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.
kipi-plugins/kipi-plugins/acquireimages/acquireimagedialog.cpp

586 lines
20 KiB

/* ============================================================
*
* 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 <caulier dot gilles at gmail dot com>
*
* 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 <tiffio.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
}
// Include files for TQt
#undef Unsorted // x headers suck - make qdir.h work with --enable-final
#include <tqvbox.h>
#include <tqlayout.h>
#include <tqdir.h>
#include <tqwidget.h>
#include <tqlabel.h>
#include <tqpushbutton.h>
#include <tqgroupbox.h>
#include <tqstring.h>
#include <tqwhatsthis.h>
#include <tqtextedit.h>
#include <tqimage.h>
#include <tqpixmap.h>
#include <tqcombobox.h>
#include <tqlistbox.h>
#include <tqfile.h>
#include <tqapplication.h>
#include <tqvgroupbox.h>
// Include files for KDE
#include <tdelocale.h>
#include <klineedit.h>
#include <tdefiledialog.h>
#include <tdemessagebox.h>
#include <knuminput.h>
#include <kinstance.h>
#include <tdeconfig.h>
#include <tdelistbox.h>
#include <klineeditdlg.h>
#include <ksqueezedtextlabel.h>
#include <tdeio/netaccess.h>
#include <kimageio.h>
#include <tdetempfile.h>
#include <tdeversion.h>
#include <kdebug.h>
#include <tdefiletreeview.h>
#include <tdeapplication.h>
#include <tdeaboutdata.h>
#include <khelpmenu.h>
#include <kiconloader.h>
#include <tdepopupmenu.h>
// Include files for libKipi.
#include <libkipi/imageinfo.h>
// 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("<p>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("<p>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("<p>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( "<p>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("<p>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("<p>The compression value of target image for JPEG and PNG formats:<p>");
whatsThis = whatsThis + i18n("<b>1</b>: very high compression<p>"
"<b>25</b>: high compression<p>"
"<b>50</b>: medium compression<p>"
"<b>75</b>: low compression (default value)<p>"
"<b>100</b>: 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("<p>Select here the target image's file format.<p>");
whatsThis = whatsThis + i18n("<b>JPEG</b>: The Joint Photographic Experts' Group "
"file format is a good Web file format but it uses lossy data compression.<p>"
"<b>PNG</b>: 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("<p><b>TIFF</b>: 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("<p><b>PPM</b>: 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("<p><b>BMP</b>: 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( "<p>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("<p>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<KIPI::ImageCollection> albums = m_interface->allAlbums();
TQValueList<KIPI::ImageCollection>::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("<qt>Error when informing the application about the new image. "
"The error was: %1</qt>" ).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