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