OLD | NEW |
| (Empty) |
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/ios/ios_util.h" | |
11 #include "base/logging.h" | |
12 #include "base/mac/scoped_cftyperef.h" | |
13 #include "base/macros.h" | |
14 #include "third_party/skia/include/utils/mac/SkCGUtils.h" | |
15 | |
16 namespace { | |
17 | |
18 const uint8 kICOHeaderMagic[4] = {0x00, 0x00, 0x01, 0x00}; | |
19 | |
20 // Returns whether the data encodes an ico image. | |
21 bool EncodesIcoImage(NSData* image_data) { | |
22 if (image_data.length < arraysize(kICOHeaderMagic)) | |
23 return false; | |
24 return memcmp(kICOHeaderMagic, image_data.bytes, | |
25 arraysize(kICOHeaderMagic)) == 0; | |
26 } | |
27 | |
28 } // namespace | |
29 | |
30 namespace gfx { | |
31 | |
32 SkBitmap CGImageToSkBitmap(CGImageRef image, CGSize size, bool is_opaque) { | |
33 SkBitmap bitmap; | |
34 if (!image) | |
35 return bitmap; | |
36 | |
37 if (!bitmap.tryAllocN32Pixels(size.width, size.height, is_opaque)) | |
38 return bitmap; | |
39 | |
40 void* data = bitmap.getPixels(); | |
41 | |
42 // Allocate a bitmap context with 4 components per pixel (BGRA). Apple | |
43 // recommends these flags for improved CG performance. | |
44 #define HAS_ARGB_SHIFTS(a, r, g, b) \ | |
45 (SK_A32_SHIFT == (a) && SK_R32_SHIFT == (r) \ | |
46 && SK_G32_SHIFT == (g) && SK_B32_SHIFT == (b)) | |
47 #if defined(SK_CPU_LENDIAN) && HAS_ARGB_SHIFTS(24, 16, 8, 0) | |
48 base::ScopedCFTypeRef<CGColorSpaceRef> color_space( | |
49 CGColorSpaceCreateDeviceRGB()); | |
50 base::ScopedCFTypeRef<CGContextRef> context(CGBitmapContextCreate( | |
51 data, | |
52 size.width, | |
53 size.height, | |
54 8, | |
55 size.width * 4, | |
56 color_space, | |
57 kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host)); | |
58 #else | |
59 #error We require that Skia's and CoreGraphics's recommended \ | |
60 image memory layout match. | |
61 #endif | |
62 #undef HAS_ARGB_SHIFTS | |
63 | |
64 DCHECK(context); | |
65 if (!context) | |
66 return bitmap; | |
67 | |
68 CGRect imageRect = CGRectMake(0.0, 0.0, size.width, size.height); | |
69 CGContextSetBlendMode(context, kCGBlendModeCopy); | |
70 CGContextDrawImage(context, imageRect, image); | |
71 | |
72 return bitmap; | |
73 } | |
74 | |
75 UIImage* SkBitmapToUIImageWithColorSpace(const SkBitmap& skia_bitmap, | |
76 CGFloat scale, | |
77 CGColorSpaceRef color_space) { | |
78 if (skia_bitmap.isNull()) | |
79 return nil; | |
80 | |
81 // First convert SkBitmap to CGImageRef. | |
82 base::ScopedCFTypeRef<CGImageRef> cg_image( | |
83 SkCreateCGImageRefWithColorspace(skia_bitmap, color_space)); | |
84 | |
85 // Now convert to UIImage. | |
86 return [UIImage imageWithCGImage:cg_image.get() | |
87 scale:scale | |
88 orientation:UIImageOrientationUp]; | |
89 } | |
90 | |
91 std::vector<SkBitmap> ImageDataToSkBitmaps(NSData* image_data) { | |
92 DCHECK(image_data); | |
93 | |
94 // On iOS 8.1.1 |CGContextDrawImage| crashes when processing images included | |
95 // in .ico files that are 88x88 pixels or larger (http://crbug.com/435068). | |
96 bool skip_images_88x88_or_larger = | |
97 base::ios::IsRunningOnOrLater(8, 1, 1) && EncodesIcoImage(image_data); | |
98 | |
99 base::ScopedCFTypeRef<CFDictionaryRef> empty_dictionary( | |
100 CFDictionaryCreate(NULL, NULL, NULL, 0, NULL, NULL)); | |
101 std::vector<SkBitmap> frames; | |
102 | |
103 base::ScopedCFTypeRef<CGImageSourceRef> source( | |
104 CGImageSourceCreateWithData((CFDataRef)image_data, empty_dictionary)); | |
105 | |
106 size_t count = CGImageSourceGetCount(source); | |
107 for (size_t index = 0; index < count; ++index) { | |
108 base::ScopedCFTypeRef<CGImageRef> cg_image( | |
109 CGImageSourceCreateImageAtIndex(source, index, empty_dictionary)); | |
110 | |
111 CGSize size = CGSizeMake(CGImageGetWidth(cg_image), | |
112 CGImageGetHeight(cg_image)); | |
113 if (size.width >= 88 && size.height >= 88 && skip_images_88x88_or_larger) | |
114 continue; | |
115 | |
116 const SkBitmap bitmap = CGImageToSkBitmap(cg_image, size, false); | |
117 if (!bitmap.empty()) | |
118 frames.push_back(bitmap); | |
119 } | |
120 | |
121 DLOG_IF(WARNING, frames.size() != count) << "Only decoded " << frames.size() | |
122 << " frames for " << count << " expected."; | |
123 return frames; | |
124 } | |
125 | |
126 } // namespace gfx | |
OLD | NEW |