第5章 ラスタデータの管理、クエリ、アプリケーション

目次

5.1. ラスタのロードと生成
5.1.1. raster2pgsqlを使ってラスタをロードする
5.1.2. PostGISラスタ関数を用いたラスタの生成
5.2. ラスタカタログ
5.2.1. ラスタカラムカタログ
5.2.2. ラスタオーバビュー
5.3. PostGISラスタを使ったカスタムアプリケーションの構築
5.3.1. ST_AsPNG を他の関数とあわせて使った PHP 出力例
5.3.2. ST_AsPNGを他の関数とあわせて使ったASP.NET C#出力例
5.3.3. ラスタクエリを画像ファイルとして出力するJavaコンソールアプリケーション
5.3.4. PLPython を使って SQL を介して画像をダンプする
5.3.5. PSQLでラスタを出力する

5.1. ラスタのロードと生成

raster2pgsqlラスタローダを使ってPostGISラスタを既存のラスタファイルからロードするのは、最もよく行われます。

5.1.1. raster2pgsqlを使ってラスタをロードする

raster2pgsqlは、GDALがサポートするラスタ書式をPostGISラスタテーブルにロードするのに適切なSQLにするバイナリファイルです。ラスタのオーバビューの生成だけでなく、ラスタファイルのフォルダのロードも可能です。

raster2pgsqlは、ほとんどの場合、PostGISの一部としてコンパイルされます(GDALライブラリをコンパイルしていない場合)が、バイナリファイルによってサポートされるラスタタイプは、GDALでコンパイルされたのと同じです。raster2pgsqlがサポートするラスタタイプの一覧を得るには、-Gスイッチを使います。この一覧は、インストールした PostGIS が提供する ST_GDALDrivers と同じになるはずです。

[注記]

このツールの古い版では、Pythonスクリプトでした。実行ファイルに置き換えられています。Pytonスクリプトが必要な場合は、GDAL PostGIS Raster Driver Usageに、Pythonの例があります。raster2pgsql の Python スクリプトは、今後の PostGIS raster では動作しないかも知れませんし、サポートされませんんおで、ご注意ください。

使用例:

raster2pgsql raster_options_go_here raster_file someschema.sometable > out.sql

-?

ヘルプを表示します。引数を全く指定しない場合にも表示されます。

-G

サポートされているラスタ書式を印字します。

(c|a|d) 相互に排他的なオプションです。

-c

新しいテーブルを生成し、ラスタを入れます。これがデフォルトモードです。

-a

既存のテーブルにラスタを追加します。

-d

テーブルを削除し、新しいテーブルを生成し、ラスタを入れます。

ラスタ処理: ラスタカタログでの適切に登録するための制約の適用

-C

SRIDやピクセルサイズ等のラスタ制約を適用して、raster_columnsビューで適切な登録ができるようにします。

-x

制約の最大範囲を無効にします。-Cフラグが使われている場合のみ適用されます。

-r

正規ブロック制約です。-Cフラグが使用されている場合のみ適用されます。

ラスタ処理: 入力ラスタデータセットの操作に使われる追加的なパラメータ

-s <SRID>

出力ラスタを指定されたSRIDにします。

-b BAND

ラスタから抽出するバンドのインデクス(1はじまり)。1より多いバンドを抽出するには、コンマ(,)で区切ります。指定しない場合、全てのバンドが抽出されます。

-t TILE_SIZE

行毎に挿入するラスタを切断します。TILE_SIZEは、「幅x高さ」で表現します。

-R, --register

ファイルシステム(データベース外)ラスタとして、ラスタを登録します。

データベースには、ラスタのメタデータとラスタのファイルパスのみ格納されます(ピクセルは格納されません)。

-l OVERVIEW_FACTOR

-l overview factorで、ラスタのオーバビューを生成します。1より多い係数を用いる場合は、コンマ (,) で区切ります。オーバビューのテーブル名は o_overview factor_tableとなります。生成されるオーバビューはデータベースに格納され、-Rは無視されます。生成されたSQLファイルは元データのテーブルとオーバビューテーブルの両方を含むことに注意して下さい。

テータベースオブジェクトの操作に使われる追加的なパラメータ

-q

PostgreSQL 識別子に引用符を付けます。

-f COLUMN

