| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | #include "imageri.h" | 
| 2 |  |  |  |  |  |  | #include "log.h" | 
| 3 |  |  |  |  |  |  | #include "iolayer.h" | 
| 4 |  |  |  |  |  |  |  | 
| 5 |  |  |  |  |  |  | #include | 
| 6 |  |  |  |  |  |  | #include | 
| 7 |  |  |  |  |  |  |  | 
| 8 |  |  |  |  |  |  |  | 
| 9 |  |  |  |  |  |  | /* | 
| 10 |  |  |  |  |  |  | =head1 NAME | 
| 11 |  |  |  |  |  |  |  | 
| 12 |  |  |  |  |  |  | tga.c - implements reading and writing targa files, uses io layer. | 
| 13 |  |  |  |  |  |  |  | 
| 14 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 15 |  |  |  |  |  |  |  | 
| 16 |  |  |  |  |  |  | io_glue *ig = io_new_fd( fd ); | 
| 17 |  |  |  |  |  |  | i_img *im   = i_readtga_wiol(ig, -1); // no limit on how much is read | 
| 18 |  |  |  |  |  |  | // or | 
| 19 |  |  |  |  |  |  | io_glue *ig = io_new_fd( fd ); | 
| 20 |  |  |  |  |  |  | return_code = i_writetga_wiol(im, ig); | 
| 21 |  |  |  |  |  |  |  | 
| 22 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 23 |  |  |  |  |  |  |  | 
| 24 |  |  |  |  |  |  | tga.c implements the basic functions to read and write portable targa | 
| 25 |  |  |  |  |  |  | files.  It uses the iolayer and needs either a seekable source or an | 
| 26 |  |  |  |  |  |  | entire memory mapped buffer. | 
| 27 |  |  |  |  |  |  |  | 
| 28 |  |  |  |  |  |  | =head1 FUNCTION REFERENCE | 
| 29 |  |  |  |  |  |  |  | 
| 30 |  |  |  |  |  |  | Some of these functions are internal. | 
| 31 |  |  |  |  |  |  |  | 
| 32 |  |  |  |  |  |  | =over | 
| 33 |  |  |  |  |  |  |  | 
| 34 |  |  |  |  |  |  | =cut | 
| 35 |  |  |  |  |  |  | */ | 
| 36 |  |  |  |  |  |  |  | 
| 37 |  |  |  |  |  |  |  | 
| 38 |  |  |  |  |  |  |  | 
| 39 |  |  |  |  |  |  |  | 
| 40 |  |  |  |  |  |  | typedef struct { | 
| 41 |  |  |  |  |  |  | unsigned char  idlength; | 
| 42 |  |  |  |  |  |  | char  colourmaptype; | 
| 43 |  |  |  |  |  |  | char  datatypecode; | 
| 44 |  |  |  |  |  |  | short int colourmaporigin; | 
| 45 |  |  |  |  |  |  | short int colourmaplength; | 
| 46 |  |  |  |  |  |  | char  colourmapdepth; | 
| 47 |  |  |  |  |  |  | short int x_origin; | 
| 48 |  |  |  |  |  |  | short int y_origin; | 
| 49 |  |  |  |  |  |  | int width; | 
| 50 |  |  |  |  |  |  | int height; | 
| 51 |  |  |  |  |  |  | char  bitsperpixel; | 
| 52 |  |  |  |  |  |  | char  imagedescriptor; | 
| 53 |  |  |  |  |  |  | } tga_header; | 
| 54 |  |  |  |  |  |  |  | 
| 55 |  |  |  |  |  |  |  | 
| 56 |  |  |  |  |  |  | typedef enum { NoInit, Raw, Rle } rle_state; | 
| 57 |  |  |  |  |  |  |  | 
| 58 |  |  |  |  |  |  | typedef struct { | 
| 59 |  |  |  |  |  |  | int compressed; | 
| 60 |  |  |  |  |  |  | size_t bytepp; | 
| 61 |  |  |  |  |  |  | rle_state state; | 
| 62 |  |  |  |  |  |  | unsigned char cval[4]; | 
| 63 |  |  |  |  |  |  | int len; | 
| 64 |  |  |  |  |  |  | unsigned char hdr; | 
| 65 |  |  |  |  |  |  | io_glue *ig; | 
| 66 |  |  |  |  |  |  | } tga_source; | 
| 67 |  |  |  |  |  |  |  | 
| 68 |  |  |  |  |  |  |  | 
| 69 |  |  |  |  |  |  | typedef struct { | 
| 70 |  |  |  |  |  |  | int compressed; | 
| 71 |  |  |  |  |  |  | int bytepp; | 
| 72 |  |  |  |  |  |  | io_glue *ig; | 
| 73 |  |  |  |  |  |  | } tga_dest; | 
| 74 |  |  |  |  |  |  |  | 
| 75 |  |  |  |  |  |  | #define TGA_MAX_DIM 0xFFFF | 
| 76 |  |  |  |  |  |  |  | 
| 77 |  |  |  |  |  |  | /* | 
| 78 |  |  |  |  |  |  | =item bpp_to_bytes(bpp) | 
| 79 |  |  |  |  |  |  |  | 
| 80 |  |  |  |  |  |  | Convert bits per pixel into bytes per pixel | 
| 81 |  |  |  |  |  |  |  | 
| 82 |  |  |  |  |  |  | bpp - bits per pixel | 
| 83 |  |  |  |  |  |  |  | 
| 84 |  |  |  |  |  |  | =cut | 
| 85 |  |  |  |  |  |  | */ | 
| 86 |  |  |  |  |  |  |  | 
| 87 |  |  |  |  |  |  |  | 
| 88 |  |  |  |  |  |  | static | 
| 89 |  |  |  |  |  |  | size_t | 
| 90 | 62 |  |  |  |  |  | bpp_to_bytes(unsigned int bpp) { | 
| 91 | 62 |  |  |  |  |  | switch (bpp) { | 
| 92 |  |  |  |  |  |  | case 8: | 
| 93 | 0 |  |  |  |  |  | return 1; | 
| 94 |  |  |  |  |  |  | case 15: | 
| 95 |  |  |  |  |  |  | case 16: | 
| 96 | 7 |  |  |  |  |  | return 2; | 
| 97 |  |  |  |  |  |  | case 24: | 
| 98 | 55 |  |  |  |  |  | return 3; | 
| 99 |  |  |  |  |  |  | case 32: | 
| 100 | 0 |  |  |  |  |  | return 4; | 
| 101 |  |  |  |  |  |  | } | 
| 102 | 0 |  |  |  |  |  | return 0; | 
| 103 |  |  |  |  |  |  | } | 
| 104 |  |  |  |  |  |  |  | 
| 105 |  |  |  |  |  |  |  | 
| 106 |  |  |  |  |  |  |  | 
| 107 |  |  |  |  |  |  | /* | 
| 108 |  |  |  |  |  |  | =item bpp_to_channels(bpp) | 
| 109 |  |  |  |  |  |  |  | 
| 110 |  |  |  |  |  |  | Convert bits per pixel and the number of attribute bits into channels | 
| 111 |  |  |  |  |  |  | in the image | 
| 112 |  |  |  |  |  |  |  | 
| 113 |  |  |  |  |  |  | bpp - bits per pixel | 
| 114 |  |  |  |  |  |  | attr_bit_count - number of attribute bits | 
| 115 |  |  |  |  |  |  |  | 
| 116 |  |  |  |  |  |  | =cut | 
| 117 |  |  |  |  |  |  | */ | 
| 118 |  |  |  |  |  |  |  | 
| 119 |  |  |  |  |  |  | static | 
| 120 |  |  |  |  |  |  | int | 
| 121 | 26 |  |  |  |  |  | bpp_to_channels(unsigned int bpp, int attr_bit_count) { | 
| 122 | 26 |  |  |  |  |  | switch (bpp) { | 
| 123 |  |  |  |  |  |  | case 8: | 
| 124 | 0 |  |  |  |  |  | return 1; | 
| 125 |  |  |  |  |  |  | case 16: | 
| 126 | 2 | 50 |  |  |  |  | if (attr_bit_count == 1) | 
| 127 | 2 |  |  |  |  |  | return 4; | 
| 128 |  |  |  |  |  |  | case 15: | 
| 129 | 0 |  |  |  |  |  | return 3; | 
| 130 |  |  |  |  |  |  | case 32: | 
| 131 | 0 | 0 |  |  |  |  | if (attr_bit_count == 8) | 
| 132 | 0 |  |  |  |  |  | return 4; | 
| 133 |  |  |  |  |  |  | case 24: | 
| 134 | 24 |  |  |  |  |  | return 3; | 
| 135 |  |  |  |  |  |  | } | 
| 136 | 0 |  |  |  |  |  | return 0; | 
| 137 |  |  |  |  |  |  | } | 
| 138 |  |  |  |  |  |  |  | 
| 139 |  |  |  |  |  |  |  | 
| 140 |  |  |  |  |  |  |  | 
| 141 |  |  |  |  |  |  | /* | 
| 142 |  |  |  |  |  |  | * Packing functions - used for (un)packing | 
| 143 |  |  |  |  |  |  | * datastructures into raw bytes. | 
| 144 |  |  |  |  |  |  | */ | 
| 145 |  |  |  |  |  |  |  | 
| 146 |  |  |  |  |  |  |  | 
| 147 |  |  |  |  |  |  | /* | 
| 148 |  |  |  |  |  |  | =item color_unpack(buf, bytepp, val) | 
| 149 |  |  |  |  |  |  |  | 
| 150 |  |  |  |  |  |  | Unpacks bytes into colour structures, for 2 byte type the first byte | 
| 151 |  |  |  |  |  |  | coming from the file will actually be GGGBBBBB, and the second will be | 
| 152 |  |  |  |  |  |  | ARRRRRGG.  "A" represents an attribute bit.  The 3 byte entry contains | 
| 153 |  |  |  |  |  |  | 1 byte each of blue, green, and red.  The 4 byte entry contains 1 byte | 
| 154 |  |  |  |  |  |  | each of blue, green, red, and attribute. | 
| 155 |  |  |  |  |  |  |  | 
| 156 |  |  |  |  |  |  | buf - pointer to data | 
| 157 |  |  |  |  |  |  | bytepp - bytes per pixel | 
| 158 |  |  |  |  |  |  | val - pointer to color to store to | 
| 159 |  |  |  |  |  |  |  | 
| 160 |  |  |  |  |  |  | =cut | 
| 161 |  |  |  |  |  |  | */ | 
| 162 |  |  |  |  |  |  |  | 
| 163 |  |  |  |  |  |  | static | 
| 164 |  |  |  |  |  |  | void | 
| 165 | 484024 |  |  |  |  |  | color_unpack(unsigned char *buf, int bytepp, i_color *val) { | 
| 166 | 484024 |  |  |  |  |  | switch (bytepp) { | 
| 167 |  |  |  |  |  |  | case 1: | 
| 168 | 0 |  |  |  |  |  | val->gray.gray_color = buf[0]; | 
| 169 | 0 |  |  |  |  |  | break; | 
| 170 |  |  |  |  |  |  | case 2: | 
| 171 | 800 |  |  |  |  |  | val->rgba.r = (buf[1] & 0x7c) << 1; | 
| 172 | 800 |  |  |  |  |  | val->rgba.g = ((buf[1] & 0x03) << 6) | ((buf[0] & 0xe0) >> 2); | 
| 173 | 800 |  |  |  |  |  | val->rgba.b = (buf[0] & 0x1f) << 3; | 
| 174 | 800 | 100 |  |  |  |  | val->rgba.a = (buf[1] & 0x80) ? 0 : 255; | 
| 175 | 800 |  |  |  |  |  | val->rgba.r |= val->rgba.r >> 5; | 
| 176 | 800 |  |  |  |  |  | val->rgba.g |= val->rgba.g >> 5; | 
| 177 | 800 |  |  |  |  |  | val->rgba.b |= val->rgba.b >> 5; | 
| 178 | 800 |  |  |  |  |  | break; | 
| 179 |  |  |  |  |  |  | case 3: | 
| 180 | 483224 |  |  |  |  |  | val->rgb.b = buf[0]; | 
| 181 | 483224 |  |  |  |  |  | val->rgb.g = buf[1]; | 
| 182 | 483224 |  |  |  |  |  | val->rgb.r = buf[2]; | 
| 183 | 483224 |  |  |  |  |  | break; | 
| 184 |  |  |  |  |  |  | case 4: | 
| 185 | 0 |  |  |  |  |  | val->rgba.b = buf[0]; | 
| 186 | 0 |  |  |  |  |  | val->rgba.g = buf[1]; | 
| 187 | 0 |  |  |  |  |  | val->rgba.r = buf[2]; | 
| 188 | 0 |  |  |  |  |  | val->rgba.a = buf[3]; | 
| 189 | 0 |  |  |  |  |  | break; | 
| 190 |  |  |  |  |  |  | } | 
| 191 | 484024 |  |  |  |  |  | } | 
| 192 |  |  |  |  |  |  |  | 
| 193 |  |  |  |  |  |  |  | 
| 194 |  |  |  |  |  |  |  | 
| 195 |  |  |  |  |  |  | /* | 
| 196 |  |  |  |  |  |  | =item color_pack | 
| 197 |  |  |  |  |  |  |  | 
| 198 |  |  |  |  |  |  | Packs a colour into an array of bytes, for 2 byte type the first byte | 
| 199 |  |  |  |  |  |  | will be GGGBBBBB, and the second will be ARRRRRGG.  "A" represents an | 
| 200 |  |  |  |  |  |  | attribute bit.  The 3 byte entry contains 1 byte each of blue, green, | 
| 201 |  |  |  |  |  |  | and red.  The 4 byte entry contains 1 byte each of blue, green, red, | 
| 202 |  |  |  |  |  |  | and attribute. | 
| 203 |  |  |  |  |  |  |  | 
| 204 |  |  |  |  |  |  | buf - destination buffer | 
| 205 |  |  |  |  |  |  | bitspp - bits per pixel | 
| 206 |  |  |  |  |  |  | val - color to pack | 
| 207 |  |  |  |  |  |  |  | 
| 208 |  |  |  |  |  |  | =cut | 
| 209 |  |  |  |  |  |  | */ | 
| 210 |  |  |  |  |  |  |  | 
| 211 |  |  |  |  |  |  | static | 
| 212 |  |  |  |  |  |  | void | 
| 213 | 497084 |  |  |  |  |  | color_pack(unsigned char *buf, int bitspp, i_color *val) { | 
| 214 | 497084 |  |  |  |  |  | switch (bitspp) { | 
| 215 |  |  |  |  |  |  | case 8: | 
| 216 | 0 |  |  |  |  |  | buf[0] = val->gray.gray_color; | 
| 217 | 0 |  |  |  |  |  | break; | 
| 218 |  |  |  |  |  |  | case 16: | 
| 219 | 400 |  |  |  |  |  | buf[0]  = (val->rgba.b >> 3); | 
| 220 | 400 |  |  |  |  |  | buf[0] |= (val->rgba.g & 0x38) << 2; | 
| 221 | 400 |  |  |  |  |  | buf[1]  = (val->rgba.r & 0xf8)>> 1; | 
| 222 | 400 |  |  |  |  |  | buf[1] |= (val->rgba.g >> 6); | 
| 223 | 400 | 100 |  |  |  |  | buf[1] |=  val->rgba.a > 0x7f ? 0 : 0x80; | 
| 224 | 400 |  |  |  |  |  | break; | 
| 225 |  |  |  |  |  |  | case 15: | 
| 226 | 45432 |  |  |  |  |  | buf[0]  = (val->rgba.b >> 3); | 
| 227 | 45432 |  |  |  |  |  | buf[0] |= (val->rgba.g & 0x38) << 2; | 
| 228 | 45432 |  |  |  |  |  | buf[1]  = (val->rgba.r & 0xf8)>> 1; | 
| 229 | 45432 |  |  |  |  |  | buf[1] |= (val->rgba.g >> 6); | 
| 230 | 45432 |  |  |  |  |  | break; | 
| 231 |  |  |  |  |  |  | case 24: | 
| 232 | 451252 |  |  |  |  |  | buf[0] = val->rgb.b; | 
| 233 | 451252 |  |  |  |  |  | buf[1] = val->rgb.g; | 
| 234 | 451252 |  |  |  |  |  | buf[2] = val->rgb.r; | 
| 235 | 451252 |  |  |  |  |  | break; | 
| 236 |  |  |  |  |  |  | case 32: | 
| 237 | 0 |  |  |  |  |  | buf[0] = val->rgba.b; | 
| 238 | 0 |  |  |  |  |  | buf[1] = val->rgba.g; | 
| 239 | 0 |  |  |  |  |  | buf[2] = val->rgba.r; | 
| 240 | 0 |  |  |  |  |  | buf[3] = val->rgba.a; | 
| 241 | 0 |  |  |  |  |  | break; | 
| 242 |  |  |  |  |  |  | } | 
| 243 | 497084 |  |  |  |  |  | } | 
| 244 |  |  |  |  |  |  |  | 
| 245 |  |  |  |  |  |  |  | 
| 246 |  |  |  |  |  |  | /* | 
| 247 |  |  |  |  |  |  | =item find_repeat | 
| 248 |  |  |  |  |  |  |  | 
| 249 |  |  |  |  |  |  | Helper function for rle compressor to find the next triple repeat of the | 
| 250 |  |  |  |  |  |  | same pixel value in buffer. | 
| 251 |  |  |  |  |  |  |  | 
| 252 |  |  |  |  |  |  | buf - buffer | 
| 253 |  |  |  |  |  |  | length - number of pixel values in buffer | 
| 254 |  |  |  |  |  |  | bytepp - number of bytes in a pixel value | 
| 255 |  |  |  |  |  |  |  | 
| 256 |  |  |  |  |  |  | =cut | 
| 257 |  |  |  |  |  |  | */ | 
| 258 |  |  |  |  |  |  |  | 
| 259 |  |  |  |  |  |  | static | 
| 260 |  |  |  |  |  |  | int | 
| 261 | 132482 |  |  |  |  |  | find_repeat(unsigned char *buf, int length, int bytepp) { | 
| 262 | 132482 |  |  |  |  |  | int i = 0; | 
| 263 |  |  |  |  |  |  |  | 
| 264 | 193399 | 100 |  |  |  |  | while(i | 
| 265 | 86904 | 100 |  |  |  |  | if(memcmp(buf+i*bytepp, buf+(i+1)*bytepp, bytepp) == 0) { | 
| 266 | 29883 | 50 |  |  |  |  | if (i == length-2) return -1; | 
| 267 | 29883 | 100 |  |  |  |  | if (memcmp(buf+(i+1)*bytepp, buf+(i+2)*bytepp,bytepp) == 0) | 
| 268 | 25987 |  |  |  |  |  | return i; | 
| 269 | 3896 |  |  |  |  |  | else i++; | 
| 270 |  |  |  |  |  |  | } | 
| 271 | 60917 |  |  |  |  |  | i++; | 
| 272 |  |  |  |  |  |  | } | 
| 273 | 106495 |  |  |  |  |  | return -1; | 
| 274 |  |  |  |  |  |  | } | 
| 275 |  |  |  |  |  |  |  | 
| 276 |  |  |  |  |  |  |  | 
| 277 |  |  |  |  |  |  | /* | 
| 278 |  |  |  |  |  |  | =item find_span | 
| 279 |  |  |  |  |  |  |  | 
| 280 |  |  |  |  |  |  | Helper function for rle compressor to find the length of a span where | 
| 281 |  |  |  |  |  |  | the same pixel value is in the buffer. | 
| 282 |  |  |  |  |  |  |  | 
| 283 |  |  |  |  |  |  | buf - buffer | 
| 284 |  |  |  |  |  |  | length - number of pixel values in buffer | 
| 285 |  |  |  |  |  |  | bytepp - number of bytes in a pixel value | 
| 286 |  |  |  |  |  |  |  | 
| 287 |  |  |  |  |  |  | =cut | 
| 288 |  |  |  |  |  |  | */ | 
| 289 |  |  |  |  |  |  |  | 
| 290 |  |  |  |  |  |  | static | 
| 291 |  |  |  |  |  |  | int | 
| 292 | 25987 |  |  |  |  |  | find_span(unsigned char *buf, int length, int bytepp) { | 
| 293 | 25987 |  |  |  |  |  | int i = 0; | 
| 294 | 440669 | 100 |  |  |  |  | while(i | 
| 295 | 438247 | 100 |  |  |  |  | if(memcmp(buf, buf+(i*bytepp), bytepp) != 0) return i; | 
| 296 | 414682 |  |  |  |  |  | i++; | 
| 297 |  |  |  |  |  |  | } | 
| 298 | 2422 |  |  |  |  |  | return length; | 
| 299 |  |  |  |  |  |  | } | 
| 300 |  |  |  |  |  |  |  | 
| 301 |  |  |  |  |  |  |  | 
| 302 |  |  |  |  |  |  | /* | 
| 303 |  |  |  |  |  |  | =item tga_header_unpack(header, headbuf) | 
| 304 |  |  |  |  |  |  |  | 
| 305 |  |  |  |  |  |  | Unpacks the header structure into from buffer and stores | 
| 306 |  |  |  |  |  |  | in the header structure. | 
| 307 |  |  |  |  |  |  |  | 
| 308 |  |  |  |  |  |  | header - header structure | 
| 309 |  |  |  |  |  |  | headbuf - buffer to unpack from | 
| 310 |  |  |  |  |  |  |  | 
| 311 |  |  |  |  |  |  | =cut | 
| 312 |  |  |  |  |  |  | */ | 
| 313 |  |  |  |  |  |  |  | 
| 314 |  |  |  |  |  |  | static | 
| 315 |  |  |  |  |  |  | void | 
| 316 | 70 |  |  |  |  |  | tga_header_unpack(tga_header *header, unsigned char headbuf[18]) { | 
| 317 | 70 |  |  |  |  |  | header->idlength        = headbuf[0]; | 
| 318 | 70 |  |  |  |  |  | header->colourmaptype   = headbuf[1]; | 
| 319 | 70 |  |  |  |  |  | header->datatypecode    = headbuf[2]; | 
| 320 | 70 |  |  |  |  |  | header->colourmaporigin = (headbuf[4] << 8) + headbuf[3]; | 
| 321 | 70 |  |  |  |  |  | header->colourmaplength = (headbuf[6] << 8) + headbuf[5]; | 
| 322 | 70 |  |  |  |  |  | header->colourmapdepth  = headbuf[7]; | 
| 323 | 70 |  |  |  |  |  | header->x_origin        = (headbuf[9] << 8) + headbuf[8]; | 
| 324 | 70 |  |  |  |  |  | header->y_origin        = (headbuf[11] << 8) + headbuf[10]; | 
| 325 | 70 |  |  |  |  |  | header->width           = (headbuf[13] << 8) + headbuf[12]; | 
| 326 | 70 |  |  |  |  |  | header->height          = (headbuf[15] << 8) + headbuf[14]; | 
| 327 | 70 |  |  |  |  |  | header->bitsperpixel    = headbuf[16]; | 
| 328 | 70 |  |  |  |  |  | header->imagedescriptor = headbuf[17]; | 
| 329 | 70 |  |  |  |  |  | } | 
| 330 |  |  |  |  |  |  |  | 
| 331 |  |  |  |  |  |  |  | 
| 332 |  |  |  |  |  |  | /* this function should never produce diagnostics to stdout, maybe to the logfile */ | 
| 333 |  |  |  |  |  |  | int | 
| 334 | 44 |  |  |  |  |  | tga_header_verify(unsigned char headbuf[18]) { | 
| 335 |  |  |  |  |  |  | tga_header header; | 
| 336 | 44 |  |  |  |  |  | tga_header_unpack(&header, headbuf); | 
| 337 | 44 |  |  |  |  |  | switch (header.datatypecode) { | 
| 338 |  |  |  |  |  |  | default: | 
| 339 |  |  |  |  |  |  | /*printf("bad typecode!\n");*/ | 
| 340 | 3 |  |  |  |  |  | return 0; | 
| 341 |  |  |  |  |  |  | case 1:  /* Uncompressed, color-mapped images */ | 
| 342 |  |  |  |  |  |  | case 3:  /* Uncompressed, grayscale images    */ | 
| 343 |  |  |  |  |  |  | case 9:  /* Compressed,   color-mapped images */ | 
| 344 |  |  |  |  |  |  | case 11: /* Compressed,   grayscale images    */ | 
| 345 | 17 | 50 |  |  |  |  | if (header.bitsperpixel != 8) | 
| 346 | 17 |  |  |  |  |  | return 0; | 
| 347 | 0 |  |  |  |  |  | break; | 
| 348 |  |  |  |  |  |  | case 0: | 
| 349 |  |  |  |  |  |  | case 2:  /* Uncompressed, rgb images          */ | 
| 350 |  |  |  |  |  |  | case 10: /* Compressed,   rgb images          */ | 
| 351 | 24 | 50 |  |  |  |  | if (header.bitsperpixel != 15 && header.bitsperpixel != 16 | 
|  |  | 100 |  |  |  |  |  | 
| 352 | 22 | 100 |  |  |  |  | && header.bitsperpixel != 24 && header.bitsperpixel != 32) | 
|  |  | 100 |  |  |  |  |  | 
| 353 | 6 |  |  |  |  |  | return 0; | 
| 354 | 18 |  |  |  |  |  | break; | 
| 355 |  |  |  |  |  |  | } | 
| 356 |  |  |  |  |  |  |  | 
| 357 | 18 |  |  |  |  |  | switch (header.colourmaptype) { | 
| 358 |  |  |  |  |  |  | default: | 
| 359 |  |  |  |  |  |  | /*printf("bad colourmaptype!\n");*/ | 
| 360 | 0 |  |  |  |  |  | return 0; | 
| 361 |  |  |  |  |  |  | case 1: | 
| 362 | 0 | 0 |  |  |  |  | if (header.datatypecode != 1 && header.datatypecode != 9) | 
|  |  | 0 |  |  |  |  |  | 
| 363 | 0 |  |  |  |  |  | return 0; /* only get a color map on a color mapped image */ | 
| 364 |  |  |  |  |  |  | case 0: | 
| 365 | 18 |  |  |  |  |  | break; | 
| 366 |  |  |  |  |  |  | } | 
| 367 |  |  |  |  |  |  |  | 
| 368 | 18 | 50 |  |  |  |  | switch (header.colourmapdepth) { | 
| 369 |  |  |  |  |  |  | default: | 
| 370 | 0 |  |  |  |  |  | return 0; | 
| 371 |  |  |  |  |  |  | case 0: /* can be 0 if no colour map */ | 
| 372 |  |  |  |  |  |  | case 15: | 
| 373 |  |  |  |  |  |  | case 16: | 
| 374 |  |  |  |  |  |  | case 24: | 
| 375 |  |  |  |  |  |  | case 32: | 
| 376 | 18 |  |  |  |  |  | break; | 
| 377 |  |  |  |  |  |  | } | 
| 378 |  |  |  |  |  |  |  | 
| 379 | 44 |  |  |  |  |  | return 1; | 
| 380 |  |  |  |  |  |  | } | 
| 381 |  |  |  |  |  |  |  | 
| 382 |  |  |  |  |  |  |  | 
| 383 |  |  |  |  |  |  | /* | 
| 384 |  |  |  |  |  |  | =item tga_header_pack(header, headbuf) | 
| 385 |  |  |  |  |  |  |  | 
| 386 |  |  |  |  |  |  | Packs header structure into buffer for writing. | 
| 387 |  |  |  |  |  |  |  | 
| 388 |  |  |  |  |  |  | header - header structure | 
| 389 |  |  |  |  |  |  | headbuf - buffer to pack into | 
| 390 |  |  |  |  |  |  |  | 
| 391 |  |  |  |  |  |  | =cut | 
| 392 |  |  |  |  |  |  | */ | 
| 393 |  |  |  |  |  |  |  | 
| 394 |  |  |  |  |  |  | static | 
| 395 |  |  |  |  |  |  | void | 
| 396 | 23 |  |  |  |  |  | tga_header_pack(tga_header *header, unsigned char headbuf[18]) { | 
| 397 | 23 |  |  |  |  |  | headbuf[0] = header->idlength; | 
| 398 | 23 |  |  |  |  |  | headbuf[1] = header->colourmaptype; | 
| 399 | 23 |  |  |  |  |  | headbuf[2] = header->datatypecode; | 
| 400 | 23 |  |  |  |  |  | headbuf[3] = header->colourmaporigin & 0xff; | 
| 401 | 23 |  |  |  |  |  | headbuf[4] = header->colourmaporigin >> 8; | 
| 402 | 23 |  |  |  |  |  | headbuf[5] = header->colourmaplength & 0xff; | 
| 403 | 23 |  |  |  |  |  | headbuf[6] = header->colourmaplength >> 8; | 
| 404 | 23 |  |  |  |  |  | headbuf[7] = header->colourmapdepth; | 
| 405 | 23 |  |  |  |  |  | headbuf[8] = header->x_origin & 0xff; | 
| 406 | 23 |  |  |  |  |  | headbuf[9] = header->x_origin >> 8; | 
| 407 | 23 |  |  |  |  |  | headbuf[10] = header->y_origin & 0xff; | 
| 408 | 23 |  |  |  |  |  | headbuf[11] = header->y_origin >> 8; | 
| 409 | 23 |  |  |  |  |  | headbuf[12] = header->width & 0xff; | 
| 410 | 23 |  |  |  |  |  | headbuf[13] = header->width >> 8; | 
| 411 | 23 |  |  |  |  |  | headbuf[14] = header->height & 0xff; | 
| 412 | 23 |  |  |  |  |  | headbuf[15] = header->height >> 8; | 
| 413 | 23 |  |  |  |  |  | headbuf[16] = header->bitsperpixel; | 
| 414 | 23 |  |  |  |  |  | headbuf[17] = header->imagedescriptor; | 
| 415 | 23 |  |  |  |  |  | } | 
| 416 |  |  |  |  |  |  |  | 
| 417 |  |  |  |  |  |  |  | 
| 418 |  |  |  |  |  |  | /* | 
| 419 |  |  |  |  |  |  | =item tga_source_read(s, buf, pixels) | 
| 420 |  |  |  |  |  |  |  | 
| 421 |  |  |  |  |  |  | Reads pixel number of pixels from source s into buffer buf.  Takes | 
| 422 |  |  |  |  |  |  | care of decompressing the stream if needed. | 
| 423 |  |  |  |  |  |  |  | 
| 424 |  |  |  |  |  |  | s - data source | 
| 425 |  |  |  |  |  |  | buf - destination buffer | 
| 426 |  |  |  |  |  |  | pixels - number of pixels to put into buffer | 
| 427 |  |  |  |  |  |  |  | 
| 428 |  |  |  |  |  |  | =cut | 
| 429 |  |  |  |  |  |  | */ | 
| 430 |  |  |  |  |  |  |  | 
| 431 |  |  |  |  |  |  | static | 
| 432 |  |  |  |  |  |  | int | 
| 433 | 108789 |  |  |  |  |  | tga_source_read(tga_source *s, unsigned char *buf, size_t pixels) { | 
| 434 | 108789 |  |  |  |  |  | int cp = 0, j, k; | 
| 435 | 108789 | 100 |  |  |  |  | if (!s->compressed) { | 
| 436 | 900 | 50 |  |  |  |  | if (i_io_read(s->ig, buf, pixels*s->bytepp) != pixels*s->bytepp) return 0; | 
| 437 | 900 |  |  |  |  |  | return 1; | 
| 438 |  |  |  |  |  |  | } | 
| 439 |  |  |  |  |  |  |  | 
| 440 | 371039 | 100 |  |  |  |  | while(cp < pixels) { | 
| 441 |  |  |  |  |  |  | int ml; | 
| 442 | 263150 | 100 |  |  |  |  | if (s->len == 0) s->state = NoInit; | 
| 443 | 263150 |  |  |  |  |  | switch (s->state) { | 
| 444 |  |  |  |  |  |  | case NoInit: | 
| 445 | 131575 | 50 |  |  |  |  | if (i_io_read(s->ig, &s->hdr, 1) != 1) return 0; | 
| 446 |  |  |  |  |  |  |  | 
| 447 | 131575 |  |  |  |  |  | s->len = (s->hdr &~(1<<7))+1; | 
| 448 | 131575 | 100 |  |  |  |  | s->state = (s->hdr & (1<<7)) ? Rle : Raw; | 
| 449 |  |  |  |  |  |  | { | 
| 450 |  |  |  |  |  |  | /* | 
| 451 |  |  |  |  |  |  | static cnt = 0; | 
| 452 |  |  |  |  |  |  | printf("%04d %s: %d\n", cnt++, s->state==Rle?"RLE":"RAW", s->len); | 
| 453 |  |  |  |  |  |  | */ | 
| 454 |  |  |  |  |  |  | } | 
| 455 | 131575 | 100 |  |  |  |  | if (s->state == Rle && i_io_read(s->ig, s->cval, s->bytepp) != s->bytepp) return 0; | 
|  |  | 50 |  |  |  |  |  | 
| 456 |  |  |  |  |  |  |  | 
| 457 | 131575 |  |  |  |  |  | break; | 
| 458 |  |  |  |  |  |  | case Rle: | 
| 459 | 21876 |  |  |  |  |  | ml = i_min(s->len, pixels-cp); | 
| 460 | 1113728 | 100 |  |  |  |  | for(k=0; kbytepp; j++) | 
|  |  | 100 |  |  |  |  |  | 
| 461 | 796713 |  |  |  |  |  | buf[(cp+k)*s->bytepp+j] = s->cval[j]; | 
| 462 | 21876 |  |  |  |  |  | cp     += ml; | 
| 463 | 21876 |  |  |  |  |  | s->len -= ml; | 
| 464 | 21876 |  |  |  |  |  | break; | 
| 465 |  |  |  |  |  |  | case Raw: | 
| 466 | 109699 |  |  |  |  |  | ml = i_min(s->len, pixels-cp); | 
| 467 | 109699 | 50 |  |  |  |  | if (i_io_read(s->ig, buf+cp*s->bytepp, ml*s->bytepp) != ml*s->bytepp) return 0; | 
| 468 | 109699 |  |  |  |  |  | cp     += ml; | 
| 469 | 109699 |  |  |  |  |  | s->len -= ml; | 
| 470 | 109699 |  |  |  |  |  | break; | 
| 471 |  |  |  |  |  |  | } | 
| 472 |  |  |  |  |  |  | } | 
| 473 | 107889 |  |  |  |  |  | return 1; | 
| 474 |  |  |  |  |  |  | } | 
| 475 |  |  |  |  |  |  |  | 
| 476 |  |  |  |  |  |  |  | 
| 477 |  |  |  |  |  |  |  | 
| 478 |  |  |  |  |  |  |  | 
| 479 |  |  |  |  |  |  | /* | 
| 480 |  |  |  |  |  |  | =item tga_dest_write(s, buf, pixels) | 
| 481 |  |  |  |  |  |  |  | 
| 482 |  |  |  |  |  |  | Writes pixels from buf to destination s.  Takes care of compressing if the | 
| 483 |  |  |  |  |  |  | destination is compressed. | 
| 484 |  |  |  |  |  |  |  | 
| 485 |  |  |  |  |  |  | s - data destination | 
| 486 |  |  |  |  |  |  | buf - source buffer | 
| 487 |  |  |  |  |  |  | pixels - number of pixels to put write to destination | 
| 488 |  |  |  |  |  |  |  | 
| 489 |  |  |  |  |  |  | =cut | 
| 490 |  |  |  |  |  |  | */ | 
| 491 |  |  |  |  |  |  |  | 
| 492 |  |  |  |  |  |  | static | 
| 493 |  |  |  |  |  |  | int | 
| 494 | 109067 |  |  |  |  |  | tga_dest_write(tga_dest *s, unsigned char *buf, size_t pixels) { | 
| 495 | 109067 |  |  |  |  |  | int cp = 0; | 
| 496 |  |  |  |  |  |  |  | 
| 497 | 109067 | 100 |  |  |  |  | if (!s->compressed) { | 
| 498 | 150 | 50 |  |  |  |  | if (i_io_write(s->ig, buf, pixels*s->bytepp) != pixels*s->bytepp) return 0; | 
| 499 | 150 |  |  |  |  |  | return 1; | 
| 500 |  |  |  |  |  |  | } | 
| 501 |  |  |  |  |  |  |  | 
| 502 | 134904 | 100 |  |  |  |  | while(cp < pixels) { | 
| 503 |  |  |  |  |  |  | int tlen; | 
| 504 | 132482 |  |  |  |  |  | int nxtrip = find_repeat(buf+cp*s->bytepp, pixels-cp, s->bytepp); | 
| 505 | 132482 | 100 |  |  |  |  | tlen = (nxtrip == -1) ? pixels-cp : nxtrip; | 
| 506 | 245801 | 100 |  |  |  |  | while(tlen) { | 
| 507 | 113319 |  |  |  |  |  | unsigned char clen = (tlen>128) ? 128 : tlen; | 
| 508 | 113319 |  |  |  |  |  | clen--; | 
| 509 | 113319 | 50 |  |  |  |  | if (i_io_write(s->ig, &clen, 1) != 1) return 0; | 
| 510 | 113319 |  |  |  |  |  | clen++; | 
| 511 | 113319 | 50 |  |  |  |  | if (i_io_write(s->ig, buf+cp*s->bytepp, clen*s->bytepp) != clen*s->bytepp) return 0; | 
| 512 | 113319 |  |  |  |  |  | tlen -= clen; | 
| 513 | 113319 |  |  |  |  |  | cp += clen; | 
| 514 |  |  |  |  |  |  | } | 
| 515 | 132482 | 100 |  |  |  |  | if (cp >= pixels) break; | 
| 516 | 25987 |  |  |  |  |  | tlen = find_span(buf+cp*s->bytepp, pixels-cp, s->bytepp); | 
| 517 | 25987 | 50 |  |  |  |  | if (tlen <3) continue; | 
| 518 | 52881 | 100 |  |  |  |  | while (tlen) { | 
| 519 | 26894 |  |  |  |  |  | unsigned char clen = (tlen>128) ? 128 : tlen; | 
| 520 | 26894 |  |  |  |  |  | clen = (clen - 1) | 0x80; | 
| 521 | 26894 | 50 |  |  |  |  | if (i_io_write(s->ig, &clen, 1) != 1) return 0; | 
| 522 | 26894 |  |  |  |  |  | clen = (clen & ~0x80) + 1; | 
| 523 | 26894 | 50 |  |  |  |  | if (i_io_write(s->ig, buf+cp*s->bytepp, s->bytepp) != s->bytepp) return 0; | 
| 524 | 26894 |  |  |  |  |  | tlen -= clen; | 
| 525 | 26894 |  |  |  |  |  | cp += clen; | 
| 526 |  |  |  |  |  |  | } | 
| 527 |  |  |  |  |  |  | } | 
| 528 | 108917 |  |  |  |  |  | return 1; | 
| 529 |  |  |  |  |  |  | } | 
| 530 |  |  |  |  |  |  |  | 
| 531 |  |  |  |  |  |  |  | 
| 532 |  |  |  |  |  |  |  | 
| 533 |  |  |  |  |  |  |  | 
| 534 |  |  |  |  |  |  |  | 
| 535 |  |  |  |  |  |  |  | 
| 536 |  |  |  |  |  |  | /* | 
| 537 |  |  |  |  |  |  | =item tga_palette_read(ig, img, bytepp, colourmaplength) | 
| 538 |  |  |  |  |  |  |  | 
| 539 |  |  |  |  |  |  | Reads the colormap from a tga file and stores in the paletted image | 
| 540 |  |  |  |  |  |  | structure. | 
| 541 |  |  |  |  |  |  |  | 
| 542 |  |  |  |  |  |  | ig - iolayer data source | 
| 543 |  |  |  |  |  |  | img - image structure | 
| 544 |  |  |  |  |  |  | bytepp - bytes per pixel | 
| 545 |  |  |  |  |  |  | colourmaplength - number of colours in colourmap | 
| 546 |  |  |  |  |  |  |  | 
| 547 |  |  |  |  |  |  | =cut | 
| 548 |  |  |  |  |  |  | */ | 
| 549 |  |  |  |  |  |  |  | 
| 550 |  |  |  |  |  |  | static | 
| 551 |  |  |  |  |  |  | int | 
| 552 | 4 |  |  |  |  |  | tga_palette_read(io_glue *ig, i_img *img, int bytepp, int colourmaplength) { | 
| 553 |  |  |  |  |  |  | int i; | 
| 554 |  |  |  |  |  |  | size_t palbsize; | 
| 555 |  |  |  |  |  |  | unsigned char *palbuf; | 
| 556 |  |  |  |  |  |  | i_color val; | 
| 557 |  |  |  |  |  |  |  | 
| 558 | 4 |  |  |  |  |  | palbsize = (size_t)colourmaplength * bytepp; | 
| 559 | 4 |  |  |  |  |  | palbuf   = mymalloc(palbsize); | 
| 560 |  |  |  |  |  |  |  | 
| 561 | 4 | 100 |  |  |  |  | if (i_io_read(ig, palbuf, palbsize) != palbsize) { | 
| 562 | 1 |  |  |  |  |  | myfree(palbuf); | 
| 563 | 1 |  |  |  |  |  | i_push_error(errno, "could not read targa colormap"); | 
| 564 | 1 |  |  |  |  |  | return 0; | 
| 565 |  |  |  |  |  |  | } | 
| 566 |  |  |  |  |  |  |  | 
| 567 |  |  |  |  |  |  | /* populate the palette of the new image */ | 
| 568 | 233 | 100 |  |  |  |  | for(i=0; i | 
| 569 | 230 |  |  |  |  |  | color_unpack(palbuf+i*bytepp, bytepp, &val); | 
| 570 | 230 | 50 |  |  |  |  | i_addcolors(img, &val, 1); | 
| 571 |  |  |  |  |  |  | } | 
| 572 | 3 |  |  |  |  |  | myfree(palbuf); | 
| 573 | 4 |  |  |  |  |  | return 1; | 
| 574 |  |  |  |  |  |  | } | 
| 575 |  |  |  |  |  |  |  | 
| 576 |  |  |  |  |  |  |  | 
| 577 |  |  |  |  |  |  | /* | 
| 578 |  |  |  |  |  |  | =item tga_palette_write(ig, img, bitspp, colourmaplength) | 
| 579 |  |  |  |  |  |  |  | 
| 580 |  |  |  |  |  |  | Stores the colormap of an image in the destination ig. | 
| 581 |  |  |  |  |  |  |  | 
| 582 |  |  |  |  |  |  | ig - iolayer data source | 
| 583 |  |  |  |  |  |  | img - image structure | 
| 584 |  |  |  |  |  |  | bitspp - bits per pixel in colourmap | 
| 585 |  |  |  |  |  |  | colourmaplength - number of colours in colourmap | 
| 586 |  |  |  |  |  |  |  | 
| 587 |  |  |  |  |  |  | =cut | 
| 588 |  |  |  |  |  |  | */ | 
| 589 |  |  |  |  |  |  |  | 
| 590 |  |  |  |  |  |  | static | 
| 591 |  |  |  |  |  |  | int | 
| 592 | 7 |  |  |  |  |  | tga_palette_write(io_glue *ig, i_img *img, int bitspp, int colourmaplength) { | 
| 593 |  |  |  |  |  |  | int i; | 
| 594 | 7 |  |  |  |  |  | size_t bytepp = bpp_to_bytes(bitspp); | 
| 595 | 7 | 50 |  |  |  |  | size_t palbsize = i_colorcount(img)*bytepp; | 
| 596 | 7 |  |  |  |  |  | unsigned char *palbuf = mymalloc(palbsize); | 
| 597 |  |  |  |  |  |  |  | 
| 598 | 1101 | 100 |  |  |  |  | for(i=0; i | 
| 599 |  |  |  |  |  |  | i_color val; | 
| 600 | 1094 | 50 |  |  |  |  | i_getcolors(img, i, &val, 1); | 
| 601 | 1094 |  |  |  |  |  | color_pack(palbuf+i*bytepp, bitspp, &val); | 
| 602 |  |  |  |  |  |  | } | 
| 603 |  |  |  |  |  |  |  | 
| 604 | 7 | 50 |  |  |  |  | if (i_io_write(ig, palbuf, palbsize) != palbsize) { | 
| 605 | 0 |  |  |  |  |  | i_push_error(errno, "could not write targa colormap"); | 
| 606 | 0 |  |  |  |  |  | return 0; | 
| 607 |  |  |  |  |  |  | } | 
| 608 | 7 |  |  |  |  |  | myfree(palbuf); | 
| 609 | 7 |  |  |  |  |  | return 1; | 
| 610 |  |  |  |  |  |  | } | 
| 611 |  |  |  |  |  |  |  | 
| 612 |  |  |  |  |  |  |  | 
| 613 |  |  |  |  |  |  |  | 
| 614 |  |  |  |  |  |  | /* | 
| 615 |  |  |  |  |  |  | =item i_readtga_wiol(ig, length) | 
| 616 |  |  |  |  |  |  |  | 
| 617 |  |  |  |  |  |  | Read in an image from the iolayer data source and return the image structure to it. | 
| 618 |  |  |  |  |  |  | Returns NULL on error. | 
| 619 |  |  |  |  |  |  |  | 
| 620 |  |  |  |  |  |  | ig     - io_glue object | 
| 621 |  |  |  |  |  |  | length - maximum length to read from data source, before closing it -1 | 
| 622 |  |  |  |  |  |  | signifies no limit. | 
| 623 |  |  |  |  |  |  |  | 
| 624 |  |  |  |  |  |  | =cut | 
| 625 |  |  |  |  |  |  | */ | 
| 626 |  |  |  |  |  |  |  | 
| 627 |  |  |  |  |  |  | i_img * | 
| 628 | 26 |  |  |  |  |  | i_readtga_wiol(io_glue *ig, int length) { | 
| 629 | 26 |  |  |  |  |  | i_img* img = NULL; | 
| 630 |  |  |  |  |  |  | int x, y; | 
| 631 |  |  |  |  |  |  | int width, height, channels; | 
| 632 |  |  |  |  |  |  | int mapped; | 
| 633 | 26 |  |  |  |  |  | char *idstring = NULL; | 
| 634 |  |  |  |  |  |  |  | 
| 635 |  |  |  |  |  |  | tga_source src; | 
| 636 |  |  |  |  |  |  | tga_header header; | 
| 637 |  |  |  |  |  |  | unsigned char headbuf[18]; | 
| 638 |  |  |  |  |  |  | unsigned char *databuf; | 
| 639 |  |  |  |  |  |  |  | 
| 640 | 26 |  |  |  |  |  | i_color *linebuf = NULL; | 
| 641 | 26 |  |  |  |  |  | i_clear_error(); | 
| 642 |  |  |  |  |  |  |  | 
| 643 | 26 |  |  |  |  |  | mm_log((1,"i_readtga(ig %p, length %d)\n", ig, length)); | 
| 644 |  |  |  |  |  |  |  | 
| 645 | 26 | 50 |  |  |  |  | if (i_io_read(ig, &headbuf, 18) != 18) { | 
| 646 | 0 |  |  |  |  |  | i_push_error(errno, "could not read targa header"); | 
| 647 | 0 |  |  |  |  |  | return NULL; | 
| 648 |  |  |  |  |  |  | } | 
| 649 |  |  |  |  |  |  |  | 
| 650 | 26 |  |  |  |  |  | tga_header_unpack(&header, headbuf); | 
| 651 |  |  |  |  |  |  |  | 
| 652 | 26 |  |  |  |  |  | mm_log((1,"Id length:         %d\n",header.idlength)); | 
| 653 | 26 |  |  |  |  |  | mm_log((1,"Colour map type:   %d\n",header.colourmaptype)); | 
| 654 | 26 |  |  |  |  |  | mm_log((1,"Image type:        %d\n",header.datatypecode)); | 
| 655 | 26 |  |  |  |  |  | mm_log((1,"Colour map offset: %d\n",header.colourmaporigin)); | 
| 656 | 26 |  |  |  |  |  | mm_log((1,"Colour map length: %d\n",header.colourmaplength)); | 
| 657 | 26 |  |  |  |  |  | mm_log((1,"Colour map depth:  %d\n",header.colourmapdepth)); | 
| 658 | 26 |  |  |  |  |  | mm_log((1,"X origin:          %d\n",header.x_origin)); | 
| 659 | 26 |  |  |  |  |  | mm_log((1,"Y origin:          %d\n",header.y_origin)); | 
| 660 | 26 |  |  |  |  |  | mm_log((1,"Width:             %d\n",header.width)); | 
| 661 | 26 |  |  |  |  |  | mm_log((1,"Height:            %d\n",header.height)); | 
| 662 | 26 |  |  |  |  |  | mm_log((1,"Bits per pixel:    %d\n",header.bitsperpixel)); | 
| 663 | 26 |  |  |  |  |  | mm_log((1,"Descriptor:        %d\n",header.imagedescriptor)); | 
| 664 |  |  |  |  |  |  |  | 
| 665 | 26 | 100 |  |  |  |  | if (header.idlength) { | 
| 666 |  |  |  |  |  |  | /* max of 256, so this is safe */ | 
| 667 | 3 |  |  |  |  |  | idstring = mymalloc(header.idlength+1); | 
| 668 | 3 | 50 |  |  |  |  | if (i_io_read(ig, idstring, header.idlength) != header.idlength) { | 
| 669 | 0 |  |  |  |  |  | i_push_error(errno, "short read on targa idstring"); | 
| 670 | 0 |  |  |  |  |  | return NULL; | 
| 671 |  |  |  |  |  |  | } | 
| 672 |  |  |  |  |  |  | } | 
| 673 |  |  |  |  |  |  |  | 
| 674 | 26 |  |  |  |  |  | width = header.width; | 
| 675 | 26 |  |  |  |  |  | height = header.height; | 
| 676 |  |  |  |  |  |  |  | 
| 677 |  |  |  |  |  |  |  | 
| 678 |  |  |  |  |  |  | /* Set tags here */ | 
| 679 |  |  |  |  |  |  |  | 
| 680 | 26 |  |  |  |  |  | switch (header.datatypecode) { | 
| 681 |  |  |  |  |  |  | case 0: /* No data in image */ | 
| 682 | 0 |  |  |  |  |  | i_push_error(0, "Targa image contains no image data"); | 
| 683 | 0 | 0 |  |  |  |  | if (idstring) myfree(idstring); | 
| 684 | 0 |  |  |  |  |  | return NULL; | 
| 685 |  |  |  |  |  |  | break; | 
| 686 |  |  |  |  |  |  | case 1:  /* Uncompressed, color-mapped images */ | 
| 687 |  |  |  |  |  |  | case 9:  /* Compressed,   color-mapped images */ | 
| 688 |  |  |  |  |  |  | case 3:  /* Uncompressed, grayscale images    */ | 
| 689 |  |  |  |  |  |  | case 11: /* Compressed,   grayscale images    */ | 
| 690 | 4 | 50 |  |  |  |  | if (header.bitsperpixel != 8) { | 
| 691 | 0 |  |  |  |  |  | i_push_error(0, "Targa: mapped/grayscale image's bpp is not 8, unsupported."); | 
| 692 | 0 | 0 |  |  |  |  | if (idstring) myfree(idstring); | 
| 693 | 0 |  |  |  |  |  | return NULL; | 
| 694 |  |  |  |  |  |  | } | 
| 695 | 4 |  |  |  |  |  | src.bytepp = 1; | 
| 696 | 4 |  |  |  |  |  | break; | 
| 697 |  |  |  |  |  |  | case 2:  /* Uncompressed, rgb images          */ | 
| 698 |  |  |  |  |  |  | case 10: /* Compressed,   rgb images          */ | 
| 699 | 22 | 50 |  |  |  |  | if ((src.bytepp = bpp_to_bytes(header.bitsperpixel))) | 
| 700 | 22 |  |  |  |  |  | break; | 
| 701 | 0 |  |  |  |  |  | i_push_error(0, "Targa: direct color image's bpp is not 15/16/24/32 - unsupported."); | 
| 702 | 0 | 0 |  |  |  |  | if (idstring) myfree(idstring); | 
| 703 | 0 |  |  |  |  |  | return NULL; | 
| 704 |  |  |  |  |  |  | break; | 
| 705 |  |  |  |  |  |  | case 32: /* Compressed color-mapped, Huffman, Delta and runlength */ | 
| 706 |  |  |  |  |  |  | case 33: /* Compressed color-mapped, Huffman, Delta and runlength */ | 
| 707 | 0 |  |  |  |  |  | i_push_error(0, "Unsupported Targa (Huffman/delta/rle/quadtree) subformat is not supported"); | 
| 708 | 0 | 0 |  |  |  |  | if (idstring) myfree(idstring); | 
| 709 | 0 |  |  |  |  |  | return NULL; | 
| 710 |  |  |  |  |  |  | break; | 
| 711 |  |  |  |  |  |  | default: /* All others which we don't know which might be */ | 
| 712 | 0 |  |  |  |  |  | i_push_error(0, "Unknown targa format"); | 
| 713 | 0 | 0 |  |  |  |  | if (idstring) myfree(idstring); | 
| 714 | 0 |  |  |  |  |  | return NULL; | 
| 715 |  |  |  |  |  |  | break; | 
| 716 |  |  |  |  |  |  | } | 
| 717 |  |  |  |  |  |  |  | 
| 718 | 26 |  |  |  |  |  | src.state = NoInit; | 
| 719 | 26 |  |  |  |  |  | src.len = 0; | 
| 720 | 26 |  |  |  |  |  | src.ig = ig; | 
| 721 | 26 |  |  |  |  |  | src.compressed = !!(header.datatypecode & (1<<3)); | 
| 722 |  |  |  |  |  |  |  | 
| 723 |  |  |  |  |  |  | /* Determine number of channels */ | 
| 724 |  |  |  |  |  |  |  | 
| 725 | 26 |  |  |  |  |  | mapped = 1; | 
| 726 | 26 |  |  |  |  |  | switch (header.datatypecode) { | 
| 727 |  |  |  |  |  |  | case 2:  /* Uncompressed, rgb images          */ /* FALLTHROUGH */ | 
| 728 |  |  |  |  |  |  | case 10: /* Compressed,   rgb images          */ /* FALLTHROUGH */ | 
| 729 | 22 |  |  |  |  |  | mapped = 0; | 
| 730 |  |  |  |  |  |  | case 1:  /* Uncompressed, color-mapped images */ | 
| 731 |  |  |  |  |  |  | case 9:  /* Compressed,   color-mapped images */ | 
| 732 | 26 | 100 |  |  |  |  | if ((channels = bpp_to_channels(mapped ? | 
|  |  | 50 |  |  |  |  |  | 
| 733 | 4 |  |  |  |  |  | header.colourmapdepth : | 
| 734 | 22 |  |  |  |  |  | header.bitsperpixel, | 
| 735 | 26 |  |  |  |  |  | header.imagedescriptor & 0xF))) break; | 
| 736 | 0 |  |  |  |  |  | i_push_error(0, "Targa Image has none of 15/16/24/32 pixel layout"); | 
| 737 | 0 | 0 |  |  |  |  | if (idstring) myfree(idstring); | 
| 738 | 0 |  |  |  |  |  | return NULL; | 
| 739 |  |  |  |  |  |  | break; | 
| 740 |  |  |  |  |  |  | case 3:  /* Uncompressed, grayscale images    */ /* FALLTHROUGH */ | 
| 741 |  |  |  |  |  |  | case 11: /* Compressed,   grayscale images    */ | 
| 742 | 0 |  |  |  |  |  | mapped = 0; | 
| 743 | 0 |  |  |  |  |  | channels = 1; | 
| 744 | 0 |  |  |  |  |  | break; | 
| 745 |  |  |  |  |  |  | default: | 
| 746 | 0 |  |  |  |  |  | i_push_error(0, "invalid or unsupported datatype code"); | 
| 747 | 0 |  |  |  |  |  | return NULL; | 
| 748 |  |  |  |  |  |  | } | 
| 749 |  |  |  |  |  |  |  | 
| 750 | 26 | 100 |  |  |  |  | if (!i_int_check_image_file_limits(width, height, channels, | 
| 751 |  |  |  |  |  |  | sizeof(i_sample_t))) { | 
| 752 | 3 |  |  |  |  |  | mm_log((1, "i_readtga_wiol: image size exceeds limits\n")); | 
| 753 | 3 |  |  |  |  |  | return NULL; | 
| 754 |  |  |  |  |  |  | } | 
| 755 |  |  |  |  |  |  |  | 
| 756 | 23 |  |  |  |  |  | img = mapped ? | 
| 757 | 42 | 100 |  |  |  |  | i_img_pal_new(width, height, channels, 256) : | 
| 758 | 19 |  |  |  |  |  | i_img_empty_ch(NULL, width, height, channels); | 
| 759 |  |  |  |  |  |  |  | 
| 760 | 23 | 50 |  |  |  |  | if (!img) { | 
| 761 | 0 | 0 |  |  |  |  | if (idstring) | 
| 762 | 0 |  |  |  |  |  | myfree(idstring); | 
| 763 | 0 |  |  |  |  |  | return NULL; | 
| 764 |  |  |  |  |  |  | } | 
| 765 |  |  |  |  |  |  |  | 
| 766 | 23 | 100 |  |  |  |  | if (idstring) { | 
| 767 | 3 |  |  |  |  |  | i_tags_add(&img->tags, "tga_idstring", 0, idstring, header.idlength, 0); | 
| 768 | 3 |  |  |  |  |  | myfree(idstring); | 
| 769 |  |  |  |  |  |  | } | 
| 770 |  |  |  |  |  |  |  | 
| 771 | 27 |  |  |  |  |  | if (mapped && | 
| 772 | 4 |  |  |  |  |  | !tga_palette_read(ig, | 
| 773 |  |  |  |  |  |  | img, | 
| 774 | 4 |  |  |  |  |  | bpp_to_bytes(header.colourmapdepth), | 
| 775 | 4 |  |  |  |  |  | header.colourmaplength) | 
| 776 |  |  |  |  |  |  | ) { | 
| 777 |  |  |  |  |  |  | /* tga_palette_read() sets a message */ | 
| 778 | 1 | 50 |  |  |  |  | if (img) i_img_destroy(img); | 
| 779 | 1 |  |  |  |  |  | return NULL; | 
| 780 |  |  |  |  |  |  | } | 
| 781 |  |  |  |  |  |  |  | 
| 782 |  |  |  |  |  |  | /* Allocate buffers */ | 
| 783 |  |  |  |  |  |  | /* width is max 0xffff, src.bytepp is max 4, so this is safe */ | 
| 784 | 22 |  |  |  |  |  | databuf = mymalloc(width*src.bytepp); | 
| 785 |  |  |  |  |  |  | /* similarly here */ | 
| 786 | 22 | 100 |  |  |  |  | if (!mapped) linebuf = mymalloc(width*sizeof(i_color)); | 
| 787 |  |  |  |  |  |  |  | 
| 788 | 108811 | 100 |  |  |  |  | for(y=0; y | 
| 789 | 108789 | 50 |  |  |  |  | if (!tga_source_read(&src, databuf, width)) { | 
| 790 | 0 |  |  |  |  |  | i_push_error(errno, "read for targa data failed"); | 
| 791 | 0 | 0 |  |  |  |  | if (linebuf) myfree(linebuf); | 
| 792 | 0 |  |  |  |  |  | myfree(databuf); | 
| 793 | 0 | 0 |  |  |  |  | if (img) i_img_destroy(img); | 
| 794 | 0 |  |  |  |  |  | return NULL; | 
| 795 |  |  |  |  |  |  | } | 
| 796 | 108789 | 100 |  |  |  |  | if (mapped && header.colourmaporigin) for(x=0; x | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 797 | 108789 | 100 |  |  |  |  | if (mapped) i_ppal(img, 0, width, header.imagedescriptor & (1<<5) ? y : height-1-y, databuf); | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 798 |  |  |  |  |  |  | else { | 
| 799 | 592133 | 100 |  |  |  |  | for(x=0; x | 
| 800 | 108339 | 50 |  |  |  |  | i_plin(img, 0, width, header.imagedescriptor & (1<<5) ? y : height-1-y, linebuf); | 
| 801 |  |  |  |  |  |  | } | 
| 802 |  |  |  |  |  |  | } | 
| 803 | 22 |  |  |  |  |  | myfree(databuf); | 
| 804 | 22 | 100 |  |  |  |  | if (linebuf) myfree(linebuf); | 
| 805 |  |  |  |  |  |  |  | 
| 806 | 22 |  |  |  |  |  | i_tags_add(&img->tags, "i_format", 0, "tga", -1, 0); | 
| 807 | 22 | 100 |  |  |  |  | i_tags_addn(&img->tags, "tga_bitspp", 0, mapped?header.colourmapdepth:header.bitsperpixel); | 
| 808 | 22 | 100 |  |  |  |  | if (src.compressed) i_tags_addn(&img->tags, "compressed", 0, 1); | 
| 809 | 26 |  |  |  |  |  | return img; | 
| 810 |  |  |  |  |  |  | } | 
| 811 |  |  |  |  |  |  |  | 
| 812 |  |  |  |  |  |  |  | 
| 813 |  |  |  |  |  |  |  | 
| 814 |  |  |  |  |  |  | /* | 
| 815 |  |  |  |  |  |  | =item i_writetga_wiol(img, ig) | 
| 816 |  |  |  |  |  |  |  | 
| 817 |  |  |  |  |  |  | Writes an image in targa format.  Returns 0 on error. | 
| 818 |  |  |  |  |  |  |  | 
| 819 |  |  |  |  |  |  | img    - image to store | 
| 820 |  |  |  |  |  |  | ig     - io_glue object | 
| 821 |  |  |  |  |  |  |  | 
| 822 |  |  |  |  |  |  | =cut | 
| 823 |  |  |  |  |  |  | */ | 
| 824 |  |  |  |  |  |  |  | 
| 825 |  |  |  |  |  |  | undef_int | 
| 826 | 26 |  |  |  |  |  | i_writetga_wiol(i_img *img, io_glue *ig, int wierdpack, int compress, char *idstring, size_t idlen) { | 
| 827 |  |  |  |  |  |  | tga_header header; | 
| 828 |  |  |  |  |  |  | tga_dest dest; | 
| 829 |  |  |  |  |  |  | unsigned char headbuf[18]; | 
| 830 |  |  |  |  |  |  | unsigned int bitspp; | 
| 831 | 26 |  |  |  |  |  | unsigned int attr_bits = 0; | 
| 832 |  |  |  |  |  |  |  | 
| 833 |  |  |  |  |  |  | int mapped; | 
| 834 |  |  |  |  |  |  |  | 
| 835 |  |  |  |  |  |  | /* parameters */ | 
| 836 |  |  |  |  |  |  |  | 
| 837 |  |  |  |  |  |  | /* | 
| 838 |  |  |  |  |  |  | int compress = 1; | 
| 839 |  |  |  |  |  |  | char *idstring = "testing"; | 
| 840 |  |  |  |  |  |  | int wierdpack = 0; | 
| 841 |  |  |  |  |  |  | */ | 
| 842 |  |  |  |  |  |  |  | 
| 843 | 26 |  |  |  |  |  | idlen = strlen(idstring); | 
| 844 | 26 |  |  |  |  |  | mapped = img->type == i_palette_type; | 
| 845 |  |  |  |  |  |  |  | 
| 846 | 26 |  |  |  |  |  | mm_log((1,"i_writetga_wiol(img %p, ig %p, idstring %p, idlen %ld, wierdpack %d, compress %d)\n", | 
| 847 |  |  |  |  |  |  | img, ig, idstring, (long)idlen, wierdpack, compress)); | 
| 848 | 26 |  |  |  |  |  | mm_log((1, "virtual %d, paletted %d\n", i_img_virtual(img), mapped)); | 
| 849 | 26 |  |  |  |  |  | mm_log((1, "channels %d\n", img->channels)); | 
| 850 |  |  |  |  |  |  |  | 
| 851 | 26 |  |  |  |  |  | i_clear_error(); | 
| 852 |  |  |  |  |  |  |  | 
| 853 | 26 | 100 |  |  |  |  | if (img->xsize > TGA_MAX_DIM || img->ysize > TGA_MAX_DIM) { | 
|  |  | 100 |  |  |  |  |  | 
| 854 | 2 |  |  |  |  |  | i_push_error(0, "image too large for TGA"); | 
| 855 | 2 |  |  |  |  |  | return 0; | 
| 856 |  |  |  |  |  |  | } | 
| 857 |  |  |  |  |  |  |  | 
| 858 | 24 |  |  |  |  |  | switch (img->channels) { | 
| 859 |  |  |  |  |  |  | case 1: | 
| 860 | 0 |  |  |  |  |  | bitspp = 8; | 
| 861 | 0 | 0 |  |  |  |  | if (wierdpack) { | 
| 862 | 0 |  |  |  |  |  | mm_log((1,"wierdpack option ignored for 1 channel images\n")); | 
| 863 | 0 |  |  |  |  |  | wierdpack=0; | 
| 864 |  |  |  |  |  |  | } | 
| 865 | 0 |  |  |  |  |  | break; | 
| 866 |  |  |  |  |  |  | case 2: | 
| 867 | 1 |  |  |  |  |  | i_push_error(0, "Cannot store 2 channel image in targa format"); | 
| 868 | 1 |  |  |  |  |  | return 0; | 
| 869 |  |  |  |  |  |  | break; | 
| 870 |  |  |  |  |  |  | case 3: | 
| 871 | 22 | 100 |  |  |  |  | bitspp = wierdpack ? 15 : 24; | 
| 872 | 22 |  |  |  |  |  | break; | 
| 873 |  |  |  |  |  |  | case 4: | 
| 874 | 1 | 50 |  |  |  |  | bitspp = wierdpack ? 16 : 32; | 
| 875 | 1 | 50 |  |  |  |  | attr_bits = wierdpack ? 1 : 8; | 
| 876 | 1 |  |  |  |  |  | break; | 
| 877 |  |  |  |  |  |  | default: | 
| 878 | 0 |  |  |  |  |  | i_push_error(0, "Targa only handles 1,3 and 4 channel images."); | 
| 879 | 0 |  |  |  |  |  | return 0; | 
| 880 |  |  |  |  |  |  | } | 
| 881 |  |  |  |  |  |  |  | 
| 882 | 23 |  |  |  |  |  | header.idlength = idlen; | 
| 883 | 23 |  |  |  |  |  | header.colourmaptype   = mapped ? 1 : 0; | 
| 884 | 23 | 100 |  |  |  |  | header.datatypecode    = mapped ? 1 : img->channels == 1 ? 3 : 2; | 
|  |  | 50 |  |  |  |  |  | 
| 885 | 23 | 100 |  |  |  |  | header.datatypecode   += compress ? 8 : 0; | 
| 886 | 23 |  |  |  |  |  | mm_log((1, "datatypecode %d\n", header.datatypecode)); | 
| 887 | 23 |  |  |  |  |  | header.colourmaporigin = 0; | 
| 888 | 23 | 100 |  |  |  |  | header.colourmaplength = mapped ? i_colorcount(img) : 0; | 
|  |  | 50 |  |  |  |  |  | 
| 889 | 23 | 100 |  |  |  |  | header.colourmapdepth  = mapped ? bitspp : 0; | 
| 890 | 23 |  |  |  |  |  | header.x_origin        = 0; | 
| 891 | 23 |  |  |  |  |  | header.y_origin        = 0; | 
| 892 | 23 |  |  |  |  |  | header.width           = img->xsize; | 
| 893 | 23 |  |  |  |  |  | header.height          = img->ysize; | 
| 894 | 23 | 100 |  |  |  |  | header.bitsperpixel    = mapped ? 8 : bitspp; | 
| 895 | 23 |  |  |  |  |  | header.imagedescriptor = (1<<5) | attr_bits; /* normal order instead of upside down */ | 
| 896 |  |  |  |  |  |  |  | 
| 897 | 23 |  |  |  |  |  | tga_header_pack(&header, headbuf); | 
| 898 |  |  |  |  |  |  |  | 
| 899 | 23 | 50 |  |  |  |  | if (i_io_write(ig, &headbuf, sizeof(headbuf)) != sizeof(headbuf)) { | 
| 900 | 0 |  |  |  |  |  | i_push_error(errno, "could not write targa header"); | 
| 901 | 0 |  |  |  |  |  | return 0; | 
| 902 |  |  |  |  |  |  | } | 
| 903 |  |  |  |  |  |  |  | 
| 904 | 23 | 100 |  |  |  |  | if (idlen) { | 
| 905 | 2 | 50 |  |  |  |  | if (i_io_write(ig, idstring, idlen) != idlen) { | 
| 906 | 0 |  |  |  |  |  | i_push_error(errno, "could not write targa idstring"); | 
| 907 | 0 |  |  |  |  |  | return 0; | 
| 908 |  |  |  |  |  |  | } | 
| 909 |  |  |  |  |  |  | } | 
| 910 |  |  |  |  |  |  |  | 
| 911 |  |  |  |  |  |  | /* Make this into a constructor? */ | 
| 912 | 23 |  |  |  |  |  | dest.compressed = compress; | 
| 913 | 23 | 100 |  |  |  |  | dest.bytepp     = mapped ? 1 : bpp_to_bytes(bitspp); | 
| 914 | 23 |  |  |  |  |  | dest.ig         = ig; | 
| 915 |  |  |  |  |  |  |  | 
| 916 | 23 |  |  |  |  |  | mm_log((1, "dest.compressed = %d\n", dest.compressed)); | 
| 917 | 23 |  |  |  |  |  | mm_log((1, "dest.bytepp = %d\n", dest.bytepp)); | 
| 918 |  |  |  |  |  |  |  | 
| 919 | 23 | 100 |  |  |  |  | if (img->type == i_palette_type) { | 
| 920 | 7 | 50 |  |  |  |  | if (!tga_palette_write(ig, img, bitspp, i_colorcount(img))) return 0; | 
|  |  | 50 |  |  |  |  |  | 
| 921 |  |  |  |  |  |  |  | 
| 922 | 7 | 50 |  |  |  |  | if (!i_img_virtual(img) && !dest.compressed) { | 
|  |  | 100 |  |  |  |  |  | 
| 923 | 2 | 50 |  |  |  |  | if (i_io_write(ig, img->idata, img->bytes) != img->bytes) { | 
| 924 | 0 |  |  |  |  |  | i_push_error(errno, "could not write targa image data"); | 
| 925 | 0 |  |  |  |  |  | return 0; | 
| 926 |  |  |  |  |  |  | } | 
| 927 |  |  |  |  |  |  | } else { | 
| 928 |  |  |  |  |  |  | int y; | 
| 929 | 5 |  |  |  |  |  | i_palidx *vals = mymalloc(sizeof(i_palidx)*img->xsize); | 
| 930 | 755 | 100 |  |  |  |  | for(y=0; yysize; y++) { | 
| 931 | 750 | 50 |  |  |  |  | i_gpal(img, 0, img->xsize, y, vals); | 
| 932 | 750 |  |  |  |  |  | tga_dest_write(&dest, vals, img->xsize); | 
| 933 |  |  |  |  |  |  | } | 
| 934 | 7 |  |  |  |  |  | myfree(vals); | 
| 935 |  |  |  |  |  |  | } | 
| 936 |  |  |  |  |  |  | } else { /* direct type */ | 
| 937 |  |  |  |  |  |  | int x, y; | 
| 938 | 16 | 100 |  |  |  |  | size_t bytepp = wierdpack ? 2 : bpp_to_bytes(bitspp); | 
| 939 | 16 |  |  |  |  |  | size_t lsize = bytepp * img->xsize; | 
| 940 | 16 |  |  |  |  |  | i_color *vals = mymalloc(img->xsize*sizeof(i_color)); | 
| 941 | 16 |  |  |  |  |  | unsigned char *buf = mymalloc(lsize); | 
| 942 |  |  |  |  |  |  |  | 
| 943 | 108333 | 100 |  |  |  |  | for(y=0; yysize; y++) { | 
| 944 | 108317 |  |  |  |  |  | i_glin(img, 0, img->xsize, y, vals); | 
| 945 | 604307 | 100 |  |  |  |  | for(x=0; xxsize; x++) color_pack(buf+x*bytepp, bitspp, vals+x); | 
| 946 | 108317 |  |  |  |  |  | tga_dest_write(&dest, buf, img->xsize); | 
| 947 |  |  |  |  |  |  | } | 
| 948 | 16 |  |  |  |  |  | myfree(buf); | 
| 949 | 16 |  |  |  |  |  | myfree(vals); | 
| 950 |  |  |  |  |  |  | } | 
| 951 |  |  |  |  |  |  |  | 
| 952 | 23 | 100 |  |  |  |  | if (i_io_close(ig)) | 
| 953 | 1 |  |  |  |  |  | return 0; | 
| 954 |  |  |  |  |  |  |  | 
| 955 | 26 |  |  |  |  |  | return 1; | 
| 956 |  |  |  |  |  |  | } | 
| 957 |  |  |  |  |  |  |  | 
| 958 |  |  |  |  |  |  | /* | 
| 959 |  |  |  |  |  |  | =back | 
| 960 |  |  |  |  |  |  |  | 
| 961 |  |  |  |  |  |  | =head1 AUTHOR | 
| 962 |  |  |  |  |  |  |  | 
| 963 |  |  |  |  |  |  | Arnar M. Hrafnkelsson | 
| 964 |  |  |  |  |  |  |  | 
| 965 |  |  |  |  |  |  | =head1 SEE ALSO | 
| 966 |  |  |  |  |  |  |  | 
| 967 |  |  |  |  |  |  | Imager(3) | 
| 968 |  |  |  |  |  |  |  | 
| 969 |  |  |  |  |  |  | =cut | 
| 970 |  |  |  |  |  |  | */ |