* Many changes for TiVo support. It actually [kinda] works. :)

This commit is contained in:
Justin Maggard
2009-03-13 08:39:37 +00:00
parent 3ae378cdc9
commit 7a2e3ae67a
17 changed files with 713 additions and 543 deletions

126
utils.c
View File

@ -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)));
}
}
}