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