3 * Copyright 2011 Google Inc.
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
10 #include "SkColorPriv.h"
12 static CGBitmapInfo ComputeCGAlphaInfo_RGBA(SkAlphaType at) {
13 CGBitmapInfo info = kCGBitmapByteOrder32Big;
15 case kOpaque_SkAlphaType:
16 case kIgnore_SkAlphaType:
17 info |= kCGImageAlphaNoneSkipLast;
19 case kPremul_SkAlphaType:
20 info |= kCGImageAlphaPremultipliedLast;
22 case kUnpremul_SkAlphaType:
23 info |= kCGImageAlphaLast;
29 static CGBitmapInfo ComputeCGAlphaInfo_BGRA(SkAlphaType at) {
30 CGBitmapInfo info = kCGBitmapByteOrder32Little;
32 case kOpaque_SkAlphaType:
33 case kIgnore_SkAlphaType:
34 info |= kCGImageAlphaNoneSkipFirst;
36 case kPremul_SkAlphaType:
37 info |= kCGImageAlphaPremultipliedFirst;
39 case kUnpremul_SkAlphaType:
40 info |= kCGImageAlphaFirst;
46 static void SkBitmap_ReleaseInfo(void* info, const void* pixelData, size_t size) {
47 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(info);
51 static bool getBitmapInfo(const SkBitmap& bm,
52 size_t* bitsPerComponent,
59 switch (bm.colorType()) {
60 case kRGB_565_SkColorType:
62 // doesn't see quite right. Are they thinking 1555?
63 *bitsPerComponent = 5;
64 *info = kCGBitmapByteOrder16Little | kCGImageAlphaNone;
69 // now treat like RGBA
70 *bitsPerComponent = 8;
71 *info = ComputeCGAlphaInfo_RGBA(kOpaque_SkAlphaType);
74 case kRGBA_8888_SkColorType:
75 *bitsPerComponent = 8;
76 *info = ComputeCGAlphaInfo_RGBA(bm.alphaType());
78 case kBGRA_8888_SkColorType:
79 *bitsPerComponent = 8;
80 *info = ComputeCGAlphaInfo_BGRA(bm.alphaType());
82 case kARGB_4444_SkColorType:
83 *bitsPerComponent = 4;
84 *info = kCGBitmapByteOrder16Little;
86 *info |= kCGImageAlphaNoneSkipLast;
88 *info |= kCGImageAlphaPremultipliedLast;
97 static SkBitmap* prepareForImageRef(const SkBitmap& bm,
98 size_t* bitsPerComponent,
101 if (!getBitmapInfo(bm, bitsPerComponent, info, &upscaleTo32)) {
108 // here we make a ceep copy of the pixels, since CG won't take our
110 bm.copyTo(copy, kN32_SkColorType);
112 copy = new SkBitmap(bm);
117 CGImageRef SkCreateCGImageRefWithColorspace(const SkBitmap& bm,
118 CGColorSpaceRef colorSpace) {
119 size_t bitsPerComponent SK_INIT_TO_AVOID_WARNING;
120 CGBitmapInfo info SK_INIT_TO_AVOID_WARNING;
122 SkBitmap* bitmap = prepareForImageRef(bm, &bitsPerComponent, &info);
123 if (NULL == bitmap) {
127 const int w = bitmap->width();
128 const int h = bitmap->height();
129 const size_t s = bitmap->getSize();
131 // our provider "owns" the bitmap*, and will take care of deleting it
132 // we initially lock it, so we can access the pixels. The bitmap will be deleted in the release
133 // proc, which will in turn unlock the pixels
134 bitmap->lockPixels();
135 CGDataProviderRef dataRef = CGDataProviderCreateWithData(bitmap, bitmap->getPixels(), s,
136 SkBitmap_ReleaseInfo);
138 bool releaseColorSpace = false;
139 if (NULL == colorSpace) {
140 colorSpace = CGColorSpaceCreateDeviceRGB();
141 releaseColorSpace = true;
144 CGImageRef ref = CGImageCreate(w, h, bitsPerComponent,
145 bitmap->bytesPerPixel() * 8,
146 bitmap->rowBytes(), colorSpace, info, dataRef,
147 NULL, false, kCGRenderingIntentDefault);
149 if (releaseColorSpace) {
150 CGColorSpaceRelease(colorSpace);
152 CGDataProviderRelease(dataRef);
156 void SkCGDrawBitmap(CGContextRef cg, const SkBitmap& bm, float x, float y) {
157 CGImageRef img = SkCreateCGImageRef(bm);
160 CGRect r = CGRectMake(0, 0, bm.width(), bm.height());
162 CGContextSaveGState(cg);
163 CGContextTranslateCTM(cg, x, r.size.height + y);
164 CGContextScaleCTM(cg, 1, -1);
166 CGContextDrawImage(cg, r, img);
168 CGContextRestoreGState(cg);
174 ///////////////////////////////////////////////////////////////////////////////
176 #include "SkStream.h"
178 class SkAutoPDFRelease {
180 SkAutoPDFRelease(CGPDFDocumentRef doc) : fDoc(doc) {}
181 ~SkAutoPDFRelease() {
183 CGPDFDocumentRelease(fDoc);
187 CGPDFDocumentRef fDoc;
189 #define SkAutoPDFRelease(...) SK_REQUIRE_LOCAL_VAR(SkAutoPDFRelease)
191 bool SkPDFDocumentToBitmap(SkStream* stream, SkBitmap* output) {
192 CGDataProviderRef data = SkCreateDataProviderFromStream(stream);
197 CGPDFDocumentRef pdf = CGPDFDocumentCreateWithProvider(data);
198 CGDataProviderRelease(data);
202 SkAutoPDFRelease releaseMe(pdf);
204 CGPDFPageRef page = CGPDFDocumentGetPage(pdf, 1);
209 CGRect bounds = CGPDFPageGetBoxRect(page, kCGPDFMediaBox);
211 int w = (int)CGRectGetWidth(bounds);
212 int h = (int)CGRectGetHeight(bounds);
215 if (!bitmap.tryAllocN32Pixels(w, h)) {
218 bitmap.eraseColor(SK_ColorWHITE);
220 size_t bitsPerComponent;
222 getBitmapInfo(bitmap, &bitsPerComponent, &info, NULL);
224 CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB();
225 CGContextRef ctx = CGBitmapContextCreate(bitmap.getPixels(), w, h,
226 bitsPerComponent, bitmap.rowBytes(),
228 CGColorSpaceRelease(cs);
231 CGContextDrawPDFPage(ctx, page);
232 CGContextRelease(ctx);
235 output->swap(bitmap);
239 ///////////////////////////////////////////////////////////////////////////////////////////////////
241 SK_API bool SkCopyPixelsFromCGImage(const SkImageInfo& info, size_t rowBytes, void* pixels,
243 CGBitmapInfo cg_bitmap_info = 0;
244 size_t bitsPerComponent = 0;
245 switch (info.colorType()) {
246 case kRGBA_8888_SkColorType:
247 bitsPerComponent = 8;
248 cg_bitmap_info = ComputeCGAlphaInfo_RGBA(info.alphaType());
250 case kBGRA_8888_SkColorType:
251 bitsPerComponent = 8;
252 cg_bitmap_info = ComputeCGAlphaInfo_BGRA(info.alphaType());
255 return false; // no other colortypes are supported (for now)
258 CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB();
259 CGContextRef cg = CGBitmapContextCreate(pixels, info.width(), info.height(), bitsPerComponent,
260 rowBytes, cs, cg_bitmap_info);
266 // use this blend mode, to avoid having to erase the pixels first, and to avoid CG performing
267 // any blending (which could introduce errors and be slower).
268 CGContextSetBlendMode(cg, kCGBlendModeCopy);
270 CGContextDrawImage(cg, CGRectMake(0, 0, info.width(), info.height()), image);
271 CGContextRelease(cg);
275 bool SkCreateBitmapFromCGImage(SkBitmap* dst, CGImageRef image, SkISize* scaleToFit) {
276 const int width = scaleToFit ? scaleToFit->width() : SkToInt(CGImageGetWidth(image));
277 const int height = scaleToFit ? scaleToFit->height() : SkToInt(CGImageGetHeight(image));
278 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
281 if (!tmp.tryAllocPixels(info)) {
285 if (!SkCopyPixelsFromCGImage(tmp.info(), tmp.rowBytes(), tmp.getPixels(), image)) {
289 CGImageAlphaInfo cgInfo = CGImageGetAlphaInfo(image);
291 case kCGImageAlphaNone:
292 case kCGImageAlphaNoneSkipLast:
293 case kCGImageAlphaNoneSkipFirst:
294 SkASSERT(SkBitmap::ComputeIsOpaque(tmp));
295 tmp.setAlphaType(kOpaque_SkAlphaType);
298 // we don't know if we're opaque or not, so compute it.
299 if (SkBitmap::ComputeIsOpaque(tmp)) {
300 tmp.setAlphaType(kOpaque_SkAlphaType);