Commit b19210fa7dbab7efa7a3cd65653be4ff2f6e08e9
Committed by
Jay Berkenbilt
1 parent
3b170ab0
QPDFWriter: Add setPCLm() and writePCLm() methods
* Add support for PCLm using setPCLm() and writePCLm() methods in QPDFWriter.hh and QPDFWriter.cc * Add a function writePCLmHeader() for PCLm header in QPDFWriter
Showing
2 changed files
with
134 additions
and
0 deletions
include/qpdf/QPDFWriter.hh
| @@ -353,6 +353,11 @@ class QPDFWriter | @@ -353,6 +353,11 @@ class QPDFWriter | ||
| 353 | QPDF_DLL | 353 | QPDF_DLL |
| 354 | void setLinearization(bool); | 354 | void setLinearization(bool); |
| 355 | 355 | ||
| 356 | + // Create PCLm output. Enables writing unreferenced objects, | ||
| 357 | + // set PCLm header and writes pages before file catalog and page tree. | ||
| 358 | + QPDF_DLL | ||
| 359 | + void setPCLm(bool); | ||
| 360 | + | ||
| 356 | QPDF_DLL | 361 | QPDF_DLL |
| 357 | void write(); | 362 | void write(); |
| 358 | 363 | ||
| @@ -417,9 +422,11 @@ class QPDFWriter | @@ -417,9 +422,11 @@ class QPDFWriter | ||
| 417 | void prepareFileForWrite(); | 422 | void prepareFileForWrite(); |
| 418 | void writeStandard(); | 423 | void writeStandard(); |
| 419 | void writeLinearized(); | 424 | void writeLinearized(); |
| 425 | + void writePCLm(); | ||
| 420 | void enqueuePart(std::vector<QPDFObjectHandle>& part); | 426 | void enqueuePart(std::vector<QPDFObjectHandle>& part); |
| 421 | void writeEncryptionDictionary(); | 427 | void writeEncryptionDictionary(); |
| 422 | void writeHeader(); | 428 | void writeHeader(); |
| 429 | + void writePCLmHeader(); | ||
| 423 | void writeHintStream(int hint_id); | 430 | void writeHintStream(int hint_id); |
| 424 | qpdf_offset_t writeXRefTable( | 431 | qpdf_offset_t writeXRefTable( |
| 425 | trailer_e which, int first, int last, int size); | 432 | trailer_e which, int first, int last, int size); |
| @@ -492,6 +499,7 @@ class QPDFWriter | @@ -492,6 +499,7 @@ class QPDFWriter | ||
| 492 | bool encrypted; | 499 | bool encrypted; |
| 493 | bool preserve_encryption; | 500 | bool preserve_encryption; |
| 494 | bool linearized; | 501 | bool linearized; |
| 502 | + bool pclm; | ||
| 495 | qpdf_object_stream_e object_stream_mode; | 503 | qpdf_object_stream_e object_stream_mode; |
| 496 | std::string encryption_key; | 504 | std::string encryption_key; |
| 497 | bool encrypt_metadata; | 505 | bool encrypt_metadata; |
libqpdf/QPDFWriter.cc
| @@ -67,6 +67,7 @@ QPDFWriter::init() | @@ -67,6 +67,7 @@ QPDFWriter::init() | ||
| 67 | encrypted = false; | 67 | encrypted = false; |
| 68 | preserve_encryption = true; | 68 | preserve_encryption = true; |
| 69 | linearized = false; | 69 | linearized = false; |
| 70 | + pclm = false; | ||
| 70 | object_stream_mode = qpdf_o_preserve; | 71 | object_stream_mode = qpdf_o_preserve; |
| 71 | encrypt_metadata = true; | 72 | encrypt_metadata = true; |
| 72 | encrypt_use_aes = false; | 73 | encrypt_use_aes = false; |
| @@ -347,6 +348,20 @@ void | @@ -347,6 +348,20 @@ void | ||
| 347 | QPDFWriter::setLinearization(bool val) | 348 | QPDFWriter::setLinearization(bool val) |
| 348 | { | 349 | { |
| 349 | this->linearized = val; | 350 | this->linearized = val; |
| 351 | + if (val) | ||
| 352 | + { | ||
| 353 | + this->pclm = false; | ||
| 354 | + } | ||
| 355 | +} | ||
| 356 | + | ||
| 357 | +void | ||
| 358 | +QPDFWriter::setPCLm(bool val) | ||
| 359 | +{ | ||
| 360 | + this->pclm = val; | ||
| 361 | + if (val) | ||
| 362 | + { | ||
| 363 | + this->linearized = false; | ||
| 364 | + } | ||
| 350 | } | 365 | } |
| 351 | 366 | ||
| 352 | void | 367 | void |
| @@ -2290,6 +2305,12 @@ QPDFWriter::write() | @@ -2290,6 +2305,12 @@ QPDFWriter::write() | ||
| 2290 | this->qdf_mode = false; | 2305 | this->qdf_mode = false; |
| 2291 | } | 2306 | } |
| 2292 | 2307 | ||
| 2308 | + if (this->pclm) | ||
| 2309 | + { | ||
| 2310 | + setStreamDataMode(qpdf_s_preserve); | ||
| 2311 | + this->encrypted = false; | ||
| 2312 | + } | ||
| 2313 | + | ||
| 2293 | if (this->qdf_mode) | 2314 | if (this->qdf_mode) |
| 2294 | { | 2315 | { |
| 2295 | if (! this->normalize_content_set) | 2316 | if (! this->normalize_content_set) |
| @@ -2428,6 +2449,10 @@ QPDFWriter::write() | @@ -2428,6 +2449,10 @@ QPDFWriter::write() | ||
| 2428 | { | 2449 | { |
| 2429 | writeLinearized(); | 2450 | writeLinearized(); |
| 2430 | } | 2451 | } |
| 2452 | + else if (this->pclm) | ||
| 2453 | + { | ||
| 2454 | + writePCLm(); | ||
| 2455 | + } | ||
| 2431 | else | 2456 | else |
| 2432 | { | 2457 | { |
| 2433 | writeStandard(); | 2458 | writeStandard(); |
| @@ -2502,6 +2527,26 @@ QPDFWriter::writeHeader() | @@ -2502,6 +2527,26 @@ QPDFWriter::writeHeader() | ||
| 2502 | } | 2527 | } |
| 2503 | 2528 | ||
| 2504 | void | 2529 | void |
| 2530 | +QPDFWriter::writePCLmHeader() | ||
| 2531 | +{ | ||
| 2532 | + setMinimumPDFVersion(pdf.getPDFVersion(), pdf.getExtensionLevel()); | ||
| 2533 | + this->final_pdf_version = this->min_pdf_version; | ||
| 2534 | + this->final_extension_level = this->min_extension_level; | ||
| 2535 | + if (! this->forced_pdf_version.empty()) | ||
| 2536 | + { | ||
| 2537 | + QTC::TC("qpdf", "QPDFWriter using forced PDF version"); | ||
| 2538 | + this->final_pdf_version = this->forced_pdf_version; | ||
| 2539 | + this->final_extension_level = this->forced_extension_level; | ||
| 2540 | + } | ||
| 2541 | + | ||
| 2542 | + writeString("%PDF-"); | ||
| 2543 | + writeString(this->final_pdf_version); | ||
| 2544 | + // PCLm version | ||
| 2545 | + writeString("\n%PCLm 1.0\n"); | ||
| 2546 | + writeStringQDF("%QDF-1.0\n\n"); | ||
| 2547 | +} | ||
| 2548 | + | ||
| 2549 | +void | ||
| 2505 | QPDFWriter::writeHintStream(int hint_id) | 2550 | QPDFWriter::writeHintStream(int hint_id) |
| 2506 | { | 2551 | { |
| 2507 | PointerHolder<Buffer> hint_buffer; | 2552 | PointerHolder<Buffer> hint_buffer; |
| @@ -3205,3 +3250,84 @@ QPDFWriter::writeStandard() | @@ -3205,3 +3250,84 @@ QPDFWriter::writeStandard() | ||
| 3205 | assert(this->md5_pipeline == 0); | 3250 | assert(this->md5_pipeline == 0); |
| 3206 | } | 3251 | } |
| 3207 | } | 3252 | } |
| 3253 | + | ||
| 3254 | +void | ||
| 3255 | +QPDFWriter::writePCLm() | ||
| 3256 | +{ | ||
| 3257 | + if (this->deterministic_id) | ||
| 3258 | + { | ||
| 3259 | + pushMD5Pipeline(); | ||
| 3260 | + } | ||
| 3261 | + | ||
| 3262 | + // Start writing | ||
| 3263 | + | ||
| 3264 | + writePCLmHeader(); | ||
| 3265 | + writeString(this->extra_header_text); | ||
| 3266 | + | ||
| 3267 | + // Image transform stream content for page strip images. | ||
| 3268 | + // Each of this new stream has to come after every page image | ||
| 3269 | + // strip written in the pclm file. | ||
| 3270 | + std::string image_transform_content = "q /image Do Q\n"; | ||
| 3271 | + | ||
| 3272 | + // enqueue all pages first | ||
| 3273 | + std::vector<QPDFObjectHandle> all = this->pdf.getAllPages(); | ||
| 3274 | + for (std::vector<QPDFObjectHandle>::iterator iter = all.begin(); | ||
| 3275 | + iter != all.end(); ++iter) | ||
| 3276 | + { | ||
| 3277 | + // enqueue page | ||
| 3278 | + enqueueObject(*iter); | ||
| 3279 | + | ||
| 3280 | + // enqueue page contents stream | ||
| 3281 | + enqueueObject((*iter).getKey("/Contents")); | ||
| 3282 | + | ||
| 3283 | + // enqueue all the strips for each page | ||
| 3284 | + QPDFObjectHandle strips = | ||
| 3285 | + (*iter).getKey("/Resources").getKey("/XObject"); | ||
| 3286 | + std::set<std::string> keys = strips.getKeys(); | ||
| 3287 | + for (std::set<std::string>::iterator image = keys.begin(); | ||
| 3288 | + image != keys.end(); ++image) | ||
| 3289 | + { | ||
| 3290 | + enqueueObject(strips.getKey(*image)); | ||
| 3291 | + enqueueObject(QPDFObjectHandle::newStream( | ||
| 3292 | + &pdf, image_transform_content)); | ||
| 3293 | + } | ||
| 3294 | + } | ||
| 3295 | + | ||
| 3296 | + // Put root in queue. | ||
| 3297 | + QPDFObjectHandle trailer = getTrimmedTrailer(); | ||
| 3298 | + enqueueObject(trailer.getKey("/Root")); | ||
| 3299 | + | ||
| 3300 | + // Now start walking queue, output each object | ||
| 3301 | + while (this->object_queue.size()) | ||
| 3302 | + { | ||
| 3303 | + QPDFObjectHandle cur_object = this->object_queue.front(); | ||
| 3304 | + this->object_queue.pop_front(); | ||
| 3305 | + writeObject(cur_object); | ||
| 3306 | + } | ||
| 3307 | + | ||
| 3308 | + // Now write out xref. next_objid is now the number of objects. | ||
| 3309 | + qpdf_offset_t xref_offset = this->pipeline->getCount(); | ||
| 3310 | + if (this->object_stream_to_objects.empty()) | ||
| 3311 | + { | ||
| 3312 | + // Write regular cross-reference table | ||
| 3313 | + writeXRefTable(t_normal, 0, this->next_objid - 1, this->next_objid); | ||
| 3314 | + } | ||
| 3315 | + else | ||
| 3316 | + { | ||
| 3317 | + // Write cross-reference stream. | ||
| 3318 | + int xref_id = this->next_objid++; | ||
| 3319 | + writeXRefStream(xref_id, xref_id, xref_offset, t_normal, | ||
| 3320 | + 0, this->next_objid - 1, this->next_objid); | ||
| 3321 | + } | ||
| 3322 | + writeString("startxref\n"); | ||
| 3323 | + writeString(QUtil::int_to_string(xref_offset)); | ||
| 3324 | + writeString("\n%%EOF\n"); | ||
| 3325 | + | ||
| 3326 | + if (this->deterministic_id) | ||
| 3327 | + { | ||
| 3328 | + QTC::TC("qpdf", "QPDFWriter standard deterministic ID", | ||
| 3329 | + this->object_stream_to_objects.empty() ? 0 : 1); | ||
| 3330 | + popPipelineStack(); | ||
| 3331 | + assert(this->md5_pipeline == 0); | ||
| 3332 | + } | ||
| 3333 | +} |