/* This file is part of the KDE Project Copyright (C) 1999 Klaas Freitag This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kgammatable.h" #include "kscandevice.h" #include "kscanslider.h" #include "kscanoption.h" #include "kscanoptset.h" #include "devselector.h" #include "imgscaninfo.h" #include #define MIN_PREVIEW_DPI 75 #define UNDEF_SCANNERNAME I18N_NOOP( "undefined" ) #define MAX_PROGRESS 100 /* --------------------------------------------------------------------------- Private class for KScanDevice ------------------------------------------------------------------------- */ class KScanDevice::KScanDevicePrivate { public: KScanDevicePrivate() : currScanResolutionX(0), currScanResolutionY(0) { } int currScanResolutionX, currScanResolutionY; }; /* --------------------------------------------------------------------------- ------------------------------------------------------------------------- */ void KScanDevice::guiSetEnabled( const TQCString& name, bool state ) { KScanOption *so = getExistingGuiElement( name ); if( so ) { TQWidget *w = so->widget(); if( w ) w->setEnabled( state ); } } /* --------------------------------------------------------------------------- ------------------------------------------------------------------------- */ KScanOption *KScanDevice::getExistingGuiElement( const TQCString& name ) { KScanOption *ret = 0L; TQCString alias = aliasName( name ); /* gui_elements is a TQList */ for( ret = gui_elements.first(); ret != 0; ret = gui_elements.next()) { if( ret->getName() == alias ) break; } return( ret ); } /* --------------------------------------------------------------------------- ------------------------------------------------------------------------- */ KScanOption *KScanDevice::getGuiElement( const TQCString& name, TQWidget *parent, const TQString& desc, const TQString& tooltip ) { if( name.isEmpty() ) return(0); TQWidget *w = 0; KScanOption *so = 0; TQCString alias = aliasName( name ); /* Check if already exists */ so = getExistingGuiElement( name ); if( so ) return( so ); /* ...else create a new one */ so = new KScanOption( alias ); if( so->valid() && so->softwareSetable()) { /** store new gui-elem in list of all gui-elements */ gui_elements.append( so ); w = so->createWidget( parent, desc, tooltip ); if( w ) { connect( so, TQT_SIGNAL( optionChanged( KScanOption* ) ), this, TQT_SLOT( slOptChanged( KScanOption* ))); w->setEnabled( so->active() ); } else { kdDebug(29000) << "ERROR: No widget created for " << name << endl; } } else { if( !so->valid()) kdDebug(29000) << "getGuiElem: no option <" << alias << ">" << endl; else if( !so->softwareSetable()) kdDebug(29000) << "getGuiElem: option <" << alias << "> is not software Setable" << endl; delete so; so = 0; } return( so ); } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- KScanDevice::KScanDevice( TQObject *parent ) : TQObject( parent ) { SANE_Status sane_stat = sane_init(NULL, NULL ); d = new KScanDevicePrivate(); option_dic = new TQAsciiDict; option_dic->setAutoDelete( true ); gui_elements.setAutoDelete( true ); scanner_initialised = false; /* stays false until openDevice. */ scanStatus = SSTAT_SILENT; data = 0; /* temporary image data buffer while scanning */ sn = 0; /* socket notifier for async scanning */ img = 0; /* temporary image to scan in */ storeOptions = 0; /* list of options to store during preview */ overall_bytes = 0; rest_bytes = 0; pixel_x = 0; pixel_y = 0; scanner_name = 0L; TDEConfig *konf = TDEGlobal::config (); konf->setGroup( GROUP_STARTUP ); bool netaccess = konf->readBoolEntry( STARTUP_ONLY_LOCAL, false ); kdDebug(29000) << "Query for network scanners " << (netaccess ? "Not enabled" : "Enabled") << endl; if( sane_stat == SANE_STATUS_GOOD ) { sane_stat = sane_get_devices( &dev_list, netaccess ? SANE_TRUE : SANE_FALSE ); // NO network devices yet // Store all available Scanner to Stringlist for( int devno = 0; sane_stat == SANE_STATUS_GOOD && dev_list[ devno ]; ++devno ) { if( dev_list[devno] ) { scanner_avail.append( dev_list[devno]->name ); scannerDevices.insert( dev_list[devno]->name, dev_list[devno] ); kdDebug(29000) << "Found Scanner: " << dev_list[devno]->name << endl; } } #if 0 connect( this, TQT_SIGNAL(sigOptionsChanged()), TQT_SLOT(slReloadAll())); #endif gammaTables = new KScanOptSet( "GammaTables" ); } else { kdDebug(29000) << "ERROR: sane_init failed -> SANE installed ?" << endl; } connect( this, TQT_SIGNAL( sigScanFinished( KScanStat )), TQT_SLOT( slScanFinished( KScanStat ))); } KScanDevice::~KScanDevice() { if( storeOptions ) delete (storeOptions ); kdDebug(29000) << "Calling sane_exit to finish sane!" << endl; sane_exit(); delete d; } KScanStat KScanDevice::openDevice( const TQCString& backend ) { KScanStat stat = KSCAN_OK; SANE_Status sane_stat = SANE_STATUS_GOOD; if( backend.isEmpty() ) return KSCAN_ERR_PARAM; // search for scanner int indx = scanner_avail.find( backend ); if( indx < 0 ) { stat = KSCAN_ERR_NO_DEVICE; } // if available, build lists of properties if( stat == KSCAN_OK ) { sane_stat = sane_open( backend, &scanner_handle ); if( sane_stat == SANE_STATUS_GOOD ) { // fill description dic with names and numbers stat = find_options(); scanner_name = backend; } else { stat = KSCAN_ERR_OPEN_DEV; scanner_name = UNDEF_SCANNERNAME; } } if( stat == KSCAN_OK ) scanner_initialised = true; return( stat ); } void KScanDevice::slCloseDevice( ) { /* First of all, send a signal to close down the scanner dev. */ emit( sigCloseDevice( )); kdDebug(29000) << "Saving scan settings" << endl; slSaveScanConfigSet( DEFAULT_OPTIONSET, i18n("the default startup setup")); /* After return, delete all related stuff */ scanner_name = UNDEF_SCANNERNAME; if( scanner_handle ) { if( scanStatus != SSTAT_SILENT ) { kdDebug(29000) << "Scanner is still active, calling cancel !" << endl; sane_cancel( scanner_handle ); } sane_close( scanner_handle ); scanner_handle = 0; } gui_elements.clear(); option_dic->clear(); scanner_initialised = false; } TQString KScanDevice::getScannerName(const TQCString& name) const { TQString ret = i18n("No scanner selected"); SANE_Device *scanner = 0L; if( !scanner_name.isNull() && scanner_initialised && name.isEmpty()) { scanner = scannerDevices[ scanner_name ]; } else if ( ! name.isEmpty() ) { scanner = scannerDevices[ name ]; ret = TQString(); } if( scanner ) { // ret.sprintf( "%s %s %s", scanner->vendor, scanner->model, scanner->type ); ret.sprintf( "%s %s", scanner->vendor, scanner->model ); } kdDebug(29000) << "getScannerName returns <" << ret << ">" << endl; return ( ret ); } TQSize KScanDevice::getMaxScanSize( void ) const { TQSize s; double min, max, q; KScanOption so_w( SANE_NAME_SCAN_BR_X ); so_w.getRange( &min, &max, &q ); s.setWidth( (int) max ); KScanOption so_h( SANE_NAME_SCAN_BR_Y ); so_h.getRange( &min, &max, &q ); s.setHeight( (int) max ); return( s ); } KScanStat KScanDevice::find_options() { KScanStat stat = KSCAN_OK; SANE_Int n; SANE_Int opt; int *new_opt; SANE_Option_Descriptor *d; if( sane_control_option(scanner_handle, 0,SANE_ACTION_GET_VALUE, &n, &opt) != SANE_STATUS_GOOD ) stat = KSCAN_ERR_CONTROL; // printf("find_options(): Found %d options\n", n ); // resize the Array which hold the descriptions if( stat == KSCAN_OK ) { option_dic->clear(); for(int i = 1; iname ) { // Die Option anhand des Namen in den Dict if( strlen( d->name ) > 0 ) { new_opt = new int; *new_opt = i; kdDebug(29000) << "Inserting <" << d->name << "> as " << *new_opt << endl; /* create a new option in the set. */ option_dic->insert ( (const char*)d->name, new_opt ); option_list.append( (const char*) d->name ); #if 0 KScanOption *newOpt = new KScanOption( d->name ); const TQString qq = newOpt->get(); tqDebug( "INIT: <%s> = <%s>", d->name, qq ); allOptionSet->insert( d->name, newOpt ); #endif } else if( d->type == SANE_TYPE_GROUP ) { // tqDebug( "######### Group found: %s ########", d->title ); } else kdDebug(29000) << "Unable to detect option " << endl; } } } } return stat; } TQStrList KScanDevice::getAllOptions() { return( option_list ); } TQStrList KScanDevice::getCommonOptions() { TQStrList com_opt; TQCString s = option_list.first(); while( !s.isEmpty() ) { KScanOption opt( s ); if( opt.commonOption() ) com_opt.append( s ); s = option_list.next(); } return( com_opt ); } TQStrList KScanDevice::getAdvancedOptions() { TQStrList com_opt; TQCString s = option_list.first(); while( !s.isEmpty() ) { KScanOption opt( s ); if( !opt.commonOption() ) com_opt.append( s ); s = option_list.next(); } return( com_opt ); } KScanStat KScanDevice::apply( KScanOption *opt, bool isGammaTable ) { KScanStat stat = KSCAN_OK; if( !opt ) return( KSCAN_ERR_PARAM ); int sane_result = 0; int *num = (*option_dic)[ opt->getName() ]; SANE_Status sane_stat = SANE_STATUS_GOOD; const TQCString& oname = opt->getName(); if ( oname == "preview" || oname == "mode" ) { sane_stat = sane_control_option( scanner_handle, *num, SANE_ACTION_SET_AUTO, 0, &sane_result ); /* No return here, please ! Carsten, does it still work than for you ? */ } if( ! opt->initialised() || opt->getBuffer() == 0 ) { kdDebug(29000) << "Attempt to set Zero buffer of " << oname << " -> skipping !" << endl; if( opt->autoSetable() ) { kdDebug(29000) << "Setting option automatic !" << endl; sane_stat = sane_control_option( scanner_handle, *num, SANE_ACTION_SET_AUTO, 0, &sane_result ); } else { sane_stat = SANE_STATUS_INVAL; } stat = KSCAN_ERR_PARAM; } else { if( ! opt->active() ) { kdDebug(29000) << "Option " << oname << " is not active now!" << endl; stat = KSCAN_OPT_NOT_ACTIVE; } else if( ! opt->softwareSetable() ) { kdDebug(29000) << "Option " << oname << " is not software Setable!" << endl; stat = KSCAN_OPT_NOT_ACTIVE; } else { sane_stat = sane_control_option( scanner_handle, *num, SANE_ACTION_SET_VALUE, opt->getBuffer(), &sane_result ); } } if( stat == KSCAN_OK ) { if( sane_stat == SANE_STATUS_GOOD ) { kdDebug(29000) << "Applied <" << oname << "> successfully" << endl; if( sane_result & SANE_INFO_RELOAD_OPTIONS ) { kdDebug(29000) << "* Setting status to reload options" << endl; stat = KSCAN_RELOAD; #if 0 tqDebug( "Emitting sigOptionChanged()" ); emit( sigOptionsChanged() ); #endif } #if 0 if( sane_result & SANE_INFO_RELOAD_PARAMS ) emit( sigScanParamsChanged() ); #endif if( sane_result & SANE_INFO_INEXACT ) { kdDebug(29000) << "Option <" << oname << "> was set inexact !" << endl; } /* if it is a gamma table, the gamma values must be stored */ if( isGammaTable ) { gammaTables->backupOption( *opt ); kdDebug(29000) << "GammaTable stored: " << opt->getName() << endl; } } else { kdDebug(29000) << "Status of sane is bad: " << sane_strstatus( sane_stat ) << " for option " << oname << endl; } } else { kdDebug(29000) << "Setting of <" << oname << "> failed -> kscanerror." << endl; } if( stat == KSCAN_OK ) { slSetDirty( oname ); } return( stat ); } bool KScanDevice::optionExists( const TQCString& name ) { if( name.isEmpty() ) return false; int *i = 0L; TQCString altname = aliasName( name ); if( ! altname.isNull() ) i = (*option_dic)[ altname ]; if( !i ) return( false ); return( *i > -1 ); } void KScanDevice::slSetDirty( const TQCString& name ) { if( optionExists( name ) ) { if( dirtyList.find( name ) == -1 ) { kdDebug(29000)<< "Setting dirty <" << name << ">" << endl; /* item not found */ dirtyList.append( name ); } } } /* This function tries to find name aliases which appear from backend to backend. * Example: Custom-Gamma is for epson backends 'gamma-correction' - not a really * cool thing :-| * Maybe this helps us out ? */ TQCString KScanDevice::aliasName( const TQCString& name ) { int *i = (*option_dic)[ name ]; TQCString ret; if( i ) return( name ); ret = name; if( name == SANE_NAME_CUSTOM_GAMMA ) { if((*option_dic)["gamma-correction"]) ret = "gamma-correction"; } if( ret != name ) kdDebug( 29000) << "Found alias for <" << name << "> which is <" << ret << ">" << endl; return( ret ); } /* Nothing to do yet. This Slot may get active to do same user Widget changes */ void KScanDevice::slOptChanged( KScanOption *opt ) { kdDebug(29000) << "Slot Option Changed for Option " << opt->getName() << endl; apply( opt ); } /* This might result in a endless recursion ! */ void KScanDevice::slReloadAllBut( KScanOption *not_opt ) { if( ! not_opt ) { kdDebug(29000) << "ReloadAllBut called with invalid argument" << endl; return; } /* Make sure its applied */ apply( not_opt ); kdDebug(29000) << "*** Reload of all except <" << not_opt->getName() << "> forced ! ***" << endl; for( KScanOption *so = gui_elements.first(); so; so = gui_elements.next()) { if( so != not_opt ) { kdDebug(29000) << "Reloading <" << so->getName() << ">" << endl; so->slReload(); so->slRedrawWidget(so); } } kdDebug(29000) << "*** Reload of all finished ! ***" << endl; } /* This might result in a endless recursion ! */ void KScanDevice::slReloadAll( ) { kdDebug(29000) << "*** Reload of all forced ! ***" << endl; for( KScanOption *so = gui_elements.first(); so; so = gui_elements.next()) { so->slReload(); so->slRedrawWidget(so); } } void KScanDevice::slStopScanning( void ) { kdDebug(29000) << "Attempt to stop scanning" << endl; if( scanStatus == SSTAT_IN_PROGRESS ) { emit( sigScanFinished( KSCAN_CANCELLED )); } scanStatus = SSTAT_STOP_NOW; } const TQString KScanDevice::previewFile() { TQString dir = (TDEGlobal::dirs())->saveLocation( "data", "ScanImages", true ); if( !dir.endsWith("/") ) dir += "/"; TQString fname = dir + TQString::fromLatin1(".previews/"); TQString sname( getScannerName(shortScannerName()) ); sname.replace( '/', "_"); return fname+sname; } TQImage KScanDevice::loadPreviewImage() { const TQString prevFile = previewFile(); kdDebug(29000) << "Loading preview from file " << prevFile << endl; TQImage image; image.load( prevFile ); return image; } bool KScanDevice::savePreviewImage( const TQImage &image ) { if( image.isNull() ) return false; const TQString prevFile = previewFile(); kdDebug(29000) << "Saving preview to file " << prevFile << endl; return image.save( prevFile, "BMP" ); } KScanStat KScanDevice::acquirePreview( bool forceGray, int dpi ) { if( ! scanner_handle ) return KSCAN_ERR_NO_DEVICE; double min, max, q; (void) forceGray; if( storeOptions ) storeOptions->clear(); else storeOptions = new KScanOptSet( "TempStore" ); /* set Preview = ON if exists */ if( optionExists( SANE_NAME_PREVIEW ) ) { KScanOption prev( aliasName(SANE_NAME_PREVIEW) ); prev.set( true ); apply( &prev ); /* after having applied, save set to false to switch preview mode off after scanning */ prev.set( false ); storeOptions->backupOption( prev ); } /* Gray-Preview only done by widget ? */ if( optionExists( SANE_NAME_GRAY_PREVIEW )) { KScanOption *so = getExistingGuiElement( SANE_NAME_GRAY_PREVIEW ); if( so ) { if( so->get() == "true" ) { /* Gray preview on */ so->set( true ); kdDebug(29000) << "Setting GrayPreview ON" << endl; } else { so->set(false ); kdDebug(29000) << "Setting GrayPreview OFF" << endl; } } apply( so ); } if( optionExists( SANE_NAME_SCAN_MODE ) ) { KScanOption mode( SANE_NAME_SCAN_MODE ); const TQString kk = mode.get(); kdDebug(29000) << "Mode is <" << kk << ">" << endl; storeOptions->backupOption( mode ); /* apply if it has a widget, or apply always ? */ if( mode.widget() ) apply( &mode ); } /** Scan Resolution should always exist. **/ KScanOption res ( SANE_NAME_SCAN_RESOLUTION ); const TQString p = res.get(); kdDebug(29000) << "Scan Resolution pre Preview is " << p << endl; storeOptions->backupOption( res ); int set_dpi = dpi; if( dpi == 0 ) { /* No resolution argument */ if( ! res.getRange( &min, &max, &q ) ) { if( ! res.getRangeFromList ( &min, &max, &q ) ) { kdDebug(29000) << "Could not retrieve resolution range!" << endl; min = 75.0; // Hope that every scanner can 75 } } kdDebug(29000) << "Minimum Range: " << min << ", Maximum Range: " << max << endl; if( min > MIN_PREVIEW_DPI ) set_dpi = (int) min; else set_dpi = MIN_PREVIEW_DPI; } /* Set scan resolution for preview. */ if( !optionExists( SANE_NAME_SCAN_Y_RESOLUTION ) ) d->currScanResolutionY = 0; else { KScanOption yres ( SANE_NAME_SCAN_Y_RESOLUTION ); /* if active ? */ storeOptions->backupOption( yres ); yres.set( set_dpi ); apply( &yres ); yres.get( &d->currScanResolutionY ); /* Resolution bind switch ? */ if( optionExists( SANE_NAME_RESOLUTION_BIND ) ) { KScanOption bind_so( SANE_NAME_RESOLUTION_BIND ); /* Switch binding on if available */ storeOptions->backupOption( bind_so ); bind_so.set( true ); apply( &bind_so ); } } res.set( set_dpi ); apply( &res ); /* Store the resulting preview for additional image information */ res.get( &d->currScanResolutionX ); if ( d->currScanResolutionY == 0 ) d->currScanResolutionY = d->currScanResolutionX; /* Start scanning */ KScanStat stat = acquire_data( true ); /* Restauration of the previous values must take place in the scanfinished slot, * because scanning works asynchron now. */ return( stat ); } /** * prepareScan tries to set as much as parameters as possible. * **/ #define NOTIFIER(X) optionNotifyString(X) TQString KScanDevice::optionNotifyString( int i ) const { const TQString sOff = " |"; const TQString sOn = " X |"; if( i > 0 ) { return sOn; } return sOff; } void KScanDevice::prepareScan( void ) { TQAsciiDictIterator it( *option_dic ); // iterator for dict kdDebug(29000) << "########################################################################################################" << endl; kdDebug(29000) << "Scanner: " << scanner_name << endl; kdDebug(29000) << " " << getScannerName() << endl; kdDebug(29000) << "----------------------------------+--------+--------+--------+--------+--------+--------+--------+" << endl; kdDebug(29000) << " Option-Name |SOFT_SEL|HARD_SEL|SOFT_DET|EMULATED|AUTOMATI|INACTIVE|ADVANCED|" << endl; kdDebug(29000) << "----------------------------------+--------+--------+--------+--------+--------+--------+--------+" << endl; while ( it.current() ) { // tqDebug( "%s -> %d", it.currentKey().latin1(), *it.current() ); int descriptor = *it.current(); const SANE_Option_Descriptor *d = sane_get_option_descriptor( scanner_handle, descriptor ); if( d ) { int cap = d->cap; TQString s = TQString(it.currentKey()).leftJustify(32, ' '); kdDebug(29000) << " " << s << " |" << NOTIFIER( ((cap) & SANE_CAP_SOFT_SELECT)) << NOTIFIER( ((cap) & SANE_CAP_HARD_SELECT)) << NOTIFIER( ((cap) & SANE_CAP_SOFT_DETECT)) << NOTIFIER( ((cap) & SANE_CAP_EMULATED) ) << NOTIFIER( ((cap) & SANE_CAP_AUTOMATIC) ) << NOTIFIER( ((cap) & SANE_CAP_INACTIVE) ) << NOTIFIER( ((cap) & SANE_CAP_ADVANCED ) ) << endl; } ++it; } kdDebug(29000) << "----------------------------------+--------+--------+--------+--------+--------+--------+--------+" << endl; KScanOption pso( SANE_NAME_PREVIEW ); const TQString q = pso.get(); kdDebug(29000) << "Preview-Switch is at the moment: " << q << endl; } /** Starts scanning * depending on if a filename is given or not, the function tries to open * the file using the TQt-Image-IO or really scans the image. **/ KScanStat KScanDevice::acquire( const TQString& filename ) { if( ! scanner_handle ) return KSCAN_ERR_NO_DEVICE; KScanOption *so = 0; if( filename.isEmpty() ) { /* *real* scanning - apply all Options and go for it */ prepareScan(); for( so = gui_elements.first(); so; so = gui_elements.next() ) { if( so->active() ) { kdDebug(29000) << "apply <" << so->getName() << ">" << endl; apply( so ); } else { kdDebug(29000) << "Option <" << so->getName() << "> is not active !" << endl; } } /** Scan Resolution should always exist. **/ KScanOption res( SANE_NAME_SCAN_RESOLUTION ); res.get( &d->currScanResolutionX ); if ( !optionExists( SANE_NAME_SCAN_Y_RESOLUTION ) ) d->currScanResolutionY = d->currScanResolutionX; else { KScanOption yres( SANE_NAME_SCAN_Y_RESOLUTION ); yres.get( &d->currScanResolutionY ); } return( acquire_data( false )); } else { /* a filename is in the parameter */ TQFileInfo file( filename ); if( file.exists() ) { TQImage i; ImgScanInfo info; if( i.load( filename )) { info.setXResolution(i.dotsPerMeterX()); // TODO: *2.54/100 info.setYResolution(i.dotsPerMeterY()); // TODO: *2.54/100 info.setScannerName(filename); emit( sigNewImage( &i, &info )); } } } return KSCAN_OK; } /** * Creates a new TQImage from the retrieved Image Options **/ KScanStat KScanDevice::createNewImage( SANE_Parameters *p ) { if( !p ) return( KSCAN_ERR_PARAM ); KScanStat stat = KSCAN_OK; if( img ) { delete( img ); img = 0; } if( p->depth == 1 ) // Lineart !! { img = new TQImage( p->pixels_per_line, p->lines, 8 ); if( img ) { img->setNumColors( 2 ); img->setColor( 0, tqRgb( 0,0,0)); img->setColor( 1, tqRgb( 255,255,255) ); } } else if( p->depth == 8 ) { // 8 bit rgb-Picture if( p->format == SANE_FRAME_GRAY ) { /* Grayscale */ img = new TQImage( p->pixels_per_line, p->lines, 8 ); if( img ) { img->setNumColors( 256 ); for(int i = 0; i<256; i++) img->setColor(i, tqRgb(i,i,i)); } } else { /* true color image */ img = new TQImage( p->pixels_per_line, p->lines, 32 ); if( img ) img->setAlphaBuffer( false ); } } else { /* ERROR: NO OTHER DEPTHS supported */ kdDebug(29000) << "KScan supports only bit dephts 1 and 8 yet!" << endl; } if( ! img ) stat = KSCAN_ERR_MEMORY; return( stat ); } KScanStat KScanDevice::acquire_data( bool isPreview ) { SANE_Status sane_stat = SANE_STATUS_GOOD; KScanStat stat = KSCAN_OK; scanningPreview = isPreview; emit sigScanStart(); sane_stat = sane_start( scanner_handle ); if( sane_stat == SANE_STATUS_GOOD ) { sane_stat = sane_get_parameters( scanner_handle, &sane_scan_param ); if( sane_stat == SANE_STATUS_GOOD ) { kdDebug(29000) << "--Pre-Loop" << endl; kdDebug(29000) << "format : " << sane_scan_param.format << endl; kdDebug(29000) << "last_frame : " << sane_scan_param.last_frame << endl; kdDebug(29000) << "lines : " << sane_scan_param.lines << endl; kdDebug(29000) << "depth : " << sane_scan_param.depth << endl; kdDebug(29000) << "pixels_per_line : " << sane_scan_param.pixels_per_line << endl; kdDebug(29000) << "bytes_per_line : " << sane_scan_param.bytes_per_line << endl; } else { stat = KSCAN_ERR_OPEN_DEV; kdDebug(29000) << "sane-get-parameters-Error: " << sane_strstatus( sane_stat ) << endl; } } else { stat = KSCAN_ERR_OPEN_DEV; kdDebug(29000) << "sane-start-Error: " << sane_strstatus( sane_stat ) << endl; } if( sane_scan_param.pixels_per_line == 0 || sane_scan_param.lines < 1 ) { kdDebug(29000) << "ERROR: Acquiring empty picture !" << endl; stat = KSCAN_ERR_EMPTY_PIC; } /* Create new Image from SANE-Parameters */ if( stat == KSCAN_OK ) { stat = createNewImage( &sane_scan_param ); } if( stat == KSCAN_OK ) { /* new buffer for scanning one line */ if(data) delete [] data; data = new SANE_Byte[ sane_scan_param.bytes_per_line +4 ]; if( ! data ) stat = KSCAN_ERR_MEMORY; } /* Signal for a progress dialog */ emit( sigScanProgress( 0 ) ); emit( sigAcquireStart() ); if( stat == KSCAN_OK ) { /* initiates Redraw of the Progress-Window */ tqApp->processEvents(); } if( stat == KSCAN_OK ) { overall_bytes = 0; scanStatus = SSTAT_IN_PROGRESS; pixel_x = 0; pixel_y = 0; overall_bytes = 0; rest_bytes = 0; /* internal status to indicate Scanning in progress * this status might be changed by pressing Stop on a GUI-Dialog displayed during scan */ if( sane_set_io_mode( scanner_handle, SANE_TRUE ) == SANE_STATUS_GOOD ) { int fd = 0; if( sane_get_select_fd( scanner_handle, &fd ) == SANE_STATUS_GOOD ) { sn = new TQSocketNotifier( fd, TQSocketNotifier::Read, this ); TQObject::connect( sn, TQT_SIGNAL(activated(int)), this, TQT_SLOT( doProcessABlock() ) ); } } else { do { doProcessABlock(); if( scanStatus != SSTAT_SILENT ) { sane_stat = sane_get_parameters( scanner_handle, &sane_scan_param ); kdDebug(29000) << "--ProcessABlock-Loop" << endl; kdDebug(29000) << "format : " << sane_scan_param.format << endl; kdDebug(29000) << "last_frame : " << sane_scan_param.last_frame << endl; kdDebug(29000) << "lines : " << sane_scan_param.lines << endl; kdDebug(29000) << "depth : " << sane_scan_param.depth << endl; kdDebug(29000) << "pixels_per_line : " << sane_scan_param.pixels_per_line << endl; kdDebug(29000) << "bytes_per_line : " << sane_scan_param.bytes_per_line << endl; } } while ( scanStatus != SSTAT_SILENT ); } } if( stat != KSCAN_OK ) { /* Scanning was disturbed in any way - end it */ kdDebug(29000) << "Scanning was disturbed - clean up" << endl; emit( sigScanFinished( stat )); } return( stat ); } void KScanDevice::loadOptionSet( KScanOptSet *optSet ) { if( !optSet ) { return; } // kdDebug(29000) << "Loading Option set: " << optSet->optSetName() << endl; TQAsciiDictIterator it(*optSet); kdDebug(29000) << "Postinstalling " << optSet->count() << " options" << endl; while( it.current() ) { KScanOption *so = it.current(); if( ! so->initialised() ) kdDebug(29000) << so->getName() << " is not initialised" << endl; if( ! so->active() ) kdDebug(29000) << so->getName() << " is not active" << endl; if( so && so->active() && so->initialised()) { const TQString qq = so->get(); kdDebug(29000) << "Post-Scan-apply <" << it.currentKey() << ">: " << qq << endl; apply( so ); } ++it; } } void KScanDevice::slScanFinished( KScanStat status ) { // clean up if( sn ) { sn->setEnabled( false ); delete sn; sn = 0; } emit( sigScanProgress( MAX_PROGRESS )); kdDebug(29000) << "Slot ScanFinished hit with status " << status << endl; if( data ) { delete[] data; data = 0; } if( status == KSCAN_OK && img ) { ImgScanInfo info; info.setXResolution(d->currScanResolutionX); info.setYResolution(d->currScanResolutionY); info.setScannerName(shortScannerName()); // put the resolution also into the image itself img->setDotsPerMeterX(static_cast(d->currScanResolutionX / 0.0254 + 0.5)); img->setDotsPerMeterY(static_cast(d->currScanResolutionY / 0.0254 + 0.5)); kdDebug(29000) << "resolutionX:" << d->currScanResolutionX << " resolutionY:" << d->currScanResolutionY << endl; if( scanningPreview ) { kdDebug(29000) << "Scanning a preview !" << endl; savePreviewImage(*img); emit( sigNewPreview( img, &info )); /* The old settings need to be redefined */ loadOptionSet( storeOptions ); } else { emit( sigNewImage( img, &info )); } } sane_cancel(scanner_handle); /* This follows after sending the signal */ if( img ) { delete img; img = 0; } /* delete the socket notifier */ if( sn ) { delete( sn ); sn = 0; } } /* This function calls at least sane_read and converts the read data from the scanner * to the qimage. * The function needs: * TQImage img valid * the data-buffer set to a appropriate size **/ void KScanDevice::doProcessABlock( void ) { int val,i; TQRgb col, newCol; SANE_Byte *rptr = 0; SANE_Int bytes_written = 0; int chan = 0; SANE_Status sane_stat = SANE_STATUS_GOOD; uchar eight_pix = 0; bool goOn = true; // int rest_bytes = 0; while( goOn && data ) { sane_stat = sane_read( scanner_handle, data + rest_bytes, sane_scan_param.bytes_per_line, &bytes_written); int red = 0; int green = 0; int blue = 0; if( sane_stat != SANE_STATUS_GOOD ) { /** any other error **/ kdDebug(29000) << "sane_read returned with error <" << sane_strstatus( sane_stat ) << ">: " << bytes_written << " bytes left" << endl; goOn = false; } if( goOn && bytes_written < 1 ) { // tqDebug( "No bytes written -> leaving out !" ); goOn = false; /** No more data -> leave ! **/ } if( goOn ) { overall_bytes += bytes_written; // tqDebug( "Bytes read: %d, bytes written: %d", bytes_written, rest_bytes ); rptr = data; // + rest_bytes; switch( sane_scan_param.format ) { case SANE_FRAME_RGB: if( sane_scan_param.lines < 1 ) break; bytes_written += rest_bytes; // die übergebliebenen Bytes dazu rest_bytes = bytes_written % 3; for( val = 0; val < ((bytes_written-rest_bytes) / 3); val++ ) { red = *rptr++; green = *rptr++; blue = *rptr++; // kdDebug(29000) << "RGB: %d, %d, %d\n", red, green, blue" << endl; if( pixel_x == sane_scan_param.pixels_per_line ) { pixel_x = 0; pixel_y++; } if( pixel_y < img->height()) img->setPixel( pixel_x, pixel_y, tqRgb( red, green,blue )); pixel_x++; } /* copy the remaining bytes to the beginning of the block :-/ */ for( val = 0; val < rest_bytes; val++ ) { *(data+val) = *rptr++; } break; case SANE_FRAME_GRAY: for( val = 0; val < bytes_written ; val++ ) { if( pixel_y >= sane_scan_param.lines ) break; if( sane_scan_param.depth == 8 ) { if( pixel_x == sane_scan_param.pixels_per_line ) { pixel_x = 0; pixel_y++; } img->setPixel( pixel_x, pixel_y, *rptr++ ); pixel_x++; } else { // Lineart /* Lineart needs to be converted to byte */ eight_pix = *rptr++; for( i = 0; i < 8; i++ ) { if( pixel_y < sane_scan_param.lines ) { chan = (eight_pix & 0x80)> 0 ? 0:1; eight_pix = eight_pix << 1; //tqDebug( "Setting on %d, %d: %d", pixel_x, pixel_y, chan ); img->setPixel( pixel_x, pixel_y, chan ); pixel_x++; if( pixel_x >= sane_scan_param.pixels_per_line ) { pixel_x = 0; pixel_y++; break; } } } } } break; case SANE_FRAME_RED: case SANE_FRAME_GREEN: case SANE_FRAME_BLUE: kdDebug(29000) << "Scanning Single color Frame: " << bytes_written << " Bytes!" << endl; for( val = 0; val < bytes_written ; val++ ) { if( pixel_x >= sane_scan_param.pixels_per_line ) { pixel_y++; pixel_x = 0; } if( pixel_y < sane_scan_param.lines ) { col = img->pixel( pixel_x, pixel_y ); red = tqRed( col ); green = tqGreen( col ); blue = tqBlue( col ); chan = *rptr++; switch( sane_scan_param.format ) { case SANE_FRAME_RED : newCol = tqRgba( chan, green, blue, 0xFF ); break; case SANE_FRAME_GREEN : newCol = tqRgba( red, chan, blue, 0xFF ); break; case SANE_FRAME_BLUE : newCol = tqRgba( red , green, chan, 0xFF ); break; default: kdDebug(29000) << "Undefined format !" << endl; newCol = tqRgba( 0xFF, 0xFF, 0xFF, 0xFF ); break; } img->setPixel( pixel_x, pixel_y, newCol ); pixel_x++; } } break; default: kdDebug(29000) << "Unexpected ERROR: No Format type" << endl; break; } /* switch */ if( (sane_scan_param.lines > 0) && (sane_scan_param.lines * pixel_y> 0) ) { int progress = (int)(((double)MAX_PROGRESS) / sane_scan_param.lines * pixel_y); if( progress < MAX_PROGRESS) emit( sigScanProgress( progress)); } if( bytes_written == 0 || sane_stat == SANE_STATUS_EOF ) { kdDebug(29000) << "Down under sane_stat not OK" << endl; goOn = false; } } if( goOn && scanStatus == SSTAT_STOP_NOW ) { /* scanStatus is set to SSTAT_STOP_NOW due to hitting slStopScanning */ /* Mostly that one is fired by the STOP-Button in the progress dialog. */ /* This is also hit after the normal finish of the scan. Most probably, * the TQSocketnotifier fires for a few times after the scan has been * cancelled. Does it matter ? To see it, just uncomment the tqDebug msg. */ kdDebug(29000) << "Stopping the scan progress !" << endl; goOn = false; scanStatus = SSTAT_SILENT; emit( sigScanFinished( KSCAN_OK )); } } /* while( 1 ) */ /** Comes here if scanning is finished or has an error **/ if( sane_stat == SANE_STATUS_EOF) { if ( sane_scan_param.last_frame) { /** Everythings okay, the picture is ready **/ kdDebug(29000) << "last frame reached - scan successful" << endl; scanStatus = SSTAT_SILENT; emit( sigScanFinished( KSCAN_OK )); } else { /** EOF und nicht letzter Frame -> Parameter neu belegen und neu starten **/ scanStatus = SSTAT_NEXT_FRAME; kdDebug(29000) << "EOF, but another frame to scan" << endl; } } if( sane_stat == SANE_STATUS_CANCELLED ) { scanStatus = SSTAT_STOP_NOW; kdDebug(29000) << "Scan was cancelled" << endl; // stat = KSCAN_CANCELLED; // emit( sigScanFinished( stat )); /* hmmm - how could this happen ? */ } } /* end of fkt */ void KScanDevice::slSaveScanConfigSet( const TQString& setName, const TQString& descr ) { if( setName.isEmpty() || setName.isNull()) return; kdDebug(29000) << "Saving Scan Configuration" << setName << endl; KScanOptSet optSet( DEFAULT_OPTIONSET ); getCurrentOptions( &optSet ); optSet.saveConfig( scanner_name , setName, descr ); } void KScanDevice::getCurrentOptions( KScanOptSet *optSet ) { if( ! optSet ) return; for( KScanOption *so = gui_elements.first(); so; so = gui_elements.next()) { kdDebug(29000) << "Storing <" << so->getName() << ">" << endl; if( so && so->active()) { apply(so); optSet->backupOption( *so ); } /* drop the thing from the dirty-list */ dirtyList.removeRef( so->getName()); } TQStrListIterator it( dirtyList ); while( it.current()) { KScanOption so( it.current() ); optSet->backupOption( so ); ++it; } } TQString KScanDevice::getConfig( const TQString& key, const TQString& def ) const { TQString confFile = SCANNER_DB_FILE; KSimpleConfig scanConfig( confFile, true ); scanConfig.setGroup( shortScannerName() ); return scanConfig.readEntry( key, def ); } void KScanDevice::slStoreConfig( const TQString& key, const TQString& val ) { TQString confFile = SCANNER_DB_FILE; TQString scannerName = shortScannerName(); if( scannerName.isEmpty() || scannerName == UNDEF_SCANNERNAME ) { kdDebug(29000) << "Skipping config write, scanner name is empty!" << endl; } else { kdDebug(29000) << "Storing config " << key << " in Group " << scannerName << endl; KSimpleConfig scanConfig( confFile ); scanConfig.setGroup( scannerName ); scanConfig.writeEntry( key, val ); scanConfig.sync(); } } bool KScanDevice::scanner_initialised = false; SANE_Handle KScanDevice::scanner_handle = 0L; SANE_Device const **KScanDevice::dev_list = 0L; TQAsciiDict *KScanDevice::option_dic = 0L; KScanOptSet *KScanDevice::gammaTables = 0L; #include "kscandevice.moc"