00001
00002
00003
00004
00005
00006
00007 #include "Jpeg2000.h"
00008 #include "Jpeg2000Callbacks.h"
00009 #include "Jpeg2000Color.h"
00010 #include "Jpeg2000FormatDefs.h"
00011 #include "Logger.h"
00012 #include <QBuffer>
00013 #include <QFile>
00014 #include <QImage>
00015 #include <QString>
00016
00017 #define JP2_RFC3745_MAGIC "\x00\x00\x00\x0c\x6a\x50\x20\x20\x0d\x0a\x87\x0a"
00018 #define JP2_MAGIC "\x0d\x0a\x87\x0a"
00019 #define J2K_CODESTREAM_MAGIC "\xff\x4f\xff\x51"
00020
00021 Jpeg2000::Jpeg2000()
00022 {
00023 }
00024
00025 void Jpeg2000::applyImageTweaks (opj_image_t *image) const
00026 {
00027 if (image->color_space == OPJ_CLRSPC_SYCC) {
00028 color_sycc_to_rgb (image);
00029 }
00030
00031 if (image->color_space != OPJ_CLRSPC_SYCC &&
00032 image->numcomps == 3 &&
00033 image->comps[0].dx == image->comps[0].dy &&
00034 image->comps[1].dx != 1) {
00035 image->color_space = OPJ_CLRSPC_SYCC;
00036 } else if (image->numcomps <= 2) {
00037 image->color_space = OPJ_CLRSPC_GRAY;
00038 }
00039
00040 if (image->icc_profile_buf) {
00041 #if defined(OPJ_HAVE_LIBLCMS1) || defined(OPJ_HAVE_LIBLCMS2)
00042 color_apply_icc_profile (image);
00043 #endif
00044 free (image->icc_profile_buf);
00045 image->icc_profile_buf = 0;
00046 image->icc_profile_len = 0;
00047 }
00048 }
00049
00050 opj_codec_t *Jpeg2000::decode (int decodeFormat) const
00051 {
00052 switch(decodeFormat)
00053 {
00054 case J2K_CFMT:
00055 return opj_create_decompress(OPJ_CODEC_J2K);
00056
00057 case JP2_CFMT:
00058 return opj_create_decompress(OPJ_CODEC_JP2);
00059
00060 case JPT_CFMT:
00061 return opj_create_decompress(OPJ_CODEC_JPT);
00062
00063 default:
00064 break;
00065 }
00066
00067 return 0;
00068 }
00069
00070 int Jpeg2000::getFileFormat(const char *filename) const
00071 {
00072 static const char *extension[] = {"pgx", "pnm", "pgm", "ppm", "bmp",
00073 "tif", "raw", "rawl", "tga", "png",
00074 "j2k", "jp2", "jpt", "j2c", "jpc"};
00075 static const int format[] = {PGX_DFMT, PXM_DFMT, PXM_DFMT, PXM_DFMT, BMP_DFMT,
00076 TIF_DFMT, RAW_DFMT, RAWL_DFMT, TGA_DFMT, PNG_DFMT,
00077 J2K_CFMT, JP2_CFMT, JPT_CFMT, J2K_CFMT, J2K_CFMT};
00078 const char * ext = strrchr(filename, '.');
00079 if (ext == NULL) {
00080 return -1;
00081 }
00082 ext++;
00083 if (*ext) {
00084 for (unsigned int i = 0; i < sizeof(format)/sizeof(*format); i++) {
00085 if(strcasecmp(ext, extension[i]) == 0) {
00086 return format[i];
00087 }
00088 }
00089 }
00090
00091 return -1;
00092 }
00093
00094 void Jpeg2000::initializeParameters (opj_dparameters_t ¶meters) const
00095 {
00096 parameters.cp_reduce = 0;
00097 parameters.cp_layer = 0;
00098 parameters.cod_format = 10;
00099 parameters.decod_format = 1;
00100 parameters.DA_x0 = 0;
00101 parameters.DA_x1 = 0;
00102 parameters.DA_y0 = 0;
00103 parameters.DA_y1 = 0;
00104 parameters.m_verbose = 0;
00105 parameters.tile_index = 0;
00106 parameters.nb_tile_to_decode = 0;
00107 parameters.jpwl_correct = 0;
00108 parameters.jpwl_exp_comps = 0;
00109 parameters.jpwl_max_tiles = 0;
00110 parameters.flags = 0;
00111 }
00112
00113 int Jpeg2000::inputFormat(const char *filename) const
00114 {
00115 FILE *reader;
00116 const char *s, *magic_s;
00117 int ext_format, magic_format;
00118 unsigned char buf[12];
00119 OPJ_SIZE_T l_nb_read;
00120
00121 reader = fopen(filename,
00122 "rb");
00123
00124 if (reader == NULL) {
00125 return -2;
00126 }
00127
00128 memset(buf, 0, 12);
00129 l_nb_read = fread(buf, 1, 12, reader);
00130 fclose(reader);
00131 if (l_nb_read != 12) {
00132 return -1;
00133 }
00134
00135 ext_format = getFileFormat(filename);
00136
00137 if (ext_format == JPT_CFMT) {
00138 return JPT_CFMT;
00139 }
00140
00141 if (memcmp(buf, JP2_RFC3745_MAGIC, 12) == 0 || memcmp(buf, JP2_MAGIC, 4) == 0) {
00142 magic_format = JP2_CFMT;
00143 magic_s = ".jp2";
00144 } else if (memcmp(buf, J2K_CODESTREAM_MAGIC, 4) == 0) {
00145 magic_format = J2K_CFMT;
00146 magic_s = ".j2k or .jpc or .j2c";
00147 } else {
00148 return -1;
00149 }
00150
00151 if (magic_format == ext_format) {
00152 return ext_format;
00153 }
00154
00155 s = filename + strlen(filename) - 4;
00156
00157 LOG4CPP_ERROR_S ((*mainCat)) << "Jpeg2000::inputFormat"
00158 << "The extension of this file is incorrect. Found " << s
00159 << ". Should be " << magic_s;
00160
00161 return magic_format;
00162 }
00163
00164 bool Jpeg2000::invalidFileExtension (const QString &filename) const
00165 {
00166 const int CHARACTER_IN_EXTENSION = 3;
00167
00168 bool invalid = true;
00169
00170
00171
00172 QString extensionGot = filename.right (CHARACTER_IN_EXTENSION);
00173
00174 QStringList extensions = supportedFileExtensions();
00175 QStringList::iterator itr;
00176 for (itr = extensions.begin(); itr != extensions.end(); itr++) {
00177
00178 QString extensionWanted = *itr;
00179 if (QString::compare (extensionGot,
00180 extensionWanted,
00181 Qt::CaseInsensitive)) {
00182
00183
00184 invalid = false;
00185 break;
00186 }
00187 }
00188
00189 return invalid;
00190 }
00191
00192 bool Jpeg2000::load (const QString &filename,
00193 QImage &imageResult) const
00194 {
00195 LOG4CPP_INFO_S ((*mainCat)) << "Jpeg2000::load"
00196 << " filename=" << filename.toLatin1().data();
00197
00198 if (invalidFileExtension (filename)) {
00199 return false;
00200 }
00201
00202 opj_dparameters_t parameters;
00203 initializeParameters (parameters);
00204
00205 parameters.decod_format = inputFormat (filename.toLatin1().data());
00206
00207 opj_stream_t *inStream = opj_stream_create_default_file_stream (filename.toLatin1().data(), 1);
00208 if (!inStream) {
00209 LOG4CPP_ERROR_S ((*mainCat)) << "Jpeg2000::load encountered error opening stream";
00210 return false;
00211 }
00212
00213
00214 opj_codec_t *inCodec = decode (parameters.decod_format);
00215 if (!inCodec) {
00216 LOG4CPP_ERROR_S ((*mainCat)) << "Jpeg2000::load encountered error creating decoding stream";
00217 opj_stream_destroy (inStream);
00218 return false;
00219 }
00220
00221
00222 opj_set_info_handler (inCodec, infoCallback, 0);
00223 opj_set_warning_handler (inCodec, warningCallback, 0);
00224 opj_set_error_handler (inCodec, errorCallback, 0);
00225
00226 if (!opj_setup_decoder (inCodec,
00227 ¶meters)) {
00228 LOG4CPP_ERROR_S ((*mainCat)) << "Jpeg2000::load encountered error decoding stream";
00229 opj_stream_destroy (inStream);
00230 opj_destroy_codec (inCodec);
00231 return false;
00232 }
00233
00234
00235 opj_image_t *image;
00236 if (!opj_read_header (inStream,
00237 inCodec,
00238 &image)) {
00239 LOG4CPP_ERROR_S ((*mainCat)) << "Jpeg2000::load encountered error reading header";
00240 opj_stream_destroy (inStream);
00241 opj_destroy_codec (inCodec);
00242 opj_image_destroy (image);
00243 return false;
00244 }
00245
00246
00247 if (!(opj_decode (inCodec,
00248 inStream,
00249 image) &&
00250 opj_end_decompress (inCodec,
00251 inStream))) {
00252 LOG4CPP_ERROR_S ((*mainCat)) << "Jpeg2000::load failed to decode image";
00253 opj_destroy_codec (inCodec);
00254 opj_stream_destroy (inStream);
00255 opj_image_destroy (image);
00256 return false;
00257 }
00258
00259
00260 opj_stream_destroy (inStream);
00261
00262 applyImageTweaks (image);
00263
00264
00265 bool success = true;
00266 QBuffer buffer;
00267 buffer.open (QBuffer::WriteOnly);
00268 if (imagetopnm (image,
00269 buffer)) {
00270 LOG4CPP_ERROR_S ((*mainCat)) << "Jpeg2000::load failed to generate new image";
00271 success = false;
00272
00273 } else {
00274
00275
00276
00277
00278
00279
00280
00281
00282 imageResult.loadFromData(buffer.data());
00283
00284 }
00285
00286
00287 if (inCodec) {
00288 opj_destroy_codec (inCodec);
00289 }
00290 opj_image_destroy (image);
00291
00292 return success;
00293 }
00294
00295 QStringList Jpeg2000::supportedFileExtensions () const
00296 {
00297 QStringList extensions;
00298
00299
00300 extensions << "j2k" << "jp2" << "jpc" << "jpt";
00301
00302 return extensions;
00303 }
00304
00305 QStringList Jpeg2000::supportedImageWildcards () const
00306 {
00307 QStringList extensions = supportedFileExtensions();
00308 QStringList wildcards;
00309
00310 QStringList::iterator itr;
00311 for (itr = extensions.begin(); itr != extensions.end(); itr++) {
00312 QString extension = *itr;
00313 QString wildcard = QString ("*.%1").arg (extension);
00314 wildcards << wildcard;
00315 }
00316
00317 return wildcards;
00318 }