1/*
2 * Copyright (C) 2019 Igalia S.L.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "JPEG2000ImageDecoder.h"
28
29#if USE(OPENJPEG)
30
31#include <openjpeg.h>
32
33namespace WebCore {
34
35// SYCC to RGB conversion code from libopenjpeg (BSD), adapted to WebKit coding style.
36// --------------------------------------------------------
37// Matrix for sYCC, Amendment 1 to IEC 61966-2-1
38//
39// Y : 0.299 0.587 0.114 :R
40// Cb: -0.1687 -0.3312 0.5 :G
41// Cr: 0.5 -0.4187 -0.0812 :B
42//
43// Inverse:
44//
45// R: 1 -3.68213e-05 1.40199 :Y
46// G: 1.00003 -0.344125 -0.714128 :Cb - 2^(prec - 1)
47// B: 0.999823 1.77204 -8.04142e-06 :Cr - 2^(prec - 1)
48//
49// -----------------------------------------------------------*/
50static void syccToRGB(int offset, int upb, int y, int cb, int cr, int* r, int* g, int* b)
51{
52 cb -= offset;
53 cr -= offset;
54
55 *r = static_cast<int>(clampTo<float>(y - 0.0000368 * cb + 1.40199 * cr + 0.5, 0, upb));
56 *g = static_cast<int>(clampTo<float>(1.0003 * y - 0.344125 * cb - 0.7141128 * cr + 0.5, 0, upb));
57 *b = static_cast<int>(clampTo<float>(0.999823 * y + 1.77204 * cb - 0.000008 * cr + 0.5, 0, upb));
58}
59
60static void sycc444ToRGB(opj_image_t* img)
61{
62 Checked<int> upb = static_cast<int>(img->comps[0].prec);
63 int offset = 1 << (upb.unsafeGet() - 1);
64 upb = (1 << upb.unsafeGet()) - 1;
65
66 Checked<size_t> maxw = static_cast<size_t>(img->comps[0].w);
67 Checked<size_t> maxh = static_cast<size_t>(img->comps[0].h);
68 size_t max = (maxw * maxh).unsafeGet();
69
70 const int* y = img->comps[0].data;
71 const int* cb = img->comps[1].data;
72 const int* cr = img->comps[2].data;
73
74 auto* d0 = static_cast<int*>(opj_image_data_alloc(sizeof(int) * max));
75 auto* d1 = static_cast<int*>(opj_image_data_alloc(sizeof(int) * max));
76 auto* d2 = static_cast<int*>(opj_image_data_alloc(sizeof(int) * max));
77 auto* r = d0;
78 auto* g = d1;
79 auto* b = d2;
80
81 if (!r || !g || !b) {
82 opj_image_data_free(r);
83 opj_image_data_free(g);
84 opj_image_data_free(b);
85 return;
86 }
87
88 for (size_t i = 0; i < max; ++i) {
89 syccToRGB(offset, upb.unsafeGet(), *y, *cb, *cr, r, g, b);
90 ++y;
91 ++cb;
92 ++cr;
93 ++r;
94 ++g;
95 ++b;
96 }
97
98 opj_image_data_free(img->comps[0].data);
99 img->comps[0].data = d0;
100 opj_image_data_free(img->comps[1].data);
101 img->comps[1].data = d1;
102 opj_image_data_free(img->comps[2].data);
103 img->comps[2].data = d2;
104 img->color_space = OPJ_CLRSPC_SRGB;
105}
106
107static void sycc422ToRGB(opj_image_t* img)
108{
109 Checked<int> upb = static_cast<int>(img->comps[0].prec);
110 int offset = 1 << (upb.unsafeGet() - 1);
111 upb = (1 << upb.unsafeGet()) - 1;
112
113 Checked<size_t> maxw = static_cast<size_t>(img->comps[0].w);
114 Checked<size_t> maxh = static_cast<size_t>(img->comps[0].h);
115 size_t max = (maxw * maxh).unsafeGet();
116
117 const int* y = img->comps[0].data;
118 const int* cb = img->comps[1].data;
119 const int* cr = img->comps[2].data;
120
121 auto* d0 = static_cast<int*>(opj_image_data_alloc(sizeof(int) * max));
122 auto* d1 = static_cast<int*>(opj_image_data_alloc(sizeof(int) * max));
123 auto* d2 = static_cast<int*>(opj_image_data_alloc(sizeof(int) * max));
124 auto* r = d0;
125 auto* g = d1;
126 auto* b = d2;
127
128 if (!r || !g || !b) {
129 opj_image_data_free(r);
130 opj_image_data_free(g);
131 opj_image_data_free(b);
132 return;
133 }
134
135 // if img->x0 is odd, then first column shall use Cb/Cr = 0.
136 size_t offx = img->x0 & 1U;
137 size_t loopmaxw = maxw.unsafeGet() - offx;
138
139 for (size_t i = 0; i < maxh.unsafeGet(); ++i) {
140 size_t j;
141
142 if (offx > 0) {
143 syccToRGB(offset, upb.unsafeGet(), *y, 0, 0, r, g, b);
144 ++y;
145 ++r;
146 ++g;
147 ++b;
148 }
149
150 for (j = 0; j < (loopmaxw & ~static_cast<size_t>(1U)); j += 2U) {
151 syccToRGB(offset, upb.unsafeGet(), *y, *cb, *cr, r, g, b);
152 ++y;
153 ++r;
154 ++g;
155 ++b;
156 syccToRGB(offset, upb.unsafeGet(), *y, *cb, *cr, r, g, b);
157 ++y;
158 ++r;
159 ++g;
160 ++b;
161 ++cb;
162 ++cr;
163 }
164 if (j < loopmaxw) {
165 syccToRGB(offset, upb.unsafeGet(), *y, *cb, *cr, r, g, b);
166 ++y;
167 ++r;
168 ++g;
169 ++b;
170 ++cb;
171 ++cr;
172 }
173 }
174
175 opj_image_data_free(img->comps[0].data);
176 img->comps[0].data = d0;
177 opj_image_data_free(img->comps[1].data);
178 img->comps[1].data = d1;
179 opj_image_data_free(img->comps[2].data);
180 img->comps[2].data = d2;
181
182 img->comps[1].w = img->comps[2].w = img->comps[0].w;
183 img->comps[1].h = img->comps[2].h = img->comps[0].h;
184 img->comps[1].dx = img->comps[2].dx = img->comps[0].dx;
185 img->comps[1].dy = img->comps[2].dy = img->comps[0].dy;
186 img->color_space = OPJ_CLRSPC_SRGB;
187}
188
189static void sycc420ToRGB(opj_image_t* img)
190{
191 Checked<int> upb = static_cast<int>(img->comps[0].prec);
192 int offset = 1 << (upb.unsafeGet() - 1);
193 upb = (1 << upb.unsafeGet()) - 1;
194
195 Checked<size_t> maxw = static_cast<size_t>(img->comps[0].w);
196 Checked<size_t> maxh = static_cast<size_t>(img->comps[0].h);
197 size_t max = (maxw * maxh).unsafeGet();
198
199 const int* y = img->comps[0].data;
200 const int* cb = img->comps[1].data;
201 const int* cr = img->comps[2].data;
202
203 auto* d0 = static_cast<int*>(opj_image_data_alloc(sizeof(int) * max));
204 auto* d1 = static_cast<int*>(opj_image_data_alloc(sizeof(int) * max));
205 auto* d2 = static_cast<int*>(opj_image_data_alloc(sizeof(int) * max));
206 auto* r = d0;
207 auto* g = d1;
208 auto* b = d2;
209
210 if (!r || !g || !b) {
211 opj_image_data_free(r);
212 opj_image_data_free(g);
213 opj_image_data_free(b);
214 return;
215 }
216
217 // if img->x0 is odd, then first column shall use Cb/Cr = 0.
218 size_t offx = img->x0 & 1U;
219 size_t loopmaxw = maxw.unsafeGet() - offx;
220 // if img->y0 is odd, then first line shall use Cb/Cr = 0.
221 size_t offy = img->y0 & 1U;
222 size_t loopmaxh = maxh.unsafeGet() - offy;
223
224 if (offy > 0) {
225 size_t j;
226 for (j = 0; j < maxw.unsafeGet(); ++j) {
227 syccToRGB(offset, upb.unsafeGet(), *y, 0, 0, r, g, b);
228 ++y;
229 ++r;
230 ++g;
231 ++b;
232 }
233 }
234
235 size_t i;
236 for (i = 0; i < (loopmaxh & ~static_cast<size_t>(1U)); i += 2U) {
237 const int* ny = y + maxw.unsafeGet();
238 int* nr = r + maxw.unsafeGet();
239 int* ng = g + maxw.unsafeGet();
240 int* nb = b + maxw.unsafeGet();
241
242 if (offx > 0) {
243 syccToRGB(offset, upb.unsafeGet(), *y, 0, 0, r, g, b);
244 ++y;
245 ++r;
246 ++g;
247 ++b;
248 syccToRGB(offset, upb.unsafeGet(), *ny, *cb, *cr, nr, ng, nb);
249 ++ny;
250 ++nr;
251 ++ng;
252 ++nb;
253 }
254
255 size_t j;
256 for (j = 0; j < (loopmaxw & ~static_cast<size_t>(1U)); j += 2U) {
257 syccToRGB(offset, upb.unsafeGet(), *y, *cb, *cr, r, g, b);
258 ++y;
259 ++r;
260 ++g;
261 ++b;
262 syccToRGB(offset, upb.unsafeGet(), *y, *cb, *cr, r, g, b);
263 ++y;
264 ++r;
265 ++g;
266 ++b;
267
268 syccToRGB(offset, upb.unsafeGet(), *ny, *cb, *cr, nr, ng, nb);
269 ++ny;
270 ++nr;
271 ++ng;
272 ++nb;
273 syccToRGB(offset, upb.unsafeGet(), *ny, *cb, *cr, nr, ng, nb);
274 ++ny;
275 ++nr;
276 ++ng;
277 ++nb;
278 ++cb;
279 ++cr;
280 }
281 if (j < loopmaxw) {
282 syccToRGB(offset, upb.unsafeGet(), *y, *cb, *cr, r, g, b);
283 ++y;
284 ++r;
285 ++g;
286 ++b;
287
288 syccToRGB(offset, upb.unsafeGet(), *ny, *cb, *cr, nr, ng, nb);
289 ++ny;
290 ++nr;
291 ++ng;
292 ++nb;
293 ++cb;
294 ++cr;
295 }
296 y += maxw.unsafeGet();
297 r += maxw.unsafeGet();
298 g += maxw.unsafeGet();
299 b += maxw.unsafeGet();
300 }
301 if (i < loopmaxh) {
302 size_t j;
303 for (j = 0; j < (maxw.unsafeGet() & ~static_cast<size_t>(1U)); j += 2U) {
304 syccToRGB(offset, upb.unsafeGet(), *y, *cb, *cr, r, g, b);
305
306 ++y;
307 ++r;
308 ++g;
309 ++b;
310
311 syccToRGB(offset, upb.unsafeGet(), *y, *cb, *cr, r, g, b);
312
313 ++y;
314 ++r;
315 ++g;
316 ++b;
317 ++cb;
318 ++cr;
319 }
320 if (j < maxw.unsafeGet())
321 syccToRGB(offset, upb.unsafeGet(), *y, *cb, *cr, r, g, b);
322 }
323
324 opj_image_data_free(img->comps[0].data);
325 img->comps[0].data = d0;
326 opj_image_data_free(img->comps[1].data);
327 img->comps[1].data = d1;
328 opj_image_data_free(img->comps[2].data);
329 img->comps[2].data = d2;
330
331 img->comps[1].w = img->comps[2].w = img->comps[0].w;
332 img->comps[1].h = img->comps[2].h = img->comps[0].h;
333 img->comps[1].dx = img->comps[2].dx = img->comps[0].dx;
334 img->comps[1].dy = img->comps[2].dy = img->comps[0].dy;
335 img->color_space = OPJ_CLRSPC_SRGB;
336}
337
338JPEG2000ImageDecoder::JPEG2000ImageDecoder(Format format, AlphaOption alphaOption, GammaAndColorProfileOption gammaAndColorProfileOption)
339 : ScalableImageDecoder(alphaOption, gammaAndColorProfileOption)
340 , m_format(format)
341{
342}
343
344ScalableImageDecoderFrame* JPEG2000ImageDecoder::frameBufferAtIndex(size_t index)
345{
346 if (index)
347 return nullptr;
348
349 if (m_frameBufferCache.isEmpty())
350 m_frameBufferCache.grow(1);
351
352 auto& frame = m_frameBufferCache[0];
353 if (!frame.isComplete())
354 decode(false, isAllDataReceived());
355 return &frame;
356}
357
358void JPEG2000ImageDecoder::decode(bool onlySize, bool allDataReceived)
359{
360 if (failed())
361 return;
362
363 std::unique_ptr<opj_codec_t, void(*)(opj_codec_t*)> decoder(opj_create_decompress(m_format == Format::JP2 ? OPJ_CODEC_JP2 : OPJ_CODEC_J2K), opj_destroy_codec);
364 if (!decoder) {
365 setFailed();
366 return;
367 }
368
369 opj_dparameters_t parameters;
370 opj_set_default_decoder_parameters(&parameters);
371 if (!opj_setup_decoder(decoder.get(), &parameters)) {
372 setFailed();
373 return;
374 }
375
376 std::unique_ptr<opj_stream_t, void(*)(opj_stream_t*)> stream(opj_stream_default_create(OPJ_TRUE), opj_stream_destroy);
377 if (!stream) {
378 setFailed();
379 return;
380 }
381
382 struct Reader {
383 SharedBuffer& data;
384 size_t offset;
385 } reader = { *m_data, 0 };
386
387 opj_stream_set_user_data(stream.get(), &reader, nullptr);
388 opj_stream_set_user_data_length(stream.get(), m_data->size());
389 opj_stream_set_read_function(stream.get(), [](void* buffer, OPJ_SIZE_T bytes, void* userData) -> OPJ_SIZE_T {
390 auto& reader = *static_cast<Reader*>(userData);
391 if (reader.offset == reader.data.size())
392 return -1;
393
394 OPJ_SIZE_T length = reader.offset + bytes > reader.data.size() ? reader.data.size() - reader.offset : bytes;
395 memcpy(buffer, reader.data.data(), length);
396 reader.offset += length;
397
398 return length;
399 });
400 opj_stream_set_skip_function(stream.get(), [](OPJ_OFF_T bytes, void* userData) -> OPJ_OFF_T {
401 auto& reader = *static_cast<Reader*>(userData);
402
403 OPJ_OFF_T skip = reader.offset + bytes > reader.data.size() ? reader.data.size() - reader.offset : bytes;
404 reader.offset += skip;
405
406 return skip;
407 });
408 opj_stream_set_seek_function(stream.get(), [](OPJ_OFF_T bytes, void* userData) -> OPJ_BOOL {
409 auto& reader = *static_cast<Reader*>(userData);
410
411 if (static_cast<unsigned>(bytes) > reader.data.size())
412 return OPJ_FALSE;
413
414 reader.offset = bytes;
415
416 return OPJ_TRUE;
417 });
418
419 opj_image_t* imagePtr = nullptr;
420 if (!opj_read_header(stream.get(), decoder.get(), &imagePtr)) {
421 if (allDataReceived)
422 setFailed();
423 opj_image_destroy(imagePtr);
424 return;
425 }
426
427 std::unique_ptr<opj_image_t, void(*)(opj_image_t*)> image(imagePtr, opj_image_destroy);
428 setSize({ static_cast<int>(image->x1 - image->x0), static_cast<int>(image->y1 - image->y0) });
429 if (onlySize)
430 return;
431
432 if (!opj_decode(decoder.get(), stream.get(), image.get())) {
433 if (allDataReceived)
434 setFailed();
435 return;
436 }
437
438 if (image->color_space == OPJ_CLRSPC_UNSPECIFIED) {
439 if (image->numcomps == 3 && image->comps[0].dx == image->comps[0].dy && image->comps[1].dx != 1)
440 image->color_space = OPJ_CLRSPC_SYCC;
441 else if (image->numcomps <= 2)
442 image->color_space = OPJ_CLRSPC_GRAY;
443 }
444
445 if (image->color_space == OPJ_CLRSPC_SYCC) {
446 if (image->numcomps < 3)
447 image->color_space = OPJ_CLRSPC_GRAY;
448 else if ((image->comps[0].dx == 1)
449 && (image->comps[1].dx == 2)
450 && (image->comps[2].dx == 2)
451 && (image->comps[0].dy == 1)
452 && (image->comps[1].dy == 2)
453 && (image->comps[2].dy == 2)) {
454 // Horizontal and vertical sub-sample.
455 sycc420ToRGB(image.get());
456 } else if ((image->comps[0].dx == 1)
457 && (image->comps[1].dx == 2)
458 && (image->comps[2].dx == 2)
459 && (image->comps[0].dy == 1)
460 && (image->comps[1].dy == 1)
461 && (image->comps[2].dy == 1)) {
462 // Horizontal sub-sample only.
463 sycc422ToRGB(image.get());
464 } else if ((image->comps[0].dx == 1)
465 && (image->comps[1].dx == 1)
466 && (image->comps[2].dx == 1)
467 && (image->comps[0].dy == 1)
468 && (image->comps[1].dy == 1)
469 && (image->comps[2].dy == 1)) {
470 // No sub-sample.
471 sycc444ToRGB(image.get());
472 }
473 }
474
475 if (image->color_space != OPJ_CLRSPC_SRGB || image->numcomps > 4 || image->numcomps < 3) {
476 // Unsupported format.
477 setFailed();
478 return;
479 }
480
481 auto& buffer = m_frameBufferCache[0];
482 if (!buffer.initialize(scaledSize(), m_premultiplyAlpha)) {
483 setFailed();
484 return;
485 }
486
487 buffer.setDecodingStatus(DecodingStatus::Partial);
488 buffer.setHasAlpha(false);
489
490 int adjust[4] = { 0, 0, 0, 0 };
491 for (OPJ_UINT32 component = 0; component < image->numcomps; ++component) {
492 if (!image->comps[component].data) {
493 setFailed();
494 break;
495 }
496
497 if (image->comps[component].prec > 8)
498 adjust[component] = image->comps[component].prec - 8;
499 }
500
501 bool subsampling = image->comps[0].dx != 1 || image->comps[0].dy != 1 || image->comps[1].dx != 1 || image->comps[1].dy != 1 || image->comps[2].dx != 1 || image->comps[2].dy != 1;
502 unsigned char nonTrivialAlphaMask = 0;
503 const IntRect& frameRect = buffer.backingStore()->frameRect();
504 for (int y = 0; y < frameRect.height(); ++y) {
505 for (int x = 0; x < frameRect.width(); ++x) {
506 int r, g, b, a;
507
508 int offset;
509 if (subsampling) {
510 int subX = frameRect.width() / image->comps[0].w;
511 int subY = frameRect.height() / image->comps[0].h;
512 offset = (y / subY) * image->comps[0].w + (x / subX);
513 } else
514 offset = y * frameRect.width() + x;
515
516 r = image->comps[0].data[offset];
517 r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
518 if (subsampling) {
519 int subX = frameRect.width() / image->comps[1].w;
520 int subY = frameRect.height() / image->comps[1].h;
521 offset = (y / subY) * image->comps[1].w + (x / subX);
522 }
523 g = image->comps[1].data[offset];
524 g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0);
525 if (subsampling) {
526 int subX = frameRect.width() / image->comps[2].w;
527 int subY = frameRect.height() / image->comps[2].h;
528 offset = (y / subY) * image->comps[2].w + (x / subX);
529 }
530 b = image->comps[2].data[offset];
531 b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0);
532
533 if (image->numcomps > 3) {
534 if (subsampling) {
535 int subX = frameRect.width() / image->comps[3].w;
536 int subY = frameRect.height() / image->comps[3].h;
537 offset = (y / subY) * image->comps[3].w + (x / subX);
538 }
539 a = image->comps[3].data[offset];
540 a += (image->comps[3].sgnd ? 1 << (image->comps[3].prec - 1) : 0);
541 }
542
543 int adjustedRed = (r >> adjust[0]) + ((r >> (adjust[0] - 1)) % 2);
544 int adjustedGreen = (g >> adjust[1]) + ((g >> (adjust[1] - 1)) % 2);
545 int adjustedBlue = (b >> adjust[2]) + ((b >> (adjust[2] - 1)) % 2);
546 int adjustedAlpha = image->numcomps > 3 ? (a >> adjust[3]) + ((a >> (adjust[3] - 1)) % 2) : 0xFF;
547 buffer.backingStore()->setPixel(x, y, adjustedRed, adjustedGreen, adjustedBlue, adjustedAlpha);
548 nonTrivialAlphaMask |= (255 - adjustedAlpha);
549 }
550 }
551
552 buffer.setDecodingStatus(DecodingStatus::Complete);
553 if (nonTrivialAlphaMask && !buffer.hasAlpha())
554 buffer.setHasAlpha(true);
555}
556
557} // namespace WebCore
558
559#endif // USE(OPENJPEG)
560