Text-Layout-0.037/0000755000400000040000000000000014640222611011516 5ustar jvjvText-Layout-0.037/Changes0000644000400000040000000001234014640222607013016 0ustar jvjvRevision history for Text::Layout 0.037 2024-06-30 Add facilities to remap the PDF corefonts to decent font files. 0.036 2024-04-22 Introducing struts. Update SYNOPOSIS example to modern PDF::API2 conventions. Fix/enhance drawing of brackgrounds. Fix problem with wrongly calculated underlining. 0.035 2024-02-19 Fix VERSION problems for defective toolchains. 0.034 2024-02-18 Packaging changes. 0.033 2024-02-18 Packaging changes. 0.032 2023-11-01 Pluggable elements extend parsing and rendering of elements. A pluggable element is used to implement the element, to include images inline in text strings. See tests/im1.pl and tests/im3.pl for examples. Rise may now also take an 'em' or 'ex' value. 1em = 100%, 1ex = 50%. 0.031 2023-05-29 Improve bounding box and line spacing determination by using the font ascender and descender values only. Allow ascender and decender to be overruled in the font config. Adapt some of the example programs to run on Microsoft Windows. 0.030 2022-09-03 Enable xx-small, medium, large, x-large and xx-large. Enable byte-access to built-in Symbol and ZapfDingbats fonts. 0.029 2022-03-17 Fix issue #11 (PDF::Builder only). Fix font changes for Markdown. Fix in convenience mode. Handle . 0.028 2022-02-04 INCOMPATIBLE: In Pango mode, the direction of rise and lower has been reversed and is no longer proportional to the font size. In convenience mode you can use percentages and points.. INCOMPATIBLE: Extent boxes are now relative to top-left. This is Pango compatible and makes the box fit when drawn at the same coordinates the layout was rendered. (Internal) Add extents method for CID fonts. More Pango compatibility. Add font properties direction and language. Add 'pt' postfix for point sizes in markup. 0.027 2021-12-23 Pango compatibility (POSSIBLY INCOMPATIBLE): get_{pixel_}extents now returns the layout extents in scalar context. In this case, ink extents are not calculated. Improve performance (15%) by cacheing bbox. 0.026 2021-12-22 Add tests for markup parsing. Update example in README. Add 'nosubset' property for fonts. POSSIBLY INCOMPATIBLE: Fix issue #10. The difference will only be noticable when you query the width for centered/right aligned texts. UNLIKELY INCOMPATIBLE: method set_pango_scale does now enable/disable. The scaling is fixed to PANGO_SCALE (1024). Fixed some issues with pango scaling. Fix regression that sometimes tripled the resultant PDF. 0.025 2021-10-22 Add font config properties underline_thickness, strikeline_position, strikeline_thickness, overline_position, overline_thickness, and strikeline_position. Overriding the font specified/calculated values may improve results for some fonts. Note that strikeline_thickness and overline_thickness will default to underline_thickness if set. Withdraw a and link aliases for href. They may serve a different purpose in the future. 0.024 2021-10-21 Retain case sensitivity for links. Remove debugging info. 0.023 2021-10-21 Add support for underline, overline and strike, and their colours. Add support for hyperlinks (span attributes a, href and link). Note that this is not part of the official Pango Markup specification. 0.022 2021-10-04 Fix some reentrancy problems. Update for PDF::API 2.042. 0.021 2021-07-09 Fix font cacheing problem with PDFAPI2. Update links for pango documentation. 0.020 2021-05-18 Use common font cache for PDFAPI. Handle some more weight variants. Added testing PDF::Builder unless it is of an incompatible version. As of 3.019 PDF::Builder changed the font metrics to compatible values. 0.019 2020-08-16 Add support for C<< >>. See tests/pdfapi3.pl for an example how to use this to embed RTL texts. Note, however, that this currently relies on the native harfbuzz library to correctly determine ('guess') the characteristics of the text. Eliminated backend loading in favour of derived classes. Enable font caching for PDF::API2. 0.018.3 2020-05-19 Dropped testing with PDF::Builder. Text::Layout will continue to work with PDF::Builder to the extent that it is compatible with PDF::API2. 0.018.2 2020-05-09 Avoid testing PDF::Builder if it is of an incompatible version. As of 3.018 PDF::Builder changed the font metrics to incompatible values. 0.018.1 2020-02-27 0.018 2020-02-06 Add support for HB Shaper features. Requires HarfBuzz::Shaper 0.019 or later. 0.017 2020-02-03 Add helper routines for PDF::Builder. Add test file for PDF::Builder. 0.016 2020-01-30 Improve documentation for FontConfig and FontDescriptor. Add FontConfig and FontDescriptor to provides. 0.015 2020-01-29 Add font attributes in registration. 0.014.1 2020-01-26 0.014 2020-01-23 Experimental support for text shaping using HarfBuzz. Implemented for the PDF::API2/Builder backend only. Requires perl module HarfBuzz::Shaper. 0.013 2019-10-22 Fix test 102. Some more version issues. 0.012 2019-10-21 Fix some packaging problems. Fix version number in release. 0.011 2019-09-01 Fix return values of get*extent and get*size. Split off FontDescriptor from FontConfig. Added tests for PDF::API2 backend. Added lots of documentation. 0.01 2019-08-30 Initial check-in. Text-Layout-0.037/tests/0000755000400000040000000000000014640222611012660 5ustar jvjvText-Layout-0.037/tests/ab.jpg0000644000400000040000000000577314507251316013766 0ustar jvjvJFIFCreated with The GIMPICC_PROFILElcms@mntrRGB XYZ   4-acspAPPL-lcms desc @cprt`6wtptchad,rXYZbXYZgXYZrTRC gTRC bTRC chrm4$dmndX$dmdd|$mluc enUS$GIMP built-in sRGBmluc enUSPublic DomainXYZ -sf32 B%nXYZ o8XYZ $XYZ bparaff Y [chrmT|L&g\mluc enUSGIMPmluc enUSsRGBC     C   d2 v^-N3枧/M>h4[Ssv=%VT⯹<ջKXz0!H_ry^S[8z!HEuY^XYcVu6=$40 "$@ڳR>28ϋMJ f<5(eC49k{uwaZ8g9|`y(!R- )8 !1 q25AQar0B"#@?6`a =>֖<8wimC` }CCl*h)!rZuϑB/ME44?Q/f&%Uqe|S ừݩivْ@0! dۗ ~ %Hxaזyfn/ʭAΚx]B]!]q^ Rm<1(hogz 9JLQI ֞AI1bT0B>ԛts Y.хIb Ő=tcTp3LQB6fxܷr9?,-/0cqK%ʐУ{~W,  !13A0q"#@Q?a_TynoESUu[(JLR~;6hV%NorN!mN}<۱I~$:"n&Tt9lcR!kyZÄ"[ԧUU-zOВk`hKڊlb[~8d^W- ! "102ABQaqr#@R?Z"LqwT9Z9n3J/M]sD6 8.k!GsFUs7ℛ\Yh8JkZO?#gE1m3UX=,;w'_SD8|o<; EY1GsV5?Ǣ'!1 AQa0@q?!萣HESc(%=-$SQd086*? dU^_dI2XjU3y=ЋĊP$Ѫ:qhB;s!pNCԘ.w9k1$!1Q q0A@a?Z]6@stt8ʝq8߱ dr=P]U8 2L0׼қ q`ݟ1Q|dk;LߴS|e`C2c#4 #3̦/A۶p9BJbL{ۦEh@G*ТC ;t_3Text-Layout-0.037/tests/tl_p_02.pl0000644000400000040000000001063314640222607014464 0ustar jvjv#!/usr/bin/perl use strict; use warnings; use utf8; use PDF::API2; use lib "../lib"; use Text::Layout; use Text::Layout::FontConfig; eval { require HarfBuzz::Shaper } or warn("HarfBuzz::Shaper not found. Expect incorrect results!\n"); # Create document and graphics environment. my $pdf = PDF::API2->new(); $pdf->mediabox( 595, 842 ); # A4 # Set up page and get the text context. my $page = $pdf->page; my $text = $page->text; my $gfx = $page->gfx; # Create a layout instance. my $layout = Text::Layout->new($pdf); my $PANGO_SCALE = $layout->set_pango_mode("on"); # Setup the fonts. setup_fonts(); # Select a font. my $font = Text::Layout::FontConfig->from_string("Sans 33"); $layout->set_font_description($font); # Start... my $x = 0; my $y = 700; # Text to render. $layout->set_markup( q{ Áhe quick brown fox } ); # Left align text. $layout->set_width( 595 * $PANGO_SCALE ); $layout->set_alignment("left"); # Render it. showlayout( $x, $y ); $y -= 100; # Right align text. $layout->set_width( 595 * $PANGO_SCALE ); $layout->set_alignment("right"); # Render it. showlayout( $x, $y ); $y -= 100; $text->font( $font->{font}, 44 ); $text->translate( $x, $y-50 ); my $txt_nomarkup = q{Áhe quick brown fox}; my $dx = $text->text($txt_nomarkup); if ( $font->{font}->can("extents") ) { my $e = $font->{font}->extents( $txt_nomarkup, 44 ); printf( "EXT: %.2f %.2f %.2f %.2f\n", @$e{qw( x y width height )} ); $gfx->save; $gfx->translate( $x, $y-50 ); # PDF::API2 text is baseline oriented, so are the extents. # So we can draw the BB at the same origin as the text. $gfx->rect( $e->{x}, $e->{y}, $e->{width}, $e->{height} ); $gfx->linewidth(0.5); $gfx->strokecolor("cyan"); $gfx->stroke; $gfx->restore; } # Draw baseline. $gfx->save; $gfx->translate( $x, $y-50 ); $gfx->move( 0, 0 ); $gfx->line( $dx, 0 ); $gfx->linewidth(0.5); $gfx->strokecolor("magenta"); $gfx->stroke; $gfx->restore; $y -= 100; # Right align text. $layout->set_width( 595 * $PANGO_SCALE ); $layout->set_alignment("center"); # Render it. showlayout( $x, $y ); $y -= 100; # This will only work properly with the HarfBuzz driver. $font = Text::Layout::FontConfig->from_string("Deva 45"); $layout->set_font_description($font); $layout->set_width( 595 * $PANGO_SCALE ); # Nepali is LTR. $layout->set_alignment("left"); # This text consists of 6 characters but will render 4 glyphs. my $phrase = "\N{DEVANAGARI LETTER TA}". "\N{DEVANAGARI LETTER MA}". "\N{DEVANAGARI VOWEL SIGN AA}". "\N{DEVANAGARI LETTER NGA}". "\N{DEVANAGARI SIGN VIRAMA}". "\N{DEVANAGARI LETTER GA}". qq{ this should look like THIS}; $layout->set_markup($phrase); showlayout( $x, $y ); # Ship out. $pdf->saveas("tl_p_02.pdf"); ################ Subroutines ################ sub showlayout { my ( $x, $y ) = @_; $layout->show( $x, $y, $text); $layout->showbb($gfx); } sub setup_fonts { # Register all corefonts. Useful for fallback. # Not required, skip if you have your own fonts. my $fd = Text::Layout::FontConfig->new; # $fd->register_corefonts; # Add font dir and register fonts. $fd->add_fontdirs( $ENV{HOME}."/.fonts", "/usr/share/fonts/" ); $fd->register_font( "ITCGaramond-Light.ttf", "Garamond" ); $fd->register_font( "ITCGaramond-Bold.ttf", "Garamond", "Bold" ); $fd->register_font( "ITCGaramond-LightItalic.ttf", "Garamond", "Italic" ); $fd->register_font( "ITCGaramond-BoldItalic.ttf", "Garamond", "BoldItalic" ); # Make Serif alias for Garamond. $fd->register_aliases( "Garamond", "Serif" ); # Add a Sans family. $fd->register_font( "DejaVuSans.ttf", "Sans" ); $fd->register_font( "DejaVuSans-Bold.ttf", "Sans", "Bold" ); $fd->register_font( "DejaVuSans-Oblique.ttf", "Sans", "Italic" ); $fd->register_font( "DejaVuSans-BoldOblique.ttf", "Sans", "BoldItalic" ); # Add Devanagari. Requires shaping. # Note that Nepali is a LTR language. $fd->register_font( "lohit-devanagari/Lohit-Devanagari.ttf", "Deva", "", "", { shaping => 1, language => 'nepali' } ); my $o = { interline => 1 }; $fd->register_font( "Helvetica", "Sanss", "", "", $o ); $fd->register_font( "HelveticaOblique", "Sanss", "Italic", "", $o ); $fd->register_font( "HelveticaBold", "Sanss", "Bold", "", $o ); } Text-Layout-0.037/tests/pango03.pl0000644000400000040000000000325514640222607014476 0ustar jvjv#!/usr/bin/perl use strict; use warnings; use utf8; use Pango; use Cairo; require "./pango00.pl"; # subs # Create document and graphics environment. my $surface = Cairo::PdfSurface->create( 'pango03.pdf', 595, 842 ); # A4 my $cr = Cairo::Context->create($surface); my $layout = Pango::Cairo::create_layout($cr); # Scale from Cairo (PDF) units to Pango. my $PANGO_SCALE = Pango->scale; # Select a font. my $font = Pango::FontDescription->from_string('Amiri 45'); $layout->set_font_description($font); # Start... my $x = 0; my $y = 842-700; # Left align text. $layout->set_width( 595 * $PANGO_SCALE ); $layout->set_alignment("left"); # Arabic is RTL, so it comes out as right aligned. $layout->set_markup( q{برنامج أهلا بالعالم} ); showlayout( $cr, $layout, $x, $y ); $y += 100; # Typeset in three parts. Note that parts 1 and 3 will be ltr, # and part 2 will be rtl. $layout->set_markup("abc"); $x += showlayout( $cr, $layout, $x, $y ); $layout->set_markup( q{برنامج أهلا بالعالم} ); # Arabic is RTL, restrict to actual width to prevent unwanted alignment. my $dx = ($layout->get_size)[0]; $layout->set_width($dx); $x += showlayout( $cr, $layout, $x, $y ); $layout->set_markup("xyz"); $dx = ($layout->get_size)[0]; $layout->set_width($dx); showlayout( $cr, $layout, $x, $y ); # Typeset as one string, using . $x = 0; $y += 100; $font = Pango::FontDescription->from_string("Sans 45"); $layout->set_font_description($font); $layout->set_width( 595 * $PANGO_SCALE ); $layout->set_markup( "abc". "".q{برنامج أهلا بالعالم}."". "def" ); showlayout( $cr, $layout, $x, $y ); # Ship out. $cr->show_page; Text-Layout-0.037/tests/tl_c_03.pl0000644000400000040000000000544714640222607014457 0ustar jvjv#!/usr/bin/perl use strict; use warnings; use utf8; use PDF::API2; use lib "../lib"; use Text::Layout; use Text::Layout::FontConfig; eval { require HarfBuzz::Shaper } or warn("HarfBuzz::Shaper not found. Expect incorrect results!\n"); # Create document and graphics environment. my $pdf = PDF::API2->new(); $pdf->mediabox( 595, 842 ); # A4 # Set up page and get the text context. my $page = $pdf->page; my $text = $page->text; # Create a layout instance. my $layout = Text::Layout->new($pdf); # Select a font. setup_fonts(); my $font = Text::Layout::FontConfig->from_string("Amiri 60"); $layout->set_font_description($font); # Start... my $x = 0; my $y = 700; # Left align text. $layout->set_width(595); $layout->set_alignment("left"); # Arabic is RTL, so it comes out as right aligned. $layout->set_markup( q{برنامج أهلا بالعالم} ); showlayout( $x, $y ); # Typeset in three parts. Note that parts 1 and 3 will be ltr, # and part 2 will be rtl. # Note, however, that this currently relies on the native # harfbuzz library to correctly determine ('guess') the # characteristics of the text. $y -= 100; $layout->set_markup("abc"); $x += showlayout( $x, $y ); $layout->set_markup( q{برنامج أهلا بالعالم} ); # Arabic is RTL, restrict to actual width to prevent unwanted alignment. $layout->set_width( ($layout->get_size)[0] ); $x += showlayout( $x, $y ); $layout->set_markup("xyz"); showlayout( $x, $y ); # Typeset as one string, using . $x = 0; $y -= 100; $font = Text::Layout::FontConfig->from_string("Sans 60"); $layout->set_font_description($font); $layout->set_markup( "abc". "".q{برنامج أهلا بالعالم}."". "def" ); showlayout( $x, $y ); # Ship out. $pdf->saveas("tl_c_03.pdf"); ################ Subroutines ################ my $gfx; sub showlayout { my ( $x, $y ) = @_; $layout->show( $x, $y, $text); my $dx = ($layout->get_size)[0]; $gfx //= $page->gfx; $layout->showbb($gfx); return $dx; } sub setup_fonts { my $fd = Text::Layout::FontConfig->new; # Add font dir and register fonts. $fd->add_fontdirs( $ENV{HOME}."/.fonts", "/usr/share/fonts/" ); # Add a Sans family. $fd->register_font( "FreeSans.ttf", "Sans" ); $fd->register_font( "FreeSansBold.ttf", "Sans", "Bold" ); $fd->register_font( "FreeSansOblique.ttf", "Sans", "Italic" ); $fd->register_font( "FreeSansBoldOblique.ttf", "Sans", "BoldItalic" ); # Add Devanagari (Indian). Requires shaping. $fd->register_font( "lohit-devanagari/Lohit-Devanagari.ttf", "Deva", "", "", { shaping => 1 } ); # Add Amiri (Arabic). Requires shaping. $fd->register_font( "amiri/amiri-regular.ttf", "Amiri", "", "", { shaping => 1, nosubset => 1, } ); } Text-Layout-0.037/tests/im1.pl0000644000400000040000000000736614640222607013724 0ustar jvjv#!/usr/bin/perl use strict; use warnings; use utf8; binmode( STDOUT => ':utf8' ); binmode( STDERR => ':utf8' ); use PDF::API2; use lib "../lib"; use Text::Layout; use Text::Layout::FontConfig; # Create document and graphics environment. my $pdf = PDF::API2->new(); $pdf->mediabox( 595, 842 ); # A4 # Set up page and get the text context. my $page = $pdf->page; my $text = $page->text; my $gfx = $page->gfx; # Create a layout instance. my $layout = Text::Layout->new($pdf); # Setup the fonts. setup_fonts(); # Select a font. my $font = Text::Layout::FontConfig->from_string("Sans 45"); $layout->set_font_description($font); $layout->register_element ( TextLayoutImageElement->new( pdf => $pdf ), "img" ); # Start... my $x = 0; my $y = 730; #=for later # Text to render. $layout->set_markup("abcdef"); showlayout( $x, $y ); $layout->set_markup("abcdef"); showlayout( $x+300, $y ); $y -= 150; $layout->set_markup("abcdef"); showlayout( $x, $y ); $layout->set_markup("abcdef"); showlayout( $x+300, $y ); $y -= 150; $layout->set_markup("abcdef"); # Render it. showlayout( $x, $y ); $y -= 150; #=cut # Make a non-zero origin object. my $xo = $pdf->xo_form; $xo->fill_color("lime"); $xo->stroke_color("green"); $xo->linewidth(2); $xo->bbox( -10, -10, 30, 70); $xo->transform( translate => [ -10, -10 ] ); $xo->rectangle(0,0,40,80); $xo->fill; $xo->move(10,0)->vline(80)->stroke; $xo->move(0,10)->hline(40)->stroke; my $dd = ""; $layout->set_markup("abcdef"); showlayout( $x, $y ); $layout->set_markup("abcdef"); showlayout( $x+300, $y ); $y -= 150; $dd = "dx=10 dy=10"; $layout->set_markup("abcdef"); showlayout( $x, $y ); $layout->set_markup("abcdef"); showlayout( $x+300, $y ); $y -= 150; $pdf->saveas("pdfapi2.pdf"); ################ Subroutines ################ sub showlayout { my ( $x, $y ) = @_; $y -= $layout->get_baseline; $layout->show( $x, $y, $text); $layout->showbb($gfx); } sub setup_fonts { # Register all corefonts. Useful for fallback. # Not required, skip if you have your own fonts. my $fd = Text::Layout::FontConfig->new; # $fd->register_corefonts; $fd->add_fontdirs( $ENV{HOME}."/.fonts", "/usr/share/fonts/" ); $fd->register_font( "ITCGaramond-Light.ttf", "Garamond" ); $fd->register_font( "ITCGaramond-Bold.ttf", "Garamond", "Bold" ); $fd->register_font( "ITCGaramond-LightItalic.ttf", "Garamond", "Italic" ); $fd->register_font( "ITCGaramond-BoldItalic.ttf", "Garamond", "BoldItalic" ); # Make Serif alias for Garamond. $fd->register_aliases( "Garamond", "Serif" ); # Add a Sans family. $fd->register_font( "DejaVuSans.ttf", "Sans", "", { shaping => 0 } ); $fd->register_font( "DejaVuSans-Bold.ttf", "Sans", "Bold" ); $fd->register_font( "DejaVuSans-Oblique.ttf", "Sans", "Italic" ); $fd->register_font( "DejaVuSans-BoldOblique.ttf", "Sans", "BoldItalic" ); # Add a Sans family. $fd->register_font( "calibri.ttf", "Cal", "", ); $fd->register_font( "calibrib.ttf", "Cal", "Bold" ); $fd->register_font( "calibri.ttf", "Cal", "Italic" ); $fd->register_font( "calibrii.ttf", "Cal", "BoldItalic" ); } ################ Classes ################ use Object::Pad; class TextLayoutImageElement :isa(Text::Layout::PDFAPI2::ImageElement); method getimage ($fragment) { $fragment->{_img} //= do { if ( $fragment->{src} eq "xo" ) { $xo; } else { $pdf->image($fragment->{src}); } }; } 1; Text-Layout-0.037/tests/tl_c_01.pl0000644000400000040000000001045614640222607014451 0ustar jvjv#!/usr/bin/perl # This is an example of using Text::Layout to create the same document # as native Pango. # # This example uses Text::Layout in Pango conformance mode. The # relevant parts of this program and its Pango counterpart are very # much the same. use strict; use warnings; use utf8; use lib "../lib"; use PDF::API2; use Text::Layout; # Create document and graphics environment. my $pdf = PDF::API2->new( file => 'tl_c_01.pdf' ); $pdf->mediabox( 595, 842 ); # A4 # Set up page and get the text context. my $page = $pdf->page; my $text = $page->text; my $gfx = $page->gfx; # Create a layout instance. my $layout = Text::Layout->new($pdf); # Tell Text::Layout that we are running in convenience mode. # my $PANGO_SCALE = $layout->set_pango_mode(0); # default my $PANGO_SCALE = $layout->get_pango_scale; # Scale from Cairo (PDF) font size to Pango. my $PANGO_FONT_SCALE = 1 * $PANGO_SCALE; # Font sizes used, scaled. my $realfontsize = 60; my $fontsize = $realfontsize * $PANGO_FONT_SCALE; my $tinysize = 20 * $PANGO_FONT_SCALE; sub main { # Select a font. my $font = Text::Layout::FontConfig->from_string("freeserif 12"); $font->set_size($fontsize); $layout->set_font_description($font); # Start... my $x = 0; my $y = 500; # PDF goes up # Text to render. # Text to render. my $txt = qq{ Áhe quick }. # $tinysize = 20 for a 20pt font. qq{brown }. # rise is in points qq{fox}. # 170.667/1024 units of a 60pt font = 10pt. qq{x}. # size=60pt for a 60pt font. qq{x }; my $txt_nomarkup = "Áhe quick brown fox "; $layout->set_markup($txt); # Left align text. $layout->set_width( 595 * $PANGO_SCALE ); $layout->set_alignment("left"); # Render it. showlayout( $x, $y ); $y -= 100; # Right align text. $layout->set_width( 595 * $PANGO_SCALE ); $layout->set_alignment("right"); # Render it. showlayout( $x, $y ); $y -= 100; # Plain PDF::API2, no Text::Layout. $text->font( $font->{font}, $realfontsize ); # PDF::API2 text is baseline oriented. $text->translate( $x, $y-50 ); my $dx = $text->text($txt_nomarkup); if ( $font->{font}->can("extents") ) { my $e = $font->{font}->extents( $txt_nomarkup, $realfontsize ); printf( "EXT: %.2f %.2f %.2f %.2f\n", @$e{qw( x y width height )} ); $gfx->save; $gfx->translate( $x, $y-50 ); # PDF::API2 text is baseline oriented, so are the extents. # So we can draw the BB at the same origin as the text. $gfx->rect( $e->{x}, $e->{y}, $e->{width}, $e->{height} ); $gfx->linewidth(0.5); $gfx->strokecolor("cyan"); $gfx->stroke; $gfx->restore; } # Draw baseline. $gfx->save; $gfx->translate( $x, $y-50 ); $gfx->move( 0, 0 ); $gfx->line( $dx, 0 ); $gfx->linewidth(0.5); $gfx->strokecolor("magenta"); $gfx->stroke; $gfx->restore; $y -= 100; # Right align text. $layout->set_width( 595 * $PANGO_SCALE ); $layout->set_alignment("center"); # Render it. showlayout( $x, $y ); # Ship out. $pdf->save; } ################ Subroutines ################ sub showlayout { my ( $x, $y ) = @_; $layout->show( $x, $y, $text); $layout->showbb($gfx); } sub setup_fonts { $^O =~ /mswin/i ? setup_fonts_windows() : setup_fonts_linux(); } sub setup_fonts_linux { my $fd = Text::Layout::FontConfig->new; # Add font dir and register fonts. $fd->add_fontdirs( $ENV{HOME}."/.fonts", "/usr/share/fonts/" ); for ( "", qw( Bold Italic BoldItalic ) ) { $fd->register_font( "FreeSerif$_.ttf", "freeserif", $_, { shaping => 0 } ); } } sub setup_fonts_windows { my $fd = Text::Layout::FontConfig->new; # Add font dir and register fonts. $fd->add_fontdirs( "C:\\Windows\\Fonts" ); $fd->register_font( "georgia.ttf", "freeserif", "" ); $fd->register_font( "georgiab.ttf", "freeserif", "bold" ); $fd->register_font( "georgiai.ttf", "freeserif", "italic" ); $fd->register_font( "georgiaz.ttf", "freeserif", "bolditalic" ); } ################ Main entry point ################ # Setup the fonts. setup_fonts(); # Run... main(); Text-Layout-0.037/tests/pango01.pl0000644000400000040000000000420314640222607014466 0ustar jvjv#!/usr/bin/perl # This example created a PDF document using pure Pango. This is # intended to be a reference for the documents created by the # tl_p_01.pl test programs. use strict; use warnings; use utf8; use Pango; use Cairo; require "./pango00.pl"; # subs # Create document and graphics environment. my $surface = Cairo::PdfSurface->create( 'pango01.pdf', 595, 842 ); # A4 my $cr = Cairo::Context->create($surface); my $layout = Pango::Cairo::create_layout($cr); # Scale from Cairo (PDF) units to Pango. my $PANGO_SCALE = Pango->scale; # Scale from Cairo (PDF) font size to Pango. my $PANGO_FONT_SCALE = 0.75 * $PANGO_SCALE; # Font sizes used, scaled. my $realfontsize = 60; my $fontsize = $realfontsize * $PANGO_FONT_SCALE; my $tinysize = 20 * $PANGO_FONT_SCALE; # Select a font. my $font = Pango::FontDescription->from_string('freeserif 12'); $font->set_size($fontsize); $layout->set_font_description($font); # Start... my $x = 0; my $y = 842-500; # Cairo goes down # Text to render. my $txt = qq{ Áhe quick }. # $tinysize = 15360 for a 20pt font. qq{brown }. # rise is in 1/1024 units. qq{fox}. # 10240/1024 units = 10pt. qq{x}. # size=45pt for a 60pt font. qq{x }; my $txt_nomarkup = "Áhe quick brown fox "; $layout->set_markup($txt); # Left align text. $layout->set_width( 595 * $PANGO_SCALE ); $layout->set_alignment("left"); # Render it. showlayout( $cr, $layout, $x, $y ); $y += 100; # Right align text. $layout->set_width( 595 * $PANGO_SCALE ); $layout->set_alignment("right"); # Render it. showlayout( $cr, $layout, $x, $y ); $y += 100; # Plain Cairo, no Pango. $cr->select_font_face( "freeserif", "normal", "normal" ); $cr->set_font_size($realfontsize); $cr->move_to( $x, $y+50 ); $cr->show_text($txt_nomarkup); $y += 100; # Right align text. $layout->set_width( 595 * $PANGO_SCALE ); $layout->set_alignment("center"); # Render it. showlayout( $cr, $layout, $x, $y ); # Ship out. $cr->show_page; Text-Layout-0.037/tests/Lohit-Devanagari.ttf0000644000400000040000000045660414434450771016547 0ustar jvjv FFTM|c,GDEFTWHGPOS@d ,GSUBA2M OS/2њ `cmapEjg! Pcvt  ]Nfpgmb2N gaspMglyfh%\nhead6hhea%$hmtxg( locagDmaxpPY# namegb#post?`*# prepO\.A9ܿ+  *0134abbcjkkllmmnop~$%&'89HIJKKL`afg \zDFLTdev2deva8MAR NEP MAR NEP abvmblwm "  N H "(.4:@FLRX^djpv| $*06<|2B=D-<'z-L/e)bO2L:|D8D8J'Wv476n?rNRY !  d R<yd7H<FGJLPQRSTW\`dejLMTZ\]^_abcdefhlmnoprsuwxyz{|} rstu~GH 28>DJPV\bhntq=~E2~E*s%v"y?:N>T  &,Lf>rstu ` "(.4:@FLRX^djpv| $*06<BHNTZ`flrx~|yC }TX[+KOU"@[{|TBCaU"6<@ADj 09:=?A CLLETTF\_GafKQRSY[\13kkvy  % &,28>DJPV\bhn{{yNqwwm~wwwwww}wwwww}lVr  &,28>DHpj44f44 3qvwxy{|}L DFLTdev2 devaMAR .NEP N    MAR .NEP N    abvsVakhn\blwfbblwshcjctnhalfthalnzloclloclnuktprespstsrphfvatu    !" $JRZbjrz $,4<DLTbj(8BL 0  4 h ~     8 < j n  nDj~W cgN(>J0F$^~\~F`~Y"*2:f~F~he~_d~Ic~Hb~Ga~Fh~fg~K8~O~i~Mk~Mj~K "o~fn~`m~Ql~Pq~`p~Qt~`s~Sr~Rv~`u~S &.6>FNV^~f~`~~_}~^|~]{~Yz~Xy~Wx~Iw~H~Y~U~ (08@~f~~`~_~Y~TZ~a~ "~f~~Y~KFHJKMOPQRSWY[\jHasGar~ N~aF &0:DNXblvmmmmmmZmmmbmem FGHMRSY\`ad" ~h ~OFM~a*  ~Zaaj~</dnx",6@JT^hr~ (2 ~ ~ ~ ~~~~~~~~~~~~~~~~~~~ ~!~"~#~$~K~'~(~)~*~+~,~-~.~/~0~1~2~3~7~8~5~~'~~Facj$( )QQ+UU,-!HR\fpz$.8BLV`jt~LMNOP5~QRST~UVWXYZ5a!FGHIKMNOTUVWXY[\]^_`cfghij !4 r &.6>FNV^~f~`~~_}~^|~]{~Yz~Xy~Wx~Iw~H~`~`WzH6Jdn &8J4>~a[t^c]U\F`Y &,fe_dIcHbGaFgKhf iM kMjK ofn`mQlP q`pQt`sSrR v`uS 6U "(.4:@FLf`~_}^|]{YzXyWxIwHYUcc fcYK QPQ &,fc`_YT[tag   '+,-.p Gc 1MYipabppp    $'-/0!28#JJ*nn+qq,tt-vv./0ppIJKRUX`abcdefghrsxzSpp LTV^deg VJpp MNOiOPjk~Ip0Lh;3:93333&3?3>=3333333p%<,Hd333333333xy|}Z &@;:93BA@3FED3pqC2  tt HsGrWjq@AB <F\T\]^_CFEFq@AB rsa K~Kbb~`  b~j  `  j   &#%&*j%&b bCM # BACE a F*\@~#+HM[eks~7&  & 0 : D !!&!.""""+"H"e%̨  '.LP^jnx7&   0 9 D !!"!.""""+"H"d%ʨi`P' p1ߨߌqR4TV\djlp   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`apcdhvnjtiqfu0kzbml{w&,o()*x-+'"@c_N+7!!!fCC\d,@)_3M_2N +7353ycGUii2!*@'W_O +'33'3@QYQ!)G@D   hg  1M2N +3#33733737#737#7##7#3#ww+xx=?==?=xx+yx=?==?=-+:::::Z")0D@A.'  "La1Ma2N-,&% +372654.'77&'7#"&'7#7463.2lx7)"9$34T2bo6/'>$33ZQG=?I=46XK#9%" 1$G^P&:*<$S0985?32 '+@@=ij1Ma7M 2Ma8N+* +2654&"462"&2654&"462"&#32G~GG~G8)J**J)+G~GG~G8)J**J)}2p2S__ST__T=DD=/Rh>UTEKX']=ReVF7Y9H+43LB#I2!@W_O +'3@Q!d$ .K!PX@ 6N@ vY@  +&54732djjdPjrrjw.wd$n .K!PX@ 6N@ vY@  +654'3daggaBbffbt  tttF2+'777'''7FUG44GVTG44GSgn(~*mQl(*lP} &@#Wg_O +#53533##<</<<i@v +735add%Qn@W_O +5!d%IIKi@_2N +353KUiidL=v@v +3dPw*7@a7Ma8N +662"26&"7{||7WXXD J > LK+PX@1M_2N@_2NY +733!53J&iH^<<JP&@#La7M_2N#+ +)54>54&#"'632!]&>JJ>&I=e43E\nDddMb(5V;402E)7BM$ebS?eEAW56!9@6 Lia7Ma8N#)#$ +2654&#"'632#"'732654&#]rG;Z52C~[kE>ubJ38lCPiniQA3=@$X]O7X$Wfj$RF;DA- +@(LJg4M2N +7!33##5!-DB<FYRA@L_1M2N +#!5!Ir^<@$/*@'+La7Ma8N&%#" +2"&5467.544.'26">54úk<6AIyyI@6;d2-%%-2UU_zGCAAC]P~b\r?8CXQAI[TKLK%PX@_4M_2N@g_2NY@ +35353KUUUii}iiWK%PX@_4N@W_OY@ +5373KU5ad}iiP2+%5%X`M?B?P0@-gW_O +!5!5``<<<<P2+7-5PW`?B<@9 La9M_2N#( +74>54&#"'63253"0/"I=W-3=z\n$33$GU2M0->'7BD$\bS.H1/B)ii7d,7@ 0/ !"LK+PX@2   iiea9M4M a: N@0i   iie4M a: NY@.-31-7.7$#$"##" +#"&'#"&46325332654& 327#"&54632275&#"dgF2E7PQ`fVH39G,=njWR!bhMQ1+M9E?;t9<@kk-!]h[ʎ.66Q@N@AM  ,@) Lh1M2N  +#'##35B;:B:kffed<@9 Lg_1M_2N(1" +%+;2%3264&#3264&#q_By^rg:A@LL@y@LL@Vf_Pf(TEFtF"?h?<1@.La7Ma8N  +"327#"&632&2QaaQh73KppH35iY$sxyyxEeXYeeYX,5D d8@5 Lg_1M2N!1 +3;2#+3264&#dBefyIBIeeGTTGlZEb^K~K2!(@% La7Ma8N#*#( +%4.54632&#"#"'7326EbbEk[|E33[;GEbbEr_G36h@M/A),S=Sba$IB7.<&,WBN\s$[< @_1M2N +###5!B^^<U@1Ma8N +62653"&53UByyB1[L>i||i>L !@L1M2N +333BBef  '@$ L1M2N  +3# #3B^~}^B^f:^ &@# L1M2N  +3# #gIII SG#@ L1M2N +3533EEW`- )@&L_1M_2N + !!5!5!BiMr<(6<d%(@%gW_O +3#3dIId,@v +#3DDd%(@%gW_O +53#53dxxI)IERdD@v +D#3# BHBNd,&dD@W_O +D5!dDDHedD@v +D#'3e1\WH<"G@D Lia:M2Ma8N""#$$! +%#"&5463254&#"'632#'275&#"w9ORaaRJ9?4N03?rSb=R21S4<<4AYJKX+C5?B!]`P/PJ48^8Z 7@4 L3Ma:M2Ma8N###" +3632#"'#73264&#"ZB:QXgn\P5=BE,>IC9X4=:-*0nnW2'@$ La:Ma8N###! +%#"&4632&#"327=lZjjZh95&F;GG;K)JWN#5nn>2 7@4 L3Ma:M2Ma8N#"#" +!#5#"&463253&#"327=IC9Y35B,EnnW2@@=Lga:Ma8N  +"&4632!327"!.^oo^[kJ=Q-5@s8I G n&VdD#]UKJV#[3@0La9M_4M2N## +354632&#"3####DLF9)-PBD0PU9g0IC9Y3&U_m"Q=9c=ry;.*0n]VgWZ(@% L3Ma:M2N"" +!#4#"#3632Bg\1BB;RSVXmR>WRM @a9M4M2N +3#3&462"BBO&&&&' /@,La9M4Ma<N## +##"'3265264&"B)*&G7@O&&" $8B9&&d *@' L3M4M2N  +3373#'dBPM5Q=Z@3M2N +3#3BBZ/@, L4Ma:M2N"""" +!#4#"#3632632#4#"B_T-B=8Mk%;WOSB_U.XmO3@OOWRXmQ Z(@% L4Ma:M2N"" +!#4#"#3632Bg\1B=IC9X46C,@EnnW23 7@4 L4Ma:Ma8M6N###" +#5#"&463253.#"327B:QXgn\O6=BE+>IC9Y3=;.*0nnWZK *@' L4Ma:M2N" +'"#3632@\+B=9TgFS- (@% La:Ma8N#*#( +$4.54632&#"#"'732=5LM5XJd;2(E,45ML5[Ll?2,M.WB-"@/AMR"8,& *!C2=H_"E#KX3@0 L_4Ma8N## +3533#327#"&5##DB)*'F7@Ddd<" $8B9JP(@% L4M2Mb8N"" +33273#5#"5PBg\1B=K!@L4M2N +333CCE  '@$ L4M2N  +3# #3~i|C[\[[C|iJ vJ &@# L4M2N  +73#'#'dxwGH|zG& @ I4N +33'>7CC<9KO%G4F5# )@&L_4M_2N + !!5#5! Rq<(<d>YLK-PX@iia6N@ iiYaQY@  +26=463"3"&=4&#d)#WHdnH">@;Lga7M_2N""#$ +&54632&#"3#!!57>54'#5gZ83-[9A 2G]  UaN@;L  hg1M2N! +333#3##5#53'#5sEEsr0B1W2m22n2d/@,gW_O +33dBBB&&>4;%"ʏdet88^7&7MN1 ʏʐN+47"@ LK$PX@#iaIMJMaLNK*PX@ ieaIMJN@#ieaINYY@""#$$" +#5#"&5463254&#"'632275&#"74)75CE:/')"2#*,S;G8$2!''='A45@#")/FD:12!$<$2]  2+'57'57m,,5,,/(.((.(Pk@W_O +!5!#:/<(  )\dD@QL i   igYaQ!!!)!($"  !"$ +D462#"&6264&"32#'+532654&#(ʏdeO.97E1A## ede/&9qii\-z8 dD@W_O +D!5!8 z:<R*dD@iYaQ +D462"&264&"54&#"'6323&/;,$!2+-N6@-;CI-@%')=5-$6$*# B9@6 LiaIMaLN#(#$ +2654&#"'632#"'732654#m2= ,+,J5?END9O2+ 6&s !"73+3>/7?+7FHdD@v +D3#|W\1P32@/ L4M2Ma8M6N"" +353273##"5#P=$HV<=B1\gB'K>`mX @_1M2N #! +!#"&46;#<\mm\4aafK@W_O +53L]ss/:dD@/ LYbR  +D"'73254'73u: " A, *5*( ! fG*!/1I "@ LIM_JN +733#5351#FR_w011"&4J ;K$PX@aIMaLN@eaINY$$" +4632"&632654&#"&MDENOM70*+11+*WccWVcc~GH>?H2]  2+75'75',,5,,/(.((.(1ZdD@O  L    hWh_O +D%73533##5##3733#535t8ky7722ͅ#FR_p ԇ0MMM#011"1(QdD@F(' L hjW_O&%#) +D#5467>54&#"'6323#3733#535/;,$!2+-N6@-;C!22#FR_-@%')=5-$6$*#0#011" 2tdD@i # +*  L   i  i  iWh_O21.,)' +D%73533##5##32654&#"'632#"'732654#t8ky77222= ,+,J5?END9O2+ 6&sp ԇ0MMM!"73+3>/7?+7(&<@9 L_4Mb<N#( +327#"&54>57#5"0/"I=W-3=z\n$33$GU2M0->'7BD$\bS.H1/B)ii  8@5Lh1M2N    +#'3#'##3"1\WIB;:B:kަffe  8@5Lh1M2N    +3##'##3W\1ZB;:B:kDffe >@;Lh1M2N +#'#73#'##31QQ1YR B;:B:kooffe XL@ILJiih 1M2N!#!! +#"&#"'632327#'##3%<I#$<I%KB;:B:k83 3ffe [:@7Lih 1M2N +462"6462"#'##3q&&&&B;:B:k&&&&fffe @@=Liih 1M2N +"&462264&"#'##3+P99P9w,,gB;:B:k8N99N ,,}ffe;@8L g_1M_2N +##!!!!!!]Dh *<<<Z @;LJii1M2N!#!! +#"&#"'6323273##3%<I#$<I%BdBd83 3WfW<? +@(a7Ma8N#### +#'3632#"326&#"\1\WxyyxEeXYeeYXަ'D <? +@(a7Ma8N#### +3#632#"326&#"AW\1ωxyyxEeXYeeYXD <?3@0La7Ma8N#### +#'#73632#"326&#"1QQ1YR։xyyxEeXYeeYXoo&D <?X#A@>LJiia7Ma8N###$!#!! +#"&#"'632327632#"326&#"%<I#$<I%xyyxEeXYeeYX83 3SD <?[#-@*ia7Ma8N#### +462"6462"632#"326&#"&&&&xyyxEeXYeeYX&&&&D b 2+'7'77 ++++"++++<? WKPX@!pqa7Ma8N@a7Ma8NY@ #### +#3632#"326&#"77xyyxEeXYeeYXdbD U'@$1Ma8N +#'32653"&53[1\W9UByyBަ[L>i||i>LU'@$1Ma8N +3#2653"&53@W\1UByyBS[L>i||i>LU/@,L1Ma8N +#'#732653"&531QQ1YRpUByyBoo[L>i||i>LU[)@&i1Ma8N +462"6462"2653"&53&&&&UByyB&&&&1[L>i||i>L /@, L1M2N   +3#533W\1EE"W`d 4@1gg1M2N   #! +3332+3264&#dBofyyfooGTTG}qq}QQ_,9@6La7M2Ma8N,, +"'732654.54654&#"#4632SX1 ,=6B**E628?BdUQ[$$,+f )14*)0 &e%.2HA[jSI&C3 #8#FT<&S@P Lia:M2M a8N#!&&#$$" +#'3#"&5463254&#"'632#'275&#"41\Wy9ORaaRJ9?4N03?rSb=R21S4<<HFAYJKX+C5?B!]`P/PJ48^8<&S@P Lia:M2M a8N#!&&#$$" +3##"&5463254&#"'632#'275&#"$W\19ORaaRJ9?4N03?rSb=R21S4<<AYJKX+C5?B!]`P/PJ48^8<)Y@V #" L  ia:M2M a8N! &$ )!)#$$" +#'#73#"&5463254&#"'632#'275&#"1QQ1YRL9ORaaRJ9?4N03?rSb=R21S4<<HooEAYJKX+C5?B!]`P/PJ48^8<(2k@h!  ,+ LJ  ia3Ma7Ma:M2M  a8N*)/-)2*2#$$#!#!! +#"&#"'632327#"&5463254&#"'632#'275&#"%<I#$<I%9ORaaRJ9?4N03?rSb=R21S4<<3 3rAYJKX+C5?B!]`P/PJ48^8<(2W@T!  ,+ L  ia9Ma:M2M  a8N*)/-)2*2#$$" +462"6462"#"&5463254&#"'632#'275&#"p&&&&$9ORaaRJ9?4N03?rSb=R21S4<<&&&&AYJKX+C5?B!]`P/PJ48^8<(2[@X!  ,+ Lii  ia:M2M  a8N*)/-)2*2#$$$ +"&462264&"#"&5463254&#"'632#'275&#"*P99P9w,,9ORaaRJ9?4N03?rSb=R21S4<<88N99N ,,AYJKX+C5?B!]`P/PJ48^8<$/6_@\'#"L  g a:M a 8N10&%430616+)%/&/! $$ +"'#"&546;54&#"'632632!327%27&'#""!.6n8DfN\dUt?4H-3;mq/7i[kK>Q-5@<\9u6@89I G __SEGS,5?B!]WWn&VdD#]2L@ILg a:Ma8N  +#'3"&4632!327"!.1\W^oo^[kJ=Q-5@s8I GHn&VdD#]UKJV2L@ILg a:Ma8N  +3#"&4632!327"!.W\1^oo^[kJ=Q-5@s8I Gn&VdD#]UKJV2R@OLg a:Ma 8N  +#'#73"&4632!327"!.1QQ1YR(^oo^[kJ=Q-5@s8I GHoon&VdD#]UKJV2!(P@M L  ga9M a:Ma 8N#"&%"(#(!! +462"6462""&4632!327"!.l&&&&P^oo^[kJ=Q-5@s8I G&&&&n&VdD#]UKJV @4M2N +#'3#31\W9BBHZ@4M2N +3##3W\15BB '@$L4M2N +#'#73#31QQ1YRBBHoo #@ a9M4M2N +462"6462"#3&&&&0BB&&&&2'k@  LKPX@a9Ma4Ma8N@ia9Ma8NY@ #$#(#& +&'57&#"'6327#"&46323264&#"}vW)786;P\>dGFna`mm`L+JACKKCAU6$3,!.)N4t4ldddZ L@ILJa3Ma7M4Ma:M2N""!#!! +#"&#"'632327#4#"#3632%<I#$<I%:Bg\1B=XmR7DWR2 +@(a:Ma8N#### +#'34632#"3264&#"1\Wm`anna`+JABKKBAHflll2 +@(a:Ma8N#### +3#4632#"3264&#"!W\1m`anna`+JABKKBA7flll23@0La:Ma8N#### +#'#734632#"3264&#"1QQ1YRm`anna`+JABKKBAHooflll2#E@BLJa3Ma7Ma:Ma8N###$!#!! +#"&#"'6323274632#"3264&#"%<I#$<I%m`anna`+JABKKBA3 3flll2#/@,a9Ma:Ma8N#### +462"6462"4632#"3264&#"n&&&&m`anna`+JABKKBA&&&&flllPZ@ @@=ggW_O   +75353!5UUU`Zii}iil<<2@ +@(a:Mb8N#### +#34632#"3264&#"77m`anna`+JABKKBAJ?flllP4@1 L4M2Mb8N"" +#'333273#5#"5/1\WBg\1B=KP4@1 L4M2Mb8N"" +3#33273#5#"52W\1Bg\1B=KP:@7 L4M2Mb8N"" +#'#7333273#5#"51QQ1YRBg\1B=KP8@5La9M4M2Mb8N"" +462"6462"33273#5#"5&&&&Bg\1B=K&"@ I4N +3#33'>7W\1CC<9KTO%G4F5Z3 ?@< L3Ma:Ma8M6N #" +632#"'#3264&#":QXgn\K5BB-T>IC9X4=,EnnW&&@#Ia9M4N +462"6462"33'>7d&&&&CC<9K&&&&vO%G4F5 J 3@0h1M2N    +#37337!5!k:B:;BT efv:< "&@"LK PX@.pia:M2M a8N@-ia:M2M a8NY@&%$#!   +7"&463234&#"632&#"327!5!4<<4S127=bSr?30N4?9JRaaRO9 /8^84JP/QP`]!B?5C+XKJYAF: a @@= ih 1M2N      +#3733'"'#267#k:B:;B2C3HtH3efzM>KK>M< "-@"LK!PX@2   ii 3Ma:M2M a8N@2    iia:M2M a8NY@!$#,+)(&%#-$-!   +7"&463234&#"632&#"327"'#267#4<<4S127=bSr?30N4?9JRaaRO9uC3HtH3/8^84JP/QP`]!B?5C+XKJYAJM>KK>M =@@=LKh1M2Ma6N#' +#373327'#"&54673k:B:5?&)7/F(!2/-Befį  4+12,,7 <9+5W@T43!"L+Kia:Ma8Ma6N-,20,5-5($$#*! +#"&5467=4&#"632&#"327327%"&4632!2/-bSr?30N4?9JRaaRO9(7/F(4<<4S12i,7 ?P`]!B?5C+XKJYA2 4+128^84JP<m@ LKPX@!pa7Ma8N@ a7Ma8NY@  +27&#"327'#"&63#2`53HppK37hQaakW\1iL$fļs$Y2_ LKPX@ pa:Ma8N@a:Ma8NY@ ###! +%#"&46327&#"3273#j)K;GG;F&59hZjjZl=W\1m>nn5#NW<u@  LKPX@"pa7Ma8N@!a7Ma8NY@  +27&#"327'#"&6373#2`53HppK37hQaa/1QQ1YRiL$fļs$Yoo2g@  LKPX@!pa:Ma8N@ a:Ma8NY@ ###! +%#"&46327&#"327373#j)K;GG;F&59hZjjZl=1QQ1YRm>nn5#NWood5mLKPX@"p_1M_2N@!_1M_2NY@  +2+&+32373#3VhhVvv1QQ1YR^"W0foo2i F@C  L3Ma:M2Ma8N#"#! +%#"&4632#&#"32733#|3Y9CI>T-BB5K\ngXT<=TW\1WnnE<,B5ڧ5 6@3g_1M_2N   !" +$&+#3322+535#55vJJvvVhhVɵ06^62 F@C  Lg3M a:M2Ma8N"#" +##3&#"327335##"&4632B5K\ngXT<=KKB3Y9CI>T-D6m,B5B6WnnEdJ hK PX@(pg_1M_2N@'g_1M_2NY@  +!5!!5!!5!!5! l  ^27'#"&'!54&#"!5!7GI8s@5-Q=JQk[^oo VJKU.]#DdV&n:db 3@0ig_1M_2N +!5!!5!!5!264&" l c,,^27'#"&'!54&#"264&"7GI8s@5-Q=JQk[^ooG,,VJKU.]#DdV&np,,d=C@@LKg_1M_2Ma6N#& +!5!!327'#"&5467=!!5!  (7/F(!2/- ^h!2R35-Q=JQk[^o8/M (7/F(7GIi, I#DdV&nH= 4+12ZVJKUd rLKPX@)pg_1M_2N@(g_1M_2NY@  +!5!!5!!5!373# l 1QQ1YR^27'#"&'!54&#"373#7GI8s@5-Q=JQk[^oo%1QQ1YRVJKU.]#DdV&noo<a$V@S L    iga7M2Ma8N#" $$###" +#3#"&6327&#"3273"'#267#ۙ3^Qal[Z3+Bwzp^9=C3HtH3EKK>M2& $/@ LK!PX@3   i 3M4Ma:Ma2Ma<N@3    i4Ma:Ma2Ma<NY@&%.-+*('%/&/#$$"$! +%#"&546327#&#"327#"'3265"'#267#|3Y9CI>+EB=6O\nhWQ:=8Z*6=}VaC3HtH3WgV]n0*.;yr=c9=Q"m_UM>KK>M<,@  LK'PX@-rga7M2Ma8N@.ga7M2Ma8NY@ ###" +#3#"&6327&#"32733#ۙ3^Qal[Z3+Bwzp^9=W\1E+EB=6O\nhWQ:=8Z*6=}VaW\1WgV]n0*.;yr=c9=Q"m_Um=@: Lh3Ma:M2N  +!5#4#"#3632dBg\1BB;RSVx66XmR>WRX5@2LJii1M2N!#!! +#"&#"'632327#3%<I#$<I%\BB83 39@6LJa3Ma7M4M2N!#!! +#"&#"'632327#3%<I#$<I%\BB3 3> J@1M2N +#3!5!BBe f:@4M2N +#3!5!BBe  z:=&@# L K1Ma6N#' +#327'#"&54675B(7/F(!2/-j 4+12,,7 92@/ L Ka9M4Ma6N#' +#327'#"&5467=264&"B(7/F(!2/-O&& 4+12,,7 &&Pb @i1M2N +#3264&"BB7,,f,,Z@4M2N +3#3BBdF 2@/L1M2Ma8N    +"'732653%#3k66"I+.BRBB o"S=9 U_ M' !;@8La9M4M2Ma<N## +##"'3265264&"#3264&"B)*&G7@O&&BBO&&" $8B9&& &&:@7 L1Ma8N  +#'#73"'7326531QQ1YRk66"I+.BRoono"S=9 U_'5@2  L4Ma<N## +#'#73#"'7326531QQ1YR@7G&*)BHoo9B8$ "Rd,  6@3L1M2N  +373##3#.MPBW\17o+7f-d,9@6 L3M4M2M6N +3#'373#'W\1ABPM5-Q=d &@# L4M2N  +3373#'dBSRDHS %@"1M_2N +3!5##73#d:B%W\1<^S@3M2N +#33#BBW\1Dd, LKPX@r1M_2N@1M_2NY +3!5##3#d:B{W\1<^9,!@3M2N +#33#BBLW\1D-d (@%1M`2N +3!5##73#d:BW\1<^@ZG"@3M2N +#33#BBTW\1Dڧd #@ i1M_2N +"&46233!D,,B ,,q<ZE @i3M2N +"&462#3&,,BB,, "@L1M_2N +5733!B03K4 <@L3M2N +57#3\BB03K4d *@' L1M2N +3#3##3kW\1BdBdeWfWZ4@1 L4Ma:M2N"" +3##4#"#3632(W\1Bg\1B=i||i>L:P4@1 L4M2Mb8N"! +73273##"5#%!5!PV<=B1\gBF K>`mX:U/@,ii1Ma8N +$"&5#265#"&462264&"zUByyB,,]P99P91[L>i||i>Lm,,I8N99NP<@9 Lii4M2Mb8N"! +73273##"5#6"&462264&"PV<=B1\gB,,]P99P9K>`mXo,,I8N99NU+@(1Ma8N +$"&5#265#3#'3#zUByyB>W\1WW\11[L>i||i>LP8@5 L4M2Mb8N"! +73273##"5#%3#'3#PV<=B1\gBW\1WW\1K>`mXU=%2@/LK1Ma8Ma6N#& +$"&5#327'#"&547676765#zUB=7Z)7/F(!2?+=B1[L>i>94+12,, ,>i>LP9"<@9LK4Mb8Ma6N"#(! +7327327'#"&5467=##"5#PV<(7/F(!2/-B1\gBK< 4+12,,7 `mX[1@.Li1M2N +462"6462"533N&&&&qEE&&&&W`- b@ LKPX@ p_1M_2N@_1M_2NY@  +!!!5!3#r9MW\1<(<6# b@ LKPX@ p_4M_2N@_4M_2NY@  +!3!5!3#[ W\15#53  J5u 4-''P%wBHF!dD@Lv +D#'#73F1QQ1YRHooBHF!dD@Lv +D373#B1QQ1YRoo2B< 2dD@'YaQ    +D273"&'3A3HtH3~M>KK>MFc dD@YaQ +D"&462,,c,,8*dD@iYaQ +D"&462264&"P99P9w,,88N99N ,,"9&dD@ JYaQ+! +D#"&5467327(F/7QC-/2!21+4?  7,mG8dD@-LJIYiaQ!#!! +D#"&#"'632327G%<I#$<I%3 3FH`dD@v +D3#73#|W\1W\1裏Fc dD@YaQ +D"&462,,c,,Z,dD@v +D3#W\1-(  @_)M*N+#####5! FBBKFF:Q>dD@3k]aQ +D3#72#.#"#>VV.OxI P32P IxNWiQ6HH6QiQEdD@:m[_O +D53"&'332673V(NxI P23P IxWWiQ6HH6QiO@'dD@[_O+D53d@]]dk" 1@.m]aQ     +"&54632"&54632&&++&&++++++*++*L@ GA*$ IK$PX@:mm  m M ` M  N@: mm  m M ` NY@%EC@?>=<;975420.-,+(& LL+%"&'732654&#"'>54&#"'>3232675#534&#"&'3323###"&'5P810|A);C.!<\. 'T%/#m?=U 3N,x|N7IqC L0SumrB!- a/xfq=,6J<I*&71,.38Y@"><9SeO7HqP<, &He>Y@V93*$ I  m  m MbN75210/.-,+(& >> +%"&'732654&#"'>54&#"'>3232675#5!###"&'5P810|A);C.!<\. 'T%/#m?=U 3N,x,rB!- a/xfq=,6J<I*&71,.38Y@"><<, &He B_@\=7*$ I  m  m  M bN;96543210/.-,+(& BB+%"&'732654&#"'>54&#"'>3232675#5!#####"&'6P8/2}@*:B/!<]7& N%."g8B] -X( "x=qCC!. a/x(lwG1/B<M,$31,.38U>$B <<^, &He`5IK$PX@;  m  m  kaMaM _N@4] m  m  m  k _NY@5542.,+)$!!+5!##"2632#.'"&546322654&#"#"&546;5 tU,X&7eHT9!Hl!C]'&K9R X+@-^<< U!C.Su$@5)\/3$'5/W<!*'6k` PP-,IK$PX@B  m m  k  eaMaM _ N@;]m  m m  k  e _ NY@MLHFB@<:98761/%$$$$+.'"&546322654&#"#"&546;5!5!.54632.#"3##"3267>32#Gl"B]&'J32'>54&#"#"&'732654&+'32654&' H(! (Y4He<5,*0>,2R gBj2<-T1FF1x,="^<<7-E (7B]BCt%1\7);nT?SN71G;;)8nE@CB;:985/&%  IKPX@4  m  m MaM`N@2 m m  m M`NY@@>7631*(#! EE +2!5!!3267.5462#"&'732654&'#"&'#5'%'.#"'>>jD{$ *>*:>J4*B <"#?9!$ C'I4N/(8bk<< '(9s04J8,"#,e0~5xI# /&*$A7@4A854"! Imm`N(*%+%+3.54632>75!5!#3267#"&5467>54&#"'>7.#"]qaE$G:#*-54&/.5#5!#'>=#Jq C L`L B q/6! JL/'( ,fN6HH6Nf/  '%<<4M /8%,)25f'$#IK+PX@m_MN@m_NY@210/ 55 +"&'3323#'>=#'>54&/.5#5!&'&IqC L0S::RL/'( ,#6! Jo&'$eO7H97O<1I /8%,)2/  '%<8(*%%@" I_N%%+5!#'>=#'>54&/.5 P+$(,$5! ^<<6Q /8%.)2/  ;!)+@(J I_N))+5!'73#'>=#'>54&/.5 m=<;:98742+)$" N N+"&'32673"&'732654&#"'>54&#"'>3232675#5!#####"&'qC L`L CP8/2}@*:B/!<]7&#M#."g8B] -U$ &x=qCC%* aiQ6HH6Q܅x(lwG1/B<I*$2-).38Y@"> <<^, #Ji P@ JD;:10$# IK$PX@<    m mmM ` MNK(PX@<    m mmM ` N@H    m mmM `M  b  NYY@)NMLKGF?=86.,(&! PP+"&'3323#####"&'#"&'732654&#"'>54&#"'>3232675#5!4&IqC L0SuqqCC!. aFP8/2}@*:B/!<]7& N%.%f6B] 2U "xN&eO7HqP<^, &Hex(lwG1/B<M,$31,.6;Y@$B<9S F@0/ JA;*$ IK(PX@/ m  m  M `N@; m  m  M `M bNY@#?=:987654321.-,+(& FF+%"&'732654&#"'>54&#"'>3232675#5!73#####"&'6P8/2}@*:B/!<]7& N%.%f6B] 2Q*x.wqCC!. a/x(lw?,4J<M,$31,.6;Y@$B<%(<^, &He I@320/ JD>1*$ IK(PX@/ m  m  M `N@; m  m  M `M bNY@#B@=<;:987654.-,+'& II+%"&'732654&#"'>54&#"'>3232675#5!%773#####"&'6P8/2}@*:B/!<]?,D5%`.He 2U "xk(%CntqCC!. a/x(lw?,4J<I*&7-*(6;]B"><;(<^, &He5D@A4('ImmM `N55$%$#+# +5!!>32'>54&#"#5#"&54632.#"3267 J,@YB<<8@3$.OBE(HeuR# 6O?,&H^<<%+iK@}2('j6/BF8 eHPqCJ4,?/(9G'=e@b65/Im  mm  a  M `N(((=(=:831.-,+*)"! ''+%2675#"&54632.#"3267!#"&'5!##5#"&'7326=K*7C]]C,,'77'7G1 )TqC,Kt453G+22$4@1M`N4#+5!####"&546;26=  qB l / ^<<^} *J@G$I mkM `N**  +%267!;#"5!##5#"&5467.54672l0C.W<9SKqC0l2Pq&#+2>:2 ,$3;;)*:<<04aF$@G))  9e@b%$I  m  m m  kaM _N  9 98620/-)'"    +"&546325!##"32632#"&'732654&#"#"&546;5QKQ);vR`P6IO6O Q)}:*M<< U!?,X}(U=!,$2k<@9ImkM `N%# +5!##5#"&5467#5!#3267 qC(^-C]&#]3?7'*`)^<<8@]C0NCCO0'7SG ! %=M@J8,I  mk`N'& 765432&='=! % %% +%>54&#"267.54675!;#""&5467.5467#5!# &*."+'+U'./;/G1I5,?^B]'"19h1@N**.!*J" .d07Sd4'6CJ42FCmN0QH'!6 <ImkM`N  +%"&'732654&'!5!5!###5H:<3|3!/;6qCUP3$9y7<<%U,@YFl@iFC@:! Immmm  k M  `  N><987654321/+)(& +267##"2632.'"&54632>54&#"#"&546;5!5!###"&', <(I"7,I4K99L I$o;)qB,$XO"92  K 3/!" G-})$3]<< Kb%.R@O,&I  m  mmM`N*(%$#"!  .. +7"&'732654&#"'>3232675!5!###"&'4j).S*4K?, <. R-R!<@9IkaM_N !!+%"&546;5!5!##"32654&'7DheHs_,>O9R)&5,1ykMm<%M (%a4X} -T@QI  m  mka M_N)'&$ -- +%"&'732654&#"#"&546;5!5!##"32632i>58X6O M3z2$)w PM);v "wR:4$2k<< U>,Vy Q ,9@6InkM_N , ,$$*!% +%>54&#"5!#!".54632#"&546;5#-&#~^$3QK46O}XkY@P7&&" 7<<>,N<"4KO6EbkHe;@8 mM`N    +7265#"&5#5!###$27'C]MqC~[;));BaE<<^Ean*@'IkM`N!"+463!5!5!##!".+R99{qC+[R(^iF@Y<<3$@E/P(/-$IKPX@4 mmm M  ` MaN@1 mmme M  `  NY@,+*)('&%"  // +%"&'32654&#"3"&4632#3267#53##5,_ -,He?,&7/!BP]BHfg[86s2BqC2seR92F*#CFrSmNUy+2B<<<38+ >@;Imk_N $"! +5!#!"34632'"&546;5@j'6l* I;#"3267#5!##5Ki5j<<e+H@E&#I mmM`N*(%$!  +2675#'5#5!!>32'>54&#"##"&'F;}D!J(Ea-*;&):)#I CE'Ea&#'6]<< #mMUK=/Y!0:."0@-Im_N-+'75!##"&'.'7326=}555ZS9+uI'k=<M.+/556<<>UK=/Y!0:."%8@5! ImM`N%%+( +5!##"'>7.#".54632>35 qB:d< @#7NycuuS1XP,^<<gS 4 "N775 *::*$DC??!/BB=OaF)TP&KiiK.P<"U>9RN=CPI75r555d*::*$DC??!/BB=OaF)TP&KiiK.P<"566dU>9RN=CPI@;ImM`N       +5#267'5!##5#"&=q])H>2rBH(He,?T<<eH@@=ImkM `N +5!##!#"&'726=35# qC#5698'<^<<@"(-6&ܴ1@@=) Immk _N11*+'! +5!#!">32'>54&#"3"&5467.546;5 *k (!3Ki5B/Hey'""';)^<< 2 U>"9. ".B/=U5 )@&M_N +53533## q>urB^<<^'2+'7555].66"LIK$PX@aM_N@caNY@""+7"&'732654&'.546;#"E{<Y0$3KA,1R9+D;1Yt] L]C0,a+T.1FC  Q'!126Mn!@M`N+5!## %rB^<<^2@/eMM_N"% +53.54632#.#"3## q }XiGO8T=V rrB^< ,Pq|`}O7, <^$_K(PX@fM_MN@"fM_NY@%" +53.#"#.546323## q[4'6I]CMrrB^<`|3$ ?>#=Uy<^(:dD@/Im]aQ +D"&'732654&#"'>32HM/I5:R+ 8.P/9SzE@<=A:)".. #U>Ea/:dD@/ Im]aQ +D"&54632.#"32679SaEW-;'C):*&!6S9B^zi7&*<8dD@-Im]aQ +D"&546;#"3267EaiK;;/C;)'A!RY@=V<3H2</$EdD@:"!Imm[_O $$+D"&5467.546;#";#"3267Fa(!";)xj/!/<86431/+)%# +53"&'3326734&#"'>323267>32#"&5332654&#"#"&'#"&'732654&#"'>J0 B[65\C=+ H3%c3Fd = 9K-Fa]CEa;?,'6:*>H-! ]BS2<,~?&7+ (?YIIeOR9:R*&  &Gfm!^p>,/C/FT@[_O+3W9a@[_O+5!<<GdD@v+D#'3,1\WNdD@v+D736W\I<dD@1k]aQ +D!5!'"&'332673GvIq B L/0L B q2+fN6HH6Nf0/dD@$]aQ#+D&'327673 I2;2)!I ?8Sl/ -"-80#=dD@2m]aQ####+D&'327673&'327673&d@ I2;2)!I ?8SJ>? F&7!2)!I @8SK60,!.80P.5&",709G@D8,+  ImmM `N99$%$#+# +'75!!>32'>54&#"#5#"&54632.#"3267665J,@YB<<8@3$.OBE(HeuR# 6O?,&H 5556<<%+iK@}2('j6/BF8 eHPqCJ4,?/(9G+Ah@e:93  Im  mm  a  M `N,,,A,A><75210/.-&%"! +++'772675#"&54632.#"3267!#"&'5!##5#"&'7326=h<<G+22$:@7IM`N4#+'75!####"&546;26=555 qB l /  5556<<^} !D@AImkM`N !! +'77"&'732654&'!5!5!###<<58X6O M3z2$)w PM);v.//d"wR:4$2k<< U>,Vy{Q0<@9InkM_N00$$*!) +'77>54&#"5!#!".54632#"&546;5A<<<#-&#~^$3QK46O}XkY@.//7&&" 7<<>,N<"4KO6EbkHe /K@H*' I mmM`N.,)(%#   +'7'2675#'5#5!!>32'>54&#"##"&555'F;}D!J(Ea-*;&):)#I CE'Ea222&#'6]<< #mM32!5!!7&632327327#"&54$(C'P1N/(8b'=#jDrq"" ..( ,!.( ,!"*H=u/(0(<~5xI # /&*k<<51 V&" /&" ( ?/"PF@CPGDC4+* Im maM`NKIA?%#!,% +3.54632>75!5!#;#"3267#"&5467.5467>54&#"'>7.#"]qaE(J8*?MeO*//**!B N+9S!!?-3DC/(JB 9):ZL(QPq*%*<<wLNy5,"5C/, -*<U:>UeO/$K4At 'T:9dD@.:1.- Im]aQ()%*$%+D.54632>323267#"&467>54&#"'>7.#"GTJ466 4K=2'(/72H:.!++!< +  **A7k:;R^C4Q ,% ,F^G8%-?K9#4$-QY!JFdD@;JA>=.%$ Imm]aQEC;9%$!*$%+D.54632>32;#"3267#"&5467.5467>54&#"'>7.#"GTJ4 828PI9 1;#*<-!&10#60  +*B7k:>>#HeeHUfG14KK41GPiJKim[q)!*@'!  Im]aQ%'$#+'#"&54632>54&#"'>32߭*:&8ETY@-\+(3q8ZcQ/."uGEa%$5).`Xn0\@ 0-' IK$PX@keaN@ mk]aQY@ %$!'+.'"&5462>54&+'32654&#"'>32>2F"4:>N]CI!x1FJ4G(!&\2Mm/(4>jQ 7UA;).( O27O;?,);/ "aE)LV2Em8D g2 1*@',&%JaN  1 1  +%2654&'"&5467.5467>54&'7P.C>30;?,Hf@8Ra6\KJU<YN8@i!-2`+]%0"B#6s, `4Ead6-*@'J'I]aQ'+*+'>54&/#"&54673267.54632!  /7X}<V=,/!'< 5W6*6$[>p-(c6C] 9*,>>,=$6#HxZ"1i1. IKPX@%kaMaN@#mkaNY@ "!$%*+.'"&5467.54632.#";#"34632.f.(6HeH/N$D,?G1kI9SfG3$ &aHqP)L Z<@Y< 3$1G5J47N+?#6M4WC '9@6JmeaN #! ' ' %+%>54&#""&546?3267"&546323$!/Y_j I mN,QSuS9@Y%@KiO6HeΓ!x'KTyI<[Pqdd6!@JaN+!"&54673267Zf9.eH([*/0s}X%JF.4@Y82.9?t% )[#IK$PX@maN@m]aQY@    +2654&#"'2654&/.54632#"&'.,??,1GG$37:mMKiY@NK41FF14K < !7y9KiqPNm-(=dE &@#maN   +264&#""&5462.AA.-AAteee}C`BB`C8dGFddFG(L6K!PX@ _N@[_OY@ +53(dL]]'v64BZ@W=7.-$#  I    m  mM ` NBBA@?>;9%($%'#+3###"&'#"&'732654&#"'>54&#"'>3232675#535rrB!- aEP810|A);C.!<\. 'T%/#m?=U 3N,xx4<, &Hexfq=,6J<I*&71,.38Y@">< 4F@ A;21(' IK(PX@4  m  mM ` N@@   m  mM ` M  b  NY@FFEDCB?=64/-$%'#+3#####"&'#"&'732654&#"'>54&#"'>3232675#5!5vqCC!. aFP8/2}@*:B/!<]7& N%.%f6B] 2Q*x4<^, &Hex(lw?,4J<M,$31,.6;Y@$B< b@FE65 J]W*$ IK(PX@0mm  M ` N@<mm  M ` M bNY@%[YVUTSRQPONM>=.-,+'& bb+%"&'732654&#"'>54&#"'>3232675#5!&'&&'77634'&'.73#####"&'6P8/2}@*:B/!<]?,D5%`.He 2U "xi -6IuBL0R0!$6FU@8/PkqCC!. a/x(lw?,4J<I*&7-*(6;]B"><$ =M 5& 2#1#!2 fP8@ A-4<^, &He0'6'6&$@!# I_N&&%$+!676'676'&'&/&67675#5LI9J&9+ 7"%-,6/! < : GhA- 1,lO6 VL  :C )J@G  ImkM`N $#"!  ) ) +'77'7'77"&'732654&'!5!5!###-555F555555RH:<3|3!/;6qCU466D4664466a3$9y7<<%U,@Yb &=@: ImM`N&&#' +'32767#%5!##5#"&52654&' .E Z<4// oqC'Y-`LZ" - 4DF*#o<<&)d;0 E 8@5k`N4# +5!#!5!##"&546;26=  qPn l / ^<<<<^} !Q@NI k  m  kM`N !! +5!%"&'732654&'!5!5!###uH:<3|3!/;6qCU=<<3$9y7<<%U,@Yh!@ JfN+#76'&'&'676Bx&UY?4BMqA4B-Xs E+!'#eE51d@aI k  m  m  kaM _N-+*(#"!  11+5!'"&'732654&#"#"&546;5!5!##"32632i>58X6O M3z2$)w PM);v<<,Vy' *L@I%Ik mm_N)'$#"!  +7267''4632.#"7!5!#!5!5#"&( GuR,!) 4q; L'Mm  !,?kOr 6 ,<<<< #f  2+' 7  ?55555"5!55ia0V)S+K#PX4  I4  IYK PX@5s u  n ] b   RKPX@5  n ] b   RK#PX@9  n ] b   R@? n ] b   RYYY@RPLHFECA>=3G$B#E+74547632367632#54&#"#54'"#"#4#"#&'"#"'&=332=32327654'3j>PY/!9+P6L& <>PY/"9+P6L& <:& -'-xj$U/WdC:"@v +73!73d5;d5<CdCN"@v +3#3PkPj~C  y #@ 3M_4N +###53533yBB<y2@/ g3M_4N +73#53533#3##5#BB<<<P @YaQ +462"&P6L66L6L&66&%55Kvi /@,_2N   +353353353KUUUiiiiii2 '1;?L@Ii j 1Ma7M 2M a 8N?>=<:9540/ +%462"&72654&"462"&72654&"462"&72654&"#3G~GG~G8)J**J)/G~GG~G8)J**J)+G~GG~G8)J**J)22T__TS__S32&#"3#3#327#"&'#73&547#7gtZb<5)@lZtN9Hs~J(4^U2$"2V]D'[~s2&%2;GcIK+PX@#lM_N@ lcNY@ #! +65!7!&'&+7!#3##5f 3sj'Pd ? 7??6?Q;gK UIKPX@aMNK+PX@mN@]aQYY#"+7327'#"&5#g@7F'*)Bn9B8$ "8Ba C@@ I _M`N  +'#373#5###53S6H\\H7RV6WZX'1FPJ IK(PX@_MaN@e_NY@ +;5.546235#5>54&"#JABffBAÇBIIB!hQdppdQh!:a$SS$a->$k IKPX@keaN@"mk]aQY@ +5&"327#"&54632@<@TG$9cNzz}.==%={K?y~0 #b IKPX@maMaN@mmaNY@"   +"32654&7.#"'632#"&546328O!94Ic;GBA79@M[^OViJ"Pk8?Fl@H hy!.)_W4  @_MN  B+!37!tBe^fd@M`N+!#!#!BB^- &@# I_M_N+!!!!57zוFi<<(,d%Qn@[_O+5!d%IIb)@&IcN+333#C͗H2#2 '1@.#Im]aQ$##"#"$"+3267.#"#"&4632632#"64&#"32t<52<<253nQ\\Qm43nQ\\Qm<52<<25zGF>>FnhhonhhzGF>>F'GIK(PX@maN@m]aQY#$#"+#"'73254632&#"NHA-%2TNHA-%2T4PU;g6PU;gOA@>Immm]aQ!#!#!#!!+632327#"&#"632327#"&#"O-/-$-/-/.$-/-/-$-/-/.$-/ B"< B" B"< B"P "@ J_N+%!5%5%`HX`=<<?B?P #@ J_N+%!=-5`W`=<;:7632/.+*'&+$462"462"462"462"462"462"462"462"$462"$462"462"462"&7((((((((V((((W(((()((u((((((,((8((r((T((s((8((V((((((((((  3dD@(m]aQ   +D264&#""&5462~((((K`DD`D2);));),C0.CC.0 >dD@3Im]aQ  +D27654&#"7#5#"'&547632#!!f- **1 n.##+2dD@'+*Im]aQ'*&3+D'#"'&54763267654'&#"'7>32T`  $"2?4$&*Xh   ,) `@=dD@2?:2&$Imk]aQ'&!)+D&'&'&'&54762>54'&+'327654'&#"'7>32o  ($*J'4,  *  &         A9dD@.:20,(  J]aQAA  +D27654&'"'&54767&'&5476?67654'&/7 )) % 0)' ('    "    )    ;6dD@+ J;, I]aQ42)'+D'76764'&/#"'&546?32767&'&54632  2#$)    /   9&- &    AEdD@:?; Imm]aQ#!&'.+D&'&'&'&54767&'&547632'.#";#"676327 9(* ),%>/$    !       2GdD@<Jmm]aQ,*%$!22'+D67654'&#""&54675732767&'&54632&  5=<;:943)'  PP +D"'&/7327654&#"'367654&#"'7>32327675#53##5#"'&'.*+""!## !- >$#    B@,  7- " e"" "/DdD@9 Imk[_O//!$)/+D5!##"'&/732764&+'327654&'uJ   +:75)%#.,-!LX""  )20X N**0!!   ;DSdD@HC32!Imm [ `PDD&(&$/$ +D5!#67632'767654&#"#5#"'&547632'.#"327675 &3"*, *"!/   ""C  1#U "%% $ɱdDIKPX@%sl[`PKPX@$l[`PKPX@%sl[`P@$l[`PYYY@ '#+D476;5#5!##5#"#"&  ]?-h? F"" @ GdD@<Im[`P   +D27675#'5#5!##5#"'& O'A?-+S lg ,g""m "=dD@2 Im[_O""+D5!##"'&''./73276= 2! )<`"( ) ""A(e: AO` GldD@a4$" I mm  l ] a Q EC<;:987651/)'  GG #+D&'&#"!3##5#"'&547632'.#"327675##5#53&'&547632''')F9' ++    (85! ,5f$% P    p "92*8dD@-Im[_O **+D"&/732654'&'&'&5476;#"}(F( #!]] !45+! % $3d7@4m_N +53"&'332673 V(NxI P23P IxBWWiQ6HH6Qidd( ?@<Im_N     +%'7'53"&'332673 "P(-V(NxI P23P Ix/<(>WWiQ6HH6QidL()n@kI    m k  m_N'&$" )) +53"&'332673'7'53"&'332673 V(NxI P23P Ix~"P(-V(NxI P23P IxWWiQ6HH6Qi/<(VWWiQ6HH6QidBW@TB@31$Im  m m _N97/-!  +53"&'332673'###"'&547632367654'&#"'767632 V(NxI P23P Ix !.-!B )'+,+F34'"5wBWWiQ6HH6Qi   !(&+++=8-'dm]d@a\UK?=$Im  k  m m _NDB:820/-! +53"&'332673&'&'5#&'&547632767654'&+'327654'&#"'7>32# V(NxI P23P Ix$$(!0;#h"%"H&<+, *$4 8BWWiQ6HH6Qi %  2 '- !-# &d=Y@VI  m  k m _N0.-+==  +53"&'332673"'&/732654'&'&'&5476;#" V(NxI P23P IxW500; ""0"" - +'GBWWiQ6HH6Qi/$$:,$"7   "2F3! 9:=@:"J6Imk]aQ$!%%&%+%>54&#"'636#"&5467.54767";#"3267.' &*."+'K(J>".]'"19 n0M'G1I5,?^B+U'./N**.!*J4(60umN0QH'%='$,]4h*&1\B++z@."+ ;!9#4 *>umN7!cC%%dH1w'**.!*%H @JN+7#&'74:B`BH<'UY-6%p'#;@8  L3Ma9M_4M2N## +!#3354632&#"3###BBdDLF9)-PBD0PU9g032.#".V;0&'6</4C / 6'#Bn8@5J IkfN%%+ 7>32.#"=3.W:/&'65C%(7G 5 6'#BPII" -@* JIdN  +53%77pd!,Cx@]]<(/7+@(J IeN%(+%77>32.#""2C<N0$$ .C C((.< :*B67<@9J IkeN%(+%77>32.#"7532C<N0$$ .C !I<((.< :*BIII7 !@ IfN%%+.54632.#""']C$$ '62+E#=U< 6'%G3@0 IkfN +53.54632.#"KJS9, +*" II]E#=U56' E !2+'%;`!5<$I/@Iv+3#'WB   )z@ )('&%$ IK#PX@MbNK(PX@MbMaN@M`MaNYY@ +%+>54&#"7.5463275#5!##'7''#*Ǹ+1I47O"5x,qC..''0wJ'4JJ4#BO(<<,5I+ 3O@L.-,+*' I mmM`N20)(%#   +'72675#'5#5!!>32'>54&#"#5'%5#"&6659&G:}Z8I(Eb.)<'):*"J BFF"Fa5133&#'6]<< #mM54&"753###"&'3.5462'"&5467.546232675$,,<*"qC3'X..9SS9#@ >i@f*I     n  lM `N>>=;750/$$$!+5!##!"3267>32#.'"&54632>54&#"#"&5463!5 qB} K! +qP B0.+L4J"1F`  *u:)^<< U?,C]'/ /#2$#'"A).$2]c/D@A."! ImmM `N//$%$#%# +5!#>32.#"#5#"&54632.#"3267 cK)  2O B>MmqP$"4KG1@^<<#&I K:eHMm<J4,?3+2:`@]32,+% I  m  mmaM _N::750.)'#!  +%"&54632.#"32675!!#"&'3267#"&'7326=>UY@6($2."(MLC.^P02P".6S9=U < /!*&#Pu<<6OpMEOFdy>Bw0Nm ,8^<<-$2<8653/-(&"  +'7'"&546325!##"32632#"&'732654&#"#"&546;5^I(LKQ);vR]O6NT6O Q,+W6!(<< U!?,X}(U=!2"kx>@;Imk_N  +5!"&5467#5!#3267 C]&#P6B7'-r64q^<<]C-MCCP)'7k]jKU! :E@B/I mkm_N 64-+'%$" : :% +%>54&#""&5467.5467#5!!;#"3267.54632 &*."+']'"19hG1I5,?^B+U'./R9>UN**.!*JmN0QH'!6 <<4'6CJ42F" .d0=US9uIg;@8Imk_N +5!"&'732654&'!# gJ<<38".:7FU^<<ɥ3$7u6<"U/C];FF=76 IK#PX@:    ^   n  nk_N@;    m  n  nk_NY@CB;942.,+)!$!'$+.'"&54632>54&#"#"&546;5!5!##"326323267#"&'#YV"Ji"#@DVI%t7&; =I%2 (*  q.:)/ 03$'"G%!*!/d<< K!   C  +h %x=*L@I("!I mmm_N%$ ** +5!"&'732654&#"'>323267#"&' 2p3"-])2FB/0!B!@a $ 13 g^<<82/-0N71G 5VC <  Id C!A@>IkaM_N !!+'7'5"&546;5!5!##"3267(W(t]CrP'6}X8\5zx/.(dtKi< O'A@>"!IkaM_N ''+'7'5"&546;5!5!##"32654&'7J(heHs\,>O9R5 yq5!(^kMm< 8(M-X}3Y@V I  m  mka M_N/-,*%$#"!  33 +'7'5"&'732654&#"#"&546;5!5!##"32632RI(_5P6O M47&)w PM);vk6!(]a"VR:5".k<< U>,VyQ2>@;InkM_N22$$*!+ +'7'7>54&#"5!#!".54632#"&546;5I(B#-&#~^$3QK46O}XkY@x5"(7&&" 7<<>,N<"4KO6EbkHe1@.m_N    +7265#5!##"&5'7;M]CEa3$%$3|<<=VV=%)@&Ik_N +5!.546;#" ep]C'6aY^<;#"3267^Ki 6BO64KG1"&:0) C!P@YG13}@@}^<< U=$=b97N>,*:< '0Q 5B/$3TLV@E1@.l_N +5!"&5463!#" da^<<"< I7@4Il_N   +'75!"&5463!#"555da/556<<"< I|*@' Im_N%#+5!#3267#"&= {F2)LK)Nm^<<4K:1]#'rOg%M@JI mmM `N  % %"   +2675#5!#>32.#"##"&=@>gB%&B"B?!He .),?T<<"' C 5/  bE #F@C! Imm_N##   +5!267'"&54632.#"7 4 F1MmuS" #(Y^<T01a!(^-NEa" ^<<? ?[9ED:]04kB/? 2@/eMM_N"% +53.54632#&$#"3## q kPcه rrB^< Zc{^B <^KPX@/M _MM bMaNK#PX@' [eM _MNK(PX@(m dM _MN@+m dM _NYYY@  +5353.54632#&$#"3##ld#q kPwLJ rrB[]]< Zdk^B <^7!9@6! Imm_N +5!.54632>3"'>7.#" 7ruS)W& S-Dp< ?!7Nu`^<<)TMm)' #C`M&3 F1C}#I 1N@K/# I  mm _N-+'%!11  +5!2654&"267.#""&54632>32#"&' R;;RD BC ,>>,HeeH0TP-EaaE/UR^<<.U=7NN=>NPB32#"&'l665R);;)*D DBB,>>,HeeH1TP.EaaE/UQ655C<<'Y@7NN=@STE?MU=>U@;$ Imm]aQ#"  +2654&#"7265#"&54632#$33$&77((Mm4B]]BOX[6'$33$'6;. gI\A@Yvli5@2 Im_N +7267'5!##"&=;J)LPq1Ga<32.#"#5#"&54632.#"3267<<<c@$*))D B E HeiJ3 ).C?,"H 5556<<#& CK: "eHMm 6 J4/B5/2>c@`760/)  I  m  mmaM _N>>;942-+'%"!   +'7%"&54632.#"32675!!#"&'3267#"&'7326=e555=VbE) );/!(ML;))M@NJF#66 555N7=U 52$*&#In<<6Op;6B47-6&-@*I`N4#+'75!##"&546;26=555)X w 6  5556<<r>@; Imk_N  +'75!"&'732654&'!#665rZ0<)E$37:FY/556<<4r'UE<> 7Og )P@M" I mmM `N  ) )&$!    +3'7'2675#5!#>32.#"##"&=665@>gB &&B"B?!He/...),?T<<"' < 5/  bE  :@  IKPX@ aN@]aQY%+>54&#"''>7.54632 "*''2_0">V(.N79S'"5""46)?/$8H&4KK4Ck5.@+Im_N +5!'%.#"'>7>3 !@l"*3(E0IR@OIF=4.-' Imme _NA?:920+)"   +53>4&#".'#"&5467.546323267#"&'32674632$,+!/(( MmA7&*U=:R*&3/\)-\+0X%4=F2&" ^<<5<++52 0$eH4XB"9RR9&D BE".C'7'#(4O@L41Im m  mk _N,*)'#!   +5!.'"&54632>54&#"#"&5463!!"32632 /E7A#.Oe T5k7&h @T&7mT 43^<</(!" L, j5$3< @6'?f "~K(PX@' [eM _MN@+ leM _NY@  +5353.54632#.#"3##dq }XiGI8W=V rrBGdd< ,Pq|`oO7, <^.{ IK(PX@*mM _MMbN@*mfM _NY@.."%$% +53.546324632.#"#.#"3## q }X=BT<$$ '6 C8W=V rrB^< ,Pq=97M; 6' 3`oO7, <^.2 IK(PX@3   kmM _MMbN@3    kmfM _NY@///2/210.."%$%+53.546324632.#"#.#"3##%53 q }XA;X>$$ '6 C8W=V rrBJI^< ,PqA<:Q; 6' 3`oO7, <^IIW2@/eMM_N"% +53.54632#.#"3## q}X`+C*B>UkrB^<4 Heu\yC.4<^yK(PX@*^M_ MM `N@-^M_ M `NY@  +53###53.54632#.#"^rBqq}X\*<*B>Uo]]<^<4 Heu\lC.4.K(PXIIYK(PX@&]fM_ MN@*mfM_ NY@.."%$% +###53.54632>32.#"#.#"rBqq}X2e,R3$&'6  <*B>U<^<4 He/,,5< 6' /\lC.4.2K(PXIIYK(PX@/   k]fM_ MN@3    kmfM_ NY@///2/210.."%$%+###53.54632>32.#"#.#"%53rBqq}X2e,R3$&'6  <*B>UI<^<4 He/,,5< 6' /\lC.4III$KPX@/M _MM aMbNK#PX@' [fM _MNK(PX@(n cM _MN@+n cM _NYYY@  +5353.#"#.546323##dq`2".IV=I!rrBTdd#=U|<^$9+϶"IKPX@$M _MMbNK#PX@!fM _MNK(PX@&^fM _MN@*mfM _NYYY@++%$%" +53.#"#.54632>32.#"3## q`2".IV=*X$O2$$ ,?rrB^#@Y82-6< F2 Q<^$9/& IKPX@- k M  _MMbNK#PX@* kf M  _MNK(PX@/ k^f M  _MN@3 kmf M  _NYYY@"//.-,+*)$" +5353.#"#.54632>32.#"3##]q[4'6I]C'P"P3$$ *: rrBddq<`|3$ ?>#@Y5/+2< F2$6<^I2@/eMM_N%" +53.#"#.546323## q$l@YIZ-rrB^'Ea~<^IH@E [eMM _N  +5353.#"#.546323##dq$l@YIZ-rrBT]]'Ea~<^I2+nIK(PX@!eMM _N@&]eMM _NY@++%$%" +53.#"#.54632>32.#"3## q$l@YIZS:[=$$ '6grB^'EaC>8I< 6')D<^I2+/IK(PX@*   keMM _N@/   k]eMM _NY@,,,/,/.-++%$%"+53.#"#.54632>32.#"3##753 q$l@YIZS:[=$$ '6grBqI^'EaC>8I< 6')D<^II-p(:@7J Im]aQ +7'"&'732654&#"'>32΅W(!'yI7N3(H(,>mPxq/dk40(&*'$(%*>,4K!/@,JIm]aQ4%$+7'"&54632.#";=UN7VJ.CI*2$ <]]/PV:*.CaZ!OX#53@0I[mm_O#$%"+4632.#"326753#5#"&aE9,)::)*MBBL*Ea=U< /!$3'#jPY(P@M'I  m  mmmM `N((%#! !$"# +5!##5#"&'32654&#"#52632#3267cqCP/TC<<;)'&&'EaZLQ04U^<< "|`%$&BO69F0:6.Z%:1@.Im_N +5!"&'53267 :d(`28^$:"9^<<<I 5F@C4(' ImM `N55$%)+# +5!!>32'>54&#"#5'7.54632.#"3267 J,@YB<<8@3$.OB(=QuR# 6O?,&H^<<%+iK@}2('j6/BF8/rcAPqCJ4,?/(9B&?i@f8710/.$ I   m  mm M `N'''?'?<:-,+*)(!  &&+%2675#"&4632.#"3267!#"&'5!##5'7.'.'7326=(U>=VZ@/%$3/!=G1OrBK}((/,'d22ISrS < /B/ =Ud~<<6d ZF%kE!+22$;@8 IM`N4#+5!##5'%##"&546;26= ,qBM k / ^<<5e} !>@; ImkM`N!!%% +5!##5'%5##"&'732654&'!5 qCSN7T/<(|>'40^<<5;6Om&']0Jv@s9.-*'!  I  mm  m  m  kM`NJJIGCA@>7621%# +267##"326325!##5'75#"&'.'"&5462>54&#"#"&546;5,AL# 3-qC!%,OJ9/,I9R&899L J$n;)2  K ,<325 6rB!-L%H('\1#^3^<<5-05 "821-<@9%$#"Ik_N--,*'$!+5!##"3267.54632.''7.546;5 >n);N  *+ ,B+.azaE^<<7&@n  '++ G%J/.x}KB]kN =@:IM`N   +%2?#5!##5'7.= dC[qC(@RB.Ca<<5]9+/L@I*)('&# I mmM`N.,%$!  +2675#'5#5!!>32'>54&#"#5'%5#"&&G:}Z8I(Eb.)<'):*"J BFF"Fa&#'6]<< #mM>^<32'>54&''7"3"&5467.546;5 Ch -:"Ki# 55gh0&&*+^<<= R:*M/5(@>`<{.I B*k  =t@ =:9.-IK(PX@(maM_MaN@%meaM_NY@ %##% +>54&#"767.5462#53##"3267#"&547675'$'*(i6(.NnN)'.q;21+"IK#PX@5   mm  mM `N@:   mm  ] mM `NY@#]]ZXUSNLB@=<97&$! '"+>32>54&#"26755!!>32'>54&#"#5#"&5467.54632.#"32675J* *-O3V 6.:K2$M(9S83(&**%N BT1@Y,$$,eHB "0,>B/)E  "".(/(C  -<<"'K48 (([*5@##*&ș ">,3 :#4J/&8';-j@ #"IK#PX@mM `N@#kmM `NY@--+# +5!!>32'>54&#"##.5467#5!5 H; Mm" 6G1#<C%1UK"Yhw{^<<iKDq'%c91Gn@+5o*/4A(= <`^@]QPDC:90-,#"IK(PX@)m  m  m _N@.]m  m  m _NY@^^[YUSNL%+(+%+#+5!!>32'>54&#">32'>54&#"'>7.#".546325#"&54632.#"3267 C$B])&6 #7&/G 4 7NE9(-7'%G<(*:L9 RiaF(H&KiiK 5+/BB/0M^<< nM,T (?1G@1F21[5?"3+(  /!0 <R29S fJIh <C.,?3+   E@D87.%" IK#PX@1  mm aM `N@5  mmM aM `NY@!  E EB@<:53)'$#   +726755!!>32'>54&#"#5#"&5467.54632.#"326750^ cQ,9SOC(8?*.TB&Z.1F8+.IM`N..$#= +5!###"'.5467%##"&546326= 'qC . )4  c^<<r   + _ Z p@ YXTHG;8/.% IK#PX@S  m ]   mnmmmk_N@T  m  m  mnmmmk_NY@5  p pomigba][VURPLJEC?=:964)'$#   +"&54632%5!#!"3267>32#>32'>54&#"#5#"&54632.#"32675"&'732654&#"#"&546;5] C $ 7OnM%D4KI<".6"D/<H*9RN7 8(!*.!(JM;/,X9S'* 1o;)u<< 0 J49Sd7'&J5," c:*.C/ " xMF(?G7'# [*$2W{ x@a`]WVSROICB65)&IK$PX@U  m m  mmnmk a M_N@S  m  m m  mmnmk_NY@3  x xwuqojiec[YMKGE@>:831-+('!   +"&54632%5!#!"3276767632#5#"&54632.#"32675#"&'#"&'.'73265.'732654&#"#"&546;5TD7N*&<-,??,   . (N$." K,In<$@8Z6O'$6p:*u<< 1F1&D]0"#1/ $V 3K-<5 \ ;)7 (CI:* Y,$2W W}@z@?<4-'$I     m  m  nml_N  W WVTPNJHDB8620+)&%   +"&54632%5!#!"3267>32#5#"&'#"&546;26=.'732654&#"#"&546;5mtL(',?$< %2 Y "3U(=M6O'+7p?,u<< 0K4 9 E q:%(=B/!'U*$2Wn $cl@ ONKE<9IK PX@Yu  mm  m  n m  laM _NK(PX@Z  mm  m  n m  laM _N@^  mm  m  n m  laM _NYY@7%% %c%cb`\ZYWSQ@>;:4210,*)('&!  $ $  +"&546322675#"&'"3>3"5!#!"2632#5#"&5467.5467.'732654&#"#"&546;5n? #!, '#  *" B6j,>,$<?!4K )!Q7/5I=Vc5k;)u;)'/ << 0G1,EB 7&-+=7(@F3$#U*$2Wn Q@>=:5/*I  m  mnnmk_NQQPNKIHFB@9731.-,+%#"    +"&5463235#"&'5!#!"32632#5##"&546;5.'732654&#"#"&46;5t/, 4r2FCZ !:g&.8]4Kr(d;)n<< *C.&9 c<Y @/.BJ3$[H2WL *}@wqpmg^]ZHB?%$IKPX@`       mm  m  nmk a M`NK#PX@^       m  mm  m  nmk`N@e       m  mm  m  nmk`NYY@/ ~|zyusbaUSNMFDA@:8751/.-,+)'"   $+72654&#""&5463232675#"&!##"32632#5#"&'3.54632&/"&5467.5467.'732654&##"&546;5!!/++$%05+  UT'7C27]' ):*#*+5 2Ki,$$A1!=/9T6O X*;)-q' - 2  ~<6*. $" (?,%< ('<(.;<&^ *C1M@J0I  m  kkM `N11.,'&%$#+5!##5#"&5467#53.5467#5!#3#3267 qC%h47N nW&0 xd*8j^<<8632*)('! % %%+>54&#"267.54675!;#"5!##5#"&54632.#"32675#"&5467.5467$&+(0N&*8,G1(0}qjK49R I '+'"S:2 4 3@ .- IK$PX@,mk Ma M`N@* mmk M`NY@,+*)('&%$#33 +%"&'732654&'%5##"&'732654&'!5!5!##9K/6!p=* G1@|&<X)"MrBN]P!FS3$$ V4KiTg;))d<<%W9S;W@T32&% Im  k  maM `N;;:975$%".# +5!##5#"&5467'%32675##"&'732654&#"'>3235 qC,"<3235qC mM<}05'a,/B$ W97e%(Q.$2." *'?8S^<<J B]`SDN:)(x;6H1,/%+:*&5WtQ ;M@J0"! Imkm  k _N;;:8#$,$!$ +%#"32654&'5!#!"3267#"&546;5#"&546;5*uS9R d^*ta3V/( yUoS9 !S9k#4K/!.<<6B.<%9SmN1FCcQ/BW?r@o43Im k  k  mM a M`N??><861/+)'%! +%267!>32#5!##5#"&'32654&#"#"3267#"&546;5r)T"@>SuXURqCT1T'O7>@C]}X.Z%/-sPq2+'6 D%=UmM4JCfG2FWEr@o76Im k  k  mM a M`NEEDB><1/+)'%! +%267!>32#5!##5#"&'32654&#"#"32654&'7#"&546;5$P%QZWP"IN?Zf:R 7W(3f4Kd.r?,^<< 6!7&C] ;)@YVP/IP6' K4H+(HQ:* g+*W+ Sw@t?>Iu  m  m  k  mmmk_N S SRPLJIGCA<:9731-,&!$!+2654&"5!#!"32632#"3.5462#"&546;5#"&'732654&#"#"&546;58''8&beBc); 'jD JhKm[jS9In9(2g4J c,m:*Ό<< 37&"<7U #,?C.7A}Q,?(\Q(HQ:* ^'$2WP<;IK#PX@Em  m   m  m  naM`N@W  m  m  m  m  nMaM`NY@3PPOMIGFD@>97310.*'&$  +%267!2632#5!##5#"&'2654&#"+"32632#"&'732654&#"#"&546;5z.X wVyaFJqC W/O|MmR: s GQ*:qP]P6IJ4KQ3z>,)'ak(R:3K-7<< "{`+".. L!C.X}"Y@!{2'6knb Sγ.IK$PX@Hu  m  kmmk aM_N@Fu  m  m  kmmk_NY@-SSRPLJIGCA=;651/)'"!   +2654&#"2654&"5!#!"3.54632!"3.54632#"&546;5#"&546;5"""" 8&&8'ot*:qIK37O$2uL K41GjWs]BjheH<,4=yN/B(~Q6O<Q}@z5%Im  m  k  k  mM aM`NQQPNJHDB=<8631-+)'$#"!  +%267!>32#>54&#"5!##5#"&'32654&#"!"3.54632#"&546;5f-X!-h9SuaENP"-&#qC X.V~]$3O79h-):yUK46OqPyaEզ6.TqO64K,8V7&&& 4<<')`'+?,`:4KO6EbyFa)?C@@3- Imk_N??><'&%! +5!##"3.54632./#"&'.5467>54&/.546;5 6h,>wd 3$!/ *<0d6 "(.#980.*($"!  +267&/"&'3>7.5!#!"3267>32#.'#"&'"&467.546;5Q1T$&/!(6e-=:) -*f+yA 2$,+J']09W @YT>S9+%4 ,&7%1!.- )e<<'=p(6#,(\40')H6OlP  7Nk;8@ 0'&%$IK(PX@.kaM _N@,mk _NY@88*)'($! +5!#!"32673267.54632'#"&5467.546;5 Hq$3O6(Nf?,>2$# /6("I'He,$;JY@^<<$2C @$+ "."45^PS9%? N./BkTu@rL@?0) I m  m m m  m  k_NTTSQIHDB=;7642-,$" +267/#"&'5!#!"3267>32#.'#"&'"&54632.#"3>7.546;52T$0"(7g*yA 1$++I"_39V Z>,-(  ]C )#AS9+%"4 ,&7r<<'=p(6#+(\5#&H6aF,>( /B. q$7NkM7H@E/IlM `N77*/"! +5!#!"34632#.'#"&54?.546;5 Zo$3i(!++I,  &se}YuY@^<7267'5!#!"3267.54632&/#"&5467.546;5$ += B@i".iK+'6(!,$< $ ]01GA7GYU>I 0! qI  C<<#=V "2$( 'T+ &A8@6'%Eh@4JkwJY@V?>430)( Imm  l _NJJIG&+&.'$! +5!##"3267.54632'#"&57'.#".546327#"&546;5 p&7aF! +$3%d.d /!(B (6'' I%`]B^<<'9S+-(r  (P  /-!.dyU7Nk *O@L  m  l  kM `N * *)'#! #$!+%3##";%5!##5##"&546;5#"&546;5b۴qC ^ /1GG1q<<5 d ^B/,>W/W@T' I mm  kM `N//.,"  +%267##">3#"5!##5#"&5467.546;5D;&5( :2(^);GqB>CMm-7O6xMET'<3H2<<=BY@. ?"/BW= ?_@\7.+*'I ml _N  ? ?><20"    +7267"5!##"3267.54632.'#"&5467.546;5,K$="'#Jk,>aE( 3#".&("CV14J/'ETeH!G8 " =<<7&9S  3$'#];;+37'7f;@Yd5w43IK PX@(snM`N@)nM`NY@55$%- +5!###"&546?.'.#"#"&5463275 qB   )}"E%PM81o5)/^<<,^  J r 't%0-&G >@;IkM`N    +35#'5!###".5467.='TqC$392"AJ(!n#<<,/!4]/%w@&? 3!g>@ 763 IK(PX@+  m  m  m _N@1  m  m m  m _NY@'  > >;91/+*)($" +2675#'5!#2#'2654&#"'7.#"3"&54632>75#"&=*P;t1GS9'7#$3<%'7K4EaU=#8"O,Eah" $2<U57'"2$ '!/5O64K  Y@`Ra@^KJBA854+*"!I  m  mm _N  R ROMHF<:20&$ +2675#5!!>32'>54&#">32'>54&#"'>7.#".46325#"&='G;#I(Ea;;)#I &7OB6/-7')G<0'H7 RiS9$AE#Ea&#'6F<< #mM$L#!:1F)& Fd[<: 3+( '!: <ZnN]CBQ@N>5/.%"! Imm   mM `NBBA@<:(( +%>35"'>7.#"25!##5"'>7.#".5467.54632>35*`0Ge<?&'7,$:ZqCDi5A!'78,!;J(!"']C-OfG$%8,+#; i<54&#"2675%7.546325#53##5#"&5467'%'"'!W$S(]0:$+J47N$!qCU,*:j%~ *'')@8d(E(V>"2FF2"><<<,1C.<5/d 9n@ (IK(PX@#M`MbN@ fM`NY@42'&%$#"! +>4&"46?''7.54632#53###"'&'.'8&,G !*3O67O# "qB!44""5  I~5qH)2FF2!CW<<r  #  A@=9.-,+*$# IK#PX@)mM `M bNK(PX@%mM `MaN@)meM `NYY@ A A@?43(% +>54&#"75!##"'6?.#".5467''7.5462>35 "# qB:bC : ):bQcy5(q($,JhK# +I ^6/.q<<2PB$'4b5$E+@Cx5k=#/BB/=W)#') ~ >@:10$#"!  IK(PX@+  mmM`MaN@(  mmeM`NY@><,$%'% +>54&#"4632.#"32675''7.546325#53##5#"&"(PiK6,/CC/.O!$,O64K /qCM-K$(hJ5 &"*&qPq5]: ,>B/1<<<"'9&q"IKPX@!kaM _N@mk _NY@  & &  +5#3''5!##"3267#"&5467.=5x;Fc);fH.P('d6d,$(5ȅ'<<7'B]" .')Z*A @*f,F@C(IkaM _N  , ,#!  +5#3''5!##"32654&'7#"&5467.=/;s);mNB]/]j(!#&x!.<<;)=UR9-(C#Uy}X-H<7@V@S/ I  m  m k  lM `N><987764*)##7!+5!!!">;2#54&+#"&="3"&5467.546;5#3265  +$24KC"F21F:Rf &#')/!Ik  ^<< 7 G1#q2FF2qG1Jj32#5#"#"&546;54&#"3"&5467.546;5  (!N6UzC5YS9]f |'"&).!^<< 2 C. i /G1Rv325!##5##"&'.46;54&#"3"&5467.546;5}0& ,?vrB  #!=U+%$,C. +6'M<<(  5 B/Rv5i(H9 $2W+@c@`93  I   m  m  kM `N@@?=-+'&$"+%267#!">325!##5#"&'2654&#".5467.46;5#K/'6B]1% ;.8qCI&Ei );7&Nm.(&0>,q1, , F2-<32#5"'7.#".54632>74&#"3"&5467.546;5  (!#J&cB"2< %4DG114&fGdxyU l/(,1:)^<< 2 R:=..#/5L1.C'fUHe5]32#5#"&54632.#"326754&#"3"&5467.546;5 [ (!2UzC 5"1GG1  5R:He`t&#')/!^<< , U=P?+,? 5 C$2Y@Pq325!3!61#"&'&'7326= qB(([*2((F-Y';z$<"..9&^<<<045*& B+(**P(29#k/@ *)('IK$PX@'mka M_N@% mmk_NY@" //  +5!732654&'!!#"&"&'732654&'% <X)"aG1@|K/6!p=*N^<32'>54&#"'#"&'7326= L):R1,C+3+4/3$55;"^<<]C=l%(Y4);.C(!+24D@A.-,+Imkm _N44"+" +5!!3>32'>54&#".5467##"&'726= 02He0-6')>,".(%+ d<( 6698'^<<yU?|5('g:9R2$4(F$"#-(/.6"F1CW@T; I  mmmm  k _NCCB@6543$$%$$(+5!#!">32#"3267#"&54632654&#"3"$5467.546;5 >X @.He2$);;) EbK4#?,Ru֘=4+22$^<< 5O6$3'CN7,>&eHfI8d<&7PQ|2+-&'.546k: xq:2 ,$3;;)*:<<5` [>$@G))>@; IkM`N% +5!##5'7.5467#5!#3267 qC(1=&#]3?7']9^<<5i W70NCCO0'7?9,///.-$IKPX@3  mm M `MaN@0  mme M `NY@,+*)"#$4 +%.'32654&#"3"&4632#3267#53##5'Pv .+Hf?,'6."CP]CHefZ87r3CqC]" \R92F*#CFrSmNUy+2B<<<<)8@ 876-IKPX@3  mm M `MaN@0  mme M `NY@5432!'$+ +7.5467.54632#52654&#">;#"267#5!##5'7.#".54632>75!5!##5m!>aB @#7NXHuS1XN>qB5iQ 4 "N7Bq32#>3"H*9RN7 8(!*.!(JM;/,X9S'* 5x/!1 C $ 7OnM%DD/uc:*.C/ " xMF(?G7'# n1"W<< 0 J49Sd6" nhJIK(PX@M`M_N@cM`NY@  +535373##dl.wrBb]]</<^`7@4J IeM`N%%+537>32.#"3## l/W:$ $ &76wrB^</4C< 6'#B<^t M@JJ I keM `N    +53537>32.#"3##Cr/X9$$ '60wrBII<%(7G< 6'#B<^FA@> J IcM_N  +5353%773##dd!+Cu`rB@]]<<%(<^?F;@8JIeM_N%(+53%77>32.#"3## d!2C<N0$$ /B,`rB^32.#"3##I]8C<N0$$ .C,grBII<<%((.< :*~<^2V@S0*)('& I  m  mmM`N.,%$#"!  22 +7"&'732654&#"'>3232675!5!##5'%5#"&'4j).S*4K?, <. R-54&"753##5'75#"&'3.5462'"&5467.546232675$,,<*"qCPj3'X..9SS9#@ Bm@j."! I     n  lM `NBBA?;943$$$%+5!##5'7!"3267>32#.'"&54632>54&#"#"&5463!5 qB} K! +qP B0.+L4J"1F`  *u:)^<<]I5Q$ U?,C]'/ /#2$#'"A).$2].=@:)("!  ImmM`N%'+#+05!5!!>32'>54&#"#5''7.#"'>32mJ,@YB<<8@3$.MB!-=%H('\1#^u<<%+iK@}2('j6/BC,;5-*5 "9B%B)@& IcaN%(+3267#"'&'&5476?%5!v([*/0s9e/- $ 82.9?,+W8;=dj91@. J+*'#ImaNE'+&+%654'#"&54673267.54632&'"&54763237X}<V=,/!' 2 -3?72J'IJ?4,[>p-(c6C] 9*,>>,=QA@88 ,&vC))E9@610 Im_NBA@?>=42/-+76"/4'&7632676'&'&#"/7267654&'&'#5!tU_);  ,e4o >24 %".  $\8 )6>HI)' ,6@-G[0/, -j*r /05,*  ?B17J%2& K* T&n<; F0Xnt@qpdXWNHFEDCBA?6 I    m  m l  mM  `Noooo~|zyusnmlj2$"#8+>7/&'5!3!##5#"&'32654&#"#"7>7&676''7&'&'&'&676.7>7.'&76?5#367632#3267!1K "1 ?WG2qCP/TC<<;)/FD0 @ '$vH# W28aY 3+1!  gB!'S ")1I(N'EaZLQ04U 9)!1 2&,o<< "|`%$& 0m 0|(6 84IE,G//0 4d$6.6khO69F0:6.Z>.4*)IKPX@?  m  mm M`MbNK#PX@<  m  mm M`MaNK(PX@<  m  mm M`MaN@9  m  mme M`NYYY@=;87651/$""+46;54&"3"&546235#5%67632'>54&#"###"&w5#2##4JJhKۭa$%(Ea-*;&):)#$$ CcF 'CG1/BN7<<mM7.#".54632>35!5!#0@,54&#"'676qC0&/H(i9x /")$34&;$,0(y<<^w#.@:^'" @'$44")3@0%!  Im`N'$,+#'#"&54632>54&#"'67675#5!0&/H(i9x /")$34&;$,0(]w#.@:^'" @'$44"y<26 IK(PX@*   kfMM _N@/   k]fMM _NY@3336365422#%'%+53.54632&54632.#"#&'&#"3##%53 q ]zESS9, +*Pn^5z rrB"J^< Z<"B=U56' #'"^B <^II;n IK(PX@!fMM _N@&]fMM _NY@;;(J%&% +53.5463267632.#"##&'#&'&'&#"3## q ]z=F..C$$ '6 P d^5z rrB^< Z<5;)+< 6'%$ }$"^B <^ I@F leMM _N    +5353.54632#&'&#"3##dvq ]Pn^5z rrB@]]< Zx'"^B <^2@/eMM_N#% +53.54632#&'&#"3## q ]Pn^5z rrB^< Zx'"^B <^N6@3IeMM_N"' +53&'454762#.#"3## oIIwGO8f.1trB^<#Y32|`}"$<)  <^0;@8 IfMM _N00&&% +530'476267632&#&/&'&#"3## nIIws .C C JH ''0^f.1trB^"$"$>"$<)  <^II^>oIK(PX@!fMM _N@&]fMM _NY@>>)W%&' +53&'45476267632.#""#1#&'&'&'&'&#"3## oIIw}s .C$$ #$ "O '0^hf.1trB^<#Y32N #+< 0$8*!>"$<)  <^6@3IeMM_N"' +53&'454762#.#"3## oIIw}GO8hf.1trB^<#Y32|`}"$<)  <^#IKPX@/MM _M bMaNK#PX@' [eMM _N@(m dMM _NYY@##"!   +5353&'454762#.#"3##doIIw}GO8hf.1trB[]]<#Y32|`}"$<)  <^48ε IK!PX@3   lmM _MMaNK+PX@0   lmeM _MN@3    lmeM _NYY@5558587644%%'%+53.54632454632.#"&'&'&#"3##%53 q YGS9, +*  Pbه rrBLJ^< ZE!,=U56' "\36^B <^II| #?@<#"! Im_N  +5!267''7.54632.#"7 ( G!DWuR,!) ^<<h p6(d$@|bLRDD4X D ! !f!!","b""##R##$L$%%&&' ''(8())$)H)t)**t**+6++,,V,,--^--..T./$/0 001<122d223F344L445f56>67678(8j889 909h999:*:~::;:;t;;;<&>P>??R?@ @AjAB B\BBC0CDDjDE.EEF*FtFG GHGGHHbHIIHIIJ$JbJJK2KLL2LLLMM@MpMMMN.NPNrNNNO6OVOPZPQnRRS2STxTUZUV(V~WPXHYYZ6Z[[f[\6\]]^ ^T^__l__`~`ajabbZbcccdTdde6efffg^ggh^h~hhii6izijj`jjk*k`k~kkl6lblllm4n0nNnjnnnootoppq qqrdrsvttzuu uFutuvvvwJwxxVxxy y,yzp{X{d{p{|,||},}f}~D~hj.T|ڀ(Ɓ܁$f̃.r hЄHd(zΆ*z։TԊH̋<􌺍$<|ؐ^ڑh"zR8~8h(hzК|n(z VʞƟ.ޠT2ΣN@̥J4<|©P \ެrV֮j @䱊P^6zµ$^жbF\JbҽJʿ.@bV~Zzfv˖@΢Rv Ѽ.TӶ&԰:Ռ2`؂0\ c0` RRb,i&      X  ,  L  X Lx  4Copyright 2011-12 Lohit Fonts Project contributors. Open type tables written by: Pravin Satpute Sneha Kore Latin glyphs designed by: Eduardo Rodriguez Tunni Licensed under the SIL Open Font License 1.1 (see file OFL.txt)Lohit DevanagariRegularFontForge 2.0 : Lohit Devanagari : 17-9-2013Lohit Devanagari2.95.5Lohit-DevanagariLohit is a trademark of Red Hat, Inc. OFL 1.1http://scripts.sil.org/OFLCopyright 2011-12 Lohit Fonts Project contributors. <http://fedorahosted.org/lohit> Open type tables written by: Pravin Satpute <psatpute AT redhat DOT com> Sneha Kore <skore At redhat DOT com> Latin glyphs designed by: Eduardo Rodriguez Tunni <fontime AT gmail DOT com> Licensed under the SIL Open Font License 1.1 (see file OFL.txt)Lohit DevanagariRegularFontForge 2.0 : Lohit Devanagari : 17-9-2013Lohit Devanagari2.95.5Lohit-DevanagariLohit is a trademark of Red Hat, Inc. OFL 1.1http://scripts.sil.org/OFL~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghjikmlnoqprsutvwxzy{}|~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~uni00B2uni00B3uni00B5uni00B9AmacronamacronAbreveabreveAogonekaogonekDcarondcaronDcroatEmacronemacron Edotaccent edotaccentEogonekeogonekEcaronecaron Gcommaaccent gcommaaccenthbarItildeitildeImacronimacronIogonekiogonekIJij Jcircumflex jcircumflex Kcommaaccent kcommaaccent kgreenlandicLacutelacute Lcommaaccent lcommaaccentLcaronlcaronLdotldotNacutenacute Ncommaaccent ncommaaccentNcaronncaronOmacronomacron Ohungarumlaut ohungarumlautRacuteracute Rcommaaccent rcommaaccentRcaronrcaronSacutesacute Tcommaaccent tcommaaccentTcarontcaronUmacronumacronUringuring Uhungarumlaut uhungarumlautUogonekuogonekZacutezacute Zdotaccent zdotaccent Scommaaccent scommaaccentuni021Auni021Buni0237 apostropheuni0307uni0326candrabinduinverteddevacandrabindudeva anusvaradeva visargadeva ashortdevaadevaaadevaidevaiidevaudevauudeva rvocalicdeva lvocalicdeva ecandradeva eshortdevaedevaaideva ocandradeva oshortdevaodevaaudevakadevakhadevagadevaghadevangadevacadevachadevajadevajhadevanyadevattadevatthadevaddadevaddhadevannadevatadevathadevadadevadhadevanadevannnadevapadevaphadevabadevabhadevamadevayadevaradevarradevaladevalladevallladevavadevashadevassadevasadevahadeva oesigndeva ooesigndeva nuktadeva avagrahadeva aasigndeva isigndeva iisigndeva usigndeva uusigndevarvocalicsigndevarrvocalicsigndevaecandrasigndevaeshortsigndeva esigndeva aisigndevaocandrasigndevaoshortsigndeva osigndeva ausigndeva viramadevaeprishthamatrasigndeva awsigndevaomdeva udattadeva anudattadeva gravedeva acutedevaecandralongsigndeva uesigndeva uuesigndevaqadevakhhadevaghhadevazadeva dddhadevarhadevafadevayyadeva rrvocalicdeva llvocalicdevalvocalicsigndevallvocalicsigndevadandadbldandazerodevaonedevatwodeva threedevafourdevafivedevasixdeva sevendeva eightdevaninedevaabbreviationsigndevahighspacingdotdeva acandradevaoedevaooedevaawdevauedevauuedeva marddadevazhadeva yaheavydevaggadevajjadevaglottalstopdevadddadevabbadevauni1CF5uni1CF6zerowidthnonjoinerzerowidthjoineruni2080uni2084Euro inr_currency afii61289uni2126 estimateduni2206 dottedcirclezerocombiningdigitdevaonecombiningdigitdevatwocombiningdigitdevathreecombiningdigitdevafourcombiningdigitdevafivecombiningdigitdevasixcombiningdigitdevasevencombiningdigitdevaeightcombiningdigitdevaninecombiningdigitdevaacombiningletterdevaucombiningletterdevakacombiningletterdevanacombiningletterdevapacombiningletterdevaracombiningletterdevavicombiningletterdevaavagrahacombiningsigndevaspacingcandrabindudevacandrabinduviramadevadoublecandrabinduviramadevacandrabindudigittwodevacandrabindudigitthreedevacandrabinduavagrahadeva pushpikadeva gapfillerdeva caretdevaheadstrokedeva signsiddhamjainomuniFB01uniFB02isign_ra_virama.alt2isigndeva.alt1esigndeva_anusvaradevaesign_ra_virama.alt1esign_ra_virama_anusvaraaisigndeva_anusvaradevaaisign_ra_virama.alt1aisign_ra_virama_anusvararadeva_viramadevaradeva_viramadeva_anusvaradevaviramadeva_radeva_altviramadeva_radevashadeva_viramadeva_radevaphadeva_radeva_nuktadevatadeva_viramadeva_tadevakadeva_viramadeva_ssadevajadeva_viramadeva_nyadevakadeva_viramadevakhadeva_viramadevagadeva_viramadevaghadeva_viramadevangadeva_viramadevacadeva_viramadevachadeva_viramadevajadeva_viramadevajhadeva_viramadevanyadeva_viramadevattadeva_viramadevatthadeva_viramadevaddadeva_viramadevaddhadeva_viramadevannadeva_viramadevatadeva_viramadevathadeva_viramadevadadeva_viramadevadhadeva_viramadevanadeva_viramadevannnadeva_viramadevapadeva_viramadevaphadeva_viramadevabadeva_viramadevabhadeva_viramadevamadeva_viramadevayadeva_viramadevaisigndeva.alt2isigndeva_anusvara.alt2ladeva_viramadevalladeva_viramadevallladeva_viramadevavadeva_viramadevashadeva_viramadevassadeva_viramadevasadeva_viramadevahadeva_viramadevaqadeva_viramadevakhhadeva_viramadevaghhadeva_viramadevazadeva_viramadevafadeva_viramadevashadeva_viramadeva.altta_virama_ra_viramadevata_virama_ta_viramadevaka_virama_ssa_viramadevaja_virama_nya_viramadevaisigndeva_anusvaradevaisign_ra_viramaisign_ra_virama_anusvaraisigndeva.alt3isigndeva_anusvaradeva.alt3isign_ra_virama.alt3isign_ra_virama_anusvara.alt3iisigndeva_anusvaradevaiisigndeva_ra_viramaiisign_ra_virama_anusvaraiisigndeva.alt1iisigndeva_anusvaradeva.alt1iisigndeva_ra_virama.alt1iisign_ra_virama_anusvara.alt1vattudeva_ulowdevavattudeva_uulowdevaglyph244 yadeva_altradeva_viramadeva.altkadeva_viramadeva_radevakhadeva_viramadeva_radevagadeva_viramadeva_radevajadeva_viramadeva_radevajhadeva_viramadeva_radevatadeva_viramadeva_radevadadeva_viramadeva_radevapadeva_viramadeva_radevaphadeva_viramadeva_radevabadeva_viramadeva_radevabhadeva_viramadeva_radevamadeva_viramadeva_radevavadeva_viramadeva_radevasadeva_viramadeva_radevahadeva_viramadeva_radevasha_virama_rvocalicdevakadeva_viramadeva_kadevakadeva_viramadeva_tadevakadeva_viramadeva_ladevakadeva_viramadeva_vadevagadeva_viramadeva_nadevangadeva_viramadeva_kadevangadeva_viramadeva_khadevangadeva_viramadeva_gadevangadeva_viramadeva_ghadevangadeva_viramadeva_madevanga_virama_ka_virama_ssadevacadeva_viramadeva_cadevachadeva_viramadeva_vadevajadeva_viramadeva_jadevanyadeva_viramadeva_cadevanyadeva_viramadeva_jadevattadeva_viramadeva_ttadevattadeva_viramadeva_tthadevattadeva_viramadeva_yadevattadeva_viramadeva_vadevatthadeva_viraamdeva_tthadevatthadeva_viraamdeva_yadevaddadeva_viramadeva_ddadevaddadeva_viramadeva_ddhadevaddadeva_viramadeva_yadevaddhadeva_viramadeva_ddhadevaddhadeva_viramadeva_yadevadadeva_viramadeva_gadevadadeva_viramadeva_ghadevadadeva_viramadeva_dadevadadeva_viramadeva_dhadevadadeva_viramadeva_nadevadadeva_viramadeva_badevadadeva_viramadeva_bhadevadadeva_viramadeva_madevadadeva_viramadeva_yadevadadeva_viramadeva_vadevanadeva_viramadeva_nadevapadeva_viramadeva_tadevapadeva_viramadeva_ladevaphadeva_viramadeva_ladevaladeva_viramadeva_ladevashadeva_viramadeva_cadevashadeva_viramadeva_nadevashadeva_viramadeva_ladevashadeva_viramadeva_vadevassadeva_viramadeva_ttadevassadeva_viramadeva_tthadevahadeva_viramadeva_nnadevahadeva_viramadeva_nadevahadeva_viramadeva_madevahadeva_viramadeva_yadevahadeva_viramadeva_ladevahadeva_viramadeva_vadevasa_virama_ta_virama_radevaja_virama_ja_viramadevadadeva_rvocalicsigndevaradeva_usigndevaradeva_uusigndevahadeva_rvocalicdevanadeva_viramadeva_altghadeva_viramadeva_radevacadeva_viramadeva_radevathadeva_viramadeva_radevadhadeva_viramadeva_radevanadeva_viramadeva_radevaladeva_viramadeva_radevanga_virama_ka_viramadevaosigndeva_anusvaradevaosign_ra_virama.alt1osign_ra_virama_anusvaraausigndeva_anusvaradevaausign_ra_virama.alt1ausign_ra_virama_anusvaranyadeva_viramadeva_radevannadeva_viramadeva_radevayadeva_viramadeva_radevassadeva_viramadeva_radevaka_virama_ssa_virama_radevaja_virama_nya_virama_radevakadeva_viramadeva_radeva.np eightdeva.np fivedeva.np zhadeva.npda_ddha_ra_yadeva jhadeva.npnep_jha_virama ladeva.mr shadeva.mrshadeva_viramadeva.mrisign_ra_virama_anusvara.jaisign_ra_virama.jaisigndeva_anusvaradeva.ja isigndeva.ja isigndeva.thaisign_ra_virama.thaisign_ra_virama_anusvara.thaisigndeva_anusvara.thaisign_ra_virama_anusvara.alt1isign_ra_virama.alt1isigndeva_anusvara.alt1isign_ra_virama_anusvara.alt4isign_ra_virama.alt4isigndeva.alt4isigndeva_anusvaradeva.alt4isign_ra_virama_anusvara.alt2ba_virama_ra_viramadevaBB_@@BB<<3'7722XXIB, UXEY KQKSZX4(Y`f UX%acc#b!!YC#DC`B-, `f-,#!#!-, dBCC ``BCB%CCTx #CCadPxC`B!e!CCB C#BC`B#PXeYC`B-,+CX#!#!CC#PXeY d P&Z( CEcEEX!%YR[X!#!X PPX!@Y 8PX!8YY  CEcEad(PX! CEcE 0PX!0Y PX f a PX` PX! ` 6PX!6``YYY% CcRXK PX! CKPX!Kac CcbYYdaY+YY#PXeYY dC#BY-, E %ad CPX#B#B!!Y`-,#!#!+ dbB #BEX CEc C`Ec*! C +0%&QX`PaRYX#Y!Y @SX+!@Y#PXeY-, C+C`B-, #B# #Babfc`*- , E Ccb PX@`Yfc`D`- , CEB*!C`B- ,C#DC`B- , E +#C%` E#a d PX!0PX @YY#PXeY%#aDD`- , E +#C%` E#a d$PX@Y#PXeY%#aDD`-, #B EPX!#!Y*!-,EdaD-,` CJPX #BYCJRX #BY-, bfc c#aC` ` #B#-,KTXdDY$ e#x-,KQXKSXdDY!Y$e#x-,CUXCaB+YC%B%B%B# %PXC`%B #a*!#a #a*!C`%B%a*!YCGCG`b PX@`Yfc Ccb PX@`Yfc`#DC>C`B-,ETX#B E#B #`B `BBB` #Ba++"Y-,+-,+-,+-,+-,+-,+-,+-,+-,+-, +-+,# bfc`KTX# .]!!Y-,,# bfc`KTX# .q!!Y--,# bfc&`KTX# .r!!Y- ,+ETX#B E#B #`B `aBB`++"Y-!, +-", +-#, +-$, +-%, +-&, +-', +-(, +-), +-*, +-., <`-/, `` C#`C%a`.*!-0,/+/*-1, G Ccb PX@`Yfc`#a8# UX G Ccb PX@`Yfc`#a8!Y-2,ETXEB1*EX0Y"Y-3,+ETXEB1*EX0Y"Y-4, 5`-5,EBEcb PX@`Yfc+Ccb PX@`Yfc+D>#84*!-6, < G Ccb PX@`Yfc`Ca8-7,.<-8, < G Ccb PX@`Yfc`CaCc8-9,% . G#B%IG#G#a Xb!Y#B8*-:,#B%%G#G#a B C+e.# <8-;,#B%% .G#G#a #B B C+ `PX @QX  &YBB# C #G#G#a#F`Cb PX@`Yfc` + a C`d#CadPXCaC`Y%b PX@`Yfca# &#Fa8# CF% CG#G#a` Cb PX@`Yfc`# +#C`+%a%b PX@`Yfc&a %`d#%`dPX!#!Y# &#Fa8Y-<,#B & .G#G#a#<8-=,#B #B F#G+#a8->,#B%%G#G#aTX. <#!%%G#G#a %%G#G#a%%I%acc# Xb!Ycb PX@`Yfc`#.# <8#!Y-?,#B C .G#G#a ` `fb PX@`Yfc# <8-@,# .F%FCXPRYX +.0+-~,>+@+-,>+A+-,>+B+-,>+@+-,>+A+-,>+B+-,?+.0+-,?+@+-,?+A+-,?+B+-,?+@+-,?+A+-,?+B+-, EPXEX#!!YYB+e$PxEX0Y-KRXYcpB:+"*B@ G?/' *B@ KC7+  * B  *B@@@@@ *D$QX@XdD(QXXDY'QX@cTXDYYYYY@ IA1)*DdDDText-Layout-0.037/tests/fontbb.pl0000644000400000040000000000604714640222607014503 0ustar jvjv#!/usr/bin/perl use v5.36; use Object::Pad; use utf8; my $verbose = 1; @ARGV = ( "Times-Roman", "FreeSerif.ttf", "DejaVuSerif.ttf", "ArialMT.ttf", "MuseJazzText.otf", "MuseJazzChord.ttf" ) unless @ARGV; use PDF::API2; sub max { $_[0] >= $_[1] ? $_[0] : $_[1] } sub min { $_[0] <= $_[1] ? $_[0] : $_[1] } my $pdf = PDF::API2->new; my $page = $pdf->page; my $gfx = $page->gfx; PDF::API2::addFontDirs( $ENV{HOME}."/.fonts", "/usr/share/fonts/" ); my $x0 = 70; my $y0 = 650; # Annotations. my $af = $pdf->font("Helvetica"); my $as = 8; my $scale = 0.08; my $dx = 3000 * $scale; my $dy = 2500 * $scale; my $sz = 1000 * $scale; my $dd = 400 * $scale; my ( $x, $y ) = ( $x0, $y0 ); for my $fn ( @ARGV ) { next unless $fn; my $font = $pdf->font($fn); # PDF::API2 units are 1/1000 em. my @xbb = $font->fontbbox; push( @xbb, $font->ascender, $font->descender ); my $xbb = sprintf( "%d %d | %d %d | %d %d", @xbb ); warn("$fn: $xbb\n"); # Scale. my @bb = map { $_ * $scale } @xbb; my $o = $pdf->xo_form; $o->line_width(0.5); $o->fill_color('black'); $o->stroke_color('black'); # Background (first glyph). $o->fill_color("yellow"); $o->rectangle( 0, $bb[1], $sz*$font->width("Á"), $bb[3] ); $o->fill; # Crosslines for origin. $o->stroke_color('lightgreen'); $o->move( -$dd, 0 ); $o->hline($dd); $o->stroke; $o->move( 0, -$dd ); $o->vline($dd); $o->stroke; # Font bounding box. $o->stroke_color("blue"); $o->fill_color("blue"); $o->rectangle(@bb[0..3]); $o->stroke; $o->textstart; $o->font( $af, $as ); $o->translate( $bb[0]+1, $bb[3]+3 ); $o->text("bounding box"); $o->translate( $bb[0]+1, $bb[1]-8 ); $o->text("$xbb[0] $xbb[1] $fn"); $o->translate( $bb[2], $bb[3]+3 ); $o->text("$xbb[2] $xbb[3]", align => "right" ); $o->textend; # Ascender and descender. $o->stroke_color("red"); $o->fill_color("red"); $o->move( -$dd, $bb[4] ); $o->hline( $bb[2]+$dd ); $o->stroke; $o->move( -$dd, $bb[5] ); $o->hline( $bb[2]+$dd ); $o->stroke; $o->textstart; $o->font( $af, $as ); $o->translate( $bb[2]+$dd, $bb[4]+2 ); $o->text( "ascender", align => "right" ); $o->translate( $bb[2]+$dd, $bb[4]-8 ); $o->text( $xbb[4], align => "right" ); $o->translate( $bb[2]+$dd, $bb[5]+2 ); $o->text( "descender", align => "right" ); $o->translate( $bb[2]+$dd, $bb[5]-8 ); $o->text( $xbb[5], align => "right" ); $o->textend; # Sample glyphs (with max asc and desc). $o->fill_color("black"); $o->stroke_color("black"); $o->textstart; $o->font( $font, $sz ); $o->translate( 0, 0 ); $o->text( "Ág" ); $o->textend; my @obb = ( min($bb[0],-$dd), $bb[1]-10, $bb[2]+$dd, $bb[3]+9 ); # $o->rectangle(@obb); $o->stroke; $o->bbox(@obb); if ( $x + $bb[2] + $dd > 590 ) { $x = $x0; $y -= $dy; } warn("X: [@{[$o->bbox]}] @ $x,$y\n"); $gfx->object( $o, $x, $y, 1, 1 ); $x += $dx; } $pdf->saveas("fontbb.pdf"); Text-Layout-0.037/tests/underline.pl0000644000400000040000000000205314640222607015207 0ustar jvjv#!/usr/bin/perl use strict; use warnings; use utf8; my $verbose = 1; use PDF::API2; my $pdf = PDF::API2->new; my $page = $pdf->page; my $text = $page->text; my $font = $pdf->corefont('Times-Roman'); $text->font( $font, 80 ); $text->translate(50,700); $text->text("the quick brown fox _ ", -underline => ["auto","auto"] ); $text->text("jumps", -underline => "auto" ); use lib 'lib'; use Text::Layout; my $layout = Text::Layout->new($pdf); #my $fc = Text::Layout::FontConfig->new( corefonts => 1 ); # Select a font. $font = Text::Layout::FontConfig->from_string("Times 80"); #my $font = $fc->from_string("Times 60"); $layout->set_font_description($font); #$font->set_shaping; $font->{underline_thickness} = 45; $font->{underline_position} = -100; $layout->set_markup( qq{the quick brown fox _ jumps} ); $layout->render( 50, 650, $text ); $layout->set_markup( qq{the quick brown fox _ jumps} ); $layout->render( 50, 550, $text ); $pdf->saveas("underline.pdf"); Text-Layout-0.037/tests/tl_p_03.pl0000644000400000040000000000560314640222607014466 0ustar jvjv#!/usr/bin/perl use strict; use warnings; use utf8; use PDF::API2; use lib "../lib"; use Text::Layout; use Text::Layout::FontConfig; eval { require HarfBuzz::Shaper } or warn("HarfBuzz::Shaper not found. Expect incorrect results!\n"); # Create document and graphics environment. my $pdf = PDF::API2->new(); $pdf->mediabox( 595, 842 ); # A4 # Set up page and get the text context. my $page = $pdf->page; my $text = $page->text; # Create a layout instance. my $layout = Text::Layout->new($pdf); my $PANGO_SCALE = $layout->set_pango_mode(1); # Select a font. setup_fonts(); my $font = Text::Layout::FontConfig->from_string("Amiri 45"); $layout->set_font_description($font); # Start... my $x = 0; my $y = 700; # Left align text. $layout->set_width( 595 * $PANGO_SCALE ); $layout->set_alignment("left"); # Arabic is RTL, so it comes out as right aligned. $layout->set_markup( q{برنامج أهلا بالعالم} ); showlayout( $x, $y ); # Typeset in three parts. Note that parts 1 and 3 will be ltr, # and part 2 will be rtl. # Note, however, that this currently relies on the native # harfbuzz library to correctly determine ('guess') the # characteristics of the text. $y -= 100; $layout->set_markup("abc"); $x += showlayout( $x, $y ); $layout->set_markup( q{برنامج أهلا بالعالم} ); # Arabic is RTL, restrict to actual width to prevent unwanted alignment. $layout->set_width( ($layout->get_size)[0] / $PANGO_SCALE ); $x += showlayout( $x, $y ); $layout->set_markup("xyz"); showlayout( $x, $y ); # Typeset as one string, using . $x = 0; $y -= 100; $font = Text::Layout::FontConfig->from_string("Sans 45"); $layout->set_font_description($font); $layout->set_markup( "abc". "".q{برنامج أهلا بالعالم}."". "def" ); showlayout( $x, $y ); # Ship out. $pdf->saveas("tl_p_03.pdf"); ################ Subroutines ################ my $gfx; sub showlayout { my ( $x, $y ) = @_; $layout->show( $x, $y, $text); my $dx = ($layout->get_size)[0] / $PANGO_SCALE; $gfx //= $page->gfx; $layout->showbb($gfx); return $dx; } sub setup_fonts { my $fd = Text::Layout::FontConfig->new; # Add font dir and register fonts. $fd->add_fontdirs( $ENV{HOME}."/.fonts", "/usr/share/fonts/" ); # Add a Sans family. $fd->register_font( "FreeSans.ttf", "Sans" ); $fd->register_font( "FreeSansBold.ttf", "Sans", "Bold" ); $fd->register_font( "FreeSansOblique.ttf", "Sans", "Italic" ); $fd->register_font( "FreeSansBoldOblique.ttf", "Sans", "BoldItalic" ); # Add Devanagari (Indian). Requires shaping. $fd->register_font( "lohit-devanagari/Lohit-Devanagari.ttf", "Deva", "", "", { shaping => 1 } ); # Add Amiri (Arabic). Requires shaping. $fd->register_font( "amiri/amiri-regular.ttf", "Amiri", "", "", { shaping => 1, nosubset => 1, } ); } Text-Layout-0.037/tests/tl_c_02.pl0000644000400000040000000001171214640222607014446 0ustar jvjv#!/usr/bin/perl use strict; use warnings; use utf8; use lib "../lib"; use PDF::API2; use Text::Layout; use Text::Layout::FontConfig; use HarfBuzz::Shaper 0.026; # Create document and graphics environment. my $pdf = PDF::API2->new(); $pdf->mediabox( 595, 842 ); # A4 # Set up page and get the text context. my $page = $pdf->page; my $text = $page->text; my $gfx = $page->gfx; # Create a layout instance. my $layout = Text::Layout->new($pdf); my $PANGO_SCALE; sub main { # Select a font. my $font = Text::Layout::FontConfig->from_string("Sans 44"); $layout->set_font_description($font); # Start... my $x = 0; my $y = 700; # Text to render. $layout->set_markup( q{ Áhe quick brown fox } ); # Left align text. $layout->set_width( 595 * $PANGO_SCALE ); $layout->set_alignment("left"); # Render it. showlayout( $x, $y ); $y -= 100; # Right align text. $layout->set_width( 595 * $PANGO_SCALE ); $layout->set_alignment("right"); # Render it. showlayout( $x, $y ); $y -= 100; $text->font( $font->{font}, 44); $text->translate( $x, $y-50 ); my $txt_nomarkup = q{Áhe quick brown fox}; my $dx = $text->text($txt_nomarkup); if ( $font->{font}->can("extents") ) { my $e = $font->{font}->extents( $txt_nomarkup, 44 ); printf( "EXT: %.2f %.2f %.2f %.2f\n", @$e{qw( x y width height )} ); $gfx->save; $gfx->translate( $x, $y-50 ); # PDF::API2 text is baseline oriented, so are the extents. # So we can draw the BB at the same origin as the text. $gfx->rect( $e->{x}, $e->{y}, $e->{width}, $e->{height} ); $gfx->linewidth(0.5); $gfx->strokecolor("cyan"); $gfx->stroke; $gfx->restore; } # Draw baseline. $gfx->save; $gfx->translate( $x, $y-50 ); $gfx->move( 0, 0 ); $gfx->line( $dx, 0 ); $gfx->linewidth(0.5); $gfx->strokecolor("magenta"); $gfx->stroke; $gfx->restore; $y -= 100; # Text to render. # $layout->set_markup( q{Áhe quick brown fox} ); # Right align text. $layout->set_width( 595 * $PANGO_SCALE ); $layout->set_alignment("center"); # Render it. showlayout( $x, $y ); $y -= 100; # This will only work properly with the HarfBuzz driver. $font = Text::Layout::FontConfig->from_string("Deva 60"); $layout->set_font_description($font); $layout->set_width( 595 * $PANGO_SCALE ); # Nepali is LTR. $layout->set_alignment("left"); # This text consists of 6 characters but will render 4 glyphs. my $phrase = "\N{DEVANAGARI LETTER TA}". "\N{DEVANAGARI LETTER MA}". "\N{DEVANAGARI VOWEL SIGN AA}". "\N{DEVANAGARI LETTER NGA}". "\N{DEVANAGARI SIGN VIRAMA}". "\N{DEVANAGARI LETTER GA}". qq{ this should look like THIS}; $layout->set_markup($phrase); showlayout( $x, $y ); # Ship out. $pdf->saveas("tl_c_02.pdf"); } ################ Subroutines ################ sub showlayout { my ( $x, $y ) = @_; $layout->show( $x, $y, $text); $layout->showbb($gfx); } sub setup_fonts { $^O =~ /mswin/i ? setup_fonts_windows() : setup_fonts_linux(); } sub setup_fonts_linux { # Register all corefonts. Useful for fallback. # Not required, skip if you have your own fonts. my $fd = Text::Layout::FontConfig->new; # $fd->register_corefonts; # Add font dir and register fonts. $fd->add_fontdirs( ".", $ENV{HOME}."/.fonts", "/usr/share/fonts/" ); # Add a Sans family. $fd->register_font( "DejaVuSans.ttf", "Sans" ); $fd->register_font( "DejaVuSans-Bold.ttf", "Sans", "Bold" ); $fd->register_font( "DejaVuSans-Oblique.ttf", "Sans", "Italic" ); $fd->register_font( "DejaVuSans-BoldOblique.ttf", "Sans", "BoldItalic" ); # Add Devanagari. Requires shaping. # Note that Nepali is a LTR language. $fd->register_font( "Lohit-Devanagari.ttf", "Deva", "", "", { shaping => 1, language => 'nepali' } ); } sub setup_fonts_windows { # Register all corefonts. Useful for fallback. # Not required, skip if you have your own fonts. my $fd = Text::Layout::FontConfig->new; # $fd->register_corefonts; # Add font dir and register fonts. $fd->add_fontdirs( ".", "C:\\Windows\\Fonts" ); $fd->register_font( "arial.ttf", "sans", "" ); $fd->register_font( "arialbd.ttf", "sans", "bold" ); $fd->register_font( "ariali.ttf", "sans", "italic" ); $fd->register_font( "arialbi.ttf", "sans", "bolditalic" ); # Add Devanagari. Requires shaping. # Note that Nepali is a LTR language. $fd->register_font( "Lohit-Devanagari.ttf", "Deva", "", "", { shaping => 1, language => 'nepali' } ); } ################ Main entry point ################ # Setup the fonts. setup_fonts(); if ( @ARGV ) { # For compliancy, use Pango units; $PANGO_SCALE = $layout->set_pango_mode("on"); } else { $PANGO_SCALE = 1; } main(); Text-Layout-0.037/tests/pango02.pl0000644000400000040000000000355714640222607014502 0ustar jvjv#!/usr/bin/perl use strict; use warnings; use utf8; use Pango; use Cairo; require "./pango00.pl"; # subs # Create document and graphics environment. my $surface = Cairo::PdfSurface->create( 'pango02.pdf', 595, 842 ); # A4 my $cr = Cairo::Context->create($surface); my $layout = Pango::Cairo::create_layout($cr); # Scale from Cairo (PDF) units to Pango. my $PANGO_SCALE = Pango->scale; # Scale from Cairo (PDF) font size to Pango. my $PANGO_FONT_SCALE = 0.75 * $PANGO_SCALE; # Font sizes used, scaled. my $realfontsize = 60; my $fontsize = $realfontsize * $PANGO_FONT_SCALE; my $tinysize = 20 * $PANGO_FONT_SCALE; # Select a font. my $font = Pango::FontDescription->from_string('freeserif 12'); $font->set_size($fontsize); $layout->set_font_description($font); # Start... my $x = 0; my $y = 842-500; # Cairo goes down # Text to render. $layout->set_markup( q{ Áhe quick brown fox } ); # Left align text. $layout->set_width( 595 * $PANGO_SCALE ); $layout->set_alignment("left"); # Render it. showlayout( $cr, $layout, $x, $y ); $y += 100; # Right align text. $layout->set_width( 595 * $PANGO_SCALE ); $layout->set_alignment("right"); # Render it. showlayout( $cr, $layout, $x, $y ); $y += 100; $font = Pango::FontDescription->from_string('Lohit Devanagari 45'); $layout->set_font_description($font); $layout->set_width( 595 * $PANGO_SCALE ); # Nepali is LTR. $layout->set_alignment("left"); # This text consists of 6 characters but will render 4 glyphs. my $phrase = "\N{DEVANAGARI LETTER TA}". "\N{DEVANAGARI LETTER MA}". "\N{DEVANAGARI VOWEL SIGN AA}". "\N{DEVANAGARI LETTER NGA}". "\N{DEVANAGARI SIGN VIRAMA}". "\N{DEVANAGARI LETTER GA}". qq{ this should look like THIS}; $layout->set_markup($phrase); showlayout( $cr, $layout, $x, $y ); # Ship out. $cr->show_page; Text-Layout-0.037/tests/tl_p_01.pl0000644000400000040000000000761514640222607014471 0ustar jvjv#!/usr/bin/perl # This is an example of using Text::Layout to create the same document # as native Pango. # # This example uses Text::Layout in Pango conformance mode. The # relevant parts of this program and its Pango counterpart are very # much the same. use strict; use warnings; use utf8; use lib "../lib"; use PDF::API2; use Text::Layout; # Create document and graphics environment. my $pdf = PDF::API2->new( file => 'tl_p_01.pdf' ); $pdf->mediabox( 595, 842 ); # A4 # Set up page and get the text context. my $page = $pdf->page; my $text = $page->text; my $gfx = $page->gfx; # Create a layout instance. my $layout = Text::Layout->new($pdf); # Tell Text::Layout that we are running in Pango compatibility. my $PANGO_SCALE = $layout->set_pango_mode("on"); # Scale from Cairo (PDF) font size to Pango. my $PANGO_FONT_SCALE = 0.75 * $PANGO_SCALE; # Font sizes used, scaled. my $realfontsize = 60; my $fontsize = $realfontsize * $PANGO_FONT_SCALE; my $tinysize = 20 * $PANGO_FONT_SCALE; sub main { # Select a font. my $font = Text::Layout::FontConfig->from_string("freeserif 12"); $font->set_size($fontsize); $layout->set_font_description($font); # Start... my $x = 0; my $y = 500; # PDF goes up # Text to render. my $txt = qq{ Áhe quick }. # $tinysize = 15360 for a 20pt font. qq{brown }. # rise is in 1/1024 units. qq{fox}. # 10240/1024 units = 10pt. qq{x}. # size=45pt for a 60pt font. qq{x }; my $txt_nomarkup = "Áhe quick brown fox "; $layout->set_markup($txt); # Left align text. $layout->set_width( 595 * $PANGO_SCALE ); $layout->set_alignment("left"); # Render it. showlayout( $x, $y ); $y -= 100; # Right align text. $layout->set_width( 595 * $PANGO_SCALE ); $layout->set_alignment("right"); # Render it. showlayout( $x, $y ); $y -= 100; # Plain PDF::API2, no Text::Layout. $text->font( $font->{font}, $realfontsize ); # PDF::API2 text is baseline oriented. $text->translate( $x, $y-50 ); my $dx = $text->text($txt_nomarkup); if ( $font->{font}->can("extents") ) { my $e = $font->{font}->extents( $txt_nomarkup, $realfontsize ); printf( "EXT: %.2f %.2f %.2f %.2f\n", @$e{qw( x y width height )} ); $gfx->save; $gfx->translate( $x, $y-50 ); # PDF::API2 text is baseline oriented, so are the extents. # So we can draw the BB at the same origin as the text. $gfx->rect( $e->{x}, $e->{y}, $e->{width}, $e->{height} ); $gfx->linewidth(0.5); $gfx->strokecolor("cyan"); $gfx->stroke; $gfx->restore; } # Draw baseline. $gfx->save; $gfx->translate( $x, $y-50 ); $gfx->move( 0, 0 ); $gfx->line( $dx, 0 ); $gfx->linewidth(0.5); $gfx->strokecolor("magenta"); $gfx->stroke; $gfx->restore; $y -= 100; # Right align text. $layout->set_width( 595 * $PANGO_SCALE ); $layout->set_alignment("center"); # Render it. showlayout( $x, $y ); # Ship out. $pdf->save; } ################ Subroutines ################ sub showlayout { my ( $x, $y ) = @_; $layout->show( $x, $y, $text); $layout->showbb($gfx); } sub setup_fonts { my $fd = Text::Layout::FontConfig->new; # Add font dir and register fonts. $fd->add_fontdirs( $ENV{HOME}."/.fonts", "/usr/share/fonts/" ); for ( "", qw( Bold Italic BoldItalic ) ) { $fd->register_font( "FreeSerif$_.ttf", "freeserif", $_, { shaping => 0 } ); } for ( "Roman", qw( Bold Italic BoldItalic ) ) { $fd->register_font( "Times-$_", "freeserixf", $_ eq "Roman" ? "" : $_, { shaping => 0 } ); } } ################ Main entry point ################ # Setup the fonts. setup_fonts(); # Run... main(); Text-Layout-0.037/tests/pango00.pl0000644000400000040000000000345314640222607014473 0ustar jvjv#! perl use strict; ################ Subroutines ################ my $cr; my $layout; my $PANGO_SCALE = 1024; sub showlayout { my ( $_cr, $_layout, $x, $y ) = @_; $cr = $_cr; $layout = $_layout; $cr->move_to( $x, $y ); $cr->set_source_rgba( 0, 0, 0, 1 ); Pango::Cairo::show_layout( $cr, $layout ); my $dx = ($layout->get_size)[0]/$PANGO_SCALE; showbb( $x, $y ); return $dx; } # Shows the bounding box of the last piece of text that was rendered. sub showbb { my ( $x, $y ) = @_; # Show origin. _showloc( $x, $y ); # Bounding box, top-left coordinates. my @e = $layout->get_pixel_extents; for ( 1, 0 ) { printf( "%-7s %6.2f %6.2f %6.2f %6.2f\n", (qw(Ink: Layout:))[$_], @{%{e[$_]}}{qw( x y width height )} ); } # NOTE: Some fonts include natural spacing in the bounding box. # NOTE: Some fonts exclude accents on capitals from the bounding box. # Show baseline. $cr->save; $cr->set_source_rgb(1,0,1); $cr->set_line_width( 0.25 ); $cr->translate( $x, $y ); my %e = %{$e[1]}; _line( $e{x}, $layout->get_baseline/$PANGO_SCALE, $e{width}, 0 ); # Show BBox. $cr->rectangle( $e{x}, $e{y}, $e{width}, $e{height} );; $cr->stroke; %e = %{$e[0]}; $cr->set_source_rgb(0,1,1); $cr->rectangle( $e{x}, $e{y}, $e{width}, $e{height} );; $cr->stroke; $cr->restore; } sub _showloc { my ( $x, $y, $d ) = @_; $x ||= 0; $y ||= 0; $d ||= 50; $cr->save; $cr->set_source_rgb(0,0,1); _line( $x-$d, $y, 2*$d, 0 ); _line( $x, $y-$d, 0, 2*$d ); $cr->restore; } sub _line { my ( $x, $y, $w, $h, $lw ) = @_; $lw ||= 0.5; $y = $y; $cr->save; $cr->move_to( $x, $y ); $cr->rel_line_to( $w, $h ); $cr->set_line_width($lw); $cr->stroke; $cr->restore; } 1; Text-Layout-0.037/tests/pango04.pl0000644000400000040000000000167014640222607014476 0ustar jvjv#!/usr/bin/perl use strict; use warnings; use utf8; use Pango; use Cairo; require "./pango00.pl"; # subs # Create document and graphics environment. my $surface = Cairo::PdfSurface->create( 'pango04.pdf', 595, 842 ); # A4 my $cr = Cairo::Context->create($surface); my $layout = Pango::Cairo::create_layout($cr); # Scale from Cairo (PDF) units to Pango. my $PANGO_SCALE = Pango->scale; # Select a font. my $font = Pango::FontDescription->from_string('AR PL New Sung 60'); $layout->set_font_description($font); $layout->get_context->set_base_gravity('west'); # Start... my $x = 0; my $y = 842-700; # Left align text. $layout->set_width( 595 * $PANGO_SCALE ); $layout->set_alignment("left"); # FireFly is TTB. # WARNING: If the font cannot be found, a substitute font may come out LTR!. $layout->set_markup("懶惰的姜貓"); $cr->translate(300,100); $cr->rotate(2*atan2(1,1)); showlayout( $cr, $layout, $x, $y ); # Ship out. $cr->show_page; Text-Layout-0.037/tests/strikes.pl0000644000400000040000000000243214640222607014707 0ustar jvjv#!/usr/bin/perl use strict; use warnings; use utf8; my $verbose = 1; use PDF::API2; my $pdf = PDF::API2->new; $pdf->default_page_size("a4"); my $page = $pdf->page; my $text = $page->text; #my $font = $pdf->corefont('Times-Roman'); my $font = $pdf->ttfont( $ENV{HOME} . '/.fonts/DejaVuSerif.ttf'); $text->font( $font, 40 ); $text->translate(50,500); $text->text("the quick brown fox _ ", -underline => ["auto","auto"] ); $text->text("jumps", -underline => ["auto","auto"] ); use lib 'lib'; use Text::Layout; warn("Text::Layout version ", $Text::Layout::VERSION, "\n"); my $layout = Text::Layout->new($pdf); # Select a font. $font = Text::Layout::FontConfig->from_string("DejaVuSerif 40"); $layout->set_font_description($font); #$font->set_shaping; $layout->set_markup( qq{the quick brown fox _ jumps} ); $layout->render( 50, 350, $text ); $font->{underline_thickness} = 45; $font->{underline_position} = -140; $font->{strikeline_position} = 320; $font->{overline_position} = 600; $layout->set_markup( qq{the quick brown fox _ jumps} ); $layout->render( 50, 250, $text ); $pdf->save("strikes.pdf"); Text-Layout-0.037/tests/tl_c_04.pl0000644000400000040000000000341014640222607014444 0ustar jvjv#!/usr/bin/perl use strict; use warnings; use utf8; use PDF::API2; use lib "../lib"; use Text::Layout; use Text::Layout::FontConfig; eval { require HarfBuzz::Shaper } or warn("HarfBuzz::Shaper not found. Expect incorrect results!\n"); # Create document and graphics environment. my $pdf = PDF::API2->new(); $pdf->mediabox( 595, 842 ); # A4 # Set up page and get the text context. # Markup::Simple *only* uses the text context, and only for rendering. my $page = $pdf->page; my $text = $page->text; # Create a layout instance. my $layout = Text::Layout->new($pdf); # Setup the fonts. setup_fonts(); # Select a font. my $font = Text::Layout::FontConfig->from_string("AR-PL-New-Sung 60"); $layout->set_font_description($font); # Start... my $x = 200; my $y = 500; # Left align text. $layout->set_width(195); $layout->set_alignment("left"); my $t = "懶惰的姜貓"; # FireFlySung is TTB. $layout->set_markup($t); showlayout( $x, $y ); $x = 0; $y = 700; $layout->set_width(595); $font->set_direction('ltr'); showlayout( $x, $y ); # Ship out. $pdf->saveas("tl_c_04.pdf"); ################ Subroutines ################ my $gfx; sub showlayout { my ( $x, $y ) = @_; $layout->show( $x, $y, $text); $gfx //= $page->gfx; $layout->showbb($gfx); } sub setup_fonts { # Register all corefonts. Useful for fallback. # Not required, skip if you have your own fonts. my $fd = Text::Layout::FontConfig->new; # $fd->register_corefonts; # Add font dir and register fonts. $fd->add_fontdirs( $ENV{HOME}."/.fonts", "/usr/share/fonts/" ); # Add FireFlySung (Chinese). Requires shaping. $fd->register_font( "fireflysung.ttf", "AR-PL-New-Sung", "", "", { shaping => 1, language => 'chinese', direction => 'ttb', nosubset => 1 } ); } Text-Layout-0.037/tests/md1.pl0000644000400000040000000000112414640222607013701 0ustar jvjv#!/usr/bin/perl use strict; use warnings; use utf8; use lib "../lib"; use Text::Layout::Markdown; # Create a layout instance. my $layout = Text::Layout::Markdown->new; binmode( STDOUT, ':utf8' ); # Text to render. $layout->set_markup( q{Áhe quick brown fox} ); # Render it. print $layout->show(), "\n"; # Text to render. $layout->set_markup( q{Áhe quick brown fox} ); # Right align text (will be ignored w/ Markdown). $layout->set_width(50); $layout->set_alignment("center"); # Render it. print $layout->show(), "\n"; Text-Layout-0.037/t/0000755000400000040000000000000014640222611011761 5ustar jvjvText-Layout-0.037/t/00-load.t0000644000400000040000000000110114611401705013274 0ustar jvjv#!perl -T use Test::More tests => 6; BEGIN { use_ok( 'Text::Layout::FontConfig' ); use_ok( 'Text::Layout' ); } note( "Testing Text::Layout $Text::Layout::VERSION, Perl $], $^X" ); eval { require HarfBuzz::Shaper; HarfBuzz::Shaper->VERSION(0.018); diag( "Shaping enabled (HarfBuzz::Shaper $HarfBuzz::Shaper::VERSION)" ); 1; } || note( "Shaping disabled (HarfBuzz::Shaper not found)" ); BEGIN { use_ok( 'Text::Layout::Markdown' ); use_ok( 'Text::Layout::PDFAPI2' ); use_ok( 'Text::Layout::Pango' ); use_ok( 'Text::Layout::Cairo' ); } Text-Layout-0.037/t/102-pdfapi.t0000644000400000040000000000600514177246042013723 0ustar jvjv#! perl use strict; use warnings; use utf8; use Test::More; if ( eval { require PDF::API2 } ) { plan tests => 32; } else { plan skip_all => "PDF::API2 not installed"; } #### All this has been tested. # Create PDF document, with a page and text content. my $pdf = PDF::API2->new; $pdf->mediabox( 595, 842 ); # A4 my $page = $pdf->page; my $text = $page->text; # Create a layout. require Text::Layout; my $layout = Text::Layout->new($pdf); isa_ok( $layout, 'Text::Layout::PDFAPI2', 'Implicit backend' ); # Create a FontConfig. require Text::Layout::FontConfig; my $fc = Text::Layout::FontConfig->new; # Register some (core) fonts. $fc->register_font( "Times-Roman", "Serif" ); $fc->register_font( "Times-Bold", "Serif", "Bold" ); $fc->register_font( "Times-Italic", "Serif", "Italic" ); $fc->register_font( "Times-BoldItalic", "Serif", "BoldItalic" ); # Lookup a font by description. my $fd = $fc->from_string("Serif 20"); #### End pre-tested setup. # Apply the font to the layout. $layout->set_font_description($fd); is( $layout->get_font_description->to_string, "Serif 20", "Font desc"); # Put some text in the layout. $layout->set_markup("The quick brows fox"); # Get baseline. Since we're working top-left this is a negative value. my $v = $layout->get_baseline; fuzz( $v, -13.66, "baseline $v" ); $v = $layout->get_iter->get_baseline; fuzz( $v, -13.66, "baseline $v" ); # Get width/height. my @a = $layout->get_pixel_size; fuzz( $a[0], 166.08, "pixel_size width $a[0]" ); fuzz( $a[1], 18.00, "pixel_size height $a[1]" ); my $a = $layout->get_pixel_size; fuzz( $a->{width}, 166.08, "pixel_size width $a->{width}" ); fuzz( $a->{height}, 18.00, "pixel_size height $a->{height}" ); # get_size should return the same, since we're not using Pango units. @a = $layout->get_size; fuzz( $a[0], 166.08, "size width" ); fuzz( $a[1], 18.00, "size height" ); $a = $layout->get_size; fuzz( $a->{width}, 166.08, "size width" ); fuzz( $a->{height}, 18.00, "size height" ); # Get extents my @ink = qw( ink layout ); my @fields = qw( x y width height ); # Subtracting height from y was introduced in 0.028. my $res = { x => 0.00, y => -18.00, width => 166.08, height => 18.00 }; # This case cannot calculate ink. my $ink = $res; my $inkres = [ $res, $ink ]; # Scalar call should yield layout values. $a = $layout->get_pixel_extents; for my $f ( @fields ) { fuzz( $a->{$f}, $res->{$f}, "pixel_extents @{[$ink[1]]} $f @{[$a->{$f}]}" ); } # List call should yield [ res ink ]. @a = $layout->get_pixel_extents; for ( 0, 1 ) { my $a = $a[$_]; for my $f ( @fields ) { fuzz( $a->{$f}, $inkres->[$_]{$f}, "pixel_extents[$_] @{[$ink[$_]]} $f @{[$a->{$f}]}" ); } } # Same, using Pango units (but we do not). @a = $layout->get_extents; for ( 0, 1 ) { my $a = $a[$_]; for my $f ( @fields ) { fuzz( $a->{$f}, $inkres->[$_]{$f}, "extents[$_] @{[$ink[$_]]} $f @{[$a->{$f}]}" ); } } # Big bang? $layout->show( 100, 500, $text ); sub fuzz { ok( $_[0] < $_[1]+0.01 && $_[0] > $_[1]-0.01, $_[2] ) } Text-Layout-0.037/t/Polo-SemiScript.ttf0000644000400000040000000005300414177246042015504 0ustar jvjvpFFTMWUGDEFT*GPOSDUtrGSUBwUXOS/2x:xVcmap>kPgaspTglyf8? CheadNH6hhea4$hmtx?locaJ maxpLxX name+OpostZRlyA'M_< I~Z~u@1@ HPfEd  8Z My((S, FE" # >_K!`# LA$jg<K)!I!0  )=a!&!%( *)X"^*00 ) ) )I,F*N@~1BSax~    " & 0 : D!"!&"""""""+"H"`"e% 1AR`x}    & 0 9 D!"!&"""""""+"H"`"d%d55Gߋ޷ެެޕޒހPQLb   #$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~&\\\JpppppFh8vBBBB.p $ 4 T N H zn84d\TBJJ^LtbbPPPpp : : ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!3q"4>'>CX  Dp   !1(p7'&76&67>.'&U    n =,/<d0  %- (S9C#&7&/722>767.'>7&>7&&>07  A` @ E  k7. '  9 $='*   ^FD: S U $B 22b/1*"%7,"  * 0 [: "6_JV67>76.'676'&7676'.#'&'4>7.6/>%  H=$ .  !      (;AG,!#E  L s M*8BK;   ;.+!. $*,/5  1%+%O0RN1B_p| ,.'4>7>^%      2$a76&467>&'&0+ M  [#F> ",3q"4>'>CX  Dp   ! n 7&.'&05% ' n6$ :!?6>72&'&>8B#  / :Y[ [fI~+%h<" %:4/vs+6&'&7>766&'&7sE{&-./4 :5 eI49U* A5 >Zi >:ZX]P,-# " (&$% 2$j(&'.>5&&'&627>76&66' %P +/ "j 0#H-    1  /'"&bC2"&#&7>27>73".'.?>76=% 1 &&'*"26b  +* NG^%"  ,"r)b!)  8+6S? 3d& &05 "u9$xM63>7'.'&>762>3>7.'&'.7>7'&'&- 4*" Pq T0 ' :O\$Cz 3Q (.6\@s ]%68)0 v         cA   $>!`n#,C>7&'.''&7>76.''.#2676{4"*9%-0 8! # (2 1  I3&  /7vUw* @- #44  2@];  Gu#oB.#'6'.4767>7>7&'&'.4'6&6YC  |q I3(RCR G788860 2 oH  ".  #eN.!  C. [ .HP= p;.>76'.#6#.'&762'.'&'&67>/#6B*-$ * 0(i$@K?'  [2)LHbzl$ CK  %")  ZEt 3hUABl7@7267&/.'.'64677>7'&.'&76&6/%  I!+,.7>W' H <,b# D8/ '"-) zH-$G;$a. ;  T0c+ )%&  D'g% 52  #! H6YP39>A/#X$. 97m-9>".'>7"'.4766&'fLT) q2&w$A k   ),&F#1 e%:2 & #"! i   %LP3'?  g6p( %-R6.'>6&'.>F    G  &  y( -! 0" !.\i#6'.66#>7{    / *# b  3. :=( ,$;f2E>>7>'>7>'&.'&6&'&>r"k  6V% ="M98 R & $P!c +  3 8" " ,Xs # E>$p2, &2"G   ! 1?R6&&'$'"&.'46'.'>27#>>5..'326s)1 ,(0  = * " & -+8 !N(5  :G< 2, *|5 t(;9#  :( 91 $x 9    x(7GT>&'&'.776.'.'4&4&7>.'7>&'636$DI= W8& ]\!2  !/.$  5J/4".7"'k. + qz/*,*?5('6,` /$  &Xq?V  LP*1$K] 08= AN $486>'&'>7>76&'&7>7>'.'>3  3?  *q E)` 8F  YA2cl&uR$L6#D*b  27@ D!A~ 6 Co E^,:'&'6677&6'.'.67>.'>>3 JG6  ( H)  #  C j   j]-e *%6 S*@  h - 2i& B5,,2c74&##3>2$7&'&'4>7&4&'&'>7'.'4&47$.>7>6&6D$ hU& $GN '"Q  W<"MMrb4O '# 7- &NE (&( ( s?  =  )*', @ -2 8$  C' )} (     HT\6$767>'&'.7.'&>767&67.'.'&7&'3>6&6M 3YPJ  Q  V (,      "0 $D& 8   4 +"% ! !    kG .?Q  T>.'767'.'4&>6&27&&'.'7>7.3#HQ.+Tu)E/' =XA !RH8 o4W$)#;T   5C&5g>G  W^?N>: * ),   #-  /%&. v #<_>47&7636&'".'.'>&7'&'.'.'&/.54&76676'>D    X   9     \ & gD 7, 6   %$! ~  /at#2<    ,+ K.% =G 9 ! F q 7&'6'&'4>0 $   W'    e*6N =7'.'&'.7672>7'.#&'&7>7 CN  !2  V# 3 /# 05%Mm+M %0g/ &" C  -$63O7.'.'.'&'.7>4&5.657.'>367& 73.#.''&'>7.67>7&&'&>8/ 'O/ +C01    Gn e$%)   '*Q'#V@e +)  fi #!$  .J lD]N"     $La6>7>76>727..'&467.'""'67.'.%.'&'6.!(F)+D(      ] $- /( !  " $#.6^ L fO;pS ! 4   ,w  `G,I5 #%:V  qxA6>76636&7.'.'.'&'&'.60 )2/.$/ $E 47r?8  @ "F  +7M @:0 $< eA?H /57  N >: 408.<=0'&'.7>7>76&'&'676&736PL3 +$BDBT> V; c=c)&4  1l-  )dWY/B+ ,BhDvQ+V   NTQ:D>'&6'.'&7>&76&67&"##.6.'>N@r$ ];D? ) yM  OkG9 [T&x  %/X>=, oU  jR=EJq03 $yI67.'&'&6&'.5&67>6>7>'.'&5>,)%/ /# <J2IR,  +/4B&Y,!_z  6 "'4 0$1WB1;8MA1!  G$  I0a6 'k=#  M[+ wQ>.'&'"'647.767667>762>76.'..7>usS[  ! P   Cp6w) TdM|*EV+,2  4|>7 -.    7#% 6\8dB ( O&!! N!O#4>&'.*#&'4>7>'.7>674.'.'\E  "Sw+>*p8L7.=4ژ.\4@oO !cOTC4H>  &, 6"  7[_570,/fFN   1'#>367"#&&'&6'.'74674.'*.'.>76l)' !&!  .T'       E(9   0  H   #46a&7 3%* !* 0D6>74&4676&'.'&#&'&76'.762^5/ <( $+( 2: H:(  !  # &Y:   1 Ao0 )1AF q=&#&'&'6&67>&5&"'>7>76W/ # $T >.  ', T   A [- &IN6!6  $N=X0c$n+   `t=!)~[d%&'&'&66367>76>726?676"'.'&..'37 k' E0%h )     !' f. 8 <%I(    `2D DW =]'= A ;)/ BI5E  VEO5(;C %1-) O + 5*:G.'&'#&&6'4>7>76&'.'&'>73>76&36 ^aIA"- I57&  6 / h[0 *L @:& 8S=$ : H8N^1 5 X&xT!!)+c!FM27>7'&565667>7&'.'&'>76>7>76n;SFQW  S3  ! ? .p  9+* 6 0"HP+HN1]      `# 9, ;0  "Xt N ,uGNW\@!#IN_636"&%"'&7>?.'.76675&&'.'67>&.&'$>0%+#G[  (LH&MA7 [[cYF =y}>P+WTq" 4(S$J [!,  .// 7$ " DH`   "/ & "*% &!(=77&'4.7.'#'.'&>7>76#67>j    :3t}/ 61%Zu)/  ak TI- 8] L)$ +)KB,5I#  W :+h%63676&'&&'7&7>.7676",\W#}M<  # 2'%V<h K$C-8E q.'>7'&'&67>   1At#*Z5e &R74(u'@ P:".?; ;2z359 g(3'.'#'&7>76&76&7>g    & % &#(* 2iC1 " T<g AIE1 Ch :, -{Fk)3 HR)0)+:2.'""&'7'.7676&'&> K<3   ;. @+t!w5&3  A3?    @2P H$g2W1#p)    "oK6#&6'&#&65464'&"'.'.&74>>'&746."&#&'6Y8 E    0  $  8l8B6-  ( +J C( sV%%%Sk   m0#!LGMY.'&'.'4&476267>&'&'.67>762636&4&726.    R_m2' 5.SO3 -} D!(9@&jG7>:.'&4'.#.'&6'.67>k&#  !,      ()    _!gk5 ;6S ( =K>  R|EhY*\ '&'6>>3.'&$" &-5  K \ !2 wWJ4 Z .62&'&66'.'&676768   ( (# ( # D N  #."$`Fs ' %6g: MW -%sG>>7>74'672>'.''&6'46&'&67454.+  *P?E^Hi+2@   d  $ 7--&BJ 0 3" N  % ;! "U]n!>>363&.56&62 "(    < A7N^  %.H}(C263>72>&'&6'&'&#.6'&&/6,E10   RE' @! g ]%$26 `$> a A (; K& n?Z o  -> 167>2?'.'&&'>74. 0( +$.  J$6 $!  =VX. &^ FSXQ I N)C6'63676'&&5467>'.'&6nSM H'$5 S4V )]$ >'D/H'~5 -;"W#Nh) - '2:9 L1G*;2H>>'.'.>'.?67&'4.'&7>&/ ./( 8U   \ c/  4  s_7\ 1($HB / 12:+ V 4((9E B2G&>7>7"&#&>'&6'&'&676642>7>&4$  #'  +tW#%zX'<     M  &}B7 M N 79y0p){+/RM   -27"9(>726#>'&.'&'6'( 3 #   . :/  !0. I  kk Q F!"  /y=.'&'>726>7>7'.'>7>H.*2<#td   [(. D&" )( IM .*     "<V7$    ,8@ )C266&.'.'&&'&7676&g(A -" $ $  "  = jKo B 0"/    <( ,17>7>.'.64'#&'.'6z  X"+ !      TO4* Dnj K"E# 6;*GR (06\&B'u0,7>7&>76.'.'.'.'69?1 C :  S  # 8,((. '. ."5 ! ?4 -?27>7>?>'>7&'&'/.'>6%( B   $3 /' X #@3I<1fE4*7-5'7=*  * $ U9 >  A<  7E7>'.''&'&?6&'.676674&#  -$+-  (")&(   \  - +$,"1 X8,    /- Je =* *29'&'.>?.'&7>>67+      2!-CA2 3!(0 (9(s1     " [Kko 2=MI?D9en?O6672&7>7.76?4&5.656&76'.67> W(*   #0+;4 '    WQ #]=)K/ e  ;      ! 23     G "  ] 6K'&'677&'4.7.'#'.'&>7>76#67>$" &-    :3t}/ 61%Zu)/  ak] !2 w TI- 8] L)$ +)KB,5I#  W :+};P"'&'&#'&'677&'4.7.'#'.'&>7>76#67>To(  &-[    :3t}/ 61%Zu)/  ak}u 22 w TI- 8] L)$ +)KB,5I#  W :+)g 9H'&'62.'""&'7'.7676&'&>x$" &-K<3   ;. @+t!w5&3  g !2 wA3?    @2P H$g2W1#p)    )}>M"'&'&#'&'62.'""&'7'.7676&'&>"o(  &-CK<3   ;. @+t!w5&3  }u 22 wA3?    @2P H$g2W1#p)    )s GV'&'6''&'62.'""&'7'.7676&'&>$" &-k$" &-\K<3   ;. @+t!w5&3  ] !2 w !2 wA3?    @2P H$g2W1#p)    [ '&'6>>3.'&$" &-B5  K [ !2 wWJ4 }%"'&'&#'&'6>>3.'&vo(  &-5  K }u 22 wWJ4 Gs .'&'6''&'6>>3.'&$" &-k$" &-55  K ] !2 w !2 wWJ4 g 5'&'663676'&&5467>'.'&6[$" &-SM H'$5 S4V )]$ >'D/H'g !2 w5 -;"W#Nh) - '2:9 L1G}:"'&'&#'&'663676'&&5467>'.'&6 o(  &-ZSM H'$5 S4V )]$ >'D/H'}u 22 w5 -;"W#Nh) - '2:9 L1Gs C'&'6''&'663676'&&5467>'.'&6$" &-k$" &-GSM H'$5 S4V )]$ >'D/H'] !2 w !2 w5 -;"W#Nh) - '2:9 L1Gm ?'&'67>7>.'.64'#&'.'6X$" &-  X"+ !      TO4* Dm !2 wnj K"E# 6;*GR (06\&B'u0}D"'&'&#'&'67>7>.'.64'#&'.'6o(  &-G  X"+ !      TO4* D}u 22 wnj K"E# 6;*GR (06\&B'u0u M'&'6''&'67>7>.'.64'#&'.'6$" &-g$" &-?  X"+ !      TO4* Dg !2 w !2 wnj K"E# 6;*GR (06\&B'u0111,.'4>7>^%      2$1117p ,S n   X    Polo Script v.1 bt David Rakowski. All Rights Reserved.Polo Script v.1 bt David Rakowski. All Rights Reserved.Polo-SemiScriptPolo-SemiScriptSemiScriptSemiScriptFontForge 2.0 : Polo-SemiScript : 11-12-2021FontForge 2.0 : Polo-SemiScript : 11-12-2021Polo-SemiScriptPolo-SemiScriptVersion 001.001 Version 001.001 Polo-SemiScriptPolo-SemiScript      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`a bcdefghijklmnopqrstuvwxyz{|}~NULHTLFCRDLEDC1DC2DC3DC4RSUSDELnbspaceuni03BCuni2206uni2126 " ,latnliga oli ,latnkern.$ljhhjIdjqOIText-Layout-0.037/t/152-pdfbuilder.t0000644000400000040000000000613214177771221014610 0ustar jvjv#! perl use strict; use warnings; use utf8; use Test::More; if ( eval { require PDF::Builder } ) { if ( $PDF::Builder::VERSION eq '3.018' ) { plan skip_all => "PDF::Builder incompatible version"; } else { plan tests => 31; } } else { plan skip_all => "PDF::Builder not installed"; } #### All this has been tested. # Create PDF document, with a page and text content. my $pdf = PDF::Builder->new; $pdf->mediabox( 595, 842 ); # A4 my $page = $pdf->page; my $text = $page->text; # Create a layout. require Text::Layout::PDFAPI2; my $layout = Text::Layout::PDFAPI2->new($pdf); # Create a FontConfig. require Text::Layout::FontConfig; my $fc = Text::Layout::FontConfig->new; # Register some (core) fonts. $fc->register_font( "Times-Roman", "Serif" ); $fc->register_font( "Times-Bold", "Serif", "Bold" ); $fc->register_font( "Times-Italic", "Serif", "Italic" ); $fc->register_font( "Times-BoldItalic", "Serif", "BoldItalic" ); # Lookup a font by description. my $fd = $fc->from_string("Serif 20"); #### End pre-tested setup. # Apply the font to the layout. $layout->set_font_description($fd); is( $layout->get_font_description->to_string, "Serif 20", "Font desc"); # Put some text in the layout. $layout->set_markup("The quick brows fox"); # Get baseline. Since we're working top-left this is a negative value. my $v = $layout->get_baseline; fuzz( $v, -13.66, "baseline $v" ); $v = $layout->get_iter->get_baseline; fuzz( $v, -13.66, "baseline $v" ); # Get width/height. my @a = $layout->get_pixel_size; fuzz( $a[0], 166.08, "pixel_size width $a[0]" ); fuzz( $a[1], 18.00, "pixel_size height $a[1]" ); my $a = $layout->get_pixel_size; fuzz( $a->{width}, 166.08, "pixel_size width $a->{width}" ); fuzz( $a->{height}, 18.00, "pixel_size height $a->{height}" ); # get_size should return the same, since we're not using Pango units. @a = $layout->get_size; fuzz( $a[0], 166.08, "size width" ); fuzz( $a[1], 18.00, "size height" ); $a = $layout->get_size; fuzz( $a->{width}, 166.08, "size width" ); fuzz( $a->{height}, 18.00, "size height" ); # Get extents my @ink = qw( ink layout ); my @fields = qw( x y width height ); # Subtracting height from y was introduced in 0.028. my $res = { x => 0.00, y => -18.00, width => 166.08, height => 18.00 }; # This case cannot calculate ink. my $ink = $res; my $inkres = [ $res, $ink ]; # Scalar call should yield layout values. $a = $layout->get_pixel_extents; for my $f ( @fields ) { fuzz( $a->{$f}, $res->{$f}, "pixel_extents @{[$ink[1]]} $f @{[$a->{$f}]}" ); } # List call should yield [ res ink ]. @a = $layout->get_pixel_extents; for ( 0, 1 ) { my $a = $a[$_]; for my $f ( @fields ) { fuzz( $a->{$f}, $inkres->[$_]{$f}, "pixel_extents[$_] @{[$ink[$_]]} $f @{[$a->{$f}]}" ); } } # Same, using Pango units (but we do not). @a = $layout->get_extents; for ( 0, 1 ) { my $a = $a[$_]; for my $f ( @fields ) { fuzz( $a->{$f}, $inkres->[$_]{$f}, "extents[$_] @{[$ink[$_]]} $f @{[$a->{$f}]}" ); } } # Big bang? $layout->show( 100, 500, $text ); sub fuzz { ok( $_[0] < $_[1]+0.01 && $_[0] > $_[1]-0.01, $_[2] ) } Text-Layout-0.037/t/200-extents.t0000644000400000040000000000362114177246042014152 0ustar jvjv#! perl use strict; use warnings; use utf8; use Test::More; if ( eval { require PDF::API2 } ) { plan tests => 12; } else { plan skip_all => "PDF::API2 not installed"; } # Currently the extents method is implemented by the PDFAPI2 backend. use Text::Layout::PDFAPI2; -d "t" && chdir("t"); #### All this has been tested. # Create PDF document, with a page and text content. my $pdf = PDF::API2->new; # Create a font. # Polo-SemiScript was one of the smallest files I could find. my $fontfile = "Polo-SemiScript.ttf"; ok( -s $fontfile, "have $fontfile" ); my $font; eval { $font = $pdf->ttfont($fontfile)}; diag($@) if $@; ok( $font, "have font" ); my $text = "The quick brown fox"; my $e = $font->extents( $text, 64 ); ok( $e, "have extents" ); my $exp = { x => 1.6, y => -12.16, width => 550.336, height => 56.96, bl => 47.104}; for ( qw( x y width height bl ) ) { fuzz( $e->{$_}, $exp->{$_}, "extent $_ $e->{$_}" ); } augment($exp); for ( qw( xMin yMin xMax yMax ) ) { fuzz( $e->{$_}, $exp->{$_}, "extent $_ $e->{$_}" ); } # visualize( $text, $e ); sub visualize { my ( $txt, $e ) = ( @_ ); my $text = (my $page = $pdf->page)->text; my $gfx = $page->gfx; $gfx->translate(50,600); $gfx->linewidth(1); $gfx->rectxy( $e->{xMin}, $e->{yMin}, $e->{xMax}, $e->{yMax} ); $gfx->strokecolor("cyan"); $gfx->stroke; $gfx->linewidth(0.5); $gfx->rect( $e->{x}, $e->{y}, $e->{width}, $e->{height} ); $gfx->line( $e->{x}, 0, $e->{x}+$e->{width}, 0 ); $gfx->strokecolor("magenta"); $gfx->stroke; $text->font($font,64); $text->translate(50,600); $text->text($txt); $pdf->save("200.pdf"); } sub fuzz { ok( $_[0] < $_[1]+0.01 && $_[0] > $_[1]-0.01, $_[2] ) } sub augment { my $e = shift; $e->{xMin} = $e->{x}; $e->{yMin} = $e->{y}; $e->{xMax} = $e->{x} + $e->{width}; $e->{yMax} = $e->{y} + $e->{height}; } Text-Layout-0.037/t/11-markup.t0000644000400000040000000001167714507716150013710 0ustar jvjv#! perl # Basic markup parsing -- regular, bold, italic and overlaps. use strict; use Test::More tests => 10; use Text::Layout::Testing; my $layout = Text::Layout::Testing->new; my $xp = [ { font => 'Times-Roman(times,normal,normal,10)', size => 10, type => "text", text => 'The quick brown fox', }, ]; $layout->set_markup("The quick brown fox"); is_deeply( $layout->_debug_text, $xp ); $xp = [ { font => 'Times-Roman(times,normal,normal,10)', size => 10, type => "text", text => 'The quick ', }, { font => 'Times-Roman(times,normal,normal,10)', size => '8.333', type => "text", text => 'brown', }, { font => 'Times-Roman(times,normal,normal,10)', size => 10, type => "text", text => ' fox', }, ]; $layout->set_markup("The quick brown fox"); is_deeply( $layout->_debug_text, $xp ); $layout->set_markup("The quick brown fox"); is_deeply( $layout->_debug_text, $xp ); $xp = [ { font => 'Times-Roman(times,normal,normal,10)', size => 10, type => "text", text => 'The quick ', }, { font => 'Helvetica(sans,normal,normal,11)', size => 11, type => "text", text => 'brown', }, { font => 'Times-Roman(times,normal,normal,10)', size => 10, type => "text", text => ' fox', }, ]; # font_desc overrides fam/style/weight. $layout->set_markup("The quick brown fox"); is_deeply( $layout->_debug_text, $xp ); $xp = [ { font => 'Times-Roman(times,normal,normal,10)', size => 10, type => "text", text => 'The quick ', }, { font => 'Helvetica-BoldOblique(sans,italic,bold,10)', size => 10, type => "text", text => 'brown', }, { font => 'Times-Roman(times,normal,normal,10)', size => 10, type => "text", text => ' fox', }, ]; $layout->set_markup("The quick brown fox"); is_deeply( $layout->_debug_text, $xp ); $xp = [ { font => 'Times-Roman(times,normal,normal,10)', size => 10, type => "text", text => 'The ', }, { font => 'Times-Roman(times,normal,normal,10)', size => 10, underline => 'single', type => "text", text => 'quick', }, { font => 'Times-Roman(times,normal,normal,10)', size => 10, type => "text", text => ' ', }, { font => 'Times-Roman(times,normal,normal,10)', size => 10, underline => 'double', underline_color => 'blue', type => "text", text => 'brown', }, { font => 'Times-Roman(times,normal,normal,10)', size => 10, type => "text", text => ' fox', }, ]; $layout->set_markup("The quick brown fox"); is_deeply( $layout->_debug_text, $xp ); $xp = [ { font => 'Times-Roman(times,normal,normal,10)', size => 10, type => "text", text => 'The ', }, { font => 'Times-Roman(times,normal,normal,10)', size => 10, strikethrough => 1, type => "text", text => 'quick', }, { font => 'Times-Roman(times,normal,normal,10)', size => 10, type => "text", text => ' brown fox', }, ]; $layout->set_markup("The quick brown fox"); is_deeply( $layout->_debug_text, $xp ); $xp = [ { font => 'Times-Roman(times,normal,normal,10)', size => 10, type => "text", text => 'The ', }, { font => 'Times-Roman(times,normal,normal,10)', size => 10, strikethrough => 1, strikethrough_color => 'yellow', type => "text", text => 'quick', }, { font => 'Times-Roman(times,normal,normal,10)', size => 10, type => "text", text => ' brown fox', }, ]; $layout->set_markup("The quick brown fox"); is_deeply( $layout->_debug_text, $xp ); $xp = [ { font => 'Times-Roman(times,normal,normal,10)', size => 10, type => "text", text => 'The ', }, { font => 'Times-Roman(times,normal,normal,10)', size => 10, strikethrough => 1, strikethrough_color => 'yellow', type => "text", text => 'quick', }, { font => 'Times-Roman(times,normal,normal,10)', size => 10, strikethrough_color => 'yellow', type => "text", text => ' brown ', }, { font => 'Times-Roman(times,normal,normal,10)', size => 10, strikethrough => 1, strikethrough_color => 'yellow', type => "text", text => 'fox', }, ]; $layout->set_markup("The quick brown fox"); is_deeply( $layout->_debug_text, $xp ); $xp = [ { font => 'Times-Roman(times,normal,normal,10)', size => 10, type => "text", text => 'The quick ', }, { font => 'Times-Roman(times,normal,normal,10)', size => 10, overline => 'double', overline_color => 'red', type => "text", text => 'brown', }, { font => 'Times-Roman(times,normal,normal,10)', size => 10, type => "text", text => ' fox', }, ]; $layout->set_markup("The quick brown fox"); is_deeply( $layout->_debug_text, $xp ); Text-Layout-0.037/t/10-markup.t0000644000400000040000000000614014507716141013674 0ustar jvjv#! perl # Basic markup parsing -- regular, bold, italic and overlaps. use strict; use Test::More tests => 9; use Text::Layout::Testing; my $layout = Text::Layout::Testing->new; my $xp = [ { font => 'Times-Roman(times,normal,normal,10)', size => 10, type => "text", text => 'The quick brown fox', }, ]; $layout->set_markup("The quick brown fox"); is_deeply( $layout->_debug_text, $xp ); $xp = [ { font => 'Times-Roman(times,normal,normal,10)', size => 10, type => "text", text => 'The quick ', }, { font => 'Times-Bold(times,normal,bold,10)', size => 10, type => "text", text => 'brown', }, { font => 'Times-Roman(times,normal,normal,10)', size => 10, type => "text", text => ' fox', }, ]; $layout->set_markup("The quick brown fox"); is_deeply( $layout->_debug_text, $xp ); $layout->set_markup("The quick brown fox"); is_deeply( $layout->_debug_text, $xp ); $xp = [ { font => 'Times-Roman(times,normal,normal,10)', size => 10, type => "text", text => 'The quick ', }, { font => 'Times-Italic(times,italic,normal,10)', size => 10, type => "text", text => 'brown', }, { font => 'Times-Roman(times,normal,normal,10)', size => 10, type => "text", text => ' fox', }, ]; $layout->set_markup("The quick brown fox"); is_deeply( $layout->_debug_text, $xp ); $layout->set_markup("The quick brown fox"); is_deeply( $layout->_debug_text, $xp ); $xp = [ { font => 'Times-Roman(times,normal,normal,10)', size => 10, type => "text", text => 'The quick ', }, { font => 'Times-BoldItalic(times,italic,bold,10)', size => 10, type => "text", text => 'brown', }, { font => 'Times-Roman(times,normal,normal,10)', size => 10, type => "text", text => ' fox', }, ]; $layout->set_markup("The quick brown fox"); is_deeply( $layout->_debug_text, $xp ); $layout->set_markup("The quick brown fox"); is_deeply( $layout->_debug_text, $xp ); $xp = [ { font => 'Times-Roman(times,normal,normal,10)', size => 10, type => "text", text => 'The ', }, { font => 'Times-Italic(times,italic,normal,10)', size => 10, type => "text", text => 'quick ', }, { font => 'Times-BoldItalic(times,italic,bold,10)', size => 10, type => "text", text => 'brown', }, { font => 'Times-Roman(times,normal,normal,10)', size => 10, type => "text", text => ' fox', }, ]; $layout->set_markup("The quick brown fox"); is_deeply( $layout->_debug_text, $xp ); $xp = [ { font => 'Times-Roman(times,normal,normal,10)', size => 10, type => "text", text => 'The ', }, { font => 'Times-BoldItalic(times,italic,bold,10)', size => 10, type => "text", text => 'quick', }, { font => 'Times-Bold(times,normal,bold,10)', size => 10, type => "text", text => ' brown', }, { font => 'Times-Roman(times,normal,normal,10)', size => 10, type => "text", text => ' fox', }, ]; $layout->set_markup("The quick brown fox"); is_deeply( $layout->_debug_text, $xp ); Text-Layout-0.037/t/210-struts.t0000755000400000040000000000165714611401705014027 0ustar jvjv#! perl use strict; use warnings; use utf8; use Test::More; if ( eval { require PDF::API2 } ) { plan tests => 1; } else { plan skip_all => "PDF::API2 not installed"; } use Text::Layout::Testing; -d "t" && chdir("t"); # Create PDF document, with a page and text content. my $pdf = PDF::API2->new; my $text = "The quick brown fox"; my $layout = Text::Layout->new($pdf); my $fc = Text::Layout::FontConfig->new( corefonts => 1 ); $layout->set_font_description( $fc->from_string( "Times 20" ) ); $layout->set_markup($text); my @s = $layout->get_struts; my $exp = [ { _x => 0, width => 10, desc => undef, asc => undef, label => 'start' }, { _x => 178.3, desc => undef, asc => undef, width => 0, label => 'end' } ]; delete $s[0]->{_strut}; delete $s[1]->{_strut}; is_deeply( \@s, $exp, "struts" ); Text-Layout-0.037/t/150-pdfbuilder.t0000644000400000040000000000227313672413332014603 0ustar jvjv#! perl use strict; use warnings; use utf8; use Test::More; if ( eval { require PDF::Builder } ) { plan tests => 7; } else { plan skip_all => "PDF::Builder not installed"; } # Create PDF document, with a page and text content. my $pdf = PDF::Builder->new; ok( $pdf, "Create PDF" ); $pdf->mediabox( 595, 842 ); # A4 my $page = $pdf->page; ok( $page, "Create PDF page" ); my $text = $page->text; ok( $text, "Create PDF page text" ); # Create a layout. require Text::Layout::PDFAPI2; my $layout = Text::Layout::PDFAPI2->new($pdf); ok( $layout, "Create layout"); # Create a FontConfig. require Text::Layout::FontConfig; my $fc = Text::Layout::FontConfig->new; ok( $fc, "Get FontConfig" ); # Register some (core) fonts. $fc->register_font( "Times-Roman", "Serif" ); $fc->register_font( "Times-Bold", "Serif", "Bold" ); $fc->register_font( "Times-Italic", "Serif", "Italic" ); $fc->register_font( "Times-BoldItalic", "Serif", "BoldItalic" ); # Lookup a font by description. my $fd = $fc->from_string("Serif 20"); isa_ok( $fd, 'Text::Layout::FontDescriptor', "Get font desc" ); isa_ok( $fd->get_font($layout), 'PDF::Builder::Resource::Font::CoreFont', "Get font" ); Text-Layout-0.037/t/100-pdfapi.t0000644000400000040000000000225713672413201013716 0ustar jvjv#! perl use strict; use warnings; use utf8; use Test::More; if ( eval { require PDF::API2 } ) { plan tests => 7; } else { plan skip_all => "PDF::API2 not installed"; } # Create PDF document, with a page and text content. my $pdf = PDF::API2->new; ok( $pdf, "Create PDF" ); $pdf->mediabox( 595, 842 ); # A4 my $page = $pdf->page; ok( $page, "Create PDF page" ); my $text = $page->text; ok( $text, "Create PDF page text" ); # Create a layout. require Text::Layout::PDFAPI2; my $layout = Text::Layout::PDFAPI2->new($pdf); ok( $layout, "Create layout"); # Create a FontConfig. require Text::Layout::FontConfig; my $fc = Text::Layout::FontConfig->new; ok( $fc, "Get FontConfig" ); # Register some (core) fonts. $fc->register_font( "Times-Roman", "Serif" ); $fc->register_font( "Times-Bold", "Serif", "Bold" ); $fc->register_font( "Times-Italic", "Serif", "Italic" ); $fc->register_font( "Times-BoldItalic", "Serif", "BoldItalic" ); # Lookup a font by description. my $fd = $fc->from_string("Serif 20"); isa_ok( $fd, 'Text::Layout::FontDescriptor', "Get font desc" ); isa_ok( $fd->get_font($layout), 'PDF::API2::Resource::Font::CoreFont', "Get font" ); Text-Layout-0.037/lib/0000755000400000040000000000000014640222611012264 5ustar jvjvText-Layout-0.037/lib/Text/0000755000400000040000000000000014640222611013210 5ustar jvjvText-Layout-0.037/lib/Text/Layout/0000755000400000040000000000000014640222611014465 5ustar jvjvText-Layout-0.037/lib/Text/Layout/Cairo.pm0000644000400000040000000000027214640222607016066 0ustar jvjv#! perl use strict; use warnings; use utf8; use Carp; package Text::Layout::Cairo; sub new { my ( $pkg, @data ) = @_; croak("Text::Layout::Cairo: Not yet implemented"); } 1; Text-Layout-0.037/lib/Text/Layout/FontDescriptor.pm0000644000400000040000000000766114640222607020007 0ustar jvjv#! perl use strict; use warnings; use utf8; package Text::Layout::FontDescriptor; use Carp; our $VERSION = "0.037"; =head1 NAME Text::Layout::FontDescriptor - font description for Text::Layout =head1 SYNOPSIS Font descriptors are used internally by Text::Layout and Text::Layout::FontConfig. =cut =head1 METHODS =over =item new( [ %atts ] ) Creates a new FontDescriptor object. Attributes: =over =item family =item style =item weight The Family, style, and weight of this font. There are mandatory. For defaults, use an empty string. =item size Optional, font size. =item font The actual font data. =item loader A code reference to call to actually create/load the font if necessary. Loading will store the font data in the C property. =back =back =cut sub new { my ( $pkg, %atts ) = @_; my $self = bless { style => "", weight => "", %atts } => $pkg; return $self; } =over =item get_font Returns the actual font data for the font this descriptor describes. If necessary, the backend will be called to create/load the font. =back =cut sub get_font { my ( $self, $context ) = @_; $self->{font} ||= do { croak("Forgot to pass a layout context to get_font?") unless UNIVERSAL::isa( $context, 'Text::Layout' ); $context->load_font( $self->{loader_data}, $self ); }; } =over =item get_family =item get_style =item get_weight Accessors to the font family, style, and weight. Readonly. =back =cut sub get_family { my ( $self ) = @_; $self->{family}; } sub get_style { my ( $self ) = @_; $self->{style}; } sub get_weight { my ( $self ) = @_; $self->{weight}; } =over =item set_size =item get_size Sets/gets the size property of the font. =back =cut sub set_size { my ( $self, $size ) = @_; $self->{size} = $size; } sub get_size { my ( $self ) = @_; $self->{size}; } =over =item set_direction =item get_direction Sets/gets the direction property of the font. =back =cut sub set_direction { my ( $self, $direction ) = @_; $self->{direction} = $direction; } sub get_direction { my ( $self ) = @_; $self->{direction}; } # Not documented -- internal use only. sub set_shaping { my ( $self, $sh ) = @_; $self->{shaping} = $sh // 1; } sub get_shaping { my ( $self ) = @_; $self->{shaping}; } # Not documented -- internal use only. sub set_interline { my ( $self, $sh ) = @_; $self->{interline} = $sh // 1; } sub get_interline { my ( $self ) = @_; $self->{interline}; } # Not documented -- internal use only. # Note that the ascender/descender values are filled in at load time, # unless overridden by a set_... call. sub set_ascender { my ( $self, $asc ) = @_; $self->{ascender} = $asc; } sub get_ascender { my ( $self ) = @_; $self->{ascender}; } sub set_descender { my ( $self, $desc ) = @_; $self->{descender} = $desc; } sub get_descender { my ( $self ) = @_; $self->{descender}; } =over =item to_string Returns a Pango-style font string, C. =back =cut sub to_string { my ( $self ) = @_; my $desc = ucfirst( $self->{family} ); $desc .= ucfirst( $self->{style} ) if $self->{style} && $self->{style} ne "normal"; $desc .= " " . ucfirst( $self->{weight} ) if $self->{weight} && $self->{weight} ne "normal"; $desc .= " " . $self->{size} if $self->{size}; return $desc; } use overload '""' => \&to_string; =head1 SEE ALSO L, L. =head1 AUTHOR Johan Vromans, C<< >> =head1 SUPPORT This module is part of L. Development takes place on GitHub: L. You can find documentation for this module with the perldoc command. perldoc Text::Layout::FontDescriptor Please report any bugs or feature requests using the issue tracker for Text::Layout on GitHub. =head1 LICENSE See L. =cut 1; Text-Layout-0.037/lib/Text/Layout/Version.pm0000644000400000040000000000013614640222607016455 0ustar jvjv# This file is generated. Do not edit! package Text::Layout::Version; our $VERSION = "0.037"; Text-Layout-0.037/lib/Text/Layout/PDFAPI2/0000755000400000040000000000000014640222611015512 5ustar jvjvText-Layout-0.037/lib/Text/Layout/PDFAPI2/ImageElement.pm0000644000400000040000000002145114640222607020414 0ustar jvjv#! perl use v5.26; use warnings; use utf8; use Object::Pad; class Text::Layout::PDFAPI2::ImageElement :does(Text::Layout::ElementRole); =head1 NAME Text::Layout::PDFAPI2::ImageElement - element for PDF images =head1 DESCRIPTION This class implements support for an C<< >> element. It can be used to include inline images in marked-up texts. The class provides the three mandatory methods according to the requirements of L. =over 4 =item parse To parse the C<< >> tag in marked-up text. =item bbox To provide the augmented bounding box for the image. =item render To render the image using one of the PDF::API2 compatible libraries. =back An additional, overridable method getimage() is provided to actually produce the desired image object. See L =head1 THE C<< >> ELEMENT Note that the C<< >> element must be self-closed, i.e., end with C<< /> >>. The image is placed at the current location in the text and aligned on the baseline of the text. The image dimensions contribute to the resultant bounding box of the formatted text. See C and C below. All attributes are key=value pairs. The value should (but need not) be enclosed in quotes. Dimensional values may be a (fractional) number optionally postfixed by C or C, or a percentage. A number indicates points. C values are multiplied by the current font size and C values are multiplied by half the font size. =over 4 =item CI Provides the source of the image. This can be the filename of a jpg, png or gif image. =item CI The desired width for the image. Dimensional. The image is scaled if necessary. =item CI The desired height for the image. Dimensional. The image is scaled if necessary. =item CI A horizontal offset for the image, wrt. the current location in the text. Dimensional. =item CI Same, but vertical. Positive amounts move up. Note the direction is opposite to the Pango C. =item CI A scaling factor, to be applied I width/height scaling. The value may be expressed as a percentage. =item CI Align the image in the width given by CI. Possible alignments are C, C
, and C. =item CI If true, the actual bounding box of an object is used for placement. By default the bounding box is only used to obtain the width and height. This attribute has no effect on image objects. =item CI The advance width of the image. Dimensional. Default advance is the image width plus horizontal offset. This overrides the advance and may be zero. =item CI The advance height of the image. Dimensional. Default advance is the image height plus vertical offset. This overrides the advance and may be zero. =back =head1 CONSTRUCTOR This class is usually instantiated in a Text::Layout register_element call: $layout->register_element ( Text::Layout::PDFAPI2::ImageElement->new( pdf => $pdf ) ); =cut use constant TYPE => "img"; use Carp; use Text::Layout::Utils qw(parse_kv); field $pdf :param :accessor; use constant DEBUG => 0; method parse( $ctx, $k, $v ) { my %ctl = ( type => TYPE ); # Split the attributes. my $attr = parse_kv($v); while ( my ( $k, $v ) = each( %$attr ) ) { # Ignore case unless required. $v = lc $v unless $k =~ /^(src)$/; if ( $k =~ /^(src|bbox)$/ ) { $ctl{$k} = $v; } elsif ( $k eq "align" && $v =~ /^(left|right|center)$/ ) { $ctl{$k} = $v; } elsif ( $k =~ /^(width|height|dx|dy|w|h)$/ ) { $v = $1 * $ctx->{size} if $v =~ /^(-?[\d.]+)em$/; $v = $1 * $ctx->{size} / 2 if $v =~ /^(-?[\d.]+)ex$/; $v = $1 * $ctx->{size} / 100 if $v =~ /^(-?[\d.]+)\%$/; $ctl{$k} = $v; } elsif ( $k =~ /^(scale)$/ ) { $v = $1 / 100 if $v =~ /^([\d.]+)\%$/; $ctl{$k} = $v; } else { carp("Invalid " . TYPE . " attribute: \"$k\"\n"); } } return \%ctl; } method render( $fragment, $gfx, $x, $y ) { my $b = $self->bbox($fragment); my @bbox = @{$b->{bbox}}; my @bb = @{$b->{bb}}; my @abox = @{$b->{abox}}; my $width = $bb[2] - $bb[0]; my $height = $bb[3] - $bb[1]; my $img = $self->getimage($fragment); my $is_image = ref($img) =~ /::Image::/; my @a; if ( $is_image ) { @a = ( $x + $bb[0], $y + $bb[1], $width, $height ); warn("IMG x=$a[0], y=$a[1], width=$a[2], height=$a[3]\n") if DEBUG; } else { my ( $xscale, $yscale ) = @bb[4,5]; @a = ( $x + $bb[0], $y + $bb[1] - $yscale*($bbox[1]), $xscale, $yscale ); unless ( $fragment->{bbox} ) { $a[0] -= $xscale*($bbox[0]); } warn("OBJ x=${x}->$a[0], y=${y}->$a[1], width=$width, height=$height", ( $xscale != 1 || $yscale != 1 ) ? ", scale=$xscale" : "", ( $xscale != $yscale ) ? ",$yscale" : "", "\n") if DEBUG; } $gfx->object( $img, @a ); return { abox => \@abox }; } method bbox( $fragment ) { return $fragment->{_bb} if $fragment->{_bb}; my @bbox; # bbox of image or object my @bb; # bbox after scaling/displacement, plus scale factors my @abox; # advance box my $img = $self->getimage($fragment); my $is_image = ref($img) =~ /::Image::/; my $img_width; my $img_height; if ( $is_image ) { $img_width = $img->width; $img_height = $img->height; @bbox = ( 0, 0, $img_width, $img_height ); } else { @bbox = $img->bbox; @bbox[0,2] = @bbox[2,0] if $bbox[2] < $bbox[0]; @bbox[1,3] = @bbox[3,1] if $bbox[3] < $bbox[1]; $img_width = $bbox[2] - $bbox[0]; $img_height = $bbox[3] - $bbox[1]; } # Target width and height. my $width = $fragment->{width} || $img_width; my $height = $fragment->{height} || $img_height; # Calculate scale factors. my $xscale = 1; if ( $width != $img_width ) { $xscale = $width / $img_width; } my $yscale = $xscale; if ( $height != $img_height ) { $yscale = $height / $img_height; } # Apply custom scale. my $scale = $fragment->{scale} // 1; if ( $scale != 1 ) { $xscale *= $scale; $yscale *= $scale; $width *= $scale; $height *= $scale; } # Displacement wrt. the origin. my $dx = $fragment->{dx} || 0; my $dy = $fragment->{dy} || 0; if ( !$is_image && $fragment->{bbox} ) { $dx += $bbox[0] * $xscale; $dy += $bbox[1] * $yscale; } # Use the image baseline, if any. if ( $fragment->{base} ) { $dy += ( $bbox[1] - $fragment->{base} ) * $yscale; } @bb = ( $dx, $dy, $width + $dx, $height + $dy, $xscale, $yscale ); @abox = @bb; # Bounding box width/height. if ( defined $fragment->{w} ) { $abox[0] = 0; $abox[2] = $fragment->{w}; } if ( defined $fragment->{a} ) { $abox[3] = $fragment->{a}; } if ( defined $fragment->{d} ) { $abox[1] = $fragment->{d}; } if ( $fragment->{align} ) { if ( $fragment->{align} eq "right" ) { $bb[0] += $abox[2] - $width; } elsif ( $fragment->{align} eq "center" ) { $bb[0] += ($abox[2]-$width)/2; } } warn( ref($img) =~ /::Image::/ ? "IMG" : "OBJ", " bbox [@bbox]", " bb [@bb]", " abox [@abox]", ( $xscale != 1 || $yscale != 1 ) ? " scale=$xscale" : "", ( $xscale != $yscale ) ? ",$yscale" : "", "\n") if DEBUG; return $fragment->{_bb} = { bbox => \@bbox, bb => \@bb, abox => \@abox }; } =head1 IMAGE PRODUCER The image object is produced with a call to method getimage(), that can be overridden in a subclass. The method gets a hash ref as argument. This hash contains all the attributes and may be used for cacheing purposes. For example, method getimage ($fragment) { $fragment->{_img} //= $self->pdf->image($fragment->{src}); } An overridden getimage() may produce a PDF XObject instead of an image object. An XObject is treated similar to an image object, but is aligned according to its bounding box if attribute C is set to a I value, i.e., not zero. =cut method getimage ($fragment) { return $fragment->{_img} if $fragment->{_img}; my $src = $fragment->{src}; # API suports jpg, png, gif and tiff. # If we have the SVGPDF module, we can do SVG images. if ( $src =~ /\.svg$/i ) { local $SIG{__WARN__} = '__IGNORE__'; if ( eval "require SVGPDF" ) { $fragment->{_img} = SVGPDF->new( pdf => $pdf ) ->process( $src, combine => "stacked" )->[0]->{xo}; } # API will complain. } # Pass to API. $fragment->{_img} //= $pdf->image($src); } =head1 SEE ALSO L, L, L. =head1 AUTHOR Johan Vromans, C<< >> =head1 SUPPORT This class is part of . Development takes place on GitHub: L. Please report any bugs or feature requests using the issue tracker for Text::Layout on GitHub. =head1 LICENSE See L. =cut 1; Text-Layout-0.037/lib/Text/Layout/FontConfig.pm0000644000400000040000000005005014640222607017064 0ustar jvjv#! perl use strict; use warnings; use utf8; package Text::Layout::FontConfig; use Carp; our $VERSION = "0.037"; use Text::Layout::FontDescriptor; =head1 NAME Text::Layout::FontConfig - Pango style font description for Text::Layout =head1 SYNOPSIS Font descriptors are strings that identify the characteristics of the desired font. For example, C. The PDF context deals with physical fonts, e.g. built-in fonts like C and fonts loaded from font files like C. To map font descriptions to physical fonts, these fonts must be registered. This defines a font family, style, and weight for the font. Note that Text::Layout::FontConfig is a singleton. Creating objects with new() will always return the same object. =cut my %fonts; my @dirs; my %maps; my $loader; my $debug = 0; my $weights = [ 100 => 'thin', 100 => 'hairline', 200 => 'extra light', 200 => 'ultra light', 300 => 'light', # supported 350 => 'book', # supported 400 => 'normal', # supported 400 => 'regular', # supported 500 => 'medium', # supported 600 => 'semi bold', # supported 'semi' 600 => 'demi bold', 700 => 'bold', # supported 800 => 'extra bold', 800 => 'ultra bold', 900 => 'black', 900 => 'heavy', # supported 950 => 'extra black', 950 => 'ultra black', ]; =head2 METHODS =over =item new( [ atts... ] ) For convenience only. Text::Layout::FontConfig is a singleton. Creating objects with new() will always return the same object. Attributes: =over =item corefonts If true, a predefined set of font names (the PDF corefonts) is registered. =back =back =cut sub new { my ( $pkg, %atts ) = @_; my $self = bless {} => $pkg; $debug = $self->{debug} = $atts{debug}; if ( $atts{corefonts} ) { $self->register_corefonts; } if ( $atts{loader} ) { $loader = $atts{loader}; } return $self; } sub reset { my ( $self ) = @_; warn("FC: Reset\n") if $debug; %fonts = (); @dirs = (); %maps = (); } sub debug { shift->{debug} } =over =item register_fonts( $font, $family, $style [ , $weight ] [ , $props ] ) Registers a font fmaily, style and weight for the given font. $font can be the name of a built-in font, or the name of a TrueType or OpenType font file. $family is a font family name such as C, C, C, or C. It is possible to specify multiple family names, e.g., C. $style is the slant style, one of C, C, or C. $weight is the font weight, like C, or C. For convenience, style combinations like "bolditalic" are allowed. A final hash reference can be passed to specify additional properties for this font. Recognized properties are: =over =item * C - If set to a true value, this font will require text shaping. This is required for fonts that deal with complex glyph rendering and ligature handling like Devanagari. Text shaping requires module L. =item * C - If set overrides the font ascender. This may be necessary to improve results for some fonts. The value is expressed in 1/1000th of an em. C - If set overrides the font descender. This may be necessary to improve results for some fonts. The value is expressed in 1/1000th of an em. =item * C, C - Overrides the font specified or calculated values for underline thickness and/or position. This may improve results for some fonts. =item * C, C - Overrides the font specified or calculated values for strikeline thickness and/or position. This may improve results for some fonts. Note that strikeline thickness will default to underline thickness, if set. =item * C, C - Overrides the font specified or calculated values for overline thickness and/or position. This may improve results for some fonts. Note that overline thickness will default to underline thickness, if set. =back =back =cut sub register_font { shift if UNIVERSAL::isa( $_[0], __PACKAGE__ ); my $props; $props = pop(@_) if UNIVERSAL::isa( $_[-1], 'HASH' ); my ( $font, $family, $style, $weight ) = @_; if ( $style && !$weight && $style =~ s/^(heavy|bold|semi(?:bold)?|medium|book|light)//i ) { $weight = $1; } $style = _norm_style( $style // "normal" ); $weight = _norm_weight( $weight // "normal" ); my $ff; if ( $font =~ /\.[ot]tf$/ ) { if ( $font =~ m;^/; ) { $ff = $font if -r -s $font; } else { foreach ( @dirs ) { next unless -r -s "$_/$font"; $ff = "$_/$font"; last; } } } else { # Assume corefont. $ff = $font } croak("Cannot find font: ", $font, "\n") unless $ff; foreach ( split(/\s*,\s*/, $family) ) { $fonts{lc $_}->{$style}->{$weight}->{loader} = $loader; $fonts{lc $_}->{$style}->{$weight}->{loader_data} = $ff; warn("FC: Registered: $ff for ", lc($_), "-$style-$weight\n") if $debug; next unless $props; while ( my($k,$v) = each %$props ) { $fonts{lc $_}->{$style}->{$weight}->{$k} = $v; } } } =over =item add_fontdirs( @dirs ) Adds one or more file paths to be searched for font files. =back =cut sub add_fontdirs { shift if UNIVERSAL::isa( $_[0], __PACKAGE__ ); my ( @d ) = @_; foreach ( @d ) { unless ( -d -r -x ) { carp("Skipped font dir: $_ [$!]"); next; } push( @dirs, $_ ); } } =over =item register_aliases( $family, $aliases, ... ) Adds aliases for existing font families. Multiple aliases can be specified, e.g. $layout->register_aliases( "times", "serif, default" ); or $layout->register_aliases( "times", "serif", "default" ); =back =cut sub register_aliases { shift if UNIVERSAL::isa( $_[0], __PACKAGE__ ); my ( $family, @aliases ) = @_; carp("Unknown font family: $family") unless exists $fonts{lc $family}; foreach ( @aliases ) { foreach ( split( /\s*,\s*/, $_ ) ) { $fonts{lc $_} = $fonts{lc $family}; } } } =over =item register_corefonts( %options ) This is a convenience method that registers all built-in corefonts. Aliases for families C, C, and C are added unless $noaliases is specified. You do not need to call this method if you provide your own font registrations. Options: =over =item aliases If true, register Serif, Sans and Mono as aliases for Times, Helvetica and Courier. This is enabled by default and can be cancelled with C. =item noaliases If true, do not register Serif, Sans and Mono as aliases for Times, Helvetica and Courier. =item remap Remap the core fonts to real TrueType or OpenType font files. Supported values are C or C to use the GNU Free Fonts (http://ftp.gnu.org/gnu/freefont/) and C or C for the TeX Gyre fonts (https://www.gust.org.pl/projects/e-foundry/tex-gyre/). =back =back =cut sub register_corefonts { shift if UNIVERSAL::isa( $_[0], __PACKAGE__ ); my %options; if ( @_ == 1 ) { $options{noaliases} = shift; } else { %options = @_; } my $noaliases = defined($options{aliases}) ? !$options{aliases} : $options{noaliases}; warn("FC: Registering corefonts\n") if $debug; register_font( "Times-Roman", "Times" ); register_font( "Times-Bold", "Times", "Bold" ); register_font( "Times-Italic", "Times", "Italic" ); register_font( "Times-BoldItalic", "Times", "BoldItalic" ); register_aliases( "Times", "Serif" ) unless $noaliases; register_font( "Helvetica", "Helvetica" ); register_font( "Helvetica-Bold", "Helvetica", "Bold" ); register_font( "Helvetica-Oblique", "Helvetica", "Oblique" ); register_font( "Helvetica-BoldOblique", "Helvetica", "BoldOblique" ); register_aliases( "Helvetica", "Sans", "Arial" ) unless $noaliases; register_font( "Courier", "Courier" ); register_font( "Courier-Bold", "Courier", "Bold" ); register_font( "Courier-Oblique", "Courier", "Italic" ); register_font( "Courier-BoldOblique", "Courier", "BoldItalic" ); register_aliases( "Courier", "Mono", "Monospace", "fixed" ) unless $noaliases; register_aliases( "Courier", "Mono", "Monospace", "fixed" ) unless $noaliases; register_font( "ZapfDingbats", "Dingbats" ); if ( 0 ) { register_font( "Georgia", "Georgia" ); register_font( "Georgia,Bold", "Georgia", "Bold" ); register_font( "Georgia,Italic", "Georgia", "Italic" ); register_font( "Georgia,BoldItalic", "Georgia", "BoldItalic" ); register_font( "Verdana", "Verdana" ); register_font( "Verdana,Bold", "Verdana", "Bold" ); register_font( "Verdana,Italic", "Verdana", "Italic" ); register_font( "Verdana,BoldItalic", "Verdana", "BoldItalic" ); register_font( "WebDings", "WebDings" ); register_font( "WingDings", "WingDings" ); } # Corefont remapping to real font files. # Biggest problem is to make sure the fonts are installed, and with # the file names used here... $options{remap} //= ""; # GNU Free Fonts. # http://ftp.gnu.org/gnu/freefont/freefont-ttf-20120503.zip if ( $options{remap} =~ /^(?:gnu[-_]?)?free(?:[-_]?fonts)?$/i ) { remap( 'Times-Roman' => "FreeSerif.ttf", 'Times-BoldItalic' => "FreeSerifBoldItalic.ttf", 'Times-Bold' => "FreeSerifBold.ttf", 'Times-Italic' => "FreeSerifItalic.ttf", 'Helvetica' => "FreeSans.ttf", 'Helvetica-BoldOblique' => "FreeSansBoldOblique.ttf", 'Helvetica-Bold' => "FreeSansBold.ttf", 'Helvetica-Oblique' => "FreeSansOblique.ttf", 'Courier' => "FreeMono.ttf", 'Courier-BoldOblique' => "FreeMonoBoldOblique.ttf", 'Courier-Bold' => "FreeMonoBold.ttf", 'Courier-Oblique' => "FreeMonoOblique.ttf", ); } # TeX Gyre fonts. # https://www.gust.org.pl/projects/e-foundry/tex-gyre/whole/tg2_501otf.zip elsif ( $options{remap} =~ /^tex(?:[-_]?gyre)?$/i ) { remap( 'Times-Roman' => "texgyretermes-regular.otf", 'Times-BoldItalic' => "texgyretermes-bolditalic.otf", 'Times-Bold' => "texgyretermes-bold.otf", 'Times-Italic' => "texgyretermes-italic.otf", 'Helvetica' => "texgyreheros-regular.otf", 'Helvetica-BoldOblique' => "texgyreheros-bolditalic.otf", 'Helvetica-Bold' => "texgyreheros-bold.otf", 'Helvetica-Oblique' => "texgyreheros-italic.otf", 'Courier' => "texgyrecursor-regular.otf", 'Courier-BoldOblique' => "texgyrecursor-bolditalic.otf", 'Courier-Bold' => "texgyrecursor-bold.otf", 'Courier-Oblique' => "texgyrecursor-italic.otf", ); } elsif ( $options{remap} ) { croak("Unrecognized core remap set"); } } =over =item remap($font) =item remap( $src => $dst, ... ) Handles font remapping. The main purpose is to remap corefonts to real fonts. With a single argument, returns the remapped value, or undef if none. With a hash argument, maps each of the targets (keys) to a font file (value). This file must be present in one of the font directories. Alternatively, the key may be one of C, C and C and the value an already registered family. =back =cut sub remap { shift if UNIVERSAL::isa( $_[0], __PACKAGE__ ); return $maps{$_[0]} if @_ == 1; my %m = @_; while ( my ($k, $v ) = each %m ) { # Check for family map. if ( $k =~ /^(Courier|Times|Helvetica)$/ && defined $fonts{lc $v} ) { if ( $k eq 'Courier' ) { $maps{'Courier'} = $fonts{lc $v}{normal}{normal}{loader_data}; $maps{'Courier-Bold'} = $fonts{lc $v}{normal}{bold}{loader_data}; $maps{'Courier-Oblique'} = $fonts{lc $v}{italic}{normal}{loader_data}; $maps{'Courier-BoldOblique'} = $fonts{lc $v}{italic}{bold}{loader_data}; } elsif ( $k eq 'Helvetica' ) { $maps{'Helvetica'} = $fonts{lc $v}{normal}{normal}{loader_data}; $maps{'Helvetica-Bold'} = $fonts{lc $v}{normal}{bold}{loader_data}; $maps{'Helvetica-Oblique'} = $fonts{lc $v}{italic}{normal}{loader_data}; $maps{'Helvetica-BoldOblique'} = $fonts{lc $v}{italic}{bold}{loader_data}; } elsif ( $k eq 'Times' ) { $maps{'Times-Roman'} = $fonts{lc $v}{normal}{normal}{loader_data}; $maps{'Times-Bold'} = $fonts{lc $v}{normal}{bold}{loader_data}; $maps{'Times-Italic'} = $fonts{lc $v}{italic}{normal}{loader_data}; $maps{'Times-BoldItalic'} = $fonts{lc $v}{italic}{bold}{loader_data}; } next; } # Map font to corefont. my $ff; if ( $v =~ m;^/; ) { $ff = $v if -r -s $v; } else { foreach ( @dirs ) { next unless -r -s "$_/$v"; $ff = "$_/$v"; last; } } $maps{$k} = $ff or carp("Invalid font mapping ($v: $!)") } 1; } =over =item find_font( $family, $style, $weight ) Returns a font descriptor based on the given family, style and weight. On Linux, fallback using fontconfig. =back =cut sub find_font { shift if UNIVERSAL::isa( $_[0], __PACKAGE__ ); my $atts; $atts = pop(@_) if UNIVERSAL::isa( $_[-1], 'HASH' ); my ( $family, $style, $weight ) = @_; warn("FC: find_font( $family, $style, $weight )\n") if $debug; my $try = sub { if ( $fonts{$family} && $fonts{$family}->{$style} && $fonts{$family}->{$style}->{$weight} ) { my $ff = $fonts{$family}->{$style}->{$weight}; my %i = ( family => $family, style => $style, weight => $weight ); ; if ( $ff->{font} ) { $i{font} = $ff->{font}; } elsif ( $ff->{loader_data} ) { $i{loader_data} = $ff->{loader_data}; $i{loader} = $loader; $i{cache} = $ff; } else { return; } for ( qw( shaping ascender descender nosubset direction language underline_thickness underline_position strikeline_thickness strikeline_position overline_thickness overline_position ) ) { $i{$_} = $ff->{$_}; } if ( $debug ) { warn("FC: found( $i{family}, $i{style}, $i{weight} ) -> ", $i{loader_data}, "\n"); } return Text::Layout::FontDescriptor->new(%i); } }; $style = _norm_style( $style // "normal" ); $weight = _norm_weight( $weight // "normal" ); my $res = $try->(); return $res if $res; # TODO: Some form of font fallback. if ( _fallback( $family, $style, $weight ) ) { $res = $try->(); return $res if $res; } # Nope. croak("Cannot find font: $family $style $weight\n"); } =over =item from_string( $description ) Returns a font descriptor using a Pango-style font description, e.g. C. On Linux, fallback using fontconfig. =back =cut my $stylep = qr/^( (?:heavy|bold|semi(?:bold)?|medium|book|light)? (?:oblique|italic) )$/ix; my $weightp = qr/^( (?:heavy|bold|semi(?:bold)?|medium|book|light) (?:oblique|italic)? )$/ix; sub from_string { shift if UNIVERSAL::isa( $_[0], __PACKAGE__ ); my ( $description ) = @_; my $i = parse($description); my $res = find_font( $i->{family}, $i->{style}, $i->{weight} ); $res->set_size($i->{size}) if $res && $i->{size}; $res; } =over =item parse( $description ) Parses a Pango-style font description and returns a hash ref with keys C, C