rsc | 2899450 | 2004-04-21 22:19:33 +0000 | [diff] [blame] | 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 | } |