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