第 9 章。栅格数据管理、查询和应用

目录
9.1. 加载和创建栅格
9.1.1. 使用 raster2pgsql 加载栅格
9.1.2. 使用 PostGIS 栅格函数创建栅格
9.1.3. 使用“out db”云栅格
9.2. 栅格目录
9.2.1. 栅格列目录
9.2.2. 栅格概览
9.3. 使用 PostGIS 栅格构建自定义应用程序
9.3.1. PHP 示例使用 ST_AsPNG 与其他栅格函数一起输出
9.3.2. ASP.NET C# 示例使用 ST_AsPNG 与其他栅格函数一起输出
9.3.3. 将栅格查询作为图像文件输出的 Java 控制台应用程序
9.3.4. 使用 PLPython 通过 SQL 导出图像
9.3.5. 使用 PSQL 输出栅格

9.1. 加载和创建栅格

对于大多数用例,您将通过使用打包的 raster2pgsql 栅格加载器加载现有栅格文件来创建 PostGIS 栅格。

9.1.1. 使用 raster2pgsql 加载栅格

raster2pgsql 是一个栅格加载器可执行文件,它将 GDAL 支持的栅格格式加载到适合加载到 PostGIS 栅格表的 SQL 中。它能够加载栅格文件文件夹,以及创建栅格的概览。

由于 raster2pgsql 通常作为 PostGIS 的一部分进行编译(除非您自己编译 GDAL 库),因此可执行文件支持的栅格类型将与 GDAL 依赖库中编译的类型相同。要获取特定 raster2pgsql 支持的栅格类型列表,请使用 -G 开关。

[Note]

当从一组对齐的栅格创建特定因子的概览时,概览可能无法对齐。访问 http://trac.osgeo.org/postgis/ticket/1764 查看概览未对齐的示例。

9.1.1.1. 示例用法

使用加载器创建输入文件并将其以 100x100 个瓦片为单位上传的示例会话可能如下所示

# -s use srid 4326
# -I create spatial index
# -C use standard raster constraints
# -M vacuum analyze after load
# *.tif load all these files
# -F include a filename column in the raster table
# -t tile the output 100x100
# public.demelevation load into this table
raster2pgsql -s 4326 -I -C -M -F -t 100x100 *.tif public.demelevation > elev.sql

# -d connect to this database
# -f read this file after connecting
psql -d gisdb -f elev.sql
[Note]

如果您没有在目标表名中指定模式,则表将在您连接的数据库或用户的默认模式中创建。

可以使用 UNIX 管道在一步骤中完成转换和上传

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

将马萨诸塞州州平面米航空瓦片加载到名为 aerial 的模式中,并创建一个完整视图、2 级和 4 级概览表,使用复制模式进行插入(没有中间文件,直接到数据库),并且 -e 不强制所有操作在一个事务中(如果您想立即查看表中的数据,而无需等待,这很有用)。将栅格分成 128x128 像素的瓦片,并应用栅格约束。使用复制模式而不是表插入。(-F) 包含一个名为 filename 的字段,用于保存切片来自的瓦片的名称。

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
--get a list of raster types supported:
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
  ...
  Arc/Info Export E00 GRID
  ZMap Plus Grid
  NOAA NGS Geoid Height Grids

9.1.1.2. raster2pgsql 选项

-?

显示帮助屏幕。如果您没有传入任何参数,也会显示帮助信息。

-G

打印支持的栅格格式。

(c|a|d|p) 这些选项是互斥的

-c

创建新表并用栅格填充它,这是默认模式

-a

将栅格追加到现有表中。

-d

删除表,创建新表并用栅格填充它

-p

准备模式,只创建表。

栅格处理:应用约束以确保在栅格目录中正确注册

-C

应用栅格约束 - srid、像素大小等,以确保栅格在 raster_columns 视图中正确注册。

-x

禁用设置最大范围约束。仅在也使用 -C 标志时应用。

-r

