2 #include "embed_pdf.h" // already included fron embed.h ...
3 #include "embed_pdf_int.h"
4 #include "embed_sfnt_int.h"
11 // NOTE: these must be in sync with the EMB_FORMAT enum
12 static const char *emb_pdf_font_subtype[][2]={ // {{{ (output_format,multibyte)
14 {"TrueType","CIDFontType2"},
15 {"Type1","CIDFontType0"},
16 {"Type1","CIDFontType0"},
20 static const char *emb_pdf_fontfile_key[]={ // {{{ (output_format)
21 "FontFile","FontFile2","FontFile3","FontFile3",NULL};
25 static const char *emb_pdf_fontfile_subtype[][2]={ // {{{ (output_format,multibyte)
28 {"OpenType","OpenType"},
29 {"Type1C","CIDFontType0C"},
33 static inline int emb_multibyte(EMB_PARAMS *emb) // {{{
35 return (emb->plan&EMB_A_MULTIBYTE)?1:0;
39 static const char *emb_pdf_escape_name(const char *name,int len) // {{{ // - statically allocated buffer
45 assert(len<=127); // pdf implementation limit
47 static char buf[128*3];
49 const char hex[]="0123456789abcdef";
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])) ) {
55 buf[++iB]=hex[(name[iA]>>4)&0x0f];
56 buf[++iB]=hex[name[iA]&0xf];
66 // this is in the font dict
67 const char *emb_pdf_get_font_subtype(EMB_PARAMS *emb) // {{{
70 return emb_pdf_font_subtype[emb->outtype][emb_multibyte(emb)];
75 const char *emb_pdf_get_fontfile_key(EMB_PARAMS *emb) // {{{
78 return emb_pdf_fontfile_key[emb->outtype];
82 // this is what to put in the font-stream dict
83 const char *emb_pdf_get_fontfile_subtype(EMB_PARAMS *emb) // {{{
86 return emb_pdf_fontfile_subtype[emb->outtype][emb_multibyte(emb)];
90 // {{{ static EMB_PDF_FONTDESCR *emb_pdf_fd_new(fontname,subset_tag,cid_registry,cid_ordering,cid_supplement,panose)
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
98 EMB_PDF_FONTDESCR *ret;
100 int len=sizeof(EMB_PDF_FONTDESCR);
102 assert(strlen(subset_tag)==6);
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;
115 fprintf(stderr,"Bad alloc: %s\n", strerror(errno));
120 // now fill the struct
122 if (cid_supplement>=0) { // free space for panose is at beginning
125 ret->fontname=ret->data+len;
126 len+=strlen(fontname)+1;
128 strncpy(ret->fontname,subset_tag,6);
129 ret->fontname[6]='+';
130 strcpy(ret->fontname+7,fontname);
133 strcpy(ret->fontname,fontname);
136 if (cid_supplement>=0) {
137 ret->registry=ret->data+len;
138 strcpy(ret->registry,cid_registry);
139 len+=strlen(cid_registry)+1;
141 ret->ordering=ret->data+len;
142 strcpy(ret->ordering,cid_ordering);
143 len+=strlen(cid_registry)+1;
145 ret->supplement=cid_supplement;
151 EMB_PDF_FONTDESCR *emb_pdf_fontdescr(EMB_PARAMS *emb) // {{{ - to be freed by user
155 const char *subset_tag=NULL;
156 // {{{ generate pdf subtag
157 static unsigned int rands=0;
164 if (emb->plan&EMB_A_SUBSET) {
166 for (iA=0;iA<6;iA++) {
167 const int x=(int)(26.0*(rand_r(&rands)/(RAND_MAX+1.0)));
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) {
181 fprintf(stderr,"NOT IMPLEMENTED\n");
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 ?
190 ret=emb_pdf_fd_new(fontname,subset_tag,NULL,NULL,-1);
196 if ( (emb->intype==EMB_FMT_TTF)||(emb->intype==EMB_FMT_OTF) ) {
197 emb_otf_get_pdf_fontdescr(emb->font->sfnt,ret);
205 EMB_PDF_FONTWIDTHS *emb_pdf_fw_new(int datasize) // {{{
208 EMB_PDF_FONTWIDTHS *ret=calloc(1,sizeof(EMB_PDF_FONTWIDTHS)+datasize*sizeof(int));
210 fprintf(stderr,"Bad alloc: %s\n", strerror(errno));
218 // if default_width==-1: default_width will be estimated
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
221 assert(getGlyphWidth);
224 if (default_width<0) {
225 freq=frequent_new(3);
229 int size=0,in_region=0; // current number of elements in after region start
231 // first pass: find continuous regions, calculate needed size, estimate dw
232 for (iA=0,b=0,c=1;iA<len;iA++,c<<=1) {
237 if ( (!glyphs)||(glyphs[b]&c) ) {
239 const int w=(*getGlyphWidth)(context,iA);
240 frequent_add(freq,w);
244 } else { // start new region
248 } else { // region end
256 default_width=frequent_get(freq,0);
259 assert(default_width>0);
261 // now create the array
262 EMB_PDF_FONTWIDTHS *ret=emb_pdf_fw_new(size+1);
266 ret->default_width=default_width;
267 ret->warray=ret->data;
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) {
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
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
291 } else { // first end previous region
295 in_region=-4; // start range region instead
296 rlen=&ret->warray[size++];
297 ret->warray[size++]=iA-4;
298 ret->warray[size++]=w;
301 ret->warray[size++]=w;
304 } else if (in_region<0) { // in range region
305 if (ret->warray[size-1]==w) {
306 in_region--; // just add
309 *rlen=in_region; // end
312 if (w!=default_width) { // start new array region
314 rlen=&ret->warray[size++];
315 ret->warray[size++]=iA; // c
316 ret->warray[size++]=w;
318 } else if (in_region) {
319 // TODO? no need to stop range region? } else if (in_region<0) { inregion--; }
327 ret->warray[size]=0; // terminator
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
335 EMB_PDF_FONTWIDTHS *emb_pdf_fontwidths(EMB_PARAMS *emb) // {{{
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);
344 return emb_otf_get_pdf_widths(emb->font->sfnt,/*encoding*/NULL,emb->font->sfnt->numGlyphs,emb->subset); // TODO: encoding
347 fprintf(stderr,"NOT IMPLEMENTED\n");
354 /*** PDF out stuff ***/
355 #include "dynstring.h"
357 #define NEXT /* {{{ */ \
358 if ( (len<0)||(len>=size) ) { \
366 // TODO? /CIDSet TODO... /FontFamily /FontStretch /FontWeight (PDF1.5?) would be nice...
367 char *emb_pdf_simple_fontdescr(EMB_PARAMS *emb,EMB_PDF_FONTDESCR *fdes,int fontfile_obj_ref) // {{{ - to be freed by user
376 pos=ret=malloc(size);
378 fprintf(stderr,"Bad alloc: %s\n", strerror(errno));
382 len=snprintf(pos,size,
383 "<</Type /FontDescriptor\n"
384 " /FontName /%s\n" // TODO? handle quoting in struct?
386 " /ItalicAngle %d\n",
387 emb_pdf_escape_name(fdes->fontname,-1),
392 if (1) { // TODO type!=EMB_PDF_TYPE3
393 len=snprintf(pos,size,
394 " /FontBBox [%d %d %d %d]\n"
397 " /CapHeight %d\n" // if font has Latin chars
399 fdes->bbxmin,fdes->bbymin,fdes->bbxmax,fdes->bbymax,
407 len=snprintf(pos,size," /XHeight %d\n",fdes->xHeight);
410 if (fdes->avgWidth) {
411 len=snprintf(pos,size," /AvgWidth %d\n",fdes->avgWidth);
416 len=snprintf(pos,size," /Style << /Panose <");
423 for (iA=0;iA<12;iA++) {
424 snprintf(pos+iA*2,size-iA*2,"%02x",fdes->panose[iA]);
428 len=snprintf(pos,size,"> >>\n");
431 // TODO (for Type0)? CIDSet -> simply our glyphs BITSET (ok. endianess?)
432 len=snprintf(pos,size,
435 emb_pdf_get_fontfile_key(emb),
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
452 if (dyn_init(&ret,500)==-1) {
456 dyn_printf(&ret,"<</Type /Font\n"
459 " /FontDescriptor %d 0 R\n",
460 emb_pdf_get_font_subtype(emb),
461 emb_pdf_escape_name(fdes->fontname,-1),
464 if (emb->plan&EMB_A_MULTIBYTE) { // multibyte
465 assert(fwid->warray);
466 dyn_printf(&ret," /CIDSystemInfo <<\n"
472 // " /CIDToGIDMap /Id...\n" // TrueType only, default /Identity [optional? which PDF version says what?]
476 fwid->default_width);
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",
484 fwid->warray[iA+1]-fwid->warray[iA],
487 } else { // c [w ... w]
488 iB=fwid->warray[iA++]; // len
489 dyn_printf(&ret," %d [",fwid->warray[iA++]); // c
491 dyn_printf(&ret," %d",fwid->warray[iA++]);
493 dyn_printf(&ret,"]");
496 dyn_printf(&ret,"]\n");
498 } else { // "not std14"
499 assert(fwid->widths);
501 " /Encoding /MacRomanEncoding\n" // optional; TODO!!!!!
502 // " /ToUnicode ?\n" // optional
508 for (iA=0,iB=fwid->first;iB<=fwid->last;iA++,iB++) {
509 dyn_printf(&ret," %d",fwid->widths[iA]);
511 dyn_printf(&ret,"]\n");
513 dyn_printf(&ret,">>\n");
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()!
528 char *emb_pdf_simple_cidfont(EMB_PARAMS *emb,const char *fontname,int descendant_obj_ref) // {{{ - to be freed by user
537 pos=ret=malloc(size);
539 fprintf(stderr,"Bad alloc: %s\n", strerror(errno));
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
549 len=snprintf(pos,size,
552 " /BaseFont /%s%s%s\n"
554 " /DescendantFonts [%d 0 R]\n",
555 // " /ToUnicode ?\n" // TODO
556 emb_pdf_escape_name(fontname,-1),
557 addenc,((addenc[0])?encoding:""),
562 len=snprintf(pos,size,">>\n");
569 char *emb_pdf_simple_stdfont(EMB_PARAMS *emb) // {{{ - to be freed by user
572 assert(emb->font->stdname);
578 pos=ret=malloc(size);
580 fprintf(stderr,"Bad alloc: %s\n", strerror(errno));
584 len=snprintf(pos,size,
589 // emb_pdf_get_font_subtype(emb),