Skip to content

Commit

Permalink
First commit - v0.2
Browse files Browse the repository at this point in the history
  • Loading branch information
sullerandras committed Jan 29, 2016
0 parents commit 2892b0a
Show file tree
Hide file tree
Showing 14 changed files with 3,549 additions and 0 deletions.
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Compile Terraria textures to higher resolution.

Old technique:
1. extract png files from Terraria xnb files
2. downscale extracted png files to 50%
3. clear separator lines
4. magnify downscaled images with ImageResizer-r133.exe
5. convert magnified images to xnb

New idea:
- instead of clearing the separator lines, we remove those rows and columns from the images (making them smaller)
- after the magnification, we need to reinsert the separator rows and columns
- This would make the magnified images smoother and hopefully no artifacts at the edges / corners
Problems:
- The tiles in the image may not belong to each other. For example there are multiple chests in a single image file, and there should be empty columns between the chests to make them nicely magnified, but no empty columns at the middle of the chests. This is especially hard to do with Walls and Tiles images because there are several variations and each of them should be compatible with any other variation.
84 changes: 84 additions & 0 deletions execute.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#!/usr/bin/env bash

TERRARIA_CONTENT_FOLDER=Terraria.v1.3.0.8-read-only/Content
EXTRACTED_FOLDER=temp1
DOWNSCALED_FOLDER=temp2
NO_SEPARATORS_FOLDER=temp3
MAGNIFIED_FOLDER=temp4
REFILLED_FOLDER=temp5
RELEASE_FOLDER=temp6-release
TARGET_TERRARIA_CONTENT_FOLDER=Terraria.v1.3.0.8/Content

