add resize (from richard miller) and rotate
This commit is contained in:
parent
6842f87125
commit
73d4cf7227
2 changed files with 300 additions and 0 deletions
152
sys/src/cmd/resize.c
Normal file
152
sys/src/cmd/resize.c
Normal file
|
@ -0,0 +1,152 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <draw.h>
|
||||
#include <memdraw.h>
|
||||
|
||||
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);
|
||||
}
|
148
sys/src/cmd/rotate.c
Normal file
148
sys/src/cmd/rotate.c
Normal file
|
@ -0,0 +1,148 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <draw.h>
|
||||
#include <memdraw.h>
|
||||
|
||||
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; y<dy; y++){
|
||||
s = byteaddr(m, addpt(m->r.min, Pt(0, y)));
|
||||
d = byteaddr(w, addpt(w->r.min, Pt(dy-y-1, 0)));
|
||||
for(x=0; x<dx; x++){
|
||||
switch(bpp){
|
||||
case 4:
|
||||
d[3] = s[3];
|
||||
case 3:
|
||||
d[2] = s[2];
|
||||
case 2:
|
||||
d[1] = s[1];
|
||||
case 1:
|
||||
d[0] = s[0];
|
||||
}
|
||||
s += bpp;
|
||||
d += line;
|
||||
}
|
||||
}
|
||||
freememimage(m);
|
||||
if(w->chan != 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; y<dy/2; y++){
|
||||
s = byteaddr(m, addpt(m->r.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);
|
||||
}
|
||||
|
Loading…
Reference in a new issue