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

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

Powered by Google App Engine
This is Rietveld 408576698