EStatusCode CFFEmbeddedFontWriter::WriteCharsets(const UIntVector& inSubsetGlyphIDs, UShortVector* inCIDMapping) { // since this is a subset the chances that i'll get a defult charset are 0. // hence i'll always do some charset. and using format 0 !!1 UIntVector::const_iterator it = inSubsetGlyphIDs.begin(); ++it; // skip the 0 mCharsetPosition = mFontFileStream.GetCurrentPosition(); mPrimitivesWriter.WriteCard8(0); if(mIsCID && inCIDMapping) { UShortVector::const_iterator itCIDs = inCIDMapping->begin(); ++itCIDs; for(; it != inSubsetGlyphIDs.end(); ++it,++itCIDs) mPrimitivesWriter.WriteSID(*itCIDs); } else { // note that this also works for CIDs! cause in this case the SIDs are actually // CIDs for(; it != inSubsetGlyphIDs.end(); ++it) mPrimitivesWriter.WriteSID(mOpenTypeInput.mCFF.GetGlyphSID(0,*it)); } return mPrimitivesWriter.GetInternalState(); }
EStatusCode CFFEmbeddedFontWriter::AddDependentGlyphs(UIntVector& ioSubsetGlyphIDs) { EStatusCode status = PDFHummus::eSuccess; UIntSet glyphsSet; UIntVector::iterator it = ioSubsetGlyphIDs.begin(); bool hasCompositeGlyphs = false; for(;it != ioSubsetGlyphIDs.end() && PDFHummus::eSuccess == status; ++it) { bool localHasCompositeGlyphs; status = AddComponentGlyphs(*it,glyphsSet,localHasCompositeGlyphs); hasCompositeGlyphs |= localHasCompositeGlyphs; } if(hasCompositeGlyphs) { UIntSet::iterator itNewGlyphs; for(it = ioSubsetGlyphIDs.begin();it != ioSubsetGlyphIDs.end(); ++it) glyphsSet.insert(*it); ioSubsetGlyphIDs.clear(); for(itNewGlyphs = glyphsSet.begin(); itNewGlyphs != glyphsSet.end(); ++itNewGlyphs) ioSubsetGlyphIDs.push_back(*itNewGlyphs); sort(ioSubsetGlyphIDs.begin(),ioSubsetGlyphIDs.end()); } return status; }
static UIntVector GetOrderedKeys(const UIntAndGlyphEncodingInfoVector& inMap) { UIntVector result; for(UIntAndGlyphEncodingInfoVector::const_iterator it = inMap.begin(); it != inMap.end(); ++it) result.push_back(it->first); sort(result.begin(),result.end()); return result; }
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 CFFEmbeddedFontWriter::WriteCharStrings(const UIntVector& inSubsetGlyphIDs) { /* 1. build the charstrings data, looping the glyphs charstrings and writing a flattened version of each charstring 2. write the charstring index based on offsets inside the data (size should be according to the max) 3. copy the data into the stream */ unsigned long* offsets = new unsigned long[inSubsetGlyphIDs.size() + 1]; MyStringBuf charStringsData; OutputStringBufferStream charStringsDataWriteStream(&charStringsData); CharStringType2Flattener charStringFlattener; UIntVector::const_iterator itGlyphs = inSubsetGlyphIDs.begin(); EStatusCode status = PDFHummus::eSuccess; do { unsigned short i=0; for(; itGlyphs != inSubsetGlyphIDs.end() && PDFHummus::eSuccess == status; ++itGlyphs,++i) { offsets[i] = (unsigned long)charStringsDataWriteStream.GetCurrentPosition(); status = charStringFlattener.WriteFlattenedGlyphProgram( 0, *itGlyphs, &(mOpenTypeInput.mCFF), &charStringsDataWriteStream); } if(status != PDFHummus::eSuccess) break; offsets[i] = (unsigned long)charStringsDataWriteStream.GetCurrentPosition(); charStringsData.pubseekoff(0,std::ios_base::beg); // write index section mCharStringPosition = mFontFileStream.GetCurrentPosition(); Byte sizeOfOffset = GetMostCompressedOffsetSize(offsets[i] + 1); mPrimitivesWriter.WriteCard16((unsigned short)inSubsetGlyphIDs.size()); mPrimitivesWriter.WriteOffSize(sizeOfOffset); mPrimitivesWriter.SetOffSize(sizeOfOffset); for(i=0;i<=inSubsetGlyphIDs.size();++i) mPrimitivesWriter.WriteOffset(offsets[i] + 1); // Write data InputStringBufferStream charStringsDataReadStream(&charStringsData); OutputStreamTraits streamCopier(&mFontFileStream); status = streamCopier.CopyToOutputStream(&charStringsDataReadStream); if(status != PDFHummus::eSuccess) break; }while(false); delete[] offsets; return status; }
EStatusCode TrueTypeEmbeddedFontWriter::WriteGlyf(const UIntVector& inSubsetGlyphIDs,unsigned long* inLocaTable) { // k. write the glyphs table. you only need to write the glyphs you are actually using. // while at it...update the locaTable TableEntry* tableEntry = mTrueTypeInput.GetTableEntry("glyf"); LongFilePositionType startTableOffset = mFontFileStream.GetCurrentPosition(); UIntVector::const_iterator it = inSubsetGlyphIDs.begin(); OutputStreamTraits streamCopier(&mFontFileStream); unsigned short glyphIndex,previousGlyphIndexEnd = 0; inLocaTable[0] = 0; EStatusCode status = eSuccess; for(;it != inSubsetGlyphIDs.end() && eSuccess == status; ++it) { glyphIndex = *it; if(glyphIndex >= mTrueTypeInput.mMaxp.NumGlyphs) { TRACE_LOG2("TrueTypeEmbeddedFontWriter::WriteGlyf, error, requested glyph index %ld is larger than the maximum glyph index for this font which is %ld. ",glyphIndex,mTrueTypeInput.mMaxp.NumGlyphs-1); status = eFailure; break; } for(unsigned short i= previousGlyphIndexEnd + 1; i<=glyphIndex;++i) inLocaTable[i] = inLocaTable[previousGlyphIndexEnd]; if(mTrueTypeInput.mGlyf[glyphIndex] != NULL) { mTrueTypeFile.GetInputStream()->SetPosition(tableEntry->Offset + mTrueTypeInput.mLoca[glyphIndex]); streamCopier.CopyToOutputStream(mTrueTypeFile.GetInputStream(), mTrueTypeInput.mLoca[(glyphIndex) + 1] - mTrueTypeInput.mLoca[glyphIndex]); } inLocaTable[glyphIndex + 1] = (unsigned long)(mFontFileStream.GetCurrentPosition() - startTableOffset); previousGlyphIndexEnd = glyphIndex + 1; } LongFilePositionType endOfTable = mFontFileStream.GetCurrentPosition(); mPrimitivesWriter.PadTo4(); LongFilePositionType endOfStream = mFontFileStream.GetCurrentPosition(); // write table entry data, which includes movement WriteTableEntryData(mGLYFEntryWritingOffset, startTableOffset, (unsigned long)(endOfTable - startTableOffset)); // restore position to end of stream mFontFileStream.SetPosition(endOfStream); return mPrimitivesWriter.GetInternalState(); }
void TrueTypeEmbeddedFontWriter::AddDependentGlyphs(UIntVector& ioSubsetGlyphIDs) { UIntSet glyphsSet; UIntVector::iterator it = ioSubsetGlyphIDs.begin(); bool hasCompositeGlyphs = false; for(;it != ioSubsetGlyphIDs.end(); ++it) hasCompositeGlyphs |= AddComponentGlyphs(*it,glyphsSet); if(hasCompositeGlyphs) { UIntSet::iterator itNewGlyphs; for(it = ioSubsetGlyphIDs.begin();it != ioSubsetGlyphIDs.end(); ++it) glyphsSet.insert(*it); ioSubsetGlyphIDs.clear(); for(itNewGlyphs = glyphsSet.begin(); itNewGlyphs != glyphsSet.end(); ++itNewGlyphs) ioSubsetGlyphIDs.push_back(*itNewGlyphs); sort(ioSubsetGlyphIDs.begin(),ioSubsetGlyphIDs.end()); } }
EStatusCode CFFEmbeddedFontWriter::WriteFDSelect(const UIntVector& inSubsetGlyphIDs,const FontDictInfoToByteMap& inNewFontDictsIndexes) { // always write format 3. cause at most cases the FD dicts count will be so low that it'd // take a bloody mircale for no repeats to occur. UIntVector::const_iterator itGlyphs = inSubsetGlyphIDs.begin(); mFDSelectPosition = mFontFileStream.GetCurrentPosition(); mPrimitivesWriter.WriteCard8(3); LongFilePositionType rangesCountPosition = mFontFileStream.GetCurrentPosition(); mPrimitivesWriter.WriteCard16(1); // temporary. will get back to this later unsigned short rangesCount = 1; Byte currentFD,newFD; unsigned short glyphIndex = 1; FontDictInfoToByteMap::const_iterator itNewIndex = inNewFontDictsIndexes.find(mOpenTypeInput.mCFF.mTopDictIndex[0].mFDSelect[*itGlyphs]); // k. seems like i probably just imagine exceptions here. i guess there must // be a proper FDSelect with FDs for all...so i'm defaulting to some 0 currentFD = (itNewIndex == inNewFontDictsIndexes.end() ? 0:itNewIndex->second); mPrimitivesWriter.WriteCard16(0); mPrimitivesWriter.WriteCard8(currentFD); ++itGlyphs; for(; itGlyphs != inSubsetGlyphIDs.end(); ++itGlyphs,++glyphIndex) { itNewIndex = inNewFontDictsIndexes.find(mOpenTypeInput.mCFF.mTopDictIndex[0].mFDSelect[*itGlyphs]); newFD = (itNewIndex == inNewFontDictsIndexes.end() ? 0:itNewIndex->second); if(newFD != currentFD) { currentFD = newFD; mPrimitivesWriter.WriteCard16(glyphIndex); mPrimitivesWriter.WriteCard8(currentFD); ++rangesCount; } } mPrimitivesWriter.WriteCard16((unsigned short)inSubsetGlyphIDs.size()); // go back to ranges count if not equal to what's already written if(rangesCount != 1) { LongFilePositionType currentPosition = mFontFileStream.GetCurrentPosition(); mFontFileStream.SetPosition(rangesCountPosition); mPrimitivesWriter.WriteCard16(rangesCount); mFontFileStream.SetPosition(currentPosition); } return mPrimitivesWriter.GetInternalState(); }
void CFFEmbeddedFontWriter::DetermineFDArrayIndexes(const UIntVector& inSubsetGlyphIDs,FontDictInfoToByteMap& outNewFontDictsIndexes) { UIntVector::const_iterator itGlyphs = inSubsetGlyphIDs.begin(); FontDictInfoSet fontDictInfos; for(; itGlyphs != inSubsetGlyphIDs.end(); ++itGlyphs) if(mOpenTypeInput.mCFF.mTopDictIndex[0].mFDSelect[*itGlyphs]) fontDictInfos.insert(mOpenTypeInput.mCFF.mTopDictIndex[0].mFDSelect[*itGlyphs]); FontDictInfoSet::iterator itFontInfos; Byte i=0; for(itFontInfos = fontDictInfos.begin(); itFontInfos != fontDictInfos.end(); ++itFontInfos,++i) outNewFontDictsIndexes.insert(FontDictInfoToByteMap::value_type(*itFontInfos,i)); }
EStatusCode CFFEmbeddedFontWriter::WriteEncodings(const UIntVector& inSubsetGlyphIDs) { // if it's a CID. don't bother with encodings (marks as 0) if(mIsCID) { mEncodingPosition = 0; return PDFHummus::eSuccess; } // not CID, write encoding, according to encoding values from the original font EncodingsInfo* encodingInfo = mOpenTypeInput.mCFF.mTopDictIndex[0].mEncoding; if(encodingInfo->mEncodingStart <= 1) { mEncodingPosition = encodingInfo->mEncodingStart; return PDFHummus::eSuccess; } else { // original font had custom encoding, let's subset it according to just the glyphs we // actually have. but cause i'm lazy i'll just do the first format. // figure out if we got supplements UIntVector::const_iterator it = inSubsetGlyphIDs.begin(); ByteAndUShortList supplements; for(; it != inSubsetGlyphIDs.end();++it) { // don't be confused! the supplements is by SID! not GID! unsigned short sid = mOpenTypeInput.mCFF.GetGlyphSID(0,*it); UShortToByteList::iterator itSupplements = encodingInfo->mSupplements.find(sid); if(itSupplements != encodingInfo->mSupplements.end()) { ByteList::iterator itMoreEncoding = itSupplements->second.begin(); for(; itMoreEncoding != itSupplements->second.end(); ++itMoreEncoding) supplements.push_back(ByteAndUShort(*itMoreEncoding,sid)); } } mEncodingPosition = mFontFileStream.GetCurrentPosition(); if(supplements.size() > 0) mPrimitivesWriter.WriteCard8(0x80); else mPrimitivesWriter.WriteCard8(0); // assuming that 0 is in the subset glyphs IDs, which does not require encoding // get the encodings count Byte encodingGlyphsCount = std::min((Byte)(inSubsetGlyphIDs.size()-1),encodingInfo->mEncodingsCount); mPrimitivesWriter.WriteCard8(encodingGlyphsCount); for(Byte i=0; i < encodingGlyphsCount;++i) { if(inSubsetGlyphIDs[i+1] < encodingInfo->mEncodingsCount) mPrimitivesWriter.WriteCard8(encodingInfo->mEncoding[inSubsetGlyphIDs[i+1]-1]); else mPrimitivesWriter.WriteCard8(0); } if(supplements.size() > 0) { mPrimitivesWriter.WriteCard8(Byte(supplements.size())); ByteAndUShortList::iterator itCollectedSupplements = supplements.begin(); for(; itCollectedSupplements != supplements.end(); ++itCollectedSupplements) { mPrimitivesWriter.WriteCard8(itCollectedSupplements->first); mPrimitivesWriter.WriteCard16(itCollectedSupplements->second); } } } return mPrimitivesWriter.GetInternalState(); }