Perhaps you will find this C program useful. It receives ASCII formatted 8 bit grey scale image data from the ESP32-CAM and writes a .bmp image file on a windows PC.
Currently, the program is configured to read a Teraterm log file, resulting from using Teraterm as the "serial monitor" for the ESP32-CAM. Developed using the Code::Blocks IDE.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const int BYTES_PER_PIXEL = 3; /// red, green, & blue
const int FILE_HEADER_SIZE = 14;
const int INFO_HEADER_SIZE = 40;
void generateBitmapImage(unsigned char* image, int height, int width, char* imageFileName);
unsigned char* createBitmapFileHeader(int height, int stride);
unsigned char* createBitmapInfoHeader(int height, int width);
char buf[200]; //line input buffer
int main ()
{
int width = 320;
int height = 240;
int nlines = 0;
unsigned char image[height][width][BYTES_PER_PIXEL];
char* imageFileName = (char*) "image.bmp";
char* formattedFileName = (char*) "teraterm.log";
FILE *fpin, *fpout;
// read formatted image data produced by ESP32-CAM
fpin = fopen(formattedFileName, "r");
if (fpin == NULL) {printf("Input file not found"); return 0;}
// get the number of lines in the file
while(fgets(buf, 100, fpin) != NULL)
nlines++;
rewind(fpin);
printf("%d lines in input file\n",nlines);
// read till '*', beginning of image data
buf[0]=0;
nlines = 0;
while (buf[0] != '*') {
fgets(buf, 100, fpin);
nlines++;
}
printf("%d lines skipped at beginning\r\n",nlines);
nlines = 0;
int i=0, j=0;
int h_one = height-1; //bitmap indexing, upside down for .BMP format
unsigned char raw;
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
fgets(buf, 100, fpin);
nlines++;
// printf("%s",buf);
// if (buf[0] == '*') printf("* encountered at line %d\r\n",nlines);
raw = atoi(buf);
image[h_one-i][j][2] = (unsigned char) ( raw ); //red
image[h_one-i][j][1] = (unsigned char) ( raw ); //green
image[h_one-i][j][0] = (unsigned char) ( raw ); //blue
}
}
generateBitmapImage((unsigned char*) image, height, width, imageFileName);
printf("Image generated!!");
}
void generateBitmapImage (unsigned char* image, int height, int width, char* imageFileName)
{
int widthInBytes = width * BYTES_PER_PIXEL;
unsigned char padding[4] = {0, 0, 0, 0}; //bug fix SJR
int paddingSize = (4 - (widthInBytes) % 4) % 4;
printf("padding bytes %d\r\n", paddingSize);
int stride = (widthInBytes) + paddingSize;
FILE* imageFile = fopen(imageFileName, "wb");
unsigned char* fileHeader = createBitmapFileHeader(height, stride);
fwrite(fileHeader, 1, FILE_HEADER_SIZE, imageFile);
unsigned char* infoHeader = createBitmapInfoHeader(height, width);
fwrite(infoHeader, 1, INFO_HEADER_SIZE, imageFile);
int i;
for (i = 0; i < height; i++) {
fwrite(image + (i*widthInBytes), BYTES_PER_PIXEL, width, imageFile);
// if(paddingSize > 0)
fwrite(padding, 1, paddingSize, imageFile);
}
fclose(imageFile);
}
unsigned char* createBitmapFileHeader (int height, int stride)
{
int fileSize = FILE_HEADER_SIZE + INFO_HEADER_SIZE + (stride * height);
static unsigned char fileHeader[] = {
0,0, /// signature
0,0,0,0, /// image file size in bytes
0,0,0,0, /// reserved
0,0,0,0, /// start of pixel array
};
fileHeader[ 0] = (unsigned char)('B');
fileHeader[ 1] = (unsigned char)('M');
fileHeader[ 2] = (unsigned char)(fileSize );
fileHeader[ 3] = (unsigned char)(fileSize >> 8);
fileHeader[ 4] = (unsigned char)(fileSize >> 16);
fileHeader[ 5] = (unsigned char)(fileSize >> 24);
fileHeader[10] = (unsigned char)(FILE_HEADER_SIZE + INFO_HEADER_SIZE);
return fileHeader;
}
unsigned char* createBitmapInfoHeader (int height, int width)
{
static unsigned char infoHeader[] = {
0,0,0,0, /// header size
0,0,0,0, /// image width
0,0,0,0, /// image height
0,0, /// number of color planes
0,0, /// bits per pixel
0,0,0,0, /// compression
0,0,0,0, /// image size
0,0,0,0, /// horizontal resolution
0,0,0,0, /// vertical resolution
0,0,0,0, /// colors in color table
0,0,0,0, /// important color count
};
infoHeader[ 0] = (unsigned char)(INFO_HEADER_SIZE);
infoHeader[ 4] = (unsigned char)(width );
infoHeader[ 5] = (unsigned char)(width >> 8);
infoHeader[ 6] = (unsigned char)(width >> 16);
infoHeader[ 7] = (unsigned char)(width >> 24);
infoHeader[ 8] = (unsigned char)(height );
infoHeader[ 9] = (unsigned char)(height >> 8);
infoHeader[10] = (unsigned char)(height >> 16);
infoHeader[11] = (unsigned char)(height >> 24);
infoHeader[12] = (unsigned char)(1);
infoHeader[14] = (unsigned char)(BYTES_PER_PIXEL*8);
return infoHeader;
}