Home | History | Annotate | Download | only in core
      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 "SkBitmap.h"
      9 #include "SkCanvas.h"
     10 #include "SkColorData.h"
     11 #include "SkConvertPixels.h"
     12 #include "SkData.h"
     13 #include "SkImageInfoPriv.h"
     14 #include "SkImageShader.h"
     15 #include "SkHalf.h"
     16 #include "SkMask.h"
     17 #include "SkNx.h"
     18 #include "SkPM4f.h"
     19 #include "SkPixmapPriv.h"
     20 #include "SkReadPixelsRec.h"
     21 #include "SkSurface.h"
     22 #include "SkTemplates.h"
     23 #include "SkUnPreMultiply.h"
     24 #include "SkUtils.h"
     25 
     26 /////////////////////////////////////////////////////////////////////////////////////////////////
     27 
     28 void SkPixmap::reset() {
     29     fPixels = nullptr;
     30     fRowBytes = 0;
     31     fInfo = SkImageInfo::MakeUnknown();
     32 }
     33 
     34 void SkPixmap::reset(const SkImageInfo& info, const void* addr, size_t rowBytes) {
     35     if (addr) {
     36         SkASSERT(info.validRowBytes(rowBytes));
     37     }
     38     fPixels = addr;
     39     fRowBytes = rowBytes;
     40     fInfo = info;
     41 }
     42 
     43 bool SkPixmap::reset(const SkMask& src) {
     44     if (SkMask::kA8_Format == src.fFormat) {
     45         this->reset(SkImageInfo::MakeA8(src.fBounds.width(), src.fBounds.height()),
     46                     src.fImage, src.fRowBytes);
     47         return true;
     48     }
     49     this->reset();
     50     return false;
     51 }
     52 
     53 void SkPixmap::setColorSpace(sk_sp<SkColorSpace> cs) {
     54     fInfo = fInfo.makeColorSpace(std::move(cs));
     55 }
     56 
     57 bool SkPixmap::extractSubset(SkPixmap* result, const SkIRect& subset) const {
     58     SkIRect srcRect, r;
     59     srcRect.set(0, 0, this->width(), this->height());
     60     if (!r.intersect(srcRect, subset)) {
     61         return false;   // r is empty (i.e. no intersection)
     62     }
     63 
     64     // If the upper left of the rectangle was outside the bounds of this SkBitmap, we should have
     65     // exited above.
     66     SkASSERT(static_cast<unsigned>(r.fLeft) < static_cast<unsigned>(this->width()));
     67     SkASSERT(static_cast<unsigned>(r.fTop) < static_cast<unsigned>(this->height()));
     68 
     69     const void* pixels = nullptr;
     70     if (fPixels) {
     71         const size_t bpp = fInfo.bytesPerPixel();
     72         pixels = (const uint8_t*)fPixels + r.fTop * fRowBytes + r.fLeft * bpp;
     73     }
     74     result->reset(fInfo.makeWH(r.width(), r.height()), pixels, fRowBytes);
     75     return true;
     76 }
     77 
     78 bool SkPixmap::readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, int x, int y,
     79                           SkTransferFunctionBehavior behavior) const {
     80     if (!SkImageInfoValidConversion(dstInfo, fInfo)) {
     81         return false;
     82     }
     83 
     84     SkReadPixelsRec rec(dstInfo, dstPixels, dstRB, x, y);
     85     if (!rec.trim(fInfo.width(), fInfo.height())) {
     86         return false;
     87     }
     88 
     89     const void* srcPixels = this->addr(rec.fX, rec.fY);
     90     const SkImageInfo srcInfo = fInfo.makeWH(rec.fInfo.width(), rec.fInfo.height());
     91     SkConvertPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, srcInfo, srcPixels, this->rowBytes(),
     92                     nullptr, behavior);
     93     return true;
     94 }
     95 
     96 static uint16_t pack_8888_to_4444(unsigned a, unsigned r, unsigned g, unsigned b) {
     97     unsigned pixel = (SkA32To4444(a) << SK_A4444_SHIFT) |
     98     (SkR32To4444(r) << SK_R4444_SHIFT) |
     99     (SkG32To4444(g) << SK_G4444_SHIFT) |
    100     (SkB32To4444(b) << SK_B4444_SHIFT);
    101     return SkToU16(pixel);
    102 }
    103 
    104 bool SkPixmap::erase(SkColor color, const SkIRect& inArea) const {
    105     if (nullptr == fPixels) {
    106         return false;
    107     }
    108     SkIRect area;
    109     if (!area.intersect(this->bounds(), inArea)) {
    110         return false;
    111     }
    112 
    113     U8CPU a = SkColorGetA(color);
    114     U8CPU r = SkColorGetR(color);
    115     U8CPU g = SkColorGetG(color);
    116     U8CPU b = SkColorGetB(color);
    117 
    118     int height = area.height();
    119     const int width = area.width();
    120     const int rowBytes = this->rowBytes();
    121 
    122     if (color == 0
    123           && width == this->rowBytesAsPixels()
    124           && inArea == this->bounds()) {
    125         // All formats represent SkColor(0) as byte 0.
    126         memset(this->writable_addr(), 0, (int64_t)height * rowBytes);
    127         return true;
    128     }
    129 
    130     switch (this->colorType()) {
    131         case kGray_8_SkColorType: {
    132             if (255 != a) {
    133                 r = SkMulDiv255Round(r, a);
    134                 g = SkMulDiv255Round(g, a);
    135                 b = SkMulDiv255Round(b, a);
    136             }
    137             int gray = SkComputeLuminance(r, g, b);
    138             uint8_t* p = this->writable_addr8(area.fLeft, area.fTop);
    139             while (--height >= 0) {
    140                 memset(p, gray, width);
    141                 p += rowBytes;
    142             }
    143             break;
    144         }
    145         case kAlpha_8_SkColorType: {
    146             uint8_t* p = this->writable_addr8(area.fLeft, area.fTop);
    147             while (--height >= 0) {
    148                 memset(p, a, width);
    149                 p += rowBytes;
    150             }
    151             break;
    152         }
    153         case kARGB_4444_SkColorType:
    154         case kRGB_565_SkColorType: {
    155             uint16_t* p = this->writable_addr16(area.fLeft, area.fTop);
    156             uint16_t v;
    157 
    158             // make rgb premultiplied
    159             if (255 != a) {
    160                 r = SkMulDiv255Round(r, a);
    161                 g = SkMulDiv255Round(g, a);
    162                 b = SkMulDiv255Round(b, a);
    163             }
    164 
    165             if (kARGB_4444_SkColorType == this->colorType()) {
    166                 v = pack_8888_to_4444(a, r, g, b);
    167             } else {
    168                 v = SkPackRGB16(r >> (8 - SK_R16_BITS),
    169                                 g >> (8 - SK_G16_BITS),
    170                                 b >> (8 - SK_B16_BITS));
    171             }
    172             while (--height >= 0) {
    173                 sk_memset16(p, v, width);
    174                 p = (uint16_t*)((char*)p + rowBytes);
    175             }
    176             break;
    177         }
    178         case kBGRA_8888_SkColorType:
    179         case kRGBA_8888_SkColorType: {
    180             uint32_t* p = this->writable_addr32(area.fLeft, area.fTop);
    181 
    182             if (255 != a && kPremul_SkAlphaType == this->alphaType()) {
    183                 r = SkMulDiv255Round(r, a);
    184                 g = SkMulDiv255Round(g, a);
    185                 b = SkMulDiv255Round(b, a);
    186             }
    187             uint32_t v = kRGBA_8888_SkColorType == this->colorType()
    188                              ? SkPackARGB_as_RGBA(a, r, g, b)
    189                              : SkPackARGB_as_BGRA(a, r, g, b);
    190 
    191             while (--height >= 0) {
    192                 sk_memset32(p, v, width);
    193                 p = (uint32_t*)((char*)p + rowBytes);
    194             }
    195             break;
    196         }
    197         case kRGBA_F16_SkColorType:
    198             // The colorspace is unspecified, so assume linear just like getColor().
    199             this->erase(SkColor4f{(1 / 255.0f) * r,
    200                                   (1 / 255.0f) * g,
    201                                   (1 / 255.0f) * b,
    202                                   (1 / 255.0f) * a}, &area);
    203             break;
    204         default:
    205             return false; // no change, so don't call notifyPixelsChanged()
    206     }
    207     return true;
    208 }
    209 
    210 bool SkPixmap::erase(const SkColor4f& origColor, const SkIRect* subset) const {
    211     SkPixmap pm;
    212     if (subset) {
    213         if (!this->extractSubset(&pm, *subset)) {
    214             return false;
    215         }
    216     } else {
    217         pm = *this;
    218     }
    219 
    220     const SkColor4f color = origColor.pin();
    221 
    222     if (kRGBA_F16_SkColorType != pm.colorType()) {
    223         return pm.erase(color.toSkColor());
    224     }
    225 
    226     const uint64_t half4 = color.premul().toF16();
    227     for (int y = 0; y < pm.height(); ++y) {
    228         sk_memset64(pm.writable_addr64(0, y), half4, pm.width());
    229     }
    230     return true;
    231 }
    232 
    233 bool SkPixmap::scalePixels(const SkPixmap& actualDst, SkFilterQuality quality) const {
    234     // We may need to tweak how we interpret these just a little below, so we make copies.
    235     SkPixmap src = *this,
    236              dst = actualDst;
    237 
    238     // Can't do anthing with empty src or dst
    239     if (src.width() <= 0 || src.height() <= 0 ||
    240         dst.width() <= 0 || dst.height() <= 0) {
    241         return false;
    242     }
    243 
    244     // no scaling involved?
    245     if (src.width() == dst.width() && src.height() == dst.height()) {
    246         return src.readPixels(dst);
    247     }
    248 
    249     // If src and dst are both unpremul, we'll fake them out to appear as if premul.
    250     bool clampAsIfUnpremul = false;
    251     if (src.alphaType() == kUnpremul_SkAlphaType &&
    252         dst.alphaType() == kUnpremul_SkAlphaType) {
    253         src.reset(src.info().makeAlphaType(kPremul_SkAlphaType), src.addr(), src.rowBytes());
    254         dst.reset(dst.info().makeAlphaType(kPremul_SkAlphaType), dst.addr(), dst.rowBytes());
    255 
    256         // In turn, we'll need to tell the image shader to clamp to [0,1] instead
    257         // of the usual [0,a] when using a bicubic scaling (kHigh_SkFilterQuality)
    258         // or a gamut transformation.
    259         clampAsIfUnpremul = true;
    260     }
    261 
    262     SkBitmap bitmap;
    263     if (!bitmap.installPixels(src)) {
    264         return false;
    265     }
    266     bitmap.setImmutable();        // Don't copy when we create an image.
    267     bitmap.setIsVolatile(true);   // Disable any caching.
    268 
    269     SkMatrix scale = SkMatrix::MakeRectToRect(SkRect::Make(src.bounds()),
    270                                               SkRect::Make(dst.bounds()),
    271                                               SkMatrix::kFill_ScaleToFit);
    272 
    273     // We'll create a shader to do this draw so we have control over the bicubic clamp.
    274     sk_sp<SkShader> shader = SkImageShader::Make(SkImage::MakeFromBitmap(bitmap),
    275                                                  SkShader::kClamp_TileMode,
    276                                                  SkShader::kClamp_TileMode,
    277                                                  &scale,
    278                                                  clampAsIfUnpremul);
    279 
    280     sk_sp<SkSurface> surface = SkSurface::MakeRasterDirect(dst.info(),
    281                                                            dst.writable_addr(),
    282                                                            dst.rowBytes());
    283     if (!shader || !surface) {
    284         return false;
    285     }
    286 
    287     SkPaint paint;
    288     paint.setBlendMode(SkBlendMode::kSrc);
    289     paint.setFilterQuality(quality);
    290     paint.setShader(std::move(shader));
    291     surface->getCanvas()->drawPaint(paint);
    292     return true;
    293 }
    294 
    295 //////////////////////////////////////////////////////////////////////////////////////////////////
    296 
    297 SkColor SkPixmap::getColor(int x, int y) const {
    298     SkASSERT(this->addr());
    299     SkASSERT((unsigned)x < (unsigned)this->width());
    300     SkASSERT((unsigned)y < (unsigned)this->height());
    301 
    302     const bool needsUnpremul = (kPremul_SkAlphaType == fInfo.alphaType());
    303     auto toColor = [needsUnpremul](uint32_t maybePremulColor) {
    304         return needsUnpremul ? SkUnPreMultiply::PMColorToColor(maybePremulColor)
    305                              : SkSwizzle_BGRA_to_PMColor(maybePremulColor);
    306     };
    307 
    308     switch (this->colorType()) {
    309         case kGray_8_SkColorType: {
    310             uint8_t value = *this->addr8(x, y);
    311             return SkColorSetRGB(value, value, value);
    312         }
    313         case kAlpha_8_SkColorType: {
    314             return SkColorSetA(0, *this->addr8(x, y));
    315         }
    316         case kRGB_565_SkColorType: {
    317             return SkPixel16ToColor(*this->addr16(x, y));
    318         }
    319         case kARGB_4444_SkColorType: {
    320             uint16_t value = *this->addr16(x, y);
    321             SkPMColor c = SkPixel4444ToPixel32(value);
    322             return toColor(c);
    323         }
    324         case kBGRA_8888_SkColorType: {
    325             uint32_t value = *this->addr32(x, y);
    326             SkPMColor c = SkSwizzle_BGRA_to_PMColor(value);
    327             return toColor(c);
    328         }
    329         case kRGBA_8888_SkColorType: {
    330             uint32_t value = *this->addr32(x, y);
    331             SkPMColor c = SkSwizzle_RGBA_to_PMColor(value);
    332             return toColor(c);
    333         }
    334         case kRGBA_F16_SkColorType: {
    335              const uint64_t* addr =
    336                  (const uint64_t*)fPixels + y * (fRowBytes >> 3) + x;
    337              Sk4f p4 = SkHalfToFloat_finite_ftz(*addr);
    338              if (p4[3] && needsUnpremul) {
    339                  float inva = 1 / p4[3];
    340                  p4 = p4 * Sk4f(inva, inva, inva, 1);
    341              }
    342              SkColor c;
    343              SkNx_cast<uint8_t>(p4 * Sk4f(255) + Sk4f(0.5f)).store(&c);
    344              // p4 is RGBA, but we want BGRA, so we need to swap next
    345              return SkSwizzle_RB(c);
    346         }
    347         default:
    348             SkDEBUGFAIL("");
    349             return SkColorSetARGB(0, 0, 0, 0);
    350     }
    351 }
    352 
    353 bool SkPixmap::computeIsOpaque() const {
    354     const int height = this->height();
    355     const int width = this->width();
    356 
    357     switch (this->colorType()) {
    358         case kAlpha_8_SkColorType: {
    359             unsigned a = 0xFF;
    360             for (int y = 0; y < height; ++y) {
    361                 const uint8_t* row = this->addr8(0, y);
    362                 for (int x = 0; x < width; ++x) {
    363                     a &= row[x];
    364                 }
    365                 if (0xFF != a) {
    366                     return false;
    367                 }
    368             }
    369             return true;
    370         } break;
    371         case kRGB_565_SkColorType:
    372         case kGray_8_SkColorType:
    373             return true;
    374             break;
    375         case kARGB_4444_SkColorType: {
    376             unsigned c = 0xFFFF;
    377             for (int y = 0; y < height; ++y) {
    378                 const SkPMColor16* row = this->addr16(0, y);
    379                 for (int x = 0; x < width; ++x) {
    380                     c &= row[x];
    381                 }
    382                 if (0xF != SkGetPackedA4444(c)) {
    383                     return false;
    384                 }
    385             }
    386             return true;
    387         } break;
    388         case kBGRA_8888_SkColorType:
    389         case kRGBA_8888_SkColorType: {
    390             SkPMColor c = (SkPMColor)~0;
    391             for (int y = 0; y < height; ++y) {
    392                 const SkPMColor* row = this->addr32(0, y);
    393                 for (int x = 0; x < width; ++x) {
    394                     c &= row[x];
    395                 }
    396                 if (0xFF != SkGetPackedA32(c)) {
    397                     return false;
    398                 }
    399             }
    400             return true;
    401         }
    402         case kRGBA_F16_SkColorType: {
    403             const SkHalf* row = (const SkHalf*)this->addr();
    404             for (int y = 0; y < height; ++y) {
    405                 for (int x = 0; x < width; ++x) {
    406                     if (row[4 * x + 3] < SK_Half1) {
    407                         return false;
    408                     }
    409                 }
    410                 row += this->rowBytes() >> 1;
    411             }
    412             return true;
    413         }
    414         default:
    415             break;
    416     }
    417     return false;
    418 }
    419 
    420 //////////////////////////////////////////////////////////////////////////////////////////////////
    421 
    422 static bool draw_orientation(const SkPixmap& dst, const SkPixmap& src, unsigned flags) {
    423     auto surf = SkSurface::MakeRasterDirect(dst.info(), dst.writable_addr(), dst.rowBytes());
    424     if (!surf) {
    425         return false;
    426     }
    427 
    428     SkBitmap bm;
    429     bm.installPixels(src);
    430 
    431     SkMatrix m;
    432     m.setIdentity();
    433 
    434     SkScalar W = SkIntToScalar(src.width());
    435     SkScalar H = SkIntToScalar(src.height());
    436     if (flags & SkPixmapPriv::kSwapXY) {
    437         SkMatrix s;
    438         s.setAll(0, 1, 0, 1, 0, 0, 0, 0, 1);
    439         m.postConcat(s);
    440         SkTSwap(W, H);
    441     }
    442     if (flags & SkPixmapPriv::kMirrorX) {
    443         m.postScale(-1, 1);
    444         m.postTranslate(W, 0);
    445     }
    446     if (flags & SkPixmapPriv::kMirrorY) {
    447         m.postScale(1, -1);
    448         m.postTranslate(0, H);
    449     }
    450     SkPaint p;
    451     p.setBlendMode(SkBlendMode::kSrc);
    452     surf->getCanvas()->concat(m);
    453     surf->getCanvas()->drawBitmap(bm, 0, 0, &p);
    454     return true;
    455 }
    456 
    457 bool SkPixmapPriv::Orient(const SkPixmap& dst, const SkPixmap& src, OrientFlags flags) {
    458     SkASSERT((flags & ~(kMirrorX | kMirrorY | kSwapXY)) == 0);
    459     if (src.colorType() != dst.colorType()) {
    460         return false;
    461     }
    462     // note: we just ignore alphaType and colorSpace for this transformation
    463 
    464     int w = src.width();
    465     int h = src.height();
    466     if (flags & kSwapXY) {
    467         SkTSwap(w, h);
    468     }
    469     if (dst.width() != w || dst.height() != h) {
    470         return false;
    471     }
    472     if (w == 0 || h == 0) {
    473         return true;
    474     }
    475 
    476     // check for aliasing to self
    477     if (src.addr() == dst.addr()) {
    478         return flags == 0;
    479     }
    480     return draw_orientation(dst, src, flags);
    481 }
    482 
    483 #define kMirrorX    SkPixmapPriv::kMirrorX
    484 #define kMirrorY    SkPixmapPriv::kMirrorY
    485 #define kSwapXY     SkPixmapPriv::kSwapXY
    486 
    487 static constexpr uint8_t gOrientationFlags[] = {
    488     0,                              // kTopLeft_SkEncodedOrigin
    489     kMirrorX,                       // kTopRight_SkEncodedOrigin
    490     kMirrorX | kMirrorY,            // kBottomRight_SkEncodedOrigin
    491                kMirrorY,            // kBottomLeft_SkEncodedOrigin
    492                           kSwapXY,  // kLeftTop_SkEncodedOrigin
    493     kMirrorX            | kSwapXY,  // kRightTop_SkEncodedOrigin
    494     kMirrorX | kMirrorY | kSwapXY,  // kRightBottom_SkEncodedOrigin
    495                kMirrorY | kSwapXY,  // kLeftBottom_SkEncodedOrigin
    496 };
    497 
    498 SkPixmapPriv::OrientFlags SkPixmapPriv::OriginToOrient(SkEncodedOrigin o) {
    499     unsigned io = static_cast<int>(o) - 1;
    500     SkASSERT(io < SK_ARRAY_COUNT(gOrientationFlags));
    501     return static_cast<SkPixmapPriv::OrientFlags>(gOrientationFlags[io]);
    502 }
    503 
    504 bool SkPixmapPriv::ShouldSwapWidthHeight(SkEncodedOrigin o) {
    505     return SkToBool(OriginToOrient(o) & kSwapXY);
    506 }
    507 
    508 SkImageInfo SkPixmapPriv::SwapWidthHeight(const SkImageInfo& info) {
    509     return info.makeWH(info.height(), info.width());
    510 }
    511 
    512