4 #include <iostream> // cout and cerr streams
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) {
32 QImage
image(inpName
);
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
);
40 // configure the module tree
41 IRoot
*root
= IRoot::compatiblePrototype()
42 .clone( confName
? Module::ShallowCopy
: Module::DeepCopy
);
44 if ( !root
->allSettingsFromFile(confName
) )
45 throw tr("Error while reading configuration file \"%1\"") .arg(confName
);
47 confName
= "<default>";
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());
55 throw tr("Can't write output file \"%1\"") .arg(outName
);
57 // decode the image and measure the PSNR
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
;
86 /* Declared and commented in main.cpp */
87 int batchRun(const vector
<const char*> &names
) {
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();
96 while (nextStart
<length
) { // process a block of files
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");
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
]);
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
);
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])
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
]);
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" );
167 outNameStart
+= "_%1.fci";
168 for (int confID
=confStart
; confID
<outpStart
; ++confID
) {
169 QString cName
= QFileInfo(QString(names
[confID
]))
171 encodeFile( names
[inputID
], outNameStart
.arg(cName
)
178 throw tr("The compression output \"%1\" should be"
179 " either fractal image or a directory") .arg(names
[outpStart
]);
180 } // switch (types[outpStart])
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
;