| |
| |
| #include <stdio.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include <math.h> |
| |
| #include "../compatibility/tnz4.h" |
| #include "../compatibility/inforegion.h" |
| #include "filebmp.h" |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| typedef enum { |
| BMP_NONE, |
| BMP_BW, |
| BMP_GREY16, |
| BMP_GREY16C, |
| BMP_GREY256, |
| BMP_GREY256C, |
| BMP_CMAPPED16, |
| BMP_CMAPPED16C, |
| BMP_CMAPPED256, |
| BMP_CMAPPED256C, |
| BMP_RGB |
| |
| } BMP_SUBTYPE; |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| #define UNUSED_REDUCE_COLORS |
| |
| |
| |
| |
| #define BMP_BI_RGB 0 |
| #define BMP_BI_RLE8 1 |
| #define BMP_BI_RLE4 2 |
| |
| #define BMP_WIN_OS2_OLD 12 |
| #define BMP_WIN_NEW 40 |
| #define BMP_OS2_NEW 64 |
| |
| #define BMP_READ_INFO 1 |
| #define BMP_READ_IMAGE 2 |
| |
| #define BMP_FERROR(fp) (ferror(fp) || feof(fp)) |
| |
| #define BMP_RMAP(x) (x & 0xe0) | ((x & 0xe0) >> 3) | ((x & 0xc0) >> 6) |
| #define BMP_GMAP(x) ((x & 0x1c) << 3) | (x & 0x1c) | ((x & 0x18) >> 3) |
| #define BMP_BMAP(x) \ |
| ((x & 0x03) << 6) | ((x & 0x03) << 4) | ((x & 0x03) << 2) | (x & 0x03) |
| |
| #define BMP_RMAP16(x) \ |
| ((x & 0xc0) << 0) | ((x & 0xc0) >> 2) | ((x & 0xc0) >> 4) | ((x & 0xc0) >> 6) |
| #define BMP_GMAP16(x) \ |
| ((x & 0x60) << 1) | ((x & 0x60) >> 1) | ((x & 0x60) >> 3) | ((x & 0x60) >> 5) |
| #define BMP_BMAP16(x) \ |
| ((x & 0x30) << 2) | ((x & 0x30) << 0) | ((x & 0x30) >> 2) | ((x & 0x30) >> 4) |
| |
| #define BMP_CUT(a, b, c) \ |
| { \ |
| if (a < b) \ |
| a = b; \ |
| else if (a > c) \ |
| a = c; \ |
| } |
| |
| #define BMP_REDUCE_COLORS(r, g, b) \ |
| ((r & 0xe0) | ((g & 0xe0) >> 3) | ((b & 0xc0) >> 6)) |
| |
| #define BMP_ADD_ERROR(pix, weight) \ |
| { \ |
| tmp = (pix).r + ((r1 * weight) >> 4); \ |
| BMP_CUT(tmp, 0, 255); \ |
| (pix).r = tmp; \ |
| tmp = (pix).g + ((g1 * weight) >> 4); \ |
| BMP_CUT(tmp, 0, 255); \ |
| (pix).g = tmp; \ |
| tmp = (pix).b + ((b1 * weight) >> 4); \ |
| BMP_CUT(tmp, 0, 255); \ |
| (pix).b = tmp; \ |
| } |
| |
| #define BMP_ADD_ERROR_BW(pix, error) \ |
| { \ |
| tmp = (pix).r + (error); \ |
| BMP_CUT(tmp, 0, 255); \ |
| (pix).r = tmp; \ |
| tmp = (pix).g + (error); \ |
| BMP_CUT(tmp, 0, 255); \ |
| (pix).g = tmp; \ |
| tmp = (pix).b + (error); \ |
| BMP_CUT(tmp, 0, 255); \ |
| (pix).b = tmp; \ |
| } |
| |
| |
| |
| |
| typedef struct { |
| UINT bfSize; |
| UINT bfOffBits; |
| UINT biSize; |
| UINT biWidth; |
| UINT biHeight; |
| UINT biPlanes; |
| UINT biBitCount; |
| UINT biCompression; |
| UINT biSizeImage; |
| UINT biXPelsPerMeter; |
| UINT biYPelsPerMeter; |
| UINT biClrUsed; |
| UINT biClrImportant; |
| UINT biFilesize; |
| UINT biPad; |
| |
| } BMP_HEADER; |
| |
| |
| |
| |
| int load_bmp_header(FILE *fp, BMP_HEADER **pHd); |
| int write_bmp_header(FILE *fp, BMP_HEADER *hd); |
| void release_bmp_header(BMP_HEADER *hd); |
| |
| int write_bmp_palette(FILE *fp, int nc, UCHAR *b, UCHAR *g, UCHAR *r); |
| |
| int make_bmp_palette(int colors, int grey, UCHAR *r, UCHAR *g, UCHAR *b); |
| |
| BMP_SUBTYPE bmp_get_colorstyle(IMAGE *img); |
| |
| int error_checking_bmp(BMP_HEADER *hd); |
| |
| int read_bmp_line(FILE *fp, void *line, UINT w, UINT h, UCHAR **map, |
| BMP_SUBTYPE type); |
| |
| int write_bmp_line(FILE *fp, void *line_buffer, UINT w, UINT row, UCHAR *map, |
| BMP_SUBTYPE type); |
| |
| int skip_bmp_lines(FILE *fp, UINT w, UINT rows, int whence, BMP_SUBTYPE type); |
| |
| |
| |
| |
| static UINT getshort(FILE *fp); |
| static UINT getint(FILE *fp); |
| static void putshort(FILE *fp, int value); |
| static void putint(FILE *fp, int value); |
| |
| static int img_read_bmp_generic(const MYSTRING fname, int type, IMAGE **); |
| #ifndef UNUSED_REDUCE_COLORS |
| static UCHAR *reduce_colors(UCHAR *buffin, int xsize, int ysize, UCHAR *rmap, |
| UCHAR *gmap, UCHAR *bmap, int nc); |
| |
| #endif |
| |
| static int loadBMP1(FILE *fp, LPIXEL *pic, UINT w, UINT h, UCHAR *r, UCHAR *g, |
| UCHAR *b); |
| static int loadBMP4(FILE *fp, LPIXEL *pic, UINT w, UINT h, UINT comp, UCHAR *r, |
| UCHAR *g, UCHAR *b); |
| static int loadBMP8(FILE *fp, LPIXEL *pic, UINT w, UINT h, UINT comp, UCHAR *r, |
| UCHAR *g, UCHAR *b); |
| static int loadBMP24(FILE *fp, LPIXEL *pic, UINT w, UINT h); |
| |
| static int writeBMP1(FILE *fp, UCHAR *pic8, UINT w, UINT h, UCHAR *map); |
| static int writeBMP4(FILE *fp, UCHAR *pic8, UINT w, UINT h, UCHAR *map); |
| static int writeBMPC4(FILE *fp, UCHAR *pic8, UINT w, UINT h, UCHAR *map); |
| static int writeBMP8(FILE *fp, UCHAR *pic8, UINT w, UINT h, UCHAR *map); |
| static int writeBMPC8(FILE *fp, UCHAR *pic8, UINT w, UINT h, UCHAR *map); |
| static int writeBMP24(FILE *fp, UCHAR *pic24, UINT w, UINT h, UCHAR *map); |
| |
| static int load_lineBMP1(FILE *fp, LPIXEL *pic, UINT w, UINT padw, UCHAR **map); |
| static int load_lineBMP4(FILE *fp, LPIXEL *pic, UINT w, UINT padw, UCHAR **map); |
| static int load_lineBMPC4(FILE *fp, LPIXEL *pic, UINT w, UINT y, UCHAR **map); |
| static int load_lineBMP8(FILE *fp, LPIXEL *pic, UINT w, UINT padw, UCHAR **map); |
| static int load_lineBMPC8(FILE *fp, LPIXEL *pic, UINT w, UINT y, UCHAR **map); |
| static int load_lineBMP24(FILE *fp, LPIXEL *pic, UINT w, UINT padb); |
| |
| static int line_writeBMP1(FILE *fp, UCHAR *pic8, UINT w, UINT padw, |
| UCHAR *pc2nc); |
| static int line_writeBMP4(FILE *fp, UCHAR *pic8, UINT w, UINT padw, |
| UCHAR *pc2nc); |
| static int line_writeBMPC4(FILE *fp, UCHAR *pic8, UINT w, UINT row, |
| UCHAR *pc2nc); |
| static int line_writeBMP8(FILE *fp, UCHAR *pic8, UINT w, UINT padw, |
| UCHAR *pc2nc); |
| static int line_writeBMPC8(FILE *fp, UCHAR *pic8, UINT w, UINT row, |
| UCHAR *pc2nc); |
| static int line_writeBMP24(FILE *fp, LPIXEL *pp, UINT w, UINT padb); |
| |
| static int skip_rowsBMP1(FILE *fp, UINT w, UINT pad, UINT rows, int whence); |
| static int skip_rowsBMP4(FILE *fp, UINT w, UINT pad, UINT rows, int whence); |
| static int skip_rowsBMPC4(FILE *fp, UINT rows); |
| static int skip_rowsBMP8(FILE *fp, UINT w, UINT pad, UINT rows, int whence); |
| static int skip_rowsBMPC8(FILE *fp, UINT rows); |
| static int skip_rowsBMP24(FILE *fp, UINT w, UINT pad, UINT rows, int whence); |
| |
| #define BMP_DEBUG 0 |
| #define __BMP_WRITE_LINE_BY_LINE |
| #define __BMP_READ_LINE_BY_LINE |
| |
| |
| int read_bmp_line(FILE *fp, void *line_buffer, UINT w, UINT row, UCHAR **map, |
| BMP_SUBTYPE type) |
| |
| { |
| LPIXEL *pic = (LPIXEL *)line_buffer; |
| unsigned int pad; |
| int rv = 0; |
| |
| switch (type) { |
| case BMP_BW: |
| pad = ((w + 31) / 32) * 32; |
| rv = load_lineBMP1(fp, pic, w, pad, map); |
| CASE BMP_GREY16 : __OR BMP_CMAPPED16 : pad = ((w + 7) / 8) * 8; |
| rv = load_lineBMP4(fp, pic, w, pad, map); |
| CASE BMP_GREY16C : __OR BMP_CMAPPED16C |
| : rv = load_lineBMPC4(fp, pic, w, row, map); |
| if (rv == -1) |
| rv = 1; |
| else if (rv == -2) |
| rv = 0; |
| else if (rv == -3) |
| rv = 0; |
| else |
| rv = 0; |
| CASE BMP_GREY256 : __OR BMP_CMAPPED256 : pad = ((w + 3) / 4) * 4; |
| rv = load_lineBMP8(fp, pic, w, pad, map); |
| CASE BMP_GREY256C : __OR BMP_CMAPPED256C |
| : rv = load_lineBMPC8(fp, pic, w, row, map); |
| if (rv == -1) |
| rv = 1; |
| else if (rv == -2) |
| rv = 0; |
| else if (rv == -3) |
| rv = 0; |
| else |
| rv = 0; |
| CASE BMP_RGB : pad = (4 - ((w * 3) % 4)) & 0x03; |
| rv = load_lineBMP24(fp, pic, w, pad); |
| DEFAULT: |
| break; |
| } |
| |
| return !rv; |
| } |
| |
| |
| int write_bmp_line(FILE *fp, void *line_buffer, UINT w, UINT row, UCHAR *map, |
| BMP_SUBTYPE type) |
| |
| { |
| UCHAR *pic = (UCHAR *)line_buffer; |
| LPIXEL *p24 = (LPIXEL *)line_buffer; |
| unsigned int pad; |
| int rv = 0; |
| |
| switch (type) { |
| case BMP_BW: |
| pad = ((w + 31) / 32) * 32; |
| rv = line_writeBMP1(fp, pic, w, pad, map); |
| CASE BMP_GREY16 : __OR BMP_CMAPPED16 : pad = ((w + 7) / 8) * 8; |
| rv = line_writeBMP4(fp, pic, w, pad, map); |
| CASE BMP_GREY16C : __OR BMP_CMAPPED16C |
| : rv = line_writeBMPC4(fp, pic, w, row, map); |
| CASE BMP_GREY256 : __OR BMP_CMAPPED256 : pad = ((w + 3) / 4) * 4; |
| rv = line_writeBMP8(fp, pic, w, pad, map); |
| CASE BMP_GREY256C : __OR BMP_CMAPPED256C |
| : rv = line_writeBMPC8(fp, pic, w, row, map); |
| CASE BMP_RGB : pad = (4 - ((w * 3) % 4)) & 0x03; |
| rv = line_writeBMP24(fp, p24, w, pad); |
| DEFAULT: |
| break; |
| } |
| |
| return rv; |
| } |
| |
| |
| int skip_bmp_lines(FILE *fp, UINT w, UINT rows, int whence, BMP_SUBTYPE type) |
| |
| { |
| unsigned int pad; |
| int rv = 0; |
| |
| switch (type) { |
| case BMP_BW: |
| pad = ((w + 31) / 32) * 32; |
| rv = skip_rowsBMP1(fp, w, pad, rows, whence); |
| CASE BMP_GREY16 : __OR BMP_CMAPPED16 : pad = ((w + 7) / 8) * 8; |
| rv = skip_rowsBMP4(fp, w, pad, rows, whence); |
| CASE BMP_GREY16C : __OR BMP_CMAPPED16C : rv = skip_rowsBMPC4(fp, rows); |
| CASE BMP_GREY256 : __OR BMP_CMAPPED256 : pad = ((w + 3) / 4) * 4; |
| rv = skip_rowsBMP8(fp, w, pad, rows, whence); |
| CASE BMP_GREY256C : __OR BMP_CMAPPED256C : rv = skip_rowsBMPC8(fp, rows); |
| CASE BMP_RGB : pad = (4 - ((w * 3) % 4)) & 0x03; |
| rv = skip_rowsBMP24(fp, w, pad, rows, whence); |
| DEFAULT: |
| break; |
| } |
| |
| return !rv; |
| } |
| |
| |
| int error_checking_bmp(BMP_HEADER *hd) |
| |
| { |
| |
| if ((hd->biBitCount != 1 && hd->biBitCount != 4 && hd->biBitCount != 8 && |
| hd->biBitCount != 24) || |
| hd->biPlanes != 1 || hd->biCompression > BMP_BI_RLE4) { |
| return UNSUPPORTED_BMP_FORMAT; |
| } |
| |
| |
| if (((hd->biBitCount == 1 || hd->biBitCount == 24) && |
| hd->biCompression != BMP_BI_RGB) || |
| (hd->biBitCount == 4 && hd->biCompression == BMP_BI_RLE8) || |
| (hd->biBitCount == 8 && hd->biCompression == BMP_BI_RLE4)) { |
| return UNSUPPORTED_BMP_FORMAT; |
| } |
| |
| return OK; |
| } |
| |
| |
| int load_bmp_header(FILE *fp, BMP_HEADER **header) |
| |
| { |
| BMP_HEADER *hd = NULL; |
| int c, c1; |
| |
| *header = NULL; |
| |
| hd = (BMP_HEADER *)calloc((size_t)1, sizeof(BMP_HEADER)); |
| if (!hd) return OUT_OF_MEMORY; |
| |
| |
| fseek(fp, 0L, SEEK_END); |
| hd->biFilesize = ftell(fp); |
| fseek(fp, 0L, 0); |
| |
| |
| c = getc(fp); |
| c1 = getc(fp); |
| if (c != 'B' || c1 != 'M') { |
| free(hd); |
| return UNSUPPORTED_BMP_FORMAT; |
| } |
| |
| hd->bfSize = getint(fp); |
| |
| |
| getshort(fp); |
| getshort(fp); |
| |
| hd->bfOffBits = getint(fp); |
| hd->biSize = getint(fp); |
| |
| if (hd->biSize == BMP_WIN_NEW || hd->biSize == BMP_OS2_NEW) { |
| hd->biWidth = getint(fp); |
| hd->biHeight = getint(fp); |
| hd->biPlanes = getshort(fp); |
| hd->biBitCount = getshort(fp); |
| hd->biCompression = getint(fp); |
| hd->biSizeImage = getint(fp); |
| hd->biXPelsPerMeter = getint(fp); |
| hd->biYPelsPerMeter = getint(fp); |
| hd->biClrUsed = getint(fp); |
| hd->biClrImportant = getint(fp); |
| } else |
| { |
| hd->biWidth = getshort(fp); |
| hd->biHeight = getshort(fp); |
| hd->biPlanes = getshort(fp); |
| hd->biBitCount = getshort(fp); |
| |
| |
| hd->biSizeImage = |
| (((hd->biPlanes * hd->biBitCount * hd->biWidth) + 31) / 32) * 4 * |
| hd->biHeight; |
| |
| hd->biCompression = BMP_BI_RGB; |
| hd->biXPelsPerMeter = 0; |
| hd->biYPelsPerMeter = 0; |
| hd->biClrUsed = 0; |
| hd->biClrImportant = 0; |
| } |
| |
| if (BMP_DEBUG) { |
| printf("\nLoadBMP:\tbfSize=%u, bfOffBits=%u\n", hd->bfSize, hd->bfOffBits); |
| printf("\t\tbiSize=%u, biWidth=%u, biHeight=%u, biPlanes=%u\n", hd->biSize, |
| hd->biWidth, hd->biHeight, hd->biPlanes); |
| printf("\t\tbiBitCount=%u, biCompression=%u, biSizeImage=%u\n", |
| hd->biBitCount, hd->biCompression, hd->biSizeImage); |
| printf("\t\tbiX,YPelsPerMeter=%u,%u biClrUsed=%u, biClrImp=%u\n", |
| hd->biXPelsPerMeter, hd->biYPelsPerMeter, hd->biClrUsed, |
| hd->biClrImportant); |
| } |
| |
| if (BMP_FERROR(fp)) { |
| free(hd); |
| return UNEXPECTED_EOF; |
| } |
| |
| *header = hd; |
| return OK; |
| } |
| |
| |
| void release_bmp_header(BMP_HEADER *hd) |
| |
| { |
| if (hd) free(hd); |
| } |
| |
| #ifndef __LIBSIMAGE__ |
| |
| |
| int img_read_bmp(const MYSTRING fname, IMAGE **pimg) |
| |
| { |
| return img_read_bmp_generic(fname, BMP_READ_IMAGE, pimg); |
| } |
| |
| |
| static int img_read_bmp_generic(const MYSTRING fname, int type, IMAGE **pimg) |
| |
| { |
| int retCode = OK; |
| |
| UCHAR r[256], g[256], b[256]; |
| BMP_HEADER *hd = NULL; |
| IMAGE *img = NULL; |
| |
| int rv, c, i; |
| LPIXEL *pic; |
| FILE *fp; |
| |
| *pimg = 0; |
| |
| |
| |
| pic = (LPIXEL *)NULL; |
| |
| |
| fp = _wfopen(fname, L"rb"); |
| if (!fp) return CANT_OPEN_FILE; |
| |
| |
| retCode = load_bmp_header(fp, &hd); |
| if (retCode != OK) goto ERROR; |
| |
| |
| if ((hd->biBitCount != 1 && hd->biBitCount != 4 && hd->biBitCount != 8 && |
| hd->biBitCount != 24) || |
| hd->biPlanes != 1 || hd->biCompression > BMP_BI_RLE4) { |
| retCode = UNSUPPORTED_BMP_FORMAT; |
| goto ERROR; |
| } |
| |
| |
| if (((hd->biBitCount == 1 || hd->biBitCount == 24) && |
| hd->biCompression != BMP_BI_RGB) || |
| (hd->biBitCount == 4 && hd->biCompression == BMP_BI_RLE8) || |
| (hd->biBitCount == 8 && hd->biCompression == BMP_BI_RLE4)) { |
| retCode = UNSUPPORTED_BMP_FORMAT; |
| goto ERROR; |
| } |
| |
| img = new_img(); |
| img->type = TOONZRGB; |
| |
| if (type == BMP_READ_INFO) { |
| fclose(fp); |
| img->xSBsize = img->xsize = hd->biWidth; |
| img->ySBsize = img->ysize = hd->biHeight; |
| release_bmp_header(hd); |
| *pimg = img; |
| return OK; |
| } |
| |
| allocate_pixmap(img, (int)hd->biWidth, (int)hd->biHeight); |
| |
| |
| if (hd->biSize != BMP_WIN_OS2_OLD) { |
| |
| c = hd->biSize - 40; |
| for (i = 0; i < c; i++) getc(fp); |
| hd->biPad = hd->bfOffBits - (hd->biSize + 14); |
| } |
| |
| |
| if (hd->biBitCount != 24) { |
| int i, cmaplen; |
| |
| |
| if (hd->biClrUsed) |
| cmaplen = hd->biClrUsed; |
| else |
| cmaplen = 1 << hd->biBitCount; |
| |
| for (i = 0; i < cmaplen; i++) { |
| b[i] = getc(fp); |
| g[i] = getc(fp); |
| r[i] = getc(fp); |
| if (hd->biSize != BMP_WIN_OS2_OLD) { |
| getc(fp); |
| hd->biPad -= 4; |
| } |
| } |
| |
| if (BMP_FERROR(fp)) { |
| retCode = UNEXPECTED_EOF; |
| goto ERROR; |
| } |
| |
| if (BMP_DEBUG) { |
| printf("LoadBMP: BMP colormap: (RGB order)\n"); |
| for (i = 0; i < cmaplen; i++) printf("%02x%02x%02x ", r[i], g[i], b[i]); |
| printf("\n\n"); |
| } |
| } |
| |
| if (hd->biSize != BMP_WIN_OS2_OLD) { |
| |
| |
| |
| |
| while (hd->biPad > 0) { |
| (void)getc(fp); |
| hd->biPad--; |
| } |
| } |
| |
| |
| |
| pic = (LPIXEL *)img->buffer; |
| |
| |
| switch (hd->biBitCount) { |
| case 1: |
| rv = loadBMP1(fp, pic, hd->biWidth, hd->biHeight, r, g, b); |
| CASE 4 : rv = loadBMP4(fp, pic, hd->biWidth, hd->biHeight, |
| hd->biCompression, r, g, b); |
| CASE 8 : rv = loadBMP8(fp, pic, hd->biWidth, hd->biHeight, |
| hd->biCompression, r, g, b); |
| CASE 24 : rv = loadBMP24(fp, pic, hd->biWidth, hd->biHeight); |
| DEFAULT: |
| retCode = UNSUPPORTED_BMP_FORMAT; |
| goto ERROR; |
| } |
| |
| if (rv) { |
| retCode = UNEXPECTED_EOF; |
| goto ERROR; |
| } |
| |
| fclose(fp); |
| release_bmp_header(hd); |
| |
| *pimg = img; |
| return OK; |
| |
| ERROR: |
| |
| fclose(fp); |
| release_bmp_header(hd); |
| |
| if (img) { |
| TFREE(img->buffer) |
| TFREE(img) |
| } |
| |
| return retCode; |
| } |
| |
| #endif /* __LIBSIMAGE__ */ |
| |
| static int img_read_bmp_region(const MYSTRING fname, IMAGE **pimg, int x1, |
| int y1, int x2, int y2, int scale) { |
| UCHAR r[256], g[256], b[256] ; |
| LPIXEL *line = NULL; |
| UINT line_size = 0; |
| BMP_HEADER *hd = NULL; |
| EXT_INFO_REGION info; |
| BMP_SUBTYPE subtype; |
| LPIXEL *pic, *appo; |
| IMAGE *img = NULL; |
| UINT start_offset; |
| UINT c, i, j; |
| char buf[512]; |
| FILE *fp; |
| UINT pad; |
| enum BMP_ERROR_CODE bmp_error = OK; |
| |
| |
| i = pad = 0; |
| |
| |
| pic = (LPIXEL *)NULL; |
| |
| |
| fp = _wfopen(fname, L"rb"); |
| if (!fp) { |
| return CANT_OPEN_FILE; |
| } |
| |
| |
| load_bmp_header(fp, &hd); |
| if (!hd) goto ERROR; |
| |
| |
| if ((hd->biBitCount != 1 && hd->biBitCount != 4 && hd->biBitCount != 8 && |
| hd->biBitCount != 24) || |
| hd->biPlanes != 1 || hd->biCompression > BMP_BI_RLE4) { |
| sprintf(buf, "Bogus BMP File! (bitCount=%d, Planes=%d, Compression=%d)", |
| hd->biBitCount, hd->biPlanes, hd->biCompression); |
| |
| bmp_error = UNSUPPORTED_BMP_FORMAT; |
| goto ERROR; |
| } |
| |
| |
| if (((hd->biBitCount == 1 || hd->biBitCount == 24) && |
| hd->biCompression != BMP_BI_RGB) || |
| (hd->biBitCount == 4 && hd->biCompression == BMP_BI_RLE8) || |
| (hd->biBitCount == 8 && hd->biCompression == BMP_BI_RLE4)) { |
| sprintf(buf, "Bogus BMP File! (bitCount=%d, Compression=%d)", |
| hd->biBitCount, hd->biCompression); |
| bmp_error = UNSUPPORTED_BMP_FORMAT; |
| goto ERROR; |
| } |
| |
| img = new_img(); |
| |
| img->type = TOONZRGB; |
| |
| img->xsize = hd->biWidth; |
| img->ysize = hd->biHeight; |
| img->xSBsize = hd->biWidth; |
| img->ySBsize = hd->biHeight; |
| img->x_dpi = (double)(hd->biXPelsPerMeter / 39); |
| img->y_dpi = (double)(hd->biYPelsPerMeter / 39); |
| |
| hd->biPad = 0; |
| if (hd->biSize != BMP_WIN_OS2_OLD) { |
| |
| c = hd->biSize - 40; |
| for (i = 0; i < c; i++) getc(fp); |
| hd->biPad = hd->bfOffBits - (hd->biSize + 14); |
| } |
| |
| |
| if (hd->biBitCount != 24) { |
| int i, cmaplen; |
| |
| |
| if (hd->biClrUsed) |
| cmaplen = hd->biClrUsed; |
| else |
| cmaplen = hd->biBitCount; |
| |
| for (i = 0; i < cmaplen; i++) { |
| b[i] = getc(fp); |
| g[i] = getc(fp); |
| r[i] = getc(fp); |
| if (hd->biSize != BMP_WIN_OS2_OLD) { |
| getc(fp); |
| hd->biPad -= 4; |
| } |
| } |
| |
| if (BMP_FERROR(fp)) { |
| bmp_error = UNEXPECTED_EOF; |
| goto ERROR; |
| } |
| |
| if (BMP_DEBUG) { |
| printf("LoadBMP: BMP colormap: (RGB order)\n"); |
| for (i = 0; i < cmaplen; i++) printf("%02x%02x%02x ", r[i], g[i], b[i]); |
| printf("\n\n"); |
| } |
| } |
| |
| if (hd->biSize != BMP_WIN_OS2_OLD) { |
| |
| |
| |
| |
| while (hd->biPad > 0) { |
| (void)getc(fp); |
| hd->biPad--; |
| } |
| } |
| |
| |
| get_info_region(&info, x1, y1, x2, y2, scale, (int)hd->biWidth, |
| (int)hd->biHeight, TNZ_BOTLEFT); |
| |
| |
| if (!allocate_pixmap(img, info.xsize, info.ysize)) { |
| bmp_error = OUT_OF_MEMORY; |
| goto ERROR; |
| } |
| |
| start_offset = info.y_offset * info.xsize + info.x_offset; |
| pic = ((LPIXEL *)img->buffer) + start_offset; |
| |
| if (line_size < hd->biWidth + 32) { |
| line_size = hd->biWidth + 32; |
| if (!line) |
| TCALLOC((LPIXEL *)line, (size_t)line_size) |
| else |
| TREALLOC(line, line_size) |
| } |
| if (!line) { |
| bmp_error = OUT_OF_MEMORY; |
| goto ERROR; |
| } |
| |
| switch (hd->biBitCount) { |
| case 1: |
| pad = ((hd->biWidth + 31) / 32) * 32; |
| CASE 4 : pad = ((hd->biWidth + 7) / 8) * 8; |
| CASE 8 : pad = ((hd->biWidth + 3) / 4) * 4; |
| CASE 24 : pad = (4 - ((hd->biWidth * 3) % 4)) & 0x03; |
| DEFAULT: |
| |
| break; |
| } |
| |
| subtype = bmp_get_colorstyle(img); |
| if (subtype == BMP_NONE) goto ERROR; |
| |
| if (info.y_offset > 0) info.scanNrow++; |
| if (info.x_offset > 0) info.scanNcol++; |
| |
| |
| |
| if (info.startScanRow > 0) |
| skip_bmp_lines(fp, hd->biWidth, (unsigned int)(info.startScanRow - 1), |
| (unsigned int)SEEK_CUR, subtype); |
| |
| for (i = 0; i < (UINT)info.scanNrow; i++) { |
| if (load_lineBMP24(fp, line, hd->biWidth, pad)) goto ERROR; |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| for (appo = pic, j = c = 0; j < (UINT)info.scanNcol; j++, c += info.step) |
| *appo++ = *(line + info.startScanCol + c); |
| pic += info.xsize; |
| |
| skip_bmp_lines(fp, hd->biWidth, (unsigned int)(info.step - 1), |
| (unsigned int)SEEK_CUR, subtype); |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| fclose(fp); |
| release_bmp_header(hd); |
| TFREE(line); |
| *pimg = img; |
| return OK; |
| |
| ERROR: |
| |
| printf("error: (row=%d)\n", i); |
| |
| fclose(fp); |
| release_bmp_header(hd); |
| |
| if (img) free_img(img); |
| TFREE(line); |
| return bmp_error; |
| } |
| |
| static int loadBMP1(FILE *fp, LPIXEL *pic, UINT w, UINT h, UCHAR *r, UCHAR *g, |
| UCHAR *b) |
| |
| { |
| UINT i, j, c, bitnum, padw, rv; |
| UCHAR byte; |
| LPIXEL *pp; |
| #ifdef BMP_READ_LINE_BY_LINE |
| UCHAR *map[3]; |
| |
| map[0] = r; |
| map[1] = g; |
| map[2] = b; |
| #endif |
| |
| rv = c = 0; |
| padw = ((w + 31) / 32) * 32; |
| |
| for (i = 0; i < h; i++) { |
| #ifdef BMP_READ_LINE_BY_LINE |
| pp = pic + (i * w); |
| rv = load_lineBMP1(fp, pp, w, padw, map); |
| if (rv) break; |
| #else |
| pp = pic + (i * w); |
| for (j = bitnum = 0; j < padw; j++, bitnum++) { |
| if ((bitnum & 7) == 0) |
| { |
| c = getc(fp); |
| bitnum = 0; |
| } |
| if (j < w) { |
| byte = (c & 0x80) ? 1 : 0; |
| c <<= 1; |
| |
| pp->r = r[byte]; |
| pp->g = g[byte]; |
| pp->b = b[byte]; |
| pp->m = 255; |
| |
| pp++; |
| } |
| } |
| if (BMP_FERROR(fp)) break; |
| #endif |
| } |
| |
| if (BMP_FERROR(fp)) rv = 1; |
| |
| return rv; |
| } |
| |
| |
| int load_lineBMP1(FILE *fp, LPIXEL *pic, UINT w, UINT padw, UCHAR **map) |
| |
| { |
| UINT j, c, bitnum; |
| UCHAR byte; |
| LPIXEL *pp; |
| |
| for (c = 0, pp = pic, j = bitnum = 0; j < padw; j++, bitnum++) { |
| if ((bitnum & 7) == 0) |
| { |
| c = getc(fp); |
| bitnum = 0; |
| } |
| if (j < w) { |
| byte = (c & 0x80) ? 1 : 0; |
| c <<= 1; |
| |
| pp->r = map[0][byte]; |
| pp->g = map[1][byte]; |
| pp->b = map[2][byte]; |
| pp->m = 255; |
| |
| pp++; |
| } |
| } |
| |
| return (BMP_FERROR(fp)); |
| } |
| |
| |
| static int skip_rowsBMP1(FILE *fp, UINT w, UINT pad, UINT rows, int whence) |
| |
| { |
| UINT offset = pad * rows; |
| UINT i, bitnum; |
| |
| for (i = bitnum = 0; i < offset; i++, bitnum++) { |
| if ((bitnum & 7) == 0) { |
| getc(fp); |
| bitnum = 0; |
| } |
| } |
| |
| return (BMP_FERROR(fp)); |
| } |
| |
| |
| static int loadBMP4(FILE *fp, LPIXEL *pic, UINT w, UINT h, UINT comp, UCHAR *r, |
| UCHAR *g, UCHAR *b) |
| |
| { |
| UINT i, j, c, c1, x, y, nybnum, padw, rv; |
| UCHAR byte; |
| LPIXEL *pp; |
| #ifdef BMP_READ_LINE_BY_LINE |
| UCHAR *map[3]; |
| |
| map[0] = r; |
| map[1] = g; |
| map[2] = b; |
| #endif |
| |
| rv = 0; |
| c = c1 = 0; |
| |
| if (comp == BMP_BI_RGB) |
| { |
| padw = ((w + 7) / 8) * 8; |
| for (i = 0; i < h; i++) { |
| pp = pic + (i * w); |
| #ifdef BMP_READ_LINE_BY_LINE |
| rv = load_lineBMP4(fp, pp, w, padw, map); |
| if (rv) break; |
| #else |
| for (j = nybnum = 0; j < padw; j++, nybnum++) { |
| if ((nybnum & 1) == 0) |
| { |
| c = getc(fp); |
| nybnum = 0; |
| } |
| if (j < w) { |
| byte = (c & 0xf0) >> 4; |
| c <<= 4; |
| |
| pp->r = r[byte]; |
| pp->g = g[byte]; |
| pp->b = b[byte]; |
| pp->m = 255; |
| |
| pp++; |
| } |
| } |
| if (BMP_FERROR(fp)) break; |
| #endif |
| } |
| } else if (comp == BMP_BI_RLE4) |
| { |
| x = y = 0; |
| pp = pic + x + (y)*w; |
| while (y < h) { |
| #ifdef BMP_READ_LINE_BY_LINE |
| |
| rv = load_lineBMPC4(fp, pp, w, y, map); |
| if (rv == -1) { |
| rv = 1; |
| break; |
| } else if (rv == -2) { |
| rv = 0; |
| y++; |
| pp = pic + y * w; |
| } else if (rv == -3) { |
| rv = 0; |
| break; |
| } else { |
| y += (rv / w); |
| pp = pic + rv; |
| rv = 0; |
| } |
| |
| #else |
| c = getc(fp); |
| if ((int)c == EOF) { |
| rv = 1; |
| break; |
| } |
| |
| if (c) |
| { |
| c1 = getc(fp); |
| for (i = 0; i < c; i++, x++, pp++) { |
| byte = (i & 1) ? (c1 & 0x0f) : ((c1 >> 4) & 0x0f); |
| pp->r = r[byte]; |
| pp->g = g[byte]; |
| pp->b = b[byte]; |
| pp->m = 255; |
| } |
| } else |
| { |
| c = getc(fp); |
| if ((int)c == EOF) { |
| rv = 1; |
| break; |
| } |
| |
| if (c == 0x00) |
| { |
| x = 0; |
| y++; |
| if (y < h) pp = pic + x + (y)*w; |
| } else if (c == 0x01) |
| break; |
| else if (c == 0x02) |
| { |
| c = getc(fp); |
| x += c; |
| c = getc(fp); |
| y += c; |
| if (y < h) pp = pic + x + (y)*w; |
| } else |
| { |
| for (i = 0; i < c; i++, x++, pp++) { |
| if ((i & 1) == 0) c1 = getc(fp); |
| byte = (i & 1) ? (c1 & 0x0f) : ((c1 >> 4) & 0x0f); |
| pp->r = r[byte]; |
| pp->g = g[byte]; |
| pp->b = b[byte]; |
| pp->m = 255; |
| } |
| if (((c & 3) == 1) || ((c & 3) == 2)) |
| getc(fp); |
| } |
| } |
| if (BMP_FERROR(fp)) break; |
| #endif |
| } |
| } else { |
| return 1; |
| } |
| |
| if (BMP_FERROR(fp)) rv = 1; |
| |
| return rv; |
| } |
| |
| |
| int load_lineBMP4(FILE *fp, LPIXEL *pic, UINT w, UINT padw, UCHAR **map) |
| |
| { |
| UINT nybnum, j, c; |
| UCHAR byte; |
| LPIXEL *pp; |
| |
| for (c = 0, pp = pic, j = nybnum = 0; j < padw; j++, nybnum++) { |
| if ((nybnum & 1) == 0) |
| { |
| c = getc(fp); |
| nybnum = 0; |
| } |
| if (j < w) { |
| byte = (c & 0xf0) >> 4; |
| c <<= 4; |
| |
| pp->r = map[0][byte]; |
| pp->g = map[1][byte]; |
| pp->b = map[2][byte]; |
| pp->m = 255; |
| |
| pp++; |
| } |
| } |
| |
| return (BMP_FERROR(fp)); |
| } |
| |
| |
| static int skip_rowsBMP4(FILE *fp, UINT w, UINT pad, UINT rows, int whence) |
| |
| { |
| UINT offset = pad * rows; |
| UINT i, nybnum; |
| |
| for (i = nybnum = 0; i < offset; i++, nybnum++) { |
| if ((nybnum & 1) == 0) { |
| getc(fp); |
| nybnum = 0; |
| } |
| } |
| |
| return (BMP_FERROR(fp)); |
| } |
| |
| |
| int load_lineBMPC4(FILE *fp, LPIXEL *pic, UINT w, UINT y, UCHAR **map) |
| |
| { |
| UINT i, c, c1, x; |
| UCHAR byte; |
| LPIXEL *pp; |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| x = 0; |
| pp = pic; |
| c = c1 = 0; |
| |
| while (1) { |
| c = getc(fp); |
| if ((int)c == EOF) return -1; |
| if (c) { |
| c1 = getc(fp); |
| for (i = 0; i < c; i++, x++, pp++) { |
| byte = (i & 1) ? (c1 & 0x0f) : ((c1 >> 4) & 0x0f); |
| pp->r = map[0][byte]; |
| pp->g = map[1][byte]; |
| pp->b = map[2][byte]; |
| pp->m = 255; |
| } |
| } else |
| { |
| c = getc(fp); |
| if ((int)c == EOF) return -1; |
| if (c == 0x00) |
| return -2; |
| else if (c == 0x01) |
| return -3; |
| else if (c == 0x02) |
| { |
| c = getc(fp); |
| x += c; |
| c = getc(fp); |
| y += c; |
| |
| return (x + y * w); |
| } else |
| { |
| for (i = 0; i < c; i++, x++, pp++) { |
| if ((i & 1) == 0) c1 = getc(fp); |
| byte = (i & 1) ? (c1 & 0x0f) : ((c1 >> 4) & 0x0f); |
| pp->r = map[0][byte]; |
| pp->g = map[1][byte]; |
| pp->b = map[2][byte]; |
| pp->m = 255; |
| } |
| if (((c & 3) == 1) || ((c & 3) == 2)) |
| getc(fp); |
| } |
| } |
| if (BMP_FERROR(fp)) break; |
| } |
| |
| return -1; |
| } |
| |
| |
| static int skip_rowsBMPC4(FILE *fp, UINT rows) |
| |
| { |
| UINT i, c, c1, rv = 0; |
| |
| while (rows > 0) { |
| c = getc(fp); |
| switch (c) { |
| case 0x00: |
| c = getc(fp); |
| switch (c) { |
| case 0x00: |
| rows--; |
| CASE 0x01 : rows = 0; |
| CASE 0x02 : c1 = getc(fp); |
| c1 = getc(fp); |
| rows -= c1; |
| DEFAULT: |
| for (i = 0; i < c; i++) { |
| if ((i & 1) == 0) getc(fp); |
| } |
| if (((c & 3) == 1) || ((c & 3) == 2)) getc(fp); |
| } |
| DEFAULT: |
| c1 = getc(fp); |
| } |
| } |
| |
| if (BMP_FERROR(fp)) rv = 1; |
| |
| return rv; |
| } |
| |
| |
| static int loadBMP8(FILE *fp, LPIXEL *pic, UINT w, UINT h, UINT comp, UCHAR *r, |
| UCHAR *g, UCHAR *b) |
| |
| { |
| UINT i, j, c, c1, padw, x, y, rv; |
| |
| LPIXEL *pp; |
| #ifdef BMP_READ_LINE_BY_LINE |
| UCHAR *map[3]; |
| |
| map[0] = r; |
| map[1] = g; |
| map[2] = b; |
| #endif |
| |
| rv = 0; |
| |
| if (comp == BMP_BI_RGB) |
| { |
| padw = ((w + 3) / 4) * 4; |
| for (i = 0; i < h; i++) { |
| #ifdef BMP_READ_LINE_BY_LINE |
| pp = pic + (i * w); |
| rv = load_lineBMP8(fp, pp, w, padw, map); |
| if (rv) break; |
| #else |
| pp = pic + (i * w); |
| for (j = 0; j < padw; j++) { |
| c = getc(fp); |
| if ((int)c == EOF) rv = 1; |
| if (j < w) { |
| pp->r = r[c]; |
| pp->g = g[c]; |
| pp->b = b[c]; |
| pp->m = 255; |
| |
| pp++; |
| } |
| } |
| if (BMP_FERROR(fp)) break; |
| #endif |
| } |
| } else if (comp == BMP_BI_RLE8) |
| { |
| x = y = 0; |
| pp = pic + x + y * w; |
| while (y < h) { |
| #ifdef BMP_READ_LINE_BY_LINE |
| |
| rv = load_lineBMPC8(fp, pp, w, y, map); |
| if (rv == -1) { |
| rv = 1; |
| break; |
| } else if (rv == -2) { |
| rv = 0; |
| y++; |
| pp = pic + y * w; |
| } else if (rv == -3) { |
| rv = 0; |
| break; |
| } else { |
| y += (rv / w); |
| pp = pic + rv; |
| rv = 0; |
| } |
| |
| #else |
| c = getc(fp); |
| if ((int)c == EOF) { |
| rv = 1; |
| break; |
| } |
| |
| if (c) { |
| c1 = getc(fp); |
| for (i = 0; i < c; i++, x++, pp++) { |
| pp->r = r[c1]; |
| pp->g = g[c1]; |
| pp->b = b[c1]; |
| pp->m = 255; |
| } |
| } else |
| { |
| c = getc(fp); |
| if ((int)c == EOF) { |
| rv = 1; |
| break; |
| } |
| |
| if (c == 0x00) |
| { |
| x = 0; |
| y++; |
| pp = pic + x + y * w; |
| } else if (c == 0x01) |
| break; |
| else if (c == 0x02) |
| { |
| c = getc(fp); |
| x += c; |
| c = getc(fp); |
| y += c; |
| pp = pic + x + y * w; |
| } else |
| { |
| for (i = 0; i < c; i++, x++, pp++) { |
| c1 = getc(fp); |
| |
| pp->r = r[c1]; |
| pp->g = g[c1]; |
| pp->b = b[c1]; |
| pp->m = 255; |
| } |
| if (c & 1) |
| getc(fp); |
| } |
| } |
| if (BMP_FERROR(fp)) break; |
| #endif |
| } |
| } else { |
| return 1; |
| } |
| |
| if (BMP_FERROR(fp)) rv = 1; |
| |
| return rv; |
| } |
| |
| |
| int load_lineBMP8(FILE *fp, LPIXEL *pic, UINT w, UINT padw, UCHAR **map) |
| |
| { |
| UINT j, c, rv = 0; |
| LPIXEL *pp; |
| |
| for (pp = pic, j = 0; j < padw; j++) { |
| c = getc(fp); |
| if ((int)c == EOF) { |
| rv = 1; |
| break; |
| } |
| if (j < w) { |
| pp->r = map[0][c]; |
| pp->g = map[1][c]; |
| pp->b = map[2][c]; |
| pp->m = 255; |
| |
| pp++; |
| } |
| } |
| if (BMP_FERROR(fp)) rv = 1; |
| |
| return rv; |
| } |
| |
| |
| static int skip_rowsBMP8(FILE *fp, UINT w, UINT pad, UINT rows, int whence) |
| |
| { |
| UINT offset = pad * rows; |
| |
| fseek(fp, (long)offset, whence); |
| |
| return (BMP_FERROR(fp)); |
| } |
| |
| |
| int load_lineBMPC8(FILE *fp, LPIXEL *pic, UINT w, UINT y, UCHAR **map) |
| |
| { |
| int i, c, c1, x; |
| LPIXEL *pp; |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| x = 0; |
| pp = pic; |
| |
| while (1) { |
| c = getc(fp); |
| if (c == EOF) return -1; |
| if (c) { |
| c1 = getc(fp); |
| for (i = 0; i < c; i++, x++, pp++) { |
| pp->r = map[0][c1]; |
| pp->g = map[1][c1]; |
| pp->b = map[2][c1]; |
| pp->m = 255; |
| } |
| } else |
| { |
| c = getc(fp); |
| if (c == EOF) return -1; |
| if (c == 0x00) |
| return -2; |
| else if (c == 0x01) |
| return -3; |
| else if (c == 0x02) |
| { |
| c = getc(fp); |
| x += c; |
| c = getc(fp); |
| y += c; |
| |
| return (x + y * w); |
| } else |
| { |
| for (i = 0; i < c; i++, x++, pp++) { |
| c1 = getc(fp); |
| |
| pp->r = map[0][c1]; |
| pp->g = map[1][c1]; |
| pp->b = map[2][c1]; |
| pp->m = 255; |
| } |
| if (c & 1) |
| getc(fp); |
| } |
| } |
| } |
| } |
| |
| |
| static int skip_rowsBMPC8(FILE *fp, UINT rows) |
| |
| { |
| int i, c, c1, rv = 0; |
| |
| while (rows > 0) { |
| c = getc(fp); |
| switch (c) { |
| case 0x00: |
| c = getc(fp); |
| switch (c) { |
| case 0x00: |
| rows--; |
| CASE 0x01 : rows = 0; |
| CASE 0x02 : c1 = getc(fp); |
| c1 = getc(fp); |
| rows -= c1; |
| DEFAULT: |
| for (i = 0; i < c; i++) getc(fp); |
| if (c & 1) getc(fp); |
| } |
| DEFAULT: |
| c1 = getc(fp); |
| } |
| } |
| |
| if (BMP_FERROR(fp)) rv = 1; |
| |
| return rv; |
| } |
| |
| |
| static int loadBMP24(FILE *fp, LPIXEL *pic, UINT w, UINT h) |
| |
| { |
| UINT i, j, padb, rv; |
| LPIXEL *pp; |
| |
| rv = 0; |
| |
| padb = (4 - ((w * 3) % 4)) & 0x03; |
| |
| for (i = 0; i < h; i++) { |
| #ifdef BMP_READ_LINE_BY_LINE |
| pp = pic + i * w; |
| rv = load_lineBMP24(fp, pp, w, padb); |
| #else |
| for (pp = pic + i * w, j = 0; j < w; j++, pp++) { |
| pp->b = getc(fp); |
| pp->g = getc(fp); |
| pp->r = getc(fp); |
| pp->m = 255; |
| } |
| for (j = 0; j < padb; j++) getc(fp); |
| |
| rv = (BMP_FERROR(fp)); |
| #endif |
| if (rv) break; |
| } |
| |
| return rv; |
| } |
| |
| |
| int load_lineBMP24(FILE *fp, LPIXEL *pic, UINT w, UINT padb) |
| |
| { |
| LPIXEL *pp; |
| UINT j; |
| |
| for (pp = pic, j = 0; j < w; j++, pp++) { |
| pp->b = getc(fp); |
| pp->g = getc(fp); |
| pp->r = getc(fp); |
| pp->m = 255; |
| } |
| for (j = 0; j < padb; j++) getc(fp); |
| |
| return (BMP_FERROR(fp)); |
| } |
| |
| |
| static int skip_rowsBMP24(FILE *fp, UINT w, UINT pad, UINT rows, int whence) |
| |
| { |
| UINT offset = (w * 3 + pad) * rows; |
| |
| fseek(fp, (long)offset, whence); |
| |
| return (BMP_FERROR(fp)); |
| } |
| |
| |
| |
| |
| |
| BMP_SUBTYPE bmp_get_colorstyle(IMAGE *img) |
| |
| { |
| return img->type; |
| } |
| |
| |
| int write_bmp_header(FILE *fp, BMP_HEADER *hd) |
| |
| { |
| putc('B', fp); |
| putc('M', fp); |
| |
| putint(fp, (int)hd->bfSize); |
| putshort(fp, 0); |
| putshort(fp, 0); |
| |
| putint(fp, (int)hd->bfOffBits); |
| |
| putint(fp, (int)hd->biSize); |
| putint(fp, (int)hd->biWidth); |
| putint(fp, (int)hd->biHeight); |
| putshort(fp, (int)hd->biPlanes); |
| putshort(fp, (int)hd->biBitCount); |
| putint(fp, |
| (int)hd->biCompression); |
| putint(fp, (int)hd->biSizeImage); |
| putint(fp, (int)hd->biXPelsPerMeter); |
| putint(fp, (int)hd->biYPelsPerMeter); |
| putint(fp, (int)hd->biClrUsed); |
| putint(fp, (int)hd->biClrImportant); |
| |
| if (BMP_FERROR(fp)) return FALSE; |
| |
| return TRUE; |
| } |
| |
| |
| int write_bmp_palette(FILE *fp, int nc, UCHAR *b, UCHAR *g, UCHAR *r) |
| |
| { |
| int i; |
| |
| for (i = 0; i < nc; i++) { |
| putc(b[i], fp); |
| putc(g[i], fp); |
| putc(r[i], fp); |
| putc(0, fp); |
| } |
| |
| if (BMP_FERROR(fp)) return FALSE; |
| |
| return TRUE; |
| } |
| |
| #ifndef __LIBSIMAGE__ |
| |
| |
| int img_write_bmp(const MYSTRING fname, IMAGE *img) |
| |
| { |
| int (*write_function)(FILE * fp, UCHAR * pic, UINT w, UINT h, UCHAR * map); |
| int h, w, i, nc, nbits, bperlin, comp; |
| UCHAR val; |
| UCHAR pc2nc[256], r1[256], g1[256], b1[256]; |
| UCHAR *pic, *graypic; |
| BMP_SUBTYPE subtype; |
| BMP_HEADER hd; |
| FILE *fp; |
| |
| subtype = bmp_get_colorstyle(img); |
| if (subtype == BMP_NONE) return UNSUPPORTED_BMP_FORMAT; |
| |
| fp = _wfopen(fname, L"wb"); |
| if (!fp) return CANT_OPEN_FILE; |
| |
| graypic = NULL; |
| nc = 0; |
| nbits = 0; |
| comp = 0; |
| h = img->ysize; |
| w = img->xsize; |
| pic = (UCHAR *)img->buffer; |
| |
| switch (subtype) { |
| case BMP_BW: |
| __OR BMP_GREY16 : __OR BMP_GREY16C : |
| |
| __OR BMP_CMAPPED256 : __OR BMP_CMAPPED256C |
| : return UNSUPPORTED_BMP_FORMAT; |
| CASE BMP_GREY256 : __OR BMP_GREY256C : nbits = 8; |
| CASE BMP_RGB : nbits = 24; |
| DEFAULT: |
| goto BMP_WRITE_ERROR; |
| } |
| |
| |
| bperlin = ((w * nbits + 31) / 32) * 4; |
| |
| |
| i = 14 + |
| 40 + |
| (nc * 4) + |
| bperlin * h; |
| |
| switch (nbits) { |
| case 4: |
| comp = (comp == TRUE) ? BMP_BI_RLE4 : BMP_BI_RGB; |
| CASE 8 : comp = (comp == TRUE) ? BMP_BI_RLE8 : BMP_BI_RGB; |
| DEFAULT: |
| comp = BMP_BI_RGB; |
| } |
| |
| |
| hd.bfSize = i; |
| hd.bfOffBits = 14 + 40 + (nc * 4); |
| hd.biSize = 40; |
| hd.biWidth = w; |
| hd.biHeight = h; |
| hd.biPlanes = 1; |
| hd.biBitCount = nbits; |
| hd.biCompression = comp; |
| hd.biSizeImage = bperlin * h; |
| hd.biXPelsPerMeter = 0 * 39; |
| hd.biYPelsPerMeter = 0 * 39; |
| hd.biClrUsed = nc; |
| hd.biClrImportant = nc; |
| |
| if (!write_bmp_header(fp, &hd)) goto BMP_WRITE_ERROR; |
| |
| write_bmp_palette(fp, nc, b1, g1, r1); |
| |
| switch (nbits) { |
| case 1: |
| write_function = writeBMP1; |
| CASE 4 : if (comp == BMP_BI_RGB) write_function = writeBMP4; |
| else write_function = writeBMPC4; |
| CASE 8 : if (comp == BMP_BI_RGB) write_function = writeBMP8; |
| else write_function = writeBMPC8; |
| CASE 24 : write_function = writeBMP24; |
| DEFAULT: |
| goto BMP_WRITE_ERROR; |
| } |
| |
| |
| val = write_function(fp, pic, (unsigned int)w, (unsigned int)h, pc2nc); |
| |
| if (graypic) free(graypic); |
| fclose(fp); |
| |
| |
| return val == 1 ? OK : WRITE_ERROR; |
| |
| BMP_WRITE_ERROR: |
| |
| fclose(fp); |
| if (graypic) free(graypic); |
| |
| _wremove(fname); |
| |
| return WRITE_ERROR; |
| } |
| |
| #endif /* __LIBSIMAGE__ */ |
| |
| |
| static int writeBMP1(FILE *fp, UCHAR *pic8, UINT w, UINT h, UCHAR *pc2nc) |
| |
| { |
| UINT i, j, c, bitnum, padw; |
| UCHAR *pp; |
| |
| padw = ((w + 31) / 32) * 32; |
| |
| for (i = 0; i < h; i++) { |
| pp = pic8 + (i * w); |
| #ifdef BMP_WRITE_LINE_BY_LINE |
| if (line_writeBMP1(fp, pp, w, padw, pc2nc) == FALSE) return FALSE; |
| #else |
| for (j = bitnum = c = 0; j <= padw; j++, bitnum++) { |
| if (bitnum == 8) |
| { |
| putc((int)c, fp); |
| bitnum = c = 0; |
| } |
| c <<= 1; |
| if (j < w) { |
| c |= (pc2nc[*pp++] & 0x01); |
| } |
| } |
| #endif |
| } |
| if (BMP_FERROR(fp)) return FALSE; |
| |
| return TRUE; |
| } |
| |
| |
| static int line_writeBMP1(FILE *fp, UCHAR *pic8, UINT w, UINT padw, |
| UCHAR *pc2nc) |
| |
| { |
| UCHAR *pp = pic8; |
| UINT j, c, bitnum; |
| |
| for (j = bitnum = c = 0; j <= padw; j++, bitnum++) { |
| if (bitnum == 8) |
| { |
| putc((int)c, fp); |
| bitnum = c = 0; |
| } |
| c <<= 1; |
| if (j < w) { |
| c |= (pc2nc[*pp++] & 0x01); |
| } |
| } |
| if (BMP_FERROR(fp)) return FALSE; |
| |
| return TRUE; |
| } |
| |
| |
| static int writeBMP4(FILE *fp, UCHAR *pic8, UINT w, UINT h, UCHAR *pc2nc) |
| |
| { |
| UINT i, j, c, nybnum, padw; |
| UCHAR *pp; |
| |
| padw = ((w + 7) / 8) * 8; |
| |
| for (i = 0; i < h; i++) { |
| pp = pic8 + (i * w); |
| #ifdef BMP_WRITE_LINE_BY_LINE |
| if (line_writeBMP4(fp, pp, w, padw, pc2nc) == FALSE) return FALSE; |
| #else |
| for (j = nybnum = c = 0; j <= padw; j++, nybnum++) { |
| if (nybnum == 2) |
| { |
| putc((int)(c & 0xff), fp); |
| nybnum = c = 0; |
| } |
| c <<= 4; |
| if (j < w) { |
| c |= (pc2nc[*pp] & 0x0f); |
| pp++; |
| } |
| } |
| #endif |
| } |
| if (BMP_FERROR(fp)) return FALSE; |
| |
| return TRUE; |
| } |
| |
| |
| static int line_writeBMP4(FILE *fp, UCHAR *pic8, UINT w, UINT padw, |
| UCHAR *pc2nc) |
| |
| { |
| UINT j, c, nybnum; |
| UCHAR *pp = pic8; |
| |
| for (j = nybnum = c = 0; j <= padw; j++, nybnum++) { |
| if (nybnum == 2) |
| { |
| putc((int)(c & 0xff), fp); |
| nybnum = c = 0; |
| } |
| c <<= 4; |
| if (j < w) { |
| c |= (pc2nc[*pp] & 0x0f); |
| pp++; |
| } |
| } |
| if (BMP_FERROR(fp)) return FALSE; |
| |
| return TRUE; |
| } |
| |
| |
| static int writeBMPC4(FILE *fp, UCHAR *pic8, UINT w, UINT h, UCHAR *pc2nc) |
| |
| { |
| UCHAR *pp1, *pp2, *pp3, byte1, byte2; |
| UINT i, cnt; |
| |
| for (i = 0; i < h; i++) { |
| pp1 = pic8 + i * w; |
| pp2 = pp1 + 2; |
| pp3 = pp1 + w + 2; |
| |
| for (; pp2 < pp3; pp2 += 2) { |
| cnt = 2; |
| |
| byte1 = ((pc2nc[*pp1] << 4) & 0xf0) | (pc2nc[*(pp1 + 1)] & 0x0f); |
| byte2 = ((pc2nc[*pp2] << 4) & 0xf0) | (pc2nc[*(pp2 + 1)] & 0x0f); |
| |
| if (byte1 != byte2) { |
| putc((int)cnt, fp); |
| putc(byte1, fp); |
| pp1 = pp2; |
| } else { |
| while (cnt <= 254 && pp2 < pp3) { |
| cnt += 2; |
| pp2 += 2; |
| byte2 = ((pc2nc[*pp2] << 4) & 0xf0) | (pc2nc[*(pp2 + 1)] & 0x0f); |
| if (byte1 != byte2 || cnt >= 254 || pp2 + 2 > pp3) { |
| if (pp2 + 2 > pp3) cnt -= 2; |
| putc((int)cnt, fp); |
| putc(byte1, fp); |
| break; |
| } |
| } |
| pp1 = pp2; |
| } |
| } |
| putc(0x00, fp); |
| putc(0x00, fp); |
| if (BMP_FERROR(fp)) return FALSE; |
| } |
| putc(0x00, fp); |
| putc(0x01, fp); |
| |
| if (BMP_FERROR(fp)) return FALSE; |
| |
| return TRUE; |
| } |
| |
| |
| static int line_writeBMPC4(FILE *fp, UCHAR *pic8, UINT w, UINT row, |
| UCHAR *pc2nc) |
| |
| { |
| UCHAR *pp1, *pp2, *pp3, byte1, byte2; |
| UINT cnt; |
| |
| pp1 = pic8 + row * w; |
| pp2 = pp1 + 2; |
| pp3 = pp1 + w + 2; |
| |
| for (; pp2 < pp3; pp2 += 2) { |
| cnt = 2; |
| |
| byte1 = ((pc2nc[*pp1] << 4) & 0xf0) | (pc2nc[*(pp1 + 1)] & 0x0f); |
| byte2 = ((pc2nc[*pp2] << 4) & 0xf0) | (pc2nc[*(pp2 + 1)] & 0x0f); |
| |
| if (byte1 != byte2) { |
| putc((int)cnt, fp); |
| putc(byte1, fp); |
| pp1 = pp2; |
| } else { |
| while (cnt <= 254 && pp2 < pp3) { |
| cnt += 2; |
| pp2 += 2; |
| byte2 = ((pc2nc[*pp2] << 4) & 0xf0) | (pc2nc[*(pp2 + 1)] & 0x0f); |
| if (byte1 != byte2 || cnt >= 254 || pp2 + 2 > pp3) { |
| if (pp2 + 2 > pp3) cnt -= 2; |
| putc((int)cnt, fp); |
| putc(byte1, fp); |
| break; |
| } |
| } |
| pp1 = pp2; |
| } |
| } |
| putc(0x00, fp); |
| putc(0x00, fp); |
| |
| if (BMP_FERROR(fp)) return FALSE; |
| |
| return TRUE; |
| } |
| |
| |
| static int writeBMP8(FILE *fp, UCHAR *pic8, UINT w, UINT h, UCHAR *pc2nc) |
| |
| { |
| UINT i, j, padw; |
| UCHAR *pp; |
| |
| padw = ((w + 3) / 4) * 4; |
| |
| for (i = 0; i < h; i++) { |
| pp = pic8 + (i * w); |
| #ifdef BMP_WRITE_LINE_BY_LINE |
| if (line_writeBMP8(fp, pp, w, padw, pc2nc) == FALSE) return FALSE; |
| #else |
| |
| for (j = 0; j < w; j++) { |
| putc(*pp, fp); |
| pp++; |
| } |
| for (; j < padw; j++) putc(0, fp); |
| #endif |
| } |
| if (BMP_FERROR(fp)) return FALSE; |
| |
| return TRUE; |
| } |
| |
| |
| static int line_writeBMP8(FILE *fp, UCHAR *pic8, UINT w, UINT padw, |
| UCHAR *pc2nc) |
| |
| { |
| UCHAR *pp = pic8; |
| UINT j; |
| |
| for (j = 0; j < w; j++) putc(pc2nc[*pp++], fp); |
| for (; j < padw; j++) putc(0, fp); |
| if (BMP_FERROR(fp)) return FALSE; |
| |
| return TRUE; |
| } |
| |
| |
| static int writeBMPC8(FILE *fp, UCHAR *pic8, UINT w, UINT h, UCHAR *pc2nc) |
| |
| { |
| UCHAR *pp1, *pp2, *pp3, byte1, byte2; |
| UINT i, cnt; |
| |
| for (i = 0; i < h; i++) { |
| pp1 = pic8 + i * w; |
| pp2 = pp1 + 1; |
| pp3 = pp1 + w + 1; |
| |
| for (; pp2 < pp3; pp2++) { |
| cnt = 1; |
| |
| byte1 = pc2nc[*pp1]; |
| byte2 = pc2nc[*pp2]; |
| |
| if (byte1 != byte2) { |
| putc((int)cnt, fp); |
| putc(byte1, fp); |
| pp1 = pp2; |
| } else { |
| while (cnt <= 254 && pp2 < pp3) { |
| cnt++; |
| pp2++; |
| byte2 = pc2nc[*pp2]; |
| if (byte1 != byte2 || cnt >= 254 || pp2 + 1 > pp3) { |
| if (pp2 + 1 > pp3) cnt--; |
| putc((int)cnt, fp); |
| putc(byte1, fp); |
| break; |
| } |
| } |
| pp1 = pp2; |
| } |
| } |
| putc(0x00, fp); |
| putc(0x00, fp); |
| if (BMP_FERROR(fp)) return FALSE; |
| } |
| putc(0x00, fp); |
| putc(0x01, fp); |
| |
| if (BMP_FERROR(fp)) return FALSE; |
| |
| return TRUE; |
| } |
| |
| |
| static int line_writeBMPC8(FILE *fp, UCHAR *pic8, UINT w, UINT row, |
| UCHAR *pc2nc) |
| |
| { |
| UCHAR *pp1, *pp2, *pp3, byte1, byte2; |
| UINT cnt; |
| |
| pp1 = pic8 + row * w; |
| pp2 = pp1 + 1; |
| pp3 = pp1 + w + 1; |
| |
| for (; pp2 < pp3; pp2++) { |
| cnt = 1; |
| |
| byte1 = pc2nc[*pp1]; |
| byte2 = pc2nc[*pp2]; |
| |
| if (byte1 != byte2) { |
| putc((int)cnt, fp); |
| putc(byte1, fp); |
| pp1 = pp2; |
| } else { |
| while (cnt <= 254 && pp2 < pp3) { |
| cnt++; |
| pp2++; |
| byte2 = pc2nc[*pp2]; |
| if (byte1 != byte2 || cnt >= 254 || pp2 + 1 > pp3) { |
| if (pp2 + 1 > pp3) cnt--; |
| putc((int)cnt, fp); |
| putc(byte1, fp); |
| break; |
| } |
| } |
| pp1 = pp2; |
| } |
| } |
| putc(0x00, fp); |
| putc(0x00, fp); |
| |
| if (BMP_FERROR(fp)) return FALSE; |
| |
| return TRUE; |
| } |
| |
| |
| static int writeBMP24(FILE *fp, UCHAR *pic24, UINT w, UINT h, UCHAR *whence) |
| |
| { |
| UINT i, j, padb; |
| LPIXEL *pixel; |
| UCHAR *pp; |
| |
| |
| |
| padb = (4 - ((w * 3) % 4)) & 0x03; |
| |
| for (i = 0; i < h; i++) { |
| pp = pic24 + (i * w * 4); |
| pixel = (LPIXEL *)pp; |
| #ifdef BMP_WRITE_LINE_BY_LINE |
| if (line_writeBMP24(fp, pixel, w, padb) == FALSE) return FALSE; |
| #else |
| for (j = 0; j < w; j++) { |
| putc(pixel->b, fp); |
| putc(pixel->g, fp); |
| putc(pixel->r, fp); |
| |
| pixel++; |
| } |
| for (j = 0; j < padb; j++) putc(0, fp); |
| #endif |
| } |
| if (BMP_FERROR(fp)) return FALSE; |
| |
| return TRUE; |
| } |
| |
| |
| static int line_writeBMP24(FILE *fp, LPIXEL *pp, UINT w, UINT padb) |
| |
| { |
| UINT j; |
| |
| for (j = 0; j < w; j++) { |
| putc(pp->b, fp); |
| putc(pp->g, fp); |
| putc(pp->r, fp); |
| |
| pp++; |
| } |
| for (j = 0; j < padb; j++) putc(0, fp); |
| if (BMP_FERROR(fp)) return FALSE; |
| |
| return TRUE; |
| } |
| |
| #ifndef __LIBSIMAGE__ |
| |
| #ifndef UNUSED_REDUCE_COLORS |
| |
| static UCHAR *reduce_colors(UCHAR *buffin, int xsize, int ysize, UCHAR *rmap, |
| UCHAR *gmap, UCHAR *bmap, int nc) |
| |
| { |
| LPIXEL *curr_pix, *next_pix, *prev_pix, *buffer; |
| static LPIXEL *mbuffer = NULL; |
| static UCHAR *ret_buf = NULL; |
| static int outbuf_size = 0; |
| static int buffin_size = 0; |
| int r1, g1, b1, dim; |
| int i, j, tmp; |
| int imax, jmax; |
| UCHAR *outbuf; |
| USHORT val; |
| |
| dim = xsize * ysize; |
| |
| if (dim > outbuf_size) { |
| if (!ret_buf) |
| TCALLOC(ret_buf, dim) |
| else |
| TREALLOC(ret_buf, dim); |
| if (!ret_buf) return NULL; |
| outbuf_size = dim; |
| } |
| |
| if (dim > buffin_size) { |
| if (!mbuffer) |
| TCALLOC(mbuffer, dim) |
| else |
| TREALLOC(mbuffer, dim); |
| if (!ret_buf) return NULL; |
| buffin_size = dim; |
| } |
| |
| memcpy(mbuffer, buffin, dim * sizeof(LPIXEL)); |
| buffer = mbuffer; |
| outbuf = ret_buf; |
| |
| imax = ysize - 1; |
| jmax = xsize - 1; |
| |
| for (i = 0; i < ysize; i++) { |
| curr_pix = buffer; |
| buffer += xsize; |
| next_pix = buffer; |
| prev_pix = NIL; |
| |
| for (j = 0; j < xsize; j++) { |
| r1 = curr_pix->r; |
| g1 = curr_pix->g; |
| b1 = curr_pix->b; |
| |
| val = BMP_REDUCE_COLORS(r1, g1, b1); |
| |
| *(outbuf++) = (unsigned char)val; |
| |
| |
| r1 -= rmap[val]; |
| g1 -= gmap[val]; |
| b1 -= bmap[val]; |
| |
| if (j != jmax) BMP_ADD_ERROR(curr_pix[1], 7) |
| if (i != imax) |
| { |
| BMP_ADD_ERROR(*next_pix, 5) |
| if (j > 0) BMP_ADD_ERROR(*prev_pix, 3) |
| if (j != jmax) BMP_ADD_ERROR(next_pix[1], 1) |
| prev_pix = next_pix; |
| next_pix++; |
| } |
| curr_pix++; |
| } |
| } |
| |
| return ret_buf; |
| } |
| #endif |
| |
| #endif /* __LIBSIMAGE__ */ |
| |
| |
| int make_bmp_palette(int colors, int grey, UCHAR *r, UCHAR *g, UCHAR *b) |
| |
| { |
| int i, j, ind, val; |
| |
| switch (colors) { |
| case 2: |
| for (i = 0; i < 2; i++) r[i] = g[i] = b[i] = i * 255; |
| CASE 16 : for (i = 0; i < 16; i++) { |
| for (j = 0; j < 16; j++) { |
| ind = i * 16 + j; |
| val = i * 16; |
| r[ind] = g[ind] = b[ind] = val; |
| } |
| } |
| CASE 256 : if (grey) { |
| for (i = 0; i < 256; i++) r[i] = g[i] = b[i] = i; |
| } |
| else { |
| for (i = 0; i < 256; i++) { |
| r[i] = BMP_RMAP(i); |
| g[i] = BMP_GMAP(i); |
| b[i] = BMP_BMAP(i); |
| } |
| } |
| DEFAULT: |
| return FALSE; |
| } |
| |
| return TRUE; |
| } |
| |
| |
| static UINT getshort(FILE *fp) |
| |
| { |
| int c = getc(fp), c1 = getc(fp); |
| |
| return ((UINT)c) + (((UINT)c1) << 8); |
| } |
| |
| |
| static UINT getint(FILE *fp) |
| |
| { |
| int c = getc(fp), c1 = getc(fp), c2 = getc(fp), c3 = getc(fp); |
| |
| return (((UINT)c) << 0) + (((UINT)c1) << 8) + (((UINT)c2) << 16) + |
| (((UINT)c3) << 24); |
| } |
| |
| |
| static void putshort(FILE *fp, int i) |
| |
| { |
| int c = (((UINT)i)) & 0xff, c1 = (((UINT)i) >> 8) & 0xff; |
| |
| putc(c, fp); |
| putc(c1, fp); |
| } |
| |
| |
| static void putint(FILE *fp, int i) |
| |
| { |
| int c = ((UINT)i) & 0xff, c1 = (((UINT)i) >> 8) & 0xff, |
| c2 = (((UINT)i) >> 16) & 0xff, c3 = (((UINT)i) >> 24) & 0xff; |
| |
| putc(c, fp); |
| putc(c1, fp); |
| putc(c2, fp); |
| putc(c3, fp); |
| } |
| |
| |
| |
| int writebmp(const MYSTRING filename, int xsize, int ysize, void *buffer, |
| int bpp) { |
| IMAGE img; |
| img.xsize = xsize; |
| img.ysize = ysize; |
| img.buffer = buffer; |
| switch (bpp) { |
| case 8: |
| img.type = BMP_GREY256C; |
| CASE 32 : img.type = BMP_RGB; |
| } |
| return img_write_bmp(filename, &img); |
| } |
| |
| |
| |
| int readbmp(const MYSTRING filename, int *xsize, int *ysize, void **buffer) { |
| IMAGE *img; |
| int retCode = img_read_bmp(filename, &img); |
| if (retCode != OK) { |
| *xsize = *ysize = 0; |
| *buffer = 0; |
| } else { |
| *xsize = img->xsize; |
| *ysize = img->ysize; |
| *buffer = img->buffer; |
| img->buffer = 0; |
| free_img(img); |
| } |
| return retCode; |
| } |
| |
| |
| |
| int readbmpregion(const MYSTRING filename, void **pimg, int x1, int y1, int x2, |
| int y2, int scale) { |
| IMAGE *img; |
| |
| int retCode = img_read_bmp_region(filename, &img, x1, y1, x2, y2, scale); |
| |
| if (retCode != OK) { |
| *pimg = 0; |
| } else { |
| *pimg = img->buffer; |
| free(img); |
| } |
| return retCode; |
| } |
| |
| |
| int readbmp_size(const MYSTRING fname, int *lx, int *ly) { |
| IMAGE *img; |
| int retCode = img_read_bmp_generic(fname, BMP_READ_INFO, &img); |
| if (retCode == OK) { |
| *lx = img->xsize; |
| *ly = img->ysize; |
| free(img); |
| } |
| return retCode; |
| } |
| |
| |
| |
| int readbmp_bbox(const MYSTRING fname, int *x0, int *y0, int *x1, int *y1) { |
| IMAGE *img; |
| int retCode = img_read_bmp_generic(fname, BMP_READ_INFO, &img); |
| if (retCode == OK) { |
| *x0 = 0; |
| *x1 = 0; |
| *x1 = img->xsize - 1; |
| *y1 = img->ysize - 1; |
| free(img); |
| } |
| return retCode; |
| } |
| |