diff --git a/examples/08_bundled_fonts_demo.py b/examples/08_bundled_fonts_demo.py new file mode 100644 index 0000000..f74e076 --- /dev/null +++ b/examples/08_bundled_fonts_demo.py @@ -0,0 +1,227 @@ +""" +Demonstration of bundled fonts in pyWebLayout. + +This example shows: +1. How to use the bundled DejaVu font families +2. Different font variants (regular, bold, italic, bold-italic) +3. The three font families (Sans, Serif, Monospace) +4. Convenient Font.from_family() method for easy font selection + +The demo creates a page showcasing all bundled fonts with different styles. +""" + +from pyWebLayout.concrete import Page +from pyWebLayout.abstract import Paragraph, Word +from pyWebLayout.style import Font, FontWeight, FontStyle, BundledFont +from pyWebLayout.style.page_style import PageStyle +from pyWebLayout.layout.document_layouter import DocumentLayouter + + +def create_font_showcase_page(): + """ + Create a page demonstrating all bundled fonts and variants. + """ + # Create page with some padding + page = Page(size=(800, 1000), style=PageStyle(border_width=20)) + layouter = DocumentLayouter(page) + + # Title + title_font = Font.from_family( + BundledFont.SANS, + font_size=32, + colour=(0, 0, 100), + weight=FontWeight.BOLD + ) + title = Paragraph(title_font) + title.add_word(Word("Bundled", title_font)) + title.add_word(Word("Fonts", title_font)) + title.add_word(Word("Showcase", title_font)) + layouter.layout_paragraph(title) + page._current_y_offset += 20 + + # Introduction + intro_font = Font.from_family(BundledFont.SANS, font_size=14, colour=(50, 50, 50)) + intro = Paragraph(intro_font) + intro_text = "pyWebLayout bundles the DejaVu font family with three font types and four variants each." + for word in intro_text.split(): + intro.add_word(Word(word, intro_font)) + layouter.layout_paragraph(intro) + page._current_y_offset += 25 + + # --- Sans Serif Section --- + section_font = Font.from_family( + BundledFont.SANS, + font_size=20, + colour=(0, 100, 0), + weight=FontWeight.BOLD + ) + sans_section = Paragraph(section_font) + sans_section.add_word(Word("Sans-Serif", section_font)) + sans_section.add_word(Word("(DejaVu", section_font)) + sans_section.add_word(Word("Sans)", section_font)) + layouter.layout_paragraph(sans_section) + page._current_y_offset += 10 + + # Sans Regular + sans_regular = Font.from_family(BundledFont.SANS, font_size=16) + demo_text_paragraph(layouter, page, sans_regular, "Regular:") + + # Sans Bold + sans_bold = Font.from_family(BundledFont.SANS, font_size=16, weight=FontWeight.BOLD) + demo_text_paragraph(layouter, page, sans_bold, "Bold:") + + # Sans Italic + sans_italic = Font.from_family(BundledFont.SANS, font_size=16, style=FontStyle.ITALIC) + demo_text_paragraph(layouter, page, sans_italic, "Italic:") + + # Sans Bold Italic + sans_bold_italic = Font.from_family( + BundledFont.SANS, + font_size=16, + weight=FontWeight.BOLD, + style=FontStyle.ITALIC + ) + demo_text_paragraph(layouter, page, sans_bold_italic, "Bold Italic:") + page._current_y_offset += 20 + + # --- Serif Section --- + serif_section = Paragraph(section_font) + serif_section.add_word(Word("Serif", section_font)) + serif_section.add_word(Word("(DejaVu", section_font)) + serif_section.add_word(Word("Serif)", section_font)) + layouter.layout_paragraph(serif_section) + page._current_y_offset += 10 + + # Serif Regular + serif_regular = Font.from_family(BundledFont.SERIF, font_size=16) + demo_text_paragraph(layouter, page, serif_regular, "Regular:") + + # Serif Bold + serif_bold = Font.from_family(BundledFont.SERIF, font_size=16, weight=FontWeight.BOLD) + demo_text_paragraph(layouter, page, serif_bold, "Bold:") + + # Serif Italic + serif_italic = Font.from_family(BundledFont.SERIF, font_size=16, style=FontStyle.ITALIC) + demo_text_paragraph(layouter, page, serif_italic, "Italic:") + + # Serif Bold Italic + serif_bold_italic = Font.from_family( + BundledFont.SERIF, + font_size=16, + weight=FontWeight.BOLD, + style=FontStyle.ITALIC + ) + demo_text_paragraph(layouter, page, serif_bold_italic, "Bold Italic:") + page._current_y_offset += 20 + + # --- Monospace Section --- + mono_section = Paragraph(section_font) + mono_section.add_word(Word("Monospace", section_font)) + mono_section.add_word(Word("(DejaVu", section_font)) + mono_section.add_word(Word("Sans", section_font)) + mono_section.add_word(Word("Mono)", section_font)) + layouter.layout_paragraph(mono_section) + page._current_y_offset += 10 + + # Mono Regular + mono_regular = Font.from_family(BundledFont.MONOSPACE, font_size=14) + demo_code_paragraph(layouter, page, mono_regular, "Regular:") + + # Mono Bold + mono_bold = Font.from_family(BundledFont.MONOSPACE, font_size=14, weight=FontWeight.BOLD) + demo_code_paragraph(layouter, page, mono_bold, "Bold:") + + # Mono Italic + mono_italic = Font.from_family(BundledFont.MONOSPACE, font_size=14, style=FontStyle.ITALIC) + demo_code_paragraph(layouter, page, mono_italic, "Italic:") + + # Mono Bold Italic + mono_bold_italic = Font.from_family( + BundledFont.MONOSPACE, + font_size=14, + weight=FontWeight.BOLD, + style=FontStyle.ITALIC + ) + demo_code_paragraph(layouter, page, mono_bold_italic, "Bold Italic:") + page._current_y_offset += 20 + + # Footer + footer_font = Font.from_family(BundledFont.SANS, font_size=12, colour=(100, 100, 100)) + footer = Paragraph(footer_font) + footer_text = "All fonts are free and open source under the Bitstream Vera License." + for word in footer_text.split(): + footer.add_word(Word(word, footer_font)) + layouter.layout_paragraph(footer) + + return page + + +def demo_text_paragraph(layouter, page, font, label): + """Create a paragraph showing sample text with the given font.""" + # Label in smaller font + label_font = Font.from_family(BundledFont.SANS, font_size=12, colour=(100, 100, 100)) + label_para = Paragraph(label_font) + label_para.add_word(Word(label, label_font)) + layouter.layout_paragraph(label_para) + page._current_y_offset += 5 + + # Sample text + para = Paragraph(font) + sample = "The quick brown fox jumps over the lazy dog. 0123456789" + for word in sample.split(): + para.add_word(Word(word, font)) + layouter.layout_paragraph(para) + page._current_y_offset += 8 + + +def demo_code_paragraph(layouter, page, font, label): + """Create a paragraph showing sample code with the given font.""" + # Label in smaller font + label_font = Font.from_family(BundledFont.SANS, font_size=12, colour=(100, 100, 100)) + label_para = Paragraph(label_font) + label_para.add_word(Word(label, label_font)) + layouter.layout_paragraph(label_para) + page._current_y_offset += 5 + + # Sample code + para = Paragraph(font) + code = "def hello(): print('Hello, World!') # 0123456789" + for word in code.split(): + para.add_word(Word(word, font)) + layouter.layout_paragraph(para) + page._current_y_offset += 8 + + +if __name__ == "__main__": + print("\n") + print("=" * 70) + print("Bundled Fonts Demonstration") + print("=" * 70) + print() + + print("Creating font showcase page...") + page = create_font_showcase_page() + + print("Rendering page...") + image = page.render() + + output_file = "demo_08_bundled_fonts.png" + image.save(output_file) + print(f"Saved: {output_file}") + + print() + print("=" * 70) + print("Demo complete!") + print() + print("The page showcases all bundled fonts:") + print(" - DejaVu Sans (Sans-serif)") + print(" - DejaVu Serif (Serif)") + print(" - DejaVu Sans Mono (Monospace)") + print() + print("Each family has 4 variants:") + print(" - Regular") + print(" - Bold") + print(" - Italic") + print(" - Bold Italic") + print("=" * 70) + print() diff --git a/pyWebLayout/assets/fonts/DEJAVU_LICENSE.txt b/pyWebLayout/assets/fonts/DEJAVU_LICENSE.txt new file mode 100644 index 0000000..df52c17 --- /dev/null +++ b/pyWebLayout/assets/fonts/DEJAVU_LICENSE.txt @@ -0,0 +1,187 @@ +Fonts are (c) Bitstream (see below). DejaVu changes are in public domain. +Glyphs imported from Arev fonts are (c) Tavmjong Bah (see below) + + +Bitstream Vera Fonts Copyright +------------------------------ + +Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is +a trademark of Bitstream, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of the fonts accompanying this license ("Fonts") and associated +documentation files (the "Font Software"), to reproduce and distribute the +Font Software, including without limitation the rights to use, copy, merge, +publish, distribute, and/or sell copies of the Font Software, and to permit +persons to whom the Font Software is furnished to do so, subject to the +following conditions: + +The above copyright and trademark notices and this permission notice shall +be included in all copies of one or more of the Font Software typefaces. + +The Font Software may be modified, altered, or added to, and in particular +the designs of glyphs or characters in the Fonts may be modified and +additional glyphs or characters may be added to the Fonts, only if the fonts +are renamed to names not containing either the words "Bitstream" or the word +"Vera". + +This License becomes null and void to the extent applicable to Fonts or Font +Software that has been modified and is distributed under the "Bitstream +Vera" names. + +The Font Software may be sold as part of a larger software package but no +copy of one or more of the Font Software typefaces may be sold by itself. + +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, +TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME +FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING +ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE +FONT SOFTWARE. + +Except as contained in this notice, the names of Gnome, the Gnome +Foundation, and Bitstream Inc., shall not be used in advertising or +otherwise to promote the sale, use or other dealings in this Font Software +without prior written authorization from the Gnome Foundation or Bitstream +Inc., respectively. For further information, contact: fonts at gnome dot +org. + +Arev Fonts Copyright +------------------------------ + +Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of the fonts accompanying this license ("Fonts") and +associated documentation files (the "Font Software"), to reproduce +and distribute the modifications to the Bitstream Vera Font Software, +including without limitation the rights to use, copy, merge, publish, +distribute, and/or sell copies of the Font Software, and to permit +persons to whom the Font Software is furnished to do so, subject to +the following conditions: + +The above copyright and trademark notices and this permission notice +shall be included in all copies of one or more of the Font Software +typefaces. + +The Font Software may be modified, altered, or added to, and in +particular the designs of glyphs or characters in the Fonts may be +modified and additional glyphs or characters may be added to the +Fonts, only if the fonts are renamed to names not containing either +the words "Tavmjong Bah" or the word "Arev". + +This License becomes null and void to the extent applicable to Fonts +or Font Software that has been modified and is distributed under the +"Tavmjong Bah Arev" names. + +The Font Software may be sold as part of a larger software package but +no copy of one or more of the Font Software typefaces may be sold by +itself. + +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL +TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. + +Except as contained in this notice, the name of Tavmjong Bah shall not +be used in advertising or otherwise to promote the sale, use or other +dealings in this Font Software without prior written authorization +from Tavmjong Bah. For further information, contact: tavmjong @ free +. fr. + +TeX Gyre DJV Math +----------------- +Fonts are (c) Bitstream (see below). DejaVu changes are in public domain. + +Math extensions done by B. Jackowski, P. Strzelczyk and P. Pianowski +(on behalf of TeX users groups) are in public domain. + +Letters imported from Euler Fraktur from AMSfonts are (c) American +Mathematical Society (see below). +Bitstream Vera Fonts Copyright +Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera +is a trademark of Bitstream, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of the fonts accompanying this license (“Fonts”) and associated +documentation +files (the “Font Software”), to reproduce and distribute the Font Software, +including without limitation the rights to use, copy, merge, publish, +distribute, +and/or sell copies of the Font Software, and to permit persons to whom +the Font Software is furnished to do so, subject to the following +conditions: + +The above copyright and trademark notices and this permission notice +shall be +included in all copies of one or more of the Font Software typefaces. + +The Font Software may be modified, altered, or added to, and in particular +the designs of glyphs or characters in the Fonts may be modified and +additional +glyphs or characters may be added to the Fonts, only if the fonts are +renamed +to names not containing either the words “Bitstream” or the word “Vera”. + +This License becomes null and void to the extent applicable to Fonts or +Font Software +that has been modified and is distributed under the “Bitstream Vera” +names. + +The Font Software may be sold as part of a larger software package but +no copy +of one or more of the Font Software typefaces may be sold by itself. + +THE FONT SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, +TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME +FOUNDATION +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, +SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN +ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR +INABILITY TO USE +THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. +Except as contained in this notice, the names of GNOME, the GNOME +Foundation, +and Bitstream Inc., shall not be used in advertising or otherwise to promote +the sale, use or other dealings in this Font Software without prior written +authorization from the GNOME Foundation or Bitstream Inc., respectively. +For further information, contact: fonts at gnome dot org. + +AMSFonts (v. 2.2) copyright + +The PostScript Type 1 implementation of the AMSFonts produced by and +previously distributed by Blue Sky Research and Y&Y, Inc. are now freely +available for general use. This has been accomplished through the +cooperation +of a consortium of scientific publishers with Blue Sky Research and Y&Y. +Members of this consortium include: + +Elsevier Science IBM Corporation Society for Industrial and Applied +Mathematics (SIAM) Springer-Verlag American Mathematical Society (AMS) + +In order to assure the authenticity of these fonts, copyright will be +held by +the American Mathematical Society. This is not meant to restrict in any way +the legitimate use of the fonts, such as (but not limited to) electronic +distribution of documents containing these fonts, inclusion of these fonts +into other public domain or commercial font collections or computer +applications, use of the outline data to create derivative fonts and/or +faces, etc. However, the AMS does require that the AMS copyright notice be +removed from any derivative versions of the fonts which have been altered in +any way. In addition, to ensure the fidelity of TeX documents using Computer +Modern fonts, Professor Donald Knuth, creator of the Computer Modern faces, +has requested that any alterations which yield different font metrics be +given a different name. + +$Id$ diff --git a/pyWebLayout/assets/fonts/DEJAVU_README.md b/pyWebLayout/assets/fonts/DEJAVU_README.md new file mode 100644 index 0000000..43148d7 --- /dev/null +++ b/pyWebLayout/assets/fonts/DEJAVU_README.md @@ -0,0 +1,67 @@ +[![Build Status](https://travis-ci.org/dejavu-fonts/dejavu-fonts.svg)](https://travis-ci.org/dejavu-fonts/dejavu-fonts) + +DejaVu fonts 2.37 (c)2004-2016 DejaVu fonts team +------------------------------------------------ + +The DejaVu fonts are a font family based on the Bitstream Vera Fonts +(http://gnome.org/fonts/). Its purpose is to provide a wider range of +characters (see status.txt for more information) while maintaining the +original look and feel. + +DejaVu fonts are based on Bitstream Vera fonts version 1.10. + +Available fonts (Sans = sans serif, Mono = monospaced): + +DejaVu Sans Mono +DejaVu Sans Mono Bold +DejaVu Sans Mono Bold Oblique +DejaVu Sans Mono Oblique +DejaVu Sans +DejaVu Sans Bold +DejaVu Sans Bold Oblique +DejaVu Sans Oblique +DejaVu Sans ExtraLight (experimental) +DejaVu Serif +DejaVu Serif Bold +DejaVu Serif Bold Italic (experimental) +DejaVu Serif Italic (experimental) +DejaVu Sans Condensed (experimental) +DejaVu Sans Condensed Bold (experimental) +DejaVu Sans Condensed Bold Oblique (experimental) +DejaVu Sans Condensed Oblique (experimental) +DejaVu Serif Condensed (experimental) +DejaVu Serif Condensed Bold (experimental) +DejaVu Serif Condensed Bold Italic (experimental) +DejaVu Serif Condensed Italic (experimental) +DejaVu Math TeX Gyre + +All fonts are also available as derivative called DejaVu LGC with support +only for Latin, Greek and Cyrillic scripts. + +For license information see LICENSE. What's new is described in NEWS. Known +bugs are in BUGS. All authors are mentioned in AUTHORS. + +Fonts are published in source form as SFD files (Spline Font Database from +FontForge - http://fontforge.sf.net/) and in compiled form as TTF files +(TrueType fonts). + +For more information go to http://dejavu.sourceforge.net/. + +Characters from Arev fonts, Copyright (c) 2006 by Tavmjong Bah: +--------------------------- +U+01BA, U+01BF, U+01F7, U+021C-U+021D, U+0220, U+0222-U+0223, +U+02B9, U+02BA, U+02BD, U+02C2-U+02C5, U+02d4-U+02D5, +U+02D7, U+02EC-U+02EE, U+0346-U+034E, U+0360, U+0362, +U+03E2-03EF, U+0460-0463, U+0466-U+0486, U+0488-U+0489, U+04A8-U+04A9, +U+0500-U+050F, U+2055-205E, U+20B0, U+20B2-U+20B3, U+2102, U+210D, U+210F, +U+2111, U+2113, U+2115, U+2118-U+211A, U+211C-U+211D, U+2124, U+2135, +U+213C-U+2140, U+2295-U+2298, U+2308-U+230B, U+26A2-U+26B1, U+2701-U+2704, +U+2706-U+2709, U+270C-U+274B, U+2758-U+275A, U+2761-U+2775, U+2780-U+2794, +U+2798-U+27AF, U+27B1-U+27BE, U+FB05-U+FB06 + +DejaVu Math TeX Gyre +-------------------- +TeX Gyre DJV Math by B. Jackowski, P. Strzelczyk and P. Pianowski +(on behalf of TeX users groups). + +$Id$ diff --git a/pyWebLayout/assets/fonts/DejaVuSans-Bold.ttf b/pyWebLayout/assets/fonts/DejaVuSans-Bold.ttf new file mode 100644 index 0000000..6d65fa7 Binary files /dev/null and b/pyWebLayout/assets/fonts/DejaVuSans-Bold.ttf differ diff --git a/pyWebLayout/assets/fonts/DejaVuSans-BoldOblique.ttf b/pyWebLayout/assets/fonts/DejaVuSans-BoldOblique.ttf new file mode 100644 index 0000000..753f2d8 Binary files /dev/null and b/pyWebLayout/assets/fonts/DejaVuSans-BoldOblique.ttf differ diff --git a/pyWebLayout/assets/fonts/DejaVuSans-Oblique.ttf b/pyWebLayout/assets/fonts/DejaVuSans-Oblique.ttf new file mode 100644 index 0000000..999bac7 Binary files /dev/null and b/pyWebLayout/assets/fonts/DejaVuSans-Oblique.ttf differ diff --git a/pyWebLayout/assets/fonts/DejaVuSans.ttf b/pyWebLayout/assets/fonts/DejaVuSans.ttf index 470298d..e5f7eec 100644 Binary files a/pyWebLayout/assets/fonts/DejaVuSans.ttf and b/pyWebLayout/assets/fonts/DejaVuSans.ttf differ diff --git a/pyWebLayout/assets/fonts/DejaVuSansMono-Bold.ttf b/pyWebLayout/assets/fonts/DejaVuSansMono-Bold.ttf new file mode 100644 index 0000000..8184ced Binary files /dev/null and b/pyWebLayout/assets/fonts/DejaVuSansMono-Bold.ttf differ diff --git a/pyWebLayout/assets/fonts/DejaVuSansMono-BoldOblique.ttf b/pyWebLayout/assets/fonts/DejaVuSansMono-BoldOblique.ttf new file mode 100644 index 0000000..754dca7 Binary files /dev/null and b/pyWebLayout/assets/fonts/DejaVuSansMono-BoldOblique.ttf differ diff --git a/pyWebLayout/assets/fonts/DejaVuSansMono-Oblique.ttf b/pyWebLayout/assets/fonts/DejaVuSansMono-Oblique.ttf new file mode 100644 index 0000000..4c858d4 Binary files /dev/null and b/pyWebLayout/assets/fonts/DejaVuSansMono-Oblique.ttf differ diff --git a/pyWebLayout/assets/fonts/DejaVuSansMono.ttf b/pyWebLayout/assets/fonts/DejaVuSansMono.ttf new file mode 100644 index 0000000..f578602 Binary files /dev/null and b/pyWebLayout/assets/fonts/DejaVuSansMono.ttf differ diff --git a/pyWebLayout/assets/fonts/DejaVuSerif-Bold.ttf b/pyWebLayout/assets/fonts/DejaVuSerif-Bold.ttf new file mode 100644 index 0000000..3bb755f Binary files /dev/null and b/pyWebLayout/assets/fonts/DejaVuSerif-Bold.ttf differ diff --git a/pyWebLayout/assets/fonts/DejaVuSerif-BoldItalic.ttf b/pyWebLayout/assets/fonts/DejaVuSerif-BoldItalic.ttf new file mode 100644 index 0000000..a36dd4b Binary files /dev/null and b/pyWebLayout/assets/fonts/DejaVuSerif-BoldItalic.ttf differ diff --git a/pyWebLayout/assets/fonts/DejaVuSerif-Italic.ttf b/pyWebLayout/assets/fonts/DejaVuSerif-Italic.ttf new file mode 100644 index 0000000..805daf2 Binary files /dev/null and b/pyWebLayout/assets/fonts/DejaVuSerif-Italic.ttf differ diff --git a/pyWebLayout/assets/fonts/DejaVuSerif.ttf b/pyWebLayout/assets/fonts/DejaVuSerif.ttf new file mode 100644 index 0000000..0b803d2 Binary files /dev/null and b/pyWebLayout/assets/fonts/DejaVuSerif.ttf differ diff --git a/pyWebLayout/assets/fonts/README.md b/pyWebLayout/assets/fonts/README.md new file mode 100644 index 0000000..6faa088 --- /dev/null +++ b/pyWebLayout/assets/fonts/README.md @@ -0,0 +1,129 @@ +# Bundled Fonts + +This directory contains free, open-source TrueType fonts bundled with pyWebLayout for consistent rendering across all platforms. + +## Font Families + +### DejaVu Sans (Sans-serif) +A modern, clean sans-serif font excellent for body text and UI elements. + +- `DejaVuSans.ttf` - Regular +- `DejaVuSans-Bold.ttf` - Bold +- `DejaVuSans-Oblique.ttf` - Italic +- `DejaVuSans-BoldOblique.ttf` - Bold Italic + +### DejaVu Serif (Serif) +A classic serif font ideal for formal documents and traditional layouts. + +- `DejaVuSerif.ttf` - Regular +- `DejaVuSerif-Bold.ttf` - Bold +- `DejaVuSerif-Italic.ttf` - Italic +- `DejaVuSerif-BoldItalic.ttf` - Bold Italic + +### DejaVu Sans Mono (Monospace) +A fixed-width font perfect for code blocks and technical content. + +- `DejaVuSansMono.ttf` - Regular +- `DejaVuSansMono-Bold.ttf` - Bold +- `DejaVuSansMono-Oblique.ttf` - Italic +- `DejaVuSansMono-BoldOblique.ttf` - Bold Italic + +## Usage + +### Easy Way: Using Font.from_family() (Recommended) + +The easiest way to use bundled fonts is with the `Font.from_family()` class method: + +```python +from pyWebLayout.style import Font, BundledFont, FontWeight, FontStyle + +# Create a sans-serif font +sans_font = Font.from_family( + BundledFont.SANS, + font_size=16 +) + +# Create a bold serif font +serif_bold = Font.from_family( + BundledFont.SERIF, + font_size=18, + weight=FontWeight.BOLD +) + +# Create an italic monospace font +mono_italic = Font.from_family( + BundledFont.MONOSPACE, + font_size=14, + style=FontStyle.ITALIC +) + +# Create a bold italic sans font +sans_bold_italic = Font.from_family( + BundledFont.SANS, + font_size=16, + weight=FontWeight.BOLD, + style=FontStyle.ITALIC +) +``` + +### Manual Way: Using get_bundled_font_path() + +You can also get the path to bundled fonts directly: + +```python +from pyWebLayout.style import Font, BundledFont, FontWeight, FontStyle, get_bundled_font_path + +# Get the path to a specific font +font_path = get_bundled_font_path( + BundledFont.SERIF, + weight=FontWeight.BOLD, + style=FontStyle.ITALIC +) + +# Create a font with that path +font = Font(font_path=font_path, font_size=16) +``` + +### Low-level Way: Direct Paths + +If you prefer to specify paths directly: + +```python +import os +from pyWebLayout.style import Font, get_bundled_fonts_dir + +# Get the fonts directory +fonts_dir = get_bundled_fonts_dir() + +# Use specific font files +sans_font = Font( + font_path=os.path.join(fonts_dir, 'DejaVuSans.ttf'), + font_size=16 +) + +serif_bold = Font( + font_path=os.path.join(fonts_dir, 'DejaVuSerif-Bold.ttf'), + font_size=18 +) + +mono_italic = Font( + font_path=os.path.join(fonts_dir, 'DejaVuSansMono-Oblique.ttf'), + font_size=14 +) +``` + +## License + +The DejaVu fonts are free software under the terms of the Bitstream Vera Fonts Copyright and the Arev Fonts Copyright. + +See `DEJAVU_LICENSE.txt` for full license details. + +## About DejaVu Fonts + +DejaVu fonts are a font family based on the Bitstream Vera Fonts. Its purpose is to provide a wider range of characters while maintaining the original look and feel through the process of collaborative development. + +- **Version**: 2.37 +- **Website**: https://dejavu-fonts.github.io/ +- **Repository**: https://github.com/dejavu-fonts/dejavu-fonts + +The fonts provide excellent Unicode coverage and are widely used in open-source projects. diff --git a/pyWebLayout/style/__init__.py b/pyWebLayout/style/__init__.py index f701ba6..9fac916 100644 --- a/pyWebLayout/style/__init__.py +++ b/pyWebLayout/style/__init__.py @@ -4,7 +4,10 @@ Style system for the pyWebLayout library. This module provides the core styling components used throughout the library. """ -from .fonts import Font, FontWeight, FontStyle, TextDecoration +from .fonts import ( + Font, FontWeight, FontStyle, TextDecoration, + BundledFont, get_bundled_font_path, get_bundled_fonts_dir +) from .abstract_style import ( AbstractStyle, AbstractStyleRegistry, FontFamily, FontSize ) @@ -14,6 +17,7 @@ from .alignment import Alignment __all__ = [ "Font", "FontWeight", "FontStyle", "TextDecoration", + "BundledFont", "get_bundled_font_path", "get_bundled_fonts_dir", "AbstractStyle", "AbstractStyleRegistry", "FontFamily", "FontSize", "ConcreteStyle", "PageStyle", "Alignment" ] diff --git a/pyWebLayout/style/fonts.py b/pyWebLayout/style/fonts.py index e6f109f..3831ee5 100644 --- a/pyWebLayout/style/fonts.py +++ b/pyWebLayout/style/fonts.py @@ -16,6 +16,9 @@ _FONT_CACHE: Dict[Tuple[Optional[str], int], ImageFont.FreeTypeFont] = {} # Cache for bundled font path to avoid repeated filesystem lookups _BUNDLED_FONT_PATH: Optional[str] = None +# Cache for bundled fonts directory +_BUNDLED_FONTS_DIR: Optional[str] = None + class FontWeight(Enum): NORMAL = "normal" @@ -33,6 +36,105 @@ class TextDecoration(Enum): STRIKETHROUGH = "strikethrough" +class BundledFont(Enum): + """Bundled font families available in pyWebLayout""" + SANS = "sans" # DejaVu Sans - modern sans-serif + SERIF = "serif" # DejaVu Serif - classic serif + MONOSPACE = "monospace" # DejaVu Sans Mono - fixed-width + + +def get_bundled_fonts_dir(): + """ + Get the directory containing bundled fonts (cached). + + Returns: + str: Path to the fonts directory, or None if not found + """ + global _BUNDLED_FONTS_DIR + + # Return cached path if available + if _BUNDLED_FONTS_DIR is not None: + return _BUNDLED_FONTS_DIR + + # First time - determine the path and cache it + current_dir = os.path.dirname(os.path.abspath(__file__)) + fonts_dir = os.path.join(os.path.dirname(current_dir), 'assets', 'fonts') + + if os.path.exists(fonts_dir) and os.path.isdir(fonts_dir): + _BUNDLED_FONTS_DIR = fonts_dir + logger.debug(f"Found bundled fonts directory at: {fonts_dir}") + return fonts_dir + else: + logger.warning(f"Bundled fonts directory not found at: {fonts_dir}") + _BUNDLED_FONTS_DIR = "" # Empty string to indicate "checked but not found" + return None + + +def get_bundled_font_path( + family: BundledFont = BundledFont.SANS, + weight: FontWeight = FontWeight.NORMAL, + style: FontStyle = FontStyle.NORMAL +) -> Optional[str]: + """ + Get the path to a specific bundled font file. + + Args: + family: The font family (SANS, SERIF, or MONOSPACE) + weight: The font weight (NORMAL or BOLD) + style: The font style (NORMAL or ITALIC) + + Returns: + str: Full path to the font file, or None if not found + + Example: + >>> # Get bold italic sans font + >>> path = get_bundled_font_path(BundledFont.SANS, FontWeight.BOLD, FontStyle.ITALIC) + >>> font = Font(font_path=path, font_size=16) + """ + fonts_dir = get_bundled_fonts_dir() + if not fonts_dir: + return None + + # Map font parameters to filename + family_map = { + BundledFont.SANS: "DejaVuSans", + BundledFont.SERIF: "DejaVuSerif", + BundledFont.MONOSPACE: "DejaVuSansMono" + } + + base_name = family_map.get(family, "DejaVuSans") + + # Build the font file name + parts = [base_name] + + if weight == FontWeight.BOLD and style == FontStyle.ITALIC: + # Special case: both bold and italic + if family == BundledFont.MONOSPACE: + parts.append("BoldOblique") + elif family == BundledFont.SERIF: + parts.append("BoldItalic") + else: # SANS + parts.append("BoldOblique") + elif weight == FontWeight.BOLD: + parts.append("Bold") + elif style == FontStyle.ITALIC: + # Italic naming differs by family + if family == BundledFont.MONOSPACE or family == BundledFont.SANS: + parts.append("Oblique") + else: # SERIF + parts.append("Italic") + + filename = "-".join(parts) + ".ttf" + font_path = os.path.join(fonts_dir, filename) + + if os.path.exists(font_path): + logger.debug(f"Found bundled font: {filename}") + return font_path + else: + logger.warning(f"Bundled font not found: {filename}") + return None + + class Font: """ Font class to manage text rendering properties including font face, size, color, and styling. @@ -53,7 +155,7 @@ class Font: Initialize a Font object with the specified properties. Args: - font_path: Path to the font file (.ttf, .otf). If None, uses default font. + font_path: Path to the font file (.ttf, .otf). If None, uses default bundled font. font_size: Size of the font in points. colour: RGB color tuple for the text. weight: Font weight (normal or bold). @@ -76,6 +178,57 @@ class Font: # Load the font file or use default self._load_font() + @classmethod + def from_family(cls, + family: BundledFont = BundledFont.SANS, + font_size: int = 16, + colour: Tuple[int, int, int] = (0, 0, 0), + weight: FontWeight = FontWeight.NORMAL, + style: FontStyle = FontStyle.NORMAL, + decoration: TextDecoration = TextDecoration.NONE, + background: Optional[Tuple[int, int, int, int]] = None, + language: str = "en_EN", + min_hyphenation_width: Optional[int] = None) -> 'Font': + """ + Create a Font using a bundled font family. + + This is a convenient way to use the bundled DejaVu fonts without needing to + specify paths manually. + + Args: + family: The font family to use (SANS, SERIF, or MONOSPACE) + font_size: Size of the font in points. + colour: RGB color tuple for the text. + weight: Font weight (normal or bold). + style: Font style (normal or italic). + decoration: Text decoration (none, underline, or strikethrough). + background: RGBA background color for the text. If None, transparent background. + language: Language code for hyphenation and text processing. + min_hyphenation_width: Minimum width in pixels required for hyphenation. + + Returns: + Font object configured with the bundled font + + Example: + >>> # Create a bold serif font + >>> font = Font.from_family(BundledFont.SERIF, font_size=18, weight=FontWeight.BOLD) + >>> + >>> # Create an italic monospace font + >>> code_font = Font.from_family(BundledFont.MONOSPACE, style=FontStyle.ITALIC) + """ + font_path = get_bundled_font_path(family, weight, style) + return cls( + font_path=font_path, + font_size=font_size, + colour=colour, + weight=weight, + style=style, + decoration=decoration, + background=background, + language=language, + min_hyphenation_width=min_hyphenation_width + ) + def _get_bundled_font_path(self): """Get the path to the bundled font (cached)""" global _BUNDLED_FONT_PATH