shithub: blie

ref: 1077381027fbb3b04aff7b5310f2fb744a8bf1fe
dir: /sample.c/

View raw version
#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;
	
	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;
	
	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)
			return;
	}
	
	tmi = allocmemimage(r, img->chan);
	memfillcolor(tmi, DBlack);
	memimagedraw(tmi, tmi->r, lastsampled, 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;
}