I have an SD card, SD card shield, and Arduino Uno R3. I need to write an image onto the SD card. I would much rather prefer going from a raw array to JPEG/PNG/BMP/etc, rather than using the formats that are easy to write, but not really openable (PPM, PGM, etc).
Is the image writing function included in the Arduino standard libraries? If not, what library should I use? I've looked at lodePNG, but ran into weird errors (vector is not a member of std).
I take zero credit for this code as I pulled it from a thread on the Arduino forums (http://forum.arduino.cc/index.php?topic=112733.0). It writes a .bmp file to an SD card.
Another discussion indicated that because of the compression algorithms associated with JPG and PNG files, the amount of code to make those work would be more difficult to fit on an Arduino, which makes sense in my head (http://forum.arduino.cc/index.php?topic=76376.0).
Hope this helps. Definitely not an expert with Arduino - just tinkered a bit.
#include <SdFat.h>
#include <SdFatUtil.h>
/*
WRITE BMP TO SD CARD
Jeff Thompson
Summer 2012
TO USE MEGA:
The SdFat library must be edited slightly to use a Mega - in line 87
of SdFatConfig.h, change to:
#define MEGA_SOFT_SPI 1
(this uses pins 10-13 for writing to the card)
Writes pixel data to an SD card, saved as a BMP file. Lots of code
via the following...
BMP header and pixel format:
http://stackoverflow.com/a/2654860
SD save:
http://arduino.cc/forum/index.php?topic=112733 (lots of thanks!)
... and the SdFat example files too
www.jeffreythompson.org
*/
char name[] = "9px_0000.bmp"; // filename convention (will auto-increment)
const int w = 16; // image width in pixels
const int h = 9; // " height
const boolean debugPrint = true; // print details of process over serial?
const int imgSize = w*h;
int px[w*h]; // actual pixel data (grayscale - added programatically below)
SdFat sd;
SdFile file;
const uint8_t cardPin = 8; // pin that the SD is connected to (d8 for SparkFun MicroSD shield)
void setup() {
// iteratively create pixel data
int increment = 256/(w*h); // divide color range (0-255) by total # of px
for (int i=0; i<imgSize; i++) {
px[i] = i * increment; // creates a gradient across pixels for testing
}
// SD setup
Serial.begin(9600);
if (!sd.init(SPI_FULL_SPEED, cardPin)) {
sd.initErrorHalt();
Serial.println("---");
}
// if name exists, create new filename
for (int i=0; i<10000; i++) {
name[4] = (i/1000)%10 + '0'; // thousands place
name[5] = (i/100)%10 + '0'; // hundreds
name[6] = (i/10)%10 + '0'; // tens
name[7] = i%10 + '0'; // ones
if (file.open(name, O_CREAT | O_EXCL | O_WRITE)) {
break;
}
}
// set fileSize (used in bmp header)
int rowSize = 4 * ((3*w + 3)/4); // how many bytes in the row (used to create padding)
int fileSize = 54 + h*rowSize; // headers (54 bytes) + pixel data
// create image data; heavily modified version via:
// http://stackoverflow.com/a/2654860
unsigned char *img = NULL; // image data
if (img) { // if there's already data in the array, clear it
free(img);
}
img = (unsigned char *)malloc(3*imgSize);
for (int y=0; y<h; y++) {
for (int x=0; x<w; x++) {
int colorVal = px[y*w + x]; // classic formula for px listed in line
img[(y*w + x)*3+0] = (unsigned char)(colorVal); // R
img[(y*w + x)*3+1] = (unsigned char)(colorVal); // G
img[(y*w + x)*3+2] = (unsigned char)(colorVal); // B
// padding (the 4th byte) will be added later as needed...
}
}
// print px and img data for debugging
if (debugPrint) {
Serial.print("\nWriting \"");
Serial.print(name);
Serial.print("\" to file...\n");
for (int i=0; i<imgSize; i++) {
Serial.print(px[i]);
Serial.print(" ");
}
}
// create padding (based on the number of pixels in a row
unsigned char bmpPad[rowSize - 3*w];
for (int i=0; i<sizeof(bmpPad); i++) { // fill with 0s
bmpPad[i] = 0;
}
// create file headers (also taken from StackOverflow example)
unsigned char bmpFileHeader[14] = { // file header (always starts with BM!)
'B','M', 0,0,0,0, 0,0, 0,0, 54,0,0,0 };
unsigned char bmpInfoHeader[40] = { // info about the file (size, etc)
40,0,0,0, 0,0,0,0, 0,0,0,0, 1,0, 24,0 };
bmpFileHeader[ 2] = (unsigned char)(fileSize );
bmpFileHeader[ 3] = (unsigned char)(fileSize >> 8);
bmpFileHeader[ 4] = (unsigned char)(fileSize >> 16);
bmpFileHeader[ 5] = (unsigned char)(fileSize >> 24);
bmpInfoHeader[ 4] = (unsigned char)( w );
bmpInfoHeader[ 5] = (unsigned char)( w >> 8);
bmpInfoHeader[ 6] = (unsigned char)( w >> 16);
bmpInfoHeader[ 7] = (unsigned char)( w >> 24);
bmpInfoHeader[ 8] = (unsigned char)( h );
bmpInfoHeader[ 9] = (unsigned char)( h >> 8);
bmpInfoHeader[10] = (unsigned char)( h >> 16);
bmpInfoHeader[11] = (unsigned char)( h >> 24);
// write the file (thanks forum!)
file.write(bmpFileHeader, sizeof(bmpFileHeader)); // write file header
file.write(bmpInfoHeader, sizeof(bmpInfoHeader)); // " info header
for (int i=0; i<h; i++) { // iterate image array
file.write(img+(w*(h-i-1)*3), 3*w); // write px data
file.write(bmpPad, (4-(w*3)%4)%4); // and padding as needed
}
file.close(); // close file when done writing
if (debugPrint) {
Serial.print("\n\n---\n");
}
}
void loop() { }
Related
I have coded a chip-8 emulator.Whatever I do, it seems that I cannot show any pixels on the screen.The weird thing is that I have checked the code, top-bottom for 2 days already, and there does not seem to be any problem.It reads the .rom file into memory, and fetches the OP code correctly.
Here is the source code:
SDL_SetRenderDrawColor( renderer, 0, 0, 0, SDL_ALPHA_OPAQUE );
SDL_RenderClear(renderer);
uint32_t pixels[(WINDOW_WIDTH / 10) * (WINDOW_HEIGHT / 10)];
uint16_t i;
for(i = 0; i < 64*32; i++){
pixels[i] = (0x00FFFFFF * display[i]) | 0xFF000000;
}
//upload the pixels to the texture
SDL_UpdateTexture(tex,NULL,pixels, 64 * sizeof(uint32_t));
//Now get the texture to the screen
SDL_RenderCopy(renderer,tex,NULL,NULL);
SDL_RenderPresent(renderer); // Update screen
ch8.drawF = false;
uint16_t x = ch8->V[((ch8->opcode & 0x0F00) >> 8)];
uint16_t y = ch8->V[((ch8->opcode & 0x00F0) >> 4)];
uint8_t n = (ch8->opcode & 0x000F);
for(i = 0; i < n; i++) {
uint8_t pixel= memory[ch8->I.word + i];
for(j = 0; j < 8; j++) {
if((pixel & (0x80 >> j)) != 0){
if(display[x + j + ((y + i) * 64)] == 1) {
ch8->V[0xF] = 1;
}
display[x + j + ((y + i) * 64)] ^= 1;
}
}
}
So basically, the problem was at init() function.I was initially using, SDL_CreateWindow and SDL_CreateRenderer,but now I'm using ,SDL_CreateWindowAndRenderer, which takes pointers to pointers of SDL_Window and SDL_Renderer instead of a pointer to a char and a pointer to a window.
Also there were 3 problems I fixed.
1.I was adding + 0x200 to NNN opcodes,because at firstly I thought that the NNN in ROM's are relative to 0, so I removed +0x200 from each XNNN opcode.Also I forgot a * at SDL_Texture* tex, its supposed to be SDL_Texture** tex, I was merely changing the address the local pointer was poiting too...
2.at opcode 2NNN, instead of (ch8->SP) = ch8->opcode & 0x0FFF; its(ch8->SP) = ch8->PC.word;
3.at opcode FX65 its i <= ((ch8->opcode & 0x0F00) >> 8)
Basically, the differences between SDL_CreateWindowAndRenderer and SDL_CreateWindow&SDL_CreateRenderer had me confused, I should had check'd the documentation first.
Now I only need to make the emulator only redraw the changed pixels, then make the emulator play sound.
I'm not sure wheather my PC is trying to fool me or if I'm just to tired to find the bug. For hours and almost days I'm trying to write a bitmap file in pure C. I don't have any problems with the format or the padding, but the content.
Here's a MWE.
int main() {
FILE *file;
int w = 256;
int h = 15;
int pad = (4 - ((3 * w) % 4)) % 4;
int filesize = 54 + (3 * w + pad) * h;
// Create file header
unsigned char bmpfileheader[14] = { 'B','M', 0,0,0,0, 0,0, 0,0, 54,0,0,0 };
bmpfileheader[2] = (unsigned char)(filesize);
bmpfileheader[3] = (unsigned char)(filesize >> 8);
bmpfileheader[4] = (unsigned char)(filesize >> 16);
bmpfileheader[5] = (unsigned char)(filesize >> 24);
// Create Info Header
unsigned char bmpinfoheader[40] = { 40,0,0,0, 0,0,0,0, 0,0,0,0, 1,0, 24,0 };
bmpinfoheader[4] = (unsigned char)(w);
bmpinfoheader[5] = (unsigned char)(w >> 8);
bmpinfoheader[6] = (unsigned char)(w >> 16);
bmpinfoheader[7] = (unsigned char)(w >> 24);
bmpinfoheader[8] = (unsigned char)(h);
bmpinfoheader[9] = (unsigned char)(h >> 8);
bmpinfoheader[10] = (unsigned char)(h >> 16);
bmpinfoheader[11] = (unsigned char)(h >> 24);
// Create content
// Allocate memory dynamically
unsigned char *bmpcontent = (unsigned char *)calloc(filesize - 54, sizeof(unsigned char));
int index;
// map data values onto blue-red scale
for (int j = 0; j < h; j++)
{
for (int i = 0; i < w; i++)
{
index = 3 * i + (3 * w + pad) * j;
// blue
*(bmpcontent + index) = 255-i;
}
}
// Write to file
file = fopen("test.bmp", "w");
fwrite(bmpfileheader, sizeof(bmpfileheader[0]), 14, file);
fwrite(bmpinfoheader, sizeof(bmpinfoheader[0]), 40, file);
fwrite(bmpcontent, sizeof(bmpcontent[0]), filesize - 54, file);
fclose(file);
// free memory
free(bmpcontent);
return 0;
}
As I'm filling the 'blue-byte' of each pixel with 255-i I'm expecting to get a smooth fade from dark blue to black in each line. But I'm getting this:
example1
As you can see there is a byte-shift in each line which causes a change of color in each new line plus a pixel-shift after every third line. The curious thing is, that it only happens, when I'm trying to write a 13 into the file. Using a hex editor I found out, that a second 13 is written before the next value finds its way into the file. When I'm reducing the width to 240 (now the content of the bitmap varies between 14 and 255) I'm getting the smooth picture without any shifts: example2
You may say that it is pure coincidence that this fault appears while writing a 13 and it may be so. But I also tried to write data into the file where the 13 appeared at non-deterministic positions, and exactly the same effect occured.
I'm at my wits end, please help me!!!
It's because a value of 13 corresponds with a newline in Windows. Windows newlines are \r\n, which corresponds to hex 0D0A. Since you're trying to write 0D, it's treated as a newline, so it's getting written to the file as 0D0A. This is so that if you put only \n in a string, it will correctly be written as \r\n to a file. Thus, to fix this, you should make sure you're writing to the file in binary mode, which prevents this "feature" from writing the extra byte to the file. See here for more info: Strange 0x0D being added to my binary file
To use binary mode, just replace "w" with "wb" in your fopen, and it will work fine. I've verified this just now, and the output is correct:
On other platforms, this problem won't happen in the first place, so this fix will only work on, and is only needed for, Windows platforms.
I want to read bmp image and draw the pixel values in GUI window but it is
not giving me the correct result,the picture it is showing is completely different then the original image I don't know where I am going wrong.
any help?
int main() {
char filename[100];
printf("Enter the bitmap image name:");
scanf("%s",filename);
int i;
FILE* f = fopen(filename, "rb");
if(f == NULL)
throw "Argument Exception";
unsigned char info[54];
fread(info, sizeof(unsigned char), 54, f); // read the 54-byte header
// extract image height and width from header
int width = *(int*)&info[18];
int height = *(int*)&info[22];
int gdriver = DETECT, gmode;
initgraph (&gdriver, &gmode,"");
cout << " Name: " << filename << endl;
cout << " Width: " << width << endl;
cout << "Height: " << height << endl;
int row_padded = (width*3 + 3) & (~3);
unsigned char* data = new unsigned char[row_padded];
unsigned char tmp;
for(int i = 0; i < height; i++)
{
fread(data, sizeof(unsigned char), row_padded, f);
for(int j = 0; j < width; j += 3)
{
// Convert (B, G, R) to (R, G, B)
tmp = data[j];
data[j] = data[j+2];
data[j+2] = tmp;
int last=width*height;
int index=last;
cout << "R: "<< (int)data[j] << " G: " << (int)data[j+1]<< " B: " << (int)data[j+2]<< endl;
cout <<((data[j] & 0xff) << 16) + ((data[j+1] & 0xff) << 8) + (data[j+2] & 0xff);
cout<<"number of time" <<i;
unsigned long rgb = 0xFA09CA;
rgb =((data[j] & 0xff) << 16) + ((data[j+1] & 0xff) << 8) + (data[j+2] & 0xff);
putpixel(j,i,data[j]);
putpixel(j,i,data[j+1]);
putpixel(j,i,data[j+1]);
}
}
getch();
}
putpixel(j,i,data[j]);
putpixel(j,i,data[j+1]);
putpixel(j,i,data[j+1]);
You are very insistent that the pixel at [j][i] be changed, so much, that you are writing to the same pixel location 3 times.
Is there a pixel stream, where by each write puts the pixel into a queue or stream (like the SPI bus interface)?
The last line doesn't look correct either. I believe it should be data[j+2], but I dunno.
There may be other issues, but I can't use my debugger on your code.
This code seems to be using the BGI library from Borland to draw graphics under MS DOS. You have, in fact, specified to autodetect your graphics card, which will initialize it into VGA 16 paletized colors and planar mode (unless you are using an EGA card or older).
Later, you are reading what it seems to be a 24-bit color image from the BMP and putpixeling as if BGI would support 24 bits (which does not).
So your program needs a massive rewritting:
Init graphics and check result values to see what graphics mode the computer is.
Open BMP, read its properties and reject it if it doesn't fit your screen in the current graphics mode, or if it isn't a palettized image, or if the number of colors (palette entries) is greater than your graphics mode supports.
Read palette from BMP, adjust it to be 6 bits per primary color and update palette registers
Read pixels from BMP, and putpixel them, taking into account that BMP pictures are stored upside down
This is just for a basic display program. A more general solution would require you to add code to either resize of pan the image to display it in your screen. Besides, you would have to check if the picture is in true color format and if so, perform some dithering to reduce the number of colors to the maximum available in your graphics mode, and then assign a palette entry to each of them.
Consider, for example, this simple program to display RAW image files. The RAW file is assumed to be 640x480 pixels, and each pixel to have 3 bytes corresponding to its level of red, green and blue, in this order. The picture needs to be color downgraded previously, to have up to 16 different colors. The program reads pixels and assign its colors to palette index. If a new pixel is already present in the palette, its index is used in putpixel. If not, its color is added to the palette, the hardware palette is updated, and the new index is used in putpixel.
#include <conio.h>
#include <graphics.h>
#include <stdio.h>
#include <dos.h>
typedef struct
{
unsigned char r;
unsigned char g;
unsigned char b;
} RGB;
void setvgapalette (int entry, RGB *val);
int main()
{
int gdriver = VGA;
int gmodo = VGAHI;
RGB palette[16];
int indxp = 0;
FILE *f;
RGB pixel;
int x, y, i;
initgraph (&gdriver, &gmodo, "c:\\comp\\tc\\bgi");
f = fopen ("PICTURE.RAW", "rb");
fread (&pixel.r, 1, 1, f); //
fread (&pixel.g, 1, 1, f); // Read one pixel (first one)
fread (&pixel.b, 1, 1, f); //
x = 0;
y = 0;
while (!feof(f))
{
for (i=0;i<indxp;i++) // search pixel color in current palette
{
if (palette[i].r == pixel.r &&
palette[i].g == pixel.g &&
palette[i].b == pixel.b)
break; // if found, finish search
}
if (i==indxp) // if not found, add its color to the palette
{
palette[i] = pixel;
setvgapalette (i, &pixel);
indxp++;
}
putpixel (x, y, i); // put pixel with color from palette index
// Update coordinates for next pixel and exit if screen full
x++;
if (x==640)
{
x = 0;
y++;
if (y==480)
break;
}
fread (&pixel.r, 1, 1, f); //
fread (&pixel.g, 1, 1, f); // Read next pixel
fread (&pixel.b, 1, 1, f); //
}
fclose (f);
getch();
closegraph();
return 0;
}
void setvgapalette (int entry, RGB *val)
{
outp (0x3c8, entry); // palette entry to write to
outp (0x3c9, val->r/4); // 6 MSb of R
outp (0x3c9, val->g/4); // 6 MSb of G
outp (0x3c9, val->b/4); // 6 MSb of B
}
Use following getcol function to get correct color.
In your putpixel function replace data[i] by getcol(data[i]).
Color code for EGAVGA and bitmap are different.
int getcol(int col)
{
switch(col)
{
case 0: return 0; //BLACK;
case 1: return 4; //RED;
case 2: return 2; //GREEN
case 3: return 6; //BROWN
case 4: return 1; //BLUE;
case 5: return 5; //MAGENTA;
case 6: return 3; //CYAN;
case 7: return 7; //LIGHTGRAY;
case 8: return 8; //DARKGRAY;
case 9: return 12; //LIGHTRED;
case 10:return 10; //LIGHTGREEN
case 11:return 14; //YELLOW;
case 12:return 9; //LIGHTBLUE;
case 13:return 13; //LIGHTMAGENTA
case 14:return 11; //LIGHTCYAN;
case 15:return 15; //WHITE;
}
return col;
}
I need a different way to have global access to 160*160 bits of data, that wont cause me to run out of ram. I am trying to create a back buffer for a 160*160 LCD black and white screen. so 160*10 ints gives me 160*160 bits because a int is 16bits. However I am running out of RAM on the board. Does anyone have a way to this where I wont use the ram? maybe allocating in someway? but I cant seem to get a proper way to allocate a 2d array. Is there any other way of doing this?
edit:
it is a msp430 rbx430 board,(here is a link to a picture of it http://i.ytimg.com/vi/rr18why8wzY/0.jpg ) and yes int's are 16bits on this device. longs and doubles are 32bits. the device has 64k memory, and I am running it at 16mhz. I am asking for 3,200 bytes
as for it making sense, how does it not? I have a 64k device, where int's are 16bits. I am creating a map for the 160*160 lcd screen by using the 1's and 0's to keep track of when a pixel is on or off. after i turn on all the pixels i want, i then take my map and apply it to the lcd. This way I do not have to draw to the lcd then erase the lcd then draw again. I can simply draw, and then draw over it. this will make it so it will not flicker.
effectively creating a back buffer to draw to the lcd.
static int lcdPixels[160][10];
/*Must call this before using RBX430_graphics*/
void initGraphics(void)
{
int h = 0;
int w = 0;
for(h=0; h < ROW_SIZE; h++)
{
for(w=0; w < COLUMN_SIZE; w++)
{
lcdPixels[h][w] = 0;
}
}
}
---------------------------------here is the rest-----------------------
void pixelOn(int posX, int posY)
{
// first grab the right column
int column = ( ((float)posX/16.0f) + 0.9f);
// next grab the right bit
int bit = posX;
while(bit > 16)
{
bit = bit - 16;
}
//turn on the bit/pixel
lcdPixels[posY][column] |= (1 << bit);
}
void pixelOFF(int posX, int posY)
{
// first grab the right column
int column = ( ((float)posX/16.0f) + 0.9f);
// next grab the right bit
int bit = posX;
while(bit > 16)
{
bit = bit - 16;
}
//turn off the bit/pixel
lcdPixels[posY][column] &= ~(1 << bit);
}
/* Call this to commit the current backBuffer to the LCD display*/
void commitBuffer(void)
{
int h = 0;
int w = 0;
int k = 0;
for(h=0; h < ROW_SIZE; h++)
{
for(w=0; w < COLUMN_SIZE; w++)
{
for(k=0; k < INT_SIZE; k++)
{
if((lcdPixels[h][w] & (1 << k)) >> k)
{
lcd_point(((w * 16) + k), h, ON);
}
else
{
lcd_point(((w * 16) + k), h, OFF);
}
}
}
}
}
So i now tried to allocate the array using malloc, and that is a no go as well. I guess I just can not do this, 160*160 bits is just to much data....
Do you have 64K of RAM or 64K of Flash memory? I think the RBX430 has a msp430f2274 on it (http://www.ti.com/product/msp430f2274) which only has 1K of RAM.
I'm trying to make a bitmap in C, just from code. I'm currently trying to make a very easy .bmp image, with a height of 1px and a width of 4 pixels, with all white pixels. I have read the format description and tried to apply it. This resulted in the following code:
char bitmap[1000];
void BMPmake()
{
// -- FILE HEADER -- //
// bitmap signature
bitmap[0] = 'B';
bitmap[1] = 'M';
// file size
bitmap[2] = 66; // 40 + 14 + 12
bitmap[3] = 0;
bitmap[4] = 0;
bitmap[5] = 0;
// reserved field (in hex. 00 00 00 00)
for(int i = 6; i < 10; i++) bitmap[i] = 0;
// offset of pixel data inside the image
for(int i = 10; i < 14; i++) bitmap[i] = 0;
// -- BITMAP HEADER -- //
// header size
bitmap[14] = 40;
for(int i = 15; i < 18; i++) bitmap[i] = 0;
// width of the image
bitmap[18] = 4;
for(int i = 19; i < 22; i++) bitmap[i] = 0;
// height of the image
bitmap[22] = 1;
for(int 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(int 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(int i = 46; i < 50; i++) bitmap[i] = 0;
// number of important colors
for(int i = 50; i < 54; i++) bitmap[i] = 0;
// -- PIXEL DATA -- //
for(int i = 54; i < 66; i++) bitmap[i] = 0;
}
void BMPwrite()
{
FILE *file;
file = fopen("bitmap.bmp", "w+");
for(int i = 0; i < 66; i++)
{
fputc(bitmap[i], file);
}
fclose(file);
}
When I try to open this image, it says that the image is damaged. Am I missing something here?
I also noticed that the encoding of the .bmp integers is little endian. I thought that this mean that I have to reverse the order of the bytes. For example, 256 in four bytes is: 00000000 00000000 00000001 00000000, and I think in little endian this would be: 00000000 00000001 00000000 00000000
Can anyone give me a hand here? Am I using a right approach? Any help would be appreciated!
Thanks in advance!
Your pixel offset (bytes 10..13) is zero, but the pixel data don't actually start at the beginning of the file, they start at byte 54.
Also:
Your comment on byte 34 says "bits" but means "bytes", but of course that doesn't matter.
Your horizontal and vertical resolutions have the wrong byte order, but I very much doubt that that matters.
If I were doing this I'd define structs for the header data (indeed, if you're on Windows, Microsoft have already done this) and use a macro or something for putting bytes into the right order portably.
Whether you "have to reverse the order of the bytes" depends on the endianity of the processor you're using. Writing separate bytes separately, as you're doing, is an effective way to avoid having to worry about this.
Here is the code tested on linux.
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <malloc.h>
#define _height 600
#define _width 800
#define _bitsperpixel 24
#define _planes 1
#define _compression 0
#define _pixelbytesize _height*_width*_bitsperpixel/8
#define _filesize _pixelbytesize+sizeof(bitmap)
#define _xpixelpermeter 0x130B //2835 , 72 DPI
#define _ypixelpermeter 0x130B //2835 , 72 DPI
#define pixel 0xFF
#pragma pack(push,1)
typedef struct{
uint8_t signature[2];
uint32_t filesize;
uint32_t reserved;
uint32_t fileoffset_to_pixelarray;
} fileheader;
typedef struct{
uint32_t dibheadersize;
uint32_t width;
uint32_t height;
uint16_t planes;
uint16_t bitsperpixel;
uint32_t compression;
uint32_t imagesize;
uint32_t ypixelpermeter;
uint32_t xpixelpermeter;
uint32_t numcolorspallette;
uint32_t mostimpcolor;
} bitmapinfoheader;
typedef struct {
fileheader fileheader;
bitmapinfoheader bitmapinfoheader;
} bitmap;
#pragma pack(pop)
int main (int argc , char *argv[]) {
FILE *fp = fopen("test.bmp","wb");
bitmap *pbitmap = (bitmap*)calloc(1,sizeof(bitmap));
uint8_t *pixelbuffer = (uint8_t*)malloc(_pixelbytesize);
strcpy(pbitmap->fileheader.signature,"BM");
pbitmap->fileheader.filesize = _filesize;
pbitmap->fileheader.fileoffset_to_pixelarray = sizeof(bitmap);
pbitmap->bitmapinfoheader.dibheadersize =sizeof(bitmapinfoheader);
pbitmap->bitmapinfoheader.width = _width;
pbitmap->bitmapinfoheader.height = _height;
pbitmap->bitmapinfoheader.planes = _planes;
pbitmap->bitmapinfoheader.bitsperpixel = _bitsperpixel;
pbitmap->bitmapinfoheader.compression = _compression;
pbitmap->bitmapinfoheader.imagesize = _pixelbytesize;
pbitmap->bitmapinfoheader.ypixelpermeter = _ypixelpermeter ;
pbitmap->bitmapinfoheader.xpixelpermeter = _xpixelpermeter ;
pbitmap->bitmapinfoheader.numcolorspallette = 0;
fwrite (pbitmap, 1, sizeof(bitmap),fp);
memset(pixelbuffer,pixel,_pixelbytesize);
fwrite(pixelbuffer,1,_pixelbytesize,fp);
fclose(fp);
free(pbitmap);
free(pixelbuffer);
}
Open your file with a hex editor to see what is actually there. This will help you determine if your code is doing something unexpected.