From d3038fad309789c3add9a6ec01367794f87bef10 Mon Sep 17 00:00:00 2001 From: Nick Zatkovich Date: Sun, 30 Jul 2017 14:08:17 -0700 Subject: [PATCH 01/11] BUILD: remove background color from textgen remove the background color when generating the text, then remove the extraneous deutex arguments --- Makefile | 6 +++--- graphics/text/smtextgen | 12 +++++++----- graphics/text/textgen | 2 +- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 17907e42..32a8cde1 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ VERSION=$(shell git describe --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 @@ -62,7 +62,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 +70,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 $< diff --git a/graphics/text/smtextgen b/graphics/text/smtextgen index 799c91ba..cba9f038 100755 --- a/graphics/text/smtextgen +++ b/graphics/text/smtextgen @@ -11,7 +11,7 @@ import re from common import * # Background color for output files. -BACKGROUND_COLOR = '#00ffff' +BACKGROUND_COLOR = None # Width of a space character in pixels. SPACE_WIDTH = 4 @@ -142,10 +142,12 @@ for xy, string in args['strings']: command_line.extend(smallfont.draw_commands_for_text( string, xy[0], xy[1])) -command_line.extend(( - '-background', BACKGROUND_COLOR, - '-flatten', args['filename'], -)) +if BACKGROUND_COLOR is not None: + command_line.extend(( + '-background', BACKGROUND_COLOR, + '-flatten' + )) +command_line.extend((args['filename'],)) invoke_command(command_line) diff --git a/graphics/text/textgen b/graphics/text/textgen index fc8ffcc4..fb8471f3 100755 --- a/graphics/text/textgen +++ b/graphics/text/textgen @@ -18,7 +18,7 @@ COLOR_RED = (0, 100, 100) COLOR_WHITE = (0, 0, 0) # Background color for output files. -BACKGROUND_COLOR = '#00ffff' +BACKGROUND_COLOR = None # Height of font in pixels. FONT_HEIGHT = 15 From 6724ef5aba638e9974f571e3d2e2e30afe27e305 Mon Sep 17 00:00:00 2001 From: Nick Zatkovich Date: Sun, 30 Jul 2017 18:58:54 -0700 Subject: [PATCH 02/11] BUILD: switch to use pillow instead create_caption still relies on ImageMagick --- graphics/text/Makefile | 66 +++++++++------------------------- graphics/text/common.py | 51 +++++++++++++-------------- graphics/text/rotate.py | 16 +++++++++ graphics/text/smtextgen | 55 +++++++++++++---------------- graphics/text/textgen | 72 ++++++++++++++------------------------ graphics/text/tint.py | 55 +++++++++++++++++++++++++++++ graphics/titlepic/Makefile | 27 ++++---------- 7 files changed, 171 insertions(+), 171 deletions(-) create mode 100644 graphics/text/rotate.py create mode 100644 graphics/text/tint.py diff --git a/graphics/text/Makefile b/graphics/text/Makefile index 32959e18..f6107cd1 100644 --- a/graphics/text/Makefile +++ b/graphics/text/Makefile @@ -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 - -# 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) - 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). +all: textgen.mk help.png credit.png wikilrs.png wivctms.png +# Generate the menu and level strings textgen.mk: config.py fontchars ../../lumps/dehacked.lmp - ./textgen $@ > $@ + ./textgen $@ + cp $(TEXTGEN_GRAPHIC_LUMPS) ../ -# 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 '#5599ff' helpbg.png # Generate transparent image containing text for the HELP screen: -helptext.png: helpttl.png - python smtextgen helptext.png 320x200 \ +help.png: helpttl.png helpbg.png + python smtextgen help.png 320x200 \ + -background "helpbg.png" \ 150,5 "file:helpttl.png" \ 10,25 "Weapons" \ 80,25 "file:../../sprites/shota0.png" \ @@ -129,43 +119,21 @@ 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 \ + +credit.png: freettl.png 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: python smtextgen $@ 49x7 \ 0,0 killers wikilrs.png: wikilrs_horiz.png - convert wikilrs_horiz.png -rotate 270 $@ + python rotate.py wikilrs_horiz.png 90 $@ cp $@ ../ wivctms.png: @@ -175,8 +143,8 @@ wivctms.png: 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 \ + helptext2.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 for graphic in $(TEXTGEN_GRAPHICS); do rm -f ../$$graphic; done diff --git a/graphics/text/common.py b/graphics/text/common.py index 8bf0c703..53fee9cd 100644 --- a/graphics/text/common.py +++ b/graphics/text/common.py @@ -4,9 +4,7 @@ import re import subprocess import sys -# ImageMagick commands used by this script: -CONVERT_COMMAND = 'convert' -IDENTIFY_COMMAND = 'identify' +from PIL import Image # Output from 'identify' looks like this: # fontchars/font033.png GIF 9x16 9x16+0+0 8-bit sRGB 32c 194B 0.000u 0:00.000 @@ -15,33 +13,34 @@ 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 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) + def invoke_command(command): - """Invoke a command, printing the command to stdout. + """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 ") + 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) + 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) + sys.stdout.write(' ') + sys.stdout.write('\n') + return subprocess.call(command) \ No newline at end of file diff --git a/graphics/text/rotate.py b/graphics/text/rotate.py new file mode 100644 index 00000000..6ff04da4 --- /dev/null +++ b/graphics/text/rotate.py @@ -0,0 +1,16 @@ +#/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() +img2 = img.rotate(int(sys.argv[2]), None, True) +img2.crop() +if os.path.exists(sys.argv[3]): # delete any previous result file + os.remove(sys.argv[3]) +img2.save(sys.argv[3]) diff --git a/graphics/text/smtextgen b/graphics/text/smtextgen index cba9f038..e9265a48 100755 --- a/graphics/text/smtextgen +++ b/graphics/text/smtextgen @@ -4,11 +4,13 @@ # 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 tint import image_tint # Background color for output files. BACKGROUND_COLOR = None @@ -53,9 +55,8 @@ 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 = [] x1, y1 = x, y @@ -70,22 +71,17 @@ class Font(object): continue filename = self.char_filename(c) - result.extend([ - '-draw', - 'image over %i,%i 0,0 "%s"' % - (x1, y1, filename) - ]) + char_image = Image.open(filename) + image.paste(char_image, (x1, y1)) x1 += self.char_width(c) - return result - - def parse_command_line(args): if len(args) < 4 or (len(args) % 2) != 0: return None result = { 'filename': args[0], + 'background': None, 'strings': [], } @@ -96,6 +92,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 @@ -118,36 +119,30 @@ if not args: smallfont = Font() -command_line = [ - CONVERT_COMMAND, - '-size', '%ix%i' % args['dimensions'], - 'xc:none', -] +if args['background'] is not None: + background_image = Image.open(args['background']) + background_image.load() + background_image = background_image.convert("RGBA") + +image = Image.new("RGBA", args['dimensions'],(0,0,0,0)) for xy, string in args['strings']: # Allow contents of a file to be included with special prefix: - if string.startswith('include:'): + if string.startswith(':'): with open(string[8:]) as f: string = f.read() # 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:]), - )) + src_image = Image.open(string[5:]) + src_image.load() + image.paste(src_image, (xy[0], xy[1])) else: - command_line.extend(smallfont.draw_commands_for_text( - string, xy[0], xy[1])) + smallfont.draw_for_text(image, string, xy[0], xy[1]) -if BACKGROUND_COLOR is not None: - command_line.extend(( - '-background', BACKGROUND_COLOR, - '-flatten' - )) +if args['background'] is not None: + image = Image.alpha_composite(background_image, image) -command_line.extend((args['filename'],)) -invoke_command(command_line) +image.save(args['filename']) diff --git a/graphics/text/textgen b/graphics/text/textgen index fb8471f3..7e49f031 100755 --- a/graphics/text/textgen +++ b/graphics/text/textgen @@ -5,24 +5,26 @@ # 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 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) +COLOR_BLUE = "#000001" +COLOR_RED = "#010000" +COLOR_WHITE = None # Background color for output files. BACKGROUND_COLOR = None # Height of font in pixels. FONT_HEIGHT = 15 -FONT_LC_HEIGHT = 15 #12 +FONT_LC_HEIGHT = 15 # 12 # If true, the font only has uppercase characters. UPPERCASE_FONT = False @@ -30,6 +32,7 @@ UPPERCASE_FONT = False # Width of a space character in pixels. SPACE_WIDTH = 7 + class Font(object): def __init__(self, fontdir, kerning_table={}): self.fontdir = fontdir @@ -106,7 +109,14 @@ class Font(object): if c is None: return x - def _make_command_line(self, text, color): + def generate_graphic(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 construction helper, used in render functions""" width = self.text_width(text) @@ -115,56 +125,27 @@ class Font(object): else: height = FONT_HEIGHT - command_line = [ - CONVERT_COMMAND, - '-size', '%ix%i' % (width, height), - 'xc:none', - ] - + 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() + txt_image.paste(char_image, (x, height - FONT_HEIGHT)) - command_line.extend([ - '-colorize', '%i,%i,%i,0' % color, - ]) + txt_image = image_tint(txt_image, color) + txt_image.save(output_filename) - 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): 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)) + font.generate_graphic(text, target, + color=color, bgcolor=bgcolor) + def generate_kerning_test(): pairs = [] @@ -175,8 +156,8 @@ 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) @@ -186,4 +167,3 @@ font = Font('fontchars', kerning_table=FONT_KERNING_RULES) generate_graphics(red_graphics, color=COLOR_RED) generate_graphics(blue_graphics, color=COLOR_BLUE) generate_graphics(white_graphics, color=COLOR_WHITE) - diff --git a/graphics/text/tint.py b/graphics/text/tint.py new file mode 100644 index 00000000..22eead0a --- /dev/null +++ b/graphics/text/tint.py @@ -0,0 +1,55 @@ +#/usr/bin/env python + +# SPDX-License-Identifier: MIT +# Copyright (c) 2017 Martin Miller +# https://stackoverflow.com/questions/12251896/colorize-image-while-preserving-transparency-with-pil + +from PIL import Image +from ImageColor import getcolor, getrgb +from ImageOps import grayscale + +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 = getrgb(tint) + tl = 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 = (map(lambda lr: int(lr * sr + 0.5), range(256)) + + map(lambda lg: int(lg * sg + 0.5), range(256)) + + map(lambda lb: int(lb * sb + 0.5), range(256))) + l = 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 += 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]) \ No newline at end of file diff --git a/graphics/titlepic/Makefile b/graphics/titlepic/Makefile index a8a2c609..c2dbf5ac 100644 --- a/graphics/titlepic/Makefile +++ b/graphics/titlepic/Makefile @@ -1,23 +1,11 @@ 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 $@ +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 $@ +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 @@ -25,8 +13,7 @@ fdmtitle.png: freedm_titlepic.png 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 - + rm -f fd1title.png fd2title.png fdmtitle.png \ + ../fd1title.png ../fd2title.png ../fdmtitle.png + .PHONY: clean From 215b7c644edb4aa72ed52902e692d312b3a22445 Mon Sep 17 00:00:00 2001 From: Nick Zatkovich Date: Sun, 30 Jul 2017 23:26:52 -0700 Subject: [PATCH 03/11] BUILD: remove the last of the imagemagick stuff The only remaining thing depending on imagemagick are the dist scripts --- Makefile | 4 +- graphics/text/.gitignore | 2 + graphics/text/Makefile | 49 +++++++++++++------ graphics/text/common.py | 46 ------------------ graphics/text/create_caption.py | 40 +++++++++++++++ graphics/text/image_dimensions.py | 23 +++++++++ graphics/text/{smtextgen => smtextgen.py} | 59 ++++++++++++----------- graphics/text/{textgen => textgen.py} | 29 +++++------ graphics/text/tint.py | 12 ++--- graphics/titlepic/.gitignore | 2 - graphics/titlepic/Makefile | 19 -------- graphics/titlepic/README | 6 +-- graphics/titlepic/create_caption | 40 --------------- 13 files changed, 149 insertions(+), 182 deletions(-) delete mode 100644 graphics/text/common.py create mode 100644 graphics/text/create_caption.py create mode 100644 graphics/text/image_dimensions.py rename graphics/text/{smtextgen => smtextgen.py} (66%) rename graphics/text/{textgen => textgen.py} (83%) delete mode 100644 graphics/titlepic/.gitignore delete mode 100644 graphics/titlepic/Makefile delete mode 100755 graphics/titlepic/create_caption diff --git a/Makefile b/Makefile index 32a8cde1..4508f4ff 100644 --- a/Makefile +++ b/Makefile @@ -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 @@ -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 diff --git a/graphics/text/.gitignore b/graphics/text/.gitignore index 4701c6de..817187ca 100644 --- a/graphics/text/.gitignore +++ b/graphics/text/.gitignore @@ -16,3 +16,5 @@ credtext*.png freettl.png helptext*.png wikilrs_horiz.png +fd?title.png +m_*.png diff --git a/graphics/text/Makefile b/graphics/text/Makefile index f6107cd1..a9727b28 100644 --- a/graphics/text/Makefile +++ b/graphics/text/Makefile @@ -52,20 +52,20 @@ TEXTGEN_GRAPHIC_LUMPS = \ TEXTGEN_GRAPHICS = $(TEXTGEN_GRAPHIC_LUMPS) \ helpttl.png freettl.png -all: textgen.mk help.png credit.png wikilrs.png wivctms.png +all: text_strings help.png credit.png wikilrs.png wivctms.png titlepic # Generate the menu and level strings -textgen.mk: config.py fontchars ../../lumps/dehacked.lmp - ./textgen $@ +text_strings: config.py fontchars ../../lumps/dehacked.lmp + python textgen.py cp $(TEXTGEN_GRAPHIC_LUMPS) ../ # Background for the help screen is a color shifted version of INTERPIC: helpbg.png: ../interpic.png - python tint.py ../interpic.png '#5599ff' helpbg.png + python tint.py ../interpic.png '#57b9b0' helpbg.png # Generate transparent image containing text for the HELP screen: -help.png: helpttl.png helpbg.png - python smtextgen help.png 320x200 \ +help.png: text_strings helpbg.png + python smtextgen.py help.png 320x200 \ -background "helpbg.png" \ 150,5 "file:helpttl.png" \ 10,25 "Weapons" \ @@ -97,8 +97,8 @@ help.png: helpttl.png helpbg.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" \ @@ -122,30 +122,47 @@ help.png: helpttl.png helpbg.png cp $@ ../ -credit.png: freettl.png helpbg.png credit.txt - python smtextgen credit.png 320x200 \ +credit.png: text_strings helpbg.png credit.txt + python smtextgen.py credit.png 320x200 \ -background "helpbg.png" \ 120,5 "file:freettl.png" \ 10,30 "include:credit.txt" + cp $@ ../ wikilrs_horiz.png: - python smtextgen $@ 49x7 \ + python smtextgen.py $@ 49x7 \ 0,0 killers wikilrs.png: wikilrs_horiz.png - python rotate.py wikilrs_horiz.png 90 $@ + python rotate.py wikilrs_horiz.png -90 $@ cp $@ ../ wivctms.png: - python smtextgen $@ 54x7 \ + python smtextgen.py $@ 54x7 \ 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 *.pyc credtext.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__ diff --git a/graphics/text/common.py b/graphics/text/common.py deleted file mode 100644 index 53fee9cd..00000000 --- a/graphics/text/common.py +++ /dev/null @@ -1,46 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause - -import re -import subprocess -import sys - -from PIL import Image - -# 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): - """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) - - -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) \ No newline at end of file diff --git a/graphics/text/create_caption.py b/graphics/text/create_caption.py new file mode 100644 index 00000000..281b0d70 --- /dev/null +++ b/graphics/text/create_caption.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python +# coding=utf-8 +from PIL import Image, ImageFont, ImageDraw +import sys +import os + +#create_caption.py + +try: + font = ImageFont.truetype("DejaVuSansCondensed-Bold.ttf", 11) +except IOError: + font = ImageFont.load_default() + + +txt1= u"© 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, (image.height - txt1_size[1] - 5)), txt1, font=font, fill=(255,165,0,255)) +draw.text(((image.width - txt2_size[0] - 10), (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, ((image.width/2 - logo.width/2), 18)) + image.paste(phase, ((image.width/2 - phase.width/2), (image.height - logo.height - 10))) + outfile_name = sys.argv[4] +else: + outfile_name = sys.argv[2] + +image = Image.alpha_composite(background_image, image) +image.save(outfile_name) diff --git a/graphics/text/image_dimensions.py b/graphics/text/image_dimensions.py new file mode 100644 index 00000000..98d1807e --- /dev/null +++ b/graphics/text/image_dimensions.py @@ -0,0 +1,23 @@ +# 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) + diff --git a/graphics/text/smtextgen b/graphics/text/smtextgen.py similarity index 66% rename from graphics/text/smtextgen rename to graphics/text/smtextgen.py index e9265a48..5dc4128f 100755 --- a/graphics/text/smtextgen +++ b/graphics/text/smtextgen.py @@ -9,7 +9,7 @@ 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. @@ -108,41 +108,42 @@ def parse_command_line(args): return result +if __name__ == '__main__': -args = parse_command_line(sys.argv[1:]) + args = parse_command_line(sys.argv[1:]) -if not args: - print("Usage: smtextgen [...text commands...]") - print("Where each text command looks like:") - print(" [x,y] [text]") - sys.exit(0) + if not args: + print("Usage: smtextgen [...text commands...]") + print("Where each text command looks like:") + print(" [x,y] [text]") + sys.exit(0) -smallfont = Font() + smallfont = Font() -if args['background'] is not None: - background_image = Image.open(args['background']) - background_image.load() - background_image = background_image.convert("RGBA") + if args['background'] is not None: + background_image = Image.open(args['background']) + background_image.load() + background_image = background_image.convert("RGBA") -image = Image.new("RGBA", args['dimensions'],(0,0,0,0)) + image = Image.new("RGBA", args['dimensions'],(0,0,0,0)) -for xy, string in args['strings']: - # Allow contents of a file to be included with special prefix: - if string.startswith(':'): - with open(string[8:]) as f: - string = f.read() + 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() - # 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.paste(src_image, (xy[0], xy[1])) - else: - smallfont.draw_for_text(image, string, xy[0], xy[1]) + # 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.paste(src_image, (xy[0], xy[1])) + else: + smallfont.draw_for_text(image, string, xy[0], xy[1]) -if args['background'] is not None: - image = Image.alpha_composite(background_image, image) + if args['background'] is not None: + image = Image.alpha_composite(background_image, image) -image.save(args['filename']) + image.save(args['filename']) diff --git a/graphics/text/textgen b/graphics/text/textgen.py similarity index 83% rename from graphics/text/textgen rename to graphics/text/textgen.py index 7e49f031..327534ac 100755 --- a/graphics/text/textgen +++ b/graphics/text/textgen.py @@ -11,10 +11,10 @@ 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: +# Tinting parameters for colorizing text: COLOR_BLUE = "#000001" COLOR_RED = "#010000" COLOR_WHITE = None @@ -31,6 +31,7 @@ UPPERCASE_FONT = False # Width of a space character in pixels. SPACE_WIDTH = 7 +LOWERCASE_RE = re.compile(r'^[a-z\!\. ]*$') class Font(object): @@ -109,8 +110,7 @@ class Font(object): if c is None: return x - def generate_graphic(self, text, output_filename, - color=COLOR_WHITE, bgcolor=BACKGROUND_COLOR): + def generate_graphic(self, text, color=COLOR_WHITE): """Get command to render text to a file with the given background color. """ @@ -136,15 +136,15 @@ class Font(object): txt_image.paste(char_image, (x, height - FONT_HEIGHT)) txt_image = image_tint(txt_image, color) - txt_image.save(output_filename) + return txt_image -def generate_graphics(graphics, color=COLOR_WHITE, bgcolor=BACKGROUND_COLOR): +def generate_graphics(graphics, color=COLOR_WHITE): for name, text in sorted(graphics.items()): # write a makefile fragment target = '%s.png' % name - font.generate_graphic(text, target, - color=color, bgcolor=bgcolor) + image = font.generate_graphic(text, color=color) + image.save(target) def generate_kerning_test(): @@ -158,12 +158,9 @@ def generate_kerning_test(): cmd = font.generate_graphic(" ".join(pairs), "kerning.png") +if __name__ == '__main__': -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) + font = Font('fontchars', kerning_table=FONT_KERNING_RULES) + generate_graphics(red_graphics, color=COLOR_RED) + generate_graphics(blue_graphics, color=COLOR_BLUE) + generate_graphics(white_graphics, color=COLOR_WHITE) diff --git a/graphics/text/tint.py b/graphics/text/tint.py index 22eead0a..31c7ece4 100644 --- a/graphics/text/tint.py +++ b/graphics/text/tint.py @@ -1,12 +1,10 @@ #/usr/bin/env python # SPDX-License-Identifier: MIT -# Copyright (c) 2017 Martin Miller +# Copyright (c) 2017 Martin Miller, Nick Zatkovich # https://stackoverflow.com/questions/12251896/colorize-image-while-preserving-transparency-with-pil -from PIL import Image -from ImageColor import getcolor, getrgb -from ImageOps import grayscale +from PIL import Image, ImageColor, ImageOps def image_tint(image, tint=None): if tint is None: @@ -14,8 +12,8 @@ def image_tint(image, tint=None): if image.mode not in ['RGB', 'RGBA']: image = image.convert('RGBA') - tr, tg, tb = getrgb(tint) - tl = getcolor(tint, "L") # tint color's overall luminosity + 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 @@ -27,7 +25,7 @@ def image_tint(image, tint=None): luts = (map(lambda lr: int(lr * sr + 0.5), range(256)) + map(lambda lg: int(lg * sg + 0.5), range(256)) + map(lambda lb: int(lb * sb + 0.5), range(256))) - l = grayscale(image) # 8-bit luminosity version of whole image + 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 diff --git a/graphics/titlepic/.gitignore b/graphics/titlepic/.gitignore deleted file mode 100644 index e1ce9728..00000000 --- a/graphics/titlepic/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -fd?title.png -m_*.png diff --git a/graphics/titlepic/Makefile b/graphics/titlepic/Makefile deleted file mode 100644 index c2dbf5ac..00000000 --- a/graphics/titlepic/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -titlepic: fd1title.png fd2title.png fdmtitle.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 fd1title.png fd2title.png fdmtitle.png \ - ../fd1title.png ../fd2title.png ../fdmtitle.png - -.PHONY: clean diff --git a/graphics/titlepic/README b/graphics/titlepic/README index bed85007..d64e4114 100644 --- a/graphics/titlepic/README +++ b/graphics/titlepic/README @@ -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 diff --git a/graphics/titlepic/create_caption b/graphics/titlepic/create_caption deleted file mode 100755 index 3a45d2df..00000000 --- a/graphics/titlepic/create_caption +++ /dev/null @@ -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 From dfde6e879383e43398f978c31fa0e1f03c724d21 Mon Sep 17 00:00:00 2001 From: Nick Zatkovich Date: Sun, 30 Jul 2017 23:31:58 -0700 Subject: [PATCH 04/11] create_captions.py: use default font --- graphics/text/create_caption.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/graphics/text/create_caption.py b/graphics/text/create_caption.py index 281b0d70..20b62387 100644 --- a/graphics/text/create_caption.py +++ b/graphics/text/create_caption.py @@ -6,10 +6,10 @@ import os #create_caption.py -try: - font = ImageFont.truetype("DejaVuSansCondensed-Bold.ttf", 11) -except IOError: - font = ImageFont.load_default() +#try: +# font = ImageFont.truetype("DejaVuSansCondensed-Bold.ttf", 11) +#except IOError: +font = ImageFont.load_default() txt1= u"© 2001-2017" From 648f6aebe9451f71a9c0deac77c2690e4ee71063 Mon Sep 17 00:00:00 2001 From: Nick Zatkovich Date: Mon, 31 Jul 2017 00:13:20 -0700 Subject: [PATCH 05/11] textgen: alpha_composite instead of paste pasting with kerning cut off some of the letters --- graphics/text/smtextgen.py | 12 ++++++++++-- graphics/text/textgen.py | 4 +++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/graphics/text/smtextgen.py b/graphics/text/smtextgen.py index 5dc4128f..47f24f1d 100755 --- a/graphics/text/smtextgen.py +++ b/graphics/text/smtextgen.py @@ -72,9 +72,16 @@ class Font(object): filename = self.char_filename(c) char_image = Image.open(filename) - image.paste(char_image, (x1, y1)) + char_image.load() + self.paste_image(image, char_image, x1, y1) x1 += self.char_width(c) + 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)) + image = Image.alpha_composite(image, int_image) + + def parse_command_line(args): if len(args) < 4 or (len(args) % 2) != 0: return None @@ -108,6 +115,7 @@ def parse_command_line(args): return result + if __name__ == '__main__': args = parse_command_line(sys.argv[1:]) @@ -138,7 +146,7 @@ if __name__ == '__main__': if string.startswith('file:'): src_image = Image.open(string[5:]) src_image.load() - image.paste(src_image, (xy[0], xy[1])) + smallfont.paste_image(image, src_image, xy[0], xy[1]) else: smallfont.draw_for_text(image, string, xy[0], xy[1]) diff --git a/graphics/text/textgen.py b/graphics/text/textgen.py index 327534ac..c93ef695 100755 --- a/graphics/text/textgen.py +++ b/graphics/text/textgen.py @@ -133,7 +133,9 @@ class Font(object): filename = self.char_filename(c) char_image = Image.open(filename) char_image.load() - txt_image.paste(char_image, (x, height - FONT_HEIGHT)) + int_image = Image.new("RGBA", txt_image.size, (0, 0, 0, 0)) + int_image.paste(char_image, (x, height - FONT_HEIGHT)) + txt_image = Image.alpha_composite(txt_image, int_image) txt_image = image_tint(txt_image, color) return txt_image From 4186211e3fde905335b7fe2fcd3325ba68780ea9 Mon Sep 17 00:00:00 2001 From: Nick Zatkovich Date: Mon, 31 Jul 2017 00:29:06 -0700 Subject: [PATCH 06/11] config.py: fix kerning table duplicate entries in the kerning table caused non-deterministic text graphics to be generated --- graphics/text/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphics/text/config.py b/graphics/text/config.py index 9fe0b973..7f7bbd30 100644 --- a/graphics/text/config.py +++ b/graphics/text/config.py @@ -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, From b00f9516e338943b4561bedd9dedf3f9a4f4099d Mon Sep 17 00:00:00 2001 From: Nick Zatkovich Date: Mon, 31 Jul 2017 00:42:57 -0700 Subject: [PATCH 07/11] rotate.py: fix for PILLOW 3.1.x --- graphics/text/rotate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphics/text/rotate.py b/graphics/text/rotate.py index 6ff04da4..0eb8996b 100644 --- a/graphics/text/rotate.py +++ b/graphics/text/rotate.py @@ -9,7 +9,7 @@ import os img = Image.open(sys.argv[1]) img.load() -img2 = img.rotate(int(sys.argv[2]), None, True) +img2 = img.rotate(int(sys.argv[2]), 0, True) img2.crop() if os.path.exists(sys.argv[3]): # delete any previous result file os.remove(sys.argv[3]) From cac04c12714d1ccc689a74fdc6f8f5a35808542f Mon Sep 17 00:00:00 2001 From: Nick Zatkovich Date: Mon, 31 Jul 2017 01:19:53 -0700 Subject: [PATCH 08/11] textgen: cleanup Make the classes self-contained Make the functions re-entrant --- graphics/text/smtextgen.py | 35 ++++++++++----------- graphics/text/textgen.py | 62 ++++++++++++++++++-------------------- 2 files changed, 46 insertions(+), 51 deletions(-) diff --git a/graphics/text/smtextgen.py b/graphics/text/smtextgen.py index 47f24f1d..7d52abf9 100755 --- a/graphics/text/smtextgen.py +++ b/graphics/text/smtextgen.py @@ -12,21 +12,16 @@ import re from image_dimensions import * from tint import image_tint -# Background color for output files. -BACKGROUND_COLOR = None - -# 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.""" @@ -57,15 +52,15 @@ class Font(object): def draw_for_text(self, image, text, x, y): text = text.upper() - + 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 @@ -73,13 +68,15 @@ class Font(object): filename = self.char_filename(c) char_image = Image.open(filename) char_image.load() - self.paste_image(image, char_image, x1, y1) + new_image = self.paste_image(new_image, char_image, x1, y1) x1 += self.char_width(c) + return new_image 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)) - image = Image.alpha_composite(image, int_image) + new_image = Image.alpha_composite(image, int_image) + return new_image def parse_command_line(args): @@ -126,7 +123,7 @@ if __name__ == '__main__': print(" [x,y] [text]") sys.exit(0) - smallfont = Font() + smallfont = SmallTextGenerator() if args['background'] is not None: background_image = Image.open(args['background']) @@ -146,9 +143,9 @@ if __name__ == '__main__': if string.startswith('file:'): src_image = Image.open(string[5:]) src_image.load() - smallfont.paste_image(image, src_image, xy[0], xy[1]) + image = smallfont.paste_image(image, src_image, xy[0], xy[1]) else: - smallfont.draw_for_text(image, string, xy[0], xy[1]) + image = smallfont.draw_for_text(image, string, xy[0], xy[1]) if args['background'] is not None: image = Image.alpha_composite(background_image, image) diff --git a/graphics/text/textgen.py b/graphics/text/textgen.py index c93ef695..99e77d7b 100755 --- a/graphics/text/textgen.py +++ b/graphics/text/textgen.py @@ -14,32 +14,30 @@ from config import * from image_dimensions import * from tint import image_tint -# Tinting parameters for colorizing text: -COLOR_BLUE = "#000001" -COLOR_RED = "#010000" -COLOR_WHITE = None - -# Background color for output files. -BACKGROUND_COLOR = 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\!\. ]*$') -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.""" @@ -87,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) @@ -110,20 +108,20 @@ class Font(object): if c is None: return x - def generate_graphic(self, text, color=COLOR_WHITE): + def generate_graphic(self, text, color=None): """Get command to render text to a file with the given background color. """ - if UPPERCASE_FONT: + 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 + height = self.FONT_HEIGHT txt_image = Image.new("RGBA", (width, height), (0, 0, 0, 0)) for c, x in self.iterate_char_positions(text): @@ -134,14 +132,14 @@ class Font(object): 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 - FONT_HEIGHT)) + int_image.paste(char_image, (x, height - self.FONT_HEIGHT)) txt_image = Image.alpha_composite(txt_image, int_image) txt_image = image_tint(txt_image, color) return txt_image -def generate_graphics(graphics, color=COLOR_WHITE): +def generate_graphics(font, graphics, color=None): for name, text in sorted(graphics.items()): # write a makefile fragment target = '%s.png' % name @@ -149,7 +147,7 @@ def generate_graphics(graphics, color=COLOR_WHITE): image.save(target) -def generate_kerning_test(): +def generate_kerning_test(font): pairs = [] for c1 in sorted(font.char_widths): char1 = "%c" % c1 @@ -162,7 +160,7 @@ def generate_kerning_test(): if __name__ == '__main__': - font = Font('fontchars', kerning_table=FONT_KERNING_RULES) - generate_graphics(red_graphics, color=COLOR_RED) - generate_graphics(blue_graphics, color=COLOR_BLUE) - generate_graphics(white_graphics, color=COLOR_WHITE) + 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) From 7251b148920917f688f5cda266b5bbabdba34301 Mon Sep 17 00:00:00 2001 From: Nick Zatkovich Date: Mon, 31 Jul 2017 02:01:48 -0700 Subject: [PATCH 09/11] rotate: fix rotate Image.rotate had different behavior under 3.1.x, transpose works on all versions --- graphics/text/Makefile | 2 +- graphics/text/rotate.py | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/graphics/text/Makefile b/graphics/text/Makefile index a9727b28..262ba020 100644 --- a/graphics/text/Makefile +++ b/graphics/text/Makefile @@ -134,7 +134,7 @@ wikilrs_horiz.png: 0,0 killers wikilrs.png: wikilrs_horiz.png - python rotate.py wikilrs_horiz.png -90 $@ + python rotate.py wikilrs_horiz.png 270 $@ cp $@ ../ wivctms.png: diff --git a/graphics/text/rotate.py b/graphics/text/rotate.py index 0eb8996b..deb80874 100644 --- a/graphics/text/rotate.py +++ b/graphics/text/rotate.py @@ -9,8 +9,19 @@ import os img = Image.open(sys.argv[1]) img.load() -img2 = img.rotate(int(sys.argv[2]), 0, True) -img2.crop() +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]) From e9015b43b36f39379a1b28bd415846c7dc216c15 Mon Sep 17 00:00:00 2001 From: Nick Zatkovich Date: Mon, 31 Jul 2017 11:31:02 -0700 Subject: [PATCH 10/11] python3 compatibility fixes --- graphics/text/create_caption.py | 10 +++++----- graphics/text/tint.py | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/graphics/text/create_caption.py b/graphics/text/create_caption.py index 20b62387..bb687fa0 100644 --- a/graphics/text/create_caption.py +++ b/graphics/text/create_caption.py @@ -21,17 +21,17 @@ 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, (image.height - txt1_size[1] - 5)), txt1, font=font, fill=(255,165,0,255)) -draw.text(((image.width - txt2_size[0] - 10), (image.height - txt2_size[1] - 5)), txt2, font=font, fill=(255,165,0,255)) +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, ((image.width/2 - logo.width/2), 18)) - image.paste(phase, ((image.width/2 - phase.width/2), (image.height - logo.height - 10))) + 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] diff --git a/graphics/text/tint.py b/graphics/text/tint.py index 31c7ece4..a766b674 100644 --- a/graphics/text/tint.py +++ b/graphics/text/tint.py @@ -22,9 +22,9 @@ def image_tint(image, tint=None): # create look-up tables to map luminosity to adjusted tint # (using floating-point math only to compute table) - luts = (map(lambda lr: int(lr * sr + 0.5), range(256)) + - map(lambda lg: int(lg * sg + 0.5), range(256)) + - map(lambda lb: int(lb * sb + 0.5), range(256))) + 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 @@ -32,7 +32,7 @@ def image_tint(image, tint=None): 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 += range(256) # for 1:1 mapping of copied alpha values + luts += tuple(range(256)) # for 1:1 mapping of copied alpha values return Image.merge(*merge_args).point(luts) From 09f39d4e64be9ad1176b60c41d29aa0662cc67c3 Mon Sep 17 00:00:00 2001 From: Nick Zatkovich Date: Mon, 31 Jul 2017 14:23:33 -0700 Subject: [PATCH 11/11] BUILD: code cleanup, VERSION fix Performed code cleanup, made changes to version number Make gets from Git to make it consistent across git versions --- Makefile | 2 +- graphics/text/Makefile | 26 +++++++++++------------ graphics/text/create_caption.py | 10 ++++----- graphics/text/image_dimensions.py | 1 + graphics/text/rotate.py | 0 graphics/text/{smtextgen.py => smtextgen} | 0 graphics/text/{textgen.py => textgen} | 0 graphics/text/tint.py | 2 +- 8 files changed, 21 insertions(+), 20 deletions(-) mode change 100644 => 100755 graphics/text/create_caption.py mode change 100644 => 100755 graphics/text/image_dimensions.py mode change 100644 => 100755 graphics/text/rotate.py rename graphics/text/{smtextgen.py => smtextgen} (100%) rename graphics/text/{textgen.py => textgen} (100%) mode change 100644 => 100755 graphics/text/tint.py diff --git a/Makefile b/Makefile index 4508f4ff..60437501 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ # 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 diff --git a/graphics/text/Makefile b/graphics/text/Makefile index 262ba020..692db89e 100644 --- a/graphics/text/Makefile +++ b/graphics/text/Makefile @@ -56,7 +56,7 @@ all: text_strings help.png credit.png wikilrs.png wivctms.png titlepic # Generate the menu and level strings text_strings: config.py fontchars ../../lumps/dehacked.lmp - python textgen.py + python textgen cp $(TEXTGEN_GRAPHIC_LUMPS) ../ # Background for the help screen is a color shifted version of INTERPIC: @@ -65,8 +65,8 @@ helpbg.png: ../interpic.png # Generate transparent image containing text for the HELP screen: help.png: text_strings helpbg.png - python smtextgen.py help.png 320x200 \ - -background "helpbg.png" \ + python smtextgen help.png 320x200 \ + -background "helpbg.png" \ 150,5 "file:helpttl.png" \ 10,25 "Weapons" \ 80,25 "file:../../sprites/shota0.png" \ @@ -123,14 +123,14 @@ help.png: text_strings helpbg.png credit.png: text_strings helpbg.png credit.txt - python smtextgen.py credit.png 320x200 \ - -background "helpbg.png" \ - 120,5 "file:freettl.png" \ + python smtextgen credit.png 320x200 \ + -background "helpbg.png" \ + 120,5 "file:freettl.png" \ 10,30 "include:credit.txt" cp $@ ../ wikilrs_horiz.png: - python smtextgen.py $@ 49x7 \ + python smtextgen $@ 49x7 \ 0,0 killers wikilrs.png: wikilrs_horiz.png @@ -138,7 +138,7 @@ wikilrs.png: wikilrs_horiz.png cp $@ ../ wivctms.png: - python smtextgen.py $@ 54x7 \ + python smtextgen $@ 54x7 \ 0,0 victims cp $@ ../ @@ -157,12 +157,12 @@ fdmtitle.png: ../titlepic/freedm_titlepic.png cp $@ ../ clean: - rm -f $(TEXTGEN_GRAPHICS) helpbg.png help.png \ - graphics.stamp *.pyc credtext.png \ - credtext.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 \ - fd1title.png fd2title.png fdmtitle.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__ diff --git a/graphics/text/create_caption.py b/graphics/text/create_caption.py old mode 100644 new mode 100755 index bb687fa0..1d1eac36 --- a/graphics/text/create_caption.py +++ b/graphics/text/create_caption.py @@ -1,18 +1,18 @@ #!/usr/bin/env python -# coding=utf-8 +# 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 -#try: -# font = ImageFont.truetype("DejaVuSansCondensed-Bold.ttf", 11) -#except IOError: font = ImageFont.load_default() -txt1= u"© 2001-2017" +txt1= "© 2001-2017" txt2= os.environ['VERSION'] background_image = Image.open(sys.argv[1]) background_image.load() diff --git a/graphics/text/image_dimensions.py b/graphics/text/image_dimensions.py old mode 100644 new mode 100755 index 98d1807e..4e9f78f7 --- a/graphics/text/image_dimensions.py +++ b/graphics/text/image_dimensions.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python # SPDX-License-Identifier: BSD-3-Clause import re diff --git a/graphics/text/rotate.py b/graphics/text/rotate.py old mode 100644 new mode 100755 diff --git a/graphics/text/smtextgen.py b/graphics/text/smtextgen similarity index 100% rename from graphics/text/smtextgen.py rename to graphics/text/smtextgen diff --git a/graphics/text/textgen.py b/graphics/text/textgen similarity index 100% rename from graphics/text/textgen.py rename to graphics/text/textgen diff --git a/graphics/text/tint.py b/graphics/text/tint.py old mode 100644 new mode 100755 index a766b674..5e940687 --- a/graphics/text/tint.py +++ b/graphics/text/tint.py @@ -50,4 +50,4 @@ if __name__ == '__main__': import os import sys - main(sys.argv[1], sys.argv[2], sys.argv[3]) \ No newline at end of file + main(sys.argv[1], sys.argv[2], sys.argv[3])