Symfoware

Symfowareについての考察blog

winstoneでお手軽にpure javaなwebサーバーを起動する

RiotなどJavaScriptのプログラムを試して見るとき、手元で簡単に起動できる
webサーバーが欲しくなります。

例えばこういうサンプル。
Riot js 書籍ビューワー風なサンプルプログラム

今はPythonやPHPのデバッグサーバーを使用しています。

・Python


$ python3 -m http.server




・PHP


$ php -S localhost:8000




PythonやPHPはインストールされていないが、Javaはインストールされている環境で
同様のことが行えないか悩んでいる時、ふとwinstoneを思い出しました。

http://winstone.sourceforge.net/




winstone.jar



こちらを参考に、Maven リポジトリからjarファイルを取得します。
Winstone、最近、更新無い・・・


winstone-4.1.jarをダウンロードしました。
http://repo.jenkins-ci.org/public/org/jenkins-ci/winstone/

2.1MBと軽量です。



起動



とりあえずwinstone-4.1.jarを配置したディレクトリをそのまま公開するには、


$ java -jar winstone-4.1.jar --webroot=




--webroot=に値を設定せずに実行すると、カレントディレクトリがwebrootになります。

825_01.png


これは便利。



Javaプログラムから起動



コマンドではなくJavaプログラムから起動したい場合のサンプルです。


  1. import java.util.HashMap;
  2. import java.util.Map;
  3. import winstone.Launcher;
  4. public class MainProcess {
  5.     public static void main(String... args) throws Exception {
  6.         Map<String, String> prop = new HashMap<String, String>();
  7.         prop.put("webroot", "");
  8.         prop.put("httpPort", "8080");
  9.         final Launcher winstone = new Launcher(prop);
  10.         Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
  11.             public void run() {
  12.                 winstone.shutdown();
  13.             }
  14.         }));
  15.     }
  16. }



Launcherを使用することで、お手軽にwebサーバーが起動できます。



【参考URL】

http://winstone.sourceforge.net/
Winstone、最近、更新無い・・・
軽量サーブレットコンテナ winstone を開発用にサクッと使う

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

  1. 2018/02/03(土) 17:44:09|
  2. Java
  3. | トラックバック:0
  4. | コメント:0
  5. | 編集

Java 同梱のScriptEngineを利用したJSON文字列のエンコード、デコード

Javaでライブラリを使わずに簡単なJSON文字列のエンコード、デコードが出来ないか。
ScriptEngineを使って実現可能か試してみます。

OpenJDK 1.8で動作を確認しています。



デコード



JSON文字列からJavaオブジェクトへの変換を試してみます。


  1. import java.util.Map;
  2. import javax.script.ScriptEngine;
  3. import javax.script.ScriptEngineManager;
  4. import jdk.nashorn.api.scripting.ScriptObjectMirror;
  5. public class MainProcess {
  6.     public static void main(String... args) throws Exception {
  7.         
  8.         ScriptEngineManager manager = new ScriptEngineManager();
  9.         ScriptEngine engine = manager.getEngineByName("javascript");
  10.         
  11.         // デコードするjson文字列
  12.         String json = "{\"result\":true, \"count\":42, \"name\":\"Symfoware\", \"list\":[1,2,3], \"map\":{\"key\":\"value\"}}";
  13.         
  14.         // JSON.parseの実行結果を得る
  15.         Object result = engine.eval("JSON.parse('" + json + "')");
  16.         
  17.         if (!(result instanceof Map)) {
  18.             System.out.println("not map");
  19.             return;
  20.         }
  21.         
  22.         // mapに変換
  23.         Map<?, ?> m = (Map<?, ?>)result;
  24.         
  25.         // Boolean
  26.         System.out.println(m.get("result"));
  27.         if (m.get("result") instanceof Boolean) {
  28.             System.out.println("result is Boolean");
  29.         }
  30.         
  31.         // Integer
  32.         System.out.println("-----");
  33.         System.out.println(m.get("count"));
  34.         if (m.get("count") instanceof Integer) {
  35.             System.out.println("count is Integer");
  36.         }
  37.         
  38.         // String
  39.         System.out.println("-----");
  40.         System.out.println(m.get("name"));
  41.         if (m.get("name") instanceof String) {
  42.             System.out.println("name is String");
  43.         }
  44.         
  45.         // Array
  46.         System.out.println("-----");
  47.         ScriptObjectMirror mirror = (ScriptObjectMirror)m.get("list");
  48.         System.out.println(mirror.isArray());
  49.         Integer[] list = mirror.to(Integer[].class);
  50.         for(Integer v : list) {
  51.             System.out.println(v);
  52.         }
  53.         
  54.         
  55.         // Map
  56.         System.out.println("-----");
  57.         ScriptObjectMirror mirror2 = (ScriptObjectMirror)m.get("map");
  58.         System.out.println(mirror2.isArray());
  59.         Map<?, ?> map = (Map<?, ?>)m.get("map");
  60.         for(Map.Entry<?, ?> entry : map.entrySet()) {
  61.             System.out.println(entry.getKey());
  62.             System.out.println(entry.getValue());
  63.         }
  64.     }
  65.     
  66.     
  67. }




