C++ How to create a bitmap file - c++

I am trying to figure out how to create a bitmap file in C++ VS. Currently I have taken in the file name and adding the ".bmp" extension to create the file. I want to know how I could change the pixels of the file by making it into different colors or patterns (ie. like a checkerboard) This is my function that I have and I believe that I have to send 3 different Bytes at a time in order to establish the color of the pixel.
void makeCheckerboardBMP(string fileName, int squaresize, int n) {
ofstream ofs;
ofs.open(fileName + ".bmp");
writeHeader(ofs, n, n);
for(int row = 0; row < n; row++) {
for(int col = 0; col < n; col++) {
if(col % 2 == 0) {
ofs << 0;
ofs << 0;
ofs << 0;
} else {
ofs << 255;
ofs << 255;
ofs << 255;
}
}
}
}
void writeHeader(ostream& out, int width, int height){
if (width % 4 != 0) {
cerr << "ERROR: There is a windows-imposed requirement on BMP that the width be a
multiple of 4.\n";
cerr << "Your width does not meet this requirement, hence this will fail. You can fix
this\n";
cerr << "by increasing the width to a multiple of 4." << endl;
exit(1);
}
BITMAPFILEHEADER tWBFH;
tWBFH.bfType = 0x4d42;
tWBFH.bfSize = 14 + 40 + (width*height*3);
tWBFH.bfReserved1 = 0;
tWBFH.bfReserved2 = 0;
tWBFH.bfOffBits = 14 + 40;
BITMAPINFOHEADER tW2BH;
memset(&tW2BH,0,40);
tW2BH.biSize = 40;
tW2BH.biWidth = width;
tW2BH.biHeight = height;
tW2BH.biPlanes = 1;
tW2BH.biBitCount = 24;
tW2BH.biCompression = 0;
out.write((char*)(&tWBFH),14);
out.write((char*)(&tW2BH),40);
}

These are the two functions I am using for my code (one greyscale, one RGB saving).
Might give you a hint whats going wrong.
Note: they are done to work, not to be efficient.
void SaveBitmapToFile( BYTE* pBitmapBits, LONG lWidth, LONG lHeight,WORD wBitsPerPixel, LPCTSTR lpszFileName )
{
RGBQUAD palette[256];
for(int i = 0; i < 256; ++i)
{
palette[i].rgbBlue = (byte)i;
palette[i].rgbGreen = (byte)i;
palette[i].rgbRed = (byte)i;
}
BITMAPINFOHEADER bmpInfoHeader = {0};
// Set the size
bmpInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
// Bit count
bmpInfoHeader.biBitCount = wBitsPerPixel;
// Use all colors
bmpInfoHeader.biClrImportant = 0;
// Use as many colors according to bits per pixel
bmpInfoHeader.biClrUsed = 0;
// Store as un Compressed
bmpInfoHeader.biCompression = BI_RGB;
// Set the height in pixels
bmpInfoHeader.biHeight = lHeight;
// Width of the Image in pixels
bmpInfoHeader.biWidth = lWidth;
// Default number of planes
bmpInfoHeader.biPlanes = 1;
// Calculate the image size in bytes
bmpInfoHeader.biSizeImage = lWidth* lHeight * (wBitsPerPixel/8);
BITMAPFILEHEADER bfh = {0};
// This value should be values of BM letters i.e 0x4D42
// 0x4D = M 0×42 = B storing in reverse order to match with endian
bfh.bfType = 'B'+('M' << 8);
// <<8 used to shift ‘M’ to end
// Offset to the RGBQUAD
bfh.bfOffBits = sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER) + sizeof(RGBQUAD) * 256;
// Total size of image including size of headers
bfh.bfSize = bfh.bfOffBits + bmpInfoHeader.biSizeImage;
// Create the file in disk to write
HANDLE hFile = CreateFile( lpszFileName,GENERIC_WRITE, 0,NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,NULL);
if( !hFile ) // return if error opening file
{
return;
}
DWORD dwWritten = 0;
// Write the File header
WriteFile( hFile, &bfh, sizeof(bfh), &dwWritten , NULL );
// Write the bitmap info header
WriteFile( hFile, &bmpInfoHeader, sizeof(bmpInfoHeader), &dwWritten, NULL );
// Write the palette
WriteFile( hFile, &palette[0], sizeof(RGBQUAD) * 256, &dwWritten, NULL );
// Write the RGB Data
if(lWidth%4 == 0)
{
WriteFile( hFile, pBitmapBits, bmpInfoHeader.biSizeImage, &dwWritten, NULL );
}
else
{
char* empty = new char[ 4 - lWidth % 4];
for(int i = 0; i < lHeight; ++i)
{
WriteFile( hFile, &pBitmapBits[i * lWidth], lWidth, &dwWritten, NULL );
WriteFile( hFile, empty, 4 - lWidth % 4, &dwWritten, NULL );
}
}
// Close the file handle
CloseHandle( hFile );
}
void SaveBitmapToFileColor( BYTE* pBitmapBits, LONG lWidth, LONG lHeight,WORD wBitsPerPixel, LPCTSTR lpszFileName )
{
BITMAPINFOHEADER bmpInfoHeader = {0};
// Set the size
bmpInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
// Bit count
bmpInfoHeader.biBitCount = wBitsPerPixel;
// Use all colors
bmpInfoHeader.biClrImportant = 0;
// Use as many colors according to bits per pixel
bmpInfoHeader.biClrUsed = 0;
// Store as un Compressed
bmpInfoHeader.biCompression = BI_RGB;
// Set the height in pixels
bmpInfoHeader.biHeight = lHeight;
// Width of the Image in pixels
bmpInfoHeader.biWidth = lWidth;
// Default number of planes
bmpInfoHeader.biPlanes = 1;
// Calculate the image size in bytes
bmpInfoHeader.biSizeImage = lWidth* lHeight * (wBitsPerPixel/8);
BITMAPFILEHEADER bfh = {0};
// This value should be values of BM letters i.e 0x4D42
// 0x4D = M 0×42 = B storing in reverse order to match with endian
bfh.bfType = 'B'+('M' << 8);
// <<8 used to shift ‘M’ to end
// Offset to the RGBQUAD
bfh.bfOffBits = sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER);
// Total size of image including size of headers
bfh.bfSize = bfh.bfOffBits + bmpInfoHeader.biSizeImage;
// Create the file in disk to write
HANDLE hFile = CreateFile( lpszFileName,GENERIC_WRITE, 0,NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,NULL);
if( !hFile ) // return if error opening file
{
return;
}
DWORD dwWritten = 0;
// Write the File header
WriteFile( hFile, &bfh, sizeof(bfh), &dwWritten , NULL );
// Write the bitmap info header
WriteFile( hFile, &bmpInfoHeader, sizeof(bmpInfoHeader), &dwWritten, NULL );
// Write the palette
//WriteFile( hFile, &palette[0], sizeof(RGBQUAD) * 256, &dwWritten, NULL );
// Write the RGB Data
if(lWidth%4 == 0)
{
WriteFile( hFile, pBitmapBits, bmpInfoHeader.biSizeImage, &dwWritten, NULL );
}
else
{
char* empty = new char[ 4 - lWidth % 4];
for(int i = 0; i < lHeight; ++i)
{
WriteFile( hFile, &pBitmapBits[i * lWidth], lWidth, &dwWritten, NULL );
WriteFile( hFile, empty, 4 - lWidth % 4, &dwWritten, NULL );
}
}
// Close the file handle
CloseHandle( hFile );
}

