📄 readbmp.c
字号:
/* zgv 5.5 - GIF, JPEG, PNM and BMP viewer, for VGA PCs running Linux. * Copyright (C) 1993-2001 Russell Marks. See README for license details. * * readbmp.c - BMP loader. * * BMP support by Carsten Engelmann (based on readpnm.c). *//* portability fixes RJM 2001 May 25 */#include <stdio.h>#include <string.h>#include <stdlib.h>#include <ctype.h>#include <unistd.h>#include <sys/stat.h>#include "zgv.h"#include "readbmp.h"#include "readpnm.h" /* for dithering routines */#include "rcfile.h"#include "rc_config.h"/* prototypes */static int flip (byte * image, unsigned int w, unsigned int h);/* for aborted_file_bmp_cleanup() */static unsigned char *work_bmap, *work_pal;static FILE *work_in;#define BMPGET2(x) ((x)[0]|((x)[1]<<8))#define BMPGET4(x) ((x)[0]|((x)[1]<<8)|((x)[2]<<16)|((x)[3]<<24))void read_bch(BITMAPCOREHEADER *bchp,unsigned char *ptr){bchp->bcSize=BMPGET4(ptr); ptr+=4;bchp->bcWidth=BMPGET2(ptr); ptr+=2;bchp->bcHeight=BMPGET2(ptr); ptr+=2;bchp->bcPlanes=BMPGET2(ptr); ptr+=2;bchp->bcBitCount=BMPGET2(ptr);}void read_bih(BITMAPINFOHEADER *bihp,unsigned char *ptr){bihp->biSize=BMPGET4(ptr); ptr+=4;bihp->biWidth=BMPGET4(ptr); ptr+=4;bihp->biHeight=BMPGET4(ptr); ptr+=4;bihp->biPlanes=BMPGET2(ptr); ptr+=2;bihp->biBitCount=BMPGET2(ptr); ptr+=2;bihp->biCompression=BMPGET4(ptr); ptr+=4;bihp->biSizeImage=BMPGET4(ptr); ptr+=4;bihp->biXPelsPerMeter=BMPGET4(ptr); ptr+=4;bihp->biYPelsPerMeter=BMPGET4(ptr); ptr+=4;bihp->biClrUsed=BMPGET4(ptr); ptr+=4;bihp->biClrImportant=BMPGET4(ptr);}int read_bmp_file (char *filename, hffunc howfarfunc, unsigned char **bmap, unsigned char **pal, int *output_type, PICINFO *pp){ FILE *in; int i, j; int iswindows = 0; int dummy, count, done, bytepp, bytes_in_image; unsigned char *buf; unsigned char read[2]; unsigned char *p; unsigned char *ptr, *dptr, *hptr; unsigned int w; unsigned int h; unsigned int palsize; BITMAPINFOHEADER bih; BITMAPCOREHEADER bch; *bmap = NULL; *pal = NULL; if ((work_in = in = fopen (filename, "rb")) == NULL) return (_PICERR_NOFILE); if ((buf = malloc (54)) == NULL) CLOSE_AND_RET(_PICERR_NOMEM); fread (buf, 1, 26, in); if (buf[0] != 'B') CLOSE_AND_RET(_PICERR_BADMAGIC); if (buf[1] != 'M') CLOSE_AND_RET(_PICERR_BADMAGIC); read_bch(&bch,buf+14); iswindows=0; if (bch.bcSize == 40) /* truly MS_Windows 3.x ?*/ { fread (buf + 26, 1, 28, in);/* then we need the rest */ read_bih(&bih,buf+14); iswindows = 1; } if ((p = calloc (768,1)) == NULL) CLOSE_AND_RET(_PICERR_NOMEM); /* only actually used if using dither 8-bit display of 24-bit image, * but defined always */ make_332_palette(p); palsize=(buf[10]|(buf[11]<<8)|(buf[12]<<16)|(buf[13]<<24)); if (iswindows) /* MS_Windows 3.x */ { pp->width = w = bih.biWidth; pp->height = h = bih.biHeight; pp->bpp = bih.biBitCount; /* Here the "offbits" - we need 'em for the * palette size - e.g. XV uses different sizes */ palsize=(palsize-54)/4; } else /* OS/2 V1.1 */ { pp->width = w = bch.bcWidth; pp->height = h = bch.bcHeight; pp->bpp = bch.bcBitCount; palsize=(palsize-26)/3; /* in case these are used later -rjm */ bih.biWidth=bch.bcWidth; bih.biHeight=bch.bcHeight; } if (w == 0 || h == 0 || palsize > 256) CLOSE_AND_RET(_PICERR_CORRUPT); if ((pp->bpp >> 3) < 3) *output_type = 1; /* w is the size of a horizontal line in bytes * bih.biWidth is the number of valid pixels in a line * the latter one is passed to vgadisp.c as pp->width */ switch (pp->bpp) { case 1: if (w % 32) w = (w / 32) * 32 + 32; break; case 4: if (w % 8) w = (w / 8) * 8 + 8; break; case 8: if (w % 4) w = (w / 4) * 4 + 4; break; case 24: if ((w * 3) % 4) w = (w * 3 / 4) * 4 + 4; else w = w * 3; break; default: CLOSE_AND_RET(_PICERR_CORRUPT); } if (w == 0 || h == 0) CLOSE_AND_RET(_PICERR_CORRUPT); if ((*pal = calloc (768,1)) == NULL) CLOSE_AND_RET(_PICERR_NOMEM); bytepp=1; if ((pp->bpp == 24) && (*output_type == 3)) bytepp = 3; if ((work_bmap = *bmap = calloc (w * (h + 2) * bytepp,1)) == NULL) CLOSE_AND_RET(_PICERR_NOMEM); bytes_in_image=w*h*bytepp; /* this should be used whenever adding a file-input-dependent amount * to the current position pointer. It's > rather than >= so that we * can point *just* past the end having read in data, which is ok. */#define FAIL_FOR_BAD_OFFSET(cur,add) \ do {if((cur)+(add)>bytes_in_image) CLOSE_AND_RET(_PICERR_CORRUPT);} while(0) /* if you look at the stuff below, `p' is the palette * which would be right to free by the time we're actually * reading the image, so... */ work_pal=p; free(buf); switch (pp->bpp) { case 1: /* 1bit non compressed */ ptr = *pal; fread (ptr , 1, 3, in); if (iswindows) fread (&dummy, 1, 1, in); fread (ptr + 3, 1, 3, in); if (iswindows) fread (&dummy, 1, 1, in); for (i = 0; i < 2; i++) { p[i] = ptr[3 * i + 2]; p[i + 256] = ptr[3 * i + 1]; p[i + 512] = ptr[3 * i]; } free (*pal); *pal = p; ptr = *bmap; for (j = h - 1; j >= 0; j--) for (i = 0, count=0 ; i < (w >> 3); i++) { hptr = ptr + j * pp->width; dummy = fgetc (in); if (count < pp->width) { hptr[count] = (dummy & 128)?1:0;count++; hptr[count] = (dummy & 64)?1:0;count++; hptr[count] = (dummy & 32)?1:0;count++; hptr[count] = (dummy & 16)?1:0;count++; hptr[count] = (dummy & 8)?1:0;count++; hptr[count] = (dummy & 4)?1:0;count++; hptr[count] = (dummy & 2)?1:0;count++; hptr[count] = dummy & 1;count++; } if (howfarfunc) howfarfunc (h-j, h); } pp->numcols=2; break; case 4: /* 4bit non compressed */ ptr = *pal; for (i = 0; i < palsize; i++) { fread (ptr + 3 * i, 1, 3, in); if (iswindows) fread (&dummy, 1, 1, in); } for (i = 0; i < palsize; i++) { p[i] = ptr[3 * i + 2]; p[i + 256] = ptr[3 * i + 1]; p[i + 512] = ptr[3 * i]; } free (*pal); *pal = p; ptr = *bmap; if ((!iswindows) || (bih.biCompression == 0)) { for (j = h - 1; j >= 0; j--) for (i = 0, count = 0; i < (w / 2); i++) { dummy = fgetc (in); if (count < pp->width) { ptr[count + j * pp->width] = dummy >> 4; count++; } if (count < pp->width) { ptr[count + j * pp->width] = dummy & 15; count++; } } } else { /* 4bit RLE compressed */ done = 0; count = 0; while (done == 0) { fread (read, 1, 2, in); if (*read) { FAIL_FOR_BAD_OFFSET(ptr-*bmap,*read); i = 0; do { *ptr = read[1] >> 4; ptr++; i++; if (i < (read[0])) { *ptr = read[1] & 15; ptr++; i++; } } while (i < (*read)); } else if (read[1] == 0) { if (howfarfunc) howfarfunc (count, h); count++; } else if (read[1] == 1) done = 1; else if (read[1] == 2) { int ofs=fgetc (in); int ytmp=fgetc (in); ofs+=bih.biWidth * ytmp; FAIL_FOR_BAD_OFFSET(ptr-*bmap,ofs); ptr += ofs; count += ytmp; if(howfarfunc) howfarfunc(count,h); } else { FAIL_FOR_BAD_OFFSET(ptr-*bmap,read[1]); dptr = hptr = malloc (((read[1]+3)>>2) << 1); fread (dptr, 1, ((read[1]+3)>>2) << 1, in); i = 0; do { *ptr = (*dptr) >> 4; i++; ptr++; if (i < read[1]) { *ptr = (*dptr) & 15; i++; ptr++; } dptr++; } while (i < read[1]); free (hptr); } } if (_PICERR_NOMEM == flip (*bmap, bih.biWidth, bih.biHeight)) CLOSE_AND_RET(_PICERR_NOMEM); } /*pp->width = w;*/ /* believed bogus -rjm 2001 Apr 10 */ pp->numcols= 16; break; case 8: /* 8bit non compressed */ ptr = *pal; for (i = 0; i < palsize; i++) { fread (ptr + 3 * i, 1, 3, in); if (iswindows) dummy = fgetc (in); } for (i = 0; i < palsize; i++) { p[i] = ptr[3 * i + 2]; p[i + 256] = ptr[3 * i + 1]; p[i + 512] = ptr[3 * i]; } free (*pal); *pal = p; ptr = *bmap; if ((!iswindows) || (bih.biCompression == 0)) for (i = h - 1; i >= 0; i--) { fread (ptr + pp->width * i, 1, pp->width, in); if (howfarfunc) howfarfunc (h - i, h); if(w>pp->width) for(j=pp->width;j<w;j++) fgetc(in); } else /* 8bit RLE compressed */ { done = 0; count = 0; while (done == 0) { fread (read, 1, 2, in); if (read[0]) { FAIL_FOR_BAD_OFFSET(ptr-*bmap,read[0]); for (i = 0; i < (int) read[0]; i++) { *ptr = read[1]; ptr++; } } else if (read[1] == 0) { if (howfarfunc) howfarfunc (count, h); count++; } else if (read[1] == 1) done = 1; else if (read[1] == 2) { int ofs=fgetc (in); int ytmp=fgetc (in); ofs+=bih.biWidth * ytmp; FAIL_FOR_BAD_OFFSET(ptr-*bmap,ofs); ptr += ofs; count += ytmp; if(howfarfunc) howfarfunc(count,h); } else { FAIL_FOR_BAD_OFFSET(ptr-*bmap,read[1]); fread (ptr, 1, read[1], in); if (read[1] % 2) fgetc (in); ptr += read[1]; } } if (_PICERR_NOMEM == flip (*bmap, bih.biWidth, bih.biHeight)) CLOSE_AND_RET(_PICERR_NOMEM); } pp->numcols= 256; break; case 24: /* true color */ /* skip any bogus `palette' */ for (i = 0; i < palsize; i++) { fgetc(in); fgetc(in); fgetc(in); if(iswindows) fgetc(in); } /* don't need temp palette at all, just transfer the 8-bit-dither one */ free (*pal); *pal = p; ptr = *bmap; if ((*output_type) == 1 || cfg.jpeg24bit==0) { *output_type=1; /* Truecolor BMPs and 8-bit display */ if (ditherinit (pp->width) == 0) CLOSE_AND_RET(_PICERR_NOMEM); for (i = 1; i <= h; i++) { hptr = ptr + pp->width * i; fread (hptr, 1, w, in); ditherline (hptr, i, pp->width); if (howfarfunc) howfarfunc (i, h); } ditherfinish (); if (_PICERR_NOMEM == flip (*bmap, pp->width, pp->height)) CLOSE_AND_RET(_PICERR_NOMEM); pp->bpp = 8; pp->numcols= 256; } else for (i = h - 1; i >= 0; i--) { fread (ptr + pp->width * 3 * i, 1, w, in); if (howfarfunc) howfarfunc (h - i, h); } break; } fclose (in); return (_PIC_OK);}static int flip (unsigned char * image, unsigned int w, unsigned int h){ unsigned int i; unsigned char *hptr; if ((hptr = malloc (w)) == 0) return (_PICERR_NOMEM); for (i = 0; i < (h / 2); i++) { memcpy (hptr, image + i * w, w); memcpy (image + i * w, image + (h - i - 1) * w, w); memcpy (image + (h - i - 1) * w, hptr, w); } free (hptr); return (_PIC_OK);}void aborted_file_bmp_cleanup (){ free (work_bmap); free (work_pal); fclose (work_in);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -