wxIScan
wxscan.cpp
Go to the documentation of this file.
00001 /***************************************************************
00002  * Name:      wxscan.cpp
00003  * Purpose:   wxWidgets wrapper around libsane (for scanner
00004  *            access)
00005  * Author:    Daniel Nell (daniel.nell@nellresearch.de)
00006  * Created:   2008-05-04
00007  * Copyright: Daniel Nell (www.nellresearch.de)
00008  * License:   wxWindows license
00009  **************************************************************/
00010 
00011 // Include headers.
00012 #include "wx_pch.h"
00013 #include "wxscan.h"
00014 
00015 
00016 #if defined( __UNIX_LIKE__ )
00017 //////////////////////////////////////////////////////////
00018 // Class wxScanSane
00019 //
00020 // Standard constructor.
00021 //
00022 wxScanSane::wxScanSane( bool bOnlyLocalDevices )
00023 {
00024     // Initialize members.
00025     m_bOnlyLocalDevices= bOnlyLocalDevices;
00026     m_nResolution= -1; // Invalid value for resolution.
00027 
00028     // Initialize SANE.
00029     m_SaneStatus= ::sane_init( NULL, NULL );
00030 
00031     // Get the device list from SANE subsystem.
00032     SaneGetDevices();
00033 }
00034 
00035 // Virtual destructor.
00036 //
00037 wxScanSane::~wxScanSane()
00038 {
00039     // Close the SANE sub system.
00040     ::sane_exit();
00041 }
00042 
00043 // Get an image from the scanning device.
00044 //
00045 bool wxScanSane::ScanImage( wxImage& oImage )
00046 {
00047     // Check if there is a proper device index.
00048     if( !IsDeviceAvailable() )
00049     {
00050         // Log and signal error.
00051         wxLogError( wxString( wxT( "bool wxScan::ScanImage() - " ) )
00052                       + _( "SANE device not available." ) );
00053         return false;
00054     }
00055 
00056 #if defined( __WXSCANDEBUG__ ) && __WXSCANDEBUG__ >= 3
00057     for( int i= 0; i < m_nDeviceCount; i++ )
00058     {
00059         if( i != m_nDeviceIndex )
00060         {
00061             wxLogMessage( wxT( "SANE DEVICE" ) );
00062             wxLogMessage( wxT( "\tname == " )   + GetDeviceName(   i ) );
00063             wxLogMessage( wxT( "\tvendor == " ) + GetDeviceVendor( i ) );
00064             wxLogMessage( wxT( "\tmodel == " )  + GetDeviceModel(  i ) );
00065             wxLogMessage( wxT( "\ttype == " )   + GetDeviceType(   i ) );
00066             wxLogMessage( wxT( "============" ) );
00067         }
00068     }
00069     ::wxSafeYield();
00070 #endif
00071 
00072 #if defined( __WXSCANDEBUG__ ) && __WXSCANDEBUG__ >= 1
00073     wxLogMessage( wxT( "DEFAULT SANE DEVICE" ));
00074     wxLogMessage( wxT( "\tname == " )   + GetDeviceName(   m_nDeviceIndex ) );
00075     wxLogMessage( wxT( "\tvendor == " ) + GetDeviceVendor( m_nDeviceIndex ) );
00076     wxLogMessage( wxT( "\tmodel == " )  + GetDeviceModel(  m_nDeviceIndex ) );
00077     wxLogMessage( wxT( "\ttype == " )   + GetDeviceType(   m_nDeviceIndex ) );
00078     wxLogMessage( wxT( "============" ) );
00079     ::wxSafeYield();
00080 #endif
00081 
00082     // Sane device handle.
00083     SANE_Handle hSaneHandle;
00084 
00085     // Open the sane device...
00086     m_SaneStatus= ::sane_open( GetDeviceName( m_nDeviceIndex ).mb_str( wxConvISO8859_1 ), &hSaneHandle );
00087     if( !IsOk() )
00088     {
00089         // Log and signal error.
00090         wxLogError( GetSaneStatusString() + wxT( " (SANE)" ) );
00091         return false;
00092     }
00093 
00094     // ... and start scanning.
00095     m_SaneStatus= ::sane_start( hSaneHandle );
00096     if( !IsOk() )
00097     {
00098         // Log and signal error.
00099         wxLogError( GetSaneStatusString() + wxT( " (SANE)" ) );
00100         return false;
00101     }
00102 
00103     // Get scanning parameters e. g. width, height, color depth etc.
00104     SANE_Parameters oSaneParameters;
00105 
00106     ::sane_get_parameters( hSaneHandle, &oSaneParameters );
00107 
00108 #if defined( __WXSCANDEBUG__ ) && __WXSCANDEBUG__ >= 1
00109     wxLogMessage( wxT( "SCANNING PARAMETERS" ) );
00110     wxLogMessage( wxString::Format( wxT( "\tformat = %d" ), oSaneParameters.format ) );
00111     wxLogMessage( wxString::Format( wxT( "\tlast_frame = %d" ), oSaneParameters.last_frame ) );
00112     wxLogMessage( wxString::Format( wxT( "\tbytes_per_line = %d" ), oSaneParameters.bytes_per_line ) );
00113     wxLogMessage( wxString::Format( wxT( "\tpixels_per_line = %d" ), oSaneParameters.pixels_per_line ) );
00114     wxLogMessage( wxString::Format( wxT( "\tlines = %d" ), oSaneParameters.lines ) );
00115     wxLogMessage( wxString::Format( wxT( "\tdepth = %d" ), oSaneParameters.depth ) );
00116     wxLogMessage( wxT( "============" ) );
00117     ::wxSafeYield();
00118 #endif
00119 
00120     // Check format information.
00121     //
00122     // Note: At the moment we only support RGB/8-bit-per-pixel scans.
00123     if(
00124            !oSaneParameters.last_frame
00125         || ( oSaneParameters.format != SANE_FRAME_RGB )
00126         || ( oSaneParameters.depth != oSaneParameters.depth )
00127       )
00128     {
00129         // Log and signal error.
00130         wxLogError( wxString( wxT( "bool wxScan::ScanImage() - " ) )
00131                       + _( "Formats other than RGB with 8 bit per pixel are not yet supported." ) );
00132         return false;
00133     }
00134 
00135     // Create scan buffer.
00136     int nImageBufferSize= ( oSaneParameters.pixels_per_line * oSaneParameters.lines * 3 + 1 ) * sizeof( SANE_Byte );
00137     SANE_Byte *pScanBuffer= (SANE_Byte *)malloc( nImageBufferSize );
00138 
00139     if( !pScanBuffer )
00140     {
00141         // Log and signal error.
00142         wxLogError( wxString( wxT( "bool wxScan::ScanImage() - " ) )
00143                       + _( "Cannot allocate read buffer." ) );
00144         return false;
00145     }
00146 
00147     // Read image from scanner.
00148     SANE_Int nScannedBytes;
00149     SANE_Byte *pScanBufferPtr= pScanBuffer;
00150 
00151     do
00152     {
00153         m_SaneStatus= ::sane_read( hSaneHandle, pScanBufferPtr, nImageBufferSize, &nScannedBytes );
00154         pScanBufferPtr += nScannedBytes * sizeof( SANE_Byte );
00155     } while( ( m_SaneStatus != SANE_STATUS_EOF ) && ( m_SaneStatus == SANE_STATUS_GOOD ) ) ;
00156     if( ( m_SaneStatus !=  SANE_STATUS_EOF ) )
00157     {
00158         // Log, clean up, and signal error.
00159         wxLogError( wxString( wxT( "bool wxScan::ScanImage() - " ) )
00160                       + _( "An error occured while fetching data from scanning device." ) );
00161         ::sane_cancel( hSaneHandle );
00162         free( pScanBuffer );
00163         return false;
00164     }
00165     m_SaneStatus= SANE_STATUS_GOOD;
00166 
00167     // Save the image in the result image.
00168     wxImage oNewImage( oSaneParameters.pixels_per_line, oSaneParameters.lines, pScanBuffer );
00169 
00170     oImage= oNewImage;
00171 
00172     // Get the image resoltuion;
00173     m_nResolution= -1;
00174 
00175     int nOptionCount;
00176     const SANE_Option_Descriptor *oSaneOptionDescriptor;
00177 
00178     ::sane_control_option( hSaneHandle, 0, SANE_ACTION_GET_VALUE, &nOptionCount, NULL );
00179     for( int i= 0; i < nOptionCount; i++ )
00180     {
00181             oSaneOptionDescriptor= ::sane_get_option_descriptor( hSaneHandle, i );
00182 
00183             wxString strOption( SANE_STRING_TO_WXSTRING( oSaneOptionDescriptor->name ) );
00184 
00185 #if defined( __WXSCANDEBUG__ ) && __WXSCANDEBUG__ >= 2
00186             wxLogMessage( wxT( "DEVICE OPTION DESCRIPTOR %d" ), i );
00187             wxLogMessage( strOption + wxString::Format( wxT( "(%d):" ), oSaneOptionDescriptor->size ) );
00188             wxLogMessage( wxT( "\t" ) + SANE_STRING_TO_WXSTRING( oSaneOptionDescriptor->title ) );
00189             wxLogMessage( wxT( "\t" ) + SANE_STRING_TO_WXSTRING( oSaneOptionDescriptor->desc  ) );
00190 #endif
00191             if( 0 == strOption.CompareTo( wxT( "resolution" ) ) )
00192             {
00193                 switch( oSaneOptionDescriptor->type )
00194                 {
00195                     case SANE_TYPE_INT :    {
00196                                                 int nValue;
00197 
00198                                                 ::sane_control_option( hSaneHandle, i, SANE_ACTION_GET_VALUE, &nValue, NULL );
00199                                                 m_nResolution= (int)nValue;
00200                                             }
00201                                             break;
00202                     case SANE_TYPE_FIXED :  {
00203                                                 SANE_Fixed   nValue;
00204 
00205                                                 ::sane_control_option( hSaneHandle, i, SANE_ACTION_GET_VALUE, &nValue, NULL );
00206                                                 m_nResolution= (int)nValue;
00207                                             }
00208                                             break;
00209                     default :               {
00210                                                 // [Nothing to do, yet.]
00211                                             }
00212                 }
00213 #if defined( __WXSCANDEBUG__ ) && __WXSCANDEBUG__ >= 1
00214                 wxLogMessage( wxT( "\tresolution == %d DPI" ), m_nResolution );
00215 #endif
00216             }
00217 #if defined( __WXSCANDEBUG__ ) && __WXSCANDEBUG__ >= 2
00218             wxLogMessage( wxT( "============" ) );
00219 #endif
00220     }
00221 
00222     if( m_nResolution > 0 )
00223     {
00224         oImage.SetOption( wxIMAGE_OPTION_RESOLUTIONUNIT, wxIMAGE_RESOLUTION_INCHES );
00225         oImage.SetOption( wxIMAGE_OPTION_RESOLUTIONX,    m_nResolution );
00226         oImage.SetOption( wxIMAGE_OPTION_RESOLUTIONY,    m_nResolution );
00227         oImage.SetOption( wxIMAGE_OPTION_RESOLUTION,     m_nResolution );
00228     }
00229 
00230     // Close the sane device.
00231     ::sane_close( hSaneHandle );
00232 
00233     // Return the state.
00234     return IsOk();
00235 }
00236 
00237 // Select the scanning device by index number.
00238 //
00239 bool wxScanSane::SetDeviceIndex( int nIndex )
00240 {
00241     int nOldIndex= m_nDeviceIndex;
00242 
00243     m_nDeviceIndex= nIndex;
00244 
00245     bool nRetCode= IsDeviceAvailable();
00246 
00247     if( !nRetCode );
00248     {
00249         m_nDeviceIndex= nOldIndex;
00250     }
00251 
00252     return nRetCode;
00253 }
00254 
00255 // Fill the SANE device list.
00256 //
00257 bool wxScanSane::SaneGetDevices()
00258 {
00259     // Get the device list from sane subsystem...
00260     m_SaneStatus= ::sane_get_devices( &m_ppDeviceList, m_bOnlyLocalDevices );
00261     if( !IsOk() )
00262     {
00263         // Log error.
00264         wxLogError( GetSaneStatusString() + wxT( " (SANE)" ) );
00265         return false ;
00266     }
00267 
00268     // ... and count the devices.
00269     for( m_nDeviceCount=0; m_ppDeviceList[m_nDeviceCount]; m_nDeviceCount++ )
00270     {
00271     }
00272 
00273     // Initialize device index (default device);
00274     m_nDeviceIndex= m_nDeviceCount > 0 ? 0 : -1;
00275 
00276     // Return the state.
00277     return IsOk();
00278 }
00279 #endif // __UNIX_LIKE__
00280 
00281 #if defined( __WXMSW__ )
00282 // Standard constructor.
00283 //
00284 // ...
00285 #endif // __WXMSW__