/* GdkPixbuf library - image transformation using 2x2 arbitrary matrix * * Copyright (C) 1999 The Free Software Foundation * * Authors: Oleg Klimov , John Costigan * * This file is part of Maemo Mapper. * * Maemo Mapper is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Maemo Mapper is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Maemo Mapper. If not, see . */ /* 1997-1999 original code was written * 2001-08-12 ported to GdkImage * 2003-01-31 ported to GdkPixbuf */ #define _GNU_SOURCE #include #include "gdk-pixbuf-rotate.h" /** * gdk_pixbuf_rotate_matrix_new: * * Creates a new 2x2 matrix. Allocates 4*sizeof(gfloat) buffer, * fills it with 1 on the main dialonal. * | 1 0 | * | 0 1 | * Static gfloat[4] buffer can be used instead. * * Return value: initialized matrix, destroy with g_free() **/ gfloat* gdk_pixbuf_rotate_matrix_new() { gfloat* matrix; matrix = g_malloc(sizeof(gfloat)*4); matrix[0] = 1; matrix[1] = 0; matrix[2] = 0; matrix[3] = 1; return matrix; } /** * gdk_pixbuf_rotate_matrix_fill_for_rotation: * @matrix: destination matrix * @angle: angle (radian) * * Prepare 2x2 matrix for rotation. * | cosf(a) -sinf(a) | * | sinf(a) cosf(a) | **/ void gdk_pixbuf_rotate_matrix_fill_for_rotation(gfloat* matrix, gfloat angle) { gfloat sa = sinf(angle), ca = cosf(angle); matrix[0] = ca; matrix[1] = -sa; matrix[2] = sa; matrix[3] = ca; } /** * gdk_pixbuf_rotate_matrix_mult_number: * @matrix: matrix to multiply * @mult: multiplier * * Multiply 2x2 matrix. * | *=mult *=mult | * | *=mult *=mult | * Use to scale image. **/ void gdk_pixbuf_rotate_matrix_mult_number(gfloat* matrix, gfloat mult) { matrix[0] *= mult; matrix[1] *= mult; matrix[2] *= mult; matrix[3] *= mult; } /** * gdk_pixbuf_rotate_matrix_mult_matrix: * @dst: matrix to store the result * @src1: left matrix to multiply * @src2: right matrix to multiply * * Multiply two 2x2 matrixes. Destination and any of the * sources can be one the same. * Use to combine two transformations. **/ void gdk_pixbuf_rotate_matrix_mult_matrix( gfloat* dst, const gfloat* src1, const gfloat* src2) { gfloat ans[4]; ans[0] = src1[0]*src2[0] + src1[1]*src2[2]; ans[1] = src1[0]*src2[1] + src1[1]*src2[3]; ans[2] = src1[2]*src2[0] + src1[3]*src2[2]; ans[3] = src1[2]*src2[1] + src1[3]*src2[3]; dst[0] = ans[0]; dst[1] = ans[1]; dst[2] = ans[2]; dst[3] = ans[3]; } /** * gdk_pixbuf_rotate_vector: * @dst_x: pointer to store X coord of the result vector * @dst_y: pointer to store Y coord of the result vector * @matrix: matrix to use * @src_x: X coord of source vector * @src_y: Y coord of source vector * * Convenience: the same matrix for transforming vectors. * Imagine you have a spaceship image, you rotate it and * now want to calculate where its spaceguns located. **/ void gdk_pixbuf_rotate_vector( gfloat* dst_x, gfloat* dst_y, const gfloat* matrix, gfloat src_x, gfloat src_y) { *dst_x = matrix[0]*src_x + matrix[1]*src_y; *dst_y = matrix[2]*src_x + matrix[3]*src_y; } inline gfloat gfloat_abs(gfloat d) { return d>0 ? d : -d; } inline gfloat gfloat_min(gfloat a, gfloat b) { return a>b ? b : a; } inline gfloat gfloat_max(gfloat a, gfloat b) { return a>b ? a : b; } /** * gdk_pixbuf_rotate_matrix_reverse: * @dest: matrix to store the result * @src: matrix to reverse * * Calculates reversed matrix. * * Return value: TRUE on success, FALSE when reverse * matrix doen't exist. **/ gboolean gdk_pixbuf_rotate_matrix_reverse(gfloat* dest, const gfloat* src) { gfloat ans[4]; gfloat det; gfloat consider_as_zero; det = gdk_pixbuf_rotate_matrix_determinant(src); consider_as_zero = (gfloat_abs(src[0]) + gfloat_abs(src[1]) + gfloat_abs(src[2]) + gfloat_abs(src[3])) * 1e-11; if (gfloat_abs(det)=px[c]) { left = px[c]; li = c; } if (right<=px[c]) { right = px[c]; ri = c; } if (top>=py[c]) { top = py[c]; ti = c; } if (bottom<=py[c]) { bottom = py[c]; bi = c; } } int_top = (gint) (dst_y + py[ti] + 0.5); int_top = CLAMP(int_top, 0, (gint)dst_height); int_bottom = (gint) (dst_y + py[bi] + 0.5); int_bottom = CLAMP(int_bottom, 0, (gint)dst_height); int_left = (gint) (dst_x + px[li] + 0.5); int_left = CLAMP(int_left, 0, (gint)dst_width); int_right = (gint) (dst_x + px[ri] + 0.5); int_right = CLAMP(int_right, 0, (gint)dst_width); if (result_rect_x) *result_rect_x = int_left; if (result_rect_y) *result_rect_y = int_top; if (result_rect_width) *result_rect_width = int_right - int_left; if (result_rect_height) *result_rect_height = int_bottom - int_top; if (int_right - int_left == 0 || int_bottom - int_top == 0) return; if (lines4) { line_l1 = li; line_r1 = ri; /* ti * li ri * bi */ if (((ti+1)%4)==ri) { line_l2 = bi; /* clockwise */ line_r2 = ti; /* line_l1 /\ line_r2 * \ \ * line_l2 \/ line_r1 */ } else { line_l2 = ti; /* anticlockwise */ line_r2 = bi; /* line_l2 /\ line_r1 * \ \ * line_l1 \/ line_r2 */ } } else { /* 2 lines case * | | * line_l1 | | line_r1 */ tmpd = (px[0]+px[1]+px[2]+px[3])/4.0; /* middle x */ tmpi = (ili+1)%4; /* valid for sure */ if (px[tmpi]>16)*src_bpl \ + (pixel_ix>>16)*SRC_CHANNELS; \ if (DST_CHANNELS==3 && SRC_CHANNELS==3) { \ dst[0] = src[0]; \ dst[1] = src[1]; \ dst[2] = src[2]; \ } \ if (DST_CHANNELS==4 && SRC_CHANNELS==3) { \ dst[0] = src[0]; \ dst[1] = src[1]; \ dst[2] = src[2]; \ dst[3] = 0xFF; \ } \ if (DST_CHANNELS==3 && SRC_CHANNELS==4) { \ guint a0, a1, t; \ a0 = (guint) src[3]; \ a1 = 0xff - a0; \ t = a0*src[0] + a1*dst[0] + 0x80; \ dst[0] = (t + (t>>8)) >> 8; \ t = a0*src[1] + a1*dst[1] + 0x80; \ dst[1] = (t + (t>>8)) >> 8; \ t = a0*src[2] + a1*dst[2] + 0x80; \ dst[2] = (t + (t>>8)) >> 8; \ } \ if (DST_CHANNELS==4 && SRC_CHANNELS==4) { \ guint a0 = (guint) src[3]; \ if (a0==255) { \ dst[0] = src[0]; \ dst[1] = src[1]; \ dst[2] = src[2]; \ dst[3] = 0xFF; \ } if (a0>0) { \ guint w0 = 0xff * a0; \ guint w1 = (0xff - a0) * dst[3]; \ guint w = w0 + w1; \ dst[0] = (w0*src[0] + w1*dst[0]) / w; \ dst[1] = (w0*src[1] + w1*dst[1]) / w; \ dst[2] = (w0*src[2] + w1*dst[2]) / w; \ dst[3] = w / 0xff; \ } \ } \ pixel_ix += pixel_right_ix; \ pixel_iy += pixel_right_iy; \ dst += DST_CHANNELS; \ } if (dst_n_channels==3 && src_n_channels==3) { for (x=x1; x>16)*src_bpl + (pixel_ix>>16)*3; dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; pixel_ix += pixel_right_ix; pixel_iy += pixel_right_iy; dst += 3; } } else if (dst_n_channels==3 && src_n_channels==4) { for (x=x1; x>16)*src_bpl + (pixel_ix>>16)*4; a0 = (guint) src[3]; a1 = 0xff - a0; t = a0*src[0] + a1*dst[0] + 0x80; dst[0] = (t + (t>>8)) >> 8; t = a0*src[1] + a1*dst[1] + 0x80; dst[1] = (t + (t>>8)) >> 8; t = a0*src[2] + a1*dst[2] + 0x80; dst[2] = (t + (t>>8)) >> 8; pixel_ix += pixel_right_ix; pixel_iy += pixel_right_iy; dst += 3; } } else if (dst_n_channels==4 && src_n_channels==3) { for (x=x1; x>16)*src_bpl + (pixel_ix>>16)*3; dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = 0xFF; pixel_ix += pixel_right_ix; pixel_iy += pixel_right_iy; dst += 4; } } else if (dst_n_channels==4 && src_n_channels==4) { for (x=x1; x>16)*src_bpl + (pixel_ix>>16)*4; a0 = (guint) src[3]; if (a0==255) { dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = 0xFF; } if (a0>0) { guint w0 = 0xff * a0; guint w1 = (0xff - a0) * dst[3]; guint w = w0 + w1; dst[0] = (w0*src[0] + w1*dst[0]) / w; dst[1] = (w0*src[1] + w1*dst[1]) / w; dst[2] = (w0*src[2] + w1*dst[2]) / w; dst[3] = w / 0xff; } pixel_ix += pixel_right_ix; pixel_iy += pixel_right_iy; dst += 4; } } } }