Home | History | Annotate | Download | only in image
      1 // Copyright (c) 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 #include <algorithm>
      8 #include <set>
      9 
     10 #include "base/logging.h"
     11 #include "base/memory/scoped_ptr.h"
     12 #include "base/stl_util.h"
     13 #include "third_party/skia/include/core/SkBitmap.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_source.h"
     17 #include "ui/gfx/size.h"
     18 
     19 #if !defined(OS_IOS)
     20 #include "ui/gfx/codec/png_codec.h"
     21 #endif
     22 
     23 #if defined(OS_IOS)
     24 #include "base/mac/foundation_util.h"
     25 #include "ui/gfx/image/image_skia_util_ios.h"
     26 #elif defined(OS_MACOSX)
     27 #include "base/mac/mac_util.h"
     28 #include "ui/gfx/image/image_skia_util_mac.h"
     29 #endif
     30 
     31 namespace gfx {
     32 
     33 namespace internal {
     34 
     35 #if defined(OS_IOS)
     36 scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromUIImage(
     37     UIImage* uiimage);
     38 // Caller takes ownership of the returned UIImage.
     39 UIImage* CreateUIImageFromPNG(
     40     const std::vector<ImagePNGRep>& image_png_reps);
     41 gfx::Size UIImageSize(UIImage* image);
     42 #elif defined(OS_MACOSX)
     43 scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromNSImage(
     44     NSImage* nsimage);
     45 // Caller takes ownership of the returned NSImage.
     46 NSImage* NSImageFromPNG(const std::vector<ImagePNGRep>& image_png_reps,
     47                         CGColorSpaceRef color_space);
     48 gfx::Size NSImageSize(NSImage* image);
     49 #endif // defined(OS_MACOSX)
     50 
     51 #if defined(OS_IOS)
     52 ImageSkia* ImageSkiaFromPNG(
     53     const std::vector<ImagePNGRep>& image_png_reps);
     54 scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromImageSkia(
     55     const ImageSkia* skia);
     56 #else
     57 // Returns a 16x16 red image to visually show error in decoding PNG.
     58 // Caller takes ownership of returned ImageSkia.
     59 ImageSkia* GetErrorImageSkia() {
     60   SkBitmap bitmap;
     61   bitmap.setConfig(SkBitmap::kARGB_8888_Config, 16, 16);
     62   bitmap.allocPixels();
     63   bitmap.eraseARGB(0xff, 0xff, 0, 0);
     64   return new ImageSkia(ImageSkiaRep(bitmap, 1.0f));
     65 }
     66 
     67 class PNGImageSource : public ImageSkiaSource {
     68  public:
     69   PNGImageSource() {}
     70   virtual ~PNGImageSource() {}
     71 
     72   virtual ImageSkiaRep GetImageForScale(float scale) OVERRIDE {
     73     if (image_skia_reps_.empty())
     74       return ImageSkiaRep();
     75 
     76     const ImageSkiaRep* rep = NULL;
     77     // gfx::ImageSkia passes one of the resource scale factors. The source
     78     // should return:
     79     // 1) The ImageSkiaRep with the highest scale if all available
     80     // scales are smaller than |scale|.
     81     // 2) The ImageSkiaRep with the smallest one that is larger than |scale|.
     82     for (ImageSkiaRepSet::const_iterator iter = image_skia_reps_.begin();
     83          iter != image_skia_reps_.end(); ++iter) {
     84       if ((*iter).scale() == scale)
     85         return (*iter);
     86       if (!rep || rep->scale() < (*iter).scale())
     87         rep = &(*iter);
     88       if (rep->scale() >= scale)
     89         break;
     90     }
     91     return rep ? *rep : ImageSkiaRep();
     92   }
     93 
     94   const gfx::Size size() const {
     95     return size_;
     96   }
     97 
     98   bool AddPNGData(const ImagePNGRep& png_rep) {
     99     const gfx::ImageSkiaRep rep = ToImageSkiaRep(png_rep);
    100     if (rep.is_null())
    101       return false;
    102     if (size_.IsEmpty())
    103       size_ = gfx::Size(rep.GetWidth(), rep.GetHeight());
    104     image_skia_reps_.insert(rep);
    105     return true;
    106   }
    107 
    108   static ImageSkiaRep ToImageSkiaRep(const ImagePNGRep& png_rep) {
    109     scoped_refptr<base::RefCountedMemory> raw_data = png_rep.raw_data;
    110     CHECK(raw_data.get());
    111     SkBitmap bitmap;
    112     if (!PNGCodec::Decode(raw_data->front(), raw_data->size(),
    113                                &bitmap)) {
    114       LOG(ERROR) << "Unable to decode PNG for " << png_rep.scale << ".";
    115       return ImageSkiaRep();
    116     }
    117     return ImageSkiaRep(bitmap, png_rep.scale);
    118   }
    119 
    120  private:
    121   struct Compare {
    122     bool operator()(const ImageSkiaRep& rep1, const ImageSkiaRep& rep2) {
    123       return rep1.scale() < rep2.scale();
    124     }
    125   };
    126 
    127   typedef std::set<ImageSkiaRep, Compare> ImageSkiaRepSet;
    128   ImageSkiaRepSet image_skia_reps_;
    129   gfx::Size size_;
    130 
    131   DISALLOW_COPY_AND_ASSIGN(PNGImageSource);
    132 };
    133 
    134 ImageSkia* ImageSkiaFromPNG(
    135     const std::vector<ImagePNGRep>& image_png_reps) {
    136   if (image_png_reps.empty())
    137     return GetErrorImageSkia();
    138   scoped_ptr<PNGImageSource> image_source(new PNGImageSource);
    139 
    140   for (size_t i = 0; i < image_png_reps.size(); ++i) {
    141     if (!image_source->AddPNGData(image_png_reps[i]))
    142       return GetErrorImageSkia();
    143   }
    144   const gfx::Size& size = image_source->size();
    145   DCHECK(!size.IsEmpty());
    146   if (size.IsEmpty())
    147     return GetErrorImageSkia();
    148   return new ImageSkia(image_source.release(), size);
    149 }
    150 
    151 scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromImageSkia(
    152     const ImageSkia* image_skia) {
    153   ImageSkiaRep image_skia_rep = image_skia->GetRepresentation(1.0f);
    154 
    155   scoped_refptr<base::RefCountedBytes> png_bytes(new base::RefCountedBytes());
    156   if (image_skia_rep.scale() != 1.0f ||
    157       !PNGCodec::EncodeBGRASkBitmap(image_skia_rep.sk_bitmap(), false,
    158           &png_bytes->data())) {
    159     return NULL;
    160   }
    161   return png_bytes;
    162 }
    163 #endif
    164 
    165 class ImageRepPNG;
    166 class ImageRepSkia;
    167 class ImageRepCocoa;
    168 class ImageRepCocoaTouch;
    169 
    170 // An ImageRep is the object that holds the backing memory for an Image. Each
    171 // RepresentationType has an ImageRep subclass that is responsible for freeing
    172 // the memory that the ImageRep holds. When an ImageRep is created, it expects
    173 // to take ownership of the image, without having to retain it or increase its
    174 // reference count.
    175 class ImageRep {
    176  public:
    177   explicit ImageRep(Image::RepresentationType rep) : type_(rep) {}
    178 
    179   // Deletes the associated pixels of an ImageRep.
    180   virtual ~ImageRep() {}
    181 
    182   // Cast helpers ("fake RTTI").
    183   ImageRepPNG* AsImageRepPNG() {
    184     CHECK_EQ(type_, Image::kImageRepPNG);
    185     return reinterpret_cast<ImageRepPNG*>(this);
    186   }
    187 
    188   ImageRepSkia* AsImageRepSkia() {
    189     CHECK_EQ(type_, Image::kImageRepSkia);
    190     return reinterpret_cast<ImageRepSkia*>(this);
    191   }
    192 
    193 #if defined(OS_IOS)
    194   ImageRepCocoaTouch* AsImageRepCocoaTouch() {
    195     CHECK_EQ(type_, Image::kImageRepCocoaTouch);
    196     return reinterpret_cast<ImageRepCocoaTouch*>(this);
    197   }
    198 #elif defined(OS_MACOSX)
    199   ImageRepCocoa* AsImageRepCocoa() {
    200     CHECK_EQ(type_, Image::kImageRepCocoa);
    201     return reinterpret_cast<ImageRepCocoa*>(this);
    202   }
    203 #endif
    204 
    205   Image::RepresentationType type() const { return type_; }
    206 
    207   virtual int Width() const = 0;
    208   virtual int Height() const = 0;
    209   virtual gfx::Size Size() const = 0;
    210 
    211  private:
    212   Image::RepresentationType type_;
    213 };
    214 
    215 class ImageRepPNG : public ImageRep {
    216  public:
    217   ImageRepPNG() : ImageRep(Image::kImageRepPNG) {
    218   }
    219 
    220   ImageRepPNG(const std::vector<ImagePNGRep>& image_png_reps)
    221       : ImageRep(Image::kImageRepPNG),
    222         image_png_reps_(image_png_reps) {
    223   }
    224 
    225   virtual ~ImageRepPNG() {
    226   }
    227 
    228   virtual int Width() const OVERRIDE {
    229     return Size().width();
    230   }
    231 
    232   virtual int Height() const OVERRIDE {
    233     return Size().height();
    234   }
    235 
    236   virtual gfx::Size Size() const OVERRIDE {
    237     // Read the PNG data to get the image size, caching it.
    238     if (!size_cache_) {
    239       for (std::vector<ImagePNGRep>::const_iterator it = image_reps().begin();
    240            it != image_reps().end(); ++it) {
    241         if (it->scale == 1.0f) {
    242           size_cache_.reset(new gfx::Size(it->Size()));
    243           return *size_cache_;
    244         }
    245       }
    246       size_cache_.reset(new gfx::Size);
    247     }
    248 
    249     return *size_cache_;
    250   }
    251 
    252   const std::vector<ImagePNGRep>& image_reps() const { return image_png_reps_; }
    253 
    254  private:
    255   std::vector<ImagePNGRep> image_png_reps_;
    256 
    257   // Cached to avoid having to parse the raw data multiple times.
    258   mutable scoped_ptr<gfx::Size> size_cache_;
    259 
    260   DISALLOW_COPY_AND_ASSIGN(ImageRepPNG);
    261 };
    262 
    263 class ImageRepSkia : public ImageRep {
    264  public:
    265   // Takes ownership of |image|.
    266   explicit ImageRepSkia(ImageSkia* image)
    267       : ImageRep(Image::kImageRepSkia),
    268         image_(image) {
    269   }
    270 
    271   virtual ~ImageRepSkia() {
    272   }
    273 
    274   virtual int Width() const OVERRIDE {
    275     return image_->width();
    276   }
    277 
    278   virtual int Height() const OVERRIDE {
    279     return image_->height();
    280   }
    281 
    282   virtual gfx::Size Size() const OVERRIDE {
    283     return image_->size();
    284   }
    285 
    286   ImageSkia* image() { return image_.get(); }
    287 
    288  private:
    289   scoped_ptr<ImageSkia> image_;
    290 
    291   DISALLOW_COPY_AND_ASSIGN(ImageRepSkia);
    292 };
    293 
    294 #if defined(OS_IOS)
    295 class ImageRepCocoaTouch : public ImageRep {
    296  public:
    297   explicit ImageRepCocoaTouch(UIImage* image)
    298       : ImageRep(Image::kImageRepCocoaTouch),
    299         image_(image) {
    300     CHECK(image);
    301   }
    302 
    303   virtual ~ImageRepCocoaTouch() {
    304     base::mac::NSObjectRelease(image_);
    305     image_ = nil;
    306   }
    307 
    308   virtual int Width() const OVERRIDE {
    309     return Size().width();
    310   }
    311 
    312   virtual int Height() const OVERRIDE {
    313     return Size().height();
    314   }
    315 
    316   virtual gfx::Size Size() const OVERRIDE {
    317     return internal::UIImageSize(image_);
    318   }
    319 
    320   UIImage* image() const { return image_; }
    321 
    322  private:
    323   UIImage* image_;
    324 
    325   DISALLOW_COPY_AND_ASSIGN(ImageRepCocoaTouch);
    326 };
    327 #elif defined(OS_MACOSX)
    328 class ImageRepCocoa : public ImageRep {
    329  public:
    330   explicit ImageRepCocoa(NSImage* image)
    331       : ImageRep(Image::kImageRepCocoa),
    332         image_(image) {
    333     CHECK(image);
    334   }
    335 
    336   virtual ~ImageRepCocoa() {
    337     base::mac::NSObjectRelease(image_);
    338     image_ = nil;
    339   }
    340 
    341   virtual int Width() const OVERRIDE {
    342     return Size().width();
    343   }
    344 
    345   virtual int Height() const OVERRIDE {
    346     return Size().height();
    347   }
    348 
    349   virtual gfx::Size Size() const OVERRIDE {
    350     return internal::NSImageSize(image_);
    351   }
    352 
    353   NSImage* image() const { return image_; }
    354 
    355  private:
    356   NSImage* image_;
    357 
    358   DISALLOW_COPY_AND_ASSIGN(ImageRepCocoa);
    359 };
    360 #endif  // defined(OS_MACOSX)
    361 
    362 // The Storage class acts similarly to the pixels in a SkBitmap: the Image
    363 // class holds a refptr instance of Storage, which in turn holds all the
    364 // ImageReps. This way, the Image can be cheaply copied.
    365 class ImageStorage : public base::RefCounted<ImageStorage> {
    366  public:
    367   ImageStorage(Image::RepresentationType default_type)
    368       : default_representation_type_(default_type),
    369 #if defined(OS_MACOSX) && !defined(OS_IOS)
    370         default_representation_color_space_(
    371             base::mac::GetGenericRGBColorSpace()),
    372 #endif  // defined(OS_MACOSX) && !defined(OS_IOS)
    373         representations_deleter_(&representations_) {
    374   }
    375 
    376   Image::RepresentationType default_representation_type() {
    377     return default_representation_type_;
    378   }
    379   Image::RepresentationMap& representations() { return representations_; }
    380 
    381 #if defined(OS_MACOSX) && !defined(OS_IOS)
    382   void set_default_representation_color_space(CGColorSpaceRef color_space) {
    383     default_representation_color_space_ = color_space;
    384   }
    385   CGColorSpaceRef default_representation_color_space() {
    386     return default_representation_color_space_;
    387   }
    388 #endif  // defined(OS_MACOSX) && !defined(OS_IOS)
    389 
    390  private:
    391   friend class base::RefCounted<ImageStorage>;
    392 
    393   ~ImageStorage() {}
    394 
    395   // The type of image that was passed to the constructor. This key will always
    396   // exist in the |representations_| map.
    397   Image::RepresentationType default_representation_type_;
    398 
    399 #if defined(OS_MACOSX) && !defined(OS_IOS)
    400   // The default representation's colorspace. This is used for converting to
    401   // NSImage. This field exists to compensate for PNGCodec not writing or
    402   // reading colorspace ancillary chunks. (sRGB, iCCP).
    403   // Not owned.
    404   CGColorSpaceRef default_representation_color_space_;
    405 #endif  // defined(OS_MACOSX) && !defined(OS_IOS)
    406 
    407   // All the representations of an Image. Size will always be at least one, with
    408   // more for any converted representations.
    409   Image::RepresentationMap representations_;
    410 
    411   STLValueDeleter<Image::RepresentationMap> representations_deleter_;
    412 
    413   DISALLOW_COPY_AND_ASSIGN(ImageStorage);
    414 };
    415 
    416 }  // namespace internal
    417 
    418 Image::Image() {
    419   // |storage_| is NULL for empty Images.
    420 }
    421 
    422 Image::Image(const std::vector<ImagePNGRep>& image_reps) {
    423   // Do not store obviously invalid ImagePNGReps.
    424   std::vector<ImagePNGRep> filtered;
    425   for (size_t i = 0; i < image_reps.size(); ++i) {
    426     if (image_reps[i].raw_data.get() && image_reps[i].raw_data->size())
    427       filtered.push_back(image_reps[i]);
    428   }
    429 
    430   if (filtered.empty())
    431     return;
    432 
    433   storage_ = new internal::ImageStorage(Image::kImageRepPNG);
    434   internal::ImageRepPNG* rep = new internal::ImageRepPNG(filtered);
    435   AddRepresentation(rep);
    436 }
    437 
    438 Image::Image(const ImageSkia& image) {
    439   if (!image.isNull()) {
    440     storage_ = new internal::ImageStorage(Image::kImageRepSkia);
    441     internal::ImageRepSkia* rep = new internal::ImageRepSkia(
    442         new ImageSkia(image));
    443     AddRepresentation(rep);
    444   }
    445 }
    446 
    447 #if defined(OS_IOS)
    448 Image::Image(UIImage* image)
    449     : storage_(new internal::ImageStorage(Image::kImageRepCocoaTouch)) {
    450   if (image) {
    451     internal::ImageRepCocoaTouch* rep = new internal::ImageRepCocoaTouch(image);
    452     AddRepresentation(rep);
    453   }
    454 }
    455 #elif defined(OS_MACOSX)
    456 Image::Image(NSImage* image) {
    457   if (image) {
    458     storage_ = new internal::ImageStorage(Image::kImageRepCocoa);
    459     internal::ImageRepCocoa* rep = new internal::ImageRepCocoa(image);
    460     AddRepresentation(rep);
    461   }
    462 }
    463 #endif
    464 
    465 Image::Image(const Image& other) : storage_(other.storage_) {
    466 }
    467 
    468 Image& Image::operator=(const Image& other) {
    469   storage_ = other.storage_;
    470   return *this;
    471 }
    472 
    473 Image::~Image() {
    474 }
    475 
    476 // static
    477 Image Image::CreateFrom1xBitmap(const SkBitmap& bitmap) {
    478   return Image(ImageSkia::CreateFrom1xBitmap(bitmap));
    479 }
    480 
    481 // static
    482 Image Image::CreateFrom1xPNGBytes(const unsigned char* input,
    483                                   size_t input_size) {
    484   if (input_size == 0u)
    485     return Image();
    486 
    487   scoped_refptr<base::RefCountedBytes> raw_data(new base::RefCountedBytes());
    488   raw_data->data().assign(input, input + input_size);
    489 
    490   return CreateFrom1xPNGBytes(raw_data);
    491 }
    492 
    493 Image Image::CreateFrom1xPNGBytes(
    494     const scoped_refptr<base::RefCountedMemory>& input) {
    495   if (!input.get() || input->size() == 0u)
    496     return Image();
    497 
    498   std::vector<ImagePNGRep> image_reps;
    499   image_reps.push_back(ImagePNGRep(input, 1.0f));
    500   return Image(image_reps);
    501 }
    502 
    503 const SkBitmap* Image::ToSkBitmap() const {
    504   // Possibly create and cache an intermediate ImageRepSkia.
    505   return ToImageSkia()->bitmap();
    506 }
    507 
    508 const ImageSkia* Image::ToImageSkia() const {
    509   internal::ImageRep* rep = GetRepresentation(kImageRepSkia, false);
    510   if (!rep) {
    511     switch (DefaultRepresentationType()) {
    512       case kImageRepPNG: {
    513         internal::ImageRepPNG* png_rep =
    514             GetRepresentation(kImageRepPNG, true)->AsImageRepPNG();
    515         rep = new internal::ImageRepSkia(
    516             internal::ImageSkiaFromPNG(png_rep->image_reps()));
    517         break;
    518       }
    519 #if defined(OS_IOS)
    520       case kImageRepCocoaTouch: {
    521         internal::ImageRepCocoaTouch* native_rep =
    522             GetRepresentation(kImageRepCocoaTouch, true)
    523                 ->AsImageRepCocoaTouch();
    524         rep = new internal::ImageRepSkia(new ImageSkia(
    525             ImageSkiaFromUIImage(native_rep->image())));
    526         break;
    527       }
    528 #elif defined(OS_MACOSX)
    529       case kImageRepCocoa: {
    530         internal::ImageRepCocoa* native_rep =
    531             GetRepresentation(kImageRepCocoa, true)->AsImageRepCocoa();
    532         rep = new internal::ImageRepSkia(new ImageSkia(
    533             ImageSkiaFromNSImage(native_rep->image())));
    534         break;
    535       }
    536 #endif
    537       default:
    538         NOTREACHED();
    539     }
    540     CHECK(rep);
    541     AddRepresentation(rep);
    542   }
    543   return rep->AsImageRepSkia()->image();
    544 }
    545 
    546 #if defined(OS_IOS)
    547 UIImage* Image::ToUIImage() const {
    548   internal::ImageRep* rep = GetRepresentation(kImageRepCocoaTouch, false);
    549   if (!rep) {
    550     switch (DefaultRepresentationType()) {
    551       case kImageRepPNG: {
    552         internal::ImageRepPNG* png_rep =
    553             GetRepresentation(kImageRepPNG, true)->AsImageRepPNG();
    554         rep = new internal::ImageRepCocoaTouch(internal::CreateUIImageFromPNG(
    555             png_rep->image_reps()));
    556         break;
    557       }
    558       case kImageRepSkia: {
    559         internal::ImageRepSkia* skia_rep =
    560             GetRepresentation(kImageRepSkia, true)->AsImageRepSkia();
    561         UIImage* image = UIImageFromImageSkia(*skia_rep->image());
    562         base::mac::NSObjectRetain(image);
    563         rep = new internal::ImageRepCocoaTouch(image);
    564         break;
    565       }
    566       default:
    567         NOTREACHED();
    568     }
    569     CHECK(rep);
    570     AddRepresentation(rep);
    571   }
    572   return rep->AsImageRepCocoaTouch()->image();
    573 }
    574 #elif defined(OS_MACOSX)
    575 NSImage* Image::ToNSImage() const {
    576   internal::ImageRep* rep = GetRepresentation(kImageRepCocoa, false);
    577   if (!rep) {
    578     CGColorSpaceRef default_representation_color_space =
    579         storage_->default_representation_color_space();
    580 
    581     switch (DefaultRepresentationType()) {
    582       case kImageRepPNG: {
    583         internal::ImageRepPNG* png_rep =
    584             GetRepresentation(kImageRepPNG, true)->AsImageRepPNG();
    585         rep = new internal::ImageRepCocoa(internal::NSImageFromPNG(
    586             png_rep->image_reps(), default_representation_color_space));
    587         break;
    588       }
    589       case kImageRepSkia: {
    590         internal::ImageRepSkia* skia_rep =
    591             GetRepresentation(kImageRepSkia, true)->AsImageRepSkia();
    592         NSImage* image = NSImageFromImageSkiaWithColorSpace(*skia_rep->image(),
    593             default_representation_color_space);
    594         base::mac::NSObjectRetain(image);
    595         rep = new internal::ImageRepCocoa(image);
    596         break;
    597       }
    598       default:
    599         NOTREACHED();
    600     }
    601     CHECK(rep);
    602     AddRepresentation(rep);
    603   }
    604   return rep->AsImageRepCocoa()->image();
    605 }
    606 #endif
    607 
    608 scoped_refptr<base::RefCountedMemory> Image::As1xPNGBytes() const {
    609   if (IsEmpty())
    610     return new base::RefCountedBytes();
    611 
    612   internal::ImageRep* rep = GetRepresentation(kImageRepPNG, false);
    613 
    614   if (rep) {
    615     const std::vector<ImagePNGRep>& image_png_reps =
    616         rep->AsImageRepPNG()->image_reps();
    617     for (size_t i = 0; i < image_png_reps.size(); ++i) {
    618       if (image_png_reps[i].scale == 1.0f)
    619         return image_png_reps[i].raw_data;
    620     }
    621     return new base::RefCountedBytes();
    622   }
    623 
    624   scoped_refptr<base::RefCountedMemory> png_bytes(NULL);
    625   switch (DefaultRepresentationType()) {
    626 #if defined(OS_IOS)
    627     case kImageRepCocoaTouch: {
    628       internal::ImageRepCocoaTouch* cocoa_touch_rep =
    629           GetRepresentation(kImageRepCocoaTouch, true)
    630               ->AsImageRepCocoaTouch();
    631       png_bytes = internal::Get1xPNGBytesFromUIImage(
    632           cocoa_touch_rep->image());
    633       break;
    634     }
    635 #elif defined(OS_MACOSX)
    636     case kImageRepCocoa: {
    637       internal::ImageRepCocoa* cocoa_rep =
    638           GetRepresentation(kImageRepCocoa, true)->AsImageRepCocoa();
    639       png_bytes = internal::Get1xPNGBytesFromNSImage(cocoa_rep->image());
    640       break;
    641     }
    642 #endif
    643     case kImageRepSkia: {
    644       internal::ImageRepSkia* skia_rep =
    645           GetRepresentation(kImageRepSkia, true)->AsImageRepSkia();
    646       png_bytes = internal::Get1xPNGBytesFromImageSkia(skia_rep->image());
    647       break;
    648     }
    649     default:
    650       NOTREACHED();
    651   }
    652   if (!png_bytes.get() || !png_bytes->size()) {
    653     // Add an ImageRepPNG with no data such that the conversion is not
    654     // attempted each time we want the PNG bytes.
    655     AddRepresentation(new internal::ImageRepPNG());
    656     return new base::RefCountedBytes();
    657   }
    658 
    659   // Do not insert representations for scale factors other than 1x even if
    660   // they are available because:
    661   // - Only the 1x PNG bytes can be accessed.
    662   // - ImageRepPNG is not used as an intermediate type in converting to a
    663   //   final type eg (converting from ImageRepSkia to ImageRepPNG to get an
    664   //   ImageRepCocoa).
    665   std::vector<ImagePNGRep> image_png_reps;
    666   image_png_reps.push_back(ImagePNGRep(png_bytes, 1.0f));
    667   rep = new internal::ImageRepPNG(image_png_reps);
    668   AddRepresentation(rep);
    669   return png_bytes;
    670 }
    671 
    672 SkBitmap Image::AsBitmap() const {
    673   return IsEmpty() ? SkBitmap() : *ToSkBitmap();
    674 }
    675 
    676 ImageSkia Image::AsImageSkia() const {
    677   return IsEmpty() ? ImageSkia() : *ToImageSkia();
    678 }
    679 
    680 #if defined(OS_MACOSX) && !defined(OS_IOS)
    681 NSImage* Image::AsNSImage() const {
    682   return IsEmpty() ? nil : ToNSImage();
    683 }
    684 #endif
    685 
    686 scoped_refptr<base::RefCountedMemory> Image::Copy1xPNGBytes() const {
    687   scoped_refptr<base::RefCountedMemory> original = As1xPNGBytes();
    688   scoped_refptr<base::RefCountedBytes> copy(new base::RefCountedBytes());
    689   copy->data().assign(original->front(), original->front() + original->size());
    690   return copy;
    691 }
    692 
    693 ImageSkia* Image::CopyImageSkia() const {
    694   return new ImageSkia(*ToImageSkia());
    695 }
    696 
    697 SkBitmap* Image::CopySkBitmap() const {
    698   return new SkBitmap(*ToSkBitmap());
    699 }
    700 
    701 #if defined(OS_IOS)
    702 UIImage* Image::CopyUIImage() const {
    703   UIImage* image = ToUIImage();
    704   base::mac::NSObjectRetain(image);
    705   return image;
    706 }
    707 #elif defined(OS_MACOSX)
    708 NSImage* Image::CopyNSImage() const {
    709   NSImage* image = ToNSImage();
    710   base::mac::NSObjectRetain(image);
    711   return image;
    712 }
    713 #endif
    714 
    715 bool Image::HasRepresentation(RepresentationType type) const {
    716   return storage_.get() && storage_->representations().count(type) != 0;
    717 }
    718 
    719 size_t Image::RepresentationCount() const {
    720   if (!storage_.get())
    721     return 0;
    722 
    723   return storage_->representations().size();
    724 }
    725 
    726 bool Image::IsEmpty() const {
    727   return RepresentationCount() == 0;
    728 }
    729 
    730 int Image::Width() const {
    731   if (IsEmpty())
    732     return 0;
    733   return GetRepresentation(DefaultRepresentationType(), true)->Width();
    734 }
    735 
    736 int Image::Height() const {
    737   if (IsEmpty())
    738     return 0;
    739   return GetRepresentation(DefaultRepresentationType(), true)->Height();
    740 }
    741 
    742 gfx::Size Image::Size() const {
    743   if (IsEmpty())
    744     return gfx::Size();
    745   return GetRepresentation(DefaultRepresentationType(), true)->Size();
    746 }
    747 
    748 void Image::SwapRepresentations(Image* other) {
    749   storage_.swap(other->storage_);
    750 }
    751 
    752 #if defined(OS_MACOSX)  && !defined(OS_IOS)
    753 void Image::SetSourceColorSpace(CGColorSpaceRef color_space) {
    754   if (storage_.get())
    755     storage_->set_default_representation_color_space(color_space);
    756 }
    757 #endif  // defined(OS_MACOSX) && !defined(OS_IOS)
    758 
    759 Image::RepresentationType Image::DefaultRepresentationType() const {
    760   CHECK(storage_.get());
    761   return storage_->default_representation_type();
    762 }
    763 
    764 internal::ImageRep* Image::GetRepresentation(
    765     RepresentationType rep_type, bool must_exist) const {
    766   CHECK(storage_.get());
    767   RepresentationMap::iterator it = storage_->representations().find(rep_type);
    768   if (it == storage_->representations().end()) {
    769     CHECK(!must_exist);
    770     return NULL;
    771   }
    772   return it->second;
    773 }
    774 
    775 void Image::AddRepresentation(internal::ImageRep* rep) const {
    776   CHECK(storage_.get());
    777   storage_->representations().insert(std::make_pair(rep->type(), rep));
    778 }
    779 
    780 }  // namespace gfx
    781