Chapter 10. Dati raster: gestione, interrogazione e applicazioni

Table of Contents

10.1. Caricare e creare raster

Nella maggior parte dei casi, creerete i raster PostGIS caricando file esterni tramite il raster loader raster2pgsql compreso nell'installazione.

10.1.1. Usare raster2pgsql per caricare i raster

The raster2pgsql is a raster loader executable that loads GDAL supported raster formats into SQL suitable for loading into a PostGIS raster table. It is capable of loading folders of raster files as well as creating overviews of rasters.

Since the raster2pgsql is compiled as part of PostGIS most often (unless you compile your own GDAL library), the raster types supported by the executable will be the same as those compiled in the GDAL dependency library. To get a list of raster types your particular raster2pgsql supports use the -G switch.

[Note]

When creating overviews of a specific factor from a set of rasters that are aligned, it is possible for the overviews to not align. Visit http://trac.osgeo.org/postgis/ticket/1764 for an example where the overviews do not align.

10.1.1.1. Example Usage

Una sessione di esempio che utilizzi il loader per creare un file di input e per caricarlo a pezzi di tile 100x100 potrebbe essere il seguente:

# -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]

If you do not specify the schema as part of the target table name, the table will be created in the default schema of the database or user you are connecting with.

La conversione e il caricamento possono essere eseguiti in un unico passaggio tramite le pipe UNIX:

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

Load rasters Massachusetts state plane meters aerial tiles into a schema called aerial and create a full view, 2 and 4 level overview tables, use copy mode for inserting (no intermediary file just straight to db), and -e don't force everything in a transaction (good if you want to see data in tables right away without waiting). Break up the rasters into 128x128 pixel tiles and apply raster constraints. Use copy mode instead of table insert. (-F) Include a field called filename to hold the name of the file the tiles were cut from.

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

Il parametro -G restituirà un elenco tipo

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

10.1.1.2. raster2pgsql options

-?

Mostra una schermata di aiuto. L'aiuto verra mostrato inoltre se non assegnate alcun parametro.

-G

Elenca i formati raster supportati.

(c|a|d|p) sono opzioni che is escludono una con l'altra:

-c

Crea una nuova tabella e carica in questa il/i raster. Questa è la modalita di default

-a

Accoda il o i raster a una tabella esistente.

-d

Elimina la tabella, ne crea una nuova e vi carica il/i dati raster

-p

Modalità di preparazione. Crea solamente la tabella.

Raster processing: Applying constraints for proper registering in raster catalogs

-C

Apply raster constraints -- srid, pixelsize etc. to ensure raster is properly registered in raster_columns view.

-x

Disable setting the max extent constraint. Only applied if -C flag is also used.

-r

Set the constraints (spatially unique and coverage tile) for regular blocking. Only applied if -C flag is also used.

Elaborazioni raster: parametri opzionali utilizzati nel trattamento dei dati raster in ingresso

-s <SRID>

Assegna lo SRID specificato al raster in uscita. Se non fornito o uguale a zero, saranno controllati i metadati del raster per determinare uno SRID appropriato.

-b BAND

Indice (a partire da 1) della banda da estrarre dal raster. Per specificare più di un indice di banda, separare con una virgola (,). Se non specificato, saranno estratte tutte le bande.

-t TILE_SIZE

Cut raster into tiles to be inserted one per table row. TILE_SIZE is expressed as WIDTHxHEIGHT or set to the value "auto" to allow the loader to compute an appropriate tile size using the first raster and applied to all rasters.

-P

Pad right-most and bottom-most tiles to guarantee that all tiles have the same width and height.

-R, --register

Register the raster as a filesystem (out-db) raster.

Nel database vengono salvati solo i metadati e il percorso del raster (non i pixel).

-l OVERVIEW_FACTOR

Create overview of the raster. For more than one factor, separate with comma(,). Overview table name follows the pattern o_overview factor_table, where overview factor is a placeholder for numerical overview factor and table is replaced with the base table name. Created overview is stored in the database and is not affected by -R. Note that your generated sql file will contain both the main table and overview tables.

-N NODATA

Valore da usare come NODATA per le bande senza un valore NODATA.

Parametri opzionali usati per la manipolazione di oggetti del database

-f COLUMN

Specifica il nome della colonna di destinazione per i raster. Il default è 'rast'.

-F

Aggiunge una colonna con il nome del file

-n COLUMN

Specify the name of the filename column. Implies -F.

-q

Wrap PostgreSQL identifiers in quotes.

-I

Crea un indice GiST sulla colonna raster.

-M

Vacuum analyze the raster table.

-k

Keeps empty tiles and skips NODATA value checks for each raster band. Note you save time in checking, but could end up with far more junk rows in your database and those junk rows are not marked as empty tiles.

-T tablespace

Specificare il tablespace per la nuova tabella. Notare che gli indici (compresa la chiave primaria) useranno sempre il tablespace di default, a meno che non venga usato anche il flag -X.

-X tablespace

Specifica il tablespace per il nuovo indice della tabella. Si applica alla chiave primaria e all'indice spaziale se viene usato il flag -I

-Y max_rows_per_copy=50

Use copy statements instead of insert statements. Optionally specify max_rows_per_copy; default 50 when not specified.

-e

Esegui ogni comando individualmente, non utilizzare una transazione.

-E ENDIAN

Controlla l'ordine dei byte prodotti nell'output binario del raster: specificare 0 per XDR e 1 per NDR (il default). Al momento viene supportato solo lo NDR.

-V version

Specifica la versione del formato in uscita. Il default è 0. Al momento 0 è l'unico supportato.

10.1.2. Creazione di raster tramite le funzioni raster di PostGIS

In varie occasioni vorrete creare raster e tabelle raster direttamente nel database. Per questo esiste una pletora di funzioni. Questi sono i passi generali da seguire.

  1. Creare una tabella con una colonna raster per contenere i nuovi valori raster può essere ottenuto da:

    CREATE TABLE myrasters(rid serial primary key, rast raster);
  2. Esistono molte funzioni per assitervi verso questo obiettivo. Se state creando un raster non derivato da altri raster, inizierete con: ST_MakeEmptyRaster, seguito da ST_AddBand

    Potete anche creare raster a partire dalle geometria. Per questo userete ST_AsRaster, magari accompagnato da altre funzioni come ST_Union o ST_MapAlgebraFct, o qualsiasi altra delle funzioni di algebra sulle mappe.

    Vi sono poi ancora più opzioni per creare nuove tabelle raster a partire da tabelle esistenti. Per esempio potete creare una tabella raster in una proiezione diversa da una tabella esistente usando ST_Transform

  3. Una volta inseriti dei valori iniziali nella tabella, vorrete creare un indice spaziale sulla colonna raster, con un comando tipo:

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

    Note the use of ST_ConvexHull since most raster operators are based on the convex hull of the rasters.

    [Note]

    Pre-2.0 versions of PostGIS raster were based on the envelop rather than the convex hull. For the spatial indexes to work properly you'll need to drop those and replace with convex hull based index.

  4. Apply raster constraints using AddRasterConstraints

10.1.3. Using "out db" cloud rasters

The raster2pgsql tool uses GDAL to access raster data, and can take advantage of a key GDAL feature: the ability to read from rasters that are stored remotely in cloud "object stores" (e.g. AWS S3, Google Cloud Storage).

Efficient use of cloud stored rasters requires the use of a "cloud optimized" format. The most well-known and widely used is the "cloud optimized GeoTIFF" format. Using a non-cloud format, like a JPEG, or an un-tiled TIFF will result in very poor performance, as the system will have to download the entire raster each time it needs to access a subset.

First, load your raster into the cloud storage of your choice. Once it is loaded, you will have a URI to access it with, either an "http" URI, or sometimes a URI specific to the service. (e.g., "s3://bucket/object"). To access non-public buckets, you will need to supply GDAL config options to authenticate your connection. Note that this command is reading from the cloud raster and writing to the database.

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

Once the table is loaded, you need to give the database permission to read from remote rasters, by setting two permissions, postgis.enable_outdb_rasters and postgis.gdal_enabled_drivers.

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

To make the changes sticky, set them directly on your database. You will need to re-connect to experience the new settings.

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

For non-public rasters, you may have to provide access keys to read from the cloud rasters. The same keys you used to write the raster2pgsql call can be set for use inside the database, with the postgis.gdal_vsi_options configuration. Note that multiple options can be set by space-separating the key=value pairs.

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

Once you have the data loaded and permissions set you can interact with the raster table like any other raster table, using the same functions. The database will handle all the mechanics of connecting to the cloud data when it needs to read pixel data.

10.2. Cataloghi raster

Esistono due tipi di viste dei cataloghi raster fornite con PostGIS. Entrambe le viste utilizzano informazioni contenute nei dati sui limiti delle tabelle raster. Da ciò risulta che le viste dei cataloghi sono sempre consistenti con i dati raster nelle tabelle, dato che sono considerati i limiti di queste.

  1. raster_columns questa vista riporta il catalogo di tutte le colonne raster nel vostro database.

  2. raster_overviews questa vista elenca tutte le colonne raste di tabelle nel vostro database che sono utilizzate come vista d'insieme per una tabella con maggiori dettagli. Le tabelle di questo tipo sono generate quando utilizzate l'opzione -l durante il caricamento.

10.2.1. Catalogo delle colonne raster

