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 25namespace { 26class ImageGeneratorCG : public SkImageGenerator { 27public: 28 ImageGeneratorCG(const SkImageInfo&, SkUniqueCFRef<CGImageSourceRef> imageSrc, 29 sk_sp<SkData> data, SkEncodedOrigin); 30 31protected: 32 sk_sp<SkData> onRefEncodedData() override; 33 34 bool onGetPixels(const SkImageInfo&, void* pixels, size_t rowBytes, const Options&) override; 35 36private: 37 const SkUniqueCFRef<CGImageSourceRef> fImageSrc; 38 const sk_sp<SkData> fData; 39 const SkEncodedOrigin fOrigin; 40 41 using INHERITED = SkImageGenerator; 42}; 43 44static 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 56std::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 (SkEncodedOriginSwapsWidthHeight(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 107ImageGeneratorCG::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 115sk_sp<SkData> ImageGeneratorCG::onRefEncodedData() { 116 return fData; 117} 118 119bool 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