Engauge Digitizer 2
Loading...
Searching...
No Matches
Jpeg2000.cpp
Go to the documentation of this file.
1/******************************************************************************************************
2 * (C) 2014 markummitchell@github.com. This file is part of Engauge Digitizer, which is released *
3 * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file *
4 * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. *
5 ******************************************************************************************************/
6
7#include "Jpeg2000.h"
8#include "Jpeg2000Callbacks.h"
9#include "Jpeg2000Color.h"
10#include "Jpeg2000FormatDefs.h"
11#include "Logger.h"
12#include <QBuffer>
13#include <QFile>
14#include <QImage>
15#include <QString>
16
17#define JP2_RFC3745_MAGIC "\x00\x00\x00\x0c\x6a\x50\x20\x20\x0d\x0a\x87\x0a"
18#define JP2_MAGIC "\x0d\x0a\x87\x0a"
19#define J2K_CODESTREAM_MAGIC "\xff\x4f\xff\x51"
20
24
25void Jpeg2000::applyImageTweaks (opj_image_t *image) const
26{
27 if (image->color_space == OPJ_CLRSPC_SYCC) {
28 color_sycc_to_rgb (image);
29 }
30
31 if (image->color_space != OPJ_CLRSPC_SYCC &&
32 image->numcomps == 3 &&
33 image->comps[0].dx == image->comps[0].dy &&
34 image->comps[1].dx != 1) {
35 image->color_space = OPJ_CLRSPC_SYCC;
36 } else if (image->numcomps <= 2) {
37 image->color_space = OPJ_CLRSPC_GRAY;
38 }
39
40 if (image->icc_profile_buf) {
41#if defined(OPJ_HAVE_LIBLCMS1) || defined(OPJ_HAVE_LIBLCMS2)
43#endif
44 free (image->icc_profile_buf);
45 image->icc_profile_buf = 0;
46 image->icc_profile_len = 0;
47 }
48}
49
50opj_codec_t *Jpeg2000::decode (int decodeFormat) const
51{
52 switch(decodeFormat)
53 {
54 case J2K_CFMT: /* JPEG-2000 codestream */
56
57 case JP2_CFMT: /* JPEG 2000 compressed image data */
59
60 case JPT_CFMT: /* JPEG 2000, JPIP */
62
63 default:
64 break;
65 }
66
67 return 0;
68}
69
70int Jpeg2000::getFileFormat(const char *filename) const
71{
72 static const char *extension[] = {"pgx", "pnm", "pgm", "ppm", "bmp",
73 "tif", "raw", "rawl", "tga", "png",
74 "j2k", "jp2", "jpt", "j2c", "jpc"};
75 static const int format[] = {PGX_DFMT, PXM_DFMT, PXM_DFMT, PXM_DFMT, BMP_DFMT,
78 const char * ext = strrchr(filename, '.');
79 if (ext == nullptr) {
80 return -1;
81 }
82 ext++;
83 if (*ext) {
84 for (unsigned int i = 0; i < sizeof(format)/sizeof(*format); i++) {
85 if(strcasecmp(ext, extension[i]) == 0) {
86 return format[i];
87 }
88 }
89 }
90
91 return -1;
92}
93
94void Jpeg2000::initializeParameters (opj_dparameters_t &parameters) const
95{
96 parameters.cp_reduce = 0;
97 parameters.cp_layer = 0;
98 parameters.cod_format = 10;
99 parameters.decod_format = 1;
100 parameters.DA_x0 = 0;
101 parameters.DA_x1 = 0;
102 parameters.DA_y0 = 0;
103 parameters.DA_y1 = 0;
104 parameters.m_verbose = 0;
105 parameters.tile_index = 0;
106 parameters.nb_tile_to_decode = 0;
107 parameters.jpwl_correct = 0;
108 parameters.jpwl_exp_comps = 0;
109 parameters.jpwl_max_tiles = 0;
110 parameters.flags = 0;
111}
112
113int Jpeg2000::inputFormat(const char *filename) const
114{
115 FILE *reader;
116 const char *s, *magic_s;
118 unsigned char buf[12];
120
122 "rb");
123
124 if (reader == nullptr) {
125 return -2;
126 }
127
128 memset(buf, 0, 12);
129 l_nb_read = fread(buf, 1, 12, reader);
130 fclose(reader);
131 if (l_nb_read != 12) {
132 return -1;
133 }
134
135 ext_format = getFileFormat(filename);
136
137 if (ext_format == JPT_CFMT) {
138 return JPT_CFMT;
139 }
140
141 if (memcmp(buf, JP2_RFC3745_MAGIC, 12) == 0 || memcmp(buf, JP2_MAGIC, 4) == 0) {
143 magic_s = ".jp2";
144 } else if (memcmp(buf, J2K_CODESTREAM_MAGIC, 4) == 0) {
146 magic_s = ".j2k or .jpc or .j2c";
147 } else {
148 return -1;
149 }
150
151 if (magic_format == ext_format) {
152 return ext_format;
153 }
154
155 s = filename + strlen(filename) - 4;
156
157 LOG4CPP_ERROR_S ((*mainCat)) << "Jpeg2000::inputFormat"
158 << "The extension of this file is incorrect. Found " << s
159 << ". Should be " << magic_s;
160
161 return magic_format;
162}
163
164bool Jpeg2000::invalidFileExtension (const QString &filename) const
165{
166 const int CHARACTER_IN_EXTENSION = 3;
167
168 bool invalid = true;
169
170 // Look for file extension in approved list. A complication is that we probably want this
171 // comparison to be case insensitive
173
174 QStringList extensions = supportedFileExtensions();
175 QStringList::iterator itr;
176 for (itr = extensions.begin(); itr != extensions.end(); itr++) {
177
179 if (QString::compare (extensionGot,
181 Qt::CaseInsensitive)) {
182
183 // Found it
184 invalid = false;
185 break;
186 }
187 }
188
189 return invalid;
190}
191
193 QImage &imageResult) const
194{
195 LOG4CPP_INFO_S ((*mainCat)) << "Jpeg2000::load"
196 << " filename=" << filename.toLatin1().data();
197
198 if (invalidFileExtension (filename)) {
199 return false;
200 }
201
203 initializeParameters (parameters);
204
205 parameters.decod_format = inputFormat (filename.toLatin1().data());
206
208 if (!inStream) {
209 LOG4CPP_ERROR_S ((*mainCat)) << "Jpeg2000::load encountered error opening stream";
210 return false;
211 }
212
213 // Create decoder
214 opj_codec_t *inCodec = decode (parameters.decod_format);
215 if (!inCodec) {
216 LOG4CPP_ERROR_S ((*mainCat)) << "Jpeg2000::load encountered error creating decoding stream";
218 return false;
219 }
220
221 // Callbacks for local handling of errors
225
227 &parameters)) {
228 LOG4CPP_ERROR_S ((*mainCat)) << "Jpeg2000::load encountered error decoding stream";
231 return false;
232 }
233
234 // Read header and, if necessary, the JP2 boxes
235 opj_image_t *image;
237 inCodec,
238 &image)) {
239 LOG4CPP_ERROR_S ((*mainCat)) << "Jpeg2000::load encountered error reading header";
242 opj_image_destroy (image);
243 return false;
244 }
245
246 // Get the decoded image
247 if (!(opj_decode (inCodec,
248 inStream,
249 image) &&
251 inStream))) {
252 LOG4CPP_ERROR_S ((*mainCat)) << "Jpeg2000::load failed to decode image";
255 opj_image_destroy (image);
256 return false;
257 }
258
259 // Close the byte stream
261
262 applyImageTweaks (image);
263
264 // Transform into ppm image in memory
265 bool success = true;
267 buffer.open (QBuffer::WriteOnly);
268 if (imagetopnm (image,
269 buffer)) {
270 LOG4CPP_ERROR_S ((*mainCat)) << "Jpeg2000::load failed to generate new image";
271 success = false;
272
273 } else {
274
275 // Intermediate file for debugging
276// QFile file ("jpeg2000.ppm");
277// file.open (QIODevice::WriteOnly);
278// file.write (buffer.data());
279// file.close ();
280
281 // Create output
282 imageResult.loadFromData(buffer.data());
283
284 }
285
286 // Deallocate
287 if (inCodec) {
289 }
290 opj_image_destroy (image);
291
292 return success;
293}
294
295QStringList Jpeg2000::supportedFileExtensions () const
296{
298
299 // Entries from openjpeg source code, and may not be correct. Order is unimportant since they are sorted later
300 extensions << "j2k" << "jp2" << "jpc" << "jpt";
301
302 return extensions;
303}
304
306{
307 QStringList extensions = supportedFileExtensions();
309
310 QStringList::iterator itr;
311 for (itr = extensions.begin(); itr != extensions.end(); itr++) {
313 QString wildcard = QString ("*.%1").arg (extension);
315 }
316
317 return wildcards;
318}
const int INNER_RADIUS_MIN
void warningCallback(const char *msg, void *)
void infoCallback(const char *msg, void *)
void errorCallback(const char *msg, void *)
void color_sycc_to_rgb(opj_image_t *img)
void color_apply_icc_profile(opj_image_t *image)
int imagetopnm(opj_image_t *image, QBuffer &buffer)
#define RAWL_DFMT
#define J2K_CFMT
#define PGX_DFMT
#define RAW_DFMT
#define TIF_DFMT
#define PNG_DFMT
#define TGA_DFMT
#define PXM_DFMT
#define JP2_CFMT
#define JPT_CFMT
#define BMP_DFMT
#define JP2_RFC3745_MAGIC
Definition Jpeg2000.cpp:17
#define J2K_CODESTREAM_MAGIC
Definition Jpeg2000.cpp:19
#define JP2_MAGIC
Definition Jpeg2000.cpp:18
log4cpp::Category * mainCat
Definition Logger.cpp:14
QStringList supportedImageWildcards() const
List the supported jpeg2000 file extensions, for filtering import files.
Definition Jpeg2000.cpp:305
bool load(const QString &filename, QImage &image) const
Load image from jpeg2000 file.
Definition Jpeg2000.cpp:192
Jpeg2000()
Single constructor.
Definition Jpeg2000.cpp:21
#define LOG4CPP_INFO_S(logger)
Definition convenience.h:18
#define LOG4CPP_ERROR_S(logger)
Definition convenience.h:12