Fixed errors in fileUtil.h.
[fic.git] / batch.cpp
blobcca2e5a664baa64bd8f7693923830535ee293469
1 #include "headers.h"
2 #include "imageUtil.h"
4 #include <iostream> // cout and cerr streams
6 #include <QDir>
7 #include <QFileInfo>
8 #include <QImage>
9 #include <QObject>
10 #include <QString>
11 #include <QTime>
13 using namespace std;
15 /** A shortcut for Qt's QObject::tr */
16 inline QString tr(const char *str) { return QObject::tr(str); }
18 /** Decodes a fractal image into a bitmap image */
19 void decodeFile(const char *inpName,QString outName) {
20 IRoot *root= IRoot::compatiblePrototype().clone(Module::ShallowCopy);
21 if ( !root->fromFile(inpName) )
22 throw tr("Error while reading file \"%1\"") .arg(inpName);
23 root->decodeAct(MTypes::Clear);
24 root->decodeAct(MTypes::Iterate,10); ///< \todo constant 10
25 if ( !root->toImage().save(outName) )
26 throw tr("Error while writing file \"%1\"") .arg(outName);
28 /** Encodes a bitmap image into a fractal image using specified configuration file.
29 * It also measures times, PSNRs, compression ratios, etc. and outputs the information. */
30 void encodeFile(const char *inpName,QString outName,const char *confName=0) {
31 // load the bitmap
32 QImage image(inpName);
33 if (image.isNull())
34 throw tr("Can't read bitmap image \"%1\"") .arg(inpName);
35 if ( image.format() != QImage::Format_RGB32 ) // convert to 24-bits
36 image= image.convertToFormat(QImage::Format_RGB32);
38 QTime time;
39 time.start();
40 // configure the module tree
41 IRoot *root= IRoot::compatiblePrototype()
42 .clone( confName ? Module::ShallowCopy : Module::DeepCopy );
43 if (confName) {
44 if ( !root->allSettingsFromFile(confName) )
45 throw tr("Error while reading configuration file \"%1\"") .arg(confName);
46 } else
47 confName= "<default>";
48 // encode the image
49 if ( !root->encode(image) )
50 throw tr("Error while encoding file \"%1\" with %2 configuration")
51 .arg(inpName) .arg( tr(confName) );
52 float encTime= time.elapsed()/1000.0;
53 int outSize= root->toFile(outName.toStdString().c_str());
54 if (!outSize)
55 throw tr("Can't write output file \"%1\"") .arg(outName);
57 // decode the image and measure the PSNR
58 time.restart();
59 root->decodeAct(MTypes::Clear);
60 root->decodeAct(MTypes::Iterate,10); ///< \todo constant 10
61 float decTime= time.elapsed()/1000.0;
62 vector<Real> psnr= Color::getPSNR( root->toImage(), image );
63 // output the information
64 cout << inpName << " " << confName << " "; //< the input and config name
65 for (int i=0; i<4; ++i) // the PSNRs
66 cout << psnr[i] << " ";
67 Real grayRatio= image.width()*image.height() / Real(outSize);
68 cout << grayRatio << " " << 3*grayRatio << " "; //< gray and color compression ratio
69 cout << encTime << " " << decTime << endl; //< encoding and decoding time
72 /** A functor providing filename classification into one of FileClassifier::FileType */
73 struct FileClassifier {
74 /** The used file types */
75 enum FileType { Fractal, Bitmap, Config, Directory };
77 FileType operator()(const char *name) const {
78 QString suffix= QFileInfo(QString(name)).suffix();
79 if (suffix=="") return Directory;
80 if (suffix=="fci") return Fractal;
81 if (suffix=="fcs") return Config;
82 else return Bitmap;
86 /* Declared and commented in main.cpp */
87 int batchRun(const vector<const char*> &names) {
88 try {
89 // classify the types of the parameters
90 vector<FileClassifier::FileType> types;
91 transform( names.begin(), names.end(), back_inserter(types), FileClassifier() );
93 int inpStart, confStart, outpStart, nextStart;
94 int length= names.size();
95 nextStart= 0;
96 while (nextStart<length) { // process a block of files
97 inpStart= nextStart;
99 FileClassifier::FileType inpType= types[inpStart];
100 // find the end of input-file list
101 for ( confStart= inpStart+1;
102 confStart<length && types[confStart]==inpType;
103 ++confStart ) /* no body */;
104 // find the end of config-file list
105 for ( outpStart= confStart;
106 outpStart<length && types[outpStart]==FileClassifier::Config;
107 ++outpStart ) /* no body */;
108 nextStart= outpStart+1; //< exactly one output per block
110 if (nextStart>length)
111 throw tr("Missing output at the end of the parameter list");
113 switch (inpType) {
115 // decompression
116 case FileClassifier::Fractal:
117 if (confStart<outpStart)
118 throw tr("No config file should be specified for decompression"
119 " (parameter %1)") .arg(confStart+1);
120 switch (types[outpStart]) {
121 case FileClassifier::Bitmap: { // the output is a single specified file
122 if (confStart-inpStart!=1) //< checking the input is single
123 throw tr("A single output file (\"%1\")"
124 " can only be used with single input") .arg(names[outpStart]);
125 decodeFile(names[inpStart],names[outpStart]);
127 break;
128 case FileClassifier::Directory: // the output is a directory
129 for (int inputID=inpStart; inputID<confStart; ++inputID) {
130 // test input's existence and permissions
131 QFileInfo inputInfo(names[inputID]);
132 if ( !inputInfo.isReadable() )
133 throw tr("Can't open file \"%1\"") .arg(names[inputID]);
134 // construct output's name and decode the file
135 QString outName= QString("%1%2%3.png") .arg(names[outpStart])
136 .arg(QDir::separator()) .arg(inputInfo.completeBaseName());
137 decodeFile( names[inputID], outName );
139 break;
140 default: // the output is *.fci
141 throw tr("The decompression output \"%1\" shouldn't be fractal image")
142 .arg(names[outpStart]);
143 } // switch (types[outpStart])
144 break;
146 // compression
147 case FileClassifier::Bitmap:
148 switch (types[outpStart]) {
149 case FileClassifier::Fractal: { // the output is a single specified file
150 if (confStart-inpStart!=1) //< checking the input is single
151 throw tr("A single output file (\"%1\")"
152 " can only be used with single input") .arg(names[outpStart]);
153 encodeFile(names[inpStart],names[outpStart]);
155 break;
156 case FileClassifier::Directory: // the output is a directory
157 for (int inputID=inpStart; inputID<confStart; ++inputID) {
158 QFileInfo inputInfo(names[inputID]);
159 if ( !inputInfo.isReadable() )
160 throw tr("Can't open file \"%1\"") .arg(names[inputID]);
161 QString outNameStart= names[outpStart]
162 + ( QDir::separator() + inputInfo.completeBaseName() );
164 if (confStart==outpStart) // using default configuration
165 encodeFile( names[inputID], outNameStart+".fci" );
166 else {
167 outNameStart+= "_%1.fci";
168 for (int confID=confStart; confID<outpStart; ++confID) {
169 QString cName= QFileInfo(QString(names[confID]))
170 .completeBaseName();
171 encodeFile( names[inputID], outNameStart.arg(cName)
172 , names[confID] );
176 break;
177 default:
178 throw tr("The compression output \"%1\" should be"
179 " either fractal image or a directory") .arg(names[outpStart]);
180 } // switch (types[outpStart])
181 break;
183 default:
184 throw tr("Invalid input file \"%1\"").arg(names[inpStart]);
185 } // switch (inpType)
187 } // while - block-of-files processing
188 } catch (QString &message) {
189 cerr << message.toStdString() << endl;
190 return 1;
192 return 0;