LibQREncode qrcode to BMP

时间:2016-06-20 14:58:38

标签: c++ image c++11 qr-code bmp

我正在使用库qrencode.h创建qrcode 这个创建工作得很好但是如何将qrcode输出到c ++中的BMP文件? 在这个时刻,我有这个代码:

<title:LocalizableTitle xml:lang="en">
</title:LocalizableTitle>

但不知何故,这会创建一个包含损坏标头的BMP。每当我打开bmp文件时,它都说:

  

“BMP Image的标头大小不受支持”

我做错了什么? 是否可以保存到png而不是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"); }

1 个答案:

答案 0 :(得分:2)

这是一个代码示例,它转储从QR码创建的24 bpp bmp文件。您看到的错误可能不是由QR-Code库引起的,而是由bmp文件代码引起的。

此示例创建的bmp文件可以与我的Windows 8.1打包的图像查看器一起使用。如果您也没有看到错误,可以检查每个二进制输出的差异以查明问题。如果你想。

此问题已标记为&#34; C ++&#34;和&#34; C ++ 11&#34;,所以这个例子使用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 << " failed\n";
        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("\0\0\0\0", 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[] = "\0\0\0";
    static const char bg_color[] = "\xff\xff\xff";

    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("\0\0\0", bmp_line_pad_bytes);
            }
        }
        pd += side_len;
    }
}

int main() {
    SaveBmp("MyQrCode.bmp", Qrc());
}