ref: 361b65e4df0b4a3562a6e57b0f7b8009c59c3f2b
dir: /sys/src/cmd/jpg/onechan.c/
#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; }