Symfoware

Symfowareについての考察blog

C# exeファイルに後から設定値を埋め込む手法の検討

プログラムで使用する何かしらの設定値を保存したい場合、
レジストリやiniファイルを使用することになると思います。

これだと、exeファイルだけコピーして別の端末で起動した時、設定値が失われてしまう。
なんとかコンパイル済のexeファイルに対して、後付で値を埋め込めないか試してみます。


最初のサンプルプログラム



文字列を出力する簡単なプログラムを作成します。

・test.cs


  1. using System;
  2. using System.IO;
  3. public class Test {
  4.         
  5.     [STAThread]
  6.     public static void Main(string[] args) {
  7.         Console.WriteLine("test");
  8.     }
  9. }




こんなバッチファイルを作成してコンパイルしました。

・build.bat


@echo off
set csc="C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe"
set opt=/nologo

%csc% %opt% /out:test.exe test.cs




出力されたtest.exeをメモ帳で開いてみると、xmlな文字列が確認できます。
735_01.png


この領域を使用して、定数値を保存できるのでは?






manifestの使用



コンパイルオプションに何も指定せずにビルドすると、
デフォルトのmanifestファイルが埋め込まれるようです。

/win32manifest (C# Compiler Options)

こちらを参考に、自分で作成したマニフェストファイルを指定してコンパイルしてみます。

・test.manifest


  1. <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  2. <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  3. <assemblyIdentity version="1.0.0.0" name="Test.app"/>
  4. <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
  5.     <security>
  6.      <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
  7.         <requestedExecutionLevel level="asInvoker" uiAccess="false"/>
  8.      </requestedPrivileges>
  9.     </security>
  10. </trustInfo>
  11. </assembly>





ビルド用のバッチファイルはこうなりました。

・build.bat


@echo off
set csc="C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe"
set opt=/nologo /win32manifest:test.manifest

%csc% %opt% /out:test.exe test.cs




出力されたexeを確認すると、指定したmanifestが埋め込まれたようです。

735_02.png





manifestにタグの追加



manifestに値を保存しておくためのタグを追加してみます。
今回はdescriptionというタグを追加しました。

・test.manifest


  1. <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  2. <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  3. <assemblyIdentity version="1.0.0.0" name="Test.app"/>
  4. <description>                             </description>
  5. <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
  6.     <security>
  7.      <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
  8.         <requestedExecutionLevel level="asInvoker" uiAccess="false"/>
  9.      </requestedPrivileges>
  10.     </security>
  11. </trustInfo>
  12. </assembly>




ポイントは、タグの内容に半角スペースをある程度含めておくことです。
ビルド後、exeのバイト数が変わると実行できなくなってしまうため、ある程度余白を設けておきます。

735_03.png


この領域に値を埋め込み、プログラムから読みだして使えば良さそうです。





値の埋め込みと読み取り



exeファイルを読み込み、descriptionタグの間に文字列を埋め込むプログラム。

・setting.cs


  1. using System;
  2. using System.IO;
  3. using System.Text;
  4. public class Test {
  5.         
  6.     [STAThread]
  7.     public static void Main(string[] args) {
  8.         
  9.         string param = args[0];
  10.         
  11.         // 元となるexeファイルの読み込み
  12.         byte[] binary = File.ReadAllBytes("test.exe");
  13.         
  14.         // descriptionタグの位置をバイナリデータから検索
  15.         int first = IndexOf("<description>", binary);
  16.         
  17.         if (first == -1) {
  18.             Console.WriteLine("descriptionタグが見つかりません。");
  19.             return;
  20.         }
  21.         
  22.         // <description>の文字数分インデックスをずらす
  23.         int binaryIndex = first + 13;
  24.         
  25.         // パラメーターの埋め込み
  26.         byte[] paramBytes = Encoding.ASCII.GetBytes(param);
  27.         for (int i = 0; i < paramBytes.Length; i++, binaryIndex++) {
  28.             binary[binaryIndex] = paramBytes[i];
  29.         }
  30.         
  31.         // パラメーターを埋め込んだexeファイル出力
  32.         File.WriteAllBytes("test_param.exe", binary);
  33.         
  34.     }
  35.     
  36.     private static int IndexOf(string target, byte[] binary) {
  37.         byte[] targetBytes = Encoding.ASCII.GetBytes(target);
  38.         
  39.         for (int i = 0; i < binary.Length - targetBytes.Length; i++) {
  40.             
  41.             bool allMatch = true;
  42.             for (int j = 0; j < targetBytes.Length; j++) {
  43.                 if (binary[i + j] != targetBytes[j]) {
  44.                     allMatch = false;
  45.                     break;
  46.                 }
  47.             }
  48.             
  49.             if (allMatch) {
  50.                 return i;
  51.             }
  52.             
  53.         }
  54.         
  55.         return -1;
  56.     }
  57. }




引数をdescriptionタグにtest.exeに埋め込み、test_param.exeとして出力します。


適当な値を埋め込んでみます。


> setting.exe test_value




出力されたtest_param.exeを見てみると、ちゃんと値が埋め込まれました。

735_04.png


test.exeを修正。埋め込まれた値を読み込めるようにします。


・test.cs


  1. using System;
  2. using System.IO;
  3. using System.Text.RegularExpressions;
  4. using System.Reflection;
  5. public class Test {
  6.         
  7.     [STAThread]
  8.     public static void Main(string[] args) {
  9.         
  10.         // 自分自身をファイルとして読み込み
  11.         var assembly = Assembly.GetExecutingAssembly();
  12.         string s;
  13.         using(StreamReader sr = new StreamReader(assembly.Location)) {
  14.             s = sr.ReadToEnd();
  15.         }
  16.         
  17.         // descriptionタグの内容を取得
  18.         Regex r = new Regex(@"<description>(.*?)</description>");
  19.         MatchCollection mc = r.Matches(s);
  20.         
  21.         string param = "";
  22.         foreach (Match m in mc) {
  23.             param = m.Groups[1].Value.Trim();
  24.         }
  25.         
  26.         if (string.IsNullOrEmpty(param)) {
  27.             Console.WriteLine("not found");
  28.             return;
  29.         }
  30.         
  31.         // 取得した値を出力
  32.         Console.WriteLine(param);
  33.         
  34.     }
  35. }





狙い通りの実行結果です。

735_05.png

テーマ:プログラミング - ジャンル:コンピュータ

  1. 2017/03/25(土) 17:55:36|
  2. 備忘録
  3. | トラックバック:0
  4. | コメント:0
  5. | 編集

FreeBSD 11 rootのssh接続の有効化

FreeBSD 11を仮想環境にインストールしました。
FreeBSD 11.0-RELEASEを仮想環境(UbuntuのKVM)にインストール

別の端末からrootでssh接続できるように変更します。



sshd_configの編集



sshの設定ファイル/etc/ssh/sshd_configを適当なエディタで開きます。
今回はviを使用しました。


vi /etc/ssh/sshd_config




設定ファイル中、


#PermitRootLogin no



となっている箇所を探します。
先頭のコメント「#」を削除して、noをyesに変更。


PermitRootLogin yes




ファイルを保存したら、sshdサービスを再起動。


/etc/rc.d/sshd restart




これで別の端末からrootでssh接続できるようになりました。

テーマ:サーバ - ジャンル:コンピュータ

  1. 2017/03/20(月) 15:51:20|
  2. 備忘録
  3. | トラックバック:0
  4. | コメント:0
  5. | 編集

FreeBSD 11.0-RELEASEを仮想環境(UbuntuのKVM)にインストール

FreeBSD 11.0-RELEASEをインストールする手順をメモしておきます。

過去の記事を参考にしました。
FreeBSD 10.0-RELEASEを仮想環境(UbuntuのKVM)にインストールする



インストーラーの取得



こちらからインストーラーを取得します。
https://www.freebsd.org/ja/where.html

733_01.png

733_02.png


FreeBSD-11.0-RELEASE-amd64-bootonly.isoをダウンロードしてきます。




仮想OSの作成



virt-managerから新しい仮想マシンの作成を実行。
以下、スクリーンショットを貼り付けておきます。

733_03.png


ダウンロードしたisoイメージを指定。

733_04.png

733_05.png


仮想ディスクのフォーマットはデフォルトの「qcow2」を選択しました。

733_06.png

733_07.png

733_08.png

以前はパフォーマンスオプションを変更しないとディスクのIOが遅かったのですが、
Ubuntu 16.04 + KVMでは解消されているようです。

こちらの手順は不要でした。
Ubuntu KVM上のFreeBSDのインストールが遅い場合の解決方法






インストール



実際のインストール手順です。
インストーラーが起動したら、そのままエンターキーを押下。

733_09.png


Installが選択されている状態でエンター。

733_10.png


キーボードレイアウトの選択です。
「Japanese 106」を選択してエンターキーを押下。

733_11.png


一番上の「Continue with jp.106.kbd keymap」を選択してエンター。

733_12.png


ホスト名を適当に入力します。
今回は「freebsd11」としました。

733_13.png


インストールオプションは、デフォルトの「lib32」「ports」が選択された状態でOK。

733_14.png


続いてネットワークの設定です。

733_15.png

733_16.png


IPv4の設定を有効化。

733_17.png


固定IPを指定したかったので、DHPCの使用はNoを選択しました。

733_18.png


IPアドレス、サブネット、デフォルトゲートウェイを入力します。

733_19.png


IPv6の設定を行うかの選択肢です。
今回は使用しないため、Noを選択しました。

733_20.png


DNSサーバーのIPアドレスを指定します。

733_21.png


ダウンロードサイトを選択します。
「ftp://ftp2.jp.frebsd.org」を選択しました。

733_22.png


パーティションの設定です。
今回はZFSにしてみます。

733_23.png


ZFSの設定はデフォルトです。

733_24.png

733_25.png


今回は1つですが、使用するディスクにチェックをつけます。
(選択状態でスペース押下)

733_26.png

733_27.png


Yesを選択してZFSパーティションの内容を確定します。

733_28.png


インストールが始まりました。

733_29.png


途中でrootのパスワードを尋ねられます。
適当にパスワードを2回入力します。

733_30.png


続いてタイムゾーンの指定です。
5 Asiaを選択。

733_31.png


その後、18 Japanを選択。

733_32.png


JSTで良いかの確認です。Yesで確定します。

733_33.png


日付と時刻の設定画面が表示されますが、両方Skipしました。

733_34.png

733_35.png


インストールするサービスはデフォルトの「sshd」「dumpdev」を選択。

733_36.png

733_37.png


root以外のユーザーを追加するかの確認です。
特に追加しないのでNoを選択。

733_38.png


最後にExitを選択してインストーラーを終了します。

733_39.png


手動で設定ファイルを編集するかの確認です。
編集しないのでNoを選択。

733_40.png


Rebootで再起動を実行します。

733_41.png


これでインストール完了です。

再起動後loginプロンプトが表示されたら

login: root
Password: (インストール中入力したパスワード)

を入力します。

733_42.png


無事ログインできました。

733_43.png

テーマ:サーバ - ジャンル:コンピュータ

  1. 2017/03/20(月) 15:34:44|
  2. 備忘録
  3. | トラックバック:0
  4. | コメント:0
  5. | 編集

HTML5 canvasで画像の矩形選択(clip)

画像の一部を矩形で範囲選択したく、Jcropを使おうとしたのですが、
開発も滞っており、jQueryの最新版(3系)では動きませんでした。

せっかくなので、jQueryプラグインを使用せず、
HTML5 canvasだけで実装できるか試してみます。


やりたいこと



こんな感じで、画像の一部をマウス操作で矩形選択したい。
730_01.png

※ネコの画像はこちらから引用しています。
Pixabay


こちらを参考にさせていただきました。
HTML5 canvasを使った矩形選択と選択範囲塗りつぶし


作成したサンプルはこちら。
rect select

ソースはこんな感じになります。


  1. <!DOCTYPE html>
  2. <html lang="ja">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <title>rect select</title>
  6. <script type="text/javascript">
  7. window.onload = function() {
  8.     var canvas = document.getElementById('drowing');
  9.     var context = canvas.getContext('2d');
  10.     var reacts = [];
  11.     
  12.     var imageObj = new Image();
  13.     imageObj.onload = function() {
  14.         canvas.width = imageObj.width;
  15.         canvas.height = imageObj.height;
  16.         draw();
  17.     };
  18.     imageObj.src = 'sample2_image.jpg';
  19.     
  20.     canvas.addEventListener("mousedown", onMouseDown, false);
  21.     canvas.addEventListener("mouseup" , onMouseUp , false);
  22.     window.addEventListener("keyup" , onKeyUp , false);
  23.     
  24.     // 矩形オブジェクト
  25.     var _rectangle = createRect();
  26.     
  27.     function createRect() {
  28.         return { startY:0, startX:0, endY:0, endX:0 };
  29.     };
  30.     
  31.     function onMouseDown (e) {
  32.         _rectangle.startY = e.clientY;
  33.         _rectangle.startX = e.clientX;
  34.         canvas.addEventListener ("mousemove", onMouseMove, false);
  35.     };
  36.     function onMouseMove (e) {
  37.         draw();
  38.         _rectangle.endY = e.layerY - _rectangle.startY;
  39.         _rectangle.endX = e.layerX - _rectangle.startX;
  40.         context.lineWidth = 5;
  41.         context.strokeStyle = "rgb(255, 0, 0)";
  42.         context.strokeRect (_rectangle.startX, _rectangle.startY, _rectangle.endX, _rectangle.endY);
  43.     };
  44.     function onMouseUp (e) {
  45.         reacts.push(_rectangle);
  46.         draw();
  47.         _rectangle = createRect();
  48.         canvas.removeEventListener ("mousemove", onMouseMove, false);
  49.     };
  50.     
  51.     function draw() {
  52.         context.drawImage(imageObj, 0, 0);
  53.         context.lineWidth = 5;
  54.         context.strokeStyle = "rgb(255, 0, 0)";
  55.         reacts.forEach(function(rect) {
  56.             context.strokeRect(rect.startX, rect.startY, rect.endX, rect.endY);
  57.         });
  58.     };
  59.     
  60.     function onKeyUp (e) {
  61.         switch(e.key) {
  62.             case 'z':
  63.                 reacts.pop();
  64.                 break;
  65.             default:
  66.                 return;
  67.         };
  68.         draw();
  69.     };
  70.     
  71. };
  72. </script>
  73.     
  74. </head>
  75. <body>
  76.     <div class="main">
  77.         <canvas id="drowing" class="drowing" width="0" height="0"></canvas>
  78.     </div>
  79.     <div>
  80.         <div>zキーで最新の矩形を削除</div>
  81.     </div>
  82. </body>
  83. </html>




canvasを二枚重ねても良かったのですが、制御が面倒だったので
毎回背景画像を描画しなおしてから、矩形を重ねています。

シビアな性能が求められる場合は一考の余地ありですが、
とりあえずの実装であればこれで十分そうです。

テーマ:プログラミング - ジャンル:コンピュータ

  1. 2017/01/26(木) 23:33:47|
  2. 備忘録
  3. | トラックバック:0
  4. | コメント:0
  5. | 編集

avconv jpg画像と音声ファイルから動画(mp4)を作成

avconv(ffmpeg)を使用して、動画から画像ファイル(jpg)と音声ファイル(aac,mp3)を抽出しました。
avconv(ffmpeg)でmp4の動画ファイルからjpg形式で画像を取り出す
avconv(ffmpeg) 動画ファイルから音声ファイルのみ抽出(aac,mp3)

出力した画像・音声を合成し、再度動画ファイルを作成してみます。





画像・音声の分割



復習として、画像と音声ファイルの抽出を行います。

・画像

target.mp4という動画ファイルからjpg画像を連番で出力


# avconv -i target.mp4 -vsync 1 -r 25 -an -y -qscale 1 image/out_%04d.jpg




1分程度の動画ファイルから1,715枚のjpg画像が抽出出来ました。



・音声

aac形式で音声ファイルを抽出します。


# avconv -i target.mp4 -c:a copy -vn -y out.aac




これで、imageフォルダに動画ファイルから抽出した画像、
out.aacに音声ファイルが取得できました。






動画・音声の結合



まず、画像を結合してmov形式の動画ファイルを作成します。


# avconv -framerate 25 -f image2 -i image/out_%04d.jpg -c:v h264 -crf 1 no_sound.mov




これで音声の入っていない動画ファイル「no_sound.mov」ができました。
これに音声を付与しつつ、mp4形式に変換します。


# avconv -i no_sound.mov -i out.aac -c:v libx264 -strict experimental result.mp4




ここで、「-strict experimental」オプションを指定していないと、

encoder 'aac' is experimental and might produce bad results.
Add '-strict experimental' if you want to use it.

というエラーが発生します。


この手順で、「result.mp4」という動画ファイルに復元できました。
※ファイルサイズは大きくなってしまいましたが。





【参考URL】

Snippets avconv
avconv Documentation
Convert from .mov to .mp4 (or h264) using avconv
avconvコマンドでtsファイルを分割(split)
Unixでwmvファイルを他のファイルフォーマットに変換したい

テーマ:サーバ - ジャンル:コンピュータ

  1. 2017/01/25(水) 00:33:29|
  2. 備忘録
  3. | トラックバック:0
  4. | コメント:0
  5. | 編集
次のページ