aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/ports/SkImageGeneratorCG.cpp
blob: 743b2182547ea246b98512ff652a7796c6d14be8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/*
 * Copyright 2016 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkImageGeneratorCG.h"
#include "SkPixmapPriv.h"

#ifdef SK_BUILD_FOR_MAC
#include <ApplicationServices/ApplicationServices.h>
#endif

#ifdef SK_BUILD_FOR_IOS
#include <CoreGraphics/CoreGraphics.h>
#include <ImageIO/ImageIO.h>
#include <MobileCoreServices/MobileCoreServices.h>
#endif

static CGImageSourceRef data_to_CGImageSrc(SkData* data) {
    CGDataProviderRef cgData = CGDataProviderCreateWithData(data, data->data(), data->size(),
            nullptr);
    if (!cgData) {
        return nullptr;
    }
    CGImageSourceRef imageSrc = CGImageSourceCreateWithDataProvider(cgData, 0);
    CGDataProviderRelease(cgData);
    return imageSrc;
}

#ifdef SK_LEGACY_NEW_FROM_ENCODED_CG
SkImageGenerator* SkImageGeneratorCG::NewFromEncodedCG(SkData* data) {
    return MakeFromEncodedCG(sk_ref_sp(data)).release();
}
#endif

std::unique_ptr<SkImageGenerator> SkImageGeneratorCG::MakeFromEncodedCG(sk_sp<SkData> data) {
    CGImageSourceRef imageSrc = data_to_CGImageSrc(data.get());
    if (!imageSrc) {
        return nullptr;
    }

    // Make sure we call CFRelease to free the imageSrc.  Since CFRelease actually takes
    // a const void*, we must cast the imageSrc to a const void*.
    SkAutoTCallVProc<const void, CFRelease> autoImageSrc(imageSrc);

    CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(imageSrc, 0, nullptr);
    if (!properties) {
        return nullptr;
    }

    CFNumberRef widthRef = (CFNumberRef) (CFDictionaryGetValue(properties,
            kCGImagePropertyPixelWidth));
    CFNumberRef heightRef = (CFNumberRef) (CFDictionaryGetValue(properties,
            kCGImagePropertyPixelHeight));
    if (nullptr == widthRef || nullptr == heightRef) {
        return nullptr;
    }

    int width, height;
    if (!CFNumberGetValue(widthRef, kCFNumberIntType, &width) ||
            !CFNumberGetValue(heightRef, kCFNumberIntType, &height)) {
        return nullptr;
    }

    bool hasAlpha = (bool) (CFDictionaryGetValue(properties,
            kCGImagePropertyHasAlpha));
    SkAlphaType alphaType = hasAlpha ? kPremul_SkAlphaType : kOpaque_SkAlphaType;
    SkImageInfo info = SkImageInfo::MakeS32(width, height, alphaType);

    auto origin = kDefault_SkEncodedOrigin;
    auto orientationRef = (CFNumberRef) (CFDictionaryGetValue(properties,
            kCGImagePropertyOrientation));
    int originInt;
    if (orientationRef && CFNumberGetValue(orientationRef, kCFNumberIntType, &originInt)) {
        origin = (SkEncodedOrigin) originInt;
    }

    if (SkPixmapPriv::ShouldSwapWidthHeight(origin)) {
        info = SkPixmapPriv::SwapWidthHeight(info);
    }

    // FIXME: We have the opportunity to extract color space information here,
    //        though I think it makes sense to wait until we understand how
    //        we want to communicate it to the generator.

    return std::unique_ptr<SkImageGenerator>(new SkImageGeneratorCG(info, autoImageSrc.release(),
                                                                    std::move(data), origin));
}

SkImageGeneratorCG::SkImageGeneratorCG(const SkImageInfo& info, const void* imageSrc,
                                       sk_sp<SkData> data, SkEncodedOrigin origin)
    : INHERITED(info)
    , fImageSrc(imageSrc)
    , fData(std::move(data))
    , fOrigin(origin)
{}

sk_sp<SkData> SkImageGeneratorCG::onRefEncodedData() {
    return fData;
}

bool SkImageGeneratorCG::onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
        const Options&) {
    if (kN32_SkColorType != info.colorType()) {
        // FIXME: Support other colorTypes.
        return false;
    }

    switch (info.alphaType()) {
        case kOpaque_SkAlphaType:
            if (kOpaque_SkAlphaType != this->getInfo().alphaType()) {
                return false;
            }
            break;
        case kPremul_SkAlphaType:
            break;
        default:
            return false;
    }

    CGImageRef image = CGImageSourceCreateImageAtIndex((CGImageSourceRef) fImageSrc.get(), 0,
            nullptr);
    if (!image) {
        return false;
    }
    SkAutoTCallVProc<CGImage, CGImageRelease> autoImage(image);

    SkPixmap dst(info, pixels, rowBytes);
    auto decode = [&image](const SkPixmap& pm) {
        // FIXME: Using SkCopyPixelsFromCGImage (as opposed to swizzling
        // ourselves) greatly restricts the color and alpha types that we
        // support.  If we swizzle ourselves, we can add support for:
        //     kUnpremul_SkAlphaType
        //     16-bit per component RGBA
        //     kGray_8_SkColorType
        // Additionally, it would be interesting to compare the performance
        // of SkSwizzler with CG's built in swizzler.
        return SkCopyPixelsFromCGImage(pm, image);
    };
    return SkPixmapPriv::Orient(dst, fOrigin, decode);
}