{"id":817,"date":"2021-06-19T22:24:31","date_gmt":"2021-06-20T02:24:31","guid":{"rendered":"https:\/\/www.alpharithms.com\/?p=817"},"modified":"2022-06-16T15:23:56","modified_gmt":"2022-06-16T19:23:56","slug":"load-a-custom-font-using-pillow-in-python","status":"publish","type":"post","link":"https:\/\/www.alpharithms.com\/load-a-custom-font-using-pillow-in-python-312422\/","title":{"rendered":"How to Load a Custom font Using Pillow in Python"},"content":{"rendered":"

The Pillow library is a popular imaging library available for Python. Among its many utilities is the ability to use custom fonts for text manipulation. In this article, we’re going to take a look at just how easy using a custom font with Pillow can be.<\/p>\n

Pillow’s text manipulation toolsets can be used for general text manipulation or analytical purposes like measuring text size and attributes. Pillow’s text utilities cater for more visual use cases and shouldn’t be regarded as a text processing or natural language processing toolset.<\/p>\n

TL;DR – Using Custom Fonts in Pillow<\/h2>\n
\"pillow
Image generated using the following TL;DR Pillow ImageFont and ImageDraw code.<\/figcaption><\/figure>\n

This article will walk you through the basics of loading a custom font in the Pillow imaging library for Python. For those that just want a copy\/paste solution check out the code below.<\/p>\n

# Load a OpenFont format font from a local directory as an ImageFont object\r\n# In this case, a TrueType font using the truetype method.\r\nfont = ImageFont.truetype(font='path\/to\/your\/font.ttf', size=42)\r\n\r\n# Create a new image onto which the text will be added\r\nimage = Image.new(mode='RGB', size=(1024, 256), color='#ffaa00')\r\n\r\n# Create an ImageDraw object onto which the font text will be placed\r\ndraw = ImageDraw.Draw(im=image)\r\n\r\n# Draw the text onto our image\r\ndraw.text(xy=(512, 128), text=\"overcoded - @}\", font=font, fill='black', anchor='mm')\r\n\r\n# Open the image via system standard image viewer\r\nimage.show()<\/pre>\n

This code isn’t very flexible but demonstrates the basic steps involved in using a custom font with the Pillow imaging library:<\/p>\n

    \n
  1. Load a FreeType compatible font (.ttf, .otf, etc.)<\/li>\n
  2. Create a Pillow Image<\/code> object to use as a background for the text<\/li>\n
  3. Create a Pillow ImageDraw<\/code> object to access the text drawing features of Pillow<\/li>\n
  4. Add the custom text to the ImageDraw<\/code> object<\/li>\n
  5. Use the Image.show()<\/code> method to view results in system default image viewer<\/li>\n<\/ol>\n

    There are plenty of options that can be specified during these steps and several notable\u00a0gotchas<\/em> that might pop up. The remainder of this article will attempt to cover the basics as well as advise on how to handle some common issues that are known to pop up.<\/p>\n

    Project Structure + Setup<\/h2>\n

    For the examples in this article, I’ll be using the Source Code Pro font<\/a> available from Google Fonts. I have downloaded it and saved it to a local fonts<\/code> subdirectory in the project folder I created for these examples. Below is the structure of the project.<\/p>\n

    .\r\n\u2514\u2500\u2500 ProjectRoot\r\n    \u251c\u2500\u2500 fonts\r\n    \u2502   \u2514\u2500\u2500 SourceCodePro-Bold.ttf\r\n    \u2514\u2500\u2500 pillow_custom_font_example.py<\/pre>\n

    Pillow<\/a> is an actively maintained fork of the now outdated Python Imaging Library (PIL). Pillow can be installed using pip as such: pip install Pillow<\/code>. Refer to the official Pillow installation docs<\/a> for more guidance on various system installs, upgrading pip, and etc.<\/p>\n

    Note<\/strong>: Pillow and PIL cannot coexist within the same Python installation. You must uninstall PIL if you have it installed before Pillow will be functional.<\/p>\n

    The ImageFont Module<\/h2>\n

    Among Pillow’s 30ish<\/em> modules, the ImageFont<\/a> module allows easy specification of custom fonts. As per the documentation, this module provides utility for bitmap fonts and fonts within the FreeType family (OpenType, TrueType, etc.).<\/p>\n

    The ImageFont module provides custom font support to be used along with the ImageDraw<\/code> module’s text<\/code> method. We’ll get to the ImageDraw.text()<\/code> method shortly but for now let’s start by using the ImageFont<\/code> module’s ImageFont<\/code> class to specify our custom Source Code Pro<\/code> font.<\/p>\n

    Supported Font Types<\/h2>\n

    Fonts come in a variety of types including bitmap, raster, vector, TrueType, OpenType, and several others. Bitmap fonts<\/a> are mostly outdated but can still be found out in the wild roaming around sometimes.<\/p>\n

    Pillow has supported bitmap fonts since its inception and modern releases support OpenType and TrueType with native ImageFont.truetype()<\/code> function. The ImageFont.load_path()<\/code> and ImageFont.load()<\/code> functions will only work with bitmap fonts containing related glyph data and will generate errors for other formats.<\/p>\n

    from PIL import ImageFont\r\nimport os\r\n\r\n# Define the path to our custom .ttf font\r\nfree_type_compatible_font = os.path.abspath(\r\n    os.path.join(\r\n        os.path.dirname(__file__), 'fonts\/SourceCodePro-Black.ttf'\r\n    )\r\n)\r\n\r\n# Open as TrueType native\r\nfont = ImageFont.truetype(font=free_type_compatible_font, size=42)\r\n\r\n>>> <PIL.ImageFont.FreeTypeFont object at 0x0000021736AE94C0>\r\n\r\n# Define the path to our custom .otf font\r\nfree_type_compatible_font = os.path.abspath(\r\n    os.path.join(\r\n        os.path.dirname(__file__), 'fonts\/Montserrat-Regular.otf'\r\n    )\r\n)\r\n\r\n# Open as OpenType font\r\nfont = ImageFont.truetype(font=free_type_compatible_font, size=42)\r\n\r\n>>> <PIL.ImageFont.FreeTypeFont object at 0x00000249E03C94C0>\r\n<\/pre>\n

    As you can see, both the .otf<\/code> and .ttf<\/code> fonts load successfully into memory via the ImageFont. Let’s see what happens when we try to load one of these fonts with the .load() or load_path() methods:<\/p>\n

    # Load using the load method\r\nfont = ImageFont.load(free_type_compatible_font)\r\n\r\n>>> OSError: cannot find glyph data file\r\n\r\n# Load using the load_path method\r\nfont = ImageFont.load_path(free_type_compatible_font)\r\n\r\n>>> OSError: cannot find font file\r\n\r\n<\/pre>\n

    While the last error might seem a bit odd, the Pillow documentation lends the following explanation:<\/p>\n

    Same as ~PIL.ImageFont.load, but searches for a bitmap font along the Python path. Raises OSError if the file could not be read.<\/em><\/p>\n

    I got a little tripped up the first time I got the “cannot find font file” error when trying to [incorrectly] load a .ttf file with the load_path() method. If you see this error just know that it can result from either a missing file\u00a0or\u00a0<\/em>a file not being read properly.<\/p>\n

    Image & ImageDraw Objects<\/h2>\n

    Much of the utility provided by the Pillow library revolves around the use of the Image class. This class is a rollover from the original PIL library and one of the primary reasons one can’t use the Pillow library if PIL is installed in the same environment. From the documentation<\/a>:<\/p>\n

    The Image module provides a class with the same name which is used to represent a PIL image. The module also provides a number of factory functions, including functions to load images from files, and to create new images.<\/em><\/p>\n

    The Image module, being so fundamental to the utilities of Pillow, has a LOT of functionality. We aren’t going to cover much of that here\u2014just know that you can do a lot other than simply load<\/code>, save<\/code>, and show<\/code> images (our use case.) Let’s create an image object to use as a background to display our text:<\/p>\n

    # Create an 1024px x 256px image in solid yellow RGB mode\r\nimage = Image.new(mode='RGB', size=(1024, 256), color='#ffaa00')<\/pre>\n

    Our next step is to create an ImageDraw object that will allow us to use our custom font to create some text. I’ll go ahead and load our font again since it’s been a minute since the top of this article.<\/p>\n

    # Load the font from local storage\r\nfont = ImageFont.truetype(font='fonts\/SourceCodePro-Regular.ttf', size=42)\r\n\r\n# Create an ImageDraw object onto which the font text will be placed\r\ndraw = ImageDraw.Draw(im=image)\r\n\r\n# Draw the text onto our image\r\ndraw.text(xy=(512, 128), text=\"feeling overcoded? - @}\", font=font, fill='black', anchor='mm')\r\n\r\n# Display the image using system standard photo viewer (it's a .png file)\r\nimage.show()\r\n<\/pre>\n

    I’ve kind of hit the gas peddle here and done several things. Let’s break this one down a bit.<\/p>\n

      \n
    1. Font – the font we loaded from local storage<\/li>\n
    2. The ImageDraw object, bound to our Image background<\/li>\n
    3. The ImageDraw.text function sets the size, text, font, and color of our text<\/li>\n
    4. The command that displays the end result<\/li>\n<\/ol>\n

      Note: I’m using the anchor=”mm” argument in the draw.text() method. This is a built-in helper method that controls the positioning (anchoring) of text. It’s a super-convenient group of functions that saves a ton<\/em> of time placing text on images. Check out the full documentation for how to use text anchors with Pillow. For now, just know that “mm” means\u00a0center the text in the middle<\/em>. Here’s what all our hard work has created:<\/p>\n

      \"overcoded
      Our text displays in a size 42 font of our choosing “anchored” to the middle of the background.<\/figcaption><\/figure>\n

      Keep in mind this is a very basic example of what the Pillow ImageFont class can achieve when coupled with other utilities the Pillow library provides. Pillow can help with text wrapping<\/a>, creating ASCII text<\/a>, or just about any other application involving the manipulation of text, images, or both that one can imagine.<\/p>\n

      Final Thoughts<\/h2>\n

      Pillow is the defacto imaging library for more artistic applications in my opinion. The OpenCV wrapper for Python is certainly an industrial-strength imaging library with a lot to offer. In my experience, OpenCV is more suited towards imaging\u00a0data<\/em> applications such as machine learning, statistical analysis, or processing large swaths of visual data. Pillow is just one of the many libraries that makes Python one of the most popular programming languages out there<\/a>. I find few other languages capable of achieving such a high workload with such minimal syntax.<\/p>\n","protected":false},"excerpt":{"rendered":"

      The Pillow library is a popular imaging library available for Python. Among its many utilities is the ability to use custom fonts for text manipulation. In this article, we’re going to take a look at just how easy using a custom font with Pillow can be. Pillow’s text manipulation toolsets can be used for general […]<\/p>\n","protected":false},"author":2,"featured_media":823,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[655,10],"tags":[343,342,345,344,143,339,341],"acf":[],"_links":{"self":[{"href":"https:\/\/www.alpharithms.com\/wp-json\/wp\/v2\/posts\/817"}],"collection":[{"href":"https:\/\/www.alpharithms.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.alpharithms.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.alpharithms.com\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.alpharithms.com\/wp-json\/wp\/v2\/comments?post=817"}],"version-history":[{"count":4,"href":"https:\/\/www.alpharithms.com\/wp-json\/wp\/v2\/posts\/817\/revisions"}],"predecessor-version":[{"id":827,"href":"https:\/\/www.alpharithms.com\/wp-json\/wp\/v2\/posts\/817\/revisions\/827"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.alpharithms.com\/wp-json\/wp\/v2\/media\/823"}],"wp:attachment":[{"href":"https:\/\/www.alpharithms.com\/wp-json\/wp\/v2\/media?parent=817"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.alpharithms.com\/wp-json\/wp\/v2\/categories?post=817"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.alpharithms.com\/wp-json\/wp\/v2\/tags?post=817"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}