PostGIS 3.7.0dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches
rtreader.py
Go to the documentation of this file.
1#! /usr/bin/env python
2#
3#
4# A simple driver to read RASTER field data directly from PostGIS/WKTRaster.
5#
6# Copyright (C) 2009 Mateusz Loskot <mateusz@loskot.net>
7#
8# This program is free software; you can redistribute it and/or
9# modify it under the terms of the GNU General Public License
10# as published by the Free Software Foundation; either version 2
11# of the License, or (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program; if not, write to the Free Software Foundation,
20# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21#
22
31import psycopg2
32import sys
33
34
36
37class RasterError(Exception):
38 def __init__(self, msg):
39 self.msg = msg
40 def __str__(self):
41 return self.msg
42
43class RasterReader(object):
44 """Reader of RASTER data stored in specified column and row (where) in a table"""
45
46 # Constructors
47
48 def __init__(self, connstr, table, column, where = ""):
49 self._connstr = connstr
50 self._conn = None
51 self._table = table
52 self._column = column
53 self._where = where
54 self._sizes = None
55 self._types = None
56 self._logging = False
57 # Connect and read RASTER header
58 self._setup()
59
60 # Public properties
61
62 logging = property(fset = lambda self, v: setattr(self, '_logging', v))
63 db = property(fget = lambda self: self._get_db())
64 table = property(fget = lambda self: self._table)
65 column = property(fget = lambda self: self._column)
66 width = property(fget = lambda self: self._get_width())
67 height = property(fget = lambda self: self._get_height())
68 num_bands = property(fget = lambda self: self._get_num_bands())
69 pixel_types = property(fget = lambda self: self._get_pixel_types())
70
71 # Public methods
72
73 def get_value(self, band, x, y):
74 return self._query_value(band, x, y)
75
76 def copy_to(self, file, raster_format='TIFF', output_format='HEX', sep='\t'):
77 """
78 Proxy for SQL command COPY TO,
79 Converts selected rasters to specified raster_format with output sent either to
80 single hex-based plain text file or one or more binary files in raster_format,
81 one raster binary file per tuple from the raster table.
82 The BIN output uses HEX output as intermediate stage.
83 raster_format - TIFF|JPEG|PNG
84 output_format - HEX|BIN; BIN is a binary file in raster_format
85 sep - if output_format=HEX, separates rid value from hex-encoded binary.
86 """
87 import os.path
88 filehex = file # No extension added, may be user-defined
89 with open(filehex, 'w') as f:
90 select = "SELECT rid, encode(ST_As%s(%s), 'hex') As rt FROM %s" % (raster_format, self._column, self._table)
91 if self._where is not None and len(self._where) > 0:
92 select += ' WHERE %s' % self._where
93 sql = "COPY (%s) TO STDOUT (DELIMITER '%s')" % (select, sep)
94 cur = self._conn.cursor()
95 cur.copy_expert(sql, f)
96
97 if output_format == 'BIN':
98 import binascii
99 with open(filehex, 'r') as f:
100 dirname = os.path.dirname(file)
101 ext = raster_format.lower()
102 for line in f.readlines():
103 rid, raster = line.split()
104 filebin = self._table + '_' + self._column + '_' + rid + '.' + ext
105 filebin = os.path.join(dirname, filebin)
106 with open(filebin, 'w+') as fbin:
107 fbin.write(binascii.unhexlify(raster))
108
109 # Private methods
110
111 def _log(self, m):
112 if self._logging:
113 sys.stderr.write('[rtreader] ' + str(m) + '\n')
114
115 def _get_db(self):
116 n = filter(lambda db: db[:6] == 'dbname', self._connstr.split())[0].split('=')[1]
117 return n.strip('\'').strip()
118
119 def _get_width(self):
120 return self._query_raster_size(0)
121
122 def _get_height(self):
123 return self._query_raster_size(1)
124
125 def _get_num_bands(self):
126 return self._query_raster_size(2)
127
129 return self._query_pixel_types()
130
131 def _setup(self):
132 self._connect()
133
134 def _connect(self):
135 try:
136 if self._conn is None:
137 self._conn = psycopg2.connect(self._connstr)
138 except Exception as e:
139 raise RasterError("Failed to connect to %s: %s" % (self._connstr, e))
140
141 def _query_single_row(self, sql):
142 assert self._conn is not None
143 #self._log(sql)
144
145 try:
146 cur = self._conn.cursor()
147 cur.execute(sql)
148 except Exception as e:
149 raise RasterError("Failed to execute query %s: %s" % (sql, e))
150
151 row = cur.fetchone()
152 if row is None:
153 raise RasterError("No tuples returned for query: %s" % sql)
154 return row
155
156 def _query_value(self, band, x, y):
157 sql = 'SELECT st_value(%s, %d, %d, %d) FROM %s' % \
158 (self._column, band, x, y, self._table)
159 if len(self._where) > 0:
160 sql += ' WHERE %s' % self._where
161
162 row = self._query_single_row(sql)
163 if row is None:
164 raise RasterError("Value of pixel %dx%d of band %d is none" %(x, y, band))
165 return row[0]
166
167 def _query_raster_size(self, dim, force = False):
168 if self._sizes is None or force is True:
169 sql = 'SELECT st_width(%s), st_height(%s), st_numbands(%s) FROM %s' % \
170 (self._column, self._column, self._column, self._table)
171 if len(self._where) > 0:
172 sql += ' WHERE %s' % self._where
173
174 self._log(sql)
175 self._sizes = self._query_single_row(sql)
176
177 if self._sizes is None:
178 raise RasterError("Failed to query raster size of dim {} with force {}".format(dim, force))
179 return self._sizes[dim]
180
182
183 types = []
184 sql = 'SELECT '
185 for i in range(0, self.num_bands):
186 if i != 0:
187 sql += ','
188 nband = i + 1
189 sql += ' st_bandpixeltype(%s, %d) ' % (self._column, nband)
190 sql += ' FROM ' + self._table
191 return self._query_single_row(sql)
__init__(self, msg)
Definition rtreader.py:38
RASTER driver (read-only)
Definition rtreader.py:37
get_value(self, band, x, y)
Definition rtreader.py:73
copy_to(self, file, raster_format='TIFF', output_format='HEX', sep='\t')
Definition rtreader.py:76
_query_value(self, band, x, y)
Definition rtreader.py:156
__init__(self, connstr, table, column, where="")
Definition rtreader.py:48
_query_raster_size(self, dim, force=False)
Definition rtreader.py:167
_query_single_row(self, sql)
Definition rtreader.py:141
#define str(s)