function extractPngsFromTerraria() {
echo "calling TExtract $1 => $2"
mkdir -p $2
mkdir -p $2/UI
java -jar "tools/TExtract 1.6.0.jar" --outputDirectory $2 $1/Images/*.xnb
java -jar "tools/TExtract 1.6.0.jar" --outputDirectory $2/UI $1/Images/UI/*.xnb
}
function downscalePngs() {
echo "downscaling images $1 => $2"
mkdir -p $2
mkdir -p $2/UI
wine tools/downscale_pngs.exe "$1" "$2"
wine tools/downscale_pngs.exe "$1/UI" "$2/UI"
}
function removeSeparators() {
echo "removing separators $1 => $2"
mkdir -p $2
mkdir -p $2/UI
python tools/remove_separators.py "$1" "$2"
python tools/remove_separators.py "$1/UI" "$2/UI"
}
function magnifyPngs() {
echo "magnifying images $1 => $2"
mkdir -p $2
mkdir -p $2/UI
RESIZE_METHOD="XBRz 2x(vbounds=wrap,hbounds=wrap)"

for filename in `ls $1 | grep -i png`; do
echo /load "$1/$filename" /resize auto "\"$RESIZE_METHOD\"" /save "$2/$filename"
done > test.scr
for filename in `ls $1/UI | grep -i png`; do
echo /load "$1/UI/$filename" /resize auto "\"$RESIZE_METHOD\"" /save "$2/UI/$filename"
done >> test.scr
wine tools/ImageResizer-r133.exe /script test.scr
}
function refillMissingPixels() {
echo "refilling missing pixels in Walls and Tiles $1 => $2"
mkdir -p $2
mkdir -p $2/UI
wine tools/refill_missing_pixels.exe $1 $2
wine tools/refill_missing_pixels.exe $1/UI $2/UI
}
function pngsToXnbs() {
echo "converting to XNB's $1 => $2"
mkdir -p $2/Images
mkdir -p $2/Images/UI
wine tools/png_to_xnb.exe $1 $2/Images
wine tools/png_to_xnb.exe $1/UI $2/Images/UI
}
function createRelease() {
version=$1
out_file=Images-$version.zip
echo "Creating zip file Images-$version.zip with all XNB's"
mkdir -p $3/Images
rm -f $out_file
rsync -ax --delete-after $2/Images/ $3/Images/
rm -rf --preserve-root $3/Images/Backgrounds
rm -rf --preserve-root $3/Images/Misc
echo "Enhanced version of the textures of Terraria 1.3.0.8" > $3/README.txt
echo "" >> $3/README.txt
echo "Crated by Andras Suller, `date +%F`, $version." >> $3/README.txt
echo "For more information visit: http://forums.terraria.org/index.php?threads/enhanced-version-of-the-textures-of-terraria-1-3-0-8.39115/" >> $3/README.txt
cd $3
zip -r ../$out_file README.txt Images
cd ..
}
# extractPngsFromTerraria $TERRARIA_CONTENT_FOLDER $EXTRACTED_FOLDER
# downscalePngs $EXTRACTED_FOLDER $DOWNSCALED_FOLDER
# removeSeparators $DOWNSCALED_FOLDER $NO_SEPARATORS_FOLDER
# magnifyPngs $NO_SEPARATORS_FOLDER $MAGNIFIED_FOLDER
refillMissingPixels $MAGNIFIED_FOLDER $REFILLED_FOLDER
pngsToXnbs $REFILLED_FOLDER $TARGET_TERRARIA_CONTENT_FOLDER
# createRelease v0.2 $TARGET_TERRARIA_CONTENT_FOLDER $RELEASE_FOLDER
70 changes: 70 additions & 0 deletions tools/Array3D.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import copy

TRANSPARENT = (0, 0, 0, 0)

class Array3D(object):
def __init__(self, data, width=0, height=0, depth=0):
if width == 0 or height == 0 or depth == 0:
raise Exception('Invalid parameters: width: %s, height: %s, depth: %s' % (width, height, depth))
if depth != 4:
raise Exception('Depth must be 4 but got %d' % depth)
super(Array3D, self).__init__()
self.data = data
self.width = width
self.height = height
self.depth = depth

def isOpaque(self, x, y):
if x < 0 or x >= self.width or y < 0 or y >= self.height:
return False
return self.data[y][x * self.depth + 3] > 0

def isTransparent(self, x, y):
return not self.isOpaque(x, y)

def anyNeighborsAreOpaque(self, x, y):
return self.isOpaque(x - 1, y) or self.isOpaque(x + 1, y) or self.isOpaque(x, y - 1) or self.isOpaque(x, y + 1)

def getPixelAt(self, x, y):
if x < 0 or x >= self.width or y < 0 or y >= self.height:
return
return self.data[y][x * self.depth : (x + 1) * self.depth]

def setPixelAt(self, x, y, color):
if len(color) != self.depth:
raise Exception('Color len should be %d but got %d' % (self.depth, len(color)))
if x < 0 or x >= self.width or y < 0 or y >= self.height:
return
for i in xrange(self.depth):
if color[i] < 0 or color[i] > 255:
raise Exception('Invalid color component: %d' % color[i])
self.data[y][x * self.depth + i] = color[i]

def copyAndRotate(self, fromx, fromy, tox, toy, width, height, rotation):
rotation = rotation % 4
for x in xrange(width):
for y in xrange(height):
if rotation == 0:
self.setPixelAt(tox + x, toy + y, self.getPixelAt(fromx + x, fromy + y))
elif rotation == 1:
self.setPixelAt(tox + (height - 1 - y), toy + x, self.getPixelAt(fromx + x, fromy + y))
elif rotation == 2:
self.setPixelAt(tox + (width - 1 - x), toy + (height - 1 - y), self.getPixelAt(fromx + x, fromy + y))
elif rotation == 3:
self.setPixelAt(tox + y, toy + (width - 1 - x), self.getPixelAt(fromx + x, fromy + y))

def nearestNonSeparator(self, x, y, vertical):
if (x == self.width - 1) or (y == self.height - 1):
return TRANSPARENT
if vertical: # vertical separator line
if self.isOpaque(x - 1, y):
return self.getPixelAt(x - 1, y)
return self.getPixelAt(x + 1, y)
if not vertical: # horizontal separator line
if self.isOpaque(x, y - 1):
return self.getPixelAt(x, y - 1)
return self.getPixelAt(x, y + 1)
return TRANSPARENT

def clone(self):
return Array3D(copy.deepcopy(self.data), self.width, self.height, self.depth)
Binary file added tools/ImageResizer-r133.exe
Binary file not shown.
Binary file added tools/TExtract 1.6.0.jar
Binary file not shown.
Binary file added tools/Wall-mask-468px.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions tools/config.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Configuration>
<LastSaveDirectory value="" />
<LastLoadDirectory value="Z:\home\andras\projects\terraria-images-magnifier-new\temp3" />
<SourceSizeMode value="" />
<TargetSizeMode value="CenterImage" />
</Configuration>
52 changes: 52 additions & 0 deletions tools/downscale_images.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
from __future__ import print_function
import glob
import ntpath
import png
import traceback
import sys

from Array3D import Array3D

def error(*objs):
print("ERROR: ", *objs, file=sys.stderr)

def downscale_pixelarray(pixelarray):
width = (pixelarray.width + 1) / 2
height = (pixelarray.height + 1) / 2
data = [[0 for x in xrange(0, width * pixelarray.depth)] for y in xrange(0, height)]
for y in xrange(0, height):
for x in xrange(0, width):
for i in xrange(4):
data[y][x * pixelarray.depth + i] = pixelarray.data[y * 2][x * pixelarray.depth * 2 + i]
return Array3D(data, width, height, pixelarray.depth)

def downscale_image(input_filename, output_filename):
img = png.Reader(filename=input_filename)
(width, height, pixels, meta) = img.asRGBA8()
data = [row for row in pixels]
pixelarray = Array3D(data, width, height, depth=4)
pixelarray = downscale_pixelarray(pixelarray)

writer = png.Writer(width=pixelarray.width, height=pixelarray.height, alpha=True, bitdepth=8, compression=9)
print('writing file %s' % output_filename)
f = open(output_filename, 'wb')
try:
writer.write(f, pixelarray.data)
finally:
f.close()

def downscale_images(input_dir, output_dir):
for input_filename in glob.glob('%s/*.png' % (input_dir,)):
output_filename = '%s/%s' % (output_dir, ntpath.basename(input_filename))
try:
downscale_image(input_filename=input_filename, output_filename=output_filename)
except Exception as err:
error("Unexpected error while processing %s: %s" % (input_filename, str(err)))
error(traceback.format_exc())
raise err

if len(sys.argv) < 3:
print("Usage: python %s input_dir output_dir" % (sys.argv[0],))
print("Downcale all *.png images in input_dir and saves the result in output_dir (with the same name).")
else:
downscale_images(sys.argv[1], sys.argv[2])
Binary file added tools/downscale_pngs.exe
Binary file not shown.
Loading

0 comments on commit 2892b0a

Please sign in to comment.