ドナドナされるプログラマのメモ

Windows用アプリのプログラミングメモ

MFCを使う場合の多言語化

MFCを使う場合の多言語化メモ。以下の英語版より抜粋。

docs.microsoft.com

マイクロソフトによると、言語ごとのリソースはリソース専用DLLに格納すればいいらしい。そうすると、以下の順番でリソースの読み込みにチャレンジしてくれる。

  1. GetUserDefaultUILanguage() が返す、現在のユーザーにおけるデフォルトUI言語。
  2. 現在のユーザーにおけるデフォルトUI言語から副言語設定を削除したもの。例:ENC(カナダ英語)⇒ENU(アメリカ英語)。

  3. GetSystemDefaultUILanguage() が返す、現在のシステムUIのデフォルト言語。

  4. システムUIのデフォルト言語から副言語設定を削除したもの。

  5. 言語コード:LOC。

  6. アプリ内部のリソース

この自動読み込みをするために、リソース専用DLLの名前は以下の命名規則に従う必要がある。

[アプリケーション名][言語コード].dll

ここで言語コードは3桁のアルファベットである。このコードは残念ながらマイクロソフト固有のものであり、ISO639とは無関係であることに注意。対応の一覧は例えば以下に記載のコードで取得できる。

docs.microsoft.com

マイクロソフト公式からは、なぜか一覧を入手できないが、たとえば以下の非マイクロソフトサイトから入手できる。

Language and country codes (ISO IETF RFC .NET LCID) - table

リソース専用DLLについては、以下のMSDNにて述べられている。

英語版:

docs.microsoft.com

これについては、日本語への翻訳が正しくできている気がする。なので、リソースのみのDLLの作り方は以下を参照すること。

日本語版:リソースのみの DLL の作成 | Microsoft Docs

 

mozjpegをつかった画像変換ソフトの開発 その2

cjpegで設定可能なオプションは色々あるが、互いに排他的なものも結構ある。しかし、どれがそうなのかは明示されていない。そこでcjpeg.cを読んで整理してみた。Groupに番号が振ってあるものは、同じ番号内で相互に影響を及ぼすもの。

Option variables       Group
-quality qualityarg        
-grayscale jpeg_set_colorspace()       1
-rgb jpeg_set_colorspace()       1
-optimize cinfo->optimize_coding        
-progressive simple_progressive       2
-baseline force_baseline simple_progressive cinfo->num_scans cinfo->scan_info 2
-targa is_targa        
-revert JINT_COMPRESS_PROFILE        
-fastcrush JBOOLEAN_OPTIMIZE_SCANS        
-dc-scan-op JINT_DC_SCAN_OPT_MODE        
-notrellis JBOOLEAN_TRELLIS_QUANT        
-trellis-dc JBOOLEAN_TRELLIS_QUANT_DC       3
-notrellis-dc JBOOLEAN_TRELLIS_QUANT_DC       3
-tune-psnr JINT_BASE_QUANT_TBL_IDX JFLOAT_LAMBDA_LOG_SCALE1 JFLOAT_LAMBDA_LOG_SCALE2 JBOOLEAN_USE_LAMBDA_WEIGHT_TBL 4
-tune-hvs-psnr JINT_BASE_QUANT_TBL_IDX JFLOAT_LAMBDA_LOG_SCALE1 JFLOAT_LAMBDA_LOG_SCALE2 JBOOLEAN_USE_LAMBDA_WEIGHT_TBL 4
-tune-ssim JINT_BASE_QUANT_TBL_IDX JFLOAT_LAMBDA_LOG_SCALE1 JFLOAT_LAMBDA_LOG_SCALE2 JBOOLEAN_USE_LAMBDA_WEIGHT_TBL 4
-tune-ms-ssim JINT_BASE_QUANT_TBL_IDX JFLOAT_LAMBDA_LOG_SCALE1 JFLOAT_LAMBDA_LOG_SCALE2 JBOOLEAN_USE_LAMBDA_WEIGHT_TBL 4
-noovershoot JBOOLEAN_OVERSHOOT_DERINGING        
-nojfif write_JFIF_header        
-dct cinfo->dct_method        
-quant-baseline force_baseline       2
-quant-table JINT_BASE_QUANT_TBL_IDX       4
-icc icc_filename        
-restart cinfo->restart_interval cinfo->restart_in_rows      
-smooth cinfo->smoothing_factor        
-maxmemory cinfo->mem->max_memory_to_use        
-outfile outfilename        
-memdst memdst        
-verbose printed_version cinfo->err->trace_level      
-version          
-qtables qtablefile        
-qslots qslotsarg        
-sample samplearg        
-scans scansarg        

