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 15static 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 33static 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 51static void SkBitmap_ReleaseInfo(void* info, const void* pixelData, size_t size) { 52 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(info); 53 delete bitmap; 54} 55 56static 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 102static 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 122CGImageRef 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 161void 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 181CGContextRef 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 205SK_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 239bool 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 272sk_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