plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

onechan.c (3731B)


      1 #include <u.h>
      2 #include <libc.h>
      3 #include <draw.h>
      4 #include <memdraw.h>
      5 #include <bio.h>
      6 #include "imagefile.h"
      7 
      8 /* Convert image to a single channel, one byte per pixel */
      9 
     10 static
     11 int
     12 notrans(ulong chan)
     13 {
     14 	switch(chan){
     15 	case GREY1:
     16 	case GREY2:
     17 	case GREY4:
     18 	case	CMAP8:
     19 	case GREY8:
     20 		return 1;
     21 	}
     22 	return 0;
     23 }
     24 
     25 static
     26 int
     27 easycase(ulong chan)
     28 {
     29 	switch(chan){
     30 	case RGB16:
     31 	case RGB24:
     32 	case RGBA32:
     33 	case ARGB32:
     34 		return 1;
     35 	}
     36 	return 0;
     37 }
     38 
     39 /*
     40  * Convert to one byte per pixel, RGBV or grey, depending
     41  */
     42 
     43 static
     44 uchar*
     45 load(Image *image, Memimage *memimage)
     46 {
     47 	uchar *data, *p, *q0, *q1, *q2;
     48 	uchar *rgbv;
     49 	int depth, ndata, dx, dy, i, v;
     50 	ulong chan, pixel;
     51 	Rectangle r;
     52 	Rawimage ri, *nri;
     53 
     54 	if(memimage == nil){
     55 		r = image->r;
     56 		depth = image->depth;
     57 		chan = image->chan;
     58 	}else{
     59 		r = memimage->r;
     60 		depth = memimage->depth;
     61 		chan = memimage->chan;
     62 	}
     63 	dx = Dx(r);
     64 	dy = Dy(r);
     65 
     66 	/*
     67 	 * Read image data into memory
     68 	 * potentially one extra byte on each end of each scan line.
     69 	 */
     70 	ndata = dy*(2+bytesperline(r, depth));
     71 	data = malloc(ndata);
     72 	if(data == nil)
     73 		return nil;
     74 	if(memimage != nil)
     75 		ndata = unloadmemimage(memimage, r, data, ndata);
     76 	else
     77 		ndata = unloadimage(image, r, data, ndata);
     78 	if(ndata < 0){
     79 		werrstr("onechan: %r");
     80 		free(data);
     81 		return nil;
     82 	}
     83 
     84 	/*
     85 	 * Repack
     86 	 */
     87 	memset(&ri, 0, sizeof(ri));
     88 	ri.r = r;
     89 	ri.cmap = nil;
     90 	ri.cmaplen = 0;
     91 	ri.nchans = 3;
     92 	ri.chanlen = dx*dy;
     93 	ri.chans[0] = malloc(ri.chanlen);
     94 	ri.chans[1] = malloc(ri.chanlen);
     95 	ri.chans[2] = malloc(ri.chanlen);
     96 	if(ri.chans[0]==nil || ri.chans[1]==nil || ri.chans[2]==nil){
     97     Err:
     98 		free(ri.chans[0]);
     99 		free(ri.chans[1]);
    100 		free(ri.chans[2]);
    101 		free(data);
    102 		return nil;
    103 	}
    104 	ri.chandesc = CRGB;
    105 
    106 	p = data;
    107 	q0 = ri.chans[0];
    108 	q1 = ri.chans[1];
    109 	q2 = ri.chans[2];
    110 
    111 	switch(chan){
    112 	default:
    113 		werrstr("can't handle image type 0x%lux", chan);
    114 		goto Err;
    115 	case RGB16:
    116 		for(i=0; i<ri.chanlen; i++, p+=2){
    117 			pixel = (p[1]<<8)|p[0];	/* rrrrrggg gggbbbbb */
    118 			v = (pixel & 0xF800) >> 8;
    119 			*q0++ = v | (v>>5);
    120 			v = (pixel & 0x07E0) >> 3;
    121 			*q1++ = v | (v>>6);
    122 			v = (pixel & 0x001F) << 3;
    123 			*q2++ = v | (v>>5);
    124 		}
    125 		break;
    126 	case RGB24:
    127 		for(i=0; i<ri.chanlen; i++){
    128 			*q2++ = *p++;
    129 			*q1++ = *p++;
    130 			*q0++ = *p++;
    131 		}
    132 		break;
    133 	case RGBA32:
    134 		for(i=0; i<ri.chanlen; i++){
    135 			*q2++ = *p++;
    136 			*q1++ = *p++;
    137 			*q0++ = *p++;
    138 			p++;
    139 		}
    140 		break;
    141 	case ARGB32:
    142 		for(i=0; i<ri.chanlen; i++){
    143 			p++;
    144 			*q2++ = *p++;
    145 			*q1++ = *p++;
    146 			*q0++ = *p++;
    147 		}
    148 		break;
    149 	}
    150 
    151 	rgbv = nil;
    152 	nri = torgbv(&ri, 1);
    153 	if(nri != nil){
    154 		rgbv = nri->chans[0];
    155 		free(nri);
    156 	}
    157 
    158 	free(ri.chans[0]);
    159 	free(ri.chans[1]);
    160 	free(ri.chans[2]);
    161 	free(data);
    162 	return rgbv;
    163 }
    164 
    165 Image*
    166 onechan(Image *i)
    167 {
    168 	uchar *data;
    169 	Image *ni;
    170 
    171 	if(notrans(i->chan))
    172 		return i;
    173 
    174 	if(easycase(i->chan))
    175 		data = load(i, nil);
    176 	else{
    177 		ni = allocimage(display, i->r, RGB24, 0, DNofill);
    178 		if(ni == nil)
    179 			return ni;
    180 		draw(ni, ni->r, i, nil, i->r.min);
    181 		data = load(ni, nil);
    182 		freeimage(ni);
    183 	}
    184 
    185 	if(data == nil)
    186 		return nil;
    187 
    188 	ni = allocimage(display, i->r, CMAP8, 0, DNofill);
    189 	if(ni != nil)
    190 		if(loadimage(ni, ni->r, data, Dx(ni->r)*Dy(ni->r)) < 0){
    191 			freeimage(ni);
    192 			ni = nil;
    193 		}
    194 	free(data);
    195 	return ni;
    196 }
    197 
    198 Memimage*
    199 memonechan(Memimage *i)
    200 {
    201 	uchar *data;
    202 	Memimage *ni;
    203 
    204 	if(notrans(i->chan))
    205 		return i;
    206 
    207 	if(easycase(i->chan))
    208 		data = load(nil, i);
    209 	else{
    210 		ni = allocmemimage(i->r, RGB24);
    211 		if(ni == nil)
    212 			return ni;
    213 		memimagedraw(ni, ni->r, i, i->r.min, nil, ZP, S);
    214 		data = load(nil, ni);
    215 		freememimage(ni);
    216 	}
    217 
    218 	if(data == nil)
    219 		return nil;
    220 
    221 	ni = allocmemimage(i->r, CMAP8);
    222 	if(ni != nil)
    223 		if(loadmemimage(ni, ni->r, data, Dx(ni->r)*Dy(ni->r)) < 0){
    224 			freememimage(ni);
    225 			ni = nil;
    226 		}
    227 	free(data);
    228 	return ni;
    229 }