Chromium Code Reviews| 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 336 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 347 // Read rows of the image | 347 // Read rows of the image | 
| 348 uint32_t rowsDecoded = turbo_jpeg_read_scanlines(dinfo, &dstRow, 1); | 348 uint32_t rowsDecoded = turbo_jpeg_read_scanlines(dinfo, &dstRow, 1); | 
| 349 | 349 | 
| 350 // If we cannot read enough rows, assume the input is incomplete | 350 // If we cannot read enough rows, assume the input is incomplete | 
| 351 if (rowsDecoded != 1) { | 351 if (rowsDecoded != 1) { | 
| 352 // Fill the remainder of the image with black. This error handling | 352 // Fill the remainder of the image with black. This error handling | 
| 353 // behavior is unspecified but SkCodec consistently uses black as | 353 // behavior is unspecified but SkCodec consistently uses black as | 
| 354 // the fill color for opaque images. If the destination is kGray, | 354 // the fill color for opaque images. If the destination is kGray, | 
| 355 // the low 8 bits of SK_ColorBLACK will be used. Conveniently, | 355 // the low 8 bits of SK_ColorBLACK will be used. Conveniently, | 
| 356 // these are zeros, which is the representation for black in kGray. | 356 // these are zeros, which is the representation for black in kGray. | 
| 357 SkSwizzler::Fill(dstRow, dstInfo, dstRowBytes, dstHeight - y, SK_Col orBLACK, NULL); | 357 // If the destination is kRGB_565, the low 16 bits of SK_ColorBLACK | 
| 358 // will be used. Conveniently, these are zeros, which is the | |
| 359 // representation for black in kRGB_565. | |
| 360 if (kNo_ZeroInitialized == options.fZeroInitialized || | |
| 361 kN32_SkColorType == dstInfo.colorType()) { | |
| 362 SkSwizzler::Fill(dstRow, dstInfo, dstRowBytes, dstHeight - y, | |
| 363 SK_ColorBLACK, NULL); | |
| 364 } | |
| 358 | 365 | 
| 359 // Prevent libjpeg from failing on incomplete decode | 366 // Prevent libjpeg from failing on incomplete decode | 
| 360 dinfo->output_scanline = dstHeight; | 367 dinfo->output_scanline = dstHeight; | 
| 361 | 368 | 
| 362 // Finish the decode and indicate that the input was incomplete. | 369 // Finish the decode and indicate that the input was incomplete. | 
| 363 turbo_jpeg_finish_decompress(dinfo); | 370 turbo_jpeg_finish_decompress(dinfo); | 
| 364 return fDecoderMgr->returnFailure("Incomplete image data", kIncomple teInput); | 371 return fDecoderMgr->returnFailure("Incomplete image data", kIncomple teInput); | 
| 365 } | 372 } | 
| 366 | 373 | 
| 367 // Convert to RGBA if necessary | 374 // Convert to RGBA if necessary | 
| 368 if (JCS_CMYK == dinfo->out_color_space) { | 375 if (JCS_CMYK == dinfo->out_color_space) { | 
| 369 convert_CMYK_to_RGBA(dstRow, dstInfo.width()); | 376 convert_CMYK_to_RGBA(dstRow, dstInfo.width()); | 
| 370 } | 377 } | 
| 371 | 378 | 
| 372 // Move to the next row | 379 // Move to the next row | 
| 373 dstRow = SkTAddOffset<JSAMPLE>(dstRow, dstRowBytes); | 380 dstRow = SkTAddOffset<JSAMPLE>(dstRow, dstRowBytes); | 
| 374 } | 381 } | 
| 375 turbo_jpeg_finish_decompress(dinfo); | 382 turbo_jpeg_finish_decompress(dinfo); | 
| 376 | 383 | 
| 377 return kSuccess; | 384 return kSuccess; | 
| 378 } | 385 } | 
| 379 | 386 | 
| 380 /* | 387 /* | 
| 381 * Enable scanline decoding for jpegs | 388 * Enable scanline decoding for jpegs | 
| 382 */ | 389 */ | 
| 383 class SkJpegScanlineDecoder : public SkScanlineDecoder { | 390 class SkJpegScanlineDecoder : public SkScanlineDecoder { | 
| 384 public: | 391 public: | 
| 385 SkJpegScanlineDecoder(const SkImageInfo& dstInfo, SkJpegCodec* codec) | 392 SkJpegScanlineDecoder(const SkImageInfo& dstInfo, SkJpegCodec* codec, | 
| 393 const SkCodec::Options& opts) | |
| 386 : INHERITED(dstInfo) | 394 : INHERITED(dstInfo) | 
| 387 , fCodec(codec) | 395 , fCodec(codec) | 
| 396 , fOpts(opts) | |
| 388 {} | 397 {} | 
| 389 | 398 | 
| 390 virtual ~SkJpegScanlineDecoder() { | 399 virtual ~SkJpegScanlineDecoder() { | 
| 391 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) { | 400 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) { | 
| 392 SkCodecPrintf("setjmp: Error in libjpeg finish_decompress\n"); | 401 SkCodecPrintf("setjmp: Error in libjpeg finish_decompress\n"); | 
| 393 return; | 402 return; | 
| 394 } | 403 } | 
| 395 | 404 | 
| 396 // We may not have decoded the entire image. Prevent libjpeg-turbo from failing on a | 405 // We may not have decoded the entire image. Prevent libjpeg-turbo from failing on a | 
| 397 // partial decode. | 406 // partial decode. | 
| 398 fCodec->fDecoderMgr->dinfo()->output_scanline = fCodec->getInfo().height (); | 407 fCodec->fDecoderMgr->dinfo()->output_scanline = fCodec->getInfo().height (); | 
| 399 turbo_jpeg_finish_decompress(fCodec->fDecoderMgr->dinfo()); | 408 turbo_jpeg_finish_decompress(fCodec->fDecoderMgr->dinfo()); | 
| 400 } | 409 } | 
| 401 | 410 | 
| 402 SkCodec::Result onGetScanlines(void* dst, int count, size_t rowBytes) overri de { | 411 SkCodec::Result onGetScanlines(void* dst, int count, size_t rowBytes) overri de { | 
| 403 // Set the jump location for libjpeg errors | 412 // Set the jump location for libjpeg errors | 
| 404 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) { | 413 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) { | 
| 405 return fCodec->fDecoderMgr->returnFailure("setjmp", SkCodec::kInvali dInput); | 414 return fCodec->fDecoderMgr->returnFailure("setjmp", SkCodec::kInvali dInput); | 
| 406 } | 415 } | 
| 407 | 416 | 
| 408 // Read rows one at a time | 417 // Read rows one at a time | 
| 409 JSAMPLE* dstRow = (JSAMPLE*) dst; | 418 JSAMPLE* dstRow = (JSAMPLE*) dst; | 
| 410 for (int y = 0; y < count; y++) { | 419 for (int y = 0; y < count; y++) { | 
| 411 // Read row of the image | 420 // Read row of the image | 
| 412 uint32_t rowsDecoded = | 421 uint32_t rowsDecoded = | 
| 413 turbo_jpeg_read_scanlines(fCodec->fDecoderMgr->dinfo(), &dst Row, 1); | 422 turbo_jpeg_read_scanlines(fCodec->fDecoderMgr->dinfo(), &dst Row, 1); | 
| 414 if (rowsDecoded != 1) { | 423 if (rowsDecoded != 1) { | 
| 415 SkSwizzler::Fill( | 424 if (SkCodec::kNo_ZeroInitialized == fOpts.fZeroInitialized || | 
| 416 dstRow, this->dstInfo(), rowBytes, count - y, SK_ColorBL ACK, NULL); | 425 kN32_SkColorType == this->dstInfo().colorType()) { | 
| 426 SkSwizzler::Fill(dstRow, this->dstInfo(), rowBytes, | |
| 427 count - y, SK_ColorBLACK, NULL); | |
| 428 } | |
| 417 fCodec->fDecoderMgr->dinfo()->output_scanline = this->dstInfo(). height(); | 429 fCodec->fDecoderMgr->dinfo()->output_scanline = this->dstInfo(). height(); | 
| 418 return SkCodec::kIncompleteInput; | 430 return SkCodec::kIncompleteInput; | 
| 419 } | 431 } | 
| 420 | 432 | 
| 421 // Convert to RGBA if necessary | 433 // Convert to RGBA if necessary | 
| 422 if (JCS_CMYK == fCodec->fDecoderMgr->dinfo()->out_color_space) { | 434 if (JCS_CMYK == fCodec->fDecoderMgr->dinfo()->out_color_space) { | 
| 423 convert_CMYK_to_RGBA(dstRow, this->dstInfo().width()); | 435 convert_CMYK_to_RGBA(dstRow, this->dstInfo().width()); | 
| 424 } | 436 } | 
| 425 | 437 | 
| 426 // Move to the next row | 438 // Move to the next row | 
| (...skipping 18 matching lines...) Expand all Loading... | |
| 445 return fCodec->fDecoderMgr->returnFailure("setjmp", SkCodec::kInvali dInput); | 457 return fCodec->fDecoderMgr->returnFailure("setjmp", SkCodec::kInvali dInput); | 
| 446 } | 458 } | 
| 447 | 459 | 
| 448 turbo_jpeg_skip_scanlines(fCodec->fDecoderMgr->dinfo(), count); | 460 turbo_jpeg_skip_scanlines(fCodec->fDecoderMgr->dinfo(), count); | 
| 449 | 461 | 
| 450 return SkCodec::kSuccess; | 462 return SkCodec::kSuccess; | 
| 451 } | 463 } | 
| 452 | 464 | 
| 453 private: | 465 private: | 
| 454 SkAutoTDelete<SkJpegCodec> fCodec; | 466 SkAutoTDelete<SkJpegCodec> fCodec; | 
| 467 const SkCodec::Options& fOpts; | |
| 
 
