1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
|
// 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/geometry/size.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"
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
|