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 | |
26 | namespace Poco { |
27 | namespace PDF { |
28 | |
29 | |
30 | Document::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 | |
43 | Document::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 | |
54 | Document::~Document() |
55 | { |
56 | HPDF_Free(_pdf); |
57 | delete _pRawData; |
58 | } |
59 | |
60 | |
61 | void 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 | |
71 | void Document::createNew(bool resetAll) |
72 | { |
73 | reset(resetAll); |
74 | HPDF_NewDoc(_pdf); |
75 | } |
76 | |
77 | |
78 | void 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 | |
88 | const 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 | |
98 | Document::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 | |
106 | const 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 | |
115 | const 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 | |
130 | const 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 | |
142 | const 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 | |
154 | const 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 | |
163 | std::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 | |
169 | std::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 | |
189 | const 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 | |
213 | const 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 | |
230 | const 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 | |
247 | void 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 | |
258 | const 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 | |
273 | const 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 | |
290 | const Encoder& Document::setCurrentEncoder(const std::string& name) |
291 | { |
292 | loadEncoder(name); |
293 | HPDF_SetCurrentEncoder(_pdf, name.c_str()); |
294 | return getCurrentEncoder(); |
295 | } |
296 | |
297 | |
298 | const 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 | |
305 | void 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 | |
333 | void 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 | |
342 | void 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 | |
351 | void 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 | |