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