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