出力先ラスタカラムの名前を指定します。デフォルトは'rast'です。

-F

ファイル名でカラムを追加します。

-I

ラスタカラムにGiSTインデクスを生成します。

-M

ラスタテーブルにVacuum analyzeを行います。

-T tablespace

生成されるテーブルのテーブルスペースを指定します。-Xフラグを併用しない場合には、インデクス(主キーを含む)はデフォルトのテーブルスペースを使用することにご注意ください。

-Y

INSERT ステートメントでなく COPY ステートメントを使います。

-e

ステートメント毎に実行して、トランザクションを使用しないようにします。

-E ENDIAN

生成されるラスタのバイナリ出力のエンディアンを制御します。XDRの場合は0を、NDRの場合は1を、それぞれ指定します。デフォルトは1です。現時点ではNDR出力のみサポートします。

-V version

出力書式の版を指定します。デフォルトは0です。現時点では0のみサポートします。

ローダを用いて入力ファイルを100x100のタイルで生成して、データベースにアップロードする例は、次の通りです。

[注記]

public.demelevationでなくdemelevationというようにスキーマ名を外すことができます。ラスタテーブルはデータベースまたユーザの指定するデフォルトのスキーマに生成されます。

raster2pgsql -s 4236 -I -C -M *.tif -F -t 100x100 public.demelevation > elev.sql
psql -d gisdb -f elev.sql

変換とアップロードは UNIX のパイプを使って一度に実行できます。

raster2pgsql -s 4236 -I -C -M *.tif -F -t 100x100 public.demelevation | psql -d gisdb

マサチューセッツ州平面のメートル単位の空中写真タイルをaerialという名前のスキーマにロードします。 元の画像と2, 4レベルのオーバビューのテーブルとを生成します。 データ格納にCOPYを使用し(データベースに仲介ファイルなくまっすぐ入ります)。 -eでトランザクションを指定しません(待たずにテーブルのデータを見たい場合には良いです)。ラスタを128x128ピクセルのタイルに分解してラスタ制約を適用します。INSERTモードでなくCOPYモードを使用します。-Fで、カラム名をタイル切り出し元ファイルのファイル名にします。

