mirror of
https://github.com/freedoom/freedoom.git
synced 2025-09-01 13:25:46 -04:00
Merge branch 'textgen'
This commit is contained in:
commit
7a8cdec79a
15 changed files with 301 additions and 315 deletions
12
Makefile
12
Makefile
|
@ -1,10 +1,10 @@
|
|||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
VERSION=$(shell git describe --dirty 2>/dev/null || cat VERSION)
|
||||
VERSION=$(shell git describe --abbrev=8 --dirty 2>/dev/null || cat VERSION)
|
||||
WADS=wads
|
||||
CPP=scripts/simplecpp
|
||||
DEUTEX=deutex
|
||||
DEUTEX_BASIC_ARGS=-v0 -rate accept -rgb 0 255 255
|
||||
DEUTEX_BASIC_ARGS=-v0 -rate accept
|
||||
DEUTEX_ARGS=$(DEUTEX_BASIC_ARGS) -doom2 bootstrap/
|
||||
|
||||
FREEDOOM1=$(WADS)/freedoom1.wad
|
||||
|
@ -16,8 +16,7 @@ OBJS=$(FREEDM) $(FREEDOOM1) $(FREEDOOM2)
|
|||
all: $(OBJS)
|
||||
|
||||
subdirs:
|
||||
$(MAKE) -C graphics/text
|
||||
$(MAKE) VERSION=$(VERSION) -C graphics/titlepic
|
||||
$(MAKE) VERSION=$(VERSION) -C graphics/text
|
||||
$(MAKE) -C lumps/playpal
|
||||
$(MAKE) -C lumps/colormap
|
||||
$(MAKE) -C lumps/genmidi
|
||||
|
@ -62,7 +61,7 @@ $(FREEDM): wadinfo_freedm.txt subdirs
|
|||
$(FREEDOOM1): wadinfo_phase1.txt subdirs
|
||||
@mkdir -p $(WADS)
|
||||
rm -f $@
|
||||
$(DEUTEX) $(DEUTEX_ARGS) -iwad -lumps -patch -flats -sounds -musics -graphics -sprites -levels -build wadinfo_phase1.txt $@
|
||||
$(DEUTEX) $(DEUTEX_ARGS) -iwad -build wadinfo_phase1.txt $@
|
||||
|
||||
#---------------------------------------------------------
|
||||
# phase 2 (doom2) iwad
|
||||
|
@ -70,7 +69,7 @@ $(FREEDOOM1): wadinfo_phase1.txt subdirs
|
|||
$(FREEDOOM2): wadinfo_phase2.txt subdirs
|
||||
@mkdir -p $(WADS)
|
||||
rm -f $@
|
||||
$(DEUTEX) $(DEUTEX_ARGS) -iwad -lumps -patch -flats -sounds -musics -graphics -sprites -levels -build wadinfo_phase2.txt $@
|
||||
$(DEUTEX) $(DEUTEX_ARGS) -iwad -build wadinfo_phase2.txt $@
|
||||
|
||||
%.html: %.adoc
|
||||
TZ=UTC asciidoc $<
|
||||
|
@ -111,7 +110,6 @@ clean:
|
|||
|
||||
$(MAKE) -C dist clean
|
||||
$(MAKE) -C graphics/text clean
|
||||
$(MAKE) -C graphics/titlepic clean
|
||||
$(MAKE) -C lumps/playpal clean
|
||||
$(MAKE) -C lumps/colormap clean
|
||||
$(MAKE) -C lumps/genmidi clean
|
||||
|
|
2
graphics/text/.gitignore
vendored
2
graphics/text/.gitignore
vendored
|
@ -16,3 +16,5 @@ credtext*.png
|
|||
freettl.png
|
||||
helptext*.png
|
||||
wikilrs_horiz.png
|
||||
fd?title.png
|
||||
m_*.png
|
||||
|
|
|
@ -52,31 +52,21 @@ TEXTGEN_GRAPHIC_LUMPS = \
|
|||
TEXTGEN_GRAPHICS = $(TEXTGEN_GRAPHIC_LUMPS) \
|
||||
helpttl.png freettl.png
|
||||
|
||||
all: graphics.stamp help.png credit.png wikilrs.png wivctms.png
|
||||
all: text_strings help.png credit.png wikilrs.png wivctms.png titlepic
|
||||
|
||||
# textgen creates multiple outputs, which is awkward to express in
|
||||
# make. Use a witness file (graphics.stamp) as suggested in the
|
||||
# automake manual: "Handling Tools that Produce Many Outputs"
|
||||
|
||||
graphics.stamp: textgen.mk $(TEXTGEN_GRAPHICS)
|
||||
# Generate the menu and level strings
|
||||
text_strings: config.py fontchars ../../lumps/dehacked.lmp
|
||||
python textgen
|
||||
cp $(TEXTGEN_GRAPHIC_LUMPS) ../
|
||||
@touch $@
|
||||
|
||||
# Construct a file of Make directives for each text graphic.
|
||||
# Each graphic depends on the directives file, so we tell textgen
|
||||
# what its name is, as a command line parameter. The directives
|
||||
# file depends on textgen's input (config, font, dehacked).
|
||||
|
||||
textgen.mk: config.py fontchars ../../lumps/dehacked.lmp
|
||||
./textgen $@ > $@
|
||||
|
||||
# Then, include the file of Make directives constructed above.
|
||||
|
||||
include textgen.mk
|
||||
# Background for the help screen is a color shifted version of INTERPIC:
|
||||
helpbg.png: ../interpic.png
|
||||
python tint.py ../interpic.png '#57b9b0' helpbg.png
|
||||
|
||||
# Generate transparent image containing text for the HELP screen:
|
||||
helptext.png: helpttl.png
|
||||
python smtextgen helptext.png 320x200 \
|
||||
help.png: text_strings helpbg.png
|
||||
python smtextgen help.png 320x200 \
|
||||
-background "helpbg.png" \
|
||||
150,5 "file:helpttl.png" \
|
||||
10,25 "Weapons" \
|
||||
80,25 "file:../../sprites/shota0.png" \
|
||||
|
@ -107,8 +97,8 @@ helptext.png: helpttl.png
|
|||
128,107 "file:../../sprites/pstra0.png" \
|
||||
170,115 "Armor" \
|
||||
220,113 "file:../../sprites/bon2a0.png" \
|
||||
240,105 "file:../../sprites/arm1b0.png" \
|
||||
280,105 "file:../../sprites/arm2b0.png" \
|
||||
240,113 "file:../../sprites/arm1b0.png" \
|
||||
280,110 "file:../../sprites/arm2b0.png" \
|
||||
145,140 "Map" \
|
||||
175,130 "file:../../sprites/pmapa0.png" \
|
||||
10,140 "Overdrive" \
|
||||
|
@ -129,35 +119,14 @@ helptext.png: helpttl.png
|
|||
276,162 "file:../../sprites/bskua0.png" \
|
||||
130,163 "Hazard suit" \
|
||||
215,142 "file:../../sprites/suita0.png"
|
||||
|
||||
# Make background transparent so it can be overlayed.
|
||||
helptext2.png : helptext.png
|
||||
convert helptext.png -transparent '#00ffff' helptext2.png
|
||||
|
||||
# Background for the help screen is a color shifted version of INTERPIC:
|
||||
helpbg.png: ../interpic.png
|
||||
convert ../interpic.png -fill '#5599ff' -tint 100 helpbg.png
|
||||
|
||||
# Draw the overlay with text and sprites onto the background to get the
|
||||
# HELP screen:
|
||||
help.png: helpbg.png helptext2.png
|
||||
convert helpbg.png \
|
||||
-draw 'image over 0,0 0,0 helptext2.png' \
|
||||
help.png
|
||||
cp $@ ../
|
||||
|
||||
credtext.png: freettl.png credit.txt
|
||||
python smtextgen credtext.png 320x200 \
|
||||
120,5 "file:freettl.png" \
|
||||
|
||||
credit.png: text_strings helpbg.png credit.txt
|
||||
python smtextgen credit.png 320x200 \
|
||||
-background "helpbg.png" \
|
||||
120,5 "file:freettl.png" \
|
||||
10,30 "include:credit.txt"
|
||||
|
||||
credtext2.png: credtext.png
|
||||
convert credtext.png -transparent '#00ffff' credtext2.png
|
||||
|
||||
credit.png: helpbg.png credtext2.png
|
||||
convert helpbg.png \
|
||||
-draw 'image over 0,0 0,0 credtext2.png' \
|
||||
credit.png
|
||||
cp $@ ../
|
||||
|
||||
wikilrs_horiz.png:
|
||||
|
@ -165,7 +134,7 @@ wikilrs_horiz.png:
|
|||
0,0 killers
|
||||
|
||||
wikilrs.png: wikilrs_horiz.png
|
||||
convert wikilrs_horiz.png -rotate 270 $@
|
||||
python rotate.py wikilrs_horiz.png 270 $@
|
||||
cp $@ ../
|
||||
|
||||
wivctms.png:
|
||||
|
@ -173,11 +142,27 @@ wivctms.png:
|
|||
0,0 victims
|
||||
cp $@ ../
|
||||
|
||||
titlepic: fd1title.png fd2title.png fdmtitle.png
|
||||
|
||||
fd1title.png: text_strings ../titlepic/titlepic.png ../m_doom.png ../t_phase1.png
|
||||
python create_caption.py ../titlepic/titlepic.png ../m_doom.png ../t_phase1.png $@
|
||||
cp $@ ../
|
||||
|
||||
fd2title.png: text_strings ../titlepic/titlepic.png ../m_doom.png ../t_phase2.png
|
||||
python create_caption.py ../titlepic/titlepic.png ../m_doom.png ../t_phase2.png $@
|
||||
cp $@ ../
|
||||
|
||||
fdmtitle.png: ../titlepic/freedm_titlepic.png
|
||||
python create_caption.py $< $@
|
||||
cp $@ ../
|
||||
|
||||
clean:
|
||||
rm -f $(TEXTGEN_GRAPHICS) helpbg.png help.png helptext.png \
|
||||
helptext2.png graphics.stamp textgen.mk *.pyc credtext.png \
|
||||
credtext2.png credit.png dmwilv*.png wikilrs.png \
|
||||
rm -f $(TEXTGEN_GRAPHICS) helpbg.png help.png \
|
||||
graphics.stamp *.pyc credtext.png \
|
||||
credtext.png credit.png dmwilv*.png wikilrs.png \
|
||||
wivctms.png wikilrs_horiz.png ../credit.png ../help.png \
|
||||
../wikilrs.png ../wivctms.png
|
||||
../wikilrs.png ../wivctms.png \
|
||||
fd1title.png fd2title.png fdmtitle.png \
|
||||
../fd1title.png ../fd2title.png ../fdmtitle.png
|
||||
for graphic in $(TEXTGEN_GRAPHICS); do rm -f ../$$graphic; done
|
||||
rm -fr __pycache__
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
# ImageMagick commands used by this script:
|
||||
CONVERT_COMMAND = 'convert'
|
||||
IDENTIFY_COMMAND = 'identify'
|
||||
|
||||
# Output from 'identify' looks like this:
|
||||
# fontchars/font033.png GIF 9x16 9x16+0+0 8-bit sRGB 32c 194B 0.000u 0:00.000
|
||||
IDENTIFY_OUTPUT_RE = re.compile(r'(\S+)\s(\S+)\s(\d+)x(\d+)(\+\d+\+\d+)?\s')
|
||||
|
||||
# Regexp to identify strings that are all lowercase (can use shorter height)
|
||||
LOWERCASE_RE = re.compile(r'^[a-z\!\. ]*$')
|
||||
|
||||
def get_image_dimensions(filename):
|
||||
proc = subprocess.Popen([IDENTIFY_COMMAND, filename],
|
||||
stdout=subprocess.PIPE)
|
||||
proc.wait()
|
||||
|
||||
line = proc.stdout.readline().decode('utf-8')
|
||||
match = IDENTIFY_OUTPUT_RE.match(line)
|
||||
assert match is not None
|
||||
return (int(match.group(3)), int(match.group(4)))
|
||||
|
||||
def invoke_command(command):
|
||||
"""Invoke a command, printing the command to stdout.
|
||||
|
||||
Args:
|
||||
command: Command and arguments as a list.
|
||||
"""
|
||||
for arg in command:
|
||||
if arg.startswith('-'):
|
||||
sys.stdout.write("\\\n ")
|
||||
|
||||
if ' ' in arg or '#' in arg:
|
||||
sys.stdout.write(repr(arg))
|
||||
else:
|
||||
sys.stdout.write(arg)
|
||||
|
||||
sys.stdout.write(' ')
|
||||
|
||||
sys.stdout.write('\n')
|
||||
return subprocess.call(command)
|
||||
|
|
@ -28,7 +28,7 @@ FONT_KERNING_RULES = {
|
|||
# Left character fits under right character:
|
||||
r'L[TY]': -4,
|
||||
r'L[014COQV]': -3,
|
||||
r'L[O09]': -2,
|
||||
r'L[9]': -2,
|
||||
r'[0O][4TY]': -2,
|
||||
r'[0O][1]': -1,
|
||||
r'Q[1T]': -2,
|
||||
|
|
40
graphics/text/create_caption.py
Executable file
40
graphics/text/create_caption.py
Executable file
|
@ -0,0 +1,40 @@
|
|||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from PIL import Image, ImageFont, ImageDraw
|
||||
import sys
|
||||
import os
|
||||
|
||||
#create_caption.py <background_image> <title?> <phase?> <outfile>
|
||||
|
||||
font = ImageFont.load_default()
|
||||
|
||||
|
||||
txt1= "© 2001-2017"
|
||||
txt2= os.environ['VERSION']
|
||||
background_image = Image.open(sys.argv[1])
|
||||
background_image.load()
|
||||
background_image = background_image.convert("RGBA")
|
||||
image = Image.new("RGBA", background_image.size, (0, 0, 0, 0))
|
||||
draw = ImageDraw.Draw(image)
|
||||
txt1_size = draw.textsize(txt1, font=font)
|
||||
txt2_size = draw.textsize(txt2, font=font)
|
||||
draw.text((5, int(image.height - txt1_size[1] - 5)), txt1, font=font, fill=(255,165,0,255))
|
||||
draw.text((int(image.width - txt2_size[0] - 10), int(image.height - txt2_size[1] - 5)), txt2, font=font, fill=(255,165,0,255))
|
||||
|
||||
if len(sys.argv) > 3:
|
||||
#paste the other stuff onto the thing.
|
||||
logo = Image.open(sys.argv[2])
|
||||
logo.load()
|
||||
phase = Image.open(sys.argv[3])
|
||||
phase.load
|
||||
image.paste(logo, ((int(image.width/2) - int(logo.width/2), 18)))
|
||||
image.paste(phase, ((int(image.width/2) - int(phase.width/2)), int(image.height - phase.height - 30)))
|
||||
outfile_name = sys.argv[4]
|
||||
else:
|
||||
outfile_name = sys.argv[2]
|
||||
|
||||
image = Image.alpha_composite(background_image, image)
|
||||
image.save(outfile_name)
|
24
graphics/text/image_dimensions.py
Executable file
24
graphics/text/image_dimensions.py
Executable file
|
@ -0,0 +1,24 @@
|
|||
#!/usr/bin/env python
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import re
|
||||
|
||||
from PIL import Image
|
||||
|
||||
def get_image_dimensions(filename):
|
||||
"""Get image dimensions w x h
|
||||
|
||||
Args:
|
||||
filename: filename of the image
|
||||
"""
|
||||
with Image.open(filename) as img:
|
||||
width, height = img.size
|
||||
return (width, height)
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
|
||||
x,y = get_image_dimensions(sys.argv[1])
|
||||
string = "%i %i" % (x, y)
|
||||
sys.stdout.write(string)
|
||||
|
27
graphics/text/rotate.py
Executable file
27
graphics/text/rotate.py
Executable file
|
@ -0,0 +1,27 @@
|
|||
#/usr/bin/env python
|
||||
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
from PIL import Image
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
img = Image.open(sys.argv[1])
|
||||
img.load()
|
||||
angle = int(sys.argv[2])
|
||||
if angle % 90 == 0:
|
||||
if angle == 90 or angle == -270:
|
||||
method = Image.ROTATE_90
|
||||
elif abs(angle) == 180:
|
||||
method = Image.ROTATE_180
|
||||
else:
|
||||
method = Image.ROTATE_270
|
||||
img2 = img.transpose(method)
|
||||
else:
|
||||
img2 = img.rotate(int(sys.argv[2]), 0, True)
|
||||
img2 = img2.crop()
|
||||
|
||||
if os.path.exists(sys.argv[3]): # delete any previous result file
|
||||
os.remove(sys.argv[3])
|
||||
img2.save(sys.argv[3])
|
|
@ -4,27 +4,24 @@
|
|||
# Script to generate text graphics using the "small" (HUD) font.
|
||||
#
|
||||
|
||||
from PIL import Image
|
||||
from glob import glob
|
||||
import sys
|
||||
import re
|
||||
|
||||
from common import *
|
||||
from image_dimensions import *
|
||||
from tint import image_tint
|
||||
|
||||
# Background color for output files.
|
||||
BACKGROUND_COLOR = '#00ffff'
|
||||
|
||||
# Width of a space character in pixels.
|
||||
SPACE_WIDTH = 4
|
||||
|
||||
# Height of the font.
|
||||
FONT_HEIGHT = 8
|
||||
|
||||
# Regexp to match dimensions/x,y coordinate pair.
|
||||
DIMENSION_MATCH_RE = re.compile(r'(\d+)[x,](\d+)')
|
||||
|
||||
class Font(object):
|
||||
class SmallTextGenerator(object):
|
||||
def __init__(self):
|
||||
self.get_font_widths()
|
||||
# Width of a space character in pixels.
|
||||
SPACE_WIDTH = 4
|
||||
# Height of the font.
|
||||
FONT_HEIGHT = 8
|
||||
# Regexp to match dimensions/x,y coordinate pair.
|
||||
|
||||
def compile_kerning_table(self, kerning_table):
|
||||
"""Given a dictionary of kerning patterns, compile Regexps."""
|
||||
|
@ -53,31 +50,33 @@ class Font(object):
|
|||
def char_filename(self, c):
|
||||
return '../stcfn%03d.png' % (ord(c))
|
||||
|
||||
def draw_commands_for_text(self, text, x, y):
|
||||
def draw_for_text(self, image, text, x, y):
|
||||
text = text.upper()
|
||||
result = []
|
||||
|
||||
new_image = image.copy()
|
||||
x1, y1 = x, y
|
||||
|
||||
for c in text:
|
||||
if c == '\n':
|
||||
y1 += FONT_HEIGHT
|
||||
y1 += self.FONT_HEIGHT
|
||||
x1 = x
|
||||
elif c == ' ':
|
||||
x1 += SPACE_WIDTH
|
||||
x1 += self.SPACE_WIDTH
|
||||
|
||||
if c not in self:
|
||||
continue
|
||||
|
||||
filename = self.char_filename(c)
|
||||
result.extend([
|
||||
'-draw',
|
||||
'image over %i,%i 0,0 "%s"' %
|
||||
(x1, y1, filename)
|
||||
])
|
||||
char_image = Image.open(filename)
|
||||
char_image.load()
|
||||
new_image = self.paste_image(new_image, char_image, x1, y1)
|
||||
x1 += self.char_width(c)
|
||||
return new_image
|
||||
|
||||
return result
|
||||
def paste_image(self, image, src, x, y):
|
||||
int_image = Image.new("RGBA", image.size, (0, 0, 0, 0))
|
||||
int_image.paste(src, (x, y))
|
||||
new_image = Image.alpha_composite(image, int_image)
|
||||
return new_image
|
||||
|
||||
|
||||
def parse_command_line(args):
|
||||
|
@ -86,6 +85,7 @@ def parse_command_line(args):
|
|||
|
||||
result = {
|
||||
'filename': args[0],
|
||||
'background': None,
|
||||
'strings': [],
|
||||
}
|
||||
|
||||
|
@ -96,6 +96,11 @@ def parse_command_line(args):
|
|||
|
||||
i = 2
|
||||
while i < len(args):
|
||||
if args[i] == '-background':
|
||||
result['background'] = args[i+1]
|
||||
i += 2
|
||||
continue
|
||||
|
||||
m = DIMENSION_MATCH_RE.match(args[i])
|
||||
if not m:
|
||||
return None
|
||||
|
@ -108,44 +113,42 @@ def parse_command_line(args):
|
|||
return result
|
||||
|
||||
|
||||
args = parse_command_line(sys.argv[1:])
|
||||
if __name__ == '__main__':
|
||||
|
||||
if not args:
|
||||
print("Usage: smtextgen <filename> <size> [...text commands...]")
|
||||
print("Where each text command looks like:")
|
||||
print(" [x,y] [text]")
|
||||
sys.exit(0)
|
||||
args = parse_command_line(sys.argv[1:])
|
||||
|
||||
smallfont = Font()
|
||||
if not args:
|
||||
print("Usage: smtextgen <filename> <size> [...text commands...]")
|
||||
print("Where each text command looks like:")
|
||||
print(" [x,y] [text]")
|
||||
sys.exit(0)
|
||||
|
||||
command_line = [
|
||||
CONVERT_COMMAND,
|
||||
'-size', '%ix%i' % args['dimensions'],
|
||||
'xc:none',
|
||||
]
|
||||
smallfont = SmallTextGenerator()
|
||||
|
||||
for xy, string in args['strings']:
|
||||
# Allow contents of a file to be included with special prefix:
|
||||
if string.startswith('include:'):
|
||||
with open(string[8:]) as f:
|
||||
string = f.read()
|
||||
if args['background'] is not None:
|
||||
background_image = Image.open(args['background'])
|
||||
background_image.load()
|
||||
background_image = background_image.convert("RGBA")
|
||||
|
||||
# Allow special notation to indicate an image file to just draw
|
||||
# rather than rendering a string.
|
||||
if string.startswith('file:'):
|
||||
command_line.extend((
|
||||
'-draw',
|
||||
'image over %i,%i 0,0 "%s"' % (
|
||||
xy[0], xy[1], string[5:]),
|
||||
))
|
||||
else:
|
||||
command_line.extend(smallfont.draw_commands_for_text(
|
||||
string, xy[0], xy[1]))
|
||||
image = Image.new("RGBA", args['dimensions'],(0,0,0,0))
|
||||
|
||||
command_line.extend((
|
||||
'-background', BACKGROUND_COLOR,
|
||||
'-flatten', args['filename'],
|
||||
))
|
||||
for xy, string in args['strings']:
|
||||
# Allow contents of a file to be included with special prefix:
|
||||
if string.startswith('include:'):
|
||||
with open(string[8:]) as f:
|
||||
string = f.read()
|
||||
|
||||
invoke_command(command_line)
|
||||
# Allow special notation to indicate an image file to just draw
|
||||
# rather than rendering a string.
|
||||
if string.startswith('file:'):
|
||||
src_image = Image.open(string[5:])
|
||||
src_image.load()
|
||||
image = smallfont.paste_image(image, src_image, xy[0], xy[1])
|
||||
else:
|
||||
image = smallfont.draw_for_text(image, string, xy[0], xy[1])
|
||||
|
||||
if args['background'] is not None:
|
||||
image = Image.alpha_composite(background_image, image)
|
||||
|
||||
image.save(args['filename'])
|
||||
|
||||
|
|
|
@ -5,37 +5,39 @@
|
|||
# Freedoom, by compositing individual font character graphics together.
|
||||
#
|
||||
|
||||
from PIL import Image
|
||||
from glob import glob
|
||||
import re
|
||||
import sys
|
||||
|
||||
from config import *
|
||||
from common import *
|
||||
from image_dimensions import *
|
||||
from tint import image_tint
|
||||
|
||||
# ImageMagick -colorize parameters for colorizing text:
|
||||
COLOR_BLUE = (100, 100, 0)
|
||||
COLOR_RED = (0, 100, 100)
|
||||
COLOR_WHITE = (0, 0, 0)
|
||||
|
||||
# Background color for output files.
|
||||
BACKGROUND_COLOR = '#00ffff'
|
||||
|
||||
# Height of font in pixels.
|
||||
FONT_HEIGHT = 15
|
||||
FONT_LC_HEIGHT = 15 #12
|
||||
|
||||
# If true, the font only has uppercase characters.
|
||||
UPPERCASE_FONT = False
|
||||
|
||||
# Width of a space character in pixels.
|
||||
SPACE_WIDTH = 7
|
||||
|
||||
class Font(object):
|
||||
class TextGenerator(object):
|
||||
def __init__(self, fontdir, kerning_table={}):
|
||||
self.fontdir = fontdir
|
||||
self.kerning_table = self.compile_kerning_table(kerning_table)
|
||||
self.get_font_widths()
|
||||
|
||||
# Tinting parameters for colorizing text:
|
||||
COLOR_BLUE = "#000001"
|
||||
COLOR_RED = "#010000"
|
||||
COLOR_WHITE = None
|
||||
|
||||
# Height of font in pixels.
|
||||
FONT_HEIGHT = 15
|
||||
FONT_LC_HEIGHT = 15 # 12
|
||||
|
||||
# If true, the font only has uppercase characters.
|
||||
UPPERCASE_FONT = False
|
||||
|
||||
# Width of a space character in pixels.
|
||||
SPACE_WIDTH = 7
|
||||
LOWERCASE_RE = re.compile(r'^[a-z\!\. ]*$')
|
||||
|
||||
def compile_kerning_table(self, kerning_table):
|
||||
"""Given a dictionary of kerning patterns, compile Regexps."""
|
||||
|
||||
|
@ -83,7 +85,7 @@ class Font(object):
|
|||
last_c = ' '
|
||||
for c in text:
|
||||
if c == ' ':
|
||||
x += SPACE_WIDTH
|
||||
x += self.SPACE_WIDTH
|
||||
|
||||
if c in self:
|
||||
x += self.kerning_adjust(last_c, c)
|
||||
|
@ -106,67 +108,46 @@ class Font(object):
|
|||
if c is None:
|
||||
return x
|
||||
|
||||
def _make_command_line(self, text, color):
|
||||
def generate_graphic(self, text, color=None):
|
||||
"""Get command to render text to a file
|
||||
with the given background color.
|
||||
"""
|
||||
|
||||
if self.UPPERCASE_FONT:
|
||||
text = text.upper()
|
||||
"""Command line construction helper, used in render functions"""
|
||||
width = self.text_width(text)
|
||||
|
||||
if LOWERCASE_RE.match(text):
|
||||
height = FONT_LC_HEIGHT
|
||||
if self.LOWERCASE_RE.match(text):
|
||||
height = self.FONT_LC_HEIGHT
|
||||
else:
|
||||
height = FONT_HEIGHT
|
||||
|
||||
command_line = [
|
||||
CONVERT_COMMAND,
|
||||
'-size', '%ix%i' % (width, height),
|
||||
'xc:none',
|
||||
]
|
||||
height = self.FONT_HEIGHT
|
||||
|
||||
txt_image = Image.new("RGBA", (width, height), (0, 0, 0, 0))
|
||||
for c, x in self.iterate_char_positions(text):
|
||||
if c is None:
|
||||
break
|
||||
|
||||
filename = self.char_filename(c)
|
||||
command_line.extend([
|
||||
'-draw',
|
||||
'image over %i,%i 0,0 %s' %
|
||||
(x, height - FONT_HEIGHT, filename)
|
||||
])
|
||||
char_image = Image.open(filename)
|
||||
char_image.load()
|
||||
int_image = Image.new("RGBA", txt_image.size, (0, 0, 0, 0))
|
||||
int_image.paste(char_image, (x, height - self.FONT_HEIGHT))
|
||||
txt_image = Image.alpha_composite(txt_image, int_image)
|
||||
|
||||
command_line.extend([
|
||||
'-colorize', '%i,%i,%i,0' % color,
|
||||
])
|
||||
txt_image = image_tint(txt_image, color)
|
||||
return txt_image
|
||||
|
||||
return command_line
|
||||
|
||||
def get_command(self, text, output_filename,
|
||||
color=COLOR_WHITE, bgcolor=BACKGROUND_COLOR):
|
||||
"""Get command to render text to a file
|
||||
with the given background color.
|
||||
"""
|
||||
|
||||
if UPPERCASE_FONT:
|
||||
text = text.upper()
|
||||
command_line = self._make_command_line(text, color)
|
||||
|
||||
if bgcolor is not None:
|
||||
command_line.extend([
|
||||
'-background', bgcolor, '-flatten'])
|
||||
|
||||
command_line.append(output_filename)
|
||||
|
||||
return command_line
|
||||
|
||||
def generate_graphics(graphics, color=COLOR_WHITE, bgcolor=BACKGROUND_COLOR):
|
||||
def generate_graphics(font, graphics, color=None):
|
||||
for name, text in sorted(graphics.items()):
|
||||
print("# %s.png: '%s'" % (name, text))
|
||||
# write a makefile fragment
|
||||
target = '%s.png' % name
|
||||
cmd = font.get_command(text, target,
|
||||
color=color, bgcolor=bgcolor)
|
||||
print("%s: %s" % (target, " ".join(sys.argv[1:])))
|
||||
print("\t" + " ".join("'%s'" % i for i in cmd))
|
||||
image = font.generate_graphic(text, color=color)
|
||||
image.save(target)
|
||||
|
||||
def generate_kerning_test():
|
||||
|
||||
def generate_kerning_test(font):
|
||||
pairs = []
|
||||
for c1 in sorted(font.char_widths):
|
||||
char1 = "%c" % c1
|
||||
|
@ -175,15 +156,11 @@ def generate_kerning_test():
|
|||
if font.kerning_adjust(char1, char2) != 0:
|
||||
pairs.append(char1 + char2)
|
||||
|
||||
cmd = font.get_command(" ".join(pairs), "kerning.png")
|
||||
invoke_command(cmd)
|
||||
cmd = font.generate_graphic(" ".join(pairs), "kerning.png")
|
||||
|
||||
font = Font('fontchars', kerning_table=FONT_KERNING_RULES)
|
||||
|
||||
# Enable to generate test image file for tweaking kerning values:
|
||||
#generate_kerning_test()
|
||||
|
||||
generate_graphics(red_graphics, color=COLOR_RED)
|
||||
generate_graphics(blue_graphics, color=COLOR_BLUE)
|
||||
generate_graphics(white_graphics, color=COLOR_WHITE)
|
||||
if __name__ == '__main__':
|
||||
|
||||
font = TextGenerator('fontchars', kerning_table=FONT_KERNING_RULES)
|
||||
generate_graphics(font, red_graphics, color=font.COLOR_RED)
|
||||
generate_graphics(font, blue_graphics, color=font.COLOR_BLUE)
|
||||
generate_graphics(font, white_graphics, color=font.COLOR_WHITE)
|
||||
|
|
53
graphics/text/tint.py
Executable file
53
graphics/text/tint.py
Executable file
|
@ -0,0 +1,53 @@
|
|||
#/usr/bin/env python
|
||||
|
||||
# SPDX-License-Identifier: MIT
|
||||
# Copyright (c) 2017 Martin Miller, Nick Zatkovich
|
||||
# https://stackoverflow.com/questions/12251896/colorize-image-while-preserving-transparency-with-pil
|
||||
|
||||
from PIL import Image, ImageColor, ImageOps
|
||||
|
||||
def image_tint(image, tint=None):
|
||||
if tint is None:
|
||||
return image
|
||||
if image.mode not in ['RGB', 'RGBA']:
|
||||
image = image.convert('RGBA')
|
||||
|
||||
tr, tg, tb = ImageColor.getrgb(tint)
|
||||
tl = ImageColor.getcolor(tint, "L") # tint color's overall luminosity
|
||||
if not tl:
|
||||
tl = 1 # avoid division by zero
|
||||
tl = float(tl) # compute luminosity preserving tint factors
|
||||
sr, sg, sb = map(lambda tv: tv / tl, (tr, tg, tb)
|
||||
) # per component adjustments
|
||||
|
||||
# create look-up tables to map luminosity to adjusted tint
|
||||
# (using floating-point math only to compute table)
|
||||
luts = (tuple(map(lambda lr: int(lr * sr + 0.5), range(256))) +
|
||||
tuple(map(lambda lg: int(lg * sg + 0.5), range(256))) +
|
||||
tuple(map(lambda lb: int(lb * sb + 0.5), range(256))))
|
||||
l = ImageOps.grayscale(image) # 8-bit luminosity version of whole image
|
||||
if Image.getmodebands(image.mode) < 4:
|
||||
merge_args = (image.mode, (l, l, l)) # for RGB verion of grayscale
|
||||
else: # include copy of image's alpha layer
|
||||
a = Image.new("L", image.size)
|
||||
a.putdata(image.getdata(3))
|
||||
merge_args = (image.mode, (l, l, l, a)) # for RGBA verion of grayscale
|
||||
luts += tuple(range(256)) # for 1:1 mapping of copied alpha values
|
||||
|
||||
return Image.merge(*merge_args).point(luts)
|
||||
|
||||
def main(input_image_path, tintcolor, result_image_path):
|
||||
image = Image.open(input_image_path)
|
||||
|
||||
image.load()
|
||||
|
||||
result = image_tint(image, tintcolor)
|
||||
if os.path.exists(result_image_path): # delete any previous result file
|
||||
os.remove(result_image_path)
|
||||
result.save(result_image_path) # file name's extension determines format
|
||||
|
||||
if __name__ == '__main__':
|
||||
import os
|
||||
import sys
|
||||
|
||||
main(sys.argv[1], sys.argv[2], sys.argv[3])
|
2
graphics/titlepic/.gitignore
vendored
2
graphics/titlepic/.gitignore
vendored
|
@ -1,2 +0,0 @@
|
|||
fd?title.png
|
||||
m_*.png
|
|
@ -1,32 +0,0 @@
|
|||
titlepic: fd1title.png fd2title.png fdmtitle.png
|
||||
|
||||
m_doom.png: ../m_doom.png
|
||||
convert -transparent '#00ffff' ../m_doom.png m_doom.png
|
||||
|
||||
m_dm.png: ../m_dm.png
|
||||
convert -transparent '#00ffff' ../m_dm.png m_dm.png
|
||||
|
||||
t_phase1.png: ../t_phase1.png
|
||||
convert -transparent '#00ffff' ../t_phase1.png t_phase1.png
|
||||
|
||||
t_phase2.png: ../t_phase2.png
|
||||
convert -transparent '#00ffff' ../t_phase2.png t_phase2.png
|
||||
|
||||
fd1title.png: titlepic.png m_doom.png t_phase1.png
|
||||
./create_caption titlepic.png m_doom.png t_phase1.png $@
|
||||
cp $@ ../
|
||||
|
||||
fd2title.png: titlepic.png m_doom.png t_phase2.png
|
||||
./create_caption titlepic.png m_doom.png t_phase2.png $@
|
||||
cp $@ ../
|
||||
|
||||
fdmtitle.png: freedm_titlepic.png
|
||||
./create_caption $< $@
|
||||
cp $@ ../
|
||||
|
||||
clean:
|
||||
rm -f m_dm.png m_doom.png fd1title.png fd2title.png fdmtitle.png \
|
||||
../fd1title.png ../fd2title.png ../fdmtitle.png t_phase1.png \
|
||||
t_phase2.png
|
||||
|
||||
.PHONY: clean
|
|
@ -1,4 +1,2 @@
|
|||
This directory contains a shell script that uses ImageMagick to layer
|
||||
some text information about the build version onto the game's title
|
||||
screen. The same is performed for each of the three IWADs.
|
||||
|
||||
This directory contains template images for generating the title screen
|
||||
for Freedoom Phase 1, Phase 2, and FreeDM
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
find_font() {
|
||||
local font fontlist
|
||||
fontlist=$(convert -list font | awk '$1=="Font:" { print $2 }')
|
||||
for font in "$@" ; do
|
||||
if echo $fontlist | grep -q $font ; then
|
||||
echo $font
|
||||
return
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
font=$(find_font Helvetica-Bold Liberation-Sans-Bold DejaVu-Sans-Condensed-Bold)
|
||||
if [ -z "$font" ] ; then echo "Cannot find any fonts" ; exit 1 ; fi
|
||||
|
||||
draw_with_footer() {
|
||||
input_file=$1;
|
||||
output_file=$2;
|
||||
shift; shift
|
||||
|
||||
convert $input_file -fill orange -font "$font" +dither \
|
||||
-pointsize 11 \
|
||||
-gravity southwest \
|
||||
-draw "text 5,5 '© 2001-2017'" \
|
||||
-gravity southeast \
|
||||
-draw "text 10,5 '$VERSION'" \
|
||||
"$@" \
|
||||
$output_file
|
||||
}
|
||||
|
||||
if [ $# = 4 ]; then
|
||||
draw_with_footer "$1" "$4" \
|
||||
-gravity north \
|
||||
-draw "image over 0,18 0,0 '$2'" \
|
||||
-gravity south \
|
||||
-draw "image over 0,30 0,0 '$3'"
|
||||
else
|
||||
draw_with_footer "$1" "$2"
|
||||
fi
|
Loading…
Add table
Add a link
Reference in a new issue