2016-06-20 24 views
2

Ich erstelle einen QRCode mit der Bibliothek qrencode.h Diese Erstellung funktioniert gut, aber wie würde man den QRCode zu einer BMP-Datei in C++ ausgeben? In diesem Moment ich diesen Code haben:LibQREncode qrcode zu 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"); 
     } 

aber irgendwie schafft ein BMP mit korrupten Header. Jedes Mal, wenn ich bin der bmp-Datei öffnen heißt es:

„BMP-Bild hat nicht unterstützten Header-Größe“

Was mache ich falsch? Und ist es möglich, in PNG statt BMP zu speichern? Ich habe Zugriff auf die libPNG Bibliothek

+0

'fwrite' benötigt zwei Größenparameter, die zusammen multipliziert ergeben die Gesamtzahl der zu schreibenden Bytes. In Ihrem Code erhält 'fwrite' die Strukturgröße zweimal (einmal in' sizeof' und einmal als Literal 'int'), so dass' fwrite' letztendlich versucht, die quadrierte Bytezahl jeder 'struct' zu schreiben. Um das zu beheben, ändern Sie diese Zeilen in etwas ähnliches: 'fwrite (& kFileHeader, sizeof (BITMAPFILEHEADER), 1, f);' –

+0

@ChristopherOicles Ich habe es in Ihren Vorschlag geändert und bekomme immer noch die nicht unterstützte Header-Größe. – Baklap4

Antwort

2

Hier ist ein Codebeispiel, das eine 24 bpp BMP-Datei aus einem QR-Code erstellt dumps. Der Fehler, den Sie sehen, wird wahrscheinlich nicht von der QR-Code-Bibliothek verursacht, sondern eher von der bmp-Datei.

Die in diesem Beispiel erstellte BMP-Datei funktioniert gut mit dem Image Viewer, der mit meinem Windows 8.1 ausgeliefert wird. Wenn Sie den Fehler auch nicht sehen, können Sie in jeder binären Ausgabe nach Unterschieden suchen, um das Problem zu lokalisieren. Wenn du willst.

Diese Frage ist mit "C++" und "C++ 11" markiert, so dass dieses Beispiel die C++ - Standardbibliothek für die Dateiausgabe verwendet und malloc nicht verwendet. (Aber fast genauso schlecht - ich benutze new und delete in einigen Container-Code, wo ein std::vector Mitglied bevorzugt wird ... sagen Sie es niemandem). Außerdem schreibt dieses Beispiel jedes Datenelement direkt in die Datei, anstatt einen Zwischenpuffer in Dateigröße wie pDestData zu verwenden.

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