legacy-imlib2/scale.c

873 lines
20 KiB
C

#include "common.h"
#include "scale.h"
#define R_VAL(x) (((x) & 0x000000ff))
#define G_VAL(x) (((x) & 0x0000ff00) >> 8)
#define B_VAL(x) (((x) & 0x00ff0000) >> 16)
#define A_VAL(x) (((x) & 0xff000000) >> 24)
#define RGBA_COMPOSE(r, g, b, a) ((a) << 24) | ((b) << 16) | ((g) << 8) | (r)
#define INV_XAP (255 - xapoints[x])
#define XAP (xapoints[x])
#define INV_YAP (255 - yapoints[dyy + y])
#define YAP (yapoints[dyy + y])
DATA32 **
CalcYPoints(DATA32 *src, int sw, int sh, int dh, int b1, int b2)
{
DATA32 **p;
int i, j = 0;
int val, inc;
p = malloc(dh * sizeof(DATA32 *));
if (dh < (b1 + b2))
{
if (dh < b1)
{
b1 = dh;
b2 = 0;
}
else
b2 = dh - b1;
}
val = 0;
inc = 1 << 16;
for (i = 0; i < b1; i++)
{
p[j++] = src + ((val >> 16) * sw);
val += inc;
}
if (dh > (b1 + b2))
{
val = (b1 << 16);
inc = ((sh - b1 - b2) << 16) / (dh - b1 - b2);
for (i = 0; i < (dh - b1 - b2); i++)
{
p[j++] = src + ((val >> 16) * sw);
val += inc;
}
}
val = (sh - b2) << 16;
inc = 1 << 16;
for (i = 0; i < b2; i++)
{
p[j++] = src + ((val >> 16) * sw);
val += inc;
}
return p;
}
int *
CalcXPoints(int sw, int dw, int b1, int b2)
{
int *p, i, j = 0;
int val, inc;
p = malloc(dw * sizeof(int));
if (dw < (b1 + b2))
{
if (dw < b1)
{
b1 = dw;
b2 = 0;
}
else
b2 = dw - b1;
}
val = 0;
inc = 1 << 16;
for (i = 0; i < b1; i++)
{
p[j++] = (val >> 16);
val += inc;
}
if (dw > (b1 + b2))
{
val = (b1 << 16);
inc = ((sw - b1 - b2) << 16) / (dw - b1 - b2);
for (i = 0; i < (dw - b1 - b2); i++)
{
p[j++] = (val >> 16);
val += inc;
}
}
val = (sw - b2) << 16;
inc = 1 << 16;
for (i = 0; i < b2; i++)
{
p[j++] = (val >> 16);
val += inc;
}
return p;
}
int *
CalcApoints(int s, int d, int b1, int b2)
{
int *p, i, v, j = 0;
p = malloc(d * sizeof(int));
if (d < (b1 + b2))
{
if (d < b1)
{
b1 = d;
b2 = 0;
}
else
b2 = d - b1;
}
/* scaling up */
if (d > s)
{
int val, inc;
for (i = 0; i < b1; i++)
p[j++] = 0;
if (d > (b1 + b2))
{
int ss, dd;
ss = s - b1 - b2;
dd = d - b1 - b2;
val = 0;
inc = (ss << 16) / dd;
for (i = 0; i < dd; i++)
{
p[j++] = (val >> 8) - ((val >> 8) & 0xffffff00);
if (((val >> 16) + b1) >= (s - 1))
p[j - 1] = 0;
val += inc;
}
}
for (i = 0; i < b2; i++)
p[j++] = 0;
}
/* scaling down */
else
{
for (i = 0; i < b1; i++)
p[j++] = 1;
if (d > (b1 + b2))
{
int ss, dd;
ss = s - b1 - b2;
dd = d - b1 - b2;
for (i = 0; i < dd; i++)
{
v = (((i + 1) * ss) / dd) - ((i * ss) / dd);
if (v != 1)
{
if (((((i + 1) * ss) / dd) + b1) >= s)
v = s - (((i * ss) / dd) + b1) - 1;
p[j++] = v;
}
else
p[j++] = v;
if (p[j - 1] < 1)
p[j - 1] = 1;
}
}
for (i = 0; i < b2; i++)
p[j++] = 1;
}
return p;
}
/* scale by pixel sampling only */
void
ScaleSampleRGBA(DATA32 **ypoints, int *xpoints, DATA32 *dest,
int dxx, int dyy, int dx, int dy, int dw, int dh, int dow)
{
DATA32 *sptr, *dptr;
int x, y, end;
/* whats the last pixel ont he line so we stop there */
end = dxx + dw;
/* go through every scanline in the output buffer */
for (y = 0; y < dh; y++)
{
/* get the pointer to the start of the destination scanline */
dptr = dest + dx + ((y + dy) * dow);
/* calculate the source line we'll scan from */
sptr = ypoints[dyy + y];
/* go thru the scanline and copy across */
for (x = dxx; x < end; x++)
*dptr++ = sptr[xpoints[x]];
}
}
/* FIXME: NEED to optimise ScaleAARGBA - currently its "ok" but needs work*/
/* scale by area sampling */
void
ScaleAARGBA(DATA32 **ypoints, int *xpoints, DATA32 *dest,
int *xapoints, int *yapoints, char xup, char yup,
int dxx, int dyy, int dx, int dy, int dw, int dh, int dow, int sow)
{
DATA32 *sptr, *ssptr, *dptr;
int x, y, i, j, end;
end = dxx + dw;
/* scaling up both ways */
if ((xup) && (yup))
{
/* go through every scanline in the output buffer */
for (y = 0; y < dh; y++)
{
/* calculate the source line we'll scan from */
dptr = dest + dx + ((y + dy) * dow);
sptr = ypoints[dyy + y];
for (x = dxx; x < end; x++)
{
int r = 0, g = 0, b = 0, a = 0;
int rr = 0, gg = 0, bb = 0, aa = 0;
DATA32 pix;
if (YAP > 0)
{
if (XAP > 0)
{
ssptr = ypoints[dyy + y];
pix = ssptr[xpoints[x]];
r = R_VAL(pix) * INV_XAP;
g = G_VAL(pix) * INV_XAP;
b = B_VAL(pix) * INV_XAP;
a = A_VAL(pix) * INV_XAP;
pix = ssptr[xpoints[x] + 1];
r += R_VAL(pix) * XAP;
g += G_VAL(pix) * XAP;
b += B_VAL(pix) * XAP;
a += A_VAL(pix) * XAP;
ssptr += sow;
pix = ssptr[xpoints[x]];
rr = R_VAL(pix) * INV_XAP;
gg = G_VAL(pix) * INV_XAP;
bb = B_VAL(pix) * INV_XAP;
aa = A_VAL(pix) * INV_XAP;
pix = ssptr[xpoints[x] + 1];
rr += R_VAL(pix) * XAP;
gg += G_VAL(pix) * XAP;
bb += B_VAL(pix) * XAP;
aa += A_VAL(pix) * XAP;
r = ((rr * YAP) + (r * INV_YAP)) >> 16;
g = ((gg * YAP) + (g * INV_YAP)) >> 16;
b = ((bb * YAP) + (b * INV_YAP)) >> 16;
a = ((aa * YAP) + (a * INV_YAP)) >> 16;
pix = RGBA_COMPOSE(r, g, b, a);
*dptr++ = pix;
}
else
{
ssptr = ypoints[dyy + y];
pix = ssptr[xpoints[x]];
r = R_VAL(pix) * INV_YAP;
g = G_VAL(pix) * INV_YAP;
b = B_VAL(pix) * INV_YAP;
a = A_VAL(pix) * INV_YAP;
ssptr += sow;
pix = ssptr[xpoints[x]];
r += R_VAL(pix) * YAP;
g += G_VAL(pix) * YAP;
b += B_VAL(pix) * YAP;
a += A_VAL(pix) * YAP;
r >>= 8;
g >>= 8;
b >>= 8;
a >>= 8;
pix = RGBA_COMPOSE(r, g, b, a);
*dptr++ = pix;
}
}
else
{
if (XAP > 0)
{
ssptr = ypoints[dyy + y];
pix = ssptr[xpoints[x]];
r = R_VAL(pix) * INV_XAP;
g = G_VAL(pix) * INV_XAP;
b = B_VAL(pix) * INV_XAP;
a = A_VAL(pix) * INV_XAP;
pix = ssptr[xpoints[x] + 1];
r += R_VAL(pix) * XAP;
g += G_VAL(pix) * XAP;
b += B_VAL(pix) * XAP;
a += A_VAL(pix) * XAP;
r >>= 8;
g >>= 8;
b >>= 8;
a >>= 8;
pix = RGBA_COMPOSE(r, g, b, a);
*dptr++ = pix;
}
else
*dptr++ = sptr[xpoints[x] ];
}
}
}
}
/* if we're scaling down vertically */
else if ((xup) && (!yup))
{
/* go through every scanline in the output buffer */
for (y = 0; y < dh; y++)
{
/* calculate the source line we'll scan from */
dptr = dest + dx + ((y + dy) * dow);
sptr = ypoints[dyy + y];
for (x = dxx; x < end; x++)
{
int r = 0, g = 0, b = 0, a = 0;
int rr = 0, gg = 0, bb = 0, aa = 0;
int count;
DATA32 pix;
if (XAP > 0)
{
if (YAP > 1)
{
for (j = 0; j < YAP; j++)
{
ssptr = ypoints[dyy + y] + (j * sow);
pix = ssptr[xpoints[x]];
r += R_VAL(pix);
g += G_VAL(pix);
b += B_VAL(pix);
a += A_VAL(pix);
}
count = j;
r = r * INV_XAP / count;
g = g * INV_XAP / count;
b = b * INV_XAP / count;
a = a * INV_XAP / count;
for (j = 0; j < YAP; j++)
{
ssptr = ypoints[dyy + y] + (j * sow);
pix = ssptr[xpoints[x] + 1];
rr += R_VAL(pix);
gg += G_VAL(pix);
bb += B_VAL(pix);
aa += A_VAL(pix);
}
count = j;
r = (r + ((rr * XAP) / count)) >> 8;
g = (g + ((gg * XAP) / count)) >> 8;
b = (b + ((bb * XAP) / count)) >> 8;
a = (a + ((aa * XAP) / count)) >> 8;
pix = RGBA_COMPOSE(r, g, b, a);
*dptr++ = pix;
}
else
{
ssptr = ypoints[dyy + y];
pix = ssptr[xpoints[x]];
r = R_VAL(pix) * INV_XAP;
g = G_VAL(pix) * INV_XAP;
b = B_VAL(pix) * INV_XAP;
a = A_VAL(pix) * INV_XAP;
pix = ssptr[xpoints[x] + 1];
r += R_VAL(pix) * XAP;
g += G_VAL(pix) * XAP;
b += B_VAL(pix) * XAP;
a += A_VAL(pix) * XAP;
r >>= 8;
g >>= 8;
b >>= 8;
a >>= 8;
pix = RGBA_COMPOSE(r, g, b, a);
*dptr++ = pix;
}
}
else
{
if (YAP > 1)
{
for (j = 0; j < YAP; j++)
{
ssptr = ypoints[dyy + y] + (j *sow);
pix = ssptr[xpoints[x]];
r += R_VAL(pix);
g += G_VAL(pix);
b += B_VAL(pix);
a += A_VAL(pix);
}
count = j;
r /= count;
g /= count;
b /= count;
a /= count;
pix = RGBA_COMPOSE(r, g, b, a);
*dptr++ = pix;
}
else
*dptr++ = sptr[xpoints[x]];
}
}
}
}
/* if we're scaling down horizontally */
else if ((!xup) && (yup))
{
/* go through every scanline in the output buffer */
for (y = 0; y < dh; y++)
{
/* calculate the source line we'll scan from */
dptr = dest + dx + ((y + dy) * dow);
sptr = ypoints[dyy + y];
for (x = dxx; x < end; x++)
{
int r = 0, g = 0, b = 0, a = 0;
int rr = 0, gg = 0, bb = 0, aa = 0;
int count;
DATA32 pix;
if (YAP > 0)
{
if (XAP > 1)
{
ssptr = ypoints[dyy + y];
for (i = 0; i < XAP; i++)
{
pix = ssptr[xpoints[x] + i];
r += R_VAL(pix);
g += G_VAL(pix);
b += B_VAL(pix);
a += A_VAL(pix);
}
count = i;
r = r * INV_YAP / count;
g = g * INV_YAP / count;
b = b * INV_YAP / count;
a = a * INV_YAP / count;
ssptr = ypoints[dyy + y] + sow;
for (i = 0; i < XAP; i++)
{
pix = ssptr[xpoints[x] + i];
rr += R_VAL(pix);
gg += G_VAL(pix);
bb += B_VAL(pix);
aa += A_VAL(pix);
}
count = i;
r = (r + ((rr * YAP) / count)) >> 8;
g = (g + ((gg * YAP) / count)) >> 8;
b = (b + ((bb * YAP) / count)) >> 8;
a = (a + ((aa * YAP) / count)) >> 8;
pix = RGBA_COMPOSE(r, g, b, a);
*dptr++ = pix;
}
else
{
ssptr = ypoints[dyy + y];
pix = ssptr[xpoints[x]];
r = R_VAL(pix) * INV_YAP;
g = G_VAL(pix) * INV_YAP;
b = B_VAL(pix) * INV_YAP;
a = A_VAL(pix) * INV_YAP;
ssptr += sow;
pix = ssptr[xpoints[x]];
r += R_VAL(pix) * YAP;
g += G_VAL(pix) * YAP;
b += B_VAL(pix) * YAP;
a += A_VAL(pix) * YAP;
r >>= 8;
g >>= 8;
b >>= 8;
a >>= 8;
pix = RGBA_COMPOSE(r, g, b, a);
*dptr++ = pix;
}
}
else
{
if (XAP > 1)
{
ssptr = ypoints[dyy + y];
for (i = 0; i < XAP; i++)
{
pix = ssptr[xpoints[x] + i];
r += R_VAL(pix);
g += G_VAL(pix);
b += B_VAL(pix);
a += A_VAL(pix);
}
count = i;
r /= count;
g /= count;
b /= count;
a /= count;
pix = RGBA_COMPOSE(r, g, b, a);
*dptr++ = pix;
}
else
*dptr++ = sptr[xpoints[x]];
}
}
}
}
/* if we're scaling down horizontally & vertically */
else
{
/* go through every scanline in the output buffer */
for (y = 0; y < dh; y++)
{
/* calculate the source line we'll scan from */
dptr = dest + dx + ((y + dy) * dow);
sptr = ypoints[dyy + y];
for (x = dxx; x < end; x++)
{
int r = 0, g = 0, b = 0, a = 0;
int count;
DATA32 pix;
if ((XAP > 1) || (YAP > 1))
{
for (j = 0; j < YAP; j++)
{
ssptr = ypoints[dyy + y] + (j * sow);
for (i = 0; i < XAP; i++)
{
pix = ssptr[xpoints[x] + i];
r += R_VAL(pix);
g += G_VAL(pix);
b += B_VAL(pix);
a += A_VAL(pix);
}
}
count = (i * j);
r /= count;
g /= count;
b /= count;
a /= count;
pix = RGBA_COMPOSE(r, g, b, a);
*dptr++ = pix;
}
else
*dptr++ = sptr[xpoints[x]];
}
}
}
}
/* scale by area sampling - IGNORE the ALPHA byte*/
void
ScaleAARGB(DATA32 **ypoints, int *xpoints, DATA32 *dest,
int *xapoints, int *yapoints, char xup, char yup,
int dxx, int dyy, int dx, int dy, int dw, int dh, int dow, int sow)
{
DATA32 *sptr, *ssptr, *dptr;
int x, y, i, j, end;
end = dxx + dw;
/* scaling up both ways */
if ((xup) && (yup))
{
/* go through every scanline in the output buffer */
for (y = 0; y < dh; y++)
{
/* calculate the source line we'll scan from */
dptr = dest + dx + ((y + dy) * dow);
sptr = ypoints[dyy + y];
for (x = dxx; x < end; x++)
{
int r = 0, g = 0, b = 0;
int rr = 0, gg = 0, bb = 0;
DATA32 pix;
if (YAP > 0)
{
if (XAP > 0)
{
ssptr = ypoints[dyy + y];
pix = ssptr[xpoints[x]];
r = R_VAL(pix) * INV_XAP;
g = G_VAL(pix) * INV_XAP;
b = B_VAL(pix) * INV_XAP;
pix = ssptr[xpoints[x] + 1];
r += R_VAL(pix) * XAP;
g += G_VAL(pix) * XAP;
b += B_VAL(pix) * XAP;
ssptr += sow;
pix = ssptr[xpoints[x]];
rr = R_VAL(pix) * INV_XAP;
gg = G_VAL(pix) * INV_XAP;
bb = B_VAL(pix) * INV_XAP;
pix = ssptr[xpoints[x] + 1];
rr += R_VAL(pix) * XAP;
gg += G_VAL(pix) * XAP;
bb += B_VAL(pix) * XAP;
r = ((rr * YAP) + (r * INV_YAP)) >> 16;
g = ((gg * YAP) + (g * INV_YAP)) >> 16;
b = ((bb * YAP) + (b * INV_YAP)) >> 16;
pix = RGBA_COMPOSE(r, g, b, 0xff);
*dptr++ = pix;
}
else
{
ssptr = ypoints[dyy + y];
pix = ssptr[xpoints[x]];
r = R_VAL(pix) * INV_YAP;
g = G_VAL(pix) * INV_YAP;
b = B_VAL(pix) * INV_YAP;
ssptr += sow;
pix = ssptr[xpoints[x]];
r += R_VAL(pix) * YAP;
g += G_VAL(pix) * YAP;
b += B_VAL(pix) * YAP;
r >>= 8;
g >>= 8;
b >>= 8;
pix = RGBA_COMPOSE(r, g, b, 0xff);
*dptr++ = pix;
}
}
else
{
if (XAP > 0)
{
ssptr = ypoints[dyy + y];
pix = ssptr[xpoints[x]];
r = R_VAL(pix) * INV_XAP;
g = G_VAL(pix) * INV_XAP;
b = B_VAL(pix) * INV_XAP;
pix = ssptr[xpoints[x] + 1];
r += R_VAL(pix) * XAP;
g += G_VAL(pix) * XAP;
b += B_VAL(pix) * XAP;
r >>= 8;
g >>= 8;
b >>= 8;
pix = RGBA_COMPOSE(r, g, b, 0xff);
*dptr++ = pix;
}
else
*dptr++ = sptr[xpoints[x] ];
}
}
}
}
/* if we're scaling down vertically */
else if ((xup) && (!yup))
{
/* go through every scanline in the output buffer */
for (y = 0; y < dh; y++)
{
/* calculate the source line we'll scan from */
dptr = dest + dx + ((y + dy) * dow);
sptr = ypoints[dyy + y];
for (x = dxx; x < end; x++)
{
int r = 0, g = 0, b = 0;
int rr = 0, gg = 0, bb = 0;
int count;
DATA32 pix;
if (XAP > 0)
{
if (YAP > 1)
{
for (j = 0; j < YAP; j++)
{
ssptr = ypoints[dyy + y] + (j * sow);
pix = ssptr[xpoints[x]];
r += R_VAL(pix);
g += G_VAL(pix);
b += B_VAL(pix);
}
count = j;
r = r * INV_XAP / count;
g = g * INV_XAP / count;
b = b * INV_XAP / count;
for (j = 0; j < YAP; j++)
{
ssptr = ypoints[dyy + y] + (j * sow);
pix = ssptr[xpoints[x] + 1];
rr += R_VAL(pix);
gg += G_VAL(pix);
bb += B_VAL(pix);
}
count = j;
r = (r + ((rr * XAP) / count)) >> 8;
g = (g + ((gg * XAP) / count)) >> 8;
b = (b + ((bb * XAP) / count)) >> 8;
pix = RGBA_COMPOSE(r, g, b, 0xff);
*dptr++ = pix;
}
else
{
ssptr = ypoints[dyy + y];
pix = ssptr[xpoints[x]];
r = R_VAL(pix) * INV_XAP;
g = G_VAL(pix) * INV_XAP;
b = B_VAL(pix) * INV_XAP;
pix = ssptr[xpoints[x] + 1];
r += R_VAL(pix) * XAP;
g += G_VAL(pix) * XAP;
b += B_VAL(pix) * XAP;
r >>= 8;
g >>= 8;
b >>= 8;
pix = RGBA_COMPOSE(r, g, b, 0xff);
*dptr++ = pix;
}
}
else
{
if (YAP > 1)
{
for (j = 0; j < YAP; j++)
{
ssptr = ypoints[dyy + y] + (j *sow);
pix = ssptr[xpoints[x]];
r += R_VAL(pix);
g += G_VAL(pix);
b += B_VAL(pix);
}
count = j;
r /= count;
g /= count;
b /= count;
pix = RGBA_COMPOSE(r, g, b, 0xff);
*dptr++ = pix;
}
else
*dptr++ = sptr[xpoints[x]];
}
}
}
}
/* if we're scaling down horizontally */
else if ((!xup) && (yup))
{
/* go through every scanline in the output buffer */
for (y = 0; y < dh; y++)
{
/* calculate the source line we'll scan from */
dptr = dest + dx + ((y + dy) * dow);
sptr = ypoints[dyy + y];
for (x = dxx; x < end; x++)
{
int r = 0, g = 0, b = 0;
int rr = 0, gg = 0, bb = 0;
int count;
DATA32 pix;
if (YAP > 0)
{
if (XAP > 1)
{
ssptr = ypoints[dyy + y];
for (i = 0; i < XAP; i++)
{
pix = ssptr[xpoints[x] + i];
r += R_VAL(pix);
g += G_VAL(pix);
b += B_VAL(pix);
}
count = i;
r = r * INV_YAP / count;
g = g * INV_YAP / count;
b = b * INV_YAP / count;
ssptr = ypoints[dyy + y] + sow;
for (i = 0; i < XAP; i++)
{
pix = ssptr[xpoints[x] + i];
rr += R_VAL(pix);
gg += G_VAL(pix);
bb += B_VAL(pix);
}
count = i;
r = (r + ((rr * YAP) / count)) >> 8;
g = (g + ((gg * YAP) / count)) >> 8;
b = (b + ((bb * YAP) / count)) >> 8;
pix = RGBA_COMPOSE(r, g, b, 0xff);
*dptr++ = pix;
}
else
{
ssptr = ypoints[dyy + y];
pix = ssptr[xpoints[x]];
r = R_VAL(pix) * INV_YAP;
g = G_VAL(pix) * INV_YAP;
b = B_VAL(pix) * INV_YAP;
ssptr += sow;
pix = ssptr[xpoints[x]];
r += R_VAL(pix) * YAP;
g += G_VAL(pix) * YAP;
b += B_VAL(pix) * YAP;
r >>= 8;
g >>= 8;
b >>= 8;
pix = RGBA_COMPOSE(r, g, b, 0xff);
*dptr++ = pix;
}
}
else
{
if (XAP > 1)
{
ssptr = ypoints[dyy + y];
for (i = 0; i < XAP; i++)
{
pix = ssptr[xpoints[x] + i];
r += R_VAL(pix);
g += G_VAL(pix);
b += B_VAL(pix);
}
count = i;
r /= count;
g /= count;
b /= count;
pix = RGBA_COMPOSE(r, g, b, 0xff);
*dptr++ = pix;
}
else
*dptr++ = sptr[xpoints[x]];
}
}
}
}
/* if we're scaling down horizontally & vertically */
else
{
/* go through every scanline in the output buffer */
for (y = 0; y < dh; y++)
{
/* calculate the source line we'll scan from */
dptr = dest + dx + ((y + dy) * dow);
sptr = ypoints[dyy + y];
for (x = dxx; x < end; x++)
{
int r = 0, g = 0, b = 0;
int count;
DATA32 pix;
if ((XAP > 1) || (YAP > 1))
{
for (j = 0; j < YAP; j++)
{
ssptr = ypoints[dyy + y] + (j * sow);
for (i = 0; i < XAP; i++)
{
pix = ssptr[xpoints[x] + i];
r += R_VAL(pix);
g += G_VAL(pix);
b += B_VAL(pix);
}
}
count = (i * j);
r /= count;
g /= count;
b /= count;
pix = RGBA_COMPOSE(r, g, b, 0xff);
*dptr++ = pix;
}
else
*dptr++ = sptr[xpoints[x]];
}
}
}
}