Java → Python プロセス起動の可能性

去年書いた
yipuran-core/ScriptExecutor.java at master · yipuran/yipuran-core · GitHub
このメソッド
public static int runStream(Supplier<String>, Supplier<Collection<String>>
, Consumer<InputStream>, BiConsumer<String, Throwable>)

public static int runStream(Supplier<String>, Consumer<InputStream>, BiConsumer<String, Throwable>)

このプロセス起動、プロセスの標準出力を Consumer<InputStream>で受信した処理をラムダ式で、
そしてプロセスが要求する入力を Supplier<Collection<String>> ラムダ式で与えるという方法は
いろんな拡がり可能性があるようだ。
PythonでPDF作成→Javaで受け取り→Wicket AJAXダウンロード - Oboe吹きプログラマの黙示録

改善する→「JavaからProcess起動で Python 実行して PDF を作らせる。」 - Oboe吹きプログラマの黙示録

JavaからProcess起動で Python 実行して PDF を作らせる。 - Oboe吹きプログラマの黙示録

↑ここまでは、単に Python にPDFを作らせる仕事をさせてそれを受け取るのだが、
画像系の処理でも同じことができるはずだ。

QRコード、バーコードを作成するくらいだったら、すでに Java の世界でも
https://github.com/zxing/zxing を使えば、Python使わなくても良いだろう。
でも、画像加工処理となってくると、ちょっとJavaじゃ辛い。良いのが見当たらないのだ。

前の投稿でも書いた Python に処理させて結果をバイナリの標準出力させれば、
Consumer<InputStream> での処理が成立する。

import sys
import io

io.BytesIO() オブジェクトに求めたい結果を出力して
getvalue() → sys.stdout.buffer.write でバイト単位出力
ができれば良いのである。

Python PILLOW 画像加工を処理するサンプル

Java Wicket で作成する Webページで画像加工前の画像をHTML img タグで表示と
Python PILLOW による簡単な加工結果を同様のHTML img タグで表示させる
(...同様のHTML img タグで表示 → 何、訳わからんことを!と思うかもしれないが
 そこが、Java Wicket を使って可能な面白さのところです。)

Pythonのコード:img_convert.jpg
引数で加工する画像ファイルPATHを受け取って、
白黒変換、ガウシアンブラー(ガウスぼかし)、リサイズします

# -*- coding: UTF-8 -*-
from PIL import Image, ImageFilter
import io
import sys

argv = sys.argv
img = Image.open(argv[1])

img2 = img.convert('L').filter(ImageFilter.GaussianBlur()).resize((120, 120),Image.LANCZOS)

po = io.BytesIO();
img2.save(po, format='JPEG')
sys.stdout.buffer.write(po.getvalue())

↑ format= の指定がないとダメです。

Webページ表示する HTMLソースです。wicket:id タグの方が加工前で
加工後は、WicketSharedResource で取得して表示するので、wicket:id が有りません。

<!-- 加工前の画像 -->
<div>
   <img wicket:id="lena" alt="lena" style="width: 120px;height: 120px">
</div>
<!-- 加工後の画像 -->
<div>
   <img src="lenaConvertImage">
</div>

Wicket
https://github.com/yipuran/yipuran-core/blob/master/src/main/java/org/yipuran/util/process/ScriptExecutor.java
を使用して書く Webページ Java です。
以下をPageクラスのコンストラクタ内で実行します。
sdir_path + "/img_convert.py" が、実行するPythonの指定で、getimagePath()が加工対象画像ファイルのパスです。

queue(new Image("lena", new PackageResourceReference(SamplePage.class, "lena.png")));

int sts = ScriptExecutor.runStream(()->"python " + sdir_path + "/img_convert.py " + getimagePath()
, inst->{
   try(ByteArrayOutputStream out = new ByteArrayOutputStream()){
      inst.transferTo(out);
      out.flush();
      getApplication().getSharedResources().add("lena_convert"
           , new ByteArrayResource("image/jpeg", out.toByteArray()));
      ((WebApplication)getApplication())
       .mountResource("lenaConvertImage", new SharedResourceReference("lena_convert"));
   }catch(Exception ex){
      throw new RuntimeException(ex);
   }
}, (e, x)->{
   logger.error(e);
   logger.error(x.getMessage(), x);
});

Python 加工したデータを標準出力から InputStream → ByteArrayOutputStream
→ メモリ上でWicket の共有リソースとするのです。

Webページの表示は、、
f:id:posturan:20190101113921j:plain

Webページコンストラクタで Python プロセス起動して結果受けるまでは
表示が待たされる作りです。凄い遅いと予測したが、思ったより遅くなかった。