1 /*
2 * Copyright 2016 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 "SkImageGeneratorCG.h"
9
10 #ifdef SK_BUILD_FOR_MAC
11 #include <ApplicationServices/ApplicationServices.h>
12 #endif
13
14 #ifdef SK_BUILD_FOR_IOS
15 #include <CoreGraphics/CoreGraphics.h>
16 #include <ImageIO/ImageIO.h>
17 #include <MobileCoreServices/MobileCoreServices.h>
18 #endif
19
data_to_CGImageSrc(SkData * data)20 static CGImageSourceRef data_to_CGImageSrc(SkData* data) {
21 CGDataProviderRef cgData = CGDataProviderCreateWithData(data, data->data(), data->size(),
22 nullptr);
23 if (!cgData) {
24 return nullptr;
25 }
26 CGImageSourceRef imageSrc = CGImageSourceCreateWithDataProvider(cgData, 0);
27 CGDataProviderRelease(cgData);
28 return imageSrc;
29 }
30
NewFromEncodedCG(SkData * data)31 SkImageGenerator* SkImageGeneratorCG::NewFromEncodedCG(SkData* data) {
32 CGImageSourceRef imageSrc = data_to_CGImageSrc(data);
33 if (!imageSrc) {
34 return nullptr;
35 }
36
37 // Make sure we call CFRelease to free the imageSrc. Since CFRelease actually takes
38 // a const void*, we must cast the imageSrc to a const void*.
39 SkAutoTCallVProc<const void, CFRelease> autoImageSrc(imageSrc);
40
41 CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(imageSrc, 0, nullptr);
42 if (!properties) {
43 return nullptr;
44 }
45
46 CFNumberRef widthRef = (CFNumberRef) (CFDictionaryGetValue(properties,
47 kCGImagePropertyPixelWidth));
48 CFNumberRef heightRef = (CFNumberRef) (CFDictionaryGetValue(properties,
49 kCGImagePropertyPixelHeight));
50 if (nullptr == widthRef || nullptr == heightRef) {
51 return nullptr;
52 }
53 bool hasAlpha = (bool) (CFDictionaryGetValue(properties,
54 kCGImagePropertyHasAlpha));
55
56 int width, height;
57 if (!CFNumberGetValue(widthRef, kCFNumberIntType, &width) ||
58 !CFNumberGetValue(heightRef, kCFNumberIntType, &height)) {
59 return nullptr;
60 }
61
62 SkAlphaType alphaType = hasAlpha ? kPremul_SkAlphaType : kOpaque_SkAlphaType;
63 SkImageInfo info = SkImageInfo::MakeS32(width, height, alphaType);
64
65 // FIXME: We have the opportunity to extract color space information here,
66 // though I think it makes sense to wait until we understand how
67 // we want to communicate it to the generator.
68
69 return new SkImageGeneratorCG(info, autoImageSrc.release(), data);
70 }
71
SkImageGeneratorCG(const SkImageInfo & info,const void * imageSrc,SkData * data)72 SkImageGeneratorCG::SkImageGeneratorCG(const SkImageInfo& info, const void* imageSrc, SkData* data)
73 : INHERITED(info)
74 , fImageSrc(imageSrc)
75 , fData(SkRef(data))
76 {}
77
onRefEncodedData()78 SkData* SkImageGeneratorCG::onRefEncodedData() {
79 return SkRef(fData.get());
80 }
81
onGetPixels(const SkImageInfo & info,void * pixels,size_t rowBytes,const Options &)82 bool SkImageGeneratorCG::onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
83 const Options&) {
84 if (kN32_SkColorType != info.colorType()) {
85 // FIXME: Support other colorTypes.
86 return false;
87 }
88
89 switch (info.alphaType()) {
90 case kOpaque_SkAlphaType:
91 if (kOpaque_SkAlphaType != this->getInfo().alphaType()) {
92 return false;
93 }
94 break;
95 case kPremul_SkAlphaType:
96 break;
97 default:
98 return false;
99 }
100
101 CGImageRef image = CGImageSourceCreateImageAtIndex((CGImageSourceRef) fImageSrc.get(), 0,
102 nullptr);
103 if (!image) {
104 return false;
105 }
106 SkAutoTCallVProc<CGImage, CGImageRelease> autoImage(image);
107
108 // FIXME: Using this function (as opposed to swizzling ourselves) greatly
109 // restricts the color and alpha types that we support. If we
110 // swizzle ourselves, we can add support for:
111 // kUnpremul_SkAlphaType
112 // 16-bit per component RGBA
113 // kGray_8_SkColorType
114 // kIndex_8_SkColorType
115 // Additionally, it would be interesting to compare the performance
116 // of SkSwizzler with CG's built in swizzler.
117 if (!SkCopyPixelsFromCGImage(info, rowBytes, pixels, image)) {
118 return false;
119 }
120
121 return true;
122 }
123