| 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 |