aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/jpg/onechan.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/jpg/onechan.c')
-rw-r--r--src/cmd/jpg/onechan.c229
1 files changed, 229 insertions, 0 deletions
diff --git a/src/cmd/jpg/onechan.c b/src/cmd/jpg/onechan.c
new file mode 100644
index 00000000..ea1c489b
--- /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;
+}