簡単にJavaからネイティブコードを使えるJNA

biz-Streamを使っていると,何かと画象イメージを扱う機会があります.

biz-Stream を使ってPDFに画像を読み込む時に、画像編集が必要になったり,
biz-Stream が生成したPDFを画像化して表示する時に、
画像編集が必要になったりする場面があるのではないでしょうか。

Javaで書かれた画像編集のソフトもありますが、
OpenCVなどの高機能なネイティブソフトを使用したいと思う方がいるかもしれません.

そのような場合,Javaからネイティブコードを使用する方法として,
JNI (= Java Native Interface) がありますが,
JNI を使うには煩雑なコーディング実装が必要で,手間がかかります.

こんなとき,Javaからネイティブコードのライブラリを使用する仕組み
JNA (= Java Native Access) が便利です.

使い方は簡単で,ダウンロードページから jna.jar をダウンロードしてclasspathに追加するだけです.

用途によって,システムの標準ライブラリを使用したり,

《 システムライブラリを使い,C言語のprintfを呼び出してコンソールに出力するサンプル【Linux環境】》
package com.sun.jna.examples;

import com.sun.jna.Library;
import com.sun.jna.Native;

public class HelloWorld {

    public interface CLibrary extends Library {
        CLibrary INSTANCE = (CLibrary)
            Native.loadLibrary( "c", CLibrary.class);
    
        void printf(String format, Object... args);
    }

    public static void main(String[] args) {
        CLibrary.INSTANCE.printf("Hello, World\n");
    }
}

動的に任意のライブラリを使用したりと使い分けることもできます.

サンプルとして,OpenCVを使って画像ファイルをプレビューするプログラムを作ってみました.

OpenCVを使ったサンプルプログラムの実行結果

《 OpenCVを使ったサンプルプログラムの実行結果 》

《 OpenCVライブラリを使い,画像をプレビューするサンプル 【Linux環境】》
package com.sun.jna.examples;

import com.sun.jna.*;
import java.io.*;
import java.util.*;

public class HellowWorld {

    /**
     *  from highgui.h 
     */
    public static final int CV_WINDOW_AUTOSIZE    = 1;
    //
    public static final int CV_LOAD_IMAGE_UNCHANGED  = -1;
    public static final int CV_LOAD_IMAGE_GRAYSCALE  =  0;
    public static final int CV_LOAD_IMAGE_COLOR      =  1;
    public static final int CV_LOAD_IMAGE_ANYDEPTH   =  2;
    public static final int CV_LOAD_IMAGE_ANYCOLOR   =  3;
    
    public static void main(String[] args) {
        try {
            NativeLibrary.addSearchPath( "cv", "/usr/lib");
            NativeLibrary.addSearchPath( "highgui", "/usr/lib");
            NativeLibrary[] Libs = new NativeLibrary[] {
                                    NativeLibrary.getInstance("cv"), 
                                    NativeLibrary.getInstance("highgui")
                                    };
            //
            HashMap  funcsMap = new HashMap();
            funcsMap.put( "cvLoadImage",        null    );
            funcsMap.put( "cvNamedWindow",      null    );
            funcsMap.put( "cvShowImage",        null    );
            funcsMap.put( "cvWaitKey",          null    );
            funcsMap.put( "cvDestroyWindow",    null    );
            funcsMap.put( "cvReleaseImage",     null    );
            //
            Function func;
            String    funcName;
            //
            Set keys = funcsMap.keySet();
            for ( Iterator it = keys.iterator(); it.hasNext();) {
                funcName = (String)it.next();
                for ( int i = 0; i < Libs.length; i++ ) {
                    try {
                        if ( null == (func = Libs[i].getFunction(funcName)) ) {
                            continue;
                        }
                        funcsMap.put( funcName, func );
                        break;
                    }
                    catch ( UnsatisfiedLinkError ex ) { continue;}
                }
            }
            //
            Pointer[]    retImg = new Pointer[1];
            InputStream ist = System.class.getClassLoader().getSystemResourceAsStream( "google-chrome.png" );
            File f = InputStream2TempFile( ist, "Img01_", ".png");
            //
            funcName = "cvLoadImage";
            func = (Function)funcsMap.get( funcName );
            Object[] Args = new Object[] { f.getAbsolutePath(), new Integer(CV_LOAD_IMAGE_COLOR) };
            retImg[0] = func.invokePointer( Args );
            //
            funcName = "cvNamedWindow";
            func = (Function)funcsMap.get( funcName );
            Args = new Object[] { "image", new Integer(CV_WINDOW_AUTOSIZE) };
            func.invokeVoid( Args ); 
            //
            funcName = "cvShowImage";
            func = (Function)funcsMap.get( funcName );
            Args = new Object[] { "image", retImg[0] };
            func.invokeVoid(Args);
            //
            funcName = "cvWaitKey";
            func = (Function)funcsMap.get( funcName );
            Args = new Object[] { new Integer(0)};
            func.invokeInt(Args);
            //
            funcName = "cvDestroyWindow";
            func = (Function)funcsMap.get( funcName );
            Args = new Object[] { "image" };
            func.invokeVoid(Args);
            //
            funcName = "cvReleaseImage";
            func = (Function)funcsMap.get( funcName );
            Args = new Object[] { retImg };
            func.invokeVoid(Args);
        }
        catch ( Throwable ex ) {
            ex.printStackTrace();
        }
    }
    
    public static File InputStream2TempFile( InputStream iStream, String prefix, String suffix ) {
        File retF = null;
        try {
            if ( null == iStream || 0 == iStream.available() ) {
                throw new Exception("ERROR: " + "iStream" + " is null or empty.");
            }
            retF = File.createTempFile( prefix, suffix );
            OutputStream oStr = new FileOutputStream( retF );
            byte buf[] = new byte[1024];
            int len;
            while ( 0 < (len = iStream.read(buf)) ) {
                oStr.write( buf, 0, len );
            }
            oStr.close();
            if ( 0 == retF.length() ) {
                throw new Exception("ERROR: " + "iStream" + " is null or empty.");
            }
        }
        catch ( Throwable ex ) {
            retF = null;
        }

        return retF;
    }
}

随分と簡単ですね.皆さんも試してみてはいかがでしょうか.

biz-Stream詳細情報  biz-Stream資料請求

超高速!!高機能!! Web帳票ソリューション biz-Stream

オンデマンドかつリアルタイムにビジネスドキュメントを生成する帳票ソリューション