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

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

Issue 1365313002: Merge SkCodec with SkScanlineDecoder (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Skip ICO in SkScaledCodec for now Created 5 years, 2 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
« no previous file with comments | « src/codec/SkJpegCodec.h ('k') | src/codec/SkScaledCodec.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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"
11 #include "SkJpegUtility_codec.h" 11 #include "SkJpegUtility_codec.h"
12 #include "SkCodecPriv.h" 12 #include "SkCodecPriv.h"
13 #include "SkColorPriv.h" 13 #include "SkColorPriv.h"
14 #include "SkScaledCodec.h" 14 #include "SkScaledCodec.h"
15 #include "SkScanlineDecoder.h"
16 #include "SkStream.h" 15 #include "SkStream.h"
17 #include "SkTemplates.h" 16 #include "SkTemplates.h"
18 #include "SkTypes.h" 17 #include "SkTypes.h"
19 18
20 // stdio is needed for libjpeg-turbo 19 // stdio is needed for libjpeg-turbo
21 #include <stdio.h> 20 #include <stdio.h>
22 21
23 extern "C" { 22 extern "C" {
24 #include "jerror.h" 23 #include "jerror.h"
25 #include "jpeglib.h" 24 #include "jpeglib.h"
(...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after
375 } 374 }
376 375
377 // Move to the next row 376 // Move to the next row
378 dstRow = SkTAddOffset<JSAMPLE>(dstRow, dstRowBytes); 377 dstRow = SkTAddOffset<JSAMPLE>(dstRow, dstRowBytes);
379 } 378 }
380 jpeg_finish_decompress(dinfo); 379 jpeg_finish_decompress(dinfo);
381 380
382 return kSuccess; 381 return kSuccess;
383 } 382 }
384 383
385 /* 384 SkCodec::Result SkJpegCodec::initializeSwizzler(const SkImageInfo& info, const O ptions& options) {
386 * Enable scanline decoding for jpegs 385 SkSwizzler::SrcConfig srcConfig;
387 */ 386 switch (info.colorType()) {
388 class SkJpegScanlineDecoder : public SkScanlineDecoder { 387 case kGray_8_SkColorType:
389 public: 388 srcConfig = SkSwizzler::kGray;
390 SkJpegScanlineDecoder(const SkImageInfo& srcInfo, SkJpegCodec* codec) 389 break;
391 : INHERITED(srcInfo) 390 case kRGBA_8888_SkColorType:
392 , fCodec(codec) 391 srcConfig = SkSwizzler::kRGBX;
393 , fOpts() 392 break;
394 {} 393 case kBGRA_8888_SkColorType:
395 394 srcConfig = SkSwizzler::kBGRX;
396 /* 395 break;
397 * Return a valid set of output dimensions for this decoder, given an input s cale 396 case kRGB_565_SkColorType:
398 */ 397 srcConfig = SkSwizzler::kRGB_565;
399 SkISize onGetScaledDimensions(float desiredScale) override { 398 break;
400 return fCodec->onGetScaledDimensions(desiredScale); 399 default:
400 // This function should only be called if the colorType is supported by jpeg
401 SkASSERT(false);
401 } 402 }
402 403
403 /* 404 fSwizzler.reset(SkSwizzler::CreateSwizzler(srcConfig, nullptr, info, options .fZeroInitialized,
404 * Create the swizzler based on the encoded format. 405 this->getInfo()));
405 * The swizzler is only used for sampling in the x direction. 406 if (!fSwizzler) {
406 */ 407 return SkCodec::kUnimplemented;
408 }
407 409
408 SkCodec::Result initializeSwizzler(const SkImageInfo& info, const SkCodec::O ptions& options) { 410 return kSuccess;
409 SkSwizzler::SrcConfig srcConfig; 411 }
410 switch (info.colorType()) { 412
411 case kGray_8_SkColorType: 413 SkCodec::Result SkJpegCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
412 srcConfig = SkSwizzler::kGray; 414 const Options& options, SkPMColor ctable[], int* ctableCount) {
413 break; 415 // Rewind the stream if needed
414 case kRGBA_8888_SkColorType: 416 if (!this->rewindIfNeeded()) {
415 srcConfig = SkSwizzler::kRGBX; 417 return kCouldNotRewind;
416 break; 418 }
417 case kBGRA_8888_SkColorType: 419
418 srcConfig = SkSwizzler::kBGRX; 420 // Set the jump location for libjpeg errors
419 break; 421 if (setjmp(fDecoderMgr->getJmpBuf())) {
420 case kRGB_565_SkColorType: 422 SkCodecPrintf("setjmp: Error from libjpeg\n");
421 srcConfig = SkSwizzler::kRGB_565; 423 return kInvalidInput;
422 break; 424 }
423 default: 425
424 //would have exited before now if the colorType was supported by jpeg 426 // Check if we can decode to the requested destination and set the output co lor space
425 SkASSERT(false); 427 if (!this->setOutputColorSpace(dstInfo)) {
428 return kInvalidConversion;
429 }
430
431 // Perform the necessary scaling
432 if (!this->nativelyScaleToDimensions(dstInfo.width(), dstInfo.height())) {
433 // full native scaling to dstInfo dimensions not supported
434
435 if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstI nfo)) {
436 return kInvalidScale;
437 }
438 // create swizzler for sampling
439 Result result = this->initializeSwizzler(dstInfo, options);
440 if (kSuccess != result) {
441 SkCodecPrintf("failed to initialize the swizzler.\n");
442 return result;
443 }
444 fStorage.reset(get_row_bytes(fDecoderMgr->dinfo()));
445 fSrcRow = static_cast<uint8_t*>(fStorage.get());
446 } else {
447 fSrcRow = nullptr;
448 fSwizzler.reset(nullptr);
449 }
450
451 // Now, given valid output dimensions, we can start the decompress
452 if (!jpeg_start_decompress(fDecoderMgr->dinfo())) {
453 SkCodecPrintf("start decompress failed\n");
454 return kInvalidInput;
455 }
456
457 return kSuccess;
458 }
459
460 SkJpegCodec::~SkJpegCodec() {
461 // FIXME: This probably does not need to be called after a full decode
462 // FIXME: Is it safe to call when it doesn't need to be called?
463 if (setjmp(fDecoderMgr->getJmpBuf())) {
464 SkCodecPrintf("setjmp: Error in libjpeg finish_decompress\n");
465 return;
466 }
467
468 // We may not have decoded the entire image. Prevent libjpeg-turbo from fai ling on a
469 // partial decode.
470 fDecoderMgr->dinfo()->output_scanline = this->getInfo().height();
471 jpeg_finish_decompress(fDecoderMgr->dinfo());
472 }
473
474 SkCodec::Result SkJpegCodec::onGetScanlines(void* dst, int count, size_t rowByte s) {
475 // Set the jump location for libjpeg errors
476 if (setjmp(fDecoderMgr->getJmpBuf())) {
477 return fDecoderMgr->returnFailure("setjmp", kInvalidInput);
478 }
479 // Read rows one at a time
480 JSAMPLE* dstRow;
481 if (fSwizzler) {
482 // write data to storage row, then sample using swizzler
483 dstRow = fSrcRow;
484 } else {
485 // write data directly to dst
486 dstRow = (JSAMPLE*) dst;
487 }
488
489 for (int y = 0; y < count; y++) {
490 // Read row of the image
491 uint32_t rowsDecoded = jpeg_read_scanlines(fDecoderMgr->dinfo(), &dstRow , 1);
492 if (rowsDecoded != 1) {
493 SkSwizzler::Fill(dstRow, this->dstInfo(), rowBytes, count - y,
494 SK_ColorBLACK, nullptr, this->options().fZeroInitialized );
495 fDecoderMgr->dinfo()->output_scanline = this->dstInfo().height();
496 return kIncompleteInput;
426 } 497 }
427 498
428 fSwizzler.reset(SkSwizzler::CreateSwizzler(srcConfig, nullptr, info, opt ions.fZeroInitialized, 499 // Convert to RGBA if necessary
429 this->getInfo())); 500 if (JCS_CMYK == fDecoderMgr->dinfo()->out_color_space) {
430 if (!fSwizzler) { 501 convert_CMYK_to_RGBA(dstRow, fDecoderMgr->dinfo()->output_width);
431 // FIXME: CreateSwizzler could fail for another reason.
432 return SkCodec::kUnimplemented;
433 }
434 return SkCodec::kSuccess;
435 }
436
437 SkCodec::Result onStart(const SkImageInfo& dstInfo, const SkCodec::Options& options,
438 SkPMColor ctable[], int* ctableCount) override {
439
440 // Rewind the stream if needed
441 if (!fCodec->rewindIfNeeded()) {
442 return SkCodec::kCouldNotRewind;
443 } 502 }
444 503
445 // Set the jump location for libjpeg errors 504 if(fSwizzler) {
446 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) { 505 // use swizzler to sample row
447 SkCodecPrintf("setjmp: Error from libjpeg\n"); 506 fSwizzler->swizzle(dst, dstRow);
448 return SkCodec::kInvalidInput; 507 dst = SkTAddOffset<JSAMPLE>(dst, rowBytes);
508 } else {
509 dstRow = SkTAddOffset<JSAMPLE>(dstRow, rowBytes);
449 } 510 }
450
451 // Check if we can decode to the requested destination and set the outpu t color space
452 if (!fCodec->setOutputColorSpace(dstInfo)) {
453 return SkCodec::kInvalidConversion;
454 }
455
456 // Perform the necessary scaling
457 if (!fCodec->nativelyScaleToDimensions(dstInfo.width(), dstInfo.height() )) {
458 // full native scaling to dstInfo dimensions not supported
459
460 if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstInfo)) {
461 return SkCodec::kInvalidScale;
462 }
463 // create swizzler for sampling
464 SkCodec::Result result = this->initializeSwizzler(dstInfo, options);
465 if (SkCodec::kSuccess != result) {
466 SkCodecPrintf("failed to initialize the swizzler.\n");
467 return result;
468 }
469 fStorage.reset(get_row_bytes(fCodec->fDecoderMgr->dinfo()));
470 fSrcRow = static_cast<uint8_t*>(fStorage.get());
471 } else {
472 fSrcRow = nullptr;
473 fSwizzler.reset(nullptr);
474 }
475
476 // Now, given valid output dimensions, we can start the decompress
477 if (!jpeg_start_decompress(fCodec->fDecoderMgr->dinfo())) {
478 SkCodecPrintf("start decompress failed\n");
479 return SkCodec::kInvalidInput;
480 }
481
482 fOpts = options;
483
484 return SkCodec::kSuccess;
485 } 511 }
486 512 return kSuccess;
487 virtual ~SkJpegScanlineDecoder() { 513 }
488 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) {
489 SkCodecPrintf("setjmp: Error in libjpeg finish_decompress\n");
490 return;
491 }
492
493 // We may not have decoded the entire image. Prevent libjpeg-turbo from failing on a
494 // partial decode.
495 fCodec->fDecoderMgr->dinfo()->output_scanline = fCodec->getInfo().height ();
496 jpeg_finish_decompress(fCodec->fDecoderMgr->dinfo());
497 }
498
499 SkCodec::Result onGetScanlines(void* dst, int count, size_t rowBytes) overri de {
500 // Set the jump location for libjpeg errors
501 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) {
502 return fCodec->fDecoderMgr->returnFailure("setjmp", SkCodec::kInvali dInput);
503 }
504 // Read rows one at a time
505 JSAMPLE* dstRow;
506 if (fSwizzler) {
507 // write data to storage row, then sample using swizzler
508 dstRow = fSrcRow;
509 } else {
510 // write data directly to dst
511 dstRow = (JSAMPLE*) dst;
512 }
513
514 for (int y = 0; y < count; y++) {
515 // Read row of the image
516 uint32_t rowsDecoded = jpeg_read_scanlines(fCodec->fDecoderMgr->dinf o(), &dstRow, 1);
517 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();
521 return SkCodec::kIncompleteInput;
522 }
523
524 // Convert to RGBA if necessary
525 if (JCS_CMYK == fCodec->fDecoderMgr->dinfo()->out_color_space) {
526 convert_CMYK_to_RGBA(dstRow, fCodec->fDecoderMgr->dinfo()->outpu t_width);
527 }
528
529 if(fSwizzler) {
530 // use swizzler to sample row
531 fSwizzler->swizzle(dst, dstRow);
532 dst = SkTAddOffset<JSAMPLE>(dst, rowBytes);
533 } else {
534 dstRow = SkTAddOffset<JSAMPLE>(dstRow, rowBytes);
535 }
536 }
537 return SkCodec::kSuccess;
538 }
539 514
540 #ifndef TURBO_HAS_SKIP 515 #ifndef TURBO_HAS_SKIP
541 // TODO (msarett): Make this a member function and avoid reallocating the 516 // TODO (msarett): Make this a member function and avoid reallocating the
542 // memory buffer on each call to skip. 517 // memory buffer on each call to skip.
543 #define jpeg_skip_scanlines(dinfo, count) \ 518 #define jpeg_skip_scanlines(dinfo, count) \
544 SkAutoMalloc storage(get_row_bytes(dinfo)); \ 519 SkAutoMalloc storage(get_row_bytes(dinfo)); \
545 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get()); \ 520 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get()); \
546 for (int y = 0; y < count; y++) { \ 521 for (int y = 0; y < count; y++) { \
547 jpeg_read_scanlines(dinfo, &storagePtr, 1); \ 522 jpeg_read_scanlines(dinfo, &storagePtr, 1); \
548 } 523 }
549 #endif 524 #endif
550 525
551 SkCodec::Result onSkipScanlines(int count) override { 526 SkCodec::Result SkJpegCodec::onSkipScanlines(int count) {
552 // Set the jump location for libjpeg errors 527 // Set the jump location for libjpeg errors
553 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) { 528 if (setjmp(fDecoderMgr->getJmpBuf())) {
554 return fCodec->fDecoderMgr->returnFailure("setjmp", SkCodec::kInvali dInput); 529 return fDecoderMgr->returnFailure("setjmp", kInvalidInput);
555 }
556
557 jpeg_skip_scanlines(fCodec->fDecoderMgr->dinfo(), count);
558
559 return SkCodec::kSuccess;
560 } 530 }
561 531
562 SkEncodedFormat onGetEncodedFormat() const override { 532 jpeg_skip_scanlines(fDecoderMgr->dinfo(), count);
563 return kJPEG_SkEncodedFormat;
564 }
565 533
566 private: 534 return kSuccess;
567 SkAutoTDelete<SkJpegCodec> fCodec; 535 }
568 SkAutoMalloc fStorage; // Only used if sampling is needed
569 uint8_t* fSrcRow; // Only used if sampling is needed
570 SkCodec::Options fOpts;
571 SkAutoTDelete<SkSwizzler> fSwizzler;
572 536
573 typedef SkScanlineDecoder INHERITED;
574 };
575
576 SkScanlineDecoder* SkJpegCodec::NewSDFromStream(SkStream* stream) {
577 SkAutoTDelete<SkJpegCodec> codec(static_cast<SkJpegCodec*>(SkJpegCodec::NewF romStream(stream)));
578 if (!codec) {
579 return nullptr;
580 }
581
582 const SkImageInfo& srcInfo = codec->getInfo();
583
584 // Return the new scanline decoder
585 return new SkJpegScanlineDecoder(srcInfo, codec.detach());
586 }
OLDNEW
« no previous file with comments | « src/codec/SkJpegCodec.h ('k') | src/codec/SkScaledCodec.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698