/* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2004-07-13 * Description : image editor printing interface. * * Copyright (C) 2006 by F.J. Cruz * Copyright (C) 2004-2007 by Gilles Caulier * * KeepRatio and Alignment options imported from Gwenview program. * Copyright (c) 2003 Angelo Naselli * * Original printing code from Kuickshow program. * Copyright (C) 2002 Carsten Pfeiffer * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program 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 General Public License for more details. * * ============================================================ */ // TQt includes. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // KDE includes. #include #include #include #include #include #include #include #include #include #include #include #include // Local includes. #include "ddebug.h" #include "dimg.h" #include "editorwindow.h" #include "icctransform.h" #include "imageprint.h" #include "imageprint.moc" namespace Digikam { class ImagePrintPrivate { public: ImagePrintPrivate(){} TQString filename; TQString inProfilePath; TQString outputProfilePath; DImg image; }; ImagePrint::ImagePrint(DImg& image, KPrinter& printer, const TQString& filename) : m_printer(printer) { d = new ImagePrintPrivate(); d->image = image; d->filename = filename; } ImagePrint::~ImagePrint() { delete d; } bool ImagePrint::printImageWithTQt() { if ( d->image.isNull() ) { DWarning() << "Supplied Image for printing is null" << endl; return false; } TQString t = "true"; TQString f = "false"; if (m_printer.option( "app-imageeditor-color-managed") != f) { IccTransform *transform = new IccTransform(); readSettings(); if (d->image.getICCProfil().isNull()) { transform->setProfiles( d->inProfilePath, d->outputProfilePath ); } else { transform->setProfiles(d->outputProfilePath); } transform->apply( d->image ); } TQImage image2Print = d->image.copyTQImage(); // Black & white print ? if ( m_printer.option( "app-imageeditor-blackwhite" ) != f) { image2Print = image2Print.convertDepth( 1, TQt::MonoOnly | TQt::ThresholdDither | TQt::AvoidDither ); } TQPainter p; p.begin( &m_printer ); TQPaintDeviceMetrics metrics( &m_printer ); p.setFont( TDEGlobalSettings::generalFont() ); TQFontMetrics fm = p.fontMetrics(); int w, h; // will be set to the width and height of the printer // when the orientation is decided. w = metrics.width(); h = metrics.height(); int filenameOffset = 0; TQSize size = image2Print.size(); bool printFilename = m_printer.option( "app-imageeditor-printFilename" ) != f; if ( printFilename ) { // filename goes into one line! filenameOffset = fm.lineSpacing() + 14; h -= filenameOffset; } if ( m_printer.option( "app-imageeditor-scaleToFit" ) != f ) { if ( m_printer.option( "app-imageeditor-auto-rotate" ) == t ) m_printer.setOrientation( size.width() <= size.height() ? KPrinter::Portrait : KPrinter::Landscape ); // Scale image to fit pagesize size.scale( w, h, TQSize::ScaleMin ); } else { int unit = (m_printer.option("app-imageeditor-scale-unit").isEmpty() ? ImageEditorPrintDialogPage::DK_INCHES : m_printer.option("app-imageeditor-scale-unit").toInt()); double inches = 1; if (unit == ImageEditorPrintDialogPage::DK_MILLIMETERS) { inches = 1/25.4; } else if (unit == ImageEditorPrintDialogPage::DK_CENTIMETERS) { inches = 1/2.54; } double wImg = (m_printer.option("app-imageeditor-scale-width").isEmpty() ? 1 : m_printer.option("app-imageeditor-scale-width").toDouble()) * inches; double hImg = (m_printer.option("app-imageeditor-scale-height").isEmpty() ? 1 : m_printer.option("app-imageeditor-scale-height").toDouble()) * inches; size.setWidth( int(wImg * m_printer.resolution()) ); size.setHeight( int(hImg * m_printer.resolution()) ); if ( m_printer.option( "app-imageeditor-auto-rotate" ) == t ) m_printer.setOrientation( wImg <= hImg ? KPrinter::Portrait : KPrinter::Landscape ); if (size.width() > w || size.height() > h) { int resp = KMessageBox::warningYesNoCancel(TDEApplication::kApplication()->mainWidget(), i18n("The image will not fit on the page, what do you want to do?"), TQString(),KStdGuiItem::cont(), i18n("Shrink") ); if (resp==KMessageBox::Cancel) { m_printer.abort(); // no need to return false, user decided to abort return true; } else if (resp == KMessageBox::No) { // Shrink size.scale(w, h, TQSize::ScaleMin); } } } // Align image. int alignment = (m_printer.option("app-imageeditor-alignment").isEmpty() ? TQt::AlignCenter : m_printer.option("app-imageeditor-alignment").toInt()); int x = 0; int y = 0; // x - alignment if ( alignment & TQt::AlignHCenter ) x = (w - size.width())/2; else if ( alignment & TQt::AlignLeft ) x = 0; else if ( alignment & TQt::AlignRight ) x = w - size.width(); // y - alignment if ( alignment & TQt::AlignVCenter ) y = (h - size.height())/2; else if ( alignment & TQt::AlignTop ) y = 0; else if ( alignment & TQt::AlignBottom ) y = h - size.height(); // Perform the actual drawing. p.drawImage( TQRect( x, y, size.width(), size.height()), image2Print ); if ( printFilename ) { TQString fname = minimizeString( d->filename, fm, w ); if ( !fname.isEmpty() ) { int fw = fm.width( fname ); int x = (w - fw)/2; int y = metrics.height() - filenameOffset/2; p.drawText( x, y, fname ); } } p.end(); return true; } TQString ImagePrint::minimizeString( TQString text, const TQFontMetrics& metrics, int maxWidth ) { // no sense to cut that tiny little string if ( text.length() <= 5 ) return TQString(); bool changed = false; while ( metrics.width( text ) > maxWidth ) { int mid = text.length() / 2; // remove 2 characters in the middle text.remove( mid, 2 ); changed = true; } // add "..." in the middle if ( changed ) { int mid = text.length() / 2; // sanity check if ( mid <= 5 ) return TQString(); text.replace( mid - 1, 3, "..." ); } return text; } void ImagePrint::readSettings() { TDEConfig* config = kapp->config(); config->setGroup("Color Management"); d->inProfilePath = config->readPathEntry("WorkSpaceProfile"); d->outputProfilePath = config->readPathEntry("ProofProfileFile"); } // Image print dialog class ------------------------------------------------------------- class ImageEditorPrintDialogPagePrivate { public: ImageEditorPrintDialogPagePrivate() { cmEnabled = false; position = 0; keepRatio = 0; scaleToFit = 0; scale = 0; addFileName = 0; blackwhite = 0; autoRotate = 0; colorManaged = 0; cmPreferences = 0; parent = 0; width = 0; height = 0; units = 0; } bool cmEnabled; TQRadioButton *scaleToFit; TQRadioButton *scale; TQCheckBox *keepRatio; TQCheckBox *addFileName; TQCheckBox *blackwhite; TQCheckBox *autoRotate; TQCheckBox *colorManaged; TQPushButton *cmPreferences; TQWidget *parent; KDoubleNumInput *width; KDoubleNumInput *height; KComboBox *position; KComboBox *units; DImg image; ImageEditorPrintDialogPage::Unit previousUnit; }; ImageEditorPrintDialogPage::ImageEditorPrintDialogPage(DImg& image, TQWidget *parent, const char *name ) : KPrintDialogPage( parent, name ) { d = new ImageEditorPrintDialogPagePrivate; d->image = image; d->parent = parent; setTitle( i18n("Image Settings") ); readSettings(); TQVBoxLayout *layout = new TQVBoxLayout( this ); layout->setMargin( KDialog::marginHint() ); layout->setSpacing( KDialog::spacingHint() ); // ------------------------------------------------------------------------ TQHBoxLayout *layout2 = new TQHBoxLayout( layout ); layout2->setSpacing(3); TQLabel* textLabel = new TQLabel( this, "Image position:" ); textLabel->setText( i18n( "Image position:" ) ); layout2->addWidget( textLabel ); d->position = new KComboBox( false, this, "Print position" ); d->position->clear(); d->position->insertItem( i18n( "Top-Left" ) ); d->position->insertItem( i18n( "Top-Central" ) ); d->position->insertItem( i18n( "Top-Right" ) ); d->position->insertItem( i18n( "Central-Left" ) ); d->position->insertItem( i18n( "Central" ) ); d->position->insertItem( i18n( "Central-Right" ) ); d->position->insertItem( i18n( "Bottom-Left" ) ); d->position->insertItem( i18n( "Bottom-Central" ) ); d->position->insertItem( i18n( "Bottom-Right" ) ); layout2->addWidget( d->position ); TQSpacerItem *spacer1 = new TQSpacerItem( 101, 21, TQSizePolicy::Expanding, TQSizePolicy::Minimum ); layout2->addItem( spacer1 ); d->addFileName = new TQCheckBox( i18n("Print fi&lename below image"), this); d->addFileName->setChecked( false ); layout->addWidget( d->addFileName ); d->blackwhite = new TQCheckBox ( i18n("Print image in &black and white"), this); d->blackwhite->setChecked( false ); layout->addWidget (d->blackwhite ); d->autoRotate = new TQCheckBox( i18n("&Auto-rotate page"), this ); d->autoRotate->setChecked( false ); layout->addWidget( d->autoRotate ); // ------------------------------------------------------------------------ TQHBox *cmbox = new TQHBox(this); d->colorManaged = new TQCheckBox(i18n("Use Color Management for Printing"), cmbox); d->colorManaged->setChecked( false ); d->cmPreferences = new TQPushButton(i18n("Settings..."), cmbox); TQWidget *space = new TQWidget(cmbox); cmbox->setStretchFactor(space, 10); cmbox->setSpacing(KDialog::spacingHint()); layout->addWidget(cmbox); // ------------------------------------------------------------------------ TQVButtonGroup *group = new TQVButtonGroup( i18n("Scaling"), this ); group->setRadioButtonExclusive( true ); layout->addWidget( group ); d->scaleToFit = new TQRadioButton( i18n("Scale image to &fit"), group ); d->scaleToFit->setChecked( true ); d->scale = new TQRadioButton( i18n("Print e&xact size: "), group ); TQHBox *hb = new TQHBox( group ); hb->setSpacing( KDialog::spacingHint() ); TQWidget *w = new TQWidget(hb); w->setFixedWidth(d->scale->style().subRect( TQStyle::SR_RadioButtonIndicator, d->scale ).width()); d->width = new KDoubleNumInput( hb, "exact width" ); d->width->setMinValue( 1 ); new TQLabel( "x", hb ); d->height = new KDoubleNumInput( hb, "exact height" ); d->height->setMinValue( 1 ); d->units = new KComboBox( false, hb, "unit combobox" ); d->units->insertItem( i18n("Millimeters") ); d->units->insertItem( i18n("Centimeters") ); d->units->insertItem( i18n("Inches") ); d->keepRatio = new TQCheckBox( i18n("Keep ratio"), hb); w = new TQWidget(hb); hb->setStretchFactor( w, 1 ); d->previousUnit = DK_MILLIMETERS; // ------------------------------------------------------------------------ connect( d->colorManaged, TQT_SIGNAL(toggled(bool)), this, TQT_SLOT(slotAlertSettings( bool )) ); connect( d->cmPreferences, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotSetupDlg()) ); connect( d->scale, TQT_SIGNAL( toggled( bool )), this, TQT_SLOT( toggleScaling( bool ))); connect(d->width, TQT_SIGNAL( valueChanged( double )), this, TQT_SLOT( slotWidthChanged( double ))); connect(d->height, TQT_SIGNAL( valueChanged( double )), this, TQT_SLOT( slotHeightChanged( double ))); connect(d->keepRatio, TQT_SIGNAL( toggled( bool )), this, TQT_SLOT( toggleRatio( bool ))); connect(d->units, TQT_SIGNAL(activated(const TQString &)), this, TQT_SLOT(slotUnitChanged(const TQString& ))); } ImageEditorPrintDialogPage::~ImageEditorPrintDialogPage() { delete d; } void ImageEditorPrintDialogPage::getOptions( TQMap& opts, bool /*incldef*/ ) { TQString t = "true"; TQString f = "false"; opts["app-imageeditor-alignment"] = TQString::number(getPosition(d->position->currentText())); opts["app-imageeditor-printFilename"] = d->addFileName->isChecked() ? t : f; opts["app-imageeditor-blackwhite"] = d->blackwhite->isChecked() ? t : f; opts["app-imageeditor-scaleToFit"] = d->scaleToFit->isChecked() ? t : f; opts["app-imageeditor-scale"] = d->scale->isChecked() ? t : f; opts["app-imageeditor-scale-unit"] = TQString::number(stringToUnit(d->units->currentText())); opts["app-imageeditor-scale-width"] = TQString::number( d->width->value() ); opts["app-imageeditor-scale-height"] = TQString::number( d->height->value() ); opts["app-imageeditor-scale-KeepRatio"] = d->keepRatio->isChecked() ? t : f; opts["app-imageeditor-auto-rotate"] = d->autoRotate->isChecked() ? t : f; opts["app-imageeditor-color-managed"] = d->colorManaged->isChecked() ? t : f; } void ImageEditorPrintDialogPage::setOptions( const TQMap& opts ) { TQString t = "true"; TQString f = "false"; TQString stVal; bool ok; double dVal; int iVal; iVal = opts["app-imageeditor-alignment"].toInt( &ok ); if (ok) { stVal = setPosition(iVal); d->position->setCurrentItem(stVal); } d->addFileName->setChecked( opts["app-imageeditor-printFilename"] != f ); // This sound strange, but if I copy the code on the line above, the checkbox // was always checked. And this is not the wanted behavior. So, with this works. // KPrint magic ;-) d->blackwhite->setChecked ( false ); d->scaleToFit->setChecked( opts["app-imageeditor-scaleToFit"] != f ); d->scale->setChecked( opts["app-imageeditor-scale"] == t ); d->autoRotate->setChecked( opts["app-imageeditor-auto-rotate"] == t ); d->colorManaged->setChecked( false ); Unit unit = static_cast( opts["app-imageeditor-scale-unit"].toInt( &ok ) ); if (ok) { stVal = unitToString(unit); d->units->setCurrentItem(stVal); d->previousUnit = unit; } else { //for back compatibility d->units->setCurrentItem(i18n("Millimeters")); } dVal = opts["app-imageeditor-scale-width"].toDouble( &ok ); if ( ok ) d->width->setValue( dVal ); dVal = opts["app-imageeditor-scale-height"].toDouble( &ok ); if ( ok ) d->height->setValue( dVal ); if ( d->scale->isChecked() == d->scaleToFit->isChecked() ) d->scaleToFit->setChecked( !d->scale->isChecked() ); d->keepRatio->setChecked( opts["app-imageeditor-scale-KeepRatio"] == t ); } int ImageEditorPrintDialogPage::getPosition(const TQString& align) { int alignment; if (align == i18n("Central-Left")) { alignment = TQt::AlignLeft | TQt::AlignVCenter; } else if (align == i18n("Central-Right")) { alignment = TQt::AlignRight | TQt::AlignVCenter; } else if (align == i18n("Top-Left")) { alignment = TQt::AlignTop | TQt::AlignLeft; } else if (align == i18n("Top-Right")) { alignment = TQt::AlignTop | TQt::AlignRight; } else if (align == i18n("Bottom-Left")) { alignment = TQt::AlignBottom | TQt::AlignLeft; } else if (align == i18n("Bottom-Right")) { alignment = TQt::AlignBottom | TQt::AlignRight; } else if (align == i18n("Top-Central")) { alignment = TQt::AlignTop | TQt::AlignHCenter; } else if (align == i18n("Bottom-Central")) { alignment = TQt::AlignBottom | TQt::AlignHCenter; } else { // Central alignment = TQt::AlignCenter; // TQt::AlignHCenter || TQt::AlignVCenter } return alignment; } TQString ImageEditorPrintDialogPage::setPosition(int align) { TQString alignment; if (align == (TQt::AlignLeft | TQt::AlignVCenter)) { alignment = i18n("Central-Left"); } else if (align == (TQt::AlignRight | TQt::AlignVCenter)) { alignment = i18n("Central-Right"); } else if (align == (TQt::AlignTop | TQt::AlignLeft)) { alignment = i18n("Top-Left"); } else if (align == (TQt::AlignTop | TQt::AlignRight)) { alignment = i18n("Top-Right"); } else if (align == (TQt::AlignBottom | TQt::AlignLeft)) { alignment = i18n("Bottom-Left"); } else if (align == (TQt::AlignBottom | TQt::AlignRight)) { alignment = i18n("Bottom-Right"); } else if (align == (TQt::AlignTop | TQt::AlignHCenter)) { alignment = i18n("Top-Central"); } else if (align == (TQt::AlignBottom | TQt::AlignHCenter)) { alignment = i18n("Bottom-Central"); } else { // Central: TQt::AlignCenter or (TQt::AlignHCenter || TQt::AlignVCenter) alignment = i18n("Central"); } return alignment; } void ImageEditorPrintDialogPage::toggleScaling( bool enable ) { d->width->setEnabled( enable ); d->height->setEnabled( enable ); d->units->setEnabled( enable ); d->keepRatio->setEnabled( enable ); } void ImageEditorPrintDialogPage::slotHeightChanged (double value) { d->width->blockSignals(true); d->height->blockSignals(true); if (d->keepRatio->isChecked()) { double width = (d->image.width() * value) / d->image.height(); d->width->setValue( width ? width : 1.); } d->height->setValue(value); d->width->blockSignals(false); d->height->blockSignals(false); } void ImageEditorPrintDialogPage::slotWidthChanged (double value) { d->width->blockSignals(true); d->height->blockSignals(true); if (d->keepRatio->isChecked()) { double height = (d->image.height() * value) / d->image.width(); d->height->setValue( height ? height : 1); } d->width->setValue(value); d->width->blockSignals(false); d->height->blockSignals(false); } void ImageEditorPrintDialogPage::toggleRatio( bool enable ) { if (!enable) return; // choosing a startup value of 15x10 cm (common photo dimention) // mContent->mHeight->value() or mContent->mWidth->value() // are usually empty at startup and hxw (0x0) is not good IMO keeping ratio double hValue, wValue; if (d->image.height() > d->image.width()) { hValue = d->height->value(); if (!hValue) hValue = 150*unitToMM(d->previousUnit); wValue = (d->image.width() * hValue)/ d->image.height(); } else { wValue = d->width->value(); if (!wValue) wValue = 150*unitToMM(d->previousUnit); hValue = (d->image.height() * wValue)/ d->image.width(); } d->width->blockSignals(true); d->height->blockSignals(true); d->width->setValue(wValue); d->height->setValue(hValue); d->width->blockSignals(false); d->height->blockSignals(false); } void ImageEditorPrintDialogPage::slotUnitChanged(const TQString& string) { Unit newUnit = stringToUnit(string); double ratio = unitToMM(d->previousUnit) / unitToMM(newUnit); d->width->blockSignals(true); d->height->blockSignals(true); d->width->setValue( d->width->value() * ratio); d->height->setValue( d->height->value() * ratio); d->width->blockSignals(false); d->height->blockSignals(false); d->previousUnit = newUnit; } void ImageEditorPrintDialogPage::readSettings() { TDEConfig* config = kapp->config(); config->setGroup("Color Management"); d->cmEnabled = config->readBoolEntry("EnableCM", false); } void ImageEditorPrintDialogPage::slotSetupDlg() { EditorWindow* editor = dynamic_cast(d->parent); editor->setup(true); } void ImageEditorPrintDialogPage::slotAlertSettings( bool t) { if (t && !d->cmEnabled) { TQString message = i18n("

Color Management is disabled.

\

You can enable it now by clicking on the \"Settings\" button.

"); KMessageBox::information(this, message); d->colorManaged->setChecked(!t); } } double ImageEditorPrintDialogPage::unitToMM(Unit unit) { if (unit == DK_MILLIMETERS) { return 1.; } else if (unit == DK_CENTIMETERS) { return 10.; } else { //DK_INCHES return 25.4; } } ImageEditorPrintDialogPage::Unit ImageEditorPrintDialogPage::stringToUnit(const TQString& unit) { if (unit == i18n("Millimeters")) { return DK_MILLIMETERS; } else if (unit == i18n("Centimeters")) { return DK_CENTIMETERS; } else {//Inches return DK_INCHES; } } TQString ImageEditorPrintDialogPage::unitToString(Unit unit) { if (unit == DK_MILLIMETERS) { return i18n("Millimeters"); } else if (unit == DK_CENTIMETERS) { return i18n("Centimeters"); } else { //DK_INCHES return i18n("Inches"); } } } // namespace Digikam