gfx/skia/trunk/src/utils/mac/SkCreateCGImageRef.cpp

changeset 0
6474c204b198
     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 +}

mercurial