Coder Social home page Coder Social logo

pdf-class-raku's Introduction

[Raku PDF Project] / PDF

Actions Status

PDF-raku

Overview

This is a low-level Raku module for accessing and manipulating data from PDF documents.

It presents a seamless view of the data in PDF or FDF documents; behind the scenes handling indexing, compression, encryption, fetching of indirect objects and unpacking of object streams. It is capable of reading, editing and creation or incremental update of PDF files.

This module understands physical data structures rather than the logical document structure. It is primarily intended as base for higher level modules; or to explore or patch data in PDF or FDF files.

It is possible to construct basic documents and perform simple edits by direct manipulation of PDF data. This requires some knowledge of how PDF documents are structured. Please see 'The Basics' and 'Recommended Reading' sections below.

Classes/roles in this module include:

  • PDF - PDF document root (trailer)
  • PDF::IO::Reader - for indexed random access to PDF files
  • PDF::IO::Filter - a collection of standard PDF decoding and encoding tools for PDF data streams
  • PDF::IO::IndObj - base class for indirect objects
  • PDF::IO::Serializer - data marshalling utilities for the preparation of full or incremental updates
  • PDF::IO::Crypt - decryption / encryption
  • PDF::IO::Writer - for the creation or update of PDF files
  • PDF::COS - Raku Bindings to PDF objects [Carousel Object System, see COS]

Example Usage

To create a one page PDF that displays 'Hello, World!'.

#!/usr/bin/env raku
# creates examples/helloworld.pdf
use PDF;
use PDF::COS::Name;
use PDF::COS::Dict;
use PDF::COS::Stream;
use PDF::COS::Type::Info;

sub prefix:</>($s) { PDF::COS::Name.COERCE($s) };

# construct a simple PDF document from scratch
my PDF $pdf .= new;
my PDF::COS::Dict $catalog = $pdf.Root = { :Type(/'Catalog') };

my @MediaBox  = 0, 0, 250, 100;

# define font /F1 as core-font Helvetica
my %Resources = :Procset[ /'PDF', /'Text'],
                :Font{
                    :F1{
                        :Type(/'Font'),
                        :Subtype(/'Type1'),
                        :BaseFont(/'Helvetica'),
                        :Encoding(/'MacRomanEncoding'),
                    },
                };

my PDF::COS::Dict $page-index = $catalog<Pages> = { :Type(/'Pages'), :@MediaBox, :%Resources, :Kids[], :Count(0) };
# add some standard metadata
my PDF::COS::Type::Info $info = $pdf.Info //= {};
$info.CreationDate = DateTime.now;
$info.Producer = "Raku PDF";

# define some basic content
my PDF::COS::Stream() $Contents = { :decoded("BT /F1 24 Tf  15 25 Td (Hello, world!) Tj ET" ) };

# create a new page. add it to the page tree
$page-index<Kids>.push: { :Type(/'Page'), :Parent($page-index), :$Contents };
$page-index<Count>++;

# save the PDF to a file
$pdf.save-as: 'examples/helloworld.pdf';

example.pdf

Then to update the PDF, adding another page:

#!/usr/bin/env raku
use PDF;
use PDF::COS::Stream;
use PDF::COS::Type::Info;

my PDF $pdf .= open: 'examples/helloworld.pdf';

# locate the document root and page tree
my $catalog = $pdf<Root>;
my $Parent = $catalog<Pages>;

# create additional content, use existing font /F1
my PDF::COS::Stream() $Contents = { :decoded("BT /F1 16 Tf  15 25 Td (Goodbye for now!) Tj ET" ) };

# create a new page. add it to the page-tree
$Parent<Kids>.push: { :Type( :name<Page> ), :$Parent, :$Contents };
$Parent<Count>++;

# update or create document metadata. set modification date
my PDF::COS::Type::Info $info = $pdf.Info //= {};
$info.ModDate = DateTime.now;

# incrementally update the existing PDF
$pdf.update;

example.pdf

Description

A PDF file consists of data structures, including dictionaries (hashes) arrays, numbers and strings, plus streams for holding graphical data such as images, fonts and general content.

