Created
January 11, 2016 17:10
-
-
Save Marginal/616680a6149dfb47e9f0 to your computer and use it in GitHub Desktop.
Extracts water v. land from an X-Plane 10 "Global Scenery" or "HD Mesh Scenery v3" DSF and saves it as a 1bpp PNG image
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
# | |
# Extracts the water v land from an X-Plane 10 "Global Scenery" or "HD Mesh Scenery v3" DSF | |
# and saves it as a 1bpp PNG image. | |
# | |
# Requires Python 2.7 plus the numpy and PIL modules, and 7-Zip | |
# | |
# Decompression requires `brew install p7zip` on Mac, 7-Zip command line on Windows, or p7zip on linux | |
P7 = '/usr/local/bin/7za' | |
# Requires X-Plane Command-Line tools - http://developer.x-plane.com/tools/xptools/ | |
DSFTOOL = '~/Desktop/X-Plane 10/tools/DSFTool' | |
# Output folder | |
OUTDIR = '.' | |
import numpy | |
import PIL.Image, PIL.PngImagePlugin | |
from os import spawnl, P_WAIT, unlink | |
from os.path import basename, expanduser, isfile, join | |
import sys | |
from tempfile import gettempdir | |
if len(sys.argv) not in [2,3]: | |
sys.exit('''Extracts the water v land from an X-Plane DSF and saves it as a 1bpp PNG image | |
Usage: dsf2png DSF_file [PNG_file] | |
''') | |
infile = sys.platform == 'win32' and sys.argv[1] or expanduser(sys.argv[1]) | |
if not isfile(infile): | |
sys.exit('"%" doesn\'t exist!' % infile) | |
else: | |
infile = sys.argv[1] | |
if len(sys.argv) == 2: | |
outfile = join(OUTDIR, basename(sys.argv[1][:-4]) + '.png') | |
else: | |
outfile = sys.argv[2] | |
if sys.platform != 'win32': | |
outfile = expanduser(outfile) | |
if sys.platform == 'win32': | |
e = spawnl(P_WAIT, P7, '"%s"' % P7, 'e', '"%s"' % infile, '-y', '-o%s' % gettempdir()) | |
else: | |
e = spawnl(P_WAIT, P7, P7, 'e', infile, '-y', '-o%s' % gettempdir()) | |
if e: | |
sys.exit('"%s" exited with %d!' % (P7, e)) | |
if sys.platform == 'win32': | |
e = spawnl(P_WAIT, DSFTOOL, '"%s"' % DSFTOOL, '--dsf2text', '"%s"' % join(gettempdir(), basename(infile)), '"%s"' % join(gettempdir(), basename(infile)[:-4] + '.txt')) | |
else: | |
e = spawnl(P_WAIT, expanduser(DSFTOOL), DSFTOOL, '--dsf2text', join(gettempdir(), basename(infile)), join(gettempdir(), basename(infile)[:-4] + '.txt')) | |
if e: | |
sys.exit('"%s" exited with %d!' % (DSFTOOL, e)) | |
if not isfile(join(gettempdir(), basename(infile)[:-4] + '.txt.elevation.raw')): | |
sys.exit('"%s" doesn\'t contain an elevation DEM - is this an X-Plane 10 Global Scenery DSF?' % infile) | |
# Source data is signed, but import as unsigned because we're just interested in non-zero | |
dem = numpy.fromfile(join(gettempdir(), basename(infile)[:-4] + '.txt.elevation.raw'), 'H') | |
assert len(dem) == 1201 * 1201 | |
dem = numpy.flipud(dem.reshape((1201, 1201))) | |
# elevation DEM is post-centric. We need to convert to point-centric | |
dem = dem.clip(0, 1) # only interested in whether non-zero elevation or not | |
post = dem[:-1,:-1] + dem[1:,:-1] + dem[:-1,1:] + dem[1:,1:] | |
post = post.astype('B') | |
assert post.shape == (1200, 1200) | |
# write as PNG | |
image = PIL.Image.frombuffer('L', post.shape, post, 'raw', 'L', 0, 1) | |
if True: # 1bpp | |
image = image.point(lambda x: x and 1 or 0, mode='1') | |
image.save(outfile, format='PNG', optimize=True) | |
else: # 8bpp, 5 levels | |
image = image.point([0,63,127,191] + [255]*252) | |
image.save(outfile, format='PNG', transparency=0, optimize=True) | |
# cleanup | |
unlink(join(gettempdir(), basename(infile))) | |
unlink(join(gettempdir(), basename(infile)[:-4] + '.txt')) | |
unlink(join(gettempdir(), basename(infile)[:-4] + '.txt.elevation.raw')) | |
unlink(join(gettempdir(), basename(infile)[:-4] + '.txt.sea_level.raw')) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment