xref: /aosp_15_r20/external/skia/src/ports/SkImageGeneratorCG.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2016 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker #include "include/ports/SkImageGeneratorCG.h"
8*c8dee2aaSAndroid Build Coastguard Worker 
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/codec/SkEncodedOrigin.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTemplates.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/utils/mac/SkCGUtils.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "src/codec/SkPixmapUtilsPriv.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "src/utils/mac/SkUniqueCFRef.h"
14*c8dee2aaSAndroid Build Coastguard Worker 
15*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_BUILD_FOR_MAC
16*c8dee2aaSAndroid Build Coastguard Worker #include <ApplicationServices/ApplicationServices.h>
17*c8dee2aaSAndroid Build Coastguard Worker #endif
18*c8dee2aaSAndroid Build Coastguard Worker 
19*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_BUILD_FOR_IOS
20*c8dee2aaSAndroid Build Coastguard Worker #include <CoreGraphics/CoreGraphics.h>
21*c8dee2aaSAndroid Build Coastguard Worker #include <ImageIO/ImageIO.h>
22*c8dee2aaSAndroid Build Coastguard Worker #include <MobileCoreServices/MobileCoreServices.h>
23*c8dee2aaSAndroid Build Coastguard Worker #endif
24*c8dee2aaSAndroid Build Coastguard Worker 
25*c8dee2aaSAndroid Build Coastguard Worker namespace {
26*c8dee2aaSAndroid Build Coastguard Worker class ImageGeneratorCG : public SkImageGenerator {
27*c8dee2aaSAndroid Build Coastguard Worker public:
28*c8dee2aaSAndroid Build Coastguard Worker     ImageGeneratorCG(const SkImageInfo&, SkUniqueCFRef<CGImageSourceRef> imageSrc,
29*c8dee2aaSAndroid Build Coastguard Worker                      sk_sp<SkData> data, SkEncodedOrigin);
30*c8dee2aaSAndroid Build Coastguard Worker 
31*c8dee2aaSAndroid Build Coastguard Worker protected:
32*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkData> onRefEncodedData() override;
33*c8dee2aaSAndroid Build Coastguard Worker 
34*c8dee2aaSAndroid Build Coastguard Worker     bool onGetPixels(const SkImageInfo&, void* pixels, size_t rowBytes, const Options&) override;
35*c8dee2aaSAndroid Build Coastguard Worker 
36*c8dee2aaSAndroid Build Coastguard Worker private:
37*c8dee2aaSAndroid Build Coastguard Worker     const SkUniqueCFRef<CGImageSourceRef> fImageSrc;
38*c8dee2aaSAndroid Build Coastguard Worker     const sk_sp<SkData> fData;
39*c8dee2aaSAndroid Build Coastguard Worker     const SkEncodedOrigin fOrigin;
40*c8dee2aaSAndroid Build Coastguard Worker 
41*c8dee2aaSAndroid Build Coastguard Worker     using INHERITED = SkImageGenerator;
42*c8dee2aaSAndroid Build Coastguard Worker };
43*c8dee2aaSAndroid Build Coastguard Worker 
data_to_CGImageSrc(SkData * data)44*c8dee2aaSAndroid Build Coastguard Worker static SkUniqueCFRef<CGImageSourceRef> data_to_CGImageSrc(SkData* data) {
45*c8dee2aaSAndroid Build Coastguard Worker     SkUniqueCFRef<CGDataProviderRef> cgData(
46*c8dee2aaSAndroid Build Coastguard Worker             CGDataProviderCreateWithData(data, data->data(), data->size(), nullptr));
47*c8dee2aaSAndroid Build Coastguard Worker     if (!cgData) {
48*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
49*c8dee2aaSAndroid Build Coastguard Worker     }
50*c8dee2aaSAndroid Build Coastguard Worker     return SkUniqueCFRef<CGImageSourceRef>(
51*c8dee2aaSAndroid Build Coastguard Worker             CGImageSourceCreateWithDataProvider(cgData.get(), nullptr));
52*c8dee2aaSAndroid Build Coastguard Worker }
53*c8dee2aaSAndroid Build Coastguard Worker 
54*c8dee2aaSAndroid Build Coastguard Worker }  // namespace
55*c8dee2aaSAndroid Build Coastguard Worker 
MakeFromEncodedCG(sk_sp<SkData> data)56*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<SkImageGenerator> SkImageGeneratorCG::MakeFromEncodedCG(sk_sp<SkData> data) {
57*c8dee2aaSAndroid Build Coastguard Worker     SkUniqueCFRef<CGImageSourceRef> imageSrc = data_to_CGImageSrc(data.get());
58*c8dee2aaSAndroid Build Coastguard Worker     if (!imageSrc) {
59*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
60*c8dee2aaSAndroid Build Coastguard Worker     }
61*c8dee2aaSAndroid Build Coastguard Worker 
62*c8dee2aaSAndroid Build Coastguard Worker     SkUniqueCFRef<CFDictionaryRef> properties(
63*c8dee2aaSAndroid Build Coastguard Worker             CGImageSourceCopyPropertiesAtIndex(imageSrc.get(), 0, nullptr));
64*c8dee2aaSAndroid Build Coastguard Worker     if (!properties) {
65*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
66*c8dee2aaSAndroid Build Coastguard Worker     }
67*c8dee2aaSAndroid Build Coastguard Worker 
68*c8dee2aaSAndroid Build Coastguard Worker     CFNumberRef widthRef = static_cast<CFNumberRef>(
69*c8dee2aaSAndroid Build Coastguard Worker             CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelWidth));
70*c8dee2aaSAndroid Build Coastguard Worker     CFNumberRef heightRef = static_cast<CFNumberRef>(
71*c8dee2aaSAndroid Build Coastguard Worker             CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelHeight));
72*c8dee2aaSAndroid Build Coastguard Worker     if (nullptr == widthRef || nullptr == heightRef) {
73*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
74*c8dee2aaSAndroid Build Coastguard Worker     }
75*c8dee2aaSAndroid Build Coastguard Worker 
76*c8dee2aaSAndroid Build Coastguard Worker     int width, height;
77*c8dee2aaSAndroid Build Coastguard Worker     if (!CFNumberGetValue(widthRef , kCFNumberIntType, &width ) ||
78*c8dee2aaSAndroid Build Coastguard Worker         !CFNumberGetValue(heightRef, kCFNumberIntType, &height))
79*c8dee2aaSAndroid Build Coastguard Worker     {
80*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
81*c8dee2aaSAndroid Build Coastguard Worker     }
82*c8dee2aaSAndroid Build Coastguard Worker 
83*c8dee2aaSAndroid Build Coastguard Worker     bool hasAlpha = bool(CFDictionaryGetValue(properties.get(), kCGImagePropertyHasAlpha));
84*c8dee2aaSAndroid Build Coastguard Worker     SkAlphaType alphaType = hasAlpha ? kPremul_SkAlphaType : kOpaque_SkAlphaType;
85*c8dee2aaSAndroid Build Coastguard Worker     SkImageInfo info = SkImageInfo::MakeS32(width, height, alphaType);
86*c8dee2aaSAndroid Build Coastguard Worker 
87*c8dee2aaSAndroid Build Coastguard Worker     SkEncodedOrigin origin = kDefault_SkEncodedOrigin;
88*c8dee2aaSAndroid Build Coastguard Worker     CFNumberRef orientationRef = static_cast<CFNumberRef>(
89*c8dee2aaSAndroid Build Coastguard Worker             CFDictionaryGetValue(properties.get(), kCGImagePropertyOrientation));
90*c8dee2aaSAndroid Build Coastguard Worker     int originInt;
91*c8dee2aaSAndroid Build Coastguard Worker     if (orientationRef && CFNumberGetValue(orientationRef, kCFNumberIntType, &originInt)) {
92*c8dee2aaSAndroid Build Coastguard Worker         origin = (SkEncodedOrigin) originInt;
93*c8dee2aaSAndroid Build Coastguard Worker     }
94*c8dee2aaSAndroid Build Coastguard Worker 
95*c8dee2aaSAndroid Build Coastguard Worker     if (SkEncodedOriginSwapsWidthHeight(origin)) {
96*c8dee2aaSAndroid Build Coastguard Worker         info = SkPixmapUtils::SwapWidthHeight(info);
97*c8dee2aaSAndroid Build Coastguard Worker     }
98*c8dee2aaSAndroid Build Coastguard Worker 
99*c8dee2aaSAndroid Build Coastguard Worker     // FIXME: We have the opportunity to extract color space information here,
100*c8dee2aaSAndroid Build Coastguard Worker     //        though I think it makes sense to wait until we understand how
101*c8dee2aaSAndroid Build Coastguard Worker     //        we want to communicate it to the generator.
102*c8dee2aaSAndroid Build Coastguard Worker 
103*c8dee2aaSAndroid Build Coastguard Worker     return std::unique_ptr<SkImageGenerator>(new ImageGeneratorCG(info, std::move(imageSrc),
104*c8dee2aaSAndroid Build Coastguard Worker                                                                   std::move(data), origin));
105*c8dee2aaSAndroid Build Coastguard Worker }
106*c8dee2aaSAndroid Build Coastguard Worker 
ImageGeneratorCG(const SkImageInfo & info,SkUniqueCFRef<CGImageSourceRef> src,sk_sp<SkData> data,SkEncodedOrigin origin)107*c8dee2aaSAndroid Build Coastguard Worker ImageGeneratorCG::ImageGeneratorCG(const SkImageInfo& info, SkUniqueCFRef<CGImageSourceRef> src,
108*c8dee2aaSAndroid Build Coastguard Worker                                    sk_sp<SkData> data, SkEncodedOrigin origin)
109*c8dee2aaSAndroid Build Coastguard Worker     : INHERITED(info)
110*c8dee2aaSAndroid Build Coastguard Worker     , fImageSrc(std::move(src))
111*c8dee2aaSAndroid Build Coastguard Worker     , fData(std::move(data))
112*c8dee2aaSAndroid Build Coastguard Worker     , fOrigin(origin)
113*c8dee2aaSAndroid Build Coastguard Worker {}
114*c8dee2aaSAndroid Build Coastguard Worker 
onRefEncodedData()115*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkData> ImageGeneratorCG::onRefEncodedData() {
116*c8dee2aaSAndroid Build Coastguard Worker     return fData;
117*c8dee2aaSAndroid Build Coastguard Worker }
118*c8dee2aaSAndroid Build Coastguard Worker 
onGetPixels(const SkImageInfo & info,void * pixels,size_t rowBytes,const Options &)119*c8dee2aaSAndroid Build Coastguard Worker bool ImageGeneratorCG::onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
120*c8dee2aaSAndroid Build Coastguard Worker                                    const Options&)
121*c8dee2aaSAndroid Build Coastguard Worker {
122*c8dee2aaSAndroid Build Coastguard Worker     if (kN32_SkColorType != info.colorType()) {
123*c8dee2aaSAndroid Build Coastguard Worker         // FIXME: Support other colorTypes.
124*c8dee2aaSAndroid Build Coastguard Worker         return false;
125*c8dee2aaSAndroid Build Coastguard Worker     }
126*c8dee2aaSAndroid Build Coastguard Worker 
127*c8dee2aaSAndroid Build Coastguard Worker     switch (info.alphaType()) {
128*c8dee2aaSAndroid Build Coastguard Worker         case kOpaque_SkAlphaType:
129*c8dee2aaSAndroid Build Coastguard Worker             if (kOpaque_SkAlphaType != this->getInfo().alphaType()) {
130*c8dee2aaSAndroid Build Coastguard Worker                 return false;
131*c8dee2aaSAndroid Build Coastguard Worker             }
132*c8dee2aaSAndroid Build Coastguard Worker             break;
133*c8dee2aaSAndroid Build Coastguard Worker         case kPremul_SkAlphaType:
134*c8dee2aaSAndroid Build Coastguard Worker             break;
135*c8dee2aaSAndroid Build Coastguard Worker         default:
136*c8dee2aaSAndroid Build Coastguard Worker             return false;
137*c8dee2aaSAndroid Build Coastguard Worker     }
138*c8dee2aaSAndroid Build Coastguard Worker 
139*c8dee2aaSAndroid Build Coastguard Worker     SkUniqueCFRef<CGImageRef> image(CGImageSourceCreateImageAtIndex(fImageSrc.get(), 0, nullptr));
140*c8dee2aaSAndroid Build Coastguard Worker     if (!image) {
141*c8dee2aaSAndroid Build Coastguard Worker         return false;
142*c8dee2aaSAndroid Build Coastguard Worker     }
143*c8dee2aaSAndroid Build Coastguard Worker 
144*c8dee2aaSAndroid Build Coastguard Worker     SkPixmap dst(info, pixels, rowBytes);
145*c8dee2aaSAndroid Build Coastguard Worker     auto decode = [&image](const SkPixmap& pm) {
146*c8dee2aaSAndroid Build Coastguard Worker         // FIXME: Using SkCopyPixelsFromCGImage (as opposed to swizzling
147*c8dee2aaSAndroid Build Coastguard Worker         // ourselves) greatly restricts the color and alpha types that we
148*c8dee2aaSAndroid Build Coastguard Worker         // support.  If we swizzle ourselves, we can add support for:
149*c8dee2aaSAndroid Build Coastguard Worker         //     kUnpremul_SkAlphaType
150*c8dee2aaSAndroid Build Coastguard Worker         //     16-bit per component RGBA
151*c8dee2aaSAndroid Build Coastguard Worker         //     kGray_8_SkColorType
152*c8dee2aaSAndroid Build Coastguard Worker         // Additionally, it would be interesting to compare the performance
153*c8dee2aaSAndroid Build Coastguard Worker         // of SkSwizzler with CG's built in swizzler.
154*c8dee2aaSAndroid Build Coastguard Worker         return SkCopyPixelsFromCGImage(pm, image.get());
155*c8dee2aaSAndroid Build Coastguard Worker     };
156*c8dee2aaSAndroid Build Coastguard Worker     return SkPixmapUtils::Orient(dst, fOrigin, decode);
157*c8dee2aaSAndroid Build Coastguard Worker }
158