00001 #include "headers.h"
00002 #include "imageUtil.h"
00003
00004 #include <iostream>
00005 #include <memory>
00006
00007 #include <QDir>
00008 #include <QFileInfo>
00009 #include <QImage>
00010 #include <QObject>
00011 #include <QString>
00012 #include <QTime>
00013
00014 using namespace std;
00015
00017 inline QString tr(const char *str) { return QObject::tr(str); }
00018
00020 void decodeFile(const char *inpName,QString outName) {
00021 auto_ptr<IRoot> root( IRoot::compatiblePrototype().clone(Module::ShallowCopy) );
00022 if ( !root->fromFile(inpName) )
00023 throw tr("Error while reading file \"%1\"") .arg(inpName);
00024 root->decodeAct(MTypes::Clear);
00025 root->decodeAct(MTypes::Iterate,10);
00026 if ( !root->toImage().save(outName) )
00027 throw tr("Error while writing file \"%1\"") .arg(outName);
00028 }
00031 void encodeFile(const char *inpName,QString outName,const char *confName=0) {
00032
00033 QImage image(inpName);
00034 if (image.isNull())
00035 throw tr("Can't read bitmap image \"%1\"") .arg(inpName);
00036 if ( image.format() != QImage::Format_RGB32 )
00037 image= image.convertToFormat(QImage::Format_RGB32);
00038
00039 QTime time;
00040 time.start();
00041
00042 Module::CloneMethod clMethod= confName ? Module::ShallowCopy : Module::DeepCopy;
00043 auto_ptr<IRoot> root( IRoot::compatiblePrototype().clone(clMethod) );
00044 if (confName) {
00045 if ( !root->allSettingsFromFile(confName) )
00046 throw tr("Error while reading configuration file \"%1\"") .arg(confName);
00047 } else
00048 confName= "<default>";
00049
00050 if ( !root->encode(image) )
00051 throw tr("Error while encoding file \"%1\" with %2 configuration")
00052 .arg(inpName) .arg( tr(confName) );
00053 float encTime= time.elapsed()/1000.0;
00054 int outSize= root->toFile(outName.toStdString().c_str());
00055 if (!outSize)
00056 throw tr("Can't write output file \"%1\"") .arg(outName);
00057
00058
00059 time.restart();
00060 root->decodeAct(MTypes::Clear);
00061 root->decodeAct(MTypes::Iterate,10);
00062 float decTime= time.elapsed()/1000.0;
00063 vector<Real> psnr= Color::getPSNR( root->toImage(), image );
00064
00065 cout << inpName << " " << confName << " ";
00066 for (int i=0; i<4; ++i)
00067 cout << psnr[i] << " ";
00068 Real grayRatio= image.width()*image.height() / Real(outSize);
00069 cout << grayRatio << " " << 3*grayRatio << " ";
00070 cout << encTime << " " << decTime << endl;
00071 }
00072
00074 struct FileClassifier {
00076 enum FileType { Fractal, Bitmap, Config, Directory };
00077
00078 FileType operator()(const char *name) const {
00079 QString suffix= QFileInfo(QString(name)).suffix();
00080 if (suffix=="") return Directory;
00081 if (suffix=="fci") return Fractal;
00082 if (suffix=="fcs") return Config;
00083 else return Bitmap;
00084 }
00085 };
00086
00087
00088 int batchRun(const vector<const char*> &names) {
00089 try {
00090
00091 vector<FileClassifier::FileType> types;
00092 transform( names.begin(), names.end(), back_inserter(types), FileClassifier() );
00093
00094 int inpStart, confStart, outpStart, nextStart;
00095 int length= names.size();
00096 nextStart= 0;
00097 while (nextStart<length) {
00098 inpStart= nextStart;
00099
00100 FileClassifier::FileType inpType= types[inpStart];
00101
00102 for ( confStart= inpStart+1;
00103 confStart<length && types[confStart]==inpType;
00104 ++confStart ) ;
00105
00106 for ( outpStart= confStart;
00107 outpStart<length && types[outpStart]==FileClassifier::Config;
00108 ++outpStart ) ;
00109 nextStart= outpStart+1;
00110
00111 if (nextStart>length)
00112 throw tr("Missing output at the end of the parameter list");
00113
00114 switch (inpType) {
00115
00116
00117 case FileClassifier::Fractal:
00118 if (confStart<outpStart)
00119 throw tr("No config file should be specified for decompression"
00120 " (parameter %1)") .arg(confStart+1);
00121 switch (types[outpStart]) {
00122 case FileClassifier::Bitmap: {
00123 if (confStart-inpStart!=1)
00124 throw tr("A single output file (\"%1\")"
00125 " can only be used with single input") .arg(names[outpStart]);
00126 decodeFile(names[inpStart],names[outpStart]);
00127 }
00128 break;
00129 case FileClassifier::Directory:
00130 for (int inputID=inpStart; inputID<confStart; ++inputID) {
00131
00132 QFileInfo inputInfo(names[inputID]);
00133 if ( !inputInfo.isReadable() )
00134 throw tr("Can't open file \"%1\"") .arg(names[inputID]);
00135
00136 QString outName= QString("%1%2%3.png") .arg(names[outpStart])
00137 .arg(QDir::separator()) .arg(inputInfo.completeBaseName());
00138 decodeFile( names[inputID], outName );
00139 }
00140 break;
00141 default:
00142 throw tr("The decompression output \"%1\" shouldn't be fractal image")
00143 .arg(names[outpStart]);
00144 }
00145 break;
00146
00147
00148 case FileClassifier::Bitmap:
00149 switch (types[outpStart]) {
00150 case FileClassifier::Fractal: {
00151 if (confStart-inpStart!=1)
00152 throw tr("A single output file (\"%1\")"
00153 " can only be used with single input") .arg(names[outpStart]);
00154 encodeFile(names[inpStart],names[outpStart]);
00155 }
00156 break;
00157 case FileClassifier::Directory:
00158 for (int inputID=inpStart; inputID<confStart; ++inputID) {
00159 QString outNameStart= names[outpStart] + ( QDir::separator()
00160 + QFileInfo(names[inputID]).completeBaseName() );
00161
00162 if (confStart==outpStart)
00163 encodeFile( names[inputID], outNameStart+".fci" );
00164 else {
00165 outNameStart+= "_%1.fci";
00166 for (int confID=confStart; confID<outpStart; ++confID) {
00167 QString cName= QFileInfo(QString(names[confID]))
00168 .completeBaseName();
00169 encodeFile( names[inputID], outNameStart.arg(cName)
00170 , names[confID] );
00171 }
00172 }
00173 }
00174 break;
00175 default:
00176 throw tr("The compression output \"%1\" should be"
00177 " either fractal image or a directory") .arg(names[outpStart]);
00178 }
00179 break;
00180
00181 default:
00182 throw tr("Invalid input file \"%1\"").arg(names[inpStart]);
00183 }
00184
00185 }
00186 } catch (QString &message) {
00187 cerr << message.toStdString() << endl;
00188 return 1;
00189 }
00190 return 0;
00191 }