Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Please add a code example for converting OTF to TTF #1283

Open
ghost opened this issue Jun 27, 2018 · 25 comments
Open

Please add a code example for converting OTF to TTF #1283

ghost opened this issue Jun 27, 2018 · 25 comments

Comments

@ghost
Copy link

ghost commented Jun 27, 2018

Please add a code example for converting OTF to TTF. The TTX tool is mentioned which apparently can do this somehow, but I can't find it in the API. When using ttLib.TTFont.save(), the written font will remain in otf/postscript format even when saved with ".ttf" ending, so at least that function doesn't seem to do a conversion from postscript outlines to truetype outlines...

@moyogo
Copy link
Collaborator

moyogo commented Jun 27, 2018

There is already a snippet that shows how to do that:
https://github.com/fonttools/fonttools/blob/master/Snippets/otf2ttf.py

@ghost
Copy link
Author

ghost commented Jun 27, 2018

Can this be be imported as a function from the ttLib library? I would prefer to properly import this from a library rather than copying 90 lines of code, because that is problematic licensing wise unless they are explicitly stated as public domain (which they don't appear to be).

@behdad
Copy link
Member

behdad commented Jun 27, 2018

Not currently. But I agree we should make that a module.

Maybe try to unify with the CFF-to-CFF2 as well.

@miguelsousa
Copy link
Collaborator

What modifications does otf2ttf.py need to make it a core part of fonttools? I'm willing to work on it since we need its functionality in the afdko.

@miguelsousa
Copy link
Collaborator

@anthrotype are the things you mentioned at #802 (comment) still needed?

@chrissimpkins
Copy link
Member

I would prefer to properly import this from a library rather than copying 90 lines of code, because that is problematic licensing wise unless they are explicitly stated as public domain (which they don't appear to be).

@Jonast the snippets all fall under the repository MIT license unless explicitly stated otherwise. You should be able to use any snippet source under that license until a library approach is available as requested

@ghost
Copy link
Author

ghost commented Jul 27, 2018

@chrissimpkins this is not the problem. The problem is that I can't import them, so it "infects" the project source code when I need to include them into the repository - this complicates the project license (especially for projects that are under a similarly liberal, but different license). Having it properly separate as installable dependencies doesn't do that at least for source code installs / projects that don't ship packaged with full deps, which applies to many simpler, smaller projects which are also those that suffer the most from the license complexity.

@twardoch
Copy link
Contributor

twardoch commented Jul 27, 2018

I'm not sure if writing a “universal font flavor converter” should be in scope of the fontTools library.

Would it convert a TTC into multiple TTFs? Would it convert a TTF+gvar into a set of static TTFs? Would it convert an OTF+SVG into a TTF+sbix? CFF2 to CFF and vice versa? With our without variations? And if not, why not?

I don't think it's so trivial anymore to define what exactly "convert" means.

Such a converter would be great but I don't think it should be placed inside fontTools. It should be a separate lib and tool.

E.g. the OTF+SVG to TTF+sbix conversion obviously would require an SVG rasterizer, other conversions might require FreeType or other dependencies.

I think having a library and tool that would do that (some kind of fontmake v2) would be great.

It'd need to define exactly what kinds of conversions might need to happen:

  • between the tables that hold the outline-based glyph data (glyf, CFF2, CFF, SVG)
  • between the tables that hold the bitmap-based glyph data (SVG, CBDT, sbix, EBDT)
  • between the outline-based and bitmap-based glyph data
  • between outline flavors
  • between variable and static glyph data
  • between packaging formats (OTF/TTF, TTC, WOFF2, WOFF)
  • between multicolor and monochrome glyph data
  • possibly between some layout data
  • possibly between the SFNT formats and development formats (DS+UFO, Glyphs etc.)

Then, at least for some of these conversions, we'd need to map out what exactly needs to happen at the conversion time.

Then, we'd need to be implement some of these conversions.

And we'd need to clarify what is out of scope, what's not implemented etc.

Compression schemes like compositization of TTF and subroutinization of CFF/CFF2 would need to be taken into account, and hinting.

Potentially, there would be a lot of dependencies, and more could appear over time. I'd prefer not to cram all this potentially complex logic into the fontTools lib.

@ghost
Copy link
Author

ghost commented Jul 27, 2018

Well, I can only speak for myself, but I only needed that exact conversion (OTF/postscript to TTF) because reportlab kinda sucks and can't handle those fonts. So I wouldn't be hugely interested in a generic conversion library - although if it existed and handled that case I'd probably use it, but right now it's just a packaging nitpick for me.

@hexazero
Copy link

For anyone looking to convert OTF to TTF fonts, I have packaged up the above reference script into a separate package here:

https://github.com/awesometoolbox/otf2ttf

It can be installed via pip:
pip install otf2ttf

And run:
otf2ttf MyFont.ttf

Pypi package:
https://pypi.org/project/otf2ttf/

Feedback and PRs welcome.

@bananakid
Copy link

bananakid commented Jan 11, 2020

Is there a way to losslessly convert TTF TrueType outlines to OTF PostScript outlines using fonttools or similar "raw" tool?

I'm comfortable with fonttools TTX converting TTF to WOFF and vice versa, and with OTF2TTF converting OTF with PostScript outlines to TTF with TrueType outlines. Both tools work very well in terms of lossless quality. I've even assembled standalone TTX.EXE & OTF2TTF using PyInstaller and added EXE to my Windows 10 system PATH variable for quick and easy scripting.

But I cannot find any lightweight CLI way to losslessly convert TTF TrueType to OTF PostScript. Every search result brings me to FontForge which doesn't fit my needs. I've also stumbled upon Adobe Font Development Kit for OpenType (AFDKO) but have no idea if it's any good for my needs.

@m4rc1e
Copy link
Contributor

m4rc1e commented Mar 19, 2021

@Zopolis4 you can use bash:

$ find /path/to/parent/font/dir -iname "*.otf" -exec otf2ttf {} \;

@abelokoj-github
Copy link

@Zopolis4 you can use bash:

$ find /path/to/parent/font/dir -iname "*.otf" -exec otf2ttf {} \;

Thank you so much for this. It worked perfectly

@bananakid
Copy link

But I cannot find any lightweight CLI way to losslessly convert TTF TrueType to OTF PostScript.

A quick update with the solution to my question since Google still outputs my post and not an actual solution: 2,5 years later @ftCLI created a fonttools snippet just for that — TTF2OTF (discusion). This is awesome!

@behdad
Copy link
Member

behdad commented Oct 20, 2023

But I cannot find any lightweight CLI way to losslessly convert TTF TrueType to OTF PostScript.

A quick update with the solution to my question since Google still outputs my post and not an actual solution: 2,5 years later @ftCLI created a fonttools snippet just for that — TTF2OTF (discusion). This is awesome!

We should probably adopt that into fonttools.

@ftCLI
Copy link

ftCLI commented Oct 21, 2023

But I cannot find any lightweight CLI way to losslessly convert TTF TrueType to OTF PostScript.

A quick update with the solution to my question since Google still outputs my post and not an actual solution: 2,5 years later @ftCLI created a fonttools snippet just for that — TTF2OTF (discusion). This is awesome!

Thanks! I've implemented a better solution in FondryTools-CLI.

ftcli converter ttf2otf PATH

Usage: https://ftcli.github.io/FoundryTools-CLI/commands/ftcli_converter.html#ftcli-converter-ttf2otf

@bananakid
Copy link

Thank you so much @ftCLI, it worked flawlessly with -t 0.0. The only minor improvement I'd like to suggest is making package compatible with PyInstaller in the future. I've tried pyinstaller both ftcli_converter.py, ttf_to_otf.py and presumably outdated standalone ttf2otf.py and didn't succeed for various reasons (everything was done in VM from scratch via pip and pyinstaller).

@justvanrossum
Copy link
Collaborator

FWIW fonttools works just fine with PyInstaller, I use it all the time.

@ftCLI
Copy link

ftCLI commented Oct 21, 2023

Thank you so much @ftCLI, it worked flawlessly with -t 0.0. The only minor improvement I'd like to suggest is making package compatible with PyInstaller in the future. I've tried pyinstaller both ftcli_converter.py, ttf_to_otf.py and presumably outdated standalone ttf2otf.py and didn't succeed for various reasons (everything was done in VM from scratch via pip and pyinstaller).

Ok. For your info, with -t 0.0 you don't have the advantages of Qu2CuPen, but you end with a lot of points, as with T2CharStringPen.

Regarding PyInstaller, I'm aware of that. Being this the module that handles the whole CLI, I fear there's not much to do:

import sys
from pathlib import Path

from loguru import logger

import click

this_directory = Path(__file__).parent
plugin_folder = this_directory.joinpath("CLI")


class FoundryToolsCLI(click.MultiCommand):
    def list_commands(self, ctx):
        rv = []
        for file in plugin_folder.iterdir():
            if file.name.endswith(".py") and file.name.startswith("ftcli_"):
                rv.append(file.name[6:-3])
        rv.sort()
        return rv

    def get_command(self, ctx, cmd_name):
        try:
            mod = __import__(f"foundryToolsCLI.CLI.ftcli_{cmd_name}", None, None, ["cli"])
        except ImportError as e:
            logger.error(e)
            return

        return mod.cli


main = FoundryToolsCLI(help="FoundryTools Command Line Interface.")


if __name__ == "__main__":
    sys.exit(main())

I'm rewriting the CLI from scratch, and it will work with PyInstaller. As a workaround, you can use PyInstaller with the files in the CLI folder by adding if __name__ == "__main__"

@bananakid
Copy link

FWIW fonttools works just fine with PyInstaller, I use it all the time.

@justvanrossum I agree, FontTools do work with PyInstaller very well indeed. However my comment addressed FoundryTools-CLI issue. I'm sorry for hijacking the discussion.

Regarding PyInstaller, I'm aware of that.
I'm rewriting the CLI from scratch, and it will work with PyInstaller. As a workaround, you can use PyInstaller with the files in the CLI folder.

Thank you for clarification, @ftCLI! Probably worth mentioning PyInstaller incompatibility in README.md for the time being. Unfortunately I couldn't succeed with creating a working executable for any of *.py files in C:\Program Files\Python\Lib\site-packages\foundryToolsCLI\CLI folder — they just return absolutely nothing when executed in isolated environment, sorry (I tried installing Python to user's AppData too). It's not a big deal since you're working on a new CLI, just reporting something that I experienced.

I'd like to add a small problem I faced when used ttf2otf. It fails to convert Microsoft's official Fluent UI System Icons font — FluentSystemIcons-Regular.ttf. Traceback is quite lengthy but it ends with AssertionError: assert charset[0] == ".notdef" (it's featured multiple times).

@ftCLI
Copy link

ftCLI commented Oct 21, 2023

Sorry, I didn't clarify. Add the following two lines to ftcli_converter.py, and then generate the executable:

if __name__ == "__main__":
    font_converter()

I'll invesigate. Maybe open an issue.

@ftCLI
Copy link

ftCLI commented Oct 21, 2023

It's a problem with the font: first glyph is not named .notdef but glyph00000. Rename it and then convert the font.

ftcli ttf rename-glyph -old glyph00000 -new .notdef FluentSystemIcons-Regular.ttf
ftcli converter ttf2otf FluentSystemIcons-Regular.ttf

Worked for me

image

@bananakid
Copy link

It's a problem with the font: first glyph is not named .notdef but glyph00000. Rename it and then convert the font.

This worked perfectly for all variations of that font, I'm forever grateful for looking into it. FoundryTools-CLI is an extremely powerful tool indeed!

C:\Windows\system32>ftcli ttf rename-glyph -old glyph00000 -new .notdef "C:\Users\Administrator\Desktop\FluentSystemIcons-Regular.ttf"
[ INFO     ] Current file: C:\Users\Administrator\Desktop\FluentSystemIcons-Regular.ttf
2 extra bytes in post.stringData array
[ INFO     ] glyph00000 renamed to .notdef
[ SUCCESS  ] File saved: C:\Users\Administrator\Desktop\FluentSystemIcons-Regular.ttf
[ INFO     ] Elapsed time: 0.2683 seconds

C:\Windows\system32>ftcli converter ttf2otf --tolerance 0.0 --output-dir C:\Users\Administrator\Downloads "C:\Users\Administrator\Desktop\FluentSystemIcons-Regular.ttf"
[ INFO     ] Converting file: C:\Users\Administrator\Desktop\FluentSystemIcons-Regular.ttf
[ SUCCESS  ] File saved: C:\Users\Administrator\Downloads\FluentSystemIcons-Regular.otf
[ INFO     ] Elapsed time: 99.6431 seconds

Unfortunately adding mentioned lines to ftcli_converter.py didn't make a big difference, the following error appears instead of void output (I tried inserting lines before and after import, error references different lines but persists):

Traceback (most recent call last):
  File "foundryToolsCLI\CLI\ftcli_converter.py", line 22, in <module>
NameError: name 'font_converter' is not defined
[4932] Failed to execute script 'ftcli_converter' due to unhandled exception!

@ftCLI
Copy link

ftCLI commented Oct 21, 2023

(I tried inserting lines before and after import, error references different lines but persists)

You have to add those lines at the end of the file.

@bananakid
Copy link

bananakid commented Oct 22, 2023

You have to add those lines at the end of the file.

Worked like a charm for ftcli_converter.pyftcli_converter.exe! Thank you so much for continued support @ftCLI, I appreciate it a lot. Unfortunately while ftcli_converter.exe executes correctly and returns no errors, it's submodules return errors when called in isolated environment. So I guess further modification is required for PyInstaller compatibility…

C:\Users\Administrator\Desktop\FoundryTools-CLI>ftcli_converter.exe ttf2otf SegoeIcons.ttf
[ INFO     ] Elapsed time: 0.0091 seconds
Traceback (most recent call last):
  File "foundryToolsCLI\CLI\ftcli_converter.py", line 373, in <module>
  File "click\core.py", line 1157, in __call__
  File "click\core.py", line 1078, in main
  File "click\core.py", line 1688, in invoke
  File "click\core.py", line 1434, in invoke
  File "click\core.py", line 783, in invoke
  File "contextlib.py", line 79, in inner
  File "foundryToolsCLI\CLI\ftcli_converter.py", line 68, in ttf2otf
  File "PyInstaller\loader\pyimod02_importers.py", line 391, in exec_module
  File "foundryToolsCLI\Lib\converters\ttf_to_otf.py", line 11, in <module>
  File "PyInstaller\loader\pyimod02_importers.py", line 391, in exec_module
  File "foundryToolsCLI\Lib\converters\otf_to_ttf.py", line 4, in <module>
  File "PyInstaller\loader\pyimod02_importers.py", line 391, in exec_module
  File "fontTools\pens\cu2quPen.py", line 16, in <module>
  File "PyInstaller\loader\pyimod02_importers.py", line 391, in exec_module
  File "fontTools\cu2qu\__init__.py", line 15, in <module>
  File "Lib\\fontTools\\cu2qu\\cu2qu.py", line 30, in init fontTools.cu2qu.cu2qu
ModuleNotFoundError: No module named 'fontTools.cu2qu.errors'
[12592] Failed to execute script 'ftcli_converter' due to unhandled exception!

P.S. I will be posting to Discussions of FoundryTools-CLI repository next time so more users could benefit. I think your work deserves to be highlighted in the community!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests