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.
tdegraphics/kooka/img_saver.cpp

898 lines
23 KiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

/***************************************************************************
img_saver.cpp - description
-------------------
begin : Mon Dec 27 1999
copyright : (C) 1999 by Klaas Freitag
email : freitag@suse.de
***************************************************************************/
/***************************************************************************
* *
* This file may be distributed and/or modified under the terms of the *
* GNU General Public License version 2 as published by the Free Software *
* Foundation and appearing in the file COPYING included in the *
* packaging of this file. *
*
* As a special exception, permission is given to link this program *
* with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
* Kreuzlingen and distribute the resulting executable without *
* including the source code for KADMOS in the source distribution. *
*
* As a special exception, permission is given to link this program *
* with any edition of Qt, and distribute the resulting executable, *
* without including the source code for Qt in the source distribution. *
* *
***************************************************************************/
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <kglobal.h>
#include <kconfig.h>
#include <kdialog.h>
#include <kimageio.h>
#include <kseparator.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kdebug.h>
#include <kio/jobclasses.h>
#include <kio/file.h>
#include <kio/job.h>
#include <kio/netaccess.h>
#include <ktempfile.h>
#include <kinputdialog.h>
#include <tqdir.h>
#include <tqlayout.h>
#include <tqfileinfo.h>
#include <tqimage.h>
#include <tqmessagebox.h>
#include <tqvbox.h>
#include <tqbuttongroup.h>
#include "resource.h"
#include "img_saver.h"
#include "previewer.h"
#include "kookaimage.h"
FormatDialog::FormatDialog( TQWidget *parent, const TQString&, const char *name )
:KDialogBase( parent, name, true,
/* Tabbed,*/ i18n( "Kooka Save Assistant" ),
Ok|Cancel, Ok )
{
buildHelp();
// readConfig();
// TQFrame *page = addPage( TQString( "Save the image") );
TQFrame *page = new TQFrame( this );
page->setFrameStyle( TQFrame::Box | TQFrame::Sunken );
Q_CHECK_PTR( page );
setMainWidget( page );
TQVBoxLayout *bigdad = new TQVBoxLayout( page, marginHint(), spacingHint());
Q_CHECK_PTR(bigdad);
// some nice words
TQLabel *l0 = new TQLabel( page );
Q_CHECK_PTR(l0);
l0->setText( i18n( "<B>Save Assistant</B><P>Select an image format to save the scanned image." ));
bigdad->addWidget( l0 );
KSeparator* sep = new KSeparator( KSeparator::HLine, page);
bigdad->addWidget( sep );
// Layout-Boxes
// TQHBoxLayout *hl1= new TQHBoxLayout( ); // Caption
TQHBoxLayout *lhBigMiddle = new TQHBoxLayout( spacingHint() ); // Big middle
Q_CHECK_PTR(lhBigMiddle);
bigdad->addLayout( lhBigMiddle );
TQVBoxLayout *lvFormatSel = new TQVBoxLayout( spacingHint() ); // Selection List
Q_CHECK_PTR(lvFormatSel);
lhBigMiddle->addLayout( lvFormatSel );
// Insert Scrolled List for formats
TQLabel *l1 = new TQLabel( page );
Q_CHECK_PTR(l1);
l1->setText( i18n( "Available image formats:" ));
lb_format = new TQListBox( page, "ListBoxFormats" );
Q_CHECK_PTR(lb_format);
#ifdef USE_KIMAGEIO
TQStringList fo = KImageIO::types();
#else
TQStringList fo = TQImage::outputFormatList();
#endif
kdDebug(28000) << "#### have " << fo.count() << " image types" << endl;
lb_format->insertStringList( fo );
connect( lb_format, TQT_SIGNAL( highlighted(const TQString&)),
TQT_SLOT( showHelp(const TQString&)));
// Insert label for helptext
l_help = new TQLabel( page );
Q_CHECK_PTR(l_help);
l_help->setFrameStyle( TQFrame::Panel|TQFrame::Sunken );
l_help->setText( i18n("-No format selected-" ));
l_help->setAlignment( AlignVCenter | AlignHCenter );
l_help->setMinimumWidth(230);
// Insert Selbox for subformat
l2 = new TQLabel( page );
Q_CHECK_PTR(l2);
l2->setText( i18n( "Select the image sub-format" ));
cb_subf = new TQComboBox( page, "ComboSubFormat" );
Q_CHECK_PTR( cb_subf );
// Checkbox to store setting
cbDontAsk = new TQCheckBox(i18n("Don't ask again for the save format if it is defined."),
page );
Q_CHECK_PTR( cbDontAsk );
TQFrame *hl = new TQFrame(page);
Q_CHECK_PTR( hl );
hl->setFrameStyle( TQFrame::HLine|TQFrame::Sunken );
// bigdad->addWidget( l_caption, 1 );
lvFormatSel->addWidget( l1, 1 );
lvFormatSel->addWidget( lb_format, 6 );
lvFormatSel->addWidget( l2, 1 );
lvFormatSel->addWidget( cb_subf, 1 );
lhBigMiddle->addWidget( l_help, 2 );
//bigdad->addStretch(1);
bigdad->addWidget( hl, 1 );
bigdad->addWidget( cbDontAsk , 2 );
bigdad->activate();
}
void FormatDialog::showHelp( const TQString& item )
{
TQString helptxt = format_help[ item ];
if( !helptxt.isEmpty() ) {
// Set the hint
l_help->setText( helptxt );
// and check subformats
check_subformat( helptxt );
} else {
l_help->setText( i18n("-no hint available-" ));
}
}
void FormatDialog::check_subformat( const TQString & format )
{
// not yet implemented
kdDebug(28000) << "This is format in check_subformat: " << format << endl;
cb_subf->setEnabled( false );
// l2 = Label "select subformat" ->bad name :-|
l2->setEnabled( false );
}
void FormatDialog::setSelectedFormat( TQString fo )
{
TQListBoxItem *item = lb_format->findItem( fo );
if( item )
{
// Select it.
lb_format->setSelected( lb_format->index(item), true );
}
}
TQString FormatDialog::getFormat( ) const
{
int item = lb_format->currentItem();
if( item > -1 )
{
const TQString f = lb_format->text( item );
return( f );
}
return( "BMP" );
}
TQCString FormatDialog::getSubFormat( ) const
{
// Not yet...
return( "" );
}
#include "formathelp.h"
void FormatDialog::buildHelp( void )
{
format_help.insert( TQString::fromLatin1("BMP"), HELP_BMP );
format_help.insert( TQString::fromLatin1("PNM"), HELP_PNM );
format_help.insert( TQString::fromLatin1("JPEG"), HELP_JPG );
format_help.insert( TQString::fromLatin1("JPG"), HELP_JPG );
format_help.insert( TQString::fromLatin1("EPS"), HELP_EPS );
}
/* ********************************************************************** */
ImgSaver::ImgSaver( TQWidget *parent, const KURL dir_name )
: TQObject( parent )
{
if( dir_name.isEmpty() || dir_name.protocol() != "file" )
{
kdDebug(28000) << "ImageServer initialised with wrong dir " << dir_name.url() << endl;
directory = Previewer::galleryRoot();
}
else
{
/* A path was given */
if( dir_name.protocol() != "file" )
{
kdDebug(28000) << "ImgSaver: Can only save local image, sorry !" << endl;
}
else
{
directory = dir_name.directory(true, false);
}
}
kdDebug(28000) << "ImageSaver uses dir <" << directory << endl;
createDir( directory );
readConfig();
last_file = "";
last_format ="";
}
ImgSaver::ImgSaver( TQWidget *parent )
:TQObject( parent )
{
directory = Previewer::galleryRoot();
createDir( directory );
readConfig();
last_file = "";
last_format ="";
}
/* Needs a full qualified directory name */
void ImgSaver::createDir( const TQString& dir )
{
KURL url( dir );
if( ! KIO::NetAccess::exists(url, false, 0) )
{
kdDebug(28000) << "Wrn: Directory <" << dir << "> does not exist -> try to create !" << endl;
// if( mkdir( TQFile::encodeName( dir ), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH ) != 0 )
if( KIO::mkdir( KURL(dir)))
{
KMessageBox::sorry(0, i18n("The folder\n%1\n does not exist and could not be created;\n"
"please check the permissions.").arg(dir));
}
}
#if 0
if( ! fi.isWritable() )
{
KMessageBox::sorry(0, i18n("The directory\n%1\n is not writeable;\nplease check the permissions.")
.arg(dir));
}
#endif
}
/**
* This function asks the user for a filename or creates
* one by itself, depending on the settings
**/
ImgSaveStat ImgSaver::saveImage( TQImage *image )
{
ImgSaveStat stat;
picType imgType;
if( !image ) return( ISS_ERR_PARAM );
/* Find out what kind of image it is */
if( image->depth() > 8 )
{
imgType = PT_HICOLOR_IMAGE;
}
else
{
if( image->depth() == 1 || image->numColors() == 2 )
{
kdDebug(28000) << "This is black And White!" << endl;
imgType = PT_BW_IMAGE;
}
else
{
imgType = PT_COLOR_IMAGE;
if( image->allGray() )
{
imgType = PT_GRAY_IMAGE;
}
}
}
TQString format = findFormat( imgType );
TQString subformat = findSubFormat( format );
// Call save-Function with this params
if( format.isEmpty() )
{
kdDebug(28000) << "Save canceled by user -> no save !" << endl;
return( ISS_SAVE_CANCELED );
}
kdDebug(28000) << "saveImage: Directory is " << directory << endl;
TQString filename = createFilename( format );
KConfig *konf = KGlobal::config ();
konf->setGroup( OP_FILE_GROUP );
if( konf->readBoolEntry( OP_ASK_FILENAME, false ) )
{
bool ok;
TQString text = KInputDialog::getText( i18n( "Filename" ), i18n("Enter filename:"),
filename, &ok );
if(ok)
{
filename = text;
}
}
TQString fi = directory + "/" + filename;
if( extension(fi).isEmpty() )
{
if( ! fi.endsWith( "." ) )
{
fi+= ".";
}
fi+=format.lower();
}
kdDebug(28000) << "saveImage: saving file <" << fi << ">" << endl;
stat = save( image, fi, format, subformat );
return( stat );
}
/**
* This member creates a filename for the image to save.
* This is done by numbering all existing files and adding
* one
**/
TQString ImgSaver::createFilename( TQString format )
{
if( format.isNull() || format.isEmpty() ) return( 0 );
TQString s = "kscan_*." + format.lower();
TQDir files( directory, s );
long c = 1;
TQString num;
num.setNum(c);
TQString fname = "kscan_" + num.rightJustify(4, '0') + "." + format.lower();
while( files.exists( fname ) ) {
num.setNum(++c);
fname = "kscan_" + num.rightJustify(4, '0') + "." + format.lower();
}
return( fname );
}
/**
* This function gets a filename from the parent. The filename must not be relative.
**/
ImgSaveStat ImgSaver::saveImage( TQImage *image, const KURL& filename, const TQString& imgFormat )
{
TQString format = imgFormat;
/* Check if the filename is local */
if( !filename.isLocalFile())
{
kdDebug(29000) << "ImgSaver: Can only save local image, sorry !" << endl;
return( ISS_ERR_PROTOCOL );
}
TQString localFilename;
localFilename = filename.directory( false, true) + filename.fileName();
kdDebug(28000) << "saveImage: Saving "<< localFilename << " in format " << format << endl;
if( format.isEmpty() )
format = "BMP";
return( save( image, localFilename, format, "" ) );
}
/*
* findFormat does all the stuff with the dialog.
*/
TQString ImgSaver::findFormat( picType type )
{
TQString format;
KConfig *konf = KGlobal::config ();
konf->setGroup( OP_FILE_GROUP );
if( type == PT_THUMBNAIL )
{
return( "BMP" );
}
// real images
switch( type )
{
case PT_THUMBNAIL:
format = konf->readEntry( OP_FORMAT_THUMBNAIL, "BMP" );
kdDebug( 28000) << "Format for Thumbnails: " << format << endl;
break;
case PT_PREVIEW:
format = konf->readEntry( OP_PREVIEW_FORMAT, "BMP" );
kdDebug( 28000) << "Format for Preview: " << format << endl;
break;
case PT_COLOR_IMAGE:
format = konf->readEntry( OP_FORMAT_COLOR, "nothing" );
kdDebug( 28000 ) << "Format for Color: " << format << endl;
break;
case PT_GRAY_IMAGE:
format = konf->readEntry( OP_FORMAT_GRAY, "nothing" );
kdDebug( 28000 ) << "Format for Gray: " << format << endl;
break;
case PT_BW_IMAGE:
format = konf->readEntry( OP_FORMAT_BW, "nothing" );
kdDebug( 28000 ) << "Format for BlackAndWhite: " << format << endl;
break;
case PT_HICOLOR_IMAGE:
format = konf->readEntry( OP_FORMAT_HICOLOR, "nothing" );
kdDebug( 28000 ) << "Format for HiColorImage: " << format << endl;
break;
default:
format = "nothing";
kdDebug( 28000 ) << "ERR: Could not find image type !" << endl;
break;
}
if( type != PT_PREVIEW ) /* Use always bmp-Default for preview scans */
{
if( format == "nothing" || ask_for_format )
{
format = startFormatDialog( type );
}
}
return( format );
}
TQString ImgSaver::picTypeAsString( picType type ) const
{
TQString res;
switch( type )
{
case PT_COLOR_IMAGE:
res = i18n( "palleted color image (16 or 24 bit depth)" );
break;
case PT_GRAY_IMAGE:
res = i18n( "palleted gray scale image (16 bit depth)" );
break;
case PT_BW_IMAGE:
res = i18n( "lineart image (black and white, 1 bit depth)" );
break;
case PT_HICOLOR_IMAGE:
res = i18n( "high (or true-) color image, not palleted" );
break;
default:
res = i18n( "Unknown image type" );
break;
}
return( res );
}
TQString ImgSaver::startFormatDialog( picType type)
{
FormatDialog fd( 0, picTypeAsString( type ), "FormatDialog" );
// set default values
if( type != PT_PREVIEW )
{
TQString defFormat = getFormatForType( type );
fd.setSelectedFormat( defFormat );
}
TQString format;
if( fd.exec() )
{
format = fd.getFormat();
kdDebug(28000) << "Storing to format <" << format << ">" << endl;
bool ask = fd.askForFormat();
kdDebug(28000)<< "Store askFor is " << ask << endl;
storeFormatForType( type, format, ask );
subformat = fd.getSubFormat();
}
return( format );
}
/*
* This method returns true if the image format given in format is remembered
* for that image type.
*/
bool ImgSaver::isRememberedFormat( picType type, TQString format ) const
{
if( getFormatForType( type ) == format )
{
return( true );
}
else
{
return( false );
}
}
TQString ImgSaver::getFormatForType( picType type ) const
{
KConfig *konf = KGlobal::config ();
Q_CHECK_PTR( konf );
konf->setGroup( OP_FILE_GROUP );
TQString f;
switch( type )
{
case PT_COLOR_IMAGE:
f = konf->readEntry( OP_FORMAT_COLOR, "BMP" );
break;
case PT_GRAY_IMAGE:
f = konf->readEntry( OP_FORMAT_GRAY, "BMP" );
break;
case PT_BW_IMAGE:
f = konf->readEntry( OP_FORMAT_BW, "BMP" );
break;
case PT_HICOLOR_IMAGE:
f = konf->readEntry( OP_FORMAT_HICOLOR, "BMP" );
break;
default:
f = "BMP";
break;
}
return( f );
}
void ImgSaver::storeFormatForType( picType type, TQString format, bool ask )
{
KConfig *konf = KGlobal::config ();
Q_CHECK_PTR( konf );
konf->setGroup( OP_FILE_GROUP );
konf->writeEntry( OP_FILE_ASK_FORMAT, ask );
ask_for_format = ask;
switch( type )
{
case PT_COLOR_IMAGE:
konf->writeEntry( OP_FORMAT_COLOR, format );
break;
case PT_GRAY_IMAGE:
konf->writeEntry( OP_FORMAT_GRAY, format );
break;
case PT_BW_IMAGE:
konf->writeEntry( OP_FORMAT_BW, format );
break;
case PT_HICOLOR_IMAGE:
konf->writeEntry( OP_FORMAT_HICOLOR, format );
break;
default:
kdDebug(28000) << "Wrong Type - cant store format setting" << endl;
break;
}
konf->sync();
}
TQString ImgSaver::findSubFormat( TQString format )
{
kdDebug(28000) << "Searching Subformat for " << format << endl;
return( subformat );
}
/**
private save() does the work to save the image.
the filename must be complete and local.
**/
ImgSaveStat ImgSaver::save( TQImage *image, const TQString &filename,
const TQString &format,
const TQString &subformat )
{
bool result = false;
kdDebug(28000) << "in ImgSaver::save: saving " << filename << endl;
if( ! format || !image )
{
kdDebug(28000) << "ImgSaver ERROR: Wrong parameter Format <" << format << "> or image" << endl;
return( ISS_ERR_PARAM );
}
if( image )
{
// remember the last processed file - only the filename - no path
TQFileInfo fi( filename );
TQString dirPath = fi.dirPath();
TQDir dir = TQDir( dirPath );
if( ! dir.exists() )
{
/* The dir to save in always should exist, except in the first preview save */
kdDebug(28000) << "Creating dir " << dirPath << endl;
if( !dir.mkdir( dirPath ) )
{
kdDebug(28000) << "ERR: Could not create directory" << endl;
}
}
if( fi.exists() && !fi.isWritable() )
{
kdDebug(28000) << "Cant write to file <" << filename << ">, cant save !" << endl;
result = false;
return( ISS_ERR_PERM );
}
/* Check the format, is it writable ? */
#ifdef USE_KIMAGEIO
if( ! KImageIO::canWrite( format ) )
{
kdDebug(28000) << "Cant write format <" << format << ">" << endl;
result = false;
return( ISS_ERR_FORMAT_NO_WRITE );
}
#endif
kdDebug(28000) << "ImgSaver: saving image to <" << filename << "> as <" << format << "/" << subformat <<">" << endl;
result = image->save( filename, format.latin1() );
last_file = fi.absFilePath();
last_format = format.latin1();
}
if( result )
return( ISS_OK );
else {
last_file = "";
last_format = "";
return( ISS_ERR_UNKNOWN );
}
}
void ImgSaver::readConfig( void )
{
KConfig *konf = KGlobal::config ();
Q_CHECK_PTR( konf );
konf->setGroup( OP_FILE_GROUP );
ask_for_format = konf->readBoolEntry( OP_FILE_ASK_FORMAT, true );
TQDir home = TQDir::home();
}
TQString ImgSaver::errorString( ImgSaveStat stat )
{
TQString re;
switch( stat ) {
case ISS_OK: re = i18n( " image save OK " ); break;
case ISS_ERR_PERM: re = i18n( " permission error " ); break;
case ISS_ERR_FILENAME: re = i18n( " bad filename " ); break;
case ISS_ERR_NO_SPACE: re = i18n( " no space on device " ); break;
case ISS_ERR_FORMAT_NO_WRITE: re = i18n( " could not write image format " ); break;
case ISS_ERR_PROTOCOL: re = i18n( " can not write file using that protocol "); break;
case ISS_SAVE_CANCELED: re = i18n( " user canceled saving " ); break;
case ISS_ERR_UNKNOWN: re = i18n( " unknown error " ); break;
case ISS_ERR_PARAM: re = i18n( " parameter wrong " ); break;
default: re = "";
}
return( re );
}
TQString ImgSaver::extension( const KURL& url )
{
TQString extension = url.fileName();
int dotPos = extension.findRev( '.' );
if( dotPos > 0 )
{
int len = extension.length();
extension = extension.right( len - dotPos -1 );
}
else
{
/* No extension was supplied */
extension = TQString();
}
return extension;
}
bool ImgSaver::renameImage( const KURL& fromUrl, KURL& toUrl, bool askExt, TQWidget *overWidget )
{
/* Check if the provided filename has a extension */
TQString extTo = extension( toUrl );
TQString extFrom = extension( fromUrl );
KURL targetUrl( toUrl );
if( extTo.isEmpty() && !extFrom.isEmpty() )
{
/* Ask if the extension should be added */
int result = KMessageBox::Yes;
TQString fName = toUrl.fileName();
if( ! fName.endsWith( "." ) )
{
fName += ".";
}
fName += extFrom;
if( askExt )
{
TQString s;
s = i18n("The filename you supplied has no file extension.\nShould the correct one be added automatically? ");
s += i18n( "That would result in the new filename: %1" ).arg( fName);
result = KMessageBox::questionYesNo(overWidget, s, i18n( "Extension Missing"),
i18n("Add Extension"), i18n("Do Not Add"),
"AutoAddExtensions" );
}
if( result == KMessageBox::Yes )
{
targetUrl.setFileName( fName );
kdDebug(28000) << "Rename file to " << targetUrl.prettyURL() << endl;
}
}
else if( !extFrom.isEmpty() && extFrom != extTo )
{
if( ! ((extFrom.lower() == "jpeg" && extTo.lower() == "jpg") ||
(extFrom.lower() == "jpg" && extTo.lower() == "jpeg" )))
{
/* extensions differ -> TODO */
KMessageBox::error( overWidget,
i18n("Format changes of images are currently not supported."),
i18n("Wrong Extension Found" ));
return(false);
}
}
bool success = false;
if( KIO::NetAccess::exists( targetUrl, false,0 ) )
{
kdDebug(28000)<< "Target already exists - can not copy" << endl;
}
else
{
if( KIO::file_move(fromUrl, targetUrl) )
{
success = true;
}
}
return( success );
}
TQString ImgSaver::tempSaveImage( KookaImage *img, const TQString& format, int colors )
{
KTempFile *tmpFile = new KTempFile( TQString(), "."+format.lower());
tmpFile->setAutoDelete( false );
tmpFile->close();
KookaImage tmpImg;
if( colors != -1 && img->numColors() != colors )
{
// Need to convert image
if( colors == 1 || colors == 8 || colors == 24 || colors == 32 )
{
tmpImg = img->convertDepth( colors );
img = &tmpImg;
}
else
{
kdDebug(29000) << "ERROR: Wrong color depth requested: " << colors << endl;
img = 0;
}
}
TQString name;
if( img )
{
name = tmpFile->name();
if( ! img->save( name, format.latin1() ) ) name = TQString();
}
delete tmpFile;
return name;
}
bool ImgSaver::copyImage( const KURL& fromUrl, const KURL& toUrl, TQWidget *overWidget )
{
/* Check if the provided filename has a extension */
TQString extTo = extension( toUrl );
TQString extFrom = extension( fromUrl );
KURL targetUrl( toUrl );
if( extTo.isEmpty() && !extFrom.isEmpty())
{
/* Ask if the extension should be added */
int result = KMessageBox::Yes;
TQString fName = toUrl.fileName();
if( ! fName.endsWith( "." ))
fName += ".";
fName += extFrom;
TQString s;
s = i18n("The filename you supplied has no file extension.\nShould the correct one be added automatically? ");
s += i18n( "That would result in the new filename: %1" ).arg( fName);
result = KMessageBox::questionYesNo(overWidget, s, i18n( "Extension Missing"),
i18n("Add Extension"), i18n("Do Not Add"),
"AutoAddExtensions" );
if( result == KMessageBox::Yes )
{
targetUrl.setFileName( fName );
}
}
else if( !extFrom.isEmpty() && extFrom != extTo )
{
/* extensions differ -> TODO */
if( ! ((extFrom.lower() == "jpeg" && extTo.lower() == "jpg") ||
(extFrom.lower() == "jpg" && extTo.lower() == "jpeg" )))
{
KMessageBox::error( overWidget, i18n("Format changes of images are currently not supported."),
i18n("Wrong Extension Found" ));
return(false);
}
}
KIO::Job *copyjob = KIO::copy( fromUrl, targetUrl, false );
return( copyjob ? true : false );
}
/* extension needs to be added */
#include "img_saver.moc"