codepad
[
create a new paste
]
login
|
about
Language:
C
C++
D
Haskell
Lua
OCaml
PHP
Perl
Plain Text
Python
Ruby
Scheme
Tcl
#include <stdio.h> #include <stdlib.h> #include <assert.h> #include <math.h> #include <string.h> /* #define DEBUG */ #if defined(DEBUG) #include "xmalloc.h" #else #define xmalloc(x, y) malloc(x) #define xfree(x, y) free(x) #define xrealloc(x, y, z) realloc(x, y) #define xmallocdump() #endif /* for xmalloc.c */ #define IDRGB 1001 #define IDPALETTE 1002 #define IDBMP 1003 #define NBYTE 1 #define NWORD 2 #define NDWORD 4 int LittleEndianRead(unsigned long *data, int size, FILE *fp) { unsigned char lsb; unsigned long msb; if (size == 0) { *data = 0; return 1; } if (fread(&lsb, 1, 1, fp) != 1) return -1; if (LittleEndianRead(&msb, size - 1, fp) < 0) return -1; *data = (unsigned long)lsb | (msb << 8); return 1; } typedef struct { unsigned long bfType1; unsigned long bfType2; unsigned long bfSize; unsigned long bfReserved1; unsigned long bfReserved2; unsigned long bfOffBits; } BitmapFileHeader; int bmHeaderCheck(FILE *fp, BitmapFileHeader *bh) { assert(sizeof(unsigned long) >= 4); if (LittleEndianRead(&(bh->bfType1), NBYTE, fp) < 0) goto error_NotRead; if (LittleEndianRead(&(bh->bfType2), NBYTE, fp) < 0) goto error_NotRead; if (LittleEndianRead(&bh->bfSize, NDWORD, fp) < 0) goto error_NotRead; if (LittleEndianRead(&bh->bfReserved1, NWORD, fp) < 0) goto error_NotRead; if (LittleEndianRead(&bh->bfReserved2, NWORD, fp) < 0) goto error_NotRead; if (LittleEndianRead(&bh->bfOffBits, NDWORD, fp) < 0) goto error_NotRead; #if 0 printf("read:bfType1: %c\n", (char)bh->bfType1); printf("read:bfType2: %c\n", (char)bh->bfType2); printf("read:bfSize: %lu\n", bh->bfSize); printf("read:bfReserved1: %lu\n", bh->bfReserved1); printf("read:bfReserved2: %lu\n", bh->bfReserved2); printf("read:bfOffBits: %lu\n", bh->bfOffBits); putchar('\n'); #endif if (bh->bfType1 != 'B' || bh->bfType2 != 'M') goto error_NotBitmap; if (bh->bfReserved1 != 0 || bh->bfReserved2 != 0) goto error_NotBitmap; return 1; error_NotBitmap: fprintf(stderr, "cannot find bmp header\n"); return 0; error_NotRead: fprintf(stderr, "cannot read bmp header\n"); return 0; } typedef struct { unsigned long biSize; long biWidth; long biHeight; unsigned long biPlanes; unsigned long biBitCount; unsigned long biCompression; unsigned long biSizeImage; long biXPixPerMeter; long biYPixPerMeter; unsigned long biClrUsed; unsigned long biClrImportant; } BitmapInfoHeader; int bmInfoHeaderCheck(FILE *fp, BitmapInfoHeader *bi) { assert(sizeof(unsigned long) >= 4); assert(sizeof(long) >= 4); if (LittleEndianRead(&bi->biSize, NDWORD, fp) < 0) goto error_NotRead; if (bi->biSize == 12) { /* not supported */ } else if (bi->biSize == 40) { if (LittleEndianRead((unsigned long *)&bi->biWidth, NDWORD, fp) < 0) goto error_NotRead; if (LittleEndianRead((unsigned long *)&bi->biHeight, NDWORD, fp) < 0) goto error_NotRead; if (LittleEndianRead(&bi->biPlanes, NWORD, fp) < 0) goto error_NotRead; if (LittleEndianRead(&bi->biBitCount, NWORD, fp) < 0) goto error_NotRead; if (LittleEndianRead(&bi->biCompression, NDWORD, fp) < 0) goto error_NotRead; if (LittleEndianRead(&bi->biSizeImage, NDWORD, fp) < 0) goto error_NotRead; if (LittleEndianRead((unsigned long *)&bi->biXPixPerMeter, NDWORD, fp) < 0) goto error_NotRead; if (LittleEndianRead((unsigned long *)&bi->biYPixPerMeter, NDWORD, fp) < 0) goto error_NotRead; if (LittleEndianRead(&bi->biClrUsed, NDWORD, fp) < 0) goto error_NotRead; if (LittleEndianRead(&bi->biClrImportant, NDWORD, fp) < 0) goto error_NotRead; } else { goto error_NotSupported1; } #if 0 printf("read:biSize: %lu\n", bi->biSize); printf("read:biWidth: %ld\n", bi->biWidth); printf("read:biHeight: %ld\n", bi->biHeight); printf("read:biPlanes: %lu\n", bi->biPlanes); printf("read:biBitcount: %lu\n", bi->biBitCount); if (bi->biSize == 40) { printf("read:biCompression: %lu\n", bi->biCompression); printf("read:biSizeImage: %lu\n", bi->biSizeImage); printf("read:biXPixPerMeter %ld\n", bi->biXPixPerMeter); printf("read:biYPixPerMeter %ld\n", bi->biYPixPerMeter); printf("read:biClrUsed: %lu\n", bi->biClrUsed); printf("read:biClrImporant: %lu\n", bi->biClrImportant); } #endif if (bi->biSize != 40) goto error_NotSupported1; if (bi->biPlanes != 1) goto error_NotSupported2; if (bi->biBitCount != 24 && bi->biBitCount != 8 && bi->biBitCount != 4) goto error_NotSupported3; if (bi->biCompression != 0) goto error_NotSupported4; return 1; error_NotSupported1: fprintf(stderr, "info header size: %lu, this format is not supported\n", bi->biSize); return 0; error_NotSupported2: fprintf(stderr, "biPlanes: %lu, this format is not supported\n", bi->biPlanes); return 0; error_NotSupported3: fprintf(stderr, "biBitCount: %lu, this format is not supported\n", bi->biBitCount); return 0; error_NotSupported4: fprintf(stderr, "biCompression: %lu, this format is not supported\n", bi->biCompression); return 0; error_NotRead: #if 0 printf("read:biSize: %lu\n", bi->biSize); printf("read:biWidth: %ld\n", bi->biWidth); printf("read:biHeight: %ld\n", bi->biHeight); printf("read:biPlanes: %lu\n", bi->biPlanes); printf("read:biBitcount: %lu\n", bi->biBitCount); if (bi->biSize == 40) { printf("read:biCompression: %lu\n", bi->biCompression); printf("read:biSizeImage: %lu\n", bi->biSizeImage); printf("read:biXPixPerMeter %ld\n", bi->biXPixPerMeter); printf("read:biYPixPerMeter %ld\n", bi->biYPixPerMeter); printf("read:biClrUsed: %lu\n", bi->biClrUsed); printf("read:biClrImporant: %lu\n", bi->biClrImportant); } #endif fprintf(stderr, "cannot read bmp info header\n"); return 0; } int isFtellGood(FILE *fp, unsigned long pos) { return (unsigned long)ftell(fp) == pos; } long iabs(long n) { return (n > 0) ? n : -n; } void task_read24(FILE *fp, BitmapFileHeader *bheader, BitmapInfoHeader *binfo, unsigned char **dataR, unsigned char **dataG, unsigned char **dataB) { long x, y, n; unsigned char dummy; int c; if (!isFtellGood(fp, bheader->bfOffBits)) { fprintf(stderr, "Header or Image Data is corrupted.\n"); return; } *dataR = xmalloc(sizeof(char) * iabs(binfo->biWidth) * iabs(binfo->biHeight), IDRGB); *dataG = xmalloc(sizeof(char) * iabs(binfo->biWidth) * iabs(binfo->biHeight), IDRGB); *dataB = xmalloc(sizeof(char) * iabs(binfo->biWidth) * iabs(binfo->biHeight), IDRGB); if (*dataR == NULL || *dataG == NULL || *dataB == NULL) { fprintf(stderr, "cannot alloc. enough memory.\n"); return; } for (y = 0; y < iabs(binfo->biHeight); y++) { c = 0; for (x = 0; x < iabs(binfo->biWidth); x++) { fread((*dataB + y * iabs(binfo->biWidth) + x), 1, 1, fp); fread((*dataG + y * iabs(binfo->biWidth) + x), 1, 1, fp); fread((*dataR + y * iabs(binfo->biWidth) + x), 1, 1, fp); c += 3; } while (c % 4 != 0) { fread(&dummy, 1, 1, fp); c++; } } n = iabs(binfo->biWidth) * 3; if (n % 4 > 0) n += 4 - (n % 4); binfo->biSizeImage = n * iabs(binfo->biHeight); bheader->bfSize = binfo->biSizeImage + binfo->biSize + 14; } void task_read_palette(FILE *fp, BitmapFileHeader *bh, BitmapInfoHeader *bi, unsigned char **dataPalette) { int i, max; unsigned char dummy; if ((max = bi->biClrUsed) == 0) { switch (bi->biBitCount) { case 4: max = 16; break; case 8: max = 256; break; } } *dataPalette = xmalloc(sizeof(char) * 3 * max, IDPALETTE); if (*dataPalette == NULL) { fprintf(stderr, "cannot alloc. enough memory.\n"); return; } for (i = 0; i < max; i++) { fread((*dataPalette + 3 * i + 0), 1, 1, fp); fread((*dataPalette + 3 * i + 1), 1, 1, fp); fread((*dataPalette + 3 * i + 2), 1, 1, fp); fread(&dummy, 1, 1, fp); } } void task_read8(FILE *fp, BitmapFileHeader *bheader, BitmapInfoHeader *binfo, unsigned char **dataR, unsigned char **dataG, unsigned char **dataB, unsigned char *dataPalette) { long x, y, n; unsigned char data; int c; if (!isFtellGood(fp, bheader->bfOffBits)) { fprintf(stderr, "Header or Image Data is corrupted.\n"); return; } *dataR = xmalloc(sizeof(char) * iabs(binfo->biWidth) * iabs(binfo->biHeight), IDRGB); *dataG = xmalloc(sizeof(char) * iabs(binfo->biWidth) * iabs(binfo->biHeight), IDRGB); *dataB = xmalloc(sizeof(char) * iabs(binfo->biWidth) * iabs(binfo->biHeight), IDRGB); if (*dataR == NULL || *dataG == NULL || *dataB == NULL) { fprintf(stderr, "cannot alloc. enough memory.\n"); return; } for (y = 0; y < iabs(binfo->biHeight); y++) { c = 0; for (x = 0; x < iabs(binfo->biWidth); x++) { fread(&data, 1, 1, fp); *(*dataB + y * iabs(binfo->biWidth) + x) = dataPalette[3 * data + 0]; *(*dataG + y * iabs(binfo->biWidth) + x) = dataPalette[3 * data + 1]; *(*dataR + y * iabs(binfo->biWidth) + x) = dataPalette[3 * data + 2]; c++; } while (c % 4 != 0) { fread(&data, 1, 1, fp); c++; } } n = iabs(binfo->biWidth) * 3; if (n % 4 > 0) n += 4 - (n % 4); binfo->biSizeImage = n * iabs(binfo->biHeight); bheader->bfSize = binfo->biSizeImage + binfo->biSize + 14; bheader->bfOffBits = 54; binfo->biBitCount = 24; binfo->biClrUsed = 0; binfo->biClrImportant = 0; } void task_read4(FILE *fp, BitmapFileHeader *bheader, BitmapInfoHeader *binfo, unsigned char **dataR, unsigned char **dataG, unsigned char **dataB, unsigned char *dataPalette) { long x, y, n; unsigned char data, rdata; int c; int bitHighLow; if (!isFtellGood(fp, bheader->bfOffBits)) { fprintf(stderr, "Header or Image Data is corrupted.\n"); return; } *dataR = xmalloc(sizeof(char) * iabs(binfo->biWidth) * iabs(binfo->biHeight), IDRGB); *dataG = xmalloc(sizeof(char) * iabs(binfo->biWidth) * iabs(binfo->biHeight), IDRGB); *dataB = xmalloc(sizeof(char) * iabs(binfo->biWidth) * iabs(binfo->biHeight), IDRGB); if (*dataR == NULL || *dataG == NULL || *dataB == NULL) { fprintf(stderr, "cannot alloc. enough memory.\n"); return; } bitHighLow = 1; for (y = 0; y < iabs(binfo->biHeight); y++) { c = 0; for (x = 0; x < iabs(binfo->biWidth); x++) { if (bitHighLow) { fread(&rdata, 1, 1, fp); data = rdata & 0xf0; data >>= 4; bitHighLow = 0; } else { data = rdata & 0x0f; bitHighLow = 1; } *(*dataB + y * iabs(binfo->biWidth) + x) = dataPalette[3 * data + 0]; *(*dataG + y * iabs(binfo->biWidth) + x) = dataPalette[3 * data + 1]; *(*dataR + y * iabs(binfo->biWidth) + x) = dataPalette[3 * data + 2]; c++; } while (c % 4 != 0) { fread(&data, 1, 1, fp); c++; } } n = iabs(binfo->biWidth) * 3; if (n % 4 > 0) n += 4 - (n % 4); binfo->biSizeImage = n * iabs(binfo->biHeight); bheader->bfSize = binfo->biSizeImage + binfo->biSize + 14; bheader->bfOffBits = 54; binfo->biBitCount = 24; binfo->biClrUsed = 0; binfo->biClrImportant = 0; } void LittleEndianWrite(unsigned long *data, int size, FILE *fp) { unsigned char lsb; unsigned long msb; if (size == 0) return; lsb = (unsigned char)(*data & 0xff); fwrite(&lsb, 1, 1, fp); msb = *data >> 8; LittleEndianWrite(&msb, size - 1, fp); } void task_write_header(FILE *fp, BitmapFileHeader *bh) { assert(sizeof(unsigned long) >= 4); assert(sizeof(long) >= 4); LittleEndianWrite(&(bh->bfType1), NBYTE, fp); LittleEndianWrite(&(bh->bfType2), NBYTE, fp); LittleEndianWrite(&(bh->bfSize), NDWORD, fp); LittleEndianWrite(&(bh->bfReserved1), NWORD, fp); LittleEndianWrite(&(bh->bfReserved2), NWORD, fp); LittleEndianWrite(&(bh->bfOffBits), NDWORD, fp); #if 0 printf("write:bfType1: %c\n", (char)bh->bfType1); printf("write:bfType2: %c\n", (char)bh->bfType2); printf("write:bfSize: %lu\n", bh->bfSize); printf("write:bfReserved1: %lu\n", bh->bfReserved1); printf("write:bfReserved2: %lu\n", bh->bfReserved2); printf("write:bfOffBits: %lu\n", bh->bfOffBits); #endif } void task_write_info(FILE *fp, BitmapInfoHeader *bi) { assert(sizeof(unsigned short) == 2); assert(sizeof(unsigned long) == 4); assert(sizeof(long) == 4); LittleEndianWrite(&(bi->biSize), NDWORD, fp); LittleEndianWrite((unsigned long *)&(bi->biWidth), NDWORD, fp); LittleEndianWrite((unsigned long *)&(bi->biHeight), NDWORD, fp); LittleEndianWrite(&(bi->biPlanes), NWORD, fp); LittleEndianWrite(&(bi->biBitCount), NWORD, fp); LittleEndianWrite(&(bi->biCompression), NDWORD, fp); LittleEndianWrite(&(bi->biSizeImage), NDWORD, fp); LittleEndianWrite((unsigned long *)&(bi->biXPixPerMeter), NDWORD, fp); LittleEndianWrite((unsigned long *)&(bi->biYPixPerMeter), NDWORD, fp); LittleEndianWrite(&(bi->biClrUsed), NDWORD, fp); LittleEndianWrite(&(bi->biClrImportant), NDWORD, fp); #if 0 printf("write:biSize: %lu\n", bi->biSize); printf("write:biWidth: %ld\n", bi->biWidth); printf("write:biHeight: %ld\n", bi->biHeight); printf("write:biPlanes: %lu\n", bi->biPlanes); printf("write:biBitcount: %lu\n", bi->biBitCount); printf("write:biCompression: %lu\n", bi->biCompression); printf("write:biSizeImage: %lu\n", bi->biSizeImage); printf("write:biXPixPerMeter %ld\n", bi->biXPixPerMeter); printf("write:biYPixPerMeter %ld\n", bi->biYPixPerMeter); printf("write:biClrUsed: %lu\n", bi->biClrUsed); printf("write:biClrImporant: %lu\n", bi->biClrImportant); #endif } void task_write24(FILE *fp, BitmapFileHeader *bh, BitmapInfoHeader *bi, unsigned char *dataR, unsigned char *dataG, unsigned char *dataB) { int x, y; int c; unsigned char dummy = '\0'; task_write_header(fp, bh); task_write_info(fp, bi); for (y = 0; y < iabs(bi->biHeight); y++) { c = 0; for (x = 0; x < iabs(bi->biWidth); x++) { fwrite(&dataB[y * iabs(bi->biWidth) + x], 1, 1, fp); fwrite(&dataG[y * iabs(bi->biWidth) + x], 1, 1, fp); fwrite(&dataR[y * iabs(bi->biWidth) + x], 1, 1, fp); c += 3; } while (c % 4 != 0) { fwrite(&dummy, 1, 1, fp); c++; } } } /* ------------------------------------------------------------------------- */ struct BMP24 { BitmapFileHeader bh; BitmapInfoHeader bi; unsigned char *dataR; unsigned char *dataG; unsigned char *dataB; unsigned char *dataPalette; }; int BMP24_read(FILE *fp, struct BMP24 *bmp) { if (!bmHeaderCheck(fp, &(bmp->bh))) return 0; if (!bmInfoHeaderCheck(fp, &(bmp->bi))) return 0; bmp->dataR = bmp->dataG = bmp->dataB = bmp->dataPalette = NULL; if ((bmp->bi).biBitCount == 24) { task_read24(fp, &(bmp->bh), &(bmp->bi), &(bmp->dataR), &(bmp->dataG), &(bmp->dataB)); } else if ((bmp->bi).biBitCount == 8) { task_read_palette(fp, &bmp->bh, &bmp->bi, &bmp->dataPalette); task_read8(fp, &bmp->bh, &bmp->bi, &bmp->dataR, &bmp->dataG, &bmp->dataB, bmp->dataPalette); xfree(bmp->dataPalette, IDPALETTE); bmp->dataPalette = NULL; } else if ((bmp->bi).biBitCount == 4) { task_read_palette(fp, &bmp->bh, &bmp->bi, &bmp->dataPalette); task_read4(fp, &bmp->bh, &bmp->bi, &bmp->dataR, &bmp->dataG, &bmp->dataB, bmp->dataPalette); xfree(bmp->dataPalette, IDPALETTE); bmp->dataPalette = NULL; } if (!(bmp->dataR && bmp->dataG && bmp->dataB)) { xfree(bmp->dataR, IDRGB); xfree(bmp->dataG, IDRGB); xfree(bmp->dataB, IDRGB); return 0; } return 1; } void BMP24_write(FILE *fp, struct BMP24 *bmp) { task_write24(fp, &bmp->bh, &bmp->bi, bmp->dataR, bmp->dataG, bmp->dataB); } void BMP24_release(struct BMP24 *bmp) { if (bmp->dataR) xfree(bmp->dataR, IDRGB); if (bmp->dataG) xfree(bmp->dataG, IDRGB); if (bmp->dataB) xfree(bmp->dataB, IDRGB); if (bmp->dataPalette) xfree(bmp->dataPalette, IDPALETTE); } /* ------------------------------------------------------------------------- */ void task_colorbmp2gray(struct BMP24 *bmp) { unsigned int c; long w, h, x, y; w = iabs((bmp->bi).biWidth); h = iabs((bmp->bi).biHeight); for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { c = bmp->dataR[y * w + x] + bmp->dataG[y * w + x] + bmp->dataB[y * w + x]; bmp->dataR[y * w + x] = bmp->dataG[y * w + x] = bmp->dataB[y * w + x] = (unsigned char)(c / 3); } } } /* ------------------------------------------------------------------------- */ void task_bmp2pgm(FILE *fpbmp, FILE *fppgm) { struct BMP24 *bmp; long Width, Height, y, x; bmp = xmalloc(sizeof(struct BMP24), IDBMP); if (!BMP24_read(fpbmp, bmp)) { fprintf(stderr, "not a bitmap file, aborted.\n"); xfree(bmp, IDBMP); return; } Width = iabs((bmp->bi).biWidth); Height = iabs((bmp->bi).biHeight); task_colorbmp2gray(bmp); fprintf(fppgm, "P2\n"); fprintf(fppgm, "%ld %ld\n", Width, Height); fprintf(fppgm, "255\n"); if ((bmp->bi).biHeight < 0) { for (y = 0; y < Height; y++) { for (x = 0; x < Width; x++) fprintf(fppgm, "%3d ", bmp->dataR[y * Width + x]); fprintf(fppgm, "\n"); } } else { for (y = Height - 1; y >= 0; y--) { for (x = 0; x < Width; x++) fprintf(fppgm, "%3d ", bmp->dataR[y * Width + x]); fprintf(fppgm, "\n"); } } BMP24_release(bmp); xfree(bmp, IDBMP); } int main(int argc, char **argv) { FILE *fpbmp, *fppgm; if (argc != 3) { fprintf(stderr, "usage: %s <filename:bmp> <filename:pgm>\n", argv[0]); exit(-1); } if ((fpbmp = fopen(argv[1], "r")) == 0) { fprintf(stderr, "cannot open the .bmp file for reading\n"); exit(-1); } if ((fppgm = fopen(argv[2], "w")) == 0) { fprintf(stderr, "cannot open the .bgm file for writing\n"); fclose(fpbmp); exit(-1); } task_bmp2pgm(fpbmp, fppgm); fclose(fpbmp); fclose(fppgm); xmallocdump(); return 0; } /* end */
Private
[
?
]
Run code
Submit