• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "include/codec/SkEncodedOrigin.h"
9 #include "include/ports/SkImageGeneratorCG.h"
10 #include "include/private/SkTemplates.h"
11 #include "include/utils/mac/SkCGUtils.h"
12 #include "src/core/SkPixmapPriv.h"
13 #include "src/utils/mac/SkUniqueCFRef.h"
14 
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 
25 namespace {
26 class ImageGeneratorCG : public SkImageGenerator {
27 public:
28     ImageGeneratorCG(const SkImageInfo&, SkUniqueCFRef<CGImageSourceRef> imageSrc,
29                      sk_sp<SkData> data, SkEncodedOrigin);
30 
31 protected:
32     sk_sp<SkData> onRefEncodedData() override;
33 
34     bool onGetPixels(const SkImageInfo&, void* pixels, size_t rowBytes, const Options&) override;
35 
36 private:
37     const SkUniqueCFRef<CGImageSourceRef> fImageSrc;
38     const sk_sp<SkData> fData;
39     const SkEncodedOrigin fOrigin;
40 
41     typedef SkImageGenerator INHERITED;
42 };
43 
data_to_CGImageSrc(SkData * data)44 static SkUniqueCFRef<CGImageSourceRef> data_to_CGImageSrc(SkData* data) {
45     SkUniqueCFRef<CGDataProviderRef> cgData(
46             CGDataProviderCreateWithData(data, data->data(), data->size(), nullptr));
47     if (!cgData) {
48         return nullptr;
49     }
50     return SkUniqueCFRef<CGImageSourceRef>(
51             CGImageSourceCreateWithDataProvider(cgData.get(), nullptr));
52 }
53 
54 }  // namespace
55 
MakeFromEncodedCG(sk_sp<SkData> data)56 std::unique_ptr<SkImageGenerator> SkImageGeneratorCG::MakeFromEncodedCG(sk_sp<SkData> data) {
57     SkUniqueCFRef<CGImageSourceRef> imageSrc = data_to_CGImageSrc(data.get());
58     if (!imageSrc) {
59         return nullptr;
60     }
61 
62     SkUniqueCFRef<CFDictionaryRef> properties(
63             CGImageSourceCopyPropertiesAtIndex(imageSrc.get(), 0, nullptr));
64     if (!properties) {
65         return nullptr;
66     }
67 
68     CFNumberRef widthRef = static_cast<CFNumberRef>(
69             CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelWidth));
70     CFNumberRef heightRef = static_cast<CFNumberRef>(
71             CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelHeight));
72     if (nullptr == widthRef || nullptr == heightRef) {
73         return nullptr;
74     }
75 
76     int width, height;
77     if (!CFNumberGetValue(widthRef , kCFNumberIntType, &width ) ||
78         !CFNumberGetValue(heightRef, kCFNumberIntType, &height))
79     {
80         return nullptr;
81     }
82 
83     bool hasAlpha = bool(CFDictionaryGetValue(properties.get(), kCGImagePropertyHasAlpha));
84     SkAlphaType alphaType = hasAlpha ? kPremul_SkAlphaType : kOpaque_SkAlphaType;
85     SkImageInfo info = SkImageInfo::MakeS32(width, height, alphaType);
86 
87     SkEncodedOrigin origin = kDefault_SkEncodedOrigin;
88     CFNumberRef orientationRef = static_cast<CFNumberRef>(
89             CFDictionaryGetValue(properties.get(), kCGImagePropertyOrientation));
90     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 
99     // 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 
103     return std::unique_ptr<SkImageGenerator>(new ImageGeneratorCG(info, std::move(imageSrc),
104                                                                   std::move(data), origin));
105 }
106 
ImageGeneratorCG(const SkImageInfo & info,SkUniqueCFRef<CGImageSourceRef> src,sk_sp<SkData> data,SkEncodedOrigin origin)107 ImageGeneratorCG::ImageGeneratorCG(const SkImageInfo& info, SkUniqueCFRef<CGImageSourceRef> src,
108                                    sk_sp<SkData> data, SkEncodedOrigin origin)
109     : INHERITED(info)
110     , fImageSrc(std::move(src))
111     , fData(std::move(data))
112     , fOrigin(origin)
113 {}
114 
onRefEncodedData()115 sk_sp<SkData> ImageGeneratorCG::onRefEncodedData() {
116     return fData;
117 }
118 
onGetPixels(const SkImageInfo & info,void * pixels,size_t rowBytes,const Options &)119 bool ImageGeneratorCG::onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
120                                    const Options&)
121 {
122     if (kN32_SkColorType != info.colorType()) {
123         // FIXME: Support other colorTypes.
124         return false;
125     }
126 
127     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     }
138 
139     SkUniqueCFRef<CGImageRef> image(CGImageSourceCreateImageAtIndex(fImageSrc.get(), 0, nullptr));
140     if (!image) {
141         return false;
142     }
143 
144     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.
154         return SkCopyPixelsFromCGImage(pm, image.get());
155     };
156     return SkPixmapPriv::Orient(dst, fOrigin, decode);
157 }
158