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