c# display pdf in window : Adding a page to a pdf document Library software class asp.net wpf html ajax qpdf-manual2-part512

Design and Library Notes
17
• The parser sees “ “ <<”, so it calls itself recursively in dictionary creation mode.
• In dictionary creation mode, the parser keeps accumulating objects until it encounters “ “ >>”. Each object that is
read is pushed onto a stack. If “ “ R” is read, the last two objects on the stack are inspected. If they are integers,
they are popped off the stack and their values are used to construct an indirect object handle which is then pushed
onto the stack. When “ “ >>” is finally read, the stack is converted into a QPDF_Dictionary which is placed in a
QPDFObjectHandle and returned.
• The resulting dictionary is saved as the trailer dictionary.
The /Prev key is searched. If present, QPDF seeks to that point and repeats except that the new trailer dictionary
is not saved. If /Prev is not present, the initial parsing process is complete.
If there is an encryption dictionary, the document's encryption parameters are initialized.
• The client requests root object. The QPDF class gets the value of root key from trailer dictionary and returns it. It
is an unresolved indirect QPDFObjectHandle.
• The client requests the /Pages key from root QPDFObjectHandle. The QPDFObjectHandle notices that it
is indirect so it asks QPDF to resolve it. QPDF looks in the object cache for an object with the root dictionary's
object ID and generation number. Upon not seeing it, it checks the cross reference table, gets the offset, and reads
the object present at that offset. It stores the result in the object cache and returns the cached result. The calling
QPDFObjectHandle replaces its object pointer with the one from the resolved QPDFObjectHandle, verifies
that it a valid dictionary object, and returns the (unresolved indirect) QPDFObject handle to the top of the Pages
hierarchy.
As the client continues to request objects, the same process is followed for each new requested object.
6.3. Casting Policy
This section describes the casting policy followed by qpdf's implementation. This is no concern to qpdf's end users
and largely of no concern to people writing code that uses qpdf, but it could be of interest to people who are porting
qpdf to a new platform or who are making modifications to the code.
The C++ code in qpdf is free of old-style casts except where unavoidable (e.g. where the old-style cast is in a macro
provided by a third-party header file). When there is a need for a cast, it is handled, in order of preference, by rewriting
the code to avoid the need for a cast, calling const_cast, calling static_cast, calling reinterpret_cast, or calling some
combination of the above. As a last resort, a compiler-specific #pragma may be used to suppress a warning that we
don't want to fix. Examples may include suppressing warnings about the use of old-style casts in code that is shared
between C and C++ code.
The casting policy explicitly prohibits casting between integer sizes for no purpose other than to quiet a compiler
warning when there is no reasonable chance of a problem resulting. The reason for this exclusion is that the practice
of adding these additional casts precludes future use of additional compiler warnings as a tool for making future
improvements to this aspect of the code, and it also damages the readability of the code.
There are a few significant areas where casting is common in the qpdf sources or where casting would be required to
quiet higher levels of compiler warnings but is omitted at present:
• char vs. unsigned char. For historical reasons, there are a lot of places in qpdf's internals that deal with
unsigned char, which means that a lot of casting is required to interoperate with standard library calls and
std::string. In retrospect, qpdf should have probably used regular (signed) char and char* everywhere and
just cast to unsigned char when needed, but it's too late to make that change now. There are reinterpret_cast
calls to go between char* and unsigned char*, and there are static_cast calls to go between char and
unsigned char. These should always be safe.
Adding a page to a pdf document - insert pages into PDF file in C#.net, ASP.NET, MVC, Ajax, WinForms, WPF
Guide C# Users to Insert (Empty) PDF Page or Pages from a Supported File Format
add a page to a pdf in reader; add and delete pages in pdf online
Adding a page to a pdf document - VB.NET PDF Page Insert Library: insert pages into PDF file in vb.net, ASP.NET, MVC, Ajax, WinForms, WPF
Easy to Use VB.NET APIs to Add a New Blank Page to PDF Document
add page number to pdf hyperlink; add pdf pages to word
Design and Library Notes
18
• Non-const unsigned char* used in the Pipeline interface. The pipeline interface has a write call that uses
unsigned char* without a const qualifier. The main reason for this is to support pipelines that make calls to
third-party libraries, such as zlib, that don't include const in their interfaces. Unfortunately, there are many places
in the code where it is desirable to have const char* with pipelines. None of the pipeline implementations in
qpdf currently modify the data passed to write, and doing so would be counter to the intent of Pipeline, but there
is nothing in the code to prevent this from being done. There are places in the code where const_cast is used to
remove the const-ness of pointers going into Pipelines. This could theoretically be unsafe, but there is adequate
testing to assert that it is safe and will remain safe in qpdf's code.
• size_t vs. qpdf_offset_t. This is pretty much unavoidable since sizes are unsigned types and offsets are
signed types. Whenever it is necessary to seek by an amount given by a size_t, it becomes necessary to mix and
match between size_t and qpdf_offset_t. Additionally, qpdf sometimes treats memory buffers like files (as
with BufferInputSource, and those seek interfaces have to be consistent with file-based input sources. Neither
gcc nor MSVC give warnings for this case by default, but both have warning flags that can enable this. (MSVC:
/W14267 or /W3, which also enables some additional warnings that we ignore; gcc: -Wconversion -Wsign-
conversion). This could matter for files whose sizes are larger than 2
63
bytes, but it is reasonable to expect that a
world where such files are common would also have larger size_t and qpdf_offset_t types in it. On most
64-bit systems at the time of this writing (the release of version 4.1.0 of qpdf), both size_t and qpdf_offset_t
are 64-bit integer types, while on many current 32-bit systems, size_t is a 32-bit type while qpdf_offset_t is
a 64-bit type. I am not aware of any cases where 32-bit systems that have size_t smaller than qpdf_offset_t
could run into problems. Although I can't conclusively rule out the possibility of such problems existing, I suspect
any cases would be pretty contrived. In the event that someone should produce a file that qpdf can't handle because
of what is suspected to be issues involving the handling of size_t vs. qpdf_offset_t (such files may behave
properly on 64-bit systems but not on 32-bit systems because they have very large embedded files or streams, for
example), the above mentioned warning flags could be enabled and all those implicit conversions could be carefully
scrutinized. (I have already gone through that exercise once in adding support for files larger than 4 GB in size.) I
continue to be committed to supporting large files on 32-bit systems, but I would not go to any lengths to support
corner cases involving large embedded files or large streams that work on 64-bit systems but not on 32-bit systems
because of size_t being too small. It is reasonable to assume that anyone working with such files would be using
a 64-bit system anyway since many 32-bit applications would have similar difficulties.
• size_t vs. int or long. There are some cases where size_t and int or long or size_t and unsigned
int or unsigned long are used interchangeably. These cases occur when working with very small amounts of
memory, such as with the bit readers (where we're working with just a few bytes at a time), some cases of strlen, and
a few other cases. I have scrutinized all of these cases and determined them to be safe, but there is no mechanism in
the code to ensure that new unsafe conversions between int and size_t aren't introduced short of good testing
and strong awareness of the issues. Again, if any such bugs are suspected in the future, enabling the additional
warning flags and scrutinizing the warnings would be in order.
To be clear, I believe qpdf to be well-behaved with respect to sizes and offsets, and qpdf's test suite includes actual
generation and full processing of files larger than 4 GB in size. The issues raised here are largely academic and should
not in any way be interpreted to mean that qpdf has practical problems involving sloppiness with integer types. I also
believe that appropriate measures have been taken in the code to avoid problems with signed vs. unsigned integers
from resulting in memory overwrites or other issues with potential security implications, though there are never any
absolute guarantees.
6.4. Encryption
Encryption is supported transparently by qpdf. When opening a PDF file, if an encryption dictionary exists, the QPDF
object processes this dictionary using the password (if any) provided. The primary decryption key is computed and
cached. No further access is made to the encryption dictionary after that time. When an object is read from a file, the
object ID and generation of the object in which it is contained is always known. Using this information along with
the stored encryption key, all stream and string objects are transparently decrypted. Raw encrypted objects are never
stored in memory. This way, nothing in the library ever has to know or care whether it is reading an encrypted file.
VB.NET PDF File & Page Process Library SDK for vb.net, ASP.NET
page, you will find detailed guidance on creating, loading, merge and splitting PDF pages and Files, adding a page into PDF document, deleting unnecessary page
add page to pdf; add page to pdf in preview
VB.NET PDF Library SDK to view, edit, convert, process PDF file
Perform annotation capabilities to mark, draw, and visualize objects on PDF document page. Capable of adding PDF file navigation features to your VB.NET program
add a page to a pdf online; add and remove pages from pdf file online
Design and Library Notes
19
An interface is also provided for writing encrypted streams and strings given an encryption key. This is used by
QPDFWriter when it rewrites encrypted files.
When copying encrypted files, unless otherwise directed, qpdf will preserve any encryption in force in the original
file. qpdf can do this with either the user or the owner password. There is no difference in capability based on which
password is used. When 40 or 128 bit encryption keys are used, the user password can be recovered with the owner
password. With 256 keys, the user and owner passwords are used independently to encrypt the actual encryption key,
so while either can be used, the owner password can no longer be used to recover the user password.
Starting with version 4.0.0, qpdf can read files that are not encrypted but that contain encrypted attachments, but it
cannot write such files. qpdf also requires the password to be specified in order to open the file, not just to extract
attachments, since once the file is open, all decryption is handled transparently. When copying files like this while
preserving encryption, qpdf will apply the file's encryption to everything in the file, not just to the attachments. When
decrypting the file, qpdf will decrypt the attachments. In general, when copying PDF files with multiple encryption
formats, qpdf will choose the newest format. The only exception to this is that clear-text metadata will be preserved
as clear-text if it is that way in the original file.
6.5. Random Number Generation
QPDF generates random numbers to support generation of encrypted data. Versions prior to 5.0.1 used random or rand
from stdlib to generate random numbers. Version 5.0.1, if available, used operating system-provided secure random
number generation instead, enabling use of stdlib random number generation only if enabled by a compile-time option.
Starting in version 5.1.0, use of insecure random numbers was disabled unless enabled at compile time. Starting in
version 5.1.0, it is also possible for you to disable use of OS-provided secure random numbers. This is especially
useful on Windows if you want to avoid a dependency on Microsoft's cryptography API. In this case, you must provide
your own random data provider. Regardless of how you compile qpdf, starting in version 5.1.0, it is possible for you
to provide your own random data provider at runtime. This would enable you to use some software-based secure
pseudorandom number generator and to avoid use of whatever the operating system provides. For details on how to
do this, please refer to the top-level README file in the source distribution and to comments in QUtil.hh.
6.6. Adding and Removing Pages
While qpdf's API has supported adding and modifying objects for some time, version 3.0 introduces specific methods
for adding and removing pages. These are largely convenience routines that handle two tricky issues: pushing
inheritable resources from the /Pages tree down to individual pages and manipulation of the /Pages tree itself. For
details, see addPage and surrounding methods in QPDF.hh.
6.7. Reserving Object Numbers
Version 3.0 of qpdf introduced the concept of reserved objects. These are seldom needed for ordinary operations, but
there are cases in which you may want to add a series of indirect objects with references to each other to a QPDF object.
This causes a problem because you can't determine the object ID that a new indirect object will have until you add it to
the QPDF object with QPDF::makeIndirectObject. The only way to add two mutually referential objects to a QPDF
object prior to version 3.0 would be to add the new objects first and then make them refer to each other after adding
them. Now it is possible to create a reserved object using QPDFObjectHandle::newReserved. This is an indirect object
that stays “unresolved” even if it is queried for its type. So now, if you want to create a set of mutually referential
objects, you can create reservations for each one of them and use those reservations to construct the references. When
finished, you can call QPDF::replaceReserved to replace the reserved objects with the real ones. This functionality
will never be needed by most applications, but it is used internally by QPDF when copying objects from other PDF
files, as discussed in Section 6.8, “Copying Objects From Other PDF Files” ” , page 20. For an example of how to
use reserved objects, search for newReserved in test_driver.cc in qpdf's sources.
C# PDF insert image Library: insert images into PDF in C#.net, ASP
image adding library control for PDF document, you can easily and quickly add an image, picture or logo to any position of specified PDF document file page.
add page number to pdf file; add page numbers to a pdf file
C# PDF insert text Library: insert text into PDF content in C#.net
C#.NET PDF SDK - Insert Text to PDF Document in C#.NET. Providing C# Demo Code for Adding and Inserting Text to PDF File Page with .NET PDF Library.
add document to pdf pages; add page number to pdf in preview
Design and Library Notes
20
6.8. Copying Objects From Other PDF Files
Version 3.0 of qpdf introduced the ability to copy objects into a QPDF object from a different QPDF object, which
we refer to as foreign objects. This allows arbitrary merging of PDF files. The qpdf command-line tool provides
limited support for basic page selection, including merging in pages from other files, but the library's API makes
it possible to implement arbitrarily complex merging operations. The main method for copying foreign objects is
QPDF::copyForeignObject. This takes an indirect object from another QPDF and copies it recursively into this object
while preserving all object structure, including circular references. This means you can add a direct object that you
create from scratch to a QPDF object with QPDF::makeIndirectObject, and you can add an indirect object from
another file with QPDF::copyForeignObject. The fact that QPDF::makeIndirectObject does not automatically detect
a foreign object and copy it is an explicit design decision. Copying a foreign object seems like a sufficiently significant
thing to do that it should be done explicitly.
The other way to copy foreign objects is by passing a page from one QPDF to another by calling QPDF::addPage.
In contrast to QPDF::makeIndirectObject, this method automatically distinguishes between indirect objects in the
current file, foreign objects, and direct objects.
6.9. Writing PDF Files
The qpdf library supports file writing of QPDF objects to PDF files through the QPDFWriter class. The
QPDFWriter class has two writing modes: one for non-linearized files, and one for linearized files. See Chapter 7,
Linearization, page 22 for a description of linearization is implemented. This section describes how we write non-
linearized files including the creation of QDF files (see Chapter 4, QDF Mode, page 12.
This outline was written prior to implementation and is not exactly accurate, but it provides a correct “notional” idea
of how writing works. Look at the code in QPDFWriter for exact details.
• Initialize state:
• next object number = 1
• object queue = empty
• renumber table: old object id/generation to new id/0 = empty
• xref table: new id -> offset = empty
• Create a QPDF object from a file.
• Write header for new PDF file.
• Request the trailer dictionary.
• For each value that is an indirect object, grab the next object number (via an operation that returns and increments
the number). Map object to new number in renumber table. Push object onto queue.
• While there are more objects on the queue:
• Pop queue.
• Look up object's new number n in the renumbering table.
• Store current offset into xref table.
• Write n 0 obj.
C# PDF File & Page Process Library SDK for C#.net, ASP.NET, MVC
Provides you with examples for adding an (empty) page to a PDF and adding empty pages to a PDF XDoc.PDF allows you to easily move PDF document pages position
add page numbers to pdf reader; add and remove pages from a pdf
VB.NET PDF insert text library: insert text into PDF content in vb
VB.NET PDF - Insert Text to PDF Document in VB.NET. Providing Demo Code for Adding and Inserting Text to PDF File Page in VB.NET Program.
add page numbers to pdf; add page numbers pdf files
Design and Library Notes
21
• If object is null, whether direct or indirect, write out null, thus eliminating unresolvable indirect object references.
• If the object is a stream stream, write stream contents, piped through any filters as required, to a memory buffer.
Use this buffer to determine the stream length.
• If object is not a stream, array, or dictionary, write out its contents.
• If object is an array or dictionary (including stream), traverse its elements (for array) or values (for dictionaries),
handling recursive dictionaries and arrays, looking for indirect objects. When an indirect object is found, if it is
not resolvable, ignore. (This case is handled when writing it out.) Otherwise, look it up in the renumbering table.
If not found, grab the next available object number, assign to the referenced object in the renumbering table, and
push the referenced object onto the queue. As a special case, when writing out a stream dictionary, replace length,
filters, and decode parameters as required.
Write out dictionary or array, replacing any unresolvable indirect object references with null (pdf spec says
reference to non-existent object is legal and resolves to null) and any resolvable ones with references to the
renumbered objects.
• If the object is a stream, write stream\n, the stream contents (from the memory buffer), and \nendstream\n.
• When done, write endobj.
Once we have finished the queue, all referenced objects will have been written out and all deleted objects or
unreferenced objects will have been skipped. The new cross-reference table will contain an offset for every new object
number from 1 up to the number of objects written. This can be used to write out a new xref table. Finally we can
write out the trailer dictionary with appropriately computed /ID (see spec, 8.3, File Identifiers), the cross reference
table offset, and %%EOF.
6.10. Filtered Streams
Support for streams is implemented through the Pipeline interface which was designed for this package.
When reading streams, create a series of Pipeline objects. The Pipeline abstract base requires implementation write()
and finish() and provides an implementation of getNext(). Each pipeline object, upon receiving data, does whatever it
is going to do and then writes the data (possibly modified) to its successor. Alternatively, a pipeline may be an end-
of-the-line pipeline that does something like store its output to a file or a memory buffer ignoring a successor. For
additional details, look at Pipeline.hh.
QPDF can read raw or filtered streams. When reading a filtered stream, the QPDF class creates a Pipeline object for
one of each appropriate filter object and chains them together. The last filter should write to whatever type of output
is required. The QPDF class has an interface to write raw or filtered stream contents to a given pipeline.
C# PDF Annotate Library: Draw, edit PDF annotation, markups in C#.
text comments on PDF page using C# demo code in Visual Stuodio .NET class. C#.NET: Add Text Box to PDF Document. Provide users with examples for adding text box
add pages to pdf document; add pages to pdf acrobat
C# PDF Library SDK to view, edit, convert, process PDF file for C#
Capable of adding PDF file navigation features to your C# program. Perform annotation capabilities to mark, draw, and visualize objects on PDF document page.
adding pages to a pdf document; add page to pdf preview
22
Chapter 7. Linearization
This chapter describes how QPDF and QPDFWriter implement creation and processing of linearized PDFS.
7.1. Basic Strategy for Linearization
To avoid the incestuous problem of having the qpdf library validate its own linearized files, we have a special linearized
file checking mode which can be invoked via qpdf --check-linearization (or qpdf --check). This mode reads the
linearization parameter dictionary and the hint streams and validates that object ordering, parameters, and hint stream
contents are correct. The validation code was first tested against linearized files created by external tools (Acrobat and
pdlin) and then used to validate files created by QPDFWriter itself.
7.2. Preparing For Linearization
Before creating a linearized PDF file from any other PDF file, the PDF file must be altered such that all page attributes
are propagated down to the page level (and not inherited from parents in the /Pages tree). We also have to know
which objects refer to which other objects, being concerned with page boundaries and a few other cases. We refer to
this part of preparing the PDF file as optimization, discussed in Section 7.3, “Optimization” ” , page 22. Note the, in
this context, the term optimization is a qpdf term, and the term linearization is a term from the PDF specification. Do
not be confused by the fact that many applications refer to linearization as optimization or web optimization.
When creating linearized PDF files from optimized PDF files, there are really only a few issues that need to be dealt
with:
• Creation of hints tables
• Placing objects in the correct order
• Filling in offsets and byte sizes
7.3. Optimization
In order to perform various operations such as linearization and splitting files into pages, it is necessary to know which
objects are referenced by which pages, page thumbnails, and root and trailer dictionary keys. It is also necessary to
ensure that all page-level attributes appear directly at the page level and are not inherited from parents in the pages tree.
We refer to the process of enforcing these constraints as optimization. As mentioned above, note that some applications
refer to linearization as optimization. Although this optimization was initially motivated by the need to create linearized
files, we are using these terms separately.
PDF file optimization is implemented in the QPDF_optimization.cc source file. That file is richly commented and
serves as the primary reference for the optimization process.
After optimization has been completed, the private member variables obj_user_to_objects and object_to_obj_users in
QPDF have been populated. Any object that has more than one value in the object_to_obj_users table is shared. Any
object that has exactly one value in the object_to_obj_users table is private. To find all the private objects in a page or
a trailer or root dictionary key, one merely has make this determination for each element in the obj_user_to_objects
table for the given page or key.
Note that pages and thumbnails have different object user types, so the above test on a page will not include objects
referenced by the page's thumbnail dictionary and nothing else.
Linearization
23
7.4. Writing Linearized Files
We will create files with only primary hint streams. We will never write overflow hint streams. (As of PDF version 1.4,
Acrobat doesn't either, and they are never necessary.) The hint streams contain offset information to objects that point
to where they would be if the hint stream were not present. This means that we have to calculate all object positions
before we can generate and write the hint table. This means that we have to generate the file in two passes. To make
this reliable, QPDFWriter in linearization mode invokes exactly the same code twice to write the file to a pipeline.
In the first pass, the target pipeline is a count pipeline chained to a discard pipeline. The count pipeline simply passes
its data through to the next pipeline in the chain but can return the number of bytes passed through it at any intermediate
point. The discard pipeline is an end of line pipeline that just throws its data away. The hint stream is not written and
dummy values with adequate padding are stored in the first cross reference table, linearization parameter dictionary,
and /Prev key of the first trailer dictionary. All the offset, length, object renumbering information, and anything else
we need for the second pass is stored.
At the end of the first pass, this information is passed to the QPDF class which constructs a compressed hint stream
in a memory buffer and returns it. QPDFWriter uses this information to write a complete hint stream object into a
memory buffer. At this point, the length of the hint stream is known.
In the second pass, the end of the pipeline chain is a regular file instead of a discard pipeline, and we have known values
for all the offsets and lengths that we didn't have in the first pass. We have to adjust offsets that appear after the start of
the hint stream by the length of the hint stream, which is known. Anything that is of variable length is padded, with the
padding code surrounding any writing code that differs in the two passes. This ensures that changes to the way things
are represented never results in offsets that were gathered during the first pass becoming incorrect for the second pass.
Using this strategy, we can write linearized files to a non-seekable output stream with only a single pass to disk or
wherever the output is going.
7.5. Calculating Linearization Data
Once a file is optimized, we have information about which objects access which other objects. We can then process
these tables to decide which part (as described in “Linearized PDF Document Structure” in the PDF specification)
each object is contained within. This tells us the exact order in which objects are written. The QPDFWriter class
asks for this information and enqueues objects for writing in the proper order. It also turns on a check that causes an
exception to be thrown if an object is encountered that has not already been queued. (This could happen only if there
were a bug in the traversal code used to calculate the linearization data.)
7.6. Known Issues with Linearization
There are a handful of known issues with this linearization code. These issues do not appear to impact the behavior of
linearized files which still work as intended: it is possible for a web browser to begin to display them before they are
fully downloaded. In fact, it seems that various other programs that create linearized files have many of these same
issues. These items make reference to terminology used in the linearization appendix of the PDF specification.
• Thread Dictionary information keys appear in part 4 with the rest of Threads instead of in part 9. Objects in part
9 are not grouped together functionally.
• We are not calculating numerators for shared object positions within content streams or interleaving them within
content streams.
• We generate only page offset, shared object, and outline hint tables. It would be relatively easy to add some additional
tables. We gather most of the information needed to create thumbnail hint tables. There are comments in the code
about this.
Linearization
24
7.7. Debugging Note
The qpdf --show-linearization command can show the complete contents of linearization hint streams. To look at the
raw data, you can extract the filtered contents of the linearization hint tables using qpdf --show-object=n --filtered-
stream-data. Then, to convert this into a bit stream (since linearization tables are bit streams written without regard
to byte boundaries), you can pipe the resulting data through the following perl code:
use bytes;
binmode STDIN;
undef $/;
my $a = <STDIN>;
my @ch = split(//, $a);
map { printf("%08b", ord($_)) } @ch;
print "\n";
25
Chapter 8. Object and Cross-Reference
Streams
This chapter provides information about the implementation of object stream and cross-reference stream support in
qpdf.
8.1. Object Streams
Object streams can contain any regular object except the following:
• stream objects
• objects with generation > 0
• the encryption dictionary
• objects containing the /Length of another stream
In addition, Adobe reader (at least as of version 8.0.0) appears to not be able to handle having the document catalog
appear in an object stream if the file is encrypted, though this is not specifically disallowed by the specification.
There are additional restrictions for linearized files. See Section 8.3, “Implications for Linearized Files” ” , page 26for
details.
The PDF specification refers to objects in object streams as “compressed objects” regardless of whether the object
stream is compressed.
The generation number of every object in an object stream must be zero. It is possible to delete and replace an object
in an object stream with a regular object.
The object stream dictionary has the following keys:
• /N: number of objects
• /First: byte offset of first object
• /Extends: indirect reference to stream that this extends
Stream collections are formed with /Extends. They must form a directed acyclic graph. These can be used for
semantic information and are not meaningful to the PDF document's syntactic structure. Although qpdf preserves
stream collections, it never generates them and doesn't make use of this information in any way.
The specification recommends limiting the number of objects in object stream for efficiency in reading and decoding.
Acrobat 6 uses no more than 100 objects per object stream for linearized files and no more 200 objects per stream for
non-linearized files. QPDFWriter, in object stream generation mode, never puts more than 100 objects in an object
stream.
Object stream contents consists of N pairs of integers, each of which is the object number and the byte offset of the
object relative to the first object in the stream, followed by the objects themselves, concatenated.
8.2. Cross-Reference Streams
For non-hybrid files, the value following startxref is the byte offset to the xref stream rather than the word xref.
Object and Cross-Reference Streams
26
For hybrid files (files containing both xref tables and cross-reference streams), the xref table's trailer dictionary contains
the key /XRefStm whose value is the byte offset to a cross-reference stream that supplements the xref table. A
PDF 1.5-compliant application should read the xref table first. Then it should replace any object that it has already
seen with any defined in the xref stream. Then it should follow any /Prev pointer in the original xref table's trailer
dictionary. The specification is not clear about what should be done, if anything, with a /Prev pointer in the xref
stream referenced by an xref table. The QPDF class ignores it, which is probably reasonable since, if this case were
to appear for any sensible PDF file, the previous xref table would probably have a corresponding /XRefStm pointer
of its own. For example, if a hybrid file were appended, the appended section would have its own xref table and /
XRefStm. The appended xref table would point to the previous xref table which would point the /XRefStm, meaning
that the new /XRefStm doesn't have to point to it.
Since xref streams must be read very early, they may not be encrypted, and the may not contain indirect objects for
keys required to read them, which are these:
• /Type: value /XRef
• /Size: value n+1: where n is highest object number (same as /Size in the trailer dictionary)
• /Index (optional): value [n count ...] used to determine which objects' information is stored in this stream.
The default is [0 /Size].
• /Prev: value offset: byte offset of previous xref stream (same as /Prev in the trailer dictionary)
• /W [...]: sizes of each field in the xref table
The other fields in the xref stream, which may be indirect if desired, are the union of those from the xref table's trailer
dictionary.
8.2.1. Cross-Reference Stream Data
The stream data is binary and encoded in big-endian byte order. Entries are concatenated, and each entry has a length
equal to the total of the entries in /W above. Each entry consists of one or more fields, the first of which is the type of
the field. The number of bytes for each field is given by /W above. A 0 in /W indicates that the field is omitted and
has the default value. The default value for the field type is “ “ 1”. All other default values are “ “ 0”.
PDF 1.5 has three field types:
• 0: for free objects. Format: 0 obj next-generation, same as the free table in a traditional cross-reference table
• 1: regular non-compressed object. Format: 1 offset generation
• 2: for objects in object streams. Format: 2 object-stream-number index, the number of object stream
containing the object and the index within the object stream of the object.
It seems standard to have the first entry in the table be 0 0 0 instead of 0 0 ffff if there are no deleted objects.
8.3. Implications for Linearized Files
For linearized files, the linearization dictionary, document catalog, and page objects may not be contained in object
streams.
Objects stored within object streams are given the highest range of object numbers within the main and first-page
cross-reference sections.
It is okay to use cross-reference streams in place of regular xref tables. There are on special considerations.
Documents you may be interested
Documents you may be interested