diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2023-01-06 10:02:49 +0200 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2023-01-06 10:04:59 +0200 |
commit | 1145733c29db0a678537ce99ff60e21613f622a8 (patch) | |
tree | 63d5d6c324629d4eef1354db3c97f857d6016a34 /lib/pdf | |
download | iscan-1145733c29db0a678537ce99ff60e21613f622a8.tar.gz |
Import iscan 2.30.4-2
Diffstat (limited to 'lib/pdf')
-rw-r--r-- | lib/pdf/Makefile.am | 44 | ||||
-rw-r--r-- | lib/pdf/array.cc | 115 | ||||
-rw-r--r-- | lib/pdf/array.hh | 87 | ||||
-rw-r--r-- | lib/pdf/dictionary.cc | 123 | ||||
-rw-r--r-- | lib/pdf/dictionary.hh | 93 | ||||
-rw-r--r-- | lib/pdf/object.cc | 103 | ||||
-rw-r--r-- | lib/pdf/object.hh | 120 | ||||
-rw-r--r-- | lib/pdf/primitive.cc | 100 | ||||
-rw-r--r-- | lib/pdf/primitive.hh | 92 | ||||
-rw-r--r-- | lib/pdf/writer.cc | 236 | ||||
-rw-r--r-- | lib/pdf/writer.hh | 165 |
11 files changed, 1278 insertions, 0 deletions
diff --git a/lib/pdf/Makefile.am b/lib/pdf/Makefile.am new file mode 100644 index 0000000..4cc3e95 --- /dev/null +++ b/lib/pdf/Makefile.am @@ -0,0 +1,44 @@ +## Makefile.am -- an automake template for a Makefile.in file +## Copyright (C) 2008 SEIKO EPSON CORPORATION +## +## This file is part of the "Image Scan!" build infra-structure. +## +## The "Image Scan!" build infra-structure is free software. +## You can redistribute it and/or modify it under the terms of the GNU +## General Public License as published by the Free Software Foundation; +## either version 2 of the License or at your option any later version. +## +## This program is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of FITNESS +## FOR A PARTICULAR PURPOSE or MERCHANTABILITY. +## See the GNU General Public License for more details. +## +## You should have received a verbatim copy of the GNU General Public +## License along with this program; if not, write to: +## +## Free Software Foundation, Inc. +## 59 Temple Place, Suite 330 +## Boston, MA 02111-1307 USA + + +if ENABLE_FRONTEND +noinst_LTLIBRARIES = libpdf.la +libpdf_la_LDFLAGS = -static +libpdf_la_SOURCES = \ + $(libpdf_la_files) +endif + +libpdf_la_files = \ + array.cc \ + array.hh \ + dictionary.cc \ + dictionary.hh \ + object.cc \ + object.hh \ + primitive.cc \ + primitive.hh \ + writer.cc \ + writer.hh + +EXTRA_DIST = \ + $(libpdf_la_files) diff --git a/lib/pdf/array.cc b/lib/pdf/array.cc new file mode 100644 index 0000000..812ee03 --- /dev/null +++ b/lib/pdf/array.cc @@ -0,0 +1,115 @@ +// array.cc -- PDF array objects +// Copyright (C) 2008 SEIKO EPSON CORPORATION +// +// This file is part of the 'iscan' program. +// +// The 'iscan' program is free-ish software. +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation; +// either version 2 of the License or at your option any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of FITNESS +// FOR A PARTICULAR PURPOSE or MERCHANTABILITY. +// See the GNU General Public License for more details. +// +// You should have received a verbatim copy of the GNU General Public +// License along with this program; if not, write to: +// +// Free Software Foundation, Inc. +// 59 Temple Place, Suite 330 +// Boston, MA 02111-1307 USA +// +// As a special exception, the copyright holders give permission +// to link the code of this program with the esmod library and +// distribute linked combinations including the two. You must obey +// the GNU General Public License in all respects for all of the +// code used other than esmod. + + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "array.hh" + +namespace iscan +{ + +namespace pdf +{ + +array::~array () +{ + store_citer it; + + for (it = _mine.begin (); _mine.end () != it; ++it) + { + object* obj = *it; + delete obj; + obj = NULL; + } +} + +void +array::insert (object *value) +{ + _store.push_back (value); +} + +void +array::insert (primitive value) +{ + primitive *copy = new primitive (); + + *copy = value; + _mine.push_back (copy); + insert (copy); +} + +void +array::insert (object value) +{ + object *copy = new object (); + + *copy = value; + _mine.push_back (copy); + insert (copy); +} + +size_t +array::size () const +{ + return _store.size (); +} + +const object * +array::operator[] (size_t index) const +{ + return _store[index]; +} + +void +array::print (FILE* fp) const +{ + store_citer it; + + fprintf (fp, "[ "); + if (4 < _store.size ()) + { + fprintf (fp, "\n"); + } + for (it = _store.begin (); _store.end () != it; ++it) + { + (*it)->print (fp); + fprintf (fp, " "); + if (4 < _store.size ()) + { + fprintf (fp, "\n"); + } + } + fprintf (fp, "]"); +} + +} // namespace pdf +} // namespace iscan diff --git a/lib/pdf/array.hh b/lib/pdf/array.hh new file mode 100644 index 0000000..7bb5ac5 --- /dev/null +++ b/lib/pdf/array.hh @@ -0,0 +1,87 @@ +// array.hh -- PDF array objects +// Copyright (C) 2008 SEIKO EPSON CORPORATION +// +// This file is part of the 'iscan' program. +// +// The 'iscan' program is free-ish software. +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation; +// either version 2 of the License or at your option any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of FITNESS +// FOR A PARTICULAR PURPOSE or MERCHANTABILITY. +// See the GNU General Public License for more details. +// +// You should have received a verbatim copy of the GNU General Public +// License along with this program; if not, write to: +// +// Free Software Foundation, Inc. +// 59 Temple Place, Suite 330 +// Boston, MA 02111-1307 USA +// +// As a special exception, the copyright holders give permission +// to link the code of this program with the esmod library and +// distribute linked combinations including the two. You must obey +// the GNU General Public License in all respects for all of the +// code used other than esmod. + +#ifndef iscan_pdf_array_hh_included +#define iscan_pdf_array_hh_included + +#ifndef __cplusplus +#error "This is a C++ header file; use a C++ compiler to compile it." +#endif + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "object.hh" +#include "primitive.hh" + +#include <vector> + +namespace iscan +{ + +namespace pdf +{ + +/*! Defines a PDF array object [p 58]. + */ +class array : public object +{ +private: + typedef std::vector<object *> store_type; + typedef store_type::iterator store_iter; + typedef store_type::const_iterator store_citer; + + store_type _store; + store_type _mine; + +public: + virtual ~array (); + + /*! Insert an object at the end the array + */ + void insert (object* obj); + + void insert (primitive obj); + void insert (object obj); + + /*! Count the number of objects in the array + */ + size_t size() const; + + /*! Obtain a reference to an object at a given index + */ + const object* operator[] (size_t index) const; + + virtual void print (FILE* fp) const; +}; + +} // namespace pdf +} // namespace iscan + +#endif // iscan_pdf_array_hh_included diff --git a/lib/pdf/dictionary.cc b/lib/pdf/dictionary.cc new file mode 100644 index 0000000..e6822e7 --- /dev/null +++ b/lib/pdf/dictionary.cc @@ -0,0 +1,123 @@ +// dictionary.cc -- PDF dictionaries +// Copyright (C) 2008 SEIKO EPSON CORPORATION +// +// This file is part of the 'iscan' program. +// +// The 'iscan' program is free-ish software. +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation; +// either version 2 of the License or at your option any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of FITNESS +// FOR A PARTICULAR PURPOSE or MERCHANTABILITY. +// See the GNU General Public License for more details. +// +// You should have received a verbatim copy of the GNU General Public +// License along with this program; if not, write to: +// +// Free Software Foundation, Inc. +// 59 Temple Place, Suite 330 +// Boston, MA 02111-1307 USA +// +// As a special exception, the copyright holders give permission +// to link the code of this program with the esmod library and +// distribute linked combinations including the two. You must obey +// the GNU General Public License in all respects for all of the +// code used other than esmod. + + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "dictionary.hh" + +namespace iscan +{ + +namespace pdf +{ + +dictionary::~dictionary () +{ + store_citer it; + + for (it = _mine.begin (); _mine.end () != it; ++it) + { + object* obj = it->second; + delete obj; + obj = NULL; + } +} + +void +dictionary::insert (const char *key, object *value) +{ + if (_mine.end () != _mine.find (key)) + { + delete _mine[key]; + } + _store[key] = value; +} + +void +dictionary::insert (const char *key, primitive value) +{ + primitive *copy = new primitive (); + + *copy = value; + insert (key, copy); + _mine[key] = copy; +} + +void +dictionary::insert (const char *key, object value) +{ + object *copy = new object (); + + *copy = value; + insert (key, copy); + _mine[key] = copy; +} + +size_t +dictionary::size () const +{ + return _store.size (); +} + +const object * +dictionary::operator[] (const char* key) const +{ + store_citer it = _store.find (key); + + return (_store.end () != it ? it->second : NULL); +} + +void +dictionary::print (FILE* fp) const +{ + store_citer it; + + if (1 >= _store.size ()) + { + it = _store.begin (); + fprintf (fp, "<< /%s ", it->first); + it->second->print (fp); + fprintf (fp, " >>"); + return; + } + + fprintf (fp, "<<\n"); + for (it = _store.begin (); _store.end () != it; ++it) + { + fprintf (fp, "/%s ", it->first); + it->second->print (fp); + fprintf (fp, "\n"); + } + fprintf (fp, ">>"); +} + +} // namespace pdf +} // namespace iscan diff --git a/lib/pdf/dictionary.hh b/lib/pdf/dictionary.hh new file mode 100644 index 0000000..d20e0d2 --- /dev/null +++ b/lib/pdf/dictionary.hh @@ -0,0 +1,93 @@ +// dictionary.hh -- PDF dictionaries +// Copyright (C) 2008 SEIKO EPSON CORPORATION +// +// This file is part of the 'iscan' program. +// +// The 'iscan' program is free-ish software. +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation; +// either version 2 of the License or at your option any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of FITNESS +// FOR A PARTICULAR PURPOSE or MERCHANTABILITY. +// See the GNU General Public License for more details. +// +// You should have received a verbatim copy of the GNU General Public +// License along with this program; if not, write to: +// +// Free Software Foundation, Inc. +// 59 Temple Place, Suite 330 +// Boston, MA 02111-1307 USA +// +// As a special exception, the copyright holders give permission +// to link the code of this program with the esmod library and +// distribute linked combinations including the two. You must obey +// the GNU General Public License in all respects for all of the +// code used other than esmod. + + +#ifndef iscan_pdf_dictionary_hh_included +#define iscan_pdf_dictionary_hh_included + +#ifndef __cplusplus +#error "This is a C++ header file; use a C++ compiler to compile it." +#endif + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "object.hh" +#include "primitive.hh" + +#include <map> + +namespace iscan +{ + +namespace pdf +{ + +/*! Defines a pdf dictionary object [p 59] + */ +class dictionary : public object +{ +private: + typedef std::map<const char *, object *> store_type; + typedef store_type::iterator store_iter; + typedef store_type::const_iterator store_citer; + + store_type _store; + store_type _mine; + +public: + virtual ~dictionary (); + + /*! Insert a key/value pair into the dictionary + * + * If the key already exists, its value is replaced with the new one. + * + * The key is written to the PDF file as a name object as defined in the + * PDF spec [p. 59] + */ + void insert (const char *key, object *value); + + void insert (const char *key, primitive value); + void insert (const char *key, object value); + + /*! Count the number of objects in the dictionary + */ + size_t size () const; + + /*! Obtain a reference to an object with a given key + */ + const object * operator[] (const char *key) const; + + virtual void print (FILE* fp) const; +}; + +} // namespace pdf +} // namespace iscan + +#endif // iscan_pdf_dictionary_hh_included diff --git a/lib/pdf/object.cc b/lib/pdf/object.cc new file mode 100644 index 0000000..dba25da --- /dev/null +++ b/lib/pdf/object.cc @@ -0,0 +1,103 @@ +// object.cc -- PDF objects +// Copyright (C) 2008 SEIKO EPSON CORPORATION +// +// This file is part of the 'iscan' program. +// +// The 'iscan' program is free-ish software. +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation; +// either version 2 of the License or at your option any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of FITNESS +// FOR A PARTICULAR PURPOSE or MERCHANTABILITY. +// See the GNU General Public License for more details. +// +// You should have received a verbatim copy of the GNU General Public +// License along with this program; if not, write to: +// +// Free Software Foundation, Inc. +// 59 Temple Place, Suite 330 +// Boston, MA 02111-1307 USA +// +// As a special exception, the copyright holders give permission +// to link the code of this program with the esmod library and +// distribute linked combinations including the two. You must obey +// the GNU General Public License in all respects for all of the +// code used other than esmod. + + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "object.hh" + +#include <stdexcept> + +namespace iscan +{ + +namespace pdf +{ + + +object::object () +{ + _obj_num = 0; +} + +object::object (size_t num) +{ + // FIXME: what if num has already been used? + _obj_num = num; +} + +object::~object (void) +{ +} + +size_t +object::obj_num () +{ + if (65535 == next_obj_num) + { + throw std::runtime_error ("PDF object number overflow"); + } + + if (is_direct ()) + { + _obj_num = ++next_obj_num; + } + return _obj_num; +} + +bool +object::operator== (object& that) const +{ + // FIXME: what if one or both instances have not gotten an object + // number yet? + return _obj_num == that._obj_num; +} + +void +object::print (FILE* fp) const +{ + fprintf (fp, "%zu 0 R", _obj_num); +} + +bool +object::is_direct () const +{ + return (0 == _obj_num); +} + +size_t object::next_obj_num = 0; + +void object::reset_object_numbers () +{ + next_obj_num = 0; +} + +} // namespace pdf +} // namespace iscan diff --git a/lib/pdf/object.hh b/lib/pdf/object.hh new file mode 100644 index 0000000..ef38e85 --- /dev/null +++ b/lib/pdf/object.hh @@ -0,0 +1,120 @@ +// object.hh -- PDF objects +// Copyright (C) 2008 SEIKO EPSON CORPORATION +// +// This file is part of the 'iscan' program. +// +// The 'iscan' program is free-ish software. +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation; +// either version 2 of the License or at your option any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of FITNESS +// FOR A PARTICULAR PURPOSE or MERCHANTABILITY. +// See the GNU General Public License for more details. +// +// You should have received a verbatim copy of the GNU General Public +// License along with this program; if not, write to: +// +// Free Software Foundation, Inc. +// 59 Temple Place, Suite 330 +// Boston, MA 02111-1307 USA +// +// As a special exception, the copyright holders give permission +// to link the code of this program with the esmod library and +// distribute linked combinations including the two. You must obey +// the GNU General Public License in all respects for all of the +// code used other than esmod. + +#ifndef iscan_pdf_object_hh_included +#define iscan_pdf_object_hh_included + +#ifndef __cplusplus +#error "This is a C++ header file; use a C++ compiler to compile it." +#endif + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <cstdlib> +#include <cstdio> + +namespace iscan +{ + +namespace pdf +{ + +using namespace std; + +/*! A base class for all pdf objects [p 51]. + * + * A pdf::object is also used to pass around object numbers in a transparent + * fashion so that object references can be output correctly as elements of + * arrays and dictionaries. + */ +class object +{ +private: + + size_t _obj_num; + static size_t next_obj_num; // the next free object number + +public: + + object (); + + /*! Creates a new pdf::object with its object number set to \a num. + * + * Constructs an indirect object. + */ + object (size_t num); + + virtual ~object (void); + + /*! Obtain the pdf::object's object number. + * + * If the object has not been allocated an object number yet, a new one is + * allocated and returned. + */ + size_t obj_num (); + + /*! Determine whether the object is direct or indirect [p 63]. + * + * Probably don't need this method. + * + * @return True if the object is direct, False if it is indirect + */ + bool is_direct () const; + + /*! Output the object contents. + * + * In the case of pdf::object, this only outputs an indirect reference to + * itself [p 64]. + * + * Each subclass re-implements this in order to print its own content. + * It should only ever output the object contents, ommitting the object + * definition header and footer [p 64] + */ + virtual void print (FILE* fp) const; + + /*! Compare the contents of two pdf::objects. + * + * Only the object contents are compared, the object number of the two + * objects can be different. + * + * In the case of pdf::object, the object numbers are compared. + */ + virtual bool operator== (object& that) const; + + /*! Reset the current object number to recycle them for new documents + */ + static void reset_object_numbers (); + +}; + +} // namespace pdf +} // namespace iscan + +#endif // iscan_pdf_object_hh_included diff --git a/lib/pdf/primitive.cc b/lib/pdf/primitive.cc new file mode 100644 index 0000000..8a47c14 --- /dev/null +++ b/lib/pdf/primitive.cc @@ -0,0 +1,100 @@ +// primitive.cc -- PDF primitives +// Copyright (C) 2008 SEIKO EPSON CORPORATION +// +// This file is part of the 'iscan' program. +// +// The 'iscan' program is free-ish software. +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation; +// either version 2 of the License or at your option any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of FITNESS +// FOR A PARTICULAR PURPOSE or MERCHANTABILITY. +// See the GNU General Public License for more details. +// +// You should have received a verbatim copy of the GNU General Public +// License along with this program; if not, write to: +// +// Free Software Foundation, Inc. +// 59 Temple Place, Suite 330 +// Boston, MA 02111-1307 USA +// +// As a special exception, the copyright holders give permission +// to link the code of this program with the esmod library and +// distribute linked combinations including the two. You must obey +// the GNU General Public License in all respects for all of the +// code used other than esmod. + + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "primitive.hh" + +#include <sstream> + +namespace iscan +{ + +namespace pdf +{ + +primitive::primitive () + : _str (string ()) +{ +} + +primitive::primitive (string value) + : _str (value) +{ +} + +primitive::primitive (int value) +{ + stringstream ss; + ss << value; + ss >> _str; +} + +primitive::primitive (size_t value) +{ + stringstream ss; + ss << value; + ss >> _str; +} + +primitive::primitive (double value) +{ + stringstream ss; + ss << value; + ss >> _str; +} + +primitive::~primitive (void) +{ +} + +bool +primitive::operator== (const primitive& that) const +{ + return _str == that._str; +} + +void +primitive::print (FILE* fp) const +{ + fprintf (fp, "%s", _str.c_str ()); +} + +// FIXME: doesn't do the default assignment just what we want? +void +primitive::operator= (const primitive& that) +{ + _str = that._str; +} + + +} // namespace pdf +} // namespace iscan diff --git a/lib/pdf/primitive.hh b/lib/pdf/primitive.hh new file mode 100644 index 0000000..e45adc0 --- /dev/null +++ b/lib/pdf/primitive.hh @@ -0,0 +1,92 @@ +// primitive.hh -- PDF primitives +// Copyright (C) 2008 SEIKO EPSON CORPORATION +// +// This file is part of the 'iscan' program. +// +// The 'iscan' program is free-ish software. +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation; +// either version 2 of the License or at your option any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of FITNESS +// FOR A PARTICULAR PURPOSE or MERCHANTABILITY. +// See the GNU General Public License for more details. +// +// You should have received a verbatim copy of the GNU General Public +// License along with this program; if not, write to: +// +// Free Software Foundation, Inc. +// 59 Temple Place, Suite 330 +// Boston, MA 02111-1307 USA +// +// As a special exception, the copyright holders give permission +// to link the code of this program with the esmod library and +// distribute linked combinations including the two. You must obey +// the GNU General Public License in all respects for all of the +// code used other than esmod. + +#ifndef iscan_pdf_primitive_hh_included +#define iscan_pdf_primitive_hh_included + +#ifndef __cplusplus +#error "This is a C++ header file; use a C++ compiler to compile it." +#endif + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "object.hh" + +#include <string> + +namespace iscan +{ + +namespace pdf +{ + using std::string; + +/*! Defines a primitive pdf object: one of string, name, integer, or real. + */ +class primitive : public object +{ +private: + string _str; + +public: + primitive (); + + /*! Create a new pdf string/name object with the given value. + */ + primitive (string value); + + /*! Create a new pdf integer object + */ + primitive (int value); + + primitive (size_t value); + + /*! Create a new pdf real object + */ + primitive (double value); + + virtual ~primitive (void); + + /*! Compare the contents of two pdf::primitives. + * + * Only the object contents are compared, the object number of the + * two objects may differ. + */ + virtual bool operator== (const primitive& other) const; + + void operator= (const primitive& that); + + virtual void print (FILE* fp) const; +}; + +} // namespace pdf +} // namespace iscan + +#endif // iscan_pdf_primitive_hh_included diff --git a/lib/pdf/writer.cc b/lib/pdf/writer.cc new file mode 100644 index 0000000..78a9355 --- /dev/null +++ b/lib/pdf/writer.cc @@ -0,0 +1,236 @@ +// writer.cc -- putting PDF object in a file +// Copyright (C) 2008 SEIKO EPSON CORPORATION +// +// This file is part of the 'iscan' program. +// +// The 'iscan' program is free-ish software. +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation; +// either version 2 of the License or at your option any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of FITNESS +// FOR A PARTICULAR PURPOSE or MERCHANTABILITY. +// See the GNU General Public License for more details. +// +// You should have received a verbatim copy of the GNU General Public +// License along with this program; if not, write to: +// +// Free Software Foundation, Inc. +// 59 Temple Place, Suite 330 +// Boston, MA 02111-1307 USA +// +// As a special exception, the copyright holders give permission +// to link the code of this program with the esmod library and +// distribute linked combinations including the two. You must obey +// the GNU General Public License in all respects for all of the +// code used other than esmod. + + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "writer.hh" + +#include <sstream> +#include <stdexcept> + +namespace iscan +{ + +namespace pdf +{ + using std::runtime_error; + using std::string; + +writer::writer (FILE *file) + : _xref (xref ()), _file (file) +{ + _xref_pos = 0; + _last_xref_pos = 0; + _saved_pos = 0; + _mode = object_mode; + _stream_len_obj = NULL; +} + +writer::~writer () +{ + delete _stream_len_obj; + _stream_len_obj = NULL; +} + +void +writer::write (object& obj) +{ + if (object_mode != _mode) + { + throw runtime_error ("invalid call to pdf::writer::write (object&)"); + } + + _xref[obj.obj_num ()] = ftell (_file); + + fprintf (_file, "%zu 0 obj\n", obj.obj_num ()); + obj.print (_file); + fprintf (_file, "\n"); + fprintf (_file, "endobj\n"); +} + +void +writer::begin_stream (dictionary& dict) +{ + if (stream_mode == _mode) + { + throw runtime_error ("invalid call to pdf::writer::begin_stream ()"); + } + _mode = stream_mode; + + _stream_len_obj = new primitive (); + dict.insert ("Length", object (_stream_len_obj->obj_num ())); + + _xref[dict.obj_num ()] = ftell (_file); + + fprintf (_file, "%zu 0 obj\n", dict.obj_num ()); + dict.print (_file); + fprintf (_file, "\n"); + fprintf (_file, "stream\n"); + + _saved_pos = ftell (_file); +} + +void +writer::write (const char *buf, size_t n) +{ + if (stream_mode != _mode) + { + throw runtime_error ("invalid call to pdf::writer::write ()"); + } + size_t rv = fwrite (buf, sizeof (char), n, _file); + if (rv != n) throw std::ios_base::failure ("write error"); +} + +void +writer::write (const string& s) +{ + if (stream_mode != _mode) + { + throw runtime_error ("invalid call to pdf::writer::write ()"); + } + fprintf (_file, "%s", s.c_str ()); +} + +void +writer::end_stream () +{ + if (stream_mode != _mode) + { + throw runtime_error ("invalid call to pdf::writer::end_stream ()"); + } + _mode = object_mode; + + size_t pos = ftell (_file); + size_t length = pos - _saved_pos; + + fprintf (_file, "\n"); + fprintf (_file, "endstream"); + fprintf (_file, "\n"); + fprintf (_file, "endobj"); + fprintf (_file, "\n"); + + // FIXME: overload the '=' operator in pdf::primitive + *_stream_len_obj = primitive (length); + + write (*_stream_len_obj); + delete _stream_len_obj; + _stream_len_obj = NULL; +} + +void +writer::header () +{ + if (_mode == stream_mode) + { + throw runtime_error ("cannot write header in stream mode"); + } + fprintf (_file, "%%PDF-1.0\n"); +} + +void +writer::trailer (dictionary& trailer_dict) +{ + if (_mode == stream_mode) + { + throw runtime_error ("cannot write trailer in stream mode"); + } + write_xref (); + write_trailer (trailer_dict); +} + +// FIXME: clean up this kludge +void +writer::write_xref () +{ + xref::const_iterator it; + + _last_xref_pos = _xref_pos; + _xref_pos = ftell (_file); + + fprintf (_file, "xref\n"); + + stringstream ss; + size_t start_obj_num = 0; + size_t cur_obj_num = 0; + size_t last_obj_num = 0; + + ss << "0000000000 65535 f " << endl; + for(it = _xref.begin (); _xref.end () != it; ++it) + { + cur_obj_num = it->first; + + if (cur_obj_num != last_obj_num + 1) + { + // write out the current xref section and start a new one + fprintf (_file, "%zu %zu\n", start_obj_num, + last_obj_num + 1 - start_obj_num); + fprintf (_file, "%s", ss.str ().c_str ()); + + ss.str (""); // flush stream + start_obj_num = cur_obj_num; + } + + last_obj_num = cur_obj_num; + + ss.width (10); + ss.fill ('0'); + ss << it->second << " 00000 n " << endl; + } + + if (!ss.str ().empty ()) + { + fprintf (_file, "%zu %zu\n", start_obj_num, + last_obj_num + 1 - start_obj_num); + fprintf (_file, "%s", ss.str ().c_str ()); + } +} + +void +writer::write_trailer (dictionary& trailer_dict) +{ + trailer_dict.insert ("Size", primitive (_xref.size () + 1)); + if (_last_xref_pos != 0) + { + trailer_dict.insert ("Prev", primitive (_last_xref_pos)); + } + + fprintf (_file, "trailer\n"); + trailer_dict.print (_file); + fprintf (_file, "\n"); + fprintf (_file, "startxref\n"); + fprintf (_file, "%zu\n", _xref_pos); + fprintf (_file, "%%%%EOF\n"); + + _xref.clear (); +} + +} // namespace pdf +} // namespace iscan diff --git a/lib/pdf/writer.hh b/lib/pdf/writer.hh new file mode 100644 index 0000000..f62c471 --- /dev/null +++ b/lib/pdf/writer.hh @@ -0,0 +1,165 @@ +// writer.hh -- putting PDF objects in a file +// Copyright (C) 2008 SEIKO EPSON CORPORATION +// +// This file is part of the 'iscan' program. +// +// The 'iscan' program is free-ish software. +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation; +// either version 2 of the License or at your option any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of FITNESS +// FOR A PARTICULAR PURPOSE or MERCHANTABILITY. +// See the GNU General Public License for more details. +// +// You should have received a verbatim copy of the GNU General Public +// License along with this program; if not, write to: +// +// Free Software Foundation, Inc. +// 59 Temple Place, Suite 330 +// Boston, MA 02111-1307 USA +// +// As a special exception, the copyright holders give permission +// to link the code of this program with the esmod library and +// distribute linked combinations including the two. You must obey +// the GNU General Public License in all respects for all of the +// code used other than esmod. + +#ifndef iscan_pdf_writer_hh_included +#define iscan_pdf_writer_hh_included + +#ifndef __cplusplus +#error "This is a C++ header file; use a C++ compiler to compile it." +#endif + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "object.hh" +#include "primitive.hh" +#include "dictionary.hh" + +#include <map> + +namespace iscan +{ + +namespace pdf +{ + using std::string; + +/*! Writes PDF objects to a file. + * See section 3.4 of the PDF Reference version 1.7 for details on the basic + * file structure of a PDF file. + * + * There are two writing modes: object mode and stream mode. + * The default mode is object mode. When begin_stream() is called, the current + * mode is set to stream mode. When end_stream() is called, the mode is reset + * to object mode. + * + * In object mode, PDF objects are written all at once. Stream mode allows the + * writing of PDF stream objects which can be written incrementally. + */ +class writer +{ +private: + typedef std::map<size_t, size_t> xref; + + xref _xref; + size_t _xref_pos; + size_t _last_xref_pos; + + FILE *_file; + size_t _saved_pos; + + primitive* _stream_len_obj; + + typedef enum { + object_mode, + stream_mode + } write_mode; + + write_mode _mode; + +public: + /*! Creates a new pdf::writer object which will write to the given stream. + */ + writer (FILE *file); + + ~writer (); + + /*! Writes a pdf::object to the file as an indirect object [p 63]. + * + * Recursively writes any child objects to the file. + * Can only be called while in object mode, which is the default + * mode. If this method is called between calls to begin_stream() and + * end_stream() a std::runtime_error exception is thrown. + */ + void write (object& object); + + /*! Initializes a PDF stream [p 60] and sets the current mode to stream mode. + * + * Pass a pdf::dictionary object, \a dict, defining the stream properties, + * omitting the mandatory "Length" property which is automatically + * calculated and written to the file. If this method is called when already + * in stream mode, a std::runtime_error exception is thrown. + */ + void begin_stream (dictionary& dict); + + /*! Writes \a n bytes from \a buf to the file as part of a PDF stream. + * + * Can only be called while in stream mode. + * Calls to this method must be contained within calls to + * begin_stream() and end_stream(). If not, a std::runtime_error + * exception is thrown. + */ + void write (const char* buf, size_t n); + + /*! Writes a string \a s to the file as part of a PDF stream. + * + * Can only be called while in stream mode. + * Calls to this method must be contained within calls to + * begin_stream() and end_stream(). If not, a std::runtime_error + * exception is thrown. + */ + void write (const string& s); + + /*! Finishes writing a PDF stream and sets the current mode to object mode. + * + * The "Length" property of the stream is written at this point as an + * indirect object. Can only be called when in stream mode, if not, a + * std::runtime_error exception is thrown. + */ + void end_stream (); + + /*! Writes the PDF header [p 92]. + * + * A std::runtime_error exception is thrown if this method is called while + * in stream mode. + */ + void header (); + + /*! Writes the PDF trailer [p 96] and xref table [p 93]. + * + * Also sets the "Prev" entry in \a trailer_dict and clears the internal + * xref table. A std::runtime_error exception is thrown if this method is + * called while in stream mode. + * + * \param trailer_dict The trailer entries to be written. + */ + void trailer (dictionary& trailer_dict); + +private: + // Writes the cross-reference table [p 93]. + void write_xref (); + + // Writes the file trailer [p 96]. + void write_trailer (dictionary& trailer_dict); +}; + +} // namespace pdf +} // namespace iscan + +#endif // iscan_pdf_writer_hh_included |