Draw bold/italic text with PIL? - python

How to draw bold/italic text with PIL? ImageFont.truetype(file, size) has an option to specify font size only.

Use the bold/italic version of the font

There is no bold features as parameter till now but easily you can solve by add stroke to the text with same color of text. it will make sense as bold font next code elaborate how to use stroke
draw.text((x, y), text, fill=color, font=font, stroke_width=2,
stroke_fill="black")

A rather hacky solution to make a font bold if (for whatever reason) you don't have a separate bold version of the font is to print the same text several times with a slight offset.
andaleMono = ImageFont.truetype(ANDALE_MONO_PATH,16)
text = "hello world"
mainOffset = (50,50)
xoff, yoff = mainOffset
draw.text(mainOffset,text,font=andaleMono,fill='black')
draw.text((xoff+1,yoff+1),text,font=andaleMono,fill='black')
draw.text((xoff-1,yoff-1),text,font=andaleMono,fill='black')

Many fonts use different TTF files for their bold/italic versions, so I'd imagine if you just specify that file it would work.

Well, this is my first comment. Here we go.
I'll try to clarify the procedure. At first What I did was use the "name" of the font like this
font = ImageFont.truetype("C:\Windows\Fonts\\Arial Negrita.ttf",25)
but only got some errors like this:
Traceback (most recent call last):
File "C:/Users/555STi/PycharmProjects/PIL/img.py", line 8, in <module>
font = ImageFont.truetype("C:\Windows\Fonts\Arial negrita.ttf",25)
File "C:\Python27\lib\site-packages\PIL\ImageFont.py", line 262, in truetype
return FreeTypeFont(font, size, index, encoding)
File "C:\Python27\lib\site-packages\PIL\ImageFont.py", line 142, in __init__
self.font = core.getfont(font, size, index, encoding)
IOError: cannot open resource
Then I remembered that sometimes fonts has other "names" or "filenames", so, what I did was going to fonts folder, then opened the Arial Font wich displayed all the styles like negrita (bold], cursiva(italic), etc.
Did a right click on the "negrita" style, selected "properties" and then there was the "real name" of the font.
In my case, the name was "ariblk"
Then, finally, just used the name like this.
font = ImageFont.truetype("C:\Windows\Fonts\\ariblk.ttf",25)
I know this post is old, but today helped me to get to the solution. So I hope to help anybody.
=)

