1 // Copyright 2005-6 Ben Hutchings <ben@decadent.org.uk>.
2 // See the file "COPYING" for licence details.
8 #include <gdkmm/pixbuf.h>
10 #include "auto_array.hpp"
13 // Find pixel differences between an "old" and "new" RGB Pixbuf
14 // (or RGBA, but the alpha component will be ignored) and copy the
15 // differing pixels from the new one to a third RGBA Pixbuf at the
16 // specified offset with full opacity.
17 // The width and height of the new Pixbufs must be equal and match
18 // the specified dimensions. The width and height of the old and
19 // third Pixbuf must be large enough to store a rectangle of
20 // those dimensions at the specified offset.
21 void diff_rgb_pixbufs(Glib::RefPtr<Gdk::Pixbuf> old_buf,
22 Glib::RefPtr<Gdk::Pixbuf> new_buf,
23 Glib::RefPtr<Gdk::Pixbuf> diff_buf,
24 int offset_x, int offset_y,
25 int width, int height)
27 assert(old_buf->get_colorspace() == Gdk::COLORSPACE_RGB);
28 assert(new_buf->get_colorspace() == Gdk::COLORSPACE_RGB);
29 assert(diff_buf->get_colorspace() == Gdk::COLORSPACE_RGB
30 && diff_buf->get_has_alpha());
31 int old_bpr = old_buf->get_rowstride();
32 int old_bpp = old_buf->get_n_channels();
34 assert(old_buf->get_width() >= offset_x + width);
35 assert(old_buf->get_height() >= offset_y + height);
36 int new_bpr = new_buf->get_rowstride();
37 int new_bpp = new_buf->get_n_channels();
39 assert(new_buf->get_width() == width);
40 assert(new_buf->get_height() == height);
41 int diff_bpr = diff_buf->get_rowstride();
42 int diff_bpp = diff_buf->get_n_channels();
43 assert(diff_bpp == 4);
44 assert(diff_buf->get_width() >= offset_x + width);
45 assert(diff_buf->get_height() >= offset_y + height);
47 const guint8 * old_p = (old_buf->get_pixels()
49 + old_bpp * offset_x);
50 const guint8 * new_p = new_buf->get_pixels();
51 guint8 * diff_p = (diff_buf->get_pixels()
53 + diff_bpp * offset_x);
55 for (int y = 0; y != height; ++y)
57 for (int x = 0; x != width; ++x)
59 if (old_p[0] != new_p[0]
60 || old_p[1] != new_p[1]
61 || old_p[2] != new_p[2])
66 diff_p[3] = 0xFF; // fully opaque
72 old_p += old_bpr - old_bpp * width;
73 new_p += new_bpr - new_bpp * width;
74 diff_p += diff_bpr - diff_bpp * width;
78 // Quantise an RGBA Pixbuf to the specified number of colours, including
79 // one transparent colour. Currently uses Floyd-Steinberg dithering.
80 void quantise_rgba_pixbuf(Glib::RefPtr<Gdk::Pixbuf> buf, int n_colours)
82 assert(buf->get_colorspace() == Gdk::COLORSPACE_RGB
83 && buf->get_has_alpha());
84 int bpr = buf->get_rowstride();
85 assert(buf->get_n_channels() == 4);
86 int width = buf->get_width();
87 int height = buf->get_height();
89 unsigned char * buf_p = buf->get_pixels();
90 auto_array<unsigned char *> rows(new unsigned char *[height]);
91 for (int y = 0; y != height; ++y)
92 rows[y] = &buf_p[y * bpr];
93 auto_array<unsigned char> quant_buf_p(
94 new unsigned char[width * height]);
95 auto_array<unsigned char *> quant_rows(
96 new unsigned char *[height]);
97 for (int y = 0; y != height; ++y)
98 quant_rows[y] = &quant_buf_p[y * width];
99 auto_array<unsigned int> colours(new unsigned int[n_colours]);
101 quantize(rows.get(), quant_rows.get(), width, height,
102 JDITHER_FS, n_colours, colours.get());
104 // Pixbuf doesn't support quantised images, so convert back to RGBA.
105 for (int y = 0; y != height; ++y)
106 for (int x = 0; x != width; ++x)
108 unsigned int colour = colours[quant_rows[y][x]];
109 rows[y][4*x] = colour;
110 rows[y][4*x+1] = colour >> 8;
111 rows[y][4*x+2] = colour >> 16;
112 rows[y][4*x+3] = colour >> 24;