Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
Replace each character in a string with a corresponding image
-
If you have individual images for each letter, ideally all with the same height and a transparent background, this should be possible. A few hints to point you in the right direction:
- Text and image data are two separate things. Because of that there is no way to replace a character with an image. A better approach would be to iterate over the string (which can easily be done like
for char in "this is a string"
) and make a list of images corresponding to the text. - The PIL library, which is included in Pythonista, is the way to go with anything related to image manipulation. I haven't used it much myself, but it is very extensive and there will almost definitely be a way to combine multiple images together.
- It would probably be helpful to create a
dict
at the start of your program that maps characters to PIL image objects. Then you can easily access the image for any character, for examplechar_images["x"]
to get the image for a lowercasex
. - To save some typing work you could dynamically create that dictionary from all image files in a certain folder. The
os
module has alistdir
function to get all files in a directory, and theos.path
module contains all sorts of utility functions to work with filenames.
- Text and image data are two separate things. Because of that there is no way to replace a character with an image. A better approach would be to iterate over the string (which can easily be done like
-
This sounds like a very fun app to write with a rich set of features that is quite doable in Pythonista. I suspect that many of the pieces are readily available.
There are LOTS of ways to approach this in Python and with Pythonista:
-
You could put together a UI with some kind of grid that would allow you to train the software on how you write each letter but also allow you to write each one so that it can be linked to the next letter seemlessly. Saving the screen to an image file in PNG should be easy enough. Save each each image in a file named with the particular letter would make it easy to match text to image and you would just need some code to concatenate the images left to right to create and image that looks like writing. That seems like the easy approach and has probably been done many times before.
-
You could store the handwritten info in some vector format that you could "play" back into an image. Then you could do some cool stuff like adding random variations to the data so that it looks more like a human wrote it in different states of mind. You could imagine writing code to make the handwriting look drunk, or angry, or sullen, etc. Then - write code to analyze the actual text of the document and make the handwriting actually react to the content of the original text.
-
You could do a variation on the PNG image method by writing out a custom "font". I could vaguely recall someone who did this one but not in Python. This one would be interesting because you would have to figure out how to install the font on the iPad after it was generated, not to mention all kinds of nasty binary file writing stuff.
-
You could also completely skip the individual character approach and do a "word" based approach. Build a ui that allows you to train it on how to write not only individual characters, but whole words. You could build a UI that works just like a journal and train it by actually writing your journal entries with it to start with. The whole word approach might get you a more natural looking effect.
-
If you want to get real ambitious and learn a lot you could go research what has been done in Python on OCR (Optical Character Recognition) which will tell you how people have used things like neural nets to train a computer on how to read handwritten text and convert it to text. I realize that this is the opposite of what you want to do, but the tools needed to "train" an OCR system is along the lines of what you need to build.
Again - this sounds like a really fun and educational project!
-
-
I think I might want to take a whack at this. I a wondering how easy it would be to get the name of a file in the IOS album though. That would be needed for the way I would do it.
If this is possible, I know how I would do it.
-
You might consider using the PIL ImageFont module, though this won't be quite as fun.
http://effbot.org/imagingbook/imagefont.htm
Not sure if ttf is supported on ios, I think not, you might need to use the convert or tool.
Googling
own handwriting font
produces many sites that let you fill out a template, scan it in, and it automatically generates a vector font file... You will then probably need to convert to the PIL format, see above. Paintfont.com looks good, though I haven't tried myself. Using a template will be a lot easier than custom OCR.Part of the key will be to use the template guides so that letters line up, and are spaced properly. Depending on your scanner this might require some time spent cleaning up noise with an image editor, or font editor.
You could do this multiple times, to create slight variations in the letters, and randomly choose letters on the fly, or have variations based on whether the letter is the beginning, middle or end of a word (extra flourishes, etc).
-
Sounds like fun :-) but I'd webSearch terms like "kerning" and "cursive" to figure out how far off real handwriting the result would be. :-(
Or you could just use Comic Sans... :-)
-
Anyone interested in what is possible with a TrueType handwriting font should have a look at the "Zapfino" font, which comes with all Apple devices. That font is not really useful for anything, but the way it adjusts characters to each other so they look (mostly) like actual handwriting is quite impressive.
-
A mini attempt... Selects an icon for every lowercase letter and then prints out the commandline parameters (or A-to-Z).
import string, sys, ui msg = ' '.join(sys.argv[1:]).lower() or string.lowercase across = 9 # j:Check, o:Sync, q:Queue, r:Read, y:Yes icons = '''Archive Battery_Charging Camera Delete Eject Forward Globe Home Info Check Key Locked Microphone Next Sync Puzzle Feed Eye Star Trash Unlocked Views Write Cross Thumbs_Up Zoom_In''' icons = {k:'Typicons192_'+v for k,v in zip(string.lowercase, icons.split())} view = ui.View() view.present() w = view.width / across h = w * 1.5 for i, c in enumerate(msg): if c != ' ': x, y = i % across, i / across iv = ui.ImageView(frame=(x*w, y*h, w, h)) iv.image = ui.Image.named(icons[c]) view.add_subview(iv)
-
Here's a solution using a TrueType font, which could be custom made on many free sites. Word wraps, auto sizes image, and a cheesy notebook paper background :)
from PIL import Image import ImageFont, ImageDraw import textwrap import itertools import console def convertStringToImage(text,numcols=60,spacing=0.6): border=30 # replace with your custom font font = ImageFont.truetype('/System/Library/Fonts/Cache/Zapfino.ttf',14) # first, figure out image size lines=list(itertools.chain.from_iterable([textwrap.wrap(t, width = numcols) for t in text.splitlines()])) y_text = 0.0 maxwidth=0 for line in lines: width, height = font.getsize(' ' + line+' ') # extra spaces handle script ligatures maxwidth=max(width,maxwidth) y_text += height*spacing size=int(maxwidth+2*border),int(y_text+2*border) #set up image image=Image.new('RGB',size) draw = ImageDraw.Draw(image) draw.rectangle(((0,0),size),fill='#e9e9e5') #draw text y_text = border for line in lines: width, height = font.getsize('a') draw.text((border, y_text), ' '+line+' ', font = font, fill = 'black') #extra space handles scripty stuff draw.line((0,y_text,size[0],y_text),fill='#6666FF') y_text += height*spacing draw.line((0,y_text,size[0],y_text),fill='#6666FF') draw.line((border,0,border,size[0]),fill='#FF6666') image.save('test.png') console.show_image('test.png') convertStringToImage('The rain in spain falls mainly on the plain.\n In fall, it mainly rains on spanish plains. The quick brown fox jumped over thr lazy dog.\n\n Sincerely, \n\t\t Lorum Ipsom',50)
-
Silly example...
-
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):
→ Installing Custom Fonts with Pythonista
(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_moved
and 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
g
where it belongs, or to allow flourishyT
s 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 theFontFile
class 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.open
opens an image from a file.
ui.Image
has 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_moved
Is 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 ontouch_began
, the would set the tangent during touch_moved, and then drop the tangent handle intouch_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.draw
instead 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.
I don't think this is off topic since it depends on whether @wtpetersen wants to implement vectors or not. I certainly appreciate the clear sample. Nicely done @JonB
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 :)
sheet
in the beta, as I understand, no longer has a fixed size like it did in 1.5. You could usefullscreen
, or set the frame size yourself.