La vista raster_columns è un catalogo di tutte le colonne di tabelle che nel vostro database sono di tipo raster. È una vista che utilizza i limiti applicati alle tabelle, per cui le informazioni sono sempre congruenti, anche se ripristinate una tabella raster dal backup di un altro database. Il catalogo raster_columns contiene le seguenti colonne.

Se non avete creato le tabelle con il loader o vi siete dimenticati di specificare l'opzione -C durante il caricamento, potete far applicare i limiti a cose fatte utilizzando AddRasterConstraints, di modo che il catalogo raster_columns registri le informazioni sulle vostre tile raster.

  • r_table_catalog Il database in cui si trova la tabella. Conterrà sempre il database corrente.

  • r_table_schema Lo schema database cui la tabella raster appartiene.

  • r_table_name tabella raster

  • r_raster_column la colonna nella tabella r_table_name che è di tipo raster. Nulla in PostGIS vi impedisce di avere più colonne raster per tabella, per cui è possibile avere una tabella raster elencata più volte con il riferimento ogni volta a una colonna raster differente..

  • srid L'identificatore del sistema di riferimento spaziale del raster. Dovrebbe essere una voce di Section 4.5, “Spatial Reference Systems”.

  • scale_x Il rapporto di scala tra le coordinate geometriche e il pixel, disponibile solo se tutte le tile nella colonna raster hanno lo stesso valore di scale_x e questo limite è applicato. Si rimanda è ST_ScaleX per ulteriori dettagli.

  • scale_y Il rapporto di scala tra le coordinate geometriche e il pixel, disponibile solo se tutte le tile nella colonna raster hanno lo stesso valore di scale_y e il vincolo su scale_y è applicato. Si rimanda a ST_ScaleY per ulteriori dettagli.

  • blocksize_x La larghezza (come numero di pixel in orizzontale) di ogni tile raster. Si rimanda a ST_Width per ulteriori dettagli.

  • blocksize_y L'altezza (number of pixels in verticale) di ogni tile raster. Si rimanda a ST_Height per ulteriori dettagli.

  • stesso_allineamento Variabile booleana pari a "vero" se tutte le tile raster hanno lo stesso allineamento. Si rimanda a ST_SameAlignment per ulteriori dettagli.

  • regular_blocking If the raster column has the spatially unique and coverage tile constraints, the value with be TRUE. Otherwise, it will be FALSE.

  • numero_bande Il numero delle bande in ogni tile del set di raster. Questa è la stessa informazione fornita da ST_NumBands

  • pixel_types Un vettore che definisce il tipo di pixel per ciascuna banda. In questo vettore avrete un numero di elementi pari al numero delle bande. I valori di pixel_types possono essere tra quelli definiti in ST_BandPixelType.

  • nodata_values Un vettore in doppia precisione che spefica i valori nodata_value per ciascuna banda. Avrete in questo vettore un numero di elementi pari al numero di bande. Questi numeri definiscono il valore del pixel che per ciascuna banda deve essere ignorato nella maggior parte delle operazioni. L'informazion è simile a quella fornita da ST_BandNoDataValue.

  • out_db An array of boolean flags indicating if the raster bands data is maintained outside the database. You will have the same number of elements in this array as you have number of bands.

  • extent This is the extent of all the raster rows in your raster set. If you plan to load more data that will change the extent of the set, you'll want to run the DropRasterConstraints function before load and then reapply constraints with AddRasterConstraints after load.

  • spatial_index A boolean that is true if raster column has a spatial index.

10.2.2. Raster Overviews

raster_overviews catalogs information about raster table columns used for overviews and additional information about them that is useful to know when utilizing overviews. Overview tables are cataloged in both raster_columns and raster_overviews because they are rasters in their own right but also serve an additional special purpose of being a lower resolution caricature of a higher resolution table. These are generated along-side the main raster table when you use the -l switch in raster loading or can be generated manually using AddOverviewConstraints.

Overview tables contain the same constraints as other raster tables as well as additional informational only constraints specific to overviews.

[Note]

The information in raster_overviews does not duplicate the information in raster_columns. If you need the information about an overview table present in raster_columns you can join the raster_overviews and raster_columns together to get the full set of information you need.

Two main reasons for overviews are:

  1. Low resolution representation of the core tables commonly used for fast mapping zoom-out.

  2. Computations are generally faster to do on them than their higher resolution parents because there are fewer records and each pixel covers more territory. Though the computations are not as accurate as the high-res tables they support, they can be sufficient in many rule-of-thumb computations.

