• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
8 #include "SkTypes.h"
9 #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
10 
11 #include "SkCGUtils.h"
12 #include "SkBitmap.h"
13 #include "SkColorPriv.h"
14 
ComputeCGAlphaInfo_RGBA(SkAlphaType at)15 static CGBitmapInfo ComputeCGAlphaInfo_RGBA(SkAlphaType at) {
16     CGBitmapInfo info = kCGBitmapByteOrder32Big;
17     switch (at) {
18         case kUnknown_SkAlphaType:
19             break;
20         case kOpaque_SkAlphaType:
21             info |= kCGImageAlphaNoneSkipLast;
22             break;
23         case kPremul_SkAlphaType:
24             info |= kCGImageAlphaPremultipliedLast;
25             break;
26         case kUnpremul_SkAlphaType:
27             info |= kCGImageAlphaLast;
28             break;
29     }
30     return info;
31 }
32 
ComputeCGAlphaInfo_BGRA(SkAlphaType at)33 static CGBitmapInfo ComputeCGAlphaInfo_BGRA(SkAlphaType at) {
34     CGBitmapInfo info = kCGBitmapByteOrder32Little;
35     switch (at) {
36         case kUnknown_SkAlphaType:
37             break;
38         case kOpaque_SkAlphaType:
39             info |= kCGImageAlphaNoneSkipFirst;
40             break;
41         case kPremul_SkAlphaType:
42             info |= kCGImageAlphaPremultipliedFirst;
43             break;
44         case kUnpremul_SkAlphaType:
45             info |= kCGImageAlphaFirst;
46             break;
47     }
48     return info;
49 }
50 
SkBitmap_ReleaseInfo(void * info,const void * pixelData,size_t size)51 static void SkBitmap_ReleaseInfo(void* info, const void* pixelData, size_t size) {
52     SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(info);
53     delete bitmap;
54 }
55 
getBitmapInfo(const SkBitmap & bm,size_t * bitsPerComponent,CGBitmapInfo * info,bool * upscaleTo32)56 static bool getBitmapInfo(const SkBitmap& bm,
57                           size_t* bitsPerComponent,
58                           CGBitmapInfo* info,
59                           bool* upscaleTo32) {
60     if (upscaleTo32) {
61         *upscaleTo32 = false;
62     }
63 
64     switch (bm.colorType()) {
65         case kRGB_565_SkColorType:
66 #if 0
67             // doesn't see quite right. Are they thinking 1555?
68             *bitsPerComponent = 5;
69             *info = kCGBitmapByteOrder16Little | kCGImageAlphaNone;
70 #else
71             if (upscaleTo32) {
72                 *upscaleTo32 = true;
73             }
74             // now treat like RGBA
75             *bitsPerComponent = 8;
76             *info = ComputeCGAlphaInfo_RGBA(kOpaque_SkAlphaType);
77 #endif
78             break;
79         case kRGBA_8888_SkColorType:
80             *bitsPerComponent = 8;
81             *info = ComputeCGAlphaInfo_RGBA(bm.alphaType());
82             break;
83         case kBGRA_8888_SkColorType:
84             *bitsPerComponent = 8;
85             *info = ComputeCGAlphaInfo_BGRA(bm.alphaType());
86             break;
87         case kARGB_4444_SkColorType:
88             *bitsPerComponent = 4;
89             *info = kCGBitmapByteOrder16Little;
90             if (bm.isOpaque()) {
91                 *info |= kCGImageAlphaNoneSkipLast;
92             } else {
93                 *info |= kCGImageAlphaPremultipliedLast;
94             }
95             break;
96         default:
97             return false;
98     }
99     return true;
100 }
101 
prepareForImageRef(const SkBitmap & bm,size_t * bitsPerComponent,CGBitmapInfo * info)102 static SkBitmap* prepareForImageRef(const SkBitmap& bm,
103                                     size_t* bitsPerComponent,
104                                     CGBitmapInfo* info) {
105     bool upscaleTo32;
106     if (!getBitmapInfo(bm, bitsPerComponent, info, &upscaleTo32)) {
107         return nullptr;
108     }
109 
110     SkBitmap* copy;
111     if (upscaleTo32) {
112         copy = new SkBitmap;
113         // here we make a ceep copy of the pixels, since CG won't take our
114         // 565 directly
115         bm.copyTo(copy, kN32_SkColorType);
116     } else {
117         copy = new SkBitmap(bm);
118     }
119     return copy;
120 }
121 
SkCreateCGImageRefWithColorspace(const SkBitmap & bm,CGColorSpaceRef colorSpace)122 CGImageRef SkCreateCGImageRefWithColorspace(const SkBitmap& bm,
123                                             CGColorSpaceRef colorSpace) {
124     size_t bitsPerComponent SK_INIT_TO_AVOID_WARNING;
125     CGBitmapInfo info       SK_INIT_TO_AVOID_WARNING;
126 
127     SkBitmap* bitmap = prepareForImageRef(bm, &bitsPerComponent, &info);
128     if (nullptr == bitmap) {
129         return nullptr;
130     }
131 
132     const int w = bitmap->width();
133     const int h = bitmap->height();
134     const size_t s = bitmap->getSize();
135 
136     // our provider "owns" the bitmap*, and will take care of deleting it
137     // we initially lock it, so we can access the pixels. The bitmap will be deleted in the release
138     // proc, which will in turn unlock the pixels
139     bitmap->lockPixels();
140     CGDataProviderRef dataRef = CGDataProviderCreateWithData(bitmap, bitmap->getPixels(), s,
141                                                              SkBitmap_ReleaseInfo);
142 
143     bool releaseColorSpace = false;
144     if (nullptr == colorSpace) {
145         colorSpace = CGColorSpaceCreateDeviceRGB();
146         releaseColorSpace = true;
147     }
148 
149     CGImageRef ref = CGImageCreate(w, h, bitsPerComponent,
150                                    bitmap->bytesPerPixel() * 8,
151                                    bitmap->rowBytes(), colorSpace, info, dataRef,
152                                    nullptr, false, kCGRenderingIntentDefault);
153 
154     if (releaseColorSpace) {
155         CGColorSpaceRelease(colorSpace);
156     }
157     CGDataProviderRelease(dataRef);
158     return ref;
159 }
160 
SkCGDrawBitmap(CGContextRef cg,const SkBitmap & bm,float x,float y)161 void SkCGDrawBitmap(CGContextRef cg, const SkBitmap& bm, float x, float y) {
162     CGImageRef img = SkCreateCGImageRef(bm);
163 
164     if (img) {
165         CGRect r = CGRectMake(0, 0, bm.width(), bm.height());
166 
167         CGContextSaveGState(cg);
168         CGContextTranslateCTM(cg, x, r.size.height + y);
169         CGContextScaleCTM(cg, 1, -1);
170 
171         CGContextDrawImage(cg, r, img);
172 
173         CGContextRestoreGState(cg);
174 
175         CGImageRelease(img);
176     }
177 }
178 
179 ///////////////////////////////////////////////////////////////////////////////////////////////////
180 
SkCreateCGContext(const SkPixmap & pmap)181 CGContextRef SkCreateCGContext(const SkPixmap& pmap) {
182     CGBitmapInfo cg_bitmap_info = 0;
183     size_t bitsPerComponent = 0;
184     switch (pmap.colorType()) {
185         case kRGBA_8888_SkColorType:
186             bitsPerComponent = 8;
187             cg_bitmap_info = ComputeCGAlphaInfo_RGBA(pmap.alphaType());
188             break;
189         case kBGRA_8888_SkColorType:
190             bitsPerComponent = 8;
191             cg_bitmap_info = ComputeCGAlphaInfo_BGRA(pmap.alphaType());
192             break;
193         default:
194             return nullptr;   // no other colortypes are supported (for now)
195     }
196 
197     size_t rb = pmap.addr() ? pmap.rowBytes() : 0;
198     CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB();
199     CGContextRef cg = CGBitmapContextCreate(pmap.writable_addr(), pmap.width(), pmap.height(),
200                                             bitsPerComponent, rb, cs, cg_bitmap_info);
201     CFRelease(cs);
202     return cg;
203 }
204 
SkCopyPixelsFromCGImage(const SkImageInfo & info,size_t rowBytes,void * pixels,CGImageRef image)205 SK_API bool SkCopyPixelsFromCGImage(const SkImageInfo& info, size_t rowBytes, void* pixels,
206                                     CGImageRef image) {
207     CGBitmapInfo cg_bitmap_info = 0;
208     size_t bitsPerComponent = 0;
209     switch (info.colorType()) {
210         case kRGBA_8888_SkColorType:
211             bitsPerComponent = 8;
212             cg_bitmap_info = ComputeCGAlphaInfo_RGBA(info.alphaType());
213             break;
214         case kBGRA_8888_SkColorType:
215             bitsPerComponent = 8;
216             cg_bitmap_info = ComputeCGAlphaInfo_BGRA(info.alphaType());
217             break;
218         default:
219             return false;   // no other colortypes are supported (for now)
220     }
221 
222     CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB();
223     CGContextRef cg = CGBitmapContextCreate(pixels, info.width(), info.height(), bitsPerComponent,
224                                             rowBytes, cs, cg_bitmap_info);
225     CFRelease(cs);
226     if (nullptr == cg) {
227         return false;
228     }
229 
230     // use this blend mode, to avoid having to erase the pixels first, and to avoid CG performing
231     // any blending (which could introduce errors and be slower).
232     CGContextSetBlendMode(cg, kCGBlendModeCopy);
233 
234     CGContextDrawImage(cg, CGRectMake(0, 0, info.width(), info.height()), image);
235     CGContextRelease(cg);
236     return true;
237 }
238 
SkCreateBitmapFromCGImage(SkBitmap * dst,CGImageRef image)239 bool SkCreateBitmapFromCGImage(SkBitmap* dst, CGImageRef image) {
240     const int width = SkToInt(CGImageGetWidth(image));
241     const int height = SkToInt(CGImageGetHeight(image));
242     SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
243 
244     SkBitmap tmp;
245     if (!tmp.tryAllocPixels(info)) {
246         return false;
247     }
248 
249     if (!SkCopyPixelsFromCGImage(tmp.info(), tmp.rowBytes(), tmp.getPixels(), image)) {
250         return false;
251     }
252 
253     CGImageAlphaInfo cgInfo = CGImageGetAlphaInfo(image);
254     switch (cgInfo) {
255         case kCGImageAlphaNone:
256         case kCGImageAlphaNoneSkipLast:
257         case kCGImageAlphaNoneSkipFirst:
258             SkASSERT(SkBitmap::ComputeIsOpaque(tmp));
259             tmp.setAlphaType(kOpaque_SkAlphaType);
260             break;
261         default:
262             // we don't know if we're opaque or not, so compute it.
263             if (SkBitmap::ComputeIsOpaque(tmp)) {
264                 tmp.setAlphaType(kOpaque_SkAlphaType);
265             }
266     }
267 
268     *dst = tmp;
269     return true;
270 }
271 
SkMakeImageFromCGImage(CGImageRef src)272 sk_sp<SkImage> SkMakeImageFromCGImage(CGImageRef src) {
273     SkBitmap bm;
274     if (!SkCreateBitmapFromCGImage(&bm, src)) {
275         return nullptr;
276     }
277 
278     bm.setImmutable();
279     return SkImage::MakeFromBitmap(bm);
280 }
281 
282 #endif//defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
283