* Many changes for TiVo support. It actually [kinda] works. :)
This commit is contained in:
126
utils.c
126
utils.c
@ -25,6 +25,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <gd.h>
|
||||
|
||||
int
|
||||
ends_with(const char * haystack, const char * needle)
|
||||
@ -147,3 +148,128 @@ make_dir(char * path, mode_t mode)
|
||||
printf("make_dir: cannot create directory '%s'", path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Use our own boxfilter resizer, because gdCopyImageResampled is slow,
|
||||
* and gdCopyImageResized looks horrible when you downscale much. */
|
||||
#define N_FRAC 8
|
||||
#define MASK_FRAC ((1 << N_FRAC) - 1)
|
||||
#define ROUND2(v) (((v) + (1 << (N_FRAC - 1))) >> N_FRAC)
|
||||
#define DIV(x, y) ( ((x) << (N_FRAC - 3)) / ((y) >> 3) )
|
||||
void
|
||||
boxfilter_resize(gdImagePtr dst, gdImagePtr src,
|
||||
int dstX, int dstY, int srcX, int srcY,
|
||||
int dstW, int dstH, int srcW, int srcH)
|
||||
{
|
||||
int x, y;
|
||||
int sy1, sy2, sx1, sx2;
|
||||
|
||||
if(!dst->trueColor)
|
||||
{
|
||||
gdImageCopyResized(dst, src, dstX, dstY, srcX, srcY, dstW, dstH,
|
||||
srcW, srcH);
|
||||
return;
|
||||
}
|
||||
for(y = dstY; y < (dstY + dstH); y++)
|
||||
{
|
||||
sy1 = (((y - dstY) * srcH) << N_FRAC) / dstH;
|
||||
sy2 = (((y - dstY + 1) * srcH) << N_FRAC) / dstH;
|
||||
for(x = dstX; x < (dstX + dstW); x++)
|
||||
{
|
||||
int sx, sy;
|
||||
int spixels = 0;
|
||||
int red = 0, green = 0, blue = 0, alpha = 0;
|
||||
sx1 = (((x - dstX) * srcW) << N_FRAC) / dstW;
|
||||
sx2 = (((x - dstX + 1) * srcW) << N_FRAC) / dstW;
|
||||
sy = sy1;
|
||||
do {
|
||||
int yportion;
|
||||
if((sy >> N_FRAC) == (sy1 >> N_FRAC))
|
||||
{
|
||||
yportion = (1 << N_FRAC) - (sy & MASK_FRAC);
|
||||
if(yportion > sy2 - sy1)
|
||||
{
|
||||
yportion = sy2 - sy1;
|
||||
}
|
||||
sy = sy & ~MASK_FRAC;
|
||||
}
|
||||
else if(sy == (sy2 & ~MASK_FRAC))
|
||||
{
|
||||
yportion = sy2 & MASK_FRAC;
|
||||
}
|
||||
else
|
||||
{
|
||||
yportion = (1 << N_FRAC);
|
||||
}
|
||||
sx = sx1;
|
||||
do {
|
||||
int xportion;
|
||||
int pcontribution;
|
||||
int p;
|
||||
if((sx >> N_FRAC) == (sx1 >> N_FRAC))
|
||||
{
|
||||
xportion = (1 << N_FRAC) - (sx & MASK_FRAC);
|
||||
if(xportion > sx2 - sx1)
|
||||
{
|
||||
xportion = sx2 - sx1;
|
||||
}
|
||||
sx = sx & ~MASK_FRAC;
|
||||
}
|
||||
else if(sx == (sx2 & ~MASK_FRAC))
|
||||
{
|
||||
xportion = sx2 & MASK_FRAC;
|
||||
}
|
||||
else
|
||||
{
|
||||
xportion = (1 << N_FRAC);
|
||||
}
|
||||
|
||||
if(xportion && yportion)
|
||||
{
|
||||
pcontribution = (xportion * yportion) >> N_FRAC;
|
||||
p = gdImageGetTrueColorPixel(src, ROUND2(sx) + srcX, ROUND2(sy) + srcY);
|
||||
if(pcontribution == (1 << N_FRAC))
|
||||
{
|
||||
// optimization for down-scaler, which many pixel has pcontribution=1
|
||||
red += gdTrueColorGetRed(p) << N_FRAC;
|
||||
green += gdTrueColorGetGreen(p) << N_FRAC;
|
||||
blue += gdTrueColorGetBlue(p) << N_FRAC;
|
||||
alpha += gdTrueColorGetAlpha(p) << N_FRAC;
|
||||
spixels += (1 << N_FRAC);
|
||||
}
|
||||
else
|
||||
{
|
||||
red += gdTrueColorGetRed(p) * pcontribution;
|
||||
green += gdTrueColorGetGreen(p) * pcontribution;
|
||||
blue += gdTrueColorGetBlue(p) * pcontribution;
|
||||
alpha += gdTrueColorGetAlpha(p) * pcontribution;
|
||||
spixels += pcontribution;
|
||||
}
|
||||
}
|
||||
sx += (1 << N_FRAC);
|
||||
}
|
||||
while(sx < sx2);
|
||||
sy += (1 << N_FRAC);
|
||||
}
|
||||
while(sy < sy2);
|
||||
if(spixels != 0)
|
||||
{
|
||||
red = DIV(red, spixels);
|
||||
green = DIV(green, spixels);
|
||||
blue = DIV(blue, spixels);
|
||||
alpha = DIV(alpha, spixels);
|
||||
}
|
||||
/* Clamping to allow for rounding errors above */
|
||||
if(red > (255 << N_FRAC))
|
||||
red = (255 << N_FRAC);
|
||||
if(green > (255 << N_FRAC))
|
||||
green = (255 << N_FRAC);
|
||||
if(blue > (255 << N_FRAC))
|
||||
blue = (255 << N_FRAC);
|
||||
if(alpha > (gdAlphaMax << N_FRAC))
|
||||
alpha = (gdAlphaMax << N_FRAC);
|
||||
gdImageSetPixel(dst, x, y,
|
||||
gdTrueColorAlpha(ROUND2(red), ROUND2(green), ROUND2(blue), ROUND2(alpha)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user