aboutsummaryrefslogtreecommitdiff
path: root/lib/pdf/writer.hh
blob: f62c471b6658bc5d5c9722d9dbc3f12190c5f6a2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
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