diff --git a/.gitignore b/.gitignore index b339d7ff6..8c0402ad5 100644 --- a/.gitignore +++ b/.gitignore @@ -210,3 +210,17 @@ node_modules/ test_batch.json *.backup.*.json frontend/public/locales/*/translation.backup*.json + +# Development/build artifacts +.gradle-cache/ +scripts/pdf-collection/ +**/tmp/ +*.backup + +# Type3 development data +docs/type3/signatures/ + + +# Type3 sample PDFs (development only) +**/type3/samples/ + diff --git a/app/core/src/main/resources/settings.yml.template b/app/core/src/main/resources/settings.yml.template index c7e86a6e0..cf117e649 100644 --- a/app/core/src/main/resources/settings.yml.template +++ b/app/core/src/main/resources/settings.yml.template @@ -183,6 +183,10 @@ stirling: python-command: /opt/venv/bin/python3 # Python interpreter path python-script: /scripts/convert_cff_to_ttf.py # Path to font wrapping script fontforge-command: fontforge # Override if FontForge is installed under a different name/path + type3: + library: + enabled: true # Match common Type3 fonts against the built-in library of converted programs + index: classpath:/type3/library/index.json # Override to point at a custom index.json (supports http:, file:, classpath:) ui: appNameNavbar: '' # name displayed on the navigation bar diff --git a/app/core/src/main/resources/type3/catalogue.json b/app/core/src/main/resources/type3/catalogue.json new file mode 100644 index 000000000..4aca2f414 --- /dev/null +++ b/app/core/src/main/resources/type3/catalogue.json @@ -0,0 +1,592 @@ +[ + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "1867" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "1888" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "2029" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "2069" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "2089" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "2116" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSansMono", + "encoding": "2174" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans-Oblique", + "encoding": "2192" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "2209" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "Cmsy10", + "encoding": "2228" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "STIXSizeThreeSym-Regular", + "encoding": "2233" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSansDisplay", + "encoding": "2239" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "4403" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "4438" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "4519" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "4685" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "4733" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "4782" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "4813" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "4834" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSansMono", + "encoding": "4878" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "4906" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "4929" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "4971" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "5001" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "5030" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "5052" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "5083" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "5116" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "5143" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "5175" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "5207" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "5243" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "Cmr10", + "encoding": "5263" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "Cmex10", + "encoding": "5270" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "Cmsy10", + "encoding": "5275" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "Cmmi10", + "encoding": "5280" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "5295" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans-Oblique", + "encoding": "5313" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSansDisplay", + "encoding": "5319" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "5334" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "5370" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "5399" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "5427" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "5459" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "5486" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "5513" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "5554" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "5601" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "5647" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "5694" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "5732" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "5771" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "5803" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "5861" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "5904" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "5924" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "5951" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "6084" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "6445" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "7195" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "7409" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "7474" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "7708" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "7747" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "7885" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "9029" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "9617" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "10460" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "11445" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans-Bold", + "encoding": "11486" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "11497" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "11543" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "12280" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "12301" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "12350" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "12372" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "12395" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "12416" + }, + { + "source": "01_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "13324" + }, + { + "source": "02_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "3214" + }, + { + "source": "02_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "3251" + }, + { + "source": "02_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "7190" + }, + { + "source": "02_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "9937" + }, + { + "source": "02_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "10792" + }, + { + "source": "02_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "10852" + }, + { + "source": "02_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "14712" + }, + { + "source": "02_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "18396" + }, + { + "source": "02_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "18719" + }, + { + "source": "02_Matplotlib.pdf", + "fontName": "DejaVuSans-Bold", + "encoding": "18741" + }, + { + "source": "02_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "18778" + }, + { + "source": "02_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "18804" + }, + { + "source": "02_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "20974" + }, + { + "source": "02_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "20993" + }, + { + "source": "02_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "21093" + }, + { + "source": "02_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "21117" + }, + { + "source": "02_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "21141" + }, + { + "source": "02_Matplotlib.pdf", + "fontName": "DejaVuSans", + "encoding": "21174" + }, + { + "source": "03_handout-beginner.pdf", + "fontName": "BMQQDV+DejaVuSans", + "encoding": "17" + }, + { + "source": "03_handout-beginner.pdf", + "fontName": "EVICAO+DejaVuSans-Bold", + "encoding": "133" + }, + { + "source": "03_handout-beginner.pdf", + "fontName": "BMQQDV+DejaVuSans", + "encoding": "152" + }, + { + "source": "04_handout-intermediate.pdf", + "fontName": "BMQQDV+DejaVuSans", + "encoding": "13" + }, + { + "source": "04_handout-intermediate.pdf", + "fontName": "BMQQDV+DejaVuSans", + "encoding": "85" + }, + { + "source": "04_handout-intermediate.pdf", + "fontName": "BMQQDV+DejaVuSans", + "encoding": "104" + }, + { + "source": "04_handout-intermediate.pdf", + "fontName": "BMQQDV+DejaVuSans", + "encoding": "121" + }, + { + "source": "04_handout-intermediate.pdf", + "fontName": "BMQQDV+DejaVuSans", + "encoding": "135" + }, + { + "source": "04_handout-intermediate.pdf", + "fontName": "BMQQDV+DejaVuSans", + "encoding": "159" + }, + { + "source": "04_handout-intermediate.pdf", + "fontName": "BMQQDV+DejaVuSans", + "encoding": "179" + }, + { + "source": "04_handout-intermediate.pdf", + "fontName": "BMQQDV+DejaVuSans", + "encoding": "198" + }, + { + "source": "04_handout-intermediate.pdf", + "fontName": "NVMZUP+SourceCodePro-Regular", + "encoding": "208" + }, + { + "source": "04_handout-intermediate.pdf", + "fontName": "BMQQDV+DejaVuSans", + "encoding": "231" + }, + { + "source": "04_handout-intermediate.pdf", + "fontName": "NVMZUP+SourceCodePro-Regular", + "encoding": "241" + }, + { + "source": "07_matplotlib.pdf", + "fontName": "SauceCodePowerline-Bold", + "encoding": "22" + }, + { + "source": "07_matplotlib.pdf", + "fontName": "SauceCodePowerline-Regular", + "encoding": "47" + }, + { + "source": "07_matplotlib.pdf", + "fontName": "SauceCodePowerline-Regular", + "encoding": "65" + }, + { + "source": "07_matplotlib.pdf", + "fontName": "SauceCodePowerline-Bold", + "encoding": "110" + }, + { + "source": "08_matplotlib.pdf", + "fontName": "F36", + "encoding": "12" + }, + { + "source": "08_matplotlib.pdf", + "fontName": "F59", + "encoding": "42" + } +] \ No newline at end of file diff --git a/app/core/src/main/resources/type3/library/fonts/cm/cmmi10.ttf b/app/core/src/main/resources/type3/library/fonts/cm/cmmi10.ttf new file mode 100644 index 000000000..fd9d30ced --- /dev/null +++ b/app/core/src/main/resources/type3/library/fonts/cm/cmmi10.ttf @@ -0,0 +1,25 @@ + + + + Index of /sites/ctan.org/fonts/cm/ps-type1/bakoma + + +

Index of /sites/ctan.org/fonts/cm/ps-type1/bakoma

+
Icon  Name                               Last modified      Size  Description
[PARENTDIR] Parent Directory - +[   ] BaKoMa-AMS.Fonts 2005-06-15 21:10 9.0K +[   ] BaKoMa-CM.Fonts 2005-06-15 21:09 9.4K +[   ] LICENCE 2005-06-15 22:56 1.4K +[   ] README.news 2005-06-15 23:25 959 +[DIR] afm/ 2009-06-30 22:43 - +[   ] bkm-art.ps.gz 1995-01-23 11:12 110K +[DIR] etc/ 2009-06-30 22:43 - +[DIR] mac/ 2009-06-30 22:43 - +[DIR] mrf/ 2009-06-30 22:43 - +[DIR] otf/ 2009-06-30 22:43 - +[DIR] patched-pfb/ 2009-06-30 22:43 - +[DIR] pfb/ 2009-06-30 22:43 - +[DIR] pfm/ 2009-06-30 22:43 - +[DIR] tfm/ 2009-06-30 22:43 - +[DIR] ttf/ 2009-06-30 22:43 - +
+ diff --git a/app/core/src/main/resources/type3/library/fonts/cm/cmr10.ttf b/app/core/src/main/resources/type3/library/fonts/cm/cmr10.ttf new file mode 100644 index 000000000..8bc44966a Binary files /dev/null and b/app/core/src/main/resources/type3/library/fonts/cm/cmr10.ttf differ diff --git a/app/core/src/main/resources/type3/library/fonts/cm/cmsy10.ttf b/app/core/src/main/resources/type3/library/fonts/cm/cmsy10.ttf new file mode 100644 index 000000000..45d8421a5 Binary files /dev/null and b/app/core/src/main/resources/type3/library/fonts/cm/cmsy10.ttf differ diff --git a/app/core/src/main/resources/type3/library/fonts/dejavu/DejaVuSans-Bold.ttf b/app/core/src/main/resources/type3/library/fonts/dejavu/DejaVuSans-Bold.ttf new file mode 100644 index 000000000..426812b9b Binary files /dev/null and b/app/core/src/main/resources/type3/library/fonts/dejavu/DejaVuSans-Bold.ttf differ diff --git a/app/core/src/main/resources/type3/library/fonts/dejavu/DejaVuSans-Oblique.ttf b/app/core/src/main/resources/type3/library/fonts/dejavu/DejaVuSans-Oblique.ttf new file mode 100644 index 000000000..a99a14c8d Binary files /dev/null and b/app/core/src/main/resources/type3/library/fonts/dejavu/DejaVuSans-Oblique.ttf differ diff --git a/app/core/src/main/resources/type3/library/fonts/dejavu/DejaVuSans.ttf b/app/core/src/main/resources/type3/library/fonts/dejavu/DejaVuSans.ttf new file mode 100644 index 000000000..fb0bd945a Binary files /dev/null and b/app/core/src/main/resources/type3/library/fonts/dejavu/DejaVuSans.ttf differ diff --git a/app/core/src/main/resources/type3/library/fonts/dejavu/DejaVuSansMono.ttf b/app/core/src/main/resources/type3/library/fonts/dejavu/DejaVuSansMono.ttf new file mode 100644 index 000000000..538ee2723 Binary files /dev/null and b/app/core/src/main/resources/type3/library/fonts/dejavu/DejaVuSansMono.ttf differ diff --git a/app/core/src/main/resources/type3/library/fonts/scp/SauceCodeProNerdFont-Regular.ttf b/app/core/src/main/resources/type3/library/fonts/scp/SauceCodeProNerdFont-Regular.ttf new file mode 100644 index 000000000..54ceb7ce2 --- /dev/null +++ b/app/core/src/main/resources/type3/library/fonts/scp/SauceCodeProNerdFont-Regular.ttf @@ -0,0 +1,1882 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ryanoasis (Ryan L McIntyre) · GitHub + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ Skip to content + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+ + + + + +
+ + + + + + + + + +
+
+ + + +
+
+
+ +
+
+ +
+
+ +
+
+ +
+ + +
+
+
+ View ryanoasis's full-sized avatar + +
+
+ +
+
+
+
💻
+
+
+
🏗️ 🔣 🌐 🐚
+ +
+
+
+ +
+
+ +
+ + +
+ +
+ +
+
+
+
💻
+
+
+
🏗️ 🔣 🌐 🐚
+ +
+
+
+ +
+ + +
+
+
+
+ + + + + + +
+ +
+ + +
+ + +
+ + + + + + +
+ +
+ +
+
+

Sponsors

+ +
+
+ @gshpychka +
+ +
+ @InfoSec812 +
+ + +
+
+ +
+ + + +
+

Organizations

+ + + @EpicGames + + @VundleVim + + @NerdFonts + + @Powerlevel9k +
+ + + + + +
+
+
+

+ Block or report ryanoasis +

+ +
+
+ +
+
+ +
+ +
+
+ + + + Block user +

+ Prevent this user from interacting with your repositories and sending you notifications. + Learn more about blocking users. +

+ + + + + +

+ You must be logged in to block users. +

+ +
+
+ +
+ +
+ + Maximum 250 characters. Please don't include any personal information such as legal names or email addresses. Markdown supported. This note will be visible to only you. + +
+ + +
+ + +
+
+ Report abuse +

+ Contact GitHub support about this user’s behavior. + Learn more about reporting abuse. +

+ Report abuse +
+
+
+ +
+ +
+ +
+
+
+ + +
+ + + + + + + +
+
+

+ Popular repositories + + Loading + + +

+ +
    + +
  1. +
    +
    +
    + + nerd-fonts + nerd-fonts + Public + +
    + + +

    + Iconic font aggregator, collection, & patcher. 3,600+ icons, 50+ patched fonts: Hack, Source Code Pro, more. Glyph collections: Font Awesome, Material Design Icons, Octicons, & more +

    + +

    + + + CSS + + + + + + + 60.4k + + + + + + 3.8k + +

    +
    +
    +
  2. + +
  3. +
    +
    +
    + + vim-devicons + vim-devicons + Public + +
    + + +

    + Adds file type icons to Vim plugins such as: NERDTree, vim-airline, CtrlP, unite, Denite, lightline, vim-startify and many more +

    + +

    + + + Vim Script + + + + + + + 5.8k + + + + + + 271 + +

    +
    +
    +
  4. + +
  5. +
    +
    +
    + + powerline-extra-symbols + powerline-extra-symbols + Public + +
    + + +

    + ▶️ Extra glyphs for your powerline separators +

    + +

    + + + PostScript + + + + + + + 1.4k + + + + + + 72 + +

    +
    +
    +
  6. + +
  7. +
    +
    +
    + + public-bash-scripts + public-bash-scripts + Public + +
    + + +

    + Bash Scripts that I can share publicly +

    + +

    + + + Shell + + + + + + + 191 + + + + + + 77 + +

    +
    +
    +
  8. + +
  9. +
    +
    +
    + + dev-interview-study-guide + dev-interview-study-guide + Public + +
    + + +

    + +

    + +

    + + + + + 157 + + + + + + 55 + +

    +
    +
    +
  10. + +
  11. +
    +
    +
    + + devicons-shell + devicons-shell + Public + +
    + + +

    + 🔣 adds font icons (glyphs ★♨☢) to filetypes via bash (faux ls with icons) +

    + +

    + + + Shell + + + + + + + 99 + + + + + + 10 + +

    +
    +
    +
  12. +
+ +
+ +
+ +
+ + +
+ + + + + +
+ + + +
+ + + +
+
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + diff --git a/app/core/src/main/resources/type3/library/fonts/stix/STIXSizeThreeSym-Regular.otf b/app/core/src/main/resources/type3/library/fonts/stix/STIXSizeThreeSym-Regular.otf new file mode 100644 index 000000000..1eda1d949 --- /dev/null +++ b/app/core/src/main/resources/type3/library/fonts/stix/STIXSizeThreeSym-Regular.otf @@ -0,0 +1,2055 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + GitHub - stipub/stixfonts: OpenType Unicode fonts for Scientific, Technical, and Mathematical texts + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ Skip to content + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+ + + + + +
+ + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+ +
+ +
+ +
+ + + + / + + stixfonts + + + Public +
+ + +
+ +
+ + +
+
+ +
+
+

+ OpenType Unicode fonts for Scientific, Technical, and Mathematical texts +

+ + +

License

+ + + + +
+ +
+ Notifications + You must be signed in to change notification settings + +
+ + + + +
+
+ +
+ + + + +
+ + + + + + +
+ + + + + + +

stipub/stixfonts

+
+
+ +
+
+ + + + + +

Repository files navigation

stixfonts

+

OpenType Unicode fonts for Scientific, Technical, and Mathematical texts

+

Overview

+ +

Type 1 fonts (STIX 2.0.0 only)

+

The STIX Two fonts are OpenType fonts and are meant to be used in that +format. For the benefit of LaTeX users who are unable to use XeTeX or +luaTeX, we have also provided version 2.0.0 of the STIX fonts as a +set of TFM files and Type 1 fonts.

+

Note that no further updates are planned to the Type 1 +distribution; future development efforts will focus on improving the +OpenType fonts.

+

About the STIX fonts.

+

The Scientific and Technical Information eXchange (STIX) fonts are +intended to satisfy the demanding needs of authors, publishers, +printers, and others working in the scientific, medical, and technical +fields. They combine a comprehensive Unicode-based collection of +mathematical symbols and alphabets with a set of text faces suitable +for professional publishing. The fonts are available royalty-free +under the SIL Open Font License.

+

Version 2 of the STIX fonts, now known as "STIX Two", is a thorough +revision undertaken by the renowned type house Tiro Typeworks +Ltd. (https://www.tiro.com). The STIX Two fonts consist of one Math +font, two variable text fonts (STIXTwoTextVF-Roman and +STIXTwoTextVF-Italic), and eight static text fonts (Regular, Italic, +Medium, Medium Italic, SemiBold, SemiBold Italic, Bold, and Bold +Italic) derived from the variable fonts. Together, they provide a +uniform set of fonts that can be used throughout the production +process, whether that be a traditional print-only process, an entirely +electronic one, or a combination of the two.

+

The STIX project began through the joint +efforts of +American Mathematical Society (AMS), +American Institute of Physics (AIP), +American Physical Society (APS), +American Chemical Society (ACS), +The Institute of Electrical and Electronic Engineers (IEEE), +and Elsevier. +These companies are collectively known as the STI Pub companies.

+

A Fresh Take on Times Roman

+

The original version of STIX was based on Times Roman, which has now +been updated for the digital age.

+

As is well known, Times Roman was originally intended for printing the +London Times. What is not generally appreciated is that the +production quality of the Times was atypically high: It was printed +on unusually high-quality paper on presses that operated more slowly +than most newspaper presses. This allowed for the design of a +typeface that could exploit this level of care: serifs could be much +finer and counters (enclosed areas such as that in the lowercase e) +could be much smaller than in other newspaper typefaces. These +features of the font have not always fared well in less exacting +environments. At the same time, a notable quirk of the Times Roman +family is that the bold font is, in many respects, strikingly +dissimilar to the roman font.

+

Tiro Typeworks explain their approach to updating the Times Roman +basis of STIX as follows:

+
+

“Our principal goal in approaching STIX Two was to address several +inherent deficiencies in the Times New Roman model as well as expand +the typographic features. This process necessarily involved +diverging somewhat from Times as familiar to people who have only +known the common digital versions, while simultaneously restoring to +that typeface aspects of the size-appropriate design characteristics +that made it so successful in newspaper, book, and journal +publishing in it’s metal type incarnation. The essential +‘Times-ness’ remains, but are with greater harmonisation of style +across the family.

+

“Most digital versions of Times have been based on an optical size +model that appears too light and fine when scaled down to typical +text sizes. In the design of STIX Two, we went back to specimens of +size-specific designs from the metal era, and adapted proportions, +weights, and spacing of the 10pt and 12pt designs. The oft-noted +mismatch between the style of different weights of Times has been +resolved with a new bold design that matches the construction of the +regular weight.”

+
+

Font implementation decisions

+
    +
  • +

    The STIX fonts do not contain fixed-width or sans serif text faces.

    +
  • +
  • +

    The sans serif, fraktur, script, etc., alphabets in Plane 1 +(U+1D400-U+1D4FF) are intended to be used only as technical symbols.

    +
  • +
  • +

    These fonts are designed to support left-to-right typesetting in +Latin-based scripts, with additional support for Greek and Cyrillic +text. Extensions to support other writing directions have been +considered, but are currently deemed to be outside the scope of the +STIX project.

    +
  • +
+

Note to TeX users

+

These fonts have been tested with both +XeTeX +and +luaTeX +with good results. For best results, XeTeX users will want to use +version 0.999992 or later of XeTeX, which ships with +TeXLive 2020. +This version fixes a number of bugs that were present in earlier +versions. Our thanks go out to Jonathan Kew and Khaled Hosny for +their generous help in identifying and fixing these bugs. LaTeX users +should also make sure they have the latest version of the +amsmath package.

+

Summary of OpenType Features and Scripts

+

Further details these features can be found in the font charts.

+

The text fonts implement the following OpenType script tags:

+
Regular   Bold      Italic    BoldItalic
+
+DFLT      DFLT      DFLT      DFLT          Default
+
+cyrl      cyrl      cyrl      cyrl          Cyrillic
+                    cyrl.MKD  cyrl.MKD      Cyrillic/Macedonian
+                    cyrl.SRB  cyrl.SRB      Cyrillic/Serbian
+
+grek      grek      grek      grek          Greek
+
+latn      latn      latn      latn          Latin
+latn.LTH  latn.LTH  latn.LTH  latn.LTH      Latin/Lithuanian
+latn.ROM  latn.ROM  latn.ROM  latn.ROM      Latin/Romanian
+latn.TRK  latn.TRK  latn.TRK  latn.TRK      Latin/Turkish
+
+

and the following features

+
c2sc    Small Capitals from Capitals
+case    Case-Sensitive Forms
+ccmp    Glyph Composition/Decomposition
+dnom    Denominators
+frac    Fractions
+kern    Kerning
+liga    Standard Ligatures -- latn only
+locl    Localized Forms    -- latn.ROM and Italic/BoldItalic cyrl.MKD only
+numr    Numerators
+onum    Oldstyle Figures
+pnum    Proportional Figures
+smcp    Small Capitals
+subs    Subscript
+sups    Superscript
+
+

All four text fonts also support the following Character Variants:

+
cv01    U+019B Lambda with horizontal, not slanted stroke -- latn only
+cv02    U+0264 Rams horn with serifs -- latn only
+cv03    U+2423 OPEN BOX curved instead of straight
+
+

In addition, the Italic and BoldItalic faces support the following +Stylistic Variants:

+
ss01    Replace two-story g by hooked g      -- Italic/BoldItalic only
+ss02    Upright parens, brackets, and braces -- Italic/BoldItalic only
+
+

STIX Two Math implements the following font features:

+
ccmp    Glyph Composition/Decomposition
+dtls    Dotless forms of i and j
+flac    Flattened accents
+ssty    Math Script style alternates
+
+

and the following Character Variants (note the different meaning of +cv03 compared to the text fonts):

+
cv01    U+019B Lambda with horizontal, not slanted stroke -- latn only
+cv02    U+0264 Rams horn with serifs -- latn only
+cv03    Replace U+2205 EMPTY SET by an oblate form
+cv04    Replace U+2216 SET MINUS by a smaller form
+
+

and the following Stylistic Sets (again, note that ss01 and ss02 have +different meanings compared to the text fonts):

+
ss01    Stylistic Set 1 -- Math chancery to roundhand (\mathcal -> \mathscr)
+ss02    Stylistic Set 2 -- Alternate italic forms: g, u, v, w, z
+ss03    Stylistic Set 3 -- Horizontal crossbar variants
+ss04    Stylistic Set 4 -- Minute, second and primes to long variants
+ss05    Stylistic Set 5 -- Short arrow variants
+ss06    Stylistic Set 6 -- Short/narrow variants
+ss07    Stylistic Set 7 -- Alternate math symbols (product, summation, etc)
+ss08    Stylistic Set 8 -- Upright integral variants; XITS compatible
+ss09    Stylistic Set 9 -- Vertical slash variants; XITS compatible
+ss10    Stylistic Set 10 -- Diagonal greater/lesser combination variants
+ss11    Stylistic Set 11 -- Long slash not-equal combination variants
+ss12    Stylistic Set 12 -- Low contrast (sans-like) variants
+ss13    Stylistic Set 13 -- Horizontally flipped sine wave glyph
+ss14    Stylistic Set 14 -- Tall variants
+ss15    Stylistic Set 15 -- Slab serif symbol variants
+ss16    Stylistic Set 16 -- Circled operator variants
+ss20    Stylistic Set 20 -- Miscellaneous variants
+
+

Build instructions

+

After cloning the project, the fonts can be built using the build.sh script (use --verbose option for more detailed build log):

+
$ ./build.sh
+
+

This may take several minutes to complete. The first time the script is called, it will create a Python virtual environment that will be also used for subsequent builds. Each time the script is called, the fonts will be rebuilt from scratch. The built fonts will be in build subdirectory, and should be manually copied and committed to fonts subdirectory.

+

Notes on source formats and build process

+

The design masters for the STIX Two Text fonts are the .vfj files, a json source format used by FontLab 7. These files contain the glyph outlines, spacing, mark anchors, kerning and associated classes, font info, and variable design space info. Changes or additions to any of these things should be made in the .vfj files.

+

The build script used to generate font files uses the .ufo and .designspace files, not the .vfj sources directly. These files can be exported from FontLab 7 using the default export profile for ‘DesignSpace + UFO’.

+

The .ren files are glyph name management files used by the build script to manage the relationship of development names in the sources to the build names used in the post or CFF tables of the fonts.

+

Because of issues with editing and managing OpenType Layout GPOS in variable font sources, the OTL projects for the STIX Two Text fonts are built in Microsoft’s Visual OpenType Layout Tool (VOLT). This means changes to OTL, including updates to mark anchors and kerning implemented in the .vfj sources need to be passed through VOLT, updated in the .vtp VOLT project files, and compiled in .input.ttf which are then used by the build script as a source for the OTL tables in the fonts.

+

Obviously, any changes or extension to the glyph set in the .vfj design sources needs to be reflected in each of the other sources used in the build process: in the .ufo files, the .ren file glyph name lists, and especially in the .input.ttf files and .vtp project files. Fresh .input.ttf files can be exported from FontLab 7, opened in VOLT, and the .vtp project files imported and updated.

+

Note that if changes or updates are made to mark anchors or kerning or associated classes in the .vfj sources, these need to be converted to VOLT format and imported into the projects, replacing or updating existing VOLT lookups and groups. This can be done using the vfj-to-volt.py tool.

+

The revised .vtp files should then be exported for future use, and the .input.ttf fonts shipped from VOLT (this is important, because although the fonts will work if just compiled and saved in VOLT, they will contain private VOLT source tables and unregistered OTL features that will be then end up in the fonts generated by the build script; so use the ‘Ship Font’ option in VOLT and overwrite the .input.ttf file (save a copy with the VOLT project, if you like, but so long as you remembered to export the updated .vtp you can always reimport as needed)).

+

IMPORTANT : the STIXTwoMath-Regular.input.ttf file is also the source for the MATH table and cmap table in the final font build. Care must be taken to preserve or extend these as necessary in this file when updating OpenType Layout or other aspects of the font.

+

Once all the source files are ready, run the build.sh as described above. The build script describes what it is doing as it runs, and verbose mode can be used to get more detail. In overview, this is what it does:

+
    +
  1. Pre-process the UFO files to: +a) remove all features and kerning groups from the UFOs; b) rename the glyphs to match the TTFs (otherwise the binary tables can’t be grafted in with FontTools easily); c) extract the binary tables and add them under data/com.github.fonttools.ttx/ in the UFO font where ufo2ft expects them; d) save the modified files in build/masters to keep the sources unchanged.
  2. +
  3. Build variable font with fontmake from build/masters UFOs.
  4. +
  5. Build binary masters with fontmake (needed for the next step) from UFOs.
  6. +
  7. Build static fonts with fontmake from UFOs, but telling it to interpolate OTL tables from the binary masters.
  8. +
  9. Post-process the fonts to fix the name tables and other final touchups.
  10. +
+
+
+ + + +
+
+ +
+
+
+
+

About

+ +

+ OpenType Unicode fonts for Scientific, Technical, and Mathematical texts +

+ + +

Resources

+ + + +

License

+ + + + + + + + + + + + + + + + +

Stars

+ + +

Watchers

+ + +

Forks

+ + + + +
+ +
+
+ + + + + + +
+
+ +

+ Packages +

+ + +
+ No packages published
+
+ + + +
+
+ + + + + +
+
+

+ Contributors + 7

+ + + + +
    +
  • +
    +
  • +
  • +
    +
  • +
  • +
    +
  • +
  • +
    +
  • +
  • +
    +
  • +
  • +
    +
  • +
  • +
    +
  • +
+ + +
+ + +
+
+ + + +
+
+

Languages

+
+ + + + +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + diff --git a/app/core/src/main/resources/type3/library/index.json b/app/core/src/main/resources/type3/library/index.json new file mode 100644 index 000000000..d457da323 --- /dev/null +++ b/app/core/src/main/resources/type3/library/index.json @@ -0,0 +1,462 @@ +[ + { + "id": "dejavu-sans-regular", + "label": "DejaVu Sans", + "aliases": [ + "DejaVuSans", + "BMQQDV+DejaVuSans", + "DejaVuSansDisplay", + "dejavusans", + "dejavusansdisplay" + ], + "program": { + "resource": "type3/library/fonts/dejavu/DejaVuSans.ttf", + "format": "ttf" + }, + "webProgram": { + "resource": "type3/library/fonts/dejavu/DejaVuSans.ttf", + "format": "ttf" + }, + "pdfProgram": { + "resource": "type3/library/fonts/dejavu/DejaVuSans.ttf", + "format": "ttf" + }, + "source": "DejaVu Fonts 2.37", + "signatures": [ + "sha256:2be58b6ef1e29a83b8634d70b9e32c37a15dea2e608894439ef7224c35b77f5d", + "sha256:994c963d70041eee141fd275fa22c525a71283de2b4a952814d02e0bbfa8caea", + "sha256:93573cb1ab32b9cb09378298fb120de079f6a309908d2ee86f91392a6aba5c31", + "sha256:4febfad91e0141f9658506a0bf8fc2a449f0ea7d97b44e95fc9a970c77af4b0a", + "sha256:0386e5811612ba4b998d57cd3869d7fbc48092a79d436deda774af107a4af813", + "sha256:b95fa2a272cbc950b81320790d04fcf19ebb24050fa2139ba6a474172cac596b", + "sha256:d034d16ac69e3e1c5008e77c4c24dc3179308a2742601e89d5c8ab327e4040dd", + "sha256:ae77c4eb2c49f72c616272f3d7ac624ddb0b4db1c77acbe6b9d13531f68e1d5d", + "sha256:85e16e36ed0290c149647be7e468a7c46e7b66fd290131213040f7bad905aa44", + "sha256:3654d4d9bcbbf6ad51628082203094069a17aad3a5e6f5c7972833566e42ab6b", + "sha256:d0c6cddc416d130701395246621a0f669fc292df4097a7a74395602faf4475df", + "sha256:cadf43a2df81340368af44c76b499223931d78dcc76c70cf4b4a93d133e368af", + "sha256:f1a874c4268b1bffffc99acabbe0a60aa662611b4bac0e688e4fc0ae3f2033bb", + "sha256:e3d87c113463c8642a4f22943064fd75c133ad31fe5efebf6de6abf211b74b5a", + "sha256:d47afb7581e98f588f0e70953e8692249aaa2ec3df36fbd90985f27b1ce1cf50", + "sha256:e47b8f112a875361a43bcb6d9c6467e0296412d29e417e58a0e60c90b664d281", + "sha256:9c67df2ac5c3dcf957dfb0cd048fa450322a72b5a2dfb05f816c536b3b090607", + "sha256:3ee773a0af6fdedb9853dca9f4d8b80a421a0024bdf06bea41f15d58e3b90c87", + "sha256:4fa06c90399d80b41cb718163a5d78af2b203df6b6579246fb0b24d349b7a591", + "sha256:ac6756c76d6e43b771cc1e643dfc7891dfaaac05aa5e302190d0a662838ab031", + "sha256:bf7b95498f7d00d228c5c155db62b6c1aa7e0215cca1690c9fdb0adcfd496b10", + "sha256:39b8e5ec8e20a788cd45166baf0ab796397f152c9cd8dec1f882c635380cad92", + "sha256:27b98489865df8df55f19e4505c093501f236465885ca3bf5b66b6f047a85bb2", + "sha256:497ddd27e1f56ef6504c61613e3a159bab13314a4970a3be13b3a556648964da", + "sha256:3b41f9e5f3a7ffa6f4cdffa2a46f02781ec1b2b0c99994707cfb139aa15a11e2", + "sha256:93723fe436a1aa654db56caf133f56280444b9dc0682af50b83787c3e49ee3ec", + "sha256:a648cb0524465bcb3bf4a2f65e0761cfc5167b1871a7db9488bee11b56062727", + "sha256:2f18ed7f982aeb954aaae388ba0c75e3c676717ca324156b42bb17f3f20ef403", + "sha256:18ce863feb57f42f2b92ac85a8c55ef3eeaa15488c5d6cd8c724b085994c64fa", + "sha256:a3eb7054e426aad7d1fac1f39ad6d3f886e34c04f780def5cf22b53cb3a45b46", + "sha256:edd22119635bfb0f2bff750137c6c6400a7fae4ff80cc252d2e6f2ca88f599a7", + "sha256:aae1797f3e3ff55d71b02590333aff86663d6bb4a5768bed7550e5987f40afe8", + "sha256:0165552fad28860f2ea6079be7a87ea0833acde99309b3ef619c8f81707c46a3", + "sha256:792a1c5aaa1743ab203a363a8f6cd07c3b043e33c72e97c4ea21f5862158e6c1", + "sha256:f4bfd64f36bf33dea79800561a67f78d5ccdb436363574abf0892f58b376a2e6", + "sha256:119da04d962622c8aa46d77f6bdfccb5d4a4ef7173775275b046efd59098e5d9", + "sha256:003af1c45e3a5ab09544e226eba25e3a70abfe6e36dd48584474cc7a497685f6", + "sha256:88b3471db1978cc83233f249453806a8369c766b089b424c86c2584196ed5dbf", + "sha256:a15cc90b7fc110cef4f07fe8a692d572e1289a9ee29c95732294662fded4e042", + "sha256:fb54c23aa081562ac114676ffe43032c9c0fb63af3e5b7b3441b88872d1f2e7a", + "sha256:4b553d51d58f5891af071359fb016caf1c6137778da129a6b208dcc8cb0c4635", + "sha256:b318f65b9dc209eb6f004e3a6c20a772ebbca3d752adc10c66a6a8a479da2838", + "sha256:64f725573c1f5d90196e94ed338a7af06baf274420414befeb9693c80acd0f77", + "sha256:9a701e082ba5a779e2b20b8de0c7844b3f7838ba8cd4bd7ef366893761fb994d", + "sha256:2f6f8d63ff6235f3b7cd6f5eba8076854892037afa2ea6962953b3e7cda3736e", + "sha256:f17b5eb0ee996d1388c548f79fa50fa2d8c6076959eff189bb745d156d54547f", + "sha256:f22c75548364bb25fc3efbe11f05c56e29f07c15c3046ddbc85a64e5cc5a97bd", + "sha256:54a6c2e4bc290b48e21eece7f81cb6633c4b53a91f198fdaabfc73743b0e4499", + "sha256:059af9dbaaab27c1d660ef00de6d4fd6e1687cfe2abca0a4c07265c2b2b450c6", + "sha256:6651550d7b913850087244b7a70961989c2efc6d8c8d060d8663ff087b7723f6", + "sha256:4d4ee6f04f57a40a589741df4747990ed485c192b0fc179a415aba822f352a8d", + "sha256:e808a8ecba94bf0190ab7218bb0702698125ee2e456e82e00da709e8188e2bf8", + "sha256:b5064b202eb1dae41545eddf674ee23bd82176e76aac8eb749540c2689f2e3ec", + "sha256:f8f14410ec170248916e19f9d09120cfd786c47906b7c3735781d24e944b094e", + "sha256:c43134bebeaf8328ac299ba978d7e663e2dc4fe99463b9d7f72f72f77936204e", + "sha256:4f763d5e2cd0bdcd4650936ac505bd0e011899712ffe80ffa4b4d43f42941327", + "sha256:cb72de0c6105b9802d360c47a292a1f7bc344939a6801b879ea09dae4e45e863", + "sha256:2add5b5ad6e536f3614b75e246b49a006edbbecdd309d24bd42c874a3ae3c8ed", + "sha256:31d0e67bc63a816302c9ff6ad9c19e17603aef1a4c3677b81b1d9084caa86e03", + "sha256:4b509d2ae2cfab89783a73df2c66f0fd50949f97696079cb58f1e58b81daaa07", + "sha256:831f7012db360331ffb5a5de6a6d6e03ffaad29f48d81cabe9fc613b25aad818", + "sha256:bf790625423c5ebdf94760eb796c847af885b930d3a30861509b07f1c77c3f60", + "sha256:f7c3be2199c397a4c702dd434ac63fc9e046d749eff8cede4513fbc2774751b4", + "sha256:8f7bf7a6382e8a762c5a84f19f84f0675f61eb1b34bd42562c0b3ac6712e29ef", + "sha256:dfaf8075e13be0e51f72485f9d825cea9ad077eb2dd9d63b9922add67d7d2761", + "sha256:853422e67ac88fe7ae28d5c459dc9f5a84f24e7840eeb2d82a00719032119326", + "sha256:b42182c55ec4bd53ab0698bee5f92945921dbccb534fdb5c6b41f1782e1fe88e", + "sha256:75466035ac34f2523215e599452e32d796d7d02bc7122ed3d02fe91ebe064c25" + ], + "glyphCoverage": [ + 32, + 33, + 37, + 39, + 40, + 41, + 43, + 44, + 45, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 61, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 76, + 77, + 78, + 79, + 80, + 82, + 83, + 84, + 85, + 87, + 88, + 89, + 91, + 93, + 95, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 122, + 215 + ] + }, + { + "id": "dejavu-sans-bold", + "label": "DejaVu Sans Bold", + "aliases": [ + "DejaVuSans-Bold", + "EVICAO+DejaVuSans-Bold", + "dejavusans-bold" + ], + "program": { + "resource": "type3/library/fonts/dejavu/DejaVuSans-Bold.ttf", + "format": "ttf" + }, + "webProgram": { + "resource": "type3/library/fonts/dejavu/DejaVuSans-Bold.ttf", + "format": "ttf" + }, + "pdfProgram": { + "resource": "type3/library/fonts/dejavu/DejaVuSans-Bold.ttf", + "format": "ttf" + }, + "source": "DejaVu Fonts 2.37", + "signatures": [ + "sha256:dc03917f2edd92a7a68a46ad36f65a908e4feb85e61cb37e9026205f3986574a", + "sha256:c845063bef18f173afbfcb90fbf6773f43648c5f0666ecfa0132afe4e164068d" + ], + "glyphCoverage": [ + 32, + 65, + 83, + 87, + 97, + 100, + 101, + 103, + 105, + 110, + 116, + 118, + 119 + ] + }, + { + "id": "dejavu-sans-oblique", + "label": "DejaVu Sans Oblique", + "aliases": [ + "DejaVuSans-Oblique", + "dejavusans-oblique" + ], + "program": { + "resource": "type3/library/fonts/dejavu/DejaVuSans-Oblique.ttf", + "format": "ttf" + }, + "webProgram": { + "resource": "type3/library/fonts/dejavu/DejaVuSans-Oblique.ttf", + "format": "ttf" + }, + "pdfProgram": { + "resource": "type3/library/fonts/dejavu/DejaVuSans-Oblique.ttf", + "format": "ttf" + }, + "source": "DejaVu Fonts 2.37", + "signatures": [ + "sha256:81cd2d4d9353ee02c7ed80c2892658072b2a8bbd9ed1832b474129dfbe35d5d8", + "sha256:08864aa8e8d17cead6059d5b4f1b1eea2053fa0ea3ca64e885d6eaacb78bccaf" + ], + "glyphCoverage": [ + 70, + 71, + 85, + 87, + 100, + 101, + 103, + 109, + 112, + 114, + 116, + 118, + 120 + ] + }, + { + "id": "dejavu-sans-mono", + "label": "DejaVu Sans Mono", + "aliases": [ + "DejaVuSansMono", + "dejavusansmono" + ], + "program": { + "resource": "type3/library/fonts/dejavu/DejaVuSansMono.ttf", + "format": "ttf" + }, + "webProgram": { + "resource": "type3/library/fonts/dejavu/DejaVuSansMono.ttf", + "format": "ttf" + }, + "pdfProgram": { + "resource": "type3/library/fonts/dejavu/DejaVuSansMono.ttf", + "format": "ttf" + }, + "source": "DejaVu Fonts 2.37", + "signatures": [ + "sha256:88758adf0b41a81204ed3ad63463f5d15c7c2f80e8942cee501d06fa7274dc4e", + "sha256:74e60bcb2d7975b0c7b372aca9fc25f55c9018005425a741830e7c4370b8d593" + ], + "glyphCoverage": [ + 35, + 39, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 67, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 105, + 107, + 108, + 109, + 111, + 112, + 114, + 116, + 121 + ] + }, + { + "id": "cmr10", + "label": "Computer Modern Roman 10pt", + "aliases": [ + "cmr10", + "Cmr10" + ], + "signatures": [ + "sha256:5b535a05c982fb8ff029dfbedd5e9d28c1c4379ebac259d207f65606a94e5b15" + ], + "program": { + "resource": "type3/library/fonts/cm/cmr10.ttf", + "format": "ttf" + }, + "webProgram": { + "resource": "type3/library/fonts/cm/cmr10.ttf", + "format": "ttf" + }, + "pdfProgram": { + "resource": "type3/library/fonts/cm/cmr10.ttf", + "format": "ttf" + }, + "glyphCoverage": [ + 48, + 49, + 53 + ], + "source": "type3/samples/01_Matplotlib.pdf" + }, + { + "id": "cmmi10", + "label": "Computer Modern Math Italic 10pt", + "aliases": [ + "cmmi10", + "Cmmi10" + ], + "signatures": [ + "sha256:6c72170517812e39f970746f53a2ae08dafbbe7374c20bcb4d5a60adc49cb77b" + ], + "program": { + "resource": "type3/library/fonts/cm/cmmi10.ttf", + "format": "ttf" + }, + "webProgram": { + "resource": "type3/library/fonts/cm/cmmi10.ttf", + "format": "ttf" + }, + "pdfProgram": { + "resource": "type3/library/fonts/cm/cmmi10.ttf", + "format": "ttf" + }, + "glyphCoverage": [ + 100, + 120 + ], + "source": "type3/samples/01_Matplotlib.pdf" + }, + { + "id": "cmsy10", + "label": "Computer Modern Symbol 10pt", + "aliases": [ + "cmsy10", + "Cmsy10" + ], + "signatures": [ + "sha256:1324cd8127143ef9023616b7911c570db3b1eb35758cdc9258ec16c0f4587775", + "sha256:2832e219b2db3bacf0d5a147d4b74ad5226fdf7562c395ef3fb12937633e037d" + ], + "program": { + "resource": "type3/library/fonts/cm/cmsy10.ttf", + "format": "ttf" + }, + "webProgram": { + "resource": "type3/library/fonts/cm/cmsy10.ttf", + "format": "ttf" + }, + "pdfProgram": { + "resource": "type3/library/fonts/cm/cmsy10.ttf", + "format": "ttf" + }, + "glyphCoverage": [ + 48, + 8734 + ], + "source": "type3/samples/01_Matplotlib.pdf" + }, + { + "id": "stix-size-three", + "label": "STIX Size Three Symbols", + "aliases": [ + "stixsizethreesym-regular", + "STIXSizeThreeSym-Regular" + ], + "signatures": [ + "sha256:33d0ab9d9d72c1aed1edfc9b815dd6a2d618cbbe9084309c7f2de0f3df3073d7" + ], + "program": { + "resource": "type3/library/fonts/stix/STIXSizeThreeSym-Regular.otf", + "format": "otf" + }, + "webProgram": { + "resource": "type3/library/fonts/stix/STIXSizeThreeSym-Regular.otf", + "format": "otf" + }, + "pdfProgram": { + "resource": "type3/library/fonts/stix/STIXSizeThreeSym-Regular.otf", + "format": "otf" + }, + "glyphCoverage": [ + 91, + 93 + ], + "source": "type3/samples/01_Matplotlib.pdf" + }, + { + "id": "sourcecodepro-regular", + "label": "Source Code Pro", + "aliases": [ + "SourceCodePro-Regular", + "sourcecodepro-regular", + "NVMZUP+SourceCodePro-Regular" + ], + "signatures": [ + "sha256:96ba693001b2ab224ad5b5a7464cecd4d33e68f30fb23f78a8473dbb031ce246", + "sha256:72fca14e9e44fc41b0cdb1c6a088f0b07f882f9f04c51a0145f43cf8b285c5b6" + ], + "program": { + "resource": "type3/library/fonts/scp/SauceCodeProNerdFont-Regular.ttf", + "format": "ttf" + }, + "webProgram": { + "resource": "type3/library/fonts/scp/SauceCodeProNerdFont-Regular.ttf", + "format": "ttf" + }, + "pdfProgram": { + "resource": "type3/library/fonts/scp/SauceCodeProNerdFont-Regular.ttf", + "format": "ttf" + }, + "glyphCoverage": [ + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 67 + ], + "source": "type3/samples/04_handout-intermediate.pdf" + } +] diff --git a/app/proprietary/build.gradle b/app/proprietary/build.gradle index 8f09c7568..3c933ec4d 100644 --- a/app/proprietary/build.gradle +++ b/app/proprietary/build.gradle @@ -75,3 +75,11 @@ dependencies { } tasks.register('prepareKotlinBuildScriptModel') {} + +tasks.register('type3SignatureTool', JavaExec) { + group = 'type3' + description = 'Dump Type3 font signatures and glyph coverage for the Type3 library' + classpath = sourceSets.main.runtimeClasspath + mainClass = 'stirling.software.SPDF.service.pdfjson.type3.tool.Type3SignatureTool' + standardInput = System.in +} diff --git a/app/proprietary/src/main/java/stirling/software/SPDF/model/json/PdfJsonFont.java b/app/proprietary/src/main/java/stirling/software/SPDF/model/json/PdfJsonFont.java index d8cae80b9..1fbbbd5b3 100644 --- a/app/proprietary/src/main/java/stirling/software/SPDF/model/json/PdfJsonFont.java +++ b/app/proprietary/src/main/java/stirling/software/SPDF/model/json/PdfJsonFont.java @@ -1,5 +1,7 @@ package stirling.software.SPDF.model.json; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; @@ -56,6 +58,12 @@ public class PdfJsonFont { /** Format hint for the pdfProgram payload. */ private String pdfProgramFormat; + /** Glyph metadata for Type3 fonts to enable precise text rewrites. */ + private List type3Glyphs; + + /** Per-strategy synthesized font payloads for Type3 normalization. */ + private List conversionCandidates; + /** ToUnicode stream encoded as Base64 when present. */ private String toUnicode; diff --git a/app/proprietary/src/main/java/stirling/software/SPDF/model/json/PdfJsonFontConversionCandidate.java b/app/proprietary/src/main/java/stirling/software/SPDF/model/json/PdfJsonFontConversionCandidate.java new file mode 100644 index 000000000..a3e0a328d --- /dev/null +++ b/app/proprietary/src/main/java/stirling/software/SPDF/model/json/PdfJsonFontConversionCandidate.java @@ -0,0 +1,69 @@ +package stirling.software.SPDF.model.json; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonInclude; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class PdfJsonFontConversionCandidate { + + /** Stable identifier for the strategy that produced this candidate. */ + private String strategyId; + + /** Human-readable label for diagnostics and UI toggles. */ + private String strategyLabel; + + /** Outcome of the conversion attempt. */ + private PdfJsonFontConversionStatus status; + + /** Summary diagnostics or error details. */ + private String message; + + /** Count of glyphs successfully synthesized. */ + private Integer synthesizedGlyphs; + + /** Count of glyphs that could not be reproduced accurately. */ + private Integer missingGlyphs; + + /** Approximate width delta (in glyph units) across the test sample. */ + private Double widthDelta; + + /** Approximate bounding box delta (in glyph units). */ + private Double bboxDelta; + + /** Base64-encoded font program (typically TTF/OTF) produced by the strategy. */ + private String program; + + /** Format hint for {@link #program}. */ + private String programFormat; + + /** Web-optimized payload (e.g. TTF) for browser preview. */ + private String webProgram; + + /** Format for the web payload. */ + private String webProgramFormat; + + /** PDF-friendly payload for re-embedding during export. */ + private String pdfProgram; + + /** Format for the PDF payload. */ + private String pdfProgramFormat; + + /** Optional PNG preview of rendered glyphs (Base64). */ + private String previewImage; + + /** Additional structured diagnostics (JSON string). */ + private String diagnostics; + + /** Known unicode/codepoint coverage derived from the conversion strategy. */ + private List glyphCoverage; +} diff --git a/app/proprietary/src/main/java/stirling/software/SPDF/model/json/PdfJsonFontConversionStatus.java b/app/proprietary/src/main/java/stirling/software/SPDF/model/json/PdfJsonFontConversionStatus.java new file mode 100644 index 000000000..4d8c6b8e1 --- /dev/null +++ b/app/proprietary/src/main/java/stirling/software/SPDF/model/json/PdfJsonFontConversionStatus.java @@ -0,0 +1,9 @@ +package stirling.software.SPDF.model.json; + +public enum PdfJsonFontConversionStatus { + SUCCESS, + WARNING, + FAILURE, + SKIPPED, + UNSUPPORTED +} diff --git a/app/proprietary/src/main/java/stirling/software/SPDF/model/json/PdfJsonFontType3Glyph.java b/app/proprietary/src/main/java/stirling/software/SPDF/model/json/PdfJsonFontType3Glyph.java new file mode 100644 index 000000000..510c6f0ba --- /dev/null +++ b/app/proprietary/src/main/java/stirling/software/SPDF/model/json/PdfJsonFontType3Glyph.java @@ -0,0 +1,27 @@ +package stirling.software.SPDF.model.json; + +import com.fasterxml.jackson.annotation.JsonInclude; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class PdfJsonFontType3Glyph { + /** Character code used in the content stream to reference this glyph. */ + private Integer charCode; + + /** PostScript glyph name, when available. */ + private String glyphName; + + /** Unicode code point represented by this glyph, if it can be resolved. */ + private Integer unicode; + + /** Raw char code used in the Type3 font encoding (0-255). */ + private Integer charCodeRaw; +} diff --git a/app/proprietary/src/main/java/stirling/software/SPDF/model/json/PdfJsonTextElement.java b/app/proprietary/src/main/java/stirling/software/SPDF/model/json/PdfJsonTextElement.java index ad80060f3..8760bcad8 100644 --- a/app/proprietary/src/main/java/stirling/software/SPDF/model/json/PdfJsonTextElement.java +++ b/app/proprietary/src/main/java/stirling/software/SPDF/model/json/PdfJsonTextElement.java @@ -37,4 +37,5 @@ public class PdfJsonTextElement { private PdfJsonTextColor strokeColor; private Integer renderingMode; private Boolean fallbackUsed; + private List charCodes; } diff --git a/app/proprietary/src/main/java/stirling/software/SPDF/service/PdfJsonConversionService.java b/app/proprietary/src/main/java/stirling/software/SPDF/service/PdfJsonConversionService.java index d65f8375e..515056b60 100644 --- a/app/proprietary/src/main/java/stirling/software/SPDF/service/PdfJsonConversionService.java +++ b/app/proprietary/src/main/java/stirling/software/SPDF/service/PdfJsonConversionService.java @@ -38,6 +38,7 @@ import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; +import java.util.stream.Collectors; import javax.imageio.ImageIO; @@ -66,6 +67,7 @@ import org.apache.pdfbox.pdmodel.font.PDFontDescriptor; import org.apache.pdfbox.pdmodel.font.PDFontFactory; import org.apache.pdfbox.pdmodel.font.PDType0Font; import org.apache.pdfbox.pdmodel.font.PDType1Font; +import org.apache.pdfbox.pdmodel.font.PDType3Font; import org.apache.pdfbox.pdmodel.font.Standard14Fonts; import org.apache.pdfbox.pdmodel.graphics.PDXObject; import org.apache.pdfbox.pdmodel.graphics.color.PDColor; @@ -103,6 +105,9 @@ import stirling.software.SPDF.model.json.PdfJsonDocument; import stirling.software.SPDF.model.json.PdfJsonDocumentMetadata; import stirling.software.SPDF.model.json.PdfJsonFont; import stirling.software.SPDF.model.json.PdfJsonFontCidSystemInfo; +import stirling.software.SPDF.model.json.PdfJsonFontConversionCandidate; +import stirling.software.SPDF.model.json.PdfJsonFontConversionStatus; +import stirling.software.SPDF.model.json.PdfJsonFontType3Glyph; import stirling.software.SPDF.model.json.PdfJsonFormField; import stirling.software.SPDF.model.json.PdfJsonImageElement; import stirling.software.SPDF.model.json.PdfJsonMetadata; @@ -112,6 +117,10 @@ import stirling.software.SPDF.model.json.PdfJsonStream; import stirling.software.SPDF.model.json.PdfJsonTextColor; import stirling.software.SPDF.model.json.PdfJsonTextElement; import stirling.software.SPDF.service.pdfjson.PdfJsonFontService; +import stirling.software.SPDF.service.pdfjson.type3.Type3ConversionRequest; +import stirling.software.SPDF.service.pdfjson.type3.Type3FontConversionService; +import stirling.software.SPDF.service.pdfjson.type3.Type3GlyphExtractor; +import stirling.software.SPDF.service.pdfjson.type3.model.Type3GlyphOutline; import stirling.software.common.service.CustomPDFDocumentFactory; import stirling.software.common.service.TaskManager; import stirling.software.common.util.ExceptionUtils; @@ -133,6 +142,10 @@ public class PdfJsonConversionService { private final PdfJsonCosMapper cosMapper; private final PdfJsonFallbackFontService fallbackFontService; private final PdfJsonFontService fontService; + private final Type3FontConversionService type3FontConversionService; + private final Type3GlyphExtractor type3GlyphExtractor; + private final Map type3NormalizedFontCache = new ConcurrentHashMap<>(); + private final Map> type3GlyphCoverageCache = new ConcurrentHashMap<>(); @Value("${stirling.pdf.json.font-normalization.enabled:true}") private boolean fontNormalizationEnabled; @@ -214,12 +227,12 @@ public class PdfJsonConversionService { // Get job ID from request context if running in async mode String jobId = getJobIdFromRequest(); - log.info("Starting PDF to JSON conversion, jobId from context: {}", jobId); + log.debug("Starting PDF to JSON conversion, jobId from context: {}", jobId); Consumer progress = progressCallback != null ? (p) -> { - log.info( + log.debug( "Progress: [{}%] {} - {}{}", p.getPercent(), p.getStage(), @@ -232,7 +245,7 @@ public class PdfJsonConversionService { } : jobId != null ? (p) -> { - log.info( + log.debug( "Progress: [{}%] {} - {}{}", p.getPercent(), p.getStage(), @@ -245,7 +258,7 @@ public class PdfJsonConversionService { reportProgressToTaskManager(jobId, p); } : (p) -> { - log.info( + log.debug( "Progress (no job): [{}%] {} - {}{}", p.getPercent(), p.getStage(), @@ -271,7 +284,7 @@ public class PdfJsonConversionService { normalizedFile = normalizePdfFonts(workingPath); if (normalizedFile != null && normalizedFile.exists()) { workingPath = normalizedFile.getPath(); - log.info("Using Ghostscript-normalized PDF for JSON export"); + log.debug("Using Ghostscript-normalized PDF for JSON export"); } } catch (IOException ex) { log.warn( @@ -291,7 +304,7 @@ public class PdfJsonConversionService { boolean useLazyImages = totalPages > 5 && jobId != null; Map fontCache = new IdentityHashMap<>(); Map imageCache = new IdentityHashMap<>(); - log.info( + log.debug( "Converting PDF to JSON ({} pages) - {} mode", totalPages, useLazyImages ? "lazy image" : "standard"); @@ -395,7 +408,7 @@ public class PdfJsonConversionService { new CachedPdfDocument( cachedPdfBytes, docMetadata, fonts, pageFontResources); documentCache.put(jobId, cached); - log.info( + log.debug( "Cached PDF bytes ({} bytes, {} pages, {} fonts) for lazy images, jobId: {}", cachedPdfBytes.length, totalPages, @@ -411,7 +424,7 @@ public class PdfJsonConversionService { progress.accept( PdfJsonConversionProgress.of(95, "serializing", "Generating JSON output")); - log.info( + log.debug( "PDF→JSON conversion complete (fonts: {}, pages: {}, lazyImages: {})", serializedFonts.size(), pdfJson.getPages().size(), @@ -438,13 +451,16 @@ public class PdfJsonConversionService { fontModels = new ArrayList<>(); pdfJson.setFonts(fontModels); } + type3NormalizedFontCache.clear(); try (PDDocument document = new PDDocument()) { applyMetadata(document, pdfJson.getMetadata()); applyXmpMetadata(document, pdfJson.getXmpMetadata()); Map fontMap = buildFontMap(document, fontModels); - log.info("Converting JSON to PDF ({} font resources)", fontMap.size()); + log.debug("Converting JSON to PDF ({} font resources)", fontMap.size()); + + Map fontLookup = buildFontModelLookup(fontModels); List pages = pdfJson.getPages(); if (pages == null) { @@ -457,7 +473,7 @@ public class PdfJsonConversionService { pageModel.getPageNumber() != null ? pageModel.getPageNumber() : pageIndex + 1; - log.info("Reconstructing page {}", pageNumberValue); + log.debug("Reconstructing page {}", pageNumberValue); PDRectangle pageSize = new PDRectangle( safeFloat(pageModel.getWidth(), 612f), @@ -496,7 +512,9 @@ public class PdfJsonConversionService { preflightTextElements( document, fontMap, fontModels, elements, pageNumberValue); - log.info( + fontLookup = buildFontModelLookup(fontModels); + + log.debug( "Page {} preflight complete (elements={}, fallbackApplied={})", pageNumberValue, elements.size(), @@ -521,15 +539,22 @@ public class PdfJsonConversionService { pageNumberValue); rewriteSucceeded = false; } else if (!preservedStreams.isEmpty()) { - log.info("Attempting token rewrite for page {}", pageNumberValue); + log.debug("Attempting token rewrite for page {}", pageNumberValue); rewriteSucceeded = - rewriteTextOperators(document, page, elements, false, false); + rewriteTextOperators( + document, + page, + elements, + false, + false, + fontLookup, + pageNumberValue); if (!rewriteSucceeded) { - log.info( + log.debug( "Token rewrite failed for page {}, regenerating text stream", pageNumberValue); } else { - log.info("Token rewrite succeeded for page {}", pageNumberValue); + log.debug("Token rewrite succeeded for page {}", pageNumberValue); } } else { rewriteSucceeded = false; @@ -550,7 +575,7 @@ public class PdfJsonConversionService { } if (shouldRegenerate) { - log.info("Regenerating page content for page {}", pageNumberValue); + log.debug("Regenerating page content for page {}", pageNumberValue); AppendMode appendMode = AppendMode.OVERWRITE; if (!preservedStreams.isEmpty()) { PDStream vectorStream = @@ -571,7 +596,7 @@ public class PdfJsonConversionService { fontModels, pageNumberValue, appendMode); - log.info("Page content regeneration complete for page {}", pageNumberValue); + log.debug("Page content regeneration complete for page {}", pageNumberValue); } // Restore annotations for this page @@ -657,7 +682,7 @@ public class PdfJsonConversionService { mapping.put(font, fontId); String key = buildFontKey(pageNumber, fontId); if (!fonts.containsKey(key)) { - fonts.put(key, buildFontModel(font, fontId, pageNumber, fontCache)); + fonts.put(key, buildFontModel(document, font, fontId, pageNumber, fontCache)); } } @@ -696,6 +721,45 @@ public class PdfJsonConversionService { return buildFontKey(page, fontId); } + private String resolveFontCacheKey(PdfJsonFont font) { + if (font == null) { + return null; + } + if (font.getUid() != null && !font.getUid().isBlank()) { + return font.getUid(); + } + if (font.getId() == null) { + return null; + } + return buildFontKey(font.getPageNumber(), font.getId()); + } + + private Map buildFontModelLookup(List fontModels) { + Map lookup = new HashMap<>(); + if (fontModels == null) { + return lookup; + } + for (PdfJsonFont font : fontModels) { + if (font == null || font.getId() == null) { + continue; + } + lookup.put(buildFontKey(font.getPageNumber(), font.getId()), font); + } + return lookup; + } + + private PdfJsonFont resolveFontModel( + Map lookup, int pageNumber, String fontId) { + if (lookup == null || fontId == null) { + return null; + } + PdfJsonFont model = lookup.get(buildFontKey(pageNumber, fontId)); + if (model != null) { + return model; + } + return lookup.get(buildFontKey(-1, fontId)); + } + private List cloneFontList(Collection source) { List clones = new ArrayList<>(); if (source == null) { @@ -729,6 +793,14 @@ public class PdfJsonConversionService { .webProgramFormat(font.getWebProgramFormat()) .pdfProgram(font.getPdfProgram()) .pdfProgramFormat(font.getPdfProgramFormat()) + .type3Glyphs( + font.getType3Glyphs() == null + ? null + : new ArrayList<>(font.getType3Glyphs())) + .conversionCandidates( + font.getConversionCandidates() == null + ? null + : new ArrayList<>(font.getConversionCandidates())) .toUnicode(font.getToUnicode()) .standard14Name(font.getStandard14Name()) .fontDescriptorFlags(font.getFontDescriptorFlags()) @@ -769,18 +841,23 @@ public class PdfJsonConversionService { } private PdfJsonFont buildFontModel( - PDFont font, String fontId, int pageNumber, Map fontCache) + PDDocument document, + PDFont font, + String fontId, + int pageNumber, + Map fontCache) throws IOException { COSBase cosObject = font.getCOSObject(); FontModelCacheEntry cacheEntry = fontCache.get(cosObject); if (cacheEntry == null) { - cacheEntry = createFontCacheEntry(font); + cacheEntry = createFontCacheEntry(document, font, fontId, pageNumber); fontCache.put(cosObject, cacheEntry); } return toPdfJsonFont(cacheEntry, fontId, pageNumber); } - private FontModelCacheEntry createFontCacheEntry(PDFont font) throws IOException { + private FontModelCacheEntry createFontCacheEntry( + PDDocument document, PDFont font, String fontId, int pageNumber) throws IOException { PDFontDescriptor descriptor = font.getFontDescriptor(); String subtype = font.getCOSObject().getNameAsString(COSName.SUBTYPE); String encoding = resolveEncoding(font); @@ -798,6 +875,61 @@ public class PdfJsonConversionService { Float italicAngle = descriptor != null ? descriptor.getItalicAngle() : null; Integer unitsPerEm = extractUnitsPerEm(font); PdfJsonCosValue cosDictionary = cosMapper.serializeCosValue(font.getCOSObject()); + List conversionCandidates = null; + List type3Glyphs = null; + String fontUid = buildFontKey(pageNumber, fontId); + if (font instanceof PDType3Font type3Font) { + try { + conversionCandidates = + type3FontConversionService.synthesize( + Type3ConversionRequest.builder() + .document(document) + .font(type3Font) + .fontId(fontId) + .pageNumber(pageNumber) + .fontUid(fontUid) + .build()); + if (conversionCandidates != null && conversionCandidates.isEmpty()) { + conversionCandidates = null; + } + try { + List outlines = + type3GlyphExtractor.extractGlyphs( + document, type3Font, fontId, pageNumber); + if (outlines != null && !outlines.isEmpty()) { + type3Glyphs = + outlines.stream() + .map( + outline -> + PdfJsonFontType3Glyph.builder() + .charCode(outline.getCharCode()) + .charCodeRaw( + outline.getCharCode() >= 0 + ? outline + .getCharCode() + : null) + .glyphName(outline.getGlyphName()) + .unicode(outline.getUnicode()) + .build()) + .collect(Collectors.toList()); + } + } catch (Exception ex) { + log.debug( + "[TYPE3] Failed to extract glyph metadata for {} (page {}): {}", + fontId, + pageNumber, + ex.getMessage()); + } + } catch (Exception ex) { + log.warn( + "[TYPE3] Failed to evaluate conversion strategies for {} (page {}): {}", + fontId, + pageNumber, + ex.getMessage(), + ex); + } + registerType3GlyphCoverage(fontUid, conversionCandidates, type3Glyphs); + } return new FontModelCacheEntry( font.getName(), @@ -815,7 +947,9 @@ public class PdfJsonConversionService { xHeight, italicAngle, unitsPerEm, - cosDictionary); + cosDictionary, + type3Glyphs, + conversionCandidates); } private PdfJsonFont toPdfJsonFont( @@ -836,6 +970,8 @@ public class PdfJsonConversionService { .webProgramFormat(programData != null ? programData.getWebFormat() : null) .pdfProgram(programData != null ? programData.getPdfBase64() : null) .pdfProgramFormat(programData != null ? programData.getPdfFormat() : null) + .type3Glyphs(cacheEntry.type3Glyphs()) + .conversionCandidates(cacheEntry.conversionCandidates()) .toUnicode(cacheEntry.toUnicode()) .standard14Name(cacheEntry.standard14Name()) .fontDescriptorFlags(cacheEntry.fontDescriptorFlags()) @@ -849,6 +985,177 @@ public class PdfJsonConversionService { .build(); } + private record FontByteSource(byte[] bytes, String format, String originLabel) {} + + private List collectConversionCandidateSources( + List conversionCandidates) { + if (conversionCandidates == null || conversionCandidates.isEmpty()) { + return Collections.emptyList(); + } + List prioritized = new ArrayList<>(); + for (PdfJsonFontConversionCandidate candidate : conversionCandidates) { + if (candidate == null) { + continue; + } + PdfJsonFontConversionStatus status = candidate.getStatus(); + if (status == PdfJsonFontConversionStatus.SUCCESS + || status == PdfJsonFontConversionStatus.WARNING) { + prioritized.add(candidate); + } + } + if (prioritized.isEmpty()) { + return Collections.emptyList(); + } + prioritized.sort( + Comparator.comparingInt( + c -> + conversionStatusPriority( + c.getStatus() != null + ? c.getStatus() + : PdfJsonFontConversionStatus.FAILURE))); + + List sources = new ArrayList<>(); + for (PdfJsonFontConversionCandidate candidate : prioritized) { + addCandidatePayload( + sources, + candidate.getPdfProgram(), + candidate.getPdfProgramFormat(), + candidate, + "pdfProgram"); + addCandidatePayload( + sources, + candidate.getProgram(), + candidate.getProgramFormat(), + candidate, + "program"); + addCandidatePayload( + sources, + candidate.getWebProgram(), + candidate.getWebProgramFormat(), + candidate, + "webProgram"); + } + sources.sort( + Comparator.comparingInt( + source -> fontFormatPreference(source.format(), source.originLabel()))); + return sources; + } + + private int conversionStatusPriority(PdfJsonFontConversionStatus status) { + return switch (status) { + case SUCCESS -> 0; + case WARNING -> 1; + default -> 2; + }; + } + + private void addCandidatePayload( + List sources, + String base64, + String format, + PdfJsonFontConversionCandidate candidate, + String label) { + if (base64 == null || base64.isBlank()) { + return; + } + try { + byte[] bytes = Base64.getDecoder().decode(base64); + if (bytes.length == 0) { + return; + } + String normalizedFormat = format != null ? format.toLowerCase(Locale.ROOT) : null; + String strategyId = + candidate.getStrategyId() != null ? candidate.getStrategyId() : "unknown"; + String origin = "candidate:" + strategyId + ":" + label; + sources.add(new FontByteSource(bytes, normalizedFormat, origin)); + log.debug( + "[FONT-DEBUG] Registered conversion candidate payload from {} (format={}, size={} bytes)", + origin, + normalizedFormat, + bytes.length); + } catch (IllegalArgumentException ex) { + log.warn( + "[TYPE3] Failed to decode {} payload for strategy {}: {}", + label, + candidate.getStrategyId(), + ex.getMessage()); + } + } + + private void registerType3GlyphCoverage( + String fontUid, + List conversionCandidates, + List glyphs) { + if (fontUid == null) { + return; + } + Set coverage = new LinkedHashSet<>(); + if (conversionCandidates != null) { + for (PdfJsonFontConversionCandidate candidate : conversionCandidates) { + if (candidate == null || candidate.getGlyphCoverage() == null) { + continue; + } + for (Integer value : candidate.getGlyphCoverage()) { + if (value != null) { + coverage.add(value); + } + } + } + } + if (glyphs != null) { + for (PdfJsonFontType3Glyph glyph : glyphs) { + if (glyph == null) { + continue; + } + Integer unicode = glyph.getUnicode(); + if (unicode != null) { + coverage.add(unicode); + } else { + Integer charCode = glyph.getCharCode(); + if (charCode != null && charCode >= 0) { + coverage.add(0xF000 | (charCode & 0xFF)); + } + } + } + } + if (!coverage.isEmpty()) { + type3GlyphCoverageCache.put(fontUid, Collections.unmodifiableSet(coverage)); + } + } + + private boolean isGlyphCoveredByType3Font(Set coverage, int codePoint) { + if (coverage == null || coverage.isEmpty()) { + return true; + } + if (coverage.contains(codePoint)) { + return true; + } + if (codePoint >= 0 && codePoint <= 0xFF) { + return coverage.contains(0xF000 | (codePoint & 0xFF)); + } + return false; + } + + private int fontFormatPreference(String format, String origin) { + if (format == null) { + return 5; + } + switch (format) { + case "ttf": + return 0; + case "truetype": + return 1; + case "otf": + case "cff": + case "type1c": + case "cidfonttype0c": + return 2; + default: + log.debug("[FONT-DEBUG] Unknown font format '{}' from {}", format, origin); + return 4; + } + } + private record FontModelCacheEntry( String baseName, String subtype, @@ -865,7 +1172,9 @@ public class PdfJsonConversionService { Float xHeight, Float italicAngle, Integer unitsPerEm, - PdfJsonCosValue cosDictionary) {} + PdfJsonCosValue cosDictionary, + List type3Glyphs, + List conversionCandidates) {} private PreflightResult preflightTextElements( PDDocument document, @@ -881,6 +1190,9 @@ public class PdfJsonConversionService { Set fallbackIds = new LinkedHashSet<>(); boolean fallbackNeeded = false; + Map fontLookup = buildFontModelLookup(fontModels); + Map> type3GlyphCache = new HashMap<>(); + for (PdfJsonTextElement element : elements) { String text = Objects.toString(element.getText(), ""); if (text.isEmpty()) { @@ -899,7 +1211,55 @@ public class PdfJsonConversionService { continue; } + PdfJsonFont fontModel = resolveFontModel(fontLookup, pageNumber, element.getFontId()); + if (font instanceof PDType3Font && fontModel != null) { + Set supportedGlyphs = + type3GlyphCache.computeIfAbsent( + fontModel.getUid() != null ? fontModel.getUid() : fontModel.getId(), + key -> { + List glyphs = fontModel.getType3Glyphs(); + if (glyphs == null || glyphs.isEmpty()) { + return Collections.emptySet(); + } + return glyphs.stream() + .map(PdfJsonFontType3Glyph::getUnicode) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + }); + + boolean missingGlyph = false; + for (int offset = 0; offset < text.length(); ) { + int codePoint = text.codePointAt(offset); + offset += Character.charCount(codePoint); + if (!supportedGlyphs.contains(codePoint)) { + missingGlyph = true; + break; + } + } + + if (missingGlyph) { + fallbackNeeded = true; + element.setFallbackUsed(Boolean.TRUE); + for (int offset = 0; offset < text.length(); ) { + int codePoint = text.codePointAt(offset); + offset += Character.charCount(codePoint); + if (!supportedGlyphs.contains(codePoint)) { + String fallbackId = + fallbackFontService.resolveFallbackFontId(codePoint); + fallbackIds.add(fallbackId != null ? fallbackId : FALLBACK_FONT_ID); + } + } + } + continue; + } + if (!fallbackFontService.canEncodeFully(font, text)) { + log.info( + "[FONT-DEBUG] Font {} (resource {}) cannot encode text '{}' on page {}", + fontModel != null ? fontModel.getId() : "unknown", + element.getFontId(), + text, + pageNumber); fallbackNeeded = true; element.setFallbackUsed(Boolean.TRUE); for (int offset = 0; offset < text.length(); ) { @@ -1990,6 +2350,7 @@ public class PdfJsonConversionService { throws IOException { List drawables = mergeDrawables(textElements, imageElements); Map imageCache = new HashMap<>(); + Map runFontLookup = buildFontModelLookup(fontModels); AppendMode mode = appendMode != null ? appendMode : AppendMode.OVERWRITE; try (PDPageContentStream contentStream = @@ -2023,7 +2384,13 @@ public class PdfJsonConversionService { List runs = buildFontRuns( - document, fontMap, fontModels, baseFont, text, element); + document, + fontMap, + fontModels, + pageNumber, + baseFont, + text, + element); PDFont activeFont = null; for (FontRun run : runs) { @@ -2034,7 +2401,66 @@ public class PdfJsonConversionService { contentStream.setFont(run.font(), fontScale); activeFont = run.font(); } - contentStream.showText(run.text()); + PdfJsonFont runFontModel = + resolveFontModel(runFontLookup, pageNumber, run.fontId()); + if (runFontModel == null) { + runFontLookup = buildFontModelLookup(fontModels); + runFontModel = + resolveFontModel(runFontLookup, pageNumber, run.fontId()); + } + // Check if this is a normalized Type3 font (has Type3 metadata but is not PDType3Font) + boolean isNormalizedType3 = !(run.font() instanceof PDType3Font) + && runFontModel != null + && runFontModel.getType3Glyphs() != null + && !runFontModel.getType3Glyphs().isEmpty(); + + if (isNormalizedType3) { + // For normalized Type3 fonts, use original text directly + // The font has proper Unicode mappings, so PDFBox can encode it correctly + contentStream.showText(run.text()); + } else { + // For actual Type3 fonts and other fonts, encode manually + byte[] encoded; + if (run.font() instanceof PDType3Font + && run.charCodes() != null + && !run.charCodes().isEmpty()) { + encoded = encodeType3CharCodes(run.charCodes()); + if (encoded == null || encoded.length == 0) { + log.warn( + "[FONT-DEBUG] Failed to emit raw Type3 char codes for font {} on page {}", + run.font().getName(), + pageNumber); + continue; + } + } else { + try { + encoded = + encodeTextWithFont( + run.font(), + runFontModel, + run.text(), + run.charCodes()); + } catch (IOException ex) { + log.warn( + "Failed to encode text '{}' with font {} on page {}: {}", + run.text(), + run.font().getName(), + pageNumber, + ex.getMessage()); + continue; + } + } + if (encoded == null || encoded.length == 0) { + log.warn( + "Failed to encode text '{}' with font {} on page {}", + run.text(), + run.font().getName(), + pageNumber); + continue; + } + contentStream.showText( + new String(encoded, StandardCharsets.ISO_8859_1)); + } } } case IMAGE -> { @@ -2060,6 +2486,7 @@ public class PdfJsonConversionService { PDDocument document, Map fontMap, List fontModels, + int pageNumber, PDFont primaryFont, String text, PdfJsonTextElement element) @@ -2070,10 +2497,12 @@ public class PdfJsonConversionService { } PDFont baseFont = primaryFont; + String baseFontId = element.getFontId(); boolean fallbackApplied = primaryFont == null; if (baseFont == null) { baseFont = ensureFallbackFont(document, fontMap, fontModels, FALLBACK_FONT_ID); if (baseFont != null) { + baseFontId = FALLBACK_FONT_ID; fallbackApplied = true; } } @@ -2082,68 +2511,161 @@ public class PdfJsonConversionService { return runs; } + Map runFontLookup = buildFontModelLookup(fontModels); + PdfJsonFont baseFontModel = resolveFontModel(runFontLookup, pageNumber, baseFontId); + boolean baseIsType3 = + baseFontModel != null + && baseFontModel.getSubtype() != null + && "type3".equalsIgnoreCase(baseFontModel.getSubtype()); + PDFont normalizedType3Font = + baseIsType3 && baseFontModel.getUid() != null + ? type3NormalizedFontCache.get(baseFontModel.getUid()) + : null; + Set baseType3Coverage = + baseIsType3 && baseFontModel != null + ? type3GlyphCoverageCache.getOrDefault( + baseFontModel.getUid(), Collections.emptySet()) + : Collections.emptySet(); + boolean hasNormalizedType3 = baseIsType3 && normalizedType3Font != null; + if (hasNormalizedType3 && log.isInfoEnabled()) { + log.info( + "[TYPE3-RUNTIME] Using normalized library font {} for Type3 resource {} on page {}", + normalizedType3Font.getName(), + baseFontModel != null ? baseFontModel.getId() : baseFontId, + pageNumber); + } + StringBuilder buffer = new StringBuilder(); + List codeBuffer = new ArrayList<>(); PDFont currentFont = baseFont; + String currentFontId = baseFontId; + + List elementCodes = element.getCharCodes(); + int codeIndex = 0; + boolean rawType3CodesUsed = false; + int rawType3GlyphCount = 0; for (int offset = 0; offset < text.length(); ) { int codePoint = text.codePointAt(offset); offset += Character.charCount(codePoint); String glyph = new String(Character.toChars(codePoint)); - PDFont targetFont = currentFont; + PDFont targetFont = baseFont; + String targetFontId = baseFontId; + Integer rawCode = null; + if (elementCodes != null && codeIndex < elementCodes.size()) { + rawCode = elementCodes.get(codeIndex); + } + codeIndex++; - if (!fallbackFontService.canEncode(baseFont, codePoint)) { + if (hasNormalizedType3) { + targetFont = normalizedType3Font; + // For normalized fonts, check if the font can actually encode the glyph + // Don't check Type3 coverage since normalized fonts have full glyph sets + if (!fallbackFontService.canEncode(normalizedType3Font, glyph)) { + // Glyph not in normalized font, will trigger fallback below + targetFont = null; + targetFontId = null; + } + } else if (baseIsType3) { + // For actual Type3 fonts without normalized replacement + boolean type3SupportsGlyph = + isGlyphCoveredByType3Font(baseType3Coverage, codePoint); + if (!type3SupportsGlyph) { + targetFont = null; + targetFontId = null; + } + } + if (targetFont == null || !fallbackFontService.canEncode(targetFont, glyph)) { fallbackApplied = true; String fallbackId = fallbackFontService.resolveFallbackFontId(codePoint); targetFont = ensureFallbackFont(document, fontMap, fontModels, fallbackId); + targetFontId = fallbackId != null ? fallbackId : FALLBACK_FONT_ID; if (targetFont == null || !fallbackFontService.canEncode(targetFont, glyph)) { String mapped = fallbackFontService.mapUnsupportedGlyph(codePoint); if (mapped != null) { - if (fallbackFontService.canEncode(baseFont, mapped)) { - glyph = mapped; - targetFont = baseFont; - } else if (targetFont != null + if (targetFont != null && fallbackFontService.canEncode(targetFont, mapped)) { glyph = mapped; + } else if (fallbackFontService.canEncode(baseFont, mapped)) { + glyph = mapped; + targetFont = baseFont; + targetFontId = baseFontId; + } + } + if (targetFont == null || !fallbackFontService.canEncode(targetFont, glyph)) { + glyph = "?"; + targetFont = + ensureFallbackFont(document, fontMap, fontModels, FALLBACK_FONT_ID); + targetFontId = FALLBACK_FONT_ID; + if (targetFont == null + || !fallbackFontService.canEncode(targetFont, glyph)) { + log.debug( + "Dropping unsupported glyph U+{} for text element", + Integer.toHexString(codePoint)); + continue; } } } - if (targetFont == null || !fallbackFontService.canEncode(targetFont, glyph)) { - glyph = "?"; - targetFont = - ensureFallbackFont(document, fontMap, fontModels, FALLBACK_FONT_ID); - if (targetFont == null || !fallbackFontService.canEncode(targetFont, glyph)) { - log.debug( - "Dropping unsupported glyph U+{} for text element", - Integer.toHexString(codePoint)); - continue; - } - } if (targetFont != baseFont) { - log.trace( + log.info( "Using fallback font '{}' for code point U+{}", targetFont.getName(), Integer.toHexString(codePoint)); } } + boolean useRawType3Glyph = + rawCode != null + && baseIsType3 + && !hasNormalizedType3 + && targetFont == baseFont + && targetFont instanceof PDType3Font; + if (targetFont != currentFont) { if (buffer.length() > 0) { - runs.add(new FontRun(currentFont, buffer.toString())); + runs.add( + new FontRun( + currentFont, + currentFontId, + buffer.toString(), + codeBuffer.isEmpty() ? null : new ArrayList<>(codeBuffer))); buffer.setLength(0); + codeBuffer.clear(); } currentFont = targetFont; + currentFontId = targetFontId; } buffer.append(glyph); + if (useRawType3Glyph + && currentFontId != null + && currentFontId.equals(element.getFontId())) { + codeBuffer.add(rawCode); + rawType3CodesUsed = true; + rawType3GlyphCount++; + } } if (buffer.length() > 0) { - runs.add(new FontRun(currentFont, buffer.toString())); + runs.add( + new FontRun( + currentFont, + currentFontId, + buffer.toString(), + codeBuffer.isEmpty() ? null : new ArrayList<>(codeBuffer))); } if (fallbackApplied) { element.setFallbackUsed(Boolean.TRUE); } + if (rawType3CodesUsed) { + log.info( + "[TYPE3-RUNTIME] Reused original Type3 charCodes for font {} on page {} ({} glyphs)", + baseFontModel != null ? baseFontModel.getId() : baseFontId, + pageNumber, + rawType3GlyphCount); + } + return runs; } @@ -2349,20 +2871,32 @@ public class PdfJsonConversionService { private static final class FontRun { private final PDFont font; + private final String fontId; private final String text; + private final List charCodes; - private FontRun(PDFont font, String text) { + private FontRun(PDFont font, String fontId, String text, List charCodes) { this.font = font; + this.fontId = fontId; this.text = text; + this.charCodes = charCodes; } private PDFont font() { return font; } + private String fontId() { + return fontId; + } + private String text() { return text; } + + private List charCodes() { + return charCodes; + } } private boolean rewriteTextOperators( @@ -2370,7 +2904,9 @@ public class PdfJsonConversionService { PDPage page, List elements, boolean removeOnly, - boolean forceRegenerate) { + boolean forceRegenerate, + Map fontLookup, + int pageNumber) { if (forceRegenerate) { log.debug("forceRegenerate flag set; skipping token rewrite for page"); return false; @@ -2390,6 +2926,7 @@ public class PdfJsonConversionService { TextElementCursor cursor = new TextElementCursor(elements); PDFont currentFont = null; String currentFontName = null; + PdfJsonFont currentFontModel = null; boolean encounteredModifiedFont = false; @@ -2404,6 +2941,8 @@ public class PdfJsonConversionService { if (i >= 2 && tokens.get(i - 2) instanceof COSName fontResourceName) { currentFont = resources.getFont(fontResourceName); currentFontName = fontResourceName.getName(); + currentFontModel = + resolveFontModel(fontLookup, pageNumber, currentFontName); log.trace( "Encountered Tf operator; switching to font resource {}", currentFontName); @@ -2413,6 +2952,7 @@ public class PdfJsonConversionService { } else { currentFont = null; currentFontName = null; + currentFontModel = null; log.debug( "Tf operator missing resource operand; clearing current font"); } @@ -2429,7 +2969,12 @@ public class PdfJsonConversionService { i, cursor.remaining()); if (!rewriteShowText( - cosString, currentFont, currentFontName, cursor, removeOnly)) { + cosString, + currentFont, + currentFontModel, + currentFontName, + cursor, + removeOnly)) { log.debug("Failed to rewrite Tj operator; aborting rewrite"); return false; } @@ -2445,7 +2990,12 @@ public class PdfJsonConversionService { i, cursor.remaining()); if (!rewriteShowTextArray( - array, currentFont, currentFontName, cursor, removeOnly)) { + array, + currentFont, + currentFontModel, + currentFontName, + cursor, + removeOnly)) { log.debug("Failed to rewrite TJ operator; aborting rewrite"); return false; } @@ -2482,6 +3032,7 @@ public class PdfJsonConversionService { private boolean rewriteShowText( COSString cosString, PDFont font, + PdfJsonFont fontModel, String expectedFontName, TextElementCursor cursor, boolean removeOnly) @@ -2511,9 +3062,18 @@ public class PdfJsonConversionService { cosString.setValue(new byte[0]); return true; } - String replacement = mergeText(consumed); + MergedText replacement = mergeText(consumed); try { - byte[] encoded = font.encode(replacement); + byte[] encoded = + encodeTextWithFont( + font, fontModel, replacement.text(), replacement.charCodes()); + if (encoded == null) { + log.debug( + "Failed to map replacement text to glyphs for font {} (text='{}')", + expectedFontName, + replacement.text()); + return false; + } cosString.setValue(encoded); return true; } catch (IOException | IllegalArgumentException | UnsupportedOperationException ex) { @@ -2528,6 +3088,7 @@ public class PdfJsonConversionService { private boolean rewriteShowTextArray( COSArray array, PDFont font, + PdfJsonFont fontModel, String expectedFontName, TextElementCursor cursor, boolean removeOnly) @@ -2556,9 +3117,18 @@ public class PdfJsonConversionService { array.set(i, new COSString(new byte[0])); continue; } - String replacement = mergeText(consumed); + MergedText replacement = mergeText(consumed); try { - byte[] encoded = font.encode(replacement); + byte[] encoded = + encodeTextWithFont( + font, fontModel, replacement.text(), replacement.charCodes()); + if (encoded == null) { + log.debug( + "Failed to map replacement text in TJ array for font {} segment {}", + expectedFontName, + i); + return false; + } array.set(i, new COSString(encoded)); } catch (IOException | IllegalArgumentException @@ -2575,6 +3145,158 @@ public class PdfJsonConversionService { return true; } + private byte[] encodeTextWithFont( + PDFont font, PdfJsonFont fontModel, String text, List rawCharCodes) + throws IOException { + boolean isType3Font = font instanceof PDType3Font; + boolean hasType3Metadata = fontModel != null + && fontModel.getType3Glyphs() != null + && !fontModel.getType3Glyphs().isEmpty(); + + // For normalized Type3 fonts (font is NOT Type3 but has Type3 metadata) + if (!isType3Font && hasType3Metadata) { + // If loaded as full font (not subset), use standard Unicode encoding + // Try standard encoding first - this works when the font has all glyphs + try { + byte[] encoded = font.encode(text); + // NOTE: Do NOT sanitize encoded bytes for normalized Type3 fonts + // Multi-byte encodings (UTF-16BE, CID fonts) have null bytes that are essential + // Removing them corrupts the byte boundaries and produces garbled text + log.info("[TYPE3] Encoded text '{}' for normalized font {}: encoded={} bytes", + text.length() > 20 ? text.substring(0, 20) + "..." : text, + fontModel.getId(), + encoded != null ? encoded.length : 0); + if (encoded != null && encoded.length > 0) { + log.info("[TYPE3] Successfully encoded text for normalized Type3 font {} using standard encoding", + fontModel.getId()); + return encoded; + } + log.info("[TYPE3] Standard encoding produced empty result for normalized Type3 font {}, falling through to Type3 mapping", + fontModel.getId()); + } catch (IOException | IllegalArgumentException ex) { + log.info("[TYPE3] Standard encoding failed for normalized Type3 font {}: {}", + fontModel.getId(), ex.getMessage()); + } + // If standard encoding failed, fall through to Type3 glyph mapping (for subset fonts) + // or return null to trigger fallback font + } else if (!isType3Font || fontModel == null) { + // For non-Type3 fonts without Type3 metadata, use standard encoding + return sanitizeEncoded(font.encode(text)); + } + + // Type3 glyph mapping logic (for actual Type3 fonts AND normalized Type3 fonts) + List glyphs = fontModel.getType3Glyphs(); + if (glyphs == null || glyphs.isEmpty()) { + return null; + } + + // For normalized Type3 fonts, DO NOT use rawCharCodes because: + // 1. They may be stale if text was edited + // 2. The subset font only has glyphs from the original PDF + // Instead, try Type3 glyph mapping and return null if glyphs are missing + // (null will trigger fallback font usage in the calling code) + + // Build Unicode to character code mapping from Type3 glyphs + Map unicodeToCode = new HashMap<>(); + for (PdfJsonFontType3Glyph glyph : glyphs) { + if (glyph == null) { + continue; + } + Integer unicode = glyph.getUnicode(); + Integer charCode = glyph.getCharCode(); + if (unicode == null || charCode == null) { + continue; + } + unicodeToCode.putIfAbsent(unicode, charCode); + } + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + boolean mappedAll = true; + for (int offset = 0; offset < text.length(); ) { + int codePoint = text.codePointAt(offset); + offset += Character.charCount(codePoint); + Integer charCode = unicodeToCode.get(codePoint); + if (charCode == null) { + log.debug( + "[TYPE3] Missing glyph mapping for code point U+{} in font {}", + Integer.toHexString(codePoint).toUpperCase(Locale.ROOT), + fontModel.getId()); + mappedAll = false; + break; + } + if (charCode < 0 || charCode > 0xFF) { + log.debug( + "[TYPE3] Unsupported Type3 charCode {} for font {} (only 1-byte codes supported)", + charCode, + fontModel.getId()); + mappedAll = false; + break; + } + baos.write(charCode); + } + if (mappedAll) { + return sanitizeEncoded(baos.toByteArray()); + } + // Fallback to rawCharCodes for actual Type3 fonts if mapping failed + if (rawCharCodes != null && !rawCharCodes.isEmpty()) { + boolean valid = true; + ByteArrayOutputStream fallbackBytes = new ByteArrayOutputStream(rawCharCodes.size()); + for (Integer code : rawCharCodes) { + if (code == null || code < 0 || code > 0xFF) { + valid = false; + break; + } + fallbackBytes.write(code); + } + if (valid) { + return fallbackBytes.toByteArray(); + } + } + return null; + } + + private byte[] encodeType3CharCodes(List charCodes) { + if (charCodes == null || charCodes.isEmpty()) { + return null; + } + ByteArrayOutputStream baos = new ByteArrayOutputStream(charCodes.size()); + for (Integer code : charCodes) { + if (code == null || code < 0 || code > 0xFF) { + return null; + } + baos.write(code); + } + return baos.toByteArray(); + } + + private byte[] sanitizeEncoded(byte[] encoded) { + if (encoded == null || encoded.length == 0) { + return new byte[0]; + } + ByteArrayOutputStream baos = new ByteArrayOutputStream(encoded.length); + for (byte b : encoded) { + if (isStrippedControlByte(b)) { + continue; + } + baos.write(b); + } + byte[] sanitized = baos.toByteArray(); + if (sanitized.length == 0) { + return sanitized; + } + return sanitized; + } + + private boolean isStrippedControlByte(byte value) { + if (value == 0) { + return true; + } + int unsigned = Byte.toUnsignedInt(value); + if (unsigned <= 0x1F) { + return !(unsigned == 0x09 || unsigned == 0x0A || unsigned == 0x0D); + } + return false; + } + private int countGlyphs(COSString value, PDFont font) { if (value == null) { return 0; @@ -2597,14 +3319,20 @@ public class PdfJsonConversionService { return Math.max(1, bytes.length); } - private String mergeText(List elements) { + private MergedText mergeText(List elements) { StringBuilder builder = new StringBuilder(); + List combinedCodes = new ArrayList<>(); for (PdfJsonTextElement element : elements) { builder.append(Objects.toString(element.getText(), "")); + if (element.getCharCodes() != null && !element.getCharCodes().isEmpty()) { + combinedCodes.addAll(element.getCharCodes()); + } } - return builder.toString(); + return new MergedText(builder.toString(), combinedCodes.isEmpty() ? null : combinedCodes); } + private record MergedText(String text, List charCodes) {} + private static class TextElementCursor { private final List elements; private int index = 0; @@ -2663,6 +3391,10 @@ public class PdfJsonConversionService { } private int countGlyphs(PdfJsonTextElement element) { + List codes = element.getCharCodes(); + if (codes != null && !codes.isEmpty()) { + return codes.size(); + } String text = element.getText(); if (text != null && !text.isEmpty()) { return Math.max(1, text.codePointCount(0, text.length())); @@ -2741,9 +3473,7 @@ public class PdfJsonConversionService { ? fontModel.getPdfProgramFormat().toLowerCase(Locale.ROOT) : null; - record FontByteSource(byte[] bytes, String format, String originLabel) {} - - List candidates = new ArrayList<>(); + List baseCandidates = new ArrayList<>(); List deferredWebCandidates = new ArrayList<>(); boolean hasPdfProgram = pdfProgram != null && !pdfProgram.isBlank(); @@ -2753,7 +3483,7 @@ public class PdfJsonConversionService { try { byte[] bytes = Base64.getDecoder().decode(pdfProgram); if (bytes.length > 0) { - candidates.add(new FontByteSource(bytes, pdfFormat, "pdfProgram")); + baseCandidates.add(new FontByteSource(bytes, pdfFormat, "pdfProgram")); } } catch (IllegalArgumentException ex) { log.warn( @@ -2775,7 +3505,7 @@ public class PdfJsonConversionService { || "cidfonttype0c".equals(originalFormat); FontByteSource source = new FontByteSource(bytes, webFormat, "webProgram"); if (preferWeb) { - candidates.add(source); + baseCandidates.add(source); } else { // Keep the converted blob as a secondary option in case loading the // original program fails: some PDFs mix Type1 metadata with actual CFF @@ -2797,7 +3527,7 @@ public class PdfJsonConversionService { if (bytes.length > 0) { // Original bytes should still be attempted. When we already preferred the // converted blob, these will be appended as fallback. - candidates.add(new FontByteSource(bytes, originalFormat, "program")); + baseCandidates.add(new FontByteSource(bytes, originalFormat, "program")); } } catch (IllegalArgumentException ex) { log.warn( @@ -2809,20 +3539,61 @@ public class PdfJsonConversionService { // If no candidates were added (e.g. both payloads missing/invalid) attempt to fall back to // the converted program when it exists but we skipped it earlier. - if (candidates.isEmpty() && hasWebProgram) { + if (baseCandidates.isEmpty() && hasWebProgram) { try { byte[] bytes = Base64.getDecoder().decode(webProgram); if (bytes.length > 0) { - candidates.add(new FontByteSource(bytes, webFormat, "webProgram")); + baseCandidates.add(new FontByteSource(bytes, webFormat, "webProgram")); } } catch (IllegalArgumentException ignored) { // Already logged above when decoding failed the first time. } } - candidates.addAll(deferredWebCandidates); + baseCandidates.addAll(deferredWebCandidates); - for (FontByteSource source : candidates) { + List conversionCandidates = + collectConversionCandidateSources(fontModel.getConversionCandidates()); + + List orderedCandidates = new ArrayList<>(); + if (!conversionCandidates.isEmpty()) { + orderedCandidates.addAll(conversionCandidates); + } + orderedCandidates.addAll(baseCandidates); + + boolean isType3Font = + fontModel.getSubtype() != null && "type3".equalsIgnoreCase(fontModel.getSubtype()); + if (isType3Font) { + cacheType3NormalizedFont(document, fontModel, orderedCandidates, originalFormat); + PDFont cachedNormalized = + fontModel.getUid() != null + ? type3NormalizedFontCache.get(fontModel.getUid()) + : null; + if (cachedNormalized != null) { + log.debug("Using cached normalized font for Type3 {}", fontModel.getId()); + return cachedNormalized; + } + PDFont restored = restoreFontFromDictionary(document, fontModel); + if (restored != null) { + return restored; + } + // Fall through to Standard14 fallback below if nothing else succeeded. + } else { + PDFont loaded = + loadFirstAvailableFont(document, fontModel, orderedCandidates, originalFormat); + if (loaded != null) { + return loaded; + } + } + + if (!isType3Font) { + PDFont restored = restoreFontFromDictionary(document, fontModel); + if (restored != null) { + return restored; + } + } + + for (FontByteSource source : orderedCandidates) { byte[] fontBytes = source.bytes(); String format = source.format(); String originLabel = source.originLabel(); @@ -2832,69 +3603,20 @@ public class PdfJsonConversionService { } try { - if (isType1Format(format)) { - try (InputStream stream = new ByteArrayInputStream(fontBytes)) { - PDFont font = new PDType1Font(document, stream); - applyAdditionalFontMetadata(document, font, fontModel); - log.debug( - "Successfully loaded Type1 font {} from {} bytes (format: {}, originalFormat: {})", - fontModel.getId(), - originLabel, - format, - originalFormat); - return font; - } - } - - try (InputStream stream = new ByteArrayInputStream(fontBytes)) { - PDFont font = PDType0Font.load(document, stream, true); - applyAdditionalFontMetadata(document, font, fontModel); - log.debug( - "Successfully loaded Type0 font {} from {} bytes (format: {}, originalFormat: {})", - fontModel.getId(), - originLabel, - format, - originalFormat); + PDFont font = + loadFontFromSource( + document, fontModel, source, originalFormat, false, false, false); + if (font != null) { return font; } } catch (IOException ex) { - log.warn( - "Unable to load embedded font program for {} from {} (format: {}, originalFormat: {}): {}", - fontModel.getId(), - originLabel, - format, - originalFormat, - ex.getMessage()); + // loadFontFromSource already logged details. } } - // As a last resort, rebuild the original font dictionary which still references the - // embedded program streams captured during extraction. This handles subset fonts whose - // raw program bytes cannot be reloaded directly (e.g., missing Unicode cmap tables). - if (fontModel.getCosDictionary() != null) { - COSBase restored = - cosMapper.deserializeCosValue(fontModel.getCosDictionary(), document); - if (restored instanceof COSDictionary cosDictionary) { - try { - PDFont font = PDFontFactory.createFont(cosDictionary); - if (font != null && font.isEmbedded()) { - applyAdditionalFontMetadata(document, font, fontModel); - log.debug( - "Successfully restored embedded font {} from original dictionary", - fontModel.getId()); - return font; - } - log.debug( - "Restored font {} from dictionary but font was {}embedded; continuing", - fontModel.getId(), - font != null && font.isEmbedded() ? "" : "not "); - } catch (IOException ex) { - log.debug( - "Failed to restore font {} from stored dictionary: {}", - fontModel.getId(), - ex.getMessage()); - } - } + PDFont restored = restoreFontFromDictionary(document, fontModel); + if (restored != null) { + return restored; } log.warn( @@ -2926,6 +3648,164 @@ public class PdfJsonConversionService { return fallback; } + private void cacheType3NormalizedFont( + PDDocument document, + PdfJsonFont fontModel, + List candidates, + String originalFormat) + throws IOException { + if (fontModel.getUid() == null || candidates == null || candidates.isEmpty()) { + return; + } + if (type3NormalizedFontCache.containsKey(fontModel.getUid())) { + return; + } + for (FontByteSource source : candidates) { + PDFont font = + loadFontFromSource(document, fontModel, source, originalFormat, true, true, true); + if (font != null) { + type3NormalizedFontCache.put(fontModel.getUid(), font); + log.info( + "Cached normalized font {} for Type3 {}", + source.originLabel(), + fontModel.getId()); + break; + } + } + } + + private PDFont loadFirstAvailableFont( + PDDocument document, + PdfJsonFont fontModel, + List candidates, + String originalFormat) + throws IOException { + for (FontByteSource source : candidates) { + PDFont font = + loadFontFromSource(document, fontModel, source, originalFormat, false, false, false); + if (font != null) { + return font; + } + } + return null; + } + + private PDFont loadFontFromSource( + PDDocument document, + PdfJsonFont fontModel, + FontByteSource source, + String originalFormat, + boolean suppressWarn, + boolean skipMetadataLog, + boolean skipMetadata) + throws IOException { + if (source == null) { + return null; + } + byte[] fontBytes = source.bytes(); + if (fontBytes == null || fontBytes.length == 0) { + return null; + } + String format = source.format(); + String originLabel = source.originLabel(); + try { + if (!skipMetadataLog) { + log.info( + "[FONT-DEBUG] Attempting to load font {} using payload {} (format={}, size={} bytes)", + fontModel.getId(), + originLabel, + format, + fontBytes.length); + } + if (isType1Format(format)) { + try (InputStream stream = new ByteArrayInputStream(fontBytes)) { + PDFont font = new PDType1Font(document, stream); + if (!skipMetadata) { + applyAdditionalFontMetadata(document, font, fontModel); + } + log.debug( + "Successfully loaded Type1 font {} from {} bytes (format: {}, originalFormat: {})", + fontModel.getId(), + originLabel, + format, + originalFormat); + return font; + } + } + try (InputStream stream = new ByteArrayInputStream(fontBytes)) { + // For library fonts (Type3 normalized fonts), load WITHOUT subsetting + // so all glyphs are available for editing + boolean willBeSubset = !originLabel.contains("type3-library"); + if (!willBeSubset) { + log.info("[TYPE3-RUNTIME] Loading library font {} WITHOUT subsetting (full glyph set) from {}", + fontModel.getId(), originLabel); + } + PDFont font = PDType0Font.load(document, stream, willBeSubset); + if (!skipMetadata) { + applyAdditionalFontMetadata(document, font, fontModel); + } + log.debug( + "Successfully loaded Type0 font {} from {} bytes (format: {}, originalFormat: {}, subset: {})", + fontModel.getId(), + originLabel, + format, + originalFormat, + willBeSubset); + return font; + } + } catch (IOException ex) { + if (suppressWarn) { + log.debug( + "Unable to load embedded font program for {} from {} (format: {}, originalFormat: {}): {}", + fontModel.getId(), + originLabel, + format, + originalFormat, + ex.getMessage()); + } else { + log.warn( + "Unable to load embedded font program for {} from {} (format: {}, originalFormat: {}): {}", + fontModel.getId(), + originLabel, + format, + originalFormat, + ex.getMessage()); + } + return null; + } + } + + private PDFont restoreFontFromDictionary(PDDocument document, PdfJsonFont fontModel) + throws IOException { + if (fontModel.getCosDictionary() == null) { + return null; + } + COSBase restored = cosMapper.deserializeCosValue(fontModel.getCosDictionary(), document); + if (!(restored instanceof COSDictionary cosDictionary)) { + return null; + } + try { + PDFont font = PDFontFactory.createFont(cosDictionary); + if (font != null && font.isEmbedded()) { + applyAdditionalFontMetadata(document, font, fontModel); + log.debug( + "Successfully restored embedded font {} from original dictionary", + fontModel.getId()); + return font; + } + log.debug( + "Restored font {} from dictionary but font was {}embedded; continuing", + fontModel.getId(), + font != null && font.isEmbedded() ? "" : "not "); + } catch (IOException ex) { + log.debug( + "Failed to restore font {} from stored dictionary: {}", + fontModel.getId(), + ex.getMessage()); + } + return null; + } + private boolean isType1Format(String format) { if (format == null) { return false; @@ -3528,7 +4408,7 @@ public class PdfJsonConversionService { for (TextPosition position : textPositions) { PDFont font = position.getFont(); String fontId = registerFont(font); - PdfJsonTextElement element = createTextElement(position, fontId); + PdfJsonTextElement element = createTextElement(position, fontId, font); if (accumulator == null) { accumulator = new TextRunAccumulator(element, position); @@ -3549,8 +4429,8 @@ public class PdfJsonConversionService { } } - private PdfJsonTextElement createTextElement(TextPosition position, String fontId) - throws IOException { + private PdfJsonTextElement createTextElement( + TextPosition position, String fontId, PDFont pdfont) throws IOException { PdfJsonTextElement element = new PdfJsonTextElement(); element.setText(position.getUnicode()); element.setFontId(fontId); @@ -3562,6 +4442,20 @@ public class PdfJsonConversionService { element.setTextMatrix(extractMatrix(position)); element.setFontMatrixSize(computeFontMatrixSize(element.getTextMatrix())); element.setSpaceWidth(position.getWidthOfSpace()); + if (pdfont instanceof PDType3Font) { + int[] codes = position.getCharacterCodes(); + if (codes != null && codes.length > 0) { + List codeList = new ArrayList<>(codes.length); + for (int code : codes) { + if (code >= 0) { + codeList.add(code); + } + } + if (!codeList.isEmpty()) { + element.setCharCodes(codeList); + } + } + } PDGraphicsState graphicsState = getGraphicsState(); if (graphicsState != null) { @@ -3687,6 +4581,7 @@ public class PdfJsonConversionService { private final float startXCoord; private final float startYCoord; private final StringBuilder textBuilder = new StringBuilder(); + private final List charCodeBuffer = new ArrayList<>(); private float totalWidth; private float maxHeight; private float endXCoord; @@ -3718,6 +4613,9 @@ public class PdfJsonConversionService { this.maxHeight = element.getHeight() != null ? element.getHeight() : 0f; this.endXCoord = position.getXDirAdj() + position.getWidthDirAdj(); this.textBuilder.append(element.getText()); + if (element.getCharCodes() != null) { + charCodeBuffer.addAll(element.getCharCodes()); + } } boolean canAppend(PdfJsonTextElement element, TextPosition position) { @@ -3765,6 +4663,9 @@ public class PdfJsonConversionService { maxHeight = height; } endXCoord = position.getXDirAdj() + position.getWidthDirAdj(); + if (element.getCharCodes() != null) { + charCodeBuffer.addAll(element.getCharCodes()); + } } PdfJsonTextElement build() { @@ -3788,6 +4689,11 @@ public class PdfJsonConversionService { result.setX(null); result.setY(null); } + if (charCodeBuffer.isEmpty()) { + result.setCharCodes(null); + } else { + result.setCharCodes(new ArrayList<>(charCodeBuffer)); + } compactTextElement(result); return result; } @@ -3843,7 +4749,7 @@ public class PdfJsonConversionService { } String key = buildFontKey(currentPage, fontId); if (!fonts.containsKey(key)) { - fonts.put(key, buildFontModel(font, fontId, currentPage, fontCache)); + fonts.put(key, buildFontModel(document, font, fontId, currentPage, fontCache)); } return fontId; } @@ -3962,7 +4868,7 @@ public class PdfJsonConversionService { */ private void reportProgressToTaskManager(String jobId, PdfJsonConversionProgress progress) { try { - log.info( + log.debug( "Reporting progress for job {}: {}% - {}", jobId, progress.getPercent(), progress.getStage()); // Add progress note to job @@ -3986,7 +4892,7 @@ public class PdfJsonConversionService { if (!added) { log.warn("Failed to add note - job {} not found in TaskManager", jobId); } else { - log.info("Successfully added progress note for job {}: {}", jobId, note); + log.debug("Successfully added progress note for job {}: {}", jobId, note); } } catch (Exception e) { log.error("Exception reporting progress for job {}: {}", jobId, e.getMessage(), e); @@ -4022,7 +4928,13 @@ public class PdfJsonConversionService { } public CachedPdfDocument withUpdatedPdfBytes(byte[] nextBytes) { - return new CachedPdfDocument(nextBytes, metadata, fonts, pageFontResources); + return withUpdatedFonts(nextBytes, this.fonts); + } + + public CachedPdfDocument withUpdatedFonts( + byte[] nextBytes, Map nextFonts) { + Map fontsToUse = nextFonts != null ? nextFonts : this.fonts; + return new CachedPdfDocument(nextBytes, metadata, fontsToUse, pageFontResources); } } @@ -4038,7 +4950,7 @@ public class PdfJsonConversionService { Consumer progress = jobId != null ? (p) -> { - log.info( + log.debug( "Progress: [{}%] {} - {}{}", p.getPercent(), p.getStage(), @@ -4105,7 +5017,7 @@ public class PdfJsonConversionService { CachedPdfDocument cached = new CachedPdfDocument(pdfBytes, docMetadata, fonts, pageFontResources); documentCache.put(jobId, cached); - log.info( + log.debug( "Cached PDF bytes ({} bytes, {} pages, {} fonts) for lazy loading, jobId: {}", pdfBytes.length, totalPages, @@ -4284,33 +5196,41 @@ public class PdfJsonConversionService { throw new IllegalArgumentException("No cached document available for jobId: " + jobId); } if (updates == null || updates.getPages() == null || updates.getPages().isEmpty()) { - log.info( + log.debug( "Incremental export requested with no page updates; returning cached PDF for jobId {}", jobId); return cached.getPdfBytes(); } try (PDDocument document = pdfDocumentFactory.load(cached.getPdfBytes(), true)) { - List fontModels = new ArrayList<>(cached.getFonts().values()); + Map mergedFonts = new LinkedHashMap<>(); + if (cached.getFonts() != null) { + cached.getFonts() + .forEach( + (key, value) -> { + PdfJsonFont clone = cloneFont(value); + mergedFonts.put(key, clone != null ? clone : value); + }); + } if (updates.getFonts() != null) { for (PdfJsonFont font : updates.getFonts()) { - if (font == null || font.getId() == null) { + if (font == null) { continue; } - boolean exists = - fontModels.stream() - .anyMatch( - existing -> - Objects.equals(existing.getId(), font.getId()) - && Objects.equals( - existing.getUid(), - font.getUid())); - if (!exists) { - fontModels.add(font); + String cacheKey = resolveFontCacheKey(font); + if (cacheKey == null) { + continue; + } + PdfJsonFont clone = cloneFont(font); + PdfJsonFont toStore = clone != null ? clone : font; + mergedFonts.put(cacheKey, toStore); + if (toStore.getUid() != null) { + type3NormalizedFontCache.remove(toStore.getUid()); } } } + List fontModels = new ArrayList<>(mergedFonts.values()); List fontModelsCopy = new ArrayList<>(fontModels); Map fontMap = buildFontMap(document, fontModelsCopy); @@ -4341,7 +5261,7 @@ public class PdfJsonConversionService { } if (updatedPages.isEmpty()) { - log.info( + log.debug( "Incremental export for jobId {} resulted in no page updates; returning cached PDF", jobId); return cached.getPdfBytes(); @@ -4351,9 +5271,9 @@ public class PdfJsonConversionService { document.save(baos); byte[] updatedBytes = baos.toByteArray(); - documentCache.put(jobId, cached.withUpdatedPdfBytes(updatedBytes)); + documentCache.put(jobId, cached.withUpdatedFonts(updatedBytes, mergedFonts)); - log.info( + log.debug( "Incremental export complete for jobId {} (pages updated: {})", jobId, updatedPages.stream().map(i -> i + 1).sorted().toList()); @@ -4365,7 +5285,7 @@ public class PdfJsonConversionService { public void clearCachedDocument(String jobId) { CachedPdfDocument cached = documentCache.remove(jobId); if (cached != null) { - log.info( + log.debug( "Removed cached PDF bytes ({} bytes) for jobId: {}", cached.getPdfBytes().length, jobId); @@ -4424,6 +5344,8 @@ public class PdfJsonConversionService { ensureFallbackResources(page, preflightResult.fallbackFontIds(), fontMap); } + Map fontLookup = buildFontModelLookup(fontModels); + AppendMode appendMode = preservedStreams.isEmpty() ? AppendMode.OVERWRITE : AppendMode.APPEND; @@ -4435,6 +5357,7 @@ public class PdfJsonConversionService { textElements, imageElements, preflightResult, + fontLookup, pageNumberValue); if (regenerateMode == RegenerateMode.REUSE_EXISTING) { @@ -4487,6 +5410,7 @@ public class PdfJsonConversionService { List textElements, List imageElements, PreflightResult preflightResult, + Map fontLookup, int pageNumberValue) throws IOException { boolean hasText = textElements != null && !textElements.isEmpty(); @@ -4506,7 +5430,8 @@ public class PdfJsonConversionService { if (hasText && !preflightResult.usesFallback()) { boolean rewriteSucceeded = - rewriteTextOperators(document, page, textElements, false, true); + rewriteTextOperators( + document, page, textElements, false, true, fontLookup, pageNumberValue); if (rewriteSucceeded) { return RegenerateMode.REUSE_EXISTING; } @@ -4529,7 +5454,7 @@ public class PdfJsonConversionService { try { Thread.sleep(TimeUnit.MINUTES.toMillis(30)); clearCachedDocument(jobId); - log.info("Auto-cleaned cached document for jobId: {}", jobId); + log.debug("Auto-cleaned cached document for jobId: {}", jobId); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } diff --git a/app/proprietary/src/main/java/stirling/software/SPDF/service/PdfJsonFallbackFontService.java b/app/proprietary/src/main/java/stirling/software/SPDF/service/PdfJsonFallbackFontService.java index ee9a4ee75..2cf555e21 100644 --- a/app/proprietary/src/main/java/stirling/software/SPDF/service/PdfJsonFallbackFontService.java +++ b/app/proprietary/src/main/java/stirling/software/SPDF/service/PdfJsonFallbackFontService.java @@ -11,6 +11,7 @@ import java.util.concurrent.ConcurrentHashMap; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.font.PDFont; import org.apache.pdfbox.pdmodel.font.PDType0Font; +import org.apache.pdfbox.pdmodel.font.PDType3Font; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; @@ -122,10 +123,19 @@ public class PdfJsonFallbackFontService { if (font == null || text == null || text.isEmpty()) { return false; } + if (font instanceof PDType3Font) { + return false; + } try { font.encode(text); return true; - } catch (IOException | IllegalArgumentException ex) { + } catch (IOException | IllegalArgumentException | UnsupportedOperationException ex) { + log.info( + "[FONT-DEBUG] Font {} cannot encode text '{}' ({}): {}", + font != null ? font.getName() : "null", + text, + font != null ? font.getClass().getSimpleName() : "null", + ex.getMessage()); return false; } } diff --git a/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/Type3ConversionRequest.java b/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/Type3ConversionRequest.java new file mode 100644 index 000000000..7a811f815 --- /dev/null +++ b/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/Type3ConversionRequest.java @@ -0,0 +1,17 @@ +package stirling.software.SPDF.service.pdfjson.type3; + +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.font.PDType3Font; + +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class Type3ConversionRequest { + private final PDDocument document; + private final PDType3Font font; + private final String fontId; + private final int pageNumber; + private final String fontUid; +} diff --git a/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/Type3ConversionStrategy.java b/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/Type3ConversionStrategy.java new file mode 100644 index 000000000..9f62dea7e --- /dev/null +++ b/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/Type3ConversionStrategy.java @@ -0,0 +1,32 @@ +package stirling.software.SPDF.service.pdfjson.type3; + +import java.io.IOException; + +import stirling.software.SPDF.model.json.PdfJsonFontConversionCandidate; + +public interface Type3ConversionStrategy { + + /** Unique identifier used when reporting results. */ + String getId(); + + /** Human-readable label for UI toggles or logs. */ + String getLabel(); + + /** True when the underlying tooling is usable on this host. */ + boolean isAvailable(); + + /** Quick predicate to avoid running on unsupported Type3 shapes. */ + default boolean supports(Type3ConversionRequest request, Type3GlyphContext context) + throws IOException { + return request != null && request.getFont() != null; + } + + /** + * Attempt to synthesise a font program for the supplied Type3 font. + * + * @param request contextual information for the conversion attempt + * @return a candidate describing the outcome, never {@code null} + */ + PdfJsonFontConversionCandidate convert( + Type3ConversionRequest request, Type3GlyphContext context) throws IOException; +} diff --git a/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/Type3FontConversionService.java b/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/Type3FontConversionService.java new file mode 100644 index 000000000..c1269c74c --- /dev/null +++ b/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/Type3FontConversionService.java @@ -0,0 +1,133 @@ +package stirling.software.SPDF.service.pdfjson.type3; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.springframework.stereotype.Service; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import stirling.software.SPDF.model.json.PdfJsonFontConversionCandidate; +import stirling.software.SPDF.model.json.PdfJsonFontConversionStatus; + +@Slf4j +@Service +@RequiredArgsConstructor +public class Type3FontConversionService { + + private final List strategies; + private final Type3GlyphExtractor glyphExtractor; + + public List synthesize(Type3ConversionRequest request) { + if (request == null || request.getFont() == null) { + return Collections.emptyList(); + } + if (strategies == null || strategies.isEmpty()) { + log.debug( + "[TYPE3] No conversion strategies registered for font {}", request.getFontId()); + return Collections.emptyList(); + } + + List candidates = new ArrayList<>(); + Type3GlyphContext glyphContext = null; + for (Type3ConversionStrategy strategy : strategies) { + if (strategy == null) { + continue; + } + PdfJsonFontConversionCandidate candidate = + runStrategy( + strategy, + request, + glyphContext == null + ? (glyphContext = + new Type3GlyphContext(request, glyphExtractor)) + : glyphContext); + if (candidate != null) { + candidates.add(candidate); + } + } + return candidates; + } + + private PdfJsonFontConversionCandidate runStrategy( + Type3ConversionStrategy strategy, + Type3ConversionRequest request, + Type3GlyphContext glyphContext) { + if (!strategy.isAvailable()) { + return PdfJsonFontConversionCandidate.builder() + .strategyId(strategy.getId()) + .strategyLabel(strategy.getLabel()) + .status(PdfJsonFontConversionStatus.SKIPPED) + .message("Strategy unavailable on current host") + .build(); + } + try { + if (!strategy.supports(request, glyphContext)) { + return PdfJsonFontConversionCandidate.builder() + .strategyId(strategy.getId()) + .strategyLabel(strategy.getLabel()) + .status(PdfJsonFontConversionStatus.UNSUPPORTED) + .message("Font not supported by strategy") + .build(); + } + } catch (IOException supportCheckException) { + log.warn( + "[TYPE3] Strategy {} support check failed for font {}: {}", + strategy.getId(), + request.getFontUid(), + supportCheckException.getMessage(), + supportCheckException); + return PdfJsonFontConversionCandidate.builder() + .strategyId(strategy.getId()) + .strategyLabel(strategy.getLabel()) + .status(PdfJsonFontConversionStatus.UNSUPPORTED) + .message("Support check failed: " + supportCheckException.getMessage()) + .build(); + } + + try { + PdfJsonFontConversionCandidate result = strategy.convert(request, glyphContext); + if (result == null) { + log.info( + "[TYPE3] Strategy {} returned null result for font {}", + strategy.getId(), + request.getFontUid()); + return PdfJsonFontConversionCandidate.builder() + .strategyId(strategy.getId()) + .strategyLabel(strategy.getLabel()) + .status(PdfJsonFontConversionStatus.FAILURE) + .message("Strategy returned null result") + .build(); + } + if (result.getStrategyId() == null) { + result.setStrategyId(strategy.getId()); + } + if (result.getStrategyLabel() == null) { + result.setStrategyLabel(strategy.getLabel()); + } + log.info( + "[TYPE3] Strategy {} finished with status {} (message: {}) for font {}", + strategy.getId(), + result.getStatus(), + result.getMessage(), + request.getFontUid()); + return result; + } catch (IOException ex) { + log.warn( + "[TYPE3] Strategy {} failed for font {}: {}", + strategy.getId(), + request.getFontUid(), + ex.getMessage(), + ex); + return PdfJsonFontConversionCandidate.builder() + .strategyId(strategy.getId()) + .strategyLabel(strategy.getLabel()) + .status(PdfJsonFontConversionStatus.FAILURE) + .message(ex.getMessage()) + .build(); + } + } +} diff --git a/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/Type3FontSignatureCalculator.java b/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/Type3FontSignatureCalculator.java new file mode 100644 index 000000000..23634a7a3 --- /dev/null +++ b/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/Type3FontSignatureCalculator.java @@ -0,0 +1,218 @@ +package stirling.software.SPDF.service.pdfjson.type3; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Locale; + +import org.apache.pdfbox.cos.COSArray; +import org.apache.pdfbox.cos.COSBase; +import org.apache.pdfbox.cos.COSDictionary; +import org.apache.pdfbox.cos.COSName; +import org.apache.pdfbox.cos.COSNumber; +import org.apache.pdfbox.cos.COSStream; +import org.apache.pdfbox.pdmodel.common.PDRectangle; +import org.apache.pdfbox.pdmodel.font.PDType3CharProc; +import org.apache.pdfbox.pdmodel.font.PDType3Font; +import org.apache.pdfbox.pdmodel.font.encoding.Encoding; +import org.apache.pdfbox.util.Matrix; + +/** + * Computes a reproducible hash for Type3 fonts so we can match them against a pre-built library of + * converted programs. The signature intentionally combines multiple aspects of the font (encoding, + * CharProc streams, glyph widths, font metrics) to minimise collisions between unrelated fonts that + * coincidentally share glyph names. + */ +public final class Type3FontSignatureCalculator { + + private Type3FontSignatureCalculator() {} + + public static String computeSignature(PDType3Font font) throws IOException { + if (font == null) { + return null; + } + MessageDigest digest = newDigest(); + updateMatrix(digest, font.getFontMatrix()); + updateRectangle(digest, font.getFontBBox()); + updateEncoding(digest, font.getEncoding()); + updateCharProcs(digest, font); + byte[] hash = digest.digest(); + return "sha256:" + toHex(hash); + } + + private static void updateEncoding(MessageDigest digest, Encoding encoding) { + if (encoding == null) { + updateInt(digest, -1); + return; + } + for (int code = 0; code <= 0xFF; code++) { + String name = encoding.getName(code); + if (name != null) { + updateInt(digest, code); + updateString(digest, name); + } + } + } + + private static void updateCharProcs(MessageDigest digest, PDType3Font font) throws IOException { + COSDictionary charProcs = + (COSDictionary) font.getCOSObject().getDictionaryObject(COSName.CHAR_PROCS); + if (charProcs == null || charProcs.size() == 0) { + updateInt(digest, 0); + return; + } + List glyphNames = new ArrayList<>(charProcs.keySet()); + glyphNames.sort(Comparator.comparing(COSName::getName, String.CASE_INSENSITIVE_ORDER)); + for (COSName glyphName : glyphNames) { + updateString(digest, glyphName.getName()); + int code = resolveCharCode(font, glyphName.getName()); + updateInt(digest, code); + if (code >= 0) { + try { + updateFloat(digest, font.getWidthFromFont(code)); + } catch (IOException ignored) { + updateFloat(digest, 0f); + } + } else { + updateFloat(digest, 0f); + } + + COSStream stream = + charProcs.getDictionaryObject(glyphName) instanceof COSStream cosStream + ? cosStream + : null; + if (stream != null) { + byte[] payload = readAllBytes(stream); + updateInt(digest, payload.length); + digest.update(payload); + PDType3CharProc charProc = new PDType3CharProc(font, stream); + updateRectangle(digest, extractGlyphBoundingBox(font, charProc)); + } else { + updateInt(digest, -1); + } + } + updateInt(digest, glyphNames.size()); + } + + private static byte[] readAllBytes(COSStream stream) throws IOException { + try (InputStream inputStream = stream.createInputStream()) { + return inputStream.readAllBytes(); + } + } + + private static COSArray extractGlyphBoundingBox(PDType3Font font, PDType3CharProc charProc) { + if (charProc == null) { + return null; + } + COSStream stream = charProc.getCOSObject(); + if (stream != null) { + COSArray bboxArray = (COSArray) stream.getDictionaryObject(COSName.BBOX); + if (bboxArray != null && bboxArray.size() == 4) { + return bboxArray; + } + } + return font.getCOSObject().getCOSArray(COSName.BBOX); + } + + private static int resolveCharCode(PDType3Font font, String glyphName) { + if (glyphName == null || font.getEncoding() == null) { + return -1; + } + Encoding encoding = font.getEncoding(); + for (int code = 0; code <= 0xFF; code++) { + String name = encoding.getName(code); + if (glyphName.equals(name)) { + return code; + } + } + return -1; + } + + private static void updateMatrix(MessageDigest digest, Matrix matrix) { + if (matrix == null) { + updateInt(digest, -1); + return; + } + float[][] values = matrix.getValues(); + updateInt(digest, values.length); + for (float[] row : values) { + if (row == null) { + updateInt(digest, -1); + continue; + } + updateInt(digest, row.length); + for (float value : row) { + updateFloat(digest, value); + } + } + } + + private static void updateRectangle(MessageDigest digest, PDRectangle rectangle) { + if (rectangle == null) { + updateInt(digest, -1); + return; + } + updateFloat(digest, rectangle.getLowerLeftX()); + updateFloat(digest, rectangle.getLowerLeftY()); + updateFloat(digest, rectangle.getUpperRightX()); + updateFloat(digest, rectangle.getUpperRightY()); + } + + private static void updateRectangle(MessageDigest digest, COSArray array) { + if (array == null) { + updateInt(digest, -1); + return; + } + updateInt(digest, array.size()); + for (int i = 0; i < array.size(); i++) { + COSBase value = array.getObject(i); + if (value instanceof COSNumber number) { + updateFloat(digest, number.floatValue()); + } else { + updateFloat(digest, 0f); + } + } + } + + private static void updateString(MessageDigest digest, String value) { + if (value == null) { + updateInt(digest, -1); + return; + } + byte[] bytes = value.getBytes(java.nio.charset.StandardCharsets.UTF_8); + updateInt(digest, bytes.length); + digest.update(bytes); + } + + private static void updateInt(MessageDigest digest, int value) { + digest.update(ByteBuffer.allocate(Integer.BYTES).putInt(value).array()); + } + + private static void updateFloat(MessageDigest digest, float value) { + if (Float.isNaN(value) || Float.isInfinite(value)) { + value = 0f; + } + digest.update(ByteBuffer.allocate(Float.BYTES).putFloat(value).array()); + } + + private static MessageDigest newDigest() { + try { + return MessageDigest.getInstance("SHA-256"); + } catch (NoSuchAlgorithmException ex) { + throw new IllegalStateException("Missing SHA-256 MessageDigest", ex); + } + } + + private static String toHex(byte[] bytes) { + StringBuilder builder = new StringBuilder(bytes.length * 2); + for (byte value : bytes) { + builder.append(String.format(Locale.ROOT, "%02x", Byte.toUnsignedInt(value))); + } + return builder.toString(); + } +} diff --git a/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/Type3GlyphContext.java b/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/Type3GlyphContext.java new file mode 100644 index 000000000..082813cc3 --- /dev/null +++ b/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/Type3GlyphContext.java @@ -0,0 +1,38 @@ +package stirling.software.SPDF.service.pdfjson.type3; + +import java.io.IOException; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; + +import org.apache.pdfbox.pdmodel.font.PDType3Font; + +import stirling.software.SPDF.service.pdfjson.type3.model.Type3GlyphOutline; + +class Type3GlyphContext { + private final Type3ConversionRequest request; + private final Type3GlyphExtractor extractor; + private final AtomicReference> glyphs = new AtomicReference<>(); + + Type3GlyphContext(Type3ConversionRequest request, Type3GlyphExtractor extractor) { + this.request = request; + this.extractor = extractor; + } + + public List getGlyphs() throws IOException { + List cached = glyphs.get(); + if (cached == null) { + cached = + extractor.extractGlyphs( + request.getDocument(), + request.getFont(), + request.getFontId(), + request.getPageNumber()); + glyphs.compareAndSet(null, cached); + } + return cached; + } + + public PDType3Font getFont() { + return request.getFont(); + } +} diff --git a/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/Type3GlyphExtractor.java b/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/Type3GlyphExtractor.java new file mode 100644 index 000000000..b662f5683 --- /dev/null +++ b/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/Type3GlyphExtractor.java @@ -0,0 +1,126 @@ +package stirling.software.SPDF.service.pdfjson.type3; + +import java.awt.geom.GeneralPath; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import org.apache.pdfbox.cos.COSArray; +import org.apache.pdfbox.cos.COSDictionary; +import org.apache.pdfbox.cos.COSName; +import org.apache.pdfbox.cos.COSStream; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.common.PDRectangle; +import org.apache.pdfbox.pdmodel.font.PDType3CharProc; +import org.apache.pdfbox.pdmodel.font.PDType3Font; +import org.springframework.stereotype.Component; + +import lombok.extern.slf4j.Slf4j; + +import stirling.software.SPDF.service.pdfjson.type3.model.Type3GlyphOutline; + +@Slf4j +@Component +public class Type3GlyphExtractor { + + public List extractGlyphs( + PDDocument document, PDType3Font font, String fontId, int pageNumber) + throws IOException { + Objects.requireNonNull(font, "font"); + COSDictionary charProcs = + (COSDictionary) font.getCOSObject().getDictionaryObject(COSName.CHAR_PROCS); + if (charProcs == null || charProcs.size() == 0) { + return List.of(); + } + List outlines = new ArrayList<>(); + for (COSName glyphName : charProcs.keySet()) { + COSStream stream = + charProcs.getDictionaryObject(glyphName) instanceof COSStream cosStream + ? cosStream + : null; + if (stream == null) { + continue; + } + PDType3CharProc charProc = new PDType3CharProc(font, stream); + outlines.add(analyseGlyph(document, font, glyphName, charProc, fontId, pageNumber)); + } + return outlines; + } + + private Type3GlyphOutline analyseGlyph( + PDDocument document, + PDType3Font font, + COSName glyphName, + PDType3CharProc charProc, + String fontId, + int pageNumber) + throws IOException { + int code = resolveCharCode(font, glyphName.getName()); + float advanceWidth = 0f; + if (code >= 0) { + advanceWidth = font.getWidthFromFont(code); + } + + PDRectangle glyphBBox = extractGlyphBoundingBox(font, charProc); + PDRectangle bbox = font.getFontBBox(); + GlyphGraphicsExtractor extractor = + new GlyphGraphicsExtractor(new PDPage(bbox != null ? bbox : new PDRectangle())); + extractor.process(charProc); + GeneralPath outline = extractor.getAccumulatedPath(); + Integer unicodeValue = null; + if (code >= 0) { + String unicode = font.toUnicode(code); + if (unicode != null && !unicode.isEmpty()) { + unicodeValue = unicode.codePointAt(0); + } else { + unicodeValue = code; + } + } + return Type3GlyphOutline.builder() + .glyphName(glyphName.getName()) + .charCode(code) + .advanceWidth(advanceWidth) + .boundingBox(glyphBBox) + .outline(outline) + .hasFill(extractor.isSawFill()) + .hasStroke(extractor.isSawStroke()) + .hasImages(extractor.isSawImage()) + .hasText(extractor.isSawText()) + .hasShading(extractor.isSawShading()) + .warnings(extractor.getWarnings()) + .unicode(unicodeValue) + .build(); + } + + private PDRectangle extractGlyphBoundingBox(PDType3Font font, PDType3CharProc charProc) { + COSStream stream = charProc != null ? charProc.getCOSObject() : null; + if (stream != null) { + COSArray bboxArray = (COSArray) stream.getDictionaryObject(COSName.BBOX); + if (bboxArray != null && bboxArray.size() == 4) { + return new PDRectangle(bboxArray); + } + } + return font.getFontBBox(); + } + + private int resolveCharCode(PDType3Font font, String glyphName) { + if (glyphName == null || font.getEncoding() == null) { + return -1; + } + for (int code = 0; code <= 0xFF; code++) { + String name = font.getEncoding().getName(code); + if (glyphName.equals(name)) { + return code; + } + } + return -1; + } + + private static final class GlyphGraphicsExtractor extends Type3GraphicsEngine { + GlyphGraphicsExtractor(PDPage page) { + super(page); + } + } +} diff --git a/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/Type3GraphicsEngine.java b/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/Type3GraphicsEngine.java new file mode 100644 index 000000000..d4e3cd6e9 --- /dev/null +++ b/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/Type3GraphicsEngine.java @@ -0,0 +1,164 @@ +package stirling.software.SPDF.service.pdfjson.type3; + +import java.awt.geom.GeneralPath; +import java.awt.geom.Point2D; +import java.io.IOException; + +import org.apache.pdfbox.contentstream.PDFGraphicsStreamEngine; +import org.apache.pdfbox.contentstream.operator.Operator; +import org.apache.pdfbox.cos.COSName; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.font.PDFont; +import org.apache.pdfbox.pdmodel.font.PDType3CharProc; +import org.apache.pdfbox.pdmodel.graphics.image.PDImage; +import org.apache.pdfbox.util.Matrix; +import org.apache.pdfbox.util.Vector; + +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +class Type3GraphicsEngine extends PDFGraphicsStreamEngine { + + private final GeneralPath accumulatedPath = new GeneralPath(); + private final GeneralPath linePath = new GeneralPath(); + private final Point2D.Float currentPoint = new Point2D.Float(); + private boolean hasCurrentPoint; + @Getter private boolean sawStroke; + @Getter private boolean sawFill; + @Getter private boolean sawImage; + @Getter private boolean sawText; + @Getter private boolean sawShading; + @Getter private String warnings; + + protected Type3GraphicsEngine(PDPage page) { + super(page); + } + + public GeneralPath getAccumulatedPath() { + return (GeneralPath) accumulatedPath.clone(); + } + + public void process(PDType3CharProc charProc) throws IOException { + accumulatedPath.reset(); + linePath.reset(); + sawStroke = false; + sawFill = false; + sawImage = false; + sawText = false; + sawShading = false; + warnings = null; + if (charProc != null) { + processChildStream(charProc, getPage()); + } + } + + @Override + public void appendRectangle(Point2D p0, Point2D p1, Point2D p2, Point2D p3) throws IOException { + moveTo((float) p0.getX(), (float) p0.getY()); + lineTo((float) p1.getX(), (float) p1.getY()); + lineTo((float) p2.getX(), (float) p2.getY()); + lineTo((float) p3.getX(), (float) p3.getY()); + closePath(); + } + + @Override + public void drawImage(PDImage pdImage) throws IOException { + sawImage = true; + } + + @Override + public void shadingFill(COSName shadingName) throws IOException { + sawShading = true; + } + + @Override + public void strokePath() throws IOException { + accumulatedPath.append(linePath, false); + linePath.reset(); + sawStroke = true; + } + + @Override + public void fillPath(int windingRule) throws IOException { + linePath.setWindingRule( + windingRule == 0 ? GeneralPath.WIND_EVEN_ODD : GeneralPath.WIND_NON_ZERO); + accumulatedPath.append(linePath, false); + linePath.reset(); + sawFill = true; + } + + @Override + public void fillAndStrokePath(int windingRule) throws IOException { + fillPath(windingRule); + sawStroke = true; + } + + @Override + public void clip(int windingRule) throws IOException { + // ignore + } + + @Override + public void moveTo(float x, float y) throws IOException { + linePath.moveTo(x, y); + currentPoint.setLocation(x, y); + hasCurrentPoint = true; + } + + @Override + public void lineTo(float x, float y) throws IOException { + linePath.lineTo(x, y); + currentPoint.setLocation(x, y); + hasCurrentPoint = true; + } + + @Override + public void curveTo(float x1, float y1, float x2, float y2, float x3, float y3) + throws IOException { + linePath.curveTo(x1, y1, x2, y2, x3, y3); + currentPoint.setLocation(x3, y3); + hasCurrentPoint = true; + } + + @Override + public Point2D getCurrentPoint() throws IOException { + return hasCurrentPoint ? (Point2D) currentPoint.clone() : null; + } + + @Override + public void closePath() throws IOException { + linePath.closePath(); + } + + @Override + public void endPath() throws IOException { + linePath.reset(); + hasCurrentPoint = false; + } + + @Override + protected void showText(byte[] string) throws IOException { + sawText = true; + super.showText(string); + } + + @Override + protected void showFontGlyph( + Matrix textRenderingMatrix, PDFont font, int code, Vector displacement) + throws IOException { + sawText = true; + super.showFontGlyph(textRenderingMatrix, font, code, displacement); + } + + @Override + protected void processOperator( + Operator operator, java.util.List operands) + throws IOException { + if ("cm".equals(operator.getName())) { + warnings = + warnings == null ? "Encountered CTM concatenation" : warnings + "; CTM concat"; + } + super.processOperator(operator, operands); + } +} diff --git a/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/Type3LibraryStrategy.java b/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/Type3LibraryStrategy.java new file mode 100644 index 000000000..4385e5725 --- /dev/null +++ b/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/Type3LibraryStrategy.java @@ -0,0 +1,113 @@ +package stirling.software.SPDF.service.pdfjson.type3; + +import java.io.IOException; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import stirling.software.SPDF.model.json.PdfJsonFontConversionCandidate; +import stirling.software.SPDF.model.json.PdfJsonFontConversionStatus; +import stirling.software.SPDF.service.pdfjson.type3.library.Type3FontLibrary; +import stirling.software.SPDF.service.pdfjson.type3.library.Type3FontLibraryEntry; +import stirling.software.SPDF.service.pdfjson.type3.library.Type3FontLibraryMatch; +import stirling.software.SPDF.service.pdfjson.type3.library.Type3FontLibraryPayload; + +@Slf4j +@Component +@Order(0) +@RequiredArgsConstructor +public class Type3LibraryStrategy implements Type3ConversionStrategy { + + private final Type3FontLibrary fontLibrary; + + @Value("${stirling.pdf.json.type3.library.enabled:true}") + private boolean enabled; + + @Override + public String getId() { + return "type3-library"; + } + + @Override + public String getLabel() { + return "Type3 Font Library"; + } + + @Override + public boolean isAvailable() { + return enabled && fontLibrary != null && fontLibrary.isLoaded(); + } + + @Override + public PdfJsonFontConversionCandidate convert( + Type3ConversionRequest request, Type3GlyphContext context) throws IOException { + if (request == null || request.getFont() == null) { + return PdfJsonFontConversionCandidate.builder() + .strategyId(getId()) + .strategyLabel(getLabel()) + .status(PdfJsonFontConversionStatus.FAILURE) + .message("No font supplied") + .build(); + } + if (!isAvailable()) { + return PdfJsonFontConversionCandidate.builder() + .strategyId(getId()) + .strategyLabel(getLabel()) + .status(PdfJsonFontConversionStatus.SKIPPED) + .message("Library disabled") + .build(); + } + + Type3FontLibraryMatch match = fontLibrary.match(request.getFont(), request.getFontUid()); + if (match == null || match.getEntry() == null) { + return PdfJsonFontConversionCandidate.builder() + .strategyId(getId()) + .strategyLabel(getLabel()) + .status(PdfJsonFontConversionStatus.UNSUPPORTED) + .message("No library entry found") + .build(); + } + + Type3FontLibraryEntry entry = match.getEntry(); + if (!entry.hasAnyPayload()) { + return PdfJsonFontConversionCandidate.builder() + .strategyId(getId()) + .strategyLabel(getLabel()) + .status(PdfJsonFontConversionStatus.FAILURE) + .message("Library entry has no payloads") + .build(); + } + + String message = + String.format( + "Matched %s via %s", + entry.getLabel(), + match.getMatchType() != null ? match.getMatchType() : "alias"); + + return PdfJsonFontConversionCandidate.builder() + .strategyId(getId()) + .strategyLabel(getLabel()) + .status(PdfJsonFontConversionStatus.SUCCESS) + .program(toBase64(entry.getProgram())) + .programFormat(toFormat(entry.getProgram())) + .webProgram(toBase64(entry.getWebProgram())) + .webProgramFormat(toFormat(entry.getWebProgram())) + .pdfProgram(toBase64(entry.getPdfProgram())) + .pdfProgramFormat(toFormat(entry.getPdfProgram())) + .glyphCoverage(entry.getGlyphCoverage()) + .message(message) + .build(); + } + + private String toBase64(Type3FontLibraryPayload payload) { + return payload != null ? payload.getBase64() : null; + } + + private String toFormat(Type3FontLibraryPayload payload) { + return payload != null ? payload.getFormat() : null; + } +} diff --git a/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/library/Type3FontLibrary.java b/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/library/Type3FontLibrary.java new file mode 100644 index 000000000..32a6abec2 --- /dev/null +++ b/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/library/Type3FontLibrary.java @@ -0,0 +1,299 @@ +package stirling.software.SPDF.service.pdfjson.type3.library; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Base64; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +import org.apache.pdfbox.cos.COSName; +import org.apache.pdfbox.pdmodel.font.PDType3Font; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import stirling.software.SPDF.service.pdfjson.type3.Type3FontSignatureCalculator; + +@Slf4j +@Component +@RequiredArgsConstructor +public class Type3FontLibrary { + + private final ObjectMapper objectMapper; + private final ResourceLoader resourceLoader; + + @Value("${stirling.pdf.json.type3.library.index:classpath:/type3/library/index.json}") + private String indexLocation; + + private final Map signatureIndex = new ConcurrentHashMap<>(); + private final Map aliasIndex = new ConcurrentHashMap<>(); + private List entries = List.of(); + + @jakarta.annotation.PostConstruct + void initialise() { + Resource resource = resourceLoader.getResource(indexLocation); + if (!resource.exists()) { + log.info("[TYPE3] Library index {} not found; Type3 library disabled", indexLocation); + entries = List.of(); + return; + } + try (InputStream inputStream = resource.getInputStream()) { + List rawEntries = + objectMapper.readValue(inputStream, new TypeReference>() {}); + List loaded = new ArrayList<>(); + for (RawEntry rawEntry : rawEntries) { + Type3FontLibraryEntry entry = toEntry(rawEntry); + if (entry != null && entry.hasAnyPayload()) { + loaded.add(entry); + } + } + entries = Collections.unmodifiableList(loaded); + signatureIndex.clear(); + aliasIndex.clear(); + + for (Type3FontLibraryEntry entry : entries) { + if (entry.getSignatures() != null) { + for (String signature : entry.getSignatures()) { + if (signature == null) { + continue; + } + String key = signature.toLowerCase(Locale.ROOT); + signatureIndex.putIfAbsent(key, entry); + } + } + if (entry.getAliases() != null) { + for (String alias : entry.getAliases()) { + String normalized = normalizeAlias(alias); + if (normalized != null) { + aliasIndex.putIfAbsent(normalized, entry); + } + } + } + } + log.info( + "[TYPE3] Loaded {} Type3 library entries (signatures={}, aliases={}) from {}", + entries.size(), + signatureIndex.size(), + aliasIndex.size(), + indexLocation); + } catch (IOException ex) { + log.warn( + "[TYPE3] Failed to load Type3 library index {}: {}", + indexLocation, + ex.getMessage(), + ex); + entries = List.of(); + signatureIndex.clear(); + aliasIndex.clear(); + } + } + + public boolean isLoaded() { + return !entries.isEmpty(); + } + + public Type3FontLibraryMatch match(PDType3Font font, String fontUid) throws IOException { + if (font == null || entries.isEmpty()) { + return null; + } + String signature = Type3FontSignatureCalculator.computeSignature(font); + if (signature != null) { + Type3FontLibraryEntry entry = signatureIndex.get(signature.toLowerCase(Locale.ROOT)); + if (entry != null) { + log.debug( + "[TYPE3] Matched Type3 font {} to library entry {} via signature {}", + fontUid, + entry.getId(), + signature); + return Type3FontLibraryMatch.builder() + .entry(entry) + .matchType("signature") + .signature(signature) + .build(); + } + log.debug( + "[TYPE3] No library entry for signature {} (font {})", + signature, + fontUid != null ? fontUid : font.getName()); + } + + String aliasKey = normalizeAlias(resolveBaseFontName(font)); + if (aliasKey != null) { + Type3FontLibraryEntry entry = aliasIndex.get(aliasKey); + if (entry != null) { + log.debug( + "[TYPE3] Matched Type3 font {} to library entry {} via alias {}", + fontUid, + entry.getId(), + aliasKey); + return Type3FontLibraryMatch.builder() + .entry(entry) + .matchType("alias:" + aliasKey) + .signature(signature) + .build(); + } + } + + if (signature != null) { + log.debug( + "[TYPE3] Library had no alias match for signature {} (font {})", + signature, + fontUid != null ? fontUid : font.getName()); + } + return null; + } + + private Type3FontLibraryEntry toEntry(RawEntry rawEntry) { + if (rawEntry == null || rawEntry.id == null) { + return null; + } + try { + Type3FontLibraryEntry.Type3FontLibraryEntryBuilder builder = + Type3FontLibraryEntry.builder() + .id(rawEntry.id) + .label(rawEntry.label != null ? rawEntry.label : rawEntry.id) + .signatures(normalizeList(rawEntry.signatures)) + .aliases(normalizeList(rawEntry.aliases)) + .program(loadPayload(rawEntry.program)) + .webProgram(loadPayload(rawEntry.webProgram)) + .pdfProgram(loadPayload(rawEntry.pdfProgram)) + .source(rawEntry.source); + if (rawEntry.glyphCoverage != null && !rawEntry.glyphCoverage.isEmpty()) { + for (Integer codePoint : rawEntry.glyphCoverage) { + if (codePoint != null) { + builder.glyphCode(codePoint); + } + } + } + return builder.build(); + } catch (IOException ex) { + log.warn( + "[TYPE3] Failed to load Type3 library entry {}: {}", + rawEntry.id, + ex.getMessage()); + return null; + } + } + + private Type3FontLibraryPayload loadPayload(RawPayload payload) throws IOException { + if (payload == null) { + return null; + } + byte[] data = null; + if (payload.base64 != null && !payload.base64.isBlank()) { + try { + data = Base64.getDecoder().decode(payload.base64); + } catch (IllegalArgumentException ex) { + log.warn("[TYPE3] Invalid base64 payload in Type3 library: {}", ex.getMessage()); + } + } else if (payload.resource != null && !payload.resource.isBlank()) { + data = loadResourceBytes(payload.resource); + } + if (data == null || data.length == 0) { + return null; + } + String base64 = Base64.getEncoder().encodeToString(data); + return new Type3FontLibraryPayload(base64, normalizeFormat(payload.format)); + } + + private byte[] loadResourceBytes(String location) throws IOException { + String resolved = resolveLocation(location); + Resource resource = resourceLoader.getResource(resolved); + if (!resource.exists()) { + throw new IOException("Resource not found: " + resolved); + } + try (InputStream inputStream = resource.getInputStream()) { + return inputStream.readAllBytes(); + } + } + + private String resolveLocation(String location) { + if (location == null || location.isBlank()) { + return location; + } + if (location.contains(":")) { + return location; + } + if (location.startsWith("/")) { + return "classpath:" + location; + } + return "classpath:/" + location; + } + + private List normalizeList(List values) { + if (values == null || values.isEmpty()) { + return List.of(); + } + return values.stream() + .filter(Objects::nonNull) + .map(String::trim) + .filter(s -> !s.isEmpty()) + .collect(Collectors.toList()); + } + + private String normalizeAlias(String alias) { + if (alias == null) { + return null; + } + String value = alias.trim(); + int plus = value.indexOf('+'); + if (plus >= 0 && plus < value.length() - 1) { + value = value.substring(plus + 1); + } + return value.isEmpty() ? null : value.toLowerCase(Locale.ROOT); + } + + private String normalizeFormat(String format) { + if (format == null) { + return null; + } + return format.trim().toLowerCase(Locale.ROOT); + } + + private String resolveBaseFontName(PDType3Font font) { + if (font == null) { + return null; + } + String baseName = null; + try { + baseName = font.getName(); + } catch (Exception ignored) { + // Some Type3 fonts throw when resolving names; fall back to COS dictionary. + } + if (baseName == null && font.getCOSObject() != null) { + baseName = font.getCOSObject().getNameAsString(COSName.BASE_FONT); + } + return baseName; + } + + private static final class RawEntry { + public String id; + public String label; + public List signatures; + public List aliases; + public RawPayload program; + public RawPayload webProgram; + public RawPayload pdfProgram; + public List glyphCoverage; + public String source; + } + + private static final class RawPayload { + public String resource; + public String format; + public String base64; + } +} diff --git a/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/library/Type3FontLibraryEntry.java b/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/library/Type3FontLibraryEntry.java new file mode 100644 index 000000000..6163998cf --- /dev/null +++ b/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/library/Type3FontLibraryEntry.java @@ -0,0 +1,30 @@ +package stirling.software.SPDF.service.pdfjson.type3.library; + +import java.util.List; + +import lombok.Builder; +import lombok.Singular; +import lombok.Value; + +@Value +@Builder +public class Type3FontLibraryEntry { + String id; + String label; + @Singular List signatures; + @Singular List aliases; + Type3FontLibraryPayload program; + Type3FontLibraryPayload webProgram; + Type3FontLibraryPayload pdfProgram; + + @Singular("glyphCode") + List glyphCoverage; + + String source; + + public boolean hasAnyPayload() { + return (program != null && program.hasPayload()) + || (webProgram != null && webProgram.hasPayload()) + || (pdfProgram != null && pdfProgram.hasPayload()); + } +} diff --git a/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/library/Type3FontLibraryMatch.java b/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/library/Type3FontLibraryMatch.java new file mode 100644 index 000000000..9f1255b2c --- /dev/null +++ b/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/library/Type3FontLibraryMatch.java @@ -0,0 +1,12 @@ +package stirling.software.SPDF.service.pdfjson.type3.library; + +import lombok.Builder; +import lombok.Value; + +@Value +@Builder +public class Type3FontLibraryMatch { + Type3FontLibraryEntry entry; + String matchType; + String signature; +} diff --git a/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/library/Type3FontLibraryPayload.java b/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/library/Type3FontLibraryPayload.java new file mode 100644 index 000000000..45f7a3d99 --- /dev/null +++ b/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/library/Type3FontLibraryPayload.java @@ -0,0 +1,13 @@ +package stirling.software.SPDF.service.pdfjson.type3.library; + +import lombok.Value; + +@Value +public class Type3FontLibraryPayload { + String base64; + String format; + + public boolean hasPayload() { + return base64 != null && !base64.isBlank(); + } +} diff --git a/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/model/Type3GlyphOutline.java b/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/model/Type3GlyphOutline.java new file mode 100644 index 000000000..32bbe4f83 --- /dev/null +++ b/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/model/Type3GlyphOutline.java @@ -0,0 +1,25 @@ +package stirling.software.SPDF.service.pdfjson.type3.model; + +import java.awt.geom.GeneralPath; + +import org.apache.pdfbox.pdmodel.common.PDRectangle; + +import lombok.Builder; +import lombok.Value; + +@Value +@Builder +public class Type3GlyphOutline { + String glyphName; + int charCode; + float advanceWidth; + PDRectangle boundingBox; + GeneralPath outline; + boolean hasStroke; + boolean hasFill; + boolean hasImages; + boolean hasText; + boolean hasShading; + String warnings; + Integer unicode; +} diff --git a/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/tool/Type3SignatureTool.java b/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/tool/Type3SignatureTool.java new file mode 100644 index 000000000..968717411 --- /dev/null +++ b/app/proprietary/src/main/java/stirling/software/SPDF/service/pdfjson/type3/tool/Type3SignatureTool.java @@ -0,0 +1,299 @@ +package stirling.software.SPDF.service.pdfjson.type3.tool; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Deque; +import java.util.IdentityHashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +import org.apache.pdfbox.Loader; +import org.apache.pdfbox.cos.COSName; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.PDResources; +import org.apache.pdfbox.pdmodel.font.PDFont; +import org.apache.pdfbox.pdmodel.font.PDType3Font; +import org.apache.pdfbox.pdmodel.graphics.PDXObject; +import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; +import com.fasterxml.jackson.databind.SerializationFeature; + +import stirling.software.SPDF.service.pdfjson.type3.Type3FontSignatureCalculator; +import stirling.software.SPDF.service.pdfjson.type3.Type3GlyphExtractor; +import stirling.software.SPDF.service.pdfjson.type3.model.Type3GlyphOutline; + +/** + * Small CLI helper that scans a PDF for Type3 fonts, computes their signatures, and optionally + * emits JSON describing the glyph coverage. This allows Type3 library entries to be added without + * digging through backend logs. + * + *

Usage: + * + *

+ * ./gradlew :proprietary:type3SignatureTool --args="--pdf path/to/sample.pdf --output type3.json --pretty"
+ * 
+ */ +public final class Type3SignatureTool { + + private static final ObjectMapper OBJECT_MAPPER = + new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT); + + private Type3SignatureTool() {} + + public static void main(String[] args) throws Exception { + Arguments arguments = Arguments.parse(args); + if (arguments.showHelp || arguments.pdf == null) { + printUsage(); + return; + } + + Path pdfPath = arguments.pdf.toAbsolutePath(); + if (!Files.exists(pdfPath)) { + throw new IOException("PDF not found: " + pdfPath); + } + + List> fonts; + try (PDDocument document = Loader.loadPDF(pdfPath.toFile())) { + fonts = collectType3Fonts(document); + } + + Map output = new LinkedHashMap<>(); + output.put("pdf", pdfPath.toString()); + output.put("fonts", fonts); + ObjectWriter writer = + arguments.pretty + ? OBJECT_MAPPER.writerWithDefaultPrettyPrinter() + : OBJECT_MAPPER.writer(); + if (arguments.output != null) { + Path parent = arguments.output.toAbsolutePath().getParent(); + if (parent != null) { + Files.createDirectories(parent); + } + writer.writeValue(arguments.output.toFile(), output); + verifyOutput(arguments.output, fonts.size()); + } else { + writer.writeValue(System.out, output); + } + } + + private static List> collectType3Fonts(PDDocument document) + throws IOException { + if (document == null || document.getNumberOfPages() == 0) { + return List.of(); + } + List> fonts = new ArrayList<>(); + Type3GlyphExtractor glyphExtractor = new Type3GlyphExtractor(); + Set visited = Collections.newSetFromMap(new IdentityHashMap<>()); + + for (int pageIndex = 0; pageIndex < document.getNumberOfPages(); pageIndex++) { + PDPage page = document.getPage(pageIndex); + PDResources resources = page.getResources(); + if (resources == null) { + continue; + } + scanResources(document, pageIndex + 1, resources, glyphExtractor, visited, fonts); + } + return fonts; + } + + private static void scanResources( + PDDocument document, + int pageNumber, + PDResources resources, + Type3GlyphExtractor glyphExtractor, + Set visited, + List> fonts) + throws IOException { + if (resources == null) { + return; + } + + for (COSName name : resources.getFontNames()) { + PDFont font = resources.getFont(name); + if (!(font instanceof PDType3Font type3Font)) { + continue; + } + Object cosObject = type3Font.getCOSObject(); + if (cosObject != null && !visited.add(cosObject)) { + continue; + } + fonts.add( + describeFont(document, pageNumber, name.getName(), type3Font, glyphExtractor)); + } + + Deque embedded = new ArrayDeque<>(); + for (COSName name : resources.getXObjectNames()) { + PDXObject xobject = resources.getXObject(name); + if (xobject instanceof PDFormXObject form && form.getResources() != null) { + embedded.add(form.getResources()); + } + } + while (!embedded.isEmpty()) { + scanResources(document, pageNumber, embedded.pop(), glyphExtractor, visited, fonts); + } + } + + private static Map describeFont( + PDDocument document, + int pageNumber, + String fontId, + PDType3Font font, + Type3GlyphExtractor glyphExtractor) + throws IOException { + Map payload = new LinkedHashMap<>(); + payload.put("pageNumber", pageNumber); + payload.put("fontId", fontId); + payload.put("baseName", safeFontName(font)); + payload.put("alias", normalizeAlias(safeFontName(font))); + payload.put("encoding", resolveEncoding(font)); + payload.put("signature", Type3FontSignatureCalculator.computeSignature(font)); + + List glyphs = + glyphExtractor.extractGlyphs(document, font, fontId, pageNumber); + payload.put("glyphCount", glyphs != null ? glyphs.size() : 0); + + Set coverage = new TreeSet<>(); + if (glyphs != null) { + for (Type3GlyphOutline glyph : glyphs) { + if (glyph == null) { + continue; + } + if (glyph.getUnicode() != null) { + coverage.add(glyph.getUnicode()); + } else if (glyph.getCharCode() >= 0) { + coverage.add(0xF000 | (glyph.getCharCode() & 0xFF)); + } + } + List> warnings = new ArrayList<>(); + for (Type3GlyphOutline glyph : glyphs) { + if (glyph != null && glyph.getWarnings() != null) { + Map warning = new LinkedHashMap<>(); + warning.put("glyphName", glyph.getGlyphName()); + warning.put("message", glyph.getWarnings()); + warnings.add(warning); + } + } + if (!warnings.isEmpty()) { + payload.put("warnings", warnings); + } + } + if (!coverage.isEmpty()) { + payload.put("glyphCoverage", new ArrayList<>(coverage)); + } + return payload; + } + + private static void verifyOutput(Path output, int fontCount) throws IOException { + Path absolute = output.toAbsolutePath(); + if (!Files.exists(absolute)) { + throw new IOException("Expected output file not found: " + absolute); + } + long size = Files.size(absolute); + if (size == 0) { + throw new IOException("Output file is empty: " + absolute); + } + System.out.println( + "Wrote " + fontCount + " fonts to " + absolute + " (" + size + " bytes, verified)"); + } + + private static String resolveEncoding(PDType3Font font) { + if (font == null || font.getEncoding() == null) { + return null; + } + Object encoding = font.getCOSObject().getDictionaryObject(COSName.ENCODING); + return encoding != null + ? encoding.toString() + : font.getEncoding().getClass().getSimpleName(); + } + + private static String safeFontName(PDType3Font font) { + if (font == null) { + return null; + } + try { + if (font.getName() != null) { + return font.getName(); + } + } catch (Exception ignored) { + // ignore + } + if (font.getCOSObject() != null) { + return font.getCOSObject().getNameAsString(COSName.BASE_FONT); + } + return null; + } + + private static String normalizeAlias(String name) { + if (name == null) { + return null; + } + int plus = name.indexOf('+'); + String normalized = plus >= 0 ? name.substring(plus + 1) : name; + normalized = normalized.trim(); + return normalized.isEmpty() ? null : normalized.toLowerCase(Locale.ROOT); + } + + private static void printUsage() { + System.out.println( + """ + Type3SignatureTool - dump Type3 font signatures for library building + Usage: + --pdf Input PDF to analyse (required) + --output Optional output file (defaults to stdout) + --pretty Pretty-print JSON output + --help Show this help + + Example: + ./gradlew :proprietary:type3SignatureTool --args="--pdf samples/foo.pdf --output foo.json --pretty" + """); + } + + private static final class Arguments { + private final Path pdf; + private final Path output; + private final boolean pretty; + private final boolean showHelp; + + private Arguments(Path pdf, Path output, boolean pretty, boolean showHelp) { + this.pdf = pdf; + this.output = output; + this.pretty = pretty; + this.showHelp = showHelp; + } + + static Arguments parse(String[] args) { + if (args == null || args.length == 0) { + return new Arguments(null, null, true, true); + } + Path pdf = null; + Path output = null; + boolean pretty = false; + boolean showHelp = false; + for (int i = 0; i < args.length; i++) { + String arg = args[i]; + if ("--pdf".equals(arg) && i + 1 < args.length) { + pdf = Paths.get(args[++i]); + } else if ("--output".equals(arg) && i + 1 < args.length) { + output = Paths.get(args[++i]); + } else if ("--pretty".equals(arg)) { + pretty = true; + } else if ("--help".equals(arg) || "-h".equals(arg)) { + showHelp = true; + } + } + return new Arguments(pdf, output, pretty, showHelp); + } + } +} diff --git a/docs/pdf_json_type3_fonts.md b/docs/pdf_json_type3_fonts.md new file mode 100644 index 000000000..8c72212e7 --- /dev/null +++ b/docs/pdf_json_type3_fonts.md @@ -0,0 +1,443 @@ +# PDF JSON Type3 Font System + +## Overview + +The PDF JSON editor needs to handle **Type3 fonts** - custom vector fonts embedded in PDFs that don't follow standard font formats. These are common in PDFs generated by Matplotlib, LaTeX, scientific papers, and presentation tools. + +When converting a PDF to JSON for editing, Type3 fonts present two challenges: +1. **No Unicode mapping** - Character codes don't map to standard Unicode characters +2. **Custom glyphs** - Each font contains vector drawing instructions unique to that PDF + +This document explains how the system handles Type3 fonts during the full PDF → JSON → PDF workflow. + +--- + +## Architecture Flow + +### PDF → JSON Conversion Flow + +``` +┌─────────────┐ +│ Input PDF │ +└──────┬──────┘ + │ + ▼ +┌─────────────────────────────────┐ +│ PDFBox Parsing │ +│ - Extract text positions │ +│ - Identify fonts │ +└──────┬──────────────────────────┘ + │ + ▼ +┌─────────────────────────────────┐ +│ Font Detection │ +│ Is this a Type3 font? │ +└──────┬──────────────────────────┘ + │ + ├─── YES (Type3) ───────────────────────┐ + │ │ + ▼ ▼ +┌──────────────────────────┐ ┌──────────────────────────────┐ +│ Type3FontConversion │ │ Extract Type3 Metadata │ +│ Service │ │ - Glyph outlines (paths) │ +│ │ │ - Character codes │ +│ 1. Calculate signature │ │ - Font matrix │ +│ 2. Match against │ │ - Bounding boxes │ +│ library │ └──────────────────────────────┘ +└──────┬───────────────────┘ + │ + ▼ +┌──────────────────────────────────────┐ +│ Library Match? │ +└──────┬───────────────────────────────┘ + │ + ├─── FOUND ─────────────────────┐ + │ │ + │ ▼ + │ ┌─────────────────────────────┐ + │ │ Load Pre-built Font │ + │ │ - TTF/OTF from library │ + │ │ - Full Unicode mappings │ + │ │ - Web + PDF payloads │ + │ └──────────┬──────────────────┘ + │ │ + ├─── NOT FOUND ──────────────────┘ + │ + ▼ +┌──────────────────────────────────────┐ +│ Store Type3 Metadata in JSON │ +│ - type3Glyphs: [{charCode, unicode, │ +│ glyphName, outline}] │ +│ - Original char codes preserved │ +│ - Font marked as Type3 │ +└──────┬───────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────┐ +│ PdfJsonDocument Output │ +│ { │ +│ fonts: [{ │ +│ id: "F1", │ +│ baseName: "ABCD+DejaVuSans", │ +│ subtype: "Type3", │ +│ type3Glyphs: [...], │ +│ conversionCandidates: [{ │ +│ strategyId: "type3-library", │ +│ status: "SUCCESS", │ +│ pdfProgram: "base64...", │ +│ glyphCoverage: [65,66,67...] │ +│ }] │ +│ }], │ +│ textElements: [{ │ +│ text: "Hello", │ +│ fontId: "F1", │ +│ charCodes: [72,101,108,108,111]│ +│ }] │ +│ } │ +└─────────────────────────────────────┘ +``` + +### JSON → PDF Conversion Flow + +``` +┌─────────────────────────────────────┐ +│ Input JSON (edited by user) │ +└──────┬──────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────┐ +│ Load Fonts from JSON │ +│ - Check for conversionCandidates │ +│ - Check for type3Glyphs │ +└──────┬──────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────┐ +│ Has conversionCandidates? │ +└──────┬──────────────────────────────┘ + │ + ├─── YES (Library Match) ───────┐ + │ │ + │ ▼ + │ ┌─────────────────────────────┐ + │ │ Load from Candidate │ + │ │ 1. Decode base64 pdfProgram│ + │ │ 2. Create PDType0Font │ + │ │ 3. Embed in new PDF │ + │ └──────────┬──────────────────┘ + │ │ + ├─── NO (Use Type3 Metadata) ───┘ + │ + ▼ +┌──────────────────────────────────────┐ +│ Text Rendering Strategy │ +│ - Normalized Type3 fonts: │ +│ Use original text (font has │ +│ Unicode mappings) │ +│ │ +│ - Actual Type3 fonts: │ +│ Use charCodes array │ +│ │ +│ - Other fonts: │ +│ Standard encoding │ +└──────┬───────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────┐ +│ Generate PDF Content Streams │ +│ - Set font: /F1 12 Tf │ +│ - Position text: x y Td │ +│ - Show text: (encoded) Tj │ +└──────┬──────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────┐ +│ Output PDF │ +│ - Fonts embedded correctly │ +│ - Text renders with proper glyphs │ +│ - Preserves visual appearance │ +└─────────────────────────────────────┘ +``` + +--- + +## Key Components + +### 1. Type3 Font Signature Matching + +**Location:** `Type3FontSignatureCalculator.java` + +**Purpose:** Creates a unique fingerprint of a Type3 font based on its glyph shapes. + +**How it works:** +```java +// 1. Extract glyph outlines from Type3 font +List glyphs = extractor.extractGlyphs(document, font, fontId, pageNumber); + +// 2. Normalize and hash the shapes +String signature = calculator.calculateSignature(glyphs); +// Result: "sha256:2be58b6ef1e29a83b8634d70b9e32c37a15dea2e..." + +// 3. Look up in library +Optional match = library.findBySignature(signature); +``` + +**Signature includes:** +- Glyph outline paths (curves, lines) +- Glyph bounding boxes +- Advance widths +- Character code mappings + +### 2. Type3 Font Library + +**Location:** `app/core/src/main/resources/type3/library/` + +**Structure:** +``` +type3/library/ +├── index.json # Font metadata and signatures +├── catalogue.json # Quick lookup of common fonts +└── fonts/ + ├── dejavu/ + │ ├── DejaVuSans.ttf + │ ├── DejaVuSans-Bold.ttf + │ └── DejaVuSans-Oblique.ttf + ├── cm/ # Computer Modern (LaTeX) + │ ├── cmr10.ttf + │ ├── cmmi10.ttf + │ └── cmsy10.ttf + ├── stix/ # Scientific symbols + │ └── STIXSizeThreeSym-Regular.otf + └── scp/ # Monospace + └── SauceCodeProNerdFont-Regular.ttf +``` + +**index.json format:** +```json +[ + { + "id": "dejavu-sans-bold", + "label": "DejaVu Sans Bold", + "aliases": [ + "DejaVuSans-Bold", + "EVICAO+DejaVuSans-Bold", + "dejavusans-bold" + ], + "signatures": [ + "sha256:a1b2c3d4...", + "sha256:e5f6g7h8..." + ], + "pdfProgram": { + "resource": "type3/library/fonts/dejavu/DejaVuSans-Bold.ttf", + "format": "ttf" + }, + "glyphCoverage": [32, 33, 65, 66, 67, ...], + "source": "DejaVu Fonts 2.37" + } +] +``` + +### 3. Normalized vs Actual Type3 Fonts + +The system handles two types of Type3 fonts differently: + +**Normalized Type3 Fonts:** +- Original PDF has Type3 font +- Matched against library +- Replaced with standard TTF/OTF +- Font object is `PDType0Font` (not `PDType3Font`) +- Has proper Unicode mappings + +**Actual Type3 Fonts:** +- Original PDF has Type3 font +- No library match found +- Keeps Type3 glyph data in JSON +- Font object is `PDType3Font` +- Uses character codes instead of Unicode + +**Rendering logic (PdfJsonConversionService.java:2411-2463):** +```java +boolean isNormalizedType3 = !(run.font() instanceof PDType3Font) + && runFontModel != null + && runFontModel.getType3Glyphs() != null + && !runFontModel.getType3Glyphs().isEmpty(); + +if (isNormalizedType3) { + // Font has Unicode mappings, use text directly + contentStream.showText(run.text()); +} else { + // Use raw byte encoding (for Type3 or other fonts) + byte[] encoded = encodeTextWithFont(run.font(), fontModel, run.text(), charCodes); + contentStream.showText(new String(encoded, StandardCharsets.ISO_8859_1)); +} +``` + +### 4. Character Code Preservation + +**Why needed:** Type3 fonts often lack ToUnicode mappings. We preserve the original character codes so text can be reconstructed. + +**Storage in JSON:** +```json +{ + "text": "Hello", + "fontId": "F1", + "charCodes": [72, 101, 108, 108, 111] +} +``` + +**Extraction (PDF → JSON):** +```java +// TextCollectingStripper.java:4431-4443 +if (pdfont instanceof PDType3Font) { + int[] codes = position.getCharacterCodes(); + if (codes != null && codes.length > 0) { + element.setCharCodes(Arrays.stream(codes) + .boxed() + .collect(Collectors.toList())); + } +} +``` + +### 5. Font Embedding Strategies + +When converting JSON → PDF, fonts are embedded based on their type: + +| Font Type | Strategy | Implementation | +|-----------|----------|----------------| +| **Normalized Type3** | Load TTF/OTF from library, embed as PDType0Font | `conversionCandidates[0].pdfProgram` | +| **Standard fonts** | Use system fonts or embedded fonts from original | PDFBox standard loading | +| **CFF/Type1C fonts** | Wrap as OpenType-CFF for browser compatibility | Optional Python converter | +| **Actual Type3** | Keep original Type3 definition | Preserve from original PDF | + +--- + +## Configuration + +**settings.yml:** +```yaml +processing: + pdf-json: + fonts: + type3: + library: + enabled: true + index: classpath:/type3/library/index.json +``` + +**Environment variables:** +```bash +# Disable Type3 library matching +STIRLING_PDF_JSON_TYPE3_LIBRARY_ENABLED=false + +# Use custom library +STIRLING_PDF_JSON_TYPE3_LIBRARY_INDEX=file:/path/to/custom/index.json +``` + +--- + +## Debugging + +### View Type3 Font Information + +**Backend logs** show signature matching: +``` +[TYPE3] Strategy type3-library finished with status SUCCESS + (message: Matched DejaVu Sans Bold via alias:dejavusans-bold) + for font 1:F2 + +[TYPE3-RUNTIME] Loading library font F2 WITHOUT subsetting + (full glyph set) from candidate:type3-library:pdfProgram +``` + +### Check JSON Output + +Look for `type3Glyphs` in font definitions: +```json +{ + "id": "F1", + "baseName": "BMQQDV+DejaVuSans", + "subtype": "Type3", + "type3Glyphs": [ + { + "charCode": 65, + "glyphName": "A", + "unicode": 65, + "advanceWidth": 684, + "bbox": [0, 0, 684, 729], + "outline": "M 72 0 L ..." + } + ] +} +``` + +### Test Signature Calculation + +Use the CLI tool to analyze any PDF: +```bash +./gradlew :proprietary:type3SignatureTool \ + --args="--pdf sample.pdf --output analysis.json --pretty" +``` + +Output shows all Type3 fonts with their signatures and glyph coverage. + +--- + +## Performance Considerations + +### Memory Management + +- **Type3 glyph data** can be large (detailed vector paths) +- **Font subsetting** not used for library fonts (full glyph set loaded) +- **Caching:** Library fonts are loaded once and cached per conversion + +### File Size Impact + +- **JSON size:** Type3 glyph data adds ~5-50KB per font +- **PDF size:** Embedding TTF/OTF fonts adds ~50-500KB per font +- **Optimization:** Use library matching to avoid storing raw Type3 data + +--- + +## Limitations + +1. **Library coverage:** Only common Type3 fonts are in the library + - Matplotlib (DejaVu Sans family) + - LaTeX (Computer Modern) + - STIX Math symbols + +2. **Glyph accuracy:** Signature matching assumes exact glyph shapes + - Slight variations may not match + - Subset fonts may have different signatures + +3. **Unicode mapping:** Unmatched Type3 fonts lose Unicode text + - Character codes preserved but not searchable + - Copy/paste may not work correctly + +4. **No runtime synthesis:** Unlike earlier designs, no attempt to convert Type3 to TTF at runtime + - All conversions must be pre-built in library + - Unknown Type3 fonts keep their Type3 definition + +--- + +## Related Files + +### Backend (Java) +- `PdfJsonConversionService.java` - Main conversion logic +- `Type3FontConversionService.java` - Signature calculation and matching +- `Type3FontLibrary.java` - Library loading and lookup +- `Type3GlyphExtractor.java` - Extract glyph data from Type3 fonts +- `Type3FontSignatureCalculator.java` - Create font fingerprints +- `PdfJsonFontType3Glyph.java` - Model for Type3 glyph data + +### Frontend (TypeScript) +- `pdfJsonEditorTypes.ts` - Type definitions for JSON structure +- `pdfJsonEditorUtils.ts` - Font handling utilities + +### Resources +- `type3/library/index.json` - Font library metadata +- `type3/library/fonts/` - Actual font files (TTF/OTF) +- `settings.yml.template` - Configuration options + +### Documentation +- `pdf_text_edit_flow.md` - Overall text editing architecture +- `type3_fallback_plan.md` - Original design and planning diff --git a/docs/pdf_text_edit_flow.md b/docs/pdf_text_edit_flow.md new file mode 100644 index 000000000..e9ccae243 --- /dev/null +++ b/docs/pdf_text_edit_flow.md @@ -0,0 +1,50 @@ +# PDF Text Edit Flow + +This high-level diagram shows every major component involved when a user edits text inside a PDF via the JSON editor. It highlights where fonts (especially Type3) are captured, matched against the library, and re-applied during export. + +```mermaid +flowchart TD + %% Upload & Extraction + A([Upload PDF]) --> B[PdfJsonConversionService] + B --> B1[Optional Ghostscript preflight] + B1 --> B2[Iterate pages & resources] + B2 --> B3[Extract text runs + fonts] + + %% Font handling (serial tree) + B3 --> C{Font subtype?} + C -->|Type 0 / TrueType / CID| C1[Copy embedded program bytes] + C -->|Type3| C2[Type3FontConversionService] + C1 --> C4[Attach font payload + metadata] + C2 --> C21{Library match?} + C21 --|Yes|--> C22[Inject canonical TTF/OTF from library] + C21 --|No|--> C23[Mark unsupported
& keep Type3 glyphs] + C2 --> C25[Record glyph charCodes + unicode mapping] + C22 --> C25 + C23 --> C25 + + %% JSON output + C4 --> D[Build PdfJsonDocument (pages, fonts, elements)] + C25 --> D + D --> E([Send JSON to UI]) + + %% Edit round-trip + E --> F[User edits text/elements] + F --> G[Patched JSON POSTed back] + G --> H{Regeneration pipeline} + H --> H1[Resolve fonts + candidates] + H1 --> H11[Prefer library/embedded payloads] + H1 --> H12[Fallback font service for missing glyphs] + H --> H2{Can rewrite token stream?} + H2 -->|Yes| H21[Rewrite existing operators] + H2 -->|No| H22[Full page regeneration] + H22 --> H23[Embed canonical fonts + Type3 glyph codes] + H21 --> I[Apply annotations/metadata] + H23 --> I + I --> J([Download edited PDF]) +``` + +**Key points** +- Type3 conversion happens entirely inside `Type3FontConversionService`. Matching entries pull canonical fonts from the library; when a signature is missing we simply keep the original Type3 glyph codes until a library entry is added. +- Raw Type3 char codes are preserved in `PdfJsonTextElement.charCodes` so edits can fall back to the original glyph sequence when users do not change the text. +- When the frontend submits changes, the backend preflights each text run, picks the proper font candidate (library > embedded > fallback), and rewrites the PDF with either token replacements or full page regeneration. +- Glyph coverage metadata from the Type3 library now informs which fonts can legitimately render new characters, so added text keeps using the original Type3 face whenever its coverage includes those code points. diff --git a/docs/type3/harvest_report.json b/docs/type3/harvest_report.json new file mode 100644 index 000000000..e9d496833 --- /dev/null +++ b/docs/type3/harvest_report.json @@ -0,0 +1,13216 @@ +{ + "generatedAt": "2025-11-08T14:01:48Z", + "totalSignatures": 450, + "fonts": [ + { + "signature": "sha256:003af1c45e3a5ab09544e226eba25e3a70abfe6e36dd48584474cc7a497685f6", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 28, + "glyphCoverage": [ + 32, + 40, + 41, + 46, + 48, + 49, + 50, + 52, + 54, + 56, + 79, + 80, + 97, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 108, + 111, + 112, + 114, + 115, + 116, + 117, + 118 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:0135aeba5bdea41d50e6d98f62846b9ffbf7416129d04989f2a33fcb26c8049c", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 18, + "glyphCoverage": [ + 32, + 40, + 41, + 48, + 49, + 50, + 53, + 73, + 74, + 78, + 83, + 85, + 97, + 105, + 108, + 110, + 116, + 117 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00020.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00020.json" + }, + { + "signature": "sha256:0161a4d84208a9e794a7f1418d3267a281fc5ac1c2ceda742a6f3bd62402f911", + "alias": "dejavusans-oblique", + "baseName": "DejaVuSans-Oblique", + "glyphCount": 2, + "glyphCoverage": [ + 77, + 97 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:0165552fad28860f2ea6079be7a87ea0833acde99309b3ef619c8f81707c46a3", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 14, + "glyphCoverage": [ + 46, + 48, + 49, + 50, + 51, + 52, + 54, + 97, + 99, + 105, + 108, + 115, + 118, + 215 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:024b48f66878300bbc5dfd572c08085c0bd6a4cd292ded8b1e656d6feee1e7c9", + "alias": "cmr10", + "baseName": "Cmr10", + "glyphCount": 17, + "glyphCoverage": [ + 40, + 41, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 61, + 99, + 103, + 108, + 111 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.json" + }, + { + "signature": "sha256:0324eb37ec25e4e03fdf2989db70b29bdaca5c6fff2d9334b44ecb5b22859cde", + "alias": "dejavuserif", + "baseName": "DejaVuSerif", + "glyphCount": 37, + "glyphCoverage": [ + 32, + 44, + 45, + 46, + 48, + 49, + 50, + 52, + 53, + 54, + 56, + 69, + 73, + 74, + 78, + 83, + 84, + 85, + 88, + 97, + 98, + 99, + 100, + 101, + 104, + 105, + 107, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00020.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00020.json" + }, + { + "signature": "sha256:0344fef03ef239cd0c79f3c546415e48d6167fd6f51c180117ec787c98efaf00", + "alias": "bitstreamverasans-roman", + "baseName": "BitstreamVeraSans-Roman", + "glyphCount": 39, + "glyphCoverage": [ + 32, + 35, + 40, + 41, + 45, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 61, + 65, + 66, + 67, + 69, + 77, + 83, + 84, + 86, + 87, + 97, + 100, + 101, + 103, + 104, + 105, + 107, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 118 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1312.6114.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1312.6114.json" + }, + { + "signature": "sha256:0386e5811612ba4b998d57cd3869d7fbc48092a79d436deda774af107a4af813", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 9, + "glyphCoverage": [ + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:04b036e5118d1ea265009b4cef09af5df3340d93e8e3a8a6382dba252fe2af7c", + "alias": null, + "baseName": null, + "glyphCount": 20, + "glyphCoverage": [ + 32, + 46, + 48, + 51, + 54, + 56, + 57, + 58, + 97, + 98, + 99, + 101, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 117 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.json" + }, + { + "signature": "sha256:04fe9fae9bfdc05853775240739e009a094170e0cc0db6c36201ee8e5c6ca3c0", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 49, + "glyphCoverage": [ + 32, + 40, + 41, + 45, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 56, + 65, + 66, + 67, + 69, + 70, + 71, + 72, + 73, + 76, + 78, + 79, + 80, + 82, + 83, + 85, + 86, + 88, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 105, + 107, + 108, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 120, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.json" + }, + { + "signature": "sha256:056649d3fbc0f331b19038c96281bd670c2c9e6f99957aae4e4ae4b881fc9591", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 25, + "glyphCoverage": [ + 32, + 40, + 41, + 48, + 49, + 50, + 54, + 56, + 58, + 71, + 80, + 84, + 87, + 97, + 100, + 101, + 105, + 107, + 109, + 110, + 111, + 114, + 116, + 117, + 119 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2307.00004.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2307.00004.json" + }, + { + "signature": "sha256:058b74992b66710d2b859fb8aabc74ea7fadcec001355bd5382fc48a682a3ac9", + "alias": "cmb10", + "baseName": "Cmb10", + "glyphCount": 1, + "glyphCoverage": [ + 115 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.json" + }, + { + "signature": "sha256:059af9dbaaab27c1d660ef00de6d4fd6e1687cfe2abca0a4c07265c2b2b450c6", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 22, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 50, + 51, + 53, + 55, + 68, + 77, + 84, + 97, + 100, + 101, + 103, + 104, + 108, + 109, + 110, + 111, + 115, + 116 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:05bde469259c29c6a70d45412a84ca54c2270e26e8df017b1bc732d081092366", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 29, + "glyphCoverage": [ + 32, + 40, + 41, + 45, + 46, + 47, + 48, + 49, + 50, + 53, + 55, + 60, + 70, + 74, + 76, + 97, + 98, + 99, + 100, + 101, + 102, + 105, + 108, + 110, + 111, + 114, + 115, + 116, + 117 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00016.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00016.json" + }, + { + "signature": "sha256:05f5eb7982c3522f8088567a1dbb5432991b82d1754b3f5abb5f7dc0f157eb00", + "alias": "stixgeneral-regular", + "baseName": "STIXGeneral-Regular", + "glyphCount": 41, + "glyphCoverage": [ + 32, + 45, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 56, + 66, + 72, + 73, + 76, + 80, + 82, + 84, + 86, + 91, + 93, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 107, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 120, + 122 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2010.11929.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2010.11929.json" + }, + { + "signature": "sha256:06c471f0065fa78d329a85bc01739eaa40c21549e6afaeeeca51a77f6d3a10ee", + "alias": null, + "baseName": null, + "glyphCount": 18, + "glyphCoverage": [ + 32, + 46, + 48, + 51, + 54, + 55, + 56, + 57, + 58, + 98, + 99, + 101, + 104, + 110, + 111, + 112, + 114, + 115 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.json" + }, + { + "signature": "sha256:06eaf46d286770042d8cce7d5d972945b5ed357a882478fd85b05ed4e6866486", + "alias": null, + "baseName": null, + "glyphCount": 5, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:08864aa8e8d17cead6059d5b4f1b1eea2053fa0ea3ca64e885d6eaacb78bccaf", + "alias": "dejavusans-oblique", + "baseName": "DejaVuSans-Oblique", + "glyphCount": 2, + "glyphCoverage": [ + 100, + 120 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:08ebe84ddecaf6fc631154c26ac0bb042d044a4c34a74ae42c74cd0cda8e397e", + "alias": null, + "baseName": null, + "glyphCount": 2, + "glyphCoverage": [ + 32, + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.08774.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.08774.json" + }, + { + "signature": "sha256:0a7f4adbb630b2d2f30813ae92edf72e46b41bd4ae3300212f2f81206142ace8", + "alias": "cmmi10", + "baseName": "Cmmi10", + "glyphCount": 7, + "glyphCoverage": [ + 44, + 47, + 78, + 82, + 102, + 114, + 952 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.json" + }, + { + "signature": "sha256:0b5d71b60a16cc077230dd6e1c01dfb1f638880a143c5a0ee9702940b0021d91", + "alias": "f251", + "baseName": "F251", + "glyphCount": 1, + "glyphCoverage": [ + 49 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2301.00006.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2301.00006.json" + }, + { + "signature": "sha256:0e948f91c2833397ccc52cf404dca8863a872f63aad1851c50a93f71ca715eff", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 26, + "glyphCoverage": [ + 32, + 37, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 65, + 67, + 80, + 99, + 100, + 101, + 109, + 110, + 111, + 112, + 115, + 116 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.json" + }, + { + "signature": "sha256:0f3192622bafbd4ebb9008852ba75a632a3c7f0019136fd191e172f1baa86004", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 39, + "glyphCoverage": [ + 32, + 45, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 58, + 66, + 67, + 68, + 70, + 71, + 73, + 76, + 77, + 80, + 82, + 83, + 84, + 97, + 98, + 99, + 101, + 102, + 105, + 107, + 108, + 110, + 111, + 112, + 114, + 115, + 116, + 117 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2304.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2304.00012.json" + }, + { + "signature": "sha256:0fcfc3ff6ebe9a206363ffc3cbf79213beed3bfc68d23bf06cf6384eeaf53947", + "alias": null, + "baseName": null, + "glyphCount": 27, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 50, + 53, + 54, + 55, + 56, + 57, + 58, + 97, + 98, + 99, + 100, + 101, + 103, + 104, + 105, + 108, + 110, + 111, + 114, + 115, + 116, + 118, + 119 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.json" + }, + { + "signature": "sha256:0ff8e8891a2f21b86c669f3abca19d1f579759f895a3762a9552dafc45be280c", + "alias": null, + "baseName": null, + "glyphCount": 18, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 50, + 55, + 56, + 57, + 58, + 98, + 101, + 102, + 105, + 110, + 111, + 112, + 114, + 115 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.json" + }, + { + "signature": "sha256:10d0df41401b54f862bea72202b1b792016985c319e70242517ec0edbe100b35", + "alias": null, + "baseName": null, + "glyphCount": 17, + "glyphCoverage": [ + 32, + 40, + 41, + 69, + 70, + 72, + 84, + 86, + 99, + 101, + 103, + 110, + 113, + 114, + 117, + 121, + 122 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2201.04294.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2201.04294.json" + }, + { + "signature": "sha256:110a520d1ad54de2554d47633b5d36988c1cfe6f0f550aff87cec1532588aa7d", + "alias": "stixnonunicode-italic", + "baseName": "STIXNonUnicode-Italic", + "glyphCount": 0, + "glyphCoverage": null, + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.json" + }, + { + "signature": "sha256:119da04d962622c8aa46d77f6bdfccb5d4a4ef7173775275b046efd59098e5d9", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 17, + "glyphCoverage": [ + 46, + 48, + 49, + 50, + 53, + 55, + 97, + 101, + 103, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:11d35f41e5cfd7d5227c6ab9469442223c72b2e6b865e1339bba49d37021b261", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 34, + "glyphCoverage": [ + 32, + 45, + 48, + 49, + 50, + 51, + 52, + 53, + 65, + 66, + 68, + 69, + 70, + 71, + 76, + 77, + 78, + 80, + 83, + 84, + 85, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 110, + 111, + 114, + 115, + 116 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.json" + }, + { + "signature": "sha256:12c5b92495a5c3f327778e704be0d4ed00b5b919e579e5c58e4be82a3d5797f6", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 46, + "glyphCoverage": [ + 32, + 40, + 41, + 45, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 56, + 57, + 65, + 66, + 67, + 69, + 71, + 72, + 76, + 77, + 78, + 80, + 84, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 107, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 118, + 122 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.json" + }, + { + "signature": "sha256:12de608415350701da162e8805694a647b45694693b72fdf3f8b917e0345a45d", + "alias": "dejavusans-oblique", + "baseName": "GCWXDV+DejaVuSans-Oblique", + "glyphCount": 1, + "glyphCoverage": [ + 70 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2301.00017.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2301.00017.json" + }, + { + "signature": "sha256:1324cd8127143ef9023616b7911c570db3b1eb35758cdc9258ec16c0f4587775", + "alias": "cmsy10", + "baseName": "Cmsy10", + "glyphCount": 1, + "glyphCoverage": [ + 48 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:155cec0369a4f5293154c9462c1537241c835cfeeac389fed6ce5204dbbc4619", + "alias": null, + "baseName": null, + "glyphCount": 29, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 52, + 54, + 55, + 56, + 57, + 58, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 107, + 108, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 119 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.json" + }, + { + "signature": "sha256:15ac052c211a0319982a9884d5182f36c18e3427641f4646ed9c283c10c90d9e", + "alias": "stixgeneral-regular", + "baseName": "STIXGeneral-Regular", + "glyphCount": 47, + "glyphCoverage": [ + 32, + 37, + 40, + 41, + 45, + 48, + 49, + 50, + 51, + 53, + 55, + 56, + 57, + 65, + 66, + 70, + 72, + 73, + 76, + 78, + 79, + 80, + 82, + 84, + 86, + 91, + 93, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 118, + 120, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2010.11929.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2010.11929.json" + }, + { + "signature": "sha256:15fe40dcd9de482e205cfe794137533b04baaf07e0257e8cfbb04e81bdd1df74", + "alias": null, + "baseName": null, + "glyphCount": 2, + "glyphCoverage": [ + 32, + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.08774.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.08774.json" + }, + { + "signature": "sha256:1645cece6175453f95822369995c91dc48de7033d1a51b08387ac9c2776263d0", + "alias": null, + "baseName": null, + "glyphCount": 2, + "glyphCoverage": [ + 32, + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.08774.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.08774.json" + }, + { + "signature": "sha256:164c839db8cd63db687b1386a245c53951cc61f98aeb108d1598a9c716ffb19e", + "alias": null, + "baseName": null, + "glyphCount": 16, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 52, + 56, + 57, + 58, + 99, + 101, + 110, + 111, + 112, + 114, + 115, + 119 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.json" + }, + { + "signature": "sha256:16620e9ffbbe40f70ba2fc77daa1ec71eb1c5a17ffa25f7e1c77399e67ec821a", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 43, + "glyphCoverage": [ + 32, + 37, + 40, + 41, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 56, + 66, + 67, + 68, + 72, + 77, + 78, + 79, + 80, + 83, + 84, + 87, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 105, + 107, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 119, + 122 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.json" + }, + { + "signature": "sha256:16eed1353d0287ad1b4ba43090668d84212cea631a68135ca4c157ad416c9728", + "alias": "cmmi10", + "baseName": "Cmmi10", + "glyphCount": 9, + "glyphCoverage": [ + 44, + 76, + 77, + 78, + 84, + 88, + 118, + 181, + 963 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.json" + }, + { + "signature": "sha256:1776fd7ebec963ee77d36ee8d6a0a8f9e49d036f174b1f3ba576eda00de0453f", + "alias": null, + "baseName": null, + "glyphCount": 1, + "glyphCoverage": [ + 90 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2306.00004.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2306.00004.json" + }, + { + "signature": "sha256:18ce863feb57f42f2b92ac85a8c55ef3eeaa15488c5d6cd8c724b085994c64fa", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 12, + "glyphCoverage": [ + 46, + 48, + 49, + 50, + 51, + 52, + 97, + 99, + 105, + 108, + 115, + 118 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:1973f402f79e93952bf2c0f725d92a04fea1f774c49ac770ae34e5ce6cc20a87", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 25, + "glyphCoverage": [ + 32, + 37, + 40, + 41, + 45, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 69, + 78, + 82, + 95, + 99, + 101, + 104, + 110, + 111, + 112, + 114, + 115, + 116 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.json" + }, + { + "signature": "sha256:19d6fa254f1aa01aa55a5effc2dafbbb88f559a5516286ad06755fa027116e15", + "alias": null, + "baseName": null, + "glyphCount": 18, + "glyphCoverage": [ + 32, + 46, + 48, + 51, + 56, + 57, + 58, + 98, + 100, + 101, + 102, + 103, + 105, + 110, + 111, + 112, + 114, + 115 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.json" + }, + { + "signature": "sha256:1a0c168b0890d6fc8bb9c272024447c05b24cadae49eb7e86d683ce6cafff238", + "alias": "cmmi10", + "baseName": "Cmmi10", + "glyphCount": 2, + "glyphCoverage": [ + 46, + 77 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.json" + }, + { + "signature": "sha256:1ba74c0f7bed040adc2e248e0d5e44bca62ce0ee0ea06842a8bd43586bf177d2", + "alias": "dejavusans-oblique", + "baseName": "DejaVuSans-Oblique", + "glyphCount": 2, + "glyphCoverage": [ + 69, + 70 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.json" + }, + { + "signature": "sha256:1dcce5224ff4802f9710dba92ddad0d6cda2c630070086f410e01d7312858a21", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 42, + "glyphCoverage": [ + 32, + 40, + 41, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 66, + 68, + 71, + 76, + 77, + 78, + 82, + 83, + 86, + 88, + 91, + 93, + 99, + 101, + 103, + 105, + 107, + 108, + 109, + 110, + 111, + 114, + 115, + 116, + 119, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.json" + }, + { + "signature": "sha256:1f52ed63e5d49ffdaac4b93a71ab4503245455d969bcae5f73561f7948fb527a", + "alias": null, + "baseName": null, + "glyphCount": 30, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:2045fe5633bf884e96c253fa25c3f11320956ccc518eccec8d6c40c2ea5ef84e", + "alias": null, + "baseName": null, + "glyphCount": 2, + "glyphCoverage": [ + 0, + 1 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_math_0608240.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_math_0608240.json" + }, + { + "signature": "sha256:20585043aeacc967df93f7cf8d41e614ec0d9534987926f0864237e83292f083", + "alias": null, + "baseName": null, + "glyphCount": 2, + "glyphCoverage": [ + 32, + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.08774.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.08774.json" + }, + { + "signature": "sha256:20a3bafbc23605719db24935dd8b91f5227eb27403f10c421a6d238bbf2da60d", + "alias": null, + "baseName": null, + "glyphCount": 27, + "glyphCoverage": [ + 32, + 46, + 48, + 50, + 51, + 52, + 54, + 55, + 56, + 57, + 58, + 97, + 98, + 99, + 100, + 101, + 104, + 105, + 107, + 109, + 110, + 111, + 112, + 114, + 115, + 117, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.json" + }, + { + "signature": "sha256:21c5e000c5ee6d3c39478cd3dc97f2e2ed1819c7c9db7def11c2e11ae7cff980", + "alias": "arialmt", + "baseName": "ArialMT", + "glyphCount": 5, + "glyphCoverage": [ + 48, + 49, + 50, + 51, + 53 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2112.07804.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2112.07804.json" + }, + { + "signature": "sha256:223e0c5fe24b1a4c8b85f771f3d7325ce029366420c26c494722e951b9bfbdca", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 38, + "glyphCoverage": [ + 32, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 66, + 67, + 70, + 76, + 77, + 80, + 83, + 97, + 99, + 100, + 101, + 103, + 104, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 118, + 119 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00009.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00009.json" + }, + { + "signature": "sha256:227d6dc20ad25316a5790e00b9a08645dde5fdca3d3d5271bd4ef712c8359e10", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 33, + "glyphCoverage": [ + 32, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 65, + 67, + 74, + 76, + 77, + 80, + 83, + 84, + 85, + 86, + 99, + 100, + 101, + 105, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 218 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2306.00007.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2306.00007.json" + }, + { + "signature": "sha256:22a8cc35f37fd522aafcf1c10e8196704f80e6f4112bf831acae9d1c171252ed", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 51, + "glyphCoverage": [ + 32, + 45, + 48, + 49, + 50, + 53, + 55, + 65, + 66, + 67, + 68, + 69, + 72, + 73, + 76, + 77, + 79, + 80, + 81, + 82, + 84, + 86, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 118, + 120, + 122, + 225, + 227, + 231, + 233, + 234, + 237, + 244 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2306.00007.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2306.00007.json" + }, + { + "signature": "sha256:22b1dc5946ddf13ec7ab8e0852d96452d2ee99cd4dde0b1867d0c855f735ce53", + "alias": null, + "baseName": null, + "glyphCount": 22, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 50, + 56, + 57, + 58, + 97, + 98, + 99, + 101, + 107, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.json" + }, + { + "signature": "sha256:2312fa74d568c0267cdd7cb451a2bb293002c39be99c0d278baae3de834b598d", + "alias": "f153", + "baseName": "F153", + "glyphCount": 42, + "glyphCoverage": [ + 39, + 44, + 46, + 58, + 65, + 66, + 69, + 71, + 73, + 74, + 76, + 77, + 79, + 80, + 83, + 84, + 87, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 122 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2005.14165.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2005.14165.json" + }, + { + "signature": "sha256:23e4b174e951cd6135e229fb397db4ff518021cf14d5f817031b9f754841e511", + "alias": null, + "baseName": null, + "glyphCount": 11, + "glyphCoverage": [ + 0, + 46, + 97, + 98, + 105, + 108, + 109, + 111, + 112, + 116, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\07_matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\07_matplotlib.json" + }, + { + "signature": "sha256:24060b048045f05f3b9c5b5a452ffdb8e002fc6075203c889ac98e4570abc512", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 37, + "glyphCoverage": [ + 32, + 40, + 41, + 44, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 56, + 60, + 67, + 68, + 73, + 77, + 86, + 91, + 93, + 97, + 101, + 103, + 105, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 119, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:252028327defa7c631e6b7e75492ec4ee1a477408725bba03dd7431266f7f51a", + "alias": "dejavusans-oblique", + "baseName": "DejaVuSans-Oblique", + "glyphCount": 1, + "glyphCoverage": [ + 84 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.json" + }, + { + "signature": "sha256:25773f8a0eaa5c6df21f421ef5da85883e5cc06c331710bdafe56149a08c5b7a", + "alias": null, + "baseName": null, + "glyphCount": 27, + "glyphCoverage": [ + 32, + 40, + 41, + 45, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 56, + 57, + 75, + 76, + 84, + 87, + 88, + 97, + 98, + 99, + 100, + 101, + 105, + 109, + 112, + 115 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2201.04294.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2201.04294.json" + }, + { + "signature": "sha256:27557b9ab139f8a5f9edcd3135f30c458c59a22cbb3713596b7cfef2545539e7", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 61, + "glyphCoverage": [ + 32, + 40, + 41, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 88, + 90, + 99, + 100, + 101, + 103, + 109, + 110, + 111, + 114, + 115, + 116, + 117, + 193, + 194, + 195, + 199, + 201, + 202, + 205, + 211, + 213, + 218 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2306.00007.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2306.00007.json" + }, + { + "signature": "sha256:27b98489865df8df55f19e4505c093501f236465885ca3bf5b66b6f047a85bb2", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 19, + "glyphCoverage": [ + 46, + 48, + 49, + 50, + 51, + 52, + 68, + 70, + 72, + 76, + 97, + 99, + 103, + 105, + 108, + 111, + 114, + 115, + 118 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:28299f37933315f1d1fa3cc9639b4f56e0e73c706c9960792c7391354ecd13c4", + "alias": null, + "baseName": null, + "glyphCount": 15, + "glyphCoverage": [ + 39, + 40, + 41, + 48, + 49, + 65, + 73, + 77, + 78, + 88, + 97, + 98, + 99, + 116, + 117 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2201.04294.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2201.04294.json" + }, + { + "signature": "sha256:2832e219b2db3bacf0d5a147d4b74ad5226fdf7562c395ef3fb12937633e037d", + "alias": "cmsy10", + "baseName": "Cmsy10", + "glyphCount": 1, + "glyphCoverage": [ + 8734 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:29166f699071782a7a72b79a9511f65ba407b5e073b605f50078cc9bf6c89284", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 31, + "glyphCoverage": [ + 32, + 40, + 41, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 71, + 80, + 84, + 87, + 97, + 100, + 101, + 105, + 107, + 109, + 110, + 111, + 114, + 116, + 117, + 119 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2307.00004.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2307.00004.json" + }, + { + "signature": "sha256:2a70400ce6ee64523330ff783b104f0b5c44f59fb6771acd37c5c3f6a7d1a1f5", + "alias": null, + "baseName": null, + "glyphCount": 1, + "glyphCoverage": [ + 71 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2201.04294.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2201.04294.json" + }, + { + "signature": "sha256:2a981ff00b15bf72bff602cfe887f2c2306e59e96a932f3b518d9e3d99c102f0", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 39, + "glyphCoverage": [ + 32, + 40, + 41, + 45, + 46, + 48, + 49, + 50, + 52, + 53, + 54, + 56, + 57, + 58, + 61, + 65, + 66, + 67, + 68, + 70, + 71, + 76, + 77, + 80, + 82, + 84, + 85, + 97, + 98, + 101, + 105, + 107, + 108, + 111, + 114, + 115, + 116, + 117, + 118 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2304.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2304.00012.json" + }, + { + "signature": "sha256:2add5b5ad6e536f3614b75e246b49a006edbbecdd309d24bd42c874a3ae3c8ed", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 21, + "glyphCoverage": [ + 45, + 48, + 49, + 50, + 51, + 52, + 97, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 108, + 109, + 110, + 111, + 114, + 115, + 116 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:2b323550fe4a3ac04f6e2ab72473aa1d24a088f51b1aca4b104185d2497c83d8", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 30, + "glyphCoverage": [ + 32, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 67, + 73, + 80, + 97, + 98, + 99, + 100, + 101, + 103, + 104, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 119, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2010.11929.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2010.11929.json" + }, + { + "signature": "sha256:2b481cd3bfef1d40b26ac83932766411b06b2342bdb137ad24fece0644e01620", + "alias": "cmsy10", + "baseName": "Cmsy10", + "glyphCount": 2, + "glyphCoverage": [ + 124, + 8722 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.json" + }, + { + "signature": "sha256:2b53d4d6f689754c91b6d050036a537d867c4fb4fae08cf52cde8ec926841c09", + "alias": "f95", + "baseName": "F95", + "glyphCount": 1, + "glyphCoverage": [ + 49 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00018.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00018.json" + }, + { + "signature": "sha256:2b72b85b468be98131f32877501f144180fb2dcb60d4039b6a87036d86328b7b", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 40, + "glyphCoverage": [ + 32, + 45, + 46, + 48, + 49, + 50, + 52, + 53, + 55, + 56, + 58, + 62, + 65, + 66, + 68, + 71, + 73, + 76, + 77, + 79, + 80, + 83, + 84, + 97, + 98, + 99, + 100, + 101, + 102, + 104, + 105, + 107, + 108, + 109, + 110, + 111, + 114, + 115, + 116, + 118 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.json" + }, + { + "signature": "sha256:2b79af294073304e3f1034c3e565e8fddc98395525d237c7d33705e125c9270c", + "alias": null, + "baseName": null, + "glyphCount": 18, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 54, + 56, + 57, + 58, + 97, + 98, + 101, + 108, + 110, + 111, + 112, + 114, + 115, + 116 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.json" + }, + { + "signature": "sha256:2be58b6ef1e29a83b8634d70b9e32c37a15dea2e608894439ef7224c35b77f5d", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 7, + "glyphCoverage": [ + 46, + 48, + 49, + 50, + 52, + 53, + 55 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:2bf8292f7fe8b83c33ee983b434bed4e20f27f7c5b248e419719b351dd97567a", + "alias": "cmr10", + "baseName": "Cmr10", + "glyphCount": 6, + "glyphCoverage": [ + 48, + 49, + 50, + 51, + 53, + 61 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1312.6114.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1312.6114.json" + }, + { + "signature": "sha256:2c09dab2a8870462740c0a9135b2a35d48907a3fee1dbb545d85c0bbd87f1fde", + "alias": null, + "baseName": null, + "glyphCount": 19, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 50, + 55, + 57, + 58, + 97, + 99, + 101, + 103, + 105, + 110, + 111, + 112, + 114, + 115, + 116 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.json" + }, + { + "signature": "sha256:2cd805c15bf495b08baeec955ba66be53eae5aae4da6cd4db8d7b89c33b2d781", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 39, + "glyphCoverage": [ + 32, + 45, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 66, + 67, + 69, + 73, + 76, + 78, + 80, + 83, + 85, + 97, + 98, + 99, + 100, + 101, + 103, + 104, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 119, + 120 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2307.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2307.00012.json" + }, + { + "signature": "sha256:2e874f74a86deeaf8872f5d640cc08357660bf65a7b2265e79a9348b3a219766", + "alias": null, + "baseName": null, + "glyphCount": 28, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:2eb5a8e84ff2327a7863c891ae4ccdeee89d2caae31a1f2a01b55b9d95c88fcb", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 7, + "glyphCoverage": [ + 46, + 48, + 49, + 50, + 53, + 54, + 55 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.json" + }, + { + "signature": "sha256:2f18ed7f982aeb954aaae388ba0c75e3c676717ca324156b42bb17f3f20ef403", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 18, + "glyphCoverage": [ + 46, + 48, + 49, + 50, + 52, + 54, + 97, + 99, + 101, + 102, + 105, + 108, + 111, + 112, + 114, + 115, + 116, + 118 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:2f6f8d63ff6235f3b7cd6f5eba8076854892037afa2ea6962953b3e7cda3736e", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 31, + "glyphCoverage": [ + 32, + 40, + 41, + 44, + 61, + 65, + 66, + 67, + 68, + 70, + 83, + 84, + 97, + 98, + 99, + 101, + 102, + 104, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 119, + 120, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:2fa383e8594fd78d28f09c8dea2de24f8626f509630de5cc967d0f5512b96219", + "alias": null, + "baseName": null, + "glyphCount": 18, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:2fb79487a605251641bb14936fd458244c87ace268459b046788bdc6b8db9b70", + "alias": null, + "baseName": null, + "glyphCount": 2, + "glyphCoverage": [ + 32, + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.08774.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.08774.json" + }, + { + "signature": "sha256:31d0e67bc63a816302c9ff6ad9c19e17603aef1a4c3677b81b1d9084caa86e03", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 6, + "glyphCoverage": [ + 46, + 48, + 49, + 50, + 51, + 53 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\03_handout-beginner.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\03_handout-beginner.json" + }, + { + "signature": "sha256:32773883080a68d1e6bae19474c8901526ffc0bceb51672184ade3850d573da5", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 42, + "glyphCoverage": [ + 32, + 45, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 66, + 68, + 70, + 71, + 73, + 76, + 77, + 78, + 82, + 83, + 84, + 89, + 90, + 91, + 93, + 97, + 98, + 99, + 100, + 101, + 103, + 105, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00010.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00010.json" + }, + { + "signature": "sha256:329e9836cb2c17977911aac0f39aca7e4219821effa752bb9821d6187ee4ae09", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 24, + "glyphCoverage": [ + 32, + 40, + 41, + 50, + 56, + 66, + 71, + 82, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2010.11929.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2010.11929.json" + }, + { + "signature": "sha256:33002ecf1ae5b81573253543920eb522523da71d50be3e10c88b7445728e8129", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 25, + "glyphCoverage": [ + 32, + 40, + 41, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 80, + 84, + 87, + 101, + 105, + 107, + 109, + 111, + 114, + 119 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2307.00004.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2307.00004.json" + }, + { + "signature": "sha256:330feb6bac005ffe77921f2245d451608190386091d4f09242a619a82062ddbe", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 28, + "glyphCoverage": [ + 32, + 45, + 48, + 49, + 50, + 51, + 52, + 53, + 56, + 57, + 61, + 69, + 76, + 98, + 99, + 101, + 102, + 103, + 104, + 105, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 119 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.json" + }, + { + "signature": "sha256:33d0ab9d9d72c1aed1edfc9b815dd6a2d618cbbe9084309c7f2de0f3df3073d7", + "alias": "stixsizethreesym-regular", + "baseName": "STIXSizeThreeSym-Regular", + "glyphCount": 2, + "glyphCoverage": [ + 91, + 93 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:346f5e1ac70f2ffa97d48f41d1c527d155555b6b9d8113ee5955c9dc9eed9032", + "alias": null, + "baseName": null, + "glyphCount": 26, + "glyphCoverage": [ + 32, + 46, + 48, + 50, + 52, + 53, + 55, + 56, + 57, + 58, + 97, + 98, + 99, + 100, + 101, + 103, + 104, + 105, + 108, + 110, + 111, + 112, + 114, + 116, + 117, + 118 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.json" + }, + { + "signature": "sha256:35354529acf8677e8aee9e994fd8c94a72e94d67dae8ae5bc0c2b58b1ad1622d", + "alias": "bitstreamverasans-roman", + "baseName": "BitstreamVeraSans-Roman", + "glyphCount": 34, + "glyphCoverage": [ + 32, + 43, + 46, + 48, + 49, + 50, + 51, + 53, + 65, + 67, + 68, + 69, + 70, + 71, + 73, + 78, + 82, + 83, + 97, + 99, + 100, + 101, + 103, + 104, + 105, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 118 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1412.6980.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1412.6980.json" + }, + { + "signature": "sha256:362261e42d2d142ebbdce7f31ef3cb6116185edb041142dbb03880ed492dd9bd", + "alias": null, + "baseName": null, + "glyphCount": 23, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 51, + 53, + 54, + 56, + 57, + 58, + 97, + 98, + 99, + 100, + 101, + 103, + 105, + 107, + 108, + 110, + 112, + 116, + 117 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.json" + }, + { + "signature": "sha256:3654d4d9bcbbf6ad51628082203094069a17aad3a5e6f5c7972833566e42ab6b", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 29, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 67, + 68, + 97, + 98, + 99, + 101, + 102, + 103, + 104, + 105, + 108, + 109, + 110, + 111, + 114, + 115, + 116, + 117, + 120 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:3686f6e2c2bc4368beb1cbf386f721c2b8577559dee563c41c0bff2fd8c0ec95", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 39, + "glyphCoverage": [ + 32, + 40, + 41, + 44, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 55, + 60, + 67, + 68, + 71, + 73, + 77, + 91, + 93, + 97, + 99, + 100, + 101, + 103, + 105, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 119, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:3756e20547fb9cab7fa562d1b8fa3340839b5b6e88626cc365320c989dcf0945", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 35, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 50, + 52, + 54, + 56, + 65, + 66, + 67, + 72, + 73, + 74, + 79, + 80, + 84, + 97, + 99, + 100, + 101, + 104, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 119, + 120, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.json" + }, + { + "signature": "sha256:383aac032c10c61cc5f1fe23f63ba528426d10f34eecc89cf12200a3095762ca", + "alias": "cmmi10", + "baseName": "Cmmi10", + "glyphCount": 7, + "glyphCoverage": [ + 44, + 46, + 47, + 77, + 78, + 178, + 963 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.json" + }, + { + "signature": "sha256:388e244c83aebc4acdec7b655f42160c00040979725c71684651d84c525610f3", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 25, + "glyphCoverage": [ + 32, + 37, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 58, + 65, + 67, + 80, + 99, + 100, + 101, + 109, + 110, + 111, + 112, + 115, + 116 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.json" + }, + { + "signature": "sha256:39074e2438659ac2ba53b6dd65fbc4a1429204d389a8f70322ea861df90fe38c", + "alias": null, + "baseName": null, + "glyphCount": 27, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:39629f519d6a19e9a215f901e2cc546505de1ed1f2a7b668c840b1d7368929df", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 20, + "glyphCoverage": [ + 32, + 40, + 41, + 48, + 49, + 50, + 53, + 55, + 69, + 73, + 84, + 88, + 97, + 104, + 105, + 108, + 110, + 114, + 116, + 117 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00020.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00020.json" + }, + { + "signature": "sha256:39b8e5ec8e20a788cd45166baf0ab796397f152c9cd8dec1f882c635380cad92", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 13, + "glyphCoverage": [ + 46, + 48, + 49, + 50, + 52, + 53, + 54, + 97, + 99, + 105, + 108, + 115, + 118 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:3a1e421cb7456fa893a94df620c1324437331e0829b86c98e01412888a9f4002", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 35, + "glyphCoverage": [ + 32, + 45, + 48, + 49, + 50, + 52, + 54, + 56, + 66, + 67, + 69, + 73, + 76, + 78, + 80, + 83, + 85, + 97, + 98, + 99, + 100, + 101, + 103, + 104, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 119, + 120 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2307.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2307.00012.json" + }, + { + "signature": "sha256:3a3c9d8bcde54f0d01902f17e4b2e6dd31d3ab7fb422aa311560bbca91581c51", + "alias": null, + "baseName": null, + "glyphCount": 5, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:3b14dd83b170ca8e08c9354da4b39f0a2c5f1cf98870f0603a6c12ca7569b09d", + "alias": "stixsizeonesym-regular", + "baseName": "STIXSizeOneSym-Regular", + "glyphCount": 0, + "glyphCoverage": null, + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00016.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00016.json" + }, + { + "signature": "sha256:3b41f9e5f3a7ffa6f4cdffa2a46f02781ec1b2b0c99994707cfb139aa15a11e2", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 5, + "glyphCoverage": [ + 32, + 48, + 49, + 50, + 53 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:3c96be4f5f8e14b5a4f4c270203246e7d58d498b4fd9d5f9ec3ba79ee4fa9bde", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 40, + "glyphCoverage": [ + 32, + 40, + 41, + 43, + 45, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 66, + 68, + 69, + 70, + 72, + 75, + 77, + 80, + 83, + 86, + 97, + 99, + 100, + 101, + 102, + 105, + 107, + 108, + 109, + 110, + 111, + 114, + 116, + 117, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.json" + }, + { + "signature": "sha256:3ee773a0af6fdedb9853dca9f4d8b80a421a0024bdf06bea41f15d58e3b90c87", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 13, + "glyphCoverage": [ + 46, + 48, + 49, + 50, + 52, + 54, + 56, + 97, + 99, + 105, + 108, + 115, + 118 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:3f99468fbd7c5c5e76c9c4fb5e1eac9d0d56e9881d439e93a3c32959c27d31d9", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 32, + "glyphCoverage": [ + 32, + 40, + 41, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 56, + 57, + 61, + 77, + 82, + 83, + 91, + 93, + 97, + 101, + 103, + 108, + 111, + 112, + 114, + 115, + 116 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00009.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00009.json" + }, + { + "signature": "sha256:3fd273845892808cc2db25e489b58441dd3f42842d50fab3d78bbf66d3edef90", + "alias": null, + "baseName": null, + "glyphCount": 20, + "glyphCoverage": [ + 32, + 46, + 48, + 50, + 54, + 55, + 56, + 57, + 58, + 99, + 100, + 101, + 103, + 104, + 110, + 111, + 112, + 114, + 115, + 117 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.json" + }, + { + "signature": "sha256:4007657b984b14b5e527e025e29a9bf907eff6b04b8b8242e82b147bc52e30c4", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 39, + "glyphCoverage": [ + 32, + 43, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 56, + 65, + 66, + 68, + 71, + 73, + 76, + 77, + 78, + 80, + 82, + 83, + 87, + 97, + 99, + 100, + 101, + 102, + 103, + 105, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 118 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1412.6980.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1412.6980.json" + }, + { + "signature": "sha256:422fa59231be16ef7d4055ff1ff7b9c3e5478a24cacaffe6d69f34883fb0df0e", + "alias": null, + "baseName": null, + "glyphCount": 26, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:426f1f10fa9d9823874136f2a6199f7834ab593270c9b6d083dd0a5dc4476448", + "alias": null, + "baseName": null, + "glyphCount": 5, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:42f5d6fceaeacd54a02ccd770b0000fd269f1724666df4efc00f71e139630c13", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 39, + "glyphCoverage": [ + 32, + 45, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 66, + 69, + 71, + 75, + 76, + 77, + 80, + 83, + 97, + 99, + 101, + 102, + 104, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 118, + 119, + 120, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2306.00008.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2306.00008.json" + }, + { + "signature": "sha256:43326b634e4feee84ade0859c37bbbefb7931bc4bd2276a65dc5575b7d722ed7", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 43, + "glyphCoverage": [ + 32, + 40, + 41, + 45, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 65, + 66, + 69, + 72, + 76, + 77, + 78, + 80, + 84, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 107, + 108, + 109, + 110, + 111, + 114, + 115, + 116, + 117, + 118, + 122 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.json" + }, + { + "signature": "sha256:43756201215aecf6c4d628e46e3d45b5943c6af42f845fd2c870b3ec8676a5e6", + "alias": null, + "baseName": null, + "glyphCount": 5, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:4390a7dfb16ef1d208d7c22bfeadfa76d3179325a63fa2075fdbc1c907f00a5a", + "alias": "dejavusans-oblique", + "baseName": "DejaVuSans-Oblique", + "glyphCount": 1, + "glyphCoverage": [ + 122 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2301.00017.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2301.00017.json" + }, + { + "signature": "sha256:441c7e93df12952ac1615c07dbd1b2cece04eb82100bb8f2dd5a0780cf285691", + "alias": "bitstreamverasans-roman", + "baseName": "BitstreamVeraSans-Roman", + "glyphCount": 32, + "glyphCoverage": [ + 32, + 42, + 45, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 61, + 76, + 79, + 91, + 93, + 97, + 99, + 101, + 102, + 103, + 104, + 105, + 108, + 109, + 110, + 111, + 114, + 115, + 116, + 117 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.json" + }, + { + "signature": "sha256:4521451b9fe7a291a87872cc2e3e127a6eb163d38c9eb1525f35d13ed5c33eb6", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 25, + "glyphCoverage": [ + 32, + 40, + 41, + 48, + 49, + 50, + 51, + 52, + 53, + 68, + 71, + 84, + 97, + 99, + 101, + 102, + 105, + 109, + 110, + 111, + 114, + 115, + 116, + 117, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00020.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00020.json" + }, + { + "signature": "sha256:456e8a38765897fa63042bbb09a132cbc29409df0d870478b46dc195ad68ec23", + "alias": null, + "baseName": null, + "glyphCount": 16, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:458411ac7398c9629252180998e264c018f1a5c8edff06e5889eeadc4a089135", + "alias": "dejavusans-oblique", + "baseName": "DejaVuSans-Oblique", + "glyphCount": 0, + "glyphCoverage": null, + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2301.00011.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2301.00011.json" + }, + { + "signature": "sha256:45ee06d5d17f02f622724144ac4593c76ef6d76da856e210a17a087a511170ac", + "alias": null, + "baseName": null, + "glyphCount": 1, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:46208ca8a881282e6f832ed94029c737d251f113226764c290b51c14490ff1a4", + "alias": null, + "baseName": null, + "glyphCount": 1, + "glyphCoverage": [ + 32 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2201.04294.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2201.04294.json" + }, + { + "signature": "sha256:487f67ce5ed85fd87b7df0ac55f12d97e71ab129cf1a286de3af43cf132f1d1b", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 34, + "glyphCoverage": [ + 32, + 40, + 41, + 45, + 46, + 48, + 49, + 50, + 52, + 54, + 55, + 56, + 58, + 61, + 67, + 69, + 80, + 97, + 98, + 99, + 100, + 101, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 118, + 119 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.08774.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.08774.json" + }, + { + "signature": "sha256:488d8740b350934300575b73b38df2a70fabfe62ecc79b352fce00bdd593b138", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 34, + "glyphCoverage": [ + 32, + 45, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 56, + 68, + 78, + 80, + 83, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00010.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00010.json" + }, + { + "signature": "sha256:4942074c8203afa328b8c4112b0d5d5239fdafb82b66a139e21b6b78f09b0e51", + "alias": null, + "baseName": null, + "glyphCount": 9, + "glyphCoverage": [ + 32, + 46, + 48, + 50, + 53, + 55, + 61, + 97, + 176 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2305.00007.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2305.00007.json" + }, + { + "signature": "sha256:4972d1a3c72cf5114a3b2e8325e957c171fd36c734c356856c590d246a1a385e", + "alias": "dejavusans-oblique", + "baseName": "DejaVuSans-Oblique", + "glyphCount": 4, + "glyphCoverage": [ + 82, + 111, + 116, + 122 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00016.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00016.json" + }, + { + "signature": "sha256:4973ae1f81c923ae24e09a00006693b4321e287f871fd0c99214f1168e2a6ba0", + "alias": "roboto-regular", + "baseName": "Roboto-Regular", + "glyphCount": 32, + "glyphCoverage": [ + 32, + 44, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 68, + 70, + 83, + 84, + 97, + 100, + 101, + 103, + 105, + 108, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 122, + 215 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1910.10683.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1910.10683.json" + }, + { + "signature": "sha256:497ddd27e1f56ef6504c61613e3a159bab13314a4970a3be13b3a556648964da", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 12, + "glyphCoverage": [ + 46, + 48, + 49, + 50, + 51, + 97, + 98, + 99, + 105, + 108, + 115, + 118 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:49d9a03832b06f5d73c8aa098cbfd109b81834e52a4dfcec0f8e8d1214aad66d", + "alias": "cmmi10", + "baseName": "Cmmi10", + "glyphCount": 6, + "glyphCoverage": [ + 78, + 97, + 105, + 110, + 114, + 116 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1312.6114.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1312.6114.json" + }, + { + "signature": "sha256:4a7ca5ba0773e9655d3c008dee4171c542863f69a104154918321e14bb5ef8b7", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 29, + "glyphCoverage": [ + 32, + 40, + 41, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 70, + 73, + 76, + 77, + 78, + 79, + 86, + 88, + 99, + 101, + 103, + 109, + 111, + 114, + 115 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.json" + }, + { + "signature": "sha256:4b0ed0ef2a8543dfab18b5744221749adbe1ff6c4ebe213ce0eb4d6a54657fbe", + "alias": "stixgeneral-regular", + "baseName": "STIXGeneral-Regular", + "glyphCount": 43, + "glyphCoverage": [ + 32, + 37, + 40, + 41, + 45, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 66, + 70, + 73, + 74, + 76, + 77, + 78, + 82, + 84, + 86, + 91, + 93, + 97, + 98, + 101, + 102, + 103, + 104, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 120 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2010.11929.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2010.11929.json" + }, + { + "signature": "sha256:4b509d2ae2cfab89783a73df2c66f0fd50949f97696079cb58f1e58b81daaa07", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 4, + "glyphCoverage": [ + 84, + 101, + 105, + 109 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\03_handout-beginner.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\03_handout-beginner.json" + }, + { + "signature": "sha256:4b553d51d58f5891af071359fb016caf1c6137778da129a6b208dcc8cb0c4635", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 9, + "glyphCoverage": [ + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 56 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:4c000f159e55414db3b27e4694abee49dcf06e43365e57f5f8936d27bf8301cf", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 42, + "glyphCoverage": [ + 32, + 45, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 66, + 67, + 69, + 70, + 71, + 73, + 76, + 77, + 78, + 79, + 80, + 84, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 122 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.json" + }, + { + "signature": "sha256:4c02bbb44e95946998ba6f7a9f6fe441a39ea802e9562aa5aca6e61529396174", + "alias": null, + "baseName": null, + "glyphCount": 1, + "glyphCoverage": [ + 89 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2305.00007.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2305.00007.json" + }, + { + "signature": "sha256:4c893bb7bcf541a56a7f38b6722196a000c177ac4d2110166b16f3e76a4b8f5c", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 13, + "glyphCoverage": [ + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 53, + 70, + 72, + 91, + 93, + 101 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00016.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00016.json" + }, + { + "signature": "sha256:4c9a0502dc5d7f0903bba10747472c9eb8f8dc131fe4cb18dbfd62e27dd812e8", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 27, + "glyphCoverage": [ + 32, + 45, + 46, + 48, + 49, + 50, + 51, + 53, + 54, + 55, + 69, + 78, + 82, + 84, + 97, + 99, + 101, + 103, + 104, + 105, + 108, + 110, + 111, + 112, + 114, + 115, + 116 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.json" + }, + { + "signature": "sha256:4cbb76b3c46407f4ea315f53ac10f8123efc705553d6ca5d32b52fe9a1be283a", + "alias": "bitstreamverasans-roman", + "baseName": "BitstreamVeraSans-Roman", + "glyphCount": 43, + "glyphCoverage": [ + 32, + 35, + 40, + 41, + 44, + 45, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 65, + 66, + 69, + 70, + 73, + 77, + 78, + 83, + 84, + 86, + 87, + 97, + 99, + 100, + 101, + 103, + 105, + 107, + 108, + 109, + 110, + 112, + 114, + 115, + 116, + 117, + 118, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1312.6114.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1312.6114.json" + }, + { + "signature": "sha256:4d4ee6f04f57a40a589741df4747990ed485c192b0fc179a415aba822f352a8d", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 26, + "glyphCoverage": [ + 32, + 45, + 48, + 49, + 50, + 51, + 52, + 53, + 56, + 65, + 67, + 68, + 70, + 77, + 97, + 98, + 99, + 101, + 105, + 109, + 110, + 111, + 112, + 114, + 115, + 116 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:4f13b886c6b872a768bd7cd546fa8bbcc496f5424dd137ea59c5c69e2e167622", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 21, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 50, + 51, + 53, + 80, + 83, + 97, + 99, + 101, + 104, + 105, + 108, + 110, + 111, + 115, + 116, + 117, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.json" + }, + { + "signature": "sha256:4f28dc946824d9b97d7bacb9d0e03853743c579603872da4879304084ed39a6d", + "alias": null, + "baseName": null, + "glyphCount": 8, + "glyphCoverage": [ + 32, + 46, + 48, + 53, + 55, + 61, + 97, + 176 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2305.00007.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2305.00007.json" + }, + { + "signature": "sha256:4f310030314f055e2d959fb3daa229e1a59966832109affb01c368cb20c874d7", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 37, + "glyphCoverage": [ + 32, + 45, + 46, + 48, + 49, + 50, + 52, + 54, + 56, + 66, + 67, + 68, + 70, + 71, + 76, + 77, + 80, + 82, + 84, + 97, + 98, + 99, + 100, + 101, + 102, + 105, + 107, + 108, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 118, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2304.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2304.00012.json" + }, + { + "signature": "sha256:4f763d5e2cd0bdcd4650936ac505bd0e011899712ffe80ffa4b4d43f42941327", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 10, + "glyphCoverage": [ + 46, + 48, + 49, + 50, + 52, + 54, + 56, + 98, + 103, + 114 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:4fa06c90399d80b41cb718163a5d78af2b203df6b6579246fb0b24d349b7a591", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 15, + "glyphCoverage": [ + 46, + 48, + 49, + 50, + 52, + 53, + 54, + 56, + 97, + 98, + 99, + 105, + 108, + 115, + 118 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:4febfad91e0141f9658506a0bf8fc2a449f0ea7d97b44e95fc9a970c77af4b0a", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 7, + "glyphCoverage": [ + 48, + 49, + 50, + 51, + 52, + 53, + 54 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:50141e99cc1e280b78a2531f5f8f7350b296ad066f960d705bdc45d48526f8fc", + "alias": "palatino-roman", + "baseName": "EGEIJU+Palatino-Roman", + "glyphCount": 43, + "glyphCoverage": [ + 32, + 34, + 40, + 41, + 46, + 48, + 49, + 51, + 65, + 67, + 69, + 70, + 71, + 72, + 75, + 76, + 78, + 79, + 80, + 81, + 83, + 86, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 118, + 119, + 120, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00001.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00001.json" + }, + { + "signature": "sha256:5019e1aff533acc45cb2bbfdfd83bdb9c5937519563c958e908978413d4d75cd", + "alias": null, + "baseName": null, + "glyphCount": 2, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:5298a6127c429a48d60112795593883804cb2b74a7cb92739e8c4d14037b5497", + "alias": null, + "baseName": null, + "glyphCount": 2, + "glyphCoverage": [ + 32, + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.08774.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.08774.json" + }, + { + "signature": "sha256:52eb4662e08a3b60a44cfe5ee62510bcd8f2a5ffd86f6496d5b3b6835e318f8b", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 39, + "glyphCoverage": [ + 32, + 40, + 41, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 61, + 70, + 73, + 80, + 82, + 91, + 93, + 97, + 99, + 100, + 101, + 103, + 105, + 108, + 110, + 111, + 112, + 115, + 116, + 117, + 120 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00009.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00009.json" + }, + { + "signature": "sha256:53b67815e91cc99242c0b5710ba59895f6a591da5e08d91be72c901dabadf191", + "alias": "dejavusans-oblique", + "baseName": "GCWXDV+DejaVuSans-Oblique", + "glyphCount": 1, + "glyphCoverage": [ + 82 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00009.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00009.json" + }, + { + "signature": "sha256:543b46259bb4daa24226cce45f83eb055636cce227089eba299a02f2dd86cbf3", + "alias": null, + "baseName": null, + "glyphCount": 18, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:54a6c2e4bc290b48e21eece7f81cb6633c4b53a91f198fdaabfc73743b0e4499", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 15, + "glyphCoverage": [ + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 97, + 100, + 101, + 103, + 105, + 110, + 114, + 115 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:54a931c531b8def6b4628b3dba97984d51c1f086b5abcc00166bf3c982c4c7f9", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 29, + "glyphCoverage": [ + 32, + 40, + 41, + 45, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 58, + 80, + 83, + 84, + 87, + 101, + 105, + 107, + 109, + 111, + 114, + 115, + 116, + 119, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2307.00004.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2307.00004.json" + }, + { + "signature": "sha256:5575017eaa98bcb106114b201ac5519e600c1b9740ec8dff0cd1038fdc6deb66", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 39, + "glyphCoverage": [ + 32, + 44, + 45, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 61, + 67, + 68, + 73, + 76, + 82, + 84, + 86, + 87, + 97, + 99, + 101, + 104, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 119, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2010.11929.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2010.11929.json" + }, + { + "signature": "sha256:57aef5aad290ef2847fe0caaa6028aface85844dadcc6a9414029aa1538abff0", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 26, + "glyphCoverage": [ + 32, + 45, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 67, + 78, + 83, + 97, + 98, + 99, + 100, + 101, + 103, + 105, + 108, + 110, + 111, + 112, + 114, + 120, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.json" + }, + { + "signature": "sha256:581d2904886e9c8e2cfb71b688c7f92f62bd88e34a4013a8693d86a4c44636ae", + "alias": "cmr10", + "baseName": "Cmr10", + "glyphCount": 2, + "glyphCoverage": [ + 40, + 41 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.json" + }, + { + "signature": "sha256:588664897c6781b783d25d2bd89dcefb792084121851e45f95ecbffd3b093309", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 36, + "glyphCoverage": [ + 32, + 37, + 40, + 41, + 44, + 45, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 56, + 57, + 61, + 65, + 67, + 68, + 69, + 70, + 71, + 73, + 82, + 86, + 87, + 97, + 98, + 99, + 100, + 104, + 109, + 111, + 112, + 114, + 115 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.json" + }, + { + "signature": "sha256:5a347b104b595d0cf8615502eb781c8a1bdef0a22e2fade4e40e0dbb790d9a30", + "alias": null, + "baseName": null, + "glyphCount": 5, + "glyphCoverage": [ + 32, + 48, + 61, + 69, + 102 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2201.04294.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2201.04294.json" + }, + { + "signature": "sha256:5a99e90aec1437d08fcaadc143f88bc30da36e05bdf3160396237b1f0b4adbf0", + "alias": null, + "baseName": null, + "glyphCount": 10, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:5b535a05c982fb8ff029dfbedd5e9d28c1c4379ebac259d207f65606a94e5b15", + "alias": "cmr10", + "baseName": "Cmr10", + "glyphCount": 3, + "glyphCoverage": [ + 48, + 49, + 53 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:5b560f3c666ad08d06978b239872d1bfe85b3ee11479f328f4ed566462d8d8aa", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 28, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 69, + 79, + 80, + 82, + 97, + 100, + 101, + 105, + 109, + 110, + 111, + 112, + 114, + 115, + 119, + 120 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00004.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00004.json" + }, + { + "signature": "sha256:5c069239852d3a0fdccc1e12368872455c1bee618c341786a46f2ee45807a67d", + "alias": null, + "baseName": null, + "glyphCount": 12, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:5c957f6b746890ec59cbf2ecabe5affc5eb7a581fee670594c36d7b1e72b98e6", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 39, + "glyphCoverage": [ + 32, + 40, + 41, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 57, + 66, + 68, + 73, + 76, + 77, + 82, + 83, + 86, + 88, + 91, + 93, + 99, + 101, + 103, + 105, + 107, + 108, + 109, + 111, + 114, + 115, + 116, + 118, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.json" + }, + { + "signature": "sha256:5d8acd70451a75a37092adbf0e3d6f4beedb658591e5d86daafd495a64785bae", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 11, + "glyphCoverage": [ + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.json" + }, + { + "signature": "sha256:5ee4f9dc93537d1086527fdafd46c527f476a1ad970aa715ddcc673d520d1035", + "alias": null, + "baseName": null, + "glyphCount": 25, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 54, + 55, + 56, + 57, + 58, + 97, + 98, + 99, + 100, + 101, + 103, + 104, + 105, + 108, + 110, + 111, + 112, + 115, + 116, + 117, + 119 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.json" + }, + { + "signature": "sha256:6000d3494f9ef02f9cebae95fa0a72764935d68fc713761a2254be48a4d1d907", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 28, + "glyphCoverage": [ + 32, + 45, + 46, + 48, + 49, + 50, + 51, + 53, + 54, + 55, + 69, + 78, + 82, + 84, + 95, + 97, + 99, + 101, + 103, + 104, + 105, + 108, + 110, + 111, + 112, + 114, + 115, + 116 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.json" + }, + { + "signature": "sha256:611938c95103a5ae5382d7bfb64bf0c2e5b191911de8e0dc8143b08bb4660c03", + "alias": null, + "baseName": null, + "glyphCount": 10, + "glyphCoverage": [ + 32, + 40, + 41, + 69, + 86, + 101, + 103, + 110, + 114, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2201.04294.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2201.04294.json" + }, + { + "signature": "sha256:61b3bf0ef35c7a3c7b4db751da75cff24a7b38d65fbc343d10cb3c24c9364580", + "alias": null, + "baseName": null, + "glyphCount": 25, + "glyphCoverage": [ + 32, + 40, + 41, + 45, + 46, + 48, + 49, + 50, + 53, + 67, + 75, + 76, + 79, + 83, + 85, + 86, + 87, + 88, + 90, + 97, + 98, + 100, + 110, + 112, + 117 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2201.04294.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2201.04294.json" + }, + { + "signature": "sha256:61c7080b7a61078fcd5157b37df7b6a3f464e39cc0081339dccbbfd7232c25fb", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 50, + "glyphCoverage": [ + 32, + 40, + 41, + 45, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 61, + 66, + 67, + 69, + 70, + 71, + 74, + 76, + 77, + 79, + 82, + 83, + 84, + 87, + 91, + 93, + 97, + 98, + 99, + 100, + 101, + 103, + 104, + 105, + 107, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 118, + 119, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2301.00017.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2301.00017.json" + }, + { + "signature": "sha256:63009fad5b8ad4d7972b7084ef795870551a6c4441e484531ba68aa7739c318c", + "alias": null, + "baseName": null, + "glyphCount": 12, + "glyphCoverage": [ + 75, + 76, + 85, + 87, + 88, + 97, + 98, + 99, + 107, + 120, + 121, + 122 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2201.04294.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2201.04294.json" + }, + { + "signature": "sha256:6321f0c1ec2f2c22f57ec0c09c441185bb3eff73b420ddd00d90efa909d29038", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 30, + "glyphCoverage": [ + 32, + 40, + 41, + 44, + 46, + 48, + 49, + 50, + 51, + 53, + 65, + 77, + 80, + 83, + 87, + 91, + 93, + 101, + 102, + 103, + 105, + 107, + 109, + 110, + 111, + 114, + 115, + 116, + 119, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2307.00004.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2307.00004.json" + }, + { + "signature": "sha256:63828dfe9ee70c090bdf59a7de158766d67aa9ff30f815ade686350fc8f62b83", + "alias": null, + "baseName": null, + "glyphCount": 10, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:64f725573c1f5d90196e94ed338a7af06baf274420414befeb9693c80acd0f77", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 23, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 55, + 57, + 58, + 65, + 68, + 69, + 70, + 76, + 78, + 79, + 84, + 85, + 87, + 103, + 117 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:652efb0fc3d4dfee78e0b90693d5c9d8f5b19fff23c1933fda4ae415509fb30d", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 41, + "glyphCoverage": [ + 32, + 40, + 41, + 44, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 60, + 67, + 68, + 71, + 73, + 77, + 91, + 93, + 97, + 99, + 100, + 101, + 103, + 105, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 119, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:656b3d196ed0e1a09ab755310b4883a7c0962de3d249d46b01df580f1c1e6e40", + "alias": null, + "baseName": null, + "glyphCount": 18, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:65ffcd833031d0c359802c02186bdfd1e1c387dc6b72847b9303865be0456769", + "alias": "dejavusans-oblique", + "baseName": "DejaVuSans-Oblique", + "glyphCount": 8, + "glyphCoverage": [ + 69, + 74, + 76, + 82, + 86, + 90, + 110, + 122 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00016.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00016.json" + }, + { + "signature": "sha256:6651550d7b913850087244b7a70961989c2efc6d8c8d060d8663ff087b7723f6", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 20, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 50, + 52, + 54, + 56, + 97, + 100, + 101, + 104, + 105, + 108, + 110, + 111, + 112, + 115, + 116, + 119 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:66674d0ace7f240e2fbb291a2e8715ae51f13e8c190e34a5cecc4b9a7b43f95b", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 32, + "glyphCoverage": [ + 32, + 40, + 41, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 97, + 98, + 99, + 101, + 104, + 105, + 107, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 118, + 122 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2301.00013.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2301.00013.json" + }, + { + "signature": "sha256:67b3ed3158ed144d93abc08b2fe49fe7d3433016be0301208af17bd3a66f8e8d", + "alias": "cmr10", + "baseName": "Cmr10", + "glyphCount": 21, + "glyphCoverage": [ + 40, + 41, + 43, + 48, + 49, + 51, + 77, + 91, + 93, + 99, + 103, + 104, + 106, + 107, + 108, + 109, + 111, + 112, + 114, + 115, + 116 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.json" + }, + { + "signature": "sha256:683e07f4193f669d49b1c93173c9627e7acd23edec5008382260084064221689", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 31, + "glyphCoverage": [ + 32, + 44, + 45, + 46, + 48, + 49, + 50, + 51, + 53, + 55, + 56, + 57, + 61, + 65, + 67, + 68, + 69, + 70, + 71, + 73, + 76, + 82, + 83, + 86, + 87, + 98, + 99, + 104, + 111, + 112, + 115 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.json" + }, + { + "signature": "sha256:68a875646bc1c69346a22aa6a858075434c0e12f0d54efa4c42b64ae1551b68c", + "alias": null, + "baseName": null, + "glyphCount": 19, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 54, + 55, + 56, + 57, + 58, + 97, + 98, + 99, + 105, + 108, + 111, + 112, + 117, + 119, + 122 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.json" + }, + { + "signature": "sha256:6993cd9bd7386c729b87cca743cd628ec9f688bf19198d847d12b625b22eaef8", + "alias": null, + "baseName": null, + "glyphCount": 9, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 50, + 53, + 61, + 97, + 176 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2305.00007.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2305.00007.json" + }, + { + "signature": "sha256:6b4c16b6bb2330825f834978609e4de7e3355820e122ec11deb1650249764af8", + "alias": "palatino-roman", + "baseName": "EGEIJU+Palatino-Roman", + "glyphCount": 40, + "glyphCoverage": [ + 32, + 35, + 45, + 48, + 49, + 50, + 51, + 52, + 53, + 65, + 67, + 69, + 76, + 79, + 80, + 83, + 84, + 86, + 87, + 97, + 98, + 99, + 100, + 101, + 103, + 104, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 118, + 119, + 120, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00001.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00001.json" + }, + { + "signature": "sha256:6b989ec043774b2345e7ac7ede2effadf8bc34eedd47d3102cba66ffe46591be", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 21, + "glyphCoverage": [ + 32, + 40, + 41, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 69, + 74, + 76, + 86, + 99, + 101 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00016.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00016.json" + }, + { + "signature": "sha256:6c72170517812e39f970746f53a2ae08dafbbe7374c20bcb4d5a60adc49cb77b", + "alias": "cmmi10", + "baseName": "Cmmi10", + "glyphCount": 2, + "glyphCoverage": [ + 100, + 120 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:6caf025e6f409de91810f2f5d392e33f1ec71e6997b57b0e0459b5556eff7a71", + "alias": "dejavusans-oblique", + "baseName": "DejaVuSans-Oblique", + "glyphCount": 4, + "glyphCoverage": [ + 67, + 97, + 115, + 116 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.json" + }, + { + "signature": "sha256:6e16048bf42b562a37efbcfcd0ef87db28525edfdb6d79b7765b989df6a2c91c", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 12, + "glyphCoverage": [ + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 101 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.json" + }, + { + "signature": "sha256:6e36c48f41b7a29d62980fb0d0f731003982baf65ec4a7dafd29c3cf45e640a2", + "alias": null, + "baseName": null, + "glyphCount": 14, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:6eb31389446e876acbb037519cd2897cfe23d1c9af7a0d2f373966fa22830ae2", + "alias": null, + "baseName": null, + "glyphCount": 11, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:6ec425e56c9f32cf92b73fe0ce417416ca7a430661258ed1592908fe2d71737c", + "alias": null, + "baseName": null, + "glyphCount": 2, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:6f16a17b5695f85750d0d0b27a5fa7359f53d21ee24b5eccfbe2bf37b696070d", + "alias": "dejavusans-bold", + "baseName": "EVICAO+DejaVuSans-Bold", + "glyphCount": 21, + "glyphCoverage": [ + 32, + 49, + 50, + 51, + 52, + 58, + 65, + 67, + 68, + 69, + 70, + 73, + 76, + 77, + 78, + 79, + 80, + 82, + 83, + 84, + 88 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\testing\\crop_test.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\testing\\crop_test.json" + }, + { + "signature": "sha256:6fad64f19cd4239624711899235b074b7cb9c794aa0207eb13c0f89ac2a8383c", + "alias": null, + "baseName": null, + "glyphCount": 2, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:6fdba4fe991567e350e60e99d668199429528190bdf0fff4d4e80441a5254b52", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 36, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 69, + 72, + 75, + 77, + 82, + 83, + 84, + 91, + 93, + 97, + 99, + 100, + 101, + 102, + 105, + 108, + 109, + 111, + 112, + 114, + 115, + 116, + 117, + 118 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00009.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00009.json" + }, + { + "signature": "sha256:703615669f7857bed777c38355bc2af5a7d254a2b0f239b9bb530e34d3ca1915", + "alias": "dejavusans-oblique", + "baseName": "GCWXDV+DejaVuSans-Oblique", + "glyphCount": 2, + "glyphCoverage": [ + 70, + 122 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2301.00017.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2301.00017.json" + }, + { + "signature": "sha256:7082a280d783b968fe36bead39a0e74981e1ea344a8fab34cc0890f42cce8c9e", + "alias": "stixsizeonesym-regular", + "baseName": "JYHTGI+STIXSizeOneSym-Regular", + "glyphCount": 2, + "glyphCoverage": [ + 40, + 41 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00009.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00009.json" + }, + { + "signature": "sha256:708a7697cf6412e516903686943d96339efca3e8303d7254d2b5784b337bf3e0", + "alias": "cmmi10", + "baseName": "Cmmi10", + "glyphCount": 2, + "glyphCoverage": [ + 69, + 102 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.json" + }, + { + "signature": "sha256:72c7041f938222b87ce2d9295547f8c19edf250af538160b69be35a968d76ea7", + "alias": "f36", + "baseName": "F36", + "glyphCount": 1, + "glyphCoverage": [ + 136 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\08_matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\08_matplotlib.json" + }, + { + "signature": "sha256:72fca14e9e44fc41b0cdb1c6a088f0b07f882f9f04c51a0145f43cf8b285c5b6", + "alias": "sourcecodepro-regular", + "baseName": "NVMZUP+SourceCodePro-Regular", + "glyphCount": 11, + "glyphCoverage": [ + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\04_handout-intermediate.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\04_handout-intermediate.json" + }, + { + "signature": "sha256:73a21cbb320db80cd51a071ca6a6b3b903e444e161fe23a862319ce17b69aa47", + "alias": null, + "baseName": null, + "glyphCount": 20, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:7430d5b54fd0d583c4e5b226a4508141661f1690324478ce4a1b842a5c03dff6", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 9, + "glyphCoverage": [ + 65, + 73, + 101, + 105, + 110, + 111, + 112, + 116, + 117 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2010.11929.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2010.11929.json" + }, + { + "signature": "sha256:74e60bcb2d7975b0c7b372aca9fc25f55c9018005425a741830e7c4370b8d593", + "alias": "dejavusansmono", + "baseName": "DejaVuSansMono", + "glyphCount": 24, + "glyphCoverage": [ + 35, + 39, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 67, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 107, + 109, + 114, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:74ed6c591919637c1d69204056956e3f318cd8c5664fc29c694dd78cd269d13f", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 34, + "glyphCoverage": [ + 32, + 40, + 41, + 48, + 50, + 52, + 53, + 54, + 55, + 56, + 65, + 66, + 67, + 79, + 80, + 83, + 84, + 97, + 98, + 99, + 100, + 101, + 102, + 105, + 107, + 108, + 109, + 110, + 111, + 114, + 115, + 116, + 121, + 122 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.json" + }, + { + "signature": "sha256:74ff3fe841fc74fd1a687b3e4af39537f040b48d7c14a654f8ab4671d15bd8e5", + "alias": "stixgeneral-regular", + "baseName": "STIXGeneral-Regular", + "glyphCount": 44, + "glyphCoverage": [ + 32, + 37, + 44, + 45, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 61, + 65, + 67, + 69, + 71, + 73, + 76, + 78, + 80, + 83, + 84, + 91, + 93, + 97, + 99, + 101, + 102, + 103, + 104, + 105, + 107, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2010.11929.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2010.11929.json" + }, + { + "signature": "sha256:75466035ac34f2523215e599452e32d796d7d02bc7122ed3d02fe91ebe064c25", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 6, + "glyphCoverage": [ + 48, + 49, + 50, + 52, + 54, + 56 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\04_handout-intermediate.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\04_handout-intermediate.json" + }, + { + "signature": "sha256:7561cd9cb77d1cb3f5073facf1e648b32e3112854006ec3f0534e1c06783bcd7", + "alias": null, + "baseName": null, + "glyphCount": 22, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 50, + 54, + 55, + 56, + 57, + 58, + 97, + 98, + 101, + 103, + 108, + 110, + 111, + 112, + 114, + 115, + 116, + 118 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.json" + }, + { + "signature": "sha256:75f43b4037af9ea2e5012658e1b59be7de8b86f4c5b46400a52ae57255ce2a72", + "alias": null, + "baseName": null, + "glyphCount": 2, + "glyphCoverage": [ + 32, + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.08774.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.08774.json" + }, + { + "signature": "sha256:7603e9fa12959bb679edaa6a170228d0f1207d4096e74a10c17d9698fe1f5587", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 44, + "glyphCoverage": [ + 32, + 40, + 41, + 45, + 46, + 48, + 49, + 50, + 52, + 53, + 54, + 55, + 56, + 57, + 73, + 77, + 78, + 80, + 83, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 122 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00010.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00010.json" + }, + { + "signature": "sha256:76787bf3069ae9414467eaf64f002c929c9d744e178919334717c553cc471bd7", + "alias": null, + "baseName": null, + "glyphCount": 16, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:77e35e2a518db305c5b0c95d0108254cd309ef56c55cfd85e5d30cd50f0089e4", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 20, + "glyphCoverage": [ + 32, + 40, + 41, + 48, + 49, + 50, + 53, + 55, + 69, + 70, + 84, + 88, + 97, + 104, + 105, + 108, + 110, + 114, + 116, + 117 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00020.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00020.json" + }, + { + "signature": "sha256:786d4ac8896d3bd4711430467fb068a137469460c8455cdafb4f9911700cf352", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 36, + "glyphCoverage": [ + 32, + 40, + 41, + 45, + 46, + 48, + 49, + 50, + 52, + 53, + 54, + 55, + 56, + 57, + 66, + 67, + 68, + 69, + 82, + 97, + 99, + 100, + 101, + 104, + 105, + 106, + 108, + 109, + 110, + 111, + 114, + 115, + 116, + 117, + 120, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00020.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00020.json" + }, + { + "signature": "sha256:792a1c5aaa1743ab203a363a8f6cd07c3b043e33c72e97c4ea21f5862158e6c1", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 17, + "glyphCoverage": [ + 43, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 56, + 97, + 99, + 101, + 105, + 108, + 115, + 118 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:7abdc8bdcd9c57b08eff9965e833054538bab0c96e4851013d7a29aa40f14d30", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 29, + "glyphCoverage": [ + 32, + 45, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 56, + 57, + 61, + 69, + 76, + 98, + 99, + 101, + 102, + 103, + 104, + 105, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 119 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.json" + }, + { + "signature": "sha256:7ad13444946eeef22e6c03076c5865f195d930c447e878bc02072a4112284c84", + "alias": "cmmi10", + "baseName": "Cmmi10", + "glyphCount": 5, + "glyphCoverage": [ + 44, + 60, + 62, + 102, + 952 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.json" + }, + { + "signature": "sha256:7ae70f71e33fb8be83c0f96a728343fa4c4ab112d97b3cdd51ce021f62536333", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 37, + "glyphCoverage": [ + 32, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 65, + 67, + 68, + 73, + 74, + 76, + 77, + 78, + 80, + 82, + 83, + 84, + 85, + 86, + 87, + 99, + 100, + 101, + 110, + 111, + 114, + 115, + 116, + 117, + 202, + 218 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2306.00007.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2306.00007.json" + }, + { + "signature": "sha256:7aee217b7e5df84b3649ae306ce0f67c48f49e5d26ebb2b38f2eb9621527f326", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 18, + "glyphCoverage": [ + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 56, + 65, + 76, + 97, + 99, + 111, + 114, + 115, + 117, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.json" + }, + { + "signature": "sha256:7b2b3d6e7ceaa3228fa56fda0fdb6affe3b1d67583448d28e1f1a860e6cc0e2d", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 36, + "glyphCoverage": [ + 32, + 40, + 41, + 46, + 48, + 49, + 50, + 52, + 53, + 54, + 55, + 56, + 65, + 66, + 79, + 80, + 81, + 83, + 84, + 87, + 97, + 98, + 99, + 100, + 101, + 102, + 105, + 107, + 108, + 109, + 110, + 111, + 114, + 115, + 116, + 117 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.json" + }, + { + "signature": "sha256:7b9326fe59fb0635b364d6547ee0cedaab4c89a842ddf8e8ad0f8eaff9542494", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 34, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 68, + 78, + 80, + 83, + 97, + 98, + 99, + 100, + 101, + 103, + 104, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00010.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00010.json" + }, + { + "signature": "sha256:7c58690e079a85eaf8821f1fa1e571c55a9958ee143352192874c6c28cdf78a3", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 33, + "glyphCoverage": [ + 32, + 40, + 41, + 46, + 48, + 49, + 50, + 52, + 54, + 55, + 56, + 58, + 61, + 67, + 69, + 80, + 97, + 98, + 99, + 100, + 101, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 118, + 119 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.08774.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.08774.json" + }, + { + "signature": "sha256:7e05c074b630c0f3e1fc23537c22bf4b6191c783601e534cd156f71c1827702c", + "alias": null, + "baseName": null, + "glyphCount": 42, + "glyphCoverage": [ + 0, + 32, + 34, + 37, + 39, + 40, + 41, + 42, + 44, + 46, + 48, + 49, + 50, + 51, + 53, + 59, + 61, + 78, + 83, + 91, + 93, + 97, + 98, + 100, + 101, + 102, + 103, + 104, + 105, + 107, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 118, + 120, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\07_matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\07_matplotlib.json" + }, + { + "signature": "sha256:7e4d797b3786609a49dacf12fe96b4798fb11648d2a690f289b8808026e59bc0", + "alias": null, + "baseName": null, + "glyphCount": 21, + "glyphCoverage": [ + 32, + 46, + 48, + 50, + 56, + 57, + 58, + 97, + 98, + 99, + 100, + 101, + 107, + 108, + 111, + 112, + 114, + 116, + 117, + 118, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.json" + }, + { + "signature": "sha256:7e98a763ef3148cfe1f17ef3c50a2df96443b21c859d4afbcdadbb94b346e16d", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 28, + "glyphCoverage": [ + 32, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 65, + 67, + 68, + 69, + 73, + 76, + 77, + 80, + 82, + 97, + 99, + 101, + 102, + 103, + 105, + 106, + 110, + 111, + 115, + 116 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2304.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2304.00012.json" + }, + { + "signature": "sha256:7eb27a3176b2478fad4a5dc2a71e4a03d009738d2e8c9ca71c3a89dd677bac2d", + "alias": null, + "baseName": null, + "glyphCount": 24, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 56, + 57, + 58, + 97, + 98, + 99, + 101, + 104, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 117 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.json" + }, + { + "signature": "sha256:7f89f241e92830a2e93753e1bf7925df342e67e11ba79091f1c96aed1dc33d22", + "alias": null, + "baseName": null, + "glyphCount": 19, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 50, + 54, + 57, + 58, + 97, + 98, + 101, + 103, + 108, + 110, + 111, + 112, + 114, + 115, + 118 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.json" + }, + { + "signature": "sha256:805f0937581231472559296bc3b983ee56953963a71befea2db3f80e4e169469", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 46, + "glyphCoverage": [ + 32, + 40, + 41, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 66, + 67, + 70, + 71, + 73, + 75, + 76, + 77, + 79, + 80, + 83, + 84, + 90, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 107, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.json" + }, + { + "signature": "sha256:80ee335f8a77c56535bad4c5309445f768ff40a1949e889ff7c79c6e035b6210", + "alias": null, + "baseName": null, + "glyphCount": 19, + "glyphCoverage": [ + 32, + 46, + 48, + 52, + 54, + 55, + 56, + 57, + 58, + 97, + 101, + 104, + 108, + 110, + 111, + 112, + 114, + 115, + 116 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.json" + }, + { + "signature": "sha256:81c7174e391afe22839414b1e46ca6316eb018bf9acf0c73612bb874f5f1dadb", + "alias": "cmr10", + "baseName": "Cmr10", + "glyphCount": 7, + "glyphCoverage": [ + 48, + 49, + 50, + 52, + 53, + 54, + 8710 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.json" + }, + { + "signature": "sha256:81cd2d4d9353ee02c7ed80c2892658072b2a8bbd9ed1832b474129dfbe35d5d8", + "alias": "dejavusans-oblique", + "baseName": "DejaVuSans-Oblique", + "glyphCount": 13, + "glyphCoverage": [ + 70, + 71, + 85, + 87, + 100, + 101, + 103, + 109, + 112, + 114, + 116, + 118, + 120 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:82510d4ebc7e869dfa5d1e68131050dd2f5115ae6c3128e34f6da643079c6103", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 37, + "glyphCoverage": [ + 32, + 40, + 41, + 43, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 60, + 70, + 91, + 93, + 97, + 98, + 99, + 100, + 101, + 102, + 105, + 107, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00016.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00016.json" + }, + { + "signature": "sha256:831f7012db360331ffb5a5de6a6d6e03ffaad29f48d81cabe9fc613b25aad818", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 43, + "glyphCoverage": [ + 32, + 40, + 41, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 55, + 65, + 66, + 70, + 71, + 76, + 77, + 82, + 83, + 84, + 88, + 89, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 120, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\04_handout-intermediate.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\04_handout-intermediate.json" + }, + { + "signature": "sha256:84f4d0643ceb447fc569de7dea4c925144334262b838d9e59df7d9e5dcd5e9fe", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 22, + "glyphCoverage": [ + 32, + 40, + 41, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 72, + 76, + 85, + 99, + 101, + 103, + 105, + 109, + 111, + 114, + 115 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.json" + }, + { + "signature": "sha256:852a6f2bcfa3c28f7f9401b9781c38b72033072b47d43afc1945fe25a83e8cea", + "alias": "bitstreamverasans-roman", + "baseName": "BitstreamVeraSans-Roman", + "glyphCount": 27, + "glyphCoverage": [ + 32, + 40, + 41, + 46, + 48, + 49, + 50, + 51, + 52, + 54, + 56, + 97, + 99, + 100, + 101, + 103, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 118 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1411.4038.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1411.4038.json" + }, + { + "signature": "sha256:853422e67ac88fe7ae28d5c459dc9f5a84f24e7840eeb2d82a00719032119326", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 10, + "glyphCoverage": [ + 32, + 67, + 83, + 97, + 100, + 101, + 105, + 110, + 111, + 115 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\04_handout-intermediate.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\04_handout-intermediate.json" + }, + { + "signature": "sha256:859a048b15fefc3ff9defa947f6f8e9a05d5f5908d58c812c5f622124e9f6ba3", + "alias": "cmmi10", + "baseName": "Cmmi10", + "glyphCount": 1, + "glyphCoverage": [ + 78 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1312.6114.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1312.6114.json" + }, + { + "signature": "sha256:85e16e36ed0290c149647be7e468a7c46e7b66fd290131213040f7bad905aa44", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 25, + "glyphCoverage": [ + 32, + 45, + 46, + 48, + 49, + 50, + 52, + 53, + 54, + 56, + 95, + 97, + 98, + 101, + 102, + 103, + 104, + 105, + 108, + 111, + 114, + 116, + 117, + 120, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:861744d3427c3613b7d4c5768f0607686e1d1ac7e28f2698ae1a4f13c0dee047", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 33, + "glyphCoverage": [ + 32, + 40, + 41, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 57, + 61, + 97, + 98, + 99, + 100, + 101, + 103, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 118, + 119 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2301.00013.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2301.00013.json" + }, + { + "signature": "sha256:86f88670f5a652fcdc32a9db52ddfff8f2c60f883224f8e2ea34b3cb38f838ab", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 46, + "glyphCoverage": [ + 32, + 45, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 56, + 65, + 66, + 67, + 68, + 71, + 75, + 77, + 80, + 81, + 82, + 83, + 84, + 86, + 87, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 107, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 118, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.json" + }, + { + "signature": "sha256:874fd92cd011b0e9a85b4dd20178bf55e6a6b8028b0676bf599c96ff1cb6e1fb", + "alias": "cmmi10", + "baseName": "Cmmi10", + "glyphCount": 6, + "glyphCoverage": [ + 67, + 97, + 115, + 116, + 957, + 963 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.json" + }, + { + "signature": "sha256:88758adf0b41a81204ed3ad63463f5d15c7c2f80e8942cee501d06fa7274dc4e", + "alias": "dejavusansmono", + "baseName": "DejaVuSansMono", + "glyphCount": 8, + "glyphCoverage": [ + 97, + 98, + 105, + 108, + 109, + 111, + 112, + 116 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:88b3471db1978cc83233f249453806a8369c766b089b424c86c2584196ed5dbf", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 14, + "glyphCoverage": [ + 46, + 48, + 49, + 50, + 52, + 54, + 56, + 100, + 101, + 102, + 105, + 108, + 110, + 117 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:891adc39642b88483fb0482b8cf16a4c549d2aedb3cd78b3b7b4dfa33fec1f4b", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 37, + "glyphCoverage": [ + 32, + 40, + 41, + 42, + 45, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 65, + 67, + 72, + 76, + 82, + 84, + 97, + 99, + 101, + 103, + 104, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.json" + }, + { + "signature": "sha256:89a981143509d54718aa9dfca9fc11145a5becc5df1bbc64d635c2dfab9a49ea", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 28, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 50, + 51, + 53, + 65, + 67, + 71, + 73, + 77, + 78, + 80, + 83, + 97, + 99, + 101, + 104, + 105, + 107, + 108, + 110, + 111, + 115, + 116, + 117, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.json" + }, + { + "signature": "sha256:8a396afacf836b2ea2b014af12f8e3798c47f7d618fe90eb3ce37c47e39be63a", + "alias": null, + "baseName": null, + "glyphCount": 1, + "glyphCoverage": [ + 90 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2306.00004.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2306.00004.json" + }, + { + "signature": "sha256:8a5c6254c3a05c8bc22fda32a45772e0248e3acf027706ae0bcd8d104a196ff3", + "alias": "bitstreamverasans-roman", + "baseName": "BitstreamVeraSans-Roman", + "glyphCount": 33, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 65, + 68, + 71, + 73, + 76, + 77, + 78, + 82, + 83, + 84, + 97, + 99, + 100, + 101, + 103, + 105, + 109, + 110, + 111, + 114, + 115, + 116, + 118 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1412.6980.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1412.6980.json" + }, + { + "signature": "sha256:8bf157c405871571d1c37500498905a960c6431643d0820d067169bf388ed63c", + "alias": "dejavusans-oblique", + "baseName": "DejaVuSans-Oblique", + "glyphCount": 4, + "glyphCoverage": [ + 78, + 105, + 110, + 111 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.json" + }, + { + "signature": "sha256:8d93c4deb0ab769facc017f4a68d094725d4c76ccc1a686be91dd9c32724390b", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 38, + "glyphCoverage": [ + 32, + 45, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 66, + 67, + 69, + 71, + 75, + 76, + 77, + 80, + 83, + 97, + 99, + 101, + 102, + 104, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 118, + 120, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2306.00008.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2306.00008.json" + }, + { + "signature": "sha256:8e701a39dab65dd40890e2da106797b8e7880d1071e0f1964a13186107a35ef2", + "alias": null, + "baseName": null, + "glyphCount": 19, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 56, + 57, + 58, + 97, + 99, + 101, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.json" + }, + { + "signature": "sha256:8e9c421c2dc17e2c7694455a378a38a6618dcf63e3c0fea4ce6c709b3a068407", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 30, + "glyphCoverage": [ + 32, + 40, + 41, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 66, + 72, + 77, + 80, + 97, + 98, + 99, + 100, + 101, + 102, + 105, + 109, + 110, + 114, + 115, + 116, + 117 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.json" + }, + { + "signature": "sha256:8f7bf7a6382e8a762c5a84f19f84f0675f61eb1b34bd42562c0b3ac6712e29ef", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 2, + "glyphCoverage": [ + 48, + 49 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\04_handout-intermediate.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\04_handout-intermediate.json" + }, + { + "signature": "sha256:903f072de2bc044c8f76e9e106989e46b71f8cd6f966dae7c19413af992a1725", + "alias": "cmr10", + "baseName": "Cmr10", + "glyphCount": 16, + "glyphCoverage": [ + 48, + 53, + 67, + 97, + 99, + 101, + 103, + 104, + 108, + 111, + 112, + 114, + 115, + 116, + 117, + 118 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.json" + }, + { + "signature": "sha256:9177a4d5b120f039dece394da53064196d859ed953ee7bb5c7a582c90fb8c59f", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 36, + "glyphCoverage": [ + 32, + 40, + 41, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 65, + 66, + 78, + 79, + 80, + 81, + 83, + 84, + 97, + 98, + 99, + 100, + 101, + 102, + 105, + 107, + 108, + 109, + 110, + 111, + 114, + 115, + 116, + 117 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.json" + }, + { + "signature": "sha256:91aeef8b175fbd35a92d59e42e03489c7f04c8ccb2530809d30269f69d2bc8dc", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 37, + "glyphCoverage": [ + 32, + 45, + 46, + 48, + 49, + 50, + 52, + 54, + 56, + 58, + 66, + 67, + 68, + 70, + 71, + 73, + 76, + 77, + 80, + 82, + 83, + 84, + 97, + 98, + 99, + 101, + 105, + 106, + 107, + 108, + 110, + 111, + 112, + 114, + 115, + 116, + 117 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2304.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2304.00012.json" + }, + { + "signature": "sha256:922646358978a6a6210de5315dc3c6cef2b817152bd38c48a92f8d0c342a75d9", + "alias": "cmmi10", + "baseName": "Cmmi10", + "glyphCount": 5, + "glyphCoverage": [ + 78, + 104, + 118, + 120, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.json" + }, + { + "signature": "sha256:93573cb1ab32b9cb09378298fb120de079f6a309908d2ee86f91392a6aba5c31", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 30, + "glyphCoverage": [ + 32, + 45, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 65, + 67, + 68, + 70, + 77, + 97, + 98, + 99, + 101, + 105, + 109, + 110, + 111, + 112, + 114, + 115, + 116 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:93723fe436a1aa654db56caf133f56280444b9dc0682af50b83787c3e49ee3ec", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 16, + "glyphCoverage": [ + 32, + 48, + 49, + 50, + 52, + 53, + 54, + 56, + 58, + 97, + 99, + 105, + 108, + 110, + 115, + 116 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:946e0daf5d8e354542c10f94a3099770045cc3a9c43787a72274c2a6408f4a07", + "alias": null, + "baseName": null, + "glyphCount": 13, + "glyphCoverage": [ + 40, + 41, + 47, + 67, + 79, + 83, + 86, + 90, + 97, + 98, + 99, + 100, + 110 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2201.04294.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2201.04294.json" + }, + { + "signature": "sha256:94fc027572c60a0956a886cd2c68ed96e78a7faeb5af345c4ac9b85d8f498639", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 27, + "glyphCoverage": [ + 32, + 48, + 49, + 50, + 51, + 52, + 53, + 65, + 66, + 68, + 69, + 73, + 76, + 77, + 80, + 82, + 97, + 99, + 101, + 102, + 103, + 105, + 106, + 110, + 111, + 115, + 116 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2304.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2304.00012.json" + }, + { + "signature": "sha256:950616e99476024b6f5d41a956c5e097f411a96faa5d5c25429d7db7f3311ba2", + "alias": null, + "baseName": null, + "glyphCount": 18, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:95215d0212f4c05cc2f76520739441a4bb070e7c4a63f79fd9a6e1b0f0f37bc5", + "alias": "dejavusans-oblique", + "baseName": "DejaVuSans-Oblique", + "glyphCount": 1, + "glyphCoverage": [ + 86 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00016.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00016.json" + }, + { + "signature": "sha256:9562c3ff5956b1015307d263db1c9dd4902486496fb031ee4cbce2f35be9c33a", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 36, + "glyphCoverage": [ + 32, + 43, + 45, + 48, + 49, + 50, + 53, + 65, + 68, + 71, + 73, + 77, + 78, + 80, + 82, + 83, + 84, + 97, + 99, + 100, + 101, + 103, + 105, + 107, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 118, + 119, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1412.6980.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1412.6980.json" + }, + { + "signature": "sha256:95e1b7cc9f3e05a608f60ce63867edc1e2bf3ea9439f5ebdf8f024617946dcca", + "alias": null, + "baseName": null, + "glyphCount": 12, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:95fce9b4fb1df3d88165775b2c3975736028fc03b2d58ac23323022313c682e0", + "alias": "cmr10", + "baseName": "Cmr10", + "glyphCount": 22, + "glyphCoverage": [ + 48, + 49, + 52, + 53, + 54, + 55, + 57, + 61, + 91, + 93, + 99, + 100, + 101, + 103, + 104, + 108, + 111, + 112, + 114, + 116, + 117, + 120 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.json" + }, + { + "signature": "sha256:9648dcd0a82d06fd02d2622bd92a5a505d6182d1bc587c0730d7e49aeff320ef", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 36, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 56, + 68, + 69, + 73, + 77, + 78, + 80, + 83, + 91, + 93, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 105, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 120 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00010.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00010.json" + }, + { + "signature": "sha256:969dba20d6519197e9ff31fd1bf2c51e0243e988cd2fbc5e3861b1a7aa9081d1", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 29, + "glyphCoverage": [ + 32, + 40, + 41, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 80, + 84, + 87, + 99, + 100, + 101, + 105, + 107, + 109, + 111, + 114, + 116, + 117, + 119 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2307.00004.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2307.00004.json" + }, + { + "signature": "sha256:96ba693001b2ab224ad5b5a7464cecd4d33e68f30fb23f78a8473dbb031ce246", + "alias": "sourcecodepro-regular", + "baseName": "NVMZUP+SourceCodePro-Regular", + "glyphCount": 11, + "glyphCoverage": [ + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 67 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\04_handout-intermediate.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\04_handout-intermediate.json" + }, + { + "signature": "sha256:96ed7774c406b3fd815a9dc875057da7f370a51a25558f5afdd73ff5146be46c", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 43, + "glyphCoverage": [ + 32, + 45, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 65, + 67, + 69, + 76, + 77, + 78, + 80, + 81, + 82, + 83, + 84, + 97, + 98, + 99, + 100, + 101, + 102, + 104, + 105, + 108, + 109, + 110, + 111, + 114, + 115, + 116, + 117, + 118, + 121, + 122 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.json" + }, + { + "signature": "sha256:9861718b01c9e30c146934e157707d933f21b6181d9b74770fc0bdcc0922d080", + "alias": "dejavusans-bold", + "baseName": "DejaVuSans-Bold", + "glyphCount": 5, + "glyphCoverage": [ + 40, + 41, + 97, + 98, + 99 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.json" + }, + { + "signature": "sha256:988490b2d00e1e972e26087a6a9bddd8e4c8e86ab9c4eb7688ea47783d099c71", + "alias": "bitstreamverasans-roman", + "baseName": "BitstreamVeraSans-Roman", + "glyphCount": 43, + "glyphCoverage": [ + 32, + 40, + 41, + 43, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 56, + 57, + 65, + 68, + 77, + 78, + 80, + 82, + 83, + 86, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 118, + 120 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1504.08083.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1504.08083.json" + }, + { + "signature": "sha256:994c963d70041eee141fd275fa22c525a71283de2b4a952814d02e0bbfa8caea", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 4, + "glyphCoverage": [ + 46, + 48, + 49, + 53 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:9958bc1f309f6bafb55834e271bb0b337704fcac51f6d989abe9553fcffa103d", + "alias": null, + "baseName": null, + "glyphCount": 15, + "glyphCoverage": [ + 0, + 46, + 97, + 98, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\07_matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\07_matplotlib.json" + }, + { + "signature": "sha256:995f39de28909f7dc7f2fe152bd5eed8633e88b76b63f2af201d8244e6902f61", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 37, + "glyphCoverage": [ + 32, + 40, + 41, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 56, + 72, + 76, + 77, + 78, + 84, + 86, + 97, + 99, + 100, + 101, + 104, + 105, + 107, + 108, + 110, + 111, + 112, + 114, + 115, + 116, + 119, + 120, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2010.11929.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2010.11929.json" + }, + { + "signature": "sha256:9976ae3253dd4c3acdc176d6825321ae25a7d33cc402d9505c695fd4f3dd605c", + "alias": null, + "baseName": null, + "glyphCount": 22, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 50, + 52, + 54, + 55, + 56, + 57, + 58, + 97, + 99, + 101, + 107, + 110, + 111, + 112, + 114, + 115, + 116, + 117 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.json" + }, + { + "signature": "sha256:99a866d34ccdbec3c87f78722c5e79a0929f34adb4e5508b73a6c5e55752b444", + "alias": "stixgeneral-regular", + "baseName": "STIXGeneral-Regular", + "glyphCount": 41, + "glyphCoverage": [ + 32, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 53, + 54, + 55, + 65, + 66, + 70, + 73, + 76, + 78, + 79, + 80, + 82, + 84, + 86, + 91, + 93, + 97, + 99, + 101, + 103, + 104, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 120, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2010.11929.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2010.11929.json" + }, + { + "signature": "sha256:99f551631bc66fe6a028fb737f2621867a74f7614c8a5045513a47641be893ab", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 29, + "glyphCoverage": [ + 32, + 40, + 41, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 97, + 98, + 99, + 100, + 101, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 118, + 119 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2301.00013.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2301.00013.json" + }, + { + "signature": "sha256:9a701e082ba5a779e2b20b8de0c7844b3f7838ba8cd4bd7ef366893761fb994d", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 10, + "glyphCoverage": [ + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:9b8b6a218e7ae50c83a959fcee95c4154565cf281317115bbefcc3d04d35af53", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 4, + "glyphCoverage": [ + 48, + 49, + 53, + 215 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00020.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00020.json" + }, + { + "signature": "sha256:9c67df2ac5c3dcf957dfb0cd048fa450322a72b5a2dfb05f816c536b3b090607", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 19, + "glyphCoverage": [ + 32, + 39, + 46, + 48, + 49, + 50, + 53, + 58, + 97, + 99, + 100, + 101, + 105, + 106, + 108, + 114, + 115, + 116, + 118 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:9d90f239030c43adaed17ee256ffd6f7abefca236cca4a5cbd453c09d1d205ef", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 19, + "glyphCoverage": [ + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 65, + 76, + 97, + 99, + 111, + 114, + 115, + 117, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.json" + }, + { + "signature": "sha256:9dd45be55386ab1cb42fe3a126c45ff86cf3950772347406ca45e276febf81de", + "alias": null, + "baseName": null, + "glyphCount": 15, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:a0020a91df99a0673c180603a354d7f4266574c89ae3b036191226b0a0c36e60", + "alias": "stixgeneral-regular", + "baseName": "STIXGeneral-Regular", + "glyphCount": 44, + "glyphCoverage": [ + 32, + 37, + 45, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 65, + 66, + 70, + 72, + 73, + 74, + 76, + 77, + 78, + 80, + 84, + 86, + 91, + 93, + 97, + 99, + 100, + 101, + 103, + 105, + 107, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2010.11929.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2010.11929.json" + }, + { + "signature": "sha256:a02de4489c20d5c87e99220a380f3e79c683f4d7208339b6f4123aa4cafb0c92", + "alias": null, + "baseName": null, + "glyphCount": 15, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:a0d80b4792100d3804ab6bdb14aba4277bcf7617dd7e7c1ed63bbe9b496b8ffa", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 39, + "glyphCoverage": [ + 32, + 40, + 41, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 72, + 73, + 76, + 77, + 82, + 83, + 85, + 86, + 88, + 91, + 93, + 99, + 101, + 103, + 105, + 107, + 108, + 109, + 111, + 114, + 115, + 116, + 118, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.json" + }, + { + "signature": "sha256:a0e524e99a3c79b6480ed166b9b030dce72e15aa29d7d87013601fa921a10272", + "alias": "stixgeneral-regular", + "baseName": "STIXGeneral-Regular", + "glyphCount": 41, + "glyphCoverage": [ + 32, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 53, + 54, + 55, + 65, + 66, + 73, + 78, + 80, + 82, + 84, + 86, + 91, + 93, + 97, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 107, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 120, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2010.11929.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2010.11929.json" + }, + { + "signature": "sha256:a0f23d0b2ce8c2b23e869bc688989b3ee5da26734d868683541613f3c773f1ea", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 17, + "glyphCoverage": [ + 32, + 40, + 41, + 48, + 49, + 50, + 53, + 70, + 74, + 78, + 83, + 85, + 97, + 105, + 108, + 110, + 117 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00020.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00020.json" + }, + { + "signature": "sha256:a1049a6f44e90f70968099ea0066d9e6716b4bb8e36e468c1a13c3685835f077", + "alias": "dejavusans-oblique", + "baseName": "DejaVuSans-Oblique", + "glyphCount": 6, + "glyphCoverage": [ + 67, + 72, + 78, + 97, + 115, + 116 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.json" + }, + { + "signature": "sha256:a15cc90b7fc110cef4f07fe8a692d572e1289a9ee29c95732294662fded4e042", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 16, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 50, + 51, + 53, + 79, + 83, + 97, + 100, + 102, + 103, + 104, + 105, + 110 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:a18d2a2ba3bbabd476ad4cc1e654e18529a7f66f68176b08e8013ddedcc86314", + "alias": "cmb10", + "baseName": "Cmb10", + "glyphCount": 1, + "glyphCoverage": [ + 120 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.json" + }, + { + "signature": "sha256:a1d729ea5972f60108d8d8009796d274342192f918e0da91416650e4df633888", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 37, + "glyphCoverage": [ + 32, + 34, + 37, + 40, + 41, + 48, + 49, + 50, + 51, + 52, + 54, + 56, + 65, + 70, + 72, + 77, + 78, + 83, + 97, + 98, + 99, + 101, + 102, + 103, + 104, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 118, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.json" + }, + { + "signature": "sha256:a26cac6893ee8d762be942b42c87d3c9141a8ed6101a5ff7f893480a65e33f01", + "alias": "dejavusans-oblique", + "baseName": "DejaVuSans-Oblique", + "glyphCount": 1, + "glyphCoverage": [ + 197 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00010.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00010.json" + }, + { + "signature": "sha256:a31ac5a47cff9dc39638bcad65dd6954cb3339ca0255e3b1372d041805a4e2d0", + "alias": "bitstreamverasans-roman", + "baseName": "BitstreamVeraSans-Roman", + "glyphCount": 33, + "glyphCoverage": [ + 32, + 43, + 45, + 48, + 49, + 50, + 51, + 52, + 53, + 65, + 67, + 68, + 70, + 71, + 73, + 78, + 82, + 83, + 97, + 99, + 100, + 101, + 103, + 105, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 118 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1412.6980.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1412.6980.json" + }, + { + "signature": "sha256:a3eb7054e426aad7d1fac1f39ad6d3f886e34c04f780def5cf22b53cb3a45b46", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 15, + "glyphCoverage": [ + 46, + 48, + 49, + 50, + 52, + 53, + 54, + 55, + 56, + 97, + 99, + 105, + 108, + 115, + 118 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:a41c81ff2fe72249df34bd3ec46f54b565362e6d7ad976365baad7e7d59f234a", + "alias": null, + "baseName": null, + "glyphCount": 14, + "glyphCoverage": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 48, + 49 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2305.00007.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2305.00007.json" + }, + { + "signature": "sha256:a648cb0524465bcb3bf4a2f65e0761cfc5167b1871a7db9488bee11b56062727", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 14, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 50, + 52, + 53, + 54, + 56, + 58, + 105, + 110, + 116, + 118 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:a88dbd41f5f97482141effaf8f2116c28e072a5a90c49af66c54a50899f064c1", + "alias": null, + "baseName": null, + "glyphCount": 27, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:a8b014bb1f8f28c5ad63b130f146c1aad6b35c3544ab7ed29a1f2a382e1ebae0", + "alias": null, + "baseName": null, + "glyphCount": 21, + "glyphCoverage": [ + 32, + 46, + 48, + 50, + 54, + 55, + 56, + 57, + 58, + 97, + 99, + 101, + 104, + 105, + 107, + 110, + 111, + 112, + 114, + 115, + 116 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.json" + }, + { + "signature": "sha256:a9a381e03100d1cd9cbe86133477f4fa9ea781a5ca542e87c0e69227efa008c8", + "alias": "cmb10", + "baseName": "Cmb10", + "glyphCount": 1, + "glyphCoverage": [ + 122 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1312.6114.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1312.6114.json" + }, + { + "signature": "sha256:a9adcf5a6accb01a9dd970bbd0e2145dafc3d4833cbdd549e6d037ed9a65b7e6", + "alias": "cmex10", + "baseName": "Cmex10", + "glyphCount": 4, + "glyphCoverage": [ + 163, + 164, + 173, + 174 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.json" + }, + { + "signature": "sha256:aae1797f3e3ff55d71b02590333aff86663d6bb4a5768bed7550e5987f40afe8", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 14, + "glyphCoverage": [ + 46, + 48, + 49, + 50, + 52, + 53, + 54, + 56, + 97, + 99, + 105, + 108, + 115, + 118 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:ab15d7137e06c0836d8848bb31e0b4f64de33719b3d248b4f61d9c4727955133", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 36, + "glyphCoverage": [ + 32, + 40, + 41, + 45, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 67, + 79, + 80, + 83, + 97, + 99, + 100, + 101, + 103, + 104, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00020.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00020.json" + }, + { + "signature": "sha256:ac6756c76d6e43b771cc1e643dfc7891dfaaac05aa5e302190d0a662838ab031", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 13, + "glyphCoverage": [ + 46, + 48, + 49, + 50, + 51, + 53, + 55, + 97, + 99, + 105, + 108, + 115, + 118 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:acf93243b66b7209865389605b1234ccde626974f542d91d20092a7ed8718e13", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 24, + "glyphCoverage": [ + 32, + 40, + 41, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 56, + 66, + 68, + 76, + 99, + 101, + 103, + 105, + 109, + 111, + 114, + 115 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.json" + }, + { + "signature": "sha256:ae77c4eb2c49f72c616272f3d7ac624ddb0b4db1c77acbe6b9d13531f68e1d5d", + "alias": "dejavusansdisplay", + "baseName": "DejaVuSansDisplay", + "glyphCount": 0, + "glyphCoverage": null, + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:af0f63f52c5fbd14ebcafa76012a08cee05ca3fbe11202c0bbc51c0c411abd76", + "alias": "dejavusans-oblique", + "baseName": "DejaVuSans-Oblique", + "glyphCount": 2, + "glyphCoverage": [ + 120, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00020.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00020.json" + }, + { + "signature": "sha256:af54ae7026c8db94b144bc5e6c6c22a9cfb55553c289aa1767c6e6dead471cc4", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 30, + "glyphCoverage": [ + 32, + 40, + 41, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 56, + 57, + 97, + 98, + 99, + 101, + 105, + 107, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 118 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2301.00013.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2301.00013.json" + }, + { + "signature": "sha256:af56d052534f88474774c6eb2d406b8d555bfd4042bfef76fb463b09e10e5f8a", + "alias": "dejavusans-oblique", + "baseName": "DejaVuSans-Oblique", + "glyphCount": 1, + "glyphCoverage": [ + 82 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00016.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00016.json" + }, + { + "signature": "sha256:b159cb2a727380dad51350865849c716a83defa9abe73f57bcaf56679b62f25e", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 30, + "glyphCoverage": [ + 32, + 40, + 41, + 44, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 76, + 78, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 105, + 108, + 109, + 110, + 111, + 114, + 115, + 116, + 117, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00010.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00010.json" + }, + { + "signature": "sha256:b1f86a1809b10e3ce29762d306dcd36de1d6dc5ae867854924f07b0d9ac2e21c", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 22, + "glyphCoverage": [ + 32, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 74, + 87, + 99, + 100, + 101, + 103, + 109, + 110, + 111, + 114, + 115, + 116, + 117 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2306.00007.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2306.00007.json" + }, + { + "signature": "sha256:b2335a0e1e06d17861be11dc34c9f4415937d3a67d8b7c8ee971972737a00c64", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 35, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 65, + 67, + 68, + 73, + 76, + 77, + 78, + 80, + 82, + 87, + 97, + 99, + 100, + 101, + 103, + 104, + 105, + 108, + 109, + 111, + 112, + 115, + 116, + 117, + 118, + 122 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2010.11929.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2010.11929.json" + }, + { + "signature": "sha256:b269fc4ddc43553ccf4610a7ca68333b1278a82880172c929141ea68b32d5d6e", + "alias": null, + "baseName": null, + "glyphCount": 11, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:b26b9a336fe43b0d9d2932ab86f4b67a6d3c4c580d585d45aed470ae3b369371", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 34, + "glyphCoverage": [ + 32, + 37, + 40, + 41, + 44, + 45, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 56, + 57, + 61, + 65, + 67, + 68, + 69, + 70, + 71, + 73, + 82, + 83, + 86, + 87, + 98, + 99, + 104, + 111, + 112, + 114, + 115 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.json" + }, + { + "signature": "sha256:b318f65b9dc209eb6f004e3a6c20a772ebbca3d752adc10c66a6a8a479da2838", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 20, + "glyphCoverage": [ + 32, + 40, + 41, + 46, + 48, + 49, + 50, + 52, + 53, + 54, + 55, + 56, + 101, + 105, + 109, + 110, + 112, + 115, + 116, + 120 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:b3523cf0e6659e2fa25d74457f671b63217474cf660c1966aed489c42bfa301d", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 36, + "glyphCoverage": [ + 32, + 45, + 48, + 49, + 53, + 54, + 55, + 56, + 57, + 66, + 67, + 69, + 73, + 76, + 78, + 80, + 83, + 85, + 97, + 98, + 99, + 100, + 101, + 103, + 104, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 119, + 120 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2307.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2307.00012.json" + }, + { + "signature": "sha256:b4158afb55f335307d668aeedaa15a0bba1cfa987e6197f5268a424dc527f225", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 44, + "glyphCoverage": [ + 32, + 40, + 41, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 56, + 64, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 75, + 76, + 77, + 80, + 83, + 84, + 97, + 98, + 99, + 100, + 101, + 102, + 105, + 107, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 117, + 118, + 120 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.json" + }, + { + "signature": "sha256:b42182c55ec4bd53ab0698bee5f92945921dbccb534fdb5c6b41f1782e1fe88e", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 7, + "glyphCoverage": [ + 32, + 48, + 49, + 50, + 51, + 53, + 65 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\04_handout-intermediate.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\04_handout-intermediate.json" + }, + { + "signature": "sha256:b5064b202eb1dae41545eddf674ee23bd82176e76aac8eb749540c2689f2e3ec", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 33, + "glyphCoverage": [ + 32, + 33, + 37, + 48, + 49, + 50, + 52, + 53, + 54, + 68, + 70, + 72, + 83, + 84, + 87, + 97, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 108, + 109, + 110, + 111, + 114, + 115, + 116, + 117, + 119, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:b60a4423b811afc89a7c957c1e1a5a000ab87865f3bae1b8ac151f84e35f923e", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 31, + "glyphCoverage": [ + 32, + 40, + 41, + 45, + 48, + 49, + 50, + 51, + 52, + 54, + 56, + 57, + 70, + 78, + 80, + 83, + 97, + 98, + 99, + 100, + 101, + 103, + 104, + 105, + 108, + 109, + 110, + 115, + 117, + 120, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00010.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00010.json" + }, + { + "signature": "sha256:b6e5518f75caaebb807cbcec5a5b0b5dc81f7b9240329662fd47fc7cf845ba70", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 30, + "glyphCoverage": [ + 32, + 45, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 56, + 66, + 69, + 76, + 77, + 80, + 83, + 85, + 97, + 98, + 99, + 100, + 101, + 102, + 104, + 108, + 110, + 111, + 114, + 115, + 116 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.json" + }, + { + "signature": "sha256:b7140d811fcca3ded1288255dcad84c5226b7aaa34187d81ee0c4fe21d358a4c", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 35, + "glyphCoverage": [ + 32, + 43, + 45, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 56, + 67, + 77, + 78, + 80, + 83, + 88, + 97, + 98, + 99, + 100, + 101, + 103, + 105, + 108, + 110, + 111, + 112, + 114, + 116, + 117, + 120, + 121, + 122 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.json" + }, + { + "signature": "sha256:b792970d7d918456323f3e4c7ffd1f374517050bb933125d58c1118a56d19f37", + "alias": null, + "baseName": null, + "glyphCount": 26, + "glyphCoverage": [ + 32, + 46, + 48, + 50, + 52, + 53, + 55, + 56, + 57, + 58, + 97, + 98, + 99, + 100, + 101, + 103, + 104, + 105, + 108, + 110, + 111, + 112, + 114, + 115, + 116, + 119 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.json" + }, + { + "signature": "sha256:b79d844da5e5d8a2c37d34ced78f7c8aab9bd37b6a576b84d24ac31e757cd818", + "alias": null, + "baseName": null, + "glyphCount": 10, + "glyphCoverage": [ + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2010.11929.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2010.11929.json" + }, + { + "signature": "sha256:b7cc74c670d548e2dc2e3b2f12410db34a6e2aa7a16054df340972f561678b70", + "alias": null, + "baseName": null, + "glyphCount": 23, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 53, + 54, + 55, + 56, + 58, + 97, + 98, + 99, + 100, + 101, + 103, + 104, + 105, + 108, + 110, + 114, + 115, + 116, + 118 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.json" + }, + { + "signature": "sha256:b8e89dded5b267184191364ed46c4a1be3b19c74135ff2c106f76c53e880b61a", + "alias": "timesnewromanpsmt", + "baseName": "TimesNewRomanPSMT", + "glyphCount": 44, + "glyphCoverage": [ + 32, + 38, + 40, + 41, + 43, + 44, + 46, + 47, + 65, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 75, + 76, + 77, + 78, + 80, + 83, + 84, + 86, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 119, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2112.07804.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2112.07804.json" + }, + { + "signature": "sha256:b90a773646e512d592aec82ebc4f99d629c2de5aa19d4a0da5d0c3fddd32e33a", + "alias": "f146", + "baseName": "F146", + "glyphCount": 60, + "glyphCoverage": [ + 34, + 39, + 44, + 45, + 46, + 48, + 49, + 50, + 53, + 54, + 56, + 57, + 58, + 65, + 66, + 67, + 69, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 79, + 80, + 81, + 83, + 84, + 85, + 87, + 89, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 122 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2005.14165.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2005.14165.json" + }, + { + "signature": "sha256:b95fa2a272cbc950b81320790d04fcf19ebb24050fa2139ba6a474172cac596b", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 20, + "glyphCoverage": [ + 32, + 40, + 41, + 48, + 50, + 52, + 54, + 56, + 83, + 85, + 97, + 100, + 101, + 102, + 104, + 108, + 110, + 115, + 116, + 117 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:b95fb7a3c3a7dc06bd2b40c5c73b890cebf6f6c14a8b7f38d08ad1c45f6fce1d", + "alias": null, + "baseName": null, + "glyphCount": 19, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 50, + 54, + 55, + 56, + 57, + 58, + 97, + 98, + 101, + 110, + 111, + 112, + 114, + 115, + 116 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.json" + }, + { + "signature": "sha256:b9616aab887ee8d50591fb2d2215f54da5a971dafa39f06218b3d24b18e39d27", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 22, + "glyphCoverage": [ + 32, + 40, + 41, + 48, + 49, + 50, + 52, + 54, + 56, + 69, + 70, + 73, + 78, + 84, + 97, + 104, + 105, + 108, + 110, + 114, + 116, + 117 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00020.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00020.json" + }, + { + "signature": "sha256:b977742dc6d83cbad27a582ce8471d2363d5d23c706c8bfe639836228912a349", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 37, + "glyphCoverage": [ + 32, + 40, + 41, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 66, + 67, + 72, + 80, + 84, + 97, + 98, + 99, + 100, + 101, + 102, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 120, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.json" + }, + { + "signature": "sha256:b9c77ef25715b96fd4823bc2d415831ec6ec7c86abbf9db007566e6c3955b318", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 27, + "glyphCoverage": [ + 32, + 40, + 41, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 76, + 82, + 97, + 100, + 101, + 103, + 105, + 108, + 109, + 110, + 111, + 114, + 115, + 116, + 117, + 118 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2307.00004.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2307.00004.json" + }, + { + "signature": "sha256:ba3fe59e864b8b6080b6f069bd099c767f03a7859d56773a8368c66ca1e173b0", + "alias": null, + "baseName": null, + "glyphCount": 2, + "glyphCoverage": [ + 0, + 1 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_math_0608240.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_math_0608240.json" + }, + { + "signature": "sha256:baeffe77e66160c0069964b3e3763101df5ac3ba8c7161b91ab7a3210cedab42", + "alias": "cmr10", + "baseName": "Cmr10", + "glyphCount": 4, + "glyphCoverage": [ + 40, + 41, + 91, + 93 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.json" + }, + { + "signature": "sha256:bce6bf189ded971caef146b3fb8df2fd988d9f0347abf9f1d4a79f0bea0a9952", + "alias": null, + "baseName": null, + "glyphCount": 8, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:bd237a63fead0b3ab8a2bc1a185666c698ba21c01e6aa66c6c25d3054a8b077a", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 39, + "glyphCoverage": [ + 32, + 40, + 41, + 45, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 67, + 69, + 70, + 73, + 76, + 82, + 84, + 97, + 98, + 99, + 101, + 102, + 103, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 118, + 120 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.json" + }, + { + "signature": "sha256:bdfd7255452653daab82327dd16413f481cc0a361dbbf8ae435cc27193bd5691", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 45, + "glyphCoverage": [ + 32, + 40, + 41, + 45, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 56, + 64, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 75, + 76, + 77, + 80, + 83, + 84, + 97, + 98, + 99, + 100, + 101, + 102, + 105, + 107, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 117, + 118, + 120 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.json" + }, + { + "signature": "sha256:bdff85a28d968fea7fbffcf4869b1a28bdd7eb8b73230a016b41bdcbe28de94b", + "alias": "cmex10", + "baseName": "Cmex10", + "glyphCount": 1, + "glyphCoverage": [ + 90 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:be1091f99be473e9d52f4fe0316911f9f629b35cfd31a2646406e47f0d79f93f", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 34, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 70, + 73, + 75, + 77, + 80, + 82, + 83, + 91, + 93, + 97, + 99, + 100, + 101, + 105, + 108, + 110, + 112, + 114, + 115, + 116, + 117, + 120 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00009.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00009.json" + }, + { + "signature": "sha256:bed9bc93af3cb26c7bb528913f303fc03baf7103147b3d994706f83efe0b4bd9", + "alias": null, + "baseName": null, + "glyphCount": 26, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:beeac216add97157addd766fc19724a2a48e92ae334da8529ae0f93c6052bf50", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 42, + "glyphCoverage": [ + 32, + 40, + 41, + 45, + 46, + 48, + 49, + 50, + 52, + 53, + 55, + 58, + 62, + 65, + 66, + 68, + 71, + 72, + 73, + 76, + 77, + 80, + 84, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 107, + 108, + 109, + 110, + 111, + 114, + 115, + 116, + 117, + 118 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.json" + }, + { + "signature": "sha256:befaf05c824b5683c37e033a184f11b83b91f1261b517bc0336df0de3b753ef5", + "alias": null, + "baseName": null, + "glyphCount": 8, + "glyphCoverage": [ + 32, + 46, + 48, + 52, + 53, + 61, + 97, + 176 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2305.00007.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2305.00007.json" + }, + { + "signature": "sha256:bf60f4be6be0dd3671bb2d1886749f1f7de0e1ffc612fa2d88a76c51471a0c6c", + "alias": "dejavusans-oblique", + "baseName": "DejaVuSans-Oblique", + "glyphCount": 11, + "glyphCoverage": [ + 69, + 74, + 76, + 82, + 86, + 99, + 101, + 110, + 111, + 116, + 122 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00016.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00016.json" + }, + { + "signature": "sha256:bf790625423c5ebdf94760eb796c847af885b930d3a30861509b07f1c77c3f60", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 9, + "glyphCoverage": [ + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 56 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\04_handout-intermediate.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\04_handout-intermediate.json" + }, + { + "signature": "sha256:bf7b95498f7d00d228c5c155db62b6c1aa7e0215cca1690c9fdb0adcfd496b10", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 14, + "glyphCoverage": [ + 46, + 48, + 49, + 50, + 65, + 66, + 67, + 68, + 97, + 99, + 105, + 108, + 115, + 118 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:c00238ce44102dedc802839b5c5ae0c481ad8ab9bdaac1817e6ac548b97d7888", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 35, + "glyphCoverage": [ + 32, + 40, + 41, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 56, + 65, + 76, + 80, + 86, + 91, + 93, + 98, + 99, + 100, + 101, + 103, + 104, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.json" + }, + { + "signature": "sha256:c06a54f65421e92ec0fee682457d70b57be20cf6e70fca4023b83e7f22ca4bce", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 48, + "glyphCoverage": [ + 32, + 40, + 41, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 65, + 66, + 67, + 69, + 71, + 72, + 73, + 75, + 76, + 78, + 80, + 82, + 83, + 84, + 85, + 86, + 88, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 107, + 108, + 109, + 111, + 114, + 115, + 116, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.json" + }, + { + "signature": "sha256:c094199f49e16eb2a19112827b49fa12c63c241a8208a7bc1f5e4dd18e3e6767", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 46, + "glyphCoverage": [ + 32, + 40, + 41, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 52, + 53, + 54, + 55, + 56, + 57, + 61, + 66, + 68, + 69, + 70, + 72, + 73, + 76, + 77, + 78, + 79, + 83, + 85, + 86, + 87, + 88, + 97, + 99, + 101, + 102, + 103, + 105, + 107, + 108, + 109, + 110, + 114, + 115, + 116, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.json" + }, + { + "signature": "sha256:c16f041bc00f839ab89a1c1096e11b745001605c0d6015e7ab505446dc73c280", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 55, + "glyphCoverage": [ + 32, + 38, + 40, + 41, + 44, + 45, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 55, + 56, + 57, + 65, + 66, + 67, + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 82, + 83, + 84, + 86, + 87, + 89, + 90, + 97, + 98, + 99, + 100, + 101, + 103, + 104, + 105, + 106, + 108, + 109, + 110, + 111, + 114, + 115, + 116, + 117, + 118, + 121, + 122 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00010.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00010.json" + }, + { + "signature": "sha256:c1c45116eadacdd05049dd1857a41961c059e0d6a2ff208348c135963ac691a2", + "alias": null, + "baseName": null, + "glyphCount": 12, + "glyphCoverage": [ + 45, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2305.00007.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2305.00007.json" + }, + { + "signature": "sha256:c387750b618ba0562b8b2df96960691ee09654e8a85d74d3adc3a160b59e4f3b", + "alias": null, + "baseName": null, + "glyphCount": 7, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:c43134bebeaf8328ac299ba978d7e663e2dc4fe99463b9d7f72f72f77936204e", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 9, + "glyphCoverage": [ + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:c47ab4ee8aedb4a62f9e246c2705d57b18ca04665aaf0c1650aaba089aa6a4fe", + "alias": null, + "baseName": null, + "glyphCount": 2, + "glyphCoverage": [ + 32, + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.08774.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.08774.json" + }, + { + "signature": "sha256:c483727e2943979d472451693b71e0466663dca9a69947ea7e345c2097952466", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 36, + "glyphCoverage": [ + 32, + 40, + 41, + 45, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 66, + 67, + 68, + 69, + 82, + 97, + 99, + 100, + 101, + 105, + 106, + 108, + 109, + 110, + 111, + 114, + 115, + 116, + 117, + 120, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00020.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00020.json" + }, + { + "signature": "sha256:c4a50af2db9e2ddb2521027ef6ebad6bcfb6ed446dbd4a0be9384a2e1385807d", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 22, + "glyphCoverage": [ + 32, + 48, + 49, + 50, + 52, + 54, + 56, + 74, + 80, + 99, + 100, + 101, + 103, + 105, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2306.00007.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2306.00007.json" + }, + { + "signature": "sha256:c768475ccc6937426dbc89759263eb5d928d9d1dea1bff6bd102cc0c30a2bff3", + "alias": null, + "baseName": null, + "glyphCount": 4, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:c770ec87a8ffd1d97726157dd27979cb6c62ec01dfccd232272761a587b7c478", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 28, + "glyphCoverage": [ + 32, + 45, + 46, + 48, + 49, + 50, + 52, + 53, + 54, + 56, + 57, + 61, + 73, + 76, + 97, + 98, + 101, + 102, + 103, + 104, + 105, + 109, + 110, + 111, + 114, + 115, + 116, + 119 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.json" + }, + { + "signature": "sha256:c845063bef18f173afbfcb90fbf6773f43648c5f0666ecfa0132afe4e164068d", + "alias": "dejavusans-bold", + "baseName": "EVICAO+DejaVuSans-Bold", + "glyphCount": 9, + "glyphCoverage": [ + 32, + 65, + 83, + 97, + 101, + 105, + 110, + 118, + 119 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\03_handout-beginner.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\03_handout-beginner.json" + }, + { + "signature": "sha256:c9bac793bd202a4edfaf584deb4eab3bc2b51a836b8d9c922d230e732c973fd0", + "alias": "cmmi10", + "baseName": "Cmmi10", + "glyphCount": 3, + "glyphCoverage": [ + 44, + 102, + 952 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.json" + }, + { + "signature": "sha256:ca1da97650d4b6f9f114de60eb3cf5a54bf67343ca4963833409576cfbdde5b7", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 19, + "glyphCoverage": [ + 45, + 48, + 49, + 50, + 52, + 54, + 56, + 65, + 67, + 68, + 69, + 82, + 86, + 101, + 108, + 110, + 111, + 114, + 116 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2301.00011.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2301.00011.json" + }, + { + "signature": "sha256:ca7fba82f8bfae72d9c8dc318d644bf41c1aa24e5b4c428cf59e964026c305d0", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 18, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 53, + 82, + 97, + 99, + 100, + 101, + 105, + 108, + 110, + 111, + 114, + 115, + 116, + 117 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.json" + }, + { + "signature": "sha256:cabd68280adb71ed72e96880a236e3103c9b79c844c648f8ef4e154bc7964380", + "alias": null, + "baseName": null, + "glyphCount": 2, + "glyphCoverage": [ + 32, + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.08774.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.08774.json" + }, + { + "signature": "sha256:cadf43a2df81340368af44c76b499223931d78dcc76c70cf4b4a93d133e368af", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 27, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 50, + 52, + 54, + 56, + 84, + 97, + 98, + 100, + 101, + 102, + 103, + 104, + 105, + 108, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 119, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:cb3f3c5f0a534574a039cd3cce8b918c3b90f97a9c9023bfaaf3cff549371af2", + "alias": null, + "baseName": null, + "glyphCount": 28, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:cb72de0c6105b9802d360c47a292a1f7bc344939a6801b879ea09dae4e45e863", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 7, + "glyphCoverage": [ + 46, + 48, + 49, + 50, + 51, + 52, + 53 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:ccb2a295edff4b28797589f9c24a66abffe5ddb7d0e81bb67368bfe0a6b78ff2", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 13, + "glyphCoverage": [ + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 56, + 57, + 61, + 98, + 101, + 115 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.json" + }, + { + "signature": "sha256:ccfec2e6dd2a08f37fd2bec5c0bf2d29a5e16e2a1224597b97c66f0391d9450a", + "alias": null, + "baseName": null, + "glyphCount": 17, + "glyphCoverage": [ + 45, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 70, + 88, + 98, + 111, + 115 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2305.00007.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2305.00007.json" + }, + { + "signature": "sha256:cdf36e104d995d8919c64cb93238647b1c118bd45799abc40f62d1975d342c6a", + "alias": null, + "baseName": null, + "glyphCount": 5, + "glyphCoverage": [ + 32, + 100, + 110, + 112, + 117 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2201.04294.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2201.04294.json" + }, + { + "signature": "sha256:ce630692329f362fe282bf3ed0ab4db17fe1c42ca8b24d6669f9a5cc324be190", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 32, + "glyphCoverage": [ + 32, + 40, + 41, + 46, + 47, + 48, + 49, + 50, + 52, + 53, + 54, + 55, + 56, + 75, + 76, + 82, + 84, + 97, + 100, + 101, + 103, + 104, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.json" + }, + { + "signature": "sha256:ceb044f2b13694e135fed4bbcee3b6f8157c0f68dce7ffc2c9ad76bc913c3eaa", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 35, + "glyphCoverage": [ + 32, + 40, + 41, + 44, + 45, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 56, + 57, + 58, + 61, + 70, + 77, + 84, + 97, + 101, + 103, + 105, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2307.00004.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2307.00004.json" + }, + { + "signature": "sha256:cf67ef2fbaee5fee0a6bb59641cac5bc4349427af15e96fe937ced3701b9d5ee", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 35, + "glyphCoverage": [ + 32, + 40, + 41, + 45, + 46, + 48, + 49, + 50, + 51, + 53, + 55, + 66, + 72, + 77, + 80, + 83, + 86, + 97, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 107, + 108, + 109, + 110, + 111, + 114, + 115, + 116, + 117, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.json" + }, + { + "signature": "sha256:cffde7e680894a295dd6d9d8a593caf7dc0d128d1c00cdc24e67fe14634b36dc", + "alias": null, + "baseName": null, + "glyphCount": 2, + "glyphCoverage": [ + 0, + 1 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_math_0608240.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_math_0608240.json" + }, + { + "signature": "sha256:d00263916a737c68d2e926c3b85d765dc358ecdb7e8217832a0e8cd0f18f6801", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 43, + "glyphCoverage": [ + 32, + 40, + 41, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 65, + 66, + 68, + 69, + 70, + 72, + 73, + 76, + 78, + 84, + 85, + 86, + 88, + 91, + 93, + 99, + 101, + 103, + 105, + 107, + 108, + 109, + 111, + 114, + 115, + 116, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.json" + }, + { + "signature": "sha256:d027709c2e978571f0408d69354c1408b11d11b420879fe9e0bf6729d030827f", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 26, + "glyphCoverage": [ + 32, + 45, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 60, + 66, + 71, + 76, + 97, + 99, + 100, + 101, + 102, + 104, + 105, + 107, + 114, + 115, + 116 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2301.00017.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2301.00017.json" + }, + { + "signature": "sha256:d034d16ac69e3e1c5008e77c4c24dc3179308a2742601e89d5c8ab327e4040dd", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 15, + "glyphCoverage": [ + 43, + 48, + 49, + 50, + 51, + 56, + 61, + 97, + 98, + 105, + 108, + 109, + 111, + 112, + 116 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:d0be010d513aac538cbbd758336e650b5f0a0a6bfa914c999a232b7b5e4e3202", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 31, + "glyphCoverage": [ + 32, + 38, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 56, + 58, + 67, + 77, + 83, + 84, + 91, + 93, + 97, + 100, + 101, + 105, + 108, + 109, + 110, + 111, + 114, + 115, + 116, + 118, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2307.00004.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2307.00004.json" + }, + { + "signature": "sha256:d0c6cddc416d130701395246621a0f669fc292df4097a7a74395602faf4475df", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 17, + "glyphCoverage": [ + 48, + 49, + 53, + 97, + 100, + 101, + 102, + 103, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 118 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:d1130974d3519377a3b1dc1c66b0e8bcd55a8bc9f8840987b24fc634aafb04e0", + "alias": null, + "baseName": null, + "glyphCount": 2, + "glyphCoverage": [ + 32, + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.08774.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.08774.json" + }, + { + "signature": "sha256:d27740fc42f090b3a2d119c15df8c3af86b3ed94128c2993f27a09d58218e7b2", + "alias": "f88", + "baseName": "F88", + "glyphCount": 1, + "glyphCoverage": [ + 49 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1506.02640.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1506.02640.json" + }, + { + "signature": "sha256:d3349f72cf3765f912977560882539173d0fc04bd3984170cdd5b94ba6f22d5e", + "alias": null, + "baseName": null, + "glyphCount": 2, + "glyphCoverage": [ + 66, + 90 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2306.00004.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2306.00004.json" + }, + { + "signature": "sha256:d35655606e2b79ad542e39e344a4cb2b990a00c5223d827556163a6ed73c91d7", + "alias": null, + "baseName": null, + "glyphCount": 22, + "glyphCoverage": [ + 32, + 46, + 48, + 51, + 54, + 56, + 57, + 58, + 97, + 99, + 100, + 101, + 102, + 104, + 105, + 110, + 111, + 112, + 114, + 115, + 116, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.json" + }, + { + "signature": "sha256:d47afb7581e98f588f0e70953e8692249aaa2ec3df36fbd90985f27b1ce1cf50", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 12, + "glyphCoverage": [ + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 97, + 98, + 114 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:d5942c0913ef64ae862556a746b28dac1a621caa5e05973e16881c8e8e15e329", + "alias": "f59", + "baseName": "F59", + "glyphCount": 1, + "glyphCoverage": [ + 42 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\08_matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\08_matplotlib.json" + }, + { + "signature": "sha256:d59cdaa2d2fe9b31f413ff5aacc5305abdf22ab3360091b81360ed72b326d28b", + "alias": "cmsy10", + "baseName": "Cmsy10", + "glyphCount": 2, + "glyphCoverage": [ + 215, + 8722 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.json" + }, + { + "signature": "sha256:d7cd4d523fa4453388f7630aa142811997ec958b5f97c5ccaea2c8145a848606", + "alias": "bitstreamverasans-roman", + "baseName": "BitstreamVeraSans-Roman", + "glyphCount": 25, + "glyphCoverage": [ + 32, + 37, + 46, + 48, + 49, + 50, + 52, + 53, + 54, + 56, + 97, + 98, + 101, + 102, + 103, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1411.4038.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1411.4038.json" + }, + { + "signature": "sha256:d82bc26c9af12c162c91a07522b7be2f7bb0e3b8d7c52b1baf0f6706b32eb632", + "alias": "dejavusans-oblique", + "baseName": "GCWXDV+DejaVuSans-Oblique", + "glyphCount": 2, + "glyphCoverage": [ + 109, + 115 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2301.00013.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2301.00013.json" + }, + { + "signature": "sha256:d8b163dab9cadae5c3de66ade49a1c4eb0bf60e8c4ec28a3c6a797ec6824ff30", + "alias": null, + "baseName": null, + "glyphCount": 21, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 52, + 53, + 55, + 56, + 57, + 58, + 97, + 98, + 100, + 101, + 107, + 110, + 111, + 112, + 114, + 115, + 116 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.json" + }, + { + "signature": "sha256:d8ee47adb650f065a7b8a1df6af5debbbbbf38380efa6859ee882368d3667249", + "alias": null, + "baseName": null, + "glyphCount": 16, + "glyphCoverage": [ + 32, + 46, + 48, + 52, + 55, + 56, + 57, + 58, + 98, + 99, + 101, + 105, + 108, + 115, + 117, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.json" + }, + { + "signature": "sha256:d9453710f906d347b0cd89f9987580a5791cdaf2fedd58210dfd8ee6ebaef9e8", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 39, + "glyphCoverage": [ + 32, + 40, + 41, + 43, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 56, + 72, + 76, + 77, + 78, + 82, + 84, + 86, + 97, + 99, + 100, + 101, + 104, + 105, + 107, + 108, + 110, + 111, + 112, + 114, + 115, + 116, + 119, + 120, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2010.11929.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2010.11929.json" + }, + { + "signature": "sha256:d9b62ed6612f5a136b21894bab0e243fa2db0e38a12e839fdf6aa40e8be435ca", + "alias": null, + "baseName": null, + "glyphCount": 24, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 51, + 53, + 54, + 55, + 56, + 57, + 58, + 97, + 98, + 99, + 100, + 101, + 107, + 108, + 111, + 112, + 114, + 116, + 118, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.json" + }, + { + "signature": "sha256:db272671de1ce4c5f262f235af656a595a57014ad62c712091fcfefd2b64e101", + "alias": null, + "baseName": null, + "glyphCount": 2, + "glyphCoverage": [ + 32, + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.08774.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.08774.json" + }, + { + "signature": "sha256:db4d5a360e398f85d6dbc3a28380abe9d2ee3999a9d3dd6c5bfa4d7780698d1d", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 40, + "glyphCoverage": [ + 32, + 40, + 41, + 45, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 56, + 57, + 58, + 61, + 65, + 66, + 67, + 68, + 70, + 71, + 76, + 77, + 80, + 82, + 84, + 85, + 97, + 98, + 101, + 105, + 107, + 108, + 111, + 114, + 115, + 116, + 117, + 118 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2304.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2304.00012.json" + }, + { + "signature": "sha256:dc03917f2edd92a7a68a46ad36f65a908e4feb85e61cb37e9026205f3986574a", + "alias": "dejavusans-bold", + "baseName": "DejaVuSans-Bold", + "glyphCount": 7, + "glyphCoverage": [ + 65, + 87, + 100, + 101, + 103, + 105, + 116 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:dc368ed8a48957edf3b32df700e387db793f68e16eb26d4a19fc22d9afd7b53a", + "alias": "cmsy10", + "baseName": "Cmsy10", + "glyphCount": 2, + "glyphCoverage": [ + 215, + 8722 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.json" + }, + { + "signature": "sha256:dc833a6412c0c42662141a5c74359463095e5082a5b34bd3835242e7b169dbd8", + "alias": null, + "baseName": null, + "glyphCount": 24, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 50, + 53, + 54, + 55, + 56, + 57, + 58, + 97, + 98, + 99, + 101, + 105, + 107, + 108, + 110, + 111, + 112, + 114, + 115, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.json" + }, + { + "signature": "sha256:dc865c7467b1df5aeca2086d6f25aaad1e67f85a2ceed0c5c80556a4b17f813f", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 33, + "glyphCoverage": [ + 32, + 44, + 45, + 46, + 48, + 49, + 50, + 51, + 53, + 55, + 56, + 57, + 61, + 65, + 67, + 68, + 69, + 70, + 71, + 73, + 76, + 82, + 86, + 87, + 97, + 98, + 99, + 100, + 104, + 109, + 111, + 112, + 115 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.json" + }, + { + "signature": "sha256:dd587a2b8c8f34908f27cf3424c8ed3eae95ddd9f9ba425a923b39d7f81af96e", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 29, + "glyphCoverage": [ + 32, + 45, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 56, + 57, + 61, + 73, + 76, + 97, + 98, + 101, + 102, + 103, + 104, + 105, + 109, + 110, + 111, + 114, + 115, + 116, + 119 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.json" + }, + { + "signature": "sha256:dd6246cf6e8b1bca972d71c6cc433a2c2772f7b821a1c366ccaea3fa8067a9a5", + "alias": "bitstreamverasans-roman", + "baseName": "BitstreamVeraSans-Roman", + "glyphCount": 41, + "glyphCoverage": [ + 32, + 37, + 40, + 41, + 46, + 47, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 64, + 65, + 68, + 70, + 80, + 83, + 86, + 95, + 97, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 118, + 119 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1504.08083.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1504.08083.json" + }, + { + "signature": "sha256:dd705929c3dd95a1fc2fbf2b67242794250edea0df597212a9485100cfc9ab5c", + "alias": null, + "baseName": null, + "glyphCount": 24, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 52, + 55, + 57, + 58, + 97, + 98, + 99, + 101, + 102, + 103, + 104, + 105, + 108, + 110, + 111, + 112, + 114, + 115, + 116, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.json" + }, + { + "signature": "sha256:de256c2f7f04a23f9a04cccea750431fafbc20df8ac0d12a0f5de5e1cbc60d88", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 38, + "glyphCoverage": [ + 32, + 40, + 41, + 45, + 46, + 48, + 49, + 50, + 52, + 54, + 56, + 57, + 66, + 67, + 68, + 69, + 74, + 78, + 82, + 83, + 85, + 97, + 99, + 100, + 101, + 105, + 106, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 120, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00020.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00020.json" + }, + { + "signature": "sha256:ded4100549c4d9983c81a1253f1a8d8913e11ba04f81eb1b6e64e2381972fdd8", + "alias": null, + "baseName": null, + "glyphCount": 3, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:dedec7b93db63b81f875c41cf26334d1e2ae7d17064c97baf12ff1fc10912d1a", + "alias": null, + "baseName": null, + "glyphCount": 2, + "glyphCoverage": [ + 0, + 1 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_math_0608240.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_math_0608240.json" + }, + { + "signature": "sha256:dfaf8075e13be0e51f72485f9d825cea9ad077eb2dd9d63b9922add67d7d2761", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 12, + "glyphCoverage": [ + 32, + 48, + 49, + 50, + 51, + 53, + 80, + 100, + 101, + 105, + 111, + 114 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\04_handout-intermediate.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\04_handout-intermediate.json" + }, + { + "signature": "sha256:e051f7caa996e098a15fb299341d97ba881d9d219058b4d16cd7d15819b9f0f6", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 24, + "glyphCoverage": [ + 32, + 41, + 48, + 49, + 50, + 51, + 52, + 70, + 73, + 83, + 86, + 91, + 93, + 97, + 98, + 99, + 100, + 101, + 107, + 108, + 109, + 112, + 115, + 117 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00016.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00016.json" + }, + { + "signature": "sha256:e060ac08052490b1b3415e890ab95e06afb8fc75e39336f75d94a2e2f69d5cf2", + "alias": "bitstreamverasans-roman", + "baseName": "BitstreamVeraSans-Roman", + "glyphCount": 39, + "glyphCoverage": [ + 32, + 37, + 40, + 41, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 64, + 65, + 70, + 80, + 95, + 97, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 118, + 119 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1504.08083.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1504.08083.json" + }, + { + "signature": "sha256:e17d3cf8c0645afc32340ae1f3c702dc62023dd5ecdaa4b5a3aa6f061e72b6d4", + "alias": null, + "baseName": null, + "glyphCount": 27, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:e20fe81d8c55d413a6f884d5caa85c4044dd4530308645e7c24dc810a4fb50fb", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 48, + "glyphCoverage": [ + 32, + 40, + 41, + 45, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 66, + 67, + 69, + 70, + 71, + 73, + 76, + 77, + 78, + 79, + 80, + 84, + 90, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 107, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 122 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.json" + }, + { + "signature": "sha256:e358c6d6d075268944df37c27434f0074078703e093179f5980158ed1e301c7f", + "alias": "cmr10", + "baseName": "Cmr10", + "glyphCount": 11, + "glyphCoverage": [ + 40, + 41, + 48, + 53, + 91, + 93, + 99, + 104, + 111, + 112, + 116 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.json" + }, + { + "signature": "sha256:e3a59bd95e14ef45ad1d5c6c7ac1586866a2dbb958ae7470a9c29b86b5de0236", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 23, + "glyphCoverage": [ + 32, + 37, + 40, + 41, + 45, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 69, + 78, + 82, + 99, + 101, + 104, + 111, + 112, + 114, + 115, + 116 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.json" + }, + { + "signature": "sha256:e3cd2fdc44bb48824770d46f7d4544a2542655842fbfe8d6a6c38b0078bc990b", + "alias": "dejavusans-oblique", + "baseName": "GCWXDV+DejaVuSans-Oblique", + "glyphCount": 3, + "glyphCoverage": [ + 77, + 82, + 83 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00009.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00009.json" + }, + { + "signature": "sha256:e3d87c113463c8642a4f22943064fd75c133ad31fe5efebf6de6abf211b74b5a", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 7, + "glyphCoverage": [ + 48, + 49, + 50, + 51, + 52, + 54, + 56 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:e4138c549037d0f410c40cf944b476c0cea0162d6de9b7d7fca4523b768f333d", + "alias": "cmr10", + "baseName": "Cmr10", + "glyphCount": 5, + "glyphCoverage": [ + 40, + 41, + 61, + 91, + 93 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.json" + }, + { + "signature": "sha256:e47b8f112a875361a43bcb6d9c6467e0296412d29e417e58a0e60c90b664d281", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 9, + "glyphCoverage": [ + 46, + 48, + 50, + 97, + 99, + 105, + 108, + 115, + 118 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:e4c23373a49a658084fe176eab9f890d45a74282c1549d57e75dfb68f58dd3ab", + "alias": null, + "baseName": null, + "glyphCount": 37, + "glyphCoverage": [ + 32, + 37, + 40, + 41, + 45, + 46, + 48, + 49, + 50, + 52, + 53, + 54, + 66, + 67, + 71, + 75, + 76, + 77, + 83, + 85, + 86, + 87, + 88, + 97, + 98, + 99, + 101, + 102, + 105, + 108, + 110, + 111, + 112, + 114, + 115, + 116, + 117 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2201.04294.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2201.04294.json" + }, + { + "signature": "sha256:e55b5d4398dedb1eca92789c74a43cd4cf1db536cb4abfbd23e6fbd71f30a5e3", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 51, + "glyphCoverage": [ + 32, + 34, + 44, + 45, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 61, + 65, + 66, + 67, + 68, + 69, + 71, + 72, + 73, + 76, + 77, + 78, + 79, + 80, + 82, + 85, + 97, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 107, + 108, + 110, + 111, + 112, + 114, + 115, + 116, + 118, + 119, + 120, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\testing\\crop_test.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\testing\\crop_test.json" + }, + { + "signature": "sha256:e5c0277de703b5a0b0e9cfb2fdbee2109337da67dd4f990c9978bdfc88377c5a", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 39, + "glyphCoverage": [ + 32, + 40, + 41, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 56, + 65, + 69, + 70, + 72, + 73, + 76, + 78, + 84, + 85, + 86, + 88, + 91, + 93, + 99, + 101, + 103, + 105, + 107, + 108, + 109, + 111, + 114, + 115, + 116, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.json" + }, + { + "signature": "sha256:e5c80cd6af540d8b3a35cd09b10a72eaf61ea98d862fab4b40fa905e605d9040", + "alias": null, + "baseName": null, + "glyphCount": 12, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:e6b58e813c778f0f097d3f0352d02bee6306a4be46cd724ed14387bf1b9bce15", + "alias": null, + "baseName": null, + "glyphCount": 3, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:e74fab88f8a0bbef59dec30f33fc99ec7ff5061e33f10ee8f75d66eaad7fc51a", + "alias": "cmsy10", + "baseName": "Cmsy10", + "glyphCount": 1, + "glyphCoverage": [ + 76 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1312.6114.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1312.6114.json" + }, + { + "signature": "sha256:e808a8ecba94bf0190ab7218bb0702698125ee2e456e82e00da709e8188e2bf8", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 28, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 50, + 53, + 54, + 70, + 83, + 84, + 97, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 107, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:e84d798157b6c84f075132752ee06f923d03aab98fd28c5aa6ce7d011c3f7668", + "alias": "cmb10", + "baseName": "Cmb10", + "glyphCount": 2, + "glyphCoverage": [ + 77, + 120 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.json" + }, + { + "signature": "sha256:e88aa5c91c5c837b7c3ced8d73a602bfbcb86e72993484cc7136954590ee6264", + "alias": null, + "baseName": null, + "glyphCount": 2, + "glyphCoverage": [ + 0, + 1 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_math_0608240.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_math_0608240.json" + }, + { + "signature": "sha256:ea023bfdfa5cb5773ac3da1678cc32bf10181e09237ddd91109ada82903643d2", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 34, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 52, + 53, + 54, + 55, + 56, + 65, + 67, + 68, + 76, + 77, + 80, + 82, + 87, + 97, + 99, + 100, + 101, + 103, + 104, + 105, + 108, + 109, + 111, + 112, + 114, + 115, + 116, + 117, + 118, + 122 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2010.11929.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2010.11929.json" + }, + { + "signature": "sha256:eacc0616ead5361e2c1670febae7a7bc72253606f5271bd42a46de7fd8cb8403", + "alias": null, + "baseName": null, + "glyphCount": 12, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:ec933bc907607493b83b456a7eeae0e5914102b7dd00f3c89c25928c162546b7", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 41, + "glyphCoverage": [ + 32, + 40, + 41, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 56, + 57, + 71, + 72, + 76, + 77, + 78, + 82, + 83, + 85, + 86, + 88, + 91, + 93, + 99, + 101, + 103, + 105, + 107, + 108, + 109, + 110, + 111, + 114, + 115, + 116, + 119, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.json" + }, + { + "signature": "sha256:ed831589b25beec65ee4760cf12bb7e2cefaad226a7514aa34e69ace202a89b7", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 44, + "glyphCoverage": [ + 32, + 37, + 40, + 41, + 45, + 46, + 48, + 49, + 50, + 52, + 53, + 54, + 56, + 65, + 66, + 72, + 76, + 77, + 78, + 80, + 83, + 95, + 97, + 98, + 99, + 100, + 101, + 103, + 104, + 105, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 122 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.json" + }, + { + "signature": "sha256:edd22119635bfb0f2bff750137c6c6400a7fae4ff80cc252d2e6f2ca88f599a7", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 15, + "glyphCoverage": [ + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 56, + 97, + 99, + 105, + 108, + 115, + 118 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:eedbff5d1f2ad46da835d6cf3c15a64746299b999ce0e9ac63c509e5e58afb79", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 41, + "glyphCoverage": [ + 32, + 40, + 41, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 66, + 68, + 69, + 70, + 72, + 76, + 85, + 86, + 91, + 93, + 97, + 99, + 100, + 101, + 102, + 103, + 104, + 107, + 108, + 110, + 111, + 114, + 115, + 116, + 117, + 120, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.json" + }, + { + "signature": "sha256:f0825768c1faf9dd3d4eb8cfc70e3d82a6c26d6ead134a7243b09cc095a8d24e", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 21, + "glyphCoverage": [ + 32, + 40, + 41, + 48, + 49, + 50, + 52, + 54, + 56, + 69, + 73, + 78, + 84, + 97, + 104, + 105, + 108, + 110, + 114, + 116, + 117 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00020.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00020.json" + }, + { + "signature": "sha256:f08d11b2e84857ae70c0e04523efd78060f730c1003f61f855da156a5d5b9846", + "alias": "dejavusans-oblique", + "baseName": "DejaVuSans-Oblique", + "glyphCount": 2, + "glyphCoverage": [ + 69, + 102 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.json" + }, + { + "signature": "sha256:f0a8d4c5f04aad152f4bec17055ab411ffc6920bb91dc1db86239c71b0c98748", + "alias": null, + "baseName": null, + "glyphCount": 8, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 53, + 61, + 97, + 176 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2305.00007.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2305.00007.json" + }, + { + "signature": "sha256:f114b2cfcfe17d984772d56fcc28c7e50321ef1495e282f3c502531d74c0a899", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 40, + "glyphCoverage": [ + 32, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 55, + 56, + 57, + 70, + 72, + 82, + 84, + 90, + 91, + 93, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00010.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00010.json" + }, + { + "signature": "sha256:f17b5eb0ee996d1388c548f79fa50fa2d8c6076959eff189bb745d156d54547f", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 26, + "glyphCoverage": [ + 32, + 39, + 65, + 66, + 67, + 68, + 73, + 97, + 98, + 100, + 101, + 102, + 104, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 118, + 120, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:f1a874c4268b1bffffc99acabbe0a60aa662611b4bac0e688e4fc0ae3f2033bb", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 7, + "glyphCoverage": [ + 46, + 48, + 49, + 50, + 52, + 54, + 56 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:f22c75548364bb25fc3efbe11f05c56e29f07c15c3046ddbc85a64e5cc5a97bd", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 21, + "glyphCoverage": [ + 32, + 48, + 49, + 50, + 72, + 80, + 91, + 93, + 99, + 100, + 101, + 102, + 105, + 110, + 111, + 113, + 114, + 115, + 117, + 121, + 122 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:f253f554170408316f266682434fdb478e1eca9a3fdc52898c261426f5a49ef4", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 35, + "glyphCoverage": [ + 32, + 37, + 40, + 41, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 80, + 81, + 83, + 84, + 87, + 97, + 101, + 105, + 107, + 108, + 109, + 110, + 111, + 114, + 115, + 116, + 117, + 119, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2307.00004.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2307.00004.json" + }, + { + "signature": "sha256:f38d112daf392f9e9bd3fba4807fe60347163a9e06574565c77ddcc80b47f1a3", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 40, + "glyphCoverage": [ + 32, + 40, + 41, + 45, + 48, + 49, + 50, + 52, + 53, + 54, + 56, + 57, + 66, + 73, + 76, + 77, + 78, + 80, + 83, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 110, + 112, + 114, + 115, + 116, + 117, + 120, + 121, + 122 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00010.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00010.json" + }, + { + "signature": "sha256:f4ba3106322b0cea5e098fd480f148bacbce844bbff42ed646da0941403f709b", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 25, + "glyphCoverage": [ + 32, + 37, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 57, + 58, + 65, + 67, + 80, + 99, + 100, + 101, + 109, + 110, + 111, + 112, + 115, + 116 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1712.09913.json" + }, + { + "signature": "sha256:f4bfd64f36bf33dea79800561a67f78d5ccdb436363574abf0892f58b376a2e6", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 25, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 85, + 97, + 99, + 101, + 103, + 104, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 119, + 120 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:f56c5032cc68f0781a81c477a7f898401c4587ae03fd3ea56341d4e4cfa7af83", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 36, + "glyphCoverage": [ + 32, + 40, + 41, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 65, + 66, + 71, + 76, + 77, + 80, + 83, + 97, + 99, + 100, + 101, + 102, + 103, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 120, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2306.00008.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2306.00008.json" + }, + { + "signature": "sha256:f5bac6f53ac4e943b15c481ff0bf6d78f85196d2ea0a8e42fccfabae29b08ba9", + "alias": null, + "baseName": null, + "glyphCount": 9, + "glyphCoverage": [ + 32, + 46, + 48, + 50, + 52, + 53, + 61, + 97, + 176 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2305.00007.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2305.00007.json" + }, + { + "signature": "sha256:f6112d6a35d5fdf5d6431b3156b713020953154042814ad12d2b81731c97250b", + "alias": null, + "baseName": null, + "glyphCount": 13, + "glyphCoverage": [ + 0, + 32, + 37, + 97, + 98, + 101, + 105, + 108, + 109, + 110, + 111, + 112, + 116 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\07_matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\07_matplotlib.json" + }, + { + "signature": "sha256:f6314bd35ccf9c7df7b1db8fc01c4c91ebe72e6a5de53ad70d56670a9d71ee46", + "alias": null, + "baseName": null, + "glyphCount": 4, + "glyphCoverage": [ + 66, + 68, + 70, + 84 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2201.04294.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2201.04294.json" + }, + { + "signature": "sha256:f7c3be2199c397a4c702dd434ac63fc9e046d749eff8cede4513fbc2774751b4", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 5, + "glyphCoverage": [ + 48, + 49, + 50, + 51, + 53 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\04_handout-intermediate.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\04_handout-intermediate.json" + }, + { + "signature": "sha256:f7caaac6228f3dd70fc47426ecfadb1e3f1739808477563d9819142638774ee4", + "alias": "dejavusans", + "baseName": "BMQQDV+DejaVuSans", + "glyphCount": 42, + "glyphCoverage": [ + 32, + 43, + 44, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 61, + 65, + 67, + 68, + 70, + 71, + 77, + 83, + 84, + 87, + 97, + 98, + 99, + 100, + 101, + 102, + 104, + 105, + 107, + 108, + 110, + 111, + 114, + 115, + 116, + 119, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2301.00017.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2301.00017.json" + }, + { + "signature": "sha256:f7da79df8dc640f471daae51285918ccce44613022ccdca0ce80705ba9d1206a", + "alias": null, + "baseName": null, + "glyphCount": 19, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 55, + 56, + 57, + 58, + 97, + 98, + 100, + 101, + 107, + 110, + 111, + 112, + 114, + 115, + 116 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.json" + }, + { + "signature": "sha256:f8c882bcaca742959e6e9242800d3945d11951d8c45f57c0d7aff1808d5fea99", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 36, + "glyphCoverage": [ + 32, + 37, + 45, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 56, + 65, + 72, + 78, + 79, + 83, + 84, + 97, + 98, + 99, + 101, + 102, + 103, + 104, + 105, + 108, + 109, + 110, + 111, + 112, + 114, + 115, + 116, + 117, + 118, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2204.02311.json" + }, + { + "signature": "sha256:f8f14410ec170248916e19f9d09120cfd786c47906b7c3735781d24e944b094e", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 11, + "glyphCoverage": [ + 32, + 83, + 84, + 101, + 109, + 110, + 111, + 115, + 116, + 119, + 121 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:fb54c23aa081562ac114676ffe43032c9c0fb63af3e5b7b3441b88872d1f2e7a", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 16, + "glyphCoverage": [ + 46, + 48, + 49, + 50, + 52, + 53, + 54, + 56, + 66, + 72, + 84, + 101, + 108, + 111, + 115, + 116 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\app\\core\\src\\main\\resources\\type3\\samples\\01_Matplotlib.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\01_Matplotlib.json" + }, + { + "signature": "sha256:fb6d39278fcde088ea76f97753966054ff518ef4a965e2a113960f6866f693af", + "alias": null, + "baseName": null, + "glyphCount": 8, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:fb6ec855289917691b68f9798b3b1663dbdfa0504802d09a87c24107526cf78d", + "alias": null, + "baseName": null, + "glyphCount": 8, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + }, + { + "signature": "sha256:fbf78b6530ef9955b64c3aa0912b42fce013e8bc89932cb8b00830042d18104b", + "alias": "f59", + "baseName": "F59", + "glyphCount": 1, + "glyphCoverage": [ + 0 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2302.00006.json" + }, + { + "signature": "sha256:fd9fbdff5bc80cfa395c472c3d1b9e8f387c4cc2bd444b058488c3f0543594f9", + "alias": null, + "baseName": null, + "glyphCount": 21, + "glyphCoverage": [ + 32, + 46, + 48, + 49, + 51, + 54, + 56, + 57, + 58, + 99, + 100, + 101, + 103, + 107, + 110, + 111, + 112, + 114, + 115, + 116, + 117 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1512.02325.json" + }, + { + "signature": "sha256:fe169013e6375f341b0cd473cc55073d709f471fee7aadfcaf7ec9c2a3c1bb2c", + "alias": "f92", + "baseName": "F92", + "glyphCount": 1, + "glyphCoverage": [ + 49 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_1506.02640.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_1506.02640.json" + }, + { + "signature": "sha256:fe9cdd80fcd2fa2d73ae0f8d10c6d91a0a70ee54a29724bd1e0bcbae66066920", + "alias": "dejavusans", + "baseName": "DejaVuSans", + "glyphCount": 27, + "glyphCoverage": [ + 32, + 45, + 46, + 48, + 49, + 50, + 52, + 53, + 61, + 67, + 80, + 82, + 97, + 100, + 101, + 102, + 104, + 105, + 108, + 109, + 110, + 111, + 114, + 115, + 116, + 117, + 122 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00005.json" + }, + { + "signature": "sha256:fed0c89c7a80873db609818a35938a11ec9d92d5518c7c2e13cd1ea3d82d79b0", + "alias": null, + "baseName": null, + "glyphCount": 28, + "glyphCoverage": [ + 65533 + ], + "samplePdf": "C:\\Users\\systo\\git\\Stirling-PDFNew\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.pdf", + "signatureJson": "C:\\Users\\systo\\git\\Stirling-PDFNew\\docs\\type3\\signatures\\scripts\\pdf-collection\\arxiv_pdf_2303.00012.json" + } + ] +} \ No newline at end of file diff --git a/docs/type3/signature_inventory.md b/docs/type3/signature_inventory.md new file mode 100644 index 000000000..56714fbca --- /dev/null +++ b/docs/type3/signature_inventory.md @@ -0,0 +1,191 @@ +# Type3 Signature Inventory + +_Generated from `docs\type3\signatures`. Run `scripts/summarize_type3_signatures.py` after capturing new samples._ + +## Alias: `cmex10` + +| Signature | Samples | Glyph Count | Coverage (first 10) | +| --- | --- | --- | --- | +| `sha256:bdff85a28d968fea7fbffcf4869b1a28bdd7eb8b73230a016b41bdcbe28de94b` | `01_Matplotlib.pdf` | 1 | 90 | + +## Alias: `cmmi10` + +| Signature | Samples | Glyph Count | Coverage (first 10) | +| --- | --- | --- | --- | +| `sha256:6c72170517812e39f970746f53a2ae08dafbbe7374c20bcb4d5a60adc49cb77b` | `01_Matplotlib.pdf` | 2 | 100, 120 | + +## Alias: `cmr10` + +| Signature | Samples | Glyph Count | Coverage (first 10) | +| --- | --- | --- | --- | +| `sha256:5b535a05c982fb8ff029dfbedd5e9d28c1c4379ebac259d207f65606a94e5b15` | `01_Matplotlib.pdf` | 3 | 48, 49, 53 | + +## Alias: `cmsy10` + +| Signature | Samples | Glyph Count | Coverage (first 10) | +| --- | --- | --- | --- | +| `sha256:1324cd8127143ef9023616b7911c570db3b1eb35758cdc9258ec16c0f4587775` | `01_Matplotlib.pdf` | 1 | 48 | +| `sha256:2832e219b2db3bacf0d5a147d4b74ad5226fdf7562c395ef3fb12937633e037d` | `01_Matplotlib.pdf` | 1 | 8734 | + +## Alias: `dejavusans` + +| Signature | Samples | Glyph Count | Coverage (first 10) | +| --- | --- | --- | --- | +| `sha256:2be58b6ef1e29a83b8634d70b9e32c37a15dea2e608894439ef7224c35b77f5d` | `01_Matplotlib.pdf` | 7 | 46, 48, 49, 50, 52, 53, 55 | +| `sha256:994c963d70041eee141fd275fa22c525a71283de2b4a952814d02e0bbfa8caea` | `01_Matplotlib.pdf` | 4 | 46, 48, 49, 53 | +| `sha256:93573cb1ab32b9cb09378298fb120de079f6a309908d2ee86f91392a6aba5c31` | `01_Matplotlib.pdf` | 30 | 32, 45, 48, 49, 50, 51, 52, 53, 54, 55 | +| `sha256:4febfad91e0141f9658506a0bf8fc2a449f0ea7d97b44e95fc9a970c77af4b0a` | `01_Matplotlib.pdf` | 7 | 48, 49, 50, 51, 52, 53, 54 | +| `sha256:0386e5811612ba4b998d57cd3869d7fbc48092a79d436deda774af107a4af813` | `01_Matplotlib.pdf` | 9 | 46, 48, 49, 50, 51, 52, 53, 54, 55 | +| `sha256:b95fa2a272cbc950b81320790d04fcf19ebb24050fa2139ba6a474172cac596b` | `01_Matplotlib.pdf` | 20 | 32, 40, 41, 48, 50, 52, 54, 56, 83, 85 | +| `sha256:d034d16ac69e3e1c5008e77c4c24dc3179308a2742601e89d5c8ab327e4040dd` | `01_Matplotlib.pdf` | 15 | 43, 48, 49, 50, 51, 56, 61, 97, 98, 105 | +| `sha256:85e16e36ed0290c149647be7e468a7c46e7b66fd290131213040f7bad905aa44` | `01_Matplotlib.pdf` | 25 | 32, 45, 46, 48, 49, 50, 52, 53, 54, 56 | +| `sha256:85e16e36ed0290c149647be7e468a7c46e7b66fd290131213040f7bad905aa44` | `01_Matplotlib.pdf` | 25 | 32, 45, 46, 48, 49, 50, 52, 53, 54, 56 | +| `sha256:3654d4d9bcbbf6ad51628082203094069a17aad3a5e6f5c7972833566e42ab6b` | `01_Matplotlib.pdf` | 29 | 32, 46, 48, 49, 50, 51, 52, 53, 54, 55 | +| `sha256:d0c6cddc416d130701395246621a0f669fc292df4097a7a74395602faf4475df` | `01_Matplotlib.pdf` | 17 | 48, 49, 53, 97, 100, 101, 102, 103, 105, 108 | +| `sha256:cadf43a2df81340368af44c76b499223931d78dcc76c70cf4b4a93d133e368af` | `01_Matplotlib.pdf` | 27 | 32, 46, 48, 49, 50, 52, 54, 56, 84, 97 | +| `sha256:f1a874c4268b1bffffc99acabbe0a60aa662611b4bac0e688e4fc0ae3f2033bb` | `01_Matplotlib.pdf` | 7 | 46, 48, 49, 50, 52, 54, 56 | +| `sha256:e3d87c113463c8642a4f22943064fd75c133ad31fe5efebf6de6abf211b74b5a` | `01_Matplotlib.pdf` | 7 | 48, 49, 50, 51, 52, 54, 56 | +| `sha256:d47afb7581e98f588f0e70953e8692249aaa2ec3df36fbd90985f27b1ce1cf50` | `01_Matplotlib.pdf` | 12 | 46, 48, 49, 50, 51, 52, 53, 54, 55, 97 | +| `sha256:e47b8f112a875361a43bcb6d9c6467e0296412d29e417e58a0e60c90b664d281` | `01_Matplotlib.pdf` | 9 | 46, 48, 50, 97, 99, 105, 108, 115, 118 | +| `sha256:9c67df2ac5c3dcf957dfb0cd048fa450322a72b5a2dfb05f816c536b3b090607` | `01_Matplotlib.pdf` | 19 | 32, 39, 46, 48, 49, 50, 53, 58, 97, 99 | +| `sha256:3ee773a0af6fdedb9853dca9f4d8b80a421a0024bdf06bea41f15d58e3b90c87` | `01_Matplotlib.pdf` | 13 | 46, 48, 49, 50, 52, 54, 56, 97, 99, 105 | +| `sha256:4fa06c90399d80b41cb718163a5d78af2b203df6b6579246fb0b24d349b7a591` | `01_Matplotlib.pdf` | 15 | 46, 48, 49, 50, 52, 53, 54, 56, 97, 98 | +| `sha256:e47b8f112a875361a43bcb6d9c6467e0296412d29e417e58a0e60c90b664d281` | `01_Matplotlib.pdf` | 9 | 46, 48, 50, 97, 99, 105, 108, 115, 118 | +| `sha256:ac6756c76d6e43b771cc1e643dfc7891dfaaac05aa5e302190d0a662838ab031` | `01_Matplotlib.pdf` | 13 | 46, 48, 49, 50, 51, 53, 55, 97, 99, 105 | +| `sha256:bf7b95498f7d00d228c5c155db62b6c1aa7e0215cca1690c9fdb0adcfd496b10` | `01_Matplotlib.pdf` | 14 | 46, 48, 49, 50, 65, 66, 67, 68, 97, 99 | +| `sha256:39b8e5ec8e20a788cd45166baf0ab796397f152c9cd8dec1f882c635380cad92` | `01_Matplotlib.pdf` | 13 | 46, 48, 49, 50, 52, 53, 54, 97, 99, 105 | +| `sha256:27b98489865df8df55f19e4505c093501f236465885ca3bf5b66b6f047a85bb2` | `01_Matplotlib.pdf` | 19 | 46, 48, 49, 50, 51, 52, 68, 70, 72, 76 | +| `sha256:497ddd27e1f56ef6504c61613e3a159bab13314a4970a3be13b3a556648964da` | `01_Matplotlib.pdf` | 12 | 46, 48, 49, 50, 51, 97, 98, 99, 105, 108 | +| `sha256:3b41f9e5f3a7ffa6f4cdffa2a46f02781ec1b2b0c99994707cfb139aa15a11e2` | `01_Matplotlib.pdf` | 5 | 32, 48, 49, 50, 53 | +| `sha256:93723fe436a1aa654db56caf133f56280444b9dc0682af50b83787c3e49ee3ec` | `01_Matplotlib.pdf` | 16 | 32, 48, 49, 50, 52, 53, 54, 56, 58, 97 | +| `sha256:a648cb0524465bcb3bf4a2f65e0761cfc5167b1871a7db9488bee11b56062727` | `01_Matplotlib.pdf` | 14 | 32, 46, 48, 49, 50, 52, 53, 54, 56, 58 | +| `sha256:2f18ed7f982aeb954aaae388ba0c75e3c676717ca324156b42bb17f3f20ef403` | `01_Matplotlib.pdf` | 18 | 46, 48, 49, 50, 52, 54, 97, 99, 101, 102 | +| `sha256:18ce863feb57f42f2b92ac85a8c55ef3eeaa15488c5d6cd8c724b085994c64fa` | `01_Matplotlib.pdf` | 12 | 46, 48, 49, 50, 51, 52, 97, 99, 105, 108 | +| `sha256:a3eb7054e426aad7d1fac1f39ad6d3f886e34c04f780def5cf22b53cb3a45b46` | `01_Matplotlib.pdf` | 15 | 46, 48, 49, 50, 52, 53, 54, 55, 56, 97 | +| `sha256:edd22119635bfb0f2bff750137c6c6400a7fae4ff80cc252d2e6f2ca88f599a7` | `01_Matplotlib.pdf` | 15 | 46, 48, 49, 50, 51, 52, 53, 54, 56, 97 | +| `sha256:aae1797f3e3ff55d71b02590333aff86663d6bb4a5768bed7550e5987f40afe8` | `01_Matplotlib.pdf` | 14 | 46, 48, 49, 50, 52, 53, 54, 56, 97, 99 | +| `sha256:0165552fad28860f2ea6079be7a87ea0833acde99309b3ef619c8f81707c46a3` | `01_Matplotlib.pdf` | 14 | 46, 48, 49, 50, 51, 52, 54, 97, 99, 105 | +| `sha256:792a1c5aaa1743ab203a363a8f6cd07c3b043e33c72e97c4ea21f5862158e6c1` | `01_Matplotlib.pdf` | 17 | 43, 46, 48, 49, 50, 51, 52, 53, 54, 56 | +| `sha256:f4bfd64f36bf33dea79800561a67f78d5ccdb436363574abf0892f58b376a2e6` | `01_Matplotlib.pdf` | 25 | 32, 46, 48, 49, 50, 51, 52, 53, 54, 85 | +| `sha256:119da04d962622c8aa46d77f6bdfccb5d4a4ef7173775275b046efd59098e5d9` | `01_Matplotlib.pdf` | 17 | 46, 48, 49, 50, 53, 55, 97, 101, 103, 105 | +| `sha256:003af1c45e3a5ab09544e226eba25e3a70abfe6e36dd48584474cc7a497685f6` | `01_Matplotlib.pdf` | 28 | 32, 40, 41, 46, 48, 49, 50, 52, 54, 56 | +| `sha256:88b3471db1978cc83233f249453806a8369c766b089b424c86c2584196ed5dbf` | `01_Matplotlib.pdf` | 14 | 46, 48, 49, 50, 52, 54, 56, 100, 101, 102 | +| `sha256:a15cc90b7fc110cef4f07fe8a692d572e1289a9ee29c95732294662fded4e042` | `01_Matplotlib.pdf` | 16 | 32, 46, 48, 49, 50, 51, 53, 79, 83, 97 | +| `sha256:fb54c23aa081562ac114676ffe43032c9c0fb63af3e5b7b3441b88872d1f2e7a` | `01_Matplotlib.pdf` | 16 | 46, 48, 49, 50, 52, 53, 54, 56, 66, 72 | +| `sha256:4b553d51d58f5891af071359fb016caf1c6137778da129a6b208dcc8cb0c4635` | `01_Matplotlib.pdf` | 9 | 46, 48, 49, 50, 51, 52, 53, 54, 56 | +| `sha256:93573cb1ab32b9cb09378298fb120de079f6a309908d2ee86f91392a6aba5c31` | `01_Matplotlib.pdf` | 30 | 32, 45, 48, 49, 50, 51, 52, 53, 54, 55 | +| `sha256:4febfad91e0141f9658506a0bf8fc2a449f0ea7d97b44e95fc9a970c77af4b0a` | `01_Matplotlib.pdf` | 7 | 48, 49, 50, 51, 52, 53, 54 | +| `sha256:0386e5811612ba4b998d57cd3869d7fbc48092a79d436deda774af107a4af813` | `01_Matplotlib.pdf` | 9 | 46, 48, 49, 50, 51, 52, 53, 54, 55 | +| `sha256:b95fa2a272cbc950b81320790d04fcf19ebb24050fa2139ba6a474172cac596b` | `01_Matplotlib.pdf` | 20 | 32, 40, 41, 48, 50, 52, 54, 56, 83, 85 | +| `sha256:b318f65b9dc209eb6f004e3a6c20a772ebbca3d752adc10c66a6a8a479da2838` | `01_Matplotlib.pdf` | 20 | 32, 40, 41, 46, 48, 49, 50, 52, 53, 54 | +| `sha256:64f725573c1f5d90196e94ed338a7af06baf274420414befeb9693c80acd0f77` | `01_Matplotlib.pdf` | 23 | 32, 46, 48, 49, 50, 51, 52, 53, 55, 57 | +| `sha256:9a701e082ba5a779e2b20b8de0c7844b3f7838ba8cd4bd7ef366893761fb994d` | `01_Matplotlib.pdf` | 10 | 46, 48, 49, 50, 51, 52, 53, 54, 55, 56 | +| `sha256:2f6f8d63ff6235f3b7cd6f5eba8076854892037afa2ea6962953b3e7cda3736e` | `01_Matplotlib.pdf` | 31 | 32, 40, 41, 44, 61, 65, 66, 67, 68, 70 | +| `sha256:f17b5eb0ee996d1388c548f79fa50fa2d8c6076959eff189bb745d156d54547f` | `01_Matplotlib.pdf` | 26 | 32, 39, 65, 66, 67, 68, 73, 97, 98, 100 | +| `sha256:f22c75548364bb25fc3efbe11f05c56e29f07c15c3046ddbc85a64e5cc5a97bd` | `01_Matplotlib.pdf` | 21 | 32, 48, 49, 50, 72, 80, 91, 93, 99, 100 | +| `sha256:54a6c2e4bc290b48e21eece7f81cb6633c4b53a91f198fdaabfc73743b0e4499` | `01_Matplotlib.pdf` | 15 | 48, 49, 50, 51, 52, 53, 54, 97, 100, 101 | +| `sha256:059af9dbaaab27c1d660ef00de6d4fd6e1687cfe2abca0a4c07265c2b2b450c6` | `01_Matplotlib.pdf` | 22 | 32, 46, 48, 49, 50, 51, 53, 55, 68, 77 | +| `sha256:6651550d7b913850087244b7a70961989c2efc6d8c8d060d8663ff087b7723f6` | `01_Matplotlib.pdf` | 20 | 32, 46, 48, 49, 50, 52, 54, 56, 97, 100 | +| `sha256:4d4ee6f04f57a40a589741df4747990ed485c192b0fc179a415aba822f352a8d` | `01_Matplotlib.pdf` | 26 | 32, 45, 48, 49, 50, 51, 52, 53, 56, 65 | +| `sha256:4febfad91e0141f9658506a0bf8fc2a449f0ea7d97b44e95fc9a970c77af4b0a` | `01_Matplotlib.pdf` | 7 | 48, 49, 50, 51, 52, 53, 54 | +| `sha256:e808a8ecba94bf0190ab7218bb0702698125ee2e456e82e00da709e8188e2bf8` | `01_Matplotlib.pdf` | 28 | 32, 46, 48, 49, 50, 53, 54, 70, 83, 84 | +| `sha256:b5064b202eb1dae41545eddf674ee23bd82176e76aac8eb749540c2689f2e3ec` | `01_Matplotlib.pdf` | 33 | 32, 33, 37, 48, 49, 50, 52, 53, 54, 68 | +| `sha256:f8f14410ec170248916e19f9d09120cfd786c47906b7c3735781d24e944b094e` | `01_Matplotlib.pdf` | 11 | 32, 83, 84, 101, 109, 110, 111, 115, 116, 119 | +| `sha256:2be58b6ef1e29a83b8634d70b9e32c37a15dea2e608894439ef7224c35b77f5d` | `01_Matplotlib.pdf` | 7 | 46, 48, 49, 50, 52, 53, 55 | +| `sha256:994c963d70041eee141fd275fa22c525a71283de2b4a952814d02e0bbfa8caea` | `01_Matplotlib.pdf` | 4 | 46, 48, 49, 53 | +| `sha256:c43134bebeaf8328ac299ba978d7e663e2dc4fe99463b9d7f72f72f77936204e` | `01_Matplotlib.pdf` | 9 | 48, 49, 50, 51, 52, 53, 54, 55, 56 | +| `sha256:4f763d5e2cd0bdcd4650936ac505bd0e011899712ffe80ffa4b4d43f42941327` | `01_Matplotlib.pdf` | 10 | 46, 48, 49, 50, 52, 54, 56, 98, 103, 114 | +| `sha256:2be58b6ef1e29a83b8634d70b9e32c37a15dea2e608894439ef7224c35b77f5d` | `01_Matplotlib.pdf` | 7 | 46, 48, 49, 50, 52, 53, 55 | +| `sha256:cb72de0c6105b9802d360c47a292a1f7bc344939a6801b879ea09dae4e45e863` | `01_Matplotlib.pdf` | 7 | 46, 48, 49, 50, 51, 52, 53 | +| `sha256:2add5b5ad6e536f3614b75e246b49a006edbbecdd309d24bd42c874a3ae3c8ed` | `01_Matplotlib.pdf` | 21 | 45, 48, 49, 50, 51, 52, 97, 99, 100, 101 | +| `sha256:85e16e36ed0290c149647be7e468a7c46e7b66fd290131213040f7bad905aa44` | `02_Matplotlib.pdf` | 25 | 32, 45, 46, 48, 49, 50, 52, 53, 54, 56 | +| `sha256:85e16e36ed0290c149647be7e468a7c46e7b66fd290131213040f7bad905aa44` | `02_Matplotlib.pdf` | 25 | 32, 45, 46, 48, 49, 50, 52, 53, 54, 56 | +| `sha256:059af9dbaaab27c1d660ef00de6d4fd6e1687cfe2abca0a4c07265c2b2b450c6` | `02_Matplotlib.pdf` | 22 | 32, 46, 48, 49, 50, 51, 53, 55, 68, 77 | +| `sha256:9a701e082ba5a779e2b20b8de0c7844b3f7838ba8cd4bd7ef366893761fb994d` | `02_Matplotlib.pdf` | 10 | 46, 48, 49, 50, 51, 52, 53, 54, 55, 56 | +| `sha256:2f6f8d63ff6235f3b7cd6f5eba8076854892037afa2ea6962953b3e7cda3736e` | `02_Matplotlib.pdf` | 31 | 32, 40, 41, 44, 61, 65, 66, 67, 68, 70 | +| `sha256:f17b5eb0ee996d1388c548f79fa50fa2d8c6076959eff189bb745d156d54547f` | `02_Matplotlib.pdf` | 26 | 32, 39, 65, 66, 67, 68, 73, 97, 98, 100 | +| `sha256:6651550d7b913850087244b7a70961989c2efc6d8c8d060d8663ff087b7723f6` | `02_Matplotlib.pdf` | 20 | 32, 46, 48, 49, 50, 52, 54, 56, 97, 100 | +| `sha256:4febfad91e0141f9658506a0bf8fc2a449f0ea7d97b44e95fc9a970c77af4b0a` | `02_Matplotlib.pdf` | 7 | 48, 49, 50, 51, 52, 53, 54 | +| `sha256:e808a8ecba94bf0190ab7218bb0702698125ee2e456e82e00da709e8188e2bf8` | `02_Matplotlib.pdf` | 28 | 32, 46, 48, 49, 50, 53, 54, 70, 83, 84 | +| `sha256:b5064b202eb1dae41545eddf674ee23bd82176e76aac8eb749540c2689f2e3ec` | `02_Matplotlib.pdf` | 33 | 32, 33, 37, 48, 49, 50, 52, 53, 54, 68 | +| `sha256:f8f14410ec170248916e19f9d09120cfd786c47906b7c3735781d24e944b094e` | `02_Matplotlib.pdf` | 11 | 32, 83, 84, 101, 109, 110, 111, 115, 116, 119 | +| `sha256:2be58b6ef1e29a83b8634d70b9e32c37a15dea2e608894439ef7224c35b77f5d` | `02_Matplotlib.pdf` | 7 | 46, 48, 49, 50, 52, 53, 55 | +| `sha256:994c963d70041eee141fd275fa22c525a71283de2b4a952814d02e0bbfa8caea` | `02_Matplotlib.pdf` | 4 | 46, 48, 49, 53 | +| `sha256:c43134bebeaf8328ac299ba978d7e663e2dc4fe99463b9d7f72f72f77936204e` | `02_Matplotlib.pdf` | 9 | 48, 49, 50, 51, 52, 53, 54, 55, 56 | +| `sha256:4f763d5e2cd0bdcd4650936ac505bd0e011899712ffe80ffa4b4d43f42941327` | `02_Matplotlib.pdf` | 10 | 46, 48, 49, 50, 52, 54, 56, 98, 103, 114 | +| `sha256:2be58b6ef1e29a83b8634d70b9e32c37a15dea2e608894439ef7224c35b77f5d` | `02_Matplotlib.pdf` | 7 | 46, 48, 49, 50, 52, 53, 55 | +| `sha256:cb72de0c6105b9802d360c47a292a1f7bc344939a6801b879ea09dae4e45e863` | `02_Matplotlib.pdf` | 7 | 46, 48, 49, 50, 51, 52, 53 | +| `sha256:31d0e67bc63a816302c9ff6ad9c19e17603aef1a4c3677b81b1d9084caa86e03` | `03_handout-beginner.pdf` | 6 | 46, 48, 49, 50, 51, 53 | +| `sha256:4b509d2ae2cfab89783a73df2c66f0fd50949f97696079cb58f1e58b81daaa07` | `03_handout-beginner.pdf` | 4 | 84, 101, 105, 109 | +| `sha256:831f7012db360331ffb5a5de6a6d6e03ffaad29f48d81cabe9fc613b25aad818` | `04_handout-intermediate.pdf` | 43 | 32, 40, 41, 46, 48, 49, 50, 51, 52, 53 | +| `sha256:bf790625423c5ebdf94760eb796c847af885b930d3a30861509b07f1c77c3f60` | `04_handout-intermediate.pdf` | 9 | 46, 48, 49, 50, 51, 52, 53, 54, 56 | +| `sha256:f7c3be2199c397a4c702dd434ac63fc9e046d749eff8cede4513fbc2774751b4` | `04_handout-intermediate.pdf` | 5 | 48, 49, 50, 51, 53 | +| `sha256:8f7bf7a6382e8a762c5a84f19f84f0675f61eb1b34bd42562c0b3ac6712e29ef` | `04_handout-intermediate.pdf` | 2 | 48, 49 | +| `sha256:dfaf8075e13be0e51f72485f9d825cea9ad077eb2dd9d63b9922add67d7d2761` | `04_handout-intermediate.pdf` | 12 | 32, 48, 49, 50, 51, 53, 80, 100, 101, 105 | +| `sha256:853422e67ac88fe7ae28d5c459dc9f5a84f24e7840eeb2d82a00719032119326` | `04_handout-intermediate.pdf` | 10 | 32, 67, 83, 97, 100, 101, 105, 110, 111, 115 | +| `sha256:b42182c55ec4bd53ab0698bee5f92945921dbccb534fdb5c6b41f1782e1fe88e` | `04_handout-intermediate.pdf` | 7 | 32, 48, 49, 50, 51, 53, 65 | +| `sha256:75466035ac34f2523215e599452e32d796d7d02bc7122ed3d02fe91ebe064c25` | `04_handout-intermediate.pdf` | 6 | 48, 49, 50, 52, 54, 56 | +| `sha256:75466035ac34f2523215e599452e32d796d7d02bc7122ed3d02fe91ebe064c25` | `04_handout-intermediate.pdf` | 6 | 48, 49, 50, 52, 54, 56 | + +## Alias: `dejavusans-bold` + +| Signature | Samples | Glyph Count | Coverage (first 10) | +| --- | --- | --- | --- | +| `sha256:dc03917f2edd92a7a68a46ad36f65a908e4feb85e61cb37e9026205f3986574a` | `01_Matplotlib.pdf` | 7 | 65, 87, 100, 101, 103, 105, 116 | +| `sha256:dc03917f2edd92a7a68a46ad36f65a908e4feb85e61cb37e9026205f3986574a` | `02_Matplotlib.pdf` | 7 | 65, 87, 100, 101, 103, 105, 116 | +| `sha256:c845063bef18f173afbfcb90fbf6773f43648c5f0666ecfa0132afe4e164068d` | `03_handout-beginner.pdf` | 9 | 32, 65, 83, 97, 101, 105, 110, 118, 119 | + +## Alias: `dejavusans-oblique` + +| Signature | Samples | Glyph Count | Coverage (first 10) | +| --- | --- | --- | --- | +| `sha256:81cd2d4d9353ee02c7ed80c2892658072b2a8bbd9ed1832b474129dfbe35d5d8` | `01_Matplotlib.pdf` | 13 | 70, 71, 85, 87, 100, 101, 103, 109, 112, 114 | +| `sha256:08864aa8e8d17cead6059d5b4f1b1eea2053fa0ea3ca64e885d6eaacb78bccaf` | `01_Matplotlib.pdf` | 2 | 100, 120 | + +## Alias: `dejavusansdisplay` + +| Signature | Samples | Glyph Count | Coverage (first 10) | +| --- | --- | --- | --- | +| `sha256:ae77c4eb2c49f72c616272f3d7ac624ddb0b4db1c77acbe6b9d13531f68e1d5d` | `01_Matplotlib.pdf` | 0 | | +| `sha256:ae77c4eb2c49f72c616272f3d7ac624ddb0b4db1c77acbe6b9d13531f68e1d5d` | `01_Matplotlib.pdf` | 0 | | + +## Alias: `dejavusansmono` + +| Signature | Samples | Glyph Count | Coverage (first 10) | +| --- | --- | --- | --- | +| `sha256:88758adf0b41a81204ed3ad63463f5d15c7c2f80e8942cee501d06fa7274dc4e` | `01_Matplotlib.pdf` | 8 | 97, 98, 105, 108, 109, 111, 112, 116 | +| `sha256:74e60bcb2d7975b0c7b372aca9fc25f55c9018005425a741830e7c4370b8d593` | `01_Matplotlib.pdf` | 24 | 35, 39, 48, 49, 50, 51, 52, 53, 54, 55 | + +## Alias: `f36` + +| Signature | Samples | Glyph Count | Coverage (first 10) | +| --- | --- | --- | --- | +| `sha256:72c7041f938222b87ce2d9295547f8c19edf250af538160b69be35a968d76ea7` | `08_matplotlib.pdf` | 1 | 136 | + +## Alias: `f59` + +| Signature | Samples | Glyph Count | Coverage (first 10) | +| --- | --- | --- | --- | +| `sha256:d5942c0913ef64ae862556a746b28dac1a621caa5e05973e16881c8e8e15e329` | `08_matplotlib.pdf` | 1 | 42 | + +## Alias: `sourcecodepro-regular` + +| Signature | Samples | Glyph Count | Coverage (first 10) | +| --- | --- | --- | --- | +| `sha256:96ba693001b2ab224ad5b5a7464cecd4d33e68f30fb23f78a8473dbb031ce246` | `04_handout-intermediate.pdf` | 11 | 48, 49, 50, 51, 52, 53, 54, 55, 56, 57 | +| `sha256:72fca14e9e44fc41b0cdb1c6a088f0b07f882f9f04c51a0145f43cf8b285c5b6` | `04_handout-intermediate.pdf` | 11 | 46, 48, 49, 50, 51, 52, 53, 54, 55, 56 | + +## Alias: `stixsizethreesym-regular` + +| Signature | Samples | Glyph Count | Coverage (first 10) | +| --- | --- | --- | --- | +| `sha256:33d0ab9d9d72c1aed1edfc9b815dd6a2d618cbbe9084309c7f2de0f3df3073d7` | `01_Matplotlib.pdf` | 2 | 91, 93 | + +## Alias: `unknown` + +| Signature | Samples | Glyph Count | Coverage (first 10) | +| --- | --- | --- | --- | +| `sha256:23e4b174e951cd6135e229fb397db4ff518021cf14d5f817031b9f754841e511` | `07_matplotlib.pdf` | 11 | 0, 46, 97, 98, 105, 108, 109, 111, 112, 116 | +| `sha256:f6112d6a35d5fdf5d6431b3156b713020953154042814ad12d2b81731c97250b` | `07_matplotlib.pdf` | 13 | 0, 32, 37, 97, 98, 101, 105, 108, 109, 110 | +| `sha256:7e05c074b630c0f3e1fc23537c22bf4b6191c783601e534cd156f71c1827702c` | `07_matplotlib.pdf` | 42 | 0, 32, 34, 37, 39, 40, 41, 42, 44, 46 | +| `sha256:9958bc1f309f6bafb55834e271bb0b337704fcac51f6d989abe9553fcffa103d` | `07_matplotlib.pdf` | 15 | 0, 46, 97, 98, 105, 108, 109, 110, 111, 112 | diff --git a/docs/type3_fallback_plan.md b/docs/type3_fallback_plan.md new file mode 100644 index 000000000..3ef7e6ad2 --- /dev/null +++ b/docs/type3_fallback_plan.md @@ -0,0 +1,150 @@ +# Type3 Font Library & Matching Plan + +This file documents where we are with Type3 font handling, what tooling already exists, and what remains to be done so future work (or another Codex session) can pick it up quickly. + +## Goal +Ensure Type3 fonts keep their appearance when users edit/export PDFs. That means: +1. Identifying common Type3 fonts we encounter (Matplotlib, LaTeX, etc.). +2. Capturing their glyph outlines once, converting them to reusable TTF/OTF binaries. +3. At runtime, matching Type3 fonts in incoming PDFs against that library (by signature) so we can embed the canonical TTF instead of falling back to generic fonts. +4. Using the captured char-code sequences so regeneration and editing preserves glyphs even when original fonts had no ToUnicode map. + +## Current State +- **Extraction**: `PdfJsonTextElement` now stores raw Type3 char codes; `encodeTextWithFont` can use them so token-level rewrites keep original glyphs. +- **Regeneration**: Page regeneration now uses those char codes when writing new content streams, so existing text should remain visible even when tokens must be rebuilt. +- **Scripts**: `scripts/index_type3_catalogue.py` scans PDFs in `app/core/src/main/resources/type3/samples` with `pdffonts` and writes `catalogue.json` (basic list of Type3 fonts encountered). This is only the first step; we still need per-font signatures and converted binaries. +- **Samples**: There are sample PDFs under `app/core/src/main/resources/type3/samples/` (Matplotlib slides, etc.) that we can mine for common Type3 fonts. +- **Library matching**: `Type3FontLibrary` loads `type3/library/index.json`, and `Type3LibraryStrategy` injects the prebuilt TTF/OTF payloads straight into `PdfJsonFont` conversion candidates. At runtime this is now the *only* conversion path; if the library does not recognise a signature we fall back to the captured Type3 glyph codes instead of trying to synthesize a font on the fly. +- **Offline conversion helpers**: `scripts/type3_to_cff.py` is still available for developers who need to turn a Type3-only PDF into a reusable TTF/OTF, but it is no longer wired into the server lifecycle. Everything shipped to users must be backed by the curated library. +- **Signature CLI**: `Type3SignatureTool` (`./gradlew :proprietary:type3SignatureTool --args="--pdf sample.pdf --output meta.json --pretty"`) dumps every Type3 font in a PDF along with its signature + glyph coverage. Use this to extend `index.json` without touching the backend. +- **Signature inventory**: `docs/type3/signatures/` stores the captured dumps, and `scripts/summarize_type3_signatures.py` keeps `docs/type3/signature_inventory.md` up to date so we know which aliases still need binaries. + +## Remaining Work +1. **Signature capture tooling** + - ✅ `Type3SignatureTool` (`./gradlew :proprietary:type3SignatureTool`) dumps signature + glyph coverage JSON; keep them under `docs/type3/signatures`. + - ✅ `scripts/summarize_type3_signatures.py` produces `docs/type3/signature_inventory.md` to highlight remaining gaps. + - ✅ `scripts/harvest_type3_fonts.py --input ` bulk-processes entire PDF folders, reusing cached signature JSON files and writing `docs/type3/harvest_report.json` so you can keep adding new samples over time. + - ✅ `scripts/download_pdf_samples.py` downloads large batches of PDF URLs into a staging folder that can immediately be fed to the harvester. + - ⏱️ Extend `scripts/index_type3_catalogue.py` to read those dumps so the catalogue and library stay in sync. + +2. **Library coverage** + - ✅ Added CM (cmr10/cmmi10/cmex10/cmsy10), STIX Size Three symbols, and SourceCodePro (SauceCode) using upstream TTF/OTF payloads. + - 🔜 Add Matplotlib-only subsets (F36/F59). For proprietary Type3 shapes, use the offline FontTools helper (`scripts/type3_to_cff.py`) to generate TTF/OTF payloads, drop them under `type3/library/fonts//`, and reference them from `index.json`. + - Each entry in `type3/library/index.json` should contain `{id, aliases, signatures, glyphCoverage, program/web/pdf payloads, source PDF}`. + +3. **Glyph coverage metadata** + - ✅ When adding a library entry, copy the `glyphCoverage` array from the signature JSON so runtime preflight knows exactly which code points exist. The backend now consults this data while building new text runs so characters stay on the original Type3 font whenever it supports them. + +4. **Automation** + - ✅ `scripts/update_type3_library.py` ingests the captured signature JSON files, merges their signatures/aliases/glyph coverage into `app/core/src/main/resources/type3/library/index.json`, and reports any fonts that still lack entries. Run it with `--apply` after harvesting new samples. + +5. **Validation** + - 🔁 After each new library entry, run a JSON→PDF roundtrip on the source PDF to confirm edited text sticks with the canonical font (FontTools stays disabled unless the font is missing). + +## Tooling/Dependencies +- Requires `pdffonts` (poppler-utils) for the current indexing script. +- Optional: `scripts/type3_to_cff.py` (fontTools) when you need to manufacture a TTF/OTF for an otherwise Type3-only font before adding it to the library. +- Backend relies on PDFBox 3.x. + +## Library Onboarding Workflow +Follow this loop whenever you encounter a new Type3 face that is missing from the library: + +1. **Capture signatures** + Run `./gradlew :proprietary:type3SignatureTool --args="--pdf path/to/sample.pdf --output docs/type3/signatures/.json --pretty"` to dump the font’s signature, glyph coverage, and aliases. Commit the JSON under `docs/type3/signatures/`. + +2. **Harvest more samples (optional)** + Use `scripts/harvest_type3_fonts.py --input ` to bulk-run the signature tool across a directory of PDFs. This keeps `docs/type3/signature_inventory.md` fresh so you can see how often each alias appears. + +3. **Collect a canonical TTF/OTF** + - If the font is really just a subset of a known family (DejaVu, Computer Modern, STIX, etc.), copy the upstream TTF/OTF into `app/core/src/main/resources/type3/library/fonts//`. + - If no canonical binary exists, feed the sample PDF through `scripts/type3_to_cff.py --input glyphs.json --ttf-output ` to synthesize one offline. Review the glyphs visually before committing. + +4. **Update the library index** + Reference the binary from `app/core/src/main/resources/type3/library/index.json` (use the `resource` field so the build packs the raw TTF/OTF). Add the captured signatures, aliases, glyph coverage, and the PDF you mined as `source`. + +5. **Apply bulk edits automatically** + After dropping new signature dumps, run `scripts/update_type3_library.py --apply` to merge any missing signatures/aliases/coverage entries into `index.json`. The script prints a list of fonts that still lack binaries so you know what to tackle next. + +6. **Verify the round-trip** + Convert the sample PDF to JSON through the app, edit text to introduce new characters, and export it back to PDF. The logs should show `[TYPE3] Strategy type3-library finished with status SUCCESS`, and the output should keep the original styling even for the new glyphs. + +Because the server no longer attempts runtime synthesis, once a font lands in the library it will stay stable across every deployment. Missing fonts simply fall back to their Type3 glyph codes until you add them to the index, so there is always a deterministic path forward. + +## How to Use the Existing Script +``` +# From repo root +scripts/index_type3_catalogue.py \ + --samples app/core/src/main/resources/type3/samples \ + --output app/core/src/main/resources/type3/catalogue.json +``` +Output is a simple JSON array with `source`, `fontName`, and `encoding`. This needs to be extended with signatures and references to the converted TTFs once that tooling is in place. + +## Expected Outcomes +- A deduplicated library of the most common Type3 fonts we encounter, each with a stable signature and prebuilt TTF/OTF. +- Backend automatically matches a Type3 font to its library entry and embeds the canonical TTF during edit/export. +- Fallback font usage drops dramatically; edited PDFs retain the original look with Type3Synth fonts only used when genuinely necessary. +- Additional metrics (e.g., glyph coverage) stored in the catalogue so we can diagnose gaps quickly. + +## Next Steps Checklist +1. Capture signatures for every sample font and add them to `type3/library/index.json`. +2. Extend catalogue JSON to include signatures + metadata. +3. Batch-convert the remaining samples into the Type3 library (TTF/OTF files under `resources/type3/library/`). +4. Provide doc or script for adding new fonts to the library. +5. Run regression tests on sample PDFs to ensure original text remains visible and new text matches the Type3 font whenever possible. + +## Library Layout Cheat Sheet +- **Index**: `app/core/src/main/resources/type3/library/index.json`. +- **Font payloads**: drop TTF/OTF data under `type3/library/fonts//.ttf`. +- **Entry schema**: + ```json + { + "id": "unique-id", + "label": "Human readable name", + "signatures": ["sha256:..."], + "aliases": ["SubsetPrefix+RealName"], + "program": {"resource": "type3/library/fonts/family/font.otf", "format": "otf"}, + "webProgram": {"resource": "...", "format": "ttf"}, + "pdfProgram": {"resource": "...", "format": "ttf"}, + "glyphCoverage": [32,65,66], + "source": "Where the sample came from" + } + ``` +- **Runtime flow**: + 1. `Type3FontConversionService` builds a `Type3ConversionRequest`. + 2. `Type3LibraryStrategy` hashes the font via `Type3FontSignatureCalculator`. + 3. If the signature/alias exists in the index, it injects the canonical payload as a `PdfJsonFontConversionCandidate`. + 4. `PdfJsonConversionService` prefers conversion candidates over embedded Type3 programs when reloading fonts, so new text uses the canonical TTF automatically. + +### Signature Capture Tool +``` +# Dump all Type3 fonts in a PDF, their signatures, and glyph coverage +./gradlew :proprietary:type3SignatureTool \ + --args="--pdf app/core/src/main/resources/type3/samples/01_Matplotlib.pdf --output tmp/signatures.json --pretty" +``` +Use the resulting JSON to fill `signatures`, `aliases`, and `glyphCoverage` in `type3/library/index.json`. Once an entry exists, runtime conversion will reuse that payload and skip the costly FontTools synthesis. + +--- +Feel free to expand this plan or add notes as the work progresses. + +--- + +## Practical Workflow (from PDF ingestion to runtime use) + +| Stage | Tool / Command | Output | +| --- | --- | --- | +| 1. Collect PDFs | `python scripts/download_pdf_collection.py --output scripts/pdf-collection` (or drop your own PDFs anywhere) | Raw PDFs ready for harvesting | +| 2. Harvest signatures | `python scripts/harvest_type3_fonts.py --input scripts/pdf-collection --pretty` | Per-PDF dumps in `docs/type3/signatures/…` + global summary `docs/type3/harvest_report.json` | +| 3. Summarize backlog | `python scripts/summarize_type3_signatures.py` | `docs/type3/signature_inventory.md` (human checklist of aliases/signatures) | +| 4. Convert fonts | Either copy the upstream TTF/OTF for the font (DejaVu, CM, STIX, etc.) or run `scripts/type3_to_cff.py` against the harvested glyph JSON to synthesize one offline; store the result under `app/core/src/main/resources/type3/library/fonts//`. | Canonical font binaries | +| 5. Register entry | Edit `app/core/src/main/resources/type3/library/index.json` (add `id`, `aliases`, `signatures`, `glyphCoverage`, and point `program/web/pdf` to the binaries). | Runtime-ready index | +| 6. Verify in app | Run a PDF→JSON→PDF roundtrip on a sample containing the font; check logs for `[TYPE3] Strategy type3-library finished with status SUCCESS`. | Confidence that edits use the canonical TTF | + +### Expected artifacts in the repo +- `scripts/pdf-collection/` — downloaded PDFs (input to the pipeline). +- `docs/type3/signatures/<...>.json` — raw signature dumps (one per PDF). +- `docs/type3/harvest_report.json` — deduplicated list of every signature encountered to date. +- `docs/type3/signature_inventory.md` — Markdown table summarizing signatures/aliases for triage. +- `app/core/src/main/resources/type3/library/fonts//.ttf` — curated binaries. +- `app/core/src/main/resources/type3/library/index.json` — mapping used at runtime. + +Once an entry exists in `index.json`, the backend automatically attaches that TTF/OTF during PDF→JSON, caches a normalized PDFont, and uses it for JSON→PDF regeneration. This eliminates the `PDType3Font.encode` limitation and keeps edited text visually identical to the original Type3 output. diff --git a/frontend/src/proprietary/tools/pdfJsonEditor/pdfJsonEditorTypes.ts b/frontend/src/proprietary/tools/pdfJsonEditor/pdfJsonEditorTypes.ts index 116838bee..97d6c7423 100644 --- a/frontend/src/proprietary/tools/pdfJsonEditor/pdfJsonEditorTypes.ts +++ b/frontend/src/proprietary/tools/pdfJsonEditor/pdfJsonEditorTypes.ts @@ -65,6 +65,7 @@ export interface PdfJsonTextElement { textMatrix?: number[] | null; fillColor?: PdfJsonTextColor | null; strokeColor?: PdfJsonTextColor | null; + charCodes?: number[] | null; fallbackUsed?: boolean | null; } diff --git a/frontend/src/proprietary/tools/pdfJsonEditor/pdfJsonEditorUtils.ts b/frontend/src/proprietary/tools/pdfJsonEditor/pdfJsonEditorUtils.ts index cb6f16338..52cec1675 100644 --- a/frontend/src/proprietary/tools/pdfJsonEditor/pdfJsonEditorUtils.ts +++ b/frontend/src/proprietary/tools/pdfJsonEditor/pdfJsonEditorUtils.ts @@ -70,6 +70,13 @@ export const cloneTextElement = (element: PdfJsonTextElement): PdfJsonTextElemen textMatrix: element.textMatrix ? [...element.textMatrix] : element.textMatrix ?? undefined, }); +const clearGlyphHints = (element: PdfJsonTextElement): void => { + if (!element) { + return; + } + element.charCodes = undefined; +}; + export const cloneImageElement = (element: PdfJsonImageElement): PdfJsonImageElement => ({ ...element, transform: element.transform ? [...element.transform] : element.transform ?? undefined, @@ -594,6 +601,7 @@ export const createMergedElement = (group: TextGroup): PdfJsonTextElement => { const reference = group.originalElements[0]; const merged = cloneTextElement(reference); merged.text = group.text; + clearGlyphHints(merged); if (reference.textMatrix && reference.textMatrix.length === 6) { merged.textMatrix = [...reference.textMatrix]; } @@ -609,6 +617,7 @@ const distributeTextAcrossElements = (text: string | undefined, elements: PdfJso if (targetChars.length === 0) { elements.forEach((element) => { element.text = ''; + clearGlyphHints(element); }); return true; } @@ -636,6 +645,7 @@ const distributeTextAcrossElements = (text: string | undefined, elements: PdfJso } element.text = sliceLength > 0 ? targetChars.slice(cursor, cursor + sliceLength).join('') : ''; + clearGlyphHints(element); cursor += sliceLength; }); diff --git a/scripts/download_pdf_collection.py b/scripts/download_pdf_collection.py new file mode 100644 index 000000000..f28926597 --- /dev/null +++ b/scripts/download_pdf_collection.py @@ -0,0 +1,583 @@ +#!/usr/bin/env python3 +""" +Mass-download PDFs from various public domains for Type3 font harvesting. + +Downloads hundreds of PDFs from: +- arXiv (scientific papers) +- Project Gutenberg (books) +- Government reports (NASA, EPA, etc.) +- Academic repositories +- Technical documentation +- And many more sources... + +Run with: python scripts/download_pdf_collection.py --output ./pdf-collection +""" + +import argparse +import asyncio +import hashlib +import random +import re +from pathlib import Path +from typing import List, Optional +from urllib.parse import urlparse + +import aiofiles +import aiohttp + + +# Extensive list of PDF URLs across multiple categories +PDF_URLS = [ + # Mathematics & Statistics + "https://arxiv.org/pdf/2103.14030.pdf", # Swin Transformer + "https://arxiv.org/pdf/2010.11929.pdf", # Vision Transformer + "https://arxiv.org/pdf/2005.14165.pdf", # GPT-3 Paper + "https://arxiv.org/pdf/1910.10683.pdf", # T5 Text-to-Text Transformer + "https://arxiv.org/pdf/1810.04805.pdf", # BERT + "https://arxiv.org/pdf/1706.03762.pdf", # Attention Is All You Need + "https://arxiv.org/pdf/1603.04467.pdf", # TensorFlow White Paper + "https://arxiv.org/pdf/1511.06434.pdf", # DCGAN + "https://arxiv.org/pdf/1506.03378.pdf", # LIME + "https://arxiv.org/pdf/1409.1556.pdf", # VGGNet + "https://arxiv.org/pdf/1312.6114.pdf", # Variational Autoencoders + "https://arxiv.org/pdf/1211.4240.pdf", # AlexNet + "https://arxiv.org/pdf/1106.1813.pdf", # CIFAR-10 + "https://arxiv.org/pdf/1003.0358.pdf", # SVM Theory + "https://arxiv.org/pdf/0909.4061.pdf", # Random Forests + + # Physics + "https://arxiv.org/pdf/2303.08774.pdf", # Quantum Computing + "https://arxiv.org/pdf/2201.04294.pdf", # Dark Matter Research + "https://arxiv.org/pdf/2105.00552.pdf", # Gravitational Waves + "https://arxiv.org/pdf/2004.00007.pdf", # Particle Physics + "https://arxiv.org/pdf/1906.10176.pdf", # Cosmology + "https://arxiv.org/pdf/1807.02101.pdf", # String Theory + "https://arxiv.org/pdf/1708.05671.pdf", # Quantum Entanglement + "https://arxiv.org/pdf/1605.08625.pdf", # Astrophysics + + # Computer Science + "https://arxiv.org/pdf/2204.02311.pdf", # PaLM Language Model + "https://arxiv.org/pdf/2112.07804.pdf", # Stable Diffusion + "https://arxiv.org/pdf/2107.03374.pdf", # Codex + "https://arxiv.org/pdf/2010.02559.pdf", # Neural Architecture Search + "https://arxiv.org/pdf/1912.01703.pdf", # YOLOv4 + "https://arxiv.org/pdf/1905.11946.pdf", # EfficientNet + "https://arxiv.org/pdf/1812.01187.pdf", # BERT Large + "https://arxiv.org/pdf/1801.00631.pdf", # Transformer Applications + "https://arxiv.org/pdf/1704.04861.pdf", # MobileNet + "https://arxiv.org/pdf/1602.07360.pdf", # SqueezeNet + "https://arxiv.org/pdf/1512.03385.pdf", # ResNet + "https://arxiv.org/pdf/1506.02640.pdf", # YOLO + "https://arxiv.org/pdf/1502.03167.pdf", # Batch Normalization + "https://arxiv.org/pdf/1412.6980.pdf", # Adam Optimizer + "https://arxiv.org/pdf/1409.4842.pdf", # GoogLeNet + "https://arxiv.org/pdf/1312.5602.pdf", # Deep Q-Network + "https://arxiv.org/pdf/1301.3781.pdf", # Word2Vec + "https://arxiv.org/pdf/1207.0580.pdf", # Dropout + "https://arxiv.org/pdf/1102.1803.pdf", # ImageNet Classification + + # Government Reports + "https://www.nasa.gov/sites/default/files/atoms/files/2023_nasa_annual_report.pdf", + "https://www.nasa.gov/sites/default/files/atoms/files/2022_nasa_annual_report.pdf", + "https://www.nasa.gov/sites/default/files/atoms/files/2021_nasa_annual_report.pdf", + "https://www.epa.gov/system/files/documents/2023-01/epa-strategic-plan-2022-2026.pdf", + "https://www.epa.gov/system/files/documents/2022-12/epa-annual-report-2022.pdf", + "https://www.nist.gov/system/files/documents/2023/02/15/NIST%20Annual%20Report%202022.pdf", + "https://www.nist.gov/system/files/documents/2022/03/01/NIST%20Annual%20Report%202021.pdf", + "https://www.noaa.gov/sites/default/files/2023-03/NOAA%20Annual%20Report%202022.pdf", + "https://www.fda.gov/media/165773/download", + "https://www.fda.gov/media/159722/download", + "https://www.cdc.gov/mmwr/PDF/wk/mm7201.pdf", + "https://www.cdc.gov/nchs/data/nvsr/nvsr71/nvsr71-01.pdf", + "https://www.bls.gov/opub/mlr/2023/article/pdf/labor-force-projections-2022-2032.pdf", + "https://www.bls.gov/opub/mlr/2023/article/pdf/union-membership-2022.pdf", + "https://www.census.gov/content/dam/Census/library/publications/2023/demo/p60-280.pdf", + "https://www.energy.gov/sites/default/files/2023-04/DOE%20Annual%20Report%202022.pdf", + + # Project Gutenberg Classics + "https://www.gutenberg.org/files/1342/1342-pdf.pdf", # Pride and Prejudice + "https://www.gutenberg.org/files/84/84-pdf.pdf", # Frankenstein + "https://www.gutenberg.org/files/11/11-pdf.pdf", # Alice in Wonderland + "https://www.gutenberg.org/files/1661/1661-pdf.pdf", # Sherlock Holmes + "https://www.gutenberg.org/files/98/98-pdf.pdf", # Tale of Two Cities + "https://www.gutenberg.org/files/2701/2701-pdf.pdf", # Moby Dick + "https://www.gutenberg.org/files/2542/2542-pdf.pdf", # A Doll's House + "https://www.gutenberg.org/files/174/174-pdf.pdf", # Picture of Dorian Gray + "https://www.gutenberg.org/files/1952/1952-pdf.pdf", # The Yellow Wallpaper + "https://www.gutenberg.org/files/1080/1080-pdf.pdf", # A Modest Proposal + "https://www.gutenberg.org/files/43/43-pdf.pdf", # Dr. Jekyll and Mr. Hyde + "https://www.gutenberg.org/files/345/345-pdf.pdf", # Dracula + "https://www.gutenberg.org/files/5200/5200-pdf.pdf", # Metamorphosis + "https://www.gutenberg.org/files/76/76-pdf.pdf", # Adventures of Huckleberry Finn + "https://www.gutenberg.org/files/74/74-pdf.pdf", # Tom Sawyer + "https://www.gutenberg.org/files/1260/1260-pdf.pdf", # Jane Eyre + "https://www.gutenberg.org/files/768/768-pdf.pdf", # Wuthering Heights + "https://www.gutenberg.org/files/219/219-pdf.pdf", # Heart of Darkness + "https://www.gutenberg.org/files/1184/1184-pdf.pdf", # The Odyssey + "https://www.gutenberg.org/files/2600/2600-pdf.pdf", # War and Peace + + # Technical Documentation + "https://www.kernel.org/doc/ols/2007/ols2007v1-pages-215-224.pdf", + "https://www.kernel.org/doc/ols/2008/ols2008v1-pages-133-142.pdf", + "https://www.kernel.org/doc/ols/2009/ols2009v1-pages-77-86.pdf", + "https://www.postgresql.org/files/documentation/pdf/15/postgresql-15-US.pdf", + "https://www.postgresql.org/files/documentation/pdf/14/postgresql-14-US.pdf", + "https://www.postgresql.org/files/documentation/pdf/13/postgresql-13-US.pdf", + "https://www.python.org/doc/essays/blt.pdf", + "https://www.python.org/doc/essays/gui-py.pdf", + + # Academic Journals + "https://www.ams.org/journals/bull/2023-60-01/S0273-0979-2023-01789-9/S0273-0979-2023-01789-9.pdf", + "https://www.ams.org/journals/bull/2022-59-02/S0273-0979-2022-01789-9/S0273-0979-2022-01789-9.pdf", + "https://www.ams.org/journals/bull/2021-58-03/S0273-0979-2021-01789-9/S0273-0979-2021-01789-9.pdf", + "https://www.ams.org/notices/202304/rnoti-p434.pdf", + "https://www.ams.org/notices/202203/rnoti-p434.pdf", + "https://www.ams.org/notices/202102/rnoti-p434.pdf", + + # Conference Papers + "https://www.usenix.org/system/files/conference/atc18/atc18-paper-zhang.pdf", + "https://www.usenix.org/system/files/conference/nsdi18/nsdi18-paper-briscoe.pdf", + "https://www.usenix.org/system/files/conference/osdi18/osdi18-paper-belay.pdf", + "https://dl.acm.org/doi/pdf/10.1145/3579990.3580020", + "https://dl.acm.org/doi/pdf/10.1145/3543507.3583301", + "https://dl.acm.org/doi/pdf/10.1145/3519935.3520001", + + # Medical Research + "https://www.nejm.org/doi/pdf/10.1056/NEJMoa2208343", + "https://www.nejm.org/doi/pdf/10.1056/NEJMoa2208344", + "https://www.nejm.org/doi/pdf/10.1056/NEJMoa2208345", + "https://jamanetwork.com/journals/jama/article-abstract/2801234/pdf", + "https://jamanetwork.com/journals/jama/article-abstract/2801235/pdf", + "https://jamanetwork.com/journals/jama/article-abstract/2801236/pdf", + + # Economics & Business + "https://www.nber.org/papers/w12345.pdf", + "https://www.nber.org/papers/w12346.pdf", + "https://www.nber.org/papers/w12347.pdf", + "https://www.imf.org/en/Publications/WP/Issues/2023/03/15/paper-12345", + "https://www.imf.org/en/Publications/WP/Issues/2023/03/16/paper-12346", + "https://www.imf.org/en/Publications/WP/Issues/2023/03/17/paper-12347", + + # Environmental Science + "https://www.ipcc.ch/report/ar6/wg1/downloads/report/IPCC_AR6_WGI_FullReport.pdf", + "https://www.ipcc.ch/report/ar6/wg2/downloads/report/IPCC_AR6_WGII_FullReport.pdf", + "https://www.ipcc.ch/report/ar6/wg3/downloads/report/IPCC_AR6_WGIII_FullReport.pdf", + "https://www.epa.gov/climate-indicators/downloads/climate-change-indicators-us-and-global.pdf", + + # Mathematics (continued) + "https://arxiv.org/pdf/2301.00001.pdf", + "https://arxiv.org/pdf/2301.00002.pdf", + "https://arxiv.org/pdf/2301.00003.pdf", + "https://arxiv.org/pdf/2301.00004.pdf", + "https://arxiv.org/pdf/2301.00005.pdf", + "https://arxiv.org/pdf/2301.00006.pdf", + "https://arxiv.org/pdf/2301.00007.pdf", + "https://arxiv.org/pdf/2301.00008.pdf", + "https://arxiv.org/pdf/2301.00009.pdf", + "https://arxiv.org/pdf/2301.00010.pdf", + "https://arxiv.org/pdf/2301.00011.pdf", + "https://arxiv.org/pdf/2301.00012.pdf", + "https://arxiv.org/pdf/2301.00013.pdf", + "https://arxiv.org/pdf/2301.00014.pdf", + "https://arxiv.org/pdf/2301.00015.pdf", + "https://arxiv.org/pdf/2301.00016.pdf", + "https://arxiv.org/pdf/2301.00017.pdf", + "https://arxiv.org/pdf/2301.00018.pdf", + "https://arxiv.org/pdf/2301.00019.pdf", + "https://arxiv.org/pdf/2301.00020.pdf", + + # Computer Science (continued) + "https://arxiv.org/pdf/2302.00001.pdf", + "https://arxiv.org/pdf/2302.00002.pdf", + "https://arxiv.org/pdf/2302.00003.pdf", + "https://arxiv.org/pdf/2302.00004.pdf", + "https://arxiv.org/pdf/2302.00005.pdf", + "https://arxiv.org/pdf/2302.00006.pdf", + "https://arxiv.org/pdf/2302.00007.pdf", + "https://arxiv.org/pdf/2302.00008.pdf", + "https://arxiv.org/pdf/2302.00009.pdf", + "https://arxiv.org/pdf/2302.00010.pdf", + "https://arxiv.org/pdf/2302.00011.pdf", + "https://arxiv.org/pdf/2302.00012.pdf", + "https://arxiv.org/pdf/2302.00013.pdf", + "https://arxiv.org/pdf/2302.00014.pdf", + "https://arxiv.org/pdf/2302.00015.pdf", + "https://arxiv.org/pdf/2302.00016.pdf", + "https://arxiv.org/pdf/2302.00017.pdf", + "https://arxiv.org/pdf/2302.00018.pdf", + "https://arxiv.org/pdf/2302.00019.pdf", + "https://arxiv.org/pdf/2302.00020.pdf", + + # Physics (continued) + "https://arxiv.org/pdf/2303.00001.pdf", + "https://arxiv.org/pdf/2303.00002.pdf", + "https://arxiv.org/pdf/2303.00003.pdf", + "https://arxiv.org/pdf/2303.00004.pdf", + "https://arxiv.org/pdf/2303.00005.pdf", + "https://arxiv.org/pdf/2303.00006.pdf", + "https://arxiv.org/pdf/2303.00007.pdf", + "https://arxiv.org/pdf/2303.00008.pdf", + "https://arxiv.org/pdf/2303.00009.pdf", + "https://arxiv.org/pdf/2303.00010.pdf", + "https://arxiv.org/pdf/2303.00011.pdf", + "https://arxiv.org/pdf/2303.00012.pdf", + "https://arxiv.org/pdf/2303.00013.pdf", + "https://arxiv.org/pdf/2303.00014.pdf", + "https://arxiv.org/pdf/2303.00015.pdf", + "https://arxiv.org/pdf/2303.00016.pdf", + "https://arxiv.org/pdf/2303.00017.pdf", + "https://arxiv.org/pdf/2303.00018.pdf", + "https://arxiv.org/pdf/2303.00019.pdf", + "https://arxiv.org/pdf/2303.00020.pdf", + + # More Government Reports + "https://www.fda.gov/media/165773/download", + "https://www.fda.gov/media/165774/download", + "https://www.fda.gov/media/165775/download", + "https://www.fda.gov/media/165776/download", + "https://www.fda.gov/media/165777/download", + "https://www.fda.gov/media/165778/download", + "https://www.fda.gov/media/165779/download", + "https://www.fda.gov/media/165780/download", + "https://www.cdc.gov/mmwr/PDF/wk/mm7202.pdf", + "https://www.cdc.gov/mmwr/PDF/wk/mm7203.pdf", + "https://www.cdc.gov/mmwr/PDF/wk/mm7204.pdf", + "https://www.cdc.gov/mmwr/PDF/wk/mm7205.pdf", + "https://www.cdc.gov/mmwr/PDF/wk/mm7206.pdf", + "https://www.cdc.gov/mmwr/PDF/wk/mm7207.pdf", + "https://www.cdc.gov/mmwr/PDF/wk/mm7208.pdf", + "https://www.cdc.gov/mmwr/PDF/wk/mm7209.pdf", + "https://www.cdc.gov/mmwr/PDF/wk/mm7210.pdf", + + # More Project Gutenberg + "https://www.gutenberg.org/files/46/46-pdf.pdf", # A Christmas Carol + "https://www.gutenberg.org/files/45/45-pdf.pdf", # The Scarlet Letter + "https://www.gutenberg.org/files/44/44-pdf.pdf", # The Strange Case of Dr. Jekyll and Mr. Hyde + "https://www.gutenberg.org/files/43/43-pdf.pdf", # The Odyssey + "https://www.gutenberg.org/files/42/42-pdf.pdf", # The Iliad + "https://www.gutenberg.org/files/41/41-pdf.pdf", # The Republic + "https://www.gutenberg.org/files/40/40-pdf.pdf", # The Prince + "https://www.gutenberg.org/files/39/39-pdf.pdf", # The Art of War + "https://www.gutenberg.org/files/38/38-pdf.pdf", # The King James Bible + "https://www.gutenberg.org/files/37/37-pdf.pdf", # The Quran + "https://www.gutenberg.org/files/36/36-pdf.pdf", # The Book of Mormon + "https://www.gutenberg.org/files/35/35-pdf.pdf", # The Tao Te Ching + "https://www.gutenberg.org/files/34/34-pdf.pdf", # The Analects of Confucius + "https://www.gutenberg.org/files/33/33-pdf.pdf", # The Dhammapada + "https://www.gutenberg.org/files/32/32-pdf.pdf", # The Upanishads + "https://www.gutenberg.org/files/31/31-pdf.pdf", # The Vedas + "https://www.gutenberg.org/files/30/30-pdf.pdf", # The Bhagavad Gita + "https://www.gutenberg.org/files/29/29-pdf.pdf", # The Ramayana + "https://www.gutenberg.org/files/28/28-pdf.pdf", # The Mahabharata + "https://www.gutenberg.org/files/27/27-pdf.pdf", # The Arabian Nights + + # Additional arXiv papers + "https://arxiv.org/pdf/2304.00001.pdf", + "https://arxiv.org/pdf/2304.00002.pdf", + "https://arxiv.org/pdf/2304.00003.pdf", + "https://arxiv.org/pdf/2304.00004.pdf", + "https://arxiv.org/pdf/2304.00005.pdf", + "https://arxiv.org/pdf/2304.00006.pdf", + "https://arxiv.org/pdf/2304.00007.pdf", + "https://arxiv.org/pdf/2304.00008.pdf", + "https://arxiv.org/pdf/2304.00009.pdf", + "https://arxiv.org/pdf/2304.00010.pdf", + "https://arxiv.org/pdf/2304.00011.pdf", + "https://arxiv.org/pdf/2304.00012.pdf", + "https://arxiv.org/pdf/2304.00013.pdf", + "https://arxiv.org/pdf/2304.00014.pdf", + "https://arxiv.org/pdf/2304.00015.pdf", + "https://arxiv.org/pdf/2304.00016.pdf", + "https://arxiv.org/pdf/2304.00017.pdf", + "https://arxiv.org/pdf/2304.00018.pdf", + "https://arxiv.org/pdf/2304.00019.pdf", + "https://arxiv.org/pdf/2304.00020.pdf", + + # Statistics and Machine Learning + "https://arxiv.org/pdf/2305.00001.pdf", + "https://arxiv.org/pdf/2305.00002.pdf", + "https://arxiv.org/pdf/2305.00003.pdf", + "https://arxiv.org/pdf/2305.00004.pdf", + "https://arxiv.org/pdf/2305.00005.pdf", + "https://arxiv.org/pdf/2305.00006.pdf", + "https://arxiv.org/pdf/2305.00007.pdf", + "https://arxiv.org/pdf/2305.00008.pdf", + "https://arxiv.org/pdf/2305.00009.pdf", + "https://arxiv.org/pdf/2305.00010.pdf", + + # Quantum Computing + "https://arxiv.org/pdf/2306.00001.pdf", + "https://arxiv.org/pdf/2306.00002.pdf", + "https://arxiv.org/pdf/2306.00003.pdf", + "https://arxiv.org/pdf/2306.00004.pdf", + "https://arxiv.org/pdf/2306.00005.pdf", + "https://arxiv.org/pdf/2306.00006.pdf", + "https://arxiv.org/pdf/2306.00007.pdf", + "https://arxiv.org/pdf/2306.00008.pdf", + "https://arxiv.org/pdf/2306.00009.pdf", + "https://arxiv.org/pdf/2306.00010.pdf", + + # Additional Government Documents + "https://www.gao.gov/assets/730/728146.pdf", + "https://www.gao.gov/assets/730/728147.pdf", + "https://www.gao.gov/assets/730/728148.pdf", + "https://www.gao.gov/assets/730/728149.pdf", + "https://www.gao.gov/assets/730/728150.pdf", + + # Technical Standards + "https://www.iso.org/files/live/sites/isoorg/files/store/en/PUB100424.pdf", + "https://www.iso.org/files/live/sites/isoorg/files/store/en/PUB100425.pdf", + "https://www.iso.org/files/live/sites/isoorg/files/store/en/PUB100426.pdf", + "https://www.iso.org/files/live/sites/isoorg/files/store/en/PUB100427.pdf", + "https://www.iso.org/files/live/sites/isoorg/files/store/en/PUB100428.pdf", + + # Historical Documents + "https://www.archives.gov/files/founding-docs/constitution-transcript.pdf", + "https://www.archives.gov/files/founding-docs/declaration-transcript.pdf", + "https://www.archives.gov/files/founding-docs/bill-of-rights-transcript.pdf", + "https://www.archives.gov/files/founding-docs/federalist-papers-transcript.pdf", + "https://www.archives.gov/files/founding-docs/anti-federalist-papers-transcript.pdf", + + # Educational Materials + "https://ocw.mit.edu/courses/6-006-introduction-to-algorithms-spring-2020/resources/mit6_006s20_lec1/", + "https://ocw.mit.edu/courses/6-006-introduction-to-algorithms-spring-2020/resources/mit6_006s20_lec2/", + "https://ocw.mit.edu/courses/6-006-introduction-to-algorithms-spring-2020/resources/mit6_006s20_lec3/", + "https://ocw.mit.edu/courses/6-006-introduction-to-algorithms-spring-2020/resources/mit6_006s20_lec4/", + "https://ocw.mit.edu/courses/6-006-introduction-to-algorithms-spring-2020/resources/mit6_006s20_lec5/", + + # Final batch to reach 300+ + "https://arxiv.org/pdf/2307.00001.pdf", + "https://arxiv.org/pdf/2307.00002.pdf", + "https://arxiv.org/pdf/2307.00003.pdf", + "https://arxiv.org/pdf/2307.00004.pdf", + "https://arxiv.org/pdf/2307.00005.pdf", + "https://arxiv.org/pdf/2307.00006.pdf", + "https://arxiv.org/pdf/2307.00007.pdf", + "https://arxiv.org/pdf/2307.00008.pdf", + "https://arxiv.org/pdf/2307.00009.pdf", + "https://arxiv.org/pdf/2307.00010.pdf", + "https://arxiv.org/pdf/2307.00011.pdf", + "https://arxiv.org/pdf/2307.00012.pdf", + "https://arxiv.org/pdf/2307.00013.pdf", + "https://arxiv.org/pdf/2307.00014.pdf", + "https://arxiv.org/pdf/2307.00015.pdf", + "https://arxiv.org/pdf/2307.00016.pdf", + "https://arxiv.org/pdf/2307.00017.pdf", + "https://arxiv.org/pdf/2307.00018.pdf", + "https://arxiv.org/pdf/2307.00019.pdf", + "https://arxiv.org/pdf/2307.00020.pdf", + "https://arxiv.org/pdf/2307.00021.pdf", + "https://arxiv.org/pdf/2307.00022.pdf", + "https://arxiv.org/pdf/2307.00023.pdf", + "https://arxiv.org/pdf/2307.00024.pdf", + "https://arxiv.org/pdf/2307.00025.pdf", + "https://arxiv.org/pdf/2307.00026.pdf", + "https://arxiv.org/pdf/2307.00027.pdf", + "https://arxiv.org/pdf/2307.00028.pdf", + "https://arxiv.org/pdf/2307.00029.pdf", + "https://arxiv.org/pdf/2307.00030.pdf", +] + +# Extended list with more categories +EXTENDED_URLS = PDF_URLS + [ + # More arXiv (various subjects) + *[ + f"https://arxiv.org/pdf/{cat}/{num:07}.pdf" + for cat, num in [ + ("math", 123456), + ("physics", 234567), + ("cs", 345678), + ("stat", 456789), + ("q-bio", 567890), + ("q-fin", 678901), + ] + ], + # Project Gutenberg samples + "https://www.gutenberg.org/files/1342/1342-pdf.pdf", + "https://www.gutenberg.org/files/84/84-pdf.pdf", + "https://www.gutenberg.org/files/11/11-pdf.pdf", + # Government economic reports + "https://www.bea.gov/sites/default/files/2023-03/gdp4q22_3rd.pdf", + "https://www.federalreserve.gov/econres/notes/feds-notes/2023/files/20230301.pdf", + # Scientific datasets documentation + "https://www.ncbi.nlm.nih.gov/pmc/articles/PMCPMC1234567/pdf/main.pdf", + # Technical conference proceedings + "https://www.usenix.org/system/files/conference/atc18/atc18-paper-zhang.pdf", + "https://dl.acm.org/doi/pdf/10.1145/3579990.3580020", + # Mathematics journals + "https://www.ams.org/journals/bull/0000-0000/0000-0001.pdf", + "https://link.springer.com/content/pdf/10.1007/s00222-023-01145-0.pdf", + # Physics repositories + "https://iopscience.iop.org/article/10.3847/1538-4357/acb123/pdf", + # Computer science technical reports + "https://www.microsoft.com/en-us/research/uploads/prod/2023/03/paper.pdf", + "https://research.google/pubs/pub12345/", + # Engineering standards + "https://www.iso.org/standard/12345.html/pdf", + "https://www.ansi.org/standards/ansiz123/pdf", + # Medical research + "https://www.nejm.org/doi/pdf/10.1056/NEJMoa2208343", + "https://jamanetwork.com/journals/jama/article-abstract/2801234/pdf", + # Environmental studies + "https://www.ipcc.ch/report/ar6/wg1/downloads/report/IPCC_AR6_WGI_FullReport.pdf", + # Economic research + "https://www.nber.org/papers/w12345.pdf", + "https://www.imf.org/en/Publications/WP/Issues/2023/03/15/paper-12345", + # Historical documents + "https://www.archives.gov/founding-docs/constitution-transcript.pdf", + "https://www.loc.gov/item/2021667891/pdf", + # Educational materials + "https://openstax.org/resources/9d88d84e2e3343f5a7c2e6a9d9b8c7e3.pdf", + # Technical manuals + "https://www.python.org/doc/essays/blt.pdf", + "https://www.r-project.org/conferences/useR-2023/abstracts/abstract_123.pdf", + + + "https://arxiv.org/pdf/1706.03762.pdf", # Attention Is All You Need +"https://arxiv.org/pdf/1502.03167.pdf", # Batch Normalization +"https://arxiv.org/pdf/1409.1556.pdf", # VGG Network +"https://arxiv.org/pdf/1512.03385.pdf", # ResNet +"https://arxiv.org/pdf/1312.6114.pdf", # Auto-Encoding Variational Bayes +"https://arxiv.org/pdf/1712.09913.pdf", # Fitting Linear Mixed-Effects Models Using lme4 +"https://arxiv.org/pdf/1504.08083.pdf", # Faster R-CNN +"https://arxiv.org/pdf/1409.4842.pdf", # Going Deeper with Convolutions +"https://arxiv.org/pdf/1608.06993.pdf", # DenseNet +"https://arxiv.org/pdf/1506.02640.pdf", # YOLO (You Only Look Once) +"https://arxiv.org/pdf/1502.03167.pdf", # Batch Normalization +"https://arxiv.org/pdf/1411.4038.pdf", # Fully Convolutional Networks +"https://arxiv.org/pdf/1512.02325.pdf", # SSD: Single Shot MultiBox Detector +"https://arxiv.org/pdf/2010.11929.pdf", # An Image is Worth 16x16 Words (ViT) +"https://arxiv.org/pdf/1312.5602.pdf", # Deep Reinforcement Learning +"https://arxiv.org/pdf/1505.04597.pdf", # U-Net +"https://arxiv.org/pdf/1603.05027.pdf", # Identity Mappings in Deep Residual Networks +"https://arxiv.org/pdf/1706.03762.pdf", # Attention is All You Need +"https://pmc.ncbi.nlm.nih.gov/articles/PMC1234567/pdf/main.pdf", # Sample biomedical paper +# U.S. House Committee on Oversight Reports[citation:2] +"https://oversight.house.gov/report/the-biden-autopen-presidency-decline-delusion-and-deception-in-the-white-house.pdf", +"https://oversight.house.gov/report/the-green-new-deal-scam-the-greenhouse-gas-reduction-fund.pdf", +"https://oversight.house.gov/report/after-action-review-of-the-covid-19-pandemic-the-lessons-learned-and-a-path-forward.pdf", +"https://oversight.house.gov/report/death-by-a-thousand-regulations-the-biden-harris-administrations-campaign-to-bury-america-in-red-tape.pdf", + +# National Archives OGIS Annual Reports[citation:6] +"https://www.archives.gov/files/ogis/reports/fy2024-annual-report.pdf", +"https://www.archives.gov/files/ogis/reports/fy2023-annual-report.pdf", +"https://www.archives.gov/files/ogis/reports/fy2022-annual-report.pdf", +"https://www.archives.gov/files/ogis/reports/fy2021-annual-report.pdf", +"https://www.archives.gov/files/ogis/reports/fy2020-annual-report.pdf", +"https://www.archives.gov/files/ogis/reports/fy2019-annual-report.pdf", +# Project Gutenberg Top Downloads[citation:3] +"https://www.gutenberg.org/files/84/84-pdf.pdf", # Frankenstein +"https://www.gutenberg.org/files/1342/1342-pdf.pdf", # Pride and Prejudice +"https://www.gutenberg.org/files/11/11-pdf.pdf", # Alice's Adventures in Wonderland +"https://www.gutenberg.org/files/1661/1661-pdf.pdf", # The Adventures of Sherlock Holmes +"https://www.gutenberg.org/files/98/98-pdf.pdf", # A Tale of Two Cities +"https://www.gutenberg.org/files/2701/2701-pdf.pdf", # Moby Dick +"https://www.gutenberg.org/files/2542/2542-pdf.pdf", # A Doll's House +"https://www.gutenberg.org/files/174/174-pdf.pdf", # The Picture of Dorian Gray +"https://www.gutenberg.org/files/1952/1952-pdf.pdf", # The Yellow Wallpaper + +# Open Library & ManyBooks[citation:1][citation:4][citation:7] +# (Note: You may need to find the direct PDF link from the book's page) +"https://openlibrary.org/books/OL1234567M/Book_Title.pdf", +"https://manybooks.net/book/123456/download/pdf" +] + + +class PDFDownloader: + def __init__(self, output_dir: Path, max_concurrent: int = 10): + self.output_dir = output_dir + self.max_concurrent = max_concurrent + self.output_dir.mkdir(parents=True, exist_ok=True) + self.downloaded = 0 + self.failed = 0 + self.skipped = 0 + + async def download_pdf(self, session: aiohttp.ClientSession, url: str) -> Optional[Path]: + try: + filename = self._url_to_filename(url) + filepath = self.output_dir / filename + if filepath.exists(): + self.skipped += 1 + print(f"✓ Already exists: {filename}") + return filepath + + async with session.get(url, timeout=aiohttp.ClientTimeout(total=60)) as response: + if response.status != 200: + print(f"✗ HTTP {response.status}: {url}") + self.failed += 1 + return None + + content = await response.read() + if not content.startswith(b"%PDF"): + print(f"✗ Not a PDF: {url}") + self.failed += 1 + return None + + async with aiofiles.open(filepath, "wb") as handle: + await handle.write(content) + self.downloaded += 1 + print(f"✓ Downloaded: {filename} ({len(content)} bytes)") + return filepath + + except Exception as exc: # pylint: disable=broad-except + print(f"✗ Error downloading {url}: {exc}") + self.failed += 1 + return None + + def _url_to_filename(self, url: str) -> str: + parsed = urlparse(url) + path = parsed.path.strip("/") or "document" + filename = re.sub(r"[^a-zA-Z0-9.-]", "_", path) + if not filename.endswith(".pdf"): + filename += ".pdf" + domain = parsed.netloc.replace("www.", "").split(".")[0] or "site" + # Hash query params for uniqueness + digest = hashlib.sha1(url.encode("utf-8")).hexdigest()[:8] + return f"{domain}_{filename}_{digest}" + + async def download_all(self, urls: List[str]) -> None: + print(f"Starting download of {len(urls)} PDFs to {self.output_dir}") + connector = aiohttp.TCPConnector(limit=self.max_concurrent) + async with aiohttp.ClientSession(connector=connector) as session: + for i in range(0, len(urls), self.max_concurrent): + batch = urls[i : i + self.max_concurrent] + await asyncio.gather(*(self.download_pdf(session, url) for url in batch)) + if i + self.max_concurrent < len(urls): + await asyncio.sleep(1) + self._print_summary() + + def _print_summary(self) -> None: + print("\n" + "=" * 40) + print("DOWNLOAD SUMMARY") + print("=" * 40) + print(f"✓ Downloaded: {self.downloaded}") + print(f"○ Skipped: {self.skipped}") + print(f"✗ Failed: {self.failed}") + total = len(list(self.output_dir.glob("*.pdf"))) + print(f"Total files in directory: {total}") + print(f"Location: {self.output_dir.resolve()}") + + +def main() -> None: + parser = argparse.ArgumentParser( + description="Download massive PDF collection for Type3 font harvesting" + ) + parser.add_argument("--output", "-o", default="./pdf-collection", help="Output directory") + parser.add_argument( + "--max-concurrent", "-c", type=int, default=5, help="Maximum concurrent downloads" + ) + parser.add_argument("--shuffle", action="store_true", help="Shuffle URL order before download") + args = parser.parse_args() + + urls = EXTENDED_URLS.copy() + if args.shuffle: + random.shuffle(urls) + + downloader = PDFDownloader(Path(args.output), args.max_concurrent) + asyncio.run(downloader.download_all(urls)) + + print(f"\nNext step: python scripts/harvest_type3_fonts.py --input {args.output}") + + +if __name__ == "__main__": + main() diff --git a/scripts/download_pdf_samples.py b/scripts/download_pdf_samples.py new file mode 100644 index 000000000..6a882c56f --- /dev/null +++ b/scripts/download_pdf_samples.py @@ -0,0 +1,195 @@ +#!/usr/bin/env python3 +""" +Download large batches of PDF URLs into a local directory so they can be fed to +scripts/harvest_type3_fonts.py (or any other processing pipeline). + +Usage examples: + + # Download every URL listed in pdf_urls.txt into tmp/type3-pdfs + python scripts/download_pdf_samples.py \ + --urls-file pdf_urls.txt \ + --output-dir tmp/type3-pdfs + + # Mix inline URLs with a file and use 16 concurrent downloads + python scripts/download_pdf_samples.py \ + --urls https://example.com/a.pdf https://example.com/b.pdf \ + --urls-file more_urls.txt \ + --output-dir tmp/type3-pdfs \ + --workers 16 +""" + +from __future__ import annotations + +import argparse +import concurrent.futures +import hashlib +import os +import re +import sys +from pathlib import Path +from typing import Iterable, List, Optional, Set, Tuple +from urllib.parse import unquote, urlparse + +import requests + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(description="Bulk download PDF URLs.") + parser.add_argument( + "--urls", + nargs="*", + default=[], + help="Inline list of PDF URLs (can be combined with --urls-file).", + ) + parser.add_argument( + "--urls-file", + action="append", + help="Text file containing one URL per line (can be repeated).", + ) + parser.add_argument( + "--output-dir", + default="tmp/harvest-pdfs", + help="Directory to store downloaded PDFs (default: %(default)s).", + ) + parser.add_argument( + "--workers", + type=int, + default=min(8, (os.cpu_count() or 4) * 2), + help="Number of concurrent downloads (default: %(default)s).", + ) + parser.add_argument( + "--timeout", + type=int, + default=120, + help="Per-request timeout in seconds (default: %(default)s).", + ) + parser.add_argument( + "--overwrite", + action="store_true", + help="Overwrite existing files (default: skip already downloaded PDFs).", + ) + return parser.parse_args() + + +def load_urls(args: argparse.Namespace) -> List[str]: + urls: List[str] = [] + seen: Set[str] = set() + + def add(url: str) -> None: + clean = url.strip() + if not clean or clean.startswith("#"): + return + if clean not in seen: + seen.add(clean) + urls.append(clean) + + for url in args.urls: + add(url) + if args.urls_file: + for file in args.urls_file: + path = Path(file) + if not path.exists(): + print(f"[WARN] URL file not found: {file}", file=sys.stderr) + continue + with path.open("r", encoding="utf-8") as handle: + for line in handle: + add(line) + if not urls: + raise SystemExit("No URLs supplied. Use --urls and/or --urls-file.") + return urls + + +def sanitize_filename(name: str) -> str: + return re.sub(r"[^A-Za-z0-9._-]+", "_", name).strip("_") or "download" + + +def build_filename(url: str, output_dir: Path) -> Path: + parsed = urlparse(url) + candidate = Path(unquote(parsed.path)).name + if not candidate: + candidate = "download.pdf" + candidate = sanitize_filename(candidate) + if not candidate.lower().endswith(".pdf"): + candidate += ".pdf" + target = output_dir / candidate + if not target.exists(): + return target + stem = target.stem + suffix = target.suffix + digest = hashlib.sha1(url.encode("utf-8")).hexdigest()[:8] + return output_dir / f"{stem}-{digest}{suffix}" + + +def download_pdf( + url: str, + output_dir: Path, + timeout: int, + overwrite: bool, +) -> Tuple[str, Optional[Path], Optional[str]]: + try: + dest = build_filename(url, output_dir) + if dest.exists() and not overwrite: + return url, dest, "exists" + + response = requests.get(url, stream=True, timeout=timeout) + response.raise_for_status() + + content_type = response.headers.get("Content-Type", "").lower() + if "pdf" not in content_type and not url.lower().endswith(".pdf"): + # Peek into the first bytes to be safe + peek = response.raw.read(5, decode_content=True) + if not peek.startswith(b"%PDF"): + return url, None, f"Skipping non-PDF content-type ({content_type or 'unknown'})" + content = peek + response.content[len(peek):] + else: + content = response.content + + output_dir.mkdir(parents=True, exist_ok=True) + dest.write_bytes(content) + return url, dest, None + except Exception as exc: # pylint: disable=broad-except + return url, None, str(exc) + + +def main() -> None: + args = parse_args() + urls = load_urls(args) + output_dir = Path(args.output_dir).resolve() + output_dir.mkdir(parents=True, exist_ok=True) + + print(f"Downloading {len(urls)} PDFs to {output_dir} using {args.workers} workers...") + + successes = 0 + skipped = 0 + failures: List[Tuple[str, str]] = [] + + with concurrent.futures.ThreadPoolExecutor(max_workers=args.workers) as executor: + future_to_url = { + executor.submit( + download_pdf, url, output_dir, args.timeout, args.overwrite + ): url + for url in urls + } + for future in concurrent.futures.as_completed(future_to_url): + url = future_to_url[future] + result_url, path, error = future.result() + if error == "exists": + skipped += 1 + print(f"[SKIP] {url} (already downloaded)") + elif error: + failures.append((result_url, error)) + print(f"[FAIL] {url} -> {error}", file=sys.stderr) + else: + successes += 1 + print(f"[OK] {url} -> {path}") + + print() + print(f"Completed. Success: {successes}, Skipped: {skipped}, Failures: {len(failures)}") + if failures: + print("Failures:") + for url, error in failures: + print(f" {url} -> {error}") + + +if __name__ == "__main__": + main() diff --git a/scripts/harvest_type3_fonts.py b/scripts/harvest_type3_fonts.py new file mode 100644 index 000000000..5edb1b2a9 --- /dev/null +++ b/scripts/harvest_type3_fonts.py @@ -0,0 +1,245 @@ +#!/usr/bin/env python3 +""" +Bulk-harvest Type3 font signatures from a folder full of PDFs. + +The script iterates over every PDF (recursively) inside the supplied --input +paths, invokes the existing Gradle Type3SignatureTool for each document, and +collects the unique Type3 font signatures that were discovered. Signature JSON +files are stored under --signatures-dir; previously captured files are reused +so you can keep dropping new PDFs into the input directory and re-run the +harvester at any time. + +Example: + python scripts/harvest_type3_fonts.py \ + --input incoming-type3-pdfs \ + --signatures docs/type3/signatures \ + --report docs/type3/harvest_report.json +""" + +from __future__ import annotations + +import argparse +import datetime as dt +import hashlib +import json +import os +import re +import shlex +import subprocess +import sys +from pathlib import Path +from typing import Dict, Iterable, List, Optional, Sequence, Tuple + +REPO_ROOT = Path(__file__).resolve().parents[1] + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(description="Bulk collect Type3 font signatures from PDFs.") + parser.add_argument( + "--input", + nargs="+", + required=True, + help="One or more PDF files or directories containing PDFs (searched recursively).", + ) + parser.add_argument( + "--signatures-dir", + default="docs/type3/signatures", + help="Destination directory for per-PDF signature JSON files.", + ) + parser.add_argument( + "--report", + default="docs/type3/harvest_report.json", + help="Summary JSON that lists every unique signature discovered so far.", + ) + default_gradle = "gradlew.bat" if os.name == "nt" else "./gradlew" + parser.add_argument( + "--gradle-cmd", + default=default_gradle, + help=f"Path to the Gradle wrapper used to invoke the Type3SignatureTool (default: {default_gradle}).", + ) + parser.add_argument( + "--force", + action="store_true", + help="Re-run the signature tool even if the output JSON already exists.", + ) + parser.add_argument( + "--pretty", + action="store_true", + help="Ask the Java tool to emit pretty-printed JSON (handy for diffs).", + ) + return parser.parse_args() + + +def discover_pdfs(paths: Sequence[str]) -> List[Path]: + pdfs: List[Path] = [] + for raw in paths: + path = Path(raw).resolve() + if path.is_file(): + if path.suffix.lower() == ".pdf": + pdfs.append(path) + elif path.is_dir(): + pdfs.extend(sorted(path.rglob("*.pdf"))) + unique = sorted(dict.fromkeys(pdfs)) + if not unique: + raise SystemExit("No PDF files found under the supplied --input paths.") + return unique + + +def sanitize_part(part: str) -> str: + cleaned = re.sub(r"[^A-Za-z0-9._-]+", "_", part) + return cleaned or "_" + + +def derive_signature_path(pdf: Path, signatures_dir: Path) -> Path: + """ + Mirror the PDF path under the signatures directory. + If the PDF lives outside the repo, fall back to a hashed filename. + """ + try: + rel = pdf.relative_to(REPO_ROOT) + except ValueError: + digest = hashlib.sha1(str(pdf).encode("utf-8")).hexdigest()[:10] + rel = Path("__external__") / f"{sanitize_part(pdf.stem)}-{digest}.pdf" + + sanitized_parts = [sanitize_part(part) for part in rel.parts] + signature_rel = Path(*sanitized_parts).with_suffix(".json") + return signatures_dir / signature_rel + + +def load_signature_file(path: Path) -> dict: + with path.open("r", encoding="utf-8") as handle: + return json.load(handle) + + +def collect_known_signatures(signatures_dir: Path) -> Dict[str, dict]: + known: Dict[str, dict] = {} + if not signatures_dir.exists(): + return known + for json_file in signatures_dir.rglob("*.json"): + try: + payload = load_signature_file(json_file) + except Exception: + continue + pdf = payload.get("pdf") + for font in payload.get("fonts", []): + signature = font.get("signature") + if not signature or signature in known: + continue + known[signature] = { + "signature": signature, + "alias": font.get("alias"), + "baseName": font.get("baseName"), + "glyphCount": font.get("glyphCount"), + "glyphCoverage": font.get("glyphCoverage"), + "samplePdf": pdf, + "signatureJson": str(json_file), + } + return known + + +def run_signature_tool( + gradle_cmd: str, pdf: Path, output_path: Path, pretty: bool, cwd: Path +) -> None: + output_path.parent.mkdir(parents=True, exist_ok=True) + args = f"--pdf {shlex.quote(str(pdf))} --output {shlex.quote(str(output_path))}" + if pretty: + args += " --pretty" + # Use shell invocation so the quoted --args string is parsed correctly by Gradle. + cmd = f"{gradle_cmd} -q :proprietary:type3SignatureTool --args=\"{args}\"" + completed = subprocess.run( + cmd, + shell=True, + cwd=cwd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + ) + if completed.returncode != 0: + raise RuntimeError( + f"Gradle Type3SignatureTool failed for {pdf}:\n{completed.stderr.strip()}" + ) + + +def extract_fonts_from_payload(payload: dict) -> List[dict]: + pdf = payload.get("pdf") + fonts = [] + for font in payload.get("fonts", []): + signature = font.get("signature") + if not signature: + continue + fonts.append( + { + "signature": signature, + "alias": font.get("alias"), + "baseName": font.get("baseName"), + "glyphCount": font.get("glyphCount"), + "glyphCoverage": font.get("glyphCoverage"), + "samplePdf": pdf, + } + ) + return fonts + + +def write_report(report_path: Path, fonts_by_signature: Dict[str, dict]) -> None: + ordered = sorted(fonts_by_signature.values(), key=lambda entry: entry["signature"]) + report = { + "generatedAt": dt.datetime.utcnow().isoformat(timespec="seconds") + "Z", + "totalSignatures": len(ordered), + "fonts": ordered, + } + report_path.parent.mkdir(parents=True, exist_ok=True) + with report_path.open("w", encoding="utf-8") as handle: + json.dump(report, handle, indent=2) + + +def main() -> None: + args = parse_args() + signatures_dir = Path(args.signatures_dir).resolve() + report_path = Path(args.report).resolve() + pdfs = discover_pdfs(args.input) + + known = collect_known_signatures(signatures_dir) + newly_added: List[Tuple[str, str]] = [] + + for pdf in pdfs: + signature_path = derive_signature_path(pdf, signatures_dir) + if signature_path.exists() and not args.force: + try: + payload = load_signature_file(signature_path) + except Exception as exc: + print(f"[WARN] Failed to parse cached signature {signature_path}: {exc}") + payload = None + else: + try: + run_signature_tool(args.gradle_cmd, pdf, signature_path, args.pretty, REPO_ROOT) + except Exception as exc: + print(f"[ERROR] Harvest failed for {pdf}: {exc}", file=sys.stderr) + continue + payload = load_signature_file(signature_path) + + if not payload: + continue + + for font in extract_fonts_from_payload(payload): + signature = font["signature"] + if signature in known: + continue + font["signatureJson"] = str(signature_path) + known[signature] = font + newly_added.append((signature, pdf.name)) + + write_report(report_path, known) + + print( + f"Processed {len(pdfs)} PDFs. " + f"Captured {len(newly_added)} new Type3 font signatures " + f"(total unique signatures: {len(known)})." + ) + if newly_added: + print("New signatures:") + for signature, sample in newly_added: + print(f" {signature} ({sample})") + + +if __name__ == "__main__": + main() diff --git a/scripts/index_type3_catalogue.py b/scripts/index_type3_catalogue.py new file mode 100644 index 000000000..49dce500e --- /dev/null +++ b/scripts/index_type3_catalogue.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 +"""Build a Type3 font catalogue from sample PDFs.""" +import argparse +import json +import subprocess +from pathlib import Path + + +def run(cmd, cwd=None): + result = subprocess.run(cmd, cwd=cwd, capture_output=True, text=True) + if result.returncode != 0: + raise RuntimeError(f"Command {' '.join(cmd)} failed: {result.stderr}") + return result.stdout + + +def parse_pdffonts(output): + lines = output.splitlines() + entries = [] + for line in lines[2:]: + if not line.strip(): + continue + parts = line.split() + if "Type" not in parts: + continue + idx = parts.index("Type") + type_value = parts[idx + 1] if idx + 1 < len(parts) else "" + if not type_value.startswith("3"): + continue + font_name = parts[0] + encoding = parts[-2] if len(parts) >= 2 else "" + entries.append((font_name, encoding)) + return entries + + +def main(): + parser = argparse.ArgumentParser(description="Index Type3 fonts from sample PDFs") + parser.add_argument( + "--samples", + default="app/core/src/main/resources/type3/samples", + help="Directory containing sample PDFs", + ) + parser.add_argument( + "--output", + default="app/core/src/main/resources/type3/catalogue.json", + help="Output JSON file", + ) + args = parser.parse_args() + + samples_dir = Path(args.samples) + out_path = Path(args.output) + out_path.parent.mkdir(parents=True, exist_ok=True) + + catalogue = [] + for pdf in sorted(samples_dir.glob("*.pdf")): + try: + output = run(["pdffonts", str(pdf)]) + except Exception as exc: + print(f"Skipping {pdf.name}: {exc}") + continue + for font_name, encoding in parse_pdffonts(output): + catalogue.append( + { + "source": pdf.name, + "fontName": font_name, + "encoding": encoding, + } + ) + + with out_path.open("w", encoding="utf-8") as handle: + json.dump(catalogue, handle, indent=2) + print(f"Wrote {len(catalogue)} entries to {out_path}") + + +if __name__ == "__main__": + main() diff --git a/scripts/summarize_type3_signatures.py b/scripts/summarize_type3_signatures.py new file mode 100644 index 000000000..ae8706935 --- /dev/null +++ b/scripts/summarize_type3_signatures.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python3 +""" +Summarize captured Type3 signature dumps as a Markdown inventory. + +Usage: + scripts/summarize_type3_signatures.py \ + --input docs/type3/signatures \ + --output docs/type3/signature_inventory.md +""" + +from __future__ import annotations + +import argparse +import json +from collections import defaultdict +from pathlib import Path +from typing import Dict, List + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(description="Summarize Type3 signature JSON dumps.") + parser.add_argument( + "--input", + default="docs/type3/signatures", + help="Directory containing signature JSON files (default: %(default)s)", + ) + parser.add_argument( + "--output", + default="docs/type3/signature_inventory.md", + help="Markdown file to write (default: %(default)s)", + ) + return parser.parse_args() + + +def load_signatures(directory: Path) -> Dict[str, List[dict]]: + inventory: Dict[str, List[dict]] = defaultdict(list) + for path in sorted(directory.glob("*.json")): + with path.open("r", encoding="utf-8") as handle: + payload = json.load(handle) + source_pdf = payload.get("pdf") or path.name + for font in payload.get("fonts", []): + alias = (font.get("alias") or font.get("baseName") or "unknown").lower() + entry = { + "source": source_pdf, + "file": path.name, + "alias": alias, + "baseName": font.get("baseName"), + "signature": font.get("signature"), + "glyphCount": font.get("glyphCount"), + "glyphCoverage": font.get("glyphCoverage"), + } + inventory[alias].append(entry) + return inventory + + +def write_markdown(inventory: Dict[str, List[dict]], output: Path, input_dir: Path) -> None: + lines: List[str] = [] + lines.append("# Type3 Signature Inventory") + lines.append("") + lines.append( + f"_Generated from `{input_dir}`. " + "Run `scripts/summarize_type3_signatures.py` after capturing new samples._" + ) + lines.append("") + + for alias in sorted(inventory.keys()): + entries = inventory[alias] + lines.append(f"## Alias: `{alias}`") + lines.append("") + lines.append("| Signature | Samples | Glyph Count | Coverage (first 10) |") + lines.append("| --- | --- | --- | --- |") + for entry in entries: + signature = entry.get("signature") or "—" + sample = Path(entry["source"]).name + glyph_count = entry.get("glyphCount") if entry.get("glyphCount") is not None else "—" + coverage = entry.get("glyphCoverage") or [] + preview = ", ".join(str(code) for code in coverage[:10]) + lines.append(f"| `{signature}` | `{sample}` | {glyph_count} | {preview} |") + lines.append("") + + output.parent.mkdir(parents=True, exist_ok=True) + output.write_text("\n".join(lines), encoding="utf-8") + + +def main() -> None: + args = parse_args() + input_dir = Path(args.input) + if not input_dir.exists(): + raise SystemExit(f"Input directory not found: {input_dir}") + inventory = load_signatures(input_dir) + output_path = Path(args.output) + write_markdown(inventory, output_path, input_dir) + print(f"Wrote inventory for {len(inventory)} aliases to {output_path}") + + +if __name__ == "__main__": + main() diff --git a/scripts/type3_to_cff.py b/scripts/type3_to_cff.py new file mode 100644 index 000000000..0aaf13218 --- /dev/null +++ b/scripts/type3_to_cff.py @@ -0,0 +1,481 @@ +#!/usr/bin/env python3 +""" +Convert Stirling PDF Type3 glyph JSON into synthesised fonts using fontTools. + +The input JSON is expected to contain: + - fontId, pageNumber (optional metadata) + - fontMatrix: 3x3 matrix describing the Type3 glyph transform + - glyphs: array of glyph records with keys: + name, code, advanceWidth, bbox, unicode, outline (list of commands) + +The script produces an OpenType CFF font and, when requested, a companion +TrueType font for web-preview usage. Only the fontTools package is required, +avoiding heavyweight build dependencies such as fontmake/ufoLib2. +""" + +from __future__ import annotations + +import argparse +import json +import math +import sys +from dataclasses import dataclass +from pathlib import Path +from typing import Dict, Iterable, List, Optional, Sequence, Tuple + +from fontTools.fontBuilder import FontBuilder +from fontTools.misc.fixedTools import otRound +from fontTools.pens.cu2quPen import Cu2QuPen +from fontTools.pens.t2CharStringPen import T2CharStringPen +from fontTools.pens.ttGlyphPen import TTGlyphPen + + +Command = Dict[str, object] +Matrix = Tuple[float, float, float, float, float, float] + + +@dataclass +class GlyphSource: + name: str + width: float + unicode: Optional[int] + char_code: Optional[int] + outline: Sequence[Command] + + +@dataclass +class GlyphBuildResult: + name: str + width: int + charstring: object + ttf_glyph: Optional[object] + unicode: Optional[int] + char_code: Optional[int] + bounds: Optional[Tuple[float, float, float, float]] + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(description="Synthesize fonts from Type3 glyph JSON.") + parser.add_argument("--input", required=True, help="Path to glyph JSON emitted by the backend") + parser.add_argument("--otf-output", required=True, help="Destination path for the CFF/OTF font") + parser.add_argument("--ttf-output", help="Optional destination path for a TrueType font") + parser.add_argument("--family-name", default="Type3 Synth", help="Family name for the output") + parser.add_argument("--style-name", default="Regular", help="Style name for the output") + parser.add_argument("--units-per-em", type=int, default=1000, help="Units per EM value") + parser.add_argument("--cu2qu-error", type=float, default=1.0, help="Max error for cubic→quadratic conversion") + return parser.parse_args() + + +def load_json(path: Path) -> Dict[str, object]: + try: + with path.open("r", encoding="utf-8") as handle: + return json.load(handle) + except Exception as exc: # pragma: no cover - fatal configuration error + print(f"ERROR: Failed to load glyph JSON '{path}': {exc}", file=sys.stderr) + sys.exit(2) + + +def parse_font_matrix(rows: Optional[Iterable[Iterable[float]]]) -> Matrix: + """ + Retrieve the raw 2×3 FontMatrix entries for diagnostics. Type3 glyph + outlines in our extractor are emitted in their native coordinate system, so + the returned matrix is currently informational only. + """ + if not rows: + return (1.0, 0.0, 0.0, 1.0, 0.0, 0.0) + values: List[List[float]] = [] + for row in rows: + try: + values.append([float(col) for col in row]) + except (TypeError, ValueError): + return (1.0, 0.0, 0.0, 1.0, 0.0, 0.0) + if len(values) < 3 or len(values[0]) < 2 or len(values[1]) < 2: + return (1.0, 0.0, 0.0, 1.0, 0.0, 0.0) + return ( + float(values[0][0]), + float(values[0][1]), + float(values[1][0]), + float(values[1][1]), + float(values[2][0]), + float(values[2][1]), + ) + + +def resolve_width(raw_width: float, default: int) -> int: + try: + value = float(raw_width) + except (TypeError, ValueError): + return default + if not math.isfinite(value) or value <= 0: + return default + width = otRound(value) + return width if width > 0 else default + + +def quadratic_to_cubic( + current: Tuple[float, float], + ctrl: Tuple[float, float], + end: Tuple[float, float], +) -> Tuple[Tuple[float, float], Tuple[float, float], Tuple[float, float]]: + """ + Convert a quadratic Bézier segment to cubic control points. + """ + c1 = ( + current[0] + (2.0 / 3.0) * (ctrl[0] - current[0]), + current[1] + (2.0 / 3.0) * (ctrl[1] - current[1]), + ) + c2 = ( + end[0] + (2.0 / 3.0) * (ctrl[0] - end[0]), + end[1] + (2.0 / 3.0) * (ctrl[1] - end[1]), + ) + return c1, c2, end + + +def iterate_glyphs(data: Dict[str, object]) -> List[GlyphSource]: + glyph_records = data.get("glyphs") or [] + sources: List[GlyphSource] = [] + for index, record in enumerate(glyph_records, start=1): + if not isinstance(record, dict): + continue + name = record.get("name") + if not isinstance(name, str) or not name: + name = f"g{index}" + width = record.get("advanceWidth") + if not isinstance(width, (int, float)) or math.isnan(width): + width = 1000.0 + unicode_value = record.get("unicode") + if not isinstance(unicode_value, int) or unicode_value <= 0: + unicode_value = None + char_code_value = record.get("charCode") + if not isinstance(char_code_value, int): + char_code_value = record.get("code") + if not isinstance(char_code_value, int): + char_code_value = record.get("charCodeRaw") + if not isinstance(char_code_value, int) or not (0 <= char_code_value <= 0x10FFFF): + char_code_value = None + outline = record.get("outline") + if not isinstance(outline, list): + outline = [] + sources.append( + GlyphSource( + name=name, + width=float(width), + unicode=unicode_value, + char_code=char_code_value, + outline=outline)) + return sources + + +def build_cff_charstring( + glyph: GlyphSource, + width: int, +) -> Tuple[object, Optional[Tuple[float, float, float, float]]]: + pen = T2CharStringPen(width=width, glyphSet=None) + bounds = [math.inf, math.inf, -math.inf, -math.inf] + + def update_bounds(point: Tuple[float, float]) -> None: + x, y = point + bounds[0] = min(bounds[0], x) + bounds[1] = min(bounds[1], y) + bounds[2] = max(bounds[2], x) + bounds[3] = max(bounds[3], y) + + current: Optional[Tuple[float, float]] = None + start_point: Optional[Tuple[float, float]] = None + open_path = False + + for command in glyph.outline: + if not isinstance(command, dict): + continue + op = command.get("cmd") + if op == "M": + if open_path: + pen.endPath() + open_path = False + point = (float(command.get("x", 0.0)), float(command.get("y", 0.0))) + pen.moveTo(point) + update_bounds(point) + current = point + start_point = point + open_path = True + elif op == "L" and current is not None: + point = (float(command.get("x", current[0])), float(command.get("y", current[1]))) + pen.lineTo(point) + update_bounds(point) + current = point + elif op == "C" and current is not None: + ctrl1 = ( + float(command.get("x1", current[0])), + float(command.get("y1", current[1])), + ) + ctrl2 = ( + float(command.get("x2", current[0])), + float(command.get("y2", current[1])), + ) + end = ( + float(command.get("x", current[0])), + float(command.get("y", current[1])), + ) + pen.curveTo(ctrl1, ctrl2, end) + update_bounds(ctrl1) + update_bounds(ctrl2) + update_bounds(end) + current = end + elif op == "Q" and current is not None: + ctrl = ( + float(command.get("x1", current[0])), + float(command.get("y1", current[1])), + ) + end = ( + float(command.get("x", current[0])), + float(command.get("y", current[1])), + ) + c1, c2, end_point = quadratic_to_cubic(current, ctrl, end) + pen.curveTo(c1, c2, end_point) + update_bounds(ctrl) + update_bounds(end_point) + current = end_point + elif op == "Z" and open_path: + pen.closePath() + open_path = False + if start_point is not None: + current = start_point + # Ignore unsupported commands silently. + + if open_path: + pen.endPath() + + charstring = pen.getCharString() + bbox = None + if bounds[0] <= bounds[2] and bounds[1] <= bounds[3]: + bbox = (bounds[0], bounds[1], bounds[2], bounds[3]) + return charstring, bbox + + +def build_ttf_glyph(glyph: GlyphSource, max_error: float) -> Optional[object]: + pen = TTGlyphPen(glyphSet=None) + draw_pen = Cu2QuPen(pen, max_error, reverse_direction=False) + + current_exists = False + + for command in glyph.outline: + if not isinstance(command, dict): + continue + op = command.get("cmd") + if op == "M": + x = float(command.get("x", 0.0)) + y = float(command.get("y", 0.0)) + draw_pen.moveTo((x, y)) + current_exists = True + elif op == "L" and current_exists: + x = float(command.get("x", 0.0)) + y = float(command.get("y", 0.0)) + draw_pen.lineTo((x, y)) + elif op == "C" and current_exists: + ctrl1 = (float(command.get("x1", 0.0)), float(command.get("y1", 0.0))) + ctrl2 = (float(command.get("x2", 0.0)), float(command.get("y2", 0.0))) + end = (float(command.get("x", 0.0)), float(command.get("y", 0.0))) + draw_pen.curveTo(ctrl1, ctrl2, end) + elif op == "Q" and current_exists: + ctrl = (float(command.get("x1", 0.0)), float(command.get("y1", 0.0))) + end = (float(command.get("x", 0.0)), float(command.get("y", 0.0))) + draw_pen.qCurveTo(ctrl, end) + elif op == "Z" and current_exists: + draw_pen.closePath() + current_exists = False + + if current_exists: + draw_pen.endPath() + + try: + glyph_obj = pen.glyph() + except Exception: + return None + return glyph_obj + + +def synthesise_fonts( + data: Dict[str, object], + otf_output: Path, + ttf_output: Optional[Path], + family_name: str, + style_name: str, + units_per_em: int, + cu2qu_error: float, +) -> None: + _font_matrix = parse_font_matrix(data.get("fontMatrix")) + glyphs = iterate_glyphs(data) + + results: List[GlyphBuildResult] = [] + global_y_min = math.inf + global_y_max = -math.inf + + default_width = max(1, units_per_em // 2) + + for glyph in glyphs: + width = resolve_width(glyph.width, default_width) + charstring, bounds = build_cff_charstring(glyph, width) + ttf_glyph = None + if ttf_output is not None: + ttf_glyph = build_ttf_glyph(glyph, cu2qu_error) + if ttf_glyph is not None: + ttf_glyph.width = width + if bounds is not None: + global_y_min = min(global_y_min, bounds[1]) + global_y_max = max(global_y_max, bounds[3]) + results.append( + GlyphBuildResult( + name=glyph.name, + width=width, + charstring=charstring, + ttf_glyph=ttf_glyph, + unicode=glyph.unicode, + char_code=glyph.char_code, + bounds=bounds, + ) + ) + + if not results: + raise RuntimeError("No glyphs provided in input JSON") + + ascent = global_y_max if math.isfinite(global_y_max) else units_per_em * 0.8 + descent = global_y_min if math.isfinite(global_y_min) else -units_per_em * 0.2 + ascent = otRound(ascent) + descent = otRound(descent) + if ascent <= 0: + ascent = otRound(units_per_em * 0.8) + if descent >= 0: + descent = -otRound(units_per_em * 0.2) + + glyph_order = [".notdef"] + [result.name for result in results] + horizontal_metrics = {result.name: (result.width, 0) for result in results} + horizontal_metrics[".notdef"] = (default_width, 0) + + cmap: Dict[int, str] = {} + next_private = 0xF000 + for result in results: + code_point = result.unicode + if code_point is None: + raw_code = result.char_code + if raw_code is not None: + code_point = raw_code + else: + code_point = next_private + next_private += 1 + cmap[code_point] = result.name + + notdef_pen = T2CharStringPen(width=default_width, glyphSet=None) + notdef_pen.endPath() + charstrings = {result.name: result.charstring for result in results} + charstrings[".notdef"] = notdef_pen.getCharString() + + name_table_entries = { + "familyName": family_name, + "styleName": style_name, + "psName": f"{family_name.replace(' ', '')}-{style_name}", + "fullName": f"{family_name} {style_name}", + } + + # Build OTF (CFF) font. + fb = FontBuilder(units_per_em, isTTF=False) + fb.setupGlyphOrder(glyph_order) + fb.setupCharacterMap(cmap) + fb.setupHorizontalMetrics(horizontal_metrics) + fb.setupHorizontalHeader(ascent=ascent, descent=descent) + fb.setupOS2( + sTypoAscender=ascent, + sTypoDescender=descent, + usWinAscent=max(ascent, 0), + usWinDescent=abs(min(descent, 0)), + sxHeight=otRound(units_per_em * 0.5), + sCapHeight=otRound(units_per_em * 0.7), + ) + fb.setupNameTable(name_table_entries) + fb.setupPost() + fb.setupCFF( + name_table_entries["psName"], + { + "FullName": name_table_entries["fullName"], + "FamilyName": name_table_entries["familyName"], + "Weight": style_name, + }, + charstrings, + {"BlueValues": []}, + ) + fb.font.save(str(otf_output)) + + if ttf_output is None: + return + + glyph_objects: Dict[str, object] = {} + empty_pen = TTGlyphPen(None) + empty_pen.moveTo((0, 0)) + empty_pen.lineTo((0, 0)) + empty_pen.closePath() + empty_glyph = empty_pen.glyph() + empty_glyph.width = default_width + glyph_objects[".notdef"] = empty_glyph + for result in results: + glyph_obj = result.ttf_glyph + if glyph_obj is None: + temp_pen = TTGlyphPen(None) + temp_pen.moveTo((0, 0)) + temp_pen.lineTo((0, 0)) + temp_pen.closePath() + glyph_obj = temp_pen.glyph() + glyph_obj.width = result.width + glyph_objects[result.name] = glyph_obj + + ttf_fb = FontBuilder(units_per_em, isTTF=True) + ttf_fb.setupGlyphOrder(glyph_order) + ttf_fb.setupCharacterMap(cmap) + ttf_fb.setupHorizontalMetrics(horizontal_metrics) + ttf_fb.setupHorizontalHeader(ascent=ascent, descent=descent) + ttf_fb.setupOS2( + sTypoAscender=ascent, + sTypoDescender=descent, + usWinAscent=max(ascent, 0), + usWinDescent=abs(min(descent, 0)), + sxHeight=otRound(units_per_em * 0.5), + sCapHeight=otRound(units_per_em * 0.7), + ) + ttf_fb.setupNameTable(name_table_entries) + ttf_fb.setupPost() + ttf_fb.setupGlyf(glyph_objects) + ttf_fb.setupDummyDSIG() + ttf_fb.font.save(str(ttf_output)) + + +def main() -> None: + args = parse_args() + input_path = Path(args.input).resolve() + otf_output = Path(args.otf_output).resolve() + ttf_output = Path(args.ttf_output).resolve() if args.ttf_output else None + + data = load_json(input_path) + try: + synthesise_fonts( + data=data, + otf_output=otf_output, + ttf_output=ttf_output, + family_name=args.family_name, + style_name=args.style_name, + units_per_em=args.units_per_em, + cu2qu_error=args.cu2qu_error, + ) + except Exception as exc: + print(f"ERROR: Failed to generate fonts: {exc}", file=sys.stderr) + if otf_output.exists(): + otf_output.unlink() + if ttf_output and ttf_output.exists(): + ttf_output.unlink() + sys.exit(1) + + message = f"Generated font at {otf_output}" + if ttf_output: + message += f" and {ttf_output}" + print(message, file=sys.stderr) + + +if __name__ == "__main__": + main() diff --git a/scripts/update_type3_library.py b/scripts/update_type3_library.py new file mode 100644 index 000000000..fe4068e0f --- /dev/null +++ b/scripts/update_type3_library.py @@ -0,0 +1,243 @@ +#!/usr/bin/env python3 +""" +Synchronize Type3 library index entries with captured signature dumps. + +The script scans docs/type3/signatures/*.json (or a custom --signatures-dir), +matches each font by alias/signature to app/core/src/main/resources/type3/library/index.json, +and updates the entry's signatures / glyphCoverage / aliases / source fields. + +Usage: + scripts/update_type3_library.py --apply + +Run without --apply to see a dry-run summary. +""" + +from __future__ import annotations + +import argparse +import json +import sys +from collections import defaultdict +from pathlib import Path +from typing import Dict, Iterable, List, Optional, Tuple + +REPO_ROOT = Path(__file__).resolve().parents[1] +DEFAULT_SIGNATURES = REPO_ROOT / "docs" / "type3" / "signatures" +DEFAULT_INDEX = ( + REPO_ROOT / "app" / "core" / "src" / "main" / "resources" / "type3" / "library" / "index.json" +) + + +def normalize_alias(value: Optional[str]) -> Optional[str]: + if not value: + return None + trimmed = value.strip() + plus = trimmed.find("+") + if plus >= 0 and plus < len(trimmed) - 1: + trimmed = trimmed[plus + 1 :] + lowered = trimmed.lower() + return lowered if lowered else None + + +def load_json(path: Path): + with path.open("r", encoding="utf-8") as handle: + return json.load(handle) + + +def dump_json(path: Path, data) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + with path.open("w", encoding="utf-8") as handle: + json.dump(data, handle, indent=2) + handle.write("\n") + + +def iter_signature_fonts(signature_file: Path): + payload = load_json(signature_file) + pdf_source = payload.get("pdf") + for font in payload.get("fonts", []): + alias = font.get("alias") or font.get("baseName") + normalized = normalize_alias(alias) or normalize_alias(font.get("baseName")) + yield { + "alias_raw": alias, + "alias": normalized, + "baseName": font.get("baseName"), + "signature": font.get("signature"), + "glyphCoverage": font.get("glyphCoverage") or [], + "pdf": pdf_source, + "file": signature_file, + } + + +def make_alias_index(entries: List[Dict]) -> Tuple[Dict[str, Dict], Dict[str, Dict]]: + alias_index: Dict[str, Dict] = {} + signature_index: Dict[str, Dict] = {} + for entry in entries: + for alias in entry.get("aliases", []) or []: + normalized = normalize_alias(alias) + if normalized: + alias_index.setdefault(normalized, entry) + base_name_alias = normalize_alias(entry.get("label")) + if base_name_alias: + alias_index.setdefault(base_name_alias, entry) + for signature in entry.get("signatures", []) or []: + signature_index.setdefault(signature.lower(), entry) + return alias_index, signature_index + + +def ensure_list(container: Dict, key: str) -> List: + value = container.get(key) + if isinstance(value, list): + return value + value = [] + container[key] = value + return value + + +def merge_sorted_unique(values: Iterable[int]) -> List[int]: + return sorted({int(v) for v in values if isinstance(v, int)}) + + +def normalize_source_path(pdf_path: Optional[str]) -> Optional[str]: + if not pdf_path: + return None + try: + source = Path(pdf_path) + rel = source.relative_to(REPO_ROOT) + except Exception: + rel = Path(pdf_path) + return str(rel).replace("\\", "/") + + +def update_library( + signatures_dir: Path, index_path: Path, apply_changes: bool +) -> Tuple[int, int, List[Tuple[str, Path]]]: + entries = load_json(index_path) + alias_index, signature_index = make_alias_index(entries) + + modifications = 0 + updated_entries = set() + unmatched: List[Tuple[str, Path]] = [] + + signature_files = sorted(signatures_dir.glob("*.json")) + if not signature_files: + print(f"No signature JSON files found under {signatures_dir}", file=sys.stderr) + return 0, 0, unmatched + + for sig_file in signature_files: + for font in iter_signature_fonts(sig_file): + signature = font["signature"] + norm_signature = signature.lower() if signature else None + alias = font["alias"] + + entry = None + if norm_signature and norm_signature in signature_index: + entry = signature_index[norm_signature] + elif alias and alias in alias_index: + entry = alias_index[alias] + + if entry is None: + unmatched.append((font.get("baseName") or font.get("alias_raw") or "unknown", sig_file)) + continue + + entry_modified = False + + # Signatures + if signature: + signature_list = ensure_list(entry, "signatures") + if signature not in signature_list: + signature_list.append(signature) + entry_modified = True + signature_index[signature.lower()] = entry + + # Aliases + alias_raw = font.get("alias_raw") + if alias_raw: + aliases = ensure_list(entry, "aliases") + if alias_raw not in aliases: + aliases.append(alias_raw) + entry_modified = True + normalized = normalize_alias(alias_raw) + if normalized: + alias_index.setdefault(normalized, entry) + + # Glyph coverage + coverage = font.get("glyphCoverage") or [] + if coverage: + existing = set(entry.get("glyphCoverage", [])) + merged = merge_sorted_unique(list(existing) + coverage) + if merged != entry.get("glyphCoverage"): + entry["glyphCoverage"] = merged + entry_modified = True + + # Source PDF + pdf_source = normalize_source_path(font.get("pdf")) + if pdf_source and not entry.get("source"): + entry["source"] = pdf_source + entry_modified = True + + if entry_modified: + modifications += 1 + updated_entries.add(entry.get("id", "")) + + if apply_changes and modifications > 0: + dump_json(index_path, entries) + + return modifications, len(updated_entries), unmatched + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(description="Update Type3 library index using signature dumps.") + parser.add_argument( + "--signatures-dir", + type=Path, + default=DEFAULT_SIGNATURES, + help=f"Directory containing signature JSON files (default: {DEFAULT_SIGNATURES})", + ) + parser.add_argument( + "--index", + type=Path, + default=DEFAULT_INDEX, + help=f"Path to type3/library/index.json (default: {DEFAULT_INDEX})", + ) + parser.add_argument( + "--apply", + action="store_true", + help="Write changes back to the index file. Without this flag the script runs in dry-run mode.", + ) + return parser.parse_args() + + +def main() -> None: + args = parse_args() + signatures_dir = args.signatures_dir if args.signatures_dir.is_absolute() else (REPO_ROOT / args.signatures_dir) + index_path = args.index if args.index.is_absolute() else (REPO_ROOT / args.index) + + if not signatures_dir.exists(): + print(f"Signature directory not found: {signatures_dir}", file=sys.stderr) + sys.exit(2) + if not index_path.exists(): + print(f"Index file not found: {index_path}", file=sys.stderr) + sys.exit(2) + + modifications, updated_entries, unmatched = update_library( + signatures_dir, index_path, apply_changes=args.apply + ) + + mode = "APPLIED" if args.apply else "DRY-RUN" + print( + f"[{mode}] Processed signatures under {signatures_dir}. " + f"Updated entries: {updated_entries}, individual modifications: {modifications}." + ) + + if unmatched: + print("\nUnmatched fonts (no library entry yet):") + for alias, sig_file in unmatched: + print(f" - {alias} (from {sig_file})") + print("Add these fonts to index.json with the proper payload before rerunning.") + + if modifications == 0: + print("No changes detected; index.json already matches captured signatures.") + + +if __name__ == "__main__": + main()