/* * Copyright 2015 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "SkCodec.h" #include "SkData.h" #include "SkCodec_libbmp.h" #include "SkCodec_libgif.h" #include "SkCodec_libico.h" #include "SkCodec_libpng.h" #include "SkCodec_wbmp.h" #include "SkCodecPriv.h" #ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK #include "SkJpegCodec.h" #endif #include "SkStream.h" #include "SkWebpCodec.h" struct DecoderProc { bool (*IsFormat)(SkStream*); SkCodec* (*NewFromStream)(SkStream*); }; static const DecoderProc gDecoderProcs[] = { { SkPngCodec::IsPng, SkPngCodec::NewFromStream }, #ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK { SkJpegCodec::IsJpeg, SkJpegCodec::NewFromStream }, #endif { SkWebpCodec::IsWebp, SkWebpCodec::NewFromStream }, { SkGifCodec::IsGif, SkGifCodec::NewFromStream }, { SkIcoCodec::IsIco, SkIcoCodec::NewFromStream }, { SkBmpCodec::IsBmp, SkBmpCodec::NewFromStream }, { SkWbmpCodec::IsWbmp, SkWbmpCodec::NewFromStream } }; SkCodec* SkCodec::NewFromStream(SkStream* stream) { if (!stream) { return NULL; } SkAutoTDelete streamDeleter(stream); SkAutoTDelete codec(NULL); for (uint32_t i = 0; i < SK_ARRAY_COUNT(gDecoderProcs); i++) { DecoderProc proc = gDecoderProcs[i]; const bool correctFormat = proc.IsFormat(stream); if (!stream->rewind()) { return NULL; } if (correctFormat) { codec.reset(proc.NewFromStream(streamDeleter.detach())); break; } } // Set the max size at 128 megapixels (512 MB for kN32). // This is about 4x smaller than a test image that takes a few minutes for // dm to decode and draw. const int32_t maxSize = 1 << 27; if (codec && codec->getInfo().width() * codec->getInfo().height() > maxSize) { SkCodecPrintf("Error: Image size too large, cannot decode.\n"); return NULL; } else { return codec.detach(); } } SkCodec* SkCodec::NewFromData(SkData* data) { if (!data) { return NULL; } return NewFromStream(SkNEW_ARGS(SkMemoryStream, (data))); } SkCodec::SkCodec(const SkImageInfo& info, SkStream* stream) : fInfo(info) , fStream(stream) , fNeedsRewind(false) {} SkCodec::~SkCodec() {} SkCodec::RewindState SkCodec::rewindIfNeeded() { // Store the value of fNeedsRewind so we can update it. Next read will // require a rewind. const bool needsRewind = fNeedsRewind; fNeedsRewind = true; if (!needsRewind) { return kNoRewindNecessary_RewindState; } return fStream->rewind() ? kRewound_RewindState : kCouldNotRewind_RewindState; } SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, const Options* options, SkPMColor ctable[], int* ctableCount) { if (kUnknown_SkColorType == info.colorType()) { return kInvalidConversion; } if (NULL == pixels) { return kInvalidParameters; } if (rowBytes < info.minRowBytes()) { return kInvalidParameters; } if (kIndex_8_SkColorType == info.colorType()) { if (NULL == ctable || NULL == ctableCount) { return kInvalidParameters; } } else { if (ctableCount) { *ctableCount = 0; } ctableCount = NULL; ctable = NULL; } // Default options. Options optsStorage; if (NULL == options) { options = &optsStorage; } const Result result = this->onGetPixels(info, pixels, rowBytes, *options, ctable, ctableCount); if ((kIncompleteInput == result || kSuccess == result) && ctableCount) { SkASSERT(*ctableCount >= 0 && *ctableCount <= 256); } return result; } SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes) { SkASSERT(kIndex_8_SkColorType != info.colorType()); if (kIndex_8_SkColorType == info.colorType()) { return kInvalidConversion; } return this->getPixels(info, pixels, rowBytes, NULL, NULL, NULL); } SkScanlineDecoder* SkCodec::getScanlineDecoder(const SkImageInfo& dstInfo, const Options* options, SkPMColor ctable[], int* ctableCount) { // Set options. Options optsStorage; if (NULL == options) { options = &optsStorage; } return this->onGetScanlineDecoder(dstInfo, *options, ctable, ctableCount); } SkScanlineDecoder* SkCodec::getScanlineDecoder(const SkImageInfo& dstInfo) { SkASSERT(kIndex_8_SkColorType != dstInfo.colorType()); if (kIndex_8_SkColorType == dstInfo.colorType()) { return NULL; } return this->getScanlineDecoder(dstInfo, NULL, NULL, NULL); }