A very small library for reading image files
at main 51 kB view raw
1#include "img.h" 2#include <stdlib.h> 3 4static ImgStatus determineFormat(Img *img); 5static ImgStatus openQoi(Img *img); 6static ImgStatus readQoi(Img *img, ImgAny buf, ImgSz bufSz); 7static ImgStatus openPbm(Img *img); 8static ImgStatus readPbm(Img *img, ImgAny buf, ImgSz bufSz); 9static ImgStatus openBmp(Img *img); 10static ImgStatus readBmp(Img *img, ImgAny buf, ImgSz bufSz); 11static ImgStatus openTga(Img *img); 12static ImgStatus readTga(Img *img, ImgAny buf, ImgSz bufSz); 13static ImgStatus openGif(Img *img); 14static ImgStatus readGif(Img *img, ImgAny buf, ImgSz bufSz); 15 16ImgStatus imgOpen(Img *img, const ImgFuncs *funcs) 17{ 18 img->funcs = *funcs; 19 ImgStatus status = determineFormat(img); 20 if(status != ImgOK) { return status; } 21 switch(img->format) { 22 case ImgFormatUnknown: 23 return ImgErrUnknownFormat; 24 case ImgFormatQoi: 25 return openQoi(img); 26 case ImgFormatPbm: 27 return openPbm(img); 28 case ImgFormatBmp: 29 return openBmp(img); 30 case ImgFormatTga: 31 return openTga(img); 32 case ImgFormatGif: 33 return openGif(img); 34 } 35} 36 37ImgStatus imgRead(Img *img, ImgAny buf, ImgSz bufSz) 38{ 39 if(img->width == 0 || img->height == 0 || img->channelCount == 0) { 40 return ImgErrUnopened; 41 } 42 switch(img->format) { 43 case ImgFormatUnknown: 44 return ImgErrUnknownFormat; 45 case ImgFormatQoi: 46 return readQoi(img, buf, bufSz); 47 case ImgFormatPbm: 48 return readPbm(img, buf, bufSz); 49 case ImgFormatBmp: 50 return readBmp(img, buf, bufSz); 51 case ImgFormatTga: 52 return readTga(img, buf, bufSz); 53 case ImgFormatGif: 54 return readGif(img, buf, bufSz); 55 } 56} 57 58ImgStatus imgClose(Img *img) 59{ 60 img->format = ImgFormatUnknown; 61 img->width = 0; 62 img->height = 0; 63 img->channelCount = 0; 64 if(img->funcs.close) { 65 return img->funcs.close(img->funcs.user); 66 } 67 return ImgOK; 68} 69 70const char *imgFormatName(ImgFormat format) 71{ 72 switch(format) { 73 case ImgFormatUnknown: 74 return "Unknown"; 75 case ImgFormatQoi: 76 return "QOI"; 77 case ImgFormatPbm: 78 return "PBM"; 79 case ImgFormatBmp: 80 return "BMP"; 81 case ImgFormatTga: 82 return "TGA"; 83 case ImgFormatGif: 84 return "GIF"; 85 } 86} 87 88const char *imgStatusMessage(ImgStatus status) 89{ 90 switch(status) { 91 case ImgOK: 92 return "OK"; 93 case ImgErrUnimplemented: 94 return "Unimplemented"; 95 case ImgErrIO: 96 return "I/O error"; 97 case ImgErrUnknownFormat: 98 return "Unknown image format"; 99 case ImgErrUnopened: 100 return "No image opened"; 101 case ImgErrBufferTooSmall: 102 return "Buffer to small to decode into"; 103 case ImgErrQoiInvalidChannelCount: 104 return "QOI: Invalid channel count"; 105 case ImgErrQoiInvalidColorSpace: 106 return "QOI: Invalid color space"; 107 case ImgErrPbmValueTooLarge: 108 return "PBM: Value too large"; 109 case ImgErrPbmInvalidInteger: 110 return "PBM: Invalid integer"; 111 case ImgErrBmpMalformedHeader: 112 return "BMP: Malformed header"; 113 case ImgErrBmpUnsupportedVariant: 114 return "BMP: Unsupported BMP variant"; 115 case ImgErrBmpPlaneCount: 116 return "BMP: Invalid plane count"; 117 case ImgErrBmpUnsupportedCompression: 118 return "BMP: Unsupported compression mode"; 119 case ImgErrBmpUnsupportedBitDepth: 120 return "BMP: Unsupported bit depth"; 121 case ImgErrBmpUnexpectedEndOfBitmap: 122 return "BMP: Unexpected end of bitmap in compressed data"; 123 case ImgErrTgaMissingColorMap: 124 return "TGA: Missing color map"; 125 case ImgErrTgaColorMapTooLong: 126 return "TGA: Color map too long (>256 colors)"; 127 case ImgErrTgaNoImageData: 128 return "TGA: Attempt to decode an image not containing image data"; 129 case ImgErrTgaUnsupportedPixelDepth: 130 return "TGA: Unsupported pixel depth"; 131 case ImgErrGifExpectedImageDescriptor: 132 return "GIF: Expected Image Descriptor"; 133 case ImgErrGifExpectedTrailer: 134 return "GIF: Expected trailer"; 135 } 136} 137 138static ImgStatus read(Img *img, ImgAny buf, ImgSz bufSz) 139{ 140 return img->funcs.read(img->funcs.user, buf, bufSz); 141} 142 143static ImgStatus readU16LE(Img *img, ImgU16 *out) 144{ 145 ImgStatus status = img->funcs.read(img->funcs.user, out, 2); 146 if(status != ImgOK) { return status; } 147 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 148 *out = __builtin_bswap16(*out); 149 #endif 150 return ImgOK; 151} 152 153static ImgStatus readU16BE(Img *img, ImgU16 *out) 154{ 155 ImgStatus status = img->funcs.read(img->funcs.user, out, 2); 156 if(status != ImgOK) { return status; } 157 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 158 *out = __builtin_bswap16(*out); 159 #endif 160 return ImgOK; 161} 162 163static ImgStatus readU24LE(Img *img, ImgU32 *out) 164{ 165 ImgU8 bytes[3]; 166 ImgStatus status = img->funcs.read(img->funcs.user, bytes, 3); 167 if(status != ImgOK) { return status; } 168 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 169 *out = ((ImgU32)bytes[2] << 16) | ((ImgU32)bytes[1] << 8) | (ImgU32)bytes[0]; 170 #else 171 *out = ((ImgU32)bytes[0] << 16) | ((ImgU32)bytes[1] << 8) | (ImgU32)bytes[2]; 172 #endif 173 return ImgOK; 174} 175 176static ImgStatus readU32LE(Img *img, ImgU32 *out) 177{ 178 ImgStatus status = img->funcs.read(img->funcs.user, out, 4); 179 if(status != ImgOK) { return status; } 180 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 181 *out = __builtin_bswap32(*out); 182 #endif 183 return ImgOK; 184} 185 186static ImgStatus readU32BE(Img *img, ImgU32 *out) 187{ 188 ImgStatus status = img->funcs.read(img->funcs.user, out, 4); 189 if(status != ImgOK) { return status; } 190 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 191 *out = __builtin_bswap32(*out); 192 #endif 193 return ImgOK; 194} 195 196static ImgStatus readS32LE(Img *img, ImgS32 *out) 197{ 198 ImgStatus status = img->funcs.read(img->funcs.user, out, 4); 199 if(status != ImgOK) { return status; } 200 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 201 *out = __builtin_bswap32(*out); 202 #endif 203 return ImgOK; 204} 205 206static ImgStatus seek(Img *img, ImgOff off) 207{ 208 return img->funcs.seek(img->funcs.user, off); 209} 210 211static ImgStatus determineTga(Img *img); 212 213static ImgStatus determineFormat(Img *img) 214{ 215 ImgStatus status; 216 char magic[8]; 217 218 status = read(img, magic, 2); 219 if(status != ImgOK) { return status; } 220 status = seek(img, -2); 221 if(status != ImgOK) { return status; } 222 223 if(magic[0] == 'P' && magic[1] >= '1' && magic[1] <= '6') { 224 img->format = ImgFormatPbm; 225 return ImgOK; 226 } 227 if(magic[0] == 'B' && magic[1] == 'M') { 228 img->format = ImgFormatBmp; 229 return ImgOK; 230 } 231 232 status = read(img, magic, 4); 233 if(status != ImgOK) { return status; } 234 status = seek(img, -4); 235 if(status != ImgOK) { return status; } 236 237 if(magic[0] == 'q' && magic[1] == 'o' && magic[2] == 'i' && magic[3] == 'f') { 238 img->format = ImgFormatQoi; 239 return ImgOK; 240 } 241 242 status = read(img, magic, 6); 243 if(status != ImgOK) { return status; } 244 status = seek(img, -6); 245 if(status != ImgOK) { return status; } 246 247 if(magic[0] == 'G' && magic[1] == 'I' && magic[2] == 'F' 248 && magic[3] == '8' && (magic[4] == '7' || magic[4] == '9') && magic[5] == 'a') { 249 img->format = ImgFormatGif; 250 return ImgOK; 251 } 252 253 status = determineTga(img); 254 if(status != ImgOK) { return status; } 255 256 if(img->format == ImgFormatUnknown) { 257 return ImgErrUnknownFormat; 258 } 259 return ImgOK; 260} 261 262struct RGBA { 263 ImgU8 r; 264 ImgU8 g; 265 ImgU8 b; 266 ImgU8 a; 267}; 268 269ImgStatus openQoi(Img *img) 270{ 271 ImgStatus status = seek(img, 4); 272 if(status != ImgOK) { return status; } 273 status = readU32BE(img, &img->width); 274 if(status != ImgOK) { return status; } 275 status = readU32BE(img, &img->height); 276 if(status != ImgOK) { return status; } 277 status = read(img, &img->channelCount, 1); 278 if(status != ImgOK) { return status; } 279 status = read(img, &img->qoi.colorSpace, 1); 280 if(status != ImgOK) { return status; } 281 282 if(img->channelCount != 3 && img->channelCount != 4) { 283 return ImgErrQoiInvalidChannelCount; 284 } 285 if(img->qoi.colorSpace != 0 && img->qoi.colorSpace != 1) { 286 return ImgErrQoiInvalidColorSpace; 287 } 288 289 return ImgOK; 290} 291 292static ImgU32 qoiIndex(struct RGBA color) { 293 return (color.r * 3 + color.g * 5 + color.b * 7 + color.a * 11) % 64; 294} 295 296/* FIXME: doesn't decode 4-chanel images correctly */ 297ImgStatus readQoi(Img *img, ImgAny buf, ImgSz bufSz) 298{ 299 ImgSz expectedSize = (ImgSz)img->width * img->height * img->channelCount; 300 if(bufSz < expectedSize) { 301 return ImgErrBufferTooSmall; 302 } 303 304 struct RGBA memory[64]; 305 for(ImgSz i = 0; i < 64; ++i) { 306 memory[i].r = 0; 307 memory[i].g = 0; 308 memory[i].b = 0; 309 memory[i].a = 0; 310 } 311 struct RGBA pixel; 312 pixel.r = 0; 313 pixel.g = 0; 314 pixel.b = 0; 315 pixel.a = 255; 316 317 ImgU8 *curr = buf; 318 ImgU8 *end = curr + bufSz; 319 ImgSz run = 0; 320 ImgU8 chunk; 321 ImgStatus status; 322 ImgS8 dr; 323 ImgS8 dg; 324 ImgS8 db; 325 326 while(curr < end) { 327 if(run > 0) { 328 --run; 329 *curr++ = pixel.r; 330 *curr++ = pixel.g; 331 *curr++ = pixel.b; 332 if(img->channelCount == 4) { 333 *curr++ = pixel.a; 334 } 335 } 336 337 status = read(img, &chunk, 1); 338 if(status != ImgOK) { return status; } 339 340 if(chunk == 0xFF) { 341 status = read(img, &pixel.r, 1); 342 if(status != ImgOK) { return status; } 343 status = read(img, &pixel.g, 1); 344 if(status != ImgOK) { return status; } 345 status = read(img, &pixel.b, 1); 346 if(status != ImgOK) { return status; } 347 status = read(img, &pixel.a, 1); 348 if(status != ImgOK) { return status; } 349 } else if(chunk == 0xFE) { 350 status = read(img, &pixel.r, 1); 351 if(status != ImgOK) { return status; } 352 status = read(img, &pixel.g, 1); 353 if(status != ImgOK) { return status; } 354 status = read(img, &pixel.b, 1); 355 if(status != ImgOK) { return status; } 356 } else if((chunk & 0xC0) == 0x00) { 357 pixel = memory[chunk]; 358 } else if((chunk & 0xC0) == 0x40) { 359 dr = (ImgS8)((chunk & 0x30) >> 4) - 2; 360 dg = (ImgS8)((chunk & 0x0C) >> 2) - 2; 361 db = (ImgS8)(chunk & 0x03) - 2; 362 pixel.r += dr; 363 pixel.g += dg; 364 pixel.b += db; 365 } else if((chunk & 0xC0) == 0x80) { 366 dg = (ImgS8)(chunk & 0x3F) - 32; 367 status = read(img, &chunk, 1); 368 if(status != ImgOK) { return status; } 369 dr = (ImgS8)(chunk >> 4) - 8 + dg; 370 db = (ImgS8)(chunk & 0xF) - 8 + dg; 371 pixel.r += dr; 372 pixel.g += dg; 373 pixel.b += db; 374 } else if((chunk & 0xC0) == 0xC0) { 375 run = chunk & 0x3F; 376 } 377 378 memory[qoiIndex(pixel)] = pixel; 379 *curr++ = pixel.r; 380 *curr++ = pixel.g; 381 *curr++ = pixel.b; 382 if(img->channelCount == 4) { 383 *curr++ = pixel.a; 384 } 385 } 386 387 return ImgOK; 388} 389 390static ImgStatus pbmReadNum(Img *img, ImgU16 *out) 391{ 392 ImgStatus status; 393 char buf[6]; 394 ImgSz len = 0; 395 char chr; 396 397 do { 398 status = read(img, &chr, 1); 399 if(status != ImgOK) { return status; } 400 if(chr == '#') { 401 do { 402 status = read(img, &chr, 1); 403 if(status != ImgOK) { return status; } 404 } while(chr != '\n'); 405 continue; 406 } 407 } while(chr == ' ' || chr == '\n'); 408 buf[len++] = chr; 409 410 do { 411 status = read(img, &chr, 1); 412 if(status != ImgOK) { return status; } 413 if(chr == ' ' || chr == '\n') { 414 buf[len] = '\0'; 415 break; 416 } 417 buf[len++] = chr; 418 if(len >= 5) { 419 return ImgErrPbmValueTooLarge; 420 } 421 } while(1); 422 423 char *endptr; 424 long value = strtol(buf, &endptr, 10); 425 if(endptr != buf + len) { 426 return ImgErrPbmInvalidInteger; 427 } 428 429 *out = value; 430 return ImgOK; 431} 432 433ImgStatus openPbm(Img *img) 434{ 435 char magic[2]; 436 ImgStatus status; 437 438 status = read(img, magic, 2); 439 if(status != ImgOK) { return status; } 440 img->pbm.variant = magic[1]; 441 442 ImgU16 width; 443 ImgU16 height; 444 status = pbmReadNum(img, &width); 445 if(status != ImgOK) { return status; } 446 status = pbmReadNum(img, &height); 447 if(status != ImgOK) { return status; } 448 if(img->pbm.variant != '1' && img->pbm.variant != '4') { 449 status = pbmReadNum(img, &img->pbm.max); 450 if(status != ImgOK) { return status; } 451 } 452 453 img->width = width; 454 img->height = height; 455 img->channelCount = 3; 456 457 return ImgOK; 458} 459 460static ImgStatus readPbm1(Img *img, ImgAny buf, ImgSz bufSz); 461static ImgStatus readPbm2(Img *img, ImgAny buf, ImgSz bufSz); 462static ImgStatus readPbm3(Img *img, ImgAny buf, ImgSz bufSz); 463static ImgStatus readPbm4(Img *img, ImgAny buf, ImgSz bufSz); 464static ImgStatus readPbm5(Img *img, ImgAny buf, ImgSz bufSz); 465static ImgStatus readPbm6(Img *img, ImgAny buf, ImgSz bufSz); 466 467ImgStatus readPbm(Img *img, ImgAny buf, ImgSz bufSz) 468{ 469 switch(img->pbm.variant) { 470 case '1': return readPbm1(img, buf, bufSz); 471 case '2': return readPbm2(img, buf, bufSz); 472 case '3': return readPbm3(img, buf, bufSz); 473 case '5': return readPbm5(img, buf, bufSz); 474 case '6': return readPbm6(img, buf, bufSz); 475 } 476 return ImgErrUnknownFormat; 477} 478 479ImgStatus readPbm1(Img *img, ImgAny buf, ImgSz bufSz) 480{ 481 ImgSz expectedSize = (ImgSz)img->width * img->height * 3; 482 if(expectedSize != bufSz) { 483 return ImgErrBufferTooSmall; 484 } 485 486 ImgU8 *curr = buf; 487 ImgU8 *end = curr + expectedSize; 488 char chr; 489 ImgStatus status; 490 do { 491 status = read(img, &chr, 1); 492 if(status != ImgOK) { return status; } 493 494 if(chr == '1') { 495 *curr++ = 0; 496 *curr++ = 0; 497 *curr++ = 0; 498 } else { 499 *curr++ = 255; 500 *curr++ = 255; 501 *curr++ = 255; 502 } 503 } while(curr < end); 504 505 return ImgOK; 506} 507 508ImgStatus readPbm2(Img *img, ImgAny buf, ImgSz bufSz) 509{ 510 ImgSz expectedSize = (ImgSz)img->width * img->height * 3; 511 if(expectedSize != bufSz) { 512 return ImgErrBufferTooSmall; 513 } 514 515 ImgU8 *curr = buf; 516 ImgU8 *end = curr + expectedSize; 517 ImgU16 pixel; 518 ImgU8 pixelU8; 519 ImgStatus status; 520 do { 521 status = pbmReadNum(img, &pixel); 522 if(status != ImgOK) { return status; } 523 524 pixelU8 = (ImgSz)pixel * 255 / img->pbm.max; 525 *curr++ = pixelU8; 526 *curr++ = pixelU8; 527 *curr++ = pixelU8; 528 } while(curr < end); 529 530 return ImgOK; 531} 532 533ImgStatus readPbm3(Img *img, ImgAny buf, ImgSz bufSz) 534{ 535 ImgSz expectedSize = (ImgSz)img->width * img->height * 3; 536 if(expectedSize != bufSz) { 537 return ImgErrBufferTooSmall; 538 } 539 540 ImgU8 *curr = buf; 541 ImgU8 *end = curr + expectedSize; 542 ImgU16 pixel; 543 ImgStatus status; 544 do { 545 status = pbmReadNum(img, &pixel); 546 if(status != ImgOK) { return status; } 547 *curr++ = (ImgSz)pixel * 255 / img->pbm.max; 548 status = pbmReadNum(img, &pixel); 549 if(status != ImgOK) { return status; } 550 *curr++ = (ImgSz)pixel * 255 / img->pbm.max; 551 status = pbmReadNum(img, &pixel); 552 if(status != ImgOK) { return status; } 553 *curr++ = (ImgSz)pixel * 255 / img->pbm.max; 554 } while(curr < end); 555 556 return ImgOK; 557} 558 559ImgStatus readPbm4(Img *img, ImgAny buf, ImgSz bufSz) 560{ 561 ImgSz expectedSize = (ImgSz)img->width * img->height * 3; 562 if(expectedSize != bufSz) { 563 return ImgErrBufferTooSmall; 564 } 565 566 ImgU8 *curr = buf; 567 ImgU8 *end = curr + expectedSize; 568 ImgU8 batch; 569 ImgStatus status; 570 do { 571 status = read(img, &batch, 1); 572 if(status != ImgOK) { return status; } 573 *curr++ = (batch >> 7) * 255; 574 if(curr >= end) { break; } 575 *curr += ((batch >> 6) & 1) * 255; 576 if(curr >= end) { break; } 577 *curr += ((batch >> 5) & 1) * 255; 578 if(curr >= end) { break; } 579 *curr += ((batch >> 4) & 1) * 255; 580 if(curr >= end) { break; } 581 *curr += ((batch >> 3) & 1) * 255; 582 if(curr >= end) { break; } 583 *curr += ((batch >> 2) & 1) * 255; 584 if(curr >= end) { break; } 585 *curr += ((batch >> 1) & 1) * 255; 586 if(curr >= end) { break; } 587 *curr += (batch & 1) * 255; 588 } while(curr < end); 589 590 return ImgOK; 591} 592 593ImgStatus readPbm5(Img *img, ImgAny buf, ImgSz bufSz) 594{ 595 ImgSz expectedSize = (ImgSz)img->width * img->height * 3; 596 if(expectedSize != bufSz) { 597 return ImgErrBufferTooSmall; 598 } 599 600 ImgU8 *curr = buf; 601 ImgU8 *end = curr + expectedSize; 602 ImgU8 pixel8; 603 ImgU16 pixel16; 604 ImgStatus status; 605 do { 606 if(img->pbm.max >= 256) { 607 status = read(img, &pixel8, 1); 608 if(status != ImgOK) { return status; } 609 } else { 610 status = readU16BE(img, &pixel16); 611 if(status != ImgOK) { return status; } 612 pixel8 = (ImgSz)pixel16 * 255 / img->pbm.max; 613 } 614 *curr++ = pixel8; 615 *curr++ = pixel8; 616 *curr++ = pixel8; 617 } while(curr < end); 618 619 return ImgOK; 620} 621 622ImgStatus readPbm6(Img *img, ImgAny buf, ImgSz bufSz) 623{ 624 ImgSz expectedSize = (ImgSz)img->width * img->height * 3; 625 if(expectedSize != bufSz) { 626 return ImgErrBufferTooSmall; 627 } 628 629 ImgU8 *curr = buf; 630 ImgU8 *end = curr + expectedSize; 631 ImgU8 pixel8[3]; 632 ImgU16 pixel16[3]; 633 ImgStatus status; 634 do { 635 if(img->pbm.max >= 256) { 636 status = read(img, pixel8, 3); 637 if(status != ImgOK) { return status; } 638 } else { 639 status = readU16BE(img, &pixel16[0]); 640 if(status != ImgOK) { return status; } 641 status = readU16BE(img, &pixel16[1]); 642 if(status != ImgOK) { return status; } 643 status = readU16BE(img, &pixel16[2]); 644 if(status != ImgOK) { return status; } 645 pixel8[0] = (ImgSz)pixel16[0] * 255 / img->pbm.max; 646 pixel8[1] = (ImgSz)pixel16[1] * 255 / img->pbm.max; 647 pixel8[2] = (ImgSz)pixel16[2] * 255 / img->pbm.max; 648 } 649 *curr++ = pixel8[0]; 650 *curr++ = pixel8[1]; 651 *curr++ = pixel8[2]; 652 } while(curr < end); 653 654 return ImgOK; 655} 656 657static ImgStatus openBmpBITMAPINFOHEADER(Img *img); 658static ImgStatus openBmpBITMAPV4HEADER(Img *img); 659static ImgStatus openBmpBITMAPV5HEADER(Img *img); 660static ImgStatus bmpReadColorTable(Img *img); 661 662ImgStatus openBmp(Img *img) 663{ 664 /* BITMAPFILEHEADER 665 WORD bfType; "BM" 666 DWORD bfSize; size of the file 667 WORD bfReserved1; must be 0 668 WORD bfReserved2; must be 0 669 DWORD bfOffBits; offset to th bitmap data 670 */ 671 672 ImgStatus status; 673 ImgU32 size; 674 ImgU16 reserved; 675 676 status = seek(img, 2); 677 if(status != ImgOK) { return status; } 678 status = readU32LE(img, &size); 679 if(status != ImgOK) { return status; } 680 status = read(img, &reserved, 2); 681 if(status != ImgOK) { return status; } 682 if(reserved != 0) { 683 return ImgErrBmpMalformedHeader; 684 } 685 status = read(img, &reserved, 2); 686 if(status != ImgOK) { return status; } 687 if(reserved != 0) { 688 return ImgErrBmpMalformedHeader; 689 } 690 status = readU32LE(img, &img->bmp.bitmapOffset); 691 if(status != ImgOK) { return status; } 692 if(img->bmp.bitmapOffset >= size) { 693 return ImgErrBmpMalformedHeader; 694 } 695 696 status = readU32LE(img, &img->bmp.headerSize); 697 if(status != ImgOK) { return status; } 698 if(img->bmp.headerSize == 40) { 699 status = openBmpBITMAPINFOHEADER(img); 700 } else if(img->bmp.headerSize == 108) { 701 status = openBmpBITMAPV4HEADER(img); 702 } else if(img->bmp.headerSize == 124) { 703 status = openBmpBITMAPV5HEADER(img); 704 } else { 705 return ImgErrBmpUnsupportedVariant; 706 } 707 if(status != ImgOK) { return status; } 708 709 return bmpReadColorTable(img); 710} 711 712ImgStatus openBmpBITMAPINFOHEADER(Img *img) 713{ 714 /* BITMAPINFOHEADER 715 DWORD biSize; 40 for BITMAPINFOHEADER 716 LONG biWidth; 717 LONG biHeight; if positive : bottom-up bitmap 718 if negative : top-down, origin at top left corner 719 WORD biPlanes; must be 1 720 WORD biBitCount; 721 DWORD biCompression; 722 DWORD biSizeImage; can be 0 for uncompressed 723 LONG biXPelsPerMeter; 724 LONG biYPelsPerMeter; 725 DWORD biClrUsed; colors count in color table 726 DWORD biClrImportant; numbers of color indices considered important 727 */ 728 729 ImgStatus status; 730 ImgU16 planes; 731 732 status = readS32LE(img, &img->bmp.width); 733 if(status != ImgOK) { return status; } 734 img->width = img->bmp.width; 735 status = readS32LE(img, &img->bmp.height); 736 if(status != ImgOK) { return status; } 737 if(img->bmp.height < 0) { 738 img->height = -img->bmp.height; 739 } else { 740 img->height = img->bmp.height; 741 } 742 status = readU16LE(img, &planes); 743 if(status != ImgOK) { return status; } 744 if(planes != 1) { 745 return ImgErrBmpPlaneCount; 746 } 747 status = readU16LE(img, &img->bmp.bitCount); 748 if(status != ImgOK) { return status; } 749 status = readU32LE(img, &img->bmp.compression); 750 if(status != ImgOK) { return status; } 751 if(img->bmp.compression != IMG_BMP_COMPRESSION_RGB 752 && img->bmp.compression != IMG_BMP_COMPRESSION_RLE8 753 && img->bmp.compression != IMG_BMP_COMPRESSION_RLE4 754 && img->bmp.compression != IMG_BMP_COMPRESSION_BITFIELDS) { 755 return ImgErrBmpUnsupportedCompression; 756 } 757 status = readU32LE(img, &img->bmp.imageSize); 758 if(status != ImgOK) { return status; } 759 status = readS32LE(img, &img->bmp.xPPM); 760 if(status != ImgOK) { return status; } 761 status = readS32LE(img, &img->bmp.yPPM); 762 if(status != ImgOK) { return status; } 763 status = readU32LE(img, &img->bmp.colorsUsed); 764 if(status != ImgOK) { return status; } 765 status = seek(img, 4); 766 if(status != ImgOK) { return status; } 767 768 return ImgOK; 769} 770 771ImgStatus openBmpBITMAPV4HEADER(Img *img) 772{ 773 /* BITMAPV4HEADER 774 <BITMAPINFOHEADER fields> 775 DWORD bV4RedMask; 776 DWORD bV4GreenMask; 777 DWORD bV4BlueMask; 778 DWORD bV4AlphaMask; 779 DWORD bV4CSType; ignored 780 CIEXYZTRIPLE bV4Endpoints; ignored 781 DWORD bV4GammaRed; ignored 782 DWORD bV4GammaGreen; ignored 783 DWORD bV4GammaBlue; ignored 784 */ 785 786 ImgStatus status; 787 788 status = openBmpBITMAPINFOHEADER(img); 789 if(status != ImgOK) { return status; } 790 status = readU32LE(img, &img->bmp.redMask); 791 if(status != ImgOK) { return status; } 792 status = readU32LE(img, &img->bmp.greenMask); 793 if(status != ImgOK) { return status; } 794 status = readU32LE(img, &img->bmp.blueMask); 795 if(status != ImgOK) { return status; } 796 status = readU32LE(img, &img->bmp.alphaMask); 797 if(status != ImgOK) { return status; } 798 799 ImgOff off = 4 /* bV4CSType*/ 800 + (4 * 3 * 3) /* bV4Endpoints */ 801 + 4 /* bV4GammaRed */ 802 + 4 /* bV4GammaGreen */ 803 + 4; /* bV4GammaBlue */ 804 status = seek(img, off); 805 if(status != ImgOK) { return status; } 806 807 return ImgOK; 808} 809 810ImgStatus openBmpBITMAPV5HEADER(Img *img) 811{ 812 /* BITMAPV5HEADER 813 <BITMAPV4HEADER fields> 814 DWORD bV5Intent; ignored 815 DWORD bV5ProfileData; ignored 816 DWORD bV5ProfileSize; ignored 817 DWORD bV5Reserved; must be 0 818 */ 819 820 ImgStatus status; 821 822 status = openBmpBITMAPV4HEADER(img); 823 if(status != ImgOK) { return status; } 824 825 ImgOff off = 4 /* bV5Intent */ 826 + 4 /* bV5ProfileData */ 827 + 4; /* bV5ProfileSize */ 828 status = seek(img, off); 829 if(status != ImgOK) { return status; } 830 831 ImgU32 reserved; 832 status = readU32LE(img, &reserved); 833 if(status != ImgOK) { return status; } 834 if(reserved != 0) { 835 return ImgErrBmpMalformedHeader; 836 } 837 838 return ImgOK; 839} 840 841ImgStatus bmpReadColorTable(Img *img) 842{ 843 ImgStatus status; 844 845 switch(img->bmp.bitCount) { 846 case 1: 847 case 2: 848 case 4: 849 case 8: 850 img->channelCount = 3; 851 if(img->bmp.colorsUsed == 0) { 852 img->bmp.colorTableSize = 1 << img->bmp.bitCount; 853 } else { 854 img->bmp.colorTableSize = img->bmp.colorsUsed; 855 } 856 status = read(img, img->bmp.colorTable, img->bmp.colorTableSize * 4); 857 if(status != ImgOK) { return status; } 858 break; 859 case 24: 860 img->channelCount = 3; 861 img->bmp.colorTableSize = 0; 862 break; 863 case 32: 864 img->channelCount = 4; 865 img->bmp.colorTableSize = 0; 866 break; 867 default: 868 return ImgErrBmpUnsupportedBitDepth; 869 } 870 871 return ImgOK; 872} 873 874static ImgStatus readBmp1BPP(Img *img, ImgAny buf, ImgSz bufSz); 875static ImgStatus readBmp2BPP(Img *img, ImgAny buf, ImgSz bufSz); 876static ImgStatus readBmp4BPP(Img *img, ImgAny buf, ImgSz bufSz); 877static ImgStatus readBmp8BPP(Img *img, ImgAny buf, ImgSz bufSz); 878static ImgStatus readBmp16BPP(Img *img, ImgAny buf, ImgSz bufSz); 879static ImgStatus readBmp24BPP(Img *img, ImgAny buf, ImgSz bufSz); 880static ImgStatus readBmp32BPP(Img *img, ImgAny buf, ImgSz bufSz); 881static ImgStatus readBmpRLE8(Img *img, ImgAny buf, ImgSz bufSz); 882static ImgStatus readBmpRLE4(Img *img, ImgAny buf, ImgSz bufSz); 883 884ImgStatus readBmp(Img *img, ImgAny buf, ImgSz bufSz) 885{ 886 ImgSz expectedSize = (ImgSz)img->width * img->height * img->channelCount; 887 if(bufSz < expectedSize) { 888 return ImgErrBufferTooSmall; 889 } 890 891 /* 892 ImgStatus status = seek(img, img->bmp.bitmapOffset - 14 - img->bmp.headerSize); 893 if(status != ImgOK) { return status; } 894 */ 895 896 if(img->bmp.compression == IMG_BMP_COMPRESSION_RLE8) { 897 return readBmpRLE8(img, buf, bufSz); 898 } 899 if(img->bmp.compression == IMG_BMP_COMPRESSION_RLE4) { 900 return readBmpRLE8(img, buf, bufSz); 901 } 902 903 switch(img->bmp.bitCount) { 904 case 1: return readBmp1BPP(img, buf, bufSz); 905 case 2: return readBmp2BPP(img, buf, bufSz); 906 case 4: return readBmp4BPP(img, buf, bufSz); 907 case 8: return readBmp8BPP(img, buf, bufSz); 908 case 16: return readBmp16BPP(img, buf, bufSz); 909 case 24: return readBmp24BPP(img, buf, bufSz); 910 case 32: return readBmp32BPP(img, buf, bufSz); 911 } 912 913 return ImgErrUnimplemented; 914} 915 916ImgStatus readBmp1BPP(Img *img, ImgAny buf, ImgSz bufSz) 917{ 918 ImgU8 *out = buf; 919 ImgOff pad = (4 - (img->width * img->bmp.bitCount / 8)) & 3; 920 921 ImgStatus status; 922 ImgU8 batch; 923 struct ImgBmpRGBQuad pixel; 924 for(ImgU32 y = 0; y < img->height; ++y) { 925 ImgU32 trueY = y; 926 if(img->bmp.height > 0) { 927 trueY = img->height - y - 1; 928 } 929 ImgU8 *scanline = &out[trueY * img->width * img->channelCount]; 930 for(ImgU32 x = 0; x < img->width; x += 8) { 931 status = read(img, &batch, 1); 932 if(status != ImgOK) { return status; } 933 934 pixel = img->bmp.colorTable[(batch >> 7) & 1]; 935 *scanline++ = pixel.red; 936 *scanline++ = pixel.green; 937 *scanline++ = pixel.blue; 938 pixel = img->bmp.colorTable[(batch >> 6) & 1]; 939 *scanline++ = pixel.red; 940 *scanline++ = pixel.green; 941 *scanline++ = pixel.blue; 942 pixel = img->bmp.colorTable[(batch >> 5) & 1]; 943 *scanline++ = pixel.red; 944 *scanline++ = pixel.green; 945 *scanline++ = pixel.blue; 946 pixel = img->bmp.colorTable[(batch >> 4) & 1]; 947 *scanline++ = pixel.red; 948 *scanline++ = pixel.green; 949 *scanline++ = pixel.blue; 950 pixel = img->bmp.colorTable[(batch >> 3) & 1]; 951 *scanline++ = pixel.red; 952 *scanline++ = pixel.green; 953 *scanline++ = pixel.blue; 954 pixel = img->bmp.colorTable[(batch >> 2) & 1]; 955 *scanline++ = pixel.red; 956 *scanline++ = pixel.green; 957 *scanline++ = pixel.blue; 958 pixel = img->bmp.colorTable[(batch >> 1) & 1]; 959 *scanline++ = pixel.red; 960 *scanline++ = pixel.green; 961 *scanline++ = pixel.blue; 962 pixel = img->bmp.colorTable[batch & 1]; 963 *scanline++ = pixel.red; 964 *scanline++ = pixel.green; 965 *scanline++ = pixel.blue; 966 } 967 if(pad != 0) { 968 status = seek(img, pad); 969 if(status != ImgOK) { return status; } 970 } 971 } 972 973 return ImgOK; 974} 975 976ImgStatus readBmp2BPP(Img *img, ImgAny buf, ImgSz bufSz) 977{ 978 ImgU8 *out = buf; 979 ImgOff pad = (4 - (img->width * img->bmp.bitCount / 8)) & 3; 980 981 ImgStatus status; 982 ImgU8 batch; 983 struct ImgBmpRGBQuad pixel; 984 for(ImgU32 y = 0; y < img->height; ++y) { 985 ImgU32 trueY = y; 986 if(img->bmp.height > 0) { 987 trueY = img->height - y - 1; 988 } 989 ImgU8 *scanline = &out[trueY * img->width * img->channelCount]; 990 for(ImgU32 x = 0; x < img->width; x += 4) { 991 status = read(img, &batch, 1); 992 if(status != ImgOK) { return status; } 993 994 pixel = img->bmp.colorTable[(batch >> 6) & 3]; 995 *scanline++ = pixel.red; 996 *scanline++ = pixel.green; 997 *scanline++ = pixel.blue; 998 pixel = img->bmp.colorTable[(batch >> 4) & 3]; 999 *scanline++ = pixel.red; 1000 *scanline++ = pixel.green; 1001 *scanline++ = pixel.blue; 1002 pixel = img->bmp.colorTable[(batch >> 2) & 3]; 1003 *scanline++ = pixel.red; 1004 *scanline++ = pixel.green; 1005 *scanline++ = pixel.blue; 1006 pixel = img->bmp.colorTable[batch & 3]; 1007 *scanline++ = pixel.red; 1008 *scanline++ = pixel.green; 1009 *scanline++ = pixel.blue; 1010 } 1011 if(pad != 0) { 1012 status = seek(img, pad); 1013 if(status != ImgOK) { return status; } 1014 } 1015 } 1016 1017 return ImgOK; 1018} 1019 1020ImgStatus readBmp4BPP(Img *img, ImgAny buf, ImgSz bufSz) 1021{ 1022 ImgU8 *out = buf; 1023 ImgOff pad = (4 - (img->width * img->bmp.bitCount / 8)) & 3; 1024 1025 ImgStatus status; 1026 ImgU8 batch; 1027 struct ImgBmpRGBQuad pixel; 1028 for(ImgU32 y = 0; y < img->height; ++y) { 1029 ImgU32 trueY = y; 1030 if(img->bmp.height > 0) { 1031 trueY = img->height - y - 1; 1032 } 1033 ImgU8 *scanline = &out[trueY * img->width * img->channelCount]; 1034 for(ImgU32 x = 0; x < img->width; x += 2) { 1035 status = read(img, &batch, 1); 1036 if(status != ImgOK) { return status; } 1037 1038 pixel = img->bmp.colorTable[(batch >> 4) & 15]; 1039 *scanline++ = pixel.red; 1040 *scanline++ = pixel.green; 1041 *scanline++ = pixel.blue; 1042 pixel = img->bmp.colorTable[batch & 15]; 1043 *scanline++ = pixel.red; 1044 *scanline++ = pixel.green; 1045 *scanline++ = pixel.blue; 1046 } 1047 if(pad != 0) { 1048 status = seek(img, pad); 1049 if(status != ImgOK) { return status; } 1050 } 1051 } 1052 1053 return ImgOK; 1054} 1055 1056ImgStatus readBmp8BPP(Img *img, ImgAny buf, ImgSz bufSz) 1057{ 1058 ImgU8 *out = buf; 1059 ImgOff pad = (4 - (img->width * img->bmp.bitCount / 8)) & 3; 1060 1061 ImgStatus status; 1062 ImgU8 idx; 1063 struct ImgBmpRGBQuad pixel; 1064 for(ImgU32 y = 0; y < img->height; ++y) { 1065 ImgU32 trueY = y; 1066 if(img->bmp.height > 0) { 1067 trueY = img->height - y - 1; 1068 } 1069 ImgU8 *scanline = &out[trueY * img->width * img->channelCount]; 1070 for(ImgU32 x = 0; x < img->width; x += 1) { 1071 status = read(img, &idx, 1); 1072 if(status != ImgOK) { return status; } 1073 1074 pixel = img->bmp.colorTable[idx]; 1075 *scanline++ = pixel.red; 1076 *scanline++ = pixel.green; 1077 *scanline++ = pixel.blue; 1078 } 1079 if(pad != 0) { 1080 status = seek(img, pad); 1081 if(status != ImgOK) { return status; } 1082 } 1083 } 1084 1085 return ImgOK; 1086} 1087 1088ImgStatus readBmp16BPP(Img *img, ImgAny buf, ImgSz bufSz) 1089{ 1090 ImgU8 *out = buf; 1091 ImgOff pad = (4 - (img->width * img->bmp.bitCount / 8)) & 3; 1092 1093 ImgStatus status; 1094 ImgU8 idx; 1095 ImgU16 pixel; 1096 for(ImgU32 y = 0; y < img->height; ++y) { 1097 ImgU32 trueY = y; 1098 if(img->bmp.height > 0) { 1099 trueY = img->height - y - 1; 1100 } 1101 ImgU8 *scanline = &out[trueY * img->width * img->channelCount]; 1102 for(ImgU32 x = 0; x < img->width; x += 1) { 1103 status = readU16LE(img, &pixel); 1104 if(status != ImgOK) { return status; } 1105 *scanline++ = (pixel >> 11) & 63; 1106 *scanline++ = (pixel >> 6) & 31; 1107 *scanline++ = pixel & 63; 1108 } 1109 if(pad != 0) { 1110 status = seek(img, pad); 1111 if(status != ImgOK) { return status; } 1112 } 1113 } 1114 1115 return ImgOK; 1116} 1117 1118ImgStatus readBmp24BPP(Img *img, ImgAny buf, ImgSz bufSz) 1119{ 1120 ImgU8 *out = buf; 1121 ImgOff pad = (4 - (img->width * img->bmp.bitCount / 8)) & 3; 1122 1123 ImgStatus status; 1124 ImgU8 idx; 1125 struct ImgBmpRGBQuad pixel; 1126 for(ImgU32 y = 0; y < img->height; ++y) { 1127 ImgU32 trueY = y; 1128 if(img->bmp.height > 0) { 1129 trueY = img->height - y - 1; 1130 } 1131 ImgU8 *scanline = &out[trueY * img->width * img->channelCount]; 1132 for(ImgU32 x = 0; x < img->width; x += 1) { 1133 status = read(img, &pixel, 3); 1134 if(status != ImgOK) { return status; } 1135 *scanline++ = pixel.red; 1136 *scanline++ = pixel.green; 1137 *scanline++ = pixel.blue; 1138 } 1139 if(pad != 0) { 1140 status = seek(img, pad); 1141 if(status != ImgOK) { return status; } 1142 } 1143 } 1144 1145 return ImgOK; 1146} 1147 1148ImgStatus readBmp32BPP(Img *img, ImgAny buf, ImgSz bufSz) 1149{ 1150 ImgU8 *out = buf; 1151 ImgOff pad = (4 - (img->width * img->bmp.bitCount / 8)) & 3; 1152 1153 ImgStatus status; 1154 ImgU8 idx; 1155 struct ImgBmpRGBQuad pixel; 1156 for(ImgU32 y = 0; y < img->height; ++y) { 1157 ImgU32 trueY = y; 1158 if(img->bmp.height > 0) { 1159 trueY = img->height - y - 1; 1160 } 1161 ImgU8 *scanline = &out[trueY * img->width * img->channelCount]; 1162 for(ImgU32 x = 0; x < img->width; x += 1) { 1163 status = read(img, &pixel, 4); 1164 if(status != ImgOK) { return status; } 1165 *scanline++ = pixel.red; 1166 *scanline++ = pixel.green; 1167 *scanline++ = pixel.blue; 1168 *scanline++ = pixel.reserved; 1169 } 1170 if(pad != 0) { 1171 status = seek(img, pad); 1172 if(status != ImgOK) { return status; } 1173 } 1174 } 1175 1176 return ImgOK; 1177} 1178 1179ImgStatus readBmpRLE8(Img *img, ImgAny buf, ImgSz bufSz) 1180{ 1181 ImgStatus status; 1182 ImgU8 *out = buf; 1183 1184 ImgU8 packet[2]; 1185 ImgU8 pixel; 1186 ImgU8 delta[2]; 1187 const struct ImgBmpRGBQuad *color; 1188 1189 ImgU32 x = 0; 1190 ImgU32 y = 0; 1191 if(img->bmp.height > 0) { 1192 y = img->height - 1; 1193 } 1194 1195 do { 1196 status = read(img, packet, 2); 1197 if(status != ImgOK) { return status; } 1198 1199 ImgU8 * curr = out + img->channelCount * (y * img->width + x); 1200 1201 /* encoded mode */ 1202 if(packet[0] != 0) { 1203 color = &img->bmp.colorTable[packet[1]]; 1204 for(ImgU8 i = 0; i < packet[0]; ++i) { 1205 *curr++ = color->red; 1206 *curr++ = color->green; 1207 *curr++ = color->blue; 1208 } 1209 x += packet[0]; 1210 continue; 1211 } 1212 1213 /* absolute mode */ 1214 if(packet[1] >= 3) { 1215 for(ImgU8 i = 0; i < packet[1]; ++i) { 1216 status = read(img, &pixel, 1); 1217 if(status != ImgOK) { return status; } 1218 color = &img->bmp.colorTable[pixel]; 1219 *curr++ = color->red; 1220 *curr++ = color->green; 1221 *curr++ = color->blue; 1222 } 1223 x += packet[1]; 1224 /* pad to word */ 1225 if((packet[1] & 1) != 0) { 1226 status = seek(img, 1); 1227 if(status != ImgOK) { return status; } 1228 } 1229 continue; 1230 } 1231 1232 /* move */ 1233 if(packet[1] == 2) { 1234 status = read(img, delta, 2); 1235 if(status != ImgOK) { return status; } 1236 x += delta[0]; 1237 if(img->bmp.height > 0) { 1238 y -= delta[1]; 1239 } else { 1240 y += delta[1]; 1241 } 1242 continue; 1243 } 1244 1245 /* end of scanline */ 1246 if(packet[1] == 0) { 1247 x = 0; 1248 if(img->bmp.height > 0) { 1249 --y; 1250 } else { 1251 ++y; 1252 } 1253 continue; 1254 } 1255 1256 /* end of bitmap */ 1257 break; 1258 } while(1); 1259 1260 return ImgOK; 1261} 1262 1263ImgStatus readBmpRLE4(Img *img, ImgAny buf, ImgSz bufSz) 1264{ 1265 ImgStatus status; 1266 ImgU8 *out = buf; 1267 1268 ImgU8 packet[2]; 1269 ImgU8 pixel; 1270 ImgU8 delta[2]; 1271 const struct ImgBmpRGBQuad *colors[2]; 1272 1273 ImgU32 x = 0; 1274 ImgU32 y = 0; 1275 if(img->bmp.height > 0) { 1276 y = img->height - 1; 1277 } 1278 1279 do { 1280 status = read(img, packet, 2); 1281 if(status != ImgOK) { return status; } 1282 1283 ImgU8 * curr = out + img->channelCount * (y * img->width + x); 1284 1285 /* encoded mode */ 1286 if(packet[0] != 0) { 1287 colors[0] = &img->bmp.colorTable[packet[1] >> 4]; 1288 colors[1] = &img->bmp.colorTable[packet[1] & 15]; 1289 /* first output all pairs */ 1290 for(ImgU8 i = 0; i < packet[0] >> 1; ++i) { 1291 *curr++ = colors[0]->red; 1292 *curr++ = colors[0]->green; 1293 *curr++ = colors[0]->blue; 1294 *curr++ = colors[1]->red; 1295 *curr++ = colors[1]->green; 1296 *curr++ = colors[1]->blue; 1297 } 1298 /* output last odd one */ 1299 if(packet[0] & 1) { 1300 *curr++ = colors[0]->red; 1301 *curr++ = colors[0]->green; 1302 *curr++ = colors[0]->blue; 1303 } 1304 x += packet[0]; 1305 /* pad to word boundary by skipping a byte */ 1306 if(packet[0] & 3) { 1307 status = seek(img, 1); 1308 if(status != ImgOK) { return status; } 1309 } 1310 continue; 1311 } 1312 1313 /* absolute mode */ 1314 if(packet[1] >= 3) { 1315 /* first output all pairs */ 1316 for(ImgU8 i = 0; i < packet[1] >> 1; ++i) { 1317 status = read(img, &pixel, 1); 1318 if(status != ImgOK) { return status; } 1319 colors[0] = &img->bmp.colorTable[pixel >> 4]; 1320 colors[1] = &img->bmp.colorTable[pixel & 15]; 1321 *curr++ = colors[0]->red; 1322 *curr++ = colors[0]->green; 1323 *curr++ = colors[0]->blue; 1324 *curr++ = colors[1]->red; 1325 *curr++ = colors[1]->green; 1326 *curr++ = colors[1]->blue; 1327 } 1328 /* output last odd one */ 1329 if(packet[0] & 1) { 1330 status = read(img, &pixel, 1); 1331 if(status != ImgOK) { return status; } 1332 colors[0] = &img->bmp.colorTable[pixel >> 4]; 1333 *curr++ = colors[0]->red; 1334 *curr++ = colors[0]->green; 1335 *curr++ = colors[0]->blue; 1336 } 1337 x += packet[1]; 1338 /* pad to word */ 1339 if((packet[1] & 3) != 0) { 1340 status = seek(img, 1); 1341 if(status != ImgOK) { return status; } 1342 } 1343 continue; 1344 } 1345 1346 /* move */ 1347 if(packet[1] == 2) { 1348 status = read(img, delta, 2); 1349 if(status != ImgOK) { return status; } 1350 x += delta[0]; 1351 if(img->bmp.height > 0) { 1352 y -= delta[1]; 1353 } else { 1354 y += delta[1]; 1355 } 1356 continue; 1357 } 1358 1359 /* end of scanline */ 1360 if(packet[1] == 0) { 1361 x = 0; 1362 if(img->bmp.height > 0) { 1363 --y; 1364 } else { 1365 ++y; 1366 } 1367 continue; 1368 } 1369 1370 /* end of bitmap */ 1371 break; 1372 } while(1); 1373 1374 return ImgOK; 1375} 1376 1377#define TGA_NO_IMAGE_DATA 0 1378#define TGA_COLOR_MAPPED 1 1379#define TGA_TRUE_COLOR 2 1380#define TGA_BLACK_AND_WHITE 3 1381#define TGA_RLE_COLOR_MAPPED 9 1382#define TGA_RLE_TRUE_COLOR 10 1383#define TGA_RLE_BLACK_AND_WHITE 11 1384 1385ImgStatus determineTga(Img *img) 1386{ 1387 ImgOff returnOff = 0; 1388 ImgStatus status; 1389 1390 status = read(img, &img->tga.idLength, 1); 1391 ++returnOff; 1392 if(status != ImgOK) { return status; } 1393 1394 status = read(img, &img->tga.colorMapType, 1); 1395 ++returnOff; 1396 if(status != ImgOK) { return status; } 1397 1398 /* invalid color map type, likely not TGA */ 1399 if(img->tga.colorMapType != 0 && img->tga.colorMapType != 1) { 1400 return seek(img, -returnOff); 1401 } 1402 1403 status = read(img, &img->tga.imageType, 1); 1404 ++returnOff; 1405 if(status != ImgOK) { return status; } 1406 1407 switch(img->tga.imageType) { 1408 case TGA_NO_IMAGE_DATA: 1409 case TGA_COLOR_MAPPED: 1410 case TGA_TRUE_COLOR: 1411 case TGA_BLACK_AND_WHITE: 1412 case TGA_RLE_COLOR_MAPPED: 1413 case TGA_RLE_TRUE_COLOR: 1414 case TGA_RLE_BLACK_AND_WHITE: 1415 break; 1416 /* invalid image type, likely not TGA */ 1417 default: 1418 return seek(img, -returnOff); 1419 } 1420 1421 status = readU16LE(img, &img->tga.colorMapFirstIndex); 1422 returnOff += 2; 1423 if(status != ImgOK) { return status; } 1424 1425 if(!img->tga.colorMapType && img->tga.colorMapFirstIndex != 0) { 1426 return seek(img, -returnOff); 1427 } 1428 1429 status = readU16LE(img, &img->tga.colorMapLength); 1430 returnOff += 2; 1431 if(status != ImgOK) { return status; } 1432 1433 if(!img->tga.colorMapType && img->tga.colorMapLength != 0) { 1434 return seek(img, -returnOff); 1435 } 1436 if(img->tga.colorMapType && img->tga.colorMapLength == 0) { 1437 return seek(img, -returnOff); 1438 } 1439 1440 status = read(img, &img->tga.colorMapEntrySize, 1); 1441 ++returnOff; 1442 if(status != ImgOK) { return status; } 1443 1444 if(!img->tga.colorMapType && img->tga.colorMapEntrySize != 0) { 1445 return seek(img, -returnOff); 1446 } 1447 1448 status = readU16LE(img, &img->tga.originX); 1449 returnOff += 2; 1450 if(status != ImgOK) { return status; } 1451 1452 status = readU16LE(img, &img->tga.originY); 1453 returnOff += 2; 1454 if(status != ImgOK) { return status; } 1455 1456 status = readU16LE(img, &img->tga.width); 1457 returnOff += 2; 1458 if(status != ImgOK) { return status; } 1459 1460 status = readU16LE(img, &img->tga.height); 1461 returnOff += 2; 1462 if(status != ImgOK) { return status; } 1463 1464 status = read(img, &img->tga.pixelDepth, 1); 1465 returnOff += 1; 1466 if(status != ImgOK) { return status; } 1467 1468 ImgU8 imageDescriptor; 1469 status = read(img, &imageDescriptor, 1); 1470 ++returnOff; 1471 if(status != ImgOK) { return status; } 1472 1473 /* unused bits must be 0 */ 1474 if((imageDescriptor >> 6) != 0) { 1475 return seek(img, -returnOff); 1476 } 1477 1478 img->tga.alphaBits = imageDescriptor & 15; 1479 img->tga.imageOrigin = (imageDescriptor >> 4) & 3; 1480 1481 img->format = ImgFormatTga; 1482 return ImgOK; 1483} 1484 1485/* Number of bytes needed to store the given amount of bits */ 1486#define BITS_TO_BYTES(bits) (((bits) + 7) >> 3) 1487 1488ImgStatus openTga(Img *img) 1489{ 1490 ImgStatus status; 1491 1492 if(img->tga.colorMapType) { 1493 if(img->tga.colorMapLength > IMG_TGA_MAX_COLOR_MAP_SIZE) { 1494 return ImgErrTgaColorMapTooLong; 1495 } 1496 } else if(img->tga.imageType == TGA_COLOR_MAPPED || img->tga.imageType == TGA_RLE_COLOR_MAPPED) { 1497 return ImgErrTgaMissingColorMap; 1498 } 1499 1500 /* the header was already read in by determineTga() */ 1501 if(img->tga.idLength) { 1502 status = read(img, img->tga.id, img->tga.idLength); 1503 if(status != ImgOK) { return status; } 1504 } 1505 /* NUL-terminate for convenience */ 1506 img->tga.id[img->tga.idLength] = '\0'; 1507 1508 /* set this here in case there is no color map */ 1509 if(img->tga.alphaBits) { 1510 img->channelCount = 4; 1511 } else { 1512 img->channelCount = 3; 1513 } 1514 img->width = img->tga.width; 1515 img->height = img->tga.height; 1516 1517 /* image data follows color map and we'll read that in readTga() */ 1518 /* so if we don't have a color map, we just return early here */ 1519 if(!img->tga.colorMapType) { 1520 return ImgOK; 1521 } 1522 1523 /* bits in a color field */ 1524 ImgU32 fieldBits = img->tga.colorMapEntrySize / 3; 1525 /* spec requires fields be at most 8 bits each */ 1526 if(fieldBits > 8) { 1527 fieldBits = 8; 1528 } 1529 /* mask of a field's bits */ 1530 ImgU32 fieldMask = (1 << fieldBits) - 1; 1531 /* bits in a full color entry (3 fields) */ 1532 ImgU32 entryBits = fieldBits * 3; 1533 /* total bits needed to store the entry (round up to 8) */ 1534 ImgU32 totalBits = BITS_TO_BYTES(img->tga.colorMapEntrySize) << 3; 1535 /* bits not used by entry */ 1536 ImgU32 alphaBits = totalBits - entryBits; 1537 /* alpha bit mask */ 1538 ImgU32 alphaMask = (1 << alphaBits) - 1; 1539 if(alphaBits != 0) { 1540 img->channelCount = 4; 1541 } else { 1542 img->channelCount = 3; 1543 } 1544 1545 ImgU8 entry8; 1546 ImgU16 entry16; 1547 ImgU32 entry32; 1548 for(ImgU16 i = img->tga.colorMapFirstIndex; i < img->tga.colorMapLength; ++i) { 1549 struct ImgTgaColor *color = &img->tga.colorMap[i]; 1550 1551 switch(totalBits) { 1552 case 8: 1553 status = read(img, &entry8, 1); 1554 if(status != ImgOK) { return status; } 1555 entry32 = entry8; 1556 break; 1557 case 16: 1558 status = readU16LE(img, &entry16); 1559 if(status != ImgOK) { return status; } 1560 entry32 = entry16; 1561 break; 1562 case 32: 1563 status = readU32LE(img, &entry32); 1564 if(status != ImgOK) { return status; } 1565 break; 1566 } 1567 1568 color->red = (entry32 >> (fieldBits * 2)) & fieldMask; 1569 color->green = (entry32 >> fieldBits) & fieldMask; 1570 color->blue = entry32 & fieldMask; 1571 if(alphaBits > 0) { 1572 color->alpha = (entry32 >> (fieldBits * 3)) & alphaMask; 1573 } 1574 } 1575 1576 return ImgOK; 1577} 1578 1579static ImgStatus readTgaColorMapped(Img *img, ImgAny buf, ImgSz bufSz); 1580static ImgStatus readTgaTrueColor(Img *img, ImgAny buf, ImgSz bufSz); 1581static ImgStatus readTgaBlackAndWhite(Img *img, ImgAny buf, ImgSz bufSz); 1582static ImgStatus readTgaRleColorMapped(Img *img, ImgAny buf, ImgSz bufSz); 1583static ImgStatus readTgaRleTrueColor(Img *img, ImgAny buf, ImgSz bufSz); 1584static ImgStatus readTgaRleBlackAndWhite(Img *img, ImgAny buf, ImgSz bufSz); 1585 1586/* TODO: Implement RLE */ 1587ImgStatus readTga(Img *img, ImgAny buf, ImgSz bufSz) 1588{ 1589 ImgSz expectedSize = (ImgSz)img->width * img->height * img->channelCount; 1590 if(bufSz < expectedSize) { 1591 return ImgErrBufferTooSmall; 1592 } 1593 1594 switch(img->tga.imageType) { 1595 case TGA_NO_IMAGE_DATA: 1596 return ImgErrTgaNoImageData; 1597 case TGA_COLOR_MAPPED: 1598 return readTgaColorMapped(img, buf, bufSz); 1599 case TGA_TRUE_COLOR: 1600 return readTgaTrueColor(img, buf, bufSz); 1601 case TGA_BLACK_AND_WHITE: 1602 return readTgaBlackAndWhite(img, buf, bufSz); 1603 case TGA_RLE_COLOR_MAPPED: 1604 return readTgaRleColorMapped(img, buf, bufSz); 1605 case TGA_RLE_TRUE_COLOR: 1606 return readTgaRleTrueColor(img, buf, bufSz); 1607 case TGA_RLE_BLACK_AND_WHITE: 1608 return readTgaRleBlackAndWhite(img, buf, bufSz); 1609 } 1610 return ImgErrUnimplemented; 1611} 1612 1613ImgStatus readTgaColorMapped(Img *img, ImgAny buf, ImgSz bufSz) 1614{ 1615 ImgStatus status; 1616 ImgSz expectedSize = (ImgSz)img->width * img->height * img->channelCount; 1617 ImgU8 *cur = buf; 1618 ImgU8 *end = cur + expectedSize; 1619 1620 /* above 8 not supported, also enforced by IMG_TGA_MAX_COLOR_MAP_LENGTH */ 1621 if(img->tga.pixelDepth > 8) { 1622 return ImgErrTgaUnsupportedPixelDepth; 1623 } 1624 1625 ImgU8 pixel; 1626 while(cur < end) { 1627 status = read(img, &pixel, 1); 1628 if(status != ImgOK) { return status; } 1629 1630 const struct ImgTgaColor *color = &img->tga.colorMap[pixel]; 1631 *cur++ = color->red; 1632 *cur++ = color->green; 1633 *cur++ = color->blue; 1634 if(img->channelCount == 4) { 1635 *cur++ = color->alpha; 1636 } 1637 } 1638 1639 return ImgOK; 1640} 1641 1642ImgStatus readTgaTrueColor(Img *img, ImgAny buf, ImgSz bufSz) 1643{ 1644 ImgStatus status; 1645 ImgSz expectedSize = (ImgSz)img->width * img->height * img->channelCount; 1646 ImgU8 *curr = buf; 1647 ImgU8 *end = curr + expectedSize; 1648 1649 ImgU32 pixelSize = BITS_TO_BYTES(img->tga.pixelDepth); 1650 ImgU32 alphaMask = (1 << img->tga.alphaBits) - 1; 1651 ImgU32 fieldBits = (img->tga.pixelDepth - img->tga.alphaBits) / 3; 1652 ImgU32 fieldMask = (1 << fieldBits) - 1; 1653 1654 ImgU8 pixel8; 1655 ImgU16 pixel16; 1656 ImgU32 pixel32; 1657 while(curr < end) { 1658 switch(pixelSize) { 1659 case 1: 1660 status = read(img, &pixel8, 1); 1661 if(status != ImgOK) { return status; } 1662 pixel32 = pixel8; 1663 break; 1664 case 2: 1665 status = readU16LE(img, &pixel16); 1666 if(status != ImgOK) { return status; } 1667 pixel32 = pixel16; 1668 break; 1669 case 3: 1670 status = readU24LE(img, &pixel32); 1671 if(status != ImgOK) { return status; }; 1672 break; 1673 case 4: 1674 status = readU32LE(img, &pixel32); 1675 if(status != ImgOK) { return status; } 1676 break; 1677 default: 1678 return ImgErrTgaUnsupportedPixelDepth; 1679 } 1680 1681 *curr++ = (pixel32 >> (2 * fieldBits)) & fieldMask; 1682 *curr++ = (pixel32 >> fieldBits) & fieldMask; 1683 *curr++ = pixel32 & fieldMask; 1684 if(img->channelCount > 3) { 1685 *curr++ = (pixel32 >> (3 * fieldBits)) & alphaMask; 1686 } 1687 } 1688 1689 return ImgOK; 1690} 1691 1692ImgStatus readTgaBlackAndWhite(Img *img, ImgAny buf, ImgSz bufSz) 1693{ 1694 ImgStatus status; 1695 ImgSz expectedSize = (ImgSz)img->width * img->height * img->channelCount; 1696 ImgU8 *curr = buf; 1697 ImgU8 *end = curr + expectedSize; 1698 1699 ImgU32 pixelSize = BITS_TO_BYTES(img->tga.pixelDepth); 1700 ImgU8 pixel8; 1701 ImgU16 pixel16; 1702 ImgU32 pixel32; 1703 while(curr < end) { 1704 switch(pixelSize) { 1705 case 1: 1706 status = read(img, &pixel8, 1); 1707 if(status != ImgOK) { return status; } 1708 break; 1709 case 2: 1710 status = readU16LE(img, &pixel16); 1711 if(status != ImgOK) { return status; } 1712 pixel8 = pixel16 >> 8; 1713 break; 1714 case 3: 1715 status = readU24LE(img, &pixel32); 1716 if(status != ImgOK) { return status; } 1717 pixel8 = pixel32 >> 16; 1718 break; 1719 case 4: 1720 status = readU32LE(img, &pixel32); 1721 if(status != ImgOK) { return status; } 1722 pixel8 = pixel32 >> 24; 1723 break; 1724 default: 1725 return ImgErrTgaUnsupportedPixelDepth; 1726 } 1727 1728 *curr++ = pixel8; 1729 *curr++ = pixel8; 1730 *curr++ = pixel8; 1731 if(img->channelCount > 3) { 1732 *curr++ = 255; 1733 } 1734 } 1735 1736 return ImgOK; 1737} 1738 1739ImgStatus readTgaRleColorMapped(Img *img, ImgAny buf, ImgSz bufSz) 1740{ 1741 return ImgErrUnimplemented; 1742} 1743 1744ImgStatus readTgaRleTrueColor(Img *img, ImgAny buf, ImgSz bufSz) 1745{ 1746 return ImgErrUnimplemented; 1747} 1748 1749ImgStatus readTgaRleBlackAndWhite(Img *img, ImgAny buf, ImgSz bufSz) 1750{ 1751 return ImgErrUnimplemented; 1752} 1753 1754ImgStatus openGif(Img *img) 1755{ 1756 ImgStatus status; 1757 1758 /* skip over header */ 1759 status = seek(img, 6); 1760 if(status != ImgOK) { return status; } 1761 1762 ImgU16 width; 1763 ImgU16 height; 1764 1765 status = readU16LE(img, &width); 1766 if(status != ImgOK) { return status; } 1767 status = readU16LE(img, &height); 1768 if(status != ImgOK) { return status; } 1769 1770 img->width = width; 1771 img->height = height; 1772 img->channelCount = 4; 1773 1774 ImgU8 flags; 1775 status = read(img, &flags, 1); 1776 if(status != ImgOK) { return status; } 1777 1778 img->gif.globalColorTableFlag = flags >> 7; 1779 img->gif.colorResolution = (flags >> 4) & 7; 1780 img->gif.sortFlag = (flags >> 3) & 1; 1781 ImgU16 gctSize = flags & 7; 1782 img->gif.globalColorTableSize = 1 << (gctSize + 1); 1783 1784 if(img->gif.globalColorTableFlag) { 1785 status = read(img, img->gif.globalColorTable, 3 * img->gif.globalColorTableSize); 1786 if(status != ImgOK) { return status; } 1787 } 1788 1789 status = read(img, &img->gif.backgroundColorIndex, 1); 1790 if(status != ImgOK) { return status; } 1791 status = read(img, &img->gif.pixelAspectRatio, 1); 1792 if(status != ImgOK) { return status; } 1793 1794 return ImgOK; 1795} 1796 1797struct GifBlock { 1798 ImgU8 size; 1799 ImgU8 data[255]; 1800}; 1801 1802struct GifImage { 1803 ImgU16 left; 1804 ImgU16 right; 1805 ImgU16 width; 1806 ImgU16 height; 1807 ImgU8 localColorTableFlag; 1808 ImgU8 interlaceFlag; 1809 ImgU8 sortFlag; 1810 ImgU16 localColorTableSize; 1811 struct ImgGifColor localColorTable[256]; 1812 ImgU8 lzwCodeSize; 1813 struct GifBlock block; 1814}; 1815 1816#define GIF_TABLE_SIZE 5021 1817#define GIF_STACK_SIZE 1024 1818 1819struct GifDecompressor { 1820 struct GifImage gifImage; 1821 /* byte offset into current block */ 1822 ImgU16 byteOff; 1823 /* bit offset into current block byte */ 1824 ImgU8 bitOff; 1825 ImgU16 code; 1826 ImgU8 *curr; 1827 1828 ImgU8 stack[GIF_STACK_SIZE]; 1829 ImgU16 stackOff; 1830 1831 ImgU8 shade[GIF_TABLE_SIZE]; 1832 ImgU16 child[GIF_TABLE_SIZE]; 1833}; 1834 1835/* read the Image Descriptor + code size */ 1836static ImgStatus gifReadImage(Img *img, struct GifImage *desc); 1837static ImgStatus gifReadBlock(Img *img, struct GifBlock *block); 1838static ImgStatus gifDecompress(Img *img, struct GifDecompressor *decompressor); 1839 1840ImgStatus readGif(Img *img, ImgAny buf, ImgSz bufSz) 1841{ 1842 ImgStatus status; 1843 ImgSz expectedSize = (ImgSz)img->width * img->height * img->channelCount; 1844 ImgU8 *curr = buf; 1845 ImgU8 *end = curr + expectedSize; 1846 1847 struct GifDecompressor decompressor; 1848 ImgU8 trailer; 1849 1850 status = gifReadImage(img, &decompressor.gifImage); 1851 if(status != ImgOK) { return status; } 1852 1853 status = gifReadBlock(img, &decompressor.gifImage.block); 1854 if(status != ImgOK) { return status; } 1855 1856 decompressor.byteOff = 0; 1857 decompressor.bitOff = 0; 1858 decompressor.curr = curr; 1859 decompressor.stackOff = 0; 1860 status = gifDecompress(img, &decompressor); 1861 if(status != ImgOK) { return status; }; 1862 1863 status = read(img, &trailer, 1); 1864 if(status != ImgOK) { return status; } 1865 1866 if(trailer != 0x3B) { 1867 return ImgErrGifExpectedTrailer; 1868 } 1869 1870 return ImgOK; 1871} 1872 1873ImgStatus gifReadImage(Img *img, struct GifImage *gifImage) 1874{ 1875 ImgStatus status; 1876 ImgU8 identifier; 1877 1878 status = read(img, &identifier, 1); 1879 if(status != ImgOK) { return status; } 1880 if(identifier != 0x2C) { 1881 return ImgErrGifExpectedImageDescriptor; 1882 } 1883 1884 status = readU16LE(img, &gifImage->left); 1885 if(status != ImgOK) { return status; } 1886 status = readU16LE(img, &gifImage->right); 1887 if(status != ImgOK) { return status; } 1888 status = readU16LE(img, &gifImage->width); 1889 if(status != ImgOK) { return status; } 1890 status = readU16LE(img, &gifImage->height); 1891 if(status != ImgOK) { return status; } 1892 1893 ImgU8 flags; 1894 status = read(img, &flags, 1); 1895 if(status != ImgOK) { return status; } 1896 1897 gifImage->localColorTableFlag = flags >> 7; 1898 gifImage->interlaceFlag = (flags >> 6) & 1; 1899 gifImage->sortFlag = (flags >> 5) & 1; 1900 ImgU16 lctSize = flags & 7; 1901 gifImage->localColorTableSize = 1 << (lctSize + 1); 1902 1903 if(gifImage->localColorTableFlag) { 1904 status = read(img, gifImage->localColorTable, 3 * gifImage->localColorTableSize); 1905 if(status != ImgOK) { return status; } 1906 } 1907 1908 status = read(img, &gifImage->lzwCodeSize, 1); 1909 if(status != ImgOK) { return status; } 1910 1911 return ImgOK; 1912} 1913 1914ImgStatus gifReadBlock(Img *img, struct GifBlock *block) 1915{ 1916 ImgStatus status; 1917 1918 status = read(img, &block->size, 1); 1919 if(status != ImgOK) { return status; } 1920 1921 if(block->size) { 1922 status = read(img, block->data, block->size); 1923 if(status != ImgOK) { return status; } 1924 } 1925 1926 return ImgOK; 1927} 1928 1929ImgStatus gifDecompress(Img *img, struct GifDecompressor *dec) 1930{ 1931 return ImgErrUnimplemented; 1932}