Click here to Skip to main content
15,887,175 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
Hello guys,

I wonder how to convert binary files to an image (png) file. I have a folder with about 3700 binary files (ex. 0, 1, 2, 3, [..] 3721, 3749, 3752 etc).

But do you know how to convert the complete content of the folder to png files?

I may use QT if it's more stable / efficient.

Thank you in advance!
Posted
Comments
Kornfeld Eliyahu Peter 7-Dec-14 9:19am    
Are you sure those binaries are images? How they can be converted into an image?
IceTrailer 7-Dec-14 9:23am    
I'm definitely sure.
An older Version of some of these binaries have been released some time ago.
Kornfeld Eliyahu Peter 7-Dec-14 9:26am    
Good! Now there are some ways to represent an image in binary - to be able to make an image from the binary you have to know how the images were converted...
IceTrailer 7-Dec-14 9:28am    
Is there a way to find out?

This is what my hex-editor says

http://pastebin.com/raw.php?i=ZJYkPVME (final png)
http://pastebin.com/raw.php?i=KZFcUFBK (binary)
Kornfeld Eliyahu Peter 7-Dec-14 9:38am    
This kind of display can not help - you have to see the numbers behind...

It's actually pretty easy, if one is vaguely familiar with image-based programming tasks.
I left a description of the file format in a comment above, though this can be seen from the code below.

I first tried to create the new image and then use GDI+ to save it as a PNG complete with 16 level transparency. Unfortunately, GDI+ saved the colour values as desired, but set all of the alpha bits of the image to 255 - or opaque. :(

Next I remembered some code that will save to a 32 bit BMP file. I tried this on the output from a function that loads the binary file into a HBITMAP and found that the image was saved as expected. Opening it with the Windows Photo Viewer makes it appear as though it's failed, however if I open it with GIMP, it's immediately apparent that the process has functioned as desired. Windows Photo Viewer shows the transparent, black area as being black and opaque.


Given that you have a desire to save them as PNG files, what I'd do would be to setup a small chunk of code that converted all of the binary files to BMP files. I'd then run Irfanview on the folder, converting all of the BMP files to 32bit PNGs.

The conversion should take no time - it may well take longer to download, start and setup Irfanview for the batch conversion.

Anyway, heres the code - you can chuck out all of the GDI+ stuff. I've just left it there as a demo of saving an HBITMAP to a png - also to demonstrate the fact that library code isn't always better than something home-rolled.

It's a console program, linked against the gdi32 and gdiplus libraries.

Without further ado -

C++
#include <cstdio>
#include <cstdlib>
#include <windows.h>
#include <gdiplus.h>

using namespace Gdiplus;

#pragma pack(push,1)                //// done to prevent gcc from padding the struct - IMPORTANT!
typedef struct
{
    unsigned char unknown1;
    unsigned short width;
    unsigned short height;
    unsigned short unknown2;
    unsigned short unknown3;
    unsigned long dataOffset;
} fileHeader, *pFileHeader;
#pragma pack(pop)


HBITMAP mCreateDibSection(HDC hdc, int width, int height, int bitCount)
{
    BITMAPINFO bi;
    ZeroMemory(&bi, sizeof(bi));
    bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
    bi.bmiHeader.biWidth = width;
    bi.bmiHeader.biHeight = height;
    bi.bmiHeader.biPlanes = 1;
    bi.bmiHeader.biBitCount = bitCount;
    bi.bmiHeader.biCompression = BI_RGB;
    return CreateDIBSection(hdc, &bi, DIB_RGB_COLORS, 0,0,0);
}

void showFileInfo(char *binFilename)
{
    fileHeader mHeader;
    FILE *fp;
    fp = fopen(binFilename, "rb");
    fread(&mHeader, sizeof(fileHeader), 1, fp);
    fclose(fp);
    printf("Width: %d\n", mHeader.width);
    printf("Height: %d\n", mHeader.height);
    printf("pixelData offset: %ld\n", mHeader.dataOffset);
}

void mPixel(int xPos, int yPos, char r, char g, char b, char a, BITMAP img)
{
    char *pixelPtr = (char*)img.bmBits + (yPos * img.bmWidthBytes) + (xPos * (img.bmBitsPixel / 8) );
    *pixelPtr++ = b;
    *pixelPtr++ = g;
    *pixelPtr++ = r;
    *pixelPtr++ = a;
}

HBITMAP loadBinaryImg(char *filename)
{
    fileHeader mHeader;
    FILE *fp;

    fp = fopen(filename, "rb");
    fread(&mHeader, sizeof(fileHeader), 1, fp);

    unsigned short *pixelData;
    pixelData = (unsigned short*) calloc( sizeof(short), mHeader.width * mHeader.width );
    fseek(fp, mHeader.dataOffset, SEEK_SET);
    fread(pixelData, sizeof(short), mHeader.width*mHeader.height, fp);
    fclose(fp);

    HDC hdc = GetDC(HWND_DESKTOP);
    //
    // The image is stored top-down, windows bmps are stored bottom-up. Using -height
    // flips the bitmap vertically,  making it the right way up
    HBITMAP mResult = mCreateDibSection(hdc, mHeader.width, -mHeader.height, 32);
    ReleaseDC(HWND_DESKTOP, hdc);

    BITMAP bm;
    GetObject(mResult, sizeof(bm), &bm);

    int xPos, yPos;
    for (yPos=0; yPos<mHeader.height; yPos++)
    {
        for (xPos=0; xPos<mHeader.width; xPos++)
        {
            unsigned short curPixel;
            curPixel = pixelData[xPos + yPos*mHeader.width];
            unsigned char r, g, b, a;

            b = curPixel & 0xF;
            g = (curPixel >> 4) & 0xF;
            r = (curPixel >> 8) & 0xF;
            a = (curPixel >> 12) & 0xF;

            // there's 1 nibble (4bits) per channel inthe input, but we need to make
            // use of 8 bits in the output. The 16 input levels must be transformed
            // to occur over a range of 256, rather than 16. (256 / 16 = 16, hence the multiplier of 16)

            // EDIT UPDATE: The above information is not quite correct. The multiplier
            // should actually be 17, since the 16 values range from 0-15, and the
            // output must range from 0-255. 255/15 = 17. Also, if 16 is used instead
            // of 17, the areas that should be opaque are still partially transparent.
            a *= 17; //16;
            r *= 17; //16;
            g *= 17; //16;
            b *= 17; //16;

            mPixel(xPos, yPos, r,g,b,a, bm);
        }
    }
    return mResult;
}


int GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
    UINT  num = 0;          // number of image encoders
    UINT  size = 0;         // size of the image encoder array in bytes

    ImageCodecInfo* pImageCodecInfo = NULL;

    GetImageEncodersSize(&num, &size);
    if(size == 0)
        return -1;  // Failure

    pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
    if(pImageCodecInfo == NULL)
        return -1;  // Failure

    GetImageEncoders(num, size, pImageCodecInfo);

    for(UINT j = 0; j < num; ++j)
    {
        if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 )
        {
            *pClsid = pImageCodecInfo[j].Clsid;
            free(pImageCodecInfo);
            return j;  // Success
        }
    }

    free(pImageCodecInfo);
    return -1;  // Failure
}

