Replace each character in a string with a corresponding image
I'm pretty new to python, and use the the pythonista app on my ipad to get some hands-on practice with it. I want to put something together in pythonista that converts a string of text into my handwriting by searching for each character and essentially replacing it with an image of that character in my handwriting, resulting in an image of the text string in my handwriting. I have a few ideas, but given that my python knowledge is pretty limited, it's difficult to know where to start.
I imagine it might work something like this -- I type up an entry (this is for a personal daily journal) in Drafts or Editorial, submit the text to Pythonista which then searches the text as a string and replaces each character with an image kept in a particular location on my device (dropbox folder? iOS photos album?), maybe does some basic formatting, and returns an image depicting what would appear to be a handwritten paragraph.
I understand it's a bit ambitious, but I don't expect to have anything done for me, I just want to know if this is even possible with some combination of LCP, Pythonista, and Drafts/Editorial and if so, if I'm headed in the right direction.
The app MyRealFont lets you create your own ttf font by drawing on the screen, then emails you a link, which you then download using wget in stash for example, or just urllib. the kerning is kind of funky, and I had to keep everything above the baseline, or else things got cut off (maybe a PIL issue) but after a few tries, results are halfway acceptable.
Could be fun to combine the MyRealFont app with this script I wrote a while ago (haven't tried yet):
(Note: the 'open in...' menu integration mentioned in the article doesn't exist anymore, so you'll just have to paste a font URL instead.)
Wow awesome stuff, everybody. I didn't realize this forum would be so responsive, this is great :)
What I described in my post was kind of the baseline of what I wanted to create, but I will definitely be finding a way to introduce a more natural variation into the way the characters are represented once I actually am able to accomplish the image replacement. I neglected to mention for the sake of brevity that I wanted the result to be an image (not text) so that it would be essentially static or permanent in the sense that it would be essentially un-editable after the fact. To introduce variation, I had in my head almost exactly what JonB described, which is to have a whole set of images (preferrably having previously been produced as vectors, allowing them to be superimposed over any background) corresponding to each character, and have Pythonista randomly select one of them to be lined up with the previous letter image. This is where I wanted to implement something like what wradcliffe mentioned, where I could regularly be prompted to write a particular character or set of characters on the screen, so that as my handwriting changes over time, each 'outdated' image will cycled out.
Wradcliffe, you also mentioned replacing whole words, and that sounds really cool. In fact, I'm trying to develop a better cursive script, and something like that would allow me to convert into cursive handwriting without having to design another Zapfino-like font, althought that sounds awesome too. I wouldn't have to record an entire webster's dictionary worth of words either, I could just design the program to prompt me to write out a word when it doesn't recognize it from my typed entry.
The answer to this question may be in this thread already, but if it is, I must have missed it. TutorialDoctor addressed this same concern actually: would I tell Pythonista to retrieve the letter images from an iOS photo album? If so, how? I couldn't find a module with an action that allows any image to be pulled from anywhere other than the camera roll, and I don't really want my character images floating around in there. If not, from where else?
Thanks so much for your help! I'm excited to get to work on this.
I should mention, using ImageDraw does produce an image, as shown above (these are images, just using PIL to get letters from a font). This could easily be extended to draw one letter at a time, from a randomly chosen font... While creating TrueType fonts is complicated, PIL's FontFile class seems very easy, basically it is a list containing metrics and the letters image.
That said. For your approach, you can store images within pythonista. You can use os.mkdir to create a folder, and one of the many methods for transferring files, like dropbox, or use urllib to download from a website, etc.
Or, If you are going to create an app that lets you draw the letters, you would be drawing onto a custom a View that implements
touch_movedand the like, or else a scene that does this. There are some drawing apps built in pythonsita, check Pythonista-Tools for some examples. When you are happy with your letter, you would save the image locally. It is possible to convert a ui.Image to a file. Vectorizing isn't necessary, if you use an alpha channel so the bg is transparent, but would allow you to scale the font and maybe be a little more efficient size wise.
It would be a good idea to also save info about the letter, such as location of the left, right and baseline for the purposes of determining spacing requirements. You might want to allow editing of these parameters graphically, for instance after drawing the letter, you'd draw blue lines showing the letter's nominal box, and allow dragging of those lines for instance to place the baseline of a
gwhere it belongs, or to allow flourishy
Ts that overlap adjacent letters. You might also want to define space between certain letter pairs manually, such as how WV and WA might get spaced differently. , etc. that doesn't necessarily need to be a new image, but maybe just a dict of dicts or something, and when you find pairs that don't look right, you'd tweak and store that combo. You could use a custom structure, which contains a ui.Image and a dict of metrics, which you can the pickle to store on disk, so the image and metrics stay together. Or better yet, use the
FontFileclass that comes with PIL, see FontFile and ImageFont source to figure out how to use, looks fairly easy....
Oh, for your specific question re opening images
PIL.Image.openopens an image from a file.
ui.Imagehas slightly different interface, not well documented, there are a few load methods iirc, from data, and maybe from a url, I forget.
https://omz-forums.appspot.com/pythonista/post/5520750224080896 will be useful, as you may need to convert between PIL images and ui Images.
@JonB - you rock. You have contributed a fabulous example of how powerfull this platform is.
I am curious about your comment on a drawing example. We have painting examples done in Pythonista, but I have not seen anyone tackle a "drawing" example. This means "vectors" - ala Illustrator vs Photoshop/Gimp. Has anyone done a UI sample that allows laying down "dots" and then doing curve fitting to the dots, etc. and then allowing the user to move the dots around? This is the basis for any modern drawing app. Illustrator has sever differnt dot types that tell the system whether to connect the dots using straight lines or splines. It looks like scene has all the rightbuilding blocks but not sure.
Well all of the painting apps in pythonista are really connecting dots. You get a new position every time
touch_movedIs called. Most examples just use lines, though one could easily connect the dots using splines instead. For a "pen tool" type interface, you would add points to a list on
touch_began, the would set the tangent during touch_moved, and then drop the tangent handle in
touch_ended. This would be done in a custom view, rather than imageview, and the drawing would happen in View.draw. Then if you wanted to get fancy, you would allow selecting existing points or tangent handles and moving... The view would have to store a list of these internally to allow editing.
For a "handwritten" font, I think images would work just fine, and "painting" seems more natural for entry. There are probably algorithms for simplifying a path that consists of high density "painted" points, but I think that would require a lot of tweaking, for little gain anyway if you don't plan on doing lots of scaling... If your want everything at some smallish font, raster fonts will work fine, maybe even better. Plus, I don't see an easy route to create TrueType fonts in pythonista -- the fontfile format in PIL is a raster format, and seems easy to work with.
OMZ's example code at: http://omz-forums.appspot.com/pythonista/post/5465174085468160 might help on the curve fitting question.
Ok, sorry to take this off topic.. here is a simple useless path( curve ) editor. You can tap to add or move points and control point handles to make simple piecewise cubic beziers. A more functional demo would auto compute control points for the smooth or endpoint case, allow you to have multiple paths (one active at a time), different colors and weights, path closure, etc... This example does show how to save a ui.View's drawing context to a file, if using
View.drawinstead of an ImageView.
@ccc - thanks for that pointer but it only covers canvas which is not interactive. I had thought that there was no spline support in ui (add_curve) but @JonB shows that it is there. It is part of the ui.Path methods.
One comment. When I ran the path editor sample on my iPad the UI came up in a tiny box 100x100. I have noticed this with quite a few scripts under the 1.6 beta. I had to add a line to force the frame larger in the init method. I reported this already in the beta thread, but apparently this is only happening to me since JonB must have run it and not seen an issue.
Sorry -- I'm not using IOS 8 yet, so am not using the beta. It was Pythonista that pushed me to IOS7, and 1.6 will force me to IOS8, but just not yet :)
sheetin the beta, as I understand, no longer has a fixed size like it did in 1.5. You could use
fullscreen, or set the frame size yourself.
Here is a simple script for opening an image from the camera roll and loading it into an imageview
from PIL import Image import ui import photos import console show_albums = False include_metadata = False original = True raw_data = True multi = False image = ui.Image.from_data(photos.pick_image(show_albums,include_metadata,original,raw_data,multi)) window = ui.load_view() window.present('popover') window['view'].image = image
If you need to know how...
when I run JonB's sample code above using 1.5 on iOS 8 Pythonista always crashes. Any idea why?