• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*
3  * Copyright 2007 The Android Open Source Project
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 
9 
10 #include "SkImageDecoder.h"
11 #include "SkImageEncoder.h"
12 #include "SkJpegUtility.h"
13 #include "SkColorPriv.h"
14 #include "SkDither.h"
15 #include "SkScaledBitmapSampler.h"
16 #include "SkStream.h"
17 #include "SkTemplates.h"
18 #include "SkUtils.h"
19 #include "SkRect.h"
20 #include "SkCanvas.h"
21 
22 #include <stdio.h>
23 extern "C" {
24     #include "jpeglib.h"
25     #include "jerror.h"
26 }
27 
28 #ifdef SK_BUILD_FOR_ANDROID
29 #include <cutils/properties.h>
30 
31 // Key to lookup the size of memory buffer set in system property
32 static const char KEY_MEM_CAP[] = "ro.media.dec.jpeg.memcap";
33 #endif
34 
35 // this enables timing code to report milliseconds for an encode
36 //#define TIME_ENCODE
37 //#define TIME_DECODE
38 
39 // this enables our rgb->yuv code, which is faster than libjpeg on ARM
40 // disable for the moment, as we have some glitches when width != multiple of 4
41 #define WE_CONVERT_TO_YUV
42 
43 //////////////////////////////////////////////////////////////////////////
44 //////////////////////////////////////////////////////////////////////////
45 
46 class SkJPEGImageIndex {
47 public:
SkJPEGImageIndex()48     SkJPEGImageIndex() {}
~SkJPEGImageIndex()49     virtual ~SkJPEGImageIndex() {
50         jpeg_destroy_huffman_index(index);
51         jpeg_finish_decompress(cinfo);
52         jpeg_destroy_decompress(cinfo);
53         delete cinfo->src;
54         free(cinfo);
55     }
56     jpeg_decompress_struct *cinfo;
57     huffman_index *index;
58 };
59 
60 
61 class SkJPEGImageDecoder : public SkImageDecoder {
62 public:
SkJPEGImageDecoder()63     SkJPEGImageDecoder() {
64         index = NULL;
65     }
~SkJPEGImageDecoder()66     ~SkJPEGImageDecoder() {
67         if (index)
68             delete index;
69     }
getFormat() const70     virtual Format getFormat() const {
71         return kJPEG_Format;
72     }
73 protected:
74     virtual bool onBuildTileIndex(SkStream *stream,
75                                 int *width, int *height);
76     virtual bool onDecodeRegion(SkBitmap* bitmap, SkIRect rect);
77     virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode);
78 private:
79     SkJPEGImageIndex *index;
80     int imageWidth;
81     int imageHeight;
82 };
83 
84 //////////////////////////////////////////////////////////////////////////
85 
86 #include "SkTime.h"
87 
88 class AutoTimeMillis {
89 public:
AutoTimeMillis(const char label[])90     AutoTimeMillis(const char label[]) : fLabel(label) {
91         if (!fLabel) {
92             fLabel = "";
93         }
94         fNow = SkTime::GetMSecs();
95     }
~AutoTimeMillis()96     ~AutoTimeMillis() {
97         SkDebugf("---- Time (ms): %s %d\n", fLabel, SkTime::GetMSecs() - fNow);
98     }
99 private:
100     const char* fLabel;
101     SkMSec      fNow;
102 };
103 
104 /* Automatically clean up after throwing an exception */
105 class JPEGAutoClean {
106 public:
JPEGAutoClean()107     JPEGAutoClean(): cinfo_ptr(NULL) {}
~JPEGAutoClean()108     ~JPEGAutoClean() {
109         if (cinfo_ptr) {
110             jpeg_destroy_decompress(cinfo_ptr);
111         }
112     }
set(jpeg_decompress_struct * info)113     void set(jpeg_decompress_struct* info) {
114         cinfo_ptr = info;
115     }
116 private:
117     jpeg_decompress_struct* cinfo_ptr;
118 };
119 
120 #ifdef SK_BUILD_FOR_ANDROID
121 /* Check if the memory cap property is set.
122    If so, use the memory size for jpeg decode.
123 */
overwrite_mem_buffer_size(j_decompress_ptr cinfo)124 static void overwrite_mem_buffer_size(j_decompress_ptr cinfo) {
125 #ifdef ANDROID_LARGE_MEMORY_DEVICE
126     cinfo->mem->max_memory_to_use = 30 * 1024 * 1024;
127 #else
128     cinfo->mem->max_memory_to_use = 5 * 1024 * 1024;
129 #endif
130 }
131 #endif
132 
133 
134 ///////////////////////////////////////////////////////////////////////////////
135 
136 /*  If we need to better match the request, we might examine the image and
137      output dimensions, and determine if the downsampling jpeg provided is
138      not sufficient. If so, we can recompute a modified sampleSize value to
139      make up the difference.
140 
141      To skip this additional scaling, just set sampleSize = 1; below.
142  */
recompute_sampleSize(int sampleSize,const jpeg_decompress_struct & cinfo)143 static int recompute_sampleSize(int sampleSize,
144                                 const jpeg_decompress_struct& cinfo) {
145     return sampleSize * cinfo.output_width / cinfo.image_width;
146 }
147 
valid_output_dimensions(const jpeg_decompress_struct & cinfo)148 static bool valid_output_dimensions(const jpeg_decompress_struct& cinfo) {
149     /* These are initialized to 0, so if they have non-zero values, we assume
150        they are "valid" (i.e. have been computed by libjpeg)
151      */
152     return cinfo.output_width != 0 && cinfo.output_height != 0;
153 }
154 
skip_src_rows(jpeg_decompress_struct * cinfo,void * buffer,int count)155 static bool skip_src_rows(jpeg_decompress_struct* cinfo, void* buffer,
156                           int count) {
157     for (int i = 0; i < count; i++) {
158         JSAMPLE* rowptr = (JSAMPLE*)buffer;
159         int row_count = jpeg_read_scanlines(cinfo, &rowptr, 1);
160         if (row_count != 1) {
161             return false;
162         }
163     }
164     return true;
165 }
166 
skip_src_rows_tile(jpeg_decompress_struct * cinfo,huffman_index * index,void * buffer,int count)167 static bool skip_src_rows_tile(jpeg_decompress_struct* cinfo,
168                           huffman_index *index, void* buffer,
169                           int count) {
170     for (int i = 0; i < count; i++) {
171         JSAMPLE* rowptr = (JSAMPLE*)buffer;
172         int row_count = jpeg_read_tile_scanline(cinfo, index, &rowptr);
173         if (row_count != 1) {
174             return false;
175         }
176     }
177     return true;
178 }
179 
180 // This guy exists just to aid in debugging, as it allows debuggers to just
181 // set a break-point in one place to see all error exists.
return_false(const jpeg_decompress_struct & cinfo,const SkBitmap & bm,const char msg[])182 static bool return_false(const jpeg_decompress_struct& cinfo,
183                          const SkBitmap& bm, const char msg[]) {
184 #ifdef SK_DEBUG
185     SkDebugf("libjpeg error %d <%s> from %s [%d %d]", cinfo.err->msg_code,
186              cinfo.err->jpeg_message_table[cinfo.err->msg_code], msg,
187              bm.width(), bm.height());
188 #endif
189     return false;   // must always return false
190 }
191 
192 // Convert a scanline of CMYK samples to RGBX in place. Note that this
193 // method moves the "scanline" pointer in its processing
convert_CMYK_to_RGB(uint8_t * scanline,unsigned int width)194 static void convert_CMYK_to_RGB(uint8_t* scanline, unsigned int width) {
195     // At this point we've received CMYK pixels from libjpeg. We
196     // perform a crude conversion to RGB (based on the formulae
197     // from easyrgb.com):
198     //  CMYK -> CMY
199     //    C = ( C * (1 - K) + K )      // for each CMY component
200     //  CMY -> RGB
201     //    R = ( 1 - C ) * 255          // for each RGB component
202     // Unfortunately we are seeing inverted CMYK so all the original terms
203     // are 1-. This yields:
204     //  CMYK -> CMY
205     //    C = ( (1-C) * (1 - (1-K) + (1-K) ) -> C = 1 - C*K
206     // The conversion from CMY->RGB remains the same
207     for (unsigned int x = 0; x < width; ++x, scanline += 4) {
208         scanline[0] = SkMulDiv255Round(scanline[0], scanline[3]);
209         scanline[1] = SkMulDiv255Round(scanline[1], scanline[3]);
210         scanline[2] = SkMulDiv255Round(scanline[2], scanline[3]);
211         scanline[3] = 255;
212     }
213 }
214 
onDecode(SkStream * stream,SkBitmap * bm,Mode mode)215 bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
216 #ifdef TIME_DECODE
217     AutoTimeMillis atm("JPEG Decode");
218 #endif
219 
220     SkAutoMalloc  srcStorage;
221     JPEGAutoClean autoClean;
222 
223     jpeg_decompress_struct  cinfo;
224     skjpeg_error_mgr        sk_err;
225     skjpeg_source_mgr       sk_stream(stream, this, false);
226 
227     cinfo.err = jpeg_std_error(&sk_err);
228     sk_err.error_exit = skjpeg_error_exit;
229 
230     // All objects need to be instantiated before this setjmp call so that
231     // they will be cleaned up properly if an error occurs.
232     if (setjmp(sk_err.fJmpBuf)) {
233         return return_false(cinfo, *bm, "setjmp");
234     }
235 
236     jpeg_create_decompress(&cinfo);
237     autoClean.set(&cinfo);
238 
239 #ifdef SK_BUILD_FOR_ANDROID
240     overwrite_mem_buffer_size(&cinfo);
241 #endif
242 
243     //jpeg_stdio_src(&cinfo, file);
244     cinfo.src = &sk_stream;
245 
246     int status = jpeg_read_header(&cinfo, true);
247     if (status != JPEG_HEADER_OK) {
248         return return_false(cinfo, *bm, "read_header");
249     }
250 
251     /*  Try to fulfill the requested sampleSize. Since jpeg can do it (when it
252         can) much faster that we, just use their num/denom api to approximate
253         the size.
254     */
255     int sampleSize = this->getSampleSize();
256 
257     if (this->getPreferQualityOverSpeed()) {
258         cinfo.dct_method = JDCT_ISLOW;
259     } else {
260         cinfo.dct_method = JDCT_IFAST;
261     }
262 
263     cinfo.scale_num = 1;
264     cinfo.scale_denom = sampleSize;
265 
266     /* this gives about 30% performance improvement. In theory it may
267        reduce the visual quality, in practice I'm not seeing a difference
268      */
269     cinfo.do_fancy_upsampling = 0;
270 
271     /* this gives another few percents */
272     cinfo.do_block_smoothing = 0;
273 
274     /* default format is RGB */
275     if (cinfo.jpeg_color_space == JCS_CMYK) {
276         // libjpeg cannot convert from CMYK to RGB - here we set up
277         // so libjpeg will give us CMYK samples back and we will
278         // later manually convert them to RGB
279         cinfo.out_color_space = JCS_CMYK;
280     } else {
281         cinfo.out_color_space = JCS_RGB;
282     }
283 
284     SkBitmap::Config config = this->getPrefConfig(k32Bit_SrcDepth, false);
285     // only these make sense for jpegs
286     if (config != SkBitmap::kARGB_8888_Config &&
287         config != SkBitmap::kARGB_4444_Config &&
288         config != SkBitmap::kRGB_565_Config) {
289         config = SkBitmap::kARGB_8888_Config;
290     }
291 
292 #ifdef ANDROID_RGB
293     cinfo.dither_mode = JDITHER_NONE;
294     if (SkBitmap::kARGB_8888_Config == config && JCS_CMYK != cinfo.out_color_space) {
295         cinfo.out_color_space = JCS_RGBA_8888;
296     } else if (SkBitmap::kRGB_565_Config == config && JCS_CMYK != cinfo.out_color_space) {
297         cinfo.out_color_space = JCS_RGB_565;
298         if (this->getDitherImage()) {
299             cinfo.dither_mode = JDITHER_ORDERED;
300         }
301     }
302 #endif
303 
304     if (sampleSize == 1 && mode == SkImageDecoder::kDecodeBounds_Mode) {
305         bm->setConfig(config, cinfo.image_width, cinfo.image_height);
306         bm->setIsOpaque(true);
307         return true;
308     }
309 
310     /*  image_width and image_height are the original dimensions, available
311         after jpeg_read_header(). To see the scaled dimensions, we have to call
312         jpeg_start_decompress(), and then read output_width and output_height.
313     */
314     if (!jpeg_start_decompress(&cinfo)) {
315         /*  If we failed here, we may still have enough information to return
316             to the caller if they just wanted (subsampled bounds). If sampleSize
317             was 1, then we would have already returned. Thus we just check if
318             we're in kDecodeBounds_Mode, and that we have valid output sizes.
319 
320             One reason to fail here is that we have insufficient stream data
321             to complete the setup. However, output dimensions seem to get
322             computed very early, which is why this special check can pay off.
323          */
324         if (SkImageDecoder::kDecodeBounds_Mode == mode &&
325                 valid_output_dimensions(cinfo)) {
326             SkScaledBitmapSampler smpl(cinfo.output_width, cinfo.output_height,
327                                        recompute_sampleSize(sampleSize, cinfo));
328             bm->setConfig(config, smpl.scaledWidth(), smpl.scaledHeight());
329             bm->setIsOpaque(true);
330             return true;
331         } else {
332             return return_false(cinfo, *bm, "start_decompress");
333         }
334     }
335     sampleSize = recompute_sampleSize(sampleSize, cinfo);
336 
337     // should we allow the Chooser (if present) to pick a config for us???
338     if (!this->chooseFromOneChoice(config, cinfo.output_width,
339                                    cinfo.output_height)) {
340         return return_false(cinfo, *bm, "chooseFromOneChoice");
341     }
342 
343 #ifdef ANDROID_RGB
344     /* short-circuit the SkScaledBitmapSampler when possible, as this gives
345        a significant performance boost.
346     */
347     if (sampleSize == 1 &&
348         ((config == SkBitmap::kARGB_8888_Config &&
349                 cinfo.out_color_space == JCS_RGBA_8888) ||
350         (config == SkBitmap::kRGB_565_Config &&
351                 cinfo.out_color_space == JCS_RGB_565)))
352     {
353         bm->lockPixels();
354         JSAMPLE* rowptr = (JSAMPLE*)bm->getPixels();
355         bm->unlockPixels();
356         bool reuseBitmap = (rowptr != NULL);
357         if (reuseBitmap && ((int) cinfo.output_width != bm->width() ||
358                 (int) cinfo.output_height != bm->height())) {
359             // Dimensions must match
360             return false;
361         }
362 
363         if (!reuseBitmap) {
364             bm->setConfig(config, cinfo.output_width, cinfo.output_height);
365             bm->setIsOpaque(true);
366             if (SkImageDecoder::kDecodeBounds_Mode == mode) {
367                 return true;
368             }
369             if (!this->allocPixelRef(bm, NULL)) {
370                 return return_false(cinfo, *bm, "allocPixelRef");
371             }
372         } else if (SkImageDecoder::kDecodeBounds_Mode == mode) {
373             return true;
374         }
375         SkAutoLockPixels alp(*bm);
376         rowptr = (JSAMPLE*)bm->getPixels();
377         INT32 const bpr =  bm->rowBytes();
378 
379         while (cinfo.output_scanline < cinfo.output_height) {
380             int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1);
381             // if row_count == 0, then we didn't get a scanline, so abort.
382             // if we supported partial images, we might return true in this case
383             if (0 == row_count) {
384                 return return_false(cinfo, *bm, "read_scanlines");
385             }
386             if (this->shouldCancelDecode()) {
387                 return return_false(cinfo, *bm, "shouldCancelDecode");
388             }
389             rowptr += bpr;
390         }
391         if (reuseBitmap) {
392             bm->notifyPixelsChanged();
393         }
394         jpeg_finish_decompress(&cinfo);
395         return true;
396     }
397 #endif
398 
399     // check for supported formats
400     SkScaledBitmapSampler::SrcConfig sc;
401     if (JCS_CMYK == cinfo.out_color_space) {
402         // In this case we will manually convert the CMYK values to RGB
403         sc = SkScaledBitmapSampler::kRGBX;
404     } else if (3 == cinfo.out_color_components && JCS_RGB == cinfo.out_color_space) {
405         sc = SkScaledBitmapSampler::kRGB;
406 #ifdef ANDROID_RGB
407     } else if (JCS_RGBA_8888 == cinfo.out_color_space) {
408         sc = SkScaledBitmapSampler::kRGBX;
409     } else if (JCS_RGB_565 == cinfo.out_color_space) {
410         sc = SkScaledBitmapSampler::kRGB_565;
411 #endif
412     } else if (1 == cinfo.out_color_components &&
413                JCS_GRAYSCALE == cinfo.out_color_space) {
414         sc = SkScaledBitmapSampler::kGray;
415     } else {
416         return return_false(cinfo, *bm, "jpeg colorspace");
417     }
418 
419     SkScaledBitmapSampler sampler(cinfo.output_width, cinfo.output_height,
420                                   sampleSize);
421 
422     bm->lockPixels();
423     JSAMPLE* rowptr = (JSAMPLE*)bm->getPixels();
424     bool reuseBitmap = (rowptr != NULL);
425     bm->unlockPixels();
426     if (reuseBitmap && (sampler.scaledWidth() != bm->width() ||
427             sampler.scaledHeight() != bm->height())) {
428         // Dimensions must match
429         return false;
430     }
431 
432     if (!reuseBitmap) {
433         bm->setConfig(config, sampler.scaledWidth(), sampler.scaledHeight());
434         // jpegs are always opaque (i.e. have no per-pixel alpha)
435         bm->setIsOpaque(true);
436 
437         if (SkImageDecoder::kDecodeBounds_Mode == mode) {
438             return true;
439         }
440         if (!this->allocPixelRef(bm, NULL)) {
441             return return_false(cinfo, *bm, "allocPixelRef");
442         }
443     } else if (SkImageDecoder::kDecodeBounds_Mode == mode) {
444         return true;
445     }
446 
447     SkAutoLockPixels alp(*bm);
448     if (!sampler.begin(bm, sc, this->getDitherImage())) {
449         return return_false(cinfo, *bm, "sampler.begin");
450     }
451 
452     // The CMYK work-around relies on 4 components per pixel here
453     uint8_t* srcRow = (uint8_t*)srcStorage.reset(cinfo.output_width * 4);
454 
455     //  Possibly skip initial rows [sampler.srcY0]
456     if (!skip_src_rows(&cinfo, srcRow, sampler.srcY0())) {
457         return return_false(cinfo, *bm, "skip rows");
458     }
459 
460     // now loop through scanlines until y == bm->height() - 1
461     for (int y = 0;; y++) {
462         JSAMPLE* rowptr = (JSAMPLE*)srcRow;
463         int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1);
464         if (0 == row_count) {
465             return return_false(cinfo, *bm, "read_scanlines");
466         }
467         if (this->shouldCancelDecode()) {
468             return return_false(cinfo, *bm, "shouldCancelDecode");
469         }
470 
471         if (JCS_CMYK == cinfo.out_color_space) {
472             convert_CMYK_to_RGB(srcRow, cinfo.output_width);
473         }
474 
475         sampler.next(srcRow);
476         if (bm->height() - 1 == y) {
477             // we're done
478             break;
479         }
480 
481         if (!skip_src_rows(&cinfo, srcRow, sampler.srcDY() - 1)) {
482             return return_false(cinfo, *bm, "skip rows");
483         }
484     }
485 
486     // we formally skip the rest, so we don't get a complaint from libjpeg
487     if (!skip_src_rows(&cinfo, srcRow,
488                        cinfo.output_height - cinfo.output_scanline)) {
489         return return_false(cinfo, *bm, "skip rows");
490     }
491     if (reuseBitmap) {
492         bm->notifyPixelsChanged();
493     }
494     jpeg_finish_decompress(&cinfo);
495 
496 //    SkDebugf("------------------- bm2 size %d [%d %d] %d\n", bm->getSize(), bm->width(), bm->height(), bm->config());
497     return true;
498 }
499 
onBuildTileIndex(SkStream * stream,int * width,int * height)500 bool SkJPEGImageDecoder::onBuildTileIndex(SkStream* stream,
501                                         int *width, int *height) {
502     SkAutoMalloc  srcStorage;
503     SkJPEGImageIndex *index = new SkJPEGImageIndex;
504 
505     jpeg_decompress_struct  *cinfo = (jpeg_decompress_struct*)
506                                         malloc(sizeof(jpeg_decompress_struct));
507     skjpeg_error_mgr        sk_err;
508     skjpeg_source_mgr       *sk_stream =
509         new skjpeg_source_mgr(stream, this, true);
510     if (cinfo == NULL || sk_stream == NULL) {
511         return false;
512     }
513 
514     cinfo->err = jpeg_std_error(&sk_err);
515     sk_err.error_exit = skjpeg_error_exit;
516 
517     // All objects need to be instantiated before this setjmp call so that
518     // they will be cleaned up properly if an error occurs.
519     if (setjmp(sk_err.fJmpBuf)) {
520         return false;
521     }
522 
523     jpeg_create_decompress(cinfo);
524     cinfo->do_fancy_upsampling = 0;
525     cinfo->do_block_smoothing = 0;
526 
527 #ifdef SK_BUILD_FOR_ANDROID
528     overwrite_mem_buffer_size(cinfo);
529 #endif
530 
531     cinfo->src = sk_stream;
532     int status = jpeg_read_header(cinfo, true);
533     if (status != JPEG_HEADER_OK) {
534         return false;
535     }
536     index->index = (huffman_index*)malloc(sizeof(huffman_index));
537     jpeg_create_huffman_index(cinfo, index->index);
538 
539     cinfo->scale_num = 1;
540     cinfo->scale_denom = 1;
541     if (!jpeg_build_huffman_index(cinfo, index->index)) {
542         return false;
543     }
544     if (fReporter)
545         fReporter->reportMemory(index->index->mem_used);
546     jpeg_destroy_decompress(cinfo);
547 
548 
549     // Init decoder to image decode mode
550     jpeg_create_decompress(cinfo);
551 
552 #ifdef SK_BUILD_FOR_ANDROID
553     overwrite_mem_buffer_size(cinfo);
554 #endif
555 
556     cinfo->src = sk_stream;
557     status = jpeg_read_header(cinfo,true);
558     if (status != JPEG_HEADER_OK) {
559         return false;
560     }
561     cinfo->out_color_space = JCS_RGBA_8888;
562     cinfo->do_fancy_upsampling = 0;
563     cinfo->do_block_smoothing = 0;
564     //jpeg_start_decompress(cinfo);
565     jpeg_start_tile_decompress(cinfo);
566 
567     cinfo->scale_num = 1;
568     index->cinfo = cinfo;
569     *height = cinfo->output_height;
570     *width = cinfo->output_width;
571     this->imageWidth = *width;
572     this->imageHeight = *height;
573     this->index = index;
574     return true;
575 }
576 
onDecodeRegion(SkBitmap * bm,SkIRect region)577 bool SkJPEGImageDecoder::onDecodeRegion(SkBitmap* bm, SkIRect region) {
578     if (index == NULL) {
579         return false;
580     }
581     jpeg_decompress_struct *cinfo = index->cinfo;
582 
583     SkIRect rect = SkIRect::MakeWH(this->imageWidth, this->imageHeight);
584     if (!rect.intersect(region)) {
585         // If the requested region is entirely outsides the image, just
586         // returns false
587         return false;
588     }
589     SkAutoMalloc  srcStorage;
590     skjpeg_error_mgr        sk_err;
591     cinfo->err = jpeg_std_error(&sk_err);
592     sk_err.error_exit = skjpeg_error_exit;
593     if (setjmp(sk_err.fJmpBuf)) {
594         return false;
595     }
596     int requestedSampleSize = this->getSampleSize();
597     cinfo->scale_denom = requestedSampleSize;
598 
599     if (this->getPreferQualityOverSpeed()) {
600         cinfo->dct_method = JDCT_ISLOW;
601     } else {
602         cinfo->dct_method = JDCT_IFAST;
603     }
604 
605     SkBitmap::Config config = this->getPrefConfig(k32Bit_SrcDepth, false);
606     if (config != SkBitmap::kARGB_8888_Config &&
607         config != SkBitmap::kARGB_4444_Config &&
608         config != SkBitmap::kRGB_565_Config) {
609         config = SkBitmap::kARGB_8888_Config;
610     }
611 
612     /* default format is RGB */
613     cinfo->out_color_space = JCS_RGB;
614 
615 #ifdef ANDROID_RGB
616     cinfo->dither_mode = JDITHER_NONE;
617     if (config == SkBitmap::kARGB_8888_Config) {
618         cinfo->out_color_space = JCS_RGBA_8888;
619     } else if (config == SkBitmap::kRGB_565_Config) {
620         cinfo->out_color_space = JCS_RGB_565;
621         if (this->getDitherImage()) {
622             cinfo->dither_mode = JDITHER_ORDERED;
623         }
624     }
625 #endif
626     int startX = rect.fLeft;
627     int startY = rect.fTop;
628     int width = rect.width();
629     int height = rect.height();
630 
631     jpeg_init_read_tile_scanline(cinfo, index->index,
632                                  &startX, &startY, &width, &height);
633     int skiaSampleSize = recompute_sampleSize(requestedSampleSize, *cinfo);
634     int actualSampleSize = skiaSampleSize * (DCTSIZE / cinfo->min_DCT_scaled_size);
635 
636     SkBitmap *bitmap = new SkBitmap;
637     SkAutoTDelete<SkBitmap> adb(bitmap);
638 
639 #ifdef ANDROID_RGB
640     /* short-circuit the SkScaledBitmapSampler when possible, as this gives
641        a significant performance boost.
642     */
643     if (skiaSampleSize == 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         bitmap->setConfig(config, cinfo->output_width, height);
650         bitmap->setIsOpaque(true);
651 
652         // Check ahead of time if the swap(dest, src) is possible or not.
653         // If yes, then we will stick to AllocPixelRef since it's cheaper
654         // with the swap happening. If no, then we will use alloc to allocate
655         // pixels to prevent garbage collection.
656         //
657         // Not using a recycled-bitmap and the output rect is same as the
658         // decoded region.
659         int w = rect.width() / actualSampleSize;
660         int h = rect.height() / actualSampleSize;
661         bool swapOnly = (rect == region) && bm->isNull() &&
662                         (w == bitmap->width()) && (h == bitmap->height()) &&
663                         ((startX - rect.x()) / actualSampleSize == 0) &&
664                         ((startY - rect.y()) / actualSampleSize == 0);
665         if (swapOnly) {
666             if (!this->allocPixelRef(bitmap, NULL)) {
667                 return return_false(*cinfo, *bitmap, "allocPixelRef");
668             }
669         } else {
670             if (!bitmap->allocPixels()) {
671                 return return_false(*cinfo, *bitmap, "allocPixels");
672             }
673         }
674 
675         SkAutoLockPixels alp(*bitmap);
676         JSAMPLE* rowptr = (JSAMPLE*)bitmap->getPixels();
677         INT32 const bpr = bitmap->rowBytes();
678         int row_total_count = 0;
679 
680         while (row_total_count < height) {
681             int row_count = jpeg_read_tile_scanline(cinfo,
682                     index->index, &rowptr);
683             // if row_count == 0, then we didn't get a scanline, so abort.
684             // if we supported partial images, we might return true in this case
685             if (0 == row_count) {
686                 return return_false(*cinfo, *bitmap, "read_scanlines");
687             }
688             if (this->shouldCancelDecode()) {
689                 return return_false(*cinfo, *bitmap, "shouldCancelDecode");
690             }
691             row_total_count += row_count;
692             rowptr += bpr;
693         }
694 
695         if (swapOnly) {
696             bm->swap(*bitmap);
697         } else {
698             cropBitmap(bm, bitmap, actualSampleSize, region.x(), region.y(),
699                        region.width(), region.height(), startX, startY);
700         }
701         return true;
702     }
703 #endif
704     // check for supported formats
705     SkScaledBitmapSampler::SrcConfig sc;
706     if (3 == cinfo->out_color_components && JCS_RGB == cinfo->out_color_space) {
707         sc = SkScaledBitmapSampler::kRGB;
708 #ifdef ANDROID_RGB
709     } else if (JCS_RGBA_8888 == cinfo->out_color_space) {
710         sc = SkScaledBitmapSampler::kRGBX;
711     } else if (JCS_RGB_565 == cinfo->out_color_space) {
712         sc = SkScaledBitmapSampler::kRGB_565;
713 #endif
714     } else if (1 == cinfo->out_color_components &&
715                JCS_GRAYSCALE == cinfo->out_color_space) {
716         sc = SkScaledBitmapSampler::kGray;
717     } else {
718         return return_false(*cinfo, *bm, "jpeg colorspace");
719     }
720 
721     SkScaledBitmapSampler sampler(width, height, skiaSampleSize);
722 
723     bitmap->setConfig(config, sampler.scaledWidth(), sampler.scaledHeight());
724     bitmap->setIsOpaque(true);
725 
726     // Check ahead of time if the swap(dest, src) is possible or not.
727     // If yes, then we will stick to AllocPixelRef since it's cheaper with the
728     // swap happening. If no, then we will use alloc to allocate pixels to
729     // prevent garbage collection.
730     int w = rect.width() / actualSampleSize;
731     int h = rect.height() / actualSampleSize;
732     bool swapOnly = (rect == region) && bm->isNull() &&
733                     (w == bitmap->width()) && (h == bitmap->height()) &&
734                     ((startX - rect.x()) / actualSampleSize == 0) &&
735                     ((startY - rect.y()) / actualSampleSize == 0);
736     if (swapOnly) {
737         if (!this->allocPixelRef(bitmap, NULL)) {
738             return return_false(*cinfo, *bitmap, "allocPixelRef");
739         }
740     } else {
741         if (!bitmap->allocPixels()) {
742             return return_false(*cinfo, *bitmap, "allocPixels");
743         }
744     }
745 
746     SkAutoLockPixels alp(*bitmap);
747     if (!sampler.begin(bitmap, sc, this->getDitherImage())) {
748         return return_false(*cinfo, *bitmap, "sampler.begin");
749     }
750 
751     uint8_t* srcRow = (uint8_t*)srcStorage.reset(width * 4);
752 
753     //  Possibly skip initial rows [sampler.srcY0]
754     if (!skip_src_rows_tile(cinfo, index->index, srcRow, sampler.srcY0())) {
755         return return_false(*cinfo, *bitmap, "skip rows");
756     }
757 
758     // now loop through scanlines until y == bitmap->height() - 1
759     for (int y = 0;; y++) {
760         JSAMPLE* rowptr = (JSAMPLE*)srcRow;
761         int row_count = jpeg_read_tile_scanline(cinfo, index->index, &rowptr);
762         if (0 == row_count) {
763             return return_false(*cinfo, *bitmap, "read_scanlines");
764         }
765         if (this->shouldCancelDecode()) {
766             return return_false(*cinfo, *bitmap, "shouldCancelDecode");
767         }
768 
769         sampler.next(srcRow);
770         if (bitmap->height() - 1 == y) {
771             // we're done
772             break;
773         }
774 
775         if (!skip_src_rows_tile(cinfo, index->index, srcRow,
776                                 sampler.srcDY() - 1)) {
777             return return_false(*cinfo, *bitmap, "skip rows");
778         }
779     }
780     if (swapOnly) {
781         bm->swap(*bitmap);
782     } else {
783         cropBitmap(bm, bitmap, actualSampleSize, region.x(), region.y(),
784                    region.width(), region.height(), startX, startY);
785     }
786     return true;
787 }
788 
789 ///////////////////////////////////////////////////////////////////////////////
790 
791 #include "SkColorPriv.h"
792 
793 // taken from jcolor.c in libjpeg
794 #if 0   // 16bit - precise but slow
795     #define CYR     19595   // 0.299
796     #define CYG     38470   // 0.587
797     #define CYB      7471   // 0.114
798 
799     #define CUR    -11059   // -0.16874
800     #define CUG    -21709   // -0.33126
801     #define CUB     32768   // 0.5
802 
803     #define CVR     32768   // 0.5
804     #define CVG    -27439   // -0.41869
805     #define CVB     -5329   // -0.08131
806 
807     #define CSHIFT  16
808 #else      // 8bit - fast, slightly less precise
809     #define CYR     77    // 0.299
810     #define CYG     150    // 0.587
811     #define CYB      29    // 0.114
812 
813     #define CUR     -43    // -0.16874
814     #define CUG    -85    // -0.33126
815     #define CUB     128    // 0.5
816 
817     #define CVR      128   // 0.5
818     #define CVG     -107   // -0.41869
819     #define CVB      -21   // -0.08131
820 
821     #define CSHIFT  8
822 #endif
823 
rgb2yuv_32(uint8_t dst[],SkPMColor c)824 static void rgb2yuv_32(uint8_t dst[], SkPMColor c) {
825     int r = SkGetPackedR32(c);
826     int g = SkGetPackedG32(c);
827     int b = SkGetPackedB32(c);
828 
829     int  y = ( CYR*r + CYG*g + CYB*b ) >> CSHIFT;
830     int  u = ( CUR*r + CUG*g + CUB*b ) >> CSHIFT;
831     int  v = ( CVR*r + CVG*g + CVB*b ) >> CSHIFT;
832 
833     dst[0] = SkToU8(y);
834     dst[1] = SkToU8(u + 128);
835     dst[2] = SkToU8(v + 128);
836 }
837 
rgb2yuv_4444(uint8_t dst[],U16CPU c)838 static void rgb2yuv_4444(uint8_t dst[], U16CPU c) {
839     int r = SkGetPackedR4444(c);
840     int g = SkGetPackedG4444(c);
841     int b = SkGetPackedB4444(c);
842 
843     int  y = ( CYR*r + CYG*g + CYB*b ) >> (CSHIFT - 4);
844     int  u = ( CUR*r + CUG*g + CUB*b ) >> (CSHIFT - 4);
845     int  v = ( CVR*r + CVG*g + CVB*b ) >> (CSHIFT - 4);
846 
847     dst[0] = SkToU8(y);
848     dst[1] = SkToU8(u + 128);
849     dst[2] = SkToU8(v + 128);
850 }
851 
rgb2yuv_16(uint8_t dst[],U16CPU c)852 static void rgb2yuv_16(uint8_t dst[], U16CPU c) {
853     int r = SkGetPackedR16(c);
854     int g = SkGetPackedG16(c);
855     int b = SkGetPackedB16(c);
856 
857     int  y = ( 2*CYR*r + CYG*g + 2*CYB*b ) >> (CSHIFT - 2);
858     int  u = ( 2*CUR*r + CUG*g + 2*CUB*b ) >> (CSHIFT - 2);
859     int  v = ( 2*CVR*r + CVG*g + 2*CVB*b ) >> (CSHIFT - 2);
860 
861     dst[0] = SkToU8(y);
862     dst[1] = SkToU8(u + 128);
863     dst[2] = SkToU8(v + 128);
864 }
865 
866 ///////////////////////////////////////////////////////////////////////////////
867 
868 typedef void (*WriteScanline)(uint8_t* SK_RESTRICT dst,
869                               const void* SK_RESTRICT src, int width,
870                               const SkPMColor* SK_RESTRICT ctable);
871 
Write_32_YUV(uint8_t * SK_RESTRICT dst,const void * SK_RESTRICT srcRow,int width,const SkPMColor *)872 static void Write_32_YUV(uint8_t* SK_RESTRICT dst,
873                          const void* SK_RESTRICT srcRow, int width,
874                          const SkPMColor*) {
875     const uint32_t* SK_RESTRICT src = (const uint32_t*)srcRow;
876     while (--width >= 0) {
877 #ifdef WE_CONVERT_TO_YUV
878         rgb2yuv_32(dst, *src++);
879 #else
880         uint32_t c = *src++;
881         dst[0] = SkGetPackedR32(c);
882         dst[1] = SkGetPackedG32(c);
883         dst[2] = SkGetPackedB32(c);
884 #endif
885         dst += 3;
886     }
887 }
888 
Write_4444_YUV(uint8_t * SK_RESTRICT dst,const void * SK_RESTRICT srcRow,int width,const SkPMColor *)889 static void Write_4444_YUV(uint8_t* SK_RESTRICT dst,
890                            const void* SK_RESTRICT srcRow, int width,
891                            const SkPMColor*) {
892     const SkPMColor16* SK_RESTRICT src = (const SkPMColor16*)srcRow;
893     while (--width >= 0) {
894 #ifdef WE_CONVERT_TO_YUV
895         rgb2yuv_4444(dst, *src++);
896 #else
897         SkPMColor16 c = *src++;
898         dst[0] = SkPacked4444ToR32(c);
899         dst[1] = SkPacked4444ToG32(c);
900         dst[2] = SkPacked4444ToB32(c);
901 #endif
902         dst += 3;
903     }
904 }
905 
Write_16_YUV(uint8_t * SK_RESTRICT dst,const void * SK_RESTRICT srcRow,int width,const SkPMColor *)906 static void Write_16_YUV(uint8_t* SK_RESTRICT dst,
907                          const void* SK_RESTRICT srcRow, int width,
908                          const SkPMColor*) {
909     const uint16_t* SK_RESTRICT src = (const uint16_t*)srcRow;
910     while (--width >= 0) {
911 #ifdef WE_CONVERT_TO_YUV
912         rgb2yuv_16(dst, *src++);
913 #else
914         uint16_t c = *src++;
915         dst[0] = SkPacked16ToR32(c);
916         dst[1] = SkPacked16ToG32(c);
917         dst[2] = SkPacked16ToB32(c);
918 #endif
919         dst += 3;
920     }
921 }
922 
Write_Index_YUV(uint8_t * SK_RESTRICT dst,const void * SK_RESTRICT srcRow,int width,const SkPMColor * SK_RESTRICT ctable)923 static void Write_Index_YUV(uint8_t* SK_RESTRICT dst,
924                             const void* SK_RESTRICT srcRow, int width,
925                             const SkPMColor* SK_RESTRICT ctable) {
926     const uint8_t* SK_RESTRICT src = (const uint8_t*)srcRow;
927     while (--width >= 0) {
928 #ifdef WE_CONVERT_TO_YUV
929         rgb2yuv_32(dst, ctable[*src++]);
930 #else
931         uint32_t c = ctable[*src++];
932         dst[0] = SkGetPackedR32(c);
933         dst[1] = SkGetPackedG32(c);
934         dst[2] = SkGetPackedB32(c);
935 #endif
936         dst += 3;
937     }
938 }
939 
ChooseWriter(const SkBitmap & bm)940 static WriteScanline ChooseWriter(const SkBitmap& bm) {
941     switch (bm.config()) {
942         case SkBitmap::kARGB_8888_Config:
943             return Write_32_YUV;
944         case SkBitmap::kRGB_565_Config:
945             return Write_16_YUV;
946         case SkBitmap::kARGB_4444_Config:
947             return Write_4444_YUV;
948         case SkBitmap::kIndex8_Config:
949             return Write_Index_YUV;
950         default:
951             return NULL;
952     }
953 }
954 
955 class SkJPEGImageEncoder : public SkImageEncoder {
956 protected:
onEncode(SkWStream * stream,const SkBitmap & bm,int quality)957     virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) {
958 #ifdef TIME_ENCODE
959         AutoTimeMillis atm("JPEG Encode");
960 #endif
961 
962         const WriteScanline writer = ChooseWriter(bm);
963         if (NULL == writer) {
964             return false;
965         }
966 
967         SkAutoLockPixels alp(bm);
968         if (NULL == bm.getPixels()) {
969             return false;
970         }
971 
972         jpeg_compress_struct    cinfo;
973         skjpeg_error_mgr        sk_err;
974         skjpeg_destination_mgr  sk_wstream(stream);
975 
976         // allocate these before set call setjmp
977         SkAutoMalloc    oneRow;
978         SkAutoLockColors ctLocker;
979 
980         cinfo.err = jpeg_std_error(&sk_err);
981         sk_err.error_exit = skjpeg_error_exit;
982         if (setjmp(sk_err.fJmpBuf)) {
983             return false;
984         }
985         jpeg_create_compress(&cinfo);
986 
987         cinfo.dest = &sk_wstream;
988         cinfo.image_width = bm.width();
989         cinfo.image_height = bm.height();
990         cinfo.input_components = 3;
991 #ifdef WE_CONVERT_TO_YUV
992         cinfo.in_color_space = JCS_YCbCr;
993 #else
994         cinfo.in_color_space = JCS_RGB;
995 #endif
996         cinfo.input_gamma = 1;
997 
998         jpeg_set_defaults(&cinfo);
999         jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
1000         cinfo.dct_method = JDCT_IFAST;
1001 
1002         jpeg_start_compress(&cinfo, TRUE);
1003 
1004         const int       width = bm.width();
1005         uint8_t*        oneRowP = (uint8_t*)oneRow.reset(width * 3);
1006 
1007         const SkPMColor* colors = ctLocker.lockColors(bm);
1008         const void*      srcRow = bm.getPixels();
1009 
1010         while (cinfo.next_scanline < cinfo.image_height) {
1011             JSAMPROW row_pointer[1];    /* pointer to JSAMPLE row[s] */
1012 
1013             writer(oneRowP, srcRow, width, colors);
1014             row_pointer[0] = oneRowP;
1015             (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
1016             srcRow = (const void*)((const char*)srcRow + bm.rowBytes());
1017         }
1018 
1019         jpeg_finish_compress(&cinfo);
1020         jpeg_destroy_compress(&cinfo);
1021 
1022         return true;
1023     }
1024 };
1025 
1026 ///////////////////////////////////////////////////////////////////////////////
1027 DEFINE_DECODER_CREATOR(JPEGImageDecoder);
1028 DEFINE_ENCODER_CREATOR(JPEGImageEncoder);
1029 ///////////////////////////////////////////////////////////////////////////////
1030 
1031 #include "SkTRegistry.h"
1032 
sk_libjpeg_dfactory(SkStream * stream)1033 static SkImageDecoder* sk_libjpeg_dfactory(SkStream* stream) {
1034     static const unsigned char gHeader[] = { 0xFF, 0xD8, 0xFF };
1035     static const size_t HEADER_SIZE = sizeof(gHeader);
1036 
1037     char buffer[HEADER_SIZE];
1038     size_t len = stream->read(buffer, HEADER_SIZE);
1039 
1040     if (len != HEADER_SIZE) {
1041         return NULL;   // can't read enough
1042     }
1043     if (memcmp(buffer, gHeader, HEADER_SIZE)) {
1044         return NULL;
1045     }
1046     return SkNEW(SkJPEGImageDecoder);
1047 }
1048 
sk_libjpeg_efactory(SkImageEncoder::Type t)1049 static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) {
1050     return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL;
1051 }
1052 
1053 
1054 static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(sk_libjpeg_dfactory);
1055 static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(sk_libjpeg_efactory);
1056