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//codec/chromeos/jpeg_codec_robust_slow.h" | |
6 | |
7 #include <setjmp.h> | |
8 | |
9 #include <memory> | |
10 | |
11 #include "base/logging.h" | |
12 | |
13 extern "C" { | |
14 // IJG provides robust JPEG decode | |
15 #include "third_party/libjpeg/jpeglib.h" | |
16 } | |
17 | |
18 #include "third_party/skia/include/core/SkBitmap.h" | |
19 #include "third_party/skia/include/core/SkColorPriv.h" | |
20 | |
21 namespace gfx { | |
22 | |
23 // Encoder/decoder shared stuff ------------------------------------------------ | |
24 | |
25 namespace { | |
26 | |
27 // used to pass error info through the JPEG library | |
28 struct CoderErrorMgr { | |
29 jpeg_error_mgr pub; | |
30 jmp_buf setjmp_buffer; | |
31 }; | |
32 | |
33 void ErrorExit(jpeg_common_struct* cinfo) { | |
34 CoderErrorMgr* err = reinterpret_cast<CoderErrorMgr*>(cinfo->err); | |
35 | |
36 // Return control to the setjmp point. | |
37 longjmp(err->setjmp_buffer, false); | |
38 } | |
39 | |
40 } // namespace | |
41 | |
42 // Decoder -------------------------------------------------------------------- | |
43 | |
44 namespace { | |
45 | |
46 struct JpegDecoderState { | |
47 JpegDecoderState(const unsigned char* in, size_t len) | |
48 : input_buffer(in), input_buffer_length(len) {} | |
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 #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; | |
124 } | |
125 } | |
126 | |
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) { | |
130 for (int x = 0; x < pixel_width; x++) { | |
131 const unsigned char* pixel_in = &bgra[x * 3]; | |
132 unsigned char* pixel_out = &rgb[x * 4]; | |
133 pixel_out[0] = pixel_in[2]; | |
134 pixel_out[1] = pixel_in[1]; | |
135 pixel_out[2] = pixel_in[0]; | |
136 pixel_out[3] = 0xff; | |
137 } | |
138 } | |
139 #endif // !defined(JCS_EXTENSIONS) | |
140 | |
141 // This class destroys the given jpeg_decompress object when it goes out of | |
142 // scope. It simplifies the error handling in Decode (and even applies to the | |
143 // success case). | |
144 class DecompressDestroyer { | |
145 public: | |
146 DecompressDestroyer() : cinfo_(NULL) {} | |
147 ~DecompressDestroyer() { DestroyManagedObject(); } | |
148 void SetManagedObject(jpeg_decompress_struct* ci) { | |
149 DestroyManagedObject(); | |
150 cinfo_ = ci; | |
151 } | |
152 void DestroyManagedObject() { | |
153 if (cinfo_) { | |
154 jpeg_destroy_decompress(cinfo_); | |
155 cinfo_ = NULL; | |
156 } | |
157 } | |
158 | |
159 private: | |
160 jpeg_decompress_struct* cinfo_; | |
161 }; | |
162 | |
163 } // namespace | |
164 | |
165 bool JPEGCodecRobustSlow::Decode(const unsigned char* input, | |
166 size_t input_size, | |
167 ColorFormat format, | |
168 std::vector<unsigned char>* output, | |
169 int* w, | |
170 int* h) { | |
171 jpeg_decompress_struct cinfo; | |
172 DecompressDestroyer destroyer; | |
173 destroyer.SetManagedObject(&cinfo); | |
174 output->clear(); | |
175 | |
176 // We set up the normal JPEG error routines, then override error_exit. | |
177 // This must be done before the call to create_decompress. | |
178 CoderErrorMgr errmgr; | |
179 cinfo.err = jpeg_std_error(&errmgr.pub); | |
180 errmgr.pub.error_exit = ErrorExit; | |
181 // Establish the setjmp return context for ErrorExit to use. | |
182 if (setjmp(errmgr.setjmp_buffer)) { | |
183 // If we get here, the JPEG code has signaled an error. | |
184 // See note in JPEGCodec::Encode() for why we need to destroy the cinfo | |
185 // manually here. | |
186 destroyer.DestroyManagedObject(); | |
187 return false; | |
188 } | |
189 | |
190 // The destroyer will destroy() cinfo on exit. We don't want to set the | |
191 // destroyer's object until cinfo is initialized. | |
192 jpeg_create_decompress(&cinfo); | |
193 | |
194 // set up the source manager | |
195 jpeg_source_mgr srcmgr; | |
196 srcmgr.init_source = InitSource; | |
197 srcmgr.fill_input_buffer = FillInputBuffer; | |
198 srcmgr.skip_input_data = SkipInputData; | |
199 srcmgr.resync_to_restart = jpeg_resync_to_restart; // use default routine | |
200 srcmgr.term_source = TermSource; | |
201 cinfo.src = &srcmgr; | |
202 | |
203 JpegDecoderState state(input, input_size); | |
204 cinfo.client_data = &state; | |
205 | |
206 // fill the file metadata into our buffer | |
207 if (jpeg_read_header(&cinfo, true) != JPEG_HEADER_OK) | |
208 return false; | |
209 | |
210 // we want to always get RGB data out | |
211 switch (cinfo.jpeg_color_space) { | |
212 case JCS_GRAYSCALE: | |
213 case JCS_RGB: | |
214 case JCS_YCbCr: | |
215 #ifdef JCS_EXTENSIONS | |
216 // Choose an output colorspace and return if it is an unsupported one. | |
217 // Same as JPEGCodec::Encode(), libjpeg-turbo supports all input formats | |
218 // used by Chromium (i.e. RGB, RGBA, and BGRA) and we just map the input | |
219 // parameters to a colorspace. | |
220 if (format == FORMAT_RGB) { | |
221 cinfo.out_color_space = JCS_RGB; | |
222 cinfo.output_components = 3; | |
223 } else if (format == FORMAT_RGBA || | |
224 (format == FORMAT_SkBitmap && SK_R32_SHIFT == 0)) { | |
225 cinfo.out_color_space = JCS_EXT_RGBX; | |
226 cinfo.output_components = 4; | |
227 } else if (format == FORMAT_BGRA || | |
228 (format == FORMAT_SkBitmap && SK_B32_SHIFT == 0)) { | |
229 cinfo.out_color_space = JCS_EXT_BGRX; | |
230 cinfo.output_components = 4; | |
231 } else { | |
232 // We can exit this function without calling jpeg_destroy_decompress() | |
233 // because DecompressDestroyer automaticaly calls it. | |
234 NOTREACHED() << "Invalid pixel format"; | |
235 return false; | |
236 } | |
237 #else | |
238 cinfo.out_color_space = JCS_RGB; | |
239 #endif | |
240 break; | |
241 case JCS_CMYK: | |
242 case JCS_YCCK: | |
243 default: | |
244 // Mozilla errors out on these color spaces, so I presume that the jpeg | |
245 // library can't do automatic color space conversion for them. We don't | |
246 // care about these anyway. | |
247 return false; | |
248 } | |
249 #ifndef JCS_EXTENSIONS | |
250 cinfo.output_components = 3; | |
251 #endif | |
252 | |
253 jpeg_calc_output_dimensions(&cinfo); | |
254 *w = cinfo.output_width; | |
255 *h = cinfo.output_height; | |
256 | |
257 jpeg_start_decompress(&cinfo); | |
258 | |
259 // FIXME(brettw) we may want to allow the capability for callers to request | |
260 // how to align row lengths as we do for the compressor. | |
261 int row_read_stride = cinfo.output_width * cinfo.output_components; | |
262 | |
263 #ifdef JCS_EXTENSIONS | |
264 // Create memory for a decoded image and write decoded lines to the memory | |
265 // without conversions same as JPEGCodec::Encode(). | |
266 int row_write_stride = row_read_stride; | |
267 output->resize(row_write_stride * cinfo.output_height); | |
268 | |
269 for (int row = 0; row < static_cast<int>(cinfo.output_height); row++) { | |
270 unsigned char* rowptr = &(*output)[row * row_write_stride]; | |
271 if (!jpeg_read_scanlines(&cinfo, &rowptr, 1)) | |
272 return false; | |
273 } | |
274 #else | |
275 if (format == FORMAT_RGB) { | |
276 // easy case, row needs no conversion | |
277 int row_write_stride = row_read_stride; | |
278 output->resize(row_write_stride * cinfo.output_height); | |
279 | |
280 for (int row = 0; row < static_cast<int>(cinfo.output_height); row++) { | |
281 unsigned char* rowptr = &(*output)[row * row_write_stride]; | |
282 if (!jpeg_read_scanlines(&cinfo, &rowptr, 1)) | |
283 return false; | |
284 } | |
285 } else { | |
286 // Rows need conversion to output format: read into a temporary buffer and | |
287 // expand to the final one. Performance: we could avoid the extra | |
288 // allocation by doing the expansion in-place. | |
289 int row_write_stride; | |
290 void (*converter)(const unsigned char* rgb, int w, unsigned char* out); | |
291 if (format == FORMAT_RGBA || | |
292 (format == FORMAT_SkBitmap && SK_R32_SHIFT == 0)) { | |
293 row_write_stride = cinfo.output_width * 4; | |
294 converter = AddAlpha; | |
295 } else if (format == FORMAT_BGRA || | |
296 (format == FORMAT_SkBitmap && SK_B32_SHIFT == 0)) { | |
297 row_write_stride = cinfo.output_width * 4; | |
298 converter = RGBtoBGRA; | |
299 } else { | |
300 NOTREACHED() << "Invalid pixel format"; | |
301 jpeg_destroy_decompress(&cinfo); | |
302 return false; | |
303 } | |
304 | |
305 output->resize(row_write_stride * cinfo.output_height); | |
306 | |
307 std::unique_ptr<unsigned char[]> row_data( | |
308 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]); | |
314 } | |
315 } | |
316 #endif | |
317 | |
318 jpeg_finish_decompress(&cinfo); | |
319 jpeg_destroy_decompress(&cinfo); | |
320 return true; | |
321 } | |
322 | |
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; | |
330 | |
331 // Skia only handles 32 bit images. | |
332 int data_length = w * h * 4; | |
333 | |
334 SkBitmap* bitmap = new SkBitmap(); | |
335 bitmap->allocN32Pixels(w, h); | |
336 memcpy(bitmap->getAddr32(0, 0), &data_vector[0], data_length); | |
337 | |
338 return bitmap; | |
339 } | |
340 | |
341 } // namespace gfx | |
OLD | NEW |