User:Dyne
From OpenSimulator
I am posting this here for the time being; it will probably eventually be put somewhere else in the User Docs section.
Below is a python script that takes one or more images (usually greyscale terrain maps, large enough for multiple sims) and splits them into sim-sized tiles. The tiles will be inverted along the Y axis to match OpenSim's axes (you could do this from L3DT, but I find it nicer to have a correctly-oriented full map handy).
Copy the script into your text editor and name the thing terrain-split.py (or whatever). Note that it requires that the Python Imaging Library be installed, or it won't work.
Usage
Assuming that your input is a 512x512 pixel image at the following path (relative to the where you invoke the script):
- mysims/multisim.png
Then you'd run it like:
python terrain-split.py mysims/multisim.png
This will do one of two things, depending on the value of the __interactive__
variable (I haven't made that into a nice commandline switch yet). If it is 0, then the script will spit out these files (along with some text output):
- mysims/multisim.0.1.png (the northwest piece)
- mysims/multisim.1.1.png (the northeast piece)
- mysims/multisim.0.0.png (the southwest piece)
- mysims/multisim.1.0.png (the southeast piece)
The numbers there are intended to aid you in picking grid positions for those sims. You choose a grid position for the lower left/southwest sim ... say (1575, 634). Then, for each sim, just add those two numbers to the base grid X and Y respectively:
- NW: 1575, 635
- NE: 1576, 635
- SW: 1575, 634
- SE: 1576, 634
If the __interactive__
variable is set to 1, the script will be slightly nicer and ask you for the base grid coordinate (always for the sim in the lower left corner) and then the name of each sim as it processes it. If I used the same input file and base coordinates as above, and named the above sims "alice", "bob", "charles", and "dan", then it'd spit out these files:
- mysims/alice.1575.635.png
- mysims/bob.1576.635.png
- mysims/charles.1575.634.png
- mysims/dan.1576.634.png
The tilesize is defined in the script (256 pixels by default, to match the required size for a sim texture at present). The script will take images of arbitrary size (so you could use a 768x1024 input, which will produce 12 sims, in 3 rows and 4 columns), but any pixels along the right or bottom edges that aren't large enough to be a full tile will get ignored. You can also specify multiple input files, and it'll loop through them one by one.
I left the noninteractive mode in, just in case someone wanted to use this in a more automatic fashion.
This has not been fully tested, so there may well be stupid bugs.
Script
#!/usr/bin/python
'''This simple script takes the filename of an image that is a multiple of the tilesize (256 by default), and splits it into tiles of that size.
USAGE: python terrain-split.py infile1 [infile2 ... infileN]
Note that any extra pixels in the original image beyond an even multiple of the tilesize are ignored.
'''
__interactive__ = 1
import Image, ImageOps
import os.path, sys
tilesize=256
for infile in sys.argv[1:]:
try:
myimage = Image.open(infile)
path, filename = os.path.split(infile)
basename, extension = os.path.splitext(filename)
(width,height) = myimage.size
tileswide = width // tilesize
tileshigh = height // tilesize
twremain = width % tilesize # leftover pixels
thremain = height % tilesize # leftover pixels
print
print "---------------------------------------------------------"
print "Input file: " + infile
print "Image dimensions: %s x %s pixels" % (width,height)
print "Output: %s x %s tiles (%s files) of %s pixels square" % (tileswide, tileshigh, tileswide*tileshigh, tilesize)
print "Pixels truncated: %s across, %s down" % (twremain, thremain)
if __interactive__:
print
print "Note: Values in [brackets] are defaults."
print
xin = raw_input("What is the desired grid X coordinate of the lower-left sim [1000]? ")
if xin == "":
basegridX = 1000
else:
basegridX = int(xin)
yin = raw_input("What is the desired grid Y coordinate of the lower-left sim [1000]? ")
if yin == "":
basegridY = 1000
else:
basegridY = int(yin)
for y in range(tileshigh):
print
print "Tiling Row #%s" % str(y+1)
for x in range(tileswide):
# Compute the upper left corner
xnew = x * tilesize
ynew = y * tilesize
yrelative = tileshigh-y-1
# Decide how to name the file
if __interactive__: # the filename will be based on individual names and will include the actual grid coordinates
nameprompt = "What is the name of the sim at row %s, column %s [%s]? " % (y+1, x+1, basename)
simname = raw_input(nameprompt)
if simname == "":
simname = basename
newfile = simname + "." + str(x + basegridX) + "." + str(basegridY+yrelative) + extension
else: # the filename of our output tile is based on the input file and includes relative positions
newfile = basename + "." + str(x) + "." + str(yrelative) + extension
outfile = os.path.join(path, newfile)
# Create the tile
# Flip the tile along the way (transpose) to account for inverted Y axis.
borders = (xnew, ynew, xnew+tilesize, ynew+tilesize)
tile = Image.new("RGB", (tilesize, tilesize))
region = myimage.crop(borders).transpose(Image.FLIP_TOP_BOTTOM)
tile.paste(region, (0,0) )
# Attempt to save it
try:
tile.save(outfile)
print "Writing: File %s with coords %s - %s" % (outfile, (xnew,ynew), (xnew+tilesize-1, ynew+tilesize-1) )
except IOError:
print "Cannot open output file ", outfile
except IOError:
print "Cannot open file ", infile
print "---------------------------------------------------------"