OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
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 #include "SkCodec.h" | 8 #include "SkCodec.h" |
9 #include "SkJpegCodec.h" | 9 #include "SkJpegCodec.h" |
10 #include "SkJpegDecoderMgr.h" | 10 #include "SkJpegDecoderMgr.h" |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
54 } | 54 } |
55 return SkSwizzler::kUnknown; | 55 return SkSwizzler::kUnknown; |
56 } | 56 } |
57 | 57 |
58 /* | 58 /* |
59 * Convert a row of CMYK samples to RGBX in place. | 59 * Convert a row of CMYK samples to RGBX in place. |
60 * Note that this method moves the row pointer. | 60 * Note that this method moves the row pointer. |
61 * @param width the number of pixels in the row that is being converted | 61 * @param width the number of pixels in the row that is being converted |
62 * CMYK is stored as four bytes per pixel | 62 * CMYK is stored as four bytes per pixel |
63 */ | 63 */ |
64 static void convert_CMYK_to_RGB(uint8_t* row, uint32_t width) { | 64 static void convert_CMYK_to_RGB(uint8_t* row, size_t rowBytes) { |
scroggo
2015/04/24 13:14:28
It seems very weird to me to pass rowBytes here. W
msarett
2015/04/24 15:08:44
Yeah you are absolutely right. I made the change
| |
65 // We will implement a crude conversion from CMYK -> RGB using formulas | 65 // We will implement a crude conversion from CMYK -> RGB using formulas |
66 // from easyrgb.com. | 66 // from easyrgb.com. |
67 // | 67 // |
68 // CMYK -> CMY | 68 // CMYK -> CMY |
69 // C = C * (1 - K) + K | 69 // C = C * (1 - K) + K |
70 // M = M * (1 - K) + K | 70 // M = M * (1 - K) + K |
71 // Y = Y * (1 - K) + K | 71 // Y = Y * (1 - K) + K |
72 // | 72 // |
73 // libjpeg actually gives us inverted CMYK, so we must subtract the | 73 // libjpeg actually gives us inverted CMYK, so we must subtract the |
74 // original terms from 1. | 74 // original terms from 1. |
(...skipping 21 matching lines...) Expand all Loading... | |
96 // B = Y * K * 255 | 96 // B = Y * K * 255 |
97 // | 97 // |
98 // As a final note, we have treated the CMYK values as if they were on | 98 // As a final note, we have treated the CMYK values as if they were on |
99 // a scale from 0-1, when in fact they are 8-bit ints scaling from 0-255. | 99 // a scale from 0-1, when in fact they are 8-bit ints scaling from 0-255. |
100 // We must divide each CMYK component by 255 to obtain the true conversion | 100 // We must divide each CMYK component by 255 to obtain the true conversion |
101 // we should perform. | 101 // we should perform. |
102 // CMYK -> RGB | 102 // CMYK -> RGB |
103 // R = C * K / 255 | 103 // R = C * K / 255 |
104 // G = M * K / 255 | 104 // G = M * K / 255 |
105 // B = Y * K / 255 | 105 // B = Y * K / 255 |
106 uint32_t width = rowBytes / 4; | |
106 for (uint32_t x = 0; x < width; x++, row += 4) { | 107 for (uint32_t x = 0; x < width; x++, row += 4) { |
107 row[0] = SkMulDiv255Round(row[0], row[3]); | 108 row[0] = SkMulDiv255Round(row[0], row[3]); |
108 row[1] = SkMulDiv255Round(row[1], row[3]); | 109 row[1] = SkMulDiv255Round(row[1], row[3]); |
109 row[2] = SkMulDiv255Round(row[2], row[3]); | 110 row[2] = SkMulDiv255Round(row[2], row[3]); |
110 row[3] = 0xFF; | 111 row[3] = 0xFF; |
111 } | 112 } |
112 } | 113 } |
113 | 114 |
114 bool SkJpegCodec::IsJpeg(SkStream* stream) { | 115 bool SkJpegCodec::IsJpeg(SkStream* stream) { |
115 static const uint8_t jpegSig[] = { 0xFF, 0xD8, 0xFF }; | 116 static const uint8_t jpegSig[] = { 0xFF, 0xD8, 0xFF }; |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
161 streamDeleter.detach(); | 162 streamDeleter.detach(); |
162 return codec; | 163 return codec; |
163 } | 164 } |
164 return NULL; | 165 return NULL; |
165 } | 166 } |
166 | 167 |
167 SkJpegCodec::SkJpegCodec(const SkImageInfo& srcInfo, SkStream* stream, | 168 SkJpegCodec::SkJpegCodec(const SkImageInfo& srcInfo, SkStream* stream, |
168 JpegDecoderMgr* decoderMgr) | 169 JpegDecoderMgr* decoderMgr) |
169 : INHERITED(srcInfo, stream) | 170 : INHERITED(srcInfo, stream) |
170 , fDecoderMgr(decoderMgr) | 171 , fDecoderMgr(decoderMgr) |
172 , fSwizzler(NULL) | |
173 , fSrcRowBytes(0) | |
171 {} | 174 {} |
172 | 175 |
173 /* | 176 /* |
174 * Return a valid set of output dimensions for this decoder, given an input scal e | 177 * Return a valid set of output dimensions for this decoder, given an input scal e |
175 */ | 178 */ |
176 SkISize SkJpegCodec::onGetScaledDimensions(float desiredScale) const { | 179 SkISize SkJpegCodec::onGetScaledDimensions(float desiredScale) const { |
177 // libjpeg supports scaling by 1/1, 1/2, 1/4, and 1/8, so we will support th ese as well | 180 // libjpeg supports scaling by 1/1, 1/2, 1/4, and 1/8, so we will support th ese as well |
178 long scale; | 181 long scale; |
179 if (desiredScale > 0.75f) { | 182 if (desiredScale > 0.75f) { |
180 scale = 1; | 183 scale = 1; |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
220 // Always allow kN32 as the color type | 223 // Always allow kN32 as the color type |
221 if (kN32_SkColorType == dst.colorType()) { | 224 if (kN32_SkColorType == dst.colorType()) { |
222 return true; | 225 return true; |
223 } | 226 } |
224 | 227 |
225 // Otherwise require that the destination color type match our recommendatio n | 228 // Otherwise require that the destination color type match our recommendatio n |
226 return dst.colorType() == src.colorType(); | 229 return dst.colorType() == src.colorType(); |
227 } | 230 } |
228 | 231 |
229 /* | 232 /* |
233 * Handles rewinding the input stream if it is necessary | |
234 */ | |
235 bool SkJpegCodec::handleRewind() { | |
236 SkCodec::RewindState rewindState = this->rewindIfNeeded(); | |
237 if (rewindState == kCouldNotRewind_RewindState) { | |
238 return fDecoderMgr->returnFalse("could not rewind"); | |
239 } else if (rewindState == kRewound_RewindState) { | |
240 JpegDecoderMgr* decoderMgr = NULL; | |
241 if (!ReadHeader(this->stream(), NULL, &decoderMgr)) { | |
242 return fDecoderMgr->returnFalse("could not rewind"); | |
243 } | |
244 SkASSERT(NULL != decoderMgr); | |
245 fDecoderMgr.reset(decoderMgr); | |
246 } | |
247 return true; | |
scroggo
2015/04/24 13:14:28
nit: I think this should go inside the else statem
msarett
2015/04/24 15:08:44
Hmmm I'm not quite sure I understand, but let me k
scroggo
2015/04/24 15:23:13
Oh no, I was confused. I like it better the first
msarett
2015/04/24 15:40:13
Done.
| |
248 } | |
249 | |
250 /* | |
251 * Checks if we can scale to the requested dimensions and performs the scaling | |
252 */ | |
253 bool SkJpegCodec::handleScaling(const SkImageInfo& dstInfo) { | |
scroggo
2015/04/24 13:14:28
You only need width and height here. Why not pass
msarett
2015/04/24 15:08:44
Agreed.
| |
254 // libjpeg can scale to 1/1, 1/2, 1/4, and 1/8 | |
255 SkASSERT(1 == fDecoderMgr->dinfo()->scale_num); | |
256 SkASSERT(1 == fDecoderMgr->dinfo()->scale_denom); | |
257 jpeg_calc_output_dimensions(fDecoderMgr->dinfo()); | |
258 const uint32_t dstWidth = dstInfo.width(); | |
259 const uint32_t dstHeight = dstInfo.height(); | |
260 while (fDecoderMgr->dinfo()->output_width != dstWidth || | |
261 fDecoderMgr->dinfo()->output_height != dstHeight) { | |
262 | |
263 // Return a failure if we have tried all of the possible scales | |
264 if (8 == fDecoderMgr->dinfo()->scale_denom || | |
265 dstWidth > fDecoderMgr->dinfo()->output_width || | |
266 dstHeight > fDecoderMgr->dinfo()->output_height) { | |
267 return fDecoderMgr->returnFalse("could not scale to requested dimens ions"); | |
268 } | |
269 | |
270 // Try the next scale | |
271 fDecoderMgr->dinfo()->scale_denom *= 2; | |
272 jpeg_calc_output_dimensions(fDecoderMgr->dinfo()); | |
273 } | |
274 return true; | |
275 } | |
276 | |
277 /* | |
278 * Create the swizzler based on the encoded format | |
279 */ | |
280 void SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo, | |
281 void* dst, size_t dstRowBytes, | |
282 const Options& options) { | |
283 SkSwizzler::SrcConfig srcConfig = get_src_config(*fDecoderMgr->dinfo()); | |
284 fSwizzler.reset(SkSwizzler::CreateSwizzler(srcConfig, NULL, dstInfo, dst, ds tRowBytes, | |
285 options.fZeroInitialized)); | |
286 fSrcRowBytes = SkSwizzler::BytesPerPixel(srcConfig) * dstInfo.width(); | |
287 } | |
288 | |
289 /* | |
230 * Performs the jpeg decode | 290 * Performs the jpeg decode |
231 */ | 291 */ |
232 SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo, | 292 SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo, |
233 void* dst, size_t dstRowBytes, | 293 void* dst, size_t dstRowBytes, |
234 const Options& options, SkPMColor*, int *) { | 294 const Options& options, SkPMColor*, int *) { |
295 | |
235 // Rewind the stream if needed | 296 // Rewind the stream if needed |
236 SkCodec::RewindState rewindState = this->rewindIfNeeded(); | 297 if (!this->handleRewind()) { |
237 if (rewindState == kCouldNotRewind_RewindState) { | 298 fDecoderMgr->returnFailure("could not rewind stream", kCouldNotRewind); |
238 return kCouldNotRewind; | |
239 } else if (rewindState == kRewound_RewindState) { | |
240 JpegDecoderMgr* decoderMgr = NULL; | |
241 if (!ReadHeader(this->stream(), NULL, &decoderMgr)) { | |
242 return kCouldNotRewind; | |
243 } | |
244 SkASSERT(NULL != decoderMgr); | |
245 fDecoderMgr.reset(decoderMgr); | |
246 } | 299 } |
247 | 300 |
248 // Get a pointer to the decompress info since we will use it quite frequentl y | 301 // Get a pointer to the decompress info since we will use it quite frequentl y |
249 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo(); | 302 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo(); |
250 | 303 |
251 // Set the jump location for libjpeg errors | 304 // Set the jump location for libjpeg errors |
252 if (setjmp(fDecoderMgr->getJmpBuf())) { | 305 if (setjmp(fDecoderMgr->getJmpBuf())) { |
253 return fDecoderMgr->returnFailure("setjmp", kInvalidInput); | 306 return fDecoderMgr->returnFailure("setjmp", kInvalidInput); |
254 } | 307 } |
255 | 308 |
256 // Check if we can decode to the requested destination | 309 // Check if we can decode to the requested destination |
257 if (!conversion_possible(dstInfo, this->getInfo())) { | 310 if (!conversion_possible(dstInfo, this->getInfo())) { |
258 return fDecoderMgr->returnFailure("conversion_possible", kInvalidConvers ion); | 311 return fDecoderMgr->returnFailure("conversion_possible", kInvalidConvers ion); |
259 } | 312 } |
260 // Check if we can scale to the requested dimensions | |
261 // libjpeg can scale to 1/1, 1/2, 1/4, and 1/8 | |
262 SkASSERT(1 == dinfo->scale_num); | |
263 SkASSERT(1 == dinfo->scale_denom); | |
264 jpeg_calc_output_dimensions(dinfo); | |
265 const uint32_t dstWidth = dstInfo.width(); | |
266 const uint32_t dstHeight = dstInfo.height(); | |
267 while (dinfo->output_width != dstWidth || dinfo->output_height != dstHeight) { | |
268 | 313 |
269 // Return a failure if we have tried all of the possible scales | 314 // Perform the necessary scaling |
270 if (8 == dinfo->scale_denom || | 315 if (!this->handleScaling(dstInfo)) { |
271 dstWidth > dinfo->output_width || | 316 fDecoderMgr->returnFailure("cannot scale to requested dims", kInvalidSca le); |
272 dstHeight > dinfo->output_height) { | |
273 return fDecoderMgr->returnFailure("cannot scale to requested dims", kInvalidScale); | |
274 } | |
275 | |
276 // Try the next scale | |
277 dinfo->scale_denom *= 2; | |
278 jpeg_calc_output_dimensions(dinfo); | |
279 } | 317 } |
280 | 318 |
281 // Now, given valid output dimensions, we can start the decompress | 319 // Now, given valid output dimensions, we can start the decompress |
282 if (!jpeg_start_decompress(dinfo)) { | 320 if (!jpeg_start_decompress(dinfo)) { |
283 return fDecoderMgr->returnFailure("startDecompress", kInvalidInput); | 321 return fDecoderMgr->returnFailure("startDecompress", kInvalidInput); |
284 } | 322 } |
285 | 323 |
286 // Create the swizzler | 324 // Create the swizzler |
287 SkSwizzler::SrcConfig srcConfig = get_src_config(*dinfo); | 325 this->initializeSwizzler(dstInfo, dst, dstRowBytes, options); |
288 SkAutoTDelete<SkSwizzler> swizzler(SkSwizzler::CreateSwizzler(srcConfig, NUL L, dstInfo, dst, | 326 if (NULL == fSwizzler) { |
289 dstRowBytes, options.fZeroInitialized)); | |
290 if (NULL == swizzler) { | |
291 return fDecoderMgr->returnFailure("getSwizzler", kInvalidInput); | 327 return fDecoderMgr->returnFailure("getSwizzler", kInvalidInput); |
scroggo
2015/04/24 13:14:28
This is not new to this change, but I think kInval
msarett
2015/04/24 15:08:44
I think kUnimplemented sounds like the right choic
| |
292 } | 328 } |
293 const uint32_t srcBytesPerPixel = SkSwizzler::BytesPerPixel(srcConfig); | |
294 | 329 |
295 // This is usually 1, but can also be 2 or 4. | 330 // This is usually 1, but can also be 2 or 4. |
296 // If we wanted to always read one row at a time, we could, but we will save space and time | 331 // If we wanted to always read one row at a time, we could, but we will save space and time |
297 // by using the recommendation from libjpeg. | 332 // by using the recommendation from libjpeg. |
298 const uint32_t rowsPerDecode = dinfo->rec_outbuf_height; | 333 const uint32_t rowsPerDecode = dinfo->rec_outbuf_height; |
299 SkASSERT(rowsPerDecode <= 4); | 334 SkASSERT(rowsPerDecode <= 4); |
300 | 335 |
301 // Create a buffer to contain decoded rows (libjpeg requires a 2D array) | 336 // Create a buffer to contain decoded rows (libjpeg requires a 2D array) |
302 const uint32_t srcRowBytes = srcBytesPerPixel * dstWidth; | 337 SkAutoTDeleteArray<uint8_t> srcBuffer(SkNEW_ARRAY(uint8_t, fSrcRowBytes * ro wsPerDecode)); |
scroggo
2015/04/24 13:14:28
Maybe SkASSERT(fSrcRowBytes != 0)
msarett
2015/04/24 15:08:44
Done.
| |
303 SkAutoTDeleteArray<uint8_t> srcBuffer(SkNEW_ARRAY(uint8_t, srcRowBytes * row sPerDecode)); | |
304 JSAMPLE* srcRows[4]; | 338 JSAMPLE* srcRows[4]; |
305 uint8_t* srcPtr = srcBuffer.get(); | 339 uint8_t* srcPtr = srcBuffer.get(); |
306 for (uint8_t i = 0; i < rowsPerDecode; i++) { | 340 for (uint8_t i = 0; i < rowsPerDecode; i++) { |
307 srcRows[i] = (JSAMPLE*) srcPtr; | 341 srcRows[i] = (JSAMPLE*) srcPtr; |
308 srcPtr += srcRowBytes; | 342 srcPtr += fSrcRowBytes; |
309 } | 343 } |
310 | 344 |
311 // Ensure that we loop enough times to decode all of the rows | 345 // Ensure that we loop enough times to decode all of the rows |
312 // libjpeg will prevent us from reading past the bottom of the image | 346 // libjpeg will prevent us from reading past the bottom of the image |
347 uint32_t dstHeight = dstInfo.height(); | |
313 for (uint32_t y = 0; y < dstHeight + rowsPerDecode - 1; y += rowsPerDecode) { | 348 for (uint32_t y = 0; y < dstHeight + rowsPerDecode - 1; y += rowsPerDecode) { |
314 // Read rows of the image | 349 // Read rows of the image |
315 uint32_t rowsDecoded = jpeg_read_scanlines(dinfo, srcRows, rowsPerDecode ); | 350 uint32_t rowsDecoded = jpeg_read_scanlines(dinfo, srcRows, rowsPerDecode ); |
316 | 351 |
317 // Convert to RGB if necessary | 352 // Convert to RGB if necessary |
318 if (JCS_CMYK == dinfo->out_color_space) { | 353 if (JCS_CMYK == dinfo->out_color_space) { |
319 convert_CMYK_to_RGB(srcRows[0], dstWidth * rowsDecoded); | 354 convert_CMYK_to_RGB(srcRows[0], fSrcRowBytes * rowsDecoded); |
320 } | 355 } |
321 | 356 |
322 // Swizzle to output destination | 357 // Swizzle to output destination |
323 for (uint32_t i = 0; i < rowsDecoded; i++) { | 358 for (uint32_t i = 0; i < rowsDecoded; i++) { |
324 swizzler->next(srcRows[i]); | 359 fSwizzler->next(srcRows[i]); |
325 } | 360 } |
326 | 361 |
327 // If we cannot read enough rows, assume the input is incomplete | 362 // If we cannot read enough rows, assume the input is incomplete |
328 if (rowsDecoded < rowsPerDecode && y + rowsDecoded < dstHeight) { | 363 if (rowsDecoded < rowsPerDecode && y + rowsDecoded < dstHeight) { |
329 // Fill the remainder of the image with black. This error handling | 364 // Fill the remainder of the image with black. This error handling |
330 // behavior is unspecified but SkCodec consistently uses black as | 365 // behavior is unspecified but SkCodec consistently uses black as |
331 // the fill color for opaque images. If the destination is kGray, | 366 // the fill color for opaque images. If the destination is kGray, |
332 // the low 8 bits of SK_ColorBLACK will be used. Conveniently, | 367 // the low 8 bits of SK_ColorBLACK will be used. Conveniently, |
333 // these are zeros, which is the representation for black in kGray. | 368 // these are zeros, which is the representation for black in kGray. |
334 SkSwizzler::Fill(swizzler->getDstRow(), dstInfo, dstRowBytes, | 369 SkSwizzler::Fill(fSwizzler->getDstRow(), dstInfo, dstRowBytes, |
335 dstHeight - y - rowsDecoded, SK_ColorBLACK, NULL); | 370 dstHeight - y - rowsDecoded, SK_ColorBLACK, NULL); |
336 | 371 |
337 // Prevent libjpeg from failing on incomplete decode | 372 // Prevent libjpeg from failing on incomplete decode |
338 dinfo->output_scanline = dstHeight; | 373 dinfo->output_scanline = dstHeight; |
339 | 374 |
340 // Finish the decode and indicate that the input was incomplete. | 375 // Finish the decode and indicate that the input was incomplete. |
341 jpeg_finish_decompress(dinfo); | 376 jpeg_finish_decompress(dinfo); |
342 return fDecoderMgr->returnFailure("Incomplete image data", kIncomple teInput); | 377 return fDecoderMgr->returnFailure("Incomplete image data", kIncomple teInput); |
343 } | 378 } |
344 } | 379 } |
345 jpeg_finish_decompress(dinfo); | 380 jpeg_finish_decompress(dinfo); |
346 | 381 |
347 return kSuccess; | 382 return kSuccess; |
348 } | 383 } |
384 | |
385 /* | |
386 * Enable scanline decoding for jpegs | |
387 */ | |
388 class SkJpegScanlineDecoder : public SkScanlineDecoder { | |
389 public: | |
390 SkJpegScanlineDecoder(const SkImageInfo& dstInfo, SkJpegCodec* codec) | |
391 : INHERITED(dstInfo) | |
392 , fCodec(codec) | |
393 { | |
394 fStorage.reset(fCodec->fSrcRowBytes); | |
395 fSrcRow = static_cast<uint8_t*>(fStorage.get()); | |
396 } | |
397 | |
398 SkImageGenerator::Result onGetScanlines(void* dst, int count, size_t rowByte s) override { | |
399 // Set the jump location for libjpeg errors | |
400 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) { | |
401 return fCodec->fDecoderMgr->returnFailure("setjmp", SkImageGenerator ::kInvalidInput); | |
402 } | |
403 | |
404 // Read rows one at a time | |
405 for (int y = 0; y < count; y++) { | |
406 // Read row of the image | |
407 uint32_t rowsDecoded = jpeg_read_scanlines(fCodec->fDecoderMgr->dinf o(), &fSrcRow, 1); | |
msarett
2015/04/22 19:52:21
Here we intentionally decode rows one at a time.
| |
408 if (rowsDecoded != 1) { | |
409 SkSwizzler::Fill(dst, this->dstInfo(), rowBytes, count - y, SK_C olorBLACK, NULL); | |
410 return SkImageGenerator::kIncompleteInput; | |
411 } | |
412 | |
413 // Convert to RGB if necessary | |
414 if (JCS_CMYK == fCodec->fDecoderMgr->dinfo()->out_color_space) { | |
415 convert_CMYK_to_RGB(fSrcRow, fCodec->fSrcRowBytes); | |
416 } | |
417 | |
418 // Swizzle to output destination | |
419 fCodec->fSwizzler->setDstRow(dst); | |
420 fCodec->fSwizzler->next(fSrcRow); | |
421 dst = SkTAddOffset<void>(dst, rowBytes); | |
422 } | |
423 | |
424 return SkImageGenerator::kSuccess; | |
425 } | |
426 | |
427 SkImageGenerator::Result onSkipScanlines(int count) override { | |
428 // Set the jump location for libjpeg errors | |
429 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) { | |
430 return fCodec->fDecoderMgr->returnFailure("setjmp", SkImageGenerator ::kInvalidInput); | |
431 } | |
432 | |
433 // Read rows but ignore the output | |
434 for (int y = 0; y < count; y++) { | |
435 jpeg_read_scanlines(fCodec->fDecoderMgr->dinfo(), &fSrcRow, 1); | |
msarett
2015/04/22 19:52:21
AFAICT there is not a skip function in libjpeg.
W
scroggo
2015/04/24 13:14:28
This seems fine to me, until/unless we discover it
| |
436 } | |
437 | |
438 return SkImageGenerator::kSuccess; | |
439 } | |
440 | |
441 void onFinish() override { | |
442 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) { | |
443 SkCodecPrintf("setjmp: Error in libjpeg finish_decompress\n"); | |
444 return; | |
445 } | |
446 | |
447 jpeg_finish_decompress(fCodec->fDecoderMgr->dinfo()); | |
448 } | |
449 | |
450 private: | |
451 SkJpegCodec* fCodec; // unowned | |
452 SkAutoMalloc fStorage; | |
453 uint8_t* fSrcRow; | |
scroggo
2015/04/24 13:14:28
// pointer into fStorage
msarett
2015/04/24 15:08:44
Done.
| |
454 | |
455 typedef SkScanlineDecoder INHERITED; | |
456 }; | |
457 | |
458 SkScanlineDecoder* SkJpegCodec::onGetScanlineDecoder(const SkImageInfo& dstInfo, | |
459 const Options& options, SkPMColor ctable[], int* ctableCount) { | |
460 | |
461 // Rewind the stream if needed | |
462 if (!this->handleRewind()) { | |
463 SkCodecPrintf("Could not rewind\n"); | |
464 return NULL; | |
465 } | |
466 | |
467 // Set the jump location for libjpeg errors | |
468 if (setjmp(fDecoderMgr->getJmpBuf())) { | |
469 SkCodecPrintf("setjmp: Error from libjpeg\n"); | |
470 return NULL; | |
471 } | |
472 | |
473 // Check if we can decode to the requested destination | |
474 if (!conversion_possible(dstInfo, this->getInfo())) { | |
475 SkCodecPrintf("Cannot convert to output type\n"); | |
476 return NULL; | |
477 } | |
478 | |
479 // Perform the necessary scaling | |
480 if (!this->handleScaling(dstInfo)) { | |
481 SkCodecPrintf("Cannot scale ot output dimensions\n"); | |
482 return NULL; | |
483 } | |
484 | |
485 // Now, given valid output dimensions, we can start the decompress | |
486 if (!jpeg_start_decompress(fDecoderMgr->dinfo())) { | |
487 SkCodecPrintf("start decompress failed\n"); | |
488 return NULL; | |
489 } | |
490 | |
491 // Create the swizzler | |
492 this->initializeSwizzler(dstInfo, NULL, dstInfo.minRowBytes(), options); | |
493 if (NULL == fSwizzler) { | |
494 SkCodecPrintf("Could not create swizzler\n"); | |
495 return NULL; | |
496 } | |
497 | |
498 // Return the new scanline decoder | |
499 return SkNEW_ARGS(SkJpegScanlineDecoder, (dstInfo, this)); | |
500 } | |
OLD | NEW |