blob: 10ac5f3d054ad81a3181753586335528a16a0e2b [file] [log] [blame]
msarett18976312016-03-09 14:20:58 -08001/*
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
Ben Wagnerd89e8112018-09-19 16:52:10 -04008#include "SkCGUtils.h"
9#include "SkEncodedOrigin.h"
msarett18976312016-03-09 14:20:58 -080010#include "SkImageGeneratorCG.h"
Leon Scroggins III0cbc10f2017-10-30 09:07:53 -040011#include "SkPixmapPriv.h"
Ben Wagnerd89e8112018-09-19 16:52:10 -040012#include "SkTemplates.h"
msarett18976312016-03-09 14:20:58 -080013
14#ifdef SK_BUILD_FOR_MAC
15#include <ApplicationServices/ApplicationServices.h>
16#endif
17
18#ifdef SK_BUILD_FOR_IOS
19#include <CoreGraphics/CoreGraphics.h>
20#include <ImageIO/ImageIO.h>
21#include <MobileCoreServices/MobileCoreServices.h>
22#endif
23
Ben Wagnerd89e8112018-09-19 16:52:10 -040024namespace {
25class ImageGeneratorCG : public SkImageGenerator {
26public:
27 /* Takes ownership of the imageSrc */
28 ImageGeneratorCG(const SkImageInfo&, const void* imageSrc, sk_sp<SkData> data, SkEncodedOrigin);
29
30protected:
31 sk_sp<SkData> onRefEncodedData() override;
32
33 bool onGetPixels(const SkImageInfo&, void* pixels, size_t rowBytes, const Options&) override;
34
35private:
36 SkAutoTCallVProc<const void, CFRelease> fImageSrc;
37 sk_sp<SkData> fData;
38 const SkEncodedOrigin fOrigin;
39
40 typedef SkImageGenerator INHERITED;
41};
42
msarett18976312016-03-09 14:20:58 -080043static CGImageSourceRef data_to_CGImageSrc(SkData* data) {
44 CGDataProviderRef cgData = CGDataProviderCreateWithData(data, data->data(), data->size(),
Ben Wagnerd89e8112018-09-19 16:52:10 -040045 nullptr);
msarett18976312016-03-09 14:20:58 -080046 if (!cgData) {
47 return nullptr;
48 }
49 CGImageSourceRef imageSrc = CGImageSourceCreateWithDataProvider(cgData, 0);
50 CGDataProviderRelease(cgData);
51 return imageSrc;
52}
53
Ben Wagnerd89e8112018-09-19 16:52:10 -040054} // namespace
55
Leon Scroggins III0cbc10f2017-10-30 09:07:53 -040056std::unique_ptr<SkImageGenerator> SkImageGeneratorCG::MakeFromEncodedCG(sk_sp<SkData> data) {
57 CGImageSourceRef imageSrc = data_to_CGImageSrc(data.get());
msarett18976312016-03-09 14:20:58 -080058 if (!imageSrc) {
59 return nullptr;
60 }
halcanary9d524f22016-03-29 09:03:52 -070061
msarett18976312016-03-09 14:20:58 -080062 // Make sure we call CFRelease to free the imageSrc. Since CFRelease actually takes
63 // a const void*, we must cast the imageSrc to a const void*.
64 SkAutoTCallVProc<const void, CFRelease> autoImageSrc(imageSrc);
65
66 CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(imageSrc, 0, nullptr);
67 if (!properties) {
68 return nullptr;
69 }
halcanary9d524f22016-03-29 09:03:52 -070070
msarett18976312016-03-09 14:20:58 -080071 CFNumberRef widthRef = (CFNumberRef) (CFDictionaryGetValue(properties,
72 kCGImagePropertyPixelWidth));
73 CFNumberRef heightRef = (CFNumberRef) (CFDictionaryGetValue(properties,
74 kCGImagePropertyPixelHeight));
75 if (nullptr == widthRef || nullptr == heightRef) {
76 return nullptr;
77 }
msarett18976312016-03-09 14:20:58 -080078
79 int width, height;
80 if (!CFNumberGetValue(widthRef, kCFNumberIntType, &width) ||
81 !CFNumberGetValue(heightRef, kCFNumberIntType, &height)) {
82 return nullptr;
83 }
halcanary9d524f22016-03-29 09:03:52 -070084
Leon Scroggins III0cbc10f2017-10-30 09:07:53 -040085 bool hasAlpha = (bool) (CFDictionaryGetValue(properties,
86 kCGImagePropertyHasAlpha));
msarett18976312016-03-09 14:20:58 -080087 SkAlphaType alphaType = hasAlpha ? kPremul_SkAlphaType : kOpaque_SkAlphaType;
Matt Sarett1e86044d2016-12-16 09:02:18 -050088 SkImageInfo info = SkImageInfo::MakeS32(width, height, alphaType);
msarett18976312016-03-09 14:20:58 -080089
Leon Scroggins III0cbc10f2017-10-30 09:07:53 -040090 auto origin = kDefault_SkEncodedOrigin;
91 auto orientationRef = (CFNumberRef) (CFDictionaryGetValue(properties,
92 kCGImagePropertyOrientation));
93 int originInt;
94 if (orientationRef && CFNumberGetValue(orientationRef, kCFNumberIntType, &originInt)) {
95 origin = (SkEncodedOrigin) originInt;
96 }
97
98 if (SkPixmapPriv::ShouldSwapWidthHeight(origin)) {
99 info = SkPixmapPriv::SwapWidthHeight(info);
100 }
101
msarett18976312016-03-09 14:20:58 -0800102 // FIXME: We have the opportunity to extract color space information here,
103 // though I think it makes sense to wait until we understand how
104 // we want to communicate it to the generator.
105
Ben Wagnerd89e8112018-09-19 16:52:10 -0400106 return std::unique_ptr<SkImageGenerator>(new ImageGeneratorCG(info, autoImageSrc.release(),
107 std::move(data), origin));
msarett18976312016-03-09 14:20:58 -0800108}
109
Ben Wagnerd89e8112018-09-19 16:52:10 -0400110ImageGeneratorCG::ImageGeneratorCG(const SkImageInfo& info, const void* imageSrc,
111 sk_sp<SkData> data, SkEncodedOrigin origin)
msarett18976312016-03-09 14:20:58 -0800112 : INHERITED(info)
113 , fImageSrc(imageSrc)
Leon Scroggins III0cbc10f2017-10-30 09:07:53 -0400114 , fData(std::move(data))
115 , fOrigin(origin)
msarett18976312016-03-09 14:20:58 -0800116{}
117
Ben Wagnerd89e8112018-09-19 16:52:10 -0400118sk_sp<SkData> ImageGeneratorCG::onRefEncodedData() {
Ben Wagnerbdf54332018-05-15 14:12:14 -0400119 return fData;
120}
msarett18976312016-03-09 14:20:58 -0800121
Ben Wagnerd89e8112018-09-19 16:52:10 -0400122bool ImageGeneratorCG::onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
123 const Options&)
124{
msarett18976312016-03-09 14:20:58 -0800125 if (kN32_SkColorType != info.colorType()) {
126 // FIXME: Support other colorTypes.
127 return false;
128 }
halcanary9d524f22016-03-29 09:03:52 -0700129
msarett18976312016-03-09 14:20:58 -0800130 switch (info.alphaType()) {
131 case kOpaque_SkAlphaType:
132 if (kOpaque_SkAlphaType != this->getInfo().alphaType()) {
133 return false;
134 }
135 break;
136 case kPremul_SkAlphaType:
137 break;
138 default:
139 return false;
140 }
halcanary9d524f22016-03-29 09:03:52 -0700141
msarett18976312016-03-09 14:20:58 -0800142 CGImageRef image = CGImageSourceCreateImageAtIndex((CGImageSourceRef) fImageSrc.get(), 0,
Ben Wagnerd89e8112018-09-19 16:52:10 -0400143 nullptr);
msarett18976312016-03-09 14:20:58 -0800144 if (!image) {
145 return false;
146 }
147 SkAutoTCallVProc<CGImage, CGImageRelease> autoImage(image);
148
Leon Scroggins III0cbc10f2017-10-30 09:07:53 -0400149 SkPixmap dst(info, pixels, rowBytes);
150 auto decode = [&image](const SkPixmap& pm) {
151 // FIXME: Using SkCopyPixelsFromCGImage (as opposed to swizzling
152 // ourselves) greatly restricts the color and alpha types that we
153 // support. If we swizzle ourselves, we can add support for:
154 // kUnpremul_SkAlphaType
155 // 16-bit per component RGBA
156 // kGray_8_SkColorType
157 // Additionally, it would be interesting to compare the performance
158 // of SkSwizzler with CG's built in swizzler.
159 return SkCopyPixelsFromCGImage(pm, image);
160 };
161 return SkPixmapPriv::Orient(dst, fOrigin, decode);
msarett18976312016-03-09 14:20:58 -0800162}