1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2015 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "client_utils/android/BitmapRegionDecoder.h" 9cb93a386Sopenharmony_ci#include "client_utils/android/BitmapRegionDecoderPriv.h" 10cb93a386Sopenharmony_ci#include "include/codec/SkAndroidCodec.h" 11cb93a386Sopenharmony_ci#include "src/codec/SkCodecPriv.h" 12cb93a386Sopenharmony_ci 13cb93a386Sopenharmony_cinamespace android { 14cb93a386Sopenharmony_cinamespace skia { 15cb93a386Sopenharmony_ci 16cb93a386Sopenharmony_cistd::unique_ptr<BitmapRegionDecoder> BitmapRegionDecoder::Make(sk_sp<SkData> data) { 17cb93a386Sopenharmony_ci auto codec = SkAndroidCodec::MakeFromData(std::move(data)); 18cb93a386Sopenharmony_ci if (nullptr == codec) { 19cb93a386Sopenharmony_ci SkCodecPrintf("Error: Failed to create codec.\n"); 20cb93a386Sopenharmony_ci return nullptr; 21cb93a386Sopenharmony_ci } 22cb93a386Sopenharmony_ci 23cb93a386Sopenharmony_ci switch (codec->getEncodedFormat()) { 24cb93a386Sopenharmony_ci case SkEncodedImageFormat::kJPEG: 25cb93a386Sopenharmony_ci case SkEncodedImageFormat::kPNG: 26cb93a386Sopenharmony_ci case SkEncodedImageFormat::kWEBP: 27cb93a386Sopenharmony_ci case SkEncodedImageFormat::kHEIF: 28cb93a386Sopenharmony_ci break; 29cb93a386Sopenharmony_ci default: 30cb93a386Sopenharmony_ci return nullptr; 31cb93a386Sopenharmony_ci } 32cb93a386Sopenharmony_ci 33cb93a386Sopenharmony_ci return std::unique_ptr<BitmapRegionDecoder>(new BitmapRegionDecoder(std::move(codec))); 34cb93a386Sopenharmony_ci} 35cb93a386Sopenharmony_ci 36cb93a386Sopenharmony_ciBitmapRegionDecoder::BitmapRegionDecoder(std::unique_ptr<SkAndroidCodec> codec) 37cb93a386Sopenharmony_ci : fCodec(std::move(codec)) 38cb93a386Sopenharmony_ci{} 39cb93a386Sopenharmony_ci 40cb93a386Sopenharmony_ciint BitmapRegionDecoder::width() const { 41cb93a386Sopenharmony_ci return fCodec->getInfo().width(); 42cb93a386Sopenharmony_ci} 43cb93a386Sopenharmony_ci 44cb93a386Sopenharmony_ciint BitmapRegionDecoder::height() const { 45cb93a386Sopenharmony_ci return fCodec->getInfo().height(); 46cb93a386Sopenharmony_ci} 47cb93a386Sopenharmony_ci 48cb93a386Sopenharmony_cibool BitmapRegionDecoder::decodeRegion(SkBitmap* bitmap, BRDAllocator* allocator, 49cb93a386Sopenharmony_ci const SkIRect& desiredSubset, int sampleSize, SkColorType dstColorType, 50cb93a386Sopenharmony_ci bool requireUnpremul, sk_sp<SkColorSpace> dstColorSpace) { 51cb93a386Sopenharmony_ci 52cb93a386Sopenharmony_ci // Fix the input sampleSize if necessary. 53cb93a386Sopenharmony_ci if (sampleSize < 1) { 54cb93a386Sopenharmony_ci sampleSize = 1; 55cb93a386Sopenharmony_ci } 56cb93a386Sopenharmony_ci 57cb93a386Sopenharmony_ci // The size of the output bitmap is determined by the size of the 58cb93a386Sopenharmony_ci // requested subset, not by the size of the intersection of the subset 59cb93a386Sopenharmony_ci // and the image dimensions. 60cb93a386Sopenharmony_ci // If inputX is negative, we will need to place decoded pixels into the 61cb93a386Sopenharmony_ci // output bitmap starting at a left offset. Call this outX. 62cb93a386Sopenharmony_ci // If outX is non-zero, subsetX must be zero. 63cb93a386Sopenharmony_ci // If inputY is negative, we will need to place decoded pixels into the 64cb93a386Sopenharmony_ci // output bitmap starting at a top offset. Call this outY. 65cb93a386Sopenharmony_ci // If outY is non-zero, subsetY must be zero. 66cb93a386Sopenharmony_ci int outX; 67cb93a386Sopenharmony_ci int outY; 68cb93a386Sopenharmony_ci SkIRect subset = desiredSubset; 69cb93a386Sopenharmony_ci SubsetType type = adjust_subset_rect(fCodec->getInfo().dimensions(), &subset, &outX, &outY); 70cb93a386Sopenharmony_ci if (SubsetType::kOutside_SubsetType == type) { 71cb93a386Sopenharmony_ci return false; 72cb93a386Sopenharmony_ci } 73cb93a386Sopenharmony_ci 74cb93a386Sopenharmony_ci // Ask the codec for a scaled subset 75cb93a386Sopenharmony_ci if (!fCodec->getSupportedSubset(&subset)) { 76cb93a386Sopenharmony_ci SkCodecPrintf("Error: Could not get subset.\n"); 77cb93a386Sopenharmony_ci return false; 78cb93a386Sopenharmony_ci } 79cb93a386Sopenharmony_ci SkISize scaledSize = fCodec->getSampledSubsetDimensions(sampleSize, subset); 80cb93a386Sopenharmony_ci 81cb93a386Sopenharmony_ci // Create the image info for the decode 82cb93a386Sopenharmony_ci SkAlphaType dstAlphaType = fCodec->computeOutputAlphaType(requireUnpremul); 83cb93a386Sopenharmony_ci SkImageInfo decodeInfo = 84cb93a386Sopenharmony_ci SkImageInfo::Make(scaledSize, dstColorType, dstAlphaType, dstColorSpace); 85cb93a386Sopenharmony_ci 86cb93a386Sopenharmony_ci // Initialize the destination bitmap 87cb93a386Sopenharmony_ci int scaledOutX = 0; 88cb93a386Sopenharmony_ci int scaledOutY = 0; 89cb93a386Sopenharmony_ci int scaledOutWidth = scaledSize.width(); 90cb93a386Sopenharmony_ci int scaledOutHeight = scaledSize.height(); 91cb93a386Sopenharmony_ci if (SubsetType::kPartiallyInside_SubsetType == type) { 92cb93a386Sopenharmony_ci scaledOutX = outX / sampleSize; 93cb93a386Sopenharmony_ci scaledOutY = outY / sampleSize; 94cb93a386Sopenharmony_ci // We need to be safe here because getSupportedSubset() may have modified the subset. 95cb93a386Sopenharmony_ci const int extraX = std::max(0, desiredSubset.width() - outX - subset.width()); 96cb93a386Sopenharmony_ci const int extraY = std::max(0, desiredSubset.height() - outY - subset.height()); 97cb93a386Sopenharmony_ci const int scaledExtraX = extraX / sampleSize; 98cb93a386Sopenharmony_ci const int scaledExtraY = extraY / sampleSize; 99cb93a386Sopenharmony_ci scaledOutWidth += scaledOutX + scaledExtraX; 100cb93a386Sopenharmony_ci scaledOutHeight += scaledOutY + scaledExtraY; 101cb93a386Sopenharmony_ci } 102cb93a386Sopenharmony_ci SkImageInfo outInfo = decodeInfo.makeWH(scaledOutWidth, scaledOutHeight); 103cb93a386Sopenharmony_ci if (kGray_8_SkColorType == dstColorType) { 104cb93a386Sopenharmony_ci // The legacy implementations of BitmapFactory and BitmapRegionDecoder 105cb93a386Sopenharmony_ci // used kAlpha8 for grayscale images (before kGray8 existed). While 106cb93a386Sopenharmony_ci // the codec recognizes kGray8, we need to decode into a kAlpha8 107cb93a386Sopenharmony_ci // bitmap in order to avoid a behavior change. 108cb93a386Sopenharmony_ci outInfo = outInfo.makeColorType(kAlpha_8_SkColorType).makeAlphaType(kPremul_SkAlphaType); 109cb93a386Sopenharmony_ci } 110cb93a386Sopenharmony_ci bitmap->setInfo(outInfo); 111cb93a386Sopenharmony_ci if (!bitmap->tryAllocPixels(allocator)) { 112cb93a386Sopenharmony_ci SkCodecPrintf("Error: Could not allocate pixels.\n"); 113cb93a386Sopenharmony_ci return false; 114cb93a386Sopenharmony_ci } 115cb93a386Sopenharmony_ci 116cb93a386Sopenharmony_ci // Zero the bitmap if the region is not completely within the image. 117cb93a386Sopenharmony_ci // TODO (msarett): Can we make this faster by implementing it to only 118cb93a386Sopenharmony_ci // zero parts of the image that we won't overwrite with 119cb93a386Sopenharmony_ci // pixels? 120cb93a386Sopenharmony_ci SkCodec::ZeroInitialized zeroInit = allocator ? allocator->zeroInit() : 121cb93a386Sopenharmony_ci SkCodec::kNo_ZeroInitialized; 122cb93a386Sopenharmony_ci if (SubsetType::kPartiallyInside_SubsetType == type && 123cb93a386Sopenharmony_ci SkCodec::kNo_ZeroInitialized == zeroInit) { 124cb93a386Sopenharmony_ci void* pixels = bitmap->getPixels(); 125cb93a386Sopenharmony_ci size_t bytes = outInfo.computeByteSize(bitmap->rowBytes()); 126cb93a386Sopenharmony_ci memset(pixels, 0, bytes); 127cb93a386Sopenharmony_ci } 128cb93a386Sopenharmony_ci 129cb93a386Sopenharmony_ci // Decode into the destination bitmap 130cb93a386Sopenharmony_ci SkAndroidCodec::AndroidOptions options; 131cb93a386Sopenharmony_ci options.fSampleSize = sampleSize; 132cb93a386Sopenharmony_ci options.fSubset = ⊂ 133cb93a386Sopenharmony_ci options.fZeroInitialized = zeroInit; 134cb93a386Sopenharmony_ci void* dst = bitmap->getAddr(scaledOutX, scaledOutY); 135cb93a386Sopenharmony_ci 136cb93a386Sopenharmony_ci SkCodec::Result result = fCodec->getAndroidPixels(decodeInfo, dst, bitmap->rowBytes(), 137cb93a386Sopenharmony_ci &options); 138cb93a386Sopenharmony_ci switch (result) { 139cb93a386Sopenharmony_ci case SkCodec::kSuccess: 140cb93a386Sopenharmony_ci case SkCodec::kIncompleteInput: 141cb93a386Sopenharmony_ci case SkCodec::kErrorInInput: 142cb93a386Sopenharmony_ci return true; 143cb93a386Sopenharmony_ci default: 144cb93a386Sopenharmony_ci SkCodecPrintf("Error: Could not get pixels with message \"%s\".\n", 145cb93a386Sopenharmony_ci SkCodec::ResultToString(result)); 146cb93a386Sopenharmony_ci return false; 147cb93a386Sopenharmony_ci } 148cb93a386Sopenharmony_ci} 149cb93a386Sopenharmony_ci 150cb93a386Sopenharmony_ci} // namespace skia 151cb93a386Sopenharmony_ci} // namespace android 152