1 /* code adapted from mtpaint - GPLv3 */
2
3 #ifdef HAVE_OPENJPEG
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <errno.h>
9 #include <sys/stat.h>
10 #include <openjpeg.h>
11
12 #include "image.h"
13 #include "rwTable.h"
14
15
16
17 /* *** PREFACE ***
18 * OpenJPEG 1.x is wasteful in the extreme, with memory overhead of about
19 * 7 times the unpacked image size. So it can fail to handle even such
20 * resolutions that fit into available memory with lots of room to spare.
21 * Still, JasPer is an even worse memory hog, if a somewhat faster one.
22 * Another thing - Linux builds of OpenJPEG cannot properly encode an opacity
23 * channel (fixed in SVN on 06.11.09, revision 541)
24 * And JP2 images with 4 channels, produced by OpenJPEG, cause JasPer
25 * to die horribly - WJ */
26
27 extern void * xmalloc(size_t n);
28 extern void set_xlate(unsigned char *xlat, int bpp);
29
stupid_callback(const char * msg,void * client_data)30 static void stupid_callback(const char *msg, void *client_data)
31 {
32 }
33
34 int
TestJP2K(char * file)35 TestJP2K(char *file)
36 {
37 unsigned char buf[8];
38 FILE *fd = fopen(file, "r");
39 int ret = 0;
40
41 if (fd == NULL)
42 return 0;
43
44 if (6 == fread(buf, sizeof(char), 6, fd)) {
45 if (buf[0] == 0xFF && buf[1] == 0x4F)
46 ret = 1;
47 if (buf[0] == 0x00 && buf[1] == 0x00 &&
48 buf[2] == 0x00 && buf[3] == 0x0c &&
49 buf[4] == 0x6A && buf[5] == 0x50)
50 ret = 1;
51 }
52 fclose(fd);
53
54 return ret;
55 }
56
57 Image *
ReadJP2K(char * file_name)58 ReadJP2K(char *file_name)
59 {
60 opj_dparameters_t par;
61 opj_dinfo_t *dinfo;
62 opj_cio_t *cio = NULL;
63 opj_image_t *image = NULL;
64 opj_image_comp_t *comp;
65 opj_event_mgr_t useless_events; // !!! Silently made mandatory in v1.2
66 unsigned char xtb[256], *dest, *buf = NULL;
67 FILE *fp;
68 Image *outImage;
69 int i, j, k, l, w, h, w0, nc, step, delta, shift, bpp;
70 int *src, codec = CODEC_JP2;
71
72 if ((fp = fopen(file_name, "rb")) == NULL) return (-1);
73
74 /* Read in the entire file */
75 fseek(fp, 0, SEEK_END);
76 l = ftell(fp);
77 fseek(fp, 0, SEEK_SET);
78 buf = malloc(l);
79 if (!buf) goto ffail;
80 i = fread(buf, 1, l, fp);
81 if (i < l) goto ffail;
82 fclose(fp);
83 if ((buf[0] == 0xFF) && (buf[1] == 0x4F)) codec = CODEC_J2K;
84
85 /* Decompress it */
86 dinfo = opj_create_decompress(codec);
87 if (!dinfo) goto lfail;
88 memset(&useless_events, 0, sizeof(useless_events));
89 useless_events.error_handler = useless_events.warning_handler =
90 useless_events.info_handler = stupid_callback;
91 opj_set_event_mgr((opj_common_ptr)dinfo, &useless_events, stderr);
92 opj_set_default_decoder_parameters(&par);
93 opj_setup_decoder(dinfo, &par);
94 cio = opj_cio_open((opj_common_ptr)dinfo, buf, l);
95 if (!cio) goto lfail;
96 image = opj_decode(dinfo, cio);
97 opj_cio_close(cio);
98 opj_destroy_decompress(dinfo);
99 free(buf);
100 if (!image) goto ifail;
101
102 /* Analyze what we got */
103 nc = image->numcomps;
104 comp = image->comps;
105 if (nc < 3)
106 bpp = 1;
107 else
108 bpp = 3;
109 /* printf("bpp = %d comps=%d\n", image->numcomps, comp); */
110 w = (comp->w + (1 << comp->factor) - 1) >> comp->factor;
111 h = (comp->h + (1 << comp->factor) - 1) >> comp->factor;
112
113 for (i = 1; i < nc; i++) /* Check if all components are the same size */
114 {
115 comp++;
116 if ((w != (comp->w + (1 << comp->factor) - 1) >> comp->factor) ||
117 (h != (comp->h + (1 << comp->factor) - 1) >> comp->factor))
118 goto ifail;
119 }
120
121 if (bpp == 1)
122 outImage = ImageNewGrey(w, h);
123 else
124 outImage = ImageNew(w, h);
125 if (!outImage) goto ifail;
126
127 /* Unpack data */
128 for (i = 0, comp = image->comps; i < nc; i++ , comp++)
129 {
130 if (i < bpp) /* Image */
131 {
132 dest = outImage->data + i;
133 step = bpp;
134 }
135 else /* Alpha */
136 {
137 if (!outImage->alpha)
138 outImage->alpha = xmalloc(w*h);
139 dest = outImage->alpha;
140 if (!dest) break; /* No alpha allocated */
141 step = 1;
142 }
143 w0 = comp->w;
144 delta = comp->sgnd ? 1 << (comp->prec - 1) : 0;
145 shift = comp->prec > 8 ? comp->prec - 8 : 0;
146 set_xlate(xtb, comp->prec - shift);
147 for (j = 0; j < h; j++)
148 {
149 src = comp->data + j * w0;
150 for (k = 0; k < w; k++)
151 {
152 *dest = xtb[(src[k] + delta) >> shift];
153 dest += step;
154 }
155 }
156 }
157 opj_image_destroy(image);
158 return outImage;
159
160 ifail: opj_image_destroy(image);
161 return NULL;
162 lfail: opj_destroy_decompress(dinfo);
163 free(buf);
164 return NULL;
165 ffail: free(buf);
166 fclose(fp);
167 return NULL;
168 }
169
170 int
WriteJP2K(char * file_name,Image * outImage)171 WriteJP2K(char *file_name, Image * outImage)
172 {
173 opj_cparameters_t par;
174 opj_cinfo_t *cinfo;
175 opj_image_cmptparm_t channels[4];
176 opj_cio_t *cio = NULL;
177 opj_image_t *image;
178 opj_event_mgr_t useless_events; // !!! Silently made mandatory in v1.2
179 unsigned char *src;
180 FILE *fp;
181 int i, j, k, nc, step;
182 int *dest, w, h, res = 1;
183 int jp2k_mode, jp2k_rate;
184
185 if ((fp = fopen(file_name, "wb")) == NULL) return 1;
186
187 /* Create intermediate structure */
188 nc = outImage->alpha ? 4 : 3;
189 w = outImage->width;
190 h = outImage->height;
191 jp2k_mode = 1;
192 jp2k_rate = 8;
193
194 memset(channels, 0, sizeof(channels));
195 for (i = 0; i < nc; i++)
196 {
197 channels[i].prec = channels[i].bpp = 8;
198 channels[i].dx = channels[i].dy = 1;
199 channels[i].w = w;
200 channels[i].h = h;
201 }
202 image = opj_image_create(nc, channels, CLRSPC_SRGB);
203 if (!image) goto ffail;
204 image->x0 = image->y0 = 0;
205 image->x1 = w; image->y1 = h;
206
207
208 /* Fill it */
209 k = w * h;
210 for (i = 0; i < nc; i++)
211 {
212 if (i < 3)
213 {
214 src = outImage->data + i;
215 step = 3;
216 }
217 else
218 {
219 src = outImage->alpha;
220 step = 1;
221 }
222 dest = image->comps[i].data;
223 for (j = 0; j < k; j++ , src += step) dest[j] = *src;
224 }
225
226 /* Compress it */
227 cinfo = opj_create_compress((jp2k_mode)? CODEC_JP2 : CODEC_J2K);
228 if (!cinfo) goto fail;
229 memset(&useless_events, 0, sizeof(useless_events));
230 useless_events.error_handler = useless_events.warning_handler =
231 useless_events.info_handler = stupid_callback;
232 opj_set_event_mgr((opj_common_ptr)cinfo, &useless_events, stderr);
233 opj_set_default_encoder_parameters(&par);
234 par.tcp_numlayers = 1;
235 par.tcp_rates[0] = jp2k_rate;
236 par.cp_disto_alloc = 1;
237 opj_setup_encoder(cinfo, &par, image);
238 cio = opj_cio_open((opj_common_ptr)cinfo, NULL, 0);
239 if (!cio) goto fail;
240 if (!opj_encode(cinfo, cio, image, NULL)) goto fail;
241
242 /* Write it */
243 k = cio_tell(cio);
244 if (fwrite(cio->buffer, 1, k, fp) == k) res = 0;
245
246 fail: if (cio) opj_cio_close(cio);
247 opj_destroy_compress(cinfo);
248 opj_image_destroy(image);
249 ffail: fclose(fp);
250 return (res);
251 }
252 #endif
253
254 #ifdef HAVE_JASPER
255
256 #include <stdio.h>
257 #include <stdlib.h>
258 #include <errno.h>
259 #include <sys/stat.h>
260 #include <jasper.h>
261
262 #include "image.h"
263 #include "rwTable.h"
264
265 /* *** PREFACE ***
266 * JasPer is QUITE a memory waster, with peak memory usage nearly TEN times the
267 * unpacked image size. But what is worse, its API is 99% undocumented.
268 * And to add insult to injury, it reacts to some invalid JP2 files (4-channel
269 * ones written by OpenJPEG) by abort()ing, instead of returning error - WJ */
270
271 static int jasper_init;
272
273 /* Build bitdepth translation table */
set_xlate(unsigned char * xlat,int bpp)274 void set_xlate(unsigned char *xlat, int bpp)
275 {
276 int i, j, m, n = (1 << bpp) - 1;
277
278 for (i = 0 , j = n , m = n + n; i <= n; i++ , j += 255 * 2)
279 xlat[i] = j / m;
280 }
281
282 int
TestJP2K(char * file)283 TestJP2K(char *file)
284 {
285 unsigned char buf[8];
286 FILE *fd = fopen(file, "r");
287 int ret = 0;
288
289 if (fd == NULL)
290 return 0;
291
292 if (6 == fread(buf, sizeof(char), 6, fd)) {
293 if (buf[0] == 0xFF && buf[1] == 0x4F)
294 ret = 1;
295 if (buf[0] == 0x00 && buf[1] == 0x00 &&
296 buf[2] == 0x00 && buf[3] == 0x0c &&
297 buf[4] == 0x6A && buf[5] == 0x50)
298 ret = 1;
299 }
300 fclose(fd);
301
302 return ret;
303 }
304
305 Image *
ReadJP2K(char * file_name)306 ReadJP2K(char *file_name)
307 {
308 jas_image_t *img;
309 jas_stream_t *inp;
310 jas_matrix_t *mx;
311 jas_seqent_t *src;
312 Image * outImage;
313 char *fmt;
314 unsigned char xtb[256], *dest;
315 int nc, cspace, mode, slots[4];
316 int bits, shift, delta, chan, step;
317 int i, j, k, n, w, h, bpp;
318 int jp2k_mode, jp2k_rate;
319
320 /* Init the dumb library */
321 if (!jasper_init) jas_init();
322 jasper_init = 1;
323 jp2k_mode = 1;
324 jp2k_rate = 8;
325
326 /* Open the file */
327 inp = jas_stream_fopen(file_name, "rb");
328 if (!inp) return NULL;
329 /* Validate format */
330 fmt = jas_image_fmttostr(jas_image_getfmt(inp));
331 if (!fmt || strcmp(fmt, (jp2k_mode)? "jp2" : "jpc"))
332 goto ffail;
333
334 /* Decode the file into a halfbaked pile of bytes */
335 img = jas_image_decode(inp, -1, NULL);
336 jas_stream_close(inp);
337 if (!img) goto dfail;
338 /* Analyze the pile's contents */
339 nc = jas_image_numcmpts(img);
340 mode = jas_clrspc_fam(cspace = jas_image_clrspc(img));
341 if (mode == JAS_CLRSPC_FAM_GRAY) bpp = 1;
342 else if (mode == JAS_CLRSPC_FAM_RGB) bpp = 3;
343 else goto ifail;
344 if (bpp == 3)
345 {
346 slots[0] = jas_image_getcmptbytype(img,
347 JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_R));
348 slots[1] = jas_image_getcmptbytype(img,
349 JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_G));
350 slots[2] = jas_image_getcmptbytype(img,
351 JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_B));
352 if ((slots[1] < 0) | (slots[2] < 0)) goto ifail;
353 }
354 else
355 {
356 slots[0] = jas_image_getcmptbytype(img,
357 JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_GRAY_Y));
358 }
359 if (slots[0] < 0) goto ifail;
360 if (nc > bpp)
361 {
362 slots[bpp] = jas_image_getcmptbytype(img, JAS_IMAGE_CT_OPACITY);
363 /* !!! JasPer has a bug - it doesn't write out component definitions if color
364 * channels are in natural order, thus losing the types of any extra components.
365 * (See where variable "needcdef" in src/libjasper/jp2/jp2_enc.c gets unset.)
366 * Then on reading, type will be replaced by component's ordinal number - WJ */
367 if (slots[bpp] < 0) slots[bpp] = jas_image_getcmptbytype(img, bpp);
368 /* Use an unlabeled extra component for alpha if no labeled one */
369 if (slots[bpp] < 0)
370 slots[bpp] = jas_image_getcmptbytype(img, JAS_IMAGE_CT_UNKNOWN);
371 nc = bpp + (slots[bpp] >= 0); // Ignore extra channels if no alpha
372 }
373 w = jas_image_cmptwidth(img, slots[0]);
374 h = jas_image_cmptheight(img, slots[0]);
375 for (i = 1; i < nc; i++) /* Check if all components are the same size */
376 {
377 if ((jas_image_cmptwidth(img, slots[i]) != w) ||
378 (jas_image_cmptheight(img, slots[i]) != h)) goto ifail;
379 }
380
381 /* Allocate "matrix" */
382 mx = jas_matrix_create(1, w);
383 if (!mx) goto ifail;
384 /* Allocate image */
385 if (bpp == 1)
386 outImage = ImageNewGrey(w, h);
387 else
388 outImage = ImageNew(w, h);
389 if (!outImage) goto mfail;
390
391 if (nc > bpp) outImage->alpha = xmalloc(w*h);
392 #if U_LCMS
393 /* JasPer implements CMS internally, but without lcms, it makes no sense
394 * to provide all the interface stuff for this one rare format - WJ */
395 while ((bpp == 3) && (cspace != JAS_CLRSPC_SRGB))
396 {
397 jas_cmprof_t *prof;
398 jas_image_t *timg;
399
400 prof = jas_cmprof_createfromclrspc(JAS_CLRSPC_SRGB);
401 if (!prof) break;
402 timg = jas_image_chclrspc(img, prof, JAS_CMXFORM_INTENT_PER);
403 jas_cmprof_destroy(prof);
404 if (!timg) break;
405 jas_image_destroy(img);
406 img = timg;
407 break;
408 }
409 #endif
410
411 /* Unravel the ugly thing into proper format */
412 for (i = n = 0; i < nc; i++)
413 {
414 if (i < bpp) /* Image */
415 {
416 dest = outImage->data + i;
417 step = bpp;
418 }
419 else /* Alpha */
420 {
421 dest = outImage->alpha;
422 step = 1;
423 }
424 chan = slots[i];
425 bits = jas_image_cmptprec(img, chan);
426 delta = jas_image_cmptsgnd(img, chan) ? 1 << (bits - 1) : 0;
427 shift = bits > 8 ? bits - 8 : 0;
428 set_xlate(xtb, bits - shift);
429 for (j = 0; j < h; j++ , n++)
430 {
431 jas_image_readcmpt(img, chan, 0, j, w, 1, mx);
432 src = jas_matrix_getref(mx, 0, 0);
433 for (k = 0; k < w; k++)
434 {
435 *dest = xtb[(unsigned)(src[k] + delta) >> shift];
436 dest += step;
437 }
438 }
439 }
440 jas_image_destroy(img);
441 return outImage;
442
443 mfail: jas_matrix_destroy(mx);
444 ifail: jas_image_destroy(img);
445 dfail: return NULL;
446 ffail: jas_stream_close(inp);
447 return NULL;
448 }
449
450 int
WriteJP2K(char * file_name,Image * outImage)451 WriteJP2K(char *file_name, Image * outImage)
452 {
453 static const jas_image_cmpttype_t chans[4] = {
454 JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_R),
455 JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_G),
456 JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_B),
457 JAS_IMAGE_CT_OPACITY };
458 jas_image_cmptparm_t cp[4];
459 jas_image_t *img;
460 jas_stream_t *outp;
461 jas_matrix_t *mx;
462 jas_seqent_t *dest;
463 char buf[256], *opts = NULL;
464 unsigned char *src;
465 int w , h, res = 1;
466 int i, j, k, n, nc, step, bpp = 3;
467 int jp2k_mode, jp2k_rate;
468
469 /* Init the dumb library */
470 if (!jasper_init) jas_init();
471 jasper_init = 1;
472 w = outImage->width;
473 h = outImage->height;
474 jp2k_mode = 1;
475 jp2k_rate = 8;
476
477 /* Open the file */
478 outp = jas_stream_fopen(file_name, "wb");
479 if (!outp) return 1;
480 /* Setup component parameters */
481 memset(cp, 0, sizeof(cp)); // Zero out all that needs zeroing
482 cp[0].hstep = cp[0].vstep = 1;
483 cp[0].width = w; cp[0].height = h;
484 cp[0].prec = 8;
485 cp[3] = cp[2] = cp[1] = cp[0];
486 /* Create image structure */
487 nc = (outImage->alpha)? 4 : 3;
488 img = jas_image_create(nc, cp, JAS_CLRSPC_SRGB);
489 if (!img) goto fail;
490 /* Allocate "matrix" */
491 mx = jas_matrix_create(1, w);
492 if (!mx) goto fail2;
493
494 /* Fill image structure */
495 for (i = n = 0; i < nc; i++)
496 {
497 /* !!! The only workaround for JasPer losing extra components' types on
498 * write is to reorder the RGB components - but then, dumb readers, such
499 * as ones in Mozilla and GTK+, would read them in wrong order - WJ */
500 jas_image_setcmpttype(img, i, chans[i]);
501 if (i < 3) /* Image */
502 {
503 src = outImage->data + i;
504 step = bpp;
505 }
506 else /* Alpha */
507 {
508 src = outImage->alpha;
509 step = 1;
510 }
511 for (j = 0; j < h; j++ , n++)
512 {
513 dest = jas_matrix_getref(mx, 0, 0);
514 for (k = 0; k < w; k++)
515 {
516 dest[k] = *src;
517 src += step;
518 }
519 jas_image_writecmpt(img, i, 0, j, w, 1, mx);
520 }
521 }
522
523 /* Compress it */
524 if (jp2k_rate) // Lossless if NO "rate" option passed
525 sprintf(opts = buf, "rate=%g", 1.0 / jp2k_rate);
526 if (!jas_image_encode(img, outp, jas_image_strtofmt(
527 jp2k_mode ? "jp2" : "jpc"), opts)) res = 0;
528 jas_stream_flush(outp);
529
530 fail3: jas_matrix_destroy(mx);
531 fail2: jas_image_destroy(img);
532 fail: jas_stream_close(outp);
533 return (res);
534 }
535 #endif
536
537