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 9 #include "base/logging.h" 10 #include "base/memory/scoped_ptr.h" 11 #include "base/stl_util.h" 12 #include "third_party/skia/include/core/SkBitmap.h" 13 #include "ui/gfx/image/image_png_rep.h" 14 #include "ui/gfx/image/image_skia.h" 15 #include "ui/gfx/size.h" 16 17 #if !defined(OS_IOS) 18 #include "ui/gfx/codec/png_codec.h" 19 #endif 20 21 #if defined(TOOLKIT_GTK) 22 #include <gdk-pixbuf/gdk-pixbuf.h> 23 #include <gdk/gdk.h> 24 #include <glib-object.h> 25 #include "ui/gfx/canvas.h" 26 #include "ui/gfx/gtk_util.h" 27 #include "ui/gfx/image/cairo_cached_surface.h" 28 #include "ui/gfx/scoped_gobject.h" 29 #elif defined(OS_IOS) 30 #include "base/mac/foundation_util.h" 31 #include "ui/gfx/image/image_skia_util_ios.h" 32 #elif defined(OS_MACOSX) 33 #include "base/mac/mac_util.h" 34 #include "ui/gfx/image/image_skia_util_mac.h" 35 #endif 36 37 namespace gfx { 38 39 namespace internal { 40 41 #if defined(TOOLKIT_GTK) 42 const ImageSkia ImageSkiaFromGdkPixbuf(GdkPixbuf* pixbuf) { 43 CHECK(pixbuf); 44 gfx::Canvas canvas(gfx::Size(gdk_pixbuf_get_width(pixbuf), 45 gdk_pixbuf_get_height(pixbuf)), 46 1.0f, 47 false); 48 skia::ScopedPlatformPaint scoped_platform_paint(canvas.sk_canvas()); 49 cairo_t* cr = scoped_platform_paint.GetPlatformSurface(); 50 gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0); 51 cairo_paint(cr); 52 return ImageSkia(canvas.ExtractImageRep()); 53 } 54 55 // Returns a 16x16 red pixbuf to visually show error in decoding PNG. 56 // Also logs error to console. 57 GdkPixbuf* GetErrorPixbuf() { 58 LOG(ERROR) << "Unable to decode PNG."; 59 GdkPixbuf* pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, 16, 16); 60 gdk_pixbuf_fill(pixbuf, 0xff0000ff); 61 return pixbuf; 62 } 63 64 GdkPixbuf* GdkPixbufFromPNG( 65 const std::vector<gfx::ImagePNGRep>& image_png_reps) { 66 scoped_refptr<base::RefCountedMemory> png_bytes(NULL); 67 for (size_t i = 0; i < image_png_reps.size(); ++i) { 68 if (image_png_reps[i].scale == 1.0f) 69 png_bytes = image_png_reps[i].raw_data; 70 } 71 72 if (!png_bytes.get()) 73 return GetErrorPixbuf(); 74 75 GdkPixbuf* pixbuf = NULL; 76 ui::ScopedGObject<GdkPixbufLoader>::Type loader(gdk_pixbuf_loader_new()); 77 78 bool ok = gdk_pixbuf_loader_write(loader.get(), 79 reinterpret_cast<const guint8*>(png_bytes->front()), png_bytes->size(), 80 NULL); 81 82 // Calling gdk_pixbuf_loader_close forces the data to be parsed by the 83 // loader. This must be done before calling gdk_pixbuf_loader_get_pixbuf. 84 if (ok) 85 ok = gdk_pixbuf_loader_close(loader.get(), NULL); 86 if (ok) 87 pixbuf = gdk_pixbuf_loader_get_pixbuf(loader.get()); 88 89 if (pixbuf) { 90 // The pixbuf is owned by the scoped loader which will delete its ref when 91 // it goes out of scope. Add a ref so that the pixbuf still exists. 92 g_object_ref(pixbuf); 93 } else { 94 return GetErrorPixbuf(); 95 } 96 97 return pixbuf; 98 } 99 100 scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromPixbuf( 101 GdkPixbuf* pixbuf) { 102 gchar* image = NULL; 103 gsize image_size; 104 GError* error = NULL; 105 CHECK(gdk_pixbuf_save_to_buffer( 106 pixbuf, &image, &image_size, "png", &error, NULL)); 107 scoped_refptr<base::RefCountedBytes> png_bytes( 108 new base::RefCountedBytes()); 109 png_bytes->data().assign(image, image + image_size); 110 g_free(image); 111 return png_bytes; 112 } 113 114 #endif // defined(TOOLKIT_GTK) 115 116 #if defined(OS_IOS) 117 scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromUIImage( 118 UIImage* uiimage); 119 // Caller takes ownership of the returned UIImage. 120 UIImage* CreateUIImageFromPNG( 121 const std::vector<gfx::ImagePNGRep>& image_png_reps); 122 gfx::Size UIImageSize(UIImage* image); 123 #elif defined(OS_MACOSX) 124 scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromNSImage( 125 NSImage* nsimage); 126 // Caller takes ownership of the returned NSImage. 127 NSImage* NSImageFromPNG(const std::vector<gfx::ImagePNGRep>& image_png_reps, 128 CGColorSpaceRef color_space); 129 gfx::Size NSImageSize(NSImage* image); 130 #endif // defined(OS_MACOSX) 131 132 #if defined(OS_IOS) 133 ImageSkia* ImageSkiaFromPNG( 134 const std::vector<gfx::ImagePNGRep>& image_png_reps); 135 scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromImageSkia( 136 const ImageSkia* skia); 137 #else 138 // Returns a 16x16 red image to visually show error in decoding PNG. 139 // Caller takes ownership of returned ImageSkia. 140 ImageSkia* GetErrorImageSkia() { 141 SkBitmap bitmap; 142 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 16, 16); 143 bitmap.allocPixels(); 144 bitmap.eraseRGB(0xff, 0, 0); 145 return new gfx::ImageSkia(gfx::ImageSkiaRep(bitmap, 1.0f)); 146 } 147 148 ImageSkia* ImageSkiaFromPNG( 149 const std::vector<gfx::ImagePNGRep>& image_png_reps) { 150 if (image_png_reps.empty()) 151 return GetErrorImageSkia(); 152 153 scoped_ptr<gfx::ImageSkia> image_skia(new ImageSkia()); 154 for (size_t i = 0; i < image_png_reps.size(); ++i) { 155 scoped_refptr<base::RefCountedMemory> raw_data = 156 image_png_reps[i].raw_data; 157 CHECK(raw_data.get()); 158 SkBitmap bitmap; 159 if (!gfx::PNGCodec::Decode(raw_data->front(), raw_data->size(), 160 &bitmap)) { 161 LOG(ERROR) << "Unable to decode PNG for " 162 << image_png_reps[i].scale 163 << "."; 164 return GetErrorImageSkia(); 165 } 166 image_skia->AddRepresentation(gfx::ImageSkiaRep( 167 bitmap, image_png_reps[i].scale)); 168 } 169 return image_skia.release(); 170 } 171 172 scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromImageSkia( 173 const ImageSkia* image_skia) { 174 ImageSkiaRep image_skia_rep = image_skia->GetRepresentation(1.0f); 175 176 scoped_refptr<base::RefCountedBytes> png_bytes(new base::RefCountedBytes()); 177 if (image_skia_rep.scale() != 1.0f || 178 !gfx::PNGCodec::EncodeBGRASkBitmap(image_skia_rep.sk_bitmap(), false, 179 &png_bytes->data())) { 180 return NULL; 181 } 182 return png_bytes; 183 } 184 #endif 185 186 class ImageRepPNG; 187 class ImageRepSkia; 188 class ImageRepGdk; 189 class ImageRepCairo; 190 class ImageRepCocoa; 191 class ImageRepCocoaTouch; 192 193 // An ImageRep is the object that holds the backing memory for an Image. Each 194 // RepresentationType has an ImageRep subclass that is responsible for freeing 195 // the memory that the ImageRep holds. When an ImageRep is created, it expects 196 // to take ownership of the image, without having to retain it or increase its 197 // reference count. 198 class ImageRep { 199 public: 200 explicit ImageRep(Image::RepresentationType rep) : type_(rep) {} 201 202 // Deletes the associated pixels of an ImageRep. 203 virtual ~ImageRep() {} 204 205 // Cast helpers ("fake RTTI"). 206 ImageRepPNG* AsImageRepPNG() { 207 CHECK_EQ(type_, Image::kImageRepPNG); 208 return reinterpret_cast<ImageRepPNG*>(this); 209 } 210 211 ImageRepSkia* AsImageRepSkia() { 212 CHECK_EQ(type_, Image::kImageRepSkia); 213 return reinterpret_cast<ImageRepSkia*>(this); 214 } 215 216 #if defined(TOOLKIT_GTK) 217 ImageRepGdk* AsImageRepGdk() { 218 CHECK_EQ(type_, Image::kImageRepGdk); 219 return reinterpret_cast<ImageRepGdk*>(this); 220 } 221 222 ImageRepCairo* AsImageRepCairo() { 223 CHECK_EQ(type_, Image::kImageRepCairo); 224 return reinterpret_cast<ImageRepCairo*>(this); 225 } 226 #endif 227 228 #if defined(OS_IOS) 229 ImageRepCocoaTouch* AsImageRepCocoaTouch() { 230 CHECK_EQ(type_, Image::kImageRepCocoaTouch); 231 return reinterpret_cast<ImageRepCocoaTouch*>(this); 232 } 233 #elif defined(OS_MACOSX) 234 ImageRepCocoa* AsImageRepCocoa() { 235 CHECK_EQ(type_, Image::kImageRepCocoa); 236 return reinterpret_cast<ImageRepCocoa*>(this); 237 } 238 #endif 239 240 Image::RepresentationType type() const { return type_; } 241 242 virtual int Width() const = 0; 243 virtual int Height() const = 0; 244 virtual gfx::Size Size() const = 0; 245 246 private: 247 Image::RepresentationType type_; 248 }; 249 250 class ImageRepPNG : public ImageRep { 251 public: 252 ImageRepPNG() : ImageRep(Image::kImageRepPNG) { 253 } 254 255 ImageRepPNG(const std::vector<ImagePNGRep>& image_png_reps) 256 : ImageRep(Image::kImageRepPNG), 257 image_png_reps_(image_png_reps) { 258 } 259 260 virtual ~ImageRepPNG() { 261 } 262 263 virtual int Width() const OVERRIDE { 264 return Size().width(); 265 } 266 267 virtual int Height() const OVERRIDE { 268 return Size().height(); 269 } 270 271 virtual gfx::Size Size() const OVERRIDE { 272 // Read the PNG data to get the image size, caching it. 273 if (!size_cache_) { 274 for (std::vector<ImagePNGRep>::const_iterator it = image_reps().begin(); 275 it != image_reps().end(); ++it) { 276 if (it->scale == 1.0f) { 277 size_cache_.reset(new gfx::Size(it->Size())); 278 return *size_cache_; 279 } 280 } 281 size_cache_.reset(new gfx::Size); 282 } 283 284 return *size_cache_; 285 } 286 287 const std::vector<ImagePNGRep>& image_reps() const { return image_png_reps_; } 288 289 private: 290 std::vector<ImagePNGRep> image_png_reps_; 291 292 // Cached to avoid having to parse the raw data multiple times. 293 mutable scoped_ptr<gfx::Size> size_cache_; 294 295 DISALLOW_COPY_AND_ASSIGN(ImageRepPNG); 296 }; 297 298 class ImageRepSkia : public ImageRep { 299 public: 300 // Takes ownership of |image|. 301 explicit ImageRepSkia(ImageSkia* image) 302 : ImageRep(Image::kImageRepSkia), 303 image_(image) { 304 } 305 306 virtual ~ImageRepSkia() { 307 } 308 309 virtual int Width() const OVERRIDE { 310 return image_->width(); 311 } 312 313 virtual int Height() const OVERRIDE { 314 return image_->height(); 315 } 316 317 virtual gfx::Size Size() const OVERRIDE { 318 return image_->size(); 319 } 320 321 ImageSkia* image() { return image_.get(); } 322 323 private: 324 scoped_ptr<ImageSkia> image_; 325 326 DISALLOW_COPY_AND_ASSIGN(ImageRepSkia); 327 }; 328 329 #if defined(TOOLKIT_GTK) 330 class ImageRepGdk : public ImageRep { 331 public: 332 explicit ImageRepGdk(GdkPixbuf* pixbuf) 333 : ImageRep(Image::kImageRepGdk), 334 pixbuf_(pixbuf) { 335 CHECK(pixbuf); 336 } 337 338 virtual ~ImageRepGdk() { 339 if (pixbuf_) { 340 g_object_unref(pixbuf_); 341 pixbuf_ = NULL; 342 } 343 } 344 345 virtual int Width() const OVERRIDE { 346 return gdk_pixbuf_get_width(pixbuf_); 347 } 348 349 virtual int Height() const OVERRIDE { 350 return gdk_pixbuf_get_height(pixbuf_); 351 } 352 353 virtual gfx::Size Size() const OVERRIDE { 354 return gfx::Size(Width(), Height()); 355 } 356 357 GdkPixbuf* pixbuf() const { return pixbuf_; } 358 359 private: 360 GdkPixbuf* pixbuf_; 361 362 DISALLOW_COPY_AND_ASSIGN(ImageRepGdk); 363 }; 364 365 // Represents data that lives on the display server instead of in the client. 366 class ImageRepCairo : public ImageRep { 367 public: 368 explicit ImageRepCairo(GdkPixbuf* pixbuf) 369 : ImageRep(Image::kImageRepCairo), 370 cairo_cache_(new CairoCachedSurface) { 371 CHECK(pixbuf); 372 cairo_cache_->UsePixbuf(pixbuf); 373 } 374 375 virtual ~ImageRepCairo() { 376 delete cairo_cache_; 377 } 378 379 virtual int Width() const OVERRIDE { 380 return cairo_cache_->Width(); 381 } 382 383 virtual int Height() const OVERRIDE { 384 return cairo_cache_->Height(); 385 } 386 387 virtual gfx::Size Size() const OVERRIDE { 388 return gfx::Size(Width(), Height()); 389 } 390 391 CairoCachedSurface* surface() const { return cairo_cache_; } 392 393 private: 394 CairoCachedSurface* cairo_cache_; 395 396 DISALLOW_COPY_AND_ASSIGN(ImageRepCairo); 397 }; 398 #endif // defined(TOOLKIT_GTK) 399 400 #if defined(OS_IOS) 401 class ImageRepCocoaTouch : public ImageRep { 402 public: 403 explicit ImageRepCocoaTouch(UIImage* image) 404 : ImageRep(Image::kImageRepCocoaTouch), 405 image_(image) { 406 CHECK(image); 407 } 408 409 virtual ~ImageRepCocoaTouch() { 410 base::mac::NSObjectRelease(image_); 411 image_ = nil; 412 } 413 414 virtual int Width() const OVERRIDE { 415 return Size().width(); 416 } 417 418 virtual int Height() const OVERRIDE { 419 return Size().height(); 420 } 421 422 virtual gfx::Size Size() const OVERRIDE { 423 return internal::UIImageSize(image_); 424 } 425 426 UIImage* image() const { return image_; } 427 428 private: 429 UIImage* image_; 430 431 DISALLOW_COPY_AND_ASSIGN(ImageRepCocoaTouch); 432 }; 433 #elif defined(OS_MACOSX) 434 class ImageRepCocoa : public ImageRep { 435 public: 436 explicit ImageRepCocoa(NSImage* image) 437 : ImageRep(Image::kImageRepCocoa), 438 image_(image) { 439 CHECK(image); 440 } 441 442 virtual ~ImageRepCocoa() { 443 base::mac::NSObjectRelease(image_); 444 image_ = nil; 445 } 446 447 virtual int Width() const OVERRIDE { 448 return Size().width(); 449 } 450 451 virtual int Height() const OVERRIDE { 452 return Size().height(); 453 } 454 455 virtual gfx::Size Size() const OVERRIDE { 456 return internal::NSImageSize(image_); 457 } 458 459 NSImage* image() const { return image_; } 460 461 private: 462 NSImage* image_; 463 464 DISALLOW_COPY_AND_ASSIGN(ImageRepCocoa); 465 }; 466 #endif // defined(OS_MACOSX) 467 468 // The Storage class acts similarly to the pixels in a SkBitmap: the Image 469 // class holds a refptr instance of Storage, which in turn holds all the 470 // ImageReps. This way, the Image can be cheaply copied. 471 class ImageStorage : public base::RefCounted<ImageStorage> { 472 public: 473 ImageStorage(gfx::Image::RepresentationType default_type) 474 : default_representation_type_(default_type), 475 #if defined(OS_MACOSX) && !defined(OS_IOS) 476 default_representation_color_space_( 477 base::mac::GetGenericRGBColorSpace()), 478 #endif // defined(OS_MACOSX) && !defined(OS_IOS) 479 representations_deleter_(&representations_) { 480 } 481 482 gfx::Image::RepresentationType default_representation_type() { 483 return default_representation_type_; 484 } 485 gfx::Image::RepresentationMap& representations() { return representations_; } 486 487 #if defined(OS_MACOSX) && !defined(OS_IOS) 488 void set_default_representation_color_space(CGColorSpaceRef color_space) { 489 default_representation_color_space_ = color_space; 490 } 491 CGColorSpaceRef default_representation_color_space() { 492 return default_representation_color_space_; 493 } 494 #endif // defined(OS_MACOSX) && !defined(OS_IOS) 495 496 private: 497 friend class base::RefCounted<ImageStorage>; 498 499 ~ImageStorage() {} 500 501 // The type of image that was passed to the constructor. This key will always 502 // exist in the |representations_| map. 503 gfx::Image::RepresentationType default_representation_type_; 504 505 #if defined(OS_MACOSX) && !defined(OS_IOS) 506 // The default representation's colorspace. This is used for converting to 507 // NSImage. This field exists to compensate for PNGCodec not writing or 508 // reading colorspace ancillary chunks. (sRGB, iCCP). 509 // Not owned. 510 CGColorSpaceRef default_representation_color_space_; 511 #endif // defined(OS_MACOSX) && !defined(OS_IOS) 512 513 // All the representations of an Image. Size will always be at least one, with 514 // more for any converted representations. 515 gfx::Image::RepresentationMap representations_; 516 517 STLValueDeleter<Image::RepresentationMap> representations_deleter_; 518 519 DISALLOW_COPY_AND_ASSIGN(ImageStorage); 520 }; 521 522 } // namespace internal 523 524 Image::Image() { 525 // |storage_| is NULL for empty Images. 526 } 527 528 Image::Image(const std::vector<ImagePNGRep>& image_reps) { 529 // Do not store obviously invalid ImagePNGReps. 530 std::vector<ImagePNGRep> filtered; 531 for (size_t i = 0; i < image_reps.size(); ++i) { 532 if (image_reps[i].raw_data.get() && image_reps[i].raw_data->size()) 533 filtered.push_back(image_reps[i]); 534 } 535 536 if (filtered.empty()) 537 return; 538 539 storage_ = new internal::ImageStorage(Image::kImageRepPNG); 540 internal::ImageRepPNG* rep = new internal::ImageRepPNG(filtered); 541 AddRepresentation(rep); 542 } 543 544 Image::Image(const ImageSkia& image) { 545 if (!image.isNull()) { 546 storage_ = new internal::ImageStorage(Image::kImageRepSkia); 547 internal::ImageRepSkia* rep = new internal::ImageRepSkia( 548 new ImageSkia(image)); 549 AddRepresentation(rep); 550 } 551 } 552 553 #if defined(TOOLKIT_GTK) 554 Image::Image(GdkPixbuf* pixbuf) { 555 if (pixbuf) { 556 storage_ = new internal::ImageStorage(Image::kImageRepGdk); 557 internal::ImageRepGdk* rep = new internal::ImageRepGdk(pixbuf); 558 AddRepresentation(rep); 559 } 560 } 561 #endif 562 563 #if defined(OS_IOS) 564 Image::Image(UIImage* image) 565 : storage_(new internal::ImageStorage(Image::kImageRepCocoaTouch)) { 566 if (image) { 567 internal::ImageRepCocoaTouch* rep = new internal::ImageRepCocoaTouch(image); 568 AddRepresentation(rep); 569 } 570 } 571 #elif defined(OS_MACOSX) 572 Image::Image(NSImage* image) { 573 if (image) { 574 storage_ = new internal::ImageStorage(Image::kImageRepCocoa); 575 internal::ImageRepCocoa* rep = new internal::ImageRepCocoa(image); 576 AddRepresentation(rep); 577 } 578 } 579 #endif 580 581 Image::Image(const Image& other) : storage_(other.storage_) { 582 } 583 584 Image& Image::operator=(const Image& other) { 585 storage_ = other.storage_; 586 return *this; 587 } 588 589 Image::~Image() { 590 } 591 592 // static 593 Image Image::CreateFrom1xBitmap(const SkBitmap& bitmap) { 594 return gfx::Image(ImageSkia::CreateFrom1xBitmap(bitmap)); 595 } 596 597 // static 598 Image Image::CreateFrom1xPNGBytes(const unsigned char* input, 599 size_t input_size) { 600 if (input_size == 0u) 601 return gfx::Image(); 602 603 scoped_refptr<base::RefCountedBytes> raw_data(new base::RefCountedBytes()); 604 raw_data->data().assign(input, input + input_size); 605 std::vector<gfx::ImagePNGRep> image_reps; 606 image_reps.push_back(ImagePNGRep(raw_data, 1.0f)); 607 return gfx::Image(image_reps); 608 } 609 610 const SkBitmap* Image::ToSkBitmap() const { 611 // Possibly create and cache an intermediate ImageRepSkia. 612 return ToImageSkia()->bitmap(); 613 } 614 615 const ImageSkia* Image::ToImageSkia() const { 616 internal::ImageRep* rep = GetRepresentation(kImageRepSkia, false); 617 if (!rep) { 618 switch (DefaultRepresentationType()) { 619 case kImageRepPNG: { 620 internal::ImageRepPNG* png_rep = 621 GetRepresentation(kImageRepPNG, true)->AsImageRepPNG(); 622 rep = new internal::ImageRepSkia( 623 internal::ImageSkiaFromPNG(png_rep->image_reps())); 624 break; 625 } 626 #if defined(TOOLKIT_GTK) 627 case kImageRepGdk: { 628 internal::ImageRepGdk* native_rep = 629 GetRepresentation(kImageRepGdk, true)->AsImageRepGdk(); 630 rep = new internal::ImageRepSkia(new ImageSkia( 631 internal::ImageSkiaFromGdkPixbuf(native_rep->pixbuf()))); 632 break; 633 } 634 #elif defined(OS_IOS) 635 case kImageRepCocoaTouch: { 636 internal::ImageRepCocoaTouch* native_rep = 637 GetRepresentation(kImageRepCocoaTouch, true) 638 ->AsImageRepCocoaTouch(); 639 rep = new internal::ImageRepSkia(new ImageSkia( 640 ImageSkiaFromUIImage(native_rep->image()))); 641 break; 642 } 643 #elif defined(OS_MACOSX) 644 case kImageRepCocoa: { 645 internal::ImageRepCocoa* native_rep = 646 GetRepresentation(kImageRepCocoa, true)->AsImageRepCocoa(); 647 rep = new internal::ImageRepSkia(new ImageSkia( 648 ImageSkiaFromNSImage(native_rep->image()))); 649 break; 650 } 651 #endif 652 default: 653 NOTREACHED(); 654 } 655 CHECK(rep); 656 AddRepresentation(rep); 657 } 658 return rep->AsImageRepSkia()->image(); 659 } 660 661 #if defined(TOOLKIT_GTK) 662 GdkPixbuf* Image::ToGdkPixbuf() const { 663 internal::ImageRep* rep = GetRepresentation(kImageRepGdk, false); 664 if (!rep) { 665 switch (DefaultRepresentationType()) { 666 case kImageRepPNG: { 667 internal::ImageRepPNG* png_rep = 668 GetRepresentation(kImageRepPNG, true)->AsImageRepPNG(); 669 rep = new internal::ImageRepGdk(internal::GdkPixbufFromPNG( 670 png_rep->image_reps())); 671 break; 672 } 673 case kImageRepSkia: { 674 internal::ImageRepSkia* skia_rep = 675 GetRepresentation(kImageRepSkia, true)->AsImageRepSkia(); 676 rep = new internal::ImageRepGdk(gfx::GdkPixbufFromSkBitmap( 677 *skia_rep->image()->bitmap())); 678 break; 679 } 680 default: 681 NOTREACHED(); 682 } 683 CHECK(rep); 684 AddRepresentation(rep); 685 } 686 return rep->AsImageRepGdk()->pixbuf(); 687 } 688 689 CairoCachedSurface* const Image::ToCairo() const { 690 internal::ImageRep* rep = GetRepresentation(kImageRepCairo, false); 691 if (!rep) { 692 // Handle any-to-Cairo conversion. This may create and cache an intermediate 693 // pixbuf before sending the data to the display server. 694 rep = new internal::ImageRepCairo(ToGdkPixbuf()); 695 CHECK(rep); 696 AddRepresentation(rep); 697 } 698 return rep->AsImageRepCairo()->surface(); 699 } 700 #endif 701 702 #if defined(OS_IOS) 703 UIImage* Image::ToUIImage() const { 704 internal::ImageRep* rep = GetRepresentation(kImageRepCocoaTouch, false); 705 if (!rep) { 706 switch (DefaultRepresentationType()) { 707 case kImageRepPNG: { 708 internal::ImageRepPNG* png_rep = 709 GetRepresentation(kImageRepPNG, true)->AsImageRepPNG(); 710 rep = new internal::ImageRepCocoaTouch(internal::CreateUIImageFromPNG( 711 png_rep->image_reps())); 712 break; 713 } 714 case kImageRepSkia: { 715 internal::ImageRepSkia* skia_rep = 716 GetRepresentation(kImageRepSkia, true)->AsImageRepSkia(); 717 UIImage* image = UIImageFromImageSkia(*skia_rep->image()); 718 base::mac::NSObjectRetain(image); 719 rep = new internal::ImageRepCocoaTouch(image); 720 break; 721 } 722 default: 723 NOTREACHED(); 724 } 725 CHECK(rep); 726 AddRepresentation(rep); 727 } 728 return rep->AsImageRepCocoaTouch()->image(); 729 } 730 #elif defined(OS_MACOSX) 731 NSImage* Image::ToNSImage() const { 732 internal::ImageRep* rep = GetRepresentation(kImageRepCocoa, false); 733 if (!rep) { 734 CGColorSpaceRef default_representation_color_space = 735 storage_->default_representation_color_space(); 736 737 switch (DefaultRepresentationType()) { 738 case kImageRepPNG: { 739 internal::ImageRepPNG* png_rep = 740 GetRepresentation(kImageRepPNG, true)->AsImageRepPNG(); 741 rep = new internal::ImageRepCocoa(internal::NSImageFromPNG( 742 png_rep->image_reps(), default_representation_color_space)); 743 break; 744 } 745 case kImageRepSkia: { 746 internal::ImageRepSkia* skia_rep = 747 GetRepresentation(kImageRepSkia, true)->AsImageRepSkia(); 748 NSImage* image = NSImageFromImageSkiaWithColorSpace(*skia_rep->image(), 749 default_representation_color_space); 750 base::mac::NSObjectRetain(image); 751 rep = new internal::ImageRepCocoa(image); 752 break; 753 } 754 default: 755 NOTREACHED(); 756 } 757 CHECK(rep); 758 AddRepresentation(rep); 759 } 760 return rep->AsImageRepCocoa()->image(); 761 } 762 #endif 763 764 scoped_refptr<base::RefCountedMemory> Image::As1xPNGBytes() const { 765 if (IsEmpty()) 766 return new base::RefCountedBytes(); 767 768 internal::ImageRep* rep = GetRepresentation(kImageRepPNG, false); 769 770 if (rep) { 771 const std::vector<gfx::ImagePNGRep>& image_png_reps = 772 rep->AsImageRepPNG()->image_reps(); 773 for (size_t i = 0; i < image_png_reps.size(); ++i) { 774 if (image_png_reps[i].scale == 1.0f) 775 return image_png_reps[i].raw_data; 776 } 777 return new base::RefCountedBytes(); 778 } 779 780 scoped_refptr<base::RefCountedMemory> png_bytes(NULL); 781 switch (DefaultRepresentationType()) { 782 #if defined(TOOLKIT_GTK) 783 case kImageRepGdk: { 784 internal::ImageRepGdk* gdk_rep = 785 GetRepresentation(kImageRepGdk, true)->AsImageRepGdk(); 786 png_bytes = internal::Get1xPNGBytesFromPixbuf(gdk_rep->pixbuf()); 787 break; 788 } 789 #elif defined(OS_IOS) 790 case kImageRepCocoaTouch: { 791 internal::ImageRepCocoaTouch* cocoa_touch_rep = 792 GetRepresentation(kImageRepCocoaTouch, true) 793 ->AsImageRepCocoaTouch(); 794 png_bytes = internal::Get1xPNGBytesFromUIImage( 795 cocoa_touch_rep->image()); 796 break; 797 } 798 #elif defined(OS_MACOSX) 799 case kImageRepCocoa: { 800 internal::ImageRepCocoa* cocoa_rep = 801 GetRepresentation(kImageRepCocoa, true)->AsImageRepCocoa(); 802 png_bytes = internal::Get1xPNGBytesFromNSImage(cocoa_rep->image()); 803 break; 804 } 805 #endif 806 case kImageRepSkia: { 807 internal::ImageRepSkia* skia_rep = 808 GetRepresentation(kImageRepSkia, true)->AsImageRepSkia(); 809 png_bytes = internal::Get1xPNGBytesFromImageSkia(skia_rep->image()); 810 break; 811 } 812 default: 813 NOTREACHED(); 814 } 815 if (!png_bytes.get() || !png_bytes->size()) { 816 // Add an ImageRepPNG with no data such that the conversion is not 817 // attempted each time we want the PNG bytes. 818 AddRepresentation(new internal::ImageRepPNG()); 819 return new base::RefCountedBytes(); 820 } 821 822 // Do not insert representations for scale factors other than 1x even if 823 // they are available because: 824 // - Only the 1x PNG bytes can be accessed. 825 // - ImageRepPNG is not used as an intermediate type in converting to a 826 // final type eg (converting from ImageRepSkia to ImageRepPNG to get an 827 // ImageRepCocoa). 828 std::vector<ImagePNGRep> image_png_reps; 829 image_png_reps.push_back(gfx::ImagePNGRep(png_bytes, 1.0f)); 830 rep = new internal::ImageRepPNG(image_png_reps); 831 AddRepresentation(rep); 832 return png_bytes; 833 } 834 835 SkBitmap Image::AsBitmap() const { 836 return IsEmpty() ? SkBitmap() : *ToSkBitmap(); 837 } 838 839 ImageSkia Image::AsImageSkia() const { 840 return IsEmpty() ? ImageSkia() : *ToImageSkia(); 841 } 842 843 #if defined(OS_MACOSX) && !defined(OS_IOS) 844 NSImage* Image::AsNSImage() const { 845 return IsEmpty() ? nil : ToNSImage(); 846 } 847 #endif 848 849 scoped_refptr<base::RefCountedMemory> Image::Copy1xPNGBytes() const { 850 scoped_refptr<base::RefCountedMemory> original = As1xPNGBytes(); 851 scoped_refptr<base::RefCountedBytes> copy(new base::RefCountedBytes()); 852 copy->data().assign(original->front(), original->front() + original->size()); 853 return copy; 854 } 855 856 ImageSkia* Image::CopyImageSkia() const { 857 return new ImageSkia(*ToImageSkia()); 858 } 859 860 SkBitmap* Image::CopySkBitmap() const { 861 return new SkBitmap(*ToSkBitmap()); 862 } 863 864 #if defined(TOOLKIT_GTK) 865 GdkPixbuf* Image::CopyGdkPixbuf() const { 866 GdkPixbuf* pixbuf = ToGdkPixbuf(); 867 g_object_ref(pixbuf); 868 return pixbuf; 869 } 870 #endif 871 872 #if defined(OS_IOS) 873 UIImage* Image::CopyUIImage() const { 874 UIImage* image = ToUIImage(); 875 base::mac::NSObjectRetain(image); 876 return image; 877 } 878 #elif defined(OS_MACOSX) 879 NSImage* Image::CopyNSImage() const { 880 NSImage* image = ToNSImage(); 881 base::mac::NSObjectRetain(image); 882 return image; 883 } 884 #endif 885 886 bool Image::HasRepresentation(RepresentationType type) const { 887 return storage_.get() && storage_->representations().count(type) != 0; 888 } 889 890 size_t Image::RepresentationCount() const { 891 if (!storage_.get()) 892 return 0; 893 894 return storage_->representations().size(); 895 } 896 897 bool Image::IsEmpty() const { 898 return RepresentationCount() == 0; 899 } 900 901 int Image::Width() const { 902 if (IsEmpty()) 903 return 0; 904 return GetRepresentation(DefaultRepresentationType(), true)->Width(); 905 } 906 907 int Image::Height() const { 908 if (IsEmpty()) 909 return 0; 910 return GetRepresentation(DefaultRepresentationType(), true)->Height(); 911 } 912 913 gfx::Size Image::Size() const { 914 if (IsEmpty()) 915 return gfx::Size(); 916 return GetRepresentation(DefaultRepresentationType(), true)->Size(); 917 } 918 919 void Image::SwapRepresentations(gfx::Image* other) { 920 storage_.swap(other->storage_); 921 } 922 923 #if defined(OS_MACOSX) && !defined(OS_IOS) 924 void Image::SetSourceColorSpace(CGColorSpaceRef color_space) { 925 if (storage_.get()) 926 storage_->set_default_representation_color_space(color_space); 927 } 928 #endif // defined(OS_MACOSX) && !defined(OS_IOS) 929 930 Image::RepresentationType Image::DefaultRepresentationType() const { 931 CHECK(storage_.get()); 932 RepresentationType default_type = storage_->default_representation_type(); 933 // The conversions above assume that the default representation type is never 934 // kImageRepCairo. 935 DCHECK_NE(default_type, kImageRepCairo); 936 return default_type; 937 } 938 939 internal::ImageRep* Image::GetRepresentation( 940 RepresentationType rep_type, bool must_exist) const { 941 CHECK(storage_.get()); 942 RepresentationMap::iterator it = storage_->representations().find(rep_type); 943 if (it == storage_->representations().end()) { 944 CHECK(!must_exist); 945 return NULL; 946 } 947 return it->second; 948 } 949 950 void Image::AddRepresentation(internal::ImageRep* rep) const { 951 CHECK(storage_.get()); 952 storage_->representations().insert(std::make_pair(rep->type(), rep)); 953 } 954 955 } // namespace gfx 956