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" |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
78 } | 78 } |
79 /* To suppress error messages with a SK_DEBUG binary, set the | 79 /* To suppress error messages with a SK_DEBUG binary, set the |
80 * environment variable "skia_images_jpeg_suppressDecoderErrors" | 80 * environment variable "skia_images_jpeg_suppressDecoderErrors" |
81 * to "true". Inside a program that links to skia: | 81 * to "true". Inside a program that links to skia: |
82 * SK_CONF_SET("images.jpeg.suppressDecoderErrors", true); */ | 82 * SK_CONF_SET("images.jpeg.suppressDecoderErrors", true); */ |
83 if (c_suppressJPEGImageDecoderErrors) { | 83 if (c_suppressJPEGImageDecoderErrors) { |
84 cinfo->err->output_message = &do_nothing_output_message; | 84 cinfo->err->output_message = &do_nothing_output_message; |
85 } | 85 } |
86 } | 86 } |
87 | 87 |
88 #ifdef SK_JPEG_INDEX_SUPPORTED | |
89 class SkJPEGImageIndex { | |
90 public: | |
91 // Takes ownership of stream. | |
92 SkJPEGImageIndex(SkStreamRewindable* stream, SkImageDecoder* decoder) | |
93 : fSrcMgr(stream, decoder) | |
94 , fStream(stream) | |
95 , fInfoInitialized(false) | |
96 , fHuffmanCreated(false) | |
97 , fDecompressStarted(false) | |
98 { | |
99 SkDEBUGCODE(fReadHeaderSucceeded = false;) | |
100 } | |
101 | |
102 ~SkJPEGImageIndex() { | |
103 if (fHuffmanCreated) { | |
104 // Set to false before calling the libjpeg function, in case | |
105 // the libjpeg function calls longjmp. Our setjmp handler may | |
106 // attempt to delete this SkJPEGImageIndex, thus entering this | |
107 // destructor again. Setting fHuffmanCreated to false first | |
108 // prevents an infinite loop. | |
109 fHuffmanCreated = false; | |
110 jpeg_destroy_huffman_index(&fHuffmanIndex); | |
111 } | |
112 if (fDecompressStarted) { | |
113 // Like fHuffmanCreated, set to false before calling libjpeg | |
114 // function to prevent potential infinite loop. | |
115 fDecompressStarted = false; | |
116 jpeg_finish_decompress(&fCInfo); | |
117 } | |
118 if (fInfoInitialized) { | |
119 this->destroyInfo(); | |
120 } | |
121 } | |
122 | |
123 /** | |
124 * Destroy the cinfo struct. | |
125 * After this call, if a huffman index was already built, it | |
126 * can be used after calling initializeInfoAndReadHeader | |
127 * again. Must not be called after startTileDecompress except | |
128 * in the destructor. | |
129 */ | |
130 void destroyInfo() { | |
131 SkASSERT(fInfoInitialized); | |
132 SkASSERT(!fDecompressStarted); | |
133 // Like fHuffmanCreated, set to false before calling libjpeg | |
134 // function to prevent potential infinite loop. | |
135 fInfoInitialized = false; | |
136 jpeg_destroy_decompress(&fCInfo); | |
137 SkDEBUGCODE(fReadHeaderSucceeded = false;) | |
138 } | |
139 | |
140 /** | |
141 * Initialize the cinfo struct. | |
142 * Calls jpeg_create_decompress, makes customizations, and | |
143 * finally calls jpeg_read_header. Returns true if jpeg_read_header | |
144 * returns JPEG_HEADER_OK. | |
145 * If cinfo was already initialized, destroyInfo must be called to | |
146 * destroy the old one. Must not be called after startTileDecompress. | |
147 */ | |
148 bool initializeInfoAndReadHeader() { | |
149 SkASSERT(!fInfoInitialized && !fDecompressStarted); | |
150 initialize_info(&fCInfo, &fSrcMgr); | |
151 fInfoInitialized = true; | |
152 const bool success = (JPEG_HEADER_OK == jpeg_read_header(&fCInfo, true))
; | |
153 SkDEBUGCODE(fReadHeaderSucceeded = success;) | |
154 return success; | |
155 } | |
156 | |
157 jpeg_decompress_struct* cinfo() { return &fCInfo; } | |
158 | |
159 huffman_index* huffmanIndex() { return &fHuffmanIndex; } | |
160 | |
161 /** | |
162 * Build the index to be used for tile based decoding. | |
163 * Must only be called after a successful call to | |
164 * initializeInfoAndReadHeader and must not be called more | |
165 * than once. | |
166 */ | |
167 bool buildHuffmanIndex() { | |
168 SkASSERT(fReadHeaderSucceeded); | |
169 SkASSERT(!fHuffmanCreated); | |
170 jpeg_create_huffman_index(&fCInfo, &fHuffmanIndex); | |
171 SkASSERT(1 == fCInfo.scale_num && 1 == fCInfo.scale_denom); | |
172 fHuffmanCreated = jpeg_build_huffman_index(&fCInfo, &fHuffmanIndex); | |
173 return fHuffmanCreated; | |
174 } | |
175 | |
176 /** | |
177 * Start tile based decoding. Must only be called after a | |
178 * successful call to buildHuffmanIndex, and must only be | |
179 * called once. | |
180 */ | |
181 bool startTileDecompress() { | |
182 SkASSERT(fHuffmanCreated); | |
183 SkASSERT(fReadHeaderSucceeded); | |
184 SkASSERT(!fDecompressStarted); | |
185 if (jpeg_start_tile_decompress(&fCInfo)) { | |
186 fDecompressStarted = true; | |
187 return true; | |
188 } | |
189 return false; | |
190 } | |
191 | |
192 private: | |
193 skjpeg_source_mgr fSrcMgr; | |
194 SkAutoTDelete<SkStream> fStream; | |
195 jpeg_decompress_struct fCInfo; | |
196 huffman_index fHuffmanIndex; | |
197 bool fInfoInitialized; | |
198 bool fHuffmanCreated; | |
199 bool fDecompressStarted; | |
200 SkDEBUGCODE(bool fReadHeaderSucceeded;) | |
201 }; | |
202 #endif | |
203 | |
204 class SkJPEGImageDecoder : public SkImageDecoder { | 88 class SkJPEGImageDecoder : public SkImageDecoder { |
205 public: | 89 public: |
206 #ifdef SK_JPEG_INDEX_SUPPORTED | |
207 SkJPEGImageDecoder() { | |
208 fImageIndex = nullptr; | |
209 fImageWidth = 0; | |
210 fImageHeight = 0; | |
211 } | |
212 | |
213 virtual ~SkJPEGImageDecoder() { delete fImageIndex; } | |
214 #endif | |
215 | 90 |
216 Format getFormat() const override { | 91 Format getFormat() const override { |
217 return kJPEG_Format; | 92 return kJPEG_Format; |
218 } | 93 } |
219 | 94 |
220 protected: | 95 protected: |
221 #ifdef SK_JPEG_INDEX_SUPPORTED | |
222 bool onBuildTileIndex(SkStreamRewindable *stream, int *width, int *height) o
verride; | |
223 bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& rect) override; | |
224 #endif | |
225 Result onDecode(SkStream* stream, SkBitmap* bm, Mode) override; | 96 Result onDecode(SkStream* stream, SkBitmap* bm, Mode) override; |
226 bool onDecodeYUV8Planes(SkStream* stream, SkISize componentSizes[3], | 97 bool onDecodeYUV8Planes(SkStream* stream, SkISize componentSizes[3], |
227 void* planes[3], size_t rowBytes[3], | 98 void* planes[3], size_t rowBytes[3], |
228 SkYUVColorSpace* colorSpace) override; | 99 SkYUVColorSpace* colorSpace) override; |
229 | 100 |
230 private: | 101 private: |
231 #ifdef SK_JPEG_INDEX_SUPPORTED | |
232 SkJPEGImageIndex* fImageIndex; | |
233 int fImageWidth; | |
234 int fImageHeight; | |
235 #endif | |
236 | 102 |
237 /** | 103 /** |
238 * Determine the appropriate bitmap colortype and out_color_space based on | 104 * Determine the appropriate bitmap colortype and out_color_space based on |
239 * both the preference of the caller and the jpeg_color_space on the | 105 * both the preference of the caller and the jpeg_color_space on the |
240 * jpeg_decompress_struct passed in. | 106 * jpeg_decompress_struct passed in. |
241 * Must be called after jpeg_read_header. | 107 * Must be called after jpeg_read_header. |
242 */ | 108 */ |
243 SkColorType getBitmapColorType(jpeg_decompress_struct*); | 109 SkColorType getBitmapColorType(jpeg_decompress_struct*); |
244 | 110 |
245 typedef SkImageDecoder INHERITED; | 111 typedef SkImageDecoder INHERITED; |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
288 for (int i = 0; i < count; i++) { | 154 for (int i = 0; i < count; i++) { |
289 JSAMPLE* rowptr = (JSAMPLE*)buffer; | 155 JSAMPLE* rowptr = (JSAMPLE*)buffer; |
290 int row_count = jpeg_read_scanlines(cinfo, &rowptr, 1); | 156 int row_count = jpeg_read_scanlines(cinfo, &rowptr, 1); |
291 if (1 != row_count) { | 157 if (1 != row_count) { |
292 return false; | 158 return false; |
293 } | 159 } |
294 } | 160 } |
295 return true; | 161 return true; |
296 } | 162 } |
297 | 163 |
298 #ifdef SK_JPEG_INDEX_SUPPORTED | |
299 static bool skip_src_rows_tile(jpeg_decompress_struct* cinfo, | |
300 huffman_index *index, void* buffer, int count) { | |
301 for (int i = 0; i < count; i++) { | |
302 JSAMPLE* rowptr = (JSAMPLE*)buffer; | |
303 int row_count = jpeg_read_tile_scanline(cinfo, index, &rowptr); | |
304 if (1 != row_count) { | |
305 return false; | |
306 } | |
307 } | |
308 return true; | |
309 } | |
310 #endif | |
311 | |
312 /////////////////////////////////////////////////////////////////////////////// | 164 /////////////////////////////////////////////////////////////////////////////// |
313 | 165 |
314 // This guy exists just to aid in debugging, as it allows debuggers to just | 166 // This guy exists just to aid in debugging, as it allows debuggers to just |
315 // set a break-point in one place to see all error exists. | 167 // set a break-point in one place to see all error exists. |
316 static void print_jpeg_decoder_errors(const jpeg_decompress_struct& cinfo, | 168 static void print_jpeg_decoder_errors(const jpeg_decompress_struct& cinfo, |
317 int width, int height, const char caller[]) { | 169 int width, int height, const char caller[]) { |
318 if (!(c_suppressJPEGImageDecoderErrors)) { | 170 if (!(c_suppressJPEGImageDecoderErrors)) { |
319 char buffer[JMSG_LENGTH_MAX]; | 171 char buffer[JMSG_LENGTH_MAX]; |
320 cinfo.err->format_message((const j_common_ptr)&cinfo, buffer); | 172 cinfo.err->format_message((const j_common_ptr)&cinfo, buffer); |
321 SkDebugf("libjpeg error %d <%s> from %s [%d %d]\n", | 173 SkDebugf("libjpeg error %d <%s> from %s [%d %d]\n", |
322 cinfo.err->msg_code, buffer, caller, width, height); | 174 cinfo.err->msg_code, buffer, caller, width, height); |
323 } | 175 } |
324 } | 176 } |
325 | 177 |
326 static bool return_false(const jpeg_decompress_struct& cinfo, | 178 static bool return_false(const jpeg_decompress_struct& cinfo, |
327 const char caller[]) { | 179 const char caller[]) { |
328 print_jpeg_decoder_errors(cinfo, 0, 0, caller); | 180 print_jpeg_decoder_errors(cinfo, 0, 0, caller); |
329 return false; | 181 return false; |
330 } | 182 } |
331 | 183 |
332 #ifdef SK_JPEG_INDEX_SUPPORTED | |
333 static bool return_false(const jpeg_decompress_struct& cinfo, | |
334 const SkBitmap& bm, const char caller[]) { | |
335 print_jpeg_decoder_errors(cinfo, bm.width(), bm.height(), caller); | |
336 return false; | |
337 } | |
338 #endif | |
339 | |
340 static SkImageDecoder::Result return_failure(const jpeg_decompress_struct& cinfo
, | 184 static SkImageDecoder::Result return_failure(const jpeg_decompress_struct& cinfo
, |
341 const SkBitmap& bm, const char call
er[]) { | 185 const SkBitmap& bm, const char call
er[]) { |
342 print_jpeg_decoder_errors(cinfo, bm.width(), bm.height(), caller); | 186 print_jpeg_decoder_errors(cinfo, bm.width(), bm.height(), caller); |
343 return SkImageDecoder::kFailure; | 187 return SkImageDecoder::kFailure; |
344 } | 188 } |
345 | 189 |
346 /////////////////////////////////////////////////////////////////////////////// | 190 /////////////////////////////////////////////////////////////////////////////// |
347 | 191 |
348 // Convert a scanline of CMYK samples to RGBX in place. Note that this | 192 // Convert a scanline of CMYK samples to RGBX in place. Note that this |
349 // method moves the "scanline" pointer in its processing | 193 // method moves the "scanline" pointer in its processing |
(...skipping 582 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
932 | 776 |
933 if (nullptr != colorSpace) { | 777 if (nullptr != colorSpace) { |
934 *colorSpace = kJPEG_SkYUVColorSpace; | 778 *colorSpace = kJPEG_SkYUVColorSpace; |
935 } | 779 } |
936 | 780 |
937 return true; | 781 return true; |
938 } | 782 } |
939 | 783 |
940 /////////////////////////////////////////////////////////////////////////////// | 784 /////////////////////////////////////////////////////////////////////////////// |
941 | 785 |
942 #ifdef SK_JPEG_INDEX_SUPPORTED | |
943 bool SkJPEGImageDecoder::onBuildTileIndex(SkStreamRewindable* stream, int *width
, int *height) { | |
944 SkAutoTDelete<SkJPEGImageIndex> imageIndex(new SkJPEGImageIndex(stream, this
)); | |
945 | |
946 skjpeg_error_mgr sk_err; | |
947 set_error_mgr(imageIndex->cinfo(), &sk_err); | |
948 | |
949 // All objects need to be instantiated before this setjmp call so that | |
950 // they will be cleaned up properly if an error occurs. | |
951 if (setjmp(sk_err.fJmpBuf)) { | |
952 return false; | |
953 } | |
954 | |
955 // create the cinfo used to create/build the huffmanIndex | |
956 if (!imageIndex->initializeInfoAndReadHeader()) { | |
957 return false; | |
958 } | |
959 | |
960 if (!imageIndex->buildHuffmanIndex()) { | |
961 return false; | |
962 } | |
963 | |
964 // destroy the cinfo used to create/build the huffman index | |
965 imageIndex->destroyInfo(); | |
966 | |
967 // Init decoder to image decode mode | |
968 if (!imageIndex->initializeInfoAndReadHeader()) { | |
969 return false; | |
970 } | |
971 | |
972 jpeg_decompress_struct* cinfo = imageIndex->cinfo(); | |
973 // We have a new cinfo, so set the error mgr again. | |
974 set_error_mgr(cinfo, &sk_err); | |
975 | |
976 // FIXME: This sets cinfo->out_color_space, which we may change later | |
977 // based on the config in onDecodeSubset. This should be fine, since | |
978 // jpeg_init_read_tile_scanline will check out_color_space again after | |
979 // that change (when it calls jinit_color_deconverter). | |
980 (void) this->getBitmapColorType(cinfo); | |
981 | |
982 turn_off_visual_optimizations(cinfo); | |
983 | |
984 // instead of jpeg_start_decompress() we start a tiled decompress | |
985 if (!imageIndex->startTileDecompress()) { | |
986 return false; | |
987 } | |
988 | |
989 SkASSERT(1 == cinfo->scale_num); | |
990 fImageWidth = cinfo->output_width; | |
991 fImageHeight = cinfo->output_height; | |
992 | |
993 if (width) { | |
994 *width = fImageWidth; | |
995 } | |
996 if (height) { | |
997 *height = fImageHeight; | |
998 } | |
999 | |
1000 delete fImageIndex; | |
1001 fImageIndex = imageIndex.detach(); | |
1002 | |
1003 return true; | |
1004 } | |
1005 | |
1006 bool SkJPEGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) { | |
1007 if (nullptr == fImageIndex) { | |
1008 return false; | |
1009 } | |
1010 jpeg_decompress_struct* cinfo = fImageIndex->cinfo(); | |
1011 | |
1012 SkIRect rect = SkIRect::MakeWH(fImageWidth, fImageHeight); | |
1013 if (!rect.intersect(region)) { | |
1014 // If the requested region is entirely outside the image return false | |
1015 return false; | |
1016 } | |
1017 | |
1018 | |
1019 skjpeg_error_mgr errorManager; | |
1020 set_error_mgr(cinfo, &errorManager); | |
1021 | |
1022 if (setjmp(errorManager.fJmpBuf)) { | |
1023 return false; | |
1024 } | |
1025 | |
1026 int requestedSampleSize = this->getSampleSize(); | |
1027 cinfo->scale_denom = requestedSampleSize; | |
1028 | |
1029 set_dct_method(*this, cinfo); | |
1030 | |
1031 const SkColorType colorType = this->getBitmapColorType(cinfo); | |
1032 adjust_out_color_space_and_dither(cinfo, colorType, *this); | |
1033 | |
1034 int startX = rect.fLeft; | |
1035 int startY = rect.fTop; | |
1036 int width = rect.width(); | |
1037 int height = rect.height(); | |
1038 | |
1039 jpeg_init_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(), | |
1040 &startX, &startY, &width, &height); | |
1041 int skiaSampleSize = recompute_sampleSize(requestedSampleSize, *cinfo); | |
1042 int actualSampleSize = skiaSampleSize * (DCTSIZE / cinfo->min_DCT_scaled_siz
e); | |
1043 | |
1044 SkScaledBitmapSampler sampler(width, height, skiaSampleSize); | |
1045 | |
1046 SkBitmap bitmap; | |
1047 // Assume an A8 bitmap is not opaque to avoid the check of each | |
1048 // individual pixel. It is very unlikely to be opaque, since | |
1049 // an opaque A8 bitmap would not be very interesting. | |
1050 // Otherwise, a jpeg image is opaque. | |
1051 bitmap.setInfo(SkImageInfo::Make(sampler.scaledWidth(), sampler.scaledHeight
(), colorType, | |
1052 kAlpha_8_SkColorType == colorType ? | |
1053 kPremul_SkAlphaType : kOpaque_SkAlphaTy
pe)); | |
1054 | |
1055 // Check ahead of time if the swap(dest, src) is possible or not. | |
1056 // If yes, then we will stick to AllocPixelRef since it's cheaper with the | |
1057 // swap happening. If no, then we will use alloc to allocate pixels to | |
1058 // prevent garbage collection. | |
1059 int w = rect.width() / actualSampleSize; | |
1060 int h = rect.height() / actualSampleSize; | |
1061 bool swapOnly = (rect == region) && bm->isNull() && | |
1062 (w == bitmap.width()) && (h == bitmap.height()) && | |
1063 ((startX - rect.x()) / actualSampleSize == 0) && | |
1064 ((startY - rect.y()) / actualSampleSize == 0); | |
1065 if (swapOnly) { | |
1066 if (!this->allocPixelRef(&bitmap, nullptr)) { | |
1067 return return_false(*cinfo, bitmap, "allocPixelRef"); | |
1068 } | |
1069 } else { | |
1070 if (!bitmap.tryAllocPixels()) { | |
1071 return return_false(*cinfo, bitmap, "allocPixels"); | |
1072 } | |
1073 } | |
1074 | |
1075 SkAutoLockPixels alp(bitmap); | |
1076 | |
1077 #ifdef ANDROID_RGB | |
1078 /* short-circuit the SkScaledBitmapSampler when possible, as this gives | |
1079 a significant performance boost. | |
1080 */ | |
1081 if (skiaSampleSize == 1 && | |
1082 ((kN32_SkColorType == colorType && cinfo->out_color_space == JCS_RGBA_88
88) || | |
1083 (kRGB_565_SkColorType == colorType && cinfo->out_color_space == JCS_RGB
_565))) | |
1084 { | |
1085 JSAMPLE* rowptr = (JSAMPLE*)bitmap.getPixels(); | |
1086 INT32 const bpr = bitmap.rowBytes(); | |
1087 int rowTotalCount = 0; | |
1088 | |
1089 while (rowTotalCount < height) { | |
1090 int rowCount = jpeg_read_tile_scanline(cinfo, | |
1091 fImageIndex->huffmanIndex(), | |
1092 &rowptr); | |
1093 // if rowCount == 0, then we didn't get a scanline, so abort. | |
1094 // onDecodeSubset() relies on onBuildTileIndex(), which | |
1095 // needs a complete image to succeed. | |
1096 if (0 == rowCount) { | |
1097 return return_false(*cinfo, bitmap, "read_scanlines"); | |
1098 } | |
1099 if (this->shouldCancelDecode()) { | |
1100 return return_false(*cinfo, bitmap, "shouldCancelDecode"); | |
1101 } | |
1102 rowTotalCount += rowCount; | |
1103 rowptr += bpr; | |
1104 } | |
1105 | |
1106 if (swapOnly) { | |
1107 bm->swap(bitmap); | |
1108 return true; | |
1109 } | |
1110 | |
1111 return cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(), | |
1112 region.width(), region.height(), startX, startY); | |
1113 } | |
1114 #endif | |
1115 | |
1116 // check for supported formats | |
1117 SkScaledBitmapSampler::SrcConfig sc; | |
1118 int srcBytesPerPixel; | |
1119 | |
1120 if (!get_src_config(*cinfo, &sc, &srcBytesPerPixel)) { | |
1121 return return_false(*cinfo, *bm, "jpeg colorspace"); | |
1122 } | |
1123 | |
1124 if (!sampler.begin(&bitmap, sc, *this)) { | |
1125 return return_false(*cinfo, bitmap, "sampler.begin"); | |
1126 } | |
1127 | |
1128 SkAutoMalloc srcStorage(width * srcBytesPerPixel); | |
1129 uint8_t* srcRow = (uint8_t*)srcStorage.get(); | |
1130 | |
1131 // Possibly skip initial rows [sampler.srcY0] | |
1132 if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow, sampler.
srcY0())) { | |
1133 return return_false(*cinfo, bitmap, "skip rows"); | |
1134 } | |
1135 | |
1136 // now loop through scanlines until y == bitmap->height() - 1 | |
1137 for (int y = 0;; y++) { | |
1138 JSAMPLE* rowptr = (JSAMPLE*)srcRow; | |
1139 int row_count = jpeg_read_tile_scanline(cinfo, fImageIndex->huffmanIndex
(), &rowptr); | |
1140 // if row_count == 0, then we didn't get a scanline, so abort. | |
1141 // onDecodeSubset() relies on onBuildTileIndex(), which | |
1142 // needs a complete image to succeed. | |
1143 if (0 == row_count) { | |
1144 return return_false(*cinfo, bitmap, "read_scanlines"); | |
1145 } | |
1146 if (this->shouldCancelDecode()) { | |
1147 return return_false(*cinfo, bitmap, "shouldCancelDecode"); | |
1148 } | |
1149 | |
1150 if (JCS_CMYK == cinfo->out_color_space) { | |
1151 convert_CMYK_to_RGB(srcRow, width); | |
1152 } | |
1153 | |
1154 sampler.next(srcRow); | |
1155 if (bitmap.height() - 1 == y) { | |
1156 // we're done | |
1157 break; | |
1158 } | |
1159 | |
1160 if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow, | |
1161 sampler.srcDY() - 1)) { | |
1162 return return_false(*cinfo, bitmap, "skip rows"); | |
1163 } | |
1164 } | |
1165 if (swapOnly) { | |
1166 bm->swap(bitmap); | |
1167 return true; | |
1168 } | |
1169 return cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(), | |
1170 region.width(), region.height(), startX, startY); | |
1171 } | |
1172 #endif | |
1173 | |
1174 /////////////////////////////////////////////////////////////////////////////// | |
1175 | |
1176 #include "SkColorPriv.h" | 786 #include "SkColorPriv.h" |
1177 | 787 |
1178 // taken from jcolor.c in libjpeg | 788 // taken from jcolor.c in libjpeg |
1179 #if 0 // 16bit - precise but slow | 789 #if 0 // 16bit - precise but slow |
1180 #define CYR 19595 // 0.299 | 790 #define CYR 19595 // 0.299 |
1181 #define CYG 38470 // 0.587 | 791 #define CYG 38470 // 0.587 |
1182 #define CYB 7471 // 0.114 | 792 #define CYB 7471 // 0.114 |
1183 | 793 |
1184 #define CUR -11059 // -0.16874 | 794 #define CUR -11059 // -0.16874 |
1185 #define CUG -21709 // -0.33126 | 795 #define CUG -21709 // -0.33126 |
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1446 return SkImageDecoder::kUnknown_Format; | 1056 return SkImageDecoder::kUnknown_Format; |
1447 } | 1057 } |
1448 | 1058 |
1449 static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) { | 1059 static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) { |
1450 return (SkImageEncoder::kJPEG_Type == t) ? new SkJPEGImageEncoder : nullptr; | 1060 return (SkImageEncoder::kJPEG_Type == t) ? new SkJPEGImageEncoder : nullptr; |
1451 } | 1061 } |
1452 | 1062 |
1453 static SkImageDecoder_DecodeReg gDReg(sk_libjpeg_dfactory); | 1063 static SkImageDecoder_DecodeReg gDReg(sk_libjpeg_dfactory); |
1454 static SkImageDecoder_FormatReg gFormatReg(get_format_jpeg); | 1064 static SkImageDecoder_FormatReg gFormatReg(get_format_jpeg); |
1455 static SkImageEncoder_EncodeReg gEReg(sk_libjpeg_efactory); | 1065 static SkImageEncoder_EncodeReg gEReg(sk_libjpeg_efactory); |
OLD | NEW |