Flutter Engine
The Flutter Engine
SkCreateCGImageRef.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2011 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
9#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
10
13#include "include/core/SkData.h"
20
21#include <climits>
22#include <memory>
23
24static CGBitmapInfo compute_cgalpha_info_rgba(SkAlphaType at) {
25 CGBitmapInfo info = kCGBitmapByteOrder32Big;
26 switch (at) {
27 case kUnknown_SkAlphaType: break;
28 case kOpaque_SkAlphaType: info |= kCGImageAlphaNoneSkipLast; break;
29 case kPremul_SkAlphaType: info |= kCGImageAlphaPremultipliedLast; break;
30 case kUnpremul_SkAlphaType: info |= kCGImageAlphaLast; break;
31 }
32 return info;
33}
34
35static CGBitmapInfo compute_cgalpha_info_bgra(SkAlphaType at) {
36 CGBitmapInfo info = kCGBitmapByteOrder32Little;
37 switch (at) {
38 case kUnknown_SkAlphaType: break;
39 case kOpaque_SkAlphaType: info |= kCGImageAlphaNoneSkipFirst; break;
40 case kPremul_SkAlphaType: info |= kCGImageAlphaPremultipliedFirst; break;
41 case kUnpremul_SkAlphaType: info |= kCGImageAlphaFirst; break;
42 }
43 return info;
44}
45static CGBitmapInfo compute_cgalpha_info_4444(SkAlphaType at) {
46 CGBitmapInfo info = kCGBitmapByteOrder16Little;
47 switch (at) {
48 case kOpaque_SkAlphaType: info |= kCGImageAlphaNoneSkipLast; break;
49 default: info |= kCGImageAlphaPremultipliedLast; break;
50 }
51 return info;
52}
53
54static bool get_bitmap_info(SkColorType skColorType,
55 SkAlphaType skAlphaType,
56 size_t* bitsPerComponent,
57 CGBitmapInfo* info,
58 bool* upscaleTo32) {
59 if (upscaleTo32) {
60 *upscaleTo32 = false;
61 }
62 switch (skColorType) {
64 if (upscaleTo32) {
65 *upscaleTo32 = true;
66 }
67 // now treat like RGBA
68 *bitsPerComponent = 8;
69 *info = compute_cgalpha_info_rgba(kOpaque_SkAlphaType);
70 break;
72 *bitsPerComponent = 8;
73 *info = compute_cgalpha_info_rgba(skAlphaType);
74 break;
76 *bitsPerComponent = 8;
77 *info = compute_cgalpha_info_bgra(skAlphaType);
78 break;
80 *bitsPerComponent = 4;
81 *info = compute_cgalpha_info_4444(skAlphaType);
82 break;
83 default:
84 return false;
85 }
86 return true;
87}
88
89static std::unique_ptr<SkBitmap> prepare_for_image_ref(const SkBitmap& bm,
90 size_t* bitsPerComponent,
91 CGBitmapInfo* info) {
92 bool upscaleTo32;
93 if (!get_bitmap_info(bm.colorType(), bm.alphaType(), bitsPerComponent, info, &upscaleTo32)) {
94 return nullptr;
95 }
96 if (upscaleTo32) {
97 std::unique_ptr<SkBitmap> copy(new SkBitmap);
98 // here we make a deep copy of the pixels, since CG won't take our
99 // 565 directly, so we always go to RGBA
100 copy->allocPixels(bm.info().makeColorType(kRGBA_8888_SkColorType));
101 bm.readPixels(copy->info(), copy->getPixels(), copy->rowBytes(), 0, 0);
102 return copy;
103 }
104 return std::make_unique<SkBitmap>(bm);
105}
106
107CGImageRef SkCreateCGImageRefWithColorspace(const SkBitmap& bm,
108 CGColorSpaceRef colorSpace) {
109 return SkCreateCGImageRef(bm);
110}
111
112CGImageRef SkCreateCGImageRef(const SkBitmap& bm) {
113 if (bm.drawsNothing()) {
114 return nullptr;
115 }
116 size_t bitsPerComponent SK_INIT_TO_AVOID_WARNING;
117 CGBitmapInfo info SK_INIT_TO_AVOID_WARNING;
118
119 std::unique_ptr<SkBitmap> bitmap = prepare_for_image_ref(bm, &bitsPerComponent, &info);
120 if (nullptr == bitmap) {
121 return nullptr;
122 }
123
124 SkPixmap pm = bitmap->pixmap(); // Copy bitmap info before releasing it.
125 const size_t s = bitmap->computeByteSize();
126 void* pixels = bitmap->getPixels();
127
128 // our provider "owns" the bitmap*, and will take care of deleting it
129 SkUniqueCFRef<CGDataProviderRef> dataRef(CGDataProviderCreateWithData(
130 bitmap.release(), pixels, s,
131 [](void* p, const void*, size_t) { delete reinterpret_cast<SkBitmap*>(p); }));
132
133 SkUniqueCFRef<CGColorSpaceRef> colorSpace(SkCreateCGColorSpace(bm.colorSpace()));
134 return CGImageCreate(pm.width(),
135 pm.height(),
136 bitsPerComponent,
137 pm.info().bytesPerPixel() * CHAR_BIT,
138 pm.rowBytes(),
139 colorSpace.get(),
140 info,
141 dataRef.get(),
142 nullptr,
143 false,
144 kCGRenderingIntentDefault);
145}
146
147void SkCGDrawBitmap(CGContextRef cg, const SkBitmap& bm, float x, float y) {
148 SkUniqueCFRef<CGImageRef> img(SkCreateCGImageRef(bm));
149
150 if (img) {
151 CGRect r = CGRectMake(0, 0, bm.width(), bm.height());
152
153 CGContextSaveGState(cg);
154 CGContextTranslateCTM(cg, x, r.size.height + y);
155 CGContextScaleCTM(cg, 1, -1);
156
157 CGContextDrawImage(cg, r, img.get());
158
159 CGContextRestoreGState(cg);
160 }
161}
162
163///////////////////////////////////////////////////////////////////////////////////////////////////
164
165CGContextRef SkCreateCGContext(const SkPixmap& pmap) {
166 CGBitmapInfo cg_bitmap_info = 0;
167 size_t bitsPerComponent = 0;
168 switch (pmap.colorType()) {
170 bitsPerComponent = 8;
171 cg_bitmap_info = compute_cgalpha_info_rgba(pmap.alphaType());
172 break;
174 bitsPerComponent = 8;
175 cg_bitmap_info = compute_cgalpha_info_bgra(pmap.alphaType());
176 break;
177 default:
178 return nullptr; // no other colortypes are supported (for now)
179 }
180
181 size_t rb = pmap.addr() ? pmap.rowBytes() : 0;
182 SkUniqueCFRef<CGColorSpaceRef> cs(SkCreateCGColorSpace(pmap.colorSpace()));
183 CGContextRef cg = CGBitmapContextCreate(pmap.writable_addr(), pmap.width(), pmap.height(),
184 bitsPerComponent, rb, cs.get(), cg_bitmap_info);
185 return cg;
186}
187
188bool SkCopyPixelsFromCGImage(const SkImageInfo& info, size_t rowBytes, void* pixels,
189 CGImageRef image) {
190 CGBitmapInfo cg_bitmap_info = 0;
191 size_t bitsPerComponent = 0;
192 switch (info.colorType()) {
194 bitsPerComponent = 8;
195 cg_bitmap_info = compute_cgalpha_info_rgba(info.alphaType());
196 break;
198 bitsPerComponent = 8;
199 cg_bitmap_info = compute_cgalpha_info_bgra(info.alphaType());
200 break;
201 default:
202 return false; // no other colortypes are supported (for now)
203 }
204
205 SkUniqueCFRef<CGColorSpaceRef> cs(SkCreateCGColorSpace(info.colorSpace()));
206 SkUniqueCFRef<CGContextRef> cg(CGBitmapContextCreate(
207 pixels, info.width(), info.height(), bitsPerComponent,
208 rowBytes, cs.get(), cg_bitmap_info));
209 if (!cg) {
210 return false;
211 }
212
213 // use this blend mode, to avoid having to erase the pixels first, and to avoid CG performing
214 // any blending (which could introduce errors and be slower).
215 CGContextSetBlendMode(cg.get(), kCGBlendModeCopy);
216
217 CGContextDrawImage(cg.get(), CGRectMake(0, 0, info.width(), info.height()), image);
218 return true;
219}
220
221bool SkCreateBitmapFromCGImage(SkBitmap* dst, CGImageRef image) {
222 const int width = SkToInt(CGImageGetWidth(image));
223 const int height = SkToInt(CGImageGetHeight(image));
224 sk_sp<SkColorSpace> colorSpace(SkMakeColorSpaceFromCGColorSpace(CGImageGetColorSpace(image)));
226
227 SkBitmap tmp;
228 if (!tmp.tryAllocPixels(info)) {
229 return false;
230 }
231
232 if (!SkCopyPixelsFromCGImage(tmp.info(), tmp.rowBytes(), tmp.getPixels(), image)) {
233 return false;
234 }
235
236 CGImageAlphaInfo cgInfo = CGImageGetAlphaInfo(image);
237 switch (cgInfo) {
238 case kCGImageAlphaNone:
239 case kCGImageAlphaNoneSkipLast:
240 case kCGImageAlphaNoneSkipFirst:
243 break;
244 default:
245 // we don't know if we're opaque or not, so compute it.
246 if (SkBitmap::ComputeIsOpaque(tmp)) {
248 }
249 }
250
251 *dst = tmp;
252 return true;
253}
254
255sk_sp<SkImage> SkMakeImageFromCGImage(CGImageRef src) {
256 SkBitmap bm;
257 if (!SkCreateBitmapFromCGImage(&bm, src)) {
258 return nullptr;
259 }
260
261 bm.setImmutable();
262 return bm.asImage();
263}
264
265CGDataProviderRef SkCreateCGDataProvider(sk_sp<SkData> data) {
266 if (!data) {
267 return nullptr;
268 }
269
270 CGDataProviderRef result = CGDataProviderCreateWithData(
271 data.get(), data->data(), data->size(), [](void* info, const void*, size_t) {
272 reinterpret_cast<SkData*>(info)->unref();
273 });
274 if (!result) {
275 return nullptr;
276 }
277
278 // Retain `data` for the release that will come when `result` is freed.
279 data->ref();
280 return result;
281}
282
283sk_sp<SkColorSpace> SkMakeColorSpaceFromCGColorSpace(CGColorSpaceRef cgColorSpace) {
284 if (!cgColorSpace) {
285 return nullptr;
286 }
287
288 // Attempt to convert by name.
289 SkUniqueCFRef<CFStringRef> name(CGColorSpaceCopyName(cgColorSpace));
290 if (name && CFStringCompare(name.get(), kCGColorSpaceSRGB, 0) == kCFCompareEqualTo) {
291 return SkColorSpace::MakeSRGB();
292 }
293
294 // Attempt to convert by parsing the ICC profile.
295 SkUniqueCFRef<CFDataRef> iccData(CGColorSpaceCopyICCData(cgColorSpace));
296 if (!iccData) {
297 return nullptr;
298 }
299 skcms_ICCProfile iccProfile;
300 if (!skcms_Parse(
301 CFDataGetBytePtr(iccData.get()), CFDataGetLength(iccData.get()), &iccProfile)) {
302 return nullptr;
303 }
304 return SkColorSpace::Make(iccProfile);
305}
306
307CGColorSpaceRef SkCreateCGColorSpace(const SkColorSpace* space) {
308 // Initialize result to sRGB. We will use this as the fallback on failure.
309 CGColorSpaceRef cgSRGB = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
310
311 // Early-out of this is sRGB (or nullptr defaulting to sRGB).
312 if (!space || space->isSRGB()) {
313 return cgSRGB;
314 }
315
316 // Create an SkData with the ICC profile.
318 skcms_Matrix3x3 to_xyzd50;
319 space->transferFn(&fn);
320 space->toXYZD50(&to_xyzd50);
321 sk_sp<SkData> iccData = SkWriteICCProfile(fn, to_xyzd50);
322 if (!iccData) {
323 return cgSRGB;
324 }
325
326 // Create a CGColorSpaceRef from that ICC data.
327 const size_t kNumComponents = 3;
328 const CGFloat kComponentRanges[6] = {0, 1, 0, 1, 0, 1};
329 SkUniqueCFRef<CGDataProviderRef> iccDataProvider(SkCreateCGDataProvider(iccData));
330 CGColorSpaceRef result = CGColorSpaceCreateICCBased(
331 kNumComponents, kComponentRanges, iccDataProvider.get(), cgSRGB);
332 if (!result) {
333 return cgSRGB;
334 }
335
336 // We will not be returning |cgSRGB|, so free it now.
337 CFRelease(cgSRGB);
338 cgSRGB = nullptr;
339
340 return result;
341}
342
343#endif//defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
kUnpremul_SkAlphaType
SkAlphaType
Definition: SkAlphaType.h:26
@ kUnknown_SkAlphaType
uninitialized
Definition: SkAlphaType.h:27
@ kOpaque_SkAlphaType
pixel is opaque
Definition: SkAlphaType.h:28
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition: SkAlphaType.h:29
#define SkASSERT(cond)
Definition: SkAssert.h:116
SkColorType
Definition: SkColorType.h:19
@ kARGB_4444_SkColorType
pixel with 4 bits for alpha, red, green, blue; in 16-bit word
Definition: SkColorType.h:23
@ kBGRA_8888_SkColorType
pixel with 8 bits for blue, green, red, alpha; in 32-bit word
Definition: SkColorType.h:26
@ kRGB_565_SkColorType
pixel with 5 bits red, 6 bits green, 5 bits blue, in 16-bit word
Definition: SkColorType.h:22
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition: SkColorType.h:24
SK_API sk_sp< SkData > SkWriteICCProfile(const skcms_TransferFunction &, const skcms_Matrix3x3 &toXYZD50)
Definition: SkICC.cpp:682
#define SK_INIT_TO_AVOID_WARNING
Definition: SkMacros.h:58
static void copy(void *dst, const uint8_t *src, int width, int bpp, int deltaSrc, int offset, const SkPMColor ctable[])
Definition: SkSwizzler.cpp:31
constexpr int SkToInt(S x)
Definition: SkTo.h:29
SkColorSpace * colorSpace() const
Definition: SkBitmap.cpp:108
sk_sp< SkImage > asImage() const
Definition: SkBitmap.cpp:645
void setImmutable()
Definition: SkBitmap.cpp:400
SkAlphaType alphaType() const
Definition: SkBitmap.h:162
int width() const
Definition: SkBitmap.h:149
size_t rowBytes() const
Definition: SkBitmap.h:238
SkColorType colorType() const
Definition: SkBitmap.h:160
bool drawsNothing() const
Definition: SkBitmap.h:226
void * getPixels() const
Definition: SkBitmap.h:283
const SkImageInfo & info() const
Definition: SkBitmap.h:139
bool readPixels(const SkImageInfo &dstInfo, void *dstPixels, size_t dstRowBytes, int srcX, int srcY) const
Definition: SkBitmap.cpp:488
static bool ComputeIsOpaque(const SkBitmap &bm)
Definition: SkBitmap.h:358
bool setAlphaType(SkAlphaType alphaType)
Definition: SkBitmap.cpp:148
int height() const
Definition: SkBitmap.h:158
bool tryAllocPixels(const SkImageInfo &info, size_t rowBytes)
Definition: SkBitmap.cpp:271
bool toXYZD50(skcms_Matrix3x3 *toXYZD50) const
static sk_sp< SkColorSpace > MakeSRGB()
void transferFn(float gabcdef[7]) const
static sk_sp< SkColorSpace > Make(const skcms_ICCProfile &)
bool isSRGB() const
size_t rowBytes() const
Definition: SkPixmap.h:145
int width() const
Definition: SkPixmap.h:160
SkColorType colorType() const
Definition: SkPixmap.h:173
SkColorSpace * colorSpace() const
Definition: SkPixmap.cpp:61
const SkImageInfo & info() const
Definition: SkPixmap.h:135
void * writable_addr() const
Definition: SkPixmap.h:483
const void * addr() const
Definition: SkPixmap.h:153
int height() const
Definition: SkPixmap.h:166
SkAlphaType alphaType() const
Definition: SkPixmap.h:175
struct MyStruct s
GAsyncResult * result
double y
double x
sk_sp< const SkImage > image
Definition: SkRecords.h:269
Definition: bitmap.py:1
Definition: copy.py:1
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
dst
Definition: cp.py:12
int32_t height
int32_t width
static bool skcms_Parse(const void *buf, size_t len, skcms_ICCProfile *profile)
Definition: skcms_public.h:245
static SkImageInfo MakeN32Premul(int width, int height)
int bytesPerPixel() const
Definition: SkImageInfo.h:492
SkImageInfo makeColorType(SkColorType newColorType) const
Definition: SkImageInfo.h:475
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63