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

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 }
Robert Sesek 2012/08/06 21:54:04 nit: blank line after
103 void PNGFromImageSkia(const ImageSkia* skia, std::vector<unsigned char>* png) {
104 CHECK(gfx::PNGCodec::EncodeBGRASkBitmap(*skia->bitmap(), false, png));
105 }
106
107 class ImageRepPNG;
46 class ImageRepSkia; 108 class ImageRepSkia;
47 class ImageRepGdk; 109 class ImageRepGdk;
48 class ImageRepCairo; 110 class ImageRepCairo;
49 class ImageRepCocoa; 111 class ImageRepCocoa;
50 112
51 // An ImageRep is the object that holds the backing memory for an Image. Each 113 // 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 114 // RepresentationType has an ImageRep subclass that is responsible for freeing
53 // the memory that the ImageRep holds. When an ImageRep is created, it expects 115 // 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 116 // to take ownership of the image, without having to retain it or increase its
55 // reference count. 117 // reference count.
56 class ImageRep { 118 class ImageRep {
57 public: 119 public:
58 explicit ImageRep(Image::RepresentationType rep) : type_(rep) {} 120 explicit ImageRep(Image::RepresentationType rep) : type_(rep) {}
59 121
60 // Deletes the associated pixels of an ImageRep. 122 // Deletes the associated pixels of an ImageRep.
61 virtual ~ImageRep() {} 123 virtual ~ImageRep() {}
62 124
63 // Cast helpers ("fake RTTI"). 125 // Cast helpers ("fake RTTI").
126 ImageRepPNG* AsImageRepPNG() {
127 CHECK_EQ(type_, Image::kImageRepPNG);
128 return reinterpret_cast<ImageRepPNG*>(this);
129 }
130
64 ImageRepSkia* AsImageRepSkia() { 131 ImageRepSkia* AsImageRepSkia() {
65 CHECK_EQ(type_, Image::kImageRepSkia); 132 CHECK_EQ(type_, Image::kImageRepSkia);
66 return reinterpret_cast<ImageRepSkia*>(this); 133 return reinterpret_cast<ImageRepSkia*>(this);
67 } 134 }
68 135
69 #if defined(TOOLKIT_GTK) 136 #if defined(TOOLKIT_GTK)
70 ImageRepGdk* AsImageRepGdk() { 137 ImageRepGdk* AsImageRepGdk() {
71 CHECK_EQ(type_, Image::kImageRepGdk); 138 CHECK_EQ(type_, Image::kImageRepGdk);
72 return reinterpret_cast<ImageRepGdk*>(this); 139 return reinterpret_cast<ImageRepGdk*>(this);
73 } 140 }
(...skipping 10 matching lines...) Expand all
84 return reinterpret_cast<ImageRepCocoa*>(this); 151 return reinterpret_cast<ImageRepCocoa*>(this);
85 } 152 }
86 #endif 153 #endif
87 154
88 Image::RepresentationType type() const { return type_; } 155 Image::RepresentationType type() const { return type_; }
89 156
90 private: 157 private:
91 Image::RepresentationType type_; 158 Image::RepresentationType type_;
92 }; 159 };
93 160
161 class ImageRepPNG : public ImageRep {
162 public:
163 ImageRepPNG(const unsigned char* input, size_t input_size)
164 : ImageRep(Image::kImageRepPNG),
165 image_(input, input + input_size) {
166 }
167 ImageRepPNG() : ImageRep(Image::kImageRepPNG) {
168 }
169
170 virtual ~ImageRepPNG() {
171 }
172
173 std::vector<unsigned char>* image() { return &image_; }
174
175 private:
176 std::vector<unsigned char> image_;
177
178 DISALLOW_COPY_AND_ASSIGN(ImageRepPNG);
179 };
180
94 class ImageRepSkia : public ImageRep { 181 class ImageRepSkia : public ImageRep {
95 public: 182 public:
96 // Takes ownership of |image|. 183 // Takes ownership of |image|.
97 explicit ImageRepSkia(ImageSkia* image) 184 explicit ImageRepSkia(ImageSkia* image)
98 : ImageRep(Image::kImageRepSkia), 185 : ImageRep(Image::kImageRepSkia),
99 image_(image) { 186 image_(image) {
100 } 187 }
101 188
102 virtual ~ImageRepSkia() { 189 virtual ~ImageRepSkia() {
103 } 190 }
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
214 301
215 friend class base::RefCounted<ImageStorage>; 302 friend class base::RefCounted<ImageStorage>;
216 }; 303 };
217 304
218 } // namespace internal 305 } // namespace internal
219 306
220 Image::Image() { 307 Image::Image() {
221 // |storage_| is NULL for empty Images. 308 // |storage_| is NULL for empty Images.
222 } 309 }
223 310
311 Image::Image(const unsigned char* png, size_t input_size)
312 : storage_(new internal::ImageStorage(Image::kImageRepPNG)) {
313 internal::ImageRepPNG* rep = new internal::ImageRepPNG(png, input_size);
314 AddRepresentation(rep);
315 }
316
224 Image::Image(const ImageSkia& image) 317 Image::Image(const ImageSkia& image)
225 : storage_(new internal::ImageStorage(Image::kImageRepSkia)) { 318 : storage_(new internal::ImageStorage(Image::kImageRepSkia)) {
226 internal::ImageRepSkia* rep = new internal::ImageRepSkia( 319 internal::ImageRepSkia* rep = new internal::ImageRepSkia(
227 new ImageSkia(image)); 320 new ImageSkia(image));
228 AddRepresentation(rep); 321 AddRepresentation(rep);
229 } 322 }
230 323
231 Image::Image(const ImageSkiaRep& image_skia_rep) 324 Image::Image(const ImageSkiaRep& image_skia_rep)
232 : storage_(new internal::ImageStorage(Image::kImageRepSkia)) { 325 : storage_(new internal::ImageStorage(Image::kImageRepSkia)) {
233 internal::ImageRepSkia* rep = 326 internal::ImageRepSkia* rep =
(...skipping 28 matching lines...) Expand all
262 } 355 }
263 356
264 Image& Image::operator=(const Image& other) { 357 Image& Image::operator=(const Image& other) {
265 storage_ = other.storage_; 358 storage_ = other.storage_;
266 return *this; 359 return *this;
267 } 360 }
268 361
269 Image::~Image() { 362 Image::~Image() {
270 } 363 }
271 364
365 const std::vector<unsigned char>* Image::ToImagePNG() const {
366 internal::ImageRep* rep = GetRepresentation(kImageRepPNG, false);
367 if (!rep) {
368 internal::ImageRepPNG* png_rep = new internal::ImageRepPNG();
369 switch (DefaultRepresentationType()) {
370 #if defined(TOOLKIT_GTK)
371 case kImageRepGdk: {
372 internal::ImageRepGdk* gdk_rep =
373 GetRepresentation(kImageRepGdk, true)->AsImageRepGdk();
374 internal::PNGFromGdkPixbuf(gdk_rep->pixbuf(), png_rep->image());
375 break;
376 }
377 #elif defined(OS_MACOSX)
378 case kImageRepCocoa: {
379 internal::ImageRepCocoa* cocoa_rep =
380 GetRepresentation(kImageRepCocoa, true)->AsImageRepCocoa();
381 internal::PNGFromNSImage(cocoa_rep->image(), png_rep->image());
382 break;
383 }
384 #endif
385 case kImageRepSkia: {
386 internal::ImageRepSkia* skia_rep =
387 GetRepresentation(kImageRepSkia, true)->AsImageRepSkia();
388 internal::PNGFromImageSkia(skia_rep->image(), png_rep->image());
389 break;
390 }
391 default:
392 NOTREACHED();
393 }
394 rep = png_rep;
395 CHECK(rep);
396 AddRepresentation(rep);
397 }
398 return rep->AsImageRepPNG()->image();
399 }
400
272 const SkBitmap* Image::ToSkBitmap() const { 401 const SkBitmap* Image::ToSkBitmap() const {
273 // Possibly create and cache an intermediate ImageRepSkia. 402 // Possibly create and cache an intermediate ImageRepSkia.
274 return ToImageSkia()->bitmap(); 403 return ToImageSkia()->bitmap();
275 } 404 }
276 405
277 const ImageSkia* Image::ToImageSkia() const { 406 const ImageSkia* Image::ToImageSkia() const {
278 internal::ImageRep* rep = GetRepresentation(kImageRepSkia, false); 407 internal::ImageRep* rep = GetRepresentation(kImageRepSkia, false);
279 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 }
280 #if defined(TOOLKIT_GTK) 417 #if defined(TOOLKIT_GTK)
281 internal::ImageRepGdk* native_rep = 418 case kImageRepGdk: {
282 GetRepresentation(kImageRepGdk, true)->AsImageRepGdk(); 419 internal::ImageRepGdk* native_rep =
283 rep = new internal::ImageRepSkia(new ImageSkia( 420 GetRepresentation(kImageRepGdk, true)->AsImageRepGdk();
284 internal::ImageSkiaFromGdkPixbuf(native_rep->pixbuf()))); 421 rep = new internal::ImageRepSkia(new ImageSkia(
422 internal::ImageSkiaFromGdkPixbuf(native_rep->pixbuf())));
423 break;
424 }
285 #elif defined(OS_MACOSX) 425 #elif defined(OS_MACOSX)
286 internal::ImageRepCocoa* native_rep = 426 case kImageRepCocoa: {
287 GetRepresentation(kImageRepCocoa, true)->AsImageRepCocoa(); 427 internal::ImageRepCocoa* native_rep =
288 rep = new internal::ImageRepSkia(new ImageSkia( 428 GetRepresentation(kImageRepCocoa, true)->AsImageRepCocoa();
289 ImageSkiaFromNSImage(native_rep->image()))); 429 rep = new internal::ImageRepSkia(new ImageSkia(
430 ImageSkiaFromNSImage(native_rep->image())));
431 break;
432 }
290 #endif 433 #endif
434 default:
435 NOTREACHED();
436 }
291 CHECK(rep); 437 CHECK(rep);
292 AddRepresentation(rep); 438 AddRepresentation(rep);
293 } 439 }
294 return rep->AsImageRepSkia()->image(); 440 return rep->AsImageRepSkia()->image();
295 } 441 }
296 442
297 #if defined(TOOLKIT_GTK) 443 #if defined(TOOLKIT_GTK)
298 GdkPixbuf* Image::ToGdkPixbuf() const { 444 GdkPixbuf* Image::ToGdkPixbuf() const {
299 internal::ImageRep* rep = GetRepresentation(kImageRepGdk, false); 445 internal::ImageRep* rep = GetRepresentation(kImageRepGdk, false);
300 if (!rep) { 446 if (!rep) {
301 internal::ImageRepSkia* skia_rep = 447 switch (DefaultRepresentationType()) {
302 GetRepresentation(kImageRepSkia, true)->AsImageRepSkia(); 448 case kImageRepPNG: {
303 rep = new internal::ImageRepGdk(gfx::GdkPixbufFromSkBitmap( 449 internal::ImageRepPNG* png_rep =
304 *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 }
305 CHECK(rep); 465 CHECK(rep);
306 AddRepresentation(rep); 466 AddRepresentation(rep);
307 } 467 }
308 return rep->AsImageRepGdk()->pixbuf(); 468 return rep->AsImageRepGdk()->pixbuf();
309 } 469 }
310 470
311 CairoCachedSurface* const Image::ToCairo() const { 471 CairoCachedSurface* const Image::ToCairo() const {
312 internal::ImageRep* rep = GetRepresentation(kImageRepCairo, false); 472 internal::ImageRep* rep = GetRepresentation(kImageRepCairo, false);
313 if (!rep) { 473 if (!rep) {
314 // 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
315 // pixbuf before sending the data to the display server. 475 // pixbuf before sending the data to the display server.
316 rep = new internal::ImageRepCairo(ToGdkPixbuf()); 476 rep = new internal::ImageRepCairo(ToGdkPixbuf());
317 CHECK(rep); 477 CHECK(rep);
318 AddRepresentation(rep); 478 AddRepresentation(rep);
319 } 479 }
320 return rep->AsImageRepCairo()->surface(); 480 return rep->AsImageRepCairo()->surface();
321 } 481 }
322 #endif 482 #endif
323 483
324 #if defined(OS_MACOSX) 484 #if defined(OS_MACOSX)
325 NSImage* Image::ToNSImage() const { 485 NSImage* Image::ToNSImage() const {
326 internal::ImageRep* rep = GetRepresentation(kImageRepCocoa, false); 486 internal::ImageRep* rep = GetRepresentation(kImageRepCocoa, false);
327 if (!rep) { 487 if (!rep) {
328 internal::ImageRepSkia* skia_rep = 488 switch (DefaultRepresentationType()) {
329 GetRepresentation(kImageRepSkia, true)->AsImageRepSkia(); 489 case kImageRepPNG: {
330 NSImage* image = NSImageFromImageSkia(*skia_rep->image()); 490 internal::ImageRepPNG* png_rep =
331 base::mac::NSObjectRetain(image); 491 GetRepresentation(kImageRepPNG, true)->AsImageRepPNG();
332 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 }
333 CHECK(rep); 507 CHECK(rep);
334 AddRepresentation(rep); 508 AddRepresentation(rep);
335 } 509 }
336 return rep->AsImageRepCocoa()->image(); 510 return rep->AsImageRepCocoa()->image();
337 } 511 }
338 #endif 512 #endif
339 513
514 std::vector<unsigned char>* Image::CopyImagePNG() const {
515 return new std::vector<unsigned char>(*ToImagePNG());
516 }
517
340 SkBitmap Image::AsBitmap() const { 518 SkBitmap Image::AsBitmap() const {
341 return IsEmpty() ? SkBitmap() : *ToSkBitmap(); 519 return IsEmpty() ? SkBitmap() : *ToSkBitmap();
342 } 520 }
343 521
344 ImageSkia Image::AsImageSkia() const { 522 ImageSkia Image::AsImageSkia() const {
345 return IsEmpty() ? ImageSkia(SkBitmap()) : *ToImageSkia(); 523 return IsEmpty() ? ImageSkia(SkBitmap()) : *ToImageSkia();
346 } 524 }
347 525
348 ImageSkia* Image::CopyImageSkia() const { 526 ImageSkia* Image::CopyImageSkia() const {
349 return new ImageSkia(*ToImageSkia()); 527 return new ImageSkia(*ToImageSkia());
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
413 } 591 }
414 return it->second; 592 return it->second;
415 } 593 }
416 594
417 void Image::AddRepresentation(internal::ImageRep* rep) const { 595 void Image::AddRepresentation(internal::ImageRep* rep) const {
418 CHECK(storage_.get()); 596 CHECK(storage_.get());
419 storage_->representations().insert(std::make_pair(rep->type(), rep)); 597 storage_->representations().insert(std::make_pair(rep->type(), rep));
420 } 598 }
421 599
422 } // namespace gfx 600 } // 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