Bitmap to base64 and writefile

I have the following code which does 2 things:

• Return a scanned fingerprint as base64
• Store this print as bitmap

While the code works most of the time, sometimes an invalid bitmap is saved (I can't open the file). I think there are some improvements (padding?) that can counter this strange behavior. The 'firstPixel' is a reference that is given by the Windows Biometric Framework, as well as the Width and the Height.

PBYTE firstPixel = (PBYTE)((PBYTE)AnsiBdbRecord) + sizeof(WINBIO_BDB_ANSI_381_RECORD);

// declare bmp structures
//https://msdn.microsoft.com/en-us/library/windows/desktop/dd183391%28v=vs.85%29.aspx
//Declare pbitmapinfo and initialize
//PBITMAPINFO info;
for (int rgbitem = 0; rgbitem<256; rgbitem++)
{
rq[rgbitem].rgbBlue = BYTE(rgbitem);
rq[rgbitem].rgbGreen = BYTE(rgbitem);
rq[rgbitem].rgbRed = BYTE(rgbitem);
rq[rgbitem].rgbReserved = BYTE(0);
}
// and initialize them to zero

//calculate scanline
int scanlinebytes = Width;
while ((scanlinebytes + padding) % 4 != 0)
//calculate new width, which will be used further instead of original Width
//calculate new imageSize
int imageSize = paddedWidth * Height;
//a new buffer is created to copy over the pixels from the firstPixel array
//this is required for padding (to make it easier, we also copy over the original array in case no padding is required)
//set all pixels to zero, so we do not have to add padding manually
long oldpos = 0;
long newpos = 0;
for (int y = 0; y < Height; y++)
{
for (int x = 0; x < Width; x++)
{
oldpos = y * Width + x;     // position in original buffer
newpos = y * paddedWidth + x;   // position in padded buffer
}
}

bmih.biHeight = Height;
bmih.biPlanes = 1; // we only have one bitplane
bmih.biBitCount = PixelDepth;
bmih.biCompression = BI_RGB;
bmih.biSizeImage = 0;
bmih.biXPelsPerMeter = 0x0ec4; // paint and PSP use this values
bmih.biYPelsPerMeter = 0x0ec4;
bmih.biClrUsed = 0; // we are in RGB mode and have no palette
bmih.biClrImportant = 0; // all colors are important

// fill the fileheader with data
bmfh.bfType = 0x4d42; // 0x4d42 = 'BM'
bmfh.bfReserved1 = 0;
bmfh.bfReserved2 = 0;

//declare and initialize bitmapinfoheader based on bitmapinfo

//Put everything in a temporary buffer, and convert buffer to base64
unsigned char * bmpBuff = new unsigned char[totalSize];
int j = 0;
memcpy((void *)(&(bmpBuff[j])), (void *)&rq, sizeof(RGBQUAD) * 256);
std::string encodedFile = base64_encode(bmpBuff, totalSize);

delete bmpBuff;

//Write file.
unsigned long bwritten;
// 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)
{
DWORD dw = GetLastError();
CloseHandle(file);
}

if (WriteFile(file, &bmfh, sizeof(BITMAPFILEHEADER), &bwritten, NULL) == false)
{
DWORD dw = GetLastError();
CloseHandle(file);
}
if (WriteFile(file, &bmih, sizeof(BITMAPINFOHEADER), &bwritten, NULL) == false)
{
DWORD dw = GetLastError();
CloseHandle(file);
}
if (WriteFile(file, &rq, + sizeof(RGBQUAD) * 256, &bwritten, NULL) == false)
{
DWORD dw = GetLastError();
CloseHandle(file);
}
// write image data
if (WriteFile(file, &paddedPixel[0], imageSize, &bwritten, NULL) == false)
{
DWORD dw = GetLastError();
CloseHandle(file);
}

// and clean up
CloseHandle(file);
return encodedFile;
}

• Consider not only posting the functions body, but the whole function. – Deduplicator Oct 26 '15 at 18:52
• BMP files have their pixel rows padded to 4 bytes. Your function doesn't do that. You should read this: Wikipedia BMP file format. – JS1 Oct 27 '15 at 1:16
• This code has comments indicating that a 24bpp bitmap is being set up, but the code actually sets up an 8bpp bitmap with a grayscale palette. I found this confusing, especially considering the definition of PixelDepth was never given. – Christopher Oicles Oct 27 '15 at 1:38
• @JS1, thanks. Added padding (see question update), and it never fails now. – Michael Oct 27 '15 at 8:27
• @ChristopherOicles, PixelDepth always needs to be 8, otherwise I will never enter this function. You are correct that the comments indicate differently. – Michael Oct 27 '15 at 8:28