#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 biClrImpotant;
} 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->biClrImpotant), 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->biClrImpotant);
}
putchar('\n');
if (bi->biSize != 40)
goto error_NotSupported1;
if (bi->biPlanes != 1)
goto error_NotSupported2;
if (bi->biBitCount != 24)
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_read(FILE *fp, BitmapFileHeader *bheader, BitmapInfoHeader *binfo,
char **dataR, char **dataG, 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_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->biClrImpotant), sizeof(unsigned long), 1, fp);
}
void task_write(int pos, FILE *fp, BitmapFileHeader *bh, BitmapInfoHeader *bi, char *data)
{
int x, y, 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++) {
if (pos == 2)
fwrite(&data[y * iabs(bi->biWidth) + x], 1, 1, fp);
else
fwrite(&dummy, 1, 1, fp);
if (pos == 1)
fwrite(&data[y * iabs(bi->biWidth) + x], 1, 1, fp);
else
fwrite(&dummy, 1, 1, fp);
if (pos == 0)
fwrite(&data[y * iabs(bi->biWidth) + x], 1, 1, fp);
else
fwrite(&dummy, 1, 1, fp);
c += 3;
}
while (c % 4 != 0) {
fwrite(&dummy, 1, 1, fp);
c++;
}
}
}
int main(int argc, char *argv[]) {
FILE *fp;
BitmapFileHeader bheader;
BitmapInfoHeader binfo;
char *dataR, *dataG, *dataB;
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, "the file \"%s\" might be a bitmap file.\n", argv[1]);
return -1;
}
if (!bmInfoHeaderCheck(fp, &binfo)) {
fprintf(stderr, "the file \"%s\" might not be a bitmap file.\n", argv[1]);
return -1;
}
dataR = dataG = dataB = NULL;
task_read(fp, &bheader, &binfo, &dataR, &dataG, &dataB);
fclose(fp);
bheader.bfSize = iabs(binfo.biWidth) * iabs(binfo.biHeight) * 3 + binfo.biSize + 14;
if ((fp = fopen("r.bmp", "wb")) == NULL) {
fprintf(stderr, "cannot open the file 'r.bmp'.\n");
}
task_write(0, fp, &bheader, &binfo, dataR);
fclose(fp);
fprintf(stderr, "output red data.\n");
if ((fp = fopen("g.bmp", "wb")) == NULL) {
fprintf(stderr, "cannot open the file 'g.bmp'.\n");
}
task_write(1, fp, &bheader, &binfo, dataG);
fclose(fp);
fprintf(stderr, "output green data.\n");
if ((fp = fopen("b.bmp", "wb")) == NULL) {
fprintf(stderr, "cannot open the file 'b.bmp'.\n");
}
task_write(2, fp, &bheader, &binfo, dataB);
fclose(fp);
fprintf(stderr, "output blue data.\n");
if (dataR != NULL)
free(dataR);
if (dataG != NULL)
free(dataG);
if (dataB != NULL)
free(dataB);
return 0;
}
/* end */