230 lines
3.6 KiB
C
230 lines
3.6 KiB
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;
|
||
|
}
|