diff --git a/sys/src/cmd/resize.c b/sys/src/cmd/resize.c new file mode 100644 index 000000000..a3e2c22c6 --- /dev/null +++ b/sys/src/cmd/resize.c @@ -0,0 +1,152 @@ +#include +#include +#include +#include + +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.x = (ssize.x<<12)/dsize.x; + 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; + 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; + 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; + } +} + +void +usage(void) +{ + sysfatal("Usage: %s [ -x width ] [ -y height ] [image]\n", argv0); +} + +void +main(int argc, char **argv) +{ + int fd, xsize, ysize; + Memimage *im, *nim; + ulong ochan, tchan; + char buf[12]; + + xsize = ysize = 0; + ARGBEGIN{ + case 'x': + xsize = atoi(EARGF(usage())); + break; + case 'y': + ysize = atoi(EARGF(usage())); + 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 || 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: + sysfatal("can't handle channel type %s", chantostr(buf, ochan)); + case GREY8: + case RGB24: + case RGBA32: + case ARGB32: + case XRGB32: + tchan = ochan; + break; + case CMAP8: + case RGB16: + case RGB15: + tchan = RGB24; + 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, xsize, ysize), tchan)) == nil) + sysfatal("addocmemimage: %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); +} diff --git a/sys/src/cmd/rotate.c b/sys/src/cmd/rotate.c new file mode 100644 index 000000000..5c4d4fa94 --- /dev/null +++ b/sys/src/cmd/rotate.c @@ -0,0 +1,148 @@ +#include +#include +#include +#include + +Memimage* +rot90(Memimage *m) +{ + int line, bpp, x, y, dx, dy; + ulong chan; + uchar *s, *d; + Memimage *w; + char buf[12]; + + bpp = m->depth/8; + chan = m->chan; + switch(chan){ + default: + sysfatal("can't handle channel type %s", chantostr(buf, chan)); + case RGB15: + bpp = 2; + case CMAP8: + case GREY8: + case RGB16: + case RGB24: + case RGBA32: + case ARGB32: + case XRGB32: + break; + case GREY1: + case GREY2: + case GREY4: + bpp = 1; + if((w = allocmemimage(m->r, GREY8)) == nil) + sysfatal("allocmemimage: %r"); + memimagedraw(w, w->r, m, m->r.min, nil, ZP, S); + freememimage(m); + m = w; + break; + } + + dx = Dx(m->r); + dy = Dy(m->r); + if((w = allocmemimage(Rect(m->r.min.x, m->r.min.y, dy, dx), m->chan)) == nil) + sysfatal("allocmemimage: %r"); + line = w->width*sizeof(ulong); + for(y=0; yr.min, Pt(0, y))); + d = byteaddr(w, addpt(w->r.min, Pt(dy-y-1, 0))); + for(x=0; xchan != chan){ + if((m = allocmemimage(w->r, chan)) == nil) + sysfatal("allocmemimage: %r"); + memimagedraw(m, m->r, w, w->r.min, nil, ZP, S); + freememimage(w); + w = m; + } + return w; +} + +Memimage* +rot180(Memimage *m) +{ + uchar *s, *d, *t; + int w, y, dy; + + dy = Dy(m->r); + w = m->width * sizeof(ulong); + if((t = malloc(w)) == nil) + sysfatal("malloc: %r"); + for(y=0; yr.min, Pt(0, y))); + d = byteaddr(m, addpt(m->r.min, Pt(0, dy-y-1))); + memmove(t, d, w); + memmove(d, s, w); + memmove(s, t, w); + } + free(t); + return m; +} + +Memimage* +rot270(Memimage *m) +{ + return rot90(rot180(m)); +} + +void +usage(void) +{ + fprint(2, "usage: %s -r degree [ file ]\n", argv0); + exits("usage"); +} + +void +main(int argc, char *argv[]) +{ + Memimage *m; + int fd, r; + + r = 0; + fd = 0; + ARGBEGIN { + case 'r': + r = atoi(EARGF(usage())); + break; + default: + usage(); + } ARGEND; + if(*argv){ + fd = open(*argv, OREAD); + if(fd < 0) + sysfatal("open: %r"); + } + memimageinit(); + if((m = readmemimage(fd)) == nil) + sysfatal("readmemimage: %r"); + switch(r % 360){ + case 90: + m = rot90(m); + break; + case 180: + m = rot180(m); + break; + case 270: + m = rot270(m); + break; + } + if(writememimage(1, m) < 0) + sysfatal("writememimage: %r"); + exits(0); +} +