• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
SkImage(int width,int height,uint32_t uniqueID)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 
peekPixels(SkPixmap * pm) const45 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 
readPixels(const SkImageInfo & dstInfo,void * dstPixels,size_t dstRowBytes,int srcX,int srcY,CachingHint chint) const53 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 
scalePixels(const SkPixmap & dst,SkFilterQuality quality,CachingHint chint) const58 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 
alphaType() const80 SkAlphaType SkImage::alphaType() const {
81     return as_IB(this)->onAlphaType();
82 }
83 
colorSpace() const84 SkColorSpace* SkImage::colorSpace() const {
85     return as_IB(this)->onImageInfo().colorSpace();
86 }
87 
refColorSpace() const88 sk_sp<SkColorSpace> SkImage::refColorSpace() const {
89     return as_IB(this)->onImageInfo().refColorSpace();
90 }
91 
makeShader(SkShader::TileMode tileX,SkShader::TileMode tileY,const SkMatrix * localMatrix) const92 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 
encodeToData(SkEncodedImageFormat type,int quality) const97 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 
encodeToData(SkPixelSerializer * serializer) const107 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 
refEncodedData() const130 sk_sp<SkData> SkImage::refEncodedData() const {
131     return sk_sp<SkData>(as_IB(this)->onRefEncoded());
132 }
133 
MakeFromEncoded(sk_sp<SkData> encoded,const SkIRect * subset)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 
toString(SkString * str) const143 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 
makeSubset(const SkIRect & subset) const149 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 
getTexture() const168 GrTexture* SkImage::getTexture() const {
169     return as_IB(this)->onGetTexture();
170 }
171 
isTextureBacked() const172 bool SkImage::isTextureBacked() const { return SkToBool(as_IB(this)->peekProxy()); }
173 
getTextureHandle(bool flushPendingGrContextIO,GrSurfaceOrigin * origin) const174 GrBackendObject SkImage::getTextureHandle(bool flushPendingGrContextIO,
175                                           GrSurfaceOrigin* origin) const {
176     return as_IB(this)->onGetTextureHandle(flushPendingGrContextIO, origin);
177 }
178 
isValid(GrContext * context) const179 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 
getTexture() const188 GrTexture* SkImage::getTexture() const { return nullptr; }
189 
isTextureBacked() const190 bool SkImage::isTextureBacked() const { return false; }
191 
getTextureHandle(bool,GrSurfaceOrigin *) const192 GrBackendObject SkImage::getTextureHandle(bool, GrSurfaceOrigin*) const { return 0; }
193 
isValid(GrContext * context) const194 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 
SkImage_Base(int width,int height,uint32_t uniqueID)205 SkImage_Base::SkImage_Base(int width, int height, uint32_t uniqueID)
206     : INHERITED(width, height, uniqueID)
207     , fAddedToCache(false)
208 {}
209 
~SkImage_Base()210 SkImage_Base::~SkImage_Base() {
211     if (fAddedToCache.load()) {
212         SkNotifyBitmapGenIDIsStale(this->uniqueID());
213     }
214 }
215 
readPixels(const SkPixmap & pmap,int srcX,int srcY,CachingHint chint) const216 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 
MakeFromBitmap(const SkBitmap & bm)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 
asLegacyBitmap(SkBitmap * bitmap,LegacyBitmapMode mode) const231 bool SkImage::asLegacyBitmap(SkBitmap* bitmap, LegacyBitmapMode mode) const {
232     return as_IB(this)->onAsLegacyBitmap(bitmap, mode);
233 }
234 
onAsLegacyBitmap(SkBitmap * bitmap,LegacyBitmapMode mode) const235 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 
MakeFromPicture(sk_sp<SkPicture> picture,const SkISize & dimensions,const SkMatrix * matrix,const SkPaint * paint,BitDepth bitDepth,sk_sp<SkColorSpace> colorSpace)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 
makeWithFilter(const SkImageFilter * filter,const SkIRect & subset,const SkIRect & clipBounds,SkIRect * outSubset,SkIPoint * offset) const261 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 
isLazyGenerated() const296 bool SkImage::isLazyGenerated() const {
297     return as_IB(this)->onIsLazyGenerated();
298 }
299 
isAlphaOnly() const300 bool SkImage::isAlphaOnly() const {
301     return as_IB(this)->onImageInfo().colorType() == kAlpha_8_SkColorType;
302 }
303 
makeColorSpace(sk_sp<SkColorSpace> target,SkTransferFunctionBehavior premulBehavior) const304 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 
MakeTextureFromMipMap(GrContext *,const SkImageInfo &,const GrMipLevel texels[],int mipLevelCount,SkBudgeted,SkDestinationSurfaceColorMode)332 sk_sp<SkImage> MakeTextureFromMipMap(GrContext*, const SkImageInfo&, const GrMipLevel texels[],
333                                      int mipLevelCount, SkBudgeted, SkDestinationSurfaceColorMode) {
334     return nullptr;
335 }
336 
MakeFromTexture(GrContext *,const GrBackendTextureDesc &,SkAlphaType,sk_sp<SkColorSpace>,TextureReleaseProc,ReleaseContext)337 sk_sp<SkImage> SkImage::MakeFromTexture(GrContext*, const GrBackendTextureDesc&, SkAlphaType,
338                                         sk_sp<SkColorSpace>, TextureReleaseProc, ReleaseContext) {
339     return nullptr;
340 }
341 
MakeFromTexture(GrContext * ctx,const GrBackendTexture & tex,GrSurfaceOrigin origin,SkAlphaType at,sk_sp<SkColorSpace> cs,TextureReleaseProc releaseP,ReleaseContext releaseC)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 
getDeferredTextureImageData(const GrContextThreadSafeProxy &,const DeferredTextureImageUsageParams[],int paramCnt,void * buffer,SkColorSpace * dstColorSpace,SkColorType dstColorType) const349 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 
MakeFromDeferredTextureImageData(GrContext * context,const void *,SkBudgeted)357 sk_sp<SkImage> SkImage::MakeFromDeferredTextureImageData(GrContext* context, const void*,
358                                                          SkBudgeted) {
359     return nullptr;
360 }
361 
MakeFromAdoptedTexture(GrContext *,const GrBackendTextureDesc &,SkAlphaType,sk_sp<SkColorSpace>)362 sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrContext*, const GrBackendTextureDesc&,
363                                                SkAlphaType, sk_sp<SkColorSpace>) {
364     return nullptr;
365 }
366 
MakeFromAdoptedTexture(GrContext * ctx,const GrBackendTexture & tex,GrSurfaceOrigin origin,SkAlphaType at,sk_sp<SkColorSpace> cs)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 
MakeFromYUVTexturesCopy(GrContext * ctx,SkYUVColorSpace space,const GrBackendObject yuvTextureHandles[3],const SkISize yuvSizes[3],GrSurfaceOrigin origin,sk_sp<SkColorSpace> imageColorSpace)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 
makeTextureImage(GrContext *,SkColorSpace * dstColorSpace) const381 sk_sp<SkImage> SkImage::makeTextureImage(GrContext*, SkColorSpace* dstColorSpace) const {
382     return nullptr;
383 }
384 
makeNonTextureImage() const385 sk_sp<SkImage> SkImage::makeNonTextureImage() const {
386     return sk_ref_sp(const_cast<SkImage*>(this));
387 }
388 
389 #endif
390 
391 ///////////////////////////////////////////////////////////////////////////////////////////////////
392 
MakeTextureFromMipMap(GrContext *,const SkImageInfo &,const GrMipLevel texels[],int mipLevelCount,SkBudgeted)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 
makeFromData(SkData * data,const SkIRect * subset)401 sk_sp<SkImage> SkImageDeserializer::makeFromData(SkData* data, const SkIRect* subset) {
402     return SkImage::MakeFromEncoded(sk_ref_sp(data), subset);
403 }
makeFromMemory(const void * data,size_t length,const SkIRect * subset)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 
SkImage_pinAsTexture(const SkImage * image,GrContext * ctx)411 bool SkImage_pinAsTexture(const SkImage* image, GrContext* ctx) {
412     SkASSERT(image);
413     SkASSERT(ctx);
414     return as_IB(image)->onPinAsTexture(ctx);
415 }
416 
SkImage_unpinAsTexture(const SkImage * image,GrContext * ctx)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 
SkImageMakeRasterCopyAndAssignColorSpace(const SkImage * src,SkColorSpace * colorSpace)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