From 87412eb05be3148e812310128f361f79922baad8 Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Sat, 18 Jun 2022 20:44:44 -0400 Subject: [PATCH] Add QPDFJob::registerProgressReporter --- TODO | 5 ++++- include/qpdf/QPDFJob.hh | 9 ++++++++ libqpdf/QPDFJob.cc | 33 +++++++++++++++++++++--------- qpdf/qtest/qpdf/filter-progress.pl | 7 ++++++- qpdf/qtest/qpdf/job-api.out | 7 +++++++ qpdf/qtest/qpdfjob.test | 3 ++- qpdf/test_driver.cc | 21 +++++++++++++++++++ 7 files changed, 72 insertions(+), 13 deletions(-) diff --git a/TODO b/TODO index f71528e1..8a0ad3a0 100644 --- a/TODO +++ b/TODO @@ -14,7 +14,10 @@ Next: Pending changes: -* Allow users to supply a custom progress reporter for QPDFJob +* Allow users to supply a custom progress reporter for QPDFJob. If one + is provided, use it instead of creating one. Then expose to the C + API. Consider also exposing a way to set a new logger and to get the + logger from QPDF and QPDFJob in the C API. * Check about runpath in the linux-bin distribution. I think the appimage build specifically is setting the runpath, which is actually desirable in this case. Make sure to understand and diff --git a/include/qpdf/QPDFJob.hh b/include/qpdf/QPDFJob.hh index 16b1ab74..96b05768 100644 --- a/include/qpdf/QPDFJob.hh +++ b/include/qpdf/QPDFJob.hh @@ -134,6 +134,14 @@ class QPDFJob "configure logger from getLogger() or call setLogger()")]] QPDF_DLL void setOutputStreams(std::ostream* out_stream, std::ostream* err_stream); + // You can register a custom progress reporter to be called by + // QPDFWriter (see QPDFWriter::registerProgressReporter). This is + // only called if you also request progress reporting through + // normal configuration methods (e.g., pass --progress, call + // config()->progress, etc.) + QPDF_DLL + void registerProgressReporter(std::function); + // Check to make sure no contradictory options have been // specified. This is called automatically after initializing from // argv or json and is also called by run, but you can call it @@ -579,6 +587,7 @@ class QPDFJob bool decrypt; int split_pages; bool progress; + std::function progress_handler; bool suppress_warnings; bool warnings_exit_zero; bool copy_encryption; diff --git a/libqpdf/QPDFJob.cc b/libqpdf/QPDFJob.cc index 606a612a..5631df49 100644 --- a/libqpdf/QPDFJob.cc +++ b/libqpdf/QPDFJob.cc @@ -323,6 +323,7 @@ QPDFJob::Members::Members() : decrypt(false), split_pages(0), progress(false), + progress_handler(nullptr), suppress_warnings(false), warnings_exit_zero(false), copy_encryption(false), @@ -463,6 +464,11 @@ QPDFJob::setOutputStreams(std::ostream* out, std::ostream* err) this->m->log->setOutputStreams(out, err); } +void +QPDFJob::registerProgressReporter(std::function handler) { + this->m->progress_handler = handler; +} + void QPDFJob::doIfVerbose( std::function fn) @@ -3146,16 +3152,23 @@ QPDFJob::setWriterOptions(QPDF& pdf, QPDFWriter& w) w.forcePDFVersion(version, extension_level); } if (m->progress) { - char const* outfilename = this->m->outfilename - ? this->m->outfilename.get() - : "standard output"; - w.registerProgressReporter( - std::shared_ptr( - // line-break - new ProgressReporter( - *this->m->log->getInfo(), - this->m->message_prefix, - outfilename))); + if (this->m->progress_handler) { + w.registerProgressReporter( + std::shared_ptr( + new QPDFWriter::FunctionProgressReporter( + this->m->progress_handler))); + } else { + char const* outfilename = this->m->outfilename + ? this->m->outfilename.get() + : "standard output"; + w.registerProgressReporter( + std::shared_ptr( + // line-break + new ProgressReporter( + *this->m->log->getInfo(), + this->m->message_prefix, + outfilename))); + } } } diff --git a/qpdf/qtest/qpdf/filter-progress.pl b/qpdf/qtest/qpdf/filter-progress.pl index 97453fcb..943929af 100644 --- a/qpdf/qtest/qpdf/filter-progress.pl +++ b/qpdf/qtest/qpdf/filter-progress.pl @@ -4,10 +4,15 @@ use warnings; my $seen = 0; while (<>) { - if (m/write progress: (?:10)?0\%/) + if (m/write progress: 0\%/) { print; } + elsif (m/write progress: 100\%/) + { + print; + $seen = 0; + } elsif (m/write progress: /) { if (! $seen) diff --git a/qpdf/qtest/qpdf/job-api.out b/qpdf/qtest/qpdf/job-api.out index d69b2ac9..7ef99171 100644 --- a/qpdf/qtest/qpdf/job-api.out +++ b/qpdf/qtest/qpdf/job-api.out @@ -1,4 +1,11 @@ normal +qpdf: a.pdf: write progress: 0% +....other write progress.... +qpdf: a.pdf: write progress: 100% +custom progress reporter +custom write progress: 0% +....other write progress.... +custom write progress: 100% error caught by check finished config usage: an input file name is required diff --git a/qpdf/qtest/qpdfjob.test b/qpdf/qtest/qpdfjob.test index f6f40755..1c14a884 100644 --- a/qpdf/qtest/qpdfjob.test +++ b/qpdf/qtest/qpdfjob.test @@ -87,7 +87,8 @@ $td->runtest("QPDFJob json partial", {$td->FILE => "job-partial-json.out", $td->EXIT_STATUS => 0}, $td->NORMALIZE_NEWLINES); $td->runtest("QPDFJob API", - {$td->COMMAND => "test_driver 84 -"}, + {$td->COMMAND => "test_driver 84 -", + $td->FILTER => "perl filter-progress.pl"}, {$td->FILE => "job-api.out", $td->EXIT_STATUS => 0}, $td->NORMALIZE_NEWLINES); $td->runtest("check output", diff --git a/qpdf/test_driver.cc b/qpdf/test_driver.cc index 106f5f99..2384ddef 100644 --- a/qpdf/test_driver.cc +++ b/qpdf/test_driver.cc @@ -2937,6 +2937,27 @@ test_84(QPDF& pdf, char const* arg2) ->qdf() ->deterministicId() ->objectStreams("preserve") + ->progress() + ->checkConfiguration(); + j.run(); + assert(j.getExitCode() == 0); + assert(!j.hasWarnings()); + assert(j.getEncryptionStatus() == 0); + } + + std::cout << "custom progress reporter" << std::endl; + { + QPDFJob j; + j.registerProgressReporter([](int p) { + std::cout << "custom write progress: " << p << "%" << std::endl; + }); + j.config() + ->inputFile("minimal.pdf") + ->outputFile("a.pdf") + ->qdf() + ->deterministicId() + ->objectStreams("preserve") + ->progress() ->checkConfiguration(); j.run(); assert(j.getExitCode() == 0);