1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/utils/mac/SkCreateCGImageRef.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,233 @@ 1.4 + 1.5 +/* 1.6 + * Copyright 2011 Google Inc. 1.7 + * 1.8 + * Use of this source code is governed by a BSD-style license that can be 1.9 + * found in the LICENSE file. 1.10 + */ 1.11 +#include "SkCGUtils.h" 1.12 +#include "SkBitmap.h" 1.13 +#include "SkColorPriv.h" 1.14 + 1.15 +static void SkBitmap_ReleaseInfo(void* info, const void* pixelData, size_t size) { 1.16 + SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(info); 1.17 + delete bitmap; 1.18 +} 1.19 + 1.20 +static bool getBitmapInfo(const SkBitmap& bm, 1.21 + size_t* bitsPerComponent, 1.22 + CGBitmapInfo* info, 1.23 + bool* upscaleTo32) { 1.24 + if (upscaleTo32) { 1.25 + *upscaleTo32 = false; 1.26 + } 1.27 + 1.28 + switch (bm.colorType()) { 1.29 + case kRGB_565_SkColorType: 1.30 +#if 0 1.31 + // doesn't see quite right. Are they thinking 1555? 1.32 + *bitsPerComponent = 5; 1.33 + *info = kCGBitmapByteOrder16Little | kCGImageAlphaNone; 1.34 + break; 1.35 +#endif 1.36 + if (upscaleTo32) { 1.37 + *upscaleTo32 = true; 1.38 + } 1.39 + // fall through 1.40 + case kPMColor_SkColorType: 1.41 + *bitsPerComponent = 8; 1.42 +#if SK_PMCOLOR_BYTE_ORDER(R,G,B,A) 1.43 + *info = kCGBitmapByteOrder32Big; 1.44 + if (bm.isOpaque()) { 1.45 + *info |= kCGImageAlphaNoneSkipLast; 1.46 + } else { 1.47 + *info |= kCGImageAlphaPremultipliedLast; 1.48 + } 1.49 +#elif SK_PMCOLOR_BYTE_ORDER(B,G,R,A) 1.50 + // Matches the CGBitmapInfo that Apple recommends for best 1.51 + // performance, used by google chrome. 1.52 + *info = kCGBitmapByteOrder32Little; 1.53 + if (bm.isOpaque()) { 1.54 + *info |= kCGImageAlphaNoneSkipFirst; 1.55 + } else { 1.56 + *info |= kCGImageAlphaPremultipliedFirst; 1.57 + } 1.58 +#else 1.59 + // ...add more formats as required... 1.60 +#warning Cannot convert SkBitmap to CGImageRef with these shiftmasks. \ 1.61 +This will probably not work. 1.62 + // Legacy behavior. Perhaps turn this into an error at some 1.63 + // point. 1.64 + *info = kCGBitmapByteOrder32Big; 1.65 + if (bm.isOpaque()) { 1.66 + *info |= kCGImageAlphaNoneSkipLast; 1.67 + } else { 1.68 + *info |= kCGImageAlphaPremultipliedLast; 1.69 + } 1.70 +#endif 1.71 + break; 1.72 + case kARGB_4444_SkColorType: 1.73 + *bitsPerComponent = 4; 1.74 + *info = kCGBitmapByteOrder16Little; 1.75 + if (bm.isOpaque()) { 1.76 + *info |= kCGImageAlphaNoneSkipLast; 1.77 + } else { 1.78 + *info |= kCGImageAlphaPremultipliedLast; 1.79 + } 1.80 + break; 1.81 + default: 1.82 + return false; 1.83 + } 1.84 + return true; 1.85 +} 1.86 + 1.87 +static SkBitmap* prepareForImageRef(const SkBitmap& bm, 1.88 + size_t* bitsPerComponent, 1.89 + CGBitmapInfo* info) { 1.90 + bool upscaleTo32; 1.91 + if (!getBitmapInfo(bm, bitsPerComponent, info, &upscaleTo32)) { 1.92 + return NULL; 1.93 + } 1.94 + 1.95 + SkBitmap* copy; 1.96 + if (upscaleTo32) { 1.97 + copy = new SkBitmap; 1.98 + // here we make a ceep copy of the pixels, since CG won't take our 1.99 + // 565 directly 1.100 + bm.copyTo(copy, kPMColor_SkColorType); 1.101 + } else { 1.102 + copy = new SkBitmap(bm); 1.103 + } 1.104 + return copy; 1.105 +} 1.106 + 1.107 +CGImageRef SkCreateCGImageRefWithColorspace(const SkBitmap& bm, 1.108 + CGColorSpaceRef colorSpace) { 1.109 + size_t bitsPerComponent SK_INIT_TO_AVOID_WARNING; 1.110 + CGBitmapInfo info SK_INIT_TO_AVOID_WARNING; 1.111 + 1.112 + SkBitmap* bitmap = prepareForImageRef(bm, &bitsPerComponent, &info); 1.113 + if (NULL == bitmap) { 1.114 + return NULL; 1.115 + } 1.116 + 1.117 + const int w = bitmap->width(); 1.118 + const int h = bitmap->height(); 1.119 + const size_t s = bitmap->getSize(); 1.120 + 1.121 + // our provider "owns" the bitmap*, and will take care of deleting it 1.122 + // we initially lock it, so we can access the pixels. The bitmap will be deleted in the release 1.123 + // proc, which will in turn unlock the pixels 1.124 + bitmap->lockPixels(); 1.125 + CGDataProviderRef dataRef = CGDataProviderCreateWithData(bitmap, bitmap->getPixels(), s, 1.126 + SkBitmap_ReleaseInfo); 1.127 + 1.128 + bool releaseColorSpace = false; 1.129 + if (NULL == colorSpace) { 1.130 + colorSpace = CGColorSpaceCreateDeviceRGB(); 1.131 + releaseColorSpace = true; 1.132 + } 1.133 + 1.134 + CGImageRef ref = CGImageCreate(w, h, bitsPerComponent, 1.135 + bitmap->bytesPerPixel() * 8, 1.136 + bitmap->rowBytes(), colorSpace, info, dataRef, 1.137 + NULL, false, kCGRenderingIntentDefault); 1.138 + 1.139 + if (releaseColorSpace) { 1.140 + CGColorSpaceRelease(colorSpace); 1.141 + } 1.142 + CGDataProviderRelease(dataRef); 1.143 + return ref; 1.144 +} 1.145 + 1.146 +void SkCGDrawBitmap(CGContextRef cg, const SkBitmap& bm, float x, float y) { 1.147 + CGImageRef img = SkCreateCGImageRef(bm); 1.148 + 1.149 + if (img) { 1.150 + CGRect r = CGRectMake(0, 0, bm.width(), bm.height()); 1.151 + 1.152 + CGContextSaveGState(cg); 1.153 + CGContextTranslateCTM(cg, x, r.size.height + y); 1.154 + CGContextScaleCTM(cg, 1, -1); 1.155 + 1.156 + CGContextDrawImage(cg, r, img); 1.157 + 1.158 + CGContextRestoreGState(cg); 1.159 + 1.160 + CGImageRelease(img); 1.161 + } 1.162 +} 1.163 + 1.164 +/////////////////////////////////////////////////////////////////////////////// 1.165 + 1.166 +#include "SkStream.h" 1.167 + 1.168 +class SkAutoPDFRelease { 1.169 +public: 1.170 + SkAutoPDFRelease(CGPDFDocumentRef doc) : fDoc(doc) {} 1.171 + ~SkAutoPDFRelease() { 1.172 + if (fDoc) { 1.173 + CGPDFDocumentRelease(fDoc); 1.174 + } 1.175 + } 1.176 +private: 1.177 + CGPDFDocumentRef fDoc; 1.178 +}; 1.179 +#define SkAutoPDFRelease(...) SK_REQUIRE_LOCAL_VAR(SkAutoPDFRelease) 1.180 + 1.181 +static void CGDataProviderReleaseData_FromMalloc(void*, const void* data, 1.182 + size_t size) { 1.183 + sk_free((void*)data); 1.184 +} 1.185 + 1.186 +bool SkPDFDocumentToBitmap(SkStream* stream, SkBitmap* output) { 1.187 + size_t size = stream->getLength(); 1.188 + void* ptr = sk_malloc_throw(size); 1.189 + stream->read(ptr, size); 1.190 + CGDataProviderRef data = CGDataProviderCreateWithData(NULL, ptr, size, 1.191 + CGDataProviderReleaseData_FromMalloc); 1.192 + if (NULL == data) { 1.193 + return false; 1.194 + } 1.195 + 1.196 + CGPDFDocumentRef pdf = CGPDFDocumentCreateWithProvider(data); 1.197 + CGDataProviderRelease(data); 1.198 + if (NULL == pdf) { 1.199 + return false; 1.200 + } 1.201 + SkAutoPDFRelease releaseMe(pdf); 1.202 + 1.203 + CGPDFPageRef page = CGPDFDocumentGetPage(pdf, 1); 1.204 + if (NULL == page) { 1.205 + return false; 1.206 + } 1.207 + 1.208 + CGRect bounds = CGPDFPageGetBoxRect(page, kCGPDFMediaBox); 1.209 + 1.210 + int w = (int)CGRectGetWidth(bounds); 1.211 + int h = (int)CGRectGetHeight(bounds); 1.212 + 1.213 + SkBitmap bitmap; 1.214 + if (!bitmap.allocPixels(SkImageInfo::MakeN32Premul(w, h))) { 1.215 + return false; 1.216 + } 1.217 + bitmap.eraseColor(SK_ColorWHITE); 1.218 + 1.219 + size_t bitsPerComponent; 1.220 + CGBitmapInfo info; 1.221 + getBitmapInfo(bitmap, &bitsPerComponent, &info, NULL); 1.222 + 1.223 + CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB(); 1.224 + CGContextRef ctx = CGBitmapContextCreate(bitmap.getPixels(), w, h, 1.225 + bitsPerComponent, bitmap.rowBytes(), 1.226 + cs, info); 1.227 + CGColorSpaceRelease(cs); 1.228 + 1.229 + if (ctx) { 1.230 + CGContextDrawPDFPage(ctx, page); 1.231 + CGContextRelease(ctx); 1.232 + } 1.233 + 1.234 + output->swap(bitmap); 1.235 + return true; 1.236 +}