1 | #include "mupdf/fitz.h" |
2 | #include "fitz-imp.h" |
3 | |
4 | #include <assert.h> |
5 | #include <string.h> |
6 | |
7 | #if FZ_ENABLE_JPX |
8 | |
9 | typedef struct fz_jpxd_s fz_jpxd; |
10 | typedef struct stream_block_s stream_block; |
11 | |
12 | static void |
13 | jpx_ycc_to_rgb(fz_context *ctx, fz_pixmap *pix, int cbsign, int crsign) |
14 | { |
15 | int w = pix->w; |
16 | int h = pix->h; |
17 | int stride = pix->stride; |
18 | int x, y; |
19 | |
20 | for (y = 0; y < h; y++) |
21 | { |
22 | unsigned char * row = &pix->samples[stride * y]; |
23 | for (x = 0; x < w; x++) |
24 | { |
25 | int ycc[3]; |
26 | ycc[0] = row[x * 3 + 0]; |
27 | ycc[1] = row[x * 3 + 1]; |
28 | ycc[2] = row[x * 3 + 2]; |
29 | |
30 | /* consciously skip Y */ |
31 | if (cbsign) |
32 | ycc[1] -= 128; |
33 | if (crsign) |
34 | ycc[2] -= 128; |
35 | |
36 | row[x * 3 + 0] = fz_clampi(ycc[0] + 1.402f * ycc[2], 0, 255); |
37 | row[x * 3 + 1] = fz_clampi(ycc[0] - 0.34413f * ycc[1] - 0.71414f * ycc[2], 0, 255); |
38 | row[x * 3 + 2] = fz_clampi(ycc[0] + 1.772f * ycc[1], 0, 255); |
39 | } |
40 | } |
41 | } |
42 | |
43 | #ifdef HAVE_LURATECH |
44 | |
45 | #include <lwf_jp2.h> |
46 | |
47 | #define MAX_COLORS 4 |
48 | #define MAX_ALPHAS 1 |
49 | #define MAX_COMPONENTS (MAX_COLORS + MAX_ALPHAS) |
50 | |
51 | #define HAS_PALETTE(cs) ( \ |
52 | (cs) == cJP2_Colorspace_Palette_Gray || \ |
53 | (cs) == cJP2_Colorspace_Palette_RGBa || \ |
54 | (cs) == cJP2_Colorspace_Palette_RGB_YCCa || \ |
55 | (cs) == cJP2_Colorspace_Palette_CIE_LABa || \ |
56 | (cs) == cJP2_Colorspace_Palette_ICCa || \ |
57 | (cs) == cJP2_Colorspace_Palette_CMYKa) |
58 | |
59 | struct fz_jpxd_s |
60 | { |
61 | fz_pixmap *pix; |
62 | JP2_Palette_Params *palette; |
63 | JP2_Property_Value width; |
64 | JP2_Property_Value height; |
65 | fz_colorspace *cs; |
66 | int expand_indexed; |
67 | unsigned long xres; |
68 | unsigned long yres; |
69 | JP2_Property_Value hstep[MAX_COMPONENTS]; |
70 | JP2_Property_Value vstep[MAX_COMPONENTS]; |
71 | JP2_Property_Value bpss[MAX_COMPONENTS]; |
72 | JP2_Property_Value signs[MAX_COMPONENTS]; |
73 | }; |
74 | |
75 | struct stream_block_s |
76 | { |
77 | const unsigned char *data; |
78 | size_t size; |
79 | }; |
80 | |
81 | static void * JP2_Callback_Conv |
82 | jpx_alloc(long size, JP2_Callback_Param param) |
83 | { |
84 | fz_context *ctx = (fz_context *) param; |
85 | return fz_malloc(ctx, size); |
86 | } |
87 | |
88 | static JP2_Error JP2_Callback_Conv |
89 | jpx_free(void *ptr, JP2_Callback_Param param) |
90 | { |
91 | fz_context *ctx = (fz_context *) param; |
92 | fz_free(ctx, ptr); |
93 | return cJP2_Error_OK; |
94 | } |
95 | |
96 | static unsigned long JP2_Callback_Conv |
97 | jpx_read(unsigned char *pucData, |
98 | unsigned long ulPos, unsigned long ulSize, |
99 | JP2_Callback_Param param) |
100 | { |
101 | stream_block *sb = (stream_block *) param; |
102 | |
103 | if (ulPos >= sb->size) |
104 | return 0; |
105 | |
106 | ulSize = (unsigned long)fz_minz(ulSize, sb->size - ulPos); |
107 | memcpy(pucData, &sb->data[ulPos], ulSize); |
108 | return ulSize; |
109 | } |
110 | |
111 | static JP2_Error JP2_Callback_Conv |
112 | jpx_write(unsigned char * pucData, short sComponent, unsigned long ulRow, |
113 | unsigned long ulStart, unsigned long ulNum, JP2_Callback_Param param) |
114 | { |
115 | fz_jpxd *state = (fz_jpxd *) param; |
116 | JP2_Property_Value hstep, vstep; |
117 | unsigned char *row; |
118 | int w, h, n, entries, expand; |
119 | JP2_Property_Value x, y, i, bps, sign; |
120 | JP2_Property_Value k; |
121 | unsigned long **palette; |
122 | |
123 | w = state->pix->w; |
124 | h = state->pix->h; |
125 | n = state->pix->n; |
126 | |
127 | if (ulRow >= (unsigned long)h || ulStart >= (unsigned long)w || sComponent >= n) |
128 | return cJP2_Error_OK; |
129 | |
130 | ulNum = fz_mini(ulNum, w - ulStart); |
131 | hstep = state->hstep[sComponent]; |
132 | vstep = state->vstep[sComponent]; |
133 | bps = state->bpss[sComponent]; |
134 | sign = state->signs[sComponent]; |
135 | |
136 | palette = state->palette ? state->palette->ppulPalette : NULL; |
137 | entries = state->palette ? state->palette->ulEntries : 1; |
138 | expand = state->expand_indexed; |
139 | |
140 | row = state->pix->samples + |
141 | state->pix->stride * ulRow * vstep + |
142 | n * ulStart * hstep + |
143 | sComponent; |
144 | |
145 | for (y = 0; ulRow * vstep + y < (JP2_Property_Value)h && y < vstep; y++) |
146 | { |
147 | unsigned char *p = row; |
148 | |
149 | for (i = 0; i < ulNum; i++) |
150 | { |
151 | for (x = 0; (ulStart + i) * hstep + x < (JP2_Property_Value)w && x < hstep; x++) |
152 | { |
153 | if (palette) |
154 | { |
155 | unsigned char v = fz_clampi(pucData[i], 0, entries - 1); |
156 | |
157 | if (expand) |
158 | { |
159 | for (k = 0; k < n; k++) |
160 | p[k] = palette[k][v]; |
161 | } |
162 | else |
163 | *p = v; |
164 | } |
165 | else |
166 | { |
167 | if (bps > 8) |
168 | { |
169 | unsigned int v = (pucData[2 * i + 1] << 8) | pucData[2 * i + 0]; |
170 | v &= (1 << bps) - 1; |
171 | v -= sign; |
172 | *p = v >> (bps - 8); |
173 | } |
174 | else if (bps == 8) |
175 | { |
176 | unsigned int v = pucData[i]; |
177 | v &= (1 << bps) - 1; |
178 | v -= sign; |
179 | *p = v; |
180 | } |
181 | else |
182 | { |
183 | unsigned int v = pucData[i]; |
184 | v &= (1 << bps) - 1; |
185 | v -= sign; |
186 | *p = v << (8 - bps); |
187 | } |
188 | } |
189 | |
190 | p += n; |
191 | } |
192 | } |
193 | |
194 | row += state->pix->stride; |
195 | } |
196 | |
197 | return cJP2_Error_OK; |
198 | } |
199 | |
200 | static fz_pixmap * |
201 | jpx_read_image(fz_context *ctx, fz_jpxd *state, const unsigned char *data, size_t size, fz_colorspace *defcs, int onlymeta) |
202 | { |
203 | JP2_Decomp_Handle doc; |
204 | JP2_Channel_Def_Params *chans = NULL; |
205 | JP2_Error err; |
206 | int colors, alphas, prealphas; |
207 | JP2_Property_Value k; |
208 | JP2_Colorspace colorspace; |
209 | JP2_Property_Value nchans; |
210 | JP2_Property_Value widths[MAX_COMPONENTS]; |
211 | JP2_Property_Value heights[MAX_COMPONENTS]; |
212 | stream_block sb; |
213 | |
214 | memset(state, 0x00, sizeof (fz_jpxd)); |
215 | |
216 | sb.data = data; |
217 | sb.size = size; |
218 | |
219 | fz_try(ctx) |
220 | { |
221 | err = JP2_Decompress_Start(&doc, |
222 | jpx_alloc, (JP2_Callback_Param) ctx, |
223 | jpx_free, (JP2_Callback_Param) ctx, |
224 | jpx_read, (JP2_Callback_Param) &sb); |
225 | if (err != cJP2_Error_OK) |
226 | fz_throw(ctx, FZ_ERROR_GENERIC, "cannot open image: %d" , (int) err); |
227 | |
228 | #if defined(JP2_LICENSE_NUM_1) && defined(JP2_LICENSE_NUM_2) |
229 | err = JP2_Document_SetLicense(doc, JP2_LICENSE_NUM_1, JP2_LICENSE_NUM_2); |
230 | if (err != cJP2_Error_OK) |
231 | fz_throw(ctx, FZ_ERROR_GENERIC, "cannot set license: %d" , (int) err); |
232 | #endif |
233 | |
234 | err = JP2_Decompress_GetProp(doc, cJP2_Prop_Extern_Colorspace, (unsigned long *) &colorspace, -1, -1); |
235 | if (err != cJP2_Error_OK) |
236 | fz_throw(ctx, FZ_ERROR_GENERIC, "cannot get colorspace: %d" , (int) err); |
237 | |
238 | err = JP2_Decompress_GetChannelDefs(doc, &chans, &nchans); |
239 | if (err != cJP2_Error_OK) |
240 | fz_throw(ctx, FZ_ERROR_GENERIC, "cannot get channel definitions: %d" , (int) err); |
241 | |
242 | colors = 0; |
243 | alphas = 0; |
244 | prealphas = 0; |
245 | for (k = 0; k < nchans; k++) |
246 | { |
247 | switch (chans[k].ulType) |
248 | { |
249 | case cJP2_Channel_Type_Color: colors++; break; |
250 | case cJP2_Channel_Type_Opacity: alphas++; break; |
251 | case cJP2_Channel_Type_Opacity_Pre: prealphas++; break; |
252 | } |
253 | } |
254 | |
255 | if (prealphas> 0) |
256 | alphas = prealphas; |
257 | colors = fz_clampi(colors, 0, MAX_COLORS); |
258 | alphas = fz_clampi(alphas, 0, MAX_ALPHAS); |
259 | |
260 | nchans = colors + alphas; |
261 | |
262 | if (HAS_PALETTE(colorspace)) |
263 | { |
264 | err = JP2_Decompress_GetProp(doc, cJP2_Prop_Width, &state->width, -1, 0); |
265 | if (err != cJP2_Error_OK) |
266 | fz_throw(ctx, FZ_ERROR_GENERIC, "cannot get width for palette indicies: %d" , (int) err); |
267 | err = JP2_Decompress_GetProp(doc, cJP2_Prop_Height, &state->height, -1, 0); |
268 | if (err != cJP2_Error_OK) |
269 | fz_throw(ctx, FZ_ERROR_GENERIC, "cannot get height for palette indicies: %d" , (int) err); |
270 | |
271 | for (k = 0; k < nchans; k++) |
272 | { |
273 | widths[k] = state->width; |
274 | heights[k] = state->height; |
275 | } |
276 | } |
277 | else |
278 | { |
279 | for (k = 0; k < nchans; k++) |
280 | { |
281 | err = JP2_Decompress_GetProp(doc, cJP2_Prop_Width, &widths[k], -1, k); |
282 | if (err != cJP2_Error_OK) |
283 | fz_throw(ctx, FZ_ERROR_GENERIC, "cannot get width for component %d: %d" , (int) k, (int) err); |
284 | err = JP2_Decompress_GetProp(doc, cJP2_Prop_Height, &heights[k], -1, k); |
285 | if (err != cJP2_Error_OK) |
286 | fz_throw(ctx, FZ_ERROR_GENERIC, "cannot get height for component %d: %d" , (int) k, (int) err); |
287 | |
288 | state->width = fz_maxi(state->width, widths[k]); |
289 | state->height = fz_maxi(state->height, heights[k]); |
290 | } |
291 | } |
292 | |
293 | err = JP2_Decompress_GetResolution(doc, &state->yres, &state->xres, NULL, |
294 | cJP2_Resolution_Dots_Per_Inch, cJP2_Resolution_Capture); |
295 | if (err != cJP2_Error_OK) |
296 | fz_throw(ctx, FZ_ERROR_GENERIC, "cannot get resolution: %d" , (int) err); |
297 | |
298 | if (state->xres == 0 || state->yres == 0) |
299 | state->xres = state->yres = 72; |
300 | |
301 | state->cs = NULL; |
302 | |
303 | if (defcs) |
304 | { |
305 | if (defcs->n == nchans) |
306 | state->cs = fz_keep_colorspace(ctx, defcs); |
307 | else |
308 | fz_warn(ctx, "jpx file (%lu) and dict colorspace (%d, %s) do not match" , nchans, defcs->n, defcs->name); |
309 | } |
310 | |
311 | #if FZ_ENABLE_ICC |
312 | if (!state->cs && colorspace == cJP2_Colorspace_Palette_ICCa) |
313 | { |
314 | unsigned char *iccprofile = NULL; |
315 | unsigned long size = 0; |
316 | fz_buffer *cbuf = NULL; |
317 | fz_var(cbuf); |
318 | |
319 | err = JP2_Decompress_GetICC(doc, &iccprofile, &size); |
320 | if (err != cJP2_Error_OK) |
321 | fz_throw(ctx, FZ_ERROR_GENERIC, "cannot get ICC color profile: %d" , (int) err); |
322 | |
323 | fz_try(ctx) |
324 | { |
325 | cbuf = fz_new_buffer_from_copied_data(ctx, iccprofile, size); |
326 | state->cs = fz_new_icc_colorspace(ctx, FZ_COLORSPACE_NONE, 0, NULL, cbuf); |
327 | } |
328 | fz_always(ctx) |
329 | fz_drop_buffer(ctx, cbuf); |
330 | fz_catch(ctx) |
331 | fz_warn(ctx, "ignoring embedded ICC profile in JPX" ); |
332 | |
333 | if (state->cs && state->cs->n != nchans) |
334 | { |
335 | fz_warn(ctx, "invalid number of components in ICC profile, ignoring ICC profile in JPX" ); |
336 | fz_drop_colorspace(ctx, state->cs); |
337 | state->cs = NULL; |
338 | } |
339 | } |
340 | #endif |
341 | |
342 | if (!state->cs) |
343 | { |
344 | switch (colors) |
345 | { |
346 | case 4: |
347 | state->cs = fz_keep_colorspace(ctx, fz_device_cmyk(ctx)); |
348 | break; |
349 | case 3: |
350 | if (colorspace == cJP2_Colorspace_CIE_LABa) |
351 | state->cs = fz_keep_colorspace(ctx, fz_device_lab(ctx)); |
352 | else |
353 | state->cs = fz_keep_colorspace(ctx, fz_device_rgb(ctx)); |
354 | break; |
355 | case 1: |
356 | state->cs = fz_keep_colorspace(ctx, fz_device_gray(ctx)); |
357 | break; |
358 | case 0: |
359 | if (alphas == 1) |
360 | { |
361 | /* alpha only images are rendered as grayscale */ |
362 | state->cs = fz_keep_colorspace(ctx, fz_device_gray(ctx)); |
363 | colors = 1; |
364 | alphas = 0; |
365 | break; |
366 | } |
367 | /* fallthrough */ |
368 | default: |
369 | fz_throw(ctx, FZ_ERROR_GENERIC, "unsupported number of components: %lu" , nchans); |
370 | } |
371 | } |
372 | } |
373 | fz_catch(ctx) |
374 | { |
375 | fz_drop_colorspace(ctx, state->cs); |
376 | JP2_Decompress_End(doc); |
377 | fz_rethrow(ctx); |
378 | } |
379 | |
380 | if (onlymeta) |
381 | { |
382 | JP2_Decompress_End(doc); |
383 | return NULL; |
384 | } |
385 | |
386 | fz_try(ctx) |
387 | { |
388 | state->pix = fz_new_pixmap(ctx, state->cs, state->width, state->height, NULL, alphas); |
389 | fz_clear_pixmap_with_value(ctx, state->pix, 0); |
390 | |
391 | if (HAS_PALETTE(colorspace)) |
392 | { |
393 | if (!fz_colorspace_is_indexed(ctx, state->cs)) |
394 | state->expand_indexed = 1; |
395 | |
396 | err = JP2_Decompress_GetPalette(doc, &state->palette); |
397 | if (err != cJP2_Error_OK) |
398 | fz_throw(ctx, FZ_ERROR_GENERIC, "cannot get indexed palette: %d" , (int) err); |
399 | |
400 | /* no available sample file */ |
401 | for (k = 0; k < state->palette->ulChannels; k++) |
402 | if (state->palette->pucSignedSample[k]) |
403 | fz_throw(ctx, FZ_ERROR_GENERIC, "signed palette components not yet supported" ); |
404 | } |
405 | |
406 | for (k = 0; k < nchans; k++) |
407 | { |
408 | state->hstep[k] = (state->width + (widths[k] - 1)) / widths[k]; |
409 | state->vstep[k] = (state->height + (heights[k] - 1)) / heights[k]; |
410 | |
411 | if (HAS_PALETTE(colorspace)) |
412 | { |
413 | state->bpss[k] = state->palette->pucBitsPerSample[k]; |
414 | state->signs[k] = state->palette->pucSignedSample[k]; |
415 | } |
416 | else |
417 | { |
418 | err = JP2_Decompress_GetProp(doc, cJP2_Prop_Bits_Per_Sample, &state->bpss[k], -1, k); |
419 | if (err != cJP2_Error_OK) |
420 | fz_throw(ctx, FZ_ERROR_GENERIC, "cannot get bits per sample for component %d: %d" , (int) k, (int) err); |
421 | err = JP2_Decompress_GetProp(doc, cJP2_Prop_Signed_Samples, &state->signs[k], -1, k); |
422 | if (err != cJP2_Error_OK) |
423 | fz_throw(ctx, FZ_ERROR_GENERIC, "cannot get signed for component %d: %d" , (int) k, (int) err); |
424 | } |
425 | if (state->signs[k]) |
426 | state->signs[k] = 1 << (state->bpss[k] - 1); |
427 | } |
428 | |
429 | err = JP2_Decompress_SetProp(doc, cJP2_Prop_Output_Parameter, (JP2_Property_Value) state); |
430 | if (err != cJP2_Error_OK) |
431 | fz_throw(ctx, FZ_ERROR_GENERIC, "cannot set write callback userdata: %d" , (int) err); |
432 | err = JP2_Decompress_SetProp(doc, cJP2_Prop_Output_Function, (JP2_Property_Value) jpx_write); |
433 | if (err != cJP2_Error_OK) |
434 | fz_throw(ctx, FZ_ERROR_GENERIC, "cannot set write callback: %d" , (int) err); |
435 | |
436 | err = JP2_Decompress_Image(doc); |
437 | if (err != cJP2_Error_OK) |
438 | fz_throw(ctx, FZ_ERROR_GENERIC, "cannot decode image: %d" , (int) err); |
439 | |
440 | if (colorspace == cJP2_Colorspace_RGB_YCCa) |
441 | jpx_ycc_to_rgb(ctx, state->pix, !state->signs[1], !state->signs[2]); |
442 | |
443 | if (state->pix->alpha && ! (HAS_PALETTE(colorspace) && !state->expand_indexed)) |
444 | { |
445 | if (alphas > 0 && prealphas == 0) |
446 | fz_premultiply_pixmap(ctx, state->pix); |
447 | } |
448 | } |
449 | fz_always(ctx) |
450 | { |
451 | fz_drop_colorspace(ctx, state->cs); |
452 | JP2_Decompress_End(doc); |
453 | } |
454 | fz_catch(ctx) |
455 | { |
456 | fz_drop_pixmap(ctx, state->pix); |
457 | fz_rethrow(ctx); |
458 | } |
459 | |
460 | return state->pix; |
461 | } |
462 | |
463 | fz_pixmap * |
464 | fz_load_jpx(fz_context *ctx, const unsigned char *data, size_t size, fz_colorspace *defcs) |
465 | { |
466 | fz_jpxd state = { 0 }; |
467 | |
468 | return jpx_read_image(ctx, &state, data, size, defcs, 0); |
469 | } |
470 | |
471 | void |
472 | fz_load_jpx_info(fz_context *ctx, const unsigned char *data, size_t size, int *wp, int *hp, int *xresp, int *yresp, fz_colorspace **cspacep) |
473 | { |
474 | fz_jpxd state = { 0 }; |
475 | |
476 | jpx_read_image(ctx, &state, data, size, NULL, 1); |
477 | |
478 | *cspacep = state.cs; |
479 | *wp = state.width; |
480 | *hp = state.height; |
481 | *xresp = state.xres; |
482 | *yresp = state.yres; |
483 | } |
484 | |
485 | #else /* HAVE_LURATECH */ |
486 | |
487 | #include <openjpeg.h> |
488 | |
489 | struct fz_jpxd_s |
490 | { |
491 | int width; |
492 | int height; |
493 | fz_colorspace *cs; |
494 | int xres; |
495 | int yres; |
496 | }; |
497 | |
498 | struct stream_block_s |
499 | { |
500 | const unsigned char *data; |
501 | OPJ_SIZE_T size; |
502 | OPJ_SIZE_T pos; |
503 | }; |
504 | |
505 | /* OpenJPEG does not provide a safe mechanism to intercept |
506 | * allocations. In the latest version all allocations go |
507 | * though opj_malloc etc, but no context is passed around. |
508 | * |
509 | * In order to ensure that allocations throughout mupdf |
510 | * are done consistently, we implement opj_malloc etc as |
511 | * functions that call down to fz_malloc etc. These |
512 | * require context variables, so we lock and unlock around |
513 | * calls to openjpeg. Any attempt to call through |
514 | * without setting these will be detected. |
515 | * |
516 | * It is therefore vital that any fz_lock/fz_unlock |
517 | * handlers are shared between all the fz_contexts in |
518 | * use at a time. |
519 | */ |
520 | |
521 | /* Potentially we can write different versions |
522 | * of get_context and set_context for different |
523 | * threading systems. |
524 | */ |
525 | |
526 | static fz_context *opj_secret = NULL; |
527 | |
528 | static void set_opj_context(fz_context *ctx) |
529 | { |
530 | opj_secret = ctx; |
531 | } |
532 | |
533 | static fz_context *get_opj_context(void) |
534 | { |
535 | return opj_secret; |
536 | } |
537 | |
538 | void opj_lock(fz_context *ctx) |
539 | { |
540 | fz_lock(ctx, FZ_LOCK_FREETYPE); |
541 | |
542 | set_opj_context(ctx); |
543 | } |
544 | |
545 | void opj_unlock(fz_context *ctx) |
546 | { |
547 | set_opj_context(NULL); |
548 | |
549 | fz_unlock(ctx, FZ_LOCK_FREETYPE); |
550 | } |
551 | |
552 | void *opj_malloc(size_t size) |
553 | { |
554 | fz_context *ctx = get_opj_context(); |
555 | |
556 | assert(ctx != NULL); |
557 | |
558 | return fz_malloc_no_throw(ctx, size); |
559 | } |
560 | |
561 | void *opj_calloc(size_t n, size_t size) |
562 | { |
563 | fz_context *ctx = get_opj_context(); |
564 | |
565 | assert(ctx != NULL); |
566 | |
567 | return fz_calloc_no_throw(ctx, n, size); |
568 | } |
569 | |
570 | void *opj_realloc(void *ptr, size_t size) |
571 | { |
572 | fz_context *ctx = get_opj_context(); |
573 | |
574 | assert(ctx != NULL); |
575 | |
576 | return fz_realloc_no_throw(ctx, ptr, size); |
577 | } |
578 | |
579 | void opj_free(void *ptr) |
580 | { |
581 | fz_context *ctx = get_opj_context(); |
582 | |
583 | assert(ctx != NULL); |
584 | |
585 | fz_free(ctx, ptr); |
586 | } |
587 | |
588 | static void * opj_aligned_malloc_n(size_t alignment, size_t size) |
589 | { |
590 | uint8_t *ptr; |
591 | int off; |
592 | |
593 | if (size == 0) |
594 | return NULL; |
595 | |
596 | size += alignment + sizeof(uint8_t); |
597 | ptr = opj_malloc(size); |
598 | if (ptr == NULL) |
599 | return NULL; |
600 | off = alignment-(((int)(intptr_t)ptr) & (alignment - 1)); |
601 | ptr[off-1] = off; |
602 | return ptr + off; |
603 | } |
604 | |
605 | void * opj_aligned_malloc(size_t size) |
606 | { |
607 | return opj_aligned_malloc_n(16, size); |
608 | } |
609 | |
610 | void * opj_aligned_32_malloc(size_t size) |
611 | { |
612 | return opj_aligned_malloc_n(32, size); |
613 | } |
614 | |
615 | void opj_aligned_free(void* ptr_) |
616 | { |
617 | uint8_t *ptr = (uint8_t *)ptr_; |
618 | uint8_t off; |
619 | if (ptr == NULL) |
620 | return; |
621 | |
622 | off = ptr[-1]; |
623 | opj_free((void *)(((unsigned char *)ptr) - off)); |
624 | } |
625 | |
626 | #if 0 |
627 | /* UNUSED currently, and moderately tricky, so deferred until required */ |
628 | void * opj_aligned_realloc(void *ptr, size_t size) |
629 | { |
630 | return opj_realloc(ptr, size); |
631 | } |
632 | #endif |
633 | |
634 | static void fz_opj_error_callback(const char *msg, void *client_data) |
635 | { |
636 | fz_context *ctx = (fz_context *)client_data; |
637 | char buf[200]; |
638 | int n; |
639 | fz_strlcpy(buf, msg, sizeof buf); |
640 | n = strlen(buf); |
641 | if (buf[n-1] == '\n') |
642 | buf[n-1] = 0; |
643 | fz_warn(ctx, "openjpeg error: %s" , buf); |
644 | } |
645 | |
646 | static void fz_opj_warning_callback(const char *msg, void *client_data) |
647 | { |
648 | fz_context *ctx = (fz_context *)client_data; |
649 | char buf[200]; |
650 | int n; |
651 | fz_strlcpy(buf, msg, sizeof buf); |
652 | n = strlen(buf); |
653 | if (buf[n-1] == '\n') |
654 | buf[n-1] = 0; |
655 | fz_warn(ctx, "openjpeg warning: %s" , buf); |
656 | } |
657 | |
658 | static void fz_opj_info_callback(const char *msg, void *client_data) |
659 | { |
660 | /* fz_warn("openjpeg info: %s", msg); */ |
661 | } |
662 | |
663 | static OPJ_SIZE_T fz_opj_stream_read(void * p_buffer, OPJ_SIZE_T p_nb_bytes, void * p_user_data) |
664 | { |
665 | stream_block *sb = (stream_block *)p_user_data; |
666 | OPJ_SIZE_T len; |
667 | |
668 | len = sb->size - sb->pos; |
669 | if (len == 0) |
670 | return (OPJ_SIZE_T)-1; /* End of file! */ |
671 | if (len > p_nb_bytes) |
672 | len = p_nb_bytes; |
673 | memcpy(p_buffer, sb->data + sb->pos, len); |
674 | sb->pos += len; |
675 | return len; |
676 | } |
677 | |
678 | static OPJ_OFF_T fz_opj_stream_skip(OPJ_OFF_T skip, void * p_user_data) |
679 | { |
680 | stream_block *sb = (stream_block *)p_user_data; |
681 | |
682 | if (skip > (OPJ_OFF_T)(sb->size - sb->pos)) |
683 | skip = (OPJ_OFF_T)(sb->size - sb->pos); |
684 | sb->pos += skip; |
685 | return sb->pos; |
686 | } |
687 | |
688 | static OPJ_BOOL fz_opj_stream_seek(OPJ_OFF_T seek_pos, void * p_user_data) |
689 | { |
690 | stream_block *sb = (stream_block *)p_user_data; |
691 | |
692 | if (seek_pos > (OPJ_OFF_T)sb->size) |
693 | return OPJ_FALSE; |
694 | sb->pos = seek_pos; |
695 | return OPJ_TRUE; |
696 | } |
697 | |
698 | static fz_pixmap * |
699 | jpx_read_image(fz_context *ctx, fz_jpxd *state, const unsigned char *data, size_t size, fz_colorspace *defcs, int onlymeta) |
700 | { |
701 | fz_pixmap *img = NULL; |
702 | opj_dparameters_t params; |
703 | opj_codec_t *codec; |
704 | opj_image_t *jpx; |
705 | opj_stream_t *stream; |
706 | OPJ_CODEC_FORMAT format; |
707 | int a, n, w, h; |
708 | int x, y, k; |
709 | stream_block sb; |
710 | OPJ_UINT32 i; |
711 | |
712 | fz_var(img); |
713 | |
714 | if (size < 2) |
715 | fz_throw(ctx, FZ_ERROR_GENERIC, "not enough data to determine image format" ); |
716 | |
717 | /* Check for SOC marker -- if found we have a bare J2K stream */ |
718 | if (data[0] == 0xFF && data[1] == 0x4F) |
719 | format = OPJ_CODEC_J2K; |
720 | else |
721 | format = OPJ_CODEC_JP2; |
722 | |
723 | opj_set_default_decoder_parameters(¶ms); |
724 | if (fz_colorspace_is_indexed(ctx, defcs)) |
725 | params.flags |= OPJ_DPARAMETERS_IGNORE_PCLR_CMAP_CDEF_FLAG; |
726 | |
727 | codec = opj_create_decompress(format); |
728 | opj_set_info_handler(codec, fz_opj_info_callback, ctx); |
729 | opj_set_warning_handler(codec, fz_opj_warning_callback, ctx); |
730 | opj_set_error_handler(codec, fz_opj_error_callback, ctx); |
731 | if (!opj_setup_decoder(codec, ¶ms)) |
732 | { |
733 | opj_destroy_codec(codec); |
734 | fz_throw(ctx, FZ_ERROR_GENERIC, "j2k decode failed" ); |
735 | } |
736 | |
737 | stream = opj_stream_default_create(OPJ_TRUE); |
738 | sb.data = data; |
739 | sb.pos = 0; |
740 | sb.size = size; |
741 | |
742 | opj_stream_set_read_function(stream, fz_opj_stream_read); |
743 | opj_stream_set_skip_function(stream, fz_opj_stream_skip); |
744 | opj_stream_set_seek_function(stream, fz_opj_stream_seek); |
745 | opj_stream_set_user_data(stream, &sb, NULL); |
746 | /* Set the length to avoid an assert */ |
747 | opj_stream_set_user_data_length(stream, size); |
748 | |
749 | if (!opj_read_header(stream, codec, &jpx)) |
750 | { |
751 | opj_stream_destroy(stream); |
752 | opj_destroy_codec(codec); |
753 | fz_throw(ctx, FZ_ERROR_GENERIC, "Failed to read JPX header" ); |
754 | } |
755 | |
756 | if (!opj_decode(codec, stream, jpx)) |
757 | { |
758 | opj_stream_destroy(stream); |
759 | opj_destroy_codec(codec); |
760 | opj_image_destroy(jpx); |
761 | fz_throw(ctx, FZ_ERROR_GENERIC, "Failed to decode JPX image" ); |
762 | } |
763 | |
764 | opj_stream_destroy(stream); |
765 | opj_destroy_codec(codec); |
766 | |
767 | /* jpx should never be NULL here, but check anyway */ |
768 | if (!jpx) |
769 | fz_throw(ctx, FZ_ERROR_GENERIC, "opj_decode failed" ); |
770 | |
771 | /* Count number of alpha and color channels */ |
772 | n = a = 0; |
773 | for (i = 0; i < jpx->numcomps; ++i) |
774 | { |
775 | if (jpx->comps[i].alpha) |
776 | ++a; |
777 | else |
778 | ++n; |
779 | } |
780 | |
781 | for (k = 1; k < n + a; k++) |
782 | { |
783 | if (!jpx->comps[k].data) |
784 | { |
785 | opj_image_destroy(jpx); |
786 | fz_throw(ctx, FZ_ERROR_GENERIC, "image components are missing data" ); |
787 | } |
788 | } |
789 | |
790 | state->width = w = jpx->x1 - jpx->x0; |
791 | state->height = h = jpx->y1 - jpx->y0; |
792 | state->xres = 72; /* openjpeg does not read the JPEG 2000 resc box */ |
793 | state->yres = 72; /* openjpeg does not read the JPEG 2000 resc box */ |
794 | |
795 | state->cs = NULL; |
796 | |
797 | if (defcs) |
798 | { |
799 | if (defcs->n == n) |
800 | state->cs = fz_keep_colorspace(ctx, defcs); |
801 | else |
802 | fz_warn(ctx, "jpx file and dict colorspace do not match" ); |
803 | } |
804 | |
805 | #if FZ_ENABLE_ICC |
806 | if (!state->cs && jpx->icc_profile_buf) |
807 | { |
808 | fz_buffer *cbuf = NULL; |
809 | fz_var(cbuf); |
810 | |
811 | fz_try(ctx) |
812 | { |
813 | cbuf = fz_new_buffer_from_copied_data(ctx, jpx->icc_profile_buf, jpx->icc_profile_len); |
814 | state->cs = fz_new_icc_colorspace(ctx, FZ_COLORSPACE_NONE, 0, NULL, cbuf); |
815 | } |
816 | fz_always(ctx) |
817 | fz_drop_buffer(ctx, cbuf); |
818 | fz_catch(ctx) |
819 | fz_warn(ctx, "ignoring embedded ICC profile in JPX" ); |
820 | |
821 | if (state->cs && state->cs->n != n) |
822 | { |
823 | fz_warn(ctx, "invalid number of components in ICC profile, ignoring ICC profile in JPX" ); |
824 | fz_drop_colorspace(ctx, state->cs); |
825 | state->cs = NULL; |
826 | } |
827 | } |
828 | #endif |
829 | |
830 | if (!state->cs) |
831 | { |
832 | switch (n) |
833 | { |
834 | case 1: state->cs = fz_keep_colorspace(ctx, fz_device_gray(ctx)); break; |
835 | case 3: state->cs = fz_keep_colorspace(ctx, fz_device_rgb(ctx)); break; |
836 | case 4: state->cs = fz_keep_colorspace(ctx, fz_device_cmyk(ctx)); break; |
837 | default: |
838 | { |
839 | opj_image_destroy(jpx); |
840 | fz_throw(ctx, FZ_ERROR_GENERIC, "unsupported number of components: %d" , n); |
841 | } |
842 | } |
843 | } |
844 | |
845 | if (onlymeta) |
846 | { |
847 | opj_image_destroy(jpx); |
848 | return NULL; |
849 | } |
850 | |
851 | fz_try(ctx) |
852 | { |
853 | unsigned char *samples; |
854 | int stride, comps; |
855 | |
856 | a = !!a; /* ignore any superfluous alpha channels */ |
857 | img = fz_new_pixmap(ctx, state->cs, w, h, NULL, a); |
858 | stride = fz_pixmap_stride(ctx, img); |
859 | comps = fz_pixmap_components(ctx, img); |
860 | samples = fz_pixmap_samples(ctx, img); |
861 | |
862 | fz_clear_pixmap_with_value(ctx, img, 0); |
863 | |
864 | for (k = 0; k < comps; k++) |
865 | { |
866 | opj_image_comp_t *comp = &(jpx->comps[k]); |
867 | int oy = comp->y0 * comp->dy - jpx->y0; |
868 | int ox = comp->x0 * comp->dx - jpx->x0; |
869 | |
870 | if (comp->data == NULL) |
871 | fz_throw(ctx, FZ_ERROR_GENERIC, "No data for JP2 image component %d" , k); |
872 | |
873 | for (y = 0; y < comp->h; y++) |
874 | { |
875 | for (x = 0; x < comp->w; x++) |
876 | { |
877 | OPJ_INT32 v; |
878 | int dx; |
879 | int dy; |
880 | |
881 | v = comp->data[y * comp->w + x]; |
882 | |
883 | if (comp->sgnd) |
884 | v = v + (1 << (comp->prec - 1)); |
885 | if (comp->prec > 8) |
886 | v = v >> (comp->prec - 8); |
887 | else if (comp->prec < 8) |
888 | v = v << (8 - comp->prec); |
889 | |
890 | for (dy = 0; dy < comp->dy; dy++) |
891 | { |
892 | for (dx = 0; dx < comp->dx; dx++) |
893 | { |
894 | int xx = ox + x * comp->dx + dx; |
895 | int yy = oy + y * comp->dy + dy; |
896 | |
897 | if (xx < w && yy < h) |
898 | samples[yy * stride + xx * comps + k] = v; |
899 | } |
900 | } |
901 | } |
902 | } |
903 | } |
904 | |
905 | if (jpx->color_space == OPJ_CLRSPC_SYCC && n == 3 && a == 0) |
906 | jpx_ycc_to_rgb(ctx, img, 1, 1); |
907 | if (a) |
908 | fz_premultiply_pixmap(ctx, img); |
909 | } |
910 | fz_always(ctx) |
911 | { |
912 | fz_drop_colorspace(ctx, state->cs); |
913 | opj_image_destroy(jpx); |
914 | } |
915 | fz_catch(ctx) |
916 | { |
917 | fz_drop_pixmap(ctx, img); |
918 | fz_rethrow(ctx); |
919 | } |
920 | |
921 | return img; |
922 | } |
923 | |
924 | fz_pixmap * |
925 | fz_load_jpx(fz_context *ctx, const unsigned char *data, size_t size, fz_colorspace *defcs) |
926 | { |
927 | fz_jpxd state = { 0 }; |
928 | fz_pixmap *pix = NULL; |
929 | |
930 | fz_try(ctx) |
931 | { |
932 | opj_lock(ctx); |
933 | pix = jpx_read_image(ctx, &state, data, size, defcs, 0); |
934 | } |
935 | fz_always(ctx) |
936 | opj_unlock(ctx); |
937 | fz_catch(ctx) |
938 | fz_rethrow(ctx); |
939 | |
940 | return pix; |
941 | } |
942 | |
943 | void |
944 | fz_load_jpx_info(fz_context *ctx, const unsigned char *data, size_t size, int *wp, int *hp, int *xresp, int *yresp, fz_colorspace **cspacep) |
945 | { |
946 | fz_jpxd state = { 0 }; |
947 | |
948 | fz_try(ctx) |
949 | { |
950 | opj_lock(ctx); |
951 | jpx_read_image(ctx, &state, data, size, NULL, 1); |
952 | } |
953 | fz_always(ctx) |
954 | opj_unlock(ctx); |
955 | fz_catch(ctx) |
956 | fz_rethrow(ctx); |
957 | |
958 | *cspacep = state.cs; |
959 | *wp = state.width; |
960 | *hp = state.height; |
961 | *xresp = state.xres; |
962 | *yresp = state.yres; |
963 | } |
964 | |
965 | #endif /* HAVE_LURATECH */ |
966 | |
967 | #else /* FZ_ENABLE_JPX */ |
968 | |
969 | fz_pixmap * |
970 | fz_load_jpx(fz_context *ctx, const unsigned char *data, size_t size, fz_colorspace *defcs) |
971 | { |
972 | fz_throw(ctx, FZ_ERROR_GENERIC, "JPX support disabled" ); |
973 | } |
974 | |
975 | void |
976 | fz_load_jpx_info(fz_context *ctx, const unsigned char *data, size_t size, int *wp, int *hp, int *xresp, int *yresp, fz_colorspace **cspacep) |
977 | { |
978 | fz_throw(ctx, FZ_ERROR_GENERIC, "JPX support disabled" ); |
979 | } |
980 | |
981 | #endif |
982 | |