mirror of https://github.com/GNOME/gimp.git
app/paint_core.c: Improvements to the transform_core_do and cubic routines
app/paint_core.c: Improvements to the transform_core_do and cubic routines by David Hodson <hodsond@acm.org> "This fixes a number of annoying inaccuracies in transform_core. The identity transform now leaves all pixels unchanged; previously it shifted the image by 1/2 pixel left and up. All edges of an image are now correctly antialiased after a transform. The cubic interpolation function has been changed to a slightly smoother one. The code has been tidied and rearranged for some minor improvements in efficiency, but the basic logic and tile handling have not changed."
This commit is contained in:
parent
55f89d6e23
commit
823817cc52
12
ChangeLog
12
ChangeLog
|
@ -1,3 +1,15 @@
|
|||
Tue Aug 3 02:13:57 1999 Jay Cox (jaycox@earthlink.net)
|
||||
|
||||
* app/paint_core.c: Improvements to the transform_core_do and cubic
|
||||
routines by David Hodson <hodsond@acm.org>
|
||||
"This fixes a number of annoying inaccuracies in transform_core.
|
||||
The identity transform now leaves all pixels unchanged; previously
|
||||
it shifted the image by 1/2 pixel left and up. All edges of an
|
||||
image are now correctly antialiased after a transform. The cubic
|
||||
interpolation function has been changed to a slightly smoother one.
|
||||
The code has been tidied and rearranged for some minor improvements
|
||||
in efficiency, but the basic logic and tile handling have not changed."
|
||||
|
||||
1999-08-03 Tor Lillqvist <tml@iki.fi>
|
||||
|
||||
* plug-ins/Makefile.am
|
||||
|
|
|
@ -48,6 +48,10 @@
|
|||
#define M_PI 3.14159265358979323846
|
||||
#endif /* M_PI */
|
||||
|
||||
#define BILINEAR(jk,j1k,jk1,j1k1,dx,dy) \
|
||||
((1-dy) * (jk + dx * (j1k - jk)) + \
|
||||
dy * (jk1 + dx * (j1k1 - jk1)))
|
||||
|
||||
/* variables */
|
||||
static TranInfo old_trans_info;
|
||||
InfoDialog * transform_info = NULL;
|
||||
|
@ -65,11 +69,6 @@ static void transform_core_grid_recalc (TransformCore *);
|
|||
void paths_draw_current (GDisplay *, DrawCore *,
|
||||
GimpMatrix);
|
||||
|
||||
|
||||
#define BILINEAR(jk,j1k,jk1,j1k1,dx,dy) \
|
||||
((1-dy) * ((1-dx)*jk + dx*j1k) + \
|
||||
dy * ((1-dx)*jk1 + dx*j1k1))
|
||||
|
||||
#define REF_TILE(i,x,y) \
|
||||
tile[i] = tile_manager_get_tile (float_tiles, x, y, TRUE, FALSE); \
|
||||
src[i] = tile_data_pointer (tile[i], (x) % TILE_WIDTH, (y) % TILE_HEIGHT);
|
||||
|
@ -989,12 +988,12 @@ transform_core_recalc (Tool *tool,
|
|||
/* Actually carry out a transformation */
|
||||
TileManager *
|
||||
transform_core_do (GImage *gimage,
|
||||
GimpDrawable *drawable,
|
||||
TileManager *float_tiles,
|
||||
int interpolation,
|
||||
GimpMatrix matrix,
|
||||
progress_func_t progress_callback,
|
||||
gpointer progress_data)
|
||||
GimpDrawable *drawable,
|
||||
TileManager *float_tiles,
|
||||
int interpolation,
|
||||
GimpMatrix matrix,
|
||||
progress_func_t progress_callback,
|
||||
gpointer progress_data)
|
||||
{
|
||||
PixelRegion destPR;
|
||||
TileManager *tiles;
|
||||
|
@ -1007,14 +1006,10 @@ transform_core_do (GImage *gimage,
|
|||
int bytes, b;
|
||||
int x, y;
|
||||
int sx, sy;
|
||||
int plus_x, plus_y;
|
||||
int plus2_x, plus2_y;
|
||||
int minus_x, minus_y;
|
||||
int x1, y1, x2, y2;
|
||||
double xinc, yinc, winc;
|
||||
double tx, ty, tw;
|
||||
double ttx = 0.0, tty = 0.0;
|
||||
double dx = 0.0, dy = 0.0;
|
||||
unsigned char * dest, * d;
|
||||
unsigned char * src[16];
|
||||
double src_a[16][MAX_CHANNELS];
|
||||
|
@ -1026,12 +1021,13 @@ transform_core_do (GImage *gimage,
|
|||
int newval;
|
||||
|
||||
alpha = 0;
|
||||
|
||||
|
||||
/* turn interpolation off for simple transformations (e.g. rot90) */
|
||||
if (gimp_matrix_is_simple (matrix))
|
||||
interpolation = FALSE;
|
||||
|
||||
/* Get the background color */
|
||||
/* Check - background colour only works for non-interpolated transforms? */
|
||||
gimage_get_background (gimage, drawable, bg_col);
|
||||
|
||||
switch (drawable_type (drawable))
|
||||
|
@ -1055,7 +1051,7 @@ transform_core_do (GImage *gimage,
|
|||
if (transform_tool_direction () == TRANSFORM_CORRECTIVE)
|
||||
{
|
||||
/* keep the original matrix here, so we dont need to recalculate
|
||||
the inverse later */
|
||||
the inverse later */
|
||||
gimp_matrix_duplicate (matrix, m);
|
||||
gimp_matrix_invert (matrix, im);
|
||||
matrix = im;
|
||||
|
@ -1066,7 +1062,7 @@ transform_core_do (GImage *gimage,
|
|||
gimp_matrix_invert (matrix, m);
|
||||
}
|
||||
|
||||
paths_transform_current_path (gimage, matrix, FALSE);
|
||||
paths_transform_current_path(gimage,matrix,FALSE);
|
||||
|
||||
x1 = float_tiles->x;
|
||||
y1 = float_tiles->y;
|
||||
|
@ -1123,229 +1119,330 @@ transform_core_do (GImage *gimage,
|
|||
for (y = ty1; y < ty2; y++)
|
||||
{
|
||||
if (progress_callback && !(y & 0xf))
|
||||
(*progress_callback)(ty1, ty2, y, progress_data);
|
||||
(*progress_callback)(ty1, ty2, y, progress_data);
|
||||
|
||||
/* When we calculate the inverse transformation, we should transform
|
||||
* the center of each destination pixel...
|
||||
*/
|
||||
tx = xinc * (tx1 + 0.5) + m[0][1] * (y + 0.5) + m[0][2];
|
||||
ty = yinc * (tx1 + 0.5) + m[1][1] * (y + 0.5) + m[1][2];
|
||||
tw = winc * (tx1 + 0.5) + m[2][1] * (y + 0.5) + m[2][2];
|
||||
|
||||
/* Actually, no. Relabel them in your head, if you must */
|
||||
|
||||
tx = xinc * tx1 + m[0][1] * y + m[0][2];
|
||||
ty = yinc * tx1 + m[1][1] * y + m[1][2];
|
||||
tw = winc * tx1 + m[2][1] * y + m[2][2];
|
||||
d = dest;
|
||||
|
||||
for (x = tx1; x < tx2; x++)
|
||||
{
|
||||
/* normalize homogeneous coords */
|
||||
if (tw == 0.0)
|
||||
g_message (_("homogeneous coordinate = 0...\n"));
|
||||
else if (tw != 1.0)
|
||||
{
|
||||
ttx = tx / tw;
|
||||
tty = ty / tw;
|
||||
}
|
||||
else
|
||||
{
|
||||
ttx = tx;
|
||||
tty = ty;
|
||||
}
|
||||
{
|
||||
/* normalize homogeneous coords */
|
||||
if (tw == 0.0)
|
||||
g_message (_("homogeneous coordinate = 0...\n"));
|
||||
else if (tw != 1.0)
|
||||
{
|
||||
ttx = tx / tw;
|
||||
tty = ty / tw;
|
||||
}
|
||||
else
|
||||
{
|
||||
ttx = tx;
|
||||
tty = ty;
|
||||
}
|
||||
|
||||
/* tx & ty are the coordinates of the point in the original
|
||||
* selection's floating buffer. Make sure they're within bounds
|
||||
*/
|
||||
if (ttx < 0)
|
||||
itx = (int) (ttx - 0.999999);
|
||||
else
|
||||
itx = (int) ttx;
|
||||
/* Set the destination pixels */
|
||||
|
||||
if (tty < 0)
|
||||
ity = (int) (tty - 0.999999);
|
||||
else
|
||||
ity = (int) tty;
|
||||
if (interpolation)
|
||||
{
|
||||
/* ttx & tty are the coordinates of the point in the original
|
||||
* selection's floating buffer. Make sure they're within bounds
|
||||
*/
|
||||
itx = floor(ttx);
|
||||
ity = floor(tty);
|
||||
|
||||
/* if interpolation is on, get the fractional error */
|
||||
if (interpolation)
|
||||
{
|
||||
dx = ttx - itx;
|
||||
dy = tty - ity;
|
||||
}
|
||||
if (cubic_interpolation)
|
||||
{
|
||||
|
||||
if (itx >= x1 && itx < x2 && ity >= y1 && ity < y2)
|
||||
{
|
||||
/* x, y coordinates into source tiles */
|
||||
sx = itx - x1;
|
||||
sy = ity - y1;
|
||||
/* expand source area to cover interpolation region */
|
||||
/* (which runs from itx - 1 to itx + 2, same in y) */
|
||||
if ((itx + 2) >= x1 && (itx - 1) < x2 &&
|
||||
(ity + 2) >= y1 && (ity - 1) < y2 )
|
||||
{
|
||||
/* to hold clipping info */
|
||||
int use_x[4], use_y[4];
|
||||
/* to hold index */
|
||||
int index_x[4], index_y[4];
|
||||
int xy_i;
|
||||
|
||||
/* Set the destination pixels */
|
||||
if (interpolation)
|
||||
{
|
||||
plus_x = (itx < (x2 - 1)) ? 1 : 0;
|
||||
plus_y = (ity < (y2 - 1)) ? 1 : 0;
|
||||
/* get the fractional error */
|
||||
double dx, dy;
|
||||
dx = ttx - itx;
|
||||
dy = tty - ity;
|
||||
|
||||
if (cubic_interpolation)
|
||||
{
|
||||
minus_x = (itx > x1) ? -1 : 0;
|
||||
plus2_x = ((itx + 1) < (x2 - 1)) ? 2 : plus_x;
|
||||
/* setup indices and clip flags */
|
||||
/* now correctly handles very small images (why?) */
|
||||
|
||||
minus_y = (ity > y1) ? -1 : 0;
|
||||
plus2_y = ((ity + 1) < (y2 - 1)) ? 2 : plus_y;
|
||||
for (xy_i = 0; xy_i < 4; ++xy_i)
|
||||
{
|
||||
use_x[xy_i] = 1;
|
||||
use_y[xy_i] = 1;
|
||||
index_x[xy_i] = (itx - 1) - x1 + xy_i;
|
||||
index_y[xy_i] = (ity - 1) - y1 + xy_i;
|
||||
}
|
||||
|
||||
REF_TILE (0, sx + minus_x, sy + minus_y);
|
||||
REF_TILE (1, sx, sy + minus_y);
|
||||
REF_TILE (2, sx + plus_x, sy + minus_y);
|
||||
REF_TILE (3, sx + plus2_x, sy + minus_y);
|
||||
REF_TILE (4, sx + minus_x, sy);
|
||||
REF_TILE (5, sx, sy);
|
||||
REF_TILE (6, sx + plus_x, sy);
|
||||
REF_TILE (7, sx + plus2_x, sy);
|
||||
REF_TILE (8, sx + minus_x, sy + plus_y);
|
||||
REF_TILE (9, sx, sy + plus_y);
|
||||
REF_TILE (10, sx + plus_x, sy + plus_y);
|
||||
REF_TILE (11, sx + plus2_x, sy + plus_y);
|
||||
REF_TILE (12, sx + minus_x, sy + plus2_y);
|
||||
REF_TILE (13, sx, sy + plus2_y);
|
||||
REF_TILE (14, sx + plus_x, sy + plus2_y);
|
||||
REF_TILE (15, sx + plus2_x, sy + plus2_y);
|
||||
/* ugly, ugly code */
|
||||
|
||||
a[0] = (minus_y * minus_x) ? src[0][alpha] : 0;
|
||||
a[1] = (minus_y) ? src[1][alpha] : 0;
|
||||
a[2] = (minus_y * plus_x) ? src[2][alpha] : 0;
|
||||
a[3] = (minus_y * plus2_x) ? src[3][alpha] : 0;
|
||||
/* clip x to left hand edge */
|
||||
if ((itx - 1) < x1) {
|
||||
use_x[0] = 0;
|
||||
index_x[0] = 0;
|
||||
if (itx < x1) {
|
||||
use_x[1] = 0;
|
||||
index_x[1] = 0;
|
||||
if ((itx + 1) < x1) {
|
||||
use_x[2] = 0;
|
||||
index_x[2] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* clip x to right hand edge */
|
||||
if ((itx + 2) >= x2) {
|
||||
int xlimit = x2 - 1 - x1;
|
||||
use_x[3] = 0;
|
||||
index_x[3] = xlimit;
|
||||
if ((itx + 1) >= x2) {
|
||||
use_x[2] = 0;
|
||||
index_x[2] = xlimit;
|
||||
if (itx >= x2) {
|
||||
use_x[1] = 0;
|
||||
index_x[1] = xlimit;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* clip y to top edge */
|
||||
if ((ity - 1) < y1) {
|
||||
use_y[0] = 0;
|
||||
index_y[0] = 0;
|
||||
if (ity < y1) {
|
||||
use_y[1] = 0;
|
||||
index_y[1] = 0;
|
||||
if ((ity + 1) < y1) {
|
||||
use_y[2] = 0;
|
||||
index_y[2] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* clip y to bottom edge */
|
||||
if ((ity + 2) >= y2) {
|
||||
int ylimit = y2 - 1 - y1;
|
||||
use_y[3] = 0;
|
||||
index_y[3] = ylimit;
|
||||
if ((ity + 1) >= y2) {
|
||||
use_y[2] = 0;
|
||||
index_y[2] = ylimit;
|
||||
if (ity >= y2) {
|
||||
use_y[1] = 0;
|
||||
index_y[1] = ylimit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
a[4] = (minus_x) ? src[4][alpha] : 0;
|
||||
a[5] = src[5][alpha];
|
||||
a[6] = (plus_x) ? src[6][alpha] : 0;
|
||||
a[7] = (plus2_x) ? src[7][alpha] : 0;
|
||||
|
||||
a[8] = (plus_y * minus_x) ? src[8][alpha] : 0;
|
||||
a[9] = (plus_y) ? src[9][alpha] : 0;
|
||||
a[10] = (plus_y * plus_x) ? src[10][alpha] : 0;
|
||||
a[11] = (plus_y * plus2_x) ? src[11][alpha] : 0;
|
||||
REF_TILE (0, index_x[0], index_y[0]);
|
||||
REF_TILE (1, index_x[1], index_y[0]);
|
||||
REF_TILE (2, index_x[2], index_y[0]);
|
||||
REF_TILE (3, index_x[3], index_y[0]);
|
||||
REF_TILE (4, index_x[0], index_y[1]);
|
||||
REF_TILE (5, index_x[1], index_y[1]);
|
||||
REF_TILE (6, index_x[2], index_y[1]);
|
||||
REF_TILE (7, index_x[3], index_y[1]);
|
||||
REF_TILE (8, index_x[0], index_y[2]);
|
||||
REF_TILE (9, index_x[1], index_y[2]);
|
||||
REF_TILE (10, index_x[2], index_y[2]);
|
||||
REF_TILE (11, index_x[3], index_y[2]);
|
||||
REF_TILE (12, index_x[0], index_y[3]);
|
||||
REF_TILE (13, index_x[1], index_y[3]);
|
||||
REF_TILE (14, index_x[2], index_y[3]);
|
||||
REF_TILE (15, index_x[3], index_y[3]);
|
||||
|
||||
a[12] = (plus2_y * minus_x) ? src[12][alpha] : 0;
|
||||
a[13] = (plus2_y) ? src[13][alpha] : 0;
|
||||
a[14] = (plus2_y * plus_x) ? src[14][alpha] : 0;
|
||||
a[15] = (plus2_y * plus2_x) ? src[15][alpha] : 0;
|
||||
a[0] = (use_x[0] && use_y[0]) ? src[0][alpha] : 0;
|
||||
a[1] = (use_x[1] && use_y[0]) ? src[1][alpha] : 0;
|
||||
a[2] = (use_x[2] && use_y[0]) ? src[2][alpha] : 0;
|
||||
a[3] = (use_x[3] && use_y[0]) ? src[3][alpha] : 0;
|
||||
|
||||
a_val = cubic (dy,
|
||||
cubic (dx, a[0], a[1], a[2], a[3]),
|
||||
cubic (dx, a[4], a[5], a[6], a[7]),
|
||||
cubic (dx, a[8], a[9], a[10], a[11]),
|
||||
cubic (dx, a[12], a[13], a[14], a[15]));
|
||||
a[4] = (use_x[0] && use_y[1]) ? src[4][alpha] : 0;
|
||||
a[5] = (use_x[1] && use_y[1]) ? src[5][alpha] : 0;
|
||||
a[6] = (use_x[2] && use_y[1]) ? src[6][alpha] : 0;
|
||||
a[7] = (use_x[3] && use_y[1]) ? src[7][alpha] : 0;
|
||||
|
||||
if (a_val != 0)
|
||||
a_recip = 255.0 / a_val;
|
||||
else
|
||||
a_recip = 0.0;
|
||||
a[8] = (use_x[0] && use_y[2]) ? src[8][alpha] : 0;
|
||||
a[9] = (use_x[1] && use_y[2]) ? src[9][alpha] : 0;
|
||||
a[10] = (use_x[2] && use_y[2]) ? src[10][alpha] : 0;
|
||||
a[11] = (use_x[3] && use_y[2]) ? src[11][alpha] : 0;
|
||||
|
||||
/* premultiply the alpha */
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
a_mult = a[i] * (1.0 / 255.0);
|
||||
for (b = 0; b < alpha; b++)
|
||||
src_a[i][b] = src[i][b] * a_mult;
|
||||
}
|
||||
a[12] = (use_x[0] && use_y[3]) ? src[12][alpha] : 0;
|
||||
a[13] = (use_x[1] && use_y[3]) ? src[13][alpha] : 0;
|
||||
a[14] = (use_x[2] && use_y[3]) ? src[14][alpha] : 0;
|
||||
a[15] = (use_x[3] && use_y[3]) ? src[15][alpha] : 0;
|
||||
|
||||
for (b = 0; b < alpha; b++)
|
||||
{
|
||||
newval =
|
||||
a_recip *
|
||||
cubic (dy,
|
||||
cubic (dx, src_a[0][b], src_a[1][b], src_a[2][b], src_a[3][b]),
|
||||
cubic (dx, src_a[4][b], src_a[5][b], src_a[6][b], src_a[7][b]),
|
||||
cubic (dx, src_a[8][b], src_a[9][b], src_a[10][b], src_a[11][b]),
|
||||
cubic (dx, src_a[12][b], src_a[13][b], src_a[14][b], src_a[15][b]));
|
||||
if ((newval & 0x100) == 0)
|
||||
*d++ = newval;
|
||||
else if (newval < 0)
|
||||
*d++ = 0;
|
||||
else
|
||||
*d++ = 255;
|
||||
}
|
||||
a_val = cubic (dy,
|
||||
cubic (dx, a[0], a[1], a[2], a[3]),
|
||||
cubic (dx, a[4], a[5], a[6], a[7]),
|
||||
cubic (dx, a[8], a[9], a[10], a[11]),
|
||||
cubic (dx, a[12], a[13], a[14], a[15]));
|
||||
|
||||
*d++ = a_val;
|
||||
if (a_val != 0)
|
||||
a_recip = 255.0 / a_val;
|
||||
else
|
||||
a_recip = 0.0;
|
||||
|
||||
for (b = 0; b < 16; b++)
|
||||
tile_release (tile[b], FALSE);
|
||||
}
|
||||
else /* linear */
|
||||
{
|
||||
REF_TILE (0, sx, sy);
|
||||
REF_TILE (1, sx + plus_x, sy);
|
||||
REF_TILE (2, sx, sy + plus_y);
|
||||
REF_TILE (3, sx + plus_x, sy + plus_y);
|
||||
/* premultiply the alpha */
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
a_mult = a[i] * (1.0 / 255.0);
|
||||
for (b = 0; b < alpha; b++)
|
||||
src_a[i][b] = src[i][b] * a_mult;
|
||||
}
|
||||
|
||||
/* Need special treatment for the alpha channel */
|
||||
if (plus_x == 0 && plus_y == 0)
|
||||
{
|
||||
a[0] = src[0][alpha];
|
||||
a[1] = a[2] = a[3] = 0;
|
||||
}
|
||||
else if (plus_x == 0)
|
||||
{
|
||||
a[0] = src[0][alpha];
|
||||
a[2] = src[2][alpha];
|
||||
a[1] = a[3] = 0;
|
||||
}
|
||||
else if (plus_y == 0)
|
||||
{
|
||||
a[0] = src[0][alpha];
|
||||
a[1] = src[1][alpha];
|
||||
a[2] = a[3] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
a[0] = src[0][alpha];
|
||||
a[1] = src[1][alpha];
|
||||
a[2] = src[2][alpha];
|
||||
a[3] = src[3][alpha];
|
||||
}
|
||||
for (b = 0; b < alpha; b++)
|
||||
{
|
||||
newval =
|
||||
a_recip *
|
||||
cubic (dy,
|
||||
cubic (dx, src_a[0][b], src_a[1][b], src_a[2][b], src_a[3][b]),
|
||||
cubic (dx, src_a[4][b], src_a[5][b], src_a[6][b], src_a[7][b]),
|
||||
cubic (dx, src_a[8][b], src_a[9][b], src_a[10][b], src_a[11][b]),
|
||||
cubic (dx, src_a[12][b], src_a[13][b], src_a[14][b], src_a[15][b]));
|
||||
if ((newval & 0x100) == 0)
|
||||
*d++ = newval;
|
||||
else if (newval < 0)
|
||||
*d++ = 0;
|
||||
else
|
||||
*d++ = 255;
|
||||
}
|
||||
|
||||
/* The alpha channel */
|
||||
a_val = BILINEAR (a[0], a[1], a[2], a[3], dx, dy);
|
||||
*d++ = a_val;
|
||||
|
||||
if (a_val != 0)
|
||||
a_recip = 255.0 / a_val;
|
||||
else
|
||||
a_recip = 0.0;
|
||||
for (b = 0; b < 16; b++)
|
||||
tile_release (tile[b], FALSE);
|
||||
}
|
||||
else /* not in source range */
|
||||
{
|
||||
/* increment the destination pointers */
|
||||
for (b = 0; b < bytes; b++)
|
||||
*d++ = bg_col[b];
|
||||
}
|
||||
|
||||
/* premultiply the alpha */
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
a_mult = a[i] * (1.0 / 255.0);
|
||||
for (b = 0; b < alpha; b++)
|
||||
src_a[i][b] = src[i][b] * a_mult;
|
||||
}
|
||||
}
|
||||
|
||||
for (b = 0; b < alpha; b++)
|
||||
*d++ = a_recip * BILINEAR (src_a[0][b], src_a[1][b], src_a[2][b], src_a[3][b], dx, dy);
|
||||
else /* linear */
|
||||
{
|
||||
|
||||
*d++ = a_val;
|
||||
/* expand source area to cover interpolation region */
|
||||
/* (which runs from itx to itx + 1, same in y) */
|
||||
if ((itx + 1) >= x1 && itx < x2 &&
|
||||
(ity + 1) >= y1 && ity < y2 )
|
||||
{
|
||||
/* to hold clipping info */
|
||||
int use_x[2], use_y[2];
|
||||
/* to hold index */
|
||||
int index_x[2], index_y[2];
|
||||
|
||||
for (b = 0; b < 4; b++)
|
||||
tile_release (tile[b], FALSE);
|
||||
}
|
||||
}
|
||||
else /* no interpolation */
|
||||
{
|
||||
REF_TILE (0, sx, sy);
|
||||
/* get the fractional error */
|
||||
double dx, dy;
|
||||
dx = ttx - itx;
|
||||
dy = tty - ity;
|
||||
|
||||
for (b = 0; b < bytes; b++)
|
||||
*d++ = src[0][b];
|
||||
/* setup indices and clip flags */
|
||||
/* now correctly handles very small images (why?) */
|
||||
|
||||
tile_release (tile[0], FALSE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* increment the destination pointers */
|
||||
for (b = 0; b < bytes; b++)
|
||||
*d++ = bg_col[b];
|
||||
}
|
||||
/* increment the transformed coordinates */
|
||||
tx += xinc;
|
||||
ty += yinc;
|
||||
tw += winc;
|
||||
}
|
||||
/* x, y coordinates into source tiles */
|
||||
sx = itx - x1;
|
||||
sy = ity - y1;
|
||||
|
||||
use_x[0] = (itx >= x1);
|
||||
index_x[0] = use_x[0] ? sx : 0;
|
||||
|
||||
use_x[1] = ((itx + 1) < x2);
|
||||
index_x[1] = use_x[1] ? sx + 1 : x2 - 1 - x1;
|
||||
|
||||
use_y[0] = (ity >= y1);
|
||||
index_y[0] = use_y[0] ? sy : 0;
|
||||
|
||||
use_y[1] = ((ity + 1) < y2);
|
||||
index_y[1] = use_y[1] ? sy + 1 : y2 - 1 - y1;
|
||||
|
||||
REF_TILE (0, index_x[0], index_y[0]);
|
||||
REF_TILE (1, index_x[1], index_y[0]);
|
||||
REF_TILE (2, index_x[0], index_y[1]);
|
||||
REF_TILE (3, index_x[1], index_y[1]);
|
||||
|
||||
/* Need special treatment for the alpha channel */
|
||||
a[0] = (use_x[0] && use_y[0]) ? src[0][alpha] : 0;
|
||||
a[1] = (use_x[1] && use_y[0]) ? src[1][alpha] : 0;
|
||||
a[2] = (use_x[0] && use_y[1]) ? src[2][alpha] : 0;
|
||||
a[3] = (use_x[1] && use_y[1]) ? src[3][alpha] : 0;
|
||||
|
||||
/* The alpha channel */
|
||||
a_val = BILINEAR (a[0], a[1], a[2], a[3], dx, dy);
|
||||
|
||||
if (a_val != 0)
|
||||
a_recip = 255.0 / a_val;
|
||||
else
|
||||
a_recip = 0.0;
|
||||
|
||||
/* premultiply the alpha */
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
a_mult = a[i] * (1.0 / 255.0);
|
||||
for (b = 0; b < alpha; b++)
|
||||
src_a[i][b] = src[i][b] * a_mult;
|
||||
}
|
||||
|
||||
for (b = 0; b < alpha; b++)
|
||||
*d++ = a_recip * BILINEAR (src_a[0][b], src_a[1][b], src_a[2][b], src_a[3][b], dx, dy);
|
||||
|
||||
*d++ = a_val;
|
||||
|
||||
for (b = 0; b < 4; b++)
|
||||
tile_release (tile[b], FALSE);
|
||||
}
|
||||
else /* not in source range */
|
||||
{
|
||||
/* increment the destination pointers */
|
||||
for (b = 0; b < bytes; b++)
|
||||
*d++ = bg_col[b];
|
||||
}
|
||||
}
|
||||
}
|
||||
else /* no interpolation */
|
||||
{
|
||||
itx = rint(ttx);
|
||||
ity = rint(tty);
|
||||
|
||||
if (itx >= x1 && itx < x2 &&
|
||||
ity >= y1 && ity < y2 )
|
||||
{
|
||||
/* x, y coordinates into source tiles */
|
||||
sx = itx - x1;
|
||||
sy = ity - y1;
|
||||
|
||||
REF_TILE (0, sx, sy);
|
||||
|
||||
for (b = 0; b < bytes; b++)
|
||||
*d++ = src[0][b];
|
||||
|
||||
tile_release (tile[0], FALSE);
|
||||
}
|
||||
else /* not in source range */
|
||||
{
|
||||
/* increment the destination pointers */
|
||||
for (b = 0; b < bytes; b++)
|
||||
*d++ = bg_col[b];
|
||||
}
|
||||
}
|
||||
/* increment the transformed coordinates */
|
||||
tx += xinc;
|
||||
ty += yinc;
|
||||
tw += winc;
|
||||
}
|
||||
|
||||
/* set the pixel region row */
|
||||
pixel_region_set_row (&destPR, 0, (y - ty1), width, dest);
|
||||
|
@ -1355,7 +1452,6 @@ transform_core_do (GImage *gimage,
|
|||
return tiles;
|
||||
}
|
||||
|
||||
|
||||
TileManager *
|
||||
transform_core_cut (GImage *gimage,
|
||||
GimpDrawable *drawable,
|
||||
|
@ -1464,10 +1560,21 @@ cubic (double dx,
|
|||
{
|
||||
double result;
|
||||
|
||||
#if 0
|
||||
/* Equivalent to Gimp 1.1.1 and earlier - some ringing */
|
||||
result = ((( ( - jm1 + j - jp1 + jp2 ) * dx +
|
||||
( jm1 + jm1 - j - j + jp1 - jp2 ) ) * dx +
|
||||
( - jm1 + jp1 ) ) * dx + j );
|
||||
|
||||
/* Recommended by Mitchell and Netravali - too blurred? */
|
||||
result = ((( ( - 7 * jm1 + 21 * j - 21 * jp1 + 7 * jp2 ) * dx +
|
||||
( 15 * jm1 - 36 * j + 27 * jp1 - 6 * jp2 ) ) * dx +
|
||||
( - 9 * jm1 + 9 * jp1 ) ) * dx + (jm1 + 16 * j + jp1) ) / 18.0;
|
||||
#else
|
||||
/* Catmull-Rom - not bad */
|
||||
result = ((( ( - jm1 + 3 * j - 3 * jp1 + jp2 ) * dx +
|
||||
( 2 * jm1 - 5 * j + 4 * jp1 - jp2 ) ) * dx +
|
||||
( - jm1 + jp1 ) ) * dx + (j + j) ) / 2.0;
|
||||
#endif
|
||||
if (result < 0.0)
|
||||
result = 0.0;
|
||||
if (result > 255.0)
|
||||
|
|
|
@ -48,6 +48,10 @@
|
|||
#define M_PI 3.14159265358979323846
|
||||
#endif /* M_PI */
|
||||
|
||||
#define BILINEAR(jk,j1k,jk1,j1k1,dx,dy) \
|
||||
((1-dy) * (jk + dx * (j1k - jk)) + \
|
||||
dy * (jk1 + dx * (j1k1 - jk1)))
|
||||
|
||||
/* variables */
|
||||
static TranInfo old_trans_info;
|
||||
InfoDialog * transform_info = NULL;
|
||||
|
@ -65,11 +69,6 @@ static void transform_core_grid_recalc (TransformCore *);
|
|||
void paths_draw_current (GDisplay *, DrawCore *,
|
||||
GimpMatrix);
|
||||
|
||||
|
||||
#define BILINEAR(jk,j1k,jk1,j1k1,dx,dy) \
|
||||
((1-dy) * ((1-dx)*jk + dx*j1k) + \
|
||||
dy * ((1-dx)*jk1 + dx*j1k1))
|
||||
|
||||
#define REF_TILE(i,x,y) \
|
||||
tile[i] = tile_manager_get_tile (float_tiles, x, y, TRUE, FALSE); \
|
||||
src[i] = tile_data_pointer (tile[i], (x) % TILE_WIDTH, (y) % TILE_HEIGHT);
|
||||
|
@ -989,12 +988,12 @@ transform_core_recalc (Tool *tool,
|
|||
/* Actually carry out a transformation */
|
||||
TileManager *
|
||||
transform_core_do (GImage *gimage,
|
||||
GimpDrawable *drawable,
|
||||
TileManager *float_tiles,
|
||||
int interpolation,
|
||||
GimpMatrix matrix,
|
||||
progress_func_t progress_callback,
|
||||
gpointer progress_data)
|
||||
GimpDrawable *drawable,
|
||||
TileManager *float_tiles,
|
||||
int interpolation,
|
||||
GimpMatrix matrix,
|
||||
progress_func_t progress_callback,
|
||||
gpointer progress_data)
|
||||
{
|
||||
PixelRegion destPR;
|
||||
TileManager *tiles;
|
||||
|
@ -1007,14 +1006,10 @@ transform_core_do (GImage *gimage,
|
|||
int bytes, b;
|
||||
int x, y;
|
||||
int sx, sy;
|
||||
int plus_x, plus_y;
|
||||
int plus2_x, plus2_y;
|
||||
int minus_x, minus_y;
|
||||
int x1, y1, x2, y2;
|
||||
double xinc, yinc, winc;
|
||||
double tx, ty, tw;
|
||||
double ttx = 0.0, tty = 0.0;
|
||||
double dx = 0.0, dy = 0.0;
|
||||
unsigned char * dest, * d;
|
||||
unsigned char * src[16];
|
||||
double src_a[16][MAX_CHANNELS];
|
||||
|
@ -1026,12 +1021,13 @@ transform_core_do (GImage *gimage,
|
|||
int newval;
|
||||
|
||||
alpha = 0;
|
||||
|
||||
|
||||
/* turn interpolation off for simple transformations (e.g. rot90) */
|
||||
if (gimp_matrix_is_simple (matrix))
|
||||
interpolation = FALSE;
|
||||
|
||||
/* Get the background color */
|
||||
/* Check - background colour only works for non-interpolated transforms? */
|
||||
gimage_get_background (gimage, drawable, bg_col);
|
||||
|
||||
switch (drawable_type (drawable))
|
||||
|
@ -1055,7 +1051,7 @@ transform_core_do (GImage *gimage,
|
|||
if (transform_tool_direction () == TRANSFORM_CORRECTIVE)
|
||||
{
|
||||
/* keep the original matrix here, so we dont need to recalculate
|
||||
the inverse later */
|
||||
the inverse later */
|
||||
gimp_matrix_duplicate (matrix, m);
|
||||
gimp_matrix_invert (matrix, im);
|
||||
matrix = im;
|
||||
|
@ -1066,7 +1062,7 @@ transform_core_do (GImage *gimage,
|
|||
gimp_matrix_invert (matrix, m);
|
||||
}
|
||||
|
||||
paths_transform_current_path (gimage, matrix, FALSE);
|
||||
paths_transform_current_path(gimage,matrix,FALSE);
|
||||
|
||||
x1 = float_tiles->x;
|
||||
y1 = float_tiles->y;
|
||||
|
@ -1123,229 +1119,330 @@ transform_core_do (GImage *gimage,
|
|||
for (y = ty1; y < ty2; y++)
|
||||
{
|
||||
if (progress_callback && !(y & 0xf))
|
||||
(*progress_callback)(ty1, ty2, y, progress_data);
|
||||
(*progress_callback)(ty1, ty2, y, progress_data);
|
||||
|
||||
/* When we calculate the inverse transformation, we should transform
|
||||
* the center of each destination pixel...
|
||||
*/
|
||||
tx = xinc * (tx1 + 0.5) + m[0][1] * (y + 0.5) + m[0][2];
|
||||
ty = yinc * (tx1 + 0.5) + m[1][1] * (y + 0.5) + m[1][2];
|
||||
tw = winc * (tx1 + 0.5) + m[2][1] * (y + 0.5) + m[2][2];
|
||||
|
||||
/* Actually, no. Relabel them in your head, if you must */
|
||||
|
||||
tx = xinc * tx1 + m[0][1] * y + m[0][2];
|
||||
ty = yinc * tx1 + m[1][1] * y + m[1][2];
|
||||
tw = winc * tx1 + m[2][1] * y + m[2][2];
|
||||
d = dest;
|
||||
|
||||
for (x = tx1; x < tx2; x++)
|
||||
{
|
||||
/* normalize homogeneous coords */
|
||||
if (tw == 0.0)
|
||||
g_message (_("homogeneous coordinate = 0...\n"));
|
||||
else if (tw != 1.0)
|
||||
{
|
||||
ttx = tx / tw;
|
||||
tty = ty / tw;
|
||||
}
|
||||
else
|
||||
{
|
||||
ttx = tx;
|
||||
tty = ty;
|
||||
}
|
||||
{
|
||||
/* normalize homogeneous coords */
|
||||
if (tw == 0.0)
|
||||
g_message (_("homogeneous coordinate = 0...\n"));
|
||||
else if (tw != 1.0)
|
||||
{
|
||||
ttx = tx / tw;
|
||||
tty = ty / tw;
|
||||
}
|
||||
else
|
||||
{
|
||||
ttx = tx;
|
||||
tty = ty;
|
||||
}
|
||||
|
||||
/* tx & ty are the coordinates of the point in the original
|
||||
* selection's floating buffer. Make sure they're within bounds
|
||||
*/
|
||||
if (ttx < 0)
|
||||
itx = (int) (ttx - 0.999999);
|
||||
else
|
||||
itx = (int) ttx;
|
||||
/* Set the destination pixels */
|
||||
|
||||
if (tty < 0)
|
||||
ity = (int) (tty - 0.999999);
|
||||
else
|
||||
ity = (int) tty;
|
||||
if (interpolation)
|
||||
{
|
||||
/* ttx & tty are the coordinates of the point in the original
|
||||
* selection's floating buffer. Make sure they're within bounds
|
||||
*/
|
||||
itx = floor(ttx);
|
||||
ity = floor(tty);
|
||||
|
||||
/* if interpolation is on, get the fractional error */
|
||||
if (interpolation)
|
||||
{
|
||||
dx = ttx - itx;
|
||||
dy = tty - ity;
|
||||
}
|
||||
if (cubic_interpolation)
|
||||
{
|
||||
|
||||
if (itx >= x1 && itx < x2 && ity >= y1 && ity < y2)
|
||||
{
|
||||
/* x, y coordinates into source tiles */
|
||||
sx = itx - x1;
|
||||
sy = ity - y1;
|
||||
/* expand source area to cover interpolation region */
|
||||
/* (which runs from itx - 1 to itx + 2, same in y) */
|
||||
if ((itx + 2) >= x1 && (itx - 1) < x2 &&
|
||||
(ity + 2) >= y1 && (ity - 1) < y2 )
|
||||
{
|
||||
/* to hold clipping info */
|
||||
int use_x[4], use_y[4];
|
||||
/* to hold index */
|
||||
int index_x[4], index_y[4];
|
||||
int xy_i;
|
||||
|
||||
/* Set the destination pixels */
|
||||
if (interpolation)
|
||||
{
|
||||
plus_x = (itx < (x2 - 1)) ? 1 : 0;
|
||||
plus_y = (ity < (y2 - 1)) ? 1 : 0;
|
||||
/* get the fractional error */
|
||||
double dx, dy;
|
||||
dx = ttx - itx;
|
||||
dy = tty - ity;
|
||||
|
||||
if (cubic_interpolation)
|
||||
{
|
||||
minus_x = (itx > x1) ? -1 : 0;
|
||||
plus2_x = ((itx + 1) < (x2 - 1)) ? 2 : plus_x;
|
||||
/* setup indices and clip flags */
|
||||
/* now correctly handles very small images (why?) */
|
||||
|
||||
minus_y = (ity > y1) ? -1 : 0;
|
||||
plus2_y = ((ity + 1) < (y2 - 1)) ? 2 : plus_y;
|
||||
for (xy_i = 0; xy_i < 4; ++xy_i)
|
||||
{
|
||||
use_x[xy_i] = 1;
|
||||
use_y[xy_i] = 1;
|
||||
index_x[xy_i] = (itx - 1) - x1 + xy_i;
|
||||
index_y[xy_i] = (ity - 1) - y1 + xy_i;
|
||||
}
|
||||
|
||||
REF_TILE (0, sx + minus_x, sy + minus_y);
|
||||
REF_TILE (1, sx, sy + minus_y);
|
||||
REF_TILE (2, sx + plus_x, sy + minus_y);
|
||||
REF_TILE (3, sx + plus2_x, sy + minus_y);
|
||||
REF_TILE (4, sx + minus_x, sy);
|
||||
REF_TILE (5, sx, sy);
|
||||
REF_TILE (6, sx + plus_x, sy);
|
||||
REF_TILE (7, sx + plus2_x, sy);
|
||||
REF_TILE (8, sx + minus_x, sy + plus_y);
|
||||
REF_TILE (9, sx, sy + plus_y);
|
||||
REF_TILE (10, sx + plus_x, sy + plus_y);
|
||||
REF_TILE (11, sx + plus2_x, sy + plus_y);
|
||||
REF_TILE (12, sx + minus_x, sy + plus2_y);
|
||||
REF_TILE (13, sx, sy + plus2_y);
|
||||
REF_TILE (14, sx + plus_x, sy + plus2_y);
|
||||
REF_TILE (15, sx + plus2_x, sy + plus2_y);
|
||||
/* ugly, ugly code */
|
||||
|
||||
a[0] = (minus_y * minus_x) ? src[0][alpha] : 0;
|
||||
a[1] = (minus_y) ? src[1][alpha] : 0;
|
||||
a[2] = (minus_y * plus_x) ? src[2][alpha] : 0;
|
||||
a[3] = (minus_y * plus2_x) ? src[3][alpha] : 0;
|
||||
/* clip x to left hand edge */
|
||||
if ((itx - 1) < x1) {
|
||||
use_x[0] = 0;
|
||||
index_x[0] = 0;
|
||||
if (itx < x1) {
|
||||
use_x[1] = 0;
|
||||
index_x[1] = 0;
|
||||
if ((itx + 1) < x1) {
|
||||
use_x[2] = 0;
|
||||
index_x[2] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* clip x to right hand edge */
|
||||
if ((itx + 2) >= x2) {
|
||||
int xlimit = x2 - 1 - x1;
|
||||
use_x[3] = 0;
|
||||
index_x[3] = xlimit;
|
||||
if ((itx + 1) >= x2) {
|
||||
use_x[2] = 0;
|
||||
index_x[2] = xlimit;
|
||||
if (itx >= x2) {
|
||||
use_x[1] = 0;
|
||||
index_x[1] = xlimit;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* clip y to top edge */
|
||||
if ((ity - 1) < y1) {
|
||||
use_y[0] = 0;
|
||||
index_y[0] = 0;
|
||||
if (ity < y1) {
|
||||
use_y[1] = 0;
|
||||
index_y[1] = 0;
|
||||
if ((ity + 1) < y1) {
|
||||
use_y[2] = 0;
|
||||
index_y[2] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* clip y to bottom edge */
|
||||
if ((ity + 2) >= y2) {
|
||||
int ylimit = y2 - 1 - y1;
|
||||
use_y[3] = 0;
|
||||
index_y[3] = ylimit;
|
||||
if ((ity + 1) >= y2) {
|
||||
use_y[2] = 0;
|
||||
index_y[2] = ylimit;
|
||||
if (ity >= y2) {
|
||||
use_y[1] = 0;
|
||||
index_y[1] = ylimit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
a[4] = (minus_x) ? src[4][alpha] : 0;
|
||||
a[5] = src[5][alpha];
|
||||
a[6] = (plus_x) ? src[6][alpha] : 0;
|
||||
a[7] = (plus2_x) ? src[7][alpha] : 0;
|
||||
|
||||
a[8] = (plus_y * minus_x) ? src[8][alpha] : 0;
|
||||
a[9] = (plus_y) ? src[9][alpha] : 0;
|
||||
a[10] = (plus_y * plus_x) ? src[10][alpha] : 0;
|
||||
a[11] = (plus_y * plus2_x) ? src[11][alpha] : 0;
|
||||
REF_TILE (0, index_x[0], index_y[0]);
|
||||
REF_TILE (1, index_x[1], index_y[0]);
|
||||
REF_TILE (2, index_x[2], index_y[0]);
|
||||
REF_TILE (3, index_x[3], index_y[0]);
|
||||
REF_TILE (4, index_x[0], index_y[1]);
|
||||
REF_TILE (5, index_x[1], index_y[1]);
|
||||
REF_TILE (6, index_x[2], index_y[1]);
|
||||
REF_TILE (7, index_x[3], index_y[1]);
|
||||
REF_TILE (8, index_x[0], index_y[2]);
|
||||
REF_TILE (9, index_x[1], index_y[2]);
|
||||
REF_TILE (10, index_x[2], index_y[2]);
|
||||
REF_TILE (11, index_x[3], index_y[2]);
|
||||
REF_TILE (12, index_x[0], index_y[3]);
|
||||
REF_TILE (13, index_x[1], index_y[3]);
|
||||
REF_TILE (14, index_x[2], index_y[3]);
|
||||
REF_TILE (15, index_x[3], index_y[3]);
|
||||
|
||||
a[12] = (plus2_y * minus_x) ? src[12][alpha] : 0;
|
||||
a[13] = (plus2_y) ? src[13][alpha] : 0;
|
||||
a[14] = (plus2_y * plus_x) ? src[14][alpha] : 0;
|
||||
a[15] = (plus2_y * plus2_x) ? src[15][alpha] : 0;
|
||||
a[0] = (use_x[0] && use_y[0]) ? src[0][alpha] : 0;
|
||||
a[1] = (use_x[1] && use_y[0]) ? src[1][alpha] : 0;
|
||||
a[2] = (use_x[2] && use_y[0]) ? src[2][alpha] : 0;
|
||||
a[3] = (use_x[3] && use_y[0]) ? src[3][alpha] : 0;
|
||||
|
||||
a_val = cubic (dy,
|
||||
cubic (dx, a[0], a[1], a[2], a[3]),
|
||||
cubic (dx, a[4], a[5], a[6], a[7]),
|
||||
cubic (dx, a[8], a[9], a[10], a[11]),
|
||||
cubic (dx, a[12], a[13], a[14], a[15]));
|
||||
a[4] = (use_x[0] && use_y[1]) ? src[4][alpha] : 0;
|
||||
a[5] = (use_x[1] && use_y[1]) ? src[5][alpha] : 0;
|
||||
a[6] = (use_x[2] && use_y[1]) ? src[6][alpha] : 0;
|
||||
a[7] = (use_x[3] && use_y[1]) ? src[7][alpha] : 0;
|
||||
|
||||
if (a_val != 0)
|
||||
a_recip = 255.0 / a_val;
|
||||
else
|
||||
a_recip = 0.0;
|
||||
a[8] = (use_x[0] && use_y[2]) ? src[8][alpha] : 0;
|
||||
a[9] = (use_x[1] && use_y[2]) ? src[9][alpha] : 0;
|
||||
a[10] = (use_x[2] && use_y[2]) ? src[10][alpha] : 0;
|
||||
a[11] = (use_x[3] && use_y[2]) ? src[11][alpha] : 0;
|
||||
|
||||
/* premultiply the alpha */
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
a_mult = a[i] * (1.0 / 255.0);
|
||||
for (b = 0; b < alpha; b++)
|
||||
src_a[i][b] = src[i][b] * a_mult;
|
||||
}
|
||||
a[12] = (use_x[0] && use_y[3]) ? src[12][alpha] : 0;
|
||||
a[13] = (use_x[1] && use_y[3]) ? src[13][alpha] : 0;
|
||||
a[14] = (use_x[2] && use_y[3]) ? src[14][alpha] : 0;
|
||||
a[15] = (use_x[3] && use_y[3]) ? src[15][alpha] : 0;
|
||||
|
||||
for (b = 0; b < alpha; b++)
|
||||
{
|
||||
newval =
|
||||
a_recip *
|
||||
cubic (dy,
|
||||
cubic (dx, src_a[0][b], src_a[1][b], src_a[2][b], src_a[3][b]),
|
||||
cubic (dx, src_a[4][b], src_a[5][b], src_a[6][b], src_a[7][b]),
|
||||
cubic (dx, src_a[8][b], src_a[9][b], src_a[10][b], src_a[11][b]),
|
||||
cubic (dx, src_a[12][b], src_a[13][b], src_a[14][b], src_a[15][b]));
|
||||
if ((newval & 0x100) == 0)
|
||||
*d++ = newval;
|
||||
else if (newval < 0)
|
||||
*d++ = 0;
|
||||
else
|
||||
*d++ = 255;
|
||||
}
|
||||
a_val = cubic (dy,
|
||||
cubic (dx, a[0], a[1], a[2], a[3]),
|
||||
cubic (dx, a[4], a[5], a[6], a[7]),
|
||||
cubic (dx, a[8], a[9], a[10], a[11]),
|
||||
cubic (dx, a[12], a[13], a[14], a[15]));
|
||||
|
||||
*d++ = a_val;
|
||||
if (a_val != 0)
|
||||
a_recip = 255.0 / a_val;
|
||||
else
|
||||
a_recip = 0.0;
|
||||
|
||||
for (b = 0; b < 16; b++)
|
||||
tile_release (tile[b], FALSE);
|
||||
}
|
||||
else /* linear */
|
||||
{
|
||||
REF_TILE (0, sx, sy);
|
||||
REF_TILE (1, sx + plus_x, sy);
|
||||
REF_TILE (2, sx, sy + plus_y);
|
||||
REF_TILE (3, sx + plus_x, sy + plus_y);
|
||||
/* premultiply the alpha */
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
a_mult = a[i] * (1.0 / 255.0);
|
||||
for (b = 0; b < alpha; b++)
|
||||
src_a[i][b] = src[i][b] * a_mult;
|
||||
}
|
||||
|
||||
/* Need special treatment for the alpha channel */
|
||||
if (plus_x == 0 && plus_y == 0)
|
||||
{
|
||||
a[0] = src[0][alpha];
|
||||
a[1] = a[2] = a[3] = 0;
|
||||
}
|
||||
else if (plus_x == 0)
|
||||
{
|
||||
a[0] = src[0][alpha];
|
||||
a[2] = src[2][alpha];
|
||||
a[1] = a[3] = 0;
|
||||
}
|
||||
else if (plus_y == 0)
|
||||
{
|
||||
a[0] = src[0][alpha];
|
||||
a[1] = src[1][alpha];
|
||||
a[2] = a[3] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
a[0] = src[0][alpha];
|
||||
a[1] = src[1][alpha];
|
||||
a[2] = src[2][alpha];
|
||||
a[3] = src[3][alpha];
|
||||
}
|
||||
for (b = 0; b < alpha; b++)
|
||||
{
|
||||
newval =
|
||||
a_recip *
|
||||
cubic (dy,
|
||||
cubic (dx, src_a[0][b], src_a[1][b], src_a[2][b], src_a[3][b]),
|
||||
cubic (dx, src_a[4][b], src_a[5][b], src_a[6][b], src_a[7][b]),
|
||||
cubic (dx, src_a[8][b], src_a[9][b], src_a[10][b], src_a[11][b]),
|
||||
cubic (dx, src_a[12][b], src_a[13][b], src_a[14][b], src_a[15][b]));
|
||||
if ((newval & 0x100) == 0)
|
||||
*d++ = newval;
|
||||
else if (newval < 0)
|
||||
*d++ = 0;
|
||||
else
|
||||
*d++ = 255;
|
||||
}
|
||||
|
||||
/* The alpha channel */
|
||||
a_val = BILINEAR (a[0], a[1], a[2], a[3], dx, dy);
|
||||
*d++ = a_val;
|
||||
|
||||
if (a_val != 0)
|
||||
a_recip = 255.0 / a_val;
|
||||
else
|
||||
a_recip = 0.0;
|
||||
for (b = 0; b < 16; b++)
|
||||
tile_release (tile[b], FALSE);
|
||||
}
|
||||
else /* not in source range */
|
||||
{
|
||||
/* increment the destination pointers */
|
||||
for (b = 0; b < bytes; b++)
|
||||
*d++ = bg_col[b];
|
||||
}
|
||||
|
||||
/* premultiply the alpha */
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
a_mult = a[i] * (1.0 / 255.0);
|
||||
for (b = 0; b < alpha; b++)
|
||||
src_a[i][b] = src[i][b] * a_mult;
|
||||
}
|
||||
}
|
||||
|
||||
for (b = 0; b < alpha; b++)
|
||||
*d++ = a_recip * BILINEAR (src_a[0][b], src_a[1][b], src_a[2][b], src_a[3][b], dx, dy);
|
||||
else /* linear */
|
||||
{
|
||||
|
||||
*d++ = a_val;
|
||||
/* expand source area to cover interpolation region */
|
||||
/* (which runs from itx to itx + 1, same in y) */
|
||||
if ((itx + 1) >= x1 && itx < x2 &&
|
||||
(ity + 1) >= y1 && ity < y2 )
|
||||
{
|
||||
/* to hold clipping info */
|
||||
int use_x[2], use_y[2];
|
||||
/* to hold index */
|
||||
int index_x[2], index_y[2];
|
||||
|
||||
for (b = 0; b < 4; b++)
|
||||
tile_release (tile[b], FALSE);
|
||||
}
|
||||
}
|
||||
else /* no interpolation */
|
||||
{
|
||||
REF_TILE (0, sx, sy);
|
||||
/* get the fractional error */
|
||||
double dx, dy;
|
||||
dx = ttx - itx;
|
||||
dy = tty - ity;
|
||||
|
||||
for (b = 0; b < bytes; b++)
|
||||
*d++ = src[0][b];
|
||||
/* setup indices and clip flags */
|
||||
/* now correctly handles very small images (why?) */
|
||||
|
||||
tile_release (tile[0], FALSE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* increment the destination pointers */
|
||||
for (b = 0; b < bytes; b++)
|
||||
*d++ = bg_col[b];
|
||||
}
|
||||
/* increment the transformed coordinates */
|
||||
tx += xinc;
|
||||
ty += yinc;
|
||||
tw += winc;
|
||||
}
|
||||
/* x, y coordinates into source tiles */
|
||||
sx = itx - x1;
|
||||
sy = ity - y1;
|
||||
|
||||
use_x[0] = (itx >= x1);
|
||||
index_x[0] = use_x[0] ? sx : 0;
|
||||
|
||||
use_x[1] = ((itx + 1) < x2);
|
||||
index_x[1] = use_x[1] ? sx + 1 : x2 - 1 - x1;
|
||||
|
||||
use_y[0] = (ity >= y1);
|
||||
index_y[0] = use_y[0] ? sy : 0;
|
||||
|
||||
use_y[1] = ((ity + 1) < y2);
|
||||
index_y[1] = use_y[1] ? sy + 1 : y2 - 1 - y1;
|
||||
|
||||
REF_TILE (0, index_x[0], index_y[0]);
|
||||
REF_TILE (1, index_x[1], index_y[0]);
|
||||
REF_TILE (2, index_x[0], index_y[1]);
|
||||
REF_TILE (3, index_x[1], index_y[1]);
|
||||
|
||||
/* Need special treatment for the alpha channel */
|
||||
a[0] = (use_x[0] && use_y[0]) ? src[0][alpha] : 0;
|
||||
a[1] = (use_x[1] && use_y[0]) ? src[1][alpha] : 0;
|
||||
a[2] = (use_x[0] && use_y[1]) ? src[2][alpha] : 0;
|
||||
a[3] = (use_x[1] && use_y[1]) ? src[3][alpha] : 0;
|
||||
|
||||
/* The alpha channel */
|
||||
a_val = BILINEAR (a[0], a[1], a[2], a[3], dx, dy);
|
||||
|
||||
if (a_val != 0)
|
||||
a_recip = 255.0 / a_val;
|
||||
else
|
||||
a_recip = 0.0;
|
||||
|
||||
/* premultiply the alpha */
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
a_mult = a[i] * (1.0 / 255.0);
|
||||
for (b = 0; b < alpha; b++)
|
||||
src_a[i][b] = src[i][b] * a_mult;
|
||||
}
|
||||
|
||||
for (b = 0; b < alpha; b++)
|
||||
*d++ = a_recip * BILINEAR (src_a[0][b], src_a[1][b], src_a[2][b], src_a[3][b], dx, dy);
|
||||
|
||||
*d++ = a_val;
|
||||
|
||||
for (b = 0; b < 4; b++)
|
||||
tile_release (tile[b], FALSE);
|
||||
}
|
||||
else /* not in source range */
|
||||
{
|
||||
/* increment the destination pointers */
|
||||
for (b = 0; b < bytes; b++)
|
||||
*d++ = bg_col[b];
|
||||
}
|
||||
}
|
||||
}
|
||||
else /* no interpolation */
|
||||
{
|
||||
itx = rint(ttx);
|
||||
ity = rint(tty);
|
||||
|
||||
if (itx >= x1 && itx < x2 &&
|
||||
ity >= y1 && ity < y2 )
|
||||
{
|
||||
/* x, y coordinates into source tiles */
|
||||
sx = itx - x1;
|
||||
sy = ity - y1;
|
||||
|
||||
REF_TILE (0, sx, sy);
|
||||
|
||||
for (b = 0; b < bytes; b++)
|
||||
*d++ = src[0][b];
|
||||
|
||||
tile_release (tile[0], FALSE);
|
||||
}
|
||||
else /* not in source range */
|
||||
{
|
||||
/* increment the destination pointers */
|
||||
for (b = 0; b < bytes; b++)
|
||||
*d++ = bg_col[b];
|
||||
}
|
||||
}
|
||||
/* increment the transformed coordinates */
|
||||
tx += xinc;
|
||||
ty += yinc;
|
||||
tw += winc;
|
||||
}
|
||||
|
||||
/* set the pixel region row */
|
||||
pixel_region_set_row (&destPR, 0, (y - ty1), width, dest);
|
||||
|
@ -1355,7 +1452,6 @@ transform_core_do (GImage *gimage,
|
|||
return tiles;
|
||||
}
|
||||
|
||||
|
||||
TileManager *
|
||||
transform_core_cut (GImage *gimage,
|
||||
GimpDrawable *drawable,
|
||||
|
@ -1464,10 +1560,21 @@ cubic (double dx,
|
|||
{
|
||||
double result;
|
||||
|
||||
#if 0
|
||||
/* Equivalent to Gimp 1.1.1 and earlier - some ringing */
|
||||
result = ((( ( - jm1 + j - jp1 + jp2 ) * dx +
|
||||
( jm1 + jm1 - j - j + jp1 - jp2 ) ) * dx +
|
||||
( - jm1 + jp1 ) ) * dx + j );
|
||||
|
||||
/* Recommended by Mitchell and Netravali - too blurred? */
|
||||
result = ((( ( - 7 * jm1 + 21 * j - 21 * jp1 + 7 * jp2 ) * dx +
|
||||
( 15 * jm1 - 36 * j + 27 * jp1 - 6 * jp2 ) ) * dx +
|
||||
( - 9 * jm1 + 9 * jp1 ) ) * dx + (jm1 + 16 * j + jp1) ) / 18.0;
|
||||
#else
|
||||
/* Catmull-Rom - not bad */
|
||||
result = ((( ( - jm1 + 3 * j - 3 * jp1 + jp2 ) * dx +
|
||||
( 2 * jm1 - 5 * j + 4 * jp1 - jp2 ) ) * dx +
|
||||
( - jm1 + jp1 ) ) * dx + (j + j) ) / 2.0;
|
||||
#endif
|
||||
if (result < 0.0)
|
||||
result = 0.0;
|
||||
if (result > 255.0)
|
||||
|
|
Loading…
Reference in New Issue