void emb_otf_get_pdf_fontdescr(OTF_FILE *otf,EMB_PDF_FONTDESCR *ret) // {{{ { int len; // TODO // ... fill in struct char *head=otf_get_table(otf,OTF_TAG('h','e','a','d'),&len); assert(head); // version is 1.0 from otf_load ret->bbxmin=get_SHORT(head+36)*1000/otf->unitsPerEm; ret->bbymin=get_SHORT(head+38)*1000/otf->unitsPerEm; ret->bbxmax=get_SHORT(head+40)*1000/otf->unitsPerEm; ret->bbymax=get_SHORT(head+42)*1000/otf->unitsPerEm; const int macStyle=get_USHORT(head+44); free(head); char *post=otf_get_table(otf,OTF_TAG('p','o','s','t'),&len); assert(post); const unsigned int post_version=get_ULONG(post); // check length assert( (post_version!=0x00010000)||(len==32) ); assert( (post_version!=0x00020000)||(len>=34+2*otf->numGlyphs) ); assert( (post_version!=0x00025000)||(len==35+otf->numGlyphs) ); assert( (post_version!=0x00030000)||(len==32) ); assert( (post_version!=0x00020000)||(get_USHORT(post+32)==otf->numGlyphs) ); // assert( (post_version==0x00030000)==(!!(otf->flags&OTF_F_FMT_CFF)) ); // ghostscript embedding does this.. // TODO: v4 (apple) : uint16 reencoding[numGlyphs] if ( (post_version==0x00010000)|| (post_version==0x00020000)|| (post_version==0x00025000)|| (post_version==0x00030000) ) { ret->italicAngle=get_LONG(post+4)>>16; if (get_ULONG(post+12)>0) { // monospaced ret->flags|=1; } } else {
// TODO no subsetting actually done (for now) int otf_subset_cff(OTF_FILE *otf,BITSET glyphs,OUTPUT_FN output,void *context) // {{{ - returns number of bytes written { assert(otf); assert(output); // TODO char *new_cff=cff_subset(...); // determine new tables. struct _OTF_WRITE otw[]={ {OTF_TAG('C','F','F',' '),otf_action_copy,otf,}, // {OTF_TAG('C','F','F',' '),otf_action_replace,new_glyf,glyfSize}, {OTF_TAG('c','m','a','p'),otf_action_copy,otf,}, #if 0 // not actually needed! {OTF_TAG('c','v','t',' '),otf_action_copy,otf,}, {OTF_TAG('f','p','g','m'),otf_action_copy,otf,}, {OTF_TAG('h','e','a','d'),otf_action_copy,otf,}, // _copy_head {OTF_TAG('h','h','e','a'),otf_action_copy,otf,}, {OTF_TAG('h','m','t','x'),otf_action_copy,otf,}, {OTF_TAG('m','a','x','p'),otf_action_copy,otf,}, {OTF_TAG('n','a','m','e'),otf_action_copy,otf,}, {OTF_TAG('p','r','e','p'),otf_action_copy,otf,}, #endif {0,0,0,0}}; // and write them int numTables=otf_intersect_tables(otf,otw); int ret=otf_write_sfnt(otw,otf->version,numTables,output,context); // free(new_cff); return ret; }
EMB_RIGHT_TYPE emb_otf_get_rights(OTF_FILE *otf) // {{{ { EMB_RIGHT_TYPE ret=EMB_RIGHT_FULL; int len; char *os2=otf_get_table(otf,OTF_TAG('O','S','/','2'),&len); if (os2) { const unsigned short os2_version=get_USHORT(os2); // check len assert( (os2_version!=0x0000)||(len==78) ); assert( (os2_version!=0x0001)||(len==86) ); assert( (os2_version<0x0002)||(os2_version>0x0004)||(len==96) ); if (os2_version<=0x0004) { // get rights unsigned short fsType=get_USHORT(os2+8); ret=fsType&0x0200; if ((fsType&0x0f)==0x0002) { ret|=EMB_RIGHT_NONE; } else if ((fsType&0x0f)==0x0004) { ret|=EMB_RIGHT_READONLY; } } free(os2); } return ret; }
EMB_RIGHT_TYPE emb_otf_get_rights(OTF_FILE *otf) // {{{ { EMB_RIGHT_TYPE ret=EMB_RIGHT_FULL; int len; char *os2=otf_get_table(otf,OTF_TAG('O','S','/','2'),&len); if (os2) { const unsigned short os2_version=get_USHORT(os2); // check len assert( (os2_version!=0x0000)||(len==78) ); assert( (os2_version!=0x0001)||(len==86) ); assert( (os2_version<0x0002)||(os2_version>0x0004)||(len==96) ); if (os2_version<=0x0004) { // get rights unsigned short fsType=get_USHORT(os2+8); // from Adobe's Fontpolicies_v9.pdf, pg 13: if (fsType==0x0002) { ret=EMB_RIGHT_NONE; } else { ret=fsType&0x0300; // EMB_RIGHT_BITMAPONLY, EMB_RIGHT_NO_SUBSET if ((fsType&0x000c)==0x0004) { ret|=EMB_RIGHT_READONLY; } } } free(os2); } return ret; }
int otf_cff_extract(OTF_FILE *otf,OUTPUT_FN output,void *context) // {{{ - returns number of bytes written { assert(otf); assert(output); int idx=otf_find_table(otf,OTF_TAG('C','F','F',' ')); if (idx==-1) { return -1; } const OTF_DIRENT *table=otf->tables+idx; return copy_block(otf->f,table->offset,table->length,output,context); }
// TODO: cmap only required in non-CID context int otf_subset(OTF_FILE *otf,BITSET glyphs,OUTPUT_FN output,void *context) // {{{ - returns number of bytes written { assert(otf); assert(glyphs); assert(output); int iA,b,c; // first pass: include all required glyphs bit_set(glyphs,0); // .notdef always required int glyfSize=0; for (iA=0,b=0,c=1;iA<otf->numGlyphs;iA++,c<<=1) { if (!c) { b++; c=1; } if (glyphs[b]&c) { int len=otf_get_glyph(otf,iA); if (len<0) { assert(0); return -1; } else if (len>0) { glyfSize+=len; len=otf_subset_glyf(otf,iA,iA,glyphs); if (len<0) { assert(0); return -1; } glyfSize+=len; } } } // second pass: calculate new glyf and loca int locaSize=(otf->numGlyphs+1)*(otf->indexToLocFormat+1)*2; char *new_loca=malloc(locaSize); char *new_glyf=malloc(glyfSize); if ( (!new_loca)||(!new_glyf) ) { fprintf(stderr,"Bad alloc: %s\n", strerror(errno)); assert(0); free(new_loca); free(new_glyf); return -1; } int offset=0; for (iA=0,b=0,c=1;iA<otf->numGlyphs;iA++,c<<=1) { if (!c) { b++; c=1; } assert(offset%2==0); // TODO? change format? if glyfSize<0x20000 if (otf->indexToLocFormat==0) { set_USHORT(new_loca+iA*2,offset/2); } else { // ==1 set_ULONG(new_loca+iA*4,offset); } if (glyphs[b]&c) { const int len=otf_get_glyph(otf,iA); assert(len>=0); memcpy(new_glyf+offset,otf->gly,len); offset+=len; } } // last entry if (otf->indexToLocFormat==0) { set_USHORT(new_loca+otf->numGlyphs*2,offset/2); } else { // ==1 set_ULONG(new_loca+otf->numGlyphs*4,offset); } assert(offset==glyfSize); // determine new tables. struct _OTF_WRITE otw[]={ // sorted // TODO: cmap only required in non-CID context or always in CFF {OTF_TAG('c','m','a','p'),otf_action_copy,otf,}, {OTF_TAG('c','v','t',' '),otf_action_copy,otf,}, {OTF_TAG('f','p','g','m'),otf_action_copy,otf,}, {OTF_TAG('g','l','y','f'),otf_action_replace,new_glyf,glyfSize}, {OTF_TAG('h','e','a','d'),otf_action_copy,otf,}, // _copy_head {OTF_TAG('h','h','e','a'),otf_action_copy,otf,}, {OTF_TAG('h','m','t','x'),otf_action_copy,otf,}, {OTF_TAG('l','o','c','a'),otf_action_replace,new_loca,locaSize}, {OTF_TAG('m','a','x','p'),otf_action_copy,otf,}, {OTF_TAG('n','a','m','e'),otf_action_copy,otf,}, {OTF_TAG('p','r','e','p'),otf_action_copy,otf,}, // vhea vmtx (never used in PDF, but possible in PS>=3011) {0,0,0,0}}; // and write them int numTables=otf_intersect_tables(otf,otw); int ret=otf_write_sfnt(otw,otf->version,numTables,output,context); free(new_loca); free(new_glyf); return ret; //TODO ? reduce cmap [to (1,0) ;-)] //TODO (cmap for non-cid) }