diff options
Diffstat (limited to 'src/cmd/jpg/onechan.c')
-rw-r--r-- | src/cmd/jpg/onechan.c | 229 |
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; +} |