2
1
mirror of https://github.com/qpdf/qpdf.git synced 2024-06-04 03:10:52 +00:00

addPageContents

git-svn-id: svn+q:///qpdf/trunk@995 71b93d88-0707-0410-a8cf-f5a4172ac649
This commit is contained in:
Jay Berkenbilt 2010-08-05 21:06:49 +00:00
parent c292442962
commit 2dbc1006fb
8 changed files with 161 additions and 32 deletions

View File

@ -1,3 +1,10 @@
2010-08-05 Jay Berkenbilt <ejb@ql.org>
* Add new methods to QPDFObjectHandle: replaceStreamData and
newStream. These methods allow users of the qpdf library to add
new streams and to replace data of existing streams. Examples are
provided.
2010-06-06 Jay Berkenbilt <ejb@ql.org> 2010-06-06 Jay Berkenbilt <ejb@ql.org>
* Fix memory leak for QPDF objects whose underlying PDF objects * Fix memory leak for QPDF objects whose underlying PDF objects

13
TODO
View File

@ -7,20 +7,19 @@ Next
in August, 2009. He seems to like to send encrypted mail (key in August, 2009. He seems to like to send encrypted mail (key
01FCC336). Tell him about newStream and replaceStreamData. 01FCC336). Tell him about newStream and replaceStreamData.
* Tell stronghorse@tom.com about QPDFObjectHandle::addPageContents.
See message from stronghorse@tom.com ("Suggestion for qpdf") from
2010-06-09 and my response.
2.2 2.2
=== ===
* Add helper routines for manipulating page content streams.
Operations should include ability to convert page contents from a
stream to an array of streams and to append or prepend to the page
contents. See message from stronghorse@tom.com ("Suggestion for
qpdf") from 2010-06-09 and my response. Consider providing an
example program that adds the line he suggests.
* Create an example that does some kind of manipulation on every * Create an example that does some kind of manipulation on every
image. Use QPDF::getAllPages and QPDFObjectHandle::getPageImages image. Use QPDF::getAllPages and QPDFObjectHandle::getPageImages
along with new stream data and dictionary manipulation. along with new stream data and dictionary manipulation.
* Add example program for addPageContents using suggestion from
stronghorse@tom.com's message above.
General General
======= =======

View File

@ -288,14 +288,22 @@ class QPDFObjectHandle
QPDF_DLL QPDF_DLL
std::map<std::string, QPDFObjectHandle> getPageImages(); std::map<std::string, QPDFObjectHandle> getPageImages();
// Throws an exception if this is not a Page object. Returns a // Returns a vector of stream objects representing the content
// vector of stream objects representing the content streams for // streams for the given page. This routine allows the caller to
// the given page. This routine allows the caller to not care // not care whether there are one or more than one content streams
// whether there are one or more than one content streams for a // for a page. Throws an exception if this is not a Page object.
// page.
QPDF_DLL QPDF_DLL
std::vector<QPDFObjectHandle> getPageContents(); std::vector<QPDFObjectHandle> getPageContents();
// Add the given object as a new content stream for this page. If
// parameter 'first' is true, add to the beginning. Otherwise,
// add to the end. This routine automatically converts the page
// contents to an array if it is a scalar, allowing the caller not
// to care what the initial structure is. Throws an exception if
// this is not a Page object.
QPDF_DLL
void addPageContents(QPDFObjectHandle contents, bool first);
// Initializers for objects. This Factory class gives the QPDF // Initializers for objects. This Factory class gives the QPDF
// class specific permission to call factory methods without // class specific permission to call factory methods without
// making it a friend of the whole QPDFObjectHandle class. // making it a friend of the whole QPDFObjectHandle class.

View File

@ -472,6 +472,35 @@ QPDFObjectHandle::getPageContents()
return result; return result;
} }
void
QPDFObjectHandle::addPageContents(QPDFObjectHandle new_contents, bool first)
{
assertPageObject();
new_contents.assertType("Stream", new_contents.isStream());
std::vector<QPDFObjectHandle> orig_contents = getPageContents();
std::vector<QPDFObjectHandle> content_streams;
if (first)
{
QTC::TC("qpdf", "QPDFObjectHandle prepend page contents");
content_streams.push_back(new_contents);
}
for (std::vector<QPDFObjectHandle>::iterator iter = orig_contents.begin();
iter != orig_contents.end(); ++iter)
{
QTC::TC("qpdf", "QPDFObjectHandle append page contents");
content_streams.push_back(*iter);
}
if (! first)
{
content_streams.push_back(new_contents);
}
QPDFObjectHandle contents = QPDFObjectHandle::newArray(content_streams);
this->replaceKey("/Contents", contents);
}
std::string std::string
QPDFObjectHandle::unparse() QPDFObjectHandle::unparse()
{ {

View File

@ -181,3 +181,5 @@ QPDF_Stream provider length mismatch 0
QPDFObjectHandle newStream 0 QPDFObjectHandle newStream 0
QPDFObjectHandle newStream with data 0 QPDFObjectHandle newStream with data 0
QPDF_Stream pipe no stream data 0 QPDF_Stream pipe no stream data 0
QPDFObjectHandle prepend page contents 0
QPDFObjectHandle append page contents 0

View File

@ -76,26 +76,8 @@ flush_tiff_cache();
show_ntests(); show_ntests();
# ---------- # ----------
$td->notify("--- Miscellaneous Tests ---"); $td->notify("--- Stream Replacement Tests ---");
$n_tests += 28; $n_tests += 8;
$td->runtest("qpdf version",
{$td->COMMAND => "qpdf --version"},
{$td->REGEXP => "qpdf version \\S+\n.*", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("C API: qpdf version",
{$td->COMMAND => "qpdf-ctest --version"},
{$td->REGEXP => "qpdf-ctest version \\S+\n",
$td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
foreach (my $i = 1; $i <= 3; ++$i)
{
$td->runtest("misc tests",
{$td->COMMAND => "test_driver 5 misc-$i.pdf"},
{$td->FILE => "misc-$i.out", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
}
$td->runtest("replace stream data", $td->runtest("replace stream data",
{$td->COMMAND => "test_driver 7 qstream.pdf"}, {$td->COMMAND => "test_driver 7 qstream.pdf"},
@ -118,6 +100,36 @@ $td->runtest("new streams",
$td->runtest("new stream", $td->runtest("new stream",
{$td->FILE => "a.pdf"}, {$td->FILE => "a.pdf"},
{$td->FILE => "new-streams.pdf"}); {$td->FILE => "new-streams.pdf"});
$td->runtest("add page contents",
{$td->COMMAND => "test_driver 10 minimal.pdf"},
{$td->STRING => "test 10 done\n", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("new stream",
{$td->FILE => "a.pdf"},
{$td->FILE => "add-contents.pdf"});
show_ntests();
# ----------
$td->notify("--- Miscellaneous Tests ---");
$n_tests += 22;
$td->runtest("qpdf version",
{$td->COMMAND => "qpdf --version"},
{$td->REGEXP => "qpdf version \\S+\n.*", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("C API: qpdf version",
{$td->COMMAND => "qpdf-ctest --version"},
{$td->REGEXP => "qpdf-ctest version \\S+\n",
$td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
foreach (my $i = 1; $i <= 3; ++$i)
{
$td->runtest("misc tests",
{$td->COMMAND => "test_driver 5 misc-$i.pdf"},
{$td->FILE => "misc-$i.out", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
}
# Make sure we ignore decode parameters that we don't understand # Make sure we ignore decode parameters that we don't understand
$td->runtest("unknown decode parameters", $td->runtest("unknown decode parameters",

View File

@ -0,0 +1,54 @@
%PDF-1.3
%¿÷¢þ
1 0 obj
<< /Pages 2 0 R /Type /Catalog >>
endobj
2 0 obj
<< /Count 1 /Kids [ 3 0 R ] /Type /Pages >>
endobj
3 0 obj
<< /Contents [ 4 0 R 5 0 R 6 0 R ] /MediaBox [ 0 0 612 792 ] /Parent 2 0 R /Resources << /Font << /F1 7 0 R >> /ProcSet 8 0 R >> /Type /Page >>
endobj
4 0 obj
<< /Length 37 >>
stream
BT /F1 12 Tf 72 620 Td (Baked) Tj ET
endstream
endobj
5 0 obj
<< /Length 44 >>
stream
BT
/F1 24 Tf
72 720 Td
(Potato) Tj
ET
endstream
endobj
6 0 obj
<< /Length 38 >>
stream
BT /F1 18 Tf 72 520 Td (Mashed) Tj ET
endstream
endobj
7 0 obj
<< /BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font >>
endobj
8 0 obj
[ /PDF /Text ]
endobj
xref
0 9
0000000000 65535 f
0000000015 00000 n
0000000064 00000 n
0000000123 00000 n
0000000282 00000 n
0000000368 00000 n
0000000461 00000 n
0000000548 00000 n
0000000655 00000 n
trailer << /Root 1 0 R /Size 9 /ID [<31415926535897932384626433832795><31415926535897932384626433832795>] >>
startxref
685
%%EOF

View File

@ -427,6 +427,24 @@ void runtest(int n, char const* filename)
w.setStreamDataMode(qpdf_s_preserve); w.setStreamDataMode(qpdf_s_preserve);
w.write(); w.write();
} }
else if (n == 10)
{
PointerHolder<Buffer> b1 = new Buffer(37);
unsigned char* bp = b1.getPointer()->getBuffer();
memcpy(bp, (char*)"BT /F1 12 Tf 72 620 Td (Baked) Tj ET\n", 37);
PointerHolder<Buffer> b2 = new Buffer(38);
bp = b2.getPointer()->getBuffer();
memcpy(bp, (char*)"BT /F1 18 Tf 72 520 Td (Mashed) Tj ET\n", 38);
std::vector<QPDFObjectHandle> pages = pdf.getAllPages();
pages[0].addPageContents(QPDFObjectHandle::newStream(&pdf, b1), true);
pages[0].addPageContents(QPDFObjectHandle::newStream(&pdf, b2), false);
QPDFWriter w(pdf, "a.pdf");
w.setStaticID(true);
w.setStreamDataMode(qpdf_s_preserve);
w.write();
}
else else
{ {
throw std::runtime_error(std::string("invalid test ") + throw std::runtime_error(std::string("invalid test ") +