EStatusCode CFFDescendentFontWriter::WriteFont( ObjectIDType inDecendentObjectID, const std::string& inFontName, FreeTypeFaceWrapper& inFontInfo, const UIntAndGlyphEncodingInfoVector& inEncodedGlyphs, ObjectsContext* inObjectsContext, bool inEmbedFont) { // reset embedded font object ID (and flag...to whether it was actually embedded or not, which may // happen due to font embedding restrictions) mEmbeddedFontFileObjectID = 0; // Logically speaking, i shouldn't be getting to CID writing // if in type 1. at least, this is the current assumption, since // i don't intend to support type 1 CIDs, but just regular type 1s. // as such - fail if got here for type 1 const char* fontType = inFontInfo.GetTypeString(); if(strcmp(scType1,fontType) == 0) { TRACE_LOG1("CFFDescendentFontWriter::WriteFont, Exception. identified type1 font when writing CFF CID font, font name - %s. type 1 CIDs are not supported.",inFontName.substr(0, MAX_TRACE_SIZE - 200).c_str()); return PDFHummus::eFailure; } if (inEmbedFont) { CFFEmbeddedFontWriter embeddedFontWriter; UIntAndGlyphEncodingInfoVector encodedGlyphs = inEncodedGlyphs; UIntVector orderedGlyphs; UShortVector cidMapping; // Gal: the following sort completely ruins everything. // the order of the glyphs should be maintained per the ENCODED characthers // which is how the input is recieved. IMPORTANT - the order is critical // for the success of the embedding, as the order determines the order of the glyphs // in the subset font and so their GID which MUST match the encoded char. //sort(encodedGlyphs.begin(), encodedGlyphs.end(), sEncodedGlypsSort); for (UIntAndGlyphEncodingInfoVector::const_iterator it = encodedGlyphs.begin(); it != encodedGlyphs.end(); ++it) { orderedGlyphs.push_back(it->first); cidMapping.push_back(it->second.mEncodedCharacter); } EStatusCode status = embeddedFontWriter.WriteEmbeddedFont(inFontInfo, orderedGlyphs, scCIDFontType0C, inFontName, inObjectsContext, &cidMapping, mEmbeddedFontFileObjectID); if (status != PDFHummus::eSuccess) return status; } DescendentFontWriter descendentFontWriter; return descendentFontWriter.WriteFont(inDecendentObjectID,inFontName,inFontInfo,inEncodedGlyphs,inObjectsContext,this); }
void Type1ToCFFEmbeddedFontWriter::TranslateFromFreeTypeToType1(FreeTypeFaceWrapper& inFontInfo, const UIntVector& inSubsetGlyphIDs, StringVector& outGlyphNames) { UIntVector::const_iterator it = inSubsetGlyphIDs.begin(); for(; it != inSubsetGlyphIDs.end(); ++it) outGlyphNames.push_back(inFontInfo.GetGlyphName(*it)); }
EStatusCode CFFANSIFontWriter::WriteFont( FreeTypeFaceWrapper& inFontInfo, WrittenFontRepresentation* inFontOccurrence, ObjectsContext* inObjectsContext) { const char* postscriptFontName = FT_Get_Postscript_Name(inFontInfo); if(!postscriptFontName) { TRACE_LOG("CFFANSIFontWriter::WriteFont, unexpected failure. no postscript font name for font"); return PDFHummus::eFailure; } std::string subsetFontName = inObjectsContext->GenerateSubsetFontPrefix() + scPlus + postscriptFontName; const char* fontType = inFontInfo.GetTypeString(); // reset embedded font object ID (and flag...to whether it was actually embedded or not, which may // happen due to font embedding restrictions) mEmbeddedFontFileObjectID = 0; EStatusCode status; if(strcmp(scType1Type,fontType) == 0) { Type1ToCFFEmbeddedFontWriter embeddedFontWriter; status = embeddedFontWriter.WriteEmbeddedFont(inFontInfo, inFontOccurrence->GetGlyphIDsAsOrderedVector(), scType1C, subsetFontName, inObjectsContext, mEmbeddedFontFileObjectID); } else if(strcmp(scCFF,fontType) == 0) { CFFEmbeddedFontWriter embeddedFontWriter; status = embeddedFontWriter.WriteEmbeddedFont(inFontInfo, inFontOccurrence->GetGlyphIDsAsOrderedVector(), scType1C, subsetFontName, inObjectsContext, mEmbeddedFontFileObjectID); } else { TRACE_LOG("CFFANSIFontWriter::WriteFont, Exception, unfamilar font type for embedding representation"); status = PDFHummus::eFailure; } if(status != PDFHummus::eSuccess) return status; ANSIFontWriter fontWriter; return fontWriter.WriteFont(inFontInfo,inFontOccurrence,inObjectsContext,this,subsetFontName); }
EStatusCode TrueTypeANSIFontWriter::WriteFont( FreeTypeFaceWrapper& inFontInfo, WrittenFontRepresentation* inFontOccurrence, ObjectsContext* inObjectsContext, bool inEmbedFont) { std::string postscriptFontName = inFontInfo.GetPostscriptName(); if(postscriptFontName.length() == 0) { TRACE_LOG("TrueTypeANSIFontWriter::WriteFont, unexpected failure. no postscript font name for font"); return PDFHummus::eFailure; } std::string fontName; // reset embedded font object ID (and flag...to whether it was actually embedded or not, which may // happen due to font embedding restrictions, or due to users choice) mEmbeddedFontFileObjectID = 0; TrueTypeEmbeddedFontWriter embeddedFontWriter; if (inEmbedFont) { fontName = inObjectsContext->GenerateSubsetFontPrefix() + scPlus + postscriptFontName; EStatusCode status = embeddedFontWriter.WriteEmbeddedFont(inFontInfo, inFontOccurrence->GetGlyphIDsAsOrderedVector(), inObjectsContext, mEmbeddedFontFileObjectID); if (PDFHummus::eFailure == status) return status; } else fontName = postscriptFontName; ANSIFontWriter fontWriter; return fontWriter.WriteFont(inFontInfo, inFontOccurrence, inObjectsContext, this, fontName); }
EStatusCode TrueTypeEmbeddedFontWriter::CreateTrueTypeSubset( FreeTypeFaceWrapper& inFontInfo, /*consider requiring only the file path...actually i don't need the whole thing*/ const UIntVector& inSubsetGlyphIDs, bool& outNotEmbedded, MyStringBuf& outFontProgram) { EStatusCode status; unsigned long* locaTable = NULL; do { UIntVector subsetGlyphIDs = inSubsetGlyphIDs; status = mTrueTypeFile.OpenFile(inFontInfo.GetFontFilePath()); if(status != PDFHummus::eSuccess) { TRACE_LOG1("TrueTypeEmbeddedFontWriter::CreateTrueTypeSubset, cannot open true type font file at %s",inFontInfo.GetFontFilePath().c_str()); break; } status = mTrueTypeInput.ReadOpenTypeFile(mTrueTypeFile.GetInputStream(),(unsigned short)inFontInfo.GetFontIndex()); if(status != PDFHummus::eSuccess) { TRACE_LOG("TrueTypeEmbeddedFontWriter::CreateTrueTypeSubset, failed to read true type file"); break; } if(mTrueTypeInput.GetOpenTypeFontType() != EOpenTypeTrueType) { TRACE_LOG("TrueTypeEmbeddedFontWriter::CreateTrueTypeSubset, font file is not true type, so there is an exceptions here. expecting true types only"); break; } // see if font may be embedded if(mTrueTypeInput.mOS2Exists && !FSType(mTrueTypeInput.mOS2.fsType).CanEmbed()) { outNotEmbedded = true; return PDFHummus::eSuccess; } else outNotEmbedded = false; AddDependentGlyphs(subsetGlyphIDs); // K. this needs a bit explaining. // i want to leave the glyph IDs as they were in the original font. // this allows me to write a more comfotable font definition. something which is generic enough // this assumption requires that the font will contain the glyphs in their original position // to allow that, when the glyph count is smaller than the actual glyphs count, i'm // padding with 0 length glyphs (their loca entries just don't move). // don't worry - it's perfectly kosher. // so - bottom line - the glyphs count will actually be 1 more than the maxium glyph index. // and from here i'll just place the glyphs in their original indexes, and fill in the // vacant glyphs with empties. mSubsetFontGlyphsCount = subsetGlyphIDs.back() + 1; mFontFileStream.Assign(&outFontProgram); mPrimitivesWriter.SetOpenTypeStream(&mFontFileStream); // assign also to some reader streams, so i can read items for checksums calculations mFontFileReaderStream.Assign(&outFontProgram); mPrimitivesReader.SetOpenTypeStream(&mFontFileReaderStream); status = WriteTrueTypeHeader(); if(status != PDFHummus::eSuccess) { TRACE_LOG("TrueTypeEmbeddedFontWriter::CreateTrueTypeSubset, failed to write true type header"); break; } status = WriteHead(); if(status != PDFHummus::eSuccess) { TRACE_LOG("TrueTypeEmbeddedFontWriter::CreateTrueTypeSubset, failed to write head table"); break; } status = WriteHHea(); if(status != PDFHummus::eSuccess) { TRACE_LOG("TrueTypeEmbeddedFontWriter::CreateTrueTypeSubset, failed to write hhea table"); break; } status = WriteHMtx(); if(status != PDFHummus::eSuccess) { TRACE_LOG("TrueTypeEmbeddedFontWriter::CreateTrueTypeSubset, failed to write hmtx table"); break; } status = WriteMaxp(); if(status != PDFHummus::eSuccess) { TRACE_LOG("TrueTypeEmbeddedFontWriter::CreateTrueTypeSubset, failed to write Maxp table"); break; } if(mTrueTypeInput.mCVTExists) { status = WriteCVT(); if(status != PDFHummus::eSuccess) { TRACE_LOG("TrueTypeEmbeddedFontWriter::CreateTrueTypeSubset, failed to write cvt table"); break; } } if(mTrueTypeInput.mFPGMExists) { status = WriteFPGM(); if(status != PDFHummus::eSuccess) { TRACE_LOG("TrueTypeEmbeddedFontWriter::CreateTrueTypeSubset, failed to write fpgm table"); break; } } if(mTrueTypeInput.mPREPExists) { status = WritePREP(); if(status != PDFHummus::eSuccess) { TRACE_LOG("TrueTypeEmbeddedFontWriter::CreateTrueTypeSubset, failed to write prep table"); break; } } status = WriteNAME(); if(status != PDFHummus::eSuccess) { TRACE_LOG("TrueTypeEmbeddedFontWriter::CreateTrueTypeSubset, failed to write name table"); break; } if(mTrueTypeInput.mOS2Exists) { status = WriteOS2(); if(status != PDFHummus::eSuccess) { TRACE_LOG("TrueTypeEmbeddedFontWriter::CreateTrueTypeSubset, failed to write os2 table"); break; } } status = WriteCMAP(); if(status != PDFHummus::eSuccess) { TRACE_LOG("TrueTypeEmbeddedFontWriter::CreateTrueTypeSubset, failed to write cmap table"); break; } locaTable = new unsigned long[mSubsetFontGlyphsCount+1]; status = WriteGlyf(subsetGlyphIDs,locaTable); if(status != PDFHummus::eSuccess) { TRACE_LOG("TrueTypeEmbeddedFontWriter::CreateTrueTypeSubset, failed to write prep table"); break; } status = WriteLoca(locaTable); if(status != PDFHummus::eSuccess) { TRACE_LOG("TrueTypeEmbeddedFontWriter::CreateTrueTypeSubset, failed to write loca table"); break; } status = CreateHeadTableCheckSumAdjustment(); }while(false); delete[] locaTable; mTrueTypeFile.CloseFile(); return status; }
EStatusCode CFFEmbeddedFontWriter::CreateCFFSubset( FreeTypeFaceWrapper& inFontInfo, const UIntVector& inSubsetGlyphIDs, UShortVector* inCIDMapping, const std::string& inSubsetFontName, bool& outNotEmbedded, MyStringBuf& outFontProgram) { EStatusCode status; do { status = mOpenTypeFile.OpenFile(inFontInfo.GetFontFilePath()); if(status != PDFHummus::eSuccess) { TRACE_LOG1("CFFEmbeddedFontWriter::CreateCFFSubset, cannot open type font file at %s",inFontInfo.GetFontFilePath().c_str()); break; } status = mOpenTypeInput.ReadOpenTypeFile(mOpenTypeFile.GetInputStream(),(unsigned short)inFontInfo.GetFontIndex()); if(status != PDFHummus::eSuccess) { TRACE_LOG("CFFEmbeddedFontWriter::CreateCFFSubset, failed to read true type file"); break; } if(mOpenTypeInput.GetOpenTypeFontType() != EOpenTypeCFF) { TRACE_LOG("CFFEmbeddedFontWriter::CreateCFFSubset, font file is not CFF, so there is an exceptions here. expecting CFFs only"); break; } // see if font may be embedded if(mOpenTypeInput.mOS2Exists && !FSType(mOpenTypeInput.mOS2.fsType).CanEmbed()) { outNotEmbedded = true; return PDFHummus::eSuccess; } else outNotEmbedded = false; UIntVector subsetGlyphIDs = inSubsetGlyphIDs; if(subsetGlyphIDs.front() != 0) // make sure 0 glyph is in subsetGlyphIDs.insert(subsetGlyphIDs.begin(),0); status = AddDependentGlyphs(subsetGlyphIDs); if(status != PDFHummus::eSuccess) { TRACE_LOG("CFFEmbeddedFontWriter::CreateCFFSubset, failed to add dependent glyphs"); break; } mIsCID = mOpenTypeInput.mCFF.mTopDictIndex[0].mTopDict.find(scROS) != mOpenTypeInput.mCFF.mTopDictIndex[0].mTopDict.end(); mFontFileStream.Assign(&outFontProgram); mPrimitivesWriter.SetStream(&mFontFileStream); status = WriteCFFHeader(); if(status != PDFHummus::eSuccess) { TRACE_LOG("CFFEmbeddedFontWriter::CreateCFFSubset, failed to write CFF header"); break; } status = WriteName(inSubsetFontName); if(status != PDFHummus::eSuccess) { TRACE_LOG("CFFEmbeddedFontWriter::CreateCFFSubset, failed to write CFF Name"); break; } status = WriteTopIndex(); if(status != PDFHummus::eSuccess) { TRACE_LOG("CFFEmbeddedFontWriter::CreateCFFSubset, failed to write Top Index"); break; } status = WriteStringIndex(); if(status != PDFHummus::eSuccess) { TRACE_LOG("CFFEmbeddedFontWriter::CreateCFFSubset, failed to write String Index"); break; } status = WriteGlobalSubrsIndex(); if(status != PDFHummus::eSuccess) { TRACE_LOG("CFFEmbeddedFontWriter::CreateCFFSubset, failed to write global subrs index"); break; } status = WriteEncodings(inSubsetGlyphIDs); if(status != PDFHummus::eSuccess) { TRACE_LOG("CFFEmbeddedFontWriter::CreateCFFSubset, failed to write encodings"); break; } status = WriteCharsets(inSubsetGlyphIDs,inCIDMapping); if(status != PDFHummus::eSuccess) { TRACE_LOG("CFFEmbeddedFontWriter::CreateCFFSubset, failed to write charstring"); break; } FontDictInfoToByteMap newFDIndexes; if(mIsCID) { DetermineFDArrayIndexes(inSubsetGlyphIDs,newFDIndexes); status = WriteFDSelect(inSubsetGlyphIDs,newFDIndexes); if(status != PDFHummus::eSuccess) break; } status = WriteCharStrings(inSubsetGlyphIDs); if(status != PDFHummus::eSuccess) { TRACE_LOG("CFFEmbeddedFontWriter::CreateCFFSubset, failed to write charstring"); break; } status = WritePrivateDictionary(); if(status != PDFHummus::eSuccess) { TRACE_LOG("CFFEmbeddedFontWriter::CreateCFFSubset, failed to write private"); break; } if(mIsCID) { status = WriteFDArray(inSubsetGlyphIDs,newFDIndexes); if(status != PDFHummus::eSuccess) break; } status = UpdateIndexesAtTopDict(); if(status != PDFHummus::eSuccess) { TRACE_LOG("CFFEmbeddedFontWriter::CreateCFFSubset, failed to update indexes"); break; } }while(false); mOpenTypeFile.CloseFile(); return status; }
EStatusCode Type1ToCFFEmbeddedFontWriter::CreateCFFSubset( FreeTypeFaceWrapper& inFontInfo, const UIntVector& inSubsetGlyphIDs, const std::string& inSubsetFontName, bool& outNotEmbedded, MyStringBuf& outFontProgram) { EStatusCode status; do { UIntVector subsetGlyphIDs = inSubsetGlyphIDs; StringVector subsetGlyphNames; if(subsetGlyphIDs.front() != 0) // make sure 0 glyph is in subsetGlyphIDs.insert(subsetGlyphIDs.begin(),0); status = mType1File.OpenFile(inFontInfo.GetFontFilePath()); if(status != PDFHummus::eSuccess) { TRACE_LOG1("Type1ToCFFEmbeddedFontWriter::CreateCFFSubset, cannot open Type 1 font file at %s",inFontInfo.GetFontFilePath().c_str()); break; } status = mType1Input.ReadType1File(mType1File.GetInputStream()); if(status != PDFHummus::eSuccess) { TRACE_LOG("Type1ToCFFEmbeddedFontWriter::CreateCFFSubset, failed to read Type 1 file"); break; } // see if font may be embedded if(mType1Input.mFontDictionary.FSTypeValid || mType1Input.mFontInfoDictionary.FSTypeValid) { if(!FSType( mType1Input.mFontInfoDictionary.FSTypeValid ? mType1Input.mFontInfoDictionary.fsType : mType1Input.mFontDictionary.fsType).CanEmbed()) { outNotEmbedded = true; return PDFHummus::eSuccess; } else outNotEmbedded = false; } else outNotEmbedded = false; // Found big gap between FreeType indexing and the way it's in the Type 1. obvioulsy due to encoding differences. // So i'm replacing the indexes of free type, with names...should be safer (also cleans up invalid glyph ids, in case // direct glyphs placement put them here) TranslateFromFreeTypeToType1(inFontInfo,subsetGlyphIDs,subsetGlyphNames); status = AddDependentGlyphs(subsetGlyphNames); if(status != PDFHummus::eSuccess) { TRACE_LOG("Type1ToCFFEmbeddedFontWriter::CreateCFFSubset, failed to add dependent glyphs"); break; } mFontFileStream.Assign(&outFontProgram); mPrimitivesWriter.SetStream(&mFontFileStream); status = WriteCFFHeader(); if(status != PDFHummus::eSuccess) { TRACE_LOG("Type1ToCFFEmbeddedFontWriter::CreateCFFSubset, failed to write CFF header"); break; } status = WriteName(inSubsetFontName); if(status != PDFHummus::eSuccess) { TRACE_LOG("Type1ToCFFEmbeddedFontWriter::CreateCFFSubset, failed to write CFF Name"); break; } status = WriteTopIndex(); if(status != PDFHummus::eSuccess) { TRACE_LOG("Type1ToCFFEmbeddedFontWriter::CreateCFFSubset, failed to write Top Index"); break; } // prepraring charset happens here, so that any added strings to the string index will happen...before // the index is written PrepareCharSetArray(subsetGlyphNames); status = WriteStringIndex(); if(status != PDFHummus::eSuccess) { TRACE_LOG("Type1ToCFFEmbeddedFontWriter::CreateCFFSubset, failed to write String Index"); break; } status = WriteGlobalSubrsIndex(); if(status != PDFHummus::eSuccess) { TRACE_LOG("Type1ToCFFEmbeddedFontWriter::CreateCFFSubset, failed to write global subrs index"); break; } status = WriteEncodings(subsetGlyphNames); if(status != PDFHummus::eSuccess) { TRACE_LOG("Type1ToCFFEmbeddedFontWriter::CreateCFFSubset, failed to write encodings"); break; } status = WriteCharsets(subsetGlyphNames); if(status != PDFHummus::eSuccess) { TRACE_LOG("Type1ToCFFEmbeddedFontWriter::CreateCFFSubset, failed to write charstring"); break; } status = WriteCharStrings(subsetGlyphNames); if(status != PDFHummus::eSuccess) { TRACE_LOG("Type1ToCFFEmbeddedFontWriter::CreateCFFSubset, failed to write charstring"); break; } status = WritePrivateDictionary(); if(status != PDFHummus::eSuccess) { TRACE_LOG("Type1ToCFFEmbeddedFontWriter::CreateCFFSubset, failed to write private"); break; } status = UpdateIndexesAtTopDict(); if(status != PDFHummus::eSuccess) { TRACE_LOG("Type1ToCFFEmbeddedFontWriter::CreateCFFSubset, failed to update indexes"); break; } }while(false); mType1File.CloseFile(); FreeTemporaryStructs(); return status; }