设置用于常规阻塞的约束(空间唯一和覆盖瓦片)。仅在也使用 -C 标志时应用。

栅格处理:用于操作输入栅格数据集的可选参数

-s <SRID>

为输出栅格分配指定的 SRID。如果未提供或为零,将检查栅格的元数据以确定合适的 SRID。

-b BAND

从栅格中提取的波段的索引(从 1 开始)。对于多个波段索引,用逗号 (,) 分隔。如果未指定,将提取栅格的所有波段。

-t TILE_SIZE

将栅格切割成瓦片,每个表行插入一个瓦片。 TILE_SIZE 表示为 WIDTHxHEIGHT 或设置为值“auto”,以允许加载器使用第一个栅格计算合适的瓦片大小并应用于所有栅格。

-P

填充最右边和最下面的瓦片,以确保所有瓦片具有相同的宽度和高度。

-R, --register

将栅格注册为文件系统(数据库外)栅格。

仅将栅格的元数据和指向栅格的路径位置存储在数据库中(而不是像素)。

-l OVERVIEW_FACTOR

创建栅格的概览。对于多个因子,用逗号 (,) 分隔。概览表名遵循模式 o_overview factor_table,其中 overview factor 是数值概览因子的占位符,table 被替换为基本表名。创建的概览存储在数据库中,不受 -R 影响。请注意,您生成的 sql 文件将包含主表和概览表。

-N NODATA

在没有 NODATA 值的波段上使用的 NODATA 值。

用于操作数据库对象的可选参数

-f COLUMN

指定目标栅格列的名称,默认值为“rast”。

-F

添加一个包含文件名的列。

-n COLUMN

指定文件名列的名称。隐含 -F。

-q

将 PostgreSQL 标识符括在引号中。

-I

在栅格列上创建 GiST 索引。

-M

对栅格表进行真空分析。

-k

保留空瓦片,并跳过每个栅格波段的 NODATA 值检查。请注意,您可以节省检查时间,但最终可能会在数据库中留下更多垃圾行,这些垃圾行不会被标记为空瓦片。

-T tablespace

指定新表的表空间。请注意,除非还使用 -X 标志,否则索引(包括主键)将继续使用默认表空间。

-X tablespace

指定表的新索引的表空间。这适用于主键和空间索引(如果使用了 -I 标志)。

-Y max_rows_per_copy=50

使用 copy 语句而不是 insert 语句。可以选择指定 max_rows_per_copy;未指定时默认为 50。

-e

单独执行每个语句,不要使用事务。

-E ENDIAN

控制生成的栅格二进制输出的字节序;指定 0 表示 XDR,指定 1 表示 NDR(默认);目前仅支持 NDR 输出。

-V version

指定输出格式的版本。默认值为 0。目前仅支持 0。

9.1.2. 使用 PostGIS 栅格函数创建栅格

在许多情况下,您可能希望直接在数据库中创建栅格和栅格表。有许多函数可以做到这一点。以下是需要遵循的一般步骤。

  1. 创建一个包含栅格列的表,以保存新的栅格记录,这可以通过以下方式完成

    CREATE TABLE myrasters(rid serial primary key, rast raster);
  2. 有许多函数可以帮助您实现这一目标。如果您创建的栅格不是其他栅格的派生,则需要从 ST_MakeEmptyRaster 开始,然后使用 ST_AddBand

    您还可以从几何图形创建栅格。要实现这一点,您需要使用 ST_AsRaster,可能还会使用其他函数,例如 ST_UnionST_MapAlgebraFct,或任何其他地图代数函数族。

    从现有表创建新的栅格表还有更多选项。例如,您可以使用 ST_Transform 从现有表创建不同投影的栅格表。

  3. 完成初始表填充后,您需要使用类似以下命令在栅格列上创建空间索引。

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

    请注意使用 ST_ConvexHull,因为大多数栅格运算符都基于栅格的凸包。

    [Note]

    PostGIS 栅格的 2.0 之前版本基于包络而不是凸包。为了使空间索引正常工作,您需要删除这些索引并替换为基于凸包的索引。

  4. 使用 AddRasterConstraints 应用栅格约束。

