2
1
mirror of https://github.com/qpdf/qpdf.git synced 2024-12-22 19:08:59 +00:00

Merge pull request #916 from m-holger/job

Split QPDFJob::run into createQPDF and writeQPDF
This commit is contained in:
Jay Berkenbilt 2023-03-18 13:27:53 -04:00 committed by GitHub
commit 16f46703dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 1106 additions and 28 deletions

View File

@ -5,7 +5,7 @@ cmake_minimum_required(VERSION 3.16)
# the project line. When updating the version, check make_dist for all
# the places it has to be updated.
project(qpdf
VERSION 11.3.1
VERSION 11.4.0
LANGUAGES C CXX)
# Enable correct rpath handling for MacOSX

View File

@ -15,6 +15,7 @@ set(EXAMPLE_CXX_PROGRAMS
pdf-set-form-values
pdf-split-pages
qpdf-job
qpdfjob-remove-annotations
qpdfjob-save-attachment)
set(EXAMPLE_C_PROGRAMS
pdf-c-objects

View File

@ -0,0 +1,78 @@
#include <qpdf/QPDFJob.hh>
#include <qpdf/QPDFUsage.hh>
#include <qpdf/QUtil.hh>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
// This example demonstrates how we can use the QPDFJob createQPDF and writeQPDF
// methods to add custom transformations to the output produced by QPDFJob runs.
// The example is a full copy of the qpdf program modified to allways remove all
// annotations from the final output.
static char const* whoami = 0;
static void
usageExit(std::string const& msg)
{
std::cerr << std::endl
<< whoami << ": " << msg << std::endl
<< std::endl
<< "For help:" << std::endl
<< " " << whoami << " --help=usage usage information"
<< std::endl
<< " " << whoami << " --help=topic help on a topic"
<< std::endl
<< " " << whoami << " --help=--option help on an option"
<< std::endl
<< " " << whoami
<< " --help general help and a topic list"
<< std::endl
<< std::endl;
exit(QPDFJob::EXIT_ERROR);
}
int
realmain(int argc, char* argv[])
{
whoami = QUtil::getWhoami(argv[0]);
QUtil::setLineBuf(stdout);
QPDFJob j;
try {
// See "HOW TO ADD A COMMAND-LINE ARGUMENT" in README-maintainer.
j.initializeFromArgv(argv);
auto qpdf_sp = j.createQPDF();
auto& pdf = *qpdf_sp;
for (auto page: pdf.getAllPages()) {
page.replaceKey("/Annots", "null"_qpdf);
}
j.writeQPDF(pdf);
} catch (QPDFUsage& e) {
usageExit(e.what());
} catch (std::exception& e) {
std::cerr << whoami << ": " << e.what() << std::endl;
return QPDFJob::EXIT_ERROR;
}
return j.getExitCode();
}
#ifdef WINDOWS_WMAIN
extern "C" int
wmain(int argc, wchar_t* argv[])
{
return QUtil::call_main_from_wmain(argc, argv, realmain);
}
#else
int
main(int argc, char* argv[])
{
return realmain(argc, argv);
}
#endif

View File

@ -0,0 +1,28 @@
#!/usr/bin/env perl
require 5.008;
use warnings;
use strict;
chdir("qpdfjob-remove-annotations");
require TestDriver;
my $td = new TestDriver('qpdfjob-remove-annotations');
cleanup();
$td->runtest("remove-annotations",
{$td->COMMAND => "qpdfjob-remove-annotations --static-id annotations.pdf out.pdf"},
{$td->STRING => "", $td->EXIT_STATUS => 0});
$td->runtest("compare files",
{$td->FILE => "out.pdf"},
{$td->FILE => "annotations-out.pdf"});
cleanup();
$td->report(2);
sub cleanup
{
unlink("out.pdf");
}

View File

@ -0,0 +1,942 @@
%PDF-1.6
%¿÷¢þ
%QDF-1.0
1 0 obj
<<
/AcroForm <<
/DR 2 0 R
/Fields [
3 0 R
4 0 R
5 0 R
]
>>
/Names <<
/EmbeddedFiles 6 0 R
>>
/Pages 7 0 R
/Type /Catalog
>>
endobj
2 0 obj
<<
/Font <<
/F1 8 0 R
>>
>>
endobj
3 0 obj
<<
/AP <<
/N 9 0 R
>>
/DA (0 0.4 0 rg /F1 18 Tf)
/DR 2 0 R
/DV ()
/FT /Tx
/Ff 0
/Rect [
72
470.774
190.8
484.922
]
/Subtype /Widget
/T (Text Box 1)
/Type /Annot
/V (Formy field)
>>
endobj
4 0 obj
<<
/AP <<
/N 11 0 R
>>
/DA (0 0.4 0 rg /F1 18 Tf)
/DR 2 0 R
/DV ()
/FT /Tx
/Ff 0
/Rect [
372
330.774
386.148
470.374
]
/Subtype /Widget
/T (Text Box 1)
/Type /Annot
/V (Rot-ccw field)
>>
endobj
5 0 obj
<<
/DV /1
/FT /Btn
/Ff 49152
/Kids [
13 0 R
14 0 R
15 0 R
]
/T (r1)
/V /2
>>
endobj
6 0 obj
<<
/Names [
(attachment1.txt)
16 0 R
]
>>
endobj
7 0 obj
<<
/Count 1
/Kids [
17 0 R
]
/Type /Pages
>>
endobj
8 0 obj
<<
/BaseFont /Courier
/Encoding /WinAnsiEncoding
/Subtype /Type1
/Type /Font
>>
endobj
9 0 obj
<<
/BBox [
0
-2.826
118.8
11.322
]
/Resources 2 0 R
/Subtype /Form
/Type /XObject
/Length 10 0 R
>>
stream
/Tx BMC
q
BT
/F1 18 Tf
(Formy field) Tj
ET
Q
EMC
endstream
endobj
10 0 obj
53
endobj
11 0 obj
<<
/BBox [
0
-2.826
140.4
11.322
]
/Matrix [
0
1
-1
0
0
0
]
/Resources 2 0 R
/Subtype /Form
/Type /XObject
/Length 12 0 R
>>
stream
/Tx BMC
q
BT
/F1 18 Tf
(Rot-ccw field) Tj
ET
Q
EMC
endstream
endobj
12 0 obj
55
endobj
13 0 obj
<<
/AP <<
/N <<
/1 18 0 R
/Off 20 0 R
>>
>>
/AS /1
/DA (0.18039 0.20392 0.21176 rg /ZaDi 0 Tf)
/DR <<
/Font <<
/ZaDi 22 0 R
>>
>>
/F 4
/FT /Btn
/MK <<
/CA (l)
>>
/Parent 5 0 R
/Rect [
152.749
648.501
164.801
660.549
]
/Subtype /Widget
/Type /Annot
>>
endobj
14 0 obj
<<
/AP <<
/N <<
/2 23 0 R
/Off 25 0 R
>>
>>
/AS /2
/DA (0.18039 0.20392 0.21176 rg /ZaDi 0 Tf)
/DR <<
/Font <<
/ZaDi 22 0 R
>>
>>
/F 4
/FT /Btn
/MK <<
/CA (l)
>>
/Parent 5 0 R
/Rect [
152.749
627.301
164.801
639.349
]
/Subtype /Widget
/Type /Annot
>>
endobj
15 0 obj
<<
/AP <<
/N <<
/3 27 0 R
/Off 29 0 R
>>
>>
/AS /3
/DA (0.18039 0.20392 0.21176 rg /ZaDi 0 Tf)
/DR <<
/Font <<
/ZaDi 22 0 R
>>
>>
/F 4
/FT /Btn
/MK <<
/CA (l)
>>
/Parent 5 0 R
/Rect [
151.399
606.501
163.451
618.549
]
/Subtype /Widget
/Type /Annot
>>
endobj
16 0 obj
<<
/EF <<
/F 31 0 R
/UF 31 0 R
>>
/F (attachment1.txt)
/Type /Filespec
/UF (attachment1.txt)
>>
endobj
%% Page 1
17 0 obj
<<
/Annots [
33 0 R
3 0 R
34 0 R
4 0 R
35 0 R
36 0 R
37 0 R
38 0 R
13 0 R
14 0 R
15 0 R
]
/Contents 39 0 R
/MediaBox [
0
0
612
792
]
/Parent 7 0 R
/Resources 2 0 R
/Type /Page
>>
endobj
18 0 obj
<<
/BBox [
0
0
12.05
12.05
]
/Resources 41 0 R
/Subtype /Form
/Type /XObject
/Length 19 0 R
>>
stream
/Tx BMC
q BT
0.18039 0.20392 0.21176 rg /ZaDi 12.05 Tf
0 0 Td
ET
Q
1 0 0 rg
6 8.4 m 7.35 8.4 8.45 7.35 8.45 6 c
8.45 4.65 7.35 3.55 6 3.55 c
4.65 3.55 3.6 4.65 3.6 6 c
3.6 7.35 4.65 8.4 6 8.4 c f*
EMC
endstream
endobj
19 0 obj
202
endobj
20 0 obj
<<
/BBox [
0
0
12.05
12.05
]
/Resources 41 0 R
/Subtype /Form
/Type /XObject
/Length 21 0 R
>>
stream
/Tx BMC
EMC
endstream
endobj
21 0 obj
12
endobj
22 0 obj
<<
/BaseFont /ZapfDingbats
/Subtype /Type1
/Type /Font
>>
endobj
23 0 obj
<<
/BBox [
0
0
12.05
12.05
]
/Resources 41 0 R
/Subtype /Form
/Type /XObject
/Length 24 0 R
>>
stream
/Tx BMC
q BT
0.18039 0.20392 0.21176 rg /ZaDi 12.05 Tf
0 0 Td
ET
Q
0 1 0 rg
6 8.4 m 7.35 8.4 8.45 7.35 8.45 6 c
8.45 4.65 7.35 3.55 6 3.55 c
4.65 3.55 3.6 4.65 3.6 6 c
3.6 7.35 4.65 8.4 6 8.4 c f*
EMC
endstream
endobj
24 0 obj
202
endobj
25 0 obj
<<
/BBox [
0
0
12.05
12.05
]
/Resources 41 0 R
/Subtype /Form
/Type /XObject
/Length 26 0 R
>>
stream
/Tx BMC
EMC
endstream
endobj
26 0 obj
12
endobj
27 0 obj
<<
/BBox [
0
0
12.05
12.05
]
/Resources 41 0 R
/Subtype /Form
/Type /XObject
/Length 28 0 R
>>
stream
/Tx BMC
q BT
0.18039 0.20392 0.21176 rg /ZaDi 12.05 Tf
0 0 Td
ET
Q
0 0 1 rg
6 8.4 m 7.35 8.4 8.45 7.35 8.45 6 c
8.45 4.65 7.35 3.55 6 3.55 c
4.65 3.55 3.6 4.65 3.6 6 c
3.6 7.35 4.65 8.4 6 8.4 c f*
EMC
endstream
endobj
28 0 obj
202
endobj
29 0 obj
<<
/BBox [
0
0
12.05
12.05
]
/Resources 41 0 R
/Subtype /Form
/Type /XObject
/Length 30 0 R
>>
stream
/Tx BMC
EMC
endstream
endobj
30 0 obj
12
endobj
31 0 obj
<<
/Params <<
/CheckSum <80a33fc110b5a7b8b4d58b8d57e814bc>
/Size 22
/Subtype /text#2fplain
>>
/Type /EmbeddedFile
/Length 32 0 R
>>
stream
content of attachment
endstream
endobj
32 0 obj
22
endobj
33 0 obj
<<
/A <<
/S /URI
/URI (https://www.qbilt.org/)
>>
/Border [
0
0
.4
]
/C [
.8
.6
.6
]
/H /I
/Rect [
72
501.832
374.4
520.696
]
/Subtype /Link
/Type /Annot
>>
endobj
34 0 obj
<<
/AP <<
/N 42 0 R
>>
/Contents (attachment1.txt)
/FS 16 0 R
/NM (attachment1.txt)
/Rect [
72
400
92
420
]
/Subtype /FileAttachment
/Type /Annot
>>
endobj
35 0 obj
<<
/AP <<
/N 44 0 R
>>
/DA ()
/Rect [
72
350
92
360
]
/Subtype /FreeText
/Type /Annot
>>
endobj
36 0 obj
<<
/AP <<
/N 46 0 R
>>
/DA ()
/Rect [
102
350
112
370
]
/Subtype /FreeText
/Type /Annot
>>
endobj
37 0 obj
<<
/AP <<
/N 48 0 R
>>
/DA ()
/Rect [
122
350
142
360
]
/Subtype /FreeText
/Type /Annot
>>
endobj
38 0 obj
<<
/AP <<
/N 50 0 R
>>
/DA ()
/Rect [
152
350
162
370
]
/Subtype /FreeText
/Type /Annot
>>
endobj
%% Contents for page 1
39 0 obj
<<
/Length 40 0 R
>>
stream
q
1 1 .7 rg
.5 .5 0 RG
72 470.77 118.8 14.15 re
B
Q
q
0 .5 .5 RG
0 1 1 rg
372 330.77 14.15 139.4 re
B
Q
q
1 0 0 RG
72 310 20 10 re
72 310 5 10 re
S
0 1 0 RG
102 310 10 20 re
102 310 10 5 re
S
0 0 1 RG
122 310 20 10 re
137 310 5 10 re
S
0.5 0 1 RG
152 310 10 20 re
152 325 10 5 re
S
10 w
0.14 .33 .18 RG
5 5 602 782 re
S
Q
BT
/F1 16 Tf
20.6 TL
170 650 Td
(radio button 1) Tj
(radio button 2) '
(radio button 3) '
1 0 0 1 72 546 Tm
/F1 20 Tf
(Thick green border surrounds page.) Tj
0 -40 Td
/F1 24 Tf
0 0 1 rg
(https://www.qbilt.org) Tj
/F1 12 Tf
1 0 0 1 202 474 Tm
(<- Formy field in yellow) Tj
1 0 0 1 392 410 Tm
14.4 TL
(<- Rot-ccw field) Tj
(with "Rot" at bottom) '
(and text going up) '
0 g
1 0 0 1 102 405 Tm
(Arrow to the left points down.) Tj
1 0 0 1 182 310 Tm
(<- Drawn rectangles appear below annotations.) Tj
ET
endstream
endobj
40 0 obj
874
endobj
41 0 obj
<<
/Font 52 0 R
/ProcSet [
/PDF
/Text
]
>>
endobj
42 0 obj
<<
/BBox [
0
0
20
20
]
/Resources <<
>>
/Subtype /Form
/Type /XObject
/Length 43 0 R
>>
stream
0 10 m
10 0 l
20 10 l
10 0 m
10 20 l
0 0 20 20 re
S
endstream
endobj
43 0 obj
52
endobj
44 0 obj
<<
/BBox [
0
0
20
10
]
/Resources 2 0 R
/Subtype /Form
/Type /XObject
/Length 45 0 R
>>
stream
1 0 0 RG
0 0 20 10 re
0 0 5 10 re
S
endstream
endobj
45 0 obj
36
endobj
46 0 obj
<<
/BBox [
0
0
20
10
]
/Matrix [
0
1
-1
0
0
0
]
/Resources 2 0 R
/Subtype /Form
/Type /XObject
/Length 47 0 R
>>
stream
0 1 0 RG
0 0 20 10 re
0 0 5 10 re
S
endstream
endobj
47 0 obj
36
endobj
48 0 obj
<<
/BBox [
0
0
20
10
]
/Matrix [
-1
0
0
-1
0
0
]
/Resources 2 0 R
/Subtype /Form
/Type /XObject
/Length 49 0 R
>>
stream
0 0 1 RG
0 0 20 10 re
0 0 5 10 re
S
endstream
endobj
49 0 obj
36
endobj
50 0 obj
<<
/BBox [
0
0
20
10
]
/Matrix [
0
-1
1
0
0
0
]
/Resources 2 0 R
/Subtype /Form
/Type /XObject
/Length 51 0 R
>>
stream
0.5 0 1 RG
0 0 20 10 re
0 0 5 10 re
S
endstream
endobj
51 0 obj
38
endobj
52 0 obj
<<
/ZaDi 22 0 R
>>
endobj
xref
0 53
0000000000 65535 f
0000000025 00000 n
0000000211 00000 n
0000000263 00000 n
0000000506 00000 n
0000000755 00000 n
0000000874 00000 n
0000000944 00000 n
0000001017 00000 n
0000001121 00000 n
0000001335 00000 n
0000001355 00000 n
0000001625 00000 n
0000001645 00000 n
0000001997 00000 n
0000002349 00000 n
0000002701 00000 n
0000002842 00000 n
0000003114 00000 n
0000003473 00000 n
0000003494 00000 n
0000003663 00000 n
0000003683 00000 n
0000003764 00000 n
0000004123 00000 n
0000004144 00000 n
0000004313 00000 n
0000004333 00000 n
0000004692 00000 n
0000004713 00000 n
0000004882 00000 n
0000004902 00000 n
0000005110 00000 n
0000005130 00000 n
0000005374 00000 n
0000005578 00000 n
0000005718 00000 n
0000005860 00000 n
0000006002 00000 n
0000006167 00000 n
0000007098 00000 n
0000007119 00000 n
0000007193 00000 n
0000007397 00000 n
0000007417 00000 n
0000007603 00000 n
0000007623 00000 n
0000007862 00000 n
0000007882 00000 n
0000008122 00000 n
0000008142 00000 n
0000008383 00000 n
0000008403 00000 n
trailer <<
/Root 1 0 R
/Size 53
/ID [<a2f146daeb6d814a742556489dab9882><7b639c67bfc16b5e891fa5468aac3a14>]
>>
startxref
8441
%%EOF

View File

@ -25,9 +25,9 @@
/* The first version of qpdf to include the version constants is 10.6.0. */
#define QPDF_MAJOR_VERSION 11
#define QPDF_MINOR_VERSION 3
#define QPDF_PATCH_VERSION 1
#define QPDF_VERSION "11.3.1"
#define QPDF_MINOR_VERSION 4
#define QPDF_PATCH_VERSION 0
#define QPDF_VERSION "11.4.0"
/*
* This file defines symbols that control the which functions,

View File

@ -397,6 +397,21 @@ class QPDFJob
QPDF_DLL
void run();
// The following two methods allow a job to be run in two stages - creation
// of a QPDF object and writing of the QPDF object. This allows the QPDF
// object to be modified prior to writing it out. See
// examples/qpdfjob-remove-annotations for an illustration of its use.
// Run the first stage of the job. Return a nullptr if the configuration is
// not valid.
QPDF_DLL
std::unique_ptr<QPDF> createQPDF();
// Run the second stage of the job. Do nothing if a nullptr is passed as
// parameter.
QPDF_DLL
void writeQPDF(QPDF& qpdf);
// CHECK STATUS -- these methods provide information known after
// run() is called.
@ -474,7 +489,7 @@ class QPDFJob
std::string to_nr;
std::string from_nr;
std::string repeat_nr;
std::shared_ptr<QPDF> pdf;
std::unique_ptr<QPDF> pdf;
std::vector<int> to_pagenos;
std::vector<int> from_pagenos;
std::vector<int> repeat_pagenos;
@ -490,25 +505,25 @@ class QPDFJob
// Basic file processing
void processFile(
std::shared_ptr<QPDF>&,
std::unique_ptr<QPDF>&,
char const* filename,
char const* password,
bool used_for_input,
bool main_input);
void processInputSource(
std::shared_ptr<QPDF>&,
std::unique_ptr<QPDF>&,
std::shared_ptr<InputSource> is,
char const* password,
bool used_for_input);
void doProcess(
std::shared_ptr<QPDF>&,
std::unique_ptr<QPDF>&,
std::function<void(QPDF*, char const*)> fn,
char const* password,
bool empty,
bool used_for_input,
bool main_input);
void doProcessOnce(
std::shared_ptr<QPDF>&,
std::unique_ptr<QPDF>&,
std::function<void(QPDF*, char const*)> fn,
char const* password,
bool empty,
@ -518,7 +533,7 @@ class QPDFJob
// Transformations
void setQPDFOptions(QPDF& pdf);
void
handlePageSpecs(QPDF& pdf, std::vector<std::shared_ptr<QPDF>>& page_heap);
handlePageSpecs(QPDF& pdf, std::vector<std::unique_ptr<QPDF>>& page_heap);
bool shouldRemoveUnreferencedResources(QPDF& pdf);
void handleRotations(QPDF& pdf);
void

View File

@ -447,11 +447,11 @@ QPDFJob::parseNumrange(char const* range, int max)
return std::vector<int>();
}
void
QPDFJob::run()
std::unique_ptr<QPDF>
QPDFJob::createQPDF()
{
checkConfiguration();
std::shared_ptr<QPDF> pdf_sp;
std::unique_ptr<QPDF> pdf_sp;
try {
processFile(pdf_sp, m->infilename.get(), m->password.get(), true, true);
} catch (QPDFExc& e) {
@ -461,12 +461,12 @@ QPDFJob::run()
if (m->check_is_encrypted || m->check_requires_password) {
this->m->encryption_status =
qpdf_es_encrypted | qpdf_es_password_incorrect;
return;
return nullptr;
}
if (m->show_encryption && pdf_sp) {
this->m->log->info("Incorrect password supplied\n");
showEncryption(*pdf_sp);
return;
return nullptr;
}
}
throw e;
@ -477,7 +477,7 @@ QPDFJob::run()
}
if (m->check_is_encrypted || m->check_requires_password) {
return;
return nullptr;
}
// If we are updating from JSON, this has to be done first before
@ -486,7 +486,7 @@ QPDFJob::run()
pdf.updateFromJSON(this->m->update_from_json);
}
std::vector<std::shared_ptr<QPDF>> page_heap;
std::vector<std::unique_ptr<QPDF>> page_heap;
if (!m->page_specs.empty()) {
handlePageSpecs(pdf, page_heap);
}
@ -495,7 +495,12 @@ QPDFJob::run()
}
handleUnderOverlay(pdf);
handleTransformations(pdf);
return pdf_sp;
}
void
QPDFJob::writeQPDF(QPDF& pdf)
{
if (!createsOutput()) {
doInspection(pdf);
} else if (m->split_pages) {
@ -527,6 +532,15 @@ QPDFJob::run()
}
}
void
QPDFJob::run()
{
auto pdf = createQPDF();
if (pdf) {
writeQPDF(*pdf);
}
}
bool
QPDFJob::hasWarnings() const
{
@ -1868,14 +1882,14 @@ QPDFJob::doInspection(QPDF& pdf)
void
QPDFJob::doProcessOnce(
std::shared_ptr<QPDF>& pdf,
std::unique_ptr<QPDF>& pdf,
std::function<void(QPDF*, char const*)> fn,
char const* password,
bool empty,
bool used_for_input,
bool main_input)
{
pdf = QPDF::create();
pdf = std::make_unique<QPDF>();
setQPDFOptions(*pdf);
if (empty) {
pdf->emptyPDF();
@ -1892,7 +1906,7 @@ QPDFJob::doProcessOnce(
void
QPDFJob::doProcess(
std::shared_ptr<QPDF>& pdf,
std::unique_ptr<QPDF>& pdf,
std::function<void(QPDF*, char const*)> fn,
char const* password,
bool empty,
@ -1976,7 +1990,7 @@ QPDFJob::doProcess(
void
QPDFJob::processFile(
std::shared_ptr<QPDF>& pdf,
std::unique_ptr<QPDF>& pdf,
char const* filename,
char const* password,
bool used_for_input,
@ -1996,7 +2010,7 @@ QPDFJob::processFile(
void
QPDFJob::processInputSource(
std::shared_ptr<QPDF>& pdf,
std::unique_ptr<QPDF>& pdf,
std::shared_ptr<InputSource> is,
char const* password,
bool used_for_input)
@ -2278,7 +2292,7 @@ QPDFJob::copyAttachments(QPDF& pdf)
v << prefix << ": copying attachments from " << to_copy.path
<< "\n";
});
std::shared_ptr<QPDF> other;
std::unique_ptr<QPDF> other;
processFile(
other,
to_copy.path.c_str(),
@ -2540,7 +2554,7 @@ added_page(QPDF& pdf, QPDFPageObjectHelper page)
void
QPDFJob::handlePageSpecs(
QPDF& pdf, std::vector<std::shared_ptr<QPDF>>& page_heap)
QPDF& pdf, std::vector<std::unique_ptr<QPDF>>& page_heap)
{
// Parse all page specifications and translate them into lists of
// actual pages.
@ -2612,10 +2626,10 @@ QPDFJob::handlePageSpecs(
new FileInputSource(page_spec.filename.c_str());
is = std::shared_ptr<InputSource>(fis);
}
std::shared_ptr<QPDF> qpdf_sp;
std::unique_ptr<QPDF> qpdf_sp;
processInputSource(qpdf_sp, is, password, true);
page_heap.push_back(qpdf_sp);
page_spec_qpdfs[page_spec.filename] = qpdf_sp.get();
page_heap.push_back(std::move(qpdf_sp));
if (cis) {
cis->stayOpen(false);
page_spec_cfis[page_spec.filename] = cis;
@ -3116,7 +3130,7 @@ QPDFJob::setWriterOptions(QPDF& pdf, QPDFWriter& w)
w.setSuppressOriginalObjectIDs(true);
}
if (m->copy_encryption) {
std::shared_ptr<QPDF> encryption_pdf;
std::unique_ptr<QPDF> encryption_pdf;
processFile(
encryption_pdf,
m->encryption_file.c_str(),

View File

@ -16,7 +16,7 @@ project = 'QPDF'
copyright = '2005-2023, Jay Berkenbilt'
author = 'Jay Berkenbilt'
# make_dist and the CI build lexically find the release version from this file.
release = '11.3.1'
release = '11.4.0'
version = release
extensions = [
'sphinx_rtd_theme',