2016-06-20 16 views
2

ライブラリでqrcodeを作成していますqrencode.h この作成はうまくいきますが、qrcodeをどのようにしてC++内のBMPファイルに出力するのですか? この瞬間私はこのコードを持っている:LibQREncode qrcode to 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イメージはサポートされていないヘッダサイズを持っていますか」? BMPではなくpngに保存することはできますか? libPNGライブラリにアクセスしています

+0

fwriteは2つのサイズパラメータをとります。これらのパラメータを掛け合わせると、書き込む合計バイト数が与えられます。あなたのコードでは、 'fwrite'は構造体のサイズを2回(' sizeof'と 'int'で1回ずつ)得ています。' fwrite'はそれぞれの 'struct'の2乗バイト数を書き込もうとします。修正するには、これらの行を同様のものに変更してください: 'fwrite(&kFileHeader、sizeof(BITMAPFILEHEADER)、1、f);' –

+0

@ChristopherOiclesまだサポートされていないヘッダサイズを取得しました。 – Baklap4

答えて

2

QRコードから作成された24 bpp bmpファイルをダンプするコード例です。表示されるエラーは、おそらくQRコードライブラリによって引き起こされるのではなく、むしろbmpファイルコードの中にあるものです。

この例で作成したbmpファイルは、Windows 8.1にパッケージされたイメージビューアで正常に動作します。エラーも表示されない場合は、各バイナリ出力の違いを調べて問題を特定できます。お望みならば。

この質問は "C++"と "C++ 11"とタグ付けされているので、この例ではファイル出力にC++標準ライブラリを使用し、mallocは使用しません。 (しかし、ほとんど同じように悪い - 私はstd::vectorメンバーが好まれている...コンテナコードでnewdeleteを使用します。誰にも言わないでください)。また、この例では、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()); 
}