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 328 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
339 | 339 |
340 // Perform the decode a single row at a time | 340 // Perform the decode a single row at a time |
341 uint32_t dstHeight = dstInfo.height(); | 341 uint32_t dstHeight = dstInfo.height(); |
342 JSAMPLE* dstRow = (JSAMPLE*) dst; | 342 JSAMPLE* dstRow = (JSAMPLE*) dst; |
343 for (uint32_t y = 0; y < dstHeight; y++) { | 343 for (uint32_t y = 0; y < dstHeight; y++) { |
344 // Read rows of the image | 344 // Read rows of the image |
345 uint32_t rowsDecoded = jpeg_read_scanlines(dinfo, &dstRow, 1); | 345 uint32_t rowsDecoded = jpeg_read_scanlines(dinfo, &dstRow, 1); |
346 | 346 |
347 // If we cannot read enough rows, assume the input is incomplete | 347 // If we cannot read enough rows, assume the input is incomplete |
348 if (rowsDecoded != 1) { | 348 if (rowsDecoded != 1) { |
349 // Fill the remainder of the image with black. This error handling | 349 this->setIncompleteScanlines(dstHeight - y); |
350 // behavior is unspecified but SkCodec consistently uses black as | |
351 // the fill color for opaque images. If the destination is kGray, | |
352 // the low 8 bits of SK_ColorBLACK will be used. Conveniently, | |
353 // these are zeros, which is the representation for black in kGray. | |
354 // If the destination is kRGB_565, the low 16 bits of SK_ColorBLACK | |
355 // will be used. Conveniently, these are zeros, which is the | |
356 // representation for black in kRGB_565. | |
357 SkSwizzler::Fill(dstRow, dstInfo, dstRowBytes, dstHeight - y, | |
358 SK_ColorBLACK, nullptr, options.fZeroInitialized); | |
359 | 350 |
360 // Prevent libjpeg from failing on incomplete decode | 351 // Prevent libjpeg from failing on incomplete decode |
361 dinfo->output_scanline = dstHeight; | 352 dinfo->output_scanline = dstHeight; |
362 | 353 |
363 // Finish the decode and indicate that the input was incomplete. | 354 // Finish the decode and indicate that the input was incomplete. |
364 jpeg_finish_decompress(dinfo); | 355 jpeg_finish_decompress(dinfo); |
365 return fDecoderMgr->returnFailure("Incomplete image data", kIncomple
teInput); | 356 return fDecoderMgr->returnFailure("Incomplete image data", kIncomple
teInput); |
366 } | 357 } |
367 | 358 |
368 // Convert to RGBA if necessary | 359 // Convert to RGBA if necessary |
369 if (JCS_CMYK == dinfo->out_color_space) { | 360 if (JCS_CMYK == dinfo->out_color_space) { |
370 convert_CMYK_to_RGBA(dstRow, dstInfo.width()); | 361 convert_CMYK_to_RGBA(dstRow, dstInfo.width()); |
371 } | 362 } |
372 | 363 |
373 // Move to the next row | 364 // Move to the next row |
374 dstRow = SkTAddOffset<JSAMPLE>(dstRow, dstRowBytes); | 365 dstRow = SkTAddOffset<JSAMPLE>(dstRow, dstRowBytes); |
375 } | 366 } |
376 jpeg_finish_decompress(dinfo); | 367 jpeg_finish_decompress(dinfo); |
377 | 368 |
378 return kSuccess; | 369 return kSuccess; |
379 } | 370 } |
380 | 371 |
381 /* | 372 /* |
382 * Enable scanline decoding for jpegs | 373 * Enable scanline decoding for jpegs |
383 */ | 374 */ |
384 class SkJpegScanlineDecoder : public SkScanlineDecoder { | 375 class SkJpegScanlineDecoder : public SkScanlineDecoder { |
385 public: | 376 public: |
386 SkJpegScanlineDecoder(const SkImageInfo& srcInfo, SkJpegCodec* codec) | 377 SkJpegScanlineDecoder(SkJpegCodec* codec) |
387 : INHERITED(srcInfo) | 378 : INHERITED(codec, codec->getInfo()) |
388 , fCodec(codec) | 379 , fCodec(codec) |
389 , fOpts() | 380 , fOpts() |
390 {} | 381 {} |
391 | 382 |
392 /* | 383 /* |
393 * Return a valid set of output dimensions for this decoder, given an input s
cale | 384 * Return a valid set of output dimensions for this decoder, given an input s
cale |
394 */ | 385 */ |
395 SkISize onGetScaledDimensions(float desiredScale) override { | 386 SkISize onGetScaledDimensions(float desiredScale) override { |
396 return fCodec->onGetScaledDimensions(desiredScale); | 387 return fCodec->onGetScaledDimensions(desiredScale); |
397 } | 388 } |
(...skipping 16 matching lines...) Expand all Loading... |
414 srcConfig = SkSwizzler::kBGRX; | 405 srcConfig = SkSwizzler::kBGRX; |
415 break; | 406 break; |
416 case kRGB_565_SkColorType: | 407 case kRGB_565_SkColorType: |
417 srcConfig = SkSwizzler::kRGB_565; | 408 srcConfig = SkSwizzler::kRGB_565; |
418 break; | 409 break; |
419 default: | 410 default: |
420 //would have exited before now if the colorType was supported by
jpeg | 411 //would have exited before now if the colorType was supported by
jpeg |
421 SkASSERT(false); | 412 SkASSERT(false); |
422 } | 413 } |
423 | 414 |
424 fSwizzler.reset(SkSwizzler::CreateSwizzler(srcConfig, nullptr, info, opt
ions.fZeroInitialized, | 415 fSwizzler.reset(SkSwizzler::CreateSwizzler(srcConfig, nullptr, info, |
425 this->getInfo())); | 416 options.fZeroInitialized, this->getInfo())); |
426 if (!fSwizzler) { | 417 if (!fSwizzler) { |
427 // FIXME: CreateSwizzler could fail for another reason. | 418 // FIXME: CreateSwizzler could fail for another reason. |
428 return SkCodec::kUnimplemented; | 419 return SkCodec::kUnimplemented; |
429 } | 420 } |
430 return SkCodec::kSuccess; | 421 return SkCodec::kSuccess; |
431 } | 422 } |
432 | 423 |
433 SkCodec::Result onStart(const SkImageInfo& dstInfo, const SkCodec::Options&
options, | 424 SkCodec::Result onStart(const SkImageInfo& dstInfo, const SkCodec::Options&
options, |
434 SkPMColor ctable[], int* ctableCount) override { | 425 SkPMColor ctable[], int* ctableCount) override { |
435 | 426 |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
485 SkCodecPrintf("setjmp: Error in libjpeg finish_decompress\n"); | 476 SkCodecPrintf("setjmp: Error in libjpeg finish_decompress\n"); |
486 return; | 477 return; |
487 } | 478 } |
488 | 479 |
489 // We may not have decoded the entire image. Prevent libjpeg-turbo from
failing on a | 480 // We may not have decoded the entire image. Prevent libjpeg-turbo from
failing on a |
490 // partial decode. | 481 // partial decode. |
491 fCodec->fDecoderMgr->dinfo()->output_scanline = fCodec->getInfo().height
(); | 482 fCodec->fDecoderMgr->dinfo()->output_scanline = fCodec->getInfo().height
(); |
492 jpeg_finish_decompress(fCodec->fDecoderMgr->dinfo()); | 483 jpeg_finish_decompress(fCodec->fDecoderMgr->dinfo()); |
493 } | 484 } |
494 | 485 |
495 SkCodec::Result onGetScanlines(void* dst, int count, size_t rowBytes) overri
de { | 486 uint32_t onGetScanlines(void* dst, int count, size_t rowBytes) override { |
496 // Set the jump location for libjpeg errors | 487 // Set the jump location for libjpeg errors |
497 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) { | 488 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) { |
498 return fCodec->fDecoderMgr->returnFailure("setjmp", SkCodec::kInvali
dInput); | 489 return fCodec->fDecoderMgr->returnFailure("setjmp", SkCodec::kInvali
dInput); |
499 } | 490 } |
500 // Read rows one at a time | 491 // Read rows one at a time |
501 JSAMPLE* dstRow; | 492 JSAMPLE* dstRow; |
502 if (fSwizzler) { | 493 if (fSwizzler) { |
503 // write data to storage row, then sample using swizzler | 494 // write data to storage row, then sample using swizzler |
504 dstRow = fSrcRow; | 495 dstRow = fSrcRow; |
505 } else { | 496 } else { |
506 // write data directly to dst | 497 // write data directly to dst |
507 dstRow = (JSAMPLE*) dst; | 498 dstRow = (JSAMPLE*) dst; |
508 } | 499 } |
509 | 500 |
510 for (int y = 0; y < count; y++) { | 501 for (int y = 0; y < count; y++) { |
511 // Read row of the image | 502 // Read row of the image |
512 uint32_t rowsDecoded = jpeg_read_scanlines(fCodec->fDecoderMgr->dinf
o(), &dstRow, 1); | 503 uint32_t rowsDecoded = jpeg_read_scanlines(fCodec->fDecoderMgr->dinf
o(), &dstRow, 1); |
513 if (rowsDecoded != 1) { | 504 if (rowsDecoded != 1) { |
514 SkSwizzler::Fill(dstRow, this->dstInfo(), rowBytes, count - y, | |
515 SK_ColorBLACK, nullptr, fOpts.fZeroInitialized); | |
516 fCodec->fDecoderMgr->dinfo()->output_scanline = this->dstInfo().
height(); | 505 fCodec->fDecoderMgr->dinfo()->output_scanline = this->dstInfo().
height(); |
517 return SkCodec::kIncompleteInput; | 506 return y; |
518 } | 507 } |
519 | 508 |
520 // Convert to RGBA if necessary | 509 // Convert to RGBA if necessary |
521 if (JCS_CMYK == fCodec->fDecoderMgr->dinfo()->out_color_space) { | 510 if (JCS_CMYK == fCodec->fDecoderMgr->dinfo()->out_color_space) { |
522 convert_CMYK_to_RGBA(dstRow, fCodec->fDecoderMgr->dinfo()->outpu
t_width); | 511 convert_CMYK_to_RGBA(dstRow, fCodec->fDecoderMgr->dinfo()->outpu
t_width); |
523 } | 512 } |
524 | 513 |
525 if(fSwizzler) { | 514 if(fSwizzler) { |
526 // use swizzler to sample row | 515 // use swizzler to sample row |
527 fSwizzler->swizzle(dst, dstRow); | 516 fSwizzler->swizzle(dst, dstRow); |
528 dst = SkTAddOffset<JSAMPLE>(dst, rowBytes); | 517 dst = SkTAddOffset<JSAMPLE>(dst, rowBytes); |
529 } else { | 518 } else { |
530 dstRow = SkTAddOffset<JSAMPLE>(dstRow, rowBytes); | 519 dstRow = SkTAddOffset<JSAMPLE>(dstRow, rowBytes); |
531 } | 520 } |
532 } | 521 } |
533 return SkCodec::kSuccess; | 522 return count; |
534 } | 523 } |
535 | 524 |
536 #ifndef TURBO_HAS_SKIP | 525 #ifndef TURBO_HAS_SKIP |
537 // TODO (msarett): Make this a member function and avoid reallocating the | 526 // TODO (msarett): Make this a member function and avoid reallocating the |
538 // memory buffer on each call to skip. | 527 // memory buffer on each call to skip. |
539 #define jpeg_skip_scanlines(dinfo, count) \ | 528 #define jpeg_skip_scanlines(dinfo, count) \ |
540 SkAutoMalloc storage(get_row_bytes(dinfo)); \ | 529 SkAutoMalloc storage(get_row_bytes(dinfo)); \ |
541 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get()); \ | 530 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get()); \ |
542 for (int y = 0; y < count; y++) { \ | 531 for (int y = 0; y < count; y++) { \ |
543 jpeg_read_scanlines(dinfo, &storagePtr, 1); \ | 532 jpeg_read_scanlines(dinfo, &storagePtr, 1); \ |
544 } | 533 } |
545 #endif | 534 #endif |
546 | 535 |
547 SkCodec::Result onSkipScanlines(int count) override { | 536 uint32_t onSkipScanlines(int count) override { |
548 // Set the jump location for libjpeg errors | 537 // Set the jump location for libjpeg errors |
549 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) { | 538 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) { |
550 return fCodec->fDecoderMgr->returnFailure("setjmp", SkCodec::kInvali
dInput); | 539 return fCodec->fDecoderMgr->returnFailure("setjmp", SkCodec::kInvali
dInput); |
551 } | 540 } |
552 | 541 |
553 jpeg_skip_scanlines(fCodec->fDecoderMgr->dinfo(), count); | 542 return jpeg_skip_scanlines(fCodec->fDecoderMgr->dinfo(), count); |
554 | |
555 return SkCodec::kSuccess; | |
556 } | 543 } |
557 | 544 |
558 SkEncodedFormat onGetEncodedFormat() const override { | 545 SkEncodedFormat onGetEncodedFormat() const override { |
559 return kJPEG_SkEncodedFormat; | 546 return kJPEG_SkEncodedFormat; |
560 } | 547 } |
561 | 548 |
562 private: | 549 private: |
563 SkAutoTDelete<SkJpegCodec> fCodec; | 550 SkJpegCodec* fCodec; // Owned by parent class |
564 SkAutoMalloc fStorage; // Only used if sampling is needed | 551 SkAutoMalloc fStorage; // Only used if sampling is needed |
565 uint8_t* fSrcRow; // Only used if sampling is needed | 552 uint8_t* fSrcRow; // Only used if sampling is needed |
566 SkCodec::Options fOpts; | 553 SkCodec::Options fOpts; |
567 SkAutoTDelete<SkSwizzler> fSwizzler; | 554 SkAutoTDelete<SkSwizzler> fSwizzler; |
568 | 555 |
569 typedef SkScanlineDecoder INHERITED; | 556 typedef SkScanlineDecoder INHERITED; |
570 }; | 557 }; |
571 | 558 |
572 SkScanlineDecoder* SkJpegCodec::NewSDFromStream(SkStream* stream) { | 559 SkScanlineDecoder* SkJpegCodec::NewSDFromStream(SkStream* stream) { |
573 SkAutoTDelete<SkJpegCodec> codec(static_cast<SkJpegCodec*>(SkJpegCodec::NewF
romStream(stream))); | 560 SkAutoTDelete<SkJpegCodec> codec(static_cast<SkJpegCodec*>(SkJpegCodec::NewF
romStream(stream))); |
574 if (!codec) { | 561 if (!codec) { |
575 return nullptr; | 562 return nullptr; |
576 } | 563 } |
577 | 564 |
578 const SkImageInfo& srcInfo = codec->getInfo(); | |
579 | |
580 // Return the new scanline decoder | 565 // Return the new scanline decoder |
581 return new SkJpegScanlineDecoder(srcInfo, codec.detach()); | 566 return new SkJpegScanlineDecoder(codec.detach()); |
582 } | 567 } |
OLD | NEW |