Commit 041397fdabde66574824db7582a26ef1e3fbfc65
1 parent
8c99e4a6
Allow reading from InputSource and writing to Pipeline
Allowing users to subclass InputSource and Pipeline to read and write from/to arbitrary sources provides the maximum flexibility for users who want to read and write from other than files or memory.
Showing
8 changed files
with
64 additions
and
7 deletions
ChangeLog
| 1 | +2012-09-23 Jay Berkenbilt <ejb@ql.org> | ||
| 2 | + | ||
| 3 | + * Add public methods QPDF::processInputSource and | ||
| 4 | + QPDFWriter::setOutputPipeline to allow users to read from custom | ||
| 5 | + input sources and to write to custom pipelines. This allows the | ||
| 6 | + maximum flexibility in sources for reading and writing PDF files. | ||
| 7 | + | ||
| 1 | 2012-09-06 Jay Berkenbilt <ejb@ql.org> | 8 | 2012-09-06 Jay Berkenbilt <ejb@ql.org> |
| 2 | 9 | ||
| 3 | * 3.0.2: release | 10 | * 3.0.2: release |
include/qpdf/QPDF.hh
| @@ -72,6 +72,13 @@ class QPDF | @@ -72,6 +72,13 @@ class QPDF | ||
| 72 | char const* buf, size_t length, | 72 | char const* buf, size_t length, |
| 73 | char const* password = 0); | 73 | char const* password = 0); |
| 74 | 74 | ||
| 75 | + // Parse a PDF file loaded from a custom InputSource. If you have | ||
| 76 | + // your own method of retrieving a PDF file, you can subclass | ||
| 77 | + // InputSource and use this method. | ||
| 78 | + QPDF_DLL | ||
| 79 | + void processInputSource(PointerHolder<InputSource>, | ||
| 80 | + char const* password = 0); | ||
| 81 | + | ||
| 75 | // Create a QPDF object for an empty PDF. This PDF has no pages | 82 | // Create a QPDF object for an empty PDF. This PDF has no pages |
| 76 | // or objects other than a minimal trailer, a document catalog, | 83 | // or objects other than a minimal trailer, a document catalog, |
| 77 | // and a /Pages tree containing zero pages. Pages and other | 84 | // and a /Pages tree containing zero pages. Pages and other |
include/qpdf/QPDFWriter.hh
| @@ -95,6 +95,15 @@ class QPDFWriter | @@ -95,6 +95,15 @@ class QPDFWriter | ||
| 95 | QPDF_DLL | 95 | QPDF_DLL |
| 96 | Buffer* getBuffer(); | 96 | Buffer* getBuffer(); |
| 97 | 97 | ||
| 98 | + // Supply your own pipeline object. Output will be written to | ||
| 99 | + // this pipeline, and QPDFWriter will call finish() on the | ||
| 100 | + // pipeline. It is the caller's responsibility to manage the | ||
| 101 | + // memory for the pipeline. The pipeline is never deleted by | ||
| 102 | + // QPDFWriter, which makes it possible for you to call additional | ||
| 103 | + // methods on the pipeline after the writing is finished. | ||
| 104 | + QPDF_DLL | ||
| 105 | + void setOutputPipeline(Pipeline*); | ||
| 106 | + | ||
| 98 | // Setting Parameters | 107 | // Setting Parameters |
| 99 | 108 | ||
| 100 | // Set the value of object stream mode. In disable mode, we never | 109 | // Set the value of object stream mode. In disable mode, we never |
libqpdf/QPDF.cc
| @@ -138,9 +138,8 @@ void | @@ -138,9 +138,8 @@ void | ||
| 138 | QPDF::processFile(char const* filename, char const* password) | 138 | QPDF::processFile(char const* filename, char const* password) |
| 139 | { | 139 | { |
| 140 | FileInputSource* fi = new FileInputSource(); | 140 | FileInputSource* fi = new FileInputSource(); |
| 141 | - this->file = fi; | ||
| 142 | fi->setFilename(filename); | 141 | fi->setFilename(filename); |
| 143 | - parse(password); | 142 | + processInputSource(fi, password); |
| 144 | } | 143 | } |
| 145 | 144 | ||
| 146 | void | 145 | void |
| @@ -148,9 +147,8 @@ QPDF::processFile(char const* description, FILE* filep, | @@ -148,9 +147,8 @@ QPDF::processFile(char const* description, FILE* filep, | ||
| 148 | bool close_file, char const* password) | 147 | bool close_file, char const* password) |
| 149 | { | 148 | { |
| 150 | FileInputSource* fi = new FileInputSource(); | 149 | FileInputSource* fi = new FileInputSource(); |
| 151 | - this->file = fi; | ||
| 152 | fi->setFile(description, filep, close_file); | 150 | fi->setFile(description, filep, close_file); |
| 153 | - parse(password); | 151 | + processInputSource(fi, password); |
| 154 | } | 152 | } |
| 155 | 153 | ||
| 156 | void | 154 | void |
| @@ -158,10 +156,18 @@ QPDF::processMemoryFile(char const* description, | @@ -158,10 +156,18 @@ QPDF::processMemoryFile(char const* description, | ||
| 158 | char const* buf, size_t length, | 156 | char const* buf, size_t length, |
| 159 | char const* password) | 157 | char const* password) |
| 160 | { | 158 | { |
| 161 | - this->file = | 159 | + processInputSource( |
| 162 | new BufferInputSource(description, | 160 | new BufferInputSource(description, |
| 163 | new Buffer((unsigned char*)buf, length), | 161 | new Buffer((unsigned char*)buf, length), |
| 164 | - true); | 162 | + true), |
| 163 | + password); | ||
| 164 | +} | ||
| 165 | + | ||
| 166 | +void | ||
| 167 | +QPDF::processInputSource(PointerHolder<InputSource> source, | ||
| 168 | + char const* password) | ||
| 169 | +{ | ||
| 170 | + this->file = source; | ||
| 165 | parse(password); | 171 | parse(password); |
| 166 | } | 172 | } |
| 167 | 173 |
libqpdf/QPDFWriter.cc
| @@ -135,6 +135,13 @@ QPDFWriter::getBuffer() | @@ -135,6 +135,13 @@ QPDFWriter::getBuffer() | ||
| 135 | } | 135 | } |
| 136 | 136 | ||
| 137 | void | 137 | void |
| 138 | +QPDFWriter::setOutputPipeline(Pipeline* p) | ||
| 139 | +{ | ||
| 140 | + this->filename = "custom pipeline"; | ||
| 141 | + initializePipelineStack(p); | ||
| 142 | +} | ||
| 143 | + | ||
| 144 | +void | ||
| 138 | QPDFWriter::setObjectStreamMode(qpdf_object_stream_e mode) | 145 | QPDFWriter::setObjectStreamMode(qpdf_object_stream_e mode) |
| 139 | { | 146 | { |
| 140 | this->object_stream_mode = mode; | 147 | this->object_stream_mode = mode; |
qpdf/qtest/qpdf.test
| @@ -149,7 +149,7 @@ $td->runtest("remove page we don't have", | @@ -149,7 +149,7 @@ $td->runtest("remove page we don't have", | ||
| 149 | $td->NORMALIZE_NEWLINES); | 149 | $td->NORMALIZE_NEWLINES); |
| 150 | # ---------- | 150 | # ---------- |
| 151 | $td->notify("--- Miscellaneous Tests ---"); | 151 | $td->notify("--- Miscellaneous Tests ---"); |
| 152 | -$n_tests += 53; | 152 | +$n_tests += 55; |
| 153 | 153 | ||
| 154 | $td->runtest("qpdf version", | 154 | $td->runtest("qpdf version", |
| 155 | {$td->COMMAND => "qpdf --version"}, | 155 | {$td->COMMAND => "qpdf --version"}, |
| @@ -403,6 +403,13 @@ $td->runtest("check output", | @@ -403,6 +403,13 @@ $td->runtest("check output", | ||
| 403 | $td->runtest("check output", | 403 | $td->runtest("check output", |
| 404 | {$td->FILE => "d.pdf"}, | 404 | {$td->FILE => "d.pdf"}, |
| 405 | {$td->FILE => "extra-header-lin-newline.pdf"}); | 405 | {$td->FILE => "extra-header-lin-newline.pdf"}); |
| 406 | +$td->runtest("output to custom pipeline", | ||
| 407 | + {$td->COMMAND => "test_driver 33 minimal.pdf"}, | ||
| 408 | + {$td->STRING => "test 33 done\n", $td->EXIT_STATUS => 0}, | ||
| 409 | + $td->NORMALIZE_NEWLINES); | ||
| 410 | +$td->runtest("check output", | ||
| 411 | + {$td->FILE => "a.pdf"}, | ||
| 412 | + {$td->FILE => "custom-pipeline.pdf"}); | ||
| 406 | 413 | ||
| 407 | show_ntests(); | 414 | show_ntests(); |
| 408 | # ---------- | 415 | # ---------- |
qpdf/qtest/qpdf/custom-pipeline.pdf
0 → 100644
No preview for this file type
qpdf/test_driver.cc
| @@ -1112,6 +1112,20 @@ void runtest(int n, char const* filename1, char const* filename2) | @@ -1112,6 +1112,20 @@ void runtest(int n, char const* filename1, char const* filename2) | ||
| 1112 | w.write(); | 1112 | w.write(); |
| 1113 | } | 1113 | } |
| 1114 | } | 1114 | } |
| 1115 | + else if (n == 33) | ||
| 1116 | + { | ||
| 1117 | + // Test writing to a custom pipeline | ||
| 1118 | + Pl_Buffer p("buffer"); | ||
| 1119 | + QPDFWriter w(pdf); | ||
| 1120 | + w.setStaticID(true); | ||
| 1121 | + w.setOutputPipeline(&p); | ||
| 1122 | + w.write(); | ||
| 1123 | + PointerHolder<Buffer> b = p.getBuffer(); | ||
| 1124 | + FILE* f = QUtil::fopen_wrapper("open a.pdf", | ||
| 1125 | + fopen("a.pdf", "wb")); | ||
| 1126 | + fwrite(b->getBuffer(), b->getSize(), 1, f); | ||
| 1127 | + fclose(f); | ||
| 1128 | + } | ||
| 1115 | else | 1129 | else |
| 1116 | { | 1130 | { |
| 1117 | throw std::runtime_error(std::string("invalid test ") + | 1131 | throw std::runtime_error(std::string("invalid test ") + |