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