Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(75)

Side by Side Diff: ui/gfx/image/image.cc

Issue 10799014: Add support for PNG representation in gfx::Image (Closed) Base URL: http://git.chromium.org/chromium/src.git@bookmark-sync
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ui/gfx/image/image.h ('k') | ui/gfx/image/image_mac.mm » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/gfx/image/image.h" 5 #include "ui/gfx/image/image.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/memory/scoped_ptr.h" 10 #include "base/memory/scoped_ptr.h"
11 #include "third_party/skia/include/core/SkBitmap.h" 11 #include "third_party/skia/include/core/SkBitmap.h"
12 #include "ui/gfx/codec/png_codec.h"
12 #include "ui/gfx/image/image_skia.h" 13 #include "ui/gfx/image/image_skia.h"
13 #include "ui/gfx/size.h" 14 #include "ui/gfx/size.h"
14 15
15 #if defined(TOOLKIT_GTK) 16 #if defined(TOOLKIT_GTK)
16 #include <gdk-pixbuf/gdk-pixbuf.h> 17 #include <gdk-pixbuf/gdk-pixbuf.h>
17 #include <gdk/gdk.h> 18 #include <gdk/gdk.h>
18 #include <glib-object.h> 19 #include <glib-object.h>
20 #include "ui/base/gtk/scoped_gobject.h"
19 #include "ui/gfx/canvas.h" 21 #include "ui/gfx/canvas.h"
20 #include "ui/gfx/gtk_util.h" 22 #include "ui/gfx/gtk_util.h"
21 #include "ui/gfx/image/cairo_cached_surface.h" 23 #include "ui/gfx/image/cairo_cached_surface.h"
22 #elif defined(OS_MACOSX) 24 #elif defined(OS_MACOSX)
23 #include "base/mac/mac_util.h" 25 #include "base/mac/mac_util.h"
24 #include "ui/gfx/image/image_skia_util_mac.h" 26 #include "ui/gfx/image/image_skia_util_mac.h"
25 #endif 27 #endif
26 28
27 namespace gfx { 29 namespace gfx {
28 30
29 namespace internal { 31 namespace internal {
30 32
31 #if defined(TOOLKIT_GTK) 33 #if defined(TOOLKIT_GTK)
32 const ImageSkia ImageSkiaFromGdkPixbuf(GdkPixbuf* pixbuf) { 34 const ImageSkia ImageSkiaFromGdkPixbuf(GdkPixbuf* pixbuf) {
33 CHECK(pixbuf); 35 CHECK(pixbuf);
34 gfx::Canvas canvas(gfx::Size(gdk_pixbuf_get_width(pixbuf), 36 gfx::Canvas canvas(gfx::Size(gdk_pixbuf_get_width(pixbuf),
35 gdk_pixbuf_get_height(pixbuf)), 37 gdk_pixbuf_get_height(pixbuf)),
36 ui::SCALE_FACTOR_100P, 38 ui::SCALE_FACTOR_100P,
37 false); 39 false);
38 skia::ScopedPlatformPaint scoped_platform_paint(canvas.sk_canvas()); 40 skia::ScopedPlatformPaint scoped_platform_paint(canvas.sk_canvas());
39 cairo_t* cr = scoped_platform_paint.GetPlatformSurface(); 41 cairo_t* cr = scoped_platform_paint.GetPlatformSurface();
40 gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0); 42 gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0);
41 cairo_paint(cr); 43 cairo_paint(cr);
42 return ImageSkia(canvas.ExtractImageRep()); 44 return ImageSkia(canvas.ExtractImageRep());
43 } 45 }
44 #endif
45 46
47 GdkPixbuf* GdkPixbufFromPNG(const std::vector<unsigned char>& png) {
48 GdkPixbuf* pixbuf = NULL;
49 ui::ScopedGObject<GdkPixbufLoader>::Type loader(gdk_pixbuf_loader_new());
50
51 bool ok = gdk_pixbuf_loader_write(loader.get(),
52 reinterpret_cast<const guint8*>(&png.front()), png.size(), NULL);
53
54 // Calling gdk_pixbuf_loader_close forces the data to be parsed by the
55 // loader. This must be done before calling gdk_pixbuf_loader_get_pixbuf.
56 if (ok)
57 ok = gdk_pixbuf_loader_close(loader.get(), NULL);
58 if (ok)
59 pixbuf = gdk_pixbuf_loader_get_pixbuf(loader.get());
60
61 if (pixbuf) {
62 // The pixbuf is owned by the scoped loader which will delete its ref when
63 // it goes out of scope. Add a ref so that the pixbuf still exists.
64 g_object_ref(pixbuf);
65 } else {
66 LOG(WARNING) << "Unable to decode PNG.";
67 // Return a 16x16 red image to visually show error.
68 pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, 16, 16);
69 gdk_pixbuf_fill(pixbuf, 0xff0000ff);
70 }
71
72 return pixbuf;
73 }
74
75 void PNGFromGdkPixbuf(GdkPixbuf* pixbuf, std::vector<unsigned char>* png) {
76 gchar* image = NULL;
77 gsize image_size;
78 GError* error = NULL;
79 CHECK(gdk_pixbuf_save_to_buffer(
80 pixbuf, &image, &image_size, "png", &error, NULL));
81 png->assign(image, image + image_size);
82 g_free(image);
83 }
84
85 #endif // defined(TOOLKIT_GTK)
86
87 #if defined(OS_MACOSX)
88 void PNGFromNSImage(NSImage* nsimage, std::vector<unsigned char>* png);
89 NSImage* NSImageFromPNG(const std::vector<unsigned char>& png);
90 #endif // defined(OS_MACOSX)
91
92 ImageSkia* ImageSkiaFromPNG(const std::vector<unsigned char>& png) {
93 SkBitmap bitmap;
94 if (!gfx::PNGCodec::Decode(&png.front(), png.size(), &bitmap)) {
95 LOG(WARNING) << "Unable to decode PNG.";
96 // Return a 16x16 red image to visually show error.
97 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 16, 16);
98 bitmap.allocPixels();
99 bitmap.eraseRGB(0xff, 0, 0);
100 }
101 return new ImageSkia(bitmap);
102 }
103
104 void PNGFromImageSkia(const ImageSkia* skia, std::vector<unsigned char>* png) {
105 CHECK(gfx::PNGCodec::EncodeBGRASkBitmap(*skia->bitmap(), false, png));
106 }
107
108 class ImageRepPNG;
46 class ImageRepSkia; 109 class ImageRepSkia;
47 class ImageRepGdk; 110 class ImageRepGdk;
48 class ImageRepCairo; 111 class ImageRepCairo;
49 class ImageRepCocoa; 112 class ImageRepCocoa;
50 113
51 // An ImageRep is the object that holds the backing memory for an Image. Each 114 // An ImageRep is the object that holds the backing memory for an Image. Each
52 // RepresentationType has an ImageRep subclass that is responsible for freeing 115 // RepresentationType has an ImageRep subclass that is responsible for freeing
53 // the memory that the ImageRep holds. When an ImageRep is created, it expects 116 // the memory that the ImageRep holds. When an ImageRep is created, it expects
54 // to take ownership of the image, without having to retain it or increase its 117 // to take ownership of the image, without having to retain it or increase its
55 // reference count. 118 // reference count.
56 class ImageRep { 119 class ImageRep {
57 public: 120 public:
58 explicit ImageRep(Image::RepresentationType rep) : type_(rep) {} 121 explicit ImageRep(Image::RepresentationType rep) : type_(rep) {}
59 122
60 // Deletes the associated pixels of an ImageRep. 123 // Deletes the associated pixels of an ImageRep.
61 virtual ~ImageRep() {} 124 virtual ~ImageRep() {}
62 125
63 // Cast helpers ("fake RTTI"). 126 // Cast helpers ("fake RTTI").
127 ImageRepPNG* AsImageRepPNG() {
128 CHECK_EQ(type_, Image::kImageRepPNG);
129 return reinterpret_cast<ImageRepPNG*>(this);
130 }
131
64 ImageRepSkia* AsImageRepSkia() { 132 ImageRepSkia* AsImageRepSkia() {
65 CHECK_EQ(type_, Image::kImageRepSkia); 133 CHECK_EQ(type_, Image::kImageRepSkia);
66 return reinterpret_cast<ImageRepSkia*>(this); 134 return reinterpret_cast<ImageRepSkia*>(this);
67 } 135 }
68 136
69 #if defined(TOOLKIT_GTK) 137 #if defined(TOOLKIT_GTK)
70 ImageRepGdk* AsImageRepGdk() { 138 ImageRepGdk* AsImageRepGdk() {
71 CHECK_EQ(type_, Image::kImageRepGdk); 139 CHECK_EQ(type_, Image::kImageRepGdk);
72 return reinterpret_cast<ImageRepGdk*>(this); 140 return reinterpret_cast<ImageRepGdk*>(this);
73 } 141 }
(...skipping 10 matching lines...) Expand all
84 return reinterpret_cast<ImageRepCocoa*>(this); 152 return reinterpret_cast<ImageRepCocoa*>(this);
85 } 153 }
86 #endif 154 #endif
87 155
88 Image::RepresentationType type() const { return type_; } 156 Image::RepresentationType type() const { return type_; }
89 157
90 private: 158 private:
91 Image::RepresentationType type_; 159 Image::RepresentationType type_;
92 }; 160 };
93 161
162 class ImageRepPNG : public ImageRep {
163 public:
164 ImageRepPNG(const unsigned char* input, size_t input_size)
165 : ImageRep(Image::kImageRepPNG),
166 image_(input, input + input_size) {
167 }
168 ImageRepPNG() : ImageRep(Image::kImageRepPNG) {
169 }
170
171 virtual ~ImageRepPNG() {
172 }
173
174 std::vector<unsigned char>* image() { return &image_; }
175
176 private:
177 std::vector<unsigned char> image_;
178
179 DISALLOW_COPY_AND_ASSIGN(ImageRepPNG);
180 };
181
94 class ImageRepSkia : public ImageRep { 182 class ImageRepSkia : public ImageRep {
95 public: 183 public:
96 // Takes ownership of |image|. 184 // Takes ownership of |image|.
97 explicit ImageRepSkia(ImageSkia* image) 185 explicit ImageRepSkia(ImageSkia* image)
98 : ImageRep(Image::kImageRepSkia), 186 : ImageRep(Image::kImageRepSkia),
99 image_(image) { 187 image_(image) {
100 } 188 }
101 189
102 virtual ~ImageRepSkia() { 190 virtual ~ImageRepSkia() {
103 } 191 }
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
214 302
215 friend class base::RefCounted<ImageStorage>; 303 friend class base::RefCounted<ImageStorage>;
216 }; 304 };
217 305
218 } // namespace internal 306 } // namespace internal
219 307
220 Image::Image() { 308 Image::Image() {
221 // |storage_| is NULL for empty Images. 309 // |storage_| is NULL for empty Images.
222 } 310 }
223 311
312 Image::Image(const unsigned char* png, size_t input_size)
313 : storage_(new internal::ImageStorage(Image::kImageRepPNG)) {
314 internal::ImageRepPNG* rep = new internal::ImageRepPNG(png, input_size);
315 AddRepresentation(rep);
316 }
317
224 Image::Image(const ImageSkia& image) 318 Image::Image(const ImageSkia& image)
225 : storage_(new internal::ImageStorage(Image::kImageRepSkia)) { 319 : storage_(new internal::ImageStorage(Image::kImageRepSkia)) {
226 internal::ImageRepSkia* rep = new internal::ImageRepSkia( 320 internal::ImageRepSkia* rep = new internal::ImageRepSkia(
227 new ImageSkia(image)); 321 new ImageSkia(image));
228 AddRepresentation(rep); 322 AddRepresentation(rep);
229 } 323 }
230 324
231 Image::Image(const ImageSkiaRep& image_skia_rep) 325 Image::Image(const ImageSkiaRep& image_skia_rep)
232 : storage_(new internal::ImageStorage(Image::kImageRepSkia)) { 326 : storage_(new internal::ImageStorage(Image::kImageRepSkia)) {
233 internal::ImageRepSkia* rep = 327 internal::ImageRepSkia* rep =
(...skipping 28 matching lines...) Expand all
262 } 356 }
263 357
264 Image& Image::operator=(const Image& other) { 358 Image& Image::operator=(const Image& other) {
265 storage_ = other.storage_; 359 storage_ = other.storage_;
266 return *this; 360 return *this;
267 } 361 }
268 362
269 Image::~Image() { 363 Image::~Image() {
270 } 364 }
271 365
366 const std::vector<unsigned char>* Image::ToImagePNG() const {
367 internal::ImageRep* rep = GetRepresentation(kImageRepPNG, false);
368 if (!rep) {
369 internal::ImageRepPNG* png_rep = new internal::ImageRepPNG();
370 switch (DefaultRepresentationType()) {
371 #if defined(TOOLKIT_GTK)
372 case kImageRepGdk: {
373 internal::ImageRepGdk* gdk_rep =
374 GetRepresentation(kImageRepGdk, true)->AsImageRepGdk();
375 internal::PNGFromGdkPixbuf(gdk_rep->pixbuf(), png_rep->image());
376 break;
377 }
378 #elif defined(OS_MACOSX)
379 case kImageRepCocoa: {
380 internal::ImageRepCocoa* cocoa_rep =
381 GetRepresentation(kImageRepCocoa, true)->AsImageRepCocoa();
382 internal::PNGFromNSImage(cocoa_rep->image(), png_rep->image());
383 break;
384 }
385 #endif
386 case kImageRepSkia: {
387 internal::ImageRepSkia* skia_rep =
388 GetRepresentation(kImageRepSkia, true)->AsImageRepSkia();
389 internal::PNGFromImageSkia(skia_rep->image(), png_rep->image());
390 break;
391 }
392 default:
393 NOTREACHED();
394 }
395 rep = png_rep;
396 CHECK(rep);
397 AddRepresentation(rep);
398 }
399 return rep->AsImageRepPNG()->image();
400 }
401
272 const SkBitmap* Image::ToSkBitmap() const { 402 const SkBitmap* Image::ToSkBitmap() const {
273 // Possibly create and cache an intermediate ImageRepSkia. 403 // Possibly create and cache an intermediate ImageRepSkia.
274 return ToImageSkia()->bitmap(); 404 return ToImageSkia()->bitmap();
275 } 405 }
276 406
277 const ImageSkia* Image::ToImageSkia() const { 407 const ImageSkia* Image::ToImageSkia() const {
278 internal::ImageRep* rep = GetRepresentation(kImageRepSkia, false); 408 internal::ImageRep* rep = GetRepresentation(kImageRepSkia, false);
279 if (!rep) { 409 if (!rep) {
410 switch (DefaultRepresentationType()) {
411 case kImageRepPNG: {
412 internal::ImageRepPNG* png_rep =
413 GetRepresentation(kImageRepPNG, true)->AsImageRepPNG();
414 rep = new internal::ImageRepSkia(
415 internal::ImageSkiaFromPNG(*png_rep->image()));
416 break;
417 }
280 #if defined(TOOLKIT_GTK) 418 #if defined(TOOLKIT_GTK)
281 internal::ImageRepGdk* native_rep = 419 case kImageRepGdk: {
282 GetRepresentation(kImageRepGdk, true)->AsImageRepGdk(); 420 internal::ImageRepGdk* native_rep =
283 rep = new internal::ImageRepSkia(new ImageSkia( 421 GetRepresentation(kImageRepGdk, true)->AsImageRepGdk();
284 internal::ImageSkiaFromGdkPixbuf(native_rep->pixbuf()))); 422 rep = new internal::ImageRepSkia(new ImageSkia(
423 internal::ImageSkiaFromGdkPixbuf(native_rep->pixbuf())));
424 break;
425 }
285 #elif defined(OS_MACOSX) 426 #elif defined(OS_MACOSX)
286 internal::ImageRepCocoa* native_rep = 427 case kImageRepCocoa: {
287 GetRepresentation(kImageRepCocoa, true)->AsImageRepCocoa(); 428 internal::ImageRepCocoa* native_rep =
288 rep = new internal::ImageRepSkia(new ImageSkia( 429 GetRepresentation(kImageRepCocoa, true)->AsImageRepCocoa();
289 ImageSkiaFromNSImage(native_rep->image()))); 430 rep = new internal::ImageRepSkia(new ImageSkia(
431 ImageSkiaFromNSImage(native_rep->image())));
432 break;
433 }
290 #endif 434 #endif
435 default:
436 NOTREACHED();
437 }
291 CHECK(rep); 438 CHECK(rep);
292 AddRepresentation(rep); 439 AddRepresentation(rep);
293 } 440 }
294 return rep->AsImageRepSkia()->image(); 441 return rep->AsImageRepSkia()->image();
295 } 442 }
296 443
297 #if defined(TOOLKIT_GTK) 444 #if defined(TOOLKIT_GTK)
298 GdkPixbuf* Image::ToGdkPixbuf() const { 445 GdkPixbuf* Image::ToGdkPixbuf() const {
299 internal::ImageRep* rep = GetRepresentation(kImageRepGdk, false); 446 internal::ImageRep* rep = GetRepresentation(kImageRepGdk, false);
300 if (!rep) { 447 if (!rep) {
301 internal::ImageRepSkia* skia_rep = 448 switch (DefaultRepresentationType()) {
302 GetRepresentation(kImageRepSkia, true)->AsImageRepSkia(); 449 case kImageRepPNG: {
303 rep = new internal::ImageRepGdk(gfx::GdkPixbufFromSkBitmap( 450 internal::ImageRepPNG* png_rep =
304 *skia_rep->image()->bitmap())); 451 GetRepresentation(kImageRepPNG, true)->AsImageRepPNG();
452 rep = new internal::ImageRepGdk(internal::GdkPixbufFromPNG(
453 *png_rep->image()));
454 break;
455 }
456 case kImageRepSkia: {
457 internal::ImageRepSkia* skia_rep =
458 GetRepresentation(kImageRepSkia, true)->AsImageRepSkia();
459 rep = new internal::ImageRepGdk(gfx::GdkPixbufFromSkBitmap(
460 *skia_rep->image()->bitmap()));
461 break;
462 }
463 default:
464 NOTREACHED();
465 }
305 CHECK(rep); 466 CHECK(rep);
306 AddRepresentation(rep); 467 AddRepresentation(rep);
307 } 468 }
308 return rep->AsImageRepGdk()->pixbuf(); 469 return rep->AsImageRepGdk()->pixbuf();
309 } 470 }
310 471
311 CairoCachedSurface* const Image::ToCairo() const { 472 CairoCachedSurface* const Image::ToCairo() const {
312 internal::ImageRep* rep = GetRepresentation(kImageRepCairo, false); 473 internal::ImageRep* rep = GetRepresentation(kImageRepCairo, false);
313 if (!rep) { 474 if (!rep) {
314 // Handle any-to-Cairo conversion. This may create and cache an intermediate 475 // Handle any-to-Cairo conversion. This may create and cache an intermediate
315 // pixbuf before sending the data to the display server. 476 // pixbuf before sending the data to the display server.
316 rep = new internal::ImageRepCairo(ToGdkPixbuf()); 477 rep = new internal::ImageRepCairo(ToGdkPixbuf());
317 CHECK(rep); 478 CHECK(rep);
318 AddRepresentation(rep); 479 AddRepresentation(rep);
319 } 480 }
320 return rep->AsImageRepCairo()->surface(); 481 return rep->AsImageRepCairo()->surface();
321 } 482 }
322 #endif 483 #endif
323 484
324 #if defined(OS_MACOSX) 485 #if defined(OS_MACOSX)
325 NSImage* Image::ToNSImage() const { 486 NSImage* Image::ToNSImage() const {
326 internal::ImageRep* rep = GetRepresentation(kImageRepCocoa, false); 487 internal::ImageRep* rep = GetRepresentation(kImageRepCocoa, false);
327 if (!rep) { 488 if (!rep) {
328 internal::ImageRepSkia* skia_rep = 489 switch (DefaultRepresentationType()) {
329 GetRepresentation(kImageRepSkia, true)->AsImageRepSkia(); 490 case kImageRepPNG: {
330 NSImage* image = NSImageFromImageSkia(*skia_rep->image()); 491 internal::ImageRepPNG* png_rep =
331 base::mac::NSObjectRetain(image); 492 GetRepresentation(kImageRepPNG, true)->AsImageRepPNG();
332 rep = new internal::ImageRepCocoa(image); 493 rep = new internal::ImageRepCocoa(internal::NSImageFromPNG(
494 *png_rep->image()));
495 break;
496 }
497 case kImageRepSkia: {
498 internal::ImageRepSkia* skia_rep =
499 GetRepresentation(kImageRepSkia, true)->AsImageRepSkia();
500 NSImage* image = NSImageFromImageSkia(*skia_rep->image());
501 base::mac::NSObjectRetain(image);
502 rep = new internal::ImageRepCocoa(image);
503 break;
504 }
505 default:
506 NOTREACHED();
507 }
333 CHECK(rep); 508 CHECK(rep);
334 AddRepresentation(rep); 509 AddRepresentation(rep);
335 } 510 }
336 return rep->AsImageRepCocoa()->image(); 511 return rep->AsImageRepCocoa()->image();
337 } 512 }
338 #endif 513 #endif
339 514
515 std::vector<unsigned char>* Image::CopyImagePNG() const {
516 return new std::vector<unsigned char>(*ToImagePNG());
517 }
518
340 SkBitmap Image::AsBitmap() const { 519 SkBitmap Image::AsBitmap() const {
341 return IsEmpty() ? SkBitmap() : *ToSkBitmap(); 520 return IsEmpty() ? SkBitmap() : *ToSkBitmap();
342 } 521 }
343 522
344 ImageSkia Image::AsImageSkia() const { 523 ImageSkia Image::AsImageSkia() const {
345 return IsEmpty() ? ImageSkia() : *ToImageSkia(); 524 return IsEmpty() ? ImageSkia() : *ToImageSkia();
346 } 525 }
347 526
348 #if defined(OS_MACOSX) 527 #if defined(OS_MACOSX)
349 NSImage* Image::AsNSImage() const { 528 NSImage* Image::AsNSImage() const {
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
419 } 598 }
420 return it->second; 599 return it->second;
421 } 600 }
422 601
423 void Image::AddRepresentation(internal::ImageRep* rep) const { 602 void Image::AddRepresentation(internal::ImageRep* rep) const {
424 CHECK(storage_.get()); 603 CHECK(storage_.get());
425 storage_->representations().insert(std::make_pair(rep->type(), rep)); 604 storage_->representations().insert(std::make_pair(rep->type(), rep));
426 } 605 }
427 606
428 } // namespace gfx 607 } // namespace gfx
OLDNEW
« no previous file with comments | « ui/gfx/image/image.h ('k') | ui/gfx/image/image_mac.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698