Related
I have able to read Bmp Header of Image as per below properties.
Image Bit-depth : 1
Image Attributes : 1
I want to scroll/Navigate in between Black and White Image (Bit Depth 1). Without Closing and reopening it (bmp image).
1) Like if input == f or F , Pixel Data goes one by one Forward Direction
Y0,Y1,Y2,Y3,Y4,....Yn
2) Like if input == r or R, Pixel Data goes one by one Backward Direction
Y123,Y122,Y121,Y120,Y119, ......Y0
3) Also I don't want to read pixels from starting (On Every Read) .
I want to read in between (Vertical Only).
Below is my code .
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct BitMap {
short Type;
long Size;
short Reserve1;
short Reserve2;
long OffBits;
long biSize;
long biWidth;
long biHeight;
short biPlanes;
short biBitCount;
long biCompression;
long biSizeImage;
long biXPelsPerMeter;
long biYPelsPerMeter;
long biClrUsed;
long biClrImportant; } Header;
unsigned char DummyValueRead ; unsigned char pixelValue =0 ;
int Horizontal= 0 ,Vertical = 0 ;
long myPalette[2]; long HeaderBytes;
unsigned char bPadding ; long wBytesPerRow ; unsigned char
bAdditionalBitsPerRow ; FILE *BMPFile; void SendPixelValues();
unsigned char input ;
int main( void ) {
BMPFile = fopen ("mul.bmp", "r");
if (BMPFile == NULL)
{
printf("Image Not Found !!!!!!");
return -1;
}
fread(&Header.Type, sizeof(Header.Type), 1, BMPFile);
fread(&Header.Size, sizeof(Header.Size), 1, BMPFile);
fread(&Header.Reserve1, sizeof(Header.Reserve1) , 1, BMPFile);
fread(&Header.Reserve2, sizeof(Header.Reserve2) , 1, BMPFile);
fread(&Header.OffBits, sizeof(Header.OffBits), 1, BMPFile);
fread(&Header.biSize, sizeof(Header.biSize), 1, BMPFile);
fread(&Header.biWidth, sizeof(Header.biWidth), 1, BMPFile);
fread(&Header.biHeight, sizeof(Header.biHeight) , 1, BMPFile);
fread(&Header.biPlanes, sizeof(Header.biClrUsed), 1, BMPFile);
fread(&Header.biBitCount, sizeof(Header.biBitCount), 1, BMPFile);
fread(&Header.biCompression, sizeof(Header.biCompression), 1, BMPFile);
fread(&Header.biSizeImage, sizeof(Header.biSizeImage), 1, BMPFile);
fread(&Header.biXPelsPerMeter, sizeof(Header.biXPelsPerMeter), 1, BMPFile);
fread(&Header.biYPelsPerMeter, sizeof(Header.biYPelsPerMeter), 1, BMPFile);
fread(&Header.biClrUsed, sizeof(Header.biClrUsed), 1, BMPFile);
fread(&Header.biClrImportant, sizeof(Header.biClrImportant), 1, BMPFile);
fseek(BMPFile,Header.OffBits,SEEK_SET) ;
printf("\nType:%hd and Type in %x\n", Header.Type,Header.Type);
printf("Size:%ld\n", Header.Size);
printf("Reserve1:%hd\n", Header.Reserve1);
printf("Reserve2:%hd\n", Header.Reserve2);
printf("OffBits:%ld\n", Header.OffBits);
printf("biSize:%ld\n", Header.biSize);
printf("Width: %ld\n", Header.biWidth);
printf("Height: %ld\n", Header.biHeight);
printf("biPlanes:%hd\n", Header.biPlanes);
printf("biBitCount:%hd\n", Header.biBitCount);
printf("biCompression:%ld\n", Header.biCompression);
printf("biSizeImage:%ld\n", Header.biSizeImage);
printf("biXPelsPerMeter:%ld\n", Header.biXPelsPerMeter);
printf("biYPelsPerMeter:%ld\n", Header.biYPelsPerMeter);
printf("biClrUsed:%ld\n", Header.biClrUsed);
printf("biClrImportant:%ld\n\n", Header.biClrImportant);
wBytesPerRow =Header.biWidth/8;
bAdditionalBitsPerRow = Header.biWidth % 8;
bPadding = (4 - ((wBytesPerRow + (bAdditionalBitsPerRow?1:0) ) % 4 ) ) %4;
HeaderBytes = Header.biWidth/8 ;
for(Vertical = 0 ; Vertical < Header.biHeight ; Vertical ++)
{
printf("Sr. No. %d \n",Vertical) ;
scanf("%c",&input) ;
if(input =='r' || input =='R' ) // Reverse Direction
{
// fseek(BMPFile,((4*968) + 3), SEEK_SET );
SendPixelValues() ;
}
if(input =='f' || input =='F' ) // Forward Direction
SendPixelValues() ;
printf("\n") ;
}
fclose(BMPFile);
return 0;
}
unsigned int bAdditionalBitsPerRowCount =
0,bPaddingCount=0; void SendPixelValues() {
for(Horizontal = 0 ; Horizontal < HeaderBytes ; Horizontal++)
{
fread(&pixelValue, sizeof(pixelValue), 1, BMPFile);
printf("0x%x ",pixelValue) ;
}
if(bAdditionalBitsPerRow > 0)
{
fread(&DummyValueRead , sizeof(DummyValueRead ), 1, BMPFile);
bAdditionalBitsPerRow++;
printf("bAdditionalBitsPerRowCount %d",bAdditionalBitsPerRowCount);
}
for(Horizontal = 0 ; Horizontal < bPadding; Horizontal++)
{
fread(&DummyValueRead , sizeof(DummyValueRead ), 1, BMPFile);
bPaddingCount++;
}
printf("bPaddingCount = %d",bPaddingCount) ;
}
Thanks
Karan
1-bit bitmap format has 8 bytes for its palette, you have to read those 8 bytes before reading the pixels.
There are 8 pixels packed in to one byte. You have to separate the bits and write them accordingly. Bitmap can have width padding, you have to calculate the padding for the input file as well as output file.
Make sure to read/write the file in binary (it matters in Windows).
Example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#pragma pack(push, 1)
struct BITMAPFILEHEADER {
short bfType;
int bfSize;
short bfReserved1;
short bfReserved2;
int bfOffBits;
};
struct BITMAPINFOHEADER {
int biSize;
int biWidth;
int biHeight;
short biPlanes;
short biBitCount;
int biCompression;
int biSizeImage;
int biXPelsPerMeter;
int biYPelsPerMeter;
int biClrUsed;
int biClrImportant;
};
#pragma pack(pop)
int main(void)
{
//set X and Y offset:
int x0 = 10;
int y0 = 10;
if(sizeof(short) != 2 ||
sizeof(int) != 4 ||
sizeof(struct BITMAPFILEHEADER) != 14 ||
sizeof(struct BITMAPINFOHEADER) != 40)
{
printf("Error, wrong structure size...");
return -1;
}
FILE *fin = fopen("mul.bmp", "rb");
FILE *fout = fopen("output.bmp", "wb");
if(fin == NULL)
{
printf("Image Not Found !!!!!!");
return -1;
}
struct BITMAPFILEHEADER header;
struct BITMAPINFOHEADER info;
fread(&header, sizeof(header), 1, fin);
fread(&info, sizeof(info), 1, fin);
if (info.biBitCount != 1)
{
printf("Error, not 1-bit bitmap\n");
return -1;
}
int old_width = info.biWidth;
int old_height = info.biHeight;
int bitcount = info.biBitCount;
int width_in_bytes = ((old_width * bitcount + 31) / 32) * 4;
char palette[8];
fread(palette, 1, sizeof(palette), fin);
int new_width = old_width - x0;
int new_height = old_height - y0;
//convert to 24-bit bitmap for output file
info.biBitCount = 24;
info.biWidth = new_width;
info.biHeight = new_height;
info.biSizeImage = ((info.biHeight * bitcount + 31) / 32) * info.biWidth;
header.bfSize = 54 + info.biSizeImage;
header.bfOffBits = 54;
fwrite(&header, 1, sizeof(header), fout);
fwrite(&info, 1, sizeof(info), fout);
char *bytes_read = malloc(width_in_bytes);
char black[3] = { 0 };
char white[3] = { 255,255,255 };
for(int y = 0; y < old_height; y++)
{
fread(bytes_read, 1, width_in_bytes, fin);
int width_index = 0;
for(int i = 0; i < width_in_bytes; i++)
{
//8 pixels are packed in to 1 byte
//separate the bits, write them as bytes in 24-bit format
for(int j = 0; j < 8; j++)
{
width_index = i * 8 + j;
if(width_index < x0) continue;
if(width_index - x0 >= new_width) break;
int pixel = (bytes_read[i] & (1 << (8 - j)));
if(pixel)
fwrite(white, 1, 3, fout);
else
fwrite(black, 1, 3, fout);
}
}
//add padding to output file
int m = width_index % 4;
if(m)
fwrite(black, 1, m, fout);
}
fclose(fin);
fclose(fout);
return 0;
}
For learning purposes, I want to create a single 2x2 bitmap image using C programming language with no external libraries (such as SDL).
I've read that I need to create a header for the bitmap file but failed to understand how to implement it in code and why does the bmp header have those parameters. I can't find any clear tutorial on how I could do it using C.
Could you provide me some guidance on how to implement this by a simple documented example? I'm using Linux.
why does the bmp header have those parameters
The pixel data in bitmap is essentially a one-dimensional array of bytes. It's impossible to interpret this data without header information which reveals width, height, bit-count and other information about the bitmap.
There are different types of bitmaps, including different palette format and non-palette 16, 24, or 32 bits, and different types within some of these groups.
The header also includes other information which are there for historical reasons. This has little value for learning C. You just have to accept it.
The header information is in two structures BITMAPFILEHEADER and BITMAPINFO It's a little more complicated because the structures are expected to be packed.
The pixel data depends on the bitmap format. There is not a single bitmap format as mentioned earlier. The example below shows a 24-bit bitmap.
Other oddities is that the width of each row should always be multiple of 4 bytes. This called padding. Also the bitmap rows start at the bottom, not at the top. This is explained in other resources
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int main(void)
{
//width, height, and bitcount are the key factors:
int32_t width = 2;
int32_t height = 2;
uint16_t bitcount = 24;//<- 24-bit bitmap
//take padding in to account
int width_in_bytes = ((width * bitcount + 31) / 32) * 4;
//total image size in bytes, not including header
uint32_t imagesize = width_in_bytes * height;
//this value is always 40, it's the sizeof(BITMAPINFOHEADER)
const uint32_t biSize = 40;
//bitmap bits start after headerfile,
//this is sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)
const uint32_t bfOffBits = 54;
//total file size:
uint32_t filesize = 54 + imagesize;
//number of planes is usually 1
const uint16_t biPlanes = 1;
//create header:
//copy to buffer instead of BITMAPFILEHEADER and BITMAPINFOHEADER
//to avoid problems with structure packing
unsigned char header[54] = { 0 };
memcpy(header, "BM", 2);
memcpy(header + 2 , &filesize, 4);
memcpy(header + 10, &bfOffBits, 4);
memcpy(header + 14, &biSize, 4);
memcpy(header + 18, &width, 4);
memcpy(header + 22, &height, 4);
memcpy(header + 26, &biPlanes, 2);
memcpy(header + 28, &bitcount, 2);
memcpy(header + 34, &imagesize, 4);
//prepare pixel data:
unsigned char* buf = malloc(imagesize);
for(int row = height - 1; row >= 0; row--)
{
for(int col = 0; col < width; col++)
{
buf[row * width_in_bytes + col * 3 + 0] = 255;//blue
buf[row * width_in_bytes + col * 3 + 1] = 0;//green
buf[row * width_in_bytes + col * 3 + 2] = 0;//red
}
}
FILE *fout = fopen("test.bmp", "wb");
fwrite(header, 1, 54, fout);
fwrite((char*)buf, 1, imagesize, fout);
fclose(fout);
free(buf);
return 0;
}
You can rewrite this code using structures. In this code structure is packed with #pragma pack(push, 1) which is compiler dependent. Use this version if #pragma directive works.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#pragma pack(push, 1)
struct my_BITMAPFILEHEADER {
uint16_t bfType;
uint32_t bfSize;
uint16_t bfReserved1;
uint16_t bfReserved2;
uint32_t bfOffBits;
};
struct my_BITMAPINFOHEADER {
uint32_t biSize;
int32_t biWidth;
int32_t biHeight;
uint16_t biPlanes;
uint16_t biBitCount;
uint32_t biCompression;
uint32_t biSizeImage;
int32_t biXPelsPerMeter;
int32_t biYPelsPerMeter;
uint32_t biClrUsed;
uint32_t biClrImportant;
};
#pragma pack(pop)
int main(void)
{
if(sizeof(struct my_BITMAPFILEHEADER) != 14 &&
sizeof(struct my_BITMAPINFOHEADER) != 40)
{
printf("bitmap structures not packed properly\n");
return 0;
}
//only width and height can be changed in this code:
int width = 2;
int height = 2;
int bitcount = 24;//<- 24-bit bitmap
int width_in_bytes = ((width * bitcount + 31) / 32) * 4; //for padding
uint32_t imagesize = width_in_bytes * height; //total image size
struct my_BITMAPFILEHEADER filehdr = { 0 };
struct my_BITMAPINFOHEADER infohdr = { 0 };
memcpy(&filehdr, "BM", 2);//bitmap signature
filehdr.bfSize = 54 + imagesize;//total file size
filehdr.bfOffBits = 54; //sizeof(filehdr) + sizeof(infohdr)
infohdr.biSize = 40; //sizeof(infohdr)
infohdr.biPlanes = 1; //number of planes is usually 1
infohdr.biWidth = width;
infohdr.biHeight = height;
infohdr.biBitCount = bitcount;
infohdr.biSizeImage = imagesize;
//prepare pixel data:
unsigned char* buf = malloc(imagesize);
for(int row = height - 1; row >= 0; row--)
{
for(int col = 0; col < width; col++)
{
buf[row * width_in_bytes + col * 3 + 0] = 255;//blue
buf[row * width_in_bytes + col * 3 + 1] = 0;//red
buf[row * width_in_bytes + col * 3 + 2] = 0;//green
}
}
FILE *fout = fopen("test.bmp", "wb");
fwrite(&filehdr, sizeof(filehdr), 1, fout);
fwrite(&infohdr, sizeof(infohdr), 1, fout);
fwrite((char*)buf, 1, imagesize, fout);
fclose(fout);
free(buf);
return 0;
}
The first version used unsigned char header[54] to achieve the same thing. See the size of each data and its relative position in memory. The structure is 14 bytes long. bfType starts at 0, and is 2 bytes long (16 bits). bfSize starts at position 2, and is 4 bytes long...
struct my_BITMAPFILEHEADER {
uint16_t bfType; //starts at 0, 2 bytes long
uint32_t bfSize; //starts at 2, 4 bytes long
uint16_t bfReserved1; //starts at 6, 2 bytes long
uint16_t bfReserved2; //starts at 8, 2 bytes long
uint32_t bfOffBits; //starts at 10, 4 bytes long
};
Then you have the next structure which is 40 bytes long:
struct my_BITMAPINFOHEADER {
uint32_t biSize;//starts at 14
int32_t biWidth;//starts at 18
int32_t biHeight;//starts at 22
uint16_t biPlanes;//starts at 26
uint16_t biBitCount;//starts at 28
uint32_t biCompression;//starts at 30
uint32_t biSizeImage;//starts at 34
int32_t biXPelsPerMeter;
int32_t biYPelsPerMeter;
uint32_t biClrUsed;
uint32_t biClrImportant;
};
biSize starts at 0. But the previous structure was 14 bytes. So biSzie starts at 14. This should reveal the mystery of the numbers used in previous version to copy integers to header
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include <stdint.h>
long asciiToBinary(int n);
long asciiToBinary(int n) {
int remainder;
long binary = 0, i = 1;
while(n != 0) {
remainder = n%2;
n = n/2;
binary= binary + (remainder*i);
i = i*10;
}
return binary;
}
typedef struct
{ //BITMAPFILEHEADER
char bfType[2];
int bfSize;
short bfReserved1;
short bfReserved2;
int bfOffBits;
//BITMAPINFOHEADER
int biSize;
int biWidth;
int biHeight;
short biPlanes;
short biBitCount;
int biCompression;
int biSizeImage;
int biXPelsPerMeter;
int biYPelsPerMeter;
int biClrUsed;
int biClrImportant;
} BITMAPINFOHEADER;
typedef struct {
unsigned char blue;
unsigned char green;
unsigned char red;
} PIXEL;
int imageInfo(BITMAPINFOHEADER *img)
{
int offset = 0;
printf("------------------------------------------------------------- BITMAPFILEHEADER\n");
printf("0x%08X (%08d) bfType %8c%c (0x%04X)\n", offset, offset, img->bfType[0], img->bfType[1], *(short *)img->bfType);
offset += sizeof img->bfType;
printf("0x%08X (%08d) bfSize %9d (0x%08X)\n", offset, offset, img->bfSize, img->bfSize);
offset += sizeof img->bfSize;
printf("0x%08X (%08d) bfReserved1 %9hd (0x%04hX)\n", offset, offset, img->bfReserved1, img->bfReserved1);
offset += sizeof img->bfReserved1;
printf("0x%08X (%08d) bfReserved2 %9hd (0x%04hX)\n", offset, offset, img->bfReserved2, img->bfReserved2);
offset += sizeof img->bfReserved2;
printf("0x%08X (%08d) bfOffBits %9d (0x%08X)\n", offset, offset, img->bfOffBits, img->bfOffBits);
printf("------------------------------------------------------------- BITMAPINFOHEADER\n");
offset += sizeof img->bfOffBits;
printf("0x%08X (%08d) biSize %9d (0x%08X)\n", offset, offset, img->biSize, img->biSize);
offset += sizeof img->biSize;
printf("0x%08X (%08d) biWidth %9d (0x%08X)\n", offset, offset, img->biWidth, img->biWidth);
offset += sizeof img->biWidth;
printf("0x%08X (%08d) biHeight %9d (0x%08X)\n", offset, offset, img->biHeight, img->biHeight);
offset += sizeof img->biHeight;
printf("0x%08X (%08d) biPlanes %9d (0x%04hX)\n", offset, offset, img->biPlanes, img->biPlanes);
offset += sizeof img->biPlanes;
printf("0x%08X (%08d) biBitCount %9d (0x%04hX)\n", offset, offset, img->biBitCount, img->biBitCount);
offset += sizeof img->biBitCount;
printf("0x%08X (%08d) biCompression %9d (0x%08X)\n", offset, offset, img->biCompression, img->biCompression);
offset += sizeof img->biCompression;
printf("0x%08X (%08d) biSizeImage %9d (0x%08X)\n", offset, offset, img->biSizeImage, img->biSizeImage);
offset += sizeof img->biSizeImage;
printf("0x%08X (%08d) biXPelsPerMeter %9d (0x%08X)\n", offset, offset, img->biXPelsPerMeter, img->biXPelsPerMeter);
offset += sizeof img->biXPelsPerMeter;
printf("0x%08X (%08d) biYPelsPerMeter %9d (0x%08X)\n", offset, offset, img->biYPelsPerMeter, img->biYPelsPerMeter);
offset += sizeof img->biYPelsPerMeter;
printf("0x%08X (%08d) biClrUsed %9d (0x%08X)\n", offset, offset, img->biClrUsed, img->biClrUsed);
offset += sizeof img->biClrUsed;
printf("0x%08X (%08d) biClrImportant %9d (0x%08X)\n", offset, offset, img->biClrImportant, img->biClrImportant);
return offset;
}
int main(){
uint32_t RGB565ColorTable[] = {
0x7E00000, 0xF8000000, 0x001F0000, 0
};
uint16_t myData[64];
for(int i = 0; i<64; i++)
{
myData[i] = 0x241B; //Random Color
}
FILE *image;
const char filename[] = "full.bmp";
FILE *fichier = fopen(filename, "rb");
FILE *fptr = fopen("tth.bmp","w+");
if(!fichier)
printf ("Erreur a l'ouverture du fichier [%s]\n", filename);
else
{
BITMAPINFOHEADER *img = malloc(sizeof *img);
char fpath[1000],mydata[100];
BITMAPINFOHEADER bih;
int i=0,b[8],g[8],r[8];
double asciiTobinary;
image=fopen("full.bmp","rb");
fseek(image,2,SEEK_SET); //reading the height and width
fread(&bih.biSize,4,1,image);
printf("\n \n Size of the image=%d\n",bih.biSize);
fseek(image,18,SEEK_SET);
fread(&bih.biWidth,4,1,image);
fseek(image,22,SEEK_SET);
fread(&bih.biHeight,4,1,image);
printf("\n \n Width of the image =%d \n Height of the image =%d \n pixel = b | g | r \n \n",bih.biWidth,bih.biHeight);
PIXEL pic[bih.biWidth*bih.biHeight*2],p;
while(!feof(image)){ //reading the pixels rgb values
fread(&p.blue,sizeof(p.blue),1,image);
fread(&p.green,sizeof(p.green),1,image);
fread(&p.red,sizeof(p.red),1,image);
pic[i]=p;
printf(" %d= %u | %u | %u ",i+54,pic[i].blue,pic[i].green,pic[i].red);
i++; }
fclose(image);
if(img)
{
int i, tmp, offset;
printf("\n[%s]\n", filename);
fread(img, sizeof(BITMAPINFOHEADER), 1, fichier);
if(img->bfType[0] == 'B' && img->bfType[1] == 'M')
{
offset = imageInfo(img);
if(img->biBitCount == 1)
{
printf("---------------------------------------------------------------------- RGBQUAD\n");
fread(&tmp, sizeof tmp, 1, fichier);
offset += sizeof img->biClrImportant;
printf("0x%08X (%08d) %9d (0x%08X)\n", offset, offset, tmp, tmp);
fread(&tmp, sizeof tmp, 1, fichier);
offset += sizeof tmp;
printf("0x%08X (%08d) %9d (0x%08X)\n", offset, offset, tmp, tmp);
printf("------------------------------------------------------------------------- BITS\n");
for(i = 0; i < img->biSizeImage / (int)sizeof tmp; i++)
{
char bin[33];
fread(&tmp, sizeof tmp, 1, fichier);
offset += sizeof tmp;
printf("0x%08X (%08d) %8d (0x%08X) (%s)\n", offset, offset, tmp, tmp, itoa(tmp, bin, 2));
}
}
}
free(img);
}
fclose(fichier);
}
if(fptr == NULL) {
printf("Error!");
exit(1);
}
fwrite(&filename, sizeof(filename), 1, fptr);
//fwrite(&myInfoHeader, sizeof(myInfoHeader), 1, fptr);
fwrite(&RGB565ColorTable, sizeof(RGB565ColorTable), 1, fptr);
fwrite(&myData, sizeof(myData), 1, fptr);
fclose(fptr);
return 0;
}
I have a pixel information array who has the biSizeImage size and contains triplets of the form (blue, green, red) with values between 0 and 255. I must change my bmp color from red, to white, but i have a problem, as can be seen in picture.
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
int main()
{
BITMAPFILEHEADER file;
BITMAPINFOHEADER info;
FILE* f=fopen("imagine.bmp","rb");
fread(&file,sizeof(BITMAPFILEHEADER),1,f);
fread(&info,sizeof(BITMAPINFOHEADER),1,f);
RGBQUAD *a=malloc(info.biSizeImage*sizeof(RGBQUAD));
fread(a,sizeof(RGBQUAD),info.biSizeImage,f);
for(int i=0;i<info.biSizeImage;i++)
{
a[i].rgbBlue=255;
a[i].rgbGreen=255;
a[i].rgbRed=255;
}
FILE* f2=fopen("imagine2.bmp","wb");
if(f2==NULL)
printf("Error");
fwrite(&file,sizeof(BITMAPFILEHEADER),1,f2);
fwrite(&info,sizeof(BITMAPINFOHEADER),1,f2);
fwrite(a,sizeof(RGBQUAD),info.biSizeImage,f2);
return 0;
Output
Original image
info.biSizeImage can be zero. Check to make sure it is not zero, or calculate it based on stride. Width, height, and bitcount values are always set.
As noted in comments, 24 bit image has 3 bytes (24 bit) per pixel. RGBQUA is for 32-bit image. You have to iterate through the height, and then width 3 bytes at a time.
int main(void)
{
BITMAPFILEHEADER file;
BITMAPINFOHEADER info;
FILE* f = fopen("imagine.bmp", "rb");
fread(&file, sizeof(BITMAPFILEHEADER), 1, f);
fread(&info, sizeof(BITMAPINFOHEADER), 1, f);
if(info.biBitCount != 24)
return 0;
int stride = ((info.biWidth * info.biBitCount + 31) / 32) * 4;
int size = stride * info.biHeight;
BYTE *a = malloc(stride * info.biHeight);
fread(a, 1, size, f);
for(int y = info.biHeight - 1; y >= 0; y--)
{
for(int x = 0; x < stride; x += 3)
{
int i = y * stride + x;
a[i + 0] = 255;
a[i + 1] = 255;
a[i + 2] = 255;
}
}
FILE* f2 = fopen("imagine2", "wb");
if(f2 == NULL)
printf("Error");
fwrite(&file, sizeof(BITMAPFILEHEADER), 1, f2);
fwrite(&info, sizeof(BITMAPINFOHEADER), 1, f2);
fwrite(a, 1, size, f2);
return 0;
}
I want to read an text file Using C Language.Here's the file:-
You see there is some pattern in the text content on the file.
0 means nothing. 9 means black. so there is coloring scheme from 0 to 9.
I have to create a bitmap image of this and the color are according to the values in the pattern. You have to adjust it with the 0-256 color scheme.
And the final output for this is shown below
Now see the pattern in the content of the text file is opposite to the final output bitmap file (not necessary). The darkness of the colors in bitmap image is according to the values in the pattern of the text content.
Anyone will tell me how I achieve this in C language.
I am able to create a BMP file but not according to the pattern in text file.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char bitmap[1900];
// -- FILE HEADER -- //
// bitmap signature
bitmap[0] = 0x42;
bitmap[1] = 0x4d;
// file size
bitmap[2] = 58; // 40 + 14 + 12
bitmap[3] = 0;
bitmap[4] = 0;
bitmap[5] = 0;
int i=0;
// reserved field (in hex. 00 00 00 00)
for(i = 6; i < 10; i++) bitmap[i] = 0;
// offset of pixel data inside the image
for(i = 10; i < 14; i++) bitmap[i] = 0;
// -- BITMAP HEADER -- //
// header size
bitmap[14] = 40;
for(i = 15; i < 18; i++) bitmap[i] = 0;
// width of the image
bitmap[18] = 4;
for(i = 19; i < 22; i++) bitmap[i] = 0;
// height of the image
bitmap[22] = 1;
for(i = 23; i < 26; i++) bitmap[i] = 0;
// reserved field
bitmap[26] = 1;
bitmap[27] = 0;
// number of bits per pixel
bitmap[28] = 24; // 3 byte
bitmap[29] = 0;
// compression method (no compression here)
for(i = 30; i < 34; i++) bitmap[i] = 0;
// size of pixel data
bitmap[34] = 12; // 12 bits => 4 pixels
bitmap[35] = 0;
bitmap[36] = 0;
bitmap[37] = 0;
// horizontal resolution of the image - pixels per meter (2835)
bitmap[38] = 0;
bitmap[39] = 0;
bitmap[40] = 0b00110000;
bitmap[41] = 0b10110001;
// vertical resolution of the image - pixels per meter (2835)
bitmap[42] = 0;
bitmap[43] = 0;
bitmap[44] = 0b00110000;
bitmap[45] = 0b10110001;
// color pallette information
for(i = 46; i < 50; i++) bitmap[i] = 0;
// number of important colors
for(i = 50; i < 54; i++) bitmap[i] = 0;
// -- PIXEL DATA -- //
for(i = 54; i < 66; i++) bitmap[i] = 255;
FILE *file;
file = fopen("bitmap.bmp", "w+");
for(i = 0; i < 66; i++)
{
fputc(bitmap[i], file);
}
fclose(file);
return 0;
}
Here is a working code. I do not check some case of error (input file badly formatted, for example). I put some commentaries, though the code itself is not difficult to understand.
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include <errno.h>
#include <ctype.h>
#define BMP_ASSERT(condition, message) \
do { \
if (! (condition)) { \
fprintf(stderr, __FILE__ ":%d: %s: Assertion `" #condition \
"` failed.\n\t: %s\n", __LINE__, __func__, message); \
exit(EXIT_FAILURE); \
} \
} while (false)
#define BMP_COLORMAP_SIZE 10
////////////////////////////////////////////////////////////////////////////////
// STRUCTS
typedef struct __attribute__((__packed__))
bmp_color
{
uint8_t r,
g,
b;
uint8_t :8;
} bmp_color_t;
typedef struct __attribute__((__packed__))
bmp_header_infos
{
uint32_t const info_size;
uint32_t width;
uint32_t height;
uint16_t const planes;
uint16_t const bpp;
uint32_t const compression;
uint32_t img_size;
uint32_t const horz_resolution;
uint32_t const vert_resolution;
uint32_t const n_colors;
uint32_t const n_important_colors;
} bmp_header_infos_t;
typedef struct __attribute__((__packed__))
bmp_header
{
/* Header */
char const signature[2];
uint32_t file_size;
uint32_t const :32; // reserved
uint32_t const img_offset;
/* Infos */
bmp_header_infos_t infos;
/* Color map */
bmp_color_t colormap[BMP_COLORMAP_SIZE];
} bmp_header_t;
typedef struct bmp_file_datas
{
size_t width;
size_t height;
/* Bit map */
uint8_t *bitmap;
} bmp_file_datas_t;
////////////////////////////////////////////////////////////////////////////////
// FUNCTIONS
/* Give a header with the right magic values */
bmp_header_t *
bmp_get_header(void)
{
static bmp_header_t _header = {
{'B', 'M'},
0u,
sizeof(_header),
{ // struct info
sizeof(_header.infos),
0u, 0u, // width, height
1u, // planes
8u, // bpp
0u, // no compression
0u, // img size
0u, 0u, // resolution
BMP_COLORMAP_SIZE,
BMP_COLORMAP_SIZE, // important colors
},
{{0u}}
};
bmp_header_t *header = malloc(sizeof(_header));
size_t i,
color;
assert(header != NULL);
memcpy(header, &_header, sizeof(*header));
// setting the scale of greys
for (i = 0 ; i < BMP_COLORMAP_SIZE ; ++i)
{
color = (i * 255) / BMP_COLORMAP_SIZE;
header->colormap[i] = (bmp_color_t){color, color, color};
}
return header;
}
/* Take all the file content and store it in a buffer */
char *
get_file_content(char const *filename)
{
FILE *file_handler = fopen(filename, "r");
size_t file_len;
char *buff;
BMP_ASSERT(file_handler != NULL, strerror(errno));
fseek(file_handler, 0, SEEK_END);
file_len = ftell(file_handler);
fseek(file_handler, 0, SEEK_SET);
buff = malloc(file_len + 1);
assert(buff != NULL);
fread(buff, file_len, 1, file_handler);
buff[file_len] = '\0';
fclose(file_handler);
return buff;
}
/* Get the greatest multiple of 4 that is >= size */
static inline size_t
multiple_of_four(size_t size)
{
while (size % 4)
++size;
return size;
}
/* Get the informations from buffer: size of line, number of lines */
void
get_file_infos(char *buff, bmp_header_t *header, bmp_file_datas_t *datas)
{
/* width & height */
header->infos.width = strchr(buff, '\n') - buff;
header->infos.height = strlen(buff) / (header->infos.width + 1);
// + 1 for the terminating '\n'
datas->width = multiple_of_four(header->infos.width);
datas->height = header->infos.height;
printf("File size: %u, %u\n", header->infos.width, header->infos.height);
/* image size & bitmap allocation */
header->infos.img_size = datas->width * datas->height;
datas->bitmap = malloc(header->infos.img_size * sizeof(*datas->bitmap));
assert(datas->bitmap != NULL);
header->file_size = header->img_offset + header->infos.img_size;
}
/* Take the informations from the buffer and store them in the bitmap */
void
write_bitmap(char *buff, bmp_file_datas_t *datas)
{
size_t ibuff,
iline = 0,
ibitmap = 0;
for (ibuff = 0 ; buff[ibuff] ; ++ibuff)
{
if (isdigit(buff[ibuff]))
{
datas->bitmap[ibitmap] = BMP_COLORMAP_SIZE - 1 - (buff[ibuff] - '0');
++ibitmap;
}
else if (buff[ibuff] == '\n')
{
++iline;
ibitmap = iline * datas->width;
}
}
}
/* Write the datas in the file: the header and the bitmap */
void
write_in_file(bmp_header_t *header,
bmp_file_datas_t *datas,
char const *filename)
{
FILE *file_handler = fopen(filename, "w");
BMP_ASSERT(file_handler != NULL, strerror(errno));
fwrite(header, sizeof(*header), 1, file_handler);
fwrite(datas->bitmap, header->infos.img_size, 1, file_handler);
fclose(file_handler);
}
int main(int argc, char **argv)
{
char *buff;
bmp_header_t *header;
bmp_file_datas_t datas;
if (argc != 3)
{
fprintf(stderr, "Usage: %s <input filename> <output filename>\n",
argv[0]);
return EXIT_FAILURE;
}
buff = get_file_content(argv[1]);
header = bmp_get_header();
get_file_infos(buff, header, &datas);
write_bitmap(buff, &datas);
write_in_file(header, &datas, argv[2]);
free(buff), free(header), free(datas.bitmap);
return EXIT_SUCCESS;
}
A crude method to achieve the required functionality would be: (Not really C, but then it is your homework not mine)
WIDTH = 0, HEIGHT = 0
if(LINE=READ_LINE(fin))
WIDTH = strlen(LINE)
++HEIGHT
else
ERROR!!!
PUSH(LINE)
while(LINE=READ_LINE(fin))
if(WIDTH != strlen(LINE))
ERROR!!!
else
++HEIGHT
PUSH(LINE)
WRITE_BMP_HEADER(WIDTH, HEIGHT)
for(h = 0; h < HEIGHT; ++h)
LINE = POP()
for(w = 0; w < WIDTH; ++w)
COLOR = (LINE[w] - '0') * 255 / 9;
WRITE_BMP_COLOR(COLOR)
WRITE_BMP_PADDING(W)
#include < stdio.h >
#include < conio.h >
#include < stdlib.h >
#include < process.h >
#include < string.h >
#include < math.h >
int count = 0;
typedef struct bitmap24 {
unsigned char header[54];
unsigned char * pixels;
}BMP;
void readBMP(char * filename) {
int i;
FILE * f = fopen(filename, "rb");
FILE * f1 = fopen("save.bmp", "wb");
FILE * pixelVals = fopen("vals.dat", "w");
unsigned char bmppad[3] = {
0,
0,
0
};
if (!f) {
printf("Could not read file!\n");
exit(0);
}
unsigned char info[54];
fread(info, sizeof(unsigned char), 54, f);
int width = * (int * ) & info[18];
int height = * (int * ) & info[22];
unsigned char * img = NULL;
if (img)
free(img);
img = (unsigned char * ) malloc(3 * width * height);
memset(img, 0, sizeof(img));
fwrite(info, sizeof(unsigned char), 54, f1);
int length = width * height;
unsigned long int image[10000][3];
for (i = 0; i < length; i++) {
image[i][2] = getc(f); // blue
image[i][1] = getc(f); // green
image[i][0] = getc(f); // red
img[count] = 255 - (unsigned char) image[i][0];
//img[count] = 10*(unsigned char)log10((double)image[i][0]+1);
count += 1;
img[count] = 255 - (unsigned char) image[i][2];
//img[count] = 10*(unsigned char)log10((double)image[i][3]+1);
count += 1;
img[count] = 255 - (unsigned char) image[i][2];
//img[count] = 10*(unsigned char)log10((double)image[i][2]+1);
count += 1;
printf("pixel %d : [%d,%d,%d]\n", i + 1, image[i][0], image[i][4], image[i][2]);
fprintf(pixelVals, "pixel %d : [%d,%d,%d]\n", i + 1, image[i][0], image[i][5], image[i][2]);
}
for (i = height - 1; i >= 0; i--) {
fwrite(img + (width * (height - i - 1) * 3), 3, width, f1);
fwrite(bmppad, 1, (4 - (width * 3) % 4) % 4, f1);
}
fclose(f);
fclose(f1);
fclose(pixelVals);
}
void main() {
char * fileName = "bitgray.bmp";
readBMP(fileName);
getch();
}
I am not getting the correct result when the image is saved. I am using 24bit bmp image of dimensions 114 X 81. The image was coming out to be inverted initially but that issue was solved. But I am still getting a slanted image. I know the problem is in the last 'for' loop.
How should I solve it ?
Bitmap scanlines are padded to 4-byte boundary. So you need to add an extra two bytes so that the row is divisible by 4. At the moment, you have 114 * 3 = 342 bytes of pixel data per line. The next number divisible by 4 is 344.
So, at the end of reading each line, just read an extra two bytes and discard them.
In general, you can work out the extra bytes like this:
extra = (alignment - ((width * bytesPerPixel) % alignment)) % alignment;
Where in this case alignment is 4.
From memory, there is a field in the header that should contain the value of the full scanwidth (width * bytesPerPixel + extra), but it's a good idea not to expect it to be correct because you can calculate it easily.
You must also be aware of this padding rule when you save a bitmap.
Your second for loop looks strange. I believe it should be:
for(i = 0; i < height; i++) {...}
or:
for(i = height-1; i >= 0; i--) {...}