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);
|
||||
|
@ -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];
|
||||
|
@ -1032,6 +1027,7 @@ transform_core_do (GImage *gimage,
|
|||
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))
|
||||
|
@ -1128,11 +1124,13 @@ transform_core_do (GImage *gimage,
|
|||
/* 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];
|
||||
d = dest;
|
||||
|
||||
/* 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 */
|
||||
|
@ -1149,82 +1147,140 @@ transform_core_do (GImage *gimage,
|
|||
tty = ty;
|
||||
}
|
||||
|
||||
/* tx & ty are the coordinates of the point in the original
|
||||
/* Set the destination pixels */
|
||||
|
||||
if (interpolation)
|
||||
{
|
||||
/* ttx & tty 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;
|
||||
|
||||
if (tty < 0)
|
||||
ity = (int) (tty - 0.999999);
|
||||
else
|
||||
ity = (int) tty;
|
||||
|
||||
/* if interpolation is on, get the fractional error */
|
||||
if (interpolation)
|
||||
{
|
||||
dx = ttx - itx;
|
||||
dy = tty - ity;
|
||||
}
|
||||
|
||||
if (itx >= x1 && itx < x2 && ity >= y1 && ity < y2)
|
||||
{
|
||||
/* x, y coordinates into source tiles */
|
||||
sx = itx - x1;
|
||||
sy = ity - y1;
|
||||
|
||||
/* Set the destination pixels */
|
||||
if (interpolation)
|
||||
{
|
||||
plus_x = (itx < (x2 - 1)) ? 1 : 0;
|
||||
plus_y = (ity < (y2 - 1)) ? 1 : 0;
|
||||
itx = floor(ttx);
|
||||
ity = floor(tty);
|
||||
|
||||
if (cubic_interpolation)
|
||||
{
|
||||
minus_x = (itx > x1) ? -1 : 0;
|
||||
plus2_x = ((itx + 1) < (x2 - 1)) ? 2 : plus_x;
|
||||
|
||||
minus_y = (ity > y1) ? -1 : 0;
|
||||
plus2_y = ((ity + 1) < (y2 - 1)) ? 2 : plus_y;
|
||||
/* 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;
|
||||
|
||||
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);
|
||||
/* get the fractional error */
|
||||
double dx, dy;
|
||||
dx = ttx - itx;
|
||||
dy = tty - ity;
|
||||
|
||||
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;
|
||||
/* setup indices and clip flags */
|
||||
/* now correctly handles very small images (why?) */
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
/* ugly, ugly code */
|
||||
|
||||
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;
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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[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[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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
a_val = cubic (dy,
|
||||
cubic (dx, a[0], a[1], a[2], a[3]),
|
||||
|
@ -1267,38 +1323,62 @@ transform_core_do (GImage *gimage,
|
|||
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];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/* 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];
|
||||
|
||||
/* get the fractional error */
|
||||
double dx, dy;
|
||||
dx = ttx - itx;
|
||||
dy = tty - ity;
|
||||
|
||||
/* setup indices and clip flags */
|
||||
/* now correctly handles very small images (why?) */
|
||||
|
||||
/* 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 */
|
||||
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];
|
||||
}
|
||||
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);
|
||||
|
@ -1324,9 +1404,26 @@ transform_core_do (GImage *gimage,
|
|||
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++)
|
||||
|
@ -1334,13 +1431,13 @@ transform_core_do (GImage *gimage,
|
|||
|
||||
tile_release (tile[0], FALSE);
|
||||
}
|
||||
}
|
||||
else
|
||||
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;
|
||||
|
@ -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);
|
||||
|
@ -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];
|
||||
|
@ -1032,6 +1027,7 @@ transform_core_do (GImage *gimage,
|
|||
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))
|
||||
|
@ -1128,11 +1124,13 @@ transform_core_do (GImage *gimage,
|
|||
/* 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];
|
||||
d = dest;
|
||||
|
||||
/* 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 */
|
||||
|
@ -1149,82 +1147,140 @@ transform_core_do (GImage *gimage,
|
|||
tty = ty;
|
||||
}
|
||||
|
||||
/* tx & ty are the coordinates of the point in the original
|
||||
/* Set the destination pixels */
|
||||
|
||||
if (interpolation)
|
||||
{
|
||||
/* ttx & tty 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;
|
||||
|
||||
if (tty < 0)
|
||||
ity = (int) (tty - 0.999999);
|
||||
else
|
||||
ity = (int) tty;
|
||||
|
||||
/* if interpolation is on, get the fractional error */
|
||||
if (interpolation)
|
||||
{
|
||||
dx = ttx - itx;
|
||||
dy = tty - ity;
|
||||
}
|
||||
|
||||
if (itx >= x1 && itx < x2 && ity >= y1 && ity < y2)
|
||||
{
|
||||
/* x, y coordinates into source tiles */
|
||||
sx = itx - x1;
|
||||
sy = ity - y1;
|
||||
|
||||
/* Set the destination pixels */
|
||||
if (interpolation)
|
||||
{
|
||||
plus_x = (itx < (x2 - 1)) ? 1 : 0;
|
||||
plus_y = (ity < (y2 - 1)) ? 1 : 0;
|
||||
itx = floor(ttx);
|
||||
ity = floor(tty);
|
||||
|
||||
if (cubic_interpolation)
|
||||
{
|
||||
minus_x = (itx > x1) ? -1 : 0;
|
||||
plus2_x = ((itx + 1) < (x2 - 1)) ? 2 : plus_x;
|
||||
|
||||
minus_y = (ity > y1) ? -1 : 0;
|
||||
plus2_y = ((ity + 1) < (y2 - 1)) ? 2 : plus_y;
|
||||
/* 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;
|
||||
|
||||
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);
|
||||
/* get the fractional error */
|
||||
double dx, dy;
|
||||
dx = ttx - itx;
|
||||
dy = tty - ity;
|
||||
|
||||
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;
|
||||
/* setup indices and clip flags */
|
||||
/* now correctly handles very small images (why?) */
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
/* ugly, ugly code */
|
||||
|
||||
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;
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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[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[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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
a_val = cubic (dy,
|
||||
cubic (dx, a[0], a[1], a[2], a[3]),
|
||||
|
@ -1267,38 +1323,62 @@ transform_core_do (GImage *gimage,
|
|||
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];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/* 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];
|
||||
|
||||
/* get the fractional error */
|
||||
double dx, dy;
|
||||
dx = ttx - itx;
|
||||
dy = tty - ity;
|
||||
|
||||
/* setup indices and clip flags */
|
||||
/* now correctly handles very small images (why?) */
|
||||
|
||||
/* 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 */
|
||||
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];
|
||||
}
|
||||
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);
|
||||
|
@ -1324,9 +1404,26 @@ transform_core_do (GImage *gimage,
|
|||
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++)
|
||||
|
@ -1334,13 +1431,13 @@ transform_core_do (GImage *gimage,
|
|||
|
||||
tile_release (tile[0], FALSE);
|
||||
}
|
||||
}
|
||||
else
|
||||
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;
|
||||
|
@ -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