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 14namespace gfx { 15namespace internal { 16 17namespace { 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. 22NSImage* 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 34scoped_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 51NSImage* 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 102gfx::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