implement ability to save PDF to memory, also update ChangeLog

This commit is contained in:
Jay Berkenbilt 2011-08-10 16:34:29 -04:00
parent 655c55f848
commit 759c56e1fe
4 changed files with 151 additions and 40 deletions

View File

@ -1,3 +1,20 @@
2011-08-10 Jay Berkenbilt <ejb@ql.org>
* include/qpdf/QPDFWriter.hh: add a new constructor that takes
only a QPDF reference and leaves specification of output for
later. Add methods setOutputFilename() to set the output to a
filename or stdout, and setOutputMemory() to indicate that output
should go to a memory buffer. Add method getBuffer() to retrieve
the buffer used if output was saved to a memory buffer.
* include/qpdf/QPDF.hh: add methods replaceObject() and
swapObjects() to allow replacement of an object and swapping of
two objects by object ID.
* include/qpdf/QPDFObjectHandle.hh: add new methods getDictAsMap()
and getArrayAsVector() for returning the elements of a dictionary
or an array as a map or vector.
2011-06-25 Jay Berkenbilt <ejb@ql.org>
* 2.2.4: release

View File

@ -24,6 +24,7 @@
#include <qpdf/QPDFXRefEntry.hh>
#include <qpdf/Pl_Buffer.hh>
#include <qpdf/PointerHolder.hh>
#include <qpdf/Pipeline.hh>
#include <qpdf/Buffer.hh>
@ -35,6 +36,24 @@ class Pl_Count;
class QPDFWriter
{
public:
// Construct a QPDFWriter object without specifying output. You
// must call one of the output setting routines defined below.
QPDF_DLL
QPDFWriter(QPDF& pdf);
// Create a QPDFWriter object that writes its output to a file or
// to stdout. This is equivalent to using the previous
// constructor and then calling setOutputFilename(). See
// setOutputFilename() for details.
QPDF_DLL
QPDFWriter(QPDF& pdf, char const* filename);
QPDF_DLL
~QPDFWriter();
// Setting Output. Output may be set only one time. If you don't
// use the filename version of the QPDFWriter constructor, you
// must call exactly one of these methods.
// Passing null as filename means write to stdout. QPDFWriter
// will create a zero-length output file upon construction. If
// write fails, the empty or partially written file will not be
@ -42,10 +61,20 @@ class QPDFWriter
// useful for tracking down problems. If your application doesn't
// want the partially written file to be left behind, you should
// delete it the eventual call to write fails.
QPDF_DLL
QPDFWriter(QPDF& pdf, char const* filename);
QPDF_DLL
~QPDFWriter();
void setOutputFilename(char const* filename);
// Indicate that QPDFWriter should create a memory buffer to
// contain the final PDF file. Obtain the memory by calling
// getBuffer().
void setOutputMemory();
// Return the buffer object containing the PDF file. If
// setOutputMemory() has been called, this method may be called
// exactly one time after write() has returned. The caller is
// responsible for deleting the buffer when done.
Buffer* getBuffer();
// Setting Parameters
// Set the value of object stream mode. In disable mode, we never
// generate any object streams. In preserve mode, we preserve
@ -177,6 +206,7 @@ class QPDFWriter
enum trailer_e { t_normal, t_lin_first, t_lin_second };
void init();
int bytesNeeded(unsigned long n);
void writeBinary(unsigned long val, unsigned int bytes);
void writeString(std::string const& str);
@ -253,6 +283,7 @@ class QPDFWriter
// clearPipelineStack is called.
Pipeline* pushPipeline(Pipeline*);
void activatePipelineStack();
void initializePipelineStack(Pipeline *);
// Calls finish on the current pipeline and pops the pipeline
// stack until the top of stack is a previous active top of stack,
@ -269,6 +300,8 @@ class QPDFWriter
char const* filename;
FILE* file;
bool close_file;
Pl_Buffer* buffer_pipeline;
Buffer* output_buffer;
bool normalize_content_set;
bool normalize_content;
bool stream_data_mode_set;

View File

@ -4,7 +4,6 @@
#include <qpdf/Pl_StdioFile.hh>
#include <qpdf/Pl_Count.hh>
#include <qpdf/Pl_Discard.hh>
#include <qpdf/Pl_Buffer.hh>
#include <qpdf/Pl_RC4.hh>
#include <qpdf/Pl_AES_PDF.hh>
#include <qpdf/Pl_Flate.hh>
@ -21,32 +20,65 @@
#include <stdlib.h>
QPDFWriter::QPDFWriter(QPDF& pdf, char const* filename) :
pdf(pdf),
filename(filename),
file(0),
close_file(false),
normalize_content_set(false),
normalize_content(false),
stream_data_mode_set(false),
stream_data_mode(qpdf_s_compress),
qdf_mode(false),
static_id(false),
suppress_original_object_ids(false),
direct_stream_lengths(true),
encrypted(false),
preserve_encryption(true),
linearized(false),
object_stream_mode(qpdf_o_preserve),
encrypt_metadata(true),
encrypt_use_aes(false),
encryption_dict_objid(0),
next_objid(1),
cur_stream_length_id(0),
cur_stream_length(0),
added_newline(false),
max_ostream_index(0)
QPDFWriter::QPDFWriter(QPDF& pdf) :
pdf(pdf)
{
init();
}
QPDFWriter::QPDFWriter(QPDF& pdf, char const* filename) :
pdf(pdf)
{
init();
setOutputFilename(filename);
}
void
QPDFWriter::init()
{
filename = 0;
file = 0;
close_file = false;
buffer_pipeline = 0;
output_buffer = 0;
normalize_content_set = false;
normalize_content = false;
stream_data_mode_set = false;
stream_data_mode = qpdf_s_compress;
qdf_mode = false;
static_id = false;
suppress_original_object_ids = false;
direct_stream_lengths = true;
encrypted = false;
preserve_encryption = true;
linearized = false;
object_stream_mode = qpdf_o_preserve;
encrypt_metadata = true;
encrypt_use_aes = false;
encryption_dict_objid = 0;
next_objid = 1;
cur_stream_length_id = 0;
cur_stream_length = 0;
added_newline = false;
max_ostream_index = 0;
}
QPDFWriter::~QPDFWriter()
{
if (file && close_file)
{
fclose(file);
}
if (output_buffer)
{
delete output_buffer;
}
}
void
QPDFWriter::setOutputFilename(char const* filename)
{
this->filename = filename;
if (filename == 0)
{
this->filename = "standard output";
@ -61,19 +93,25 @@ QPDFWriter::QPDFWriter(QPDF& pdf, char const* filename) :
fopen(filename, "wb+"));
close_file = true;
}
Pipeline* p = new Pl_StdioFile("qdf output", file);
Pipeline* p = new Pl_StdioFile("qpdf output", file);
to_delete.push_back(p);
pipeline = new Pl_Count("qdf count", p);
to_delete.push_back(pipeline);
pipeline_stack.push_back(pipeline);
initializePipelineStack(p);
}
QPDFWriter::~QPDFWriter()
void
QPDFWriter::setOutputMemory()
{
if (file && close_file)
{
fclose(file);
}
this->buffer_pipeline = new Pl_Buffer("qpdf output");
to_delete.push_back(this->buffer_pipeline);
initializePipelineStack(this->buffer_pipeline);
}
Buffer*
QPDFWriter::getBuffer()
{
Buffer* result = this->output_buffer;
this->output_buffer = 0;
return result;
}
void
@ -565,6 +603,14 @@ QPDFWriter::pushPipeline(Pipeline* p)
return p;
}
void
QPDFWriter::initializePipelineStack(Pipeline *p)
{
this->pipeline = new Pl_Count("qpdf count", p);
to_delete.push_back(this->pipeline);
this->pipeline_stack.push_back(this->pipeline);
}
void
QPDFWriter::activatePipelineStack()
{
@ -1503,6 +1549,8 @@ QPDFWriter::generateObjectStreams()
void
QPDFWriter::write()
{
// XXX Check output
// Do preliminary setup
if (this->linearized)
@ -1656,6 +1704,11 @@ QPDFWriter::write()
fclose(this->file);
}
this->file = 0;
if (this->buffer_pipeline)
{
this->output_buffer = this->buffer_pipeline->getBuffer();
this->buffer_pipeline = 0;
}
}
void

View File

@ -584,10 +584,18 @@ void runtest(int n, char const* filename)
<< std::endl;
}
QPDFWriter w(pdf, "a.pdf");
// Exercise writing to memory buffer
QPDFWriter w(pdf);
w.setOutputMemory();
w.setStaticID(true);
w.setStreamDataMode(qpdf_s_preserve);
w.write();
Buffer* b = w.getBuffer();
FILE* f = QUtil::fopen_wrapper(std::string("open a.pdf"),
fopen("a.pdf", "wb"));
fwrite(b->getBuffer(), b->getSize(), 1, f);
fclose(f);
delete b;
}
else
{