raster2pgsql -I -C -e -Y -F -s 26986 -t 128x128  -l 2,4 bostonaerials2008/*.jpg aerials.boston | psql -U postgres -d gisdb -h localhost -p 5432
-- サポートされているラスタタイプの一覧:
raster2pgsql -G

-Gコマンドの出力は次のようになります。

Available GDAL raster formats:
  Virtual Raster
  GeoTIFF
  National Imagery Transmission Format
  Raster Product Format TOC format
  ECRG TOC format
  Erdas Imagine Images (.img)
  CEOS SAR Image
  CEOS Image
  JAXA PALSAR Product Reader (Level 1.1/1.5)
  Ground-based SAR Applications Testbed File Format (.gff)
  ELAS
  Arc/Info Binary Grid
  Arc/Info ASCII Grid
  GRASS ASCII Grid
  SDTS Raster
  DTED Elevation Raster
  Portable Network Graphics
  JPEG JFIF
  In Memory Raster
  Japanese DEM (.mem)
  Graphics Interchange Format (.gif)
  Graphics Interchange Format (.gif)
  Envisat Image Format
  Maptech BSB Nautical Charts
  X11 PixMap Format
  MS Windows Device Independent Bitmap
  SPOT DIMAP
  AirSAR Polarimetric Image
  RadarSat 2 XML Product
  PCIDSK Database File
  PCRaster Raster File
  ILWIS Raster Map
  SGI Image File Format 1.0
  SRTMHGT File Format
  Leveller heightfield
  Terragen heightfield
  USGS Astrogeology ISIS cube (Version 3)
  USGS Astrogeology ISIS cube (Version 2)
  NASA Planetary Data System
  EarthWatch .TIL
  ERMapper .ers Labelled
  NOAA Polar Orbiter Level 1b Data Set
  FIT Image
  GRIdded Binary (.grb)
  Raster Matrix Format
  EUMETSAT Archive native (.nat)
  Idrisi Raster A.1
  Intergraph Raster
  Golden Software ASCII Grid (.grd)
  Golden Software Binary Grid (.grd)
  Golden Software 7 Binary Grid (.grd)
  COSAR Annotated Binary Matrix (TerraSAR-X)
  TerraSAR-X Product
  DRDC COASP SAR Processor Raster
  R Object Data Store
  Portable Pixmap Format (netpbm)
  USGS DOQ (Old Style)
  USGS DOQ (New Style)
  ENVI .hdr Labelled
  ESRI .hdr Labelled
  Generic Binary (.hdr Labelled)
  PCI .aux Labelled
  Vexcel MFF Raster
  Vexcel MFF2 (HKV) Raster
  Fuji BAS Scanner Image
  GSC Geogrid
  EOSAT FAST Format
  VTP .bt (Binary Terrain) 1.3 Format
  Erdas .LAN/.GIS
  Convair PolGASP
  Image Data and Analysis
  NLAPS Data Format
  Erdas Imagine Raw
  DIPEx
  FARSITE v.4 Landscape File (.lcp)
  NOAA Vertical Datum .GTX
  NADCON .los/.las Datum Grid Shift
  NTv2 Datum Grid Shift
  ACE2
  Snow Data Assimilation System
  Swedish Grid RIK (.rik)
  USGS Optional ASCII DEM (and CDED)
  GeoSoft Grid Exchange Format
  Northwood Numeric Grid Format .grd/.tab
  Northwood Classified Grid Format .grc/.tab
  ARC Digitized Raster Graphics
  Standard Raster Product (ASRP/USRP)
  Magellan topo (.blx)
  SAGA GIS Binary Grid (.sdat)
  Kml Super Overlay
  ASCII Gridded XYZ
  HF2/HFZ heightfield raster
  OziExplorer Image File
  USGS LULC Composite Theme Grid
  Arc/Info Export E00 GRID
  ZMap Plus Grid
  NOAA NGS Geoid Height Grids

5.1.2. PostGISラスタ関数を用いたラスタの生成

データベース内でラスタやラスタテーブルを生成したい場合が多くあります。これを行うための関数が多数あります。一般的な手順は次の通りです。

  1. 新しいラスタ行を保持するためのラスタカラムを持つテーブルを生成します。次を実行します。

    CREATE TABLE myrasters(rid serial primary key, rast raster);
  2. この目標で助けとなる関数は多数あります。他のラスタの派生でないラスタを生成する場合、ST_MakeEmptyRasterST_AddBandを順次実行して作業を開始します。

    ジオメトリからラスタを生成することもできます。ST_AsRasterを使います。ST_UnionST_MapAlgebraFctや、地図解析関数群等といった、他の関数を組み合わせる場合もあります。

    既存テーブルから新しいラスタテーブルを生成するための多数の選択肢があります。たとえば、ST_Transformを使って、既存テーブルから異なる投影法のラスタテーブルを生成します。

  3. はじめにテーブルにデータを入れたら、ラスタカラムに空間インデクスを生成したくなるでしょう。次のようにします。

    CREATE INDEX myrasters_rast_st_convexhull_idx ON myrasters USING gist( ST_ConvexHull(rast) );

    xref linkend="RT_ST_ConvexHull" />を使用していることに注意して下さい。多くのラスタ演算子はラスタの凸包を元にしています。

    [注記]

    2.0より前の PostGIS ラスタは、エンベロープを基本にして、凸包ではありませんでした。空間インデクスを適切に働かせるには、エンベロープを基本にしたインデクスを削除して、凸包を元にしたインデクスに置き換えます。

  4. AddRasterConstraintsを用いてラスタ制約を適用します。

5.2. ラスタカタログ

PostGISが生成する、2つのラスタカタログのビューがあります。両方ともラスタテーブルの制約の中に埋め込まれる情報を用いています。

  1. raster_columns データベース内のラスタテーブルのカラム全てのカタログです。

  2. raster_overviews データベース内の、より詳細なテーブルのためのオーバビューを提供するラスタテーブルのカラム全てのカタログです。この種のテーブルは、ロード時に-lを指定した時に生成されます。

5.2.1. ラスタカラムカタログ

raster_columnsは、ラスタタイプのデータベースにおける全てのラスタテーブルカラムのカタログです。テーブルの制約を使ったビューなので、他のデータベースのバックアップからラスタテーブルをリストアしたとしても、情報は常に矛盾がありません。raster_columnsカタログには次のカラムがあります。

ローダを使わずにテーブルを生成したり、ロード時に-Cフラグを忘れたりした場合には、事後にAddRasterConstraintsで制約を強制でき、raster_columnsカタログは、ラスタタイルの共通の情報を登録します。

  • r_table_catalog テーブルが存在するデータベースです。これは常に現在のデータベースを読みます。

  • r_table_schema ラスタテーブルが属するデータベーススキーマです。

  • r_table_name raster table

  • r_raster_column ラスタタイプであるr_table_nameテーブル内のカラムです。PostGISには、1つのテーブルに複数のラスタカラムを持つことを妨げません。異なるラスタカラムを持つラスタテーブルが、ラスタカラム毎に複数回出現するテーブルを持つことができます。

  • srid ラスタの空間参照系識別番号です。「SPATIAL_REF_SYSテーブルと空間参照系」 にあるエントリであるべきです。

  • scale_x 地理空間座標とピクセルの間の拡大縮小係数です。これは、ラスタカラムのすべてのタイルが同じscale_xを持ち、制約が適用されている場合のみ出現します。詳細情報についてはST_ScaleXを参照してください。

  • scale_y 地理空間座標とピクセルの間の拡大縮小係数です。これは、ラスタカラムのすべてのタイルが同じscale_yを持ち、制約が適用されている場合のみ出現します。詳細情報についてはST_ScaleYを参照してください。

  • blocksize_x ラスタタイルごとの幅(横方向のピクセル数)です。詳細情報についてはST_Widthを参照してください。

  • blocksize_y ラスタタイルごとの高さ(縦方向のピクセル数)です。詳細情報についてはST_Heightを参照してください。

  • same_alignment 全てのラスタタイルが同じアラインメントを持っているかを示す真偽値です。詳細情報についてはST_SameAlignmentを参照してください。

  • regular_blocking テーブルに設定された真偽値の制約フラグで、タイルがオーバラップせず、かつアラインメント、ピクセルサイズ、SRID等が同じであるかどうかを示します。実際の評価は行いませんが、与えられた情報を利用するので、参考情報として使うべきものです。将来的には、確実にこの制約がかかるようにして、trueが返る時にはこの情報が正しいことを保証できるようにする予定です。

  • num_bands 格納されているラスタセットのタイル毎のバンド数です。ST_NumBandsで得られる情報と同じです。

  • pixel_types バンドごとのピクセルタイプを定義する配列です。この配列の要素数はバンド数と同じです。pixel_typesは、ST_BandPixelTypeで定義されるピクセルタイプのひとつを取ります。

  • nodata_values バンド毎のnodata_valueを示す倍精度浮動小数点数です。この配列の要素数はバンド数と同じです。これらの数は、バンド毎にほとんどの操作で無視すべきピクセル値を定義します。ST_BandNoDataValue で提供される情報と似ています。

  • extent ラスタ集合における全てのラスタ行の範囲です。集合の範囲を変更するデータを別途ロードする予定である場合、ロード前にDropRasterConstraints関数を実行して、ロード後にAddRasterConstraintsで制約を再適用します。

5.2.2. ラスタオーバビュー

raster_overviews は、オーバビューで使われるラスタテーブルカラムに関する情報のカタログで、オーバビューを用いる際に知っておくと便利な情報も持ちます。オーバビューテーブルはraster_columnsraster_overviewsの両方のカタログに入れられます。オーバビューもラスタのひとつであるのは確かですが、より高い解像度テーブルの解像度を落としたカリカチュアになるという特殊な目的を満たすためでもあるからです。ラスタをロードする際に-lスイッチを使うと、オーバビューが主ラスタテーブルと一緒に生成されます。

オーバビューテーブルには、他のラスタテーブルと同じ制約と、オーバビュー特有の制約となる追加情報があります。

[注記]

raster_overviewsの情報はraster_columnsとは重複しません。raster_columnsにあるオーバビューテーブルに関する情報が必要な場合は、raster_overviewsraster_columnsを結合すると、必要な情報の集合を完全に取得することができます。

オーバビューの主たる理由は次の2つです。

  1. ズームアウトした際の地図表示を早くするために、主テーブルの低解像度表現が一般的に使われます。

  2. レコード数が少なく、ピクセル毎の適用範囲が広いため、高解像度の元テーブルより計算が一般的に早くなります。計算は高解像度テーブルより精度は落ちますが、大まかな計算には十分でありえます。

raster_overviewsカタログには、次の情報のカラムがあります。

  • o_table_catalog オーバビューテーブルが存在するデータベースです。常に現在のデータベースを読みます。

  • o_table_schema オーバビューラスタテーブルが属するデータベーススキーマです。

  • o_table_name ラスタオーバビューテーブル名です。

  • o_raster_column オーバビューテーブル内のラスタカラムです。

  • r_table_catalog このオーバビューの元となるラスタテーブルのデータベースです。常に現在のデータベースを読みます。

  • r_table_schema このオーバビューの元となるラスタテーブルが属するデータベーススキーマです。

  • r_table_name このオーバビューの元となるラスタテーブルです。

  • r_raster_column このオーバビューの元となるラスタカラムです。

  • overview_factor - オーバビューテーブルのピラミッドレベルです。高い数字ほど解像度が低くなります。raster2pgsqlは、画像のフォルダを渡された場合は、分割して、イメージファイルのオーバビューの計算とロードを行います。レベル1は元ファイルと同じです。レベル2は、元ファイルの4分の1になります。たとえば、5000x5000ピクセルの画像ファイルのフォルダがあるとして、125x125に分ける場合、画像ファイルごとに(5000*5000)/(125*125) = 1600行のレコードを持ち、o_2テーブル(レベル2)はceiling(1600/Power(2,2)) = 400行、o_3(レベル3)ではceiling(1600/Power(2,3) ) = 200行のレコードを持ちます。 ピクセルがタイルサイズで割り切れない場合、スクラップタイル(完全には値が入っていない)が得られます。raster2pgsqlによって生成される個々のオーバビュータイルは、元となるラスタと同じピクセル数を持ち、個々のピクセルの表現範囲(オリジナルの Power(2,overview_factor)ピクセル分)が低い解像度になっている点に注意して下さい。

5.3. PostGISラスタを使ったカスタムアプリケーションの構築

PostGISラスタには、対応イメージ書式のラスタをレンダリングするSQL関数があり、レンダリングを行うための多数の選択肢があります。たとえば、Rendering PostGIS Raster graphics with LibreOffice Base Reportsで例を挙げている通り、OpenOffice/LibreOfficeを使うことができます。さらに、ここで示すように、幅広い言語で使うことができます。

5.3.1. ST_AsPNG を他の関数とあわせて使った PHP 出力例

本節では、PHP の PostgreSQL ドライバと ST_AsGDALRaster 等の関数を使って、HTML img タグに埋め込むことができる PHP リクエストストリームにラスタの 1, 2, 3 バンドを出力する方法を示します

サンプルクエリでは、 指定したWGS84バウンディングボックスにインタセクトするタイルを取って、 ST_Unionでインタセクトしたタイルを結合して全てのバンドを返し、ST_Transformでユーザ指定投影法に変換し、ST_AsPNGを使ってPNGで結果を出力するためのラスタ関数群全体をまとめる方法を示します。

後に示すスクリプトは、

http://mywebserver/test_raster.php?srid=2249

で、マサチューセッツ州平面(フィート単位)のラスタ画像を取得します。

<?php
/** test_raster.php コンテント **/
$conn_str ='dbname=mydb host=localhost port=5432 user=myuser password=mypwd';
$dbconn = pg_connect($conn_str);
header('Content-Type: image/png');  
/** 投影法が指定されたらそれを使います。
    指定されないなら、マサチューセッツ州平面(メートル) を使います。 **/
