|
1 /* |
|
2 * Copyright 2007 The Android Open Source Project |
|
3 * |
|
4 * Use of this source code is governed by a BSD-style license that can be |
|
5 * found in the LICENSE file. |
|
6 */ |
|
7 |
|
8 |
|
9 #include "SkImageDecoder.h" |
|
10 #include "SkImageEncoder.h" |
|
11 #include "SkJpegUtility.h" |
|
12 #include "SkColorPriv.h" |
|
13 #include "SkDither.h" |
|
14 #include "SkScaledBitmapSampler.h" |
|
15 #include "SkStream.h" |
|
16 #include "SkTemplates.h" |
|
17 #include "SkTime.h" |
|
18 #include "SkUtils.h" |
|
19 #include "SkRTConf.h" |
|
20 #include "SkRect.h" |
|
21 #include "SkCanvas.h" |
|
22 |
|
23 |
|
24 #include <stdio.h> |
|
25 extern "C" { |
|
26 #include "jpeglib.h" |
|
27 #include "jerror.h" |
|
28 } |
|
29 |
|
30 // These enable timing code that report milliseconds for an encoding/decoding |
|
31 //#define TIME_ENCODE |
|
32 //#define TIME_DECODE |
|
33 |
|
34 // this enables our rgb->yuv code, which is faster than libjpeg on ARM |
|
35 #define WE_CONVERT_TO_YUV |
|
36 |
|
37 // If ANDROID_RGB is defined by in the jpeg headers it indicates that jpeg offers |
|
38 // support for two additional formats (1) JCS_RGBA_8888 and (2) JCS_RGB_565. |
|
39 |
|
40 #if defined(SK_DEBUG) |
|
41 #define DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_WARNINGS false |
|
42 #define DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_ERRORS false |
|
43 #else // !defined(SK_DEBUG) |
|
44 #define DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_WARNINGS true |
|
45 #define DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_ERRORS true |
|
46 #endif // defined(SK_DEBUG) |
|
47 SK_CONF_DECLARE(bool, c_suppressJPEGImageDecoderWarnings, |
|
48 "images.jpeg.suppressDecoderWarnings", |
|
49 DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_WARNINGS, |
|
50 "Suppress most JPG warnings when calling decode functions."); |
|
51 SK_CONF_DECLARE(bool, c_suppressJPEGImageDecoderErrors, |
|
52 "images.jpeg.suppressDecoderErrors", |
|
53 DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_ERRORS, |
|
54 "Suppress most JPG error messages when decode " |
|
55 "function fails."); |
|
56 |
|
57 ////////////////////////////////////////////////////////////////////////// |
|
58 ////////////////////////////////////////////////////////////////////////// |
|
59 |
|
60 static void overwrite_mem_buffer_size(jpeg_decompress_struct* cinfo) { |
|
61 #ifdef SK_BUILD_FOR_ANDROID |
|
62 /* Check if the device indicates that it has a large amount of system memory |
|
63 * if so, increase the memory allocation to 30MB instead of the default 5MB. |
|
64 */ |
|
65 #ifdef ANDROID_LARGE_MEMORY_DEVICE |
|
66 cinfo->mem->max_memory_to_use = 30 * 1024 * 1024; |
|
67 #else |
|
68 cinfo->mem->max_memory_to_use = 5 * 1024 * 1024; |
|
69 #endif |
|
70 #endif // SK_BUILD_FOR_ANDROID |
|
71 } |
|
72 |
|
73 ////////////////////////////////////////////////////////////////////////// |
|
74 ////////////////////////////////////////////////////////////////////////// |
|
75 |
|
76 static void do_nothing_emit_message(jpeg_common_struct*, int) { |
|
77 /* do nothing */ |
|
78 } |
|
79 static void do_nothing_output_message(j_common_ptr) { |
|
80 /* do nothing */ |
|
81 } |
|
82 |
|
83 static void initialize_info(jpeg_decompress_struct* cinfo, skjpeg_source_mgr* src_mgr) { |
|
84 SkASSERT(cinfo != NULL); |
|
85 SkASSERT(src_mgr != NULL); |
|
86 jpeg_create_decompress(cinfo); |
|
87 overwrite_mem_buffer_size(cinfo); |
|
88 cinfo->src = src_mgr; |
|
89 /* To suppress warnings with a SK_DEBUG binary, set the |
|
90 * environment variable "skia_images_jpeg_suppressDecoderWarnings" |
|
91 * to "true". Inside a program that links to skia: |
|
92 * SK_CONF_SET("images.jpeg.suppressDecoderWarnings", true); */ |
|
93 if (c_suppressJPEGImageDecoderWarnings) { |
|
94 cinfo->err->emit_message = &do_nothing_emit_message; |
|
95 } |
|
96 /* To suppress error messages with a SK_DEBUG binary, set the |
|
97 * environment variable "skia_images_jpeg_suppressDecoderErrors" |
|
98 * to "true". Inside a program that links to skia: |
|
99 * SK_CONF_SET("images.jpeg.suppressDecoderErrors", true); */ |
|
100 if (c_suppressJPEGImageDecoderErrors) { |
|
101 cinfo->err->output_message = &do_nothing_output_message; |
|
102 } |
|
103 } |
|
104 |
|
105 #ifdef SK_BUILD_FOR_ANDROID |
|
106 class SkJPEGImageIndex { |
|
107 public: |
|
108 SkJPEGImageIndex(SkStreamRewindable* stream, SkImageDecoder* decoder) |
|
109 : fSrcMgr(stream, decoder) |
|
110 , fInfoInitialized(false) |
|
111 , fHuffmanCreated(false) |
|
112 , fDecompressStarted(false) |
|
113 { |
|
114 SkDEBUGCODE(fReadHeaderSucceeded = false;) |
|
115 } |
|
116 |
|
117 ~SkJPEGImageIndex() { |
|
118 if (fHuffmanCreated) { |
|
119 // Set to false before calling the libjpeg function, in case |
|
120 // the libjpeg function calls longjmp. Our setjmp handler may |
|
121 // attempt to delete this SkJPEGImageIndex, thus entering this |
|
122 // destructor again. Setting fHuffmanCreated to false first |
|
123 // prevents an infinite loop. |
|
124 fHuffmanCreated = false; |
|
125 jpeg_destroy_huffman_index(&fHuffmanIndex); |
|
126 } |
|
127 if (fDecompressStarted) { |
|
128 // Like fHuffmanCreated, set to false before calling libjpeg |
|
129 // function to prevent potential infinite loop. |
|
130 fDecompressStarted = false; |
|
131 jpeg_finish_decompress(&fCInfo); |
|
132 } |
|
133 if (fInfoInitialized) { |
|
134 this->destroyInfo(); |
|
135 } |
|
136 } |
|
137 |
|
138 /** |
|
139 * Destroy the cinfo struct. |
|
140 * After this call, if a huffman index was already built, it |
|
141 * can be used after calling initializeInfoAndReadHeader |
|
142 * again. Must not be called after startTileDecompress except |
|
143 * in the destructor. |
|
144 */ |
|
145 void destroyInfo() { |
|
146 SkASSERT(fInfoInitialized); |
|
147 SkASSERT(!fDecompressStarted); |
|
148 // Like fHuffmanCreated, set to false before calling libjpeg |
|
149 // function to prevent potential infinite loop. |
|
150 fInfoInitialized = false; |
|
151 jpeg_destroy_decompress(&fCInfo); |
|
152 SkDEBUGCODE(fReadHeaderSucceeded = false;) |
|
153 } |
|
154 |
|
155 /** |
|
156 * Initialize the cinfo struct. |
|
157 * Calls jpeg_create_decompress, makes customizations, and |
|
158 * finally calls jpeg_read_header. Returns true if jpeg_read_header |
|
159 * returns JPEG_HEADER_OK. |
|
160 * If cinfo was already initialized, destroyInfo must be called to |
|
161 * destroy the old one. Must not be called after startTileDecompress. |
|
162 */ |
|
163 bool initializeInfoAndReadHeader() { |
|
164 SkASSERT(!fInfoInitialized && !fDecompressStarted); |
|
165 initialize_info(&fCInfo, &fSrcMgr); |
|
166 fInfoInitialized = true; |
|
167 const bool success = (JPEG_HEADER_OK == jpeg_read_header(&fCInfo, true)); |
|
168 SkDEBUGCODE(fReadHeaderSucceeded = success;) |
|
169 return success; |
|
170 } |
|
171 |
|
172 jpeg_decompress_struct* cinfo() { return &fCInfo; } |
|
173 |
|
174 huffman_index* huffmanIndex() { return &fHuffmanIndex; } |
|
175 |
|
176 /** |
|
177 * Build the index to be used for tile based decoding. |
|
178 * Must only be called after a successful call to |
|
179 * initializeInfoAndReadHeader and must not be called more |
|
180 * than once. |
|
181 */ |
|
182 bool buildHuffmanIndex() { |
|
183 SkASSERT(fReadHeaderSucceeded); |
|
184 SkASSERT(!fHuffmanCreated); |
|
185 jpeg_create_huffman_index(&fCInfo, &fHuffmanIndex); |
|
186 SkASSERT(1 == fCInfo.scale_num && 1 == fCInfo.scale_denom); |
|
187 fHuffmanCreated = jpeg_build_huffman_index(&fCInfo, &fHuffmanIndex); |
|
188 return fHuffmanCreated; |
|
189 } |
|
190 |
|
191 /** |
|
192 * Start tile based decoding. Must only be called after a |
|
193 * successful call to buildHuffmanIndex, and must only be |
|
194 * called once. |
|
195 */ |
|
196 bool startTileDecompress() { |
|
197 SkASSERT(fHuffmanCreated); |
|
198 SkASSERT(fReadHeaderSucceeded); |
|
199 SkASSERT(!fDecompressStarted); |
|
200 if (jpeg_start_tile_decompress(&fCInfo)) { |
|
201 fDecompressStarted = true; |
|
202 return true; |
|
203 } |
|
204 return false; |
|
205 } |
|
206 |
|
207 private: |
|
208 skjpeg_source_mgr fSrcMgr; |
|
209 jpeg_decompress_struct fCInfo; |
|
210 huffman_index fHuffmanIndex; |
|
211 bool fInfoInitialized; |
|
212 bool fHuffmanCreated; |
|
213 bool fDecompressStarted; |
|
214 SkDEBUGCODE(bool fReadHeaderSucceeded;) |
|
215 }; |
|
216 #endif |
|
217 |
|
218 class SkJPEGImageDecoder : public SkImageDecoder { |
|
219 public: |
|
220 #ifdef SK_BUILD_FOR_ANDROID |
|
221 SkJPEGImageDecoder() { |
|
222 fImageIndex = NULL; |
|
223 fImageWidth = 0; |
|
224 fImageHeight = 0; |
|
225 } |
|
226 |
|
227 virtual ~SkJPEGImageDecoder() { |
|
228 SkDELETE(fImageIndex); |
|
229 } |
|
230 #endif |
|
231 |
|
232 virtual Format getFormat() const { |
|
233 return kJPEG_Format; |
|
234 } |
|
235 |
|
236 protected: |
|
237 #ifdef SK_BUILD_FOR_ANDROID |
|
238 virtual bool onBuildTileIndex(SkStreamRewindable *stream, int *width, int *height) SK_OVERRIDE; |
|
239 virtual bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& rect) SK_OVERRIDE; |
|
240 #endif |
|
241 virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE; |
|
242 |
|
243 private: |
|
244 #ifdef SK_BUILD_FOR_ANDROID |
|
245 SkJPEGImageIndex* fImageIndex; |
|
246 int fImageWidth; |
|
247 int fImageHeight; |
|
248 #endif |
|
249 |
|
250 /** |
|
251 * Determine the appropriate bitmap config and out_color_space based on |
|
252 * both the preference of the caller and the jpeg_color_space on the |
|
253 * jpeg_decompress_struct passed in. |
|
254 * Must be called after jpeg_read_header. |
|
255 */ |
|
256 SkBitmap::Config getBitmapConfig(jpeg_decompress_struct*); |
|
257 |
|
258 typedef SkImageDecoder INHERITED; |
|
259 }; |
|
260 |
|
261 ////////////////////////////////////////////////////////////////////////// |
|
262 |
|
263 /* Automatically clean up after throwing an exception */ |
|
264 class JPEGAutoClean { |
|
265 public: |
|
266 JPEGAutoClean(): cinfo_ptr(NULL) {} |
|
267 ~JPEGAutoClean() { |
|
268 if (cinfo_ptr) { |
|
269 jpeg_destroy_decompress(cinfo_ptr); |
|
270 } |
|
271 } |
|
272 void set(jpeg_decompress_struct* info) { |
|
273 cinfo_ptr = info; |
|
274 } |
|
275 private: |
|
276 jpeg_decompress_struct* cinfo_ptr; |
|
277 }; |
|
278 |
|
279 /////////////////////////////////////////////////////////////////////////////// |
|
280 |
|
281 /* If we need to better match the request, we might examine the image and |
|
282 output dimensions, and determine if the downsampling jpeg provided is |
|
283 not sufficient. If so, we can recompute a modified sampleSize value to |
|
284 make up the difference. |
|
285 |
|
286 To skip this additional scaling, just set sampleSize = 1; below. |
|
287 */ |
|
288 static int recompute_sampleSize(int sampleSize, |
|
289 const jpeg_decompress_struct& cinfo) { |
|
290 return sampleSize * cinfo.output_width / cinfo.image_width; |
|
291 } |
|
292 |
|
293 static bool valid_output_dimensions(const jpeg_decompress_struct& cinfo) { |
|
294 /* These are initialized to 0, so if they have non-zero values, we assume |
|
295 they are "valid" (i.e. have been computed by libjpeg) |
|
296 */ |
|
297 return 0 != cinfo.output_width && 0 != cinfo.output_height; |
|
298 } |
|
299 |
|
300 static bool skip_src_rows(jpeg_decompress_struct* cinfo, void* buffer, int count) { |
|
301 for (int i = 0; i < count; i++) { |
|
302 JSAMPLE* rowptr = (JSAMPLE*)buffer; |
|
303 int row_count = jpeg_read_scanlines(cinfo, &rowptr, 1); |
|
304 if (1 != row_count) { |
|
305 return false; |
|
306 } |
|
307 } |
|
308 return true; |
|
309 } |
|
310 |
|
311 #ifdef SK_BUILD_FOR_ANDROID |
|
312 static bool skip_src_rows_tile(jpeg_decompress_struct* cinfo, |
|
313 huffman_index *index, void* buffer, int count) { |
|
314 for (int i = 0; i < count; i++) { |
|
315 JSAMPLE* rowptr = (JSAMPLE*)buffer; |
|
316 int row_count = jpeg_read_tile_scanline(cinfo, index, &rowptr); |
|
317 if (1 != row_count) { |
|
318 return false; |
|
319 } |
|
320 } |
|
321 return true; |
|
322 } |
|
323 #endif |
|
324 |
|
325 // This guy exists just to aid in debugging, as it allows debuggers to just |
|
326 // set a break-point in one place to see all error exists. |
|
327 static bool return_false(const jpeg_decompress_struct& cinfo, |
|
328 const SkBitmap& bm, const char caller[]) { |
|
329 if (!(c_suppressJPEGImageDecoderErrors)) { |
|
330 char buffer[JMSG_LENGTH_MAX]; |
|
331 cinfo.err->format_message((const j_common_ptr)&cinfo, buffer); |
|
332 SkDebugf("libjpeg error %d <%s> from %s [%d %d]\n", |
|
333 cinfo.err->msg_code, buffer, caller, bm.width(), bm.height()); |
|
334 } |
|
335 return false; // must always return false |
|
336 } |
|
337 |
|
338 // Convert a scanline of CMYK samples to RGBX in place. Note that this |
|
339 // method moves the "scanline" pointer in its processing |
|
340 static void convert_CMYK_to_RGB(uint8_t* scanline, unsigned int width) { |
|
341 // At this point we've received CMYK pixels from libjpeg. We |
|
342 // perform a crude conversion to RGB (based on the formulae |
|
343 // from easyrgb.com): |
|
344 // CMYK -> CMY |
|
345 // C = ( C * (1 - K) + K ) // for each CMY component |
|
346 // CMY -> RGB |
|
347 // R = ( 1 - C ) * 255 // for each RGB component |
|
348 // Unfortunately we are seeing inverted CMYK so all the original terms |
|
349 // are 1-. This yields: |
|
350 // CMYK -> CMY |
|
351 // C = ( (1-C) * (1 - (1-K) + (1-K) ) -> C = 1 - C*K |
|
352 // The conversion from CMY->RGB remains the same |
|
353 for (unsigned int x = 0; x < width; ++x, scanline += 4) { |
|
354 scanline[0] = SkMulDiv255Round(scanline[0], scanline[3]); |
|
355 scanline[1] = SkMulDiv255Round(scanline[1], scanline[3]); |
|
356 scanline[2] = SkMulDiv255Round(scanline[2], scanline[3]); |
|
357 scanline[3] = 255; |
|
358 } |
|
359 } |
|
360 |
|
361 /** |
|
362 * Common code for setting the error manager. |
|
363 */ |
|
364 static void set_error_mgr(jpeg_decompress_struct* cinfo, skjpeg_error_mgr* errorManager) { |
|
365 SkASSERT(cinfo != NULL); |
|
366 SkASSERT(errorManager != NULL); |
|
367 cinfo->err = jpeg_std_error(errorManager); |
|
368 errorManager->error_exit = skjpeg_error_exit; |
|
369 } |
|
370 |
|
371 /** |
|
372 * Common code for turning off upsampling and smoothing. Turning these |
|
373 * off helps performance without showing noticable differences in the |
|
374 * resulting bitmap. |
|
375 */ |
|
376 static void turn_off_visual_optimizations(jpeg_decompress_struct* cinfo) { |
|
377 SkASSERT(cinfo != NULL); |
|
378 /* this gives about 30% performance improvement. In theory it may |
|
379 reduce the visual quality, in practice I'm not seeing a difference |
|
380 */ |
|
381 cinfo->do_fancy_upsampling = 0; |
|
382 |
|
383 /* this gives another few percents */ |
|
384 cinfo->do_block_smoothing = 0; |
|
385 } |
|
386 |
|
387 /** |
|
388 * Common code for setting the dct method. |
|
389 */ |
|
390 static void set_dct_method(const SkImageDecoder& decoder, jpeg_decompress_struct* cinfo) { |
|
391 SkASSERT(cinfo != NULL); |
|
392 #ifdef DCT_IFAST_SUPPORTED |
|
393 if (decoder.getPreferQualityOverSpeed()) { |
|
394 cinfo->dct_method = JDCT_ISLOW; |
|
395 } else { |
|
396 cinfo->dct_method = JDCT_IFAST; |
|
397 } |
|
398 #else |
|
399 cinfo->dct_method = JDCT_ISLOW; |
|
400 #endif |
|
401 } |
|
402 |
|
403 SkBitmap::Config SkJPEGImageDecoder::getBitmapConfig(jpeg_decompress_struct* cinfo) { |
|
404 SkASSERT(cinfo != NULL); |
|
405 |
|
406 SrcDepth srcDepth = k32Bit_SrcDepth; |
|
407 if (JCS_GRAYSCALE == cinfo->jpeg_color_space) { |
|
408 srcDepth = k8BitGray_SrcDepth; |
|
409 } |
|
410 |
|
411 SkBitmap::Config config = this->getPrefConfig(srcDepth, /*hasAlpha*/ false); |
|
412 switch (config) { |
|
413 case SkBitmap::kA8_Config: |
|
414 // Only respect A8 config if the original is grayscale, |
|
415 // in which case we will treat the grayscale as alpha |
|
416 // values. |
|
417 if (cinfo->jpeg_color_space != JCS_GRAYSCALE) { |
|
418 config = SkBitmap::kARGB_8888_Config; |
|
419 } |
|
420 break; |
|
421 case SkBitmap::kARGB_8888_Config: |
|
422 // Fall through. |
|
423 case SkBitmap::kARGB_4444_Config: |
|
424 // Fall through. |
|
425 case SkBitmap::kRGB_565_Config: |
|
426 // These are acceptable destination configs. |
|
427 break; |
|
428 default: |
|
429 // Force all other configs to 8888. |
|
430 config = SkBitmap::kARGB_8888_Config; |
|
431 break; |
|
432 } |
|
433 |
|
434 switch (cinfo->jpeg_color_space) { |
|
435 case JCS_CMYK: |
|
436 // Fall through. |
|
437 case JCS_YCCK: |
|
438 // libjpeg cannot convert from CMYK or YCCK to RGB - here we set up |
|
439 // so libjpeg will give us CMYK samples back and we will later |
|
440 // manually convert them to RGB |
|
441 cinfo->out_color_space = JCS_CMYK; |
|
442 break; |
|
443 case JCS_GRAYSCALE: |
|
444 if (SkBitmap::kA8_Config == config) { |
|
445 cinfo->out_color_space = JCS_GRAYSCALE; |
|
446 break; |
|
447 } |
|
448 // The data is JCS_GRAYSCALE, but the caller wants some sort of RGB |
|
449 // config. Fall through to set to the default. |
|
450 default: |
|
451 cinfo->out_color_space = JCS_RGB; |
|
452 break; |
|
453 } |
|
454 return config; |
|
455 } |
|
456 |
|
457 #ifdef ANDROID_RGB |
|
458 /** |
|
459 * Based on the config and dither mode, adjust out_color_space and |
|
460 * dither_mode of cinfo. |
|
461 */ |
|
462 static void adjust_out_color_space_and_dither(jpeg_decompress_struct* cinfo, |
|
463 SkBitmap::Config config, |
|
464 const SkImageDecoder& decoder) { |
|
465 SkASSERT(cinfo != NULL); |
|
466 cinfo->dither_mode = JDITHER_NONE; |
|
467 if (JCS_CMYK == cinfo->out_color_space) { |
|
468 return; |
|
469 } |
|
470 switch(config) { |
|
471 case SkBitmap::kARGB_8888_Config: |
|
472 cinfo->out_color_space = JCS_RGBA_8888; |
|
473 break; |
|
474 case SkBitmap::kRGB_565_Config: |
|
475 cinfo->out_color_space = JCS_RGB_565; |
|
476 if (decoder.getDitherImage()) { |
|
477 cinfo->dither_mode = JDITHER_ORDERED; |
|
478 } |
|
479 break; |
|
480 default: |
|
481 break; |
|
482 } |
|
483 } |
|
484 #endif |
|
485 |
|
486 |
|
487 /** |
|
488 Sets all pixels in given bitmap to SK_ColorWHITE for all rows >= y. |
|
489 Used when decoding fails partway through reading scanlines to fill |
|
490 remaining lines. */ |
|
491 static void fill_below_level(int y, SkBitmap* bitmap) { |
|
492 SkIRect rect = SkIRect::MakeLTRB(0, y, bitmap->width(), bitmap->height()); |
|
493 SkCanvas canvas(*bitmap); |
|
494 canvas.clipRect(SkRect::Make(rect)); |
|
495 canvas.drawColor(SK_ColorWHITE); |
|
496 } |
|
497 |
|
498 /** |
|
499 * Get the config and bytes per pixel of the source data. Return |
|
500 * whether the data is supported. |
|
501 */ |
|
502 static bool get_src_config(const jpeg_decompress_struct& cinfo, |
|
503 SkScaledBitmapSampler::SrcConfig* sc, |
|
504 int* srcBytesPerPixel) { |
|
505 SkASSERT(sc != NULL && srcBytesPerPixel != NULL); |
|
506 if (JCS_CMYK == cinfo.out_color_space) { |
|
507 // In this case we will manually convert the CMYK values to RGB |
|
508 *sc = SkScaledBitmapSampler::kRGBX; |
|
509 // The CMYK work-around relies on 4 components per pixel here |
|
510 *srcBytesPerPixel = 4; |
|
511 } else if (3 == cinfo.out_color_components && JCS_RGB == cinfo.out_color_space) { |
|
512 *sc = SkScaledBitmapSampler::kRGB; |
|
513 *srcBytesPerPixel = 3; |
|
514 #ifdef ANDROID_RGB |
|
515 } else if (JCS_RGBA_8888 == cinfo.out_color_space) { |
|
516 *sc = SkScaledBitmapSampler::kRGBX; |
|
517 *srcBytesPerPixel = 4; |
|
518 } else if (JCS_RGB_565 == cinfo.out_color_space) { |
|
519 *sc = SkScaledBitmapSampler::kRGB_565; |
|
520 *srcBytesPerPixel = 2; |
|
521 #endif |
|
522 } else if (1 == cinfo.out_color_components && |
|
523 JCS_GRAYSCALE == cinfo.out_color_space) { |
|
524 *sc = SkScaledBitmapSampler::kGray; |
|
525 *srcBytesPerPixel = 1; |
|
526 } else { |
|
527 return false; |
|
528 } |
|
529 return true; |
|
530 } |
|
531 |
|
532 bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { |
|
533 #ifdef TIME_DECODE |
|
534 SkAutoTime atm("JPEG Decode"); |
|
535 #endif |
|
536 |
|
537 JPEGAutoClean autoClean; |
|
538 |
|
539 jpeg_decompress_struct cinfo; |
|
540 skjpeg_source_mgr srcManager(stream, this); |
|
541 |
|
542 skjpeg_error_mgr errorManager; |
|
543 set_error_mgr(&cinfo, &errorManager); |
|
544 |
|
545 // All objects need to be instantiated before this setjmp call so that |
|
546 // they will be cleaned up properly if an error occurs. |
|
547 if (setjmp(errorManager.fJmpBuf)) { |
|
548 return return_false(cinfo, *bm, "setjmp"); |
|
549 } |
|
550 |
|
551 initialize_info(&cinfo, &srcManager); |
|
552 autoClean.set(&cinfo); |
|
553 |
|
554 int status = jpeg_read_header(&cinfo, true); |
|
555 if (status != JPEG_HEADER_OK) { |
|
556 return return_false(cinfo, *bm, "read_header"); |
|
557 } |
|
558 |
|
559 /* Try to fulfill the requested sampleSize. Since jpeg can do it (when it |
|
560 can) much faster that we, just use their num/denom api to approximate |
|
561 the size. |
|
562 */ |
|
563 int sampleSize = this->getSampleSize(); |
|
564 |
|
565 set_dct_method(*this, &cinfo); |
|
566 |
|
567 SkASSERT(1 == cinfo.scale_num); |
|
568 cinfo.scale_denom = sampleSize; |
|
569 |
|
570 turn_off_visual_optimizations(&cinfo); |
|
571 |
|
572 const SkBitmap::Config config = this->getBitmapConfig(&cinfo); |
|
573 |
|
574 #ifdef ANDROID_RGB |
|
575 adjust_out_color_space_and_dither(&cinfo, config, *this); |
|
576 #endif |
|
577 |
|
578 if (1 == sampleSize && SkImageDecoder::kDecodeBounds_Mode == mode) { |
|
579 // Assume an A8 bitmap is not opaque to avoid the check of each |
|
580 // individual pixel. It is very unlikely to be opaque, since |
|
581 // an opaque A8 bitmap would not be very interesting. |
|
582 // Otherwise, a jpeg image is opaque. |
|
583 return bm->setConfig(config, cinfo.image_width, cinfo.image_height, 0, |
|
584 SkBitmap::kA8_Config == config ? |
|
585 kPremul_SkAlphaType : kOpaque_SkAlphaType); |
|
586 } |
|
587 |
|
588 /* image_width and image_height are the original dimensions, available |
|
589 after jpeg_read_header(). To see the scaled dimensions, we have to call |
|
590 jpeg_start_decompress(), and then read output_width and output_height. |
|
591 */ |
|
592 if (!jpeg_start_decompress(&cinfo)) { |
|
593 /* If we failed here, we may still have enough information to return |
|
594 to the caller if they just wanted (subsampled bounds). If sampleSize |
|
595 was 1, then we would have already returned. Thus we just check if |
|
596 we're in kDecodeBounds_Mode, and that we have valid output sizes. |
|
597 |
|
598 One reason to fail here is that we have insufficient stream data |
|
599 to complete the setup. However, output dimensions seem to get |
|
600 computed very early, which is why this special check can pay off. |
|
601 */ |
|
602 if (SkImageDecoder::kDecodeBounds_Mode == mode && valid_output_dimensions(cinfo)) { |
|
603 SkScaledBitmapSampler smpl(cinfo.output_width, cinfo.output_height, |
|
604 recompute_sampleSize(sampleSize, cinfo)); |
|
605 // Assume an A8 bitmap is not opaque to avoid the check of each |
|
606 // individual pixel. It is very unlikely to be opaque, since |
|
607 // an opaque A8 bitmap would not be very interesting. |
|
608 // Otherwise, a jpeg image is opaque. |
|
609 return bm->setConfig(config, smpl.scaledWidth(), smpl.scaledHeight(), |
|
610 0, SkBitmap::kA8_Config == config ? |
|
611 kPremul_SkAlphaType : kOpaque_SkAlphaType); |
|
612 } else { |
|
613 return return_false(cinfo, *bm, "start_decompress"); |
|
614 } |
|
615 } |
|
616 sampleSize = recompute_sampleSize(sampleSize, cinfo); |
|
617 |
|
618 // should we allow the Chooser (if present) to pick a config for us??? |
|
619 if (!this->chooseFromOneChoice(config, cinfo.output_width, cinfo.output_height)) { |
|
620 return return_false(cinfo, *bm, "chooseFromOneChoice"); |
|
621 } |
|
622 |
|
623 SkScaledBitmapSampler sampler(cinfo.output_width, cinfo.output_height, sampleSize); |
|
624 // Assume an A8 bitmap is not opaque to avoid the check of each |
|
625 // individual pixel. It is very unlikely to be opaque, since |
|
626 // an opaque A8 bitmap would not be very interesting. |
|
627 // Otherwise, a jpeg image is opaque. |
|
628 bm->setConfig(config, sampler.scaledWidth(), sampler.scaledHeight(), 0, |
|
629 SkBitmap::kA8_Config != config ? kOpaque_SkAlphaType : kPremul_SkAlphaType); |
|
630 if (SkImageDecoder::kDecodeBounds_Mode == mode) { |
|
631 return true; |
|
632 } |
|
633 if (!this->allocPixelRef(bm, NULL)) { |
|
634 return return_false(cinfo, *bm, "allocPixelRef"); |
|
635 } |
|
636 |
|
637 SkAutoLockPixels alp(*bm); |
|
638 |
|
639 #ifdef ANDROID_RGB |
|
640 /* short-circuit the SkScaledBitmapSampler when possible, as this gives |
|
641 a significant performance boost. |
|
642 */ |
|
643 if (sampleSize == 1 && |
|
644 ((config == SkBitmap::kARGB_8888_Config && |
|
645 cinfo.out_color_space == JCS_RGBA_8888) || |
|
646 (config == SkBitmap::kRGB_565_Config && |
|
647 cinfo.out_color_space == JCS_RGB_565))) |
|
648 { |
|
649 JSAMPLE* rowptr = (JSAMPLE*)bm->getPixels(); |
|
650 INT32 const bpr = bm->rowBytes(); |
|
651 |
|
652 while (cinfo.output_scanline < cinfo.output_height) { |
|
653 int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1); |
|
654 if (0 == row_count) { |
|
655 // if row_count == 0, then we didn't get a scanline, |
|
656 // so return early. We will return a partial image. |
|
657 fill_below_level(cinfo.output_scanline, bm); |
|
658 cinfo.output_scanline = cinfo.output_height; |
|
659 break; // Skip to jpeg_finish_decompress() |
|
660 } |
|
661 if (this->shouldCancelDecode()) { |
|
662 return return_false(cinfo, *bm, "shouldCancelDecode"); |
|
663 } |
|
664 rowptr += bpr; |
|
665 } |
|
666 jpeg_finish_decompress(&cinfo); |
|
667 return true; |
|
668 } |
|
669 #endif |
|
670 |
|
671 // check for supported formats |
|
672 SkScaledBitmapSampler::SrcConfig sc; |
|
673 int srcBytesPerPixel; |
|
674 |
|
675 if (!get_src_config(cinfo, &sc, &srcBytesPerPixel)) { |
|
676 return return_false(cinfo, *bm, "jpeg colorspace"); |
|
677 } |
|
678 |
|
679 if (!sampler.begin(bm, sc, *this)) { |
|
680 return return_false(cinfo, *bm, "sampler.begin"); |
|
681 } |
|
682 |
|
683 SkAutoMalloc srcStorage(cinfo.output_width * srcBytesPerPixel); |
|
684 uint8_t* srcRow = (uint8_t*)srcStorage.get(); |
|
685 |
|
686 // Possibly skip initial rows [sampler.srcY0] |
|
687 if (!skip_src_rows(&cinfo, srcRow, sampler.srcY0())) { |
|
688 return return_false(cinfo, *bm, "skip rows"); |
|
689 } |
|
690 |
|
691 // now loop through scanlines until y == bm->height() - 1 |
|
692 for (int y = 0;; y++) { |
|
693 JSAMPLE* rowptr = (JSAMPLE*)srcRow; |
|
694 int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1); |
|
695 if (0 == row_count) { |
|
696 // if row_count == 0, then we didn't get a scanline, |
|
697 // so return early. We will return a partial image. |
|
698 fill_below_level(y, bm); |
|
699 cinfo.output_scanline = cinfo.output_height; |
|
700 break; // Skip to jpeg_finish_decompress() |
|
701 } |
|
702 if (this->shouldCancelDecode()) { |
|
703 return return_false(cinfo, *bm, "shouldCancelDecode"); |
|
704 } |
|
705 |
|
706 if (JCS_CMYK == cinfo.out_color_space) { |
|
707 convert_CMYK_to_RGB(srcRow, cinfo.output_width); |
|
708 } |
|
709 |
|
710 sampler.next(srcRow); |
|
711 if (bm->height() - 1 == y) { |
|
712 // we're done |
|
713 break; |
|
714 } |
|
715 |
|
716 if (!skip_src_rows(&cinfo, srcRow, sampler.srcDY() - 1)) { |
|
717 return return_false(cinfo, *bm, "skip rows"); |
|
718 } |
|
719 } |
|
720 |
|
721 // we formally skip the rest, so we don't get a complaint from libjpeg |
|
722 if (!skip_src_rows(&cinfo, srcRow, |
|
723 cinfo.output_height - cinfo.output_scanline)) { |
|
724 return return_false(cinfo, *bm, "skip rows"); |
|
725 } |
|
726 jpeg_finish_decompress(&cinfo); |
|
727 |
|
728 return true; |
|
729 } |
|
730 |
|
731 #ifdef SK_BUILD_FOR_ANDROID |
|
732 bool SkJPEGImageDecoder::onBuildTileIndex(SkStreamRewindable* stream, int *width, int *height) { |
|
733 |
|
734 SkAutoTDelete<SkJPEGImageIndex> imageIndex(SkNEW_ARGS(SkJPEGImageIndex, (stream, this))); |
|
735 jpeg_decompress_struct* cinfo = imageIndex->cinfo(); |
|
736 |
|
737 skjpeg_error_mgr sk_err; |
|
738 set_error_mgr(cinfo, &sk_err); |
|
739 |
|
740 // All objects need to be instantiated before this setjmp call so that |
|
741 // they will be cleaned up properly if an error occurs. |
|
742 if (setjmp(sk_err.fJmpBuf)) { |
|
743 return false; |
|
744 } |
|
745 |
|
746 // create the cinfo used to create/build the huffmanIndex |
|
747 if (!imageIndex->initializeInfoAndReadHeader()) { |
|
748 return false; |
|
749 } |
|
750 |
|
751 if (!imageIndex->buildHuffmanIndex()) { |
|
752 return false; |
|
753 } |
|
754 |
|
755 // destroy the cinfo used to create/build the huffman index |
|
756 imageIndex->destroyInfo(); |
|
757 |
|
758 // Init decoder to image decode mode |
|
759 if (!imageIndex->initializeInfoAndReadHeader()) { |
|
760 return false; |
|
761 } |
|
762 |
|
763 // FIXME: This sets cinfo->out_color_space, which we may change later |
|
764 // based on the config in onDecodeSubset. This should be fine, since |
|
765 // jpeg_init_read_tile_scanline will check out_color_space again after |
|
766 // that change (when it calls jinit_color_deconverter). |
|
767 (void) this->getBitmapConfig(cinfo); |
|
768 |
|
769 turn_off_visual_optimizations(cinfo); |
|
770 |
|
771 // instead of jpeg_start_decompress() we start a tiled decompress |
|
772 if (!imageIndex->startTileDecompress()) { |
|
773 return false; |
|
774 } |
|
775 |
|
776 SkASSERT(1 == cinfo->scale_num); |
|
777 fImageWidth = cinfo->output_width; |
|
778 fImageHeight = cinfo->output_height; |
|
779 |
|
780 if (width) { |
|
781 *width = fImageWidth; |
|
782 } |
|
783 if (height) { |
|
784 *height = fImageHeight; |
|
785 } |
|
786 |
|
787 SkDELETE(fImageIndex); |
|
788 fImageIndex = imageIndex.detach(); |
|
789 |
|
790 return true; |
|
791 } |
|
792 |
|
793 bool SkJPEGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) { |
|
794 if (NULL == fImageIndex) { |
|
795 return false; |
|
796 } |
|
797 jpeg_decompress_struct* cinfo = fImageIndex->cinfo(); |
|
798 |
|
799 SkIRect rect = SkIRect::MakeWH(fImageWidth, fImageHeight); |
|
800 if (!rect.intersect(region)) { |
|
801 // If the requested region is entirely outside the image return false |
|
802 return false; |
|
803 } |
|
804 |
|
805 |
|
806 skjpeg_error_mgr errorManager; |
|
807 set_error_mgr(cinfo, &errorManager); |
|
808 |
|
809 if (setjmp(errorManager.fJmpBuf)) { |
|
810 return false; |
|
811 } |
|
812 |
|
813 int requestedSampleSize = this->getSampleSize(); |
|
814 cinfo->scale_denom = requestedSampleSize; |
|
815 |
|
816 set_dct_method(*this, cinfo); |
|
817 |
|
818 const SkBitmap::Config config = this->getBitmapConfig(cinfo); |
|
819 #ifdef ANDROID_RGB |
|
820 adjust_out_color_space_and_dither(cinfo, config, *this); |
|
821 #endif |
|
822 |
|
823 int startX = rect.fLeft; |
|
824 int startY = rect.fTop; |
|
825 int width = rect.width(); |
|
826 int height = rect.height(); |
|
827 |
|
828 jpeg_init_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(), |
|
829 &startX, &startY, &width, &height); |
|
830 int skiaSampleSize = recompute_sampleSize(requestedSampleSize, *cinfo); |
|
831 int actualSampleSize = skiaSampleSize * (DCTSIZE / cinfo->min_DCT_scaled_size); |
|
832 |
|
833 SkScaledBitmapSampler sampler(width, height, skiaSampleSize); |
|
834 |
|
835 SkBitmap bitmap; |
|
836 bitmap.setConfig(config, sampler.scaledWidth(), sampler.scaledHeight()); |
|
837 // Assume an A8 bitmap is not opaque to avoid the check of each |
|
838 // individual pixel. It is very unlikely to be opaque, since |
|
839 // an opaque A8 bitmap would not be very interesting. |
|
840 // Otherwise, a jpeg image is opaque. |
|
841 bitmap.setConfig(config, sampler.scaledWidth(), sampler.scaledHeight(), 0, |
|
842 config == SkBitmap::kA8_Config ? kPremul_SkAlphaType : |
|
843 kOpaque_SkAlphaType); |
|
844 |
|
845 // Check ahead of time if the swap(dest, src) is possible or not. |
|
846 // If yes, then we will stick to AllocPixelRef since it's cheaper with the |
|
847 // swap happening. If no, then we will use alloc to allocate pixels to |
|
848 // prevent garbage collection. |
|
849 int w = rect.width() / actualSampleSize; |
|
850 int h = rect.height() / actualSampleSize; |
|
851 bool swapOnly = (rect == region) && bm->isNull() && |
|
852 (w == bitmap.width()) && (h == bitmap.height()) && |
|
853 ((startX - rect.x()) / actualSampleSize == 0) && |
|
854 ((startY - rect.y()) / actualSampleSize == 0); |
|
855 if (swapOnly) { |
|
856 if (!this->allocPixelRef(&bitmap, NULL)) { |
|
857 return return_false(*cinfo, bitmap, "allocPixelRef"); |
|
858 } |
|
859 } else { |
|
860 if (!bitmap.allocPixels()) { |
|
861 return return_false(*cinfo, bitmap, "allocPixels"); |
|
862 } |
|
863 } |
|
864 |
|
865 SkAutoLockPixels alp(bitmap); |
|
866 |
|
867 #ifdef ANDROID_RGB |
|
868 /* short-circuit the SkScaledBitmapSampler when possible, as this gives |
|
869 a significant performance boost. |
|
870 */ |
|
871 if (skiaSampleSize == 1 && |
|
872 ((config == SkBitmap::kARGB_8888_Config && |
|
873 cinfo->out_color_space == JCS_RGBA_8888) || |
|
874 (config == SkBitmap::kRGB_565_Config && |
|
875 cinfo->out_color_space == JCS_RGB_565))) |
|
876 { |
|
877 JSAMPLE* rowptr = (JSAMPLE*)bitmap.getPixels(); |
|
878 INT32 const bpr = bitmap.rowBytes(); |
|
879 int rowTotalCount = 0; |
|
880 |
|
881 while (rowTotalCount < height) { |
|
882 int rowCount = jpeg_read_tile_scanline(cinfo, |
|
883 fImageIndex->huffmanIndex(), |
|
884 &rowptr); |
|
885 // if rowCount == 0, then we didn't get a scanline, so abort. |
|
886 // onDecodeSubset() relies on onBuildTileIndex(), which |
|
887 // needs a complete image to succeed. |
|
888 if (0 == rowCount) { |
|
889 return return_false(*cinfo, bitmap, "read_scanlines"); |
|
890 } |
|
891 if (this->shouldCancelDecode()) { |
|
892 return return_false(*cinfo, bitmap, "shouldCancelDecode"); |
|
893 } |
|
894 rowTotalCount += rowCount; |
|
895 rowptr += bpr; |
|
896 } |
|
897 |
|
898 if (swapOnly) { |
|
899 bm->swap(bitmap); |
|
900 } else { |
|
901 cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(), |
|
902 region.width(), region.height(), startX, startY); |
|
903 } |
|
904 return true; |
|
905 } |
|
906 #endif |
|
907 |
|
908 // check for supported formats |
|
909 SkScaledBitmapSampler::SrcConfig sc; |
|
910 int srcBytesPerPixel; |
|
911 |
|
912 if (!get_src_config(*cinfo, &sc, &srcBytesPerPixel)) { |
|
913 return return_false(*cinfo, *bm, "jpeg colorspace"); |
|
914 } |
|
915 |
|
916 if (!sampler.begin(&bitmap, sc, *this)) { |
|
917 return return_false(*cinfo, bitmap, "sampler.begin"); |
|
918 } |
|
919 |
|
920 SkAutoMalloc srcStorage(width * srcBytesPerPixel); |
|
921 uint8_t* srcRow = (uint8_t*)srcStorage.get(); |
|
922 |
|
923 // Possibly skip initial rows [sampler.srcY0] |
|
924 if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow, sampler.srcY0())) { |
|
925 return return_false(*cinfo, bitmap, "skip rows"); |
|
926 } |
|
927 |
|
928 // now loop through scanlines until y == bitmap->height() - 1 |
|
929 for (int y = 0;; y++) { |
|
930 JSAMPLE* rowptr = (JSAMPLE*)srcRow; |
|
931 int row_count = jpeg_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(), &rowptr); |
|
932 // if row_count == 0, then we didn't get a scanline, so abort. |
|
933 // onDecodeSubset() relies on onBuildTileIndex(), which |
|
934 // needs a complete image to succeed. |
|
935 if (0 == row_count) { |
|
936 return return_false(*cinfo, bitmap, "read_scanlines"); |
|
937 } |
|
938 if (this->shouldCancelDecode()) { |
|
939 return return_false(*cinfo, bitmap, "shouldCancelDecode"); |
|
940 } |
|
941 |
|
942 if (JCS_CMYK == cinfo->out_color_space) { |
|
943 convert_CMYK_to_RGB(srcRow, width); |
|
944 } |
|
945 |
|
946 sampler.next(srcRow); |
|
947 if (bitmap.height() - 1 == y) { |
|
948 // we're done |
|
949 break; |
|
950 } |
|
951 |
|
952 if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow, |
|
953 sampler.srcDY() - 1)) { |
|
954 return return_false(*cinfo, bitmap, "skip rows"); |
|
955 } |
|
956 } |
|
957 if (swapOnly) { |
|
958 bm->swap(bitmap); |
|
959 } else { |
|
960 cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(), |
|
961 region.width(), region.height(), startX, startY); |
|
962 } |
|
963 return true; |
|
964 } |
|
965 #endif |
|
966 |
|
967 /////////////////////////////////////////////////////////////////////////////// |
|
968 |
|
969 #include "SkColorPriv.h" |
|
970 |
|
971 // taken from jcolor.c in libjpeg |
|
972 #if 0 // 16bit - precise but slow |
|
973 #define CYR 19595 // 0.299 |
|
974 #define CYG 38470 // 0.587 |
|
975 #define CYB 7471 // 0.114 |
|
976 |
|
977 #define CUR -11059 // -0.16874 |
|
978 #define CUG -21709 // -0.33126 |
|
979 #define CUB 32768 // 0.5 |
|
980 |
|
981 #define CVR 32768 // 0.5 |
|
982 #define CVG -27439 // -0.41869 |
|
983 #define CVB -5329 // -0.08131 |
|
984 |
|
985 #define CSHIFT 16 |
|
986 #else // 8bit - fast, slightly less precise |
|
987 #define CYR 77 // 0.299 |
|
988 #define CYG 150 // 0.587 |
|
989 #define CYB 29 // 0.114 |
|
990 |
|
991 #define CUR -43 // -0.16874 |
|
992 #define CUG -85 // -0.33126 |
|
993 #define CUB 128 // 0.5 |
|
994 |
|
995 #define CVR 128 // 0.5 |
|
996 #define CVG -107 // -0.41869 |
|
997 #define CVB -21 // -0.08131 |
|
998 |
|
999 #define CSHIFT 8 |
|
1000 #endif |
|
1001 |
|
1002 static void rgb2yuv_32(uint8_t dst[], SkPMColor c) { |
|
1003 int r = SkGetPackedR32(c); |
|
1004 int g = SkGetPackedG32(c); |
|
1005 int b = SkGetPackedB32(c); |
|
1006 |
|
1007 int y = ( CYR*r + CYG*g + CYB*b ) >> CSHIFT; |
|
1008 int u = ( CUR*r + CUG*g + CUB*b ) >> CSHIFT; |
|
1009 int v = ( CVR*r + CVG*g + CVB*b ) >> CSHIFT; |
|
1010 |
|
1011 dst[0] = SkToU8(y); |
|
1012 dst[1] = SkToU8(u + 128); |
|
1013 dst[2] = SkToU8(v + 128); |
|
1014 } |
|
1015 |
|
1016 static void rgb2yuv_4444(uint8_t dst[], U16CPU c) { |
|
1017 int r = SkGetPackedR4444(c); |
|
1018 int g = SkGetPackedG4444(c); |
|
1019 int b = SkGetPackedB4444(c); |
|
1020 |
|
1021 int y = ( CYR*r + CYG*g + CYB*b ) >> (CSHIFT - 4); |
|
1022 int u = ( CUR*r + CUG*g + CUB*b ) >> (CSHIFT - 4); |
|
1023 int v = ( CVR*r + CVG*g + CVB*b ) >> (CSHIFT - 4); |
|
1024 |
|
1025 dst[0] = SkToU8(y); |
|
1026 dst[1] = SkToU8(u + 128); |
|
1027 dst[2] = SkToU8(v + 128); |
|
1028 } |
|
1029 |
|
1030 static void rgb2yuv_16(uint8_t dst[], U16CPU c) { |
|
1031 int r = SkGetPackedR16(c); |
|
1032 int g = SkGetPackedG16(c); |
|
1033 int b = SkGetPackedB16(c); |
|
1034 |
|
1035 int y = ( 2*CYR*r + CYG*g + 2*CYB*b ) >> (CSHIFT - 2); |
|
1036 int u = ( 2*CUR*r + CUG*g + 2*CUB*b ) >> (CSHIFT - 2); |
|
1037 int v = ( 2*CVR*r + CVG*g + 2*CVB*b ) >> (CSHIFT - 2); |
|
1038 |
|
1039 dst[0] = SkToU8(y); |
|
1040 dst[1] = SkToU8(u + 128); |
|
1041 dst[2] = SkToU8(v + 128); |
|
1042 } |
|
1043 |
|
1044 /////////////////////////////////////////////////////////////////////////////// |
|
1045 |
|
1046 typedef void (*WriteScanline)(uint8_t* SK_RESTRICT dst, |
|
1047 const void* SK_RESTRICT src, int width, |
|
1048 const SkPMColor* SK_RESTRICT ctable); |
|
1049 |
|
1050 static void Write_32_YUV(uint8_t* SK_RESTRICT dst, |
|
1051 const void* SK_RESTRICT srcRow, int width, |
|
1052 const SkPMColor*) { |
|
1053 const uint32_t* SK_RESTRICT src = (const uint32_t*)srcRow; |
|
1054 while (--width >= 0) { |
|
1055 #ifdef WE_CONVERT_TO_YUV |
|
1056 rgb2yuv_32(dst, *src++); |
|
1057 #else |
|
1058 uint32_t c = *src++; |
|
1059 dst[0] = SkGetPackedR32(c); |
|
1060 dst[1] = SkGetPackedG32(c); |
|
1061 dst[2] = SkGetPackedB32(c); |
|
1062 #endif |
|
1063 dst += 3; |
|
1064 } |
|
1065 } |
|
1066 |
|
1067 static void Write_4444_YUV(uint8_t* SK_RESTRICT dst, |
|
1068 const void* SK_RESTRICT srcRow, int width, |
|
1069 const SkPMColor*) { |
|
1070 const SkPMColor16* SK_RESTRICT src = (const SkPMColor16*)srcRow; |
|
1071 while (--width >= 0) { |
|
1072 #ifdef WE_CONVERT_TO_YUV |
|
1073 rgb2yuv_4444(dst, *src++); |
|
1074 #else |
|
1075 SkPMColor16 c = *src++; |
|
1076 dst[0] = SkPacked4444ToR32(c); |
|
1077 dst[1] = SkPacked4444ToG32(c); |
|
1078 dst[2] = SkPacked4444ToB32(c); |
|
1079 #endif |
|
1080 dst += 3; |
|
1081 } |
|
1082 } |
|
1083 |
|
1084 static void Write_16_YUV(uint8_t* SK_RESTRICT dst, |
|
1085 const void* SK_RESTRICT srcRow, int width, |
|
1086 const SkPMColor*) { |
|
1087 const uint16_t* SK_RESTRICT src = (const uint16_t*)srcRow; |
|
1088 while (--width >= 0) { |
|
1089 #ifdef WE_CONVERT_TO_YUV |
|
1090 rgb2yuv_16(dst, *src++); |
|
1091 #else |
|
1092 uint16_t c = *src++; |
|
1093 dst[0] = SkPacked16ToR32(c); |
|
1094 dst[1] = SkPacked16ToG32(c); |
|
1095 dst[2] = SkPacked16ToB32(c); |
|
1096 #endif |
|
1097 dst += 3; |
|
1098 } |
|
1099 } |
|
1100 |
|
1101 static void Write_Index_YUV(uint8_t* SK_RESTRICT dst, |
|
1102 const void* SK_RESTRICT srcRow, int width, |
|
1103 const SkPMColor* SK_RESTRICT ctable) { |
|
1104 const uint8_t* SK_RESTRICT src = (const uint8_t*)srcRow; |
|
1105 while (--width >= 0) { |
|
1106 #ifdef WE_CONVERT_TO_YUV |
|
1107 rgb2yuv_32(dst, ctable[*src++]); |
|
1108 #else |
|
1109 uint32_t c = ctable[*src++]; |
|
1110 dst[0] = SkGetPackedR32(c); |
|
1111 dst[1] = SkGetPackedG32(c); |
|
1112 dst[2] = SkGetPackedB32(c); |
|
1113 #endif |
|
1114 dst += 3; |
|
1115 } |
|
1116 } |
|
1117 |
|
1118 static WriteScanline ChooseWriter(const SkBitmap& bm) { |
|
1119 switch (bm.config()) { |
|
1120 case SkBitmap::kARGB_8888_Config: |
|
1121 return Write_32_YUV; |
|
1122 case SkBitmap::kRGB_565_Config: |
|
1123 return Write_16_YUV; |
|
1124 case SkBitmap::kARGB_4444_Config: |
|
1125 return Write_4444_YUV; |
|
1126 case SkBitmap::kIndex8_Config: |
|
1127 return Write_Index_YUV; |
|
1128 default: |
|
1129 return NULL; |
|
1130 } |
|
1131 } |
|
1132 |
|
1133 class SkJPEGImageEncoder : public SkImageEncoder { |
|
1134 protected: |
|
1135 virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) { |
|
1136 #ifdef TIME_ENCODE |
|
1137 SkAutoTime atm("JPEG Encode"); |
|
1138 #endif |
|
1139 |
|
1140 SkAutoLockPixels alp(bm); |
|
1141 if (NULL == bm.getPixels()) { |
|
1142 return false; |
|
1143 } |
|
1144 |
|
1145 jpeg_compress_struct cinfo; |
|
1146 skjpeg_error_mgr sk_err; |
|
1147 skjpeg_destination_mgr sk_wstream(stream); |
|
1148 |
|
1149 // allocate these before set call setjmp |
|
1150 SkAutoMalloc oneRow; |
|
1151 SkAutoLockColors ctLocker; |
|
1152 |
|
1153 cinfo.err = jpeg_std_error(&sk_err); |
|
1154 sk_err.error_exit = skjpeg_error_exit; |
|
1155 if (setjmp(sk_err.fJmpBuf)) { |
|
1156 return false; |
|
1157 } |
|
1158 |
|
1159 // Keep after setjmp or mark volatile. |
|
1160 const WriteScanline writer = ChooseWriter(bm); |
|
1161 if (NULL == writer) { |
|
1162 return false; |
|
1163 } |
|
1164 |
|
1165 jpeg_create_compress(&cinfo); |
|
1166 cinfo.dest = &sk_wstream; |
|
1167 cinfo.image_width = bm.width(); |
|
1168 cinfo.image_height = bm.height(); |
|
1169 cinfo.input_components = 3; |
|
1170 #ifdef WE_CONVERT_TO_YUV |
|
1171 cinfo.in_color_space = JCS_YCbCr; |
|
1172 #else |
|
1173 cinfo.in_color_space = JCS_RGB; |
|
1174 #endif |
|
1175 cinfo.input_gamma = 1; |
|
1176 |
|
1177 jpeg_set_defaults(&cinfo); |
|
1178 jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); |
|
1179 #ifdef DCT_IFAST_SUPPORTED |
|
1180 cinfo.dct_method = JDCT_IFAST; |
|
1181 #endif |
|
1182 |
|
1183 jpeg_start_compress(&cinfo, TRUE); |
|
1184 |
|
1185 const int width = bm.width(); |
|
1186 uint8_t* oneRowP = (uint8_t*)oneRow.reset(width * 3); |
|
1187 |
|
1188 const SkPMColor* colors = ctLocker.lockColors(bm); |
|
1189 const void* srcRow = bm.getPixels(); |
|
1190 |
|
1191 while (cinfo.next_scanline < cinfo.image_height) { |
|
1192 JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ |
|
1193 |
|
1194 writer(oneRowP, srcRow, width, colors); |
|
1195 row_pointer[0] = oneRowP; |
|
1196 (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); |
|
1197 srcRow = (const void*)((const char*)srcRow + bm.rowBytes()); |
|
1198 } |
|
1199 |
|
1200 jpeg_finish_compress(&cinfo); |
|
1201 jpeg_destroy_compress(&cinfo); |
|
1202 |
|
1203 return true; |
|
1204 } |
|
1205 }; |
|
1206 |
|
1207 /////////////////////////////////////////////////////////////////////////////// |
|
1208 DEFINE_DECODER_CREATOR(JPEGImageDecoder); |
|
1209 DEFINE_ENCODER_CREATOR(JPEGImageEncoder); |
|
1210 /////////////////////////////////////////////////////////////////////////////// |
|
1211 |
|
1212 static bool is_jpeg(SkStreamRewindable* stream) { |
|
1213 static const unsigned char gHeader[] = { 0xFF, 0xD8, 0xFF }; |
|
1214 static const size_t HEADER_SIZE = sizeof(gHeader); |
|
1215 |
|
1216 char buffer[HEADER_SIZE]; |
|
1217 size_t len = stream->read(buffer, HEADER_SIZE); |
|
1218 |
|
1219 if (len != HEADER_SIZE) { |
|
1220 return false; // can't read enough |
|
1221 } |
|
1222 if (memcmp(buffer, gHeader, HEADER_SIZE)) { |
|
1223 return false; |
|
1224 } |
|
1225 return true; |
|
1226 } |
|
1227 |
|
1228 |
|
1229 static SkImageDecoder* sk_libjpeg_dfactory(SkStreamRewindable* stream) { |
|
1230 if (is_jpeg(stream)) { |
|
1231 return SkNEW(SkJPEGImageDecoder); |
|
1232 } |
|
1233 return NULL; |
|
1234 } |
|
1235 |
|
1236 static SkImageDecoder::Format get_format_jpeg(SkStreamRewindable* stream) { |
|
1237 if (is_jpeg(stream)) { |
|
1238 return SkImageDecoder::kJPEG_Format; |
|
1239 } |
|
1240 return SkImageDecoder::kUnknown_Format; |
|
1241 } |
|
1242 |
|
1243 static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) { |
|
1244 return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL; |
|
1245 } |
|
1246 |
|
1247 static SkImageDecoder_DecodeReg gDReg(sk_libjpeg_dfactory); |
|
1248 static SkImageDecoder_FormatReg gFormatReg(get_format_jpeg); |
|
1249 static SkImageEncoder_EncodeReg gEReg(sk_libjpeg_efactory); |