1 // Copyright 2015 The Chromium 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.
5 #include "ui/gfx/chromeos/codec/jpeg_codec_robust_slow.h"
9 #include "base/logging.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "third_party/skia/include/core/SkBitmap.h"
12 #include "third_party/skia/include/core/SkColorPriv.h"
15 // IJG provides robust JPEG decode
16 #include "third_party/libjpeg/jpeglib.h"
21 // Encoder/decoder shared stuff ------------------------------------------------
25 // used to pass error info through the JPEG library
26 struct CoderErrorMgr
{
28 jmp_buf setjmp_buffer
;
31 void ErrorExit(jpeg_common_struct
* cinfo
) {
32 CoderErrorMgr
*err
= reinterpret_cast<CoderErrorMgr
*>(cinfo
->err
);
34 // Return control to the setjmp point.
35 longjmp(err
->setjmp_buffer
, false);
40 // Decoder --------------------------------------------------------------------
44 struct JpegDecoderState
{
45 JpegDecoderState(const unsigned char* in
, size_t len
)
46 : input_buffer(in
), input_buffer_length(len
) {
49 const unsigned char* input_buffer
;
50 size_t input_buffer_length
;
53 // Callback to initialize the source.
55 // From the JPEG library:
56 // "Initialize source. This is called by jpeg_read_header() before any data is
57 // actually read. May leave bytes_in_buffer set to 0 (in which case a
58 // fill_input_buffer() call will occur immediately)."
59 void InitSource(j_decompress_ptr cinfo
) {
60 JpegDecoderState
* state
= static_cast<JpegDecoderState
*>(cinfo
->client_data
);
61 cinfo
->src
->next_input_byte
= state
->input_buffer
;
62 cinfo
->src
->bytes_in_buffer
= state
->input_buffer_length
;
65 // Callback to fill the buffer. Since our buffer already contains all the data,
66 // we should never need to provide more data. If libjpeg thinks it needs more
67 // data, our input is probably corrupt.
69 // From the JPEG library:
70 // "This is called whenever bytes_in_buffer has reached zero and more data is
71 // wanted. In typical applications, it should read fresh data into the buffer
72 // (ignoring the current state of next_input_byte and bytes_in_buffer), reset
73 // the pointer & count to the start of the buffer, and return TRUE indicating
74 // that the buffer has been reloaded. It is not necessary to fill the buffer
75 // entirely, only to obtain at least one more byte. bytes_in_buffer MUST be
76 // set to a positive value if TRUE is returned. A FALSE return should only
77 // be used when I/O suspension is desired."
78 boolean
FillInputBuffer(j_decompress_ptr cinfo
) {
82 // Skip data in the buffer. Since we have all the data at once, this operation
83 // is easy. It is not clear if this ever gets called because the JPEG library
84 // should be able to do the skip itself (it has all the data).
86 // From the JPEG library:
87 // "Skip num_bytes worth of data. The buffer pointer and count should be
88 // advanced over num_bytes input bytes, refilling the buffer as needed. This
89 // is used to skip over a potentially large amount of uninteresting data
90 // (such as an APPn marker). In some applications it may be possible to
91 // optimize away the reading of the skipped data, but it's not clear that
92 // being smart is worth much trouble; large skips are uncommon.
93 // bytes_in_buffer may be zero on return. A zero or negative skip count
94 // should be treated as a no-op."
95 void SkipInputData(j_decompress_ptr cinfo
, long num_bytes
) {
96 if (num_bytes
> static_cast<long>(cinfo
->src
->bytes_in_buffer
)) {
97 // Since all our data should be in the buffer, trying to skip beyond it
98 // means that there is some kind of error or corrupt input data. A 0 for
99 // bytes left means it will call FillInputBuffer which will then fail.
100 cinfo
->src
->next_input_byte
+= cinfo
->src
->bytes_in_buffer
;
101 cinfo
->src
->bytes_in_buffer
= 0;
102 } else if (num_bytes
> 0) {
103 cinfo
->src
->bytes_in_buffer
-= static_cast<size_t>(num_bytes
);
104 cinfo
->src
->next_input_byte
+= num_bytes
;
108 // Our source doesn't need any cleanup, so this is a NOP.
110 // From the JPEG library:
111 // "Terminate source --- called by jpeg_finish_decompress() after all data has
112 // been read to clean up JPEG source manager. NOT called by jpeg_abort() or
114 void TermSource(j_decompress_ptr cinfo
) {
117 #if !defined(JCS_EXTENSIONS)
118 // Converts one row of rgb data to rgba data by adding a fully-opaque alpha
120 void AddAlpha(const unsigned char* rgb
, int pixel_width
, unsigned char* rgba
) {
121 for (int x
= 0; x
< pixel_width
; x
++) {
122 memcpy(&rgba
[x
* 4], &rgb
[x
* 3], 3);
123 rgba
[x
* 4 + 3] = 0xff;
127 // Converts one row of RGB data to BGRA by reordering the color components and
128 // adding alpha values of 0xff.
129 void RGBtoBGRA(const unsigned char* bgra
, int pixel_width
, unsigned char* rgb
)
131 for (int x
= 0; x
< pixel_width
; x
++) {
132 const unsigned char* pixel_in
= &bgra
[x
* 3];
133 unsigned char* pixel_out
= &rgb
[x
* 4];
134 pixel_out
[0] = pixel_in
[2];
135 pixel_out
[1] = pixel_in
[1];
136 pixel_out
[2] = pixel_in
[0];
140 #endif // !defined(JCS_EXTENSIONS)
142 // This class destroys the given jpeg_decompress object when it goes out of
143 // scope. It simplifies the error handling in Decode (and even applies to the
145 class DecompressDestroyer
{
147 DecompressDestroyer() : cinfo_(NULL
) {
149 ~DecompressDestroyer() {
150 DestroyManagedObject();
152 void SetManagedObject(jpeg_decompress_struct
* ci
) {
153 DestroyManagedObject();
156 void DestroyManagedObject() {
158 jpeg_destroy_decompress(cinfo_
);
163 jpeg_decompress_struct
* cinfo_
;
168 bool JPEGCodecRobustSlow::Decode(const unsigned char* input
, size_t input_size
,
170 std::vector
<unsigned char>* output
, int* w
,
172 jpeg_decompress_struct cinfo
;
173 DecompressDestroyer destroyer
;
174 destroyer
.SetManagedObject(&cinfo
);
177 // We set up the normal JPEG error routines, then override error_exit.
178 // This must be done before the call to create_decompress.
179 CoderErrorMgr errmgr
;
180 cinfo
.err
= jpeg_std_error(&errmgr
.pub
);
181 errmgr
.pub
.error_exit
= ErrorExit
;
182 // Establish the setjmp return context for ErrorExit to use.
183 if (setjmp(errmgr
.setjmp_buffer
)) {
184 // If we get here, the JPEG code has signaled an error.
185 // See note in JPEGCodec::Encode() for why we need to destroy the cinfo
187 destroyer
.DestroyManagedObject();
191 // The destroyer will destroy() cinfo on exit. We don't want to set the
192 // destroyer's object until cinfo is initialized.
193 jpeg_create_decompress(&cinfo
);
195 // set up the source manager
196 jpeg_source_mgr srcmgr
;
197 srcmgr
.init_source
= InitSource
;
198 srcmgr
.fill_input_buffer
= FillInputBuffer
;
199 srcmgr
.skip_input_data
= SkipInputData
;
200 srcmgr
.resync_to_restart
= jpeg_resync_to_restart
; // use default routine
201 srcmgr
.term_source
= TermSource
;
204 JpegDecoderState
state(input
, input_size
);
205 cinfo
.client_data
= &state
;
207 // fill the file metadata into our buffer
208 if (jpeg_read_header(&cinfo
, true) != JPEG_HEADER_OK
)
211 // we want to always get RGB data out
212 switch (cinfo
.jpeg_color_space
) {
216 #ifdef JCS_EXTENSIONS
217 // Choose an output colorspace and return if it is an unsupported one.
218 // Same as JPEGCodec::Encode(), libjpeg-turbo supports all input formats
219 // used by Chromium (i.e. RGB, RGBA, and BGRA) and we just map the input
220 // parameters to a colorspace.
221 if (format
== FORMAT_RGB
) {
222 cinfo
.out_color_space
= JCS_RGB
;
223 cinfo
.output_components
= 3;
224 } else if (format
== FORMAT_RGBA
||
225 (format
== FORMAT_SkBitmap
&& SK_R32_SHIFT
== 0)) {
226 cinfo
.out_color_space
= JCS_EXT_RGBX
;
227 cinfo
.output_components
= 4;
228 } else if (format
== FORMAT_BGRA
||
229 (format
== FORMAT_SkBitmap
&& SK_B32_SHIFT
== 0)) {
230 cinfo
.out_color_space
= JCS_EXT_BGRX
;
231 cinfo
.output_components
= 4;
233 // We can exit this function without calling jpeg_destroy_decompress()
234 // because DecompressDestroyer automaticaly calls it.
235 NOTREACHED() << "Invalid pixel format";
239 cinfo
.out_color_space
= JCS_RGB
;
245 // Mozilla errors out on these color spaces, so I presume that the jpeg
246 // library can't do automatic color space conversion for them. We don't
247 // care about these anyway.
250 #ifndef JCS_EXTENSIONS
251 cinfo
.output_components
= 3;
254 jpeg_calc_output_dimensions(&cinfo
);
255 *w
= cinfo
.output_width
;
256 *h
= cinfo
.output_height
;
258 jpeg_start_decompress(&cinfo
);
260 // FIXME(brettw) we may want to allow the capability for callers to request
261 // how to align row lengths as we do for the compressor.
262 int row_read_stride
= cinfo
.output_width
* cinfo
.output_components
;
264 #ifdef JCS_EXTENSIONS
265 // Create memory for a decoded image and write decoded lines to the memory
266 // without conversions same as JPEGCodec::Encode().
267 int row_write_stride
= row_read_stride
;
268 output
->resize(row_write_stride
* cinfo
.output_height
);
270 for (int row
= 0; row
< static_cast<int>(cinfo
.output_height
); row
++) {
271 unsigned char* rowptr
= &(*output
)[row
* row_write_stride
];
272 if (!jpeg_read_scanlines(&cinfo
, &rowptr
, 1))
276 if (format
== FORMAT_RGB
) {
277 // easy case, row needs no conversion
278 int row_write_stride
= row_read_stride
;
279 output
->resize(row_write_stride
* cinfo
.output_height
);
281 for (int row
= 0; row
< static_cast<int>(cinfo
.output_height
); row
++) {
282 unsigned char* rowptr
= &(*output
)[row
* row_write_stride
];
283 if (!jpeg_read_scanlines(&cinfo
, &rowptr
, 1))
287 // Rows need conversion to output format: read into a temporary buffer and
288 // expand to the final one. Performance: we could avoid the extra
289 // allocation by doing the expansion in-place.
290 int row_write_stride
;
291 void (*converter
)(const unsigned char* rgb
, int w
, unsigned char* out
);
292 if (format
== FORMAT_RGBA
||
293 (format
== FORMAT_SkBitmap
&& SK_R32_SHIFT
== 0)) {
294 row_write_stride
= cinfo
.output_width
* 4;
295 converter
= AddAlpha
;
296 } else if (format
== FORMAT_BGRA
||
297 (format
== FORMAT_SkBitmap
&& SK_B32_SHIFT
== 0)) {
298 row_write_stride
= cinfo
.output_width
* 4;
299 converter
= RGBtoBGRA
;
301 NOTREACHED() << "Invalid pixel format";
302 jpeg_destroy_decompress(&cinfo
);
306 output
->resize(row_write_stride
* cinfo
.output_height
);
308 scoped_ptr
<unsigned char[]> row_data(new unsigned char[row_read_stride
]);
309 unsigned char* rowptr
= row_data
.get();
310 for (int row
= 0; row
< static_cast<int>(cinfo
.output_height
); row
++) {
311 if (!jpeg_read_scanlines(&cinfo
, &rowptr
, 1))
313 converter(rowptr
, *w
, &(*output
)[row
* row_write_stride
]);
318 jpeg_finish_decompress(&cinfo
);
319 jpeg_destroy_decompress(&cinfo
);
324 SkBitmap
* JPEGCodecRobustSlow::Decode(const unsigned char* input
,
327 std::vector
<unsigned char> data_vector
;
328 if (!Decode(input
, input_size
, FORMAT_SkBitmap
, &data_vector
, &w
, &h
))
331 // Skia only handles 32 bit images.
332 int data_length
= w
* h
* 4;
334 SkBitmap
* bitmap
= new SkBitmap();
335 bitmap
->allocN32Pixels(w
, h
);
336 memcpy(bitmap
->getAddr32(0, 0), &data_vector
[0], data_length
);