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));
    
}
Exemplo n.º 3
0
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;	
}