![]() |
wxIScan
|
00001 /*************************************************************** 00002 * Name: wxpoppler.cpp 00003 * Purpose: wxWidgets wrapper around libpoppler for PDF file 00004 * viewing. 00005 * Author: Daniel Nell (daniel.nell@nellresearch.de) 00006 * Created: 2008-07-08 00007 * Copyright: Daniel Nell (www.nellresearch.de) 00008 * License: 00009 **************************************************************/ 00010 00011 #include <wx/filename.h> 00012 #include <wx/filesys.h> 00013 #include <wxpoppler.h> 00014 #include <gdk-pixbuf/gdk-pixbuf.h> 00015 #if wxUSE_PDF 00016 # include <wx/mstream.h> 00017 # if __WXPDFDOC__ 00018 # include <wx/pdfdoc.h> 00019 # endif // __WXPDFDOC__ 00020 #endif // wxUSE_PDF 00021 00022 ///////////////////////////////////////////////////////////////////////////// 00023 // Class wxPoppler 00024 // 00025 00026 #if __WXPOPPLER_DYNAMIC__ 00027 // Define dynamic library. 00028 wxDynamicLibrary wxPoppler::m_oWxPopplerDynamicLibrary; 00029 00030 // Define and initialize dynamic poppler-glib functions with NULL; 00031 wxPoppler::t_poppler_document_new_from_data *wxPoppler::poppler_document_new_from_data= NULL; 00032 wxPoppler::t_poppler_document_new_from_file *wxPoppler::poppler_document_new_from_file= NULL; 00033 wxPoppler::t_poppler_document_get_page *wxPoppler::poppler_document_get_page= NULL; 00034 wxPoppler::t_poppler_page_render_to_pixbuf *wxPoppler::poppler_page_render_to_pixbuf= NULL; 00035 wxPoppler::t_poppler_page_get_size *wxPoppler::poppler_page_get_size= NULL; 00036 wxPoppler::t_poppler_document_get_n_pages *wxPoppler::poppler_document_get_n_pages= NULL; 00037 00038 #endif // __WXPOPPLER_DYNAMIC__ 00039 00040 00041 // Initialize static members. 00042 // 00043 int wxPoppler::m_nGlobalDpi= 300; 00044 00045 00046 // Standard constructor. 00047 // 00048 wxPoppler::wxPoppler() 00049 { 00050 // Initialize normal members; 00051 m_pPdfPage= NULL; 00052 m_pPdfDocument= NULL; 00053 m_nDpi= m_nGlobalDpi; 00054 00055 #if __WXPOPPLER_DYNAMIC__ 00056 if( !m_oWxPopplerDynamicLibrary.IsLoaded() ) 00057 { 00058 if( m_oWxPopplerDynamicLibrary.Load( wxDynamicLibrary::CanonicalizeName( wxT( WXPOPPPLER_LIBPOPPLER ) ) ) ) 00059 { 00060 poppler_document_new_from_data= (t_poppler_document_new_from_data *)m_oWxPopplerDynamicLibrary.GetSymbol( wxT( "poppler_document_new_from_data" ) ); 00061 poppler_document_new_from_file= (t_poppler_document_new_from_file *)m_oWxPopplerDynamicLibrary.GetSymbol( wxT( "poppler_document_new_from_file" ) ); 00062 poppler_document_get_page = (t_poppler_document_get_page *)m_oWxPopplerDynamicLibrary.GetSymbol( wxT( "poppler_document_get_page" ) ); 00063 poppler_page_render_to_pixbuf = (t_poppler_page_render_to_pixbuf *)m_oWxPopplerDynamicLibrary.GetSymbol( wxT( "poppler_page_render_to_pixbuf" ) ); 00064 poppler_page_get_size = (t_poppler_page_get_size *)m_oWxPopplerDynamicLibrary.GetSymbol( wxT( "poppler_page_get_size" ) ); 00065 poppler_document_get_n_pages = (t_poppler_document_get_n_pages *)m_oWxPopplerDynamicLibrary.GetSymbol( wxT( "poppler_document_get_n_pages" ) ); 00066 } 00067 else 00068 { 00069 // Log error message. 00070 wxLogError( wxString( wxT( "wxPoppler::wxPoppler -- " ) ) 00071 + _( "Cannot load poppler library." ) ); 00072 } 00073 } 00074 #endif // __WXPOPPLER_DYNAMIC__ 00075 } 00076 00077 // Virtual destructor. 00078 // 00079 wxPoppler::~wxPoppler() 00080 { 00081 // If exists delete the PDF page. 00082 if( m_pPdfPage ) 00083 { 00084 g_object_unref( m_pPdfPage ); 00085 } 00086 00087 // If exists delete the PDF document. 00088 if( m_pPdfDocument ) 00089 { 00090 g_object_unref( m_pPdfDocument ); 00091 } 00092 } 00093 00094 // Opens a PDF stream from file or memory depending on the parameterization. 00095 // 00096 bool wxPoppler::Open( char *pcData, const int nLength, const wxString& strFileName ) 00097 { 00098 GError *pGError= NULL; 00099 00100 if( pcData && nLength ) 00101 { 00102 m_pPdfDocument= poppler_document_new_from_data( pcData, nLength, "", &pGError ); 00103 } 00104 else 00105 { 00106 wxFileName oFileName( strFileName ); 00107 wxString strFileNameAsUri= wxFileSystem::FileNameToURL( oFileName ); 00108 // // Add the "file://" protocol-identifier. 00109 // wxString strFileNameAsUri= wxT( "file://" ) + strFileName; 00110 // 00111 // // Replace backslashes by slashes to confirm to the "file://" URI rules. 00112 // strFileNameAsUri.Replace( wxT( "\\" ), wxT( "/" ) ); 00113 // 00114 // Open the file. 00115 m_pPdfDocument= poppler_document_new_from_file( strFileNameAsUri.char_str(), "", &pGError ); 00116 } 00117 if( !m_pPdfDocument ) 00118 { 00119 // Log error message from poppler library. 00120 if( pGError ) 00121 { 00122 wxLogError( wxT( "wxPoppler::Open -- GError: %s" ), 00123 wxString( pGError->message, wxConvLibc ).c_str() ); 00124 g_clear_error( &pGError ); 00125 } 00126 00127 // Signal error. 00128 return false; 00129 } 00130 return true; 00131 } 00132 00133 // Select the given page number to render by a consecutive call to RenderPage(). 00134 // 00135 bool wxPoppler::SelectPage( int nIndex ) 00136 { 00137 PopplerPage *pPdfPageTemp= poppler_document_get_page( m_pPdfDocument, nIndex ); 00138 00139 if( !pPdfPageTemp ) 00140 { 00141 return false; 00142 } 00143 m_pPdfPage= pPdfPageTemp; 00144 g_object_ref( m_pPdfPage ); 00145 return true; 00146 } 00147 00148 // Render the (previously selected) PDF page and store the result in m_oImage. 00149 // 00150 bool wxPoppler::RenderPage() 00151 { 00152 if( !m_pPdfPage ) 00153 { 00154 // Signal error. 00155 wxLogError( wxString( wxT( "wxPoppler::RenderPage -- " ) ) 00156 + _( "PDF page is not valid." ) ); 00157 return false; 00158 } 00159 00160 double dblWidth, dblHeight; 00161 double dblDpiBy72= (double)m_nDpi / 72.0; 00162 00163 poppler_page_get_size( m_pPdfPage, &dblWidth, &dblHeight ); 00164 00165 int nWidth= (int)( dblWidth * dblDpiBy72 ); 00166 int nHeight= (int)( dblHeight * dblDpiBy72 ); 00167 00168 GdkPixbuf *pGdkPixBuf= gdk_pixbuf_new( GDK_COLORSPACE_RGB, false, 8, nWidth, nHeight ); 00169 if( !pGdkPixBuf ) 00170 { 00171 // Signal error. 00172 wxLogError( wxString( wxT( "wxPoppler::RenderPage -- " ) ) 00173 + _( "Cannot create GdkPixbuf object." ) ); 00174 return false; 00175 } 00176 00177 poppler_page_render_to_pixbuf( m_pPdfPage, 0, 0, nWidth, nHeight, dblDpiBy72, 0, pGdkPixBuf ); 00178 if( 00179 ( gdk_pixbuf_get_colorspace( pGdkPixBuf ) != GDK_COLORSPACE_RGB ) 00180 || ( gdk_pixbuf_get_bits_per_sample( pGdkPixBuf ) != 8 ) 00181 || ( gdk_pixbuf_get_has_alpha( pGdkPixBuf ) ) 00182 || ( gdk_pixbuf_get_n_channels( pGdkPixBuf ) != 3 ) 00183 ) 00184 { 00185 // Signal error. 00186 wxLogError( wxString( wxT( "wxPoppler::RenderPage -- " ) ) 00187 + _( "Got wrong bitmap format from libpoppler." ) ); 00188 g_object_unref( pGdkPixBuf ); 00189 return false; 00190 } 00191 00192 int nPixBufRowSize= gdk_pixbuf_get_rowstride( pGdkPixBuf ); 00193 guchar *pPixBufData= gdk_pixbuf_get_pixels( pGdkPixBuf ); 00194 int nImageBufRowSize= 3 * nWidth; 00195 unsigned char *pImageBuf= (unsigned char *)malloc( nImageBufRowSize * nHeight ); 00196 00197 if( !pImageBuf ) 00198 { 00199 // Signal error. 00200 wxLogError( wxString( wxT( "wxPoppler::RenderPage -- " ) ) 00201 + _( "Cannot allocate a buffer for wxImage object." ) ); 00202 g_object_unref( pGdkPixBuf ); 00203 return false; 00204 } 00205 00206 unsigned char *pImageBufLine= pImageBuf; 00207 00208 for( int y= 0; y < nHeight; y++ ) 00209 { 00210 00211 memcpy( pImageBufLine, pPixBufData, nImageBufRowSize ); 00212 pPixBufData += nPixBufRowSize; 00213 pImageBufLine += nImageBufRowSize; 00214 } 00215 00216 // Create an wxImage object an set resolution information. 00217 m_oImage= wxImage( nWidth, nHeight, pImageBuf ); 00218 m_oImage.SetOption( wxIMAGE_OPTION_RESOLUTIONUNIT, wxIMAGE_RESOLUTION_INCHES ); 00219 m_oImage.SetOption( wxIMAGE_OPTION_RESOLUTION, m_nDpi ); 00220 m_oImage.SetOption( wxIMAGE_OPTION_RESOLUTIONX, m_nDpi ); 00221 m_oImage.SetOption( wxIMAGE_OPTION_RESOLUTIONY, m_nDpi ); 00222 00223 g_object_unref( pGdkPixBuf ); 00224 return true; 00225 } 00226 00227 00228 00229 #if wxUSE_PDF 00230 ///////////////////////////////////////////////////////////////////////////// 00231 // Class wxPDFHandler 00232 // 00233 IMPLEMENT_DYNAMIC_CLASS( wxPDFHandler, wxImageHandler ) 00234 00235 // Loads an image from a stream, putting the resulting data into image. 00236 // 00237 bool wxPDFHandler::LoadFile( wxImage* poImage, wxInputStream& oIStream, bool bVerbose, int nIndex ) 00238 { 00239 // Check if there is a valid PDF file. 00240 if( !CanRead( oIStream ) ) 00241 { 00242 if( bVerbose ) 00243 { 00244 wxLogError( wxString( wxT( "wxPDFHandler::LoadFile -- " ) ) 00245 + _( "PDF: This is not a PDF file." ) ); 00246 } 00247 return false; 00248 } 00249 00250 // Write the input stream to a memory buffer (by using a wxMemoryOutputStream object). 00251 wxFileOffset oOffset= oIStream.TellI(); 00252 oIStream.SeekI( 0, wxFromEnd ); 00253 wxFileOffset nSize= oIStream.TellI(); 00254 oIStream.SeekI( 0 ); 00255 char *pcData= new char[nSize]; 00256 wxMemoryOutputStream oOStream( pcData, nSize ); 00257 oIStream.Read( oOStream ); 00258 oIStream.SeekI( oOffset ); 00259 00260 int bRetC= true; 00261 int nPage= ( nIndex >= 0 ) ? nIndex : 0; 00262 wxPoppler oPoppler; 00263 00264 // Render an image of the selected page. 00265 if( oPoppler.Open( (char *)oOStream.GetOutputStreamBuffer()->GetBufferStart(), 00266 oOStream.GetOutputStreamBuffer()->GetBufferSize() ) 00267 && oPoppler.SelectPage( nPage ) 00268 && oPoppler.RenderPage() 00269 ) 00270 { 00271 (*poImage)= oPoppler.GetImage(); 00272 m_nPageCount= oPoppler.GetPageCount(); 00273 } 00274 else 00275 { 00276 if( bVerbose ) 00277 { 00278 wxLogError( wxString( wxT( "wxPDFHandler::LoadFile -- " ) ) 00279 + _( "Cannot render temporary PDF file." ) ); 00280 } 00281 bRetC= false; 00282 } 00283 delete[] pcData; 00284 return bRetC; 00285 } 00286 00287 // Saves a given image in the output stream. 00288 // 00289 bool wxPDFHandler::SaveFile( wxImage* poImage, wxOutputStream& oOStream, bool bVerbose ) 00290 { 00291 #if __WXPDFDOC__ 00292 if( poImage->HasOption( wxIMAGE_OPTION_RESOLUTIONUNIT ) ) 00293 { 00294 int nResolutionUnit= poImage->GetOptionInt( wxIMAGE_OPTION_RESOLUTIONUNIT ); 00295 int nResolution= 0; 00296 00297 // Get image resolution- 00298 if( poImage->HasOption( wxIMAGE_OPTION_RESOLUTION ) ) 00299 { 00300 nResolution= poImage->GetOptionInt( wxIMAGE_OPTION_RESOLUTION ); 00301 } 00302 else if( poImage->HasOption( wxIMAGE_OPTION_RESOLUTIONX ) && ( poImage->HasOption( wxIMAGE_OPTION_RESOLUTIONY ) ) ) 00303 { 00304 int nResolutionX= poImage->GetOptionInt( wxIMAGE_OPTION_RESOLUTIONX ); 00305 int nResolutionY= poImage->GetOptionInt( wxIMAGE_OPTION_RESOLUTIONY ); 00306 00307 if( nResolutionX == nResolutionY ) 00308 { 00309 nResolution= nResolutionX; 00310 } 00311 } 00312 if( nResolution ) 00313 { 00314 // Save image in a temporary file. 00315 wxString strTempFileName= wxFileName::CreateTempFileName( wxEmptyString ); 00316 00317 poImage->SaveFile( strTempFileName, wxT( "image/jpeg" ) ); 00318 00319 // Create a PDF document, add a page, and put the image on it. 00320 wxPdfDocument oPdfDocument; 00321 00322 oPdfDocument.AddPage( ( poImage->GetHeight() > poImage->GetWidth() ) ? wxPORTRAIT : wxLANDSCAPE ); 00323 00324 oPdfDocument.SetImageScale( (double)nResolution * ( nResolutionUnit == wxIMAGE_RESOLUTION_CM ? 2.54 : 1.0 ) / 72.0 ); 00325 oPdfDocument.Image( strTempFileName, 0 , 0, 0, 0, wxT( "image/jpeg" ) ); 00326 00327 // Remove temporary file. 00328 ::wxRemoveFile( strTempFileName ); 00329 00330 // Send the PDF to the output stream. 00331 wxMemoryInputStream oMemoryInputStream( oPdfDocument.CloseAndGetBuffer() ); 00332 00333 oOStream.Write( oMemoryInputStream ); 00334 00335 // Signal success. 00336 return true; 00337 } 00338 } 00339 #endif // __WXPDFDOC__ 00340 // File saving not possible or not implemented. 00341 return false; 00342 } 00343 00344 // Check if the file contains a PDF document. 00345 // 00346 bool wxPDFHandler::DoCanRead( wxInputStream& oIStream ) 00347 { 00348 unsigned char aucHeader[4]; 00349 00350 if ( !oIStream.Read( aucHeader, WXSIZEOF( aucHeader ) ) ) 00351 { 00352 return false; 00353 } 00354 return memcmp( aucHeader, "%PDF", WXSIZEOF( aucHeader ) ) == 0; 00355 } 00356 #endif // wxUSE_PDF