#include #include #include #include #include "../compatibility/tnz4.h" #include "../compatibility/inforegion.h" #include "filebmp.h" /* typedef unsigned long ULONG; typedef unsigned short USHORT; typedef unsigned char UCHAR; typedef unsigned int UINT; typedef void IMAGERGB; typedef struct {USHORT m,b,g,r;} SPIXEL; #define CASE break; case #define __OR ; case #define DEFAULT break; default #define TRUE 1 #define FALSE 0 #define NIL (void*)0 */ 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; /* typedef struct bmpimage { int xsize,ysize; LPIXEL *buffer; BMP_SUBTYPE type; } IMAGE; */ #define UNUSED_REDUCE_COLORS /*---------------------------------------------------------------------------*/ /*-- Defines ----------------------------------------------------------------*/ #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; \ } /*---------------------------------------------------------------------------*/ /*-- Structures and Enums ---------------------------------------------------*/ 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; /*---------------------------------------------------------------------------*/ /*-- Prototypes -------------------------------------------------------------*/ 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); /*---------------------------------------------------------------------------*/ /*-- Local Prototypes -------------------------------------------------------*/ 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; /* return 0 for unsuccess */ } /*---------------------------------------------------------------------------*/ 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; /* 0 for unsuccess */ } /*---------------------------------------------------------------------------*/ 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) /*---------------------------------------------------------------------------*/ { /* error checking */ 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; } /* error checking */ 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; /* figure out the file size */ fseek(fp, 0L, SEEK_END); hd->biFilesize = ftell(fp); fseek(fp, 0L, 0); /* read the file type (first two bytes) */ c = getc(fp); c1 = getc(fp); if (c != 'B' || c1 != 'M') { free(hd); return UNSUPPORTED_BMP_FORMAT; } hd->bfSize = getint(fp); /* reserved and ignored */ 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 /* old bitmap format */ { hd->biWidth = getshort(fp); hd->biHeight = getshort(fp); hd->biPlanes = getshort(fp); hd->biBitCount = getshort(fp); /* Not in old versions so have to compute them */ 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; /* returns 'NULL' on unsuccess */ pic = (LPIXEL *)NULL; /* open image file */ fp = _wfopen(fname, L"rb"); if (!fp) return CANT_OPEN_FILE; /* load up the image header */ retCode = load_bmp_header(fp, &hd); if (retCode != OK) goto ERROR; /* error checking */ 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; } /* error checking */ 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); /* hd->biPad; */ if (hd->biSize != BMP_WIN_OS2_OLD) { /* skip ahead to colormap, using biSize */ c = hd->biSize - 40; /* 40 bytes read from biSize to biClrImportant */ for (i = 0; i < c; i++) getc(fp); hd->biPad = hd->bfOffBits - (hd->biSize + 14); } /* load up colormap, if any */ if (hd->biBitCount != 24) { int i, cmaplen; /*cmaplen = (hd->biClrUsed) ? hd->biClrUsed : 1 << hd->biBitCount;*/ 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) { /* Waste any unused bytes between the colour map (if present) and the start of the actual bitmap data. */ while (hd->biPad > 0) { (void)getc(fp); hd->biPad--; } } /* create 32 bit image buffer */ pic = (LPIXEL *)img->buffer; /* load up the image */ 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] /* ,*map[3] */; 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; /* initialize some variables */ i = pad = 0; /* returns 'NULL' on unsuccess */ pic = (LPIXEL *)NULL; /* open image file */ fp = _wfopen(fname, L"rb"); if (!fp) { return CANT_OPEN_FILE; } /* load up the image header */ load_bmp_header(fp, &hd); if (!hd) goto ERROR; /* error checking */ if ((hd->biBitCount != 1 && hd->biBitCount != 4 && hd->biBitCount != 8 && hd->biBitCount != 24) || hd->biPlanes != 1 || hd->biCompression > BMP_BI_RLE4) { snprintf(buf, sizeof(buf), "Bogus BMP File! (bitCount=%d, Planes=%d, Compression=%d)", hd->biBitCount, hd->biPlanes, hd->biCompression); bmp_error = UNSUPPORTED_BMP_FORMAT; goto ERROR; } /* error checking */ 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)) { snprintf(buf, sizeof(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) { /* skip ahead to colormap, using biSize */ c = hd->biSize - 40; /* 40 bytes read from biSize to biClrImportant */ for (i = 0; i < c; i++) getc(fp); hd->biPad = hd->bfOffBits - (hd->biSize + 14); } /* load up colormap, if any */ if (hd->biBitCount != 24) { int i, cmaplen; /*cmaplen = (hd->biClrUsed) ? hd->biClrUsed : 1 << hd->biBitCount;*/ 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) { /* Waste any unused bytes between the colour map (if present) and the start of the actual bitmap data. */ while (hd->biPad > 0) { (void)getc(fp); hd->biPad--; } } /* get information about the portion of the image to load */ get_info_region(&info, x1, y1, x2, y2, scale, (int)hd->biWidth, (int)hd->biHeight, TNZ_BOTLEFT); /* create 32 bit image buffer */ 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: /* segnala errore ed esci */ 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++; /* print_info_region(&info); */ 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; /* QUESTO SWITCH VA AGGIUSTATO! switch (subtype) { CASE BMP_BW: if (load_lineBMP1(fp, line, hd->biWidth, pad, map)) goto ERROR; CASE BMP_GREY16: __OR BMP_CMAPPED16: if (load_lineBMP4(fp, line, hd->biWidth, pad, map)) goto ERROR; CASE BMP_GREY16C: __OR BMP_CMAPPED16C: if (load_lineBMPC4(fp, line, hd->biWidth, i, map)==-1) goto ERROR; CASE BMP_GREY256: __OR BMP_CMAPPED256: if (load_lineBMP8(fp, line, hd->biWidth, pad, map)) goto ERROR; CASE BMP_GREY256C: __OR BMP_CMAPPED256C: if (load_lineBMPC8(fp, line, hd->biWidth, i, map)==-1) goto ERROR; CASE BMP_RGB: 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); } /* if (BMP_FERROR(fp)) { bmp_error(fname, "File appears truncated. Winging it.\n"); goto ERROR; } */ 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; /* 'w', padded to be a multiple of 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) /* read the next byte */ { 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) /* read the next byte */ { 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) /* read uncompressed data */ { padw = ((w + 7) / 8) * 8; /* 'w' padded to a multiple of 8pix (32 bits) */ 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) /* read next byte */ { 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) /* read RLE4 compressed data */ { 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) /* encoded mode */ { 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==0x00 : escape codes */ { c = getc(fp); if ((int)c == EOF) { rv = 1; break; } if (c == 0x00) /* end of line */ { x = 0; y++; if (y < h) pp = pic + x + (y)*w; } else if (c == 0x01) break; /* end of pic */ else if (c == 0x02) /* delta */ { c = getc(fp); x += c; c = getc(fp); y += c; if (y < h) pp = pic + x + (y)*w; } else /* absolute mode */ { 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)) /* read pad byte */ 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) /* read next byte */ { 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; /* * Codici di ritorno: * * -1: incontrata la file del file (EOF) * -2: incontrata la fine della linea (Escape code 0x00 0x00) * -3: incontrata la fine dell' immagine (Escape code 0x00 0x01) * altro: incontrato un delta (Escape code 0x00 0x02) */ /* initialize some variables */ x = 0; pp = pic; c = c1 = 0; while (1) { c = getc(fp); if ((int)c == EOF) return -1; if (c) { /* encoded mode */ 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==0x00 : escape codes */ { c = getc(fp); if ((int)c == EOF) return -1; if (c == 0x00) /* end of line */ return -2; else if (c == 0x01) /* end of pic */ return -3; else if (c == 0x02) /* delta */ { c = getc(fp); x += c; c = getc(fp); y += c; return (x + y * w); } else /* absolute mode */ { 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)) /* read pad byte */ 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); /* x buffer offest */ c1 = getc(fp); /* y buffer offest */ 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) /* read uncompressed data */ { padw = ((w + 3) / 4) * 4; /* 'w' padded to a multiple of 4pix (32 bits) */ 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) /* read RLE8 compressed data */ { 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) { /* encoded mode */ 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==0x00 : escape codes */ { c = getc(fp); if ((int)c == EOF) { rv = 1; break; } if (c == 0x00) /* end of line */ { x = 0; y++; pp = pic + x + y * w; } else if (c == 0x01) break; /* end of pic */ else if (c == 0x02) /* delta */ { c = getc(fp); x += c; c = getc(fp); y += c; pp = pic + x + y * w; } else /* absolute mode */ { 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) /* odd length run: read an extra pad byte */ 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; /* * Codici di ritorno: * * -1: incontrata la file del file (EOF) * -2: incontrata la fine della linea (Escape code 0x00 0x00) * -3: incontrata la fine dell' immagine (Escape code 0x00 0x01) * altro: incontrato un delta (Escape code 0x00 0x02) */ x = 0; pp = pic; while (1) { c = getc(fp); if (c == EOF) return -1; if (c) { /* encoded mode */ 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==0x00 : escape codes */ { c = getc(fp); if (c == EOF) return -1; if (c == 0x00) /* end of line */ return -2; else if (c == 0x01) /* end of pic */ return -3; else if (c == 0x02) /* delta */ { c = getc(fp); x += c; c = getc(fp); y += c; return (x + y * w); } else /* absolute mode */ { 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) /* odd length run: read an extra pad byte */ 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); /* x buffer offest */ c1 = getc(fp); /* y buffer offest */ 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; /* # of pad bytes to read at EOscanline */ 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); /* blue */ pp->g = getc(fp); /* green */ pp->r = getc(fp); /* red */ 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); /* blue */ pp->g = getc(fp); /* green */ pp->r = getc(fp); /* red */ 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 WRITE --------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ 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); /* BMP file magic number */ putint(fp, (int)hd->bfSize); putshort(fp, 0); /* reserved1 */ putshort(fp, 0); /* reserved2 */ putint(fp, (int)hd->bfOffBits); /* offset from BOfile to BObitmap */ putint(fp, (int)hd->biSize); /* size of bitmap info header */ putint(fp, (int)hd->biWidth); /* width */ putint(fp, (int)hd->biHeight); /* height */ putshort(fp, (int)hd->biPlanes); /* must be '1' */ putshort(fp, (int)hd->biBitCount); /* 1,4,8, or 24 */ putint(fp, (int)hd->biCompression); /* BMP_BI_RGB, BMP_BI_RLE8 or BMP_BI_RLE4 */ putint(fp, (int)hd->biSizeImage); /* size of raw image data */ putint(fp, (int)hd->biXPelsPerMeter); /* dpi * 39" per meter */ putint(fp, (int)hd->biYPelsPerMeter); /* dpi * 39" per meter */ putint(fp, (int)hd->biClrUsed); /* colors used in cmap */ putint(fp, (int)hd->biClrImportant); /* same as above */ 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; } /* number bytes written per line */ bperlin = ((w * nbits + 31) / 32) * 4; /* compute filesize and write it */ i = 14 + /* size of bitmap file header */ 40 + /* size of bitmap info header */ (nc * 4) + /* size of colormap */ bperlin * h; /* size of image data */ 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; } /* fill image header */ 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; } /* write out the image */ val = write_function(fp, pic, (unsigned int)w, (unsigned int)h, pc2nc); if (graypic) free(graypic); fclose(fp); /* 0 failed , 1 ok */ 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; /* 'w', padded to be a multiple of 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) /* write the next byte */ { 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) /* write the next byte */ { 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; /* 'w' padded to a multiple of 8pix (32 bits) */ 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) /* write next byte */ { 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) /* write next byte */ { 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; /* 'w' padded to a multiple of 4pix (32 bits) */ 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= 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; /* pc2nc not used */ padb = (4 - ((w * 3) % 4)) & 0x03; /* # of pad bytes to write at EOscanline */ 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; /* errors on colors */ r1 -= rmap[val]; g1 -= gmap[val]; b1 -= bmap[val]; if (j != jmax) BMP_ADD_ERROR(curr_pix[1], 7) /* RIGHT */ if (i != imax) /* UP */ { BMP_ADD_ERROR(*next_pix, 5) if (j > 0) BMP_ADD_ERROR(*prev_pix, 3) /* UP LEFT */ if (j != jmax) BMP_ADD_ERROR(next_pix[1], 1) /* UP RIGHT */ 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; }