SkBitmapRegionDecoder clean-up

Use SkCodecPrintf instead of SkDebugf.

Check if the conversion is possible rather than starting many decodes
that will certainly fail.

Small refactor to code that deals with subsets that fall outside
of the image.

BUG=skia:

Review URL: https://codereview.chromium.org/1395383002
This commit is contained in:
msarett 2015-10-12 10:24:38 -07:00 committed by Commit bot
parent 34422610ac
commit 04965c6f11
7 changed files with 56 additions and 28 deletions

View File

@ -114,6 +114,10 @@ Error BRDSrc::draw(SkCanvas* canvas) const {
return Error::Nonfatal(SkStringPrintf("Could not create brd for %s.", fPath.c_str()));
}
if (!brd->conversionSupported(colorType)) {
return Error::Nonfatal("Cannot convert to color type.\n");
}
const uint32_t width = brd->width();
const uint32_t height = brd->height();
// Visually inspecting very small output images is not necessary.

View File

@ -7,6 +7,8 @@
#include "SkBitmapRegionCanvas.h"
#include "SkCanvas.h"
#include "SkCodecPriv.h"
#include "SkCodecTools.h"
SkBitmapRegionCanvas::SkBitmapRegionCanvas(SkCodec* decoder)
: INHERITED(decoder->getInfo().width(), decoder->getInfo().height())
@ -15,8 +17,11 @@ SkBitmapRegionCanvas::SkBitmapRegionCanvas(SkCodec* decoder)
/*
* Chooses the correct image subset offsets and dimensions for the partial decode.
*
* @return true if the subset is completely contained within the image
* false otherwise
*/
static inline void set_subset_region(int inputOffset, int inputDimension,
static bool set_subset_region(int inputOffset, int inputDimension,
int imageOriginalDimension, int* imageSubsetOffset, int* outOffset,
int* imageSubsetDimension) {
@ -30,17 +35,8 @@ static inline void set_subset_region(int inputOffset, int inputDimension,
// Use outOffset to make sure we don't decode pixels past the edge of the region.
*imageSubsetDimension = SkTMin(imageOriginalDimension - *imageSubsetOffset,
inputDimension - *outOffset);
}
/*
* Returns a scaled dimension based on the original dimension and the sample size.
* TODO: Share this implementation with SkScaledCodec.
*/
static int get_scaled_dimension(int srcDimension, int sampleSize) {
if (sampleSize > srcDimension) {
return 1;
}
return srcDimension / sampleSize;
return (*outOffset == 0) && (*imageSubsetDimension == inputDimension);
}
/*
@ -56,7 +52,7 @@ SkBitmap* SkBitmapRegionCanvas::decodeRegion(int inputX, int inputY,
SkColorType dstColorType) {
// Reject color types not supported by this method
if (kIndex_8_SkColorType == dstColorType || kGray_8_SkColorType == dstColorType) {
SkDebugf("Error: Color type not supported.\n");
SkCodecPrintf("Error: Color type not supported.\n");
return nullptr;
}
@ -79,7 +75,8 @@ SkBitmap* SkBitmapRegionCanvas::decodeRegion(int inputX, int inputY,
// bitmap. If the region is not fully contained within the image, this
// will not be the same as inputWidth.
int imageSubsetWidth;
set_subset_region(inputX, inputWidth, this->width(), &imageSubsetX, &outX, &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.
@ -96,11 +93,11 @@ SkBitmap* SkBitmapRegionCanvas::decodeRegion(int inputX, int inputY,
// bitmap. If the region is not fully contained within the image, this
// will not be the same as inputHeight.
int imageSubsetHeight;
set_subset_region(inputY, inputHeight, this->height(), &imageSubsetY, &outY,
&imageSubsetHeight);
imageContainsEntireSubset &= set_subset_region(inputY, inputHeight, this->height(),
&imageSubsetY, &outY, &imageSubsetHeight);
if (imageSubsetWidth <= 0 || imageSubsetHeight <= 0) {
SkDebugf("Error: Region must intersect part of the image.\n");
SkCodecPrintf("Error: Region must intersect part of the image.\n");
return nullptr;
}
@ -115,7 +112,7 @@ SkBitmap* SkBitmapRegionCanvas::decodeRegion(int inputX, int inputY,
// Start the scanline decoder
SkCodec::Result r = fDecoder->startScanlineDecode(decodeInfo);
if (SkCodec::kSuccess != r) {
SkDebugf("Error: Could not start scanline decoder.\n");
SkCodecPrintf("Error: Could not start scanline decoder.\n");
return nullptr;
}
@ -123,13 +120,13 @@ SkBitmap* SkBitmapRegionCanvas::decodeRegion(int inputX, int inputY,
SkBitmap tmp;
SkImageInfo tmpInfo = decodeInfo.makeWH(this->width(), imageSubsetHeight);
if (!tmp.tryAllocPixels(tmpInfo)) {
SkDebugf("Error: Could not allocate pixels.\n");
SkCodecPrintf("Error: Could not allocate pixels.\n");
return nullptr;
}
// Skip the unneeded rows
if (!fDecoder->skipScanlines(imageSubsetY)) {
SkDebugf("Error: Failed to skip scanlines.\n");
SkCodecPrintf("Error: Failed to skip scanlines.\n");
return nullptr;
}
@ -144,7 +141,7 @@ SkBitmap* SkBitmapRegionCanvas::decodeRegion(int inputX, int inputY,
SkAutoTDelete<SkBitmap> bitmap(new SkBitmap());
SkImageInfo dstInfo = decodeInfo.makeWH(outWidth, outHeight);
if (!bitmap->tryAllocPixels(dstInfo)) {
SkDebugf("Error: Could not allocate pixels.\n");
SkCodecPrintf("Error: Could not allocate pixels.\n");
return nullptr;
}
@ -155,9 +152,7 @@ SkBitmap* SkBitmapRegionCanvas::decodeRegion(int inputX, int inputY,
// 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 (0 != outX || 0 != outY ||
inputX + inputWidth > this->width() ||
inputY + inputHeight > this->height()) {
if (imageContainsEntireSubset) {
bitmap->eraseColor(0);
}
@ -177,3 +172,15 @@ SkBitmap* SkBitmapRegionCanvas::decodeRegion(int inputX, int inputY,
return bitmap.detach();
}
bool SkBitmapRegionCanvas::conversionSupported(SkColorType colorType) {
// SkCanvas does not draw to these color types.
if (kIndex_8_SkColorType == colorType || kGray_8_SkColorType == colorType) {
return false;
}
// FIXME: Call virtual function when it lands.
SkImageInfo info = SkImageInfo::Make(0, 0, colorType, fDecoder->getInfo().alphaType(),
fDecoder->getInfo().profileType());
return conversion_possible(info, fDecoder->getInfo());
}

View File

@ -34,6 +34,8 @@ public:
SkBitmap* decodeRegion(int start_x, int start_y, int width, int height,
int sampleSize, SkColorType prefColorType) override;
bool conversionSupported(SkColorType colorType) override;
private:
SkAutoTDelete<SkCodec> fDecoder;

View File

@ -9,6 +9,7 @@
#include "SkBitmapRegionDecoderInterface.h"
#include "SkBitmapRegionSampler.h"
#include "SkCodec.h"
#include "SkCodecPriv.h"
#include "SkImageDecoder.h"
SkBitmapRegionDecoderInterface* SkBitmapRegionDecoderInterface::CreateBitmapRegionDecoder(
@ -19,11 +20,11 @@ SkBitmapRegionDecoderInterface* SkBitmapRegionDecoderInterface::CreateBitmapRegi
SkImageDecoder* decoder = SkImageDecoder::Factory(stream);
int width, height;
if (nullptr == decoder) {
SkDebugf("Error: Could not create image decoder.\n");
SkCodecPrintf("Error: Could not create image decoder.\n");
return nullptr;
}
if (!decoder->buildTileIndex(streamDeleter.detach(), &width, &height)) {
SkDebugf("Error: Could not build tile index.\n");
SkCodecPrintf("Error: Could not build tile index.\n");
delete decoder;
return nullptr;
}
@ -32,7 +33,7 @@ SkBitmapRegionDecoderInterface* SkBitmapRegionDecoderInterface::CreateBitmapRegi
case kCanvas_Strategy: {
SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(streamDeleter.detach()));
if (nullptr == codec) {
SkDebugf("Error: Failed to create decoder.\n");
SkCodecPrintf("Error: Failed to create decoder.\n");
return nullptr;
}
switch (codec->getScanlineOrder()) {
@ -40,7 +41,7 @@ SkBitmapRegionDecoderInterface* SkBitmapRegionDecoderInterface::CreateBitmapRegi
case SkCodec::kNone_SkScanlineOrder:
break;
default:
SkDebugf("Error: Scanline ordering not supported.\n");
SkCodecPrintf("Error: Scanline ordering not supported.\n");
return nullptr;
}
return new SkBitmapRegionCanvas(codec.detach());

View File

@ -56,6 +56,11 @@ public:
virtual SkBitmap* decodeRegion(int start_x, int start_y, int width,
int height, int sampleSize,
SkColorType colorType) = 0;
/*
* @param Requested destination color type
* @return true if we support the requested color type and false otherwise
*/
virtual bool conversionSupported(SkColorType colorType) = 0;
int width() const { return fWidth; }
int height() const { return fHeight; }

View File

@ -6,6 +6,7 @@
*/
#include "SkBitmapRegionSampler.h"
#include "SkCodecPriv.h"
SkBitmapRegionSampler::SkBitmapRegionSampler(SkImageDecoder* decoder, int width,
int height)
@ -43,7 +44,7 @@ SkBitmap* SkBitmapRegionSampler::decodeRegion(int start_x, int start_y,
SkAutoTDelete<SkBitmap> bitmap(new SkBitmap());
if (!fDecoder->decodeSubset(bitmap.get(), region, prefColorType)) {
SkDebugf("Error: decodeRegion failed.\n");
SkCodecPrintf("Error: decodeRegion failed.\n");
return nullptr;
}
return bitmap.detach();

View File

@ -32,6 +32,14 @@ public:
SkBitmap* decodeRegion(int start_x, int start_y, int width, int height,
int sampleSize, SkColorType prefColorType) override;
bool conversionSupported(SkColorType colorType) override {
// SkBitmapRegionSampler does not allow the client to check if the conversion
// is supported. We will return true as a default. If the conversion is in
// fact not supported, decodeRegion() will ignore the prefColorType and choose
// its own color type. We catch this and fail non-fatally in our test code.
return true;
}
private:
SkAutoTDelete<SkImageDecoder> fDecoder;