Given your writeHeader is properly implemented this is almost correct. You need to fix 2 issues though:
You are writing one int per color channel. This should be one byte instead. You need to cast the literals to unsigned char.
Scanlines in bitmaps need to be DWORD-aligned. After your inner loop over col you need to write additional bytes to account for this, unless the size in bytes of the row is a multiple of four.

You need to force the output to be written in binary format, not text, this is chosen when you open your file/create your stream and to output all the values as bytes, not integers, this can be done in a number of ways possibly the easiest being write chr(0) or chr(255) - you also need to start your file with a header section - there are a number of formats that make this too long to go into in an answer here - some of them are down to preference as much as anything. There is a good summary in Wikipedia.
Basically you have to inform the receiving applications which format you are using, the number of rows, columns and how the colours are stored.

Related

Convert wmf file to emf file with SetWinMetaFileBits api in c++

I am trying to convert a wmf file to emf file. From what I've learned on Internet, the best solution looks like this.
BYTE* buffer;
HDC hdc = CreateMetaFileA(filename);
HMETAFILE hmf = CloseMetaFile(hdc);
UINT metasize = GetMetaFileBitsEx(hmf, 0, NULL);
buffer = (BYTE*)malloc(metasize);
HENHMETAFILE hEMF = SetWinMetaFileBits(metasize, buffer, NULL, NULL);
The idea here is to use CreateMetaFileA and CloseMetaFile to get HMETAFILE hmf.
Then I tried my code and the weird thing came. The handle hmf always points ??? in memory and the metasize is always 24 with different pictures. And hEMF is always None.
This is really sad because I spend my whole night on figuring out how to make the code work.
I do read a lot of materials including
http://math2.org/luasearch-2/luadist-extract/cdlua-5.2.dist/src/win32/wmf_emf.c
https://www-user.tu-chemnitz.de/~heha/viewzip.cgi/hs/wmfsave.zip/src/wmfsave.cpp?auto=CPP
Can anyone help me here? Thanks.
You need to initialize the METAFILEPICT structure.
Minimal example:
if (hmf) {
DWORD nSize = GetMetaFileBitsEx( hmf, 0, NULL );
if (nSize) {
BYTE *lpvData = new BYTE[nSize];
if (lpvData) {
DWORD dw = GetMetaFileBitsEx( hmf, nSize, lpvData );
if (dw) {
// Fill out a METAFILEPICT structure
mp.mm = MM_ANISOTROPIC;
mp.xExt = 1000;
mp.yExt = 1000;
mp.hMF = NULL;
// Get a reference DC
hDC = GetDC( NULL );
// Make an enhanced metafile from the windows metafile
hemf = SetWinMetaFileBits( nSize, lpvData, hDC, &mp );
// Clean up
ReleaseDC( NULL, hDC );
}
delete[] lpvData;
}
DeleteMetaFile( hmf );
}
My test code:
hdcMeta = CreateMetaFile(NULL);
hBrush = CreateSolidBrush(RGB(0, 0, 255));
Rectangle(hdcMeta, 0, 0, 100, 100);
MoveToEx(hdcMeta, 0, 0, NULL);
LineTo(hdcMeta, 100, 100);
MoveToEx(hdcMeta, 0, 100, NULL);
LineTo(hdcMeta, 100, 0);
SelectObject(hdcMeta, hBrush);
Ellipse(hdcMeta, 20, 20, 80, 80);
hmf = CloseMetaFile(hdcMeta);
UINT nSize = GetMetaFileBitsEx(hmf, 0, NULL);
Debug:
You can see nSize = 114
I suspect that you use CreateMetaFileA and CloseMetaFile to directly load the file name and return a handle to a Windows-format metafile is a wrong way.
Updated:
You can get the handle of WMF file in another way.
#include <windows.h>
#include <iostream>
#include <vector>
#pragma pack(1)
typedef struct tagWIN16RECT
{
WORD left;
WORD top;
WORD right;
WORD bottom;
} WIN16RECT;
typedef struct tagPLACEABLEMETAHEADER
{
DWORD key;
WORD hmf;
WIN16RECT bbox;
WORD inch;
DWORD reserved;
WORD checksum;
} PLACEABLEMETAHEADER;
#pragma pack()
HENHMETAFILE WINAPI ConvertWMFToEWMF(IN LPCWSTR lpszMetaFile)
{
HANDLE hFile = ::CreateFileW(
lpszMetaFile,
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == NULL || hFile == INVALID_HANDLE_VALUE)
return NULL;
DWORD dwSize = ::GetFileSize(hFile, NULL);
std::vector<BYTE> data(dwSize);
DWORD dwRead;
BOOL bSuccess = ::ReadFile(hFile, &data[0], dwSize, &dwRead, NULL);
::CloseHandle(hFile);
HENHMETAFILE hEnhMetaFile = NULL;
if (bSuccess)
{
PLACEABLEMETAHEADER * hdr = (PLACEABLEMETAHEADER*)&data[0];
int iPlaceableHeaderSize = sizeof(PLACEABLEMETAHEADER);
int iOffset = 0;
if (hdr->key != 0x9AC6CDD7) //not placeable header
{
iOffset = 0; //offset remains zero
}
else
{
iOffset = iPlaceableHeaderSize; //file is offset with placeable windows metafile header
}
hEnhMetaFile = ::SetWinMetaFileBits(data.size(), &data[iOffset], NULL, NULL);
if (NULL == hEnhMetaFile)
{
DWORD dwError = GetLastError();
std::cout << "Failed with error code: " << dwError;
}
else
{
std::cout << "Success! Metafile opened and returned as enhanced metafile";
}
}
return hEnhMetaFile;
}
int main()
{
HENHMETAFILE hEMF = ConvertWMFToEWMF(L"C:\\Users\\strives\\Desktop\\AN00010.WMF");
HENHMETAFILE newHEMF = CopyEnhMetaFile(hEMF, L"new EMF.emf");
return 0;
}
This worked for me
CStatic * m_pictCtrl = (CStatic *)this->GetDlgItem(PICT_STATIC);
LPCSTR file = filePath;
ALDUSMFHEADER aldusmfHeader;
DWORD wBytesRead;
double xOri, xExt, yOri, yExt;
HANDLE fh = CreateFileA(file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
ReadFile(fh, (void *)&aldusmfHeader, ALDUSMFHEADERSIZE, &wBytesRead, NULL);
xOri = aldusmfHeader.bbox.left;
xExt = aldusmfHeader.bbox.right - xOri;
if (aldusmfHeader.bbox.bottom < aldusmfHeader.bbox.top) {
yOri = aldusmfHeader.bbox.bottom;
yExt = aldusmfHeader.bbox.top - aldusmfHeader.bbox.bottom;
}
else {
yOri = aldusmfHeader.bbox.top;
yExt = aldusmfHeader.bbox.top - aldusmfHeader.bbox.bottom;
}
if (wBytesRead == -1 || wBytesRead < ALDUSMFHEADERSIZE)
{
AfxMessageBox(L" is not a placeable Windows metafile : it cannot be converted into EMF format.");
CloseHandle(fh);
return 0;
}
// Envelope in /100 cm
double Density = static_cast<double>(aldusmfHeader.inch);
double Top = static_cast<double>(aldusmfHeader.bbox.top) / Density;
double RawBottom = static_cast<double>(aldusmfHeader.bbox.bottom) / Density;
double Left = static_cast<double>(aldusmfHeader.bbox.left) / Density;
double RawRight = static_cast<double>(aldusmfHeader.bbox.right) / Density;
// In order to correctly import the EMF metafile into WORD, add one delta
double Bottom, Right, Delta, Rate = 0.1;
if (RawBottom > RawRight)
{
Delta = Rate * RawRight;
Right = RawRight + Delta;
Bottom = Right * RawBottom / RawRight;
}
else
{
Delta = Rate * RawBottom;
Bottom = RawBottom + Delta;
Right = Bottom * RawRight / RawBottom;
}
// Metafile header
SetFilePointer(fh, ALDUSMFHEADERSIZE, NULL, FILE_BEGIN);
METAHEADER mfHeader;
ReadFile(fh, (void *)&mfHeader, sizeof(METAHEADER), &wBytesRead, NULL);
// Allocate memory in order to save into memory bits after the Aldus header in the WMF metafile
// * 2 : 16 bits API
DWORD dwSize = mfHeader.mtSize * 2 * sizeof(BYTE);
BYTE *lpMFBits = (BYTE *)malloc(dwSize);
if (lpMFBits == nullptr)
{
AfxMessageBox(L"nullptr lpmfbits");
//cout << "Not enough memory to convert " << WMFFileName << " into EMF format." << endl;
CloseHandle(fh);
return 0;
}
// Bits after the Aldus header
SetFilePointer(fh, ALDUSMFHEADERSIZE, NULL, FILE_BEGIN);
ReadFile(fh, (void *)lpMFBits, dwSize, &wBytesRead, NULL);
if (wBytesRead == -1)
{
//cout << "Error while reading " << WMFFileName << " : impossible to convert it into EMF format." << endl;
free(lpMFBits);
CloseHandle(fh);
return 0;
}
// Save these bits into a memory enhanced metafile
// The memory enhanced metafile only contains 32 bits API functions : TextOut has been converted into ExtTextOutW,
// CreateFontIndirect has been converted into ExtCreateFontIndirectW, ...
METAFILEPICT MetaFilePict;
MetaFilePict.hMF = NULL;
MetaFilePict.mm = MM_ANISOTROPIC;
double Fact = 10.0 * Density;
MetaFilePict.xExt = static_cast<LONG>(Fact * (Right - Left));
MetaFilePict.yExt = static_cast<LONG>(Fact * (Bottom - Top));
HENHMETAFILE hMemoryEnhMetafile = SetWinMetaFileBits(dwSize, lpMFBits, NULL, &MetaFilePict);
free(lpMFBits);
CloseHandle(fh);
if (m_pictCtrl->GetEnhMetaFile() == NULL)
m_pictCtrl->SetEnhMetaFile(hMemoryEnhMetafile);

I need to create monocrome .bmp signature file by using C++ code but not able to create

I need to create monocrome .bmp signature file by using C++ code but not able to create. below is the code snippet.
bool SaveBMP ( BYTE* Buffer, int width, int height, long paddedsize, LPCTSTR bmpfile )
{
// declare bmp structures
BITMAPFILEHEADER bmfh;
BITMAPINFOHEADER info;
// andinitialize them to zero
memset ( &bmfh, 0, sizeof (BITMAPFILEHEADER ) );
memset ( &info, 0, sizeof (BITMAPINFOHEADER ) );
// fill the fileheader with data
bmfh.bfType = 0x4d42; // 0x4d42 = 'BM'
bmfh.bfReserved1 = 0;
bmfh.bfReserved2 = 0;
bmfh.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + paddedsize;
bmfh.bfOffBits = 0x36; // number of bytes to start of bitmap bits
// fill the infoheader
info.biSize = sizeof(BITMAPINFOHEADER);
info.biWidth = width;
info.biHeight = height;
info.biPlanes = 1; // we only have one bitplane
info.biBitCount = 1; // RGB mode is 24 bits
info.biCompression = BI_RGB;
info.biSizeImage = 0; // can be 0 for 24 bit images
info.biXPelsPerMeter = 0x0ec4; // paint and PSP use this values
info.biYPelsPerMeter = 0x0ec4;
info.biClrUsed = 0; // we are in RGB mode and have no palette
info.biClrImportant = 0; // all colors are important
// now we open the file to write to
HANDLE file = CreateFile ( bmpfile , GENERIC_WRITE, FILE_SHARE_READ,
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
if ( file == NULL )
{
CloseHandle ( file );
return false;
}
// write file header
unsigned long bwritten;
if ( WriteFile ( file, &bmfh, sizeof ( BITMAPFILEHEADER ), &bwritten, NULL ) == false )
{
CloseHandle ( file );
return false;
}
// write infoheader
if ( WriteFile ( file, &info, sizeof ( BITMAPINFOHEADER ), &bwritten, NULL ) == false )
{
CloseHandle ( file );
return false;
}
// write image data
if ( WriteFile ( file, Buffer, paddedsize, &bwritten, NULL ) == false )
{
CloseHandle ( file );
return false;
}
// and close file
CloseHandle ( file );
return true;
}
**//when I run this code the created bitmap file is blank, signature is not being shown, only the background of signature file is able to show. **
Monochrom bitmap requires a palette. In this case the palette size is 8 bytes (2 RGBQUAD values)
This extra 8 bytes should be added to BITMAPFILEHEADER file size.
After BITMAPFILEHEADER, you are working with BITMAPINFOHEADER which does not contain information about palettes. You have to use BITMAPINFO directly instead of BITMAPINFOHEADER
BITMAPINFO* bmpinfo = (BITMAPINFO*)malloc(palette_size + sizeof(BITMAPINFOHEADER));
bmpinfo->bmiHeader = { sizeof(BITMAPINFOHEADER),
width, height, 1, bitcount, BI_RGB, 0, 0, 0, 0, 0 };
If Buffer was not retrieved for a monochrome bitmap then you cannot simply change bitcount in this save function and expect everything to work.
if ( file == NULL )// <-error
{
CloseHandle ( file );
return false;
}
If CreateFile fails, the return value is INVALID_HANDLE_VALUE. You can find out these values from online documentation for API functions. The corrected version should be
if(file != INVALID_HANDLE_VALUE)
{
unsigned long bwritten;
WriteFile(file, &bmfh, sizeof(BITMAPFILEHEADER), &bwritten, NULL);
WriteFile(file, bmpinfo, 8 + sizeof(BITMAPINFOHEADER), &bwritten, NULL);
WriteFile(file, Buffer, paddedsize, &bwritten, NULL);
CloseHandle(file);
return true;
}
return false;

C++ bitmap to base64

I have the following code to create a bitmap:
//raw data
PBYTE firstPixel = (PBYTE)((PBYTE)AnsiBdbRecord) + sizeof(WINBIO_BDB_ANSI_381_RECORD);
// declare other bmp structures
BITMAPFILEHEADER bmfh;
BITMAPINFOHEADER info;
RGBQUAD rq[256];
// create the grayscale palette
for (int i = 0; i<256; i++)
{
rq[i].rgbBlue = i;
rq[i].rgbGreen = i;
rq[i].rgbRed = i;
rq[i].rgbReserved = 0;
}
//RGBQUAD bl = { 0,0,0,0 }; //black color
//RGBQUAD wh = { 0xff,0xff,0xff,0xff }; // white color
// andinitialize them to zero
memset(&bmfh, 0, sizeof(BITMAPFILEHEADER));
memset(&info, 0, sizeof(BITMAPINFOHEADER));
// fill the fileheader with data
bmfh.bfType = 0x4d42; // 0x4d42 = 'BM'
bmfh.bfReserved1 = 0;
bmfh.bfReserved2 = 0;
bmfh.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); // + padding;
bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD);
// fill the infoheader
info.biSize = sizeof(BITMAPINFOHEADER);
info.biWidth = Width;
info.biHeight = Height;
info.biPlanes = 1; // we only have one bitplane
info.biBitCount = PixelDepth; // RGB mode is 24 bits
info.biCompression = BI_RGB;
info.biSizeImage = 0; // can be 0 for 24 bit images
info.biXPelsPerMeter = 0x0ec4; // paint and PSP use this values
info.biYPelsPerMeter = 0x0ec4;
info.biClrUsed = 0; // we are in RGB mode and have no palette
info.biClrImportant = 0; // all colors are importantenter code here
And I save it as follows:
HANDLE file = CreateFile(bmpfile, GENERIC_WRITE, FILE_SHARE_READ,
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (file == NULL)
{
DWORD dw = GetLastError();
CloseHandle(file);
}
// write file header
if (WriteFile(file, &bmfh, sizeof(BITMAPFILEHEADER), &bwritten, NULL) == false)
{
DWORD dw = GetLastError();
CloseHandle(file);
}
// write infoheader
if (WriteFile(file, &info, sizeof(BITMAPINFOHEADER), &bwritten, NULL) == false)
{
DWORD dw = GetLastError();
CloseHandle(file);
}
//write rgbquad for black
if (WriteFile(file, &rq, sizeof(rq), &bwritten, NULL) == false)
{
DWORD dw = GetLastError();
CloseHandle(file);
}
// write image data
if (WriteFile(file, &firstPixel[0], imageSize, &bwritten, NULL) == false)
{
DWORD dw = GetLastError();
CloseHandle(file);
}
// and clean up
CloseHandle(file);
I think the above is the standard way of saving bitmap images. However, instead of saving the image, I want it to be available as BASE64 and pass it in a HTTP Post. Therefore, this question relates to this one, but I am having a lot of difficulties converting the bmp structure to BASE64. I have taken the BASE64 encoder from here, but I have no idea how to pass the BMPFILEHEADER, BMPINFOHEADER, RGBQUAD, and raw data structure as a parameter to the BASE64 encoder.
Any thoughts or pointers on how to combine the information I gathered?
UPDATE
Thanks to Roman Pustylnikov, I have gotten a bit farther already:
I'm creating a struct like this:
struct ImageBuffer
{
BITMAPFILEHEADER bfheader;
BITMAPINFOHEADER infobmp;
RGBQUAD rgb[256];
PBYTE bitmap;
};
Fill it as follows:
ImageBuffer capture;
capture.bfheader = bmfh;
capture.infobmp = info;
// create the grayscale palette
for (int i = 0; i<256; i++)
{
capture.rgb[i].rgbBlue = i;
capture.rgb[i].rgbGreen = i;
capture.rgb[i].rgbRed = i;
capture.rgb[i].rgbReserved = 0;
}
capture.bitmap = firstPixel;
And convert it as follows:
int totalSize = sizeof(capture.bfheader) + sizeof(capture.infobmp) + sizeof(capture.rgb) + imageSize;
std::string encodedImage = base64_encode(reinterpret_cast<const unsigned char*>(&capture), totalSize);
However, it gives me an invalid bitmap. Also, when I load the bitmap from disk (the one that is generated with writefile), I get a different base64 string. I use C# code to compare the two Base64 strings:
// generated base64 string
string test = "Put base64string generated from C++ here";
byte[] imageBytes = Convert.FromBase64String(test);
// generate the same string based on the actual bmp
byte[] data = File.ReadAllBytes(#"c:\successtest.bmp");
string original = Convert.ToBase64String(data);
UPDATE TWO: solution
The solution can be found in the latest update of Roman Pustylnikov's answer.
You can do it without file in the middle, using the following example as encoder/decoder:
The first approach is to create the contiguous memory and put it as an input:
int size=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*256 + imageSize ;
unsigned char * bmpBuff = new char[size];
int i = 0;
memcpy((void *)( &( bmpBuff[i] )), (void *) &bfheader,sizeof(BITMAPFILEHEADER) );
i+=sizeof(BITMAPFILEHEADER);
memcpy((void *)( &( bmpBuff[i] )), (void *) &infobmp,sizeof(BITMAPINFOHEADER) );
i+=sizeof(BITMAPINFOHEADER);
memcpy((void *)( &( bmpBuff[i] )), (void *) &rq,sizeof(RGBQUAD)*256 );
i+=sizeof(RGBQUAD)*256;
memcpy((void *)( &( bmpBuff[i] )), (void *) firstPixel, imageSize );
std::string encodedImage = base64_encode(bmpBuff, size);
The cons of this approach is that you need to duplicate the memory.
Another approach is to handle the "lost triplet". For this we'll need to define a structure:
struct ScreenShotBuffer
{
BITMAPFILEHEADER bfheader;
BITMAPINFO infobmp;
RGBQUAD rgb[256];
};
Now here comes the tricky part. Since the encoding handles the triples of bytes, you need to handle the border between two buffers (I haven't tested this so it might contain bugs, just a general approach).
int size=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*256;
unsigned char *info = einterpret_cast<const unsigned char*> &screenshotInfo;
unsigned char *img = einterpret_cast<const unsigned char*> firstPixel;
std::string encodedInfo = base64_encode(info , size);
std::string encodedLostTriplet = "";
int offset = size%3;
unsigned char lostTriplet[3];
if (offset) {
lostTriplet[0]=info[size-offset];
if (offset==2)
lostTriplet[1] = info[size-offset+1];
else
lostTriplet[1] = img[0];
lostTriplet[2] = img[2-offset];
encodedLostTriplet = base64_encode(lostTriplet, 3);
}
else {
offset=3;
}
std::string encodedData = base64_encode(reinterpret_cast<const unsigned char*> &img[3-offset], imageSize - (3 - offset) );
std::string encodedImage = encodedInfo + lostTriplet + encodedData;
A little bit messy but should work on the same memory.

How to save an image in Intel RealSense(Visual C++)

I'm working on Intel RealSense SDK (R2). I want to save the image from Camera_viewer. I have worked till saving the frame to specific buffers and retrieving from the same. I want to know how to save those frames/images to a specified location/folder.
Here's my code:
PXCImage *colorIm, *depthIm;
for (int i=0; i<MAX_FRAMES; i++) {
// This function blocks until all streams are ready (depth and color)
// if false streams will be unaligned
if (psm->AcquireFrame(true)<PXC_STATUS_NO_ERROR) break;
// retrieve all available image samples
PXCCapture::Sample *sample = psm->QuerySample();
// retrieve the image or frame by type from the sample
colorIm = sample->color;
depthIm = sample->depth;
// render the frame
if (!renderColor->RenderFrame(colorIm)) break;
if (!renderDepth->RenderFrame(depthIm)) break;
// release or unlock the current frame to fetch the next frame
psm->ReleaseFrame();
}
I'm able to retrieve the frames/images successfully, but I want to save those files for further use. So I want to know how to save those files in a folder.
Thanks in advance
Same question was asked here and the answer that was posted solved the initial question. However there was a follow-up question on how to save the images to specific folder.
If you have that specific question, then answer would be the same SetFileName() only. According to this link, pxcCHAR *file is the full path of the file to playback or to be recorded. . That being said, you can create a custom folder and point your path to that custom folder followed by a valid file name to save your image.
To save the data I would create a Bitmap from the image data as ThorngardSO said and use the code from http://www.runicsoft.com/bmp.cpp to save it -
#include <windows.h>
#include <stdio.h> // for memset
bool SaveBMP ( BYTE* Buffer, int width, int height, long paddedsize, LPCTSTR bmpfile )
{
// declare bmp structures
BITMAPFILEHEADER bmfh;
BITMAPINFOHEADER info;
// andinitialize them to zero
memset ( &bmfh, 0, sizeof (BITMAPFILEHEADER ) );
memset ( &info, 0, sizeof (BITMAPINFOHEADER ) );
// fill the fileheader with data
bmfh.bfType = 0x4d42; // 0x4d42 = 'BM'
bmfh.bfReserved1 = 0;
bmfh.bfReserved2 = 0;
bmfh.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + paddedsize;
bmfh.bfOffBits = 0x36; // number of bytes to start of bitmap bits
// fill the infoheader
info.biSize = sizeof(BITMAPINFOHEADER);
info.biWidth = width;
info.biHeight = height;
info.biPlanes = 1; // we only have one bitplane
info.biBitCount = 24; // RGB mode is 24 bits
info.biCompression = BI_RGB;
info.biSizeImage = 0; // can be 0 for 24 bit images
info.biXPelsPerMeter = 0x0ec4; // paint and PSP use this values
info.biYPelsPerMeter = 0x0ec4;
info.biClrUsed = 0; // we are in RGB mode and have no palette
info.biClrImportant = 0; // all colors are important
// now we open the file to write to
HANDLE file = CreateFile ( bmpfile , GENERIC_WRITE, FILE_SHARE_READ,
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
if ( file == NULL )
{
CloseHandle ( file );
return false;
}
// write file header
unsigned long bwritten;
if ( WriteFile ( file, &bmfh, sizeof ( BITMAPFILEHEADER ), &bwritten, NULL ) == false )
{
CloseHandle ( file );
return false;
}
// write infoheader
if ( WriteFile ( file, &info, sizeof ( BITMAPINFOHEADER ), &bwritten, NULL ) == false )
{
CloseHandle ( file );
return false;
}
// write image data
if ( WriteFile ( file, Buffer, paddedsize, &bwritten, NULL ) == false )
{
CloseHandle ( file );
return false;
}
// and close file
CloseHandle ( file );
return true;
}
This can then be subsequently loaded using more code from the same link -
/*******************************************************************
BYTE* LoadBMP ( int* width, int* height, long* size
LPCTSTR bmpfile )
The function loads a 24 bit bitmap from bmpfile,
stores it's width and height in the supplied variables
and the whole size of the data (padded) in <size>
and returns a buffer of the image data
On error the return value is NULL.
NOTE: make sure you [] delete the returned array at end of
program!!!
*******************************************************************/
BYTE* LoadBMP ( int* width, int* height, long* size, LPCTSTR bmpfile )
{
// declare bitmap structures
BITMAPFILEHEADER bmpheader;
BITMAPINFOHEADER bmpinfo;
// value to be used in ReadFile funcs
DWORD bytesread;
// open file to read from
HANDLE file = CreateFile ( bmpfile , GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL );
if ( NULL == file )
return NULL; // coudn't open file
// read file header
if ( ReadFile ( file, &bmpheader, sizeof ( BITMAPFILEHEADER ), &bytesread, NULL ) == false )
{
CloseHandle ( file );
return NULL;
}
//read bitmap info
if ( ReadFile ( file, &bmpinfo, sizeof ( BITMAPINFOHEADER ), &bytesread, NULL ) == false )
{
CloseHandle ( file );
return NULL;
}
// check if file is actually a bmp
if ( bmpheader.bfType != 'MB' )
{
CloseHandle ( file );
return NULL;
}
// get image measurements
*width = bmpinfo.biWidth;
*height = abs ( bmpinfo.biHeight );
// check if bmp is uncompressed
if ( bmpinfo.biCompression != BI_RGB )
{
CloseHandle ( file );
return NULL;
}
// check if we have 24 bit bmp
if ( bmpinfo.biBitCount != 24 )
{
CloseHandle ( file );
return NULL;
}
// create buffer to hold the data
*size = bmpheader.bfSize - bmpheader.bfOffBits;
BYTE* Buffer = new BYTE[ *size ];
// move file pointer to start of bitmap data
SetFilePointer ( file, bmpheader.bfOffBits, NULL, FILE_BEGIN );
// read bmp data
if ( ReadFile ( file, Buffer, *size, &bytesread, NULL ) == false )
{
delete [] Buffer;
CloseHandle ( file );
return NULL;
}
// everything successful here: close file and return buffer
CloseHandle ( file );
return Buffer;
}
You can then load those bitmap files at a later date using the code from Intel https://software.intel.com/sites/landingpage/realsense/camera-sdk/v1.1/documentation/html/manuals_image_and_audio_data.html -
// Image info
PXCImage::ImageInfo info={};
info.format=PXCImage::PIXEL_FORMAT_RGB32;
info.width=image_width;
info.height=image_height;
// Create the image instance
PXCImage image=session->CreateImage(&info);
// Write data
PXCImage::ImageData data;
image->AcquireAccess(PXCImage::ACCESS_WRITE,&data);
... // copy the imported image to data.planes[0]
image->ReleaseAccess(&data);
Using these three sets of code you should easily be able to save Bitmaps in any specified folder using WriteFile then, once loaded you can convert the bitmap back into ImageData.
Let me know how it goes.

Change pixel to Symbols/Chars

I want to try and make, in C++, a Program that takes an Image and scans pixel by pixel, for relatively Dark pixels it prints a space and for Light Pixels it prints symbols like:
"##$%^!M()-~, etc" that will paint new picture with only symbols.
I am new and I really would appreciate some guidance for how it is I can approach that,
I would like to Surprise my teacher.
Thank you very much in advance.
ok that what i already had:
#include <windows.h>
#include <stdio.h>
BYTE* ConvertBMPToRGBBuffer(BYTE* Buffer, int width, int height)
{
// first make sure the parameters are valid
if ((NULL == Buffer) || (width == 0) || (height == 0))
return NULL;
// find the number of padding bytes
int padding = 0;
int scanlinebytes = width * 3;
while ((scanlinebytes + padding) % 4 != 0) // DWORD = 4 bytes
padding++;
// get the padded scanline width
int psw = scanlinebytes + padding;
// create new buffer
BYTE* newbuf = new BYTE[width*height * 3];
// now we loop trough all bytes of the original buffer,
// swap the R and B bytes and the scanlines
long bufpos = 0;
long newpos = 0;
for (int y = 0; y < height; y++)
for (int x = 0; x < 3 * width; x += 3)
{
newpos = y * 3 * width + x;
bufpos = (height - y - 1) * psw + x;
newbuf[newpos] = Buffer[bufpos + 2];
newbuf[newpos + 1] = Buffer[bufpos + 1];
newbuf[newpos + 2] = Buffer[bufpos];
}
return newbuf;
}
BYTE* LoadBMP(int* width, int* height, long* size, LPCTSTR bmpfile)
{
// declare bitmap structures
BITMAPFILEHEADER bmpheader;
BITMAPINFOHEADER bmpinfo;
// value to be used in ReadFile funcs
DWORD bytesread;
// open file to read from
HANDLE file = CreateFile(bmpfile, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (NULL == file)
return NULL; // coudn't open file
// read file header
if (ReadFile(file, &bmpheader, sizeof (BITMAPFILEHEADER), &bytesread, NULL) == false)
{
CloseHandle(file);
return NULL;
}
//read bitmap info
if (ReadFile(file, &bmpinfo, sizeof (BITMAPINFOHEADER), &bytesread, NULL) == false)
{
CloseHandle(file);
return NULL;
}
// check if file is actually a bmp
if (bmpheader.bfType != 'MB')
{
CloseHandle(file);
return NULL;
}
// get image measurements
*width = bmpinfo.biWidth;
*height = abs(bmpinfo.biHeight);
// check if bmp is uncompressed
if (bmpinfo.biCompression != BI_RGB)
{
CloseHandle(file);
return NULL;
}
// check if we have 24 bit bmp
if (bmpinfo.biBitCount != 24)
{
CloseHandle(file);
return NULL;
}
// create buffer to hold the data
*size = bmpheader.bfSize - bmpheader.bfOffBits;
BYTE* Buffer = new BYTE[*size];
// move file pointer to start of bitmap data
SetFilePointer(file, bmpheader.bfOffBits, NULL, FILE_BEGIN);
// read bmp data
if (ReadFile(file, Buffer, *size, &bytesread, NULL) == false)
{
delete[] Buffer;
CloseHandle(file);
return NULL;
}
// everything successful here: close file and return buffer
CloseHandle(file);
return Buffer;
}
void main()
{
int x, y;
long s, s2;
BYTE* a = LoadBMP(&x, &y, &s, L"20140626_143101.bmp);
BYTE* b = ConvertBMPToRGBBuffer(a, x, y);
// what now??
delete[] a;
delete[] b;
}
after i convert the BMP to RGB Buffer what i can do next?? to check about the buffer if it dark or light pixels
I would like to set you on the correct path, that is, without giving you the entire answer. I have found some references which will take you to what it is you would like to learn.
Firstly, one must decode the image. That is copy the image into a variable in another, readable, format. Writing one of these, especially when knew to C++, is not a good idea. But there are many libraries which do this very thing. I recommend:
http://cimg.sourceforge.net/ and then as brief tutorial: http://www.math.ucla.edu/~wittman/hyper/vick/Cimg_tutorial.pdf and Proceeding That to Edit a Single Pixel: http://cimg.sourceforge.net/reference/group__cimg__loops.html (Look at the: Loops over interior regions and borders section)
This hopefully will point you in the right direction.
P.S. Feel free to ask if you have any more questions.