|
|
/* This file is part of the KDE Project
|
|
|
Copyright (C) 1999 Klaas Freitag <freitag@suse.de>
|
|
|
|
|
|
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 <stdlib.h>
|
|
|
#include <tqwidget.h>
|
|
|
#include <tqobject.h>
|
|
|
#include <tqasciidict.h>
|
|
|
#include <tqcombobox.h>
|
|
|
#include <tqslider.h>
|
|
|
#include <tqcheckbox.h>
|
|
|
#include <tqlineedit.h>
|
|
|
#include <tqlabel.h>
|
|
|
#include <tqlayout.h>
|
|
|
#include <tqtooltip.h>
|
|
|
#include <tqimage.h>
|
|
|
#include <tqfileinfo.h>
|
|
|
#include <tqapplication.h>
|
|
|
#include <kdebug.h>
|
|
|
#include <klocale.h>
|
|
|
#include <kglobal.h>
|
|
|
#include <kconfig.h>
|
|
|
#include <kstandarddirs.h>
|
|
|
|
|
|
#include <unistd.h>
|
|
|
#include "kgammatable.h"
|
|
|
#include "kscandevice.h"
|
|
|
#include "kscanslider.h"
|
|
|
#include "kscanoption.h"
|
|
|
#include "kscanoptset.h"
|
|
|
#include "devselector.h"
|
|
|
#include "imgscaninfo.h"
|
|
|
|
|
|
#include <ksimpleconfig.h>
|
|
|
|
|
|
#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<KScanOption> */
|
|
|
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<int>;
|
|
|
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;
|
|
|
|
|
|
KConfig *konf = KGlobal::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; i<n; i++)
|
|
|
{
|
|
|
d = (SANE_Option_Descriptor*)
|
|
|
sane_get_option_descriptor( scanner_handle, i);
|
|
|
|
|
|
if( d )
|
|
|
{
|
|
|
// logOptions( d );
|
|
|
if(d->name )
|
|
|
{
|
|
|
// 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();
|
|
|
qDebug( "INIT: <%s> = <%s>", d->name, qq );
|
|
|
allOptionSet->insert( d->name, newOpt );
|
|
|
#endif
|
|
|
}
|
|
|
else if( d->type == SANE_TYPE_GROUP )
|
|
|
{
|
|
|
// qDebug( "######### 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
|
|
|
qDebug( "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 = (KGlobal::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<int> 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() )
|
|
|
{
|
|
|
// qDebug( "%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<KScanOption> 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<int>(d->currScanResolutionX / 0.0254 + 0.5));
|
|
|
img->setDotsPerMeterY(static_cast<int>(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 )
|
|
|
{
|
|
|
// qDebug( "No bytes written -> leaving out !" );
|
|
|
goOn = false; /** No more data -> leave ! **/
|
|
|
}
|
|
|
|
|
|
if( goOn )
|
|
|
{
|
|
|
overall_bytes += bytes_written;
|
|
|
// qDebug( "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 <20>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;
|
|
|
//qDebug( "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 qDebug 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<int> *KScanDevice::option_dic = 0L;
|
|
|
KScanOptSet *KScanDevice::gammaTables = 0L;
|
|
|
|
|
|
|
|
|
#include "kscandevice.moc"
|