1 #include "embed.h"
2 #include "embed_pdf.h" // already included fron embed.h ...
3 #include "embed_pdf_int.h"
4 #include "embed_sfnt_int.h"
5 #include <assert.h>
6 #include <errno.h>
7 #include <string.h>
8 #include <time.h>
9 #include "frequent.h"
10
11 // NOTE: these must be in sync with the EMB_FORMAT enum
12 static const char *emb_pdf_font_subtype[][2]={ // {{{ (output_format,multibyte)
13 {"Type1",NULL},
14 {"TrueType","CIDFontType2"},
15 {"Type1","CIDFontType0"},
16 {"Type1","CIDFontType0"},
17 {"Type1",NULL}};
18 // }}}
19
20 static const char *emb_pdf_fontfile_key[]={ // {{{ (output_format)
21 "FontFile","FontFile2","FontFile3","FontFile3",NULL};
22 // }}}
23
24 // ... PDF1.6 here
25 static const char *emb_pdf_fontfile_subtype[][2]={ // {{{ (output_format,multibyte)
26 {NULL,NULL},
27 {NULL,NULL},
28 {"OpenType","OpenType"},
29 {"Type1C","CIDFontType0C"},
30 {NULL,NULL}};
31 // }}}
32
emb_multibyte(EMB_PARAMS * emb)33 static inline int emb_multibyte(EMB_PARAMS *emb) // {{{
34 {
35 return (emb->plan&EMB_A_MULTIBYTE)?1:0;
36 }
37 // }}}
38
emb_pdf_escape_name(const char * name,int len)39 static const char *emb_pdf_escape_name(const char *name,int len) // {{{ // - statically allocated buffer
40 {
41 assert(name);
42 if (len==-1) {
43 len=strlen(name);
44 }
45 assert(len<=127); // pdf implementation limit
46
47 static char buf[128*3];
48 int iA,iB;
49 const char hex[]="0123456789abcdef";
50
51 for (iA=0,iB=0;iA<len;iA++,iB++) {
52 if ( ((unsigned char)name[iA]<33)||((unsigned char)name[iA]>126)||
53 (strchr("#()<>[]{}/%",name[iA])) ) {
54 buf[iB]='#';
55 buf[++iB]=hex[(name[iA]>>4)&0x0f];
56 buf[++iB]=hex[name[iA]&0xf];
57 } else {
58 buf[iB]=name[iA];
59 }
60 }
61 buf[iB]=0;
62 return buf;
63 }
64 // }}}
65
66 // this is in the font dict
emb_pdf_get_font_subtype(EMB_PARAMS * emb)67 const char *emb_pdf_get_font_subtype(EMB_PARAMS *emb) // {{{
68 {
69 assert(emb);
70 return emb_pdf_font_subtype[emb->outtype][emb_multibyte(emb)];
71 }
72 // }}}
73
74 // in font descriptor
emb_pdf_get_fontfile_key(EMB_PARAMS * emb)75 const char *emb_pdf_get_fontfile_key(EMB_PARAMS *emb) // {{{
76 {
77 assert(emb);
78 return emb_pdf_fontfile_key[emb->outtype];
79 }
80 // }}}
81
82 // this is what to put in the font-stream dict
emb_pdf_get_fontfile_subtype(EMB_PARAMS * emb)83 const char *emb_pdf_get_fontfile_subtype(EMB_PARAMS *emb) // {{{
84 {
85 assert(emb);
86 return emb_pdf_fontfile_subtype[emb->outtype][emb_multibyte(emb)];
87 }
88 // }}}
89
90 // {{{ static EMB_PDF_FONTDESCR *emb_pdf_fd_new(fontname,subset_tag,cid_registry,cid_ordering,cid_supplement,panose)
emb_pdf_fd_new(const char * fontname,const char * subset_tag,const char * cid_registry,const char * cid_ordering,int cid_supplement)91 static EMB_PDF_FONTDESCR *emb_pdf_fd_new(const char *fontname,
92 const char *subset_tag,
93 const char *cid_registry, // or supplement==-1
94 const char *cid_ordering, // or supplement==-1
95 int cid_supplement) // -1 for non-cid
96 {
97 assert(fontname);
98 EMB_PDF_FONTDESCR *ret;
99
100 int len=sizeof(EMB_PDF_FONTDESCR);
101 if (subset_tag) {
102 assert(strlen(subset_tag)==6);
103 len+=7;
104 }
105 len+=strlen(fontname)+1;
106 if (cid_supplement>=0) { // cid font
107 len+=12; // space for panose
108 assert(cid_registry);
109 assert(cid_ordering);
110 len+=strlen(cid_registry)+1;
111 len+=strlen(cid_ordering)+1;
112 }
113 ret=calloc(1,len);
114 if (!ret) {
115 fprintf(stderr,"Bad alloc: %s\n", strerror(errno));
116 assert(0);
117 return NULL;
118 }
119
120 // now fill the struct
121 len=0;
122 if (cid_supplement>=0) { // free space for panose is at beginning
123 len+=12;
124 }
125 ret->fontname=ret->data+len;
126 len+=strlen(fontname)+1;
127 if (subset_tag) {
128 snprintf(ret->fontname, 6, "%s", subset_tag);
129 ret->fontname[6]='+';
130 strcpy(ret->fontname+7,fontname);
131 len+=7;
132 } else {
133 strcpy(ret->fontname,fontname);
134 }
135 ret->italicAngle=90;
136 if (cid_supplement>=0) {
137 ret->registry=ret->data+len;
138 strcpy(ret->registry,cid_registry);
139 len+=strlen(cid_registry)+1;
140
141 ret->ordering=ret->data+len;
142 strcpy(ret->ordering,cid_ordering);
143 len+=strlen(cid_registry)+1;
144 }
145 ret->supplement=cid_supplement;
146
147 return ret;
148 }
149 // }}}
150
emb_pdf_fontdescr(EMB_PARAMS * emb)151 EMB_PDF_FONTDESCR *emb_pdf_fontdescr(EMB_PARAMS *emb) // {{{ - to be freed by user
152 {
153 assert(emb);
154
155 const char *subset_tag=NULL;
156 // {{{ generate pdf subtag
157 static unsigned int rands=0;
158 if (!rands) {
159 rands=time(NULL);
160 }
161
162 char subtag[7];
163 subtag[6]=0;
164 if (emb->plan&EMB_A_SUBSET) {
165 int iA;
166 for (iA=0;iA<6;iA++) {
167 const int x=(int)(26.0*(rand_r(&rands)/(RAND_MAX+1.0)));
168 subtag[iA]='A'+x;
169 }
170 subset_tag=subtag;
171 }
172 // }}}
173
174 const char *fontname=NULL;
175 if ( (emb->intype==EMB_FMT_TTF)||(emb->intype==EMB_FMT_OTF) ) { // TODO? use fontinfo from CFF when outtype==CFT, etc.?
176 assert(emb->font->sfnt);
177 fontname=emb_otf_get_fontname(emb->font->sfnt);
178 } else if (emb->outtype==EMB_FMT_STDFONT) {
179 return NULL;
180 } else {
181 fprintf(stderr,"NOT IMPLEMENTED\n");
182 assert(0);
183 return NULL;
184 }
185
186 EMB_PDF_FONTDESCR *ret;
187 if (emb->plan&EMB_A_MULTIBYTE) { // multibyte
188 ret=emb_pdf_fd_new(fontname,subset_tag,"Adobe","Identity",0); // TODO other /ROS ?
189 } else {
190 ret=emb_pdf_fd_new(fontname,subset_tag,NULL,NULL,-1);
191 }
192 if (!ret) {
193 return NULL;
194 }
195
196 if ( (emb->intype==EMB_FMT_TTF)||(emb->intype==EMB_FMT_OTF) ) {
197 emb_otf_get_pdf_fontdescr(emb->font->sfnt,ret);
198 } else {
199 assert(0);
200 }
201 return ret;
202 }
203 // }}}
204
emb_pdf_fw_new(int datasize)205 EMB_PDF_FONTWIDTHS *emb_pdf_fw_new(int datasize) // {{{
206 {
207 assert(datasize>=0);
208 EMB_PDF_FONTWIDTHS *ret=calloc(1,sizeof(EMB_PDF_FONTWIDTHS)+datasize*sizeof(int));
209 if (!ret) {
210 fprintf(stderr,"Bad alloc: %s\n", strerror(errno));
211 assert(0);
212 return NULL;
213 }
214 return ret;
215 }
216 // }}}
217
218 // if default_width==-1: default_width will be estimated
emb_pdf_fw_cidwidths(const BITSET glyphs,int len,int default_width,int (* getGlyphWidth)(void * context,int gid),void * context)219 EMB_PDF_FONTWIDTHS *emb_pdf_fw_cidwidths(const BITSET glyphs,int len,int default_width,int (*getGlyphWidth)(void *context,int gid),void *context) // {{{ glyphs==NULL -> output all
220 {
221 assert(getGlyphWidth);
222
223 FREQUENT *freq=NULL;
224 if (default_width<0) {
225 freq=frequent_new(3);
226 }
227
228 int iA,b,c;
229 int size=0,in_region=0; // current number of elements in after region start
230
231 // first pass: find continuous regions, calculate needed size, estimate dw
232 for (iA=0,b=0,c=1;iA<len;iA++,c<<=1) {
233 if (!c) {
234 b++;
235 c=1;
236 }
237 if ( (!glyphs)||(glyphs[b]&c) ) {
238 if (freq) {
239 const int w=(*getGlyphWidth)(context,iA);
240 frequent_add(freq,w);
241 }
242 if (in_region) {
243 in_region++;
244 } else { // start new region
245 size+=2; // len c
246 in_region=1;
247 }
248 } else { // region end
249 size+=in_region;
250 in_region=0;
251 }
252 }
253 size+=in_region;
254
255 if (freq) {
256 default_width=frequent_get(freq,0);
257 free(freq);
258 }
259 assert(default_width>0);
260
261 // now create the array
262 EMB_PDF_FONTWIDTHS *ret=emb_pdf_fw_new(size+1);
263 if (!ret) {
264 return NULL;
265 }
266 ret->default_width=default_width;
267 ret->warray=ret->data;
268
269 // second pass
270 in_region=0;
271 size=0;
272 int *rlen=0; // position of current len field (only valid if in_region!=0)
273 for (iA=0,b=0,c=1;iA<len;iA++,c<<=1) {
274 if (!c) {
275 b++;
276 c=1;
277 }
278 if ( (!glyphs)||(glyphs[b]&c) ) {
279 const int w=(*getGlyphWidth)(context,iA);
280 if (in_region>0) { // in array region
281 if ( (w==default_width)&&(ret->warray[size-1]==default_width) ) { // omit this and prev entry
282 size--;
283 *rlen=in_region-1; // !=0, as it does not start with >default_width
284 in_region=0; // end region, immediate restart will take just the same amount of space
285 } else if ( (in_region>=4)&&
286 (ret->warray[size-1]==w)&&(ret->warray[size-2]==w)&&
287 (ret->warray[size-3]==w)&&(ret->warray[size-4]==w) ) {
288 // five in a row. c1 c2 w [l c] is equally short and can be extended (-len c1 w) [w/ cost of array-region restart]
289 if (in_region==4) { // completely replace
290 size-=6;
291 } else { // first end previous region
292 size-=4;
293 *rlen=in_region-4;
294 }
295 in_region=-4; // start range region instead
296 rlen=&ret->warray[size++];
297 ret->warray[size++]=iA-4;
298 ret->warray[size++]=w;
299 } else { // just add
300 in_region++;
301 ret->warray[size++]=w;
302 }
303 continue;
304 } else if (in_region<0) { // in range region
305 if (ret->warray[size-1]==w) {
306 in_region--; // just add
307 continue;
308 }
309 *rlen=in_region; // end
310 in_region=0;
311 }
312 if (w!=default_width) { // start new array region
313 in_region=1;
314 rlen=&ret->warray[size++];
315 ret->warray[size++]=iA; // c
316 ret->warray[size++]=w;
317 }
318 } else if (in_region) {
319 // TODO? no need to stop range region? } else if (in_region<0) { inregion--; }
320 *rlen=in_region;
321 in_region=0;
322 }
323 }
324 if (in_region) {
325 *rlen=in_region;
326 }
327 ret->warray[size]=0; // terminator
328 return ret;
329 }
330 // }}}
331
332 // TODO: encoding into EMB_PARAMS (emb_new_enc(...,encoding,len ,to_unicode));
333 // -> will then change interpretation of BITSET...(?really?); can we allow dynamic encoding map generation?
334 // -> encoding has a "len"; len<256
emb_pdf_fontwidths(EMB_PARAMS * emb)335 EMB_PDF_FONTWIDTHS *emb_pdf_fontwidths(EMB_PARAMS *emb) // {{{
336 {
337 assert(emb);
338
339 if ( (emb->intype==EMB_FMT_TTF)||(emb->intype==EMB_FMT_OTF) ) {
340 assert(emb->font->sfnt);
341 if (emb->plan&EMB_A_MULTIBYTE) {
342 return emb_otf_get_pdf_cidwidths(emb->font->sfnt,emb->subset);
343 } else {
344 return emb_otf_get_pdf_widths(emb->font->sfnt,/*encoding*/NULL,emb->font->sfnt->numGlyphs,emb->subset); // TODO: encoding
345 }
346 } else {
347 fprintf(stderr,"NOT IMPLEMENTED\n");
348 assert(0);
349 return NULL;
350 }
351 }
352 // }}}
353
354 /*** PDF out stuff ***/
355 #include "dynstring.h"
356
357 #define NEXT /* {{{ */ \
358 if ( (len<0)||(len>=size) ) { \
359 assert(0); \
360 free(ret); \
361 return NULL; \
362 } \
363 pos+=len; \
364 size-=len; /* }}} */
365
366 // TODO? /CIDSet TODO... /FontFamily /FontStretch /FontWeight (PDF1.5?) would be nice...
emb_pdf_simple_fontdescr(EMB_PARAMS * emb,EMB_PDF_FONTDESCR * fdes,int fontfile_obj_ref)367 char *emb_pdf_simple_fontdescr(EMB_PARAMS *emb,EMB_PDF_FONTDESCR *fdes,int fontfile_obj_ref) // {{{ - to be freed by user
368 {
369 assert(emb);
370 assert(fdes);
371
372 char *ret=NULL,*pos;
373 int len,size;
374
375 size=300;
376 pos=ret=malloc(size);
377 if (!ret) {
378 fprintf(stderr,"Bad alloc: %s\n", strerror(errno));
379 return NULL;
380 }
381
382 len=snprintf(pos,size,
383 "<</Type /FontDescriptor\n"
384 " /FontName /%s\n" // TODO? handle quoting in struct?
385 " /Flags %d\n"
386 " /ItalicAngle %d\n",
387 emb_pdf_escape_name(fdes->fontname,-1),
388 fdes->flags,
389 fdes->italicAngle);
390 NEXT;
391
392 if (1) { // TODO type!=EMB_PDF_TYPE3
393 len=snprintf(pos,size,
394 " /FontBBox [%d %d %d %d]\n"
395 " /Ascent %d\n"
396 " /Descent %d\n"
397 " /CapHeight %d\n" // if font has Latin chars
398 " /StemV %d\n",
399 fdes->bbxmin,fdes->bbymin,fdes->bbxmax,fdes->bbymax,
400 fdes->ascent,
401 fdes->descent,
402 fdes->capHeight,
403 fdes->stemV);
404 NEXT;
405 }
406 if (fdes->xHeight) {
407 len=snprintf(pos,size," /XHeight %d\n",fdes->xHeight);
408 NEXT;
409 }
410 if (fdes->avgWidth) {
411 len=snprintf(pos,size," /AvgWidth %d\n",fdes->avgWidth);
412 NEXT;
413 }
414 if (fdes->panose) {
415 int iA;
416 len=snprintf(pos,size," /Style << /Panose <");
417 NEXT;
418 if (size<30) {
419 assert(0);
420 free(ret);
421 return NULL;
422 }
423 for (iA=0;iA<12;iA++) {
424 snprintf(pos+iA*2,size-iA*2,"%02x",fdes->panose[iA]);
425 }
426 size-=24;
427 pos+=24;
428 len=snprintf(pos,size,"> >>\n");
429 NEXT;
430 }
431 // TODO (for Type0)? CIDSet -> simply our glyphs BITSET (ok. endianess?)
432 len=snprintf(pos,size,
433 " /%s %d 0 R\n"
434 ">>\n",
435 emb_pdf_get_fontfile_key(emb),
436 fontfile_obj_ref);
437 NEXT;
438
439 return ret;
440 }
441 // }}}
442
emb_pdf_simple_font(EMB_PARAMS * emb,EMB_PDF_FONTDESCR * fdes,EMB_PDF_FONTWIDTHS * fwid,int fontdescr_obj_ref)443 char *emb_pdf_simple_font(EMB_PARAMS *emb,EMB_PDF_FONTDESCR *fdes,EMB_PDF_FONTWIDTHS *fwid,int fontdescr_obj_ref) // {{{ - to be freed by user
444 {
445 assert(emb);
446 assert(fdes);
447 assert(fwid);
448
449 int iA,iB;
450 DYN_STRING ret;
451
452 if (dyn_init(&ret,500)==-1) {
453 return NULL;
454 }
455
456 dyn_printf(&ret,"<</Type /Font\n"
457 " /Subtype /%s\n"
458 " /BaseFont /%s\n"
459 " /FontDescriptor %d 0 R\n",
460 emb_pdf_get_font_subtype(emb),
461 emb_pdf_escape_name(fdes->fontname,-1),
462 fontdescr_obj_ref);
463
464 if (emb->plan&EMB_A_MULTIBYTE) { // multibyte
465 assert(fwid->warray);
466 dyn_printf(&ret," /CIDSystemInfo <<\n"
467 " /Registry (%s)\n"
468 " /Ordering (%s)\n"
469 " /Supplement %d\n"
470 " >>\n"
471 " /DW %d\n",
472 // " /CIDToGIDMap /Id...\n" // TrueType only, default /Identity [optional? which PDF version says what?]
473 fdes->registry,
474 fdes->ordering,
475 fdes->supplement,
476 fwid->default_width);
477
478 if (fwid->warray[0]) {
479 dyn_printf(&ret," /W [");
480 for (iA=0;fwid->warray[iA];) {
481 if (fwid->warray[iA]<0) { // c1 (c1-len) w
482 dyn_printf(&ret," %d %d %d",
483 fwid->warray[iA+1],
484 fwid->warray[iA+1]-fwid->warray[iA],
485 fwid->warray[iA+2]);
486 iA+=3;
487 } else { // c [w ... w]
488 iB=fwid->warray[iA++]; // len
489 dyn_printf(&ret," %d [",fwid->warray[iA++]); // c
490 for (;iB>0;iB--) {
491 dyn_printf(&ret," %d",fwid->warray[iA++]);
492 }
493 dyn_printf(&ret,"]");
494 }
495 }
496 dyn_printf(&ret,"]\n");
497 }
498 } else { // "not std14"
499 assert(fwid->widths);
500 dyn_printf(&ret,
501 " /Encoding /MacRomanEncoding\n" // optional; TODO!!!!!
502 // " /ToUnicode ?\n" // optional
503 " /FirstChar %d\n"
504 " /LastChar %d\n"
505 " /Widths [",
506 fwid->first,
507 fwid->last);
508 for (iA=0,iB=fwid->first;iB<=fwid->last;iA++,iB++) {
509 dyn_printf(&ret," %d",fwid->widths[iA]);
510 }
511 dyn_printf(&ret,"]\n");
512 }
513 dyn_printf(&ret,">>\n");
514 if (ret.len==-1) {
515 dyn_free(&ret);
516 assert(0);
517 return NULL;
518 }
519
520 return ret.buf;
521 }
522 // }}}
523
524 // TODO? + encoding as param? TODO + ToUnicode cmap => we need another struct EMB_PDF_FONTMAP
525 // (TODO?? fontname here without subset-tag [_some_ pdfs out there seem to be that way])
526 // TODO? don't do the CidType0 check here?
527 // NOTE: this is _additionally_ to emb_pdf_simple_font()!
emb_pdf_simple_cidfont(EMB_PARAMS * emb,const char * fontname,int descendant_obj_ref)528 char *emb_pdf_simple_cidfont(EMB_PARAMS *emb,const char *fontname,int descendant_obj_ref) // {{{ - to be freed by user
529 {
530 assert(emb);
531 assert(fontname);
532
533 char *ret=NULL,*pos;
534 int len,size;
535
536 size=250;
537 pos=ret=malloc(size);
538 if (!ret) {
539 fprintf(stderr,"Bad alloc: %s\n", strerror(errno));
540 return NULL;
541 }
542 // for CFF: one of:
543 // UniGB-UCS2-H, UniCNS-UCS2-H, UniJIS-UCS2-H, UniKS-UCS2-H
544 const char *encoding="Identity-H",*addenc="-";
545 if (emb->outtype==EMB_FMT_TTF) { // !=CidType0
546 addenc="";
547 }
548
549 len=snprintf(pos,size,
550 "<</Type /Font\n"
551 " /Subtype /Type0\n"
552 " /BaseFont /%s%s%s\n"
553 " /Encoding /%s\n"
554 " /DescendantFonts [%d 0 R]\n",
555 // " /ToUnicode ?\n" // TODO
556 emb_pdf_escape_name(fontname,-1),
557 addenc,((addenc[0])?encoding:""),
558 encoding,
559 descendant_obj_ref);
560 NEXT;
561
562 len=snprintf(pos,size,">>\n");
563 NEXT;
564
565 return ret;
566 }
567 // }}}
568
emb_pdf_simple_stdfont(EMB_PARAMS * emb)569 char *emb_pdf_simple_stdfont(EMB_PARAMS *emb) // {{{ - to be freed by user
570 {
571 assert(emb);
572 assert(emb->font->stdname);
573
574 char *ret=NULL,*pos;
575 int len,size;
576
577 size=300;
578 pos=ret=malloc(size);
579 if (!ret) {
580 fprintf(stderr,"Bad alloc: %s\n", strerror(errno));
581 return NULL;
582 }
583
584 len=snprintf(pos,size,
585 "<</Type/Font\n"
586 " /Subtype /Type1\n"
587 " /BaseFont /%s\n"
588 ">>\n",
589 // emb_pdf_get_font_subtype(emb),
590 emb->font->stdname);
591 NEXT;
592
593 return ret;
594 }
595 // }}}
596 #undef NEXT
597
598