/* -*- mona-c++ -*-
* Copyright (c) Leipzig, Madrid 2004 - 2008
* Max-Planck-Institute for Human Cognitive and Brain Science
* Max-Planck-Institute for Evolutionary Anthropology
* BIT, ETSI Telecomunicacion, UPM
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string>
#include <libmona/3DImagePtr.hh>
#include <libmona/monaException.hh>
using namespace mona;
using namespace std;
inline bool am_big_endian()
{
#ifdef WORDS_BIGENDIAN
return true;
#else
return false;
#endif
}
template <typename I>
void handle_endian(I b, I e)
{
typedef typename iterator_traits<I>::value_type Pixel;
typedef union {
char s[sizeof(Pixel)];
Pixel v;
} shuffle;
switch (sizeof(Pixel)) {
case 2:
while (b != e) {
shuffle s;
s.v = *b;
swap(s.s[0], s.s[1]);
*b = s.v;
++b;
}
break;
case 4:
while (b != e) {
shuffle s;
s.v = *b;
swap(s.s[0], s.s[3]);
swap(s.s[1], s.s[2]);
*b = s.v;
++b;
}
break;
case 8:
while (b != e) {
shuffle s;
s.v = *b;
swap(s.s[0],s.s[7]);
swap(s.s[1],s.s[6]);
swap(s.s[2],s.s[5]);
swap(s.s[3],s.s[4]);
*b = s.v;
++b;
}
break;
// default:
}
}
template <typename Image>
C3DImageWrap read_image_type(CInputFile& in_file, const C3DBounds& size, const C3DFVector& scale, bool big_endian)
{
typedef typename Image::value_type T;
Image *image = new Image(size);
if (!image) {
stringstream errmsg;
errmsg << "Unable to allocate image of size " << size;
throw runtime_error(errmsg.str());
}
if (fread(&(*image)(0,0,0), sizeof(T), image->size(), in_file) != image->size()) {
throw runtime_error("Unable to read full image");
}
image->set_attribute("voxel", new C3DVectorAttribute(scale));
if ( (sizeof(T) > 1 ) && (big_endian != am_big_endian())) {
handle_endian(image->begin(), image->end());
}
return C3DImageWrap(image);
}
C3DImageWrap read_image(CInputFile& in_file, int pixel_type, const C3DBounds& size, const C3DFVector& scale, bool high_endian)
{
switch (pixel_type) {
case it_ubyte: return read_image_type<C3DUBImage>(in_file, size, scale, high_endian);
case it_sbyte: return read_image_type<C3DSBImage>(in_file, size, scale, high_endian);
case it_sshort:return read_image_type<C3DSSImage>(in_file, size, scale, high_endian);
case it_ushort:return read_image_type<C3DUSImage>(in_file, size, scale, high_endian);
case it_sint: return read_image_type<C3DSIImage>(in_file, size, scale, high_endian);
case it_uint: return read_image_type<C3DUIImage>(in_file, size, scale, high_endian);
case it_float: return read_image_type<C3DFImage> (in_file, size, scale, high_endian);
case it_double: return read_image_type<C3DDImage> (in_file, size, scale, high_endian);
default:
throw invalid_argument("given input pixel format not supported");
};
}
int run(int argc, const char *args[])
{
int pixel_type;
bool high_endian = false;
vector<int> size;
vector<float> scale;
string in_filename;
string out_filename;
string type;
const popt::option::Dictionary PixelTypeTable[] = {
{"ubyte", it_ubyte},
{"sbyte", it_sbyte},
{"short", it_sshort},
{"ushort",it_ushort},
{"int", it_sint},
{"uint", it_uint},
{"float", it_float},
{"double", it_double},
{NULL, 0}
};
C3DImageIOPluginHandler imageio;
if (imageio.get_set().empty())
throw runtime_error("Sorry, no 3D output formats supported");
popt::COptions options;
options.push_back(popt::option( in_filename, "in-file", 'i', "input file name", NULL));
options.push_back(popt::option( out_filename, "out-file", 'o', "output file name", NULL));
options.push_back(popt::option( pixel_type, PixelTypeTable, "repn", 'r',"input pixel type ", "short"));
options.push_back(popt::option( high_endian, "big-endian", 'b', "input data is big endian"));
options.push_back(popt::option( size, "size", 's', "size of input NX,NY,NZ", "1,1,1"));
options.push_back(popt::option( scale, "scale", 'f', "scale of input voxels FX,FY,FZ", "1.0,1.0,1.0"));
options.push_back(popt::option( type, imageio.get_set(), "type", 't', "Output file type", "vista"));
vector<string> unknows_args;
popt::parse_options(argc, args, options, unknows_args);
if (!unknows_args.empty()) {
cverr() << "Unknown arguments: ";
for (vector<string>::const_iterator i = unknows_args.begin(); i != unknows_args.end();
++i)
cverb << *i << " ";
cverb << "\n";
return -1;
}
if (in_filename.empty()) {
cverr() << "No input file given, run '" << args[0] << " --help' to get help\n";
return -1;
}
if (out_filename.empty()) {
cverr() << "No output filename given, run '" << args[0] << " --help' to get help\n";
return -1;
}
CInputFile in_file(in_filename);
if ( !in_file )
throw mona_fatal_error(string("Unable to open ")+ in_filename);
if (size.size() != 3)
throw invalid_argument("size takes exactly 3 parameters");
if (scale.size() != 3)
throw invalid_argument("scale takes exactly 3 parameters");
C3DBounds bsize(size[0], size[1],size[2]);
C3DFVector fscale(scale[0], scale[1], scale[2]);
C3DImageList out_images;
out_images.push_back(read_image(in_file, pixel_type, bsize, fscale, high_endian));
return !imageio.save(type, out_images, out_filename);
}
int main(int argc, const char *args[])
{
try {
return run(argc, args);
}
catch (const mona_runtime_error& e){
cerr << args[0] << " error: " << e.what() << endl;
}
catch (const mona_fatal_error& e){
cerr << args[0] << " fatal: " << e.what() << endl;
}
catch (const mona_exception& e){
cerr << args[0] << " error: " << e.what() << endl;
}
catch (const runtime_error &e){
cerr << args[0] << " runtime: " << e.what() << endl;
}
catch (const invalid_argument &e){
cerr << args[0] << " error: " << e.what() << endl;
}
catch (const exception& e){
cerr << args[0] << " error: " << e.what() << endl;
}
catch (...){
cerr << args[0] << " unknown exception" << endl;
}
return EXIT_FAILURE;
}