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.
445 lines
12 KiB
445 lines
12 KiB
/***************************************************************************
|
|
sq_converter.cpp - description
|
|
-------------------
|
|
begin : ??? Mar 3 2005
|
|
copyright : (C) 2005 by Baryshev Dmitry
|
|
email : ksquirrel.iv@gmail.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 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <tqapplication.h>
|
|
#include <tqfile.h>
|
|
|
|
#include <tdemessagebox.h>
|
|
#include <kstringhandler.h>
|
|
#include <kstandarddirs.h>
|
|
#include <tdetempfile.h>
|
|
#include <tdelocale.h>
|
|
|
|
#include "ksquirrel.h"
|
|
#include "sq_converter.h"
|
|
#include "sq_widgetstack.h"
|
|
#include "sq_diroperator.h"
|
|
#include "sq_libraryhandler.h"
|
|
#include "sq_config.h"
|
|
#include "sq_errorstring.h"
|
|
#include "sq_imageloader.h"
|
|
#include "sq_imageconvert.h"
|
|
|
|
SQ_Converter * SQ_Converter::m_sing = 0;
|
|
|
|
SQ_Converter::SQ_Converter(TQObject *parent) : TQObject(parent)
|
|
{
|
|
m_sing = this;
|
|
|
|
err_internal = i18n("internal error") + '\n';
|
|
err_failed = i18n("failed") + '\n';
|
|
|
|
special_action = i18n("Converting");
|
|
|
|
image = 0;
|
|
}
|
|
|
|
SQ_Converter::~SQ_Converter()
|
|
{
|
|
if(image) free(image);
|
|
}
|
|
|
|
void SQ_Converter::slotStartEdit()
|
|
{
|
|
files.clear();
|
|
|
|
KFileItemList *items = (KFileItemList *)SQ_WidgetStack::instance()->selectedItems();
|
|
|
|
if(!items || !items->count())
|
|
{
|
|
KMessageBox::information(KSquirrel::app(), i18n("Select files to edit"));
|
|
return;
|
|
}
|
|
else if(!items->first()->url().isLocalFile())
|
|
{
|
|
KMessageBox::information(KSquirrel::app(), i18n("Converter cannot work with remote files.\nSorry"));
|
|
return;
|
|
}
|
|
|
|
KFileItem *i = items->first();
|
|
|
|
for(;i;i = items->next())
|
|
{
|
|
if(i->isFile())
|
|
files.append(i->url().path());
|
|
}
|
|
|
|
startEditPrivate();
|
|
}
|
|
|
|
TQString SQ_Converter::adjustFileName(const TQString &globalprefix, const TQString &name1, int replace, TQString putto, bool paged, int page)
|
|
{
|
|
TQFileInfo ff(name1);
|
|
TQString name = ff.dirPath() + '/' + (replace == 0 ? globalprefix : (replace == 2 ? TQString() : globalprefix)) + ff.fileName();
|
|
ff = TQFileInfo(name);
|
|
|
|
TQString result, inner, filter = lw->filter;
|
|
TQString ext = ff.extension(false);
|
|
TQString prefix, suffix, name2 = name;
|
|
TQString spage = TQString::fromLatin1("page_%1.").arg((TQString::fromLatin1("%1").arg(page)).rightJustify(3, '0'));
|
|
|
|
if(!putto.isEmpty())
|
|
{
|
|
if(TQFile::exists(putto))
|
|
name2 = putto + '/' + ff.fileName();
|
|
}
|
|
|
|
prefix = name2;
|
|
|
|
prefix.truncate(name2.length() - ext.length());
|
|
|
|
suffix = (SQ_LibraryHandler::instance()->knownExtension(TQString::fromLatin1("*.") + ext))
|
|
? TQString(lw->codec->extension(32)) : ext;
|
|
|
|
if(replace == 0 || replace == 2)
|
|
result = (!paged) ? (prefix + inner + suffix) : (prefix + spage + inner + suffix);
|
|
else
|
|
{
|
|
result = (!paged) ? (prefix + inner + suffix) : (prefix + spage + inner + suffix);
|
|
|
|
if(TQFile::exists(result))
|
|
{
|
|
inner = TQString::fromLatin1("1.");
|
|
result = (!paged) ? (prefix + inner + suffix) : (prefix + spage + inner + suffix);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void SQ_Converter::errorjmp(jmp_buf jmp, const int code)
|
|
{
|
|
error_code = code;
|
|
longjmp(jmp, 1);
|
|
}
|
|
|
|
void SQ_Converter::decodingCycle()
|
|
{
|
|
int i, j;
|
|
TQString name;
|
|
jmp_buf jmp;
|
|
RGBA *scan;
|
|
int errors, gerrors = 0, current;
|
|
TQString putto;
|
|
int replace = imageopt.where_to_put;
|
|
bool brk;
|
|
|
|
SQ_Config::instance()->setGroup("Edit tools");
|
|
|
|
int allpages = SQ_Config::instance()->readNumEntry("load_pages", 0);
|
|
int pages_num = SQ_Config::instance()->readNumEntry("load_pages_number", 1);
|
|
|
|
if(pages_num < 1) pages_num = 1;
|
|
|
|
altw = SQ_LibraryHandler::instance()->libraryByName(SQ_Config::instance()->readEntry("altlibrary", "Portable Network Graphics"));
|
|
multi = SQ_Config::instance()->readBoolEntry("multi", true);
|
|
|
|
tempfile = new KTempFile;
|
|
tempfile->setAutoDelete(true);
|
|
|
|
if(tempfile->status())
|
|
{
|
|
KMessageBox::error(KSquirrel::app(), i18n("Temporary file creation failed"));
|
|
return;
|
|
}
|
|
|
|
tempfile->close();
|
|
|
|
TQStringList::iterator last_it = files.fromLast();
|
|
TQStringList::iterator itEnd = files.end();
|
|
convert->startConvertion(files.count());
|
|
|
|
putto = imageopt.putto;
|
|
|
|
for(TQStringList::iterator it = files.begin();it != itEnd;++it)
|
|
{
|
|
currentFile = *it;
|
|
last = (it == last_it);
|
|
|
|
TQFileInfo ff(*it);
|
|
|
|
emit convertText(special_action + ' ' + KStringHandler::rsqueeze(ff.fileName()) + "... ", false);
|
|
|
|
if((lr = SQ_LibraryHandler::instance()->libraryForFile(*it)))
|
|
{
|
|
lw = SQ_LibraryHandler::instance()->libraryByName(convopt.libname);
|
|
|
|
if(!lr || !lw)
|
|
{
|
|
gerrors++;
|
|
emit convertText(err_internal, true);
|
|
emit oneFileProcessed();
|
|
continue;
|
|
}
|
|
|
|
name = TQFile::encodeName(*it);
|
|
|
|
i = lr->codec->read_init(name.ascii());
|
|
|
|
if(setjmp(jmp))
|
|
{
|
|
gerrors++;
|
|
|
|
lr->codec->read_close();
|
|
|
|
emit convertText(SQ_ErrorString::instance()->stringSN(error_code), true);
|
|
emit oneFileProcessed();
|
|
|
|
continue;
|
|
}
|
|
|
|
if(i != SQE_OK)
|
|
errorjmp(jmp, i);
|
|
|
|
errors = 0;
|
|
current = 0;
|
|
|
|
while(true)
|
|
{
|
|
brk = (allpages == 1 && current) || (allpages == 2 && current == pages_num);
|
|
|
|
i = lr->codec->read_next();
|
|
|
|
im = lr->codec->image(current-1);
|
|
|
|
if(i != SQE_OK || brk)
|
|
{
|
|
if(i == SQE_NOTOK || brk)
|
|
{
|
|
if(current == 1)
|
|
name = adjustFileName(prefix, *it, replace, putto);
|
|
else
|
|
name = adjustFileName(prefix, *it, replace, putto, true, current);
|
|
|
|
lastFrame = last;
|
|
|
|
i = manipAndWriteDecodedImage(tempfile->name(), im);
|
|
|
|
emit convertText(errors ? (i18n("1 error", "%n errors", errors)+'\n') : SQ_ErrorString::instance()->stringSN(SQE_OK), true);
|
|
emit oneFileProcessed();
|
|
|
|
i = SQE_OK;
|
|
|
|
if(replace == 2)
|
|
{
|
|
emit convertText(i18n("Removing") + KStringHandler::rsqueeze(ff.fileName()) + TQString("... "), false);
|
|
|
|
bool b = TQFile::remove(*it);
|
|
|
|
emit convertText(b ? SQ_ErrorString::instance()->stringSN(SQE_OK) : err_failed, true);
|
|
emit oneFileProcessed();
|
|
}
|
|
|
|
i = copyFile(tempfile->name(), name);
|
|
|
|
break;
|
|
}
|
|
else
|
|
errorjmp(jmp, i);
|
|
}
|
|
|
|
if(current)
|
|
{
|
|
name = adjustFileName(prefix, *it, replace, putto, true, current);
|
|
|
|
lastFrame = false;
|
|
|
|
manipAndWriteDecodedImage(tempfile->name(), im);
|
|
i = copyFile(tempfile->name(), name);
|
|
}
|
|
|
|
im = lr->codec->image(current);
|
|
|
|
image = (RGBA *)realloc(image, im->w * im->h * sizeof(RGBA));
|
|
|
|
if(!image)
|
|
{
|
|
i = SQE_R_NOMEMORY;
|
|
errorjmp(jmp, i);
|
|
}
|
|
|
|
for(int pass = 0;pass < im->passes;pass++)
|
|
{
|
|
lr->codec->read_next_pass();
|
|
|
|
for(j = 0;j < im->h;j++)
|
|
{
|
|
scan = image + j * im->w;
|
|
i = lr->codec->read_scanline(scan);
|
|
errors += (int)(i != SQE_OK);
|
|
}
|
|
}
|
|
|
|
if(im->needflip)
|
|
fmt_utils::flipv((char *)image, im->w * sizeof(RGBA), im->h);
|
|
|
|
convert->fillWriteOptions(&opt, lw->opt);
|
|
|
|
opt.alpha = im->hasalpha;
|
|
|
|
current++;
|
|
}
|
|
|
|
lr->codec->read_close();
|
|
}
|
|
else
|
|
{
|
|
emit convertText(SQ_ErrorString::instance()->stringSN(SQE_R_NOTSUPPORTED), true);
|
|
emit oneFileProcessed();
|
|
}
|
|
}
|
|
|
|
if(image)
|
|
{
|
|
free(image);
|
|
image = 0;
|
|
}
|
|
|
|
delete convert;
|
|
delete tempfile;
|
|
|
|
if(imageopt.close && !gerrors)
|
|
emit done(true);
|
|
else
|
|
emit done(false);
|
|
}
|
|
|
|
int SQ_Converter::manipAndWriteDecodedImage(const TQString &name, fmt_image *im)
|
|
{
|
|
int passes = opt.interlaced ? lw->opt.passes : 1;
|
|
int s, j, err;
|
|
RGBA *scan = 0;
|
|
|
|
scan = new RGBA [im->w];
|
|
|
|
if(!scan)
|
|
return SQE_W_NOMEMORY;
|
|
|
|
err = lw->codec->write_init(name.ascii(), *im, opt);
|
|
|
|
if(err != SQE_OK)
|
|
goto error_exit;
|
|
|
|
err = lw->codec->write_next();
|
|
|
|
if(err != SQE_OK)
|
|
goto error_exit;
|
|
|
|
for(s = 0;s < passes;s++)
|
|
{
|
|
err = lw->codec->write_next_pass();
|
|
|
|
if(err != SQE_OK)
|
|
goto error_exit;
|
|
|
|
for(j = 0;j < im->h;j++)
|
|
{
|
|
if(lw->opt.needflip)
|
|
determineNextScan(*im, scan, im->h-j-1);
|
|
else
|
|
determineNextScan(*im, scan, j);
|
|
|
|
err = lw->codec->write_scanline(scan);
|
|
|
|
if(err != SQE_OK)
|
|
goto error_exit;
|
|
}
|
|
}
|
|
|
|
err = SQE_OK;
|
|
|
|
error_exit:
|
|
|
|
lw->codec->write_close();
|
|
|
|
delete scan;
|
|
|
|
return err;
|
|
}
|
|
|
|
int SQ_Converter::copyFile(const TQString &src, const TQString &dst) const
|
|
{
|
|
TQFile f_src(src), f_dst(dst);
|
|
TQ_LONG read;
|
|
char data[4096];
|
|
|
|
if(!f_src.open(IO_ReadOnly))
|
|
return SQE_R_NOFILE;
|
|
|
|
if(!f_dst.open(IO_WriteOnly))
|
|
{
|
|
f_src.close();
|
|
return SQE_W_NOFILE;
|
|
}
|
|
|
|
while(!f_src.atEnd())
|
|
{
|
|
read = f_src.readBlock(data, sizeof(data));
|
|
|
|
f_dst.writeBlock(data, read);
|
|
|
|
if(f_dst.status() != IO_Ok || f_src.status() != IO_Ok)
|
|
{
|
|
f_src.close();
|
|
f_dst.close();
|
|
|
|
return SQE_W_ERROR;
|
|
}
|
|
}
|
|
|
|
f_src.close();
|
|
f_dst.close();
|
|
|
|
return SQE_OK;
|
|
}
|
|
|
|
void SQ_Converter::determineNextScan(const fmt_image &im, RGBA *scan, int y)
|
|
{
|
|
memcpy(scan, image + y * im.w, im.w * sizeof(RGBA));
|
|
}
|
|
|
|
void SQ_Converter::startEditPrivate()
|
|
{
|
|
convert = new SQ_ImageConvert(KSquirrel::app());
|
|
convert->setCaption(i18n("Convert 1 file", "Convert %n files", files.count()));
|
|
|
|
connect(convert, TQT_SIGNAL(convert(SQ_ImageOptions*, SQ_ImageConvertOptions*)), this, TQT_SLOT(slotStartConvert(SQ_ImageOptions*, SQ_ImageConvertOptions*)));
|
|
connect(this, TQT_SIGNAL(convertText(const TQString &, bool)), convert, TQT_SLOT(slotDebugText(const TQString &, bool)));
|
|
connect(this, TQT_SIGNAL(oneFileProcessed()), convert, TQT_SLOT(slotOneProcessed()));
|
|
connect(this, TQT_SIGNAL(done(bool)), convert, TQT_SLOT(slotDone(bool)));
|
|
|
|
convert->exec();
|
|
}
|
|
|
|
void SQ_Converter::slotStartConvert(SQ_ImageOptions *o, SQ_ImageConvertOptions *copt)
|
|
{
|
|
imageopt = *o;
|
|
convopt = *copt;
|
|
|
|
decodingCycle();
|
|
}
|
|
|
|
#include "sq_converter.moc"
|