PDFlib TET で、 PDF イメージを読み取るサンプルプログラムです。ここでは、イメージをメモリ上に抽出し、Java Image I/O API に引き渡してイメージのメタデータを取得します。
この JRE と一緒に提供される javax.imageio パッケージは、サポートされるフォーマットに制限があります。例えば、TIFF イメージのために out-of-the-box はサポートされません。TIFF や JPEG2000 等のその他のフォーマットを得るために、「Java Advanced Imaging Image I/O」ツールをインストールする必要があります。その際、プログラムや Ant ビルドファイルの変更は必要としません。ライブラリが classpath によって見つける事ができれば十分です。詳しくはダウンロードした
クックブックの doc ディレクトリにある readme.txt をご覧ください。
テスト中、JAI 1.1. ライブラリには JPEG2000 ファイルに関する問題が見つかっています。この問題が原因の場合、下記のようなエラーになります。
java.lang.NullPointerException
at com.sun.media.imageioimpl.plugins.jpeg2000.J2KMetadata.replace(J2KMetadata.java:962)
at com.sun.media.imageioimpl.plugins.jpeg2000.J2KMetadata.addNode(J2KMetadata.java:631)
at jj2000.j2k.fileformat.reader.FileFormatReader.readFileFormat(FileFormatReader.java:279)
at com.sun.media.imageioimpl.plugins.jpeg2000.J2KMetadata.<init>(J2KMetadata.java:135)
at com.sun.media.imageioimpl.plugins.jpeg2000.J2KImageReader.getImageMetadata(
J2KImageReader.java:419)
at com.pdflib.cookbook.tet.image.image_reader.print_metadata(image_reader.java:243)
at com.pdflib.cookbook.tet.image.image_reader.main(image_reader.java:171)
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.util.Iterator;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.stream.ImageInputStream;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import com.pdflib.TETException;
import com.pdflib.TET;
/**
* PDFlib TET で、 PDF イメージを読み取るサンプルプログラムです。ここでは、イメージを
* メモリ上に抽出し、Java Image I/O API に引き渡してイメージのメタデータを取得します。
*
* この JRE と一緒に提供される javax.imageio パッケージは、サポートされるフォーマットに
* 制限があります。例えば、TIFF イメージのために out-of-the-box はサポートされません。
* TIFF や JPEG2000 等のその他のフォーマットを得るために、「Java Advanced Imaging Image
* I/O」ツールをインストールする必要があります。その際、プログラムや Ant ビルドファイルが
* の変更を必要としません。ライブラリclasspath によって見つける事ができれば十分です。詳し
* くはダウンロードしたクックブックの doc ディレクトリにある readme.txt をご覧ください。
*
* テスト中、JAI 1.1. ライブラリには JPEG2000 ファイルに関する問題が見つかっています。次に
* 類似する例外は、その兆候と思われます。
*
* java.lang.NullPointerException
* at com.sun.media.imageioimpl.plugins.jpeg2000.J2KMetadata.replace(J2KMetadata.java:962)
* at com.sun.media.imageioimpl.plugins.jpeg2000.J2KMetadata.addNode(J2KMetadata.java:631)
* at jj2000.j2k.fileformat.reader.FileFormatReader.readFileFormat
* (FileFormatReader.java:279)
* at com.sun.media.imageioimpl.plugins.jpeg2000.J2KMetadata.(J2KMetadata.java:135)
* at com.sun.media.imageioimpl.plugins.jpeg2000.J2KImageReader.getImageMetadata
* (J2KImageReader.java:419)
* at com.pdflib.cookbook.tet.image.images_in_memory.print_metadata
* (images_in_memory.java:243)
* at com.pdflib.cookbook.tet.image.images_in_memory.main(images_in_memory.java:171)
*
* この問題は、現在 JAI 1.2 デイリービルドで修正されています。
*
* 必要な製品: TET 4
*
* 必要なデータ: PDF 文書
*
* @version $Id: images_in_memory.java,v 1.1 2010/07/20 14:13:23 stm Exp $
*/
public class images_in_memory
{
/**
* グローバルオプションリスト
*/
static final String GLOBAL_OPTLIST = "searchpath={../resource/cmap "
+ "../resource/glyphlist ../input}";
/**
* 文書の特別なオプションリスト
*/
static final String DOC_OPTLIST = "";
/**
* ページの特別なオプションリスト
*/
static final String PAGE_OPTLIST = "granularity=page";
/**
* 基本的な画像抽出オプション(詳細は下記の通り)
*/
static final String BASE_IMAGE_OPTLIST = "compression=auto format=auto";
/**
* System.out に送られるエンコーディング。
* 例えば、コマンドウィンドウでデフォルトエンコーディングと異なる文字コードを
* 指定することがする。
*/
private static final String OUTPUT_ENCODING = System
.getProperty("file.encoding");
/**
* メタデータツリーで使用される、インデントのための空白、またはタブ
*/
private static final String METADATA_INDENTATION = " ";
/**
* OUTPUT_ENCODING にて指定されたエンコーディングで System.out より出力
*/
private static PrintStream out;
public static void main(String argv[]) throws UnsupportedEncodingException {
System.out.println("Using output encoding \"" + OUTPUT_ENCODING + "\"");
out = new PrintStream(System.out, true, OUTPUT_ENCODING);
TET tet = null;
try {
if (argv.length != 1) {
throw new Exception("usage: images_in_memory ");
}
tet = new TET();
tet.set_option(GLOBAL_OPTLIST);
int doc = tet.open_document(argv[0], DOC_OPTLIST);
if (doc == -1) {
throw new Exception("Error " + tet.get_errnum() + "in "
+ tet.get_apiname() + "(): " + tet.get_errmsg());
}
/* 文書のページ番号を取得する */
int n_pages = (int) tet.pcos_get_number(doc, "length:pages");
/* ページ数分ループする */
for (int pageno = 1; pageno <= n_pages; ++pageno) {
int page = tet.open_page(doc, pageno, PAGE_OPTLIST);
if (page < 0) {
print_tet_error(tet, pageno);
continue; /* 次のページへ */
}
/* ページ上で全てのイメージを取得する */
int imageno = -1;
while (tet.get_image_info(page) == 1) {
imageno++;
/*
* write_image_file() で"typeonlly"を指定することで、イメージファイルを
* 生成せずに、イメージの種類のみを返す
*/
int imageType = tet.write_image_file(doc, tet.imageid,
BASE_IMAGE_OPTLIST + " typeonly");
/*
* イメージの種別を表す数値を種別名へマップする。
* write_image_file()の戻り値については、TETのマニュアルを参照のこと。
*/
String imageFormat;
switch (imageType) {
case 10:
imageFormat = "tiff";
break;
case 20:
imageFormat = "jpg";
break;
case 30:
imageFormat = "jpeg2000";
break;
case 40:
imageFormat = "raw";
break;
default:
System.err.println("Page " + pageno + " image "
+ imageno
+ ": write_image_file returned unknown value "
+ imageType + ", skipping image, error: "
+ tet.get_errmsg());
continue;
}
/*
* イメージを抽出し、メモリに書き込む
*/
byte imagedata[] = tet.get_image_data(doc, tet.imageid,
BASE_IMAGE_OPTLIST);
if (imagedata == null) {
print_tet_error(tet, pageno);
continue; /* 次のイメージを処理 */
}
/*
* イメージのメタデータを抽出する
*/
print_metadata(imagedata, imageFormat, pageno, imageno + 1);
}
if (tet.get_errnum() != 0) {
print_tet_error(tet, pageno);
}
tet.close_page(page);
}
tet.close_document(doc);
}
catch (TETException e) {
System.err.println("TET exception occurred in extractor sample:");
System.err.println("[" + e.get_errnum() + "] " + e.get_apiname()
+ ": " + e.get_errmsg());
}
catch (Exception e) {
e.printStackTrace();
}
finally {
if (tet != null) {
tet.delete();
}
}
}
/**
* ImageReader クラスよりバイナリイメージデータを取り出し、メタデータを出力する
*
* @param imagedata
* イメージのバイナリデータ
* @param imageFormat
* イメージのフォーマット名
* @param pageno
* イメージデータが含まれているページ番号
* @param imageno
* ページ内でのイメージデータの番号
*
* @throws IOException
* ImageIO API によるエラー
*/
private static void print_metadata(byte[] imagedata,
String imageFormat, int pageno, int imageno) throws IOException {
/*
* ImageReader クラスよりバイナリ画像データを取り出す
*/
Iterator<ImageReader> readerIterator = ImageIO.getImageReadersByFormatName(imageFormat);
if (readerIterator != null && readerIterator.hasNext()) {
/*
* 初めの1つのみImageReaderオブジェクトを取り出す
*/
ImageReader reader = (ImageReader) readerIterator.next();
/*
* バイナリデータから ImageInputStream を生成し、 ImageReaderインスタンスに
* 設定する
*/
ImageInputStream inputStream =
ImageIO.createImageInputStream(new ByteArrayInputStream(imagedata));
reader.setInput(inputStream);
/*
* メタデータを取得し、出力する
*/
IIOMetadata metadata = reader.getImageMetadata(0);
if (metadata != null) {
String format = metadata.getNativeMetadataFormatName();
Node tree = metadata.getAsTree(format);
print_metadata(tree, pageno, imageno);
}
}
else {
System.err.println("No Java ImageReader available for suffix "
+ imageFormat);
}
}
/**
* DOM ツリーからメタデータを出力する
*
* @param tree
* 出力のための DOM ツリー
* @param pageno
* メタデータを持つイメージのページ番号
* @param imageno
* ページ内のイメージの数
*/
private static void print_metadata(Node tree, int pageno, int imageno) {
out.println("Metadata for image "
+ imageno + " on page " + pageno + ":");
print_metadata(tree, 0);
}
/**
* DOM サブツリーをたどり、ノード名と値を出力する
*
* @param node
* 出力するサブツリー
* @param level
* インデントに使用される総ツリー内の現在のレベル
*/
private static void print_metadata(Node node, int level) {
String indentation = get_indentation(level);
out.print(indentation + "node=\"" + node.getNodeName() + "\"");
String value = node.getNodeValue();
if (value != null) {
out.print(" value=\"" + value + "\"");
}
out.println();
NamedNodeMap map = node.getAttributes();
if (map != null) {
int length = map.getLength();
if (length > 0) {
out.print(indentation + " ");
for (int i = 0; i < length; i++) {
Node attr = map.item(i);
out.print(" " + attr.getNodeName() + "=\""
+ attr.getNodeValue() + "\"");
}
out.println();
}
}
NodeList children = node.getChildNodes();
for (int i = 0; i < children.getLength(); i += 1) {
print_metadata(children.item(i), level + 1);
}
}
/**
* パラメータのレベルからインデントの空白文字数を算出する
*
* @param level
* インデントのレベル
*
* @return インデントのレベルから算出した、空白数
*/
private static String get_indentation(int level) {
StringBuffer indentation = new StringBuffer();
for (int i = 0; i < level; i += 1) {
indentation.append(METADATA_INDENTATION);
}
return indentation.toString();
}
/**
* TET エラーレポート
*
* @param tet
* TET オブジェクト
* @param pageno
* エラーとなったページ番号
*/
private static void print_tet_error(TET tet, int pageno) {
System.err.println("Error " + tet.get_errnum() + " in "
+ tet.get_apiname() + "() on page " + pageno + ": "
+ tet.get_errmsg());
}
}