if (!empty( $_REQUEST['srid'] ) && is_numeric( $_REQUEST['srid']) ){
		$input_srid = intval($_REQUEST['srid']);
}
else { $input_srid = 26986; }
/** PostgreSQL 9.0以上ではbytea_outputの設定が必要でしょう。
    8.4 では不要です。 **/
$sql = "set bytea_output='escape';
SELECT ST_AsPNG(ST_Transform(
			ST_AddBand(ST_Union(rast,1), ARRAY[ST_Union(rast,2),ST_Union(rast,3)])
				,$input_srid) ) As new_rast
 FROM aerials.boston 
	WHERE 
	 ST_Intersects(rast, ST_Transform(ST_MakeEnvelope(-71.1217, 42.227, -71.1210, 42.218,4326),26986) )"; 
$result = pg_query($sql);
$row = pg_fetch_row($result);
pg_free_result($result);
if ($row === false) return;
echo pg_unescape_bytea($row[0]);
?>

5.3.2. ST_AsPNGを他の関数とあわせて使ったASP.NET C#出力例

本節では、Npgsql PostgreSQL .NETドライバとST_AsGDALRaster等の関数を使って、HTML imgタグに埋め込むことができるように、ラスタの 1, 2, 3 バンドを出力する方法を示します。

この例ではNpgsql .NET PostgreSQLドライバが必要です。最新版はhttp://npgsql.projects.postgresql.org/ あります。最新版をダウンロードして、ASP.NET の binフォルダに入れるだけでうまくいきます。

