A portable function to create a bmp file from raw

2020-06-24 08:23发布

I have an array of raw bytes and I want to make a bmp file from those bytes. That is, I have to fill bitmap header structre and other things, then write down the bytes so I have a bmp file in the proper format.

As I need this for some quick check only, I wonder if there is a portable method to do this - take raw bytes and save them as a bmp file. Any Windows version won't do as I'm writing that on Unix.

Alternatively, I can save those bytes as any other image format - I only need to have a quick look at the resulting picture.

标签: c++ unix bitmap
6条回答
我想做一个坏孩纸
2楼-- · 2020-06-24 09:02

The following will give you a .ppm image from a byte array. The "P6" specifies binary format 3 byte per pixel, but plain text is also supported and various forms of grayscale. The reason you should use this is that it is easy as can be and most *nix systems have a bunch of ppmto*-tools: ppmtobmp, ppmtojpeg, ..., ppmtopng... you name it.

typedef struct {
    int width;
    int height;
    uint8_t *data;
    size_t size;
} ppm_image;

size_t ppm_save(ppm_image *img, FILE *outfile) {
    size_t n = 0;
    n += fprintf(outfile, "P6\n# THIS IS A COMMENT\n%d %d\n%d\n", 
                 img->width, img->height, 0xFF);
    n += fwrite(img->data, 1, img->width * img->height * 3, outfile);
    return n;
}

There is also ppmtocad... who would have guessed?

查看更多
叼着烟拽天下
3楼-- · 2020-06-24 09:09

Boost GIL supports read/write to JPG, TIFF and PNG.

Being heavily template-based you can adapt your image format to the library. It may be an overkill for you tho.

查看更多
爱情/是我丢掉的垃圾
4楼-- · 2020-06-24 09:11

This is the code I use for .bmp Greyscale images

To save as color bitmap, just make sure about not using the palette (for 24bits)

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 );
}
查看更多
霸刀☆藐视天下
5楼-- · 2020-06-24 09:23

Try EasyBMP, it is open-source cross-platform C++ library and it is just fun to create BMP files with it:

BMP AnImage;
// Set size to 640 × 480
AnImage.SetSize(640,480);
// Set its color depth to 32-bits
AnImage.SetBitDepth(32);

// Set one of the pixels
AnImage(14,18)->Red = 255;
AnImage(14,18)->Green = 255;
AnImage(14,18)->Blue = 255;
AnImage(14,18)->Alpha = 0;

AnImage.WriteToFile("Output.bmp");
查看更多
▲ chillily
6楼-- · 2020-06-24 09:28

Just take a look at the typedefs for BITMAPFILEHEADER and BITMAPINFOHEADER from WinGDI, the fields are easy. Make sure you have 16-bit int for WORD and 32-bit int for DWORD. If you're doing RGBRGBRGB... it's super-easy to fill in the headers and write out the data...

查看更多
何必那么认真
7楼-- · 2020-06-24 09:29

You could use SOIL, it's lightweight, portable, and although aimed for OpenGL it can load images (and also save images) and give you back the raw data.

Here's some example usage usage (from the SOIL site)

   /* load an image as a heightmap, forcing greyscale (so channels should be 1) */
   int width, height, channels;
   unsigned char *ht_map = SOIL_load_image
   (
    "terrain.tga",
    &width, &height, &channels,
    SOIL_LOAD_L
   );

Here's the readable formats that SOIL has to offer:

Readable Image Formats:
BMP - non-1bpp, non-RLE (from stb_image documentation)
PNG - non-interlaced (from stb_image documentation)
JPG - JPEG baseline (from stb_image documentation)
TGA - greyscale or RGB or RGBA or indexed, uncompressed or RLE
DDS - DXT1/2/3/4/5, uncompressed, cubemaps (can't read 3D DDS files yet)
PSD - (from stb_image documentation)
HDR - converted to LDR, unless loaded with *HDR* functions (RGBE or RGBdivA or RGBdivA2)

EDIT: You can also use stb_image (which is also cross-platform and portable) if you prefer, which has all documentation and such in the single file.

查看更多
登录 后发表回答