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