サンプルクエリでは、指定したWGS84バウンディングボックスにインタセクトするタイルを取り、ST_Unionでインタセクトしたタイルを結合して全てのバンドを返し、ST_Transformでユーザ指定投影法に変換し、ST_AsPNGを使ってPNGで結果を出力するためのラスタ関数群全体をまとめる方法を示します。

この例はC#で実装している点を除いては「ST_AsPNG を他の関数とあわせて使った PHP 出力例」と同じです。

後に示すスクリプトは、

http://mywebserver/TestRaster.ashx?srid=2249

で、マサチューセッツ州平面(フィート単位)のラスタ画像を取得します。

 -- web.config 接続文字列部 --
<connectionStrings>
    <add name="DSN" 
        connectionString="server=localhost;database=mydb;Port=5432;User Id=myuser;password=mypwd"/>
</connectionStrings>
// Code for TestRaster.ashx
<%@ WebHandler Language="C#" Class="TestRaster" %>
using System;
using System.Data;
using System.Web;
using Npgsql;

public class TestRaster : IHttpHandler
{
	public void ProcessRequest(HttpContext context)
	{
		
		context.Response.ContentType = "image/png";
		context.Response.BinaryWrite(GetResults(context));
		
	}

	public bool IsReusable {
		get { return false; }
	}

