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