整理するだけで1時間かかってしまった。でも、これでGUIを正しく挙動させることができそうだ。

mozjpegをつかった画像変換ソフトの開発 その1

mozjpegを使ったwindows用の画像変換ソフトで、以下を満たすものを探したが見つからなかった。

  • Windows
  • GUI
  • 複数の画像ファイルを一括変換
  • 入力ファイルはJPEG, PNG, GIF, BMP
  • マルチスレッドにより複数同時圧縮

無いなら作ればいいじゃん、ということで開発に着手。開発方針は

  • 見た目は普通、Vectorでの公開を目標に
  • 中身は手抜き
  • 2日で完成

ソフトウェアの要件は

  • Windows
  • GUIベース
  • 開発言語はC++
  • MFCを使用
  • 入力ファイルタイプはjpeg, png, gif, bmp
  • 出力ファイルタイプはjpeg
  • 出力にはmozjpegを使用
  • 出力オプションはmozjpegに準拠
  • 複数のファイルをドラッグ&ドロップにより入力可能
  • 入力がjpegだった場合、上書き保存にも対応
  • 変換はマルチスレッドにより複数同時実行可能
  • GUIサイズは1024×768以下
  • jpeg関連ライブラリはスタティック(dllはセキュリティ対策がめんどい)
  • 変換設定の保存、呼び出し、初期化が可能
  • mozjpegの出力オプションは、一般的な変換設定と高度な設定に分割する

こんなところか。

mozjpegのwindows用ビルドにチャレンジ

mozjpegのwindows用ビルドにチャレンジしてみた。

mozjpegはmozillaが開発している、libjpegおよびlibjpeg-turbo互換のJPEG画像処理ライブラリ。圧縮率と画質の両立を目指して開発されている。

github.com

ちょっと手元にある大量のpngファイルを纏めてjpegにしたくなったのだが、このライブラリを使ってそのような処理をしてくれるソフトは無いようだ。ということで作ってみることにした。一番の難所はmozjpegのビルドっぽかったので、本記事はビルドに特化した。

まず、用意したもの。

  • Visual Studio 2019 Community Version 16.4.2
  • CMake Version 3.16.3
  • yasm Version 1.3.0 (SIMD命令を使うバイナリを作るために必要。使わない設定なら不要?)

JPEG圧縮演算のボトルネックはDCT(離散コサイン変換)らしい。んで、これを高速化するアプローチの一つに、それに適したCPUの命令(SIMD)を使う手がある。mozjpegのCMAKEデフォルト設定ではSIMDをサポートするCPUならSIMDを使うことになっているんだけど、そのためにはSIMD命令の書かれたコードをアセンブルできる必要がある。それがYASMやNASMらしい。これが入っていないと、「No CMAKE_ASM_NASM_COMPILER could be found.」って怒られてしまう。対策は、NASMやYASMを入れるか、CMAKEの「WITH_SIMD」のチェックを外せばよい。

自分の環境にはYASM等は入っていなかったので、まずはWITH_SIMDのチェックを外してチャレンジ。特段の問題もなくプロジェクトが生成され、ビルドも成功。

次にYASMを導入してみた。

Visual Studio 2019へYASMを導入するバッチファイルが、以下のGitHubプロジェクトにて公開されていたので活用させてもらった。

github.com

動作としては、Visual Studioのインストール先を調べるMicrosoft製のソフトウェアvswhere.exeを使ってインストールされているバージョンを判別し、バージョンに応じた適切な場所にYASMやその設定ファイルをコピーする。また、これらに必要なvswhereや適切なYASMのダウンロードをする。という内容になっている。

バッチファイルを見ると、頭の方にYASMやvswhereのバージョンを指定する場所があるのでこれを書き換え、管理者権限で実行(通常、yasmのコピー先は管理者権限が必要なprogram files以下である)すればインストールできる。

vswhereのバージョンは以下のGitHubプロジェクトにて確認する。