実行結果


true
result is Boolean
-----
42
count is Integer
-----
Symfoware
name is String
-----
true
1
2
3
-----
false
key
value




データ型も判定で来てるし、いい感です。
リストを変換する時がちょっと癖があって
ScriptObjectMirrorのtoを使用してやります。

ScriptObjectMirror mirror = (ScriptObjectMirror)m.get("list");
Integer[] list = mirror.to(Integer[].class);




callMember



https://codereview.stackexchange.com/questions/91184/java-json-stringifier-with-the-nashorn-api
JavaScriptの関数をcallMemberでJavaの世界に持ってこれるようです。

こちらのほうがすっきりしていますね。


  1. import java.util.Map;
  2. import javax.script.ScriptEngine;
  3. import javax.script.ScriptEngineManager;
  4. import jdk.nashorn.api.scripting.ScriptObjectMirror;
  5. public class MainProcess {
  6.     public static void main(String... args) throws Exception {
  7.         
  8.         ScriptEngineManager manager = new ScriptEngineManager();
  9.         ScriptEngine engine = manager.getEngineByName("javascript");
  10.         
  11.         // デコードするjson文字列
  12.         String jsonString = "{\"result\":true, \"count\":42, \"name\":\"Symfoware\", \"list\":[1,2,3], \"map\":{\"key\":\"value\"}}";
  13.         
  14.         // JSON.parseの実行結果を得る
  15.         ScriptObjectMirror json = (ScriptObjectMirror) engine.eval("JSON");
  16.         Object result = json.callMember("parse", jsonString);
  17.         
  18.         if (!(result instanceof Map)) {
  19.             System.out.println("not map");
  20.             return;
  21.         }
  22.         
  23.         // mapに変換
  24.         Map<?, ?> m = (Map<?, ?>)result;
  25.         
  26.         // Boolean
  27.         System.out.println(m.get("result"));
  28.         if (m.get("result") instanceof Boolean) {
  29.             System.out.println("result is Boolean");
  30.         }
  31.         
  32.         // Integer
  33.         System.out.println("-----");
  34.         System.out.println(m.get("count"));
  35.         if (m.get("count") instanceof Integer) {
  36.             System.out.println("count is Integer");
  37.         }
  38.         
  39.         // String
  40.         System.out.println("-----");
  41.         System.out.println(m.get("name"));
  42.         if (m.get("name") instanceof String) {
  43.             System.out.println("name is String");
  44.         }
  45.         
  46.         // Array
  47.         System.out.println("-----");
  48.         ScriptObjectMirror mirror = (ScriptObjectMirror)m.get("list");
  49.         System.out.println(mirror.isArray());
  50.         Integer[] list = mirror.to(Integer[].class);
  51.         for(Integer v : list) {
  52.             System.out.println(v);
  53.         }
  54.         
  55.         
  56.         // Map
  57.         System.out.println("-----");
  58.         ScriptObjectMirror mirror2 = (ScriptObjectMirror)m.get("map");
  59.         System.out.println(mirror2.isArray());
  60.         Map<?, ?> map = (Map<?, ?>)m.get("map");
  61.         for(Map.Entry<?, ?> entry : map.entrySet()) {
  62.             System.out.println(entry.getKey());
  63.             System.out.println(entry.getValue());
  64.         }
  65.     }
  66.     
  67.     
  68. }







エンコード



JavaオブジェクトをJSONにデコードする方法がわからず苦労しました。
普通にJavaオブジェクトをJSON.stringifyに渡してもうまく行きません。

以下は変換に失敗するコードです。


  1. import java.util.HashMap;
  2. import java.util.Map;
  3. import javax.script.ScriptEngine;
  4. import javax.script.ScriptEngineManager;
  5. import jdk.nashorn.api.scripting.ScriptObjectMirror;
  6. public class MainProcess {
  7.     public static void main(String... args) throws Exception {
  8.         
  9.         ScriptEngineManager manager = new ScriptEngineManager();
  10.         ScriptEngine engine = manager.getEngineByName("javascript");
  11.         
  12.         // エンコードするJavaオブジェクト
  13.         Map<Object, Object> m = new HashMap<>();
  14.         m.put("result", true);
  15.         m.put("count", 42);
  16.         m.put("name", "Symfoware");
  17.         m.put("list", new int[]{1, 2, 3});
  18.         
  19.         Map<String, String> map = new HashMap<>();
  20.         map.put("key", "value");
  21.         m.put("map", map);
  22.         
  23.         ScriptObjectMirror json = (ScriptObjectMirror) engine.eval("JSON");
  24.         Object result = json.callMember("stringify", m);
  25.         System.out.println(result);
  26.     }
  27.     
  28. }




実行結果


undefined




JSON.stringifyの引数に指定するのは、javascriptエンジンが解釈可能なオブジェクト
「ScriptObjectMirror」でなくてはいけません。

試行錯誤しながら、こんなコードで変換できました。


  1. import javax.script.ScriptEngine;
  2. import javax.script.ScriptEngineManager;
  3. import jdk.nashorn.api.scripting.ScriptObjectMirror;
  4. public class MainProcess {
  5.     public static void main(String... args) throws Exception {
  6.         
  7.         ScriptEngineManager manager = new ScriptEngineManager();
  8.         ScriptEngine engine = manager.getEngineByName("javascript");
  9.         
  10.         // json文字列に変換する辞書
  11.         ScriptObjectMirror m = (ScriptObjectMirror)engine.eval("new Object()");
  12.         
  13.         m.put("result", true);
  14.         m.put("count", 42);
  15.         m.put("name", "Symfoware");
  16.         
  17.         ScriptObjectMirror list = (ScriptObjectMirror)engine.eval("new Array()");
  18.         list.callMember("push", 1);
  19.         list.callMember("push", 2);
  20.         list.callMember("push", 3);
  21.         m.put("list", list);
  22.         
  23.         ScriptObjectMirror map = (ScriptObjectMirror)engine.eval("new Object()");
  24.         map.put("key", "value");
  25.         m.put("map", map);
  26.         
  27.         
  28.         ScriptObjectMirror json = (ScriptObjectMirror) engine.eval("JSON");
  29.         Object result = json.callMember("stringify", m);
  30.         System.out.println(result);
  31.         
  32.     }
  33.     
  34. }




実行結果


{"result":true,"count":42,"name":"Symfoware","list":[1,2,3],"map":{"key":"value"}}



いい感じです。



【参考URL】

Java スクリプトプログラマーズガイド
Java の上の JavaScript エンジン Nashorn の基本
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/JSON
https://docs.oracle.com/javase/8/docs/jdk/api/nashorn/jdk/nashorn/api/scripting/ScriptObjectMirror.html

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

  1. 2018/02/01(木) 23:42:52|
  2. Java
  3. | トラックバック:0
  4. | コメント:0
  5. | 編集

Riot js 書籍ビューワー風なサンプルプログラム

キーボードの左右キーで画像を切り替えるRiotサンプル
Riot キーボードの矢印キーで画像を切り替える

PDFファイルをjpgファイルに変換
PDFBox 2でpdfファイルをページごとにjpgファイルへ変換する

これを組み合わせ、pdfから変換したjpgファイルを見開きで表示するサンプルを作ってみます。


