blob: b1058c6c9dd2019788ab066ee4b6031bdde1a740 [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
8#include "SkImageGeneratorCG.h"
Leon Scroggins III0cbc10f2017-10-30 09:07:53 -04009#include "SkPixmapPriv.h"
msarett18976312016-03-09 14:20:58 -080010
11#ifdef SK_BUILD_FOR_MAC
12#include <ApplicationServices/ApplicationServices.h>
13#endif
14
15#ifdef SK_BUILD_FOR_IOS
16#include <CoreGraphics/CoreGraphics.h>
17#include <ImageIO/ImageIO.h>
18#include <MobileCoreServices/MobileCoreServices.h>
19#endif
20
21static CGImageSourceRef data_to_CGImageSrc(SkData* data) {
22 CGDataProviderRef cgData = CGDataProviderCreateWithData(data, data->data(), data->size(),
23 nullptr);
24 if (!cgData) {
25 return nullptr;
26 }
27 CGImageSourceRef imageSrc = CGImageSourceCreateWithDataProvider(cgData, 0);
28 CGDataProviderRelease(cgData);
29 return imageSrc;
30}
31
Leon Scroggins III0cbc10f2017-10-30 09:07:53 -040032std::unique_ptr<SkImageGenerator> SkImageGeneratorCG::MakeFromEncodedCG(sk_sp<SkData> data) {
33 CGImageSourceRef imageSrc = data_to_CGImageSrc(data.get());
msarett18976312016-03-09 14:20:58 -080034 if (!imageSrc) {
35 return nullptr;
36 }
halcanary9d524f22016-03-29 09:03:52 -070037
msarett18976312016-03-09 14:20:58 -080038 // Make sure we call CFRelease to free the imageSrc. Since CFRelease actually takes
39 // a const void*, we must cast the imageSrc to a const void*.
40 SkAutoTCallVProc<const void, CFRelease> autoImageSrc(imageSrc);
41
42 CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(imageSrc, 0, nullptr);
43 if (!properties) {
44 return nullptr;
45 }
halcanary9d524f22016-03-29 09:03:52 -070046
msarett18976312016-03-09 14:20:58 -080047 CFNumberRef widthRef = (CFNumberRef) (CFDictionaryGetValue(properties,
48 kCGImagePropertyPixelWidth));
49 CFNumberRef heightRef = (CFNumberRef) (CFDictionaryGetValue(properties,
50 kCGImagePropertyPixelHeight));
51 if (nullptr == widthRef || nullptr == heightRef) {
52 return nullptr;
53 }
msarett18976312016-03-09 14:20:58 -080054
55 int width, height;
56 if (!CFNumberGetValue(widthRef, kCFNumberIntType, &width) ||
57 !CFNumberGetValue(heightRef, kCFNumberIntType, &height)) {
58 return nullptr;
59 }
halcanary9d524f22016-03-29 09:03:52 -070060
Leon Scroggins III0cbc10f2017-10-30 09:07:53 -040061 bool hasAlpha = (bool) (CFDictionaryGetValue(properties,
62 kCGImagePropertyHasAlpha));
msarett18976312016-03-09 14:20:58 -080063 SkAlphaType alphaType = hasAlpha ? kPremul_SkAlphaType : kOpaque_SkAlphaType;
Matt Sarett1e86044d2016-12-16 09:02:18 -050064 SkImageInfo info = SkImageInfo::MakeS32(width, height, alphaType);
msarett18976312016-03-09 14:20:58 -080065
Leon Scroggins III0cbc10f2017-10-30 09:07:53 -040066 auto origin = kDefault_SkEncodedOrigin;
67 auto orientationRef = (CFNumberRef) (CFDictionaryGetValue(properties,
68 kCGImagePropertyOrientation));
69 int originInt;
70 if (orientationRef && CFNumberGetValue(orientationRef, kCFNumberIntType, &originInt)) {
71 origin = (SkEncodedOrigin) originInt;
72 }
73
74 if (SkPixmapPriv::ShouldSwapWidthHeight(origin)) {
75 info = SkPixmapPriv::SwapWidthHeight(info);
76 }
77
msarett18976312016-03-09 14:20:58 -080078 // FIXME: We have the opportunity to extract color space information here,
79 // though I think it makes sense to wait until we understand how
80 // we want to communicate it to the generator.
81
Leon Scroggins III0cbc10f2017-10-30 09:07:53 -040082 return std::unique_ptr<SkImageGenerator>(new SkImageGeneratorCG(info, autoImageSrc.release(),
83 std::move(data), origin));
msarett18976312016-03-09 14:20:58 -080084}
85
Leon Scroggins III0cbc10f2017-10-30 09:07:53 -040086SkImageGeneratorCG::SkImageGeneratorCG(const SkImageInfo& info, const void* imageSrc,
87 sk_sp<SkData> data, SkEncodedOrigin origin)
msarett18976312016-03-09 14:20:58 -080088 : INHERITED(info)
89 , fImageSrc(imageSrc)
Leon Scroggins III0cbc10f2017-10-30 09:07:53 -040090 , fData(std::move(data))
91 , fOrigin(origin)
msarett18976312016-03-09 14:20:58 -080092{}
93
Ben Wagnerbdf54332018-05-15 14:12:14 -040094sk_sp<SkData> SkImageGeneratorCG::onRefEncodedData() {
95 return fData;
96}
msarett18976312016-03-09 14:20:58 -080097
98bool SkImageGeneratorCG::onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
Matt Sarettebb1b5c2017-05-12 11:41:27 -040099 const Options&) {
msarett18976312016-03-09 14:20:58 -0800100 if (kN32_SkColorType != info.colorType()) {
101 // FIXME: Support other colorTypes.
102 return false;
103 }
halcanary9d524f22016-03-29 09:03:52 -0700104
msarett18976312016-03-09 14:20:58 -0800105 switch (info.alphaType()) {
106 case kOpaque_SkAlphaType:
107 if (kOpaque_SkAlphaType != this->getInfo().alphaType()) {
108 return false;
109 }
110 break;
111 case kPremul_SkAlphaType:
112 break;
113 default:
114 return false;
115 }
halcanary9d524f22016-03-29 09:03:52 -0700116
msarett18976312016-03-09 14:20:58 -0800117 CGImageRef image = CGImageSourceCreateImageAtIndex((CGImageSourceRef) fImageSrc.get(), 0,
118 nullptr);
119 if (!image) {
120 return false;
121 }
122 SkAutoTCallVProc<CGImage, CGImageRelease> autoImage(image);
123
Leon Scroggins III0cbc10f2017-10-30 09:07:53 -0400124 SkPixmap dst(info, pixels, rowBytes);
125 auto decode = [&image](const SkPixmap& pm) {
126 // FIXME: Using SkCopyPixelsFromCGImage (as opposed to swizzling
127 // ourselves) greatly restricts the color and alpha types that we
128 // support. If we swizzle ourselves, we can add support for:
129 // kUnpremul_SkAlphaType
130 // 16-bit per component RGBA
131 // kGray_8_SkColorType
132 // Additionally, it would be interesting to compare the performance
133 // of SkSwizzler with CG's built in swizzler.
134 return SkCopyPixelsFromCGImage(pm, image);
135 };
136 return SkPixmapPriv::Orient(dst, fOrigin, decode);
msarett18976312016-03-09 14:20:58 -0800137}