scroggo
2015/08/03 18:41:24
I missed this when I first reviewed, but mention i
 
 | |
| 455 | 468 | 
| 456 typedef SkScanlineDecoder INHERITED; | 469 typedef SkScanlineDecoder INHERITED; | 
| 457 }; | 470 }; | 
| 458 | 471 | 
| 459 SkScanlineDecoder* SkJpegCodec::onGetScanlineDecoder(const SkImageInfo& dstInfo, | 472 SkScanlineDecoder* SkJpegCodec::onGetScanlineDecoder(const SkImageInfo& dstInfo, | 
| 460 const Options& options, SkPMColor ctable[], int* ctableCount) { | 473 const Options& options, SkPMColor ctable[], int* ctableCount) { | 
| 461 | 474 | 
| 462 // Rewind the stream if needed | 475 // Rewind the stream if needed | 
| 463 if (!this->handleRewind()) { | 476 if (!this->handleRewind()) { | 
| 464 SkCodecPrintf("Could not rewind\n"); | 477 SkCodecPrintf("Could not rewind\n"); | 
| (...skipping 27 matching lines...) Expand all Loading... | |
| 492 return NULL; | 505 return NULL; | 
| 493 } | 506 } | 
| 494 | 507 | 
| 495 // Now, given valid output dimensions, we can start the decompress | 508 // Now, given valid output dimensions, we can start the decompress | 
| 496 if (!turbo_jpeg_start_decompress(codec->fDecoderMgr->dinfo())) { | 509 if (!turbo_jpeg_start_decompress(codec->fDecoderMgr->dinfo())) { | 
| 497 SkCodecPrintf("start decompress failed\n"); | 510 SkCodecPrintf("start decompress failed\n"); | 
| 498 return NULL; | 511 return NULL; | 
| 499 } | 512 } | 
| 500 | 513 | 
| 501 // Return the new scanline decoder | 514 // Return the new scanline decoder | 
| 502 return SkNEW_ARGS(SkJpegScanlineDecoder, (dstInfo, codec.detach())); | 515 return SkNEW_ARGS(SkJpegScanlineDecoder, (dstInfo, codec.detach(), options)) ; | 
| 503 } | 516 } | 
| OLD | NEW |