サンプル



Riot キーボードの矢印キーで画像を切り替える
こことほとんど同様の内容です。

imageフォルダにlist.jsonを作成。
画像のリストを記載しておきます。

・image/list.json


  1. [
  2.     {"url1":"image/001.jpg", "url2":"image/002.jpg"},
  3.     {"url1":"image/003.jpg", "url2":"image/004.jpg"},
  4.     {"url1":"image/005.jpg", "url2":"image/006.jpg"},
  5.     {"url1":"image/007.jpg", "url2":"image/008.jpg"},
  6.     {"url1":"image/009.jpg", "url2":"image/010.jpg"},
  7.     {"url1":"image/011.jpg", "url2":"image/012.jpg"},
  8.     {"url1":"image/013.jpg", "url2":"image/014.jpg"},
  9.     {"url1":"image/015.jpg", "url2":"image/016.jpg"},
  10.     {"url1":"image/017.jpg", "url2":"image/018.jpg"},
  11.     {"url1":"image/019.jpg", "url2":"image/020.jpg"},
  12.     {"url1":"image/021.jpg", "url2":"image/022.jpg"},
  13.     {"url1":"image/023.jpg", "url2":"image/024.jpg"},
  14.     {"url1":"image/025.jpg", "url2":"image/026.jpg"},
  15.     {"url1":"image/027.jpg", "url2":"image/028.jpg"},
  16.     {"url1":"image/029.jpg", "url2":"image/030.jpg"},
  17.     {"url1":"image/031.jpg", "url2":"image/032.jpg"},
  18.     {"url1":"image/033.jpg", "url2":"image/034.jpg"}
  19. ]




表示するriotなプログラムはこうなりました。


  1. <!doctype html>
  2. <html lang="ja">
  3. <html>
  4. <head>
  5.     <meta charset="UTF-8">
  6.     <title>Riotサンプル</title>
  7.     <meta http-equiv="X-UA-Compatible" content="IE=edge">
  8. </head>
  9. <body>
  10.     <my-tag></my-tag>
  11. </body>
  12. <script type="riot/tag">
  13. <my-tag>
  14.     <h3>画像表示サンプル { info }</h3>
  15.     <div style="float:left;width:50%">
  16.         <img src="{ url1 }" style="width:100%;height:100%">
  17.     </div>
  18.     <div style="float:left;width:50%">
  19.         <img src="{ url2 }" style="width:100%;height:100%">
  20.     </div>
  21.     <br clear="both"/>
  22. var self = this
  23. self.imagelist = []
  24. self.url1 = ''
  25. self.url2 = ''
  26. self.info = ''
  27. self.index = 0
  28. updateView(operation) {
  29.     self.url1 = self.imagelist[self.index].url1
  30.     self.url2 = self.imagelist[self.index].url2
  31.     self.info = `( ${self.index + 1} / ${self.imagelist.length} ):${operation}`
  32.     self.update()
  33. }
  34. getList() {
  35.     // 画像のURLリストを取得
  36.     const url = 'image/list.json'
  37.     fetch(url)
  38.     .then(function(response) {
  39.         return response.json()
  40.     }).then(function(json){
  41.         self.imagelist = json
  42.         self.updateView('getList')
  43.     })
  44. }
  45. keydown(event) {
  46.     var operation = ''
  47.     switch (event.keyCode) {
  48.         case 37: // left 1つ前の画像
  49.             operation = 'left'
  50.             self.index--
  51.             break
  52.         case 39: // right 次の画像
  53.             operation = 'right'
  54.             self.index++
  55.             break
  56.         default:
  57.             return
  58.     }
  59.     // 範囲チェック
  60.     if (self.index < 0) {
  61.         self.index = 0
  62.         return
  63.     }
  64.     if (self.imagelist.length - 1 < self.index) {
  65.         self.index = self.imagelist.length - 1
  66.         return
  67.     }
  68.     self.updateView(operation)
  69. }
  70. document.onkeydown = this.keydown;
  71. this.getList()
  72. </my-tag>
  73. </script>
  74. <!-- マウント -->
  75. <script src="https://cdnjs.cloudflare.com/ajax/libs/fetch/2.0.3/fetch.min.js"></script>
  76. <script src="https://cdnjs.cloudflare.com/ajax/libs/riot/3.8.1/riot+compiler.min.js"></script>
  77. <script>
  78. riot.mount('my-tag')
  79. </script>
  80.     
  81. </html>




