LibQREncode qrcode to BMP

LibQREncode qrcode to BMP

本文关键字:BMP to qrcode LibQREncode      更新时间:2023-10-16

我正在用库qrencode.h创建一个qrcode该创建工作正常,但是如何将QRCode输出到C 中的BMP文件?此刻,我有此代码:

const char*         szSourceSring = QRCODE_TEXT;
unsigned int    unWidth, x, y, l, n, unWidthAdjusted, unDataBytes;
unsigned char*  pRGBData, *pSourceData, *pDestData;
QRcode*         pQRC;
FILE*           f;
 
if (pQRC = QRcode_encodeString(szSourceSring, 4, QR_ECLEVEL_H, QR_MODE_8, 1))
        {
        unWidth = pQRC->width;
        unWidthAdjusted = unWidth * OUT_FILE_PIXEL_PRESCALER * 3;
        if (unWidthAdjusted % 4)
            unWidthAdjusted = (unWidthAdjusted / 4 + 1) * 4;
        unDataBytes = unWidthAdjusted * unWidth * OUT_FILE_PIXEL_PRESCALER;
 
            // Allocate pixels buffer
 
        if (!(pRGBData = (unsigned char*)malloc(unDataBytes)))
            {
            printf("Out of memory");
            }
           
            // Preset to white
 
        memset(pRGBData, 0xff, unDataBytes);
 
 
            // Prepare bmp headers
 
        BITMAPFILEHEADER kFileHeader;
        kFileHeader.bfType = 0x4D42;  // "BM"
        kFileHeader.bfSize =    sizeof(BITMAPFILEHEADER) +
                                sizeof(BITMAPINFOHEADER) +
                                unDataBytes;
        kFileHeader.bfReserved1 = 0;
        kFileHeader.bfReserved2 = 0;
        kFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) +
                                sizeof(BITMAPINFOHEADER);
 
        BITMAPINFOHEADER kInfoHeader;
        kInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
        kInfoHeader.biWidth = unWidth * OUT_FILE_PIXEL_PRESCALER;
        kInfoHeader.biHeight = -((int)unWidth * OUT_FILE_PIXEL_PRESCALER);
        kInfoHeader.biPlanes = 1;
        kInfoHeader.biBitCount = 24;
        kInfoHeader.biCompression = BI_RGB;
        kInfoHeader.biSizeImage = 0;
        kInfoHeader.biXPelsPerMeter = 0;
        kInfoHeader.biYPelsPerMeter = 0;
        kInfoHeader.biClrUsed = 0;
        kInfoHeader.biClrImportant = 0;
 
            // Convert QrCode bits to bmp pixels
 
        pSourceData = pQRC->data;
        for(y = 0; y < unWidth; y++)
        {
            pDestData = pRGBData + unWidthAdjusted * y * OUT_FILE_PIXEL_PRESCALER;
            for(x = 0; x < unWidth; x++)
            {
                if (*pSourceData & 1)
                {
                    for(l = 0; l < OUT_FILE_PIXEL_PRESCALER; l++)
                    {
                        for(n = 0; n < OUT_FILE_PIXEL_PRESCALER; n++)
                        {
                            *(pDestData +       n * 3 + unWidthAdjusted * l) =  PIXEL_COLOR_B;
                            *(pDestData + 1 +   n * 3 + unWidthAdjusted * l) =  PIXEL_COLOR_G;
                            *(pDestData + 2 +   n * 3 + unWidthAdjusted * l) =  PIXEL_COLOR_R;
                        }
                    }
                }
                pDestData += 3 * OUT_FILE_PIXEL_PRESCALER;
                pSourceData++;
            }
        }
 
 
            // Output the bmp file
 
        /*if (((f = fopen(OUT_FILE, "r")) != NULL))
            {*/
            f = fopen(OUT_FILE, "wb");
            fwrite(&kFileHeader, sizeof(BITMAPFILEHEADER), 14, f);
            fwrite(&kInfoHeader, sizeof(BITMAPINFOHEADER), 40, f);
            fwrite(pRGBData, sizeof(unsigned char), unDataBytes, f);
           
            fclose(f);
/*          }
        else
            {
            printf("Unable to open file");
            }
*/
            // Free data
 
        free(pRGBData);
        QRcode_free(pQRC);
        }
    else
        {
        printf("NULL returned");
        }

,但以某种方式创建了一个带有损坏的标题的BMP。每当我打开BMP文件时,都会说:

" BMP图像的标头尺寸不支持"

我在做什么错?是否可以保存到PNG而不是BMP?我可以访问libPNG

这是一个代码示例,该示例转载了从QR-Code创建的24 BPP BMP文件。您看到的错误可能不是QR代码库引起的,而是BMP文件代码中的某些错误。

该示例创建的BMP文件与Windows 8.1打包的图像查看器正常工作。如果您也看不到错误,则可以检查每个二进制输出的差异以查明问题。如果您想要。

