plan9fox/sys/src/cmd/resize.c
2015-09-23 17:52:35 +02:00

191 lines
3.7 KiB
C

#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
int nflag;
static void
resample(Memimage *dst, Rectangle r, Memimage *src, Rectangle sr)
{
Point sp, dp;
Point _sp, qp;
Point ssize, dsize;
uchar *pdst0, *pdst, *psrc0, *psrc;
ulong s00, s01, s10, s11;
int tx, ty, bpp, bpl;
ssize = subpt(subpt(sr.max, sr.min), Pt(1,1));
dsize = subpt(subpt(r.max, r.min), Pt(1,1));
pdst0 = byteaddr(dst, r.min);
bpp = src->depth/8;
bpl = src->width*sizeof(int);
qp = Pt(0, 0);
if(dsize.x > 0)
qp.x = (ssize.x<<12)/dsize.x;
if(dsize.y > 0)
qp.y = (ssize.y<<12)/dsize.y;
_sp.y = sr.min.y<<12;
for(dp.y=0; dp.y<=dsize.y; dp.y++){
sp.y = _sp.y>>12;
ty = _sp.y&0xFFF;
if(nflag)
ty = ty << 1 & 0x1000;
pdst = pdst0;
sp.x = sr.min.x;
psrc0 = byteaddr(src, sp);
_sp.x = 0;
for(dp.x=0; dp.x<=dsize.x; dp.x++){
sp.x = _sp.x>>12;
tx = _sp.x&0xFFF;
if(nflag)
tx = tx << 1 & 0x1000;
psrc = psrc0 + sp.x*bpp;
s00 = (0x1000-tx)*(0x1000-ty);
s01 = tx*(0x1000-ty);
s10 = (0x1000-tx)*ty;
s11 = tx*ty;
switch(bpp){
case 4:
pdst[3] = (s11*psrc[bpl+bpp+3] +
s10*psrc[bpl+3] +
s01*psrc[bpp+3] +
s00*psrc[3]) >>24;
case 3:
pdst[2] = (s11*psrc[bpl+bpp+2] +
s10*psrc[bpl+2] +
s01*psrc[bpp+2] +
s00*psrc[2]) >>24;
pdst[1] = (s11*psrc[bpl+bpp+1] +
s10*psrc[bpl+1] +
s01*psrc[bpp+1] +
s00*psrc[1]) >>24;
case 1:
pdst[0] = (s11*psrc[bpl+bpp] +
s10*psrc[bpl] +
s01*psrc[bpp] +
s00*psrc[0]) >>24;
}
pdst += bpp;
_sp.x += qp.x;
}
pdst0 += dst->width*sizeof(int);
_sp.y += qp.y;
}
}
enum {
PERCENT = 0x80000000,
};
static int
getsize(char *s)
{
int v;
v = strtol(s, &s, 10) & ~PERCENT;
if(*s == '%')
v |= PERCENT;
return v;
}
void
usage(void)
{
sysfatal("Usage: %s [ -x width ] [ -y height ] [ file ]\n", argv0);
}
void
main(int argc, char **argv)
{
int fd, xsize, ysize;
Memimage *im, *nim;
ulong ochan, tchan;
xsize = ysize = 0;
ARGBEGIN{
case 'a':
xsize = ysize = getsize(EARGF(usage()));
break;
case 'x':
xsize = getsize(EARGF(usage()));
break;
case 'y':
ysize = getsize(EARGF(usage()));
break;
case 'n':
nflag++;
break;
default:
usage();
}ARGEND
fd = 0;
if(*argv){
fd = open(*argv, OREAD);
if(fd < 0)
sysfatal("open: %r");
}
memimageinit();
if((im = readmemimage(fd)) == nil)
sysfatal("readmemimage: %r");
if(xsize & PERCENT)
xsize = ((xsize & ~PERCENT) * Dx(im->r)) / 100;
if(ysize & PERCENT)
ysize = ((ysize & ~PERCENT) * Dy(im->r)) / 100;
if(xsize || ysize){
if(ysize == 0)
ysize = (xsize * Dy(im->r)) / Dx(im->r);
if(xsize == 0)
xsize = (ysize * Dx(im->r)) / Dy(im->r);
ochan = im->chan;
switch(ochan){
default:
for(tchan = ochan; tchan; tchan >>= 8)
if(TYPE(tchan) == CAlpha){
tchan = RGBA32;
break;
}
if(tchan == 0)
tchan = RGB24;
break;
case GREY8:
case RGB24:
case RGBA32:
case ARGB32:
case XRGB32:
tchan = ochan;
break;
case GREY1:
case GREY2:
case GREY4:
tchan = GREY8;
break;
}
if(tchan != ochan){
if((nim = allocmemimage(im->r, tchan)) == nil)
sysfatal("allocimage: %r");
memimagedraw(nim, nim->r, im, im->r.min, nil, ZP, S);
freememimage(im);
im = nim;
}
if((nim = allocmemimage(
Rect(im->r.min.x, im->r.min.y, im->r.min.x+xsize, im->r.min.y+ysize),
tchan)) == nil)
sysfatal("allocmemimage: %r");
resample(nim, nim->r, im, im->r);
freememimage(im);
im = nim;
if(tchan != ochan){
if((im = allocmemimage(nim->r, ochan)) == nil)
sysfatal("allocimage: %r");
memimagedraw(im, im->r, nim, nim->r.min, nil, ZP, S);
freememimage(nim);
}
}
if(writememimage(1, im) < 0)
sysfatal("writememimage: %r");
exits(0);
}