Home | History | Annotate | Download | only in image
      1 /*
      2  * Copyright 2012 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 "SkBitmapCache.h"
     10 #include "SkCanvas.h"
     11 #include "SkColorSpace_Base.h"
     12 #include "SkData.h"
     13 #include "SkImageEncoder.h"
     14 #include "SkImageFilter.h"
     15 #include "SkImageFilterCache.h"
     16 #include "SkImageGenerator.h"
     17 #include "SkImagePriv.h"
     18 #include "SkImageShader.h"
     19 #include "SkImage_Base.h"
     20 #include "SkNextID.h"
     21 #include "SkPicture.h"
     22 #include "SkPixelRef.h"
     23 #include "SkPixelSerializer.h"
     24 #include "SkReadPixelsRec.h"
     25 #include "SkSpecialImage.h"
     26 #include "SkStream.h"
     27 #include "SkString.h"
     28 #include "SkSurface.h"
     29 
     30 #if SK_SUPPORT_GPU
     31 #include "GrTexture.h"
     32 #include "GrContext.h"
     33 #include "SkImage_Gpu.h"
     34 #endif
     35 
     36 SkImage::SkImage(int width, int height, uint32_t uniqueID)
     37     : fWidth(width)
     38     , fHeight(height)
     39     , fUniqueID(kNeedNewImageUniqueID == uniqueID ? SkNextID::ImageID() : uniqueID)
     40 {
     41     SkASSERT(width > 0);
     42     SkASSERT(height > 0);
     43 }
     44 
     45 bool SkImage::peekPixels(SkPixmap* pm) const {
     46     SkPixmap tmp;
     47     if (!pm) {
     48         pm = &tmp;
     49     }
     50     return as_IB(this)->onPeekPixels(pm);
     51 }
     52 
     53 bool SkImage::readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
     54                            int srcX, int srcY, CachingHint chint) const {
     55     return as_IB(this)->onReadPixels(dstInfo, dstPixels, dstRowBytes, srcX, srcY, chint);
     56 }
     57 
     58 bool SkImage::scalePixels(const SkPixmap& dst, SkFilterQuality quality, CachingHint chint) const {
     59     if (this->width() == dst.width() && this->height() == dst.height()) {
     60         return this->readPixels(dst, 0, 0, chint);
     61     }
     62 
     63     // Idea: If/when SkImageGenerator supports a native-scaling API (where the generator itself
     64     //       can scale more efficiently) we should take advantage of it here.
     65     //
     66     SkBitmap bm;
     67     if (as_IB(this)->getROPixels(&bm, dst.info().colorSpace(), chint)) {
     68         SkPixmap pmap;
     69         // Note: By calling the pixmap scaler, we never cache the final result, so the chint
     70         //       is (currently) only being applied to the getROPixels. If we get a request to
     71         //       also attempt to cache the final (scaled) result, we would add that logic here.
     72         //
     73         return bm.peekPixels(&pmap) && pmap.scalePixels(dst, quality);
     74     }
     75     return false;
     76 }
     77 
     78 ///////////////////////////////////////////////////////////////////////////////////////////////////
     79 
     80 SkAlphaType SkImage::alphaType() const {
     81     return as_IB(this)->onAlphaType();
     82 }
     83 
     84 SkColorSpace* SkImage::colorSpace() const {
     85     return as_IB(this)->onImageInfo().colorSpace();
     86 }
     87 
     88 sk_sp<SkColorSpace> SkImage::refColorSpace() const {
     89     return as_IB(this)->onImageInfo().refColorSpace();
     90 }
     91 
     92 sk_sp<SkShader> SkImage::makeShader(SkShader::TileMode tileX, SkShader::TileMode tileY,
     93                                     const SkMatrix* localMatrix) const {
     94     return SkImageShader::Make(sk_ref_sp(const_cast<SkImage*>(this)), tileX, tileY, localMatrix);
     95 }
     96 
     97 sk_sp<SkData> SkImage::encodeToData(SkEncodedImageFormat type, int quality) const {
     98     SkBitmap bm;
     99     SkColorSpace* legacyColorSpace = nullptr;
    100     if (as_IB(this)->getROPixels(&bm, legacyColorSpace)) {
    101         SkDynamicMemoryWStream buf;
    102         return SkEncodeImage(&buf, bm, type, quality) ? buf.detachAsData() : nullptr;
    103     }
    104     return nullptr;
    105 }
    106 
    107 sk_sp<SkData> SkImage::encodeToData(SkPixelSerializer* serializer) const {
    108     sk_sp<SkData> encoded(this->refEncodedData());
    109     if (encoded &&
    110         (!serializer || serializer->useEncodedData(encoded->data(), encoded->size()))) {
    111         return encoded;
    112     }
    113 
    114     SkBitmap bm;
    115     SkPixmap pmap;
    116     SkColorSpace* legacyColorSpace = nullptr;
    117     if (as_IB(this)->getROPixels(&bm, legacyColorSpace) && bm.peekPixels(&pmap)) {
    118         if (serializer) {
    119             return serializer->encodeToData(pmap);
    120         } else {
    121             SkDynamicMemoryWStream buf;
    122             return SkEncodeImage(&buf, pmap, SkEncodedImageFormat::kPNG, 100)
    123                    ? buf.detachAsData() : nullptr;
    124         }
    125     }
    126 
    127     return nullptr;
    128 }
    129 
    130 sk_sp<SkData> SkImage::refEncodedData() const {
    131     return sk_sp<SkData>(as_IB(this)->onRefEncoded());
    132 }
    133 
    134 sk_sp<SkImage> SkImage::MakeFromEncoded(sk_sp<SkData> encoded, const SkIRect* subset) {
    135     if (nullptr == encoded || 0 == encoded->size()) {
    136         return nullptr;
    137     }
    138     return SkImage::MakeFromGenerator(SkImageGenerator::MakeFromEncoded(encoded), subset);
    139 }
    140 
    141 ///////////////////////////////////////////////////////////////////////////////////////////////////
    142 
    143 const char* SkImage::toString(SkString* str) const {
    144     str->appendf("image: (id:%d (%d, %d) %s)", this->uniqueID(), this->width(), this->height(),
    145                  this->isOpaque() ? "opaque" : "");
    146     return str->c_str();
    147 }
    148 
    149 sk_sp<SkImage> SkImage::makeSubset(const SkIRect& subset) const {
    150     if (subset.isEmpty()) {
    151         return nullptr;
    152     }
    153 
    154     const SkIRect bounds = SkIRect::MakeWH(this->width(), this->height());
    155     if (!bounds.contains(subset)) {
    156         return nullptr;
    157     }
    158 
    159     // optimization : return self if the subset == our bounds
    160     if (bounds == subset) {
    161         return sk_ref_sp(const_cast<SkImage*>(this));
    162     }
    163     return as_IB(this)->onMakeSubset(subset);
    164 }
    165 
    166 #if SK_SUPPORT_GPU
    167 
    168 GrTexture* SkImage::getTexture() const {
    169     return as_IB(this)->onGetTexture();
    170 }
    171 
    172 bool SkImage::isTextureBacked() const { return SkToBool(as_IB(this)->peekProxy()); }
    173 
    174 GrBackendObject SkImage::getTextureHandle(bool flushPendingGrContextIO,
    175                                           GrSurfaceOrigin* origin) const {
    176     return as_IB(this)->onGetTextureHandle(flushPendingGrContextIO, origin);
    177 }
    178 
    179 bool SkImage::isValid(GrContext* context) const {
    180     if (context && context->abandoned()) {
    181         return false;
    182     }
    183     return as_IB(this)->onIsValid(context);
    184 }
    185 
    186 #else
    187 
    188 GrTexture* SkImage::getTexture() const { return nullptr; }
    189 
    190 bool SkImage::isTextureBacked() const { return false; }
    191 
    192 GrBackendObject SkImage::getTextureHandle(bool, GrSurfaceOrigin*) const { return 0; }
    193 
    194 bool SkImage::isValid(GrContext* context) const {
    195     if (context) {
    196         return false;
    197     }
    198     return as_IB(this)->onIsValid(context);
    199 }
    200 
    201 #endif
    202 
    203 ///////////////////////////////////////////////////////////////////////////////
    204 
    205 SkImage_Base::SkImage_Base(int width, int height, uint32_t uniqueID)
    206     : INHERITED(width, height, uniqueID)
    207     , fAddedToCache(false)
    208 {}
    209 
    210 SkImage_Base::~SkImage_Base() {
    211     if (fAddedToCache.load()) {
    212         SkNotifyBitmapGenIDIsStale(this->uniqueID());
    213     }
    214 }
    215 
    216 bool SkImage::readPixels(const SkPixmap& pmap, int srcX, int srcY, CachingHint chint) const {
    217     return this->readPixels(pmap.info(), pmap.writable_addr(), pmap.rowBytes(), srcX, srcY, chint);
    218 }
    219 
    220 ///////////////////////////////////////////////////////////////////////////////////////////////////
    221 
    222 sk_sp<SkImage> SkImage::MakeFromBitmap(const SkBitmap& bm) {
    223     SkPixelRef* pr = bm.pixelRef();
    224     if (nullptr == pr) {
    225         return nullptr;
    226     }
    227 
    228     return SkMakeImageFromRasterBitmap(bm, kIfMutable_SkCopyPixelsMode);
    229 }
    230 
    231 bool SkImage::asLegacyBitmap(SkBitmap* bitmap, LegacyBitmapMode mode) const {
    232     return as_IB(this)->onAsLegacyBitmap(bitmap, mode);
    233 }
    234 
    235 bool SkImage_Base::onAsLegacyBitmap(SkBitmap* bitmap, LegacyBitmapMode mode) const {
    236     // As the base-class, all we can do is make a copy (regardless of mode).
    237     // Subclasses that want to be more optimal should override.
    238     SkImageInfo info = this->onImageInfo().makeColorType(kN32_SkColorType).makeColorSpace(nullptr);
    239     if (!bitmap->tryAllocPixels(info)) {
    240         return false;
    241     }
    242     if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), 0, 0)) {
    243         bitmap->reset();
    244         return false;
    245     }
    246 
    247     if (kRO_LegacyBitmapMode == mode) {
    248         bitmap->setImmutable();
    249     }
    250     return true;
    251 }
    252 
    253 sk_sp<SkImage> SkImage::MakeFromPicture(sk_sp<SkPicture> picture, const SkISize& dimensions,
    254                                         const SkMatrix* matrix, const SkPaint* paint,
    255                                         BitDepth bitDepth, sk_sp<SkColorSpace> colorSpace) {
    256     return MakeFromGenerator(SkImageGenerator::MakeFromPicture(dimensions, std::move(picture),
    257                                                                matrix, paint, bitDepth,
    258                                                                std::move(colorSpace)));
    259 }
    260 
    261 sk_sp<SkImage> SkImage::makeWithFilter(const SkImageFilter* filter, const SkIRect& subset,
    262                                        const SkIRect& clipBounds, SkIRect* outSubset,
    263                                        SkIPoint* offset) const {
    264     if (!filter || !outSubset || !offset || !this->bounds().contains(subset)) {
    265         return nullptr;
    266     }
    267     SkColorSpace* colorSpace = as_IB(this)->onImageInfo().colorSpace();
    268     sk_sp<SkSpecialImage> srcSpecialImage = SkSpecialImage::MakeFromImage(
    269         subset, sk_ref_sp(const_cast<SkImage*>(this)), colorSpace);
    270     if (!srcSpecialImage) {
    271         return nullptr;
    272     }
    273 
    274     sk_sp<SkImageFilterCache> cache(
    275         SkImageFilterCache::Create(SkImageFilterCache::kDefaultTransientSize));
    276     SkImageFilter::OutputProperties outputProperties(colorSpace);
    277     SkImageFilter::Context context(SkMatrix::I(), clipBounds, cache.get(), outputProperties);
    278 
    279     sk_sp<SkSpecialImage> result = filter->filterImage(srcSpecialImage.get(), context, offset);
    280     if (!result) {
    281         return nullptr;
    282     }
    283 
    284     *outSubset = SkIRect::MakeWH(result->width(), result->height());
    285     if (!outSubset->intersect(clipBounds.makeOffset(-offset->x(), -offset->y()))) {
    286         return nullptr;
    287     }
    288     offset->fX += outSubset->x();
    289     offset->fY += outSubset->y();
    290 
    291     // Note that here we're returning the special image's entire backing store, loose padding
    292     // and all!
    293     return result->asImage();
    294 }
    295 
    296 bool SkImage::isLazyGenerated() const {
    297     return as_IB(this)->onIsLazyGenerated();
    298 }
    299 
    300 bool SkImage::isAlphaOnly() const {
    301     return as_IB(this)->onImageInfo().colorType() == kAlpha_8_SkColorType;
    302 }
    303 
    304 sk_sp<SkImage> SkImage::makeColorSpace(sk_sp<SkColorSpace> target,
    305                                        SkTransferFunctionBehavior premulBehavior) const {
    306     SkColorSpaceTransferFn fn;
    307     if (!target || !target->isNumericalTransferFn(&fn)) {
    308         return nullptr;
    309     }
    310 
    311     // No need to create a new image if:
    312     // (1) The color spaces are equal.
    313     // (2) The color type is kAlpha8.
    314     if (SkColorSpace::Equals(this->colorSpace(), target.get()) ||
    315             kAlpha_8_SkColorType == as_IB(this)->onImageInfo().colorType()) {
    316         return sk_ref_sp(const_cast<SkImage*>(this));
    317     }
    318 
    319     SkColorType targetColorType = kN32_SkColorType;
    320     if (SkTransferFunctionBehavior::kRespect == premulBehavior && target->gammaIsLinear()) {
    321         targetColorType = kRGBA_F16_SkColorType;
    322     }
    323 
    324     // TODO: We might consider making this a deferred conversion?
    325     return as_IB(this)->onMakeColorSpace(std::move(target), targetColorType, premulBehavior);
    326 }
    327 
    328 //////////////////////////////////////////////////////////////////////////////////////
    329 
    330 #if !SK_SUPPORT_GPU
    331 
    332 sk_sp<SkImage> MakeTextureFromMipMap(GrContext*, const SkImageInfo&, const GrMipLevel texels[],
    333                                      int mipLevelCount, SkBudgeted, SkDestinationSurfaceColorMode) {
    334     return nullptr;
    335 }
    336 
    337 sk_sp<SkImage> SkImage::MakeFromTexture(GrContext*, const GrBackendTextureDesc&, SkAlphaType,
    338                                         sk_sp<SkColorSpace>, TextureReleaseProc, ReleaseContext) {
    339     return nullptr;
    340 }
    341 
    342 sk_sp<SkImage> SkImage::MakeFromTexture(GrContext* ctx,
    343                                         const GrBackendTexture& tex, GrSurfaceOrigin origin,
    344                                         SkAlphaType at, sk_sp<SkColorSpace> cs,
    345                                         TextureReleaseProc releaseP, ReleaseContext releaseC) {
    346     return nullptr;
    347 }
    348 
    349 size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy&,
    350                                             const DeferredTextureImageUsageParams[],
    351                                             int paramCnt, void* buffer,
    352                                             SkColorSpace* dstColorSpace,
    353                                             SkColorType dstColorType) const {
    354     return 0;
    355 }
    356 
    357 sk_sp<SkImage> SkImage::MakeFromDeferredTextureImageData(GrContext* context, const void*,
    358                                                          SkBudgeted) {
    359     return nullptr;
    360 }
    361 
    362 sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrContext*, const GrBackendTextureDesc&,
    363                                                SkAlphaType, sk_sp<SkColorSpace>) {
    364     return nullptr;
    365 }
    366 
    367 sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrContext* ctx,
    368                                                const GrBackendTexture& tex, GrSurfaceOrigin origin,
    369                                                SkAlphaType at, sk_sp<SkColorSpace> cs) {
    370     return nullptr;
    371 }
    372 
    373 sk_sp<SkImage> SkImage::MakeFromYUVTexturesCopy(GrContext* ctx, SkYUVColorSpace space,
    374                                                 const GrBackendObject yuvTextureHandles[3],
    375                                                 const SkISize yuvSizes[3],
    376                                                 GrSurfaceOrigin origin,
    377                                                 sk_sp<SkColorSpace> imageColorSpace) {
    378     return nullptr;
    379 }
    380 
    381 sk_sp<SkImage> SkImage::makeTextureImage(GrContext*, SkColorSpace* dstColorSpace) const {
    382     return nullptr;
    383 }
    384 
    385 sk_sp<SkImage> SkImage::makeNonTextureImage() const {
    386     return sk_ref_sp(const_cast<SkImage*>(this));
    387 }
    388 
    389 #endif
    390 
    391 ///////////////////////////////////////////////////////////////////////////////////////////////////
    392 
    393 sk_sp<SkImage> MakeTextureFromMipMap(GrContext*, const SkImageInfo&, const GrMipLevel texels[],
    394                                      int mipLevelCount, SkBudgeted) {
    395     return nullptr;
    396 }
    397 
    398 ///////////////////////////////////////////////////////////////////////////////////////////////////
    399 #include "SkImageDeserializer.h"
    400 
    401 sk_sp<SkImage> SkImageDeserializer::makeFromData(SkData* data, const SkIRect* subset) {
    402     return SkImage::MakeFromEncoded(sk_ref_sp(data), subset);
    403 }
    404 sk_sp<SkImage> SkImageDeserializer::makeFromMemory(const void* data, size_t length,
    405                                                    const SkIRect* subset) {
    406     return SkImage::MakeFromEncoded(SkData::MakeWithCopy(data, length), subset);
    407 }
    408 
    409 ///////////////////////////////////////////////////////////////////////////////////////////////////
    410 
    411 bool SkImage_pinAsTexture(const SkImage* image, GrContext* ctx) {
    412     SkASSERT(image);
    413     SkASSERT(ctx);
    414     return as_IB(image)->onPinAsTexture(ctx);
    415 }
    416 
    417 void SkImage_unpinAsTexture(const SkImage* image, GrContext* ctx) {
    418     SkASSERT(image);
    419     SkASSERT(ctx);
    420     as_IB(image)->onUnpinAsTexture(ctx);
    421 }
    422 
    423 ///////////////////////////////////////////////////////////////////////////////////////////////////
    424 
    425 sk_sp<SkImage> SkImageMakeRasterCopyAndAssignColorSpace(const SkImage* src,
    426                                                         SkColorSpace* colorSpace) {
    427     // Read the pixels out of the source image, with no conversion
    428     SkImageInfo info = as_IB(src)->onImageInfo();
    429     if (kUnknown_SkColorType == info.colorType()) {
    430         SkDEBUGFAIL("Unexpected color type");
    431         return nullptr;
    432     }
    433 
    434     size_t rowBytes = info.minRowBytes();
    435     size_t size = info.getSafeSize(rowBytes);
    436     auto data = SkData::MakeUninitialized(size);
    437     if (!data) {
    438         return nullptr;
    439     }
    440 
    441     SkPixmap pm(info, data->writable_data(), rowBytes);
    442     if (!src->readPixels(pm, 0, 0, SkImage::kDisallow_CachingHint)) {
    443         return nullptr;
    444     }
    445 
    446     // Wrap them in a new image with a different color space
    447     return SkImage::MakeRasterData(info.makeColorSpace(sk_ref_sp(colorSpace)), data, rowBytes);
    448 }
    449