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

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

Powered by Google App Engine
This is Rietveld 408576698