1 /*
2 * PDF file output routines.
3 *
4 * Copyright 2008 by Tobias Hoffmann.
5 *
6 * This file is licensed as noted in "COPYING"
7 * which should have been included with this file.
8 *
9 */
10 #include <stdio.h>
11 #include <assert.h>
12 #include <stdarg.h>
13 #include <memory.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include "pdfutils.h"
17 #include "fontembed/embed.h"
18
pdfOut_printf(pdfOut * pdf,const char * fmt,...)19 void pdfOut_printf(pdfOut *pdf,const char *fmt,...) // {{{
20 {
21 assert(pdf);
22 int len;
23 va_list ap;
24
25 va_start(ap,fmt);
26 len=vprintf(fmt,ap);
27 va_end(ap);
28 pdf->filepos+=len;
29 }
30 // }}}
31
pdfOut_putString(pdfOut * pdf,const char * str,int len)32 void pdfOut_putString(pdfOut *pdf,const char *str,int len) // {{{ - >len==-1: strlen()
33 {
34 assert(pdf);
35 assert(str);
36 if (len==-1) {
37 len=strlen(str);
38 }
39 putc('(',stdout);
40 // escape special chars: \0 \\ \( \) -- don't bother about balanced parens
41 int iA=0;
42 for (;len>0;iA++,len--) {
43 if ( (str[iA]<32)||(str[iA]>126) ) {
44 fwrite(str,1,iA,stdout);
45 fprintf(stdout,"\\%03o",(unsigned char)str[iA]);
46 pdf->filepos+=iA+4;
47 str+=iA+1;
48 iA=-1;
49 } else if ( (str[iA]=='(')||(str[iA]==')')||(str[iA]=='\\') ) {
50 fwrite(str,1,iA,stdout);
51 fprintf(stdout,"\\%c",str[iA]);
52 pdf->filepos+=iA+2;
53 str+=iA+1;
54 iA=-1;
55 }
56 }
57 pdf->filepos+=iA+2;
58 fwrite(str,1,iA,stdout);
59 putc(')',stdout);
60 }
61 // }}}
62
pdfOut_putHexString(pdfOut * pdf,const char * str,int len)63 void pdfOut_putHexString(pdfOut *pdf,const char *str,int len) // {{{ - >len==-1: strlen()
64 {
65 assert(pdf);
66 assert(str);
67 if (len==-1) {
68 len=strlen(str);
69 }
70 pdf->filepos+=2*len+2;
71 putc('<',stdout);
72 for (;len>0;str++,len--) {
73 fprintf(stdout,"%02x",(unsigned char)*str);
74 }
75 putc('>',stdout);
76 }
77 // }}}
78
pdfOut_new()79 pdfOut *pdfOut_new() // {{{ - NULL on error
80 {
81 pdfOut *ret=malloc(sizeof(pdfOut));
82 if (ret) {
83 memset(ret,0,sizeof(pdfOut));
84 }
85
86 return ret;
87 }
88 // }}}
89
90 // NOTE: uses statically allocated buffer
pdfOut_to_pdfdate(struct tm * curtm)91 const char *pdfOut_to_pdfdate(struct tm *curtm) // {{{
92 {
93 static char curdate[250];
94 if (!curtm) {
95 time_t curtime;
96 curtime = time(NULL);
97 curtm = localtime(&curtime);
98 }
99 strftime(curdate, sizeof(curdate), "D:%Y%m%d%H%M%S%z", curtm);
100 curdate[23]=0;
101 curdate[22]='\'';
102 curdate[21]=curdate[18];
103 curdate[20]=curdate[17];
104 curdate[19]='\'';
105 return curdate;
106 }
107 // }}}
108
pdfOut_add_xref(pdfOut * pdf)109 int pdfOut_add_xref(pdfOut *pdf) // {{{ - returns obj_no
110 {
111 assert(pdf);
112 assert(pdf->xrefsize<=pdf->xrefalloc);
113
114 if (pdf->xrefsize==pdf->xrefalloc) {
115 long *tmp;
116 pdf->xrefalloc+=50;
117 tmp=realloc(pdf->xref,sizeof(long)*pdf->xrefalloc);
118 if (!tmp) {
119 pdf->xrefalloc=-1;
120 return -1;
121 }
122 pdf->xref=tmp;
123 }
124 pdf->xref[pdf->xrefsize++]=pdf->filepos;
125 return pdf->xrefsize; // xrefsize+1
126 }
127 // }}}
128
pdfOut_add_page(pdfOut * pdf,int obj)129 int pdfOut_add_page(pdfOut *pdf,int obj) // {{{ - returns false on error
130 {
131 assert(pdf);
132 assert(obj>0);
133 assert(pdf->pagessize<=pdf->pagesalloc);
134
135 if (pdf->pagessize==pdf->pagesalloc) {
136 int *tmp;
137 pdf->pagesalloc+=10;
138 tmp=realloc(pdf->pages,sizeof(int)*pdf->pagesalloc);
139 if (!tmp) {
140 pdf->pagesalloc=-1;
141 return 0;
142 }
143 pdf->pages=tmp;
144 }
145 pdf->pages[pdf->pagessize++]=obj;
146 return 1;
147 }
148 // }}}
149
pdfOut_add_kv(pdfOut * pdf,const char * key,const char * val)150 int pdfOut_add_kv(pdfOut *pdf,const char *key,const char *val) // {{{ - returns false on error
151 {
152 assert(pdf);
153 assert(pdf->kvsize<=pdf->kvalloc);
154
155 if (pdf->kvsize==pdf->kvalloc) {
156 struct keyval_t *tmp;
157 pdf->kvalloc+=10;
158 tmp=realloc(pdf->kv,sizeof(struct keyval_t)*pdf->kvalloc);
159 if (!tmp) {
160 pdf->kvalloc=-1;
161 return 0;
162 }
163 pdf->kv=tmp;
164 }
165 pdf->kv[pdf->kvsize].key=strdup(key);
166 pdf->kv[pdf->kvsize].value=strdup(val);
167 if ( (!pdf->kv[pdf->kvsize].key)||(!pdf->kv[pdf->kvsize].value) ) {
168 return 0;
169 }
170 pdf->kvsize++;
171 return 1;
172 }
173 // }}}
174
pdfOut_begin_pdf(pdfOut * pdf)175 int pdfOut_begin_pdf(pdfOut *pdf) // ,...output_device?...) // {{{ - false on error
176 {
177 assert(pdf);
178 assert(pdf->kvsize==0); // otherwise: finish_pdf has not been called
179 int pages_obj;
180
181 pdf->xrefsize=pdf->pagessize=0;
182 pdf->filepos=0;
183 pages_obj=pdfOut_add_xref(pdf); // fixed later
184 if (pages_obj!=1) {
185 return 0;
186 }
187 pdfOut_printf(pdf,"%%PDF-1.3\n");
188 return 1;
189 }
190 // }}}
191
pdfOut_finish_pdf(pdfOut * pdf)192 void pdfOut_finish_pdf(pdfOut *pdf) // {{{
193 {
194 int iA;
195 int root_obj,info_obj=0,xref_start;
196 assert( (pdf)&&(pdf->filepos!=-1) );
197
198 // pages
199 const int pages_obj=1;
200 pdf->xref[0]=pdf->filepos; // now fix it
201 pdfOut_printf(pdf,"%d 0 obj\n"
202 "<</Type/Pages\n"
203 " /Count %d\n"
204 " /Kids [",
205 pages_obj,pdf->pagessize);
206 for (iA=0;iA<pdf->pagessize;iA++) {
207 pdfOut_printf(pdf,"%d 0 R ",pdf->pages[iA]);
208 }
209 pdfOut_printf(pdf,"]\n"
210 ">>\n"
211 "endobj\n");
212
213 // rootdict
214 root_obj=pdfOut_add_xref(pdf);
215 pdfOut_printf(pdf,"%d 0 obj\n"
216 "<</Type/Catalog\n"
217 " /Pages %d 0 R\n"
218 ">>\n"
219 "endobj\n",
220 root_obj,pages_obj);
221
222 // info
223 if (pdf->kvsize) {
224 info_obj=pdfOut_add_xref(pdf);
225 pdfOut_printf(pdf,"%d 0 obj\n"
226 "<<\n",
227 info_obj);
228 for (iA=0;iA<pdf->kvsize;iA++) {
229 pdfOut_printf(pdf," /%s ",pdf->kv[iA].key);
230 pdfOut_putString(pdf,pdf->kv[iA].value,-1);
231 pdfOut_printf(pdf,"\n");
232 }
233 pdfOut_printf(pdf,">>\n"
234 "endobj\n");
235 }
236 // TODO: some return-value checking (??)
237
238 // write xref
239 xref_start=pdf->filepos;
240 pdfOut_printf(pdf,"xref\n"
241 "%d %d\n"
242 "%010d 65535 f \n",
243 0,pdf->xrefsize+1,0);
244 for (iA=0;iA<pdf->xrefsize;iA++) {
245 pdfOut_printf(pdf,"%010ld 00000 n \n",
246 pdf->xref[iA]);
247 }
248 pdfOut_printf(pdf,"trailer\n"
249 "<<\n"
250 " /Size %d\n"
251 " /Root %d 0 R\n",
252 pdf->xrefsize+1,
253 root_obj);
254 if (info_obj) {
255 pdfOut_printf(pdf," /Info %d 0 R\n",info_obj);
256 }
257 pdfOut_printf(pdf,">>\n"
258 "startxref\n"
259 "%d\n"
260 "%%%%EOF\n",
261 xref_start);
262
263 // set to done
264 pdf->filepos=-1;
265 for (iA=0;iA<pdf->kvsize;iA++) {
266 free(pdf->kv[iA].key);
267 free(pdf->kv[iA].value);
268 }
269 pdf->kvsize=0;
270 }
271 // }}}
272
pdfOut_free(pdfOut * pdf)273 void pdfOut_free(pdfOut *pdf) // {{{
274 {
275 if (pdf) {
276 assert(pdf->kvsize==0); // otherwise: finish_pdf has not been called
277 free(pdf->kv);
278 free(pdf->pages);
279 free(pdf->xref);
280 free(pdf);
281 }
282 }
283 // }}}
284
pdfOut_outfn(const char * buf,int len,void * context)285 static void pdfOut_outfn(const char *buf,int len,void *context) // {{{
286 {
287 pdfOut *pdf=(pdfOut *)context;
288
289 if (fwrite(buf,1,len,stdout)!=len) {
290 perror("Short write");
291 assert(0);
292 return;
293 }
294 pdf->filepos+=len;
295 }
296 // }}}
297
pdfOut_write_font(pdfOut * pdf,EMB_PARAMS * emb)298 int pdfOut_write_font(pdfOut *pdf,EMB_PARAMS *emb) // {{{
299 {
300 assert(pdf);
301 assert(emb);
302
303 EMB_PDF_FONTDESCR *fdes=emb_pdf_fontdescr(emb);
304 if (!fdes) {
305 if (emb->outtype==EMB_FMT_STDFONT) { // std-14 font
306 const int f_obj=pdfOut_add_xref(pdf);
307 char *res=emb_pdf_simple_stdfont(emb);
308 if (!res) {
309 return 0;
310 }
311
312 pdfOut_printf(pdf,"%d 0 obj\n"
313 "%s"
314 "endobj\n"
315 ,f_obj,res);
316 free(res);
317 return f_obj;
318 }
319 return 0;
320 }
321
322 const int ff_obj=pdfOut_add_xref(pdf);
323 pdfOut_printf(pdf,"%d 0 obj\n"
324 "<</Length %d 0 R\n"
325 ,ff_obj,ff_obj+1);
326 if (emb_pdf_get_fontfile_subtype(emb)) {
327 pdfOut_printf(pdf," /Subtype /%s\n",
328 emb_pdf_get_fontfile_subtype(emb));
329 }
330 if (emb->outtype==EMB_FMT_TTF) {
331 pdfOut_printf(pdf," /Length1 %d 0 R\n"
332 ,ff_obj+2);
333 } else if (emb->outtype==EMB_FMT_T1) { // TODO
334 pdfOut_printf(pdf," /Length1 ?\n"
335 " /Length2 ?\n"
336 " /Length3 ?\n"
337 );
338 }
339 pdfOut_printf(pdf,">>\n"
340 "stream\n");
341 long streamsize=-pdf->filepos;
342 const int outlen=emb_embed(emb,pdfOut_outfn,pdf);
343 streamsize+=pdf->filepos;
344 pdfOut_printf(pdf,"\nendstream\n"
345 "endobj\n");
346
347 const int l0_obj=pdfOut_add_xref(pdf);
348 assert(l0_obj==ff_obj+1);
349 pdfOut_printf(pdf,"%d 0 obj\n"
350 "%ld\n"
351 "endobj\n"
352 ,l0_obj,streamsize);
353
354 if (emb->outtype==EMB_FMT_TTF) {
355 const int l1_obj=pdfOut_add_xref(pdf);
356 assert(l1_obj==ff_obj+2);
357 pdfOut_printf(pdf,"%d 0 obj\n"
358 "%d\n"
359 "endobj\n"
360 ,l1_obj,outlen);
361 }
362
363 const int fd_obj=pdfOut_add_xref(pdf);
364 char *res=emb_pdf_simple_fontdescr(emb,fdes,ff_obj);
365 if (!res) {
366 free(fdes);
367 return 0;
368 }
369 pdfOut_printf(pdf,"%d 0 obj\n"
370 "%s"
371 "endobj\n"
372 ,fd_obj,res);
373 free(res);
374
375 EMB_PDF_FONTWIDTHS *fwid=emb_pdf_fontwidths(emb);
376 if (!fwid) {
377 free(fdes);
378 return 0;
379 }
380 const int f_obj=pdfOut_add_xref(pdf);
381 res=emb_pdf_simple_font(emb,fdes,fwid,fd_obj);
382 if (!res) {
383 free(fwid);
384 free(fdes);
385 return 0;
386 }
387 pdfOut_printf(pdf,"%d 0 obj\n"
388 "%s"
389 "endobj\n"
390 ,f_obj,res);
391 free(res);
392 free(fwid);
393
394 if (emb->plan&EMB_A_MULTIBYTE) {
395 res=emb_pdf_simple_cidfont(emb,fdes->fontname,f_obj);
396 if (!res) {
397 free(fdes);
398 return 0;
399 }
400 const int cf_obj=pdfOut_add_xref(pdf);
401 pdfOut_printf(pdf,"%d 0 obj\n"
402 "%s"
403 "endobj\n"
404 ,cf_obj,res);
405 free(res);
406 free(fdes);
407 return cf_obj;
408 }
409
410 free(fdes);
411 return f_obj;
412 }
413 // }}}
414
415 #if 0
416 one_page(...parent,resources,mediabox,contents);
417 {
418 // " /Resources %d 0 R\n"
419 pdfOut_printf(pdf,"%d 0 obj\n"
420 "<</Type/Page\n"
421 " /Parent 1 0 R\n"
422 " /MediaBox [0 0 %d %d]\n"
423 " /Contents %d 0 R\n"
424 ">>\n"
425 "endobj\n"
426 ,,,PageWidth,PageLength // TODO: into pdf->
427 ...
428 }
429
430 ... pfb_embedder ... pfa?
431 #endif
432