These days there are many AI tools that try to imitate various human actions. Calligrapher.ai is one of these tools. It is an app that converts text input into a handwritten form. Go to the website and give it a try yourself. It is a very simple app but does something very powerful. There is not much need for handwritten notes these days. Most people prefer typing on their devices. If we want our text look like handwritten text we can utilize fonts to do that. However, that still doesn't make it handwritten. There is something unique about handwritten words. Everybody has different handwriting, and such notes like letters demonstrate more effort than something that is typed in.
What makes calligrapher.ai different from choices available is that it generates random handwriting every time, and truly makes the the text look like a human wrote the text. It gives few configuration options. We can changes the speed, legibility, and stroke width of the text. It also gives nine different styles option. If we have a long text to convert to handwritten form and want to keep the style of writing consistent, choosing one style might be better rather than letting the app chose them randomly. For many this may not be a useful tool at all, but it is still fun to play with.
In this post I would like to share how to automate converting text into handwritten svg format and save them in our machines for future use. To accomplish this we will use Selenium to launch the app and do the repetitive actions. The code shared below can be used a template for such projects or any other project that involves Selenium. There is something fun, and there is something to learn in this post.
I didn't come across this tool and the project by accident. I did have project with a real use case last week and small part of it involved using calligrapher.ai with Selenium. Initially, I didn't want to use Selenium, because I thought there had to be a python library that did what calligrapher does. There was one. However, I couldn't get it to work properly due to code being old, and updates in the various libraries made certain classes and functions become obsolete and not work. I do believe given enough time that could have been resolved, and code could be refactored to achieve the goal. But that would require more time, which I didn't have at the time. Hence, automating with Selenium was a faster option.
The purpose of the code below is to take a list of text, convert them to handwritten format in a style of our choosing and saving them as svg files. The list of text can be short to do list, song lyrics, poems, letters, or something even much longer. We can utilize document manipulating and/or creating libraries and add our svg files into them. That is not included in this post. I may cover that step in future posts. Let me know if that is something you are would be interested in.
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver import ActionChains
from selenium.webdriver.support.ui import Select
def get_text():
text_list = ['Hive is a decentralized blockchain network.',
'Hive power the next generation of web.',
'True ownership of property is possible with tech and networks like Hive.',
'Building communities and tools to benefit the humanity is what Hive does.']
return text_list
def get_calligrapher():
calli_url = "https://www.calligrapher.ai"
driver = webdriver.Chrome()
driver.maximize_window()
driver.get(calli_url)
speed_slider = WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.ID, 'speed-slider')))
ActionChains(driver).drag_and_drop_by_offset(speed_slider, 40, 0).perform()
bias_slider = WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.ID, 'bias-slider')))
ActionChains(driver).drag_and_drop_by_offset(bias_slider, 20, 0).perform()
width_slider = WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.ID, 'width-slider')))
ActionChains(driver).drag_and_drop_by_offset(width_slider, 20, 0).perform()
select = Select(driver.find_element('id', 'select-style'))
select.select_by_visible_text('9')
return driver
def get_calligrapher_text(driver, text):
text_input = WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.ID, 'text-input')))
text_input.clear()
text_input.send_keys(text)
draw_button = WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.ID, 'draw-button')))
draw_button.click()
time.sleep(3)
save_button = WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.ID, 'save-button')))
save_button.click()
time.sleep(1)
def main():
text_list = get_text()
driver = get_calligrapher()
for text in text_list:
get_calligrapher_text(driver, text)
if __name__ == "__main__":
main()
We start our code in our main() function which only have four lines and utilizing three other functions: get_text(), get_calligrapher(), get_calligrapher_text(). Simple enough.
First we need our list of text that we are planning to convert to handwritten format. Important thing to mention here is that the app only accepts 50 character long text. Anything longer than 50 characters is truncated. If we are not mindful of this, we may lost some parts of our text. We do want to prep our text keeping this fact in mind. My sample text doesn't follow this. If you were to test, you would see that not all letters have been displayed.
Get_calligrapher() function launches the app and makes the initial configuration changes. The app is very simple, identifying all the elements to use with Selenium was super easy. There aren't many elements either. Three elements we make changes to are sliders and configure the speed, legibility, and stroke width of the text. The fourth element we make changes to is the styles option. I selected number 9 style for testing purposes. But all nine styles are good. So, this function launches the app and makes the initial configuration changes per our liking.
The main action happens in the last function, get_calligrapher_text(). Here we input our text. Since we will be repeating the same process and inputting many texts, we want to make sure we clear the input field first. Otherwise it will keep adding the text to the previous ones. Draw button will draw the text in handwritten format on the screen. Lastly, we click the save button and the svg file will end up in our downloads folder. I used three second sleep before saving the file. Not doing so resulted on saved file only having parts of the text.
Now you too can automate handwriting with calligrapher.ai. Nothing complicated here. This is just a template to get started. Let me know what you think about the app in the comments.