2つの画像を左右に並べて表示しています。
動作している様子はこんな感じです。

824_01.gif

※このgifはpeekを使用して作成しました。
Ubuntu 画面をキャプチャしてgifアニメを作成する(Peek)

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

  1. 2018/01/31(水) 23:09:23|
  2. Java
  3. | トラックバック:0
  4. | コメント:0
  5. | 編集

PDFBox 2でpdfファイルをページごとにjpgファイルへ変換する

Apache PDFBox
PDFファイルを操作するライブラです。
PDFファイルの内容をページごとにjpgファイルへ変換してみます。


ライブラリの入手



ダウンロードページ
https://pdfbox.apache.org/download.cgi

「pdfbox-2.0.8.jar」
「fontbox-2.0.8.jar」
「pdfbox-tools-2.0.8.jar」

をダウンロードしてビルドパスに含めました。

823_01.png


「fontbox-2.0.8.jar」
変換するpdfがすべて画像で構成されていれば必要ないのですが、
フォントが埋め込まれているページの変換を行う場合は必要です。
こんなエラーが発生し、変換に失敗します。


Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/fontbox/cff/CFFParser$ByteSource
    at org.apache.pdfbox.pdmodel.font.PDFontFactory.createFont(PDFontFactory.java:60)
    at org.apache.pdfbox.pdmodel.PDResources.getFont(PDResources.java:143)




Apache Commons Loggingに依存していますので、
http://commons.apache.org/proper/commons-logging/download_logging.cgi
こちらから「commons-logging-1.2-bin.zip」をダウンロード。
解凍してcommons-logging-1.2.jarもビルドパスに含めておきます。





サンプルのPDF



変換に使用するPDFファイルはこちらを使用させていただきました。
ftp://ftp.oreilly.co.jp/9784873113647/PCI_sample.pdf

「集合知プログラミング」のサンプルページです。



プログラム



jpgへ変換するプログラムはこちらを参考にしました。
Apache PDFBoxでPDFページを画像にする(ラスタライズ)
https://pdfbox.apache.org/2.0/migration.html#pdf-rendering


  1. import java.awt.image.BufferedImage;
  2. import java.io.File;
  3. import java.io.FileInputStream;
  4. import java.io.IOException;
  5. import java.io.InputStream;
  6. import org.apache.pdfbox.pdmodel.PDDocument;
  7. import org.apache.pdfbox.rendering.ImageType;
  8. import org.apache.pdfbox.rendering.PDFRenderer;
  9. import org.apache.pdfbox.tools.imageio.ImageIOUtil;
  10. public class MainProcess {
  11.     public static void main(String... args) {
  12.         
  13.         File file = new File("PCI_sample.pdf");
  14.         
  15.         try (InputStream in = new FileInputStream(file);
  16.                 PDDocument doc = PDDocument.load(in)) {
  17.             
  18.             
  19.             PDFRenderer pdfRenderer = new PDFRenderer(doc);
  20.             for (int i = 0; i < doc.getNumberOfPages(); i++) {
  21.                 BufferedImage image = pdfRenderer.renderImageWithDPI(i, 300, ImageType.RGB);
  22.                 ImageIOUtil.writeImage(image, String.format("%03d.jpg", i + 1), 300);
  23.             }
  24.             
  25.             
  26.         } catch (IOException e) {
  27.             e.printStackTrace();
  28.         }
  29.                 
  30.         
  31.     }
  32.     
  33.     
  34. }




変換した画像と元のPDFとの比較です。
左がjpg、右がpdfです。

823_02.png

823_03.png


jpg側、縮小しているため字が潰れて見えますが、拡大すると綺麗に変換されていることが
確認できます。

823_04.png




【参考URL】

Apache PDFBoxでPDFページを画像にする(ラスタライズ)
https://pdfbox.apache.org/2.0/migration.html#pdf-rendering

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

  1. 2018/01/31(水) 22:33:33|
  2. Java
  3. | トラックバック:0
  4. | コメント:0
  5. | 編集

