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.
Related
I have created with GIMP a C-Source image dump like the following:
/* GIMP RGBA C-Source image dump (example.c) */
static const struct {
guint width;
guint height;
guint bytes_per_pixel; /* 2:RGB16, 3:RGB, 4:RGBA */
guint8 pixel_data[304 * 98 * 2 + 1];
} example= {
304, 98, 2,
"\206\061\206\061..... }
Is there a way to convert this image from RG565 to RGB888?
I mean , I have found a way to covert pixel by pixel:
for (i = 0; i < w * h; i++)
{
uint16_t color = *RGB565p++;
uint8_t r = ((color >> 11) & 0x1F);
uint8_t g = ((color >> 5) & 0x3F);
uint8_t b = (color & 0x1F);
r = ((((color >> 11) & 0x1F) * 527) + 23) >> 6;
g = ((((color >> 5) & 0x3F) * 259) + 33) >> 6;
b = (((color & 0x1F) * 527) + 23) >> 6;
uint32_t RGB888 = r << 16 | g << 8 | b;
printf("%d \n", RGB888);
}
the problem is that using this logic I get numbers that are not represented as the one used n the original image:
P3
304 98
255
3223857
3223857
3223857
3223857
3223857
3223857
3223857
3223857
Did I miss something?
EDIT: here you can find the original image:
https://drive.google.com/file/d/1YBphg5_V6M2FA3HWcaFZT4fHqD6yeEOl/view
There are two things you need to do to create a C file similar to the original.
Increase the size of the pixel buffer, because you are creating three bytes per pixel from the original's two bytes.
Write strings that represent the new pixel data
The first part means simply changing the 2 to 3, so you get:
guint8 pixel_data[304 * 98 * 3 + 1];
} example= {
304, 98, 3,
In the second part the simplest method would be to print ALL characters in hexadecimal or octal representation. (The original code has the "printable" characters visible, but the non-printable as octal escape sequences.)
To print ALL the characters in hexadecimal representation, do similar to
for (i = 0; i < w * h; i++)
{
...
R, G and B calculation goes here
...
// Print start of line and string (every 16 pixels)
if (i % 16 == 0)
printf("\n\"");
printf("\\x%02x\\x%02x\\x%02x", r, g, b);
// Print end of string and line (every 16 pixels)
if ((i+1) % 16 == 0)
printf("\"\n");
}
printf("\"\n"); // Termination of last line
This prints three bytes in hex representation \xab\xcd\xef and after 16 pixels, prints end of string and newline.
Note that the byte order might need changing depending on your implementation. So b, g, r instead of r, g, b.
I want to convert a buffer of binary data in bytes into a buffer of sextets, where a sextet is a byte with the two most significant bits set to zero. I also want to do the reverse, i.e. convert a buffer of sextets back to bytes. As a test I am generating a buffer in bytes using a pseudo-random number generator that creates numbers between 0 and 255 using the built in version available in C. This is in order to simulate binary data. The details of the pseudo-random number generator and how good it is is of little importance, just that a stream of byte with various values is generated. Eventually a binary file will be read.
I've modified the functions in the link:
How do I base64 encode (decode) in C?
so that instead of encoding bytes to base64 characters, then decoding them back to bytes, sextets are used instead of base64. My encoding functions is as follows:
int bytesToSextets(int inx, int iny, int numBytes, CBYTE* byteData, BYTE* sextetData) {
static int modTable[] = { 0, 2, 1 };
int numSextets = 4 * ((numBytes + 2) / 3);
int i, j;
for (i = inx, j = iny; i < numBytes;) {
BYTE byteA = i < numBytes ? byteData[i++] : 0;
BYTE byteB = i < numBytes ? byteData[i++] : 0;
BYTE byteC = i < numBytes ? byteData[i++] : 0;
UINT triple = (byteA << 0x10) + (byteB << 0x08) + byteC;
sextetData[j++] = (triple >> 18) & 0x3F;
sextetData[j++] = (triple >> 12) & 0x3F;
sextetData[j++] = (triple >> 6) & 0x3F;
sextetData[j++] = triple & 0x3F;
}
for (int i = 0; i < modTable[numBytes % 3]; i++) {
sextetData[numSextets - 1 - i] = 0;
}
return j - iny;
}
where inx is the index in the input byte buffer where I want to start encoding, iny is the index in the output sextet buffer where the beginning of the sextets are written to, numBytes is the number of bytes to be encoded, and *byteData, *sextetData are the respective buffers to read from and write to. The last for-loop sets elements of sextetData to zero, not to '=' as given in the original code when there is padding. Although zero bytes can be valid data, as the length of the buffers are known in advance, I presume this is not a problem. The function returns with the number of sextets written, which can be checked against 4 * ((numBytes + 2) / 3). The first few sextets of the output buffer encode the number of bytes of data encodes in the rest of the buffer, with the number of sextets given in the formula.
The code for decoding sextets back to bytes is as follows:
int sextetsToBytes(int inx, int iny, int numBytes, CBYTE* sextetData, BYTE* byteData) {
int numSextets = 4 * ((numBytes + 2) / 3);
int padding = 0;
if (sextetData[numSextets - 1 + inx] == 0) padding++;
if (sextetData[numSextets - 2 + inx] == 0) padding++;
int i, j;
for (i = inx, j = iny; i < numSextets + inx;) {
UINT sextetA = sextetData[i++];
UINT sextetB = sextetData[i++];
UINT sextetC = sextetData[i++];
UINT sextetD = sextetData[i++];
UINT triple = (sextetA << 18) + (sextetB << 12) + (sextetC << 6) + sextetD;
if (j < numBytes) byteData[j++] = (triple >> 16) & 0xFF;
if (j < numBytes) byteData[j++] = (triple >> 8) & 0xFF;
if (j < numBytes) byteData[j++] = triple & 0xFF;
}
return j - iny - padding;
}
where as before inx and iny are the indices to start reading from and writing to a buffer, numBytes is the number of bytes that will be in the output buffer, from which the number of input sextets are calculated. The length of the input buffer is found from the first few sextets written by bytesToSextets(), so inx is the position in the input sextet buffer to start the actual conversion back to bytes. In the original function the number of sextets is given, from which the number of bytes is calculated using numSextets / 4 * 3. As this is already known, this is not done and should not make a difference. The last two arguments *sextetData and *byteData are the respectively input and output buffers.
An input buffer in bytes is created, converted to sextets, then as a test converted back to bytes. A comparison is made between the generated initial buffer of bytes and the output buffer in bytes after converting back from the intermediate sextet buffer. When the length of the input buffer is a multiple of 3, the match is perfect and the final output buffer is exactly the same. However, if the number of bytes in the initial buffer is not a multiple of 3, the last 3 bytes in the final output buffer may not match the original bytes. This has obviously something to do with the padding when the number of bytes is not a multiple of 3, but I am unable to find the source of the problem. Incidentally, the return values from the two functions are always correct, even when the last few bytes do not match.
In a header file I have the following typedefs:
typedef unsigned char BYTE;
typedef const unsigned char CBYTE;
typedef unsigned int UINT;
Although the main function is more complicated, in its simplest version it would have a form like:
// Allocate memory for bufA and bufB.
// Write the data length and other information into sextets 0 to 4 in bufB.
// Convert the bytes in bufA starting at index 0 to sextets in bufB starting at index 5.
int countSextets = bytesToSextets(0, 5, lenBufA, bufA, bufB);
// Allocate memory for bufC.
// Convert the sextets in bufB starting at index 5 back to bytes in bufC starting at index 0.
int countBytes = sextetsToBytes(5, 0, lenBufC, bufB, bufC);
As I said, this all works correctly, except that when the lenBufA is not a multiple of 3, the last 3 recovered bytes in bufC do not match those in bufA, but the calculated buffer lengths are all correct.
Perhaps someone can kindly help throw some light on this.
sextetData[numSextets - 1 - i] = 0; should be sextetData[iny + numSextets - 1 - i] = 0;.
The version of sextetsToBytes() I originally posted had the problem that I tested for padding by using:
if (sextetData[numSextets - 1 + inx] == 0) padding++;
if (sextetData[numSextets - 2 + inx] == 0) padding++;
as of course testing for '=' for base64 cannot be used, however, testing for zero can still cause problems, as zero can be a valid data item. This indeed sometimes caused a difference between the specified number of output bytes and the number found by counting up the bytes in the loop and subtracting the padding bytes. By just removing the padding bytes from the function, then checking the counted number returned against the specified input value numBytes, works. The modified code is as follows:
int sextetsToBytes(int numBytes, CBYTE* sextetData, BYTE* byteData) {
int numSextets = 4 * ((numBytes + 2) / 3);
int i, j;
for (i = 0, j = 0; i < numSextets;) {
UINT sextetA = sextetData[i++];
UINT sextetB = sextetData[i++];
UINT sextetC = sextetData[i++];
UINT sextetD = sextetData[i++];
UINT triple = (sextetA << 18) + (sextetB << 12) + (sextetC << 6) + sextetD;
if (j < numBytes) byteData[j++] = (triple >> 16) & 0xFF;
if (j < numBytes) byteData[j++] = (triple >> 8) & 0xFF;
if (j < numBytes) byteData[j++] = triple & 0xFF;
}
return j;
}
I am trying to read and display the disk geometry of a floppy in C. I was able to manage the first few entries (as far as I know of they're correct at least) such as:
Bytes per Sector
Sectors per Cluster
Reserved Sectors for the Boot Record
Number of FATS
My problem is I'm stuck at trying to figure out bit shifting for the rest of the geometry, which is what I was told to do in order to properly read in the values. I don't believe it's a problem with my code, but here is what I'm doing (SECTORSIZE is a const 512)::
void getSector(char *sector, int secNum, FILE *fp)
{
fseek(fp, (secNum*SECTORSIZE), SEEK_SET);
fread(sector, sizeof(char), SECTORSIZE, fp);
}
FILE *fp;
char sector[512];
unsigned int fileSize;
int i;
int diroffset;
char name[8];
name[0] = 0;
fp = fopen("floppy", "r");
//sector 0 contains the disk geometry
getSector(sector, 0, fp);
printf("Bytes per Sector: %d\n", (((unsigned int)sector[0x0c]) << 8u) | (unsigned int)sector[11]);
printf("Sectors per Cluster: %d\n", ((unsigned int)sector[0x0d] ));
printf("Reserved Sectors for the Boot Record: %d\n", (((unsigned int)sector[0x0f]) << 8u) | (unsigned int)sector[0x0e]);
printf("Number of FATS: %d\n", ((unsigned int)sector[0x10]));
//printf("Max # of Root Directory Entries: %d\n", (((unsigned int)sector[0x12]) << 8u) | (unsigned int)sector[0x11]);
//printf("Number of Sectors: %d\n", (((unsigned int)sector[12])) | (unsigned int)sector[11]);
//printf("Sectors per FAT: %d\n", ((unsigned int)sector[13] << 8u));
//printf("Sectors per Track: %d\n", (((unsigned int)sector[12]) << 8u) | (unsigned int)sector[11]);
//printf("Number of Surfaces: %d\n", (((unsigned int)sector[12]) << 8u) | (unsigned int)sector[11]);
The commented out sections are the parts where I'm still working on them. I pretty much just copied the first line and just changed the string name to match. The next one after number of FATS is the max # of root directories which is where I'm running into trouble. I have a list of the hex representation for each geometry location but the bit shifting is what's throwing me off.
However I am also noticing that when I'm displaying filenames I'm displaying an extra name of random characters. Below is how I'm finding filenames:
diroffset = 0;
while(diroffset <= 512) {
getSector(sector, 19, fp);
// print name of the file
if((void *) sector[0] != NULL)
for(i = 0; i < 8; i++)
name[i] = sector[diroffset + i];
if(name[0] != 0) {
printf("Filename: ");
for(i = 0; i < 8; i++)
printf("%c", name[i]);
putchar('\n');
}
name[0] = 0;
diroffset += 32;
}
It was my understanding that every 32 you would have a new filename, which it works as far as I know except displaying these characters as the last file found:
Filename: É·╬╩
I would like some more clarification on bit shifting in general, such as when and where to bit shift. I was trying to follow examples provided to me but maybe I'm just over complicating something and I'm not seeing it.
PS: If you're curious why I have so many unsigned int it's because my IDE complains otherwise when using bit operators
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 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() { }