2
1
mirror of https://github.com/qpdf/qpdf.git synced 2024-06-08 13:20:53 +00:00

Merge pull request #933 from m-holger/c_job

C-API : expose QPDFJob::createQPDF and writeQPDF
This commit is contained in:
Jay Berkenbilt 2023-04-02 09:01:26 -04:00 committed by GitHub
commit 230f1ab290
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 130 additions and 46 deletions

View File

@ -32,6 +32,7 @@
*/
#include <qpdf/DLL.h>
#include <qpdf/qpdf-c.h>
#include <qpdf/qpdflogger-c.h>
#include <string.h>
#ifndef QPDF_NO_WCHAR_T
@ -138,6 +139,28 @@ extern "C" {
QPDF_DLL
int qpdfjob_run(qpdfjob_handle j);
/* The following two functions allow a job to be run in two stages -
* creation of a qpdf_data object and writing of the qpdf_data object. This
* allows the qpdf_data object to be modified prior to writing it out. See
* examples/qpdfjob-remove-annotations for a C++ illustration of its use.
*
* This function wraps QPDFJob::createQPDF. It runs the first stage of the
* job. A nullptr is returned if the job did not produce any pdf file to be
* written.
*/
QPDF_DLL
qpdf_data qpdfjob_create_qpdf(qpdfjob_handle j);
/* This function wraps QPDFJob::writeQPDF. It returns the error code that
* qpdf would return with the equivalent command-line invocation. Exit code
* values are defined in Constants.h in the qpdf_exit_code_e type. NOTE it
* is the callers responsibility to clean up the resources associated
* qpdf_data object by calling qpdf_cleanup after the call to
* qpdfjob_write_qpdf.
*/
QPDF_DLL
int qpdfjob_write_qpdf(qpdfjob_handle j, qpdf_data qpdf);
/* Allow specification of a custom progress reporter. The progress
* reporter is only used if progress is otherwise requested (with
* the --progress option or "progress": "" in the JSON).

View File

@ -12,6 +12,7 @@
#include <qpdf/QPDFWriter.hh>
#include <qpdf/QTC.hh>
#include <qpdf/QUtil.hh>
#include <qpdf/qpdf-c_impl.hh>
#include <qpdf/qpdflogger-c_impl.hh>
#include <cstring>
@ -20,50 +21,6 @@
#include <stdexcept>
#include <string>
struct _qpdf_error
{
std::shared_ptr<QPDFExc> exc;
};
struct _qpdf_data
{
_qpdf_data();
~_qpdf_data() = default;
std::shared_ptr<QPDF> qpdf;
std::shared_ptr<QPDFWriter> qpdf_writer;
std::shared_ptr<QPDFExc> error;
_qpdf_error tmp_error;
std::list<QPDFExc> warnings;
std::string tmp_string;
// Parameters for functions we call
char const* filename; // or description
char const* buffer;
unsigned long long size;
char const* password;
bool write_memory;
std::shared_ptr<Buffer> output_buffer;
// QPDFObjectHandle support
bool silence_errors;
bool oh_error_occurred;
std::map<qpdf_oh, std::shared_ptr<QPDFObjectHandle>> oh_cache;
qpdf_oh next_oh;
std::set<std::string> cur_iter_dict_keys;
std::set<std::string>::const_iterator dict_iter;
std::string cur_dict_key;
};
_qpdf_data::_qpdf_data() :
write_memory(false),
silence_errors(false),
oh_error_occurred(false),
next_oh(0)
{
}
// must set qpdf->filename and qpdf->password
static void
call_read(qpdf_data qpdf)

View File

@ -0,0 +1,47 @@
#include <qpdf/qpdf-c.h>
#include <memory>
#include <qpdf/QPDF.hh>
#include <qpdf/QPDFExc.hh>
#include <qpdf/QPDFWriter.hh>
struct _qpdf_error
{
std::shared_ptr<QPDFExc> exc;
};
struct _qpdf_data
{
_qpdf_data() = default;
_qpdf_data(std::unique_ptr<QPDF>&& qpdf) :
qpdf(std::move(qpdf)){};
~_qpdf_data() = default;
std::shared_ptr<QPDF> qpdf;
std::shared_ptr<QPDFWriter> qpdf_writer;
std::shared_ptr<QPDFExc> error;
_qpdf_error tmp_error;
std::list<QPDFExc> warnings;
std::string tmp_string;
// Parameters for functions we call
char const* filename{nullptr}; // or description
char const* buffer{nullptr};
unsigned long long size{0};
char const* password{nullptr};
bool write_memory{false};
std::shared_ptr<Buffer> output_buffer;
// QPDFObjectHandle support
bool silence_errors{false};
bool oh_error_occurred{false};
std::map<qpdf_oh, std::shared_ptr<QPDFObjectHandle>> oh_cache;
qpdf_oh next_oh{0};
std::set<std::string> cur_iter_dict_keys;
std::set<std::string>::const_iterator dict_iter;
std::string cur_dict_key;
};

View File

@ -4,6 +4,7 @@
#include <qpdf/QPDFLogger.hh>
#include <qpdf/QPDFUsage.hh>
#include <qpdf/QUtil.hh>
#include <qpdf/qpdf-c_impl.hh>
#include <qpdf/qpdflogger-c_impl.hh>
#include <cstdio>
@ -98,6 +99,30 @@ qpdfjob_run(qpdfjob_handle j)
});
}
qpdf_data
qpdfjob_create_qpdf(qpdfjob_handle j)
{
QUtil::setLineBuf(stdout);
try {
auto qpdf = j->j.createQPDF();
return qpdf ? new _qpdf_data(std::move(qpdf)) : nullptr;
} catch (std::exception& e) {
*j->j.getLogger()->getError()
<< j->j.getMessagePrefix() << ": " << e.what() << "\n";
}
return nullptr;
}
int
qpdfjob_write_qpdf(qpdfjob_handle j, qpdf_data qpdf)
{
QUtil::setLineBuf(stdout);
return wrap_qpdfjob(j, [qpdf](qpdfjob_handle jh) {
jh->j.writeQPDF(*(qpdf->qpdf));
return jh->j.getExitCode();
});
}
static int
run_with_handle(std::function<int(qpdfjob_handle)> fn)
{

View File

@ -97,6 +97,33 @@ run_tests()
assert(qpdfjob_run(j) == 2);
qpdfjob_cleanup(&j);
printf("json error test passed\n");
/* qpdfjob_create_qpdf and qpdfjob_write_qpdf test */
argv[0] = "qpdfjob";
argv[1] = "minimal.pdf";
argv[2] = "d.pdf";
argv[3] = "--deterministic-id";
argv[4] = "--progress";
argv[5] = NULL;
j = qpdfjob_init();
assert(qpdfjob_initialize_from_argv(j, argv) == 0);
qpdf_data qpdf = qpdfjob_create_qpdf(j);
assert(qpdfjob_write_qpdf(j, qpdf) == 0);
qpdf_cleanup(&qpdf);
qpdfjob_cleanup(&j);
/* Try to open a missing file to test case of QPDFJob::createQPDF returning
* nullptr.
*/
argv[0] = "qpdfjob";
argv[1] = "m.pdf";
argv[2] = "--check";
argv[3] = NULL;
j = qpdfjob_init();
assert(qpdfjob_initialize_from_argv(j, argv) == 0);
assert(qpdfjob_create_qpdf(j) == NULL);
qpdfjob_cleanup(&j);
printf("qpdfjob_create_qpdf and qpdfjob_write_qpdf test passed\n");
}
int

