You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
872 lines
25 KiB
872 lines
25 KiB
|
|
/* This file is part of the KDE Project
|
|
Copyright (C) 2000 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 <tqlabel.h>
|
|
#include <tqfontmetrics.h>
|
|
#include <tqhbox.h>
|
|
#include <tqtooltip.h>
|
|
#include <tqpopupmenu.h>
|
|
#include <tqfile.h>
|
|
#include <tqtextstream.h>
|
|
#include <tqcombobox.h>
|
|
#include <tqradiobutton.h>
|
|
#include <tqgroupbox.h>
|
|
#include <tqlayout.h>
|
|
|
|
#include <kdebug.h>
|
|
#include <tdelocale.h>
|
|
#include <kcombobox.h>
|
|
#include <tdeaction.h>
|
|
#include <kstandarddirs.h>
|
|
|
|
#include "previewer.h"
|
|
#include "img_canvas.h"
|
|
#include "sizeindicator.h"
|
|
#include "devselector.h" /* for definition of config key :( */
|
|
#include "kscandevice.h"
|
|
#include <tqslider.h>
|
|
#include <tqcheckbox.h>
|
|
#include <tdeconfig.h>
|
|
#include <tqbuttongroup.h>
|
|
#include <tqvbuttongroup.h>
|
|
#include <tdemessagebox.h>
|
|
#include <tqvaluevector.h>
|
|
|
|
#define ID_CUSTOM 0
|
|
#define ID_A4 1
|
|
#define ID_A5 2
|
|
#define ID_A6 3
|
|
#define ID_9_13 4
|
|
#define ID_10_15 5
|
|
#define ID_LETTER 6
|
|
|
|
/** Config tags for autoselection **/
|
|
#define CFG_AUTOSEL_DO "doAutoselection" /* do it or not */
|
|
#define CFG_AUTOSEL_THRESH "autoselThreshold" /* threshold */
|
|
#define CFG_AUTOSEL_DUSTSIZE "autoselDustsize" /* dust size */
|
|
/* tag if a scan of the empty scanner results in black or white image */
|
|
#define CFG_SCANNER_EMPTY_BG "scannerBackgroundWhite"
|
|
|
|
/* Defaultvalues for the threshold for the autodetection */
|
|
#define DEF_THRESH_BLACK "45"
|
|
#define DEF_THRESH_WHITE "240"
|
|
|
|
/* Items for the combobox to set the color of an empty scan */
|
|
#define BG_ITEM_BLACK 0
|
|
#define BG_ITEM_WHITE 1
|
|
|
|
|
|
class Previewer::PreviewerPrivate
|
|
{
|
|
public:
|
|
PreviewerPrivate():
|
|
m_doAutoSelection(false),
|
|
m_autoSelThresh(0),
|
|
m_dustsize(5),
|
|
m_bgIsWhite(false),
|
|
m_sliderThresh(0),
|
|
m_sliderDust(0),
|
|
m_cbAutoSel(0),
|
|
m_cbBackground(0),
|
|
m_autoSelGroup(0),
|
|
m_scanner(0)
|
|
{
|
|
}
|
|
bool m_doAutoSelection; /* switch auto-selection on and off */
|
|
int m_autoSelThresh; /* threshold for auto selection */
|
|
int m_dustsize; /* dustsize for auto selection */
|
|
|
|
bool m_bgIsWhite; /* indicates if a scan without paper
|
|
* results in black or white */
|
|
TQSlider *m_sliderThresh;
|
|
TQSlider *m_sliderDust;
|
|
TQCheckBox *m_cbAutoSel;
|
|
TQComboBox *m_cbBackground;
|
|
TQGroupBox *m_autoSelGroup;
|
|
KScanDevice *m_scanner;
|
|
|
|
TQMemArray<long> m_heightSum;
|
|
TQMemArray<long> m_widthSum;
|
|
};
|
|
|
|
Previewer::Previewer(TQWidget *parent, const char *name )
|
|
: TQWidget(parent,name)
|
|
{
|
|
d = new PreviewerPrivate();
|
|
|
|
// beautification to look like the left scanparams widget in the dialog
|
|
TQHBoxLayout *htop = new TQHBoxLayout( this );
|
|
TQFrame *frame = new TQFrame( this );
|
|
frame->setFrameStyle( TQFrame::Panel | TQFrame::Raised );
|
|
frame->setLineWidth( 1 );
|
|
htop->addWidget( frame );
|
|
|
|
TQVBoxLayout *top = new TQVBoxLayout( frame, KDialog::marginHint(), KDialog::spacingHint() );
|
|
layout = new TQHBoxLayout( KDialog::spacingHint() );
|
|
top->addLayout( layout, 9 );
|
|
TQVBoxLayout *left = new TQVBoxLayout( KDialog::spacingHint() );
|
|
layout->addLayout( left, 2 );
|
|
|
|
/* Load autoselection values from Config file */
|
|
TDEConfig *cfg = TDEGlobal::config();
|
|
cfg->setGroup( GROUP_STARTUP );
|
|
|
|
/* Units etc. TODO: get from Config */
|
|
sizeUnit = KRuler::Millimetres;
|
|
displayUnit = sizeUnit;
|
|
d->m_autoSelThresh = 240;
|
|
|
|
overallHeight = 295; /* Default DIN A4 */
|
|
overallWidth = 210;
|
|
kdDebug(29000) << "Previewer: got Overallsize: " <<
|
|
overallWidth << " x " << overallHeight << endl;
|
|
img_canvas = new ImageCanvas( frame );
|
|
|
|
img_canvas->setDefaultScaleKind( ImageCanvas::DYNAMIC );
|
|
img_canvas->enableContextMenu(true);
|
|
img_canvas->repaint();
|
|
layout->addWidget( img_canvas, 6 );
|
|
|
|
/* Actions for the previewer zoom */
|
|
TDEAction *act;
|
|
act = new TDEAction(i18n("Scale to W&idth"), "scaletowidth", CTRL+Key_I,
|
|
this, TQ_SLOT( slScaleToWidth()), this, "preview_scaletowidth" );
|
|
act->plug( img_canvas->contextMenu());
|
|
|
|
act = new TDEAction(i18n("Scale to &Height"), "scaletoheight", CTRL+Key_H,
|
|
this, TQ_SLOT( slScaleToHeight()), this, "preview_scaletoheight" );
|
|
act->plug( img_canvas->contextMenu());
|
|
|
|
/*Signals: Control the custom-field and show size of selection */
|
|
connect( img_canvas, TQ_SIGNAL(newRect()), this, TQ_SLOT(slCustomChange()));
|
|
connect( img_canvas, TQ_SIGNAL(newRect(TQRect)), this, TQ_SLOT(slNewDimen(TQRect)));
|
|
|
|
/* Stuff for the preview-Notification */
|
|
left->addWidget( new TQLabel( i18n("<B>Preview</B>"), frame ), 1);
|
|
|
|
// Create a button group to contain buttons for Portrait/Landscape
|
|
bgroup = new TQVButtonGroup( i18n("Scan Size"), frame );
|
|
|
|
// -----
|
|
pre_format_combo = new TQComboBox( frame, "PREVIEWFORMATCOMBO" );
|
|
pre_format_combo->insertItem( i18n( "Custom" ), ID_CUSTOM);
|
|
pre_format_combo->insertItem( i18n( "DIN A4" ), ID_A4);
|
|
pre_format_combo->insertItem( i18n( "DIN A5" ), ID_A5);
|
|
pre_format_combo->insertItem( i18n( "DIN A6" ), ID_A6);
|
|
pre_format_combo->insertItem( i18n( "9x13 cm" ), ID_9_13 );
|
|
pre_format_combo->insertItem( i18n( "10x15 cm" ), ID_10_15 );
|
|
pre_format_combo->insertItem( i18n( "Letter" ), ID_LETTER);
|
|
|
|
connect( pre_format_combo, TQ_SIGNAL(activated (int)),
|
|
this, TQ_SLOT( slFormatChange(int)));
|
|
|
|
left->addWidget( pre_format_combo, 1 );
|
|
|
|
/** Potrait- and Landscape Selector **/
|
|
TQFontMetrics fm = bgroup->fontMetrics();
|
|
int w = fm.width( (const TQString)i18n(" Landscape " ) );
|
|
int h = fm.height( );
|
|
|
|
rb1 = new TQRadioButton( i18n("&Landscape"), bgroup );
|
|
landscape_id = bgroup->id( rb1 );
|
|
rb2 = new TQRadioButton( i18n("P&ortrait"), bgroup );
|
|
portrait_id = bgroup->id( rb2 );
|
|
bgroup->setButton( portrait_id );
|
|
|
|
connect(bgroup, TQ_SIGNAL(clicked(int)), this, TQ_SLOT(slOrientChange(int)));
|
|
|
|
int rblen = 5+w+12; // 12 for the button?
|
|
rb1->setGeometry( 5, 6, rblen, h );
|
|
rb2->setGeometry( 5, 1+h/2+h, rblen, h );
|
|
|
|
left->addWidget( bgroup, 2 );
|
|
|
|
|
|
/** Autoselection Box **/
|
|
d->m_autoSelGroup = new TQGroupBox( 1,TQt::Horizontal, i18n("Auto-Selection"), frame);
|
|
|
|
TQHBox *hbox = new TQHBox(d->m_autoSelGroup);
|
|
d->m_cbAutoSel = new TQCheckBox( i18n("Active on"), hbox );
|
|
TQToolTip::add( d->m_cbAutoSel, i18n("Check here if you want autodetection\n"
|
|
"of the document on the preview."));
|
|
|
|
/* combobox to select if black or white background */
|
|
d->m_cbBackground = new TQComboBox( hbox );
|
|
d->m_cbBackground->insertItem(i18n("Black"), BG_ITEM_BLACK );
|
|
d->m_cbBackground->insertItem(i18n("White"), BG_ITEM_WHITE );
|
|
connect( d->m_cbBackground, TQ_SIGNAL(activated(int) ),
|
|
this, TQ_SLOT( slScanBackgroundChanged( int )));
|
|
|
|
|
|
TQToolTip::add( d->m_cbBackground,
|
|
i18n("Select whether a scan of the empty\n"
|
|
"scanner glass results in a\n"
|
|
"black or a white image."));
|
|
connect( d->m_cbAutoSel, TQ_SIGNAL(toggled(bool) ), TQ_SLOT(slAutoSelToggled(bool)));
|
|
|
|
(void) new TQLabel( i18n("scanner background"), d->m_autoSelGroup );
|
|
|
|
TQLabel *l1= new TQLabel( i18n("Thresh&old:"), d->m_autoSelGroup );
|
|
d->m_sliderThresh = new TQSlider( 0, 254, 10, d->m_autoSelThresh, TQt::Horizontal,
|
|
d->m_autoSelGroup );
|
|
connect( d->m_sliderThresh, TQ_SIGNAL(valueChanged(int)), TQ_SLOT(slSetAutoSelThresh(int)));
|
|
TQToolTip::add( d->m_sliderThresh,
|
|
i18n("Threshold for autodetection.\n"
|
|
"All pixels higher (on black background)\n"
|
|
"or smaller (on white background)\n"
|
|
"than this are considered to be part of the image."));
|
|
l1->setBuddy(d->m_sliderThresh);
|
|
|
|
#if 0 /** Dustsize-Slider: No deep impact on result **/
|
|
(void) new TQLabel( i18n("Dust size:"), grBox );
|
|
d->m_sliderDust = new TQSlider( 0, 50, 5, d->m_dustsize, TQt::Horizontal, grBox );
|
|
connect( d->m_sliderDust, TQ_SIGNAL(valueChanged(int)), TQ_SLOT(slSetAutoSelDustsize(int)));
|
|
#endif
|
|
|
|
/* disable Autoselbox as long as no scanner is connected */
|
|
d->m_autoSelGroup->setEnabled(false);
|
|
|
|
left->addWidget(d->m_autoSelGroup);
|
|
|
|
/* Labels for the dimension */
|
|
TQGroupBox *gbox = new TQGroupBox( 1,TQt::Horizontal, i18n("Selection"), frame, "GROUPBOX" );
|
|
|
|
TQLabel *l2 = new TQLabel( i18n("width - mm" ), gbox );
|
|
TQLabel *l3 = new TQLabel( i18n("height - mm" ), gbox );
|
|
|
|
connect( this, TQ_SIGNAL(setScanWidth(const TQString&)),
|
|
l2, TQ_SLOT(setText(const TQString&)));
|
|
connect( this, TQ_SIGNAL(setScanHeight(const TQString&)),
|
|
l3, TQ_SLOT(setText(const TQString&)));
|
|
|
|
/* size indicator */
|
|
TQHBox *hb = new TQHBox( gbox );
|
|
(void) new TQLabel( i18n( "Size:"), hb );
|
|
SizeIndicator *indi = new SizeIndicator( hb );
|
|
TQToolTip::add( indi, i18n( "This size field shows how large the uncompressed image will be.\n"
|
|
"It tries to warn you, if you try to produce huge images by \n"
|
|
"changing its background color." ));
|
|
indi->setText( i18n("-") );
|
|
|
|
connect( this, TQ_SIGNAL( setSelectionSize(long)),
|
|
indi, TQ_SLOT( setSizeInByte (long)) );
|
|
|
|
left->addWidget( gbox, 1 );
|
|
|
|
left->addStretch( 6 );
|
|
|
|
top->activate();
|
|
|
|
/* Preset custom Cutting */
|
|
pre_format_combo->setCurrentItem( ID_CUSTOM );
|
|
slFormatChange( ID_CUSTOM);
|
|
|
|
scanResX = -1;
|
|
scanResY = -1;
|
|
pix_per_byte = 1;
|
|
|
|
selectionWidthMm = 0.0;
|
|
selectionHeightMm = 0.0;
|
|
recalcFileSize();
|
|
}
|
|
|
|
Previewer::~Previewer()
|
|
{
|
|
delete d;
|
|
}
|
|
|
|
bool Previewer::setPreviewImage( const TQImage &image )
|
|
{
|
|
if ( image.isNull() )
|
|
return false;
|
|
|
|
m_previewImage = image;
|
|
img_canvas->newImage( &m_previewImage );
|
|
|
|
return true;
|
|
}
|
|
|
|
TQString Previewer::galleryRoot()
|
|
{
|
|
TQString dir = (TDEGlobal::dirs())->saveLocation( "data", "ScanImages", true );
|
|
|
|
if( !dir.endsWith("/") )
|
|
dir += "/";
|
|
|
|
return( dir );
|
|
|
|
}
|
|
|
|
void Previewer::newImage( TQImage *ni )
|
|
{
|
|
/* image canvas does not copy the image, so we hold a copy here */
|
|
m_previewImage = *ni;
|
|
|
|
/* clear the auto detection arrays */
|
|
d->m_heightSum.resize( 0 );
|
|
d->m_widthSum.resize( 0 );
|
|
|
|
img_canvas->newImage( &m_previewImage );
|
|
findSelection( );
|
|
}
|
|
|
|
void Previewer::setScanSize( int w, int h, KRuler::MetricStyle unit )
|
|
{
|
|
overallWidth = w;
|
|
overallHeight = h;
|
|
sizeUnit = unit;
|
|
}
|
|
|
|
|
|
void Previewer::slSetDisplayUnit( KRuler::MetricStyle unit )
|
|
{
|
|
displayUnit = unit;
|
|
}
|
|
|
|
|
|
void Previewer::slOrientChange( int id )
|
|
{
|
|
(void) id;
|
|
/* Gets either portrait or landscape-id */
|
|
/* Just read the format-selection and call slFormatChange */
|
|
slFormatChange( pre_format_combo->currentItem() );
|
|
}
|
|
|
|
/** Slot called whenever the format selection combo changes. **/
|
|
void Previewer::slFormatChange( int id )
|
|
{
|
|
TQPoint p(0,0);
|
|
bool lands_allowed;
|
|
bool portr_allowed;
|
|
bool setSelection = true;
|
|
int s_long = 0;
|
|
int s_short= 0;
|
|
|
|
isCustom = false;
|
|
|
|
switch( id )
|
|
{
|
|
case ID_LETTER:
|
|
s_long = 294;
|
|
s_short = 210;
|
|
lands_allowed = false;
|
|
portr_allowed = true;
|
|
break;
|
|
case ID_CUSTOM:
|
|
lands_allowed = false;
|
|
portr_allowed = false;
|
|
setSelection = false;
|
|
isCustom = true;
|
|
break;
|
|
case ID_A4:
|
|
s_long = 297;
|
|
s_short = 210;
|
|
lands_allowed = false;
|
|
portr_allowed = true;
|
|
break;
|
|
case ID_A5:
|
|
s_long = 210;
|
|
s_short = 148;
|
|
lands_allowed = true;
|
|
portr_allowed = true;
|
|
break;
|
|
case ID_A6:
|
|
s_long = 148;
|
|
s_short = 105;
|
|
lands_allowed = true;
|
|
portr_allowed = true;
|
|
break;
|
|
case ID_9_13:
|
|
s_long = 130;
|
|
s_short = 90;
|
|
lands_allowed = true;
|
|
portr_allowed = true;
|
|
break;
|
|
case ID_10_15:
|
|
s_long = 150;
|
|
s_short = 100;
|
|
lands_allowed = true;
|
|
portr_allowed = true;
|
|
break;
|
|
default:
|
|
lands_allowed = true;
|
|
portr_allowed = true;
|
|
setSelection = false;
|
|
break;
|
|
}
|
|
|
|
rb1->setEnabled( lands_allowed );
|
|
rb2->setEnabled( portr_allowed );
|
|
|
|
int format_id = bgroup->id( bgroup->selected() );
|
|
if( !lands_allowed && format_id == landscape_id )
|
|
{
|
|
bgroup->setButton( portrait_id );
|
|
format_id = portrait_id;
|
|
}
|
|
/* Convert the new dimension to a new TQRect and call slot in canvas */
|
|
if( setSelection )
|
|
{
|
|
TQRect newrect;
|
|
newrect.setRect( 0,0, p.y(), p.x() );
|
|
|
|
if( format_id == portrait_id )
|
|
{ /* Portrait Mode */
|
|
p = calcPercent( s_short, s_long );
|
|
kdDebug(29000) << "Now is portrait-mode" << endl;
|
|
}
|
|
else
|
|
{ /* Landscape-Mode */
|
|
p = calcPercent( s_long, s_short );
|
|
}
|
|
|
|
newrect.setWidth( p.x() );
|
|
newrect.setHeight( p.y() );
|
|
|
|
img_canvas->newRectSlot( newrect );
|
|
}
|
|
}
|
|
|
|
/* This is called when the user fiddles around in the image.
|
|
* This makes the selection custom-sized immediately.
|
|
*/
|
|
void Previewer::slCustomChange( void )
|
|
{
|
|
if( isCustom )return;
|
|
pre_format_combo->setCurrentItem(ID_CUSTOM);
|
|
slFormatChange( ID_CUSTOM );
|
|
}
|
|
|
|
|
|
void Previewer::slNewScanResolutions( int x, int y )
|
|
{
|
|
kdDebug(29000) << "got new Scan Resolutions: " << x << "|" << y << endl;
|
|
scanResX = x;
|
|
scanResY = y;
|
|
|
|
recalcFileSize();
|
|
}
|
|
|
|
|
|
/* This slot is called with the new dimension for the selection
|
|
* in values between 0..1000. It emits signals, that redraw the
|
|
* size labels.
|
|
*/
|
|
void Previewer::slNewDimen(TQRect r)
|
|
{
|
|
if( r.height() > 0)
|
|
selectionWidthMm = (overallWidth / 1000 * r.width());
|
|
if( r.width() > 0)
|
|
selectionHeightMm = (overallHeight / 1000 * r.height());
|
|
|
|
TQString s;
|
|
s = i18n("width %1 mm").arg( int(selectionWidthMm));
|
|
emit(setScanWidth(s));
|
|
|
|
kdDebug(29000) << "Setting new Dimension " << s << endl;
|
|
s = i18n("height %1 mm").arg(int(selectionHeightMm));
|
|
emit(setScanHeight(s));
|
|
|
|
recalcFileSize( );
|
|
|
|
}
|
|
|
|
void Previewer::recalcFileSize( void )
|
|
{
|
|
/* Calculate file size */
|
|
long size_in_byte = 0;
|
|
if( scanResY > -1 && scanResX > -1 )
|
|
{
|
|
double w_inch = ((double) selectionWidthMm) / 25.4;
|
|
double h_inch = ((double) selectionHeightMm) / 25.4;
|
|
|
|
int pix_w = int( w_inch * double( scanResX ));
|
|
int pix_h = int( h_inch * double( scanResY ));
|
|
|
|
size_in_byte = pix_w * pix_h / pix_per_byte;
|
|
}
|
|
|
|
emit( setSelectionSize( size_in_byte ));
|
|
}
|
|
|
|
|
|
TQPoint Previewer::calcPercent( int w_mm, int h_mm )
|
|
{
|
|
TQPoint p(0,0);
|
|
if( overallWidth < 1.0 || overallHeight < 1.0 ) return( p );
|
|
|
|
if( sizeUnit == KRuler::Millimetres ) {
|
|
p.setX( static_cast<int>(1000.0*w_mm / overallWidth) );
|
|
p.setY( static_cast<int>(1000.0*h_mm / overallHeight) );
|
|
} else {
|
|
kdDebug(29000) << "ERROR: Only mm supported yet !" << endl;
|
|
}
|
|
return( p );
|
|
|
|
}
|
|
|
|
void Previewer::slScaleToWidth()
|
|
{
|
|
if( img_canvas )
|
|
{
|
|
img_canvas->handle_popup( ImageCanvas::ID_FIT_WIDTH );
|
|
}
|
|
}
|
|
|
|
void Previewer::slScaleToHeight()
|
|
{
|
|
if( img_canvas )
|
|
{
|
|
img_canvas->handle_popup( ImageCanvas::ID_FIT_HEIGHT);
|
|
}
|
|
}
|
|
|
|
void Previewer::slConnectScanner( KScanDevice *scan )
|
|
{
|
|
kdDebug(29000) << "Connecting scan device!" << endl;
|
|
d->m_scanner = scan;
|
|
|
|
if( scan )
|
|
{
|
|
/* Enable the by-default disabled autoselection group */
|
|
d->m_autoSelGroup->setEnabled(true);
|
|
TQString h;
|
|
|
|
h = scan->getConfig( CFG_AUTOSEL_DO, TQString("unknown") );
|
|
if( h == TQString("on") )
|
|
d->m_cbAutoSel->setChecked(true);
|
|
else
|
|
d->m_cbAutoSel->setChecked(false);
|
|
|
|
TQString isWhite = d->m_scanner->getConfig( CFG_SCANNER_EMPTY_BG, "unknown" );
|
|
|
|
h = scan->getConfig( CFG_AUTOSEL_DUSTSIZE, TQString("5") );
|
|
d->m_dustsize = h.toInt();
|
|
|
|
TQString thresh = DEF_THRESH_BLACK; /* for black */
|
|
if( isWhite.lower() == "yes" )
|
|
thresh = DEF_THRESH_WHITE;
|
|
|
|
h = scan->getConfig( CFG_AUTOSEL_THRESH, thresh );
|
|
d->m_sliderThresh->setValue( h.toInt() );
|
|
}
|
|
}
|
|
|
|
void Previewer::slSetScannerBgIsWhite( bool b )
|
|
{
|
|
d->m_bgIsWhite = b;
|
|
|
|
if( d->m_scanner )
|
|
{
|
|
if( b ) // The background _is_ white
|
|
{
|
|
d->m_cbBackground->setCurrentItem( BG_ITEM_WHITE );
|
|
}
|
|
else
|
|
{
|
|
d->m_cbBackground->setCurrentItem( BG_ITEM_BLACK );
|
|
}
|
|
|
|
d->m_scanner->slStoreConfig( CFG_SCANNER_EMPTY_BG, b ? TQString("Yes") : TQString("No"));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* reads the scanner dependant config file through the m_scanner pointer.
|
|
* If a value for the scanner is not yet known, the function starts up a
|
|
* popup and asks the user. The result is stored.
|
|
*/
|
|
void Previewer::checkForScannerBg()
|
|
{
|
|
if( d->m_scanner ) /* Is the scan device already known? */
|
|
{
|
|
TQString isWhite = d->m_scanner->getConfig( CFG_SCANNER_EMPTY_BG, "unknown" );
|
|
bool goWhite = false;
|
|
if( isWhite == "unknown" )
|
|
{
|
|
/* not yet known, should ask the user. */
|
|
kdDebug(29000) << "Dont know the scanner background yet!" << endl;
|
|
|
|
goWhite = ( KMessageBox::questionYesNo( this,
|
|
i18n("The autodetection of images on the preview depends on the background color of the preview image (Think of a preview of an empty scanner).\nPlease select whether the background of the preview image is black or white"),
|
|
i18n("Image Autodetection"),
|
|
i18n("White"), i18n("Black") ) == KMessageBox::Yes );
|
|
kdDebug(29000) << "User said " << isWhite << endl;
|
|
|
|
}
|
|
else
|
|
{
|
|
if( isWhite.lower() == "yes" )
|
|
goWhite = true;
|
|
}
|
|
|
|
/* remember value */
|
|
slSetScannerBgIsWhite( goWhite );
|
|
}
|
|
}
|
|
|
|
void Previewer::slScanBackgroundChanged( int indx )
|
|
{
|
|
slSetScannerBgIsWhite( indx == BG_ITEM_WHITE );
|
|
}
|
|
|
|
void Previewer::slAutoSelToggled(bool isOn )
|
|
{
|
|
if( isOn )
|
|
checkForScannerBg();
|
|
|
|
if( d->m_cbAutoSel )
|
|
{
|
|
TQRect r = img_canvas->sel();
|
|
|
|
kdDebug(29000) << "The rect is " << r.width() << " x " << r.height() << endl;
|
|
d->m_doAutoSelection = isOn;
|
|
|
|
/* Store configuration */
|
|
if( d->m_scanner )
|
|
{
|
|
d->m_scanner->slStoreConfig( CFG_AUTOSEL_DO,
|
|
isOn ? "on" : "off" );
|
|
}
|
|
|
|
if( isOn && r.width() < 2 && r.height() < 2) /* There is no selection yet */
|
|
{
|
|
/* if there is already an image, check, if the bg-color is set already */
|
|
if( img_canvas->rootImage() )
|
|
{
|
|
kdDebug(29000) << "No selection -> try to find one!" << endl;
|
|
|
|
findSelection();
|
|
}
|
|
|
|
}
|
|
}
|
|
if( d->m_sliderThresh )
|
|
d->m_sliderThresh->setEnabled(isOn);
|
|
if( d->m_sliderDust )
|
|
d->m_sliderDust->setEnabled(isOn);
|
|
if( d->m_cbBackground )
|
|
d->m_cbBackground->setEnabled(isOn);
|
|
|
|
}
|
|
|
|
|
|
void Previewer::slSetAutoSelThresh(int t)
|
|
{
|
|
d->m_autoSelThresh = t;
|
|
kdDebug(29000) << "Setting threshold to " << t << endl;
|
|
if( d->m_scanner )
|
|
d->m_scanner->slStoreConfig( CFG_AUTOSEL_THRESH, TQString::number(t) );
|
|
findSelection();
|
|
}
|
|
|
|
void Previewer::slSetAutoSelDustsize(int dSize)
|
|
{
|
|
d->m_dustsize = dSize;
|
|
kdDebug(29000) << "Setting dustsize to " << dSize << endl;
|
|
findSelection();
|
|
}
|
|
|
|
/**
|
|
* This method tries to find a selection on the preview image automatically.
|
|
* It uses the image of the preview image canvas, the previewer global
|
|
* threshold setting and a dustsize.
|
|
**/
|
|
void Previewer::findSelection( )
|
|
{
|
|
kdDebug(29000) << "Searching Selection" << endl;
|
|
|
|
kdDebug(29000) << "Threshold: " << d->m_autoSelThresh << endl;
|
|
kdDebug(29000) << "dustsize: " << d->m_dustsize << endl;
|
|
kdDebug(29000) << "isWhite: " << d->m_bgIsWhite << endl;
|
|
|
|
|
|
if( ! d->m_doAutoSelection ) return;
|
|
int line;
|
|
int x;
|
|
const TQImage *img = img_canvas->rootImage();
|
|
if( ! img ) return;
|
|
|
|
long iWidth = img->width();
|
|
long iHeight = img->height();
|
|
|
|
TQMemArray<long> heightSum;
|
|
TQMemArray<long> widthSum;
|
|
|
|
kdDebug(29000)<< "Preview size is " << iWidth << "x" << iHeight << endl;
|
|
|
|
if( (d->m_heightSum).size() == 0 && (iHeight>0) )
|
|
{
|
|
kdDebug(29000) << "Starting to fill Array " << endl;
|
|
TQMemArray<long> heightSum(iHeight);
|
|
TQMemArray<long> widthSum(iWidth);
|
|
heightSum.fill(0);
|
|
widthSum.fill(0);
|
|
|
|
kdDebug(29000) << "filled Array with zero " << endl;
|
|
|
|
for( line = 0; line < iHeight; line++ )
|
|
{
|
|
|
|
for( x = 0; x < iWidth; x++ )
|
|
{
|
|
int gray = tqGray( img->pixel( x, line ));
|
|
// kdDebug(29000) << "Gray-Value at line " << gray << endl;
|
|
Q_ASSERT( line < iHeight );
|
|
Q_ASSERT( x < iWidth );
|
|
int hsum = heightSum.at(line);
|
|
int wsum = widthSum.at(x);
|
|
|
|
heightSum[line] = hsum+gray;
|
|
widthSum [x] = wsum+gray;
|
|
}
|
|
heightSum[line] = heightSum[line]/iWidth;
|
|
}
|
|
/* Divide by amount of pixels */
|
|
kdDebug(29000) << "Resizing now" << endl;
|
|
for( x = 0; x < iWidth; x++ )
|
|
widthSum[x] = widthSum[x]/iHeight;
|
|
|
|
kdDebug(29000) << "Filled Arrays successfully" << endl;
|
|
d->m_widthSum = widthSum;
|
|
d->m_heightSum = heightSum;
|
|
}
|
|
/* Now try to find values in arrays that have grayAdds higher or lower
|
|
* than threshold */
|
|
#if 0
|
|
/* debug output */
|
|
{
|
|
TQFile fi( "/tmp/thheight.dat");
|
|
if( fi.open( IO_ReadWrite ) ) {
|
|
TQTextStream str( &fi );
|
|
|
|
str << "# height ##################" << endl;
|
|
for( x = 0; x < iHeight; x++ )
|
|
str << x << '\t' << d->m_heightSum[x] << endl;
|
|
fi.close();
|
|
}
|
|
}
|
|
TQFile fi1( "/tmp/thwidth.dat");
|
|
if( fi1.open( IO_ReadWrite ))
|
|
{
|
|
TQTextStream str( &fi1 );
|
|
str << "# width ##################" << endl;
|
|
str << "# " << iWidth << " points" << endl;
|
|
for( x = 0; x < iWidth; x++ )
|
|
str << x << '\t' << d->m_widthSum[x] << endl;
|
|
|
|
fi1.close();
|
|
}
|
|
#endif
|
|
int start = 0;
|
|
int end = 0;
|
|
TQRect r;
|
|
|
|
/** scale to 0..1000 range **/
|
|
start = 0;
|
|
end = 0;
|
|
imagePiece( d->m_heightSum, start, end ); // , d->m_threshold, d->m_dustsize, false );
|
|
|
|
r.setTop( 1000*start/iHeight );
|
|
r.setBottom( 1000*end/iHeight);
|
|
// r.setTop( start );
|
|
// r.setBottom( end );
|
|
|
|
start = 0;
|
|
end = 0;
|
|
imagePiece( d->m_widthSum, start, end ); // , d->m_threshold, d->m_dustsize, false );
|
|
r.setLeft( 1000*start/iWidth );
|
|
r.setRight( 1000*end/iWidth );
|
|
// r.setLeft( start );
|
|
// r.setRight( end );
|
|
|
|
kdDebug(29000) << " -- Autodetection -- " << endl;
|
|
kdDebug(29000) << "Area top " << r.top() << endl;
|
|
kdDebug(29000) << "Area left" << r.left() << endl;
|
|
kdDebug(29000) << "Area bottom " << r.bottom() << endl;
|
|
kdDebug(29000) << "Area right " << r.right() << endl;
|
|
kdDebug(29000) << "Area width " << r.width() << endl;
|
|
kdDebug(29000) << "Area height " << r.height() << endl;
|
|
|
|
img_canvas->newRectSlot( r );
|
|
slCustomChange();
|
|
}
|
|
|
|
|
|
/*
|
|
* returns an Array containing the
|
|
*/
|
|
bool Previewer::imagePiece( TQMemArray<long> src, int& start, int& end )
|
|
{
|
|
for( uint x = 0; x < src.size(); x++ )
|
|
{
|
|
if( !d->m_bgIsWhite )
|
|
{
|
|
/* pixelvalue needs to be higher than threshold, white background */
|
|
if( src[x] > d->m_autoSelThresh )
|
|
{
|
|
/* Ok this pixel could be the start */
|
|
int iStart = x;
|
|
int iEnd = x;
|
|
x++;
|
|
while( x < src.size() && src[x] > d->m_autoSelThresh )
|
|
{
|
|
x++;
|
|
}
|
|
iEnd = x;
|
|
|
|
int delta = iEnd-iStart;
|
|
|
|
if( delta > d->m_dustsize && end-start < delta )
|
|
{
|
|
start = iStart;
|
|
end = iEnd;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* pixelvalue needs to be lower than threshold, black background */
|
|
if( src[x] < d->m_autoSelThresh )
|
|
{
|
|
int iStart = x;
|
|
int iEnd = x;
|
|
x++;
|
|
while( x < src.size() && src[x] < d->m_autoSelThresh )
|
|
{
|
|
x++;
|
|
}
|
|
iEnd = x;
|
|
|
|
int delta = iEnd-iStart;
|
|
|
|
if( delta > d->m_dustsize && end-start < delta )
|
|
{
|
|
start = iStart;
|
|
end = iEnd;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return (end-start)>0;
|
|
}
|
|
|
|
#include "previewer.moc"
|