OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2007 The Android Open Source Project | 2 * Copyright 2007 The Android Open Source Project |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 | 8 |
9 #include "SkImageDecoder.h" | 9 #include "SkImageDecoder.h" |
10 #include "SkImageEncoder.h" | 10 #include "SkImageEncoder.h" |
11 #include "SkJpegUtility.h" | 11 #include "SkJpegUtility.h" |
12 #include "SkColorPriv.h" | 12 #include "SkColorPriv.h" |
13 #include "SkDither.h" | 13 #include "SkDither.h" |
14 #include "SkScaledBitmapSampler.h" | 14 #include "SkScaledBitmapSampler.h" |
15 #include "SkStream.h" | 15 #include "SkStream.h" |
16 #include "SkTemplates.h" | 16 #include "SkTemplates.h" |
17 #include "SkTime.h" | 17 #include "SkTime.h" |
18 #include "SkUtils.h" | 18 #include "SkUtils.h" |
19 #include "SkRTConf.h" | 19 #include "SkRTConf.h" |
20 #include "SkRect.h" | 20 #include "SkRect.h" |
21 #include "SkCanvas.h" | 21 #include "SkCanvas.h" |
22 | 22 |
23 | 23 |
24 #include <stdio.h> | 24 #include <stdio.h> |
25 extern "C" { | 25 extern "C" { |
| 26 #ifdef SK_BUILD_FOR_ANDROID |
| 27 #include "manglejpeglib.h" |
| 28 #else |
26 #include "jpeglib.h" | 29 #include "jpeglib.h" |
| 30 #endif |
27 #include "jerror.h" | 31 #include "jerror.h" |
28 } | 32 } |
29 | 33 |
30 // These enable timing code that report milliseconds for an encoding/decoding | 34 // These enable timing code that report milliseconds for an encoding/decoding |
31 //#define TIME_ENCODE | 35 //#define TIME_ENCODE |
32 //#define TIME_DECODE | 36 //#define TIME_DECODE |
33 | 37 |
34 // this enables our rgb->yuv code, which is faster than libjpeg on ARM | 38 // this enables our rgb->yuv code, which is faster than libjpeg on ARM |
35 #define WE_CONVERT_TO_YUV | 39 #define WE_CONVERT_TO_YUV |
36 | 40 |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
106 // attempt to delete this SkJPEGImageIndex, thus entering this | 110 // attempt to delete this SkJPEGImageIndex, thus entering this |
107 // destructor again. Setting fHuffmanCreated to false first | 111 // destructor again. Setting fHuffmanCreated to false first |
108 // prevents an infinite loop. | 112 // prevents an infinite loop. |
109 fHuffmanCreated = false; | 113 fHuffmanCreated = false; |
110 jpeg_destroy_huffman_index(&fHuffmanIndex); | 114 jpeg_destroy_huffman_index(&fHuffmanIndex); |
111 } | 115 } |
112 if (fDecompressStarted) { | 116 if (fDecompressStarted) { |
113 // Like fHuffmanCreated, set to false before calling libjpeg | 117 // Like fHuffmanCreated, set to false before calling libjpeg |
114 // function to prevent potential infinite loop. | 118 // function to prevent potential infinite loop. |
115 fDecompressStarted = false; | 119 fDecompressStarted = false; |
116 jpeg_finish_decompress(&fCInfo); | 120 jFinDecompress(&fCInfo); |
117 } | 121 } |
118 if (fInfoInitialized) { | 122 if (fInfoInitialized) { |
119 this->destroyInfo(); | 123 this->destroyInfo(); |
120 } | 124 } |
121 } | 125 } |
122 | 126 |
123 /** | 127 /** |
124 * Destroy the cinfo struct. | 128 * Destroy the cinfo struct. |
125 * After this call, if a huffman index was already built, it | 129 * After this call, if a huffman index was already built, it |
126 * can be used after calling initializeInfoAndReadHeader | 130 * can be used after calling initializeInfoAndReadHeader |
127 * again. Must not be called after startTileDecompress except | 131 * again. Must not be called after startTileDecompress except |
128 * in the destructor. | 132 * in the destructor. |
129 */ | 133 */ |
130 void destroyInfo() { | 134 void destroyInfo() { |
131 SkASSERT(fInfoInitialized); | 135 SkASSERT(fInfoInitialized); |
132 SkASSERT(!fDecompressStarted); | 136 SkASSERT(!fDecompressStarted); |
133 // Like fHuffmanCreated, set to false before calling libjpeg | 137 // Like fHuffmanCreated, set to false before calling libjpeg |
134 // function to prevent potential infinite loop. | 138 // function to prevent potential infinite loop. |
135 fInfoInitialized = false; | 139 fInfoInitialized = false; |
136 jpeg_destroy_decompress(&fCInfo); | 140 jDestDecompress(&fCInfo); |
137 SkDEBUGCODE(fReadHeaderSucceeded = false;) | 141 SkDEBUGCODE(fReadHeaderSucceeded = false;) |
138 } | 142 } |
139 | 143 |
140 /** | 144 /** |
141 * Initialize the cinfo struct. | 145 * Initialize the cinfo struct. |
142 * Calls jpeg_create_decompress, makes customizations, and | 146 * Calls jpeg_create_decompress, makes customizations, and |
143 * finally calls jpeg_read_header. Returns true if jpeg_read_header | 147 * finally calls jReadHeader. Returns true if jReadHeader |
144 * returns JPEG_HEADER_OK. | 148 * returns JPEG_HEADER_OK. |
145 * If cinfo was already initialized, destroyInfo must be called to | 149 * If cinfo was already initialized, destroyInfo must be called to |
146 * destroy the old one. Must not be called after startTileDecompress. | 150 * destroy the old one. Must not be called after startTileDecompress. |
147 */ | 151 */ |
148 bool initializeInfoAndReadHeader() { | 152 bool initializeInfoAndReadHeader() { |
149 SkASSERT(!fInfoInitialized && !fDecompressStarted); | 153 SkASSERT(!fInfoInitialized && !fDecompressStarted); |
150 initialize_info(&fCInfo, &fSrcMgr); | 154 initialize_info(&fCInfo, &fSrcMgr); |
151 fInfoInitialized = true; | 155 fInfoInitialized = true; |
152 const bool success = (JPEG_HEADER_OK == jpeg_read_header(&fCInfo, true))
; | 156 const bool success = (JPEG_HEADER_OK == jReadHeader(&fCInfo, true)); |
153 SkDEBUGCODE(fReadHeaderSucceeded = success;) | 157 SkDEBUGCODE(fReadHeaderSucceeded = success;) |
154 return success; | 158 return success; |
155 } | 159 } |
156 | 160 |
157 jpeg_decompress_struct* cinfo() { return &fCInfo; } | 161 jpeg_decompress_struct* cinfo() { return &fCInfo; } |
158 | 162 |
159 huffman_index* huffmanIndex() { return &fHuffmanIndex; } | 163 huffman_index* huffmanIndex() { return &fHuffmanIndex; } |
160 | 164 |
161 /** | 165 /** |
162 * Build the index to be used for tile based decoding. | 166 * Build the index to be used for tile based decoding. |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
233 #ifdef SK_BUILD_FOR_ANDROID | 237 #ifdef SK_BUILD_FOR_ANDROID |
234 SkJPEGImageIndex* fImageIndex; | 238 SkJPEGImageIndex* fImageIndex; |
235 int fImageWidth; | 239 int fImageWidth; |
236 int fImageHeight; | 240 int fImageHeight; |
237 #endif | 241 #endif |
238 | 242 |
239 /** | 243 /** |
240 * Determine the appropriate bitmap colortype and out_color_space based on | 244 * Determine the appropriate bitmap colortype and out_color_space based on |
241 * both the preference of the caller and the jpeg_color_space on the | 245 * both the preference of the caller and the jpeg_color_space on the |
242 * jpeg_decompress_struct passed in. | 246 * jpeg_decompress_struct passed in. |
243 * Must be called after jpeg_read_header. | 247 * Must be called after jReadHeader. |
244 */ | 248 */ |
245 SkColorType getBitmapColorType(jpeg_decompress_struct*); | 249 SkColorType getBitmapColorType(jpeg_decompress_struct*); |
246 | 250 |
247 typedef SkImageDecoder INHERITED; | 251 typedef SkImageDecoder INHERITED; |
248 }; | 252 }; |
249 | 253 |
250 ////////////////////////////////////////////////////////////////////////// | 254 ////////////////////////////////////////////////////////////////////////// |
251 | 255 |
252 /* Automatically clean up after throwing an exception */ | 256 /* Automatically clean up after throwing an exception */ |
253 class JPEGAutoClean { | 257 class JPEGAutoClean { |
254 public: | 258 public: |
255 JPEGAutoClean(): cinfo_ptr(NULL) {} | 259 JPEGAutoClean(): cinfo_ptr(NULL) {} |
256 ~JPEGAutoClean() { | 260 ~JPEGAutoClean() { |
257 if (cinfo_ptr) { | 261 if (cinfo_ptr) { |
258 jpeg_destroy_decompress(cinfo_ptr); | 262 jDestDecompress(cinfo_ptr); |
259 } | 263 } |
260 } | 264 } |
261 void set(jpeg_decompress_struct* info) { | 265 void set(jpeg_decompress_struct* info) { |
262 cinfo_ptr = info; | 266 cinfo_ptr = info; |
263 } | 267 } |
264 private: | 268 private: |
265 jpeg_decompress_struct* cinfo_ptr; | 269 jpeg_decompress_struct* cinfo_ptr; |
266 }; | 270 }; |
267 | 271 |
268 /////////////////////////////////////////////////////////////////////////////// | 272 /////////////////////////////////////////////////////////////////////////////// |
(...skipping 13 matching lines...) Expand all Loading... |
282 static bool valid_output_dimensions(const jpeg_decompress_struct& cinfo) { | 286 static bool valid_output_dimensions(const jpeg_decompress_struct& cinfo) { |
283 /* These are initialized to 0, so if they have non-zero values, we assume | 287 /* These are initialized to 0, so if they have non-zero values, we assume |
284 they are "valid" (i.e. have been computed by libjpeg) | 288 they are "valid" (i.e. have been computed by libjpeg) |
285 */ | 289 */ |
286 return 0 != cinfo.output_width && 0 != cinfo.output_height; | 290 return 0 != cinfo.output_width && 0 != cinfo.output_height; |
287 } | 291 } |
288 | 292 |
289 static bool skip_src_rows(jpeg_decompress_struct* cinfo, void* buffer, int count
) { | 293 static bool skip_src_rows(jpeg_decompress_struct* cinfo, void* buffer, int count
) { |
290 for (int i = 0; i < count; i++) { | 294 for (int i = 0; i < count; i++) { |
291 JSAMPLE* rowptr = (JSAMPLE*)buffer; | 295 JSAMPLE* rowptr = (JSAMPLE*)buffer; |
292 int row_count = jpeg_read_scanlines(cinfo, &rowptr, 1); | 296 int row_count = jReadScanlines(cinfo, &rowptr, 1); |
293 if (1 != row_count) { | 297 if (1 != row_count) { |
294 return false; | 298 return false; |
295 } | 299 } |
296 } | 300 } |
297 return true; | 301 return true; |
298 } | 302 } |
299 | 303 |
300 #ifdef SK_BUILD_FOR_ANDROID | 304 #ifdef SK_BUILD_FOR_ANDROID |
301 static bool skip_src_rows_tile(jpeg_decompress_struct* cinfo, | 305 static bool skip_src_rows_tile(jpeg_decompress_struct* cinfo, |
302 huffman_index *index, void* buffer, int count) { | 306 huffman_index *index, void* buffer, int count) { |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
369 scanline[3] = 255; | 373 scanline[3] = 255; |
370 } | 374 } |
371 } | 375 } |
372 | 376 |
373 /** | 377 /** |
374 * Common code for setting the error manager. | 378 * Common code for setting the error manager. |
375 */ | 379 */ |
376 static void set_error_mgr(jpeg_decompress_struct* cinfo, skjpeg_error_mgr* error
Manager) { | 380 static void set_error_mgr(jpeg_decompress_struct* cinfo, skjpeg_error_mgr* error
Manager) { |
377 SkASSERT(cinfo != NULL); | 381 SkASSERT(cinfo != NULL); |
378 SkASSERT(errorManager != NULL); | 382 SkASSERT(errorManager != NULL); |
379 cinfo->err = jpeg_std_error(errorManager); | 383 cinfo->err = jStdError(errorManager); |
380 errorManager->error_exit = skjpeg_error_exit; | 384 errorManager->error_exit = skjpeg_error_exit; |
381 } | 385 } |
382 | 386 |
383 /** | 387 /** |
384 * Common code for turning off upsampling and smoothing. Turning these | 388 * Common code for turning off upsampling and smoothing. Turning these |
385 * off helps performance without showing noticable differences in the | 389 * off helps performance without showing noticable differences in the |
386 * resulting bitmap. | 390 * resulting bitmap. |
387 */ | 391 */ |
388 static void turn_off_visual_optimizations(jpeg_decompress_struct* cinfo) { | 392 static void turn_off_visual_optimizations(jpeg_decompress_struct* cinfo) { |
389 SkASSERT(cinfo != NULL); | 393 SkASSERT(cinfo != NULL); |
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
555 | 559 |
556 // All objects need to be instantiated before this setjmp call so that | 560 // All objects need to be instantiated before this setjmp call so that |
557 // they will be cleaned up properly if an error occurs. | 561 // they will be cleaned up properly if an error occurs. |
558 if (setjmp(errorManager.fJmpBuf)) { | 562 if (setjmp(errorManager.fJmpBuf)) { |
559 return return_failure(cinfo, *bm, "setjmp"); | 563 return return_failure(cinfo, *bm, "setjmp"); |
560 } | 564 } |
561 | 565 |
562 initialize_info(&cinfo, &srcManager); | 566 initialize_info(&cinfo, &srcManager); |
563 autoClean.set(&cinfo); | 567 autoClean.set(&cinfo); |
564 | 568 |
565 int status = jpeg_read_header(&cinfo, true); | 569 int status = jReadHeader(&cinfo, true); |
566 if (status != JPEG_HEADER_OK) { | 570 if (status != JPEG_HEADER_OK) { |
567 return return_failure(cinfo, *bm, "read_header"); | 571 return return_failure(cinfo, *bm, "read_header"); |
568 } | 572 } |
569 | 573 |
570 /* Try to fulfill the requested sampleSize. Since jpeg can do it (when it | 574 /* Try to fulfill the requested sampleSize. Since jpeg can do it (when it |
571 can) much faster that we, just use their num/denom api to approximate | 575 can) much faster that we, just use their num/denom api to approximate |
572 the size. | 576 the size. |
573 */ | 577 */ |
574 int sampleSize = this->getSampleSize(); | 578 int sampleSize = this->getSampleSize(); |
575 | 579 |
(...skipping 14 matching lines...) Expand all Loading... |
590 // Assume an A8 bitmap is not opaque to avoid the check of each | 594 // Assume an A8 bitmap is not opaque to avoid the check of each |
591 // individual pixel. It is very unlikely to be opaque, since | 595 // individual pixel. It is very unlikely to be opaque, since |
592 // an opaque A8 bitmap would not be very interesting. | 596 // an opaque A8 bitmap would not be very interesting. |
593 // Otherwise, a jpeg image is opaque. | 597 // Otherwise, a jpeg image is opaque. |
594 bool success = bm->setInfo(SkImageInfo::Make(cinfo.image_width, cinfo.im
age_height, | 598 bool success = bm->setInfo(SkImageInfo::Make(cinfo.image_width, cinfo.im
age_height, |
595 colorType, alphaType)); | 599 colorType, alphaType)); |
596 return success ? kSuccess : kFailure; | 600 return success ? kSuccess : kFailure; |
597 } | 601 } |
598 | 602 |
599 /* image_width and image_height are the original dimensions, available | 603 /* image_width and image_height are the original dimensions, available |
600 after jpeg_read_header(). To see the scaled dimensions, we have to call | 604 after jReadHeader(). To see the scaled dimensions, we have to call |
601 jpeg_start_decompress(), and then read output_width and output_height. | 605 jStrtDecompress(), and then read output_width and output_height. |
602 */ | 606 */ |
603 if (!jpeg_start_decompress(&cinfo)) { | 607 if (!jStrtDecompress(&cinfo)) { |
604 /* If we failed here, we may still have enough information to return | 608 /* If we failed here, we may still have enough information to return |
605 to the caller if they just wanted (subsampled bounds). If sampleSize | 609 to the caller if they just wanted (subsampled bounds). If sampleSize |
606 was 1, then we would have already returned. Thus we just check if | 610 was 1, then we would have already returned. Thus we just check if |
607 we're in kDecodeBounds_Mode, and that we have valid output sizes. | 611 we're in kDecodeBounds_Mode, and that we have valid output sizes. |
608 | 612 |
609 One reason to fail here is that we have insufficient stream data | 613 One reason to fail here is that we have insufficient stream data |
610 to complete the setup. However, output dimensions seem to get | 614 to complete the setup. However, output dimensions seem to get |
611 computed very early, which is why this special check can pay off. | 615 computed very early, which is why this special check can pay off. |
612 */ | 616 */ |
613 if (SkImageDecoder::kDecodeBounds_Mode == mode && valid_output_dimension
s(cinfo)) { | 617 if (SkImageDecoder::kDecodeBounds_Mode == mode && valid_output_dimension
s(cinfo)) { |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
647 a significant performance boost. | 651 a significant performance boost. |
648 */ | 652 */ |
649 if (sampleSize == 1 && | 653 if (sampleSize == 1 && |
650 ((kN32_SkColorType == colorType && cinfo.out_color_space == JCS_RGBA_888
8) || | 654 ((kN32_SkColorType == colorType && cinfo.out_color_space == JCS_RGBA_888
8) || |
651 (kRGB_565_SkColorType == colorType && cinfo.out_color_space == JCS_RGB_
565))) | 655 (kRGB_565_SkColorType == colorType && cinfo.out_color_space == JCS_RGB_
565))) |
652 { | 656 { |
653 JSAMPLE* rowptr = (JSAMPLE*)bm->getPixels(); | 657 JSAMPLE* rowptr = (JSAMPLE*)bm->getPixels(); |
654 INT32 const bpr = bm->rowBytes(); | 658 INT32 const bpr = bm->rowBytes(); |
655 | 659 |
656 while (cinfo.output_scanline < cinfo.output_height) { | 660 while (cinfo.output_scanline < cinfo.output_height) { |
657 int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1); | 661 int row_count = jReadScanlines(&cinfo, &rowptr, 1); |
658 if (0 == row_count) { | 662 if (0 == row_count) { |
659 // if row_count == 0, then we didn't get a scanline, | 663 // if row_count == 0, then we didn't get a scanline, |
660 // so return early. We will return a partial image. | 664 // so return early. We will return a partial image. |
661 fill_below_level(cinfo.output_scanline, bm); | 665 fill_below_level(cinfo.output_scanline, bm); |
662 cinfo.output_scanline = cinfo.output_height; | 666 cinfo.output_scanline = cinfo.output_height; |
663 jpeg_finish_decompress(&cinfo); | 667 jFinDecompress(&cinfo); |
664 return kPartialSuccess; | 668 return kPartialSuccess; |
665 } | 669 } |
666 if (this->shouldCancelDecode()) { | 670 if (this->shouldCancelDecode()) { |
667 return return_failure(cinfo, *bm, "shouldCancelDecode"); | 671 return return_failure(cinfo, *bm, "shouldCancelDecode"); |
668 } | 672 } |
669 rowptr += bpr; | 673 rowptr += bpr; |
670 } | 674 } |
671 jpeg_finish_decompress(&cinfo); | 675 jFinDecompress(&cinfo); |
672 return kSuccess; | 676 return kSuccess; |
673 } | 677 } |
674 #endif | 678 #endif |
675 | 679 |
676 // check for supported formats | 680 // check for supported formats |
677 SkScaledBitmapSampler::SrcConfig sc; | 681 SkScaledBitmapSampler::SrcConfig sc; |
678 int srcBytesPerPixel; | 682 int srcBytesPerPixel; |
679 | 683 |
680 if (!get_src_config(cinfo, &sc, &srcBytesPerPixel)) { | 684 if (!get_src_config(cinfo, &sc, &srcBytesPerPixel)) { |
681 return return_failure(cinfo, *bm, "jpeg colorspace"); | 685 return return_failure(cinfo, *bm, "jpeg colorspace"); |
682 } | 686 } |
683 | 687 |
684 if (!sampler.begin(bm, sc, *this)) { | 688 if (!sampler.begin(bm, sc, *this)) { |
685 return return_failure(cinfo, *bm, "sampler.begin"); | 689 return return_failure(cinfo, *bm, "sampler.begin"); |
686 } | 690 } |
687 | 691 |
688 SkAutoMalloc srcStorage(cinfo.output_width * srcBytesPerPixel); | 692 SkAutoMalloc srcStorage(cinfo.output_width * srcBytesPerPixel); |
689 uint8_t* srcRow = (uint8_t*)srcStorage.get(); | 693 uint8_t* srcRow = (uint8_t*)srcStorage.get(); |
690 | 694 |
691 // Possibly skip initial rows [sampler.srcY0] | 695 // Possibly skip initial rows [sampler.srcY0] |
692 if (!skip_src_rows(&cinfo, srcRow, sampler.srcY0())) { | 696 if (!skip_src_rows(&cinfo, srcRow, sampler.srcY0())) { |
693 return return_failure(cinfo, *bm, "skip rows"); | 697 return return_failure(cinfo, *bm, "skip rows"); |
694 } | 698 } |
695 | 699 |
696 // now loop through scanlines until y == bm->height() - 1 | 700 // now loop through scanlines until y == bm->height() - 1 |
697 for (int y = 0;; y++) { | 701 for (int y = 0;; y++) { |
698 JSAMPLE* rowptr = (JSAMPLE*)srcRow; | 702 JSAMPLE* rowptr = (JSAMPLE*)srcRow; |
699 int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1); | 703 int row_count = jReadScanlines(&cinfo, &rowptr, 1); |
700 if (0 == row_count) { | 704 if (0 == row_count) { |
701 // if row_count == 0, then we didn't get a scanline, | 705 // if row_count == 0, then we didn't get a scanline, |
702 // so return early. We will return a partial image. | 706 // so return early. We will return a partial image. |
703 fill_below_level(y, bm); | 707 fill_below_level(y, bm); |
704 cinfo.output_scanline = cinfo.output_height; | 708 cinfo.output_scanline = cinfo.output_height; |
705 jpeg_finish_decompress(&cinfo); | 709 jFinDecompress(&cinfo); |
706 return kPartialSuccess; | 710 return kPartialSuccess; |
707 } | 711 } |
708 if (this->shouldCancelDecode()) { | 712 if (this->shouldCancelDecode()) { |
709 return return_failure(cinfo, *bm, "shouldCancelDecode"); | 713 return return_failure(cinfo, *bm, "shouldCancelDecode"); |
710 } | 714 } |
711 | 715 |
712 if (JCS_CMYK == cinfo.out_color_space) { | 716 if (JCS_CMYK == cinfo.out_color_space) { |
713 convert_CMYK_to_RGB(srcRow, cinfo.output_width); | 717 convert_CMYK_to_RGB(srcRow, cinfo.output_width); |
714 } | 718 } |
715 | 719 |
716 sampler.next(srcRow); | 720 sampler.next(srcRow); |
717 if (bm->height() - 1 == y) { | 721 if (bm->height() - 1 == y) { |
718 // we're done | 722 // we're done |
719 break; | 723 break; |
720 } | 724 } |
721 | 725 |
722 if (!skip_src_rows(&cinfo, srcRow, sampler.srcDY() - 1)) { | 726 if (!skip_src_rows(&cinfo, srcRow, sampler.srcDY() - 1)) { |
723 return return_failure(cinfo, *bm, "skip rows"); | 727 return return_failure(cinfo, *bm, "skip rows"); |
724 } | 728 } |
725 } | 729 } |
726 | 730 |
727 // we formally skip the rest, so we don't get a complaint from libjpeg | 731 // we formally skip the rest, so we don't get a complaint from libjpeg |
728 if (!skip_src_rows(&cinfo, srcRow, | 732 if (!skip_src_rows(&cinfo, srcRow, |
729 cinfo.output_height - cinfo.output_scanline)) { | 733 cinfo.output_height - cinfo.output_scanline)) { |
730 return return_failure(cinfo, *bm, "skip rows"); | 734 return return_failure(cinfo, *bm, "skip rows"); |
731 } | 735 } |
732 jpeg_finish_decompress(&cinfo); | 736 jFinDecompress(&cinfo); |
733 | 737 |
734 return kSuccess; | 738 return kSuccess; |
735 } | 739 } |
736 | 740 |
737 /////////////////////////////////////////////////////////////////////////////// | 741 /////////////////////////////////////////////////////////////////////////////// |
738 | 742 |
739 enum SizeType { | 743 enum SizeType { |
740 kSizeForMemoryAllocation_SizeType, | 744 kSizeForMemoryAllocation_SizeType, |
741 kActualSize_SizeType | 745 kActualSize_SizeType |
742 }; | 746 }; |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
828 bufferraw2[24 + i] = &outputV[scanline * rowBytesV]; | 832 bufferraw2[24 + i] = &outputV[scanline * rowBytesV]; |
829 } else if (scanline == uvMaxH) { | 833 } else if (scanline == uvMaxH) { |
830 bufferraw2[16 + i] = uLastRow; | 834 bufferraw2[16 + i] = uLastRow; |
831 bufferraw2[24 + i] = vLastRow; | 835 bufferraw2[24 + i] = vLastRow; |
832 hasUVLastRow = true; | 836 hasUVLastRow = true; |
833 } else { | 837 } else { |
834 bufferraw2[16 + i] = dummyRow; | 838 bufferraw2[16 + i] = dummyRow; |
835 bufferraw2[24 + i] = dummyRow; | 839 bufferraw2[24 + i] = dummyRow; |
836 } | 840 } |
837 } | 841 } |
838 JDIMENSION scanlinesRead = jpeg_read_raw_data(&cinfo, bufferraw, yScanli
nesToRead); | 842 JDIMENSION scanlinesRead = jReadRawData(&cinfo, bufferraw, yScanlinesToR
ead); |
839 | 843 |
840 if (scanlinesRead == 0) { | 844 if (scanlinesRead == 0) { |
841 return false; | 845 return false; |
842 } | 846 } |
843 | 847 |
844 if (hasYLastRow) { | 848 if (hasYLastRow) { |
845 memcpy(&outputY[yMaxH * rowBytesY], yLastRow, yWidth); | 849 memcpy(&outputY[yMaxH * rowBytesY], yLastRow, yWidth); |
846 } | 850 } |
847 if (hasUVLastRow) { | 851 if (hasUVLastRow) { |
848 memcpy(&outputU[uvMaxH * rowBytesU], uLastRow, uvSize.width()); | 852 memcpy(&outputU[uvMaxH * rowBytesU], uLastRow, uvSize.width()); |
(...skipping 26 matching lines...) Expand all Loading... |
875 | 879 |
876 // All objects need to be instantiated before this setjmp call so that | 880 // All objects need to be instantiated before this setjmp call so that |
877 // they will be cleaned up properly if an error occurs. | 881 // they will be cleaned up properly if an error occurs. |
878 if (setjmp(errorManager.fJmpBuf)) { | 882 if (setjmp(errorManager.fJmpBuf)) { |
879 return return_false(cinfo, "setjmp YUV8"); | 883 return return_false(cinfo, "setjmp YUV8"); |
880 } | 884 } |
881 | 885 |
882 initialize_info(&cinfo, &srcManager); | 886 initialize_info(&cinfo, &srcManager); |
883 autoClean.set(&cinfo); | 887 autoClean.set(&cinfo); |
884 | 888 |
885 int status = jpeg_read_header(&cinfo, true); | 889 int status = jReadHeader(&cinfo, true); |
886 if (status != JPEG_HEADER_OK) { | 890 if (status != JPEG_HEADER_OK) { |
887 return return_false(cinfo, "read_header YUV8"); | 891 return return_false(cinfo, "read_header YUV8"); |
888 } | 892 } |
889 | 893 |
890 if (!appears_to_be_yuv(cinfo)) { | 894 if (!appears_to_be_yuv(cinfo)) { |
891 // It's not an error to not be encoded in YUV, so no need to use return_
false() | 895 // It's not an error to not be encoded in YUV, so no need to use return_
false() |
892 return false; | 896 return false; |
893 } | 897 } |
894 | 898 |
895 cinfo.out_color_space = JCS_YCbCr; | 899 cinfo.out_color_space = JCS_YCbCr; |
896 cinfo.raw_data_out = TRUE; | 900 cinfo.raw_data_out = TRUE; |
897 | 901 |
898 if (!planes || !planes[0] || !rowBytes || !rowBytes[0]) { // Compute size on
ly | 902 if (!planes || !planes[0] || !rowBytes || !rowBytes[0]) { // Compute size on
ly |
899 update_components_sizes(cinfo, componentSizes, kSizeForMemoryAllocation_
SizeType); | 903 update_components_sizes(cinfo, componentSizes, kSizeForMemoryAllocation_
SizeType); |
900 return true; | 904 return true; |
901 } | 905 } |
902 | 906 |
903 set_dct_method(*this, &cinfo); | 907 set_dct_method(*this, &cinfo); |
904 | 908 |
905 SkASSERT(1 == cinfo.scale_num); | 909 SkASSERT(1 == cinfo.scale_num); |
906 cinfo.scale_denom = 1; | 910 cinfo.scale_denom = 1; |
907 | 911 |
908 turn_off_visual_optimizations(&cinfo); | 912 turn_off_visual_optimizations(&cinfo); |
909 | 913 |
910 #ifdef ANDROID_RGB | 914 #ifdef ANDROID_RGB |
911 cinfo.dither_mode = JDITHER_NONE; | 915 cinfo.dither_mode = JDITHER_NONE; |
912 #endif | 916 #endif |
913 | 917 |
914 /* image_width and image_height are the original dimensions, available | 918 /* image_width and image_height are the original dimensions, available |
915 after jpeg_read_header(). To see the scaled dimensions, we have to call | 919 after jReadHeader(). To see the scaled dimensions, we have to call |
916 jpeg_start_decompress(), and then read output_width and output_height. | 920 jStrtDecompress(), and then read output_width and output_height. |
917 */ | 921 */ |
918 if (!jpeg_start_decompress(&cinfo)) { | 922 if (!jStrtDecompress(&cinfo)) { |
919 return return_false(cinfo, "start_decompress YUV8"); | 923 return return_false(cinfo, "start_decompress YUV8"); |
920 } | 924 } |
921 | 925 |
922 // Seems like jpeg_start_decompress is updating our opinion of whether cinfo
represents YUV. | 926 // Seems like jStrtDecompress is updating our opinion of whether cinfo repre
sents YUV. |
923 // Again, not really an error. | 927 // Again, not really an error. |
924 if (!appears_to_be_yuv(cinfo)) { | 928 if (!appears_to_be_yuv(cinfo)) { |
925 return false; | 929 return false; |
926 } | 930 } |
927 | 931 |
928 if (!output_raw_data(cinfo, planes, rowBytes)) { | 932 if (!output_raw_data(cinfo, planes, rowBytes)) { |
929 return return_false(cinfo, "output_raw_data"); | 933 return return_false(cinfo, "output_raw_data"); |
930 } | 934 } |
931 | 935 |
932 update_components_sizes(cinfo, componentSizes, kActualSize_SizeType); | 936 update_components_sizes(cinfo, componentSizes, kActualSize_SizeType); |
933 jpeg_finish_decompress(&cinfo); | 937 jFinDecompress(&cinfo); |
934 | 938 |
935 if (NULL != colorSpace) { | 939 if (NULL != colorSpace) { |
936 *colorSpace = kJPEG_SkYUVColorSpace; | 940 *colorSpace = kJPEG_SkYUVColorSpace; |
937 } | 941 } |
938 | 942 |
939 return true; | 943 return true; |
940 } | 944 } |
941 | 945 |
942 /////////////////////////////////////////////////////////////////////////////// | 946 /////////////////////////////////////////////////////////////////////////////// |
943 | 947 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
977 set_error_mgr(cinfo, &sk_err); | 981 set_error_mgr(cinfo, &sk_err); |
978 | 982 |
979 // FIXME: This sets cinfo->out_color_space, which we may change later | 983 // FIXME: This sets cinfo->out_color_space, which we may change later |
980 // based on the config in onDecodeSubset. This should be fine, since | 984 // based on the config in onDecodeSubset. This should be fine, since |
981 // jpeg_init_read_tile_scanline will check out_color_space again after | 985 // jpeg_init_read_tile_scanline will check out_color_space again after |
982 // that change (when it calls jinit_color_deconverter). | 986 // that change (when it calls jinit_color_deconverter). |
983 (void) this->getBitmapColorType(cinfo); | 987 (void) this->getBitmapColorType(cinfo); |
984 | 988 |
985 turn_off_visual_optimizations(cinfo); | 989 turn_off_visual_optimizations(cinfo); |
986 | 990 |
987 // instead of jpeg_start_decompress() we start a tiled decompress | 991 // instead of jStrtDecompress() we start a tiled decompress |
988 if (!imageIndex->startTileDecompress()) { | 992 if (!imageIndex->startTileDecompress()) { |
989 return false; | 993 return false; |
990 } | 994 } |
991 | 995 |
992 SkASSERT(1 == cinfo->scale_num); | 996 SkASSERT(1 == cinfo->scale_num); |
993 fImageWidth = cinfo->output_width; | 997 fImageWidth = cinfo->output_width; |
994 fImageHeight = cinfo->output_height; | 998 fImageHeight = cinfo->output_height; |
995 | 999 |
996 if (width) { | 1000 if (width) { |
997 *width = fImageWidth; | 1001 *width = fImageWidth; |
(...skipping 354 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1352 return false; | 1356 return false; |
1353 } | 1357 } |
1354 | 1358 |
1355 jpeg_compress_struct cinfo; | 1359 jpeg_compress_struct cinfo; |
1356 skjpeg_error_mgr sk_err; | 1360 skjpeg_error_mgr sk_err; |
1357 skjpeg_destination_mgr sk_wstream(stream); | 1361 skjpeg_destination_mgr sk_wstream(stream); |
1358 | 1362 |
1359 // allocate these before set call setjmp | 1363 // allocate these before set call setjmp |
1360 SkAutoMalloc oneRow; | 1364 SkAutoMalloc oneRow; |
1361 | 1365 |
1362 cinfo.err = jpeg_std_error(&sk_err); | 1366 cinfo.err = jStdError(&sk_err); |
1363 sk_err.error_exit = skjpeg_error_exit; | 1367 sk_err.error_exit = skjpeg_error_exit; |
1364 if (setjmp(sk_err.fJmpBuf)) { | 1368 if (setjmp(sk_err.fJmpBuf)) { |
1365 return false; | 1369 return false; |
1366 } | 1370 } |
1367 | 1371 |
1368 // Keep after setjmp or mark volatile. | 1372 // Keep after setjmp or mark volatile. |
1369 const WriteScanline writer = ChooseWriter(bm); | 1373 const WriteScanline writer = ChooseWriter(bm); |
1370 if (NULL == writer) { | 1374 if (NULL == writer) { |
1371 return false; | 1375 return false; |
1372 } | 1376 } |
1373 | 1377 |
1374 jpeg_create_compress(&cinfo); | 1378 jpeg_create_compress(&cinfo); |
1375 cinfo.dest = &sk_wstream; | 1379 cinfo.dest = &sk_wstream; |
1376 cinfo.image_width = bm.width(); | 1380 cinfo.image_width = bm.width(); |
1377 cinfo.image_height = bm.height(); | 1381 cinfo.image_height = bm.height(); |
1378 cinfo.input_components = 3; | 1382 cinfo.input_components = 3; |
1379 #ifdef WE_CONVERT_TO_YUV | 1383 #ifdef WE_CONVERT_TO_YUV |
1380 cinfo.in_color_space = JCS_YCbCr; | 1384 cinfo.in_color_space = JCS_YCbCr; |
1381 #else | 1385 #else |
1382 cinfo.in_color_space = JCS_RGB; | 1386 cinfo.in_color_space = JCS_RGB; |
1383 #endif | 1387 #endif |
1384 cinfo.input_gamma = 1; | 1388 cinfo.input_gamma = 1; |
1385 | 1389 |
1386 jpeg_set_defaults(&cinfo); | 1390 jSetDefaults(&cinfo); |
1387 jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values
*/); | 1391 jSetQuality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); |
1388 #ifdef DCT_IFAST_SUPPORTED | 1392 #ifdef DCT_IFAST_SUPPORTED |
1389 cinfo.dct_method = JDCT_IFAST; | 1393 cinfo.dct_method = JDCT_IFAST; |
1390 #endif | 1394 #endif |
1391 | 1395 |
1392 jpeg_start_compress(&cinfo, TRUE); | 1396 jStrtCompress(&cinfo, TRUE); |
1393 | 1397 |
1394 const int width = bm.width(); | 1398 const int width = bm.width(); |
1395 uint8_t* oneRowP = (uint8_t*)oneRow.reset(width * 3); | 1399 uint8_t* oneRowP = (uint8_t*)oneRow.reset(width * 3); |
1396 | 1400 |
1397 const SkPMColor* colors = bm.getColorTable() ? bm.getColorTable()->readC
olors() : NULL; | 1401 const SkPMColor* colors = bm.getColorTable() ? bm.getColorTable()->readC
olors() : NULL; |
1398 const void* srcRow = bm.getPixels(); | 1402 const void* srcRow = bm.getPixels(); |
1399 | 1403 |
1400 while (cinfo.next_scanline < cinfo.image_height) { | 1404 while (cinfo.next_scanline < cinfo.image_height) { |
1401 JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ | 1405 JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ |
1402 | 1406 |
1403 writer(oneRowP, srcRow, width, colors); | 1407 writer(oneRowP, srcRow, width, colors); |
1404 row_pointer[0] = oneRowP; | 1408 row_pointer[0] = oneRowP; |
1405 (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); | 1409 (void) jWrtScanlines(&cinfo, row_pointer, 1); |
1406 srcRow = (const void*)((const char*)srcRow + bm.rowBytes()); | 1410 srcRow = (const void*)((const char*)srcRow + bm.rowBytes()); |
1407 } | 1411 } |
1408 | 1412 |
1409 jpeg_finish_compress(&cinfo); | 1413 jFinCompress(&cinfo); |
1410 jpeg_destroy_compress(&cinfo); | 1414 jDestCompress(&cinfo); |
1411 | 1415 |
1412 return true; | 1416 return true; |
1413 } | 1417 } |
1414 }; | 1418 }; |
1415 | 1419 |
1416 /////////////////////////////////////////////////////////////////////////////// | 1420 /////////////////////////////////////////////////////////////////////////////// |
1417 DEFINE_DECODER_CREATOR(JPEGImageDecoder); | 1421 DEFINE_DECODER_CREATOR(JPEGImageDecoder); |
1418 DEFINE_ENCODER_CREATOR(JPEGImageEncoder); | 1422 DEFINE_ENCODER_CREATOR(JPEGImageEncoder); |
1419 /////////////////////////////////////////////////////////////////////////////// | 1423 /////////////////////////////////////////////////////////////////////////////// |
1420 | 1424 |
(...skipping 28 matching lines...) Expand all Loading... |
1449 return SkImageDecoder::kUnknown_Format; | 1453 return SkImageDecoder::kUnknown_Format; |
1450 } | 1454 } |
1451 | 1455 |
1452 static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) { | 1456 static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) { |
1453 return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL; | 1457 return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL; |
1454 } | 1458 } |
1455 | 1459 |
1456 static SkImageDecoder_DecodeReg gDReg(sk_libjpeg_dfactory); | 1460 static SkImageDecoder_DecodeReg gDReg(sk_libjpeg_dfactory); |
1457 static SkImageDecoder_FormatReg gFormatReg(get_format_jpeg); | 1461 static SkImageDecoder_FormatReg gFormatReg(get_format_jpeg); |
1458 static SkImageEncoder_EncodeReg gEReg(sk_libjpeg_efactory); | 1462 static SkImageEncoder_EncodeReg gEReg(sk_libjpeg_efactory); |
OLD | NEW |