From a7748612ee267be39a435617ffd31fa92c3d3bdb Mon Sep 17 00:00:00 2001 From: Jesper Ek Date: Thu, 2 Jan 2014 15:06:06 +0100 Subject: [PATCH] Initial commit. --- INSTALL.txt | 83 ++ LICENSE.txt | 27 + README.md | 22 + README.txt | 160 +++ composer.json | 23 + library/Zend/Pdf.php | 1428 ++++++++++++++++++++ library/Zend/Pdf/Action.php | 404 ++++++ library/Zend/Pdf/Action/GoTo.php | 116 ++ library/Zend/Pdf/Action/GoTo3DView.php | 39 + library/Zend/Pdf/Action/GoToE.php | 38 + library/Zend/Pdf/Action/GoToR.php | 38 + library/Zend/Pdf/Action/Hide.php | 39 + library/Zend/Pdf/Action/ImportData.php | 39 + library/Zend/Pdf/Action/JavaScript.php | 39 + library/Zend/Pdf/Action/Launch.php | 38 + library/Zend/Pdf/Action/Movie.php | 38 + library/Zend/Pdf/Action/Named.php | 39 + library/Zend/Pdf/Action/Rendition.php | 39 + library/Zend/Pdf/Action/ResetForm.php | 39 + library/Zend/Pdf/Action/SetOCGState.php | 39 + library/Zend/Pdf/Action/Sound.php | 39 + library/Zend/Pdf/Action/SubmitForm.php | 39 + library/Zend/Pdf/Action/Thread.php | 38 + library/Zend/Pdf/Action/Trans.php | 39 + library/Zend/Pdf/Action/URI.php | 167 +++ library/Zend/Pdf/Action/Unknown.php | 38 + library/Zend/Pdf/Annotation.php | 230 ++++ library/Zend/Pdf/Annotation/FileAttachment.php | 101 ++ library/Zend/Pdf/Annotation/Link.php | 162 +++ library/Zend/Pdf/Annotation/Markup.php | 142 ++ library/Zend/Pdf/Annotation/Text.php | 95 ++ library/Zend/Pdf/Canvas.php | 182 +++ library/Zend/Pdf/Canvas/Abstract.php | 1217 +++++++++++++++++ library/Zend/Pdf/Canvas/Interface.php | 493 +++++++ library/Zend/Pdf/Cmap.php | 336 +++++ library/Zend/Pdf/Cmap/ByteEncoding.php | 447 ++++++ library/Zend/Pdf/Cmap/ByteEncoding/Static.php | 62 + library/Zend/Pdf/Cmap/SegmentToDelta.php | 407 ++++++ library/Zend/Pdf/Cmap/TrimmedTable.php | 231 ++++ library/Zend/Pdf/Color.php | 53 + library/Zend/Pdf/Color/Cmyk.php | 126 ++ library/Zend/Pdf/Color/GrayScale.php | 84 ++ library/Zend/Pdf/Color/Html.php | 412 ++++++ library/Zend/Pdf/Color/Rgb.php | 114 ++ library/Zend/Pdf/Destination.php | 113 ++ library/Zend/Pdf/Destination/Explicit.php | 122 ++ library/Zend/Pdf/Destination/Fit.php | 75 + library/Zend/Pdf/Destination/FitBoundingBox.php | 75 + .../Pdf/Destination/FitBoundingBoxHorizontally.php | 98 ++ .../Pdf/Destination/FitBoundingBoxVertically.php | 98 ++ library/Zend/Pdf/Destination/FitHorizontally.php | 98 ++ library/Zend/Pdf/Destination/FitRectangle.php | 171 +++ library/Zend/Pdf/Destination/FitVertically.php | 98 ++ library/Zend/Pdf/Destination/Named.php | 101 ++ library/Zend/Pdf/Destination/Unknown.php | 37 + library/Zend/Pdf/Destination/Zoom.php | 177 +++ library/Zend/Pdf/Element.php | 176 +++ library/Zend/Pdf/Element/Array.php | 181 +++ library/Zend/Pdf/Element/Boolean.php | 83 ++ library/Zend/Pdf/Element/Dictionary.php | 236 ++++ library/Zend/Pdf/Element/Name.php | 161 +++ library/Zend/Pdf/Element/Null.php | 75 + library/Zend/Pdf/Element/Numeric.php | 95 ++ library/Zend/Pdf/Element/Object.php | 284 ++++ library/Zend/Pdf/Element/Object/Stream.php | 453 +++++++ library/Zend/Pdf/Element/Reference.php | 303 +++++ library/Zend/Pdf/Element/Reference/Context.php | 83 ++ library/Zend/Pdf/Element/Reference/Table.php | 198 +++ library/Zend/Pdf/Element/Stream.php | 130 ++ library/Zend/Pdf/Element/String.php | 263 ++++ library/Zend/Pdf/Element/String/Binary.php | 98 ++ library/Zend/Pdf/ElementFactory.php | 446 ++++++ library/Zend/Pdf/ElementFactory/Interface.php | 158 +++ library/Zend/Pdf/ElementFactory/Proxy.php | 234 ++++ library/Zend/Pdf/Exception.php | 343 +++++ library/Zend/Pdf/FileParser.php | 485 +++++++ library/Zend/Pdf/FileParser/Font.php | 217 +++ library/Zend/Pdf/FileParser/Font/OpenType.php | 1138 ++++++++++++++++ .../Zend/Pdf/FileParser/Font/OpenType/TrueType.php | 90 ++ library/Zend/Pdf/FileParser/Image.php | 63 + library/Zend/Pdf/FileParser/Image/Png.php | 329 +++++ library/Zend/Pdf/FileParserDataSource.php | 189 +++ library/Zend/Pdf/FileParserDataSource/File.php | 198 +++ library/Zend/Pdf/FileParserDataSource/String.php | 128 ++ library/Zend/Pdf/Filter/Ascii85.php | 181 +++ library/Zend/Pdf/Filter/AsciiHex.php | 135 ++ library/Zend/Pdf/Filter/Compression.php | 391 ++++++ library/Zend/Pdf/Filter/Compression/Flate.php | 102 ++ library/Zend/Pdf/Filter/Compression/Lzw.php | 95 ++ library/Zend/Pdf/Filter/Interface.php | 50 + library/Zend/Pdf/Filter/RunLength.php | 125 ++ library/Zend/Pdf/Font.php | 732 ++++++++++ library/Zend/Pdf/Image.php | 247 ++++ library/Zend/Pdf/NameTree.php | 154 +++ library/Zend/Pdf/Outline.php | 373 +++++ library/Zend/Pdf/Outline/Created.php | 315 +++++ library/Zend/Pdf/Outline/Loaded.php | 460 +++++++ library/Zend/Pdf/Page.php | 773 +++++++++++ library/Zend/Pdf/Parser.php | 472 +++++++ .../Pdf/RecursivelyIteratableObjectsContainer.php | 45 + library/Zend/Pdf/Resource.php | 165 +++ library/Zend/Pdf/Resource/ContentStream.php | 114 ++ library/Zend/Pdf/Resource/Extractor.php | 86 ++ library/Zend/Pdf/Resource/Font.php | 530 ++++++++ library/Zend/Pdf/Resource/Font/CidFont.php | 492 +++++++ .../Zend/Pdf/Resource/Font/CidFont/TrueType.php | 88 ++ library/Zend/Pdf/Resource/Font/Extracted.php | 274 ++++ library/Zend/Pdf/Resource/Font/FontDescriptor.php | 204 +++ library/Zend/Pdf/Resource/Font/Simple.php | 283 ++++ library/Zend/Pdf/Resource/Font/Simple/Parsed.php | 105 ++ .../Pdf/Resource/Font/Simple/Parsed/TrueType.php | 67 + library/Zend/Pdf/Resource/Font/Simple/Standard.php | 82 ++ .../Pdf/Resource/Font/Simple/Standard/Courier.php | 295 ++++ .../Resource/Font/Simple/Standard/CourierBold.php | 296 ++++ .../Font/Simple/Standard/CourierBoldOblique.php | 297 ++++ .../Font/Simple/Standard/CourierOblique.php | 297 ++++ .../Resource/Font/Simple/Standard/Helvetica.php | 305 +++++ .../Font/Simple/Standard/HelveticaBold.php | 305 +++++ .../Font/Simple/Standard/HelveticaBoldOblique.php | 308 +++++ .../Font/Simple/Standard/HelveticaOblique.php | 307 +++++ .../Pdf/Resource/Font/Simple/Standard/Symbol.php | 465 +++++++ .../Resource/Font/Simple/Standard/TimesBold.php | 304 +++++ .../Font/Simple/Standard/TimesBoldItalic.php | 305 +++++ .../Resource/Font/Simple/Standard/TimesItalic.php | 305 +++++ .../Resource/Font/Simple/Standard/TimesRoman.php | 305 +++++ .../Resource/Font/Simple/Standard/ZapfDingbats.php | 491 +++++++ library/Zend/Pdf/Resource/Font/Type0.php | 257 ++++ library/Zend/Pdf/Resource/GraphicsState.php | 109 ++ library/Zend/Pdf/Resource/Image.php | 73 + library/Zend/Pdf/Resource/Image/Jpeg.php | 152 +++ library/Zend/Pdf/Resource/Image/Png.php | 380 ++++++ library/Zend/Pdf/Resource/Image/Tiff.php | 442 ++++++ library/Zend/Pdf/Resource/ImageFactory.php | 71 + library/Zend/Pdf/Resource/Unified.php | 38 + library/Zend/Pdf/StringParser.php | 731 ++++++++++ library/Zend/Pdf/Style.php | 294 ++++ library/Zend/Pdf/Target.php | 76 ++ library/Zend/Pdf/Trailer.php | 126 ++ library/Zend/Pdf/Trailer/Generator.php | 77 ++ library/Zend/Pdf/Trailer/Keeper.php | 143 ++ library/Zend/Pdf/UpdateInfoContainer.php | 131 ++ 141 files changed, 30906 insertions(+) create mode 100644 INSTALL.txt create mode 100644 LICENSE.txt create mode 100644 README.md create mode 100644 README.txt create mode 100644 composer.json create mode 100644 library/Zend/Pdf.php create mode 100644 library/Zend/Pdf/Action.php create mode 100644 library/Zend/Pdf/Action/GoTo.php create mode 100644 library/Zend/Pdf/Action/GoTo3DView.php create mode 100644 library/Zend/Pdf/Action/GoToE.php create mode 100644 library/Zend/Pdf/Action/GoToR.php create mode 100644 library/Zend/Pdf/Action/Hide.php create mode 100644 library/Zend/Pdf/Action/ImportData.php create mode 100644 library/Zend/Pdf/Action/JavaScript.php create mode 100644 library/Zend/Pdf/Action/Launch.php create mode 100644 library/Zend/Pdf/Action/Movie.php create mode 100644 library/Zend/Pdf/Action/Named.php create mode 100644 library/Zend/Pdf/Action/Rendition.php create mode 100644 library/Zend/Pdf/Action/ResetForm.php create mode 100644 library/Zend/Pdf/Action/SetOCGState.php create mode 100644 library/Zend/Pdf/Action/Sound.php create mode 100644 library/Zend/Pdf/Action/SubmitForm.php create mode 100644 library/Zend/Pdf/Action/Thread.php create mode 100644 library/Zend/Pdf/Action/Trans.php create mode 100644 library/Zend/Pdf/Action/URI.php create mode 100644 library/Zend/Pdf/Action/Unknown.php create mode 100644 library/Zend/Pdf/Annotation.php create mode 100644 library/Zend/Pdf/Annotation/FileAttachment.php create mode 100644 library/Zend/Pdf/Annotation/Link.php create mode 100644 library/Zend/Pdf/Annotation/Markup.php create mode 100644 library/Zend/Pdf/Annotation/Text.php create mode 100644 library/Zend/Pdf/Canvas.php create mode 100644 library/Zend/Pdf/Canvas/Abstract.php create mode 100644 library/Zend/Pdf/Canvas/Interface.php create mode 100644 library/Zend/Pdf/Cmap.php create mode 100644 library/Zend/Pdf/Cmap/ByteEncoding.php create mode 100644 library/Zend/Pdf/Cmap/ByteEncoding/Static.php create mode 100644 library/Zend/Pdf/Cmap/SegmentToDelta.php create mode 100644 library/Zend/Pdf/Cmap/TrimmedTable.php create mode 100644 library/Zend/Pdf/Color.php create mode 100644 library/Zend/Pdf/Color/Cmyk.php create mode 100644 library/Zend/Pdf/Color/GrayScale.php create mode 100644 library/Zend/Pdf/Color/Html.php create mode 100644 library/Zend/Pdf/Color/Rgb.php create mode 100644 library/Zend/Pdf/Destination.php create mode 100644 library/Zend/Pdf/Destination/Explicit.php create mode 100644 library/Zend/Pdf/Destination/Fit.php create mode 100644 library/Zend/Pdf/Destination/FitBoundingBox.php create mode 100644 library/Zend/Pdf/Destination/FitBoundingBoxHorizontally.php create mode 100644 library/Zend/Pdf/Destination/FitBoundingBoxVertically.php create mode 100644 library/Zend/Pdf/Destination/FitHorizontally.php create mode 100644 library/Zend/Pdf/Destination/FitRectangle.php create mode 100644 library/Zend/Pdf/Destination/FitVertically.php create mode 100644 library/Zend/Pdf/Destination/Named.php create mode 100644 library/Zend/Pdf/Destination/Unknown.php create mode 100644 library/Zend/Pdf/Destination/Zoom.php create mode 100644 library/Zend/Pdf/Element.php create mode 100644 library/Zend/Pdf/Element/Array.php create mode 100644 library/Zend/Pdf/Element/Boolean.php create mode 100644 library/Zend/Pdf/Element/Dictionary.php create mode 100644 library/Zend/Pdf/Element/Name.php create mode 100644 library/Zend/Pdf/Element/Null.php create mode 100644 library/Zend/Pdf/Element/Numeric.php create mode 100644 library/Zend/Pdf/Element/Object.php create mode 100644 library/Zend/Pdf/Element/Object/Stream.php create mode 100644 library/Zend/Pdf/Element/Reference.php create mode 100644 library/Zend/Pdf/Element/Reference/Context.php create mode 100644 library/Zend/Pdf/Element/Reference/Table.php create mode 100644 library/Zend/Pdf/Element/Stream.php create mode 100644 library/Zend/Pdf/Element/String.php create mode 100644 library/Zend/Pdf/Element/String/Binary.php create mode 100644 library/Zend/Pdf/ElementFactory.php create mode 100644 library/Zend/Pdf/ElementFactory/Interface.php create mode 100644 library/Zend/Pdf/ElementFactory/Proxy.php create mode 100644 library/Zend/Pdf/Exception.php create mode 100644 library/Zend/Pdf/FileParser.php create mode 100644 library/Zend/Pdf/FileParser/Font.php create mode 100644 library/Zend/Pdf/FileParser/Font/OpenType.php create mode 100644 library/Zend/Pdf/FileParser/Font/OpenType/TrueType.php create mode 100644 library/Zend/Pdf/FileParser/Image.php create mode 100644 library/Zend/Pdf/FileParser/Image/Png.php create mode 100644 library/Zend/Pdf/FileParserDataSource.php create mode 100644 library/Zend/Pdf/FileParserDataSource/File.php create mode 100644 library/Zend/Pdf/FileParserDataSource/String.php create mode 100644 library/Zend/Pdf/Filter/Ascii85.php create mode 100644 library/Zend/Pdf/Filter/AsciiHex.php create mode 100644 library/Zend/Pdf/Filter/Compression.php create mode 100644 library/Zend/Pdf/Filter/Compression/Flate.php create mode 100644 library/Zend/Pdf/Filter/Compression/Lzw.php create mode 100644 library/Zend/Pdf/Filter/Interface.php create mode 100644 library/Zend/Pdf/Filter/RunLength.php create mode 100644 library/Zend/Pdf/Font.php create mode 100644 library/Zend/Pdf/Image.php create mode 100644 library/Zend/Pdf/NameTree.php create mode 100644 library/Zend/Pdf/Outline.php create mode 100644 library/Zend/Pdf/Outline/Created.php create mode 100644 library/Zend/Pdf/Outline/Loaded.php create mode 100644 library/Zend/Pdf/Page.php create mode 100644 library/Zend/Pdf/Parser.php create mode 100644 library/Zend/Pdf/RecursivelyIteratableObjectsContainer.php create mode 100644 library/Zend/Pdf/Resource.php create mode 100644 library/Zend/Pdf/Resource/ContentStream.php create mode 100644 library/Zend/Pdf/Resource/Extractor.php create mode 100644 library/Zend/Pdf/Resource/Font.php create mode 100644 library/Zend/Pdf/Resource/Font/CidFont.php create mode 100644 library/Zend/Pdf/Resource/Font/CidFont/TrueType.php create mode 100644 library/Zend/Pdf/Resource/Font/Extracted.php create mode 100644 library/Zend/Pdf/Resource/Font/FontDescriptor.php create mode 100644 library/Zend/Pdf/Resource/Font/Simple.php create mode 100644 library/Zend/Pdf/Resource/Font/Simple/Parsed.php create mode 100644 library/Zend/Pdf/Resource/Font/Simple/Parsed/TrueType.php create mode 100644 library/Zend/Pdf/Resource/Font/Simple/Standard.php create mode 100644 library/Zend/Pdf/Resource/Font/Simple/Standard/Courier.php create mode 100644 library/Zend/Pdf/Resource/Font/Simple/Standard/CourierBold.php create mode 100644 library/Zend/Pdf/Resource/Font/Simple/Standard/CourierBoldOblique.php create mode 100644 library/Zend/Pdf/Resource/Font/Simple/Standard/CourierOblique.php create mode 100644 library/Zend/Pdf/Resource/Font/Simple/Standard/Helvetica.php create mode 100644 library/Zend/Pdf/Resource/Font/Simple/Standard/HelveticaBold.php create mode 100644 library/Zend/Pdf/Resource/Font/Simple/Standard/HelveticaBoldOblique.php create mode 100644 library/Zend/Pdf/Resource/Font/Simple/Standard/HelveticaOblique.php create mode 100644 library/Zend/Pdf/Resource/Font/Simple/Standard/Symbol.php create mode 100644 library/Zend/Pdf/Resource/Font/Simple/Standard/TimesBold.php create mode 100644 library/Zend/Pdf/Resource/Font/Simple/Standard/TimesBoldItalic.php create mode 100644 library/Zend/Pdf/Resource/Font/Simple/Standard/TimesItalic.php create mode 100644 library/Zend/Pdf/Resource/Font/Simple/Standard/TimesRoman.php create mode 100644 library/Zend/Pdf/Resource/Font/Simple/Standard/ZapfDingbats.php create mode 100644 library/Zend/Pdf/Resource/Font/Type0.php create mode 100644 library/Zend/Pdf/Resource/GraphicsState.php create mode 100644 library/Zend/Pdf/Resource/Image.php create mode 100644 library/Zend/Pdf/Resource/Image/Jpeg.php create mode 100644 library/Zend/Pdf/Resource/Image/Png.php create mode 100644 library/Zend/Pdf/Resource/Image/Tiff.php create mode 100644 library/Zend/Pdf/Resource/ImageFactory.php create mode 100644 library/Zend/Pdf/Resource/Unified.php create mode 100644 library/Zend/Pdf/StringParser.php create mode 100644 library/Zend/Pdf/Style.php create mode 100644 library/Zend/Pdf/Target.php create mode 100644 library/Zend/Pdf/Trailer.php create mode 100644 library/Zend/Pdf/Trailer/Generator.php create mode 100644 library/Zend/Pdf/Trailer/Keeper.php create mode 100644 library/Zend/Pdf/UpdateInfoContainer.php diff --git a/INSTALL.txt b/INSTALL.txt new file mode 100644 index 0000000..a8e4c19 --- /dev/null +++ b/INSTALL.txt @@ -0,0 +1,83 @@ +INSTALLATION +------------ + +Zend Framework requires no special installation steps. Simply download the framework, +extract it to the folder you would like to keep it in, and add the library directory +to your PHP include_path. To use components in the extras library, add the extras/library +directory to your PHP include_path, as well. +If you would like to use Zend_Tool, simply add bin/zf.bat (for Windows) or +bin/zf.sh (for anything else) to your system executable path. + +SYSTEM REQUIREMENTS +------------------- + +Zend Framework requires PHP 5.2.11 or later. Please see the system requirements +appendix for more detailed information: + +http://framework.zend.com/manual/en/requirements.html + +DEVELOPMENT VERSIONS +-------------------- + +If you would like to preview enhancements or bug fixes that have not yet been +released, you can obtain the current development version of Zend Framework using one +of the following methods: + +* Download the latest nightly snapshot. For those who care to brave the cutting + (often bleeding) edge, the nightly snapshots represent the latest single- + download development version of Zend Framework development. Snapshots are bundled + with documentation in English only or in all available languages. If you anticipate + updating to the latest development version of Zend Framework often, consider using + Subversion as described below. + + http://framework.zend.com/download/snapshot + +* Using a Subversion (SVN) client. Zend Framework is open source software, and + the Subversion repository used for its development is publicly available. Consider + using SVN to get Zend Framework if you already use SVN for your application + development, want to contribute back to the framework, or need to upgrade your + framework version very often. + + Exporting is useful if you want to get a particular framework revision without the + .svn directories as created in a working copy. + + Checking out a working copy is necessary if you would like to directly contribute + to Zend Framework; a working copy can be updated any time with svn update. + + An externals definition is highly convenient for developers already using SVN to + manage their application working copies. + + The URL for the trunk of the Zend Framework SVN repository is: + + http://framework.zend.com/svn/framework/trunk + + For more information about Subversion, please see the official website: + + http://subversion.tigris.org + +CONFIGURING THE INCLUDE PATH +---------------------------- + +Once you have a copy of Zend Framework available, your application will need to +access the framework classes. Though there are several ways to achieve this, your +PHP include_path needs to contain the path to the Zend Framework classes under the +/library directory in this distribution. You can find out more about the PHP +include_path configuration directive here: + +http://www.php.net/manual/en/ini.core.php#ini.include-path + +Instructions on how to change PHP configuration directives can be found here: + +http://www.php.net/manual/en/configuration.changes.php + +GETTING STARTED +--------------- + +A great place to get up-to-speed quickly is the Zend Framework QuickStart: + +http://framework.zend.com/docs/quickstart + +The QuickStart covers some of the most commonly used components of ZF. Since +Zend Framework is designed with a use-at-will architecture and components are +loosely coupled, you can select and use only those components that are needed for +your project. diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..36e9760 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,27 @@ +Copyright (c) 2005-2012, Zend Technologies USA, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of Zend Technologies USA, Inc. nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..1fb9a65 --- /dev/null +++ b/README.md @@ -0,0 +1,22 @@ +Zend Framework 1 for Composer +============================= + +This package is a part of the Zend Framework 1. Each component was separated and put into its own composer package. Some modifications were made for improved [Composer](http://getcomposer.org/) integration. This package can also be found at [Packagist](http://packagist.org/packages/zf1). + +## Why? + +**Size!** Zend Framework is very large and contains a huge amount of files (over 72000 files in the main repository!). If you're only using a part of the framework, using the separated packages will greatly reduce the amount of files. This will make setup faster and easier on your disks. + +**Autoloading!** Explicit `require_once` calls in the source code has been commented out to rely on composer autoloading, this reduces the number of included files to a minimum. + +**Migration!** Zend Framework 2 has been around for a while now, and migrating all your projects takes a lot of time. Using these packages makes it easier to migrate each component separately. Also, some packages doesn't exist in zf2 (such as the zend-search-lucene), now you can continue using that package without requiring the entire framework. + +If you're using major parts of the framework, I would recommend checking out the [zendframework1 package](https://github.com/bombayworks/zendframework1), which contains the entire framework optimized for composer usage. + +## How to use + +Add `"zf1/zend-pdf": "~1.12"` to the require section of your composer.json, include the composer autoloader and you're good to go. + +## Broken dependencies? + +Dependencies have been set automatically based on the [requirements from the zend framework manual](http://framework.zend.com/manual/1.12/en/requirements.introduction.html), if you find any broken dependencies please submit an issue. \ No newline at end of file diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..596d08c --- /dev/null +++ b/README.txt @@ -0,0 +1,160 @@ +Welcome to the Zend Framework 1.12 Release! + +RELEASE INFORMATION +--------------- +Zend Framework 1.12.3 Release ([INSERT REV NUM HERE]). +Released on March 13, 2013 + +IMPORTANT FIXES FOR 1.12.3 +-------------------------- + +This release incorporates is primarily aimed to update +Zend_Service_Twitter to the Twitter v1.1 API: + + - http://framework.zend.com/issues/browse/ZF-12530 + +Because the Twitter v1.1 API is not backwards compatible with v1.0, the +API for Zend_Service_Twitter has been changed; if you have been using it +previously, you will need to update your code accordingly. Both the +end-user and API documentation have been updated to reflect the changes. + +NEW FEATURES +============ + +Zend_Loader changes +---- + +A number of autoloaders and autoloader facilities were back ported from +ZF2 to provide performant alternatives to those already available in the +1.X releases. These include: Zend_Loader_StandardAutoloader, which +improves on Zend_Loader_Autoloader by allowing the ability to specify a +specific path to associate with a vendor prefix or namespace; +Zend_Loader_ClassMapAutoloader, which provides the ability to use lookup +tables for autoloading (which are typically the fastest possible way to +autoload); and Zend_Loader_AutoloaderFactory, which can both create and +update autoloaders for you, as well as register them with +spl_autoload_register(). + +The Zend_Loader changes were back ported from ZF2 by Matthew Weier +O’Phinney + +Zend_EventManager +---- + +Zend_EventManager is a component that allows you to attach and detach +listeners to named events, both on a per-instance basis as well as via +shared collections; trigger events; and interrupt execution of +listeners. + +Zend_EventManager was back ported from ZF2 by Matthew Weier O’Phinney + +Zend_Http_UserAgent_Features_Adapter_Browscap +---- + +This class provides a features adapter that calls get_browser() in order +to discover mobile device capabilities to inject into UserAgent device +instances. + +Browscap (http://browsers.garykeith.com/) is an open project dedicated +to collecting an disseminating a “database” of browser capabilities. PHP +has built-in support for using these files via the get_browser() +function. This function requires that your php.ini provides a browscap +entry pointing to the PHP-specific php_browscap.ini file which is +available at http://browsers.garykeith.com/stream.asp?PHP_BrowsCapINI. + +Zend_Http_UserAgent_Features_Adapter_Browscap was created by Matthew +Weier O’Phinney + +Zend_Mobile_Push +---- + +Zend_Mobile_Push is a component for implementing push notifications for +the 3 major push notification platforms (Apple (Apns), Google (C2dm) and +Microsoft (Mpns). + +Zend_Mobile_Push was contributed by Mike Willbanks. + +Zend_Gdata_Analytics +---- + +Zend_Gdata_Analytics is an extension to Zend_Gdata to allow interaction +with Google’s Analytics Data Export API. This extension does not +encompass any major changes in the overall operation of Zend_Gdata +components. + +Zend_Gdata_Analytics was contributed by Daniel Hartmann. + +Removed features +================ + +Zend_Http_UserAgent_Features_Adapter_WurflApi +---- + +Due to the changes in licensing of WURFL, we have removed the WurflApi +adapter. We will be providing the WurflApi adapter to ScientiaMobile so +that users of WURFL will still have that option. + +Bug Fixes +========= + +In addition, over 200 reported issues in the tracker have been fixed. +We’d like to particularly thank Adam Lundrigan, Frank Brückner and +Martin Hujer for their efforts in making this happen. Thanks also to the +many people who ran the ZF1 unit tests and reported their results! + +For a complete list, visit: + + * http://framework.zend.com/issues/secure/IssueNavigator.jspa?requestId=12877 + * http://framework.zend.com/changelog/ + +MIGRATION NOTES +--------------- + +A detailed list of migration notes may be found at: + +http://framework.zend.com/manual/en/migration.html + +SYSTEM REQUIREMENTS +------------------- + +Zend Framework requires PHP 5.2.11 or later. Please see our reference +guide for more detailed system requirements: + +http://framework.zend.com/manual/en/requirements.html + +INSTALLATION +------------ + +Please see INSTALL.txt. + +QUESTIONS AND FEEDBACK +---------------------- + +Online documentation can be found at http://framework.zend.com/manual. +Questions that are not addressed in the manual should be directed to the +appropriate mailing list: + +http://framework.zend.com/wiki/display/ZFDEV/Mailing+Lists + +If you find code in this release behaving in an unexpected manner or +contrary to its documented behavior, please create an issue in the Zend +Framework issue tracker at: + +http://framework.zend.com/issues + +If you would like to be notified of new releases, you can subscribe to +the fw-announce mailing list by sending a blank message to +fw-announce-subscribe@lists.zend.com. + +LICENSE +------- + +The files in this archive are released under the Zend Framework license. +You can find a copy of this license in LICENSE.txt. + +ACKNOWLEDGEMENTS +---------------- + +The Zend Framework team would like to thank all the contributors to the Zend +Framework project, our corporate sponsor, and you, the Zend Framework user. +Please visit us sometime soon at http://framework.zend.com. diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..319ea7f --- /dev/null +++ b/composer.json @@ -0,0 +1,23 @@ +{ + "name": "zf1/zend-pdf", + "description": "Zend Framework 1 Pdf package", + "keywords": [ + "framework", + "zf1", + "zend", + "pdf" + ], + "homepage": "http://framework.zend.com/", + "license": "BSD-3-Clause", + "require": { + "php": ">=5.2.11", + "zf1/zend-exception": "self.version", + "zf1/zend-log": "self.version", + "zf1/zend-memory": "self.version" + }, + "autoload": { + "psr-0": { + "Zend_Pdf": "library/" + } + } +} \ No newline at end of file diff --git a/library/Zend/Pdf.php b/library/Zend/Pdf.php new file mode 100644 index 0000000..97d9830 --- /dev/null +++ b/library/Zend/Pdf.php @@ -0,0 +1,1428 @@ +render($updateOnly, $file); + + fclose($file); + } + + /** + * Creates or loads PDF document. + * + * If $source is null, then it creates a new document. + * + * If $source is a string and $load is false, then it loads document + * from a binary string. + * + * If $source is a string and $load is true, then it loads document + * from a file. + + * $revision used to roll back document to specified version + * (0 - current version, 1 - previous version, 2 - ...) + * + * @param string $source - PDF file to load + * @param integer $revision + * @throws Zend_Pdf_Exception + * @return Zend_Pdf + */ + public function __construct($source = null, $revision = null, $load = false) + { + // require_once 'Zend/Pdf/ElementFactory.php'; + $this->_objFactory = Zend_Pdf_ElementFactory::createFactory(1); + + if ($source !== null) { + // require_once 'Zend/Pdf/Parser.php'; + $this->_parser = new Zend_Pdf_Parser($source, $this->_objFactory, $load); + $this->_pdfHeaderVersion = $this->_parser->getPDFVersion(); + $this->_trailer = $this->_parser->getTrailer(); + if ($this->_trailer->Encrypt !== null) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Encrypted document modification is not supported'); + } + if ($revision !== null) { + $this->rollback($revision); + } else { + $this->_loadPages($this->_trailer->Root->Pages); + } + + $this->_loadNamedDestinations($this->_trailer->Root, $this->_parser->getPDFVersion()); + $this->_loadOutlines($this->_trailer->Root); + + if ($this->_trailer->Info !== null) { + $this->properties = $this->_trailer->Info->toPhp(); + + if (isset($this->properties['Trapped'])) { + switch ($this->properties['Trapped']) { + case 'True': + $this->properties['Trapped'] = true; + break; + + case 'False': + $this->properties['Trapped'] = false; + break; + + case 'Unknown': + $this->properties['Trapped'] = null; + break; + + default: + // Wrong property value + // Do nothing + break; + } + } + + $this->_originalProperties = $this->properties; + } + + $this->_isNewDocument = false; + } else { + $this->_pdfHeaderVersion = Zend_Pdf::PDF_VERSION; + + $trailerDictionary = new Zend_Pdf_Element_Dictionary(); + + /** + * Document id + */ + $docId = md5(uniqid(rand(), true)); // 32 byte (128 bit) identifier + $docIdLow = substr($docId, 0, 16); // first 16 bytes + $docIdHigh = substr($docId, 16, 16); // second 16 bytes + + $trailerDictionary->ID = new Zend_Pdf_Element_Array(); + $trailerDictionary->ID->items[] = new Zend_Pdf_Element_String_Binary($docIdLow); + $trailerDictionary->ID->items[] = new Zend_Pdf_Element_String_Binary($docIdHigh); + + $trailerDictionary->Size = new Zend_Pdf_Element_Numeric(0); + + // require_once 'Zend/Pdf/Trailer/Generator.php'; + $this->_trailer = new Zend_Pdf_Trailer_Generator($trailerDictionary); + + /** + * Document catalog indirect object. + */ + $docCatalog = $this->_objFactory->newObject(new Zend_Pdf_Element_Dictionary()); + $docCatalog->Type = new Zend_Pdf_Element_Name('Catalog'); + $docCatalog->Version = new Zend_Pdf_Element_Name(Zend_Pdf::PDF_VERSION); + $this->_trailer->Root = $docCatalog; + + /** + * Pages container + */ + $docPages = $this->_objFactory->newObject(new Zend_Pdf_Element_Dictionary()); + $docPages->Type = new Zend_Pdf_Element_Name('Pages'); + $docPages->Kids = new Zend_Pdf_Element_Array(); + $docPages->Count = new Zend_Pdf_Element_Numeric(0); + $docCatalog->Pages = $docPages; + } + } + + /** + * Retrive number of revisions. + * + * @return integer + */ + public function revisions() + { + $revisions = 1; + $currentTrailer = $this->_trailer; + + while ($currentTrailer->getPrev() !== null && $currentTrailer->getPrev()->Root !== null ) { + $revisions++; + $currentTrailer = $currentTrailer->getPrev(); + } + + return $revisions++; + } + + /** + * Rollback document $steps number of revisions. + * This method must be invoked before any changes, applied to the document. + * Otherwise behavior is undefined. + * + * @param integer $steps + */ + public function rollback($steps) + { + for ($count = 0; $count < $steps; $count++) { + if ($this->_trailer->getPrev() !== null && $this->_trailer->getPrev()->Root !== null) { + $this->_trailer = $this->_trailer->getPrev(); + } else { + break; + } + } + $this->_objFactory->setObjectCount($this->_trailer->Size->value); + + // Mark content as modified to force new trailer generation at render time + $this->_trailer->Root->touch(); + + $this->pages = array(); + $this->_loadPages($this->_trailer->Root->Pages); + } + + + /** + * Load pages recursively + * + * @param Zend_Pdf_Element_Reference $pages + * @param array|null $attributes + */ + protected function _loadPages(Zend_Pdf_Element_Reference $pages, $attributes = array()) + { + if ($pages->getType() != Zend_Pdf_Element::TYPE_DICTIONARY) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Wrong argument'); + } + + foreach ($pages->getKeys() as $property) { + if (in_array($property, self::$_inheritableAttributes)) { + $attributes[$property] = $pages->$property; + $pages->$property = null; + } + } + + + foreach ($pages->Kids->items as $child) { + if ($child->Type->value == 'Pages') { + $this->_loadPages($child, $attributes); + } else if ($child->Type->value == 'Page') { + foreach (self::$_inheritableAttributes as $property) { + if ($child->$property === null && array_key_exists($property, $attributes)) { + /** + * Important note. + * If any attribute or dependant object is an indirect object, then it's still + * shared between pages. + */ + if ($attributes[$property] instanceof Zend_Pdf_Element_Object || + $attributes[$property] instanceof Zend_Pdf_Element_Reference) { + $child->$property = $attributes[$property]; + } else { + $child->$property = $this->_objFactory->newObject($attributes[$property]); + } + } + } + + // require_once 'Zend/Pdf/Page.php'; + $this->pages[] = new Zend_Pdf_Page($child, $this->_objFactory); + } + } + } + + /** + * Load named destinations recursively + * + * @param Zend_Pdf_Element_Reference $root Document catalog entry + * @param string $pdfHeaderVersion + * @throws Zend_Pdf_Exception + */ + protected function _loadNamedDestinations(Zend_Pdf_Element_Reference $root, $pdfHeaderVersion) + { + if ($root->Version !== null && version_compare($root->Version->value, $pdfHeaderVersion, '>')) { + $versionIs_1_2_plus = version_compare($root->Version->value, '1.1', '>'); + } else { + $versionIs_1_2_plus = version_compare($pdfHeaderVersion, '1.1', '>'); + } + + if ($versionIs_1_2_plus) { + // PDF version is 1.2+ + // Look for Destinations structure at Name dictionary + if ($root->Names !== null && $root->Names->Dests !== null) { + // require_once 'Zend/Pdf/NameTree.php'; + // require_once 'Zend/Pdf/Target.php'; + foreach (new Zend_Pdf_NameTree($root->Names->Dests) as $name => $destination) { + $this->_namedTargets[$name] = Zend_Pdf_Target::load($destination); + } + } + } else { + // PDF version is 1.1 (or earlier) + // Look for Destinations sructure at Dest entry of document catalog + if ($root->Dests !== null) { + if ($root->Dests->getType() != Zend_Pdf_Element::TYPE_DICTIONARY) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Document catalog Dests entry must be a dictionary.'); + } + + // require_once 'Zend/Pdf/Target.php'; + foreach ($root->Dests->getKeys() as $destKey) { + $this->_namedTargets[$destKey] = Zend_Pdf_Target::load($root->Dests->$destKey); + } + } + } + } + + /** + * Load outlines recursively + * + * @param Zend_Pdf_Element_Reference $root Document catalog entry + */ + protected function _loadOutlines(Zend_Pdf_Element_Reference $root) + { + if ($root->Outlines === null) { + return; + } + + if ($root->Outlines->getType() != Zend_Pdf_Element::TYPE_DICTIONARY) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Document catalog Outlines entry must be a dictionary.'); + } + + if ($root->Outlines->Type !== null && $root->Outlines->Type->value != 'Outlines') { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Outlines Type entry must be an \'Outlines\' string.'); + } + + if ($root->Outlines->First === null) { + return; + } + + $outlineDictionary = $root->Outlines->First; + $processedDictionaries = new SplObjectStorage(); + while ($outlineDictionary !== null && !$processedDictionaries->contains($outlineDictionary)) { + $processedDictionaries->attach($outlineDictionary); + + // require_once 'Zend/Pdf/Outline/Loaded.php'; + $this->outlines[] = new Zend_Pdf_Outline_Loaded($outlineDictionary); + + $outlineDictionary = $outlineDictionary->Next; + } + + $this->_originalOutlines = $this->outlines; + + if ($root->Outlines->Count !== null) { + $this->_originalOpenOutlinesCount = $root->Outlines->Count->value; + } + } + + /** + * Orginize pages to tha pages tree structure. + * + * @todo atomatically attach page to the document, if it's not done yet. + * @todo check, that page is attached to the current document + * + * @todo Dump pages as a balanced tree instead of a plain set. + */ + protected function _dumpPages() + { + $root = $this->_trailer->Root; + $pagesContainer = $root->Pages; + + $pagesContainer->touch(); + $pagesContainer->Kids->items = array(); + + foreach ($this->pages as $page ) { + $page->render($this->_objFactory); + + $pageDictionary = $page->getPageDictionary(); + $pageDictionary->touch(); + $pageDictionary->Parent = $pagesContainer; + + $pagesContainer->Kids->items[] = $pageDictionary; + } + + $this->_refreshPagesHash(); + + $pagesContainer->Count->touch(); + $pagesContainer->Count->value = count($this->pages); + + + // Refresh named destinations list + foreach ($this->_namedTargets as $name => $namedTarget) { + if ($namedTarget instanceof Zend_Pdf_Destination_Explicit) { + // Named target is an explicit destination + if ($this->resolveDestination($namedTarget, false) === null) { + unset($this->_namedTargets[$name]); + } + } else if ($namedTarget instanceof Zend_Pdf_Action) { + // Named target is an action + if ($this->_cleanUpAction($namedTarget, false) === null) { + // Action is a GoTo action with an unresolved destination + unset($this->_namedTargets[$name]); + } + } else { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Wrong type of named targed (\'' . get_class($namedTarget) . '\').'); + } + } + + // Refresh outlines + // require_once 'Zend/Pdf/RecursivelyIteratableObjectsContainer.php'; + $iterator = new RecursiveIteratorIterator(new Zend_Pdf_RecursivelyIteratableObjectsContainer($this->outlines), RecursiveIteratorIterator::SELF_FIRST); + foreach ($iterator as $outline) { + $target = $outline->getTarget(); + + if ($target !== null) { + if ($target instanceof Zend_Pdf_Destination) { + // Outline target is a destination + if ($this->resolveDestination($target, false) === null) { + $outline->setTarget(null); + } + } else if ($target instanceof Zend_Pdf_Action) { + // Outline target is an action + if ($this->_cleanUpAction($target, false) === null) { + // Action is a GoTo action with an unresolved destination + $outline->setTarget(null); + } + } else { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Wrong outline target.'); + } + } + } + + $openAction = $this->getOpenAction(); + if ($openAction !== null) { + if ($openAction instanceof Zend_Pdf_Action) { + // OpenAction is an action + if ($this->_cleanUpAction($openAction, false) === null) { + // Action is a GoTo action with an unresolved destination + $this->setOpenAction(null); + } + } else if ($openAction instanceof Zend_Pdf_Destination) { + // OpenAction target is a destination + if ($this->resolveDestination($openAction, false) === null) { + $this->setOpenAction(null); + } + } else { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('OpenAction has to be either PDF Action or Destination.'); + } + } + } + + /** + * Dump named destinations + * + * @todo Create a balanced tree instead of plain structure. + */ + protected function _dumpNamedDestinations() + { + ksort($this->_namedTargets, SORT_STRING); + + $destArrayItems = array(); + foreach ($this->_namedTargets as $name => $destination) { + $destArrayItems[] = new Zend_Pdf_Element_String($name); + + if ($destination instanceof Zend_Pdf_Target) { + $destArrayItems[] = $destination->getResource(); + } else { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('PDF named destinations must be a Zend_Pdf_Target object.'); + } + } + $destArray = $this->_objFactory->newObject(new Zend_Pdf_Element_Array($destArrayItems)); + + $DestTree = $this->_objFactory->newObject(new Zend_Pdf_Element_Dictionary()); + $DestTree->Names = $destArray; + + $root = $this->_trailer->Root; + + if ($root->Names === null) { + $root->touch(); + $root->Names = $this->_objFactory->newObject(new Zend_Pdf_Element_Dictionary()); + } else { + $root->Names->touch(); + } + $root->Names->Dests = $DestTree; + } + + /** + * Dump outlines recursively + */ + protected function _dumpOutlines() + { + $root = $this->_trailer->Root; + + if ($root->Outlines === null) { + if (count($this->outlines) == 0) { + return; + } else { + $root->Outlines = $this->_objFactory->newObject(new Zend_Pdf_Element_Dictionary()); + $root->Outlines->Type = new Zend_Pdf_Element_Name('Outlines'); + $updateOutlinesNavigation = true; + } + } else { + $updateOutlinesNavigation = false; + if (count($this->_originalOutlines) != count($this->outlines)) { + // If original and current outlines arrays have different size then outlines list was updated + $updateOutlinesNavigation = true; + } else if ( !(array_keys($this->_originalOutlines) === array_keys($this->outlines)) ) { + // If original and current outlines arrays have different keys (with a glance to an order) then outlines list was updated + $updateOutlinesNavigation = true; + } else { + foreach ($this->outlines as $key => $outline) { + if ($this->_originalOutlines[$key] !== $outline) { + $updateOutlinesNavigation = true; + } + } + } + } + + $lastOutline = null; + $openOutlinesCount = 0; + if ($updateOutlinesNavigation) { + $root->Outlines->touch(); + $root->Outlines->First = null; + + foreach ($this->outlines as $outline) { + if ($lastOutline === null) { + // First pass. Update Outlines dictionary First entry using corresponding value + $lastOutline = $outline->dumpOutline($this->_objFactory, $updateOutlinesNavigation, $root->Outlines); + $root->Outlines->First = $lastOutline; + } else { + // Update previous outline dictionary Next entry (Prev is updated within dumpOutline() method) + $currentOutlineDictionary = $outline->dumpOutline($this->_objFactory, $updateOutlinesNavigation, $root->Outlines, $lastOutline); + $lastOutline->Next = $currentOutlineDictionary; + $lastOutline = $currentOutlineDictionary; + } + $openOutlinesCount += $outline->openOutlinesCount(); + } + + $root->Outlines->Last = $lastOutline; + } else { + foreach ($this->outlines as $outline) { + $lastOutline = $outline->dumpOutline($this->_objFactory, $updateOutlinesNavigation, $root->Outlines, $lastOutline); + $openOutlinesCount += $outline->openOutlinesCount(); + } + } + + if ($openOutlinesCount != $this->_originalOpenOutlinesCount) { + $root->Outlines->touch; + $root->Outlines->Count = new Zend_Pdf_Element_Numeric($openOutlinesCount); + } + } + + /** + * Create page object, attached to the PDF document. + * Method signatures: + * + * 1. Create new page with a specified pagesize. + * If $factory is null then it will be created and page must be attached to the document to be + * included into output. + * --------------------------------------------------------- + * new Zend_Pdf_Page(string $pagesize); + * --------------------------------------------------------- + * + * 2. Create new page with a specified pagesize (in default user space units). + * If $factory is null then it will be created and page must be attached to the document to be + * included into output. + * --------------------------------------------------------- + * new Zend_Pdf_Page(numeric $width, numeric $height); + * --------------------------------------------------------- + * + * @param mixed $param1 + * @param mixed $param2 + * @return Zend_Pdf_Page + */ + public function newPage($param1, $param2 = null) + { + // require_once 'Zend/Pdf/Page.php'; + if ($param2 === null) { + return new Zend_Pdf_Page($param1, $this->_objFactory); + } else { + return new Zend_Pdf_Page($param1, $param2, $this->_objFactory); + } + } + + /** + * Return the document-level Metadata + * or null Metadata stream is not presented + * + * @return string + */ + public function getMetadata() + { + if ($this->_trailer->Root->Metadata !== null) { + return $this->_trailer->Root->Metadata->value; + } else { + return null; + } + } + + /** + * Sets the document-level Metadata (mast be valid XMP document) + * + * @param string $metadata + */ + public function setMetadata($metadata) + { + $metadataObject = $this->_objFactory->newStreamObject($metadata); + $metadataObject->dictionary->Type = new Zend_Pdf_Element_Name('Metadata'); + $metadataObject->dictionary->Subtype = new Zend_Pdf_Element_Name('XML'); + + $this->_trailer->Root->Metadata = $metadataObject; + $this->_trailer->Root->touch(); + } + + /** + * Return the document-level JavaScript + * or null if there is no JavaScript for this document + * + * @return string + */ + public function getJavaScript() + { + return $this->_javaScript; + } + + /** + * Get open Action + * Returns Zend_Pdf_Target (Zend_Pdf_Destination or Zend_Pdf_Action object) + * + * @return Zend_Pdf_Target + */ + public function getOpenAction() + { + if ($this->_trailer->Root->OpenAction !== null) { + // require_once 'Zend/Pdf/Target.php'; + return Zend_Pdf_Target::load($this->_trailer->Root->OpenAction); + } else { + return null; + } + } + + /** + * Set open Action which is actually Zend_Pdf_Destination or Zend_Pdf_Action object + * + * @param Zend_Pdf_Target $openAction + * @returns Zend_Pdf + */ + public function setOpenAction(Zend_Pdf_Target $openAction = null) + { + $root = $this->_trailer->Root; + $root->touch(); + + if ($openAction === null) { + $root->OpenAction = null; + } else { + $root->OpenAction = $openAction->getResource(); + + if ($openAction instanceof Zend_Pdf_Action) { + $openAction->dumpAction($this->_objFactory); + } + } + + return $this; + } + + /** + * Return an associative array containing all the named destinations (or GoTo actions) in the PDF. + * Named targets can be used to reference from outside + * the PDF, ex: 'http://www.something.com/mydocument.pdf#MyAction' + * + * @return array + */ + public function getNamedDestinations() + { + return $this->_namedTargets; + } + + /** + * Return specified named destination + * + * @param string $name + * @return Zend_Pdf_Destination_Explicit|Zend_Pdf_Action_GoTo + */ + public function getNamedDestination($name) + { + if (isset($this->_namedTargets[$name])) { + return $this->_namedTargets[$name]; + } else { + return null; + } + } + + /** + * Set specified named destination + * + * @param string $name + * @param Zend_Pdf_Destination_Explicit|Zend_Pdf_Action_GoTo $target + */ + public function setNamedDestination($name, $destination = null) + { + if ($destination !== null && + !$destination instanceof Zend_Pdf_Action_GoTo && + !$destination instanceof Zend_Pdf_Destination_Explicit) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('PDF named destination must refer an explicit destination or a GoTo PDF action.'); + } + + if ($destination !== null) { + $this->_namedTargets[$name] = $destination; + } else { + unset($this->_namedTargets[$name]); + } + } + + /** + * Pages collection hash: + * => Zend_Pdf_Page + * + * @var SplObjectStorage + */ + protected $_pageReferences = null; + + /** + * Pages collection hash: + * => Zend_Pdf_Page + * + * @var array + */ + protected $_pageNumbers = null; + + /** + * Refresh page collection hashes + * + * @return Zend_Pdf + */ + protected function _refreshPagesHash() + { + $this->_pageReferences = array(); + $this->_pageNumbers = array(); + $count = 1; + foreach ($this->pages as $page) { + $pageDictionaryHashId = spl_object_hash($page->getPageDictionary()->getObject()); + $this->_pageReferences[$pageDictionaryHashId] = $page; + $this->_pageNumbers[$count++] = $page; + } + + return $this; + } + + /** + * Resolve destination. + * + * Returns Zend_Pdf_Page page object or null if destination is not found within PDF document. + * + * @param Zend_Pdf_Destination $destination Destination to resolve + * @param boolean $refreshPagesHash Refresh page collection hashes before processing + * @return Zend_Pdf_Page|null + * @throws Zend_Pdf_Exception + */ + public function resolveDestination(Zend_Pdf_Destination $destination, $refreshPageCollectionHashes = true) + { + if ($this->_pageReferences === null || $refreshPageCollectionHashes) { + $this->_refreshPagesHash(); + } + + if ($destination instanceof Zend_Pdf_Destination_Named) { + if (!isset($this->_namedTargets[$destination->getName()])) { + return null; + } + $destination = $this->getNamedDestination($destination->getName()); + + if ($destination instanceof Zend_Pdf_Action) { + if (!$destination instanceof Zend_Pdf_Action_GoTo) { + return null; + } + $destination = $destination->getDestination(); + } + + if (!$destination instanceof Zend_Pdf_Destination_Explicit) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Named destination target has to be an explicit destination.'); + } + } + + // Named target is an explicit destination + $pageElement = $destination->getResource()->items[0]; + + if ($pageElement->getType() == Zend_Pdf_Element::TYPE_NUMERIC) { + // Page reference is a PDF number + if (!isset($this->_pageNumbers[$pageElement->value])) { + return null; + } + + return $this->_pageNumbers[$pageElement->value]; + } + + // Page reference is a PDF page dictionary reference + $pageDictionaryHashId = spl_object_hash($pageElement->getObject()); + if (!isset($this->_pageReferences[$pageDictionaryHashId])) { + return null; + } + return $this->_pageReferences[$pageDictionaryHashId]; + } + + /** + * Walk through action and its chained actions tree and remove nodes + * if they are GoTo actions with an unresolved target. + * + * Returns null if root node is deleted or updated action overwise. + * + * @todo Give appropriate name and make method public + * + * @param Zend_Pdf_Action $action + * @param boolean $refreshPagesHash Refresh page collection hashes before processing + * @return Zend_Pdf_Action|null + */ + protected function _cleanUpAction(Zend_Pdf_Action $action, $refreshPageCollectionHashes = true) + { + if ($this->_pageReferences === null || $refreshPageCollectionHashes) { + $this->_refreshPagesHash(); + } + + // Named target is an action + if ($action instanceof Zend_Pdf_Action_GoTo && + $this->resolveDestination($action->getDestination(), false) === null) { + // Action itself is a GoTo action with an unresolved destination + return null; + } + + // Walk through child actions + $iterator = new RecursiveIteratorIterator($action, RecursiveIteratorIterator::SELF_FIRST); + + $actionsToClean = array(); + $deletionCandidateKeys = array(); + foreach ($iterator as $chainedAction) { + if ($chainedAction instanceof Zend_Pdf_Action_GoTo && + $this->resolveDestination($chainedAction->getDestination(), false) === null) { + // Some child action is a GoTo action with an unresolved destination + // Mark it as a candidate for deletion + $actionsToClean[] = $iterator->getSubIterator(); + $deletionCandidateKeys[] = $iterator->getSubIterator()->key(); + } + } + foreach ($actionsToClean as $id => $action) { + unset($action->next[$deletionCandidateKeys[$id]]); + } + + return $action; + } + + /** + * Extract fonts attached to the document + * + * returns array of Zend_Pdf_Resource_Font_Extracted objects + * + * @return array + * @throws Zend_Pdf_Exception + */ + public function extractFonts() + { + $fontResourcesUnique = array(); + foreach ($this->pages as $page) { + $pageResources = $page->extractResources(); + + if ($pageResources->Font === null) { + // Page doesn't contain have any font reference + continue; + } + + $fontResources = $pageResources->Font; + + foreach ($fontResources->getKeys() as $fontResourceName) { + $fontDictionary = $fontResources->$fontResourceName; + + if (! ($fontDictionary instanceof Zend_Pdf_Element_Reference || + $fontDictionary instanceof Zend_Pdf_Element_Object) ) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Font dictionary has to be an indirect object or object reference.'); + } + + $fontResourcesUnique[spl_object_hash($fontDictionary->getObject())] = $fontDictionary; + } + } + + $fonts = array(); + // require_once 'Zend/Pdf/Exception.php'; + foreach ($fontResourcesUnique as $resourceId => $fontDictionary) { + try { + // Try to extract font + // require_once 'Zend/Pdf/Resource/Font/Extracted.php'; + $extractedFont = new Zend_Pdf_Resource_Font_Extracted($fontDictionary); + + $fonts[$resourceId] = $extractedFont; + } catch (Zend_Pdf_Exception $e) { + if ($e->getMessage() != 'Unsupported font type.') { + throw $e; + } + } + } + + return $fonts; + } + + /** + * Extract font attached to the page by specific font name + * + * $fontName should be specified in UTF-8 encoding + * + * @return Zend_Pdf_Resource_Font_Extracted|null + * @throws Zend_Pdf_Exception + */ + public function extractFont($fontName) + { + $fontResourcesUnique = array(); + // require_once 'Zend/Pdf/Exception.php'; + foreach ($this->pages as $page) { + $pageResources = $page->extractResources(); + + if ($pageResources->Font === null) { + // Page doesn't contain have any font reference + continue; + } + + $fontResources = $pageResources->Font; + + foreach ($fontResources->getKeys() as $fontResourceName) { + $fontDictionary = $fontResources->$fontResourceName; + + if (! ($fontDictionary instanceof Zend_Pdf_Element_Reference || + $fontDictionary instanceof Zend_Pdf_Element_Object) ) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Font dictionary has to be an indirect object or object reference.'); + } + + $resourceId = spl_object_hash($fontDictionary->getObject()); + if (isset($fontResourcesUnique[$resourceId])) { + continue; + } else { + // Mark resource as processed + $fontResourcesUnique[$resourceId] = 1; + } + + if ($fontDictionary->BaseFont->value != $fontName) { + continue; + } + + try { + // Try to extract font + // require_once 'Zend/Pdf/Resource/Font/Extracted.php'; + return new Zend_Pdf_Resource_Font_Extracted($fontDictionary); + } catch (Zend_Pdf_Exception $e) { + if ($e->getMessage() != 'Unsupported font type.') { + throw $e; + } + // Continue searhing + } + } + } + + return null; + } + + /** + * Render the completed PDF to a string. + * If $newSegmentOnly is true and it's not a new document, + * then only appended part of PDF is returned. + * + * @param boolean $newSegmentOnly + * @param resource $outputStream + * @return string + * @throws Zend_Pdf_Exception + */ + public function render($newSegmentOnly = false, $outputStream = null) + { + if ($this->_isNewDocument) { + // Drop full document first time even $newSegmentOnly is set to true + $newSegmentOnly = false; + $this->_isNewDocument = false; + } + + // Save document properties if necessary + if ($this->properties != $this->_originalProperties) { + $docInfo = $this->_objFactory->newObject(new Zend_Pdf_Element_Dictionary()); + + foreach ($this->properties as $key => $value) { + switch ($key) { + case 'Trapped': + switch ($value) { + case true: + $docInfo->$key = new Zend_Pdf_Element_Name('True'); + break; + + case false: + $docInfo->$key = new Zend_Pdf_Element_Name('False'); + break; + + case null: + $docInfo->$key = new Zend_Pdf_Element_Name('Unknown'); + break; + + default: + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Wrong Trapped document property vale: \'' . $value . '\'. Only true, false and null values are allowed.'); + break; + } + + case 'CreationDate': + // break intentionally omitted + case 'ModDate': + $docInfo->$key = new Zend_Pdf_Element_String((string)$value); + break; + + case 'Title': + // break intentionally omitted + case 'Author': + // break intentionally omitted + case 'Subject': + // break intentionally omitted + case 'Keywords': + // break intentionally omitted + case 'Creator': + // break intentionally omitted + case 'Producer': + if (extension_loaded('mbstring') === true) { + $detected = mb_detect_encoding($value); + if ($detected !== 'ASCII') { + $value = "\xfe\xff" . mb_convert_encoding($value, 'UTF-16', $detected); + } + } + $docInfo->$key = new Zend_Pdf_Element_String((string)$value); + break; + + default: + // Set property using PDF type based on PHP type + $docInfo->$key = Zend_Pdf_Element::phpToPdf($value); + break; + } + } + + $this->_trailer->Info = $docInfo; + } + + $this->_dumpPages(); + $this->_dumpNamedDestinations(); + $this->_dumpOutlines(); + + // Check, that PDF file was modified + // File is always modified by _dumpPages() now, but future implementations may eliminate this. + if (!$this->_objFactory->isModified()) { + if ($newSegmentOnly) { + // Do nothing, return + return ''; + } + + if ($outputStream === null) { + return $this->_trailer->getPDFString(); + } else { + $pdfData = $this->_trailer->getPDFString(); + while ( strlen($pdfData) > 0 && ($byteCount = fwrite($outputStream, $pdfData)) != false ) { + $pdfData = substr($pdfData, $byteCount); + } + + return ''; + } + } + + // offset (from a start of PDF file) of new PDF file segment + $offset = $this->_trailer->getPDFLength(); + // Last Object number in a list of free objects + $lastFreeObject = $this->_trailer->getLastFreeObject(); + + // Array of cross-reference table subsections + $xrefTable = array(); + // Object numbers of first objects in each subsection + $xrefSectionStartNums = array(); + + // Last cross-reference table subsection + $xrefSection = array(); + // Dummy initialization of the first element (specail case - header of linked list of free objects). + $xrefSection[] = 0; + $xrefSectionStartNums[] = 0; + // Object number of last processed PDF object. + // Used to manage cross-reference subsections. + // Initialized by zero (specail case - header of linked list of free objects). + $lastObjNum = 0; + + if ($outputStream !== null) { + if (!$newSegmentOnly) { + $pdfData = $this->_trailer->getPDFString(); + while ( strlen($pdfData) > 0 && ($byteCount = fwrite($outputStream, $pdfData)) != false ) { + $pdfData = substr($pdfData, $byteCount); + } + } + } else { + $pdfSegmentBlocks = ($newSegmentOnly) ? array() : array($this->_trailer->getPDFString()); + } + + // Iterate objects to create new reference table + foreach ($this->_objFactory->listModifiedObjects() as $updateInfo) { + $objNum = $updateInfo->getObjNum(); + + if ($objNum - $lastObjNum != 1) { + // Save cross-reference table subsection and start new one + $xrefTable[] = $xrefSection; + $xrefSection = array(); + $xrefSectionStartNums[] = $objNum; + } + + if ($updateInfo->isFree()) { + // Free object cross-reference table entry + $xrefSection[] = sprintf("%010d %05d f \n", $lastFreeObject, $updateInfo->getGenNum()); + $lastFreeObject = $objNum; + } else { + // In-use object cross-reference table entry + $xrefSection[] = sprintf("%010d %05d n \n", $offset, $updateInfo->getGenNum()); + + $pdfBlock = $updateInfo->getObjectDump(); + $offset += strlen($pdfBlock); + + if ($outputStream === null) { + $pdfSegmentBlocks[] = $pdfBlock; + } else { + while ( strlen($pdfBlock) > 0 && ($byteCount = fwrite($outputStream, $pdfBlock)) != false ) { + $pdfBlock = substr($pdfBlock, $byteCount); + } + } + } + $lastObjNum = $objNum; + } + // Save last cross-reference table subsection + $xrefTable[] = $xrefSection; + + // Modify first entry (specail case - header of linked list of free objects). + $xrefTable[0][0] = sprintf("%010d 65535 f \n", $lastFreeObject); + + $xrefTableStr = "xref\n"; + foreach ($xrefTable as $sectId => $xrefSection) { + $xrefTableStr .= sprintf("%d %d \n", $xrefSectionStartNums[$sectId], count($xrefSection)); + foreach ($xrefSection as $xrefTableEntry) { + $xrefTableStr .= $xrefTableEntry; + } + } + + $this->_trailer->Size->value = $this->_objFactory->getObjectCount(); + + $pdfBlock = $xrefTableStr + . $this->_trailer->toString() + . "startxref\n" . $offset . "\n" + . "%%EOF\n"; + + $this->_objFactory->cleanEnumerationShiftCache(); + + if ($outputStream === null) { + $pdfSegmentBlocks[] = $pdfBlock; + + return implode('', $pdfSegmentBlocks); + } else { + while ( strlen($pdfBlock) > 0 && ($byteCount = fwrite($outputStream, $pdfBlock)) != false ) { + $pdfBlock = substr($pdfBlock, $byteCount); + } + + return ''; + } + } + + + /** + * Set the document-level JavaScript + * + * @param string $javascript + */ + public function setJavaScript($javascript) + { + $this->_javaScript = $javascript; + } + + + /** + * Convert date to PDF format (it's close to ASN.1 (Abstract Syntax Notation + * One) defined in ISO/IEC 8824). + * + * @todo This really isn't the best location for this method. It should + * probably actually exist as Zend_Pdf_Element_Date or something like that. + * + * @todo Address the following E_STRICT issue: + * PHP Strict Standards: date(): It is not safe to rely on the system's + * timezone settings. Please use the date.timezone setting, the TZ + * environment variable or the date_default_timezone_set() function. In + * case you used any of those methods and you are still getting this + * warning, you most likely misspelled the timezone identifier. + * + * @param integer $timestamp (optional) If omitted, uses the current time. + * @return string + */ + public static function pdfDate($timestamp = null) + { + if ($timestamp === null) { + $date = date('\D\:YmdHisO'); + } else { + $date = date('\D\:YmdHisO', $timestamp); + } + return substr_replace($date, '\'', -2, 0) . '\''; + } + +} diff --git a/library/Zend/Pdf/Action.php b/library/Zend/Pdf/Action.php new file mode 100644 index 0000000..e005261 --- /dev/null +++ b/library/Zend/Pdf/Action.php @@ -0,0 +1,404 @@ +getType() != Zend_Pdf_Element::TYPE_DICTIONARY) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('$dictionary mast be a direct or an indirect dictionary object.'); + } + + $this->_actionDictionary = $dictionary; + + if ($dictionary->Next !== null) { + if ($dictionary->Next instanceof Zend_Pdf_Element_Dictionary) { + // Check if dictionary object is not already processed + if (!$processedActions->contains($dictionary->Next)) { + $processedActions->attach($dictionary->Next); + $this->next[] = Zend_Pdf_Action::load($dictionary->Next, $processedActions); + } + } else if ($dictionary->Next instanceof Zend_Pdf_Element_Array) { + foreach ($dictionary->Next->items as $chainedActionDictionary) { + // Check if dictionary object is not already processed + if (!$processedActions->contains($chainedActionDictionary)) { + $processedActions->attach($chainedActionDictionary); + $this->next[] = Zend_Pdf_Action::load($chainedActionDictionary, $processedActions); + } + } + } else { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('PDF Action dictionary Next entry must be a dictionary or an array.'); + } + } + + $this->_originalNextList = $this->next; + } + + /** + * Load PDF action object using specified dictionary + * + * @internal + * @param Zend_Pdf_Element $dictionary (It's actually Dictionary or Dictionary Object or Reference to a Dictionary Object) + * @param SplObjectStorage $processedActions list of already processed action dictionaries, used to avoid cyclic references + * @return Zend_Pdf_Action + * @throws Zend_Pdf_Exception + */ + public static function load(Zend_Pdf_Element $dictionary, SplObjectStorage $processedActions = null) + { + if ($processedActions === null) { + $processedActions = new SplObjectStorage(); + } + + // require_once 'Zend/Pdf/Element.php'; + if ($dictionary->getType() != Zend_Pdf_Element::TYPE_DICTIONARY) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('$dictionary mast be a direct or an indirect dictionary object.'); + } + if (isset($dictionary->Type) && $dictionary->Type->value != 'Action') { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Action dictionary Type entry must be set to \'Action\'.'); + } + + if ($dictionary->S === null) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Action dictionary must contain S entry'); + } + + switch ($dictionary->S->value) { + case 'GoTo': + // require_once 'Zend/Pdf/Action/GoTo.php'; + return new Zend_Pdf_Action_GoTo($dictionary, $processedActions); + break; + + case 'GoToR': + // require_once 'Zend/Pdf/Action/GoToR.php'; + return new Zend_Pdf_Action_GoToR($dictionary, $processedActions); + break; + + case 'GoToE': + // require_once 'Zend/Pdf/Action/GoToE.php'; + return new Zend_Pdf_Action_GoToE($dictionary, $processedActions); + break; + + case 'Launch': + // require_once 'Zend/Pdf/Action/Launch.php'; + return new Zend_Pdf_Action_Launch($dictionary, $processedActions); + break; + + case 'Thread': + // require_once 'Zend/Pdf/Action/Thread.php'; + return new Zend_Pdf_Action_Thread($dictionary, $processedActions); + break; + + case 'URI': + // require_once 'Zend/Pdf/Action/URI.php'; + return new Zend_Pdf_Action_URI($dictionary, $processedActions); + break; + + case 'Sound': + // require_once 'Zend/Pdf/Action/Sound.php'; + return new Zend_Pdf_Action_Sound($dictionary, $processedActions); + break; + + case 'Movie': + // require_once 'Zend/Pdf/Action/Movie.php'; + return new Zend_Pdf_Action_Movie($dictionary, $processedActions); + break; + + case 'Hide': + // require_once 'Zend/Pdf/Action/Hide.php'; + return new Zend_Pdf_Action_Hide($dictionary, $processedActions); + break; + + case 'Named': + // require_once 'Zend/Pdf/Action/Named.php'; + return new Zend_Pdf_Action_Named($dictionary, $processedActions); + break; + + case 'SubmitForm': + // require_once 'Zend/Pdf/Action/SubmitForm.php'; + return new Zend_Pdf_Action_SubmitForm($dictionary, $processedActions); + break; + + case 'ResetForm': + // require_once 'Zend/Pdf/Action/ResetForm.php'; + return new Zend_Pdf_Action_ResetForm($dictionary, $processedActions); + break; + + case 'ImportData': + // require_once 'Zend/Pdf/Action/ImportData.php'; + return new Zend_Pdf_Action_ImportData($dictionary, $processedActions); + break; + + case 'JavaScript': + // require_once 'Zend/Pdf/Action/JavaScript.php'; + return new Zend_Pdf_Action_JavaScript($dictionary, $processedActions); + break; + + case 'SetOCGState': + // require_once 'Zend/Pdf/Action/SetOCGState.php'; + return new Zend_Pdf_Action_SetOCGState($dictionary, $processedActions); + break; + + case 'Rendition': + // require_once 'Zend/Pdf/Action/Rendition.php'; + return new Zend_Pdf_Action_Rendition($dictionary, $processedActions); + break; + + case 'Trans': + // require_once 'Zend/Pdf/Action/Trans.php'; + return new Zend_Pdf_Action_Trans($dictionary, $processedActions); + break; + + case 'GoTo3DView': + // require_once 'Zend/Pdf/Action/GoTo3DView.php'; + return new Zend_Pdf_Action_GoTo3DView($dictionary, $processedActions); + break; + + default: + // require_once 'Zend/Pdf/Action/Unknown.php'; + return new Zend_Pdf_Action_Unknown($dictionary, $processedActions); + break; + } + } + + /** + * Get resource + * + * @internal + * @return Zend_Pdf_Element + */ + public function getResource() + { + return $this->_actionDictionary; + } + + /** + * Dump Action and its child actions into PDF structures + * + * Returns dictionary indirect object or reference + * + * @internal + * @param Zend_Pdf_ElementFactory $factory Object factory for newly created indirect objects + * @param SplObjectStorage $processedActions list of already processed actions (used to prevent infinity loop caused by cyclic references) + * @return Zend_Pdf_Element_Object|Zend_Pdf_Element_Reference Dictionary indirect object + */ + public function dumpAction(Zend_Pdf_ElementFactory_Interface $factory, SplObjectStorage $processedActions = null) + { + if ($processedActions === null) { + $processedActions = new SplObjectStorage(); + } + if ($processedActions->contains($this)) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Action chain cyclyc reference is detected.'); + } + $processedActions->attach($this); + + $childListUpdated = false; + if (count($this->_originalNextList) != count($this->next)) { + // If original and current children arrays have different size then children list was updated + $childListUpdated = true; + } else if ( !(array_keys($this->_originalNextList) === array_keys($this->next)) ) { + // If original and current children arrays have different keys (with a glance to an order) then children list was updated + $childListUpdated = true; + } else { + foreach ($this->next as $key => $childAction) { + if ($this->_originalNextList[$key] !== $childAction) { + $childListUpdated = true; + break; + } + } + } + + if ($childListUpdated) { + $this->_actionDictionary->touch(); + switch (count($this->next)) { + case 0: + $this->_actionDictionary->Next = null; + break; + + case 1: + $child = reset($this->next); + $this->_actionDictionary->Next = $child->dumpAction($factory, $processedActions); + break; + + default: + // require_once 'Zend/Pdf/Element/Array.php'; + $pdfChildArray = new Zend_Pdf_Element_Array(); + foreach ($this->next as $child) { + + $pdfChildArray->items[] = $child->dumpAction($factory, $processedActions); + } + $this->_actionDictionary->Next = $pdfChildArray; + break; + } + } else { + foreach ($this->next as $child) { + $child->dumpAction($factory, $processedActions); + } + } + + if ($this->_actionDictionary instanceof Zend_Pdf_Element_Dictionary) { + // It's a newly created action. Register it within object factory and return indirect object + return $factory->newObject($this->_actionDictionary); + } else { + // It's a loaded object + return $this->_actionDictionary; + } + } + + + //////////////////////////////////////////////////////////////////////// + // RecursiveIterator interface methods + ////////////// + + /** + * Returns current child action. + * + * @return Zend_Pdf_Action + */ + public function current() + { + return current($this->next); + } + + /** + * Returns current iterator key + * + * @return integer + */ + public function key() + { + return key($this->next); + } + + /** + * Go to next child + */ + public function next() + { + return next($this->next); + } + + /** + * Rewind children + */ + public function rewind() + { + return reset($this->next); + } + + /** + * Check if current position is valid + * + * @return boolean + */ + public function valid() + { + return current($this->next) !== false; + } + + /** + * Returns the child action. + * + * @return Zend_Pdf_Action|null + */ + public function getChildren() + { + return current($this->next); + } + + /** + * Implements RecursiveIterator interface. + * + * @return bool whether container has any pages + */ + public function hasChildren() + { + return count($this->next) > 0; + } + + + //////////////////////////////////////////////////////////////////////// + // Countable interface methods + ////////////// + + /** + * count() + * + * @return int + */ + public function count() + { + return count($this->childOutlines); + } +} diff --git a/library/Zend/Pdf/Action/GoTo.php b/library/Zend/Pdf/Action/GoTo.php new file mode 100644 index 0000000..09040b2 --- /dev/null +++ b/library/Zend/Pdf/Action/GoTo.php @@ -0,0 +1,116 @@ +_destination = Zend_Pdf_Destination::load($dictionary->D); + } + + /** + * Create new Zend_Pdf_Action_GoTo object using specified destination + * + * @param Zend_Pdf_Destination|string $destination + * @return Zend_Pdf_Action_GoTo + */ + public static function create($destination) + { + if (is_string($destination)) { + // require_once 'Zend/Pdf/Destination/Named.php'; + $destination = Zend_Pdf_Destination_Named::create($destination); + } + + if (!$destination instanceof Zend_Pdf_Destination) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('$destination parameter must be a Zend_Pdf_Destination object or string.'); + } + + $dictionary = new Zend_Pdf_Element_Dictionary(); + $dictionary->Type = new Zend_Pdf_Element_Name('Action'); + $dictionary->S = new Zend_Pdf_Element_Name('GoTo'); + $dictionary->Next = null; + $dictionary->D = $destination->getResource(); + + return new Zend_Pdf_Action_GoTo($dictionary, new SplObjectStorage()); + } + + /** + * Set goto action destination + * + * @param Zend_Pdf_Destination|string $destination + * @return Zend_Pdf_Action_GoTo + */ + public function setDestination(Zend_Pdf_Destination $destination) + { + $this->_destination = $destination; + + $this->_actionDictionary->touch(); + $this->_actionDictionary->D = $destination->getResource(); + + return $this; + } + + /** + * Get goto action destination + * + * @return Zend_Pdf_Destination + */ + public function getDestination() + { + return $this->_destination; + } +} diff --git a/library/Zend/Pdf/Action/GoTo3DView.php b/library/Zend/Pdf/Action/GoTo3DView.php new file mode 100644 index 0000000..c71e6d6 --- /dev/null +++ b/library/Zend/Pdf/Action/GoTo3DView.php @@ -0,0 +1,39 @@ +URI === null) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('URI action dictionary entry is required'); + } + } + + /** + * Validate URI + * + * @param string $uri + * @return true + * @throws Zend_Pdf_Exception + */ + protected static function _validateUri($uri) + { + $scheme = parse_url((string)$uri, PHP_URL_SCHEME); + if ($scheme === false || $scheme === null) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Invalid URI'); + } + } + + /** + * Create new Zend_Pdf_Action_URI object using specified uri + * + * @param string $uri The URI to resolve, encoded in 7-bit ASCII + * @param boolean $isMap A flag specifying whether to track the mouse position when the URI is resolved + * @return Zend_Pdf_Action_URI + */ + public static function create($uri, $isMap = false) + { + self::_validateUri($uri); + + $dictionary = new Zend_Pdf_Element_Dictionary(); + $dictionary->Type = new Zend_Pdf_Element_Name('Action'); + $dictionary->S = new Zend_Pdf_Element_Name('URI'); + $dictionary->Next = null; + $dictionary->URI = new Zend_Pdf_Element_String($uri); + if ($isMap) { + $dictionary->IsMap = new Zend_Pdf_Element_Boolean(true); + } + + return new Zend_Pdf_Action_URI($dictionary, new SplObjectStorage()); + } + + /** + * Set URI to resolve + * + * @param string $uri The uri to resolve, encoded in 7-bit ASCII. + * @return Zend_Pdf_Action_URI + */ + public function setUri($uri) + { + $this->_validateUri($uri); + + $this->_actionDictionary->touch(); + $this->_actionDictionary->URI = new Zend_Pdf_Element_String($uri); + + return $this; + } + + /** + * Get URI to resolve + * + * @return string + */ + public function getUri() + { + return $this->_actionDictionary->URI->value; + } + + /** + * Set IsMap property + * + * If the IsMap flag is true and the user has triggered the URI action by clicking + * an annotation, the coordinates of the mouse position at the time the action is + * performed should be transformed from device space to user space and then offset + * relative to the upper-left corner of the annotation rectangle. + * + * @param boolean $isMap A flag specifying whether to track the mouse position when the URI is resolved + * @return Zend_Pdf_Action_URI + */ + public function setIsMap($isMap) + { + $this->_actionDictionary->touch(); + + if ($isMap) { + $this->_actionDictionary->IsMap = new Zend_Pdf_Element_Boolean(true); + } else { + $this->_actionDictionary->IsMap = null; + } + + return $this; + } + + /** + * Get IsMap property + * + * If the IsMap flag is true and the user has triggered the URI action by clicking + * an annotation, the coordinates of the mouse position at the time the action is + * performed should be transformed from device space to user space and then offset + * relative to the upper-left corner of the annotation rectangle. + * + * @return boolean + */ + public function getIsMap() + { + return $this->_actionDictionary->IsMap !== null && + $this->_actionDictionary->IsMap->value; + } +} diff --git a/library/Zend/Pdf/Action/Unknown.php b/library/Zend/Pdf/Action/Unknown.php new file mode 100644 index 0000000..f7ff685 --- /dev/null +++ b/library/Zend/Pdf/Action/Unknown.php @@ -0,0 +1,38 @@ +_annotationDictionary; + } + + + /** + * Set bottom edge of the annotation rectangle. + * + * @param float $bottom + * @return Zend_Pdf_Annotation + */ + public function setBottom($bottom) { + $this->_annotationDictionary->Rect->items[1]->touch(); + $this->_annotationDictionary->Rect->items[1]->value = $bottom; + + return $this; + } + + /** + * Get bottom edge of the annotation rectangle. + * + * @return float + */ + public function getBottom() { + return $this->_annotationDictionary->Rect->items[1]->value; + } + + /** + * Set top edge of the annotation rectangle. + * + * @param float $top + * @return Zend_Pdf_Annotation + */ + public function setTop($top) { + $this->_annotationDictionary->Rect->items[3]->touch(); + $this->_annotationDictionary->Rect->items[3]->value = $top; + + return $this; + } + + /** + * Get top edge of the annotation rectangle. + * + * @return float + */ + public function getTop() { + return $this->_annotationDictionary->Rect->items[3]->value; + } + + /** + * Set right edge of the annotation rectangle. + * + * @param float $right + * @return Zend_Pdf_Annotation + */ + public function setRight($right) { + $this->_annotationDictionary->Rect->items[2]->touch(); + $this->_annotationDictionary->Rect->items[2]->value = $right; + + return $this; + } + + /** + * Get right edge of the annotation rectangle. + * + * @return float + */ + public function getRight() { + return $this->_annotationDictionary->Rect->items[2]->value; + } + + /** + * Set left edge of the annotation rectangle. + * + * @param float $left + * @return Zend_Pdf_Annotation + */ + public function setLeft($left) { + $this->_annotationDictionary->Rect->items[0]->touch(); + $this->_annotationDictionary->Rect->items[0]->value = $left; + + return $this; + } + + /** + * Get left edge of the annotation rectangle. + * + * @return float + */ + public function getLeft() { + return $this->_annotationDictionary->Rect->items[0]->value; + } + + /** + * Return text to be displayed for the annotation or, if this type of annotation + * does not display text, an alternate description of the annotation’s contents + * in human-readable form. + * + * @return string + */ + public function getText() { + if ($this->_annotationDictionary->Contents === null) { + return ''; + } + + return $this->_annotationDictionary->Contents->value; + } + + /** + * Set text to be displayed for the annotation or, if this type of annotation + * does not display text, an alternate description of the annotation’s contents + * in human-readable form. + * + * @param string $text + * @return Zend_Pdf_Annotation + */ + public function setText($text) { + // require_once 'Zend/Pdf/Element/String.php'; + + if ($this->_annotationDictionary->Contents === null) { + $this->_annotationDictionary->touch(); + $this->_annotationDictionary->Contents = new Zend_Pdf_Element_String($text); + } else { + $this->_annotationDictionary->Contents->touch(); + $this->_annotationDictionary->Contents->value = new Zend_Pdf_Element_String($text); + } + + return $this; + } + + /** + * Annotation object constructor + * + * @throws Zend_Pdf_Exception + */ + public function __construct(Zend_Pdf_Element $annotationDictionary) + { + if ($annotationDictionary->getType() != Zend_Pdf_Element::TYPE_DICTIONARY) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Annotation dictionary resource has to be a dictionary.'); + } + + $this->_annotationDictionary = $annotationDictionary; + + if ($this->_annotationDictionary->Type !== null && + $this->_annotationDictionary->Type->value != 'Annot') { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Wrong resource type. \'Annot\' expected.'); + } + + if ($this->_annotationDictionary->Rect === null) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('\'Rect\' dictionary entry is required.'); + } + + if (count($this->_annotationDictionary->Rect->items) != 4 || + $this->_annotationDictionary->Rect->items[0]->getType() != Zend_Pdf_Element::TYPE_NUMERIC || + $this->_annotationDictionary->Rect->items[1]->getType() != Zend_Pdf_Element::TYPE_NUMERIC || + $this->_annotationDictionary->Rect->items[2]->getType() != Zend_Pdf_Element::TYPE_NUMERIC || + $this->_annotationDictionary->Rect->items[3]->getType() != Zend_Pdf_Element::TYPE_NUMERIC ) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('\'Rect\' dictionary entry must be an array of four numeric elements.'); + } + } + + /** + * Load Annotation object from a specified resource + * + * @internal + * @param Zend_Pdf_Element $resource + * @return Zend_Pdf_Annotation + */ + public static function load(Zend_Pdf_Element $resource) + { + /** @todo implementation */ + } +} diff --git a/library/Zend/Pdf/Annotation/FileAttachment.php b/library/Zend/Pdf/Annotation/FileAttachment.php new file mode 100644 index 0000000..1f3c919 --- /dev/null +++ b/library/Zend/Pdf/Annotation/FileAttachment.php @@ -0,0 +1,101 @@ +getType() != Zend_Pdf_Element::TYPE_DICTIONARY) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Annotation dictionary resource has to be a dictionary.'); + } + + if ($annotationDictionary->Subtype === null || + $annotationDictionary->Subtype->getType() != Zend_Pdf_Element::TYPE_NAME || + $annotationDictionary->Subtype->value != 'FileAttachment') { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Subtype => FileAttachment entry is requires'); + } + + parent::__construct($annotationDictionary); + } + + /** + * Create link annotation object + * + * @param float $x1 + * @param float $y1 + * @param float $x2 + * @param float $y2 + * @param string $fileSpecification + * @return Zend_Pdf_Annotation_FileAttachment + */ + public static function create($x1, $y1, $x2, $y2, $fileSpecification) + { + $annotationDictionary = new Zend_Pdf_Element_Dictionary(); + + $annotationDictionary->Type = new Zend_Pdf_Element_Name('Annot'); + $annotationDictionary->Subtype = new Zend_Pdf_Element_Name('FileAttachment'); + + $rectangle = new Zend_Pdf_Element_Array(); + $rectangle->items[] = new Zend_Pdf_Element_Numeric($x1); + $rectangle->items[] = new Zend_Pdf_Element_Numeric($y1); + $rectangle->items[] = new Zend_Pdf_Element_Numeric($x2); + $rectangle->items[] = new Zend_Pdf_Element_Numeric($y2); + $annotationDictionary->Rect = $rectangle; + + $fsDictionary = new Zend_Pdf_Element_Dictionary(); + $fsDictionary->Type = new Zend_Pdf_Element_Name('Filespec'); + $fsDictionary->F = new Zend_Pdf_Element_String($fileSpecification); + + $annotationDictionary->FS = $fsDictionary; + + + return new Zend_Pdf_Annotation_FileAttachment($annotationDictionary); + } +} diff --git a/library/Zend/Pdf/Annotation/Link.php b/library/Zend/Pdf/Annotation/Link.php new file mode 100644 index 0000000..4a76ba9 --- /dev/null +++ b/library/Zend/Pdf/Annotation/Link.php @@ -0,0 +1,162 @@ +getType() != Zend_Pdf_Element::TYPE_DICTIONARY) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Annotation dictionary resource has to be a dictionary.'); + } + + if ($annotationDictionary->Subtype === null || + $annotationDictionary->Subtype->getType() != Zend_Pdf_Element::TYPE_NAME || + $annotationDictionary->Subtype->value != 'Link') { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Subtype => Link entry is requires'); + } + + parent::__construct($annotationDictionary); + } + + /** + * Create link annotation object + * + * @param float $x1 + * @param float $y1 + * @param float $x2 + * @param float $y2 + * @param Zend_Pdf_Target|string $target + * @return Zend_Pdf_Annotation_Link + */ + public static function create($x1, $y1, $x2, $y2, $target) + { + if (is_string($target)) { + // require_once 'Zend/Pdf/Destination/Named.php'; + $destination = Zend_Pdf_Destination_Named::create($target); + } + if (!$target instanceof Zend_Pdf_Target) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('$target parameter must be a Zend_Pdf_Target object or a string.'); + } + + $annotationDictionary = new Zend_Pdf_Element_Dictionary(); + + $annotationDictionary->Type = new Zend_Pdf_Element_Name('Annot'); + $annotationDictionary->Subtype = new Zend_Pdf_Element_Name('Link'); + + $rectangle = new Zend_Pdf_Element_Array(); + $rectangle->items[] = new Zend_Pdf_Element_Numeric($x1); + $rectangle->items[] = new Zend_Pdf_Element_Numeric($y1); + $rectangle->items[] = new Zend_Pdf_Element_Numeric($x2); + $rectangle->items[] = new Zend_Pdf_Element_Numeric($y2); + $annotationDictionary->Rect = $rectangle; + + if ($target instanceof Zend_Pdf_Destination) { + $annotationDictionary->Dest = $target->getResource(); + } else { + $annotationDictionary->A = $target->getResource(); + } + + return new Zend_Pdf_Annotation_Link($annotationDictionary); + } + + /** + * Set link annotation destination + * + * @param Zend_Pdf_Target|string $target + * @return Zend_Pdf_Annotation_Link + */ + public function setDestination($target) + { + if (is_string($target)) { + // require_once 'Zend/Pdf/Destination/Named.php'; + $destination = Zend_Pdf_Destination_Named::create($target); + } + if (!$target instanceof Zend_Pdf_Target) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('$target parameter must be a Zend_Pdf_Target object or a string.'); + } + + $this->_annotationDictionary->touch(); + $this->_annotationDictionary->Dest = $destination->getResource(); + if ($target instanceof Zend_Pdf_Destination) { + $this->_annotationDictionary->Dest = $target->getResource(); + $this->_annotationDictionary->A = null; + } else { + $this->_annotationDictionary->Dest = null; + $this->_annotationDictionary->A = $target->getResource(); + } + + return $this; + } + + /** + * Get link annotation destination + * + * @return Zend_Pdf_Target|null + */ + public function getDestination() + { + if ($this->_annotationDictionary->Dest === null && + $this->_annotationDictionary->A === null) { + return null; + } + + if ($this->_annotationDictionary->Dest !== null) { + // require_once 'Zend/Pdf/Destination.php'; + return Zend_Pdf_Destination::load($this->_annotationDictionary->Dest); + } else { + // require_once 'Zend/Pdf/Action.php'; + return Zend_Pdf_Action::load($this->_annotationDictionary->A); + } + } +} diff --git a/library/Zend/Pdf/Annotation/Markup.php b/library/Zend/Pdf/Annotation/Markup.php new file mode 100644 index 0000000..18f83d2 --- /dev/null +++ b/library/Zend/Pdf/Annotation/Markup.php @@ -0,0 +1,142 @@ +getType() != Zend_Pdf_Element::TYPE_DICTIONARY) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Annotation dictionary resource has to be a dictionary.'); + } + + if ($annotationDictionary->Subtype === null || + $annotationDictionary->Subtype->getType() != Zend_Pdf_Element::TYPE_NAME || + !in_array( $annotationDictionary->Subtype->value, + array(self::SUBTYPE_HIGHLIGHT, + self::SUBTYPE_UNDERLINE, + self::SUBTYPE_SQUIGGLY, + self::SUBTYPE_STRIKEOUT) )) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Subtype => Markup entry is omitted or has wrong value.'); + } + + parent::__construct($annotationDictionary); + } + + /** + * Create markup annotation object + * + * Text markup annotations appear as highlights, underlines, strikeouts or + * jagged ("squiggly") underlines in the text of a document. When opened, + * they display a pop-up window containing the text of the associated note. + * + * $subType parameter may contain + * Zend_Pdf_Annotation_Markup::SUBTYPE_HIGHLIGHT + * Zend_Pdf_Annotation_Markup::SUBTYPE_UNDERLINE + * Zend_Pdf_Annotation_Markup::SUBTYPE_SQUIGGLY + * Zend_Pdf_Annotation_Markup::SUBTYPE_STRIKEOUT + * for for a highlight, underline, squiggly-underline, or strikeout annotation, + * respectively. + * + * $quadPoints is an array of 8xN numbers specifying the coordinates of + * N quadrilaterals default user space. Each quadrilateral encompasses a word or + * group of contiguous words in the text underlying the annotation. + * The coordinates for each quadrilateral are given in the order + * x1 y1 x2 y2 x3 y3 x4 y4 + * specifying the quadrilateral’s four vertices in counterclockwise order + * starting from left bottom corner. + * The text is oriented with respect to the edge connecting points + * (x1, y1) and (x2, y2). + * + * @param float $x1 + * @param float $y1 + * @param float $x2 + * @param float $y2 + * @param string $text + * @param string $subType + * @param array $quadPoints [x1 y1 x2 y2 x3 y3 x4 y4] + * @return Zend_Pdf_Annotation_Markup + * @throws Zend_Pdf_Exception + */ + public static function create($x1, $y1, $x2, $y2, $text, $subType, $quadPoints) + { + $annotationDictionary = new Zend_Pdf_Element_Dictionary(); + + $annotationDictionary->Type = new Zend_Pdf_Element_Name('Annot'); + $annotationDictionary->Subtype = new Zend_Pdf_Element_Name($subType); + + $rectangle = new Zend_Pdf_Element_Array(); + $rectangle->items[] = new Zend_Pdf_Element_Numeric($x1); + $rectangle->items[] = new Zend_Pdf_Element_Numeric($y1); + $rectangle->items[] = new Zend_Pdf_Element_Numeric($x2); + $rectangle->items[] = new Zend_Pdf_Element_Numeric($y2); + $annotationDictionary->Rect = $rectangle; + + $annotationDictionary->Contents = new Zend_Pdf_Element_String($text); + + if (!is_array($quadPoints) || count($quadPoints) == 0 || count($quadPoints) % 8 != 0) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('$quadPoints parameter must be an array of 8xN numbers'); + } + $points = new Zend_Pdf_Element_Array(); + foreach ($quadPoints as $quadPoint) { + $points->items[] = new Zend_Pdf_Element_Numeric($quadPoint); + } + $annotationDictionary->QuadPoints = $points; + + return new Zend_Pdf_Annotation_Markup($annotationDictionary); + } +} diff --git a/library/Zend/Pdf/Annotation/Text.php b/library/Zend/Pdf/Annotation/Text.php new file mode 100644 index 0000000..4b802a9 --- /dev/null +++ b/library/Zend/Pdf/Annotation/Text.php @@ -0,0 +1,95 @@ +getType() != Zend_Pdf_Element::TYPE_DICTIONARY) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Annotation dictionary resource has to be a dictionary.'); + } + + if ($annotationDictionary->Subtype === null || + $annotationDictionary->Subtype->getType() != Zend_Pdf_Element::TYPE_NAME || + $annotationDictionary->Subtype->value != 'Text') { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Subtype => Text entry is requires'); + } + + parent::__construct($annotationDictionary); + } + + /** + * Create link annotation object + * + * @param float $x1 + * @param float $y1 + * @param float $x2 + * @param float $y2 + * @param string $text + * @return Zend_Pdf_Annotation_Text + */ + public static function create($x1, $y1, $x2, $y2, $text) + { + $annotationDictionary = new Zend_Pdf_Element_Dictionary(); + + $annotationDictionary->Type = new Zend_Pdf_Element_Name('Annot'); + $annotationDictionary->Subtype = new Zend_Pdf_Element_Name('Text'); + + $rectangle = new Zend_Pdf_Element_Array(); + $rectangle->items[] = new Zend_Pdf_Element_Numeric($x1); + $rectangle->items[] = new Zend_Pdf_Element_Numeric($y1); + $rectangle->items[] = new Zend_Pdf_Element_Numeric($x2); + $rectangle->items[] = new Zend_Pdf_Element_Numeric($y2); + $annotationDictionary->Rect = $rectangle; + + $annotationDictionary->Contents = new Zend_Pdf_Element_String($text); + + return new Zend_Pdf_Annotation_Text($annotationDictionary); + } +} diff --git a/library/Zend/Pdf/Canvas.php b/library/Zend/Pdf/Canvas.php new file mode 100644 index 0000000..9acb3a5 --- /dev/null +++ b/library/Zend/Pdf/Canvas.php @@ -0,0 +1,182 @@ + array(), + 'XObject' => array(), + 'ExtGState' => array()); + + /** + * Object constructor + * + * @param float $width + * @param float $height + */ + public function __construct($width, $height) + { + $this->_width = $width; + $this->_height = $height; + } + + /** + * Add procedure set to the canvas description + * + * @param string $procSetName + */ + protected function _addProcSet($procSetName) + { + $this->_procset[$procSetName] = 1; + } + + /** + * Attach resource to the canvas + * + * Method returns a name of the resource which can be used + * as a resource reference within drawing instructions stream + * Allowed types: 'ExtGState', 'ColorSpace', 'Pattern', 'Shading', + * 'XObject', 'Font', 'Properties' + * + * @param string $type + * @param Zend_Pdf_Resource $resource + * @return string + */ + protected function _attachResource($type, Zend_Pdf_Resource $resource) + { + // Check, that resource is already attached to resource set. + $resObject = $resource->getResource(); + foreach ($this->_resources[$type] as $resName => $collectedResObject) { + if ($collectedResObject === $resObject) { + return $resName; + } + } + + $idCounter = 1; + do { + $newResName = $type[0] . $idCounter++; + } while (isset($this->_resources[$type][$newResName])); + + $this->_resources[$type][$newResName] = $resObject; + + return $newResName; + } + + /** + * Returns dictionaries of used resources. + * + * Used for canvas implementations interoperability + * + * Structure of the returned array: + * array( + * => array( + * => , + * => , + * => , + * ... + * ), + * => array( + * => , + * => , + * => , + * ... + * ), + * ... + * 'ProcSet' => array() + * ) + * + * where ProcSet array is a list of used procedure sets names (strings). + * Allowed procedure set names: 'PDF', 'Text', 'ImageB', 'ImageC', 'ImageI' + * + * @internal + * @return array + */ + public function getResources() + { + $this->_resources['ProcSet'] = array_keys($this->_procSet); + return $this->_resources; + } + + /** + * Get drawing instructions stream + * + * It has to be returned as a PDF stream object to make it reusable. + * + * @internal + * @returns Zend_Pdf_Resource_ContentStream + */ + public function getContents() + { + /** @todo implementation */ + } + + /** + * Return the height of this page in points. + * + * @return float + */ + public function getHeight() + { + return $this->_height; + } + + /** + * Return the width of this page in points. + * + * @return float + */ + public function getWidth() + { + return $this->_width; + } +} diff --git a/library/Zend/Pdf/Canvas/Abstract.php b/library/Zend/Pdf/Canvas/Abstract.php new file mode 100644 index 0000000..ec04fcb --- /dev/null +++ b/library/Zend/Pdf/Canvas/Abstract.php @@ -0,0 +1,1217 @@ +saveGS(); + + $this->translate($x1, $y1); + + if ($x2 === null) { + $with = $canvas->getWidth(); + } else { + $with = $x2 - $x1; + } + if ($y2 === null) { + $height = $canvas->getHeight(); + } else { + $height = $y2 - $y1; + } + + $this->clipRectangle(0, 0, $with, $height); + + if ($x2 !== null || $y2 !== null) { + // Drawn canvas has to be scaled. + if ($x2 !== null) { + $xScale = $with/$canvas->getWidth(); + } else { + $xScale = 1; + } + + if ($y2 !== null) { + $yScale = $height/$canvas->getHeight(); + } else { + $yScale = 1; + } + + $this->scale($xScale, $yScale); + } + + $contentsToDraw = $canvas->getContents(); + /** @todo implementation */ + + $this->restoreGS(); + + return $this; + } + + /** + * Set fill color. + * + * @param Zend_Pdf_Color $color + * @return Zend_Pdf_Canvas_Interface + */ + public function setFillColor(Zend_Pdf_Color $color) + { + $this->_addProcSet('PDF'); + $this->_contents .= $color->instructions(false); + + return $this; + } + + /** + * Set line color. + * + * @param Zend_Pdf_Color $color + * @return Zend_Pdf_Canvas_Interface + */ + public function setLineColor(Zend_Pdf_Color $color) + { + $this->_addProcSet('PDF'); + $this->_contents .= $color->instructions(true); + + return $this; + } + + /** + * Set line width. + * + * @param float $width + * @return Zend_Pdf_Canvas_Interface + */ + public function setLineWidth($width) + { + $this->_addProcSet('PDF'); + $widthObj = new Zend_Pdf_Element_Numeric($width); + $this->_contents .= $widthObj->toString() . " w\n"; + + return $this; + } + + /** + * Set line dashing pattern + * + * Pattern is an array of floats: array(on_length, off_length, on_length, off_length, ...) + * or Zend_Pdf_Page::LINE_DASHING_SOLID constant + * Phase is shift from the beginning of line. + * + * @param mixed $pattern + * @param array $phase + * @return Zend_Pdf_Canvas_Interface + */ + public function setLineDashingPattern($pattern, $phase = 0) + { + $this->_addProcSet('PDF'); + + // require_once 'Zend/Pdf/Page.php'; + if ($pattern === Zend_Pdf_Page::LINE_DASHING_SOLID) { + $pattern = array(); + $phase = 0; + } + + $dashPattern = new Zend_Pdf_Element_Array(); + $phaseEleemnt = new Zend_Pdf_Element_Numeric($phase); + + foreach ($pattern as $dashItem) { + $dashElement = new Zend_Pdf_Element_Numeric($dashItem); + $dashPattern->items[] = $dashElement; + } + + $this->_contents .= $dashPattern->toString() . ' ' + . $phaseEleemnt->toString() . " d\n"; + + return $this; + } + + /** + * Set current font. + * + * @param Zend_Pdf_Resource_Font $font + * @param float $fontSize + * @return Zend_Pdf_Canvas_Interface + */ + public function setFont(Zend_Pdf_Resource_Font $font, $fontSize) + { + $this->_addProcSet('Text'); + $fontName = $this->_attachResource('Font', $font); + + $this->_font = $font; + $this->_fontSize = $fontSize; + + $fontNameObj = new Zend_Pdf_Element_Name($fontName); + $fontSizeObj = new Zend_Pdf_Element_Numeric($fontSize); + $this->_contents .= $fontNameObj->toString() . ' ' . $fontSizeObj->toString() . " Tf\n"; + + return $this; + } + + /** + * Set the style to use for future drawing operations on this page + * + * @param Zend_Pdf_Style $style + * @return Zend_Pdf_Canvas_Interface + */ + public function setStyle(Zend_Pdf_Style $style) + { + $this->_addProcSet('Text'); + $this->_addProcSet('PDF'); + if ($style->getFont() !== null) { + $this->setFont($style->getFont(), $style->getFontSize()); + } + $this->_contents .= $style->instructions($this->_dictionary->Resources); + + $this->_style = $style; + + return $this; + } + + /** + * Get current font. + * + * @return Zend_Pdf_Resource_Font $font + */ + public function getFont() + { + return $this->_font; + } + + /** + * Get current font size + * + * @return float $fontSize + */ + public function getFontSize() + { + return $this->_fontSize; + } + + /** + * Return the style, applied to the page. + * + * @return Zend_Pdf_Style + */ + public function getStyle() + { + return $this->_style; + } + + /** + * Save the graphics state of this page. + * This takes a snapshot of the currently applied style, position, clipping area and + * any rotation/translation/scaling that has been applied. + * + * @todo check for the open paths + * @throws Zend_Pdf_Exception - if a save is performed with an open path + * @return Zend_Pdf_Canvas_Interface + */ + public function saveGS() + { + $this->_saveCount++; + + $this->_addProcSet('PDF'); + $this->_contents .= " q\n"; + + return $this; + } + + /** + * Restore the graphics state that was saved with the last call to saveGS(). + * + * @throws Zend_Pdf_Exception - if there is no previously saved state + * @return Zend_Pdf_Canvas_Interface + */ + public function restoreGS() + { + if ($this->_saveCount-- <= 0) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Restoring graphics state which is not saved'); + } + $this->_contents .= " Q\n"; + + return $this; + } + + /** + * Set the transparancy + * + * $alpha == 0 - transparent + * $alpha == 1 - opaque + * + * Transparency modes, supported by PDF: + * Normal (default), Multiply, Screen, Overlay, Darken, Lighten, ColorDodge, ColorBurn, HardLight, + * SoftLight, Difference, Exclusion + * + * @param float $alpha + * @param string $mode + * @return Zend_Pdf_Canvas_Interface + */ + public function setAlpha($alpha, $mode = 'Normal') + { + $this->_addProcSet('Text'); + $this->_addProcSet('PDF'); + + $graphicsState = new Zend_Pdf_Resource_GraphicsState(); + + $graphicsState->setAlpha($alpha, $mode); + $gStateName = $this->_attachResource('ExtGState', $graphicsState); + + $gStateNameObject = new Zend_Pdf_Element_Name($gStateName); + $this->_contents .= $gStateNameObject->toString() . " gs\n"; + + return $this; + } + + /** + * Intersect current clipping area with a circle. + * + * @param float $x + * @param float $y + * @param float $radius + * @param float $startAngle + * @param float $endAngle + * @return Zend_Pdf_Canvas_Interface + */ + public function clipCircle($x, $y, $radius, $startAngle = null, $endAngle = null) + { + $this->clipEllipse($x - $radius, $y - $radius, + $x + $radius, $y + $radius, + $startAngle, $endAngle); + + return $this; + } + + /** + * Intersect current clipping area with a polygon. + * + * Method signatures: + * drawEllipse($x1, $y1, $x2, $y2); + * drawEllipse($x1, $y1, $x2, $y2, $startAngle, $endAngle); + * + * @todo process special cases with $x2-$x1 == 0 or $y2-$y1 == 0 + * + * @param float $x1 + * @param float $y1 + * @param float $x2 + * @param float $y2 + * @param float $startAngle + * @param float $endAngle + * @return Zend_Pdf_Canvas_Interface + */ + public function clipEllipse($x1, $y1, $x2, $y2, $startAngle = null, $endAngle = null) + { + $this->_addProcSet('PDF'); + + if ($x2 < $x1) { + $temp = $x1; + $x1 = $x2; + $x2 = $temp; + } + if ($y2 < $y1) { + $temp = $y1; + $y1 = $y2; + $y2 = $temp; + } + + $x = ($x1 + $x2)/2.; + $y = ($y1 + $y2)/2.; + + $xC = new Zend_Pdf_Element_Numeric($x); + $yC = new Zend_Pdf_Element_Numeric($y); + + if ($startAngle !== null) { + if ($startAngle != 0) { $startAngle = fmod($startAngle, M_PI*2); } + if ($endAngle != 0) { $endAngle = fmod($endAngle, M_PI*2); } + + if ($startAngle > $endAngle) { + $endAngle += M_PI*2; + } + + $clipPath = $xC->toString() . ' ' . $yC->toString() . " m\n"; + $clipSectors = (int)ceil(($endAngle - $startAngle)/M_PI_4); + $clipRadius = max($x2 - $x1, $y2 - $y1); + + for($count = 0; $count <= $clipSectors; $count++) { + $pAngle = $startAngle + ($endAngle - $startAngle)*$count/(float)$clipSectors; + + $pX = new Zend_Pdf_Element_Numeric($x + cos($pAngle)*$clipRadius); + $pY = new Zend_Pdf_Element_Numeric($y + sin($pAngle)*$clipRadius); + $clipPath .= $pX->toString() . ' ' . $pY->toString() . " l\n"; + } + + $this->_contents .= $clipPath . "h\nW\nn\n"; + } + + $xLeft = new Zend_Pdf_Element_Numeric($x1); + $xRight = new Zend_Pdf_Element_Numeric($x2); + $yUp = new Zend_Pdf_Element_Numeric($y2); + $yDown = new Zend_Pdf_Element_Numeric($y1); + + $xDelta = 2*(M_SQRT2 - 1)*($x2 - $x1)/3.; + $yDelta = 2*(M_SQRT2 - 1)*($y2 - $y1)/3.; + $xr = new Zend_Pdf_Element_Numeric($x + $xDelta); + $xl = new Zend_Pdf_Element_Numeric($x - $xDelta); + $yu = new Zend_Pdf_Element_Numeric($y + $yDelta); + $yd = new Zend_Pdf_Element_Numeric($y - $yDelta); + + $this->_contents .= $xC->toString() . ' ' . $yUp->toString() . " m\n" + . $xr->toString() . ' ' . $yUp->toString() . ' ' + . $xRight->toString() . ' ' . $yu->toString() . ' ' + . $xRight->toString() . ' ' . $yC->toString() . " c\n" + . $xRight->toString() . ' ' . $yd->toString() . ' ' + . $xr->toString() . ' ' . $yDown->toString() . ' ' + . $xC->toString() . ' ' . $yDown->toString() . " c\n" + . $xl->toString() . ' ' . $yDown->toString() . ' ' + . $xLeft->toString() . ' ' . $yd->toString() . ' ' + . $xLeft->toString() . ' ' . $yC->toString() . " c\n" + . $xLeft->toString() . ' ' . $yu->toString() . ' ' + . $xl->toString() . ' ' . $yUp->toString() . ' ' + . $xC->toString() . ' ' . $yUp->toString() . " c\n" + . "h\nW\nn\n"; + + return $this; + } + + /** + * Intersect current clipping area with a polygon. + * + * @param array $x - array of float (the X co-ordinates of the vertices) + * @param array $y - array of float (the Y co-ordinates of the vertices) + * @param integer $fillMethod + * @return Zend_Pdf_Canvas_Interface + */ + public function clipPolygon($x, $y, $fillMethod = Zend_Pdf_Page::FILL_METHOD_NON_ZERO_WINDING) + { + $this->_addProcSet('PDF'); + + $firstPoint = true; + foreach ($x as $id => $xVal) { + $xObj = new Zend_Pdf_Element_Numeric($xVal); + $yObj = new Zend_Pdf_Element_Numeric($y[$id]); + + if ($firstPoint) { + $path = $xObj->toString() . ' ' . $yObj->toString() . " m\n"; + $firstPoint = false; + } else { + $path .= $xObj->toString() . ' ' . $yObj->toString() . " l\n"; + } + } + + $this->_contents .= $path; + + if ($fillMethod == Zend_Pdf_Page::FILL_METHOD_NON_ZERO_WINDING) { + $this->_contents .= " h\n W\nn\n"; + } else { + // Even-Odd fill method. + $this->_contents .= " h\n W*\nn\n"; + } + + return $this; + } + + /** + * Intersect current clipping area with a rectangle. + * + * @param float $x1 + * @param float $y1 + * @param float $x2 + * @param float $y2 + * @return Zend_Pdf_Canvas_Interface + */ + public function clipRectangle($x1, $y1, $x2, $y2) + { + $this->_addProcSet('PDF'); + + $x1Obj = new Zend_Pdf_Element_Numeric($x1); + $y1Obj = new Zend_Pdf_Element_Numeric($y1); + $widthObj = new Zend_Pdf_Element_Numeric($x2 - $x1); + $height2Obj = new Zend_Pdf_Element_Numeric($y2 - $y1); + + $this->_contents .= $x1Obj->toString() . ' ' . $y1Obj->toString() . ' ' + . $widthObj->toString() . ' ' . $height2Obj->toString() . " re\n" + . " W\nn\n"; + + return $this; + } + +// ------------------------------------------------------------------------------------------ + /** + * Draw a circle centered on x, y with a radius of radius. + * + * Method signatures: + * drawCircle($x, $y, $radius); + * drawCircle($x, $y, $radius, $fillType); + * drawCircle($x, $y, $radius, $startAngle, $endAngle); + * drawCircle($x, $y, $radius, $startAngle, $endAngle, $fillType); + * + * + * It's not a really circle, because PDF supports only cubic Bezier curves. + * But _very_ good approximation. + * It differs from a real circle on a maximum 0.00026 radiuses + * (at PI/8, 3*PI/8, 5*PI/8, 7*PI/8, 9*PI/8, 11*PI/8, 13*PI/8 and 15*PI/8 angles). + * At 0, PI/4, PI/2, 3*PI/4, PI, 5*PI/4, 3*PI/2 and 7*PI/4 it's exactly a tangent to a circle. + * + * @param float $x + * @param float $y + * @param float $radius + * @param mixed $param4 + * @param mixed $param5 + * @param mixed $param6 + * @return Zend_Pdf_Canvas_Interface + */ + public function drawCircle($x, $y, $radius, $param4 = null, $param5 = null, $param6 = null) + { + $this->drawEllipse($x - $radius, $y - $radius, + $x + $radius, $y + $radius, + $param4, $param5, $param6); + + return $this; + } + + /** + * Draw an ellipse inside the specified rectangle. + * + * Method signatures: + * drawEllipse($x1, $y1, $x2, $y2); + * drawEllipse($x1, $y1, $x2, $y2, $fillType); + * drawEllipse($x1, $y1, $x2, $y2, $startAngle, $endAngle); + * drawEllipse($x1, $y1, $x2, $y2, $startAngle, $endAngle, $fillType); + * + * @todo process special cases with $x2-$x1 == 0 or $y2-$y1 == 0 + * + * @param float $x1 + * @param float $y1 + * @param float $x2 + * @param float $y2 + * @param mixed $param5 + * @param mixed $param6 + * @param mixed $param7 + * @return Zend_Pdf_Canvas_Interface + */ + public function drawEllipse($x1, $y1, $x2, $y2, $param5 = null, $param6 = null, $param7 = null) + { + if ($param5 === null) { + // drawEllipse($x1, $y1, $x2, $y2); + $startAngle = null; + $fillType = Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE; + } else if ($param6 === null) { + // drawEllipse($x1, $y1, $x2, $y2, $fillType); + $startAngle = null; + $fillType = $param5; + } else { + // drawEllipse($x1, $y1, $x2, $y2, $startAngle, $endAngle); + // drawEllipse($x1, $y1, $x2, $y2, $startAngle, $endAngle, $fillType); + $startAngle = $param5; + $endAngle = $param6; + + if ($param7 === null) { + $fillType = Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE; + } else { + $fillType = $param7; + } + } + + $this->_addProcSet('PDF'); + + if ($x2 < $x1) { + $temp = $x1; + $x1 = $x2; + $x2 = $temp; + } + if ($y2 < $y1) { + $temp = $y1; + $y1 = $y2; + $y2 = $temp; + } + + $x = ($x1 + $x2)/2.; + $y = ($y1 + $y2)/2.; + + $xC = new Zend_Pdf_Element_Numeric($x); + $yC = new Zend_Pdf_Element_Numeric($y); + + if ($startAngle !== null) { + if ($startAngle != 0) { $startAngle = fmod($startAngle, M_PI*2); } + if ($endAngle != 0) { $endAngle = fmod($endAngle, M_PI*2); } + + if ($startAngle > $endAngle) { + $endAngle += M_PI*2; + } + + $clipPath = $xC->toString() . ' ' . $yC->toString() . " m\n"; + $clipSectors = (int)ceil(($endAngle - $startAngle)/M_PI_4); + $clipRadius = max($x2 - $x1, $y2 - $y1); + + for($count = 0; $count <= $clipSectors; $count++) { + $pAngle = $startAngle + ($endAngle - $startAngle)*$count/(float)$clipSectors; + + $pX = new Zend_Pdf_Element_Numeric($x + cos($pAngle)*$clipRadius); + $pY = new Zend_Pdf_Element_Numeric($y + sin($pAngle)*$clipRadius); + $clipPath .= $pX->toString() . ' ' . $pY->toString() . " l\n"; + } + + $this->_contents .= "q\n" . $clipPath . "h\nW\nn\n"; + } + + $xLeft = new Zend_Pdf_Element_Numeric($x1); + $xRight = new Zend_Pdf_Element_Numeric($x2); + $yUp = new Zend_Pdf_Element_Numeric($y2); + $yDown = new Zend_Pdf_Element_Numeric($y1); + + $xDelta = 2*(M_SQRT2 - 1)*($x2 - $x1)/3.; + $yDelta = 2*(M_SQRT2 - 1)*($y2 - $y1)/3.; + $xr = new Zend_Pdf_Element_Numeric($x + $xDelta); + $xl = new Zend_Pdf_Element_Numeric($x - $xDelta); + $yu = new Zend_Pdf_Element_Numeric($y + $yDelta); + $yd = new Zend_Pdf_Element_Numeric($y - $yDelta); + + $this->_contents .= $xC->toString() . ' ' . $yUp->toString() . " m\n" + . $xr->toString() . ' ' . $yUp->toString() . ' ' + . $xRight->toString() . ' ' . $yu->toString() . ' ' + . $xRight->toString() . ' ' . $yC->toString() . " c\n" + . $xRight->toString() . ' ' . $yd->toString() . ' ' + . $xr->toString() . ' ' . $yDown->toString() . ' ' + . $xC->toString() . ' ' . $yDown->toString() . " c\n" + . $xl->toString() . ' ' . $yDown->toString() . ' ' + . $xLeft->toString() . ' ' . $yd->toString() . ' ' + . $xLeft->toString() . ' ' . $yC->toString() . " c\n" + . $xLeft->toString() . ' ' . $yu->toString() . ' ' + . $xl->toString() . ' ' . $yUp->toString() . ' ' + . $xC->toString() . ' ' . $yUp->toString() . " c\n"; + + switch ($fillType) { + case Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE: + $this->_contents .= " B*\n"; + break; + case Zend_Pdf_Page::SHAPE_DRAW_FILL: + $this->_contents .= " f*\n"; + break; + case Zend_Pdf_Page::SHAPE_DRAW_STROKE: + $this->_contents .= " S\n"; + break; + } + + if ($startAngle !== null) { + $this->_contents .= "Q\n"; + } + + return $this; + } + + /** + * Draw an image at the specified position on the page. + * + * @param Zend_Pdf_Image $image + * @param float $x1 + * @param float $y1 + * @param float $x2 + * @param float $y2 + * @return Zend_Pdf_Canvas_Interface + */ + public function drawImage(Zend_Pdf_Resource_Image $image, $x1, $y1, $x2, $y2) + { + $this->_addProcSet('PDF'); + + $imageName = $this->_attachResource('XObject', $image); + $imageNameObj = new Zend_Pdf_Element_Name($imageName); + + $x1Obj = new Zend_Pdf_Element_Numeric($x1); + $y1Obj = new Zend_Pdf_Element_Numeric($y1); + $widthObj = new Zend_Pdf_Element_Numeric($x2 - $x1); + $heightObj = new Zend_Pdf_Element_Numeric($y2 - $y1); + + $this->_contents .= "q\n" + . '1 0 0 1 ' . $x1Obj->toString() . ' ' . $y1Obj->toString() . " cm\n" + . $widthObj->toString() . ' 0 0 ' . $heightObj->toString() . " 0 0 cm\n" + . $imageNameObj->toString() . " Do\n" + . "Q\n"; + + return $this; + } + + /** + * Draw a LayoutBox at the specified position on the page. + * + * @internal (not implemented now) + * + * @param Zend_Pdf_Element_LayoutBox $box + * @param float $x + * @param float $y + * @return Zend_Pdf_Canvas_Interface + */ + public function drawLayoutBox($box, $x, $y) + { + /** @todo implementation */ + return $this; + } + + /** + * Draw a line from x1,y1 to x2,y2. + * + * @param float $x1 + * @param float $y1 + * @param float $x2 + * @param float $y2 + * @return Zend_Pdf_Canvas_Interface + */ + public function drawLine($x1, $y1, $x2, $y2) + { + $this->_addProcSet('PDF'); + + $x1Obj = new Zend_Pdf_Element_Numeric($x1); + $y1Obj = new Zend_Pdf_Element_Numeric($y1); + $x2Obj = new Zend_Pdf_Element_Numeric($x2); + $y2Obj = new Zend_Pdf_Element_Numeric($y2); + + $this->_contents .= $x1Obj->toString() . ' ' . $y1Obj->toString() . " m\n" + . $x2Obj->toString() . ' ' . $y2Obj->toString() . " l\n S\n"; + + return $this; + } + + /** + * Draw a polygon. + * + * If $fillType is Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE or + * Zend_Pdf_Page::SHAPE_DRAW_FILL, then polygon is automatically closed. + * See detailed description of these methods in a PDF documentation + * (section 4.4.2 Path painting Operators, Filling) + * + * @param array $x - array of float (the X co-ordinates of the vertices) + * @param array $y - array of float (the Y co-ordinates of the vertices) + * @param integer $fillType + * @param integer $fillMethod + * @return Zend_Pdf_Canvas_Interface + */ + public function drawPolygon($x, $y, + $fillType = Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE, + $fillMethod = Zend_Pdf_Page::FILL_METHOD_NON_ZERO_WINDING) + { + $this->_addProcSet('PDF'); + + $firstPoint = true; + foreach ($x as $id => $xVal) { + $xObj = new Zend_Pdf_Element_Numeric($xVal); + $yObj = new Zend_Pdf_Element_Numeric($y[$id]); + + if ($firstPoint) { + $path = $xObj->toString() . ' ' . $yObj->toString() . " m\n"; + $firstPoint = false; + } else { + $path .= $xObj->toString() . ' ' . $yObj->toString() . " l\n"; + } + } + + $this->_contents .= $path; + + switch ($fillType) { + case Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE: + if ($fillMethod == Zend_Pdf_Page::FILL_METHOD_NON_ZERO_WINDING) { + $this->_contents .= " b\n"; + } else { + // Even-Odd fill method. + $this->_contents .= " b*\n"; + } + break; + case Zend_Pdf_Page::SHAPE_DRAW_FILL: + if ($fillMethod == Zend_Pdf_Page::FILL_METHOD_NON_ZERO_WINDING) { + $this->_contents .= " h\n f\n"; + } else { + // Even-Odd fill method. + $this->_contents .= " h\n f*\n"; + } + break; + case Zend_Pdf_Page::SHAPE_DRAW_STROKE: + $this->_contents .= " S\n"; + break; + } + + return $this; + } + + /** + * Draw a rectangle. + * + * Fill types: + * Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE - fill rectangle and stroke (default) + * Zend_Pdf_Page::SHAPE_DRAW_STROKE - stroke rectangle + * Zend_Pdf_Page::SHAPE_DRAW_FILL - fill rectangle + * + * @param float $x1 + * @param float $y1 + * @param float $x2 + * @param float $y2 + * @param integer $fillType + * @return Zend_Pdf_Canvas_Interface + */ + public function drawRectangle($x1, $y1, $x2, $y2, $fillType = Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE) + { + $this->_addProcSet('PDF'); + + $x1Obj = new Zend_Pdf_Element_Numeric($x1); + $y1Obj = new Zend_Pdf_Element_Numeric($y1); + $widthObj = new Zend_Pdf_Element_Numeric($x2 - $x1); + $height2Obj = new Zend_Pdf_Element_Numeric($y2 - $y1); + + $this->_contents .= $x1Obj->toString() . ' ' . $y1Obj->toString() . ' ' + . $widthObj->toString() . ' ' . $height2Obj->toString() . " re\n"; + + switch ($fillType) { + case Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE: + $this->_contents .= " B*\n"; + break; + case Zend_Pdf_Page::SHAPE_DRAW_FILL: + $this->_contents .= " f*\n"; + break; + case Zend_Pdf_Page::SHAPE_DRAW_STROKE: + $this->_contents .= " S\n"; + break; + } + + return $this; + } + + /** + * Draw a rounded rectangle. + * + * Fill types: + * Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE - fill rectangle and stroke (default) + * Zend_Pdf_Page::SHAPE_DRAW_STROKE - stroke rectangle + * Zend_Pdf_Page::SHAPE_DRAW_FILL - fill rectangle + * + * radius is an integer representing radius of the four corners, or an array + * of four integers representing the radius starting at top left, going + * clockwise + * + * @param float $x1 + * @param float $y1 + * @param float $x2 + * @param float $y2 + * @param integer|array $radius + * @param integer $fillType + * @return Zend_Pdf_Canvas_Interface + */ + public function drawRoundedRectangle($x1, $y1, $x2, $y2, $radius, + $fillType = Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE) + { + + $this->_addProcSet('PDF'); + + if(!is_array($radius)) { + $radius = array($radius, $radius, $radius, $radius); + } else { + for ($i = 0; $i < 4; $i++) { + if(!isset($radius[$i])) { + $radius[$i] = 0; + } + } + } + + $topLeftX = $x1; + $topLeftY = $y2; + $topRightX = $x2; + $topRightY = $y2; + $bottomRightX = $x2; + $bottomRightY = $y1; + $bottomLeftX = $x1; + $bottomLeftY = $y1; + + //draw top side + $x1Obj = new Zend_Pdf_Element_Numeric($topLeftX + $radius[0]); + $y1Obj = new Zend_Pdf_Element_Numeric($topLeftY); + $this->_contents .= $x1Obj->toString() . ' ' . $y1Obj->toString() . " m\n"; + $x1Obj = new Zend_Pdf_Element_Numeric($topRightX - $radius[1]); + $y1Obj = new Zend_Pdf_Element_Numeric($topRightY); + $this->_contents .= $x1Obj->toString() . ' ' . $y1Obj->toString() . " l\n"; + + //draw top right corner if needed + if ($radius[1] != 0) { + $x1Obj = new Zend_Pdf_Element_Numeric($topRightX); + $y1Obj = new Zend_Pdf_Element_Numeric($topRightY); + $x2Obj = new Zend_Pdf_Element_Numeric($topRightX); + $y2Obj = new Zend_Pdf_Element_Numeric($topRightY); + $x3Obj = new Zend_Pdf_Element_Numeric($topRightX); + $y3Obj = new Zend_Pdf_Element_Numeric($topRightY - $radius[1]); + $this->_contents .= $x1Obj->toString() . ' ' . $y1Obj->toString() . ' ' + . $x2Obj->toString() . ' ' . $y2Obj->toString() . ' ' + . $x3Obj->toString() . ' ' . $y3Obj->toString() . ' ' + . " c\n"; + } + + //draw right side + $x1Obj = new Zend_Pdf_Element_Numeric($bottomRightX); + $y1Obj = new Zend_Pdf_Element_Numeric($bottomRightY + $radius[2]); + $this->_contents .= $x1Obj->toString() . ' ' . $y1Obj->toString() . " l\n"; + + //draw bottom right corner if needed + if ($radius[2] != 0) { + $x1Obj = new Zend_Pdf_Element_Numeric($bottomRightX); + $y1Obj = new Zend_Pdf_Element_Numeric($bottomRightY); + $x2Obj = new Zend_Pdf_Element_Numeric($bottomRightX); + $y2Obj = new Zend_Pdf_Element_Numeric($bottomRightY); + $x3Obj = new Zend_Pdf_Element_Numeric($bottomRightX - $radius[2]); + $y3Obj = new Zend_Pdf_Element_Numeric($bottomRightY); + $this->_contents .= $x1Obj->toString() . ' ' . $y1Obj->toString() . ' ' + . $x2Obj->toString() . ' ' . $y2Obj->toString() . ' ' + . $x3Obj->toString() . ' ' . $y3Obj->toString() . ' ' + . " c\n"; + } + + //draw bottom side + $x1Obj = new Zend_Pdf_Element_Numeric($bottomLeftX + $radius[3]); + $y1Obj = new Zend_Pdf_Element_Numeric($bottomLeftY); + $this->_contents .= $x1Obj->toString() . ' ' . $y1Obj->toString() . " l\n"; + + //draw bottom left corner if needed + if ($radius[3] != 0) { + $x1Obj = new Zend_Pdf_Element_Numeric($bottomLeftX); + $y1Obj = new Zend_Pdf_Element_Numeric($bottomLeftY); + $x2Obj = new Zend_Pdf_Element_Numeric($bottomLeftX); + $y2Obj = new Zend_Pdf_Element_Numeric($bottomLeftY); + $x3Obj = new Zend_Pdf_Element_Numeric($bottomLeftX); + $y3Obj = new Zend_Pdf_Element_Numeric($bottomLeftY + $radius[3]); + $this->_contents .= $x1Obj->toString() . ' ' . $y1Obj->toString() . ' ' + . $x2Obj->toString() . ' ' . $y2Obj->toString() . ' ' + . $x3Obj->toString() . ' ' . $y3Obj->toString() . ' ' + . " c\n"; + } + + //draw left side + $x1Obj = new Zend_Pdf_Element_Numeric($topLeftX); + $y1Obj = new Zend_Pdf_Element_Numeric($topLeftY - $radius[0]); + $this->_contents .= $x1Obj->toString() . ' ' . $y1Obj->toString() . " l\n"; + + //draw top left corner if needed + if ($radius[0] != 0) { + $x1Obj = new Zend_Pdf_Element_Numeric($topLeftX); + $y1Obj = new Zend_Pdf_Element_Numeric($topLeftY); + $x2Obj = new Zend_Pdf_Element_Numeric($topLeftX); + $y2Obj = new Zend_Pdf_Element_Numeric($topLeftY); + $x3Obj = new Zend_Pdf_Element_Numeric($topLeftX + $radius[0]); + $y3Obj = new Zend_Pdf_Element_Numeric($topLeftY); + $this->_contents .= $x1Obj->toString() . ' ' . $y1Obj->toString() . ' ' + . $x2Obj->toString() . ' ' . $y2Obj->toString() . ' ' + . $x3Obj->toString() . ' ' . $y3Obj->toString() . ' ' + . " c\n"; + } + + switch ($fillType) { + case Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE: + $this->_contents .= " B*\n"; + break; + case Zend_Pdf_Page::SHAPE_DRAW_FILL: + $this->_contents .= " f*\n"; + break; + case Zend_Pdf_Page::SHAPE_DRAW_STROKE: + $this->_contents .= " S\n"; + break; + } + + return $this; + } + + /** + * Draw a line of text at the specified position. + * + * @param string $text + * @param float $x + * @param float $y + * @param string $charEncoding (optional) Character encoding of source text. + * Defaults to current locale. + * @throws Zend_Pdf_Exception + * @return Zend_Pdf_Canvas_Interface + */ + public function drawText($text, $x, $y, $charEncoding = '') + { + if ($this->_font === null) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Font has not been set'); + } + + $this->_addProcSet('Text'); + + $textObj = new Zend_Pdf_Element_String($this->_font->encodeString($text, $charEncoding)); + $xObj = new Zend_Pdf_Element_Numeric($x); + $yObj = new Zend_Pdf_Element_Numeric($y); + + $this->_contents .= "BT\n" + . $xObj->toString() . ' ' . $yObj->toString() . " Td\n" + . $textObj->toString() . " Tj\n" + . "ET\n"; + + return $this; + } + + /** + * Close the path by drawing a straight line back to it's beginning. + * + * @internal (needs implementation) + * + * @throws Zend_Pdf_Exception - if a path hasn't been started with pathMove() + * @return Zend_Pdf_Canvas_Interface + */ + public function pathClose() + { + /** @todo implementation */ + return $this; + } + + /** + * Continue the open path in a straight line to the specified position. + * + * @internal (needs implementation) + * + * @param float $x - the X co-ordinate to move to + * @param float $y - the Y co-ordinate to move to + * @return Zend_Pdf_Canvas_Interface + */ + public function pathLine($x, $y) + { + /** @todo implementation */ + return $this; + } + + /** + * Start a new path at the specified position. If a path has already been started, + * move the cursor without drawing a line. + * + * @internal (needs implementation) + * + * @param float $x - the X co-ordinate to move to + * @param float $y - the Y co-ordinate to move to + * @return Zend_Pdf_Canvas_Interface + */ + public function pathMove($x, $y) + { + /** @todo implementation */ + return $this; + } + + /** + * Rotate the page. + * + * @param float $x - the X co-ordinate of rotation point + * @param float $y - the Y co-ordinate of rotation point + * @param float $angle - rotation angle + * @return Zend_Pdf_Canvas_Interface + */ + public function rotate($x, $y, $angle) + { + $cos = new Zend_Pdf_Element_Numeric(cos($angle)); + $sin = new Zend_Pdf_Element_Numeric(sin($angle)); + $mSin = new Zend_Pdf_Element_Numeric(-$sin->value); + + $xObj = new Zend_Pdf_Element_Numeric($x); + $yObj = new Zend_Pdf_Element_Numeric($y); + + $mXObj = new Zend_Pdf_Element_Numeric(-$x); + $mYObj = new Zend_Pdf_Element_Numeric(-$y); + + + $this->_addProcSet('PDF'); + $this->_contents .= '1 0 0 1 ' . $xObj->toString() . ' ' . $yObj->toString() . " cm\n" + . $cos->toString() . ' ' . $sin->toString() . ' ' . $mSin->toString() . ' ' . $cos->toString() . " 0 0 cm\n" + . '1 0 0 1 ' . $mXObj->toString() . ' ' . $mYObj->toString() . " cm\n"; + + return $this; + } + + /** + * Scale coordination system. + * + * @param float $xScale - X dimention scale factor + * @param float $yScale - Y dimention scale factor + * @return Zend_Pdf_Canvas_Interface + */ + public function scale($xScale, $yScale) + { + $xScaleObj = new Zend_Pdf_Element_Numeric($xScale); + $yScaleObj = new Zend_Pdf_Element_Numeric($yScale); + + $this->_addProcSet('PDF'); + $this->_contents .= $xScaleObj->toString() . ' 0 0 ' . $yScaleObj->toString() . " 0 0 cm\n"; + + return $this; + } + + /** + * Translate coordination system. + * + * @param float $xShift - X coordinate shift + * @param float $yShift - Y coordinate shift + * @return Zend_Pdf_Canvas_Interface + */ + public function translate($xShift, $yShift) + { + $xShiftObj = new Zend_Pdf_Element_Numeric($xShift); + $yShiftObj = new Zend_Pdf_Element_Numeric($yShift); + + $this->_addProcSet('PDF'); + $this->_contents .= '1 0 0 1 ' . $xShiftObj->toString() . ' ' . $yShiftObj->toString() . " cm\n"; + + return $this; + } + + /** + * Translate coordination system. + * + * @param float $x - the X co-ordinate of axis skew point + * @param float $y - the Y co-ordinate of axis skew point + * @param float $xAngle - X axis skew angle + * @param float $yAngle - Y axis skew angle + * @return Zend_Pdf_Canvas_Interface + */ + public function skew($x, $y, $xAngle, $yAngle) + { + $tanXObj = new Zend_Pdf_Element_Numeric(tan($xAngle)); + $tanYObj = new Zend_Pdf_Element_Numeric(-tan($yAngle)); + + $xObj = new Zend_Pdf_Element_Numeric($x); + $yObj = new Zend_Pdf_Element_Numeric($y); + + $mXObj = new Zend_Pdf_Element_Numeric(-$x); + $mYObj = new Zend_Pdf_Element_Numeric(-$y); + + $this->_addProcSet('PDF'); + $this->_contents .= '1 0 0 1 ' . $xObj->toString() . ' ' . $yObj->toString() . " cm\n" + . '1 ' . $tanXObj->toString() . ' ' . $tanYObj->toString() . " 1 0 0 cm\n" + . '1 0 0 1 ' . $mXObj->toString() . ' ' . $mYObj->toString() . " cm\n"; + + return $this; + } + + /** + * Writes the raw data to the page's content stream. + * + * Be sure to consult the PDF reference to ensure your syntax is correct. No + * attempt is made to ensure the validity of the stream data. + * + * @param string $data + * @param string $procSet (optional) Name of ProcSet to add. + * @return Zend_Pdf_Canvas_Interface + */ + public function rawWrite($data, $procSet = null) + { + if (! empty($procSet)) { + $this->_addProcSet($procSet); + } + $this->_contents .= $data; + + return $this; + } +} diff --git a/library/Zend/Pdf/Canvas/Interface.php b/library/Zend/Pdf/Canvas/Interface.php new file mode 100644 index 0000000..88b20f4 --- /dev/null +++ b/library/Zend/Pdf/Canvas/Interface.php @@ -0,0 +1,493 @@ + => array( + * => , + * => , + * => , + * ... + * ), + * => array( + * => , + * => , + * => , + * ... + * ), + * ... + * 'ProcSet' => array() + * ) + * + * where ProcSet array is a list of used procedure sets names (strings). + * Allowed procedure set names: 'PDF', 'Text', 'ImageB', 'ImageC', 'ImageI' + * + * @internal + * @return array + */ + public function getResources(); + + /** + * Get drawing instructions stream + * + * It has to be returned as a PDF stream object to make it reusable. + * + * @internal + * @returns Zend_Pdf_Resource_ContentStream + */ + public function getContents(); + + /** + * Return canvas height. + * + * @return float + */ + public function getHeight(); + + /** + * Return canvas width. + * + * @return float + */ + public function getWidth(); + + /** + * Draw a canvas at the specified location + * + * If upper right corner is not specified then canvas heght and width + * are used. + * + * @param Zend_Pdf_Canvas_Interface $canvas + * @param float $x1 + * @param float $y1 + * @param float $x2 + * @param float $y2 + * @return Zend_Pdf_Canvas_Interface + */ + public function drawCanvas(Zend_Pdf_Canvas_Interface $canvas, $x1, $y1, $x2 = null, $y2 = null); + + /** + * Set fill color. + * + * @param Zend_Pdf_Color $color + * @return Zend_Pdf_Canvas_Interface + */ + public function setFillColor(Zend_Pdf_Color $color); + + /** + * Set line color. + * + * @param Zend_Pdf_Color $color + * @return Zend_Pdf_Canvas_Interface + */ + public function setLineColor(Zend_Pdf_Color $color); + + /** + * Set line width. + * + * @param float $width + * @return Zend_Pdf_Canvas_Interface + */ + public function setLineWidth($width); + + /** + * Set line dashing pattern + * + * Pattern is an array of floats: array(on_length, off_length, on_length, off_length, ...) + * or Zend_Pdf_Page::LINE_DASHING_SOLID constant + * Phase is shift from the beginning of line. + * + * @param mixed $pattern + * @param array $phase + * @return Zend_Pdf_Canvas_Interface + */ + public function setLineDashingPattern($pattern, $phase = 0); + + /** + * Set current font. + * + * @param Zend_Pdf_Resource_Font $font + * @param float $fontSize + * @return Zend_Pdf_Canvas_Interface + */ + public function setFont(Zend_Pdf_Resource_Font $font, $fontSize); + + /** + * Set the style to use for future drawing operations on this page + * + * @param Zend_Pdf_Style $style + * @return Zend_Pdf_Canvas_Interface + */ + public function setStyle(Zend_Pdf_Style $style); + + /** + * Get current font. + * + * @return Zend_Pdf_Resource_Font $font + */ + public function getFont(); + + /** + * Get current font size + * + * @return float $fontSize + */ + public function getFontSize(); + + /** + * Return the style, applied to the page. + * + * @return Zend_Pdf_Style|null + */ + public function getStyle(); + + /** + * Save the graphics state of this page. + * This takes a snapshot of the currently applied style, position, clipping area and + * any rotation/translation/scaling that has been applied. + * + * @throws Zend_Pdf_Exception - if a save is performed with an open path + * @return Zend_Pdf_Page + */ + public function saveGS(); + + /** + * Set the transparancy + * + * $alpha == 0 - transparent + * $alpha == 1 - opaque + * + * Transparency modes, supported by PDF: + * Normal (default), Multiply, Screen, Overlay, Darken, Lighten, ColorDodge, ColorBurn, HardLight, + * SoftLight, Difference, Exclusion + * + * @param float $alpha + * @param string $mode + * @throws Zend_Pdf_Exception + * @return Zend_Pdf_Canvas_Interface + */ + public function setAlpha($alpha, $mode = 'Normal'); + + /** + * Intersect current clipping area with a circle. + * + * @param float $x + * @param float $y + * @param float $radius + * @param float $startAngle + * @param float $endAngle + * @return Zend_Pdf_Canvas_Interface + */ + public function clipCircle($x, $y, $radius, $startAngle = null, $endAngle = null); + + /** + * Intersect current clipping area with a polygon. + * + * Method signatures: + * drawEllipse($x1, $y1, $x2, $y2); + * drawEllipse($x1, $y1, $x2, $y2, $startAngle, $endAngle); + * + * @todo process special cases with $x2-$x1 == 0 or $y2-$y1 == 0 + * + * @param float $x1 + * @param float $y1 + * @param float $x2 + * @param float $y2 + * @param float $startAngle + * @param float $endAngle + * @return Zend_Pdf_Canvas_Interface + */ + public function clipEllipse($x1, $y1, $x2, $y2, $startAngle = null, $endAngle = null); + + /** + * Intersect current clipping area with a polygon. + * + * @param array $x - array of float (the X co-ordinates of the vertices) + * @param array $y - array of float (the Y co-ordinates of the vertices) + * @param integer $fillMethod + * @return Zend_Pdf_Canvas_Interface + */ + public function clipPolygon($x, $y, $fillMethod = Zend_Pdf_Page::FILL_METHOD_NON_ZERO_WINDING); + + /** + * Intersect current clipping area with a rectangle. + * + * @param float $x1 + * @param float $y1 + * @param float $x2 + * @param float $y2 + * @return Zend_Pdf_Canvas_Interface + */ + public function clipRectangle($x1, $y1, $x2, $y2); + + /** + * Draw a circle centered on x, y with a radius of radius. + * + * Method signatures: + * drawCircle($x, $y, $radius); + * drawCircle($x, $y, $radius, $fillType); + * drawCircle($x, $y, $radius, $startAngle, $endAngle); + * drawCircle($x, $y, $radius, $startAngle, $endAngle, $fillType); + * + * + * It's not a really circle, because PDF supports only cubic Bezier curves. + * But _very_ good approximation. + * It differs from a real circle on a maximum 0.00026 radiuses + * (at PI/8, 3*PI/8, 5*PI/8, 7*PI/8, 9*PI/8, 11*PI/8, 13*PI/8 and 15*PI/8 angles). + * At 0, PI/4, PI/2, 3*PI/4, PI, 5*PI/4, 3*PI/2 and 7*PI/4 it's exactly a tangent to a circle. + * + * @param float $x + * @param float $y + * @param float $radius + * @param mixed $param4 + * @param mixed $param5 + * @param mixed $param6 + * @return Zend_Pdf_Canvas_Interface + */ + public function drawCircle($x, $y, $radius, $param4 = null, $param5 = null, $param6 = null); + + /** + * Draw an ellipse inside the specified rectangle. + * + * Method signatures: + * drawEllipse($x1, $y1, $x2, $y2); + * drawEllipse($x1, $y1, $x2, $y2, $fillType); + * drawEllipse($x1, $y1, $x2, $y2, $startAngle, $endAngle); + * drawEllipse($x1, $y1, $x2, $y2, $startAngle, $endAngle, $fillType); + * + * @todo process special cases with $x2-$x1 == 0 or $y2-$y1 == 0 + * + * @param float $x1 + * @param float $y1 + * @param float $x2 + * @param float $y2 + * @param mixed $param5 + * @param mixed $param6 + * @param mixed $param7 + * @return Zend_Pdf_Canvas_Interface + */ + public function drawEllipse($x1, $y1, $x2, $y2, $param5 = null, $param6 = null, $param7 = null); + + /** + * Draw an image at the specified position on the page. + * + * @param Zend_Pdf_Image $image + * @param float $x1 + * @param float $y1 + * @param float $x2 + * @param float $y2 + * @return Zend_Pdf_Canvas_Interface + */ + public function drawImage(Zend_Pdf_Resource_Image $image, $x1, $y1, $x2, $y2); + + /** + * Draw a LayoutBox at the specified position on the page. + * + * @internal (not implemented now) + * + * @param Zend_Pdf_Element_LayoutBox $box + * @param float $x + * @param float $y + * @return Zend_Pdf_Canvas_Interface + */ + public function drawLayoutBox($box, $x, $y); + + /** + * Draw a line from x1,y1 to x2,y2. + * + * @param float $x1 + * @param float $y1 + * @param float $x2 + * @param float $y2 + * @return Zend_Pdf_Canvas_Interface + */ + public function drawLine($x1, $y1, $x2, $y2); + + /** + * Draw a polygon. + * + * If $fillType is Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE or + * Zend_Pdf_Page::SHAPE_DRAW_FILL, then polygon is automatically closed. + * See detailed description of these methods in a PDF documentation + * (section 4.4.2 Path painting Operators, Filling) + * + * @param array $x - array of float (the X co-ordinates of the vertices) + * @param array $y - array of float (the Y co-ordinates of the vertices) + * @param integer $fillType + * @param integer $fillMethod + * @return Zend_Pdf_Canvas_Interface + */ + public function drawPolygon($x, $y, + $fillType = Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE, + $fillMethod = Zend_Pdf_Page::FILL_METHOD_NON_ZERO_WINDING); + /** + * Draw a rectangle. + * + * Fill types: + * Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE - fill rectangle and stroke (default) + * Zend_Pdf_Page::SHAPE_DRAW_STROKE - stroke rectangle + * Zend_Pdf_Page::SHAPE_DRAW_FILL - fill rectangle + * + * @param float $x1 + * @param float $y1 + * @param float $x2 + * @param float $y2 + * @param integer $fillType + * @return Zend_Pdf_Canvas_Interface + */ + public function drawRectangle($x1, $y1, $x2, $y2, $fillType = Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE); + + /** + * Draw a rounded rectangle. + * + * Fill types: + * Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE - fill rectangle and stroke (default) + * Zend_Pdf_Page::SHAPE_DRAW_STROKE - stroke rectangle + * Zend_Pdf_Page::SHAPE_DRAW_FILL - fill rectangle + * + * radius is an integer representing radius of the four corners, or an array + * of four integers representing the radius starting at top left, going + * clockwise + * + * @param float $x1 + * @param float $y1 + * @param float $x2 + * @param float $y2 + * @param integer|array $radius + * @param integer $fillType + * @return Zend_Pdf_Canvas_Interface + */ + public function drawRoundedRectangle($x1, $y1, $x2, $y2, $radius, + $fillType = Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE); + + /** + * Draw a line of text at the specified position. + * + * @param string $text + * @param float $x + * @param float $y + * @param string $charEncoding (optional) Character encoding of source text. + * Defaults to current locale. + * @throws Zend_Pdf_Exception + * @return Zend_Pdf_Canvas_Interface + */ + public function drawText($text, $x, $y, $charEncoding = ''); + + /** + * Close the path by drawing a straight line back to it's beginning. + * + * @internal (needs implementation) + * + * @throws Zend_Pdf_Exception - if a path hasn't been started with pathMove() + * @return Zend_Pdf_Canvas_Interface + */ + public function pathClose(); + + /** + * Continue the open path in a straight line to the specified position. + * + * @internal (needs implementation) + * + * @param float $x - the X co-ordinate to move to + * @param float $y - the Y co-ordinate to move to + * @return Zend_Pdf_Canvas_Interface + */ + public function pathLine($x, $y); + + /** + * Start a new path at the specified position. If a path has already been started, + * move the cursor without drawing a line. + * + * @internal (needs implementation) + * + * @param float $x - the X co-ordinate to move to + * @param float $y - the Y co-ordinate to move to + * @return Zend_Pdf_Canvas_Interface + */ + public function pathMove($x, $y); + + /** + * Rotate the page. + * + * @param float $x - the X co-ordinate of rotation point + * @param float $y - the Y co-ordinate of rotation point + * @param float $angle - rotation angle + * @return Zend_Pdf_Canvas_Interface + */ + public function rotate($x, $y, $angle); + + /** + * Scale coordination system. + * + * @param float $xScale - X dimention scale factor + * @param float $yScale - Y dimention scale factor + * @return Zend_Pdf_Canvas_Interface + */ + public function scale($xScale, $yScale); + + /** + * Translate coordination system. + * + * @param float $xShift - X coordinate shift + * @param float $yShift - Y coordinate shift + * @return Zend_Pdf_Canvas_Interface + */ + public function translate($xShift, $yShift); + + /** + * Translate coordination system. + * + * @param float $x - the X co-ordinate of axis skew point + * @param float $y - the Y co-ordinate of axis skew point + * @param float $xAngle - X axis skew angle + * @param float $yAngle - Y axis skew angle + * @return Zend_Pdf_Canvas_Interface + */ + public function skew($x, $y, $xAngle, $yAngle); + + /** + * Writes the raw data to the page's content stream. + * + * Be sure to consult the PDF reference to ensure your syntax is correct. No + * attempt is made to ensure the validity of the stream data. + * + * @param string $data + * @param string $procSet (optional) Name of ProcSet to add. + * @return Zend_Pdf_Canvas_Interface + */ + public function rawWrite($data, $procSet = null); +} diff --git a/library/Zend/Pdf/Cmap.php b/library/Zend/Pdf/Cmap.php new file mode 100644 index 0000000..a3b05d8 --- /dev/null +++ b/library/Zend/Pdf/Cmap.php @@ -0,0 +1,336 @@ + + *
  • {@link http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6cmap.html} + *
  • {@link http://www.microsoft.com/OpenType/OTSpec/cmap.htm} + *
  • {@link http://partners.adobe.com/public/developer/opentype/index_cmap.html} + * + * + * @todo Write code for Zend_Pdf_FontCmap_HighByteMapping class. + * @todo Write code for Zend_Pdf_FontCmap_MixedCoverage class. + * @todo Write code for Zend_Pdf_FontCmap_TrimmedArray class. + * @todo Write code for Zend_Pdf_FontCmap_SegmentedCoverage class. + * + * @package Zend_Pdf + * @subpackage Fonts + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +abstract class Zend_Pdf_Cmap +{ + /**** Class Constants ****/ + + + /* Cmap Table Types */ + + /** + * Byte Encoding character map table type. + */ + const TYPE_BYTE_ENCODING = 0x00; + + /** + * High Byte Mapping character map table type. + */ + const TYPE_HIGH_BYTE_MAPPING = 0x02; + + /** + * Segment Value to Delta Mapping character map table type. + */ + const TYPE_SEGMENT_TO_DELTA = 0x04; + + /** + * Trimmed Table character map table type. + */ + const TYPE_TRIMMED_TABLE = 0x06; + + /** + * Mixed Coverage character map table type. + */ + const TYPE_MIXED_COVERAGE = 0x08; + + /** + * Trimmed Array character map table type. + */ + const TYPE_TRIMMED_ARRAY = 0x0a; + + /** + * Segmented Coverage character map table type. + */ + const TYPE_SEGMENTED_COVERAGE = 0x0c; + + /** + * Static Byte Encoding character map table type. Variant of + * {@link TYPE_BYTEENCODING}. + */ + const TYPE_BYTE_ENCODING_STATIC = 0xf1; + + /** + * Unknown character map table type. + */ + const TYPE_UNKNOWN = 0xff; + + + /* Special Glyph Names */ + + /** + * Glyph representing missing characters. + */ + const MISSING_CHARACTER_GLYPH = 0x00; + + + + /**** Public Interface ****/ + + + /* Factory Methods */ + + /** + * Instantiates the appropriate concrete subclass based on the type of cmap + * table and returns the instance. + * + * The cmap type must be one of the following values: + *
      + *
    • {@link Zend_Pdf_Cmap::TYPE_BYTE_ENCODING} + *
    • {@link Zend_Pdf_Cmap::TYPE_BYTE_ENCODING_STATIC} + *
    • {@link Zend_Pdf_Cmap::TYPE_HIGH_BYTE_MAPPING} + *
    • {@link Zend_Pdf_Cmap::TYPE_SEGMENT_TO_DELTA} + *
    • {@link Zend_Pdf_Cmap::TYPE_TRIMMED_TABLE} + *
    • {@link Zend_Pdf_Cmap::TYPE_MIXED_COVERAGE} + *
    • {@link Zend_Pdf_Cmap::TYPE_TRIMMED_ARRAY} + *
    • {@link Zend_Pdf_Cmap::TYPE_SEGMENTED_COVERAGE} + *
    + * + * Throws an exception if the table type is invalid or the cmap table data + * cannot be validated. + * + * @param integer $cmapType Type of cmap. + * @param mixed $cmapData Cmap table data. Usually a string or array. + * @return Zend_Pdf_Cmap + * @throws Zend_Pdf_Exception + */ + public static function cmapWithTypeData($cmapType, $cmapData) + { + switch ($cmapType) { + case Zend_Pdf_Cmap::TYPE_BYTE_ENCODING: + // require_once 'Zend/Pdf/Cmap/ByteEncoding.php'; + return new Zend_Pdf_Cmap_ByteEncoding($cmapData); + + case Zend_Pdf_Cmap::TYPE_BYTE_ENCODING_STATIC: + // require_once 'Zend/Pdf/Cmap/ByteEncoding/Static.php'; + return new Zend_Pdf_Cmap_ByteEncoding_Static($cmapData); + + case Zend_Pdf_Cmap::TYPE_HIGH_BYTE_MAPPING: + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('High byte mapping cmap currently unsupported', + Zend_Pdf_Exception::CMAP_TYPE_UNSUPPORTED); + + case Zend_Pdf_Cmap::TYPE_SEGMENT_TO_DELTA: + // require_once 'Zend/Pdf/Cmap/SegmentToDelta.php'; + return new Zend_Pdf_Cmap_SegmentToDelta($cmapData); + + case Zend_Pdf_Cmap::TYPE_TRIMMED_TABLE: + // require_once 'Zend/Pdf/Cmap/TrimmedTable.php'; + return new Zend_Pdf_Cmap_TrimmedTable($cmapData); + + case Zend_Pdf_Cmap::TYPE_MIXED_COVERAGE: + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Mixed coverage cmap currently unsupported', + Zend_Pdf_Exception::CMAP_TYPE_UNSUPPORTED); + + case Zend_Pdf_Cmap::TYPE_TRIMMED_ARRAY: + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Trimmed array cmap currently unsupported', + Zend_Pdf_Exception::CMAP_TYPE_UNSUPPORTED); + + case Zend_Pdf_Cmap::TYPE_SEGMENTED_COVERAGE: + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Segmented coverage cmap currently unsupported', + Zend_Pdf_Exception::CMAP_TYPE_UNSUPPORTED); + + default: + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("Unknown cmap type: $cmapType", + Zend_Pdf_Exception::CMAP_UNKNOWN_TYPE); + } + } + + + /* Abstract Methods */ + + /** + * Object constructor + * + * Parses the raw binary table data. Throws an exception if the table is + * malformed. + * + * @param string $cmapData Raw binary cmap table data. + * @throws Zend_Pdf_Exception + */ + abstract public function __construct($cmapData); + + /** + * Returns an array of glyph numbers corresponding to the Unicode characters. + * + * If a particular character doesn't exist in this font, the special 'missing + * character glyph' will be substituted. + * + * See also {@link glyphNumberForCharacter()}. + * + * @param array $characterCodes Array of Unicode character codes (code points). + * @return array Array of glyph numbers. + */ + abstract public function glyphNumbersForCharacters($characterCodes); + + /** + * Returns the glyph number corresponding to the Unicode character. + * + * If a particular character doesn't exist in this font, the special 'missing + * character glyph' will be substituted. + * + * See also {@link glyphNumbersForCharacters()} which is optimized for bulk + * operations. + * + * @param integer $characterCode Unicode character code (code point). + * @return integer Glyph number. + */ + abstract public function glyphNumberForCharacter($characterCode); + + /** + * Returns an array containing the Unicode characters that have entries in + * this character map. + * + * @return array Unicode character codes. + */ + abstract public function getCoveredCharacters(); + + /** + * Returns an array containing the glyphs numbers that have entries in this character map. + * Keys are Unicode character codes (integers) + * + * This functionality is partially covered by glyphNumbersForCharacters(getCoveredCharacters()) + * call, but this method do it in more effective way (prepare complete list instead of searching + * glyph for each character code). + * + * @internal + * @return array Array representing => pairs. + */ + abstract public function getCoveredCharactersGlyphs(); + + + /**** Internal Methods ****/ + + + /* Internal Utility Methods */ + + /** + * Extracts a signed 2-byte integer from a string. + * + * Integers are always big-endian. Throws an exception if the index is out + * of range. + * + * @param string &$data + * @param integer $index Position in string of integer. + * @return integer + * @throws Zend_Pdf_Exception + */ + protected function _extractInt2(&$data, $index) + { + if (($index < 0) | (($index + 1) > strlen($data))) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("Index out of range: $index", + Zend_Pdf_Exception::INDEX_OUT_OF_RANGE); + } + $number = ord($data[$index]); + if (($number & 0x80) == 0x80) { // negative + $number = ~((((~ $number) & 0xff) << 8) | ((~ ord($data[++$index])) & 0xff)); + } else { + $number = ($number << 8) | ord($data[++$index]); + } + return $number; + } + + /** + * Extracts an unsigned 2-byte integer from a string. + * + * Integers are always big-endian. Throws an exception if the index is out + * of range. + * + * @param string &$data + * @param integer $index Position in string of integer. + * @return integer + * @throws Zend_Pdf_Exception + */ + protected function _extractUInt2(&$data, $index) + { + if (($index < 0) | (($index + 1) > strlen($data))) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("Index out of range: $index", + Zend_Pdf_Exception::INDEX_OUT_OF_RANGE); + } + $number = (ord($data[$index]) << 8) | ord($data[++$index]); + return $number; + } + + /** + * Extracts an unsigned 4-byte integer from a string. + * + * Integers are always big-endian. Throws an exception if the index is out + * of range. + * + * NOTE: If you ask for a 4-byte unsigned integer on a 32-bit machine, the + * resulting value WILL BE SIGNED because PHP uses signed integers internally + * for everything. To guarantee portability, be sure to use bitwise or + * similar operators on large integers! + * + * @param string &$data + * @param integer $index Position in string of integer. + * @return integer + * @throws Zend_Pdf_Exception + */ + protected function _extractUInt4(&$data, $index) + { + if (($index < 0) | (($index + 3) > strlen($data))) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("Index out of range: $index", + Zend_Pdf_Exception::INDEX_OUT_OF_RANGE); + } + $number = (ord($data[$index]) << 24) | (ord($data[++$index]) << 16) | + (ord($data[++$index]) << 8) | ord($data[++$index]); + return $number; + } + +} diff --git a/library/Zend/Pdf/Cmap/ByteEncoding.php b/library/Zend/Pdf/Cmap/ByteEncoding.php new file mode 100644 index 0000000..575df02 --- /dev/null +++ b/library/Zend/Pdf/Cmap/ByteEncoding.php @@ -0,0 +1,447 @@ + $characterCode) { + + if (! isset($this->_glyphIndexArray[$characterCode])) { + $glyphNumbers[$key] = Zend_Pdf_Cmap::MISSING_CHARACTER_GLYPH; + continue; + } + + $glyphNumbers[$key] = $this->_glyphIndexArray[$characterCode]; + + } + return $glyphNumbers; + } + + /** + * Returns the glyph number corresponding to the Unicode character. + * + * If a particular character doesn't exist in this font, the special 'missing + * character glyph' will be substituted. + * + * See also {@link glyphNumbersForCharacters()} which is optimized for bulk + * operations. + * + * @param integer $characterCode Unicode character code (code point). + * @return integer Glyph number. + */ + public function glyphNumberForCharacter($characterCode) + { + if (! isset($this->_glyphIndexArray[$characterCode])) { + return Zend_Pdf_Cmap::MISSING_CHARACTER_GLYPH; + } + return $this->_glyphIndexArray[$characterCode]; + } + + /** + * Returns an array containing the Unicode characters that have entries in + * this character map. + * + * @return array Unicode character codes. + */ + public function getCoveredCharacters() + { + return array_keys($this->_glyphIndexArray); + } + + /** + * Returns an array containing the glyphs numbers that have entries in this character map. + * Keys are Unicode character codes (integers) + * + * This functionality is partially covered by glyphNumbersForCharacters(getCoveredCharacters()) + * call, but this method do it in more effective way (prepare complete list instead of searching + * glyph for each character code). + * + * @internal + * @return array Array representing => pairs. + */ + public function getCoveredCharactersGlyphs() + { + return $this->_glyphIndexArray; + } + + + /* Object Lifecycle */ + + /** + * Object constructor + * + * Parses the raw binary table data. Throws an exception if the table is + * malformed. + * + * @param string $cmapData Raw binary cmap table data. + * @throws Zend_Pdf_Exception + */ + public function __construct($cmapData) + { + /* Sanity check: This table must be exactly 262 bytes long. + */ + $actualLength = strlen($cmapData); + if ($actualLength != 262) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Insufficient table data', + Zend_Pdf_Exception::CMAP_TABLE_DATA_TOO_SMALL); + } + + /* Sanity check: Make sure this is right data for this table type. + */ + $type = $this->_extractUInt2($cmapData, 0); + if ($type != Zend_Pdf_Cmap::TYPE_BYTE_ENCODING) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Wrong cmap table type', + Zend_Pdf_Exception::CMAP_WRONG_TABLE_TYPE); + } + + $length = $this->_extractUInt2($cmapData, 2); + if ($length != $actualLength) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("Table length ($length) does not match actual length ($actualLength)", + Zend_Pdf_Exception::CMAP_WRONG_TABLE_LENGTH); + } + + /* Mapping tables should be language-independent. The font may not work + * as expected if they are not. Unfortunately, many font files in the + * wild incorrectly record a language ID in this field, so we can't + * call this a failure. + */ + $language = $this->_extractUInt2($cmapData, 4); + if ($language != 0) { + // Record a warning here somehow? + } + + /* The mapping between the Mac Roman and Unicode characters is static. + * For simplicity, just put all 256 glyph indices into one array keyed + * off the corresponding Unicode character. + */ + $i = 6; + $this->_glyphIndexArray[0x00] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x01] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x02] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x03] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x04] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x05] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x06] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x07] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x08] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x09] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x0a] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x0b] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x0c] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x0d] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x0e] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x0f] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x10] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x11] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x12] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x13] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x14] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x15] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x16] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x17] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x18] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x19] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x1a] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x1b] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x1c] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x1d] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x1e] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x1f] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x20] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x21] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x22] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x23] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x24] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x25] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x26] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x27] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x28] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x29] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x2a] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x2b] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x2c] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x2d] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x2e] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x2f] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x30] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x31] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x32] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x33] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x34] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x35] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x36] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x37] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x38] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x39] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x3a] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x3b] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x3c] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x3d] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x3e] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x3f] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x40] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x41] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x42] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x43] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x44] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x45] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x46] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x47] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x48] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x49] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x4a] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x4b] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x4c] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x4d] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x4e] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x4f] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x50] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x51] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x52] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x53] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x54] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x55] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x56] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x57] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x58] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x59] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x5a] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x5b] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x5c] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x5d] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x5e] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x5f] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x60] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x61] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x62] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x63] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x64] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x65] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x66] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x67] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x68] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x69] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x6a] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x6b] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x6c] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x6d] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x6e] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x6f] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x70] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x71] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x72] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x73] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x74] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x75] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x76] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x77] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x78] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x79] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x7a] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x7b] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x7c] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x7d] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x7e] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x7f] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xc4] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xc5] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xc7] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xc9] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xd1] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xd6] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xdc] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xe1] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xe0] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xe2] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xe4] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xe3] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xe5] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xe7] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xe9] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xe8] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xea] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xeb] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xed] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xec] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xee] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xef] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xf1] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xf3] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xf2] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xf4] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xf6] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xf5] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xfa] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xf9] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xfb] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xfc] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x2020] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xb0] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xa2] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xa3] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xa7] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x2022] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xb6] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xdf] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xae] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xa9] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x2122] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xb4] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xa8] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x2260] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xc6] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xd8] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x221e] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xb1] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x2264] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x2265] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xa5] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xb5] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x2202] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x2211] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x220f] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x03c0] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x222b] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xaa] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xba] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x03a9] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xe6] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xf8] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xbf] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xa1] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xac] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x221a] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x0192] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x2248] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x2206] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xab] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xbb] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x2026] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xa0] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xc0] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xc3] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xd5] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x0152] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x0153] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x2013] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x2014] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x201c] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x201d] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x2018] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x2019] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xf7] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x25ca] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xff] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x0178] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x2044] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x20ac] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x2039] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x203a] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xfb01] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xfb02] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x2021] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xb7] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x201a] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x201e] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x2030] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xc2] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xca] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xc1] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xcb] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xc8] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xcd] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xce] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xcf] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xcc] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xd3] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xd4] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xf8ff] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xd2] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xda] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xdb] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xd9] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x0131] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x02c6] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x02dc] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xaf] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x02d8] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x02d9] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x02da] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0xb8] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x02dd] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x02db] = ord($cmapData[$i++]); + $this->_glyphIndexArray[0x02c7] = ord($cmapData[$i]); + } + +} diff --git a/library/Zend/Pdf/Cmap/ByteEncoding/Static.php b/library/Zend/Pdf/Cmap/ByteEncoding/Static.php new file mode 100644 index 0000000..b22f0ee --- /dev/null +++ b/library/Zend/Pdf/Cmap/ByteEncoding/Static.php @@ -0,0 +1,62 @@ +_glyphIndexArray = $cmapData; + } + +} diff --git a/library/Zend/Pdf/Cmap/SegmentToDelta.php b/library/Zend/Pdf/Cmap/SegmentToDelta.php new file mode 100644 index 0000000..9043688 --- /dev/null +++ b/library/Zend/Pdf/Cmap/SegmentToDelta.php @@ -0,0 +1,407 @@ + $characterCode) { + + /* These tables only cover the 16-bit character range. + */ + if ($characterCode > 0xffff) { + $glyphNumbers[$key] = Zend_Pdf_Cmap::MISSING_CHARACTER_GLYPH; + continue; + } + + /* Determine where to start the binary search. The segments are + * ordered from lowest-to-highest. We are looking for the first + * segment whose end code is greater than or equal to our character + * code. + * + * If the end code at the top of the search range is larger, then + * our target is probably below it. + * + * If it is smaller, our target is probably above it, so move the + * search range to the end of the segment list. + */ + if ($this->_searchRangeEndCode >= $characterCode) { + $searchIndex = $this->_searchRange; + } else { + $searchIndex = $this->_segmentCount; + } + + /* Now do a binary search to find the first segment whose end code + * is greater or equal to our character code. No matter the number + * of segments (there may be hundreds in a large font), we will only + * need to perform $this->_searchIterations. + */ + for ($i = 1; $i <= $this->_searchIterations; $i++) { + if ($this->_segmentTableEndCodes[$searchIndex] >= $characterCode) { + $subtableIndex = $searchIndex; + $searchIndex -= $this->_searchRange >> $i; + } else { + $searchIndex += $this->_searchRange >> $i; + } + } + + /* If the segment's start code is greater than our character code, + * that character is not represented in this font. Move on. + */ + if ($this->_segmentTableStartCodes[$subtableIndex] > $characterCode) { + $glyphNumbers[$key] = Zend_Pdf_Cmap::MISSING_CHARACTER_GLYPH; + continue; + } + + if ($this->_segmentTableIdRangeOffsets[$subtableIndex] == 0) { + /* This segment uses a simple mapping from character code to + * glyph number. + */ + $glyphNumbers[$key] = ($characterCode + $this->_segmentTableIdDeltas[$subtableIndex]) % 65536; + + } else { + /* This segment relies on the glyph index array to determine the + * glyph number. The calculation below determines the correct + * index into that array. It's a little odd because the range + * offset in the font file is designed to quickly provide an + * address of the index in the raw binary data instead of the + * index itself. Since we've parsed the data into arrays, we + * must process it a bit differently. + */ + $glyphIndex = ($characterCode - $this->_segmentTableStartCodes[$subtableIndex] + + $this->_segmentTableIdRangeOffsets[$subtableIndex] - $this->_segmentCount + + $subtableIndex - 1); + $glyphNumbers[$key] = $this->_glyphIndexArray[$glyphIndex]; + + } + + } + return $glyphNumbers; + } + + /** + * Returns the glyph number corresponding to the Unicode character. + * + * If a particular character doesn't exist in this font, the special 'missing + * character glyph' will be substituted. + * + * See also {@link glyphNumbersForCharacters()} which is optimized for bulk + * operations. + * + * @param integer $characterCode Unicode character code (code point). + * @return integer Glyph number. + */ + public function glyphNumberForCharacter($characterCode) + { + /* This code is pretty much a copy of glyphNumbersForCharacters(). + * See that method for inline documentation. + */ + + if ($characterCode > 0xffff) { + return Zend_Pdf_Cmap::MISSING_CHARACTER_GLYPH; + } + + if ($this->_searchRangeEndCode >= $characterCode) { + $searchIndex = $this->_searchRange; + } else { + $searchIndex = $this->_segmentCount; + } + + for ($i = 1; $i <= $this->_searchIterations; $i++) { + if ($this->_segmentTableEndCodes[$searchIndex] >= $characterCode) { + $subtableIndex = $searchIndex; + $searchIndex -= $this->_searchRange >> $i; + } else { + $searchIndex += $this->_searchRange >> $i; + } + } + + if ($this->_segmentTableStartCodes[$subtableIndex] > $characterCode) { + return Zend_Pdf_Cmap::MISSING_CHARACTER_GLYPH; + } + + if ($this->_segmentTableIdRangeOffsets[$subtableIndex] == 0) { + $glyphNumber = ($characterCode + $this->_segmentTableIdDeltas[$subtableIndex]) % 65536; + } else { + $glyphIndex = ($characterCode - $this->_segmentTableStartCodes[$subtableIndex] + + $this->_segmentTableIdRangeOffsets[$subtableIndex] - $this->_segmentCount + + $subtableIndex - 1); + $glyphNumber = $this->_glyphIndexArray[$glyphIndex]; + } + return $glyphNumber; + } + + /** + * Returns an array containing the Unicode characters that have entries in + * this character map. + * + * @return array Unicode character codes. + */ + public function getCoveredCharacters() + { + $characterCodes = array(); + for ($i = 1; $i <= $this->_segmentCount; $i++) { + for ($code = $this->_segmentTableStartCodes[$i]; $code <= $this->_segmentTableEndCodes[$i]; $code++) { + $characterCodes[] = $code; + } + } + return $characterCodes; + } + + + /** + * Returns an array containing the glyphs numbers that have entries in this character map. + * Keys are Unicode character codes (integers) + * + * This functionality is partially covered by glyphNumbersForCharacters(getCoveredCharacters()) + * call, but this method do it in more effective way (prepare complete list instead of searching + * glyph for each character code). + * + * @internal + * @return array Array representing => pairs. + */ + public function getCoveredCharactersGlyphs() + { + $glyphNumbers = array(); + + for ($segmentNum = 1; $segmentNum <= $this->_segmentCount; $segmentNum++) { + if ($this->_segmentTableIdRangeOffsets[$segmentNum] == 0) { + $delta = $this->_segmentTableIdDeltas[$segmentNum]; + + for ($code = $this->_segmentTableStartCodes[$segmentNum]; + $code <= $this->_segmentTableEndCodes[$segmentNum]; + $code++) { + $glyphNumbers[$code] = ($code + $delta) % 65536; + } + } else { + $code = $this->_segmentTableStartCodes[$segmentNum]; + $glyphIndex = $this->_segmentTableIdRangeOffsets[$segmentNum] - ($this->_segmentCount - $segmentNum) - 1; + + while ($code <= $this->_segmentTableEndCodes[$segmentNum]) { + $glyphNumbers[$code] = $this->_glyphIndexArray[$glyphIndex]; + + $code++; + $glyphIndex++; + } + } + } + + return $glyphNumbers; + } + + + + /* Object Lifecycle */ + + /** + * Object constructor + * + * Parses the raw binary table data. Throws an exception if the table is + * malformed. + * + * @param string $cmapData Raw binary cmap table data. + * @throws Zend_Pdf_Exception + */ + public function __construct($cmapData) + { + /* Sanity check: The table should be at least 23 bytes in size. + */ + $actualLength = strlen($cmapData); + if ($actualLength < 23) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Insufficient table data', + Zend_Pdf_Exception::CMAP_TABLE_DATA_TOO_SMALL); + } + + /* Sanity check: Make sure this is right data for this table type. + */ + $type = $this->_extractUInt2($cmapData, 0); + if ($type != Zend_Pdf_Cmap::TYPE_SEGMENT_TO_DELTA) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Wrong cmap table type', + Zend_Pdf_Exception::CMAP_WRONG_TABLE_TYPE); + } + + $length = $this->_extractUInt2($cmapData, 2); + if ($length != $actualLength) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("Table length ($length) does not match actual length ($actualLength)", + Zend_Pdf_Exception::CMAP_WRONG_TABLE_LENGTH); + } + + /* Mapping tables should be language-independent. The font may not work + * as expected if they are not. Unfortunately, many font files in the + * wild incorrectly record a language ID in this field, so we can't + * call this a failure. + */ + $language = $this->_extractUInt2($cmapData, 4); + if ($language != 0) { + // Record a warning here somehow? + } + + /* These two values are stored premultiplied by two which is convienent + * when using the binary data directly, but we're parsing it out to + * native PHP data types, so divide by two. + */ + $this->_segmentCount = $this->_extractUInt2($cmapData, 6) >> 1; + $this->_searchRange = $this->_extractUInt2($cmapData, 8) >> 1; + + $this->_searchIterations = $this->_extractUInt2($cmapData, 10) + 1; + + $offset = 14; + for ($i = 1; $i <= $this->_segmentCount; $i++, $offset += 2) { + $this->_segmentTableEndCodes[$i] = $this->_extractUInt2($cmapData, $offset); + } + + $this->_searchRangeEndCode = $this->_segmentTableEndCodes[$this->_searchRange]; + + $offset += 2; // reserved bytes + + for ($i = 1; $i <= $this->_segmentCount; $i++, $offset += 2) { + $this->_segmentTableStartCodes[$i] = $this->_extractUInt2($cmapData, $offset); + } + + for ($i = 1; $i <= $this->_segmentCount; $i++, $offset += 2) { + $this->_segmentTableIdDeltas[$i] = $this->_extractInt2($cmapData, $offset); // signed + } + + /* The range offset helps determine the index into the glyph index array. + * Like the segment count and search range above, it's stored as a byte + * multiple in the font, so divide by two as we extract the values. + */ + for ($i = 1; $i <= $this->_segmentCount; $i++, $offset += 2) { + $this->_segmentTableIdRangeOffsets[$i] = $this->_extractUInt2($cmapData, $offset) >> 1; + } + + /* The size of the glyph index array varies by font and depends on the + * extent of the usage of range offsets versus deltas. Some fonts may + * not have any entries in this array. + */ + for (; $offset < $length; $offset += 2) { + $this->_glyphIndexArray[] = $this->_extractUInt2($cmapData, $offset); + } + + /* Sanity check: After reading all of the data, we should be at the end + * of the table. + */ + if ($offset != $length) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("Ending offset ($offset) does not match length ($length)", + Zend_Pdf_Exception::CMAP_FINAL_OFFSET_NOT_LENGTH); + } + } + +} diff --git a/library/Zend/Pdf/Cmap/TrimmedTable.php b/library/Zend/Pdf/Cmap/TrimmedTable.php new file mode 100644 index 0000000..c4baa3f --- /dev/null +++ b/library/Zend/Pdf/Cmap/TrimmedTable.php @@ -0,0 +1,231 @@ + $characterCode) { + + if (($characterCode < $this->_startCode) || ($characterCode > $this->_endCode)) { + $glyphNumbers[$key] = Zend_Pdf_Cmap::MISSING_CHARACTER_GLYPH; + continue; + } + + $glyphIndex = $characterCode - $this->_startCode; + $glyphNumbers[$key] = $this->_glyphIndexArray[$glyphIndex]; + + } + return $glyphNumbers; + } + + /** + * Returns the glyph number corresponding to the Unicode character. + * + * If a particular character doesn't exist in this font, the special 'missing + * character glyph' will be substituted. + * + * See also {@link glyphNumbersForCharacters()} which is optimized for bulk + * operations. + * + * @param integer $characterCode Unicode character code (code point). + * @return integer Glyph number. + */ + public function glyphNumberForCharacter($characterCode) + { + if (($characterCode < $this->_startCode) || ($characterCode > $this->_endCode)) { + return Zend_Pdf_Cmap::MISSING_CHARACTER_GLYPH; + } + $glyphIndex = $characterCode - $this->_startCode; + return $this->_glyphIndexArray[$glyphIndex]; + } + + /** + * Returns an array containing the Unicode characters that have entries in + * this character map. + * + * @return array Unicode character codes. + */ + public function getCoveredCharacters() + { + $characterCodes = array(); + for ($code = $this->_startCode; $code <= $this->_endCode; $code++) { + $characterCodes[] = $code; + } + return $characterCodes; + } + + + /** + * Returns an array containing the glyphs numbers that have entries in this character map. + * Keys are Unicode character codes (integers) + * + * This functionality is partially covered by glyphNumbersForCharacters(getCoveredCharacters()) + * call, but this method do it in more effective way (prepare complete list instead of searching + * glyph for each character code). + * + * @internal + * @return array Array representing => pairs. + */ + public function getCoveredCharactersGlyphs() + { + $glyphNumbers = array(); + for ($code = $this->_startCode; $code <= $this->_endCode; $code++) { + $glyphNumbers[$code] = $this->_glyphIndexArray[$code - $this->_startCode]; + } + + return $glyphNumbers; + } + + + /* Object Lifecycle */ + + /** + * Object constructor + * + * Parses the raw binary table data. Throws an exception if the table is + * malformed. + * + * @param string $cmapData Raw binary cmap table data. + * @throws Zend_Pdf_Exception + */ + public function __construct($cmapData) + { + /* Sanity check: The table should be at least 9 bytes in size. + */ + $actualLength = strlen($cmapData); + if ($actualLength < 9) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Insufficient table data', + Zend_Pdf_Exception::CMAP_TABLE_DATA_TOO_SMALL); + } + + /* Sanity check: Make sure this is right data for this table type. + */ + $type = $this->_extractUInt2($cmapData, 0); + if ($type != Zend_Pdf_Cmap::TYPE_TRIMMED_TABLE) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Wrong cmap table type', + Zend_Pdf_Exception::CMAP_WRONG_TABLE_TYPE); + } + + $length = $this->_extractUInt2($cmapData, 2); + if ($length != $actualLength) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("Table length ($length) does not match actual length ($actualLength)", + Zend_Pdf_Exception::CMAP_WRONG_TABLE_LENGTH); + } + + /* Mapping tables should be language-independent. The font may not work + * as expected if they are not. Unfortunately, many font files in the + * wild incorrectly record a language ID in this field, so we can't + * call this a failure. + */ + $language = $this->_extractUInt2($cmapData, 4); + if ($language != 0) { + // Record a warning here somehow? + } + + $this->_startCode = $this->_extractUInt2($cmapData, 6); + + $entryCount = $this->_extractUInt2($cmapData, 8); + $expectedCount = ($length - 10) >> 1; + if ($entryCount != $expectedCount) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("Entry count is wrong; expected: $expectedCount; actual: $entryCount", + Zend_Pdf_Exception::CMAP_WRONG_ENTRY_COUNT); + } + + $this->_endCode = $this->_startCode + $entryCount - 1; + + $offset = 10; + for ($i = 0; $i < $entryCount; $i++, $offset += 2) { + $this->_glyphIndexArray[] = $this->_extractUInt2($cmapData, $offset); + } + + /* Sanity check: After reading all of the data, we should be at the end + * of the table. + */ + if ($offset != $length) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("Ending offset ($offset) does not match length ($length)", + Zend_Pdf_Exception::CMAP_FINAL_OFFSET_NOT_LENGTH); + } + } + +} diff --git a/library/Zend/Pdf/Color.php b/library/Zend/Pdf/Color.php new file mode 100644 index 0000000..277a257 --- /dev/null +++ b/library/Zend/Pdf/Color.php @@ -0,0 +1,53 @@ + 1) { $c = 1; } + + if ($m < 0) { $m = 0; } + if ($m > 1) { $m = 1; } + + if ($y < 0) { $y = 0; } + if ($y > 1) { $y = 1; } + + if ($k < 0) { $k = 0; } + if ($k > 1) { $k = 1; } + + $this->_c = new Zend_Pdf_Element_Numeric($c); + $this->_m = new Zend_Pdf_Element_Numeric($m); + $this->_y = new Zend_Pdf_Element_Numeric($y); + $this->_k = new Zend_Pdf_Element_Numeric($k); + } + + /** + * Instructions, which can be directly inserted into content stream + * to switch color. + * Color set instructions differ for stroking and nonstroking operations. + * + * @param boolean $stroking + * @return string + */ + public function instructions($stroking) + { + return $this->_c->toString() . ' ' + . $this->_m->toString() . ' ' + . $this->_y->toString() . ' ' + . $this->_k->toString() . ($stroking? " K\n" : " k\n"); + } + + /** + * Get color components (color space dependent) + * + * @return array + */ + public function getComponents() + { + return array($this->_c->value, $this->_m->value, $this->_y->value, $this->_k->value); + } +} + diff --git a/library/Zend/Pdf/Color/GrayScale.php b/library/Zend/Pdf/Color/GrayScale.php new file mode 100644 index 0000000..2f09fdb --- /dev/null +++ b/library/Zend/Pdf/Color/GrayScale.php @@ -0,0 +1,84 @@ + 1) { $grayLevel = 1; } + + $this->_grayLevel = new Zend_Pdf_Element_Numeric($grayLevel); + } + + /** + * Instructions, which can be directly inserted into content stream + * to switch color. + * Color set instructions differ for stroking and nonstroking operations. + * + * @param boolean $stroking + * @return string + */ + public function instructions($stroking) + { + return $this->_grayLevel->toString() . ($stroking? " G\n" : " g\n"); + } + + /** + * Get color components (color space dependent) + * + * @return array + */ + public function getComponents() + { + return array($this->_grayLevel->value); + } +} + diff --git a/library/Zend/Pdf/Color/Html.php b/library/Zend/Pdf/Color/Html.php new file mode 100644 index 0000000..4dfac1b --- /dev/null +++ b/library/Zend/Pdf/Color/Html.php @@ -0,0 +1,412 @@ +_color = self::color($color); + } + + + /** + * Instructions, which can be directly inserted into content stream + * to switch color. + * Color set instructions differ for stroking and nonstroking operations. + * + * @param boolean $stroking + * @return string + */ + public function instructions($stroking) + { + return $this->_color->instructions($stroking); + } + + /** + * Get color components (color space dependent) + * + * @return array + */ + public function getComponents() + { + return $this->_color->getComponents(); + } + + /** + * Creates a Zend_Pdf_Color object from the HTML representation. + * + * @param string $color May either be a hexidecimal number of the form + * #rrggbb or one of the 140 well-known names (black, white, blue, etc.) + * @return Zend_Pdf_Color + */ + public static function color($color) + { + $pattern = '/^#([A-Fa-f0-9]{2})([A-Fa-f0-9]{2})([A-Fa-f0-9]{2})$/'; + if (preg_match($pattern, $color, $matches)) { + $r = round((hexdec($matches[1]) / 255), 3); + $g = round((hexdec($matches[2]) / 255), 3); + $b = round((hexdec($matches[3]) / 255), 3); + if (($r == $g) && ($g == $b)) { + // require_once 'Zend/Pdf/Color/GrayScale.php'; + return new Zend_Pdf_Color_GrayScale($r); + } else { + // require_once 'Zend/Pdf/Color/Rgb.php'; + return new Zend_Pdf_Color_Rgb($r, $g, $b); + } + } else { + return Zend_Pdf_Color_Html::namedColor($color); + } + } + + /** + * Creates a Zend_Pdf_Color object from the named color. + * + * @param string $color One of the 140 well-known color names (black, white, + * blue, etc.) + * @return Zend_Pdf_Color + */ + public static function namedColor($color) + { + switch (strtolower($color)) { + case 'aqua': + $r = 0.0; $g = 1.0; $b = 1.0; break; + case 'black': + $r = 0.0; $g = 0.0; $b = 0.0; break; + case 'blue': + $r = 0.0; $g = 0.0; $b = 1.0; break; + case 'fuchsia': + $r = 1.0; $g = 0.0; $b = 1.0; break; + case 'gray': + $r = 0.502; $g = 0.502; $b = 0.502; break; + case 'green': + $r = 0.0; $g = 0.502; $b = 0.0; break; + case 'lime': + $r = 0.0; $g = 1.0; $b = 0.0; break; + case 'maroon': + $r = 0.502; $g = 0.0; $b = 0.0; break; + case 'navy': + $r = 0.0; $g = 0.0; $b = 0.502; break; + case 'olive': + $r = 0.502; $g = 0.502; $b = 0.0; break; + case 'purple': + $r = 0.502; $g = 0.0; $b = 0.502; break; + case 'red': + $r = 1.0; $g = 0.0; $b = 0.0; break; + case 'silver': + $r = 0.753; $g = 0.753; $b = 0.753; break; + case 'teal': + $r = 0.0; $g = 0.502; $b = 0.502; break; + case 'white': + $r = 1.0; $g = 1.0; $b = 1.0; break; + case 'yellow': + $r = 1.0; $g = 1.0; $b = 0.0; break; + + case 'aliceblue': + $r = 0.941; $g = 0.973; $b = 1.0; break; + case 'antiquewhite': + $r = 0.980; $g = 0.922; $b = 0.843; break; + case 'aquamarine': + $r = 0.498; $g = 1.0; $b = 0.831; break; + case 'azure': + $r = 0.941; $g = 1.0; $b = 1.0; break; + case 'beige': + $r = 0.961; $g = 0.961; $b = 0.863; break; + case 'bisque': + $r = 1.0; $g = 0.894; $b = 0.769; break; + case 'blanchedalmond': + $r = 1.0; $g = 1.0; $b = 0.804; break; + case 'blueviolet': + $r = 0.541; $g = 0.169; $b = 0.886; break; + case 'brown': + $r = 0.647; $g = 0.165; $b = 0.165; break; + case 'burlywood': + $r = 0.871; $g = 0.722; $b = 0.529; break; + case 'cadetblue': + $r = 0.373; $g = 0.620; $b = 0.627; break; + case 'chartreuse': + $r = 0.498; $g = 1.0; $b = 0.0; break; + case 'chocolate': + $r = 0.824; $g = 0.412; $b = 0.118; break; + case 'coral': + $r = 1.0; $g = 0.498; $b = 0.314; break; + case 'cornflowerblue': + $r = 0.392; $g = 0.584; $b = 0.929; break; + case 'cornsilk': + $r = 1.0; $g = 0.973; $b = 0.863; break; + case 'crimson': + $r = 0.863; $g = 0.078; $b = 0.235; break; + case 'cyan': + $r = 0.0; $g = 1.0; $b = 1.0; break; + case 'darkblue': + $r = 0.0; $g = 0.0; $b = 0.545; break; + case 'darkcyan': + $r = 0.0; $g = 0.545; $b = 0.545; break; + case 'darkgoldenrod': + $r = 0.722; $g = 0.525; $b = 0.043; break; + case 'darkgray': + $r = 0.663; $g = 0.663; $b = 0.663; break; + case 'darkgreen': + $r = 0.0; $g = 0.392; $b = 0.0; break; + case 'darkkhaki': + $r = 0.741; $g = 0.718; $b = 0.420; break; + case 'darkmagenta': + $r = 0.545; $g = 0.0; $b = 0.545; break; + case 'darkolivegreen': + $r = 0.333; $g = 0.420; $b = 0.184; break; + case 'darkorange': + $r = 1.0; $g = 0.549; $b = 0.0; break; + case 'darkorchid': + $r = 0.6; $g = 0.196; $b = 0.8; break; + case 'darkred': + $r = 0.545; $g = 0.0; $b = 0.0; break; + case 'darksalmon': + $r = 0.914; $g = 0.588; $b = 0.478; break; + case 'darkseagreen': + $r = 0.561; $g = 0.737; $b = 0.561; break; + case 'darkslateblue': + $r = 0.282; $g = 0.239; $b = 0.545; break; + case 'darkslategray': + $r = 0.184; $g = 0.310; $b = 0.310; break; + case 'darkturquoise': + $r = 0.0; $g = 0.808; $b = 0.820; break; + case 'darkviolet': + $r = 0.580; $g = 0.0; $b = 0.827; break; + case 'deeppink': + $r = 1.0; $g = 0.078; $b = 0.576; break; + case 'deepskyblue': + $r = 0.0; $g = 0.749; $b = 1.0; break; + case 'dimgray': + $r = 0.412; $g = 0.412; $b = 0.412; break; + case 'dodgerblue': + $r = 0.118; $g = 0.565; $b = 1.0; break; + case 'firebrick': + $r = 0.698; $g = 0.133; $b = 0.133; break; + case 'floralwhite': + $r = 1.0; $g = 0.980; $b = 0.941; break; + case 'forestgreen': + $r = 0.133; $g = 0.545; $b = 0.133; break; + case 'gainsboro': + $r = 0.863; $g = 0.863; $b = 0.863; break; + case 'ghostwhite': + $r = 0.973; $g = 0.973; $b = 1.0; break; + case 'gold': + $r = 1.0; $g = 0.843; $b = 0.0; break; + case 'goldenrod': + $r = 0.855; $g = 0.647; $b = 0.125; break; + case 'greenyellow': + $r = 0.678; $g = 1.0; $b = 0.184; break; + case 'honeydew': + $r = 0.941; $g = 1.0; $b = 0.941; break; + case 'hotpink': + $r = 1.0; $g = 0.412; $b = 0.706; break; + case 'indianred': + $r = 0.804; $g = 0.361; $b = 0.361; break; + case 'indigo': + $r = 0.294; $g = 0.0; $b = 0.510; break; + case 'ivory': + $r = 1.0; $g = 0.941; $b = 0.941; break; + case 'khaki': + $r = 0.941; $g = 0.902; $b = 0.549; break; + case 'lavender': + $r = 0.902; $g = 0.902; $b = 0.980; break; + case 'lavenderblush': + $r = 1.0; $g = 0.941; $b = 0.961; break; + case 'lawngreen': + $r = 0.486; $g = 0.988; $b = 0.0; break; + case 'lemonchiffon': + $r = 1.0; $g = 0.980; $b = 0.804; break; + case 'lightblue': + $r = 0.678; $g = 0.847; $b = 0.902; break; + case 'lightcoral': + $r = 0.941; $g = 0.502; $b = 0.502; break; + case 'lightcyan': + $r = 0.878; $g = 1.0; $b = 1.0; break; + case 'lightgoldenrodyellow': + $r = 0.980; $g = 0.980; $b = 0.824; break; + case 'lightgreen': + $r = 0.565; $g = 0.933; $b = 0.565; break; + case 'lightgrey': + $r = 0.827; $g = 0.827; $b = 0.827; break; + case 'lightpink': + $r = 1.0; $g = 0.714; $b = 0.757; break; + case 'lightsalmon': + $r = 1.0; $g = 0.627; $b = 0.478; break; + case 'lightseagreen': + $r = 0.125; $g = 0.698; $b = 0.667; break; + case 'lightskyblue': + $r = 0.529; $g = 0.808; $b = 0.980; break; + case 'lightslategray': + $r = 0.467; $g = 0.533; $b = 0.6; break; + case 'lightsteelblue': + $r = 0.690; $g = 0.769; $b = 0.871; break; + case 'lightyellow': + $r = 1.0; $g = 1.0; $b = 0.878; break; + case 'limegreen': + $r = 0.196; $g = 0.804; $b = 0.196; break; + case 'linen': + $r = 0.980; $g = 0.941; $b = 0.902; break; + case 'magenta': + $r = 1.0; $g = 0.0; $b = 1.0; break; + case 'mediumaquamarine': + $r = 0.4; $g = 0.804; $b = 0.667; break; + case 'mediumblue': + $r = 0.0; $g = 0.0; $b = 0.804; break; + case 'mediumorchid': + $r = 0.729; $g = 0.333; $b = 0.827; break; + case 'mediumpurple': + $r = 0.576; $g = 0.439; $b = 0.859; break; + case 'mediumseagreen': + $r = 0.235; $g = 0.702; $b = 0.443; break; + case 'mediumslateblue': + $r = 0.482; $g = 0.408; $b = 0.933; break; + case 'mediumspringgreen': + $r = 0.0; $g = 0.980; $b = 0.604; break; + case 'mediumturquoise': + $r = 0.282; $g = 0.820; $b = 0.8; break; + case 'mediumvioletred': + $r = 0.780; $g = 0.082; $b = 0.522; break; + case 'midnightblue': + $r = 0.098; $g = 0.098; $b = 0.439; break; + case 'mintcream': + $r = 0.961; $g = 1.0; $b = 0.980; break; + case 'mistyrose': + $r = 1.0; $g = 0.894; $b = 0.882; break; + case 'moccasin': + $r = 1.0; $g = 0.894; $b = 0.710; break; + case 'navajowhite': + $r = 1.0; $g = 0.871; $b = 0.678; break; + case 'oldlace': + $r = 0.992; $g = 0.961; $b = 0.902; break; + case 'olivedrab': + $r = 0.420; $g = 0.557; $b = 0.137; break; + case 'orange': + $r = 1.0; $g = 0.647; $b = 0.0; break; + case 'orangered': + $r = 1.0; $g = 0.271; $b = 0.0; break; + case 'orchid': + $r = 0.855; $g = 0.439; $b = 0.839; break; + case 'palegoldenrod': + $r = 0.933; $g = 0.910; $b = 0.667; break; + case 'palegreen': + $r = 0.596; $g = 0.984; $b = 0.596; break; + case 'paleturquoise': + $r = 0.686; $g = 0.933; $b = 0.933; break; + case 'palevioletred': + $r = 0.859; $g = 0.439; $b = 0.576; break; + case 'papayawhip': + $r = 1.0; $g = 0.937; $b = 0.835; break; + case 'peachpuff': + $r = 1.0; $g = 0.937; $b = 0.835; break; + case 'peru': + $r = 0.804; $g = 0.522; $b = 0.247; break; + case 'pink': + $r = 1.0; $g = 0.753; $b = 0.796; break; + case 'plum': + $r = 0.867; $g = 0.627; $b = 0.867; break; + case 'powderblue': + $r = 0.690; $g = 0.878; $b = 0.902; break; + case 'rosybrown': + $r = 0.737; $g = 0.561; $b = 0.561; break; + case 'royalblue': + $r = 0.255; $g = 0.412; $b = 0.882; break; + case 'saddlebrown': + $r = 0.545; $g = 0.271; $b = 0.075; break; + case 'salmon': + $r = 0.980; $g = 0.502; $b = 0.447; break; + case 'sandybrown': + $r = 0.957; $g = 0.643; $b = 0.376; break; + case 'seagreen': + $r = 0.180; $g = 0.545; $b = 0.341; break; + case 'seashell': + $r = 1.0; $g = 0.961; $b = 0.933; break; + case 'sienna': + $r = 0.627; $g = 0.322; $b = 0.176; break; + case 'skyblue': + $r = 0.529; $g = 0.808; $b = 0.922; break; + case 'slateblue': + $r = 0.416; $g = 0.353; $b = 0.804; break; + case 'slategray': + $r = 0.439; $g = 0.502; $b = 0.565; break; + case 'snow': + $r = 1.0; $g = 0.980; $b = 0.980; break; + case 'springgreen': + $r = 0.0; $g = 1.0; $b = 0.498; break; + case 'steelblue': + $r = 0.275; $g = 0.510; $b = 0.706; break; + case 'tan': + $r = 0.824; $g = 0.706; $b = 0.549; break; + case 'thistle': + $r = 0.847; $g = 0.749; $b = 0.847; break; + case 'tomato': + $r = 0.992; $g = 0.388; $b = 0.278; break; + case 'turquoise': + $r = 0.251; $g = 0.878; $b = 0.816; break; + case 'violet': + $r = 0.933; $g = 0.510; $b = 0.933; break; + case 'wheat': + $r = 0.961; $g = 0.871; $b = 0.702; break; + case 'whitesmoke': + $r = 0.961; $g = 0.961; $b = 0.961; break; + case 'yellowgreen': + $r = 0.604; $g = 0.804; $b = 0.196; break; + + default: + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Unknown color name: ' . $color); + } + if (($r == $g) && ($g == $b)) { + // require_once 'Zend/Pdf/Color/GrayScale.php'; + return new Zend_Pdf_Color_GrayScale($r); + } else { + // require_once 'Zend/Pdf/Color/Rgb.php'; + return new Zend_Pdf_Color_Rgb($r, $g, $b); + } + } +} diff --git a/library/Zend/Pdf/Color/Rgb.php b/library/Zend/Pdf/Color/Rgb.php new file mode 100644 index 0000000..1df2a04 --- /dev/null +++ b/library/Zend/Pdf/Color/Rgb.php @@ -0,0 +1,114 @@ + 1) { $r = 1; } + + if ($g < 0) { $g = 0; } + if ($g > 1) { $g = 1; } + + if ($b < 0) { $b = 0; } + if ($b > 1) { $b = 1; } + + $this->_r = new Zend_Pdf_Element_Numeric($r); + $this->_g = new Zend_Pdf_Element_Numeric($g); + $this->_b = new Zend_Pdf_Element_Numeric($b); + } + + /** + * Instructions, which can be directly inserted into content stream + * to switch color. + * Color set instructions differ for stroking and nonstroking operations. + * + * @param boolean $stroking + * @return string + */ + public function instructions($stroking) + { + return $this->_r->toString() . ' ' + . $this->_g->toString() . ' ' + . $this->_b->toString() . ($stroking? " RG\n" : " rg\n"); + } + + /** + * Get color components (color space dependent) + * + * @return array + */ + public function getComponents() + { + return array($this->_r->value, $this->_g->value, $this->_b->value); + } +} + diff --git a/library/Zend/Pdf/Destination.php b/library/Zend/Pdf/Destination.php new file mode 100644 index 0000000..9439b05 --- /dev/null +++ b/library/Zend/Pdf/Destination.php @@ -0,0 +1,113 @@ +getType() == Zend_Pdf_Element::TYPE_NAME || $resource->getType() == Zend_Pdf_Element::TYPE_STRING) { + // require_once 'Zend/Pdf/Destination/Named.php'; + return new Zend_Pdf_Destination_Named($resource); + } + + if ($resource->getType() != Zend_Pdf_Element::TYPE_ARRAY) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('An explicit destination must be a direct or an indirect array object.'); + } + if (count($resource->items) < 2) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('An explicit destination array must contain at least two elements.'); + } + + switch ($resource->items[1]->value) { + case 'XYZ': + // require_once 'Zend/Pdf/Destination/Zoom.php'; + return new Zend_Pdf_Destination_Zoom($resource); + break; + + case 'Fit': + // require_once 'Zend/Pdf/Destination/Fit.php'; + return new Zend_Pdf_Destination_Fit($resource); + break; + + case 'FitH': + // require_once 'Zend/Pdf/Destination/FitHorizontally.php'; + return new Zend_Pdf_Destination_FitHorizontally($resource); + break; + + case 'FitV': + // require_once 'Zend/Pdf/Destination/FitVertically.php'; + return new Zend_Pdf_Destination_FitVertically($resource); + break; + + case 'FitR': + // require_once 'Zend/Pdf/Destination/FitRectangle.php'; + return new Zend_Pdf_Destination_FitRectangle($resource); + break; + + case 'FitB': + // require_once 'Zend/Pdf/Destination/FitBoundingBox.php'; + return new Zend_Pdf_Destination_FitBoundingBox($resource); + break; + + case 'FitBH': + // require_once 'Zend/Pdf/Destination/FitBoundingBoxHorizontally.php'; + return new Zend_Pdf_Destination_FitBoundingBoxHorizontally($resource); + break; + + case 'FitBV': + // require_once 'Zend/Pdf/Destination/FitBoundingBoxVertically.php'; + return new Zend_Pdf_Destination_FitBoundingBoxVertically($resource); + break; + + default: + // require_once 'Zend/Pdf/Destination/Unknown.php'; + return new Zend_Pdf_Destination_Unknown($resource); + break; + } + } +} diff --git a/library/Zend/Pdf/Destination/Explicit.php b/library/Zend/Pdf/Destination/Explicit.php new file mode 100644 index 0000000..f732d09 --- /dev/null +++ b/library/Zend/Pdf/Destination/Explicit.php @@ -0,0 +1,122 @@ +getType() != Zend_Pdf_Element::TYPE_ARRAY) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Explicit destination resource Array must be a direct or an indirect array object.'); + } + + $this->_destinationArray = $destinationArray; + + switch (count($this->_destinationArray->items)) { + case 0: + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Destination array must contain a page reference.'); + break; + + case 1: + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Destination array must contain a destination type name.'); + break; + + default: + // Do nothing + break; + } + + switch ($this->_destinationArray->items[0]->getType()) { + case Zend_Pdf_Element::TYPE_NUMERIC: + $this->_isRemote = true; + break; + + case Zend_Pdf_Element::TYPE_DICTIONARY: + $this->_isRemote = false; + break; + + default: + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Destination target must be a page number or page dictionary object.'); + break; + } + } + + /** + * Returns true if it's a remote destination + * + * @return boolean + */ + public function isRemote() + { + return $this->_isRemote; + } + + /** + * Get resource + * + * @internal + * @return Zend_Pdf_Element + */ + public function getResource() + { + return $this->_destinationArray; + } +} diff --git a/library/Zend/Pdf/Destination/Fit.php b/library/Zend/Pdf/Destination/Fit.php new file mode 100644 index 0000000..d26c3cc --- /dev/null +++ b/library/Zend/Pdf/Destination/Fit.php @@ -0,0 +1,75 @@ +items[] = $page->getPageDictionary(); + } else if (is_integer($page)) { + $destinationArray->items[] = new Zend_Pdf_Element_Numeric($page); + } else { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Page entry must be a Zend_Pdf_Page object or a page number.'); + } + + $destinationArray->items[] = new Zend_Pdf_Element_Name('Fit'); + + return new Zend_Pdf_Destination_Fit($destinationArray); + } +} diff --git a/library/Zend/Pdf/Destination/FitBoundingBox.php b/library/Zend/Pdf/Destination/FitBoundingBox.php new file mode 100644 index 0000000..0f5246a --- /dev/null +++ b/library/Zend/Pdf/Destination/FitBoundingBox.php @@ -0,0 +1,75 @@ +items[] = $page->getPageDictionary(); + } else if (is_integer($page)) { + $destinationArray->items[] = new Zend_Pdf_Element_Numeric($page); + } else { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Page entry must be a Zend_Pdf_Page object or a page number.'); + } + + $destinationArray->items[] = new Zend_Pdf_Element_Name('FitB'); + + return new Zend_Pdf_Destination_FitBoundingBox($destinationArray); + } +} diff --git a/library/Zend/Pdf/Destination/FitBoundingBoxHorizontally.php b/library/Zend/Pdf/Destination/FitBoundingBoxHorizontally.php new file mode 100644 index 0000000..692b514 --- /dev/null +++ b/library/Zend/Pdf/Destination/FitBoundingBoxHorizontally.php @@ -0,0 +1,98 @@ +items[] = $page->getPageDictionary(); + } else if (is_integer($page)) { + $destinationArray->items[] = new Zend_Pdf_Element_Numeric($page); + } else { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Page entry must be a Zend_Pdf_Page object or a page number.'); + } + + $destinationArray->items[] = new Zend_Pdf_Element_Name('FitBH'); + $destinationArray->items[] = new Zend_Pdf_Element_Numeric($top); + + return new Zend_Pdf_Destination_FitBoundingBoxHorizontally($destinationArray); + } + + /** + * Get top edge of the displayed page + * + * @return float + */ + public function getTopEdge() + { + return $this->_destinationArray->items[2]->value; + } + + /** + * Set top edge of the displayed page + * + * @param float $top + * @return Zend_Pdf_Action_FitBoundingBoxHorizontally + */ + public function setTopEdge($top) + { + $this->_destinationArray->items[2] = new Zend_Pdf_Element_Numeric($top); + return $this; + } +} diff --git a/library/Zend/Pdf/Destination/FitBoundingBoxVertically.php b/library/Zend/Pdf/Destination/FitBoundingBoxVertically.php new file mode 100644 index 0000000..33a6c7c --- /dev/null +++ b/library/Zend/Pdf/Destination/FitBoundingBoxVertically.php @@ -0,0 +1,98 @@ +items[] = $page->getPageDictionary(); + } else if (is_integer($page)) { + $destinationArray->items[] = new Zend_Pdf_Element_Numeric($page); + } else { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Page entry must be a Zend_Pdf_Page object or a page number.'); + } + + $destinationArray->items[] = new Zend_Pdf_Element_Name('FitBV'); + $destinationArray->items[] = new Zend_Pdf_Element_Numeric($left); + + return new Zend_Pdf_Destination_FitBoundingBoxVertically($destinationArray); + } + + /** + * Get left edge of the displayed page + * + * @return float + */ + public function getLeftEdge() + { + return $this->_destinationArray->items[2]->value; + } + + /** + * Set left edge of the displayed page + * + * @param float $left + * @return Zend_Pdf_Action_FitBoundingBoxVertically + */ + public function setLeftEdge($left) + { + $this->_destinationArray->items[2] = new Zend_Pdf_Element_Numeric($left); + return $this; + } + +} diff --git a/library/Zend/Pdf/Destination/FitHorizontally.php b/library/Zend/Pdf/Destination/FitHorizontally.php new file mode 100644 index 0000000..98116e2 --- /dev/null +++ b/library/Zend/Pdf/Destination/FitHorizontally.php @@ -0,0 +1,98 @@ +items[] = $page->getPageDictionary(); + } else if (is_integer($page)) { + $destinationArray->items[] = new Zend_Pdf_Element_Numeric($page); + } else { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Page entry must be a Zend_Pdf_Page object or a page number.'); + } + + $destinationArray->items[] = new Zend_Pdf_Element_Name('FitH'); + $destinationArray->items[] = new Zend_Pdf_Element_Numeric($top); + + return new Zend_Pdf_Destination_FitHorizontally($destinationArray); + } + + /** + * Get top edge of the displayed page + * + * @return float + */ + public function getTopEdge() + { + return $this->_destinationArray->items[2]->value; + } + + /** + * Set top edge of the displayed page + * + * @param float $top + * @return Zend_Pdf_Action_FitHorizontally + */ + public function setTopEdge($top) + { + $this->_destinationArray->items[2] = new Zend_Pdf_Element_Numeric($top); + + return $this; + } +} diff --git a/library/Zend/Pdf/Destination/FitRectangle.php b/library/Zend/Pdf/Destination/FitRectangle.php new file mode 100644 index 0000000..841eaa1 --- /dev/null +++ b/library/Zend/Pdf/Destination/FitRectangle.php @@ -0,0 +1,171 @@ +items[] = $page->getPageDictionary(); + } else if (is_integer($page)) { + $destinationArray->items[] = new Zend_Pdf_Element_Numeric($page); + } else { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Page entry must be a Zend_Pdf_Page object or a page number.'); + } + + $destinationArray->items[] = new Zend_Pdf_Element_Name('FitR'); + $destinationArray->items[] = new Zend_Pdf_Element_Numeric($left); + $destinationArray->items[] = new Zend_Pdf_Element_Numeric($bottom); + $destinationArray->items[] = new Zend_Pdf_Element_Numeric($right); + $destinationArray->items[] = new Zend_Pdf_Element_Numeric($top); + + return new Zend_Pdf_Destination_FitRectangle($destinationArray); + } + + /** + * Get left edge of the displayed page + * + * @return float + */ + public function getLeftEdge() + { + return $this->_destinationArray->items[2]->value; + } + + /** + * Set left edge of the displayed page + * + * @param float $left + * @return Zend_Pdf_Action_FitRectangle + */ + public function setLeftEdge($left) + { + $this->_destinationArray->items[2] = new Zend_Pdf_Element_Numeric($left); + return $this; + } + + /** + * Get bottom edge of the displayed page + * + * @return float + */ + public function getBottomEdge() + { + return $this->_destinationArray->items[3]->value; + } + + /** + * Set bottom edge of the displayed page + * + * @param float $bottom + * @return Zend_Pdf_Action_FitRectangle + */ + public function setBottomEdge($bottom) + { + $this->_destinationArray->items[3] = new Zend_Pdf_Element_Numeric($bottom); + return $this; + } + + /** + * Get right edge of the displayed page + * + * @return float + */ + public function getRightEdge() + { + return $this->_destinationArray->items[4]->value; + } + + /** + * Set right edge of the displayed page + * + * @param float $right + * @return Zend_Pdf_Action_FitRectangle + */ + public function setRightEdge($right) + { + $this->_destinationArray->items[4] = new Zend_Pdf_Element_Numeric($right); + return $this; + } + + /** + * Get top edge of the displayed page + * + * @return float + */ + public function getTopEdge() + { + return $this->_destinationArray->items[5]->value; + } + + /** + * Set top edge of the displayed page + * + * @param float $top + * @return Zend_Pdf_Action_FitRectangle + */ + public function setTopEdge($top) + { + $this->_destinationArray->items[5] = new Zend_Pdf_Element_Numeric($top); + return $this; + } +} diff --git a/library/Zend/Pdf/Destination/FitVertically.php b/library/Zend/Pdf/Destination/FitVertically.php new file mode 100644 index 0000000..806a344 --- /dev/null +++ b/library/Zend/Pdf/Destination/FitVertically.php @@ -0,0 +1,98 @@ +items[] = $page->getPageDictionary(); + } else if (is_integer($page)) { + $destinationArray->items[] = new Zend_Pdf_Element_Numeric($page); + } else { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Page entry must be a Zend_Pdf_Page object or page number.'); + } + + $destinationArray->items[] = new Zend_Pdf_Element_Name('FitV'); + $destinationArray->items[] = new Zend_Pdf_Element_Numeric($left); + + return new Zend_Pdf_Destination_FitVertically($destinationArray); + } + + /** + * Get left edge of the displayed page + * + * @return float + */ + public function getLeftEdge() + { + return $this->_destinationArray->items[2]->value; + } + + /** + * Set left edge of the displayed page + * + * @param float $left + * @return Zend_Pdf_Action_FitVertically + */ + public function setLeftEdge($left) + { + $this->_destinationArray->items[2] = new Zend_Pdf_Element_Numeric($left); + + return $this; + } +} diff --git a/library/Zend/Pdf/Destination/Named.php b/library/Zend/Pdf/Destination/Named.php new file mode 100644 index 0000000..f7db3db --- /dev/null +++ b/library/Zend/Pdf/Destination/Named.php @@ -0,0 +1,101 @@ +getType() != Zend_Pdf_Element::TYPE_NAME && $resource->getType() != Zend_Pdf_Element::TYPE_STRING) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Named destination resource must be a PDF name or a PDF string.'); + } + + $this->_nameElement = $resource; + } + + /** + * Create named destination object + * + * @param string $name + * @return Zend_Pdf_Destination_Named + */ + public static function create($name) + { + return new Zend_Pdf_Destination_Named(new Zend_Pdf_Element_String($name)); + } + + /** + * Get name + * + * @return Zend_Pdf_Element + */ + public function getName() + { + return $this->_nameElement->value; + } + + /** + * Get resource + * + * @internal + * @return Zend_Pdf_Element + */ + public function getResource() + { + return $this->_nameElement; + } +} diff --git a/library/Zend/Pdf/Destination/Unknown.php b/library/Zend/Pdf/Destination/Unknown.php new file mode 100644 index 0000000..726276e --- /dev/null +++ b/library/Zend/Pdf/Destination/Unknown.php @@ -0,0 +1,37 @@ +items[] = $page->getPageDictionary(); + } else if (is_integer($page)) { + $destinationArray->items[] = new Zend_Pdf_Element_Numeric($page); + } else { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Page entry must be a Zend_Pdf_Page object or a page number.'); + } + + $destinationArray->items[] = new Zend_Pdf_Element_Name('XYZ'); + + if ($left === null) { + $destinationArray->items[] = new Zend_Pdf_Element_Null(); + } else { + $destinationArray->items[] = new Zend_Pdf_Element_Numeric($left); + } + + if ($top === null) { + $destinationArray->items[] = new Zend_Pdf_Element_Null(); + } else { + $destinationArray->items[] = new Zend_Pdf_Element_Numeric($top); + } + + if ($zoom === null) { + $destinationArray->items[] = new Zend_Pdf_Element_Null(); + } else { + $destinationArray->items[] = new Zend_Pdf_Element_Numeric($zoom); + } + + return new Zend_Pdf_Destination_Zoom($destinationArray); + } + + /** + * Get left edge of the displayed page (null means viewer application 'current value') + * + * @return float + */ + public function getLeftEdge() + { + return $this->_destinationArray->items[2]->value; + } + + /** + * Set left edge of the displayed page (null means viewer application 'current value') + * + * @param float $left + * @return Zend_Pdf_Action_Zoom + */ + public function setLeftEdge($left) + { + if ($left === null) { + $this->_destinationArray->items[2] = new Zend_Pdf_Element_Null(); + } else { + $this->_destinationArray->items[2] = new Zend_Pdf_Element_Numeric($left); + } + + return $this; + } + + /** + * Get top edge of the displayed page (null means viewer application 'current value') + * + * @return float + */ + public function getTopEdge() + { + return $this->_destinationArray->items[3]->value; + } + + /** + * Set top edge of the displayed page (null means viewer application 'current viewer') + * + * @param float $top + * @return Zend_Pdf_Action_Zoom + */ + public function setTopEdge($top) + { + if ($top === null) { + $this->_destinationArray->items[3] = new Zend_Pdf_Element_Null(); + } else { + $this->_destinationArray->items[3] = new Zend_Pdf_Element_Numeric($top); + } + + return $this; + } + + /** + * Get ZoomFactor of the displayed page (null or 0 means viewer application 'current value') + * + * @return float + */ + public function getZoomFactor() + { + return $this->_destinationArray->items[4]->value; + } + + /** + * Set ZoomFactor of the displayed page (null or 0 means viewer application 'current viewer') + * + * @param float $zoom + * @return Zend_Pdf_Action_Zoom + */ + public function setZoomFactor($zoom) + { + if ($zoom === null) { + $this->_destinationArray->items[4] = new Zend_Pdf_Element_Null(); + } else { + $this->_destinationArray->items[4] = new Zend_Pdf_Element_Numeric($zoom); + } + + return $this; + } +} diff --git a/library/Zend/Pdf/Element.php b/library/Zend/Pdf/Element.php new file mode 100644 index 0000000..f7f11ed --- /dev/null +++ b/library/Zend/Pdf/Element.php @@ -0,0 +1,176 @@ +_parentObject = $parent; + } + + + /** + * Get top level parent indirect object. + * + * @return Zend_Pdf_Element_Object + */ + public function getParentObject() + { + return $this->_parentObject; + } + + + /** + * Mark object as modified, to include it into new PDF file segment. + * + * We don't automate this action to keep control on PDF update process. + * All new objects are treated as "modified" automatically. + */ + public function touch() + { + if ($this->_parentObject !== null) { + $this->_parentObject->touch(); + } + } + + /** + * Clean up resources, used by object + */ + public function cleanUp() + { + // Do nothing + } + + /** + * Convert PDF element to PHP type. + * + * @return mixed + */ + public function toPhp() + { + return $this->value; + } + + /** + * Convert PHP value into PDF element. + * + * @param mixed $input + * @return Zend_Pdf_Element + */ + public static function phpToPdf($input) + { + if (is_numeric($input)) { + // require_once 'Zend/Pdf/Element/Numeric.php'; + return new Zend_Pdf_Element_Numeric($input); + } else if (is_bool($input)) { + // require_once 'Zend/Pdf/Element/Boolean.php'; + return new Zend_Pdf_Element_Boolean($input); + } else if (is_array($input)) { + $pdfElementsArray = array(); + $isDictionary = false; + + foreach ($input as $key => $value) { + if (is_string($key)) { + $isDictionary = true; + } + $pdfElementsArray[$key] = Zend_Pdf_Element::phpToPdf($value); + } + + if ($isDictionary) { + // require_once 'Zend/Pdf/Element/Dictionary.php'; + return new Zend_Pdf_Element_Dictionary($pdfElementsArray); + } else { + // require_once 'Zend/Pdf/Element/Array.php'; + return new Zend_Pdf_Element_Array($pdfElementsArray); + } + } else { + // require_once 'Zend/Pdf/Element/String.php'; + return new Zend_Pdf_Element_String((string)$input); + } + } +} diff --git a/library/Zend/Pdf/Element/Array.php b/library/Zend/Pdf/Element/Array.php new file mode 100644 index 0000000..4c67a5e --- /dev/null +++ b/library/Zend/Pdf/Element/Array.php @@ -0,0 +1,181 @@ +items = new ArrayObject(); + + if ($val !== null && is_array($val)) { + foreach ($val as $element) { + if (!$element instanceof Zend_Pdf_Element) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Array elements must be Zend_Pdf_Element objects'); + } + $this->items[] = $element; + } + } else if ($val !== null){ + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Argument must be an array'); + } + } + + + /** + * Getter + * + * @param string $property + * @throws Zend_Pdf_Exception + */ + public function __get($property) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Undefined property: Zend_Pdf_Element_Array::$' . $property); + } + + + /** + * Setter + * + * @param mixed $offset + * @param mixed $value + * @throws Zend_Pdf_Exception + */ + public function __set($property, $value) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Undefined property: Zend_Pdf_Element_Array::$' . $property); + } + + /** + * Return type of the element. + * + * @return integer + */ + public function getType() + { + return Zend_Pdf_Element::TYPE_ARRAY; + } + + + /** + * Return object as string + * + * @param Zend_Pdf_Factory $factory + * @return string + */ + public function toString($factory = null) + { + $outStr = '['; + $lastNL = 0; + + foreach ($this->items as $element) { + if (strlen($outStr) - $lastNL > 128) { + $outStr .= "\n"; + $lastNL = strlen($outStr); + } + + $outStr .= $element->toString($factory) . ' '; + } + $outStr .= ']'; + + return $outStr; + } + + /** + * Detach PDF object from the factory (if applicable), clone it and attach to new factory. + * + * @param Zend_Pdf_ElementFactory $factory The factory to attach + * @param array &$processed List of already processed indirect objects, used to avoid objects duplication + * @param integer $mode Cloning mode (defines filter for objects cloning) + * @returns Zend_Pdf_Element + */ + public function makeClone(Zend_Pdf_ElementFactory $factory, array &$processed, $mode) + { + $newArray = new self(); + + foreach ($this->items as $key => $value) { + $newArray->items[$key] = $value->makeClone($factory, $processed, $mode); + } + + return $newArray; + } + + /** + * Set top level parent indirect object. + * + * @param Zend_Pdf_Element_Object $parent + */ + public function setParentObject(Zend_Pdf_Element_Object $parent) + { + parent::setParentObject($parent); + + foreach ($this->items as $item) { + $item->setParentObject($parent); + } + } + + /** + * Convert PDF element to PHP type. + * + * Dictionary is returned as an associative array + * + * @return mixed + */ + public function toPhp() + { + $phpArray = array(); + + foreach ($this->items as $item) { + $phpArray[] = $item->toPhp(); + } + + return $phpArray; + } +} diff --git a/library/Zend/Pdf/Element/Boolean.php b/library/Zend/Pdf/Element/Boolean.php new file mode 100644 index 0000000..f0b30d4 --- /dev/null +++ b/library/Zend/Pdf/Element/Boolean.php @@ -0,0 +1,83 @@ +value = $val; + } + + + /** + * Return type of the element. + * + * @return integer + */ + public function getType() + { + return Zend_Pdf_Element::TYPE_BOOL; + } + + + /** + * Return object as string + * + * @param Zend_Pdf_Factory $factory + * @return string + */ + public function toString($factory = null) + { + return $this->value ? 'true' : 'false'; + } +} diff --git a/library/Zend/Pdf/Element/Dictionary.php b/library/Zend/Pdf/Element/Dictionary.php new file mode 100644 index 0000000..214a4c8 --- /dev/null +++ b/library/Zend/Pdf/Element/Dictionary.php @@ -0,0 +1,236 @@ + Zend_Pdf_Element) + * + * @var array + */ + private $_items = array(); + + + /** + * Object constructor + * + * @param array $val - array of Zend_Pdf_Element objects + * @throws Zend_Pdf_Exception + */ + public function __construct($val = null) + { + if ($val === null) { + return; + } else if (!is_array($val)) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Argument must be an array'); + } + + foreach ($val as $name => $element) { + if (!$element instanceof Zend_Pdf_Element) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Array elements must be Zend_Pdf_Element objects'); + } + if (!is_string($name)) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Array keys must be strings'); + } + $this->_items[$name] = $element; + } + } + + + /** + * Add element to an array + * + * @name Zend_Pdf_Element_Name $name + * @param Zend_Pdf_Element $val - Zend_Pdf_Element object + * @throws Zend_Pdf_Exception + */ + public function add(Zend_Pdf_Element_Name $name, Zend_Pdf_Element $val) + { + $this->_items[$name->value] = $val; + } + + /** + * Return dictionary keys + * + * @return array + */ + public function getKeys() + { + return array_keys($this->_items); + } + + + /** + * Get handler + * + * @param string $property + * @return Zend_Pdf_Element | null + */ + public function __get($item) + { + $element = isset($this->_items[$item]) ? $this->_items[$item] + : null; + + return $element; + } + + /** + * Set handler + * + * @param string $property + * @param mixed $value + */ + public function __set($item, $value) + { + if ($value === null) { + unset($this->_items[$item]); + } else { + $this->_items[$item] = $value; + } + } + + /** + * Return type of the element. + * + * @return integer + */ + public function getType() + { + return Zend_Pdf_Element::TYPE_DICTIONARY; + } + + + /** + * Return object as string + * + * @param Zend_Pdf_Factory $factory + * @return string + */ + public function toString($factory = null) + { + $outStr = '<<'; + $lastNL = 0; + + foreach ($this->_items as $name => $element) { + if (!is_object($element)) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Wrong data'); + } + + if (strlen($outStr) - $lastNL > 128) { + $outStr .= "\n"; + $lastNL = strlen($outStr); + } + + $nameObj = new Zend_Pdf_Element_Name($name); + $outStr .= $nameObj->toString($factory) . ' ' . $element->toString($factory) . ' '; + } + $outStr .= '>>'; + + return $outStr; + } + + /** + * Detach PDF object from the factory (if applicable), clone it and attach to new factory. + * + * @param Zend_Pdf_ElementFactory $factory The factory to attach + * @param array &$processed List of already processed indirect objects, used to avoid objects duplication + * @param integer $mode Cloning mode (defines filter for objects cloning) + * @returns Zend_Pdf_Element + * @throws Zend_Pdf_Exception + */ + public function makeClone(Zend_Pdf_ElementFactory $factory, array &$processed, $mode) + { + if (isset($this->_items['Type'])) { + if ($this->_items['Type']->value == 'Pages') { + // It's a page tree node + // skip it and its children + return new Zend_Pdf_Element_Null(); + } + + if ($this->_items['Type']->value == 'Page' && + $mode == Zend_Pdf_Element::CLONE_MODE_SKIP_PAGES + ) { + // It's a page node, skip it + return new Zend_Pdf_Element_Null(); + } + } + + $newDictionary = new self(); + foreach ($this->_items as $key => $value) { + $newDictionary->_items[$key] = $value->makeClone($factory, $processed, $mode); + } + + return $newDictionary; + } + + /** + * Set top level parent indirect object. + * + * @param Zend_Pdf_Element_Object $parent + */ + public function setParentObject(Zend_Pdf_Element_Object $parent) + { + parent::setParentObject($parent); + + foreach ($this->_items as $item) { + $item->setParentObject($parent); + } + } + + /** + * Convert PDF element to PHP type. + * + * Dictionary is returned as an associative array + * + * @return mixed + */ + public function toPhp() + { + $phpArray = array(); + + foreach ($this->_items as $itemName => $item) { + $phpArray[$itemName] = $item->toPhp(); + } + + return $phpArray; + } +} diff --git a/library/Zend/Pdf/Element/Name.php b/library/Zend/Pdf/Element/Name.php new file mode 100644 index 0000000..35cd856 --- /dev/null +++ b/library/Zend/Pdf/Element/Name.php @@ -0,0 +1,161 @@ +value = (string)$val; + } + + + /** + * Return type of the element. + * + * @return integer + */ + public function getType() + { + return Zend_Pdf_Element::TYPE_NAME; + } + + + /** + * Escape string according to the PDF rules + * + * @param string $inStr + * @return string + */ + public static function escape($inStr) + { + $outStr = ''; + + for ($count = 0; $count < strlen($inStr); $count++) { + $nextCode = ord($inStr[$count]); + + switch ($inStr[$count]) { + case '(': + // fall through to next case + case ')': + // fall through to next case + case '<': + // fall through to next case + case '>': + // fall through to next case + case '[': + // fall through to next case + case ']': + // fall through to next case + case '{': + // fall through to next case + case '}': + // fall through to next case + case '/': + // fall through to next case + case '%': + // fall through to next case + case '\\': + // fall through to next case + case '#': + $outStr .= sprintf('#%02X', $nextCode); + break; + + default: + if ($nextCode >= 33 && $nextCode <= 126 ) { + // Visible ASCII symbol + $outStr .= $inStr[$count]; + } else { + $outStr .= sprintf('#%02X', $nextCode); + } + } + + } + + return $outStr; + } + + + /** + * Unescape string according to the PDF rules + * + * @param string $inStr + * @return string + */ + public static function unescape($inStr) + { + $outStr = ''; + + for ($count = 0; $count < strlen($inStr); $count++) { + if ($inStr[$count] != '#' ) { + $outStr .= $inStr[$count]; + } else { + // Escape sequence + $outStr .= chr(base_convert(substr($inStr, $count+1, 2), 16, 10 )); + $count +=2; + } + } + return $outStr; + } + + + /** + * Return object as string + * + * @param Zend_Pdf_Factory $factory + * @return string + */ + public function toString($factory = null) + { + return '/' . self::escape((string)$this->value); + } +} diff --git a/library/Zend/Pdf/Element/Null.php b/library/Zend/Pdf/Element/Null.php new file mode 100644 index 0000000..dbc976f --- /dev/null +++ b/library/Zend/Pdf/Element/Null.php @@ -0,0 +1,75 @@ +value = null; + } + + + /** + * Return type of the element. + * + * @return integer + */ + public function getType() + { + return Zend_Pdf_Element::TYPE_NULL; + } + + + /** + * Return object as string + * + * @param Zend_Pdf_Factory $factory + * @return string + */ + public function toString($factory = null) + { + return 'null'; + } +} diff --git a/library/Zend/Pdf/Element/Numeric.php b/library/Zend/Pdf/Element/Numeric.php new file mode 100644 index 0000000..175f31f --- /dev/null +++ b/library/Zend/Pdf/Element/Numeric.php @@ -0,0 +1,95 @@ +value = $val; + } + + + /** + * Return type of the element. + * + * @return integer + */ + public function getType() + { + return Zend_Pdf_Element::TYPE_NUMERIC; + } + + + /** + * Return object as string + * + * @param Zend_Pdf_Factory $factory + * @return string + */ + public function toString($factory = null) + { + if (is_integer($this->value)) { + return (string)$this->value; + } + + /** + * PDF doesn't support exponental format. + * Fixed point format must be used instead + */ + $prec = 0; $v = $this->value; + while (abs( floor($v) - $v ) > 1e-10) { + $prec++; $v *= 10; + } + return sprintf("%.{$prec}F", $this->value); + } +} diff --git a/library/Zend/Pdf/Element/Object.php b/library/Zend/Pdf/Element/Object.php new file mode 100644 index 0000000..23d83a2 --- /dev/null +++ b/library/Zend/Pdf/Element/Object.php @@ -0,0 +1,284 @@ + 0) ) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Object number must be positive integer.'); + } + + if ( !(is_integer($genNum) && $genNum >= 0) ) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Generation number must be non-negative integer.'); + } + + $this->_value = $val; + $this->_objNum = $objNum; + $this->_genNum = $genNum; + $this->_factory = $factory; + + $this->setParentObject($this); + + $factory->registerObject($this, $objNum . ' ' . $genNum); + } + + + /** + * Check, that object is generated by specified factory + * + * @return Zend_Pdf_ElementFactory + */ + public function getFactory() + { + return $this->_factory; + } + + /** + * Return type of the element. + * + * @return integer + */ + public function getType() + { + return $this->_value->getType(); + } + + + /** + * Get object number + * + * @return integer + */ + public function getObjNum() + { + return $this->_objNum; + } + + + /** + * Get generation number + * + * @return integer + */ + public function getGenNum() + { + return $this->_genNum; + } + + + /** + * Return reference to the object + * + * @param Zend_Pdf_Factory $factory + * @return string + */ + public function toString($factory = null) + { + if ($factory === null) { + $shift = 0; + } else { + $shift = $factory->getEnumerationShift($this->_factory); + } + + return $this->_objNum + $shift . ' ' . $this->_genNum . ' R'; + } + + + /** + * Dump object to a string to save within PDF file. + * + * $factory parameter defines operation context. + * + * @param Zend_Pdf_ElementFactory $factory + * @return string + */ + public function dump(Zend_Pdf_ElementFactory $factory) + { + $shift = $factory->getEnumerationShift($this->_factory); + + return $this->_objNum + $shift . " " . $this->_genNum . " obj \n" + . $this->_value->toString($factory) . "\n" + . "endobj\n"; + } + + /** + * Get handler + * + * @param string $property + * @return mixed + */ + public function __get($property) + { + return $this->_value->$property; + } + + /** + * Set handler + * + * @param string $property + * @param mixed $value + */ + public function __set($property, $value) + { + $this->_value->$property = $value; + } + + /** + * Call handler + * + * @param string $method + * @param array $args + * @return mixed + */ + public function __call($method, $args) + { + return call_user_func_array(array($this->_value, $method), $args); + } + + /** + * Detach PDF object from the factory (if applicable), clone it and attach to new factory. + * + * @param Zend_Pdf_ElementFactory $factory The factory to attach + * @param array &$processed List of already processed indirect objects, used to avoid objects duplication + * @param integer $mode Cloning mode (defines filter for objects cloning) + * @returns Zend_Pdf_Element + */ + public function makeClone(Zend_Pdf_ElementFactory $factory, array &$processed, $mode) + { + $id = spl_object_hash($this); + if (isset($processed[$id])) { + // Do nothing if object is already processed + // return it + return $processed[$id]; + } + + // Create obect with null value and register it in $processed container + $processed[$id] = $clonedObject = $factory->newObject(new Zend_Pdf_Element_Null()); + + // Pecursively process actual data + $clonedObject->_value = $this->_value->makeClone($factory, $processed, $mode); + + if ($clonedObject->_value instanceof Zend_Pdf_Element_Null) { + // Do not store null objects within $processed container since it may be filtered + // by $mode parameter but used in some future pass + unset($processed[$id]); + + // Return direct null object + return $clonedObject->_value; + } + + return $clonedObject; + } + + /** + * Mark object as modified, to include it into new PDF file segment + */ + public function touch() + { + $this->_factory->markAsModified($this); + } + + /** + * Return object, which can be used to identify object and its references identity + * + * @return Zend_Pdf_Element_Object + */ + public function getObject() + { + return $this; + } + + /** + * Clean up resources, used by object + */ + public function cleanUp() + { + $this->_value = null; + } + + /** + * Convert PDF element to PHP type. + * + * @return mixed + */ + public function toPhp() + { + return $this->_value->toPhp(); + } +} diff --git a/library/Zend/Pdf/Element/Object/Stream.php b/library/Zend/Pdf/Element/Object/Stream.php new file mode 100644 index 0000000..08b35b6 --- /dev/null +++ b/library/Zend/Pdf/Element/Object/Stream.php @@ -0,0 +1,453 @@ +_dictionary = new Zend_Pdf_Element_Dictionary(); + $this->_dictionary->Length = new Zend_Pdf_Element_Numeric(strlen( $val )); + $this->_streamDecoded = true; + } else { + $this->_dictionary = $dictionary; + $this->_streamDecoded = false; + } + } + + + /** + * Extract dictionary data which are used to store information and to normalize filters + * information before defiltering. + * + * @return array + */ + private function _extractDictionaryData() + { + $dictionaryArray = array(); + + $dictionaryArray['Filter'] = array(); + $dictionaryArray['DecodeParms'] = array(); + if ($this->_dictionary->Filter === null) { + // Do nothing. + } else if ($this->_dictionary->Filter->getType() == Zend_Pdf_Element::TYPE_ARRAY) { + foreach ($this->_dictionary->Filter->items as $id => $filter) { + $dictionaryArray['Filter'][$id] = $filter->value; + $dictionaryArray['DecodeParms'][$id] = array(); + + if ($this->_dictionary->DecodeParms !== null ) { + if ($this->_dictionary->DecodeParms->items[$id] !== null && + $this->_dictionary->DecodeParms->items[$id]->value !== null ) { + foreach ($this->_dictionary->DecodeParms->items[$id]->getKeys() as $paramKey) { + $dictionaryArray['DecodeParms'][$id][$paramKey] = + $this->_dictionary->DecodeParms->items[$id]->$paramKey->value; + } + } + } + } + } else if ($this->_dictionary->Filter->getType() != Zend_Pdf_Element::TYPE_NULL) { + $dictionaryArray['Filter'][0] = $this->_dictionary->Filter->value; + $dictionaryArray['DecodeParms'][0] = array(); + if ($this->_dictionary->DecodeParms !== null ) { + foreach ($this->_dictionary->DecodeParms->getKeys() as $paramKey) { + $dictionaryArray['DecodeParms'][0][$paramKey] = + $this->_dictionary->DecodeParms->$paramKey->value; + } + } + } + + if ($this->_dictionary->F !== null) { + $dictionaryArray['F'] = $this->_dictionary->F->value; + } + + $dictionaryArray['FFilter'] = array(); + $dictionaryArray['FDecodeParms'] = array(); + if ($this->_dictionary->FFilter === null) { + // Do nothing. + } else if ($this->_dictionary->FFilter->getType() == Zend_Pdf_Element::TYPE_ARRAY) { + foreach ($this->_dictionary->FFilter->items as $id => $filter) { + $dictionaryArray['FFilter'][$id] = $filter->value; + $dictionaryArray['FDecodeParms'][$id] = array(); + + if ($this->_dictionary->FDecodeParms !== null ) { + if ($this->_dictionary->FDecodeParms->items[$id] !== null && + $this->_dictionary->FDecodeParms->items[$id]->value !== null) { + foreach ($this->_dictionary->FDecodeParms->items[$id]->getKeys() as $paramKey) { + $dictionaryArray['FDecodeParms'][$id][$paramKey] = + $this->_dictionary->FDecodeParms->items[$id]->items[$paramKey]->value; + } + } + } + } + } else { + $dictionaryArray['FFilter'][0] = $this->_dictionary->FFilter->value; + $dictionaryArray['FDecodeParms'][0] = array(); + if ($this->_dictionary->FDecodeParms !== null ) { + foreach ($this->_dictionary->FDecodeParms->getKeys() as $paramKey) { + $dictionaryArray['FDecodeParms'][0][$paramKey] = + $this->_dictionary->FDecodeParms->items[$paramKey]->value; + } + } + } + + return $dictionaryArray; + } + + /** + * Decode stream + * + * @throws Zend_Pdf_Exception + */ + private function _decodeStream() + { + if ($this->_initialDictionaryData === null) { + $this->_initialDictionaryData = $this->_extractDictionaryData(); + } + + /** + * All applied stream filters must be processed to decode stream. + * If we don't recognize any of applied filetrs an exception should be thrown here + */ + if (isset($this->_initialDictionaryData['F'])) { + /** @todo Check, how external files can be processed. */ + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('External filters are not supported now.'); + } + + foreach ($this->_initialDictionaryData['Filter'] as $id => $filterName ) { + $valueRef = &$this->_value->value->getRef(); + $this->_value->value->touch(); + switch ($filterName) { + case 'ASCIIHexDecode': + // require_once 'Zend/Pdf/Filter/AsciiHex.php'; + $valueRef = Zend_Pdf_Filter_AsciiHex::decode($valueRef); + break; + + case 'ASCII85Decode': + // require_once 'Zend/Pdf/Filter/Ascii85.php'; + $valueRef = Zend_Pdf_Filter_Ascii85::decode($valueRef); + break; + + case 'FlateDecode': + // require_once 'Zend/Pdf/Filter/Compression/Flate.php'; + $valueRef = Zend_Pdf_Filter_Compression_Flate::decode($valueRef, + $this->_initialDictionaryData['DecodeParms'][$id]); + break; + + case 'LZWDecode': + // require_once 'Zend/Pdf/Filter/Compression/Lzw.php'; + $valueRef = Zend_Pdf_Filter_Compression_Lzw::decode($valueRef, + $this->_initialDictionaryData['DecodeParms'][$id]); + break; + + case 'RunLengthDecode': + // require_once 'Zend/Pdf/Filter/RunLength.php'; + $valueRef = Zend_Pdf_Filter_RunLength::decode($valueRef); + break; + + default: + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Unknown stream filter: \'' . $filterName . '\'.'); + } + } + + $this->_streamDecoded = true; + } + + /** + * Encode stream + * + * @throws Zend_Pdf_Exception + */ + private function _encodeStream() + { + /** + * All applied stream filters must be processed to encode stream. + * If we don't recognize any of applied filetrs an exception should be thrown here + */ + if (isset($this->_initialDictionaryData['F'])) { + /** @todo Check, how external files can be processed. */ + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('External filters are not supported now.'); + } + + $filters = array_reverse($this->_initialDictionaryData['Filter'], true); + + foreach ($filters as $id => $filterName ) { + $valueRef = &$this->_value->value->getRef(); + $this->_value->value->touch(); + switch ($filterName) { + case 'ASCIIHexDecode': + // require_once 'Zend/Pdf/Filter/AsciiHex.php'; + $valueRef = Zend_Pdf_Filter_AsciiHex::encode($valueRef); + break; + + case 'ASCII85Decode': + // require_once 'Zend/Pdf/Filter/Ascii85.php'; + $valueRef = Zend_Pdf_Filter_Ascii85::encode($valueRef); + break; + + case 'FlateDecode': + // require_once 'Zend/Pdf/Filter/Compression/Flate.php'; + $valueRef = Zend_Pdf_Filter_Compression_Flate::encode($valueRef, + $this->_initialDictionaryData['DecodeParms'][$id]); + break; + + case 'LZWDecode': + // require_once 'Zend/Pdf/Filter/Compression/Lzw.php'; + $valueRef = Zend_Pdf_Filter_Compression_Lzw::encode($valueRef, + $this->_initialDictionaryData['DecodeParms'][$id]); + break; + + case 'RunLengthDecode': + // require_once 'Zend/Pdf/Filter/RunLength.php'; + $valueRef = Zend_Pdf_Filter_RunLength::encode($valueRef); + break; + + default: + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Unknown stream filter: \'' . $filterName . '\'.'); + } + } + + $this->_streamDecoded = false; + } + + /** + * Get handler + * + * @param string $property + * @return mixed + * @throws Zend_Pdf_Exception + */ + public function __get($property) + { + if ($property == 'dictionary') { + /** + * If stream is not decoded yet, then store original decoding options (do it only once). + */ + if (( !$this->_streamDecoded ) && ($this->_initialDictionaryData === null)) { + $this->_initialDictionaryData = $this->_extractDictionaryData(); + } + + return $this->_dictionary; + } + + if ($property == 'value') { + if (!$this->_streamDecoded) { + $this->_decodeStream(); + } + + return $this->_value->value->getRef(); + } + + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Unknown stream object property requested.'); + } + + + /** + * Set handler + * + * @param string $property + * @param mixed $value + */ + public function __set($property, $value) + { + if ($property == 'value') { + $valueRef = &$this->_value->value->getRef(); + $valueRef = $value; + $this->_value->value->touch(); + + $this->_streamDecoded = true; + + return; + } + + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Unknown stream object property: \'' . $property . '\'.'); + } + + + /** + * Treat stream data as already encoded + */ + public function skipFilters() + { + $this->_streamDecoded = false; + } + + + /** + * Call handler + * + * @param string $method + * @param array $args + * @return mixed + */ + public function __call($method, $args) + { + if (!$this->_streamDecoded) { + $this->_decodeStream(); + } + + switch (count($args)) { + case 0: + return $this->_value->$method(); + case 1: + return $this->_value->$method($args[0]); + default: + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Unsupported number of arguments'); + } + } + + /** + * Detach PDF object from the factory (if applicable), clone it and attach to new factory. + * + * @param Zend_Pdf_ElementFactory $factory The factory to attach + * @param array &$processed List of already processed indirect objects, used to avoid objects duplication + * @param integer $mode Cloning mode (defines filter for objects cloning) + * @returns Zend_Pdf_Element + */ + public function makeClone(Zend_Pdf_ElementFactory $factory, array &$processed, $mode) + { + $id = spl_object_hash($this); + if (isset($processed[$id])) { + // Do nothing if object is already processed + // return it + return $processed[$id]; + } + + $streamValue = $this->_value; + $streamDictionary = $this->_dictionary->makeClone($factory, $processed, $mode); + + // Make new empty instance of stream object and register it in $processed container + $processed[$id] = $clonedObject = $factory->newStreamObject(''); + + // Copy current object data and state + $clonedObject->_dictionary = $this->_dictionary->makeClone($factory, $processed, $mode); + $clonedObject->_value = $this->_value->makeClone($factory, $processed, $mode); + $clonedObject->_initialDictionaryData = $this->_initialDictionaryData; + $clonedObject->_streamDecoded = $this->_streamDecoded; + + return $clonedObject; + } + + /** + * Dump object to a string to save within PDF file + * + * $factory parameter defines operation context. + * + * @param Zend_Pdf_ElementFactory $factory + * @return string + */ + public function dump(Zend_Pdf_ElementFactory $factory) + { + $shift = $factory->getEnumerationShift($this->_factory); + + if ($this->_streamDecoded) { + $this->_initialDictionaryData = $this->_extractDictionaryData(); + $this->_encodeStream(); + } else if ($this->_initialDictionaryData != null) { + $newDictionary = $this->_extractDictionaryData(); + + if ($this->_initialDictionaryData !== $newDictionary) { + $this->_decodeStream(); + $this->_initialDictionaryData = $newDictionary; + $this->_encodeStream(); + } + } + + // Update stream length + $this->dictionary->Length->value = $this->_value->length(); + + return $this->_objNum + $shift . " " . $this->_genNum . " obj \n" + . $this->dictionary->toString($factory) . "\n" + . $this->_value->toString($factory) . "\n" + . "endobj\n"; + } + + /** + * Clean up resources, used by object + */ + public function cleanUp() + { + $this->_dictionary = null; + $this->_value = null; + } +} diff --git a/library/Zend/Pdf/Element/Reference.php b/library/Zend/Pdf/Element/Reference.php new file mode 100644 index 0000000..6e64074 --- /dev/null +++ b/library/Zend/Pdf/Element/Reference.php @@ -0,0 +1,303 @@ + 0) ) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Object number must be positive integer'); + } + if ( !(is_integer($genNum) && $genNum >= 0) ) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Generation number must be non-negative integer'); + } + + $this->_objNum = $objNum; + $this->_genNum = $genNum; + $this->_ref = null; + $this->_context = $context; + $this->_factory = $factory; + } + + /** + * Check, that object is generated by specified factory + * + * @return Zend_Pdf_ElementFactory + */ + public function getFactory() + { + return $this->_factory; + } + + + /** + * Return type of the element. + * + * @return integer + */ + public function getType() + { + if ($this->_ref === null) { + $this->_dereference(); + } + + return $this->_ref->getType(); + } + + + /** + * Return reference to the object + * + * @param Zend_Pdf_Factory $factory + * @return string + */ + public function toString($factory = null) + { + if ($factory === null) { + $shift = 0; + } else { + $shift = $factory->getEnumerationShift($this->_factory); + } + + return $this->_objNum + $shift . ' ' . $this->_genNum . ' R'; + } + + + /** + * Dereference. + * Take inderect object, take $value member of this object (must be Zend_Pdf_Element), + * take reference to the $value member of this object and assign it to + * $value member of current PDF Reference object + * $obj can be null + * + * @throws Zend_Pdf_Exception + */ + private function _dereference() + { + if (($obj = $this->_factory->fetchObject($this->_objNum . ' ' . $this->_genNum)) === null) { + $obj = $this->_context->getParser()->getObject( + $this->_context->getRefTable()->getOffset($this->_objNum . ' ' . $this->_genNum . ' R'), + $this->_context + ); + } + + if ($obj === null ) { + $this->_ref = new Zend_Pdf_Element_Null(); + return; + } + + if ($obj->toString() != $this->_objNum . ' ' . $this->_genNum . ' R') { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Incorrect reference to the object'); + } + + $this->_ref = $obj; + } + + /** + * Detach PDF object from the factory (if applicable), clone it and attach to new factory. + * + * @param Zend_Pdf_ElementFactory $factory The factory to attach + * @param array &$processed List of already processed indirect objects, used to avoid objects duplication + * @param integer $mode Cloning mode (defines filter for objects cloning) + * @returns Zend_Pdf_Element + */ + public function makeClone(Zend_Pdf_ElementFactory $factory, array &$processed, $mode) + { + if ($this->_ref === null) { + $this->_dereference(); + } + + // This code duplicates code in Zend_Pdf_Element_Object class, + // but allows to avoid unnecessary method call in most cases + $id = spl_object_hash($this->_ref); + if (isset($processed[$id])) { + // Do nothing if object is already processed + // return it + return $processed[$id]; + } + + return $this->_ref->makeClone($factory, $processed, $mode); + } + + /** + * Mark object as modified, to include it into new PDF file segment. + */ + public function touch() + { + if ($this->_ref === null) { + $this->_dereference(); + } + + $this->_ref->touch(); + } + + /** + * Return object, which can be used to identify object and its references identity + * + * @return Zend_Pdf_Element_Object + */ + public function getObject() + { + if ($this->_ref === null) { + $this->_dereference(); + } + + return $this->_ref; + } + + /** + * Get handler + * + * @param string $property + * @return mixed + */ + public function __get($property) + { + if ($this->_ref === null) { + $this->_dereference(); + } + + return $this->_ref->$property; + } + + /** + * Set handler + * + * @param string $property + * @param mixed $value + */ + public function __set($property, $value) + { + if ($this->_ref === null) { + $this->_dereference(); + } + + $this->_ref->$property = $value; + } + + /** + * Call handler + * + * @param string $method + * @param array $args + * @return mixed + */ + public function __call($method, $args) + { + if ($this->_ref === null) { + $this->_dereference(); + } + + return call_user_func_array(array($this->_ref, $method), $args); + } + + /** + * Clean up resources + */ + public function cleanUp() + { + $this->_ref = null; + } + + /** + * Convert PDF element to PHP type. + * + * @return mixed + */ + public function toPhp() + { + if ($this->_ref === null) { + $this->_dereference(); + } + + return $this->_ref->toPhp(); + } +} diff --git a/library/Zend/Pdf/Element/Reference/Context.php b/library/Zend/Pdf/Element/Reference/Context.php new file mode 100644 index 0000000..305d27e --- /dev/null +++ b/library/Zend/Pdf/Element/Reference/Context.php @@ -0,0 +1,83 @@ +_stringParser = $parser; + $this->_refTable = $refTable; + } + + + /** + * Context parser + * + * @return Zend_Pdf_StringParser + */ + public function getParser() + { + return $this->_stringParser; + } + + + /** + * Context reference table + * + * @return Zend_Pdf_Element_Reference_Table + */ + public function getRefTable() + { + return $this->_refTable; + } +} + diff --git a/library/Zend/Pdf/Element/Reference/Table.php b/library/Zend/Pdf/Element/Reference/Table.php new file mode 100644 index 0000000..bca124e --- /dev/null +++ b/library/Zend/Pdf/Element/Reference/Table.php @@ -0,0 +1,198 @@ + next free object number + * + * @var array + */ + private $_free; + + /** + * Generation numbers for free objects. + * Array: objNum => nextGeneration + * + * @var array + */ + private $_generations; + + /** + * In use entries + * 'reference' => offset + * + * @var array + */ + private $_inuse; + + /** + * Generation numbers for free objects. + * Array: objNum => objGeneration + * + * @var array + */ + private $_usedObjects; + + + + /** + * Object constructor + */ + public function __construct() + { + $this->_parent = null; + $this->_free = array(); $this->_generations = array(); + $this->_inuse = array(); $this->_usedObjects = array(); + } + + + /** + * Add reference to the reference table + * + * @param string $ref + * @param integer $offset + * @param boolean $inuse + */ + public function addReference($ref, $offset, $inuse = true) + { + $refElements = explode(' ', $ref); + if (!is_numeric($refElements[0]) || !is_numeric($refElements[1]) || $refElements[2] != 'R') { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("Incorrect reference: '$ref'"); + } + $objNum = (int)$refElements[0]; + $genNum = (int)$refElements[1]; + + if ($inuse) { + $this->_inuse[$ref] = $offset; + $this->_usedObjects[$objNum] = $objNum; + } else { + $this->_free[$ref] = $offset; + $this->_generations[$objNum] = $genNum; + } + } + + + /** + * Set parent reference table + * + * @param Zend_Pdf_Element_Reference_Table $parent + */ + public function setParent(self $parent) + { + $this->_parent = $parent; + } + + + /** + * Get object offset + * + * @param string $ref + * @return integer + */ + public function getOffset($ref) + { + if (isset($this->_inuse[$ref])) { + return $this->_inuse[$ref]; + } + + if (isset($this->_free[$ref])) { + return null; + } + + if (isset($this->_parent)) { + return $this->_parent->getOffset($ref); + } + + return null; + } + + + /** + * Get next object from a list of free objects. + * + * @param string $ref + * @return integer + * @throws Zend_Pdf_Exception + */ + public function getNextFree($ref) + { + if (isset($this->_inuse[$ref])) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Object is not free'); + } + + if (isset($this->_free[$ref])) { + return $this->_free[$ref]; + } + + if (isset($this->_parent)) { + return $this->_parent->getNextFree($ref); + } + + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Object not found.'); + } + + + /** + * Get next generation number for free object + * + * @param integer $objNum + * @return unknown + */ + public function getNewGeneration($objNum) + { + if (isset($this->_usedObjects[$objNum])) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Object is not free'); + } + + if (isset($this->_generations[$objNum])) { + return $this->_generations[$objNum]; + } + + if (isset($this->_parent)) { + return $this->_parent->getNewGeneration($objNum); + } + + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Object not found.'); + } +} diff --git a/library/Zend/Pdf/Element/Stream.php b/library/Zend/Pdf/Element/Stream.php new file mode 100644 index 0000000..e86972a --- /dev/null +++ b/library/Zend/Pdf/Element/Stream.php @@ -0,0 +1,130 @@ +value = Zend_Pdf::getMemoryManager()->create($val); + } + + + /** + * Return type of the element. + * + * @return integer + */ + public function getType() + { + return Zend_Pdf_Element::TYPE_STREAM; + } + + + /** + * Stream length. + * (Method is used to avoid string copying, which may occurs in some cases) + * + * @return integer + */ + public function length() + { + return strlen($this->value->getRef()); + } + + + /** + * Clear stream + * + */ + public function clear() + { + $ref = &$this->value->getRef(); + $ref = ''; + $this->value->touch(); + } + + + /** + * Append value to a stream + * + * @param mixed $val + */ + public function append($val) + { + $ref = &$this->value->getRef(); + $ref .= (string)$val; + $this->value->touch(); + } + + + /** + * Detach PDF object from the factory (if applicable), clone it and attach to new factory. + * + * @param Zend_Pdf_ElementFactory $factory The factory to attach + * @param array &$processed List of already processed indirect objects, used to avoid objects duplication + * @param integer $mode Cloning mode (defines filter for objects cloning) + * @returns Zend_Pdf_Element + */ + public function makeClone(Zend_Pdf_ElementFactory $factory, array &$processed, $mode) + { + return new self($this->value->getRef()); + } + + /** + * Return object as string + * + * @param Zend_Pdf_Factory $factory + * @return string + */ + public function toString($factory = null) + { + return "stream\n" . $this->value->getRef() . "\nendstream"; + } +} diff --git a/library/Zend/Pdf/Element/String.php b/library/Zend/Pdf/Element/String.php new file mode 100644 index 0000000..103bd04 --- /dev/null +++ b/library/Zend/Pdf/Element/String.php @@ -0,0 +1,263 @@ +value = (string)$val; + } + + + /** + * Return type of the element. + * + * @return integer + */ + public function getType() + { + return Zend_Pdf_Element::TYPE_STRING; + } + + + /** + * Return object as string + * + * @param Zend_Pdf_Factory $factory + * @return string + */ + public function toString($factory = null) + { + return '(' . self::escape((string)$this->value) . ')'; + } + + + /** + * Escape string according to the PDF rules + * + * @param string $str + * @return string + */ + public static function escape($str) + { + $outEntries = array(); + + foreach (str_split($str, 128) as $chunk) { + // Collect sequence of unescaped characters + $offset = strcspn($chunk, "\n\r\t\x08\x0C()\\"); + $chunkOut = substr($chunk, 0, $offset); + + while ($offset < strlen($chunk)) { + $nextCode = ord($chunk[$offset++]); + switch ($nextCode) { + // "\n" - line feed (LF) + case 10: + $chunkOut .= '\\n'; + break; + + // "\r" - carriage return (CR) + case 13: + $chunkOut .= '\\r'; + break; + + // "\t" - horizontal tab (HT) + case 9: + $chunkOut .= '\\t'; + break; + + // "\b" - backspace (BS) + case 8: + $chunkOut .= '\\b'; + break; + + // "\f" - form feed (FF) + case 12: + $chunkOut .= '\\f'; + break; + + // '(' - left paranthesis + case 40: + $chunkOut .= '\\('; + break; + + // ')' - right paranthesis + case 41: + $chunkOut .= '\\)'; + break; + + // '\' - backslash + case 92: + $chunkOut .= '\\\\'; + break; + + default: + // This code is never executed extually + // + // Don't use non-ASCII characters escaping + // if ($nextCode >= 32 && $nextCode <= 126 ) { + // // Visible ASCII symbol + // $chunkEntries[] = chr($nextCode); + // } else { + // $chunkEntries[] = sprintf('\\%03o', $nextCode); + // } + + break; + } + + // Collect sequence of unescaped characters + $start = $offset; + $offset += strcspn($chunk, "\n\r\t\x08\x0C()\\", $offset); + $chunkOut .= substr($chunk, $start, $offset - $start); + } + + $outEntries[] = $chunkOut; + } + + return implode("\\\n", $outEntries); + } + + + /** + * Unescape string according to the PDF rules + * + * @param string $str + * @return string + */ + public static function unescape($str) + { + $outEntries = array(); + + $offset = 0; + while ($offset < strlen($str)) { + // Searche for the next escaped character/sequence + $escapeCharOffset = strpos($str, '\\', $offset); + if ($escapeCharOffset === false || $escapeCharOffset == strlen($str) - 1) { + // There are no escaped characters or '\' char has came at the end of string + $outEntries[] = substr($str, $offset); + break; + } else { + // Collect unescaped characters sequence + $outEntries[] = substr($str, $offset, $escapeCharOffset - $offset); + // Go to the escaped character + $offset = $escapeCharOffset + 1; + + switch ($str[$offset]) { + // '\\n' - line feed (LF) + case 'n': + $outEntries[] = "\n"; + break; + + // '\\r' - carriage return (CR) + case 'r': + $outEntries[] = "\r"; + break; + + // '\\t' - horizontal tab (HT) + case 't': + $outEntries[] = "\t"; + break; + + // '\\b' - backspace (BS) + case 'b': + $outEntries[] = "\x08"; + break; + + // '\\f' - form feed (FF) + case 'f': + $outEntries[] = "\x0C"; + break; + + // '\\(' - left paranthesis + case '(': + $outEntries[] = '('; + break; + + // '\\)' - right paranthesis + case ')': + $outEntries[] = ')'; + break; + + // '\\\\' - backslash + case '\\': + $outEntries[] = '\\'; + break; + + // "\\\n" or "\\\n\r" + case "\n": + // skip new line symbol + if ($str[$offset + 1] == "\r") { + $offset++; + } + break; + + default: + if (strpos('0123456789', $str[$offset]) !== false) { + // Character in octal representation + // '\\xxx' + $nextCode = '0' . $str[$offset]; + + if (strpos('0123456789', $str[$offset + 1]) !== false) { + $nextCode .= $str[++$offset]; + + if (strpos('0123456789', $str[$offset + 1]) !== false) { + $nextCode .= $str[++$offset]; + } + } + + $outEntries[] = chr(octdec($nextCode)); + } else { + $outEntries[] = $str[$offset]; + } + break; + } + + $offset++; + } + } + + return implode($outEntries); + } + +} diff --git a/library/Zend/Pdf/Element/String/Binary.php b/library/Zend/Pdf/Element/String/Binary.php new file mode 100644 index 0000000..0cda7fd --- /dev/null +++ b/library/Zend/Pdf/Element/String/Binary.php @@ -0,0 +1,98 @@ +value) . '>'; + } +} diff --git a/library/Zend/Pdf/ElementFactory.php b/library/Zend/Pdf/ElementFactory.php new file mode 100644 index 0000000..fcf3898 --- /dev/null +++ b/library/Zend/Pdf/ElementFactory.php @@ -0,0 +1,446 @@ + Zend_Pdf_Element_Object + * + * @var array + */ + private $_modifiedObjects = array(); + + /** + * List of the removed objects + * + * Array: ojbectNumber => Zend_Pdf_Element_Object + * + * @var SplObjectStorage + */ + private $_removedObjects; + + /** + * List of registered objects. + * Used for resources clean up when factory is destroyed. + * + * Array of Zend_Pdf_Element objects + * + * @var array + */ + private $_registeredObjects = array(); + + /** + * PDF object counter. + * Actually it's an object number for new PDF object + * + * @var integer + */ + private $_objectCount; + + + /** + * List of the attached object factories. + * Array of Zend_Pdf_ElementFactory_Interface objects + * + * @var array + */ + private $_attachedFactories = array(); + + + /** + * Factory internal id + * + * @var integer + */ + private $_factoryId; + + /** + * Identity, used for factory id generation + * + * @var integer + */ + private static $_identity = 0; + + + /** + * Internal cache to save calculated shifts + * + * @var array + */ + private $_shiftCalculationCache = array(); + + + /** + * Object constructor + * + * @param integer $objCount + */ + public function __construct($objCount) + { + $this->_objectCount = (int)$objCount; + $this->_factoryId = self::$_identity++; + $this->_removedObjects = new SplObjectStorage(); + } + + + /** + * Get factory + * + * @return Zend_Pdf_ElementFactory_Interface + */ + public function getFactory() + { + return $this; + } + + /** + * Factory generator + * + * @param integer $objCount + * @return Zend_Pdf_ElementFactory_Interface + */ + static public function createFactory($objCount) + { + // require_once 'Zend/Pdf/ElementFactory/Proxy.php'; + return new Zend_Pdf_ElementFactory_Proxy(new Zend_Pdf_ElementFactory($objCount)); + } + + /** + * Close factory and clean-up resources + * + * @internal + */ + public function close() + { + $this->_modifiedObjects = null; + $this->_removedObjects = null; + $this->_attachedFactories = null; + + foreach ($this->_registeredObjects as $obj) { + $obj->cleanUp(); + } + $this->_registeredObjects = null; + } + + /** + * Get source factory object + * + * @return Zend_Pdf_ElementFactory + */ + public function resolve() + { + return $this; + } + + /** + * Get factory ID + * + * @return integer + */ + public function getId() + { + return $this->_factoryId; + } + + /** + * Set object counter + * + * @param integer $objCount + */ + public function setObjectCount($objCount) + { + $this->_objectCount = (int)$objCount; + } + + /** + * Get object counter + * + * @return integer + */ + public function getObjectCount() + { + $count = $this->_objectCount; + + foreach ($this->_attachedFactories as $attached) { + $count += $attached->getObjectCount() - 1; // -1 as "0" object is a special case and shared between factories + } + + return $count; + } + + + /** + * Attach factory to the current; + * + * @param Zend_Pdf_ElementFactory_Interface $factory + */ + public function attach(Zend_Pdf_ElementFactory_Interface $factory) + { + if ( $factory === $this || isset($this->_attachedFactories[$factory->getId()])) { + /** + * Don't attach factory twice. + * We do not check recusively because of nature of attach operation + * (Pages are always attached to the Documents, Fonts are always attached + * to the pages even if pages already use Document level object factory and so on) + */ + return; + } + + $this->_attachedFactories[$factory->getId()] = $factory; + } + + + /** + * Calculate object enumeration shift. + * + * @param Zend_Pdf_ElementFactory_Interface $factory + * @return integer + */ + public function calculateShift(Zend_Pdf_ElementFactory_Interface $factory) + { + if ($factory === $this) { + return 0; + } + + if (isset($this->_shiftCalculationCache[$factory->_factoryId])) { + return $this->_shiftCalculationCache[$factory->_factoryId]; + } + + $shift = $this->_objectCount - 1; + + foreach ($this->_attachedFactories as $subFactory) { + $subFactoryShift = $subFactory->calculateShift($factory); + + if ($subFactoryShift != -1) { + // context found + $this->_shiftCalculationCache[$factory->_factoryId] = $shift + $subFactoryShift; + return $shift + $subFactoryShift; + } else { + $shift += $subFactory->getObjectCount()-1; + } + } + + $this->_shiftCalculationCache[$factory->_factoryId] = -1; + return -1; + } + + /** + * Clean enumeration shift cache. + * Has to be used after PDF render operation to let followed updates be correct. + */ + public function cleanEnumerationShiftCache() + { + $this->_shiftCalculationCache = array(); + + foreach ($this->_attachedFactories as $attached) { + $attached->cleanEnumerationShiftCache(); + } + } + + /** + * Retrive object enumeration shift. + * + * @param Zend_Pdf_ElementFactory_Interface $factory + * @return integer + * @throws Zend_Pdf_Exception + */ + public function getEnumerationShift(Zend_Pdf_ElementFactory_Interface $factory) + { + if (($shift = $this->calculateShift($factory)) == -1) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Wrong object context'); + } + + return $shift; + } + + /** + * Mark object as modified in context of current factory. + * + * @param Zend_Pdf_Element_Object $obj + * @throws Zend_Pdf_Exception + */ + public function markAsModified(Zend_Pdf_Element_Object $obj) + { + if ($obj->getFactory() !== $this) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Object is not generated by this factory'); + } + + $this->_modifiedObjects[$obj->getObjNum()] = $obj; + } + + + /** + * Remove object in context of current factory. + * + * @param Zend_Pdf_Element_Object $obj + * @throws Zend_Pdf_Exception + */ + public function remove(Zend_Pdf_Element_Object $obj) + { + if (!$obj->compareFactory($this)) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Object is not generated by this factory'); + } + + $this->_modifiedObjects[$obj->getObjNum()] = $obj; + $this->_removedObjects->attach($obj); + } + + + /** + * Generate new Zend_Pdf_Element_Object + * + * @todo Reusage of the freed object. It's not a support of new feature, but only improvement. + * + * @param Zend_Pdf_Element $objectValue + * @return Zend_Pdf_Element_Object + */ + public function newObject(Zend_Pdf_Element $objectValue) + { + // require_once 'Zend/Pdf/Element/Object.php'; + $obj = new Zend_Pdf_Element_Object($objectValue, $this->_objectCount++, 0, $this); + $this->_modifiedObjects[$obj->getObjNum()] = $obj; + return $obj; + } + + /** + * Generate new Zend_Pdf_Element_Object_Stream + * + * @todo Reusage of the freed object. It's not a support of new feature, but only improvement. + * + * @param mixed $objectValue + * @return Zend_Pdf_Element_Object_Stream + */ + public function newStreamObject($streamValue) + { + // require_once 'Zend/Pdf/Element/Object/Stream.php'; + $obj = new Zend_Pdf_Element_Object_Stream($streamValue, $this->_objectCount++, 0, $this); + $this->_modifiedObjects[$obj->getObjNum()] = $obj; + return $obj; + } + + + /** + * Enumerate modified objects. + * Returns array of Zend_Pdf_UpdateInfoContainer + * + * @param Zend_Pdf_ElementFactory_Interface $rootFactory + * @return array + */ + public function listModifiedObjects($rootFactory = null) + { + if ($rootFactory == null) { + $rootFactory = $this; + $shift = 0; + } else { + $shift = $rootFactory->getEnumerationShift($this); + } + + ksort($this->_modifiedObjects); + + $result = array(); + // require_once 'Zend/Pdf/UpdateInfoContainer.php'; + foreach ($this->_modifiedObjects as $objNum => $obj) { + if ($this->_removedObjects->contains($obj)) { + $result[$objNum+$shift] = new Zend_Pdf_UpdateInfoContainer($objNum + $shift, + $obj->getGenNum()+1, + true); + } else { + $result[$objNum+$shift] = new Zend_Pdf_UpdateInfoContainer($objNum + $shift, + $obj->getGenNum(), + false, + $obj->dump($rootFactory)); + } + } + + foreach ($this->_attachedFactories as $factory) { + $result += $factory->listModifiedObjects($rootFactory); + } + + return $result; + } + + /** + * Register object in the factory + * + * It's used to clear "parent object" referencies when factory is closed and clean up resources + * + * @param string $refString + * @param Zend_Pdf_Element_Object $obj + */ + public function registerObject(Zend_Pdf_Element_Object $obj, $refString) + { + $this->_registeredObjects[$refString] = $obj; + } + + /** + * Fetch object specified by reference + * + * @param string $refString + * @return Zend_Pdf_Element_Object|null + */ + public function fetchObject($refString) + { + if (!isset($this->_registeredObjects[$refString])) { + return null; + } + return $this->_registeredObjects[$refString]; + } + + + /** + * Check if PDF file was modified + * + * @return boolean + */ + public function isModified() + { + if (count($this->_modifiedObjects) != 0) { + return true; + } + + foreach ($this->_attachedFactories as $subFactory) { + if ($subFactory->isModified()) { + return true; + } + } + + return false; + } +} + diff --git a/library/Zend/Pdf/ElementFactory/Interface.php b/library/Zend/Pdf/ElementFactory/Interface.php new file mode 100644 index 0000000..ffa5a4b --- /dev/null +++ b/library/Zend/Pdf/ElementFactory/Interface.php @@ -0,0 +1,158 @@ +_factory = $factory; + } + + public function __destruct() + { + $this->_factory->close(); + $this->_factory = null; + } + + /** + * Get factory + * + * @return Zend_Pdf_ElementFactory_Interface + */ + public function getFactory() + { + return $this->_factory->getFactory(); + } + + /** + * Close factory and clean-up resources + * + * @internal + */ + public function close() + { + // Do nothing + } + + /** + * Get source factory object + * + * @return Zend_Pdf_ElementFactory + */ + public function resolve() + { + return $this->_factory->resolve(); + } + + /** + * Get factory ID + * + * @return integer + */ + public function getId() + { + return $this->_factory->getId(); + } + + /** + * Set object counter + * + * @param integer $objCount + */ + public function setObjectCount($objCount) + { + $this->_factory->setObjectCount($objCount); + } + + /** + * Get object counter + * + * @return integer + */ + public function getObjectCount() + { + return $this->_factory->getObjectCount(); + } + + /** + * Attach factory to the current; + * + * @param Zend_Pdf_ElementFactory_Interface $factory + */ + public function attach(Zend_Pdf_ElementFactory_Interface $factory) + { + $this->_factory->attach($factory); + } + + /** + * Calculate object enumeration shift. + * + * @internal + * @param Zend_Pdf_ElementFactory_Interface $factory + * @return integer + */ + public function calculateShift(Zend_Pdf_ElementFactory_Interface $factory) + { + return $this->_factory->calculateShift($factory); + } + + /** + * Clean enumeration shift cache. + * Has to be used after PDF render operation to let followed updates be correct. + * + * @param Zend_Pdf_ElementFactory_Interface $factory + * @return integer + */ + public function cleanEnumerationShiftCache() + { + return $this->_factory->cleanEnumerationShiftCache(); + } + + /** + * Retrive object enumeration shift. + * + * @param Zend_Pdf_ElementFactory_Interface $factory + * @return integer + * @throws Zend_Pdf_Exception + */ + public function getEnumerationShift(Zend_Pdf_ElementFactory_Interface $factory) + { + return $this->_factory->getEnumerationShift($factory); + } + + /** + * Mark object as modified in context of current factory. + * + * @param Zend_Pdf_Element_Object $obj + * @throws Zend_Pdf_Exception + */ + public function markAsModified(Zend_Pdf_Element_Object $obj) + { + $this->_factory->markAsModified($obj); + } + + /** + * Remove object in context of current factory. + * + * @param Zend_Pdf_Element_Object $obj + * @throws Zend_Pdf_Exception + */ + public function remove(Zend_Pdf_Element_Object $obj) + { + $this->_factory->remove($obj); + } + + /** + * Generate new Zend_Pdf_Element_Object + * + * @todo Reusage of the freed object. It's not a support of new feature, but only improvement. + * + * @param Zend_Pdf_Element $objectValue + * @return Zend_Pdf_Element_Object + */ + public function newObject(Zend_Pdf_Element $objectValue) + { + return $this->_factory->newObject($objectValue); + } + + /** + * Generate new Zend_Pdf_Element_Object_Stream + * + * @todo Reusage of the freed object. It's not a support of new feature, but only improvement. + * + * @param mixed $objectValue + * @return Zend_Pdf_Element_Object_Stream + */ + public function newStreamObject($streamValue) + { + return $this->_factory->newStreamObject($streamValue); + } + + /** + * Enumerate modified objects. + * Returns array of Zend_Pdf_UpdateInfoContainer + * + * @param Zend_Pdf_ElementFactory $rootFactory + * @return array + */ + public function listModifiedObjects($rootFactory = null) + { + return $this->_factory->listModifiedObjects($rootFactory); + } + + /** + * Check if PDF file was modified + * + * @return boolean + */ + public function isModified() + { + return $this->_factory->isModified(); + } +} diff --git a/library/Zend/Pdf/Exception.php b/library/Zend/Pdf/Exception.php new file mode 100644 index 0000000..3764f02 --- /dev/null +++ b/library/Zend/Pdf/Exception.php @@ -0,0 +1,343 @@ +_isScreened to true if successful. + * + * @throws Zend_Pdf_Exception + */ + abstract public function screen(); + + /** + * Reads and parses the complete binary file. + * + * Must set $this->_isParsed to true if successful. + * + * @throws Zend_Pdf_Exception + */ + abstract public function parse(); + + + /* Object Lifecycle */ + + /** + * Object constructor. + * + * Verifies that the data source has been properly initialized. + * + * @param Zend_Pdf_FileParserDataSource $dataSource + * @throws Zend_Pdf_Exception + */ + public function __construct(Zend_Pdf_FileParserDataSource $dataSource) + { + if ($dataSource->getSize() == 0) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('The data source has not been properly initialized', + Zend_Pdf_Exception::BAD_DATA_SOURCE); + } + $this->_dataSource = $dataSource; + } + + /** + * Object destructor. + * + * Discards the data source object. + */ + public function __destruct() + { + $this->_dataSource = null; + } + + + /* Accessors */ + + /** + * Returns true if the file has passed a cursory validation check. + * + * @return boolean + */ + public function isScreened() + { + return $this->_isScreened; + } + + /** + * Returns true if the file has been successfully parsed. + * + * @return boolean + */ + public function isParsed() + { + return $this->_isParsed; + } + + /** + * Returns the data source object representing the file being parsed. + * + * @return Zend_Pdf_FileParserDataSource + */ + public function getDataSource() + { + return $this->_dataSource; + } + + + /* Primitive Methods */ + + /** + * Convenience wrapper for the data source object's moveToOffset() method. + * + * @param integer $offset Destination byte offset. + * @throws Zend_Pdf_Exception + */ + public function moveToOffset($offset) + { + $this->_dataSource->moveToOffset($offset); + } + + public function getOffset() { + return $this->_dataSource->getOffset(); + } + + public function getSize() { + return $this->_dataSource->getSize(); + } + + /** + * Convenience wrapper for the data source object's readBytes() method. + * + * @param integer $byteCount Number of bytes to read. + * @return string + * @throws Zend_Pdf_Exception + */ + public function readBytes($byteCount) + { + return $this->_dataSource->readBytes($byteCount); + } + + /** + * Convenience wrapper for the data source object's skipBytes() method. + * + * @param integer $byteCount Number of bytes to skip. + * @throws Zend_Pdf_Exception + */ + public function skipBytes($byteCount) + { + $this->_dataSource->skipBytes($byteCount); + } + + + /* Parser Methods */ + + /** + * Reads the signed integer value from the binary file at the current byte + * offset. + * + * Advances the offset by the number of bytes read. Throws an exception if + * an error occurs. + * + * @param integer $size Size of integer in bytes: 1-4 + * @param integer $byteOrder (optional) Big- or little-endian byte order. + * Use the BYTE_ORDER_ constants defined in {@link Zend_Pdf_FileParser}. + * If omitted, uses big-endian. + * @return integer + * @throws Zend_Pdf_Exception + */ + public function readInt($size, $byteOrder = Zend_Pdf_FileParser::BYTE_ORDER_BIG_ENDIAN) + { + if (($size < 1) || ($size > 4)) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("Invalid signed integer size: $size", + Zend_Pdf_Exception::INVALID_INTEGER_SIZE); + } + $bytes = $this->_dataSource->readBytes($size); + /* unpack() will not work for this method because it always works in + * the host byte order for signed integers. It also does not allow for + * variable integer sizes. + */ + if ($byteOrder == Zend_Pdf_FileParser::BYTE_ORDER_BIG_ENDIAN) { + $number = ord($bytes[0]); + if (($number & 0x80) == 0x80) { + /* This number is negative. Extract the positive equivalent. + */ + $number = (~ $number) & 0xff; + for ($i = 1; $i < $size; $i++) { + $number = ($number << 8) | ((~ ord($bytes[$i])) & 0xff); + } + /* Now turn this back into a negative number by taking the + * two's complement (we didn't add one above so won't + * subtract it below). This works reliably on both 32- and + * 64-bit systems. + */ + $number = ~$number; + } else { + for ($i = 1; $i < $size; $i++) { + $number = ($number << 8) | ord($bytes[$i]); + } + } + } else if ($byteOrder == Zend_Pdf_FileParser::BYTE_ORDER_LITTLE_ENDIAN) { + $number = ord($bytes[$size - 1]); + if (($number & 0x80) == 0x80) { + /* Negative number. See discussion above. + */ + $number = 0; + for ($i = --$size; $i >= 0; $i--) { + $number |= ((~ ord($bytes[$i])) & 0xff) << ($i * 8); + } + $number = ~$number; + } else { + $number = 0; + for ($i = --$size; $i >= 0; $i--) { + $number |= ord($bytes[$i]) << ($i * 8); + } + } + } else { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("Invalid byte order: $byteOrder", + Zend_Pdf_Exception::INVALID_BYTE_ORDER); + } + return $number; + } + + /** + * Reads the unsigned integer value from the binary file at the current byte + * offset. + * + * Advances the offset by the number of bytes read. Throws an exception if + * an error occurs. + * + * NOTE: If you ask for a 4-byte unsigned integer on a 32-bit machine, the + * resulting value WILL BE SIGNED because PHP uses signed integers internally + * for everything. To guarantee portability, be sure to use bitwise operators + * operators on large unsigned integers! + * + * @param integer $size Size of integer in bytes: 1-4 + * @param integer $byteOrder (optional) Big- or little-endian byte order. + * Use the BYTE_ORDER_ constants defined in {@link Zend_Pdf_FileParser}. + * If omitted, uses big-endian. + * @return integer + * @throws Zend_Pdf_Exception + */ + public function readUInt($size, $byteOrder = Zend_Pdf_FileParser::BYTE_ORDER_BIG_ENDIAN) + { + if (($size < 1) || ($size > 4)) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("Invalid unsigned integer size: $size", + Zend_Pdf_Exception::INVALID_INTEGER_SIZE); + } + $bytes = $this->_dataSource->readBytes($size); + /* unpack() is a bit heavyweight for this simple conversion. Just + * work the bytes directly. + */ + if ($byteOrder == Zend_Pdf_FileParser::BYTE_ORDER_BIG_ENDIAN) { + $number = ord($bytes[0]); + for ($i = 1; $i < $size; $i++) { + $number = ($number << 8) | ord($bytes[$i]); + } + } else if ($byteOrder == Zend_Pdf_FileParser::BYTE_ORDER_LITTLE_ENDIAN) { + $number = 0; + for ($i = --$size; $i >= 0; $i--) { + $number |= ord($bytes[$i]) << ($i * 8); + } + } else { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("Invalid byte order: $byteOrder", + Zend_Pdf_Exception::INVALID_BYTE_ORDER); + } + return $number; + } + + /** + * Returns true if the specified bit is set in the integer bitfield. + * + * @param integer $bit Bit number to test (i.e. - 0-31) + * @param integer $bitField + * @return boolean + */ + public function isBitSet($bit, $bitField) + { + $bitMask = 1 << $bit; + $isSet = (($bitField & $bitMask) == $bitMask); + return $isSet; + } + + /** + * Reads the signed fixed-point number from the binary file at the current + * byte offset. + * + * Common fixed-point sizes are 2.14 and 16.16. + * + * Advances the offset by the number of bytes read. Throws an exception if + * an error occurs. + * + * @param integer $mantissaBits Number of bits in the mantissa + * @param integer $fractionBits Number of bits in the fraction + * @param integer $byteOrder (optional) Big- or little-endian byte order. + * Use the BYTE_ORDER_ constants defined in {@link Zend_Pdf_FileParser}. + * If omitted, uses big-endian. + * @return float + * @throws Zend_Pdf_Exception + */ + public function readFixed($mantissaBits, $fractionBits, + $byteOrder = Zend_Pdf_FileParser::BYTE_ORDER_BIG_ENDIAN) + { + $bitsToRead = $mantissaBits + $fractionBits; + if (($bitsToRead % 8) !== 0) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Fixed-point numbers are whole bytes', + Zend_Pdf_Exception::BAD_FIXED_POINT_SIZE); + } + $number = $this->readInt(($bitsToRead >> 3), $byteOrder) / (1 << $fractionBits); + return $number; + } + + /** + * Reads the Unicode UTF-16-encoded string from the binary file at the + * current byte offset. + * + * The byte order of the UTF-16 string must be specified. You must also + * supply the desired resulting character set. + * + * Advances the offset by the number of bytes read. Throws an exception if + * an error occurs. + * + * @todo Consider changing $byteCount to a character count. They are not + * always equivalent (in the case of surrogates). + * @todo Make $byteOrder optional if there is a byte-order mark (BOM) in the + * string being extracted. + * + * @param integer $byteCount Number of bytes (characters * 2) to return. + * @param integer $byteOrder (optional) Big- or little-endian byte order. + * Use the BYTE_ORDER_ constants defined in {@link Zend_Pdf_FileParser}. + * If omitted, uses big-endian. + * @param string $characterSet (optional) Desired resulting character set. + * You may use any character set supported by {@link iconv()}. If omitted, + * uses 'current locale'. + * @return string + * @throws Zend_Pdf_Exception + */ + public function readStringUTF16($byteCount, + $byteOrder = Zend_Pdf_FileParser::BYTE_ORDER_BIG_ENDIAN, + $characterSet = '') + { + if ($byteCount == 0) { + return ''; + } + $bytes = $this->_dataSource->readBytes($byteCount); + if ($byteOrder == Zend_Pdf_FileParser::BYTE_ORDER_BIG_ENDIAN) { + if ($characterSet == 'UTF-16BE') { + return $bytes; + } + return iconv('UTF-16BE', $characterSet, $bytes); + } else if ($byteOrder == Zend_Pdf_FileParser::BYTE_ORDER_LITTLE_ENDIAN) { + if ($characterSet == 'UTF-16LE') { + return $bytes; + } + return iconv('UTF-16LE', $characterSet, $bytes); + } else { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("Invalid byte order: $byteOrder", + Zend_Pdf_Exception::INVALID_BYTE_ORDER); + } + } + + /** + * Reads the Mac Roman-encoded string from the binary file at the current + * byte offset. + * + * You must supply the desired resulting character set. + * + * Advances the offset by the number of bytes read. Throws an exception if + * an error occurs. + * + * @param integer $byteCount Number of bytes (characters) to return. + * @param string $characterSet (optional) Desired resulting character set. + * You may use any character set supported by {@link iconv()}. If omitted, + * uses 'current locale'. + * @return string + * @throws Zend_Pdf_Exception + */ + public function readStringMacRoman($byteCount, $characterSet = '') + { + if ($byteCount == 0) { + return ''; + } + $bytes = $this->_dataSource->readBytes($byteCount); + if ($characterSet == 'MacRoman') { + return $bytes; + } + return iconv('MacRoman', $characterSet, $bytes); + } + + /** + * Reads the Pascal string from the binary file at the current byte offset. + * + * The length of the Pascal string is determined by reading the length bytes + * which preceed the character data. You must supply the desired resulting + * character set. + * + * Advances the offset by the number of bytes read. Throws an exception if + * an error occurs. + * + * @param string $characterSet (optional) Desired resulting character set. + * You may use any character set supported by {@link iconv()}. If omitted, + * uses 'current locale'. + * @param integer $lengthBytes (optional) Number of bytes that make up the + * length. Default is 1. + * @return string + * @throws Zend_Pdf_Exception + */ + public function readStringPascal($characterSet = '', $lengthBytes = 1) + { + $byteCount = $this->readUInt($lengthBytes); + if ($byteCount == 0) { + return ''; + } + $bytes = $this->_dataSource->readBytes($byteCount); + if ($characterSet == 'ASCII') { + return $bytes; + } + return iconv('ASCII', $characterSet, $bytes); + } + +} diff --git a/library/Zend/Pdf/FileParser/Font.php b/library/Zend/Pdf/FileParser/Font.php new file mode 100644 index 0000000..f975025 --- /dev/null +++ b/library/Zend/Pdf/FileParser/Font.php @@ -0,0 +1,217 @@ +fontType = Zend_Pdf_Font::TYPE_UNKNOWN; + } + + + /* Accessors */ + + /** + * Get handler + * + * @param string $property + * @return mixed + */ + public function __get($property) + { + if (isset($this->_fontProperties[$property])) { + return $this->_fontProperties[$property]; + } else { + return null; + } + } + + /* NOTE: The set handler is defined below in the internal methods group. */ + + + /* Parser Methods */ + + /** + * Reads the Unicode UTF-16-encoded string from the binary file at the + * current offset location. Overridden to fix return character set at UTF-16BE. + * + * @todo Deal with to-dos in the parent method. + * + * @param integer $byteCount Number of bytes (characters * 2) to return. + * @param integer $byteOrder (optional) Big- or little-endian byte order. + * Use the BYTE_ORDER_ constants defined in {@link Zend_Pdf_FileParser}. If + * omitted, uses big-endian. + * @param string $characterSet (optional) --Ignored-- + * @return string + * @throws Zend_Pdf_Exception + */ + public function readStringUTF16($byteCount, + $byteOrder = Zend_Pdf_FileParser::BYTE_ORDER_BIG_ENDIAN, + $characterSet = '') + { + return parent::readStringUTF16($byteCount, $byteOrder, 'UTF-16BE'); + } + + /** + * Reads the Mac Roman-encoded string from the binary file at the current + * offset location. Overridden to fix return character set at UTF-16BE. + * + * @param integer $byteCount Number of bytes (characters) to return. + * @param string $characterSet (optional) --Ignored-- + * @return string + * @throws Zend_Pdf_Exception + */ + public function readStringMacRoman($byteCount, $characterSet = '') + { + return parent::readStringMacRoman($byteCount, 'UTF-16BE'); + } + + /** + * Reads the Pascal string from the binary file at the current offset + * location. Overridden to fix return character set at UTF-16BE. + * + * @param string $characterSet (optional) --Ignored-- + * @param integer $lengthBytes (optional) Number of bytes that make up the + * length. Default is 1. + * @return string + * @throws Zend_Pdf_Exception + */ + public function readStringPascal($characterSet = '', $lengthBytes = 1) + { + return parent::readStringPascal('UTF-16BE'); + } + + + /* Utility Methods */ + + /** + * Writes the entire font properties array to STDOUT. Used only for debugging. + */ + public function writeDebug() + { + print_r($this->_fontProperties); + } + + + + /**** Internal Methods ****/ + + + /* Internal Accessors */ + + /** + * Set handler + * + * NOTE: This method is protected. Other classes may freely interrogate + * the font properties, but only this and its subclasses may set them. + * + * @param string $property + * @param mixed $value + */ + public function __set($property, $value) + { + if ($value === null) { + unset($this->_fontProperties[$property]); + } else { + $this->_fontProperties[$property] = $value; + } + } + + + /* Internal Utility Methods */ + + /** + * If debug logging is enabled, writes the log message. + * + * The log message is a sprintf() style string and any number of arguments + * may accompany it as additional parameters. + * + * @param string $message + * @param mixed (optional, multiple) Additional arguments + */ + protected function _debugLog($message) + { + if (! $this->_debug) { + return; + } + if (func_num_args() > 1) { + $args = func_get_args(); + $message = array_shift($args); + $message = vsprintf($message, $args); + } + + // require_once 'Zend/Log.php'; + $logger = new Zend_Log(); + $logger->log($message, Zend_Log::DEBUG); + } +} diff --git a/library/Zend/Pdf/FileParser/Font/OpenType.php b/library/Zend/Pdf/FileParser/Font/OpenType.php new file mode 100644 index 0000000..8c34a91 --- /dev/null +++ b/library/Zend/Pdf/FileParser/Font/OpenType.php @@ -0,0 +1,1138 @@ + + *
  • {@link http://developer.apple.com/textfonts/TTRefMan/} + *
  • {@link http://www.microsoft.com/typography/OTSPEC/} + *
  • {@link http://partners.adobe.com/public/developer/opentype/index_spec.html} + * + * + * @package Zend_Pdf + * @subpackage FileParser + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +abstract class Zend_Pdf_FileParser_Font_OpenType extends Zend_Pdf_FileParser_Font +{ + /**** Instance Variables ****/ + + + /** + * Stores the scaler type (font type) for the font file. See + * {@link _readScalerType()}. + * @var integer + */ + protected $_scalerType = 0; + + /** + * Stores the byte offsets to the various information tables. + * @var array + */ + protected $_tableDirectory = array(); + + + + /**** Public Interface ****/ + + + /* Semi-Concrete Class Implementation */ + + /** + * Verifies that the font file is in the expected format. + * + * NOTE: This method should be overridden in subclasses to check the + * specific format and set $this->_isScreened! + * + * @throws Zend_Pdf_Exception + */ + public function screen() + { + if ($this->_isScreened) { + return; + } + $this->_readScalerType(); + } + + /** + * Reads and parses the font data from the file on disk. + * + * NOTE: This method should be overridden in subclasses to add type- + * specific parsing and set $this->isParsed. + * + * @throws Zend_Pdf_Exception + */ + public function parse() + { + if ($this->_isParsed) { + return; + } + + /* Screen the font file first, if it hasn't been done yet. + */ + $this->screen(); + + /* Start by reading the table directory. + */ + $this->_parseTableDirectory(); + + /* Then parse all of the required tables. + */ + $this->_parseHeadTable(); + $this->_parseNameTable(); + $this->_parsePostTable(); + $this->_parseHheaTable(); + $this->_parseMaxpTable(); + $this->_parseOs2Table(); + $this->_parseHmtxTable(); + $this->_parseCmapTable(); + + /* If present, parse the optional tables. + */ + /** + * @todo Add parser for kerning pairs. + * @todo Add parser for ligatures. + * @todo Add parser for other useful hinting tables. + */ + } + + + + /**** Internal Methods ****/ + + + /* Parser Methods */ + + /** + * Parses the OpenType table directory. + * + * The table directory contains the identifier, checksum, byte offset, and + * length of each of the information tables housed in the font file. + * + * @throws Zend_Pdf_Exception + */ + protected function _parseTableDirectory() + { + $this->moveToOffset(4); + + $tableCount = $this->readUInt(2); + $this->_debugLog('%d tables', $tableCount); + + /* Sanity check, in case we're not actually reading a OpenType file and + * the first four bytes coincidentally matched an OpenType signature in + * screen() above. + * + * There are at minimum 7 required tables: cmap, head, hhea, hmtx, maxp, + * name, and post. In the current OpenType standard, only 32 table types + * are defined, so use 50 as a practical limit. + */ + if (($tableCount < 7) || ($tableCount > 50)) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Table count not within expected range', + Zend_Pdf_Exception::BAD_TABLE_COUNT); + } + + /* Skip the next 6 bytes, which contain values to aid a binary search. + */ + $this->skipBytes(6); + + /* The directory contains four values: the name of the table, checksum, + * offset to the table from the beginning of the font, and actual data + * length of the table. + */ + for ($tableIndex = 0; $tableIndex < $tableCount; $tableIndex++) { + $tableName = $this->readBytes(4); + + /* We ignore the checksum here for two reasons: First, the PDF viewer + * will do this later anyway; Second, calculating the checksum would + * require unsigned integers, which PHP does not currently provide. + * We may revisit this in the future. + */ + $this->skipBytes(4); + + $tableOffset = $this->readUInt(4); + $tableLength = $this->readUInt(4); + $this->_debugLog('%s offset: 0x%x; length: %d', $tableName, $tableOffset, $tableLength); + + /* Sanity checks for offset and length values. + */ + $fileSize = $this->_dataSource->getSize(); + if (($tableOffset < 0) || ($tableOffset > $fileSize)) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("Table offset ($tableOffset) not within expected range", + Zend_Pdf_Exception::INDEX_OUT_OF_RANGE); + } + if (($tableLength < 0) || (($tableOffset + $tableLength) > $fileSize)) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("Table length ($tableLength) not within expected range", + Zend_Pdf_Exception::INDEX_OUT_OF_RANGE); + } + + $this->_tableDirectory[$tableName]['offset'] = $tableOffset; + $this->_tableDirectory[$tableName]['length'] = $tableLength; + } + } + + + /** + * Parses the OpenType head (Font Header) table. + * + * The head table contains global information about the font such as the + * revision number and global metrics. + * + * @throws Zend_Pdf_Exception + */ + protected function _parseHeadTable() + { + $this->_jumpToTable('head'); + + /* We can read any version 1 table. + */ + $tableVersion = $this->_readTableVersion(1, 1); + + /* Skip the font revision number and checksum adjustment. + */ + $this->skipBytes(8); + + $magicNumber = $this->readUInt(4); + if ($magicNumber != 0x5f0f3cf5) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Wrong magic number. Expected: 0x5f0f3cf5; actual: ' + . sprintf('%x', $magicNumber), + Zend_Pdf_Exception::BAD_MAGIC_NUMBER); + } + + /* Most of the flags we ignore, but there are a few values that are + * useful for our layout routines. + */ + $flags = $this->readUInt(2); + $this->baselineAtZero = $this->isBitSet(0, $flags); + $this->useIntegerScaling = $this->isBitSet(3, $flags); + + $this->unitsPerEm = $this->readUInt(2); + $this->_debugLog('Units per em: %d', $this->unitsPerEm); + + /* Skip creation and modification date/time. + */ + $this->skipBytes(16); + + $this->xMin = $this->readInt(2); + $this->yMin = $this->readInt(2); + $this->xMax = $this->readInt(2); + $this->yMax = $this->readInt(2); + $this->_debugLog('Font bounding box: %d %d %d %d', + $this->xMin, $this->yMin, $this->xMax, $this->yMax); + + /* The style bits here must match the fsSelection bits in the OS/2 + * table, if present. + */ + $macStyleBits = $this->readUInt(2); + $this->isBold = $this->isBitSet(0, $macStyleBits); + $this->isItalic = $this->isBitSet(1, $macStyleBits); + + /* We don't need the remainder of data in this table: smallest readable + * size, font direction hint, indexToLocFormat, and glyphDataFormat. + */ + } + + + /** + * Parses the OpenType name (Naming) table. + * + * The name table contains all of the identifying strings associated with + * the font such as its name, copyright, trademark, license, etc. + * + * @throws Zend_Pdf_Exception + */ + protected function _parseNameTable() + { + $this->_jumpToTable('name'); + $baseOffset = $this->_tableDirectory['name']['offset']; + + /* The name table begins with a short header, followed by each of the + * fixed-length name records, followed by the variable-length strings. + */ + + /* We only understand version 0 tables. + */ + $tableFormat = $this->readUInt(2); + if ($tableFormat != 0) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("Unable to read format $tableFormat table", + Zend_Pdf_Exception::DONT_UNDERSTAND_TABLE_VERSION); + } + $this->_debugLog('Format %d table', $tableFormat); + + $nameCount = $this->readUInt(2); + $this->_debugLog('%d name strings', $nameCount); + + $storageOffset = $this->readUInt(2) + $baseOffset; + $this->_debugLog('Storage offset: 0x%x', $storageOffset); + + /* Scan the name records for those we're interested in. We'll skip over + * encodings and languages we don't understand or support. Prefer the + * Microsoft Unicode encoding for a given name/language combination, but + * use Mac Roman if nothing else is available. We will extract the + * actual strings later. + */ + $nameRecords = array(); + for ($nameIndex = 0; $nameIndex < $nameCount; $nameIndex++) { + + $platformID = $this->readUInt(2); + $encodingID = $this->readUInt(2); + + if (! ( (($platformID == 3) && ($encodingID == 1)) || // Microsoft Unicode + (($platformID == 1) && ($encodingID == 0)) // Mac Roman + ) ) { + $this->skipBytes(8); // Not a supported encoding. Move on. + continue; + } + + $languageID = $this->readUInt(2); + $nameID = $this->readUInt(2); + $nameLength = $this->readUInt(2); + $nameOffset = $this->readUInt(2); + + $languageCode = $this->_languageCodeForPlatform($platformID, $languageID); + if ($languageCode === null) { + $this->_debugLog('Skipping languageID: 0x%x; platformID %d', $languageID, $platformID); + continue; // Not a supported language. Move on. + } + + $this->_debugLog('Adding nameID: %d; languageID: 0x%x; platformID: %d; offset: 0x%x (0x%x); length: %d', + $nameID, $languageID, $platformID, $baseOffset + $nameOffset, $nameOffset, $nameLength); + + /* Entries in the name table are sorted by platform ID. If an entry + * exists for both Mac Roman and Microsoft Unicode, the Unicode entry + * will prevail since it is processed last. + */ + $nameRecords[$nameID][$languageCode] = array('platform' => $platformID, + 'offset' => $nameOffset, + 'length' => $nameLength ); + } + + /* Now go back and extract the interesting strings. + */ + $fontNames = array(); + foreach ($nameRecords as $name => $languages) { + foreach ($languages as $language => $attributes) { + $stringOffset = $storageOffset + $attributes['offset']; + $this->moveToOffset($stringOffset); + if ($attributes['platform'] == 3) { + $string = $this->readStringUTF16($attributes['length']); + } else { + $string = $this->readStringMacRoman($attributes['length']); + } + $fontNames[$name][$language] = $string; + } + } + + $this->names = $fontNames; + } + + + /** + * Parses the OpenType post (PostScript Information) table. + * + * The post table contains additional information required for using the font + * on PostScript printers. It also contains the preferred location and + * thickness for an underline, which is used by our layout code. + * + * @throws Zend_Pdf_Exception + */ + protected function _parsePostTable() + { + $this->_jumpToTable('post'); + + /* We can read versions 1-4 tables. + */ + $tableVersion = $this->_readTableVersion(1, 4); + + $this->italicAngle = $this->readFixed(16, 16); + + $this->underlinePosition = $this->readInt(2); + $this->underlineThickness = $this->readInt(2); + + $fixedPitch = $this->readUInt(4); + $this->isMonospaced = ($fixedPitch !== 0); + + /* Skip over PostScript virtual memory usage. + */ + $this->skipBytes(16); + + /* The format of the remainder of this table is dependent on the table + * version. However, since it contains glyph ordering information and + * PostScript names which we don't use, move on. (This may change at + * some point in the future though...) + */ + } + + + /** + * Parses the OpenType hhea (Horizontal Header) table. + * + * The hhea table contains information used for horizontal layout. It also + * contains some vertical layout information for Apple systems. The vertical + * layout information for the PDF file is usually taken from the OS/2 table. + * + * @throws Zend_Pdf_Exception + */ + protected function _parseHheaTable() + { + $this->_jumpToTable('hhea'); + + /* We can read any version 1 table. + */ + $tableVersion = $this->_readTableVersion(1, 1); + + /* The typographic ascent, descent, and line gap values are Apple- + * specific. Similar values exist in the OS/2 table. We'll use these + * values unless better values are found in OS/2. + */ + $this->ascent = $this->readInt(2); + $this->descent = $this->readInt(2); + $this->lineGap = $this->readInt(2); + + /* The descent value is supposed to be negative--it's the distance + * relative to the baseline. However, some fonts improperly store a + * positive value in this field. If a positive value is found, flip the + * sign and record a warning in the debug log that we did this. + */ + if ($this->descent > 0) { + $this->_debugLog('Warning: Font should specify negative descent. Actual: %d; Using %d', + $this->descent, -$this->descent); + $this->descent = -$this->descent; + } + + /* Skip over advance width, left and right sidebearing, max x extent, + * caret slope rise, run, and offset, and the four reserved fields. + */ + $this->skipBytes(22); + + /* These values are needed to read the hmtx table. + */ + $this->metricDataFormat = $this->readInt(2); + $this->numberHMetrics = $this->readUInt(2); + $this->_debugLog('hmtx data format: %d; number of metrics: %d', + $this->metricDataFormat, $this->numberHMetrics); + } + + + /** + * Parses the OpenType hhea (Horizontal Header) table. + * + * The hhea table contains information used for horizontal layout. It also + * contains some vertical layout information for Apple systems. The vertical + * layout information for the PDF file is usually taken from the OS/2 table. + * + * @throws Zend_Pdf_Exception + */ + protected function _parseMaxpTable() + { + $this->_jumpToTable('maxp'); + + /* We don't care about table version. + */ + $this->_readTableVersion(0, 1); + + /* The number of glyphs in the font. + */ + $this->numGlyphs = $this->readUInt(2); + $this->_debugLog('number of glyphs: %d', $this->numGlyphs); + + // Skip other maxp table entries (if presented with table version 1.0)... + } + + + /** + * Parses the OpenType OS/2 (OS/2 and Windows Metrics) table. + * + * The OS/2 table contains additional metrics data that is required to use + * the font on the OS/2 or Microsoft Windows platforms. It is not required + * for Macintosh fonts, so may not always be present. When available, we use + * this table to determine most of the vertical layout and stylistic + * information and for the font. + * + * @throws Zend_Pdf_Exception + */ + protected function _parseOs2Table() + { + if (! $this->numberHMetrics) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("hhea table must be parsed prior to calling this method", + Zend_Pdf_Exception::PARSED_OUT_OF_ORDER); + } + + try { + $this->_jumpToTable('OS/2'); + } catch (Zend_Pdf_Exception $e) { + /* This table is not always present. If missing, use default values. + */ + // require_once 'Zend/Pdf/Exception.php'; + if ($e->getCode() == Zend_Pdf_Exception::REQUIRED_TABLE_NOT_FOUND) { + $this->_debugLog('No OS/2 table found. Using default values'); + $this->fontWeight = Zend_Pdf_Font::WEIGHT_NORMAL; + $this->fontWidth = Zend_Pdf_Font::WIDTH_NORMAL; + $this->isEmbeddable = true; + $this->isSubsettable = true; + $this->strikeThickness = $this->unitsPerEm * 0.05; + $this->strikePosition = $this->unitsPerEm * 0.225; + $this->isSerifFont = false; // the style of the font is unknown + $this->isSansSerifFont = false; + $this->isOrnamentalFont = false; + $this->isScriptFont = false; + $this->isSymbolicFont = false; + $this->isAdobeLatinSubset = false; + $this->vendorID = ''; + $this->xHeight = 0; + $this->capitalHeight = 0; + return; + } else { + /* Something else went wrong. Throw this exception higher up the chain. + */ + throw $e; + throw new Zend_Pdf_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /* Version 0 tables are becoming rarer these days. They are only found + * in older fonts. + * + * Version 1 formally defines the Unicode character range bits and adds + * two new fields to the end of the table. + * + * Version 2 defines several additional flags to the embedding bits + * (fsType field) and five new fields to the end of the table. + * + * Versions 2 and 3 are structurally identical. There are only two + * significant differences between the two: First, in version 3, the + * average character width (xAvgCharWidth field) is calculated using all + * non-zero width glyphs in the font instead of just the Latin lower- + * case alphabetic characters; this doesn't affect us. Second, in + * version 3, the embedding bits (fsType field) have been made mutually + * exclusive; see additional discusson on this below. + * + * We can understand all four of these table versions. + */ + $tableVersion = $this->readUInt(2); + if (($tableVersion < 0) || ($tableVersion > 3)) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("Unable to read version $tableVersion table", + Zend_Pdf_Exception::DONT_UNDERSTAND_TABLE_VERSION); + } + $this->_debugLog('Version %d table', $tableVersion); + + $this->averageCharWidth = $this->readInt(2); + + /* Indicates the visual weight and aspect ratio of the characters. Used + * primarily to logically sort fonts in lists. Also used to help choose + * a more appropriate substitute font when necessary. See the WEIGHT_ + * and WIDTH_ constants defined in Zend_Pdf_Font. + */ + $this->fontWeight = $this->readUInt(2); + $this->fontWidth = $this->readUInt(2); + + /* Describes the font embedding licensing rights. We can only embed and + * subset a font when given explicit permission. + * + * NOTE: We always interpret these bits according to the rules defined + * in version 3 of this table, regardless of the actual version. This + * means we will perform our checks in order from the most-restrictive + * to the least. + */ + $embeddingFlags = $this->readUInt(2); + $this->_debugLog('Embedding flags: %d', $embeddingFlags); + if ($this->isBitSet(9, $embeddingFlags)) { + /* Only bitmaps may be embedded. We don't have the ability to strip + * outlines from fonts yet, so this means no embed. + */ + $this->isEmbeddable = false; + } elseif ($this->isBitSet(2, $embeddingFlags) + || $this->isBitSet(3, $embeddingFlags) + || $this->isBitSet(4, $embeddingFlags) + ) { + /* One of: + * Restricted License embedding (0x0002) + * Preview & Print embedding (0x0004) + * Editable embedding (0x0008) + * is set. + */ + $this->isEmbeddable = true; + } elseif ($this->isBitSet(1, $embeddingFlags)) { + /* Restricted license embedding & no other embedding is set. + * We currently don't have any way to + * enforce this, so interpret this as no embed. This may be revised + * in the future... + */ + $this->isEmbeddable = false; + } else { + /* The remainder of the bit settings grant us permission to embed + * the font. There may be additional usage rights granted or denied + * but those only affect the PDF viewer application, not our code. + */ + $this->isEmbeddable = true; + } + $this->_debugLog('Font ' . ($this->isEmbeddable ? 'may' : 'may not') . ' be embedded'); + $isSubsettable = $this->isBitSet($embeddingFlags, 8); + + /* Recommended size and offset for synthesized subscript characters. + */ + $this->subscriptXSize = $this->readInt(2); + $this->subscriptYSize = $this->readInt(2); + $this->subscriptXOffset = $this->readInt(2); + $this->subscriptYOffset = $this->readInt(2); + + /* Recommended size and offset for synthesized superscript characters. + */ + $this->superscriptXSize = $this->readInt(2); + $this->superscriptYSize = $this->readInt(2); + $this->superscriptXOffset = $this->readInt(2); + $this->superscriptYOffset = $this->readInt(2); + + /* Size and vertical offset for the strikethrough. + */ + $this->strikeThickness = $this->readInt(2); + $this->strikePosition = $this->readInt(2); + + /* Describes the class of font: serif, sans serif, script. etc. These + * values are defined here: + * http://www.microsoft.com/OpenType/OTSpec/ibmfc.htm + */ + $familyClass = ($this->readUInt(2) >> 8); // don't care about subclass + $this->_debugLog('Font family class: %d', $familyClass); + $this->isSerifFont = ((($familyClass >= 1) && ($familyClass <= 5)) || + ($familyClass == 7)); + $this->isSansSerifFont = ($familyClass == 8); + $this->isOrnamentalFont = ($familyClass == 9); + $this->isScriptFont = ($familyClass == 10); + $this->isSymbolicFont = ($familyClass == 12); + + /* Skip over the PANOSE number. The interesting values for us overlap + * with the font family class defined above. + */ + $this->skipBytes(10); + + /* The Unicode range is made up of four 4-byte unsigned long integers + * which are used as bitfields covering a 128-bit range. Each bit + * represents a Unicode code block. If the bit is set, this font at + * least partially covers the characters in that block. + */ + $unicodeRange1 = $this->readUInt(4); + $unicodeRange2 = $this->readUInt(4); + $unicodeRange3 = $this->readUInt(4); + $unicodeRange4 = $this->readUInt(4); + $this->_debugLog('Unicode ranges: 0x%x 0x%x 0x%x 0x%x', + $unicodeRange1, $unicodeRange2, $unicodeRange3, $unicodeRange4); + + /* The Unicode range is currently only used to decide if the character + * set covered by the font is a subset of the Adobe Latin set, meaning + * it only has the basic latin set. If it covers any other characters, + * even any of the extended latin characters, it is considered symbolic + * to PDF and must be described differently in the Font Descriptor. + */ + /** + * @todo Font is recognized as Adobe Latin subset font if it only contains + * Basic Latin characters (only bit 0 of Unicode range bits is set). + * Actually, other Unicode subranges like General Punctuation (bit 31) also + * fall into Adobe Latin characters. So this code has to be modified. + */ + $this->isAdobeLatinSubset = (($unicodeRange1 == 1) && ($unicodeRange2 == 0) && + ($unicodeRange3 == 0) && ($unicodeRange4 == 0)); + $this->_debugLog(($this->isAdobeLatinSubset ? 'Is' : 'Is not') . ' a subset of Adobe Latin'); + + $this->vendorID = $this->readBytes(4); + + /* Skip the font style bits. We use the values found in the 'head' table. + * Also skip the first Unicode and last Unicode character indicies. Our + * cmap implementation does not need these values. + */ + $this->skipBytes(6); + + /* Typographic ascender, descender, and line gap. These values are + * preferred to those in the 'hhea' table. + */ + $this->ascent = $this->readInt(2); + $this->descent = $this->readInt(2); + $this->lineGap = $this->readInt(2); + + /* The descent value is supposed to be negative--it's the distance + * relative to the baseline. However, some fonts improperly store a + * positive value in this field. If a positive value is found, flip the + * sign and record a warning in the debug log that we did this. + */ + if ($this->descent > 0) { + $this->_debugLog('Warning: Font should specify negative descent. Actual: %d; Using %d', + $this->descent, -$this->descent); + $this->descent = -$this->descent; + } + + /* Skip over Windows-specific ascent and descent. + */ + $this->skipBytes(4); + + /* Versions 0 and 1 tables do not contain the x or capital height + * fields. Record zero for unknown. + */ + if ($tableVersion < 2) { + $this->xHeight = 0; + $this->capitalHeight = 0; + } else { + + /* Skip over the Windows code page coverages. We are only concerned + * with Unicode coverage. + */ + $this->skipBytes(8); + + $this->xHeight = $this->readInt(2); + $this->capitalHeight = $this->readInt(2); + + /* Ignore the remaining fields in this table. They are Windows-specific. + */ + } + /** + * @todo Obtain the x and capital heights from the 'glyf' table if they + * haven't been supplied here instead of storing zero. + */ + } + + + /** + * Parses the OpenType hmtx (Horizontal Metrics) table. + * + * The hmtx table contains the horizontal metrics for every glyph contained + * within the font. These are the critical values for horizontal layout of + * text. + * + * @throws Zend_Pdf_Exception + */ + protected function _parseHmtxTable() + { + $this->_jumpToTable('hmtx'); + + if (! $this->numberHMetrics) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("hhea table must be parsed prior to calling this method", + Zend_Pdf_Exception::PARSED_OUT_OF_ORDER); + } + + /* We only understand version 0 tables. + */ + if ($this->metricDataFormat != 0) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("Unable to read format $this->metricDataFormat table.", + Zend_Pdf_Exception::DONT_UNDERSTAND_TABLE_VERSION); + } + + /* The hmtx table has no header. For each glpyh in the font, it contains + * the glyph's advance width and its left side bearing. We don't use the + * left side bearing. + */ + $glyphWidths = array(); + for ($i = 0; $i < $this->numberHMetrics; $i++) { + $glyphWidths[$i] = $this->readUInt(2); + $this->skipBytes(2); + } + /* Populate last value for the rest of array + */ + while (count($glyphWidths) < $this->numGlyphs) { + $glyphWidths[] = end($glyphWidths); + } + $this->glyphWidths = $glyphWidths; + + /* There is an optional table of left side bearings which is sometimes + * used for monospaced fonts. We don't use the left side bearing, so + * we can safely ignore it. + */ + } + + + /** + * Parses the OpenType cmap (Character to Glyph Mapping) table. + * + * The cmap table provides the maps from character codes to font glyphs. + * There are usually at least two character maps in a font: Microsoft Unicode + * and Macintosh Roman. For very complex fonts, there may also be mappings + * for the characters in the Unicode Surrogates Area, which are UCS-4 + * characters. + * + * @todo Need to rework the selection logic for picking a subtable. We should + * have an explicit list of preferences, followed by a list of those that + * are tolerable. Most specifically, since everything above this layer deals + * in Unicode, we need to be sure to only accept format 0 MacRoman tables. + * + * @throws Zend_Pdf_Exception + */ + protected function _parseCmapTable() + { + $this->_jumpToTable('cmap'); + $baseOffset = $this->_tableDirectory['cmap']['offset']; + + /* We only understand version 0 tables. + */ + $tableVersion = $this->readUInt(2); + if ($tableVersion != 0) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("Unable to read version $tableVersion table", + Zend_Pdf_Exception::DONT_UNDERSTAND_TABLE_VERSION); + } + $this->_debugLog('Version %d table', $tableVersion); + + $subtableCount = $this->readUInt(2); + $this->_debugLog('%d subtables', $subtableCount); + + /* Like the name table, there may be many different encoding subtables + * present. Ideally, we are looking for an acceptable Unicode table. + */ + $subtables = array(); + for ($subtableIndex = 0; $subtableIndex < $subtableCount; $subtableIndex++) { + + $platformID = $this->readUInt(2); + $encodingID = $this->readUInt(2); + + if (! ( (($platformID == 0) && ($encodingID == 3)) || // Unicode 2.0 or later + (($platformID == 0) && ($encodingID == 0)) || // Unicode + (($platformID == 3) && ($encodingID == 1)) || // Microsoft Unicode + (($platformID == 1) && ($encodingID == 0)) // Mac Roman + ) ) { + $this->_debugLog('Unsupported encoding: platformID: %d; encodingID: %d; skipping', + $platformID, $encodingID); + $this->skipBytes(4); + continue; + } + + $subtableOffset = $this->readUInt(4); + if ($subtableOffset < 0) { // Sanity check for 4-byte unsigned on 32-bit platform + $this->_debugLog('Offset 0x%x out of range for platformID: %d; skipping', + $subtableOffset, $platformID); + continue; + } + + $this->_debugLog('Found subtable; platformID: %d; encodingID: %d; offset: 0x%x (0x%x)', + $platformID, $encodingID, $baseOffset + $subtableOffset, $subtableOffset); + + $subtables[$platformID][$encodingID][] = $subtableOffset; + } + + /* In preferred order, find a subtable to use. + */ + $offsets = array(); + + /* Unicode 2.0 or later semantics + */ + if (isset($subtables[0][3])) { + foreach ($subtables[0][3] as $offset) { + $offsets[] = $offset; + } + } + + /* Unicode default semantics + */ + if (isset($subtables[0][0])) { + foreach ($subtables[0][0] as $offset) { + $offsets[] = $offset; + } + } + + /* Microsoft Unicode + */ + if (isset($subtables[3][1])) { + foreach ($subtables[3][1] as $offset) { + $offsets[] = $offset; + } + } + + /* Mac Roman. + */ + if (isset($subtables[1][0])) { + foreach ($subtables[1][0] as $offset) { + $offsets[] = $offset; + } + } + + $cmapType = -1; + + foreach ($offsets as $offset) { + $cmapOffset = $baseOffset + $offset; + $this->moveToOffset($cmapOffset); + $format = $this->readUInt(2); + $language = -1; + switch ($format) { + case 0x0: + $cmapLength = $this->readUInt(2); + $language = $this->readUInt(2); + if ($language != 0) { + $this->_debugLog('Type 0 cmap tables must be language-independent;' + . ' language: %d; skipping', $language); + continue; + } + break; + + case 0x4: // break intentionally omitted + case 0x6: + $cmapLength = $this->readUInt(2); + $language = $this->readUInt(2); + if ($language != 0) { + $this->_debugLog('Warning: cmap tables must be language-independent - this font' + . ' may not work properly; language: %d', $language); + } + break; + + case 0x2: // break intentionally omitted + case 0x8: // break intentionally omitted + case 0xa: // break intentionally omitted + case 0xc: + $this->_debugLog('Format: 0x%x currently unsupported; skipping', $format); + continue; + //$this->skipBytes(2); + //$cmapLength = $this->readUInt(4); + //$language = $this->readUInt(4); + //if ($language != 0) { + // $this->_debugLog('Warning: cmap tables must be language-independent - this font' + // . ' may not work properly; language: %d', $language); + //} + //break; + + default: + $this->_debugLog('Unknown subtable format: 0x%x; skipping', $format); + continue; + } + $cmapType = $format; + break; + } + if ($cmapType == -1) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Unable to find usable cmap table', + Zend_Pdf_Exception::CANT_FIND_GOOD_CMAP); + } + + /* Now extract the subtable data and create a Zend_Pdf_FontCmap object. + */ + $this->_debugLog('Using cmap type %d; offset: 0x%x; length: %d', + $cmapType, $cmapOffset, $cmapLength); + $this->moveToOffset($cmapOffset); + $cmapData = $this->readBytes($cmapLength); + + // require_once 'Zend/Pdf/Cmap.php'; + $this->cmap = Zend_Pdf_Cmap::cmapWithTypeData($cmapType, $cmapData); + } + + + /** + * Reads the scaler type from the header of the OpenType font file and + * returns it as an unsigned long integer. + * + * The scaler type defines the type of font: OpenType font files may contain + * TrueType or PostScript outlines. Throws an exception if the scaler type + * is not recognized. + * + * @return integer + * @throws Zend_Pdf_Exception + */ + protected function _readScalerType() + { + if ($this->_scalerType != 0) { + return $this->_scalerType; + } + + $this->moveToOffset(0); + + $this->_scalerType = $this->readUInt(4); + + switch ($this->_scalerType) { + case 0x00010000: // version 1.0 - Windows TrueType signature + $this->_debugLog('Windows TrueType signature'); + break; + + case 0x74727565: // 'true' - Macintosh TrueType signature + $this->_debugLog('Macintosh TrueType signature'); + break; + + case 0x4f54544f: // 'OTTO' - the CFF signature + $this->_debugLog('PostScript CFF signature'); + break; + + case 0x74797031: // 'typ1' + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Unsupported font type: PostScript in sfnt wrapper', + Zend_Pdf_Exception::WRONG_FONT_TYPE); + + default: + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Not an OpenType font file', + Zend_Pdf_Exception::WRONG_FONT_TYPE); + } + return $this->_scalerType; + } + + /** + * Validates a given table's existence, then sets the file pointer to the + * start of that table. + * + * @param string $tableName + * @throws Zend_Pdf_Exception + */ + protected function _jumpToTable($tableName) + { + if (empty($this->_tableDirectory[$tableName])) { // do not allow NULL or zero + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("Required table '$tableName' not found!", + Zend_Pdf_Exception::REQUIRED_TABLE_NOT_FOUND); + } + $this->_debugLog("Parsing $tableName table..."); + $this->moveToOffset($this->_tableDirectory[$tableName]['offset']); + } + + /** + * Reads the fixed 16.16 table version number and checks for compatibility. + * If the version is incompatible, throws an exception. If it is compatible, + * returns the version number. + * + * @param float $minVersion Minimum compatible version number. + * @param float $maxVertion Maximum compatible version number. + * @return float Table version number. + * @throws Zend_Pdf_Exception + */ + protected function _readTableVersion($minVersion, $maxVersion) + { + $tableVersion = $this->readFixed(16, 16); + if (($tableVersion < $minVersion) || ($tableVersion > $maxVersion)) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("Unable to read version $tableVersion table", + Zend_Pdf_Exception::DONT_UNDERSTAND_TABLE_VERSION); + } + $this->_debugLog('Version %.2f table', $tableVersion); + return $tableVersion; + } + + /** + * Utility method that returns ISO 639 two-letter language codes from the + * TrueType platform and language ID. Returns NULL for languages that are + * not supported. + * + * @param integer $platformID + * @param integer $encodingID + * @return string | null + */ + protected function _languageCodeForPlatform($platformID, $languageID) + { + if ($platformID == 3) { // Microsoft encoding. + /* The low-order bytes specify the language, the high-order bytes + * specify the dialect. We just care about the language. For the + * complete list, see: + * http://www.microsoft.com/globaldev/reference/lcid-all.mspx + */ + $languageID &= 0xff; + switch ($languageID) { + case 0x09: + return 'en'; + case 0x0c: + return 'fr'; + case 0x07: + return 'de'; + case 0x10: + return 'it'; + case 0x13: + return 'nl'; + case 0x1d: + return 'sv'; + case 0x0a: + return 'es'; + case 0x06: + return 'da'; + case 0x16: + return 'pt'; + case 0x14: + return 'no'; + case 0x0d: + return 'he'; + case 0x11: + return 'ja'; + case 0x01: + return 'ar'; + case 0x0b: + return 'fi'; + case 0x08: + return 'el'; + + default: + return null; + } + + } else if ($platformID == 1) { // Macintosh encoding. + switch ($languageID) { + case 0: + return 'en'; + case 1: + return 'fr'; + case 2: + return 'de'; + case 3: + return 'it'; + case 4: + return 'nl'; + case 5: + return 'sv'; + case 6: + return 'es'; + case 7: + return 'da'; + case 8: + return 'pt'; + case 9: + return 'no'; + case 10: + return 'he'; + case 11: + return 'ja'; + case 12: + return 'ar'; + case 13: + return 'fi'; + case 14: + return 'el'; + + default: + return null; + } + + } else { // Unknown encoding. + return null; + } + } + +} diff --git a/library/Zend/Pdf/FileParser/Font/OpenType/TrueType.php b/library/Zend/Pdf/FileParser/Font/OpenType/TrueType.php new file mode 100644 index 0000000..5944b7f --- /dev/null +++ b/library/Zend/Pdf/FileParser/Font/OpenType/TrueType.php @@ -0,0 +1,90 @@ +_isScreened) { + return; + } + + parent::screen(); + + switch ($this->_readScalerType()) { + case 0x00010000: // version 1.0 - Windows TrueType signature + break; + + case 0x74727565: // 'true' - Macintosh TrueType signature + break; + + default: + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Not a TrueType font file', + Zend_Pdf_Exception::WRONG_FONT_TYPE); + } + + $this->fontType = Zend_Pdf_Font::TYPE_TRUETYPE; + $this->_isScreened = true; + } + + /** + * Reads and parses the TrueType font data from the file on disk. + * + * @throws Zend_Pdf_Exception + */ + public function parse() + { + if ($this->_isParsed) { + return; + } + + parent::parse(); + + /* There is nothing additional to parse for TrueType fonts at this time. + */ + + $this->_isParsed = true; + } +} diff --git a/library/Zend/Pdf/FileParser/Image.php b/library/Zend/Pdf/FileParser/Image.php new file mode 100644 index 0000000..560c3e9 --- /dev/null +++ b/library/Zend/Pdf/FileParser/Image.php @@ -0,0 +1,63 @@ +imageType = Zend_Pdf_Image::TYPE_UNKNOWN; + } +} diff --git a/library/Zend/Pdf/FileParser/Image/Png.php b/library/Zend/Pdf/FileParser/Image/Png.php new file mode 100644 index 0000000..787a2c8 --- /dev/null +++ b/library/Zend/Pdf/FileParser/Image/Png.php @@ -0,0 +1,329 @@ +_isParsed) { + $this->parse(); + } + return $this->_width; + } + + public function getHeight() { + if(!$this->_isParsed) { + $this->parse(); + } + return $this->_width; + } + + public function getBitDepth() { + if(!$this->_isParsed) { + $this->parse(); + } + return $this->_bits; + } + + public function getColorSpace() { + if(!$this->_isParsed) { + $this->parse(); + } + return $this->_color; + } + + public function getCompressionStrategy() { + if(!$this->_isParsed) { + $this->parse(); + } + return $this->_compression; + } + + public function getPaethFilter() { + if(!$this->_isParsed) { + $this->parse(); + } + return $this->_preFilter; + } + + public function getInterlacingMode() { + if(!$this->_isParsed) { + $this->parse(); + } + return $this->_interlacing; + } + + public function getRawImageData() { + if(!$this->_isParsed) { + $this->parse(); + } + return $this->_imageData; + } + + public function getRawPaletteData() { + if(!$this->_isParsed) { + $this->parse(); + } + return $this->_paletteData; + } + + public function getRawTransparencyData() { + if(!$this->_isParsed) { + $this->parse(); + } + return $this->_transparencyData; + } + + /* Semi-Concrete Class Implementation */ + + /** + * Verifies that the image file is in the expected format. + * + * @throws Zend_Pdf_Exception + */ + public function screen() + { + if ($this->_isScreened) { + return; + } + return $this->_checkSignature(); + } + + /** + * Reads and parses the image data from the file on disk. + * + * @throws Zend_Pdf_Exception + */ + public function parse() + { + if ($this->_isParsed) { + return; + } + + /* Screen the font file first, if it hasn't been done yet. + */ + $this->screen(); + + $this->_parseIHDRChunk(); + $this->_parseChunks(); + } + + + protected function _parseSignature() { + $this->moveToOffset(1); //Skip the first byte (%) + if('PNG' != $this->readBytes(3)) { + $this->_isPNG = false; + } else { + $this->_isPNG = true; + } + } + + protected function _checkSignature() { + if(!isset($this->_isPNG)) { + $this->_parseSignature(); + } + return $this->_isPNG; + } + + protected function _parseChunks() { + $this->moveToOffset(33); //Variable chunks start at the end of IHDR + + //Start processing chunks. If there are no more bytes to read parsing is complete. + $size = $this->getSize(); + while($size - $this->getOffset() >= 8) { + $chunkLength = $this->readUInt(4); + if($chunkLength < 0 || ($chunkLength + $this->getOffset() + 4) > $size) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("PNG Corrupt: Invalid Chunk Size In File."); + } + + $chunkType = $this->readBytes(4); + $offset = $this->getOffset(); + + //If we know how to process the chunk, do it here, else ignore the chunk and move on to the next + switch($chunkType) { + case 'IDAT': // This chunk may appear more than once. It contains the actual image data. + $this->_parseIDATChunk($offset, $chunkLength); + break; + + case 'PLTE': // This chunk contains the image palette. + $this->_parsePLTEChunk($offset, $chunkLength); + break; + + case 'tRNS': // This chunk contains non-alpha channel transparency data + $this->_parseTRNSChunk($offset, $chunkLength); + break; + + case 'IEND': + break 2; //End the loop too + + //@TODO Implement the rest of the PNG chunks. (There are many not implemented here) + } + if($offset + $chunkLength + 4 < $size) { + $this->moveToOffset($offset + $chunkLength + 4); //Skip past the data finalizer. (Don't rely on the parse to leave the offsets correct) + } + } + if(empty($this->_imageData)) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception ( "This PNG is corrupt. All png must contain IDAT chunks." ); + } + } + + protected function _parseIHDRChunk() { + $this->moveToOffset(12); //IHDR must always start at offset 12 and run for 17 bytes + if(!$this->readBytes(4) == 'IHDR') { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception( "This PNG is corrupt. The first chunk in a PNG file must be IHDR." ); + } + $this->_width = $this->readUInt(4); + $this->_height = $this->readUInt(4); + $this->_bits = $this->readInt(1); + $this->_color = $this->readInt(1); + $this->_compression = $this->readInt(1); + $this->_preFilter = $this->readInt(1); + $this->_interlacing = $this->readInt(1); + if($this->_interlacing != Zend_Pdf_Image::PNG_INTERLACING_DISABLED) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception( "Only non-interlaced images are currently supported." ); + } + } + + protected function _parseIDATChunk($chunkOffset, $chunkLength) { + $this->moveToOffset($chunkOffset); + if(!isset($this->_imageData)) { + $this->_imageData = $this->readBytes($chunkLength); + } else { + $this->_imageData .= $this->readBytes($chunkLength); + } + } + + protected function _parsePLTEChunk($chunkOffset, $chunkLength) { + $this->moveToOffset($chunkOffset); + $this->_paletteData = $this->readBytes($chunkLength); + } + + protected function _parseTRNSChunk($chunkOffset, $chunkLength) { + $this->moveToOffset($chunkOffset); + + //Processing of tRNS data varies dependending on the color depth + + switch($this->_color) { + case Zend_Pdf_Image::PNG_CHANNEL_GRAY: + $baseColor = $this->readInt(1); + $this->_transparencyData = array($baseColor, $baseColor); + break; + + case Zend_Pdf_Image::PNG_CHANNEL_RGB: + + //@TODO Fix this hack. + //This parser cheats and only uses the lsb's (and only works with < 16 bit depth images) + + /* + From the standard: + + For color type 2 (truecolor), the tRNS chunk contains a single RGB color value, stored in the format: + + Red: 2 bytes, range 0 .. (2^bitdepth)-1 + Green: 2 bytes, range 0 .. (2^bitdepth)-1 + Blue: 2 bytes, range 0 .. (2^bitdepth)-1 + + (If the image bit depth is less than 16, the least significant bits are used and the others are 0.) + Pixels of the specified color value are to be treated as transparent (equivalent to alpha value 0); + all other pixels are to be treated as fully opaque (alpha value 2bitdepth-1). + + */ + + $red = $this->readInt(1); + $this->skipBytes(1); + $green = $this->readInt(1); + $this->skipBytes(1); + $blue = $this->readInt(1); + + $this->_transparencyData = array($red, $red, $green, $green, $blue, $blue); + + break; + + case Zend_Pdf_Image::PNG_CHANNEL_INDEXED: + + //@TODO Fix this hack. + //This parser cheats too. It only masks the first color in the palette. + + /* + From the standard: + + For color type 3 (indexed color), the tRNS chunk contains a series of one-byte alpha values, corresponding to entries in the PLTE chunk: + + Alpha for palette index 0: 1 byte + Alpha for palette index 1: 1 byte + ...etc... + + Each entry indicates that pixels of the corresponding palette index must be treated as having the specified alpha value. + Alpha values have the same interpretation as in an 8-bit full alpha channel: 0 is fully transparent, 255 is fully opaque, + regardless of image bit depth. The tRNS chunk must not contain more alpha values than there are palette entries, + but tRNS can contain fewer values than there are palette entries. In this case, the alpha value for all remaining palette + entries is assumed to be 255. In the common case in which only palette index 0 need be made transparent, only a one-byte + tRNS chunk is needed. + + */ + + $tmpData = $this->readBytes($chunkLength); + if(($trnsIdx = strpos($tmpData, "\0")) !== false) { + $this->_transparencyData = array($trnsIdx, $trnsIdx); + } + + break; + + case Zend_Pdf_Image::PNG_CHANNEL_GRAY_ALPHA: + //Fall through to the next case + case Zend_Pdf_Image::PNG_CHANNEL_RGB_ALPHA: + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception( "tRNS chunk illegal for Alpha Channel Images" ); + break; + } + } +} diff --git a/library/Zend/Pdf/FileParserDataSource.php b/library/Zend/Pdf/FileParserDataSource.php new file mode 100644 index 0000000..d6ef6ee --- /dev/null +++ b/library/Zend/Pdf/FileParserDataSource.php @@ -0,0 +1,189 @@ +_offset. + * + * Throws an exception if there is insufficient data to completely fulfill + * the request or if an error occurs. + * + * @param integer $byteCount Number of bytes to read. + * @return string + * @throws Zend_Pdf_Exception + */ + abstract public function readBytes($byteCount); + + /** + * Returns the entire contents of the data source as a string. + * + * This method may be called at any time and so must preserve the byte + * offset of the read position, both through $this->_offset and whatever + * other additional pointers (such as the seek position of a file pointer) + * that might be used. + * + * @return string + */ + abstract public function readAllBytes(); + + + /* Object Magic Methods */ + + /** + * Returns a description of the object for debugging purposes. + * + * Subclasses should override this method to provide a more specific + * description of the actual object being represented. + * + * @return string + */ + public function __toString() + { + return get_class($this); + } + + + /* Accessors */ + + /** + * Returns the byte offset of the current read position within the data + * source. + * + * @return integer + */ + public function getOffset() + { + return $this->_offset; + } + + /** + * Returns the total size in bytes of the data source. + * + * @return integer + */ + public function getSize() + { + return $this->_size; + } + + + /* Primitive Methods */ + + /** + * Moves the current read position to the specified byte offset. + * + * Throws an exception you attempt to move before the beginning or beyond + * the end of the data source. + * + * If a subclass needs to perform additional tasks (such as performing a + * fseek() on a filesystem source), it should do so after calling this + * parent method. + * + * @param integer $offset Destination byte offset. + * @throws Zend_Pdf_Exception + */ + public function moveToOffset($offset) + { + if ($this->_offset == $offset) { + return; // Not moving; do nothing. + } + if ($offset < 0) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Attempt to move before start of data source', + Zend_Pdf_Exception::MOVE_BEFORE_START_OF_FILE); + } + if ($offset >= $this->_size) { // Offsets are zero-based. + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Attempt to move beyond end of data source', + Zend_Pdf_Exception::MOVE_BEYOND_END_OF_FILE); + } + $this->_offset = $offset; + } + + /** + * Shifts the current read position within the data source by the specified + * number of bytes. + * + * You may move forward (positive numbers) or backward (negative numbers). + * Throws an exception you attempt to move before the beginning or beyond + * the end of the data source. + * + * @param integer $byteCount Number of bytes to skip. + * @throws Zend_Pdf_Exception + */ + public function skipBytes($byteCount) + { + $this->moveToOffset($this->_offset + $byteCount); + } +} diff --git a/library/Zend/Pdf/FileParserDataSource/File.php b/library/Zend/Pdf/FileParserDataSource/File.php new file mode 100644 index 0000000..d2ec9c7 --- /dev/null +++ b/library/Zend/Pdf/FileParserDataSource/File.php @@ -0,0 +1,198 @@ +_size = @filesize($filePath)) === false) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("Error while obtaining file size: $filePath", + Zend_Pdf_Exception::CANT_GET_FILE_SIZE); + } + if (($this->_fileResource = @fopen($filePath, 'rb')) === false) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("Cannot open file for reading: $filePath", + Zend_Pdf_Exception::CANT_OPEN_FILE); + } + $this->_filePath = $filePath; + } + + /** + * Object destructor. + * + * Closes the file if it had been successfully opened. + */ + public function __destruct() + { + if (is_resource($this->_fileResource)) { + @fclose($this->_fileResource); + } + } + + /** + * Returns the specified number of raw bytes from the file at the byte + * offset of the current read position. + * + * Advances the read position by the number of bytes read. + * + * Throws an exception if an error was encountered while reading the file or + * if there is insufficient data to completely fulfill the request. + * + * @param integer $byteCount Number of bytes to read. + * @return string + * @throws Zend_Pdf_Exception + */ + public function readBytes($byteCount) + { + $bytes = @fread($this->_fileResource, $byteCount); + if ($bytes === false) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Unexpected error while reading file', + Zend_Pdf_Exception::ERROR_DURING_READ); + } + if (strlen($bytes) != $byteCount) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("Insufficient data to read $byteCount bytes", + Zend_Pdf_Exception::INSUFFICIENT_DATA); + } + $this->_offset += $byteCount; + return $bytes; + } + + /** + * Returns the entire contents of the file as a string. + * + * Preserves the current file seek position. + * + * @return string + */ + public function readAllBytes() + { + return file_get_contents($this->_filePath); + } + + + /* Object Magic Methods */ + + /** + * Returns the full filesystem path of the file. + * + * @return string + */ + public function __toString() + { + return $this->_filePath; + } + + + /* Primitive Methods */ + + /** + * Seeks the file read position to the specified byte offset. + * + * Throws an exception if the file pointer cannot be moved or if it is + * moved beyond EOF (end of file). + * + * @param integer $offset Destination byte offset. + * @throws Zend_Pdf_Exception + */ + public function moveToOffset($offset) + { + if ($this->_offset == $offset) { + return; // Not moving; do nothing. + } + parent::moveToOffset($offset); + $result = @fseek($this->_fileResource, $offset, SEEK_SET); + if ($result !== 0) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Error while setting new file position', + Zend_Pdf_Exception::CANT_SET_FILE_POSITION); + } + if (feof($this->_fileResource)) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Moved beyond the end of the file', + Zend_Pdf_Exception::MOVE_BEYOND_END_OF_FILE); + } + } + +} diff --git a/library/Zend/Pdf/FileParserDataSource/String.php b/library/Zend/Pdf/FileParserDataSource/String.php new file mode 100644 index 0000000..a891719 --- /dev/null +++ b/library/Zend/Pdf/FileParserDataSource/String.php @@ -0,0 +1,128 @@ +_size = strlen($string); + $this->_string = $string; + } + + /** + * Object destructor. + */ + public function __destruct() + { + $this->_string = ''; + } + + /** + * Returns the specified number of raw bytes from the string at the byte + * offset of the current read position. + * + * Advances the read position by the number of bytes read. + * + * Throws an exception if there is insufficient data to completely fulfill + * the request. + * + * @param integer $byteCount Number of bytes to read. + * @return string + * @throws Zend_Pdf_Exception + */ + public function readBytes($byteCount) + { + if (($this->_offset + $byteCount) > $this->_size) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("Insufficient data to read $byteCount bytes", + Zend_Pdf_Exception::INSUFFICIENT_DATA); + } + $bytes = substr($this->_string, $this->_offset, $byteCount); + $this->_offset += $byteCount; + return $bytes; + } + + /** + * Returns the entire string. + * + * Preserves the current read position. + * + * @return string + */ + public function readAllBytes() + { + return $this->_string; + } + + + /* Object Magic Methods */ + + /** + * Returns a string containing the parsed string's length. + * + * @return string + */ + public function __toString() + { + return "String ($this->_size bytes)"; + } +} diff --git a/library/Zend/Pdf/Filter/Ascii85.php b/library/Zend/Pdf/Filter/Ascii85.php new file mode 100644 index 0000000..18a22d2 --- /dev/null +++ b/library/Zend/Pdf/Filter/Ascii85.php @@ -0,0 +1,181 @@ += 0; $j--) { + $foo = (int) (($b / pow(85,$j)) + 33); + $b %= pow(85,$j); + $output .= chr($foo); + } + } + + //encode partial chunk + if ($i < $dataLength) { + $n = $dataLength - $i; + $chunk = substr($data, -$n); + + //0 pad the rest + for ($j = $n;$j < 4;$j++) { + $chunk .= "\0"; + } + + $b = unpack("N", $chunk); + $b = $b[1]; + + //encode just $n + 1 + for ($j = 4; $j >= (4 - $n); $j--) { + $foo = (int) (($b / pow(85,$j)) + 33); + $b %= pow(85,$j); + $output .= chr($foo); + } + } + + //EOD + $output .= '~>'; + + //make sure lines are split + $output = chunk_split($output, 76, "\n"); + + //get rid of new line at the end + $output = substr($output, 0, -1); + return $output; + } + + /** + * Decode data + * + * @param string $data + * @param array $params + * @return string + * @throws Zend_Pdf_Exception + */ + public static function decode($data, $params = null) + { + $output = ''; + + //get rid of the whitespaces + $whiteSpace = array("\x00", "\x09", "\x0A", "\x0C", "\x0D", "\x20"); + $data = str_replace($whiteSpace, '', $data); + + if (substr($data, -2) != '~>') { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Invalid EOF marker'); + return ''; + } + + $data = substr($data, 0, (strlen($data) - 2)); + $dataLength = strlen($data); + + for ($i = 0; $i < $dataLength; $i += 5) { + $b = 0; + + if (substr($data, $i, 1) == "z") { + $i -= 4; + $output .= pack("N", 0); + continue; + } + + $c = substr($data, $i, 5); + + if(strlen($c) < 5) { + //partial chunk + break; + } + + $c = unpack('C5', $c); + $value = 0; + + for ($j = 1; $j <= 5; $j++) { + $value += (($c[$j] - 33) * pow(85, (5 - $j))); + } + + $output .= pack("N", $value); + } + + //decode partial + if ($i < $dataLength) { + $value = 0; + $chunk = substr($data, $i); + $partialLength = strlen($chunk); + + //pad the rest of the chunk with u's + //until the lenght of the chunk is 5 + for ($j = 0; $j < (5 - $partialLength); $j++) { + $chunk .= 'u'; + } + + $c = unpack('C5', $chunk); + + for ($j = 1; $j <= 5; $j++) { + $value += (($c[$j] - 33) * pow(85, (5 - $j))); + } + + $foo = pack("N", $value); + $output .= substr($foo, 0, ($partialLength - 1)); + } + + return $output; + } +} diff --git a/library/Zend/Pdf/Filter/AsciiHex.php b/library/Zend/Pdf/Filter/AsciiHex.php new file mode 100644 index 0000000..bd5b45d --- /dev/null +++ b/library/Zend/Pdf/Filter/AsciiHex.php @@ -0,0 +1,135 @@ +'; + } + + /** + * Decode data + * + * @param string $data + * @param array $params + * @return string + * @throws Zend_Pdf_Exception + */ + public static function decode($data, $params = null) + { + $output = ''; + $oddCode = true; + $commentMode = false; + + for ($count = 0; $count < strlen($data) && $data[$count] != '>'; $count++) { + $charCode = ord($data[$count]); + + if ($commentMode) { + if ($charCode == 0x0A || $charCode == 0x0D ) { + $commentMode = false; + } + + continue; + } + + switch ($charCode) { + //Skip white space + case 0x00: // null character + // fall through to next case + case 0x09: // Tab + // fall through to next case + case 0x0A: // Line feed + // fall through to next case + case 0x0C: // Form Feed + // fall through to next case + case 0x0D: // Carriage return + // fall through to next case + case 0x20: // Space + // Do nothing + break; + + case 0x25: // '%' + // Switch to comment mode + $commentMode = true; + break; + + default: + if ($charCode >= 0x30 /*'0'*/ && $charCode <= 0x39 /*'9'*/) { + $code = $charCode - 0x30; + } else if ($charCode >= 0x41 /*'A'*/ && $charCode <= 0x46 /*'F'*/) { + $code = $charCode - 0x37/*0x41 - 0x0A*/; + } else if ($charCode >= 0x61 /*'a'*/ && $charCode <= 0x66 /*'f'*/) { + $code = $charCode - 0x57/*0x61 - 0x0A*/; + } else { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Wrong character in a encoded stream'); + } + + if ($oddCode) { + // Odd pass. Store hex digit for next pass + // Scope of $hexCodeHigh variable is whole function + $hexCodeHigh = $code; + } else { + // Even pass. + // Add decoded character to the output + // ($hexCodeHigh is stored in previous pass) + $output .= chr($hexCodeHigh*16 + $code); + } + $oddCode = !$oddCode; + + break; + } + } + + /* Check that stream is terminated by End Of Data marker */ + if ($data[$count] != '>') { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Wrong encoded stream End Of Data marker.'); + } + + /* Last '0' character is omitted */ + if (!$oddCode) { + $output .= chr($hexCodeHigh*16); + } + + return $output; + } +} diff --git a/library/Zend/Pdf/Filter/Compression.php b/library/Zend/Pdf/Filter/Compression.php new file mode 100644 index 0000000..1e60d7d --- /dev/null +++ b/library/Zend/Pdf/Filter/Compression.php @@ -0,0 +1,391 @@ + 2) { + if ($chainStartOffset != $offset) { + // Drop down previouse (non-repeatable chars) run + $output .= chr($offset - $chainStartOffset - 1) + . substr($data, $chainStartOffset, $offset - $chainStartOffset); + } + + $output .= chr(257 - $repeatedCharChainLength) . $data[$offset]; + + $offset += $repeatedCharChainLength; + $chainStartOffset = $offset; + } else { + $offset++; + + if ($offset - $chainStartOffset == 128) { + // Maximum run length is reached + // Drop down non-repeatable chars run + $output .= "\x7F" . substr($data, $chainStartOffset, 128); + + $chainStartOffset = $offset; + } + } + } + + if ($chainStartOffset != $offset) { + // Drop down non-repeatable chars run + $output .= chr($offset - $chainStartOffset - 1) . substr($data, $chainStartOffset, $offset - $chainStartOffset); + } + + $output .= "\x80"; + + return $output; + } + + /** + * Decode data + * + * @param string $data + * @param array $params + * @return string + * @throws Zend_Pdf_Exception + */ + public static function decode($data, $params = null) + { + $dataLength = strlen($data); + $output = ''; + $offset = 0; + + while($offset < $dataLength) { + $length = ord($data[$offset]); + + $offset++; + + if ($length == 128) { + // EOD byte + break; + } else if ($length < 128) { + $length++; + + $output .= substr($data, $offset, $length); + + $offset += $length; + } else if ($length > 128) { + $output .= str_repeat($data[$offset], 257 - $length); + + $offset++; + } + } + + return $output; + } +} + diff --git a/library/Zend/Pdf/Font.php b/library/Zend/Pdf/Font.php new file mode 100644 index 0000000..6eb58d6 --- /dev/null +++ b/library/Zend/Pdf/Font.php @@ -0,0 +1,732 @@ +getFontName(Zend_Pdf_Font::NAME_POSTSCRIPT, '', ''); + Zend_Pdf_Font::$_fontNames[$fontName] = $font; + $filePathKey = md5($filePath); + Zend_Pdf_Font::$_fontFilePaths[$filePathKey] = $font; + return $font; + + } else { + /* The type of font could not be determined. Give up. + */ + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("Cannot determine font type: $filePath", + Zend_Pdf_Exception::CANT_DETERMINE_FONT_TYPE); + } + + } + + + + /**** Internal Methods ****/ + + + /* Font Extraction Methods */ + + /** + * Attempts to extract a TrueType font from the data source. + * + * If the font parser throws an exception that suggests the data source + * simply doesn't contain a TrueType font, catches it and returns null. If + * an exception is thrown that suggests the TrueType font is corrupt or + * otherwise unusable, throws that exception. If successful, returns the + * font object. + * + * @param Zend_Pdf_FileParserDataSource $dataSource + * @param integer $embeddingOptions Options for font embedding. + * @return Zend_Pdf_Resource_Font_OpenType_TrueType May also return null if + * the data source does not appear to contain a TrueType font. + * @throws Zend_Pdf_Exception + */ + protected static function _extractTrueTypeFont($dataSource, $embeddingOptions) + { + try { + // require_once 'Zend/Pdf/FileParser/Font/OpenType/TrueType.php'; + $fontParser = new Zend_Pdf_FileParser_Font_OpenType_TrueType($dataSource); + + $fontParser->parse(); + if ($fontParser->isAdobeLatinSubset) { + // require_once 'Zend/Pdf/Resource/Font/Simple/Parsed/TrueType.php'; + $font = new Zend_Pdf_Resource_Font_Simple_Parsed_TrueType($fontParser, $embeddingOptions); + } else { + // require_once 'Zend/Pdf/Resource/Font/CidFont/TrueType.php'; + // require_once 'Zend/Pdf/Resource/Font/Type0.php'; + /* Use Composite Type 0 font which supports Unicode character mapping */ + $cidFont = new Zend_Pdf_Resource_Font_CidFont_TrueType($fontParser, $embeddingOptions); + $font = new Zend_Pdf_Resource_Font_Type0($cidFont); + } + } catch (Zend_Pdf_Exception $e) { + /* The following exception codes suggest that this isn't really a + * TrueType font. If we caught such an exception, simply return + * null. For all other cases, it probably is a TrueType font but has + * a problem; throw the exception again. + */ + $fontParser = null; + // require_once 'Zend/Pdf/Exception.php'; + switch ($e->getCode()) { + case Zend_Pdf_Exception::WRONG_FONT_TYPE: // break intentionally omitted + case Zend_Pdf_Exception::BAD_TABLE_COUNT: // break intentionally omitted + case Zend_Pdf_Exception::BAD_MAGIC_NUMBER: + return null; + + default: + throw new Zend_Pdf_Exception($e->getMessage(), $e->getCode(), $e); + } + } + return $font; + } +} diff --git a/library/Zend/Pdf/Image.php b/library/Zend/Pdf/Image.php new file mode 100644 index 0000000..70590c8 --- /dev/null +++ b/library/Zend/Pdf/Image.php @@ -0,0 +1,247 @@ + object tree entries + * + * @var array + */ + protected $_items = array(); + + /** + * Object constructor + * + * @param Zend_Pdf_Element $rootDictionary root of name dictionary + */ + public function __construct(Zend_Pdf_Element $rootDictionary) + { + if ($rootDictionary->getType() != Zend_Pdf_Element::TYPE_DICTIONARY) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Name tree root must be a dictionary.'); + } + + $intermediateNodes = array(); + $leafNodes = array(); + if ($rootDictionary->Kids !== null) { + $intermediateNodes[] = $rootDictionary; + } else { + $leafNodes[] = $rootDictionary; + } + + while (count($intermediateNodes) != 0) { + $newIntermediateNodes = array(); + foreach ($intermediateNodes as $node) { + foreach ($node->Kids->items as $childNode) { + if ($childNode->Kids !== null) { + $newIntermediateNodes[] = $childNode; + } else { + $leafNodes[] = $childNode; + } + } + } + $intermediateNodes = $newIntermediateNodes; + } + + foreach ($leafNodes as $leafNode) { + $destinationsCount = count($leafNode->Names->items)/2; + for ($count = 0; $count < $destinationsCount; $count++) { + $this->_items[$leafNode->Names->items[$count*2]->value] = $leafNode->Names->items[$count*2 + 1]; + } + } + } + + public function current() + { + return current($this->_items); + } + + + public function next() + { + return next($this->_items); + } + + + public function key() + { + return key($this->_items); + } + + + public function valid() { + return current($this->_items)!==false; + } + + + public function rewind() + { + reset($this->_items); + } + + + public function offsetExists($offset) + { + return array_key_exists($offset, $this->_items); + } + + + public function offsetGet($offset) + { + return $this->_items[$offset]; + } + + + public function offsetSet($offset, $value) + { + if ($offset === null) { + $this->_items[] = $value; + } else { + $this->_items[$offset] = $value; + } + } + + + public function offsetUnset($offset) + { + unset($this->_items[$offset]); + } + + + public function clear() + { + $this->_items = array(); + } + + public function count() + { + return count($this->_items); + } +} diff --git a/library/Zend/Pdf/Outline.php b/library/Zend/Pdf/Outline.php new file mode 100644 index 0000000..1faccdf --- /dev/null +++ b/library/Zend/Pdf/Outline.php @@ -0,0 +1,373 @@ +_open; + } + + /** + * Sets 'isOpen' outline flag + * + * @param boolean $isOpen + * @return Zend_Pdf_Outline + */ + public function setIsOpen($isOpen) + { + $this->_open = $isOpen; + return $this; + } + + /** + * Returns true if outline item is displayed in italic + * + * @return boolean + */ + abstract public function isItalic(); + + /** + * Sets 'isItalic' outline flag + * + * @param boolean $isItalic + * @return Zend_Pdf_Outline + */ + abstract public function setIsItalic($isItalic); + + /** + * Returns true if outline item is displayed in bold + * + * @return boolean + */ + abstract public function isBold(); + + /** + * Sets 'isBold' outline flag + * + * @param boolean $isBold + * @return Zend_Pdf_Outline + */ + abstract public function setIsBold($isBold); + + + /** + * Get outline text color. + * + * @return Zend_Pdf_Color_Rgb + */ + abstract public function getColor(); + + /** + * Set outline text color. + * (null means default color which is black) + * + * @param Zend_Pdf_Color_Rgb $color + * @return Zend_Pdf_Outline + */ + abstract public function setColor(Zend_Pdf_Color_Rgb $color); + + /** + * Get outline target. + * + * @return Zend_Pdf_Target + */ + abstract public function getTarget(); + + /** + * Set outline target. + * Null means no target + * + * @param Zend_Pdf_Target|string $target + * @return Zend_Pdf_Outline + */ + abstract public function setTarget($target = null); + + /** + * Get outline options + * + * @return array + */ + public function getOptions() + { + return array('title' => $this->_title, + 'open' => $this->_open, + 'color' => $this->_color, + 'italic' => $this->_italic, + 'bold' => $this->_bold, + 'target' => $this->_target); + } + + /** + * Set outline options + * + * @param array $options + * @return Zend_Pdf_Action + * @throws Zend_Pdf_Exception + */ + public function setOptions(array $options) + { + foreach ($options as $key => $value) { + switch ($key) { + case 'title': + $this->setTitle($value); + break; + + case 'open': + $this->setIsOpen($value); + break; + + case 'color': + $this->setColor($value); + break; + case 'italic': + $this->setIsItalic($value); + break; + + case 'bold': + $this->setIsBold($value); + break; + + case 'target': + $this->setTarget($value); + break; + + default: + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("Unknown option name - '$key'."); + break; + } + } + + return $this; + } + + /** + * Create new Outline object + * + * It provides two forms of input parameters: + * + * 1. Zend_Pdf_Outline::create(string $title[, Zend_Pdf_Target $target]) + * 2. Zend_Pdf_Outline::create(array $options) + * + * Second form allows to provide outline options as an array. + * The followed options are supported: + * 'title' - string, outline title, required + * 'open' - boolean, true if outline entry is open (default value is false) + * 'color' - Zend_Pdf_Color_Rgb object, true if outline entry is open (default value is null - black) + * 'italic' - boolean, true if outline entry is displayed in italic (default value is false) + * 'bold' - boolean, true if outline entry is displayed in bold (default value is false) + * 'target' - Zend_Pdf_Target object or string, outline item destination + * + * @return Zend_Pdf_Outline + * @throws Zend_Pdf_Exception + */ + public static function create($param1, $param2 = null) + { + // require_once 'Zend/Pdf/Outline/Created.php'; + if (is_string($param1)) { + if ($param2 !== null && !($param2 instanceof Zend_Pdf_Target || is_string($param2))) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Outline create method takes $title (string) and $target (Zend_Pdf_Target or string) or an array as an input'); + } + + return new Zend_Pdf_Outline_Created(array('title' => $param1, + 'target' => $param2)); + } else { + if (!is_array($param1) || $param2 !== null) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Outline create method takes $title (string) and $destination (Zend_Pdf_Destination) or an array as an input'); + } + + return new Zend_Pdf_Outline_Created($param1); + } + } + + /** + * Returns number of the total number of open items at all levels of the outline. + * + * @internal + * @return integer + */ + public function openOutlinesCount() + { + $count = 1; // Include this outline + + if ($this->isOpen()) { + foreach ($this->childOutlines as $child) { + $count += $child->openOutlinesCount(); + } + } + + return $count; + } + + /** + * Dump Outline and its child outlines into PDF structures + * + * Returns dictionary indirect object or reference + * + * @param Zend_Pdf_ElementFactory $factory object factory for newly created indirect objects + * @param boolean $updateNavigation Update navigation flag + * @param Zend_Pdf_Element $parent Parent outline dictionary reference + * @param Zend_Pdf_Element $prev Previous outline dictionary reference + * @param SplObjectStorage $processedOutlines List of already processed outlines + * @return Zend_Pdf_Element + */ + abstract public function dumpOutline(Zend_Pdf_ElementFactory_Interface $factory, + $updateNavigation, + Zend_Pdf_Element $parent, + Zend_Pdf_Element $prev = null, + SplObjectStorage $processedOutlines = null); + + + //////////////////////////////////////////////////////////////////////// + // RecursiveIterator interface methods + ////////////// + + /** + * Returns the child outline. + * + * @return Zend_Pdf_Outline + */ + public function current() + { + return current($this->childOutlines); + } + + /** + * Returns current iterator key + * + * @return integer + */ + public function key() + { + return key($this->childOutlines); + } + + /** + * Go to next child + */ + public function next() + { + return next($this->childOutlines); + } + + /** + * Rewind children + */ + public function rewind() + { + return reset($this->childOutlines); + } + + /** + * Check if current position is valid + * + * @return boolean + */ + public function valid() + { + return current($this->childOutlines) !== false; + } + + /** + * Returns the child outline. + * + * @return Zend_Pdf_Outline|null + */ + public function getChildren() + { + return current($this->childOutlines); + } + + /** + * Implements RecursiveIterator interface. + * + * @return bool whether container has any pages + */ + public function hasChildren() + { + return count($this->childOutlines) > 0; + } + + + //////////////////////////////////////////////////////////////////////// + // Countable interface methods + ////////////// + + /** + * count() + * + * @return int + */ + public function count() + { + return count($this->childOutlines); + } +} diff --git a/library/Zend/Pdf/Outline/Created.php b/library/Zend/Pdf/Outline/Created.php new file mode 100644 index 0000000..37e530b --- /dev/null +++ b/library/Zend/Pdf/Outline/Created.php @@ -0,0 +1,315 @@ +_title; + } + + /** + * Set outline title + * + * @param string $title + * @return Zend_Pdf_Outline + */ + public function setTitle($title) + { + $this->_title = $title; + return $this; + } + + /** + * Returns true if outline item is displayed in italic + * + * @return boolean + */ + public function isItalic() + { + return $this->_italic; + } + + /** + * Sets 'isItalic' outline flag + * + * @param boolean $isItalic + * @return Zend_Pdf_Outline + */ + public function setIsItalic($isItalic) + { + $this->_italic = $isItalic; + return $this; + } + + /** + * Returns true if outline item is displayed in bold + * + * @return boolean + */ + public function isBold() + { + return $this->_bold; + } + + /** + * Sets 'isBold' outline flag + * + * @param boolean $isBold + * @return Zend_Pdf_Outline + */ + public function setIsBold($isBold) + { + $this->_bold = $isBold; + return $this; + } + + + /** + * Get outline text color. + * + * @return Zend_Pdf_Color_Rgb + */ + public function getColor() + { + return $this->_color; + } + + /** + * Set outline text color. + * (null means default color which is black) + * + * @param Zend_Pdf_Color_Rgb $color + * @return Zend_Pdf_Outline + */ + public function setColor(Zend_Pdf_Color_Rgb $color) + { + $this->_color = $color; + return $this; + } + + /** + * Get outline target. + * + * @return Zend_Pdf_Target + */ + public function getTarget() + { + return $this->_target; + } + + /** + * Set outline target. + * Null means no target + * + * @param Zend_Pdf_Target|string $target + * @return Zend_Pdf_Outline + * @throws Zend_Pdf_Exception + */ + public function setTarget($target = null) + { + if (is_string($target)) { + // require_once 'Zend/Pdf/Destination/Named.php'; + $target = new Zend_Pdf_Destination_Named($target); + } + + if ($target === null || $target instanceof Zend_Pdf_Target) { + $this->_target = $target; + } else { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Outline target has to be Zend_Pdf_Destination or Zend_Pdf_Action object or string'); + } + + return $this; + } + + + /** + * Object constructor + * + * @param array $options + * @throws Zend_Pdf_Exception + */ + public function __construct($options = array()) + { + if (!isset($options['title'])) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Title parameter is required.'); + } + + $this->setOptions($options); + } + + /** + * Dump Outline and its child outlines into PDF structures + * + * Returns dictionary indirect object or reference + * + * @internal + * @param Zend_Pdf_ElementFactory $factory object factory for newly created indirect objects + * @param boolean $updateNavigation Update navigation flag + * @param Zend_Pdf_Element $parent Parent outline dictionary reference + * @param Zend_Pdf_Element $prev Previous outline dictionary reference + * @param SplObjectStorage $processedOutlines List of already processed outlines + * @return Zend_Pdf_Element + * @throws Zend_Pdf_Exception + */ + public function dumpOutline(Zend_Pdf_ElementFactory_Interface $factory, + $updateNavigation, + Zend_Pdf_Element $parent, + Zend_Pdf_Element $prev = null, + SplObjectStorage $processedOutlines = null) + { + if ($processedOutlines === null) { + $processedOutlines = new SplObjectStorage(); + } + $processedOutlines->attach($this); + + $outlineDictionary = $factory->newObject(new Zend_Pdf_Element_Dictionary()); + + $outlineDictionary->Title = new Zend_Pdf_Element_String($this->getTitle()); + + $target = $this->getTarget(); + if ($target === null) { + // Do nothing + } else if ($target instanceof Zend_Pdf_Destination) { + $outlineDictionary->Dest = $target->getResource(); + } else if ($target instanceof Zend_Pdf_Action) { + $outlineDictionary->A = $target->getResource(); + } else { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Outline target has to be Zend_Pdf_Destination, Zend_Pdf_Action object or null'); + } + + $color = $this->getColor(); + if ($color !== null) { + $components = $color->getComponents(); + $colorComponentElements = array(new Zend_Pdf_Element_Numeric($components[0]), + new Zend_Pdf_Element_Numeric($components[1]), + new Zend_Pdf_Element_Numeric($components[2])); + $outlineDictionary->C = new Zend_Pdf_Element_Array($colorComponentElements); + } + + if ($this->isItalic() || $this->isBold()) { + $outlineDictionary->F = new Zend_Pdf_Element_Numeric(($this->isItalic()? 1 : 0) | // Bit 1 - Italic + ($this->isBold()? 2 : 0)); // Bit 2 - Bold + } + + + $outlineDictionary->Parent = $parent; + $outlineDictionary->Prev = $prev; + + $lastChild = null; + foreach ($this->childOutlines as $childOutline) { + if ($processedOutlines->contains($childOutline)) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Outlines cyclyc reference is detected.'); + } + + if ($lastChild === null) { + $lastChild = $childOutline->dumpOutline($factory, true, $outlineDictionary, null, $processedOutlines); + $outlineDictionary->First = $lastChild; + } else { + $childOutlineDictionary = $childOutline->dumpOutline($factory, true, $outlineDictionary, $lastChild, $processedOutlines); + $lastChild->Next = $childOutlineDictionary; + $lastChild = $childOutlineDictionary; + } + } + $outlineDictionary->Last = $lastChild; + + if (count($this->childOutlines) != 0) { + $outlineDictionary->Count = new Zend_Pdf_Element_Numeric(($this->isOpen()? 1 : -1)*count($this->childOutlines)); + } + + return $outlineDictionary; + } +} diff --git a/library/Zend/Pdf/Outline/Loaded.php b/library/Zend/Pdf/Outline/Loaded.php new file mode 100644 index 0000000..db7310e --- /dev/null +++ b/library/Zend/Pdf/Outline/Loaded.php @@ -0,0 +1,460 @@ +_outlineDictionary->Title === null) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Outline dictionary Title entry is required.'); + } + return $this->_outlineDictionary->Title->value; + } + + /** + * Set outline title + * + * @param string $title + * @return Zend_Pdf_Outline + */ + public function setTitle($title) + { + $this->_outlineDictionary->Title->touch(); + $this->_outlineDictionary->Title = new Zend_Pdf_Element_String($title); + return $this; + } + + /** + * Sets 'isOpen' outline flag + * + * @param boolean $isOpen + * @return Zend_Pdf_Outline + */ + public function setIsOpen($isOpen) + { + parent::setIsOpen($isOpen); + + if ($this->_outlineDictionary->Count === null) { + // Do Nothing. + return this; + } + + $childrenCount = $this->_outlineDictionary->Count->value; + $isOpenCurrentState = ($childrenCount > 0); + if ($isOpen != $isOpenCurrentState) { + $this->_outlineDictionary->Count->touch(); + $this->_outlineDictionary->Count->value = ($isOpen? 1 : -1)*abs($childrenCount); + } + + return $this; + } + + /** + * Returns true if outline item is displayed in italic + * + * @return boolean + */ + public function isItalic() + { + if ($this->_outlineDictionary->F === null) { + return false; + } + return $this->_outlineDictionary->F->value & 1; + } + + /** + * Sets 'isItalic' outline flag + * + * @param boolean $isItalic + * @return Zend_Pdf_Outline + */ + public function setIsItalic($isItalic) + { + if ($this->_outlineDictionary->F === null) { + $this->_outlineDictionary->touch(); + $this->_outlineDictionary->F = new Zend_Pdf_Element_Numeric($isItalic? 1 : 0); + } else { + $this->_outlineDictionary->F->touch(); + if ($isItalic) { + $this->_outlineDictionary->F->value = $this->_outlineDictionary->F->value | 1; + } else { + $this->_outlineDictionary->F->value = $this->_outlineDictionary->F->value | ~1; + } + } + return $this; + } + + /** + * Returns true if outline item is displayed in bold + * + * @return boolean + */ + public function isBold() + { + if ($this->_outlineDictionary->F === null) { + return false; + } + return $this->_outlineDictionary->F->value & 2; + } + + /** + * Sets 'isBold' outline flag + * + * @param boolean $isBold + * @return Zend_Pdf_Outline + */ + public function setIsBold($isBold) + { + if ($this->_outlineDictionary->F === null) { + $this->_outlineDictionary->touch(); + $this->_outlineDictionary->F = new Zend_Pdf_Element_Numeric($isBold? 2 : 0); + } else { + $this->_outlineDictionary->F->touch(); + if ($isBold) { + $this->_outlineDictionary->F->value = $this->_outlineDictionary->F->value | 2; + } else { + $this->_outlineDictionary->F->value = $this->_outlineDictionary->F->value | ~2; + } + } + return $this; + } + + + /** + * Get outline text color. + * + * @return Zend_Pdf_Color_Rgb + */ + public function getColor() + { + if ($this->_outlineDictionary->C === null) { + return null; + } + + $components = $this->_outlineDictionary->C->items; + + // require_once 'Zend/Pdf/Color/Rgb.php'; + return new Zend_Pdf_Color_Rgb($components[0], $components[1], $components[2]); + } + + /** + * Set outline text color. + * (null means default color which is black) + * + * @param Zend_Pdf_Color_Rgb $color + * @return Zend_Pdf_Outline + */ + public function setColor(Zend_Pdf_Color_Rgb $color) + { + $this->_outlineDictionary->touch(); + + if ($color === null) { + $this->_outlineDictionary->C = null; + } else { + $components = $color->getComponents(); + $colorComponentElements = array(new Zend_Pdf_Element_Numeric($components[0]), + new Zend_Pdf_Element_Numeric($components[1]), + new Zend_Pdf_Element_Numeric($components[2])); + $this->_outlineDictionary->C = new Zend_Pdf_Element_Array($colorComponentElements); + } + + return $this; + } + + /** + * Get outline target. + * + * @return Zend_Pdf_Target + * @throws Zend_Pdf_Exception + */ + public function getTarget() + { + if ($this->_outlineDictionary->Dest !== null) { + if ($this->_outlineDictionary->A !== null) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Outline dictionary may contain Dest or A entry, but not both.'); + } + + // require_once 'Zend/Pdf/Destination.php'; + return Zend_Pdf_Destination::load($this->_outlineDictionary->Dest); + } else if ($this->_outlineDictionary->A !== null) { + // require_once 'Zend/Pdf/Action.php'; + return Zend_Pdf_Action::load($this->_outlineDictionary->A); + } + + return null; + } + + /** + * Set outline target. + * Null means no target + * + * @param Zend_Pdf_Target|string $target + * @return Zend_Pdf_Outline + * @throws Zend_Pdf_Exception + */ + public function setTarget($target = null) + { + $this->_outlineDictionary->touch(); + + if (is_string($target)) { + // require_once 'Zend/Pdf/Destination/Named.php'; + $target = Zend_Pdf_Destination_Named::create($target); + } + + if ($target === null) { + $this->_outlineDictionary->Dest = null; + $this->_outlineDictionary->A = null; + } else if ($target instanceof Zend_Pdf_Destination) { + $this->_outlineDictionary->Dest = $target->getResource(); + $this->_outlineDictionary->A = null; + } else if ($target instanceof Zend_Pdf_Action) { + $this->_outlineDictionary->Dest = null; + $this->_outlineDictionary->A = $target->getResource(); + } else { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Outline target has to be Zend_Pdf_Destination or Zend_Pdf_Action object or string'); + } + + return $this; + } + + /** + * Set outline options + * + * @param array $options + * @return Zend_Pdf_Actions_Traceable + * @throws Zend_Pdf_Exception + */ + public function setOptions(array $options) + { + parent::setOptions($options); + + return $this; + } + + + + /** + * Create PDF outline object using specified dictionary + * + * @internal + * @param Zend_Pdf_Element $dictionary (It's actually Dictionary or Dictionary Object or Reference to a Dictionary Object) + * @param Zend_Pdf_Action $parentAction + * @param SplObjectStorage $processedOutlines List of already processed Outline dictionaries, + * used to avoid cyclic references + * @return Zend_Pdf_Action + * @throws Zend_Pdf_Exception + */ + public function __construct(Zend_Pdf_Element $dictionary, SplObjectStorage $processedDictionaries = null) + { + if ($dictionary->getType() != Zend_Pdf_Element::TYPE_DICTIONARY) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('$dictionary mast be an indirect dictionary object.'); + } + + if ($processedDictionaries === null) { + $processedDictionaries = new SplObjectStorage(); + } + $processedDictionaries->attach($dictionary); + + $this->_outlineDictionary = $dictionary; + + if ($dictionary->Count !== null) { + if ($dictionary->Count->getType() != Zend_Pdf_Element::TYPE_NUMERIC) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Outline dictionary Count entry must be a numeric element.'); + } + + $childOutlinesCount = $dictionary->Count->value; + if ($childOutlinesCount > 0) { + $this->_open = true; + } + $childOutlinesCount = abs($childOutlinesCount); + + $childDictionary = $dictionary->First; + + $children = new SplObjectStorage(); + while ($childDictionary !== null) { + // Check children structure for cyclic references + if ($children->contains($childDictionary)) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Outline childs load error.'); + } + + if (!$processedDictionaries->contains($childDictionary)) { + $this->childOutlines[] = new Zend_Pdf_Outline_Loaded($childDictionary, $processedDictionaries); + } + + $childDictionary = $childDictionary->Next; + } + + $this->_originalChildOutlines = $this->childOutlines; + } + } + + /** + * Dump Outline and its child outlines into PDF structures + * + * Returns dictionary indirect object or reference + * + * @internal + * @param Zend_Pdf_ElementFactory $factory object factory for newly created indirect objects + * @param boolean $updateNavigation Update navigation flag + * @param Zend_Pdf_Element $parent Parent outline dictionary reference + * @param Zend_Pdf_Element $prev Previous outline dictionary reference + * @param SplObjectStorage $processedOutlines List of already processed outlines + * @return Zend_Pdf_Element + * @throws Zend_Pdf_Exception + */ + public function dumpOutline(Zend_Pdf_ElementFactory_Interface $factory, + $updateNavigation, + Zend_Pdf_Element $parent, + Zend_Pdf_Element $prev = null, + SplObjectStorage $processedOutlines = null) + { + if ($processedOutlines === null) { + $processedOutlines = new SplObjectStorage(); + } + $processedOutlines->attach($this); + + if ($updateNavigation) { + $this->_outlineDictionary->touch(); + + $this->_outlineDictionary->Parent = $parent; + $this->_outlineDictionary->Prev = $prev; + $this->_outlineDictionary->Next = null; + } + + $updateChildNavigation = false; + if (count($this->_originalChildOutlines) != count($this->childOutlines)) { + // If original and current children arrays have different size then children list was updated + $updateChildNavigation = true; + } else if ( !(array_keys($this->_originalChildOutlines) === array_keys($this->childOutlines)) ) { + // If original and current children arrays have different keys (with a glance to an order) then children list was updated + $updateChildNavigation = true; + } else { + foreach ($this->childOutlines as $key => $childOutline) { + if ($this->_originalChildOutlines[$key] !== $childOutline) { + $updateChildNavigation = true; + break; + } + } + } + + $lastChild = null; + if ($updateChildNavigation) { + $this->_outlineDictionary->touch(); + $this->_outlineDictionary->First = null; + + foreach ($this->childOutlines as $childOutline) { + if ($processedOutlines->contains($childOutline)) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Outlines cyclyc reference is detected.'); + } + + if ($lastChild === null) { + // First pass. Update Outlines dictionary First entry using corresponding value + $lastChild = $childOutline->dumpOutline($factory, $updateChildNavigation, $this->_outlineDictionary, null, $processedOutlines); + $this->_outlineDictionary->First = $lastChild; + } else { + // Update previous outline dictionary Next entry (Prev is updated within dumpOutline() method) + $childOutlineDictionary = $childOutline->dumpOutline($factory, $updateChildNavigation, $this->_outlineDictionary, $lastChild, $processedOutlines); + $lastChild->Next = $childOutlineDictionary; + $lastChild = $childOutlineDictionary; + } + } + + $this->_outlineDictionary->Last = $lastChild; + + if (count($this->childOutlines) != 0) { + $this->_outlineDictionary->Count = new Zend_Pdf_Element_Numeric(($this->isOpen()? 1 : -1)*count($this->childOutlines)); + } else { + $this->_outlineDictionary->Count = null; + } + } else { + foreach ($this->childOutlines as $childOutline) { + if ($processedOutlines->contains($childOutline)) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Outlines cyclyc reference is detected.'); + } + $lastChild = $childOutline->dumpOutline($factory, $updateChildNavigation, $this->_outlineDictionary, $lastChild, $processedOutlines); + } + } + + return $this->_outlineDictionary; + } + + public function dump($level = 0) + { + printf(":%3d:%s:%s:%s%s :\n", count($this->childOutlines),$this->isItalic()? 'i':' ', $this->isBold()? 'b':' ', str_pad('', 4*$level), $this->getTitle()); + + if ($this->isOpen() || true) { + foreach ($this->childOutlines as $child) { + $child->dump($level + 1); + } + } + } +} diff --git a/library/Zend/Pdf/Page.php b/library/Zend/Pdf/Page.php new file mode 100644 index 0000000..0b6c971 --- /dev/null +++ b/library/Zend/Pdf/Page.php @@ -0,0 +1,773 @@ +getType()) { + case Zend_Pdf_Element::TYPE_DICTIONARY: + $this->_dictionary = $param1; + $this->_objFactory = $param2; + $this->_attached = true; + $this->_safeGS = false; + return; + break; + + case Zend_Pdf_Element::TYPE_NULL: + $this->_objFactory = $param2; + $pageWidth = $pageHeight = 0; + break; + + default: + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Unrecognized object type.'); + break; + + } + } else if ($param1 instanceof Zend_Pdf_Page && $param2 === null && $param3 === null) { + // Duplicate existing page. + // Let already existing content and resources to be shared between pages + // We don't give existing content modification functionality, so we don't need "deep copy" + $this->_objFactory = $param1->_objFactory; + $this->_attached = &$param1->_attached; + $this->_safeGS = false; + + $this->_dictionary = $this->_objFactory->newObject(new Zend_Pdf_Element_Dictionary()); + + foreach ($param1->_dictionary->getKeys() as $key) { + if ($key == 'Contents') { + // Clone Contents property + + $this->_dictionary->Contents = new Zend_Pdf_Element_Array(); + + if ($param1->_dictionary->Contents->getType() != Zend_Pdf_Element::TYPE_ARRAY) { + // Prepare array of content streams and add existing stream + $this->_dictionary->Contents->items[] = $param1->_dictionary->Contents; + } else { + // Clone array of the content streams + foreach ($param1->_dictionary->Contents->items as $srcContentStream) { + $this->_dictionary->Contents->items[] = $srcContentStream; + } + } + } else { + $this->_dictionary->$key = $param1->_dictionary->$key; + } + } + + return; + } else if (is_string($param1) && + ($param2 === null || $param2 instanceof Zend_Pdf_ElementFactory_Interface) && + $param3 === null) { + if ($param2 !== null) { + $this->_objFactory = $param2; + } else { + // require_once 'Zend/Pdf/ElementFactory.php'; + $this->_objFactory = Zend_Pdf_ElementFactory::createFactory(1); + } + $this->_attached = false; + $this->_safeGS = true; /** New page created. That's users App responsibility to track GS changes */ + + switch (strtolower($param1)) { + case 'a4': + $param1 = Zend_Pdf_Page::SIZE_A4; + break; + case 'a4-landscape': + $param1 = Zend_Pdf_Page::SIZE_A4_LANDSCAPE; + break; + case 'letter': + $param1 = Zend_Pdf_Page::SIZE_LETTER; + break; + case 'letter-landscape': + $param1 = Zend_Pdf_Page::SIZE_LETTER_LANDSCAPE; + break; + default: + // should be in "x:y" or "x:y:" form + } + + $pageDim = explode(':', $param1); + if(count($pageDim) == 2 || count($pageDim) == 3) { + $pageWidth = $pageDim[0]; + $pageHeight = $pageDim[1]; + } else { + /** + * @todo support of user defined pagesize notations, like: + * "210x297mm", "595x842", "8.5x11in", "612x792" + */ + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Wrong pagesize notation.'); + } + /** + * @todo support of pagesize recalculation to "default user space units" + */ + + } else if (is_numeric($param1) && is_numeric($param2) && + ($param3 === null || $param3 instanceof Zend_Pdf_ElementFactory_Interface)) { + if ($param3 !== null) { + $this->_objFactory = $param3; + } else { + // require_once 'Zend/Pdf/ElementFactory.php'; + $this->_objFactory = Zend_Pdf_ElementFactory::createFactory(1); + } + + $this->_attached = false; + $this->_safeGS = true; /** New page created. That's users App responsibility to track GS changes */ + $pageWidth = $param1; + $pageHeight = $param2; + + } else { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Unrecognized method signature, wrong number of arguments or wrong argument types.'); + } + + $this->_dictionary = $this->_objFactory->newObject(new Zend_Pdf_Element_Dictionary()); + $this->_dictionary->Type = new Zend_Pdf_Element_Name('Page'); + // require_once 'Zend/Pdf.php'; + $this->_dictionary->LastModified = new Zend_Pdf_Element_String(Zend_Pdf::pdfDate()); + $this->_dictionary->Resources = new Zend_Pdf_Element_Dictionary(); + $this->_dictionary->MediaBox = new Zend_Pdf_Element_Array(); + $this->_dictionary->MediaBox->items[] = new Zend_Pdf_Element_Numeric(0); + $this->_dictionary->MediaBox->items[] = new Zend_Pdf_Element_Numeric(0); + $this->_dictionary->MediaBox->items[] = new Zend_Pdf_Element_Numeric($pageWidth); + $this->_dictionary->MediaBox->items[] = new Zend_Pdf_Element_Numeric($pageHeight); + $this->_dictionary->Contents = new Zend_Pdf_Element_Array(); + } + + + /** + * Attach resource to the canvas + * + * Method returns a name of the resource which can be used + * as a resource reference within drawing instructions stream + * Allowed types: 'ExtGState', 'ColorSpace', 'Pattern', 'Shading', + * 'XObject', 'Font', 'Properties' + * + * @param string $type + * @param Zend_Pdf_Resource $resource + * @return string + */ + protected function _attachResource($type, Zend_Pdf_Resource $resource) + { + // Check that Resources dictionary contains appropriate resource set + if ($this->_dictionary->Resources->$type === null) { + $this->_dictionary->Resources->touch(); + $this->_dictionary->Resources->$type = new Zend_Pdf_Element_Dictionary(); + } else { + $this->_dictionary->Resources->$type->touch(); + } + + // Check, that resource is already attached to resource set. + $resObject = $resource->getResource(); + foreach ($this->_dictionary->Resources->$type->getKeys() as $ResID) { + if ($this->_dictionary->Resources->$type->$ResID === $resObject) { + return $ResID; + } + } + + $idCounter = 1; + do { + $newResName = $type[0] . $idCounter++; + } while ($this->_dictionary->Resources->$type->$newResName !== null); + + $this->_dictionary->Resources->$type->$newResName = $resObject; + $this->_objFactory->attach($resource->getFactory()); + + return $newResName; + } + + /** + * Add procedureSet to the Page description + * + * @param string $procSetName + */ + protected function _addProcSet($procSetName) + { + // Check that Resources dictionary contains ProcSet entry + if ($this->_dictionary->Resources->ProcSet === null) { + $this->_dictionary->Resources->touch(); + $this->_dictionary->Resources->ProcSet = new Zend_Pdf_Element_Array(); + } else { + $this->_dictionary->Resources->ProcSet->touch(); + } + + foreach ($this->_dictionary->Resources->ProcSet->items as $procSetEntry) { + if ($procSetEntry->value == $procSetName) { + // Procset is already included into a ProcSet array + return; + } + } + + $this->_dictionary->Resources->ProcSet->items[] = new Zend_Pdf_Element_Name($procSetName); + } + + /** + * Returns dictionaries of used resources. + * + * Used for canvas implementations interoperability + * + * Structure of the returned array: + * array( + * => array( + * => , + * => , + * => , + * ... + * ), + * => array( + * => , + * => , + * => , + * ... + * ), + * ... + * 'ProcSet' => array() + * ) + * + * where ProcSet array is a list of used procedure sets names (strings). + * Allowed procedure set names: 'PDF', 'Text', 'ImageB', 'ImageC', 'ImageI' + * + * @internal + * @return array + */ + public function getResources() + { + $resources = array(); + $resDictionary = $this->_dictionary->Resources; + + foreach ($resDictionary->getKeys() as $resType) { + $resources[$resType] = array(); + + if ($resType == 'ProcSet') { + foreach ($resDictionary->ProcSet->items as $procSetEntry) { + $resources[$resType][] = $procSetEntry->value; + } + } else { + $resMap = $resDictionary->$resType; + + foreach ($resMap->getKeys() as $resId) { + $resources[$resType][$resId] =new Zend_Pdf_Resource_Unified($resMap->$resId); + } + } + } + + return $resources; + } + + /** + * Get drawing instructions stream + * + * It has to be returned as a PDF stream object to make it reusable. + * + * @internal + * @returns Zend_Pdf_Resource_ContentStream + */ + public function getContents() + { + /** @todo implementation */ + } + + /** + * Return the height of this page in points. + * + * @return float + */ + public function getHeight() + { + return $this->_dictionary->MediaBox->items[3]->value - + $this->_dictionary->MediaBox->items[1]->value; + } + + /** + * Return the width of this page in points. + * + * @return float + */ + public function getWidth() + { + return $this->_dictionary->MediaBox->items[2]->value - + $this->_dictionary->MediaBox->items[0]->value; + } + + /** + * Clone page, extract it and dependent objects from the current document, + * so it can be used within other docs. + */ + public function __clone() + { + $factory = Zend_Pdf_ElementFactory::createFactory(1); + $processed = array(); + + // Clone dictionary object. + // Do it explicitly to prevent sharing page attributes between different + // results of clonePage() operation (other resources are still shared) + $dictionary = new Zend_Pdf_Element_Dictionary(); + foreach ($this->_dictionary->getKeys() as $key) { + $dictionary->$key = $this->_dictionary->$key->makeClone($factory->getFactory(), + $processed, + Zend_Pdf_Element::CLONE_MODE_SKIP_PAGES); + } + + $this->_dictionary = $factory->newObject($dictionary); + $this->_objFactory = $factory; + $this->_attached = false; + $this->_style = null; + $this->_font = null; + } + + /** + * Clone page, extract it and dependent objects from the current document, + * so it can be used within other docs. + * + * @internal + * @param Zend_Pdf_ElementFactory_Interface $factory + * @param array $processed + * @return Zend_Pdf_Page + */ + public function clonePage($factory, &$processed) + { + // Clone dictionary object. + // Do it explicitly to prevent sharing page attributes between different + // results of clonePage() operation (other resources are still shared) + $dictionary = new Zend_Pdf_Element_Dictionary(); + foreach ($this->_dictionary->getKeys() as $key) { + $dictionary->$key = $this->_dictionary->$key->makeClone($factory->getFactory(), + $processed, + Zend_Pdf_Element::CLONE_MODE_SKIP_PAGES); + } + + $clonedPage = new Zend_Pdf_Page($factory->newObject($dictionary), $factory); + $clonedPage->_attached = false; + + return $clonedPage; + } + + /** + * Retrive PDF file reference to the page + * + * @internal + * @return Zend_Pdf_Element_Dictionary + */ + public function getPageDictionary() + { + return $this->_dictionary; + } + + /** + * Dump current drawing instructions into the content stream. + * + * @todo Don't forget to close all current graphics operations (like path drawing) + * + * @throws Zend_Pdf_Exception + */ + public function flush() + { + if ($this->_saveCount != 0) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Saved graphics state is not restored'); + } + + if ($this->_contents == '') { + return; + } + + if ($this->_dictionary->Contents->getType() != Zend_Pdf_Element::TYPE_ARRAY) { + /** + * It's a stream object. + * Prepare Contents page attribute for update. + */ + $this->_dictionary->touch(); + + $currentPageContents = $this->_dictionary->Contents; + $this->_dictionary->Contents = new Zend_Pdf_Element_Array(); + $this->_dictionary->Contents->items[] = $currentPageContents; + } else { + $this->_dictionary->Contents->touch(); + } + + if ((!$this->_safeGS) && (count($this->_dictionary->Contents->items) != 0)) { + /** + * Page already has some content which is not treated as safe. + * + * Add save/restore GS operators + */ + $this->_addProcSet('PDF'); + + $newContentsArray = new Zend_Pdf_Element_Array(); + $newContentsArray->items[] = $this->_objFactory->newStreamObject(" q\n"); + foreach ($this->_dictionary->Contents->items as $contentStream) { + $newContentsArray->items[] = $contentStream; + } + $newContentsArray->items[] = $this->_objFactory->newStreamObject(" Q\n"); + + $this->_dictionary->touch(); + $this->_dictionary->Contents = $newContentsArray; + + $this->_safeGS = true; + } + + $this->_dictionary->Contents->items[] = + $this->_objFactory->newStreamObject($this->_contents); + + $this->_contents = ''; + } + + /** + * Prepare page to be rendered into PDF. + * + * @todo Don't forget to close all current graphics operations (like path drawing) + * + * @param Zend_Pdf_ElementFactory_Interface $objFactory + * @throws Zend_Pdf_Exception + */ + public function render(Zend_Pdf_ElementFactory_Interface $objFactory) + { + $this->flush(); + + if ($objFactory === $this->_objFactory) { + // Page is already attached to the document. + return; + } + + if ($this->_attached) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Page is attached to other documen. Use clone $page to get it context free.'); + } else { + $objFactory->attach($this->_objFactory); + } + } + + /** + * Extract resources attached to the page + * + * This method is not intended to be used in userland, but helps to optimize some document wide operations + * + * returns array of Zend_Pdf_Element_Dictionary objects + * + * @internal + * @return array + */ + public function extractResources() + { + return $this->_dictionary->Resources; + } + + /** + * Extract fonts attached to the page + * + * returns array of Zend_Pdf_Resource_Font_Extracted objects + * + * @return array + * @throws Zend_Pdf_Exception + */ + public function extractFonts() + { + if ($this->_dictionary->Resources->Font === null) { + // Page doesn't have any font attached + // Return empty array + return array(); + } + + $fontResources = $this->_dictionary->Resources->Font; + + $fontResourcesUnique = array(); + foreach ($fontResources->getKeys() as $fontResourceName) { + $fontDictionary = $fontResources->$fontResourceName; + + if (! ($fontDictionary instanceof Zend_Pdf_Element_Reference || + $fontDictionary instanceof Zend_Pdf_Element_Object) ) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Font dictionary has to be an indirect object or object reference.'); + } + + $fontResourcesUnique[spl_object_hash($fontDictionary->getObject())] = $fontDictionary; + } + + $fonts = array(); + // require_once 'Zend/Pdf/Exception.php'; + foreach ($fontResourcesUnique as $resourceId => $fontDictionary) { + try { + // require_once 'Zend/Pdf/Resource/Font/Extracted.php'; + // Try to extract font + $extractedFont = new Zend_Pdf_Resource_Font_Extracted($fontDictionary); + + $fonts[$resourceId] = $extractedFont; + } catch (Zend_Pdf_Exception $e) { + if ($e->getMessage() != 'Unsupported font type.') { + throw new Zend_Pdf_Exception($e->getMessage(), $e->getCode(), $e); + } + } + } + + return $fonts; + } + + /** + * Extract font attached to the page by specific font name + * + * $fontName should be specified in UTF-8 encoding + * + * @return Zend_Pdf_Resource_Font_Extracted|null + * @throws Zend_Pdf_Exception + */ + public function extractFont($fontName) + { + if ($this->_dictionary->Resources->Font === null) { + // Page doesn't have any font attached + return null; + } + + $fontResources = $this->_dictionary->Resources->Font; + + $fontResourcesUnique = array(); + + // require_once 'Zend/Pdf/Exception.php'; + foreach ($fontResources->getKeys() as $fontResourceName) { + $fontDictionary = $fontResources->$fontResourceName; + + if (! ($fontDictionary instanceof Zend_Pdf_Element_Reference || + $fontDictionary instanceof Zend_Pdf_Element_Object) ) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Font dictionary has to be an indirect object or object reference.'); + } + + $resourceId = spl_object_hash($fontDictionary->getObject()); + if (isset($fontResourcesUnique[$resourceId])) { + continue; + } else { + // Mark resource as processed + $fontResourcesUnique[$resourceId] = 1; + } + + if ($fontDictionary->BaseFont->value != $fontName) { + continue; + } + + try { + // Try to extract font + // require_once 'Zend/Pdf/Resource/Font/Extracted.php'; + return new Zend_Pdf_Resource_Font_Extracted($fontDictionary); + } catch (Zend_Pdf_Exception $e) { + if ($e->getMessage() != 'Unsupported font type.') { + throw new Zend_Pdf_Exception($e->getMessage(), $e->getCode(), $e); + } + + // Continue searhing font with specified name + } + } + + return null; + } + + /** + * + * @param Zend_Pdf_Annotation $annotation + * @return Zend_Pdf_Page + */ + public function attachAnnotation(Zend_Pdf_Annotation $annotation) + { + $annotationDictionary = $annotation->getResource(); + if (!$annotationDictionary instanceof Zend_Pdf_Element_Object && + !$annotationDictionary instanceof Zend_Pdf_Element_Reference) { + $annotationDictionary = $this->_objFactory->newObject($annotationDictionary); + } + + if ($this->_dictionary->Annots === null) { + $this->_dictionary->touch(); + $this->_dictionary->Annots = new Zend_Pdf_Element_Array(); + } else { + $this->_dictionary->Annots->touch(); + } + + $this->_dictionary->Annots->items[] = $annotationDictionary; + + $annotationDictionary->touch(); + $annotationDictionary->P = $this->_dictionary; + + return $this; + } +} + diff --git a/library/Zend/Pdf/Parser.php b/library/Zend/Pdf/Parser.php new file mode 100644 index 0000000..982789c --- /dev/null +++ b/library/Zend/Pdf/Parser.php @@ -0,0 +1,472 @@ +_stringParser->data); + } + + /** + * Get PDF String + * + * @return string + */ + public function getPDFString() + { + return $this->_stringParser->data; + } + + /** + * PDF version specified in the file header + * + * @return string + */ + public function getPDFVersion() + { + return $this->_pdfVersion; + } + + /** + * Load XReference table and referenced objects + * + * @param integer $offset + * @throws Zend_Pdf_Exception + * @return Zend_Pdf_Trailer_Keeper + */ + private function _loadXRefTable($offset) + { + $this->_stringParser->offset = $offset; + + // require_once 'Zend/Pdf/Element/Reference/Table.php'; + $refTable = new Zend_Pdf_Element_Reference_Table(); + // require_once 'Zend/Pdf/Element/Reference/Context.php'; + $context = new Zend_Pdf_Element_Reference_Context($this->_stringParser, $refTable); + $this->_stringParser->setContext($context); + + $nextLexeme = $this->_stringParser->readLexeme(); + if ($nextLexeme == 'xref') { + /** + * Common cross-reference table + */ + $this->_stringParser->skipWhiteSpace(); + while ( ($nextLexeme = $this->_stringParser->readLexeme()) != 'trailer' ) { + if (!ctype_digit($nextLexeme)) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(sprintf('PDF file syntax error. Offset - 0x%X. Cross-reference table subheader values must contain only digits.', $this->_stringParser->offset-strlen($nextLexeme))); + } + $objNum = (int)$nextLexeme; + + $refCount = $this->_stringParser->readLexeme(); + if (!ctype_digit($refCount)) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(sprintf('PDF file syntax error. Offset - 0x%X. Cross-reference table subheader values must contain only digits.', $this->_stringParser->offset-strlen($refCount))); + } + + $this->_stringParser->skipWhiteSpace(); + while ($refCount > 0) { + $objectOffset = substr($this->_stringParser->data, $this->_stringParser->offset, 10); + if (!ctype_digit($objectOffset)) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(sprintf('PDF file cross-reference table syntax error. Offset - 0x%X. Offset must contain only digits.', $this->_stringParser->offset)); + } + // Force $objectOffset to be treated as decimal instead of octal number + for ($numStart = 0; $numStart < strlen($objectOffset)-1; $numStart++) { + if ($objectOffset[$numStart] != '0') { + break; + } + } + $objectOffset = substr($objectOffset, $numStart); + $this->_stringParser->offset += 10; + + if (strpos("\x00\t\n\f\r ", $this->_stringParser->data[$this->_stringParser->offset]) === false) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(sprintf('PDF file cross-reference table syntax error. Offset - 0x%X. Value separator must be white space.', $this->_stringParser->offset)); + } + $this->_stringParser->offset++; + + $genNumber = substr($this->_stringParser->data, $this->_stringParser->offset, 5); + if (!ctype_digit($objectOffset)) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(sprintf('PDF file cross-reference table syntax error. Offset - 0x%X. Offset must contain only digits.', $this->_stringParser->offset)); + } + // Force $objectOffset to be treated as decimal instead of octal number + for ($numStart = 0; $numStart < strlen($genNumber)-1; $numStart++) { + if ($genNumber[$numStart] != '0') { + break; + } + } + $genNumber = substr($genNumber, $numStart); + $this->_stringParser->offset += 5; + + if (strpos("\x00\t\n\f\r ", $this->_stringParser->data[$this->_stringParser->offset]) === false) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(sprintf('PDF file cross-reference table syntax error. Offset - 0x%X. Value separator must be white space.', $this->_stringParser->offset)); + } + $this->_stringParser->offset++; + + $inUseKey = $this->_stringParser->data[$this->_stringParser->offset]; + $this->_stringParser->offset++; + + switch ($inUseKey) { + case 'f': + // free entry + unset( $this->_refTable[$objNum . ' ' . $genNumber . ' R'] ); + $refTable->addReference($objNum . ' ' . $genNumber . ' R', + $objectOffset, + false); + break; + + case 'n': + // in-use entry + + $refTable->addReference($objNum . ' ' . $genNumber . ' R', + $objectOffset, + true); + } + + if ( !Zend_Pdf_StringParser::isWhiteSpace(ord( $this->_stringParser->data[$this->_stringParser->offset] )) ) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(sprintf('PDF file cross-reference table syntax error. Offset - 0x%X. Value separator must be white space.', $this->_stringParser->offset)); + } + $this->_stringParser->offset++; + if ( !Zend_Pdf_StringParser::isWhiteSpace(ord( $this->_stringParser->data[$this->_stringParser->offset] )) ) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(sprintf('PDF file cross-reference table syntax error. Offset - 0x%X. Value separator must be white space.', $this->_stringParser->offset)); + } + $this->_stringParser->offset++; + + $refCount--; + $objNum++; + } + } + + $trailerDictOffset = $this->_stringParser->offset; + $trailerDict = $this->_stringParser->readElement(); + if (!$trailerDict instanceof Zend_Pdf_Element_Dictionary) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(sprintf('PDF file syntax error. Offset - 0x%X. Dictionary expected after \'trailer\' keyword.', $trailerDictOffset)); + } + } else { + $xrefStream = $this->_stringParser->getObject($offset, $context); + + if (!$xrefStream instanceof Zend_Pdf_Element_Object_Stream) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(sprintf('PDF file syntax error. Offset - 0x%X. Cross-reference stream expected.', $offset)); + } + + $trailerDict = $xrefStream->dictionary; + if ($trailerDict->Type->value != 'XRef') { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(sprintf('PDF file syntax error. Offset - 0x%X. Cross-reference stream object must have /Type property assigned to /XRef.', $offset)); + } + if ($trailerDict->W === null || $trailerDict->W->getType() != Zend_Pdf_Element::TYPE_ARRAY) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(sprintf('PDF file syntax error. Offset - 0x%X. Cross reference stream dictionary doesn\'t have W entry or it\'s not an array.', $offset)); + } + + $entryField1Size = $trailerDict->W->items[0]->value; + $entryField2Size = $trailerDict->W->items[1]->value; + $entryField3Size = $trailerDict->W->items[2]->value; + + if ($entryField2Size == 0 || $entryField3Size == 0) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(sprintf('PDF file syntax error. Offset - 0x%X. Wrong W dictionary entry. Only type field of stream entries has default value and could be zero length.', $offset)); + } + + $xrefStreamData = $xrefStream->value; + + if ($trailerDict->Index !== null) { + if ($trailerDict->Index->getType() != Zend_Pdf_Element::TYPE_ARRAY) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(sprintf('PDF file syntax error. Offset - 0x%X. Cross reference stream dictionary Index entry must be an array.', $offset)); + } + $sections = count($trailerDict->Index->items)/2; + } else { + $sections = 1; + } + + $streamOffset = 0; + + $size = $entryField1Size + $entryField2Size + $entryField3Size; + $entries = strlen($xrefStreamData)/$size; + + for ($count = 0; $count < $sections; $count++) { + if ($trailerDict->Index !== null) { + $objNum = $trailerDict->Index->items[$count*2 ]->value; + $entries = $trailerDict->Index->items[$count*2 + 1]->value; + } else { + $objNum = 0; + $entries = $trailerDict->Size->value; + } + + for ($count2 = 0; $count2 < $entries; $count2++) { + if ($entryField1Size == 0) { + $type = 1; + } else if ($entryField1Size == 1) { // Optimyze one-byte field case + $type = ord($xrefStreamData[$streamOffset++]); + } else { + $type = Zend_Pdf_StringParser::parseIntFromStream($xrefStreamData, $streamOffset, $entryField1Size); + $streamOffset += $entryField1Size; + } + + if ($entryField2Size == 1) { // Optimyze one-byte field case + $field2 = ord($xrefStreamData[$streamOffset++]); + } else { + $field2 = Zend_Pdf_StringParser::parseIntFromStream($xrefStreamData, $streamOffset, $entryField2Size); + $streamOffset += $entryField2Size; + } + + if ($entryField3Size == 1) { // Optimyze one-byte field case + $field3 = ord($xrefStreamData[$streamOffset++]); + } else { + $field3 = Zend_Pdf_StringParser::parseIntFromStream($xrefStreamData, $streamOffset, $entryField3Size); + $streamOffset += $entryField3Size; + } + + switch ($type) { + case 0: + // Free object + $refTable->addReference($objNum . ' ' . $field3 . ' R', $field2, false); + // Debug output: + // echo "Free object - $objNum $field3 R, next free - $field2\n"; + break; + + case 1: + // In use object + $refTable->addReference($objNum . ' ' . $field3 . ' R', $field2, true); + // Debug output: + // echo "In-use object - $objNum $field3 R, offset - $field2\n"; + break; + + case 2: + // Object in an object stream + // Debug output: + // echo "Compressed object - $objNum 0 R, object stream - $field2 0 R, offset - $field3\n"; + break; + } + + $objNum++; + } + } + + // $streamOffset . ' ' . strlen($xrefStreamData) . "\n"; + // "$entries\n"; + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Cross-reference streams are not supported yet.'); + } + + + // require_once 'Zend/Pdf/Trailer/Keeper.php'; + $trailerObj = new Zend_Pdf_Trailer_Keeper($trailerDict, $context); + if ($trailerDict->Prev instanceof Zend_Pdf_Element_Numeric || + $trailerDict->Prev instanceof Zend_Pdf_Element_Reference ) { + $trailerObj->setPrev($this->_loadXRefTable($trailerDict->Prev->value)); + $context->getRefTable()->setParent($trailerObj->getPrev()->getRefTable()); + } + + /** + * We set '/Prev' dictionary property to the current cross-reference section offset. + * It doesn't correspond to the actual data, but is true when trailer will be used + * as a trailer for next generated PDF section. + */ + $trailerObj->Prev = new Zend_Pdf_Element_Numeric($offset); + + return $trailerObj; + } + + + /** + * Get Trailer object + * + * @return Zend_Pdf_Trailer_Keeper + */ + public function getTrailer() + { + return $this->_trailer; + } + + /** + * Object constructor + * + * Note: PHP duplicates string, which is sent by value, only of it's updated. + * Thus we don't need to care about overhead + * + * @param mixed $source + * @param Zend_Pdf_ElementFactory_Interface $factory + * @param boolean $load + * @throws Zend_Exception + */ + public function __construct($source, Zend_Pdf_ElementFactory_Interface $factory, $load) + { + if ($load) { + if (($pdfFile = @fopen($source, 'rb')) === false ) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception( "Can not open '$source' file for reading." ); + } + + $data = ''; + $byteCount = filesize($source); + while ($byteCount > 0 && !feof($pdfFile)) { + $nextBlock = fread($pdfFile, $byteCount); + if ($nextBlock === false) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception( "Error occured while '$source' file reading." ); + } + + $data .= $nextBlock; + $byteCount -= strlen($nextBlock); + } + if ($byteCount != 0) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception( "Error occured while '$source' file reading." ); + } + fclose($pdfFile); + + $this->_stringParser = new Zend_Pdf_StringParser($data, $factory); + } else { + $this->_stringParser = new Zend_Pdf_StringParser($source, $factory); + } + + $pdfVersionComment = $this->_stringParser->readComment(); + if (substr($pdfVersionComment, 0, 5) != '%PDF-') { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('File is not a PDF.'); + } + + $pdfVersion = substr($pdfVersionComment, 5); + if (version_compare($pdfVersion, '0.9', '<') || + version_compare($pdfVersion, '1.61', '>=') + ) { + /** + * @todo + * To support PDF versions 1.5 (Acrobat 6) and PDF version 1.7 (Acrobat 7) + * Stream compression filter must be implemented (for compressed object streams). + * Cross reference streams must be implemented + */ + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(sprintf('Unsupported PDF version. Zend_Pdf supports PDF 1.0-1.4. Current version - \'%f\'', $pdfVersion)); + } + $this->_pdfVersion = $pdfVersion; + + $this->_stringParser->offset = strrpos($this->_stringParser->data, '%%EOF'); + if ($this->_stringParser->offset === false || + strlen($this->_stringParser->data) - $this->_stringParser->offset > 7) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Pdf file syntax error. End-of-fle marker expected at the end of file.'); + } + + $this->_stringParser->offset--; + /** + * Go to end of cross-reference table offset + */ + while (Zend_Pdf_StringParser::isWhiteSpace( ord($this->_stringParser->data[$this->_stringParser->offset]) )&& + ($this->_stringParser->offset > 0)) { + $this->_stringParser->offset--; + } + /** + * Go to the start of cross-reference table offset + */ + while ( (!Zend_Pdf_StringParser::isWhiteSpace( ord($this->_stringParser->data[$this->_stringParser->offset]) ))&& + ($this->_stringParser->offset > 0)) { + $this->_stringParser->offset--; + } + /** + * Go to the end of 'startxref' keyword + */ + while (Zend_Pdf_StringParser::isWhiteSpace( ord($this->_stringParser->data[$this->_stringParser->offset]) )&& + ($this->_stringParser->offset > 0)) { + $this->_stringParser->offset--; + } + /** + * Go to the white space (eol marker) before 'startxref' keyword + */ + $this->_stringParser->offset -= 9; + + $nextLexeme = $this->_stringParser->readLexeme(); + if ($nextLexeme != 'startxref') { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(sprintf('Pdf file syntax error. \'startxref\' keyword expected. Offset - 0x%X.', $this->_stringParser->offset-strlen($nextLexeme))); + } + + $startXref = $this->_stringParser->readLexeme(); + if (!ctype_digit($startXref)) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(sprintf('Pdf file syntax error. Cross-reference table offset must contain only digits. Offset - 0x%X.', $this->_stringParser->offset-strlen($nextLexeme))); + } + + $this->_trailer = $this->_loadXRefTable($startXref); + $factory->setObjectCount($this->_trailer->Size->value); + } + + + /** + * Object destructor + */ + public function __destruct() + { + $this->_stringParser->cleanUp(); + } +} diff --git a/library/Zend/Pdf/RecursivelyIteratableObjectsContainer.php b/library/Zend/Pdf/RecursivelyIteratableObjectsContainer.php new file mode 100644 index 0000000..f229422 --- /dev/null +++ b/library/Zend/Pdf/RecursivelyIteratableObjectsContainer.php @@ -0,0 +1,45 @@ +_objects = $objects; } + + public function current() { return current($this->_objects); } + public function key() { return key($this->_objects); } + public function next() { return next($this->_objects); } + public function rewind() { return reset($this->_objects); } + public function valid() { return current($this->_objects) !== false; } + public function getChildren() { return current($this->_objects); } + public function hasChildren() { return count($this->_objects) > 0; } + + public function count() { return count($this->_objects); } +} diff --git a/library/Zend/Pdf/Resource.php b/library/Zend/Pdf/Resource.php new file mode 100644 index 0000000..86d9efd --- /dev/null +++ b/library/Zend/Pdf/Resource.php @@ -0,0 +1,165 @@ +_objectFactory = $resource->getFactory(); + $this->_resource = $resource; + + return; + } + + // require_once 'Zend/Pdf/ElementFactory.php'; + + $this->_objectFactory = Zend_Pdf_ElementFactory::createFactory(1); + if ($resource instanceof Zend_Pdf_Element) { + $this->_resource = $this->_objectFactory->newObject($resource); + } else { + $this->_resource = $this->_objectFactory->newStreamObject($resource); + } + } + + /** + * Clone page, extract it and dependent objects from the current document, + * so it can be used within other docs. + */ + public function __clone() + { + /** @todo implementation*/ + +// $factory = Zend_Pdf_ElementFactory::createFactory(1); +// $processed = array(); +// +// // Clone dictionary object. +// // Do it explicitly to prevent sharing resource attributes between different +// // results of clone operation (other resources are still shared) +// $dictionary = new Zend_Pdf_Element_Dictionary(); +// foreach ($this->_pageDictionary->getKeys() as $key) { +// $dictionary->$key = $this->_pageDictionary->$key->makeClone($factory->getFactory(), +// $processed, +// Zend_Pdf_Element::CLONE_MODE_SKIP_PAGES); +// } +// +// $this->_pageDictionary = $factory->newObject($dictionary); +// $this->_objectFactory = $factory; +// $this->_attached = false; +// $this->_style = null; +// $this->_font = null; + } + + /** + * Clone resource, extract it and dependent objects from the current document, + * so it can be used within other docs. + * + * @internal + * @param Zend_Pdf_ElementFactory_Interface $factory + * @param array $processed + * @return Zend_Pdf_Page + */ + public function cloneResource($factory, &$processed) + { + /** @todo implementation*/ + +// // Clone dictionary object. +// // Do it explicitly to prevent sharing page attributes between different +// // results of clonePage() operation (other resources are still shared) +// $dictionary = new Zend_Pdf_Element_Dictionary(); +// foreach ($this->_pageDictionary->getKeys() as $key) { +// $dictionary->$key = $this->_pageDictionary->$key->makeClone($factory->getFactory(), +// $processed, +// Zend_Pdf_Element::CLONE_MODE_SKIP_PAGES); +// } +// +// $clonedPage = new Zend_Pdf_Page($factory->newObject($dictionary), $factory); +// $clonedPage->_attached = false; +// +// return $clonedPage; + } + + /** + * Get resource. + * Used to reference resource in an internal PDF data structures (resource dictionaries) + * + * @internal + * @return Zend_Pdf_Element_Object + */ + public function getResource() + { + return $this->_resource; + } + + /** + * Get factory. + * + * @internal + * @return Zend_Pdf_ElementFactory_Interface + */ + public function getFactory() + { + return $this->_objectFactory; + } +} diff --git a/library/Zend/Pdf/Resource/ContentStream.php b/library/Zend/Pdf/Resource/ContentStream.php new file mode 100644 index 0000000..e0ffb81 --- /dev/null +++ b/library/Zend/Pdf/Resource/ContentStream.php @@ -0,0 +1,114 @@ +_bufferedContent .= $instructions; + return $this; + } + + /** + * Get current stream content + * + * @return string + */ + public function getInstructions() + { + $this->flush(); + return $this->_resource->value; + } + + /** + * Clear stream content. + * + * @return Zend_Pdf_Resource_ContentStream + */ + public function clear() + { + $this->_resource->value = ''; + $this->_bufferedContent = ''; + return $this; + } + + /** + * Flush buffered content + */ + public function flush() + { + $this->_resource->value .= $this->_bufferedContent; + $this->_bufferedContent = ''; + + return $this; + } +} diff --git a/library/Zend/Pdf/Resource/Extractor.php b/library/Zend/Pdf/Resource/Extractor.php new file mode 100644 index 0000000..8fec25c --- /dev/null +++ b/library/Zend/Pdf/Resource/Extractor.php @@ -0,0 +1,86 @@ +_factory = Zend_Pdf_ElementFactory::createFactory(1); + $this->_processed = array(); + } + + /** + * Clone page, extract it and dependent objects from the current document, + * so it can be used within other docs + * + * return Zend_Pdf_Page + */ + public function clonePage(Zend_Pdf_Page $page) + { + return $page->clonePage($this->_factory, $this->_processed); + } +} + diff --git a/library/Zend/Pdf/Resource/Font.php b/library/Zend/Pdf/Resource/Font.php new file mode 100644 index 0000000..61ad611 --- /dev/null +++ b/library/Zend/Pdf/Resource/Font.php @@ -0,0 +1,530 @@ +_resource->Type = new Zend_Pdf_Element_Name('Font'); + } + + + /* Object Magic Methods */ + + /** + * Returns the full name of the font in the encoding method of the current + * locale. Transliterates any characters that cannot be naturally + * represented in that character set. + * + * @return string + */ + public function __toString() + { + return $this->getFontName(Zend_Pdf_Font::NAME_FULL, '', '//TRANSLIT'); + } + + + /* Accessors */ + + /** + * Returns the type of font. + * + * @return integer One of the TYPE_ constants defined in + * {@link Zend_Pdf_Font}. + */ + public function getFontType() + { + return $this->_fontType; + } + + /** + * Returns the specified descriptive name for the font. + * + * The font name type is usually one of the following: + *
      + *
    • {@link Zend_Pdf_Font::NAME_FULL} + *
    • {@link Zend_Pdf_Font::NAME_FAMILY} + *
    • {@link Zend_Pdf_Font::NAME_PREFERRED_FAMILY} + *
    • {@link Zend_Pdf_Font::NAME_STYLE} + *
    • {@link Zend_Pdf_Font::NAME_PREFERRED_STYLE} + *
    • {@link Zend_Pdf_Font::NAME_DESCRIPTION} + *
    • {@link Zend_Pdf_Font::NAME_SAMPLE_TEXT} + *
    • {@link Zend_Pdf_Font::NAME_ID} + *
    • {@link Zend_Pdf_Font::NAME_VERSION} + *
    • {@link Zend_Pdf_Font::NAME_POSTSCRIPT} + *
    • {@link Zend_Pdf_Font::NAME_CID_NAME} + *
    • {@link Zend_Pdf_Font::NAME_DESIGNER} + *
    • {@link Zend_Pdf_Font::NAME_DESIGNER_URL} + *
    • {@link Zend_Pdf_Font::NAME_MANUFACTURER} + *
    • {@link Zend_Pdf_Font::NAME_VENDOR_URL} + *
    • {@link Zend_Pdf_Font::NAME_COPYRIGHT} + *
    • {@link Zend_Pdf_Font::NAME_TRADEMARK} + *
    • {@link Zend_Pdf_Font::NAME_LICENSE} + *
    • {@link Zend_Pdf_Font::NAME_LICENSE_URL} + *
    + * + * Note that not all names are available for all fonts. In addition, some + * fonts may contain additional names, whose indicies are in the range + * 256 to 32767 inclusive, which are used for certain font layout features. + * + * If the preferred language translation is not available, uses the first + * available translation for the name, which is usually English. + * + * If the requested name does not exist, returns null. + * + * All names are stored internally as Unicode strings, using UTF-16BE + * encoding. You may optionally supply a different resulting character set. + * + * @param integer $nameType Type of name requested. + * @param mixed $language Preferred language (string) or array of languages + * in preferred order. Use the ISO 639 standard 2-letter language codes. + * @param string $characterSet (optional) Desired resulting character set. + * You may use any character set supported by {@link iconv()}; + * @return string + */ + public function getFontName($nameType, $language, $characterSet = null) + { + if (! isset($this->_fontNames[$nameType])) { + return null; + } + $name = null; + if (is_array($language)) { + foreach ($language as $code) { + if (isset($this->_fontNames[$nameType][$code])) { + $name = $this->_fontNames[$nameType][$code]; + break; + } + } + } else { + if (isset($this->_fontNames[$nameType][$language])) { + $name = $this->_fontNames[$nameType][$language]; + } + } + /* If the preferred language could not be found, use whatever is first. + */ + if ($name === null) { + $names = $this->_fontNames[$nameType]; + $name = reset($names); + } + /* Convert the character set if requested. + */ + if (($characterSet !== null) && ($characterSet != 'UTF-16BE') && PHP_OS != 'AIX') { // AIX knows not this charset + $name = iconv('UTF-16BE', $characterSet, $name); + } + return $name; + } + + /** + * Returns whole set of font names. + * + * @return array + */ + public function getFontNames() + { + return $this->_fontNames; + } + + /** + * Returns true if font is bold. + * + * @return boolean + */ + public function isBold() + { + return $this->_isBold; + } + + /** + * Returns true if font is italic. + * + * @return boolean + */ + public function isItalic() + { + return $this->_isItalic; + } + + /** + * Returns true if font is monospace. + * + * @return boolean + */ + public function isMonospace() + { + return $this->_isMonospace; + } + + /** + * Returns the suggested position below the text baseline of the underline + * in glyph units. + * + * This value is usually negative. + * + * @return integer + */ + public function getUnderlinePosition() + { + return $this->_underlinePosition; + } + + /** + * Returns the suggested line thickness of the underline in glyph units. + * + * @return integer + */ + public function getUnderlineThickness() + { + return $this->_underlineThickness; + } + + /** + * Returns the suggested position above the text baseline of the + * strikethrough in glyph units. + * + * @return integer + */ + public function getStrikePosition() + { + return $this->_strikePosition; + } + + /** + * Returns the suggested line thickness of the strikethrough in glyph units. + * + * @return integer + */ + public function getStrikeThickness() + { + return $this->_strikeThickness; + } + + /** + * Returns the number of glyph units per em. + * + * Used to convert glyph space to user space. Frequently used in conjunction + * with {@link widthsForGlyphs()} to calculate the with of a run of text. + * + * @return integer + */ + public function getUnitsPerEm() + { + return $this->_unitsPerEm; + } + + /** + * Returns the typographic ascent in font glyph units. + * + * The typographic ascent is the distance from the font's baseline to the + * top of the text frame. It is frequently used to locate the initial + * baseline for a paragraph of text inside a given rectangle. + * + * @return integer + */ + public function getAscent() + { + return $this->_ascent; + } + + /** + * Returns the typographic descent in font glyph units. + * + * The typographic descent is the distance below the font's baseline to the + * bottom of the text frame. It is always negative. + * + * @return integer + */ + public function getDescent() + { + return $this->_descent; + } + + /** + * Returns the typographic line gap in font glyph units. + * + * The typographic line gap is the distance between the bottom of the text + * frame of one line to the top of the text frame of the next. It is + * typically combined with the typographical ascent and descent to determine + * the font's total line height (or leading). + * + * @return integer + */ + public function getLineGap() + { + return $this->_lineGap; + } + + /** + * Returns the suggested line height (or leading) in font glyph units. + * + * This value is determined by adding together the values of the typographic + * ascent, descent, and line gap. This value yields the suggested line + * spacing as determined by the font developer. + * + * It should be noted that this is only a guideline; layout engines will + * frequently modify this value to achieve special effects such as double- + * spacing. + * + * @return integer + */ + public function getLineHeight() + { + return $this->_ascent - $this->_descent + $this->_lineGap; + } + + + /* Information and Conversion Methods */ + + /** + * Returns an array of glyph numbers corresponding to the Unicode characters. + * + * If a particular character doesn't exist in this font, the special 'missing + * character glyph' will be substituted. + * + * See also {@link glyphNumberForCharacter()}. + * + * @param array $characterCodes Array of Unicode character codes (code points). + * @return array Array of glyph numbers. + */ + abstract public function glyphNumbersForCharacters($characterCodes); + + /** + * Returns the glyph number corresponding to the Unicode character. + * + * If a particular character doesn't exist in this font, the special 'missing + * character glyph' will be substituted. + * + * See also {@link glyphNumbersForCharacters()} which is optimized for bulk + * operations. + * + * @param integer $characterCode Unicode character code (code point). + * @return integer Glyph number. + */ + abstract public function glyphNumberForCharacter($characterCode); + + /** + * Returns a number between 0 and 1 inclusive that indicates the percentage + * of characters in the string which are covered by glyphs in this font. + * + * Since no one font will contain glyphs for the entire Unicode character + * range, this method can be used to help locate a suitable font when the + * actual contents of the string are not known. + * + * Note that some fonts lie about the characters they support. Additionally, + * fonts don't usually contain glyphs for control characters such as tabs + * and line breaks, so it is rare that you will get back a full 1.0 score. + * The resulting value should be considered informational only. + * + * @param string $string + * @param string $charEncoding (optional) Character encoding of source text. + * If omitted, uses 'current locale'. + * @return float + */ + abstract public function getCoveredPercentage($string, $charEncoding = ''); + + /** + * Returns the widths of the glyphs. + * + * The widths are expressed in the font's glyph space. You are responsible + * for converting to user space as necessary. See {@link unitsPerEm()}. + * + * See also {@link widthForGlyph()}. + * + * @param array $glyphNumbers Array of glyph numbers. + * @return array Array of glyph widths (integers). + * @throws Zend_Pdf_Exception + */ + abstract public function widthsForGlyphs($glyphNumbers); + + /** + * Returns the width of the glyph. + * + * Like {@link widthsForGlyphs()} but used for one glyph at a time. + * + * @param integer $glyphNumber + * @return integer + * @throws Zend_Pdf_Exception + */ + abstract public function widthForGlyph($glyphNumber); + + /** + * Convert string to the font encoding. + * + * The method is used to prepare string for text drawing operators + * + * @param string $string + * @param string $charEncoding Character encoding of source text. + * @return string + */ + abstract public function encodeString($string, $charEncoding); + + /** + * Convert string from the font encoding. + * + * The method is used to convert strings retrieved from existing content streams + * + * @param string $string + * @param string $charEncoding Character encoding of resulting text. + * @return string + */ + abstract public function decodeString($string, $charEncoding); + + + + /**** Internal Methods ****/ + + + /** + * If the font's glyph space is not 1000 units per em, converts the value. + * + * @internal + * @param integer $value + * @return integer + */ + public function toEmSpace($value) + { + if ($this->_unitsPerEm == 1000) { + return $value; + } + return ceil(($value / $this->_unitsPerEm) * 1000); // always round up + } +} + diff --git a/library/Zend/Pdf/Resource/Font/CidFont.php b/library/Zend/Pdf/Resource/Font/CidFont.php new file mode 100644 index 0000000..8d468aa --- /dev/null +++ b/library/Zend/Pdf/Resource/Font/CidFont.php @@ -0,0 +1,492 @@ +parse(); + + + /* Object properties */ + + $this->_fontNames = $fontParser->names; + + $this->_isBold = $fontParser->isBold; + $this->_isItalic = $fontParser->isItalic; + $this->_isMonospaced = $fontParser->isMonospaced; + + $this->_underlinePosition = $fontParser->underlinePosition; + $this->_underlineThickness = $fontParser->underlineThickness; + $this->_strikePosition = $fontParser->strikePosition; + $this->_strikeThickness = $fontParser->strikeThickness; + + $this->_unitsPerEm = $fontParser->unitsPerEm; + + $this->_ascent = $fontParser->ascent; + $this->_descent = $fontParser->descent; + $this->_lineGap = $fontParser->lineGap; + + + $this->_cmap = $fontParser->cmap; + + + /* Resource dictionary */ + + $baseFont = $this->getFontName(Zend_Pdf_Font::NAME_POSTSCRIPT, 'en', 'UTF-8'); + $this->_resource->BaseFont = new Zend_Pdf_Element_Name($baseFont); + + + /** + * Prepare widths array. + */ + /* Constract characters widths array using font CMap and glyphs widths array */ + $glyphWidths = $fontParser->glyphWidths; + $charGlyphs = $this->_cmap->getCoveredCharactersGlyphs(); + $charWidths = array(); + foreach ($charGlyphs as $charCode => $glyph) { + if(isset($glyphWidths[$glyph]) && !is_null($glyphWidths[$glyph])) { + $charWidths[$charCode] = $glyphWidths[$glyph]; + } + } + $this->_charWidths = $charWidths; + $this->_missingCharWidth = $glyphWidths[0]; + + /* Width array optimization. Step1: extract default value */ + $widthFrequencies = array_count_values($charWidths); + $defaultWidth = null; + $defaultWidthFrequency = -1; + foreach ($widthFrequencies as $width => $frequency) { + if ($frequency > $defaultWidthFrequency) { + $defaultWidth = $width; + $defaultWidthFrequency = $frequency; + } + } + + // Store default value in the font dictionary + $this->_resource->DW = new Zend_Pdf_Element_Numeric($this->toEmSpace($defaultWidth)); + + // Remove characters which corresponds to default width from the widths array + $defWidthChars = array_keys($charWidths, $defaultWidth); + foreach ($defWidthChars as $charCode) { + unset($charWidths[$charCode]); + } + + // Order cheracter widths aray by character codes + ksort($charWidths, SORT_NUMERIC); + + /* Width array optimization. Step2: Compact character codes sequences */ + $lastCharCode = -1; + $widthsSequences = array(); + foreach ($charWidths as $charCode => $width) { + if ($lastCharCode == -1) { + $charCodesSequense = array(); + $sequenceStartCode = $charCode; + } else if ($charCode != $lastCharCode + 1) { + // New chracters sequence detected + $widthsSequences[$sequenceStartCode] = $charCodesSequense; + $charCodesSequense = array(); + $sequenceStartCode = $charCode; + } + $charCodesSequense[] = $width; + $lastCharCode = $charCode; + } + // Save last sequence, if widths array is not empty (it may happens for monospaced fonts) + if (count($charWidths) != 0) { + $widthsSequences[$sequenceStartCode] = $charCodesSequense; + } + + $pdfCharsWidths = array(); + foreach ($widthsSequences as $startCode => $widthsSequence) { + /* Width array optimization. Step3: Compact widths sequences */ + $pdfWidths = array(); + $lastWidth = -1; + $widthsInSequence = 0; + foreach ($widthsSequence as $width) { + if ($lastWidth != $width) { + // New width is detected + if ($widthsInSequence != 0) { + // Previous width value was a part of the widths sequence. Save it as 'c_1st c_last w'. + $pdfCharsWidths[] = new Zend_Pdf_Element_Numeric($startCode); // First character code + $pdfCharsWidths[] = new Zend_Pdf_Element_Numeric($startCode + $widthsInSequence - 1); // Last character code + $pdfCharsWidths[] = new Zend_Pdf_Element_Numeric($this->toEmSpace($lastWidth)); // Width + + // Reset widths sequence + $startCode = $startCode + $widthsInSequence; + $widthsInSequence = 0; + } + + // Collect new width + $pdfWidths[] = new Zend_Pdf_Element_Numeric($this->toEmSpace($width)); + + $lastWidth = $width; + } else { + // Width is equal to previous + if (count($pdfWidths) != 0) { + // We already have some widths collected + // So, we've just detected new widths sequence + + // Remove last element from widths list, since it's a part of widths sequence + array_pop($pdfWidths); + + // and write the rest if it's not empty + if (count($pdfWidths) != 0) { + // Save it as 'c_1st [w1 w2 ... wn]'. + $pdfCharsWidths[] = new Zend_Pdf_Element_Numeric($startCode); // First character code + $pdfCharsWidths[] = new Zend_Pdf_Element_Array($pdfWidths); // Widths array + + // Reset widths collection + $startCode += count($pdfWidths); + $pdfWidths = array(); + } + + $widthsInSequence = 2; + } else { + // Continue widths sequence + $widthsInSequence++; + } + } + } + + // Check if we have widths collection or widths sequence to wite it down + if (count($pdfWidths) != 0) { + // We have some widths collected + // Save it as 'c_1st [w1 w2 ... wn]'. + $pdfCharsWidths[] = new Zend_Pdf_Element_Numeric($startCode); // First character code + $pdfCharsWidths[] = new Zend_Pdf_Element_Array($pdfWidths); // Widths array + } else if ($widthsInSequence != 0){ + // We have widths sequence + // Save it as 'c_1st c_last w'. + $pdfCharsWidths[] = new Zend_Pdf_Element_Numeric($startCode); // First character code + $pdfCharsWidths[] = new Zend_Pdf_Element_Numeric($startCode + $widthsInSequence - 1); // Last character code + $pdfCharsWidths[] = new Zend_Pdf_Element_Numeric($this->toEmSpace($lastWidth)); // Width + } + } + + /* Create the Zend_Pdf_Element_Array object and add it to the font's + * object factory and resource dictionary. + */ + $widthsArrayElement = new Zend_Pdf_Element_Array($pdfCharsWidths); + $widthsObject = $this->_objectFactory->newObject($widthsArrayElement); + $this->_resource->W = $widthsObject; + + + /* CIDSystemInfo dictionary */ + $cidSystemInfo = new Zend_Pdf_Element_Dictionary(); + $cidSystemInfo->Registry = new Zend_Pdf_Element_String('Adobe'); + $cidSystemInfo->Ordering = new Zend_Pdf_Element_String('UCS'); + $cidSystemInfo->Supplement = new Zend_Pdf_Element_Numeric(0); + $cidSystemInfoObject = $this->_objectFactory->newObject($cidSystemInfo); + $this->_resource->CIDSystemInfo = $cidSystemInfoObject; + } + + + + /** + * Returns an array of glyph numbers corresponding to the Unicode characters. + * + * If a particular character doesn't exist in this font, the special 'missing + * character glyph' will be substituted. + * + * See also {@link glyphNumberForCharacter()}. + * + * @param array $characterCodes Array of Unicode character codes (code points). + * @return array Array of glyph numbers. + */ + public function glyphNumbersForCharacters($characterCodes) + { + /** + * CIDFont object is not actually a font. It does not have an Encoding entry, + * it cannot be listed in the Font subdictionary of a resource dictionary, and + * it cannot be used as the operand of the Tf operator. + * + * Throw an exception. + */ + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('CIDFont PDF objects could not be used as the operand of the text drawing operators'); + } + + /** + * Returns the glyph number corresponding to the Unicode character. + * + * If a particular character doesn't exist in this font, the special 'missing + * character glyph' will be substituted. + * + * See also {@link glyphNumbersForCharacters()} which is optimized for bulk + * operations. + * + * @param integer $characterCode Unicode character code (code point). + * @return integer Glyph number. + */ + public function glyphNumberForCharacter($characterCode) + { + /** + * CIDFont object is not actually a font. It does not have an Encoding entry, + * it cannot be listed in the Font subdictionary of a resource dictionary, and + * it cannot be used as the operand of the Tf operator. + * + * Throw an exception. + */ + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('CIDFont PDF objects could not be used as the operand of the text drawing operators'); + } + + + /** + * Returns a number between 0 and 1 inclusive that indicates the percentage + * of characters in the string which are covered by glyphs in this font. + * + * Since no one font will contain glyphs for the entire Unicode character + * range, this method can be used to help locate a suitable font when the + * actual contents of the string are not known. + * + * Note that some fonts lie about the characters they support. Additionally, + * fonts don't usually contain glyphs for control characters such as tabs + * and line breaks, so it is rare that you will get back a full 1.0 score. + * The resulting value should be considered informational only. + * + * @param string $string + * @param string $charEncoding (optional) Character encoding of source text. + * If omitted, uses 'current locale'. + * @return float + */ + public function getCoveredPercentage($string, $charEncoding = '') + { + /* Convert the string to UTF-16BE encoding so we can match the string's + * character codes to those found in the cmap. + */ + if ($charEncoding != 'UTF-16BE') { + $string = iconv($charEncoding, 'UTF-16BE', $string); + } + + $charCount = iconv_strlen($string, 'UTF-16BE'); + if ($charCount == 0) { + return 0; + } + + /* Calculate the score by doing a lookup for each character. + */ + $score = 0; + $maxIndex = strlen($string); + for ($i = 0; $i < $maxIndex; $i++) { + /** + * @todo Properly handle characters encoded as surrogate pairs. + */ + $charCode = (ord($string[$i]) << 8) | ord($string[++$i]); + /* This could probably be optimized a bit with a binary search... + */ + if (isset($this->_charWidths[$charCode])) { + $score++; + } + } + return $score / $charCount; + } + + /** + * Returns the widths of the Chars. + * + * The widths are expressed in the font's glyph space. You are responsible + * for converting to user space as necessary. See {@link unitsPerEm()}. + * + * See also {@link widthForChar()}. + * + * @param array &$glyphNumbers Array of glyph numbers. + * @return array Array of glyph widths (integers). + */ + public function widthsForChars($charCodes) + { + $widths = array(); + foreach ($charCodes as $key => $charCode) { + if (!isset($this->_charWidths[$charCode])) { + $widths[$key] = $this->_missingCharWidth; + } else { + $widths[$key] = $this->_charWidths[$charCode]; + } + } + return $widths; + } + + /** + * Returns the width of the character. + * + * Like {@link widthsForChars()} but used for one char at a time. + * + * @param integer $charCode + * @return integer + */ + public function widthForChar($charCode) + { + if (!isset($this->_charWidths[$charCode])) { + return $this->_missingCharWidth; + } + return $this->_charWidths[$charCode]; + } + + /** + * Returns the widths of the glyphs. + * + * @param array &$glyphNumbers Array of glyph numbers. + * @return array Array of glyph widths (integers). + * @throws Zend_Pdf_Exception + */ + public function widthsForGlyphs($glyphNumbers) + { + /** + * CIDFont object is not actually a font. It does not have an Encoding entry, + * it cannot be listed in the Font subdictionary of a resource dictionary, and + * it cannot be used as the operand of the Tf operator. + * + * Throw an exception. + */ + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('CIDFont PDF objects could not be used as the operand of the text drawing operators'); + } + + /** + * Returns the width of the glyph. + * + * Like {@link widthsForGlyphs()} but used for one glyph at a time. + * + * @param integer $glyphNumber + * @return integer + * @throws Zend_Pdf_Exception + */ + public function widthForGlyph($glyphNumber) + { + /** + * CIDFont object is not actually a font. It does not have an Encoding entry, + * it cannot be listed in the Font subdictionary of a resource dictionary, and + * it cannot be used as the operand of the Tf operator. + * + * Throw an exception. + */ + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('CIDFont PDF objects could not be used as the operand of the text drawing operators'); + } + + /** + * Convert string to the font encoding. + * + * @param string $string + * @param string $charEncoding Character encoding of source text. + * @return string + * @throws Zend_Pdf_Exception + * */ + public function encodeString($string, $charEncoding) + { + /** + * CIDFont object is not actually a font. It does not have an Encoding entry, + * it cannot be listed in the Font subdictionary of a resource dictionary, and + * it cannot be used as the operand of the Tf operator. + * + * Throw an exception. + */ + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('CIDFont PDF objects could not be used as the operand of the text drawing operators'); + } + + /** + * Convert string from the font encoding. + * + * @param string $string + * @param string $charEncoding Character encoding of resulting text. + * @return string + * @throws Zend_Pdf_Exception + */ + public function decodeString($string, $charEncoding) + { + /** + * CIDFont object is not actually a font. It does not have an Encoding entry, + * it cannot be listed in the Font subdictionary of a resource dictionary, and + * it cannot be used as the operand of the Tf operator. + * + * Throw an exception. + */ + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('CIDFont PDF objects could not be used as the operand of the text drawing operators'); + } +} diff --git a/library/Zend/Pdf/Resource/Font/CidFont/TrueType.php b/library/Zend/Pdf/Resource/Font/CidFont/TrueType.php new file mode 100644 index 0000000..2b11f3c --- /dev/null +++ b/library/Zend/Pdf/Resource/Font/CidFont/TrueType.php @@ -0,0 +1,88 @@ +_fontType = Zend_Pdf_Font::TYPE_CIDFONT_TYPE_2; + + $this->_resource->Subtype = new Zend_Pdf_Element_Name('CIDFontType2'); + + $fontDescriptor = Zend_Pdf_Resource_Font_FontDescriptor::factory($this, $fontParser, $embeddingOptions); + $this->_resource->FontDescriptor = $this->_objectFactory->newObject($fontDescriptor); + + /* Prepare CIDToGIDMap */ + // Initialize 128K string of null characters (65536 2 byte integers) + $cidToGidMapData = str_repeat("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 8192); + // Fill the index + $charGlyphs = $this->_cmap->getCoveredCharactersGlyphs(); + foreach ($charGlyphs as $charCode => $glyph) { + $cidToGidMapData[$charCode*2 ] = chr($glyph >> 8); + $cidToGidMapData[$charCode*2 + 1] = chr($glyph & 0xFF); + } + // Store CIDToGIDMap within compressed stream object + $cidToGidMap = $this->_objectFactory->newStreamObject($cidToGidMapData); + $cidToGidMap->dictionary->Filter = new Zend_Pdf_Element_Name('FlateDecode'); + $this->_resource->CIDToGIDMap = $cidToGidMap; + } + +} diff --git a/library/Zend/Pdf/Resource/Font/Extracted.php b/library/Zend/Pdf/Resource/Font/Extracted.php new file mode 100644 index 0000000..f1861c7 --- /dev/null +++ b/library/Zend/Pdf/Resource/Font/Extracted.php @@ -0,0 +1,274 @@ +_objectFactory = $fontDictionary->getFactory(); + $this->_resource = $fontDictionary; + + if ($fontDictionary->Encoding !== null) { + $this->_encoding = $fontDictionary->Encoding->value; + } + + switch ($fontDictionary->Subtype->value) { + case 'Type0': + // Composite type 0 font + if (count($fontDictionary->DescendantFonts->items) != 1) { + // Multiple descendant fonts are not supported + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(self::TYPE_NOT_SUPPORTED); + } + + $fontDictionaryIterator = $fontDictionary->DescendantFonts->items->getIterator(); + $fontDictionaryIterator->rewind(); + $descendantFont = $fontDictionaryIterator->current(); + $fontDescriptor = $descendantFont->FontDescriptor; + break; + + case 'Type1': + if ($fontDictionary->FontDescriptor === null) { + // That's one of the standard fonts + $standardFont = Zend_Pdf_Font::fontWithName($fontDictionary->BaseFont->value); + + $this->_fontNames = $standardFont->getFontNames(); + $this->_isBold = $standardFont->isBold(); + $this->_isItalic = $standardFont->isItalic(); + $this->_isMonospace = $standardFont->isMonospace(); + $this->_underlinePosition = $standardFont->getUnderlinePosition(); + $this->_underlineThickness = $standardFont->getUnderlineThickness(); + $this->_strikePosition = $standardFont->getStrikePosition(); + $this->_strikeThickness = $standardFont->getStrikeThickness(); + $this->_unitsPerEm = $standardFont->getUnitsPerEm(); + $this->_ascent = $standardFont->getAscent(); + $this->_descent = $standardFont->getDescent(); + $this->_lineGap = $standardFont->getLineGap(); + + return; + } + + $fontDescriptor = $fontDictionary->FontDescriptor; + break; + + case 'TrueType': + $fontDescriptor = $fontDictionary->FontDescriptor; + break; + + default: + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(self::TYPE_NOT_SUPPORTED); + } + + $this->_fontNames[Zend_Pdf_Font::NAME_POSTSCRIPT]['en'] = iconv('UTF-8', 'UTF-16BE', $fontDictionary->BaseFont->value); + + $this->_isBold = false; // this property is actually not used anywhere + $this->_isItalic = ( ($fontDescriptor->Flags->value & (1 << 6)) != 0 ); // Bit-7 is set + $this->_isMonospace = ( ($fontDescriptor->Flags->value & (1 << 0)) != 0 ); // Bit-1 is set + $this->_underlinePosition = null; // Can't be extracted + $this->_underlineThickness = null; // Can't be extracted + $this->_strikePosition = null; // Can't be extracted + $this->_strikeThickness = null; // Can't be extracted + $this->_unitsPerEm = null; // Can't be extracted + $this->_ascent = $fontDescriptor->Ascent->value; + $this->_descent = $fontDescriptor->Descent->value; + $this->_lineGap = null; // Can't be extracted + } + + /** + * Returns an array of glyph numbers corresponding to the Unicode characters. + * + * If a particular character doesn't exist in this font, the special 'missing + * character glyph' will be substituted. + * + * See also {@link glyphNumberForCharacter()}. + * + * @param array $characterCodes Array of Unicode character codes (code points). + * @return array Array of glyph numbers. + */ + public function glyphNumbersForCharacters($characterCodes) + { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(self::OPERATION_NOT_SUPPORTED); + } + + /** + * Returns the glyph number corresponding to the Unicode character. + * + * If a particular character doesn't exist in this font, the special 'missing + * character glyph' will be substituted. + * + * See also {@link glyphNumbersForCharacters()} which is optimized for bulk + * operations. + * + * @param integer $characterCode Unicode character code (code point). + * @return integer Glyph number. + */ + public function glyphNumberForCharacter($characterCode) + { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(self::OPERATION_NOT_SUPPORTED); + } + + /** + * Returns a number between 0 and 1 inclusive that indicates the percentage + * of characters in the string which are covered by glyphs in this font. + * + * Since no one font will contain glyphs for the entire Unicode character + * range, this method can be used to help locate a suitable font when the + * actual contents of the string are not known. + * + * Note that some fonts lie about the characters they support. Additionally, + * fonts don't usually contain glyphs for control characters such as tabs + * and line breaks, so it is rare that you will get back a full 1.0 score. + * The resulting value should be considered informational only. + * + * @param string $string + * @param string $charEncoding (optional) Character encoding of source text. + * If omitted, uses 'current locale'. + * @return float + */ + public function getCoveredPercentage($string, $charEncoding = '') + { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(self::OPERATION_NOT_SUPPORTED); + } + + /** + * Returns the widths of the glyphs. + * + * The widths are expressed in the font's glyph space. You are responsible + * for converting to user space as necessary. See {@link unitsPerEm()}. + * + * See also {@link widthForGlyph()}. + * + * @param array $glyphNumbers Array of glyph numbers. + * @return array Array of glyph widths (integers). + * @throws Zend_Pdf_Exception + */ + public function widthsForGlyphs($glyphNumbers) + { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(self::OPERATION_NOT_SUPPORTED); + } + + /** + * Returns the width of the glyph. + * + * Like {@link widthsForGlyphs()} but used for one glyph at a time. + * + * @param integer $glyphNumber + * @return integer + * @throws Zend_Pdf_Exception + */ + public function widthForGlyph($glyphNumber) + { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(self::OPERATION_NOT_SUPPORTED); + } + + /** + * Convert string to the font encoding. + * + * The method is used to prepare string for text drawing operators + * + * @param string $string + * @param string $charEncoding Character encoding of source text. + * @return string + */ + public function encodeString($string, $charEncoding) + { + if ($this->_encoding == 'Identity-H') { + return iconv($charEncoding, 'UTF-16BE', $string); + } + + if ($this->_encoding == 'WinAnsiEncoding') { + return iconv($charEncoding, 'CP1252//IGNORE', $string); + } + + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(self::ENCODING_NOT_SUPPORTED); + } + + /** + * Convert string from the font encoding. + * + * The method is used to convert strings retrieved from existing content streams + * + * @param string $string + * @param string $charEncoding Character encoding of resulting text. + * @return string + */ + public function decodeString($string, $charEncoding) + { + if ($this->_encoding == 'Identity-H') { + return iconv('UTF-16BE', $charEncoding, $string); + } + + if ($this->_encoding == 'WinAnsiEncoding') { + return iconv('CP1252', $charEncoding, $string); + } + + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(self::ENCODING_NOT_SUPPORTED); + } +} diff --git a/library/Zend/Pdf/Resource/Font/FontDescriptor.php b/library/Zend/Pdf/Resource/Font/FontDescriptor.php new file mode 100644 index 0000000..adc2f85 --- /dev/null +++ b/library/Zend/Pdf/Resource/Font/FontDescriptor.php @@ -0,0 +1,204 @@ +Type = new Zend_Pdf_Element_Name('FontDescriptor'); + $fontDescriptor->FontName = new Zend_Pdf_Element_Name($font->getResource()->BaseFont->value); + + /* The font flags value is a bitfield that describes the stylistic + * attributes of the font. We will set as many of the bits as can be + * determined from the font parser. + */ + $flags = 0; + if ($fontParser->isMonospaced) { // bit 1: FixedPitch + $flags |= 1 << 0; + } + if ($fontParser->isSerifFont) { // bit 2: Serif + $flags |= 1 << 1; + } + if (! $fontParser->isAdobeLatinSubset) { // bit 3: Symbolic + $flags |= 1 << 2; + } + if ($fontParser->isScriptFont) { // bit 4: Script + $flags |= 1 << 3; + } + if ($fontParser->isAdobeLatinSubset) { // bit 6: Nonsymbolic + $flags |= 1 << 5; + } + if ($fontParser->isItalic) { // bit 7: Italic + $flags |= 1 << 6; + } + // bits 17-19: AllCap, SmallCap, ForceBold; not available + $fontDescriptor->Flags = new Zend_Pdf_Element_Numeric($flags); + + $fontBBox = array(new Zend_Pdf_Element_Numeric($font->toEmSpace($fontParser->xMin)), + new Zend_Pdf_Element_Numeric($font->toEmSpace($fontParser->yMin)), + new Zend_Pdf_Element_Numeric($font->toEmSpace($fontParser->xMax)), + new Zend_Pdf_Element_Numeric($font->toEmSpace($fontParser->yMax))); + $fontDescriptor->FontBBox = new Zend_Pdf_Element_Array($fontBBox); + + $fontDescriptor->ItalicAngle = new Zend_Pdf_Element_Numeric($fontParser->italicAngle); + + $fontDescriptor->Ascent = new Zend_Pdf_Element_Numeric($font->toEmSpace($fontParser->ascent)); + $fontDescriptor->Descent = new Zend_Pdf_Element_Numeric($font->toEmSpace($fontParser->descent)); + + $fontDescriptor->CapHeight = new Zend_Pdf_Element_Numeric($fontParser->capitalHeight); + /** + * The vertical stem width is not yet extracted from the OpenType font + * file. For now, record zero which is interpreted as 'unknown'. + * @todo Calculate value for StemV. + */ + $fontDescriptor->StemV = new Zend_Pdf_Element_Numeric(0); + + $fontDescriptor->MissingWidth = new Zend_Pdf_Element_Numeric($fontParser->glyphWidths[0]); + + /* Set up font embedding. This is where the actual font program itself + * is embedded within the PDF document. + * + * Note that it is not requried that fonts be embedded within the PDF + * document to use them. If the recipient of the PDF has the font + * installed on their computer, they will see the correct fonts in the + * document. If they don't, the PDF viewer will substitute or synthesize + * a replacement. + * + * There are several guidelines for font embedding: + * + * First, the developer might specifically request not to embed the font. + */ + if (!($embeddingOptions & Zend_Pdf_Font::EMBED_DONT_EMBED)) { + + /* Second, the font author may have set copyright bits that prohibit + * the font program from being embedded. Yes this is controversial, + * but it's the rules: + * http://partners.adobe.com/public/developer/en/acrobat/sdk/FontPolicies.pdf + * + * To keep the developer in the loop, and to prevent surprising bug + * reports of "your PDF doesn't have the right fonts," throw an + * exception if the font cannot be embedded. + */ + if (! $fontParser->isEmbeddable) { + /* This exception may be suppressed if the developer decides that + * it's not a big deal that the font program can't be embedded. + */ + if (!($embeddingOptions & Zend_Pdf_Font::EMBED_SUPPRESS_EMBED_EXCEPTION)) { + $message = 'This font cannot be embedded in the PDF document. If you would like to use ' + . 'it anyway, you must pass Zend_Pdf_Font::EMBED_SUPPRESS_EMBED_EXCEPTION ' + . 'in the $options parameter of the font constructor.'; + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception($message, Zend_Pdf_Exception::FONT_CANT_BE_EMBEDDED); + } + + } else { + /* Otherwise, the default behavior is to embed all custom fonts. + */ + /* This section will change soon to a stream object data + * provider model so that we don't have to keep a copy of the + * entire font in memory. + * + * We also cannot build font subsetting until the data provider + * model is in place. + */ + $fontFile = $fontParser->getDataSource()->readAllBytes(); + $fontFileObject = $font->getFactory()->newStreamObject($fontFile); + $fontFileObject->dictionary->Length1 = new Zend_Pdf_Element_Numeric(strlen($fontFile)); + if (!($embeddingOptions & Zend_Pdf_Font::EMBED_DONT_COMPRESS)) { + /* Compress the font file using Flate. This generally cuts file + * sizes by about half! + */ + $fontFileObject->dictionary->Filter = new Zend_Pdf_Element_Name('FlateDecode'); + } + if ($fontParser instanceof Zend_Pdf_FileParser_Font_OpenType_Type1 /* not implemented now */) { + $fontDescriptor->FontFile = $fontFileObject; + } else if ($fontParser instanceof Zend_Pdf_FileParser_Font_OpenType_TrueType) { + $fontDescriptor->FontFile2 = $fontFileObject; + } else { + $fontDescriptor->FontFile3 = $fontFileObject; + } + } + } + + return $fontDescriptor; + } +} diff --git a/library/Zend/Pdf/Resource/Font/Simple.php b/library/Zend/Pdf/Resource/Font/Simple.php new file mode 100644 index 0000000..f890833 --- /dev/null +++ b/library/Zend/Pdf/Resource/Font/Simple.php @@ -0,0 +1,283 @@ +_resource->Encoding = new Zend_Pdf_Element_Name('WinAnsiEncoding'); + } + + /** + * Returns an array of glyph numbers corresponding to the Unicode characters. + * + * If a particular character doesn't exist in this font, the special 'missing + * character glyph' will be substituted. + * + * See also {@link glyphNumberForCharacter()}. + * + * @param array $characterCodes Array of Unicode character codes (code points). + * @return array Array of glyph numbers. + */ + public function glyphNumbersForCharacters($characterCodes) + { + return $this->_cmap->glyphNumbersForCharacters($characterCodes); + } + + /** + * Returns the glyph number corresponding to the Unicode character. + * + * If a particular character doesn't exist in this font, the special 'missing + * character glyph' will be substituted. + * + * See also {@link glyphNumbersForCharacters()} which is optimized for bulk + * operations. + * + * @param integer $characterCode Unicode character code (code point). + * @return integer Glyph number. + */ + public function glyphNumberForCharacter($characterCode) + { + return $this->_cmap->glyphNumberForCharacter($characterCode); + } + + /** + * Returns a number between 0 and 1 inclusive that indicates the percentage + * of characters in the string which are covered by glyphs in this font. + * + * Since no one font will contain glyphs for the entire Unicode character + * range, this method can be used to help locate a suitable font when the + * actual contents of the string are not known. + * + * Note that some fonts lie about the characters they support. Additionally, + * fonts don't usually contain glyphs for control characters such as tabs + * and line breaks, so it is rare that you will get back a full 1.0 score. + * The resulting value should be considered informational only. + * + * @param string $string + * @param string $charEncoding (optional) Character encoding of source text. + * If omitted, uses 'current locale'. + * @return float + */ + public function getCoveredPercentage($string, $charEncoding = '') + { + /* Convert the string to UTF-16BE encoding so we can match the string's + * character codes to those found in the cmap. + */ + if ($charEncoding != 'UTF-16BE') { + if (PHP_OS != 'AIX') { // AIX doesnt know what UTF-16BE is + $string = iconv($charEncoding, 'UTF-16BE', $string); + } + } + + $charCount = (PHP_OS != 'AIX') ? iconv_strlen($string, 'UTF-16BE') : strlen($string); + if ($charCount == 0) { + return 0; + } + + /* Fetch the covered character code list from the font's cmap. + */ + $coveredCharacters = $this->_cmap->getCoveredCharacters(); + + /* Calculate the score by doing a lookup for each character. + */ + $score = 0; + $maxIndex = strlen($string); + for ($i = 0; $i < $maxIndex; $i++) { + /** + * @todo Properly handle characters encoded as surrogate pairs. + */ + $charCode = (ord($string[$i]) << 8) | ord($string[++$i]); + /* This could probably be optimized a bit with a binary search... + */ + if (in_array($charCode, $coveredCharacters)) { + $score++; + } + } + return $score / $charCount; + } + + /** + * Returns the widths of the glyphs. + * + * The widths are expressed in the font's glyph space. You are responsible + * for converting to user space as necessary. See {@link unitsPerEm()}. + * + * See also {@link widthForGlyph()}. + * + * @param array &$glyphNumbers Array of glyph numbers. + * @return array Array of glyph widths (integers). + */ + public function widthsForGlyphs($glyphNumbers) + { + $widths = array(); + foreach ($glyphNumbers as $key => $glyphNumber) { + if (!isset($this->_glyphWidths[$glyphNumber])) { + $widths[$key] = $this->_missingGlyphWidth; + } else { + $widths[$key] = $this->_glyphWidths[$glyphNumber]; + } + } + return $widths; + } + + /** + * Returns the width of the glyph. + * + * Like {@link widthsForGlyphs()} but used for one glyph at a time. + * + * @param integer $glyphNumber + * @return integer + */ + public function widthForGlyph($glyphNumber) + { + if (!isset($this->_glyphWidths[$glyphNumber])) { + return $this->_missingGlyphWidth; + } + return $this->_glyphWidths[$glyphNumber]; + } + + /** + * Convert string to the font encoding. + * + * The method is used to prepare string for text drawing operators + * + * @param string $string + * @param string $charEncoding Character encoding of source text. + * @return string + */ + public function encodeString($string, $charEncoding) + { + if (PHP_OS == 'AIX') { + return $string; // returning here b/c AIX doesnt know what CP1252 is + } + + return iconv($charEncoding, 'CP1252//IGNORE', $string); + } + + /** + * Convert string from the font encoding. + * + * The method is used to convert strings retrieved from existing content streams + * + * @param string $string + * @param string $charEncoding Character encoding of resulting text. + * @return string + */ + public function decodeString($string, $charEncoding) + { + return iconv('CP1252', $charEncoding, $string); + } +} diff --git a/library/Zend/Pdf/Resource/Font/Simple/Parsed.php b/library/Zend/Pdf/Resource/Font/Simple/Parsed.php new file mode 100644 index 0000000..604cc79 --- /dev/null +++ b/library/Zend/Pdf/Resource/Font/Simple/Parsed.php @@ -0,0 +1,105 @@ +parse(); + + /* Object properties */ + + $this->_fontNames = $fontParser->names; + + $this->_isBold = $fontParser->isBold; + $this->_isItalic = $fontParser->isItalic; + $this->_isMonospaced = $fontParser->isMonospaced; + + $this->_underlinePosition = $fontParser->underlinePosition; + $this->_underlineThickness = $fontParser->underlineThickness; + $this->_strikePosition = $fontParser->strikePosition; + $this->_strikeThickness = $fontParser->strikeThickness; + + $this->_unitsPerEm = $fontParser->unitsPerEm; + + $this->_ascent = $fontParser->ascent; + $this->_descent = $fontParser->descent; + $this->_lineGap = $fontParser->lineGap; + + $this->_glyphWidths = $fontParser->glyphWidths; + $this->_missingGlyphWidth = $this->_glyphWidths[0]; + + + $this->_cmap = $fontParser->cmap; + + + /* Resource dictionary */ + + $baseFont = $this->getFontName(Zend_Pdf_Font::NAME_POSTSCRIPT, 'en', 'UTF-8'); + $this->_resource->BaseFont = new Zend_Pdf_Element_Name($baseFont); + + $this->_resource->FirstChar = new Zend_Pdf_Element_Numeric(0); + $this->_resource->LastChar = new Zend_Pdf_Element_Numeric(count($this->_glyphWidths) - 1); + + /* Now convert the scalar glyph widths to Zend_Pdf_Element_Numeric objects. + */ + $pdfWidths = array(); + foreach ($this->_glyphWidths as $width) { + $pdfWidths[] = new Zend_Pdf_Element_Numeric($this->toEmSpace($width)); + } + /* Create the Zend_Pdf_Element_Array object and add it to the font's + * object factory and resource dictionary. + */ + $widthsArrayElement = new Zend_Pdf_Element_Array($pdfWidths); + $widthsObject = $this->_objectFactory->newObject($widthsArrayElement); + $this->_resource->Widths = $widthsObject; + } +} diff --git a/library/Zend/Pdf/Resource/Font/Simple/Parsed/TrueType.php b/library/Zend/Pdf/Resource/Font/Simple/Parsed/TrueType.php new file mode 100644 index 0000000..25e8a9e --- /dev/null +++ b/library/Zend/Pdf/Resource/Font/Simple/Parsed/TrueType.php @@ -0,0 +1,67 @@ +_fontType = Zend_Pdf_Font::TYPE_TRUETYPE; + + $this->_resource->Subtype = new Zend_Pdf_Element_Name('TrueType'); + + $fontDescriptor = Zend_Pdf_Resource_Font_FontDescriptor::factory($this, $fontParser, $embeddingOptions); + $this->_resource->FontDescriptor = $this->_objectFactory->newObject($fontDescriptor); + } + +} diff --git a/library/Zend/Pdf/Resource/Font/Simple/Standard.php b/library/Zend/Pdf/Resource/Font/Simple/Standard.php new file mode 100644 index 0000000..bf1da1b --- /dev/null +++ b/library/Zend/Pdf/Resource/Font/Simple/Standard.php @@ -0,0 +1,82 @@ + + *
  • Courier - {@link Zend_Pdf_Resource_Font_Simple_Standard_Courier} + *
  • Courier-Bold - {@link Zend_Pdf_Resource_Font_Simple_Standard_CourierBold} + *
  • Courier-Oblique - {@link Zend_Pdf_Resource_Font_Simple_Standard_CourierOblique} + *
  • Courier-BoldOblique - {@link Zend_Pdf_Resource_Font_Simple_Standard_CourierBoldOblique} + *
  • Helvetica - {@link Zend_Pdf_Resource_Font_Simple_Standard_Helvetica} + *
  • Helvetica-Bold - {@link Zend_Pdf_Resource_Font_Simple_Standard_HelveticaBold} + *
  • Helvetica-Oblique - {@link Zend_Pdf_Resource_Font_Simple_Standard_HelveticaOblique} + *
  • Helvetica-BoldOblique - {@link Zend_Pdf_Resource_Font_Simple_Standard_HelveticaBoldOblique} + *
  • Symbol - {@link Zend_Pdf_Resource_Font_Simple_Standard_Symbol} + *
  • Times - {@link Zend_Pdf_Resource_Font_Simple_Standard_Times} + *
  • Times-Bold - {@link Zend_Pdf_Resource_Font_Simple_Standard_TimesBold} + *
  • Times-Italic - {@link Zend_Pdf_Resource_Font_Simple_Standard_TimesItalic} + *
  • Times-BoldItalic - {@link Zend_Pdf_Resource_Font_Simple_Standard_TimesBoldItalic} + *
  • ZapfDingbats - {@link Zend_Pdf_Resource_Font_Simple_Standard_ZapfDingbats} + * + * + * Font objects should be normally be obtained from the factory methods + * {@link Zend_Pdf_Font::fontWithName} and {@link Zend_Pdf_Font::fontWithPath}. + * + * @package Zend_Pdf + * @subpackage Fonts + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +abstract class Zend_Pdf_Resource_Font_Simple_Standard extends Zend_Pdf_Resource_Font_Simple +{ + /**** Public Interface ****/ + + + /* Object Lifecycle */ + + /** + * Object constructor + */ + public function __construct() + { + $this->_fontType = Zend_Pdf_Font::TYPE_STANDARD; + + parent::__construct(); + $this->_resource->Subtype = new Zend_Pdf_Element_Name('Type1'); + } +} diff --git a/library/Zend/Pdf/Resource/Font/Simple/Standard/Courier.php b/library/Zend/Pdf/Resource/Font/Simple/Standard/Courier.php new file mode 100644 index 0000000..f7d3a8e --- /dev/null +++ b/library/Zend/Pdf/Resource/Font/Simple/Standard/Courier.php @@ -0,0 +1,295 @@ +_fontNames[Zend_Pdf_Font::NAME_COPYRIGHT]['en'] = + "\x00\x43\x00\x6f\x00\x70\x00\x79\x00\x72\x00\x69\x00\x67\x00\x68\x00" + . "\x74\x00\x20\x00\x28\x00\x63\x00\x29\x00\x20\x00\x31\x00\x39\x00" + . "\x38\x00\x39\x00\x2c\x00\x20\x00\x31\x00\x39\x00\x39\x00\x30\x00" + . "\x2c\x00\x20\x00\x31\x00\x39\x00\x39\x00\x31\x00\x2c\x00\x20\x00" + . "\x31\x00\x39\x00\x39\x00\x32\x00\x2c\x00\x20\x00\x31\x00\x39\x00" + . "\x39\x00\x33\x00\x2c\x00\x20\x00\x31\x00\x39\x00\x39\x00\x37\x00" + . "\x20\x00\x41\x00\x64\x00\x6f\x00\x62\x00\x65\x00\x20\x00\x53\x00" + . "\x79\x00\x73\x00\x74\x00\x65\x00\x6d\x00\x73\x00\x20\x00\x49\x00" + . "\x6e\x00\x63\x00\x6f\x00\x72\x00\x70\x00\x6f\x00\x72\x00\x61\x00" + . "\x74\x00\x65\x00\x64\x00\x2e\x00\x20\x00\x20\x00\x41\x00\x6c\x00" + . "\x6c\x00\x20\x00\x52\x00\x69\x00\x67\x00\x68\x00\x74\x00\x73\x00" + . "\x20\x00\x52\x00\x65\x00\x73\x00\x65\x00\x72\x00\x76\x00\x65\x00" + . "\x64\x00\x2e"; + $this->_fontNames[Zend_Pdf_Font::NAME_FAMILY]['en'] = + "\x00\x43\x00\x6f\x00\x75\x00\x72\x00\x69\x00\x65\x00\x72"; + $this->_fontNames[Zend_Pdf_Font::NAME_STYLE]['en'] = + "\x00\x4d\x00\x65\x00\x64\x00\x69\x00\x75\x00\x6d"; + $this->_fontNames[Zend_Pdf_Font::NAME_ID]['en'] = + "\x00\x34\x00\x33\x00\x30\x00\x35\x00\x30"; + $this->_fontNames[Zend_Pdf_Font::NAME_FULL]['en'] = + "\x00\x43\x00\x6f\x00\x75\x00\x72\x00\x69\x00\x65\x00\x72\x00\x20\x00" + . "\x4d\x00\x65\x00\x64\x00\x69\x00\x75\x00\x6d"; + $this->_fontNames[Zend_Pdf_Font::NAME_VERSION]['en'] = + "\x00\x30\x00\x30\x00\x33\x00\x2e\x00\x30\x00\x30\x00\x30"; + $this->_fontNames[Zend_Pdf_Font::NAME_POSTSCRIPT]['en'] = + "\x00\x43\x00\x6f\x00\x75\x00\x72\x00\x69\x00\x65\x00\x72"; + + $this->_isBold = false; + $this->_isItalic = false; + $this->_isMonospaced = true; + + $this->_underlinePosition = -100; + $this->_underlineThickness = 50; + $this->_strikePosition = 225; + $this->_strikeThickness = 50; + + $this->_unitsPerEm = 1000; + + $this->_ascent = 629; + $this->_descent = -157; + $this->_lineGap = 414; + + /* The glyph numbers assigned here are synthetic; they do not match the + * actual glyph numbers used by the font. This is not a big deal though + * since this data never makes it to the PDF file. It is only used + * internally for layout calculations. + */ + $this->_glyphWidths = array( + 0x00 => 0x01f4, 0x01 => 0x0258, 0x02 => 0x0258, 0x03 => 0x0258, + 0x04 => 0x0258, 0x05 => 0x0258, 0x06 => 0x0258, 0x07 => 0x0258, + 0x08 => 0x0258, 0x09 => 0x0258, 0x0a => 0x0258, 0x0b => 0x0258, + 0x0c => 0x0258, 0x0d => 0x0258, 0x0e => 0x0258, 0x0f => 0x0258, + 0x10 => 0x0258, 0x11 => 0x0258, 0x12 => 0x0258, 0x13 => 0x0258, + 0x14 => 0x0258, 0x15 => 0x0258, 0x16 => 0x0258, 0x17 => 0x0258, + 0x18 => 0x0258, 0x19 => 0x0258, 0x1a => 0x0258, 0x1b => 0x0258, + 0x1c => 0x0258, 0x1d => 0x0258, 0x1e => 0x0258, 0x1f => 0x0258, + 0x20 => 0x0258, 0x21 => 0x0258, 0x22 => 0x0258, 0x23 => 0x0258, + 0x24 => 0x0258, 0x25 => 0x0258, 0x26 => 0x0258, 0x27 => 0x0258, + 0x28 => 0x0258, 0x29 => 0x0258, 0x2a => 0x0258, 0x2b => 0x0258, + 0x2c => 0x0258, 0x2d => 0x0258, 0x2e => 0x0258, 0x2f => 0x0258, + 0x30 => 0x0258, 0x31 => 0x0258, 0x32 => 0x0258, 0x33 => 0x0258, + 0x34 => 0x0258, 0x35 => 0x0258, 0x36 => 0x0258, 0x37 => 0x0258, + 0x38 => 0x0258, 0x39 => 0x0258, 0x3a => 0x0258, 0x3b => 0x0258, + 0x3c => 0x0258, 0x3d => 0x0258, 0x3e => 0x0258, 0x3f => 0x0258, + 0x40 => 0x0258, 0x41 => 0x0258, 0x42 => 0x0258, 0x43 => 0x0258, + 0x44 => 0x0258, 0x45 => 0x0258, 0x46 => 0x0258, 0x47 => 0x0258, + 0x48 => 0x0258, 0x49 => 0x0258, 0x4a => 0x0258, 0x4b => 0x0258, + 0x4c => 0x0258, 0x4d => 0x0258, 0x4e => 0x0258, 0x4f => 0x0258, + 0x50 => 0x0258, 0x51 => 0x0258, 0x52 => 0x0258, 0x53 => 0x0258, + 0x54 => 0x0258, 0x55 => 0x0258, 0x56 => 0x0258, 0x57 => 0x0258, + 0x58 => 0x0258, 0x59 => 0x0258, 0x5a => 0x0258, 0x5b => 0x0258, + 0x5c => 0x0258, 0x5d => 0x0258, 0x5e => 0x0258, 0x5f => 0x0258, + 0x60 => 0x0258, 0x61 => 0x0258, 0x62 => 0x0258, 0x63 => 0x0258, + 0x64 => 0x0258, 0x65 => 0x0258, 0x66 => 0x0258, 0x67 => 0x0258, + 0x68 => 0x0258, 0x69 => 0x0258, 0x6a => 0x0258, 0x6b => 0x0258, + 0x6c => 0x0258, 0x6d => 0x0258, 0x6e => 0x0258, 0x6f => 0x0258, + 0x70 => 0x0258, 0x71 => 0x0258, 0x72 => 0x0258, 0x73 => 0x0258, + 0x74 => 0x0258, 0x75 => 0x0258, 0x76 => 0x0258, 0x77 => 0x0258, + 0x78 => 0x0258, 0x79 => 0x0258, 0x7a => 0x0258, 0x7b => 0x0258, + 0x7c => 0x0258, 0x7d => 0x0258, 0x7e => 0x0258, 0x7f => 0x0258, + 0x80 => 0x0258, 0x81 => 0x0258, 0x82 => 0x0258, 0x83 => 0x0258, + 0x84 => 0x0258, 0x85 => 0x0258, 0x86 => 0x0258, 0x87 => 0x0258, + 0x88 => 0x0258, 0x89 => 0x0258, 0x8a => 0x0258, 0x8b => 0x0258, + 0x8c => 0x0258, 0x8d => 0x0258, 0x8e => 0x0258, 0x8f => 0x0258, + 0x90 => 0x0258, 0x91 => 0x0258, 0x92 => 0x0258, 0x93 => 0x0258, + 0x94 => 0x0258, 0x95 => 0x0258, 0x96 => 0x0258, 0x97 => 0x0258, + 0x98 => 0x0258, 0x99 => 0x0258, 0x9a => 0x0258, 0x9b => 0x0258, + 0x9c => 0x0258, 0x9d => 0x0258, 0x9e => 0x0258, 0x9f => 0x0258, + 0xa0 => 0x0258, 0xa1 => 0x0258, 0xa2 => 0x0258, 0xa3 => 0x0258, + 0xa4 => 0x0258, 0xa5 => 0x0258, 0xa6 => 0x0258, 0xa7 => 0x0258, + 0xa8 => 0x0258, 0xa9 => 0x0258, 0xaa => 0x0258, 0xab => 0x0258, + 0xac => 0x0258, 0xad => 0x0258, 0xae => 0x0258, 0xaf => 0x0258, + 0xb0 => 0x0258, 0xb1 => 0x0258, 0xb2 => 0x0258, 0xb3 => 0x0258, + 0xb4 => 0x0258, 0xb5 => 0x0258, 0xb6 => 0x0258, 0xb7 => 0x0258, + 0xb8 => 0x0258, 0xb9 => 0x0258, 0xba => 0x0258, 0xbb => 0x0258, + 0xbc => 0x0258, 0xbd => 0x0258, 0xbe => 0x0258, 0xbf => 0x0258, + 0xc0 => 0x0258, 0xc1 => 0x0258, 0xc2 => 0x0258, 0xc3 => 0x0258, + 0xc4 => 0x0258, 0xc5 => 0x0258, 0xc6 => 0x0258, 0xc7 => 0x0258, + 0xc8 => 0x0258, 0xc9 => 0x0258, 0xca => 0x0258, 0xcb => 0x0258, + 0xcc => 0x0258, 0xcd => 0x0258, 0xce => 0x0258, 0xcf => 0x0258, + 0xd0 => 0x0258, 0xd1 => 0x0258, 0xd2 => 0x0258, 0xd3 => 0x0258, + 0xd4 => 0x0258, 0xd5 => 0x0258, 0xd6 => 0x0258, 0xd7 => 0x0258, + 0xd8 => 0x0258, 0xd9 => 0x0258, 0xda => 0x0258, 0xdb => 0x0258, + 0xdc => 0x0258, 0xdd => 0x0258, 0xde => 0x0258, 0xdf => 0x0258, + 0xe0 => 0x0258, 0xe1 => 0x0258, 0xe2 => 0x0258, 0xe3 => 0x0258, + 0xe4 => 0x0258, 0xe5 => 0x0258, 0xe6 => 0x0258, 0xe7 => 0x0258, + 0xe8 => 0x0258, 0xe9 => 0x0258, 0xea => 0x0258, 0xeb => 0x0258, + 0xec => 0x0258, 0xed => 0x0258, 0xee => 0x0258, 0xef => 0x0258, + 0xf0 => 0x0258, 0xf1 => 0x0258, 0xf2 => 0x0258, 0xf3 => 0x0258, + 0xf4 => 0x0258, 0xf5 => 0x0258, 0xf6 => 0x0258, 0xf7 => 0x0258, + 0xf8 => 0x0258, 0xf9 => 0x0258, 0xfa => 0x0258, 0xfb => 0x0258, + 0xfc => 0x0258, 0xfd => 0x0258, 0xfe => 0x0258, 0xff => 0x0258, + 0x0100 => 0x0258, 0x0101 => 0x0258, 0x0102 => 0x0258, 0x0103 => 0x0258, + 0x0104 => 0x0258, 0x0105 => 0x0258, 0x0106 => 0x0258, 0x0107 => 0x0258, + 0x0108 => 0x0258, 0x0109 => 0x0258, 0x010a => 0x0258, 0x010b => 0x0258, + 0x010c => 0x0258, 0x010d => 0x0258, 0x010e => 0x0258, 0x010f => 0x0258, + 0x0110 => 0x0258, 0x0111 => 0x0258, 0x0112 => 0x0258, 0x0113 => 0x0258, + 0x0114 => 0x0258, 0x0115 => 0x0258, 0x0116 => 0x0258, 0x0117 => 0x0258, + 0x0118 => 0x0258, 0x0119 => 0x0258, 0x011a => 0x0258, 0x011b => 0x0258, + 0x011c => 0x0258, 0x011d => 0x0258, 0x011e => 0x0258, 0x011f => 0x0258, + 0x0120 => 0x0258, 0x0121 => 0x0258, 0x0122 => 0x0258, 0x0123 => 0x0258, + 0x0124 => 0x0258, 0x0125 => 0x0258, 0x0126 => 0x0258, 0x0127 => 0x0258, + 0x0128 => 0x0258, 0x0129 => 0x0258, 0x012a => 0x0258, 0x012b => 0x0258, + 0x012c => 0x0258, 0x012d => 0x0258, 0x012e => 0x0258, 0x012f => 0x0258, + 0x0130 => 0x0258, 0x0131 => 0x0258, 0x0132 => 0x0258, 0x0133 => 0x0258, + 0x0134 => 0x0258, 0x0135 => 0x0258, 0x0136 => 0x0258, 0x0137 => 0x0258, + 0x0138 => 0x0258, 0x0139 => 0x0258, 0x013a => 0x0258, 0x013b => 0x0258, + ); + + /* The cmap table is similarly synthesized. + */ + $cmapData = array( + 0x20 => 0x01, 0x21 => 0x02, 0x22 => 0x03, 0x23 => 0x04, + 0x24 => 0x05, 0x25 => 0x06, 0x26 => 0x07, 0x2019 => 0x08, + 0x28 => 0x09, 0x29 => 0x0a, 0x2a => 0x0b, 0x2b => 0x0c, + 0x2c => 0x0d, 0x2d => 0x0e, 0x2e => 0x0f, 0x2f => 0x10, + 0x30 => 0x11, 0x31 => 0x12, 0x32 => 0x13, 0x33 => 0x14, + 0x34 => 0x15, 0x35 => 0x16, 0x36 => 0x17, 0x37 => 0x18, + 0x38 => 0x19, 0x39 => 0x1a, 0x3a => 0x1b, 0x3b => 0x1c, + 0x3c => 0x1d, 0x3d => 0x1e, 0x3e => 0x1f, 0x3f => 0x20, + 0x40 => 0x21, 0x41 => 0x22, 0x42 => 0x23, 0x43 => 0x24, + 0x44 => 0x25, 0x45 => 0x26, 0x46 => 0x27, 0x47 => 0x28, + 0x48 => 0x29, 0x49 => 0x2a, 0x4a => 0x2b, 0x4b => 0x2c, + 0x4c => 0x2d, 0x4d => 0x2e, 0x4e => 0x2f, 0x4f => 0x30, + 0x50 => 0x31, 0x51 => 0x32, 0x52 => 0x33, 0x53 => 0x34, + 0x54 => 0x35, 0x55 => 0x36, 0x56 => 0x37, 0x57 => 0x38, + 0x58 => 0x39, 0x59 => 0x3a, 0x5a => 0x3b, 0x5b => 0x3c, + 0x5c => 0x3d, 0x5d => 0x3e, 0x5e => 0x3f, 0x5f => 0x40, + 0x2018 => 0x41, 0x61 => 0x42, 0x62 => 0x43, 0x63 => 0x44, + 0x64 => 0x45, 0x65 => 0x46, 0x66 => 0x47, 0x67 => 0x48, + 0x68 => 0x49, 0x69 => 0x4a, 0x6a => 0x4b, 0x6b => 0x4c, + 0x6c => 0x4d, 0x6d => 0x4e, 0x6e => 0x4f, 0x6f => 0x50, + 0x70 => 0x51, 0x71 => 0x52, 0x72 => 0x53, 0x73 => 0x54, + 0x74 => 0x55, 0x75 => 0x56, 0x76 => 0x57, 0x77 => 0x58, + 0x78 => 0x59, 0x79 => 0x5a, 0x7a => 0x5b, 0x7b => 0x5c, + 0x7c => 0x5d, 0x7d => 0x5e, 0x7e => 0x5f, 0xa1 => 0x60, + 0xa2 => 0x61, 0xa3 => 0x62, 0x2044 => 0x63, 0xa5 => 0x64, + 0x0192 => 0x65, 0xa7 => 0x66, 0xa4 => 0x67, 0x27 => 0x68, + 0x201c => 0x69, 0xab => 0x6a, 0x2039 => 0x6b, 0x203a => 0x6c, + 0xfb01 => 0x6d, 0xfb02 => 0x6e, 0x2013 => 0x6f, 0x2020 => 0x70, + 0x2021 => 0x71, 0xb7 => 0x72, 0xb6 => 0x73, 0x2022 => 0x74, + 0x201a => 0x75, 0x201e => 0x76, 0x201d => 0x77, 0xbb => 0x78, + 0x2026 => 0x79, 0x2030 => 0x7a, 0xbf => 0x7b, 0x60 => 0x7c, + 0xb4 => 0x7d, 0x02c6 => 0x7e, 0x02dc => 0x7f, 0xaf => 0x80, + 0x02d8 => 0x81, 0x02d9 => 0x82, 0xa8 => 0x83, 0x02da => 0x84, + 0xb8 => 0x85, 0x02dd => 0x86, 0x02db => 0x87, 0x02c7 => 0x88, + 0x2014 => 0x89, 0xc6 => 0x8a, 0xaa => 0x8b, 0x0141 => 0x8c, + 0xd8 => 0x8d, 0x0152 => 0x8e, 0xba => 0x8f, 0xe6 => 0x90, + 0x0131 => 0x91, 0x0142 => 0x92, 0xf8 => 0x93, 0x0153 => 0x94, + 0xdf => 0x95, 0xcf => 0x96, 0xe9 => 0x97, 0x0103 => 0x98, + 0x0171 => 0x99, 0x011b => 0x9a, 0x0178 => 0x9b, 0xf7 => 0x9c, + 0xdd => 0x9d, 0xc2 => 0x9e, 0xe1 => 0x9f, 0xdb => 0xa0, + 0xfd => 0xa1, 0x0219 => 0xa2, 0xea => 0xa3, 0x016e => 0xa4, + 0xdc => 0xa5, 0x0105 => 0xa6, 0xda => 0xa7, 0x0173 => 0xa8, + 0xcb => 0xa9, 0x0110 => 0xaa, 0xf6c3 => 0xab, 0xa9 => 0xac, + 0x0112 => 0xad, 0x010d => 0xae, 0xe5 => 0xaf, 0x0145 => 0xb0, + 0x013a => 0xb1, 0xe0 => 0xb2, 0x0162 => 0xb3, 0x0106 => 0xb4, + 0xe3 => 0xb5, 0x0116 => 0xb6, 0x0161 => 0xb7, 0x015f => 0xb8, + 0xed => 0xb9, 0x25ca => 0xba, 0x0158 => 0xbb, 0x0122 => 0xbc, + 0xfb => 0xbd, 0xe2 => 0xbe, 0x0100 => 0xbf, 0x0159 => 0xc0, + 0xe7 => 0xc1, 0x017b => 0xc2, 0xde => 0xc3, 0x014c => 0xc4, + 0x0154 => 0xc5, 0x015a => 0xc6, 0x010f => 0xc7, 0x016a => 0xc8, + 0x016f => 0xc9, 0xb3 => 0xca, 0xd2 => 0xcb, 0xc0 => 0xcc, + 0x0102 => 0xcd, 0xd7 => 0xce, 0xfa => 0xcf, 0x0164 => 0xd0, + 0x2202 => 0xd1, 0xff => 0xd2, 0x0143 => 0xd3, 0xee => 0xd4, + 0xca => 0xd5, 0xe4 => 0xd6, 0xeb => 0xd7, 0x0107 => 0xd8, + 0x0144 => 0xd9, 0x016b => 0xda, 0x0147 => 0xdb, 0xcd => 0xdc, + 0xb1 => 0xdd, 0xa6 => 0xde, 0xae => 0xdf, 0x011e => 0xe0, + 0x0130 => 0xe1, 0x2211 => 0xe2, 0xc8 => 0xe3, 0x0155 => 0xe4, + 0x014d => 0xe5, 0x0179 => 0xe6, 0x017d => 0xe7, 0x2265 => 0xe8, + 0xd0 => 0xe9, 0xc7 => 0xea, 0x013c => 0xeb, 0x0165 => 0xec, + 0x0119 => 0xed, 0x0172 => 0xee, 0xc1 => 0xef, 0xc4 => 0xf0, + 0xe8 => 0xf1, 0x017a => 0xf2, 0x012f => 0xf3, 0xd3 => 0xf4, + 0xf3 => 0xf5, 0x0101 => 0xf6, 0x015b => 0xf7, 0xef => 0xf8, + 0xd4 => 0xf9, 0xd9 => 0xfa, 0x2206 => 0xfb, 0xfe => 0xfc, + 0xb2 => 0xfd, 0xd6 => 0xfe, 0xb5 => 0xff, 0xec => 0x0100, + 0x0151 => 0x0101, 0x0118 => 0x0102, 0x0111 => 0x0103, 0xbe => 0x0104, + 0x015e => 0x0105, 0x013e => 0x0106, 0x0136 => 0x0107, 0x0139 => 0x0108, + 0x2122 => 0x0109, 0x0117 => 0x010a, 0xcc => 0x010b, 0x012a => 0x010c, + 0x013d => 0x010d, 0xbd => 0x010e, 0x2264 => 0x010f, 0xf4 => 0x0110, + 0xf1 => 0x0111, 0x0170 => 0x0112, 0xc9 => 0x0113, 0x0113 => 0x0114, + 0x011f => 0x0115, 0xbc => 0x0116, 0x0160 => 0x0117, 0x0218 => 0x0118, + 0x0150 => 0x0119, 0xb0 => 0x011a, 0xf2 => 0x011b, 0x010c => 0x011c, + 0xf9 => 0x011d, 0x221a => 0x011e, 0x010e => 0x011f, 0x0157 => 0x0120, + 0xd1 => 0x0121, 0xf5 => 0x0122, 0x0156 => 0x0123, 0x013b => 0x0124, + 0xc3 => 0x0125, 0x0104 => 0x0126, 0xc5 => 0x0127, 0xd5 => 0x0128, + 0x017c => 0x0129, 0x011a => 0x012a, 0x012e => 0x012b, 0x0137 => 0x012c, + 0x2212 => 0x012d, 0xce => 0x012e, 0x0148 => 0x012f, 0x0163 => 0x0130, + 0xac => 0x0131, 0xf6 => 0x0132, 0xfc => 0x0133, 0x2260 => 0x0134, + 0x0123 => 0x0135, 0xf0 => 0x0136, 0x017e => 0x0137, 0x0146 => 0x0138, + 0xb9 => 0x0139, 0x012b => 0x013a, 0x20ac => 0x013b); + // require_once 'Zend/Pdf/Cmap.php'; + $this->_cmap = Zend_Pdf_Cmap::cmapWithTypeData( + Zend_Pdf_Cmap::TYPE_BYTE_ENCODING_STATIC, $cmapData); + + + /* Resource dictionary */ + + /* The resource dictionary for the standard fonts is sparse because PDF + * viewers already have all of the metrics data. We only need to provide + * the font name and encoding method. + */ + $this->_resource->BaseFont = new Zend_Pdf_Element_Name('Courier'); + } +} diff --git a/library/Zend/Pdf/Resource/Font/Simple/Standard/CourierBold.php b/library/Zend/Pdf/Resource/Font/Simple/Standard/CourierBold.php new file mode 100644 index 0000000..4f383cf --- /dev/null +++ b/library/Zend/Pdf/Resource/Font/Simple/Standard/CourierBold.php @@ -0,0 +1,296 @@ +_fontNames[Zend_Pdf_Font::NAME_COPYRIGHT]['en'] = + "\x00\x43\x00\x6f\x00\x70\x00\x79\x00\x72\x00\x69\x00\x67\x00\x68\x00" + . "\x74\x00\x20\x00\x28\x00\x63\x00\x29\x00\x20\x00\x31\x00\x39\x00" + . "\x38\x00\x39\x00\x2c\x00\x20\x00\x31\x00\x39\x00\x39\x00\x30\x00" + . "\x2c\x00\x20\x00\x31\x00\x39\x00\x39\x00\x31\x00\x2c\x00\x20\x00" + . "\x31\x00\x39\x00\x39\x00\x33\x00\x2c\x00\x20\x00\x31\x00\x39\x00" + . "\x39\x00\x37\x00\x20\x00\x41\x00\x64\x00\x6f\x00\x62\x00\x65\x00" + . "\x20\x00\x53\x00\x79\x00\x73\x00\x74\x00\x65\x00\x6d\x00\x73\x00" + . "\x20\x00\x49\x00\x6e\x00\x63\x00\x6f\x00\x72\x00\x70\x00\x6f\x00" + . "\x72\x00\x61\x00\x74\x00\x65\x00\x64\x00\x2e\x00\x20\x00\x20\x00" + . "\x41\x00\x6c\x00\x6c\x00\x20\x00\x52\x00\x69\x00\x67\x00\x68\x00" + . "\x74\x00\x73\x00\x20\x00\x52\x00\x65\x00\x73\x00\x65\x00\x72\x00" + . "\x76\x00\x65\x00\x64\x00\x2e"; + $this->_fontNames[Zend_Pdf_Font::NAME_FAMILY]['en'] = + "\x00\x43\x00\x6f\x00\x75\x00\x72\x00\x69\x00\x65\x00\x72"; + $this->_fontNames[Zend_Pdf_Font::NAME_STYLE]['en'] = + "\x00\x42\x00\x6f\x00\x6c\x00\x64"; + $this->_fontNames[Zend_Pdf_Font::NAME_ID]['en'] = + "\x00\x34\x00\x33\x00\x30\x00\x34\x00\x38"; + $this->_fontNames[Zend_Pdf_Font::NAME_FULL]['en'] = + "\x00\x43\x00\x6f\x00\x75\x00\x72\x00\x69\x00\x65\x00\x72\x00\x2d\x00" + . "\x42\x00\x6f\x00\x6c\x00\x64\x00\x20\x00\x42\x00\x6f\x00\x6c\x00" + . "\x64"; + $this->_fontNames[Zend_Pdf_Font::NAME_VERSION]['en'] = + "\x00\x30\x00\x30\x00\x33\x00\x2e\x00\x30\x00\x30\x00\x30"; + $this->_fontNames[Zend_Pdf_Font::NAME_POSTSCRIPT]['en'] = + "\x00\x43\x00\x6f\x00\x75\x00\x72\x00\x69\x00\x65\x00\x72\x00\x2d\x00" + . "\x42\x00\x6f\x00\x6c\x00\x64"; + + $this->_isBold = true; + $this->_isItalic = false; + $this->_isMonospaced = true; + + $this->_underlinePosition = -100; + $this->_underlineThickness = 50; + $this->_strikePosition = 225; + $this->_strikeThickness = 50; + + $this->_unitsPerEm = 1000; + + $this->_ascent = 629; + $this->_descent = -157; + $this->_lineGap = 414; + + /* The glyph numbers assigned here are synthetic; they do not match the + * actual glyph numbers used by the font. This is not a big deal though + * since this data never makes it to the PDF file. It is only used + * internally for layout calculations. + */ + $this->_glyphWidths = array( + 0x00 => 0x01f4, 0x01 => 0x0258, 0x02 => 0x0258, 0x03 => 0x0258, + 0x04 => 0x0258, 0x05 => 0x0258, 0x06 => 0x0258, 0x07 => 0x0258, + 0x08 => 0x0258, 0x09 => 0x0258, 0x0a => 0x0258, 0x0b => 0x0258, + 0x0c => 0x0258, 0x0d => 0x0258, 0x0e => 0x0258, 0x0f => 0x0258, + 0x10 => 0x0258, 0x11 => 0x0258, 0x12 => 0x0258, 0x13 => 0x0258, + 0x14 => 0x0258, 0x15 => 0x0258, 0x16 => 0x0258, 0x17 => 0x0258, + 0x18 => 0x0258, 0x19 => 0x0258, 0x1a => 0x0258, 0x1b => 0x0258, + 0x1c => 0x0258, 0x1d => 0x0258, 0x1e => 0x0258, 0x1f => 0x0258, + 0x20 => 0x0258, 0x21 => 0x0258, 0x22 => 0x0258, 0x23 => 0x0258, + 0x24 => 0x0258, 0x25 => 0x0258, 0x26 => 0x0258, 0x27 => 0x0258, + 0x28 => 0x0258, 0x29 => 0x0258, 0x2a => 0x0258, 0x2b => 0x0258, + 0x2c => 0x0258, 0x2d => 0x0258, 0x2e => 0x0258, 0x2f => 0x0258, + 0x30 => 0x0258, 0x31 => 0x0258, 0x32 => 0x0258, 0x33 => 0x0258, + 0x34 => 0x0258, 0x35 => 0x0258, 0x36 => 0x0258, 0x37 => 0x0258, + 0x38 => 0x0258, 0x39 => 0x0258, 0x3a => 0x0258, 0x3b => 0x0258, + 0x3c => 0x0258, 0x3d => 0x0258, 0x3e => 0x0258, 0x3f => 0x0258, + 0x40 => 0x0258, 0x41 => 0x0258, 0x42 => 0x0258, 0x43 => 0x0258, + 0x44 => 0x0258, 0x45 => 0x0258, 0x46 => 0x0258, 0x47 => 0x0258, + 0x48 => 0x0258, 0x49 => 0x0258, 0x4a => 0x0258, 0x4b => 0x0258, + 0x4c => 0x0258, 0x4d => 0x0258, 0x4e => 0x0258, 0x4f => 0x0258, + 0x50 => 0x0258, 0x51 => 0x0258, 0x52 => 0x0258, 0x53 => 0x0258, + 0x54 => 0x0258, 0x55 => 0x0258, 0x56 => 0x0258, 0x57 => 0x0258, + 0x58 => 0x0258, 0x59 => 0x0258, 0x5a => 0x0258, 0x5b => 0x0258, + 0x5c => 0x0258, 0x5d => 0x0258, 0x5e => 0x0258, 0x5f => 0x0258, + 0x60 => 0x0258, 0x61 => 0x0258, 0x62 => 0x0258, 0x63 => 0x0258, + 0x64 => 0x0258, 0x65 => 0x0258, 0x66 => 0x0258, 0x67 => 0x0258, + 0x68 => 0x0258, 0x69 => 0x0258, 0x6a => 0x0258, 0x6b => 0x0258, + 0x6c => 0x0258, 0x6d => 0x0258, 0x6e => 0x0258, 0x6f => 0x0258, + 0x70 => 0x0258, 0x71 => 0x0258, 0x72 => 0x0258, 0x73 => 0x0258, + 0x74 => 0x0258, 0x75 => 0x0258, 0x76 => 0x0258, 0x77 => 0x0258, + 0x78 => 0x0258, 0x79 => 0x0258, 0x7a => 0x0258, 0x7b => 0x0258, + 0x7c => 0x0258, 0x7d => 0x0258, 0x7e => 0x0258, 0x7f => 0x0258, + 0x80 => 0x0258, 0x81 => 0x0258, 0x82 => 0x0258, 0x83 => 0x0258, + 0x84 => 0x0258, 0x85 => 0x0258, 0x86 => 0x0258, 0x87 => 0x0258, + 0x88 => 0x0258, 0x89 => 0x0258, 0x8a => 0x0258, 0x8b => 0x0258, + 0x8c => 0x0258, 0x8d => 0x0258, 0x8e => 0x0258, 0x8f => 0x0258, + 0x90 => 0x0258, 0x91 => 0x0258, 0x92 => 0x0258, 0x93 => 0x0258, + 0x94 => 0x0258, 0x95 => 0x0258, 0x96 => 0x0258, 0x97 => 0x0258, + 0x98 => 0x0258, 0x99 => 0x0258, 0x9a => 0x0258, 0x9b => 0x0258, + 0x9c => 0x0258, 0x9d => 0x0258, 0x9e => 0x0258, 0x9f => 0x0258, + 0xa0 => 0x0258, 0xa1 => 0x0258, 0xa2 => 0x0258, 0xa3 => 0x0258, + 0xa4 => 0x0258, 0xa5 => 0x0258, 0xa6 => 0x0258, 0xa7 => 0x0258, + 0xa8 => 0x0258, 0xa9 => 0x0258, 0xaa => 0x0258, 0xab => 0x0258, + 0xac => 0x0258, 0xad => 0x0258, 0xae => 0x0258, 0xaf => 0x0258, + 0xb0 => 0x0258, 0xb1 => 0x0258, 0xb2 => 0x0258, 0xb3 => 0x0258, + 0xb4 => 0x0258, 0xb5 => 0x0258, 0xb6 => 0x0258, 0xb7 => 0x0258, + 0xb8 => 0x0258, 0xb9 => 0x0258, 0xba => 0x0258, 0xbb => 0x0258, + 0xbc => 0x0258, 0xbd => 0x0258, 0xbe => 0x0258, 0xbf => 0x0258, + 0xc0 => 0x0258, 0xc1 => 0x0258, 0xc2 => 0x0258, 0xc3 => 0x0258, + 0xc4 => 0x0258, 0xc5 => 0x0258, 0xc6 => 0x0258, 0xc7 => 0x0258, + 0xc8 => 0x0258, 0xc9 => 0x0258, 0xca => 0x0258, 0xcb => 0x0258, + 0xcc => 0x0258, 0xcd => 0x0258, 0xce => 0x0258, 0xcf => 0x0258, + 0xd0 => 0x0258, 0xd1 => 0x0258, 0xd2 => 0x0258, 0xd3 => 0x0258, + 0xd4 => 0x0258, 0xd5 => 0x0258, 0xd6 => 0x0258, 0xd7 => 0x0258, + 0xd8 => 0x0258, 0xd9 => 0x0258, 0xda => 0x0258, 0xdb => 0x0258, + 0xdc => 0x0258, 0xdd => 0x0258, 0xde => 0x0258, 0xdf => 0x0258, + 0xe0 => 0x0258, 0xe1 => 0x0258, 0xe2 => 0x0258, 0xe3 => 0x0258, + 0xe4 => 0x0258, 0xe5 => 0x0258, 0xe6 => 0x0258, 0xe7 => 0x0258, + 0xe8 => 0x0258, 0xe9 => 0x0258, 0xea => 0x0258, 0xeb => 0x0258, + 0xec => 0x0258, 0xed => 0x0258, 0xee => 0x0258, 0xef => 0x0258, + 0xf0 => 0x0258, 0xf1 => 0x0258, 0xf2 => 0x0258, 0xf3 => 0x0258, + 0xf4 => 0x0258, 0xf5 => 0x0258, 0xf6 => 0x0258, 0xf7 => 0x0258, + 0xf8 => 0x0258, 0xf9 => 0x0258, 0xfa => 0x0258, 0xfb => 0x0258, + 0xfc => 0x0258, 0xfd => 0x0258, 0xfe => 0x0258, 0xff => 0x0258, + 0x0100 => 0x0258, 0x0101 => 0x0258, 0x0102 => 0x0258, 0x0103 => 0x0258, + 0x0104 => 0x0258, 0x0105 => 0x0258, 0x0106 => 0x0258, 0x0107 => 0x0258, + 0x0108 => 0x0258, 0x0109 => 0x0258, 0x010a => 0x0258, 0x010b => 0x0258, + 0x010c => 0x0258, 0x010d => 0x0258, 0x010e => 0x0258, 0x010f => 0x0258, + 0x0110 => 0x0258, 0x0111 => 0x0258, 0x0112 => 0x0258, 0x0113 => 0x0258, + 0x0114 => 0x0258, 0x0115 => 0x0258, 0x0116 => 0x0258, 0x0117 => 0x0258, + 0x0118 => 0x0258, 0x0119 => 0x0258, 0x011a => 0x0258, 0x011b => 0x0258, + 0x011c => 0x0258, 0x011d => 0x0258, 0x011e => 0x0258, 0x011f => 0x0258, + 0x0120 => 0x0258, 0x0121 => 0x0258, 0x0122 => 0x0258, 0x0123 => 0x0258, + 0x0124 => 0x0258, 0x0125 => 0x0258, 0x0126 => 0x0258, 0x0127 => 0x0258, + 0x0128 => 0x0258, 0x0129 => 0x0258, 0x012a => 0x0258, 0x012b => 0x0258, + 0x012c => 0x0258, 0x012d => 0x0258, 0x012e => 0x0258, 0x012f => 0x0258, + 0x0130 => 0x0258, 0x0131 => 0x0258, 0x0132 => 0x0258, 0x0133 => 0x0258, + 0x0134 => 0x0258, 0x0135 => 0x0258, 0x0136 => 0x0258, 0x0137 => 0x0258, + 0x0138 => 0x0258, 0x0139 => 0x0258, 0x013a => 0x0258, 0x013b => 0x0258, + ); + + /* The cmap table is similarly synthesized. + */ + $cmapData = array( + 0x20 => 0x01, 0x21 => 0x02, 0x22 => 0x03, 0x23 => 0x04, + 0x24 => 0x05, 0x25 => 0x06, 0x26 => 0x07, 0x2019 => 0x08, + 0x28 => 0x09, 0x29 => 0x0a, 0x2a => 0x0b, 0x2b => 0x0c, + 0x2c => 0x0d, 0x2d => 0x0e, 0x2e => 0x0f, 0x2f => 0x10, + 0x30 => 0x11, 0x31 => 0x12, 0x32 => 0x13, 0x33 => 0x14, + 0x34 => 0x15, 0x35 => 0x16, 0x36 => 0x17, 0x37 => 0x18, + 0x38 => 0x19, 0x39 => 0x1a, 0x3a => 0x1b, 0x3b => 0x1c, + 0x3c => 0x1d, 0x3d => 0x1e, 0x3e => 0x1f, 0x3f => 0x20, + 0x40 => 0x21, 0x41 => 0x22, 0x42 => 0x23, 0x43 => 0x24, + 0x44 => 0x25, 0x45 => 0x26, 0x46 => 0x27, 0x47 => 0x28, + 0x48 => 0x29, 0x49 => 0x2a, 0x4a => 0x2b, 0x4b => 0x2c, + 0x4c => 0x2d, 0x4d => 0x2e, 0x4e => 0x2f, 0x4f => 0x30, + 0x50 => 0x31, 0x51 => 0x32, 0x52 => 0x33, 0x53 => 0x34, + 0x54 => 0x35, 0x55 => 0x36, 0x56 => 0x37, 0x57 => 0x38, + 0x58 => 0x39, 0x59 => 0x3a, 0x5a => 0x3b, 0x5b => 0x3c, + 0x5c => 0x3d, 0x5d => 0x3e, 0x5e => 0x3f, 0x5f => 0x40, + 0x2018 => 0x41, 0x61 => 0x42, 0x62 => 0x43, 0x63 => 0x44, + 0x64 => 0x45, 0x65 => 0x46, 0x66 => 0x47, 0x67 => 0x48, + 0x68 => 0x49, 0x69 => 0x4a, 0x6a => 0x4b, 0x6b => 0x4c, + 0x6c => 0x4d, 0x6d => 0x4e, 0x6e => 0x4f, 0x6f => 0x50, + 0x70 => 0x51, 0x71 => 0x52, 0x72 => 0x53, 0x73 => 0x54, + 0x74 => 0x55, 0x75 => 0x56, 0x76 => 0x57, 0x77 => 0x58, + 0x78 => 0x59, 0x79 => 0x5a, 0x7a => 0x5b, 0x7b => 0x5c, + 0x7c => 0x5d, 0x7d => 0x5e, 0x7e => 0x5f, 0xa1 => 0x60, + 0xa2 => 0x61, 0xa3 => 0x62, 0x2044 => 0x63, 0xa5 => 0x64, + 0x0192 => 0x65, 0xa7 => 0x66, 0xa4 => 0x67, 0x27 => 0x68, + 0x201c => 0x69, 0xab => 0x6a, 0x2039 => 0x6b, 0x203a => 0x6c, + 0xfb01 => 0x6d, 0xfb02 => 0x6e, 0x2013 => 0x6f, 0x2020 => 0x70, + 0x2021 => 0x71, 0xb7 => 0x72, 0xb6 => 0x73, 0x2022 => 0x74, + 0x201a => 0x75, 0x201e => 0x76, 0x201d => 0x77, 0xbb => 0x78, + 0x2026 => 0x79, 0x2030 => 0x7a, 0xbf => 0x7b, 0x60 => 0x7c, + 0xb4 => 0x7d, 0x02c6 => 0x7e, 0x02dc => 0x7f, 0xaf => 0x80, + 0x02d8 => 0x81, 0x02d9 => 0x82, 0xa8 => 0x83, 0x02da => 0x84, + 0xb8 => 0x85, 0x02dd => 0x86, 0x02db => 0x87, 0x02c7 => 0x88, + 0x2014 => 0x89, 0xc6 => 0x8a, 0xaa => 0x8b, 0x0141 => 0x8c, + 0xd8 => 0x8d, 0x0152 => 0x8e, 0xba => 0x8f, 0xe6 => 0x90, + 0x0131 => 0x91, 0x0142 => 0x92, 0xf8 => 0x93, 0x0153 => 0x94, + 0xdf => 0x95, 0xcf => 0x96, 0xe9 => 0x97, 0x0103 => 0x98, + 0x0171 => 0x99, 0x011b => 0x9a, 0x0178 => 0x9b, 0xf7 => 0x9c, + 0xdd => 0x9d, 0xc2 => 0x9e, 0xe1 => 0x9f, 0xdb => 0xa0, + 0xfd => 0xa1, 0x0219 => 0xa2, 0xea => 0xa3, 0x016e => 0xa4, + 0xdc => 0xa5, 0x0105 => 0xa6, 0xda => 0xa7, 0x0173 => 0xa8, + 0xcb => 0xa9, 0x0110 => 0xaa, 0xf6c3 => 0xab, 0xa9 => 0xac, + 0x0112 => 0xad, 0x010d => 0xae, 0xe5 => 0xaf, 0x0145 => 0xb0, + 0x013a => 0xb1, 0xe0 => 0xb2, 0x0162 => 0xb3, 0x0106 => 0xb4, + 0xe3 => 0xb5, 0x0116 => 0xb6, 0x0161 => 0xb7, 0x015f => 0xb8, + 0xed => 0xb9, 0x25ca => 0xba, 0x0158 => 0xbb, 0x0122 => 0xbc, + 0xfb => 0xbd, 0xe2 => 0xbe, 0x0100 => 0xbf, 0x0159 => 0xc0, + 0xe7 => 0xc1, 0x017b => 0xc2, 0xde => 0xc3, 0x014c => 0xc4, + 0x0154 => 0xc5, 0x015a => 0xc6, 0x010f => 0xc7, 0x016a => 0xc8, + 0x016f => 0xc9, 0xb3 => 0xca, 0xd2 => 0xcb, 0xc0 => 0xcc, + 0x0102 => 0xcd, 0xd7 => 0xce, 0xfa => 0xcf, 0x0164 => 0xd0, + 0x2202 => 0xd1, 0xff => 0xd2, 0x0143 => 0xd3, 0xee => 0xd4, + 0xca => 0xd5, 0xe4 => 0xd6, 0xeb => 0xd7, 0x0107 => 0xd8, + 0x0144 => 0xd9, 0x016b => 0xda, 0x0147 => 0xdb, 0xcd => 0xdc, + 0xb1 => 0xdd, 0xa6 => 0xde, 0xae => 0xdf, 0x011e => 0xe0, + 0x0130 => 0xe1, 0x2211 => 0xe2, 0xc8 => 0xe3, 0x0155 => 0xe4, + 0x014d => 0xe5, 0x0179 => 0xe6, 0x017d => 0xe7, 0x2265 => 0xe8, + 0xd0 => 0xe9, 0xc7 => 0xea, 0x013c => 0xeb, 0x0165 => 0xec, + 0x0119 => 0xed, 0x0172 => 0xee, 0xc1 => 0xef, 0xc4 => 0xf0, + 0xe8 => 0xf1, 0x017a => 0xf2, 0x012f => 0xf3, 0xd3 => 0xf4, + 0xf3 => 0xf5, 0x0101 => 0xf6, 0x015b => 0xf7, 0xef => 0xf8, + 0xd4 => 0xf9, 0xd9 => 0xfa, 0x2206 => 0xfb, 0xfe => 0xfc, + 0xb2 => 0xfd, 0xd6 => 0xfe, 0xb5 => 0xff, 0xec => 0x0100, + 0x0151 => 0x0101, 0x0118 => 0x0102, 0x0111 => 0x0103, 0xbe => 0x0104, + 0x015e => 0x0105, 0x013e => 0x0106, 0x0136 => 0x0107, 0x0139 => 0x0108, + 0x2122 => 0x0109, 0x0117 => 0x010a, 0xcc => 0x010b, 0x012a => 0x010c, + 0x013d => 0x010d, 0xbd => 0x010e, 0x2264 => 0x010f, 0xf4 => 0x0110, + 0xf1 => 0x0111, 0x0170 => 0x0112, 0xc9 => 0x0113, 0x0113 => 0x0114, + 0x011f => 0x0115, 0xbc => 0x0116, 0x0160 => 0x0117, 0x0218 => 0x0118, + 0x0150 => 0x0119, 0xb0 => 0x011a, 0xf2 => 0x011b, 0x010c => 0x011c, + 0xf9 => 0x011d, 0x221a => 0x011e, 0x010e => 0x011f, 0x0157 => 0x0120, + 0xd1 => 0x0121, 0xf5 => 0x0122, 0x0156 => 0x0123, 0x013b => 0x0124, + 0xc3 => 0x0125, 0x0104 => 0x0126, 0xc5 => 0x0127, 0xd5 => 0x0128, + 0x017c => 0x0129, 0x011a => 0x012a, 0x012e => 0x012b, 0x0137 => 0x012c, + 0x2212 => 0x012d, 0xce => 0x012e, 0x0148 => 0x012f, 0x0163 => 0x0130, + 0xac => 0x0131, 0xf6 => 0x0132, 0xfc => 0x0133, 0x2260 => 0x0134, + 0x0123 => 0x0135, 0xf0 => 0x0136, 0x017e => 0x0137, 0x0146 => 0x0138, + 0xb9 => 0x0139, 0x012b => 0x013a, 0x20ac => 0x013b); + // require_once 'Zend/Pdf/Cmap.php'; + $this->_cmap = Zend_Pdf_Cmap::cmapWithTypeData( + Zend_Pdf_Cmap::TYPE_BYTE_ENCODING_STATIC, $cmapData); + + + /* Resource dictionary */ + + /* The resource dictionary for the standard fonts is sparse because PDF + * viewers already have all of the metrics data. We only need to provide + * the font name and encoding method. + */ + $this->_resource->BaseFont = new Zend_Pdf_Element_Name('Courier-Bold'); + } +} diff --git a/library/Zend/Pdf/Resource/Font/Simple/Standard/CourierBoldOblique.php b/library/Zend/Pdf/Resource/Font/Simple/Standard/CourierBoldOblique.php new file mode 100644 index 0000000..42e0307 --- /dev/null +++ b/library/Zend/Pdf/Resource/Font/Simple/Standard/CourierBoldOblique.php @@ -0,0 +1,297 @@ +_fontNames[Zend_Pdf_Font::NAME_COPYRIGHT]['en'] = + "\x00\x43\x00\x6f\x00\x70\x00\x79\x00\x72\x00\x69\x00\x67\x00\x68\x00" + . "\x74\x00\x20\x00\x28\x00\x63\x00\x29\x00\x20\x00\x31\x00\x39\x00" + . "\x38\x00\x39\x00\x2c\x00\x20\x00\x31\x00\x39\x00\x39\x00\x30\x00" + . "\x2c\x00\x20\x00\x31\x00\x39\x00\x39\x00\x31\x00\x2c\x00\x20\x00" + . "\x31\x00\x39\x00\x39\x00\x33\x00\x2c\x00\x20\x00\x31\x00\x39\x00" + . "\x39\x00\x37\x00\x20\x00\x41\x00\x64\x00\x6f\x00\x62\x00\x65\x00" + . "\x20\x00\x53\x00\x79\x00\x73\x00\x74\x00\x65\x00\x6d\x00\x73\x00" + . "\x20\x00\x49\x00\x6e\x00\x63\x00\x6f\x00\x72\x00\x70\x00\x6f\x00" + . "\x72\x00\x61\x00\x74\x00\x65\x00\x64\x00\x2e\x00\x20\x00\x20\x00" + . "\x41\x00\x6c\x00\x6c\x00\x20\x00\x52\x00\x69\x00\x67\x00\x68\x00" + . "\x74\x00\x73\x00\x20\x00\x52\x00\x65\x00\x73\x00\x65\x00\x72\x00" + . "\x76\x00\x65\x00\x64\x00\x2e"; + $this->_fontNames[Zend_Pdf_Font::NAME_FAMILY]['en'] = + "\x00\x43\x00\x6f\x00\x75\x00\x72\x00\x69\x00\x65\x00\x72"; + $this->_fontNames[Zend_Pdf_Font::NAME_STYLE]['en'] = + "\x00\x42\x00\x6f\x00\x6c\x00\x64"; + $this->_fontNames[Zend_Pdf_Font::NAME_ID]['en'] = + "\x00\x34\x00\x33\x00\x30\x00\x34\x00\x39"; + $this->_fontNames[Zend_Pdf_Font::NAME_FULL]['en'] = + "\x00\x43\x00\x6f\x00\x75\x00\x72\x00\x69\x00\x65\x00\x72\x00\x2d\x00" + . "\x42\x00\x6f\x00\x6c\x00\x64\x00\x4f\x00\x62\x00\x6c\x00\x69\x00" + . "\x71\x00\x75\x00\x65\x00\x20\x00\x42\x00\x6f\x00\x6c\x00\x64"; + $this->_fontNames[Zend_Pdf_Font::NAME_VERSION]['en'] = + "\x00\x30\x00\x30\x00\x33\x00\x2e\x00\x30\x00\x30\x00\x30"; + $this->_fontNames[Zend_Pdf_Font::NAME_POSTSCRIPT]['en'] = + "\x00\x43\x00\x6f\x00\x75\x00\x72\x00\x69\x00\x65\x00\x72\x00\x2d\x00" + . "\x42\x00\x6f\x00\x6c\x00\x64\x00\x4f\x00\x62\x00\x6c\x00\x69\x00" + . "\x71\x00\x75\x00\x65"; + + $this->_isBold = true; + $this->_isItalic = true; + $this->_isMonospaced = true; + + $this->_underlinePosition = -100; + $this->_underlineThickness = 50; + $this->_strikePosition = 225; + $this->_strikeThickness = 50; + + $this->_unitsPerEm = 1000; + + $this->_ascent = 629; + $this->_descent = -157; + $this->_lineGap = 414; + + /* The glyph numbers assigned here are synthetic; they do not match the + * actual glyph numbers used by the font. This is not a big deal though + * since this data never makes it to the PDF file. It is only used + * internally for layout calculations. + */ + $this->_glyphWidths = array( + 0x00 => 0x01f4, 0x01 => 0x0258, 0x02 => 0x0258, 0x03 => 0x0258, + 0x04 => 0x0258, 0x05 => 0x0258, 0x06 => 0x0258, 0x07 => 0x0258, + 0x08 => 0x0258, 0x09 => 0x0258, 0x0a => 0x0258, 0x0b => 0x0258, + 0x0c => 0x0258, 0x0d => 0x0258, 0x0e => 0x0258, 0x0f => 0x0258, + 0x10 => 0x0258, 0x11 => 0x0258, 0x12 => 0x0258, 0x13 => 0x0258, + 0x14 => 0x0258, 0x15 => 0x0258, 0x16 => 0x0258, 0x17 => 0x0258, + 0x18 => 0x0258, 0x19 => 0x0258, 0x1a => 0x0258, 0x1b => 0x0258, + 0x1c => 0x0258, 0x1d => 0x0258, 0x1e => 0x0258, 0x1f => 0x0258, + 0x20 => 0x0258, 0x21 => 0x0258, 0x22 => 0x0258, 0x23 => 0x0258, + 0x24 => 0x0258, 0x25 => 0x0258, 0x26 => 0x0258, 0x27 => 0x0258, + 0x28 => 0x0258, 0x29 => 0x0258, 0x2a => 0x0258, 0x2b => 0x0258, + 0x2c => 0x0258, 0x2d => 0x0258, 0x2e => 0x0258, 0x2f => 0x0258, + 0x30 => 0x0258, 0x31 => 0x0258, 0x32 => 0x0258, 0x33 => 0x0258, + 0x34 => 0x0258, 0x35 => 0x0258, 0x36 => 0x0258, 0x37 => 0x0258, + 0x38 => 0x0258, 0x39 => 0x0258, 0x3a => 0x0258, 0x3b => 0x0258, + 0x3c => 0x0258, 0x3d => 0x0258, 0x3e => 0x0258, 0x3f => 0x0258, + 0x40 => 0x0258, 0x41 => 0x0258, 0x42 => 0x0258, 0x43 => 0x0258, + 0x44 => 0x0258, 0x45 => 0x0258, 0x46 => 0x0258, 0x47 => 0x0258, + 0x48 => 0x0258, 0x49 => 0x0258, 0x4a => 0x0258, 0x4b => 0x0258, + 0x4c => 0x0258, 0x4d => 0x0258, 0x4e => 0x0258, 0x4f => 0x0258, + 0x50 => 0x0258, 0x51 => 0x0258, 0x52 => 0x0258, 0x53 => 0x0258, + 0x54 => 0x0258, 0x55 => 0x0258, 0x56 => 0x0258, 0x57 => 0x0258, + 0x58 => 0x0258, 0x59 => 0x0258, 0x5a => 0x0258, 0x5b => 0x0258, + 0x5c => 0x0258, 0x5d => 0x0258, 0x5e => 0x0258, 0x5f => 0x0258, + 0x60 => 0x0258, 0x61 => 0x0258, 0x62 => 0x0258, 0x63 => 0x0258, + 0x64 => 0x0258, 0x65 => 0x0258, 0x66 => 0x0258, 0x67 => 0x0258, + 0x68 => 0x0258, 0x69 => 0x0258, 0x6a => 0x0258, 0x6b => 0x0258, + 0x6c => 0x0258, 0x6d => 0x0258, 0x6e => 0x0258, 0x6f => 0x0258, + 0x70 => 0x0258, 0x71 => 0x0258, 0x72 => 0x0258, 0x73 => 0x0258, + 0x74 => 0x0258, 0x75 => 0x0258, 0x76 => 0x0258, 0x77 => 0x0258, + 0x78 => 0x0258, 0x79 => 0x0258, 0x7a => 0x0258, 0x7b => 0x0258, + 0x7c => 0x0258, 0x7d => 0x0258, 0x7e => 0x0258, 0x7f => 0x0258, + 0x80 => 0x0258, 0x81 => 0x0258, 0x82 => 0x0258, 0x83 => 0x0258, + 0x84 => 0x0258, 0x85 => 0x0258, 0x86 => 0x0258, 0x87 => 0x0258, + 0x88 => 0x0258, 0x89 => 0x0258, 0x8a => 0x0258, 0x8b => 0x0258, + 0x8c => 0x0258, 0x8d => 0x0258, 0x8e => 0x0258, 0x8f => 0x0258, + 0x90 => 0x0258, 0x91 => 0x0258, 0x92 => 0x0258, 0x93 => 0x0258, + 0x94 => 0x0258, 0x95 => 0x0258, 0x96 => 0x0258, 0x97 => 0x0258, + 0x98 => 0x0258, 0x99 => 0x0258, 0x9a => 0x0258, 0x9b => 0x0258, + 0x9c => 0x0258, 0x9d => 0x0258, 0x9e => 0x0258, 0x9f => 0x0258, + 0xa0 => 0x0258, 0xa1 => 0x0258, 0xa2 => 0x0258, 0xa3 => 0x0258, + 0xa4 => 0x0258, 0xa5 => 0x0258, 0xa6 => 0x0258, 0xa7 => 0x0258, + 0xa8 => 0x0258, 0xa9 => 0x0258, 0xaa => 0x0258, 0xab => 0x0258, + 0xac => 0x0258, 0xad => 0x0258, 0xae => 0x0258, 0xaf => 0x0258, + 0xb0 => 0x0258, 0xb1 => 0x0258, 0xb2 => 0x0258, 0xb3 => 0x0258, + 0xb4 => 0x0258, 0xb5 => 0x0258, 0xb6 => 0x0258, 0xb7 => 0x0258, + 0xb8 => 0x0258, 0xb9 => 0x0258, 0xba => 0x0258, 0xbb => 0x0258, + 0xbc => 0x0258, 0xbd => 0x0258, 0xbe => 0x0258, 0xbf => 0x0258, + 0xc0 => 0x0258, 0xc1 => 0x0258, 0xc2 => 0x0258, 0xc3 => 0x0258, + 0xc4 => 0x0258, 0xc5 => 0x0258, 0xc6 => 0x0258, 0xc7 => 0x0258, + 0xc8 => 0x0258, 0xc9 => 0x0258, 0xca => 0x0258, 0xcb => 0x0258, + 0xcc => 0x0258, 0xcd => 0x0258, 0xce => 0x0258, 0xcf => 0x0258, + 0xd0 => 0x0258, 0xd1 => 0x0258, 0xd2 => 0x0258, 0xd3 => 0x0258, + 0xd4 => 0x0258, 0xd5 => 0x0258, 0xd6 => 0x0258, 0xd7 => 0x0258, + 0xd8 => 0x0258, 0xd9 => 0x0258, 0xda => 0x0258, 0xdb => 0x0258, + 0xdc => 0x0258, 0xdd => 0x0258, 0xde => 0x0258, 0xdf => 0x0258, + 0xe0 => 0x0258, 0xe1 => 0x0258, 0xe2 => 0x0258, 0xe3 => 0x0258, + 0xe4 => 0x0258, 0xe5 => 0x0258, 0xe6 => 0x0258, 0xe7 => 0x0258, + 0xe8 => 0x0258, 0xe9 => 0x0258, 0xea => 0x0258, 0xeb => 0x0258, + 0xec => 0x0258, 0xed => 0x0258, 0xee => 0x0258, 0xef => 0x0258, + 0xf0 => 0x0258, 0xf1 => 0x0258, 0xf2 => 0x0258, 0xf3 => 0x0258, + 0xf4 => 0x0258, 0xf5 => 0x0258, 0xf6 => 0x0258, 0xf7 => 0x0258, + 0xf8 => 0x0258, 0xf9 => 0x0258, 0xfa => 0x0258, 0xfb => 0x0258, + 0xfc => 0x0258, 0xfd => 0x0258, 0xfe => 0x0258, 0xff => 0x0258, + 0x0100 => 0x0258, 0x0101 => 0x0258, 0x0102 => 0x0258, 0x0103 => 0x0258, + 0x0104 => 0x0258, 0x0105 => 0x0258, 0x0106 => 0x0258, 0x0107 => 0x0258, + 0x0108 => 0x0258, 0x0109 => 0x0258, 0x010a => 0x0258, 0x010b => 0x0258, + 0x010c => 0x0258, 0x010d => 0x0258, 0x010e => 0x0258, 0x010f => 0x0258, + 0x0110 => 0x0258, 0x0111 => 0x0258, 0x0112 => 0x0258, 0x0113 => 0x0258, + 0x0114 => 0x0258, 0x0115 => 0x0258, 0x0116 => 0x0258, 0x0117 => 0x0258, + 0x0118 => 0x0258, 0x0119 => 0x0258, 0x011a => 0x0258, 0x011b => 0x0258, + 0x011c => 0x0258, 0x011d => 0x0258, 0x011e => 0x0258, 0x011f => 0x0258, + 0x0120 => 0x0258, 0x0121 => 0x0258, 0x0122 => 0x0258, 0x0123 => 0x0258, + 0x0124 => 0x0258, 0x0125 => 0x0258, 0x0126 => 0x0258, 0x0127 => 0x0258, + 0x0128 => 0x0258, 0x0129 => 0x0258, 0x012a => 0x0258, 0x012b => 0x0258, + 0x012c => 0x0258, 0x012d => 0x0258, 0x012e => 0x0258, 0x012f => 0x0258, + 0x0130 => 0x0258, 0x0131 => 0x0258, 0x0132 => 0x0258, 0x0133 => 0x0258, + 0x0134 => 0x0258, 0x0135 => 0x0258, 0x0136 => 0x0258, 0x0137 => 0x0258, + 0x0138 => 0x0258, 0x0139 => 0x0258, 0x013a => 0x0258, 0x013b => 0x0258, + ); + + /* The cmap table is similarly synthesized. + */ + $cmapData = array( + 0x20 => 0x01, 0x21 => 0x02, 0x22 => 0x03, 0x23 => 0x04, + 0x24 => 0x05, 0x25 => 0x06, 0x26 => 0x07, 0x2019 => 0x08, + 0x28 => 0x09, 0x29 => 0x0a, 0x2a => 0x0b, 0x2b => 0x0c, + 0x2c => 0x0d, 0x2d => 0x0e, 0x2e => 0x0f, 0x2f => 0x10, + 0x30 => 0x11, 0x31 => 0x12, 0x32 => 0x13, 0x33 => 0x14, + 0x34 => 0x15, 0x35 => 0x16, 0x36 => 0x17, 0x37 => 0x18, + 0x38 => 0x19, 0x39 => 0x1a, 0x3a => 0x1b, 0x3b => 0x1c, + 0x3c => 0x1d, 0x3d => 0x1e, 0x3e => 0x1f, 0x3f => 0x20, + 0x40 => 0x21, 0x41 => 0x22, 0x42 => 0x23, 0x43 => 0x24, + 0x44 => 0x25, 0x45 => 0x26, 0x46 => 0x27, 0x47 => 0x28, + 0x48 => 0x29, 0x49 => 0x2a, 0x4a => 0x2b, 0x4b => 0x2c, + 0x4c => 0x2d, 0x4d => 0x2e, 0x4e => 0x2f, 0x4f => 0x30, + 0x50 => 0x31, 0x51 => 0x32, 0x52 => 0x33, 0x53 => 0x34, + 0x54 => 0x35, 0x55 => 0x36, 0x56 => 0x37, 0x57 => 0x38, + 0x58 => 0x39, 0x59 => 0x3a, 0x5a => 0x3b, 0x5b => 0x3c, + 0x5c => 0x3d, 0x5d => 0x3e, 0x5e => 0x3f, 0x5f => 0x40, + 0x2018 => 0x41, 0x61 => 0x42, 0x62 => 0x43, 0x63 => 0x44, + 0x64 => 0x45, 0x65 => 0x46, 0x66 => 0x47, 0x67 => 0x48, + 0x68 => 0x49, 0x69 => 0x4a, 0x6a => 0x4b, 0x6b => 0x4c, + 0x6c => 0x4d, 0x6d => 0x4e, 0x6e => 0x4f, 0x6f => 0x50, + 0x70 => 0x51, 0x71 => 0x52, 0x72 => 0x53, 0x73 => 0x54, + 0x74 => 0x55, 0x75 => 0x56, 0x76 => 0x57, 0x77 => 0x58, + 0x78 => 0x59, 0x79 => 0x5a, 0x7a => 0x5b, 0x7b => 0x5c, + 0x7c => 0x5d, 0x7d => 0x5e, 0x7e => 0x5f, 0xa1 => 0x60, + 0xa2 => 0x61, 0xa3 => 0x62, 0x2044 => 0x63, 0xa5 => 0x64, + 0x0192 => 0x65, 0xa7 => 0x66, 0xa4 => 0x67, 0x27 => 0x68, + 0x201c => 0x69, 0xab => 0x6a, 0x2039 => 0x6b, 0x203a => 0x6c, + 0xfb01 => 0x6d, 0xfb02 => 0x6e, 0x2013 => 0x6f, 0x2020 => 0x70, + 0x2021 => 0x71, 0xb7 => 0x72, 0xb6 => 0x73, 0x2022 => 0x74, + 0x201a => 0x75, 0x201e => 0x76, 0x201d => 0x77, 0xbb => 0x78, + 0x2026 => 0x79, 0x2030 => 0x7a, 0xbf => 0x7b, 0x60 => 0x7c, + 0xb4 => 0x7d, 0x02c6 => 0x7e, 0x02dc => 0x7f, 0xaf => 0x80, + 0x02d8 => 0x81, 0x02d9 => 0x82, 0xa8 => 0x83, 0x02da => 0x84, + 0xb8 => 0x85, 0x02dd => 0x86, 0x02db => 0x87, 0x02c7 => 0x88, + 0x2014 => 0x89, 0xc6 => 0x8a, 0xaa => 0x8b, 0x0141 => 0x8c, + 0xd8 => 0x8d, 0x0152 => 0x8e, 0xba => 0x8f, 0xe6 => 0x90, + 0x0131 => 0x91, 0x0142 => 0x92, 0xf8 => 0x93, 0x0153 => 0x94, + 0xdf => 0x95, 0xcf => 0x96, 0xe9 => 0x97, 0x0103 => 0x98, + 0x0171 => 0x99, 0x011b => 0x9a, 0x0178 => 0x9b, 0xf7 => 0x9c, + 0xdd => 0x9d, 0xc2 => 0x9e, 0xe1 => 0x9f, 0xdb => 0xa0, + 0xfd => 0xa1, 0x0219 => 0xa2, 0xea => 0xa3, 0x016e => 0xa4, + 0xdc => 0xa5, 0x0105 => 0xa6, 0xda => 0xa7, 0x0173 => 0xa8, + 0xcb => 0xa9, 0x0110 => 0xaa, 0xf6c3 => 0xab, 0xa9 => 0xac, + 0x0112 => 0xad, 0x010d => 0xae, 0xe5 => 0xaf, 0x0145 => 0xb0, + 0x013a => 0xb1, 0xe0 => 0xb2, 0x0162 => 0xb3, 0x0106 => 0xb4, + 0xe3 => 0xb5, 0x0116 => 0xb6, 0x0161 => 0xb7, 0x015f => 0xb8, + 0xed => 0xb9, 0x25ca => 0xba, 0x0158 => 0xbb, 0x0122 => 0xbc, + 0xfb => 0xbd, 0xe2 => 0xbe, 0x0100 => 0xbf, 0x0159 => 0xc0, + 0xe7 => 0xc1, 0x017b => 0xc2, 0xde => 0xc3, 0x014c => 0xc4, + 0x0154 => 0xc5, 0x015a => 0xc6, 0x010f => 0xc7, 0x016a => 0xc8, + 0x016f => 0xc9, 0xb3 => 0xca, 0xd2 => 0xcb, 0xc0 => 0xcc, + 0x0102 => 0xcd, 0xd7 => 0xce, 0xfa => 0xcf, 0x0164 => 0xd0, + 0x2202 => 0xd1, 0xff => 0xd2, 0x0143 => 0xd3, 0xee => 0xd4, + 0xca => 0xd5, 0xe4 => 0xd6, 0xeb => 0xd7, 0x0107 => 0xd8, + 0x0144 => 0xd9, 0x016b => 0xda, 0x0147 => 0xdb, 0xcd => 0xdc, + 0xb1 => 0xdd, 0xa6 => 0xde, 0xae => 0xdf, 0x011e => 0xe0, + 0x0130 => 0xe1, 0x2211 => 0xe2, 0xc8 => 0xe3, 0x0155 => 0xe4, + 0x014d => 0xe5, 0x0179 => 0xe6, 0x017d => 0xe7, 0x2265 => 0xe8, + 0xd0 => 0xe9, 0xc7 => 0xea, 0x013c => 0xeb, 0x0165 => 0xec, + 0x0119 => 0xed, 0x0172 => 0xee, 0xc1 => 0xef, 0xc4 => 0xf0, + 0xe8 => 0xf1, 0x017a => 0xf2, 0x012f => 0xf3, 0xd3 => 0xf4, + 0xf3 => 0xf5, 0x0101 => 0xf6, 0x015b => 0xf7, 0xef => 0xf8, + 0xd4 => 0xf9, 0xd9 => 0xfa, 0x2206 => 0xfb, 0xfe => 0xfc, + 0xb2 => 0xfd, 0xd6 => 0xfe, 0xb5 => 0xff, 0xec => 0x0100, + 0x0151 => 0x0101, 0x0118 => 0x0102, 0x0111 => 0x0103, 0xbe => 0x0104, + 0x015e => 0x0105, 0x013e => 0x0106, 0x0136 => 0x0107, 0x0139 => 0x0108, + 0x2122 => 0x0109, 0x0117 => 0x010a, 0xcc => 0x010b, 0x012a => 0x010c, + 0x013d => 0x010d, 0xbd => 0x010e, 0x2264 => 0x010f, 0xf4 => 0x0110, + 0xf1 => 0x0111, 0x0170 => 0x0112, 0xc9 => 0x0113, 0x0113 => 0x0114, + 0x011f => 0x0115, 0xbc => 0x0116, 0x0160 => 0x0117, 0x0218 => 0x0118, + 0x0150 => 0x0119, 0xb0 => 0x011a, 0xf2 => 0x011b, 0x010c => 0x011c, + 0xf9 => 0x011d, 0x221a => 0x011e, 0x010e => 0x011f, 0x0157 => 0x0120, + 0xd1 => 0x0121, 0xf5 => 0x0122, 0x0156 => 0x0123, 0x013b => 0x0124, + 0xc3 => 0x0125, 0x0104 => 0x0126, 0xc5 => 0x0127, 0xd5 => 0x0128, + 0x017c => 0x0129, 0x011a => 0x012a, 0x012e => 0x012b, 0x0137 => 0x012c, + 0x2212 => 0x012d, 0xce => 0x012e, 0x0148 => 0x012f, 0x0163 => 0x0130, + 0xac => 0x0131, 0xf6 => 0x0132, 0xfc => 0x0133, 0x2260 => 0x0134, + 0x0123 => 0x0135, 0xf0 => 0x0136, 0x017e => 0x0137, 0x0146 => 0x0138, + 0xb9 => 0x0139, 0x012b => 0x013a, 0x20ac => 0x013b); + // require_once 'Zend/Pdf/Cmap.php'; + $this->_cmap = Zend_Pdf_Cmap::cmapWithTypeData( + Zend_Pdf_Cmap::TYPE_BYTE_ENCODING_STATIC, $cmapData); + + + /* Resource dictionary */ + + /* The resource dictionary for the standard fonts is sparse because PDF + * viewers already have all of the metrics data. We only need to provide + * the font name and encoding method. + */ + $this->_resource->BaseFont = new Zend_Pdf_Element_Name('Courier-BoldOblique'); + } +} diff --git a/library/Zend/Pdf/Resource/Font/Simple/Standard/CourierOblique.php b/library/Zend/Pdf/Resource/Font/Simple/Standard/CourierOblique.php new file mode 100644 index 0000000..6f1abfa --- /dev/null +++ b/library/Zend/Pdf/Resource/Font/Simple/Standard/CourierOblique.php @@ -0,0 +1,297 @@ +_fontNames[Zend_Pdf_Font::NAME_COPYRIGHT]['en'] = + "\x00\x43\x00\x6f\x00\x70\x00\x79\x00\x72\x00\x69\x00\x67\x00\x68\x00" + . "\x74\x00\x20\x00\x28\x00\x63\x00\x29\x00\x20\x00\x31\x00\x39\x00" + . "\x38\x00\x39\x00\x2c\x00\x20\x00\x31\x00\x39\x00\x39\x00\x30\x00" + . "\x2c\x00\x20\x00\x31\x00\x39\x00\x39\x00\x31\x00\x2c\x00\x20\x00" + . "\x31\x00\x39\x00\x39\x00\x32\x00\x2c\x00\x20\x00\x31\x00\x39\x00" + . "\x39\x00\x33\x00\x2c\x00\x20\x00\x31\x00\x39\x00\x39\x00\x37\x00" + . "\x20\x00\x41\x00\x64\x00\x6f\x00\x62\x00\x65\x00\x20\x00\x53\x00" + . "\x79\x00\x73\x00\x74\x00\x65\x00\x6d\x00\x73\x00\x20\x00\x49\x00" + . "\x6e\x00\x63\x00\x6f\x00\x72\x00\x70\x00\x6f\x00\x72\x00\x61\x00" + . "\x74\x00\x65\x00\x64\x00\x2e\x00\x20\x00\x20\x00\x41\x00\x6c\x00" + . "\x6c\x00\x20\x00\x52\x00\x69\x00\x67\x00\x68\x00\x74\x00\x73\x00" + . "\x20\x00\x52\x00\x65\x00\x73\x00\x65\x00\x72\x00\x76\x00\x65\x00" + . "\x64\x00\x2e"; + $this->_fontNames[Zend_Pdf_Font::NAME_FAMILY]['en'] = + "\x00\x43\x00\x6f\x00\x75\x00\x72\x00\x69\x00\x65\x00\x72"; + $this->_fontNames[Zend_Pdf_Font::NAME_STYLE]['en'] = + "\x00\x4d\x00\x65\x00\x64\x00\x69\x00\x75\x00\x6d"; + $this->_fontNames[Zend_Pdf_Font::NAME_ID]['en'] = + "\x00\x34\x00\x33\x00\x30\x00\x35\x00\x31"; + $this->_fontNames[Zend_Pdf_Font::NAME_FULL]['en'] = + "\x00\x43\x00\x6f\x00\x75\x00\x72\x00\x69\x00\x65\x00\x72\x00\x2d\x00" + . "\x4f\x00\x62\x00\x6c\x00\x69\x00\x71\x00\x75\x00\x65\x00\x20\x00" + . "\x4d\x00\x65\x00\x64\x00\x69\x00\x75\x00\x6d"; + $this->_fontNames[Zend_Pdf_Font::NAME_VERSION]['en'] = + "\x00\x30\x00\x30\x00\x33\x00\x2e\x00\x30\x00\x30\x00\x30"; + $this->_fontNames[Zend_Pdf_Font::NAME_POSTSCRIPT]['en'] = + "\x00\x43\x00\x6f\x00\x75\x00\x72\x00\x69\x00\x65\x00\x72\x00\x2d\x00" + . "\x4f\x00\x62\x00\x6c\x00\x69\x00\x71\x00\x75\x00\x65"; + + $this->_isBold = false; + $this->_isItalic = true; + $this->_isMonospaced = true; + + $this->_underlinePosition = -100; + $this->_underlineThickness = 50; + $this->_strikePosition = 225; + $this->_strikeThickness = 50; + + $this->_unitsPerEm = 1000; + + $this->_ascent = 629; + $this->_descent = -157; + $this->_lineGap = 414; + + /* The glyph numbers assigned here are synthetic; they do not match the + * actual glyph numbers used by the font. This is not a big deal though + * since this data never makes it to the PDF file. It is only used + * internally for layout calculations. + */ + $this->_glyphWidths = array( + 0x00 => 0x01f4, 0x01 => 0x0258, 0x02 => 0x0258, 0x03 => 0x0258, + 0x04 => 0x0258, 0x05 => 0x0258, 0x06 => 0x0258, 0x07 => 0x0258, + 0x08 => 0x0258, 0x09 => 0x0258, 0x0a => 0x0258, 0x0b => 0x0258, + 0x0c => 0x0258, 0x0d => 0x0258, 0x0e => 0x0258, 0x0f => 0x0258, + 0x10 => 0x0258, 0x11 => 0x0258, 0x12 => 0x0258, 0x13 => 0x0258, + 0x14 => 0x0258, 0x15 => 0x0258, 0x16 => 0x0258, 0x17 => 0x0258, + 0x18 => 0x0258, 0x19 => 0x0258, 0x1a => 0x0258, 0x1b => 0x0258, + 0x1c => 0x0258, 0x1d => 0x0258, 0x1e => 0x0258, 0x1f => 0x0258, + 0x20 => 0x0258, 0x21 => 0x0258, 0x22 => 0x0258, 0x23 => 0x0258, + 0x24 => 0x0258, 0x25 => 0x0258, 0x26 => 0x0258, 0x27 => 0x0258, + 0x28 => 0x0258, 0x29 => 0x0258, 0x2a => 0x0258, 0x2b => 0x0258, + 0x2c => 0x0258, 0x2d => 0x0258, 0x2e => 0x0258, 0x2f => 0x0258, + 0x30 => 0x0258, 0x31 => 0x0258, 0x32 => 0x0258, 0x33 => 0x0258, + 0x34 => 0x0258, 0x35 => 0x0258, 0x36 => 0x0258, 0x37 => 0x0258, + 0x38 => 0x0258, 0x39 => 0x0258, 0x3a => 0x0258, 0x3b => 0x0258, + 0x3c => 0x0258, 0x3d => 0x0258, 0x3e => 0x0258, 0x3f => 0x0258, + 0x40 => 0x0258, 0x41 => 0x0258, 0x42 => 0x0258, 0x43 => 0x0258, + 0x44 => 0x0258, 0x45 => 0x0258, 0x46 => 0x0258, 0x47 => 0x0258, + 0x48 => 0x0258, 0x49 => 0x0258, 0x4a => 0x0258, 0x4b => 0x0258, + 0x4c => 0x0258, 0x4d => 0x0258, 0x4e => 0x0258, 0x4f => 0x0258, + 0x50 => 0x0258, 0x51 => 0x0258, 0x52 => 0x0258, 0x53 => 0x0258, + 0x54 => 0x0258, 0x55 => 0x0258, 0x56 => 0x0258, 0x57 => 0x0258, + 0x58 => 0x0258, 0x59 => 0x0258, 0x5a => 0x0258, 0x5b => 0x0258, + 0x5c => 0x0258, 0x5d => 0x0258, 0x5e => 0x0258, 0x5f => 0x0258, + 0x60 => 0x0258, 0x61 => 0x0258, 0x62 => 0x0258, 0x63 => 0x0258, + 0x64 => 0x0258, 0x65 => 0x0258, 0x66 => 0x0258, 0x67 => 0x0258, + 0x68 => 0x0258, 0x69 => 0x0258, 0x6a => 0x0258, 0x6b => 0x0258, + 0x6c => 0x0258, 0x6d => 0x0258, 0x6e => 0x0258, 0x6f => 0x0258, + 0x70 => 0x0258, 0x71 => 0x0258, 0x72 => 0x0258, 0x73 => 0x0258, + 0x74 => 0x0258, 0x75 => 0x0258, 0x76 => 0x0258, 0x77 => 0x0258, + 0x78 => 0x0258, 0x79 => 0x0258, 0x7a => 0x0258, 0x7b => 0x0258, + 0x7c => 0x0258, 0x7d => 0x0258, 0x7e => 0x0258, 0x7f => 0x0258, + 0x80 => 0x0258, 0x81 => 0x0258, 0x82 => 0x0258, 0x83 => 0x0258, + 0x84 => 0x0258, 0x85 => 0x0258, 0x86 => 0x0258, 0x87 => 0x0258, + 0x88 => 0x0258, 0x89 => 0x0258, 0x8a => 0x0258, 0x8b => 0x0258, + 0x8c => 0x0258, 0x8d => 0x0258, 0x8e => 0x0258, 0x8f => 0x0258, + 0x90 => 0x0258, 0x91 => 0x0258, 0x92 => 0x0258, 0x93 => 0x0258, + 0x94 => 0x0258, 0x95 => 0x0258, 0x96 => 0x0258, 0x97 => 0x0258, + 0x98 => 0x0258, 0x99 => 0x0258, 0x9a => 0x0258, 0x9b => 0x0258, + 0x9c => 0x0258, 0x9d => 0x0258, 0x9e => 0x0258, 0x9f => 0x0258, + 0xa0 => 0x0258, 0xa1 => 0x0258, 0xa2 => 0x0258, 0xa3 => 0x0258, + 0xa4 => 0x0258, 0xa5 => 0x0258, 0xa6 => 0x0258, 0xa7 => 0x0258, + 0xa8 => 0x0258, 0xa9 => 0x0258, 0xaa => 0x0258, 0xab => 0x0258, + 0xac => 0x0258, 0xad => 0x0258, 0xae => 0x0258, 0xaf => 0x0258, + 0xb0 => 0x0258, 0xb1 => 0x0258, 0xb2 => 0x0258, 0xb3 => 0x0258, + 0xb4 => 0x0258, 0xb5 => 0x0258, 0xb6 => 0x0258, 0xb7 => 0x0258, + 0xb8 => 0x0258, 0xb9 => 0x0258, 0xba => 0x0258, 0xbb => 0x0258, + 0xbc => 0x0258, 0xbd => 0x0258, 0xbe => 0x0258, 0xbf => 0x0258, + 0xc0 => 0x0258, 0xc1 => 0x0258, 0xc2 => 0x0258, 0xc3 => 0x0258, + 0xc4 => 0x0258, 0xc5 => 0x0258, 0xc6 => 0x0258, 0xc7 => 0x0258, + 0xc8 => 0x0258, 0xc9 => 0x0258, 0xca => 0x0258, 0xcb => 0x0258, + 0xcc => 0x0258, 0xcd => 0x0258, 0xce => 0x0258, 0xcf => 0x0258, + 0xd0 => 0x0258, 0xd1 => 0x0258, 0xd2 => 0x0258, 0xd3 => 0x0258, + 0xd4 => 0x0258, 0xd5 => 0x0258, 0xd6 => 0x0258, 0xd7 => 0x0258, + 0xd8 => 0x0258, 0xd9 => 0x0258, 0xda => 0x0258, 0xdb => 0x0258, + 0xdc => 0x0258, 0xdd => 0x0258, 0xde => 0x0258, 0xdf => 0x0258, + 0xe0 => 0x0258, 0xe1 => 0x0258, 0xe2 => 0x0258, 0xe3 => 0x0258, + 0xe4 => 0x0258, 0xe5 => 0x0258, 0xe6 => 0x0258, 0xe7 => 0x0258, + 0xe8 => 0x0258, 0xe9 => 0x0258, 0xea => 0x0258, 0xeb => 0x0258, + 0xec => 0x0258, 0xed => 0x0258, 0xee => 0x0258, 0xef => 0x0258, + 0xf0 => 0x0258, 0xf1 => 0x0258, 0xf2 => 0x0258, 0xf3 => 0x0258, + 0xf4 => 0x0258, 0xf5 => 0x0258, 0xf6 => 0x0258, 0xf7 => 0x0258, + 0xf8 => 0x0258, 0xf9 => 0x0258, 0xfa => 0x0258, 0xfb => 0x0258, + 0xfc => 0x0258, 0xfd => 0x0258, 0xfe => 0x0258, 0xff => 0x0258, + 0x0100 => 0x0258, 0x0101 => 0x0258, 0x0102 => 0x0258, 0x0103 => 0x0258, + 0x0104 => 0x0258, 0x0105 => 0x0258, 0x0106 => 0x0258, 0x0107 => 0x0258, + 0x0108 => 0x0258, 0x0109 => 0x0258, 0x010a => 0x0258, 0x010b => 0x0258, + 0x010c => 0x0258, 0x010d => 0x0258, 0x010e => 0x0258, 0x010f => 0x0258, + 0x0110 => 0x0258, 0x0111 => 0x0258, 0x0112 => 0x0258, 0x0113 => 0x0258, + 0x0114 => 0x0258, 0x0115 => 0x0258, 0x0116 => 0x0258, 0x0117 => 0x0258, + 0x0118 => 0x0258, 0x0119 => 0x0258, 0x011a => 0x0258, 0x011b => 0x0258, + 0x011c => 0x0258, 0x011d => 0x0258, 0x011e => 0x0258, 0x011f => 0x0258, + 0x0120 => 0x0258, 0x0121 => 0x0258, 0x0122 => 0x0258, 0x0123 => 0x0258, + 0x0124 => 0x0258, 0x0125 => 0x0258, 0x0126 => 0x0258, 0x0127 => 0x0258, + 0x0128 => 0x0258, 0x0129 => 0x0258, 0x012a => 0x0258, 0x012b => 0x0258, + 0x012c => 0x0258, 0x012d => 0x0258, 0x012e => 0x0258, 0x012f => 0x0258, + 0x0130 => 0x0258, 0x0131 => 0x0258, 0x0132 => 0x0258, 0x0133 => 0x0258, + 0x0134 => 0x0258, 0x0135 => 0x0258, 0x0136 => 0x0258, 0x0137 => 0x0258, + 0x0138 => 0x0258, 0x0139 => 0x0258, 0x013a => 0x0258, 0x013b => 0x0258, + ); + + /* The cmap table is similarly synthesized. + */ + $cmapData = array( + 0x20 => 0x01, 0x21 => 0x02, 0x22 => 0x03, 0x23 => 0x04, + 0x24 => 0x05, 0x25 => 0x06, 0x26 => 0x07, 0x2019 => 0x08, + 0x28 => 0x09, 0x29 => 0x0a, 0x2a => 0x0b, 0x2b => 0x0c, + 0x2c => 0x0d, 0x2d => 0x0e, 0x2e => 0x0f, 0x2f => 0x10, + 0x30 => 0x11, 0x31 => 0x12, 0x32 => 0x13, 0x33 => 0x14, + 0x34 => 0x15, 0x35 => 0x16, 0x36 => 0x17, 0x37 => 0x18, + 0x38 => 0x19, 0x39 => 0x1a, 0x3a => 0x1b, 0x3b => 0x1c, + 0x3c => 0x1d, 0x3d => 0x1e, 0x3e => 0x1f, 0x3f => 0x20, + 0x40 => 0x21, 0x41 => 0x22, 0x42 => 0x23, 0x43 => 0x24, + 0x44 => 0x25, 0x45 => 0x26, 0x46 => 0x27, 0x47 => 0x28, + 0x48 => 0x29, 0x49 => 0x2a, 0x4a => 0x2b, 0x4b => 0x2c, + 0x4c => 0x2d, 0x4d => 0x2e, 0x4e => 0x2f, 0x4f => 0x30, + 0x50 => 0x31, 0x51 => 0x32, 0x52 => 0x33, 0x53 => 0x34, + 0x54 => 0x35, 0x55 => 0x36, 0x56 => 0x37, 0x57 => 0x38, + 0x58 => 0x39, 0x59 => 0x3a, 0x5a => 0x3b, 0x5b => 0x3c, + 0x5c => 0x3d, 0x5d => 0x3e, 0x5e => 0x3f, 0x5f => 0x40, + 0x2018 => 0x41, 0x61 => 0x42, 0x62 => 0x43, 0x63 => 0x44, + 0x64 => 0x45, 0x65 => 0x46, 0x66 => 0x47, 0x67 => 0x48, + 0x68 => 0x49, 0x69 => 0x4a, 0x6a => 0x4b, 0x6b => 0x4c, + 0x6c => 0x4d, 0x6d => 0x4e, 0x6e => 0x4f, 0x6f => 0x50, + 0x70 => 0x51, 0x71 => 0x52, 0x72 => 0x53, 0x73 => 0x54, + 0x74 => 0x55, 0x75 => 0x56, 0x76 => 0x57, 0x77 => 0x58, + 0x78 => 0x59, 0x79 => 0x5a, 0x7a => 0x5b, 0x7b => 0x5c, + 0x7c => 0x5d, 0x7d => 0x5e, 0x7e => 0x5f, 0xa1 => 0x60, + 0xa2 => 0x61, 0xa3 => 0x62, 0x2044 => 0x63, 0xa5 => 0x64, + 0x0192 => 0x65, 0xa7 => 0x66, 0xa4 => 0x67, 0x27 => 0x68, + 0x201c => 0x69, 0xab => 0x6a, 0x2039 => 0x6b, 0x203a => 0x6c, + 0xfb01 => 0x6d, 0xfb02 => 0x6e, 0x2013 => 0x6f, 0x2020 => 0x70, + 0x2021 => 0x71, 0xb7 => 0x72, 0xb6 => 0x73, 0x2022 => 0x74, + 0x201a => 0x75, 0x201e => 0x76, 0x201d => 0x77, 0xbb => 0x78, + 0x2026 => 0x79, 0x2030 => 0x7a, 0xbf => 0x7b, 0x60 => 0x7c, + 0xb4 => 0x7d, 0x02c6 => 0x7e, 0x02dc => 0x7f, 0xaf => 0x80, + 0x02d8 => 0x81, 0x02d9 => 0x82, 0xa8 => 0x83, 0x02da => 0x84, + 0xb8 => 0x85, 0x02dd => 0x86, 0x02db => 0x87, 0x02c7 => 0x88, + 0x2014 => 0x89, 0xc6 => 0x8a, 0xaa => 0x8b, 0x0141 => 0x8c, + 0xd8 => 0x8d, 0x0152 => 0x8e, 0xba => 0x8f, 0xe6 => 0x90, + 0x0131 => 0x91, 0x0142 => 0x92, 0xf8 => 0x93, 0x0153 => 0x94, + 0xdf => 0x95, 0xcf => 0x96, 0xe9 => 0x97, 0x0103 => 0x98, + 0x0171 => 0x99, 0x011b => 0x9a, 0x0178 => 0x9b, 0xf7 => 0x9c, + 0xdd => 0x9d, 0xc2 => 0x9e, 0xe1 => 0x9f, 0xdb => 0xa0, + 0xfd => 0xa1, 0x0219 => 0xa2, 0xea => 0xa3, 0x016e => 0xa4, + 0xdc => 0xa5, 0x0105 => 0xa6, 0xda => 0xa7, 0x0173 => 0xa8, + 0xcb => 0xa9, 0x0110 => 0xaa, 0xf6c3 => 0xab, 0xa9 => 0xac, + 0x0112 => 0xad, 0x010d => 0xae, 0xe5 => 0xaf, 0x0145 => 0xb0, + 0x013a => 0xb1, 0xe0 => 0xb2, 0x0162 => 0xb3, 0x0106 => 0xb4, + 0xe3 => 0xb5, 0x0116 => 0xb6, 0x0161 => 0xb7, 0x015f => 0xb8, + 0xed => 0xb9, 0x25ca => 0xba, 0x0158 => 0xbb, 0x0122 => 0xbc, + 0xfb => 0xbd, 0xe2 => 0xbe, 0x0100 => 0xbf, 0x0159 => 0xc0, + 0xe7 => 0xc1, 0x017b => 0xc2, 0xde => 0xc3, 0x014c => 0xc4, + 0x0154 => 0xc5, 0x015a => 0xc6, 0x010f => 0xc7, 0x016a => 0xc8, + 0x016f => 0xc9, 0xb3 => 0xca, 0xd2 => 0xcb, 0xc0 => 0xcc, + 0x0102 => 0xcd, 0xd7 => 0xce, 0xfa => 0xcf, 0x0164 => 0xd0, + 0x2202 => 0xd1, 0xff => 0xd2, 0x0143 => 0xd3, 0xee => 0xd4, + 0xca => 0xd5, 0xe4 => 0xd6, 0xeb => 0xd7, 0x0107 => 0xd8, + 0x0144 => 0xd9, 0x016b => 0xda, 0x0147 => 0xdb, 0xcd => 0xdc, + 0xb1 => 0xdd, 0xa6 => 0xde, 0xae => 0xdf, 0x011e => 0xe0, + 0x0130 => 0xe1, 0x2211 => 0xe2, 0xc8 => 0xe3, 0x0155 => 0xe4, + 0x014d => 0xe5, 0x0179 => 0xe6, 0x017d => 0xe7, 0x2265 => 0xe8, + 0xd0 => 0xe9, 0xc7 => 0xea, 0x013c => 0xeb, 0x0165 => 0xec, + 0x0119 => 0xed, 0x0172 => 0xee, 0xc1 => 0xef, 0xc4 => 0xf0, + 0xe8 => 0xf1, 0x017a => 0xf2, 0x012f => 0xf3, 0xd3 => 0xf4, + 0xf3 => 0xf5, 0x0101 => 0xf6, 0x015b => 0xf7, 0xef => 0xf8, + 0xd4 => 0xf9, 0xd9 => 0xfa, 0x2206 => 0xfb, 0xfe => 0xfc, + 0xb2 => 0xfd, 0xd6 => 0xfe, 0xb5 => 0xff, 0xec => 0x0100, + 0x0151 => 0x0101, 0x0118 => 0x0102, 0x0111 => 0x0103, 0xbe => 0x0104, + 0x015e => 0x0105, 0x013e => 0x0106, 0x0136 => 0x0107, 0x0139 => 0x0108, + 0x2122 => 0x0109, 0x0117 => 0x010a, 0xcc => 0x010b, 0x012a => 0x010c, + 0x013d => 0x010d, 0xbd => 0x010e, 0x2264 => 0x010f, 0xf4 => 0x0110, + 0xf1 => 0x0111, 0x0170 => 0x0112, 0xc9 => 0x0113, 0x0113 => 0x0114, + 0x011f => 0x0115, 0xbc => 0x0116, 0x0160 => 0x0117, 0x0218 => 0x0118, + 0x0150 => 0x0119, 0xb0 => 0x011a, 0xf2 => 0x011b, 0x010c => 0x011c, + 0xf9 => 0x011d, 0x221a => 0x011e, 0x010e => 0x011f, 0x0157 => 0x0120, + 0xd1 => 0x0121, 0xf5 => 0x0122, 0x0156 => 0x0123, 0x013b => 0x0124, + 0xc3 => 0x0125, 0x0104 => 0x0126, 0xc5 => 0x0127, 0xd5 => 0x0128, + 0x017c => 0x0129, 0x011a => 0x012a, 0x012e => 0x012b, 0x0137 => 0x012c, + 0x2212 => 0x012d, 0xce => 0x012e, 0x0148 => 0x012f, 0x0163 => 0x0130, + 0xac => 0x0131, 0xf6 => 0x0132, 0xfc => 0x0133, 0x2260 => 0x0134, + 0x0123 => 0x0135, 0xf0 => 0x0136, 0x017e => 0x0137, 0x0146 => 0x0138, + 0xb9 => 0x0139, 0x012b => 0x013a, 0x20ac => 0x013b); + // require_once 'Zend/Pdf/Cmap.php'; + $this->_cmap = Zend_Pdf_Cmap::cmapWithTypeData( + Zend_Pdf_Cmap::TYPE_BYTE_ENCODING_STATIC, $cmapData); + + + /* Resource dictionary */ + + /* The resource dictionary for the standard fonts is sparse because PDF + * viewers already have all of the metrics data. We only need to provide + * the font name and encoding method. + */ + $this->_resource->BaseFont = new Zend_Pdf_Element_Name('Courier-Oblique'); + } +} diff --git a/library/Zend/Pdf/Resource/Font/Simple/Standard/Helvetica.php b/library/Zend/Pdf/Resource/Font/Simple/Standard/Helvetica.php new file mode 100644 index 0000000..8299bf2 --- /dev/null +++ b/library/Zend/Pdf/Resource/Font/Simple/Standard/Helvetica.php @@ -0,0 +1,305 @@ +_fontNames[Zend_Pdf_Font::NAME_COPYRIGHT]['en'] = + "\x00\x43\x00\x6f\x00\x70\x00\x79\x00\x72\x00\x69\x00\x67\x00\x68\x00" + . "\x74\x00\x20\x00\x28\x00\x63\x00\x29\x00\x20\x00\x31\x00\x39\x00" + . "\x38\x00\x35\x00\x2c\x00\x20\x00\x31\x00\x39\x00\x38\x00\x37\x00" + . "\x2c\x00\x20\x00\x31\x00\x39\x00\x38\x00\x39\x00\x2c\x00\x20\x00" + . "\x31\x00\x39\x00\x39\x00\x30\x00\x2c\x00\x20\x00\x31\x00\x39\x00" + . "\x39\x00\x37\x00\x20\x00\x41\x00\x64\x00\x6f\x00\x62\x00\x65\x00" + . "\x20\x00\x53\x00\x79\x00\x73\x00\x74\x00\x65\x00\x6d\x00\x73\x00" + . "\x20\x00\x49\x00\x6e\x00\x63\x00\x6f\x00\x72\x00\x70\x00\x6f\x00" + . "\x72\x00\x61\x00\x74\x00\x65\x00\x64\x00\x2e\x00\x20\x00\x20\x00" + . "\x41\x00\x6c\x00\x6c\x00\x20\x00\x52\x00\x69\x00\x67\x00\x68\x00" + . "\x74\x00\x73\x00\x20\x00\x52\x00\x65\x00\x73\x00\x65\x00\x72\x00" + . "\x76\x00\x65\x00\x64\x00\x2e\x00\x48\x00\x65\x00\x6c\x00\x76\x00" + . "\x65\x00\x74\x00\x69\x00\x63\x00\x61\x00\x20\x00\x69\x00\x73\x00" + . "\x20\x00\x61\x00\x20\x00\x74\x00\x72\x00\x61\x00\x64\x00\x65\x00" + . "\x6d\x00\x61\x00\x72\x00\x6b\x00\x20\x00\x6f\x00\x66\x00\x20\x00" + . "\x4c\x00\x69\x00\x6e\x00\x6f\x00\x74\x00\x79\x00\x70\x00\x65\x00" + . "\x2d\x00\x48\x00\x65\x00\x6c\x00\x6c\x00\x20\x00\x41\x00\x47\x00" + . "\x20\x00\x61\x00\x6e\x00\x64\x00\x2f\x00\x6f\x00\x72\x00\x20\x00" + . "\x69\x00\x74\x00\x73\x00\x20\x00\x73\x00\x75\x00\x62\x00\x73\x00" + . "\x69\x00\x64\x00\x69\x00\x61\x00\x72\x00\x69\x00\x65\x00\x73\x00" + . "\x2e"; + $this->_fontNames[Zend_Pdf_Font::NAME_FAMILY]['en'] = + "\x00\x48\x00\x65\x00\x6c\x00\x76\x00\x65\x00\x74\x00\x69\x00\x63\x00" + . "\x61"; + $this->_fontNames[Zend_Pdf_Font::NAME_STYLE]['en'] = + "\x00\x4d\x00\x65\x00\x64\x00\x69\x00\x75\x00\x6d"; + $this->_fontNames[Zend_Pdf_Font::NAME_ID]['en'] = + "\x00\x34\x00\x33\x00\x30\x00\x35\x00\x34"; + $this->_fontNames[Zend_Pdf_Font::NAME_FULL]['en'] = + "\x00\x48\x00\x65\x00\x6c\x00\x76\x00\x65\x00\x74\x00\x69\x00\x63\x00" + . "\x61\x00\x20\x00\x4d\x00\x65\x00\x64\x00\x69\x00\x75\x00\x6d"; + $this->_fontNames[Zend_Pdf_Font::NAME_VERSION]['en'] = + "\x00\x30\x00\x30\x00\x32\x00\x2e\x00\x30\x00\x30\x00\x30"; + $this->_fontNames[Zend_Pdf_Font::NAME_POSTSCRIPT]['en'] = + "\x00\x48\x00\x65\x00\x6c\x00\x76\x00\x65\x00\x74\x00\x69\x00\x63\x00" + . "\x61"; + + $this->_isBold = false; + $this->_isItalic = false; + $this->_isMonospaced = false; + + $this->_underlinePosition = -100; + $this->_underlineThickness = 50; + $this->_strikePosition = 225; + $this->_strikeThickness = 50; + + $this->_unitsPerEm = 1000; + + $this->_ascent = 718; + $this->_descent = -207; + $this->_lineGap = 275; + + /* The glyph numbers assigned here are synthetic; they do not match the + * actual glyph numbers used by the font. This is not a big deal though + * since this data never makes it to the PDF file. It is only used + * internally for layout calculations. + */ + $this->_glyphWidths = array( + 0x00 => 0x01f4, 0x01 => 0x0116, 0x02 => 0x0116, 0x03 => 0x0163, + 0x04 => 0x022c, 0x05 => 0x022c, 0x06 => 0x0379, 0x07 => 0x029b, + 0x08 => 0xde, 0x09 => 0x014d, 0x0a => 0x014d, 0x0b => 0x0185, + 0x0c => 0x0248, 0x0d => 0x0116, 0x0e => 0x014d, 0x0f => 0x0116, + 0x10 => 0x0116, 0x11 => 0x022c, 0x12 => 0x022c, 0x13 => 0x022c, + 0x14 => 0x022c, 0x15 => 0x022c, 0x16 => 0x022c, 0x17 => 0x022c, + 0x18 => 0x022c, 0x19 => 0x022c, 0x1a => 0x022c, 0x1b => 0x0116, + 0x1c => 0x0116, 0x1d => 0x0248, 0x1e => 0x0248, 0x1f => 0x0248, + 0x20 => 0x022c, 0x21 => 0x03f7, 0x22 => 0x029b, 0x23 => 0x029b, + 0x24 => 0x02d2, 0x25 => 0x02d2, 0x26 => 0x029b, 0x27 => 0x0263, + 0x28 => 0x030a, 0x29 => 0x02d2, 0x2a => 0x0116, 0x2b => 0x01f4, + 0x2c => 0x029b, 0x2d => 0x022c, 0x2e => 0x0341, 0x2f => 0x02d2, + 0x30 => 0x030a, 0x31 => 0x029b, 0x32 => 0x030a, 0x33 => 0x02d2, + 0x34 => 0x029b, 0x35 => 0x0263, 0x36 => 0x02d2, 0x37 => 0x029b, + 0x38 => 0x03b0, 0x39 => 0x029b, 0x3a => 0x029b, 0x3b => 0x0263, + 0x3c => 0x0116, 0x3d => 0x0116, 0x3e => 0x0116, 0x3f => 0x01d5, + 0x40 => 0x022c, 0x41 => 0xde, 0x42 => 0x022c, 0x43 => 0x022c, + 0x44 => 0x01f4, 0x45 => 0x022c, 0x46 => 0x022c, 0x47 => 0x0116, + 0x48 => 0x022c, 0x49 => 0x022c, 0x4a => 0xde, 0x4b => 0xde, + 0x4c => 0x01f4, 0x4d => 0xde, 0x4e => 0x0341, 0x4f => 0x022c, + 0x50 => 0x022c, 0x51 => 0x022c, 0x52 => 0x022c, 0x53 => 0x014d, + 0x54 => 0x01f4, 0x55 => 0x0116, 0x56 => 0x022c, 0x57 => 0x01f4, + 0x58 => 0x02d2, 0x59 => 0x01f4, 0x5a => 0x01f4, 0x5b => 0x01f4, + 0x5c => 0x014e, 0x5d => 0x0104, 0x5e => 0x014e, 0x5f => 0x0248, + 0x60 => 0x014d, 0x61 => 0x022c, 0x62 => 0x022c, 0x63 => 0xa7, + 0x64 => 0x022c, 0x65 => 0x022c, 0x66 => 0x022c, 0x67 => 0x022c, + 0x68 => 0xbf, 0x69 => 0x014d, 0x6a => 0x022c, 0x6b => 0x014d, + 0x6c => 0x014d, 0x6d => 0x01f4, 0x6e => 0x01f4, 0x6f => 0x022c, + 0x70 => 0x022c, 0x71 => 0x022c, 0x72 => 0x0116, 0x73 => 0x0219, + 0x74 => 0x015e, 0x75 => 0xde, 0x76 => 0x014d, 0x77 => 0x014d, + 0x78 => 0x022c, 0x79 => 0x03e8, 0x7a => 0x03e8, 0x7b => 0x0263, + 0x7c => 0x014d, 0x7d => 0x014d, 0x7e => 0x014d, 0x7f => 0x014d, + 0x80 => 0x014d, 0x81 => 0x014d, 0x82 => 0x014d, 0x83 => 0x014d, + 0x84 => 0x014d, 0x85 => 0x014d, 0x86 => 0x014d, 0x87 => 0x014d, + 0x88 => 0x014d, 0x89 => 0x03e8, 0x8a => 0x03e8, 0x8b => 0x0172, + 0x8c => 0x022c, 0x8d => 0x030a, 0x8e => 0x03e8, 0x8f => 0x016d, + 0x90 => 0x0379, 0x91 => 0x0116, 0x92 => 0xde, 0x93 => 0x0263, + 0x94 => 0x03b0, 0x95 => 0x0263, 0x96 => 0x0116, 0x97 => 0x022c, + 0x98 => 0x022c, 0x99 => 0x022c, 0x9a => 0x022c, 0x9b => 0x029b, + 0x9c => 0x0248, 0x9d => 0x029b, 0x9e => 0x029b, 0x9f => 0x022c, + 0xa0 => 0x02d2, 0xa1 => 0x01f4, 0xa2 => 0x01f4, 0xa3 => 0x022c, + 0xa4 => 0x02d2, 0xa5 => 0x02d2, 0xa6 => 0x022c, 0xa7 => 0x02d2, + 0xa8 => 0x022c, 0xa9 => 0x029b, 0xaa => 0x02d2, 0xab => 0xfa, + 0xac => 0x02e1, 0xad => 0x029b, 0xae => 0x01f4, 0xaf => 0x022c, + 0xb0 => 0x02d2, 0xb1 => 0xde, 0xb2 => 0x022c, 0xb3 => 0x0263, + 0xb4 => 0x02d2, 0xb5 => 0x022c, 0xb6 => 0x029b, 0xb7 => 0x01f4, + 0xb8 => 0x01f4, 0xb9 => 0x0116, 0xba => 0x01d7, 0xbb => 0x02d2, + 0xbc => 0x030a, 0xbd => 0x022c, 0xbe => 0x022c, 0xbf => 0x029b, + 0xc0 => 0x014d, 0xc1 => 0x01f4, 0xc2 => 0x0263, 0xc3 => 0x029b, + 0xc4 => 0x030a, 0xc5 => 0x02d2, 0xc6 => 0x029b, 0xc7 => 0x0283, + 0xc8 => 0x02d2, 0xc9 => 0x022c, 0xca => 0x014d, 0xcb => 0x030a, + 0xcc => 0x029b, 0xcd => 0x029b, 0xce => 0x0248, 0xcf => 0x022c, + 0xd0 => 0x0263, 0xd1 => 0x01dc, 0xd2 => 0x01f4, 0xd3 => 0x02d2, + 0xd4 => 0x0116, 0xd5 => 0x029b, 0xd6 => 0x022c, 0xd7 => 0x022c, + 0xd8 => 0x01f4, 0xd9 => 0x022c, 0xda => 0x022c, 0xdb => 0x02d2, + 0xdc => 0x0116, 0xdd => 0x0248, 0xde => 0x0104, 0xdf => 0x02e1, + 0xe0 => 0x030a, 0xe1 => 0x0116, 0xe2 => 0x0258, 0xe3 => 0x029b, + 0xe4 => 0x014d, 0xe5 => 0x022c, 0xe6 => 0x0263, 0xe7 => 0x0263, + 0xe8 => 0x0225, 0xe9 => 0x02d2, 0xea => 0x02d2, 0xeb => 0xde, + 0xec => 0x013d, 0xed => 0x022c, 0xee => 0x02d2, 0xef => 0x029b, + 0xf0 => 0x029b, 0xf1 => 0x022c, 0xf2 => 0x01f4, 0xf3 => 0xde, + 0xf4 => 0x030a, 0xf5 => 0x022c, 0xf6 => 0x022c, 0xf7 => 0x01f4, + 0xf8 => 0x0116, 0xf9 => 0x030a, 0xfa => 0x02d2, 0xfb => 0x0264, + 0xfc => 0x022c, 0xfd => 0x014d, 0xfe => 0x030a, 0xff => 0x022c, + 0x0100 => 0x0116, 0x0101 => 0x022c, 0x0102 => 0x029b, 0x0103 => 0x022c, + 0x0104 => 0x0342, 0x0105 => 0x029b, 0x0106 => 0x012b, 0x0107 => 0x029b, + 0x0108 => 0x022c, 0x0109 => 0x03e8, 0x010a => 0x022c, 0x010b => 0x0116, + 0x010c => 0x0116, 0x010d => 0x022c, 0x010e => 0x0342, 0x010f => 0x0225, + 0x0110 => 0x022c, 0x0111 => 0x022c, 0x0112 => 0x02d2, 0x0113 => 0x029b, + 0x0114 => 0x022c, 0x0115 => 0x022c, 0x0116 => 0x0342, 0x0117 => 0x029b, + 0x0118 => 0x029b, 0x0119 => 0x030a, 0x011a => 0x0190, 0x011b => 0x022c, + 0x011c => 0x02d2, 0x011d => 0x022c, 0x011e => 0x01c5, 0x011f => 0x02d2, + 0x0120 => 0x014d, 0x0121 => 0x02d2, 0x0122 => 0x022c, 0x0123 => 0x02d2, + 0x0124 => 0x022c, 0x0125 => 0x029b, 0x0126 => 0x029b, 0x0127 => 0x029b, + 0x0128 => 0x030a, 0x0129 => 0x01f4, 0x012a => 0x029b, 0x012b => 0x0116, + 0x012c => 0x01f4, 0x012d => 0x0248, 0x012e => 0x0116, 0x012f => 0x022c, + 0x0130 => 0x0116, 0x0131 => 0x0248, 0x0132 => 0x022c, 0x0133 => 0x022c, + 0x0134 => 0x0225, 0x0135 => 0x022c, 0x0136 => 0x022c, 0x0137 => 0x01f4, + 0x0138 => 0x022c, 0x0139 => 0x014d, 0x013a => 0x0116, 0x013b => 0x022c, + ); + + /* The cmap table is similarly synthesized. + */ + $cmapData = array( + 0x20 => 0x01, 0x21 => 0x02, 0x22 => 0x03, 0x23 => 0x04, + 0x24 => 0x05, 0x25 => 0x06, 0x26 => 0x07, 0x2019 => 0x08, + 0x28 => 0x09, 0x29 => 0x0a, 0x2a => 0x0b, 0x2b => 0x0c, + 0x2c => 0x0d, 0x2d => 0x0e, 0x2e => 0x0f, 0x2f => 0x10, + 0x30 => 0x11, 0x31 => 0x12, 0x32 => 0x13, 0x33 => 0x14, + 0x34 => 0x15, 0x35 => 0x16, 0x36 => 0x17, 0x37 => 0x18, + 0x38 => 0x19, 0x39 => 0x1a, 0x3a => 0x1b, 0x3b => 0x1c, + 0x3c => 0x1d, 0x3d => 0x1e, 0x3e => 0x1f, 0x3f => 0x20, + 0x40 => 0x21, 0x41 => 0x22, 0x42 => 0x23, 0x43 => 0x24, + 0x44 => 0x25, 0x45 => 0x26, 0x46 => 0x27, 0x47 => 0x28, + 0x48 => 0x29, 0x49 => 0x2a, 0x4a => 0x2b, 0x4b => 0x2c, + 0x4c => 0x2d, 0x4d => 0x2e, 0x4e => 0x2f, 0x4f => 0x30, + 0x50 => 0x31, 0x51 => 0x32, 0x52 => 0x33, 0x53 => 0x34, + 0x54 => 0x35, 0x55 => 0x36, 0x56 => 0x37, 0x57 => 0x38, + 0x58 => 0x39, 0x59 => 0x3a, 0x5a => 0x3b, 0x5b => 0x3c, + 0x5c => 0x3d, 0x5d => 0x3e, 0x5e => 0x3f, 0x5f => 0x40, + 0x2018 => 0x41, 0x61 => 0x42, 0x62 => 0x43, 0x63 => 0x44, + 0x64 => 0x45, 0x65 => 0x46, 0x66 => 0x47, 0x67 => 0x48, + 0x68 => 0x49, 0x69 => 0x4a, 0x6a => 0x4b, 0x6b => 0x4c, + 0x6c => 0x4d, 0x6d => 0x4e, 0x6e => 0x4f, 0x6f => 0x50, + 0x70 => 0x51, 0x71 => 0x52, 0x72 => 0x53, 0x73 => 0x54, + 0x74 => 0x55, 0x75 => 0x56, 0x76 => 0x57, 0x77 => 0x58, + 0x78 => 0x59, 0x79 => 0x5a, 0x7a => 0x5b, 0x7b => 0x5c, + 0x7c => 0x5d, 0x7d => 0x5e, 0x7e => 0x5f, 0xa1 => 0x60, + 0xa2 => 0x61, 0xa3 => 0x62, 0x2044 => 0x63, 0xa5 => 0x64, + 0x0192 => 0x65, 0xa7 => 0x66, 0xa4 => 0x67, 0x27 => 0x68, + 0x201c => 0x69, 0xab => 0x6a, 0x2039 => 0x6b, 0x203a => 0x6c, + 0xfb01 => 0x6d, 0xfb02 => 0x6e, 0x2013 => 0x6f, 0x2020 => 0x70, + 0x2021 => 0x71, 0xb7 => 0x72, 0xb6 => 0x73, 0x2022 => 0x74, + 0x201a => 0x75, 0x201e => 0x76, 0x201d => 0x77, 0xbb => 0x78, + 0x2026 => 0x79, 0x2030 => 0x7a, 0xbf => 0x7b, 0x60 => 0x7c, + 0xb4 => 0x7d, 0x02c6 => 0x7e, 0x02dc => 0x7f, 0xaf => 0x80, + 0x02d8 => 0x81, 0x02d9 => 0x82, 0xa8 => 0x83, 0x02da => 0x84, + 0xb8 => 0x85, 0x02dd => 0x86, 0x02db => 0x87, 0x02c7 => 0x88, + 0x2014 => 0x89, 0xc6 => 0x8a, 0xaa => 0x8b, 0x0141 => 0x8c, + 0xd8 => 0x8d, 0x0152 => 0x8e, 0xba => 0x8f, 0xe6 => 0x90, + 0x0131 => 0x91, 0x0142 => 0x92, 0xf8 => 0x93, 0x0153 => 0x94, + 0xdf => 0x95, 0xcf => 0x96, 0xe9 => 0x97, 0x0103 => 0x98, + 0x0171 => 0x99, 0x011b => 0x9a, 0x0178 => 0x9b, 0xf7 => 0x9c, + 0xdd => 0x9d, 0xc2 => 0x9e, 0xe1 => 0x9f, 0xdb => 0xa0, + 0xfd => 0xa1, 0x0219 => 0xa2, 0xea => 0xa3, 0x016e => 0xa4, + 0xdc => 0xa5, 0x0105 => 0xa6, 0xda => 0xa7, 0x0173 => 0xa8, + 0xcb => 0xa9, 0x0110 => 0xaa, 0xf6c3 => 0xab, 0xa9 => 0xac, + 0x0112 => 0xad, 0x010d => 0xae, 0xe5 => 0xaf, 0x0145 => 0xb0, + 0x013a => 0xb1, 0xe0 => 0xb2, 0x0162 => 0xb3, 0x0106 => 0xb4, + 0xe3 => 0xb5, 0x0116 => 0xb6, 0x0161 => 0xb7, 0x015f => 0xb8, + 0xed => 0xb9, 0x25ca => 0xba, 0x0158 => 0xbb, 0x0122 => 0xbc, + 0xfb => 0xbd, 0xe2 => 0xbe, 0x0100 => 0xbf, 0x0159 => 0xc0, + 0xe7 => 0xc1, 0x017b => 0xc2, 0xde => 0xc3, 0x014c => 0xc4, + 0x0154 => 0xc5, 0x015a => 0xc6, 0x010f => 0xc7, 0x016a => 0xc8, + 0x016f => 0xc9, 0xb3 => 0xca, 0xd2 => 0xcb, 0xc0 => 0xcc, + 0x0102 => 0xcd, 0xd7 => 0xce, 0xfa => 0xcf, 0x0164 => 0xd0, + 0x2202 => 0xd1, 0xff => 0xd2, 0x0143 => 0xd3, 0xee => 0xd4, + 0xca => 0xd5, 0xe4 => 0xd6, 0xeb => 0xd7, 0x0107 => 0xd8, + 0x0144 => 0xd9, 0x016b => 0xda, 0x0147 => 0xdb, 0xcd => 0xdc, + 0xb1 => 0xdd, 0xa6 => 0xde, 0xae => 0xdf, 0x011e => 0xe0, + 0x0130 => 0xe1, 0x2211 => 0xe2, 0xc8 => 0xe3, 0x0155 => 0xe4, + 0x014d => 0xe5, 0x0179 => 0xe6, 0x017d => 0xe7, 0x2265 => 0xe8, + 0xd0 => 0xe9, 0xc7 => 0xea, 0x013c => 0xeb, 0x0165 => 0xec, + 0x0119 => 0xed, 0x0172 => 0xee, 0xc1 => 0xef, 0xc4 => 0xf0, + 0xe8 => 0xf1, 0x017a => 0xf2, 0x012f => 0xf3, 0xd3 => 0xf4, + 0xf3 => 0xf5, 0x0101 => 0xf6, 0x015b => 0xf7, 0xef => 0xf8, + 0xd4 => 0xf9, 0xd9 => 0xfa, 0x2206 => 0xfb, 0xfe => 0xfc, + 0xb2 => 0xfd, 0xd6 => 0xfe, 0xb5 => 0xff, 0xec => 0x0100, + 0x0151 => 0x0101, 0x0118 => 0x0102, 0x0111 => 0x0103, 0xbe => 0x0104, + 0x015e => 0x0105, 0x013e => 0x0106, 0x0136 => 0x0107, 0x0139 => 0x0108, + 0x2122 => 0x0109, 0x0117 => 0x010a, 0xcc => 0x010b, 0x012a => 0x010c, + 0x013d => 0x010d, 0xbd => 0x010e, 0x2264 => 0x010f, 0xf4 => 0x0110, + 0xf1 => 0x0111, 0x0170 => 0x0112, 0xc9 => 0x0113, 0x0113 => 0x0114, + 0x011f => 0x0115, 0xbc => 0x0116, 0x0160 => 0x0117, 0x0218 => 0x0118, + 0x0150 => 0x0119, 0xb0 => 0x011a, 0xf2 => 0x011b, 0x010c => 0x011c, + 0xf9 => 0x011d, 0x221a => 0x011e, 0x010e => 0x011f, 0x0157 => 0x0120, + 0xd1 => 0x0121, 0xf5 => 0x0122, 0x0156 => 0x0123, 0x013b => 0x0124, + 0xc3 => 0x0125, 0x0104 => 0x0126, 0xc5 => 0x0127, 0xd5 => 0x0128, + 0x017c => 0x0129, 0x011a => 0x012a, 0x012e => 0x012b, 0x0137 => 0x012c, + 0x2212 => 0x012d, 0xce => 0x012e, 0x0148 => 0x012f, 0x0163 => 0x0130, + 0xac => 0x0131, 0xf6 => 0x0132, 0xfc => 0x0133, 0x2260 => 0x0134, + 0x0123 => 0x0135, 0xf0 => 0x0136, 0x017e => 0x0137, 0x0146 => 0x0138, + 0xb9 => 0x0139, 0x012b => 0x013a, 0x20ac => 0x013b); + // require_once 'Zend/Pdf/Cmap.php'; + $this->_cmap = Zend_Pdf_Cmap::cmapWithTypeData( + Zend_Pdf_Cmap::TYPE_BYTE_ENCODING_STATIC, $cmapData); + + + /* Resource dictionary */ + + /* The resource dictionary for the standard fonts is sparse because PDF + * viewers already have all of the metrics data. We only need to provide + * the font name and encoding method. + */ + $this->_resource->BaseFont = new Zend_Pdf_Element_Name('Helvetica'); + } +} diff --git a/library/Zend/Pdf/Resource/Font/Simple/Standard/HelveticaBold.php b/library/Zend/Pdf/Resource/Font/Simple/Standard/HelveticaBold.php new file mode 100644 index 0000000..3a8a605 --- /dev/null +++ b/library/Zend/Pdf/Resource/Font/Simple/Standard/HelveticaBold.php @@ -0,0 +1,305 @@ +_fontNames[Zend_Pdf_Font::NAME_COPYRIGHT]['en'] = + "\x00\x43\x00\x6f\x00\x70\x00\x79\x00\x72\x00\x69\x00\x67\x00\x68\x00" + . "\x74\x00\x20\x00\x28\x00\x63\x00\x29\x00\x20\x00\x31\x00\x39\x00" + . "\x38\x00\x35\x00\x2c\x00\x20\x00\x31\x00\x39\x00\x38\x00\x37\x00" + . "\x2c\x00\x20\x00\x31\x00\x39\x00\x38\x00\x39\x00\x2c\x00\x20\x00" + . "\x31\x00\x39\x00\x39\x00\x30\x00\x2c\x00\x20\x00\x31\x00\x39\x00" + . "\x39\x00\x37\x00\x20\x00\x41\x00\x64\x00\x6f\x00\x62\x00\x65\x00" + . "\x20\x00\x53\x00\x79\x00\x73\x00\x74\x00\x65\x00\x6d\x00\x73\x00" + . "\x20\x00\x49\x00\x6e\x00\x63\x00\x6f\x00\x72\x00\x70\x00\x6f\x00" + . "\x72\x00\x61\x00\x74\x00\x65\x00\x64\x00\x2e\x00\x20\x00\x20\x00" + . "\x41\x00\x6c\x00\x6c\x00\x20\x00\x52\x00\x69\x00\x67\x00\x68\x00" + . "\x74\x00\x73\x00\x20\x00\x52\x00\x65\x00\x73\x00\x65\x00\x72\x00" + . "\x76\x00\x65\x00\x64\x00\x2e\x00\x48\x00\x65\x00\x6c\x00\x76\x00" + . "\x65\x00\x74\x00\x69\x00\x63\x00\x61\x00\x20\x00\x69\x00\x73\x00" + . "\x20\x00\x61\x00\x20\x00\x74\x00\x72\x00\x61\x00\x64\x00\x65\x00" + . "\x6d\x00\x61\x00\x72\x00\x6b\x00\x20\x00\x6f\x00\x66\x00\x20\x00" + . "\x4c\x00\x69\x00\x6e\x00\x6f\x00\x74\x00\x79\x00\x70\x00\x65\x00" + . "\x2d\x00\x48\x00\x65\x00\x6c\x00\x6c\x00\x20\x00\x41\x00\x47\x00" + . "\x20\x00\x61\x00\x6e\x00\x64\x00\x2f\x00\x6f\x00\x72\x00\x20\x00" + . "\x69\x00\x74\x00\x73\x00\x20\x00\x73\x00\x75\x00\x62\x00\x73\x00" + . "\x69\x00\x64\x00\x69\x00\x61\x00\x72\x00\x69\x00\x65\x00\x73\x00" + . "\x2e"; + $this->_fontNames[Zend_Pdf_Font::NAME_FAMILY]['en'] = + "\x00\x48\x00\x65\x00\x6c\x00\x76\x00\x65\x00\x74\x00\x69\x00\x63\x00" + . "\x61"; + $this->_fontNames[Zend_Pdf_Font::NAME_STYLE]['en'] = + "\x00\x42\x00\x6f\x00\x6c\x00\x64"; + $this->_fontNames[Zend_Pdf_Font::NAME_ID]['en'] = + "\x00\x34\x00\x33\x00\x30\x00\x35\x00\x32"; + $this->_fontNames[Zend_Pdf_Font::NAME_FULL]['en'] = + "\x00\x48\x00\x65\x00\x6c\x00\x76\x00\x65\x00\x74\x00\x69\x00\x63\x00" + . "\x61\x00\x2d\x00\x42\x00\x6f\x00\x6c\x00\x64\x00\x20\x00\x42\x00" + . "\x6f\x00\x6c\x00\x64"; + $this->_fontNames[Zend_Pdf_Font::NAME_VERSION]['en'] = + "\x00\x30\x00\x30\x00\x32\x00\x2e\x00\x30\x00\x30\x00\x30"; + $this->_fontNames[Zend_Pdf_Font::NAME_POSTSCRIPT]['en'] = + "\x00\x48\x00\x65\x00\x6c\x00\x76\x00\x65\x00\x74\x00\x69\x00\x63\x00" + . "\x61\x00\x2d\x00\x42\x00\x6f\x00\x6c\x00\x64"; + + $this->_isBold = true; + $this->_isItalic = false; + $this->_isMonospaced = false; + + $this->_underlinePosition = -100; + $this->_underlineThickness = 50; + $this->_strikePosition = 225; + $this->_strikeThickness = 50; + + $this->_unitsPerEm = 1000; + + $this->_ascent = 718; + $this->_descent = -207; + $this->_lineGap = 275; + + /* The glyph numbers assigned here are synthetic; they do not match the + * actual glyph numbers used by the font. This is not a big deal though + * since this data never makes it to the PDF file. It is only used + * internally for layout calculations. + */ + $this->_glyphWidths = array( + 0x00 => 0x01f4, 0x01 => 0x0116, 0x02 => 0x014d, 0x03 => 0x01da, + 0x04 => 0x022c, 0x05 => 0x022c, 0x06 => 0x0379, 0x07 => 0x02d2, + 0x08 => 0x0116, 0x09 => 0x014d, 0x0a => 0x014d, 0x0b => 0x0185, + 0x0c => 0x0248, 0x0d => 0x0116, 0x0e => 0x014d, 0x0f => 0x0116, + 0x10 => 0x0116, 0x11 => 0x022c, 0x12 => 0x022c, 0x13 => 0x022c, + 0x14 => 0x022c, 0x15 => 0x022c, 0x16 => 0x022c, 0x17 => 0x022c, + 0x18 => 0x022c, 0x19 => 0x022c, 0x1a => 0x022c, 0x1b => 0x014d, + 0x1c => 0x014d, 0x1d => 0x0248, 0x1e => 0x0248, 0x1f => 0x0248, + 0x20 => 0x0263, 0x21 => 0x03cf, 0x22 => 0x02d2, 0x23 => 0x02d2, + 0x24 => 0x02d2, 0x25 => 0x02d2, 0x26 => 0x029b, 0x27 => 0x0263, + 0x28 => 0x030a, 0x29 => 0x02d2, 0x2a => 0x0116, 0x2b => 0x022c, + 0x2c => 0x02d2, 0x2d => 0x0263, 0x2e => 0x0341, 0x2f => 0x02d2, + 0x30 => 0x030a, 0x31 => 0x029b, 0x32 => 0x030a, 0x33 => 0x02d2, + 0x34 => 0x029b, 0x35 => 0x0263, 0x36 => 0x02d2, 0x37 => 0x029b, + 0x38 => 0x03b0, 0x39 => 0x029b, 0x3a => 0x029b, 0x3b => 0x0263, + 0x3c => 0x014d, 0x3d => 0x0116, 0x3e => 0x014d, 0x3f => 0x0248, + 0x40 => 0x022c, 0x41 => 0x0116, 0x42 => 0x022c, 0x43 => 0x0263, + 0x44 => 0x022c, 0x45 => 0x0263, 0x46 => 0x022c, 0x47 => 0x014d, + 0x48 => 0x0263, 0x49 => 0x0263, 0x4a => 0x0116, 0x4b => 0x0116, + 0x4c => 0x022c, 0x4d => 0x0116, 0x4e => 0x0379, 0x4f => 0x0263, + 0x50 => 0x0263, 0x51 => 0x0263, 0x52 => 0x0263, 0x53 => 0x0185, + 0x54 => 0x022c, 0x55 => 0x014d, 0x56 => 0x0263, 0x57 => 0x022c, + 0x58 => 0x030a, 0x59 => 0x022c, 0x5a => 0x022c, 0x5b => 0x01f4, + 0x5c => 0x0185, 0x5d => 0x0118, 0x5e => 0x0185, 0x5f => 0x0248, + 0x60 => 0x014d, 0x61 => 0x022c, 0x62 => 0x022c, 0x63 => 0xa7, + 0x64 => 0x022c, 0x65 => 0x022c, 0x66 => 0x022c, 0x67 => 0x022c, + 0x68 => 0xee, 0x69 => 0x01f4, 0x6a => 0x022c, 0x6b => 0x014d, + 0x6c => 0x014d, 0x6d => 0x0263, 0x6e => 0x0263, 0x6f => 0x022c, + 0x70 => 0x022c, 0x71 => 0x022c, 0x72 => 0x0116, 0x73 => 0x022c, + 0x74 => 0x015e, 0x75 => 0x0116, 0x76 => 0x01f4, 0x77 => 0x01f4, + 0x78 => 0x022c, 0x79 => 0x03e8, 0x7a => 0x03e8, 0x7b => 0x0263, + 0x7c => 0x014d, 0x7d => 0x014d, 0x7e => 0x014d, 0x7f => 0x014d, + 0x80 => 0x014d, 0x81 => 0x014d, 0x82 => 0x014d, 0x83 => 0x014d, + 0x84 => 0x014d, 0x85 => 0x014d, 0x86 => 0x014d, 0x87 => 0x014d, + 0x88 => 0x014d, 0x89 => 0x03e8, 0x8a => 0x03e8, 0x8b => 0x0172, + 0x8c => 0x0263, 0x8d => 0x030a, 0x8e => 0x03e8, 0x8f => 0x016d, + 0x90 => 0x0379, 0x91 => 0x0116, 0x92 => 0x0116, 0x93 => 0x0263, + 0x94 => 0x03b0, 0x95 => 0x0263, 0x96 => 0x0116, 0x97 => 0x022c, + 0x98 => 0x022c, 0x99 => 0x0263, 0x9a => 0x022c, 0x9b => 0x029b, + 0x9c => 0x0248, 0x9d => 0x029b, 0x9e => 0x02d2, 0x9f => 0x022c, + 0xa0 => 0x02d2, 0xa1 => 0x022c, 0xa2 => 0x022c, 0xa3 => 0x022c, + 0xa4 => 0x02d2, 0xa5 => 0x02d2, 0xa6 => 0x022c, 0xa7 => 0x02d2, + 0xa8 => 0x0263, 0xa9 => 0x029b, 0xaa => 0x02d2, 0xab => 0xfa, + 0xac => 0x02e1, 0xad => 0x029b, 0xae => 0x022c, 0xaf => 0x022c, + 0xb0 => 0x02d2, 0xb1 => 0x0116, 0xb2 => 0x022c, 0xb3 => 0x0263, + 0xb4 => 0x02d2, 0xb5 => 0x022c, 0xb6 => 0x029b, 0xb7 => 0x022c, + 0xb8 => 0x022c, 0xb9 => 0x0116, 0xba => 0x01ee, 0xbb => 0x02d2, + 0xbc => 0x030a, 0xbd => 0x0263, 0xbe => 0x022c, 0xbf => 0x02d2, + 0xc0 => 0x0185, 0xc1 => 0x022c, 0xc2 => 0x0263, 0xc3 => 0x029b, + 0xc4 => 0x030a, 0xc5 => 0x02d2, 0xc6 => 0x029b, 0xc7 => 0x02e7, + 0xc8 => 0x02d2, 0xc9 => 0x0263, 0xca => 0x014d, 0xcb => 0x030a, + 0xcc => 0x02d2, 0xcd => 0x02d2, 0xce => 0x0248, 0xcf => 0x0263, + 0xd0 => 0x0263, 0xd1 => 0x01ee, 0xd2 => 0x022c, 0xd3 => 0x02d2, + 0xd4 => 0x0116, 0xd5 => 0x029b, 0xd6 => 0x022c, 0xd7 => 0x022c, + 0xd8 => 0x022c, 0xd9 => 0x0263, 0xda => 0x0263, 0xdb => 0x02d2, + 0xdc => 0x0116, 0xdd => 0x0248, 0xde => 0x0118, 0xdf => 0x02e1, + 0xe0 => 0x030a, 0xe1 => 0x0116, 0xe2 => 0x0258, 0xe3 => 0x029b, + 0xe4 => 0x0185, 0xe5 => 0x0263, 0xe6 => 0x0263, 0xe7 => 0x0263, + 0xe8 => 0x0225, 0xe9 => 0x02d2, 0xea => 0x02d2, 0xeb => 0x0116, + 0xec => 0x0185, 0xed => 0x022c, 0xee => 0x02d2, 0xef => 0x02d2, + 0xf0 => 0x02d2, 0xf1 => 0x022c, 0xf2 => 0x01f4, 0xf3 => 0x0116, + 0xf4 => 0x030a, 0xf5 => 0x0263, 0xf6 => 0x022c, 0xf7 => 0x022c, + 0xf8 => 0x0116, 0xf9 => 0x030a, 0xfa => 0x02d2, 0xfb => 0x0264, + 0xfc => 0x0263, 0xfd => 0x014d, 0xfe => 0x030a, 0xff => 0x0263, + 0x0100 => 0x0116, 0x0101 => 0x0263, 0x0102 => 0x029b, 0x0103 => 0x0263, + 0x0104 => 0x0342, 0x0105 => 0x029b, 0x0106 => 0x0190, 0x0107 => 0x02d2, + 0x0108 => 0x0263, 0x0109 => 0x03e8, 0x010a => 0x022c, 0x010b => 0x0116, + 0x010c => 0x0116, 0x010d => 0x0263, 0x010e => 0x0342, 0x010f => 0x0225, + 0x0110 => 0x0263, 0x0111 => 0x0263, 0x0112 => 0x02d2, 0x0113 => 0x029b, + 0x0114 => 0x022c, 0x0115 => 0x0263, 0x0116 => 0x0342, 0x0117 => 0x029b, + 0x0118 => 0x029b, 0x0119 => 0x030a, 0x011a => 0x0190, 0x011b => 0x0263, + 0x011c => 0x02d2, 0x011d => 0x0263, 0x011e => 0x0225, 0x011f => 0x02d2, + 0x0120 => 0x0185, 0x0121 => 0x02d2, 0x0122 => 0x0263, 0x0123 => 0x02d2, + 0x0124 => 0x0263, 0x0125 => 0x02d2, 0x0126 => 0x02d2, 0x0127 => 0x02d2, + 0x0128 => 0x030a, 0x0129 => 0x01f4, 0x012a => 0x029b, 0x012b => 0x0116, + 0x012c => 0x022c, 0x012d => 0x0248, 0x012e => 0x0116, 0x012f => 0x0263, + 0x0130 => 0x014d, 0x0131 => 0x0248, 0x0132 => 0x0263, 0x0133 => 0x0263, + 0x0134 => 0x0225, 0x0135 => 0x0263, 0x0136 => 0x0263, 0x0137 => 0x01f4, + 0x0138 => 0x0263, 0x0139 => 0x014d, 0x013a => 0x0116, 0x013b => 0x022c, + ); + + /* The cmap table is similarly synthesized. + */ + $cmapData = array( + 0x20 => 0x01, 0x21 => 0x02, 0x22 => 0x03, 0x23 => 0x04, + 0x24 => 0x05, 0x25 => 0x06, 0x26 => 0x07, 0x2019 => 0x08, + 0x28 => 0x09, 0x29 => 0x0a, 0x2a => 0x0b, 0x2b => 0x0c, + 0x2c => 0x0d, 0x2d => 0x0e, 0x2e => 0x0f, 0x2f => 0x10, + 0x30 => 0x11, 0x31 => 0x12, 0x32 => 0x13, 0x33 => 0x14, + 0x34 => 0x15, 0x35 => 0x16, 0x36 => 0x17, 0x37 => 0x18, + 0x38 => 0x19, 0x39 => 0x1a, 0x3a => 0x1b, 0x3b => 0x1c, + 0x3c => 0x1d, 0x3d => 0x1e, 0x3e => 0x1f, 0x3f => 0x20, + 0x40 => 0x21, 0x41 => 0x22, 0x42 => 0x23, 0x43 => 0x24, + 0x44 => 0x25, 0x45 => 0x26, 0x46 => 0x27, 0x47 => 0x28, + 0x48 => 0x29, 0x49 => 0x2a, 0x4a => 0x2b, 0x4b => 0x2c, + 0x4c => 0x2d, 0x4d => 0x2e, 0x4e => 0x2f, 0x4f => 0x30, + 0x50 => 0x31, 0x51 => 0x32, 0x52 => 0x33, 0x53 => 0x34, + 0x54 => 0x35, 0x55 => 0x36, 0x56 => 0x37, 0x57 => 0x38, + 0x58 => 0x39, 0x59 => 0x3a, 0x5a => 0x3b, 0x5b => 0x3c, + 0x5c => 0x3d, 0x5d => 0x3e, 0x5e => 0x3f, 0x5f => 0x40, + 0x2018 => 0x41, 0x61 => 0x42, 0x62 => 0x43, 0x63 => 0x44, + 0x64 => 0x45, 0x65 => 0x46, 0x66 => 0x47, 0x67 => 0x48, + 0x68 => 0x49, 0x69 => 0x4a, 0x6a => 0x4b, 0x6b => 0x4c, + 0x6c => 0x4d, 0x6d => 0x4e, 0x6e => 0x4f, 0x6f => 0x50, + 0x70 => 0x51, 0x71 => 0x52, 0x72 => 0x53, 0x73 => 0x54, + 0x74 => 0x55, 0x75 => 0x56, 0x76 => 0x57, 0x77 => 0x58, + 0x78 => 0x59, 0x79 => 0x5a, 0x7a => 0x5b, 0x7b => 0x5c, + 0x7c => 0x5d, 0x7d => 0x5e, 0x7e => 0x5f, 0xa1 => 0x60, + 0xa2 => 0x61, 0xa3 => 0x62, 0x2044 => 0x63, 0xa5 => 0x64, + 0x0192 => 0x65, 0xa7 => 0x66, 0xa4 => 0x67, 0x27 => 0x68, + 0x201c => 0x69, 0xab => 0x6a, 0x2039 => 0x6b, 0x203a => 0x6c, + 0xfb01 => 0x6d, 0xfb02 => 0x6e, 0x2013 => 0x6f, 0x2020 => 0x70, + 0x2021 => 0x71, 0xb7 => 0x72, 0xb6 => 0x73, 0x2022 => 0x74, + 0x201a => 0x75, 0x201e => 0x76, 0x201d => 0x77, 0xbb => 0x78, + 0x2026 => 0x79, 0x2030 => 0x7a, 0xbf => 0x7b, 0x60 => 0x7c, + 0xb4 => 0x7d, 0x02c6 => 0x7e, 0x02dc => 0x7f, 0xaf => 0x80, + 0x02d8 => 0x81, 0x02d9 => 0x82, 0xa8 => 0x83, 0x02da => 0x84, + 0xb8 => 0x85, 0x02dd => 0x86, 0x02db => 0x87, 0x02c7 => 0x88, + 0x2014 => 0x89, 0xc6 => 0x8a, 0xaa => 0x8b, 0x0141 => 0x8c, + 0xd8 => 0x8d, 0x0152 => 0x8e, 0xba => 0x8f, 0xe6 => 0x90, + 0x0131 => 0x91, 0x0142 => 0x92, 0xf8 => 0x93, 0x0153 => 0x94, + 0xdf => 0x95, 0xcf => 0x96, 0xe9 => 0x97, 0x0103 => 0x98, + 0x0171 => 0x99, 0x011b => 0x9a, 0x0178 => 0x9b, 0xf7 => 0x9c, + 0xdd => 0x9d, 0xc2 => 0x9e, 0xe1 => 0x9f, 0xdb => 0xa0, + 0xfd => 0xa1, 0x0219 => 0xa2, 0xea => 0xa3, 0x016e => 0xa4, + 0xdc => 0xa5, 0x0105 => 0xa6, 0xda => 0xa7, 0x0173 => 0xa8, + 0xcb => 0xa9, 0x0110 => 0xaa, 0xf6c3 => 0xab, 0xa9 => 0xac, + 0x0112 => 0xad, 0x010d => 0xae, 0xe5 => 0xaf, 0x0145 => 0xb0, + 0x013a => 0xb1, 0xe0 => 0xb2, 0x0162 => 0xb3, 0x0106 => 0xb4, + 0xe3 => 0xb5, 0x0116 => 0xb6, 0x0161 => 0xb7, 0x015f => 0xb8, + 0xed => 0xb9, 0x25ca => 0xba, 0x0158 => 0xbb, 0x0122 => 0xbc, + 0xfb => 0xbd, 0xe2 => 0xbe, 0x0100 => 0xbf, 0x0159 => 0xc0, + 0xe7 => 0xc1, 0x017b => 0xc2, 0xde => 0xc3, 0x014c => 0xc4, + 0x0154 => 0xc5, 0x015a => 0xc6, 0x010f => 0xc7, 0x016a => 0xc8, + 0x016f => 0xc9, 0xb3 => 0xca, 0xd2 => 0xcb, 0xc0 => 0xcc, + 0x0102 => 0xcd, 0xd7 => 0xce, 0xfa => 0xcf, 0x0164 => 0xd0, + 0x2202 => 0xd1, 0xff => 0xd2, 0x0143 => 0xd3, 0xee => 0xd4, + 0xca => 0xd5, 0xe4 => 0xd6, 0xeb => 0xd7, 0x0107 => 0xd8, + 0x0144 => 0xd9, 0x016b => 0xda, 0x0147 => 0xdb, 0xcd => 0xdc, + 0xb1 => 0xdd, 0xa6 => 0xde, 0xae => 0xdf, 0x011e => 0xe0, + 0x0130 => 0xe1, 0x2211 => 0xe2, 0xc8 => 0xe3, 0x0155 => 0xe4, + 0x014d => 0xe5, 0x0179 => 0xe6, 0x017d => 0xe7, 0x2265 => 0xe8, + 0xd0 => 0xe9, 0xc7 => 0xea, 0x013c => 0xeb, 0x0165 => 0xec, + 0x0119 => 0xed, 0x0172 => 0xee, 0xc1 => 0xef, 0xc4 => 0xf0, + 0xe8 => 0xf1, 0x017a => 0xf2, 0x012f => 0xf3, 0xd3 => 0xf4, + 0xf3 => 0xf5, 0x0101 => 0xf6, 0x015b => 0xf7, 0xef => 0xf8, + 0xd4 => 0xf9, 0xd9 => 0xfa, 0x2206 => 0xfb, 0xfe => 0xfc, + 0xb2 => 0xfd, 0xd6 => 0xfe, 0xb5 => 0xff, 0xec => 0x0100, + 0x0151 => 0x0101, 0x0118 => 0x0102, 0x0111 => 0x0103, 0xbe => 0x0104, + 0x015e => 0x0105, 0x013e => 0x0106, 0x0136 => 0x0107, 0x0139 => 0x0108, + 0x2122 => 0x0109, 0x0117 => 0x010a, 0xcc => 0x010b, 0x012a => 0x010c, + 0x013d => 0x010d, 0xbd => 0x010e, 0x2264 => 0x010f, 0xf4 => 0x0110, + 0xf1 => 0x0111, 0x0170 => 0x0112, 0xc9 => 0x0113, 0x0113 => 0x0114, + 0x011f => 0x0115, 0xbc => 0x0116, 0x0160 => 0x0117, 0x0218 => 0x0118, + 0x0150 => 0x0119, 0xb0 => 0x011a, 0xf2 => 0x011b, 0x010c => 0x011c, + 0xf9 => 0x011d, 0x221a => 0x011e, 0x010e => 0x011f, 0x0157 => 0x0120, + 0xd1 => 0x0121, 0xf5 => 0x0122, 0x0156 => 0x0123, 0x013b => 0x0124, + 0xc3 => 0x0125, 0x0104 => 0x0126, 0xc5 => 0x0127, 0xd5 => 0x0128, + 0x017c => 0x0129, 0x011a => 0x012a, 0x012e => 0x012b, 0x0137 => 0x012c, + 0x2212 => 0x012d, 0xce => 0x012e, 0x0148 => 0x012f, 0x0163 => 0x0130, + 0xac => 0x0131, 0xf6 => 0x0132, 0xfc => 0x0133, 0x2260 => 0x0134, + 0x0123 => 0x0135, 0xf0 => 0x0136, 0x017e => 0x0137, 0x0146 => 0x0138, + 0xb9 => 0x0139, 0x012b => 0x013a, 0x20ac => 0x013b); + // require_once 'Zend/Pdf/Cmap.php'; + $this->_cmap = Zend_Pdf_Cmap::cmapWithTypeData( + Zend_Pdf_Cmap::TYPE_BYTE_ENCODING_STATIC, $cmapData); + + + /* Resource dictionary */ + + /* The resource dictionary for the standard fonts is sparse because PDF + * viewers already have all of the metrics data. We only need to provide + * the font name and encoding method. + */ + $this->_resource->BaseFont = new Zend_Pdf_Element_Name('Helvetica-Bold'); + } +} diff --git a/library/Zend/Pdf/Resource/Font/Simple/Standard/HelveticaBoldOblique.php b/library/Zend/Pdf/Resource/Font/Simple/Standard/HelveticaBoldOblique.php new file mode 100644 index 0000000..7cd8ed7 --- /dev/null +++ b/library/Zend/Pdf/Resource/Font/Simple/Standard/HelveticaBoldOblique.php @@ -0,0 +1,308 @@ +_fontNames[Zend_Pdf_Font::NAME_COPYRIGHT]['en'] = + "\x00\x43\x00\x6f\x00\x70\x00\x79\x00\x72\x00\x69\x00\x67\x00\x68\x00" + . "\x74\x00\x20\x00\x28\x00\x63\x00\x29\x00\x20\x00\x31\x00\x39\x00" + . "\x38\x00\x35\x00\x2c\x00\x20\x00\x31\x00\x39\x00\x38\x00\x37\x00" + . "\x2c\x00\x20\x00\x31\x00\x39\x00\x38\x00\x39\x00\x2c\x00\x20\x00" + . "\x31\x00\x39\x00\x39\x00\x30\x00\x2c\x00\x20\x00\x31\x00\x39\x00" + . "\x39\x00\x37\x00\x20\x00\x41\x00\x64\x00\x6f\x00\x62\x00\x65\x00" + . "\x20\x00\x53\x00\x79\x00\x73\x00\x74\x00\x65\x00\x6d\x00\x73\x00" + . "\x20\x00\x49\x00\x6e\x00\x63\x00\x6f\x00\x72\x00\x70\x00\x6f\x00" + . "\x72\x00\x61\x00\x74\x00\x65\x00\x64\x00\x2e\x00\x20\x00\x20\x00" + . "\x41\x00\x6c\x00\x6c\x00\x20\x00\x52\x00\x69\x00\x67\x00\x68\x00" + . "\x74\x00\x73\x00\x20\x00\x52\x00\x65\x00\x73\x00\x65\x00\x72\x00" + . "\x76\x00\x65\x00\x64\x00\x2e\x00\x48\x00\x65\x00\x6c\x00\x76\x00" + . "\x65\x00\x74\x00\x69\x00\x63\x00\x61\x00\x20\x00\x69\x00\x73\x00" + . "\x20\x00\x61\x00\x20\x00\x74\x00\x72\x00\x61\x00\x64\x00\x65\x00" + . "\x6d\x00\x61\x00\x72\x00\x6b\x00\x20\x00\x6f\x00\x66\x00\x20\x00" + . "\x4c\x00\x69\x00\x6e\x00\x6f\x00\x74\x00\x79\x00\x70\x00\x65\x00" + . "\x2d\x00\x48\x00\x65\x00\x6c\x00\x6c\x00\x20\x00\x41\x00\x47\x00" + . "\x20\x00\x61\x00\x6e\x00\x64\x00\x2f\x00\x6f\x00\x72\x00\x20\x00" + . "\x69\x00\x74\x00\x73\x00\x20\x00\x73\x00\x75\x00\x62\x00\x73\x00" + . "\x69\x00\x64\x00\x69\x00\x61\x00\x72\x00\x69\x00\x65\x00\x73\x00" + . "\x2e"; + $this->_fontNames[Zend_Pdf_Font::NAME_FAMILY]['en'] = + "\x00\x48\x00\x65\x00\x6c\x00\x76\x00\x65\x00\x74\x00\x69\x00\x63\x00" + . "\x61"; + $this->_fontNames[Zend_Pdf_Font::NAME_STYLE]['en'] = + "\x00\x42\x00\x6f\x00\x6c\x00\x64"; + $this->_fontNames[Zend_Pdf_Font::NAME_ID]['en'] = + "\x00\x34\x00\x33\x00\x30\x00\x35\x00\x33"; + $this->_fontNames[Zend_Pdf_Font::NAME_FULL]['en'] = + "\x00\x48\x00\x65\x00\x6c\x00\x76\x00\x65\x00\x74\x00\x69\x00\x63\x00" + . "\x61\x00\x2d\x00\x42\x00\x6f\x00\x6c\x00\x64\x00\x4f\x00\x62\x00" + . "\x6c\x00\x69\x00\x71\x00\x75\x00\x65\x00\x20\x00\x42\x00\x6f\x00" + . "\x6c\x00\x64"; + $this->_fontNames[Zend_Pdf_Font::NAME_VERSION]['en'] = + "\x00\x30\x00\x30\x00\x32\x00\x2e\x00\x30\x00\x30\x00\x30"; + $this->_fontNames[Zend_Pdf_Font::NAME_POSTSCRIPT]['en'] = + "\x00\x48\x00\x65\x00\x6c\x00\x76\x00\x65\x00\x74\x00\x69\x00\x63\x00" + . "\x61\x00\x2d\x00\x42\x00\x6f\x00\x6c\x00\x64\x00\x4f\x00\x62\x00" + . "\x6c\x00\x69\x00\x71\x00\x75\x00\x65"; + + $this->_isBold = true; + $this->_isItalic = true; + $this->_isMonospaced = false; + + $this->_underlinePosition = -100; + $this->_underlineThickness = 50; + $this->_strikePosition = 225; + $this->_strikeThickness = 50; + + $this->_unitsPerEm = 1000; + + $this->_ascent = 718; + $this->_descent = -207; + $this->_lineGap = 275; + + /* The glyph numbers assigned here are synthetic; they do not match the + * actual glyph numbers used by the font. This is not a big deal though + * since this data never makes it to the PDF file. It is only used + * internally for layout calculations. + */ + $this->_glyphWidths = array( + 0x00 => 0x01f4, 0x01 => 0x0116, 0x02 => 0x014d, 0x03 => 0x01da, + 0x04 => 0x022c, 0x05 => 0x022c, 0x06 => 0x0379, 0x07 => 0x02d2, + 0x08 => 0x0116, 0x09 => 0x014d, 0x0a => 0x014d, 0x0b => 0x0185, + 0x0c => 0x0248, 0x0d => 0x0116, 0x0e => 0x014d, 0x0f => 0x0116, + 0x10 => 0x0116, 0x11 => 0x022c, 0x12 => 0x022c, 0x13 => 0x022c, + 0x14 => 0x022c, 0x15 => 0x022c, 0x16 => 0x022c, 0x17 => 0x022c, + 0x18 => 0x022c, 0x19 => 0x022c, 0x1a => 0x022c, 0x1b => 0x014d, + 0x1c => 0x014d, 0x1d => 0x0248, 0x1e => 0x0248, 0x1f => 0x0248, + 0x20 => 0x0263, 0x21 => 0x03cf, 0x22 => 0x02d2, 0x23 => 0x02d2, + 0x24 => 0x02d2, 0x25 => 0x02d2, 0x26 => 0x029b, 0x27 => 0x0263, + 0x28 => 0x030a, 0x29 => 0x02d2, 0x2a => 0x0116, 0x2b => 0x022c, + 0x2c => 0x02d2, 0x2d => 0x0263, 0x2e => 0x0341, 0x2f => 0x02d2, + 0x30 => 0x030a, 0x31 => 0x029b, 0x32 => 0x030a, 0x33 => 0x02d2, + 0x34 => 0x029b, 0x35 => 0x0263, 0x36 => 0x02d2, 0x37 => 0x029b, + 0x38 => 0x03b0, 0x39 => 0x029b, 0x3a => 0x029b, 0x3b => 0x0263, + 0x3c => 0x014d, 0x3d => 0x0116, 0x3e => 0x014d, 0x3f => 0x0248, + 0x40 => 0x022c, 0x41 => 0x0116, 0x42 => 0x022c, 0x43 => 0x0263, + 0x44 => 0x022c, 0x45 => 0x0263, 0x46 => 0x022c, 0x47 => 0x014d, + 0x48 => 0x0263, 0x49 => 0x0263, 0x4a => 0x0116, 0x4b => 0x0116, + 0x4c => 0x022c, 0x4d => 0x0116, 0x4e => 0x0379, 0x4f => 0x0263, + 0x50 => 0x0263, 0x51 => 0x0263, 0x52 => 0x0263, 0x53 => 0x0185, + 0x54 => 0x022c, 0x55 => 0x014d, 0x56 => 0x0263, 0x57 => 0x022c, + 0x58 => 0x030a, 0x59 => 0x022c, 0x5a => 0x022c, 0x5b => 0x01f4, + 0x5c => 0x0185, 0x5d => 0x0118, 0x5e => 0x0185, 0x5f => 0x0248, + 0x60 => 0x014d, 0x61 => 0x022c, 0x62 => 0x022c, 0x63 => 0xa7, + 0x64 => 0x022c, 0x65 => 0x022c, 0x66 => 0x022c, 0x67 => 0x022c, + 0x68 => 0xee, 0x69 => 0x01f4, 0x6a => 0x022c, 0x6b => 0x014d, + 0x6c => 0x014d, 0x6d => 0x0263, 0x6e => 0x0263, 0x6f => 0x022c, + 0x70 => 0x022c, 0x71 => 0x022c, 0x72 => 0x0116, 0x73 => 0x022c, + 0x74 => 0x015e, 0x75 => 0x0116, 0x76 => 0x01f4, 0x77 => 0x01f4, + 0x78 => 0x022c, 0x79 => 0x03e8, 0x7a => 0x03e8, 0x7b => 0x0263, + 0x7c => 0x014d, 0x7d => 0x014d, 0x7e => 0x014d, 0x7f => 0x014d, + 0x80 => 0x014d, 0x81 => 0x014d, 0x82 => 0x014d, 0x83 => 0x014d, + 0x84 => 0x014d, 0x85 => 0x014d, 0x86 => 0x014d, 0x87 => 0x014d, + 0x88 => 0x014d, 0x89 => 0x03e8, 0x8a => 0x03e8, 0x8b => 0x0172, + 0x8c => 0x0263, 0x8d => 0x030a, 0x8e => 0x03e8, 0x8f => 0x016d, + 0x90 => 0x0379, 0x91 => 0x0116, 0x92 => 0x0116, 0x93 => 0x0263, + 0x94 => 0x03b0, 0x95 => 0x0263, 0x96 => 0x0116, 0x97 => 0x022c, + 0x98 => 0x022c, 0x99 => 0x0263, 0x9a => 0x022c, 0x9b => 0x029b, + 0x9c => 0x0248, 0x9d => 0x029b, 0x9e => 0x02d2, 0x9f => 0x022c, + 0xa0 => 0x02d2, 0xa1 => 0x022c, 0xa2 => 0x022c, 0xa3 => 0x022c, + 0xa4 => 0x02d2, 0xa5 => 0x02d2, 0xa6 => 0x022c, 0xa7 => 0x02d2, + 0xa8 => 0x0263, 0xa9 => 0x029b, 0xaa => 0x02d2, 0xab => 0xfa, + 0xac => 0x02e1, 0xad => 0x029b, 0xae => 0x022c, 0xaf => 0x022c, + 0xb0 => 0x02d2, 0xb1 => 0x0116, 0xb2 => 0x022c, 0xb3 => 0x0263, + 0xb4 => 0x02d2, 0xb5 => 0x022c, 0xb6 => 0x029b, 0xb7 => 0x022c, + 0xb8 => 0x022c, 0xb9 => 0x0116, 0xba => 0x01ee, 0xbb => 0x02d2, + 0xbc => 0x030a, 0xbd => 0x0263, 0xbe => 0x022c, 0xbf => 0x02d2, + 0xc0 => 0x0185, 0xc1 => 0x022c, 0xc2 => 0x0263, 0xc3 => 0x029b, + 0xc4 => 0x030a, 0xc5 => 0x02d2, 0xc6 => 0x029b, 0xc7 => 0x02e7, + 0xc8 => 0x02d2, 0xc9 => 0x0263, 0xca => 0x014d, 0xcb => 0x030a, + 0xcc => 0x02d2, 0xcd => 0x02d2, 0xce => 0x0248, 0xcf => 0x0263, + 0xd0 => 0x0263, 0xd1 => 0x01ee, 0xd2 => 0x022c, 0xd3 => 0x02d2, + 0xd4 => 0x0116, 0xd5 => 0x029b, 0xd6 => 0x022c, 0xd7 => 0x022c, + 0xd8 => 0x022c, 0xd9 => 0x0263, 0xda => 0x0263, 0xdb => 0x02d2, + 0xdc => 0x0116, 0xdd => 0x0248, 0xde => 0x0118, 0xdf => 0x02e1, + 0xe0 => 0x030a, 0xe1 => 0x0116, 0xe2 => 0x0258, 0xe3 => 0x029b, + 0xe4 => 0x0185, 0xe5 => 0x0263, 0xe6 => 0x0263, 0xe7 => 0x0263, + 0xe8 => 0x0225, 0xe9 => 0x02d2, 0xea => 0x02d2, 0xeb => 0x0116, + 0xec => 0x0185, 0xed => 0x022c, 0xee => 0x02d2, 0xef => 0x02d2, + 0xf0 => 0x02d2, 0xf1 => 0x022c, 0xf2 => 0x01f4, 0xf3 => 0x0116, + 0xf4 => 0x030a, 0xf5 => 0x0263, 0xf6 => 0x022c, 0xf7 => 0x022c, + 0xf8 => 0x0116, 0xf9 => 0x030a, 0xfa => 0x02d2, 0xfb => 0x0264, + 0xfc => 0x0263, 0xfd => 0x014d, 0xfe => 0x030a, 0xff => 0x0263, + 0x0100 => 0x0116, 0x0101 => 0x0263, 0x0102 => 0x029b, 0x0103 => 0x0263, + 0x0104 => 0x0342, 0x0105 => 0x029b, 0x0106 => 0x0190, 0x0107 => 0x02d2, + 0x0108 => 0x0263, 0x0109 => 0x03e8, 0x010a => 0x022c, 0x010b => 0x0116, + 0x010c => 0x0116, 0x010d => 0x0263, 0x010e => 0x0342, 0x010f => 0x0225, + 0x0110 => 0x0263, 0x0111 => 0x0263, 0x0112 => 0x02d2, 0x0113 => 0x029b, + 0x0114 => 0x022c, 0x0115 => 0x0263, 0x0116 => 0x0342, 0x0117 => 0x029b, + 0x0118 => 0x029b, 0x0119 => 0x030a, 0x011a => 0x0190, 0x011b => 0x0263, + 0x011c => 0x02d2, 0x011d => 0x0263, 0x011e => 0x0225, 0x011f => 0x02d2, + 0x0120 => 0x0185, 0x0121 => 0x02d2, 0x0122 => 0x0263, 0x0123 => 0x02d2, + 0x0124 => 0x0263, 0x0125 => 0x02d2, 0x0126 => 0x02d2, 0x0127 => 0x02d2, + 0x0128 => 0x030a, 0x0129 => 0x01f4, 0x012a => 0x029b, 0x012b => 0x0116, + 0x012c => 0x022c, 0x012d => 0x0248, 0x012e => 0x0116, 0x012f => 0x0263, + 0x0130 => 0x014d, 0x0131 => 0x0248, 0x0132 => 0x0263, 0x0133 => 0x0263, + 0x0134 => 0x0225, 0x0135 => 0x0263, 0x0136 => 0x0263, 0x0137 => 0x01f4, + 0x0138 => 0x0263, 0x0139 => 0x014d, 0x013a => 0x0116, 0x013b => 0x022c, + ); + + /* The cmap table is similarly synthesized. + */ + $cmapData = array( + 0x20 => 0x01, 0x21 => 0x02, 0x22 => 0x03, 0x23 => 0x04, + 0x24 => 0x05, 0x25 => 0x06, 0x26 => 0x07, 0x2019 => 0x08, + 0x28 => 0x09, 0x29 => 0x0a, 0x2a => 0x0b, 0x2b => 0x0c, + 0x2c => 0x0d, 0x2d => 0x0e, 0x2e => 0x0f, 0x2f => 0x10, + 0x30 => 0x11, 0x31 => 0x12, 0x32 => 0x13, 0x33 => 0x14, + 0x34 => 0x15, 0x35 => 0x16, 0x36 => 0x17, 0x37 => 0x18, + 0x38 => 0x19, 0x39 => 0x1a, 0x3a => 0x1b, 0x3b => 0x1c, + 0x3c => 0x1d, 0x3d => 0x1e, 0x3e => 0x1f, 0x3f => 0x20, + 0x40 => 0x21, 0x41 => 0x22, 0x42 => 0x23, 0x43 => 0x24, + 0x44 => 0x25, 0x45 => 0x26, 0x46 => 0x27, 0x47 => 0x28, + 0x48 => 0x29, 0x49 => 0x2a, 0x4a => 0x2b, 0x4b => 0x2c, + 0x4c => 0x2d, 0x4d => 0x2e, 0x4e => 0x2f, 0x4f => 0x30, + 0x50 => 0x31, 0x51 => 0x32, 0x52 => 0x33, 0x53 => 0x34, + 0x54 => 0x35, 0x55 => 0x36, 0x56 => 0x37, 0x57 => 0x38, + 0x58 => 0x39, 0x59 => 0x3a, 0x5a => 0x3b, 0x5b => 0x3c, + 0x5c => 0x3d, 0x5d => 0x3e, 0x5e => 0x3f, 0x5f => 0x40, + 0x2018 => 0x41, 0x61 => 0x42, 0x62 => 0x43, 0x63 => 0x44, + 0x64 => 0x45, 0x65 => 0x46, 0x66 => 0x47, 0x67 => 0x48, + 0x68 => 0x49, 0x69 => 0x4a, 0x6a => 0x4b, 0x6b => 0x4c, + 0x6c => 0x4d, 0x6d => 0x4e, 0x6e => 0x4f, 0x6f => 0x50, + 0x70 => 0x51, 0x71 => 0x52, 0x72 => 0x53, 0x73 => 0x54, + 0x74 => 0x55, 0x75 => 0x56, 0x76 => 0x57, 0x77 => 0x58, + 0x78 => 0x59, 0x79 => 0x5a, 0x7a => 0x5b, 0x7b => 0x5c, + 0x7c => 0x5d, 0x7d => 0x5e, 0x7e => 0x5f, 0xa1 => 0x60, + 0xa2 => 0x61, 0xa3 => 0x62, 0x2044 => 0x63, 0xa5 => 0x64, + 0x0192 => 0x65, 0xa7 => 0x66, 0xa4 => 0x67, 0x27 => 0x68, + 0x201c => 0x69, 0xab => 0x6a, 0x2039 => 0x6b, 0x203a => 0x6c, + 0xfb01 => 0x6d, 0xfb02 => 0x6e, 0x2013 => 0x6f, 0x2020 => 0x70, + 0x2021 => 0x71, 0xb7 => 0x72, 0xb6 => 0x73, 0x2022 => 0x74, + 0x201a => 0x75, 0x201e => 0x76, 0x201d => 0x77, 0xbb => 0x78, + 0x2026 => 0x79, 0x2030 => 0x7a, 0xbf => 0x7b, 0x60 => 0x7c, + 0xb4 => 0x7d, 0x02c6 => 0x7e, 0x02dc => 0x7f, 0xaf => 0x80, + 0x02d8 => 0x81, 0x02d9 => 0x82, 0xa8 => 0x83, 0x02da => 0x84, + 0xb8 => 0x85, 0x02dd => 0x86, 0x02db => 0x87, 0x02c7 => 0x88, + 0x2014 => 0x89, 0xc6 => 0x8a, 0xaa => 0x8b, 0x0141 => 0x8c, + 0xd8 => 0x8d, 0x0152 => 0x8e, 0xba => 0x8f, 0xe6 => 0x90, + 0x0131 => 0x91, 0x0142 => 0x92, 0xf8 => 0x93, 0x0153 => 0x94, + 0xdf => 0x95, 0xcf => 0x96, 0xe9 => 0x97, 0x0103 => 0x98, + 0x0171 => 0x99, 0x011b => 0x9a, 0x0178 => 0x9b, 0xf7 => 0x9c, + 0xdd => 0x9d, 0xc2 => 0x9e, 0xe1 => 0x9f, 0xdb => 0xa0, + 0xfd => 0xa1, 0x0219 => 0xa2, 0xea => 0xa3, 0x016e => 0xa4, + 0xdc => 0xa5, 0x0105 => 0xa6, 0xda => 0xa7, 0x0173 => 0xa8, + 0xcb => 0xa9, 0x0110 => 0xaa, 0xf6c3 => 0xab, 0xa9 => 0xac, + 0x0112 => 0xad, 0x010d => 0xae, 0xe5 => 0xaf, 0x0145 => 0xb0, + 0x013a => 0xb1, 0xe0 => 0xb2, 0x0162 => 0xb3, 0x0106 => 0xb4, + 0xe3 => 0xb5, 0x0116 => 0xb6, 0x0161 => 0xb7, 0x015f => 0xb8, + 0xed => 0xb9, 0x25ca => 0xba, 0x0158 => 0xbb, 0x0122 => 0xbc, + 0xfb => 0xbd, 0xe2 => 0xbe, 0x0100 => 0xbf, 0x0159 => 0xc0, + 0xe7 => 0xc1, 0x017b => 0xc2, 0xde => 0xc3, 0x014c => 0xc4, + 0x0154 => 0xc5, 0x015a => 0xc6, 0x010f => 0xc7, 0x016a => 0xc8, + 0x016f => 0xc9, 0xb3 => 0xca, 0xd2 => 0xcb, 0xc0 => 0xcc, + 0x0102 => 0xcd, 0xd7 => 0xce, 0xfa => 0xcf, 0x0164 => 0xd0, + 0x2202 => 0xd1, 0xff => 0xd2, 0x0143 => 0xd3, 0xee => 0xd4, + 0xca => 0xd5, 0xe4 => 0xd6, 0xeb => 0xd7, 0x0107 => 0xd8, + 0x0144 => 0xd9, 0x016b => 0xda, 0x0147 => 0xdb, 0xcd => 0xdc, + 0xb1 => 0xdd, 0xa6 => 0xde, 0xae => 0xdf, 0x011e => 0xe0, + 0x0130 => 0xe1, 0x2211 => 0xe2, 0xc8 => 0xe3, 0x0155 => 0xe4, + 0x014d => 0xe5, 0x0179 => 0xe6, 0x017d => 0xe7, 0x2265 => 0xe8, + 0xd0 => 0xe9, 0xc7 => 0xea, 0x013c => 0xeb, 0x0165 => 0xec, + 0x0119 => 0xed, 0x0172 => 0xee, 0xc1 => 0xef, 0xc4 => 0xf0, + 0xe8 => 0xf1, 0x017a => 0xf2, 0x012f => 0xf3, 0xd3 => 0xf4, + 0xf3 => 0xf5, 0x0101 => 0xf6, 0x015b => 0xf7, 0xef => 0xf8, + 0xd4 => 0xf9, 0xd9 => 0xfa, 0x2206 => 0xfb, 0xfe => 0xfc, + 0xb2 => 0xfd, 0xd6 => 0xfe, 0xb5 => 0xff, 0xec => 0x0100, + 0x0151 => 0x0101, 0x0118 => 0x0102, 0x0111 => 0x0103, 0xbe => 0x0104, + 0x015e => 0x0105, 0x013e => 0x0106, 0x0136 => 0x0107, 0x0139 => 0x0108, + 0x2122 => 0x0109, 0x0117 => 0x010a, 0xcc => 0x010b, 0x012a => 0x010c, + 0x013d => 0x010d, 0xbd => 0x010e, 0x2264 => 0x010f, 0xf4 => 0x0110, + 0xf1 => 0x0111, 0x0170 => 0x0112, 0xc9 => 0x0113, 0x0113 => 0x0114, + 0x011f => 0x0115, 0xbc => 0x0116, 0x0160 => 0x0117, 0x0218 => 0x0118, + 0x0150 => 0x0119, 0xb0 => 0x011a, 0xf2 => 0x011b, 0x010c => 0x011c, + 0xf9 => 0x011d, 0x221a => 0x011e, 0x010e => 0x011f, 0x0157 => 0x0120, + 0xd1 => 0x0121, 0xf5 => 0x0122, 0x0156 => 0x0123, 0x013b => 0x0124, + 0xc3 => 0x0125, 0x0104 => 0x0126, 0xc5 => 0x0127, 0xd5 => 0x0128, + 0x017c => 0x0129, 0x011a => 0x012a, 0x012e => 0x012b, 0x0137 => 0x012c, + 0x2212 => 0x012d, 0xce => 0x012e, 0x0148 => 0x012f, 0x0163 => 0x0130, + 0xac => 0x0131, 0xf6 => 0x0132, 0xfc => 0x0133, 0x2260 => 0x0134, + 0x0123 => 0x0135, 0xf0 => 0x0136, 0x017e => 0x0137, 0x0146 => 0x0138, + 0xb9 => 0x0139, 0x012b => 0x013a, 0x20ac => 0x013b); + // require_once 'Zend/Pdf/Cmap.php'; + $this->_cmap = Zend_Pdf_Cmap::cmapWithTypeData( + Zend_Pdf_Cmap::TYPE_BYTE_ENCODING_STATIC, $cmapData); + + + /* Resource dictionary */ + + /* The resource dictionary for the standard fonts is sparse because PDF + * viewers already have all of the metrics data. We only need to provide + * the font name and encoding method. + */ + $this->_resource->BaseFont = new Zend_Pdf_Element_Name('Helvetica-BoldOblique'); + } +} diff --git a/library/Zend/Pdf/Resource/Font/Simple/Standard/HelveticaOblique.php b/library/Zend/Pdf/Resource/Font/Simple/Standard/HelveticaOblique.php new file mode 100644 index 0000000..1f38693 --- /dev/null +++ b/library/Zend/Pdf/Resource/Font/Simple/Standard/HelveticaOblique.php @@ -0,0 +1,307 @@ +_fontNames[Zend_Pdf_Font::NAME_COPYRIGHT]['en'] = + "\x00\x43\x00\x6f\x00\x70\x00\x79\x00\x72\x00\x69\x00\x67\x00\x68\x00" + . "\x74\x00\x20\x00\x28\x00\x63\x00\x29\x00\x20\x00\x31\x00\x39\x00" + . "\x38\x00\x35\x00\x2c\x00\x20\x00\x31\x00\x39\x00\x38\x00\x37\x00" + . "\x2c\x00\x20\x00\x31\x00\x39\x00\x38\x00\x39\x00\x2c\x00\x20\x00" + . "\x31\x00\x39\x00\x39\x00\x30\x00\x2c\x00\x20\x00\x31\x00\x39\x00" + . "\x39\x00\x37\x00\x20\x00\x41\x00\x64\x00\x6f\x00\x62\x00\x65\x00" + . "\x20\x00\x53\x00\x79\x00\x73\x00\x74\x00\x65\x00\x6d\x00\x73\x00" + . "\x20\x00\x49\x00\x6e\x00\x63\x00\x6f\x00\x72\x00\x70\x00\x6f\x00" + . "\x72\x00\x61\x00\x74\x00\x65\x00\x64\x00\x2e\x00\x20\x00\x20\x00" + . "\x41\x00\x6c\x00\x6c\x00\x20\x00\x52\x00\x69\x00\x67\x00\x68\x00" + . "\x74\x00\x73\x00\x20\x00\x52\x00\x65\x00\x73\x00\x65\x00\x72\x00" + . "\x76\x00\x65\x00\x64\x00\x2e\x00\x48\x00\x65\x00\x6c\x00\x76\x00" + . "\x65\x00\x74\x00\x69\x00\x63\x00\x61\x00\x20\x00\x69\x00\x73\x00" + . "\x20\x00\x61\x00\x20\x00\x74\x00\x72\x00\x61\x00\x64\x00\x65\x00" + . "\x6d\x00\x61\x00\x72\x00\x6b\x00\x20\x00\x6f\x00\x66\x00\x20\x00" + . "\x4c\x00\x69\x00\x6e\x00\x6f\x00\x74\x00\x79\x00\x70\x00\x65\x00" + . "\x2d\x00\x48\x00\x65\x00\x6c\x00\x6c\x00\x20\x00\x41\x00\x47\x00" + . "\x20\x00\x61\x00\x6e\x00\x64\x00\x2f\x00\x6f\x00\x72\x00\x20\x00" + . "\x69\x00\x74\x00\x73\x00\x20\x00\x73\x00\x75\x00\x62\x00\x73\x00" + . "\x69\x00\x64\x00\x69\x00\x61\x00\x72\x00\x69\x00\x65\x00\x73\x00" + . "\x2e"; + $this->_fontNames[Zend_Pdf_Font::NAME_FAMILY]['en'] = + "\x00\x48\x00\x65\x00\x6c\x00\x76\x00\x65\x00\x74\x00\x69\x00\x63\x00" + . "\x61"; + $this->_fontNames[Zend_Pdf_Font::NAME_STYLE]['en'] = + "\x00\x4d\x00\x65\x00\x64\x00\x69\x00\x75\x00\x6d"; + $this->_fontNames[Zend_Pdf_Font::NAME_ID]['en'] = + "\x00\x34\x00\x33\x00\x30\x00\x35\x00\x35"; + $this->_fontNames[Zend_Pdf_Font::NAME_FULL]['en'] = + "\x00\x48\x00\x65\x00\x6c\x00\x76\x00\x65\x00\x74\x00\x69\x00\x63\x00" + . "\x61\x00\x2d\x00\x4f\x00\x62\x00\x6c\x00\x69\x00\x71\x00\x75\x00" + . "\x65\x00\x20\x00\x4d\x00\x65\x00\x64\x00\x69\x00\x75\x00\x6d"; + $this->_fontNames[Zend_Pdf_Font::NAME_VERSION]['en'] = + "\x00\x30\x00\x30\x00\x32\x00\x2e\x00\x30\x00\x30\x00\x30"; + $this->_fontNames[Zend_Pdf_Font::NAME_POSTSCRIPT]['en'] = + "\x00\x48\x00\x65\x00\x6c\x00\x76\x00\x65\x00\x74\x00\x69\x00\x63\x00" + . "\x61\x00\x2d\x00\x4f\x00\x62\x00\x6c\x00\x69\x00\x71\x00\x75\x00" + . "\x65"; + + $this->_isBold = false; + $this->_isItalic = true; + $this->_isMonospaced = false; + + $this->_underlinePosition = -100; + $this->_underlineThickness = 50; + $this->_strikePosition = 225; + $this->_strikeThickness = 50; + + $this->_unitsPerEm = 1000; + + $this->_ascent = 718; + $this->_descent = -207; + $this->_lineGap = 275; + + /* The glyph numbers assigned here are synthetic; they do not match the + * actual glyph numbers used by the font. This is not a big deal though + * since this data never makes it to the PDF file. It is only used + * internally for layout calculations. + */ + $this->_glyphWidths = array( + 0x00 => 0x01f4, 0x01 => 0x0116, 0x02 => 0x0116, 0x03 => 0x0163, + 0x04 => 0x022c, 0x05 => 0x022c, 0x06 => 0x0379, 0x07 => 0x029b, + 0x08 => 0xde, 0x09 => 0x014d, 0x0a => 0x014d, 0x0b => 0x0185, + 0x0c => 0x0248, 0x0d => 0x0116, 0x0e => 0x014d, 0x0f => 0x0116, + 0x10 => 0x0116, 0x11 => 0x022c, 0x12 => 0x022c, 0x13 => 0x022c, + 0x14 => 0x022c, 0x15 => 0x022c, 0x16 => 0x022c, 0x17 => 0x022c, + 0x18 => 0x022c, 0x19 => 0x022c, 0x1a => 0x022c, 0x1b => 0x0116, + 0x1c => 0x0116, 0x1d => 0x0248, 0x1e => 0x0248, 0x1f => 0x0248, + 0x20 => 0x022c, 0x21 => 0x03f7, 0x22 => 0x029b, 0x23 => 0x029b, + 0x24 => 0x02d2, 0x25 => 0x02d2, 0x26 => 0x029b, 0x27 => 0x0263, + 0x28 => 0x030a, 0x29 => 0x02d2, 0x2a => 0x0116, 0x2b => 0x01f4, + 0x2c => 0x029b, 0x2d => 0x022c, 0x2e => 0x0341, 0x2f => 0x02d2, + 0x30 => 0x030a, 0x31 => 0x029b, 0x32 => 0x030a, 0x33 => 0x02d2, + 0x34 => 0x029b, 0x35 => 0x0263, 0x36 => 0x02d2, 0x37 => 0x029b, + 0x38 => 0x03b0, 0x39 => 0x029b, 0x3a => 0x029b, 0x3b => 0x0263, + 0x3c => 0x0116, 0x3d => 0x0116, 0x3e => 0x0116, 0x3f => 0x01d5, + 0x40 => 0x022c, 0x41 => 0xde, 0x42 => 0x022c, 0x43 => 0x022c, + 0x44 => 0x01f4, 0x45 => 0x022c, 0x46 => 0x022c, 0x47 => 0x0116, + 0x48 => 0x022c, 0x49 => 0x022c, 0x4a => 0xde, 0x4b => 0xde, + 0x4c => 0x01f4, 0x4d => 0xde, 0x4e => 0x0341, 0x4f => 0x022c, + 0x50 => 0x022c, 0x51 => 0x022c, 0x52 => 0x022c, 0x53 => 0x014d, + 0x54 => 0x01f4, 0x55 => 0x0116, 0x56 => 0x022c, 0x57 => 0x01f4, + 0x58 => 0x02d2, 0x59 => 0x01f4, 0x5a => 0x01f4, 0x5b => 0x01f4, + 0x5c => 0x014e, 0x5d => 0x0104, 0x5e => 0x014e, 0x5f => 0x0248, + 0x60 => 0x014d, 0x61 => 0x022c, 0x62 => 0x022c, 0x63 => 0xa7, + 0x64 => 0x022c, 0x65 => 0x022c, 0x66 => 0x022c, 0x67 => 0x022c, + 0x68 => 0xbf, 0x69 => 0x014d, 0x6a => 0x022c, 0x6b => 0x014d, + 0x6c => 0x014d, 0x6d => 0x01f4, 0x6e => 0x01f4, 0x6f => 0x022c, + 0x70 => 0x022c, 0x71 => 0x022c, 0x72 => 0x0116, 0x73 => 0x0219, + 0x74 => 0x015e, 0x75 => 0xde, 0x76 => 0x014d, 0x77 => 0x014d, + 0x78 => 0x022c, 0x79 => 0x03e8, 0x7a => 0x03e8, 0x7b => 0x0263, + 0x7c => 0x014d, 0x7d => 0x014d, 0x7e => 0x014d, 0x7f => 0x014d, + 0x80 => 0x014d, 0x81 => 0x014d, 0x82 => 0x014d, 0x83 => 0x014d, + 0x84 => 0x014d, 0x85 => 0x014d, 0x86 => 0x014d, 0x87 => 0x014d, + 0x88 => 0x014d, 0x89 => 0x03e8, 0x8a => 0x03e8, 0x8b => 0x0172, + 0x8c => 0x022c, 0x8d => 0x030a, 0x8e => 0x03e8, 0x8f => 0x016d, + 0x90 => 0x0379, 0x91 => 0x0116, 0x92 => 0xde, 0x93 => 0x0263, + 0x94 => 0x03b0, 0x95 => 0x0263, 0x96 => 0x0116, 0x97 => 0x022c, + 0x98 => 0x022c, 0x99 => 0x022c, 0x9a => 0x022c, 0x9b => 0x029b, + 0x9c => 0x0248, 0x9d => 0x029b, 0x9e => 0x029b, 0x9f => 0x022c, + 0xa0 => 0x02d2, 0xa1 => 0x01f4, 0xa2 => 0x01f4, 0xa3 => 0x022c, + 0xa4 => 0x02d2, 0xa5 => 0x02d2, 0xa6 => 0x022c, 0xa7 => 0x02d2, + 0xa8 => 0x022c, 0xa9 => 0x029b, 0xaa => 0x02d2, 0xab => 0xfa, + 0xac => 0x02e1, 0xad => 0x029b, 0xae => 0x01f4, 0xaf => 0x022c, + 0xb0 => 0x02d2, 0xb1 => 0xde, 0xb2 => 0x022c, 0xb3 => 0x0263, + 0xb4 => 0x02d2, 0xb5 => 0x022c, 0xb6 => 0x029b, 0xb7 => 0x01f4, + 0xb8 => 0x01f4, 0xb9 => 0x0116, 0xba => 0x01d7, 0xbb => 0x02d2, + 0xbc => 0x030a, 0xbd => 0x022c, 0xbe => 0x022c, 0xbf => 0x029b, + 0xc0 => 0x014d, 0xc1 => 0x01f4, 0xc2 => 0x0263, 0xc3 => 0x029b, + 0xc4 => 0x030a, 0xc5 => 0x02d2, 0xc6 => 0x029b, 0xc7 => 0x0283, + 0xc8 => 0x02d2, 0xc9 => 0x022c, 0xca => 0x014d, 0xcb => 0x030a, + 0xcc => 0x029b, 0xcd => 0x029b, 0xce => 0x0248, 0xcf => 0x022c, + 0xd0 => 0x0263, 0xd1 => 0x01dc, 0xd2 => 0x01f4, 0xd3 => 0x02d2, + 0xd4 => 0x0116, 0xd5 => 0x029b, 0xd6 => 0x022c, 0xd7 => 0x022c, + 0xd8 => 0x01f4, 0xd9 => 0x022c, 0xda => 0x022c, 0xdb => 0x02d2, + 0xdc => 0x0116, 0xdd => 0x0248, 0xde => 0x0104, 0xdf => 0x02e1, + 0xe0 => 0x030a, 0xe1 => 0x0116, 0xe2 => 0x0258, 0xe3 => 0x029b, + 0xe4 => 0x014d, 0xe5 => 0x022c, 0xe6 => 0x0263, 0xe7 => 0x0263, + 0xe8 => 0x0225, 0xe9 => 0x02d2, 0xea => 0x02d2, 0xeb => 0xde, + 0xec => 0x013d, 0xed => 0x022c, 0xee => 0x02d2, 0xef => 0x029b, + 0xf0 => 0x029b, 0xf1 => 0x022c, 0xf2 => 0x01f4, 0xf3 => 0xde, + 0xf4 => 0x030a, 0xf5 => 0x022c, 0xf6 => 0x022c, 0xf7 => 0x01f4, + 0xf8 => 0x0116, 0xf9 => 0x030a, 0xfa => 0x02d2, 0xfb => 0x0264, + 0xfc => 0x022c, 0xfd => 0x014d, 0xfe => 0x030a, 0xff => 0x022c, + 0x0100 => 0x0116, 0x0101 => 0x022c, 0x0102 => 0x029b, 0x0103 => 0x022c, + 0x0104 => 0x0342, 0x0105 => 0x029b, 0x0106 => 0x012b, 0x0107 => 0x029b, + 0x0108 => 0x022c, 0x0109 => 0x03e8, 0x010a => 0x022c, 0x010b => 0x0116, + 0x010c => 0x0116, 0x010d => 0x022c, 0x010e => 0x0342, 0x010f => 0x0225, + 0x0110 => 0x022c, 0x0111 => 0x022c, 0x0112 => 0x02d2, 0x0113 => 0x029b, + 0x0114 => 0x022c, 0x0115 => 0x022c, 0x0116 => 0x0342, 0x0117 => 0x029b, + 0x0118 => 0x029b, 0x0119 => 0x030a, 0x011a => 0x0190, 0x011b => 0x022c, + 0x011c => 0x02d2, 0x011d => 0x022c, 0x011e => 0x01c5, 0x011f => 0x02d2, + 0x0120 => 0x014d, 0x0121 => 0x02d2, 0x0122 => 0x022c, 0x0123 => 0x02d2, + 0x0124 => 0x022c, 0x0125 => 0x029b, 0x0126 => 0x029b, 0x0127 => 0x029b, + 0x0128 => 0x030a, 0x0129 => 0x01f4, 0x012a => 0x029b, 0x012b => 0x0116, + 0x012c => 0x01f4, 0x012d => 0x0248, 0x012e => 0x0116, 0x012f => 0x022c, + 0x0130 => 0x0116, 0x0131 => 0x0248, 0x0132 => 0x022c, 0x0133 => 0x022c, + 0x0134 => 0x0225, 0x0135 => 0x022c, 0x0136 => 0x022c, 0x0137 => 0x01f4, + 0x0138 => 0x022c, 0x0139 => 0x014d, 0x013a => 0x0116, 0x013b => 0x022c, + ); + + /* The cmap table is similarly synthesized. + */ + $cmapData = array( + 0x20 => 0x01, 0x21 => 0x02, 0x22 => 0x03, 0x23 => 0x04, + 0x24 => 0x05, 0x25 => 0x06, 0x26 => 0x07, 0x2019 => 0x08, + 0x28 => 0x09, 0x29 => 0x0a, 0x2a => 0x0b, 0x2b => 0x0c, + 0x2c => 0x0d, 0x2d => 0x0e, 0x2e => 0x0f, 0x2f => 0x10, + 0x30 => 0x11, 0x31 => 0x12, 0x32 => 0x13, 0x33 => 0x14, + 0x34 => 0x15, 0x35 => 0x16, 0x36 => 0x17, 0x37 => 0x18, + 0x38 => 0x19, 0x39 => 0x1a, 0x3a => 0x1b, 0x3b => 0x1c, + 0x3c => 0x1d, 0x3d => 0x1e, 0x3e => 0x1f, 0x3f => 0x20, + 0x40 => 0x21, 0x41 => 0x22, 0x42 => 0x23, 0x43 => 0x24, + 0x44 => 0x25, 0x45 => 0x26, 0x46 => 0x27, 0x47 => 0x28, + 0x48 => 0x29, 0x49 => 0x2a, 0x4a => 0x2b, 0x4b => 0x2c, + 0x4c => 0x2d, 0x4d => 0x2e, 0x4e => 0x2f, 0x4f => 0x30, + 0x50 => 0x31, 0x51 => 0x32, 0x52 => 0x33, 0x53 => 0x34, + 0x54 => 0x35, 0x55 => 0x36, 0x56 => 0x37, 0x57 => 0x38, + 0x58 => 0x39, 0x59 => 0x3a, 0x5a => 0x3b, 0x5b => 0x3c, + 0x5c => 0x3d, 0x5d => 0x3e, 0x5e => 0x3f, 0x5f => 0x40, + 0x2018 => 0x41, 0x61 => 0x42, 0x62 => 0x43, 0x63 => 0x44, + 0x64 => 0x45, 0x65 => 0x46, 0x66 => 0x47, 0x67 => 0x48, + 0x68 => 0x49, 0x69 => 0x4a, 0x6a => 0x4b, 0x6b => 0x4c, + 0x6c => 0x4d, 0x6d => 0x4e, 0x6e => 0x4f, 0x6f => 0x50, + 0x70 => 0x51, 0x71 => 0x52, 0x72 => 0x53, 0x73 => 0x54, + 0x74 => 0x55, 0x75 => 0x56, 0x76 => 0x57, 0x77 => 0x58, + 0x78 => 0x59, 0x79 => 0x5a, 0x7a => 0x5b, 0x7b => 0x5c, + 0x7c => 0x5d, 0x7d => 0x5e, 0x7e => 0x5f, 0xa1 => 0x60, + 0xa2 => 0x61, 0xa3 => 0x62, 0x2044 => 0x63, 0xa5 => 0x64, + 0x0192 => 0x65, 0xa7 => 0x66, 0xa4 => 0x67, 0x27 => 0x68, + 0x201c => 0x69, 0xab => 0x6a, 0x2039 => 0x6b, 0x203a => 0x6c, + 0xfb01 => 0x6d, 0xfb02 => 0x6e, 0x2013 => 0x6f, 0x2020 => 0x70, + 0x2021 => 0x71, 0xb7 => 0x72, 0xb6 => 0x73, 0x2022 => 0x74, + 0x201a => 0x75, 0x201e => 0x76, 0x201d => 0x77, 0xbb => 0x78, + 0x2026 => 0x79, 0x2030 => 0x7a, 0xbf => 0x7b, 0x60 => 0x7c, + 0xb4 => 0x7d, 0x02c6 => 0x7e, 0x02dc => 0x7f, 0xaf => 0x80, + 0x02d8 => 0x81, 0x02d9 => 0x82, 0xa8 => 0x83, 0x02da => 0x84, + 0xb8 => 0x85, 0x02dd => 0x86, 0x02db => 0x87, 0x02c7 => 0x88, + 0x2014 => 0x89, 0xc6 => 0x8a, 0xaa => 0x8b, 0x0141 => 0x8c, + 0xd8 => 0x8d, 0x0152 => 0x8e, 0xba => 0x8f, 0xe6 => 0x90, + 0x0131 => 0x91, 0x0142 => 0x92, 0xf8 => 0x93, 0x0153 => 0x94, + 0xdf => 0x95, 0xcf => 0x96, 0xe9 => 0x97, 0x0103 => 0x98, + 0x0171 => 0x99, 0x011b => 0x9a, 0x0178 => 0x9b, 0xf7 => 0x9c, + 0xdd => 0x9d, 0xc2 => 0x9e, 0xe1 => 0x9f, 0xdb => 0xa0, + 0xfd => 0xa1, 0x0219 => 0xa2, 0xea => 0xa3, 0x016e => 0xa4, + 0xdc => 0xa5, 0x0105 => 0xa6, 0xda => 0xa7, 0x0173 => 0xa8, + 0xcb => 0xa9, 0x0110 => 0xaa, 0xf6c3 => 0xab, 0xa9 => 0xac, + 0x0112 => 0xad, 0x010d => 0xae, 0xe5 => 0xaf, 0x0145 => 0xb0, + 0x013a => 0xb1, 0xe0 => 0xb2, 0x0162 => 0xb3, 0x0106 => 0xb4, + 0xe3 => 0xb5, 0x0116 => 0xb6, 0x0161 => 0xb7, 0x015f => 0xb8, + 0xed => 0xb9, 0x25ca => 0xba, 0x0158 => 0xbb, 0x0122 => 0xbc, + 0xfb => 0xbd, 0xe2 => 0xbe, 0x0100 => 0xbf, 0x0159 => 0xc0, + 0xe7 => 0xc1, 0x017b => 0xc2, 0xde => 0xc3, 0x014c => 0xc4, + 0x0154 => 0xc5, 0x015a => 0xc6, 0x010f => 0xc7, 0x016a => 0xc8, + 0x016f => 0xc9, 0xb3 => 0xca, 0xd2 => 0xcb, 0xc0 => 0xcc, + 0x0102 => 0xcd, 0xd7 => 0xce, 0xfa => 0xcf, 0x0164 => 0xd0, + 0x2202 => 0xd1, 0xff => 0xd2, 0x0143 => 0xd3, 0xee => 0xd4, + 0xca => 0xd5, 0xe4 => 0xd6, 0xeb => 0xd7, 0x0107 => 0xd8, + 0x0144 => 0xd9, 0x016b => 0xda, 0x0147 => 0xdb, 0xcd => 0xdc, + 0xb1 => 0xdd, 0xa6 => 0xde, 0xae => 0xdf, 0x011e => 0xe0, + 0x0130 => 0xe1, 0x2211 => 0xe2, 0xc8 => 0xe3, 0x0155 => 0xe4, + 0x014d => 0xe5, 0x0179 => 0xe6, 0x017d => 0xe7, 0x2265 => 0xe8, + 0xd0 => 0xe9, 0xc7 => 0xea, 0x013c => 0xeb, 0x0165 => 0xec, + 0x0119 => 0xed, 0x0172 => 0xee, 0xc1 => 0xef, 0xc4 => 0xf0, + 0xe8 => 0xf1, 0x017a => 0xf2, 0x012f => 0xf3, 0xd3 => 0xf4, + 0xf3 => 0xf5, 0x0101 => 0xf6, 0x015b => 0xf7, 0xef => 0xf8, + 0xd4 => 0xf9, 0xd9 => 0xfa, 0x2206 => 0xfb, 0xfe => 0xfc, + 0xb2 => 0xfd, 0xd6 => 0xfe, 0xb5 => 0xff, 0xec => 0x0100, + 0x0151 => 0x0101, 0x0118 => 0x0102, 0x0111 => 0x0103, 0xbe => 0x0104, + 0x015e => 0x0105, 0x013e => 0x0106, 0x0136 => 0x0107, 0x0139 => 0x0108, + 0x2122 => 0x0109, 0x0117 => 0x010a, 0xcc => 0x010b, 0x012a => 0x010c, + 0x013d => 0x010d, 0xbd => 0x010e, 0x2264 => 0x010f, 0xf4 => 0x0110, + 0xf1 => 0x0111, 0x0170 => 0x0112, 0xc9 => 0x0113, 0x0113 => 0x0114, + 0x011f => 0x0115, 0xbc => 0x0116, 0x0160 => 0x0117, 0x0218 => 0x0118, + 0x0150 => 0x0119, 0xb0 => 0x011a, 0xf2 => 0x011b, 0x010c => 0x011c, + 0xf9 => 0x011d, 0x221a => 0x011e, 0x010e => 0x011f, 0x0157 => 0x0120, + 0xd1 => 0x0121, 0xf5 => 0x0122, 0x0156 => 0x0123, 0x013b => 0x0124, + 0xc3 => 0x0125, 0x0104 => 0x0126, 0xc5 => 0x0127, 0xd5 => 0x0128, + 0x017c => 0x0129, 0x011a => 0x012a, 0x012e => 0x012b, 0x0137 => 0x012c, + 0x2212 => 0x012d, 0xce => 0x012e, 0x0148 => 0x012f, 0x0163 => 0x0130, + 0xac => 0x0131, 0xf6 => 0x0132, 0xfc => 0x0133, 0x2260 => 0x0134, + 0x0123 => 0x0135, 0xf0 => 0x0136, 0x017e => 0x0137, 0x0146 => 0x0138, + 0xb9 => 0x0139, 0x012b => 0x013a, 0x20ac => 0x013b); + // require_once 'Zend/Pdf/Cmap.php'; + $this->_cmap = Zend_Pdf_Cmap::cmapWithTypeData( + Zend_Pdf_Cmap::TYPE_BYTE_ENCODING_STATIC, $cmapData); + + + /* Resource dictionary */ + + /* The resource dictionary for the standard fonts is sparse because PDF + * viewers already have all of the metrics data. We only need to provide + * the font name and encoding method. + */ + $this->_resource->BaseFont = new Zend_Pdf_Element_Name('Helvetica-Oblique'); + } +} diff --git a/library/Zend/Pdf/Resource/Font/Simple/Standard/Symbol.php b/library/Zend/Pdf/Resource/Font/Simple/Standard/Symbol.php new file mode 100644 index 0000000..f22138c --- /dev/null +++ b/library/Zend/Pdf/Resource/Font/Simple/Standard/Symbol.php @@ -0,0 +1,465 @@ + "\x20", 0x21 => "\x21", 0x2200 => "\x22", 0x23 => "\x23", + 0x2203 => "\x24", 0x25 => "\x25", 0x26 => "\x26", 0x220b => "\x27", + 0x28 => "\x28", 0x29 => "\x29", 0x2217 => "\x2a", 0x2b => "\x2b", + 0x2c => "\x2c", 0x2212 => "\x2d", 0x2e => "\x2e", 0x2f => "\x2f", + 0x30 => "\x30", 0x31 => "\x31", 0x32 => "\x32", 0x33 => "\x33", + 0x34 => "\x34", 0x35 => "\x35", 0x36 => "\x36", 0x37 => "\x37", + 0x38 => "\x38", 0x39 => "\x39", 0x3a => "\x3a", 0x3b => "\x3b", + 0x3c => "\x3c", 0x3d => "\x3d", 0x3e => "\x3e", 0x3f => "\x3f", + 0x2245 => "\x40", 0x0391 => "\x41", 0x0392 => "\x42", 0x03a7 => "\x43", + 0x2206 => "\x44", 0x0395 => "\x45", 0x03a6 => "\x46", 0x0393 => "\x47", + 0x0397 => "\x48", 0x0399 => "\x49", 0x03d1 => "\x4a", 0x039a => "\x4b", + 0x039b => "\x4c", 0x039c => "\x4d", 0x039d => "\x4e", 0x039f => "\x4f", + 0x03a0 => "\x50", 0x0398 => "\x51", 0x03a1 => "\x52", 0x03a3 => "\x53", + 0x03a4 => "\x54", 0x03a5 => "\x55", 0x03c2 => "\x56", 0x2126 => "\x57", + 0x039e => "\x58", 0x03a8 => "\x59", 0x0396 => "\x5a", 0x5b => "\x5b", + 0x2234 => "\x5c", 0x5d => "\x5d", 0x22a5 => "\x5e", 0x5f => "\x5f", + 0xf8e5 => "\x60", 0x03b1 => "\x61", 0x03b2 => "\x62", 0x03c7 => "\x63", + 0x03b4 => "\x64", 0x03b5 => "\x65", 0x03c6 => "\x66", 0x03b3 => "\x67", + 0x03b7 => "\x68", 0x03b9 => "\x69", 0x03d5 => "\x6a", 0x03ba => "\x6b", + 0x03bb => "\x6c", 0xb5 => "\x6d", 0x03bd => "\x6e", 0x03bf => "\x6f", + 0x03c0 => "\x70", 0x03b8 => "\x71", 0x03c1 => "\x72", 0x03c3 => "\x73", + 0x03c4 => "\x74", 0x03c5 => "\x75", 0x03d6 => "\x76", 0x03c9 => "\x77", + 0x03be => "\x78", 0x03c8 => "\x79", 0x03b6 => "\x7a", 0x7b => "\x7b", + 0x7c => "\x7c", 0x7d => "\x7d", 0x223c => "\x7e", 0x20ac => "\xa0", + 0x03d2 => "\xa1", 0x2032 => "\xa2", 0x2264 => "\xa3", 0x2044 => "\xa4", + 0x221e => "\xa5", 0x0192 => "\xa6", 0x2663 => "\xa7", 0x2666 => "\xa8", + 0x2665 => "\xa9", 0x2660 => "\xaa", 0x2194 => "\xab", 0x2190 => "\xac", + 0x2191 => "\xad", 0x2192 => "\xae", 0x2193 => "\xaf", 0xb0 => "\xb0", + 0xb1 => "\xb1", 0x2033 => "\xb2", 0x2265 => "\xb3", 0xd7 => "\xb4", + 0x221d => "\xb5", 0x2202 => "\xb6", 0x2022 => "\xb7", 0xf7 => "\xb8", + 0x2260 => "\xb9", 0x2261 => "\xba", 0x2248 => "\xbb", 0x2026 => "\xbc", + 0xf8e6 => "\xbd", 0xf8e7 => "\xbe", 0x21b5 => "\xbf", 0x2135 => "\xc0", + 0x2111 => "\xc1", 0x211c => "\xc2", 0x2118 => "\xc3", 0x2297 => "\xc4", + 0x2295 => "\xc5", 0x2205 => "\xc6", 0x2229 => "\xc7", 0x222a => "\xc8", + 0x2283 => "\xc9", 0x2287 => "\xca", 0x2284 => "\xcb", 0x2282 => "\xcc", + 0x2286 => "\xcd", 0x2208 => "\xce", 0x2209 => "\xcf", 0x2220 => "\xd0", + 0x2207 => "\xd1", 0xf6da => "\xd2", 0xf6d9 => "\xd3", 0xf6db => "\xd4", + 0x220f => "\xd5", 0x221a => "\xd6", 0x22c5 => "\xd7", 0xac => "\xd8", + 0x2227 => "\xd9", 0x2228 => "\xda", 0x21d4 => "\xdb", 0x21d0 => "\xdc", + 0x21d1 => "\xdd", 0x21d2 => "\xde", 0x21d3 => "\xdf", 0x25ca => "\xe0", + 0x2329 => "\xe1", 0xf8e8 => "\xe2", 0xf8e9 => "\xe3", 0xf8ea => "\xe4", + 0x2211 => "\xe5", 0xf8eb => "\xe6", 0xf8ec => "\xe7", 0xf8ed => "\xe8", + 0xf8ee => "\xe9", 0xf8ef => "\xea", 0xf8f0 => "\xeb", 0xf8f1 => "\xec", + 0xf8f2 => "\xed", 0xf8f3 => "\xee", 0xf8f4 => "\xef", 0x232a => "\xf1", + 0x222b => "\xf2", 0x2320 => "\xf3", 0xf8f5 => "\xf4", 0x2321 => "\xf5", + 0xf8f6 => "\xf6", 0xf8f7 => "\xf7", 0xf8f8 => "\xf8", 0xf8f9 => "\xf9", + 0xf8fa => "\xfa", 0xf8fb => "\xfb", 0xf8fc => "\xfc", 0xf8fd => "\xfd", + 0xf8fe => "\xfe"); + + /** + * Array for conversion from special font encoding to local encoding. + * See {@link decodeString()}. + * @var array + */ + protected $_fromFontEncoding = array( + 0x20 => "\x00\x20", 0x21 => "\x00\x21", 0x22 => "\x22\x00", + 0x23 => "\x00\x23", 0x24 => "\x22\x03", 0x25 => "\x00\x25", + 0x26 => "\x00\x26", 0x27 => "\x22\x0b", 0x28 => "\x00\x28", + 0x29 => "\x00\x29", 0x2a => "\x22\x17", 0x2b => "\x00\x2b", + 0x2c => "\x00\x2c", 0x2d => "\x22\x12", 0x2e => "\x00\x2e", + 0x2f => "\x00\x2f", 0x30 => "\x00\x30", 0x31 => "\x00\x31", + 0x32 => "\x00\x32", 0x33 => "\x00\x33", 0x34 => "\x00\x34", + 0x35 => "\x00\x35", 0x36 => "\x00\x36", 0x37 => "\x00\x37", + 0x38 => "\x00\x38", 0x39 => "\x00\x39", 0x3a => "\x00\x3a", + 0x3b => "\x00\x3b", 0x3c => "\x00\x3c", 0x3d => "\x00\x3d", + 0x3e => "\x00\x3e", 0x3f => "\x00\x3f", 0x40 => "\x22\x45", + 0x41 => "\x03\x91", 0x42 => "\x03\x92", 0x43 => "\x03\xa7", + 0x44 => "\x22\x06", 0x45 => "\x03\x95", 0x46 => "\x03\xa6", + 0x47 => "\x03\x93", 0x48 => "\x03\x97", 0x49 => "\x03\x99", + 0x4a => "\x03\xd1", 0x4b => "\x03\x9a", 0x4c => "\x03\x9b", + 0x4d => "\x03\x9c", 0x4e => "\x03\x9d", 0x4f => "\x03\x9f", + 0x50 => "\x03\xa0", 0x51 => "\x03\x98", 0x52 => "\x03\xa1", + 0x53 => "\x03\xa3", 0x54 => "\x03\xa4", 0x55 => "\x03\xa5", + 0x56 => "\x03\xc2", 0x57 => "\x21\x26", 0x58 => "\x03\x9e", + 0x59 => "\x03\xa8", 0x5a => "\x03\x96", 0x5b => "\x00\x5b", + 0x5c => "\x22\x34", 0x5d => "\x00\x5d", 0x5e => "\x22\xa5", + 0x5f => "\x00\x5f", 0x60 => "\xf8\xe5", 0x61 => "\x03\xb1", + 0x62 => "\x03\xb2", 0x63 => "\x03\xc7", 0x64 => "\x03\xb4", + 0x65 => "\x03\xb5", 0x66 => "\x03\xc6", 0x67 => "\x03\xb3", + 0x68 => "\x03\xb7", 0x69 => "\x03\xb9", 0x6a => "\x03\xd5", + 0x6b => "\x03\xba", 0x6c => "\x03\xbb", 0x6d => "\x00\xb5", + 0x6e => "\x03\xbd", 0x6f => "\x03\xbf", 0x70 => "\x03\xc0", + 0x71 => "\x03\xb8", 0x72 => "\x03\xc1", 0x73 => "\x03\xc3", + 0x74 => "\x03\xc4", 0x75 => "\x03\xc5", 0x76 => "\x03\xd6", + 0x77 => "\x03\xc9", 0x78 => "\x03\xbe", 0x79 => "\x03\xc8", + 0x7a => "\x03\xb6", 0x7b => "\x00\x7b", 0x7c => "\x00\x7c", + 0x7d => "\x00\x7d", 0x7e => "\x22\x3c", 0xa0 => "\x20\xac", + 0xa1 => "\x03\xd2", 0xa2 => "\x20\x32", 0xa3 => "\x22\x64", + 0xa4 => "\x20\x44", 0xa5 => "\x22\x1e", 0xa6 => "\x01\x92", + 0xa7 => "\x26\x63", 0xa8 => "\x26\x66", 0xa9 => "\x26\x65", + 0xaa => "\x26\x60", 0xab => "\x21\x94", 0xac => "\x21\x90", + 0xad => "\x21\x91", 0xae => "\x21\x92", 0xaf => "\x21\x93", + 0xb0 => "\x00\xb0", 0xb1 => "\x00\xb1", 0xb2 => "\x20\x33", + 0xb3 => "\x22\x65", 0xb4 => "\x00\xd7", 0xb5 => "\x22\x1d", + 0xb6 => "\x22\x02", 0xb7 => "\x20\x22", 0xb8 => "\x00\xf7", + 0xb9 => "\x22\x60", 0xba => "\x22\x61", 0xbb => "\x22\x48", + 0xbc => "\x20\x26", 0xbd => "\xf8\xe6", 0xbe => "\xf8\xe7", + 0xbf => "\x21\xb5", 0xc0 => "\x21\x35", 0xc1 => "\x21\x11", + 0xc2 => "\x21\x1c", 0xc3 => "\x21\x18", 0xc4 => "\x22\x97", + 0xc5 => "\x22\x95", 0xc6 => "\x22\x05", 0xc7 => "\x22\x29", + 0xc8 => "\x22\x2a", 0xc9 => "\x22\x83", 0xca => "\x22\x87", + 0xcb => "\x22\x84", 0xcc => "\x22\x82", 0xcd => "\x22\x86", + 0xce => "\x22\x08", 0xcf => "\x22\x09", 0xd0 => "\x22\x20", + 0xd1 => "\x22\x07", 0xd2 => "\xf6\xda", 0xd3 => "\xf6\xd9", + 0xd4 => "\xf6\xdb", 0xd5 => "\x22\x0f", 0xd6 => "\x22\x1a", + 0xd7 => "\x22\xc5", 0xd8 => "\x00\xac", 0xd9 => "\x22\x27", + 0xda => "\x22\x28", 0xdb => "\x21\xd4", 0xdc => "\x21\xd0", + 0xdd => "\x21\xd1", 0xde => "\x21\xd2", 0xdf => "\x21\xd3", + 0xe0 => "\x25\xca", 0xe1 => "\x23\x29", 0xe2 => "\xf8\xe8", + 0xe3 => "\xf8\xe9", 0xe4 => "\xf8\xea", 0xe5 => "\x22\x11", + 0xe6 => "\xf8\xeb", 0xe7 => "\xf8\xec", 0xe8 => "\xf8\xed", + 0xe9 => "\xf8\xee", 0xea => "\xf8\xef", 0xeb => "\xf8\xf0", + 0xec => "\xf8\xf1", 0xed => "\xf8\xf2", 0xee => "\xf8\xf3", + 0xef => "\xf8\xf4", 0xf1 => "\x23\x2a", 0xf2 => "\x22\x2b", + 0xf3 => "\x23\x20", 0xf4 => "\xf8\xf5", 0xf5 => "\x23\x21", + 0xf6 => "\xf8\xf6", 0xf7 => "\xf8\xf7", 0xf8 => "\xf8\xf8", + 0xf9 => "\xf8\xf9", 0xfa => "\xf8\xfa", 0xfb => "\xf8\xfb", + 0xfc => "\xf8\xfc", 0xfd => "\xf8\xfd", 0xfe => "\xf8\xfe", + ); + + + + /**** Public Interface ****/ + + + /* Object Lifecycle */ + + /** + * Object constructor + */ + public function __construct() + { + parent::__construct(); + + + /* Object properties */ + + /* The font names are stored internally as Unicode UTF-16BE-encoded + * strings. Since this information is static, save unnecessary trips + * through iconv() and just use pre-encoded hexidecimal strings. + */ + $this->_fontNames[Zend_Pdf_Font::NAME_COPYRIGHT]['en'] = + "\x00\x43\x00\x6f\x00\x70\x00\x79\x00\x72\x00\x69\x00\x67\x00\x68\x00" + . "\x74\x00\x20\x00\x28\x00\x63\x00\x29\x00\x20\x00\x31\x00\x39\x00" + . "\x38\x00\x35\x00\x2c\x00\x20\x00\x31\x00\x39\x00\x38\x00\x37\x00" + . "\x2c\x00\x20\x00\x31\x00\x39\x00\x38\x00\x39\x00\x2c\x00\x20\x00" + . "\x31\x00\x39\x00\x39\x00\x30\x00\x2c\x00\x20\x00\x31\x00\x39\x00" + . "\x39\x00\x37\x00\x20\x00\x41\x00\x64\x00\x6f\x00\x62\x00\x65\x00" + . "\x20\x00\x53\x00\x79\x00\x73\x00\x74\x00\x65\x00\x6d\x00\x73\x00" + . "\x20\x00\x49\x00\x6e\x00\x63\x00\x6f\x00\x72\x00\x70\x00\x6f\x00" + . "\x72\x00\x61\x00\x74\x00\x65\x00\x64\x00\x2e\x00\x20\x00\x41\x00" + . "\x6c\x00\x6c\x00\x20\x00\x72\x00\x69\x00\x67\x00\x68\x00\x74\x00" + . "\x73\x00\x20\x00\x72\x00\x65\x00\x73\x00\x65\x00\x72\x00\x76\x00" + . "\x65\x00\x64\x00\x2e"; + $this->_fontNames[Zend_Pdf_Font::NAME_FAMILY]['en'] = + "\x00\x53\x00\x79\x00\x6d\x00\x62\x00\x6f\x00\x6c"; + $this->_fontNames[Zend_Pdf_Font::NAME_STYLE]['en'] = + "\x00\x4d\x00\x65\x00\x64\x00\x69\x00\x75\x00\x6d"; + $this->_fontNames[Zend_Pdf_Font::NAME_ID]['en'] = + "\x00\x34\x00\x33\x00\x30\x00\x36\x00\x34"; + $this->_fontNames[Zend_Pdf_Font::NAME_FULL]['en'] = + "\x00\x53\x00\x79\x00\x6d\x00\x62\x00\x6f\x00\x6c\x00\x20\x00\x4d\x00" + . "\x65\x00\x64\x00\x69\x00\x75\x00\x6d"; + $this->_fontNames[Zend_Pdf_Font::NAME_VERSION]['en'] = + "\x00\x30\x00\x30\x00\x31\x00\x2e\x00\x30\x00\x30\x00\x38"; + $this->_fontNames[Zend_Pdf_Font::NAME_POSTSCRIPT]['en'] = + "\x00\x53\x00\x79\x00\x6d\x00\x62\x00\x6f\x00\x6c"; + + $this->_isBold = false; + $this->_isItalic = false; + $this->_isMonospaced = false; + + $this->_underlinePosition = -100; + $this->_underlineThickness = 50; + $this->_strikePosition = 225; + $this->_strikeThickness = 50; + + $this->_unitsPerEm = 1000; + + $this->_ascent = 1000; + $this->_descent = 0; + $this->_lineGap = 200; + + /* The glyph numbers assigned here are synthetic; they do not match the + * actual glyph numbers used by the font. This is not a big deal though + * since this data never makes it to the PDF file. It is only used + * internally for layout calculations. + */ + $this->_glyphWidths = array( + 0x00 => 0x01f4, 0x01 => 0xfa, 0x02 => 0x014d, 0x03 => 0x02c9, + 0x04 => 0x01f4, 0x05 => 0x0225, 0x06 => 0x0341, 0x07 => 0x030a, + 0x08 => 0x01b7, 0x09 => 0x014d, 0x0a => 0x014d, 0x0b => 0x01f4, + 0x0c => 0x0225, 0x0d => 0xfa, 0x0e => 0x0225, 0x0f => 0xfa, + 0x10 => 0x0116, 0x11 => 0x01f4, 0x12 => 0x01f4, 0x13 => 0x01f4, + 0x14 => 0x01f4, 0x15 => 0x01f4, 0x16 => 0x01f4, 0x17 => 0x01f4, + 0x18 => 0x01f4, 0x19 => 0x01f4, 0x1a => 0x01f4, 0x1b => 0x0116, + 0x1c => 0x0116, 0x1d => 0x0225, 0x1e => 0x0225, 0x1f => 0x0225, + 0x20 => 0x01bc, 0x21 => 0x0225, 0x22 => 0x02d2, 0x23 => 0x029b, + 0x24 => 0x02d2, 0x25 => 0x0264, 0x26 => 0x0263, 0x27 => 0x02fb, + 0x28 => 0x025b, 0x29 => 0x02d2, 0x2a => 0x014d, 0x2b => 0x0277, + 0x2c => 0x02d2, 0x2d => 0x02ae, 0x2e => 0x0379, 0x2f => 0x02d2, + 0x30 => 0x02d2, 0x31 => 0x0300, 0x32 => 0x02e5, 0x33 => 0x022c, + 0x34 => 0x0250, 0x35 => 0x0263, 0x36 => 0x02b2, 0x37 => 0x01b7, + 0x38 => 0x0300, 0x39 => 0x0285, 0x3a => 0x031b, 0x3b => 0x0263, + 0x3c => 0x014d, 0x3d => 0x035f, 0x3e => 0x014d, 0x3f => 0x0292, + 0x40 => 0x01f4, 0x41 => 0x01f4, 0x42 => 0x0277, 0x43 => 0x0225, + 0x44 => 0x0225, 0x45 => 0x01ee, 0x46 => 0x01b7, 0x47 => 0x0209, + 0x48 => 0x019b, 0x49 => 0x025b, 0x4a => 0x0149, 0x4b => 0x025b, + 0x4c => 0x0225, 0x4d => 0x0225, 0x4e => 0x0240, 0x4f => 0x0209, + 0x50 => 0x0225, 0x51 => 0x0225, 0x52 => 0x0209, 0x53 => 0x0225, + 0x54 => 0x025b, 0x55 => 0x01b7, 0x56 => 0x0240, 0x57 => 0x02c9, + 0x58 => 0x02ae, 0x59 => 0x01ed, 0x5a => 0x02ae, 0x5b => 0x01ee, + 0x5c => 0x01e0, 0x5d => 0xc8, 0x5e => 0x01e0, 0x5f => 0x0225, + 0x60 => 0x02ee, 0x61 => 0x026c, 0x62 => 0xf7, 0x63 => 0x0225, + 0x64 => 0xa7, 0x65 => 0x02c9, 0x66 => 0x01f4, 0x67 => 0x02f1, + 0x68 => 0x02f1, 0x69 => 0x02f1, 0x6a => 0x02f1, 0x6b => 0x0412, + 0x6c => 0x03db, 0x6d => 0x025b, 0x6e => 0x03db, 0x6f => 0x025b, + 0x70 => 0x0190, 0x71 => 0x0225, 0x72 => 0x019b, 0x73 => 0x0225, + 0x74 => 0x0225, 0x75 => 0x02c9, 0x76 => 0x01ee, 0x77 => 0x01cc, + 0x78 => 0x0225, 0x79 => 0x0225, 0x7a => 0x0225, 0x7b => 0x0225, + 0x7c => 0x03e8, 0x7d => 0x025b, 0x7e => 0x03e8, 0x7f => 0x0292, + 0x80 => 0x0337, 0x81 => 0x02ae, 0x82 => 0x031b, 0x83 => 0x03db, + 0x84 => 0x0300, 0x85 => 0x0300, 0x86 => 0x0337, 0x87 => 0x0300, + 0x88 => 0x0300, 0x89 => 0x02c9, 0x8a => 0x02c9, 0x8b => 0x02c9, + 0x8c => 0x02c9, 0x8d => 0x02c9, 0x8e => 0x02c9, 0x8f => 0x02c9, + 0x90 => 0x0300, 0x91 => 0x02c9, 0x92 => 0x0316, 0x93 => 0x0316, + 0x94 => 0x037a, 0x95 => 0x0337, 0x96 => 0x0225, 0x97 => 0xfa, + 0x98 => 0x02c9, 0x99 => 0x025b, 0x9a => 0x025b, 0x9b => 0x0412, + 0x9c => 0x03db, 0x9d => 0x025b, 0x9e => 0x03db, 0x9f => 0x025b, + 0xa0 => 0x01ee, 0xa1 => 0x0149, 0xa2 => 0x0316, 0xa3 => 0x0316, + 0xa4 => 0x0312, 0xa5 => 0x02c9, 0xa6 => 0x0180, 0xa7 => 0x0180, + 0xa8 => 0x0180, 0xa9 => 0x0180, 0xaa => 0x0180, 0xab => 0x0180, + 0xac => 0x01ee, 0xad => 0x01ee, 0xae => 0x01ee, 0xaf => 0x01ee, + 0xb0 => 0x0149, 0xb1 => 0x0112, 0xb2 => 0x02ae, 0xb3 => 0x02ae, + 0xb4 => 0x02ae, 0xb5 => 0x0180, 0xb6 => 0x0180, 0xb7 => 0x0180, + 0xb8 => 0x0180, 0xb9 => 0x0180, 0xba => 0x0180, 0xbb => 0x01ee, + 0xbc => 0x01ee, 0xbd => 0x01ee, 0xbe => 0x0316); + + /* The cmap table is similarly synthesized. + */ + $cmapData = array( + 0x20 => 0x01, 0x21 => 0x02, 0x2200 => 0x03, 0x23 => 0x04, + 0x2203 => 0x05, 0x25 => 0x06, 0x26 => 0x07, 0x220b => 0x08, + 0x28 => 0x09, 0x29 => 0x0a, 0x2217 => 0x0b, 0x2b => 0x0c, + 0x2c => 0x0d, 0x2212 => 0x0e, 0x2e => 0x0f, 0x2f => 0x10, + 0x30 => 0x11, 0x31 => 0x12, 0x32 => 0x13, 0x33 => 0x14, + 0x34 => 0x15, 0x35 => 0x16, 0x36 => 0x17, 0x37 => 0x18, + 0x38 => 0x19, 0x39 => 0x1a, 0x3a => 0x1b, 0x3b => 0x1c, + 0x3c => 0x1d, 0x3d => 0x1e, 0x3e => 0x1f, 0x3f => 0x20, + 0x2245 => 0x21, 0x0391 => 0x22, 0x0392 => 0x23, 0x03a7 => 0x24, + 0x2206 => 0x25, 0x0395 => 0x26, 0x03a6 => 0x27, 0x0393 => 0x28, + 0x0397 => 0x29, 0x0399 => 0x2a, 0x03d1 => 0x2b, 0x039a => 0x2c, + 0x039b => 0x2d, 0x039c => 0x2e, 0x039d => 0x2f, 0x039f => 0x30, + 0x03a0 => 0x31, 0x0398 => 0x32, 0x03a1 => 0x33, 0x03a3 => 0x34, + 0x03a4 => 0x35, 0x03a5 => 0x36, 0x03c2 => 0x37, 0x2126 => 0x38, + 0x039e => 0x39, 0x03a8 => 0x3a, 0x0396 => 0x3b, 0x5b => 0x3c, + 0x2234 => 0x3d, 0x5d => 0x3e, 0x22a5 => 0x3f, 0x5f => 0x40, + 0xf8e5 => 0x41, 0x03b1 => 0x42, 0x03b2 => 0x43, 0x03c7 => 0x44, + 0x03b4 => 0x45, 0x03b5 => 0x46, 0x03c6 => 0x47, 0x03b3 => 0x48, + 0x03b7 => 0x49, 0x03b9 => 0x4a, 0x03d5 => 0x4b, 0x03ba => 0x4c, + 0x03bb => 0x4d, 0xb5 => 0x4e, 0x03bd => 0x4f, 0x03bf => 0x50, + 0x03c0 => 0x51, 0x03b8 => 0x52, 0x03c1 => 0x53, 0x03c3 => 0x54, + 0x03c4 => 0x55, 0x03c5 => 0x56, 0x03d6 => 0x57, 0x03c9 => 0x58, + 0x03be => 0x59, 0x03c8 => 0x5a, 0x03b6 => 0x5b, 0x7b => 0x5c, + 0x7c => 0x5d, 0x7d => 0x5e, 0x223c => 0x5f, 0x20ac => 0x60, + 0x03d2 => 0x61, 0x2032 => 0x62, 0x2264 => 0x63, 0x2044 => 0x64, + 0x221e => 0x65, 0x0192 => 0x66, 0x2663 => 0x67, 0x2666 => 0x68, + 0x2665 => 0x69, 0x2660 => 0x6a, 0x2194 => 0x6b, 0x2190 => 0x6c, + 0x2191 => 0x6d, 0x2192 => 0x6e, 0x2193 => 0x6f, 0xb0 => 0x70, + 0xb1 => 0x71, 0x2033 => 0x72, 0x2265 => 0x73, 0xd7 => 0x74, + 0x221d => 0x75, 0x2202 => 0x76, 0x2022 => 0x77, 0xf7 => 0x78, + 0x2260 => 0x79, 0x2261 => 0x7a, 0x2248 => 0x7b, 0x2026 => 0x7c, + 0xf8e6 => 0x7d, 0xf8e7 => 0x7e, 0x21b5 => 0x7f, 0x2135 => 0x80, + 0x2111 => 0x81, 0x211c => 0x82, 0x2118 => 0x83, 0x2297 => 0x84, + 0x2295 => 0x85, 0x2205 => 0x86, 0x2229 => 0x87, 0x222a => 0x88, + 0x2283 => 0x89, 0x2287 => 0x8a, 0x2284 => 0x8b, 0x2282 => 0x8c, + 0x2286 => 0x8d, 0x2208 => 0x8e, 0x2209 => 0x8f, 0x2220 => 0x90, + 0x2207 => 0x91, 0xf6da => 0x92, 0xf6d9 => 0x93, 0xf6db => 0x94, + 0x220f => 0x95, 0x221a => 0x96, 0x22c5 => 0x97, 0xac => 0x98, + 0x2227 => 0x99, 0x2228 => 0x9a, 0x21d4 => 0x9b, 0x21d0 => 0x9c, + 0x21d1 => 0x9d, 0x21d2 => 0x9e, 0x21d3 => 0x9f, 0x25ca => 0xa0, + 0x2329 => 0xa1, 0xf8e8 => 0xa2, 0xf8e9 => 0xa3, 0xf8ea => 0xa4, + 0x2211 => 0xa5, 0xf8eb => 0xa6, 0xf8ec => 0xa7, 0xf8ed => 0xa8, + 0xf8ee => 0xa9, 0xf8ef => 0xaa, 0xf8f0 => 0xab, 0xf8f1 => 0xac, + 0xf8f2 => 0xad, 0xf8f3 => 0xae, 0xf8f4 => 0xaf, 0x232a => 0xb0, + 0x222b => 0xb1, 0x2320 => 0xb2, 0xf8f5 => 0xb3, 0x2321 => 0xb4, + 0xf8f6 => 0xb5, 0xf8f7 => 0xb6, 0xf8f8 => 0xb7, 0xf8f9 => 0xb8, + 0xf8fa => 0xb9, 0xf8fb => 0xba, 0xf8fc => 0xbb, 0xf8fd => 0xbc, + 0xf8fe => 0xbd, 0xf8ff => 0xbe); + // require_once 'Zend/Pdf/Cmap.php'; + $this->_cmap = Zend_Pdf_Cmap::cmapWithTypeData( + Zend_Pdf_Cmap::TYPE_BYTE_ENCODING_STATIC, $cmapData); + + + /* Resource dictionary */ + + /* The resource dictionary for the standard fonts is sparse because PDF + * viewers already have all of the metrics data. We only need to provide + * the font name and encoding method. + */ + $this->_resource->BaseFont = new Zend_Pdf_Element_Name('Symbol'); + + /* This font has a built-in custom character encoding method. Don't + * override with WinAnsi like the other built-in fonts or else it will + * not work as expected. + */ + $this->_resource->Encoding = null; + } + + + /* Information and Conversion Methods */ + + /** + * Convert string encoding from local encoding to font encoding. Overridden + * to defeat the conversion behavior for this ornamental font. + * + * @param string $string + * @param string $charEncoding Character encoding of source text. + * @return string + */ + public function encodeString($string, $charEncoding) + { + /* This isn't the optimal time to perform this conversion, but it must + * live here until the remainder of the layout code is completed. This, + * and the $charEncoding parameter, will go away soon... + */ + if ($charEncoding != 'UTF-16BE') { + $string = iconv($charEncoding, 'UTF-16BE', $string); + } + /** + * @todo Properly handle characters encoded as surrogate pairs. + */ + $encodedString = ''; + for ($i = 0; $i < strlen($string); $i++) { + $characterCode = (ord($string[$i++]) << 8) | ord($string[$i]); + if (isset($this->_toFontEncoding[$characterCode])) { + $encodedString .= $this->_toFontEncoding[$characterCode]; + } else { + /* For now, mimic the behavior in Zend_Pdf_Font::encodeString() + * where unknown characters are removed completely. This is not + * perfect, but we should be consistent. In a future revision, + * we will use the well-known substitution character 0x1a + * (Control-Z). + */ + } + } + return $encodedString; + } + + /** + * Convert string encoding from font encoding to local encoding. Overridden + * to defeat the conversion behavior for this ornamental font. + * + * @param string $string + * @param string $charEncoding Character encoding of resulting text. + * @return string + */ + public function decodeString($string, $charEncoding) + { + $decodedString = ''; + for ($i = 0; $i < strlen($string); $i++) { + $characterCode = ord($string[$i]); + if (isset($this->_fromFontEncoding[$characterCode])) { + $decodedString .= $this->_fromFontEncoding[$characterCode]; + } else { + /* For now, mimic the behavior in Zend_Pdf_Font::encodeString() + * where unknown characters are removed completely. This is not + * perfect, but we should be consistent. In a future revision, + * we will use the Unicode substitution character (U+FFFD). + */ + } + } + if ($charEncoding != 'UTF-16BE') { + $decodedString = iconv('UTF-16BE', $charEncoding, $decodedString); + } + return $decodedString; + } + + /** + * Converts a Latin-encoded string that fakes the font's internal encoding + * to the proper Unicode characters, in UTF-16BE encoding. + * + * Used to maintain backwards compatibility with the 20 year-old legacy + * method of using this font, which is still employed by recent versions of + * some popular word processors. + * + * Note that using this method adds overhead due to the additional + * character conversion. Don't use this for new code; it is more efficient + * to use the appropriate Unicode characters directly. + * + * @param string $string + * @param string $charEncoding (optional) Character encoding of source + * string. Defaults to current locale. + * @return string + */ + public function toUnicode($string, $charEncoding = '') + { + /* When using these faked strings, the closest match to the font's + * internal encoding is ISO-8859-1. + */ + if ($charEncoding != 'ISO-8859-1') { + $string = iconv($charEncoding, 'ISO-8859-1', $string); + } + return $this->decodeString($string, 'UTF-16BE'); + } +} diff --git a/library/Zend/Pdf/Resource/Font/Simple/Standard/TimesBold.php b/library/Zend/Pdf/Resource/Font/Simple/Standard/TimesBold.php new file mode 100644 index 0000000..58d173c --- /dev/null +++ b/library/Zend/Pdf/Resource/Font/Simple/Standard/TimesBold.php @@ -0,0 +1,304 @@ +_fontNames[Zend_Pdf_Font::NAME_COPYRIGHT]['en'] = + "\x00\x43\x00\x6f\x00\x70\x00\x79\x00\x72\x00\x69\x00\x67\x00\x68\x00" + . "\x74\x00\x20\x00\x28\x00\x63\x00\x29\x00\x20\x00\x31\x00\x39\x00" + . "\x38\x00\x35\x00\x2c\x00\x20\x00\x31\x00\x39\x00\x38\x00\x37\x00" + . "\x2c\x00\x20\x00\x31\x00\x39\x00\x38\x00\x39\x00\x2c\x00\x20\x00" + . "\x31\x00\x39\x00\x39\x00\x30\x00\x2c\x00\x20\x00\x31\x00\x39\x00" + . "\x39\x00\x33\x00\x2c\x00\x20\x00\x31\x00\x39\x00\x39\x00\x37\x00" + . "\x20\x00\x41\x00\x64\x00\x6f\x00\x62\x00\x65\x00\x20\x00\x53\x00" + . "\x79\x00\x73\x00\x74\x00\x65\x00\x6d\x00\x73\x00\x20\x00\x49\x00" + . "\x6e\x00\x63\x00\x6f\x00\x72\x00\x70\x00\x6f\x00\x72\x00\x61\x00" + . "\x74\x00\x65\x00\x64\x00\x2e\x00\x20\x00\x20\x00\x41\x00\x6c\x00" + . "\x6c\x00\x20\x00\x52\x00\x69\x00\x67\x00\x68\x00\x74\x00\x73\x00" + . "\x20\x00\x52\x00\x65\x00\x73\x00\x65\x00\x72\x00\x76\x00\x65\x00" + . "\x64\x00\x2e\x00\x54\x00\x69\x00\x6d\x00\x65\x00\x73\x00\x20\x00" + . "\x69\x00\x73\x00\x20\x00\x61\x00\x20\x00\x74\x00\x72\x00\x61\x00" + . "\x64\x00\x65\x00\x6d\x00\x61\x00\x72\x00\x6b\x00\x20\x00\x6f\x00" + . "\x66\x00\x20\x00\x4c\x00\x69\x00\x6e\x00\x6f\x00\x74\x00\x79\x00" + . "\x70\x00\x65\x00\x2d\x00\x48\x00\x65\x00\x6c\x00\x6c\x00\x20\x00" + . "\x41\x00\x47\x00\x20\x00\x61\x00\x6e\x00\x64\x00\x2f\x00\x6f\x00" + . "\x72\x00\x20\x00\x69\x00\x74\x00\x73\x00\x20\x00\x73\x00\x75\x00" + . "\x62\x00\x73\x00\x69\x00\x64\x00\x69\x00\x61\x00\x72\x00\x69\x00" + . "\x65\x00\x73\x00\x2e"; + $this->_fontNames[Zend_Pdf_Font::NAME_FAMILY]['en'] = + "\x00\x54\x00\x69\x00\x6d\x00\x65\x00\x73"; + $this->_fontNames[Zend_Pdf_Font::NAME_STYLE]['en'] = + "\x00\x42\x00\x6f\x00\x6c\x00\x64"; + $this->_fontNames[Zend_Pdf_Font::NAME_ID]['en'] = + "\x00\x34\x00\x33\x00\x30\x00\x36\x00\x35"; + $this->_fontNames[Zend_Pdf_Font::NAME_FULL]['en'] = + "\x00\x54\x00\x69\x00\x6d\x00\x65\x00\x73\x00\x2d\x00\x42\x00\x6f\x00" + . "\x6c\x00\x64\x00\x20\x00\x42\x00\x6f\x00\x6c\x00\x64"; + $this->_fontNames[Zend_Pdf_Font::NAME_VERSION]['en'] = + "\x00\x30\x00\x30\x00\x32\x00\x2e\x00\x30\x00\x30\x00\x30"; + $this->_fontNames[Zend_Pdf_Font::NAME_POSTSCRIPT]['en'] = + "\x00\x54\x00\x69\x00\x6d\x00\x65\x00\x73\x00\x2d\x00\x42\x00\x6f\x00" + . "\x6c\x00\x64"; + + $this->_isBold = true; + $this->_isItalic = false; + $this->_isMonospaced = false; + + $this->_underlinePosition = -100; + $this->_underlineThickness = 50; + $this->_strikePosition = 225; + $this->_strikeThickness = 50; + + $this->_unitsPerEm = 1000; + + $this->_ascent = 683; + $this->_descent = -217; + $this->_lineGap = 300; + + /* The glyph numbers assigned here are synthetic; they do not match the + * actual glyph numbers used by the font. This is not a big deal though + * since this data never makes it to the PDF file. It is only used + * internally for layout calculations. + */ + $this->_glyphWidths = array( + 0x00 => 0x01f4, 0x01 => 0xfa, 0x02 => 0x014d, 0x03 => 0x022b, + 0x04 => 0x01f4, 0x05 => 0x01f4, 0x06 => 0x03e8, 0x07 => 0x0341, + 0x08 => 0x014d, 0x09 => 0x014d, 0x0a => 0x014d, 0x0b => 0x01f4, + 0x0c => 0x023a, 0x0d => 0xfa, 0x0e => 0x014d, 0x0f => 0xfa, + 0x10 => 0x0116, 0x11 => 0x01f4, 0x12 => 0x01f4, 0x13 => 0x01f4, + 0x14 => 0x01f4, 0x15 => 0x01f4, 0x16 => 0x01f4, 0x17 => 0x01f4, + 0x18 => 0x01f4, 0x19 => 0x01f4, 0x1a => 0x01f4, 0x1b => 0x014d, + 0x1c => 0x014d, 0x1d => 0x023a, 0x1e => 0x023a, 0x1f => 0x023a, + 0x20 => 0x01f4, 0x21 => 0x03a2, 0x22 => 0x02d2, 0x23 => 0x029b, + 0x24 => 0x02d2, 0x25 => 0x02d2, 0x26 => 0x029b, 0x27 => 0x0263, + 0x28 => 0x030a, 0x29 => 0x030a, 0x2a => 0x0185, 0x2b => 0x01f4, + 0x2c => 0x030a, 0x2d => 0x029b, 0x2e => 0x03b0, 0x2f => 0x02d2, + 0x30 => 0x030a, 0x31 => 0x0263, 0x32 => 0x030a, 0x33 => 0x02d2, + 0x34 => 0x022c, 0x35 => 0x029b, 0x36 => 0x02d2, 0x37 => 0x02d2, + 0x38 => 0x03e8, 0x39 => 0x02d2, 0x3a => 0x02d2, 0x3b => 0x029b, + 0x3c => 0x014d, 0x3d => 0x0116, 0x3e => 0x014d, 0x3f => 0x0245, + 0x40 => 0x01f4, 0x41 => 0x014d, 0x42 => 0x01f4, 0x43 => 0x022c, + 0x44 => 0x01bc, 0x45 => 0x022c, 0x46 => 0x01bc, 0x47 => 0x014d, + 0x48 => 0x01f4, 0x49 => 0x022c, 0x4a => 0x0116, 0x4b => 0x014d, + 0x4c => 0x022c, 0x4d => 0x0116, 0x4e => 0x0341, 0x4f => 0x022c, + 0x50 => 0x01f4, 0x51 => 0x022c, 0x52 => 0x022c, 0x53 => 0x01bc, + 0x54 => 0x0185, 0x55 => 0x014d, 0x56 => 0x022c, 0x57 => 0x01f4, + 0x58 => 0x02d2, 0x59 => 0x01f4, 0x5a => 0x01f4, 0x5b => 0x01bc, + 0x5c => 0x018a, 0x5d => 0xdc, 0x5e => 0x018a, 0x5f => 0x0208, + 0x60 => 0x014d, 0x61 => 0x01f4, 0x62 => 0x01f4, 0x63 => 0xa7, + 0x64 => 0x01f4, 0x65 => 0x01f4, 0x66 => 0x01f4, 0x67 => 0x01f4, + 0x68 => 0x0116, 0x69 => 0x01f4, 0x6a => 0x01f4, 0x6b => 0x014d, + 0x6c => 0x014d, 0x6d => 0x022c, 0x6e => 0x022c, 0x6f => 0x01f4, + 0x70 => 0x01f4, 0x71 => 0x01f4, 0x72 => 0xfa, 0x73 => 0x021c, + 0x74 => 0x015e, 0x75 => 0x014d, 0x76 => 0x01f4, 0x77 => 0x01f4, + 0x78 => 0x01f4, 0x79 => 0x03e8, 0x7a => 0x03e8, 0x7b => 0x01f4, + 0x7c => 0x014d, 0x7d => 0x014d, 0x7e => 0x014d, 0x7f => 0x014d, + 0x80 => 0x014d, 0x81 => 0x014d, 0x82 => 0x014d, 0x83 => 0x014d, + 0x84 => 0x014d, 0x85 => 0x014d, 0x86 => 0x014d, 0x87 => 0x014d, + 0x88 => 0x014d, 0x89 => 0x03e8, 0x8a => 0x03e8, 0x8b => 0x012c, + 0x8c => 0x029b, 0x8d => 0x030a, 0x8e => 0x03e8, 0x8f => 0x014a, + 0x90 => 0x02d2, 0x91 => 0x0116, 0x92 => 0x0116, 0x93 => 0x01f4, + 0x94 => 0x02d2, 0x95 => 0x022c, 0x96 => 0x0185, 0x97 => 0x01bc, + 0x98 => 0x01f4, 0x99 => 0x022c, 0x9a => 0x01bc, 0x9b => 0x02d2, + 0x9c => 0x023a, 0x9d => 0x02d2, 0x9e => 0x02d2, 0x9f => 0x01f4, + 0xa0 => 0x02d2, 0xa1 => 0x01f4, 0xa2 => 0x0185, 0xa3 => 0x01bc, + 0xa4 => 0x02d2, 0xa5 => 0x02d2, 0xa6 => 0x01f4, 0xa7 => 0x02d2, + 0xa8 => 0x022c, 0xa9 => 0x029b, 0xaa => 0x02d2, 0xab => 0xfa, + 0xac => 0x02eb, 0xad => 0x029b, 0xae => 0x01bc, 0xaf => 0x01f4, + 0xb0 => 0x02d2, 0xb1 => 0x0116, 0xb2 => 0x01f4, 0xb3 => 0x029b, + 0xb4 => 0x02d2, 0xb5 => 0x01f4, 0xb6 => 0x029b, 0xb7 => 0x0185, + 0xb8 => 0x0185, 0xb9 => 0x0116, 0xba => 0x01ee, 0xbb => 0x02d2, + 0xbc => 0x030a, 0xbd => 0x022c, 0xbe => 0x01f4, 0xbf => 0x02d2, + 0xc0 => 0x01bc, 0xc1 => 0x01bc, 0xc2 => 0x029b, 0xc3 => 0x0263, + 0xc4 => 0x030a, 0xc5 => 0x02d2, 0xc6 => 0x022c, 0xc7 => 0x02a0, + 0xc8 => 0x02d2, 0xc9 => 0x022c, 0xca => 0x012c, 0xcb => 0x030a, + 0xcc => 0x02d2, 0xcd => 0x02d2, 0xce => 0x023a, 0xcf => 0x022c, + 0xd0 => 0x029b, 0xd1 => 0x01ee, 0xd2 => 0x01f4, 0xd3 => 0x02d2, + 0xd4 => 0x0116, 0xd5 => 0x029b, 0xd6 => 0x01f4, 0xd7 => 0x01bc, + 0xd8 => 0x01bc, 0xd9 => 0x022c, 0xda => 0x022c, 0xdb => 0x02d2, + 0xdc => 0x0185, 0xdd => 0x023a, 0xde => 0xdc, 0xdf => 0x02eb, + 0xe0 => 0x030a, 0xe1 => 0x0185, 0xe2 => 0x0258, 0xe3 => 0x029b, + 0xe4 => 0x01bc, 0xe5 => 0x01f4, 0xe6 => 0x029b, 0xe7 => 0x029b, + 0xe8 => 0x0225, 0xe9 => 0x02d2, 0xea => 0x02d2, 0xeb => 0x0116, + 0xec => 0x01a0, 0xed => 0x01bc, 0xee => 0x02d2, 0xef => 0x02d2, + 0xf0 => 0x02d2, 0xf1 => 0x01bc, 0xf2 => 0x01bc, 0xf3 => 0x0116, + 0xf4 => 0x030a, 0xf5 => 0x01f4, 0xf6 => 0x01f4, 0xf7 => 0x0185, + 0xf8 => 0x0116, 0xf9 => 0x030a, 0xfa => 0x02d2, 0xfb => 0x0264, + 0xfc => 0x022c, 0xfd => 0x012c, 0xfe => 0x030a, 0xff => 0x022c, + 0x0100 => 0x0116, 0x0101 => 0x01f4, 0x0102 => 0x029b, 0x0103 => 0x022c, + 0x0104 => 0x02ee, 0x0105 => 0x022c, 0x0106 => 0x018a, 0x0107 => 0x030a, + 0x0108 => 0x029b, 0x0109 => 0x03e8, 0x010a => 0x01bc, 0x010b => 0x0185, + 0x010c => 0x0185, 0x010d => 0x029b, 0x010e => 0x02ee, 0x010f => 0x0225, + 0x0110 => 0x01f4, 0x0111 => 0x022c, 0x0112 => 0x02d2, 0x0113 => 0x029b, + 0x0114 => 0x01bc, 0x0115 => 0x01f4, 0x0116 => 0x02ee, 0x0117 => 0x022c, + 0x0118 => 0x022c, 0x0119 => 0x030a, 0x011a => 0x0190, 0x011b => 0x01f4, + 0x011c => 0x02d2, 0x011d => 0x022c, 0x011e => 0x0225, 0x011f => 0x02d2, + 0x0120 => 0x01bc, 0x0121 => 0x02d2, 0x0122 => 0x01f4, 0x0123 => 0x02d2, + 0x0124 => 0x029b, 0x0125 => 0x02d2, 0x0126 => 0x02d2, 0x0127 => 0x02d2, + 0x0128 => 0x030a, 0x0129 => 0x01bc, 0x012a => 0x029b, 0x012b => 0x0185, + 0x012c => 0x022c, 0x012d => 0x023a, 0x012e => 0x0185, 0x012f => 0x022c, + 0x0130 => 0x014d, 0x0131 => 0x023a, 0x0132 => 0x01f4, 0x0133 => 0x022c, + 0x0134 => 0x0225, 0x0135 => 0x01f4, 0x0136 => 0x01f4, 0x0137 => 0x01bc, + 0x0138 => 0x022c, 0x0139 => 0x012c, 0x013a => 0x0116, 0x013b => 0x01f4, + ); + + /* The cmap table is similarly synthesized. + */ + $cmapData = array( + 0x20 => 0x01, 0x21 => 0x02, 0x22 => 0x03, 0x23 => 0x04, + 0x24 => 0x05, 0x25 => 0x06, 0x26 => 0x07, 0x2019 => 0x08, + 0x28 => 0x09, 0x29 => 0x0a, 0x2a => 0x0b, 0x2b => 0x0c, + 0x2c => 0x0d, 0x2d => 0x0e, 0x2e => 0x0f, 0x2f => 0x10, + 0x30 => 0x11, 0x31 => 0x12, 0x32 => 0x13, 0x33 => 0x14, + 0x34 => 0x15, 0x35 => 0x16, 0x36 => 0x17, 0x37 => 0x18, + 0x38 => 0x19, 0x39 => 0x1a, 0x3a => 0x1b, 0x3b => 0x1c, + 0x3c => 0x1d, 0x3d => 0x1e, 0x3e => 0x1f, 0x3f => 0x20, + 0x40 => 0x21, 0x41 => 0x22, 0x42 => 0x23, 0x43 => 0x24, + 0x44 => 0x25, 0x45 => 0x26, 0x46 => 0x27, 0x47 => 0x28, + 0x48 => 0x29, 0x49 => 0x2a, 0x4a => 0x2b, 0x4b => 0x2c, + 0x4c => 0x2d, 0x4d => 0x2e, 0x4e => 0x2f, 0x4f => 0x30, + 0x50 => 0x31, 0x51 => 0x32, 0x52 => 0x33, 0x53 => 0x34, + 0x54 => 0x35, 0x55 => 0x36, 0x56 => 0x37, 0x57 => 0x38, + 0x58 => 0x39, 0x59 => 0x3a, 0x5a => 0x3b, 0x5b => 0x3c, + 0x5c => 0x3d, 0x5d => 0x3e, 0x5e => 0x3f, 0x5f => 0x40, + 0x2018 => 0x41, 0x61 => 0x42, 0x62 => 0x43, 0x63 => 0x44, + 0x64 => 0x45, 0x65 => 0x46, 0x66 => 0x47, 0x67 => 0x48, + 0x68 => 0x49, 0x69 => 0x4a, 0x6a => 0x4b, 0x6b => 0x4c, + 0x6c => 0x4d, 0x6d => 0x4e, 0x6e => 0x4f, 0x6f => 0x50, + 0x70 => 0x51, 0x71 => 0x52, 0x72 => 0x53, 0x73 => 0x54, + 0x74 => 0x55, 0x75 => 0x56, 0x76 => 0x57, 0x77 => 0x58, + 0x78 => 0x59, 0x79 => 0x5a, 0x7a => 0x5b, 0x7b => 0x5c, + 0x7c => 0x5d, 0x7d => 0x5e, 0x7e => 0x5f, 0xa1 => 0x60, + 0xa2 => 0x61, 0xa3 => 0x62, 0x2044 => 0x63, 0xa5 => 0x64, + 0x0192 => 0x65, 0xa7 => 0x66, 0xa4 => 0x67, 0x27 => 0x68, + 0x201c => 0x69, 0xab => 0x6a, 0x2039 => 0x6b, 0x203a => 0x6c, + 0xfb01 => 0x6d, 0xfb02 => 0x6e, 0x2013 => 0x6f, 0x2020 => 0x70, + 0x2021 => 0x71, 0xb7 => 0x72, 0xb6 => 0x73, 0x2022 => 0x74, + 0x201a => 0x75, 0x201e => 0x76, 0x201d => 0x77, 0xbb => 0x78, + 0x2026 => 0x79, 0x2030 => 0x7a, 0xbf => 0x7b, 0x60 => 0x7c, + 0xb4 => 0x7d, 0x02c6 => 0x7e, 0x02dc => 0x7f, 0xaf => 0x80, + 0x02d8 => 0x81, 0x02d9 => 0x82, 0xa8 => 0x83, 0x02da => 0x84, + 0xb8 => 0x85, 0x02dd => 0x86, 0x02db => 0x87, 0x02c7 => 0x88, + 0x2014 => 0x89, 0xc6 => 0x8a, 0xaa => 0x8b, 0x0141 => 0x8c, + 0xd8 => 0x8d, 0x0152 => 0x8e, 0xba => 0x8f, 0xe6 => 0x90, + 0x0131 => 0x91, 0x0142 => 0x92, 0xf8 => 0x93, 0x0153 => 0x94, + 0xdf => 0x95, 0xcf => 0x96, 0xe9 => 0x97, 0x0103 => 0x98, + 0x0171 => 0x99, 0x011b => 0x9a, 0x0178 => 0x9b, 0xf7 => 0x9c, + 0xdd => 0x9d, 0xc2 => 0x9e, 0xe1 => 0x9f, 0xdb => 0xa0, + 0xfd => 0xa1, 0x0219 => 0xa2, 0xea => 0xa3, 0x016e => 0xa4, + 0xdc => 0xa5, 0x0105 => 0xa6, 0xda => 0xa7, 0x0173 => 0xa8, + 0xcb => 0xa9, 0x0110 => 0xaa, 0xf6c3 => 0xab, 0xa9 => 0xac, + 0x0112 => 0xad, 0x010d => 0xae, 0xe5 => 0xaf, 0x0145 => 0xb0, + 0x013a => 0xb1, 0xe0 => 0xb2, 0x0162 => 0xb3, 0x0106 => 0xb4, + 0xe3 => 0xb5, 0x0116 => 0xb6, 0x0161 => 0xb7, 0x015f => 0xb8, + 0xed => 0xb9, 0x25ca => 0xba, 0x0158 => 0xbb, 0x0122 => 0xbc, + 0xfb => 0xbd, 0xe2 => 0xbe, 0x0100 => 0xbf, 0x0159 => 0xc0, + 0xe7 => 0xc1, 0x017b => 0xc2, 0xde => 0xc3, 0x014c => 0xc4, + 0x0154 => 0xc5, 0x015a => 0xc6, 0x010f => 0xc7, 0x016a => 0xc8, + 0x016f => 0xc9, 0xb3 => 0xca, 0xd2 => 0xcb, 0xc0 => 0xcc, + 0x0102 => 0xcd, 0xd7 => 0xce, 0xfa => 0xcf, 0x0164 => 0xd0, + 0x2202 => 0xd1, 0xff => 0xd2, 0x0143 => 0xd3, 0xee => 0xd4, + 0xca => 0xd5, 0xe4 => 0xd6, 0xeb => 0xd7, 0x0107 => 0xd8, + 0x0144 => 0xd9, 0x016b => 0xda, 0x0147 => 0xdb, 0xcd => 0xdc, + 0xb1 => 0xdd, 0xa6 => 0xde, 0xae => 0xdf, 0x011e => 0xe0, + 0x0130 => 0xe1, 0x2211 => 0xe2, 0xc8 => 0xe3, 0x0155 => 0xe4, + 0x014d => 0xe5, 0x0179 => 0xe6, 0x017d => 0xe7, 0x2265 => 0xe8, + 0xd0 => 0xe9, 0xc7 => 0xea, 0x013c => 0xeb, 0x0165 => 0xec, + 0x0119 => 0xed, 0x0172 => 0xee, 0xc1 => 0xef, 0xc4 => 0xf0, + 0xe8 => 0xf1, 0x017a => 0xf2, 0x012f => 0xf3, 0xd3 => 0xf4, + 0xf3 => 0xf5, 0x0101 => 0xf6, 0x015b => 0xf7, 0xef => 0xf8, + 0xd4 => 0xf9, 0xd9 => 0xfa, 0x2206 => 0xfb, 0xfe => 0xfc, + 0xb2 => 0xfd, 0xd6 => 0xfe, 0xb5 => 0xff, 0xec => 0x0100, + 0x0151 => 0x0101, 0x0118 => 0x0102, 0x0111 => 0x0103, 0xbe => 0x0104, + 0x015e => 0x0105, 0x013e => 0x0106, 0x0136 => 0x0107, 0x0139 => 0x0108, + 0x2122 => 0x0109, 0x0117 => 0x010a, 0xcc => 0x010b, 0x012a => 0x010c, + 0x013d => 0x010d, 0xbd => 0x010e, 0x2264 => 0x010f, 0xf4 => 0x0110, + 0xf1 => 0x0111, 0x0170 => 0x0112, 0xc9 => 0x0113, 0x0113 => 0x0114, + 0x011f => 0x0115, 0xbc => 0x0116, 0x0160 => 0x0117, 0x0218 => 0x0118, + 0x0150 => 0x0119, 0xb0 => 0x011a, 0xf2 => 0x011b, 0x010c => 0x011c, + 0xf9 => 0x011d, 0x221a => 0x011e, 0x010e => 0x011f, 0x0157 => 0x0120, + 0xd1 => 0x0121, 0xf5 => 0x0122, 0x0156 => 0x0123, 0x013b => 0x0124, + 0xc3 => 0x0125, 0x0104 => 0x0126, 0xc5 => 0x0127, 0xd5 => 0x0128, + 0x017c => 0x0129, 0x011a => 0x012a, 0x012e => 0x012b, 0x0137 => 0x012c, + 0x2212 => 0x012d, 0xce => 0x012e, 0x0148 => 0x012f, 0x0163 => 0x0130, + 0xac => 0x0131, 0xf6 => 0x0132, 0xfc => 0x0133, 0x2260 => 0x0134, + 0x0123 => 0x0135, 0xf0 => 0x0136, 0x017e => 0x0137, 0x0146 => 0x0138, + 0xb9 => 0x0139, 0x012b => 0x013a, 0x20ac => 0x013b); + // require_once 'Zend/Pdf/Cmap.php'; + $this->_cmap = Zend_Pdf_Cmap::cmapWithTypeData( + Zend_Pdf_Cmap::TYPE_BYTE_ENCODING_STATIC, $cmapData); + + + /* Resource dictionary */ + + /* The resource dictionary for the standard fonts is sparse because PDF + * viewers already have all of the metrics data. We only need to provide + * the font name and encoding method. + */ + $this->_resource->BaseFont = new Zend_Pdf_Element_Name('Times-Bold'); + } +} diff --git a/library/Zend/Pdf/Resource/Font/Simple/Standard/TimesBoldItalic.php b/library/Zend/Pdf/Resource/Font/Simple/Standard/TimesBoldItalic.php new file mode 100644 index 0000000..1b45c2c --- /dev/null +++ b/library/Zend/Pdf/Resource/Font/Simple/Standard/TimesBoldItalic.php @@ -0,0 +1,305 @@ +_fontNames[Zend_Pdf_Font::NAME_COPYRIGHT]['en'] = + "\x00\x43\x00\x6f\x00\x70\x00\x79\x00\x72\x00\x69\x00\x67\x00\x68\x00" + . "\x74\x00\x20\x00\x28\x00\x63\x00\x29\x00\x20\x00\x31\x00\x39\x00" + . "\x38\x00\x35\x00\x2c\x00\x20\x00\x31\x00\x39\x00\x38\x00\x37\x00" + . "\x2c\x00\x20\x00\x31\x00\x39\x00\x38\x00\x39\x00\x2c\x00\x20\x00" + . "\x31\x00\x39\x00\x39\x00\x30\x00\x2c\x00\x20\x00\x31\x00\x39\x00" + . "\x39\x00\x33\x00\x2c\x00\x20\x00\x31\x00\x39\x00\x39\x00\x37\x00" + . "\x20\x00\x41\x00\x64\x00\x6f\x00\x62\x00\x65\x00\x20\x00\x53\x00" + . "\x79\x00\x73\x00\x74\x00\x65\x00\x6d\x00\x73\x00\x20\x00\x49\x00" + . "\x6e\x00\x63\x00\x6f\x00\x72\x00\x70\x00\x6f\x00\x72\x00\x61\x00" + . "\x74\x00\x65\x00\x64\x00\x2e\x00\x20\x00\x20\x00\x41\x00\x6c\x00" + . "\x6c\x00\x20\x00\x52\x00\x69\x00\x67\x00\x68\x00\x74\x00\x73\x00" + . "\x20\x00\x52\x00\x65\x00\x73\x00\x65\x00\x72\x00\x76\x00\x65\x00" + . "\x64\x00\x2e\x00\x54\x00\x69\x00\x6d\x00\x65\x00\x73\x00\x20\x00" + . "\x69\x00\x73\x00\x20\x00\x61\x00\x20\x00\x74\x00\x72\x00\x61\x00" + . "\x64\x00\x65\x00\x6d\x00\x61\x00\x72\x00\x6b\x00\x20\x00\x6f\x00" + . "\x66\x00\x20\x00\x4c\x00\x69\x00\x6e\x00\x6f\x00\x74\x00\x79\x00" + . "\x70\x00\x65\x00\x2d\x00\x48\x00\x65\x00\x6c\x00\x6c\x00\x20\x00" + . "\x41\x00\x47\x00\x20\x00\x61\x00\x6e\x00\x64\x00\x2f\x00\x6f\x00" + . "\x72\x00\x20\x00\x69\x00\x74\x00\x73\x00\x20\x00\x73\x00\x75\x00" + . "\x62\x00\x73\x00\x69\x00\x64\x00\x69\x00\x61\x00\x72\x00\x69\x00" + . "\x65\x00\x73\x00\x2e"; + $this->_fontNames[Zend_Pdf_Font::NAME_FAMILY]['en'] = + "\x00\x54\x00\x69\x00\x6d\x00\x65\x00\x73"; + $this->_fontNames[Zend_Pdf_Font::NAME_STYLE]['en'] = + "\x00\x42\x00\x6f\x00\x6c\x00\x64"; + $this->_fontNames[Zend_Pdf_Font::NAME_ID]['en'] = + "\x00\x34\x00\x33\x00\x30\x00\x36\x00\x36"; + $this->_fontNames[Zend_Pdf_Font::NAME_FULL]['en'] = + "\x00\x54\x00\x69\x00\x6d\x00\x65\x00\x73\x00\x2d\x00\x42\x00\x6f\x00" + . "\x6c\x00\x64\x00\x49\x00\x74\x00\x61\x00\x6c\x00\x69\x00\x63\x00" + . "\x20\x00\x42\x00\x6f\x00\x6c\x00\x64"; + $this->_fontNames[Zend_Pdf_Font::NAME_VERSION]['en'] = + "\x00\x30\x00\x30\x00\x32\x00\x2e\x00\x30\x00\x30\x00\x30"; + $this->_fontNames[Zend_Pdf_Font::NAME_POSTSCRIPT]['en'] = + "\x00\x54\x00\x69\x00\x6d\x00\x65\x00\x73\x00\x2d\x00\x42\x00\x6f\x00" + . "\x6c\x00\x64\x00\x49\x00\x74\x00\x61\x00\x6c\x00\x69\x00\x63"; + + $this->_isBold = true; + $this->_isItalic = true; + $this->_isMonospaced = false; + + $this->_underlinePosition = -100; + $this->_underlineThickness = 50; + $this->_strikePosition = 225; + $this->_strikeThickness = 50; + + $this->_unitsPerEm = 1000; + + $this->_ascent = 683; + $this->_descent = -217; + $this->_lineGap = 300; + + /* The glyph numbers assigned here are synthetic; they do not match the + * actual glyph numbers used by the font. This is not a big deal though + * since this data never makes it to the PDF file. It is only used + * internally for layout calculations. + */ + $this->_glyphWidths = array( + 0x00 => 0x01f4, 0x01 => 0xfa, 0x02 => 0x0185, 0x03 => 0x022b, + 0x04 => 0x01f4, 0x05 => 0x01f4, 0x06 => 0x0341, 0x07 => 0x030a, + 0x08 => 0x014d, 0x09 => 0x014d, 0x0a => 0x014d, 0x0b => 0x01f4, + 0x0c => 0x023a, 0x0d => 0xfa, 0x0e => 0x014d, 0x0f => 0xfa, + 0x10 => 0x0116, 0x11 => 0x01f4, 0x12 => 0x01f4, 0x13 => 0x01f4, + 0x14 => 0x01f4, 0x15 => 0x01f4, 0x16 => 0x01f4, 0x17 => 0x01f4, + 0x18 => 0x01f4, 0x19 => 0x01f4, 0x1a => 0x01f4, 0x1b => 0x014d, + 0x1c => 0x014d, 0x1d => 0x023a, 0x1e => 0x023a, 0x1f => 0x023a, + 0x20 => 0x01f4, 0x21 => 0x0340, 0x22 => 0x029b, 0x23 => 0x029b, + 0x24 => 0x029b, 0x25 => 0x02d2, 0x26 => 0x029b, 0x27 => 0x029b, + 0x28 => 0x02d2, 0x29 => 0x030a, 0x2a => 0x0185, 0x2b => 0x01f4, + 0x2c => 0x029b, 0x2d => 0x0263, 0x2e => 0x0379, 0x2f => 0x02d2, + 0x30 => 0x02d2, 0x31 => 0x0263, 0x32 => 0x02d2, 0x33 => 0x029b, + 0x34 => 0x022c, 0x35 => 0x0263, 0x36 => 0x02d2, 0x37 => 0x029b, + 0x38 => 0x0379, 0x39 => 0x029b, 0x3a => 0x0263, 0x3b => 0x0263, + 0x3c => 0x014d, 0x3d => 0x0116, 0x3e => 0x014d, 0x3f => 0x023a, + 0x40 => 0x01f4, 0x41 => 0x014d, 0x42 => 0x01f4, 0x43 => 0x01f4, + 0x44 => 0x01bc, 0x45 => 0x01f4, 0x46 => 0x01bc, 0x47 => 0x014d, + 0x48 => 0x01f4, 0x49 => 0x022c, 0x4a => 0x0116, 0x4b => 0x0116, + 0x4c => 0x01f4, 0x4d => 0x0116, 0x4e => 0x030a, 0x4f => 0x022c, + 0x50 => 0x01f4, 0x51 => 0x01f4, 0x52 => 0x01f4, 0x53 => 0x0185, + 0x54 => 0x0185, 0x55 => 0x0116, 0x56 => 0x022c, 0x57 => 0x01bc, + 0x58 => 0x029b, 0x59 => 0x01f4, 0x5a => 0x01bc, 0x5b => 0x0185, + 0x5c => 0x015c, 0x5d => 0xdc, 0x5e => 0x015c, 0x5f => 0x023a, + 0x60 => 0x0185, 0x61 => 0x01f4, 0x62 => 0x01f4, 0x63 => 0xa7, + 0x64 => 0x01f4, 0x65 => 0x01f4, 0x66 => 0x01f4, 0x67 => 0x01f4, + 0x68 => 0x0116, 0x69 => 0x01f4, 0x6a => 0x01f4, 0x6b => 0x014d, + 0x6c => 0x014d, 0x6d => 0x022c, 0x6e => 0x022c, 0x6f => 0x01f4, + 0x70 => 0x01f4, 0x71 => 0x01f4, 0x72 => 0xfa, 0x73 => 0x01f4, + 0x74 => 0x015e, 0x75 => 0x014d, 0x76 => 0x01f4, 0x77 => 0x01f4, + 0x78 => 0x01f4, 0x79 => 0x03e8, 0x7a => 0x03e8, 0x7b => 0x01f4, + 0x7c => 0x014d, 0x7d => 0x014d, 0x7e => 0x014d, 0x7f => 0x014d, + 0x80 => 0x014d, 0x81 => 0x014d, 0x82 => 0x014d, 0x83 => 0x014d, + 0x84 => 0x014d, 0x85 => 0x014d, 0x86 => 0x014d, 0x87 => 0x014d, + 0x88 => 0x014d, 0x89 => 0x03e8, 0x8a => 0x03b0, 0x8b => 0x010a, + 0x8c => 0x0263, 0x8d => 0x02d2, 0x8e => 0x03b0, 0x8f => 0x012c, + 0x90 => 0x02d2, 0x91 => 0x0116, 0x92 => 0x0116, 0x93 => 0x01f4, + 0x94 => 0x02d2, 0x95 => 0x01f4, 0x96 => 0x0185, 0x97 => 0x01bc, + 0x98 => 0x01f4, 0x99 => 0x022c, 0x9a => 0x01bc, 0x9b => 0x0263, + 0x9c => 0x023a, 0x9d => 0x0263, 0x9e => 0x029b, 0x9f => 0x01f4, + 0xa0 => 0x02d2, 0xa1 => 0x01bc, 0xa2 => 0x0185, 0xa3 => 0x01bc, + 0xa4 => 0x02d2, 0xa5 => 0x02d2, 0xa6 => 0x01f4, 0xa7 => 0x02d2, + 0xa8 => 0x022c, 0xa9 => 0x029b, 0xaa => 0x02d2, 0xab => 0xfa, + 0xac => 0x02eb, 0xad => 0x029b, 0xae => 0x01bc, 0xaf => 0x01f4, + 0xb0 => 0x02d2, 0xb1 => 0x0116, 0xb2 => 0x01f4, 0xb3 => 0x0263, + 0xb4 => 0x029b, 0xb5 => 0x01f4, 0xb6 => 0x029b, 0xb7 => 0x0185, + 0xb8 => 0x0185, 0xb9 => 0x0116, 0xba => 0x01ee, 0xbb => 0x029b, + 0xbc => 0x02d2, 0xbd => 0x022c, 0xbe => 0x01f4, 0xbf => 0x029b, + 0xc0 => 0x0185, 0xc1 => 0x01bc, 0xc2 => 0x0263, 0xc3 => 0x0263, + 0xc4 => 0x02d2, 0xc5 => 0x029b, 0xc6 => 0x022c, 0xc7 => 0x0260, + 0xc8 => 0x02d2, 0xc9 => 0x022c, 0xca => 0x012c, 0xcb => 0x02d2, + 0xcc => 0x029b, 0xcd => 0x029b, 0xce => 0x023a, 0xcf => 0x022c, + 0xd0 => 0x0263, 0xd1 => 0x01ee, 0xd2 => 0x01bc, 0xd3 => 0x02d2, + 0xd4 => 0x0116, 0xd5 => 0x029b, 0xd6 => 0x01f4, 0xd7 => 0x01bc, + 0xd8 => 0x01bc, 0xd9 => 0x022c, 0xda => 0x022c, 0xdb => 0x02d2, + 0xdc => 0x0185, 0xdd => 0x023a, 0xde => 0xdc, 0xdf => 0x02eb, + 0xe0 => 0x02d2, 0xe1 => 0x0185, 0xe2 => 0x0258, 0xe3 => 0x029b, + 0xe4 => 0x0185, 0xe5 => 0x01f4, 0xe6 => 0x0263, 0xe7 => 0x0263, + 0xe8 => 0x0225, 0xe9 => 0x02d2, 0xea => 0x029b, 0xeb => 0x0116, + 0xec => 0x016e, 0xed => 0x01bc, 0xee => 0x02d2, 0xef => 0x029b, + 0xf0 => 0x029b, 0xf1 => 0x01bc, 0xf2 => 0x0185, 0xf3 => 0x0116, + 0xf4 => 0x02d2, 0xf5 => 0x01f4, 0xf6 => 0x01f4, 0xf7 => 0x0185, + 0xf8 => 0x0116, 0xf9 => 0x02d2, 0xfa => 0x02d2, 0xfb => 0x0264, + 0xfc => 0x01f4, 0xfd => 0x012c, 0xfe => 0x02d2, 0xff => 0x0240, + 0x0100 => 0x0116, 0x0101 => 0x01f4, 0x0102 => 0x029b, 0x0103 => 0x01f4, + 0x0104 => 0x02ee, 0x0105 => 0x022c, 0x0106 => 0x017e, 0x0107 => 0x029b, + 0x0108 => 0x0263, 0x0109 => 0x03e8, 0x010a => 0x01bc, 0x010b => 0x0185, + 0x010c => 0x0185, 0x010d => 0x0263, 0x010e => 0x02ee, 0x010f => 0x0225, + 0x0110 => 0x01f4, 0x0111 => 0x022c, 0x0112 => 0x02d2, 0x0113 => 0x029b, + 0x0114 => 0x01bc, 0x0115 => 0x01f4, 0x0116 => 0x02ee, 0x0117 => 0x022c, + 0x0118 => 0x022c, 0x0119 => 0x02d2, 0x011a => 0x0190, 0x011b => 0x01f4, + 0x011c => 0x029b, 0x011d => 0x022c, 0x011e => 0x0225, 0x011f => 0x02d2, + 0x0120 => 0x0185, 0x0121 => 0x02d2, 0x0122 => 0x01f4, 0x0123 => 0x029b, + 0x0124 => 0x0263, 0x0125 => 0x029b, 0x0126 => 0x029b, 0x0127 => 0x029b, + 0x0128 => 0x02d2, 0x0129 => 0x0185, 0x012a => 0x029b, 0x012b => 0x0185, + 0x012c => 0x01f4, 0x012d => 0x025e, 0x012e => 0x0185, 0x012f => 0x022c, + 0x0130 => 0x0116, 0x0131 => 0x025e, 0x0132 => 0x01f4, 0x0133 => 0x022c, + 0x0134 => 0x0225, 0x0135 => 0x01f4, 0x0136 => 0x01f4, 0x0137 => 0x0185, + 0x0138 => 0x022c, 0x0139 => 0x012c, 0x013a => 0x0116, 0x013b => 0x01f4, + ); + + /* The cmap table is similarly synthesized. + */ + $cmapData = array( + 0x20 => 0x01, 0x21 => 0x02, 0x22 => 0x03, 0x23 => 0x04, + 0x24 => 0x05, 0x25 => 0x06, 0x26 => 0x07, 0x2019 => 0x08, + 0x28 => 0x09, 0x29 => 0x0a, 0x2a => 0x0b, 0x2b => 0x0c, + 0x2c => 0x0d, 0x2d => 0x0e, 0x2e => 0x0f, 0x2f => 0x10, + 0x30 => 0x11, 0x31 => 0x12, 0x32 => 0x13, 0x33 => 0x14, + 0x34 => 0x15, 0x35 => 0x16, 0x36 => 0x17, 0x37 => 0x18, + 0x38 => 0x19, 0x39 => 0x1a, 0x3a => 0x1b, 0x3b => 0x1c, + 0x3c => 0x1d, 0x3d => 0x1e, 0x3e => 0x1f, 0x3f => 0x20, + 0x40 => 0x21, 0x41 => 0x22, 0x42 => 0x23, 0x43 => 0x24, + 0x44 => 0x25, 0x45 => 0x26, 0x46 => 0x27, 0x47 => 0x28, + 0x48 => 0x29, 0x49 => 0x2a, 0x4a => 0x2b, 0x4b => 0x2c, + 0x4c => 0x2d, 0x4d => 0x2e, 0x4e => 0x2f, 0x4f => 0x30, + 0x50 => 0x31, 0x51 => 0x32, 0x52 => 0x33, 0x53 => 0x34, + 0x54 => 0x35, 0x55 => 0x36, 0x56 => 0x37, 0x57 => 0x38, + 0x58 => 0x39, 0x59 => 0x3a, 0x5a => 0x3b, 0x5b => 0x3c, + 0x5c => 0x3d, 0x5d => 0x3e, 0x5e => 0x3f, 0x5f => 0x40, + 0x2018 => 0x41, 0x61 => 0x42, 0x62 => 0x43, 0x63 => 0x44, + 0x64 => 0x45, 0x65 => 0x46, 0x66 => 0x47, 0x67 => 0x48, + 0x68 => 0x49, 0x69 => 0x4a, 0x6a => 0x4b, 0x6b => 0x4c, + 0x6c => 0x4d, 0x6d => 0x4e, 0x6e => 0x4f, 0x6f => 0x50, + 0x70 => 0x51, 0x71 => 0x52, 0x72 => 0x53, 0x73 => 0x54, + 0x74 => 0x55, 0x75 => 0x56, 0x76 => 0x57, 0x77 => 0x58, + 0x78 => 0x59, 0x79 => 0x5a, 0x7a => 0x5b, 0x7b => 0x5c, + 0x7c => 0x5d, 0x7d => 0x5e, 0x7e => 0x5f, 0xa1 => 0x60, + 0xa2 => 0x61, 0xa3 => 0x62, 0x2044 => 0x63, 0xa5 => 0x64, + 0x0192 => 0x65, 0xa7 => 0x66, 0xa4 => 0x67, 0x27 => 0x68, + 0x201c => 0x69, 0xab => 0x6a, 0x2039 => 0x6b, 0x203a => 0x6c, + 0xfb01 => 0x6d, 0xfb02 => 0x6e, 0x2013 => 0x6f, 0x2020 => 0x70, + 0x2021 => 0x71, 0xb7 => 0x72, 0xb6 => 0x73, 0x2022 => 0x74, + 0x201a => 0x75, 0x201e => 0x76, 0x201d => 0x77, 0xbb => 0x78, + 0x2026 => 0x79, 0x2030 => 0x7a, 0xbf => 0x7b, 0x60 => 0x7c, + 0xb4 => 0x7d, 0x02c6 => 0x7e, 0x02dc => 0x7f, 0xaf => 0x80, + 0x02d8 => 0x81, 0x02d9 => 0x82, 0xa8 => 0x83, 0x02da => 0x84, + 0xb8 => 0x85, 0x02dd => 0x86, 0x02db => 0x87, 0x02c7 => 0x88, + 0x2014 => 0x89, 0xc6 => 0x8a, 0xaa => 0x8b, 0x0141 => 0x8c, + 0xd8 => 0x8d, 0x0152 => 0x8e, 0xba => 0x8f, 0xe6 => 0x90, + 0x0131 => 0x91, 0x0142 => 0x92, 0xf8 => 0x93, 0x0153 => 0x94, + 0xdf => 0x95, 0xcf => 0x96, 0xe9 => 0x97, 0x0103 => 0x98, + 0x0171 => 0x99, 0x011b => 0x9a, 0x0178 => 0x9b, 0xf7 => 0x9c, + 0xdd => 0x9d, 0xc2 => 0x9e, 0xe1 => 0x9f, 0xdb => 0xa0, + 0xfd => 0xa1, 0x0219 => 0xa2, 0xea => 0xa3, 0x016e => 0xa4, + 0xdc => 0xa5, 0x0105 => 0xa6, 0xda => 0xa7, 0x0173 => 0xa8, + 0xcb => 0xa9, 0x0110 => 0xaa, 0xf6c3 => 0xab, 0xa9 => 0xac, + 0x0112 => 0xad, 0x010d => 0xae, 0xe5 => 0xaf, 0x0145 => 0xb0, + 0x013a => 0xb1, 0xe0 => 0xb2, 0x0162 => 0xb3, 0x0106 => 0xb4, + 0xe3 => 0xb5, 0x0116 => 0xb6, 0x0161 => 0xb7, 0x015f => 0xb8, + 0xed => 0xb9, 0x25ca => 0xba, 0x0158 => 0xbb, 0x0122 => 0xbc, + 0xfb => 0xbd, 0xe2 => 0xbe, 0x0100 => 0xbf, 0x0159 => 0xc0, + 0xe7 => 0xc1, 0x017b => 0xc2, 0xde => 0xc3, 0x014c => 0xc4, + 0x0154 => 0xc5, 0x015a => 0xc6, 0x010f => 0xc7, 0x016a => 0xc8, + 0x016f => 0xc9, 0xb3 => 0xca, 0xd2 => 0xcb, 0xc0 => 0xcc, + 0x0102 => 0xcd, 0xd7 => 0xce, 0xfa => 0xcf, 0x0164 => 0xd0, + 0x2202 => 0xd1, 0xff => 0xd2, 0x0143 => 0xd3, 0xee => 0xd4, + 0xca => 0xd5, 0xe4 => 0xd6, 0xeb => 0xd7, 0x0107 => 0xd8, + 0x0144 => 0xd9, 0x016b => 0xda, 0x0147 => 0xdb, 0xcd => 0xdc, + 0xb1 => 0xdd, 0xa6 => 0xde, 0xae => 0xdf, 0x011e => 0xe0, + 0x0130 => 0xe1, 0x2211 => 0xe2, 0xc8 => 0xe3, 0x0155 => 0xe4, + 0x014d => 0xe5, 0x0179 => 0xe6, 0x017d => 0xe7, 0x2265 => 0xe8, + 0xd0 => 0xe9, 0xc7 => 0xea, 0x013c => 0xeb, 0x0165 => 0xec, + 0x0119 => 0xed, 0x0172 => 0xee, 0xc1 => 0xef, 0xc4 => 0xf0, + 0xe8 => 0xf1, 0x017a => 0xf2, 0x012f => 0xf3, 0xd3 => 0xf4, + 0xf3 => 0xf5, 0x0101 => 0xf6, 0x015b => 0xf7, 0xef => 0xf8, + 0xd4 => 0xf9, 0xd9 => 0xfa, 0x2206 => 0xfb, 0xfe => 0xfc, + 0xb2 => 0xfd, 0xd6 => 0xfe, 0xb5 => 0xff, 0xec => 0x0100, + 0x0151 => 0x0101, 0x0118 => 0x0102, 0x0111 => 0x0103, 0xbe => 0x0104, + 0x015e => 0x0105, 0x013e => 0x0106, 0x0136 => 0x0107, 0x0139 => 0x0108, + 0x2122 => 0x0109, 0x0117 => 0x010a, 0xcc => 0x010b, 0x012a => 0x010c, + 0x013d => 0x010d, 0xbd => 0x010e, 0x2264 => 0x010f, 0xf4 => 0x0110, + 0xf1 => 0x0111, 0x0170 => 0x0112, 0xc9 => 0x0113, 0x0113 => 0x0114, + 0x011f => 0x0115, 0xbc => 0x0116, 0x0160 => 0x0117, 0x0218 => 0x0118, + 0x0150 => 0x0119, 0xb0 => 0x011a, 0xf2 => 0x011b, 0x010c => 0x011c, + 0xf9 => 0x011d, 0x221a => 0x011e, 0x010e => 0x011f, 0x0157 => 0x0120, + 0xd1 => 0x0121, 0xf5 => 0x0122, 0x0156 => 0x0123, 0x013b => 0x0124, + 0xc3 => 0x0125, 0x0104 => 0x0126, 0xc5 => 0x0127, 0xd5 => 0x0128, + 0x017c => 0x0129, 0x011a => 0x012a, 0x012e => 0x012b, 0x0137 => 0x012c, + 0x2212 => 0x012d, 0xce => 0x012e, 0x0148 => 0x012f, 0x0163 => 0x0130, + 0xac => 0x0131, 0xf6 => 0x0132, 0xfc => 0x0133, 0x2260 => 0x0134, + 0x0123 => 0x0135, 0xf0 => 0x0136, 0x017e => 0x0137, 0x0146 => 0x0138, + 0xb9 => 0x0139, 0x012b => 0x013a, 0x20ac => 0x013b); + // require_once 'Zend/Pdf/Cmap.php'; + $this->_cmap = Zend_Pdf_Cmap::cmapWithTypeData( + Zend_Pdf_Cmap::TYPE_BYTE_ENCODING_STATIC, $cmapData); + + + /* Resource dictionary */ + + /* The resource dictionary for the standard fonts is sparse because PDF + * viewers already have all of the metrics data. We only need to provide + * the font name and encoding method. + */ + $this->_resource->BaseFont = new Zend_Pdf_Element_Name('Times-BoldItalic'); + } +} diff --git a/library/Zend/Pdf/Resource/Font/Simple/Standard/TimesItalic.php b/library/Zend/Pdf/Resource/Font/Simple/Standard/TimesItalic.php new file mode 100644 index 0000000..64987a8 --- /dev/null +++ b/library/Zend/Pdf/Resource/Font/Simple/Standard/TimesItalic.php @@ -0,0 +1,305 @@ +_fontNames[Zend_Pdf_Font::NAME_COPYRIGHT]['en'] = + "\x00\x43\x00\x6f\x00\x70\x00\x79\x00\x72\x00\x69\x00\x67\x00\x68\x00" + . "\x74\x00\x20\x00\x28\x00\x63\x00\x29\x00\x20\x00\x31\x00\x39\x00" + . "\x38\x00\x35\x00\x2c\x00\x20\x00\x31\x00\x39\x00\x38\x00\x37\x00" + . "\x2c\x00\x20\x00\x31\x00\x39\x00\x38\x00\x39\x00\x2c\x00\x20\x00" + . "\x31\x00\x39\x00\x39\x00\x30\x00\x2c\x00\x20\x00\x31\x00\x39\x00" + . "\x39\x00\x33\x00\x2c\x00\x20\x00\x31\x00\x39\x00\x39\x00\x37\x00" + . "\x20\x00\x41\x00\x64\x00\x6f\x00\x62\x00\x65\x00\x20\x00\x53\x00" + . "\x79\x00\x73\x00\x74\x00\x65\x00\x6d\x00\x73\x00\x20\x00\x49\x00" + . "\x6e\x00\x63\x00\x6f\x00\x72\x00\x70\x00\x6f\x00\x72\x00\x61\x00" + . "\x74\x00\x65\x00\x64\x00\x2e\x00\x20\x00\x20\x00\x41\x00\x6c\x00" + . "\x6c\x00\x20\x00\x52\x00\x69\x00\x67\x00\x68\x00\x74\x00\x73\x00" + . "\x20\x00\x52\x00\x65\x00\x73\x00\x65\x00\x72\x00\x76\x00\x65\x00" + . "\x64\x00\x2e\x00\x54\x00\x69\x00\x6d\x00\x65\x00\x73\x00\x20\x00" + . "\x69\x00\x73\x00\x20\x00\x61\x00\x20\x00\x74\x00\x72\x00\x61\x00" + . "\x64\x00\x65\x00\x6d\x00\x61\x00\x72\x00\x6b\x00\x20\x00\x6f\x00" + . "\x66\x00\x20\x00\x4c\x00\x69\x00\x6e\x00\x6f\x00\x74\x00\x79\x00" + . "\x70\x00\x65\x00\x2d\x00\x48\x00\x65\x00\x6c\x00\x6c\x00\x20\x00" + . "\x41\x00\x47\x00\x20\x00\x61\x00\x6e\x00\x64\x00\x2f\x00\x6f\x00" + . "\x72\x00\x20\x00\x69\x00\x74\x00\x73\x00\x20\x00\x73\x00\x75\x00" + . "\x62\x00\x73\x00\x69\x00\x64\x00\x69\x00\x61\x00\x72\x00\x69\x00" + . "\x65\x00\x73\x00\x2e"; + $this->_fontNames[Zend_Pdf_Font::NAME_FAMILY]['en'] = + "\x00\x54\x00\x69\x00\x6d\x00\x65\x00\x73"; + $this->_fontNames[Zend_Pdf_Font::NAME_STYLE]['en'] = + "\x00\x4d\x00\x65\x00\x64\x00\x69\x00\x75\x00\x6d"; + $this->_fontNames[Zend_Pdf_Font::NAME_ID]['en'] = + "\x00\x34\x00\x33\x00\x30\x00\x36\x00\x37"; + $this->_fontNames[Zend_Pdf_Font::NAME_FULL]['en'] = + "\x00\x54\x00\x69\x00\x6d\x00\x65\x00\x73\x00\x2d\x00\x49\x00\x74\x00" + . "\x61\x00\x6c\x00\x69\x00\x63\x00\x20\x00\x4d\x00\x65\x00\x64\x00" + . "\x69\x00\x75\x00\x6d"; + $this->_fontNames[Zend_Pdf_Font::NAME_VERSION]['en'] = + "\x00\x30\x00\x30\x00\x32\x00\x2e\x00\x30\x00\x30\x00\x30"; + $this->_fontNames[Zend_Pdf_Font::NAME_POSTSCRIPT]['en'] = + "\x00\x54\x00\x69\x00\x6d\x00\x65\x00\x73\x00\x2d\x00\x49\x00\x74\x00" + . "\x61\x00\x6c\x00\x69\x00\x63"; + + $this->_isBold = false; + $this->_isItalic = true; + $this->_isMonospaced = false; + + $this->_underlinePosition = -100; + $this->_underlineThickness = 50; + $this->_strikePosition = 225; + $this->_strikeThickness = 50; + + $this->_unitsPerEm = 1000; + + $this->_ascent = 683; + $this->_descent = -217; + $this->_lineGap = 300; + + /* The glyph numbers assigned here are synthetic; they do not match the + * actual glyph numbers used by the font. This is not a big deal though + * since this data never makes it to the PDF file. It is only used + * internally for layout calculations. + */ + $this->_glyphWidths = array( + 0x00 => 0x01f4, 0x01 => 0xfa, 0x02 => 0x014d, 0x03 => 0x01a4, + 0x04 => 0x01f4, 0x05 => 0x01f4, 0x06 => 0x0341, 0x07 => 0x030a, + 0x08 => 0x014d, 0x09 => 0x014d, 0x0a => 0x014d, 0x0b => 0x01f4, + 0x0c => 0x02a3, 0x0d => 0xfa, 0x0e => 0x014d, 0x0f => 0xfa, + 0x10 => 0x0116, 0x11 => 0x01f4, 0x12 => 0x01f4, 0x13 => 0x01f4, + 0x14 => 0x01f4, 0x15 => 0x01f4, 0x16 => 0x01f4, 0x17 => 0x01f4, + 0x18 => 0x01f4, 0x19 => 0x01f4, 0x1a => 0x01f4, 0x1b => 0x014d, + 0x1c => 0x014d, 0x1d => 0x02a3, 0x1e => 0x02a3, 0x1f => 0x02a3, + 0x20 => 0x01f4, 0x21 => 0x0398, 0x22 => 0x0263, 0x23 => 0x0263, + 0x24 => 0x029b, 0x25 => 0x02d2, 0x26 => 0x0263, 0x27 => 0x0263, + 0x28 => 0x02d2, 0x29 => 0x02d2, 0x2a => 0x014d, 0x2b => 0x01bc, + 0x2c => 0x029b, 0x2d => 0x022c, 0x2e => 0x0341, 0x2f => 0x029b, + 0x30 => 0x02d2, 0x31 => 0x0263, 0x32 => 0x02d2, 0x33 => 0x0263, + 0x34 => 0x01f4, 0x35 => 0x022c, 0x36 => 0x02d2, 0x37 => 0x0263, + 0x38 => 0x0341, 0x39 => 0x0263, 0x3a => 0x022c, 0x3b => 0x022c, + 0x3c => 0x0185, 0x3d => 0x0116, 0x3e => 0x0185, 0x3f => 0x01a6, + 0x40 => 0x01f4, 0x41 => 0x014d, 0x42 => 0x01f4, 0x43 => 0x01f4, + 0x44 => 0x01bc, 0x45 => 0x01f4, 0x46 => 0x01bc, 0x47 => 0x0116, + 0x48 => 0x01f4, 0x49 => 0x01f4, 0x4a => 0x0116, 0x4b => 0x0116, + 0x4c => 0x01bc, 0x4d => 0x0116, 0x4e => 0x02d2, 0x4f => 0x01f4, + 0x50 => 0x01f4, 0x51 => 0x01f4, 0x52 => 0x01f4, 0x53 => 0x0185, + 0x54 => 0x0185, 0x55 => 0x0116, 0x56 => 0x01f4, 0x57 => 0x01bc, + 0x58 => 0x029b, 0x59 => 0x01bc, 0x5a => 0x01bc, 0x5b => 0x0185, + 0x5c => 0x0190, 0x5d => 0x0113, 0x5e => 0x0190, 0x5f => 0x021d, + 0x60 => 0x0185, 0x61 => 0x01f4, 0x62 => 0x01f4, 0x63 => 0xa7, + 0x64 => 0x01f4, 0x65 => 0x01f4, 0x66 => 0x01f4, 0x67 => 0x01f4, + 0x68 => 0xd6, 0x69 => 0x022c, 0x6a => 0x01f4, 0x6b => 0x014d, + 0x6c => 0x014d, 0x6d => 0x01f4, 0x6e => 0x01f4, 0x6f => 0x01f4, + 0x70 => 0x01f4, 0x71 => 0x01f4, 0x72 => 0xfa, 0x73 => 0x020b, + 0x74 => 0x015e, 0x75 => 0x014d, 0x76 => 0x022c, 0x77 => 0x022c, + 0x78 => 0x01f4, 0x79 => 0x0379, 0x7a => 0x03e8, 0x7b => 0x01f4, + 0x7c => 0x014d, 0x7d => 0x014d, 0x7e => 0x014d, 0x7f => 0x014d, + 0x80 => 0x014d, 0x81 => 0x014d, 0x82 => 0x014d, 0x83 => 0x014d, + 0x84 => 0x014d, 0x85 => 0x014d, 0x86 => 0x014d, 0x87 => 0x014d, + 0x88 => 0x014d, 0x89 => 0x0379, 0x8a => 0x0379, 0x8b => 0x0114, + 0x8c => 0x022c, 0x8d => 0x02d2, 0x8e => 0x03b0, 0x8f => 0x0136, + 0x90 => 0x029b, 0x91 => 0x0116, 0x92 => 0x0116, 0x93 => 0x01f4, + 0x94 => 0x029b, 0x95 => 0x01f4, 0x96 => 0x014d, 0x97 => 0x01bc, + 0x98 => 0x01f4, 0x99 => 0x01f4, 0x9a => 0x01bc, 0x9b => 0x022c, + 0x9c => 0x02a3, 0x9d => 0x022c, 0x9e => 0x0263, 0x9f => 0x01f4, + 0xa0 => 0x02d2, 0xa1 => 0x01bc, 0xa2 => 0x0185, 0xa3 => 0x01bc, + 0xa4 => 0x02d2, 0xa5 => 0x02d2, 0xa6 => 0x01f4, 0xa7 => 0x02d2, + 0xa8 => 0x01f4, 0xa9 => 0x0263, 0xaa => 0x02d2, 0xab => 0xfa, + 0xac => 0x02f8, 0xad => 0x0263, 0xae => 0x01bc, 0xaf => 0x01f4, + 0xb0 => 0x029b, 0xb1 => 0x0116, 0xb2 => 0x01f4, 0xb3 => 0x022c, + 0xb4 => 0x029b, 0xb5 => 0x01f4, 0xb6 => 0x0263, 0xb7 => 0x0185, + 0xb8 => 0x0185, 0xb9 => 0x0116, 0xba => 0x01d7, 0xbb => 0x0263, + 0xbc => 0x02d2, 0xbd => 0x01f4, 0xbe => 0x01f4, 0xbf => 0x0263, + 0xc0 => 0x0185, 0xc1 => 0x01bc, 0xc2 => 0x022c, 0xc3 => 0x0263, + 0xc4 => 0x02d2, 0xc5 => 0x0263, 0xc6 => 0x01f4, 0xc7 => 0x0220, + 0xc8 => 0x02d2, 0xc9 => 0x01f4, 0xca => 0x012c, 0xcb => 0x02d2, + 0xcc => 0x0263, 0xcd => 0x0263, 0xce => 0x02a3, 0xcf => 0x01f4, + 0xd0 => 0x022c, 0xd1 => 0x01dc, 0xd2 => 0x01bc, 0xd3 => 0x029b, + 0xd4 => 0x0116, 0xd5 => 0x0263, 0xd6 => 0x01f4, 0xd7 => 0x01bc, + 0xd8 => 0x01bc, 0xd9 => 0x01f4, 0xda => 0x01f4, 0xdb => 0x029b, + 0xdc => 0x014d, 0xdd => 0x02a3, 0xde => 0x0113, 0xdf => 0x02f8, + 0xe0 => 0x02d2, 0xe1 => 0x014d, 0xe2 => 0x0258, 0xe3 => 0x0263, + 0xe4 => 0x0185, 0xe5 => 0x01f4, 0xe6 => 0x022c, 0xe7 => 0x022c, + 0xe8 => 0x0225, 0xe9 => 0x02d2, 0xea => 0x029b, 0xeb => 0x0116, + 0xec => 0x012c, 0xed => 0x01bc, 0xee => 0x02d2, 0xef => 0x0263, + 0xf0 => 0x0263, 0xf1 => 0x01bc, 0xf2 => 0x0185, 0xf3 => 0x0116, + 0xf4 => 0x02d2, 0xf5 => 0x01f4, 0xf6 => 0x01f4, 0xf7 => 0x0185, + 0xf8 => 0x0116, 0xf9 => 0x02d2, 0xfa => 0x02d2, 0xfb => 0x0264, + 0xfc => 0x01f4, 0xfd => 0x012c, 0xfe => 0x02d2, 0xff => 0x01f4, + 0x0100 => 0x0116, 0x0101 => 0x01f4, 0x0102 => 0x0263, 0x0103 => 0x01f4, + 0x0104 => 0x02ee, 0x0105 => 0x01f4, 0x0106 => 0x012c, 0x0107 => 0x029b, + 0x0108 => 0x022c, 0x0109 => 0x03d4, 0x010a => 0x01bc, 0x010b => 0x014d, + 0x010c => 0x014d, 0x010d => 0x0263, 0x010e => 0x02ee, 0x010f => 0x0225, + 0x0110 => 0x01f4, 0x0111 => 0x01f4, 0x0112 => 0x02d2, 0x0113 => 0x0263, + 0x0114 => 0x01bc, 0x0115 => 0x01f4, 0x0116 => 0x02ee, 0x0117 => 0x01f4, + 0x0118 => 0x01f4, 0x0119 => 0x02d2, 0x011a => 0x0190, 0x011b => 0x01f4, + 0x011c => 0x029b, 0x011d => 0x01f4, 0x011e => 0x01c5, 0x011f => 0x02d2, + 0x0120 => 0x0185, 0x0121 => 0x029b, 0x0122 => 0x01f4, 0x0123 => 0x0263, + 0x0124 => 0x022c, 0x0125 => 0x0263, 0x0126 => 0x0263, 0x0127 => 0x0263, + 0x0128 => 0x02d2, 0x0129 => 0x0185, 0x012a => 0x0263, 0x012b => 0x014d, + 0x012c => 0x01bc, 0x012d => 0x02a3, 0x012e => 0x014d, 0x012f => 0x01f4, + 0x0130 => 0x0116, 0x0131 => 0x02a3, 0x0132 => 0x01f4, 0x0133 => 0x01f4, + 0x0134 => 0x0225, 0x0135 => 0x01f4, 0x0136 => 0x01f4, 0x0137 => 0x0185, + 0x0138 => 0x01f4, 0x0139 => 0x012c, 0x013a => 0x0116, 0x013b => 0x01f4, + ); + + /* The cmap table is similarly synthesized. + */ + $cmapData = array( + 0x20 => 0x01, 0x21 => 0x02, 0x22 => 0x03, 0x23 => 0x04, + 0x24 => 0x05, 0x25 => 0x06, 0x26 => 0x07, 0x2019 => 0x08, + 0x28 => 0x09, 0x29 => 0x0a, 0x2a => 0x0b, 0x2b => 0x0c, + 0x2c => 0x0d, 0x2d => 0x0e, 0x2e => 0x0f, 0x2f => 0x10, + 0x30 => 0x11, 0x31 => 0x12, 0x32 => 0x13, 0x33 => 0x14, + 0x34 => 0x15, 0x35 => 0x16, 0x36 => 0x17, 0x37 => 0x18, + 0x38 => 0x19, 0x39 => 0x1a, 0x3a => 0x1b, 0x3b => 0x1c, + 0x3c => 0x1d, 0x3d => 0x1e, 0x3e => 0x1f, 0x3f => 0x20, + 0x40 => 0x21, 0x41 => 0x22, 0x42 => 0x23, 0x43 => 0x24, + 0x44 => 0x25, 0x45 => 0x26, 0x46 => 0x27, 0x47 => 0x28, + 0x48 => 0x29, 0x49 => 0x2a, 0x4a => 0x2b, 0x4b => 0x2c, + 0x4c => 0x2d, 0x4d => 0x2e, 0x4e => 0x2f, 0x4f => 0x30, + 0x50 => 0x31, 0x51 => 0x32, 0x52 => 0x33, 0x53 => 0x34, + 0x54 => 0x35, 0x55 => 0x36, 0x56 => 0x37, 0x57 => 0x38, + 0x58 => 0x39, 0x59 => 0x3a, 0x5a => 0x3b, 0x5b => 0x3c, + 0x5c => 0x3d, 0x5d => 0x3e, 0x5e => 0x3f, 0x5f => 0x40, + 0x2018 => 0x41, 0x61 => 0x42, 0x62 => 0x43, 0x63 => 0x44, + 0x64 => 0x45, 0x65 => 0x46, 0x66 => 0x47, 0x67 => 0x48, + 0x68 => 0x49, 0x69 => 0x4a, 0x6a => 0x4b, 0x6b => 0x4c, + 0x6c => 0x4d, 0x6d => 0x4e, 0x6e => 0x4f, 0x6f => 0x50, + 0x70 => 0x51, 0x71 => 0x52, 0x72 => 0x53, 0x73 => 0x54, + 0x74 => 0x55, 0x75 => 0x56, 0x76 => 0x57, 0x77 => 0x58, + 0x78 => 0x59, 0x79 => 0x5a, 0x7a => 0x5b, 0x7b => 0x5c, + 0x7c => 0x5d, 0x7d => 0x5e, 0x7e => 0x5f, 0xa1 => 0x60, + 0xa2 => 0x61, 0xa3 => 0x62, 0x2044 => 0x63, 0xa5 => 0x64, + 0x0192 => 0x65, 0xa7 => 0x66, 0xa4 => 0x67, 0x27 => 0x68, + 0x201c => 0x69, 0xab => 0x6a, 0x2039 => 0x6b, 0x203a => 0x6c, + 0xfb01 => 0x6d, 0xfb02 => 0x6e, 0x2013 => 0x6f, 0x2020 => 0x70, + 0x2021 => 0x71, 0xb7 => 0x72, 0xb6 => 0x73, 0x2022 => 0x74, + 0x201a => 0x75, 0x201e => 0x76, 0x201d => 0x77, 0xbb => 0x78, + 0x2026 => 0x79, 0x2030 => 0x7a, 0xbf => 0x7b, 0x60 => 0x7c, + 0xb4 => 0x7d, 0x02c6 => 0x7e, 0x02dc => 0x7f, 0xaf => 0x80, + 0x02d8 => 0x81, 0x02d9 => 0x82, 0xa8 => 0x83, 0x02da => 0x84, + 0xb8 => 0x85, 0x02dd => 0x86, 0x02db => 0x87, 0x02c7 => 0x88, + 0x2014 => 0x89, 0xc6 => 0x8a, 0xaa => 0x8b, 0x0141 => 0x8c, + 0xd8 => 0x8d, 0x0152 => 0x8e, 0xba => 0x8f, 0xe6 => 0x90, + 0x0131 => 0x91, 0x0142 => 0x92, 0xf8 => 0x93, 0x0153 => 0x94, + 0xdf => 0x95, 0xcf => 0x96, 0xe9 => 0x97, 0x0103 => 0x98, + 0x0171 => 0x99, 0x011b => 0x9a, 0x0178 => 0x9b, 0xf7 => 0x9c, + 0xdd => 0x9d, 0xc2 => 0x9e, 0xe1 => 0x9f, 0xdb => 0xa0, + 0xfd => 0xa1, 0x0219 => 0xa2, 0xea => 0xa3, 0x016e => 0xa4, + 0xdc => 0xa5, 0x0105 => 0xa6, 0xda => 0xa7, 0x0173 => 0xa8, + 0xcb => 0xa9, 0x0110 => 0xaa, 0xf6c3 => 0xab, 0xa9 => 0xac, + 0x0112 => 0xad, 0x010d => 0xae, 0xe5 => 0xaf, 0x0145 => 0xb0, + 0x013a => 0xb1, 0xe0 => 0xb2, 0x0162 => 0xb3, 0x0106 => 0xb4, + 0xe3 => 0xb5, 0x0116 => 0xb6, 0x0161 => 0xb7, 0x015f => 0xb8, + 0xed => 0xb9, 0x25ca => 0xba, 0x0158 => 0xbb, 0x0122 => 0xbc, + 0xfb => 0xbd, 0xe2 => 0xbe, 0x0100 => 0xbf, 0x0159 => 0xc0, + 0xe7 => 0xc1, 0x017b => 0xc2, 0xde => 0xc3, 0x014c => 0xc4, + 0x0154 => 0xc5, 0x015a => 0xc6, 0x010f => 0xc7, 0x016a => 0xc8, + 0x016f => 0xc9, 0xb3 => 0xca, 0xd2 => 0xcb, 0xc0 => 0xcc, + 0x0102 => 0xcd, 0xd7 => 0xce, 0xfa => 0xcf, 0x0164 => 0xd0, + 0x2202 => 0xd1, 0xff => 0xd2, 0x0143 => 0xd3, 0xee => 0xd4, + 0xca => 0xd5, 0xe4 => 0xd6, 0xeb => 0xd7, 0x0107 => 0xd8, + 0x0144 => 0xd9, 0x016b => 0xda, 0x0147 => 0xdb, 0xcd => 0xdc, + 0xb1 => 0xdd, 0xa6 => 0xde, 0xae => 0xdf, 0x011e => 0xe0, + 0x0130 => 0xe1, 0x2211 => 0xe2, 0xc8 => 0xe3, 0x0155 => 0xe4, + 0x014d => 0xe5, 0x0179 => 0xe6, 0x017d => 0xe7, 0x2265 => 0xe8, + 0xd0 => 0xe9, 0xc7 => 0xea, 0x013c => 0xeb, 0x0165 => 0xec, + 0x0119 => 0xed, 0x0172 => 0xee, 0xc1 => 0xef, 0xc4 => 0xf0, + 0xe8 => 0xf1, 0x017a => 0xf2, 0x012f => 0xf3, 0xd3 => 0xf4, + 0xf3 => 0xf5, 0x0101 => 0xf6, 0x015b => 0xf7, 0xef => 0xf8, + 0xd4 => 0xf9, 0xd9 => 0xfa, 0x2206 => 0xfb, 0xfe => 0xfc, + 0xb2 => 0xfd, 0xd6 => 0xfe, 0xb5 => 0xff, 0xec => 0x0100, + 0x0151 => 0x0101, 0x0118 => 0x0102, 0x0111 => 0x0103, 0xbe => 0x0104, + 0x015e => 0x0105, 0x013e => 0x0106, 0x0136 => 0x0107, 0x0139 => 0x0108, + 0x2122 => 0x0109, 0x0117 => 0x010a, 0xcc => 0x010b, 0x012a => 0x010c, + 0x013d => 0x010d, 0xbd => 0x010e, 0x2264 => 0x010f, 0xf4 => 0x0110, + 0xf1 => 0x0111, 0x0170 => 0x0112, 0xc9 => 0x0113, 0x0113 => 0x0114, + 0x011f => 0x0115, 0xbc => 0x0116, 0x0160 => 0x0117, 0x0218 => 0x0118, + 0x0150 => 0x0119, 0xb0 => 0x011a, 0xf2 => 0x011b, 0x010c => 0x011c, + 0xf9 => 0x011d, 0x221a => 0x011e, 0x010e => 0x011f, 0x0157 => 0x0120, + 0xd1 => 0x0121, 0xf5 => 0x0122, 0x0156 => 0x0123, 0x013b => 0x0124, + 0xc3 => 0x0125, 0x0104 => 0x0126, 0xc5 => 0x0127, 0xd5 => 0x0128, + 0x017c => 0x0129, 0x011a => 0x012a, 0x012e => 0x012b, 0x0137 => 0x012c, + 0x2212 => 0x012d, 0xce => 0x012e, 0x0148 => 0x012f, 0x0163 => 0x0130, + 0xac => 0x0131, 0xf6 => 0x0132, 0xfc => 0x0133, 0x2260 => 0x0134, + 0x0123 => 0x0135, 0xf0 => 0x0136, 0x017e => 0x0137, 0x0146 => 0x0138, + 0xb9 => 0x0139, 0x012b => 0x013a, 0x20ac => 0x013b); + // require_once 'Zend/Pdf/Cmap.php'; + $this->_cmap = Zend_Pdf_Cmap::cmapWithTypeData( + Zend_Pdf_Cmap::TYPE_BYTE_ENCODING_STATIC, $cmapData); + + + /* Resource dictionary */ + + /* The resource dictionary for the standard fonts is sparse because PDF + * viewers already have all of the metrics data. We only need to provide + * the font name and encoding method. + */ + $this->_resource->BaseFont = new Zend_Pdf_Element_Name('Times-Italic'); + } +} diff --git a/library/Zend/Pdf/Resource/Font/Simple/Standard/TimesRoman.php b/library/Zend/Pdf/Resource/Font/Simple/Standard/TimesRoman.php new file mode 100644 index 0000000..9d69ee8 --- /dev/null +++ b/library/Zend/Pdf/Resource/Font/Simple/Standard/TimesRoman.php @@ -0,0 +1,305 @@ +_fontNames[Zend_Pdf_Font::NAME_COPYRIGHT]['en'] = + "\x00\x43\x00\x6f\x00\x70\x00\x79\x00\x72\x00\x69\x00\x67\x00\x68\x00" + . "\x74\x00\x20\x00\x28\x00\x63\x00\x29\x00\x20\x00\x31\x00\x39\x00" + . "\x38\x00\x35\x00\x2c\x00\x20\x00\x31\x00\x39\x00\x38\x00\x37\x00" + . "\x2c\x00\x20\x00\x31\x00\x39\x00\x38\x00\x39\x00\x2c\x00\x20\x00" + . "\x31\x00\x39\x00\x39\x00\x30\x00\x2c\x00\x20\x00\x31\x00\x39\x00" + . "\x39\x00\x33\x00\x2c\x00\x20\x00\x31\x00\x39\x00\x39\x00\x37\x00" + . "\x20\x00\x41\x00\x64\x00\x6f\x00\x62\x00\x65\x00\x20\x00\x53\x00" + . "\x79\x00\x73\x00\x74\x00\x65\x00\x6d\x00\x73\x00\x20\x00\x49\x00" + . "\x6e\x00\x63\x00\x6f\x00\x72\x00\x70\x00\x6f\x00\x72\x00\x61\x00" + . "\x74\x00\x65\x00\x64\x00\x2e\x00\x20\x00\x20\x00\x41\x00\x6c\x00" + . "\x6c\x00\x20\x00\x52\x00\x69\x00\x67\x00\x68\x00\x74\x00\x73\x00" + . "\x20\x00\x52\x00\x65\x00\x73\x00\x65\x00\x72\x00\x76\x00\x65\x00" + . "\x64\x00\x2e\x00\x54\x00\x69\x00\x6d\x00\x65\x00\x73\x00\x20\x00" + . "\x69\x00\x73\x00\x20\x00\x61\x00\x20\x00\x74\x00\x72\x00\x61\x00" + . "\x64\x00\x65\x00\x6d\x00\x61\x00\x72\x00\x6b\x00\x20\x00\x6f\x00" + . "\x66\x00\x20\x00\x4c\x00\x69\x00\x6e\x00\x6f\x00\x74\x00\x79\x00" + . "\x70\x00\x65\x00\x2d\x00\x48\x00\x65\x00\x6c\x00\x6c\x00\x20\x00" + . "\x41\x00\x47\x00\x20\x00\x61\x00\x6e\x00\x64\x00\x2f\x00\x6f\x00" + . "\x72\x00\x20\x00\x69\x00\x74\x00\x73\x00\x20\x00\x73\x00\x75\x00" + . "\x62\x00\x73\x00\x69\x00\x64\x00\x69\x00\x61\x00\x72\x00\x69\x00" + . "\x65\x00\x73\x00\x2e"; + $this->_fontNames[Zend_Pdf_Font::NAME_FAMILY]['en'] = + "\x00\x54\x00\x69\x00\x6d\x00\x65\x00\x73"; + $this->_fontNames[Zend_Pdf_Font::NAME_STYLE]['en'] = + "\x00\x52\x00\x6f\x00\x6d\x00\x61\x00\x6e"; + $this->_fontNames[Zend_Pdf_Font::NAME_ID]['en'] = + "\x00\x34\x00\x33\x00\x30\x00\x36\x00\x38"; + $this->_fontNames[Zend_Pdf_Font::NAME_FULL]['en'] = + "\x00\x54\x00\x69\x00\x6d\x00\x65\x00\x73\x00\x2d\x00\x52\x00\x6f\x00" + . "\x6d\x00\x61\x00\x6e\x00\x20\x00\x52\x00\x6f\x00\x6d\x00\x61\x00" + . "\x6e"; + $this->_fontNames[Zend_Pdf_Font::NAME_VERSION]['en'] = + "\x00\x30\x00\x30\x00\x32\x00\x2e\x00\x30\x00\x30\x00\x30"; + $this->_fontNames[Zend_Pdf_Font::NAME_POSTSCRIPT]['en'] = + "\x00\x54\x00\x69\x00\x6d\x00\x65\x00\x73\x00\x2d\x00\x52\x00\x6f\x00" + . "\x6d\x00\x61\x00\x6e"; + + $this->_isBold = false; + $this->_isItalic = false; + $this->_isMonospaced = false; + + $this->_underlinePosition = -100; + $this->_underlineThickness = 50; + $this->_strikePosition = 225; + $this->_strikeThickness = 50; + + $this->_unitsPerEm = 1000; + + $this->_ascent = 683; + $this->_descent = -217; + $this->_lineGap = 300; + + /* The glyph numbers assigned here are synthetic; they do not match the + * actual glyph numbers used by the font. This is not a big deal though + * since this data never makes it to the PDF file. It is only used + * internally for layout calculations. + */ + $this->_glyphWidths = array( + 0x00 => 0x01f4, 0x01 => 0xfa, 0x02 => 0x014d, 0x03 => 0x0198, + 0x04 => 0x01f4, 0x05 => 0x01f4, 0x06 => 0x0341, 0x07 => 0x030a, + 0x08 => 0x014d, 0x09 => 0x014d, 0x0a => 0x014d, 0x0b => 0x01f4, + 0x0c => 0x0234, 0x0d => 0xfa, 0x0e => 0x014d, 0x0f => 0xfa, + 0x10 => 0x0116, 0x11 => 0x01f4, 0x12 => 0x01f4, 0x13 => 0x01f4, + 0x14 => 0x01f4, 0x15 => 0x01f4, 0x16 => 0x01f4, 0x17 => 0x01f4, + 0x18 => 0x01f4, 0x19 => 0x01f4, 0x1a => 0x01f4, 0x1b => 0x0116, + 0x1c => 0x0116, 0x1d => 0x0234, 0x1e => 0x0234, 0x1f => 0x0234, + 0x20 => 0x01bc, 0x21 => 0x0399, 0x22 => 0x02d2, 0x23 => 0x029b, + 0x24 => 0x029b, 0x25 => 0x02d2, 0x26 => 0x0263, 0x27 => 0x022c, + 0x28 => 0x02d2, 0x29 => 0x02d2, 0x2a => 0x014d, 0x2b => 0x0185, + 0x2c => 0x02d2, 0x2d => 0x0263, 0x2e => 0x0379, 0x2f => 0x02d2, + 0x30 => 0x02d2, 0x31 => 0x022c, 0x32 => 0x02d2, 0x33 => 0x029b, + 0x34 => 0x022c, 0x35 => 0x0263, 0x36 => 0x02d2, 0x37 => 0x02d2, + 0x38 => 0x03b0, 0x39 => 0x02d2, 0x3a => 0x02d2, 0x3b => 0x0263, + 0x3c => 0x014d, 0x3d => 0x0116, 0x3e => 0x014d, 0x3f => 0x01d5, + 0x40 => 0x01f4, 0x41 => 0x014d, 0x42 => 0x01bc, 0x43 => 0x01f4, + 0x44 => 0x01bc, 0x45 => 0x01f4, 0x46 => 0x01bc, 0x47 => 0x014d, + 0x48 => 0x01f4, 0x49 => 0x01f4, 0x4a => 0x0116, 0x4b => 0x0116, + 0x4c => 0x01f4, 0x4d => 0x0116, 0x4e => 0x030a, 0x4f => 0x01f4, + 0x50 => 0x01f4, 0x51 => 0x01f4, 0x52 => 0x01f4, 0x53 => 0x014d, + 0x54 => 0x0185, 0x55 => 0x0116, 0x56 => 0x01f4, 0x57 => 0x01f4, + 0x58 => 0x02d2, 0x59 => 0x01f4, 0x5a => 0x01f4, 0x5b => 0x01bc, + 0x5c => 0x01e0, 0x5d => 0xc8, 0x5e => 0x01e0, 0x5f => 0x021d, + 0x60 => 0x014d, 0x61 => 0x01f4, 0x62 => 0x01f4, 0x63 => 0xa7, + 0x64 => 0x01f4, 0x65 => 0x01f4, 0x66 => 0x01f4, 0x67 => 0x01f4, + 0x68 => 0xb4, 0x69 => 0x01bc, 0x6a => 0x01f4, 0x6b => 0x014d, + 0x6c => 0x014d, 0x6d => 0x022c, 0x6e => 0x022c, 0x6f => 0x01f4, + 0x70 => 0x01f4, 0x71 => 0x01f4, 0x72 => 0xfa, 0x73 => 0x01c5, + 0x74 => 0x015e, 0x75 => 0x014d, 0x76 => 0x01bc, 0x77 => 0x01bc, + 0x78 => 0x01f4, 0x79 => 0x03e8, 0x7a => 0x03e8, 0x7b => 0x01bc, + 0x7c => 0x014d, 0x7d => 0x014d, 0x7e => 0x014d, 0x7f => 0x014d, + 0x80 => 0x014d, 0x81 => 0x014d, 0x82 => 0x014d, 0x83 => 0x014d, + 0x84 => 0x014d, 0x85 => 0x014d, 0x86 => 0x014d, 0x87 => 0x014d, + 0x88 => 0x014d, 0x89 => 0x03e8, 0x8a => 0x0379, 0x8b => 0x0114, + 0x8c => 0x0263, 0x8d => 0x02d2, 0x8e => 0x0379, 0x8f => 0x0136, + 0x90 => 0x029b, 0x91 => 0x0116, 0x92 => 0x0116, 0x93 => 0x01f4, + 0x94 => 0x02d2, 0x95 => 0x01f4, 0x96 => 0x014d, 0x97 => 0x01bc, + 0x98 => 0x01bc, 0x99 => 0x01f4, 0x9a => 0x01bc, 0x9b => 0x02d2, + 0x9c => 0x0234, 0x9d => 0x02d2, 0x9e => 0x02d2, 0x9f => 0x01bc, + 0xa0 => 0x02d2, 0xa1 => 0x01f4, 0xa2 => 0x0185, 0xa3 => 0x01bc, + 0xa4 => 0x02d2, 0xa5 => 0x02d2, 0xa6 => 0x01bc, 0xa7 => 0x02d2, + 0xa8 => 0x01f4, 0xa9 => 0x0263, 0xaa => 0x02d2, 0xab => 0xfa, + 0xac => 0x02f8, 0xad => 0x0263, 0xae => 0x01bc, 0xaf => 0x01bc, + 0xb0 => 0x02d2, 0xb1 => 0x0116, 0xb2 => 0x01bc, 0xb3 => 0x0263, + 0xb4 => 0x029b, 0xb5 => 0x01bc, 0xb6 => 0x0263, 0xb7 => 0x0185, + 0xb8 => 0x0185, 0xb9 => 0x0116, 0xba => 0x01d7, 0xbb => 0x029b, + 0xbc => 0x02d2, 0xbd => 0x01f4, 0xbe => 0x01bc, 0xbf => 0x02d2, + 0xc0 => 0x014d, 0xc1 => 0x01bc, 0xc2 => 0x0263, 0xc3 => 0x022c, + 0xc4 => 0x02d2, 0xc5 => 0x029b, 0xc6 => 0x022c, 0xc7 => 0x024c, + 0xc8 => 0x02d2, 0xc9 => 0x01f4, 0xca => 0x012c, 0xcb => 0x02d2, + 0xcc => 0x02d2, 0xcd => 0x02d2, 0xce => 0x0234, 0xcf => 0x01f4, + 0xd0 => 0x0263, 0xd1 => 0x01dc, 0xd2 => 0x01f4, 0xd3 => 0x02d2, + 0xd4 => 0x0116, 0xd5 => 0x0263, 0xd6 => 0x01bc, 0xd7 => 0x01bc, + 0xd8 => 0x01bc, 0xd9 => 0x01f4, 0xda => 0x01f4, 0xdb => 0x02d2, + 0xdc => 0x014d, 0xdd => 0x0234, 0xde => 0xc8, 0xdf => 0x02f8, + 0xe0 => 0x02d2, 0xe1 => 0x014d, 0xe2 => 0x0258, 0xe3 => 0x0263, + 0xe4 => 0x014d, 0xe5 => 0x01f4, 0xe6 => 0x0263, 0xe7 => 0x0263, + 0xe8 => 0x0225, 0xe9 => 0x02d2, 0xea => 0x029b, 0xeb => 0x0116, + 0xec => 0x0146, 0xed => 0x01bc, 0xee => 0x02d2, 0xef => 0x02d2, + 0xf0 => 0x02d2, 0xf1 => 0x01bc, 0xf2 => 0x01bc, 0xf3 => 0x0116, + 0xf4 => 0x02d2, 0xf5 => 0x01f4, 0xf6 => 0x01bc, 0xf7 => 0x0185, + 0xf8 => 0x0116, 0xf9 => 0x02d2, 0xfa => 0x02d2, 0xfb => 0x0264, + 0xfc => 0x01f4, 0xfd => 0x012c, 0xfe => 0x02d2, 0xff => 0x01f4, + 0x0100 => 0x0116, 0x0101 => 0x01f4, 0x0102 => 0x0263, 0x0103 => 0x01f4, + 0x0104 => 0x02ee, 0x0105 => 0x022c, 0x0106 => 0x0158, 0x0107 => 0x02d2, + 0x0108 => 0x0263, 0x0109 => 0x03d4, 0x010a => 0x01bc, 0x010b => 0x014d, + 0x010c => 0x014d, 0x010d => 0x0263, 0x010e => 0x02ee, 0x010f => 0x0225, + 0x0110 => 0x01f4, 0x0111 => 0x01f4, 0x0112 => 0x02d2, 0x0113 => 0x0263, + 0x0114 => 0x01bc, 0x0115 => 0x01f4, 0x0116 => 0x02ee, 0x0117 => 0x022c, + 0x0118 => 0x022c, 0x0119 => 0x02d2, 0x011a => 0x0190, 0x011b => 0x01f4, + 0x011c => 0x029b, 0x011d => 0x01f4, 0x011e => 0x01c5, 0x011f => 0x02d2, + 0x0120 => 0x014d, 0x0121 => 0x02d2, 0x0122 => 0x01f4, 0x0123 => 0x029b, + 0x0124 => 0x0263, 0x0125 => 0x02d2, 0x0126 => 0x02d2, 0x0127 => 0x02d2, + 0x0128 => 0x02d2, 0x0129 => 0x01bc, 0x012a => 0x0263, 0x012b => 0x014d, + 0x012c => 0x01f4, 0x012d => 0x0234, 0x012e => 0x014d, 0x012f => 0x01f4, + 0x0130 => 0x0116, 0x0131 => 0x0234, 0x0132 => 0x01f4, 0x0133 => 0x01f4, + 0x0134 => 0x0225, 0x0135 => 0x01f4, 0x0136 => 0x01f4, 0x0137 => 0x01bc, + 0x0138 => 0x01f4, 0x0139 => 0x012c, 0x013a => 0x0116, 0x013b => 0x01f4, + ); + + /* The cmap table is similarly synthesized. + */ + $cmapData = array( + 0x20 => 0x01, 0x21 => 0x02, 0x22 => 0x03, 0x23 => 0x04, + 0x24 => 0x05, 0x25 => 0x06, 0x26 => 0x07, 0x2019 => 0x08, + 0x28 => 0x09, 0x29 => 0x0a, 0x2a => 0x0b, 0x2b => 0x0c, + 0x2c => 0x0d, 0x2d => 0x0e, 0x2e => 0x0f, 0x2f => 0x10, + 0x30 => 0x11, 0x31 => 0x12, 0x32 => 0x13, 0x33 => 0x14, + 0x34 => 0x15, 0x35 => 0x16, 0x36 => 0x17, 0x37 => 0x18, + 0x38 => 0x19, 0x39 => 0x1a, 0x3a => 0x1b, 0x3b => 0x1c, + 0x3c => 0x1d, 0x3d => 0x1e, 0x3e => 0x1f, 0x3f => 0x20, + 0x40 => 0x21, 0x41 => 0x22, 0x42 => 0x23, 0x43 => 0x24, + 0x44 => 0x25, 0x45 => 0x26, 0x46 => 0x27, 0x47 => 0x28, + 0x48 => 0x29, 0x49 => 0x2a, 0x4a => 0x2b, 0x4b => 0x2c, + 0x4c => 0x2d, 0x4d => 0x2e, 0x4e => 0x2f, 0x4f => 0x30, + 0x50 => 0x31, 0x51 => 0x32, 0x52 => 0x33, 0x53 => 0x34, + 0x54 => 0x35, 0x55 => 0x36, 0x56 => 0x37, 0x57 => 0x38, + 0x58 => 0x39, 0x59 => 0x3a, 0x5a => 0x3b, 0x5b => 0x3c, + 0x5c => 0x3d, 0x5d => 0x3e, 0x5e => 0x3f, 0x5f => 0x40, + 0x2018 => 0x41, 0x61 => 0x42, 0x62 => 0x43, 0x63 => 0x44, + 0x64 => 0x45, 0x65 => 0x46, 0x66 => 0x47, 0x67 => 0x48, + 0x68 => 0x49, 0x69 => 0x4a, 0x6a => 0x4b, 0x6b => 0x4c, + 0x6c => 0x4d, 0x6d => 0x4e, 0x6e => 0x4f, 0x6f => 0x50, + 0x70 => 0x51, 0x71 => 0x52, 0x72 => 0x53, 0x73 => 0x54, + 0x74 => 0x55, 0x75 => 0x56, 0x76 => 0x57, 0x77 => 0x58, + 0x78 => 0x59, 0x79 => 0x5a, 0x7a => 0x5b, 0x7b => 0x5c, + 0x7c => 0x5d, 0x7d => 0x5e, 0x7e => 0x5f, 0xa1 => 0x60, + 0xa2 => 0x61, 0xa3 => 0x62, 0x2044 => 0x63, 0xa5 => 0x64, + 0x0192 => 0x65, 0xa7 => 0x66, 0xa4 => 0x67, 0x27 => 0x68, + 0x201c => 0x69, 0xab => 0x6a, 0x2039 => 0x6b, 0x203a => 0x6c, + 0xfb01 => 0x6d, 0xfb02 => 0x6e, 0x2013 => 0x6f, 0x2020 => 0x70, + 0x2021 => 0x71, 0xb7 => 0x72, 0xb6 => 0x73, 0x2022 => 0x74, + 0x201a => 0x75, 0x201e => 0x76, 0x201d => 0x77, 0xbb => 0x78, + 0x2026 => 0x79, 0x2030 => 0x7a, 0xbf => 0x7b, 0x60 => 0x7c, + 0xb4 => 0x7d, 0x02c6 => 0x7e, 0x02dc => 0x7f, 0xaf => 0x80, + 0x02d8 => 0x81, 0x02d9 => 0x82, 0xa8 => 0x83, 0x02da => 0x84, + 0xb8 => 0x85, 0x02dd => 0x86, 0x02db => 0x87, 0x02c7 => 0x88, + 0x2014 => 0x89, 0xc6 => 0x8a, 0xaa => 0x8b, 0x0141 => 0x8c, + 0xd8 => 0x8d, 0x0152 => 0x8e, 0xba => 0x8f, 0xe6 => 0x90, + 0x0131 => 0x91, 0x0142 => 0x92, 0xf8 => 0x93, 0x0153 => 0x94, + 0xdf => 0x95, 0xcf => 0x96, 0xe9 => 0x97, 0x0103 => 0x98, + 0x0171 => 0x99, 0x011b => 0x9a, 0x0178 => 0x9b, 0xf7 => 0x9c, + 0xdd => 0x9d, 0xc2 => 0x9e, 0xe1 => 0x9f, 0xdb => 0xa0, + 0xfd => 0xa1, 0x0219 => 0xa2, 0xea => 0xa3, 0x016e => 0xa4, + 0xdc => 0xa5, 0x0105 => 0xa6, 0xda => 0xa7, 0x0173 => 0xa8, + 0xcb => 0xa9, 0x0110 => 0xaa, 0xf6c3 => 0xab, 0xa9 => 0xac, + 0x0112 => 0xad, 0x010d => 0xae, 0xe5 => 0xaf, 0x0145 => 0xb0, + 0x013a => 0xb1, 0xe0 => 0xb2, 0x0162 => 0xb3, 0x0106 => 0xb4, + 0xe3 => 0xb5, 0x0116 => 0xb6, 0x0161 => 0xb7, 0x015f => 0xb8, + 0xed => 0xb9, 0x25ca => 0xba, 0x0158 => 0xbb, 0x0122 => 0xbc, + 0xfb => 0xbd, 0xe2 => 0xbe, 0x0100 => 0xbf, 0x0159 => 0xc0, + 0xe7 => 0xc1, 0x017b => 0xc2, 0xde => 0xc3, 0x014c => 0xc4, + 0x0154 => 0xc5, 0x015a => 0xc6, 0x010f => 0xc7, 0x016a => 0xc8, + 0x016f => 0xc9, 0xb3 => 0xca, 0xd2 => 0xcb, 0xc0 => 0xcc, + 0x0102 => 0xcd, 0xd7 => 0xce, 0xfa => 0xcf, 0x0164 => 0xd0, + 0x2202 => 0xd1, 0xff => 0xd2, 0x0143 => 0xd3, 0xee => 0xd4, + 0xca => 0xd5, 0xe4 => 0xd6, 0xeb => 0xd7, 0x0107 => 0xd8, + 0x0144 => 0xd9, 0x016b => 0xda, 0x0147 => 0xdb, 0xcd => 0xdc, + 0xb1 => 0xdd, 0xa6 => 0xde, 0xae => 0xdf, 0x011e => 0xe0, + 0x0130 => 0xe1, 0x2211 => 0xe2, 0xc8 => 0xe3, 0x0155 => 0xe4, + 0x014d => 0xe5, 0x0179 => 0xe6, 0x017d => 0xe7, 0x2265 => 0xe8, + 0xd0 => 0xe9, 0xc7 => 0xea, 0x013c => 0xeb, 0x0165 => 0xec, + 0x0119 => 0xed, 0x0172 => 0xee, 0xc1 => 0xef, 0xc4 => 0xf0, + 0xe8 => 0xf1, 0x017a => 0xf2, 0x012f => 0xf3, 0xd3 => 0xf4, + 0xf3 => 0xf5, 0x0101 => 0xf6, 0x015b => 0xf7, 0xef => 0xf8, + 0xd4 => 0xf9, 0xd9 => 0xfa, 0x2206 => 0xfb, 0xfe => 0xfc, + 0xb2 => 0xfd, 0xd6 => 0xfe, 0xb5 => 0xff, 0xec => 0x0100, + 0x0151 => 0x0101, 0x0118 => 0x0102, 0x0111 => 0x0103, 0xbe => 0x0104, + 0x015e => 0x0105, 0x013e => 0x0106, 0x0136 => 0x0107, 0x0139 => 0x0108, + 0x2122 => 0x0109, 0x0117 => 0x010a, 0xcc => 0x010b, 0x012a => 0x010c, + 0x013d => 0x010d, 0xbd => 0x010e, 0x2264 => 0x010f, 0xf4 => 0x0110, + 0xf1 => 0x0111, 0x0170 => 0x0112, 0xc9 => 0x0113, 0x0113 => 0x0114, + 0x011f => 0x0115, 0xbc => 0x0116, 0x0160 => 0x0117, 0x0218 => 0x0118, + 0x0150 => 0x0119, 0xb0 => 0x011a, 0xf2 => 0x011b, 0x010c => 0x011c, + 0xf9 => 0x011d, 0x221a => 0x011e, 0x010e => 0x011f, 0x0157 => 0x0120, + 0xd1 => 0x0121, 0xf5 => 0x0122, 0x0156 => 0x0123, 0x013b => 0x0124, + 0xc3 => 0x0125, 0x0104 => 0x0126, 0xc5 => 0x0127, 0xd5 => 0x0128, + 0x017c => 0x0129, 0x011a => 0x012a, 0x012e => 0x012b, 0x0137 => 0x012c, + 0x2212 => 0x012d, 0xce => 0x012e, 0x0148 => 0x012f, 0x0163 => 0x0130, + 0xac => 0x0131, 0xf6 => 0x0132, 0xfc => 0x0133, 0x2260 => 0x0134, + 0x0123 => 0x0135, 0xf0 => 0x0136, 0x017e => 0x0137, 0x0146 => 0x0138, + 0xb9 => 0x0139, 0x012b => 0x013a, 0x20ac => 0x013b); + // require_once 'Zend/Pdf/Cmap.php'; + $this->_cmap = Zend_Pdf_Cmap::cmapWithTypeData( + Zend_Pdf_Cmap::TYPE_BYTE_ENCODING_STATIC, $cmapData); + + + /* Resource dictionary */ + + /* The resource dictionary for the standard fonts is sparse because PDF + * viewers already have all of the metrics data. We only need to provide + * the font name and encoding method. + */ + $this->_resource->BaseFont = new Zend_Pdf_Element_Name('Times-Roman'); + } +} diff --git a/library/Zend/Pdf/Resource/Font/Simple/Standard/ZapfDingbats.php b/library/Zend/Pdf/Resource/Font/Simple/Standard/ZapfDingbats.php new file mode 100644 index 0000000..6c904f1 --- /dev/null +++ b/library/Zend/Pdf/Resource/Font/Simple/Standard/ZapfDingbats.php @@ -0,0 +1,491 @@ + "\x20", 0x2701 => "\x21", 0x2702 => "\x22", 0x2703 => "\x23", + 0x2704 => "\x24", 0x260e => "\x25", 0x2706 => "\x26", 0x2707 => "\x27", + 0x2708 => "\x28", 0x2709 => "\x29", 0x261b => "\x2a", 0x261e => "\x2b", + 0x270c => "\x2c", 0x270d => "\x2d", 0x270e => "\x2e", 0x270f => "\x2f", + 0x2710 => "\x30", 0x2711 => "\x31", 0x2712 => "\x32", 0x2713 => "\x33", + 0x2714 => "\x34", 0x2715 => "\x35", 0x2716 => "\x36", 0x2717 => "\x37", + 0x2718 => "\x38", 0x2719 => "\x39", 0x271a => "\x3a", 0x271b => "\x3b", + 0x271c => "\x3c", 0x271d => "\x3d", 0x271e => "\x3e", 0x271f => "\x3f", + 0x2720 => "\x40", 0x2721 => "\x41", 0x2722 => "\x42", 0x2723 => "\x43", + 0x2724 => "\x44", 0x2725 => "\x45", 0x2726 => "\x46", 0x2727 => "\x47", + 0x2605 => "\x48", 0x2729 => "\x49", 0x272a => "\x4a", 0x272b => "\x4b", + 0x272c => "\x4c", 0x272d => "\x4d", 0x272e => "\x4e", 0x272f => "\x4f", + 0x2730 => "\x50", 0x2731 => "\x51", 0x2732 => "\x52", 0x2733 => "\x53", + 0x2734 => "\x54", 0x2735 => "\x55", 0x2736 => "\x56", 0x2737 => "\x57", + 0x2738 => "\x58", 0x2739 => "\x59", 0x273a => "\x5a", 0x273b => "\x5b", + 0x273c => "\x5c", 0x273d => "\x5d", 0x273e => "\x5e", 0x273f => "\x5f", + 0x2740 => "\x60", 0x2741 => "\x61", 0x2742 => "\x62", 0x2743 => "\x63", + 0x2744 => "\x64", 0x2745 => "\x65", 0x2746 => "\x66", 0x2747 => "\x67", + 0x2748 => "\x68", 0x2749 => "\x69", 0x274a => "\x6a", 0x274b => "\x6b", + 0x25cf => "\x6c", 0x274d => "\x6d", 0x25a0 => "\x6e", 0x274f => "\x6f", + 0x2750 => "\x70", 0x2751 => "\x71", 0x2752 => "\x72", 0x25b2 => "\x73", + 0x25bc => "\x74", 0x25c6 => "\x75", 0x2756 => "\x76", 0x25d7 => "\x77", + 0x2758 => "\x78", 0x2759 => "\x79", 0x275a => "\x7a", 0x275b => "\x7b", + 0x275c => "\x7c", 0x275d => "\x7d", 0x275e => "\x7e", 0x2768 => "\x80", + 0x2769 => "\x81", 0x276a => "\x82", 0x276b => "\x83", 0x276c => "\x84", + 0x276d => "\x85", 0x276e => "\x86", 0x276f => "\x87", 0x2770 => "\x88", + 0x2771 => "\x89", 0x2772 => "\x8a", 0x2773 => "\x8b", 0x2774 => "\x8c", + 0x2775 => "\x8d", 0x2761 => "\xa1", 0x2762 => "\xa2", 0x2763 => "\xa3", + 0x2764 => "\xa4", 0x2765 => "\xa5", 0x2766 => "\xa6", 0x2767 => "\xa7", + 0x2663 => "\xa8", 0x2666 => "\xa9", 0x2665 => "\xaa", 0x2660 => "\xab", + 0x2460 => "\xac", 0x2461 => "\xad", 0x2462 => "\xae", 0x2463 => "\xaf", + 0x2464 => "\xb0", 0x2465 => "\xb1", 0x2466 => "\xb2", 0x2467 => "\xb3", + 0x2468 => "\xb4", 0x2469 => "\xb5", 0x2776 => "\xb6", 0x2777 => "\xb7", + 0x2778 => "\xb8", 0x2779 => "\xb9", 0x277a => "\xba", 0x277b => "\xbb", + 0x277c => "\xbc", 0x277d => "\xbd", 0x277e => "\xbe", 0x277f => "\xbf", + 0x2780 => "\xc0", 0x2781 => "\xc1", 0x2782 => "\xc2", 0x2783 => "\xc3", + 0x2784 => "\xc4", 0x2785 => "\xc5", 0x2786 => "\xc6", 0x2787 => "\xc7", + 0x2788 => "\xc8", 0x2789 => "\xc9", 0x278a => "\xca", 0x278b => "\xcb", + 0x278c => "\xcc", 0x278d => "\xcd", 0x278e => "\xce", 0x278f => "\xcf", + 0x2790 => "\xd0", 0x2791 => "\xd1", 0x2792 => "\xd2", 0x2793 => "\xd3", + 0x2794 => "\xd4", 0x2192 => "\xd5", 0x2194 => "\xd6", 0x2195 => "\xd7", + 0x2798 => "\xd8", 0x2799 => "\xd9", 0x279a => "\xda", 0x279b => "\xdb", + 0x279c => "\xdc", 0x279d => "\xdd", 0x279e => "\xde", 0x279f => "\xdf", + 0x27a0 => "\xe0", 0x27a1 => "\xe1", 0x27a2 => "\xe2", 0x27a3 => "\xe3", + 0x27a4 => "\xe4", 0x27a5 => "\xe5", 0x27a6 => "\xe6", 0x27a7 => "\xe7", + 0x27a8 => "\xe8", 0x27a9 => "\xe9", 0x27aa => "\xea", 0x27ab => "\xeb", + 0x27ac => "\xec", 0x27ad => "\xed", 0x27ae => "\xee", 0x27af => "\xef", + 0x27b1 => "\xf1", 0x27b2 => "\xf2", 0x27b3 => "\xf3", 0x27b4 => "\xf4", + 0x27b5 => "\xf5", 0x27b6 => "\xf6", 0x27b7 => "\xf7", 0x27b8 => "\xf8", + 0x27b9 => "\xf9", 0x27ba => "\xfa", 0x27bb => "\xfb", 0x27bc => "\xfc", + 0x27bd => "\xfd", 0x27be => "\xfe"); + + /** + * Array for conversion from special font encoding to local encoding. + * See {@link decodeString()}. + * @var array + */ + protected $_fromFontEncoding = array( + 0x20 => "\x00\x20", 0x21 => "\x27\x01", 0x22 => "\x27\x02", + 0x23 => "\x27\x03", 0x24 => "\x27\x04", 0x25 => "\x26\x0e", + 0x26 => "\x27\x06", 0x27 => "\x27\x07", 0x28 => "\x27\x08", + 0x29 => "\x27\x09", 0x2a => "\x26\x1b", 0x2b => "\x26\x1e", + 0x2c => "\x27\x0c", 0x2d => "\x27\x0d", 0x2e => "\x27\x0e", + 0x2f => "\x27\x0f", 0x30 => "\x27\x10", 0x31 => "\x27\x11", + 0x32 => "\x27\x12", 0x33 => "\x27\x13", 0x34 => "\x27\x14", + 0x35 => "\x27\x15", 0x36 => "\x27\x16", 0x37 => "\x27\x17", + 0x38 => "\x27\x18", 0x39 => "\x27\x19", 0x3a => "\x27\x1a", + 0x3b => "\x27\x1b", 0x3c => "\x27\x1c", 0x3d => "\x27\x1d", + 0x3e => "\x27\x1e", 0x3f => "\x27\x1f", 0x40 => "\x27\x20", + 0x41 => "\x27\x21", 0x42 => "\x27\x22", 0x43 => "\x27\x23", + 0x44 => "\x27\x24", 0x45 => "\x27\x25", 0x46 => "\x27\x26", + 0x47 => "\x27\x27", 0x48 => "\x26\x05", 0x49 => "\x27\x29", + 0x4a => "\x27\x2a", 0x4b => "\x27\x2b", 0x4c => "\x27\x2c", + 0x4d => "\x27\x2d", 0x4e => "\x27\x2e", 0x4f => "\x27\x2f", + 0x50 => "\x27\x30", 0x51 => "\x27\x31", 0x52 => "\x27\x32", + 0x53 => "\x27\x33", 0x54 => "\x27\x34", 0x55 => "\x27\x35", + 0x56 => "\x27\x36", 0x57 => "\x27\x37", 0x58 => "\x27\x38", + 0x59 => "\x27\x39", 0x5a => "\x27\x3a", 0x5b => "\x27\x3b", + 0x5c => "\x27\x3c", 0x5d => "\x27\x3d", 0x5e => "\x27\x3e", + 0x5f => "\x27\x3f", 0x60 => "\x27\x40", 0x61 => "\x27\x41", + 0x62 => "\x27\x42", 0x63 => "\x27\x43", 0x64 => "\x27\x44", + 0x65 => "\x27\x45", 0x66 => "\x27\x46", 0x67 => "\x27\x47", + 0x68 => "\x27\x48", 0x69 => "\x27\x49", 0x6a => "\x27\x4a", + 0x6b => "\x27\x4b", 0x6c => "\x25\xcf", 0x6d => "\x27\x4d", + 0x6e => "\x25\xa0", 0x6f => "\x27\x4f", 0x70 => "\x27\x50", + 0x71 => "\x27\x51", 0x72 => "\x27\x52", 0x73 => "\x25\xb2", + 0x74 => "\x25\xbc", 0x75 => "\x25\xc6", 0x76 => "\x27\x56", + 0x77 => "\x25\xd7", 0x78 => "\x27\x58", 0x79 => "\x27\x59", + 0x7a => "\x27\x5a", 0x7b => "\x27\x5b", 0x7c => "\x27\x5c", + 0x7d => "\x27\x5d", 0x7e => "\x27\x5e", 0x80 => "\x27\x68", + 0x81 => "\x27\x69", 0x82 => "\x27\x6a", 0x83 => "\x27\x6b", + 0x84 => "\x27\x6c", 0x85 => "\x27\x6d", 0x86 => "\x27\x6e", + 0x87 => "\x27\x6f", 0x88 => "\x27\x70", 0x89 => "\x27\x71", + 0x8a => "\x27\x72", 0x8b => "\x27\x73", 0x8c => "\x27\x74", + 0x8d => "\x27\x75", 0xa1 => "\x27\x61", 0xa2 => "\x27\x62", + 0xa3 => "\x27\x63", 0xa4 => "\x27\x64", 0xa5 => "\x27\x65", + 0xa6 => "\x27\x66", 0xa7 => "\x27\x67", 0xa8 => "\x26\x63", + 0xa9 => "\x26\x66", 0xaa => "\x26\x65", 0xab => "\x26\x60", + 0xac => "\x24\x60", 0xad => "\x24\x61", 0xae => "\x24\x62", + 0xaf => "\x24\x63", 0xb0 => "\x24\x64", 0xb1 => "\x24\x65", + 0xb2 => "\x24\x66", 0xb3 => "\x24\x67", 0xb4 => "\x24\x68", + 0xb5 => "\x24\x69", 0xb6 => "\x27\x76", 0xb7 => "\x27\x77", + 0xb8 => "\x27\x78", 0xb9 => "\x27\x79", 0xba => "\x27\x7a", + 0xbb => "\x27\x7b", 0xbc => "\x27\x7c", 0xbd => "\x27\x7d", + 0xbe => "\x27\x7e", 0xbf => "\x27\x7f", 0xc0 => "\x27\x80", + 0xc1 => "\x27\x81", 0xc2 => "\x27\x82", 0xc3 => "\x27\x83", + 0xc4 => "\x27\x84", 0xc5 => "\x27\x85", 0xc6 => "\x27\x86", + 0xc7 => "\x27\x87", 0xc8 => "\x27\x88", 0xc9 => "\x27\x89", + 0xca => "\x27\x8a", 0xcb => "\x27\x8b", 0xcc => "\x27\x8c", + 0xcd => "\x27\x8d", 0xce => "\x27\x8e", 0xcf => "\x27\x8f", + 0xd0 => "\x27\x90", 0xd1 => "\x27\x91", 0xd2 => "\x27\x92", + 0xd3 => "\x27\x93", 0xd4 => "\x27\x94", 0xd5 => "\x21\x92", + 0xd6 => "\x21\x94", 0xd7 => "\x21\x95", 0xd8 => "\x27\x98", + 0xd9 => "\x27\x99", 0xda => "\x27\x9a", 0xdb => "\x27\x9b", + 0xdc => "\x27\x9c", 0xdd => "\x27\x9d", 0xde => "\x27\x9e", + 0xdf => "\x27\x9f", 0xe0 => "\x27\xa0", 0xe1 => "\x27\xa1", + 0xe2 => "\x27\xa2", 0xe3 => "\x27\xa3", 0xe4 => "\x27\xa4", + 0xe5 => "\x27\xa5", 0xe6 => "\x27\xa6", 0xe7 => "\x27\xa7", + 0xe8 => "\x27\xa8", 0xe9 => "\x27\xa9", 0xea => "\x27\xaa", + 0xeb => "\x27\xab", 0xec => "\x27\xac", 0xed => "\x27\xad", + 0xee => "\x27\xae", 0xef => "\x27\xaf", 0xf1 => "\x27\xb1", + 0xf2 => "\x27\xb2", 0xf3 => "\x27\xb3", 0xf4 => "\x27\xb4", + 0xf5 => "\x27\xb5", 0xf6 => "\x27\xb6", 0xf7 => "\x27\xb7", + 0xf8 => "\x27\xb8", 0xf9 => "\x27\xb9", 0xfa => "\x27\xba", + 0xfb => "\x27\xbb", 0xfc => "\x27\xbc", 0xfd => "\x27\xbd", + 0xfe => "\x27\xbe"); + + + + /**** Public Interface ****/ + + + /* Object Lifecycle */ + + /** + * Object constructor + */ + public function __construct() + { + parent::__construct(); + + + /* Object properties */ + + /* The font names are stored internally as Unicode UTF-16BE-encoded + * strings. Since this information is static, save unnecessary trips + * through iconv() and just use pre-encoded hexidecimal strings. + */ + $this->_fontNames[Zend_Pdf_Font::NAME_COPYRIGHT]['en'] = + "\x00\x43\x00\x6f\x00\x70\x00\x79\x00\x72\x00\x69\x00\x67\x00\x68\x00" + . "\x74\x00\x20\x00\x28\x00\x63\x00\x29\x00\x20\x00\x31\x00\x39\x00" + . "\x38\x00\x35\x00\x2c\x00\x20\x00\x31\x00\x39\x00\x38\x00\x37\x00" + . "\x2c\x00\x20\x00\x31\x00\x39\x00\x38\x00\x38\x00\x2c\x00\x20\x00" + . "\x31\x00\x39\x00\x38\x00\x39\x00\x2c\x00\x20\x00\x31\x00\x39\x00" + . "\x39\x00\x37\x00\x20\x00\x41\x00\x64\x00\x6f\x00\x62\x00\x65\x00" + . "\x20\x00\x53\x00\x79\x00\x73\x00\x74\x00\x65\x00\x6d\x00\x73\x00" + . "\x20\x00\x49\x00\x6e\x00\x63\x00\x6f\x00\x72\x00\x70\x00\x6f\x00" + . "\x72\x00\x61\x00\x74\x00\x65\x00\x64\x00\x2e\x00\x20\x00\x41\x00" + . "\x6c\x00\x6c\x00\x20\x00\x52\x00\x69\x00\x67\x00\x68\x00\x74\x00" + . "\x73\x00\x20\x00\x52\x00\x65\x00\x73\x00\x65\x00\x72\x00\x76\x00" + . "\x65\x00\x64\x00\x2e\x00\x49\x00\x54\x00\x43\x00\x20\x00\x5a\x00" + . "\x61\x00\x70\x00\x66\x00\x20\x00\x44\x00\x69\x00\x6e\x00\x67\x00" + . "\x62\x00\x61\x00\x74\x00\x73\x00\x20\x00\x69\x00\x73\x00\x20\x00" + . "\x61\x00\x20\x00\x72\x00\x65\x00\x67\x00\x69\x00\x73\x00\x74\x00" + . "\x65\x00\x72\x00\x65\x00\x64\x00\x20\x00\x74\x00\x72\x00\x61\x00" + . "\x64\x00\x65\x00\x6d\x00\x61\x00\x72\x00\x6b\x00\x20\x00\x6f\x00" + . "\x66\x00\x20\x00\x49\x00\x6e\x00\x74\x00\x65\x00\x72\x00\x6e\x00" + . "\x61\x00\x74\x00\x69\x00\x6f\x00\x6e\x00\x61\x00\x6c\x00\x20\x00" + . "\x54\x00\x79\x00\x70\x00\x65\x00\x66\x00\x61\x00\x63\x00\x65\x00" + . "\x20\x00\x43\x00\x6f\x00\x72\x00\x70\x00\x6f\x00\x72\x00\x61\x00" + . "\x74\x00\x69\x00\x6f\x00\x6e\x00\x2e"; + $this->_fontNames[Zend_Pdf_Font::NAME_FAMILY]['en'] = + "\x00\x5a\x00\x61\x00\x70\x00\x66\x00\x44\x00\x69\x00\x6e\x00\x67\x00" + . "\x62\x00\x61\x00\x74\x00\x73"; + $this->_fontNames[Zend_Pdf_Font::NAME_STYLE]['en'] = + "\x00\x4d\x00\x65\x00\x64\x00\x69\x00\x75\x00\x6d"; + $this->_fontNames[Zend_Pdf_Font::NAME_ID]['en'] = + "\x00\x34\x00\x33\x00\x30\x00\x38\x00\x32"; + $this->_fontNames[Zend_Pdf_Font::NAME_FULL]['en'] = + "\x00\x5a\x00\x61\x00\x70\x00\x66\x00\x44\x00\x69\x00\x6e\x00\x67\x00" + . "\x62\x00\x61\x00\x74\x00\x73\x00\x20\x00\x4d\x00\x65\x00\x64\x00" + . "\x69\x00\x75\x00\x6d"; + $this->_fontNames[Zend_Pdf_Font::NAME_VERSION]['en'] = + "\x00\x30\x00\x30\x00\x32\x00\x2e\x00\x30\x00\x30\x00\x30"; + $this->_fontNames[Zend_Pdf_Font::NAME_POSTSCRIPT]['en'] = + "\x00\x5a\x00\x61\x00\x70\x00\x66\x00\x44\x00\x69\x00\x6e\x00\x67\x00" + . "\x62\x00\x61\x00\x74\x00\x73"; + + $this->_isBold = false; + $this->_isItalic = false; + $this->_isMonospaced = false; + + $this->_underlinePosition = -100; + $this->_underlineThickness = 50; + $this->_strikePosition = 225; + $this->_strikeThickness = 50; + + $this->_unitsPerEm = 1000; + + $this->_ascent = 1000; + $this->_descent = 0; + $this->_lineGap = 200; + + /* The glyph numbers assigned here are synthetic; they do not match the + * actual glyph numbers used by the font. This is not a big deal though + * since this data never makes it to the PDF file. It is only used + * internally for layout calculations. + */ + $this->_glyphWidths = array( + 0x00 => 0x01f4, 0x01 => 0x0116, 0x02 => 0x03ce, 0x03 => 0x03c1, + 0x04 => 0x03ce, 0x05 => 0x03d4, 0x06 => 0x02cf, 0x07 => 0x0315, + 0x08 => 0x0316, 0x09 => 0x0317, 0x0a => 0x02b2, 0x0b => 0x03c0, + 0x0c => 0x03ab, 0x0d => 0x0225, 0x0e => 0x0357, 0x0f => 0x038f, + 0x10 => 0x03a5, 0x11 => 0x038f, 0x12 => 0x03b1, 0x13 => 0x03ce, + 0x14 => 0x02f3, 0x15 => 0x034e, 0x16 => 0x02fa, 0x17 => 0x02f9, + 0x18 => 0x023b, 0x19 => 0x02a5, 0x1a => 0x02fb, 0x1b => 0x02f8, + 0x1c => 0x02f7, 0x1d => 0x02f2, 0x1e => 0x01ee, 0x1f => 0x0228, + 0x20 => 0x0219, 0x21 => 0x0241, 0x22 => 0x02b4, 0x23 => 0x0312, + 0x24 => 0x0314, 0x25 => 0x0314, 0x26 => 0x0316, 0x27 => 0x0319, + 0x28 => 0x031a, 0x29 => 0x0330, 0x2a => 0x0337, 0x2b => 0x0315, + 0x2c => 0x0349, 0x2d => 0x0337, 0x2e => 0x0341, 0x2f => 0x0330, + 0x30 => 0x033f, 0x31 => 0x039b, 0x32 => 0x02e8, 0x33 => 0x02d3, + 0x34 => 0x02ed, 0x35 => 0x0316, 0x36 => 0x0318, 0x37 => 0x02b7, + 0x38 => 0x0308, 0x39 => 0x0300, 0x3a => 0x0318, 0x3b => 0x02f7, + 0x3c => 0x02c3, 0x3d => 0x02c4, 0x3e => 0x02aa, 0x3f => 0x02bd, + 0x40 => 0x033a, 0x41 => 0x032f, 0x42 => 0x0315, 0x43 => 0x0315, + 0x44 => 0x02c3, 0x45 => 0x02af, 0x46 => 0x02b8, 0x47 => 0x02b1, + 0x48 => 0x0312, 0x49 => 0x0313, 0x4a => 0x02c9, 0x4b => 0x0317, + 0x4c => 0x0311, 0x4d => 0x0317, 0x4e => 0x0369, 0x4f => 0x02f9, + 0x50 => 0x02fa, 0x51 => 0x02fa, 0x52 => 0x02f7, 0x53 => 0x02f7, + 0x54 => 0x037c, 0x55 => 0x037c, 0x56 => 0x0314, 0x57 => 0x0310, + 0x58 => 0x01b6, 0x59 => 0x8a, 0x5a => 0x0115, 0x5b => 0x019f, + 0x5c => 0x0188, 0x5d => 0x0188, 0x5e => 0x029c, 0x5f => 0x029c, + 0x60 => 0x0186, 0x61 => 0x0186, 0x62 => 0x013d, 0x63 => 0x013d, + 0x64 => 0x0114, 0x65 => 0x0114, 0x66 => 0x01fd, 0x67 => 0x01fd, + 0x68 => 0x019a, 0x69 => 0x019a, 0x6a => 0xea, 0x6b => 0xea, + 0x6c => 0x014e, 0x6d => 0x014e, 0x6e => 0x02dc, 0x6f => 0x0220, + 0x70 => 0x0220, 0x71 => 0x038e, 0x72 => 0x029b, 0x73 => 0x02f8, + 0x74 => 0x02f8, 0x75 => 0x0308, 0x76 => 0x0253, 0x77 => 0x02b6, + 0x78 => 0x0272, 0x79 => 0x0314, 0x7a => 0x0314, 0x7b => 0x0314, + 0x7c => 0x0314, 0x7d => 0x0314, 0x7e => 0x0314, 0x7f => 0x0314, + 0x80 => 0x0314, 0x81 => 0x0314, 0x82 => 0x0314, 0x83 => 0x0314, + 0x84 => 0x0314, 0x85 => 0x0314, 0x86 => 0x0314, 0x87 => 0x0314, + 0x88 => 0x0314, 0x89 => 0x0314, 0x8a => 0x0314, 0x8b => 0x0314, + 0x8c => 0x0314, 0x8d => 0x0314, 0x8e => 0x0314, 0x8f => 0x0314, + 0x90 => 0x0314, 0x91 => 0x0314, 0x92 => 0x0314, 0x93 => 0x0314, + 0x94 => 0x0314, 0x95 => 0x0314, 0x96 => 0x0314, 0x97 => 0x0314, + 0x98 => 0x0314, 0x99 => 0x0314, 0x9a => 0x0314, 0x9b => 0x0314, + 0x9c => 0x0314, 0x9d => 0x0314, 0x9e => 0x0314, 0x9f => 0x0314, + 0xa0 => 0x0314, 0xa1 => 0x037e, 0xa2 => 0x0346, 0xa3 => 0x03f8, + 0xa4 => 0x01ca, 0xa5 => 0x02ec, 0xa6 => 0x039c, 0xa7 => 0x02ec, + 0xa8 => 0x0396, 0xa9 => 0x039f, 0xaa => 0x03a0, 0xab => 0x03a0, + 0xac => 0x0342, 0xad => 0x0369, 0xae => 0x033c, 0xaf => 0x039c, + 0xb0 => 0x039c, 0xb1 => 0x0395, 0xb2 => 0x03a2, 0xb3 => 0x03a3, + 0xb4 => 0x01cf, 0xb5 => 0x0373, 0xb6 => 0x0344, 0xb7 => 0x0344, + 0xb8 => 0x0363, 0xb9 => 0x0363, 0xba => 0x02b8, 0xbb => 0x02b8, + 0xbc => 0x036a, 0xbd => 0x036a, 0xbe => 0x02f8, 0xbf => 0x03b2, + 0xc0 => 0x0303, 0xc1 => 0x0361, 0xc2 => 0x0303, 0xc3 => 0x0378, + 0xc4 => 0x03c7, 0xc5 => 0x0378, 0xc6 => 0x033f, 0xc7 => 0x0369, + 0xc8 => 0x039f, 0xc9 => 0x03ca, 0xca => 0x0396); + + /* The cmap table is similarly synthesized. + */ + $cmapData = array( + 0x20 => 0x01, 0x2701 => 0x02, 0x2702 => 0x03, 0x2703 => 0x04, + 0x2704 => 0x05, 0x260e => 0x06, 0x2706 => 0x07, 0x2707 => 0x08, + 0x2708 => 0x09, 0x2709 => 0x0a, 0x261b => 0x0b, 0x261e => 0x0c, + 0x270c => 0x0d, 0x270d => 0x0e, 0x270e => 0x0f, 0x270f => 0x10, + 0x2710 => 0x11, 0x2711 => 0x12, 0x2712 => 0x13, 0x2713 => 0x14, + 0x2714 => 0x15, 0x2715 => 0x16, 0x2716 => 0x17, 0x2717 => 0x18, + 0x2718 => 0x19, 0x2719 => 0x1a, 0x271a => 0x1b, 0x271b => 0x1c, + 0x271c => 0x1d, 0x271d => 0x1e, 0x271e => 0x1f, 0x271f => 0x20, + 0x2720 => 0x21, 0x2721 => 0x22, 0x2722 => 0x23, 0x2723 => 0x24, + 0x2724 => 0x25, 0x2725 => 0x26, 0x2726 => 0x27, 0x2727 => 0x28, + 0x2605 => 0x29, 0x2729 => 0x2a, 0x272a => 0x2b, 0x272b => 0x2c, + 0x272c => 0x2d, 0x272d => 0x2e, 0x272e => 0x2f, 0x272f => 0x30, + 0x2730 => 0x31, 0x2731 => 0x32, 0x2732 => 0x33, 0x2733 => 0x34, + 0x2734 => 0x35, 0x2735 => 0x36, 0x2736 => 0x37, 0x2737 => 0x38, + 0x2738 => 0x39, 0x2739 => 0x3a, 0x273a => 0x3b, 0x273b => 0x3c, + 0x273c => 0x3d, 0x273d => 0x3e, 0x273e => 0x3f, 0x273f => 0x40, + 0x2740 => 0x41, 0x2741 => 0x42, 0x2742 => 0x43, 0x2743 => 0x44, + 0x2744 => 0x45, 0x2745 => 0x46, 0x2746 => 0x47, 0x2747 => 0x48, + 0x2748 => 0x49, 0x2749 => 0x4a, 0x274a => 0x4b, 0x274b => 0x4c, + 0x25cf => 0x4d, 0x274d => 0x4e, 0x25a0 => 0x4f, 0x274f => 0x50, + 0x2750 => 0x51, 0x2751 => 0x52, 0x2752 => 0x53, 0x25b2 => 0x54, + 0x25bc => 0x55, 0x25c6 => 0x56, 0x2756 => 0x57, 0x25d7 => 0x58, + 0x2758 => 0x59, 0x2759 => 0x5a, 0x275a => 0x5b, 0x275b => 0x5c, + 0x275c => 0x5d, 0x275d => 0x5e, 0x275e => 0x5f, 0x2768 => 0x60, + 0x2769 => 0x61, 0x276a => 0x62, 0x276b => 0x63, 0x276c => 0x64, + 0x276d => 0x65, 0x276e => 0x66, 0x276f => 0x67, 0x2770 => 0x68, + 0x2771 => 0x69, 0x2772 => 0x6a, 0x2773 => 0x6b, 0x2774 => 0x6c, + 0x2775 => 0x6d, 0x2761 => 0x6e, 0x2762 => 0x6f, 0x2763 => 0x70, + 0x2764 => 0x71, 0x2765 => 0x72, 0x2766 => 0x73, 0x2767 => 0x74, + 0x2663 => 0x75, 0x2666 => 0x76, 0x2665 => 0x77, 0x2660 => 0x78, + 0x2460 => 0x79, 0x2461 => 0x7a, 0x2462 => 0x7b, 0x2463 => 0x7c, + 0x2464 => 0x7d, 0x2465 => 0x7e, 0x2466 => 0x7f, 0x2467 => 0x80, + 0x2468 => 0x81, 0x2469 => 0x82, 0x2776 => 0x83, 0x2777 => 0x84, + 0x2778 => 0x85, 0x2779 => 0x86, 0x277a => 0x87, 0x277b => 0x88, + 0x277c => 0x89, 0x277d => 0x8a, 0x277e => 0x8b, 0x277f => 0x8c, + 0x2780 => 0x8d, 0x2781 => 0x8e, 0x2782 => 0x8f, 0x2783 => 0x90, + 0x2784 => 0x91, 0x2785 => 0x92, 0x2786 => 0x93, 0x2787 => 0x94, + 0x2788 => 0x95, 0x2789 => 0x96, 0x278a => 0x97, 0x278b => 0x98, + 0x278c => 0x99, 0x278d => 0x9a, 0x278e => 0x9b, 0x278f => 0x9c, + 0x2790 => 0x9d, 0x2791 => 0x9e, 0x2792 => 0x9f, 0x2793 => 0xa0, + 0x2794 => 0xa1, 0x2192 => 0xa2, 0x2194 => 0xa3, 0x2195 => 0xa4, + 0x2798 => 0xa5, 0x2799 => 0xa6, 0x279a => 0xa7, 0x279b => 0xa8, + 0x279c => 0xa9, 0x279d => 0xaa, 0x279e => 0xab, 0x279f => 0xac, + 0x27a0 => 0xad, 0x27a1 => 0xae, 0x27a2 => 0xaf, 0x27a3 => 0xb0, + 0x27a4 => 0xb1, 0x27a5 => 0xb2, 0x27a6 => 0xb3, 0x27a7 => 0xb4, + 0x27a8 => 0xb5, 0x27a9 => 0xb6, 0x27aa => 0xb7, 0x27ab => 0xb8, + 0x27ac => 0xb9, 0x27ad => 0xba, 0x27ae => 0xbb, 0x27af => 0xbc, + 0x27b1 => 0xbd, 0x27b2 => 0xbe, 0x27b3 => 0xbf, 0x27b4 => 0xc0, + 0x27b5 => 0xc1, 0x27b6 => 0xc2, 0x27b7 => 0xc3, 0x27b8 => 0xc4, + 0x27b9 => 0xc5, 0x27ba => 0xc6, 0x27bb => 0xc7, 0x27bc => 0xc8, + 0x27bd => 0xc9, 0x27be => 0xca); + // require_once 'Zend/Pdf/Cmap.php'; + $this->_cmap = Zend_Pdf_Cmap::cmapWithTypeData( + Zend_Pdf_Cmap::TYPE_BYTE_ENCODING_STATIC, $cmapData); + + + /* Resource dictionary */ + + /* The resource dictionary for the standard fonts is sparse because PDF + * viewers already have all of the metrics data. We only need to provide + * the font name and encoding method. + */ + $this->_resource->BaseFont = new Zend_Pdf_Element_Name('ZapfDingbats'); + + /* This font has a built-in custom character encoding method. Don't + * override with WinAnsi like the other built-in fonts or else it will + * not work as expected. + */ + $this->_resource->Encoding = null; + } + + + /* Information and Conversion Methods */ + + /** + * Convert string encoding from local encoding to font encoding. Overridden + * to defeat the conversion behavior for this ornamental font. + * + * @param string $string + * @param string $charEncoding Character encoding of source text. + * @return string + */ + public function encodeString($string, $charEncoding) + { + /* This isn't the optimal time to perform this conversion, but it must + * live here until the remainder of the layout code is completed. This, + * and the $charEncoding parameter, will go away soon... + */ + if ($charEncoding != 'UTF-16BE') { + $string = iconv($charEncoding, 'UTF-16BE', $string); + } + /** + * @todo Properly handle characters encoded as surrogate pairs. + */ + $encodedString = ''; + for ($i = 0; $i < strlen($string); $i++) { + $characterCode = (ord($string[$i++]) << 8) | ord($string[$i]); + if (isset($this->_toFontEncoding[$characterCode])) { + $encodedString .= $this->_toFontEncoding[$characterCode]; + } else { + /* For now, mimic the behavior in Zend_Pdf_Font::encodeString() + * where unknown characters are removed completely. This is not + * perfect, but we should be consistent. In a future revision, + * we will use the well-known substitution character 0x1a + * (Control-Z). + */ + } + } + return $encodedString; + } + + /** + * Convert string encoding from font encoding to local encoding. Overridden + * to defeat the conversion behavior for this ornamental font. + * + * @param string $string + * @param string $charEncoding Character encoding of resulting text. + * @return string + */ + public function decodeString($string, $charEncoding) + { + $decodedString = ''; + for ($i = 0; $i < strlen($string); $i++) { + $characterCode = ord($string[$i]); + if (isset($this->_fromFontEncoding[$characterCode])) { + $decodedString .= $this->_fromFontEncoding[$characterCode]; + } else { + /* For now, mimic the behavior in Zend_Pdf_Font::encodeString() + * where unknown characters are removed completely. This is not + * perfect, but we should be consistent. In a future revision, + * we will use the Unicode substitution character (U+FFFD). + */ + } + } + if ($charEncoding != 'UTF-16BE') { + $decodedString = iconv('UTF-16BE', $charEncoding, $decodedString); + } + return $decodedString; + } + + /** + * Converts a Latin-encoded string that fakes the font's internal encoding + * to the proper Unicode characters, in UTF-16BE encoding. + * + * Used to maintain backwards compatibility with the 20 year-old legacy + * method of using this font, which is still employed by recent versions of + * some popular word processors. + * + * Note that using this method adds overhead due to the additional + * character conversion. Don't use this for new code; it is more efficient + * to use the appropriate Unicode characters directly. + * + * @param string $string + * @param string $charEncoding (optional) Character encoding of source + * string. Defaults to current locale. + * @return string + */ + public function toUnicode($string, $charEncoding = '') + { + /* When using these faked strings, the closest match to the font's + * internal encoding is ISO-8859-1. + */ + if ($charEncoding != 'ISO-8859-1') { + $string = iconv($charEncoding, 'ISO-8859-1', $string); + } + return $this->decodeString($string, 'UTF-16BE'); + } +} diff --git a/library/Zend/Pdf/Resource/Font/Type0.php b/library/Zend/Pdf/Resource/Font/Type0.php new file mode 100644 index 0000000..6bf44aa --- /dev/null +++ b/library/Zend/Pdf/Resource/Font/Type0.php @@ -0,0 +1,257 @@ +> def' . "\n" + . '/CMapName /Adobe-Identity-UCS def ' . "\n" + . '/CMapType 2 def ' . "\n" + . '1 begincodespacerange' . "\n" + . '<0000> ' . "\n" + . 'endcodespacerange ' . "\n" + . '1 beginbfrange ' . "\n" + . '<0000> <0000> ' . "\n" + . 'endbfrange ' . "\n" + . 'endcmap ' . "\n" + . 'CMapName currentdict /CMap defineresource pop ' . "\n" + . 'end ' + . 'end '; + } + + /** + * Object constructor + * + */ + public function __construct(Zend_Pdf_Resource_Font_CidFont $descendantFont) + { + parent::__construct(); + + $this->_objectFactory->attach($descendantFont->getFactory()); + + $this->_fontType = Zend_Pdf_Font::TYPE_TYPE_0; + $this->_descendantFont = $descendantFont; + + + $this->_fontNames = $descendantFont->getFontNames(); + + $this->_isBold = $descendantFont->isBold(); + $this->_isItalic = $descendantFont->isItalic(); + $this->_isMonospaced = $descendantFont->isMonospace(); + + $this->_underlinePosition = $descendantFont->getUnderlinePosition(); + $this->_underlineThickness = $descendantFont->getUnderlineThickness(); + $this->_strikePosition = $descendantFont->getStrikePosition(); + $this->_strikeThickness = $descendantFont->getStrikeThickness(); + + $this->_unitsPerEm = $descendantFont->getUnitsPerEm(); + + $this->_ascent = $descendantFont->getAscent(); + $this->_descent = $descendantFont->getDescent(); + $this->_lineGap = $descendantFont->getLineGap(); + + + $this->_resource->Subtype = new Zend_Pdf_Element_Name('Type0'); + $this->_resource->BaseFont = new Zend_Pdf_Element_Name($descendantFont->getResource()->BaseFont->value); + $this->_resource->DescendantFonts = new Zend_Pdf_Element_Array(array( $descendantFont->getResource() )); + $this->_resource->Encoding = new Zend_Pdf_Element_Name('Identity-H'); + + $toUnicode = $this->_objectFactory->newStreamObject(self::getToUnicodeCMapData()); + $this->_resource->ToUnicode = $toUnicode; + + } + + /** + * Returns an array of glyph numbers corresponding to the Unicode characters. + * + * Zend_Pdf uses 'Identity-H' encoding for Type 0 fonts. + * So we don't need to perform any conversion + * + * See also {@link glyphNumberForCharacter()}. + * + * @param array $characterCodes Array of Unicode character codes (code points). + * @return array Array of glyph numbers. + */ + public function glyphNumbersForCharacters($characterCodes) + { + return $characterCodes; + } + + /** + * Returns the glyph number corresponding to the Unicode character. + * + * Zend_Pdf uses 'Identity-H' encoding for Type 0 fonts. + * So we don't need to perform any conversion + * + * @param integer $characterCode Unicode character code (code point). + * @return integer Glyph number. + */ + public function glyphNumberForCharacter($characterCode) + { + return $characterCode; + } + + /** + * Returns a number between 0 and 1 inclusive that indicates the percentage + * of characters in the string which are covered by glyphs in this font. + * + * Since no one font will contain glyphs for the entire Unicode character + * range, this method can be used to help locate a suitable font when the + * actual contents of the string are not known. + * + * Note that some fonts lie about the characters they support. Additionally, + * fonts don't usually contain glyphs for control characters such as tabs + * and line breaks, so it is rare that you will get back a full 1.0 score. + * The resulting value should be considered informational only. + * + * @param string $string + * @param string $charEncoding (optional) Character encoding of source text. + * If omitted, uses 'current locale'. + * @return float + */ + public function getCoveredPercentage($string, $charEncoding = '') + { + return $this->_descendantFont->getCoveredPercentage($string, $charEncoding); + } + + /** + * Returns the widths of the glyphs. + * + * The widths are expressed in the font's glyph space. You are responsible + * for converting to user space as necessary. See {@link unitsPerEm()}. + * + * Throws an exception if the glyph number is out of range. + * + * See also {@link widthForGlyph()}. + * + * @param array &$glyphNumbers Array of glyph numbers. + * @return array Array of glyph widths (integers). + * @throws Zend_Pdf_Exception + */ + public function widthsForGlyphs($glyphNumbers) + { + return $this->_descendantFont->widthsForChars($glyphNumbers); + } + + /** + * Returns the width of the glyph. + * + * Like {@link widthsForGlyphs()} but used for one glyph at a time. + * + * @param integer $glyphNumber + * @return integer + * @throws Zend_Pdf_Exception + */ + public function widthForGlyph($glyphNumber) + { + return $this->_descendantFont->widthForChar($glyphNumber); + } + + /** + * Convert string to the font encoding. + * + * The method is used to prepare string for text drawing operators + * + * @param string $string + * @param string $charEncoding Character encoding of source text. + * @return string + */ + public function encodeString($string, $charEncoding) + { + return iconv($charEncoding, 'UTF-16BE', $string); + } + + /** + * Convert string from the font encoding. + * + * The method is used to convert strings retrieved from existing content streams + * + * @param string $string + * @param string $charEncoding Character encoding of resulting text. + * @return string + */ + public function decodeString($string, $charEncoding) + { + return iconv('UTF-16BE', $charEncoding, $string); + } +} diff --git a/library/Zend/Pdf/Resource/GraphicsState.php b/library/Zend/Pdf/Resource/GraphicsState.php new file mode 100644 index 0000000..06e2a08 --- /dev/null +++ b/library/Zend/Pdf/Resource/GraphicsState.php @@ -0,0 +1,109 @@ +Type = new Zend_Pdf_Element_Name('ExtGState'); + + $extGStateObject = $factory->newObject($gsDictionary); + } + + if ($extGStateObject->getType() != Zend_Pdf_Element::TYPE_DICTIONARY) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Graphics state PDF object must be a dictionary'); + } + + parent::__construct($gsDictionary); + } + + /** + * Set the transparancy + * + * $alpha == 0 - transparent + * $alpha == 1 - opaque + * + * Transparency modes, supported by PDF: + * Normal (default), Multiply, Screen, Overlay, Darken, Lighten, ColorDodge, ColorBurn, HardLight, + * SoftLight, Difference, Exclusion + * + * @param float $alpha + * @param string $mode + * @throws Zend_Pdf_Exception + * @return Zend_Pdf_Canvas_Interface + */ + public function setAlpha($alpha, $mode = 'Normal') + { + if (!in_array($mode, array('Normal', 'Multiply', 'Screen', 'Overlay', 'Darken', 'Lighten', 'ColorDodge', + 'ColorBurn', 'HardLight', 'SoftLight', 'Difference', 'Exclusion'))) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Unsupported transparency mode.'); + } + if (!is_numeric($alpha) || $alpha < 0 || $alpha > 1) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Alpha value must be numeric between 0 (transparent) and 1 (opaque).'); + } + + $this->_resource->BM = new Zend_Pdf_Element_Name($mode); + $this->_resource->CA = new Zend_Pdf_Element_Numeric($alpha); + $this->_resource->ca = new Zend_Pdf_Element_Numeric($alpha); + } + + + /** @todo add other Graphics State features support */ +} + diff --git a/library/Zend/Pdf/Resource/Image.php b/library/Zend/Pdf/Resource/Image.php new file mode 100644 index 0000000..60b6402 --- /dev/null +++ b/library/Zend/Pdf/Resource/Image.php @@ -0,0 +1,73 @@ +_resource->dictionary->Type = new Zend_Pdf_Element_Name('XObject'); + $this->_resource->dictionary->Subtype = new Zend_Pdf_Element_Name('Image'); + } + /** + * get the height in pixels of the image + * + * @return integer + */ + abstract public function getPixelHeight(); + + /** + * get the width in pixels of the image + * + * @return integer + */ + abstract public function getPixelWidth(); + + /** + * gets an associative array of information about an image + * + * @return array + */ + abstract public function getProperties(); +} + diff --git a/library/Zend/Pdf/Resource/Image/Jpeg.php b/library/Zend/Pdf/Resource/Image/Jpeg.php new file mode 100644 index 0000000..cde69f9 --- /dev/null +++ b/library/Zend/Pdf/Resource/Image/Jpeg.php @@ -0,0 +1,152 @@ +_resource->dictionary; + $imageDictionary->Width = new Zend_Pdf_Element_Numeric($imageInfo[0]); + $imageDictionary->Height = new Zend_Pdf_Element_Numeric($imageInfo[1]); + $imageDictionary->ColorSpace = new Zend_Pdf_Element_Name($colorSpace); + $imageDictionary->BitsPerComponent = new Zend_Pdf_Element_Numeric($imageInfo['bits']); + if ($imageInfo[2] == IMAGETYPE_JPEG) { + $imageDictionary->Filter = new Zend_Pdf_Element_Name('DCTDecode'); + } else if ($imageInfo[2] == IMAGETYPE_JPEG2000){ + $imageDictionary->Filter = new Zend_Pdf_Element_Name('JPXDecode'); + } + + if (($imageFile = @fopen($imageFileName, 'rb')) === false ) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception( "Can not open '$imageFileName' file for reading." ); + } + $byteCount = filesize($imageFileName); + $this->_resource->value = ''; + + while ($byteCount > 0 && !feof($imageFile)) { + $nextBlock = fread($imageFile, $byteCount); + if ($nextBlock === false) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception( "Error occured while '$imageFileName' file reading." ); + } + + $this->_resource->value .= $nextBlock; + $byteCount -= strlen($nextBlock); + } + if ($byteCount != 0) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception( "Error occured while '$imageFileName' file reading." ); + } + fclose($imageFile); + $this->_resource->skipFilters(); + + $this->_width = $imageInfo[0]; + $this->_height = $imageInfo[1]; + $this->_imageProperties = array(); + $this->_imageProperties['bitDepth'] = $imageInfo['bits']; + $this->_imageProperties['jpegImageType'] = $imageInfo[2]; + $this->_imageProperties['jpegColorType'] = $imageInfo['channels']; + } + + /** + * Image width + */ + public function getPixelWidth() { + return $this->_width; + } + + /** + * Image height + */ + public function getPixelHeight() { + return $this->_height; + } + + /** + * Image properties + */ + public function getProperties() { + return $this->_imageProperties; + } +} + diff --git a/library/Zend/Pdf/Resource/Image/Png.php b/library/Zend/Pdf/Resource/Image/Png.php new file mode 100644 index 0000000..ce4d667 --- /dev/null +++ b/library/Zend/Pdf/Resource/Image/Png.php @@ -0,0 +1,380 @@ +_width = $width; + $this->_height = $height; + $this->_imageProperties = array(); + $this->_imageProperties['bitDepth'] = $bits; + $this->_imageProperties['pngColorType'] = $color; + $this->_imageProperties['pngFilterType'] = $prefilter; + $this->_imageProperties['pngCompressionType'] = $compression; + $this->_imageProperties['pngInterlacingType'] = $interlacing; + + fseek($imageFile, 4, SEEK_CUR); //4 Byte Ending Sequence + $imageData = ''; + + /* + * The following loop processes PNG chunks. 4 Byte Longs are packed first give the chunk length + * followed by the chunk signature, a four byte code. IDAT and IEND are manditory in any PNG. + */ + while (!feof($imageFile)) { + $chunkLengthBytes = fread($imageFile, 4); + if ($chunkLengthBytes === false) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Error ocuured while image file reading.'); + } + + $chunkLengthtmp = unpack('Ni', $chunkLengthBytes); + $chunkLength = $chunkLengthtmp['i']; + $chunkType = fread($imageFile, 4); + switch($chunkType) { + case 'IDAT': //Image Data + /* + * Reads the actual image data from the PNG file. Since we know at this point that the compression + * strategy is the default strategy, we also know that this data is Zip compressed. We will either copy + * the data directly to the PDF and provide the correct FlateDecode predictor, or decompress the data + * decode the filters and output the data as a raw pixel map. + */ + $imageData .= fread($imageFile, $chunkLength); + fseek($imageFile, 4, SEEK_CUR); + break; + + case 'PLTE': //Palette + $paletteData = fread($imageFile, $chunkLength); + fseek($imageFile, 4, SEEK_CUR); + break; + + case 'tRNS': //Basic (non-alpha channel) transparency. + $trnsData = fread($imageFile, $chunkLength); + switch ($color) { + case Zend_Pdf_Resource_Image_Png::PNG_CHANNEL_GRAY: + $baseColor = ord(substr($trnsData, 1, 1)); + $transparencyData = array(new Zend_Pdf_Element_Numeric($baseColor), + new Zend_Pdf_Element_Numeric($baseColor)); + break; + + case Zend_Pdf_Resource_Image_Png::PNG_CHANNEL_RGB: + $red = ord(substr($trnsData,1,1)); + $green = ord(substr($trnsData,3,1)); + $blue = ord(substr($trnsData,5,1)); + $transparencyData = array(new Zend_Pdf_Element_Numeric($red), + new Zend_Pdf_Element_Numeric($red), + new Zend_Pdf_Element_Numeric($green), + new Zend_Pdf_Element_Numeric($green), + new Zend_Pdf_Element_Numeric($blue), + new Zend_Pdf_Element_Numeric($blue)); + break; + + case Zend_Pdf_Resource_Image_Png::PNG_CHANNEL_INDEXED: + //Find the first transparent color in the index, we will mask that. (This is a bit of a hack. This should be a SMask and mask all entries values). + if(($trnsIdx = strpos($trnsData, "\0")) !== false) { + $transparencyData = array(new Zend_Pdf_Element_Numeric($trnsIdx), + new Zend_Pdf_Element_Numeric($trnsIdx)); + } + break; + + case Zend_Pdf_Resource_Image_Png::PNG_CHANNEL_GRAY_ALPHA: + // Fall through to the next case + + case Zend_Pdf_Resource_Image_Png::PNG_CHANNEL_RGB_ALPHA: + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception( "tRNS chunk illegal for Alpha Channel Images" ); + break; + } + fseek($imageFile, 4, SEEK_CUR); //4 Byte Ending Sequence + break; + + case 'IEND'; + break 2; //End the loop too + + default: + fseek($imageFile, $chunkLength + 4, SEEK_CUR); //Skip the section + break; + } + } + fclose($imageFile); + + $compressed = true; + $imageDataTmp = ''; + $smaskData = ''; + switch ($color) { + case Zend_Pdf_Resource_Image_Png::PNG_CHANNEL_RGB: + $colorSpace = new Zend_Pdf_Element_Name('DeviceRGB'); + break; + + case Zend_Pdf_Resource_Image_Png::PNG_CHANNEL_GRAY: + $colorSpace = new Zend_Pdf_Element_Name('DeviceGray'); + break; + + case Zend_Pdf_Resource_Image_Png::PNG_CHANNEL_INDEXED: + if(empty($paletteData)) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception( "PNG Corruption: No palette data read for indexed type PNG." ); + } + $colorSpace = new Zend_Pdf_Element_Array(); + $colorSpace->items[] = new Zend_Pdf_Element_Name('Indexed'); + $colorSpace->items[] = new Zend_Pdf_Element_Name('DeviceRGB'); + $colorSpace->items[] = new Zend_Pdf_Element_Numeric((strlen($paletteData)/3-1)); + $paletteObject = $this->_objectFactory->newObject(new Zend_Pdf_Element_String_Binary($paletteData)); + $colorSpace->items[] = $paletteObject; + break; + + case Zend_Pdf_Resource_Image_Png::PNG_CHANNEL_GRAY_ALPHA: + /* + * To decode PNG's with alpha data we must create two images from one. One image will contain the Gray data + * the other will contain the Gray transparency overlay data. The former will become the object data and the latter + * will become the Shadow Mask (SMask). + */ + if($bits > 8) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("Alpha PNGs with bit depth > 8 are not yet supported"); + } + + $colorSpace = new Zend_Pdf_Element_Name('DeviceGray'); + + // require_once 'Zend/Pdf/ElementFactory.php'; + $decodingObjFactory = Zend_Pdf_ElementFactory::createFactory(1); + $decodingStream = $decodingObjFactory->newStreamObject($imageData); + $decodingStream->dictionary->Filter = new Zend_Pdf_Element_Name('FlateDecode'); + $decodingStream->dictionary->DecodeParms = new Zend_Pdf_Element_Dictionary(); + $decodingStream->dictionary->DecodeParms->Predictor = new Zend_Pdf_Element_Numeric(15); + $decodingStream->dictionary->DecodeParms->Columns = new Zend_Pdf_Element_Numeric($width); + $decodingStream->dictionary->DecodeParms->Colors = new Zend_Pdf_Element_Numeric(2); //GreyAlpha + $decodingStream->dictionary->DecodeParms->BitsPerComponent = new Zend_Pdf_Element_Numeric($bits); + $decodingStream->skipFilters(); + + $pngDataRawDecoded = $decodingStream->value; + + //Iterate every pixel and copy out gray data and alpha channel (this will be slow) + for($pixel = 0, $pixelcount = ($width * $height); $pixel < $pixelcount; $pixel++) { + $imageDataTmp .= $pngDataRawDecoded[($pixel*2)]; + $smaskData .= $pngDataRawDecoded[($pixel*2)+1]; + } + $compressed = false; + $imageData = $imageDataTmp; //Overwrite image data with the gray channel without alpha + break; + + case Zend_Pdf_Resource_Image_Png::PNG_CHANNEL_RGB_ALPHA: + /* + * To decode PNG's with alpha data we must create two images from one. One image will contain the RGB data + * the other will contain the Gray transparency overlay data. The former will become the object data and the latter + * will become the Shadow Mask (SMask). + */ + if($bits > 8) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("Alpha PNGs with bit depth > 8 are not yet supported"); + } + + $colorSpace = new Zend_Pdf_Element_Name('DeviceRGB'); + + // require_once 'Zend/Pdf/ElementFactory.php'; + $decodingObjFactory = Zend_Pdf_ElementFactory::createFactory(1); + $decodingStream = $decodingObjFactory->newStreamObject($imageData); + $decodingStream->dictionary->Filter = new Zend_Pdf_Element_Name('FlateDecode'); + $decodingStream->dictionary->DecodeParms = new Zend_Pdf_Element_Dictionary(); + $decodingStream->dictionary->DecodeParms->Predictor = new Zend_Pdf_Element_Numeric(15); + $decodingStream->dictionary->DecodeParms->Columns = new Zend_Pdf_Element_Numeric($width); + $decodingStream->dictionary->DecodeParms->Colors = new Zend_Pdf_Element_Numeric(4); //RGBA + $decodingStream->dictionary->DecodeParms->BitsPerComponent = new Zend_Pdf_Element_Numeric($bits); + $decodingStream->skipFilters(); + + $pngDataRawDecoded = $decodingStream->value; + + //Iterate every pixel and copy out rgb data and alpha channel (this will be slow) + for($pixel = 0, $pixelcount = ($width * $height); $pixel < $pixelcount; $pixel++) { + $imageDataTmp .= $pngDataRawDecoded[($pixel*4)+0] . $pngDataRawDecoded[($pixel*4)+1] . $pngDataRawDecoded[($pixel*4)+2]; + $smaskData .= $pngDataRawDecoded[($pixel*4)+3]; + } + + $compressed = false; + $imageData = $imageDataTmp; //Overwrite image data with the RGB channel without alpha + break; + + default: + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception( "PNG Corruption: Invalid color space." ); + } + + if(empty($imageData)) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception( "Corrupt PNG Image. Mandatory IDAT chunk not found." ); + } + + $imageDictionary = $this->_resource->dictionary; + if(!empty($smaskData)) { + /* + * Includes the Alpha transparency data as a Gray Image, then assigns the image as the Shadow Mask for the main image data. + */ + $smaskStream = $this->_objectFactory->newStreamObject($smaskData); + $smaskStream->dictionary->Type = new Zend_Pdf_Element_Name('XObject'); + $smaskStream->dictionary->Subtype = new Zend_Pdf_Element_Name('Image'); + $smaskStream->dictionary->Width = new Zend_Pdf_Element_Numeric($width); + $smaskStream->dictionary->Height = new Zend_Pdf_Element_Numeric($height); + $smaskStream->dictionary->ColorSpace = new Zend_Pdf_Element_Name('DeviceGray'); + $smaskStream->dictionary->BitsPerComponent = new Zend_Pdf_Element_Numeric($bits); + $imageDictionary->SMask = $smaskStream; + + // Encode stream with FlateDecode filter + $smaskStreamDecodeParms = array(); + $smaskStreamDecodeParms['Predictor'] = new Zend_Pdf_Element_Numeric(15); + $smaskStreamDecodeParms['Columns'] = new Zend_Pdf_Element_Numeric($width); + $smaskStreamDecodeParms['Colors'] = new Zend_Pdf_Element_Numeric(1); + $smaskStreamDecodeParms['BitsPerComponent'] = new Zend_Pdf_Element_Numeric(8); + $smaskStream->dictionary->DecodeParms = new Zend_Pdf_Element_Dictionary($smaskStreamDecodeParms); + $smaskStream->dictionary->Filter = new Zend_Pdf_Element_Name('FlateDecode'); + } + + if(!empty($transparencyData)) { + //This is experimental and not properly tested. + $imageDictionary->Mask = new Zend_Pdf_Element_Array($transparencyData); + } + + $imageDictionary->Width = new Zend_Pdf_Element_Numeric($width); + $imageDictionary->Height = new Zend_Pdf_Element_Numeric($height); + $imageDictionary->ColorSpace = $colorSpace; + $imageDictionary->BitsPerComponent = new Zend_Pdf_Element_Numeric($bits); + $imageDictionary->Filter = new Zend_Pdf_Element_Name('FlateDecode'); + + $decodeParms = array(); + $decodeParms['Predictor'] = new Zend_Pdf_Element_Numeric(15); // Optimal prediction + $decodeParms['Columns'] = new Zend_Pdf_Element_Numeric($width); + $decodeParms['Colors'] = new Zend_Pdf_Element_Numeric((($color==Zend_Pdf_Resource_Image_Png::PNG_CHANNEL_RGB || $color==Zend_Pdf_Resource_Image_Png::PNG_CHANNEL_RGB_ALPHA)?(3):(1))); + $decodeParms['BitsPerComponent'] = new Zend_Pdf_Element_Numeric($bits); + $imageDictionary->DecodeParms = new Zend_Pdf_Element_Dictionary($decodeParms); + + //Include only the image IDAT section data. + $this->_resource->value = $imageData; + + //Skip double compression + if ($compressed) { + $this->_resource->skipFilters(); + } + } + + /** + * Image width + */ + public function getPixelWidth() { + return $this->_width; + } + + /** + * Image height + */ + public function getPixelHeight() { + return $this->_height; + } + + /** + * Image properties + */ + public function getProperties() { + return $this->_imageProperties; + } +} diff --git a/library/Zend/Pdf/Resource/Image/Tiff.php b/library/Zend/Pdf/Resource/Image/Tiff.php new file mode 100644 index 0000000..101c1fd --- /dev/null +++ b/library/Zend/Pdf/Resource/Image/Tiff.php @@ -0,0 +1,442 @@ +_endianType)) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("The unpackBytes function can only be used after the endianness of the file is known"); + } + switch($type) { + case Zend_Pdf_Resource_Image_Tiff::UNPACK_TYPE_BYTE: + $format = 'C'; + $unpacked = unpack($format, $bytes); + return $unpacked[1]; + break; + case Zend_Pdf_Resource_Image_Tiff::UNPACK_TYPE_SHORT: + $format = ($this->_endianType == Zend_Pdf_Resource_Image_Tiff::TIFF_ENDIAN_LITTLE)?'v':'n'; + $unpacked = unpack($format, $bytes); + return $unpacked[1]; + break; + case Zend_Pdf_Resource_Image_Tiff::UNPACK_TYPE_LONG: + $format = ($this->_endianType == Zend_Pdf_Resource_Image_Tiff::TIFF_ENDIAN_LITTLE)?'V':'N'; + $unpacked = unpack($format, $bytes); + return $unpacked[1]; + break; + case Zend_Pdf_Resource_Image_Tiff::UNPACK_TYPE_RATIONAL: + $format = ($this->_endianType == Zend_Pdf_Resource_Image_Tiff::TIFF_ENDIAN_LITTLE)?'V2':'N2'; + $unpacked = unpack($format, $bytes); + return ($unpacked[1]/$unpacked[2]); + break; + } + } + + /** + * Object constructor + * + * @param string $imageFileName + * @throws Zend_Pdf_Exception + */ + public function __construct($imageFileName) + { + if (($imageFile = @fopen($imageFileName, 'rb')) === false ) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception( "Can not open '$imageFileName' file for reading." ); + } + + $byteOrderIndicator = fread($imageFile, 2); + if($byteOrderIndicator == 'II') { + $this->_endianType = Zend_Pdf_Resource_Image_Tiff::TIFF_ENDIAN_LITTLE; + } else if($byteOrderIndicator == 'MM') { + $this->_endianType = Zend_Pdf_Resource_Image_Tiff::TIFF_ENDIAN_BIG; + } else { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception( "Not a tiff file or Tiff corrupt. No byte order indication found" ); + } + + $version = $this->unpackBytes(Zend_Pdf_Resource_Image_Tiff::UNPACK_TYPE_SHORT, fread($imageFile, 2)); + + if($version != 42) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception( "Not a tiff file or Tiff corrupt. Incorrect version number." ); + } + $ifdOffset = $this->unpackBytes(Zend_Pdf_Resource_Image_Tiff::UNPACK_TYPE_LONG, fread($imageFile, 4)); + + $fileStats = fstat($imageFile); + $this->_fileSize = $fileStats['size']; + + /* + * Tiff files are stored as a series of Image File Directories (IFD) each direcctory + * has a specific number of entries each 12 bytes in length. At the end of the directories + * is four bytes pointing to the offset of the next IFD. + */ + + while($ifdOffset > 0) { + if(fseek($imageFile, $ifdOffset, SEEK_SET) == -1 || $ifdOffset+2 >= $this->_fileSize) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("Could not seek to the image file directory as indexed by the file. Likely cause is TIFF corruption. Offset: ". $ifdOffset); + } + + $numDirEntries = $this->unpackBytes(Zend_Pdf_Resource_Image_Tiff::UNPACK_TYPE_SHORT, fread($imageFile, 2)); + + /* + * Since we now know how many entries are in this (IFD) we can extract the data. + * The format of a TIFF directory entry is: + * + * 2 bytes (short) tag code; See TIFF_TAG constants at the top for supported values. (There are many more in the spec) + * 2 bytes (short) field type + * 4 bytes (long) number of values, or value count. + * 4 bytes (mixed) data if the data will fit into 4 bytes or an offset if the data is too large. + */ + for($dirEntryIdx = 1; $dirEntryIdx <= $numDirEntries; $dirEntryIdx++) { + $tag = $this->unpackBytes(Zend_Pdf_Resource_Image_Tiff::UNPACK_TYPE_SHORT, fread($imageFile, 2)); + $fieldType = $this->unpackBytes(Zend_Pdf_Resource_Image_Tiff::UNPACK_TYPE_SHORT, fread($imageFile, 2)); + $valueCount = $this->unpackBytes(Zend_Pdf_Resource_Image_Tiff::UNPACK_TYPE_LONG, fread($imageFile, 4)); + + switch($fieldType) { + case Zend_Pdf_Resource_Image_Tiff::TIFF_FIELD_TYPE_BYTE: + $fieldLength = $valueCount; + break; + case Zend_Pdf_Resource_Image_Tiff::TIFF_FIELD_TYPE_ASCII: + $fieldLength = $valueCount; + break; + case Zend_Pdf_Resource_Image_Tiff::TIFF_FIELD_TYPE_SHORT: + $fieldLength = $valueCount * 2; + break; + case Zend_Pdf_Resource_Image_Tiff::TIFF_FIELD_TYPE_LONG: + $fieldLength = $valueCount * 4; + break; + case Zend_Pdf_Resource_Image_Tiff::TIFF_FIELD_TYPE_RATIONAL: + $fieldLength = $valueCount * 8; + break; + default: + $fieldLength = $valueCount; + } + + $offsetBytes = fread($imageFile, 4); + + if($fieldLength <= 4) { + switch($fieldType) { + case Zend_Pdf_Resource_Image_Tiff::TIFF_FIELD_TYPE_BYTE: + $value = $this->unpackBytes(Zend_Pdf_Resource_Image_Tiff::UNPACK_TYPE_BYTE, $offsetBytes); + break; + case Zend_Pdf_Resource_Image_Tiff::TIFF_FIELD_TYPE_ASCII: + //Fall through to next case + case Zend_Pdf_Resource_Image_Tiff::TIFF_FIELD_TYPE_LONG: + $value = $this->unpackBytes(Zend_Pdf_Resource_Image_Tiff::UNPACK_TYPE_LONG, $offsetBytes); + break; + case Zend_Pdf_Resource_Image_Tiff::TIFF_FIELD_TYPE_SHORT: + //Fall through to next case + default: + $value = $this->unpackBytes(Zend_Pdf_Resource_Image_Tiff::UNPACK_TYPE_SHORT, $offsetBytes); + } + } else { + $refOffset = $this->unpackBytes(Zend_Pdf_Resource_Image_Tiff::UNPACK_TYPE_LONG, $offsetBytes); + } + /* + * Linear tag processing is probably not the best way to do this. I've processed the tags according to the + * Tiff 6 specification and make some assumptions about when tags will be < 4 bytes and fit into $value and when + * they will be > 4 bytes and require seek/extraction of the offset. Same goes for extracting arrays of data, like + * the data offsets and length. This should be fixed in the future. + */ + switch($tag) { + case Zend_Pdf_Resource_Image_Tiff::TIFF_TAG_IMAGE_WIDTH: + $this->_width = $value; + break; + case Zend_Pdf_Resource_Image_Tiff::TIFF_TAG_IMAGE_LENGTH: + $this->_height = $value; + break; + case Zend_Pdf_Resource_Image_Tiff::TIFF_TAG_BITS_PER_SAMPLE: + if($valueCount>1) { + $fp = ftell($imageFile); + fseek($imageFile, $refOffset, SEEK_SET); + $this->_bitsPerSample = $this->unpackBytes(Zend_Pdf_Resource_Image_Tiff::UNPACK_TYPE_SHORT, fread($imageFile, 2)); + fseek($imageFile, $fp, SEEK_SET); + } else { + $this->_bitsPerSample = $value; + } + break; + case Zend_Pdf_Resource_Image_Tiff::TIFF_TAG_COMPRESSION: + $this->_compression = $value; + switch($value) { + case Zend_Pdf_Resource_Image_Tiff::TIFF_COMPRESSION_UNCOMPRESSED: + $this->_filter = 'None'; + break; + case Zend_Pdf_Resource_Image_Tiff::TIFF_COMPRESSION_CCITT1D: + //Fall through to next case + case Zend_Pdf_Resource_Image_Tiff::TIFF_COMPRESSION_GROUP_3_FAX: + //Fall through to next case + case Zend_Pdf_Resource_Image_Tiff::TIFF_COMPRESSION_GROUP_4_FAX: + $this->_filter = 'CCITTFaxDecode'; + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("CCITTFaxDecode Compression Mode Not Currently Supported"); + break; + case Zend_Pdf_Resource_Image_Tiff::TIFF_COMPRESSION_LZW: + $this->_filter = 'LZWDecode'; + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("LZWDecode Compression Mode Not Currently Supported"); + break; + case Zend_Pdf_Resource_Image_Tiff::TIFF_COMPRESSION_JPEG: + $this->_filter = 'DCTDecode'; //Should work, doesnt... + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("JPEG Compression Mode Not Currently Supported"); + break; + case Zend_Pdf_Resource_Image_Tiff::TIFF_COMPRESSION_FLATE: + //fall through to next case + case Zend_Pdf_Resource_Image_Tiff::TIFF_COMPRESSION_FLATE_OBSOLETE_CODE: + $this->_filter = 'FlateDecode'; + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("ZIP/Flate Compression Mode Not Currently Supported"); + break; + case Zend_Pdf_Resource_Image_Tiff::TIFF_COMPRESSION_PACKBITS: + $this->_filter = 'RunLengthDecode'; + break; + } + break; + case Zend_Pdf_Resource_Image_Tiff::TIFF_TAG_PHOTOMETRIC_INTERPRETATION: + $this->_colorCode = $value; + $this->_whiteIsZero = false; + $this->_blackIsZero = false; + switch($value) { + case Zend_Pdf_Resource_Image_Tiff::TIFF_PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO: + $this->_whiteIsZero = true; + $this->_colorSpace = 'DeviceGray'; + break; + case Zend_Pdf_Resource_Image_Tiff::TIFF_PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO: + $this->_blackIsZero = true; + $this->_colorSpace = 'DeviceGray'; + break; + case Zend_Pdf_Resource_Image_Tiff::TIFF_PHOTOMETRIC_INTERPRETATION_YCBCR: + //fall through to next case + case Zend_Pdf_Resource_Image_Tiff::TIFF_PHOTOMETRIC_INTERPRETATION_RGB: + $this->_colorSpace = 'DeviceRGB'; + break; + case Zend_Pdf_Resource_Image_Tiff::TIFF_PHOTOMETRIC_INTERPRETATION_RGB_INDEXED: + $this->_colorSpace = 'Indexed'; + break; + case Zend_Pdf_Resource_Image_Tiff::TIFF_PHOTOMETRIC_INTERPRETATION_CMYK: + $this->_colorSpace = 'DeviceCMYK'; + break; + case Zend_Pdf_Resource_Image_Tiff::TIFF_PHOTOMETRIC_INTERPRETATION_CIELAB: + $this->_colorSpace = 'Lab'; + break; + default: + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('TIFF: Unknown or Unsupported Color Type: '. $value); + } + break; + case Zend_Pdf_Resource_Image_Tiff::TIFF_TAG_STRIP_OFFSETS: + if($valueCount>1) { + $format = ($this->_endianType == Zend_Pdf_Resource_Image_Tiff::TIFF_ENDIAN_LITTLE)?'V*':'N*'; + $fp = ftell($imageFile); + fseek($imageFile, $refOffset, SEEK_SET); + $stripOffsetsBytes = fread($imageFile, $fieldLength); + $this->_imageDataOffset = unpack($format, $stripOffsetsBytes); + fseek($imageFile, $fp, SEEK_SET); + } else { + $this->_imageDataOffset = $value; + } + break; + case Zend_Pdf_Resource_Image_Tiff::TIFF_TAG_STRIP_BYTE_COUNTS: + if($valueCount>1) { + $format = ($this->_endianType == Zend_Pdf_Resource_Image_Tiff::TIFF_ENDIAN_LITTLE)?'V*':'N*'; + $fp = ftell($imageFile); + fseek($imageFile, $refOffset, SEEK_SET); + $stripByteCountsBytes = fread($imageFile, $fieldLength); + $this->_imageDataLength = unpack($format, $stripByteCountsBytes); + fseek($imageFile, $fp, SEEK_SET); + } else { + $this->_imageDataLength = $value; + } + break; + default: + //For debugging. It should be harmless to ignore unknown tags, though there is some good info in them. + //echo "Unknown tag detected: ". $tag . " value: ". $value; + } + } + $ifdOffset = $this->unpackBytes(Zend_Pdf_Resource_Image_Tiff::UNPACK_TYPE_LONG, fread($imageFile, 4)); + } + + if(!isset($this->_imageDataOffset) || !isset($this->_imageDataLength)) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("TIFF: The image processed did not contain image data as expected."); + } + + $imageDataBytes = ''; + if(is_array($this->_imageDataOffset)) { + if(!is_array($this->_imageDataLength)) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("TIFF: The image contained multiple data offsets but not multiple data lengths. Tiff may be corrupt."); + } + foreach($this->_imageDataOffset as $idx => $offset) { + fseek($imageFile, $this->_imageDataOffset[$idx], SEEK_SET); + $imageDataBytes .= fread($imageFile, $this->_imageDataLength[$idx]); + } + } else { + fseek($imageFile, $this->_imageDataOffset, SEEK_SET); + $imageDataBytes = fread($imageFile, $this->_imageDataLength); + } + if($imageDataBytes === '') { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("TIFF: No data. Image Corruption"); + } + + fclose($imageFile); + + parent::__construct(); + + $imageDictionary = $this->_resource->dictionary; + if(!isset($this->_width) || !isset($this->_width)) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception("Problem reading tiff file. Tiff is probably corrupt."); + } + + $this->_imageProperties = array(); + $this->_imageProperties['bitDepth'] = $this->_bitsPerSample; + $this->_imageProperties['fileSize'] = $this->_fileSize; + $this->_imageProperties['TIFFendianType'] = $this->_endianType; + $this->_imageProperties['TIFFcompressionType'] = $this->_compression; + $this->_imageProperties['TIFFwhiteIsZero'] = $this->_whiteIsZero; + $this->_imageProperties['TIFFblackIsZero'] = $this->_blackIsZero; + $this->_imageProperties['TIFFcolorCode'] = $this->_colorCode; + $this->_imageProperties['TIFFimageDataOffset'] = $this->_imageDataOffset; + $this->_imageProperties['TIFFimageDataLength'] = $this->_imageDataLength; + $this->_imageProperties['PDFfilter'] = $this->_filter; + $this->_imageProperties['PDFcolorSpace'] = $this->_colorSpace; + + $imageDictionary->Width = new Zend_Pdf_Element_Numeric($this->_width); + if($this->_whiteIsZero === true) { + $imageDictionary->Decode = new Zend_Pdf_Element_Array(array(new Zend_Pdf_Element_Numeric(1), new Zend_Pdf_Element_Numeric(0))); + } + $imageDictionary->Height = new Zend_Pdf_Element_Numeric($this->_height); + $imageDictionary->ColorSpace = new Zend_Pdf_Element_Name($this->_colorSpace); + $imageDictionary->BitsPerComponent = new Zend_Pdf_Element_Numeric($this->_bitsPerSample); + if(isset($this->_filter) && $this->_filter != 'None') { + $imageDictionary->Filter = new Zend_Pdf_Element_Name($this->_filter); + } + + $this->_resource->value = $imageDataBytes; + $this->_resource->skipFilters(); + } + /** + * Image width (defined in Zend_Pdf_Resource_Image_Interface) + */ + public function getPixelWidth() { + return $this->_width; + } + + /** + * Image height (defined in Zend_Pdf_Resource_Image_Interface) + */ + public function getPixelHeight() { + return $this->_height; + } + + /** + * Image properties (defined in Zend_Pdf_Resource_Image_Interface) + */ + public function getProperties() { + return $this->_imageProperties; + } +} + diff --git a/library/Zend/Pdf/Resource/ImageFactory.php b/library/Zend/Pdf/Resource/ImageFactory.php new file mode 100644 index 0000000..7b6a4e9 --- /dev/null +++ b/library/Zend/Pdf/Resource/ImageFactory.php @@ -0,0 +1,71 @@ +_context = null; + $this->_elements = array(); + $this->_objFactory = null; + } + + /** + * Character with code $chCode is white space + * + * @param integer $chCode + * @return boolean + */ + public static function isWhiteSpace($chCode) + { + if ($chCode == 0x00 || // null character + $chCode == 0x09 || // Tab + $chCode == 0x0A || // Line feed + $chCode == 0x0C || // Form Feed + $chCode == 0x0D || // Carriage return + $chCode == 0x20 // Space + ) { + return true; + } else { + return false; + } + } + + + /** + * Character with code $chCode is a delimiter character + * + * @param integer $chCode + * @return boolean + */ + public static function isDelimiter($chCode ) + { + if ($chCode == 0x28 || // '(' + $chCode == 0x29 || // ')' + $chCode == 0x3C || // '<' + $chCode == 0x3E || // '>' + $chCode == 0x5B || // '[' + $chCode == 0x5D || // ']' + $chCode == 0x7B || // '{' + $chCode == 0x7D || // '}' + $chCode == 0x2F || // '/' + $chCode == 0x25 // '%' + ) { + return true; + } else { + return false; + } + } + + + /** + * Skip white space + * + * @param boolean $skipComment + */ + public function skipWhiteSpace($skipComment = true) + { + if ($skipComment) { + while (true) { + $this->offset += strspn($this->data, "\x00\t\n\f\r ", $this->offset); + + if ($this->offset < strlen($this->data) && $this->data[$this->offset] == '%') { + // Skip comment + $this->offset += strcspn($this->data, "\r\n", $this->offset); + } else { + // Non white space character not equal to '%' is found + return; + } + } + } else { + $this->offset += strspn($this->data, "\x00\t\n\f\r ", $this->offset); + } + +// /** Original (non-optimized) implementation. */ +// +// while ($this->offset < strlen($this->data)) { +// if (strpos("\x00\t\n\f\r ", $this->data[$this->offset]) !== false) { +// $this->offset++; +// } else if (ord($this->data[$this->offset]) == 0x25 && $skipComment) { // '%' +// $this->skipComment(); +// } else { +// return; +// } +// } + } + + + /** + * Skip comment + */ + public function skipComment() + { + while ($this->offset < strlen($this->data)) + { + if (ord($this->data[$this->offset]) != 0x0A || // Line feed + ord($this->data[$this->offset]) != 0x0d // Carriage return + ) { + $this->offset++; + } else { + return; + } + } + } + + + /** + * Read comment line + * + * @return string + */ + public function readComment() + { + $this->skipWhiteSpace(false); + + /** Check if it's a comment line */ + if ($this->data[$this->offset] != '%') { + return ''; + } + + for ($start = $this->offset; + $this->offset < strlen($this->data); + $this->offset++) { + if (ord($this->data[$this->offset]) == 0x0A || // Line feed + ord($this->data[$this->offset]) == 0x0d // Carriage return + ) { + break; + } + } + + return substr($this->data, $start, $this->offset-$start); + } + + + /** + * Returns next lexeme from a pdf stream + * + * @return string + */ + public function readLexeme() + { + // $this->skipWhiteSpace(); + while (true) { + $this->offset += strspn($this->data, "\x00\t\n\f\r ", $this->offset); + + if ($this->offset < strlen($this->data) && $this->data[$this->offset] == '%') { + $this->offset += strcspn($this->data, "\r\n", $this->offset); + } else { + break; + } + } + + if ($this->offset >= strlen($this->data)) { + return ''; + } + + if ( /* self::isDelimiter( ord($this->data[$start]) ) */ + strpos('()<>[]{}/%', $this->data[$this->offset]) !== false ) { + + switch (substr($this->data, $this->offset, 2)) { + case '<<': + $this->offset += 2; + return '<<'; + break; + + case '>>': + $this->offset += 2; + return '>>'; + break; + + default: + return $this->data[$this->offset++]; + break; + } + } else { + $start = $this->offset; + $compare = ''; + if( version_compare( phpversion(), '5.2.5' ) >= 0) { + $compare = "()<>[]{}/%\x00\t\n\f\r "; + } else { + $compare = "()<>[]{}/%\x00\t\n\r "; + } + + $this->offset += strcspn($this->data, $compare, $this->offset); + + return substr($this->data, $start, $this->offset - $start); + } + } + + + /** + * Read elemental object from a PDF stream + * + * @return Zend_Pdf_Element + * @throws Zend_Pdf_Exception + */ + public function readElement($nextLexeme = null) + { + if ($nextLexeme === null) { + $nextLexeme = $this->readLexeme(); + } + + /** + * Note: readElement() method is a public method and could be invoked from other classes. + * If readElement() is used not by Zend_Pdf_StringParser::getObject() method, then we should not care + * about _elements member management. + */ + switch ($nextLexeme) { + case '(': + return ($this->_elements[] = $this->_readString()); + + case '<': + return ($this->_elements[] = $this->_readBinaryString()); + + case '/': + return ($this->_elements[] = new Zend_Pdf_Element_Name( + Zend_Pdf_Element_Name::unescape( $this->readLexeme() ) + )); + + case '[': + return ($this->_elements[] = $this->_readArray()); + + case '<<': + return ($this->_elements[] = $this->_readDictionary()); + + case ')': + // fall through to next case + case '>': + // fall through to next case + case ']': + // fall through to next case + case '>>': + // fall through to next case + case '{': + // fall through to next case + case '}': + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(sprintf('PDF file syntax error. Offset - 0x%X.', + $this->offset)); + + default: + if (strcasecmp($nextLexeme, 'true') == 0) { + return ($this->_elements[] = new Zend_Pdf_Element_Boolean(true)); + } else if (strcasecmp($nextLexeme, 'false') == 0) { + return ($this->_elements[] = new Zend_Pdf_Element_Boolean(false)); + } else if (strcasecmp($nextLexeme, 'null') == 0) { + return ($this->_elements[] = new Zend_Pdf_Element_Null()); + } + + $ref = $this->_readReference($nextLexeme); + if ($ref !== null) { + return ($this->_elements[] = $ref); + } + + return ($this->_elements[] = $this->_readNumeric($nextLexeme)); + } + } + + + /** + * Read string PDF object + * Also reads trailing ')' from a pdf stream + * + * @return Zend_Pdf_Element_String + * @throws Zend_Pdf_Exception + */ + private function _readString() + { + $start = $this->offset; + $openedBrackets = 1; + + $this->offset += strcspn($this->data, '()\\', $this->offset); + + while ($this->offset < strlen($this->data)) { + switch (ord( $this->data[$this->offset] )) { + case 0x28: // '(' - opened bracket in the string, needs balanced pair. + $this->offset++; + $openedBrackets++; + break; + + case 0x29: // ')' - pair to the opened bracket + $this->offset++; + $openedBrackets--; + break; + + case 0x5C: // '\\' - escape sequence, skip next char from a check + $this->offset += 2; + } + + if ($openedBrackets == 0) { + break; // end of string + } + + $this->offset += strcspn($this->data, '()\\', $this->offset); + } + if ($openedBrackets != 0) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(sprintf('PDF file syntax error. Unexpected end of file while string reading. Offset - 0x%X. \')\' expected.', $start)); + } + + return new Zend_Pdf_Element_String(Zend_Pdf_Element_String::unescape( substr($this->data, + $start, + $this->offset - $start - 1) )); + } + + + /** + * Read binary string PDF object + * Also reads trailing '>' from a pdf stream + * + * @return Zend_Pdf_Element_String_Binary + * @throws Zend_Pdf_Exception + */ + private function _readBinaryString() + { + $start = $this->offset; + + $this->offset += strspn($this->data, "\x00\t\n\f\r 0123456789abcdefABCDEF", $this->offset); + + if ($this->offset >= strlen($this->data) - 1) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(sprintf('PDF file syntax error. Unexpected end of file while reading binary string. Offset - 0x%X. \'>\' expected.', $start)); + } + + if ($this->data[$this->offset++] != '>') { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(sprintf('PDF file syntax error. Unexpected character while binary string reading. Offset - 0x%X.', $this->offset)); + } + + return new Zend_Pdf_Element_String_Binary( + Zend_Pdf_Element_String_Binary::unescape( substr($this->data, + $start, + $this->offset - $start - 1) )); + } + + + /** + * Read array PDF object + * Also reads trailing ']' from a pdf stream + * + * @return Zend_Pdf_Element_Array + * @throws Zend_Pdf_Exception + */ + private function _readArray() + { + $elements = array(); + + while ( strlen($nextLexeme = $this->readLexeme()) != 0 ) { + if ($nextLexeme != ']') { + $elements[] = $this->readElement($nextLexeme); + } else { + return new Zend_Pdf_Element_Array($elements); + } + } + + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(sprintf('PDF file syntax error. Unexpected end of file while array reading. Offset - 0x%X. \']\' expected.', $this->offset)); + } + + + /** + * Read dictionary PDF object + * Also reads trailing '>>' from a pdf stream + * + * @return Zend_Pdf_Element_Dictionary + * @throws Zend_Pdf_Exception + */ + private function _readDictionary() + { + $dictionary = new Zend_Pdf_Element_Dictionary(); + + while ( strlen($nextLexeme = $this->readLexeme()) != 0 ) { + if ($nextLexeme != '>>') { + $nameStart = $this->offset - strlen($nextLexeme); + + $name = $this->readElement($nextLexeme); + $value = $this->readElement(); + + if (!$name instanceof Zend_Pdf_Element_Name) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(sprintf('PDF file syntax error. Name object expected while dictionary reading. Offset - 0x%X.', $nameStart)); + } + + $dictionary->add($name, $value); + } else { + return $dictionary; + } + } + + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(sprintf('PDF file syntax error. Unexpected end of file while dictionary reading. Offset - 0x%X. \'>>\' expected.', $this->offset)); + } + + + /** + * Read reference PDF object + * + * @param string $nextLexeme + * @return Zend_Pdf_Element_Reference + */ + private function _readReference($nextLexeme = null) + { + $start = $this->offset; + + if ($nextLexeme === null) { + $objNum = $this->readLexeme(); + } else { + $objNum = $nextLexeme; + } + if (!ctype_digit($objNum)) { // it's not a reference + $this->offset = $start; + return null; + } + + $genNum = $this->readLexeme(); + if (!ctype_digit($genNum)) { // it's not a reference + $this->offset = $start; + return null; + } + + $rMark = $this->readLexeme(); + if ($rMark != 'R') { // it's not a reference + $this->offset = $start; + return null; + } + + $ref = new Zend_Pdf_Element_Reference((int)$objNum, (int)$genNum, $this->_context, $this->_objFactory->resolve()); + + return $ref; + } + + + /** + * Read numeric PDF object + * + * @param string $nextLexeme + * @return Zend_Pdf_Element_Numeric + */ + private function _readNumeric($nextLexeme = null) + { + if ($nextLexeme === null) { + $nextLexeme = $this->readLexeme(); + } + + return new Zend_Pdf_Element_Numeric($nextLexeme); + } + + + /** + * Read inderect object from a PDF stream + * + * @param integer $offset + * @param Zend_Pdf_Element_Reference_Context $context + * @return Zend_Pdf_Element_Object + */ + public function getObject($offset, Zend_Pdf_Element_Reference_Context $context) + { + if ($offset === null ) { + return new Zend_Pdf_Element_Null(); + } + + // Save current offset to make getObject() reentrant + $offsetSave = $this->offset; + + $this->offset = $offset; + $this->_context = $context; + $this->_elements = array(); + + $objNum = $this->readLexeme(); + if (!ctype_digit($objNum)) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(sprintf('PDF file syntax error. Offset - 0x%X. Object number expected.', $this->offset - strlen($objNum))); + } + + $genNum = $this->readLexeme(); + if (!ctype_digit($genNum)) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(sprintf('PDF file syntax error. Offset - 0x%X. Object generation number expected.', $this->offset - strlen($genNum))); + } + + $objKeyword = $this->readLexeme(); + if ($objKeyword != 'obj') { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(sprintf('PDF file syntax error. Offset - 0x%X. \'obj\' keyword expected.', $this->offset - strlen($objKeyword))); + } + + $objValue = $this->readElement(); + + $nextLexeme = $this->readLexeme(); + + if( $nextLexeme == 'endobj' ) { + /** + * Object is not generated by factory (thus it's not marked as modified object). + * But factory is assigned to the obect. + */ + $obj = new Zend_Pdf_Element_Object($objValue, (int)$objNum, (int)$genNum, $this->_objFactory->resolve()); + + foreach ($this->_elements as $element) { + $element->setParentObject($obj); + } + + // Restore offset value + $this->offset = $offsetSave; + + return $obj; + } + + /** + * It's a stream object + */ + if ($nextLexeme != 'stream') { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(sprintf('PDF file syntax error. Offset - 0x%X. \'endobj\' or \'stream\' keywords expected.', $this->offset - strlen($nextLexeme))); + } + + if (!$objValue instanceof Zend_Pdf_Element_Dictionary) { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(sprintf('PDF file syntax error. Offset - 0x%X. Stream extent must be preceded by stream dictionary.', $this->offset - strlen($nextLexeme))); + } + + /** + * References are automatically dereferenced at this moment. + */ + $streamLength = $objValue->Length->value; + + /** + * 'stream' keyword must be followed by either cr-lf sequence or lf character only. + * This restriction gives the possibility to recognize all cases exactly + */ + if ($this->data[$this->offset] == "\r" && + $this->data[$this->offset + 1] == "\n" ) { + $this->offset += 2; + } else if ($this->data[$this->offset] == "\n" ) { + $this->offset++; + } else { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(sprintf('PDF file syntax error. Offset - 0x%X. \'stream\' must be followed by either cr-lf sequence or lf character only.', $this->offset - strlen($nextLexeme))); + } + + $dataOffset = $this->offset; + + $this->offset += $streamLength; + + $nextLexeme = $this->readLexeme(); + if ($nextLexeme != 'endstream') { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(sprintf('PDF file syntax error. Offset - 0x%X. \'endstream\' keyword expected.', $this->offset - strlen($nextLexeme))); + } + + $nextLexeme = $this->readLexeme(); + if ($nextLexeme != 'endobj') { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception(sprintf('PDF file syntax error. Offset - 0x%X. \'endobj\' keyword expected.', $this->offset - strlen($nextLexeme))); + } + + $obj = new Zend_Pdf_Element_Object_Stream(substr($this->data, + $dataOffset, + $streamLength), + (int)$objNum, + (int)$genNum, + $this->_objFactory->resolve(), + $objValue); + + foreach ($this->_elements as $element) { + $element->setParentObject($obj); + } + + // Restore offset value + $this->offset = $offsetSave; + + return $obj; + } + + + /** + * Get length of source string + * + * @return integer + */ + public function getLength() + { + return strlen($this->data); + } + + /** + * Get source string + * + * @return string + */ + public function getString() + { + return $this->data; + } + + + /** + * Parse integer value from a binary stream + * + * @param string $stream + * @param integer $offset + * @param integer $size + * @return integer + */ + public static function parseIntFromStream($stream, $offset, $size) + { + $value = 0; + for ($count = 0; $count < $size; $count++) { + $value *= 256; + $value += ord($stream[$offset + $count]); + } + + return $value; + } + + + + /** + * Set current context + * + * @param Zend_Pdf_Element_Reference_Context $context + */ + public function setContext(Zend_Pdf_Element_Reference_Context $context) + { + $this->_context = $context; + } + + /** + * Object constructor + * + * Note: PHP duplicates string, which is sent by value, only of it's updated. + * Thus we don't need to care about overhead + * + * @param string $pdfString + * @param Zend_Pdf_ElementFactory_Interface $factory + */ + public function __construct($source, Zend_Pdf_ElementFactory_Interface $factory) + { + $this->data = $source; + $this->_objFactory = $factory; + } +} diff --git a/library/Zend/Pdf/Style.php b/library/Zend/Pdf/Style.php new file mode 100644 index 0000000..746ff01 --- /dev/null +++ b/library/Zend/Pdf/Style.php @@ -0,0 +1,294 @@ +_fillColor = $anotherStyle->_fillColor; + $this->_color = $anotherStyle->_color; + $this->_lineWidth = $anotherStyle->_lineWidth; + $this->_lineDashingPattern = $anotherStyle->_lineDashingPattern; + $this->_lineDashingPhase = $anotherStyle->_lineDashingPhase; + $this->_font = $anotherStyle->_font; + $this->_fontSize = $anotherStyle->_fontSize; + } + } + + + /** + * Set fill color. + * + * @param Zend_Pdf_Color $color + */ + public function setFillColor(Zend_Pdf_Color $color) + { + $this->_fillColor = $color; + } + + /** + * Set line color. + * + * @param Zend_Pdf_Color $color + */ + public function setLineColor(Zend_Pdf_Color $color) + { + $this->_color = $color; + } + + /** + * Set line width. + * + * @param float $width + */ + public function setLineWidth($width) + { + // require_once 'Zend/Pdf/Element/Numeric.php'; + $this->_lineWidth = new Zend_Pdf_Element_Numeric($width); + } + + + /** + * Set line dashing pattern + * + * @param array $pattern + * @param float $phase + */ + public function setLineDashingPattern($pattern, $phase = 0) + { + // require_once 'Zend/Pdf/Page.php'; + if ($pattern === Zend_Pdf_Page::LINE_DASHING_SOLID) { + $pattern = array(); + $phase = 0; + } + + // require_once 'Zend/Pdf/Element/Numeric.php'; + $this->_lineDashingPattern = $pattern; + $this->_lineDashingPhase = new Zend_Pdf_Element_Numeric($phase); + } + + + /** + * Set current font. + * + * @param Zend_Pdf_Resource_Font $font + * @param float $fontSize + */ + public function setFont(Zend_Pdf_Resource_Font $font, $fontSize) + { + $this->_font = $font; + $this->_fontSize = $fontSize; + } + + /** + * Modify current font size + * + * @param float $fontSize + */ + public function setFontSize($fontSize) + { + $this->_fontSize = $fontSize; + } + + /** + * Get fill color. + * + * @return Zend_Pdf_Color|null + */ + public function getFillColor() + { + return $this->_fillColor; + } + + /** + * Get line color. + * + * @return Zend_Pdf_Color|null + */ + public function getLineColor() + { + return $this->_color; + } + + /** + * Get line width. + * + * @return float + */ + public function getLineWidth() + { + return $this->_lineWidth->value; + } + + /** + * Get line dashing pattern + * + * @return array + */ + public function getLineDashingPattern() + { + return $this->_lineDashingPattern; + } + + + /** + * Get current font. + * + * @return Zend_Pdf_Resource_Font $font + */ + public function getFont() + { + return $this->_font; + } + + /** + * Get current font size + * + * @return float $fontSize + */ + public function getFontSize() + { + return $this->_fontSize; + } + + /** + * Get line dashing phase + * + * @return float + */ + public function getLineDashingPhase() + { + return $this->_lineDashingPhase->value; + } + + + /** + * Dump style to a string, which can be directly inserted into content stream + * + * @return string + */ + public function instructions() + { + $instructions = ''; + + if ($this->_fillColor !== null) { + $instructions .= $this->_fillColor->instructions(false); + } + + if ($this->_color !== null) { + $instructions .= $this->_color->instructions(true); + } + + if ($this->_lineWidth !== null) { + $instructions .= $this->_lineWidth->toString() . " w\n"; + } + + if ($this->_lineDashingPattern !== null) { + // require_once 'Zend/Pdf/Element/Array.php'; + $dashPattern = new Zend_Pdf_Element_Array(); + + // require_once 'Zend/Pdf/Element/Numeric.php'; + foreach ($this->_lineDashingPattern as $dashItem) { + $dashElement = new Zend_Pdf_Element_Numeric($dashItem); + $dashPattern->items[] = $dashElement; + } + + $instructions .= $dashPattern->toString() . ' ' + . $this->_lineDashingPhase->toString() . " d\n"; + } + + return $instructions; + } + +} diff --git a/library/Zend/Pdf/Target.php b/library/Zend/Pdf/Target.php new file mode 100644 index 0000000..0cb984c --- /dev/null +++ b/library/Zend/Pdf/Target.php @@ -0,0 +1,76 @@ +getType() == Zend_Pdf_Element::TYPE_DICTIONARY) { + if (($resource->Type === null || $resource->Type->value =='Action') && $resource->S !== null) { + // It's a well-formed action, load it + // require_once 'Zend/Pdf/Action.php'; + return Zend_Pdf_Action::load($resource); + } else if ($resource->D !== null) { + // It's a destination + $resource = $resource->D; + } else { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Wrong resource type.'); + } + } + + if ($resource->getType() == Zend_Pdf_Element::TYPE_ARRAY || + $resource->getType() == Zend_Pdf_Element::TYPE_NAME || + $resource->getType() == Zend_Pdf_Element::TYPE_STRING) { + // Resource is an array, just treat it as an explicit destination array + // require_once 'Zend/Pdf/Destination.php'; + return Zend_Pdf_Destination::load($resource); + } else { + // require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception( 'Wrong resource type.' ); + } + } + + /** + * Get resource + * + * @internal + * @return Zend_Pdf_Element + */ + abstract public function getResource(); +} diff --git a/library/Zend/Pdf/Trailer.php b/library/Zend/Pdf/Trailer.php new file mode 100644 index 0000000..c4c3e23 --- /dev/null +++ b/library/Zend/Pdf/Trailer.php @@ -0,0 +1,126 @@ +_dict = $dict; + + foreach ($this->_dict->getKeys() as $dictKey) { + $this->_checkDictKey($dictKey); + } + } + + /** + * Get handler + * + * @param string $property + * @return mixed + */ + public function __get($property) + { + return $this->_dict->$property; + } + + /** + * Set handler + * + * @param string $property + * @param mixed $value + */ + public function __set($property, $value) + { + $this->_checkDictKey($property); + $this->_dict->$property = $value; + } + + /** + * Return string trailer representation + * + * @return string + */ + public function toString() + { + return "trailer\n" . $this->_dict->toString() . "\n"; + } + + + /** + * Get length of source PDF + * + * @return string + */ + abstract public function getPDFLength(); + + /** + * Get PDF String + * + * @return string + */ + abstract public function getPDFString(); + + /** + * Get header of free objects list + * Returns object number of last free object + * + * @return integer + */ + abstract public function getLastFreeObject(); +} diff --git a/library/Zend/Pdf/Trailer/Generator.php b/library/Zend/Pdf/Trailer/Generator.php new file mode 100644 index 0000000..535605e --- /dev/null +++ b/library/Zend/Pdf/Trailer/Generator.php @@ -0,0 +1,77 @@ +_context = $context; + $this->_prev = $prev; + } + + /** + * Setter for $this->_prev + * + * @param Zend_Pdf_Trailer_Keeper $prev + */ + public function setPrev(Zend_Pdf_Trailer_Keeper $prev) + { + $this->_prev = $prev; + } + + /** + * Getter for $this->_prev + * + * @return Zend_Pdf_Trailer + */ + public function getPrev() + { + return $this->_prev; + } + + /** + * Get length of source PDF + * + * @return string + */ + public function getPDFLength() + { + return $this->_context->getParser()->getLength(); + } + + /** + * Get PDF String + * + * @return string + */ + public function getPDFString() + { + return $this->_context->getParser()->getString(); + } + + /** + * Get reference table, which corresponds to the trailer. + * Proxy to the $_context member methad call + * + * @return Zend_Pdf_Element_Reference_Context + */ + public function getRefTable() + { + return $this->_context->getRefTable(); + } + + /** + * Get header of free objects list + * Returns object number of last free object + * + * @throws Zend_Pdf_Exception + * @return integer + */ + public function getLastFreeObject() + { + try { + $this->_context->getRefTable()->getNextFree('0 65535 R'); + } catch (Zend_Pdf_Exception $e) { + if ($e->getMessage() == 'Object not found.') { + /** + * Here is work around for some wrong generated PDFs. + * We have not found reference to the header of free object list, + * thus we treat it as there are no free objects. + */ + return 0; + } + + throw new Zend_Pdf_Exception($e->getMessage(), $e->getCode(), $e); + } + } +} diff --git a/library/Zend/Pdf/UpdateInfoContainer.php b/library/Zend/Pdf/UpdateInfoContainer.php new file mode 100644 index 0000000..19d79f3 --- /dev/null +++ b/library/Zend/Pdf/UpdateInfoContainer.php @@ -0,0 +1,131 @@ +_objNum = $objNum; + $this->_genNum = $genNum; + $this->_isFree = $isFree; + + if ($dump !== null) { + if (strlen($dump) > 1024) { + // require_once 'Zend/Pdf.php'; + $this->_dump = Zend_Pdf::getMemoryManager()->create($dump); + } else { + $this->_dump = $dump; + } + } + } + + + /** + * Get object number + * + * @return integer + */ + public function getObjNum() + { + return $this->_objNum; + } + + /** + * Get generation number + * + * @return integer + */ + public function getGenNum() + { + return $this->_genNum; + } + + /** + * Check, that object is free + * + * @return boolean + */ + public function isFree() + { + return $this->_isFree; + } + + /** + * Get string representation of the object + * + * @return string + */ + public function getObjectDump() + { + if ($this->_dump === null) { + return ''; + } + + if (is_string($this->_dump)) { + return $this->_dump; + } + + return $this->_dump->getRef(); + } +} +