1//
2// Document.cpp
3//
4// Library: PDF
5// Package: PDFCore
6// Module: Document
7//
8// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
9// and Contributors.
10//
11// SPDX-License-Identifier: BSL-1.0
12//
13
14
15#include "Poco/PDF/Document.h"
16#include "Poco/PDF/PDFException.h"
17#include "Poco/File.h"
18#include "Poco/Path.h"
19#include "Poco/LocalDateTime.h"
20#include "Poco/DateTimeFormatter.h"
21#include "Poco/StringTokenizer.h"
22#include "Poco/NumberParser.h"
23#include <utility>
24#include "Util.h"
25
26namespace Poco {
27namespace PDF {
28
29
30Document::Document(const std::string fileName,
31 Poco::UInt32 pageCount,
32 Page::Size pageSize,
33 Page::Orientation orientation):
34 _pdf(HPDF_New(HPDF_Error_Handler, 0)),
35 _fileName(fileName),
36 _pRawData(0),
37 _size(0)
38{
39 init(pageCount, pageSize, orientation);
40}
41
42
43Document::Document(Poco::UInt32 pageCount,
44 Page::Size pageSize,
45 Page::Orientation orientation):
46 _pdf(HPDF_New(HPDF_Error_Handler, 0)),
47 _pRawData(0),
48 _size(0)
49{
50 init(pageCount, pageSize, orientation);
51}
52
53
54Document::~Document()
55{
56 HPDF_Free(_pdf);
57 delete _pRawData;
58}
59
60
61void Document::init(Poco::UInt32 pageCount,
62 Page::Size pageSize, Page::Orientation orientation)
63{
64 useUTF8Encoding();
65 compression(COMPRESSION_ALL);
66 for (Poco::UInt32 i = 0; i < pageCount; ++i)
67 addPage(pageSize, orientation);
68}
69
70
71void Document::createNew(bool resetAll)
72{
73 reset(resetAll);
74 HPDF_NewDoc(_pdf);
75}
76
77
78void Document::save(const std::string fileName)
79{
80 std::string fn = fileName.empty() ? _fileName : fileName;
81 if (fn.empty())
82 HPDF_SaveToStream (_pdf);
83 else
84 HPDF_SaveToFile(_pdf, fn.c_str());
85}
86
87
88const Document::DataPtr Document::data(SizeType& sz)
89{
90 sz = size();
91 delete _pRawData;
92 _pRawData = new HPDF_BYTE[sz];
93 HPDF_ReadFromStream(_pdf, _pRawData, &sz);
94 return _pRawData;
95}
96
97
98Document::SizeType Document::size()
99{
100 if (HPDF_Stream_Validate(_pdf->stream)) HPDF_ResetStream(_pdf);
101 HPDF_SaveToStream(_pdf);
102 return _size = HPDF_GetStreamSize(_pdf);
103}
104
105
106const Page& Document::addPage(Page::Size pageSize, Page::Orientation orientation)
107{
108 Page page(this, HPDF_AddPage(_pdf), pageSize);
109 page.setSizeAndOrientation(pageSize, orientation);
110 _pages.push_back(page);
111 return _pages.back();
112}
113
114
115const Page& Document::insertPage(int index,
116 Page::Size pageSize,
117 Page::Orientation orientation)
118{
119 poco_assert (index > 0);
120 poco_assert (index < _pages.size());
121 HPDF_Page target = *((HPDF_Page*) HPDF_List_ItemAt(_pdf->page_list, static_cast<HPDF_UINT>(index)));
122 return *_pages.insert(_pages.begin() + index,
123 Page(this,
124 HPDF_InsertPage(_pdf, target),
125 pageSize,
126 orientation));
127}
128
129
130const Page& Document::getCurrentPage()
131{
132 Page p(this, HPDF_GetCurrentPage(_pdf));
133 PageContainer::iterator it = _pages.begin();
134 PageContainer::iterator end = _pages.end();
135 for (;it != end; ++it)
136 if (*it == p) return *it;
137
138 throw NotFoundException("Current page not found.");
139}
140
141
142const Font& Document::loadFont(const std::string& name, const std::string& encoding)
143{
144 Font font(&_pdf, HPDF_GetFont(_pdf, name.c_str(), encoding.empty() ? 0 : encoding.c_str()));
145 std::pair<FontContainer::iterator, bool> ret =
146 _fonts.insert(FontContainer::value_type(name, font));
147
148 if (ret.second) return ret.first->second;
149
150 throw IllegalStateException("Could not create font.");
151}
152
153
154const Font& Document::font(const std::string& name, const std::string& encoding)
155{
156 FontContainer::iterator it = _fonts.find(name);
157 if (_fonts.end() != it) return it->second;
158
159 return loadFont(name, encoding);
160}
161
162
163std::string Document::loadType1Font(const std::string& afmFileName, const std::string& pfmFileName)
164{
165 return HPDF_LoadType1FontFromFile(_pdf, afmFileName.c_str(), pfmFileName.c_str());
166}
167
168
169std::string Document::loadTTFont(const std::string& fileName, bool embed, int index)
170{
171 if (-1 == index)
172 {
173 return HPDF_LoadTTFontFromFile(_pdf,
174 fileName.c_str(),
175 embed ? HPDF_TRUE : HPDF_FALSE);
176 }
177 else if (index >= 0)
178 {
179 return HPDF_LoadTTFontFromFile2(_pdf,
180 fileName.c_str(),
181 static_cast<HPDF_UINT>(index),
182 embed ? HPDF_TRUE : HPDF_FALSE);
183 }
184 else
185 throw InvalidArgumentException("Invalid font index.");
186}
187
188
189const Image& Document::loadPNGImageImpl(const std::string& fileName, bool doLoad)
190{
191 Path path(fileName);
192
193 if (File(path).exists())
194 {
195 std::pair<ImageContainer::iterator, bool> it;
196 if (doLoad)
197 {
198 Image image(&_pdf, HPDF_LoadPngImageFromFile(_pdf, Poco::Path::transcode(fileName).c_str()));
199 it = _images.insert(ImageContainer::value_type(path.getBaseName(), image));
200 }
201 else
202 {
203 Image image(&_pdf, HPDF_LoadPngImageFromFile2(_pdf, Poco::Path::transcode(fileName).c_str()));
204 it = _images.insert(ImageContainer::value_type(path.getBaseName(), image));
205 }
206 if (it.second) return it.first->second;
207 else throw IllegalStateException("Could not insert image.");
208 }
209 else
210 throw NotFoundException("File not found: " + fileName);
211}
212
213const Image& Document::loadBMPImageImpl(const std::string& fileName, bool /*doLoad*/)
214{
215 Path path(fileName);
216
217 if (File(path).exists())
218 {
219 Image image(&_pdf, LoadBMPImageFromFile(_pdf, Poco::Path::transcode(fileName).c_str()));
220 std::pair<ImageContainer::iterator, bool> it =
221 _images.insert(ImageContainer::value_type(path.getBaseName(), image));
222 if (it.second) return it.first->second;
223 else throw IllegalStateException("Could not insert image.");
224 }
225 else
226 throw NotFoundException("File not found: " + fileName);
227}
228
229
230const Image& Document::loadJPEGImage(const std::string& fileName)
231{
232 Path path(fileName);
233
234 if (File(path).exists())
235 {
236 Image image(&_pdf, HPDF_LoadJpegImageFromFile(_pdf, Poco::Path::transcode(fileName).c_str()));
237 std::pair<ImageContainer::iterator, bool> it =
238 _images.insert(ImageContainer::value_type(path.getBaseName(), image));
239 if (it.second) return it.first->second;
240 else throw IllegalStateException("Could not insert image.");
241 }
242 else
243 throw NotFoundException("File not found: " + fileName);
244}
245
246
247void Document::encryption(Encryption mode, Poco::UInt32 keyLength)
248{
249 if (ENCRYPT_R3 == mode && (keyLength < 5 || keyLength > 128))
250 throw InvalidArgumentException("Invalid key length.");
251
252 HPDF_SetEncryptionMode(_pdf,
253 static_cast<HPDF_EncryptMode>(mode),
254 static_cast<HPDF_UINT>(keyLength));
255}
256
257
258const Encoder& Document::loadEncoder(const std::string& name)
259{
260 EncoderContainer::iterator it = _encoders.find(name);
261 if (_encoders.end() == it) return it->second;
262
263 Encoder enc(&_pdf, HPDF_GetEncoder(_pdf, name.c_str()), name);
264 std::pair<EncoderContainer::iterator, bool> ret =
265 _encoders.insert(EncoderContainer::value_type(name, enc));
266
267 if (ret.second) return ret.first->second;
268
269 throw IllegalStateException("Could not create encoder.");
270}
271
272
273const Encoder& Document::getCurrentEncoder()
274{
275 HPDF_Encoder enc = HPDF_GetCurrentEncoder(_pdf);
276 std::string name = enc->name;
277 EncoderContainer::iterator it = _encoders.find(name);
278 if (_encoders.end() == it)
279 {
280 std::pair<EncoderContainer::iterator, bool> ret =
281 _encoders.insert(EncoderContainer::value_type(name, Encoder(&_pdf, enc)));
282
283 if (ret.second) return ret.first->second;
284 }
285
286 return it->second;
287}
288
289
290const Encoder& Document::setCurrentEncoder(const std::string& name)
291{
292 loadEncoder(name);
293 HPDF_SetCurrentEncoder(_pdf, name.c_str());
294 return getCurrentEncoder();
295}
296
297
298const Outline& Document::createOutline(const std::string& title, const Outline& parent, const Encoder& encoder)
299{
300 _outlines.push_back(Outline(&_pdf, HPDF_CreateOutline(_pdf, parent, title.c_str(), encoder)));
301 return _outlines.back();
302}
303
304
305void Document::setInfo(Info info, const LocalDateTime& dt)
306{
307 if (INFO_CREATION_DATE == info || INFO_MOD_DATE == info)
308 {
309 HPDF_Date hpdfDate;
310 hpdfDate.year = dt.year();
311 hpdfDate.month = dt.month();
312 hpdfDate.day = dt.day();
313 hpdfDate.hour = dt.hour();
314 hpdfDate.minutes = dt.minute();
315 hpdfDate.seconds = dt.second();
316 std::string tzd = DateTimeFormatter::tzdISO(dt.tzd());
317 StringTokenizer st(tzd, "+-:");
318 if (st.count() >= 2)
319 {
320 hpdfDate.ind = tzd[0];
321 hpdfDate.off_hour = NumberParser::parse(st[0]);
322 hpdfDate.off_minutes = NumberParser::parse(st[1]);
323 }
324 else hpdfDate.ind = ' ';
325
326 HPDF_SetInfoDateAttr(_pdf, static_cast<HPDF_InfoType>(info), hpdfDate);
327 }
328 else
329 throw InvalidArgumentException("Can not set document info.");
330}
331
332
333void Document::setInfo(Info info, const std::string& value)
334{
335 if (INFO_CREATION_DATE == info || INFO_MOD_DATE == info)
336 throw InvalidArgumentException("Can not set document date.");
337
338 HPDF_SetInfoAttr(_pdf, static_cast<HPDF_InfoType>(info), value.c_str());
339}
340
341
342void Document::setPassword(const std::string& ownerPassword, const std::string& userPassword)
343{
344 if (ownerPassword.empty())
345 throw InvalidArgumentException("Owner password empty.");
346
347 HPDF_SetPassword(_pdf, ownerPassword.c_str(), userPassword.c_str());
348}
349
350
351void Document::reset(bool all)
352{
353 if (!all) HPDF_FreeDoc(_pdf);
354 else
355 {
356 _pages.clear();
357 _fonts.clear();
358 _encoders.clear();
359 _outlines.clear();
360 _images.clear();
361 HPDF_FreeDocAll(_pdf);
362 }
363}
364
365
366} } // namespace Poco::PDF
367