The raster_overviews catalog contains the following columns of information.

  • o_table_catalog The database the overview table is in. This will always read the current database.

  • o_table_schema The database schema the overview raster table belongs to.

  • o_table_name raster overview table name

  • o_raster_column the raster column in the overview table.

  • r_table_catalog The database the raster table that this overview services is in. This will always read the current database.

  • r_table_schema The database schema the raster table that this overview services belongs to.

  • r_table_name raster table that this overview services.

  • r_raster_column the raster column that this overview column services.

  • overview_factor - this is the pyramid level of the overview table. The higher the number the lower the resolution of the table. raster2pgsql if given a folder of images, will compute overview of each image file and load separately. Level 1 is assumed and always the original file. Level 2 is will have each tile represent 4 of the original. So for example if you have a folder of 5000x5000 pixel image files that you chose to chunk 125x125, for each image file your base table will have (5000*5000)/(125*125) records = 1600, your (l=2) o_2 table will have ceiling(1600/Power(2,2)) = 400 rows, your (l=3) o_3 will have ceiling(1600/Power(2,3) ) = 200 rows. If your pixels aren't divisible by the size of your tiles, you'll get some scrap tiles (tiles not completely filled). Note that each overview tile generated by raster2pgsql has the same number of pixels as its parent, but is of a lower resolution where each pixel of it represents (Power(2,overview_factor) pixels of the original).

10.3. Costruire applicazioni personalizzate con PostGIS Raster

The fact that PostGIS raster provides you with SQL functions to render rasters in known image formats gives you a lot of options for rendering them. For example you can use OpenOffice / LibreOffice for rendering as demonstrated in Rendering PostGIS Raster graphics with LibreOffice Base Reports. In addition you can use a wide variety of languages as demonstrated in this section.

10.3.1. Esempio di output in PHP, utilizzando ST_AsPNG assieme ad altre funzioni raster

In questo paragrafo mostreremo come utilizzare il driver PHP PostgreSQL e la famiglia di funzioni ST_AsGDALRaster per estrarre le bande 1,2,3 di un raster a una richiesta PHP che poi può essere inserita in un tag src di un'immagine HTML.

La query di esempio mostra come combinare varie funzioni raster per recuperare tutte le tile che intersecano una data area rettangolare in wgs84, unisce le tile risultanti per tutte le bande con ST_Union, le trasforma in una proiezione specificata dall'utente con ST_Transform e infine crea un PNG in uscita tramite ST_AsPNG.

Andreste a chiamare il codice sotto utilizzando

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

per ottenere l'immagine raster proiettata nel sistema di riferimento Massachusetts state plane feet.


<?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'] ) &amp;&amp; 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]);
?>

10.3.2. Esempio ASP.NET C# di output con ST_AsPNG, assieme ad altre funzioni raster

In questo paragrafo vi mostreremo come usare il driver .NET Npgsql e la famiglia di funzioni ST_AsGDALRaster per inviare in uscita le bande 1,2,3 di un raster a una richiesta PHP che può poi essere inserita nel tag src di un immagine html.

Per questo vi servirà il driver PostgreSQL npgsql .NET. Potete recuperare il più recente da http://npgsql.projects.postgresql.org/. Scaricatelo e salvatelo nella vostra cartella bin di ASP.NET per poter lavorare.

La query di esempio mostra come combinare varie funzioni raster per recuperare tutte le tile che intersecano una data area rettangolare in wgs84, unisce le tile risultanti per tutte le bande con ST_Union, le trasforma in una proiezione specificata dall'utente con ST_Transform e infine crea un PNG in uscita tramite ST_AsPNG.

Questo è lo stesso esempio illustrato in Section 10.3.1, “Esempio di output in PHP, utilizzando ST_AsPNG assieme ad altre funzioni raster”, implementato in C#.

Richiamerete il codice sotto come

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

per ottenere l'immagine raster nel sistema di riferimento Massachusetts state plane feet.

 -- 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;
        }
}

10.3.3. app per Java console per esportare una query raster come file immagine

Questa è una semplice app per console java che prende una query, ne restituisce la corrispondente immagine e la scrive in un file specificato.

Potete scaricare i driver JDBC per PostgreSQL più recenti da http://jdbc.postgresql.org/download.html

Potete compilare il codice seguente con un comando tipo:

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

E lanciarlo dalla riga di comando con un'istruzione tipo

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);
      }
  }
}

10.3.4. Utilizzare PLPython per esportare immagini tramite SQL

Si tratta di una funzione plpython che crea un file per ogni record nella directory del server. Richiede la presenza di plpython. Dovrebbe funzionare bene sia con plpythonu che 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

10.3.5. Produrre raster con PSQL

Purtroppo PSQL non ha una funzionalità integrata facile da usare per l'output dei binari. Si tratta di un piccolo hack che si appoggia al supporto per gli oggetti di grandi dimensioni di PostgreSQL, piuttosto datato. Per usarlo, lanciate prima la riga di comando di psql collegata al vostro database.

A differenza dell'approcio python, questo sistema crea il file in locale sul vostro computer.

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);