17dd7cddfSDavid du Colombier /* 27dd7cddfSDavid du Colombier * rotate an image 180° in O(log Dx + log Dy) /dev/draw writes, 37dd7cddfSDavid du Colombier * using an extra buffer same size as the image. 47dd7cddfSDavid du Colombier * 57dd7cddfSDavid du Colombier * the basic concept is that you can invert an array by inverting 67dd7cddfSDavid du Colombier * the top half, inverting the bottom half, and then swapping them. 77dd7cddfSDavid du Colombier * the code does this slightly backwards to ensure O(log n) runtime. 87dd7cddfSDavid du Colombier * (If you do it wrong, you can get O(log² n) runtime.) 97dd7cddfSDavid du Colombier * 107dd7cddfSDavid du Colombier * This is usually overkill, but it speeds up slow remote 117dd7cddfSDavid du Colombier * connections quite a bit. 127dd7cddfSDavid du Colombier */ 137dd7cddfSDavid du Colombier 147dd7cddfSDavid du Colombier #include <u.h> 157dd7cddfSDavid du Colombier #include <libc.h> 167dd7cddfSDavid du Colombier #include <bio.h> 177dd7cddfSDavid du Colombier #include <draw.h> 187dd7cddfSDavid du Colombier #include <event.h> 197dd7cddfSDavid du Colombier #include "page.h" 207dd7cddfSDavid du Colombier 217dd7cddfSDavid du Colombier int ndraw = 0; 227dd7cddfSDavid du Colombier enum { 237dd7cddfSDavid du Colombier Xaxis = 0, 247dd7cddfSDavid du Colombier Yaxis = 1, 257dd7cddfSDavid du Colombier }; 267dd7cddfSDavid du Colombier 277dd7cddfSDavid du Colombier Image *mtmp; 287dd7cddfSDavid du Colombier 297dd7cddfSDavid du Colombier void 307dd7cddfSDavid du Colombier writefile(char *name, Image *im, int gran) 317dd7cddfSDavid du Colombier { 327dd7cddfSDavid du Colombier static int c = 100; 337dd7cddfSDavid du Colombier int fd; 347dd7cddfSDavid du Colombier char buf[200]; 357dd7cddfSDavid du Colombier 367dd7cddfSDavid du Colombier snprint(buf, sizeof buf, "%d%s%d", c++, name, gran); 377dd7cddfSDavid du Colombier fd = create(buf, OWRITE, 0666); 387dd7cddfSDavid du Colombier if(fd < 0) 397dd7cddfSDavid du Colombier return; 407dd7cddfSDavid du Colombier writeimage(fd, im, 0); 417dd7cddfSDavid du Colombier close(fd); 427dd7cddfSDavid du Colombier } 437dd7cddfSDavid du Colombier 447dd7cddfSDavid du Colombier void 457dd7cddfSDavid du Colombier moveup(Image *im, Image *tmp, int a, int b, int c, int axis) 467dd7cddfSDavid du Colombier { 477dd7cddfSDavid du Colombier Rectangle range; 487dd7cddfSDavid du Colombier Rectangle dr0, dr1; 497dd7cddfSDavid du Colombier Point p0, p1; 507dd7cddfSDavid du Colombier 517dd7cddfSDavid du Colombier if(a == b || b == c) 527dd7cddfSDavid du Colombier return; 537dd7cddfSDavid du Colombier 546b6b9ac8SDavid du Colombier drawop(tmp, tmp->r, im, nil, im->r.min, S); 557dd7cddfSDavid du Colombier 567dd7cddfSDavid du Colombier switch(axis){ 577dd7cddfSDavid du Colombier case Xaxis: 587dd7cddfSDavid du Colombier range = Rect(a, im->r.min.y, c, im->r.max.y); 597dd7cddfSDavid du Colombier dr0 = range; 607dd7cddfSDavid du Colombier dr0.max.x = dr0.min.x+(c-b); 617dd7cddfSDavid du Colombier p0 = Pt(b, im->r.min.y); 627dd7cddfSDavid du Colombier 637dd7cddfSDavid du Colombier dr1 = range; 647dd7cddfSDavid du Colombier dr1.min.x = dr1.max.x-(b-a); 657dd7cddfSDavid du Colombier p1 = Pt(a, im->r.min.y); 667dd7cddfSDavid du Colombier break; 677dd7cddfSDavid du Colombier case Yaxis: 687dd7cddfSDavid du Colombier range = Rect(im->r.min.x, a, im->r.max.x, c); 697dd7cddfSDavid du Colombier dr0 = range; 707dd7cddfSDavid du Colombier dr0.max.y = dr0.min.y+(c-b); 717dd7cddfSDavid du Colombier p0 = Pt(im->r.min.x, b); 727dd7cddfSDavid du Colombier 737dd7cddfSDavid du Colombier dr1 = range; 747dd7cddfSDavid du Colombier dr1.min.y = dr1.max.y-(b-a); 757dd7cddfSDavid du Colombier p1 = Pt(im->r.min.x, a); 767dd7cddfSDavid du Colombier break; 777dd7cddfSDavid du Colombier } 786b6b9ac8SDavid du Colombier drawop(im, dr0, tmp, nil, p0, S); 796b6b9ac8SDavid du Colombier drawop(im, dr1, tmp, nil, p1, S); 807dd7cddfSDavid du Colombier } 817dd7cddfSDavid du Colombier 827dd7cddfSDavid du Colombier void 837dd7cddfSDavid du Colombier interlace(Image *im, Image *tmp, int axis, int n, Image *mask, int gran) 847dd7cddfSDavid du Colombier { 857dd7cddfSDavid du Colombier Point p0, p1; 867dd7cddfSDavid du Colombier Rectangle r0, r1; 877dd7cddfSDavid du Colombier 887dd7cddfSDavid du Colombier r0 = im->r; 897dd7cddfSDavid du Colombier r1 = im->r; 907dd7cddfSDavid du Colombier switch(axis) { 917dd7cddfSDavid du Colombier case Xaxis: 927dd7cddfSDavid du Colombier r0.max.x = n; 937dd7cddfSDavid du Colombier r1.min.x = n; 947dd7cddfSDavid du Colombier p0 = (Point){gran, 0}; 957dd7cddfSDavid du Colombier p1 = (Point){-gran, 0}; 967dd7cddfSDavid du Colombier break; 977dd7cddfSDavid du Colombier case Yaxis: 987dd7cddfSDavid du Colombier r0.max.y = n; 997dd7cddfSDavid du Colombier r1.min.y = n; 1007dd7cddfSDavid du Colombier p0 = (Point){0, gran}; 1017dd7cddfSDavid du Colombier p1 = (Point){0, -gran}; 1027dd7cddfSDavid du Colombier break; 1037dd7cddfSDavid du Colombier } 1047dd7cddfSDavid du Colombier 1056b6b9ac8SDavid du Colombier drawop(tmp, im->r, im, display->opaque, im->r.min, S); 1066b6b9ac8SDavid du Colombier gendrawop(im, r0, tmp, p0, mask, mask->r.min, S); 1076b6b9ac8SDavid du Colombier gendrawop(im, r0, tmp, p1, mask, p1, S); 1087dd7cddfSDavid du Colombier } 1097dd7cddfSDavid du Colombier 1107dd7cddfSDavid du Colombier /* 1117dd7cddfSDavid du Colombier * Halve the grating period in the mask. 1127dd7cddfSDavid du Colombier * The grating currently looks like 1137dd7cddfSDavid du Colombier * ####____####____####____####____ 1147dd7cddfSDavid du Colombier * where #### is opacity. 1157dd7cddfSDavid du Colombier * 1167dd7cddfSDavid du Colombier * We want 1177dd7cddfSDavid du Colombier * ##__##__##__##__##__##__##__##__ 1187dd7cddfSDavid du Colombier * which is achieved by shifting the mask 1197dd7cddfSDavid du Colombier * and drawing on itself through itself. 1207dd7cddfSDavid du Colombier * Draw doesn't actually allow this, so 1217dd7cddfSDavid du Colombier * we have to copy it first. 1227dd7cddfSDavid du Colombier * 1237dd7cddfSDavid du Colombier * ####____####____####____####____ (dst) 1247dd7cddfSDavid du Colombier * + ____####____####____####____#### (src) 1257dd7cddfSDavid du Colombier * in __####____####____####____####__ (mask) 1267dd7cddfSDavid du Colombier * =========================================== 1277dd7cddfSDavid du Colombier * ##__##__##__##__##__##__##__##__ 1287dd7cddfSDavid du Colombier */ 1297dd7cddfSDavid du Colombier int 1307dd7cddfSDavid du Colombier nextmask(Image *mask, int axis, int maskdim) 1317dd7cddfSDavid du Colombier { 1327dd7cddfSDavid du Colombier Point δ; 1337dd7cddfSDavid du Colombier 1347dd7cddfSDavid du Colombier δ = axis==Xaxis ? Pt(maskdim,0) : Pt(0,maskdim); 1356b6b9ac8SDavid du Colombier drawop(mtmp, mtmp->r, mask, nil, mask->r.min, S); 1366b6b9ac8SDavid du Colombier gendrawop(mask, mask->r, mtmp, δ, mtmp, divpt(δ,-2), S); 1377dd7cddfSDavid du Colombier // writefile("mask", mask, maskdim/2); 1387dd7cddfSDavid du Colombier return maskdim/2; 1397dd7cddfSDavid du Colombier } 1407dd7cddfSDavid du Colombier 1417dd7cddfSDavid du Colombier void 1427dd7cddfSDavid du Colombier shuffle(Image *im, Image *tmp, int axis, int n, Image *mask, int gran, 1437dd7cddfSDavid du Colombier int lastnn) 1447dd7cddfSDavid du Colombier { 1457dd7cddfSDavid du Colombier int nn, left; 1467dd7cddfSDavid du Colombier 1477dd7cddfSDavid du Colombier if(gran == 0) 1487dd7cddfSDavid du Colombier return; 1497dd7cddfSDavid du Colombier left = n%(2*gran); 1507dd7cddfSDavid du Colombier nn = n - left; 1517dd7cddfSDavid du Colombier 1527dd7cddfSDavid du Colombier interlace(im, tmp, axis, nn, mask, gran); 1537dd7cddfSDavid du Colombier // writefile("interlace", im, gran); 1547dd7cddfSDavid du Colombier 1557dd7cddfSDavid du Colombier gran = nextmask(mask, axis, gran); 1567dd7cddfSDavid du Colombier shuffle(im, tmp, axis, n, mask, gran, nn); 1577dd7cddfSDavid du Colombier // writefile("shuffle", im, gran); 1587dd7cddfSDavid du Colombier moveup(im, tmp, lastnn, nn, n, axis); 1597dd7cddfSDavid du Colombier // writefile("move", im, gran); 1607dd7cddfSDavid du Colombier } 1617dd7cddfSDavid du Colombier 1627dd7cddfSDavid du Colombier void 1637dd7cddfSDavid du Colombier rot180(Image *im) 1647dd7cddfSDavid du Colombier { 1655d459b5aSDavid du Colombier Image *tmp, *tmp0; 1667dd7cddfSDavid du Colombier Image *mask; 1677dd7cddfSDavid du Colombier Rectangle rmask; 1687dd7cddfSDavid du Colombier int gran; 1697dd7cddfSDavid du Colombier 1705d459b5aSDavid du Colombier if(chantodepth(im->chan) < 8){ 1715d459b5aSDavid du Colombier /* this speeds things up dramatically; draw is too slow on sub-byte pixel sizes */ 1725d459b5aSDavid du Colombier tmp0 = xallocimage(display, im->r, CMAP8, 0, DNofill); 1736b6b9ac8SDavid du Colombier drawop(tmp0, tmp0->r, im, nil, im->r.min, S); 1745d459b5aSDavid du Colombier }else 1755d459b5aSDavid du Colombier tmp0 = im; 1767dd7cddfSDavid du Colombier 1775d459b5aSDavid du Colombier tmp = xallocimage(display, tmp0->r, tmp0->chan, 0, DNofill); 1785d459b5aSDavid du Colombier if(tmp == nil){ 1795d459b5aSDavid du Colombier if(tmp0 != im) 1805d459b5aSDavid du Colombier freeimage(tmp0); 1815d459b5aSDavid du Colombier return; 1825d459b5aSDavid du Colombier } 1837dd7cddfSDavid du Colombier for(gran=1; gran<Dx(im->r); gran *= 2) 1847dd7cddfSDavid du Colombier ; 1857dd7cddfSDavid du Colombier gran /= 4; 1867dd7cddfSDavid du Colombier 1877dd7cddfSDavid du Colombier rmask.min = ZP; 1887dd7cddfSDavid du Colombier rmask.max = (Point){2*gran, 100}; 1897dd7cddfSDavid du Colombier 1907dd7cddfSDavid du Colombier mask = xallocimage(display, rmask, GREY1, 1, DTransparent); 1917dd7cddfSDavid du Colombier mtmp = xallocimage(display, rmask, GREY1, 1, DTransparent); 192*5316891fSDavid du Colombier if(mask == nil || mtmp == nil) { 193*5316891fSDavid du Colombier fprint(2, "out of memory during rot180: %r\n"); 194*5316891fSDavid du Colombier wexits("memory"); 195*5316891fSDavid du Colombier } 1967dd7cddfSDavid du Colombier rmask.max.x = gran; 1976b6b9ac8SDavid du Colombier drawop(mask, rmask, display->opaque, nil, ZP, S); 1987dd7cddfSDavid du Colombier // writefile("mask", mask, gran); 1997dd7cddfSDavid du Colombier shuffle(im, tmp, Xaxis, Dx(im->r), mask, gran, 0); 2007dd7cddfSDavid du Colombier freeimage(mask); 2017dd7cddfSDavid du Colombier freeimage(mtmp); 2027dd7cddfSDavid du Colombier 2037dd7cddfSDavid du Colombier for(gran=1; gran<Dy(im->r); gran *= 2) 2047dd7cddfSDavid du Colombier ; 2057dd7cddfSDavid du Colombier gran /= 4; 2067dd7cddfSDavid du Colombier rmask.max = (Point){100, 2*gran}; 2077dd7cddfSDavid du Colombier mask = xallocimage(display, rmask, GREY1, 1, DTransparent); 2087dd7cddfSDavid du Colombier mtmp = xallocimage(display, rmask, GREY1, 1, DTransparent); 209*5316891fSDavid du Colombier if(mask == nil || mtmp == nil) { 210*5316891fSDavid du Colombier fprint(2, "out of memory during rot180: %r\n"); 211*5316891fSDavid du Colombier wexits("memory"); 212*5316891fSDavid du Colombier } 2137dd7cddfSDavid du Colombier rmask.max.y = gran; 2146b6b9ac8SDavid du Colombier drawop(mask, rmask, display->opaque, nil, ZP, S); 2157dd7cddfSDavid du Colombier shuffle(im, tmp, Yaxis, Dy(im->r), mask, gran, 0); 2167dd7cddfSDavid du Colombier freeimage(mask); 2177dd7cddfSDavid du Colombier freeimage(mtmp); 2187dd7cddfSDavid du Colombier freeimage(tmp); 2195d459b5aSDavid du Colombier if(tmp0 != im) 2205d459b5aSDavid du Colombier freeimage(tmp0); 2217dd7cddfSDavid du Colombier } 22208fd2d13SDavid du Colombier 22308fd2d13SDavid du Colombier /* rotates an image 90 degrees clockwise */ 22408fd2d13SDavid du Colombier Image * 22508fd2d13SDavid du Colombier rot90(Image *im) 22608fd2d13SDavid du Colombier { 22708fd2d13SDavid du Colombier Image *tmp; 22808fd2d13SDavid du Colombier int i, j, dx, dy; 22908fd2d13SDavid du Colombier 23008fd2d13SDavid du Colombier dx = Dx(im->r); 23108fd2d13SDavid du Colombier dy = Dy(im->r); 23208fd2d13SDavid du Colombier tmp = xallocimage(display, Rect(0, 0, dy, dx), im->chan, 0, DCyan); 233*5316891fSDavid du Colombier if(tmp == nil) { 234*5316891fSDavid du Colombier fprint(2, "out of memory during rot90: %r\n"); 235*5316891fSDavid du Colombier wexits("memory"); 236*5316891fSDavid du Colombier } 23708fd2d13SDavid du Colombier 23808fd2d13SDavid du Colombier for(j = 0; j < dx; j++) { 23908fd2d13SDavid du Colombier for(i = 0; i < dy; i++) { 240*5316891fSDavid du Colombier drawop(tmp, Rect(i, j, i+1, j+1), im, nil, Pt(j, dy-(i+1)), S); 24108fd2d13SDavid du Colombier } 24208fd2d13SDavid du Colombier } 24308fd2d13SDavid du Colombier freeimage(im); 24408fd2d13SDavid du Colombier 24508fd2d13SDavid du Colombier return(tmp); 24608fd2d13SDavid du Colombier } 24708fd2d13SDavid du Colombier 24808fd2d13SDavid du Colombier /* from resample.c -- resize from → to using interpolation */ 24908fd2d13SDavid du Colombier 25008fd2d13SDavid du Colombier 25108fd2d13SDavid du Colombier #define K2 7 /* from -.7 to +.7 inclusive, meaning .2 into each adjacent pixel */ 25208fd2d13SDavid du Colombier #define NK (2*K2+1) 25308fd2d13SDavid du Colombier double K[NK]; 25408fd2d13SDavid du Colombier 25508fd2d13SDavid du Colombier double 25608fd2d13SDavid du Colombier fac(int L) 25708fd2d13SDavid du Colombier { 25808fd2d13SDavid du Colombier int i, f; 25908fd2d13SDavid du Colombier 26008fd2d13SDavid du Colombier f = 1; 26108fd2d13SDavid du Colombier for(i=L; i>1; --i) 26208fd2d13SDavid du Colombier f *= i; 26308fd2d13SDavid du Colombier return f; 26408fd2d13SDavid du Colombier } 26508fd2d13SDavid du Colombier 26608fd2d13SDavid du Colombier /* 26708fd2d13SDavid du Colombier * i0(x) is the modified Bessel function, Σ (x/2)^2L / (L!)² 26808fd2d13SDavid du Colombier * There are faster ways to calculate this, but we precompute 26908fd2d13SDavid du Colombier * into a table so let's keep it simple. 27008fd2d13SDavid du Colombier */ 27108fd2d13SDavid du Colombier double 27208fd2d13SDavid du Colombier i0(double x) 27308fd2d13SDavid du Colombier { 27408fd2d13SDavid du Colombier double v; 27508fd2d13SDavid du Colombier int L; 27608fd2d13SDavid du Colombier 27708fd2d13SDavid du Colombier v = 1.0; 27808fd2d13SDavid du Colombier for(L=1; L<10; L++) 27908fd2d13SDavid du Colombier v += pow(x/2., 2*L)/pow(fac(L), 2); 28008fd2d13SDavid du Colombier return v; 28108fd2d13SDavid du Colombier } 28208fd2d13SDavid du Colombier 28308fd2d13SDavid du Colombier double 28408fd2d13SDavid du Colombier kaiser(double x, double τ, double α) 28508fd2d13SDavid du Colombier { 28608fd2d13SDavid du Colombier if(fabs(x) > τ) 28708fd2d13SDavid du Colombier return 0.; 28808fd2d13SDavid du Colombier return i0(α*sqrt(1-(x*x/(τ*τ))))/i0(α); 28908fd2d13SDavid du Colombier } 29008fd2d13SDavid du Colombier 29108fd2d13SDavid du Colombier 29208fd2d13SDavid du Colombier void 29308fd2d13SDavid du Colombier resamplex(uchar *in, int off, int d, int inx, uchar *out, int outx) 29408fd2d13SDavid du Colombier { 29508fd2d13SDavid du Colombier int i, x, k; 29608fd2d13SDavid du Colombier double X, xx, v, rat; 29708fd2d13SDavid du Colombier 29808fd2d13SDavid du Colombier 29908fd2d13SDavid du Colombier rat = (double)inx/(double)outx; 30008fd2d13SDavid du Colombier for(x=0; x<outx; x++){ 30108fd2d13SDavid du Colombier if(inx == outx){ 30208fd2d13SDavid du Colombier /* don't resample if size unchanged */ 30308fd2d13SDavid du Colombier out[off+x*d] = in[off+x*d]; 30408fd2d13SDavid du Colombier continue; 30508fd2d13SDavid du Colombier } 30608fd2d13SDavid du Colombier v = 0.0; 30708fd2d13SDavid du Colombier X = x*rat; 30808fd2d13SDavid du Colombier for(k=-K2; k<=K2; k++){ 30908fd2d13SDavid du Colombier xx = X + rat*k/10.; 31008fd2d13SDavid du Colombier i = xx; 31108fd2d13SDavid du Colombier if(i < 0) 31208fd2d13SDavid du Colombier i = 0; 31308fd2d13SDavid du Colombier if(i >= inx) 31408fd2d13SDavid du Colombier i = inx-1; 31508fd2d13SDavid du Colombier v += in[off+i*d] * K[K2+k]; 31608fd2d13SDavid du Colombier } 31708fd2d13SDavid du Colombier out[off+x*d] = v; 31808fd2d13SDavid du Colombier } 31908fd2d13SDavid du Colombier } 32008fd2d13SDavid du Colombier 32108fd2d13SDavid du Colombier void 32208fd2d13SDavid du Colombier resampley(uchar **in, int off, int iny, uchar **out, int outy) 32308fd2d13SDavid du Colombier { 32408fd2d13SDavid du Colombier int y, i, k; 32508fd2d13SDavid du Colombier double Y, yy, v, rat; 32608fd2d13SDavid du Colombier 32708fd2d13SDavid du Colombier rat = (double)iny/(double)outy; 32808fd2d13SDavid du Colombier for(y=0; y<outy; y++){ 32908fd2d13SDavid du Colombier if(iny == outy){ 33008fd2d13SDavid du Colombier /* don't resample if size unchanged */ 33108fd2d13SDavid du Colombier out[y][off] = in[y][off]; 33208fd2d13SDavid du Colombier continue; 33308fd2d13SDavid du Colombier } 33408fd2d13SDavid du Colombier v = 0.0; 33508fd2d13SDavid du Colombier Y = y*rat; 33608fd2d13SDavid du Colombier for(k=-K2; k<=K2; k++){ 33708fd2d13SDavid du Colombier yy = Y + rat*k/10.; 33808fd2d13SDavid du Colombier i = yy; 33908fd2d13SDavid du Colombier if(i < 0) 34008fd2d13SDavid du Colombier i = 0; 34108fd2d13SDavid du Colombier if(i >= iny) 34208fd2d13SDavid du Colombier i = iny-1; 34308fd2d13SDavid du Colombier v += in[i][off] * K[K2+k]; 34408fd2d13SDavid du Colombier } 34508fd2d13SDavid du Colombier out[y][off] = v; 34608fd2d13SDavid du Colombier } 34708fd2d13SDavid du Colombier 34808fd2d13SDavid du Colombier } 34908fd2d13SDavid du Colombier 35008fd2d13SDavid du Colombier Image* 35108fd2d13SDavid du Colombier resample(Image *from, Image *to) 35208fd2d13SDavid du Colombier { 35308fd2d13SDavid du Colombier int i, j, bpl, nchan; 35408fd2d13SDavid du Colombier uchar **oscan, **nscan; 35508fd2d13SDavid du Colombier char tmp[20]; 35608fd2d13SDavid du Colombier int xsize, ysize; 35708fd2d13SDavid du Colombier double v; 35808fd2d13SDavid du Colombier Image *t1, *t2; 35908fd2d13SDavid du Colombier ulong tchan; 36008fd2d13SDavid du Colombier 36108fd2d13SDavid du Colombier for(i=-K2; i<=K2; i++){ 36208fd2d13SDavid du Colombier K[K2+i] = kaiser(i/10., K2/10., 4.); 36308fd2d13SDavid du Colombier } 36408fd2d13SDavid du Colombier 36508fd2d13SDavid du Colombier /* normalize */ 36608fd2d13SDavid du Colombier v = 0.0; 36708fd2d13SDavid du Colombier for(i=0; i<NK; i++) 36808fd2d13SDavid du Colombier v += K[i]; 36908fd2d13SDavid du Colombier for(i=0; i<NK; i++) 37008fd2d13SDavid du Colombier K[i] /= v; 37108fd2d13SDavid du Colombier 37208fd2d13SDavid du Colombier switch(from->chan){ 37308fd2d13SDavid du Colombier case GREY8: 37408fd2d13SDavid du Colombier case RGB24: 37508fd2d13SDavid du Colombier case RGBA32: 37608fd2d13SDavid du Colombier case ARGB32: 37708fd2d13SDavid du Colombier case XRGB32: 37808fd2d13SDavid du Colombier break; 37908fd2d13SDavid du Colombier 38008fd2d13SDavid du Colombier case CMAP8: 38108fd2d13SDavid du Colombier case RGB15: 38208fd2d13SDavid du Colombier case RGB16: 38308fd2d13SDavid du Colombier tchan = RGB24; 38408fd2d13SDavid du Colombier goto Convert; 38508fd2d13SDavid du Colombier 38608fd2d13SDavid du Colombier case GREY1: 38708fd2d13SDavid du Colombier case GREY2: 38808fd2d13SDavid du Colombier case GREY4: 38908fd2d13SDavid du Colombier tchan = GREY8; 39008fd2d13SDavid du Colombier Convert: 39108fd2d13SDavid du Colombier /* use library to convert to byte-per-chan form, then convert back */ 392*5316891fSDavid du Colombier t1 = xallocimage(display, Rect(0, 0, Dx(from->r), Dy(from->r)), tchan, 0, DNofill); 393*5316891fSDavid du Colombier if(t1 == nil) { 394*5316891fSDavid du Colombier fprint(2, "out of memory for temp image 1 in resample: %r\n"); 395*5316891fSDavid du Colombier wexits("memory"); 396*5316891fSDavid du Colombier } 397*5316891fSDavid du Colombier drawop(t1, t1->r, from, nil, ZP, S); 398*5316891fSDavid du Colombier t2 = xallocimage(display, to->r, tchan, 0, DNofill); 399*5316891fSDavid du Colombier if(t2 == nil) { 400*5316891fSDavid du Colombier fprint(2, "out of memory temp image 2 in resample: %r\n"); 401*5316891fSDavid du Colombier wexits("memory"); 402*5316891fSDavid du Colombier } 40308fd2d13SDavid du Colombier resample(t1, t2); 404*5316891fSDavid du Colombier drawop(to, to->r, t2, nil, ZP, S); 40508fd2d13SDavid du Colombier freeimage(t1); 40608fd2d13SDavid du Colombier freeimage(t2); 40708fd2d13SDavid du Colombier return to; 40808fd2d13SDavid du Colombier 40908fd2d13SDavid du Colombier default: 41008fd2d13SDavid du Colombier sysfatal("can't handle channel type %s", chantostr(tmp, from->chan)); 41108fd2d13SDavid du Colombier } 41208fd2d13SDavid du Colombier 41308fd2d13SDavid du Colombier xsize = Dx(to->r); 41408fd2d13SDavid du Colombier ysize = Dy(to->r); 41508fd2d13SDavid du Colombier oscan = malloc(Dy(from->r)*sizeof(uchar*)); 41608fd2d13SDavid du Colombier nscan = malloc(max(ysize, Dy(from->r))*sizeof(uchar*)); 41708fd2d13SDavid du Colombier if(oscan == nil || nscan == nil) 41808fd2d13SDavid du Colombier sysfatal("can't allocate: %r"); 41908fd2d13SDavid du Colombier 42008fd2d13SDavid du Colombier /* unload original image into scan lines */ 42108fd2d13SDavid du Colombier bpl = bytesperline(from->r, from->depth); 42208fd2d13SDavid du Colombier for(i=0; i<Dy(from->r); i++){ 42308fd2d13SDavid du Colombier oscan[i] = malloc(bpl); 42408fd2d13SDavid du Colombier if(oscan[i] == nil) 42508fd2d13SDavid du Colombier sysfatal("can't allocate: %r"); 42608fd2d13SDavid du Colombier j = unloadimage(from, Rect(from->r.min.x, from->r.min.y+i, from->r.max.x, from->r.min.y+i+1), oscan[i], bpl); 42708fd2d13SDavid du Colombier if(j != bpl) 42808fd2d13SDavid du Colombier sysfatal("unloadimage"); 42908fd2d13SDavid du Colombier } 43008fd2d13SDavid du Colombier 43108fd2d13SDavid du Colombier /* allocate scan lines for destination. we do y first, so need at least Dy(from->r) lines */ 43208fd2d13SDavid du Colombier bpl = bytesperline(Rect(0, 0, xsize, Dy(from->r)), from->depth); 43308fd2d13SDavid du Colombier for(i=0; i<max(ysize, Dy(from->r)); i++){ 43408fd2d13SDavid du Colombier nscan[i] = malloc(bpl); 43508fd2d13SDavid du Colombier if(nscan[i] == nil) 43608fd2d13SDavid du Colombier sysfatal("can't allocate: %r"); 43708fd2d13SDavid du Colombier } 43808fd2d13SDavid du Colombier 43908fd2d13SDavid du Colombier /* resample in X */ 44008fd2d13SDavid du Colombier nchan = from->depth/8; 44108fd2d13SDavid du Colombier for(i=0; i<Dy(from->r); i++){ 44208fd2d13SDavid du Colombier for(j=0; j<nchan; j++){ 44308fd2d13SDavid du Colombier if(j==0 && from->chan==XRGB32) 44408fd2d13SDavid du Colombier continue; 44508fd2d13SDavid du Colombier resamplex(oscan[i], j, nchan, Dx(from->r), nscan[i], xsize); 44608fd2d13SDavid du Colombier } 44708fd2d13SDavid du Colombier free(oscan[i]); 44808fd2d13SDavid du Colombier oscan[i] = nscan[i]; 44908fd2d13SDavid du Colombier nscan[i] = malloc(bpl); 45008fd2d13SDavid du Colombier if(nscan[i] == nil) 45108fd2d13SDavid du Colombier sysfatal("can't allocate: %r"); 45208fd2d13SDavid du Colombier } 45308fd2d13SDavid du Colombier 45408fd2d13SDavid du Colombier /* resample in Y */ 45508fd2d13SDavid du Colombier for(i=0; i<xsize; i++) 45608fd2d13SDavid du Colombier for(j=0; j<nchan; j++) 45708fd2d13SDavid du Colombier resampley(oscan, nchan*i+j, Dy(from->r), nscan, ysize); 45808fd2d13SDavid du Colombier 45908fd2d13SDavid du Colombier /* pack data into destination */ 46008fd2d13SDavid du Colombier bpl = bytesperline(to->r, from->depth); 46108fd2d13SDavid du Colombier for(i=0; i<ysize; i++){ 46208fd2d13SDavid du Colombier j = loadimage(to, Rect(0, i, xsize, i+1), nscan[i], bpl); 46308fd2d13SDavid du Colombier if(j != bpl) 46408fd2d13SDavid du Colombier sysfatal("loadimage: %r"); 46508fd2d13SDavid du Colombier } 46608fd2d13SDavid du Colombier 46708fd2d13SDavid du Colombier for(i=0; i<Dy(from->r); i++){ 46808fd2d13SDavid du Colombier free(oscan[i]); 46908fd2d13SDavid du Colombier free(nscan[i]); 47008fd2d13SDavid du Colombier } 47108fd2d13SDavid du Colombier free(oscan); 47208fd2d13SDavid du Colombier free(nscan); 47308fd2d13SDavid du Colombier 47408fd2d13SDavid du Colombier return to; 47508fd2d13SDavid du Colombier } 476