	public byte[] GetResults(HttpContext context)
	{
		byte[] result = null;
		NpgsqlCommand command;
		string sql = null;
		int input_srid = 26986;
        try {
		    using (NpgsqlConnection conn = new NpgsqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["DSN"].ConnectionString)) {
			    conn.Open();

                if (context.Request["srid"] != null)
                {
                    input_srid = Convert.ToInt32(context.Request["srid"]);  
                }
                sql = @"SELECT ST_AsPNG(
                            ST_Transform(
			                ST_AddBand(
                                ST_Union(rast,1), ARRAY[ST_Union(rast,2),ST_Union(rast,3)])
				                    ,:input_srid) ) As new_rast 
                        FROM aerials.boston 
	                        WHERE 
	                            ST_Intersects(rast, 
                                    ST_Transform(ST_MakeEnvelope(-71.1217, 42.227, -71.1210, 42.218,4326),26986) )";
			    command = new NpgsqlCommand(sql, conn);
                command.Parameters.Add(new NpgsqlParameter("input_srid", input_srid));
           
			
			    result = (byte[]) command.ExecuteScalar();
                conn.Close();
			}

		}
        catch (Exception ex)
        {
            result = null;
            context.Response.Write(ex.Message.Trim());
        }
		return result;
	}
}

5.3.3. ラスタクエリを画像ファイルとして出力するJavaコンソールアプリケーション

ひとつのイメージを取って指定したファイルに出力する、Javaコンソールアプリケーションです。

最新のPostgreSQL JDBC ドライバはhttp://jdbc.postgresql.org/download.htmlから取得できます。

後に示すコードをコンパイルします。コマンドは次の通りです。

set env CLASSPATH .:..\postgresql-9.0-801.jdbc4.jar
javac SaveQueryImage.java
jar cfm SaveQueryImage.jar Manifest.txt *.class

次のようにコマンドラインから呼び出します。

