SkCreateCGImageRef.cpp revision c280d112a820fce69bf6bac4dafdbb99d84077e9
1#include "SkCGUtils.h"
2#include "SkBitmap.h"
3#include "SkColorPriv.h"
4
5static void SkBitmap_ReleaseInfo(void* info, const void* pixelData, size_t size) {
6    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(info);
7    delete bitmap;
8}
9
10#define HAS_ARGB_SHIFTS(a, r, g, b) \
11    (SK_A32_SHIFT == (a) && SK_R32_SHIFT == (r) \
12    && SK_G32_SHIFT == (g) && SK_B32_SHIFT == (b))
13
14static SkBitmap* prepareForImageRef(const SkBitmap& bm,
15                                    size_t* bitsPerComponent,
16                                    CGBitmapInfo* info) {
17    bool upscaleTo32 = false;
18
19    switch (bm.config()) {
20        case SkBitmap::kRGB_565_Config:
21            upscaleTo32 = true;
22            // fall through
23        case SkBitmap::kARGB_8888_Config:
24            *bitsPerComponent = 8;
25#if defined(SK_CPU_LENDIAN) && HAS_ARGB_SHIFTS(24, 0, 8, 16) \
26 || defined(SK_CPU_BENDIAN) && HAS_ARGB_SHIFTS(0, 24, 16, 8)
27            *info = kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast;
28#elif defined(SK_CPU_LENDIAN) && HAS_ARGB_SHIFTS(24, 16, 8, 0) \
29   || defined(SK_CPU_BENDIAN) && HAS_ARGB_SHIFTS(24, 16, 8, 0)
30            // Matches the CGBitmapInfo that Apple recommends for best
31            // performance, used by google chrome.
32            *info = kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst;
33#else
34// ...add more formats as required...
35#warning Cannot convert SkBitmap to CGImageRef with these shiftmasks. \
36            This will probably not work.
37            // Legacy behavior. Perhaps turn this into an error at some
38            // point.
39            *info = kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast;
40#endif
41            break;
42#if 0
43        case SkBitmap::kRGB_565_Config:
44            // doesn't see quite right. Are they thinking 1555?
45            *bitsPerComponent = 5;
46            *info = kCGBitmapByteOrder16Little;
47            break;
48#endif
49        case SkBitmap::kARGB_4444_Config:
50            *bitsPerComponent = 4;
51            *info = kCGBitmapByteOrder16Little | kCGImageAlphaPremultipliedLast;
52            break;
53        default:
54            return NULL;
55    }
56
57    SkBitmap* copy;
58    if (upscaleTo32) {
59        copy = new SkBitmap;
60        // here we make a ceep copy of the pixels, since CG won't take our
61        // 565 directly
62        bm.copyTo(copy, SkBitmap::kARGB_8888_Config);
63    } else {
64        copy = new SkBitmap(bm);
65    }
66    return copy;
67}
68
69#undef HAS_ARGB_SHIFTS
70
71CGImageRef SkCreateCGImageRefWithColorspace(const SkBitmap& bm,
72                                            CGColorSpaceRef colorSpace) {
73    size_t bitsPerComponent SK_INIT_TO_AVOID_WARNING;
74    CGBitmapInfo info       SK_INIT_TO_AVOID_WARNING;
75
76    SkBitmap* bitmap = prepareForImageRef(bm, &bitsPerComponent, &info);
77    if (NULL == bitmap) {
78        return NULL;
79    }
80
81    const int w = bitmap->width();
82    const int h = bitmap->height();
83    const size_t s = bitmap->getSize();
84
85    // our provider "owns" the bitmap*, and will take care of deleting it
86	// we initially lock it, so we can access the pixels. The bitmap will be deleted in the release
87	// proc, which will in turn unlock the pixels
88	bitmap->lockPixels();
89    CGDataProviderRef dataRef = CGDataProviderCreateWithData(bitmap, bitmap->getPixels(), s,
90															 SkBitmap_ReleaseInfo);
91
92    bool releaseColorSpace = false;
93    if (NULL == colorSpace) {
94        colorSpace = CGColorSpaceCreateDeviceRGB();
95        releaseColorSpace = true;
96    }
97
98    CGImageRef ref = CGImageCreate(w, h, bitsPerComponent,
99                                   bitmap->bytesPerPixel() * 8,
100                                   bitmap->rowBytes(), colorSpace, info, dataRef,
101                                   NULL, false, kCGRenderingIntentDefault);
102
103    if (releaseColorSpace) {
104        CGColorSpaceRelease(colorSpace);
105    }
106    CGDataProviderRelease(dataRef);
107    return ref;
108}
109
110void SkCGDrawBitmap(CGContextRef cg, const SkBitmap& bm, float x, float y) {
111    CGImageRef img = SkCreateCGImageRef(bm);
112
113    if (img) {
114        CGRect r = CGRectMake(0, 0, bm.width(), bm.height());
115
116        CGContextSaveGState(cg);
117        CGContextTranslateCTM(cg, x, r.size.height + y);
118        CGContextScaleCTM(cg, 1, -1);
119
120        CGContextDrawImage(cg, r, img);
121
122        CGContextRestoreGState(cg);
123
124        CGImageRelease(img);
125    }
126}
127
128
129
130