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