Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- """
- PIL Line Writer
- Simple class for writing multiline text centered on an image with even line
- spacing.
- To use create a line writer object by passing a PIL image object and a padding
- value. Then to write text call the LineWriter's text method with the text you
- would like centered on the image over multiple lines. It also takes an optional
- line height argument which will scale the line heights. Additionally you can
- pass any keyword settings that are valid for ImageDraw.draw.text.
- Example:
- image = Image.new("RGBA", (300, 300), "yellow")
- writer = LineWriter(image, 60)
- writer.text(
- "To the inspiration of necessity, we owe half the wise, beautiful, and useful blessings of the world.",
- 1.5,
- fill="black"
- )
- image.show()
- """
- from PIL import Image, ImageDraw
- class LineWriter:
- """ Simple class for writing multiline text centered on a PIL image with
- even line spacing. """
- def __init__(self, image: Image.Image, padding: int, offset_x: int = 0, offset_y: int = 0):
- self._image = image
- self._draw = ImageDraw.Draw(image)
- self._padding = padding
- self._last_line_y = 0
- self._offset_x = offset_x
- self._offset_y = offset_y
- @property
- def height(self) -> int:
- """ Height of the image. """
- return self._image.size[1]
- @property
- def last_line_y(self) -> int:
- """ Gives the y position after the last line drawn. """
- return self._last_line_y
- @property
- def width(self) -> int:
- """ Width of the image. """
- return self._image.size[0]
- def line_height(self, font) -> int:
- """ Height of our standard line. """
- return self._draw.textsize("hj", font=font)[0]
- def text(self, message: str, line_height: float=1.0, **settings):
- """ Writes the text centered on the image. Takes a line height argument
- for scaling the line height and also takes all valid keywords for
- ImageDraw.Draw.text. """
- lines = self._build_lines(message, settings.get("font"))
- height = self.line_height(settings.get("font")) * line_height
- self._last_line_y = (self.height - len(lines) * height) // 2
- for line in lines:
- width, _ = self._draw.textsize(line, settings.get("font"))
- self._draw.text(
- (
- (self.width - width) // 2 + self._offset_x,
- self.last_line_y + self._offset_y
- ),
- line,
- **settings
- )
- self._last_line_y += height
- def _build_lines(self, message: str, font):
- """ Breaks a line of text up into a series of lines that fit onto the
- image with the correct padding. """
- lines = []
- line = []
- for word in message.split(" "):
- test_line = list(line)
- test_line.append(word)
- width, _ = self._draw.textsize(" ".join(test_line), font=font)
- if width > self.width - self._padding * 2:
- lines.append(" ".join(line))
- line = [word]
- else:
- line = test_line
- if line:
- lines.append(" ".join(line))
- return lines
- if __name__ == "__main__":
- image = Image.new("RGBA", (300, 300), "yellow")
- writer = LineWriter(image, 60)
- writer.text(
- "To the inspiration of necessity, we owe half the wise, beautiful, and useful blessings of the world.",
- 1.5,
- fill="black"
- )
- image.show()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement