/* ============================================================ * * This file is a part of kipi-plugins project * http://www.kipi-plugins.org * * Date : 2003-10-01 * Description : Acquire image dialog * * Copyright (C) 2003-2008 by Gilles Caulier * * 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. * * ============================================================ */ // C Ansi includes extern "C" { #include #include #include #include #include #include #include #include } // Include files for TQt #undef Unsorted // x headers suck - make qdir.h work with --enable-final #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Include files for KDE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Include files for libKipi. #include // Local includes #include "pluginsversion.h" #include "acquireimagedialog.h" #include "acquireimagedialog.moc" namespace KIPIAcquireImagesPlugin { // Used by slotOK() method. #undef NETACCESS_WIDGET #if TDE_VERSION >= 0x30200 #define NETACCESS_WIDGET , this #else #define NETACCESS_WIDGET #endif AcquireImageDialog::AcquireImageDialog( KIPI::Interface* interface, TQWidget *parent, const TQImage &img) : KDialogBase( IconList, i18n("Save Target Image Options"), Help|Ok|Cancel, Ok, parent, "AcquireImageDialog", true, false ), m_interface( interface ) { KImageIO::registerFormats(); m_qimageScanned = img; setupImageOptions(); setupAlbumsList(); readSettings(); slotImageFormatChanged(m_imagesFormat->currentText()); page_setupImageOptions->setFocus(); resize( 600, 400 ); // About data and help button. m_about = new KIPIPlugins::KPAboutData(I18N_NOOP("Acquire images"), 0, TDEAboutData::License_GPL, I18N_NOOP("A Kipi plugin to acquire images"), "(c) 2003-2008, Gilles Caulier"); m_about->addAuthor("Gilles Caulier", I18N_NOOP("Author and maintainer"), "caulier dot gilles at gmail dot com"); m_helpButton = actionButton( Help ); KHelpMenu* helpMenu = new KHelpMenu(this, m_about, false); helpMenu->menu()->removeItemAt(0); helpMenu->menu()->insertItem(i18n("Plugin Handbook"), this, TQT_SLOT(slotHelp()), 0, -1, 0); m_helpButton->setPopup( helpMenu->menu() ); } AcquireImageDialog::~AcquireImageDialog() { delete m_about; } void AcquireImageDialog::slotHelp() { TDEApplication::kApplication()->invokeHelp("acquireimages", "kipi-plugins"); } void AcquireImageDialog::readSettings(void) { // Read all settings from configuration file. m_config = new TDEConfig("kipirc"); m_config->setGroup("AcquireImages Settings"); m_FileName->setText(m_config->readPathEntry("DefaultImageFileName", i18n("image"))); m_imageCompression->setValue(m_config->readNumEntry("ImageCompression", 75)); m_imagesFormat->setCurrentText(m_config->readEntry("ImageFormat", "TIFF")); delete m_config; // Get the image files filters from the hosts app. m_ImagesFilesSort = m_interface->fileExtensions(); } void AcquireImageDialog::writeSettings(void) { // Write all settings in configuration file. m_config = new TDEConfig("kipirc"); m_config->setGroup("AcquireImages Settings"); m_config->writePathEntry("DefaultImageFileName", m_FileName->text()); m_config->writeEntry("ImageCompression", m_imageCompression->value()); m_config->writeEntry("ImageFormat", m_imagesFormat->currentText()); m_config->sync(); delete m_config; } void AcquireImageDialog::setupImageOptions(void) { TQString whatsThis; page_setupImageOptions = addPage( i18n("Target Image"), i18n("Target Image Options"), BarIcon("image-x-generic", TDEIcon::SizeMedium ) ); TQVBoxLayout *vlay = new TQVBoxLayout( page_setupImageOptions, 0, spacingHint() ); //--------------------------------------------- TQGroupBox * groupBox1 = new TQGroupBox( page_setupImageOptions ); groupBox1->setFlat(false); groupBox1->setTitle(i18n("File Name && Caption")); TQWhatsThis::add( groupBox1, i18n("

The target image preview with the file name and caption.") ); TQGridLayout* grid2 = new TQGridLayout( groupBox1, 3, 3 , 20, 10); m_ImageFileName = new TQLabel( i18n("File name (without suffix):"), groupBox1); grid2->addMultiCellWidget(m_ImageFileName, 0, 0, 0, 3); m_FileName = new TQLineEdit(i18n("acquired_image"), groupBox1); TQWhatsThis::add( m_FileName, i18n("

Enter here the target image file name without suffix " "(that will be automatically added to the file name according " "to the file-format option.)") ); m_ImageFileName->setBuddy(m_FileName); grid2->addMultiCellWidget(m_FileName, 1, 1, 0, 3); m_ImageComments = new TQLabel( i18n("Caption:"), groupBox1); grid2->addMultiCellWidget(m_ImageComments, 2, 2, 0, 3); m_CommentsEdit = new TQTextEdit(groupBox1); m_CommentsEdit->setMaximumHeight( 200 ); TQWhatsThis::add( m_CommentsEdit, i18n("

Enter here the target image's caption.") ); grid2->addMultiCellWidget(m_CommentsEdit, 3, 3, 0, 2); m_preview = new TQLabel( groupBox1, "preview" ); m_preview->setFixedHeight( 120 ); m_preview->setAlignment( TQt::AlignHCenter | TQt::AlignVCenter ); m_preview->setSizePolicy( TQSizePolicy( TQSizePolicy::Preferred, TQSizePolicy::Preferred ) ); TQWhatsThis::add( m_preview, i18n( "

The preview of the target image." ) ); m_preview->setScaledContents( false ); TQImage scanned = m_qimageScanned.smoothScale((m_qimageScanned.width() * 100) / m_qimageScanned.height(), 100); TQPixmap pix; pix.convertFromImage(scanned); m_preview->setPixmap(pix); grid2->addMultiCellWidget(m_preview, 3, 3, 3, 3); vlay->addWidget( groupBox1 ); //--------------------------------------------- TQGroupBox * groupBox2 = new TQGroupBox( i18n("Saving Options"), page_setupImageOptions ); groupBox2->setColumnLayout(0, TQt::Vertical ); groupBox2->layout()->setSpacing( 6 ); groupBox2->layout()->setMargin( 11 ); TQWhatsThis::add( groupBox2, i18n("

The saving options of the target image.") ); TQVBoxLayout * groupBox2Layout = new TQVBoxLayout( groupBox2->layout() ); groupBox2Layout->setAlignment( TQt::AlignTop ); m_imageCompression = new KIntNumInput(75, groupBox2); m_imageCompression->setRange(1, 100, 1, true ); m_imageCompression->setLabel( i18n("Image compression:") ); whatsThis = i18n("

The compression value of target image for JPEG and PNG formats:

"); whatsThis = whatsThis + i18n("1: very high compression

" "25: high compression

" "50: medium compression

" "75: low compression (default value)

" "100: no compression"); TQWhatsThis::add( m_imageCompression, whatsThis); groupBox2Layout->addWidget( m_imageCompression ); TQHBoxLayout *hlay12 = new TQHBoxLayout( ); groupBox2Layout->addLayout( hlay12 ); m_imagesFormat = new TQComboBox(false, groupBox2); m_imagesFormat->insertItem("JPEG"); m_imagesFormat->insertItem("PNG"); m_imagesFormat->insertItem("TIFF"); m_imagesFormat->insertItem("PPM"); m_imagesFormat->insertItem("BMP"); m_imagesFormat->setCurrentText ("TIFF"); whatsThis = i18n("

Select here the target image's file format.

"); whatsThis = whatsThis + i18n("JPEG: The Joint Photographic Experts' Group " "file format is a good Web file format but it uses lossy data compression.

" "PNG: the Portable Network Graphics format is an extensible file format for " "the lossless, portable, well-compressed storage of raster images. PNG provides a " "patent-free replacement for GIF and can also replace many common uses of TIFF. PNG " "is designed to work well in online viewing applications, such as the World Wide Web, " "so it is fully streamable with a progressive display option. Also, PNG can store gamma " "and chromaticity data for improved color matching on heterogeneous platforms."); whatsThis = whatsThis + i18n("

TIFF: the Tagged Image File Format is a rather old standard " "that is still very popular today. It is a highly flexible and platform-independent " "format which is supported by numerous image processing applications and by virtually all " "prepress software on the market."); whatsThis = whatsThis + i18n("

PPM: the Portable Pixel Map file format is used as an " "intermediate format for storing color bitmap information. PPM files may be either " "binary or ASCII and store pixel values up to 24 bits in size. This format generates " "the biggest-sized text files for encoding images without losing quality."); whatsThis = whatsThis + i18n("

BMP: the BitMaP file format is a popular image format from the " "Win32 environment. It efficiently stores mapped or unmapped RGB graphics data with pixels " "1-, 4-, 8-, or 24-bits in size. Data may be stored raw or compressed using a 4-bit or " "8-bit RLE data compression algorithm. BMP is an excellent choice for a simple bitmap " "format which supports a wide range of RGB image data."); TQWhatsThis::add( m_imagesFormat, whatsThis ); m_labelImageFormat = new TQLabel( i18n("Image file format:"), groupBox2); hlay12->addWidget( m_labelImageFormat ); m_labelImageFormat->setBuddy( m_imagesFormat ); hlay12->addStretch( 1 ); hlay12->addWidget( m_imagesFormat ); vlay->addWidget( groupBox2 ); vlay->addStretch(1); //--------------------------------------------- connect(m_imagesFormat, TQT_SIGNAL(activated(const TQString &)), this, TQT_SLOT(slotImageFormatChanged(const TQString &))); } void AcquireImageDialog::setupAlbumsList(void) { TQString whatsThis; page_setupAlbumsList = addPage( i18n("Selection"), i18n("Album selection"), BarIcon("folder_image", TDEIcon::SizeMedium ) ); TQVBoxLayout *vlay = new TQVBoxLayout( page_setupAlbumsList, 0, spacingHint() ); //--------------------------------------------- TQVGroupBox * groupBox1 = new TQVGroupBox( i18n("Select Folder in Which to Save Target Image"), page_setupAlbumsList ); m_uploadPath = new KIPI::UploadWidget( m_interface, groupBox1, "m_uploadPath" ); TQWidget* w = new TQWidget( groupBox1 ); TQHBoxLayout* hlay = new TQHBoxLayout( w, 6 ); hlay->addStretch( 1 ); m_addNewAlbumButton = new TQPushButton (i18n( "&Add New Folder"), w, "PushButton_AddNewAlbum"); hlay->addWidget( m_addNewAlbumButton ); TQWhatsThis::add( m_addNewAlbumButton, i18n( "

Add a new folder.")); vlay->addWidget( groupBox1 ); //--------------------------------------------- TQGroupBox * groupBox2 = new TQGroupBox( i18n("Album Description"), page_setupAlbumsList ); groupBox2->setColumnLayout(0, TQt::Vertical ); groupBox2->layout()->setSpacing( 6 ); groupBox2->layout()->setMargin( 11 ); TQWhatsThis::add( groupBox2, i18n("

The description of the current Album in the selection list.") ); TQVBoxLayout * groupBox2Layout = new TQVBoxLayout( groupBox2->layout() ); groupBox2Layout->setAlignment( TQt::AlignTop ); m_AlbumComments = new KSqueezedTextLabel( groupBox2 ); m_AlbumComments->setAlignment( int( TQLabel::WordBreak | TQLabel::AlignVCenter ) ); groupBox2Layout->addWidget( m_AlbumComments ); m_AlbumCollection = new KSqueezedTextLabel( groupBox2 ); m_AlbumCollection->setAlignment( int( TQLabel::WordBreak | TQLabel::AlignVCenter ) ); groupBox2Layout->addWidget( m_AlbumCollection ); m_AlbumDate = new KSqueezedTextLabel( groupBox2 ); m_AlbumDate->setAlignment( int( TQLabel::WordBreak | TQLabel::AlignVCenter ) ); groupBox2Layout->addWidget( m_AlbumDate ); m_AlbumItems = new KSqueezedTextLabel( groupBox2 ); m_AlbumItems->setAlignment( int( TQLabel::WordBreak | TQLabel::AlignVCenter ) ); groupBox2Layout->addWidget( m_AlbumItems ); vlay->addWidget( groupBox2 ); if ( !m_interface->hasFeature( KIPI::AlbumsHaveComments) ) groupBox2->hide(); else vlay->addStretch(1); //--------------------------------------------- connect(m_addNewAlbumButton, TQT_SIGNAL(clicked()), m_uploadPath, TQT_SLOT(mkdir())); connect(m_uploadPath, TQT_SIGNAL( folderItemSelected( const KURL & ) ), this, TQT_SLOT( slotAlbumSelected( const KURL & ))); //--------------------------------------------- slotAlbumSelected( m_uploadPath->path() ); } void AcquireImageDialog::slotAlbumSelected( const KURL &url ) { TQString comments, category, date, items; TQValueList albums = m_interface->allAlbums(); TQValueList::Iterator albumIt; for( albumIt = albums.begin() ; albumIt != albums.end() ; ++albumIt ) { if ( (*albumIt).path() == url ) break; } if (albumIt != albums.end()) { comments = (*albumIt).comment(); category = (*albumIt).category(); date = (*albumIt).date().toString( TQt::LocalDate ); items.setNum((*albumIt).images().count()); } m_AlbumComments->setText( i18n("Caption: %1").arg(comments) ); m_AlbumCollection->setText( i18n("Collection: %1").arg(category) ); m_AlbumDate->setText( i18n("Date: %1").arg(date) ); m_AlbumItems->setText( i18n("Items: %1").arg( items ) ); } void AcquireImageDialog::slotOk() { // PENDING( aurelien) // It would be nice if m_uploadPath kept its value between multiple snapshots. KURL url = m_uploadPath->path(); url.adjustPath(1); kdDebug(51001) << k_funcinfo << "path:" << url.prettyURL() << endl; if (!url.isValid()) { KMessageBox::error(this, i18n("You must select a target album for this image.")); return; } if (m_FileName->text().isEmpty()) { KMessageBox::error(this, i18n("You must provide a file name for this image.")); return; } writeSettings(); // Get all scanned image information. TQString imageFormat = m_imagesFormat->currentText(); int imageCompression = m_imageCompression->value(); TQString Commentsimg = m_CommentsEdit->text(); // Find an unique url TQString fileName = m_FileName->text(); TQString ext = extension(imageFormat); url.setFileName(fileName + ext); if (TDEIO::NetAccess::exists(url, false NETACCESS_WIDGET)) { for (int idx = 1; idx < 100 ; ++idx) { url.setFileName(TQString("%1_%2%3").arg(fileName).arg(idx).arg(ext)); kdDebug(51001) << "File already exist. Try to fixed target Url to: " << url.prettyURL() << endl; if (!TDEIO::NetAccess::exists(url, false NETACCESS_WIDGET)) break; } } kdDebug(51001) << k_funcinfo << "Saving image as " << url.prettyURL() << endl; // Save file KTempFile tmp; tmp.setAutoDelete(true); TQString imagePath; if (url.isLocalFile()) { imagePath=url.path(); } else { imagePath=tmp.name(); } bool ok=false; if (imageFormat=="JPEG" || imageFormat=="PNG") { ok = m_qimageScanned.save(imagePath, imageFormat.latin1(), imageCompression); } else if (imageFormat=="TIFF") { ok = TQImageToTiff(m_qimageScanned, imagePath); } else { ok = m_qimageScanned.save(imagePath, imageFormat.latin1()); } if ( !ok ) { KMessageBox::error(this, i18n("Cannot write image file \"%1\".").arg(imagePath)); return; } // Upload the image if necessary if ( !url.isLocalFile()) { if (!TDEIO::NetAccess::upload(imagePath, url NETACCESS_WIDGET)) { KMessageBox::error(this, i18n("Could not upload image to \"%1\".").arg(url.prettyURL())); return; } } // Save the comments for this image. TQString err; ok = m_interface->addImage( url, err ); if ( !ok ) { KMessageBox::error(this, i18n("Error when informing the application about the new image. " "The error was: %1" ).arg( err ) ); return; } KIPI::ImageInfo info = m_interface->info( url ); info.setDescription( Commentsimg ); m_interface->refreshImages( KURL::List(url) ); close(); delete this; } void AcquireImageDialog::slotImageFormatChanged(const TQString &string) { if ( string == "JPEG" || string == "PNG" ) m_imageCompression->setEnabled(true); else m_imageCompression->setEnabled(false); } TQString AcquireImageDialog::extension(const TQString& imageFormat) { if (imageFormat == "PNG") return ".png"; if (imageFormat == "JPEG") return ".jpg"; if (imageFormat == "TIFF") return ".tif"; if (imageFormat == "BMP") return ".bmp"; if (imageFormat == "PPM") return ".ppm"; Q_ASSERT(false); return ""; } bool AcquireImageDialog::TQImageToTiff(const TQImage& image, const TQString& dst) { TIFF *tif; unsigned char *data; int x, y; TQRgb rgb; tif = TIFFOpen(TQFile::encodeName(dst).data(), "w"); if ( tif ) { TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, image.width()); TIFFSetField(tif, TIFFTAG_IMAGELENGTH, image.height()); TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8); TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_ADOBE_DEFLATE); { TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3); TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tif, 0)); data = new unsigned char[image.width()*3]; unsigned char *dptr = 0; for (y = 0 ; y < image.height() ; ++y) { dptr = data; for (x = 0 ; x < image.width() ; ++x) { rgb = *((uint *)image.scanLine(y) + x); *(dptr++) = tqRed(rgb); *(dptr++) = tqGreen(rgb); *(dptr++) = tqBlue(rgb); } TIFFWriteScanline(tif, data, y, 0); } delete [] data; } TIFFClose(tif); return true; } return false; } } // NameSpace KIPIAcquireImagesPlugin