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