Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / ui / gfx / chromeos / codec / jpeg_codec_robust_slow.cc
blobc5a78aac036c16d1557607bd9df131c27d08af4b
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"
7 #include <setjmp.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"
14 extern "C" {
15 // IJG provides robust JPEG decode
16 #include "third_party/libjpeg/jpeglib.h"
19 namespace gfx {
21 // Encoder/decoder shared stuff ------------------------------------------------
23 namespace {
25 // used to pass error info through the JPEG library
26 struct CoderErrorMgr {
27 jpeg_error_mgr pub;
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);
38 } // namespace
40 // Decoder --------------------------------------------------------------------
42 namespace {
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) {
79 return false;
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
113 // jpeg_destroy()."
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
119 // value.
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];
137 pixel_out[3] = 0xff;
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
144 // success case).
145 class DecompressDestroyer {
146 public:
147 DecompressDestroyer() : cinfo_(NULL) {
149 ~DecompressDestroyer() {
150 DestroyManagedObject();
152 void SetManagedObject(jpeg_decompress_struct* ci) {
153 DestroyManagedObject();
154 cinfo_ = ci;
156 void DestroyManagedObject() {
157 if (cinfo_) {
158 jpeg_destroy_decompress(cinfo_);
159 cinfo_ = NULL;
162 private:
163 jpeg_decompress_struct* cinfo_;
166 } // namespace
168 bool JPEGCodecRobustSlow::Decode(const unsigned char* input, size_t input_size,
169 ColorFormat format,
170 std::vector<unsigned char>* output, int* w,
171 int* h) {
172 jpeg_decompress_struct cinfo;
173 DecompressDestroyer destroyer;
174 destroyer.SetManagedObject(&cinfo);
175 output->clear();
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
186 // manually here.
187 destroyer.DestroyManagedObject();
188 return false;
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;
202 cinfo.src = &srcmgr;
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)
209 return false;
211 // we want to always get RGB data out
212 switch (cinfo.jpeg_color_space) {
213 case JCS_GRAYSCALE:
214 case JCS_RGB:
215 case JCS_YCbCr:
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;
232 } else {
233 // We can exit this function without calling jpeg_destroy_decompress()
234 // because DecompressDestroyer automaticaly calls it.
235 NOTREACHED() << "Invalid pixel format";
236 return false;
238 #else
239 cinfo.out_color_space = JCS_RGB;
240 #endif
241 break;
242 case JCS_CMYK:
243 case JCS_YCCK:
244 default:
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.
248 return false;
250 #ifndef JCS_EXTENSIONS
251 cinfo.output_components = 3;
252 #endif
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))
273 return false;
275 #else
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))
284 return false;
286 } else {
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;
300 } else {
301 NOTREACHED() << "Invalid pixel format";
302 jpeg_destroy_decompress(&cinfo);
303 return false;
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))
312 return false;
313 converter(rowptr, *w, &(*output)[row * row_write_stride]);
316 #endif
318 jpeg_finish_decompress(&cinfo);
319 jpeg_destroy_decompress(&cinfo);
320 return true;
323 // static
324 SkBitmap* JPEGCodecRobustSlow::Decode(const unsigned char* input,
325 size_t input_size) {
326 int w, h;
327 std::vector<unsigned char> data_vector;
328 if (!Decode(input, input_size, FORMAT_SkBitmap, &data_vector, &w, &h))
329 return NULL;
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);
338 return bitmap;
341 } // namespace gfx