Chromium Code Reviews| Index: tools/SkBitmapRegionCanvas.cpp |
| diff --git a/tools/SkBitmapRegionCanvas.cpp b/tools/SkBitmapRegionCanvas.cpp |
| index f9c9573c445c2c3e7a86704cbf09fd11c7fa611b..3b1a039a73e0666d41a89f1edbe71ff7e6472b16 100644 |
| --- a/tools/SkBitmapRegionCanvas.cpp |
| +++ b/tools/SkBitmapRegionCanvas.cpp |
| @@ -15,125 +15,101 @@ SkBitmapRegionCanvas::SkBitmapRegionCanvas(SkCodec* decoder) |
| , fDecoder(decoder) |
| {} |
| -/* |
| - * 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* SkBitmapRegionCanvas::decodeRegion(int inputX, int inputY, |
| - int inputWidth, int inputHeight, |
| - int sampleSize, |
| - SkColorType dstColorType) { |
| +bool SkBitmapRegionCanvas::prepareRegion(const SkIRect& desiredSubset, |
| + int sampleSize, |
| + SkColorType dstColorType, |
| + bool requireUnpremul, |
| + SkImageInfo* outInfo) { |
| // Reject color types not supported by this method |
| if (kIndex_8_SkColorType == dstColorType || kGray_8_SkColorType == dstColorType) { |
|
scroggo
2015/10/27 15:00:50
Should we also check for requireUnpremul here? I s
|
| SkCodecPrintf("Error: Color type not supported.\n"); |
| - return nullptr; |
| + return false; |
| } |
| // Fix the input sampleSize if necessary. |
| if (sampleSize < 1) { |
| sampleSize = 1; |
| } |
| + fSampleSize = sampleSize; |
| - // The size of the output bitmap is determined by the size of the |
| - // requested subset, not by the size of the intersection of the subset |
| - // and the image dimensions. |
| - // If inputX is negative, we will need to place decoded pixels into the |
| - // output bitmap starting at a left offset. Call this outX. |
| - // If outX is non-zero, subsetX must be zero. |
| - // If inputY is negative, we will need to place decoded pixels into the |
| - // output bitmap starting at a top offset. Call this outY. |
| - // If outY is non-zero, subsetY must be zero. |
| - int outX; |
| - int outY; |
| - SkIRect subset = SkIRect::MakeXYWH(inputX, inputY, inputWidth, inputHeight); |
| - SubsetType type = adjust_subset_rect(fDecoder->getInfo().dimensions(), &subset, &outX, &outY); |
| - if (SubsetType::kOutside_SubsetType == type) { |
| - return nullptr; |
| + fSubset = desiredSubset; |
| + fSubsetType = adjust_subset_rect(fDecoder->getInfo().dimensions(), &fSubset, &fOutX, &fOutY); |
| + if (SubsetType::kOutside_SubsetType == fSubsetType) { |
| + return false; |
| } |
| - // Create the image info for the decode |
| + // Create the image info. |
| SkAlphaType dstAlphaType = fDecoder->getInfo().alphaType(); |
| - if (kUnpremul_SkAlphaType == dstAlphaType) { |
| - dstAlphaType = kPremul_SkAlphaType; |
| + if (kOpaque_SkAlphaType != dstAlphaType) { |
| + dstAlphaType = requireUnpremul ? kUnpremul_SkAlphaType : kPremul_SkAlphaType; |
| + } |
| + fOutInfo = SkImageInfo::Make(get_scaled_dimension(desiredSubset.width(), sampleSize), |
| + get_scaled_dimension(desiredSubset.height(), sampleSize), dstColorType, dstAlphaType); |
| + *outInfo = fOutInfo; |
| + |
| + // The decoder does not know anything about the scale that we are applying. |
| + fDecodeInfo = fOutInfo.makeWH(this->width(), this->height()); |
| + |
| + // Check that we can convert to the requested color and alpha types. |
| + return conversion_possible(fOutInfo, fDecoder->getInfo()); |
| +} |
| + |
| +bool SkBitmapRegionCanvas::decodeRegion(SkBitmap& bitmap) { |
| + if (fOutInfo.isEmpty()) { |
| + SkCodecPrintf("Error: Call prepareRegion() first."); |
| + return false; |
| + } |
| + |
| + if (bitmap.width() < fOutInfo.width() || bitmap.height() < fOutInfo.height() || |
| + bitmap.colorType() != fOutInfo.colorType()) { |
| + SkCodecPrintf("Error: Invalid size or color type for input bitmap."); |
| + return false; |
| } |
| - SkImageInfo decodeInfo = SkImageInfo::Make(this->width(), this->height(), |
| - dstColorType, dstAlphaType); |
| + bitmap.setAlphaType(fOutInfo.alphaType()); |
| // Start the scanline decoder |
| - SkCodec::Result r = fDecoder->startScanlineDecode(decodeInfo); |
| + SkCodec::Result r = fDecoder->startScanlineDecode(fDecodeInfo); |
| if (SkCodec::kSuccess != r) { |
| SkCodecPrintf("Error: Could not start scanline decoder.\n"); |
| - return nullptr; |
| + return false; |
| } |
| // Allocate a bitmap for the unscaled decode |
| SkBitmap tmp; |
| - SkImageInfo tmpInfo = decodeInfo.makeWH(this->width(), subset.height()); |
| + SkImageInfo tmpInfo = fDecodeInfo.makeWH(this->width(), fSubset.height()); |
| if (!tmp.tryAllocPixels(tmpInfo)) { |
| SkCodecPrintf("Error: Could not allocate pixels.\n"); |
| - return nullptr; |
| + return false; |
| } |
| // Skip the unneeded rows |
| - if (!fDecoder->skipScanlines(subset.y())) { |
| + if (!fDecoder->skipScanlines(fSubset.y())) { |
| SkCodecPrintf("Error: Failed to skip scanlines.\n"); |
| - return nullptr; |
| + return false; |
| } |
| // Decode the necessary rows |
| - fDecoder->getScanlines(tmp.getAddr(0, 0), subset.height(), tmp.rowBytes()); |
| - |
| - // Calculate the size of the output |
| - const int outWidth = get_scaled_dimension(inputWidth, sampleSize); |
| - const int outHeight = get_scaled_dimension(inputHeight, sampleSize); |
| - |
| - // Initialize the destination bitmap |
| - SkAutoTDelete<SkBitmap> bitmap(new SkBitmap()); |
| - SkImageInfo dstInfo = decodeInfo.makeWH(outWidth, outHeight); |
| - if (!bitmap->tryAllocPixels(dstInfo)) { |
| - SkCodecPrintf("Error: Could not allocate pixels.\n"); |
| - return nullptr; |
| - } |
| + fDecoder->getScanlines(tmp.getAddr(0, 0), fSubset.height(), tmp.rowBytes()); |
| // 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 (SubsetType::kPartiallyInside_SubsetType == type) { |
| - bitmap->eraseColor(0); |
| + if (SubsetType::kPartiallyInside_SubsetType == fSubsetType) { |
| + bitmap.eraseColor(0); |
| } |
| // Use a canvas to crop and scale to the destination bitmap |
| - SkCanvas canvas(*bitmap); |
| + SkCanvas canvas(bitmap); |
| // TODO (msarett): Maybe we can take advantage of the fact that SkRect uses floats? |
| - SkRect src = SkRect::MakeXYWH((SkScalar) subset.x(), (SkScalar) 0, |
| - (SkScalar) subset.width(), (SkScalar) subset.height()); |
| - SkRect dst = SkRect::MakeXYWH((SkScalar) (outX / sampleSize), (SkScalar) (outY / sampleSize), |
| - (SkScalar) get_scaled_dimension(subset.width(), sampleSize), |
| - (SkScalar) get_scaled_dimension(subset.height(), sampleSize)); |
| + SkRect src = SkRect::MakeXYWH((SkScalar) fSubset.x(), (SkScalar) 0, |
| + (SkScalar) fSubset.width(), (SkScalar) fSubset.height()); |
| + SkRect dst = SkRect::MakeXYWH((SkScalar) (fOutX / fSampleSize), |
| + (SkScalar) (fOutY / fSampleSize), |
| + (SkScalar) get_scaled_dimension(fSubset.width(), fSampleSize), |
| + (SkScalar) get_scaled_dimension(fSubset.height(), fSampleSize)); |
| SkPaint paint; |
| // Overwrite the dst with the src pixels |
| paint.setXfermodeMode(SkXfermode::kSrc_Mode); |
| // TODO (msarett): Test multiple filter qualities. kNone is the default. |
| canvas.drawBitmapRect(tmp, src, dst, &paint); |
| - 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()); |
| + return true; |
| } |