From e2f017af7599617065e54b1ad68a0ccc6afaf980 Mon Sep 17 00:00:00 2001 From: gregor herrmann Date: Fri, 15 Dec 2023 21:25:39 +0100 Subject: New upstream version 3.026 --- lib/PDF/Builder/Annotation.pm | 148 +++- lib/PDF/Builder/Basic/PDF.pm | 2 +- lib/PDF/Builder/Basic/PDF/Array.pm | 73 +- lib/PDF/Builder/Basic/PDF/Bool.pm | 24 +- lib/PDF/Builder/Basic/PDF/Dict.pm | 59 +- lib/PDF/Builder/Basic/PDF/File.pm | 267 ++++-- lib/PDF/Builder/Basic/PDF/Filter.pm | 26 +- lib/PDF/Builder/Basic/PDF/Filter/ASCII85Decode.pm | 2 +- lib/PDF/Builder/Basic/PDF/Filter/ASCIIHexDecode.pm | 2 +- lib/PDF/Builder/Basic/PDF/Filter/FlateDecode.pm | 23 +- lib/PDF/Builder/Basic/PDF/Filter/LZWDecode.pm | 71 +- .../Builder/Basic/PDF/Filter/RunLengthDecode.pm | 2 +- lib/PDF/Builder/Basic/PDF/Literal.pm | 2 +- lib/PDF/Builder/Basic/PDF/Name.pm | 50 +- lib/PDF/Builder/Basic/PDF/Null.pm | 58 +- lib/PDF/Builder/Basic/PDF/Number.pm | 24 +- lib/PDF/Builder/Basic/PDF/Objind.pm | 109 ++- lib/PDF/Builder/Basic/PDF/Page.pm | 32 +- lib/PDF/Builder/Basic/PDF/Pages.pm | 102 ++- lib/PDF/Builder/Basic/PDF/String.pm | 58 +- lib/PDF/Builder/Basic/PDF/Utils.pm | 92 +- lib/PDF/Builder/Content.pm | 923 ++++++++++++++++----- lib/PDF/Builder/Content/Hyphenate_basic.pm | 2 +- lib/PDF/Builder/Content/Text.pm | 226 +++-- lib/PDF/Builder/Docs.pm | 574 +++++++++++-- lib/PDF/Builder/FontManager.pm | 69 +- lib/PDF/Builder/Lite.pm | 362 ++++++-- lib/PDF/Builder/Matrix.pm | 2 +- lib/PDF/Builder/NamedDestination.pm | 62 +- lib/PDF/Builder/Outline.pm | 188 ++++- lib/PDF/Builder/Outlines.pm | 2 +- lib/PDF/Builder/Page.pm | 322 ++++--- lib/PDF/Builder/Resource.pm | 26 +- lib/PDF/Builder/Resource/BaseFont.pm | 386 +++++++-- lib/PDF/Builder/Resource/CIDFont.pm | 87 +- lib/PDF/Builder/Resource/CIDFont/CJKFont.pm | 44 +- lib/PDF/Builder/Resource/CIDFont/TrueType.pm | 127 ++- .../Builder/Resource/CIDFont/TrueType/FontFile.pm | 2 +- lib/PDF/Builder/Resource/ColorSpace.pm | 34 +- lib/PDF/Builder/Resource/ColorSpace/DeviceN.pm | 14 +- lib/PDF/Builder/Resource/ColorSpace/Indexed.pm | 20 +- .../Builder/Resource/ColorSpace/Indexed/ACTFile.pm | 16 +- lib/PDF/Builder/Resource/ColorSpace/Indexed/Hue.pm | 14 +- .../Resource/ColorSpace/Indexed/WebColor.pm | 18 +- lib/PDF/Builder/Resource/ColorSpace/Separation.pm | 32 +- lib/PDF/Builder/Resource/Colors.pm | 2 +- lib/PDF/Builder/Resource/ExtGState.pm | 284 ++++++- lib/PDF/Builder/Resource/Font.pm | 34 +- lib/PDF/Builder/Resource/Font/BdFont.pm | 14 +- lib/PDF/Builder/Resource/Font/CoreFont.pm | 65 +- .../Builder/Resource/Font/CoreFont/bankgothic.pm | 2 +- lib/PDF/Builder/Resource/Font/CoreFont/courier.pm | 2 +- .../Builder/Resource/Font/CoreFont/courierbold.pm | 2 +- .../Resource/Font/CoreFont/courierboldoblique.pm | 2 +- .../Resource/Font/CoreFont/courieroblique.pm | 2 +- lib/PDF/Builder/Resource/Font/CoreFont/georgia.pm | 2 +- .../Builder/Resource/Font/CoreFont/georgiabold.pm | 2 +- .../Resource/Font/CoreFont/georgiabolditalic.pm | 2 +- .../Resource/Font/CoreFont/georgiaitalic.pm | 2 +- .../Builder/Resource/Font/CoreFont/helvetica.pm | 2 +- .../Resource/Font/CoreFont/helveticabold.pm | 2 +- .../Resource/Font/CoreFont/helveticaboldoblique.pm | 2 +- .../Resource/Font/CoreFont/helveticaoblique.pm | 2 +- lib/PDF/Builder/Resource/Font/CoreFont/symbol.pm | 2 +- .../Builder/Resource/Font/CoreFont/timesbold.pm | 2 +- .../Resource/Font/CoreFont/timesbolditalic.pm | 2 +- .../Builder/Resource/Font/CoreFont/timesitalic.pm | 2 +- .../Builder/Resource/Font/CoreFont/timesroman.pm | 2 +- .../Builder/Resource/Font/CoreFont/trebuchet.pm | 2 +- .../Resource/Font/CoreFont/trebuchetbold.pm | 2 +- .../Resource/Font/CoreFont/trebuchetbolditalic.pm | 2 +- .../Resource/Font/CoreFont/trebuchetitalic.pm | 2 +- lib/PDF/Builder/Resource/Font/CoreFont/verdana.pm | 2 +- .../Builder/Resource/Font/CoreFont/verdanabold.pm | 2 +- .../Resource/Font/CoreFont/verdanabolditalic.pm | 2 +- .../Resource/Font/CoreFont/verdanaitalic.pm | 2 +- lib/PDF/Builder/Resource/Font/CoreFont/webdings.pm | 2 +- .../Builder/Resource/Font/CoreFont/wingdings.pm | 2 +- .../Builder/Resource/Font/CoreFont/zapfdingbats.pm | 2 +- lib/PDF/Builder/Resource/Font/Postscript.pm | 101 ++- lib/PDF/Builder/Resource/Font/SynFont.pm | 10 +- lib/PDF/Builder/Resource/Glyphs.pm | 2 +- lib/PDF/Builder/Resource/PaperSizes.pm | 19 +- lib/PDF/Builder/Resource/Pattern.pm | 16 +- lib/PDF/Builder/Resource/Shading.pm | 2 +- lib/PDF/Builder/Resource/UniFont.pm | 68 +- lib/PDF/Builder/Resource/XObject.pm | 24 +- lib/PDF/Builder/Resource/XObject/Form.pm | 36 +- lib/PDF/Builder/Resource/XObject/Form/BarCode.pm | 37 +- .../Resource/XObject/Form/BarCode/codabar.pm | 17 +- .../Resource/XObject/Form/BarCode/code128.pm | 11 +- .../Resource/XObject/Form/BarCode/code3of9.pm | 17 +- .../Builder/Resource/XObject/Form/BarCode/ean13.pm | 17 +- .../Resource/XObject/Form/BarCode/int2of5.pm | 19 +- lib/PDF/Builder/Resource/XObject/Form/Hybrid.pm | 20 +- lib/PDF/Builder/Resource/XObject/Image.pm | 108 ++- lib/PDF/Builder/Resource/XObject/Image/GD.pm | 13 +- lib/PDF/Builder/Resource/XObject/Image/GIF.pm | 19 +- lib/PDF/Builder/Resource/XObject/Image/JPEG.pm | 10 +- lib/PDF/Builder/Resource/XObject/Image/PNG.pm | 19 +- lib/PDF/Builder/Resource/XObject/Image/PNG_IPL.pm | 16 +- lib/PDF/Builder/Resource/XObject/Image/PNM.pm | 13 +- lib/PDF/Builder/Resource/XObject/Image/TIFF.pm | 35 +- .../Builder/Resource/XObject/Image/TIFF/File.pm | 17 +- .../Builder/Resource/XObject/Image/TIFF/File_GT.pm | 17 +- lib/PDF/Builder/Resource/XObject/Image/TIFF_GT.pm | 18 +- lib/PDF/Builder/UniWrap.pm | 2 +- lib/PDF/Builder/Util.pm | 46 +- lib/PDF/Builder/ViewerPreferences.pm | 40 +- 109 files changed, 4652 insertions(+), 1372 deletions(-) (limited to 'lib/PDF/Builder') diff --git a/lib/PDF/Builder/Annotation.pm b/lib/PDF/Builder/Annotation.pm index db08e50..150dfe5 100644 --- a/lib/PDF/Builder/Annotation.pm +++ b/lib/PDF/Builder/Annotation.pm @@ -5,8 +5,8 @@ use base 'PDF::Builder::Basic::PDF::Dict'; use strict; use warnings; -our $VERSION = '3.025'; # VERSION -our $LAST_UPDATE = '3.024'; # manually update whenever code is changed +our $VERSION = '3.026'; # VERSION +our $LAST_UPDATE = '3.026'; # manually update whenever code is changed use PDF::Builder::Basic::PDF::Utils; use List::Util qw(min max); @@ -41,14 +41,18 @@ available icon set may be larger or smaller than given here, and some Readers activate an annotation on a single mouse click, while others require a double click. Not all features provided here may be available on all PDF Readers. -=over +=head2 new + + $annotation = PDF::Builder::Annotation->new() -=item $annotation = PDF::Builder::Annotation->new() +=over Returns an annotation object (called from $page->annotation()). It is normally I necessary to explicitly call this method (see examples). +=back + =cut # %opts removed, as there are currently none @@ -77,13 +81,13 @@ sub new { # note that %opts is given as the only format in most cases, as rect # is a mandatory "option" -=back - =head2 Annotation types -=over +=head3 link + + $annotation->link($page, %opts) -=item $annotation->link($page, %opts) +=over Defines the annotation as a launch-page with page C<$page> (within I document) and opts %opts (rect, border, color, I: see @@ -93,6 +97,8 @@ B that C<$page> is I a simple page number, but is a page structure such as C<$pdf-Eopenpage(page_number)>, I a Named Destination defined elsewhere. +=back + =cut # consider goto() as alias, for consistency with NamedDestination @@ -123,7 +129,11 @@ sub link { return $self; } -=item $annotation->pdf($pdffile, $page_number, %opts) +=head3 pdf, pdfile, pdf_file + + $annotation->pdf($pdffile, $page_number, %opts) + +=over Defines the annotation as a PDF-file with filepath C<$pdffile>, on page C<$page_number>, and opts %opts (rect, border, color, I: see @@ -138,6 +148,8 @@ Originally this method was named C, and then C but a recent PDF::API2 change made it C. For compatibility, it has been changed to C, with C and C still available as aliases. +=back + =cut sub pdfile { return pdf(@_); } ## no critic @@ -165,7 +177,11 @@ sub pdf { return $self; } -=item $annotation->launch($file, %opts) +=head3 launch, file + + $annotation->launch($file, %opts) + +=over Defines the annotation as a launch-file with filepath C<$file> (a local file) and options %opts (rect, border, color: see descriptions below). @@ -178,6 +194,8 @@ Originally this method was named C, but a recent PDF::API2 change made it C. For compatibility, it has been changed to C, with C still available as an alias. +=back + =cut sub file { return launch(@_); } ## no critic @@ -201,7 +219,11 @@ sub launch { return $self; } -=item $annotation->uri($url, %opts) +=head3 uri, url + + $annotation->uri($url, %opts) + +=over Defines the annotation as a launch-url with url C<$url> and options %opts (rect, border, color: see descriptions below). @@ -213,6 +235,8 @@ Originally this method was named C, but a recent PDF::API2 change made it C. For compatibility, it has been changed to C, with C still available as an alias. +=back + =cut sub url { return uri(@_); } ## no critic @@ -236,7 +260,11 @@ sub uri { return $self; } -=item $annotation->text($text, %opts) +=head3 text + + $annotation->text($text, %opts) + +=over Defines the annotation as a text note with content string C<$text> and options %opts (rect, color, text, open: see descriptions below). @@ -252,6 +280,8 @@ rectangle). The icon size is fixed, and its fill color set by C. Additional options: +=back + =over =item icon => name_string @@ -317,7 +347,11 @@ sub text { return $self; } -=item $annotation->markup($text, $PointList, $highlight, %opts) +=head3 markup + + $annotation->markup($text, $PointList, $highlight, %opts) + +=over Defines the annotation as a text note with content string C<$text> and options %opts (color, text, open, opacity: see descriptions below). @@ -328,6 +362,8 @@ C is the popup's label string, not to be confused with the main C<$text>. There is no icon. Instead, the annotated text marked by C<$PointList> is highlighted in one of four ways specified by C<$highlight>. +=back + =over =item $PointList => [ 8n numbers ] @@ -428,7 +464,11 @@ sub markup { return $self; } -=item $annotation->movie($file, $contentType, %opts) +=head3 movie + + $annotation->movie($file, $contentType, %opts) + +=over Defines the annotation as a movie from C<$file> with content (MIME) type C<$contentType> and @@ -440,6 +480,8 @@ player. It is known to play .avi and .wav files -- others have not been tested. Using Adobe Reader, it will not play .mpg files (unsupported type). More work is probably needed on this annotation method. +=back + =cut sub movie { @@ -475,7 +517,11 @@ sub movie { return $self; } -=item $annotation->file_attachment($file, %opts) +=head3 file_attachment + + $annotation->file_attachment($file, %opts) + +=over Defines the annotation as a file attachment with file $file and options %opts (rect, color: see descriptions below). Note that C applies to @@ -502,6 +548,8 @@ including the path, give the C option. Options: +=back + =over =item icon => name_string @@ -639,13 +687,13 @@ sub file_attachment { # =============== end of annotation types ======================== -=back - =head2 Internal routines and common options -=over +=head3 rect -=item $annotation->rect($llx,$lly, $urx,$ury) + $annotation->rect($llx,$lly, $urx,$ury) + +=over Sets the rectangle (active click area) of the annotation, given by 'rect' option. This is any pair of diagonally opposite corners of the rectangle. @@ -654,6 +702,8 @@ The default clickable area is the icon itself. Defining option. I.> +=back + =over =item rect => [LLx, LLy, URx, URy] @@ -673,7 +723,11 @@ sub rect { return $self; } -=item $annotation->border(@b) +=head3 border + + $annotation->border(@b) + +=over Sets the border-style of the annotation, if applicable, as given by the border option. There are three entries in the array: @@ -692,6 +746,8 @@ border C<[0 0 0]> (solid line of width 0, and thus invisible). Defining option: +=back + =over =item border => [CRh, CRv, W] @@ -731,11 +787,17 @@ sub border { return $self; } -=item $annotation->content(@lines) +=head3 content + + $annotation->content(@lines) + +=over Sets the text-content of the C annotation. This is a text string or array of strings. +=back + =cut sub content { @@ -753,7 +815,11 @@ sub name { return $self; } -=item $annotation->open($bool) +=head3 open + + $annotation->open($bool) + +=over Display the C annotation either open or closed, if applicable. @@ -762,6 +828,8 @@ already open for editing, while "closed" has to be clicked on to edit it. Defining option: +=back + =over =item open => boolean @@ -779,7 +847,11 @@ sub open { ## no critic return $self; } -=item $annotation->dest($page, I) +=head3 dest + + $annotation->dest($page, I) + +=over For certain annotation types (C or C), the I specifies how the content of the page C<$page> is to be fit to the window, @@ -789,11 +861,17 @@ These fit settings are listed in L. "xyz" is the B fit setting, with position (left and top) and zoom the same as the calling page's ([undef, undef, undef]). -=item $annotation->dest($name) +=back + + $annotation->dest($name) + +=over Connect the Annotation to a "Named Destination" defined elsewhere, including the optional desired I (default: xyz undef*3). +=back + =cut sub dest { @@ -842,7 +920,11 @@ sub dest { return $self; } -=item $annotation->Color(@color) +=head3 Color + + $annotation->Color(@color) + +=over Set the icon's fill color. The color is an array of 1, 3, or 4 numbers, each in the range 0.0 to 1.0. If 1 number is given, it is the grayscale value (0 = @@ -859,7 +941,9 @@ is black. Defining option: -Named colors are not supported at this time. +Named colors (e.g., 'black') are not supported at this time. + +=back =over @@ -912,11 +996,17 @@ sub Color { return $self; } -=item text => string +=head3 text string + + text => string + +=over Specify an optional B for annotation. This text or comment only shows up I in the pop-up containing the file or text. +=back + =cut sub icon_appearance { @@ -1039,8 +1129,4 @@ sub icon_appearance { return $self; } -=back - -=cut - 1; diff --git a/lib/PDF/Builder/Basic/PDF.pm b/lib/PDF/Builder/Basic/PDF.pm index e997191..f4e9a45 100644 --- a/lib/PDF/Builder/Basic/PDF.pm +++ b/lib/PDF/Builder/Basic/PDF.pm @@ -3,7 +3,7 @@ package PDF::Builder::Basic::PDF; use strict; use warnings; -our $VERSION = '3.025'; # VERSION +our $VERSION = '3.026'; # VERSION our $LAST_UPDATE = '3.020'; # manually update whenever code is changed =head1 NAME diff --git a/lib/PDF/Builder/Basic/PDF/Array.pm b/lib/PDF/Builder/Basic/PDF/Array.pm index ac4b40e..18ede12 100644 --- a/lib/PDF/Builder/Basic/PDF/Array.pm +++ b/lib/PDF/Builder/Basic/PDF/Array.pm @@ -20,8 +20,8 @@ use base 'PDF::Builder::Basic::PDF::Objind'; use strict; use warnings; -our $VERSION = '3.025'; # VERSION -our $LAST_UPDATE = '3.024'; # manually update whenever code is changed +our $VERSION = '3.026'; # VERSION +our $LAST_UPDATE = '3.026'; # manually update whenever code is changed =head1 NAME @@ -30,13 +30,17 @@ Inherits from L =head1 METHODS -=over +=head2 new + + PDF::Array->new($parent, @values) -=item PDF::Array->new($parent, @values) +=over Creates an array with the given storage parent and an optional list of values to initialise the array with. +=back + =cut sub new { @@ -49,9 +53,16 @@ sub new { return $self; } -=item $a->outobjdeep($fh, $pdf) +=head2 outobjdeep -Outputs an array as a PDF array to the given filehandle. + $a->outobjdeep($fh, $pdf) + +=over + +Outputs an array as a PDF array to the given filehandle. It's unusual to +need to call this method from user code. + +=back =cut @@ -67,26 +78,34 @@ sub outobjdeep { return; } -=item $a->elements() +=head2 elements + + $a->elements() + +=over Returns the contents of the array. -Formerly called C, which is now B. +=back =cut -sub elementsof { return elements(@_); } - sub elements { my $self = shift(); return @{$self->{' val'}}; } -=item $a->add_elements(@elements) +=head2 add_elements + + $a->add_elements(@elements) + +=over Appends the given elements to the array. An element is only added if it is defined. +=back + =cut sub add_elements { @@ -99,18 +118,18 @@ sub add_elements { return $self; } -=item $a->remove_element($element) +=head2 remove_element + + $a->remove_element($element) + +=over Removes all occurrences of an element from an array. -Formerly called C, which is now B and will be removed. +=back =cut -# not listed as deprecated, not used internally, should not have been -# used in external code. remove after July 2021. -sub removeobj { return remove_element(@_); } - sub remove_element { my ($self, $element) = @_; @@ -118,21 +137,33 @@ sub remove_element { return $self; } -=item $a->val() +=head2 val + + $a->val() + +=over Returns a reference to the contents of the array. +=back + =cut sub val { return $_[0]->{' val'}; } -=item $a->copy($pdf) +=head2 copy + + $a->copy($pdf) + +=over Copies the array with deep-copy on elements which are not full PDF objects with respect to a particular $pdf output context. +=back + =cut sub copy { @@ -151,8 +182,4 @@ sub copy { return $res; } -=back - -=cut - 1; diff --git a/lib/PDF/Builder/Basic/PDF/Bool.pm b/lib/PDF/Builder/Basic/PDF/Bool.pm index c163ca5..5dc796a 100644 --- a/lib/PDF/Builder/Basic/PDF/Bool.pm +++ b/lib/PDF/Builder/Basic/PDF/Bool.pm @@ -20,8 +20,8 @@ use base 'PDF::Builder::Basic::PDF::String'; use strict; use warnings; -our $VERSION = '3.025'; # VERSION -our $LAST_UPDATE = '3.024'; # manually update whenever code is changed +our $VERSION = '3.026'; # VERSION +our $LAST_UPDATE = '3.026'; # manually update whenever code is changed =head1 NAME @@ -31,30 +31,36 @@ B or B =head1 METHODS -=over +=head2 convert + + $b->convert($str) -=item $b->convert($str) +=over Converts a string into the string which will be stored. +=back + =cut sub convert { return $_[1] eq 'true'; } -=item $b->as_pdf() +=head2 as_pdf + + $b->as_pdf() + +=over Converts the value to a PDF output form. +=back + =cut sub as_pdf { return $_[0]->{'val'}? 'true': 'false'; } -=back - -=cut - 1; diff --git a/lib/PDF/Builder/Basic/PDF/Dict.pm b/lib/PDF/Builder/Basic/PDF/Dict.pm index 05264c6..c2a4ecb 100644 --- a/lib/PDF/Builder/Basic/PDF/Dict.pm +++ b/lib/PDF/Builder/Basic/PDF/Dict.pm @@ -20,8 +20,8 @@ use base 'PDF::Builder::Basic::PDF::Objind'; use strict; use warnings; -our $VERSION = '3.025'; # VERSION -our $LAST_UPDATE = '3.024'; # manually update whenever code is changed +our $VERSION = '3.026'; # VERSION +our $LAST_UPDATE = '3.026'; # manually update whenever code is changed our $mincache = 16 * 1024 * 1024; @@ -60,8 +60,17 @@ source PDF the stream starts. =head1 METHODS +=head2 new + + $d = PDF::Builder::Basic::PDF->new() + =over +Creates a new instance of a dictionary. The usual practice is to call +C instead. + +=back + =cut sub new { @@ -74,10 +83,16 @@ sub new { return $self; } -=item $type = $d->type($type) +=head2 type + + $type = $d->type($type) + +=over Get/Set the standard Type key. It can be passed, and will return, a text value rather than a Name object. +=back + =cut sub type { @@ -90,10 +105,16 @@ sub type { return $self->{'Type'}->val(); } -=item @filters = $d->filter(@filters) +=head2 filter + + @filters = $d->filter(@filters) + +=over Get/Set one or more filters being used by the optional stream attached to the dictionary. +=back + =cut sub filter { @@ -113,10 +134,14 @@ sub filter { return $self->{'Filter'}; } -# Undocumented alias, which may be removed in a future release +# Undocumented alias, which may be removed in a future release TBD sub filters { return filter(@_); } -=item $d->outobjdeep($fh, $pdf) +=head2 outobjdeep + + $d->outobjdeep($fh, $pdf) + +=over Outputs the contents of the dictionary to a PDF file. This is a recursive call. @@ -124,6 +149,8 @@ It also outputs a stream if the dictionary has a stream element. If this occurs then this method will calculate the length of the stream and insert it into the stream's dictionary. +=back + =cut sub outobjdeep { @@ -234,7 +261,11 @@ sub outobjdeep { return; } -=item $d->read_stream($force_memory) +=head2 read_stream + + $d->read_stream($force_memory) + +=over Reads in a stream from a PDF file. If the stream is greater than C (defaults to 32768) bytes to be stored, then @@ -243,6 +274,8 @@ file as a data cache. If $force_memory is set, this caching will not occur and the data will all be stored in the $self->{' stream'} variable. +=back + =cut sub read_stream { @@ -316,18 +349,20 @@ sub read_stream { return $self; } -=item $d->val() +=head2 val + + $d->val() + +=over Returns the dictionary, which is itself. +=back + =cut sub val { return $_[0]; } -=back - -=cut - 1; diff --git a/lib/PDF/Builder/Basic/PDF/File.pm b/lib/PDF/Builder/Basic/PDF/File.pm index beafb51..e6561a3 100644 --- a/lib/PDF/Builder/Basic/PDF/File.pm +++ b/lib/PDF/Builder/Basic/PDF/File.pm @@ -20,8 +20,8 @@ package PDF::Builder::Basic::PDF::File; use strict; use warnings; -our $VERSION = '3.025'; # VERSION -our $LAST_UPDATE = '3.024'; # manually update whenever code is changed +our $VERSION = '3.026'; # VERSION +our $LAST_UPDATE = '3.026'; # manually update whenever code is changed =head1 NAME @@ -29,12 +29,12 @@ PDF::Builder::Basic::PDF::File - Holds the trailers and cross-reference tables f =head1 SYNOPSIS - $p = PDF::Builder::Basic::PDF::File->open("filename.pdf", 1); - $p->new_obj($obj_ref); - $p->free_obj($obj_ref); - $p->append_file(); - $p->close_file(); - $p->release(); # IMPORTANT! + $p = PDF::Builder::Basic::PDF::File->open("filename.pdf", 1); + $p->new_obj($obj_ref); + $p->free_obj($obj_ref); + $p->append_file(); + $p->close_file(); + $p->release(); # IMPORTANT! =head1 DESCRIPTION @@ -142,10 +142,6 @@ is in PDF, which contains the location of the previous cross-reference table. =back -=head1 METHODS - -=over - =cut use Scalar::Util qw(blessed weaken); @@ -189,12 +185,20 @@ use PDF::Builder::Basic::PDF::Pages; use PDF::Builder::Basic::PDF::Null; use POSIX qw(ceil floor); -=item PDF::Builder::Basic::PDF::File->new() +=head1 METHODS + +=head2 new + + PDF::Builder::Basic::PDF::File->new() + +=over Creates a new, empty file object which can act as the host to other PDF objects. Since there is no file associated with this object, it is assumed that the object is created in readiness for creating a new PDF file. +=back + =cut sub new { @@ -211,7 +215,11 @@ sub new { return $self; } -=item $p = PDF::Builder::Basic::PDF::File->open($filename, $update, %options) +=head2 open + + $p = PDF::Builder::Basic::PDF::File->open($filename, $update, %options) + +=over Opens the file and reads all the trailers and cross reference tables to build a complete directory of objects. @@ -241,6 +249,8 @@ longer fail on them, but merely comment on their existence. =back +=back + =cut sub open { @@ -284,6 +294,7 @@ sub open { # out inline comment and create a separate comment further along). } + # there should always be 'startxref' within 16*64 bytes of end $fh->seek(0, 2); # go to end of file my $end = $fh->tell(); $self->{' epos'} = $end; @@ -297,7 +308,8 @@ sub open { warn "Malformed PDF file $filename"; #orig 'die' } } - my $xpos = $1; + my $xpos = $1; # offset given after 'startxref' + # should point to either xref table ('xref'), or object with xref stream $self->{' xref_position'} = $xpos; my $tdict = $self->readxrtr($xpos, %options); @@ -308,9 +320,13 @@ sub open { return $self; } # end of open() -=item $new_version = $p->version($version, %opts) # Set +=head2 version + + $new_version = $p->version($version, %opts) # Set -=item $ver = $p->version() # Get + $ver = $p->version() # Get + +=over Gets/sets the PDF version (e.g., 1.5). Setting sets both the header and trailer versions. Getting returns the higher of header and trailer versions. @@ -322,6 +338,8 @@ A warning message is given if you attempt to I the PDF version, as you might have already read in a higher level file, or used a higher level feature. This message is suppressed if the 'silent' option is given with any value. +=back + =cut sub version { @@ -368,9 +386,13 @@ sub version { return $old_version; } -=item $new_version = $p->header_version($version, %opts) # Set +=head2 header_version + + $new_version = $p->header_version($version, %opts) # Set -=item $version = $p->header_version() # Get + $version = $p->header_version() # Get + +=over Gets/sets the PDF version stored in the file header. @@ -381,6 +403,8 @@ A warning message is given if you attempt to I the PDF version, as you might have already read in a higher level file, or used a higher level feature. This message is suppressed if the 'silent' option is given with any value. +=back + =cut sub header_version { @@ -415,9 +439,13 @@ sub header_version { return $old_version; } -=item $new_version = $p->trailer_version($version, %opts) # Set +=head2 trailer_version + + $new_version = $p->trailer_version($version, %opts) # Set + + $version = $p->trailer_version() # Get -=item $version = $p->trailer_version() # Get +=over Gets/sets the PDF version stored in the document catalog. @@ -432,6 +460,8 @@ A warning message is given if you attempt to I the PDF version, as you might have already read in a higher level file, or used a higher level feature. This message is suppressed if the 'silent' option is given with any value. +=back + =cut sub trailer_version { @@ -470,11 +500,17 @@ sub trailer_version { return $old_version; } -=item $prev_version = $p->require_version($version) +=head2 require_version + + $prev_version = $p->require_version($version) + +=over Ensures that the PDF version is at least C<$version>. Silently sets the version to the higher level. +=back + =cut sub require_version { @@ -484,7 +520,11 @@ sub require_version { return $current_version; } -=item $p->release() +=head2 release + + $p->release() + +=over Releases ALL of the memory used by the PDF document and all of its component objects. After calling this method, do B expect to @@ -501,6 +541,8 @@ you've called this method, though, don't expect to be able to do anything else with the C object; it'll have B internal state whatsoever. +=back + =cut # Maintainer's Question: Couldn't this be handled by a DESTROY method @@ -540,11 +582,17 @@ sub release { return; } # end of release() -=item $p->append_file() +=head2 append_file + + $p->append_file() + +=over Appends the objects for output to the read file and then appends the appropriate table. +=back + =cut sub append_file { @@ -585,7 +633,11 @@ sub append_file { return; } # end of append_file() -=item $p->out_file($fname) +=head2 out_file + + $p->out_file($fname) + +=over Writes a PDF file to a file of the given filename, based on the current list of objects to be output. It creates the trailer dictionary based on information @@ -593,6 +645,8 @@ in C<$self>. $fname may be a string or an IO object. +=back + =cut sub out_file { @@ -604,12 +658,18 @@ sub out_file { return $self; } -=item $p->create_file($fname) +=head2 create_file + + $p->create_file($fname) + +=over Creates a new output file (no check is made of an existing open file) of the given filename or IO object. Note: make sure that C<< $p->{' version'} >> is set correctly before calling this function. +=back + =cut sub create_file { @@ -638,10 +698,16 @@ sub create_file { return $self; } -=item $p->close_file() +=head2 close_file + + $p->close_file() + +=over Closes up the open file for output, by outputting the trailer, etc. +=back + =cut sub close_file { @@ -674,7 +740,11 @@ sub close_file { return $self; } # end of close_file() -=item ($value, $str) = $p->readval($str, %opts) +=head2 readval + + ($value, $str) = $p->readval($str, %opts) + +=over Reads a PDF value from the current position in the file. If C<$str> is too short, read some more from the current location in the file until the whole @@ -684,6 +754,8 @@ object is read. This is a recursive call which may slurp in a whole big stream Returns the recursive data structure read and also the current C<$str> that has been read from the file. +=back + =cut sub readval { @@ -918,10 +990,16 @@ sub readval { return ($result, $str); } # end of readval() -=item $ref = $p->read_obj($objind, %opts) +=head2 read_obj + + $ref = $p->read_obj($objind, %opts) + +=over Given an indirect object reference, locate it and read the object returning -the read in object. +the read-in object. + +=back =cut @@ -934,10 +1012,16 @@ sub read_obj { return $objind; } -=item $ref = $p->read_objnum($num, $gen, %opts) +=head2 read_objnum + + $ref = $p->read_objnum($num, $gen, %opts) + +=over Returns a fully read object of given number and generation in this file +=back + =cut sub read_objnum { @@ -1014,12 +1098,18 @@ sub read_objnum { return $object; } # end of read_objnum() -=item $objind = $p->new_obj($obj) +=head2 new_obj + + $objind = $p->new_obj($obj) + +=over Creates a new, free object reference based on free space in the cross reference chain. If nothing is free, then think up a new number. If C<$obj>, then turns that object into this new object rather than returning a new object. +=back + =cut sub new_obj { @@ -1072,11 +1162,17 @@ sub new_obj { } } -=item $p->out_obj($obj) +=head2 out_obj + + $p->out_obj($obj) + +=over Indicates that the given object reference should appear in the output xref table whether with data or freed. +=back + =cut sub out_obj { @@ -1095,10 +1191,16 @@ sub out_obj { return $obj; } -=item $p->free_obj($obj) +=head2 free_obj + + $p->free_obj($obj) + +=over Marks an object reference for output as being freed. +=back + =cut sub free_obj { @@ -1111,10 +1213,16 @@ sub free_obj { return; } -=item $p->remove_obj($objind) +=head2 remove_obj + + $p->remove_obj($objind) + +=over Removes the object from all places where we might remember it. +=back + =cut sub remove_obj { @@ -1132,9 +1240,13 @@ sub remove_obj { return $self; } -=item $p->ship_out(@objects) +=head2 ship_out -=item $p->ship_out() + $p->ship_out(@objects) + + $p->ship_out() + +=over Ships the given objects (or all objects for output if C<@objects> is empty) to the currently open output file (assuming there is one). Freed objects are not @@ -1143,6 +1255,8 @@ becomes its source and it will not be shipped again unless out_obj is called again. Notice that a shipped out object can be re-output or even freed, but that it will not cause the data already output to be changed. +=back + =cut sub ship_out { @@ -1185,12 +1299,18 @@ sub ship_out { return $self; } # end of ship_out() -=item $p->copy($outpdf, \&filter) +=head2 copy + + $p->copy($outpdf, \&filter) + +=over Iterates over every object in the file reading the object, calling C with the object, and outputting the result. If C is not defined, just copies input to output. +=back + =cut sub copy { @@ -1237,21 +1357,23 @@ sub copy { return $self; } # end of copy() -=back - =head1 PRIVATE METHODS & FUNCTIONS The following methods and functions are considered B to this class. This does not mean you cannot use them if you have a need, just that they aren't really designed for users of this class. -=over +=head2 locate_obj -=item $offset = $p->locate_obj($num, $gen) + $offset = $p->locate_obj($num, $gen) + +=over Returns a file offset to the object asked for by following the chain of cross reference tables until it finds the one you want. +=back + =cut sub locate_obj { @@ -1274,12 +1396,18 @@ sub locate_obj { return; } -=item update($fh, $str, $instream) +=head2 update + + update($fh, $str, $instream) + +=over Keeps reading C<$fh> for more data to ensure that C<$str> has at least a line full for C to work on. At this point we also take the opportunity to ignore comments. +=back + =cut sub update { @@ -1311,11 +1439,17 @@ sub update { return $str; } # end of update() -=item $objind = $p->test_obj($num, $gen) +=head2 test_obj + + $objind = $p->test_obj($num, $gen) + +=over Tests the cache to see whether an object reference (which may or may not have been getobj()ed) has been cached. Returns it if it has. +=back + =cut sub test_obj { @@ -1324,10 +1458,16 @@ sub test_obj { return $self->{' objcache'}{$num, $gen}; } -=item $p->add_obj($objind) +=head2 add_obj + + $p->add_obj($objind) + +=over Adds the given object to the internal object cache. +=back + =cut sub add_obj { @@ -1339,7 +1479,11 @@ sub add_obj { return $obj; } -=item $tdict = $p->readxrtr($xpos, %options) +=head2 readxrtr + + $tdict = $p->readxrtr($xpos, %options) + +=over Recursive function which reads each of the cross-reference and trailer tables in turn until there are no more. @@ -1355,6 +1499,8 @@ for details. See C for options allowed. +=back + =cut sub _unpack_xref_stream { @@ -1403,7 +1549,8 @@ sub _unpack_xref_stream { sub readxrtr { my ($self, $xpos, %options) = @_; - # $xpos SHOULD be pointing to "xref" keyword + # $xpos SHOULD be pointing to "xref" keyword + # UNLESS an xref stream is in use (v 1.5+) # copy dashed option names to preferred undashed names if (defined $options{'-diags'} && !defined $options{'diags'}) { $options{'diags'} = delete($options{'-diags'}); } @@ -1423,7 +1570,7 @@ sub readxrtr { # $buf = update($fh, $buf); #} - if ($buf =~ s/^xref$cr//i) { # remove xrefEOL from buffer + if ($buf =~ s/^xref$cr//i) { # xref table, remove xrefEOL from buffer # Plain XRef tables. # # look to match startobj# count# EOL of first (or only) subsection @@ -1610,7 +1757,7 @@ sub readxrtr { ($tdict, $buf) = $self->readval($buf); - } elsif ($buf =~ m/^(\d+)\s+(\d+)\s+obj/i) { + } elsif ($buf =~ m/^(\d+)\s+(\d+)\s+obj/i) { # object for xref stream my ($xref_obj, $xref_gen) = ($1, $2); $PDF::Builder::global_pdf->verCheckOutput(1.5, "importing cross-reference stream"); # XRef streams @@ -1687,14 +1834,20 @@ sub readxrtr { return $tdict; } # end of readxrtr() -=item $p->out_trailer($tdict, $update) +=head2 out_trailer + + $p->out_trailer($tdict, $update) -=item $p->out_trailer($tdict) + $p->out_trailer($tdict) + +=over Outputs the body and trailer for a PDF file by outputting all the objects in the ' outlist' and then outputting a xref table for those objects and any freed ones. It then outputs the trailing dictionary and the trailer code. +=back + =cut sub out_trailer { @@ -1838,10 +1991,16 @@ sub out_trailer { return; } # end of out_trailer() -=item PDF::Builder::Basic::PDF::File->_new() +=head2 _new + + PDF::Builder::Basic::PDF::File->_new() + +=over Creates a very empty PDF file object (used by new() and open()) +=back + =cut sub _new { @@ -1860,13 +2019,11 @@ sub _new { 1; -=back - =head1 AUTHOR Martin Hosken Martin_Hosken@sil.org -Copyright Martin Hosken 1999 and onwards +Copyright Martin Hosken 1999 No warranty or expression of effectiveness, least of all regarding anyone's safety, is implied in this software or documentation. diff --git a/lib/PDF/Builder/Basic/PDF/Filter.pm b/lib/PDF/Builder/Basic/PDF/Filter.pm index f09ac70..1b5c741 100644 --- a/lib/PDF/Builder/Basic/PDF/Filter.pm +++ b/lib/PDF/Builder/Basic/PDF/Filter.pm @@ -18,8 +18,8 @@ package PDF::Builder::Basic::PDF::Filter; use strict; use warnings; -our $VERSION = '3.025'; # VERSION -our $LAST_UPDATE = '3.024'; # manually update whenever code is changed +our $VERSION = '3.026'; # VERSION +our $LAST_UPDATE = '3.026'; # manually update whenever code is changed use PDF::Builder::Basic::PDF::Filter::ASCII85Decode; use PDF::Builder::Basic::PDF::Filter::ASCIIHexDecode; @@ -56,14 +56,22 @@ the same time. =head1 METHODS -=over +=head2 new + + PDF::Builder::Basic::PDF::Filter->new() -=item PDF::Builder::Basic::PDF::Filter->new() +=over Creates a new filter object with empty state information ready for processing data both input and output. -=item $dat = $f->infilt($str, $isend) +=back + +=head2 infilt + + $dat = $f->infilt($str, $isend) + +=over Filters from output to input the data. Notice that C<$isend == 0> implies that there is more data to come and so following it C<$f> may contain state @@ -75,7 +83,13 @@ C<$f> will be that the state information is empty. Error messages are most likely to occur here since if there is required state information to be stored following this data, then that would imply an error in the data. -=item $str = $f->outfilt($dat, $isend) +=back + +=head2 outfilt + + $str = $f->outfilt($dat, $isend) + +=over Filter stored data ready for output. Parallels C. diff --git a/lib/PDF/Builder/Basic/PDF/Filter/ASCII85Decode.pm b/lib/PDF/Builder/Basic/PDF/Filter/ASCII85Decode.pm index ea436b8..d5f3e93 100644 --- a/lib/PDF/Builder/Basic/PDF/Filter/ASCII85Decode.pm +++ b/lib/PDF/Builder/Basic/PDF/Filter/ASCII85Decode.pm @@ -5,7 +5,7 @@ use base 'PDF::Builder::Basic::PDF::Filter'; use strict; use warnings; -our $VERSION = '3.025'; # VERSION +our $VERSION = '3.026'; # VERSION our $LAST_UPDATE = '3.010'; # manually update whenever code is changed =head1 NAME diff --git a/lib/PDF/Builder/Basic/PDF/Filter/ASCIIHexDecode.pm b/lib/PDF/Builder/Basic/PDF/Filter/ASCIIHexDecode.pm index b1be2aa..8af79f7 100644 --- a/lib/PDF/Builder/Basic/PDF/Filter/ASCIIHexDecode.pm +++ b/lib/PDF/Builder/Basic/PDF/Filter/ASCIIHexDecode.pm @@ -5,7 +5,7 @@ use base 'PDF::Builder::Basic::PDF::Filter'; use strict; use warnings; -our $VERSION = '3.025'; # VERSION +our $VERSION = '3.026'; # VERSION our $LAST_UPDATE = '2.029'; # manually update whenever code is changed =head1 NAME diff --git a/lib/PDF/Builder/Basic/PDF/Filter/FlateDecode.pm b/lib/PDF/Builder/Basic/PDF/Filter/FlateDecode.pm index 712f9d7..7ed60cc 100644 --- a/lib/PDF/Builder/Basic/PDF/Filter/FlateDecode.pm +++ b/lib/PDF/Builder/Basic/PDF/Filter/FlateDecode.pm @@ -5,8 +5,8 @@ use base 'PDF::Builder::Basic::PDF::Filter'; use strict; use warnings; -our $VERSION = '3.025'; # VERSION -our $LAST_UPDATE = '3.016'; # manually update whenever code is changed +our $VERSION = '3.026'; # VERSION +our $LAST_UPDATE = '3.026'; # manually update whenever code is changed use POSIX qw(ceil floor); @@ -18,18 +18,17 @@ PDF::Builder::Basic::PDF::Filter::FlateDecode - compress and uncompress stream f =cut +# not specifying a minimum version BEGIN { eval { require Compress::Zlib }; $havezlib = !$@; } sub new { - return unless $havezlib; + return unless $havezlib; # undef returned should prove fatal my ($class, $decode_parms) = @_; - my ($self) = { - DecodeParms => $decode_parms, - }; + my ($self) = { 'DecodeParms' => $decode_parms }; $self->{'outfilt'} = Compress::Zlib::deflateInit( -Level => 9, @@ -54,7 +53,7 @@ sub infilt { if ($self->{'DecodeParms'} and $self->{'DecodeParms'}->{'Predictor'}) { my $predictor = $self->{'DecodeParms'}->{'Predictor'}->val(); - if ($predictor == 2) { + if ($predictor == 2) { die "The TIFF predictor logic has not been implemented"; } elsif ($predictor >= 10 and $predictor <= 15) { $result = $self->_depredict_png($result); @@ -74,11 +73,11 @@ sub _depredict_png { $stream = $self->{'_depredict_next'} . $stream if defined $self->{'_depredict_next'}; $prev = $self->{'_depredict_prev'} if defined $self->{'_depredict_prev'}; - my $alpha = $param->{'Alpha'} ? $param->{'Alpha'}->val(): 0; - my $bpc = $param->{'BitsPerComponent'}? $param->{'BitsPerComponent'}->val(): 8; - my $colors = $param->{'Colors'} ? $param->{'Colors'}->val(): 1; - my $columns = $param->{'Columns'} ? $param->{'Columns'}->val(): 1; - my $height = $param->{'Height'} ? $param->{'Height'}->val(): 0; + my $alpha = $param->{'Alpha'} ? $param->{'Alpha'}->val(): 0; + my $bpc = $param->{'BitsPerComponent'} ? $param->{'BitsPerComponent'}->val(): 8; + my $colors = $param->{'Colors'} ? $param->{'Colors'}->val(): 1; + my $columns = $param->{'Columns'} ? $param->{'Columns'}->val(): 1; + my $height = $param->{'Height'} ? $param->{'Height'}->val(): 0; my $comp = $colors + $alpha; my $bpp = ceil($bpc * $comp / 8); diff --git a/lib/PDF/Builder/Basic/PDF/Filter/LZWDecode.pm b/lib/PDF/Builder/Basic/PDF/Filter/LZWDecode.pm index d4e91dd..7d444e6 100644 --- a/lib/PDF/Builder/Basic/PDF/Filter/LZWDecode.pm +++ b/lib/PDF/Builder/Basic/PDF/Filter/LZWDecode.pm @@ -6,8 +6,8 @@ use Carp; use POSIX; use base 'PDF::Builder::Basic::PDF::Filter::FlateDecode'; -our $VERSION = '3.025'; # VERSION -our $LAST_UPDATE = '3.023'; # manually update whenever code is changed +our $VERSION = '3.026'; # VERSION +our $LAST_UPDATE = '3.026'; # manually update whenever code is changed =head1 NAME @@ -15,10 +15,12 @@ PDF::Builder::Basic::PDF::Filter::LZWDecode - compress and uncompress stream fil =cut +# extensively extended from PDF::API2 version, for TIFF support + sub new { my ($class, $decode_parms) = @_; - my $self = { DecodeParms => $decode_parms, }; + my $self = { 'DecodeParms' => $decode_parms }; bless $self, $class; $self->_reset_code(); @@ -38,15 +40,15 @@ sub infilt { } $self->{'table'} = [ map { chr } 0 .. $self->{'clear_table'} - 1 ]; - while ( $data ne q{} ) { + while ($data ne q{}) { ($code, $partial_code, $partial_bits) = $self->read_dat(\$data, $partial_code, $partial_bits, $self->{'code_length'}); last unless defined $code; unless ($early_change) { - if ($self->{next_code} == (1 << $self->{code_length}) - and $self->{code_length} < 12) { + if ($self->{'next_code'} == (1 << $self->{'code_length'}) + and $self->{'code_length'} < 12) { $self->{'code_length'}++; } } @@ -71,7 +73,7 @@ sub infilt { if ($early_change) { if ($self->{'next_code'} == (1 << $self->{'code_length'}) - and $self->{code_length} < 12) { + and $self->{'code_length'} < 12) { $self->{'code_length'}++; } } @@ -80,8 +82,9 @@ sub infilt { $self->{'partial_bits'} = $partial_bits; if ($self->_predictor_type() == 2) { - return $self->_depredict($result); + return $self->_depredict($result); } + return $result; } @@ -95,30 +98,30 @@ sub outfilt { $self->{'buf'} = q{}; $self->{'buf_pos'} = 0; $self->_write_code($self->{'clear_table'}); - + if ($self->_predictor_type() == 2) { $str = $self->_predict($str); } - + for my $i (0 .. length($str)) { my $char = substr($str, $i, 1); $bytes_in += 1; - + if (exists $self->{'table'}{ $seen . $char }) { $seen .= $char; next; } - + $self->_write_code($self->{'table'}{$seen}); - + $self->_new_code($seen . $char); - + $seen = $char; - + if ($self->{'at_max_code'}) { $self->_write_code($self->{'clear_table'}); $self->_reset_code(); - + undef $checkpoint; undef $last_ratio; } @@ -132,10 +135,10 @@ sub outfilt { } return pack 'B*', $self->{'buf'}; } - + sub _reset_code { my $self = shift; - + $self->{'initial_code_length'} = 9; $self->{'max_code_length'} = 12; $self->{'code_length'} = $self->{'initial_code_length'}; @@ -147,15 +150,15 @@ sub _reset_code { $self->{'table'} = { map { chr $_ => $_ } 0 .. $self->{'clear_table'} - 1 }; return; } - + sub _new_code { my ($self, $word) = @_; - + if ($self->{'at_max_code'} == 0) { $self->{'table'}{$word} = $self->{'next_code'}; $self->{'next_code'} += 1; } - + if ($self->{'next_code'} >= $self->{'next_increase'}) { if ($self->{'code_length'} < $self->{'max_code_length'}) { $self->{'code_length'} += 1; @@ -166,17 +169,17 @@ sub _new_code { } return; } - + sub _write_code { my ($self, $code) = @_; - + if (not defined $code) { return; } - + if ($code > (2**$self->{'code_length'})) { croak "Code $code too large for current code length $self->{'code_length'}"; } - + for my $bit (reverse 0 .. ($self->{'code_length'} - 1)) { if (($code >> $bit) & 1) { $self->{'buf'} .= '1'; @@ -184,20 +187,20 @@ sub _write_code { $self->{'buf'} .= '0'; } } - + $self->{'buf_pos'} += $self->{'code_length'}; return; } - + sub read_dat { my ($self, $data_ref, $partial_code, $partial_bits, $code_length) = @_; if (not defined $partial_bits) { $partial_bits = 0; } if (not defined $partial_code) { $partial_code = 0; } - while ($partial_bits < $code_length ) { + while ($partial_bits < $code_length) { return (undef, $partial_code, $partial_bits) unless length($$data_ref); - $partial_code = ($partial_code << 8 ) + unpack('C', $$data_ref); + $partial_code = ($partial_code << 8) + unpack('C', $$data_ref); substr($$data_ref, 0, 1, q{}); $partial_bits += 8; } @@ -223,7 +226,7 @@ sub _predictor_type { } return 1; } - + sub _depredict { my ($self, $data) = @_; my $param = $self->{'DecodeParms'}; @@ -233,7 +236,7 @@ sub _depredict { my $colors = $param->{'Colors'} ? $param->{'Colors'}->val() : 1; my $columns = $param->{'Columns'} ? $param->{'Columns'}->val() : 1; my $rows = $param->{'Rows'} ? $param->{'Rows'}->val() : 0; - + my $comp = $colors + $alpha; my $bpp = ceil($bpc * $comp / 8); my $max = 256; @@ -252,7 +255,7 @@ sub _depredict { } return $data; } - + sub _predict { my ($self, $data) = @_; my $param = $self->{'DecodeParms'}; @@ -262,7 +265,7 @@ sub _predict { my $colors = $param->{'Colors'} ? $param->{'Colors'}->val() : 1; my $columns = $param->{'Columns'} ? $param->{'Columns'}->val() : 1; my $rows = $param->{'Rows'} ? $param->{'Rows'}->val() : 0; - + my $comp = $colors + $alpha; my $bpp = ceil($bpc * $comp / 8); my $max = 256; @@ -281,5 +284,5 @@ sub _predict { } return $data; } - + 1; diff --git a/lib/PDF/Builder/Basic/PDF/Filter/RunLengthDecode.pm b/lib/PDF/Builder/Basic/PDF/Filter/RunLengthDecode.pm index a4ab760..2e44356 100644 --- a/lib/PDF/Builder/Basic/PDF/Filter/RunLengthDecode.pm +++ b/lib/PDF/Builder/Basic/PDF/Filter/RunLengthDecode.pm @@ -5,7 +5,7 @@ use base 'PDF::Builder::Basic::PDF::Filter'; use strict; use warnings; -our $VERSION = '3.025'; # VERSION +our $VERSION = '3.026'; # VERSION our $LAST_UPDATE = '2.029'; # manually update whenever code is changed =head1 NAME diff --git a/lib/PDF/Builder/Basic/PDF/Literal.pm b/lib/PDF/Builder/Basic/PDF/Literal.pm index 299d5f0..0e30ea5 100644 --- a/lib/PDF/Builder/Basic/PDF/Literal.pm +++ b/lib/PDF/Builder/Basic/PDF/Literal.pm @@ -6,7 +6,7 @@ use base 'PDF::Builder::Basic::PDF::Objind'; use strict; use warnings; -our $VERSION = '3.025'; # VERSION +our $VERSION = '3.026'; # VERSION our $LAST_UPDATE = '3.024'; # manually update whenever code is changed use PDF::Builder::Basic::PDF::Filter; diff --git a/lib/PDF/Builder/Basic/PDF/Name.pm b/lib/PDF/Builder/Basic/PDF/Name.pm index fe1b94b..5402a71 100644 --- a/lib/PDF/Builder/Basic/PDF/Name.pm +++ b/lib/PDF/Builder/Basic/PDF/Name.pm @@ -20,8 +20,8 @@ use base 'PDF::Builder::Basic::PDF::String'; use strict; use warnings; -our $VERSION = '3.025'; # VERSION -our $LAST_UPDATE = '3.024'; # manually update whenever code is changed +our $VERSION = '3.026'; # VERSION +our $LAST_UPDATE = '3.026'; # manually update whenever code is changed =head1 NAME @@ -30,14 +30,18 @@ and stores PDF names (things beginning with /) =head1 METHODS -=over +=head2 from_pdf + + $n = PDF::Builder::Basic::PDF::Name->from_pdf($string) -=item $n = PDF::Builder::Basic::PDF::Name->from_pdf($string) +=over Creates a new string object (not a full object yet) from a given -string. The string is parsed according to input criteria with +string. The string is parsed according to input criteria with escaping working, particular to Names. +=back + =cut sub from_pdf { @@ -49,11 +53,17 @@ sub from_pdf { return $self; } -=item $n->convert($string, $pdf) +=head2 convert + + $n->convert($string, $pdf) + +=over Converts a name into a string by removing the / and converting any hex munging. +=back + =cut sub convert { @@ -63,11 +73,17 @@ sub convert { return $string; } -=item $s->as_pdf($pdf) +=head2 as_pdf + + $s->as_pdf($pdf) + +=over Returns a name formatted as PDF. C<$pdf> is optional but should be the PDF File object for which the name is intended if supplied. +=back + =cut sub as_pdf { @@ -84,11 +100,17 @@ sub as_pdf { # spaces were implicitly allowed in names as well but it would be best # to ignore that (PDF 1.3, section H.3.2.4.3). -=item PDF::Builder::Basic::PDF::Name->string_to_name($string, $pdf) +=head2 string_to_name + + PDF::Builder::Basic::PDF::Name->string_to_name($string, $pdf) + +=over Suitably encode the string C<$string> for output in the File object C<$pdf> (the exact format may depend on the version of $pdf). +=back + =cut sub string_to_name { @@ -102,12 +124,18 @@ sub string_to_name { return $string; } -=item PDF::Builder::Basic::PDF::Name->name_to_string($string, $pdf) +=head2 name_to_string + + PDF::Builder::Basic::PDF::Name->name_to_string($string, $pdf) + +=over Suitably decode the string C<$string> as read from the File object C<$pdf> (the exact decoding may depend on the version of $pdf). Principally, undo the hex encoding for PDF versions > 1.1. +=back + =cut sub name_to_string { @@ -123,8 +151,4 @@ sub name_to_string { return $string; } -=back - -=cut - 1; diff --git a/lib/PDF/Builder/Basic/PDF/Null.pm b/lib/PDF/Builder/Basic/PDF/Null.pm index ad2ff08..8a8ad71 100644 --- a/lib/PDF/Builder/Basic/PDF/Null.pm +++ b/lib/PDF/Builder/Basic/PDF/Null.pm @@ -20,8 +20,8 @@ use base 'PDF::Builder::Basic::PDF::Objind'; use strict; use warnings; -our $VERSION = '3.025'; # VERSION -our $LAST_UPDATE = '3.024'; # manually update whenever code is changed +our $VERSION = '3.026'; # VERSION +our $LAST_UPDATE = '3.026'; # manually update whenever code is changed =head1 NAME @@ -30,37 +30,53 @@ PDF::Builder::Basic::PDF::Objind and cannot be subclassed. =head1 METHODS -=over - =cut # There is only one null object (section 3.2.8). my $null_obj = bless {}, 'PDF::Builder::Basic::PDF::Null'; -=item PDF::Builder::Basic::PDF::Null->new() +=head2 new + + PDF::Builder::Basic::PDF::Null->new() + +=over Returns the null object. There is only one null object. +=back + =cut sub new { return $null_obj; } -=item $s->realise() +=head2 realise + + $s->realise() + +=over Pretends to finish reading the object. +=back + =cut sub realise { return $null_obj; } -=item $s->outobjdeep() +=head2 outobjdeep + + $s->outobjdeep() + +=over Output the object in PDF format. +=back + =cut sub outobjdeep { @@ -70,38 +86,52 @@ sub outobjdeep { return; } -=item $s->is_obj() +=head2 is_obj + + $s->is_obj() + +=over Returns false because null is not a full object. +=back + =cut sub is_obj { return 0; } -=item $s->copy() +=head2 copy + + $s->copy() + +=over Another no-op. +=back + =cut sub copy { return $null_obj; } -=item $s->val() +=head2 val + + $s->val() + +=over Return undef. +=back + =cut sub val { return undef; ## no critic (undef is intentional) } -=back - -=cut - 1; diff --git a/lib/PDF/Builder/Basic/PDF/Number.pm b/lib/PDF/Builder/Basic/PDF/Number.pm index 7cdde2c..3426a7b 100644 --- a/lib/PDF/Builder/Basic/PDF/Number.pm +++ b/lib/PDF/Builder/Basic/PDF/Number.pm @@ -20,8 +20,8 @@ use base 'PDF::Builder::Basic::PDF::String'; use strict; use warnings; -our $VERSION = '3.025'; # VERSION -our $LAST_UPDATE = '3.024'; # manually update whenever code is changed +our $VERSION = '3.026'; # VERSION +our $LAST_UPDATE = '3.026'; # manually update whenever code is changed =head1 NAME @@ -29,30 +29,36 @@ PDF::Builder::Basic::PDF::Number - Numbers in PDF. Inherits from Lconvert($str) -=item $n->convert($str) +=over Converts a string from PDF to internal, by doing nothing +=back + =cut sub convert { return $_[1]; } -=item $n->as_pdf() +=head2 as_pdf + + $n->as_pdf() + +=over Converts a number to PDF format +=back + =cut sub as_pdf { return $_[0]->{'val'}; } -=back - -=cut - 1; diff --git a/lib/PDF/Builder/Basic/PDF/Objind.pm b/lib/PDF/Builder/Basic/PDF/Objind.pm index 5553446..628e37c 100644 --- a/lib/PDF/Builder/Basic/PDF/Objind.pm +++ b/lib/PDF/Builder/Basic/PDF/Objind.pm @@ -19,8 +19,8 @@ use strict; use warnings; use Scalar::Util 'isweak'; -our $VERSION = '3.025'; # VERSION -our $LAST_UPDATE = '3.024'; # manually update whenever code is changed +our $VERSION = '3.026'; # VERSION +our $LAST_UPDATE = '3.026'; # manually update whenever code is changed =head1 NAME @@ -63,8 +63,6 @@ Holds a direct reference to the next free object in the free list. =head1 METHODS -=over - =cut use Scalar::Util qw(blessed reftype weaken); @@ -76,10 +74,16 @@ $uidc = "pdfuid000"; @inst = qw(parent objnum objgen isfree nextfree uid realised); $inst{" $_"} = 1 for @inst; -=item PDF::Builder::Basic::PDF::Objind->new() +=head2 new + + PDF::Builder::Basic::PDF::Objind->new() + +=over Creates a new indirect object +=back + =cut sub new { @@ -88,10 +92,16 @@ sub new { return bless {}, ref $class || $class; } -=item $UID = $r->uid() +=head2 uid + + $UID = $r->uid() + +=over Returns a Unique id for this object, creating one if it didn't have one before +=back + =cut sub uid { @@ -99,7 +109,11 @@ sub uid { return $_[0]->{' uid'}; } -=item $r->release() +=head2 release + + $r->release() + +=over Releases ALL of the memory used by this indirect object, and all of its component/child objects. This method is called automatically by @@ -113,6 +127,8 @@ references within our own internal data structures. Calling 'C' forces these circular references to be cleaned up and the entire internal data structure purged. +=back + =cut # Maintainer's Question: Couldn't this be handled by a DESTROY method @@ -143,7 +159,11 @@ sub release { return; } -=item $value = $r->val() +=head2 val + + $value = $r->val() + +=over Returns the value of this object or reads the object and then returns its value. @@ -151,6 +171,8 @@ its value. Note that all direct subclasses *must* make their own versions of this subroutine otherwise we could be in for a very deep loop! +=back + =cut sub val { @@ -170,10 +192,16 @@ sub val { } } -=item $r->realise() +=head2 realise + + $r->realise() + +=over Makes sure that the object is fully read in, etc. +=back + =cut sub realise { @@ -184,12 +212,18 @@ sub realise { return $self; } -=item $v = $r->outobjdeep($fh, $pdf) +=head2 outobjdeep + + $v = $r->outobjdeep($fh, $pdf) + +=over If you really want to output this object, then you need to read it first. This also means that all direct subclasses must subclass this method, or they will loop forever! +=back + =cut sub outobjdeep { @@ -209,11 +243,17 @@ sub outobjdeep { } } -=item $r->outobj($fh, $pdf) +=head2 outobj + + $r->outobj($fh, $pdf) + +=over If this is a full object then outputs a reference to the object, otherwise calls outobjdeep to output the contents of the object at this point. +=back + =cut sub outobj { @@ -227,18 +267,19 @@ sub outobj { return; } -=item $s = $r->elements() +=head2 elements + + $s = $r->elements() + +=over Abstract superclass function filler. Returns self here but should return something more useful if an array. -The old name of this method, C, has been B and will -be removed in the future. +=back =cut -sub elementsof { return elements(@_); } - sub elements { my ($self) = @_; @@ -249,12 +290,18 @@ sub elements { } } -=item $s = $r->empty() +=head2 empty + + $s = $r->empty() + +=over Empties all content from this object to free up memory or to be read to pass the object into the free list. Simplistically undefs all instance variables other than object number and generation. +=back + =cut sub empty { @@ -267,13 +314,19 @@ sub empty { return $self; } -=item $o = $r->merge($objind) +=head2 merge + + $o = $r->merge($objind) + +=over This merges content information into an object reference placeholder. This occurs when an object reference is read before the object definition and the information in the read data needs to be merged into the object placeholder. +=back + =cut sub merge { @@ -291,19 +344,29 @@ sub merge { return bless $self, ref($other); } -=item $r->is_obj($pdf) +=head2 is_obj + + $r->is_obj($pdf) + +=over Returns whether this object is a full object with its own object number or whether it is purely a sub-object. C<$pdf> indicates which output file we are concerned that the object is an object in. +=back + =cut sub is_obj { return defined $_[1]->{' objects'}{$_[0]->uid()}; } -=item $r->copy($pdf, $res) +=head2 copy + + $r->copy($pdf, $res) + +=over Returns a new copy of this object. The object is assumed to be some kind of associative array and the copy is a deep copy for elements which are @@ -317,6 +380,8 @@ new one. It is up to the caller to bless C<$res>, etc. Notice that elements from C<$self> are not copied into C<$res> if there is already an entry for them existing in C<$res>. +=back + =cut sub copy { @@ -338,8 +403,4 @@ sub copy { return $res; } -=back - -=cut - 1; diff --git a/lib/PDF/Builder/Basic/PDF/Page.pm b/lib/PDF/Builder/Basic/PDF/Page.pm index 2f66457..0824e4e 100644 --- a/lib/PDF/Builder/Basic/PDF/Page.pm +++ b/lib/PDF/Builder/Basic/PDF/Page.pm @@ -20,8 +20,8 @@ use base 'PDF::Builder::Basic::PDF::Pages'; use strict; use warnings; -our $VERSION = '3.025'; # VERSION -our $LAST_UPDATE = '3.022'; # manually update whenever code is changed +our $VERSION = '3.026'; # VERSION +our $LAST_UPDATE = '3.026'; # manually update whenever code is changed use PDF::Builder::Basic::PDF::Dict; use PDF::Builder::Basic::PDF::Utils; @@ -52,9 +52,11 @@ The currently open stream =head1 METHODS -=over +=head2 new + + PDF::Builder::Basic::PDF::Page->new($pdf, $parent, $index) -=item PDF::Builder::Basic::PDF::Page->new($pdf, $parent, $index) +=over Creates a new page based on a pages object (perhaps the root object). @@ -68,6 +70,8 @@ are either optional or can be inherited. The optional index value indicates the index in the parent list that this page should be inserted (so that new pages need not be appended) +=back + =cut sub new { @@ -87,7 +91,11 @@ sub new { # the add() method was deleted from PDF::API2 2.034, but it looks like it # still may be used in Builder.pm! apparently calls Content.pm's add(). -#=item $p->add($str) +#=head2 add +# +# $p->add($str) +# +#=over # #Adds the string to the currently active stream for this page. If no stream #exists, then one is created and added to the list of streams for this page. @@ -95,6 +103,8 @@ sub new { #The slightly cryptic name is an aim to keep it short given the number of times #people are likely to have to type it. # +#=back +# #=cut # #sub add { @@ -120,10 +130,16 @@ sub new { # return $self; #} -=item $p->ship_out($pdf) +=head2 ship_out + + $p->ship_out($pdf) + +=over Ships the page out to the given output file context +=back + =cut sub ship_out { @@ -137,8 +153,4 @@ sub ship_out { return $self; } -=back - -=cut - 1; diff --git a/lib/PDF/Builder/Basic/PDF/Pages.pm b/lib/PDF/Builder/Basic/PDF/Pages.pm index 569304d..707c8f0 100644 --- a/lib/PDF/Builder/Basic/PDF/Pages.pm +++ b/lib/PDF/Builder/Basic/PDF/Pages.pm @@ -20,8 +20,8 @@ use warnings; use base 'PDF::Builder::Basic::PDF::Dict'; -our $VERSION = '3.025'; # VERSION -our $LAST_UPDATE = '3.024'; # manually update whenever code is changed +our $VERSION = '3.026'; # VERSION +our $LAST_UPDATE = '3.026'; # manually update whenever code is changed use PDF::Builder::Basic::PDF::Array; use PDF::Builder::Basic::PDF::Dict; @@ -43,9 +43,11 @@ themselves. =head1 METHODS -=over +=head2 new + + PDF::Builder::Basic::PDF::Pages->new($pdf, $parent) -=item PDF::Builder::Basic::PDF::Pages->new($pdf, $parent) +=over This creates a new Pages object in a PDF. Notice that the C<$parent> here is not the file context for the object, but the parent pages object for these @@ -55,6 +57,8 @@ I. C<$pdf> is the file object (or a reference to an array of I file object [3.016 and later, or multiple file objects earlier]) in which to create the new Pages object. +=back + =cut sub new { @@ -96,7 +100,11 @@ sub new { # return $self; #} -#=item $p->out_obj($is_new) +#=head2 out_obj +# +# $p->out_obj($is_new) +# +#=over # #Tells all the files that this thing is destined for that they should output this #object, come time to output. If this object has no parent, then it must be the @@ -104,6 +112,8 @@ sub new { #If C<$is_new> is set, then call C rather than C to create as #a new object in the file. # +#=back +# #=cut # #sub out_obj { @@ -130,11 +140,17 @@ sub _pdf { return $self->get_top()->{' parent'}; } -=item $p->find_page($page_number) +=head2 find_page + + $p->find_page($page_number) + +=over Returns the given page, using the page count values in the pages tree. Pages start at 0. +=back + =cut sub find_page { @@ -165,7 +181,11 @@ sub find_page_recursively { return; } -=item $p->add_page($page, $page_number) +=head2 add_page + + $p->add_page($page, $page_number) + +=over Inserts the page before the given C<$page_number>. C<$page_number> can be negative to count backwards from the END of the document. -1 is after the last @@ -178,6 +198,8 @@ document may simply be inserted in the appropriate leaf in the pages tree without adding any new branches or leaves, leaving it unbalanced (slower performance, but still usable). +=back + =cut # -- removed from end of second para: @@ -237,10 +259,10 @@ sub add_page_recursively { my ($self, $page, $page_index) = @_; my $parent = $self; - my $max_kids_per_parent = 8; # Why 8? + my $max_kids_per_parent = 8; # Why 8? effort to somewhat balance tree? if (scalar $parent->{'Kids'}->elements() >= $max_kids_per_parent and $parent->{'Parent'} and - $page_index < 1) { + $page_index < 0) { my $grandparent = $parent->{'Parent'}->realise(); $parent = $parent->new($parent->_pdf(), $grandparent); @@ -275,7 +297,11 @@ sub set_modified { return; } -#=item $root_pages = $p->rebuild_tree([@pglist]) +#=head2 rebuild_tree +# +# $root_pages = $p->rebuild_tree([@pglist]) +# +#=over # #B # @@ -285,6 +311,8 @@ sub set_modified { # #Returns the top of the tree for insertion in the root object. # +#=back +# #=cut # TBD where's the code? @@ -293,10 +321,16 @@ sub set_modified { # return; #} -=item @objects = $p->get_pages() +=head2 get_pages + + @objects = $p->get_pages() + +=over Returns a list of page objects in the document, in page order. +=back + =cut sub get_pages { @@ -325,10 +359,16 @@ sub get_pages_recursively { return @pages; } -=item $p->find_prop($key) +=head2 find_prop + + $p->find_prop($key) + +=over Searches up through the inheritance tree to find a property (key). +=back + =cut sub find_prop { @@ -354,7 +394,11 @@ sub find_prop { return; } -=item $p->add_font($pdf, $font) +=head2 add_font + + $p->add_font($pdf, $font) + +=over Creates or edits the resource dictionary at this level in the hierarchy. If the font is already supported, even through the hierarchy, then it is not added. @@ -364,6 +408,8 @@ swapped the order of C<$pdf> and C<$font>, requiring ad hoc swapping of parameters in user code, contrary to the POD definition above. Now the code matches the documentation. +=back + =cut sub add_font { @@ -395,14 +441,20 @@ sub add_font { return $self; } # end of add_font() -=item $p->bbox($xmin,$ymin, $xmax,$ymax, $param) +=head2 bbox + + $p->bbox($xmin,$ymin, $xmax,$ymax, $param) -=item $p->bbox($xmin,$ymin, $xmax,$ymax) + $p->bbox($xmin,$ymin, $xmax,$ymax) + +=over Specifies the bounding box for this and all child pages. If the values are identical to those inherited, no change is made. C<$param> specifies the attribute name so that other 'bounding box'es can be set with this method. +=back + =cut sub bbox { @@ -428,11 +480,17 @@ sub bbox { return $self; } -=item $p->proc_set(@entries) +=head2 proc_set + + $p->proc_set(@entries) + +=over Ensures that the current resource contains all the entries in the proc_sets listed. If necessary, it creates a local resource dictionary to achieve this. +=back + =cut sub proc_set { @@ -474,10 +532,16 @@ sub empty { return $self; } -=item $p->get_top() +=head2 get_top + + $p->get_top() + +=over Returns the top of the pages tree. +=back + =cut sub get_top { @@ -489,8 +553,4 @@ sub get_top { return $top->realise(); } -=back - -=cut - 1; diff --git a/lib/PDF/Builder/Basic/PDF/String.pm b/lib/PDF/Builder/Basic/PDF/String.pm index 526a85b..3371103 100644 --- a/lib/PDF/Builder/Basic/PDF/String.pm +++ b/lib/PDF/Builder/Basic/PDF/String.pm @@ -20,8 +20,8 @@ use base 'PDF::Builder::Basic::PDF::Objind'; use strict; use warnings; -our $VERSION = '3.025'; # VERSION -our $LAST_UPDATE = '3.024'; # manually update whenever code is changed +our $VERSION = '3.026'; # VERSION +our $LAST_UPDATE = '3.026'; # manually update whenever code is changed =head1 NAME @@ -30,8 +30,6 @@ for simple objects that are basically stringlike (Number, Name, etc.) =head1 METHODS -=over - =cut our %trans = ( @@ -56,12 +54,18 @@ our %out_trans = ( ')' => ')', ); -=item PDF::Builder::Basic::PDF::String->from_pdf($string) +=head2 from_pdf + + PDF::Builder::Basic::PDF::String->from_pdf($string) + +=over Creates a new string object (not a full object yet) from a given string. The string is parsed according to input criteria with escaping working. +=back + =cut sub from_pdf { @@ -74,12 +78,18 @@ sub from_pdf { return $self; } -=item PDF::Builder::Basic::PDF::String->new($string) +=head2 new + + PDF::Builder::Basic::PDF::String->new($string) + +=over Creates a new string object (not a full object yet) from a given string. The string is parsed according to input criteria with escaping working. +=back + =cut sub new { @@ -92,10 +102,16 @@ sub new { return $self; } -=item $s->convert($str) +=head2 convert + + $s->convert($str) + +=over Returns $str converted as per criteria for input from PDF file +=back + =cut sub convert { @@ -171,20 +187,32 @@ sub convert { return $output; } -=item $s->val() +=head2 val + + $s->val() + +=over Returns the value of this string (the string itself). +=back + =cut sub val { return $_[0]->{'val'}; } -=item $s->as_pdf() +=head2 as_pdf + + $s->as_pdf() + +=over Returns the string formatted for output as PDF for PDF File object $pdf. +=back + =cut sub as_pdf { @@ -210,10 +238,16 @@ sub as_pdf { } } -=item $s->outobjdeep($fh, $pdf) +=head2 outobjdeep + + $s->outobjdeep($fh, $pdf) + +=over Outputs the string in PDF format, complete with necessary conversions. +=back + =cut sub outobjdeep { @@ -223,8 +257,4 @@ sub outobjdeep { return; } -=back - -=cut - 1; diff --git a/lib/PDF/Builder/Basic/PDF/Utils.pm b/lib/PDF/Builder/Basic/PDF/Utils.pm index a008c9e..8b3f7ed 100644 --- a/lib/PDF/Builder/Basic/PDF/Utils.pm +++ b/lib/PDF/Builder/Basic/PDF/Utils.pm @@ -18,8 +18,8 @@ package PDF::Builder::Basic::PDF::Utils; use strict; use warnings; -our $VERSION = '3.025'; # VERSION -our $LAST_UPDATE = '3.024'; # manually update whenever code is changed +our $VERSION = '3.026'; # VERSION +our $LAST_UPDATE = '3.026'; # manually update whenever code is changed =head1 NAME @@ -29,9 +29,7 @@ PDF::Builder::Basic::PDF::Utils - Utility functions for PDF library A set of utility functions to save the fingers of the PDF library users! -=head1 FUNCTIONS - -=over +=head1 METHODS =cut @@ -50,67 +48,107 @@ use vars qw(@EXPORT @ISA); @EXPORT = qw(PDFBool PDFArray PDFDict PDFName PDFNull PDFNum PDFString PDFStr PDFStrHex PDFUtf); -=item PDFBool() +=head2 PDFBool + + PDFBool() + +=over Creates a Bool via PDF::Builder::Basic::PDF::Bool->new() +=back + =cut sub PDFBool { return PDF::Builder::Basic::PDF::Bool->new(@_); } -=item PDFArray() +=head2 PDFArray + + PDFArray() + +=over Creates an array via PDF::Builder::Basic::PDF::Array->new() +=back + =cut sub PDFArray { return PDF::Builder::Basic::PDF::Array->new(@_); } -=item PDFDict() +=head2 PDFDict + + PDFDict() + +=over Creates a dict via PDF::Builder::Basic::PDF::Dict->new() +=back + =cut sub PDFDict { return PDF::Builder::Basic::PDF::Dict->new(@_); } -=item PDFName() +=head2 PDFName + + PDFName() + +=over Creates a name via PDF::Builder::Basic::PDF::Name->new() +=back + =cut sub PDFName { return PDF::Builder::Basic::PDF::Name->new(@_); } -=item PDFNull() +=head2 PDFNull + + PDFNull() + +=over Creates a null via PDF::Builder::Basic::PDF::Null->new() +=back + =cut sub PDFNull { return PDF::Builder::Basic::PDF::Null->new(@_); } -=item PDFNum() +=head2 PDFNum + + PDFNum() + +=over Creates a number via PDF::Builder::Basic::PDF::Number->new() +=back + =cut sub PDFNum { return PDF::Builder::Basic::PDF::Number->new(@_); } -=item PDFString($text, $usage) +=head2 PDFString + + PDFString($text, $usage) + +=over Returns either PDFStr($text) or PDFUtf($text), depending on whether C<$text> is already in UTF-8 and whether the C<$usage> permits UTF-8. If UTF-8 is I @@ -155,6 +193,8 @@ Any other usage where UTF-8 text is B permitted. =back +=back + =cut sub PDFString { @@ -184,22 +224,34 @@ sub PDFString { } } -=item PDFStr() +=head2 PDFStr + + PDFStr() + +=over Creates a string via PDF::Builder::Basic::PDF::String->new() B It is preferable that you use C instead. +=back + =cut sub PDFStr { return PDF::Builder::Basic::PDF::String->new(@_); } -=item PDFStrHex() +=head2 PDFStrHex + + PDFStrHex() + +=over Creates a hex-string via PDF::Builder::Basic::PDF::String->new() +=back + =cut sub PDFStrHex { @@ -208,12 +260,18 @@ sub PDFStrHex { return $string; } -=item PDFUtf() +=head2 PDFUtf + + PDFUtf() + +=over Creates a utf8-string via PDF::Builder::Basic::PDF::String->new() B It is preferable that you use C instead. +=back + =cut sub PDFUtf { @@ -222,8 +280,4 @@ sub PDFUtf { return $string; } -=back - -=cut - 1; diff --git a/lib/PDF/Builder/Content.pm b/lib/PDF/Builder/Content.pm index e1f7621..1e36edb 100644 --- a/lib/PDF/Builder/Content.pm +++ b/lib/PDF/Builder/Content.pm @@ -5,8 +5,8 @@ use base 'PDF::Builder::Basic::PDF::Dict'; use strict; use warnings; -our $VERSION = '3.025'; # VERSION -our $LAST_UPDATE = '3.024'; # manually update whenever code is changed +our $VERSION = '3.026'; # VERSION +our $LAST_UPDATE = '3.026'; # manually update whenever code is changed use Carp; use Compress::Zlib qw(); @@ -132,13 +132,17 @@ translate, rotate, scale, and skew calls I any previous settings. If you want to combine multiple transformations for text, use the C call. -=over +=head3 translate + + $content->translate($dx,$dy) -=item $content->translate($dx,$dy) +=over -Moves the origin along the x and y axes by +Moves the origin along the x and y axes to C<$dx> and C<$dy> respectively. +=back + =cut sub _translate { @@ -156,7 +160,11 @@ sub translate { return $self; } -=item $content->rotate($degrees) +=head3 rotate + + $content->rotate($degrees) + +=over Rotates the coordinate system counter-clockwise (anti-clockwise) around the current origin. Use a negative argument to rotate clockwise. Note that 360 @@ -172,6 +180,8 @@ This C call permits any angle. Do not confuse it with the I rotation C call, which only permits increments of 90 degrees (with opposite sign!), but I shift the origin to another corner of the sheet. +=back + =cut sub _rotate { @@ -189,11 +199,17 @@ sub rotate { return $self; } -=item $content->scale($sx,$sy) +=head3 scale + + $content->scale($sx,$sy) + +=over Scales (stretches) the coordinate systems along the x and y axes. Separate multipliers are provided for x and y. +=back + =cut sub _scale { @@ -211,13 +227,19 @@ sub scale { return $self; } -=item $content->skew($skx,$sky) +=head3 skew + + $content->skew($skx,$sky) + +=over Skews the coordinate system by C<$skx> degrees (counter-clockwise/anti-clockwise) from the x axis I C<$sky> degrees (clockwise) from the y axis. Note that 360 degrees will be treated the same as 0 degrees. +=back + =cut sub _skew { @@ -235,7 +257,11 @@ sub skew { return $self; } -=item $content->transform(%opts) +=head3 transform + + $content->transform(%opts) + +=over Use one or more of the given %opts: @@ -273,6 +299,8 @@ If C is true, and if this is not the first call to a transformation method, the previous transformation will be performed again, modified by any other provided arguments. +=back + =cut sub _transform { @@ -380,7 +408,11 @@ sub transform { return $self; } -=item $content->transform_rel(%opts) +=head3 transform_rel + + $content->transform_rel(%opts) + +=over Makes transformations similarly to C, except that it I to the previously set values, rather than I them (except for @@ -388,6 +420,8 @@ I, which B the new values with the old). Unlike C, C and C are not supported. +=back + =cut sub transform_rel { @@ -420,22 +454,28 @@ sub transform_rel { return $self; } -=item $content->matrix($a, $b, $c, $d, $e, $f) +=head3 matrix + + $content->matrix($a, $b, $c, $d, $e, $f) + +=over I<(Advanced)> Sets the current transformation matrix manually. Unless you have a particular need to enter transformations manually, you should use the C method instead. - $a = cos(rot) * scale factor for X - $b = sin(rot) * tan(skew for X) - $c = -sin(rot) * tan(skew for Y) - $d = cos(rot) * scale factor for Y - $e = translation for X - $f = translation for Y + $a = cos(rot) * scale factor for X + $b = sin(rot) * tan(skew for X) + $c = -sin(rot) * tan(skew for Y) + $d = cos(rot) * scale factor for Y + $e = translation for X + $f = translation for Y In text mode, the text matrix is B. In graphics mode, C<$self> is B. +=back + =cut sub _matrix_text { @@ -478,15 +518,15 @@ sub matrix { } } -=back - =head2 Graphics State Parameters The following calls also affect the B state. -=over +=head3 linewidth, line_width -=item $content->linewidth($width) + $content->linewidth($width) + +=over Sets the width of the stroke (in points). This is the line drawn in graphics mode, or the I of a character in text mode (with appropriate C @@ -497,6 +537,8 @@ B C This is provided for compatibility with PDF::API2. +=back + =cut sub _linewidth { @@ -519,7 +561,11 @@ sub linewidth { return $self; } -=item $content->linecap($style) +=head3 linecap, line_cap + + $content->linecap($style) + +=over Sets the style to be used at the end of a stroke. This applies to lines which come to a free-floating end, I to "joins" ("corners") in @@ -551,6 +597,8 @@ being set, C<$self> is B so that calls may be chained. Either a number or a string (case-insensitive) may be given. +=back + =cut sub _linecap { @@ -584,7 +632,11 @@ sub linecap { return $self; } -=item $content->linejoin($style) +=head3 linejoin, line_join + + $content->linejoin($style) + +=over Sets the style of join to be used at corners of a path (within a multisegment polyline). @@ -621,6 +673,8 @@ being set, C<$self> is B so that calls may be chained. Either a number or a string (case-insensitive) may be given. +=back + =cut sub _linejoin { @@ -654,7 +708,11 @@ sub linejoin { return $self; } -=item $content->miterlimit($ratio) +=head3 miterlimit, miter_limit + + $content->miterlimit($ratio) + +=over Sets the miter limit when the line join style is a I join. @@ -675,6 +733,8 @@ This is provided for compatibility with PDF::API2. Long ago, in a distant galaxy, this method was misnamed I, but that was removed a while ago. Any code using that name should be updated! +=back + =cut sub _miterlimit { @@ -700,13 +760,17 @@ sub miterlimit { # Note: miterlimit was originally named incorrectly to meterlimit, renamed. # is available in PDF::API2 -=item $content->linedash() +=head3 linedash, line_dash_pattern + + $content->linedash() -=item $content->linedash($length) + $content->linedash($length) -=item $content->linedash($dash_length, $gap_length, ...) + $content->linedash($dash_length, $gap_length, ...) -=item $content->linedash('pattern' => [$dash_length, $gap_length, ...], 'shift' => $offset) + $content->linedash('pattern' => [$dash_length, $gap_length, ...], 'shift' => $offset) + +=over Sets the line dash pattern. @@ -731,6 +795,9 @@ the reader software to form an even number of elements (pairs). If a single argument of B<-1> is given, the current setting is B. This is an array consisting of two elements: an anonymous array containing the dash pattern (default: empty), and the shift (offset) amount (default: 0). +It may be used directly in a linedash() call, as linedash will recognize the +special pattern [ array, number ]. + If the dash pattern is being I, C<$self> is B so that calls may be chained. @@ -738,6 +805,8 @@ B C This is provided for compatibility with PDF::API2. +=back + =cut sub _linedash { @@ -769,15 +838,31 @@ sub line_dash_pattern { return linedash(@_); } ## no critic sub linedash { my ($self, @pat) = @_; + # request existing pattern and offset? if (scalar @pat == 1 && $pat[0] == -1) { return @{$self->{' linedash'}}; } + # request to restore stored pattern and offset? + if (scalar @pat == 2 && ref($pat[0]) eq 'ARRAY' && ref($pat[1]) eq '') { + @{$self->{' linedash'}} = @pat; + if (@{$pat[0]}) { + # not an empty array + return ('[', floats(@{$pat[0]}), '] ', $pat[1], ' d'); + } else { + return ('[ ] 0 d'); + } + } + # anything else, including empty pattern $self->add($self->_linedash(@pat)); return $self; } -=item $content->flatness($tolerance) +=head3 flatness, flatness_tolerance + + $content->flatness($tolerance) + +=over I<(Advanced)> Sets the maximum variation in output pixels when drawing curves. The defined range of C<$tolerance> is 0 to 100, with 0 meaning I C This is provided for compatibility with PDF::API2. +=back + =cut sub _flatness { @@ -819,11 +906,17 @@ sub flatness { return $self; } -=item $content->egstate($object) +=head3 egstate + + $content->egstate($object) + +=over I<(Advanced)> Adds an Extended Graphic State B containing additional state parameters. +=back + =cut sub egstate { @@ -835,18 +928,20 @@ sub egstate { return $self; } -=back - =head2 Path Construction (Drawing) -=over +=head3 move + + $content->move($x,$y) -=item $content->move($x,$y) +=over Starts a new path at the specified coordinates. Note that multiple x,y pairs I be given, although this isn't that useful (only the last pair would have an effect). +=back + =cut sub _move { @@ -879,11 +974,17 @@ sub move { return $self; } -=item $content->close() +=head3 close + + $content->close() + +=over Closes and ends the current path by extending a line from the current position to the starting position. +=back + =cut sub close { @@ -896,7 +997,11 @@ sub close { return $self; } -=item $content->endpath() +=head3 endpath, end + + $content->endpath() + +=over Ends the current path without explicitly enclosing it. That is, unlike C, there is B line segment @@ -907,6 +1012,8 @@ B C This is provided for compatibility with PDF::API2. Do not confuse it with the C<$pdf-Eend()> method! +=back + =cut sub end { return endpath(@_); } ## no critic @@ -919,18 +1026,18 @@ sub endpath { return $self; } -=back - =head3 Straight line constructs -B None of these will actually be I until you call C or -C. They are merely setting up the path to draw. +B None of these will actually be I until you call C, +C, or C. They are merely setting up the path to draw. -=over +=head4 line + + $content->line($x,$y) -=item $content->line($x,$y) + $content->line($x,$y, $x2,$y2,...) -=item $content->line($x,$y, $x2,$y2,...) +=over Extends the path in a line from the I coordinates to the specified coordinates, and updates the current position to be the new @@ -942,6 +1049,8 @@ because the first C<[$x,$y]> pair in a polyline is a I operation. Also, the C setting will be used rather than the C setting for treating the ends of segments. +=back + =cut sub _line { @@ -972,14 +1081,20 @@ sub line { return $self; } -=item $content->hline($x) +=head4 hline, vline -=item $content->vline($y) + $content->hline($x) + + $content->vline($y) + +=over Shortcuts for drawing horizontal and vertical lines from the current position. They are like C, but to the new x and current y (C), or to the the current x and new y (C). +=back + =cut sub hline { @@ -1010,7 +1125,11 @@ sub vline { return $self; } -=item $content->polyline($x1,$y1, ..., $xn,$yn) +=head4 polyline + + $content->polyline($x1,$y1, ..., $xn,$yn) + +=over This is a shortcut for creating a polyline path from the current position. It extends the path in line segments along the specified coordinates. @@ -1023,6 +1142,8 @@ I order (unlike the I order in C). Thus, while this is provided for compatibility with PDF::API2, it is I really an alias or alternate name for C! +=back + =cut # TBD document line_join vs line_cap? (see poly()). perhaps demo in Content.pl? @@ -1041,7 +1162,11 @@ sub polyline { return $self; } -=item $content->poly($x1,$y1, ..., $xn,$yn) +=head4 poly + + $content->poly($x1,$y1, ..., $xn,$yn) + +=over This is a shortcut for creating a polyline path. It moves to C<[$x1,$y1]>, and then extends the path in line segments along the specified coordinates. @@ -1057,6 +1182,8 @@ A critical distinction between the C method and the C method is that in this (C), the first pair of coordinates are treated as a I order. +=back + =cut sub poly { @@ -1071,7 +1198,11 @@ sub poly { return $self; } -=item $content = $content->rectangle($x1, $y1, $x2, $y2) +=head4 rectangle + + $content = $content->rectangle($x1, $y1, $x2, $y2) + +=over Creates a new rectangle-shaped path, between the two corner points C<[$x1, $y1]> and C<[$x2, $y2]>. The corner points are swapped if necessary, to make @@ -1082,6 +1213,8 @@ B that this is I an alias or alternate name for C. It handles only one rectangle, and takes corner coordinates for corner "2", rather than the width and height. +=back + =cut sub rectangle { @@ -1107,9 +1240,13 @@ sub rectangle { return $self; } -=item $content = $content->rect($x,$y, $w,$h) +=head4 rect + + $content = $content->rect($x,$y, $w,$h) -=item $content = $content->rect($x1,$y1, $w1,$h1, ..., $xn,$yn, $wn,$hn) + $content = $content->rect($x1,$y1, $w1,$h1, ..., $xn,$yn, $wn,$hn) + +=over This creates paths for one or more rectangles, with their lower left points at C<[$x,$y]> and specified widths (+x direction) and heights (+y direction). @@ -1123,6 +1260,8 @@ B that this differs from the C method in that multiple rectangles may be drawn in one call, and the second pair for each rectangle are the width and height, not the opposite corner coordinates. +=back + =cut sub rect { @@ -1145,7 +1284,11 @@ sub rect { return $self; } -=item $content->rectxy($x1,$y1, $x2,$y2) +=head4 rectxy + + $content->rectxy($x1,$y1, $x2,$y2) + +=over This creates a rectangular path, with C<[$x1,$y1]> and C<[$x2,$y2]> specifying I corners. They can be Lower Left and Upper Right, @@ -1156,6 +1299,8 @@ The current position is changed to the C<[$x1,$y1]> (first) pair. This is not I an alias or alternate name for C, as it permits the corner points to be specified in any order. +=back + =cut # TBD allow multiple rectangles, as in rect() @@ -1168,20 +1313,22 @@ sub rectxy { return $self; } -=back - =head3 Curved line constructs -B None of these will actually be I until you call C or -C. They are merely setting up the path to draw. +B None of these will actually be I until you call C, +C, or C. They are merely setting up the path to draw. -=over +=head4 circle -=item $content->circle($xc,$yc, $radius) + $content->circle($xc,$yc, $radius) + +=over This creates a circular path centered on C<[$xc,$yc]> with the specified radius. It does B change the current position. +=back + =cut sub circle { @@ -1193,12 +1340,18 @@ sub circle { return $self; } -=item $content->ellipse($xc,$yc, $rx,$ry) +=head4 ellipse + + $content->ellipse($xc,$yc, $rx,$ry) + +=over This creates a closed elliptical path centered on C<[$xc,$yc]>, with axis radii (semidiameters) specified by C<$rx> (x axis) and C<$ry> (y axis), respectively. It does not change the current position. +=back + =cut sub ellipse { @@ -1302,9 +1455,13 @@ sub _arctocurve { } } -=item $content->arc($xc,$yc, $rx,$ry, $alpha,$beta, $move, $dir) +=head4 arc -=item $content->arc($xc,$yc, $rx,$ry, $alpha,$beta, $move) + $content->arc($xc,$yc, $rx,$ry, $alpha,$beta, $move, $dir) + + $content->arc($xc,$yc, $rx,$ry, $alpha,$beta, $move) + +=over This extends the path along an arc of an ellipse centered at C<[$xc,$yc]>. The semidiameters of the elliptical curve are C<$rx> (x axis) and C<$ry> @@ -1320,6 +1477,8 @@ The optional C<$dir> arc sweep direction defaults to 0 (I), for a counter-clockwise/anti-clockwise sweep. Set to 1 (I) for a clockwise sweep. +=back + =cut sub arc { @@ -1353,9 +1512,13 @@ sub arc { return $self; } -=item $content->pie($xc,$yc, $rx,$ry, $alpha,$beta, $dir) +=head4 pie -=item $content->pie($xc,$yc, $rx,$ry, $alpha,$beta) + $content->pie($xc,$yc, $rx,$ry, $alpha,$beta, $dir) + + $content->pie($xc,$yc, $rx,$ry, $alpha,$beta) + +=over Creates a pie-shaped path from an ellipse centered on C<[$xc,$yc]>. The x-axis and y-axis semidiameters of the ellipse are C<$rx> and C<$ry>, @@ -1374,6 +1537,8 @@ sweep. This is a shortcut to draw a section of elliptical (or circular) arc and connect it to the center of the ellipse or circle, to form a pie shape. +=back + =cut sub pie { @@ -1389,10 +1554,14 @@ sub pie { return $self; } -=item $content->curve($cx1,$cy1, $cx2,$cy2, $x,$y) +=head4 curve + + $content->curve($cx1,$cy1, $cx2,$cy2, $x,$y) + +=over This extends the path in a curve from the current point to C<[$x,$y]>, -using the two specified I points to create a cubic Bezier curve, and +using the two specified I points to create a B, and updates the current position to be the new point (C<[$x,$y]>). Within a B object, the text's baseline follows the Bezier curve. @@ -1401,6 +1570,8 @@ Note that while multiple sets of three C<[x,y]> pairs are permitted, these are treated as I cubic Bezier curves. There is no attempt made to smoothly blend one curve into the next! +=back + =cut sub curve { @@ -1426,7 +1597,11 @@ sub curve { return $self; } -=item $content->qbspline($cx1,$cy1, $x,$y) +=head4 qbspline, spline + + $content->qbspline($cx1,$cy1, $x,$y) + +=over This extends the path in a curve from the current point to C<[$x,$y]>, using the two specified points to create a quadratic Bezier curve, and updates @@ -1459,6 +1634,8 @@ name is usable here. Since there are both quadratic and cubic splines available in PDF, it is preferred to use more descriptive names such as C and C to minimize confusion. +=back + =cut sub spline { return qbspline(@_); } ## no critic @@ -1491,7 +1668,11 @@ sub qbspline { return $self; } -=item $content->bspline($ptsRef, %opts) +=head4 bspline, cbspline + + $content->bspline($ptsRef, %opts) + +=over This extends the path in a curve from the current point to the end of a list of coordinate pairs in the array referenced by C<$ptsRef>. Smoothly continuous @@ -1510,6 +1691,8 @@ of the last line or curve drawn becomes the new current point. Options %opts: +=back + =over =item 'firstseg' => 'I' @@ -1628,14 +1811,16 @@ Bezier control points. =back -=back +=over -=head3 Special cases +B Adjacent points which are duplicates are consolidated. An extra coordinate at the end of the input point list (not a full C<[x,y]> pair) will, as usual, be ignored. +=back + =over =item 0 given points (after duplicate consolidation) @@ -1663,11 +1848,15 @@ C, C, and C. =back +=over + B C This is to emphasize that it is a I Bezier spline, as opposed to a I Bezier spline (see C above). +=back + =cut sub cbspline { return bspline(@_); } ## no critic @@ -2281,20 +2470,22 @@ sub _sweep { return $result; } -=over +=head4 bogen -=item $content->bogen($x1,$y1, $x2,$y2, $radius, $move, $larger, $reverse) + $content->bogen($x1,$y1, $x2,$y2, $radius, $move, $larger, $reverse) -=item $content->bogen($x1,$y1, $x2,$y2, $radius, $move, $larger) + $content->bogen($x1,$y1, $x2,$y2, $radius, $move, $larger) -=item $content->bogen($x1,$y1, $x2,$y2, $radius, $move) + $content->bogen($x1,$y1, $x2,$y2, $radius, $move) -=item $content->bogen($x1,$y1, $x2,$y2, $radius) + $content->bogen($x1,$y1, $x2,$y2, $radius) -(German for I, as in a segment (arc) of a circle. This is a segment -of a circle defined by the intersection of two circles of a given radius, -with the two intersection points as inputs. There are four possible resulting -arcs, which can be selected with C<$larger> and C<$reverse>.) +=over + +(I is German for I, as in a segment (arc) of a circle. This is a +segment of a circle defined by the intersection of two circles of a given +radius, with the two intersection points as inputs. There are B possible +resulting arcs, which can be selected with C<$larger> and C<$reverse>.) This extends the path along an arc of a circle of the specified radius between C<[$x1,$y1]> to C<[$x2,$y2]>. The current position is then set @@ -2307,38 +2498,59 @@ I a straight line to I and then the arc, but a blending into the curve from the current point. It will often I pass through I! Set C<$larger> to a I value to draw the larger ("outer") arc between the -two points, instead of the smaller one. Both arcs are -drawn I from I to I. The default value of I draws -the smaller arc. +two points, instead of the smaller one. Both arcs are drawn I from +I to I. The default value of I draws the smaller arc. +Note that the "other" circle's larger arc is used (the center point is +"flipped" across the line between I and I), rather than using the +"remainder" of the smaller arc's circle (which would necessitate reversing the +direction of travel along the arc -- see C<$reverse>). Set C<$reverse> to a I value to draw the mirror image of the specified arc (flip it over, so that its center point is on the other side of the line connecting the two points). Both arcs are drawn I from I to I. The default (I) draws -clockwise arcs. +clockwise arcs. An arc is B drawn from I to I; the direction +(clockwise or counter-clockwise) may be chosen. The C<$radius> value cannot be smaller than B the distance from C<[$x1,$y1]> to C<[$x2,$y2]>. If it is too small, the radius will be set to half the distance between the points (resulting in an arc that is a -semicircle). This is a silent error. +semicircle). This is a silent error, as even if the points are correct, due +to rounding etc. they may not fall I on the two circles. + +You can think of "looking" from I to I. In the dengenerate case, where +the radius is exactly half the distance between the points, there is no +difference between "small" and "large" arcs, and both cirles will coincide +with their center half way between I and I. Only the direction matters. +Once the radius is any larger, the two circles become distinct. The primary +circle is centered to your right, whose small arc is CW on your left; the +secondary circle is centered to your left, whose small arc is CCW on your +right. The "large" arcs are the arcs using the remainder of the circles: CW +large is part of the left (secondary) circle, and CCW large is part of the +right (primary) circle. + +=back =cut sub bogen { - my ($self, $x1,$y1, $x2,$y2, $r, $move, $larc, $spf) = @_; + my ($self, $x1,$y1, $x2,$y2, $r, $move, $larc, $dir) = @_; + # in POD description, dir is "reverse" flag my ($p0_x,$p0_y, $p1_x,$p1_y, $p2_x,$p2_y, $p3_x,$p3_y); - my ($dx,$dy, $x,$y, $alpha,$beta, $alpha_rad, $d,$z, $dir, @points); + my ($dx,$dy, $x,$y, $alpha,$beta, $alpha_rad, $d,$z, @points); if ($x1 == $x2 && $y1 == $y2) { die "bogen requires two distinct points"; + # SVG def of (arc) merely leaves it as a point } if ($r <= 0.0) { die "bogen requires a positive radius"; + # SVG def of (arc) merely takes absolute value } $move = 0 if !defined $move; $larc = 0 if !defined $larc; - $spf = 0 if !defined $spf; + $dir = 0 if !defined $dir; $dx = $x2 - $x1; $dy = $y2 - $y1; @@ -2350,7 +2562,7 @@ sub bogen { $alpha = rad2deg($alpha_rad); # use the complementary angle for flipped arc (arc center on other side) # effectively clockwise draw from P2 to P1 - $alpha -= 180 if $spf; + $alpha -= 180 if $dir; $d = 2*$r; # z/d must be no greater than 1.0 (arcsine arg) @@ -2368,7 +2580,7 @@ sub bogen { # note that start and end could be well out of +/-360 degree range @points = _arctocurve($r,$r, 90+$alpha+$beta/2,90+$alpha-$beta/2, 1); - if ($spf) { # flip order of points for reverse arc + if ($dir) { # flip order of points for reverse arc my @pts = @points; @points = (); while (@pts) { @@ -2406,15 +2618,18 @@ sub bogen { return $self; } -=back - =head2 Path Painting (Drawing) +=head3 stroke + + $content->stroke() + =over -=item $content->stroke() +Strokes the current path. That is, it is drawing solid or dashed I, but +B filling areas. -Strokes the current path. +=back =cut @@ -2430,11 +2645,15 @@ sub stroke { return $self; } -=item $content->fill($use_even_odd_fill) +=head3 fill + + $content->fill($use_even_odd_fill) -=item $content->fill('rule' => $rule) + $content->fill('rule' => $rule) -=item $content->fill() # use default nonzero rule + $content->fill() # use default nonzero rule + +=over Fill the current path's enclosed I. It does I stroke the enclosing path around the area. @@ -2466,6 +2685,8 @@ for more details on filling. The "rule" parameter is added for PDF::API2 compatibility. +=back + =cut sub fill { @@ -2487,11 +2708,15 @@ sub fill { return $self; } -=item $content->fillstroke($use_even_odd_fill) +=head3 fillstroke, paint, fill_stroke + + $content->fillstroke($use_even_odd_fill) + + $content->fillstroke('rule' => $rule) -=item $content->fillstroke('rule' => $rule) + $content->fillstroke() # use default nonzero rule -=item $content->fillstroke() # use default nonzero rule +=over B the current path's enclosed I and then B the enclosing path around the area (possibly with a different color). @@ -2528,6 +2753,8 @@ B C and C C is for compatibility with PDF::API2, while C is added for compatibility with many other PDF::API2-related renamed methods. +=back + =cut sub paint { return fillstroke(@_); } ## no critic @@ -2553,11 +2780,15 @@ sub fillstroke { return $self; } -=item $content->clip($use_even_odd_fill) +=head3 clip + + $content->clip($use_even_odd_fill) -=item $content->clip('rule' => $rule) + $content->clip('rule' => $rule) -=item $content->clip() # use default nonzero rule + $content->clip() # use default nonzero rule + +=over Modifies the current clipping path by intersecting it with the current path. Initially (a fresh page), the clipping path is the entire media. Each @@ -2610,6 +2841,8 @@ See the object discussion in L. The "rule" parameter is added for PDF::API2 compatibility. +=back + =cut sub clip { @@ -2631,7 +2864,11 @@ sub clip { return $self; } -=item $content->shade($shade, @coord) +=head3 shade + + $content->shade($shade, @coord) + +=over Sets the shading matrix. @@ -2648,6 +2885,8 @@ X-scaled and translated, Y-scaled and translated. =back +=back + =cut sub shade { @@ -2668,15 +2907,15 @@ sub shade { return $self; } -=back - =head2 Colors -=over +=head3 fillcolor, fill_color, strokecolor, stroke_color -=item $content->fillcolor($color) + $content->fillcolor($color) -=item $content->strokecolor($color) + $content->strokecolor($color) + +=over Sets the fill (enclosed area) or stroke (path) color. The interior of text characters are I, and (I ordered by C) the outline is @@ -2749,6 +2988,8 @@ B C and C. These are provided for PDF::API2 compatibility. +=back + =cut # TBD document in POD (examples) and add t tests for (pattern/shading space, @@ -2918,24 +3159,24 @@ sub strokecolor { } } -=back - =head2 External Objects -=over +=head3 image -=item $content->image($image_object, $x,$y, $width,$height) + $content->image($image_object, $x,$y, $width,$height) -=item $content->image($image_object, $x,$y, $scale) + $content->image($image_object, $x,$y, $scale) -=item $content->image($image_object, $x,$y) + $content->image($image_object, $x,$y) -=item $content->image($image_object) + $content->image($image_object) # Example my $image_object = $pdf->image_jpeg($my_image_file); $content->image($image_object, 100, 200); +=over + Places an image on the page in the specified location (specifies the lower left corner of the image). The default location is C<[0,0]>. @@ -2949,6 +3190,8 @@ For example, if you have a 600x600 image that you would like to be shown at 600dpi (i.e., one inch square), set the width and height to 72. (72 Big Points is one inch) +=back + =cut # deprecated in PDF::API2 -- suggests use of object() instead @@ -2982,13 +3225,17 @@ sub image { return $self; } -=item $content->formimage($form_object, $x,$y, $scaleX, $scaleY) +=head3 formimage -=item $content->formimage($form_object, $x,$y, $scale) + $content->formimage($form_object, $x,$y, $scaleX, $scaleY) -=item $content->formimage($form_object, $x,$y) + $content->formimage($form_object, $x,$y, $scale) -=item $content->formimage($form_object) + $content->formimage($form_object, $x,$y) + + $content->formimage($form_object) + +=over Places an XObject on the page in the specified location (giving the lower left corner of the image) and scale (applied to the image's native height @@ -3008,6 +3255,8 @@ by image width and height I C, and require scaling of C and have the user manually scale I by the image width and height (in pixels) in the call to C. +=back + =cut sub formimage { @@ -3035,11 +3284,20 @@ sub formimage { return $self; } -=item $content = $content->object($object, $x,$y, $scale_x,$scale_y) +=head3 object + + $content = $content->object($object, $x,$y, $scale_x,$scale_y) + +=over Places an image or other external object (a.k.a. XObject) on the page in the specified location. +Up to four optional arguments may be given, with their defaults as described +below. + +If C<$x> and C<$y> are omitted, the object will be placed at C<[0, 0]>. + For images, C<$scale_x> and C<$scale_y> represent the width and height of the image on the page, in points. If C<$scale_x> is omitted, it will default to 72 pixels per inch. If C<$scale_y> is omitted, the image will be scaled @@ -3054,13 +3312,19 @@ above), the position and scale will be relative to the updated coordinates. If no coordinate transformations are needed, this method can be called directly from the L object instead. +=back + =cut -# Behavior based on argument count -# 0: Place at 0, 0, 100% -# 2: Place at X, Y, 100% -# 3: Place at X, Y, scaled -# 4: Place at X, Y, scale_w, scale_h +# Behavior based on argument count. xo, x,y, scale_x/w,scale_y/h +# 1: Place at 0, 0, 100% +# 2: Place at x, 0, 100% +# 3: Place at X, Y, 100% +# 4: Place at X, Y, scaled +# 5: Place at X, Y, scale_w, scale_h +# TBD: size=>'points' or 'scale' to override Image usage. can do by finding +# an element 'size' (string) and inserting undef's before it to fill +# out @_ to 7+ in length. sub object { my ($self, $object, $x, $y, $scale_x, $scale_y) = @_; @@ -3085,8 +3349,6 @@ sub object { return $self; } -=back - =head2 Text =head3 Text State Parameters @@ -3095,9 +3357,11 @@ All of the following parameters that take a size are applied before any scaling takes place, so you don't need to adjust values to counteract scaling. -=over +=head4 charspace, character_spacing, char_space -=item $spacing = $content->charspace($spacing) + $spacing = $content->charspace($spacing) + +=over Sets additional spacing between B in a line. This is in I, and is initially zero. @@ -3107,10 +3371,28 @@ If C<$spacing> is given, the current setting is replaced by that value and C<$self> is B (to permit chaining). If C<$spacing> is not given, the current setting is B. +One use for character spacing is to adjust I in a line of text. +It is common to adjust inter-word spacing (e.g., TeX "glue" length) to justify +a line (see C), but in cases where the result is words too close +together (or too far apart), you may want to adjust tracking in order to force +spaces back to a more "reasonable" standard size. For example, if you have a +fairly "loose" line, with wide spaces between words, you could add a little +character spacing between the letters of words, and shrink the spaces down to a +more reasonable size. Don't overdo it, and make the words themselves difficult +to read! You also would want to take care to "drive" the resulting spaces +towards a consistent width throughout a document (or at least, a paragraph). + +You may also choose to use character spacing for special effects, such as a +high-level heading expanded with extra space. This is a decorative effect, and +should be used with restraint. + B be careful about using C if you are using a connected -font. This might include Arabic, Devanagari, Latin cursive handwriting, and so -on. You don't want to leave gaps between characters, or cause overlaps. For -such fonts and typefaces, set the C spacing to 0. +("script") font. This might include Arabic, Devanagari, Latin cursive +handwriting, and so on. You don't want to leave gaps between characters, or +cause overlaps. For such fonts and typefaces, you I need to explicitly set +the C spacing to 0, if you have set it to non-zero elsewhere. +PDF::Builder may not be able to determine that a given font is a connected +script font, and automatically suppress non-zero character spacing. B C and C @@ -3118,6 +3400,8 @@ I is provided for compatibility with PDF::API2, while I is provided to be consistent with many other method name changes in PDF::API2. +=back + =cut sub _charspace { @@ -3143,7 +3427,11 @@ sub charspace { } } -=item $spacing = $content->wordspace($spacing) +=head4 wordspace, word_spacing, word_space + + $spacing = $content->wordspace($spacing) + +=over Sets additional spacing between B in a line. This is in I and is initially zero @@ -3153,6 +3441,10 @@ If C<$spacing> is given, the current setting is replaced by that value and C<$self> is B (to permit chaining). If C<$spacing> is not given, the current setting is B. +See the note in C in regards to I adjustment, and its +effect on C. The two calls may often be used together for optimal +results (although resulting in a somewhat increased PDF file size). + Note that it is a limitation of the PDF specification (as of version 1.7, section 9.3.3) that only spacing with an ASCII space (x20) is adjusted. Neither required blanks (xA0) nor any multiple-byte spaces (including thin and wide @@ -3164,6 +3456,8 @@ I is provided for compatibility with PDF::API2, while I is provided to be consistent with many other method name changes in PDF::API2. +=back + =cut sub _wordspace { @@ -3189,7 +3483,11 @@ sub wordspace { } } -=item $scale = $content->hscale($scale) +=head4 hscale + + $scale = $content->hscale($scale) + +=over Sets the percentage of horizontal text scaling (relative sizing, I spacing). This is initally 100 (percent, i.e., no scaling). A scale of greater @@ -3205,6 +3503,8 @@ justify text, you will usually be better off using C and C to expand (or slightly condense) a line to fill a desired width. Also see the C calls for this purpose. +=back + =cut sub _hscale { @@ -3230,9 +3530,15 @@ sub hscale { # note that the private class data ' hspace' is no longer supported # PDF::API2 still provides 'hspace' and '_hspace' -=item $leading = $content->leading($leading) +# lead() and the associated lead variable have been replaced by leading() + +=head4 leading + + $leading = $content->leading($leading) -=item $leading = $content->leading() + $leading = $content->leading() + +=over Sets the text leading, which is the distance between baselines. This is initially B (i.e., the lines will be printed on top of each @@ -3247,20 +3553,10 @@ text baseline distance, in points). In cold metal typesetting, I was usually the I spacing between lines beyond the font height itself, created by inserting lead (type alloy) shims. -=item $leading = $content->lead($leading) - -=item $leading = $content->lead() - -B to be removed after March 2023. Use C now. - -Note that the C<$self-E{' lead'}> internal variable is no longer available, -having been replaced by C<$self-E{' leading'}>. +=back =cut -# to be removed 3/2023 or later -sub lead { return leading(@_); } - sub _leading { my ($leading) = @_; @@ -3280,7 +3576,11 @@ sub leading { } } -=item $mode = $content->render($mode) +=head4 render + + $mode = $content->render($mode) + +=over Sets the text rendering mode. @@ -3308,6 +3608,8 @@ If C<$mode> is given, the current setting is replaced by that value and C<$self> is B (to permit chaining). If C<$mode> is not given, the current setting is B. +=back + =cut sub _render { @@ -3330,7 +3632,11 @@ sub render { } } -=item $dist = $content->rise($dist) +=head4 rise + + $dist = $content->rise($dist) + +=over Adjusts the baseline up or down from its current location. This is initially zero. A C<$dist> greater than 0 moves the baseline B the page @@ -3342,6 +3648,8 @@ If C<$dist> is given, the current setting is replaced by that value and C<$self> is B (to permit chaining). If C<$dist> is not given, the current setting is B. +=back + =cut sub _rise { @@ -3363,7 +3671,11 @@ sub rise { } } -=item %state = $content->textstate(charspace => $value, wordspace => $value, ...) +=head4 textstate + + %state = $content->textstate(charspace => $value, wordspace => $value, ...) + +=over This is a shortcut for setting multiple text state parameters at once. If any parameters are set, an I hash is B. @@ -3372,6 +3684,8 @@ state settings (a hash of the state is B). B This does not work with the C and C commands. +=back + =cut sub textstate { @@ -3419,7 +3733,11 @@ sub textstate { return %state; } -=item $content->font($font_object, $size) +=head4 font + + $content->font($font_object, $size) + +=over Sets the font and font size. C<$font> is an object created by calling L to add the font to the document. @@ -3434,6 +3752,8 @@ L to add the font to the document. $pdf->save('sample.pdf'); +=back + =cut sub _font { @@ -3477,15 +3797,15 @@ sub _fontset { return $self; } -=back - =head3 Positioning Text -=over +=head4 position -=item $content = $content->position($x, $y) # Set (also returns object, for ease of chaining) + $content = $content->position($x, $y) # Set (also returns object, for ease of chaining) -=item ($x, $y) = $content->position() # Get + ($x, $y) = $content->position() # Get + +=over If called I arguments (Set), moves to the start of the current line of text, offset by C<$x> and C<$y> (right and up for positive values). @@ -3496,6 +3816,8 @@ cursor (before the effects of any coordinate transformation methods). Note that this is very similar in function to C, added recently to PDF::API2 and added here for compatibility. +=back + =cut sub position { @@ -3517,7 +3839,11 @@ sub position { return @{$self->{' textlinematrix'}}; } -=item ($tx,$ty) = $content->textpos() +=head4 textpos, (see also) position + + ($tx,$ty) = $content->textpos() + +=over B the current text position on the page (where next write will happen) as an array. @@ -3527,6 +3853,8 @@ the next write will occur. B C (added for compatibility with PDF::API2) +=back + =cut sub _textpos { @@ -3556,7 +3884,11 @@ sub textpos { return $self->_textpos(@{$self->{" textlinematrix"}}); } -=item $content->distance($dx,$dy) +=head4 distance + + $content->distance($dx,$dy) + +=over This moves to the start of the previously-written line, plus an offset by the given amounts, which are both required. C<[0,0]> would overwrite the previous @@ -3569,6 +3901,8 @@ B that subsequent text writes will be relative to this new starting (left) point and Y position! E.g., if you give a non-zero C<$dx>, subsequent lines will be indented by that amount. +=back + =cut sub distance { @@ -3582,11 +3916,15 @@ sub distance { return $self; } -=item $content->cr() +=head4 cr + + $content->cr() + + $content->cr($vertical_offset) -=item $content->cr($vertical_offset) + $content->cr(0) -=item $content->cr(0) +=over If passed without an argument, moves (down) to the start of the I line (distance set by C). This is similar to C. @@ -3603,6 +3941,8 @@ That is, it acts as a simple carriage return, without a linefeed. Note that any setting for C is ignored. If you wish to account for the C setting, you may wish to use the C method instead. +=back + =cut sub cr { @@ -3620,11 +3960,15 @@ sub cr { return $self; } -=item $content->nl() +=head4 nl + + $content->nl() -=item $content->nl($indent) + $content->nl($indent) -=item $content->nl(0) + $content->nl(0) + +=over Moves to the start of the next line (see C). If C<$indent> is not given, or is 0, there is no indentation. Otherwise, indent by that amount (Ident @@ -3634,6 +3978,8 @@ space", or roughly 88 per em. Note that any setting for C is ignored. If you wish to account for the C setting, you may wish to use the C method instead. +=back + =cut sub nl { @@ -3653,7 +3999,11 @@ sub nl { return $self; } -=item $content = $content->crlf() +=head4 crlf + + $content = $content->crlf() + +=over Moves to the start of the next line, based on the L setting. It returns its own object, for ease of chaining. @@ -3663,6 +4013,8 @@ If leading isn't set, a default distance of 120% of the font size will be used. Added for compatibility with PDF::API2 changes; may be used to replace both C and C methods. +=back + =cut sub crlf { @@ -3681,7 +4033,14 @@ sub crlf { return $self; } -=item $width = $content->advancewidth($string, %opts) +=head4 advancewidth, text_width + + $width = $content->advancewidth($string, %opts) + +=over + +Returns the number of points that will be used (horizontally) by the input +string. This assumes all on one line (no line breaking). Options %opts: @@ -3727,6 +4086,8 @@ B C This is provided for compatibility with PDF::API2. +=back + =cut sub text_width { return advancewidth(@_); } ## no critic @@ -3743,6 +4104,10 @@ sub advancewidth { $opts{$k} = $self->{" $k"} unless defined $opts{$k}; } # any other options given are ignored + + # $opts{'font'} (not ' font'}) needs to be defined. fail if not. + # other code should first fatal error in text() call, this is a fallback + return 0 if !defined $opts{'font'}; $glyph_width = $opts{'font'}->width($text)*$opts{'fontsize'}; $num_space = $text =~ y/\x20/\x20/; @@ -3754,31 +4119,59 @@ sub advancewidth { return $advance; } -=back - =head3 Rendering Text -=over +=head4 Single Lines -=back +=head4 text -=head4 Single Lines + $width = $content->text($text, %opts) =over -=item $width = $content->text($text, %opts) - -Adds text to the page (left justified). +Adds text to the page (left justified by default). The width used (in points) is B. Options: =over +=item 'align' => position + +Align the text, assuming left-to-right writing direction (RTL/bidirectional is +not currently supported). + +=over + +=item 'l' or 'left' (case insensitive). + +B Text I at the current text position. + +=item 'c' or 'center' (case insensitive). + +Text is I at the current text position. + +=item 'r' or 'right' (case insensitive). + +Text I (is right justified to) at the current text position. + +=back + +In all cases, the ending text position is at the (right) end of the text. +If mixing various alignments, you should explicitly place the current text +position so as to not overwrite earlier text. + =item 'indent' => $distance Indents the text by the number of points (A value less than 0 gives an I). +The indentation amount moves the text left (negative indentation) or right +(positive indentation), regardless of alignment. This allows desired alignment +effects (for centered and right) that aren't exactly aligned on the current +position. For example, consider a column of decimal numbers centered on a +desired I position, but aligned on their decimal points. The C +would be on a per-line basis, adjusted by the length of the number and the +decimal position. =item 'underline' => 'none' @@ -3824,10 +4217,20 @@ Example: # distance 7, thickness 1.5, color yellow 'strikethru' => [4,[1,'red'],7,[1.5,'yellow']], +=item 'strokecolor' => color_spec + +Defines the underline or strikethru line color, if different from the text +color. + +=back + =back =cut +# TBD: consider 'overline' similar to underline +# bidirectional/RTL identation, alignment meanings? + sub _text_underline { my ($self, $xy1,$xy2, $underline, $color) = @_; @@ -3953,12 +4356,26 @@ sub _text_strikethru { sub text { my ($self, $text, %opts) = @_; # copy dashed option names to preferred undashed names + if (defined $opts{'-align'} && !defined $opts{'align'}) { $opts{'align'} = delete($opts{'-align'}); } if (defined $opts{'-indent'} && !defined $opts{'indent'}) { $opts{'indent'} = delete($opts{'-indent'}); } if (defined $opts{'-underline'} && !defined $opts{'underline'}) { $opts{'underline'} = delete($opts{'-underline'}); } if (defined $opts{'-strokecolor'} && !defined $opts{'strokecolor'}) { $opts{'strokecolor'} = delete($opts{'-strokecolor'}); } if (defined $opts{'-strikethru'} && !defined $opts{'strikethru'}) { $opts{'strikethru'} = delete($opts{'-strikethru'}); } - my $wd = 0; + my $align = 'l'; # default + if (defined $opts{'align'}) { + $align = lc($opts{'align'}); + if ($align eq 'l' || $align eq 'left') { + $align = 'l'; + } elsif ($align eq 'c' || $align eq 'center') { + $align = 'c'; + } elsif ($align eq 'r' || $align eq 'right') { + $align = 'r'; + } else { + $align = 'l'; # silent error on bad alignment + } + } + if ($self->{' fontset'} == 0) { unless (defined($self->{' font'}) and $self->{' fontsize'}) { croak q{Can't add text without first setting a font and font size}; @@ -3966,24 +4383,48 @@ sub text { $self->font($self->{' font'}, $self->{' fontsize'}); $self->{' fontset'} = 1; } + + my $wd = $self->advancewidth($text); + + my $indent = 0; # default if (defined $opts{'indent'}) { - $wd += $opts{'indent'}; - $self->matrix_update($wd, 0); + $indent = $opts{'indent'}; + # TBD: later may define indentation for RTL/bidirectional } - my $ulxy1 = [$self->_textpos2()]; - if (defined $opts{'indent'}) { - # changed for Acrobat 8 and possibly others - # $self->add('[', (-$opts{'indent'}*(1000/$self->{' fontsize'})*(100/$self->hscale())), ']', 'TJ'); - $self->add($self->{' font'}->text($text, $self->{' fontsize'}, (-$opts{'indent'}*(1000/$self->{' fontsize'})*(100/$self->hscale())))); + # now have alignment, indentation amount, text width + # adjust indentation by text width and alignment. negative to move text left + if ($align eq 'l') { + # no change + } elsif ($align eq 'c') { + $indent -= $wd/2; + } else { # 'r' + $indent -= $wd; + } + + # indent is points to move text left (<0) or right (>0) + # per input 'indent' AND alignment AND text width + $self->matrix_update($indent, 0) if ($indent); # move current pos to start + + my $ulxy1 = [$self->_textpos2()]; # x,y start of under/thru line + + if ($indent) { + # now indent is positive >0 to move left. convert to milliems and scale + $self->add( + $self->{' font'}->text( + $text, + $self->{' fontsize'}, + -$indent*(1000/$self->{' fontsize'})*(100/$self->hscale()) )); } else { - $self->add($self->{' font'}->text($text, $self->{' fontsize'})); + $self->add( + $self->{' font'}->text( + $text, + $self->{' fontsize'} )); } - $wd = $self->advancewidth($text); - $self->matrix_update($wd, 0); + $self->matrix_update($wd, 0); # move current position right to end of text - my $ulxy2 = [$self->_textpos2()]; + my $ulxy2 = [$self->_textpos2()]; # x,y end of under/thru line if (defined $opts{'underline'}) { $self->_text_underline($ulxy1,$ulxy2, $opts{'underline'}, $opts{'strokecolor'}); @@ -4019,7 +4460,11 @@ sub _metaEnd { return $self; } -=item $width = $content->textHS($HSarray, $settings, %opts) +=head4 textHS + + $width = $content->textHS($HSarray, $settings, %opts) + +=over Takes an array of hashes produced by HarfBuzz::Shaper and outputs them to the PDF output file. HarfBuzz outputs glyph CIDs and positioning information. @@ -4164,13 +4609,15 @@ to HarfBuzz::Shaper (C only, with .ttf or .otf files), and the font size must be the same. The appropriate location on the page must also already have been specified. -B as HarfBuzz::Shaper is still in its early days, it is possible that -there will be major changes in its API. We hope that all changes will be -upwardly compatible, but do not control this package and cannot guarantee that -there will not be any incompatible changes that in turn require changes to -PDF::Builder (C). +=back =cut +#B as HarfBuzz::Shaper is still in its early days, it is possible that +#there will be major changes in its API. We hope that all changes will be +#upwardly compatible, but do not control this package and cannot guarantee that +#there will not be any incompatible changes that in turn require changes to +#PDF::Builder (C). +# sub textHS { my ($self, $HSarray, $settings, %opts) = @_; @@ -4468,7 +4915,11 @@ sub _outputCID { return; } -=item $width = $content->advancewidthHS($HSarray, $settings, %opts) +=head4 advancewidthHS, text_widthHS + + $width = $content->advancewidthHS($HSarray, $settings, %opts) + +=over Returns text chunk width (in points) for Shaper-defined glyph array. This is the horizontal width for LTR and RTL direction, and the vertical @@ -4512,7 +4963,7 @@ This is treated as 0 if an ax override setting is given. =item 'minKern' => amount (default 1) If the amount of kerning (font character width B glyph I -value) is I than this many character grid units, use the unaltered ax +value) is I than this many character grid units, use the unaltered I for the width (C will output a kern amount in the TJ operation). Otherwise, ignore kerning and use ax of the actual character width. The intent is to avoid bloating the PDF code with unnecessary tiny kerning adjustments in @@ -4526,6 +4977,8 @@ Returns total width in points. B C +=back + =cut sub text_widthHS { return advancewidthHS(@_); } ## no critic @@ -4607,19 +5060,26 @@ sub advancewidthHS { return $width; # height >0 for TTB and BTT } -=back - =head2 Advanced Methods -=over +=head3 save -=item $content->save() + $content->save() + +=over Saves the current I state on a PDF stack. See PDF definition 8.4.2 through 8.4.4 for details. This includes the line width, the line cap style, line join style, miter limit, line dash pattern, stroke color, fill color, current transformation matrix, current clipping port, flatness, and dictname. -This method applies to both I and I objects. + +This method applies to I I objects. If attempted with +I objects, you will receive a one-time (per run) warning message, and +should update your code B to do save() and restore() on a text object. +Only save() generates the message, as presumably each restore() has already had +a save() performed. + +=back =cut @@ -4645,20 +5105,33 @@ sub _save { sub save { my ($self) = shift; - #unless ($self->_in_text_object()) { + our @MSG_COUNT; + if ($self->_in_text_object()) { + # warning in text mode, no other effect + if (!$MSG_COUNT[2]) { + print STDERR "Can not call save() or restore() on a text object.\n"; + $MSG_COUNT[2]++; + } + } else { $self->add(_save()); - #} + } return $self; } -=item $content->restore() +=head3 restore + + $content->restore() + +=over Restores the most recently saved graphics state (see C), removing it from the stack. You cannot I the graphics state (pop it off the stack) unless you have done at least one I (pushed it on the stack). This method applies to both I and I objects. +=back + =cut sub _restore { @@ -4668,14 +5141,20 @@ sub _restore { sub restore { my ($self) = shift; - #unless ($self->_in_text_object()) { + if ($self->_in_text_object()) { + # save() already gave any warning + } else { $self->add(_restore()); - #} + } return $self; } -=item $content->add(@content) +=head3 add + + $content->add(@content) + +=over Add raw content (arbitrary string(s)) to the PDF stream. You will generally want to use the other methods in this class instead, @@ -4726,12 +5205,20 @@ PDF into a string and look for a certain pattern of "cm" output or similar, which is not within a save/restore (q/Q). If the stream is already compressed, this might not be possible. -=item $content->addNS(@content) +=back + +=head3 addNS + + $content->addNS(@content) + +=over Like C, but does B make sure there is a space between each element and before and after the new content. It is up to I to ensure that any necessary spaces in the PDF stream are placed there explicitly! +=back + =cut # add to 'poststream' string (dumped by ET) @@ -4779,7 +5266,11 @@ sub _in_text_object { return $self->{' apiistext'}; } -=item $content->compressFlate() +=head3 compressFlate + + $content->compressFlate() + +=over Marks content for compression on output. This is done automatically in nearly all cases, so you shouldn't need to call this yourself. @@ -4788,6 +5279,8 @@ The C call can set the B parameter to 'flate' (default) to compress all object streams, or 'none' to suppress compression and allow you to examine the output in an editor. +=back + =cut sub compressFlate { @@ -4799,7 +5292,11 @@ sub compressFlate { return $self; } -=item $content->textstart() +=head3 textstart + + $content->textstart() + +=over Starts a text object (ignored if already in a text object). You will likely want to use the C method (text I, not text output) instead. @@ -4808,6 +5305,8 @@ Note that calling this method, besides outputting a B marker, will reset most text settings to their default values. In addition, B itself will reset some transformation matrices. +=back + =cut sub textstart { @@ -4841,13 +5340,19 @@ sub textstart { return $self; } -=item $content->textend() +=head3 textend + + $content->textend() + +=over Ends a text object (ignored if not in a text object). Note that calling this method, besides outputting an B marker, will output any accumulated I content. +=back + =cut sub textend { @@ -4862,10 +5367,6 @@ sub textend { return $self; } -=back - -=cut - # helper function for many methods sub resource { my ($self, $type, $key, $obj, $force) = @_; diff --git a/lib/PDF/Builder/Content/Hyphenate_basic.pm b/lib/PDF/Builder/Content/Hyphenate_basic.pm index dbf6069..bebb679 100644 --- a/lib/PDF/Builder/Content/Hyphenate_basic.pm +++ b/lib/PDF/Builder/Content/Hyphenate_basic.pm @@ -5,7 +5,7 @@ use base 'PDF::Builder::Content::Text'; use strict; use warnings; -our $VERSION = '3.025'; # VERSION +our $VERSION = '3.026'; # VERSION our $LAST_UPDATE = '3.025'; # manually update whenever code is changed =head1 NAME diff --git a/lib/PDF/Builder/Content/Text.pm b/lib/PDF/Builder/Content/Text.pm index 20a4ef0..6b7565e 100644 --- a/lib/PDF/Builder/Content/Text.pm +++ b/lib/PDF/Builder/Content/Text.pm @@ -9,8 +9,8 @@ use List::Util qw(min max); #use Data::Dumper; # for debugging # $Data::Dumper::Sortkeys = 1; # hash keys in sorted order -our $VERSION = '3.025'; # VERSION -our $LAST_UPDATE = '3.025'; # manually update whenever code is changed +our $VERSION = '3.026'; # VERSION +our $LAST_UPDATE = '3.026'; # manually update whenever code is changed =head1 NAME @@ -34,9 +34,11 @@ sub new { =head2 Single Lines from a String -=over +=head3 text_left + + $width = $content->text_left($text, %opts) -=item $width = $content->text_left($text, %opts) +=over Alias for C. Implemented for symmetry, for those who use a lot of C and C, and desire a matching C. @@ -53,12 +55,15 @@ The width used (in points) is B. sub text_left { my ($self, $text, @opts) = @_; - return $self->text($text, @opts); + # override any stray 'align' that got through to here + return $self->text($text, @opts, 'align'=>'l'); } -=over +=head3 text_center -=item $width = $content->text_center($text, %opts) + $width = $content->text_center($text, %opts) + +=over As C, but I on the current point. @@ -72,13 +77,15 @@ The width used (in points) is B. sub text_center { my ($self, $text, @opts) = @_; - my $width = $self->advancewidth($text, @opts); - return $self->text($text, 'indent' => -($width/2), @opts); + # override any stray 'align' that got through to here + return $self->text($text, @opts, 'align'=>'c'); } -=over +=head3 text_right -=item $width = $content->text_right($text, %opts) + $width = $content->text_right($text, %opts) + +=over As C, but right-aligned to the current point. @@ -94,13 +101,15 @@ The width used (in points) is B. sub text_right { my ($self, $text, @opts) = @_; - my $width = $self->advancewidth($text, @opts); - return $self->text($text, 'indent' => -$width, @opts); + # override any stray 'align' that got through to here + return $self->text($text, @opts, 'align'=>'r'); } -=over +=head3 text_justified + + $width = $content->text_justified($text, $width, %opts) -=item $width = $content->text_justified($text, $width, %opts) +=over As C, but stretches text using C, C, and (as a last resort) C, to fill the desired @@ -302,7 +311,8 @@ sub text_justified { } # original $overage was not near 0 # do the output, with wordspace, charspace, and possiby hscale changed - $self->text($text, %opts); + # override any stray 'align' that got through to here + $self->text($text, %opts, 'align'=>'l'); # restore settings $self->hscale($hs); $self->wordspace($ws); $self->charspace($cs); @@ -316,7 +326,7 @@ The string is split at regular blanks (spaces), x20, to find the longest substring that will fit the C<$width>. If a single word is longer than C<$width>, it will overflow. To stay strictly within the desired bounds, set the option -C=>0 to disallow spillover. +C=E0 to disallow spillover. =head3 Hyphenation @@ -332,7 +342,7 @@ There are hard coded minimums of 2 letters before the split, and 2 letters after the split. See C. Note that neither hyphenation nor simple line splitting makes any attempt to prevent widows and orphans, prevent splitting of the last word in a column or page, or otherwise engage in -I. +more desirable I. =over @@ -566,16 +576,22 @@ sub _removeSHY { return $out; } -=over +=head4 text_fill_left, text_fill + + ($width, $leftover) = $content->text_fill_left($string, $width, %opts) -=item ($width, $leftover) = $content->text_fill_left($string, $width, %opts) +=over Fill a line of 'width' with as much text as will fit, and outputs it left justified. The width actually used, and the leftover text (that didn't fit), are B. -=item ($width, $leftover) = $content->text_fill($string, $width, %opts) +=back + + ($width, $leftover) = $content->text_fill($string, $width, %opts) + +=over Alias for text_fill_left(). @@ -590,7 +606,8 @@ sub text_fill_left { my $over = (not(defined($opts{'spillover'}) and $opts{'spillover'} == 0)); my ($line, $ret) = $self->_text_fill_line($text, $width, $over, %opts); - $width = $self->text($line, %opts); + # override any stray 'align' that got through to here + $width = $self->text($line, %opts, 'align'=>'l'); return ($width, $ret); } @@ -599,9 +616,11 @@ sub text_fill { return $self->text_fill_left(@_); } -=over +=head4 text_fill_center + + ($width, $leftover) = $content->text_fill_center($string, $width, %opts) -=item ($width, $leftover) = $content->text_fill_center($string, $width, %opts) +=over Fill a line of 'width' with as much text as will fit, and outputs it centered. @@ -623,9 +642,11 @@ sub text_fill_center { return ($width, $ret); } -=over +=head4 text_fill_right -=item ($width, $leftover) = $content->text_fill_right($string, $width, %opts) + ($width, $leftover) = $content->text_fill_right($string, $width, %opts) + +=over Fill a line of 'width' with as much text as will fit, and outputs it right justified. @@ -647,9 +668,11 @@ sub text_fill_right { return ($width, $ret); } -=over +=head4 text_fill_justified + + ($width, $leftover) = $content->text_fill_justified($string, $width, %opts) -=item ($width, $leftover) = $content->text_fill_justified($string, $width, %opts) +=over Fill a line of 'width' with as much text as will fit, and outputs it fully justified (stretched or condensed). @@ -696,12 +719,13 @@ sub text_fill_justified { # if last line, use $align (don't justify) if ($ret eq '') { my $lw = $self->advancewidth($line, %opts); + # override any stray 'align' that got through to here if ($align eq 'l') { - $width = $self->text($line, %opts); + $width = $self->text($line, %opts, 'align'=>'l'); } elsif ($align eq 'c') { - $width = $self->text($line, 'indent' => ($width-$lw)/2, %opts); + $width = $self->text($line, 'indent' => ($width-$lw)/2, %opts, 'align'=>'l'); } else { # 'r' - $width = $self->text($line, 'indent' => ($width-$lw), %opts); + $width = $self->text($line, 'indent' => ($width-$lw), %opts, 'align'=>'l'); } } else { $width = $self->text_justified($line, $width, %opts); @@ -711,11 +735,17 @@ sub text_fill_justified { =head2 Larger Text Segments -=over +=head3 paragraph + + ($overflow_text, $unused_height) = $txt->paragraph($text, $width,$height, $continue, %opts) -=item ($overflow_text, $unused_height) = $txt->paragraph($text, $width,$height, $continue, %opts) + ($overflow_text, $unused_height) = $txt->paragraph($text, $width,$height, %opts) -=item $overflow_text = $txt->paragraph($text, $width,$height, $continue, %opts) + $overflow_text = $txt->paragraph($text, $width,$height, $continue, %opts) + + $overflow_text = $txt->paragraph($text, $width,$height, %opts) + +=over Print a single string into a rectangular area on the page, of given width and maximum height. The baseline of the first (top) line is at the current text @@ -726,6 +756,10 @@ not fit all of it within the rectangle). If called in an array context, the unused height is also B (may be 0 or negative if it just filled the rectangle). +C<$continue> is optional, with a default value of 0. An C<%opts> list may be +given after the fixed parameters, whether or not C<$continue> is explicitly +given. + If C<$continue> is 1, the first line does B get special treatment for indenting or outdenting, because we're printing the continuation of the paragraph that was interrupted earlier. If it's 0, the first line may be @@ -792,7 +826,16 @@ fit to a given width, and nothing is done for "widows and orphans". # TBD for bidi/RTL languages, should indenting be on right? sub paragraph { - my ($self, $text, $width,$height, $continue, %opts) = @_; + my ($self, $text, $width,$height, @optsA) = @_; + # if odd number of elements in optsA, it contains $continue flag and + # remainder is %opts. if even, paragraph is being called PDF::API2 style + # with no $continue (default to 0). + my $continue = 0; + if (@optsA % 2) { + $continue = splice(@optsA, 0, 1); + } + my %opts = @optsA; + # copy dashed option names to preferred undashed names if (defined $opts{'-align'} && !defined $opts{'align'}) { $opts{'align'} = delete($opts{'-align'}); } if (defined $opts{'-pndnt'} && !defined $opts{'pndnt'}) { $opts{'pndnt'} = delete($opts{'-pndnt'}); } @@ -851,11 +894,13 @@ sub paragraph { return $text; } -=over +=head3 section, paragraphs -=item ($overflow_text, $continue, $unused_height) = $txt->section($text, $width,$height, $continue, %opts) + ($overflow_text, $continue, $unused_height) = $txt->section($text, $width,$height, $continue, %opts) -=item $overflow_text = $txt->section($text, $width,$height, $continue, %opts) + $overflow_text = $txt->section($text, $width,$height, $continue, %opts) + +=over The C<$text> contains a string with one or more paragraphs C<$width> wide, starting at the current text position, with a newline \n between each @@ -885,6 +930,10 @@ will also be added after the last paragraph printed. See C for other C<%opts> you can use, such as C and C. +B paragraphs + +This is for compatibiity with PDF::API2. + =back =cut @@ -938,9 +987,11 @@ sub section { return $overflow; } -=over +=head3 textlabel + + $width = $txt->textlabel($x,$y, $font, $size, $text, %opts) -=item $width = $txt->textlabel($x,$y, $font, $size, $text, %opts) +=over Place a line of text at an arbitrary C<[$x,$y]> on the page, with various text settings (treatments) specified in the call. @@ -1080,9 +1131,11 @@ sub textlabel { $wht = $self->text_center($text, %opts); } elsif (defined($opts{'left'}) && $opts{'left'} || defined($opts{'align'}) && $opts{'align'} =~ /^l/i) { - $wht = $self->text($text, %opts); # explicitly left aligned + # override any stray 'align' that got through to here + $wht = $self->text($text, %opts, 'align'=>'l'); # explicitly left aligned } else { - $wht = $self->text($text, %opts); # left aligned by default + # override any stray 'align' that got through to here + $wht = $self->text($text, %opts, 'align'=>'l'); # left aligned by default } $self->textend(); @@ -1097,9 +1150,11 @@ sub textlabel { =head2 Complex Column Output with Markup -=over +=head3 column -=item ($rc, $next_y, $unused) = $text->column($page, $text, $grfx, $markup, $txt, %opts) + ($rc, $next_y, $unused) = $text->column($page, $text, $grfx, $markup, $txt, %opts) + +=over This method fills out a column of text on a page, returning any unused portion that could not be fit, and where it left off on the page. @@ -1200,6 +1255,7 @@ and CSS. Currently, HTML tags 'u', 'ins' (underline) 'ovl' (TBD -- non-HTML, overline) 'k' (TBD -- non-HTML, kerning left/right shift) + 'blockquote' (block quote) are supported (fully or in part I "TBD"), along with limited CSS for color, font-size, font-family, etc. @@ -1226,6 +1282,7 @@ Sorry! Supported CSS properties: + border-* TBD color (foreground color) display (inline/block) font-family (name as defined to FontManager, e.g. Times) @@ -1236,9 +1293,11 @@ Supported CSS properties: list-style-position (outside) TBD inside list-style-type (marker description, see also _marker-before/after) margin-top/right/bottom/left (pt, bare number = pt, % of font-size) + margin TBD update four margin-* properties text-decoration (none, underline, line-through, overline) text-height (leading, as ratio of baseline-spacing to font-size) text-indent (pt, bare number = pt, % of current font-size) + text-align (left/right) TBD, future also center/justify? width (pt, bare number) width of horizontal rule Non-standard CSS "properties". You may want to set these in CSS: @@ -1632,7 +1691,7 @@ It contains nothing to be used. # TBD, future: # * = not official HTML5 or CSS (i.e., extension) -# perhaps 3.026? +# perhaps 3.027? # arbitrary paragraph shapes (path) # at a minimum, hyphenate-basic usage including &SHY; #
, , , ,
, , 
,
/
/
,
* @@ -1669,7 +1728,7 @@ It contains nothing to be used. # * material to keep together, such as headings and paragraph text # leading (line-height) as a dimension instead of a ratio, convert to ratio # -# 3.027 or later? +# 3.028 or later? # left/right auto margins?
may need this # Text::KnuthLiang hyphenation # *, * control hypenation in a word (and remember @@ -1861,17 +1920,19 @@ sub _default_css { $style{'body'}->{'_left'} = '0'; $style{'body'}->{'_right'} = '0'; $style{'body'}->{'text-indent'} = '0'; - #$style{'body'}->{'text-align'} = 'left'; # center, right + #$style{'body'}->{'text-align'} = 'left'; # TBD center, right #$style{'body'}->{'text-transform'} = 'none'; # capitalize, uppercase, lowercase - #$style{'body'}->{'border-style'} = 'none'; # solid, dotted, dashed... + #$style{'body'}->{'border-style'} = 'none'; # solid, dotted, dashed... TBD #$style{'body'}->{'border-width'} = '1pt'; #$style{'body'}->{'border-color'} = 'inherit'; + # TBD border-* individually specify for top/right/bottom/left $style{'body'}->{'text-decoration'} = 'none'; $style{'body'}->{'display'} = 'block'; $style{'body'}->{'width'} = '-1'; # TBD currently unused $style{'body'}->{'height'} = '-1'; # TBD currently unused ex. hr size $style{'body'}->{'_href'} = ''; + $style{'p'}->{'display'} = 'block'; $style{'font'}->{'display'} = 'inline'; $style{'span'}->{'display'} = 'inline'; @@ -1887,12 +1948,12 @@ sub _default_css { $style{'ul'}->{'display'} = 'block'; $style{'ul'}->{'margin-bottom'} = '50%'; $style{'ol'}->{'list-style-type'} = '.o'; # decimal, lower-roman, upper-roman, lower-alpha, upper-alpha, none - $style{'ol'}->{'list-style-position'} = 'outside'; # inside + $style{'ol'}->{'list-style-position'} = 'outside'; # inside TBD $style{'ol'}->{'display'} = 'block'; $style{'ol'}->{'margin-bottom'} = '50%'; $style{'ol'}->{'_marker-before'} = ''; # content to add before marker $style{'ol'}->{'_marker-after'} = '.'; # content to add after marker - #$style{'sl'}->{'list-style-type'} = 'none'; + #$style{'sl'}->{'list-style-type'} = 'none'; TBD $style{'li'}->{'display'} = 'block'; # should inherit from ul or ol $style{'li'}->{'margin-top'} = '50%'; # relative to text's font-size @@ -1954,17 +2015,17 @@ sub _default_css { $style{'del'}->{'display'} = 'inline'; $style{'del'}->{'text-decoration'} = 'line-through'; - # non-standard tag for overline + # non-standard tag for overline TBD #$style{'ovl'}->{'display'} = 'inline'; #$style{'ovl'}->{'text-decoration'} = 'overline'; # non-standard tag for kerning (+ font-size fraction to move left, - right) - # e.g., for vulgar fraction adjust / and denominator + # e.g., for vulgar fraction adjust / and denominator TBD #$style{'k'}->{'display'} = 'inline'; #$style{'k'}->{'_kern'} = '0.2'; $style{'hr'}->{'display'} = 'block'; - $style{'hr'}->{'height'} = '1'; # 1pt default thickness + $style{'hr'}->{'height'} = '0.5'; # 1/2 pt default thickness $style{'hr'}->{'width'} = '-1'; # default width is full column $style{'hr'}->{'margin-top'} = '100%'; $style{'hr'}->{'margin-bottom'} = '100%'; @@ -1977,9 +2038,9 @@ sub _default_css { $style{'blockquote'}->{'text-height'} = '1.00'; # close spacing $style{'blockquote'}->{'font-size'} = '80%'; # smaller type - #$style{'sc'}->{'font-size'} = '80%'; # smaller type + #$style{'sc'}->{'font-size'} = '80%'; # smaller type TBD #$style{'sc'}->{'_expand'} = '110%'; # wider type TBD _expand - #likewise for pc (petite caps) + #likewise for pc (petite caps) TBD return \%style; } # end of _default_css() @@ -2097,6 +2158,7 @@ sub _output_text { my $start = 1; # counter for ordered lists my $list_depth = 0; # nesting level of ol and ul my $list_marker = ''; # li marker text + my $reversed_ol = 0; # count down from start my $phrase=''; my $remainder=''; @@ -2227,11 +2289,20 @@ sub _output_text { $list_depth++; } if ($tag eq 'ol') { + # save any existing start and reversed_ol values + $properties[-2]->{'_start'} = $start; # current start + $properties[-2]->{'_reversed_ol'} = $reversed_ol; # cur flag + $start = 1; if (defined $mytext[$el]->{'start'}) { $start = $mytext[$el]->{'start'}; } - $list_depth++; + if (defined $mytext[$el]->{'reversed'}) { + $reversed_ol = 1; + } else { + $reversed_ol = 0; + } + $list_depth++; } if ($tag eq 'li') { # paragraph, but label depends on parent (list-style-type) @@ -2249,7 +2320,11 @@ sub _output_text { # it's a bullet character } else { # fully formatted ordered list item - $start++; + if ($reversed_ol) { + $start--; + } else { + $start++; + } } # sl: use normal marker width, marker is blank. position # is always outside (ignore inside if given) @@ -2378,6 +2453,11 @@ sub _output_text { if ($tag eq 'ol' || $tag eq 'ul') { $list_depth--; } # note that current_prop should be all up to date by the # time you hit the end tag + if ($tag eq 'ol') { + # restore any saved start and reversed_ol values + $start = $properties[-2]->{'_start'}; # current start + $reversed_ol = $properties[-2]->{'_reversed_ol'}; # cur flag + } # ready to pick larger of top and bottom margins (block display) $botm = $current_prop->{'margin-bottom'}; @@ -2462,6 +2542,9 @@ sub _output_text { # any size as a percentage of font-size will use the current fs my $fs = $current_prop->{'font-size'}; + # uncommon to only change font size without also changing something + # else, so make font selection call at the same time, besides, + # there is very little involved in just returning current font. if ($call_get_font) { $text->font($pdf->get_font( 'face' => $current_prop->{'font-family'}, @@ -2536,7 +2619,7 @@ sub _output_text { $remainder = ''; # for now, all whitespace convert to single blanks - # TBD blank preserve for or
+	    # TBD blank preserve for  or 
 (CSS white-space)
 	    $phrase =~ s/\s+/ /g;
 
 	    # a phrase may have multiple words. see if entire thing fits, and if
