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 | 353 | QPDF_DLL |
| 354 | 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 | 361 | QPDF_DLL |
| 357 | 362 | void write(); |
| 358 | 363 | |
| ... | ... | @@ -417,9 +422,11 @@ class QPDFWriter |
| 417 | 422 | void prepareFileForWrite(); |
| 418 | 423 | void writeStandard(); |
| 419 | 424 | void writeLinearized(); |
| 425 | + void writePCLm(); | |
| 420 | 426 | void enqueuePart(std::vector<QPDFObjectHandle>& part); |
| 421 | 427 | void writeEncryptionDictionary(); |
| 422 | 428 | void writeHeader(); |
| 429 | + void writePCLmHeader(); | |
| 423 | 430 | void writeHintStream(int hint_id); |
| 424 | 431 | qpdf_offset_t writeXRefTable( |
| 425 | 432 | trailer_e which, int first, int last, int size); |
| ... | ... | @@ -492,6 +499,7 @@ class QPDFWriter |
| 492 | 499 | bool encrypted; |
| 493 | 500 | bool preserve_encryption; |
| 494 | 501 | bool linearized; |
| 502 | + bool pclm; | |
| 495 | 503 | qpdf_object_stream_e object_stream_mode; |
| 496 | 504 | std::string encryption_key; |
| 497 | 505 | bool encrypt_metadata; | ... | ... |
libqpdf/QPDFWriter.cc
| ... | ... | @@ -67,6 +67,7 @@ QPDFWriter::init() |
| 67 | 67 | encrypted = false; |
| 68 | 68 | preserve_encryption = true; |
| 69 | 69 | linearized = false; |
| 70 | + pclm = false; | |
| 70 | 71 | object_stream_mode = qpdf_o_preserve; |
| 71 | 72 | encrypt_metadata = true; |
| 72 | 73 | encrypt_use_aes = false; |
| ... | ... | @@ -347,6 +348,20 @@ void |
| 347 | 348 | QPDFWriter::setLinearization(bool val) |
| 348 | 349 | { |
| 349 | 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 | 367 | void |
| ... | ... | @@ -2290,6 +2305,12 @@ QPDFWriter::write() |
| 2290 | 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 | 2314 | if (this->qdf_mode) |
| 2294 | 2315 | { |
| 2295 | 2316 | if (! this->normalize_content_set) |
| ... | ... | @@ -2428,6 +2449,10 @@ QPDFWriter::write() |
| 2428 | 2449 | { |
| 2429 | 2450 | writeLinearized(); |
| 2430 | 2451 | } |
| 2452 | + else if (this->pclm) | |
| 2453 | + { | |
| 2454 | + writePCLm(); | |
| 2455 | + } | |
| 2431 | 2456 | else |
| 2432 | 2457 | { |
| 2433 | 2458 | writeStandard(); |
| ... | ... | @@ -2502,6 +2527,26 @@ QPDFWriter::writeHeader() |
| 2502 | 2527 | } |
| 2503 | 2528 | |
| 2504 | 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 | 2550 | QPDFWriter::writeHintStream(int hint_id) |
| 2506 | 2551 | { |
| 2507 | 2552 | PointerHolder<Buffer> hint_buffer; |
| ... | ... | @@ -3205,3 +3250,84 @@ QPDFWriter::writeStandard() |
| 3205 | 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 | +} | ... | ... |