#!/usr/bin/env python import atexit import os import re import sys import time from binascii import hexlify from subprocess import PIPE, Popen from nose.tools import assert_almost_equal, eq_ import mapnik from .utilities import execution_path, run_all, side_by_side_image MAPNIK_TEST_DBNAME = 'mapnik-tmp-pgraster-test-db' POSTGIS_TEMPLATE_DBNAME = 'template_postgis' DEBUG_OUTPUT = False def log(msg): if DEBUG_OUTPUT: print(msg) def setup(): # All of the paths used are relative, if we run the tests # from another directory we need to chdir() os.chdir(execution_path('.')) def call(cmd, silent=False): stdin, stderr = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE).communicate() stdin = stdin.decode() stderr = stderr.decode() if not stderr: return stdin.strip() elif not silent and 'error' in stderr.lower() \ or 'not found' in stderr.lower() \ or 'could not connect' in stderr.lower() \ or 'bad connection' in stderr.lower() \ or 'not recognized as an internal' in stderr.lower(): raise RuntimeError(stderr.strip()) def psql_can_connect(): """Test ability to connect to a postgis template db with no options. Basically, to run these tests your user must have full read access over unix sockets without supplying a password. This keeps these tests simple and focused on postgis not on postgres auth issues. """ try: call('psql %s -c "select postgis_version()"' % POSTGIS_TEMPLATE_DBNAME) return True except RuntimeError: print('Notice: skipping pgraster tests (connection)') return False def psql_run(cmd): cmd = 'psql --set ON_ERROR_STOP=1 %s -c "%s"' % \ (MAPNIK_TEST_DBNAME, cmd.replace('"', '\\"')) log('DEBUG: running ' + cmd) call(cmd) def raster2pgsql_on_path(): """Test for presence of raster2pgsql on the user path. We require this program to load test data into a temporarily database. """ try: call('raster2pgsql') return True except RuntimeError: print('Notice: skipping pgraster tests (raster2pgsql)') return False def createdb_and_dropdb_on_path(): """Test for presence of dropdb/createdb on user path. We require these programs to setup and teardown the testing db. """ try: call('createdb --help') call('dropdb --help') return True except RuntimeError: print('Notice: skipping pgraster tests (createdb/dropdb)') return False def postgis_setup(): call('dropdb %s' % MAPNIK_TEST_DBNAME, silent=True) call( 'createdb -T %s %s' % (POSTGIS_TEMPLATE_DBNAME, MAPNIK_TEST_DBNAME), silent=False) def postgis_takedown(): pass # fails as the db is in use: https://github.com/mapnik/mapnik/issues/960 #call('dropdb %s' % MAPNIK_TEST_DBNAME) def import_raster(filename, tabname, tilesize, constraint, overview): log('tile: ' + tilesize + ' constraints: ' + str(constraint) + ' overviews: ' + overview) cmd = 'raster2pgsql -Y -I -q' if constraint: cmd += ' -C' if tilesize: cmd += ' -t ' + tilesize if overview: cmd += ' -l ' + overview cmd += ' %s %s | psql --set ON_ERROR_STOP=1 -q %s' % ( os.path.abspath(os.path.normpath(filename)), tabname, MAPNIK_TEST_DBNAME) log('Import call: ' + cmd) call(cmd) def drop_imported(tabname, overview): psql_run('DROP TABLE IF EXISTS "' + tabname + '";') if overview: for of in overview.split(','): psql_run('DROP TABLE IF EXISTS "o_' + of + '_' + tabname + '";') def compare_images(expected, im): expected = os.path.join( os.path.dirname(expected), os.path.basename(expected).replace( ':', '_')) if not os.path.exists(expected) or os.environ.get('UPDATE'): print('generating expected image %s' % expected) im.save(expected, 'png32') expected_im = mapnik.Image.open(expected) diff = expected.replace('.png', '-diff.png') if len(im.tostring("png32")) != len(expected_im.tostring("png32")): compared = side_by_side_image(expected_im, im) compared.save(diff) assert False, 'images do not match, check diff at %s' % diff else: if os.path.exists(diff): os.unlink(diff) return True if 'pgraster' in mapnik.DatasourceCache.plugin_names() \ and createdb_and_dropdb_on_path() \ and psql_can_connect() \ and raster2pgsql_on_path(): # initialize test database postgis_setup() # [old]dataraster.tif, 2283x1913 int16 single-band # dataraster-small.tif, 457x383 int16 single-band def _test_dataraster_16bsi_rendering(lbl, overview, rescale, clip): if rescale: lbl += ' Sc' if clip: lbl += ' Cl' ds = mapnik.PgRaster(dbname=MAPNIK_TEST_DBNAME, table='"dataRaster"', band=1, use_overviews=1 if overview else 0, prescale_rasters=rescale, clip_rasters=clip) fs = ds.featureset() feature = fs.next() eq_(feature['rid'], 1) lyr = mapnik.Layer('dataraster_16bsi') lyr.datasource = ds expenv = mapnik.Box2d(-14637, 3903178, 1126863, 4859678) env = lyr.envelope() # As the input size is a prime number both horizontally # and vertically, we expect the extent of the overview # tables to be a pixel wider than the original, whereas # the pixel size in geographical units depends on the # overview factor. So we start with the original pixel size # as base scale and multiply by the overview factor. # NOTE: the overview table extent only grows north and east pixsize = 500 # see gdalinfo dataraster.tif pixsize = 2497 # see gdalinfo dataraster-small.tif tol = pixsize * max(overview.split(',')) if overview else 0 assert_almost_equal(env.minx, expenv.minx) assert_almost_equal(env.miny, expenv.miny, delta=tol) assert_almost_equal(env.maxx, expenv.maxx, delta=tol) assert_almost_equal(env.maxy, expenv.maxy) mm = mapnik.Map(256, 256) style = mapnik.Style() col = mapnik.RasterColorizer() col.default_mode = mapnik.COLORIZER_DISCRETE col.add_stop(0, mapnik.Color(0x40, 0x40, 0x40, 255)) col.add_stop(10, mapnik.Color(0x80, 0x80, 0x80, 255)) col.add_stop(20, mapnik.Color(0xa0, 0xa0, 0xa0, 255)) sym = mapnik.RasterSymbolizer() sym.colorizer = col rule = mapnik.Rule() rule.symbols.append(sym) style.rules.append(rule) mm.append_style('foo', style) lyr.styles.append('foo') mm.layers.append(lyr) mm.zoom_to_box(expenv) im = mapnik.Image(mm.width, mm.height) t0 = time.time() # we want wall time to include IO waits mapnik.render(mm, im) lap = time.time() - t0 log('T ' + str(lap) + ' -- ' + lbl + ' E:full') # no data eq_(im.view(1, 1, 1, 1).tostring(), b'\x00\x00\x00\x00') eq_(im.view(255, 255, 1, 1).tostring(), b'\x00\x00\x00\x00') eq_(im.view(195, 116, 1, 1).tostring(), b'\x00\x00\x00\x00') # A0A0A0 eq_(im.view(100, 120, 1, 1).tostring(), b'\xa0\xa0\xa0\xff') eq_(im.view(75, 80, 1, 1).tostring(), b'\xa0\xa0\xa0\xff') # 808080 eq_(im.view(74, 170, 1, 1).tostring(), b'\x80\x80\x80\xff') eq_(im.view(30, 50, 1, 1).tostring(), b'\x80\x80\x80\xff') # 404040 eq_(im.view(190, 70, 1, 1).tostring(), b'\x40\x40\x40\xff') eq_(im.view(140, 170, 1, 1).tostring(), b'\x40\x40\x40\xff') # Now zoom over a portion of the env (1/10) newenv = mapnik.Box2d(273663, 4024478, 330738, 4072303) mm.zoom_to_box(newenv) t0 = time.time() # we want wall time to include IO waits mapnik.render(mm, im) lap = time.time() - t0 log('T ' + str(lap) + ' -- ' + lbl + ' E:1/10') # nodata eq_(hexlify(im.view(255, 255, 1, 1).tostring()), b'00000000') eq_(hexlify(im.view(200, 254, 1, 1).tostring()), b'00000000') # A0A0A0 eq_(hexlify(im.view(90, 232, 1, 1).tostring()), b'a0a0a0ff') eq_(hexlify(im.view(96, 245, 1, 1).tostring()), b'a0a0a0ff') # 808080 eq_(hexlify(im.view(1, 1, 1, 1).tostring()), b'808080ff') eq_(hexlify(im.view(128, 128, 1, 1).tostring()), b'808080ff') # 404040 eq_(hexlify(im.view(255, 0, 1, 1).tostring()), b'404040ff') def _test_dataraster_16bsi(lbl, tilesize, constraint, overview): import_raster( '../data/raster/dataraster-small.tif', 'dataRaster', tilesize, constraint, overview) if constraint: lbl += ' C' if tilesize: lbl += ' T:' + tilesize if overview: lbl += ' O:' + overview for prescale in [0, 1]: for clip in [0, 1]: _test_dataraster_16bsi_rendering(lbl, overview, prescale, clip) drop_imported('dataRaster', overview) def test_dataraster_16bsi(): # for tilesize in ['','256x256']: for tilesize in ['256x256']: for constraint in [0, 1]: # for overview in ['','4','2,16']: for overview in ['', '2']: _test_dataraster_16bsi( 'data_16bsi', tilesize, constraint, overview) # river.tiff, RGBA 8BUI def _test_rgba_8bui_rendering(lbl, overview, rescale, clip): if rescale: lbl += ' Sc' if clip: lbl += ' Cl' ds = mapnik.PgRaster(dbname=MAPNIK_TEST_DBNAME, table='(select * from "River") foo', use_overviews=1 if overview else 0, prescale_rasters=rescale, clip_rasters=clip) fs = ds.featureset() feature = fs.next() eq_(feature['rid'], 1) lyr = mapnik.Layer('rgba_8bui') lyr.datasource = ds expenv = mapnik.Box2d(0, -210, 256, 0) env = lyr.envelope() # As the input size is a prime number both horizontally # and vertically, we expect the extent of the overview # tables to be a pixel wider than the original, whereas # the pixel size in geographical units depends on the # overview factor. So we start with the original pixel size # as base scale and multiply by the overview factor. # NOTE: the overview table extent only grows north and east pixsize = 1 # see gdalinfo river.tif tol = pixsize * max(overview.split(',')) if overview else 0 assert_almost_equal(env.minx, expenv.minx) assert_almost_equal(env.miny, expenv.miny, delta=tol) assert_almost_equal(env.maxx, expenv.maxx, delta=tol) assert_almost_equal(env.maxy, expenv.maxy) mm = mapnik.Map(256, 256) style = mapnik.Style() sym = mapnik.RasterSymbolizer() rule = mapnik.Rule() rule.symbols.append(sym) style.rules.append(rule) mm.append_style('foo', style) lyr.styles.append('foo') mm.layers.append(lyr) mm.zoom_to_box(expenv) im = mapnik.Image(mm.width, mm.height) t0 = time.time() # we want wall time to include IO waits mapnik.render(mm, im) lap = time.time() - t0 log('T ' + str(lap) + ' -- ' + lbl + ' E:full') expected = 'images/support/pgraster/%s-%s-%s-%s-box1.png' % ( lyr.name, lbl, overview, clip) compare_images(expected, im) # no data eq_(hexlify(im.view(3, 3, 1, 1).tostring()), b'00000000') eq_(hexlify(im.view(250, 250, 1, 1).tostring()), b'00000000') # full opaque river color eq_(hexlify(im.view(175, 118, 1, 1).tostring()), b'b9d8f8ff') # half-transparent pixel pxstr = hexlify(im.view(122, 138, 1, 1).tostring()).decode() apat = ".*(..)$" match = re.match(apat, pxstr) assert match, 'pixel ' + pxstr + ' does not match pattern ' + apat alpha = match.group(1) assert alpha != 'ff' and alpha != '00', \ 'unexpected full transparent/opaque pixel: ' + alpha # Now zoom over a portion of the env (1/10) newenv = mapnik.Box2d(166, -105, 191, -77) mm.zoom_to_box(newenv) t0 = time.time() # we want wall time to include IO waits im = mapnik.Image(mm.width, mm.height) mapnik.render(mm, im) lap = time.time() - t0 log('T ' + str(lap) + ' -- ' + lbl + ' E:1/10') expected = 'images/support/pgraster/%s-%s-%s-%s-box2.png' % ( lyr.name, lbl, overview, clip) compare_images(expected, im) # no data eq_(hexlify(im.view(255, 255, 1, 1).tostring()), b'00000000') eq_(hexlify(im.view(200, 40, 1, 1).tostring()), b'00000000') # full opaque river color eq_(hexlify(im.view(100, 168, 1, 1).tostring()), b'b9d8f8ff') # half-transparent pixel pxstr = hexlify(im.view(122, 138, 1, 1).tostring()).decode() apat = ".*(..)$" match = re.match(apat, pxstr) assert match, 'pixel ' + pxstr + ' does not match pattern ' + apat alpha = match.group(1) assert alpha != 'ff' and alpha != '00', \ 'unexpected full transparent/opaque pixel: ' + alpha def _test_rgba_8bui(lbl, tilesize, constraint, overview): import_raster( '../data/raster/river.tiff', 'River', tilesize, constraint, overview) if constraint: lbl += ' C' if tilesize: lbl += ' T:' + tilesize if overview: lbl += ' O:' + overview for prescale in [0, 1]: for clip in [0, 1]: _test_rgba_8bui_rendering(lbl, overview, prescale, clip) drop_imported('River', overview) def test_rgba_8bui(): for tilesize in ['', '16x16']: for constraint in [0, 1]: for overview in ['2']: _test_rgba_8bui( 'rgba_8bui', tilesize, constraint, overview) # nodata-edge.tif, RGB 8BUI def _test_rgb_8bui_rendering(lbl, tnam, overview, rescale, clip): if rescale: lbl += ' Sc' if clip: lbl += ' Cl' ds = mapnik.PgRaster(dbname=MAPNIK_TEST_DBNAME, table=tnam, use_overviews=1 if overview else 0, prescale_rasters=rescale, clip_rasters=clip) fs = ds.featureset() feature = fs.next() eq_(feature['rid'], 1) lyr = mapnik.Layer('rgba_8bui') lyr.datasource = ds expenv = mapnik.Box2d(-12329035.7652168, 4508650.39854396, -12328653.0279471, 4508957.34625536) env = lyr.envelope() # As the input size is a prime number both horizontally # and vertically, we expect the extent of the overview # tables to be a pixel wider than the original, whereas # the pixel size in geographical units depends on the # overview factor. So we start with the original pixel size # as base scale and multiply by the overview factor. # NOTE: the overview table extent only grows north and east pixsize = 2 # see gdalinfo nodata-edge.tif tol = pixsize * max(overview.split(',')) if overview else 0 assert_almost_equal(env.minx, expenv.minx, places=0) assert_almost_equal(env.miny, expenv.miny, delta=tol) assert_almost_equal(env.maxx, expenv.maxx, delta=tol) assert_almost_equal(env.maxy, expenv.maxy, places=0) mm = mapnik.Map(256, 256) style = mapnik.Style() sym = mapnik.RasterSymbolizer() rule = mapnik.Rule() rule.symbols.append(sym) style.rules.append(rule) mm.append_style('foo', style) lyr.styles.append('foo') mm.layers.append(lyr) mm.zoom_to_box(expenv) im = mapnik.Image(mm.width, mm.height) t0 = time.time() # we want wall time to include IO waits mapnik.render(mm, im) lap = time.time() - t0 log('T ' + str(lap) + ' -- ' + lbl + ' E:full') expected = 'images/support/pgraster/%s-%s-%s-%s-%s-box1.png' % ( lyr.name, tnam, lbl, overview, clip) compare_images(expected, im) # no data eq_(hexlify(im.view(3, 16, 1, 1).tostring()), '00000000') eq_(hexlify(im.view(128, 16, 1, 1).tostring()), '00000000') eq_(hexlify(im.view(250, 16, 1, 1).tostring()), '00000000') eq_(hexlify(im.view(3, 240, 1, 1).tostring()), '00000000') eq_(hexlify(im.view(128, 240, 1, 1).tostring()), '00000000') eq_(hexlify(im.view(250, 240, 1, 1).tostring()), '00000000') # dark brown eq_(hexlify(im.view(174, 39, 1, 1).tostring()), 'c3a698ff') # dark gray eq_(hexlify(im.view(195, 132, 1, 1).tostring()), '575f62ff') # Now zoom over a portion of the env (1/10) newenv = mapnik.Box2d(-12329035.7652168, 4508926.651484220, -12328997.49148983, 4508957.34625536) mm.zoom_to_box(newenv) t0 = time.time() # we want wall time to include IO waits im = mapnik.Image(mm.width, mm.height) mapnik.render(mm, im) lap = time.time() - t0 log('T ' + str(lap) + ' -- ' + lbl + ' E:1/10') expected = 'images/support/pgraster/%s-%s-%s-%s-%s-box2.png' % ( lyr.name, tnam, lbl, overview, clip) compare_images(expected, im) # no data eq_(hexlify(im.view(3, 16, 1, 1).tostring()), '00000000') eq_(hexlify(im.view(128, 16, 1, 1).tostring()), '00000000') eq_(hexlify(im.view(250, 16, 1, 1).tostring()), '00000000') # black eq_(hexlify(im.view(3, 42, 1, 1).tostring()), '000000ff') eq_(hexlify(im.view(3, 134, 1, 1).tostring()), '000000ff') eq_(hexlify(im.view(3, 244, 1, 1).tostring()), '000000ff') # gray eq_(hexlify(im.view(135, 157, 1, 1).tostring()), '4e555bff') # brown eq_(hexlify(im.view(195, 223, 1, 1).tostring()), 'f2cdbaff') def _test_rgb_8bui(lbl, tilesize, constraint, overview): tnam = 'nodataedge' import_raster( '../data/raster/nodata-edge.tif', tnam, tilesize, constraint, overview) if constraint: lbl += ' C' if tilesize: lbl += ' T:' + tilesize if overview: lbl += ' O:' + overview for prescale in [0, 1]: for clip in [0, 1]: _test_rgb_8bui_rendering(lbl, tnam, overview, prescale, clip) #drop_imported(tnam, overview) def test_rgb_8bui(): for tilesize in ['64x64']: for constraint in [1]: for overview in ['']: _test_rgb_8bui('rgb_8bui', tilesize, constraint, overview) def _test_grayscale_subquery(lbl, pixtype, value): # # 3 8 13 # +---+---+---+ # 3 | v | v | v | NOTE: writes different color # +---+---+---+ in 13,8 and 8,13 # 8 | v | v | a | # +---+---+---+ # 13 | v | b | v | # +---+---+---+ # val_a = int(value / 3) val_b = val_a * 2 sql = "(select 3 as i, " \ " ST_SetValues(" \ " ST_SetValues(" \ " ST_AsRaster(" \ " ST_MakeEnvelope(0,0,14,14), " \ " 1.0, -1.0, '%s', %s" \ " ), " \ " 11, 6, 4, 5, %s::float8" \ " )," \ " 6, 11, 5, 4, %s::float8" \ " ) as \"R\"" \ ") as foo" % (pixtype, value, val_a, val_b) rescale = 0 clip = 0 if rescale: lbl += ' Sc' if clip: lbl += ' Cl' ds = mapnik.PgRaster(dbname=MAPNIK_TEST_DBNAME, table=sql, raster_field='"R"', use_overviews=1, prescale_rasters=rescale, clip_rasters=clip) fs = ds.featureset() feature = fs.next() eq_(feature['i'], 3) lyr = mapnik.Layer('grayscale_subquery') lyr.datasource = ds expenv = mapnik.Box2d(0, 0, 14, 14) env = lyr.envelope() assert_almost_equal(env.minx, expenv.minx, places=0) assert_almost_equal(env.miny, expenv.miny, places=0) assert_almost_equal(env.maxx, expenv.maxx, places=0) assert_almost_equal(env.maxy, expenv.maxy, places=0) mm = mapnik.Map(15, 15) style = mapnik.Style() sym = mapnik.RasterSymbolizer() rule = mapnik.Rule() rule.symbols.append(sym) style.rules.append(rule) mm.append_style('foo', style) lyr.styles.append('foo') mm.layers.append(lyr) mm.zoom_to_box(expenv) im = mapnik.Image(mm.width, mm.height) t0 = time.time() # we want wall time to include IO waits mapnik.render(mm, im) lap = time.time() - t0 log('T ' + str(lap) + ' -- ' + lbl + ' E:full') expected = 'images/support/pgraster/%s-%s-%s-%s.png' % ( lyr.name, lbl, pixtype, value) compare_images(expected, im) h = format(value, '02x') hex_v = h + h + h + 'ff' hex_v = hex_v.encode() h = format(val_a, '02x') hex_a = h + h + h + 'ff' hex_a = hex_a.encode() h = format(val_b, '02x') hex_b = h + h + h + 'ff' hex_b = hex_b.encode() eq_(hexlify(im.view(3, 3, 1, 1).tostring()), hex_v) eq_(hexlify(im.view(8, 3, 1, 1).tostring()), hex_v) eq_(hexlify(im.view(13, 3, 1, 1).tostring()), hex_v) eq_(hexlify(im.view(3, 8, 1, 1).tostring()), hex_v) eq_(hexlify(im.view(8, 8, 1, 1).tostring()), hex_v) eq_(hexlify(im.view(13, 8, 1, 1).tostring()), hex_a) eq_(hexlify(im.view(3, 13, 1, 1).tostring()), hex_v) eq_(hexlify(im.view(8, 13, 1, 1).tostring()), hex_b) eq_(hexlify(im.view(13, 13, 1, 1).tostring()), hex_v) def test_grayscale_2bui_subquery(): _test_grayscale_subquery('grayscale_2bui_subquery', '2BUI', 3) def test_grayscale_4bui_subquery(): _test_grayscale_subquery('grayscale_4bui_subquery', '4BUI', 15) def test_grayscale_8bui_subquery(): _test_grayscale_subquery('grayscale_8bui_subquery', '8BUI', 63) def test_grayscale_8bsi_subquery(): # NOTE: we're using a positive integer because Mapnik # does not support negative data values anyway _test_grayscale_subquery('grayscale_8bsi_subquery', '8BSI', 69) def test_grayscale_16bui_subquery(): _test_grayscale_subquery('grayscale_16bui_subquery', '16BUI', 126) def test_grayscale_16bsi_subquery(): # NOTE: we're using a positive integer because Mapnik # does not support negative data values anyway _test_grayscale_subquery('grayscale_16bsi_subquery', '16BSI', 144) def test_grayscale_32bui_subquery(): _test_grayscale_subquery('grayscale_32bui_subquery', '32BUI', 255) def test_grayscale_32bsi_subquery(): # NOTE: we're using a positive integer because Mapnik # does not support negative data values anyway _test_grayscale_subquery('grayscale_32bsi_subquery', '32BSI', 129) def _test_data_subquery(lbl, pixtype, value): # # 3 8 13 # +---+---+---+ # 3 | v | v | v | NOTE: writes different values # +---+---+---+ in 13,8 and 8,13 # 8 | v | v | a | # +---+---+---+ # 13 | v | b | v | # +---+---+---+ # val_a = value / 3 val_b = val_a * 2 sql = "(select 3 as i, " \ " ST_SetValues(" \ " ST_SetValues(" \ " ST_AsRaster(" \ " ST_MakeEnvelope(0,0,14,14), " \ " 1.0, -1.0, '%s', %s" \ " ), " \ " 11, 6, 5, 5, %s::float8" \ " )," \ " 6, 11, 5, 5, %s::float8" \ " ) as \"R\"" \ ") as foo" % (pixtype, value, val_a, val_b) overview = '' rescale = 0 clip = 0 if rescale: lbl += ' Sc' if clip: lbl += ' Cl' ds = mapnik.PgRaster(dbname=MAPNIK_TEST_DBNAME, table=sql, raster_field='R', use_overviews=0 if overview else 0, band=1, prescale_rasters=rescale, clip_rasters=clip) fs = ds.featureset() feature = fs.next() eq_(feature['i'], 3) lyr = mapnik.Layer('data_subquery') lyr.datasource = ds expenv = mapnik.Box2d(0, 0, 14, 14) env = lyr.envelope() assert_almost_equal(env.minx, expenv.minx, places=0) assert_almost_equal(env.miny, expenv.miny, places=0) assert_almost_equal(env.maxx, expenv.maxx, places=0) assert_almost_equal(env.maxy, expenv.maxy, places=0) mm = mapnik.Map(15, 15) style = mapnik.Style() col = mapnik.RasterColorizer() col.default_mode = mapnik.COLORIZER_DISCRETE col.add_stop(val_a, mapnik.Color(0xff, 0x00, 0x00, 255)) col.add_stop(val_b, mapnik.Color(0x00, 0xff, 0x00, 255)) col.add_stop(value, mapnik.Color(0x00, 0x00, 0xff, 255)) sym = mapnik.RasterSymbolizer() sym.colorizer = col rule = mapnik.Rule() rule.symbols.append(sym) style.rules.append(rule) mm.append_style('foo', style) lyr.styles.append('foo') mm.layers.append(lyr) mm.zoom_to_box(expenv) im = mapnik.Image(mm.width, mm.height) t0 = time.time() # we want wall time to include IO waits mapnik.render(mm, im) lap = time.time() - t0 log('T ' + str(lap) + ' -- ' + lbl + ' E:full') expected = 'images/support/pgraster/%s-%s-%s-%s.png' % ( lyr.name, lbl, pixtype, value) compare_images(expected, im) def test_data_2bui_subquery(): _test_data_subquery('data_2bui_subquery', '2BUI', 3) def test_data_4bui_subquery(): _test_data_subquery('data_4bui_subquery', '4BUI', 15) def test_data_8bui_subquery(): _test_data_subquery('data_8bui_subquery', '8BUI', 63) def test_data_8bsi_subquery(): # NOTE: we're using a positive integer because Mapnik # does not support negative data values anyway _test_data_subquery('data_8bsi_subquery', '8BSI', 69) def test_data_16bui_subquery(): _test_data_subquery('data_16bui_subquery', '16BUI', 126) def test_data_16bsi_subquery(): # NOTE: we're using a positive integer because Mapnik # does not support negative data values anyway _test_data_subquery('data_16bsi_subquery', '16BSI', 135) def test_data_32bui_subquery(): _test_data_subquery('data_32bui_subquery', '32BUI', 255) def test_data_32bsi_subquery(): # NOTE: we're using a positive integer because Mapnik # does not support negative data values anyway _test_data_subquery('data_32bsi_subquery', '32BSI', 264) def test_data_32bf_subquery(): _test_data_subquery('data_32bf_subquery', '32BF', 450) def test_data_64bf_subquery(): _test_data_subquery('data_64bf_subquery', '64BF', 3072) def _test_rgba_subquery(lbl, pixtype, r, g, b, a, g1, b1): # # 3 8 13 # +---+---+---+ # 3 | v | v | h | NOTE: writes different alpha # +---+---+---+ in 13,8 and 8,13 # 8 | v | v | a | # +---+---+---+ # 13 | v | b | v | # +---+---+---+ # sql = "(select 3 as i, " \ " ST_SetValues(" \ " ST_SetValues(" \ " ST_AddBand(" \ " ST_AddBand(" \ " ST_AddBand(" \ " ST_AsRaster(" \ " ST_MakeEnvelope(0,0,14,14), " \ " 1.0, -1.0, '%s', %s" \ " )," \ " '%s', %d::float" \ " ), " \ " '%s', %d::float" \ " ), " \ " '%s', %d::float" \ " ), " \ " 2, 11, 6, 4, 5, %s::float8" \ " )," \ " 3, 6, 11, 5, 4, %s::float8" \ " ) as r" \ ") as foo" % ( pixtype, r, pixtype, g, pixtype, b, pixtype, a, g1, b1) overview = '' rescale = 0 clip = 0 if rescale: lbl += ' Sc' if clip: lbl += ' Cl' ds = mapnik.PgRaster(dbname=MAPNIK_TEST_DBNAME, table=sql, raster_field='r', use_overviews=0 if overview else 0, prescale_rasters=rescale, clip_rasters=clip) fs = ds.featureset() feature = fs.next() eq_(feature['i'], 3) lyr = mapnik.Layer('rgba_subquery') lyr.datasource = ds expenv = mapnik.Box2d(0, 0, 14, 14) env = lyr.envelope() assert_almost_equal(env.minx, expenv.minx, places=0) assert_almost_equal(env.miny, expenv.miny, places=0) assert_almost_equal(env.maxx, expenv.maxx, places=0) assert_almost_equal(env.maxy, expenv.maxy, places=0) mm = mapnik.Map(15, 15) style = mapnik.Style() sym = mapnik.RasterSymbolizer() rule = mapnik.Rule() rule.symbols.append(sym) style.rules.append(rule) mm.append_style('foo', style) lyr.styles.append('foo') mm.layers.append(lyr) mm.zoom_to_box(expenv) im = mapnik.Image(mm.width, mm.height) t0 = time.time() # we want wall time to include IO waits mapnik.render(mm, im) lap = time.time() - t0 log('T ' + str(lap) + ' -- ' + lbl + ' E:full') expected = 'images/support/pgraster/%s-%s-%s-%s-%s-%s-%s-%s-%s.png' % ( lyr.name, lbl, pixtype, r, g, b, a, g1, b1) compare_images(expected, im) hex_v = format(r << 24 | g << 16 | b << 8 | a, '08x').encode() hex_a = format(r << 24 | g1 << 16 | b << 8 | a, '08x').encode() hex_b = format(r << 24 | g << 16 | b1 << 8 | a, '08x').encode() eq_(hexlify(im.view(3, 3, 1, 1).tostring()), hex_v) eq_(hexlify(im.view(8, 3, 1, 1).tostring()), hex_v) eq_(hexlify(im.view(13, 3, 1, 1).tostring()), hex_v) eq_(hexlify(im.view(3, 8, 1, 1).tostring()), hex_v) eq_(hexlify(im.view(8, 8, 1, 1).tostring()), hex_v) eq_(hexlify(im.view(13, 8, 1, 1).tostring()), hex_a) eq_(hexlify(im.view(3, 13, 1, 1).tostring()), hex_v) eq_(hexlify(im.view(8, 13, 1, 1).tostring()), hex_b) eq_(hexlify(im.view(13, 13, 1, 1).tostring()), hex_v) def test_rgba_8bui_subquery(): _test_rgba_subquery( 'rgba_8bui_subquery', '8BUI', 255, 0, 0, 255, 255, 255) # def test_rgba_16bui_subquery(): # _test_rgba_subquery('rgba_16bui_subquery', '16BUI', 65535, 0, 0, 65535, 65535, 65535) # def test_rgba_32bui_subquery(): # _test_rgba_subquery('rgba_32bui_subquery', '32BUI') atexit.register(postgis_takedown) def enabled(tname): enabled = len(sys.argv) < 2 or tname in sys.argv if not enabled: print("Skipping " + tname + " as not explicitly enabled") return enabled if __name__ == "__main__": setup() fail = run_all(eval(x) for x in dir() if x.startswith("test_") and enabled(x)) exit(fail)