With reference to the other answers here, my search for the name for the bold variant of Arial produced the following (arialbd.ttf):
def FindFontsVariantsWithBase(fontBase="arial"):
import matplotlib
system_fonts = matplotlib.font_manager.findSystemFonts(fontpaths=None, fontext='ttf')
# for font in np.sort(system_fonts):
# print(font)
fonts = np.sort(system_fonts).tolist()
res = [i for i in fonts if fontBase in i]
print(res)
FindFontsVariantsWithBase("arial")
['C:\WINDOWS\Fonts\arial.ttf', 'C:\WINDOWS\Fonts\arialbd.ttf', 'C:\WINDOWS\Fonts\arialbi.ttf', 'C:\WINDOWS\Fonts\ariali.ttf', 'C:\Windows\Fonts\arial.ttf', 'C:\Windows\Fonts\arialbd.ttf', 'C:\Windows\Fonts\arialbi.ttf', 'C:\Windows\Fonts\ariali.ttf'] (

Related

Specifying a Font from a file location ptext in pygame

I understand how to use a font from the .ttf file in normal python.
font1 = pygame.font.Font("/resources/fonts/robotoThin.ttf")
but I could not find in the documentation of ptext, or on the web how to specify the font when using
ptext.draw(text,(x,y))
Using pycharm
According to the ptext repo's README, you can specify the fontname parameter in your call to ptext.draw like so:
ptext.draw(text, (x,y), fontname="fonts/Viga.ttf")
There are also options for creating templates for the fontname (see the link above) but I'm not seeing a way to save the font as a variable to avoid reloading it every time.

Retrieving font style, size and other attributes from a word document

I am working with python 3.6, my question is that is it possible to retrieve information from an existing document such as the font name of the text, the font size,etc.
I have tried using python-docx to help me with it but when I try using run.font I only get None returned.
I think this is helpful.
import docx
path = '/home/karamveer/Downloads/222.docx' #your docx file path
doc = docx.Document(path)
for p in doc.paragraphs:
name = p.style.font.name
size = p.style.font.size
print name, size
Using run.font work. The other answer didn't work as well for me so I'll answer this here
For font names, it will always return None if it's is "inherited from the style hierarchy," according to the documentation. I'll assume this means the default font of the document's default style. I've tried this with different fonts and it worked for me, giving me None for the default font and naming the different font names.
Font size appears to be the same, giving None for default sizes.
Font documentation
I used this to check and it worked for me. Hope it helps.
for p in doc.paragraphs:
fonts = []
texts = []
sizes = []
for i in p.runs:
fonts.append(i.font.name)
texts.append(i.text)
sizes.append(i.font.size)
print(texts, fonts, sizes, sep="\n")

Creating a lightweight fallback font with fontforge and fonttools

For a webapp I need a way to prevent that a browser falls back to another font if my web font doesn't include a character. It seems the only way to do this is to add another font to the fontstack which includes "all" possible characters 1.
There are already existing fallback fonts, but those are more debug helpers as they show the codepoint as number, therefore they are much to heavy (>2MB).
The fallback font for my usecase should just show something like a box to signal a missing character.
My idea was to generate a simple font with only one glyph and apply a feature file which will replace all glyphs with this one.
My script for fontforge:
import fontforge
import fontTools.feaLib.builder as feaLibBuilder
from fontTools.ttLib import TTFont
font_name = 'maeh.ttf'
font = fontforge.font()
glyph = font.createChar(33, "theone")
pen = glyph.glyphPen()
pen.moveTo((100,100))
pen.lineTo((100,500))
pen.lineTo((500,500))
pen.lineTo((500,100))
pen.closePath()
for i in range(34, 99):
glyph = font.createChar(i)
glyph.width=10
font.cidConvertTo('Adobe', 'Identity', 0) # doesn't make a difference
font.generate(font_name)
font = TTFont(font_name)
feaLibBuilder.addOpenTypeFeatures(font, 'fallback.fea')
font.save("fea_"+font_name)
My feature file:
languagesystem DFLT dflt;
#all=[\00035-\00039];
##all=[A-Z] this works
feature liga {
sub #all by theone;
} liga;
But the above results in a
KeyError: ('cid00037', 'SingleSubst[0]', 'Lookup[0]', 'LookupList')
with changing numbers for cid00037.
If I use the out commented A-Z from the Feature file it works, so this approach doesn't seem to be completely wrong.
Why can't fonttools find the glyphs if I specify the range in CID notation?
Is there another way to crate a class for the OpenType feature file which includes all glyphs?
While working on the above problem, somebody hinted me to the Adobe NotDef font, which is pretty much what I was looking for. For some reason I wasn't able to convert the .otf of the Adobe NotDef to woff or woff2 with fontforge. Also all the online tools to create the web font files like fontsquirrel failed. To create the woff file I used sfnt2woff from the woff-tools package. For the woff2 file I used https://github.com/google/woff2.

Pdftron - creating new element with same styles as existing element

I am trying to create PDF editing prototype using PdfTron software.
I have successfully created interface where user can click on image, created from PDF, select region and will be presented a text input where he/she can then enter text, that will replace the content in PDF file.
Now the text replacing part is problematic. Since there is no API doc for Python (only examples) I am following Java / Android API documentation.
Where I am for now. I have following code to find out the elements that are in user selected rectangle. Values x1, y1, x2, y2 are PDF coordinates based on user selection in the front end.
rect = Rect(x1, y1, x2, y2)
text = ''
extractor = TextExtractor()
extractor.Begin(page)
line = extractor.GetFirstLine()
words = []
while line.IsValid():
word = line.GetFirstWord()
while word.IsValid():
elRect = word.GetBBox()
elRect.Normalize()
if elRect.IntersectRect(elRect, rect):
text += ' ' + word.GetString()
words.append(word)
word = word.GetNextWord()
line = line.GetNextLine()
words is basically array where I store the content that will later need to be replaced for new element.
Now the problem. I want the new element have the same style and font that the old text has.
Api (link) tells me that using
style = words[0].GetStyle()
gives me style of the word and I can get font from style using
font = style.GetFont()
doc : https://www.pdftron.com/pdfnet/mobile/docs/Android/pdftron/PDF/TextExtractor.Style.html
But this returned font is of Obj class not Font class.
And apparently creating new text element with font requires object of Font class.
Because
element = eb.CreateTextBegin(font, 10.0);
generates an error:
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/home/alan/.virtualenvs/pdfprint/local/lib/python2.7/site-packages/PDFNetPython2.py", line 5056, in CreateTextBegin
def CreateTextBegin(self, *args): return _PDFNetPython2.ElementBuilder_CreateTextBegin(self, *args)
NotImplementedError: Wrong number or type of arguments for overloaded function 'ElementBuilder_CreateTextBegin'.
Possible C/C++ prototypes are:
pdftron::PDF::ElementBuilder::CreateTextBegin(pdftron::PDF::Font,double)
pdftron::PDF::ElementBuilder::CreateTextBegin()
Perhaps there is better approach to achieving same result?
Edit1
Reading docs I found that you can create Font object based on Object like:
font = Font(style.GetFont())
Still stuck on creating element with those styles though.
/edit1
Edit2
I use following code to test writing into file:
style = elements[0].GetStyle()
font = Font(style.GetFont())
fontsize = style.GetFontSize()
eb = ElementBuilder()
element = eb.CreateTextBegin(font, 10.0)
writer.WriteElement(element)
element = eb.CreateTextRun('My Name')
element.SetTextMatrix(10, 0, 0, 10, 100, 100)
gstate = element.GetGState()
gstate.SetTextRenderMode(GState.e_fill_text)
gstate.SetStrokeColorSpace(ColorSpace.CreateDeviceRGB())
gstate.SetStrokeColor(ColorPt(1, 1, 1))
element.UpdateTextMetrics()
writer.WriteElement(element)
writer.WriteElement(eb.CreateTextEnd())
writer.End()
from core.helpers import ensure_dir
ensure_dir(output_filename)
doc.Save(output_filename, SDFDoc.e_linearized)
doc.Close()
What I cant figure out is:
How to copy styles from existing element.
How to position new element in document.
Why this test code does not give me visible results. As far as I see new file gets created by it does not have "My Name" anywhere in it.
/Edit2
Based on the code above it looks like you want to append some text to an existing page based on the font style (font name + color) used by the first word on the page.
There are couple issue with the above code. You are setting the stroke color rather than fill:
gstate.SetTextRenderMode(GState.e_fill_text)
gstate.SetStrokeColorSpace(ColorSpace.CreateDeviceRGB());
gstate.SetStrokeColor(ColorPt(1, 1, 1))
try
gstate.SetTextRenderMode(GState.e_fill_text)
gstate.SetFillColorSpace(ColorSpace.CreateDeviceRGB());
gstate.SetFillColor(ColorPt(1, 0, 0)) // hardcode to red … for testing purposes only
The main issue is most likely related to Font handling. You are hijacking an existing font and are assuming that this font is using ‘standard encoding’. However this font is likely not using standard encoding. Also fonts in existing PDFs are often sub-setted (this means that the font does not contain a full list of glyphs, but only character references that are present in the document). As a result, you may see notdef or whitespace instead of the expected text. This and some other issues are covered here:
https://groups.google.com/d/msg/pdfnet-sdk/RBTuJG2uILk/pGkrKnqZ_YIJ
https://groups.google.com/d/msg/pdfnet-sdk/2y8s5aehq-c/xyknr9W5r-cJ
As an solution, instead of using embedded font directly you can find a matching system font (e.g. based on font name and other properties) and create a new font. PDFNet offers a utility method Font.Create(doc, font) , or Font.Create(doc, "Font name").
This methods will create a Unicode font so you should use eb.CreateUnicodeTextRun() rather than eb.CreateTextRun().
Alternatively you could use AcroForm as a template (see InteractiveForms sample) and pdfdoc.FattenAnnotations() to end-up with read-only version of the document.

Python PIL using different font

I have an image I would like to add text to but I want to use both a different style font and a something bigger than the smallest thing known to mankind. Heck you can hardly read the text it's so darn small. I can print the text to the screen but I can't change the font style or the size of it as I don't know where the fonts are stored. I would think there would be more than one font/font size standardly available for use with Python/PIL. Where are they stored at? I am on a Linux.
Adapted from this answer:
image = Image.new("RGBA", (600,150), (255,255,255))
draw = ImageDraw.Draw(image)
font = ImageFont.truetype("resources/HelveticaNeueLight.ttf", fontsize)
draw.text((10, 0), txt, (0,0,0), font=font)
Looks like you can specify any .ttf file and any fontsize you want using the above modules and functions.

Categories

Resources