• 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 
onDecode(SkStream * stream,SkBitmap * bm,Mode mode)192 bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
193 #ifdef TIME_DECODE
194     AutoTimeMillis atm("JPEG Decode");
195 #endif
196 
197     SkAutoMalloc  srcStorage;
198     JPEGAutoClean autoClean;
199 
200     jpeg_decompress_struct  cinfo;
201     skjpeg_error_mgr        sk_err;
202     skjpeg_source_mgr       sk_stream(stream, this, false);
203 
204     cinfo.err = jpeg_std_error(&sk_err);
205     sk_err.error_exit = skjpeg_error_exit;
206 
207     // All objects need to be instantiated before this setjmp call so that
208     // they will be cleaned up properly if an error occurs.
209     if (setjmp(sk_err.fJmpBuf)) {
210         return return_false(cinfo, *bm, "setjmp");
211     }
212 
213     jpeg_create_decompress(&cinfo);
214     autoClean.set(&cinfo);
215 
216 #ifdef SK_BUILD_FOR_ANDROID
217     overwrite_mem_buffer_size(&cinfo);
218 #endif
219 
220     //jpeg_stdio_src(&cinfo, file);
221     cinfo.src = &sk_stream;
222 
223     int status = jpeg_read_header(&cinfo, true);
224     if (status != JPEG_HEADER_OK) {
225         return return_false(cinfo, *bm, "read_header");
226     }
227 
228     /*  Try to fulfill the requested sampleSize. Since jpeg can do it (when it
229         can) much faster that we, just use their num/denom api to approximate
230         the size.
231     */
232     int sampleSize = this->getSampleSize();
233 
234     if (this->getPreferQualityOverSpeed()) {
235         cinfo.dct_method = JDCT_ISLOW;
236     } else {
237         cinfo.dct_method = JDCT_IFAST;
238     }
239 
240     cinfo.scale_num = 1;
241     cinfo.scale_denom = sampleSize;
242 
243     /* this gives about 30% performance improvement. In theory it may
244        reduce the visual quality, in practice I'm not seeing a difference
245      */
246     cinfo.do_fancy_upsampling = 0;
247 
248     /* this gives another few percents */
249     cinfo.do_block_smoothing = 0;
250 
251     /* default format is RGB */
252     cinfo.out_color_space = JCS_RGB;
253 
254     SkBitmap::Config config = this->getPrefConfig(k32Bit_SrcDepth, false);
255     // only these make sense for jpegs
256     if (config != SkBitmap::kARGB_8888_Config &&
257         config != SkBitmap::kARGB_4444_Config &&
258         config != SkBitmap::kRGB_565_Config) {
259         config = SkBitmap::kARGB_8888_Config;
260     }
261 
262 #ifdef ANDROID_RGB
263     cinfo.dither_mode = JDITHER_NONE;
264     if (config == SkBitmap::kARGB_8888_Config) {
265         cinfo.out_color_space = JCS_RGBA_8888;
266     } else if (config == SkBitmap::kRGB_565_Config) {
267         cinfo.out_color_space = JCS_RGB_565;
268         if (this->getDitherImage()) {
269             cinfo.dither_mode = JDITHER_ORDERED;
270         }
271     }
272 #endif
273 
274     if (sampleSize == 1 && mode == SkImageDecoder::kDecodeBounds_Mode) {
275         bm->setConfig(config, cinfo.image_width, cinfo.image_height);
276         bm->setIsOpaque(true);
277         return true;
278     }
279 
280     /*  image_width and image_height are the original dimensions, available
281         after jpeg_read_header(). To see the scaled dimensions, we have to call
282         jpeg_start_decompress(), and then read output_width and output_height.
283     */
284     if (!jpeg_start_decompress(&cinfo)) {
285         /*  If we failed here, we may still have enough information to return
286             to the caller if they just wanted (subsampled bounds). If sampleSize
287             was 1, then we would have already returned. Thus we just check if
288             we're in kDecodeBounds_Mode, and that we have valid output sizes.
289 
290             One reason to fail here is that we have insufficient stream data
291             to complete the setup. However, output dimensions seem to get
292             computed very early, which is why this special check can pay off.
293          */
294         if (SkImageDecoder::kDecodeBounds_Mode == mode &&
295                 valid_output_dimensions(cinfo)) {
296             SkScaledBitmapSampler smpl(cinfo.output_width, cinfo.output_height,
297                                        recompute_sampleSize(sampleSize, cinfo));
298             bm->setConfig(config, smpl.scaledWidth(), smpl.scaledHeight());
299             bm->setIsOpaque(true);
300             return true;
301         } else {
302             return return_false(cinfo, *bm, "start_decompress");
303         }
304     }
305     sampleSize = recompute_sampleSize(sampleSize, cinfo);
306 
307     // should we allow the Chooser (if present) to pick a config for us???
308     if (!this->chooseFromOneChoice(config, cinfo.output_width,
309                                    cinfo.output_height)) {
310         return return_false(cinfo, *bm, "chooseFromOneChoice");
311     }
312 
313 #ifdef ANDROID_RGB
314     /* short-circuit the SkScaledBitmapSampler when possible, as this gives
315        a significant performance boost.
316     */
317     if (sampleSize == 1 &&
318         ((config == SkBitmap::kARGB_8888_Config &&
319                 cinfo.out_color_space == JCS_RGBA_8888) ||
320         (config == SkBitmap::kRGB_565_Config &&
321                 cinfo.out_color_space == JCS_RGB_565)))
322     {
323         bm->lockPixels();
324         JSAMPLE* rowptr = (JSAMPLE*)bm->getPixels();
325         bm->unlockPixels();
326         bool reuseBitmap = (rowptr != NULL);
327         if (reuseBitmap && ((int) cinfo.output_width != bm->width() ||
328                 (int) cinfo.output_height != bm->height())) {
329             // Dimensions must match
330             return false;
331         }
332 
333         if (!reuseBitmap) {
334             bm->setConfig(config, cinfo.output_width, cinfo.output_height);
335             bm->setIsOpaque(true);
336             if (SkImageDecoder::kDecodeBounds_Mode == mode) {
337                 return true;
338             }
339             if (!this->allocPixelRef(bm, NULL)) {
340                 return return_false(cinfo, *bm, "allocPixelRef");
341             }
342         } else if (SkImageDecoder::kDecodeBounds_Mode == mode) {
343             return true;
344         }
345         SkAutoLockPixels alp(*bm);
346         rowptr = (JSAMPLE*)bm->getPixels();
347         INT32 const bpr =  bm->rowBytes();
348 
349         while (cinfo.output_scanline < cinfo.output_height) {
350             int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1);
351             // if row_count == 0, then we didn't get a scanline, so abort.
352             // if we supported partial images, we might return true in this case
353             if (0 == row_count) {
354                 return return_false(cinfo, *bm, "read_scanlines");
355             }
356             if (this->shouldCancelDecode()) {
357                 return return_false(cinfo, *bm, "shouldCancelDecode");
358             }
359             rowptr += bpr;
360         }
361         if (reuseBitmap) {
362             bm->notifyPixelsChanged();
363         }
364         jpeg_finish_decompress(&cinfo);
365         return true;
366     }
367 #endif
368 
369     // check for supported formats
370     SkScaledBitmapSampler::SrcConfig sc;
371     if (3 == cinfo.out_color_components && JCS_RGB == cinfo.out_color_space) {
372         sc = SkScaledBitmapSampler::kRGB;
373 #ifdef ANDROID_RGB
374     } else if (JCS_RGBA_8888 == cinfo.out_color_space) {
375         sc = SkScaledBitmapSampler::kRGBX;
376     } else if (JCS_RGB_565 == cinfo.out_color_space) {
377         sc = SkScaledBitmapSampler::kRGB_565;
378 #endif
379     } else if (1 == cinfo.out_color_components &&
380                JCS_GRAYSCALE == cinfo.out_color_space) {
381         sc = SkScaledBitmapSampler::kGray;
382     } else {
383         return return_false(cinfo, *bm, "jpeg colorspace");
384     }
385 
386     SkScaledBitmapSampler sampler(cinfo.output_width, cinfo.output_height,
387                                   sampleSize);
388 
389     bm->lockPixels();
390     JSAMPLE* rowptr = (JSAMPLE*)bm->getPixels();
391     bool reuseBitmap = (rowptr != NULL);
392     bm->unlockPixels();
393     if (reuseBitmap && (sampler.scaledWidth() != bm->width() ||
394             sampler.scaledHeight() != bm->height())) {
395         // Dimensions must match
396         return false;
397     }
398 
399     if (!reuseBitmap) {
400         bm->setConfig(config, sampler.scaledWidth(), sampler.scaledHeight());
401         // jpegs are always opaque (i.e. have no per-pixel alpha)
402         bm->setIsOpaque(true);
403 
404         if (SkImageDecoder::kDecodeBounds_Mode == mode) {
405             return true;
406         }
407         if (!this->allocPixelRef(bm, NULL)) {
408             return return_false(cinfo, *bm, "allocPixelRef");
409         }
410     } else if (SkImageDecoder::kDecodeBounds_Mode == mode) {
411         return true;
412     }
413 
414     SkAutoLockPixels alp(*bm);
415     if (!sampler.begin(bm, sc, this->getDitherImage())) {
416         return return_false(cinfo, *bm, "sampler.begin");
417     }
418 
419     uint8_t* srcRow = (uint8_t*)srcStorage.reset(cinfo.output_width * 4);
420 
421     //  Possibly skip initial rows [sampler.srcY0]
422     if (!skip_src_rows(&cinfo, srcRow, sampler.srcY0())) {
423         return return_false(cinfo, *bm, "skip rows");
424     }
425 
426     // now loop through scanlines until y == bm->height() - 1
427     for (int y = 0;; y++) {
428         JSAMPLE* rowptr = (JSAMPLE*)srcRow;
429         int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1);
430         if (0 == row_count) {
431             return return_false(cinfo, *bm, "read_scanlines");
432         }
433         if (this->shouldCancelDecode()) {
434             return return_false(cinfo, *bm, "shouldCancelDecode");
435         }
436 
437         sampler.next(srcRow);
438         if (bm->height() - 1 == y) {
439             // we're done
440             break;
441         }
442 
443         if (!skip_src_rows(&cinfo, srcRow, sampler.srcDY() - 1)) {
444             return return_false(cinfo, *bm, "skip rows");
445         }
446     }
447 
448     // we formally skip the rest, so we don't get a complaint from libjpeg
449     if (!skip_src_rows(&cinfo, srcRow,
450                        cinfo.output_height - cinfo.output_scanline)) {
451         return return_false(cinfo, *bm, "skip rows");
452     }
453     if (reuseBitmap) {
454         bm->notifyPixelsChanged();
455     }
456     jpeg_finish_decompress(&cinfo);
457 
458 //    SkDebugf("------------------- bm2 size %d [%d %d] %d\n", bm->getSize(), bm->width(), bm->height(), bm->config());
459     return true;
460 }
461 
onBuildTileIndex(SkStream * stream,int * width,int * height)462 bool SkJPEGImageDecoder::onBuildTileIndex(SkStream* stream,
463                                         int *width, int *height) {
464     SkAutoMalloc  srcStorage;
465     SkJPEGImageIndex *index = new SkJPEGImageIndex;
466 
467     jpeg_decompress_struct  *cinfo = (jpeg_decompress_struct*)
468                                         malloc(sizeof(jpeg_decompress_struct));
469     skjpeg_error_mgr        sk_err;
470     skjpeg_source_mgr       *sk_stream =
471         new skjpeg_source_mgr(stream, this, true);
472     if (cinfo == NULL || sk_stream == NULL) {
473         return false;
474     }
475 
476     cinfo->err = jpeg_std_error(&sk_err);
477     sk_err.error_exit = skjpeg_error_exit;
478 
479     // All objects need to be instantiated before this setjmp call so that
480     // they will be cleaned up properly if an error occurs.
481     if (setjmp(sk_err.fJmpBuf)) {
482         return false;
483     }
484 
485     jpeg_create_decompress(cinfo);
486     cinfo->do_fancy_upsampling = 0;
487     cinfo->do_block_smoothing = 0;
488 
489 #ifdef SK_BUILD_FOR_ANDROID
490     overwrite_mem_buffer_size(cinfo);
491 #endif
492 
493     cinfo->src = sk_stream;
494     int status = jpeg_read_header(cinfo, true);
495     if (status != JPEG_HEADER_OK) {
496         return false;
497     }
498     index->index = (huffman_index*)malloc(sizeof(huffman_index));
499     jpeg_create_huffman_index(cinfo, index->index);
500 
501     cinfo->scale_num = 1;
502     cinfo->scale_denom = 1;
503     if (!jpeg_build_huffman_index(cinfo, index->index)) {
504         return false;
505     }
506     if (fReporter)
507         fReporter->reportMemory(index->index->mem_used);
508     jpeg_destroy_decompress(cinfo);
509 
510 
511     // Init decoder to image decode mode
512     jpeg_create_decompress(cinfo);
513 
514 #ifdef SK_BUILD_FOR_ANDROID
515     overwrite_mem_buffer_size(cinfo);
516 #endif
517 
518     cinfo->src = sk_stream;
519     status = jpeg_read_header(cinfo,true);
520     if (status != JPEG_HEADER_OK) {
521         return false;
522     }
523     cinfo->out_color_space = JCS_RGBA_8888;
524     cinfo->do_fancy_upsampling = 0;
525     cinfo->do_block_smoothing = 0;
526     //jpeg_start_decompress(cinfo);
527     jpeg_start_tile_decompress(cinfo);
528 
529     cinfo->scale_num = 1;
530     index->cinfo = cinfo;
531     *height = cinfo->output_height;
532     *width = cinfo->output_width;
533     this->imageWidth = *width;
534     this->imageHeight = *height;
535     this->index = index;
536     return true;
537 }
538 
onDecodeRegion(SkBitmap * bm,SkIRect region)539 bool SkJPEGImageDecoder::onDecodeRegion(SkBitmap* bm, SkIRect region) {
540     if (index == NULL) {
541         return false;
542     }
543     jpeg_decompress_struct *cinfo = index->cinfo;
544 
545     SkIRect rect = SkIRect::MakeWH(this->imageWidth, this->imageHeight);
546     if (!rect.intersect(region)) {
547         // If the requested region is entirely outsides the image, just
548         // returns false
549         return false;
550     }
551     SkAutoMalloc  srcStorage;
552     skjpeg_error_mgr        sk_err;
553     cinfo->err = jpeg_std_error(&sk_err);
554     sk_err.error_exit = skjpeg_error_exit;
555     if (setjmp(sk_err.fJmpBuf)) {
556         return false;
557     }
558     int requestedSampleSize = this->getSampleSize();
559     cinfo->scale_denom = requestedSampleSize;
560 
561     if (this->getPreferQualityOverSpeed()) {
562         cinfo->dct_method = JDCT_ISLOW;
563     } else {
564         cinfo->dct_method = JDCT_IFAST;
565     }
566 
567     SkBitmap::Config config = this->getPrefConfig(k32Bit_SrcDepth, false);
568     if (config != SkBitmap::kARGB_8888_Config &&
569         config != SkBitmap::kARGB_4444_Config &&
570         config != SkBitmap::kRGB_565_Config) {
571         config = SkBitmap::kARGB_8888_Config;
572     }
573 
574     /* default format is RGB */
575     cinfo->out_color_space = JCS_RGB;
576 
577 #ifdef ANDROID_RGB
578     cinfo->dither_mode = JDITHER_NONE;
579     if (config == SkBitmap::kARGB_8888_Config) {
580         cinfo->out_color_space = JCS_RGBA_8888;
581     } else if (config == SkBitmap::kRGB_565_Config) {
582         cinfo->out_color_space = JCS_RGB_565;
583         if (this->getDitherImage()) {
584             cinfo->dither_mode = JDITHER_ORDERED;
585         }
586     }
587 #endif
588     int startX = rect.fLeft;
589     int startY = rect.fTop;
590     int width = rect.width();
591     int height = rect.height();
592 
593     jpeg_init_read_tile_scanline(cinfo, index->index,
594                                  &startX, &startY, &width, &height);
595     int skiaSampleSize = recompute_sampleSize(requestedSampleSize, *cinfo);
596     int actualSampleSize = skiaSampleSize * (DCTSIZE / cinfo->min_DCT_scaled_size);
597 
598     SkBitmap *bitmap = new SkBitmap;
599     SkAutoTDelete<SkBitmap> adb(bitmap);
600 
601 #ifdef ANDROID_RGB
602     /* short-circuit the SkScaledBitmapSampler when possible, as this gives
603        a significant performance boost.
604     */
605     if (skiaSampleSize == 1 &&
606         ((config == SkBitmap::kARGB_8888_Config &&
607                 cinfo->out_color_space == JCS_RGBA_8888) ||
608         (config == SkBitmap::kRGB_565_Config &&
609                 cinfo->out_color_space == JCS_RGB_565)))
610     {
611         bitmap->setConfig(config, cinfo->output_width, height);
612         bitmap->setIsOpaque(true);
613 
614         // Check ahead of time if the swap(dest, src) is possible or not.
615         // If yes, then we will stick to AllocPixelRef since it's cheaper
616         // with the swap happening. If no, then we will use alloc to allocate
617         // pixels to prevent garbage collection.
618         //
619         // Not using a recycled-bitmap and the output rect is same as the
620         // decoded region.
621         int w = rect.width() / actualSampleSize;
622         int h = rect.height() / actualSampleSize;
623         bool swapOnly = (rect == region) && bm->isNull() &&
624                         (w == bitmap->width()) && (h == bitmap->height()) &&
625                         ((startX - rect.x()) / actualSampleSize == 0) &&
626                         ((startY - rect.y()) / actualSampleSize == 0);
627         if (swapOnly) {
628             if (!this->allocPixelRef(bitmap, NULL)) {
629                 return return_false(*cinfo, *bitmap, "allocPixelRef");
630             }
631         } else {
632             if (!bitmap->allocPixels()) {
633                 return return_false(*cinfo, *bitmap, "allocPixels");
634             }
635         }
636 
637         SkAutoLockPixels alp(*bitmap);
638         JSAMPLE* rowptr = (JSAMPLE*)bitmap->getPixels();
639         INT32 const bpr = bitmap->rowBytes();
640         int row_total_count = 0;
641 
642         while (row_total_count < height) {
643             int row_count = jpeg_read_tile_scanline(cinfo,
644                     index->index, &rowptr);
645             // if row_count == 0, then we didn't get a scanline, so abort.
646             // if we supported partial images, we might return true in this case
647             if (0 == row_count) {
648                 return return_false(*cinfo, *bitmap, "read_scanlines");
649             }
650             if (this->shouldCancelDecode()) {
651                 return return_false(*cinfo, *bitmap, "shouldCancelDecode");
652             }
653             row_total_count += row_count;
654             rowptr += bpr;
655         }
656 
657         if (swapOnly) {
658             bm->swap(*bitmap);
659         } else {
660             cropBitmap(bm, bitmap, actualSampleSize, region.x(), region.y(),
661                        region.width(), region.height(), startX, startY);
662         }
663         return true;
664     }
665 #endif
666     // check for supported formats
667     SkScaledBitmapSampler::SrcConfig sc;
668     if (3 == cinfo->out_color_components && JCS_RGB == cinfo->out_color_space) {
669         sc = SkScaledBitmapSampler::kRGB;
670 #ifdef ANDROID_RGB
671     } else if (JCS_RGBA_8888 == cinfo->out_color_space) {
672         sc = SkScaledBitmapSampler::kRGBX;
673     } else if (JCS_RGB_565 == cinfo->out_color_space) {
674         sc = SkScaledBitmapSampler::kRGB_565;
675 #endif
676     } else if (1 == cinfo->out_color_components &&
677                JCS_GRAYSCALE == cinfo->out_color_space) {
678         sc = SkScaledBitmapSampler::kGray;
679     } else {
680         return return_false(*cinfo, *bm, "jpeg colorspace");
681     }
682 
683     SkScaledBitmapSampler sampler(width, height, skiaSampleSize);
684 
685     bitmap->setConfig(config, sampler.scaledWidth(), sampler.scaledHeight());
686     bitmap->setIsOpaque(true);
687 
688     // Check ahead of time if the swap(dest, src) is possible or not.
689     // If yes, then we will stick to AllocPixelRef since it's cheaper with the
690     // swap happening. If no, then we will use alloc to allocate pixels to
691     // prevent garbage collection.
692     int w = rect.width() / actualSampleSize;
693     int h = rect.height() / actualSampleSize;
694     bool swapOnly = (rect == region) && bm->isNull() &&
695                     (w == bitmap->width()) && (h == bitmap->height()) &&
696                     ((startX - rect.x()) / actualSampleSize == 0) &&
697                     ((startY - rect.y()) / actualSampleSize == 0);
698     if (swapOnly) {
699         if (!this->allocPixelRef(bitmap, NULL)) {
700             return return_false(*cinfo, *bitmap, "allocPixelRef");
701         }
702     } else {
703         if (!bitmap->allocPixels()) {
704             return return_false(*cinfo, *bitmap, "allocPixels");
705         }
706     }
707 
708     SkAutoLockPixels alp(*bitmap);
709     if (!sampler.begin(bitmap, sc, this->getDitherImage())) {
710         return return_false(*cinfo, *bitmap, "sampler.begin");
711     }
712 
713     uint8_t* srcRow = (uint8_t*)srcStorage.reset(width * 4);
714 
715     //  Possibly skip initial rows [sampler.srcY0]
716     if (!skip_src_rows_tile(cinfo, index->index, srcRow, sampler.srcY0())) {
717         return return_false(*cinfo, *bitmap, "skip rows");
718     }
719 
720     // now loop through scanlines until y == bitmap->height() - 1
721     for (int y = 0;; y++) {
722         JSAMPLE* rowptr = (JSAMPLE*)srcRow;
723         int row_count = jpeg_read_tile_scanline(cinfo, index->index, &rowptr);
724         if (0 == row_count) {
725             return return_false(*cinfo, *bitmap, "read_scanlines");
726         }
727         if (this->shouldCancelDecode()) {
728             return return_false(*cinfo, *bitmap, "shouldCancelDecode");
729         }
730 
731         sampler.next(srcRow);
732         if (bitmap->height() - 1 == y) {
733             // we're done
734             break;
735         }
736 
737         if (!skip_src_rows_tile(cinfo, index->index, srcRow,
738                                 sampler.srcDY() - 1)) {
739             return return_false(*cinfo, *bitmap, "skip rows");
740         }
741     }
742     if (swapOnly) {
743         bm->swap(*bitmap);
744     } else {
745         cropBitmap(bm, bitmap, actualSampleSize, region.x(), region.y(),
746                    region.width(), region.height(), startX, startY);
747     }
748     return true;
749 }
750 
751 ///////////////////////////////////////////////////////////////////////////////
752 
753 #include "SkColorPriv.h"
754 
755 // taken from jcolor.c in libjpeg
756 #if 0   // 16bit - precise but slow
757     #define CYR     19595   // 0.299
758     #define CYG     38470   // 0.587
759     #define CYB      7471   // 0.114
760 
761     #define CUR    -11059   // -0.16874
762     #define CUG    -21709   // -0.33126
763     #define CUB     32768   // 0.5
764 
765     #define CVR     32768   // 0.5
766     #define CVG    -27439   // -0.41869
767     #define CVB     -5329   // -0.08131
768 
769     #define CSHIFT  16
770 #else      // 8bit - fast, slightly less precise
771     #define CYR     77    // 0.299
772     #define CYG     150    // 0.587
773     #define CYB      29    // 0.114
774 
775     #define CUR     -43    // -0.16874
776     #define CUG    -85    // -0.33126
777     #define CUB     128    // 0.5
778 
779     #define CVR      128   // 0.5
780     #define CVG     -107   // -0.41869
781     #define CVB      -21   // -0.08131
782 
783     #define CSHIFT  8
784 #endif
785 
rgb2yuv_32(uint8_t dst[],SkPMColor c)786 static void rgb2yuv_32(uint8_t dst[], SkPMColor c) {
787     int r = SkGetPackedR32(c);
788     int g = SkGetPackedG32(c);
789     int b = SkGetPackedB32(c);
790 
791     int  y = ( CYR*r + CYG*g + CYB*b ) >> CSHIFT;
792     int  u = ( CUR*r + CUG*g + CUB*b ) >> CSHIFT;
793     int  v = ( CVR*r + CVG*g + CVB*b ) >> CSHIFT;
794 
795     dst[0] = SkToU8(y);
796     dst[1] = SkToU8(u + 128);
797     dst[2] = SkToU8(v + 128);
798 }
799 
rgb2yuv_4444(uint8_t dst[],U16CPU c)800 static void rgb2yuv_4444(uint8_t dst[], U16CPU c) {
801     int r = SkGetPackedR4444(c);
802     int g = SkGetPackedG4444(c);
803     int b = SkGetPackedB4444(c);
804 
805     int  y = ( CYR*r + CYG*g + CYB*b ) >> (CSHIFT - 4);
806     int  u = ( CUR*r + CUG*g + CUB*b ) >> (CSHIFT - 4);
807     int  v = ( CVR*r + CVG*g + CVB*b ) >> (CSHIFT - 4);
808 
809     dst[0] = SkToU8(y);
810     dst[1] = SkToU8(u + 128);
811     dst[2] = SkToU8(v + 128);
812 }
813 
rgb2yuv_16(uint8_t dst[],U16CPU c)814 static void rgb2yuv_16(uint8_t dst[], U16CPU c) {
815     int r = SkGetPackedR16(c);
816     int g = SkGetPackedG16(c);
817     int b = SkGetPackedB16(c);
818 
819     int  y = ( 2*CYR*r + CYG*g + 2*CYB*b ) >> (CSHIFT - 2);
820     int  u = ( 2*CUR*r + CUG*g + 2*CUB*b ) >> (CSHIFT - 2);
821     int  v = ( 2*CVR*r + CVG*g + 2*CVB*b ) >> (CSHIFT - 2);
822 
823     dst[0] = SkToU8(y);
824     dst[1] = SkToU8(u + 128);
825     dst[2] = SkToU8(v + 128);
826 }
827 
828 ///////////////////////////////////////////////////////////////////////////////
829 
830 typedef void (*WriteScanline)(uint8_t* SK_RESTRICT dst,
831                               const void* SK_RESTRICT src, int width,
832                               const SkPMColor* SK_RESTRICT ctable);
833 
Write_32_YUV(uint8_t * SK_RESTRICT dst,const void * SK_RESTRICT srcRow,int width,const SkPMColor *)834 static void Write_32_YUV(uint8_t* SK_RESTRICT dst,
835                          const void* SK_RESTRICT srcRow, int width,
836                          const SkPMColor*) {
837     const uint32_t* SK_RESTRICT src = (const uint32_t*)srcRow;
838     while (--width >= 0) {
839 #ifdef WE_CONVERT_TO_YUV
840         rgb2yuv_32(dst, *src++);
841 #else
842         uint32_t c = *src++;
843         dst[0] = SkGetPackedR32(c);
844         dst[1] = SkGetPackedG32(c);
845         dst[2] = SkGetPackedB32(c);
846 #endif
847         dst += 3;
848     }
849 }
850 
Write_4444_YUV(uint8_t * SK_RESTRICT dst,const void * SK_RESTRICT srcRow,int width,const SkPMColor *)851 static void Write_4444_YUV(uint8_t* SK_RESTRICT dst,
852                            const void* SK_RESTRICT srcRow, int width,
853                            const SkPMColor*) {
854     const SkPMColor16* SK_RESTRICT src = (const SkPMColor16*)srcRow;
855     while (--width >= 0) {
856 #ifdef WE_CONVERT_TO_YUV
857         rgb2yuv_4444(dst, *src++);
858 #else
859         SkPMColor16 c = *src++;
860         dst[0] = SkPacked4444ToR32(c);
861         dst[1] = SkPacked4444ToG32(c);
862         dst[2] = SkPacked4444ToB32(c);
863 #endif
864         dst += 3;
865     }
866 }
867 
Write_16_YUV(uint8_t * SK_RESTRICT dst,const void * SK_RESTRICT srcRow,int width,const SkPMColor *)868 static void Write_16_YUV(uint8_t* SK_RESTRICT dst,
869                          const void* SK_RESTRICT srcRow, int width,
870                          const SkPMColor*) {
871     const uint16_t* SK_RESTRICT src = (const uint16_t*)srcRow;
872     while (--width >= 0) {
873 #ifdef WE_CONVERT_TO_YUV
874         rgb2yuv_16(dst, *src++);
875 #else
876         uint16_t c = *src++;
877         dst[0] = SkPacked16ToR32(c);
878         dst[1] = SkPacked16ToG32(c);
879         dst[2] = SkPacked16ToB32(c);
880 #endif
881         dst += 3;
882     }
883 }
884 
Write_Index_YUV(uint8_t * SK_RESTRICT dst,const void * SK_RESTRICT srcRow,int width,const SkPMColor * SK_RESTRICT ctable)885 static void Write_Index_YUV(uint8_t* SK_RESTRICT dst,
886                             const void* SK_RESTRICT srcRow, int width,
887                             const SkPMColor* SK_RESTRICT ctable) {
888     const uint8_t* SK_RESTRICT src = (const uint8_t*)srcRow;
889     while (--width >= 0) {
890 #ifdef WE_CONVERT_TO_YUV
891         rgb2yuv_32(dst, ctable[*src++]);
892 #else
893         uint32_t c = ctable[*src++];
894         dst[0] = SkGetPackedR32(c);
895         dst[1] = SkGetPackedG32(c);
896         dst[2] = SkGetPackedB32(c);
897 #endif
898         dst += 3;
899     }
900 }
901 
ChooseWriter(const SkBitmap & bm)902 static WriteScanline ChooseWriter(const SkBitmap& bm) {
903     switch (bm.config()) {
904         case SkBitmap::kARGB_8888_Config:
905             return Write_32_YUV;
906         case SkBitmap::kRGB_565_Config:
907             return Write_16_YUV;
908         case SkBitmap::kARGB_4444_Config:
909             return Write_4444_YUV;
910         case SkBitmap::kIndex8_Config:
911             return Write_Index_YUV;
912         default:
913             return NULL;
914     }
915 }
916 
917 class SkJPEGImageEncoder : public SkImageEncoder {
918 protected:
onEncode(SkWStream * stream,const SkBitmap & bm,int quality)919     virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) {
920 #ifdef TIME_ENCODE
921         AutoTimeMillis atm("JPEG Encode");
922 #endif
923 
924         const WriteScanline writer = ChooseWriter(bm);
925         if (NULL == writer) {
926             return false;
927         }
928 
929         SkAutoLockPixels alp(bm);
930         if (NULL == bm.getPixels()) {
931             return false;
932         }
933 
934         jpeg_compress_struct    cinfo;
935         skjpeg_error_mgr        sk_err;
936         skjpeg_destination_mgr  sk_wstream(stream);
937 
938         // allocate these before set call setjmp
939         SkAutoMalloc    oneRow;
940         SkAutoLockColors ctLocker;
941 
942         cinfo.err = jpeg_std_error(&sk_err);
943         sk_err.error_exit = skjpeg_error_exit;
944         if (setjmp(sk_err.fJmpBuf)) {
945             return false;
946         }
947         jpeg_create_compress(&cinfo);
948 
949         cinfo.dest = &sk_wstream;
950         cinfo.image_width = bm.width();
951         cinfo.image_height = bm.height();
952         cinfo.input_components = 3;
953 #ifdef WE_CONVERT_TO_YUV
954         cinfo.in_color_space = JCS_YCbCr;
955 #else
956         cinfo.in_color_space = JCS_RGB;
957 #endif
958         cinfo.input_gamma = 1;
959 
960         jpeg_set_defaults(&cinfo);
961         jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
962         cinfo.dct_method = JDCT_IFAST;
963 
964         jpeg_start_compress(&cinfo, TRUE);
965 
966         const int       width = bm.width();
967         uint8_t*        oneRowP = (uint8_t*)oneRow.reset(width * 3);
968 
969         const SkPMColor* colors = ctLocker.lockColors(bm);
970         const void*      srcRow = bm.getPixels();
971 
972         while (cinfo.next_scanline < cinfo.image_height) {
973             JSAMPROW row_pointer[1];    /* pointer to JSAMPLE row[s] */
974 
975             writer(oneRowP, srcRow, width, colors);
976             row_pointer[0] = oneRowP;
977             (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
978             srcRow = (const void*)((const char*)srcRow + bm.rowBytes());
979         }
980 
981         jpeg_finish_compress(&cinfo);
982         jpeg_destroy_compress(&cinfo);
983 
984         return true;
985     }
986 };
987 
988 ///////////////////////////////////////////////////////////////////////////////
989 
990 #include "SkTRegistry.h"
991 
DFactory(SkStream * stream)992 static SkImageDecoder* DFactory(SkStream* stream) {
993     static const char gHeader[] = { 0xFF, 0xD8, 0xFF };
994     static const size_t HEADER_SIZE = sizeof(gHeader);
995 
996     char buffer[HEADER_SIZE];
997     size_t len = stream->read(buffer, HEADER_SIZE);
998 
999     if (len != HEADER_SIZE) {
1000         return NULL;   // can't read enough
1001     }
1002     if (memcmp(buffer, gHeader, HEADER_SIZE)) {
1003         return NULL;
1004     }
1005     return SkNEW(SkJPEGImageDecoder);
1006 }
1007 
EFactory(SkImageEncoder::Type t)1008 static SkImageEncoder* EFactory(SkImageEncoder::Type t) {
1009     return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL;
1010 }
1011 
1012 static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(DFactory);
1013 static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(EFactory);
1014