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 "SkImageGeneratorCG.h" 9 10 #ifdef SK_BUILD_FOR_MAC 11 #include <ApplicationServices/ApplicationServices.h> 12 #endif 13 14 #ifdef SK_BUILD_FOR_IOS 15 #include <CoreGraphics/CoreGraphics.h> 16 #include <ImageIO/ImageIO.h> 17 #include <MobileCoreServices/MobileCoreServices.h> 18 #endif 19 20 static CGImageSourceRef data_to_CGImageSrc(SkData* data) { 21 CGDataProviderRef cgData = CGDataProviderCreateWithData(data, data->data(), data->size(), 22 nullptr); 23 if (!cgData) { 24 return nullptr; 25 } 26 CGImageSourceRef imageSrc = CGImageSourceCreateWithDataProvider(cgData, 0); 27 CGDataProviderRelease(cgData); 28 return imageSrc; 29 } 30 31 SkImageGenerator* SkImageGeneratorCG::NewFromEncodedCG(SkData* data) { 32 CGImageSourceRef imageSrc = data_to_CGImageSrc(data); 33 if (!imageSrc) { 34 return nullptr; 35 } 36 37 // Make sure we call CFRelease to free the imageSrc. Since CFRelease actually takes 38 // a const void*, we must cast the imageSrc to a const void*. 39 SkAutoTCallVProc<const void, CFRelease> autoImageSrc(imageSrc); 40 41 CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(imageSrc, 0, nullptr); 42 if (!properties) { 43 return nullptr; 44 } 45 46 CFNumberRef widthRef = (CFNumberRef) (CFDictionaryGetValue(properties, 47 kCGImagePropertyPixelWidth)); 48 CFNumberRef heightRef = (CFNumberRef) (CFDictionaryGetValue(properties, 49 kCGImagePropertyPixelHeight)); 50 if (nullptr == widthRef || nullptr == heightRef) { 51 return nullptr; 52 } 53 bool hasAlpha = (bool) (CFDictionaryGetValue(properties, 54 kCGImagePropertyHasAlpha)); 55 56 int width, height; 57 if (!CFNumberGetValue(widthRef, kCFNumberIntType, &width) || 58 !CFNumberGetValue(heightRef, kCFNumberIntType, &height)) { 59 return nullptr; 60 } 61 62 SkAlphaType alphaType = hasAlpha ? kPremul_SkAlphaType : kOpaque_SkAlphaType; 63 SkImageInfo info = SkImageInfo::MakeS32(width, height, alphaType); 64 65 // FIXME: We have the opportunity to extract color space information here, 66 // though I think it makes sense to wait until we understand how 67 // we want to communicate it to the generator. 68 69 return new SkImageGeneratorCG(info, autoImageSrc.release(), data); 70 } 71 72 SkImageGeneratorCG::SkImageGeneratorCG(const SkImageInfo& info, const void* imageSrc, SkData* data) 73 : INHERITED(info) 74 , fImageSrc(imageSrc) 75 , fData(SkRef(data)) 76 {} 77 78 SkData* SkImageGeneratorCG::onRefEncodedData() { 79 return SkRef(fData.get()); 80 } 81 82 bool SkImageGeneratorCG::onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, 83 const Options&) { 84 if (kN32_SkColorType != info.colorType()) { 85 // FIXME: Support other colorTypes. 86 return false; 87 } 88 89 switch (info.alphaType()) { 90 case kOpaque_SkAlphaType: 91 if (kOpaque_SkAlphaType != this->getInfo().alphaType()) { 92 return false; 93 } 94 break; 95 case kPremul_SkAlphaType: 96 break; 97 default: 98 return false; 99 } 100 101 CGImageRef image = CGImageSourceCreateImageAtIndex((CGImageSourceRef) fImageSrc.get(), 0, 102 nullptr); 103 if (!image) { 104 return false; 105 } 106 SkAutoTCallVProc<CGImage, CGImageRelease> autoImage(image); 107 108 // FIXME: Using this function (as opposed to swizzling ourselves) greatly 109 // restricts the color and alpha types that we support. If we 110 // swizzle ourselves, we can add support for: 111 // kUnpremul_SkAlphaType 112 // 16-bit per component RGBA 113 // kGray_8_SkColorType 114 // kIndex_8_SkColorType 115 // Additionally, it would be interesting to compare the performance 116 // of SkSwizzler with CG's built in swizzler. 117 if (!SkCopyPixelsFromCGImage(info, rowBytes, pixels, image)) { 118 return false; 119 } 120 121 return true; 122 } 123