2 * Copyright 2011 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #include "include/core/SkTypes.h"
9 #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
11 #include "include/core/SkBitmap.h"
12 #include "include/private/SkColorData.h"
13 #include "include/private/SkMacros.h"
14 #include "include/private/SkTo.h"
15 #include "include/utils/mac/SkCGUtils.h"
16 #include "src/utils/mac/SkUniqueCFRef.h"
21 static CGBitmapInfo compute_cgalpha_info_rgba(SkAlphaType at) {
22 CGBitmapInfo info = kCGBitmapByteOrder32Big;
24 case kUnknown_SkAlphaType: break;
25 case kOpaque_SkAlphaType: info |= kCGImageAlphaNoneSkipLast; break;
26 case kPremul_SkAlphaType: info |= kCGImageAlphaPremultipliedLast; break;
27 case kUnpremul_SkAlphaType: info |= kCGImageAlphaLast; break;
32 static CGBitmapInfo compute_cgalpha_info_bgra(SkAlphaType at) {
33 CGBitmapInfo info = kCGBitmapByteOrder32Little;
35 case kUnknown_SkAlphaType: break;
36 case kOpaque_SkAlphaType: info |= kCGImageAlphaNoneSkipFirst; break;
37 case kPremul_SkAlphaType: info |= kCGImageAlphaPremultipliedFirst; break;
38 case kUnpremul_SkAlphaType: info |= kCGImageAlphaFirst; break;
42 static CGBitmapInfo compute_cgalpha_info_4444(SkAlphaType at) {
43 CGBitmapInfo info = kCGBitmapByteOrder16Little;
45 case kOpaque_SkAlphaType: info |= kCGImageAlphaNoneSkipLast; break;
46 default: info |= kCGImageAlphaPremultipliedLast; break;
51 static bool get_bitmap_info(SkColorType skColorType,
52 SkAlphaType skAlphaType,
53 size_t* bitsPerComponent,
59 switch (skColorType) {
60 case kRGB_565_SkColorType:
64 // now treat like RGBA
65 *bitsPerComponent = 8;
66 *info = compute_cgalpha_info_rgba(kOpaque_SkAlphaType);
68 case kRGBA_8888_SkColorType:
69 *bitsPerComponent = 8;
70 *info = compute_cgalpha_info_rgba(skAlphaType);
72 case kBGRA_8888_SkColorType:
73 *bitsPerComponent = 8;
74 *info = compute_cgalpha_info_bgra(skAlphaType);
76 case kARGB_4444_SkColorType:
77 *bitsPerComponent = 4;
78 *info = compute_cgalpha_info_4444(skAlphaType);
86 static std::unique_ptr<SkBitmap> prepare_for_image_ref(const SkBitmap& bm,
87 size_t* bitsPerComponent,
90 if (!get_bitmap_info(bm.colorType(), bm.alphaType(), bitsPerComponent, info, &upscaleTo32)) {
94 std::unique_ptr<SkBitmap> copy(new SkBitmap);
95 // here we make a deep copy of the pixels, since CG won't take our
96 // 565 directly, so we always go to RGBA
97 copy->allocPixels(bm.info().makeColorType(kRGBA_8888_SkColorType));
98 bm.readPixels(copy->info(), copy->getPixels(), copy->rowBytes(), 0, 0);
101 return std::make_unique<SkBitmap>(bm);
104 CGImageRef SkCreateCGImageRefWithColorspace(const SkBitmap& bm,
105 CGColorSpaceRef colorSpace) {
106 if (bm.drawsNothing()) {
109 size_t bitsPerComponent SK_INIT_TO_AVOID_WARNING;
110 CGBitmapInfo info SK_INIT_TO_AVOID_WARNING;
112 std::unique_ptr<SkBitmap> bitmap = prepare_for_image_ref(bm, &bitsPerComponent, &info);
113 if (nullptr == bitmap) {
117 SkPixmap pm = bitmap->pixmap(); // Copy bitmap info before releasing it.
118 const size_t s = bitmap->computeByteSize();
119 void* pixels = bitmap->getPixels();
121 // our provider "owns" the bitmap*, and will take care of deleting it
122 SkUniqueCFRef<CGDataProviderRef> dataRef(CGDataProviderCreateWithData(
123 bitmap.release(), pixels, s,
124 [](void* p, const void*, size_t) { delete reinterpret_cast<SkBitmap*>(p); }));
126 SkUniqueCFRef<CGColorSpaceRef> rgb;
127 if (nullptr == colorSpace) {
128 rgb.reset(CGColorSpaceCreateDeviceRGB());
129 colorSpace = rgb.get();
131 return CGImageCreate(pm.width(), pm.height(), bitsPerComponent,
132 pm.info().bytesPerPixel() * CHAR_BIT, pm.rowBytes(), colorSpace,
133 info, dataRef.get(), nullptr, false, kCGRenderingIntentDefault);
136 void SkCGDrawBitmap(CGContextRef cg, const SkBitmap& bm, float x, float y) {
137 SkUniqueCFRef<CGImageRef> img(SkCreateCGImageRef(bm));
140 CGRect r = CGRectMake(0, 0, bm.width(), bm.height());
142 CGContextSaveGState(cg);
143 CGContextTranslateCTM(cg, x, r.size.height + y);
144 CGContextScaleCTM(cg, 1, -1);
146 CGContextDrawImage(cg, r, img.get());
148 CGContextRestoreGState(cg);
152 ///////////////////////////////////////////////////////////////////////////////////////////////////
154 CGContextRef SkCreateCGContext(const SkPixmap& pmap) {
155 CGBitmapInfo cg_bitmap_info = 0;
156 size_t bitsPerComponent = 0;
157 switch (pmap.colorType()) {
158 case kRGBA_8888_SkColorType:
159 bitsPerComponent = 8;
160 cg_bitmap_info = compute_cgalpha_info_rgba(pmap.alphaType());
162 case kBGRA_8888_SkColorType:
163 bitsPerComponent = 8;
164 cg_bitmap_info = compute_cgalpha_info_bgra(pmap.alphaType());
167 return nullptr; // no other colortypes are supported (for now)
170 size_t rb = pmap.addr() ? pmap.rowBytes() : 0;
171 SkUniqueCFRef<CGColorSpaceRef> cs(CGColorSpaceCreateDeviceRGB());
172 CGContextRef cg = CGBitmapContextCreate(pmap.writable_addr(), pmap.width(), pmap.height(),
173 bitsPerComponent, rb, cs.get(), cg_bitmap_info);
177 bool SkCopyPixelsFromCGImage(const SkImageInfo& info, size_t rowBytes, void* pixels,
179 CGBitmapInfo cg_bitmap_info = 0;
180 size_t bitsPerComponent = 0;
181 switch (info.colorType()) {
182 case kRGBA_8888_SkColorType:
183 bitsPerComponent = 8;
184 cg_bitmap_info = compute_cgalpha_info_rgba(info.alphaType());
186 case kBGRA_8888_SkColorType:
187 bitsPerComponent = 8;
188 cg_bitmap_info = compute_cgalpha_info_bgra(info.alphaType());
191 return false; // no other colortypes are supported (for now)
194 SkUniqueCFRef<CGColorSpaceRef> cs(CGColorSpaceCreateDeviceRGB());
195 SkUniqueCFRef<CGContextRef> cg(CGBitmapContextCreate(
196 pixels, info.width(), info.height(), bitsPerComponent,
197 rowBytes, cs.get(), cg_bitmap_info));
202 // use this blend mode, to avoid having to erase the pixels first, and to avoid CG performing
203 // any blending (which could introduce errors and be slower).
204 CGContextSetBlendMode(cg.get(), kCGBlendModeCopy);
206 CGContextDrawImage(cg.get(), CGRectMake(0, 0, info.width(), info.height()), image);
210 bool SkCreateBitmapFromCGImage(SkBitmap* dst, CGImageRef image) {
211 const int width = SkToInt(CGImageGetWidth(image));
212 const int height = SkToInt(CGImageGetHeight(image));
213 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
216 if (!tmp.tryAllocPixels(info)) {
220 if (!SkCopyPixelsFromCGImage(tmp.info(), tmp.rowBytes(), tmp.getPixels(), image)) {
224 CGImageAlphaInfo cgInfo = CGImageGetAlphaInfo(image);
226 case kCGImageAlphaNone:
227 case kCGImageAlphaNoneSkipLast:
228 case kCGImageAlphaNoneSkipFirst:
229 SkASSERT(SkBitmap::ComputeIsOpaque(tmp));
230 tmp.setAlphaType(kOpaque_SkAlphaType);
233 // we don't know if we're opaque or not, so compute it.
234 if (SkBitmap::ComputeIsOpaque(tmp)) {
235 tmp.setAlphaType(kOpaque_SkAlphaType);
243 sk_sp<SkImage> SkMakeImageFromCGImage(CGImageRef src) {
245 if (!SkCreateBitmapFromCGImage(&bm, src)) {
253 #endif//defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)