java -jar SaveQueryImage.jar "SELECT ST_AsPNG(ST_AsRaster(ST_Buffer(ST_Point(1,5),10, 'quad_segs=2'),150, 150, '8BUI',100));" "test.png" 
 -- Manifest.txt --
Class-Path: postgresql-9.0-801.jdbc4.jar
Main-Class: SaveQueryImage
// Code for SaveQueryImage.java
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.io.*;

public class SaveQueryImage {
  public static void main(String[] argv) {
      System.out.println("Checking if Driver is registered with DriverManager.");
      
      try {
        //java.sql.DriverManager.registerDriver (new org.postgresql.Driver());
        Class.forName("org.postgresql.Driver");
      } 
      catch (ClassNotFoundException cnfe) {
        System.out.println("Couldn't find the driver!");
        cnfe.printStackTrace();
        System.exit(1);
      }
      
      Connection conn = null;
      
      try {
        conn = DriverManager.getConnection("jdbc:postgresql://localhost:5432/mydb","myuser", "mypwd");
        conn.setAutoCommit(false);

        PreparedStatement sGetImg = conn.prepareStatement(argv[0]);
		
        ResultSet rs = sGetImg.executeQuery();
		
		FileOutputStream fout;
		try
		{
			rs.next();
			/** ユーザが指定するファイルへの出力 **/
			fout = new FileOutputStream(new File(argv[1]) );
			fout.write(rs.getBytes(1));
			fout.close();
		}
		catch(Exception e)
		{
			System.out.println("Can't create file");
			e.printStackTrace();
		}
		
        rs.close();
		sGetImg.close();
        conn.close();
      } 
      catch (SQLException se) {
        System.out.println("Couldn't connect: print out a stack trace and exit.");
        se.printStackTrace();
        System.exit(1);
      }   
  }
}

5.3.4. PLPython を使って SQL を介して画像をダンプする

これは、サーバディレクトリ内でレコードごとにファイルを生成するPythonストアド関数です。

// PLPython PostgreSQLストアドプロシージャです。
// PL/Pythonが必要です。
CREATE OR REPLACE FUNCTION write_file (param_bytes bytea, param_filepath text)
RETURNS text
AS $$
f = open(param_filepath, 'wb+')
f.write(param_bytes)
return param_filepath
$$ LANGUAGE plpythonu;
-- 5つの画像をPostgreSQLサーバに可変サイズで描きます。
-- PostgreSQLデーモンのアカウントにフォルダへの書き込み権限が必要ですので
-- ご注意ください。
-- 生成されたファイル名をエコーバックします。
 SELECT write_file(ST_AsPNG(
	ST_AsRaster(ST_Buffer(ST_Point(1,5),j*5, 'quad_segs=2'),150*j, 150*j, '8BUI',100)),
	 'C:/temp/slices'|| j || '.png')
	 FROM generate_series(1,5) As j;
	 
     write_file
---------------------
 C:/temp/slices1.png
 C:/temp/slices2.png
 C:/temp/slices3.png
 C:/temp/slices4.png
 C:/temp/slices5.png	 

5.3.5. PSQLでラスタを出力する

悲しいことにPSQLには、組み込み機能を用いてバイナリを出力するのは簡単ではありません。これは、ちょっとしたハックです。Clever Trick Challenge -- Outputting bytea with psqlで提案されている概要に基づいています。レガシー気味になっているPostgreSQLラージオブジェクトのサポートに乗っているものです。最初の起動時に、PSQLはデータベースに接続します。

この方法はPythonの場合と違い、ローカル機にファイルが生成されます

SELECT oid, lowrite(lo_open(oid, 131072), png) As num_bytes
 FROM 
 ( VALUES (lo_create(0), 
   ST_AsPNG( (SELECT rast FROM aerials.boston WHERE rid=1) ) 
  ) ) As v(oid,png);
-- 次のような出力が得られます --
   oid   | num_bytes
---------+-----------
 2630819 |     74860
 
-- 続いて、oidに注意して'C:/temp/aerial_smap.png'を
-- ローカル機のファイルパスに置き換えたうえで
-- 次を実行します。
 \lo_export 2630819 'C:/temp/aerial_samp.png'
 
-- データベース上のラージオブジェクトストレージから
-- ファイルを削除します。
SELECT lo_unlink(2630819);