@@ -2775,7 +2858,7 @@ sub _output_text {
 				$pageno = $1;
 				$xpos = $2;
 				$ypos = $3; 
-				$zoom = 1;
+				$zoom = undef;
 			    } elsif ($href =~ m/^#(\d+)-(\d+)-(\d+)-(.+)$/) {
 				# #p-x-y-z format (zoom, at a specific spot)
 				$pageno = $1; # integer > 0
@@ -3021,10 +3104,10 @@ sub _output_text {
 	    # do nothing, leave the font state/colors as-is
 	} else { # 2
 	    # restore to entry with @entry_state
-	    return (2, $next_y, []);
+	    return (2, $next_y-$botm, []);
 	}
 
-	return (0, $next_y, []);
+	return (0, $next_y-$botm, []);
     } else {
 	# we ran out of vertical space in the column. return -1 and 
 	# remainder of mytext list (next_y would be inapplicable)
@@ -3751,6 +3834,25 @@ sub _size2pt {
 # for ordered, returns $prefix.formatted_value.$suffix.blank
 # for unordered, returns string .disc, .circle, .square, or .box
 #   (.box is nonstandard marker)
+#
+# TBD check that 'none' works properly (as ?)
+# TBD for ol, there are many other formats: cjk-decimal, decimal-leading-zero,
+#      lower-greek, upper-greek?, lower-latin = lower-alpha, upper-latin =
+#      upper-alpha, arabic-indic, -moz-arabic-indic, armenian, [-moz-]bengali, 
+#      cambodian (khmer), [-moz-]cjk-earthly-branch, [-moz-]cjk-heavenly-stem, 
+#      cjk-ideographic, [-moz-]devanagari, ethiopi-numeric, georgian,
+#      [-moz-]gujarati, [-moz-]gurmukhi, hebrew, hiragana, hiragana-iroha, 
+#      japanese-formal, japanese-informal, [-moz-]kannada, katakana, 
+#      katakana-iroha, korean-hangul-formal, korean-hanja-formal, 
+#      korean-hanja-informal, [-moz-]lao, lower-armenian, upper-armenian, 
+#      [-moz-]malayalam, mongolian, [-moz-]myanmar, [-moz-]oriya, 
+#      [-moz-]persian, simp-chinese-formal, simp-chinese-informal, [-moz-]tamil,
+#      [-moz-]telugu, [-moz-]thai, tibetan, trad-chinese-formal, 
+#      trad-chinese-informal, disclosure-open, disclosure-closed
+# TBD for ol, some browser-specific formats: -moz-ethiopic-halehame,
+#      -moz-ethiopic-halehame-am, [-moz-]ethiopic-halehame-ti-et, [-moz-]hangul,
+#      [-moz-]hangul-consonant, [-moz-]urdu
+# TBD for ul, ability to select images and possibly other characters
 sub _marker {
     my ($type, $depth, $value, $prefix, $suffix) = @_; 
                                      # type = list-style-type, 
@@ -4007,7 +4109,7 @@ sub _revise_baseline {
 } # end of _revise_baseline()
 
 # just something to pause during debugging
-sub  _pause {
+sub _pause {
     print STDERR "====> Press Enter key to continue...";
     my $input = <>;
     return;
diff --git a/lib/PDF/Builder/Docs.pm b/lib/PDF/Builder/Docs.pm
index a0983f5..b2eac66 100644
--- a/lib/PDF/Builder/Docs.pm
+++ b/lib/PDF/Builder/Docs.pm
@@ -3,8 +3,8 @@ package PDF::Builder::Docs;
 use strict;
 use warnings;
 
-our $VERSION = '3.025'; # VERSION
-our $LAST_UPDATE = '3.025'; # manually update whenever code is changed
+our $VERSION = '3.026'; # VERSION
+our $LAST_UPDATE = '3.026'; # manually update whenever code is changed
 
 # originally part of Builder.pm, it was split out due to its length
 
@@ -60,7 +60,13 @@ PDF::Builder can make use of some optional libraries, which are not I
 for a successful installation. If you want improved speed and capabilities for
 certain functions, you may want to install and use these libraries:
 
-B<*> Graphics::TIFF -- PDF::Builder inherited a rather slow, buggy, and limited 
+=over
+
+=item * 
+
+Graphics::TIFF
+
+PDF::Builder inherited a rather slow, buggy, and limited 
 TIFF image library from PDF::API2. If Graphics::TIFF (available on CPAN, uses 
 libtiff.a) is installed, PDF::Builder will use that instead, unless you specify 
 that it is to use the old, pure Perl library. The only time you might want to 
@@ -68,7 +74,11 @@ consider this is when you need to pass an open filehandle to C
 instead of a file name. See resolved bug reports RT 84665 and RT 118047, as well
 as C, for more information.
 
-B<*> Image::PNG::Libpng -- PDF::Builder inherited a rather slow and buggy pure 
+=item * 
+
+Image::PNG::Libpng
+
+PDF::Builder inherited a rather slow and buggy pure 
 Perl PNG image library from PDF::API2. If Image::PNG::Libpng (available on 
 CPAN, uses libpng.a) is installed, PDF::Builder will use that instead, unless 
 you specify that it is to use the old, pure Perl library. Using the new library 
@@ -76,22 +86,47 @@ will give you improved speed, the ability to use 16 bit samples, and the
 ability to read interlaced PNG files. See resolved bug report RT 124349, as well
 as C, for more information.
 
-B<*> HarfBuzz::Shaper -- This library enables PDF::Builder to handle complex
+=item * 
+
+HarfBuzz::Shaper
+
+This library enables PDF::Builder to handle complex
 scripts (Arabic, Devanagari, etc.) as well as non-LTR writing systems. It is
 also useful for Latin and other simple scripts, for ligatures and improved
 kerning. HarfBuzz::Shaper is based on a set of HarfBuzz libraries, which it
 will attempt to build if they are not found. See C for more 
 information.
 
-B<*> Text::Markdown -- This library is used if you want to format "Markdown"
+=item * 
+
+Text::Markdown
+
+This library is used if you want to format "Markdown"
 style code in PDF::Builder, via the C method. It translates a certain
 dialect of Markdown into HTML, which is then further processed.
 
-B<*> HTML::TreeBuilder -- This library is used to format HTML input into a 
+=item * 
+
+HTML::TreeBuilder
+
+This library is used to format HTML input into a 
 data structure which PDF::Builder can interpret, via the C method.
 Note that if Markdown input is used, it will also need HTML::TreeBuilder to
 handle the HTML the Markdown is translated to.
 
+=item * 
+
+Pod::Simple::XHTML
+
+This library is used if you wish to generate the HTML documentation from the
+POD and PM source, using C. Note that the full set of
+documentation can also be found online at 
+https://www.catskilltech.com/FreeSW/product/PDF-Builder/title/PDF%3A%3ABuilder/freeSW_full 
+under the "Documentation" link. This online documentation is updated at 
+every CPAN release, but not necessarily when the GitHub repository is updated.
+
+=back
+
 Note that the installation process will B attempt to install these 
 libraries automatically. If you don't wish to use one or more of them, you are
 free to not install the optional librarie(s). If you may want to make use of
@@ -493,6 +528,43 @@ temporarily exiting (ET) to graphics mode to draw the lines, and then returning
 be easily made. Since "BT" resets some text settings, this needs to be done
 with care!
 
+=head2 Notes on Reader support of features
+
+PDF Readers are complex pieces of software, written by different groups at
+different times. Thus, they may differ in how they support features and handle
+non-standard (i.e., not quite meeting standards) content! Most Readers out 
+there support all or most features up through PDF 1.7, and some support PDF 2.x
+features. Note that PDF::Builder supports PDF 1.4 for the most part, with a few
+PDF 1.5 features added. Most any Reader out there I (in theory) support 
+any PDF produced with PDF::Builder.
+
+There is no official I of a Reader, although Adobe's
+Acrobat Reader (I, a free download) is so prevalent that it is almost a 
+I standard. At least, we I to get PDF::Builder and its tests and 
+examples to run on AAR. Sometimes it can be difficult, as, for example, the 
+handling of save (B) and restore (B) operators (commands) within a text 
+stream. The PDF standard sort of suggests that these apply only to the Graphics 
+Stream, and possibly shouldn't appear in a Text Stream. Most Readers appear to 
+just ignore q and Q within a text stream, and AAR usually seems to, but certain 
+combinations of stream size and compression seem to trigger a warning in AAR 
+upon load! This particular case is now a moot point, as C and 
+C have been reverted to being no-ops (with a single warning message 
+given if found) in a Text Stream.
+
+We have been advised that certain stream operators may not be strictly allowed
+within certain parts of a stream (particularly certain graphics state operators
+after path construction has started). No Reader seems to give problems with 
+this at the moment, but users should be aware that the ordering of their 
+PDF::Builder calls I need to be updated at some point, to get PDFs usable 
+on all Readers. If necessary, we will add code to enforce this (or at least, 
+warn of potential problems). Please feel free to report if you find such
+restrictions are necessary.
+
+Also note that not all I (including compression methods) may be
+supported on all Readers. For example, at this time, AAR (and a number of other
+Readers) apparently do not support CCITT Group 4 Fax compression (for some TIFF
+images). This remains under investigation.
+
 =head2 PDF Versions Supported
 
 When creating a PDF file using the functions in PDF::Builder, the output is
@@ -531,19 +603,28 @@ In 2017, PDF::Builder was forked by Phil M. Perry, who desired a more aggressive
 schedule of new features and bug fixes than Simms was providing, although some 
 of Simms's work I been ported from PDF::API2.
 
-According to "pdfapi2_for_fun_and_profit_APW2005.pdf" (on 
+According to Alfred Reibenschuh's 2005 presentation 
+"pdfapi2_for_fun_and_profit_APW2005.pdf" (on 
 http://pdfapi2.sourceforge.net, an unmaintained site), the history of PDF::API2
 (the predecessor to PDF::Builder) goes as such:
 
 =over
 
-=item E E EE First Code implemented based on PDFlib-0.6 (AFPL)
+=item * 
+
+First Code implemented based on PDFlib-0.6 (AFPL)
+
+=item * 
+
+Changed to Text::PDF with a total rewrite as Text::PDF::API (procedural)
+
+=item * 
 
-=item E E EE Changed to Text::PDF with a total rewrite as Text::PDF::API (procedural)
+Unmaintainable Code triggered rewrite into new Namespace PDF::API2 (object-oriented, LGPL)
 
-=item E E EE Unmaintainable Code triggered rewrite into new Namespace PDF::API2 (object-oriented, LGPL)
+=item * 
 
-=item E E EE Object-Structure streamlined in 0.4x
+Object-Structure streamlined in 0.4x
 
 =back
 
@@ -595,21 +676,33 @@ The C parameter accepts the following values:
 
 =over
 
-=item 0 = Do not output any diagnostic messages; just return any version override.
+=item Z<>0 
 
-=item 1 = Output error-level (serious) diagnostic messages, as well as returning any version override.
+Do not output any diagnostic messages; just return any version override.
+
+=item Z<>1 
+
+Output error-level (serious) diagnostic messages, as well as returning any version override.
 
 Errors include, in no place was the /Root object specified, or if it was, the indicated object was not found. An object claims another object as its child (/Kids list), but another object has already claimed that child. An object claims a child, but that child does not list a Parent, or the child lists a different Parent.
 
-=item 2 = Output error- (serious) and warning- (less serious) level diagnostic messages, as well as returning any version override. B
+=item Z<>2
+
+Output error- (serious) and warning- (less serious) level diagnostic messages, as well as returning any version override. B
 
-=item 3 = Output error- (serious), warning- (less serious), and note- (informational) level diagnostic messages, as well as returning any version override.
+=item Z<>3
+
+Output error- (serious), warning- (less serious), and note- (informational) level diagnostic messages, as well as returning any version override.
 
 Notes include, in no place was the (optional) /Info object specified, or if it was, the indicated object was not found. An object was referenced, but no entry for it was found among the objects. (This may be OK if the object is not defined, or is on the free list, as the reference will then be ignored.) An object is defined, but it appears that no other object is referencing it.
 
-=item 4 = Output error-, warning-, and note-level diagnostic messages, as well as returning any version override. Also dump the diagnostic data structure.
+=item Z<>4
+
+Output error-, warning-, and note-level diagnostic messages, as well as returning any version override. Also dump the diagnostic data structure.
+
+=item Z<>5
 
-=item 5 = Output error-, warning-, and note-level diagnostic messages, as well as returning any version override. Also dump the diagnostic data structure and the C<$self> data structure (generally useful only if you have already read in the PDF file).
+Output error-, warning-, and note-level diagnostic messages, as well as returning any version override. Also dump the diagnostic data structure and the C<$self> data structure (generally useful only if you have already read in the PDF file).
 
 =back
 
@@ -632,8 +725,6 @@ Controls viewing preferences for the PDF.
 
 =over
 
-=over
-
 =item fullscreen
 
 Full-screen mode, with no menu bar, window controls, or any other window visible.
@@ -648,14 +739,10 @@ Document outline visible.
 
 =back
 
-=back
-
 =head3 Page Layout Options
 
 =over
 
-=over
-
 =item singlepage
 
 Display one page at a time.
@@ -666,13 +753,11 @@ Display the pages in one column.
 
 =item twocolumnleft
 
-Display the pages in two columns, with oddnumbered pages on the left.
+Display the pages in two columns, with odd-numbered pages on the left.
 
 =item twocolumnright
 
-Display the pages in two columns, with oddnumbered pages on the right.
-
-=back
+Display the pages in two columns, with odd-numbered pages on the right.
 
 =back
 
@@ -680,8 +765,6 @@ Display the pages in two columns, with oddnumbered pages on the right.
 
 =over
 
-=over
-
 =item hidetoolbar
 
 Specifying whether to hide tool bars.
@@ -734,8 +817,6 @@ Print duplex by default and flip on the long edge of the sheet.
 
 =back
 
-=back
-
 =head3 Page Fit Options
 
 These options are used for the C layout, as well as for 
@@ -916,11 +997,11 @@ consider what readers and other PDF tools may be used with a PDF you produce!
 Also note that earlier Acrobat readers had coordinate limits as small as 3240
 User Units (45 inches), and I media size of 72 or 3 User Units.
 
-=head3 User Units
+=head3 User Units (userunit)
 
-=over
+    $pdf->userunit($number)
 
-=item $pdf->userunit($number)
+=over
 
 The default User Unit in the PDF coordinate system is one point (1/72 inch). You
 can think of it as a scale factor to enable larger (or even, smaller) documents.
@@ -968,19 +1049,19 @@ may be scaled down to the current User Unit.
 
 =back
 
-=head3 Media Box
+=head3 Media Box (mediabox)
 
-=over
+    $pdf->mediabox($name)
 
-=item $pdf->mediabox($name)
+    $pdf->mediabox($name, orient => 'orientation' )
 
-=item $pdf->mediabox($name, orient => 'orientation' )
+    $pdf->mediabox($w,$h)
 
-=item $pdf->mediabox($w,$h)
+    $pdf->mediabox($llx,$lly, $urx,$ury)
 
-=item $pdf->mediabox($llx,$lly, $urx,$ury)
+    ($llx,$lly, $urx,$ury) = $pdf->mediabox()
 
-=item ($llx,$lly, $urx,$ury) = $pdf->mediabox()
+=over
 
 Sets the global Media Box (or page's Media Box, if C<< $page-> >> instead). 
 This defines the width and height (or by corner
@@ -994,8 +1075,8 @@ addition, the Media Box defines the overall I for text and
 graphics operations.
 
 If no arguments are given, the current Media Box (global or page) coordinates
-are returned instead. The former C (page only) function is 
-B and will likely be removed some time in the future. In addition,
+are returned instead. The former C (page only) function was 
+B and has been removed. In addition,
 when I the Media Box, the resulting coordinates are returned. This 
 permits you to specify the page size by a name (alias) and get the dimensions 
 back, all in one call.
@@ -1035,6 +1116,8 @@ can't make C I from top to bottom!).
 
 B
 
+=back
+
     $pdf = PDF::Builder->new();
     $pdf->mediabox('A4'); # A4 size (595 Pt wide by 842 Pt high)
     ...
@@ -1050,6 +1133,8 @@ B
     ...
     $pdf->saveas('our/new.pdf');
 
+=over
+
 See the L source code for the full list of
 supported names (aliases) and their dimensions in points. You are free to add
 additional paper sizes to this file, if you wish. You might want to do this if
@@ -1060,19 +1145,19 @@ size as the full media (Media Box), and you don't mind their starting at 0,0.
 
 =back
 
-=head3 Crop Box
+=head3 Crop Box (cropbox)
 
-=over
+    $pdf->cropbox($name)
 
-=item $pdf->cropbox($name)
+    $pdf->cropbox($name, orient => 'orientation')
 
-=item $pdf->cropbox($name, orient => 'orientation')
+    $pdf->cropbox($w,$h)
 
-=item $pdf->cropbox($w,$h)
+    $pdf->cropbox($llx,$lly, $urx,$ury)
 
-=item $pdf->cropbox($llx,$lly, $urx,$ury)
+    ($llx,$lly, $urx,$ury) = $pdf->cropbox()
 
-=item ($llx,$lly, $urx,$ury) = $pdf->cropbox()
+=over
 
 Sets the global Crop Box (or page's Crop Box, if C<< $page-> >> instead). 
 This will define the media size to which the output will 
@@ -1092,8 +1177,8 @@ may show you the full media size (Media Box) and a 100 Point wide blank area
 (in this example) around the visible content.
 
 If no arguments are given, the current Crop Box (global or page) coordinates
-are returned instead. The former C (page only) function is 
-B and will likely be removed some time in the future. If a Crop Box
+are returned instead. The former C (page only) function was 
+B and has been removed. If a Crop Box
 has not been defined, the Media Box coordinates (which always exist) will be
 returned instead. In addition,
 when I the Crop Box, the resulting coordinates are returned. This 
@@ -1127,19 +1212,19 @@ Crop Box (and other boxes).
 
 =back
 
-=head3 Bleed Box
+=head3 Bleed Box (bleedbox)
 
-=over
+    $pdf->bleedbox($name)
 
-=item $pdf->bleedbox($name)
+    $pdf->bleedbox($name, orient => 'orientation')
 
-=item $pdf->bleedbox($name, orient => 'orientation')
+    $pdf->bleedbox($w,$h)
 
-=item $pdf->bleedbox($w,$h)
+    $pdf->bleedbox($llx,$lly, $urx,$ury)
 
-=item $pdf->bleedbox($llx,$lly, $urx,$ury)
+    ($llx,$lly, $urx,$ury) = $pdf->bleedbox()
 
-=item ($llx,$lly, $urx,$ury) = $pdf->bleedbox()
+=over
 
 Sets the global Bleed Box (or page's Bleed Box, if C<< $page-> >> instead). 
 This is typically used in printing on paper, where you want 
@@ -1156,8 +1241,8 @@ alignment dots, etc., while crop marks (trim guides) are at least partly within
 the bleed area (and should be printed after content is printed).
 
 If no arguments are given, the current Bleed Box (global or page) coordinates
-are returned instead. The former C (page only) function is 
-B and will likely be removed some time in the future. If a Bleed Box
+are returned instead. The former C (page only) function was 
+B and has been removed. If a Bleed Box
 has not been defined, the Crop Box coordinates (if defined) will be returned,
 otherwise the Media Box coordinates (which always exist) will be returned. 
 In addition, when I the Bleed Box, the resulting coordinates are 
@@ -1177,19 +1262,19 @@ the page Bleed Box (and other boxes).
 
 =back
 
-=head3 Trim Box
+=head3 Trim Box (trimbox)
 
-=over
+    $pdf->trimbox($name)
 
-=item $pdf->trimbox($name)
+    $pdf->trimbox($name, orient => 'orientation')
 
-=item $pdf->trimbox($name, orient => 'orientation')
+    $pdf->trimbox($w,$h)
 
-=item $pdf->trimbox($w,$h)
+    $pdf->trimbox($llx,$lly, $urx,$ury)
 
-=item $pdf->trimbox($llx,$lly, $urx,$ury)
+    ($llx,$lly, $urx,$ury) = $pdf->trimbox()
 
-=item ($llx,$lly, $urx,$ury) = $pdf->trimbox()
+=over
 
 Sets the global Trim Box (or page's Trim Box, if C<< $page-> >> instead). 
 This is supposed to be the actual dimensions of the 
@@ -1199,8 +1284,8 @@ the trim box. The default value is equal to Crop Box, but is often a bit
 smaller than any Bleed Box, to allow the desired "bleed" effect.
 
 If no arguments are given, the current Trim Box (global or page) coordinates
-are returned instead. The former C (page only) function is 
-B and will likely be removed some time in the future. If a Trim Box
+are returned instead. The former C (page only) function was 
+B and has been removed. If a Trim Box
 has not been defined, the Crop Box coordinates (if defined) will be returned,
 otherwise the Media Box coordinates (which always exist) will be returned. 
 In addition, when I the Trim Box, the resulting coordinates are 
@@ -1220,19 +1305,19 @@ the page Trim Box (and other boxes).
 
 =back
 
-=head3 Art Box
+=head3 Art Box (artbox)
 
-=over
+    $pdf->artbox($name)
 
-=item $pdf->artbox($name)
+    $pdf->artbox($name, orient => 'orientation')
 
-=item $pdf->artbox($name, orient => 'orientation')
+    $pdf->artbox($w,$h)
 
-=item $pdf->artbox($w,$h)
+    $pdf->artbox($llx,$lly, $urx,$ury)
 
-=item $pdf->artbox($llx,$lly, $urx,$ury)
+    ($llx,$lly, $urx,$ury) = $pdf->artbox()
 
-=item ($llx,$lly, $urx,$ury) = $pdf->artbox()
+=over
 
 Sets the global Art Box (or page's Art Box, if C<< $page-> >> instead). 
 This is supposed to define "the extent of the page's 
@@ -1245,8 +1330,8 @@ used for defining "important" content (e.g., I advertisements) that
 may or may not be brought over to another page (e.g., N-up printing).
 
 If no arguments are given, the current Art Box (global or page) coordinates
-are returned instead. The former C (page only) function is 
-B and will likely be removed some time in the future. If an Art Box
+are returned instead. The former C (page only) function was 
+B and has been removed. If an Art Box
 has not been defined, the Crop Box coordinates (if defined) will be returned,
 otherwise the Media Box coordinates (which always exist) will be returned. 
 In addition, when I the Art Box, the resulting coordinates are 
@@ -1283,7 +1368,7 @@ bound together into books or magazines. You would usually just supply a PDF
 with all the pages; they would take care of the signature layout (which 
 includes offsets and 180 degree rotations). 
 
-(As an aside, don't count on a printer having
+(As an aside, don't count on a commercial printer having
 any particular font available, so be sure to ask. Usually they will want you
 to embed all fonts used, but ask first, and double-check before handing over
 the print job! TTF/OTF fonts (C) are embedded by default, but other 
@@ -1311,8 +1396,9 @@ Crop Box, but crop marks for trimming (if used) should go just outside the Trim
 Box (partly or wholly within the Bleed Box), and
 be drawn I all content. If you're I trimming the paper, don't try 
 to do any bleed effects (including solid background color pages/covers), as 
-you will usually have a white edge around the 
-sheet anyway. Don't count on a PDF document I being physically printed,
+you will usually have a white edge around the sheet anyway (printers leave a 
+clean, dry route for the feed rollers). Don't count on a PDF document I 
+being physically printed,
 and not just displayed (where you can do things like bleed all the way to the
 media edge). Finally, for single sheet printing, an Art Box is 
 probably unnecessary, but if you're combining pages into N-up prints, or doing 
@@ -1432,6 +1518,23 @@ See also L.
 
 =head3 PS Fonts
 
+=head4 WARNING: End of Adobe Support
+
+B
+
 PS (T1) fonts are limited to single byte encodings. You cannot use UTF-8 or 
 other multibyte encodings with T1 fonts.
 The default encoding for the T1 fonts is
@@ -1443,12 +1546,16 @@ guarantee that future changes to font files will permit consistent results>.
 B many Type1 fonts are limited to 256 glyphs, but some are available
 with more than 256 glyphs. Still, a maximum of 256 at a time are usable.
 
-C accepts both ASCII (.pfa) and binary (.pfb) Type1 glyph files.
+C accepts ASCII (.pfa), binary (.pfb), and .t1 Type1 glyph files.
 Font metrics can be supplied in either ASCII (.afm) or binary (.pfm) format,
 as can be seen in the examples given below. It is possible to use .pfa with .pfm
 and .pfb with .afm if that's what's available. The ASCII and binary files have
 the same content, just in different formats.
 
+B the file name given for the glyph file (first argument to C)
+I have a file extension of .pfa, .pfb, or .t1; as the extension will
+be checked to see how to parse the file.
+
 To allow UTF-8 text and extended glyph counts in one font, you should 
 consider replacing your use of Type1 fonts with TrueType (.ttf) and OpenType
 (.otf) fonts. There are tools, such as I, which can do a fairly good
@@ -1604,6 +1711,63 @@ the default list for the appropriate OS. If none can be found, find_ms() is
 tried, and as last resort use the C<.cmap> (if available), even if C 
 is not 1.
 
+B There is a "gotcha" with TrueType fonts that you need to be aware
+of when using them. PDF::Builder outputs to the text stream a list of I as four-digit hex codes, rather than the list of character byte codes 
+used by other
+font types. The B operator, if used (C<$text->wordspace(n)>) to adjust
+inter-word spacing, B by most, if not all, PDF Readers
+(including Adobe products). This is because this operator is looking for actual
+ASCII spaces (x20 bytes) in the stream, to apply the width change to. Note that 
+only ASCII spaces are affected (not other spaces), and not at all for TrueType 
+and OpenType fonts! We are considering adding ways to emulate word spacing for 
+TrueType font support, as well as possibly extending it to non-ASCII spaces for 
+all font types. Note that inter-character spacing (via C<$text->charspace(n)> 
+and the B operator) still works for all font types.
+
+PDF::Builder has been updated to attempt to respect the B operator when
+using TTF/OTF fonts. If the C amount is non-zero, it will split up 
+sentences on ASCII spaces (x20) and individually place words on the page. This 
+necessarily bloats the PDF file size, but is the only way to adjust word 
+spacing via the C method. Note that again, I ASCII spaces
+(x20) are affected (to match the behavior of the B operator for other font
+types), and other spaces (xA0 required/non-breaking space, thin space, etc.)
+are not handled.
+
+B Well, sometimes you get lucky and can
+specify the exact directory that the C<.ttf> or C<.otf> file will reside in,
+making it easy to specify the path to the font file (for uses such as 
+C, C, or Font Manager calls). Other times, the operating
+system will play hide and seek with you, leaving you to expend much time and
+energy to track down where the file is. Linux distributions tend to have their
+own favorite hiding places for font files, but at least they tend to be
+consistent! On the other hand, Windows often decides that it knows better than
+you, and will put files in an unexpected place, and under an unexpected name!
+
+To find out where your TTF or OTF file ended up, if you don't see an obvious 
+entry in /Windows/Fonts (even if you drag and dropped the font file there), 
+you need to look in /Users/XXXX/AppData/Local/Microsoft/Windows/Fonts, 
+depending on what user name you were signed on as when you installed the font. 
+Even then, you may not be done, as the name may have been changed to something 
+unrecognizable. You may need to look at Windows' mapping of font name to 
+filename.
+
+In the command shell (command line), or whatever equivalent you like to use, 
+enter "regedit" to bring up the registry editor. For the top level, choose 
+(click on) either C (for global font settings, in 
+/Windows/Fonts) or C (for fonts installed by whoever is 
+currently signed on, in /Users/XXXX/AppData...). From there, both have the same 
+path: C Microsoft E Windows NT E CurrentVersion E 
+Fonts>. This should bring up a listing of all the installed fonts (full name, 
+e.g. "Papyrus Regular") and their actual filename ("PAPYRUS.TTF"). For 
+instance, I just installed (drag and drop into /Windows/Fonts) a blackletter 
+"Gothic" font named I. It ended up in my /Users/XXXX... 
+directory as C.
+
+You don't need to change anything in the registry, just look. You I have 
+the capability to change things, including hiding/showing the font, if you 
+care to get into those things.
+
 =back
 
 =head3 CJK Fonts
@@ -1729,11 +1893,24 @@ in landscape mode)
 I have found some code that should allow the C or C routine
 to auto-rotate to (supposedly) the correct orientation, by looking for the Exif
 metadata "Orientation" tag in the file. However, three problems arise: 
-B<1)> if a photo has been edited, and rotated or flipped in the process, there is no guarantee that the Orientation tag has been corrected. 
-B<2)> more than one Orientation tag may exist (e.g., in the binary APP1/Exif header, I in XML data), and they may not agree with each other -- which should be used? 
-B<3)> the code would need to uncompress the raster data, swap and/or transpose rows and/or columns, and recompress the raster data for inclusion into the PDF. This is costly and error-prone.
+
+=over
+
+=item 1.
+
+If a photo has been edited, and rotated or flipped in the process, there is no guarantee that the Orientation tag has been corrected. 
+
+=item 2.
+
+More than one Orientation tag may exist (e.g., in the binary APP1/Exif header, I in XML data), and they may not agree with each other -- which should be used? 
+
+=item 3.
+
+The code would need to uncompress the raster data, swap and/or transpose rows and/or columns, and recompress the raster data for inclusion into the PDF. This is costly and error-prone.
 In any case, the user would need to be able to override any auto-rotate function.
 
+=back
+
 For the time being, PDF::Builder will simply leave it up to the user of the
 library to take care of rotating and/or flipping an image which displays 
 incorrectly. It is possible that we will consider adding some sort of query or warning that the image appears to I be "normally" oriented (Orientation value 1 or "Top-left"), according to the Orientation flag. You can consider either (re-)saving the photo in an editor such as PhotoShop or GIMP, or using PDF::Builder code similar to the following (for images rotated 180 degrees):
@@ -1792,6 +1969,9 @@ it is available, unless explicitly told not to. Your code can test whether
 Graphics::TIFF is available by examining C<< $tiff->usesLib() >> or
 C<< $pdf->LA_GT() >>.
 
+Note that the first query is only available once the C<$tiff> object has been
+created. This may or may not be too late for your purposes.
+
 =over
 
 =item = -1 
@@ -1836,6 +2016,9 @@ if it is available, unless explicitly told not to. Your code can test whether
 Image::PNG::Libpng is available by examining C<< $png->usesLib() >> or
 C<< $pdf->LA_IPL() >>.
 
+Note that the first query is only available once the C<$png> object has been
+created. This may or may not be too late for your purposes.
+
 =over
 
 =item = -1 
@@ -1970,13 +2153,21 @@ means of one of the following:
 
 =over
 
-=item B is a value to be I for 'ax' (points)
+=item B 
+
+is a value to be I for 'ax' (points)
 
-=item B is a I value (I) of the original 'ax'
+=item B 
 
-=item B I 'ax' by the value (points). If negative, increase 'ax'
+is a I value (I) of the original 'ax'
 
-=item B I 'ax' by the given I. Again, negative increases 'ax'
+=item B 
+
+I 'ax' by the value (points). If negative, increase 'ax'
+
+=item B 
+
+I 'ax' by the given I. Again, negative increases 'ax'
 
 =back
 
@@ -2015,6 +2206,207 @@ how fitting to a line length (splitting up an array) could be done, as well as
 how words might be split on hard and soft hyphens. At some point, full paragraph
 and page shaping could be possible.
 
+=head2 MARKUP
+
+This section documents the markup capabilities of the C method.
+It is expected to be updated over time as more functionality is added.
+
+A certain flavor of I is supported, as translated by the 
+Text::Markdown package into HTML. That I (and more, as direct input), 
+along with a subset of CSS, is 
+supported by C. This is I the full Markdown or HTML languages, 
+by any stretch of the imagination, so check before using! Also, a small I 
+markup which only does paragraphs (separated by empty lines) is provided.
+
+In all markup cases, certain CSS settings can be given as parameters or options
+to the C call, including a CSS