| Index: tools/SkBitmapRegionCodec.cpp
|
| diff --git a/tools/SkBitmapRegionCodec.cpp b/tools/SkBitmapRegionCodec.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..5dbb947d182c005657b9e9508af12d6084788f98
|
| --- /dev/null
|
| +++ b/tools/SkBitmapRegionCodec.cpp
|
| @@ -0,0 +1,160 @@
|
| +/*
|
| + * 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 "SkBitmapRegionCodec.h"
|
| +#include "SkBitmapRegionDecoderPriv.h"
|
| +#include "SkCanvas.h"
|
| +#include "SkCodec.h"
|
| +#include "SkCodecPriv.h"
|
| +
|
| +SkBitmapRegionCodec::SkBitmapRegionCodec(SkCodec* codec)
|
| + : INHERITED(codec->getInfo().width(), codec->getInfo().height())
|
| + , fCodec(codec)
|
| +{}
|
| +
|
| +/*
|
| + * Three differences from the Android version:
|
| + * Returns a skia bitmap instead of an Android bitmap.
|
| + * Android version attempts to reuse a recycled bitmap.
|
| + * Removed the options object and used parameters for color type and sample size.
|
| + */
|
| +SkBitmap* SkBitmapRegionCodec::decodeRegion(int inputX, int inputY, int inputWidth, int inputHeight,
|
| + int sampleSize, SkColorType dstColorType) {
|
| +
|
| + // Fix the input sampleSize if necessary.
|
| + if (sampleSize < 1) {
|
| + sampleSize = 1;
|
| + }
|
| +
|
| + // The client may not necessarily request a region that is fully within
|
| + // the image. We may need to do some calculation to determine what part
|
| + // of the image to decode.
|
| +
|
| + // The left offset of the portion of the image we want, where zero
|
| + // indicates the left edge of the image.
|
| + int imageSubsetX;
|
| +
|
| + // The size of the output bitmap is determined by the size of the
|
| + // requested region, not by the size of the intersection of the region
|
| + // and the image dimensions. If inputX is negative, we will need to
|
| + // place decoded pixels into the output bitmap starting at a left offset.
|
| + // If this is non-zero, imageSubsetX must be zero.
|
| + int outX;
|
| +
|
| + // The width of the portion of the image that we will write to the output
|
| + // bitmap. If the region is not fully contained within the image, this
|
| + // will not be the same as inputWidth.
|
| + int imageSubsetWidth;
|
| + bool imageContainsEntireSubset = set_subset_region(inputX, inputWidth, this->width(),
|
| + &imageSubsetX, &outX, &imageSubsetWidth);
|
| +
|
| + // The top offset of the portion of the image we want, where zero
|
| + // indicates the top edge of the image.
|
| + int imageSubsetY;
|
| +
|
| + // The size of the output bitmap is determined by the size of the
|
| + // requested region, not by the size of the intersection of the region
|
| + // and the image dimensions. If inputY is negative, we will need to
|
| + // place decoded pixels into the output bitmap starting at a top offset.
|
| + // If this is non-zero, imageSubsetY must be zero.
|
| + int outY;
|
| +
|
| + // The height of the portion of the image that we will write to the output
|
| + // bitmap. If the region is not fully contained within the image, this
|
| + // will not be the same as inputHeight.
|
| + int imageSubsetHeight;
|
| + imageContainsEntireSubset &= set_subset_region(inputY, inputHeight, this->height(),
|
| + &imageSubsetY, &outY, &imageSubsetHeight);
|
| +
|
| + if (imageSubsetWidth <= 0 || imageSubsetHeight <= 0) {
|
| + SkCodecPrintf("Error: Region must intersect part of the image.\n");
|
| + return nullptr;
|
| + }
|
| +
|
| + // Ask the codec for a scaled subset
|
| + SkIRect subset = SkIRect::MakeXYWH(imageSubsetX, imageSubsetY, imageSubsetWidth,
|
| + imageSubsetHeight);
|
| + SkCodec::Options options;
|
| + options.fSubset = ⊂
|
| + if (!fCodec->getScaledSubsetDimensions(get_scale(sampleSize), &options)) {
|
| + SkCodecPrintf("Error: Could not scale.\n");
|
| + return nullptr;
|
| + }
|
| +
|
| + // Create the image info the decode
|
| + SkAlphaType dstAlphaType = fCodec->getInfo().alphaType();
|
| + if (kUnpremul_SkAlphaType == dstAlphaType) {
|
| + dstAlphaType = kPremul_SkAlphaType;
|
| + }
|
| + SkImageInfo decodeInfo = SkImageInfo::Make(options.fScaledSubset.width(),
|
| + options.fScaledSubset.height(), dstColorType, dstAlphaType);
|
| +
|
| + // Construct a color table for the decode if necessary
|
| + SkAutoTUnref<SkColorTable> colorTable(nullptr);
|
| + SkPMColor* colorPtr = nullptr;
|
| + int* colorCountPtr = nullptr;
|
| + int maxColors = 256;
|
| + SkPMColor colors[maxColors];
|
| + if (kIndex_8_SkColorType == dstColorType) {
|
| + // TODO (msarett): This performs a copy that is completely unnecessary.
|
| + // And then below we need to use a const cast....
|
| + // Finish this comment.
|
| + colorTable.reset(new SkColorTable(colors, maxColors));
|
| + colorPtr = const_cast<SkPMColor*>(colorTable->readColors());
|
| + colorCountPtr = &maxColors;
|
| + }
|
| +
|
| + // Initialize the destination bitmap
|
| + SkAutoTDelete<SkBitmap> bitmap(new SkBitmap());
|
| + int scaledOutX = 0;
|
| + int scaledOutY = 0;
|
| + int scaledOutWidth = options.fScaledSubset.width();
|
| + int scaledOutHeight = options.fScaledSubset.height();
|
| + if (!imageContainsEntireSubset) {
|
| + scaledOutX = outX / sampleSize;
|
| + scaledOutY = outY / sampleSize;
|
| + int scaledExtraX = (inputWidth - outX - imageSubsetWidth) / sampleSize;
|
| + int scaledExtraY = (inputHeight - outY - imageSubsetHeight) / sampleSize;
|
| + scaledOutWidth += scaledOutX + scaledExtraX;
|
| + scaledOutHeight += scaledOutY + scaledExtraY;
|
| + }
|
| + SkImageInfo outInfo = decodeInfo.makeWH(scaledOutWidth, scaledOutHeight);
|
| + if (!bitmap->tryAllocPixels(outInfo, nullptr, colorTable.get())) {
|
| + SkCodecPrintf("Error: Could not allocate pixels.\n");
|
| + return nullptr;
|
| + }
|
| +
|
| + // Zero the bitmap if the region is not completely within the image.
|
| + // TODO (msarett): Can we make this faster by implementing it to only
|
| + // zero parts of the image that we won't overwrite with
|
| + // pixels?
|
| + // TODO (msarett): This could be skipped if memory is zero initialized.
|
| + // This would matter if this code is moved to Android and
|
| + // uses Android bitmaps.
|
| + if (!imageContainsEntireSubset && SkCodec::kNo_ZeroInitialized == options.fZeroInitialized) {
|
| + bitmap->eraseColor(0);
|
| + }
|
| +
|
| + // Decode into the destination bitmap
|
| + void* dst = bitmap->getAddr(scaledOutX, scaledOutY);
|
| + size_t rowBytes = bitmap->rowBytes();
|
| + SkCodec::Result result = fCodec->getPixels(decodeInfo, dst, rowBytes, &options, colorPtr,
|
| + colorCountPtr);
|
| + if (SkCodec::kSuccess != result && SkCodec::kIncompleteInput != result) {
|
| + SkCodecPrintf("Error: Could not get pixels.\n");
|
| + return nullptr;
|
| + }
|
| +
|
| + return bitmap.detach();
|
| +}
|
| +
|
| +bool SkBitmapRegionCodec::conversionSupported(SkColorType colorType) {
|
| + // FIXME: Call virtual function when it lands.
|
| + SkImageInfo info = SkImageInfo::Make(0, 0, colorType, fCodec->getInfo().alphaType(),
|
| + fCodec->getInfo().profileType());
|
| + return conversion_possible(info, fCodec->getInfo());
|
| +}
|
|
|