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

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
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)), false); 37 gdk_pixbuf_get_height(pixbuf)), false);
36 skia::ScopedPlatformPaint scoped_platform_paint(canvas.sk_canvas()); 38 skia::ScopedPlatformPaint scoped_platform_paint(canvas.sk_canvas());
37 cairo_t* cr = scoped_platform_paint.GetPlatformSurface(); 39 cairo_t* cr = scoped_platform_paint.GetPlatformSurface();
38 gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0); 40 gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0);
39 cairo_paint(cr); 41 cairo_paint(cr);
40 return ImageSkia(SkBitmap(canvas.ExtractBitmap())); 42 return ImageSkia(SkBitmap(canvas.ExtractBitmap()));
41 } 43 }
44
45 GdkPixbuf* GdkPixbufFromPNG(const std::vector<unsigned char>& png) {
46 GdkPixbuf* pixbuf = NULL;
47 ui::ScopedGObject<GdkPixbufLoader>::Type loader(gdk_pixbuf_loader_new());
48
49 bool ok = gdk_pixbuf_loader_write(loader.get(),
50 reinterpret_cast<const guint8*>(&png.front()), png.size(), NULL);
51
52 // Calling gdk_pixbuf_loader_close forces the data to be parsed by the
53 // loader. This must be done before calling gdk_pixbuf_loader_get_pixbuf.
54 if (ok)
55 ok = gdk_pixbuf_loader_close(loader.get(), NULL);
56 if (ok)
57 pixbuf = gdk_pixbuf_loader_get_pixbuf(loader.get());
58
59 if (!pixbuf) {
60 LOG(WARNING) << "Unable to decode PNG.";
61 // Return a 16x16 red image to visually show error.
62 pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, 32, 32);
Robert Sesek 2012/07/31 14:07:17 Does this leak the pixbuf because this is gdk_pixb
cjhopman 2012/08/03 22:15:25 Yes, you're right. A ref should only be added when
63 gdk_pixbuf_fill(pixbuf, 0xff0000ff);
64 }
65
66 g_object_ref(pixbuf);
67 return pixbuf;
68 }
69
70 void PNGFromGdkPixbuf(GdkPixbuf* pixbuf, std::vector<unsigned char>* png) {
71 gchar* image = NULL;
72 gsize image_size;
73 GError* error = NULL;
74 if (!gdk_pixbuf_save_to_buffer(
75 pixbuf, &image, &image_size, "png", &error, NULL)) {
76 LOG(WARNING) << "Unable to encode PNG: " << error->message;
77 g_error_free(error);
78 } else {
79 png->assign(image, image + image_size);
80 g_free(image);
81 }
82 }
83
84 #endif // defined(TOOLKIT_GTK)
85
86 #if defined(OS_MACOSX)
87 void PNGFromNSImage(NSImage* nsimage, std::vector<unsigned char>* png);
88 NSImage* NSImageFromPNG(const std::vector<unsigned char>& png);
42 #endif 89 #endif
43 90
91 ImageSkia* ImageSkiaFromPNG(const std::vector<unsigned char>& png) {
92 SkBitmap bitmap;
93 if (!gfx::PNGCodec::Decode(&png.front(), png.size(), &bitmap)) {
94 LOG(WARNING) << "Unable to decode PNG, returning empty bitmap.";
95 // Return a 16x16 red image to visually show error.
96 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 16, 16);
97 bitmap.allocPixels();
98 bitmap.eraseRGB(0xff, 0, 0);
99 }
100 return new ImageSkia(bitmap);
101 }
102 void PNGFromImageSkia(const ImageSkia* skia, std::vector<unsigned char>* png) {
103 if (!gfx::PNGCodec::EncodeBGRASkBitmap(*skia->bitmap(), false, png)) {
104 LOG(WARNING) << "Unable to encode bitmap, returning empty PNG.";
105 png->clear();
106 }
107 }
108
109 class ImageRepPNG;
44 class ImageRepSkia; 110 class ImageRepSkia;
45 class ImageRepGdk; 111 class ImageRepGdk;
46 class ImageRepCairo; 112 class ImageRepCairo;
47 class ImageRepCocoa; 113 class ImageRepCocoa;
48 114
49 // An ImageRep is the object that holds the backing memory for an Image. Each 115 // An ImageRep is the object that holds the backing memory for an Image. Each
50 // RepresentationType has an ImageRep subclass that is responsible for freeing 116 // RepresentationType has an ImageRep subclass that is responsible for freeing
51 // the memory that the ImageRep holds. When an ImageRep is created, it expects 117 // the memory that the ImageRep holds. When an ImageRep is created, it expects
52 // to take ownership of the image, without having to retain it or increase its 118 // to take ownership of the image, without having to retain it or increase its
53 // reference count. 119 // reference count.
54 class ImageRep { 120 class ImageRep {
55 public: 121 public:
56 explicit ImageRep(Image::RepresentationType rep) : type_(rep) {} 122 explicit ImageRep(Image::RepresentationType rep) : type_(rep) {}
57 123
58 // Deletes the associated pixels of an ImageRep. 124 // Deletes the associated pixels of an ImageRep.
59 virtual ~ImageRep() {} 125 virtual ~ImageRep() {}
60 126
61 // Cast helpers ("fake RTTI"). 127 // Cast helpers ("fake RTTI").
128 ImageRepPNG* AsImageRepPNG() {
129 CHECK_EQ(type_, Image::kImageRepPNG);
130 return reinterpret_cast<ImageRepPNG*>(this);
131 }
132
62 ImageRepSkia* AsImageRepSkia() { 133 ImageRepSkia* AsImageRepSkia() {
63 CHECK_EQ(type_, Image::kImageRepSkia); 134 CHECK_EQ(type_, Image::kImageRepSkia);
64 return reinterpret_cast<ImageRepSkia*>(this); 135 return reinterpret_cast<ImageRepSkia*>(this);
65 } 136 }
66 137
67 #if defined(TOOLKIT_GTK) 138 #if defined(TOOLKIT_GTK)
68 ImageRepGdk* AsImageRepGdk() { 139 ImageRepGdk* AsImageRepGdk() {
69 CHECK_EQ(type_, Image::kImageRepGdk); 140 CHECK_EQ(type_, Image::kImageRepGdk);
70 return reinterpret_cast<ImageRepGdk*>(this); 141 return reinterpret_cast<ImageRepGdk*>(this);
71 } 142 }
(...skipping 10 matching lines...) Expand all
82 return reinterpret_cast<ImageRepCocoa*>(this); 153 return reinterpret_cast<ImageRepCocoa*>(this);
83 } 154 }
84 #endif 155 #endif
85 156
86 Image::RepresentationType type() const { return type_; } 157 Image::RepresentationType type() const { return type_; }
87 158
88 private: 159 private:
89 Image::RepresentationType type_; 160 Image::RepresentationType type_;
90 }; 161 };
91 162
163 class ImageRepPNG : public ImageRep {
164 public:
165 ImageRepPNG(const unsigned char* input, size_t input_size)
166 : ImageRep(Image::kImageRepPNG),
167 image_(input, input + input_size) {
168 }
169 ImageRepPNG() : ImageRep(Image::kImageRepPNG) {
170 }
171
172 virtual ~ImageRepPNG() {
173 }
174
175 std::vector<unsigned char>* image() { return &image_; }
176
177 private:
178 std::vector<unsigned char> image_;
179
180 DISALLOW_COPY_AND_ASSIGN(ImageRepPNG);
181 };
182
92 class ImageRepSkia : public ImageRep { 183 class ImageRepSkia : public ImageRep {
93 public: 184 public:
94 // Takes ownership of |image|. 185 // Takes ownership of |image|.
95 explicit ImageRepSkia(ImageSkia* image) 186 explicit ImageRepSkia(ImageSkia* image)
96 : ImageRep(Image::kImageRepSkia), 187 : ImageRep(Image::kImageRepSkia),
97 image_(image) { 188 image_(image) {
98 } 189 }
99 190
100 virtual ~ImageRepSkia() { 191 virtual ~ImageRepSkia() {
101 } 192 }
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
212 303
213 friend class base::RefCounted<ImageStorage>; 304 friend class base::RefCounted<ImageStorage>;
214 }; 305 };
215 306
216 } // namespace internal 307 } // namespace internal
217 308
218 Image::Image() { 309 Image::Image() {
219 // |storage_| is NULL for empty Images. 310 // |storage_| is NULL for empty Images.
220 } 311 }
221 312
313 Image::Image(const unsigned char* png, size_t input_size)
314 : storage_(new internal::ImageStorage(Image::kImageRepPNG)) {
315 internal::ImageRepPNG* rep = new internal::ImageRepPNG(png, input_size);
316 AddRepresentation(rep);
317 }
318
222 Image::Image(const ImageSkia& image) 319 Image::Image(const ImageSkia& image)
223 : storage_(new internal::ImageStorage(Image::kImageRepSkia)) { 320 : storage_(new internal::ImageStorage(Image::kImageRepSkia)) {
224 internal::ImageRepSkia* rep = new internal::ImageRepSkia( 321 internal::ImageRepSkia* rep = new internal::ImageRepSkia(
225 new ImageSkia(image)); 322 new ImageSkia(image));
226 AddRepresentation(rep); 323 AddRepresentation(rep);
227 } 324 }
228 325
229 Image::Image(const ImageSkiaRep& image_skia_rep) 326 Image::Image(const ImageSkiaRep& image_skia_rep)
230 : storage_(new internal::ImageStorage(Image::kImageRepSkia)) { 327 : storage_(new internal::ImageStorage(Image::kImageRepSkia)) {
231 internal::ImageRepSkia* rep = 328 internal::ImageRepSkia* rep =
(...skipping 28 matching lines...) Expand all
260 } 357 }
261 358
262 Image& Image::operator=(const Image& other) { 359 Image& Image::operator=(const Image& other) {
263 storage_ = other.storage_; 360 storage_ = other.storage_;
264 return *this; 361 return *this;
265 } 362 }
266 363
267 Image::~Image() { 364 Image::~Image() {
268 } 365 }
269 366
367 const std::vector<unsigned char>* Image::ToImagePNG() const {
368 internal::ImageRep* rep = GetRepresentation(kImageRepPNG, false);
369 if (!rep) {
370 switch (DefaultRepresentationType()) {
371 #if defined(TOOLKIT_GTK)
372 case kImageRepGdk: {
373 internal::ImageRepGdk* gdk_rep =
374 GetRepresentation(kImageRepGdk, true)->AsImageRepGdk();
375 internal::ImageRepPNG* png_rep = new internal::ImageRepPNG();
376 internal::PNGFromGdkPixbuf(gdk_rep->pixbuf(), png_rep->image());
377 rep = png_rep;
378 break;
379 }
380 #elif defined(OS_MACOSX)
381 case kImageRepCocoa: {
382 internal::ImageRepCocoa* cocoa_rep =
383 GetRepresentation(kImageRepCocoa, true)->AsImageRepCocoa();
384 internal::ImageRepPNG* png_rep = new internal::ImageRepPNG();
385 internal::PNGFromNSImage(cocoa_rep->image(), png_rep->image());
386 rep = png_rep;
387 break;
388 }
389 #endif
390 case kImageRepSkia: {
391 internal::ImageRepSkia* skia_rep =
392 GetRepresentation(kImageRepSkia, true)->AsImageRepSkia();
393 internal::ImageRepPNG* png_rep = new internal::ImageRepPNG();
394 internal::PNGFromImageSkia(skia_rep->image(), png_rep->image());
395 rep = png_rep;
396 break;
397 }
398 default:
399 NOTREACHED();
400 }
401 CHECK(rep);
402 AddRepresentation(rep);
403 }
404 return rep->AsImageRepPNG()->image();
405 }
406
270 const SkBitmap* Image::ToSkBitmap() const { 407 const SkBitmap* Image::ToSkBitmap() const {
271 // Possibly create and cache an intermediate ImageRepSkia. 408 // Possibly create and cache an intermediate ImageRepSkia.
272 return ToImageSkia()->bitmap(); 409 return ToImageSkia()->bitmap();
273 } 410 }
274 411
275 const ImageSkia* Image::ToImageSkia() const { 412 const ImageSkia* Image::ToImageSkia() const {
276 internal::ImageRep* rep = GetRepresentation(kImageRepSkia, false); 413 internal::ImageRep* rep = GetRepresentation(kImageRepSkia, false);
277 if (!rep) { 414 if (!rep) {
415 switch (DefaultRepresentationType()) {
416 case kImageRepPNG: {
417 internal::ImageRepPNG* png_rep =
418 GetRepresentation(kImageRepPNG, true)->AsImageRepPNG();
419 rep = new internal::ImageRepSkia(
420 internal::ImageSkiaFromPNG(*png_rep->image()));
421 break;
422 }
278 #if defined(TOOLKIT_GTK) 423 #if defined(TOOLKIT_GTK)
279 internal::ImageRepGdk* native_rep = 424 case kImageRepGdk: {
280 GetRepresentation(kImageRepGdk, true)->AsImageRepGdk(); 425 internal::ImageRepGdk* native_rep =
281 rep = new internal::ImageRepSkia(new ImageSkia( 426 GetRepresentation(kImageRepGdk, true)->AsImageRepGdk();
282 internal::ImageSkiaFromGdkPixbuf(native_rep->pixbuf()))); 427 rep = new internal::ImageRepSkia(new ImageSkia(
428 internal::ImageSkiaFromGdkPixbuf(native_rep->pixbuf())));
429 break;
430 }
283 #elif defined(OS_MACOSX) 431 #elif defined(OS_MACOSX)
284 internal::ImageRepCocoa* native_rep = 432 case kImageRepCocoa: {
285 GetRepresentation(kImageRepCocoa, true)->AsImageRepCocoa(); 433 internal::ImageRepCocoa* native_rep =
286 rep = new internal::ImageRepSkia(new ImageSkia( 434 GetRepresentation(kImageRepCocoa, true)->AsImageRepCocoa();
287 ImageSkiaFromNSImage(native_rep->image()))); 435 rep = new internal::ImageRepSkia(new ImageSkia(
436 ImageSkiaFromNSImage(native_rep->image())));
437 break;
438 }
288 #endif 439 #endif
440 default:
441 NOTREACHED();
442 }
289 CHECK(rep); 443 CHECK(rep);
290 AddRepresentation(rep); 444 AddRepresentation(rep);
291 } 445 }
292 return rep->AsImageRepSkia()->image(); 446 return rep->AsImageRepSkia()->image();
293 } 447 }
294 448
295 #if defined(TOOLKIT_GTK) 449 #if defined(TOOLKIT_GTK)
296 GdkPixbuf* Image::ToGdkPixbuf() const { 450 GdkPixbuf* Image::ToGdkPixbuf() const {
297 internal::ImageRep* rep = GetRepresentation(kImageRepGdk, false); 451 internal::ImageRep* rep = GetRepresentation(kImageRepGdk, false);
298 if (!rep) { 452 if (!rep) {
299 internal::ImageRepSkia* skia_rep = 453 switch (DefaultRepresentationType()) {
300 GetRepresentation(kImageRepSkia, true)->AsImageRepSkia(); 454 case kImageRepPNG: {
301 rep = new internal::ImageRepGdk(gfx::GdkPixbufFromSkBitmap( 455 internal::ImageRepPNG* png_rep =
302 *skia_rep->image()->bitmap())); 456 GetRepresentation(kImageRepPNG, true)->AsImageRepPNG();
457 rep = new internal::ImageRepGdk(internal::GdkPixbufFromPNG(
458 *png_rep->image()));
459 break;
460 }
461 case kImageRepSkia: {
462 internal::ImageRepSkia* skia_rep =
463 GetRepresentation(kImageRepSkia, true)->AsImageRepSkia();
464 rep = new internal::ImageRepGdk(gfx::GdkPixbufFromSkBitmap(
465 *skia_rep->image()->bitmap()));
466 break;
467 }
468 default:
469 NOTREACHED();
470 }
303 CHECK(rep); 471 CHECK(rep);
304 AddRepresentation(rep); 472 AddRepresentation(rep);
305 } 473 }
306 return rep->AsImageRepGdk()->pixbuf(); 474 return rep->AsImageRepGdk()->pixbuf();
307 } 475 }
308 476
309 CairoCachedSurface* const Image::ToCairo() const { 477 CairoCachedSurface* const Image::ToCairo() const {
310 internal::ImageRep* rep = GetRepresentation(kImageRepCairo, false); 478 internal::ImageRep* rep = GetRepresentation(kImageRepCairo, false);
311 if (!rep) { 479 if (!rep) {
312 // Handle any-to-Cairo conversion. This may create and cache an intermediate 480 // Handle any-to-Cairo conversion. This may create and cache an intermediate
313 // pixbuf before sending the data to the display server. 481 // pixbuf before sending the data to the display server.
314 rep = new internal::ImageRepCairo(ToGdkPixbuf()); 482 rep = new internal::ImageRepCairo(ToGdkPixbuf());
315 CHECK(rep); 483 CHECK(rep);
316 AddRepresentation(rep); 484 AddRepresentation(rep);
317 } 485 }
318 return rep->AsImageRepCairo()->surface(); 486 return rep->AsImageRepCairo()->surface();
319 } 487 }
320 #endif 488 #endif
321 489
322 #if defined(OS_MACOSX) 490 #if defined(OS_MACOSX)
323 NSImage* Image::ToNSImage() const { 491 NSImage* Image::ToNSImage() const {
324 internal::ImageRep* rep = GetRepresentation(kImageRepCocoa, false); 492 internal::ImageRep* rep = GetRepresentation(kImageRepCocoa, false);
325 if (!rep) { 493 if (!rep) {
326 internal::ImageRepSkia* skia_rep = 494 switch (DefaultRepresentationType()) {
327 GetRepresentation(kImageRepSkia, true)->AsImageRepSkia(); 495 case kImageRepPNG: {
328 NSImage* image = NSImageFromImageSkia(*skia_rep->image()); 496 internal::ImageRepPNG* png_rep =
329 base::mac::NSObjectRetain(image); 497 GetRepresentation(kImageRepPNG, true)->AsImageRepPNG();
330 rep = new internal::ImageRepCocoa(image); 498 rep = new internal::ImageRepCocoa(internal::NSImageFromPNG(
499 *png_rep->image()));
500 break;
501 }
502 case kImageRepSkia: {
503 internal::ImageRepSkia* skia_rep =
504 GetRepresentation(kImageRepSkia, true)->AsImageRepSkia();
505 NSImage* image = NSImageFromImageSkia(*skia_rep->image());
506 base::mac::NSObjectRetain(image);
507 rep = new internal::ImageRepCocoa(image);
508 break;
509 }
510 default:
511 NOTREACHED();
512 }
331 CHECK(rep); 513 CHECK(rep);
332 AddRepresentation(rep); 514 AddRepresentation(rep);
333 } 515 }
334 return rep->AsImageRepCocoa()->image(); 516 return rep->AsImageRepCocoa()->image();
335 } 517 }
336 #endif 518 #endif
337 519
520 std::vector<unsigned char>* Image::CopyImagePNG() const {
521 return new std::vector<unsigned char>(*ToImagePNG());
522 }
523
338 ImageSkia* Image::CopyImageSkia() const { 524 ImageSkia* Image::CopyImageSkia() const {
339 return new ImageSkia(*ToImageSkia()); 525 return new ImageSkia(*ToImageSkia());
340 } 526 }
341 527
342 SkBitmap* Image::CopySkBitmap() const { 528 SkBitmap* Image::CopySkBitmap() const {
343 return new SkBitmap(*ToSkBitmap()); 529 return new SkBitmap(*ToSkBitmap());
344 } 530 }
345 531
346 #if defined(TOOLKIT_GTK) 532 #if defined(TOOLKIT_GTK)
347 GdkPixbuf* Image::CopyGdkPixbuf() const { 533 GdkPixbuf* Image::CopyGdkPixbuf() const {
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
403 } 589 }
404 return it->second; 590 return it->second;
405 } 591 }
406 592
407 void Image::AddRepresentation(internal::ImageRep* rep) const { 593 void Image::AddRepresentation(internal::ImageRep* rep) const {
408 CHECK(storage_.get()); 594 CHECK(storage_.get());
409 storage_->representations().insert(std::make_pair(rep->type(), rep)); 595 storage_->representations().insert(std::make_pair(rep->type(), rep));
410 } 596 }
411 597
412 } // namespace gfx 598 } // namespace gfx
OLDNEW
« no previous file with comments | « ui/gfx/image/image.h ('k') | ui/gfx/image/image_mac.mm » ('j') | ui/gfx/image/image_mac.mm » ('J')

Powered by Google App Engine
This is Rietveld 408576698