Why not?
diff --git a/src/cmd/jpg/onechan.c b/src/cmd/jpg/onechan.c
new file mode 100644
index 0000000..ea1c489
--- /dev/null
+++ b/src/cmd/jpg/onechan.c
@@ -0,0 +1,229 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <memdraw.h>
+#include <bio.h>
+#include "imagefile.h"
+
+/* Convert image to a single channel, one byte per pixel */
+
+static
+int
+notrans(ulong chan)
+{
+	switch(chan){
+	case GREY1:
+	case GREY2:
+	case GREY4:
+	case	CMAP8:
+	case GREY8:
+		return 1;
+	}
+	return 0;
+}
+
+static
+int
+easycase(ulong chan)
+{
+	switch(chan){
+	case RGB16:
+	case RGB24:
+	case RGBA32:
+	case ARGB32:
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * Convert to one byte per pixel, RGBV or grey, depending
+ */
+
+static
+uchar*
+load(Image *image, Memimage *memimage)
+{
+	uchar *data, *p, *q0, *q1, *q2;
+	uchar *rgbv;
+	int depth, ndata, dx, dy, i, v;
+	ulong chan, pixel;
+	Rectangle r;
+	Rawimage ri, *nri;
+
+	if(memimage == nil){
+		r = image->r;
+		depth = image->depth;
+		chan = image->chan;
+	}else{
+		r = memimage->r;
+		depth = memimage->depth;
+		chan = memimage->chan;
+	}
+	dx = Dx(r);
+	dy = Dy(r);
+
+	/* 
+	 * Read image data into memory
+	 * potentially one extra byte on each end of each scan line.
+	 */
+	ndata = dy*(2+bytesperline(r, depth));
+	data = malloc(ndata);
+	if(data == nil)
+		return nil;
+	if(memimage != nil)
+		ndata = unloadmemimage(memimage, r, data, ndata);
+	else
+		ndata = unloadimage(image, r, data, ndata);
+	if(ndata < 0){
+		werrstr("onechan: %r");
+		free(data);
+		return nil;
+	}
+
+	/*
+	 * Repack
+	 */
+	memset(&ri, 0, sizeof(ri));
+	ri.r = r;
+	ri.cmap = nil;
+	ri.cmaplen = 0;
+	ri.nchans = 3;
+	ri.chanlen = dx*dy;
+	ri.chans[0] = malloc(ri.chanlen);
+	ri.chans[1] = malloc(ri.chanlen);
+	ri.chans[2] = malloc(ri.chanlen);
+	if(ri.chans[0]==nil || ri.chans[1]==nil || ri.chans[2]==nil){
+    Err:
+		free(ri.chans[0]);
+		free(ri.chans[1]);
+		free(ri.chans[2]);
+		free(data);
+		return nil;
+	}
+	ri.chandesc = CRGB;
+
+	p = data;
+	q0 = ri.chans[0];
+	q1 = ri.chans[1];
+	q2 = ri.chans[2];
+
+	switch(chan){
+	default:
+		werrstr("can't handle image type 0x%lux", chan);
+		goto Err;
+	case RGB16:
+		for(i=0; i<ri.chanlen; i++, p+=2){
+			pixel = (p[1]<<8)|p[0];	/* rrrrrggg gggbbbbb */
+			v = (pixel & 0xF800) >> 8;
+			*q0++ = v | (v>>5);
+			v = (pixel & 0x07E0) >> 3;
+			*q1++ = v | (v>>6);
+			v = (pixel & 0x001F) << 3;
+			*q2++ = v | (v>>5);
+		}
+		break;
+	case RGB24:
+		for(i=0; i<ri.chanlen; i++){
+			*q2++ = *p++;
+			*q1++ = *p++;
+			*q0++ = *p++;
+		}
+		break;
+	case RGBA32:
+		for(i=0; i<ri.chanlen; i++){
+			*q2++ = *p++;
+			*q1++ = *p++;
+			*q0++ = *p++;
+			p++;
+		}
+		break;
+	case ARGB32:
+		for(i=0; i<ri.chanlen; i++){
+			p++;
+			*q2++ = *p++;
+			*q1++ = *p++;
+			*q0++ = *p++;
+		}
+		break;
+	}
+
+	rgbv = nil;
+	nri = torgbv(&ri, 1);
+	if(nri != nil){
+		rgbv = nri->chans[0];
+		free(nri);
+	}
+
+	free(ri.chans[0]);
+	free(ri.chans[1]);
+	free(ri.chans[2]);
+	free(data);
+	return rgbv;
+}
+
+Image*
+onechan(Image *i)
+{
+	uchar *data;
+	Image *ni;
+
+	if(notrans(i->chan))
+		return i;
+
+	if(easycase(i->chan))
+		data = load(i, nil);
+	else{
+		ni = allocimage(display, i->r, RGB24, 0, DNofill);
+		if(ni == nil)
+			return ni;
+		draw(ni, ni->r, i, nil, i->r.min);
+		data = load(ni, nil);
+		freeimage(ni);
+	}
+
+	if(data == nil)
+		return nil;
+
+	ni = allocimage(display, i->r, CMAP8, 0, DNofill);
+	if(ni != nil)
+		if(loadimage(ni, ni->r, data, Dx(ni->r)*Dy(ni->r)) < 0){
+			freeimage(ni);
+			ni = nil;
+		}
+	free(data);
+	return ni;
+}
+
+Memimage*
+memonechan(Memimage *i)
+{
+	uchar *data;
+	Memimage *ni;
+
+	if(notrans(i->chan))
+		return i;
+
+	if(easycase(i->chan))
+		data = load(nil, i);
+	else{
+		ni = allocmemimage(i->r, RGB24);
+		if(ni == nil)
+			return ni;
+		memimagedraw(ni, ni->r, i, i->r.min, nil, ZP, S);
+		data = load(nil, ni);
+		freememimage(ni);
+	}
+
+	if(data == nil)
+		return nil;
+
+	ni = allocmemimage(i->r, CMAP8);
+	if(ni != nil)
+		if(loadmemimage(ni, ni->r, data, Dx(ni->r)*Dy(ni->r)) < 0){
+			freememimage(ni);
+			ni = nil;
+		}
+	free(data);
+	return ni;
+}