Reputation: 8720
Is it possible to write a class that will take vector of Pixels:
struct Pixel
{
unsigned char Blue;
unsigned char Green;
unsigned char Red;
unsigned char Alpha;
};
And generate a BMP from the vector. I am attempting to start from a basic example, so I am trying with just 4 Pixels, so that is why some of the header values are hard coded.
Here is my header:
uint16_t const BITMAP_FILE_TYPE = 0x4d42; //BM, little-endian
static uint32_t const BITS_PER_BYTE = 8;
static uint32_t const BITS_PER_PIXEL = 24;
#pragma pack(1)
struct BITMAPFILEHEADER {
//uint16_t bfType;
uint32_t bfSize;
uint16_t bfReserved1;
uint16_t bfReserved2;
uint32_t bfOffBits;
}; BITMAPFILEHEADER;
struct 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;
}; BITMAPINFOHEADER;
#pragma pack()
inline uint64_t CalcBitmapFileSize(uint32_t widthBytes, uint32_t height) {
uint64_t fileSize = widthBytes * height;
uint32_t padSize = (widthBytes) % sizeof(uint32_t);
if (padSize > 0) {
padSize = sizeof(uint32_t) - padSize;
padSize *= height;
}
fileSize += padSize;
fileSize += sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
return fileSize;
}
class BitMapFileWriter
{
public:
BitMapFileWriter();
void WriteBMPFile(vector<Pixel> pixelVec, string fileName, uint32_t WIDTH, uint32_t HEIGHT);
};
And here is my impl:
void BitMapFileWriter::WriteBMPFile(vector<Pixel> pixelVec, string fileName, uint32_t WIDTH, uint32_t HEIGHT)
{
FILE *filePtr; // file pointer
BITMAPFILEHEADER bitmapFileHeader; // bitmap file header
BITMAPINFOHEADER bitmapInfoHeader; // bitmap info header
memset(&bitmapFileHeader, 0, sizeof(bitmapFileHeader));
memset(&bitmapInfoHeader, 0, sizeof(bitmapInfoHeader));
// open file for writing binary mode
filePtr = fopen("C:\\BMP\\4PixelOutPut.bmp", "wb");
// define the bitmap file header
//bitmapFileHeader.bfType = BITMAP_FILE_TYPE;
unsigned short bfType=0x4d42;
bitmapFileHeader.bfSize = static_cast<uint32_t>(CalcBitmapFileSize(WIDTH * (BITS_PER_PIXEL / BITS_PER_BYTE), HEIGHT));
bitmapFileHeader.bfReserved1 = 0;
bitmapFileHeader.bfReserved2 = 0;
bitmapFileHeader.bfOffBits = sizeof(bitmapFileHeader) + sizeof(bitmapInfoHeader);
// define the bitmap information header
bitmapInfoHeader.biSize = sizeof(bitmapInfoHeader);
bitmapInfoHeader.biWidth = WIDTH; // bitmap width
bitmapInfoHeader.biHeight = HEIGHT; // bitmap height
bitmapInfoHeader.biPlanes = 1;
bitmapInfoHeader.biBitCount = BITS_PER_PIXEL;
bitmapInfoHeader.biCompression = 0; // no compression
bitmapInfoHeader.biSizeImage = (WIDTH * HEIGHT) * 4; // width * height
bitmapInfoHeader.biXPelsPerMeter = 5000;
bitmapInfoHeader.biYPelsPerMeter = 5000;
bitmapInfoHeader.biClrUsed = 0;
bitmapInfoHeader.biClrImportant = 0;
fwrite(&bfType,1,sizeof(bfType),filePtr);
// write the bitmap file header
fwrite(&bitmapFileHeader, 1, sizeof(BITMAPFILEHEADER), filePtr);
// write the bitmap info header
fwrite(&bitmapInfoHeader, 1, sizeof(BITMAPINFOHEADER), filePtr);
for(int i=0; i<4; i++)
{
Pixel pixel = pixelVec[i];
fwrite(&pixel.Blue, 1, 1, filePtr);
fwrite(&pixel.Green, 1, 1, filePtr);
fwrite(&pixel.Red, 1, 1, filePtr);
}
// close our file
fclose(filePtr);
}
And calling it: BitMapFileWriter bmfw; bmfw.WriteBMPFile(pixelVec,"c:\BMP\4PixelBMP.txt", 2, 2);
Upvotes: 0
Views: 1015
Reputation: 3107
I found this class lying around which you might be able to use as reference. It's a "surface" class with members for width, height and a std::vector
of (32-bit) pixel colors.
Its Save
member function saves the surface to a .bmp file. It could easily be transformed into into a stand-alone function taking a width, height and vector.
The Writer
class wraps an ofstream
object and supplies the file output interface used in Save
.
The BIH
struct should look familiar, and the rest of Surface
's member functions provide a very minimal drawing API.
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
struct Color {
union {
struct { unsigned char b,g,r,a; };
unsigned char bytes[4];
unsigned int ref;
};
Color(unsigned int ref=0) : ref(ref) {}
};
class Surface {
int width, height;
std::vector<Color> pixels;
public:
void Fill(Color color) { std::fill(pixels.begin(), pixels.end(), color); }
void HLine(int left, int y, int len, Color color) {
if(y < 0 || y >= height || left >= width) { return; }
if(left < 0) { len += left; left = 0; }
if(left + len > width) { len = width - left; }
int offset = y * width + left;
std::fill(pixels.begin() + offset, pixels.begin() + offset + len, color);
}
void RectFill(int x, int y, int w, int h, Color color) {
for(int i=0; i<h; ++i) { HLine(x, y + i, w, color); }
}
Surface(int width, int height) :
width(width),
height(height),
pixels(width*height, Color())
{}
template <typename I> Color& operator () (const I& x, const I& y) { return pixels[y*width+x]; }
template <typename I> const Color& operator () (const I& x, const I& y) const { return pixels[y*width+x]; }
class Writer {
std::ofstream ofs;
public:
Writer(const char* filename) : ofs(filename, std::ios_base::out | std::ios_base::binary) {}
void operator () (const void* pbuf, int size) { ofs.write(static_cast<const char*>(pbuf), size); }
template <typename T> void operator () (const T& obj) { operator () (&obj, sizeof(obj)); }
};
struct BIH {
unsigned int sz;
int width, height;
unsigned short planes;
short bits;
unsigned int compress, szimage;
int xppm, yppm;
unsigned int clrused, clrimp;
};
void Save(const char* filename) const {
Writer w(filename);;
w("BM", 2);
BIH bih = {sizeof(bih)};
bih.width = width;
bih.height = -height;
bih.planes = 1;
bih.bits = 32;
const unsigned int headersize = sizeof(bih) + 14;
const int szbuf = int(sizeof(Color) * pixels.size());
const unsigned int filesize = static_cast<unsigned int>(headersize + szbuf);
w(filesize);
const unsigned short z = 0;
w(z);
w(z);
w(headersize);
w(bih);
w(pixels.data(), szbuf);
}
};
int main() {
Surface surf(600, 600);
Color color;
for(int j=0; j<12; ++j) {
color.g = 0;
for(int i=0; i<12; ++i) {
color.b = 255 - (color.g + color.r) / 2;
surf.RectFill(i*50, j*50, 50, 50, color);
color.g += 21;
}
color.r += 21;
}
surf.Save("MyBmpFile.bmp");
}
Upvotes: 1