1 // Copyright 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "skia/ext/skia_utils_ios.h" 6 7 #import <ImageIO/ImageIO.h> 8 #import <UIKit/UIKit.h> 9 10 #include "base/logging.h" 11 #include "base/mac/scoped_cftyperef.h" 12 #include "third_party/skia/include/utils/mac/SkCGUtils.h" 13 14 namespace gfx { 15 16 SkBitmap CGImageToSkBitmap(CGImageRef image, CGSize size, bool is_opaque) { 17 SkBitmap bitmap; 18 if (!image) 19 return bitmap; 20 21 bitmap.setConfig(SkBitmap::kARGB_8888_Config, size.width, size.height); 22 if (!bitmap.allocPixels()) 23 return bitmap; 24 25 bitmap.setIsOpaque(is_opaque); 26 void* data = bitmap.getPixels(); 27 28 // Allocate a bitmap context with 4 components per pixel (BGRA). Apple 29 // recommends these flags for improved CG performance. 30 #define HAS_ARGB_SHIFTS(a, r, g, b) \ 31 (SK_A32_SHIFT == (a) && SK_R32_SHIFT == (r) \ 32 && SK_G32_SHIFT == (g) && SK_B32_SHIFT == (b)) 33 #if defined(SK_CPU_LENDIAN) && HAS_ARGB_SHIFTS(24, 16, 8, 0) 34 base::ScopedCFTypeRef<CGColorSpaceRef> color_space( 35 CGColorSpaceCreateDeviceRGB()); 36 base::ScopedCFTypeRef<CGContextRef> context(CGBitmapContextCreate( 37 data, 38 size.width, 39 size.height, 40 8, 41 size.width * 4, 42 color_space, 43 kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host)); 44 #else 45 #error We require that Skia's and CoreGraphics's recommended \ 46 image memory layout match. 47 #endif 48 #undef HAS_ARGB_SHIFTS 49 50 DCHECK(context); 51 if (!context) 52 return bitmap; 53 54 CGRect imageRect = CGRectMake(0.0, 0.0, size.width, size.height); 55 CGContextSetBlendMode(context, kCGBlendModeCopy); 56 CGContextDrawImage(context, imageRect, image); 57 58 return bitmap; 59 } 60 61 UIImage* SkBitmapToUIImageWithColorSpace(const SkBitmap& skia_bitmap, 62 CGFloat scale, 63 CGColorSpaceRef color_space) { 64 if (skia_bitmap.isNull()) 65 return nil; 66 67 // First convert SkBitmap to CGImageRef. 68 base::ScopedCFTypeRef<CGImageRef> cg_image( 69 SkCreateCGImageRefWithColorspace(skia_bitmap, color_space)); 70 71 // Now convert to UIImage. 72 return [UIImage imageWithCGImage:cg_image.get() 73 scale:scale 74 orientation:UIImageOrientationUp]; 75 } 76 77 std::vector<SkBitmap> ImageDataToSkBitmaps(NSData* image_data) { 78 DCHECK(image_data); 79 base::ScopedCFTypeRef<CFDictionaryRef> empty_dictionary( 80 CFDictionaryCreate(NULL, NULL, NULL, 0, NULL, NULL)); 81 std::vector<SkBitmap> frames; 82 83 base::ScopedCFTypeRef<CGImageSourceRef> source( 84 CGImageSourceCreateWithData((CFDataRef)image_data, empty_dictionary)); 85 86 size_t count = CGImageSourceGetCount(source); 87 for (size_t index = 0; index < count; ++index) { 88 base::ScopedCFTypeRef<CGImageRef> cg_image( 89 CGImageSourceCreateImageAtIndex(source, index, empty_dictionary)); 90 91 CGSize size = CGSizeMake(CGImageGetWidth(cg_image), 92 CGImageGetHeight(cg_image)); 93 const SkBitmap bitmap = CGImageToSkBitmap(cg_image, size, false); 94 if (!bitmap.empty()) 95 frames.push_back(bitmap); 96 } 97 98 DLOG_IF(WARNING, frames.size() != count) << "Only decoded " << frames.size() 99 << " frames for " << count << " expected."; 100 return frames; 101 } 102 103 } // namespace gfx 104