1 // Copyright 2019 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "core/fxcodec/jpx/cjpx_decoder.h"
8
9 #include <algorithm>
10 #include <limits>
11 #include <utility>
12
13 #include "core/fxcodec/jpx/jpx_decode_utils.h"
14 #include "core/fxcrt/fx_safe_types.h"
15 #include "third_party/base/optional.h"
16 #include "third_party/base/ptr_util.h"
17 #include "third_party/base/stl_util.h"
18
19 #if !defined(USE_SYSTEM_LIBOPENJPEG2)
20 #include "third_party/libopenjpeg20/opj_malloc.h"
21 #endif
22
23 namespace fxcodec {
24
25 namespace {
26
27 // Used with std::unique_ptr to call opj_image_data_free on raw memory.
28 struct OpjImageDataDeleter {
operator ()fxcodec::__anon4185ad640111::OpjImageDataDeleter29 inline void operator()(void* ptr) const { opj_image_data_free(ptr); }
30 };
31
32 using ScopedOpjImageData = std::unique_ptr<int, OpjImageDataDeleter>;
33
34 struct OpjImageRgbData {
35 ScopedOpjImageData r;
36 ScopedOpjImageData g;
37 ScopedOpjImageData b;
38 };
39
fx_ignore_callback(const char * msg,void * client_data)40 void fx_ignore_callback(const char* msg, void* client_data) {}
41
fx_opj_stream_create_memory_stream(DecodeData * data)42 opj_stream_t* fx_opj_stream_create_memory_stream(DecodeData* data) {
43 if (!data || !data->src_data || data->src_size <= 0)
44 return nullptr;
45
46 opj_stream_t* stream = opj_stream_create(OPJ_J2K_STREAM_CHUNK_SIZE,
47 /*p_is_input=*/OPJ_TRUE);
48 if (!stream)
49 return nullptr;
50
51 opj_stream_set_user_data(stream, data, nullptr);
52 opj_stream_set_user_data_length(stream, data->src_size);
53 opj_stream_set_read_function(stream, opj_read_from_memory);
54 opj_stream_set_skip_function(stream, opj_skip_from_memory);
55 opj_stream_set_seek_function(stream, opj_seek_from_memory);
56 return stream;
57 }
58
alloc_rgb(size_t size)59 Optional<OpjImageRgbData> alloc_rgb(size_t size) {
60 OpjImageRgbData data;
61 data.r.reset(static_cast<int*>(opj_image_data_alloc(size)));
62 if (!data.r)
63 return {};
64
65 data.g.reset(static_cast<int*>(opj_image_data_alloc(size)));
66 if (!data.g)
67 return {};
68
69 data.b.reset(static_cast<int*>(opj_image_data_alloc(size)));
70 if (!data.b)
71 return {};
72
73 return data;
74 }
75
sycc_to_rgb(int offset,int upb,int y,int cb,int cr,int * out_r,int * out_g,int * out_b)76 void sycc_to_rgb(int offset,
77 int upb,
78 int y,
79 int cb,
80 int cr,
81 int* out_r,
82 int* out_g,
83 int* out_b) {
84 cb -= offset;
85 cr -= offset;
86 *out_r = pdfium::clamp(y + static_cast<int>(1.402 * cr), 0, upb);
87 *out_g = pdfium::clamp(y - static_cast<int>(0.344 * cb + 0.714 * cr), 0, upb);
88 *out_b = pdfium::clamp(y + static_cast<int>(1.772 * cb), 0, upb);
89 }
90
sycc444_to_rgb(opj_image_t * img)91 void sycc444_to_rgb(opj_image_t* img) {
92 int prec = img->comps[0].prec;
93 // If we shift 31 we're going to go negative, then things go bad.
94 if (prec > 30)
95 return;
96 int offset = 1 << (prec - 1);
97 int upb = (1 << prec) - 1;
98 OPJ_UINT32 maxw =
99 std::min({img->comps[0].w, img->comps[1].w, img->comps[2].w});
100 OPJ_UINT32 maxh =
101 std::min({img->comps[0].h, img->comps[1].h, img->comps[2].h});
102 FX_SAFE_SIZE_T max_size = maxw;
103 max_size *= maxh;
104 max_size *= sizeof(int);
105 if (!max_size.IsValid())
106 return;
107
108 const int* y = img->comps[0].data;
109 const int* cb = img->comps[1].data;
110 const int* cr = img->comps[2].data;
111 if (!y || !cb || !cr)
112 return;
113
114 Optional<OpjImageRgbData> data = alloc_rgb(max_size.ValueOrDie());
115 if (!data.has_value())
116 return;
117
118 int* r = data.value().r.get();
119 int* g = data.value().g.get();
120 int* b = data.value().b.get();
121 max_size /= sizeof(int);
122 for (size_t i = 0; i < max_size.ValueOrDie(); ++i)
123 sycc_to_rgb(offset, upb, *y++, *cb++, *cr++, r++, g++, b++);
124
125 opj_image_data_free(img->comps[0].data);
126 opj_image_data_free(img->comps[1].data);
127 opj_image_data_free(img->comps[2].data);
128 img->comps[0].data = data.value().r.release();
129 img->comps[1].data = data.value().g.release();
130 img->comps[2].data = data.value().b.release();
131 }
132
sycc420_422_size_is_valid(opj_image_t * img)133 bool sycc420_422_size_is_valid(opj_image_t* img) {
134 return img && img->comps[0].w != std::numeric_limits<OPJ_UINT32>::max() &&
135 (img->comps[0].w + 1) / 2 == img->comps[1].w &&
136 img->comps[1].w == img->comps[2].w &&
137 img->comps[1].h == img->comps[2].h;
138 }
139
sycc420_size_is_valid(opj_image_t * img)140 bool sycc420_size_is_valid(opj_image_t* img) {
141 return sycc420_422_size_is_valid(img) &&
142 img->comps[0].h != std::numeric_limits<OPJ_UINT32>::max() &&
143 (img->comps[0].h + 1) / 2 == img->comps[1].h;
144 }
145
sycc420_must_extend_cbcr(OPJ_UINT32 y,OPJ_UINT32 cbcr)146 bool sycc420_must_extend_cbcr(OPJ_UINT32 y, OPJ_UINT32 cbcr) {
147 return (y & 1) && (cbcr == y / 2);
148 }
149
sycc420_to_rgb(opj_image_t * img)150 void sycc420_to_rgb(opj_image_t* img) {
151 if (!sycc420_size_is_valid(img))
152 return;
153
154 OPJ_UINT32 prec = img->comps[0].prec;
155 if (!prec)
156 return;
157
158 OPJ_UINT32 offset = 1 << (prec - 1);
159 OPJ_UINT32 upb = (1 << prec) - 1;
160 OPJ_UINT32 yw = img->comps[0].w;
161 OPJ_UINT32 yh = img->comps[0].h;
162 OPJ_UINT32 cbw = img->comps[1].w;
163 OPJ_UINT32 cbh = img->comps[1].h;
164 OPJ_UINT32 crw = img->comps[2].w;
165 bool extw = sycc420_must_extend_cbcr(yw, cbw);
166 bool exth = sycc420_must_extend_cbcr(yh, cbh);
167 FX_SAFE_UINT32 safe_size = yw;
168 safe_size *= yh;
169 safe_size *= sizeof(int);
170 if (!safe_size.IsValid())
171 return;
172
173 const int* y = img->comps[0].data;
174 const int* cb = img->comps[1].data;
175 const int* cr = img->comps[2].data;
176 if (!y || !cb || !cr)
177 return;
178
179 Optional<OpjImageRgbData> data = alloc_rgb(safe_size.ValueOrDie());
180 if (!data.has_value())
181 return;
182
183 int* r = data.value().r.get();
184 int* g = data.value().g.get();
185 int* b = data.value().b.get();
186 const int* ny = nullptr;
187 int* nr = nullptr;
188 int* ng = nullptr;
189 int* nb = nullptr;
190 OPJ_UINT32 i = 0;
191 OPJ_UINT32 j = 0;
192 for (i = 0; i < (yh & ~(OPJ_UINT32)1); i += 2) {
193 ny = y + yw;
194 nr = r + yw;
195 ng = g + yw;
196 nb = b + yw;
197 for (j = 0; j < (yw & ~(OPJ_UINT32)1); j += 2) {
198 sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b);
199 ++y;
200 ++r;
201 ++g;
202 ++b;
203 sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b);
204 ++y;
205 ++r;
206 ++g;
207 ++b;
208 sycc_to_rgb(offset, upb, *ny, *cb, *cr, nr, ng, nb);
209 ++ny;
210 ++nr;
211 ++ng;
212 ++nb;
213 sycc_to_rgb(offset, upb, *ny, *cb, *cr, nr, ng, nb);
214 ++ny;
215 ++nr;
216 ++ng;
217 ++nb;
218 ++cb;
219 ++cr;
220 }
221 if (j < yw) {
222 if (extw) {
223 --cb;
224 --cr;
225 }
226 sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b);
227 ++y;
228 ++r;
229 ++g;
230 ++b;
231 sycc_to_rgb(offset, upb, *ny, *cb, *cr, nr, ng, nb);
232 ++ny;
233 ++nr;
234 ++ng;
235 ++nb;
236 ++cb;
237 ++cr;
238 }
239 y += yw;
240 r += yw;
241 g += yw;
242 b += yw;
243 }
244 if (i < yh) {
245 if (exth) {
246 cb -= cbw;
247 cr -= crw;
248 }
249 for (j = 0; j < (yw & ~(OPJ_UINT32)1); j += 2) {
250 sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b);
251 ++y;
252 ++r;
253 ++g;
254 ++b;
255 sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b);
256 ++y;
257 ++r;
258 ++g;
259 ++b;
260 ++cb;
261 ++cr;
262 }
263 if (j < yw) {
264 if (extw) {
265 --cb;
266 --cr;
267 }
268 sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b);
269 }
270 }
271
272 opj_image_data_free(img->comps[0].data);
273 opj_image_data_free(img->comps[1].data);
274 opj_image_data_free(img->comps[2].data);
275 img->comps[0].data = data.value().r.release();
276 img->comps[1].data = data.value().g.release();
277 img->comps[2].data = data.value().b.release();
278 img->comps[1].w = yw;
279 img->comps[1].h = yh;
280 img->comps[2].w = yw;
281 img->comps[2].h = yh;
282 img->comps[1].dx = img->comps[0].dx;
283 img->comps[2].dx = img->comps[0].dx;
284 img->comps[1].dy = img->comps[0].dy;
285 img->comps[2].dy = img->comps[0].dy;
286 }
287
sycc422_size_is_valid(opj_image_t * img)288 bool sycc422_size_is_valid(opj_image_t* img) {
289 return sycc420_422_size_is_valid(img) && img->comps[0].h == img->comps[1].h;
290 }
291
sycc422_to_rgb(opj_image_t * img)292 void sycc422_to_rgb(opj_image_t* img) {
293 if (!sycc422_size_is_valid(img))
294 return;
295
296 int prec = img->comps[0].prec;
297 if (prec <= 0 || prec >= 32)
298 return;
299
300 int offset = 1 << (prec - 1);
301 int upb = (1 << prec) - 1;
302 OPJ_UINT32 maxw = img->comps[0].w;
303 OPJ_UINT32 maxh = img->comps[0].h;
304 FX_SAFE_SIZE_T max_size = maxw;
305 max_size *= maxh;
306 max_size *= sizeof(int);
307 if (!max_size.IsValid())
308 return;
309
310 const int* y = img->comps[0].data;
311 const int* cb = img->comps[1].data;
312 const int* cr = img->comps[2].data;
313 if (!y || !cb || !cr)
314 return;
315
316 Optional<OpjImageRgbData> data = alloc_rgb(max_size.ValueOrDie());
317 if (!data.has_value())
318 return;
319
320 int* r = data.value().r.get();
321 int* g = data.value().g.get();
322 int* b = data.value().b.get();
323 for (uint32_t i = 0; i < maxh; ++i) {
324 OPJ_UINT32 j;
325 for (j = 0; j < (maxw & ~static_cast<OPJ_UINT32>(1)); j += 2) {
326 sycc_to_rgb(offset, upb, *y++, *cb, *cr, r++, g++, b++);
327 sycc_to_rgb(offset, upb, *y++, *cb++, *cr++, r++, g++, b++);
328 }
329 if (j < maxw) {
330 sycc_to_rgb(offset, upb, *y++, *cb++, *cr++, r++, g++, b++);
331 }
332 }
333
334 opj_image_data_free(img->comps[0].data);
335 opj_image_data_free(img->comps[1].data);
336 opj_image_data_free(img->comps[2].data);
337 img->comps[0].data = data.value().r.release();
338 img->comps[1].data = data.value().g.release();
339 img->comps[2].data = data.value().b.release();
340 img->comps[1].w = maxw;
341 img->comps[1].h = maxh;
342 img->comps[2].w = maxw;
343 img->comps[2].h = maxh;
344 img->comps[1].dx = img->comps[0].dx;
345 img->comps[2].dx = img->comps[0].dx;
346 img->comps[1].dy = img->comps[0].dy;
347 img->comps[2].dy = img->comps[0].dy;
348 }
349
is_sycc420(const opj_image_t * img)350 bool is_sycc420(const opj_image_t* img) {
351 return img->comps[0].dx == 1 && img->comps[0].dy == 1 &&
352 img->comps[1].dx == 2 && img->comps[1].dy == 2 &&
353 img->comps[2].dx == 2 && img->comps[2].dy == 2;
354 }
355
is_sycc422(const opj_image_t * img)356 bool is_sycc422(const opj_image_t* img) {
357 return img->comps[0].dx == 1 && img->comps[0].dy == 1 &&
358 img->comps[1].dx == 2 && img->comps[1].dy == 1 &&
359 img->comps[2].dx == 2 && img->comps[2].dy == 1;
360 }
361
is_sycc444(const opj_image_t * img)362 bool is_sycc444(const opj_image_t* img) {
363 return img->comps[0].dx == 1 && img->comps[0].dy == 1 &&
364 img->comps[1].dx == 1 && img->comps[1].dy == 1 &&
365 img->comps[2].dx == 1 && img->comps[2].dy == 1;
366 }
367
color_sycc_to_rgb(opj_image_t * img)368 void color_sycc_to_rgb(opj_image_t* img) {
369 if (img->numcomps < 3) {
370 img->color_space = OPJ_CLRSPC_GRAY;
371 return;
372 }
373 if (is_sycc420(img))
374 sycc420_to_rgb(img);
375 else if (is_sycc422(img))
376 sycc422_to_rgb(img);
377 else if (is_sycc444(img))
378 sycc444_to_rgb(img);
379 else
380 return;
381
382 img->color_space = OPJ_CLRSPC_SRGB;
383 }
384
385 } // namespace
386
387 // static
Sycc420ToRgbForTesting(opj_image_t * img)388 void CJPX_Decoder::Sycc420ToRgbForTesting(opj_image_t* img) {
389 sycc420_to_rgb(img);
390 }
391
CJPX_Decoder(ColorSpaceOption option)392 CJPX_Decoder::CJPX_Decoder(ColorSpaceOption option)
393 : m_ColorSpaceOption(option) {}
394
~CJPX_Decoder()395 CJPX_Decoder::~CJPX_Decoder() {
396 if (m_Codec)
397 opj_destroy_codec(m_Codec.Release());
398 if (m_Stream)
399 opj_stream_destroy(m_Stream.Release());
400 if (m_Image)
401 opj_image_destroy(m_Image.Release());
402 }
403
Init(pdfium::span<const uint8_t> src_data)404 bool CJPX_Decoder::Init(pdfium::span<const uint8_t> src_data) {
405 static const unsigned char szJP2Header[] = {
406 0x00, 0x00, 0x00, 0x0c, 0x6a, 0x50, 0x20, 0x20, 0x0d, 0x0a, 0x87, 0x0a};
407 if (src_data.empty() || src_data.size() < sizeof(szJP2Header))
408 return false;
409
410 m_Image = nullptr;
411 m_SrcData = src_data;
412 m_DecodeData =
413 pdfium::MakeUnique<DecodeData>(src_data.data(), src_data.size());
414 m_Stream = fx_opj_stream_create_memory_stream(m_DecodeData.get());
415 if (!m_Stream)
416 return false;
417
418 opj_set_default_decoder_parameters(&m_Parameters);
419 m_Parameters.decod_format = 0;
420 m_Parameters.cod_format = 3;
421 if (memcmp(m_SrcData.data(), szJP2Header, sizeof(szJP2Header)) == 0) {
422 m_Codec = opj_create_decompress(OPJ_CODEC_JP2);
423 m_Parameters.decod_format = 1;
424 } else {
425 m_Codec = opj_create_decompress(OPJ_CODEC_J2K);
426 }
427 if (!m_Codec)
428 return false;
429
430 if (m_ColorSpaceOption == kIndexedColorSpace)
431 m_Parameters.flags |= OPJ_DPARAMETERS_IGNORE_PCLR_CMAP_CDEF_FLAG;
432 opj_set_info_handler(m_Codec.Get(), fx_ignore_callback, nullptr);
433 opj_set_warning_handler(m_Codec.Get(), fx_ignore_callback, nullptr);
434 opj_set_error_handler(m_Codec.Get(), fx_ignore_callback, nullptr);
435 if (!opj_setup_decoder(m_Codec.Get(), &m_Parameters))
436 return false;
437
438 m_Image = nullptr;
439 opj_image_t* pTempImage = nullptr;
440 if (!opj_read_header(m_Stream.Get(), m_Codec.Get(), &pTempImage))
441 return false;
442
443 m_Image = pTempImage;
444 return true;
445 }
446
StartDecode()447 bool CJPX_Decoder::StartDecode() {
448 if (!m_Parameters.nb_tile_to_decode) {
449 if (!opj_set_decode_area(m_Codec.Get(), m_Image.Get(), m_Parameters.DA_x0,
450 m_Parameters.DA_y0, m_Parameters.DA_x1,
451 m_Parameters.DA_y1)) {
452 opj_image_destroy(m_Image.Release());
453 return false;
454 }
455 if (!(opj_decode(m_Codec.Get(), m_Stream.Get(), m_Image.Get()) &&
456 opj_end_decompress(m_Codec.Get(), m_Stream.Get()))) {
457 opj_image_destroy(m_Image.Release());
458 return false;
459 }
460 } else if (!opj_get_decoded_tile(m_Codec.Get(), m_Stream.Get(), m_Image.Get(),
461 m_Parameters.tile_index)) {
462 return false;
463 }
464
465 opj_stream_destroy(m_Stream.Release());
466 if (m_Image->color_space != OPJ_CLRSPC_SYCC && m_Image->numcomps == 3 &&
467 m_Image->comps[0].dx == m_Image->comps[0].dy &&
468 m_Image->comps[1].dx != 1) {
469 m_Image->color_space = OPJ_CLRSPC_SYCC;
470 } else if (m_Image->numcomps <= 2) {
471 m_Image->color_space = OPJ_CLRSPC_GRAY;
472 }
473 if (m_Image->color_space == OPJ_CLRSPC_SYCC)
474 color_sycc_to_rgb(m_Image.Get());
475
476 if (m_Image->icc_profile_buf) {
477 // TODO(palmer): Using |opj_free| here resolves the crash described in
478 // https://crbug.com/737033, but ultimately we need to harmonize the
479 // memory allocation strategy across OpenJPEG and its PDFium callers.
480 #if !defined(USE_SYSTEM_LIBOPENJPEG2)
481 opj_free(m_Image->icc_profile_buf);
482 #else
483 free(m_Image->icc_profile_buf);
484 #endif
485 m_Image->icc_profile_buf = nullptr;
486 m_Image->icc_profile_len = 0;
487 }
488 return true;
489 }
490
GetInfo() const491 CJPX_Decoder::JpxImageInfo CJPX_Decoder::GetInfo() const {
492 return {m_Image->x1, m_Image->y1, m_Image->numcomps};
493 }
494
Decode(uint8_t * dest_buf,uint32_t pitch,bool swap_rgb)495 bool CJPX_Decoder::Decode(uint8_t* dest_buf, uint32_t pitch, bool swap_rgb) {
496 if (m_Image->comps[0].w != m_Image->x1 || m_Image->comps[0].h != m_Image->y1)
497 return false;
498
499 if (pitch<(m_Image->comps[0].w * 8 * m_Image->numcomps + 31)>> 5 << 2)
500 return false;
501
502 if (swap_rgb && m_Image->numcomps < 3)
503 return false;
504
505 memset(dest_buf, 0xff, m_Image->y1 * pitch);
506 std::vector<uint8_t*> channel_bufs(m_Image->numcomps);
507 std::vector<int> adjust_comps(m_Image->numcomps);
508 for (uint32_t i = 0; i < m_Image->numcomps; i++) {
509 channel_bufs[i] = dest_buf + i;
510 adjust_comps[i] = m_Image->comps[i].prec - 8;
511 if (i > 0) {
512 if (m_Image->comps[i].dx != m_Image->comps[i - 1].dx ||
513 m_Image->comps[i].dy != m_Image->comps[i - 1].dy ||
514 m_Image->comps[i].prec != m_Image->comps[i - 1].prec) {
515 return false;
516 }
517 }
518 }
519 if (swap_rgb)
520 std::swap(channel_bufs[0], channel_bufs[2]);
521
522 uint32_t width = m_Image->comps[0].w;
523 uint32_t height = m_Image->comps[0].h;
524 for (uint32_t channel = 0; channel < m_Image->numcomps; ++channel) {
525 uint8_t* pChannel = channel_bufs[channel];
526 if (adjust_comps[channel] < 0) {
527 for (uint32_t row = 0; row < height; ++row) {
528 uint8_t* pScanline = pChannel + row * pitch;
529 for (uint32_t col = 0; col < width; ++col) {
530 uint8_t* pPixel = pScanline + col * m_Image->numcomps;
531 if (!m_Image->comps[channel].data)
532 continue;
533
534 int src = m_Image->comps[channel].data[row * width + col];
535 src += m_Image->comps[channel].sgnd
536 ? 1 << (m_Image->comps[channel].prec - 1)
537 : 0;
538 if (adjust_comps[channel] > 0) {
539 *pPixel = 0;
540 } else {
541 *pPixel = static_cast<uint8_t>(src << -adjust_comps[channel]);
542 }
543 }
544 }
545 } else {
546 for (uint32_t row = 0; row < height; ++row) {
547 uint8_t* pScanline = pChannel + row * pitch;
548 for (uint32_t col = 0; col < width; ++col) {
549 uint8_t* pPixel = pScanline + col * m_Image->numcomps;
550 if (!m_Image->comps[channel].data)
551 continue;
552
553 int src = m_Image->comps[channel].data[row * width + col];
554 src += m_Image->comps[channel].sgnd
555 ? 1 << (m_Image->comps[channel].prec - 1)
556 : 0;
557 if (adjust_comps[channel] - 1 < 0) {
558 *pPixel = static_cast<uint8_t>((src >> adjust_comps[channel]));
559 } else {
560 int tmpPixel = (src >> adjust_comps[channel]) +
561 ((src >> (adjust_comps[channel] - 1)) % 2);
562 tmpPixel = pdfium::clamp(tmpPixel, 0, 255);
563 *pPixel = static_cast<uint8_t>(tmpPixel);
564 }
565 }
566 }
567 }
568 }
569 return true;
570 }
571
572 } // namespace fxcodec
573