blob: a716cab881fda8988a3967f7d9f4f56dc0891510 [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 Wagner7b562292018-09-19 22:31:07 -04008#include "mac/SkUniqueCFRef.h"
Ben Wagnerd89e8112018-09-19 16:52:10 -04009#include "SkCGUtils.h"
10#include "SkEncodedOrigin.h"
msarett18976312016-03-09 14:20:58 -080011#include "SkImageGeneratorCG.h"
Leon Scroggins III0cbc10f2017-10-30 09:07:53 -040012#include "SkPixmapPriv.h"
Ben Wagnerd89e8112018-09-19 16:52:10 -040013#include "SkTemplates.h"
msarett18976312016-03-09 14:20:58 -080014
15#ifdef SK_BUILD_FOR_MAC
16#include <ApplicationServices/ApplicationServices.h>
17#endif
18
19#ifdef SK_BUILD_FOR_IOS
20#include <CoreGraphics/CoreGraphics.h>
21#include <ImageIO/ImageIO.h>
22#include <MobileCoreServices/MobileCoreServices.h>
23#endif
24
Ben Wagnerd89e8112018-09-19 16:52:10 -040025namespace {
26class ImageGeneratorCG : public SkImageGenerator {
27public:
Ben Wagner7b562292018-09-19 22:31:07 -040028 ImageGeneratorCG(const SkImageInfo&, SkUniqueCFRef<CGImageSourceRef> imageSrc,
29 sk_sp<SkData> data, SkEncodedOrigin);
Ben Wagnerd89e8112018-09-19 16:52:10 -040030
31protected:
32 sk_sp<SkData> onRefEncodedData() override;
33
34 bool onGetPixels(const SkImageInfo&, void* pixels, size_t rowBytes, const Options&) override;
35
36private:
Ben Wagner7b562292018-09-19 22:31:07 -040037 const SkUniqueCFRef<CGImageSourceRef> fImageSrc;
38 const sk_sp<SkData> fData;
39 const SkEncodedOrigin fOrigin;
Ben Wagnerd89e8112018-09-19 16:52:10 -040040
41 typedef SkImageGenerator INHERITED;
42};
43
Ben Wagner7b562292018-09-19 22:31:07 -040044static SkUniqueCFRef<CGImageSourceRef> data_to_CGImageSrc(SkData* data) {
45 SkUniqueCFRef<CGDataProviderRef> cgData(
46 CGDataProviderCreateWithData(data, data->data(), data->size(), nullptr));
msarett18976312016-03-09 14:20:58 -080047 if (!cgData) {
48 return nullptr;
49 }
Ben Wagner7b562292018-09-19 22:31:07 -040050 return SkUniqueCFRef<CGImageSourceRef>(
51 CGImageSourceCreateWithDataProvider(cgData.get(), nullptr));
msarett18976312016-03-09 14:20:58 -080052}
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) {
Ben Wagner7b562292018-09-19 22:31:07 -040057 SkUniqueCFRef<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
Ben Wagner7b562292018-09-19 22:31:07 -040062 SkUniqueCFRef<CFDictionaryRef> properties(
63 CGImageSourceCopyPropertiesAtIndex(imageSrc.get(), 0, nullptr));
msarett18976312016-03-09 14:20:58 -080064 if (!properties) {
65 return nullptr;
66 }
halcanary9d524f22016-03-29 09:03:52 -070067
Ben Wagner7b562292018-09-19 22:31:07 -040068 CFNumberRef widthRef = static_cast<CFNumberRef>(
69 CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelWidth));
70 CFNumberRef heightRef = static_cast<CFNumberRef>(
71 CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelHeight));
msarett18976312016-03-09 14:20:58 -080072 if (nullptr == widthRef || nullptr == heightRef) {
73 return nullptr;
74 }
msarett18976312016-03-09 14:20:58 -080075
76 int width, height;
Ben Wagner7b562292018-09-19 22:31:07 -040077 if (!CFNumberGetValue(widthRef , kCFNumberIntType, &width ) ||
78 !CFNumberGetValue(heightRef, kCFNumberIntType, &height))
79 {
msarett18976312016-03-09 14:20:58 -080080 return nullptr;
81 }
halcanary9d524f22016-03-29 09:03:52 -070082
Ben Wagner7b562292018-09-19 22:31:07 -040083 bool hasAlpha = bool(CFDictionaryGetValue(properties.get(), kCGImagePropertyHasAlpha));
msarett18976312016-03-09 14:20:58 -080084 SkAlphaType alphaType = hasAlpha ? kPremul_SkAlphaType : kOpaque_SkAlphaType;
Matt Sarett1e86044d2016-12-16 09:02:18 -050085 SkImageInfo info = SkImageInfo::MakeS32(width, height, alphaType);
msarett18976312016-03-09 14:20:58 -080086
Ben Wagner7b562292018-09-19 22:31:07 -040087 SkEncodedOrigin origin = kDefault_SkEncodedOrigin;
88 CFNumberRef orientationRef = static_cast<CFNumberRef>(
89 CFDictionaryGetValue(properties.get(), kCGImagePropertyOrientation));
Leon Scroggins III0cbc10f2017-10-30 09:07:53 -040090 int originInt;
91 if (orientationRef && CFNumberGetValue(orientationRef, kCFNumberIntType, &originInt)) {
92 origin = (SkEncodedOrigin) originInt;
93 }
94
95 if (SkPixmapPriv::ShouldSwapWidthHeight(origin)) {
96 info = SkPixmapPriv::SwapWidthHeight(info);
97 }
98
msarett18976312016-03-09 14:20:58 -080099 // FIXME: We have the opportunity to extract color space information here,
100 // though I think it makes sense to wait until we understand how
101 // we want to communicate it to the generator.
102
Ben Wagner7b562292018-09-19 22:31:07 -0400103 return std::unique_ptr<SkImageGenerator>(new ImageGeneratorCG(info, std::move(imageSrc),
Ben Wagnerd89e8112018-09-19 16:52:10 -0400104 std::move(data), origin));
msarett18976312016-03-09 14:20:58 -0800105}
106
Ben Wagner7b562292018-09-19 22:31:07 -0400107ImageGeneratorCG::ImageGeneratorCG(const SkImageInfo& info, SkUniqueCFRef<CGImageSourceRef> src,
Ben Wagnerd89e8112018-09-19 16:52:10 -0400108 sk_sp<SkData> data, SkEncodedOrigin origin)
msarett18976312016-03-09 14:20:58 -0800109 : INHERITED(info)
Ben Wagner7b562292018-09-19 22:31:07 -0400110 , fImageSrc(std::move(src))
Leon Scroggins III0cbc10f2017-10-30 09:07:53 -0400111 , fData(std::move(data))
112 , fOrigin(origin)
msarett18976312016-03-09 14:20:58 -0800113{}
114
Ben Wagnerd89e8112018-09-19 16:52:10 -0400115sk_sp<SkData> ImageGeneratorCG::onRefEncodedData() {
Ben Wagnerbdf54332018-05-15 14:12:14 -0400116 return fData;
117}
msarett18976312016-03-09 14:20:58 -0800118
Ben Wagnerd89e8112018-09-19 16:52:10 -0400119bool ImageGeneratorCG::onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
120 const Options&)
121{
msarett18976312016-03-09 14:20:58 -0800122 if (kN32_SkColorType != info.colorType()) {
123 // FIXME: Support other colorTypes.
124 return false;
125 }
halcanary9d524f22016-03-29 09:03:52 -0700126
msarett18976312016-03-09 14:20:58 -0800127 switch (info.alphaType()) {
128 case kOpaque_SkAlphaType:
129 if (kOpaque_SkAlphaType != this->getInfo().alphaType()) {
130 return false;
131 }
132 break;
133 case kPremul_SkAlphaType:
134 break;
135 default:
136 return false;
137 }
halcanary9d524f22016-03-29 09:03:52 -0700138
Ben Wagner7b562292018-09-19 22:31:07 -0400139 SkUniqueCFRef<CGImageRef> image(CGImageSourceCreateImageAtIndex(fImageSrc.get(), 0, nullptr));
msarett18976312016-03-09 14:20:58 -0800140 if (!image) {
141 return false;
142 }
msarett18976312016-03-09 14:20:58 -0800143
Leon Scroggins III0cbc10f2017-10-30 09:07:53 -0400144 SkPixmap dst(info, pixels, rowBytes);
145 auto decode = [&image](const SkPixmap& pm) {
146 // FIXME: Using SkCopyPixelsFromCGImage (as opposed to swizzling
147 // ourselves) greatly restricts the color and alpha types that we
148 // support. If we swizzle ourselves, we can add support for:
149 // kUnpremul_SkAlphaType
150 // 16-bit per component RGBA
151 // kGray_8_SkColorType
152 // Additionally, it would be interesting to compare the performance
153 // of SkSwizzler with CG's built in swizzler.
Ben Wagner7b562292018-09-19 22:31:07 -0400154 return SkCopyPixelsFromCGImage(pm, image.get());
Leon Scroggins III0cbc10f2017-10-30 09:07:53 -0400155 };
156 return SkPixmapPriv::Orient(dst, fOrigin, decode);
msarett18976312016-03-09 14:20:58 -0800157}