mirror of
https://github.com/qpdf/qpdf.git
synced 2024-12-22 10:58:58 +00:00
addPageContents
git-svn-id: svn+q:///qpdf/trunk@995 71b93d88-0707-0410-a8cf-f5a4172ac649
This commit is contained in:
parent
c292442962
commit
2dbc1006fb
@ -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>
|
||||
|
||||
* Fix memory leak for QPDF objects whose underlying PDF objects
|
||||
|
13
TODO
13
TODO
@ -7,20 +7,19 @@ Next
|
||||
in August, 2009. He seems to like to send encrypted mail (key
|
||||
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
|
||||
===
|
||||
|
||||
* 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
|
||||
image. Use QPDF::getAllPages and QPDFObjectHandle::getPageImages
|
||||
along with new stream data and dictionary manipulation.
|
||||
|
||||
* Add example program for addPageContents using suggestion from
|
||||
stronghorse@tom.com's message above.
|
||||
|
||||
General
|
||||
=======
|
||||
|
@ -288,14 +288,22 @@ class QPDFObjectHandle
|
||||
QPDF_DLL
|
||||
std::map<std::string, QPDFObjectHandle> getPageImages();
|
||||
|
||||
// Throws an exception if this is not a Page object. Returns a
|
||||
// vector of stream objects representing the content streams for
|
||||
// the given page. This routine allows the caller to not care
|
||||
// whether there are one or more than one content streams for a
|
||||
// page.
|
||||
// Returns a vector of stream objects representing the content
|
||||
// streams for the given page. This routine allows the caller to
|
||||
// not care whether there are one or more than one content streams
|
||||
// for a page. Throws an exception if this is not a Page object.
|
||||
QPDF_DLL
|
||||
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
|
||||
// class specific permission to call factory methods without
|
||||
// making it a friend of the whole QPDFObjectHandle class.
|
||||
|
@ -472,6 +472,35 @@ QPDFObjectHandle::getPageContents()
|
||||
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
|
||||
QPDFObjectHandle::unparse()
|
||||
{
|
||||
|
@ -181,3 +181,5 @@ QPDF_Stream provider length mismatch 0
|
||||
QPDFObjectHandle newStream 0
|
||||
QPDFObjectHandle newStream with data 0
|
||||
QPDF_Stream pipe no stream data 0
|
||||
QPDFObjectHandle prepend page contents 0
|
||||
QPDFObjectHandle append page contents 0
|
||||
|
@ -76,26 +76,8 @@ flush_tiff_cache();
|
||||
|
||||
show_ntests();
|
||||
# ----------
|
||||
$td->notify("--- Miscellaneous Tests ---");
|
||||
$n_tests += 28;
|
||||
|
||||
$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->notify("--- Stream Replacement Tests ---");
|
||||
$n_tests += 8;
|
||||
|
||||
$td->runtest("replace stream data",
|
||||
{$td->COMMAND => "test_driver 7 qstream.pdf"},
|
||||
@ -118,6 +100,36 @@ $td->runtest("new streams",
|
||||
$td->runtest("new stream",
|
||||
{$td->FILE => "a.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
|
||||
$td->runtest("unknown decode parameters",
|
||||
|
54
qpdf/qtest/qpdf/add-contents.pdf
Normal file
54
qpdf/qtest/qpdf/add-contents.pdf
Normal 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
|
@ -427,6 +427,24 @@ void runtest(int n, char const* filename)
|
||||
w.setStreamDataMode(qpdf_s_preserve);
|
||||
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
|
||||
{
|
||||
throw std::runtime_error(std::string("invalid test ") +
|
||||
|
Loading…
Reference in New Issue
Block a user