Skip to content

Instantly share code, notes, and snippets.

@s-m-e
Last active July 27, 2021 00:47
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save s-m-e/527b26ad2423a11999bb9c3f887a0e96 to your computer and use it in GitHub Desktop.
Save s-m-e/527b26ad2423a11999bb9c3f887a0e96 to your computer and use it in GitHub Desktop.
A Python (3) class for figuring out the width and height of a formatted svg text.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Loosely based on http://stackoverflow.com/a/28741636/1672565
import subprocess
import struct
import os
class svg_text_length(object):
def __init__(
self, text = 'Hello World',
font = 'Arial', font_size = 10, font_weight = 400, font_style = 'normal',
clean_up = True
):
# Cross-platform ...
temp_svg_name = 'temp_svg_text_length.svg'
temp_png_name = 'temp_svg_text_length.png'
# Speeding this thing up on Linux for lots of queries!
# temp_svg_name = '/dev/shm/temp_svg_text_length.svg'
# temp_png_name = '/dev/shm/temp_svg_text_length.png'
svg_cnt = self.__get_dummy_svg__(text, font, font_size, font_weight, font_style)
self.__write_text__(temp_svg_name, svg_cnt)
self.__convert_svg2png__(temp_svg_name, temp_png_name)
png_cnt = self.__read_binary__(temp_png_name)
self.width, self.height = self.__get_image_info__(png_cnt)
if clean_up:
self.__clean_up__([temp_svg_name, temp_png_name])
def get_size(self):
return self.width, self.height
def get_width(self):
return self.width
def __clean_up__(self, file_names):
for file_name in file_names:
os.remove(file_name)
def __convert_svg2png__(self, dest, targ):
# TODO not exactly cross platform ...
inkscape_p = subprocess.Popen(
['inkscape', '-f', dest, '-e', targ, '-d', '90', '-D'],
stdin = subprocess.PIPE,
stdout = subprocess.PIPE
)
inkscape_out = inkscape_p.communicate()[0].decode(encoding = 'UTF-8')
def __get_dummy_svg__(self, text, font, font_size, font_weight, font_style):
return '''
<svg xmlns="http://www.w3.org/2000/svg">
<text
font-weight="%d" font-size="%0.2f" font-family="%s" letter-spacing="0"
font-style="%s" word-spacing="0">
<tspan font-family="%s">%s</tspan>
</text>
</svg>
''' % (font_weight, font_size, font, font_style, font, text)
def __get_image_info__(self, data):
if self.__is_png__(data):
w, h = struct.unpack('>LL', data[16:24])
width = int(w)
height = int(h)
else:
raise Exception('not a png image')
return width, height
def __is_png__(self, data):
return (data[:8] == b'\x89PNG\r\n\x1a\n'and (data[12:16] == b'IHDR'))
def __read_binary__(self, file_name):
f = open(file_name, 'rb')
data = f.read()
f.close()
return data
def __write_text__(self, file_name, cnt):
f = open(file_name, 'w')
f.write(cnt)
f.close()
if __name__ == '__main__':
print(svg_text_length(
text = 'Hello world! Even more text.',
font = 'Arial',
font_size = 25.0,
font_weight = 400,
font_style = 'italic',
clean_up = False
).get_size())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment