Home | History | Annotate | Download | only in android
      1 /*
      2  * Copyright 2015 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkBitmapRegionCanvas.h"
      9 #include "SkBitmapRegionDecoderPriv.h"
     10 #include "SkCanvas.h"
     11 #include "SkCodecPriv.h"
     12 
     13 SkBitmapRegionCanvas::SkBitmapRegionCanvas(SkCodec* decoder)
     14     : INHERITED(decoder->getInfo().width(), decoder->getInfo().height())
     15     , fDecoder(decoder)
     16 {}
     17 
     18 bool SkBitmapRegionCanvas::decodeRegion(SkBitmap* bitmap, SkBRDAllocator* allocator,
     19         const SkIRect& desiredSubset, int sampleSize, SkColorType dstColorType,
     20         bool requireUnpremul) {
     21 
     22     // Reject color types not supported by this method
     23     if (kIndex_8_SkColorType == dstColorType || kGray_8_SkColorType == dstColorType) {
     24         SkCodecPrintf("Error: Color type not supported.\n");
     25         return false;
     26     }
     27 
     28     // Reject requests for unpremultiplied alpha
     29     if (requireUnpremul) {
     30         SkCodecPrintf("Error: Alpha type not supported.\n");
     31         return false;
     32     }
     33     SkAlphaType dstAlphaType = fDecoder->getInfo().alphaType();
     34     if (kUnpremul_SkAlphaType == dstAlphaType) {
     35         dstAlphaType = kPremul_SkAlphaType;
     36     }
     37 
     38     // Fix the input sampleSize if necessary.
     39     if (sampleSize < 1) {
     40         sampleSize = 1;
     41     }
     42 
     43     // The size of the output bitmap is determined by the size of the
     44     // requested subset, not by the size of the intersection of the subset
     45     // and the image dimensions.
     46     // If inputX is negative, we will need to place decoded pixels into the
     47     // output bitmap starting at a left offset.  Call this outX.
     48     // If outX is non-zero, subsetX must be zero.
     49     // If inputY is negative, we will need to place decoded pixels into the
     50     // output bitmap starting at a top offset.  Call this outY.
     51     // If outY is non-zero, subsetY must be zero.
     52     int outX;
     53     int outY;
     54     SkIRect subset = desiredSubset;
     55     SubsetType type = adjust_subset_rect(fDecoder->getInfo().dimensions(), &subset, &outX, &outY);
     56     if (SubsetType::kOutside_SubsetType == type) {
     57         return false;
     58     }
     59 
     60     // Create the image info for the decode
     61     SkImageInfo decodeInfo = SkImageInfo::Make(this->width(), this->height(),
     62             dstColorType, dstAlphaType);
     63 
     64     // Start the scanline decoder
     65     SkCodec::Result r = fDecoder->startScanlineDecode(decodeInfo);
     66     if (SkCodec::kSuccess != r) {
     67         SkCodecPrintf("Error: Could not start scanline decoder.\n");
     68         return false;
     69     }
     70 
     71     // Allocate a bitmap for the unscaled decode
     72     SkBitmap tmp;
     73     SkImageInfo tmpInfo = decodeInfo.makeWH(this->width(), subset.height());
     74     if (!tmp.tryAllocPixels(tmpInfo)) {
     75         SkCodecPrintf("Error: Could not allocate pixels.\n");
     76         return false;
     77     }
     78 
     79     // Skip the unneeded rows
     80     if (!fDecoder->skipScanlines(subset.y())) {
     81         SkCodecPrintf("Error: Failed to skip scanlines.\n");
     82         return false;
     83     }
     84 
     85     // Decode the necessary rows
     86     fDecoder->getScanlines(tmp.getAddr(0, 0), subset.height(), tmp.rowBytes());
     87 
     88     // Calculate the size of the output
     89     const int outWidth = get_scaled_dimension(desiredSubset.width(), sampleSize);
     90     const int outHeight = get_scaled_dimension(desiredSubset.height(), sampleSize);
     91 
     92     // Initialize the destination bitmap
     93     SkImageInfo dstInfo = decodeInfo.makeWH(outWidth, outHeight);
     94     bitmap->setInfo(dstInfo, dstInfo.minRowBytes());
     95     if (!bitmap->tryAllocPixels(allocator, nullptr)) {
     96         SkCodecPrintf("Error: Could not allocate pixels.\n");
     97         return false;
     98     }
     99 
    100     // Zero the bitmap if the region is not completely within the image.
    101     // TODO (msarett): Can we make this faster by implementing it to only
    102     //                 zero parts of the image that we won't overwrite with
    103     //                 pixels?
    104     if (SubsetType::kPartiallyInside_SubsetType == type) {
    105         SkCodec::ZeroInitialized zeroInit = allocator ? allocator->zeroInit() :
    106                     SkCodec::kNo_ZeroInitialized;
    107         if (SkCodec::kNo_ZeroInitialized == zeroInit) {
    108             bitmap->eraseColor(0);
    109         }
    110     }
    111 
    112     // Use a canvas to crop and scale to the destination bitmap
    113     SkCanvas canvas(*bitmap);
    114     // TODO (msarett): Maybe we can take advantage of the fact that SkRect uses floats?
    115     SkRect src = SkRect::MakeXYWH((SkScalar) subset.x(), (SkScalar) 0,
    116             (SkScalar) subset.width(), (SkScalar) subset.height());
    117     SkRect dst = SkRect::MakeXYWH((SkScalar) (outX / sampleSize), (SkScalar) (outY / sampleSize),
    118             (SkScalar) get_scaled_dimension(subset.width(), sampleSize),
    119             (SkScalar) get_scaled_dimension(subset.height(), sampleSize));
    120     SkPaint paint;
    121     // Overwrite the dst with the src pixels
    122     paint.setXfermodeMode(SkXfermode::kSrc_Mode);
    123     // TODO (msarett): Test multiple filter qualities.  kNone is the default.
    124     canvas.drawBitmapRect(tmp, src, dst, &paint);
    125 
    126     return true;
    127 }
    128 
    129 bool SkBitmapRegionCanvas::conversionSupported(SkColorType colorType) {
    130     // SkCanvas does not draw to these color types.
    131     if (kIndex_8_SkColorType == colorType || kGray_8_SkColorType == colorType) {
    132         return false;
    133     }
    134 
    135     // FIXME: Call virtual function when it lands.
    136     SkImageInfo info = SkImageInfo::Make(0, 0, colorType, fDecoder->getInfo().alphaType(),
    137             fDecoder->getInfo().profileType());
    138     return conversion_possible(info, fDecoder->getInfo());
    139 }
    140