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 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
296 } | 296 } |
297 return true; | 297 return true; |
298 } | 298 } |
299 | 299 |
300 /* | 300 /* |
301 * Performs the jpeg decode | 301 * Performs the jpeg decode |
302 */ | 302 */ |
303 SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo, | 303 SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo, |
304 void* dst, size_t dstRowBytes, | 304 void* dst, size_t dstRowBytes, |
305 const Options& options, SkPMColor*, int
*) { | 305 const Options& options, SkPMColor*, int
*) { |
306 | |
307 // Do not allow a regular decode if the caller has asked for a scanline deco
der | |
308 if (NULL != this->scanlineDecoder()) { | |
309 return fDecoderMgr->returnFailure("cannot getPixels() if a scanline deco
der has been" | |
310 "created", kInvalidParameters); | |
311 } | |
312 | |
313 // Rewind the stream if needed | 306 // Rewind the stream if needed |
314 if (!this->handleRewind()) { | 307 if (!this->handleRewind()) { |
315 return fDecoderMgr->returnFailure("could not rewind stream", kCouldNotRe
wind); | 308 return fDecoderMgr->returnFailure("could not rewind stream", kCouldNotRe
wind); |
316 } | 309 } |
317 | 310 |
318 // Get a pointer to the decompress info since we will use it quite frequentl
y | 311 // Get a pointer to the decompress info since we will use it quite frequentl
y |
319 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo(); | 312 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo(); |
320 | 313 |
321 // Set the jump location for libjpeg errors | 314 // Set the jump location for libjpeg errors |
322 if (setjmp(fDecoderMgr->getJmpBuf())) { | 315 if (setjmp(fDecoderMgr->getJmpBuf())) { |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
373 | 366 |
374 // Move to the next row | 367 // Move to the next row |
375 dstRow = SkTAddOffset<JSAMPLE>(dstRow, dstRowBytes); | 368 dstRow = SkTAddOffset<JSAMPLE>(dstRow, dstRowBytes); |
376 } | 369 } |
377 turbo_jpeg_finish_decompress(dinfo); | 370 turbo_jpeg_finish_decompress(dinfo); |
378 | 371 |
379 return kSuccess; | 372 return kSuccess; |
380 } | 373 } |
381 | 374 |
382 /* | 375 /* |
383 * We override the destructor to ensure that the scanline decoder is left in a | |
384 * finished state before destroying the decode manager. | |
385 */ | |
386 SkJpegCodec::~SkJpegCodec() { | |
387 SkAutoTDelete<SkScanlineDecoder> decoder(this->detachScanlineDecoder()); | |
388 if (NULL != decoder) { | |
389 if (setjmp(fDecoderMgr->getJmpBuf())) { | |
390 SkCodecPrintf("setjmp: Error in libjpeg finish_decompress\n"); | |
391 return; | |
392 } | |
393 | |
394 // We may not have decoded the entire image. Prevent libjpeg-turbo from
failing on a | |
395 // partial decode. | |
396 fDecoderMgr->dinfo()->output_scanline = this->getInfo().height(); | |
397 turbo_jpeg_finish_decompress(fDecoderMgr->dinfo()); | |
398 } | |
399 } | |
400 | |
401 /* | |
402 * Enable scanline decoding for jpegs | 376 * Enable scanline decoding for jpegs |
403 */ | 377 */ |
404 class SkJpegScanlineDecoder : public SkScanlineDecoder { | 378 class SkJpegScanlineDecoder : public SkScanlineDecoder { |
405 public: | 379 public: |
406 SkJpegScanlineDecoder(const SkImageInfo& dstInfo, SkJpegCodec* codec) | 380 SkJpegScanlineDecoder(const SkImageInfo& dstInfo, SkJpegCodec* codec) |
407 : INHERITED(dstInfo) | 381 : INHERITED(dstInfo) |
408 , fCodec(codec) | 382 , fCodec(codec) |
409 {} | 383 {} |
410 | 384 |
| 385 virtual ~SkJpegScanlineDecoder() { |
| 386 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) { |
| 387 SkCodecPrintf("setjmp: Error in libjpeg finish_decompress\n"); |
| 388 return; |
| 389 } |
| 390 |
| 391 // We may not have decoded the entire image. Prevent libjpeg-turbo from
failing on a |
| 392 // partial decode. |
| 393 fCodec->fDecoderMgr->dinfo()->output_scanline = fCodec->getInfo().height
(); |
| 394 turbo_jpeg_finish_decompress(fCodec->fDecoderMgr->dinfo()); |
| 395 } |
| 396 |
411 SkCodec::Result onGetScanlines(void* dst, int count, size_t rowBytes) overri
de { | 397 SkCodec::Result onGetScanlines(void* dst, int count, size_t rowBytes) overri
de { |
412 // Set the jump location for libjpeg errors | 398 // Set the jump location for libjpeg errors |
413 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) { | 399 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) { |
414 return fCodec->fDecoderMgr->returnFailure("setjmp", SkCodec::kInvali
dInput); | 400 return fCodec->fDecoderMgr->returnFailure("setjmp", SkCodec::kInvali
dInput); |
415 } | 401 } |
416 | 402 |
417 // Read rows one at a time | 403 // Read rows one at a time |
418 JSAMPLE* dstRow = (JSAMPLE*) dst; | 404 JSAMPLE* dstRow = (JSAMPLE*) dst; |
419 for (int y = 0; y < count; y++) { | 405 for (int y = 0; y < count; y++) { |
420 // Read row of the image | 406 // Read row of the image |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
453 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) { | 439 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) { |
454 return fCodec->fDecoderMgr->returnFailure("setjmp", SkCodec::kInvali
dInput); | 440 return fCodec->fDecoderMgr->returnFailure("setjmp", SkCodec::kInvali
dInput); |
455 } | 441 } |
456 | 442 |
457 turbo_jpeg_skip_scanlines(fCodec->fDecoderMgr->dinfo(), count); | 443 turbo_jpeg_skip_scanlines(fCodec->fDecoderMgr->dinfo(), count); |
458 | 444 |
459 return SkCodec::kSuccess; | 445 return SkCodec::kSuccess; |
460 } | 446 } |
461 | 447 |
462 private: | 448 private: |
463 SkJpegCodec* fCodec; // unowned | 449 SkAutoTDelete<SkJpegCodec> fCodec; |
464 | 450 |
465 typedef SkScanlineDecoder INHERITED; | 451 typedef SkScanlineDecoder INHERITED; |
466 }; | 452 }; |
467 | 453 |
468 SkScanlineDecoder* SkJpegCodec::onGetScanlineDecoder(const SkImageInfo& dstInfo, | 454 SkScanlineDecoder* SkJpegCodec::onGetScanlineDecoder(const SkImageInfo& dstInfo, |
469 const Options& options, SkPMColor ctable[], int* ctableCount) { | 455 const Options& options, SkPMColor ctable[], int* ctableCount) { |
470 | 456 |
471 // Rewind the stream if needed | 457 // Rewind the stream if needed |
472 if (!this->handleRewind()) { | 458 if (!this->handleRewind()) { |
473 SkCodecPrintf("Could not rewind\n"); | 459 SkCodecPrintf("Could not rewind\n"); |
474 return NULL; | 460 return NULL; |
475 } | 461 } |
476 | 462 |
477 // Set the jump location for libjpeg errors | 463 // Set the jump location for libjpeg errors |
478 if (setjmp(fDecoderMgr->getJmpBuf())) { | 464 if (setjmp(fDecoderMgr->getJmpBuf())) { |
479 SkCodecPrintf("setjmp: Error from libjpeg\n"); | 465 SkCodecPrintf("setjmp: Error from libjpeg\n"); |
480 return NULL; | 466 return NULL; |
481 } | 467 } |
482 | 468 |
| 469 SkStream* stream = this->stream()->duplicate(); |
| 470 if (!stream) { |
| 471 return NULL; |
| 472 } |
| 473 SkAutoTDelete<SkJpegCodec> codec(static_cast<SkJpegCodec*>(SkJpegCodec::NewF
romStream(stream))); |
| 474 if (!codec) { |
| 475 return NULL; |
| 476 } |
| 477 |
483 // Check if we can decode to the requested destination and set the output co
lor space | 478 // Check if we can decode to the requested destination and set the output co
lor space |
484 if (!this->setOutputColorSpace(dstInfo)) { | 479 if (!codec->setOutputColorSpace(dstInfo)) { |
485 SkCodecPrintf("Cannot convert to output type\n"); | 480 SkCodecPrintf("Cannot convert to output type\n"); |
486 return NULL; | 481 return NULL; |
487 } | 482 } |
488 | 483 |
489 // Perform the necessary scaling | 484 // Perform the necessary scaling |
490 if (!this->scaleToDimensions(dstInfo.width(), dstInfo.height())) { | 485 if (!codec->scaleToDimensions(dstInfo.width(), dstInfo.height())) { |
491 SkCodecPrintf("Cannot scale to output dimensions\n"); | 486 SkCodecPrintf("Cannot scale to output dimensions\n"); |
492 return NULL; | 487 return NULL; |
493 } | 488 } |
494 | 489 |
495 // Now, given valid output dimensions, we can start the decompress | 490 // Now, given valid output dimensions, we can start the decompress |
496 if (!turbo_jpeg_start_decompress(fDecoderMgr->dinfo())) { | 491 if (!turbo_jpeg_start_decompress(codec->fDecoderMgr->dinfo())) { |
497 SkCodecPrintf("start decompress failed\n"); | 492 SkCodecPrintf("start decompress failed\n"); |
498 return NULL; | 493 return NULL; |
499 } | 494 } |
500 | 495 |
501 // Return the new scanline decoder | 496 // Return the new scanline decoder |
502 return SkNEW_ARGS(SkJpegScanlineDecoder, (dstInfo, this)); | 497 return SkNEW_ARGS(SkJpegScanlineDecoder, (dstInfo, codec.detach())); |
503 } | 498 } |
OLD | NEW |