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 }