2

我有一个原始字节数组,我想用这些字节制作一个 bmp 文件。也就是说,我必须填写位图头结构和其他内容,然后写下字节,这样我就有了一个格式正确的 bmp 文件。

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

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

4

6 回答 6

5

这是我用于 .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 );
}
于 2012-12-06T14:21:59.737 回答
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(它也是跨平台和可移植的),它在单个文件中包含所有文档等。

于 2012-12-06T14:06:34.407 回答
2

以下将为您提供来自字节数组的.ppm图像。指定每像素 3 字节的"P6"二进制格式,但也支持纯文本和各种形式的灰度。你应该使用它的原因是它很简单,而且大多数 *nix 系统都有一堆 ppmto*-工具: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……谁能猜到?

于 2012-12-06T14:19:43.687 回答
2

试试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");
于 2013-10-17T12:36:49.043 回答
1

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

由于高度基于模板,您可以使图像格式适应库。这对你来说可能有点过头了。

于 2012-12-06T14:15:03.343 回答
-2

只需查看 WinGDI 的 typedefBITMAPFILEHEADERBITMAPINFOHEADER来自 WinGDI 的 typedef,这些字段很简单。确保您有 16 位 int 用于 WORD 和 32 位 int 用于 DWORD。如果您正在做 RGBRGBRGB... 填写标题并写出数据非常容易...

于 2012-12-06T16:20:33.233 回答