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 #import <AppKit/AppKit.h>
      8 
      9 #include "base/logging.h"
     10 #include "base/mac/scoped_nsobject.h"
     11 #include "ui/gfx/image/image_png_rep.h"
     12 #include "ui/gfx/size.h"
     13 
     14 namespace gfx {
     15 namespace internal {
     16 
     17 namespace {
     18 
     19 // Returns a 16x16 red NSImage to visually show when a NSImage cannot be
     20 // created from PNG data.
     21 // Caller takes ownership of the returned NSImage.
     22 NSImage* GetErrorNSImage() {
     23   NSRect rect = NSMakeRect(0, 0, 16, 16);
     24   NSImage* image = [[NSImage alloc] initWithSize:rect.size];
     25   [image lockFocus];
     26   [[NSColor colorWithDeviceRed:1.0 green:0.0 blue:0.0 alpha:1.0] set];
     27   NSRectFill(rect);
     28   [image unlockFocus];
     29   return image;
     30 }
     31 
     32 }  // namespace
     33 
     34 scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromNSImage(
     35     NSImage* nsimage) {
     36   CGImageRef cg_image = [nsimage CGImageForProposedRect:NULL
     37                                                 context:nil
     38                                                   hints:nil];
     39   base::scoped_nsobject<NSBitmapImageRep> ns_bitmap(
     40       [[NSBitmapImageRep alloc] initWithCGImage:cg_image]);
     41   NSData* ns_data = [ns_bitmap representationUsingType:NSPNGFileType
     42                                             properties:nil];
     43   const unsigned char* bytes =
     44       static_cast<const unsigned char*>([ns_data bytes]);
     45   scoped_refptr<base::RefCountedBytes> refcounted_bytes(
     46       new base::RefCountedBytes());
     47   refcounted_bytes->data().assign(bytes, bytes + [ns_data length]);
     48   return refcounted_bytes;
     49 }
     50 
     51 NSImage* NSImageFromPNG(const std::vector<gfx::ImagePNGRep>& image_png_reps,
     52                         CGColorSpaceRef color_space) {
     53   if (image_png_reps.empty()) {
     54     LOG(ERROR) << "Unable to decode PNG.";
     55     return GetErrorNSImage();
     56   }
     57 
     58   base::scoped_nsobject<NSImage> image;
     59   for (size_t i = 0; i < image_png_reps.size(); ++i) {
     60     scoped_refptr<base::RefCountedMemory> png = image_png_reps[i].raw_data;
     61     CHECK(png.get());
     62     base::scoped_nsobject<NSData> ns_data(
     63         [[NSData alloc] initWithBytes:png->front() length:png->size()]);
     64     base::scoped_nsobject<NSBitmapImageRep> ns_image_rep(
     65         [[NSBitmapImageRep alloc] initWithData:ns_data]);
     66     if (!ns_image_rep) {
     67       LOG(ERROR) << "Unable to decode PNG at "
     68                  << image_png_reps[i].scale
     69                  << ".";
     70       return GetErrorNSImage();
     71     }
     72 
     73     // PNGCodec ignores colorspace related ancillary chunks (sRGB, iCCP). Ignore
     74     // colorspace information when decoding directly from PNG to an NSImage so
     75     // that the conversions: PNG -> SkBitmap -> NSImage and PNG -> NSImage
     76     // produce visually similar results.
     77     CGColorSpaceModel decoded_color_space_model = CGColorSpaceGetModel(
     78         [[ns_image_rep colorSpace] CGColorSpace]);
     79     CGColorSpaceModel color_space_model = CGColorSpaceGetModel(color_space);
     80     if (decoded_color_space_model == color_space_model) {
     81       base::scoped_nsobject<NSColorSpace> ns_color_space(
     82           [[NSColorSpace alloc] initWithCGColorSpace:color_space]);
     83       NSBitmapImageRep* ns_retagged_image_rep =
     84           [ns_image_rep
     85               bitmapImageRepByRetaggingWithColorSpace:ns_color_space];
     86       if (ns_retagged_image_rep && ns_retagged_image_rep != ns_image_rep)
     87         ns_image_rep.reset([ns_retagged_image_rep retain]);
     88     }
     89 
     90     if (!image.get()) {
     91       float scale = image_png_reps[i].scale;
     92       NSSize image_size = NSMakeSize([ns_image_rep pixelsWide] / scale,
     93                                      [ns_image_rep pixelsHigh] / scale);
     94       image.reset([[NSImage alloc] initWithSize:image_size]);
     95     }
     96     [image addRepresentation:ns_image_rep];
     97   }
     98 
     99   return image.release();
    100 }
    101 
    102 gfx::Size NSImageSize(NSImage* image) {
    103   NSSize size = [image size];
    104   int width = static_cast<int>(size.width);
    105   int height = static_cast<int>(size.height);
    106   return gfx::Size(width, height);
    107 }
    108 
    109 } // namespace internal
    110 } // namespace gfx
    111 
    112