Riot キーボードの矢印キーで画像を切り替える

Riotで画像ビューワーみたいなものを作ってみようと思います。
最初のサンプルとして、キーボードの矢印キーで画像を切り替えるプログラムを作ってみます。


フォルダやファイルの構成



・index.html
画像を表示する

・image/list.json
画像のURLを記載したjson
プログラム初期化時に読み込む

・image/001.jpg ... 005.jpg
表示する画像ファイル

こんな感じです。

822_01.png

list.jsonの記載内容です。
これを最初に読み込み、画像を表示します。


  1. [
  2.     {"url":"image/001.jpg"},
  3.     {"url":"image/002.jpg"},
  4.     {"url":"image/003.jpg"},
  5.     {"url":"image/004.jpg"},
  6.     {"url":"image/005.jpg"}
  7. ]




表示に使用する画像はこちらからお借りしています。
https://matome.naver.jp/odai/2148577671688302101





index.html



表示するプログラムはこうなりました。


  1. <!doctype html>
  2. <html lang="ja">
  3. <html>
  4. <head>
  5.     <meta charset="UTF-8">
  6.     <title>Riotサンプル</title>
  7.     <meta http-equiv="X-UA-Compatible" content="IE=edge">
  8. </head>
  9. <body>
  10.     <my-tag></my-tag>
  11. </body>
  12. <script type="riot/tag">
  13. <my-tag>
  14.     <h3>画像表示サンプル { info }</h3>
  15.     <img src="{ url }" style="width:100%;height:100%">
  16. var self = this
  17. self.imagelist = []
  18. self.url = ''
  19. self.info = ''
  20. self.index = 0
  21. updateView(operation) {
  22.     self.url = self.imagelist[self.index].url
  23.     self.info = `( ${self.index + 1} / ${self.imagelist.length} ):${operation}`
  24.     self.update()
  25. }
  26. getList() {
  27.     // 画像のURLリストを取得
  28.     const url = 'image/list.json'
  29.     fetch(url)
  30.     .then(function(response) {
  31.         return response.json()
  32.     }).then(function(json){
  33.         self.imagelist = json
  34.         self.updateView('getList')
  35.     })
  36. }
  37. keydown(event) {
  38.     var operation = ''
  39.     switch (event.keyCode) {
  40.         case 37: // left 1つ前の画像
  41.             operation = 'left'
  42.             self.index--
  43.             break
  44.         case 39: // right 次の画像
  45.             operation = 'right'
  46.             self.index++
  47.             break
  48.         default:
  49.             return
  50.     }
  51.     // 範囲チェック
  52.     if (self.index < 0) {
  53.         self.index = 0
  54.         return
  55.     }
  56.     if (self.imagelist.length - 1 < self.index) {
  57.         self.index = self.imagelist.length - 1
  58.         return
  59.     }
  60.     self.updateView(operation)
  61. }
  62. document.onkeydown = this.keydown;
  63. this.getList()
  64. </my-tag>
  65. </script>
  66. <!-- マウント -->
  67. <script src="https://cdnjs.cloudflare.com/ajax/libs/fetch/2.0.3/fetch.min.js"></script>
  68. <script src="https://cdnjs.cloudflare.com/ajax/libs/riot/3.8.1/riot+compiler.min.js"></script>
  69. <script>
  70. riot.mount('my-tag')
  71. </script>
  72.     
  73. </html>




最初にimage/list.jsonを読み込む。
document.onkeydownでキーボードのイベントを拾い、
右・左の矢印キーの場合は画像のsrcを入れ替えています。

動作している様子はこんな感じです。

822_02.gif


思ったより簡単に実装できました。
次は画像の事前読み込みなどに挑戦してみたいと思います。



【参考URL】

新世代Aqours #ラブライブサンシャイン! 画像集【iPhone用Android用PC用】
キーボードによる画像の移動
テンプレート文字列

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

  1. 2018/01/30(火) 23:21:43|
  2. Java
  3. | トラックバック:0
  4. | コメント:0
  5. | 編集
前のページ 次のページ