github.com

最後に、pathにYASMコピー先を追加する。今回の例では、C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VCだった。

以上より、無事ビルド環境を構築することができた。なお、まだエラーが出る人はうっかり「PNG_SUPPORTED」にチェックをいれてしまっていないか確認すること。

 

2020/12/23追記:

MozJpegによる画像処理をマルチスレッドで実行するWindowsアプリを作成した。

donadona.hatenablog.jp

現在の最新版はVersion 1.2。

donadona.hatenablog.jp

枕木の自動配置 2

枕木の自動配置だけど、上下方向にレールを曲げる場合はレールの中心と枕木の中心がずれているせいで工夫が必要になってしまうのか。ということは、対策は以下のいずれかかなあ。

  1. 中心を一致させる
  2. ずれの分補正する
  3. ずれを考慮した計算にする

さて、どれが楽なのやら。中心を一致させるのが一番に見えるけど、枕木の傾きを変える際に位置も同時にずれちゃうからNGっぽいのよね。

・・いや、問題ないのか?よくわからないな。今度図を書いて整理してみよう。

枕木の自動配置

  •  背景
  • スクリプトの仕様
    • 概略仕様
    • 詳細仕様
      • RailroadTiePosition
  • 覚えたことのメモ

 背景

嫌なことに気づいてしまった。勾配ごとに枕木の本数が決まっているということは、曲線レールや直線レールも勾配ごとに枕木の本数が違うということか。直線なら3パターン、曲線なら2パターン。今までは手計算&手動配置でやっていたけど、これは無理だ。何らかの自動化をしないと、面倒な作業が増え続けてしまう。

自動化方法は、3パターンぐらいは思いつく。

  1. Unity上にマップエディタを構築し、レールを置いたときに枕木を自動配置する。
    いつかはやりたいけど、あまりにも工数が多い。しかも、ヤードのシミュレーションという本題からも外れている。
  2. Unity上のスクリプトにより、指定のレールに対し枕木を自動配置する。
    工数はそんなに多くなさそう。Runしていない状態でモデル情報をいじる必要がある。
  3. SketchUp!上のスクリプトにより、指定のレールに対し枕木を自動配置する。
    工数はそんなに多くなさそう。Rubyを学ぶ必要がある。

2.のRunしていない状態でモデル情報をいじるのは将来必要な技術な感じがするけど、Rubyの難易度は低そうだし今回は3.で行ってみることにする。

続きを読む

30kg 10mレールメモ

30kg 10mのレールモデルを作ろうと思ったが、枕木本数の情報などがない。仕方ないので、20mのデータから任意長さのレールについて枕木本数と枕木間隔を求めるスプレッドシートを作った。

枕木本数の計算

枕木本数は、レール長さに比例すると仮定した。なお、枕木あたりの荷重が20mの場合未満となるように小数点以下繰り上げとした。10mの場合の本数を以下に示す。

表 枕木の本数 (レール長10mの場合)

長さ 10 m
線路の形状 丙線 簡易線
基本 13 13
半径≧400m 15 13
勾配≦30‰ 15 13
半径<400mまたは勾配>30‰ 16 15

枕木間隔の計算

  • 軌条継目における枕木間隔(A)
    25mでも20mでも枕木本数に関係なく380mmだったため、本計算でも380mm固定とした。
  • (A)の隣の間隔(B)、中間枕木の間隔(C)の性質
    25m, 20mのデータより、(C)は10mmの倍数であることと、(B)<(C)、(B)は理論値より3mm大きいことが読み取れた。そこで、それぞれ以下のように定めた。
  • 中間枕木の間隔(C)
    関数ceiling(a, b)を、「a以上の最も小さいbの倍数を求める関数」(例:ceiling(114.8, 10)=120)とすると、
    (C)= ceiling((レール長-(A))/(枕木本数-1),10)
  • (A)の隣の間隔(B)
    (B)= (レール長-(A)-(C)*(枕木本数-3))/2+3

10mの場合の計算例を以下に示す。

表 枕木間隔(10mレールの場合)

長さ 10 m    
枕木配置数 13 13 15 16
軌条継ぎ目における間隔 (A) 380 380 380 380
(A)の隣の間隔 763 763 673 588
上記以外 (=中間枕木) の間隔 810 810 690 650