ref: 2334bbcfe1b0137c8e271bc9d14f18f5d29132ae
dir: /sample.c/
#include <u.h> #include <libc.h> #include <draw.h> #include <memdraw.h> #include <event.h> #include "blie.h" /* direct copy from /sys/src/cmd/iconv.c:/^writeuncompressed */ static void writeuncompressed(int fd, Memimage *m) { char chanstr[32]; int bpl, y, j; uchar *buf; if(chantostr(chanstr, m->chan) == nil) sysfatal("can't convert channel descriptor: %r"); fprint(fd, "%11s %11d %11d %11d %11d ", chanstr, m->r.min.x, m->r.min.y, m->r.max.x, m->r.max.y); bpl = bytesperline(m->r, m->depth); buf = malloc(bpl); if(buf == nil) sysfatal("malloc failed: %r"); for(y=m->r.min.y; y<m->r.max.y; y++){ j = unloadmemimage(m, Rect(m->r.min.x, y, m->r.max.x, y+1), buf, bpl); if(j != bpl) sysfatal("image unload failed: %r"); if(write(fd, buf, bpl) != bpl) sysfatal("write failed: %r"); } free(buf); } /* * uses external program for resampling in a pipe. * I can see several improvements for performance: * * 1. only scaling what's needed, which means calculating * the rectangle we want, extracting that to a * separate image for resampling. * 2. integrate resample functionality in this program * 3. only resample if zoom level or data changes. * at the moment, it resamples when panning. */ static Memimage* resample(Memimage *src, int nx, int ny) { int pin[2]; int pout[2]; int re, ro; char x[11], y[11]; Memimage *tm; Dir *dir; if (nx == Dx(src->r) && ny == Dy(src->r)) return nil; snprint(x, sizeof(x), "%d", nx); snprint(y, sizeof(y), "%d", ny); if (pipe(pout) < 0) { close(pout[0]); close(pout[1]); goto Err; } if (pipe(pin) < 0) { close(pout[0]); close(pout[1]); close(pin[0]); close(pin[1]); goto Err; } dir = dirfstat(pin[0]); if (!dir) { free(dir); goto Err; } dir->length = src->width * Dy(src->r) * sizeof(ulong) + 12 * 5; if (!dirfwstat(pin[0], dir)) { free(dir); goto Err; } free(dir); switch (fork()) { case -1: /* error */ goto Err; case 0: /* child */ dup(pin[1], 0); dup(pout[1], 1); close(pin[0]); close(pout[0]); execl("/bin/resample", "resample", "-x", x, "-y", y, nil); sysfatal("cannot exec: %r"); default: /* parent */ close(pout[1]); close(pin[1]); re = pout[0]; ro = pin[0]; } writeuncompressed(ro, src); tm = readmemimage(re); if (!tm) { close(re); close(ro); goto Err; } close(re); close(ro); return tm; Err: fprint(2, "resample: %r\n"); return nil; } Memimage *lastsampled = nil; void sampleview(Image *img, Memimage *src) { Memimage *tmi; Rectangle r; int nw; if (!vstate.dirty) return; if (!src) return; r.min = ZP; r.max = Pt(Dx(img->r), Dy(img->r)); if (vstate.dirty & Dzoom) { freememimage(lastsampled); lastsampled = nil; } if (!lastsampled) { lastsampled = resample(src, Dx(src->r)*vstate.zoom, Dy(src->r)*vstate.zoom); if (lastsampled) src = lastsampled; } tmi = allocmemimage(r, img->chan); memfillcolor(tmi, DBlack); memimagedraw(tmi, tmi->r, src, addpt(tmi->r.min, vstate.offset), nil, ZP, S); nw = tmi->width * tmi->r.max.y * sizeof(ulong); // tmi->r.max.y == Dy(tmi->r) draw(img, img->r, display->black, nil, ZP); loadimage(img, img->r, tmi->data->bdata, nw); freememimage(tmi); vstate.dirty = 0; }