PDF files are also indexed for random access and may also have internal compression and/or encryption.

They have a reasonably well specified structure. The document starts from the Root entry in the trailer dictionary, which is the main entry point into a PDF.

This module is based on the PDF 32000-1:2008 1.7 specification. It implements syntax, basic data-types, serialization and encryption rules as described in the first four chapters of the specification. Read and write access to data structures is via direct manipulation of tied arrays and hashes.

The Basics

The examples/helloworld.pdf file that we created above contains:

%PDF-1.3
%...(control characters)
1 0 obj <<
  /CreationDate (D:20151225000000Z00'00')
  /Producer (Raku PDF)
>>
endobj

2 0 obj <<
  /Type /Catalog
  /Pages 3 0 R
>>
endobj

3 0 obj <<
  /Type /Pages
  /Count 1
  /Kids [ 4 0 R ]
  /MediaBox [ 0 0 250 100 ]
  /Resources <<
    /Font <<
      /F1 6 0 R
    >>
    /Procset [ /PDF /Text ]
  >>
>>
endobj

4 0 obj <<
  /Type /Page
  /Contents 5 0 R
  /Parent 3 0 R
>>
endobj

5 0 obj <<
  /Length 44
>> stream
BT /F1 24 Tf  15 25 Td (Hello, world!) Tj ET
endstream
endobj

6 0 obj <<
  /Type /Font
  /Subtype /Type1
  /BaseFont /Helvetica
  /Encoding /MacRomanEncoding
>>
endobj

xref
0 7
0000000000 65535 f 
0000000014 00000 n 
0000000101 00000 n 
0000000155 00000 n 
0000000334 00000 n 
0000000404 00000 n 
0000000501 00000 n 
trailer
<<
  /ID [ <d743a886fcdcf87b69c36548219ea941> <d743a886fcdcf87b69c36548219ea941> ]
  /Info 1 0 R
  /Root 2 0 R
  /Size 7
>>
startxref
610
%%EOF

The PDF is composed of a series indirect objects, for example, the first object is:

1 0 obj <<
  /CreationDate (D:20151225000000Z00'00')
  /Producer (Raku PDF)
>> endobj

It's an indirect object with object number 1 and generation number 0, with a << ... >> delimited dictionary containing the author and the date that the document was created. This PDF dictionary is roughly equivalent to the Raku hash:

{ :CreationDate("D:20151225000000Z00'00'"), :Producer("Raku PDF"), }

The bottom of the PDF contains:

trailer
<<
  /ID [ <d743a886fcdcf87b69c36548219ea941> <d743a886fcdcf87b69c36548219ea941> ]
  /Info 1 0 R
  /Root 2 0 R
  /Size 7
>>
startxref
610
%%EOF

The << ... >> delimited section is the trailer dictionary and the main entry point into the document. The entry /Info 1 0 R is an indirect reference to the first object (object number 1, generation 0) described above. The entry /Root 2 0 R points the root of the actual PDF document, commonly known as the Document Catalog.

Immediately above the trailer is the cross reference table:

xref
0 7
0000000000 65535 f 
0000000014 00000 n 
0000000101 00000 n 
0000000155 00000 n 
0000000334 00000 n 
0000000404 00000 n 
0000000501 00000 n 

This indexes the indirect objects in the PDF by byte offset (generation number) for random access.

We can quickly put PDF to work using the Raku REPL, to better explore the document:

