228
// Converts XRGB/ARGB (Cairo)-formatted pixels to RGBA (GDK).
229
void fix_cairo_pixbuf(Gdk.Pixbuf pixbuf) {
230
uchar *gdk_pixels = pixbuf.pixels;
231
for (int j = 0 ; j < pixbuf.height; ++j) {
232
uchar *p = gdk_pixels;
233
uchar *end = p + 4 * pixbuf.width;
237
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
249
gdk_pixels += pixbuf.rowstride;
253
// Rotates a pixbuf to an arbitrary angle, given in degrees, and returns the rotated
254
// pixbuf. The caller is responsible for destroying the returned pixbuf after use.
255
Gdk.Pixbuf rotate_arb(Gdk.Pixbuf source_pixbuf, double angle) {
256
angle = degrees_to_radians(angle);
258
double x_min = 0.0, y_min = 0.0, x_max = 0.0, y_max = 0.0;
262
// Compute how much the corners of the source image will
263
// move by to determine how big the dest pixbuf should be.
265
// Lower left corner.
266
x_tmp = -(Math.sin(angle) * source_pixbuf.height);
267
y_tmp = (Math.cos(angle) * source_pixbuf.height);
269
if(x_tmp < x_min) x_min = x_tmp;
270
if(x_tmp > x_max) x_max = x_tmp;
272
if(y_tmp < y_min) y_min = y_tmp;
273
if(y_tmp > y_max) y_max = y_tmp;
275
// Lower right corner.
276
x_tmp = (Math.cos(angle) * source_pixbuf.width) - (Math.sin(angle) * source_pixbuf.height);
277
y_tmp = (Math.sin(angle) * source_pixbuf.width) + (Math.cos(angle) * source_pixbuf.height);
279
if(x_tmp < x_min) x_min = x_tmp;
280
if(x_tmp > x_max) x_max = x_tmp;
282
if(y_tmp < y_min) y_min = y_tmp;
283
if(y_tmp > y_max) y_max = y_tmp;
285
// Upper right corner.
286
x_tmp = (Math.cos(angle) * source_pixbuf.width);
287
y_tmp = (Math.sin(angle) * source_pixbuf.width);
289
if(x_tmp < x_min) x_min = x_tmp;
290
if(x_tmp > x_max) x_max = x_tmp;
292
if(y_tmp < y_min) y_min = y_tmp;
293
if(y_tmp > y_max) y_max = y_tmp;
295
Gdk.Pixbuf dest_pixbuf = new Gdk.Pixbuf(Gdk.Colorspace.RGB, true, 8, (int) Math.round(x_max - x_min), (int) Math.round(y_max - y_min));
297
Cairo.ImageSurface surface;
299
if(source_pixbuf.has_alpha) {
300
surface = new Cairo.ImageSurface.for_data(
301
(uchar []) dest_pixbuf.pixels, Cairo.Format.ARGB32,
302
dest_pixbuf.width, dest_pixbuf.height, dest_pixbuf.rowstride);
304
surface = new Cairo.ImageSurface.for_data(
305
(uchar []) dest_pixbuf.pixels, Cairo.Format.RGB24,
306
dest_pixbuf.width, dest_pixbuf.height, dest_pixbuf.rowstride);
309
Cairo.Context context = new Cairo.Context(surface);
311
context.set_source_rgb(0, 0, 0);
312
context.rectangle(0, 0, dest_pixbuf.width, dest_pixbuf.height);
315
context.translate(-x_min, -y_min);
316
context.rotate(angle);
317
Gdk.cairo_set_source_pixbuf(context, source_pixbuf, 0, 0);
318
context.get_source().set_filter(Cairo.Filter.BEST);
321
fix_cairo_pixbuf(dest_pixbuf);