一个从原始字节创建bmp文件的可移植函数?

时间:2012-12-06 13:55:51

标签: c++ unix bitmap

我有一个原始字节数组,我想从这些字节中生成一个bmp文件。也就是说,我必须填写位图头结构和其他东西,然后写下字节,这样我就有一个正确格式的bmp文件。

由于我只需要一些快速检查,我想知道是否有一个可移植的方法来执行此操作 - 获取原始字节并将它们保存为bmp文件。任何Windows版本都不会像我在Unix上写的那样。

或者,我可以将这些字节保存为任何其他图像格式 - 我只需要快速查看结果图片。

6 个答案:

答案 0 :(得分:4)

这是我用于.bmp灰度图像的代码

要保存为彩色位图,请确保不使用调色板(24位)

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 );
}

答案 1 :(得分:2)

您可以使用SOIL,它轻巧,便携,虽然针对OpenGL,但它可以加载图像(还可以保存图像)并返回原始数据。

以下是一些示例用法用法(来自SOIL网站)

   /* 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
   );

以下是SOIL提供的可读格式:

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)

编辑:如果您愿意,也可以使用stb_image(也是跨平台和可移植的),其中包含所有文档等单个文件。

答案 2 :(得分:2)

以下内容将为您提供字节数组中的.ppm图像。 "P6"指定二进制格式每像素3字节,但也支持纯文本和各种形式的灰度。您应该使用它的原因是它很容易,并且大多数* nix系统都有一堆ppmto * -tools:ppmtobmp,ppmtojpeg,...,ppmtopng ...您可以命名。

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;
}

还有ppmtocad ......会猜到谁?

答案 3 :(得分:1)

Boost GIL支持对JPG,TIFF和PNG的读/写。

基于模板,您可以调整图像格式到库中。这可能对你来说太过分了。

答案 4 :(得分:1)

试试EasyBMP,它是一个开源的跨平台C ++库,用它创建BMP文件很有趣:

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");

答案 5 :(得分:-2)

只需查看WinGDI中BITMAPFILEHEADERBITMAPINFOHEADER的typedef,字段很简单。确保WORD为16位int,DWORD为32位int。如果您正在使用RGBRGBRGB ...填写标题并写出数据非常容易......