// Copyright 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "ui/gfx/image/image.h" #import <UIKit/UIKit.h> #include <cmath> #include <limits> #include "base/logging.h" #include "base/mac/scoped_cftyperef.h" #include "base/mac/scoped_nsobject.h" #include "ui/gfx/image/image_png_rep.h" #include "ui/gfx/image/image_skia.h" #include "ui/gfx/image/image_skia_util_ios.h" #include "ui/gfx/size.h" namespace gfx { namespace internal { namespace { // Returns a 16x16 red UIImage to visually show when a UIImage cannot be // created from PNG data. Logs error as well. // Caller takes ownership of returned UIImage. UIImage* CreateErrorUIImage(float scale) { LOG(ERROR) << "Unable to decode PNG into UIImage."; base::ScopedCFTypeRef<CGColorSpaceRef> color_space( CGColorSpaceCreateDeviceRGB()); base::ScopedCFTypeRef<CGContextRef> context(CGBitmapContextCreate( NULL, // Allow CG to allocate memory. 16, // width 16, // height 8, // bitsPerComponent 0, // CG will calculate by default. color_space, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host)); CGContextSetRGBFillColor(context, 1.0, 0.0, 0.0, 1.0); CGContextFillRect(context, CGRectMake(0.0, 0.0, 16, 16)); base::ScopedCFTypeRef<CGImageRef> cg_image( CGBitmapContextCreateImage(context)); return [[UIImage imageWithCGImage:cg_image.get() scale:scale orientation:UIImageOrientationUp] retain]; } // Converts from ImagePNGRep to UIImage. UIImage* CreateUIImageFromImagePNGRep(const gfx::ImagePNGRep& image_png_rep) { float scale = image_png_rep.scale; scoped_refptr<base::RefCountedMemory> png = image_png_rep.raw_data; CHECK(png.get()); NSData* data = [NSData dataWithBytes:png->front() length:png->size()]; UIImage* image = [[UIImage alloc] initWithData:data scale:scale]; return image ? image : CreateErrorUIImage(scale); } } // namespace scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromUIImage( UIImage* uiimage) { NSData* data = UIImagePNGRepresentation(uiimage); if ([data length] == 0) return NULL; scoped_refptr<base::RefCountedBytes> png_bytes( new base::RefCountedBytes()); png_bytes->data().resize([data length]); [data getBytes:&png_bytes->data().at(0) length:[data length]]; return png_bytes; } UIImage* CreateUIImageFromPNG( const std::vector<gfx::ImagePNGRep>& image_png_reps) { float ideal_scale = ImageSkia::GetMaxSupportedScale(); if (image_png_reps.empty()) return CreateErrorUIImage(ideal_scale); // Find best match for |ideal_scale|. float smallest_diff = std::numeric_limits<float>::max(); size_t closest_index = 0u; for (size_t i = 0; i < image_png_reps.size(); ++i) { float scale = image_png_reps[i].scale; float diff = std::abs(ideal_scale - scale); if (diff < smallest_diff) { smallest_diff = diff; closest_index = i; } } return CreateUIImageFromImagePNGRep(image_png_reps[closest_index]); } scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromImageSkia( const ImageSkia* skia) { // iOS does not expose libpng, so conversion from ImageSkia to PNG must go // through UIImage. // TODO(rohitrao): Rewrite the callers of this function to save the UIImage // representation in the gfx::Image. If we're generating it, we might as well // hold on to it. const gfx::ImageSkiaRep& image_skia_rep = skia->GetRepresentation(1.0f); if (image_skia_rep.scale() != 1.0f) return NULL; UIImage* image = UIImageFromImageSkiaRep(image_skia_rep); return Get1xPNGBytesFromUIImage(image); } ImageSkia* ImageSkiaFromPNG( const std::vector<gfx::ImagePNGRep>& image_png_reps) { // iOS does not expose libpng, so conversion from PNG to ImageSkia must go // through UIImage. gfx::ImageSkia* image_skia = new gfx::ImageSkia(); for (size_t i = 0; i < image_png_reps.size(); ++i) { base::scoped_nsobject<UIImage> uiimage( CreateUIImageFromImagePNGRep(image_png_reps[i])); gfx::ImageSkiaRep image_skia_rep = ImageSkiaRepOfScaleFromUIImage( uiimage, image_png_reps[i].scale); if (!image_skia_rep.is_null()) image_skia->AddRepresentation(image_skia_rep); } return image_skia; } gfx::Size UIImageSize(UIImage* image) { int width = static_cast<int>(image.size.width); int height = static_cast<int>(image.size.height); return gfx::Size(width, height); } } // namespace internal } // namespace gfx