2

For every page in a given PDF file it's possible to list the fonts used:

$ pdffonts -f 10 -l 10 file.pdf
name                                 type              encoding         emb sub uni object ID
------------------------------------ ----------------- ---------------- --- --- --- ---------
[none]                               Type 3            Custom           yes no  no      12  0
DIIDPF+ArialMT                       CID TrueType      Identity-H       yes yes yes     95  0
DIIEDH+Arial                         CID TrueType      Identity-H       yes yes no     101  0
DIIEBG+TimesNewRomanPSMT             CID TrueType      Identity-H       yes yes yes    106  0
DIIEDG+Arial                         CID TrueType      Identity-H       yes yes no     112  0
Arial                                TrueType          WinAnsi          yes no  no     121  0

I need to identify likely problematic fonts based on pdffonts output and count characters based on its font. I achieved it by implementing the following snippet:

def count_fonts_ocurrencies_by_page(pdf_filepath):
    page_layout = next(extract_pages(pdf_filepath))

    fonts = []

    for element in page_layout:
        if isinstance(element, LTTextContainer):
            for text_line in element:
                for character in text_line:
                    if isinstance(character, LTChar):
                        fonts.append(character.fontname)

    return Counter(fonts)

I'm looking forward to find a straightforward way to do the same (or close, I only need to know something like a percentage of font usage on a single PDF page) without iterating every char (if possible) or maybe without using a whole module, like pdfminer, just for one function and for one PDF page at time. It would be also helpful if I could do something similar (re)using the minimum code from pdfminer, as it's built in a modular way.

Aserre
  • 4,916
  • 5
  • 33
  • 56
Kfcaio
  • 442
  • 1
  • 8
  • 20
  • There is a difference between text rendering (encoding, glyph) and text extraction (ToUnicode, CMap), right? I agree that what I asked is not a trivial task, but maybe any direction/clarification about my problem would be helpful and worthy. As a PDF newbie, lack of field vocabulary is also a thing – Kfcaio Jul 14 '21 at 11:39

1 Answers1

4

You could try using pdftohtml from the same package of pdffonts and then parse html file with xpath taking into account the styles

pdftohtml -f 1 -l 1 -c -s -i -fontfullname fonts.pdf

Generated doc

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
<title>fonts-html.html</title>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
 <br/>
<style type="text/css">
<!--
    p {margin: 0; padding: 0;}  .ft10{font-size:16px;font-family:BAAAAA+NotoSans-CondensedExtraBold;color:#000000;}
    .ft11{font-size:16px;font-family:CAAAAA+DejaVuMathTeXGyre-Regular;color:#000000;}
    .ft12{font-size:13px;font-family:DAAAAA+Baekmuk-Headline;color:#000000;}
    .ft13{font-size:13px;font-family:EAAAAA+LMMono9-Regular;color:#000000;}
    .ft14{font-size:13px;font-family:FAAAAA+CantarellRegular;color:#000000;}
    .ft15{font-size:13px;font-family:GAAAAA+Courier;color:#000000;}
-->
</style>
</head>
<body bgcolor="#A0A0A0" vlink="blue" link="blue">
<div id="page1-div" style="position:relative;width:892px;height:1263px;">
<img width="892" height="1263" src="fonts001.png" alt="background image"/>
<p style="position:absolute;top:64px;left:86px;white-space:nowrap" class="ft10"><b>Font1</b></p>
<p style="position:absolute;top:91px;left:86px;white-space:nowrap" class="ft11">font3</p>
<p style="position:absolute;top:109px;left:86px;white-space:nowrap" class="ft12">font4</p>
<p style="position:absolute;top:124px;left:86px;white-space:nowrap" class="ft13">font5</p>
<p style="position:absolute;top:144px;left:86px;white-space:nowrap" class="ft14">font6</p>
<p style="position:absolute;top:163px;left:86px;white-space:nowrap" class="ft15">font7</p>
</div>
</body>
</html>

Parsing html with python and counting characters by font (class attribute)

from lxml import html                      
tree = html.parse(r'/home/luis/tmp/fonts-html.html')
eleList = tree.xpath("//p[@class='ft10']")
len(eleList[0].text_content())
# text length: 5 
eleList = tree.xpath("//p[@class[contains(.,'ft')]]")
eleList[0].get('class')
# class name: 'ft10'
LMC
  • 10,453
  • 2
  • 27
  • 52
  • 1
    Thanks a lot, it looks great. So far, the only mismatch, between `pdffonts` and `pdftohtml`, I've found is `[none]` named fonts listed by the former. I don't know if there are any char using a `[none]` (Type 3) font, as `pdftohtml` only lists "valid fonts" (?). It seems that `pdfminer.six` could name and count those chars. For some of my cases, it found `Myriad pro` font and `pdffonts` named it as `[none]`. Anyway, I think this solution is very helpful : ) – Kfcaio Jul 19 '21 at 11:56
  • More on unnamed type 3 font: https://stackoverflow.com/questions/40233971/gnuplot-pdfcairo-unnamed-type-3-font-in-output-on-macos – Kfcaio Jul 19 '21 at 11:59