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