123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538 |
- /*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
- #include "include/core/SkBitmap.h"
- #include "include/core/SkCanvas.h"
- #include "include/core/SkData.h"
- #include "include/core/SkImageEncoder.h"
- #include "include/core/SkImageFilter.h"
- #include "include/core/SkImageGenerator.h"
- #include "include/core/SkPicture.h"
- #include "include/core/SkString.h"
- #include "include/core/SkSurface.h"
- #include "src/core/SkBitmapCache.h"
- #include "src/core/SkCachedData.h"
- #include "src/core/SkColorSpacePriv.h"
- #include "src/core/SkImageFilterCache.h"
- #include "src/core/SkImagePriv.h"
- #include "src/core/SkNextID.h"
- #include "src/core/SkSpecialImage.h"
- #include "src/image/SkImage_Base.h"
- #include "src/image/SkReadPixelsRec.h"
- #include "src/shaders/SkImageShader.h"
- #if SK_SUPPORT_GPU
- #include "include/gpu/GrContext.h"
- #include "include/gpu/GrTexture.h"
- #include "src/image/SkImage_Gpu.h"
- #endif
- #include "include/gpu/GrBackendSurface.h"
- SkImage::SkImage(const SkImageInfo& info, uint32_t uniqueID)
- : fInfo(info)
- , fUniqueID(kNeedNewImageUniqueID == uniqueID ? SkNextID::ImageID() : uniqueID) {
- SkASSERT(info.width() > 0);
- SkASSERT(info.height() > 0);
- }
- bool SkImage::peekPixels(SkPixmap* pm) const {
- SkPixmap tmp;
- if (!pm) {
- pm = &tmp;
- }
- return as_IB(this)->onPeekPixels(pm);
- }
- bool SkImage::readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, int srcX,
- int srcY, CachingHint chint) const {
- return as_IB(this)->onReadPixels(dstInfo, dstPixels, dstRowBytes, srcX, srcY, chint);
- }
- bool SkImage::scalePixels(const SkPixmap& dst, SkFilterQuality quality, CachingHint chint) const {
- if (this->width() == dst.width() && this->height() == dst.height()) {
- return this->readPixels(dst, 0, 0, chint);
- }
- // Idea: If/when SkImageGenerator supports a native-scaling API (where the generator itself
- // can scale more efficiently) we should take advantage of it here.
- //
- SkBitmap bm;
- if (as_IB(this)->getROPixels(&bm, chint)) {
- SkPixmap pmap;
- // Note: By calling the pixmap scaler, we never cache the final result, so the chint
- // is (currently) only being applied to the getROPixels. If we get a request to
- // also attempt to cache the final (scaled) result, we would add that logic here.
- //
- return bm.peekPixels(&pmap) && pmap.scalePixels(dst, quality);
- }
- return false;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- SkColorType SkImage::colorType() const { return fInfo.colorType(); }
- SkAlphaType SkImage::alphaType() const { return fInfo.alphaType(); }
- SkColorSpace* SkImage::colorSpace() const { return fInfo.colorSpace(); }
- sk_sp<SkColorSpace> SkImage::refColorSpace() const { return fInfo.refColorSpace(); }
- sk_sp<SkShader> SkImage::makeShader(SkTileMode tmx, SkTileMode tmy,
- const SkMatrix* localMatrix) const {
- return SkImageShader::Make(sk_ref_sp(const_cast<SkImage*>(this)), tmx, tmy, localMatrix);
- }
- sk_sp<SkData> SkImage::encodeToData(SkEncodedImageFormat type, int quality) const {
- SkBitmap bm;
- if (as_IB(this)->getROPixels(&bm)) {
- return SkEncodeBitmap(bm, type, quality);
- }
- return nullptr;
- }
- sk_sp<SkData> SkImage::encodeToData() const {
- if (auto encoded = this->refEncodedData()) {
- return encoded;
- }
- return this->encodeToData(SkEncodedImageFormat::kPNG, 100);
- }
- sk_sp<SkData> SkImage::refEncodedData() const {
- return sk_sp<SkData>(as_IB(this)->onRefEncoded());
- }
- sk_sp<SkImage> SkImage::MakeFromEncoded(sk_sp<SkData> encoded, const SkIRect* subset) {
- if (nullptr == encoded || 0 == encoded->size()) {
- return nullptr;
- }
- return SkImage::MakeFromGenerator(SkImageGenerator::MakeFromEncoded(std::move(encoded)),
- subset);
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- sk_sp<SkImage> SkImage::makeSubset(const SkIRect& subset) const {
- if (subset.isEmpty()) {
- return nullptr;
- }
- const SkIRect bounds = SkIRect::MakeWH(this->width(), this->height());
- if (!bounds.contains(subset)) {
- return nullptr;
- }
- // optimization : return self if the subset == our bounds
- if (bounds == subset) {
- return sk_ref_sp(const_cast<SkImage*>(this));
- }
- // CONTEXT TODO: propagate the context parameter to the top-level API
- #if SK_SUPPORT_GPU
- return as_IB(this)->onMakeSubset(as_IB(this)->context(), subset);
- #else
- return as_IB(this)->onMakeSubset(nullptr, subset);
- #endif
- }
- #if SK_SUPPORT_GPU
- GrTexture* SkImage::getTexture() const {
- return as_IB(this)->onGetTexture();
- }
- bool SkImage::isTextureBacked() const { return as_IB(this)->onIsTextureBacked(); }
- GrBackendTexture SkImage::getBackendTexture(bool flushPendingGrContextIO,
- GrSurfaceOrigin* origin) const {
- return as_IB(this)->onGetBackendTexture(flushPendingGrContextIO, origin);
- }
- bool SkImage::isValid(GrContext* context) const {
- if (context && context->abandoned()) {
- return false;
- }
- return as_IB(this)->onIsValid(context);
- }
- GrSemaphoresSubmitted SkImage::flush(GrContext* context, const GrFlushInfo& flushInfo) {
- return as_IB(this)->onFlush(context, flushInfo);
- }
- void SkImage::flush(GrContext* context) { as_IB(this)->onFlush(context, {}); }
- #else
- GrTexture* SkImage::getTexture() const { return nullptr; }
- bool SkImage::isTextureBacked() const { return false; }
- GrBackendTexture SkImage::getBackendTexture(bool flushPendingGrContextIO,
- GrSurfaceOrigin* origin) const {
- return GrBackendTexture(); // invalid
- }
- bool SkImage::isValid(GrContext* context) const {
- if (context) {
- return false;
- }
- return as_IB(this)->onIsValid(context);
- }
- GrSemaphoresSubmitted SkImage::flush(GrContext*, const GrFlushInfo&) {
- return GrSemaphoresSubmitted::kNo;
- }
- void SkImage::flush(GrContext*) {}
- #endif
- ///////////////////////////////////////////////////////////////////////////////
- SkImage_Base::SkImage_Base(const SkImageInfo& info, uint32_t uniqueID)
- : INHERITED(info, uniqueID), fAddedToRasterCache(false) {}
- SkImage_Base::~SkImage_Base() {
- if (fAddedToRasterCache.load()) {
- SkNotifyBitmapGenIDIsStale(this->uniqueID());
- }
- }
- GrBackendTexture SkImage_Base::onGetBackendTexture(bool flushPendingGrContextIO,
- GrSurfaceOrigin* origin) const {
- return GrBackendTexture(); // invalid
- }
- bool SkImage::readPixels(const SkPixmap& pmap, int srcX, int srcY, CachingHint chint) const {
- return this->readPixels(pmap.info(), pmap.writable_addr(), pmap.rowBytes(), srcX, srcY, chint);
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- sk_sp<SkImage> SkImage::MakeFromBitmap(const SkBitmap& bm) {
- if (!bm.pixelRef()) {
- return nullptr;
- }
- return SkMakeImageFromRasterBitmap(bm, kIfMutable_SkCopyPixelsMode);
- }
- bool SkImage::asLegacyBitmap(SkBitmap* bitmap, LegacyBitmapMode ) const {
- return as_IB(this)->onAsLegacyBitmap(bitmap);
- }
- sk_sp<SkCachedData> SkImage_Base::getPlanes(SkYUVASizeInfo*, SkYUVAIndex[4],
- SkYUVColorSpace*, const void*[4]) {
- return nullptr;
- }
- bool SkImage_Base::onAsLegacyBitmap(SkBitmap* bitmap) const {
- // As the base-class, all we can do is make a copy (regardless of mode).
- // Subclasses that want to be more optimal should override.
- SkImageInfo info = fInfo.makeColorType(kN32_SkColorType).makeColorSpace(nullptr);
- if (!bitmap->tryAllocPixels(info)) {
- return false;
- }
- if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), 0, 0)) {
- bitmap->reset();
- return false;
- }
- bitmap->setImmutable();
- return true;
- }
- sk_sp<SkImage> SkImage::MakeFromPicture(sk_sp<SkPicture> picture, const SkISize& dimensions,
- const SkMatrix* matrix, const SkPaint* paint,
- BitDepth bitDepth, sk_sp<SkColorSpace> colorSpace) {
- return MakeFromGenerator(SkImageGenerator::MakeFromPicture(dimensions, std::move(picture),
- matrix, paint, bitDepth,
- std::move(colorSpace)));
- }
- sk_sp<SkImage> SkImage::makeWithFilter(const SkImageFilter* filter, const SkIRect& subset,
- const SkIRect& clipBounds, SkIRect* outSubset,
- SkIPoint* offset) const {
- GrContext* context = as_IB(this)->context();
- return this->makeWithFilter(context, filter, subset, clipBounds, outSubset, offset);
- }
- sk_sp<SkImage> SkImage::makeWithFilter(GrContext* grContext,
- const SkImageFilter* filter, const SkIRect& subset,
- const SkIRect& clipBounds, SkIRect* outSubset,
- SkIPoint* offset) const {
- if (!filter || !outSubset || !offset || !this->bounds().contains(subset)) {
- return nullptr;
- }
- sk_sp<SkSpecialImage> srcSpecialImage =
- #if SK_SUPPORT_GPU
- SkSpecialImage::MakeFromImage(grContext, subset, sk_ref_sp(const_cast<SkImage*>(this)));
- #else
- SkSpecialImage::MakeFromImage(nullptr, subset, sk_ref_sp(const_cast<SkImage*>(this)));
- #endif
- if (!srcSpecialImage) {
- return nullptr;
- }
- sk_sp<SkImageFilterCache> cache(
- SkImageFilterCache::Create(SkImageFilterCache::kDefaultTransientSize));
- SkImageFilter::OutputProperties outputProperties(fInfo.colorType(), fInfo.colorSpace());
- // The filters operate in the local space of the src image, where (0,0) corresponds to the
- // subset's top left corner. But the clip bounds and any crop rects on the filters are in the
- // original coordinate system, so configure the CTM to correct crop rects and explicitly adjust
- // the clip bounds (since it is assumed to already be in image space).
- SkImageFilter::Context context(SkMatrix::MakeTrans(-subset.x(), -subset.y()),
- clipBounds.makeOffset(-subset.x(), -subset.y()),
- cache.get(), outputProperties);
- sk_sp<SkSpecialImage> result = filter->filterImage(srcSpecialImage.get(), context, offset);
- if (!result) {
- return nullptr;
- }
- // The output image and offset are relative to the subset rectangle, so the offset needs to
- // be shifted to put it in the correct spot with respect to the original coordinate system
- offset->fX += subset.x();
- offset->fY += subset.y();
- // Final clip against the exact clipBounds (the clip provided in the context gets adjusted
- // to account for pixel-moving filters so doesn't always exactly match when finished). The
- // clipBounds are translated into the clippedDstRect coordinate space, including the
- // result->subset() ensures that the result's image pixel origin does not affect results.
- SkIRect dstRect = result->subset();
- SkIRect clippedDstRect = dstRect;
- if (!clippedDstRect.intersect(clipBounds.makeOffset(result->subset().x() - offset->x(),
- result->subset().y() - offset->y()))) {
- return nullptr;
- }
- // Adjust the geometric offset if the top-left corner moved as well
- offset->fX += (clippedDstRect.x() - dstRect.x());
- offset->fY += (clippedDstRect.y() - dstRect.y());
- *outSubset = clippedDstRect;
- return result->asImage();
- }
- bool SkImage::isLazyGenerated() const {
- return as_IB(this)->onIsLazyGenerated();
- }
- bool SkImage::isAlphaOnly() const { return SkColorTypeIsAlphaOnly(fInfo.colorType()); }
- sk_sp<SkImage> SkImage::makeColorSpace(sk_sp<SkColorSpace> target) const {
- if (!target) {
- return nullptr;
- }
- // No need to create a new image if:
- // (1) The color spaces are equal.
- // (2) The color type is kAlpha8.
- SkColorSpace* colorSpace = this->colorSpace();
- if (!colorSpace) {
- colorSpace = sk_srgb_singleton();
- }
- if (SkColorSpace::Equals(colorSpace, target.get()) || this->isAlphaOnly()) {
- return sk_ref_sp(const_cast<SkImage*>(this));
- }
- // CONTEXT TODO: propagate the context parameter to the top-level API
- #if SK_SUPPORT_GPU
- return as_IB(this)->onMakeColorTypeAndColorSpace(as_IB(this)->context(),
- #else
- return as_IB(this)->onMakeColorTypeAndColorSpace(nullptr,
- #endif
- this->colorType(), std::move(target));
- }
- sk_sp<SkImage> SkImage::makeColorTypeAndColorSpace(SkColorType targetColorType,
- sk_sp<SkColorSpace> targetColorSpace) const {
- if (kUnknown_SkColorType == targetColorType || !targetColorSpace) {
- return nullptr;
- }
- SkColorType colorType = this->colorType();
- SkColorSpace* colorSpace = this->colorSpace();
- if (!colorSpace) {
- colorSpace = sk_srgb_singleton();
- }
- if (colorType == targetColorType &&
- (SkColorSpace::Equals(colorSpace, targetColorSpace.get()) || this->isAlphaOnly())) {
- return sk_ref_sp(const_cast<SkImage*>(this));
- }
- // CONTEXT TODO: propagate the context parameter to the top-level API
- #if SK_SUPPORT_GPU
- return as_IB(this)->onMakeColorTypeAndColorSpace(as_IB(this)->context(),
- #else
- return as_IB(this)->onMakeColorTypeAndColorSpace(nullptr,
- #endif
- targetColorType, std::move(targetColorSpace));
- }
- sk_sp<SkImage> SkImage::makeNonTextureImage() const {
- if (!this->isTextureBacked()) {
- return sk_ref_sp(const_cast<SkImage*>(this));
- }
- return this->makeRasterImage();
- }
- sk_sp<SkImage> SkImage::makeRasterImage() const {
- SkPixmap pm;
- if (this->peekPixels(&pm)) {
- return sk_ref_sp(const_cast<SkImage*>(this));
- }
- const size_t rowBytes = fInfo.minRowBytes();
- size_t size = fInfo.computeByteSize(rowBytes);
- if (SkImageInfo::ByteSizeOverflowed(size)) {
- return nullptr;
- }
- sk_sp<SkData> data = SkData::MakeUninitialized(size);
- pm = {fInfo.makeColorSpace(nullptr), data->writable_data(), fInfo.minRowBytes()};
- if (!this->readPixels(pm, 0, 0)) {
- return nullptr;
- }
- return SkImage::MakeRasterData(fInfo, std::move(data), rowBytes);
- }
- //////////////////////////////////////////////////////////////////////////////////////
- #if !SK_SUPPORT_GPU
- sk_sp<SkImage> SkImage::MakeFromTexture(GrContext* ctx,
- const GrBackendTexture& tex, GrSurfaceOrigin origin,
- SkColorType ct, SkAlphaType at, sk_sp<SkColorSpace> cs,
- TextureReleaseProc releaseP, ReleaseContext releaseC) {
- return nullptr;
- }
- bool SkImage::MakeBackendTextureFromSkImage(GrContext*,
- sk_sp<SkImage>,
- GrBackendTexture*,
- BackendTextureReleaseProc*) {
- return false;
- }
- sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrContext* ctx,
- const GrBackendTexture& tex, GrSurfaceOrigin origin,
- SkColorType ct, SkAlphaType at,
- sk_sp<SkColorSpace> cs) {
- return nullptr;
- }
- sk_sp<SkImage> SkImage::MakeFromYUVATexturesCopy(GrContext* context,
- SkYUVColorSpace yuvColorSpace,
- const GrBackendTexture yuvaTextures[],
- const SkYUVAIndex yuvaIndices[4],
- SkISize imageSize,
- GrSurfaceOrigin imageOrigin,
- sk_sp<SkColorSpace> imageColorSpace) {
- return nullptr;
- }
- sk_sp<SkImage> SkImage::MakeFromYUVATexturesCopyWithExternalBackend(
- GrContext* context,
- SkYUVColorSpace yuvColorSpace,
- const GrBackendTexture yuvaTextures[],
- const SkYUVAIndex yuvaIndices[4],
- SkISize imageSize,
- GrSurfaceOrigin imageOrigin,
- const GrBackendTexture& backendTexture,
- sk_sp<SkColorSpace> imageColorSpace) {
- return nullptr;
- }
- sk_sp<SkImage> SkImage::MakeFromYUVTexturesCopy(GrContext* ctx, SkYUVColorSpace space,
- const GrBackendTexture[3],
- GrSurfaceOrigin origin,
- sk_sp<SkColorSpace> imageColorSpace) {
- return nullptr;
- }
- sk_sp<SkImage> SkImage::MakeFromYUVTexturesCopyWithExternalBackend(
- GrContext* context, SkYUVColorSpace yuvColorSpace, const GrBackendTexture yuvTextures[3],
- GrSurfaceOrigin surfaceOrigin, const GrBackendTexture& backendTexture,
- sk_sp<SkColorSpace> colorSpace) {
- return nullptr;
- }
- sk_sp<SkImage> SkImage::MakeFromNV12TexturesCopy(GrContext* ctx, SkYUVColorSpace space,
- const GrBackendTexture[2],
- GrSurfaceOrigin origin,
- sk_sp<SkColorSpace> imageColorSpace) {
- return nullptr;
- }
- sk_sp<SkImage> SkImage::makeTextureImage(GrContext*, SkColorSpace* dstColorSpace,
- GrMipMapped mipMapped) const {
- return nullptr;
- }
- sk_sp<SkImage> MakeFromNV12TexturesCopyWithExternalBackend(GrContext* context,
- SkYUVColorSpace yuvColorSpace,
- const GrBackendTexture nv12Textures[2],
- GrSurfaceOrigin surfaceOrigin,
- const GrBackendTexture& backendTexture,
- sk_sp<SkColorSpace> colorSpace) {
- return nullptr;
- }
- #endif
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- bool SkImage_pinAsTexture(const SkImage* image, GrContext* ctx) {
- SkASSERT(image);
- SkASSERT(ctx);
- return as_IB(image)->onPinAsTexture(ctx);
- }
- void SkImage_unpinAsTexture(const SkImage* image, GrContext* ctx) {
- SkASSERT(image);
- SkASSERT(ctx);
- as_IB(image)->onUnpinAsTexture(ctx);
- }
- SkIRect SkImage_getSubset(const SkImage* image) {
- SkASSERT(image);
- return as_IB(image)->onGetSubset();
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- sk_sp<SkImage> SkImageMakeRasterCopyAndAssignColorSpace(const SkImage* src,
- SkColorSpace* colorSpace) {
- // Read the pixels out of the source image, with no conversion
- const SkImageInfo& info = src->imageInfo();
- if (kUnknown_SkColorType == info.colorType()) {
- SkDEBUGFAIL("Unexpected color type");
- return nullptr;
- }
- size_t rowBytes = info.minRowBytes();
- size_t size = info.computeByteSize(rowBytes);
- if (SkImageInfo::ByteSizeOverflowed(size)) {
- return nullptr;
- }
- auto data = SkData::MakeUninitialized(size);
- if (!data) {
- return nullptr;
- }
- SkPixmap pm(info, data->writable_data(), rowBytes);
- if (!src->readPixels(pm, 0, 0, SkImage::kDisallow_CachingHint)) {
- return nullptr;
- }
- // Wrap them in a new image with a different color space
- return SkImage::MakeRasterData(info.makeColorSpace(sk_ref_sp(colorSpace)), data, rowBytes);
- }
|