9.1.3. 使用“out db”云栅格

raster2pgsql 工具使用 GDAL 访问栅格数据,并且可以利用 GDAL 的一项关键功能:能够读取存储在云“对象存储”(例如 AWS S3、Google Cloud Storage)中的 远程 栅格数据。

有效使用云存储的栅格需要使用“云优化”格式。最知名和最广泛使用的格式是“云优化 GeoTIFF”格式。使用非云格式,例如 JPEG 或未平铺的 TIFF,会导致性能非常差,因为系统每次需要访问子集时都必须下载整个栅格。

首先,将您的栅格加载到您选择的云存储中。加载完成后,您将拥有一个 URI 来访问它,可以是“http” URI,也可以是特定于服务的 URI(例如,“s3://bucket/object”)。要访问非公开存储桶,您需要提供 GDAL 配置选项来验证您的连接。请注意,此命令是从云栅格 读取 数据并 写入 数据库。

AWS_ACCESS_KEY_ID=xxxxxxxxxxxxxxxxxxxx \
AWS_SECRET_ACCESS_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx \
raster2pgsql \
  -s 990000 \
  -t 256x256 \
  -I \
  -R \
  /vsis3/your.bucket.com/your_file.tif \
  your_table \
  | psql your_db

加载表后,您需要通过设置两个权限来授予数据库从远程栅格读取的权限:postgis.enable_outdb_rasterspostgis.gdal_enabled_drivers

SET postgis.enable_outdb_rasters = true;
SET postgis.gdal_enabled_drivers TO 'ENABLE_ALL';
    

要使更改持久生效,请直接在您的数据库上设置它们。您需要重新连接才能体验新设置。

ALTER DATABASE your_db SET postgis.enable_outdb_rasters = true;
ALTER DATABASE your_db SET postgis.gdal_enabled_drivers TO 'ENABLE_ALL';
    

对于非公开栅格,您可能需要提供访问密钥才能读取云栅格。您用于写入 raster2pgsql 调用的相同密钥可以设置为在数据库内部使用,使用 postgis.gdal_vsi_options 配置。请注意,可以通过空格分隔 key=value 对来设置多个选项。

SET postgis.gdal_vsi_options = 'AWS_ACCESS_KEY_ID=xxxxxxxxxxxxxxxxxxxx
AWS_SECRET_ACCESS_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';

数据加载完毕并设置权限后,您可以像操作其他栅格表一样操作栅格表,使用相同的函数。数据库将在需要读取像素数据时处理连接到云数据的全部机制。

9.2. 栅格目录

PostGIS 附带两个栅格目录视图。这两个视图都利用了栅格表约束中嵌入的信息。因此,目录视图始终与表中的栅格数据一致,因为约束是强制执行的。

  1. raster_columns 此视图将数据库中所有栅格表列编入目录。

  2. raster_overviews 此视图将数据库中所有用作更精细表概览的栅格表列编入目录。当您在加载过程中使用 -l 开关时,将生成此类型的表。

9.2.1. 栅格列目录

raster_columns 是数据库中所有类型为栅格的栅格表列的目录。它是一个利用表约束的视图,因此即使您从另一个数据库的备份中恢复一个栅格表,信息也始终保持一致。以下列存在于 raster_columns 目录中。

如果您创建的表不是使用加载器创建的,或者在加载过程中忘记指定 -C 标志,您可以使用 AddRasterConstraints 在事后强制执行约束,以便 raster_columns 目录注册有关栅格瓦片的通用信息。

  • r_table_catalog 表所在的数据库。这将始终读取当前数据库。

  • r_table_schema 栅格表所属的数据库模式。

  • r_table_name 栅格表

  • r_raster_column r_table_name 表中类型为栅格的列。PostGIS 中没有任何内容阻止您在每个表中拥有多个栅格列,因此有可能在每个表中使用不同的栅格列多次列出栅格表。

  • srid 栅格的空间参考标识符。应为 第 4.5 节,“空间参考系统” 中的条目。

  • scale_x 几何空间坐标与像素之间的缩放比例。仅当光栅列中的所有图块具有相同的 scale_x 且应用此约束时才可用。有关更多详细信息,请参阅 ST_ScaleX

  • scale_y 几何空间坐标与像素之间的缩放比例。仅当光栅列中的所有图块具有相同的 scale_y 且应用 scale_y 约束时才可用。有关更多详细信息,请参阅 ST_ScaleY

  • blocksize_x 每个光栅图块的宽度(像素数)。有关更多详细信息,请参阅 ST_Width

  • blocksize_y 每个光栅图块的高度(像素数)。有关更多详细信息,请参阅 ST_Height

  • same_alignment 如果所有光栅图块具有相同的对齐方式,则为布尔值 true。有关更多详细信息,请参阅 ST_SameAlignment

  • regular_blocking 如果光栅列具有空间唯一和覆盖图块约束,则值为 TRUE。否则,将为 FALSE。

  • num_bands 光栅集中每个图块中的波段数。这与 ST_NumBands 提供的信息相同。

  • pixel_types 定义每个波段像素类型的数组。此数组中的元素数量与波段数量相同。像素类型是在 ST_BandPixelType 中定义的以下类型之一。

  • nodata_values 表示每个波段 nodata_value 的双精度数字数组。此数组中的元素数量与波段数量相同。这些数字定义每个波段的像素值,这些像素值应在大多数操作中被忽略。这与 ST_BandNoDataValue 提供的信息类似。

  • out_db 布尔标志数组,指示光栅波段数据是否保存在数据库外部。此数组中的元素数量与波段数量相同。

  • extent 这是光栅集中所有光栅行的范围。如果您计划加载更多数据,这将改变集合的范围,您需要在加载之前运行 DropRasterConstraints 函数,然后在加载后使用 AddRasterConstraints 重新应用约束。

  • spatial_index 如果光栅列具有空间索引,则为布尔值 true。

9.2.2. 栅格概览

raster_overviews 目录了用于概览的栅格表列的信息,以及在使用概览时需要了解的有关这些列的附加信息。概览表在 raster_columnsraster_overviews 中都有目录,因为它们本身就是栅格,但还具有作为更高分辨率表的低分辨率概览的额外特殊用途。当您在加载栅格时使用 -l 开关时,这些概览表会与主栅格表一起生成,或者可以使用 AddOverviewConstraints 手动生成。

概览表包含与其他栅格表相同的约束,以及特定于概览的附加信息性约束。

[Note]

raster_overviews 中的信息不会重复 raster_columns 中的信息。如果您需要有关 raster_columns 中存在的概览表的信息,可以将 raster_overviewsraster_columns 连接在一起,以获取您需要的完整信息集。

概览的主要原因有两个:

  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 个图块。例如,如果您有一个包含 5000x5000 像素图像文件的文件夹,并且您选择将它们分成 125x125 的块,那么对于每个图像文件,您的基本表将有 (5000*5000)/(125*125) 个记录 = 1600 个,您的 (l=2) o_2 表将有 ceiling(1600/Power(2,2)) = 400 行,您的 (l=3) o_3 将有 ceiling(1600/Power(2,3) ) = 200 行。如果您的像素不能被图块大小整除,您将得到一些废弃的图块(未完全填充的图块)。请注意,raster2pgsql 生成的每个概览图块都具有与其父图块相同数量的像素,但解析度较低,其中每个像素代表原始文件的 (Power(2,overview_factor) 个像素。

9.3. 使用 PostGIS Raster 构建自定义应用程序

PostGIS Raster 提供了 SQL 函数来渲染已知图像格式的栅格,这为您提供了许多渲染选项。例如,您可以使用 OpenOffice/LibreOffice 进行渲染,如 使用 LibreOffice Base Reports 渲染 PostGIS Raster 图形 中所示。此外,您还可以使用本节中所示的多种语言。

9.3.1. PHP 示例使用 ST_AsPNG 与其他栅格函数一起输出

在本节中,我们将演示如何使用 PHP PostgreSQL 驱动程序和 ST_AsGDALRaster 函数族将栅格的波段 1、2、3 输出到 PHP 请求流,然后可以将其嵌入到 img src html 标签中。

此示例查询演示了如何将多个栅格函数组合在一起,以获取与特定 wgs 84 边界框相交的所有图块,然后使用 ST_Union 将相交的图块合并在一起,返回所有波段,使用 ST_Transform 转换为用户指定的投影,然后使用 ST_AsPNG 将结果输出为 png。

您可以使用以下方法调用:

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

以获取马萨诸塞州平面英尺的栅格图像。

<?php
/** contents of 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 a particular projection was requested use it otherwise use mass state plane meters **/
if (!empty( $_REQUEST['srid'] ) && is_numeric( $_REQUEST['srid']) ){
		$input_srid = intval($_REQUEST['srid']);
}
else { $input_srid = 26986; }
/** The set bytea_output may be needed for PostgreSQL 9.0+, but not for 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]);
?>

9.3.2. ASP.NET C# 示例,使用 ST_AsPNG 与其他栅格函数一起输出

在本节中,我们将演示如何使用 Npgsql PostgreSQL .NET 驱动程序和 ST_AsGDALRaster 函数族将栅格的波段 1、2、3 输出到 PHP 请求流,然后可以将其嵌入到 img src html 标签中。

此练习需要使用 npgsql .NET PostgreSQL 驱动程序,您可以从 http://npgsql.projects.postgresql.org/ 获取最新版本。只需下载最新版本并将其放入您的 ASP.NET bin 文件夹中,您就可以开始了。

此示例查询演示了如何将多个栅格函数组合在一起,以获取与特定 wgs 84 边界框相交的所有图块,然后使用 ST_Union 将相交的图块合并在一起,返回所有波段,使用 ST_Transform 转换为用户指定的投影,然后使用 ST_AsPNG 将结果输出为 png。

此示例与 第 9.3.1 节,“PHP 示例,使用 ST_AsPNG 与其他栅格函数一起输出” 中的示例相同,只是在 C# 中实现。

您可以使用以下方法调用:

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

以获取马萨诸塞州平面英尺的栅格图像。

 -- web.config connection string section --
<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;
	}
}

9.3.3. 将栅格查询作为图像文件输出的 Java 控制台应用程序

这是一个简单的 Java 控制台应用程序,它接受一个返回一个图像的查询,并将结果输出到指定的文件。

您可以从 https://jdbc.postgresql.ac.cn/download.html 下载最新的 PostgreSQL JDBC 驱动程序。

您可以使用类似以下命令的命令编译以下代码:

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();
			/** Output to file name requested by user **/
			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);
      }
  }
}

9.3.4. 使用 PLPython 通过 SQL 导出图像

这是一个 plpython 存储函数,它为每个记录在服务器目录中创建一个文件。需要您安装 plpython。应该与 plpythonu 和 plpython3u 都能正常工作。

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;
--write out 5 images to the PostgreSQL server in varying sizes
-- note the postgresql daemon account needs to have write access to folder
-- this echos back the file names created;
 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

9.3.5. 使用 PSQL 输出栅格

遗憾的是,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);
-- you'll get an output something like --
   oid   | num_bytes
---------+-----------
 2630819 |     74860

-- next note the oid and do this replacing the c:/test.png to file path location
-- on your local computer
 \lo_export 2630819 'C:/temp/aerial_samp.png'

-- this deletes the file from large object storage on db
SELECT lo_unlink(2630819);