Wolfram CDF Playerでローカルファイルの読み込みと書き込みを行う

Wolfram CDF Player を汎用するにあるように、 CDF PlayerでもJ/Linkを使えばローカルファイルの読み込み、書き込みができる(※CDFファイルの作成にはMathematicaが必要)。

上記リンク先ではテキストファイルを読み込む例が載っているが、バイナリファイルとして読み込んでImportStringを使えば、 Mathematicaが対応している形式すべてのファイルを読み込むことができる。

J/Linkでバイナリファイルを読み込むときのポイントとしては、

  • “[B”というクラス名でbyte型の配列を作ってBufferedInputStream.read(byte[])で一気に読み込むことで高速化
  • 読み込んだbyte[]がMathematicaに入った時に符号付き整数で扱われるため、FromCharacterCodeに突っ込む前に0〜255になるように修正

が挙げられる。

一方、CDF PlayerではExportのみならずExportStringが使えない(ImportStringは使えるのに)ので、書き込むほうは不自由が残る。 ここではテキストと画像(BMP、PNG、JPEG)に限って保存する関数を作ってみた。

ImportWithJLink[filepath_?(FileExistsQ[FindFile[#]] &), format_] := (
  Needs["JLink`"];
  JLink`InstallJava[];
  JLink`JavaBlock[
   Module[{br, byte, result}, 
    br = JLink`JavaNew["java.io.BufferedInputStream", 
      JLink`JavaNew["java.io.FileInputStream", [email protected]]];
    byte = JLink`JavaNew["[B", {FileByteCount[[email protected]]}];
    [email protected][byte];
    result = 
     ImportString[
      FromCharacterCode[
       JLink`JavaObjectToExpression[byte] /. x_?Negative :> x + 256], 
      format];
    [email protected][];
    result]]);
ExportWithJLink[filepath_, string_String, format : "Text"] := (
  Needs["JLink`"];
  JLink`InstallJava[];
  JLink`JavaBlock[
   Module[{bw},
    bw = JLink`JavaNew["java.io.BufferedWriter",
      JLink`JavaNew["java.io.FileWriter", filepath]
      ];
    [email protected][string];
    [email protected][];
    filepath
    ]
   ]);
ExportWithJLink[filepath_, image_, format : "PNG" | "BMP" | "JPG"] := (
  Needs["JLink`"];
  JLink`InstallJava[];
  JLink`JavaBlock[
   JLink`LoadJavaClass["javax.imageio.ImageIO"];
   JLink`LoadJavaClass["java.awt.image.BufferedImage"];
   Module[{img, bi, width, height},
    img = Rasterize[image];
    {width, height} = ImageDimensions[img];
    bi = JLink`JavaNew["java.awt.image.BufferedImage",
      width, height, java`awt`image`BufferedImage`TYPEUINTUBGR
      ];
    [email protected][0, 0, width, height,
      Flatten[
       Apply[(#1*2^16 + #2*2^8 + #3) &, 
        ImageData[img, "Byte"], {2}]],
      0, width];
    If[javax`imageio`ImageIO`write[bi, format,
      JLink`JavaNew["java.io.File", filepath]],
     filepath, $Failed]
    ]
   ]);

読み込み

img = ImportWithJLink["ExampleData/lena.tif", "TIFF"]

書き込み

file = FileNameJoin[{$TemporaryDirectory, "testfile.png"}];
ExportWithJLink[file, img, "PNG"];
Import[file]