void saveHbitmapAsPng(HBITMAP img, wchar_t *outputFilename)
{
    Bitmap *bitmap = Bitmap::FromHBITMAP(img, NULL);
    CLSID encoderClsid;
    GetEncoderClsid(L"image/png", &encoderClsid);
    bitmap->Save(outputFilename, &encoderClsid, NULL);
    delete bitmap;
}

void saveHbitmapAsBmp(HBITMAP img, char *outputFilename)
{
    HDC hdcScreen = GetDC(HWND_DESKTOP);
    BITMAP bm;

    char *lpbitmap;
    HANDLE hDIB;
    DWORD dwBmpSize, dwSizeofDIB, dwBytesWritten;
    HANDLE hFile;

    // Get the BITMAP from the HBITMAP
    GetObject(img,sizeof(bm),&bm);

    BITMAPFILEHEADER   bmfHeader;
    BITMAPINFOHEADER   bi;

    bi.biSize = sizeof(BITMAPINFOHEADER);
    bi.biWidth = bm.bmWidth;
    bi.biHeight = bm.bmHeight;
    bi.biPlanes = 1;
    bi.biBitCount = 32;
    bi.biCompression = BI_RGB;
    bi.biSizeImage = 0;
    bi.biXPelsPerMeter = 0;
    bi.biYPelsPerMeter = 0;
    bi.biClrUsed = 0;
    bi.biClrImportant = 0;

    dwBmpSize = ((bm.bmWidth * bi.biBitCount + 31) / 32) * 4 * bm.bmHeight;

    // Starting with 32-bit Windows, GlobalAlloc and LocalAlloc are implemented as wrapper functions that
    // call HeapAlloc using a handle to the process's default heap. Therefore, GlobalAlloc and LocalAlloc
    // have greater overhead than HeapAlloc.
    hDIB = GlobalAlloc(GHND,dwBmpSize);
    lpbitmap = (char *)GlobalLock(hDIB);

    // Gets the "bits" from the bitmap and copies them into a buffer
    // which is pointed to by lpbitmap.
    GetDIBits(hdcScreen, img, 0,
        (UINT)bm.bmHeight,
        lpbitmap,
        (BITMAPINFO *)&bi, DIB_RGB_COLORS);


    // A file is created, this is where we will save the screen capture.
    hFile = CreateFile(outputFilename,
        GENERIC_WRITE,
        0,
        NULL,
        CREATE_ALWAYS,
        FILE_ATTRIBUTE_NORMAL, NULL);

    // Add the size of the headers to the size of the bitmap to get the total file size
    dwSizeofDIB = dwBmpSize + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);

    //Offset to where the actual bitmap bits start.
    bmfHeader.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER);

    //Size of the file
    bmfHeader.bfSize = dwSizeofDIB;

    //bfType must always be BM for Bitmaps
    bmfHeader.bfType = 0x4D42; //BM

    WriteFile(hFile, (LPSTR)&bmfHeader, sizeof(BITMAPFILEHEADER), &dwBytesWritten, NULL);
    WriteFile(hFile, (LPSTR)&bi, sizeof(BITMAPINFOHEADER), &dwBytesWritten, NULL);
    WriteFile(hFile, (LPSTR)lpbitmap, dwBmpSize, &dwBytesWritten, NULL);

    //Unlock and Free the DIB from the heap
    GlobalUnlock(hDIB);
    GlobalFree(hDIB);

    //Close the handle for the file that was created
    CloseHandle(hFile);

    //Clean up
