• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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