#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef struct {
unsigned char bfType1;
unsigned char bfType2;
unsigned long bfSize;
unsigned short bfReserved1;
unsigned short bfReserved2;
unsigned long bfOffBits;
} BitmapFileHeader;
int bmHeaderCheck(FILE *fp, BitmapFileHeader *bh) {
assert(sizeof(unsigned short) == 2);
assert(sizeof(unsigned long) == 4);
if (fread(&(bh->bfType1), sizeof(unsigned char), 1, fp) != 1)
goto error_NotRead;
if (fread(&(bh->bfType2), sizeof(unsigned char), 1, fp) != 1)
goto error_NotRead;
if (fread(&(bh->bfSize), sizeof(unsigned long), 1, fp) != 1)
goto error_NotRead;
if (fread(&(bh->bfReserved1), sizeof(unsigned short), 1, fp) != 1)
goto error_NotRead;
if (fread(&(bh->bfReserved2), sizeof(unsigned short), 1, fp) != 1)
goto error_NotRead;
if (fread(&(bh->bfOffBits), sizeof(unsigned long), 1, fp) != 1)
goto error_NotRead;
if (bh->bfType1 != 'B' || bh->bfType2 != 'M')
goto error_NotBitmap;
if (bh->bfReserved1 != 0 || bh->bfReserved2 != 0)
goto error_NotBitmap;
printf("bfType1: %c\n", bh->bfType1);
printf("bfType2: %c\n", bh->bfType2);
printf("bfSize: %lu\n", bh->bfSize);
printf("bfReserved1: %u\n", bh->bfReserved1);
printf("bfReserved2: %u\n", bh->bfReserved2);
printf("bfOffBits: %lu\n", bh->bfOffBits);
putchar('\n');
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 short biPlanes;
unsigned short 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 short) == 2);
assert(sizeof(unsigned long) == 4);
assert(sizeof(long) == 4);
if (fread(&(bi->biSize), sizeof(unsigned long), 1, fp) != 1)
goto error_NotRead;
if (bi->biSize == 12) {
bi->biWidth = 0;
if (fread(&(bi->biWidth), sizeof(short), 1, fp) != 1)
goto error_NotRead;
bi->biHeight = 0;
if (fread(&(bi->biHeight), sizeof(short), 1, fp) != 1)
goto error_NotRead;
if (fread(&(bi->biPlanes), sizeof(unsigned short), 1, fp) != 1)
goto error_NotRead;
if (fread(&(bi->biBitCount), sizeof(unsigned short), 1, fp) != 1)
goto error_NotRead;
if (bi->biWidth > 32768)
bi->biWidth = -bi->biWidth;
if (bi->biHeight > 32768)
bi->biWidth = -bi->biHeight;
} else if (bi->biSize == 40) {
if (fread(&(bi->biWidth), sizeof(long), 1, fp) != 1)
goto error_NotRead;
if (fread(&(bi->biHeight), sizeof(long), 1, fp) != 1)
goto error_NotRead;
if (fread(&(bi->biPlanes), sizeof(unsigned short), 1, fp) != 1)
goto error_NotRead;
if (fread(&(bi->biBitCount), sizeof(unsigned short), 1, fp) != 1)
goto error_NotRead;
if (fread(&(bi->biCompression), sizeof(unsigned long), 1, fp) != 1)
goto error_NotRead;
if (fread(&(bi->biSizeImage), sizeof(unsigned long), 1, fp) != 1)
goto error_NotRead;
if (fread(&(bi->biXPixPerMeter), sizeof(long), 1, fp) != 1)
goto error_NotRead;
if (fread(&(bi->biYPixPerMeter), sizeof(long), 1, fp) != 1)
goto error_NotRead;
if (fread(&(bi->biClrUsed), sizeof(unsigned long), 1, fp) != 1)
goto error_NotRead;
if (fread(&(bi->biClrImportant), sizeof(unsigned long), 1, fp) != 1)
goto error_NotRead;
} else
goto error_NotSupported1;
printf("biSize: %lu\n", bi->biSize);
printf("biWidth: %ld\n", bi->biWidth);
printf("biHeight: %ld\n", bi->biHeight);
printf("biPlanes: %u\n", bi->biPlanes);
printf("biBitcount: %u\n", bi->biBitCount);
if (bi->biSize == 40) {
printf("biCompression: %lu\n", bi->biCompression);
printf("biSizeImage: %lu\n", bi->biSizeImage);
printf("biXPixPerMeter %ld\n", bi->biXPixPerMeter);
printf("biYPixPerMeter %ld\n", bi->biYPixPerMeter);
printf("biClrUsed: %lu\n", bi->biClrUsed);
printf("biClrImporant: %lu\n", bi->biClrImportant);
}
putchar('\n');
if (bi->biSize != 40)
goto error_NotSupported1;
if (bi->biPlanes != 1)
goto error_NotSupported2;
if (bi->biBitCount != 24 && bi->biBitCount != 8)
goto error_NotSupported3;
if (bi->biCompression != 0)
goto error_NotSupported4;
return 1;
error_NotSupported1:
fprintf(stderr, "info header size: this format is not supported\n");
return 0;
error_NotSupported2:
fprintf(stderr, "biPlanes: this format is not supported\n");
return 0;
error_NotSupported3:
fprintf(stderr, "biBitCount: this format is not supported\n");
return 0;
error_NotSupported4:
fprintf(stderr, "biCompression: this format is not supported\n");
return 0;
error_NotRead:
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;
unsigned char dummy;
int c;
if (!isFtellGood(fp, bheader->bfOffBits)) {
fprintf(stderr, "Header or Image Data is corrupted.\n");
return;
}
*dataR = malloc(sizeof(char) * iabs(binfo->biWidth) * iabs(binfo->biHeight));
*dataG = malloc(sizeof(char) * iabs(binfo->biWidth) * iabs(binfo->biHeight));
*dataB = malloc(sizeof(char) * iabs(binfo->biWidth) * iabs(binfo->biHeight));
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++;
}
}
return;
}
void task_read_palette(FILE *fp, BitmapFileHeader *bh, BitmapInfoHeader *bi,
unsigned char **dataPalette)
{
int i, max;
unsigned char dummy;
if ((max = bi->biClrUsed) == 0)
max = 256;
*dataPalette = malloc(sizeof(char) * 3 * max);
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;
unsigned char data;
int c;
if (!isFtellGood(fp, bheader->bfOffBits)) {
fprintf(stderr, "Header or Image Data is corrupted.\n");
return;
}
*dataR = malloc(sizeof(char) * iabs(binfo->biWidth) * iabs(binfo->biHeight));
*dataG = malloc(sizeof(char) * iabs(binfo->biWidth) * iabs(binfo->biHeight));
*dataB = malloc(sizeof(char) * iabs(binfo->biWidth) * iabs(binfo->biHeight));
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++;
}
}
}
void task_write_header(FILE *fp, BitmapFileHeader *bh) {
assert(sizeof(unsigned short) == 2);
assert(sizeof(unsigned long) == 4);
fwrite(&(bh->bfType1), sizeof(unsigned char), 1, fp);
fwrite(&(bh->bfType2), sizeof(unsigned char), 1, fp);
fwrite(&(bh->bfSize), sizeof(unsigned long), 1, fp);
fwrite(&(bh->bfReserved1), sizeof(unsigned short), 1, fp);
fwrite(&(bh->bfReserved2), sizeof(unsigned short), 1, fp);
fwrite(&(bh->bfOffBits), sizeof(unsigned long), 1, fp);
}
void task_write_info(FILE *fp, BitmapInfoHeader *bi) {
assert(sizeof(unsigned short) == 2);
assert(sizeof(unsigned long) == 4);
assert(sizeof(long) == 4);
fwrite(&(bi->biSize), sizeof(unsigned long), 1, fp);
fwrite(&(bi->biWidth), sizeof(long), 1, fp);
fwrite(&(bi->biHeight), sizeof(long), 1, fp);
fwrite(&(bi->biPlanes), sizeof(unsigned short), 1, fp);
fwrite(&(bi->biBitCount), sizeof(unsigned short), 1, fp);
fwrite(&(bi->biCompression), sizeof(unsigned long), 1, fp);
fwrite(&(bi->biSizeImage), sizeof(unsigned long), 1, fp);
fwrite(&(bi->biXPixPerMeter), sizeof(long), 1, fp);
fwrite(&(bi->biYPixPerMeter), sizeof(long), 1, fp);
fwrite(&(bi->biClrUsed), sizeof(unsigned long), 1, fp);
fwrite(&(bi->biClrImportant), sizeof(unsigned long), 1, fp);
}
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++;
}
}
}
#define LOW 100
#define HIGH 150
int isBetween2(unsigned char c) {
if (c >= LOW && c <= HIGH)
return 1;
else
return 0;
}
int isBetween(unsigned char r, unsigned char g, unsigned char b) {
return isBetween2(r) && isBetween2(g) && isBetween2(b);
}
void task_convert(BitmapFileHeader *bh, BitmapInfoHeader *bi,
unsigned char *dataR, unsigned char *dataG, unsigned char *dataB)
{
unsigned long x, y, idx;
for (y = 0; y < iabs(bi->biHeight); y++)
for (x = 0; x < iabs(bi->biWidth); x++) {
idx = y * bi->biWidth + x;
if (isBetween(dataR[idx], dataG[idx], dataB[idx]))
dataR[idx] = dataG[idx] = dataB[idx] = 255;
else
dataR[idx] = dataG[idx] = dataB[idx] = 0;
}
}
int main(int argc, char *argv[]) {
FILE *fp;
BitmapFileHeader bheader;
BitmapInfoHeader binfo;
unsigned char *dataR, *dataG, *dataB, *dataPalette;
if ((fp = fopen(argv[1], "rb")) == NULL) {
fprintf(stderr, "cannot open the file \"%s\".\n", argv[1]);
return -1;
}
if(!bmHeaderCheck(fp, &bheader)) {
fprintf(stderr, "cannot handle the file \"%s\".\n", argv[1]);
return -1;
}
if (!bmInfoHeaderCheck(fp, &binfo)) {
fprintf(stderr, "cannot handle the file \"%s\".\n", argv[1]);
return -1;
}
dataR = dataG = dataB = dataPalette = NULL;
if (binfo.biBitCount == 24) {
int n;
task_read24(fp, &bheader, &binfo, &dataR, &dataG, &dataB);
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;
} else if (binfo.biBitCount == 8) {
int n;
task_read_palette(fp, &bheader, &binfo, &dataPalette);
task_read8(fp, &bheader, &binfo, &dataR, &dataG, &dataB, dataPalette);
free(dataPalette);
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;
}
fclose(fp);
if (dataR && dataG && dataB) {
task_convert(&bheader, &binfo, dataR, dataG, dataB);
if ((fp = fopen(argv[2], "wb")) == NULL) {
fprintf(stderr, "cannot open the file \"%s\".\n", argv[2]);
return -1;
}
task_write24(fp, &bheader, &binfo, dataR, dataG, dataB);
fclose(fp);
}
free(dataR);
free(dataG);
free(dataB);
return 0;
}
/* end */