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 "SkColorData.h" 14 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 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 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 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 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 deep copy of the pixels, since CG won't take our 114 // 565 directly 115 copy->allocPixels(bm.info().makeColorType(kN32_SkColorType)); 116 bm.readPixels(copy->info(), copy->getPixels(), copy->rowBytes(), 0, 0); 117 } else { 118 copy = new SkBitmap(bm); 119 } 120 return copy; 121 } 122 123 CGImageRef SkCreateCGImageRefWithColorspace(const SkBitmap& bm, 124 CGColorSpaceRef colorSpace) { 125 size_t bitsPerComponent SK_INIT_TO_AVOID_WARNING; 126 CGBitmapInfo info SK_INIT_TO_AVOID_WARNING; 127 128 SkBitmap* bitmap = prepareForImageRef(bm, &bitsPerComponent, &info); 129 if (nullptr == bitmap) { 130 return nullptr; 131 } 132 133 const int w = bitmap->width(); 134 const int h = bitmap->height(); 135 const size_t s = bitmap->computeByteSize(); 136 137 // our provider "owns" the bitmap*, and will take care of deleting it 138 CGDataProviderRef dataRef = CGDataProviderCreateWithData(bitmap, bitmap->getPixels(), s, 139 SkBitmap_ReleaseInfo); 140 141 bool releaseColorSpace = false; 142 if (nullptr == colorSpace) { 143 colorSpace = CGColorSpaceCreateDeviceRGB(); 144 releaseColorSpace = true; 145 } 146 147 CGImageRef ref = CGImageCreate(w, h, bitsPerComponent, 148 bitmap->bytesPerPixel() * 8, 149 bitmap->rowBytes(), colorSpace, info, dataRef, 150 nullptr, false, kCGRenderingIntentDefault); 151 152 if (releaseColorSpace) { 153 CGColorSpaceRelease(colorSpace); 154 } 155 CGDataProviderRelease(dataRef); 156 return ref; 157 } 158 159 void SkCGDrawBitmap(CGContextRef cg, const SkBitmap& bm, float x, float y) { 160 CGImageRef img = SkCreateCGImageRef(bm); 161 162 if (img) { 163 CGRect r = CGRectMake(0, 0, bm.width(), bm.height()); 164 165 CGContextSaveGState(cg); 166 CGContextTranslateCTM(cg, x, r.size.height + y); 167 CGContextScaleCTM(cg, 1, -1); 168 169 CGContextDrawImage(cg, r, img); 170 171 CGContextRestoreGState(cg); 172 173 CGImageRelease(img); 174 } 175 } 176 177 /////////////////////////////////////////////////////////////////////////////////////////////////// 178 179 CGContextRef SkCreateCGContext(const SkPixmap& pmap) { 180 CGBitmapInfo cg_bitmap_info = 0; 181 size_t bitsPerComponent = 0; 182 switch (pmap.colorType()) { 183 case kRGBA_8888_SkColorType: 184 bitsPerComponent = 8; 185 cg_bitmap_info = ComputeCGAlphaInfo_RGBA(pmap.alphaType()); 186 break; 187 case kBGRA_8888_SkColorType: 188 bitsPerComponent = 8; 189 cg_bitmap_info = ComputeCGAlphaInfo_BGRA(pmap.alphaType()); 190 break; 191 default: 192 return nullptr; // no other colortypes are supported (for now) 193 } 194 195 size_t rb = pmap.addr() ? pmap.rowBytes() : 0; 196 CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB(); 197 CGContextRef cg = CGBitmapContextCreate(pmap.writable_addr(), pmap.width(), pmap.height(), 198 bitsPerComponent, rb, cs, cg_bitmap_info); 199 CFRelease(cs); 200 return cg; 201 } 202 203 bool SkCopyPixelsFromCGImage(const SkImageInfo& info, size_t rowBytes, void* pixels, 204 CGImageRef image) { 205 CGBitmapInfo cg_bitmap_info = 0; 206 size_t bitsPerComponent = 0; 207 switch (info.colorType()) { 208 case kRGBA_8888_SkColorType: 209 bitsPerComponent = 8; 210 cg_bitmap_info = ComputeCGAlphaInfo_RGBA(info.alphaType()); 211 break; 212 case kBGRA_8888_SkColorType: 213 bitsPerComponent = 8; 214 cg_bitmap_info = ComputeCGAlphaInfo_BGRA(info.alphaType()); 215 break; 216 default: 217 return false; // no other colortypes are supported (for now) 218 } 219 220 CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB(); 221 CGContextRef cg = CGBitmapContextCreate(pixels, info.width(), info.height(), bitsPerComponent, 222 rowBytes, cs, cg_bitmap_info); 223 CFRelease(cs); 224 if (nullptr == cg) { 225 return false; 226 } 227 228 // use this blend mode, to avoid having to erase the pixels first, and to avoid CG performing 229 // any blending (which could introduce errors and be slower). 230 CGContextSetBlendMode(cg, kCGBlendModeCopy); 231 232 CGContextDrawImage(cg, CGRectMake(0, 0, info.width(), info.height()), image); 233 CGContextRelease(cg); 234 return true; 235 } 236 237 bool SkCreateBitmapFromCGImage(SkBitmap* dst, CGImageRef image) { 238 const int width = SkToInt(CGImageGetWidth(image)); 239 const int height = SkToInt(CGImageGetHeight(image)); 240 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height); 241 242 SkBitmap tmp; 243 if (!tmp.tryAllocPixels(info)) { 244 return false; 245 } 246 247 if (!SkCopyPixelsFromCGImage(tmp.info(), tmp.rowBytes(), tmp.getPixels(), image)) { 248 return false; 249 } 250 251 CGImageAlphaInfo cgInfo = CGImageGetAlphaInfo(image); 252 switch (cgInfo) { 253 case kCGImageAlphaNone: 254 case kCGImageAlphaNoneSkipLast: 255 case kCGImageAlphaNoneSkipFirst: 256 SkASSERT(SkBitmap::ComputeIsOpaque(tmp)); 257 tmp.setAlphaType(kOpaque_SkAlphaType); 258 break; 259 default: 260 // we don't know if we're opaque or not, so compute it. 261 if (SkBitmap::ComputeIsOpaque(tmp)) { 262 tmp.setAlphaType(kOpaque_SkAlphaType); 263 } 264 } 265 266 *dst = tmp; 267 return true; 268 } 269 270 sk_sp<SkImage> SkMakeImageFromCGImage(CGImageRef src) { 271 SkBitmap bm; 272 if (!SkCreateBitmapFromCGImage(&bm, src)) { 273 return nullptr; 274 } 275 276 bm.setImmutable(); 277 return SkImage::MakeFromBitmap(bm); 278 } 279 280 #endif//defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) 281