Home | History | Annotate | Download | only in image
      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