度々使う自前の画像読み込み関数。メモリ確保を関数側にやらせると呼び出し側の処理が煩雑になるので、いっそのことメモリ確保関数を渡してしまうことにした。
#pragma once #include <stdio.h> #include <string> #include <functional> #pragma warning(disable:4996) //! @brief PPM(RGB各1byte,カラー,テキスト)を読み込む //! @param [in] fname //! @param [out] width 画像幅 //! @param [out] height 画像高さ //! @param [out] vmax 最大値 //! @param [in] memalloc メモリ確保用の関数 //! @retval true 読み込み成功 //! @retval false 読み込み失敗 bool ppmP3_read( const char* const fname, int *width, int *height, int *vmax, std::function<unsigned char*(const size_t pixelcount)> memalloc ) { *width = -1; *height = -1; *vmax = -1; FILE* fp; fp = fopen(fname, "rb"); char tmp[2048]; char c; while (c = fgetc(fp)) { if (isspace(c)) continue; if (c == 'P') { //フォーマットを特定する c = fgetc(fp) - '0'; if (c != 3) { fclose(fp); return false; } continue; } if (c == '#') { //コメントを読み飛ばす while (c != '\r' && c != '\n') c = fgetc(fp); continue; } //幅取得 if (*width < 0) { int s = 0; while (1) { if (isdigit(c)) { tmp[s++] = c; c = fgetc(fp); } else { tmp[s] = '\0'; *width = atoi(tmp); break; } } continue; } //高さ取得 if (*height < 0) { int s = 0; while (1) { if (isdigit(c)) { tmp[s++] = c; c = fgetc(fp); } else { tmp[s] = '\0'; *height = atoi(tmp); break; } } continue; } //最大値(白)取得 if (*vmax < 0) { int s = 0; while (1) { if (isdigit(c)) { tmp[s++] = c; c = fgetc(fp); } else { tmp[s] = '\0'; *vmax = atoi(tmp); break; } } break; } else { break; } } if (*width < 0 || *height < 0 || *vmax < 0) { return false; }
//////////////////////////////////////// //メモリ確保 size_t count = *width* *height; size_t memsize = count*3; unsigned char* pimg = memalloc(count); ////////////////////////////////////////
int read = 0; char text[100]; int index = 0; //メモリサイズ分まで読み込む while (read < memsize) { int c = fgetc(fp);//一文字取得 if (c == EOF)//入力できなかったらループから出る break; //数字ならストックする if (isdigit(c)) { text[index] = (char)c; index++; } else { //数字以外が入力されたら、 //ストックした数字を数値化 //ただし数字が何もストックされていないなら //なにもしない if (index) { text[index] = '\0'; pimg[read] = atoi(text); read++; index = 0; } } } return read == memsize; }
#include <vector> // https://www.study.suzulang.com/2dcg-functions/nbyte-data-type #include "NByteData.hpp" // 以下をベースに変更: // https://www.study.suzulang.com/cppppm-readerwriter/ppm-p3-reader-cpp #include "ppmP3_read.hpp" ///////////////////////////////////////////////////// void ppmP3_write( const char* const fname, const int width, const int height, const unsigned char* const p, const int vmax );
int main() { using PixelT = NByteData<3>; std::vector<PixelT> mem; // 画像読み込み int width; int height; int vmax; ppmP3_read( "C:\\test\\p.ppm", &width, &height, &vmax, [&mem](const size_t pixelcount) { mem.resize(pixelcount); return (unsigned char*)&mem[0]; } ); // 色を反転 for(auto& p : mem){ p.data()[0] = 255 - p.data()[0]; p.data()[1] = 255 - p.data()[1]; p.data()[2] = 255 - p.data()[2]; } ///////////////////////////////// ///////////////////////////////// ppmP3_write( "C:\\test\\q.ppm", width, height, (unsigned char*)&mem[0], 255); }
//! @brief PPM(RGB各1byte,カラー,テキスト)を書き込む //! @param [in] fname ファイル名 //! @param [in] width 画像の幅 //! @param [in] height 画像の高さ //! @param [in] p 画像のメモリへのアドレス //! @param [in] vmax 全てのRGBの中の最大値。普通の画像なら255 //! @details RGBRGBRGB....のメモリを渡すと、RGBテキストでファイル名fnameで書き込む void ppmP3_write( const char* const fname, const int width, const int height, const unsigned char* const p, const int vmax ) { FILE* fp = fopen(fname, "wb"); fprintf(fp, "P3\n%d %d\n%d\n", width, height, vmax); size_t k = 0; for (size_t i = 0; i < (size_t)height; i++) { for (size_t j = 0; j < (size_t)width; j++) { fprintf(fp, "%d %d %d ", p[k * 3 + 0], p[k * 3 + 1], p[k * 3 + 2] ); k++; } fprintf(fp, "\n"); } fclose(fp); }