Blob
1 #include <u.h>2 #include <libc.h>3 #include <draw.h>4 #include <memdraw.h>5 #include <bio.h>6 #include "imagefile.h"8 /* Convert image to a single channel, one byte per pixel */10 static11 int12 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 }25 static26 int27 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 }39 /*40 * Convert to one byte per pixel, RGBV or grey, depending41 */43 static44 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;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);66 /*67 * Read image data into memory68 * 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 else77 ndata = unloadimage(image, r, data, ndata);78 if(ndata < 0){79 werrstr("onechan: %r");80 free(data);81 return nil;82 }84 /*85 * Repack86 */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;106 p = data;107 q0 = ri.chans[0];108 q1 = ri.chans[1];109 q2 = ri.chans[2];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 }151 rgbv = nil;152 nri = torgbv(&ri, 1);153 if(nri != nil){154 rgbv = nri->chans[0];155 free(nri);156 }158 free(ri.chans[0]);159 free(ri.chans[1]);160 free(ri.chans[2]);161 free(data);162 return rgbv;163 }165 Image*166 onechan(Image *i)167 {168 uchar *data;169 Image *ni;171 if(notrans(i->chan))172 return i;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 }185 if(data == nil)186 return nil;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 }198 Memimage*199 memonechan(Memimage *i)200 {201 uchar *data;202 Memimage *ni;204 if(notrans(i->chan))205 return i;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 }218 if(data == nil)219 return nil;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 }