done:
//    DeleteObject(hbmScreen);
//    DeleteObject(hdcMemDC);
    ReleaseDC(NULL,hdcScreen);
//    ReleaseDC(hWnd,hdcWindow);

//    return 0;
}



int main()
{
    // Initialize GDI+
    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);


    HBITMAP someBin = loadBinaryImg("something.bin");
    saveHbitmapAsPng(someBin, L"output.png");
    saveHbitmapAsBmp(someBin, "output.bmp");

    // Shutdown GDI+
    GdiplusShutdown(gdiplusToken);


    return 0;
}
 
Share this answer
 
v2
Comments
Jochen Arndt 8-Dec-14 7:10am    
Have 5 for your effort.
enhzflep 8-Dec-14 17:26pm    
Thank-you Jochen. :)
Try this:
C#
byte[] oByteArray= File.ReadAllBytes(@"path-to-binary-file");
MemoryStream oMemoryStream = new MemoryStream(oByteArray);
Image oImage = Image.FromStream(oMemoryStream);
oImage.Save(@"path-to-png-image", ImageFormat.Png);
 
Share this answer
 
v2
Comments
IceTrailer 7-Dec-14 10:25am    
Thank you,

okay first it's c# (but it doesn't matter)..
second Visual Studio tells me that Image.Save has to be static.

Do you know how to fix?
static void Main(string[] args)
{
string oldFile = @"D:\Daniel\Desktop\ip\0";
string newFile = @"D:\Daniel\Desktop\ip\new\0.png";

byte[] oByteArray = File.ReadAllBytes(oldFile);
MemoryStream oMemoryStream = new MemoryStream(oByteArray);
Image oImage = Image.FromStream(oMemoryStream);
Image.Save(newFile, ImageFormat.Png);

}

Thank you in advance.
Kornfeld Eliyahu Peter 7-Dec-14 11:18am    
Of course it should be oImage...Updated the answer...
IceTrailer 7-Dec-14 13:13pm    
Oh crap.. I get at line
Image oImage = Image.FromStream(oMemoryStream);
System.ArgumentException in System.Drawing.dll
Additional information: Invalid parameter.
Do you know how to fix?
Kornfeld Eliyahu Peter 7-Dec-14 14:42pm    
Probably the byte array can not be converted to image :-(...
Try these:
1. Image.FromStream(oMemoryStream, true);
2. Bitmap oBitmap = new Bitmap(oMemoryStream); oBitmap.Save(@"path-to-png-image", ImageFormat.Png);
syed shanu 7-Dec-14 20:48pm    
Did you import the System.Drawing.dll
Namespace to your CS file.
If not you have to import the name space at the top as
using System.Drawing.dll;

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900