windowsでシステムのプロパティの環境変数のPATHにパスを追加するのが嫌なので、環境変数を適用したコマンドプロンプトを開くバッチファイルを作成する
cd C:\mybins\command\work
set PATH_ANC=C:\Users\yamada\anaconda3;C:\Users\yamada\anaconda3\Scripts;C:\Users\yamada\anaconda3\Library\bin
set PATH_APP=C:\mybins\7za;C:\mybins\command\ffmpeg-2021-11-29-git-86a2123a6e-full_build\bin;C:\mybins\ImageMagick-7.1.0-portable-Q16-x64
set PATH_CMP=C:\mybins\command\PortableGit\bin;C:\mybins\command\depot_tools
set path=%PATH_ANC%;%PATH_APP%;%PATH_CMP%;%path%;
%windir%\system32\cmd.exe /k
一行目のcdでカレントディレクトリを設定する。
二行目以降、setで環境変数を三つ設定。一行でもいいのだが自分が管理しやすいように分割している。
最後のset path=で三つを結合し%path%と混ぜる。なおanaconda3を%path%より前に書かないとmicrosoft store?的な物が起動してしまう可能性がある。
最後のcmd.exeでコマンドプロンプトを開く。
SDL2に続いてSDL_imageを使う。
マニュアルを読むとpngの読込関数なんかが入っているが、別途libpng等を使っているのでただのラッパーだと思われる。
URL https://www.libsdl.org/projects/SDL_image/
ダウンロード SDL2_image-devel-2.0.5-VC.zip (Visual C++ 32/64-bit)
パス設定
include : SDL2_image-2.0.5\include
lib : SDL2_image-2.0.5\lib\x64
// このマクロを定義しないとエントリポイントが SDL_main になる #define SDL_MAIN_HANDLED #include <SDL.h> // IMG_Load #include <SDL_image.h> #pragma comment(lib,"SDL2.lib") #pragma comment(lib,"SDL2_image.lib") // 必要ファイル: // SDL2.dll // SDL2_image.dll // libpng16-16.dll // zlib1.dll int main(int argc, char* argv[]) { // これがないと IMG_Loadがnullptrを返す //SDL_Init(SDL_INIT_VIDEO); // PNG読むなら必要 //IMG_Init(IMG_INIT_PNG); // ↑の筈なんだが無くても動いたりする? ////////////////////////////// Uint32 rmask, gmask, bmask, amask; #if SDL_BYTEORDER == SDL_BIG_ENDIAN rmask = 0xff000000; gmask = 0x00ff0000; bmask = 0x0000ff00; amask = 0x000000ff; #else rmask = 0x000000ff; gmask = 0x0000ff00; bmask = 0x00ff0000; amask = 0xff000000; #endif ////////////////////////////// //■ レンダラ作成 SDL_Surface* surf_out = SDL_CreateRGBSurface(0, 500, 500, 32, rmask, gmask, bmask, amask); SDL_Renderer* rend_out = SDL_CreateSoftwareRenderer(surf_out); //////////////////////////// // 画像を読み込んでコピー SDL_Surface* surf_in = IMG_Load("C:\\test\\data\\a.png"); SDL_BlitSurface(surf_in, nullptr, surf_out, nullptr); SDL_FreeSurface(surf_in); //////////////////////////// // アルファブレンドの設定 SDL_SetRenderDrawBlendMode(rend_out, SDL_BLENDMODE_BLEND); ////////////////////////////// // 赤で直線 SDL_SetRenderDrawColor(rend_out, 255, 0, 0, 100); SDL_RenderDrawLine(rend_out, 50, 20, 500, 200); // ファイルに保存 //SDL_SaveBMP(surf_out, "out.bmp"); IMG_SavePNG(surf_out, "out.png"); ////////////////////////////// //■ レンダラ破棄 SDL_DestroyRenderer(rend_out); SDL_FreeSurface(surf_out); return 0; }
結果のサイズを500x500に設定しているのでクリップされている。
諸事情によりSDLライブラリ。
URL https://www.libsdl.org/download-2.0.php
ダウンロード SDL2-devel-2.0.18-VC.zip (Visual C++ 32/64-bit)
パス設定
include : SDL2-2.0.18\include
lib : SDL2-2.0.18\lib\x64
ウィンドウに画像を表示するサンプルばかりだったので、画像を作成してファイルに保存するサンプルにした。
SDL_CreateRGBSurface と SDL_CreateSoftwareRenderer を使う。
// このマクロを定義しないとエントリポイントが SDL_main になる #define SDL_MAIN_HANDLED #include <SDL.h> #pragma comment(lib,"SDL2.lib") // 必要ファイル: // SDL2.dll int main(int argc, char* argv[]) { ////////////////////////////// Uint32 rmask, gmask, bmask, amask; #if SDL_BYTEORDER == SDL_BIG_ENDIAN rmask = 0xff000000; gmask = 0x00ff0000; bmask = 0x0000ff00; amask = 0x000000ff; #else rmask = 0x000000ff; gmask = 0x0000ff00; bmask = 0x00ff0000; amask = 0xff000000; #endif ////////////////////////////// SDL_Surface* surf = SDL_CreateRGBSurface( 0, 256, 256, 32, rmask, gmask, bmask, amask); //■ レンダラ作成 SDL_Renderer* render = SDL_CreateSoftwareRenderer(surf); // アルファブレンドの設定 SDL_SetRenderDrawBlendMode(render, SDL_BLENDMODE_BLEND); ////////////////////////////// // 黒でクリア SDL_SetRenderDrawColor(render, 0, 0, 0, 255); SDL_RenderClear(render); ////////////////////////////// // 赤で直線 SDL_SetRenderDrawColor(render, 255, 0, 0, 150); SDL_RenderDrawLine(render, 50, 20, 500, 200); ////////////////////////////// // ファイルに保存 SDL_SaveBMP(surf, "out.bmp"); ////////////////////////////// //■ レンダラ破棄 SDL_DestroyRenderer(render); SDL_FreeSurface(surf); return 0; }
要素数が「最大N個」の配列が欲しい場合がある。std::vectorではnewでヒープに確保されるので重すぎる。std::arrayはスタックに確保できるがpush_backできない。
そんなわけで、push_backできるがスタックに置ける配列を考える。
#include<array> namespace szl { //! @brief 最大要素数が決まっている可変長配列 //! @tparam T arrayに入れるデータ型 //! @tparam MAX arrayの要素数 template<typename T, size_t MAX> class LimitedVector { std::array<T, MAX> _data; size_t count; //!< 現在の要素数 public: LimitedVector() :count(0) {} auto begin() { return _data.begin(); } auto end() { return _data.begin() + count; } const auto cbegin()const { return _data.cbegin(); } const auto cend()const { return _data.cbegin() + count; } void push_back(const T& v) { if (count >= MAX) throw "count >= MAX"; _data[count++] = v; } void pop_back() { if (count == 0) throw "count == 0"; count--; } T& back() { if (count == 0) throw "count == 0"; return _data[count - 1]; } const T& back()const { return _data[count - 1]; } const T* data()const { return _data; } T* data() { return _data; } size_t size()const { return count; } const T& operator[](const size_t index)const { return _data[index]; } T& operator[](const size_t index) { return _data[index]; } }; }
#include "LimitedVector.hpp" int main() { szl::LimitedVector<int, 3> v; v.push_back(3); v.push_back(4); v.push_back(6); printf("%d\n", v.size()); v[1] = 1; for (auto vv : v) { printf("-- %d\n", vv); } v.pop_back(); printf("-------\n"); for (auto vv : v) { printf("-- %d\n", vv); } }
実行例
windowsはいつの頃からか、ゴミ箱の中身のファイルサイズ合計が表示されなくなった。
知りたかったのでC++ + Win32APIでゴミ箱のファイル容量を取得してみる。
#include <iostream> #include <windows.h> #include <shellapi.h> // shell32.lib void GetRecycleBin(const char* drive = nullptr) { printf("\"%s\"\n", drive); SHQUERYRBINFO rbInfo = { sizeof(SHQUERYRBINFO) }; DWORDLONG i64MB; // ごみ箱の情報を取得する if (SHQueryRecycleBin(drive, &rbInfo) == S_OK) { i64MB = (rbInfo.i64Size / 1024 / 1024); printf("ファイルサイズ合計 :%I64u MiB\n", i64MB); printf("ファイル数合計 :%I64u 個\n", rbInfo.i64NumItems); } else { printf("ごみ箱の情報を取得できません。\n"); } printf("-----------------------\n"); } // メイン関数 int main(void) { GetRecycleBin("C:\\"); GetRecycleBin("H:\\"); GetRecycleBin(""); getchar(); return 0; }
"C:\"
ファイルサイズ合計 :1299 MiB
ファイル数合計 :114 個
-----------------------
"H:\"
ファイルサイズ合計 :6454 MiB
ファイル数合計 :739 個
-----------------------
""
ファイルサイズ合計 :7754 MiB
ファイル数合計 :853 個
-----------------------
bpy.app.handlers.frame_change_pre.appendに指定した関数がフレームが変わるたびに走る。
この例では、テキストオブジェクトに現在のフレーム数を代入している。
import bpy def frame_change_pre(scene): bpy.data.objects['Text'].data.body = str(scene.frame_current) bpy.app.handlers.frame_change_pre.append(frame_change_pre)
3x3のソーベルフィルタを実装する。
SobelFilter.hpp
#pragma once #include <valarray>
#include <array>
//! @brief ソーベルフィルタ //! @note フィルタを変えれば他の用途にも使える class SobelFilter { // フィルタサイズ 3x3 static constexpr int FilterSize = 3; std::array < std::array<int, FilterSize>, FilterSize > filterH; //!< 水平方向 std::array < std::array<int, FilterSize>, FilterSize > filterV; //!< 垂直方向 int m_width; //!< 入出力画像の幅 int m_height; //!< 入出力画像の高さ const unsigned char* m_pimg; //!< 元画像へのポインタ // -1 →(+1)→ 0 // 0 →(+1)→ 1 // 1 →(+1)→ 2 //! @brief 水平のフィルタを取得 int fH(const int x, const int y)const { return filterH[x + 1][y + 1]; } //! @brief 垂直のフィルタを取得 int fV(const int x, const int y)const { return filterV[x + 1][y + 1]; } public: //! @brief 一画素のサイズ。RGBで3バイト static constexpr int PixelSize = 3; using Vector3d = std::valarray<int>; //! @brief [in] w 画像幅 //! @brief [in] h 画像幅 //! @brief [in] pimg 元画像へのポインタ SobelFilter(int w, int h, const unsigned char* pimg) { //ソーベルフィルタ作成 filterH[0] = { -1, 0, 1 }; filterH[1] = { -2, 0, 2 }; filterH[2] = { -1, 0, 1 }; filterV[0] = { -1,-2,-1 }; filterV[1] = { 0, 0, 0 }; filterV[2] = { 1, 2, 1 }; // 画像へアクセスする諸々の設定 m_width = w; m_height = h; m_pimg = pimg; } //! @brief 元画像の(x,y)座標の画素を取得 Vector3d pixel(const int x, const int y) { const unsigned char* p = &m_pimg[(y * m_width + x) * PixelSize]; return Vector3d({ p[0], p[1], p[2] }); } // (x,y)座標のフィルタ後の値を取得 Vector3d get(const int x, const int y) { Vector3d tmp({ 0,0,0 }); std::array<Vector3d, FilterSize * 2> px;; std::fill(px.begin(), px.end(), Vector3d{ 0,0,0 }); //水平9画素についての合計 px[0] = pixel(x - 1, y - 1) * fH(-1, -1) + pixel(x , y - 1) * fH( 0, -1) + pixel(x + 1, y - 1) * fH( 1, -1); px[1] = pixel(x - 1, y) * fH(-1, 0) + pixel(x , y) * fH( 0, 0) + pixel(x + 1, y) * fH( 1, 0); px[2] = pixel(x - 1, y + 1) * fH(-1, 1) + pixel(x , y + 1) * fH( 0, 1) + pixel(x + 1, y + 1) * fH( 1, 1); //////////////////////////////////////////////// // 垂直9画素についての合計 px[3] = pixel(x - 1, y - 1) * fV(-1, -1) + pixel(x, y - 1) * fV(0, -1) + pixel(x + 1, y - 1) * fV(1, -1); px[4] = pixel(x - 1, y) * fV(-1, 0) + pixel(x, y) * fV(0, 0) + pixel(x + 1, y) * fV(1, 0); px[5] = pixel(x - 1, y + 1) * fV(-1, 1) + pixel(x, y + 1) * fV(0, 1) + pixel(x + 1, y + 1) * fV(1, 1); for (auto& k : px) { for (int i = 0; i < PixelSize; i++) { tmp[i] += k[i]; } } for (int i = 0; i < PixelSize; i++) { tmp[i] = (tmp[i] < 0) ? 0 : tmp[i]; tmp[i] = (tmp[i] > 255) ? 255 : tmp[i]; } return tmp; } };
//! @brief width 画像横画素数 //! @brief height 画像縦画素数 //! @param [in] pimg 入力画像 //! @param [out] dst 出力先 //! @return なし void sobel( const int width, const int height, const unsigned char* pimg, unsigned char* dst ) { SobelFilter sf(width, height, pimg); size_t sz = SobelFilter::PixelSize; for (int x = 1; x < width - 1; x++) { for (int y = 1; y < height - 1; y++) { SobelFilter::Vector3d px = sf.get(x, y); for (size_t p = 0; p < sz; p++) { dst[(y * width + x) * sz + p] = px[p]; } } } }
#include <iostream> #include <vector> #include "SobelFilter.hpp" #include "NByteData.hpp" // https://www.study.suzulang.com/2dcg-functions/nbyte-data-type #include "ppmP3_read.hpp" // https://www.study.suzulang.com/cppppm-readerwriter/ppm-p3-reader-cpp void ppmP3_write( const char* const fname, const int width, const int height, const unsigned char* const p, const int vmax );
int main() { int width; int height; int vmax; unsigned char* pimg; ppmP3_read("C:\\data\\b.ppm", &width, &height, &vmax, &pimg); std::vector<unsigned char> ret(width * height * 3); sobel(width, height, pimg, ret.data()); ppmP3_write("C:\\data\\sobel.ppm", width, height, ret.data(), 255); std::cout << "Hello World!\n"; }
//! @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); }
Gantry 5 にはcssではなくscssを指定する。
SCSSについての説明は、とりあえず極限まで簡略化すると、SCSSの文法はCSS+書きやすい新たな構文 という感じなので、ひとまず拡張子を.cssから.scssにするだけで良い。
説明を読むとcssも受け付けるというようなことを書いてあったのだが、試した限りだと上手くいかない。
そして、ファイル名を「custom.scss」とした上で、内容に以下の一行を記述する。
.scssに拡張子を変更する事に加え、ファイル名の先頭に_を加える
変更前:
変更後:
最初のステップで作成したcustom.scssファイルの次の行に、_と拡張子.scssを除いたスタイルの記述されたファイル名を指定する。
ここまでで、custom.scssの内容は以下のようになる。
custom.scssに、スタイルを記述したscssファイルを指定する。
テーマを見て、g5_heliumといったテーマ名を確認する。
以下のディレクトリへ、二つのscssファイルをアップロードする。
例えば、
scss/ディレクトリがない場合は自分で作成する。
アップロードが終わると、以下の構成になっている
www/mywebsite/templates/g5_helium/custom/scss/custom.scss
www/mywebsite/templates/g5_helium/custom/scss/_textcolor.scss
scssファイルはスタイルそのものではなく、「cssに近い文法で書ける、cssを生成するためのメタ言語であり、cssにコンパイルして使用する」。
なのでGantry 5 の設定画面でコンパイルする。
画面右、Extras→Clear Cacheでキャッシュをクリアする
Stylesの画面右、Recomple CSSをクリックする。
以下のディレクトリにテンプレートに使用する画像を入れるらしい。
How to add Custom CSS/SCSS in Gantry 5 Theme
https://www.rcatheme.com/documentation/gantry5/how-to-add-custom-css-scss-in-gantry5-theme
Creating Custom File Overrides
#pragma once #include <vector> #include<cassert> class Thermography { using InputColor = std::array<int, 3>; using CalcColor = std::array<double, 3>; using OutputColor = std::array<unsigned char, 3>; std::vector< InputColor > m_ctable; double m_dmin; double m_dmax; private: template<typename Return> Return clamp(Return _min, Return _max, double value) const { if (value < _min) return _min; if (value > _max) return _max; return value; } //! @brief 0.0~1.0 の範囲のRGBを取得 CalcColor calc(const int from, const double ratio)const { constexpr int R = 0, G = 1, B = 2; const int to = from + 1; double r = (m_ctable[from][R] + (m_ctable[to][R] - m_ctable[from][R]) * ratio) / 255.0; double g = (m_ctable[from][G] + (m_ctable[to][G] - m_ctable[from][G]) * ratio) / 255.0; double b = (m_ctable[from][B] + (m_ctable[to][B] - m_ctable[from][B]) * ratio) / 255.0; return CalcColor{r,g,b}; } //! @brief 0~255の範囲のRGBを取得 OutputColor toOutput(const CalcColor& cc)const { return OutputColor{ clamp<unsigned char>(0 ,255 ,cc[0] * 255), clamp<unsigned char>(0 ,255 ,cc[1] * 255), clamp<unsigned char>(0 ,255 ,cc[2] * 255) }; } public: // @brief カラーテーブルを設定する template<class It> void setColorTable(It first, It last) { for (auto c = first;c!= last;c++) m_ctable.push_back(*c); } // @brief カラーテーブルを設定する void setColorTable( std::initializer_list< InputColor > colors ) { setColorTable(colors.begin(), colors.end()); } // @brief 着色する値の範囲を設定 void setArea(double _min, double _max) { m_dmin = _min; m_dmax = _max; } //! @brief 値をRGB色へ変換 OutputColor thermography(const double value)const { constexpr int R = 0, G = 1, B = 2; int N = m_ctable.size(); // 値の正規化 double nvalue; double vwidth = m_dmax - m_dmin; nvalue = (value - m_dmin) / vwidth; int from, to; double ratio; ////////////////////////////// // 範囲外 if (nvalue <= 0.0) { from = 0; ratio = 0.0; } else if (nvalue >= 1.0) { from = m_ctable.size() - 2; ratio = 1.0; } ////////////////////////////// // 範囲内なら from ~ to の間で正規化してratioにする else { from = nvalue * (N - 1); to = from + 1; double NnFrom = from / double(N - 1); double NnTo = to / double(N - 1); ratio = (nvalue - NnFrom) / (NnTo - NnFrom); } CalcColor rgb = calc(from, ratio); return toOutput(rgb); } };
#include <iostream> // https://www.study.suzulang.com/2dcg-functions/nbyte-data-type #include "NByteData.hpp" #include "ppmP3_read.hpp" #include "thermography.h" #include <vector> #include <array> 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\\ppp.ppm", &width, &height, &vmax, [&mem](const size_t pixelcount) { mem.resize(pixelcount); return (unsigned char*)&mem[0]; } );
////////////////////////////////////////////// ////////////////////////////////////////////// std::vector< std::array<int, 3>> ColorTable{ std::array<int, 3>{ 0 , 0, 0 }, // 黒 std::array<int, 3>{ 0 , 0, 255}, // 青 std::array<int, 3>{ 0 ,200,200}, // 水色 std::array<int, 3>{ 0 ,255, 0 }, // 緑 std::array<int, 3>{200,200, 0 }, // 橙 std::array<int, 3>{255, 0 , 0 }, // 赤 std::array<int, 3>{255,255,255} // 白 }; Thermography c; c.setArea(0, 255);//この範囲外の値は0,255として扱われる c.setColorTable(ColorTable.begin(), ColorTable.end());
// 色を反転 for (auto& p : mem) { std::array<unsigned char,3> rgb = c.thermography(p.data()[0]); p.data()[0] = rgb[0]; p.data()[1] = rgb[1]; p.data()[2] = rgb[2]; p.data()[0] = (p.data()[0] > 255) ? 255 : p.data()[0]; p.data()[1] = (p.data()[1] > 255) ? 255 : p.data()[1]; p.data()[2] = (p.data()[2] > 255) ? 255 : p.data()[2]; } ///////////////////////////////// ///////////////////////////////// ppmP3_write( "C:\\test\\qqq.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); }
#include <iostream> // https://www.study.suzulang.com/2dcg-functions/nbyte-data-type #include "NByteData.hpp"
// https://suzulang.com/ppmp3_read-memalloc-ver/ #include "ppmP3_read.hpp" #include "thermography.h" #include <vector> #include <array> 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\\ppp.ppm", &width, &height, &vmax, [&mem](const size_t pixelcount) { mem.resize(pixelcount); return (unsigned char*)&mem[0]; } );
////////////////////////////////////////////// ////////////////////////////////////////////// std::vector< std::array<int, 3>> ColorTable{ std::array<int, 3>{ 0 , 0, 0 }, // 黒 std::array<int, 3>{ 0 , 0, 255}, // 青 std::array<int, 3>{ 0 ,200,200}, // 水色 std::array<int, 3>{ 0 ,255, 0 }, // 緑 std::array<int, 3>{200,200, 0 }, // 橙 std::array<int, 3>{255, 0 , 0 }, // 赤 std::array<int, 3>{255,255,255} // 白 }; Thermography c; c.setArea(0, 255);//この範囲外の値は0,255として扱われる c.setColorTable(ColorTable.begin(), ColorTable.end());
// 色を反転 for (auto& p : mem) { std::array<unsigned char,3> rgb = c.thermography(p.data()[0]); p.data()[0] = rgb[0]; p.data()[1] = rgb[1]; p.data()[2] = rgb[2]; p.data()[0] = (p.data()[0] > 255) ? 255 : p.data()[0]; p.data()[1] = (p.data()[1] > 255) ? 255 : p.data()[1]; p.data()[2] = (p.data()[2] > 255) ? 255 : p.data()[2]; } ///////////////////////////////// ///////////////////////////////// ppmP3_write( "C:\\test\\qqq.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); }
・さくらのレンタルサーバー
・Wordpress 5.9
WordPress 5.8 からwebpに正式対応している。にもかかわらずwebpファイルをアップロードできない問題に遭遇した。
より具体的に言うと、一枚画像は転送できるが、アニメーションwebpは転送できないという状況に遭遇した。
WordPressがWebPを使えるためには、サーバー側でImageMagickを有効にしていなければいけない。
さくらのレンタルサーバーの場合デフォルトでは無効になっているので、以下の手順で有効化する。
1.コントロールパネルへログイン
https://secure.sakura.ad.jp/rs/cp/
アニメーションgif版:17.5MB
webp版:210KB
In WordPress, the lossless WebP format is only supported when the hosting server uses Imagick (the PHP library) until LibGD adds support.
https://make.wordpress.org/core/2021/06/07/wordpress-5-8-adds-webp-support/