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;