| #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; |
| } |