Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(85)

Side by Side Diff: src/codec/SkJpegCodec.cpp

Issue 1332053002: Fill incomplete images in SkCodec parent class (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698