• 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 "include/core/SkImage.h"
9 
10 #include "include/core/SkBitmap.h"
11 #include "include/core/SkColorSpace.h"
12 #include "include/core/SkData.h"
13 #include "include/core/SkPixmap.h"
14 #include "include/core/SkTileMode.h"
15 #include "include/core/SkTypes.h"
16 #include "src/core/SkColorSpacePriv.h"
17 #include "src/core/SkImageInfoPriv.h"
18 #include "src/core/SkMipmap.h"
19 #include "src/core/SkNextID.h"
20 #include "src/image/SkImage_Base.h"
21 #include "src/shaders/SkImageShader.h"
22 
23 #include <utility>
24 
25 class SkShader;
26 
SkImage(const SkImageInfo & info,uint32_t uniqueID)27 SkImage::SkImage(const SkImageInfo& info, uint32_t uniqueID)
28         : fInfo(info)
29         , fUniqueID(kNeedNewImageUniqueID == uniqueID ? SkNextID::ImageID() : uniqueID) {
30     SkASSERT(info.width() > 0);
31     SkASSERT(info.height() > 0);
32 }
33 
peekPixels(SkPixmap * pm) const34 bool SkImage::peekPixels(SkPixmap* pm) const {
35     SkPixmap tmp;
36     if (!pm) {
37         pm = &tmp;
38     }
39     return as_IB(this)->onPeekPixels(pm);
40 }
41 
readPixels(GrDirectContext * dContext,const SkImageInfo & dstInfo,void * dstPixels,size_t dstRowBytes,int srcX,int srcY,CachingHint chint) const42 bool SkImage::readPixels(GrDirectContext* dContext, const SkImageInfo& dstInfo, void* dstPixels,
43                          size_t dstRowBytes, int srcX, int srcY, CachingHint chint) const {
44     return as_IB(this)->onReadPixels(dContext, dstInfo, dstPixels, dstRowBytes, srcX, srcY, chint);
45 }
46 
47 #ifndef SK_IMAGE_READ_PIXELS_DISABLE_LEGACY_API
readPixels(const SkImageInfo & dstInfo,void * dstPixels,size_t dstRowBytes,int srcX,int srcY,CachingHint chint) const48 bool SkImage::readPixels(const SkImageInfo& dstInfo, void* dstPixels,
49                          size_t dstRowBytes, int srcX, int srcY, CachingHint chint) const {
50     auto dContext = as_IB(this)->directContext();
51     return this->readPixels(dContext, dstInfo, dstPixels, dstRowBytes, srcX, srcY, chint);
52 }
53 #endif
54 
55 #if defined(GRAPHITE_TEST_UTILS)
readPixelsGraphite(skgpu::graphite::Recorder * recorder,const SkPixmap & dst,int srcX,int srcY) const56 bool SkImage::readPixelsGraphite(skgpu::graphite::Recorder* recorder,
57                                  const SkPixmap& dst,
58                                  int srcX,
59                                  int srcY) const {
60     return as_IB(this)->onReadPixelsGraphite(recorder, dst, srcX, srcY);
61 }
62 #endif
63 
asyncRescaleAndReadPixels(const SkImageInfo & info,const SkIRect & srcRect,RescaleGamma rescaleGamma,RescaleMode rescaleMode,ReadPixelsCallback callback,ReadPixelsContext context) const64 void SkImage::asyncRescaleAndReadPixels(const SkImageInfo& info,
65                                         const SkIRect& srcRect,
66                                         RescaleGamma rescaleGamma,
67                                         RescaleMode rescaleMode,
68                                         ReadPixelsCallback callback,
69                                         ReadPixelsContext context) const {
70     if (!SkIRect::MakeWH(this->width(), this->height()).contains(srcRect) ||
71         !SkImageInfoIsValid(info)) {
72         callback(context, nullptr);
73         return;
74     }
75     as_IB(this)->onAsyncRescaleAndReadPixels(
76             info, srcRect, rescaleGamma, rescaleMode, callback, context);
77 }
78 
asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,sk_sp<SkColorSpace> dstColorSpace,const SkIRect & srcRect,const SkISize & dstSize,RescaleGamma rescaleGamma,RescaleMode rescaleMode,ReadPixelsCallback callback,ReadPixelsContext context) const79 void SkImage::asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,
80                                               sk_sp<SkColorSpace> dstColorSpace,
81                                               const SkIRect& srcRect,
82                                               const SkISize& dstSize,
83                                               RescaleGamma rescaleGamma,
84                                               RescaleMode rescaleMode,
85                                               ReadPixelsCallback callback,
86                                               ReadPixelsContext context) const {
87     if (!SkIRect::MakeWH(this->width(), this->height()).contains(srcRect) || dstSize.isZero() ||
88         (dstSize.width() & 0b1) || (dstSize.height() & 0b1)) {
89         callback(context, nullptr);
90         return;
91     }
92     as_IB(this)->onAsyncRescaleAndReadPixelsYUV420(yuvColorSpace,
93                                                    /*readAlpha=*/false,
94                                                    std::move(dstColorSpace),
95                                                    srcRect,
96                                                    dstSize,
97                                                    rescaleGamma,
98                                                    rescaleMode,
99                                                    callback,
100                                                    context);
101 }
102 
asyncRescaleAndReadPixelsYUVA420(SkYUVColorSpace yuvColorSpace,sk_sp<SkColorSpace> dstColorSpace,const SkIRect & srcRect,const SkISize & dstSize,RescaleGamma rescaleGamma,RescaleMode rescaleMode,ReadPixelsCallback callback,ReadPixelsContext context) const103 void SkImage::asyncRescaleAndReadPixelsYUVA420(SkYUVColorSpace yuvColorSpace,
104                                                sk_sp<SkColorSpace> dstColorSpace,
105                                                const SkIRect& srcRect,
106                                                const SkISize& dstSize,
107                                                RescaleGamma rescaleGamma,
108                                                RescaleMode rescaleMode,
109                                                ReadPixelsCallback callback,
110                                                ReadPixelsContext context) const {
111     if (!SkIRect::MakeWH(this->width(), this->height()).contains(srcRect) || dstSize.isZero() ||
112         (dstSize.width() & 0b1) || (dstSize.height() & 0b1)) {
113         callback(context, nullptr);
114         return;
115     }
116     as_IB(this)->onAsyncRescaleAndReadPixelsYUV420(yuvColorSpace,
117                                                    /*readAlpha=*/true,
118                                                    std::move(dstColorSpace),
119                                                    srcRect,
120                                                    dstSize,
121                                                    rescaleGamma,
122                                                    rescaleMode,
123                                                    callback,
124                                                    context);
125 }
126 
scalePixels(const SkPixmap & dst,const SkSamplingOptions & sampling,CachingHint chint) const127 bool SkImage::scalePixels(const SkPixmap& dst, const SkSamplingOptions& sampling,
128                           CachingHint chint) const {
129     // Context TODO: Elevate GrDirectContext requirement to public API.
130     auto dContext = as_IB(this)->directContext();
131     if (this->width() == dst.width() && this->height() == dst.height()) {
132         return this->readPixels(dContext, dst, 0, 0, chint);
133     }
134 
135     // Idea: If/when SkImageGenerator supports a native-scaling API (where the generator itself
136     //       can scale more efficiently) we should take advantage of it here.
137     //
138     SkBitmap bm;
139     if (as_IB(this)->getROPixels(dContext, &bm, chint)) {
140         SkPixmap pmap;
141         // Note: By calling the pixmap scaler, we never cache the final result, so the chint
142         //       is (currently) only being applied to the getROPixels. If we get a request to
143         //       also attempt to cache the final (scaled) result, we would add that logic here.
144         //
145         return bm.peekPixels(&pmap) && pmap.scalePixels(dst, sampling);
146     }
147     return false;
148 }
149 
150 ///////////////////////////////////////////////////////////////////////////////////////////////////
151 
colorType() const152 SkColorType SkImage::colorType() const { return fInfo.colorType(); }
153 
alphaType() const154 SkAlphaType SkImage::alphaType() const { return fInfo.alphaType(); }
155 
colorSpace() const156 SkColorSpace* SkImage::colorSpace() const { return fInfo.colorSpace(); }
157 
refColorSpace() const158 sk_sp<SkColorSpace> SkImage::refColorSpace() const { return fInfo.refColorSpace(); }
159 
makeShader(const SkSamplingOptions & sampling,const SkMatrix & lm) const160 sk_sp<SkShader> SkImage::makeShader(const SkSamplingOptions& sampling, const SkMatrix& lm) const {
161     return SkImageShader::Make(sk_ref_sp(const_cast<SkImage*>(this)),
162                                SkTileMode::kClamp, SkTileMode::kClamp,
163                                sampling, &lm);
164 }
165 
makeShader(const SkSamplingOptions & sampling,const SkMatrix * lm) const166 sk_sp<SkShader> SkImage::makeShader(const SkSamplingOptions& sampling, const SkMatrix* lm) const {
167     return SkImageShader::Make(sk_ref_sp(const_cast<SkImage*>(this)),
168                                SkTileMode::kClamp, SkTileMode::kClamp,
169                                sampling, lm);
170 }
171 
makeShader(SkTileMode tmx,SkTileMode tmy,const SkSamplingOptions & sampling,const SkMatrix & lm) const172 sk_sp<SkShader> SkImage::makeShader(SkTileMode tmx, SkTileMode tmy,
173                                     const SkSamplingOptions& sampling,
174                                     const SkMatrix& lm) const {
175     return SkImageShader::Make(sk_ref_sp(const_cast<SkImage*>(this)), tmx, tmy,
176                                sampling, &lm);
177 }
178 
makeShader(SkTileMode tmx,SkTileMode tmy,const SkSamplingOptions & sampling,const SkMatrix * localMatrix) const179 sk_sp<SkShader> SkImage::makeShader(SkTileMode tmx, SkTileMode tmy,
180                                     const SkSamplingOptions& sampling,
181                                     const SkMatrix* localMatrix) const {
182     return SkImageShader::Make(sk_ref_sp(const_cast<SkImage*>(this)), tmx, tmy,
183                                sampling, localMatrix);
184 }
185 
makeRawShader(SkTileMode tmx,SkTileMode tmy,const SkSamplingOptions & sampling,const SkMatrix & lm) const186 sk_sp<SkShader> SkImage::makeRawShader(SkTileMode tmx, SkTileMode tmy,
187                                        const SkSamplingOptions& sampling,
188                                        const SkMatrix& lm) const {
189     return SkImageShader::MakeRaw(sk_ref_sp(const_cast<SkImage*>(this)), tmx, tmy,
190                                   sampling, &lm);
191 }
192 
makeRawShader(const SkSamplingOptions & sampling,const SkMatrix & lm) const193 sk_sp<SkShader> SkImage::makeRawShader(const SkSamplingOptions& sampling,
194                                        const SkMatrix& lm) const {
195     return SkImageShader::MakeRaw(sk_ref_sp(const_cast<SkImage*>(this)),
196                                   SkTileMode::kClamp, SkTileMode::kClamp,
197                                   sampling, &lm);
198 }
199 
makeRawShader(const SkSamplingOptions & sampling,const SkMatrix * localMatrix) const200 sk_sp<SkShader> SkImage::makeRawShader(const SkSamplingOptions& sampling,
201                                        const SkMatrix* localMatrix) const {
202     return SkImageShader::MakeRaw(sk_ref_sp(const_cast<SkImage*>(this)),
203                                   SkTileMode::kClamp, SkTileMode::kClamp,
204                                   sampling, localMatrix);
205 }
206 
makeRawShader(SkTileMode tmx,SkTileMode tmy,const SkSamplingOptions & sampling,const SkMatrix * localMatrix) const207 sk_sp<SkShader> SkImage::makeRawShader(SkTileMode tmx, SkTileMode tmy,
208                                        const SkSamplingOptions& sampling,
209                                        const SkMatrix* localMatrix) const {
210     return SkImageShader::MakeRaw(sk_ref_sp(const_cast<SkImage*>(this)), tmx, tmy,
211                                   sampling, localMatrix);
212 }
213 
refEncodedData() const214 sk_sp<SkData> SkImage::refEncodedData() const {
215     return sk_sp<SkData>(as_IB(this)->onRefEncoded());
216 }
217 
218 ///////////////////////////////////////////////////////////////////////////////////////////////////
219 
readPixels(GrDirectContext * dContext,const SkPixmap & pmap,int srcX,int srcY,CachingHint chint) const220 bool SkImage::readPixels(GrDirectContext* dContext, const SkPixmap& pmap, int srcX, int srcY,
221                          CachingHint chint) const {
222     return this->readPixels(dContext, pmap.info(), pmap.writable_addr(), pmap.rowBytes(), srcX,
223                             srcY, chint);
224 }
225 
226 #ifndef SK_IMAGE_READ_PIXELS_DISABLE_LEGACY_API
readPixels(const SkPixmap & pmap,int srcX,int srcY,CachingHint chint) const227 bool SkImage::readPixels(const SkPixmap& pmap, int srcX, int srcY, CachingHint chint) const {
228     auto dContext = as_IB(this)->directContext();
229     return this->readPixels(dContext, pmap, srcX, srcY, chint);
230 }
231 #endif
232 
asLegacyBitmap(SkBitmap * bitmap,LegacyBitmapMode) const233 bool SkImage::asLegacyBitmap(SkBitmap* bitmap, LegacyBitmapMode ) const {
234     // Context TODO: Elevate GrDirectContext requirement to public API.
235     auto dContext = as_IB(this)->directContext();
236     return as_IB(this)->onAsLegacyBitmap(dContext, bitmap);
237 }
238 
isAlphaOnly() const239 bool SkImage::isAlphaOnly() const { return SkColorTypeIsAlphaOnly(fInfo.colorType()); }
240 
reinterpretColorSpace(sk_sp<SkColorSpace> target) const241 sk_sp<SkImage> SkImage::reinterpretColorSpace(sk_sp<SkColorSpace> target) const {
242     if (!target) {
243         return nullptr;
244     }
245 
246     // No need to create a new image if:
247     // (1) The color spaces are equal.
248     // (2) The color type is kAlpha8.
249     SkColorSpace* colorSpace = this->colorSpace();
250     if (!colorSpace) {
251         colorSpace = sk_srgb_singleton();
252     }
253     if (SkColorSpace::Equals(colorSpace, target.get()) || this->isAlphaOnly()) {
254         return sk_ref_sp(const_cast<SkImage*>(this));
255     }
256 
257     return as_IB(this)->onReinterpretColorSpace(std::move(target));
258 }
259 
makeNonTextureImage(GrDirectContext * dContext) const260 sk_sp<SkImage> SkImage::makeNonTextureImage(GrDirectContext* dContext) const {
261     if (!this->isTextureBacked()) {
262         return sk_ref_sp(const_cast<SkImage*>(this));
263     }
264     return this->makeRasterImage(dContext, kDisallow_CachingHint);
265 }
266 
makeRasterImage(GrDirectContext * dContext,CachingHint chint) const267 sk_sp<SkImage> SkImage::makeRasterImage(GrDirectContext* dContext, CachingHint chint) const {
268     SkPixmap pm;
269     if (this->peekPixels(&pm)) {
270         return sk_ref_sp(const_cast<SkImage*>(this));
271     }
272 
273     const size_t rowBytes = fInfo.minRowBytes();
274     size_t size = fInfo.computeByteSize(rowBytes);
275     if (SkImageInfo::ByteSizeOverflowed(size)) {
276         return nullptr;
277     }
278 
279     if (!dContext) {
280         // Try to get the saved context if the client didn't pass it in (but they really should).
281         dContext = as_IB(this)->directContext();
282     }
283     sk_sp<SkData> data = SkData::MakeUninitialized(size);
284     pm = {fInfo.makeColorSpace(nullptr), data->writable_data(), fInfo.minRowBytes()};
285     if (!this->readPixels(dContext, pm, 0, 0, chint)) {
286         return nullptr;
287     }
288 
289     return SkImages::RasterFromData(fInfo, std::move(data), rowBytes);
290 }
291 
hasMipmaps() const292 bool SkImage::hasMipmaps() const { return as_IB(this)->onHasMipmaps(); }
293 
isProtected() const294 bool SkImage::isProtected() const { return as_IB(this)->onIsProtected(); }
295 
withMipmaps(sk_sp<SkMipmap> mips) const296 sk_sp<SkImage> SkImage::withMipmaps(sk_sp<SkMipmap> mips) const {
297     if (mips == nullptr || mips->validForRootLevel(this->imageInfo())) {
298         if (auto result = as_IB(this)->onMakeWithMipmaps(std::move(mips))) {
299             return result;
300         }
301     }
302     return sk_ref_sp((const_cast<SkImage*>(this)));
303 }
304 
withDefaultMipmaps() const305 sk_sp<SkImage> SkImage::withDefaultMipmaps() const {
306     return this->withMipmaps(nullptr);
307 }
308