此问题被标记为" C "answers" C 11",因此此示例使用C STD库进行文件输出,并且不使用malloc。(但是几乎同样糟糕 - 我在某些容器代码中使用newdelete,其中首选std::vector成员...不要告诉任何人)。另外,此示例将每个数据直接写入文件,而不是使用文件大小的中间缓冲区,例如pDestData

#include <iostream>
#include <fstream>
// A fake (or "somewhat limited") QR Code data container
struct Qrc {
    int dimsize;          // the width and height
    unsigned char* data;  // buffer which contains the elements
    Qrc() {
        static const unsigned int bin[] = { // encodes an important secret message
            0xfc8b7d7f,0xa801a83,0xd6e54d76,0xaa9eb2ed,0x43ed05db,0xb8786837,0x55555fe0,
            0x5a4c807f,0xcf315c00,0x6e8019ce,0xc7819e0d,0xd4857ba8,0x4ac5e347,0xf6f349ba,
            0xd433ccdd,0x2998361e,0x4453fab3,0x526d9085,0x81f38924,0xb4da0811,0x84b3131a,
            0x9639915e,0x3b74a4ff,0x42aa0c11,0x4127be16,0x1f4350,0xff620296,0xad54de1,
            0xd38c2272,0xa3f76155,0x5366a7ab,0x9bdd2257,0x300d5520,0x85842e7f,0 };
        dimsize = 33;
        data = new unsigned char[dimsize * dimsize];
        auto p = data;
        auto endp = p + dimsize * dimsize;
        for(unsigned int b : bin) {
            for(int i=0; i<32; ++i) {
                if(p == endp) break;
                *(p++) = b & (1 << i) ? 255 : 0;
    }   }   }
    Qrc(const Qrc&) = delete;
    Qrc& operator = (const Qrc&) = delete;
    ~Qrc() { delete [] data; }
};
struct BIH {   // a private definition of BITMAPINFOHEADER
    unsigned int   sz;
    int            width, height;
    unsigned short planes;
    short          bits;
    unsigned int   compress, szimage;
    int            xppm, yppm;
    unsigned int   clrused, clrimp;
};
void SaveBmp(const char* filename, const Qrc& qrc) {
    // Asker's Qrc struct delivered as a pointer, from a C API, but this example doesn't mimic that.
    std::ofstream ofs(filename, std::ios_base::out | std::ios_base::binary);
    if(!ofs) {
        std::cout << "Writing " << filename << " failedn";
        return;
    }
    const int side_len            = qrc.dimsize;  // width and height of the (square) QR Code
    const int pixel_side_len      = 4; // QRC element's size in the bmp image (in pixels)
    const int bmp_line_bytes      = side_len * pixel_side_len * 3;
    const int bmp_line_pad_bytes  = (4 - bmp_line_bytes % 4) % 4;  // bmp line data padding size
    const int bmp_data_size       = side_len * (bmp_line_bytes + bmp_line_pad_bytes);
    BIH bih = { sizeof(bih) };      
    bih.width = side_len * pixel_side_len;   // element count * element size
    bih.height = -side_len * pixel_side_len; // negative height => data begins at top of image
    bih.planes = 1;
    bih.bits = 24;
    const int header_size = sizeof(bih) + 14;  // size of the bmp file header
    const int filesize    = header_size + bmp_data_size; // size of the whole file
    ofs.write("BM", 2);
    ofs.write(reinterpret_cast<const char*>(&filesize), 4);
    ofs.write("", 4);  // 2x 16-bit reserved fields
    ofs.write(reinterpret_cast<const char*>(&header_size), 4);
    ofs.write(reinterpret_cast<const char*>(&bih), sizeof(bih));
    // pixel colors, as Blue, Green, Red char-valued triples
    // the terminating null also makes these usable as 32bpp BGRA values, with Alpha always 0.
    static const char fg_color[] = "";
    static const char bg_color[] = "xffxffxff";
    auto pd = qrc.data;
    // send pixel data directly to the bmp file
    // QRC elements are expanded into squares
    // whose sides are "pixel_side_len" in length.
    for(int y=0; y<side_len; ++y) {
        for(int j=0; j<pixel_side_len; ++j) {
            auto pdj = pd;
            for(int x=0; x<side_len; ++x) {
                for(int i=0; i<pixel_side_len; ++i) {
                    // *pdj will be 0 or 255 (from "fake" Qrc)
                    // Using "*pdj & 1" here, just to match asker's code
                    // without knowing why this was done.
                    ofs.write(*pdj & 1 ? fg_color : bg_color, 3);
                }
                ++pdj;
            }
            if(bmp_line_pad_bytes) {
                ofs.write("", bmp_line_pad_bytes);
            }
        }
        pd += side_len;
    }
}
int main() {
    SaveBmp("MyQrCode.bmp", Qrc());
}