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