View File

@ -9,3 +9,8 @@ json warn test passed
|custom|qpdfjob json|custom|: |custom|an output file name is required; use - for standard output|custom|
|custom|qpdfjob json|custom|: |custom|an output file name is required; use - for standard output|custom|
json error test passed
qpdfjob: d.pdf: write progress: 0%
....other write progress....
qpdfjob: d.pdf: write progress: 100%
qpdfjob: open m.pdf: No such file or directory
qpdfjob_create_qpdf and qpdfjob_write_qpdf test passed

Binary file not shown.

View File

@ -43,7 +43,7 @@ my @good_json = (
"underlay-overlay-password",
"misc-options",
);
my $n_tests = 10 + scalar(@bad_json) + (2 * scalar(@good_json));
my $n_tests = 11 + scalar(@bad_json) + (2 * scalar(@good_json));
foreach my $i (@bad_json)
@ -104,7 +104,7 @@ $td->runtest("C job API",
$td->FILTER => "perl filter-progress.pl"},
{$td->FILE => "qpdfjob-ctest.out", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
foreach my $i (['a.pdf', 1], ['b.pdf', 2], ['c.pdf', 3])
foreach my $i (['a.pdf', 1], ['b.pdf', 2], ['c.pdf', 3], ['d.pdf', 4])
{
$td->runtest("check output",
{$td->FILE => $i->[0]},