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 "ui/gfx/image/image.h" 6 7 #import <UIKit/UIKit.h> 8 #include <cmath> 9 #include <limits> 10 11 #include "base/logging.h" 12 #include "base/mac/scoped_cftyperef.h" 13 #include "base/mac/scoped_nsobject.h" 14 #include "ui/gfx/image/image_png_rep.h" 15 #include "ui/gfx/image/image_skia.h" 16 #include "ui/gfx/image/image_skia_util_ios.h" 17 #include "ui/gfx/size.h" 18 19 namespace gfx { 20 namespace internal { 21 22 namespace { 23 24 // Returns a 16x16 red UIImage to visually show when a UIImage cannot be 25 // created from PNG data. Logs error as well. 26 // Caller takes ownership of returned UIImage. 27 UIImage* CreateErrorUIImage(float scale) { 28 LOG(ERROR) << "Unable to decode PNG into UIImage."; 29 base::ScopedCFTypeRef<CGColorSpaceRef> color_space( 30 CGColorSpaceCreateDeviceRGB()); 31 base::ScopedCFTypeRef<CGContextRef> context(CGBitmapContextCreate( 32 NULL, // Allow CG to allocate memory. 33 16, // width 34 16, // height 35 8, // bitsPerComponent 36 0, // CG will calculate by default. 37 color_space, 38 kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host)); 39 CGContextSetRGBFillColor(context, 1.0, 0.0, 0.0, 1.0); 40 CGContextFillRect(context, CGRectMake(0.0, 0.0, 16, 16)); 41 base::ScopedCFTypeRef<CGImageRef> cg_image( 42 CGBitmapContextCreateImage(context)); 43 return [[UIImage imageWithCGImage:cg_image.get() 44 scale:scale 45 orientation:UIImageOrientationUp] retain]; 46 } 47 48 // Converts from ImagePNGRep to UIImage. 49 UIImage* CreateUIImageFromImagePNGRep(const gfx::ImagePNGRep& image_png_rep) { 50 float scale = image_png_rep.scale; 51 scoped_refptr<base::RefCountedMemory> png = image_png_rep.raw_data; 52 CHECK(png.get()); 53 NSData* data = [NSData dataWithBytes:png->front() length:png->size()]; 54 UIImage* image = [[UIImage alloc] initWithData:data scale:scale]; 55 return image ? image : CreateErrorUIImage(scale); 56 } 57 58 } // namespace 59 60 scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromUIImage( 61 UIImage* uiimage) { 62 NSData* data = UIImagePNGRepresentation(uiimage); 63 64 if ([data length] == 0) 65 return NULL; 66 67 scoped_refptr<base::RefCountedBytes> png_bytes( 68 new base::RefCountedBytes()); 69 png_bytes->data().resize([data length]); 70 [data getBytes:&png_bytes->data().at(0) length:[data length]]; 71 return png_bytes; 72 } 73 74 UIImage* CreateUIImageFromPNG( 75 const std::vector<gfx::ImagePNGRep>& image_png_reps) { 76 float ideal_scale = ImageSkia::GetMaxSupportedScale(); 77 78 if (image_png_reps.empty()) 79 return CreateErrorUIImage(ideal_scale); 80 81 // Find best match for |ideal_scale|. 82 float smallest_diff = std::numeric_limits<float>::max(); 83 size_t closest_index = 0u; 84 for (size_t i = 0; i < image_png_reps.size(); ++i) { 85 float scale = image_png_reps[i].scale; 86 float diff = std::abs(ideal_scale - scale); 87 if (diff < smallest_diff) { 88 smallest_diff = diff; 89 closest_index = i; 90 } 91 } 92 93 return CreateUIImageFromImagePNGRep(image_png_reps[closest_index]); 94 } 95 96 scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromImageSkia( 97 const ImageSkia* skia) { 98 // iOS does not expose libpng, so conversion from ImageSkia to PNG must go 99 // through UIImage. 100 // TODO(rohitrao): Rewrite the callers of this function to save the UIImage 101 // representation in the gfx::Image. If we're generating it, we might as well 102 // hold on to it. 103 const gfx::ImageSkiaRep& image_skia_rep = skia->GetRepresentation(1.0f); 104 if (image_skia_rep.scale() != 1.0f) 105 return NULL; 106 107 UIImage* image = UIImageFromImageSkiaRep(image_skia_rep); 108 return Get1xPNGBytesFromUIImage(image); 109 } 110 111 ImageSkia* ImageSkiaFromPNG( 112 const std::vector<gfx::ImagePNGRep>& image_png_reps) { 113 // iOS does not expose libpng, so conversion from PNG to ImageSkia must go 114 // through UIImage. 115 gfx::ImageSkia* image_skia = new gfx::ImageSkia(); 116 for (size_t i = 0; i < image_png_reps.size(); ++i) { 117 base::scoped_nsobject<UIImage> uiimage( 118 CreateUIImageFromImagePNGRep(image_png_reps[i])); 119 gfx::ImageSkiaRep image_skia_rep = ImageSkiaRepOfScaleFromUIImage( 120 uiimage, image_png_reps[i].scale); 121 if (!image_skia_rep.is_null()) 122 image_skia->AddRepresentation(image_skia_rep); 123 } 124 return image_skia; 125 } 126 127 gfx::Size UIImageSize(UIImage* image) { 128 int width = static_cast<int>(image.size.width); 129 int height = static_cast<int>(image.size.height); 130 return gfx::Size(width, height); 131 } 132 133 } // namespace internal 134 } // namespace gfx 135