1 /* PDF post-processor functions */
10 static char *pdf_title
; /* document title */
11 static int pdf_width
; /* page width */
12 static int pdf_height
; /* page height */
13 static int pdf_pages
; /* pages object id */
14 static int pdf_root
; /* root object id */
15 static int pdf_pos
; /* current pdf file offset */
16 static int *obj_off
; /* object offsets */
17 static int obj_sz
, obj_n
; /* number of pdf objects */
18 static int *page_id
; /* page object ids */
19 static int page_sz
, page_n
; /* number of pages */
21 static struct sbuf
*pg
; /* current page contents */
22 static int o_f
, o_s
, o_m
; /* font and size */
23 static int o_h
, o_v
; /* current user position */
24 static int p_h
, p_v
; /* current output position */
25 static int o_i
, p_i
; /* output and pdf fonts (indices into pfont[]) */
26 static int p_f
, p_s
, p_m
; /* output font */
27 static int o_queued
; /* queued character type */
28 static char o_iset
[1024]; /* fonts accesssed in this page */
29 static int *xobj
; /* page xobject object ids */
30 static int xobj_sz
, xobj_n
; /* number of xobjects */
32 /* loaded PDF fonts */
34 char name
[128]; /* font PostScript name */
35 char path
[1024]; /* font path */
36 char desc
[1024]; /* font descriptor path */
37 int gbeg
; /* the first glyph */
38 int gend
; /* the last glyph */
39 int sub
; /* subfont number */
40 int obj
; /* the font object */
41 int des
; /* font descriptor */
42 int cid
; /* CID-indexed */
45 static struct pfont
*pfonts
;
46 static int pfonts_n
, pfonts_sz
;
48 /* print formatted pdf output */
49 static void pdfout(char *s
, ...)
53 pdf_pos
+= vprintf(s
, ap
);
57 /* print pdf output */
58 static void pdfouts(char *s
)
64 /* print pdf output */
65 static void pdfmem(char *s
, int len
)
67 fwrite(s
, len
, 1, stdout
);
71 /* allocate an object number */
72 static int obj_map(void)
74 if (obj_n
== obj_sz
) {
76 obj_off
= mextend(obj_off
, obj_n
, obj_sz
, sizeof(obj_off
[0]));
81 /* start the definition of an object */
82 static int obj_beg(int id
)
86 obj_off
[id
] = pdf_pos
;
87 pdfout("%d 0 obj\n", id
);
91 /* end an object definition */
92 static void obj_end(void)
97 void out(char *s
, ...)
101 /* the length of the clear-text, encrypted, and fixed-content portions */
102 static int type1lengths(char *t1
, int l
, int *l1
, int *l2
, int *l3
)
105 char *cleartext
= t1
;
106 char *encrypted
= NULL
;
107 char *fixedcont
= NULL
;
108 for (i
= 0; i
< l
- 5 && !encrypted
; i
++)
109 if (t1
[i
] == 'e' && !memcmp("eexec", t1
+ i
, 5))
113 for (; i
< l
- 512 && !fixedcont
; i
++)
114 if (t1
[i
] == '0' && !memcmp("00000", t1
+ i
, 5))
116 *l1
= encrypted
- cleartext
;
117 *l2
= fixedcont
? fixedcont
- cleartext
: 0;
121 /* return font type: 't': TrueType, '1': Type 1, 'o': OpenType */
122 static int fonttype(char *path
)
124 char *ext
= strrchr(path
, '.');
125 if (ext
&& !strcmp(".ttf", ext
))
127 if (ext
&& !strcmp(".otf", ext
))
132 /* write the object corresponding to the given font */
133 static void pfont_write(struct pfont
*ps
)
137 struct font
*fn
= dev_fontopen(ps
->desc
);
138 /* the encoding object */
139 enc_obj
= obj_beg(0);
141 pdfout(" /Type /Encoding\n");
142 pdfout(" /Differences [ %d", ps
->gbeg
% 256);
143 for (i
= ps
->gbeg
; i
<= ps
->gend
; i
++)
144 pdfout(" /%s", font_glget(fn
, i
)->id
);
148 /* the font object */
151 pdfout(" /Type /Font\n");
152 if (fonttype(ps
->path
) == 't')
153 pdfout(" /Subtype /TrueType\n");
155 pdfout(" /Subtype /Type1\n");
156 pdfout(" /BaseFont /%s\n", ps
->name
);
157 pdfout(" /FirstChar %d\n", ps
->gbeg
% 256);
158 pdfout(" /LastChar %d\n", ps
->gend
% 256);
159 pdfout(" /Widths [");
160 for (i
= ps
->gbeg
; i
<= ps
->gend
; i
++)
161 pdfout(" %d", (long) font_glget(fn
, i
)->wid
* 100 * 72 / dev_res
);
163 pdfout(" /FontDescriptor %d 0 R\n", ps
->des
);
164 pdfout(" /Encoding %d 0 R\n", enc_obj
);
170 static void encodehex(struct sbuf
*d
, char *s
, int n
)
172 static char hex
[] = "0123456789ABCDEF";
174 for (i
= 0; i
< n
; i
++) {
175 sbuf_chr(d
, hex
[((unsigned char) s
[i
]) >> 4]);
176 sbuf_chr(d
, hex
[((unsigned char) s
[i
]) & 0x0f]);
177 if (i
% 40 == 39 && i
+ 1 < n
)
183 /* write the object corresponding to this CID font */
184 static void pfont_writecid(struct pfont
*ps
)
187 struct font
*fn
= dev_fontopen(ps
->desc
);
191 cid_obj
= obj_beg(0);
193 pdfout(" /Type /Font\n");
194 pdfout(" /Subtype /CIDFontType2\n");
195 pdfout(" /BaseFont /%s\n", ps
->name
);
196 pdfout(" /CIDSystemInfo <</Ordering(Identity)/Registry(Adobe)/Supplement 0>>\n");
197 pdfout(" /FontDescriptor %d 0 R\n", ps
->des
);
198 pdfout(" /DW 1000\n");
199 while (font_glget(fn
, gcnt
))
201 pdfout(" /W [ %d [", ps
->gbeg
);
202 for (i
= ps
->gbeg
; i
<= ps
->gend
; i
++)
203 pdfout(" %d", (long) font_glget(fn
, i
)->wid
* 100 * 72 / dev_res
);
207 /* the font object */
210 pdfout(" /Type /Font\n");
211 pdfout(" /Subtype /Type0\n");
212 pdfout(" /BaseFont /%s\n", ps
->name
);
213 pdfout(" /Encoding /Identity-H\n");
214 pdfout(" /DescendantFonts [%d 0 R]\n", cid_obj
);
220 /* write font descriptor; returns its object ID */
221 static int writedesc(struct font
*fn
)
226 int fntype
= fonttype(font_path(fn
));
227 if (fntype
== '1' || fntype
== 't') {
228 int fd
= open(font_path(fn
), O_RDONLY
);
229 struct sbuf
*ffsb
= sbuf_make();
230 struct sbuf
*sb
= sbuf_make();
231 int l1
= 0, l2
= 0, l3
= 0;
233 /* reading the font file */
234 while ((nr
= read(fd
, buf
, sizeof(buf
))) > 0)
235 sbuf_mem(ffsb
, buf
, nr
);
238 /* initialize Type 1 lengths */
240 if (type1lengths(sbuf_buf(ffsb
), sbuf_len(ffsb
),
243 /* remove the fixed-content portion of the font */
245 sbuf_cut(ffsb
, l1
+ l2
);
248 /* encoding file contents */
249 encodehex(sb
, sbuf_buf(ffsb
), sbuf_len(ffsb
));
250 /* write font data if it has nonzero length */
252 str_obj
= obj_beg(0);
254 pdfout(" /Filter /ASCIIHexDecode\n");
255 pdfout(" /Length %d\n", sbuf_len(sb
));
256 pdfout(" /Length1 %d\n", l1
);
258 pdfout(" /Length2 %d\n", l2
);
260 pdfout(" /Length3 %d\n", l3
);
263 pdfouts(sbuf_buf(sb
));
264 pdfout("endstream\n");
270 /* the font descriptor */
271 des_obj
= obj_beg(0);
273 pdfout(" /Type /FontDescriptor\n");
274 pdfout(" /FontName /%s\n", font_name(fn
));
275 pdfout(" /Flags 32\n");
276 pdfout(" /FontBBox [-1000 -1000 1000 1000]\n");
277 pdfout(" /MissingWidth 1000\n");
278 pdfout(" /StemV 100\n");
279 pdfout(" /ItalicAngle 0\n");
280 pdfout(" /CapHeight 100\n");
281 pdfout(" /Ascent 100\n");
282 pdfout(" /Descent 100\n");
284 pdfout(" /FontFile%s %d 0 R\n",
285 fntype
== 't' ? "2" : "", str_obj
);
291 static int pfont_find(struct glyph
*g
)
293 struct font
*fn
= g
->font
;
294 char *name
= font_name(fn
);
295 struct pfont
*ps
= NULL
;
296 int fntype
= fonttype(font_path(fn
));
297 int sub
= fntype
== '1' ? font_glnum(fn
, g
) / 256 : 0;
299 for (i
= 0; i
< pfonts_n
; i
++)
300 if (!strcmp(name
, pfonts
[i
].name
) && pfonts
[i
].sub
== sub
)
302 if (pfonts_n
== pfonts_sz
) {
304 pfonts
= mextend(pfonts
, pfonts_n
,
305 pfonts_sz
, sizeof(pfonts
[0]));
307 ps
= &pfonts
[pfonts_n
];
308 snprintf(ps
->name
, sizeof(ps
->name
), "%s", name
);
309 snprintf(ps
->path
, sizeof(ps
->path
), "%s", font_path(fn
));
310 snprintf(ps
->desc
, sizeof(ps
->desc
), "%s", font_desc(fn
));
311 ps
->cid
= fntype
== 't';
315 for (i
= 0; i
< pfonts_n
; i
++)
316 if (!strcmp(pfonts
[i
].name
, ps
->name
))
319 ps
->des
= pfonts
[i
].des
;
321 ps
->des
= writedesc(fn
);
325 static void pfont_done(void)
328 for (i
= 0; i
< pfonts_n
; i
++) {
330 pfont_writecid(&pfonts
[i
]);
332 pfont_write(&pfonts
[i
]);
337 static void o_flush(void)
340 sbuf_printf(pg
, ">] TJ\n");
344 static int o_loadfont(struct glyph
*g
)
346 int fn
= pfont_find(g
);
351 /* like pdfpos() but assume that uh and uv are multiplied by 100 */
352 static char *pdfpos00(int uh
, int uv
)
355 int h
= (long) uh
* 72 / dev_res
;
356 int v
= (long) pdf_height
* 100 - (long) uv
* 72 / dev_res
;
357 sprintf(buf
, "%s%d.%02d %s%d.%02d",
358 h
< 0 ? "-" : "", abs(h
) / 100, abs(h
) % 100,
359 v
< 0 ? "-" : "", abs(v
) / 100, abs(v
) % 100);
363 /* convert troff position to pdf position; returns a static buffer */
364 static char *pdfpos(int uh
, int uv
)
366 return pdfpos00(uh
* 100, uv
* 100);
369 /* troff length to thousands of a unit of text space; returns a static buffer */
370 static char *pdfunit(int uh
, int sz
)
373 int h
= (long) uh
* 1000 * 72 / sz
/ dev_res
;
374 sprintf(buf
, "%s%d", h
< 0 ? "-" : "", abs(h
));
378 /* convert troff color to pdf color; returns a static buffer */
379 static char *pdfcolor(int m
)
382 int r
= CLR_R(m
) * 1000 / 255;
383 int g
= CLR_G(m
) * 1000 / 255;
384 int b
= CLR_B(m
) * 1000 / 255;
385 sbuf_printf(pg
, "%d.%03d %d.%03d %d.%03d",
386 r
/ 1000, r
% 1000, g
/ 1000, g
% 1000, b
/ 1000, b
% 1000);
390 static void o_queue(struct glyph
*g
)
395 sbuf_printf(pg
, "1 0 0 1 %s Tm\n", pdfpos(o_h
, o_v
));
400 sbuf_printf(pg
, "[<");
403 sbuf_printf(pg
, "> %s <", pdfunit(p_h
- o_h
, o_s
));
404 /* printing glyph identifier */
405 gid
= font_glnum(g
->font
, g
);
407 sbuf_printf(pg
, "%04x", gid
);
409 sbuf_printf(pg
, "%02x", gid
% 256);
410 /* updating gbeg and gend */
411 if (gid
< pfonts
[o_i
].gbeg
)
412 pfonts
[o_i
].gbeg
= gid
;
413 if (gid
> pfonts
[o_i
].gend
)
414 pfonts
[o_i
].gend
= gid
;
416 p_h
= o_h
+ font_wid(g
->font
, o_s
, g
->wid
);
419 static void out_fontup(void)
423 sbuf_printf(pg
, "%s rg\n", pdfcolor(o_m
));
426 if (o_i
>= 0 && (o_i
!= p_i
|| o_s
!= p_s
)) {
427 struct pfont
*ps
= &pfonts
[o_i
];
430 sbuf_printf(pg
, "/%s %d Tf\n", ps
->name
, o_s
);
432 sbuf_printf(pg
, "/%s.%d %d Tf\n", ps
->name
, ps
->sub
, o_s
);
442 g
= dev_glyph(c
, o_f
);
443 fn
= g
? g
->font
: dev_font(o_f
);
445 outrel(*c
== ' ' && fn
? font_swid(fn
, o_s
) : 1, 0);
463 void outrel(int h
, int v
)
486 void outrotate(int deg
)
490 void outeps(char *eps
)
494 static char *strcut(char *dst
, char *src
)
496 while (*src
== ' ' || *src
== '\n')
500 while (*src
&& (src
[0] != '"' || src
[1] == '"')) {
508 while (*src
&& *src
!= ' ' && *src
!= '\n')
515 /* return a copy of a PDF object; returns a static buffer */
516 static char *pdf_copy(char *pdf
, int len
, int pos
)
518 static char buf
[1 << 12];
520 pos
+= pdf_ws(pdf
, len
, pos
);
521 datlen
= pdf_len(pdf
, len
, pos
);
522 if (datlen
> sizeof(buf
) - 1)
523 datlen
= sizeof(buf
) - 1;
524 memcpy(buf
, pdf
+ pos
, datlen
);
529 static void pdf_dictcopy(char *pdf
, int len
, int pos
, struct sbuf
*sb
);
531 /* write stream to sb */
532 static int pdf_strcopy(char *pdf
, int len
, int pos
, struct sbuf
*sb
)
536 if ((val
= pdf_dval_val(pdf
, len
, pos
, "/Length")) < 0)
538 slen
= atoi(pdf
+ val
);
539 pos
= pos
+ pdf_len(pdf
, len
, pos
);
540 pos
+= pdf_ws(pdf
, len
, pos
);
541 if (pos
+ slen
+ 15 > len
)
544 pos
+= strlen("stream");
545 if (pdf
[pos
] == '\r')
548 if (pdf
[pos
] == '\r' || pdf
[pos
] == ' ')
550 if (pdf
[pos
] == '\n')
552 pos
+= strlen("endstream") + 1;
553 sbuf_mem(sb
, pdf
+ beg
, pos
- beg
);
557 /* copy a PDF object and return its new identifier */
558 static int pdf_objcopy(char *pdf
, int len
, int pos
)
561 if ((pos
= pdf_ref(pdf
, len
, pos
)) < 0)
563 if (pdf_type(pdf
, len
, pos
) == 'd') {
564 struct sbuf
*sb
= sbuf_make();
565 pdf_dictcopy(pdf
, len
, pos
, sb
);
567 if (pdf_dval(pdf
, len
, pos
, "/Length") >= 0)
568 pdf_strcopy(pdf
, len
, pos
, sb
);
570 pdfmem(sbuf_buf(sb
), sbuf_len(sb
));
575 pdfmem(pdf
+ pos
, pdf_len(pdf
, len
, pos
));
582 /* copy a PDF dictionary recursively */
583 static void pdf_dictcopy(char *pdf
, int len
, int pos
, struct sbuf
*sb
)
587 sbuf_printf(sb
, "<<");
589 if ((key
= pdf_dkey(pdf
, len
, pos
, i
)) < 0)
591 sbuf_printf(sb
, " %s", pdf_copy(pdf
, len
, key
));
592 val
= pdf_dval(pdf
, len
, pos
, pdf_copy(pdf
, len
, key
));
593 if (pdf_type(pdf
, len
, val
) == 'r') {
594 if ((id
= pdf_objcopy(pdf
, len
, val
)) >= 0)
595 sbuf_printf(sb
, " %d 0 R", id
);
597 sbuf_printf(sb
, " %s", pdf_copy(pdf
, len
, val
));
600 sbuf_printf(sb
, " >>");
603 /* copy resources dictionary */
604 static void pdf_rescopy(char *pdf
, int len
, int pos
, struct sbuf
*sb
)
606 char *res_fields
[] = {"/ProcSet", "/ExtGState", "/ColorSpace",
607 "/Pattern", "/Shading", "/Properties", "/Font", "/XObject"};
609 sbuf_printf(sb
, " /Resources <<\n");
610 for (i
= 0; i
< LEN(res_fields
); i
++) {
611 if ((res
= pdf_dval_val(pdf
, len
, pos
, res_fields
[i
])) >= 0) {
612 if (pdf_type(pdf
, len
, res
) == 'd') {
613 sbuf_printf(sb
, " %s ", res_fields
[i
]);
614 pdf_dictcopy(pdf
, len
, res
, sb
);
615 sbuf_printf(sb
, "\n");
617 sbuf_printf(sb
, " %s %s\n", res_fields
[i
],
618 pdf_copy(pdf
, len
, res
));
622 sbuf_printf(sb
, " >>\n");
625 static int pdfext(char *pdf
, int len
)
627 char *cont_fields
[] = {"/Filter", "/DecodeParms"};
628 int trailer
, root
, cont
, pages
, page1
, res
;
629 int kids_val
, page1_val
, val
;
634 if ((trailer
= pdf_trailer(pdf
, len
)) < 0)
636 if ((root
= pdf_dval_obj(pdf
, len
, trailer
, "/Root")) < 0)
638 if ((pages
= pdf_dval_obj(pdf
, len
, root
, "/Pages")) < 0)
640 if ((kids_val
= pdf_dval_val(pdf
, len
, pages
, "/Kids")) < 0)
642 if ((page1_val
= pdf_lval(pdf
, len
, kids_val
, 0)) < 0)
644 if ((page1
= pdf_ref(pdf
, len
, page1_val
)) < 0)
646 if ((cont
= pdf_dval_obj(pdf
, len
, page1
, "/Contents")) < 0)
648 if ((val
= pdf_dval_val(pdf
, len
, cont
, "/Length")) < 0)
650 res
= pdf_dval_val(pdf
, len
, page1
, "/Resources");
651 length
= atoi(pdf
+ val
);
652 bbox
= pdf_dval_val(pdf
, len
, page1
, "/MediaBox");
654 bbox
= pdf_dval_val(pdf
, len
, pages
, "/MediaBox");
656 sbuf_printf(sb
, "<<\n");
657 sbuf_printf(sb
, " /Type /XObject\n");
658 sbuf_printf(sb
, " /Subtype /Form\n");
659 sbuf_printf(sb
, " /FormType 1\n");
661 sbuf_printf(sb
, " /BBox %s\n", pdf_copy(pdf
, len
, bbox
));
662 sbuf_printf(sb
, " /Matrix [1 0 0 1 %s]\n", pdfpos(o_h
, o_v
));
664 pdf_rescopy(pdf
, len
, res
, sb
);
665 sbuf_printf(sb
, " /Length %d\n", length
);
666 for (i
= 0; i
< LEN(cont_fields
); i
++)
667 if ((val
= pdf_dval_val(pdf
, len
, cont
, cont_fields
[i
])) >= 0)
668 sbuf_printf(sb
, " %s %s\n", cont_fields
[i
],
669 pdf_copy(pdf
, len
, val
));
670 sbuf_printf(sb
, ">>\n");
671 pdf_strcopy(pdf
, len
, cont
, sb
);
672 xobj_id
= obj_beg(0);
673 pdfmem(sbuf_buf(sb
), sbuf_len(sb
));
676 if (xobj_n
== xobj_sz
) {
678 xobj
= mextend(xobj
, xobj_n
, xobj_sz
, sizeof(xobj
[0]));
680 xobj
[xobj_n
++] = xobj_id
;
684 void outpdf(char *spec
)
691 spec
= strcut(pdf
, spec
);
694 /* reading the pdf file */
696 fd
= open(pdf
, O_RDONLY
);
697 while ((nr
= read(fd
, buf
, sizeof(buf
))) > 0)
698 sbuf_mem(sb
, buf
, nr
);
701 xobj_id
= pdfext(sbuf_buf(sb
), sbuf_len(sb
));
705 sbuf_printf(pg
, "ET /FO%d Do BT\n", xobj_id
);
710 void outlink(char *spec
)
737 static int draw_path
; /* number of path segments */
738 static int draw_point
; /* point was set for postscript newpath */
746 sbuf_printf(pg
, "%s m\n", pdfpos(o_h
, o_v
));
749 void drawend(int close
, int fill
)
754 if (!fill
) /* stroking color */
755 sbuf_printf(pg
, "%s RG\n", pdfcolor(o_m
));
757 sbuf_printf(pg
, "f\n");
759 sbuf_printf(pg
, close
? "s\n" : "S\n");
762 void drawmbeg(char *s
)
766 void drawmend(char *s
)
770 void drawl(int h
, int v
)
773 sbuf_printf(pg
, "%s l\n", pdfpos(o_h
, o_v
));
776 /* draw circle/ellipse quadrant */
777 static void drawquad(int ch
, int cv
)
780 long x0
= o_h
* 1000;
781 long y0
= o_v
* 1000;
782 long x3
= x0
+ ch
* 1000 / 2;
783 long y3
= y0
+ cv
* 1000 / 2;
785 long y1
= y0
+ cv
* b
/ 1000 / 2;
786 long x2
= x0
+ ch
* b
/ 1000 / 2;
789 x1
= x3
- ch
* b
/ 1000 / 2;
792 y2
= y3
- cv
* b
/ 1000 / 2;
794 sbuf_printf(pg
, "%s ", pdfpos00(x1
/ 10, y1
/ 10));
795 sbuf_printf(pg
, "%s ", pdfpos00(x2
/ 10, y2
/ 10));
796 sbuf_printf(pg
, "%s c\n", pdfpos00(x3
/ 10, y3
/ 10));
797 outrel(ch
/ 2, cv
/ 2);
810 /* draw an ellipse */
811 void drawe(int h
, int v
)
821 void drawa(int h1
, int v1
, int h2
, int v2
)
823 drawl(h1
+ h2
, v1
+ v2
);
827 void draws(int h1
, int v1
, int h2
, int v2
)
830 sbuf_printf(pg
, "%s l\n", pdfpos(o_h
, o_v
));
833 void ps_header(char *title
, int pagewidth
, int pageheight
, int linewidth
)
837 pdf_root
= obj_map();
838 pdf_pages
= obj_map();
840 pdfout("%%PDF-1.6\n");
841 pdf_width
= (pagewidth
* 72 + 127) / 254;
842 pdf_height
= (pageheight
* 72 + 127) / 254;
845 void ps_trailer(int pages
)
850 /* pdf pages object */
853 pdfout(" /Type /Pages\n");
854 pdfout(" /MediaBox [ 0 0 %d %d ]\n", pdf_width
, pdf_height
);
855 pdfout(" /Count %d\n", page_n
);
857 for (i
= 0; i
< page_n
; i
++)
858 pdfout(" %d 0 R", page_id
[i
]);
862 /* pdf root object */
865 pdfout(" /Type /Catalog\n");
866 pdfout(" /Pages %d 0 R\n", pdf_pages
);
872 info_id
= obj_beg(0);
875 pdfout(" /Title (%s)\n", pdf_title
);
876 pdfout(" /Creator (Neatroff)\n");
877 pdfout(" /Producer (Neatpost)\n");
883 pdfout("0 %d\n", obj_n
);
884 pdfout("0000000000 65535 f \n");
885 for (i
= 1; i
< obj_n
; i
++)
886 pdfout("%010d 00000 n \n", obj_off
[i
]);
890 pdfout(" /Size %d\n", obj_n
);
891 pdfout(" /Root %d 0 R\n", pdf_root
);
892 pdfout(" /Info %d 0 R\n", info_id
);
894 pdfout("startxref\n");
895 pdfout("%d\n", xref_off
);
901 void ps_pagebeg(int n
)
904 sbuf_printf(pg
, "BT\n");
907 void ps_pageend(int n
)
912 sbuf_printf(pg
, "ET\n");
914 cont_id
= obj_beg(0);
916 pdfout(" /Length %d\n", sbuf_len(pg
) - 1);
919 pdfmem(sbuf_buf(pg
), sbuf_len(pg
));
920 pdfout("endstream\n");
922 /* the page object */
923 if (page_n
== page_sz
) {
925 page_id
= mextend(page_id
, page_n
, page_sz
, sizeof(page_id
[0]));
927 page_id
[page_n
++] = obj_beg(0);
929 pdfout(" /Type /Page\n");
930 pdfout(" /Parent %d 0 R\n", pdf_pages
);
931 pdfout(" /Resources <<\n");
933 for (i
= 0; i
< pfonts_n
; i
++) {
935 struct pfont
*ps
= &pfonts
[i
];
937 pdfout(" /%s %d 0 R", ps
->name
, ps
->obj
);
939 pdfout(" /%s.%d %d 0 R", ps
->name
, ps
->sub
, ps
->obj
);
943 if (xobj_n
) { /* XObjects */
944 pdfout(" /XObject <<");
945 for (i
= 0; i
< xobj_n
; i
++)
946 pdfout(" /FO%d %d 0 R", i
, xobj
[i
]);
950 pdfout(" /Contents %d 0 R\n", cont_id
);
954 memset(o_iset
, 0, pfonts_n
* sizeof(o_iset
[0]));