snoopy: ~/git/PDF-raku $ raku -M PDF
> my $pdf = PDF.open: "examples/helloworld.pdf"
ID => [CÜ{ÃHADCN:C CÜ{ÃHADCN:C], Info => ind-ref => [1 0], Root => ind-ref => [2 0]
> $pdf.keys
(Root Info ID)

This is the root of the PDF, loaded from the trailer dictionary

> $pdf<Info>
{CreationDate => D:20151225000000Z00'00', ModDate => D:20151225000000Z00'00', Producer => Raku PDF}

That's the document information entry, commonly used to store basic meta-data about the document.

(PDF::IO has conveniently fetched indirect object 1 from the PDF, when we dereferenced this entry).

> $pdf<Root>
{Pages => ind-ref => [3 0], Type => Catalog}

The trailer Root entry references the document catalog, which contains the actual PDF content. Exploring further; the catalog potentially contains a number of pages, each with content.

> $pdf<Root><Pages>
{Count => 1, Kids => [ind-ref => [4 0]], MediaBox => [0 0 420 595], Resources => Font => F1 => ind-ref => [6 0], Type => Pages}
> $pdf<Root><Pages><Kids>[0]
{Contents => ind-ref => [5 0], Parent => ind-ref => [3 0], Type => Page}
> $pdf<Root><Pages><Kids>[0]<Contents>
{Length => 44}
"BT /F1 24 Tf  15 25 Td (Hello, world!) Tj ET"

The page /Contents entry is a PDF stream which contains graphical instructions. In the above example, to output the text Hello, world! at coordinates 100, 250.

Reading and Writing of PDF files:

PDF is a base class for opening or creating PDF documents.

  • my $pdf = PDF.open("mydoc.pdf" :repair) Opens an input PDF (or FDF) document.

    • :!repair causes the read to load only the trailer dictionary and cross reference tables from the tail of the PDF (Cross Reference Table or a PDF 1.5+ Stream). Remaining objects will be lazily loaded on demand.
    • :repair causes the reader to perform a full scan, ignoring and recalculating the cross reference stream/index and stream lengths. This can be handy if the PDF document has been hand-edited.
  • $pdf.update This performs an incremental update to the input pdf, which must be indexed PDF (not applicable to PDFs opened with :repair, FDF or JSON files). A new section is appended to the PDF that contains only updated and newly created objects. This method can be used as a fast and efficient way to make small updates to a large existing PDF document.

    • :diffs(IO::Handle $fh) - saves just the updates to an alternate location. This can be later appended to the base PDF to reproduce the updated PDF.
  • $pdf.save-as("mydoc-2.pdf", :compress, :stream, :preserve, :rebuild) Saves a new document, including any updates. Options:

    • :compress - compress objects for minimal size
    • :!compress - uncompress objects for human readability
    • :stream - write the PDF progressively
    • :preserve - copy the input PDF, then incrementally update. This is generally faster and ensures that any digital signatures are not invalidated,
    • :rebuild - discard any unreferenced objects. renumber remaining objects. It may be a good idea to rebuild a PDF Document, that's been incrementally updated a number of times.

Note that the :compress and :rebuild options are a trade-off. The document may take longer to save, however file-sizes and the time needed to reopen the document may improve.

  • $pdf.save-as("mydoc.json", :compress, :rebuild); my $pdf2 = $pdf.open: "mydoc.json" Documents can also be saved and opened from an intermediate JSON representation. This can be handy for debugging, analysis and/or ad-hoc patching of PDF files.

Reading PDF Files

The .open method loads a PDF index (cross reference table and/or stream). The document can then be access randomly via the .ind.obj(...) method.

The document can be traversed by dereferencing Array and Hash objects. The reader will load indirect objects via the index, as needed.

use PDF::IO::Reader;
use PDF::COS::Name;

my PDF::IO::Reader $reader .= new;
$reader.open: 'examples/helloworld.pdf';

# objects can be directly fetched by object-number and generation-number:
my $page1 = $reader.ind-obj(4, 0).object;

# Hashes and arrays are tied. This is usually more convenient for navigating
my $pdf = $reader.trailer<Root>;
$page1 = $pdf<Pages><Kids>[0];

# Tied objects can also be updated directly.
$reader.trailer<Info><Creator> = PDF::COS::Name.COERCE: 't/helloworld.t';

Utility Scripts

  • pdf-rewriter.raku [--repair] [--rebuild] [--stream] [--[/]compress] [--password=Xxx] [--decrypt] [--class=Module] [--render] <pdf-or-json-file-in> [<pdf-or-json-file-out>] This script is a thin wrapper for the PDF .open and .save-as methods. It can typically be used to:
    • uncompress or render a PDF for human readability
    • repair a PDF who's cross-reference index or stream lengths have become invalid
    • convert between PDF and JSON

Decode Filters

Filters are used to compress or decompress stream data in objects of type PDF::COS::Stream. These are implemented as follows:

Filter Name Short Name Filter Class
ASCIIHexDecode AHx PDF::IO::Filter::ASCIIHex
ASCII85Decode A85 PDF::IO::Filter::ASCII85
CCITTFaxDecode CCF NYI
Crypt NYI
DCTDecode DCT NYI
FlateDecode Fl PDF::IO::Filter::Flate
LZWDecode LZW PDF::IO::Filter::LZW (decode only)
JBIG2Decode NYI
JPXDecode NYI
RunLengthDecode RL PDF::IO::Filter::RunLength

Input to all filters is byte strings, with characters in the range \x0 ... \0xFF. latin-1 encoding is recommended to enforce this.

Each filter has encode and decode methods, which accept and return latin-1 encoded strings, or binary blobs.

my Blob $encoded = PDF::IO::Filter.encode( :dict{ :Filter<RunLengthDecode> },
                                      "This    is waaay toooooo loooong!");
say $encoded.bytes;

Encryption

PDF::IO::Crypt supports RC4 and AES encryption (revisions /R 2 - 4 and versions /V 1 - 4 of PDF Encryption).

To open an encrypted PDF document, specify either the user or owner password: PDF.open( "enc.pdf", :password<ssh!>)

A document can be encrypted using the encrypt method: $pdf.encrypt( :owner-pass<ssh1>, :user-pass<abc>, :aes )

  • :aes encrypts the document using stronger V4 AES encryption, introduced with PDF 1.6.

Note that it's quite common to leave the user-password blank. This indicates that the document is readable by anyone, but may have restrictions on update, printing or copying of the PDF.

An encrypted PDF can be saved as JSON. It will remain encrypted and passwords may be required, to reopen it.

Built-in objects

PDF::COS also provides a few essential derived classes, that are needed read and write PDF files, including encryption, object streams and cross reference streams.

Class Base Class Description
PDF PDF::COS::Dict document entry point - the trailer dictionary
PDF::COS::Type::Encrypt PDF::COS::Dict PDF Encryption/Permissions dictionary
PDF::COS::Type::Info PDF::COS::Dict Document Information Dictionary
PDF::COS::Type::ObjStm PDF::COS::Stream PDF 1.5+ Object stream (packed indirect objects)
PDF::COS::Type::XRef PDF::COS::Stream PDF 1.5+ Cross Reference stream
PDF::COS::TextString PDF::COS::ByteString Implements the 'text-string' data-type

Further Reading

  • PDF Explained By John Whitington (120pp) - Offers an excellent overview of the PDF format.
  • PDF 32000-1:2008 1.7 specification - This is the main reference used in the construction of this module.

See also

  • PDF::Lite - basic graphics; including images, fonts, text and general graphics
  • PDF::API6 - general purpose PDF manipulation (under construction)

pdf-class-raku's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

pdf-class-raku's Issues

todo mine the PDF 32000 specification

I suspect that much of the material has been indirectly or directly produced from Adobe's internal data dictionaries and accurately represents the internal structure, as represented by the Adobe suite.

I've been manually constructing classes from the spec (which is what everyone seems to do); but a structured dump of the object definitions would greatly assist with checking the classes built so far, and with the completion of PDF::Class.

Hopefully achievable with the tools built to date. For example, both pdf-checker.p6 and pdf-toc.p6 are capable of scanning the specification PDF.

Dumping the tables in PDF Spec to JSON or some-such would be a big help. These seem to be reasonable well defined as such via the documents struct tree root.

Trailer dict not serializing indirect objects

E.g. from t/helloworld.pdf:

<< /Info << /Author (t/helloworld.t) /Creator (PDF::Tools) >> /Root 1 0 R /Size 10 >>
startxref
10416
%%EOF

Info entry is wrong. PDF spec says that it must be an indirect object.

This module has gone Glacial - on the back-burner

This module was mostly built using the pre 2016 ufo build-tool, which is no longer available.

It's now reliant on rakudo 2016.xx precompilation, which isn't yet fast to load or run. Now takes quite a few minutes to run the test-suite, with most of the time spent in precompilation and/or loading.

At this stage, I'm only regressing this module occasionally. There doesn't seem to be a fair bit of scope for optimization both in rakudo and within this module. May look at this again towards the end of 2016 or early in 2017.

Convert PDF::DOM::* to roles. Simplify PDF::DOM::Delegator and PDF::Reader interface

Currently, the PDF::Reader.ind-obj method fully realizes DOM objects using an unnecessary and convoluted callback mechanism. This is currently needed to ensure objects are stantiated to the correct type.

But if all of PDF::DOM classes are converted to roles, We can then simply subclass the ind-obj method then apply the roles at run-time. Simpler, more conventional and easier to extend.

core fonts and single byte encodings - not a comfortable fit

The plan is to encode core fonts using single byte encodings. To this end, Font::AFM calculates string-widths for a 0..255 (latin1) subset only.

The core fonts use an ExtendedRoman character set, which goes well past this. Consider:

% perl6 -MFont::Metrics::helvetica-bold -M Font::AFM -e 'my $hb = Font::Metrics::helvetica-bold.new; say $hb.Wx.keys (-) @Font::AFM::ISOLatin1Encoding'
set(Kcommaaccent, OE, guilsinglright, Umacron, radical, Sacute, oe, ecaron, dcaron, ohungarumlaut, perthousand, amacron, dagger, Nacute, Tcaron, notequal, lslash, quotesinglbase, Dcroat, lacute, fi, cacute, Ecaron, ncommaaccent, Zacute, umacron, ccaron, Aogonek, ncaron, zacute, nacute, summation, Amacron, Ncommaaccent, Ccaron, florin, lozenge, abreve, emdash, sacute, commaaccent, Emacron, scaron, endash, partialdiff, Ohungarumlaut, ellipsis, Rcaron, quotedblleft, zdotaccent, zcaron, Rcommaaccent, Lacute, scedilla, Ydieresis, fl, quotedblbase, Scaron, uring, edotaccent, omacron, tcaron, Zcaron, Omacron, Edotaccent, Racute, Euro, uhungarumlaut, racute, guilsinglleft, aogonek, lcaron, lessequal, greaterequal, tcommaaccent, rcommaaccent, gbreve, dcroat, Uogonek, Uhungarumlaut, Tcommaaccent, Zdotaccent, Lcommaaccent, Uring, trademark, Delta, Scedilla, emacron, imacron, Dcaron, Lcaron, Scommaaccent, Imacron, Lslash, Gcommaaccent, Cacute, Gbreve, quotesingle, gcommaaccent, Idotaccent, fraction, bullet, Ncaron, Eogonek, eogonek, quotedblright, lcommaaccent, iogonek, rcaron, kcommaaccent, scommaaccent, Iogonek, daggerdbl, Abreve, uogonek)

That's an extra 115 glyphs that fall outside of the latin-1 subset.

Will need a solution in the long term. I'm not sure if there's a nicer solution than moving to Identity-H.

Handle 'must be indirect reference' constraints in spec

A generic mechanism may be necessary to handle the 'must be an indirect reference; constraint on certain entries. For example the threads entry in the Catalog object see [PDF 1.7 TABLE 3.25 Entries in the catalog dictionary].

Most likely the entry trait (Dictionaries) and index trait Arrays needs an additional :ind-ref argument that is somehow interpreted during Dict/Array ast constructuions and/or passed-through to the serializer. so that it 'knows' to construct an indirect object.

Rely a lot more on PDF::Type::Delegator autoloading

It currently takes a long time for perl6 -I PDF -e0

A lot of classes are being eagerly loaded via use statements.

At this stage, at least, it may make sense to make greater use of PDF::Type::Delegator to autoload these classes, on demand, when needed.

todo build class documenter tool

Write a script that traverses the PDF::Class document hierarchy and automatically generates documentation and a representation of the Zen object tree.

Could be it outputs markdown or html for publication.

Additional actions modelling is incorrect

PDF::Class currently has just PDF::AdditionalActions (based on Table 194), but there are actually 4 types Table 194 Annotation, 195 Page , 196 Form and 197 Catalog

Error Converting Int to UInt

I have a script that uses PDF::API6 to extract pages from a larger PDF. For one particular file I'm getting an endless series of errors about coercing Int to UInt. when I run pdf-checker --repair here is what the errors look like

Warning: unable to coerce object -167 of type Int to UInt
Warning: unable to coerce object -167 of type Int to UInt
Error in 4649 0 R (PDF::Annot::Link) /StructParent entry: Int.StructParent: -167 not of type: UInt

It seems that coercing an Int to a UInt is something that should be easy.
I upgraded to the latest modules available with not change.
I'm running Ubuntu Linux 20.04.5

/Resources entry placed in /Pages not /Page

A bit of an anomaly w.r.t to PDF::Lite, for example t/helloword.pdf has '<< /Type /Pages /Resources <<...>> >>' in the page tree, not at the page-level. Other PDF's similarly affected.

precompilation fragilities

There's a few work arounds in the test suite.

In particular some of the tests have use PDF::Content::Util::TransformMatrix, prior to use PDF.

If they don't, dies as follows:

% perl6 -I lib t/helloworld.t
t/helloworld.t .. 
ok 1 - MediaBox bad setter - dies
ok 2 - MediaBox bad setter - ignored
ok 3 - The object is-a 'PDF::Content::Text::Block'
ok 4 - The object is-a 'PDF::Content::Text::Block'
ok 5 - The object is-a 'PDF::Content::Text::Block'
ok 6 - $img.Width
Cannot invoke this object (REPR: Null; VMNull)
  in sub multiply at /home/david/git/perl6-PDF/../perl6-PDF-Content/lib/PDF/Content/Util/TransformMatrix.pm (PDF::Content::Util::TransformMatrix) line 44
  in method track-graphics at /home/david/git/perl6-PDF/../perl6-PDF-Content/lib/PDF/Content/Ops.pm (PDF::Content::Ops) line 706
  in method op at /home/david/git/perl6-PDF/../perl6-PDF-Content/lib/PDF/Content/Ops.pm (PDF::Content::Ops) line 639
  in method do at /home/david/git/perl6-PDF/../perl6-PDF-Content/lib/PDF/Content.pm (PDF::Content) line 187
  in block  at t/helloworld.t line 58
  in method graphics at /home/david/git/perl6-PDF/../perl6-PDF-Content/lib/PDF/Content.pm (PDF::Content) line 51
  in method graphics at /home/david/git/perl6-PDF/../perl6-PDF-Content/lib/PDF/Content/Graphics.pm (PDF::Content::Graphics) line 49
  in block <unit> at t/helloworld.t line 22

I've also had to make some adjustments in PDF::Content::Op, which requires rather than using PDF::Content::Util::TransformMatrix.

Not sure why a simple dependency-fee set of functions is causing such mayhem.

Error during installation (testing phase)

Hello,
I'm trying to upgrade this module, because I have an error message processing some PDF files using PDF::API6:
Probable version skew in pre-compiled [...] (PDF::Font)' (cause: no object at index 776)
But I'm getting this error during the testing phase:

$ zef install 'PDF::Class:ver<0.1.2>'
===> Searching for: PDF::Class
===> Testing: PDF::Class:ver<0.1.2>:auth<github:p6-pdf>:api<PDF-1.7>
eval error:     use PDF::Class;
    use PDF::Catalog;
    my PDF::Class $pdf .= new;

    my PDF::Catalog $doc = $pdf.catalog;
    try {
        $doc.PageMode   = 'UseToes';
        CATCH { default { say "err, that didn't work: $_" } }
    }

    # same again, bypassing type checking
    $doc<PageMode>  = :name<UseToes>;

  in block  at t/00-readme.t line 25
unknown /ShadingType 42 - supported range is 1..7
No Doc handler class [PDF PDF::COS::Type]::Unknown
No Doc handler class [PDF PDF::COS::Type]::Annot::Caret
Probable version skew in pre-compiled '/home/nando/.zef/store/PDF-Class-0.1.2.tar.gz/PDF-Class-0.1.2/lib/PDF/OutputIntent.pm (PDF::OutputIntent)' (cause: no object at index 776)
  in method find-delegate at /home/nando/.zef/store/PDF-Class-0.1.2.tar.gz/PDF-Class-0.1.2/lib/PDF/Class/Loader.pm (PDF::Class::Loader) line 32
  in method load-delegate at /home/nando/.zef/store/PDF-Class-0.1.2.tar.gz/PDF-Class-0.1.2/lib/PDF/Class/Loader.pm (PDF::Class::Loader) line 105
  in block <unit> at t/load-delegate.t line 23

# Looks like you planned 18 tests, but ran 11
===> Testing [FAIL]: PDF::Class:ver<0.1.2>:auth<github:p6-pdf>:api<PDF-1.7>
Aborting due to test failure: PDF::Class:ver<0.1.2>:auth<github:p6-pdf>:api<PDF-1.7> (use --force-test to override)
  in code  at /opt/rakudo-pkg/share/perl6/sources/8244C3B17ACA61B0EC04857BB3283A8FAF7A186D (Zef::Client) line 374
  in method test at /opt/rakudo-pkg/share/perl6/sources/8244C3B17ACA61B0EC04857BB3283A8FAF7A186D (Zef::Client) line 354
  in code  at /opt/rakudo-pkg/share/perl6/sources/8244C3B17ACA61B0EC04857BB3283A8FAF7A186D (Zef::Client) line 523
  in sub  at /opt/rakudo-pkg/share/perl6/sources/8244C3B17ACA61B0EC04857BB3283A8FAF7A186D (Zef::Client) line 520
  in method install at /opt/rakudo-pkg/share/perl6/sources/8244C3B17ACA61B0EC04857BB3283A8FAF7A186D (Zef::Client) line 621
  in sub MAIN at /opt/rakudo-pkg/share/perl6/sources/81436475BD18D66BFD96BBCEE07CCCDC0F368879 (Zef::CLI) line 152
  in block <unit> at /opt/rakudo-pkg/share/perl6/resources/D822DF07A6D5CB602F97ED307F62A1B3B5D2C90D line 3
  in sub MAIN at /opt/rakudo-pkg/bin/zef line 2
  in block <unit> at /opt/rakudo-pkg/bin/zef line 2

I have the following modules installed:

$ zef list --installed|grep PDF
===> Found via /opt/rakudo-pkg/share/perl6
===> Found via /home/nando/.perl6
PDF::API6:ver<0.1.0>:auth<github:p6-pdf>
PDF::Class:ver<0.1.0>:auth<github:p6-pdf>:api<PDF-1.7>
PDF::Content:ver<0.2.1>:auth<github:p6-pdf>:api<PDF-1.7>
PDF::Grammar:ver<0.1.5>:auth<github:p6-pdf>:api<PDF-1.7>
PDF:ver<0.2.8>:auth<github:p6-pdf>:api<PDF-1.7>

and perl6 version is:

perl6 -v
This is Rakudo version 2018.03 built on MoarVM version 2018.03
implementing Perl 6.c.

Script pdf-info throwing exception after pdf-checker reports no error

After pdf-checker.raku --repair myFile.pdf ran and reported "completed with 0 warnings and 0 errors" I tried to display the file info with pdf-info.raku myFile.pdf and got the following error:

Type check failed in assignment to $box; expected List but got Positional[Numeric] (Positional[Numeric])
in sub MAIN at /home/tsalada/rakudo-2020.06/share/perl6/site/resources/564D3C75174AAD1D6ACB041994069B712F6EA8B9 line 51
in block at /home/tsalada/rakudo-2020.06/share/perl6/site/resources/564D3C75174AAD1D6ACB041994069B712F6EA8B9 line 7
in sub MAIN at /home/tsalada/rakudo-2020.06/share/perl6/site/bin/pdf-info.raku line 3
in block at /home/tsalada/rakudo-2020.06/share/perl6/site/bin/pdf-info.raku line 1

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.