ぬの部屋(仮)
nu-no-he-ya
  •  123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
         12
    3456789
    10111213141516
    17181920212223
    242526272829 
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
        123
    45678910
    11121314151617
    18192021222324
    25262728   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    15161718192021
    293031    
           
         12
    3456789
    10111213141516
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728     
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
          1
    2345678
    9101112131415
    16171819202122
    232425262728 
           
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
  • PNM Writer(改)

    PNMの書き込み関数を書いた。

    ただし前回のPNM Readerで書いたPNM_TYPE列挙体が共通のため、前回のPNM Readerと同じファイルに書くことが望ましい。

    プログラム本体(含 PNM Reader)

    #pragma once
    
    #include <fstream>
    #include <sstream>
    #include <string>
    #include <vector>
    #include <algorithm>
    
    
    //! @brief PNMファイルの種類
    enum class PNM_TYPE {
      P1 = 1,  //Portable bitmap   ASCII
      P2 = 2,  //Portable graymap  ASCII
      P3 = 3,  //Portable pixmap   ASCII
      P4 = 4,  //Portable bitmap   Binary
      P5 = 5,  //Portable graymap  Binary
      P6 = 6,  //Portable pixmap   Binary
      PError = 7,
      PBitmap = 8,
      PGraymap = 9,
      PPixmap = 10
    };
    //////////////////////////////////////////////////////////
    // PNM Reader
    
    
    //! @class CGetGrayBits //! @brief 配列上のx番目の画素値を取得するクラス //! @sa https://suzulang.com/bit-depth-1-2-4-getpixelvalue/ class CGetGrayBits { unsigned char* m_p; //!< 画素へのポインタ const int m_depth = 1; //!< ビット深度 unsigned char m_mask = 1; //!< depth8未満の時のビットマスク public: //! @brief コンストラクタ //! @param [in] p 画素配列へのポインタ CGetGrayBits( const void* const p) : m_p(static_cast<unsigned char*>(const_cast<void*>(p))) { } //! @brief 指定した番号の画素を取得 //! @param [in] x 画素番号 //! @return 画素値 int operator[](const std::size_t x) { // x ドットが何バイト目かを算出 (0開始) std::size_t byte = x / (8 / m_depth); unsigned char c = m_p[byte]; std::size_t pos = x % (8 / m_depth); int shift = 8 - m_depth - pos * m_depth; unsigned char mask1 = m_mask << shift; unsigned int val = (c & mask1) >> shift; return val; } }; //! @brief ストリームから入力 bitmap ASCII //! @param [out] img 画像の格納先 //! @param [out] s 入力ストリーム void read_P1(std::vector<unsigned char>& img, std::ifstream& s) { while (s.eof() == false) { char c; s.read(&c, 1); if (isdigit(c) != false) { img.push_back(c - '0'); } } } //! @brief ストリームから入力 graymap,pixmap ASCII //! @param [out] img 画像の格納先 //! @param [out] s 入力ストリーム void read_P23(std::vector<unsigned char> & img, std::ifstream & s) { while (s.eof() == false) { std::string val; s >> val; int value; try { value = std::stoi(val); } catch (std::invalid_argument) { continue; } img.push_back(value); } } //! @brief ストリームから入力 bitmap Binary //! @param [out] img 画像の格納先 //! @param [out] s 入力ストリーム //! @return なし //! @details P4は1ビット=1画素なので全部読み込んでから1ビットずつとりだしている void read_P4(std::vector<unsigned char> & img, std::ifstream & s, int count) { std::vector<unsigned char> tmp; unsigned char tc; while (!s.eof()) { s.read((char*)& tc, sizeof(char)); tmp.push_back(tc); } CGetGrayBits bits(&tmp[0]); for (size_t i = 0; i < count; i++) { img.push_back(bits[i]); } } //! @brief ストリームから入力 graymap,pixmap Binary //! @param [out] img 画像の格納先 //! @param [out] s 入力ストリーム //! @return なし void read_P56(std::vector<unsigned char> & img, std::ifstream & s) { while (s.eof() == false) { unsigned char c; s.read((char*)& c, 1); img.push_back(c); } } //! @brief pnmファイルを読み込む //! @param [in] fpathname pnmファイルへのパス //! @param [out] img 画像の格納先 //! @param [out] width 横方向の画素数 //! @param [out] height 縦方向の画素数 //! @param [out] maxvalue 画素の最大値 //! @param [out] datatype 形式を識別する定数 //! @retval true 読込成功 //! @retval false 読込失敗 bool read_pnm(const char* fpathname, std::vector<unsigned char> * img, int* width, int* height, int* maxvalue, PNM_TYPE * datatype) { std::ifstream ifs(fpathname, std::ios::in | std::ios::binary); if (!ifs) return false; std::string text; *width = -1; *height = -1; *maxvalue = -1; //タイプの読み取り PNM_TYPE type; { int _type = (int)PNM_TYPE::PError; while (std::getline(ifs, text).eof() == false) { if (text[0] == 'P') { _type = ((int)text[1] - (int)'0'); break; } } switch (_type) { case (int)PNM_TYPE::P1:*datatype = PNM_TYPE::PBitmap; break; case (int)PNM_TYPE::P2:*datatype = PNM_TYPE::PGraymap; break; case (int)PNM_TYPE::P3:*datatype = PNM_TYPE::PPixmap; break; case (int)PNM_TYPE::P4:*datatype = PNM_TYPE::PBitmap; break; case (int)PNM_TYPE::P5:*datatype = PNM_TYPE::PGraymap; break; case (int)PNM_TYPE::P6:*datatype = PNM_TYPE::PPixmap; break; default: *datatype = PNM_TYPE::PError; return false; } type = (PNM_TYPE)_type; } while (std::getline(ifs, text).eof() == false) { //コメントスキップ if (text[0] == '#') continue; //コメントでないなら各種値の入力 std::stringstream ss(text); //幅入力 if (*width < 0) { ss >> *width; if (*width < 0) continue; } //高さ入力 if (*height < 0) { ss >> *height; if (*height < 0) continue; } //最大値入力 if (*datatype != PNM_TYPE::PBitmap) { if (*maxvalue < 0) { ss >> *maxvalue; if (*maxvalue < 0) continue; } } break; } int count = *width * *height; switch (type) { case PNM_TYPE::P1: img->reserve(count); read_P1(*img, ifs); break; case PNM_TYPE::P2: img->reserve(count); read_P23(*img, ifs); break; case PNM_TYPE::P3: img->reserve(count * 3); read_P23(*img, ifs); break; case PNM_TYPE::P4: read_P4(*img, ifs, count); break; case PNM_TYPE::P5: read_P56(*img, ifs); break; case PNM_TYPE::P6: read_P56(*img, ifs); break; } }
    //
    //////////////////////////////////////////////////////////
    
    //////////////////////////////////////////////////////////
    // PNM Writer
    
    
    //! @brief 1byteの各ビットに配列のようにアクセスするためのクラス
    class bititerator_t {
      unsigned char* m_c;
      int m_index;
    public:
      bititerator_t(unsigned char* c, const int index) {
        m_c = c;
        m_index = 7 - index;
      }
      void operator=(const int value) {
        unsigned char mask = (1 << m_index);
    
        if (value) {
          *m_c |= mask;
        }
        else {
          *m_c &= ~mask;
        }
      }
      operator unsigned char() {
        unsigned char mask = (1 << m_index);
    
        return (*m_c & mask) ? 1 : 0;
      }
    
    
    };
    
    //! @brief 1byteの各ビットに配列のようにアクセスするためのクラス
    class BitArray {
      unsigned char c;
    public:
      BitArray() :c(0) {}
      bititerator_t operator[](const int i) {
        return bititerator_t(&c, i);
      }
      operator unsigned char() {
        return c;
      }
      unsigned char operator=(const unsigned char value) {
        c = value;
        return c;
      }
    };
    //////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////
    
    
    
    //! @brief データタイプを文字列に変換
    std::string to_string(const PNM_TYPE type) {
      switch (type) {
      case PNM_TYPE::P1:return "P1"; break;
      case PNM_TYPE::P2:return "P2"; break;
      case PNM_TYPE::P3:return "P3"; break;
      case PNM_TYPE::P4:return "P4"; break;
      case PNM_TYPE::P5:return "P5"; break;
      case PNM_TYPE::P6:return "P6"; break;
      }
      return "";
    
    }
    
    //! @brief 各データタイプにおける1ピクセルのビット数を求める
    int pixel_bit_count(const PNM_TYPE type) {
      switch (type) {
      case PNM_TYPE::P1:return 1;   break;
      case PNM_TYPE::P2:return 8;   break;
      case PNM_TYPE::P3:return 8 * 3; break;
      case PNM_TYPE::P4:return 1;   break;
      case PNM_TYPE::P5:return 8;   break;
      case PNM_TYPE::P6:return 8 * 3; break;
      }
      return -1;
    
    }
    //! @brief Portable bitmap   ASCII
    //! @param [in,out] s 出力先
    //! @param [in] img 1byte1画素の画像データ
    //! @param [in] width 幅画素数
    //! @param [in] height 高さ画素数
    //! @return なし
    void write_P1(std::ofstream& s, const unsigned char* img, const int width, const int height) {
      int count = width * height;
      for (size_t i = 0; i < count; i++) {
        s << std::to_string(img[i] ? 1 : 0);
      }
    }
    //! @brief ストリームへ出力 Portable graymap  ASCII
    //! @param [in,out] 出力先
    //! @param [in] img 画像データ
    //! @param [in] width 画素数幅
    //! @param [in] height 画素数高さ
    //! @return なし
    void write_P2(std::ofstream & s, const unsigned char* img, const int width, const int height) {
      int count = width * height;
      int i = 0;
      for (size_t h = 0; h < height; h++) {
        for (size_t w = 0; w < width; w++) {
          s << std::to_string(img[i]) << " ";
          i++;
        }
        s << std::endl;
      }
    }
    //! @brief ストリームへ出力 Portable pixmap   ASCII
    //! @param [in,out] 出力先
    //! @param [in] img 画像データ
    //! @param [in] width 画素数幅
    //! @param [in] height 画素数高さ
    //! @return なし
    void write_P3(std::ofstream & s, const unsigned char* img, const int width, const int height) {
      int count = width * height;
      int i = 0;
      for (size_t h = 0; h < height; h++) {
        for (size_t w = 0; w < width; w++) {
          s << std::to_string(img[i * 3 + 0]) << " ";
          s << std::to_string(img[i * 3 + 1]) << " ";
          s << std::to_string(img[i * 3 + 2]) << " ";
          i++;
        }
        s << std::endl;
      }
    }
    //! @brief ストリームへ出力 Portable bitmap   Binary
    //@details 入力が1byte 1pixel なので、 8要素を1byteにまとめる
    //! @param [in,out] 出力先
    //! @param [in] img 画像データ
    //! @param [in] count 画素数
    //! @return なし
    void write_P4(std::ofstream & s, const unsigned char* img, const int count) {
    
      int bitindex = 0;
      BitArray bits;
      for (size_t i = 0; i < count; i++) {
    
        if (bitindex == 0) {
          bits = 0;
        }
    
        bits[bitindex] = img[i];
    
        bitindex++;
        bitindex %= 8;
    
        if (bitindex == 0) {
          unsigned char c = bits;
          s.write((const char*)& c, 1);
        }
      }
    
    }
    //! @brief ストリームへ出力 Portable graymap  Binary , Portable pixmap   Binary
    //@details 入力が1byte 1pixel なので、 8要素を1byteにまとめる
    //! @param [in,out] 出力先
    //! @param [in] img 画像データ
    //! @param [in] bytes 画像データのバイト数
    //! @return なし
    void write_P56(std::ofstream & s, const unsigned char* img, const int bytes) {
      s.write((char*)img, bytes);
    }
    //! @brief pnmファイルを書き込む
    //! @param [in] fpathname pnmファイルへのパス
    //! @param [in] img 画像の格納先
    //! @param [int] width 横方向の画素数
    //! @param [in] height 縦方向の画素数
    //! @param [in] datatype 形式を識別、指定する定数
    //! @retval true 書き込み成功
    //! @retval false 書き込み失敗
    bool write_pnm(const char* fpathname, const unsigned char* img, const int width, const int height, const PNM_TYPE datatype) {
    
      if (datatype >= PNM_TYPE::PError)
        return false;
    
      int count = width * height;
      if (count <= 0)
        return false;
    
      std::ofstream ofs(fpathname, std::ios::out | std::ios::binary);
      if (!ofs)
        return false;
    
    
      int pixelbit = pixel_bit_count(datatype);
    
    
      ofs << to_string(datatype) << std::endl;
      ofs << width << " " << height << std::endl;
    
      int maxvalue = -1;
      if ((datatype != PNM_TYPE::P1) && (datatype != PNM_TYPE::P4)) {
        maxvalue = *std::max_element(
          img,
          img + count * pixel_bit_count(datatype) / 8);
    
        ofs << maxvalue << std::endl;
      }
    
    
      switch (datatype) {
      case PNM_TYPE::P1:
        write_P1(ofs, img, width, height);
        break;
      case PNM_TYPE::P2:
        write_P2(ofs, img, width, height);
        break;
      case PNM_TYPE::P3:
        write_P3(ofs, img, width, height);
        break;
      case PNM_TYPE::P4:
        write_P4(ofs, img, width * height);
        break;
      case PNM_TYPE::P5:
        write_P56(ofs, img, width * height);
        break;
      case PNM_TYPE::P6:
        write_P56(ofs, img, width * height * 3);
        break;
      }
    }
    

    テストプログラム

    #include <iostream>
    
    #include "pnm_rw.hpp"
    
    
    int main()
    {
      const char* fpathname = "C:\\test\\butterfly-5546907_640-ascii.pbm";
    
    
      std::vector<unsigned char> img;
      int width, height, maxvalue;
      PNM_TYPE type;
      read_pnm(
        fpathname,
        &img,
        &width,
        &height,
        &maxvalue,
        &type
      );
    
    
      switch (type) {
    
      case PNM_TYPE::PBitmap:
        write_pnm("C:\\test\\out-ascii.pbm", img.data(), width, height, PNM_TYPE::P1);
        write_pnm("C:\\test\\out-binary.pbm", img.data(), width, height, PNM_TYPE::P4);
        break;
      case PNM_TYPE::PGraymap:
        write_pnm("C:\\test\\out-ascii.pgm", img.data(), width, height, PNM_TYPE::P2);
        write_pnm("C:\\test\\out-binary.pgm", img.data(), width, height, PNM_TYPE::P5);
        break;
      case PNM_TYPE::PPixmap:
        write_pnm("C:\\test\\out-ascii.ppm", img.data(), width, height, PNM_TYPE::P3);
        write_pnm("C:\\test\\out-binary.ppm", img.data(), width, height, PNM_TYPE::P6);
        break;
      }
    }