dataops (
dataops.cpp) –
this example shows how to create documents both direct file (write-only) and
a memory-based documents. It mostly uses API for memory-based PDF documents.
It contains several sections, which create a PDF document with a rounded filled
rectangle on a page. Such document is saved into a file (directly, or through
a memory buffer), same as the file loaded and re-saved. It also compares whether
the result file content is the same for both save to a disk and save to a memory buffer.
1 /*
2 * (c) 2013-2016 http://www.litePDF.cz
3 * (c) 2017 zyx [@:] zyx gmx [dot] us
4 *
5 * This software is provided 'as-is', without any express or implied
6 * warranty. In no event will the authors be held liable for any damages
7 * arising from the use of this software.
8 *
9 * Permission is granted to anyone to use this software for any purpose,
10 * including commercial applications, and to alter it and redistribute it
11 * freely, subject to the following restrictions:
12 *
13 * 1. The origin of this software must not be misrepresented; you must not
14 * claim that you wrote the original software. If you use this software
15 * in a product, an acknowledgment in the product documentation would be
16 * appreciated but is not required.
17 * 2. Altered source versions must be plainly marked as such, and must not be
18 * misrepresented as being the original software.
19 * 3. This notice may not be removed or altered from any source distribution.
20 */
21
22 #include <windows.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <string>
26
27 #include "share/litePDF.h"
28
29 static std::string to_string(unsigned int num)
30 {
31 char buff[128];
32
33 sprintf(buff, "%u", num);
34
35 return std::string(buff);
36 }
37
38 static void drawPage(litePDF::TLitePDF &litePDF)
39 {
40 // add a new page to it, with large-enough pixel scale
41 HDC hDC = litePDF.AddPage(litePDF.MMToUnit(210), litePDF.MMToUnit(297), 2100, 2970, LitePDFDrawFlag_None);
42
43 HGDIOBJ oldBrush, oldPen;
44
45 oldBrush = SelectObject(hDC, GetStockObject(LTGRAY_BRUSH));
46 oldPen = SelectObject(hDC, GetStockObject(BLACK_PEN));
47
48 // draw rectangle
49 RoundRect(hDC, 200, 200, 1900, 2770, 300, 300);
50
51 SelectObject(hDC, oldPen);
52 SelectObject(hDC, oldBrush);
53
54 // finish drawing
55 litePDF.FinishPage(hDC);
56 }
57
58 static void saveToData(litePDF::TLitePDF &litePDF,
59 BYTE **pdata,
60 unsigned int &dataLength)
61 {
62 dataLength = 0;
63 *pdata = NULL;
64
65 if (!litePDF.SaveToData(NULL, &dataLength)) {
66 throw TLitePDFException(ERROR_CANNOT_MAKE, "Failed to get data length");
67 }
68
69 if (!dataLength) {
70 throw TLitePDFException(ERROR_CANNOT_MAKE, "Returned data length is 0");
71 }
72
73 *pdata = (BYTE *) malloc(sizeof(BYTE) * dataLength);
74 if (!*pdata) {
75 std::string msg = "Failed to allocate " + to_string(dataLength) + " bytes";
76 throw TLitePDFException(ERROR_OUTOFMEMORY, msg.c_str());
77 }
78
79 if (!litePDF.SaveToData(*pdata, &dataLength)) {
80 throw TLitePDFException(ERROR_CANNOT_MAKE, "Failed to get data");
81 }
82 }
83
84 static void saveDataToFile(const char *fileName,
85 const BYTE *data,
86 unsigned int dataLength)
87 {
88 FILE *f = fopen(fileName, "wb");
89 if (!f) {
90 std::string msg = "Failed to open " + std::string(fileName);
91 throw TLitePDFException(ERROR_CANNOT_MAKE, msg.c_str());
92 }
93
94 if (fwrite(data, sizeof(BYTE), dataLength, f) != dataLength) {
95 fclose(f);
96 std::string msg = "Failed to write to " + std::string(fileName);
97 throw TLitePDFException(ERROR_CANNOT_MAKE, msg.c_str());
98 }
99
100 fclose(f);
101 }
102
103 static void cmpFileAndData(const char *fileName,
104 const BYTE *data,
105 unsigned int dataLength)
106 {
107 FILE *f = fopen(fileName, "rb");
108 if (!f) {
109 std::string msg = "Failed to open " + std::string(fileName);
110 throw TLitePDFException(ERROR_CANNOT_MAKE, msg.c_str());
111 }
112
113 if (fseek(f, 0, SEEK_END) != 0) {
114 fclose(f);
115 throw TLitePDFException(ERROR_CANNOT_MAKE,
116 "Failed to move to the end of the file");
117 }
118
119 long fileLength = ftell(f);
120 if (fileLength != (long) dataLength) {
121 fclose(f);
122 std::string msg = "File length (" + to_string(fileLength) +
123 ") differs from data length (" +
124 to_string(dataLength) + ")";
125 throw TLitePDFException(ERROR_CANNOT_MAKE, msg.c_str());
126 }
127
128 if (fseek(f, 0, SEEK_SET) != 0) {
129 fclose(f);
130 throw TLitePDFException(ERROR_CANNOT_MAKE,
131 "Failed to move to the beginning of the file");
132 }
133
134 BYTE buff[1024];
135 unsigned int read, dataOffset = 0;
136 while(read = fread(buff, sizeof(BYTE), 1024, f), read > 0) {
137 if (memcmp(buff, data + dataOffset, read) != 0) {
138 fclose(f);
139 throw TLitePDFException(ERROR_CANNOT_MAKE,
140 "File and data content differs");
141 }
142
143 dataOffset += read;
144
145 if (feof(f)) {
146 break;
147 }
148 }
149
150 fclose(f);
151
152 if (dataOffset != dataLength) {
153 std::string msg = "Did not finish with dataOffset (" +
154 to_string(dataOffset) +
155 ") at the end of data (" + to_string(dataLength) + ")";
156 throw TLitePDFException(ERROR_CANNOT_MAKE, msg.c_str());
157 }
158 }
159
160 static void cmpDataAndData(const BYTE *data1,
161 unsigned int data1Length,
162 const BYTE *data2,
163 unsigned int data2Length)
164 {
165 if (data1Length != data2Length) {
166 std::string msg = "data1 length (" + to_string(data1Length) +
167 ") differs from data2 length (" +
168 to_string(data2Length) + ")";
169 throw TLitePDFException(ERROR_CANNOT_MAKE, msg.c_str());
170 }
171
172 if (0 != memcmp(data1, data2, data1Length)) {
173 throw TLitePDFException(ERROR_CANNOT_MAKE, "Data contents differ");
174 }
175 }
176
177 int main(void)
178 {
179 BYTE *data1 = NULL, *data2 = NULL;
180 unsigned int data1Length, data2Length;
181 int res = 0;
182
183 using namespace litePDF;
184
185 try {
186 TLitePDF litePDF;
187
188 //-----------------------------------------------------------------
189
190 // begin write-only PDF file
191 litePDF.CreateFileDocument("dataops-file1.pdf");
192
193 // fill a page
194 drawPage(litePDF);
195
196 // close the document
197 litePDF.Close();
198
199 //-----------------------------------------------------------------
200
201 // begin write-only PDF file
202 litePDF.CreateMemDocument();
203
204 // fill a page
205 drawPage(litePDF);
206
207 // save memory-based PDF to file
208 litePDF.SaveToFile("dataops-file2.pdf");
209
210 // close the document
211 litePDF.Close();
212
213 //-----------------------------------------------------------------
214
215 // create memory PDF
216 litePDF.CreateMemDocument();
217
218 // fill a page
219 drawPage(litePDF);
220
221 // save to data; the 'data1' and 'data1Length' stores saved PDF now
222 saveToData(litePDF, &data1, data1Length);
223
224 // close the document
225 litePDF.Close();
226
227 //-----------------------------------------------------------------
228
229 // save data to file
230 saveDataToFile("dataops-data1.pdf", data1, data1Length);
231
232 // compare file and data - the content should be the same.
233 // cannot compare write-only file PDF with memory-based, because the way
234 // they are written into the disk are different
235 cmpFileAndData("dataops-file2.pdf", data1, data1Length);
236
237 //-----------------------------------------------------------------
238
239 // load from file
240 litePDF.LoadFromFile("dataops-file2.pdf", NULL, false);
241
242 // save to data
243 saveToData(litePDF, &data2, data2Length);
244
245 // close the document
246 litePDF.Close();
247
248 //-----------------------------------------------------------------
249
250 // save data to file
251 saveDataToFile("dataops-data2.pdf", data2, data2Length);
252
253 // free the data1 and swap with data2, it's reused
254 free(data1);
255 data1 = data2;
256 data2 = NULL;
257 data1Length = data2Length;
258
259 //-----------------------------------------------------------------
260
261 // load from file
262 litePDF.LoadFromFile("dataops-file2.pdf", NULL, true);
263
264 // save to data
265 saveToData(litePDF, &data2, data2Length);
266
267 // close the document
268 litePDF.Close();
269
270 // save data to file
271 saveDataToFile("dataops-data3.pdf", data2, data2Length);
272
273 //-----------------------------------------------------------------
274
275 // compare data - the content should be the same
276 cmpDataAndData(data1, data1Length, data2, data2Length);
277
278 // free the data2, it's reused
279 free(data2);
280 data2 = NULL;
281
282 //-----------------------------------------------------------------
283
284 // load from data
285 litePDF.LoadFromData(data1, data1Length, NULL);
286
287 // save to data
288 saveToData(litePDF, &data2, data2Length);
289
290 // close the document
291 litePDF.Close();
292
293 // save data to file
294 saveDataToFile("dataops-data4.pdf", data2, data2Length);
295
296 //-----------------------------------------------------------------
297
298 // compare data - the content should be the same
299 cmpDataAndData(data1, data1Length, data2, data2Length);
300
301 // free the data2, it's reused
302 free(data2);
303 data2 = NULL;
304
305 //-----------------------------------------------------------------
306
307 } catch (TLitePDFException &ex) {
308 fprintf(stderr, "litePDF Exception: %x: %s\n", ex.getCode(), ex.getMessage());
309 res = 1;
310 }
311
312 if (data1) {
313 free(data1);
314 }
315
316 if (data2) {
317 free(data2);
318 }
319
320 return res;
321 }