EStatusCode UsedFontsRepository::WriteState(ObjectsContext* inStateWriter,ObjectIDType inObjectID)
{
	EStatusCode status = PDFHummus::eSuccess;
	ObjectIDTypeList usedFontsObjects;

	inStateWriter->StartNewIndirectObject(inObjectID);
	DictionaryContext* usedFontsRepositoryObject = inStateWriter->StartDictionary();

	usedFontsRepositoryObject->WriteKey("Type");
	usedFontsRepositoryObject->WriteNameValue("UsedFontsRepository");

	usedFontsRepositoryObject->WriteKey("mUsedFonts");
	inStateWriter->StartArray();


	StringAndLongToPDFUsedFontMap::iterator it = mUsedFonts.begin();

	for(; it != mUsedFonts.end();++it)
	{
		PDFTextString aTextString(it->first.first);
		inStateWriter->WriteLiteralString(aTextString.ToString());
        
        inStateWriter->WriteInteger(it->first.second);
		
		ObjectIDType usedFontID = inStateWriter->GetInDirectObjectsRegistry().AllocateNewObjectID();
		inStateWriter->WriteNewIndirectObjectReference(usedFontID);
		usedFontsObjects.push_back(usedFontID);
	}

	inStateWriter->EndArray(eTokenSeparatorEndLine);

	usedFontsRepositoryObject->WriteKey("mOptionaMetricsFiles");
	inStateWriter->StartArray();

	StringToStringMap::iterator itOptionals = mOptionaMetricsFiles.begin();
	for(; itOptionals != mOptionaMetricsFiles.end();++itOptionals)
	{
		PDFTextString aTextString(itOptionals->first);
		inStateWriter->WriteLiteralString(aTextString.ToString());

		aTextString = itOptionals->second;
		inStateWriter->WriteLiteralString(aTextString.ToString());
	}

	inStateWriter->EndArray(eTokenSeparatorEndLine);

	inStateWriter->EndDictionary(usedFontsRepositoryObject);
	inStateWriter->EndIndirectObject();

	if(usedFontsObjects.size() > 0)
	{
		it = mUsedFonts.begin();
		ObjectIDTypeList::iterator itIDs = usedFontsObjects.begin();

		for(; it != mUsedFonts.end() && PDFHummus::eSuccess == status;++it,++itIDs)
			status = it->second->WriteState(inStateWriter,*itIDs);
	}

	return status;
}
Beispiel #2
0
EStatusCode PDFUsedFont::WriteState(ObjectsContext* inStateWriter,ObjectIDType inObjectID)
{
	inStateWriter->StartNewIndirectObject(inObjectID);
	DictionaryContext* pdfUsedFontObject = inStateWriter->StartDictionary();

	pdfUsedFontObject->WriteKey("Type");
	pdfUsedFontObject->WriteNameValue("PDFUsedFont");

	ObjectIDType writtenFontObject;

	if(mWrittenFont)
	{
		writtenFontObject = inStateWriter->GetInDirectObjectsRegistry().AllocateNewObjectID();

		pdfUsedFontObject->WriteKey("mWrittenFont");
		pdfUsedFontObject->WriteNewObjectReferenceValue(writtenFontObject);
	}

	inStateWriter->EndDictionary(pdfUsedFontObject);
	inStateWriter->EndIndirectObject();

	if(mWrittenFont)
		mWrittenFont->WriteState(inStateWriter,writtenFontObject);

	return PDFHummus::eSuccess;
}
vector<string> PDFModifiedPage::WriteModifiedResourcesDict(PDFParser* inParser,PDFDictionary* inResourcesDictionary,ObjectsContext& inObjectContext,PDFDocumentCopyingContext* inCopyingContext)
{
	vector<string> formResourcesNames;

    MapIterator<PDFNameToPDFObjectMap>  resourcesDictionaryIt = inResourcesDictionary->GetIterator();
        
    // create modified page object
    DictionaryContext* dict = mWriter->GetObjectsContext().StartDictionary();
        
    // copy all elements of the page to the new page object, but the "Contents" and "Resources" elements
    while(resourcesDictionaryIt.MoveNext())
    {
        if(resourcesDictionaryIt.GetKey()->GetValue() != "XObject")
        {
            dict->WriteKey(resourcesDictionaryIt.GetKey()->GetValue());
            inCopyingContext->CopyDirectObjectAsIs(resourcesDictionaryIt.GetValue());
        }
    }   

    // now write a new xobject entry.
	dict->WriteKey("XObject");
	DictionaryContext* xobjectDict = inObjectContext.StartDictionary();

	PDFObjectCastPtr<PDFDictionary> existingXObjectDict(inParser->QueryDictionaryObject(inResourcesDictionary,"XObject"));
    string imageObjectName;
	if(existingXObjectDict.GetPtr())
	{
        // i'm having a very sophisticated algo here to create a new unique name. 
        // i'm making sure it's different in one letter from any name, using a well known discrete math proof method

		MapIterator<PDFNameToPDFObjectMap>  itExisting = existingXObjectDict->GetIterator();
		unsigned long i=0;
		while(itExisting.MoveNext())
		{
			string name = itExisting.GetKey()->GetValue();
			xobjectDict->WriteKey(name);
			inCopyingContext->CopyDirectObjectAsIs(itExisting.GetValue());
			imageObjectName.push_back((char)(GetDifferentChar((name.length() >= i+1) ? name[i]:0x39)));
			++i;
		}
		inObjectContext.EndLine();
	}

	PDFFormXObjectVector::iterator itForms = mContenxts.begin();
	imageObjectName.push_back('_');
	for(int i=0;itForms != mContenxts.end();++i,++itForms)
	{
		string formObjectName = imageObjectName + Int(i).ToString();
		xobjectDict->WriteKey(formObjectName);
		xobjectDict->WriteObjectReferenceValue((*itForms)->GetObjectID());
		formResourcesNames.push_back(formObjectName);
	}

	inObjectContext.EndDictionary(xobjectDict);
	inObjectContext.EndDictionary(dict);

	return formResourcesNames;
}
EStatusCode CFFEmbeddedFontWriter::WriteEmbeddedFont(
	FreeTypeFaceWrapper& inFontInfo,
	const UIntVector& inSubsetGlyphIDs,
	const std::string& inFontFile3SubType,
	const std::string& inSubsetFontName,
	ObjectsContext* inObjectsContext,
	UShortVector* inCIDMapping,
	ObjectIDType& outEmbeddedFontObjectID)
{
	MyStringBuf rawFontProgram; 
	bool notEmbedded;
		// as oppose to true type, the reason for using a memory stream here is mainly peformance - i don't want to start
		// setting file pointers and move in a file stream
	EStatusCode status;

	do
	{
		status = CreateCFFSubset(inFontInfo,inSubsetGlyphIDs,inCIDMapping,inSubsetFontName,notEmbedded,rawFontProgram);
		if(status != PDFHummus::eSuccess)
		{
			TRACE_LOG("CFFEmbeddedFontWriter::WriteEmbeddedFont, failed to write embedded font program");
			break;
		}	

		if(notEmbedded)
		{
			// can't embed. mark succesful, and go back empty
			outEmbeddedFontObjectID = 0;
			TRACE_LOG("CFFEmbeddedFontWriter::WriteEmbeddedFont, font may not be embedded. so not embedding");
			return PDFHummus::eSuccess;
		}

		outEmbeddedFontObjectID = inObjectsContext->StartNewIndirectObject();
		
		DictionaryContext* fontProgramDictionaryContext = inObjectsContext->StartDictionary();

		rawFontProgram.pubseekoff(0,std::ios_base::beg);

		fontProgramDictionaryContext->WriteKey(scSubtype);
		fontProgramDictionaryContext->WriteNameValue(inFontFile3SubType);
		PDFStream* pdfStream = inObjectsContext->StartPDFStream(fontProgramDictionaryContext);


		// now copy the created font program to the output stream
		InputStringBufferStream fontProgramStream(&rawFontProgram);
		OutputStreamTraits streamCopier(pdfStream->GetWriteStream());
		status = streamCopier.CopyToOutputStream(&fontProgramStream);
		if(status != PDFHummus::eSuccess)
		{
			TRACE_LOG("CFFEmbeddedFontWriter::WriteEmbeddedFont, failed to copy font program into pdf stream");
			break;
		}


		inObjectsContext->EndPDFStream(pdfStream);
		delete pdfStream;
	}while(false);

	return status;	
}
void ObjectsContext::EndPDFStream(PDFStream* inStream)
{
	// finalize the stream write to end stream context and calculate length
	inStream->FinalizeStreamWrite();

	if(inStream->GetExtentObjectID() == 0)
    {
        DictionaryContext* streamDictionaryContext = inStream->GetStreamDictionaryForDirectExtentStream();
        
        // Length (write as a direct object)
        streamDictionaryContext->WriteKey(scLength);
        streamDictionaryContext->WriteIntegerValue(inStream->GetLength());
        
        
        EndDictionary(streamDictionaryContext);
        
        // Write Stream Content
        WriteKeyword(scStream);
        
        inStream->FlushStreamContentForDirectExtentStream();
        
        EndLine();
		WriteKeyword(scEndStream);
        EndIndirectObject();
        
    }
    else
    {
        WritePDFStreamEndWithoutExtent();
        EndIndirectObject();
        WritePDFStreamExtent(inStream);
    }
}
PDFStream* ObjectsContext::StartUnfilteredPDFStream(DictionaryContext* inStreamDictionary)
{
	// write stream header and allocate PDF stream.
	// PDF stream will take care of maintaining state for the stream till writing is finished

	// Write the stream header
	// Write Stream Dictionary (note that inStreamDictionary is optionally used)
	DictionaryContext* streamDictionaryContext = (NULL == inStreamDictionary ? StartDictionary() : inStreamDictionary);

	// Length (write as an indirect object)
	streamDictionaryContext->WriteKey(scLength);
	ObjectIDType lengthObjectID = mReferencesRegistry.AllocateNewObjectID();
	streamDictionaryContext->WriteNewObjectReferenceValue(lengthObjectID);
		
	EndDictionary(streamDictionaryContext);

	// Write Stream Content
	WriteKeyword(scStream);

	// now begin the stream itself
	PDFStream* result = new PDFStream(false,mOutputStream, mEncryptionHelper,lengthObjectID,NULL);

	// break encryption, if any, when writing a stream, cause if encryption is desired, only top level elements should be encrypted. hence - the stream itself is, but its contents do not re-encrypt
	if(mEncryptionHelper)
		mEncryptionHelper->PauseEncryption();

	return result;
}
vector<string> PDFModifiedPage::WriteNewResourcesDictionary(ObjectsContext& inObjectContext) {
	vector<string> formResourcesNames;

	// no existing resource dictionary, so write a new one
	DictionaryContext*  dict = inObjectContext.StartDictionary();
	dict->WriteKey("XObject");
	DictionaryContext* xobjectDict = inObjectContext.StartDictionary();
	for (unsigned long i = 0; i<mContenxts.size(); ++i)
	{
		string formObjectName = string("myForm_") + Int(i).ToString();
		dict->WriteKey(formObjectName);
		dict->WriteObjectReferenceValue(mContenxts[i]->GetObjectID());
		formResourcesNames.push_back(formObjectName);
	}
	inObjectContext.EndDictionary(xobjectDict);
	inObjectContext.EndDictionary(dict);
	return formResourcesNames;	
}
EStatusCode TrueTypeEmbeddedFontWriter::WriteEmbeddedFont(	
								FreeTypeFaceWrapper& inFontInfo,
								const UIntVector& inSubsetGlyphIDs,
								ObjectsContext* inObjectsContext,
								ObjectIDType& outEmbeddedFontObjectID)
{
	MyStringBuf rawFontProgram;
	bool notEmbedded;
	EStatusCode status;

	do
	{
		status = CreateTrueTypeSubset(inFontInfo,inSubsetGlyphIDs,notEmbedded,rawFontProgram);
		if(status != PDFHummus::eSuccess)
		{
			TRACE_LOG("TrueTypeEmbeddedFontWriter::WriteEmbeddedFont, failed to write embedded font program");
			break;
		}	

		if(notEmbedded)
		{
			// can't embed. mark succesful, and go back empty
			outEmbeddedFontObjectID = 0;
			TRACE_LOG("TrueTypeEmbeddedFontWriter::WriteEmbeddedFont, font may not be embedded. so not embedding");
			return PDFHummus::eSuccess;
		}

		outEmbeddedFontObjectID = inObjectsContext->StartNewIndirectObject();
		
		DictionaryContext* fontProgramDictionaryContext = inObjectsContext->StartDictionary();

		// Length1 (decompressed true type program length)

		fontProgramDictionaryContext->WriteKey(scLength1);
		fontProgramDictionaryContext->WriteIntegerValue(rawFontProgram.GetCurrentWritePosition());
		rawFontProgram.pubseekoff(0,std::ios_base::beg);
		PDFStream* pdfStream = inObjectsContext->StartPDFStream(fontProgramDictionaryContext);


		// now copy the created font program to the output stream
		InputStringBufferStream fontProgramStream(&rawFontProgram);
		OutputStreamTraits streamCopier(pdfStream->GetWriteStream());
		status = streamCopier.CopyToOutputStream(&fontProgramStream);
		if(status != PDFHummus::eSuccess)
		{
			TRACE_LOG("TrueTypeEmbeddedFontWriter::WriteEmbeddedFont, failed to copy font program into pdf stream");
			break;
		}


		inObjectsContext->EndPDFStream(pdfStream);
		delete pdfStream;
	}while(false);

	return status;
}
PDFStream* ObjectsContext::StartPDFStream(DictionaryContext* inStreamDictionary,bool inForceDirectExtentObject)
{
	// write stream header and allocate PDF stream.
	// PDF stream will take care of maintaining state for the stream till writing is finished

	// Write the stream header
	// Write Stream Dictionary (note that inStreamDictionary is optionally used)
	DictionaryContext* streamDictionaryContext = (NULL == inStreamDictionary ? StartDictionary() : inStreamDictionary);

	// Compression (if necessary)
	if(mCompressStreams)
	{
		streamDictionaryContext->WriteKey(scFilter);
		streamDictionaryContext->WriteNameValue(scFlateDecode);
	}

	PDFStream* result = NULL;
    if(!inForceDirectExtentObject)
    {
    
        // Length (write as an indirect object)
        streamDictionaryContext->WriteKey(scLength);
        ObjectIDType lengthObjectID = mReferencesRegistry.AllocateNewObjectID();
        streamDictionaryContext->WriteNewObjectReferenceValue(lengthObjectID);
            

        EndDictionary(streamDictionaryContext);

        // Write Stream Content
        WriteKeyword(scStream);
        
		result = new PDFStream(mCompressStreams,mOutputStream, mEncryptionHelper,lengthObjectID,mExtender);
    }
    else
		result = new PDFStream(mCompressStreams,mOutputStream, mEncryptionHelper,streamDictionaryContext,mExtender);

	// break encryption, if any, when writing a stream, cause if encryption is desired, only top level elements should be encrypted. hence - the stream itself is, but its contents do not re-encrypt
	if (mEncryptionHelper)
		mEncryptionHelper->PauseEncryption();

	return result;
}
EStatusCode WrittenFontCFF::WriteState(ObjectsContext* inStateWriter,ObjectIDType inObjectID)
{
	inStateWriter->StartNewIndirectObject(inObjectID);

	DictionaryContext* writtenFontDictionary = inStateWriter->StartDictionary();

	writtenFontDictionary->WriteKey("Type");
	writtenFontDictionary->WriteNameValue("WrittenFontCFF");

	writtenFontDictionary->WriteKey("mAvailablePositionsCount");
	writtenFontDictionary->WriteIntegerValue(mAvailablePositionsCount);

	writtenFontDictionary->WriteKey("mFreeList");

	inStateWriter->StartArray();
	UCharAndUCharList::iterator it = mFreeList.begin();
	for(; it != mFreeList.end();++it)
	{
		inStateWriter->WriteInteger(it->first);
		inStateWriter->WriteInteger(it->second);
	}
	inStateWriter->EndArray(eTokenSeparatorEndLine);

	writtenFontDictionary->WriteKey("mAssignedPositions");
	inStateWriter->StartArray();
	for(int i=0;i<256;++i)
		inStateWriter->WriteInteger(mAssignedPositions[i]);
	inStateWriter->EndArray(eTokenSeparatorEndLine);

	writtenFontDictionary->WriteKey("mIsCID");
	writtenFontDictionary->WriteBooleanValue(mIsCID);

	EStatusCode status = AbstractWrittenFont::WriteStateInDictionary(inStateWriter,writtenFontDictionary);
	if(PDFHummus::eSuccess == status)
	{
		inStateWriter->EndDictionary(writtenFontDictionary);
		inStateWriter->EndIndirectObject();

		status = AbstractWrittenFont::WriteStateAfterDictionary(inStateWriter);
	}
	return status;
}
EStatusCode IndirectObjectsReferenceRegistry::WriteState(ObjectsContext* inStateWriter,ObjectIDType inObjectID)
{
	ObjectIDTypeList objects;

	inStateWriter->StartNewIndirectObject(inObjectID);
	
	DictionaryContext* myDictionary = inStateWriter->StartDictionary();
	
	myDictionary->WriteKey("Type");
	myDictionary->WriteNameValue("IndirectObjectsReferenceRegistry");

	myDictionary->WriteKey("mObjectsWritesRegistry");
	
	ObjectWriteInformationVector::iterator it = mObjectsWritesRegistry.begin();

	inStateWriter->StartArray();
	for(; it != mObjectsWritesRegistry.end(); ++it)
	{
		ObjectIDType objectWriteEntry = inStateWriter->GetInDirectObjectsRegistry().AllocateNewObjectID();
		inStateWriter->WriteIndirectObjectReference(objectWriteEntry);
		objects.push_back(objectWriteEntry);
	}
	inStateWriter->EndArray(eTokenSeparatorEndLine);

	inStateWriter->EndDictionary(myDictionary);
	inStateWriter->EndIndirectObject();

	ObjectIDTypeList::iterator itIDs = objects.begin();

	it = mObjectsWritesRegistry.begin();

	for(; it != mObjectsWritesRegistry.end(); ++it,++itIDs)
	{
		inStateWriter->StartNewIndirectObject(*itIDs);

		DictionaryContext* registryDictionary = inStateWriter->StartDictionary();
		
		registryDictionary->WriteKey("Type");
		registryDictionary->WriteNameValue("ObjectWriteInformation");

		registryDictionary->WriteKey("mObjectWritten");
		registryDictionary->WriteBooleanValue(it->mObjectWritten);

		if(it->mObjectWritten)
		{
			registryDictionary->WriteKey("mWritePosition");
			registryDictionary->WriteIntegerValue(it->mWritePosition);
		}

		registryDictionary->WriteKey("mObjectReferenceType");
		registryDictionary->WriteIntegerValue(it->mObjectReferenceType);

		inStateWriter->EndDictionary(registryDictionary);
		inStateWriter->EndIndirectObject();
	}

	return PDFHummus::eSuccess;
}
void DescendentFontWriter::WriteCIDSystemInfo(ObjectIDType inCIDSystemInfoObjectID)
{
	FT_Bool isCID;
	const char* registry;
	const char* ordering;
	FT_Int supplement;
	
	if(FT_Get_CID_Is_Internally_CID_Keyed(*mFontInfo,&isCID) != 0)
		isCID = false;	
	if(isCID && FT_Get_CID_Registry_Ordering_Supplement(*mFontInfo,&registry,&ordering,&supplement) != 0)
		isCID = false;

	if(!isCID)
	{
		registry = scAdobe;
		ordering = scIdentity;
		supplement = 0;
	}

	mObjectsContext->StartNewIndirectObject(inCIDSystemInfoObjectID);
	DictionaryContext* systemInfoContext = mObjectsContext->StartDictionary();

	// Registry
	systemInfoContext->WriteKey(scRegistry);
	systemInfoContext->WriteLiteralStringValue(registry);

	// Ordering
	systemInfoContext->WriteKey(scOrdering);
	systemInfoContext->WriteLiteralStringValue(ordering);

	// Supplement
	systemInfoContext->WriteKey(scSupplement);
	systemInfoContext->WriteIntegerValue(supplement);

	mObjectsContext->EndDictionary(systemInfoContext);
	mObjectsContext->EndIndirectObject();
}
PDFStream* ObjectsContext::StartPDFStream(DictionaryContext* inStreamDictionary,bool inForceDirectExtentObject)
{
	// write stream header and allocate PDF stream.
	// PDF stream will take care of maintaining state for the stream till writing is finished

	// Write the stream header
	// Write Stream Dictionary (note that inStreamDictionary is optionally used)
	DictionaryContext* streamDictionaryContext = (NULL == inStreamDictionary ? StartDictionary() : inStreamDictionary);

	// Compression (if necessary)
	if(mCompressStreams)
	{
		streamDictionaryContext->WriteKey(scFilter);
		streamDictionaryContext->WriteNameValue(scFlateDecode);
	}

    if(!inForceDirectExtentObject)
    {
    
        // Length (write as an indirect object)
        streamDictionaryContext->WriteKey(scLength);
        ObjectIDType lengthObjectID = mReferencesRegistry.AllocateNewObjectID();
        streamDictionaryContext->WriteNewObjectReferenceValue(lengthObjectID);
            

        EndDictionary(streamDictionaryContext);

        // Write Stream Content
        WriteKeyword(scStream);
        
        return new PDFStream(mCompressStreams,mOutputStream,lengthObjectID,mExtender);
    }
    else
        return new PDFStream(mCompressStreams,mOutputStream,streamDictionaryContext,mExtender);
	
}
Beispiel #14
0
EStatusCode ObjectsContext::WriteState(ObjectsContext* inStateWriter,ObjectIDType inObjectID)
{
	EStatusCode status;
		
	do
	{
		inStateWriter->StartNewIndirectObject(inObjectID);

		ObjectIDType referencesRegistryObjectID = inStateWriter->GetInDirectObjectsRegistry().AllocateNewObjectID();
		ObjectIDType subsetFontsNameSequanceID = inStateWriter->GetInDirectObjectsRegistry().AllocateNewObjectID();

		DictionaryContext* objectsContextDict = inStateWriter->StartDictionary();

		objectsContextDict->WriteKey("Type");
		objectsContextDict->WriteNameValue("ObjectsContext");

		objectsContextDict->WriteKey("mReferencesRegistry");
		objectsContextDict->WriteNewObjectReferenceValue(referencesRegistryObjectID);

		objectsContextDict->WriteKey("mCompressStreams");
		objectsContextDict->WriteBooleanValue(mCompressStreams);

		objectsContextDict->WriteKey("mSubsetFontsNamesSequance");
		objectsContextDict->WriteNewObjectReferenceValue(subsetFontsNameSequanceID);

		inStateWriter->EndDictionary(objectsContextDict);

		inStateWriter->EndIndirectObject();

		status = mReferencesRegistry.WriteState(inStateWriter,referencesRegistryObjectID);
		if(status != PDFHummus::eSuccess)
			break;

		// write subset fonts names sequance
		inStateWriter->StartNewIndirectObject(subsetFontsNameSequanceID);

		DictionaryContext* sequanceDict = inStateWriter->StartDictionary();

		sequanceDict->WriteKey("Type");
		sequanceDict->WriteNameValue("UppercaseSequance");


		sequanceDict->WriteKey("mSequanceString");
		sequanceDict->WriteLiteralStringValue(mSubsetFontsNamesSequance.ToString());

		inStateWriter->EndDictionary(sequanceDict);

		inStateWriter->EndIndirectObject();		
	}while(false);

	return status;
}
Beispiel #15
0
EStatusCode WrittenFontTrueType::WriteState(ObjectsContext* inStateWriter,ObjectIDType inObjectID)
{
	inStateWriter->StartNewIndirectObject(inObjectID);

	DictionaryContext* writtenFontDictionary = inStateWriter->StartDictionary();

	writtenFontDictionary->WriteKey("Type");
	writtenFontDictionary->WriteNameValue("WrittenFontTrueType");

	EStatusCode status = AbstractWrittenFont::WriteStateInDictionary(inStateWriter,writtenFontDictionary);
	if(PDFHummus::eSuccess == status)
	{
		inStateWriter->EndDictionary(writtenFontDictionary);
		inStateWriter->EndIndirectObject();

		status = AbstractWrittenFont::WriteStateAfterDictionary(inStateWriter);
	}
	return status;
}
PDFStream* ObjectsContext::StartUnfilteredPDFStream(DictionaryContext* inStreamDictionary)
{
	// write stream header and allocate PDF stream.
	// PDF stream will take care of maintaining state for the stream till writing is finished

	// Write the stream header
	// Write Stream Dictionary (note that inStreamDictionary is optionally used)
	DictionaryContext* streamDictionaryContext = (NULL == inStreamDictionary ? StartDictionary() : inStreamDictionary);

	// Length (write as an indirect object)
	streamDictionaryContext->WriteKey(scLength);
	ObjectIDType lengthObjectID = mReferencesRegistry.AllocateNewObjectID();
	streamDictionaryContext->WriteNewObjectReferenceValue(lengthObjectID);
		
	EndDictionary(streamDictionaryContext);

	// Write Stream Content
	WriteKeyword(scStream);

	// now begin the stream itself
	return new PDFStream(false,mOutputStream,lengthObjectID,NULL);
}
EStatusCode DCTDecodeFilterTest::ModifyImageObject(PDFWriter* inWriter,ObjectIDType inImageObject)
{
    EStatusCode status = eSuccess;
    PDFDocumentCopyingContext* modifiedFileContext = inWriter->CreatePDFCopyingContextForModifiedFile();
    
    do
    {
        // get image source dictionary
        PDFObjectCastPtr<PDFStreamInput> imageStream(inWriter->GetModifiedFileParser().ParseNewObject(inImageObject));
        
        RefCountPtr<PDFDictionary> imageDictionary(imageStream->QueryStreamDictionary());
        
        // strt object for modified image
        inWriter->GetObjectsContext().StartModifiedIndirectObject(inImageObject);
        
        DictionaryContext* newImageDictionary = inWriter->GetObjectsContext().StartDictionary();
        
        MapIterator<PDFNameToPDFObjectMap> it = imageDictionary->GetIterator();
        
        // copy all but "Filter" and "Length"
        ObjectIDTypeList indirectObjects;
        
        while (it.MoveNext())
        {
            if(it.GetKey()->GetValue() == "Filter" || it.GetKey()->GetValue() == "Length")
                continue;
            
            newImageDictionary->WriteKey(it.GetKey()->GetValue());
            EStatusCodeAndObjectIDTypeList result = modifiedFileContext->CopyDirectObjectWithDeepCopy(it.GetValue());
            if(result.first != eSuccess)
            {
                status = result.first;
                break;
            }
            indirectObjects.insert(indirectObjects.end(),result.second.begin(),result.second.end());
        }
        if(status != eSuccess)
            break;
        
        // start image stream for this dictionary (make sure it's unfiltered)
        PDFStream* newImageStream = inWriter->GetObjectsContext().StartUnfilteredPDFStream(newImageDictionary);
        
        // copy source stream through read filter
        IByteReader* sourceImage = modifiedFileContext->GetSourceDocumentParser()->StartReadingFromStream(imageStream.GetPtr());
        if(!sourceImage)
        {
            cout<<"failed to read DCT stream\n";
            status = eFailure;
            break;
        }
        
        OutputStreamTraits traits(newImageStream->GetWriteStream());
        status = traits.CopyToOutputStream(sourceImage);
        
        // finalize stream
        inWriter->GetObjectsContext().EndPDFStream(newImageStream);
        delete newImageStream;
 
        // late check for status so stream is deleted
        if(status != eSuccess)
            break;
        
        // copy remaining indirect objects from image stream dictionary
        status = modifiedFileContext->CopyNewObjectsForDirectObject(indirectObjects);
        
    }
    while (false);
    
    delete modifiedFileContext;
    return status;
    
}
PDFHummus::EStatusCode PDFModifiedPage::WritePage()
{
	EStatusCode status = EndContentContext(); // just in case someone forgot to close the latest content context

	do {
		if (status != eSuccess || !mIsDirty) {
			break;
		}

		// allocate an object ID for the new contents stream (for placing the form)
		// we first create the modified page object, so that we can define a name for the new form xobject
		// that is unique
		ObjectsContext& objectContext = mWriter->GetObjectsContext();
		ObjectIDType newContentObjectID = objectContext.GetInDirectObjectsRegistry().AllocateNewObjectID();
		ObjectIDType newEncapsulatingObjectID = 0;


		// create a copying context, so we can copy the page dictionary, and modify its contents + resources dict
		PDFDocumentCopyingContext* copyingContext = mWriter->CreatePDFCopyingContextForModifiedFile();

		// get the page object
		ObjectIDType pageObjectID = copyingContext->GetSourceDocumentParser()->GetPageObjectID(mPageIndex);
		PDFObjectCastPtr<PDFDictionary> pageDictionaryObject = copyingContext->GetSourceDocumentParser()->ParsePage(mPageIndex);
		MapIterator<PDFNameToPDFObjectMap>  pageDictionaryObjectIt = pageDictionaryObject->GetIterator();

		// create modified page object
		objectContext.StartModifiedIndirectObject(pageObjectID);
		DictionaryContext* modifiedPageObject = mWriter->GetObjectsContext().StartDictionary();

		// copy all elements of the page to the new page object, but the "Contents", "Resources" and "Annots" elements
		while (pageDictionaryObjectIt.MoveNext())
		{
			if (pageDictionaryObjectIt.GetKey()->GetValue() != "Resources" &&
				pageDictionaryObjectIt.GetKey()->GetValue() != "Contents" &&
				pageDictionaryObjectIt.GetKey()->GetValue() != "Annots")
			{
				modifiedPageObject->WriteKey(pageDictionaryObjectIt.GetKey()->GetValue());
				copyingContext->CopyDirectObjectAsIs(pageDictionaryObjectIt.GetValue());
			}
		}

		// Write new annotations entry, joining existing annotations, and new ones (from links attaching or what not)
		if (pageDictionaryObject->Exists("Annots") || mWriter->GetDocumentContext().GetAnnotations().size() > 0)
		{
			modifiedPageObject->WriteKey("Annots");
			objectContext.StartArray();

			// write old annots, if any exist
			if(pageDictionaryObject->Exists("Annots")) {
				PDFObjectCastPtr<PDFArray> anArray(copyingContext->GetSourceDocumentParser()->QueryDictionaryObject(pageDictionaryObject.GetPtr(), "Annots"));
				SingleValueContainerIterator<PDFObjectVector> refs = anArray->GetIterator();
				while (refs.MoveNext())
					copyingContext->CopyDirectObjectAsIs(refs.GetItem());

			}

			// write new annots from links
			ObjectIDTypeSet& annotations = mWriter->GetDocumentContext().GetAnnotations();
			if (annotations.size() > 0)
			{
				ObjectIDTypeSet::iterator it = annotations.begin();
				for (; it != annotations.end(); ++it)
					objectContext.WriteNewIndirectObjectReference(*it);
			}
			annotations.clear();
			objectContext.EndArray(eTokenSeparatorEndLine);

		}

		// Write new contents entry, joining the existing contents with the new one. take care of various scenarios of the existing Contents
		modifiedPageObject->WriteKey("Contents");
		if (!pageDictionaryObject->Exists("Contents"))
		{	// no contents
			objectContext.WriteIndirectObjectReference(newContentObjectID);
		}
		else
		{
			objectContext.StartArray();
			if (mEnsureContentEncapsulation)
			{
				newEncapsulatingObjectID = objectContext.GetInDirectObjectsRegistry().AllocateNewObjectID();
				objectContext.WriteNewIndirectObjectReference(newEncapsulatingObjectID);
			}

			RefCountPtr<PDFObject> pageContent(copyingContext->GetSourceDocumentParser()->QueryDictionaryObject(pageDictionaryObject.GetPtr(), "Contents"));
			if (pageContent->GetType() == PDFObject::ePDFObjectStream)
			{
				// single content stream. must be a refrence which points to it
				PDFObjectCastPtr<PDFIndirectObjectReference> ref(pageDictionaryObject->QueryDirectObject("Contents"));
				objectContext.WriteIndirectObjectReference(ref->mObjectID, ref->mVersion);
			}
			else if (pageContent->GetType() == PDFObject::ePDFObjectArray)
			{
				PDFArray* anArray = (PDFArray*)pageContent.GetPtr();

				// multiple content streams
				SingleValueContainerIterator<PDFObjectVector> refs = anArray->GetIterator();
				PDFObjectCastPtr<PDFIndirectObjectReference> ref;
				while (refs.MoveNext())
				{
					ref = refs.GetItem();
					objectContext.WriteIndirectObjectReference(ref->mObjectID, ref->mVersion);
				}

			}
			else {
				// this basically means no content...or whatever. just ignore.
			}

			objectContext.WriteNewIndirectObjectReference(newContentObjectID);
			objectContext.EndArray();
			objectContext.EndLine();
		}

		// Write a new resource entry. copy all but the "XObject" entry, which needs to be modified. Just for kicks i'm keeping the original 
		// form (either direct dictionary, or indirect object)
		ObjectIDType resourcesIndirect = 0;
		ObjectIDType newResourcesIndirect = 0;
		vector<string> formResourcesNames;

		modifiedPageObject->WriteKey("Resources");
		if (!pageDictionaryObject->Exists("Resources"))
		{
			// check if there's inherited dict. if so - write directly as a modified version
			PDFObjectCastPtr<PDFDictionary> parentDict(
				pageDictionaryObject->Exists("Parent") ? 
					copyingContext->GetSourceDocumentParser()->QueryDictionaryObject(pageDictionaryObject.GetPtr(), "Parent"): 
					NULL);
			if(!parentDict) {
				formResourcesNames = WriteNewResourcesDictionary(objectContext);
			}
			else {
				PDFObjectCastPtr<PDFDictionary> inheritedResources = findInheritedResources(copyingContext->GetSourceDocumentParser(),parentDict.GetPtr());
				if(!inheritedResources) {
					formResourcesNames = WriteNewResourcesDictionary(objectContext);
				} else {
					formResourcesNames = WriteModifiedResourcesDict(copyingContext->GetSourceDocumentParser(), inheritedResources.GetPtr(), objectContext, copyingContext);
				}
			}
		}
		else
		{
			// resources may be direct, or indirect. if direct, write as is, adding the new form xobject, otherwise wait till page object ends and write then
			PDFObjectCastPtr<PDFIndirectObjectReference> resourceDictRef(pageDictionaryObject->QueryDirectObject("Resources"));
			if (!resourceDictRef)
			{
				PDFObjectCastPtr<PDFDictionary> resourceDict(pageDictionaryObject->QueryDirectObject("Resources"));
				formResourcesNames = WriteModifiedResourcesDict(copyingContext->GetSourceDocumentParser(), resourceDict.GetPtr(), objectContext, copyingContext);
			}
			else
			{
				resourcesIndirect = resourceDictRef->mObjectID;
				// later will write a modified version of the resources dictionary, with the new form.
				// only modify the resources dict object if wasn't already modified (can happen when sharing resources dict between multiple pages).
				// in the case where it was alrady modified, create a new resources dictionary that's a copy, and use it instead, to avoid overwriting
				// the previous modification
				GetObjectWriteInformationResult res = objectContext.GetInDirectObjectsRegistry().GetObjectWriteInformation(resourcesIndirect);
				if (res.first && res.second.mIsDirty)
				{
					newResourcesIndirect = objectContext.GetInDirectObjectsRegistry().AllocateNewObjectID();
					modifiedPageObject->WriteObjectReferenceValue(newResourcesIndirect);
				}
				else
					modifiedPageObject->WriteObjectReferenceValue(resourcesIndirect);
			}
		}

		objectContext.EndDictionary(modifiedPageObject);
		objectContext.EndIndirectObject();

		if (resourcesIndirect != 0)
		{
			if (newResourcesIndirect != 0)
				objectContext.StartNewIndirectObject(newResourcesIndirect);
			else
				objectContext.StartModifiedIndirectObject(resourcesIndirect);
			PDFObjectCastPtr<PDFDictionary> resourceDict(copyingContext->GetSourceDocumentParser()->ParseNewObject(resourcesIndirect));
			formResourcesNames = WriteModifiedResourcesDict(copyingContext->GetSourceDocumentParser(), resourceDict.GetPtr(), objectContext, copyingContext);
			objectContext.EndIndirectObject();
		}

		// if required write encapsulation code, so that new stream is independent of graphic context of original
		PDFStream* newStream;
		PrimitiveObjectsWriter primitivesWriter;
		if (newEncapsulatingObjectID != 0)
		{
			objectContext.StartNewIndirectObject(newEncapsulatingObjectID);
			newStream = objectContext.StartPDFStream();
			primitivesWriter.SetStreamForWriting(newStream->GetWriteStream());
			primitivesWriter.WriteKeyword("q");
			objectContext.EndPDFStream(newStream);

		}

		// last but not least, create the actual content stream object, placing the form
		objectContext.StartNewIndirectObject(newContentObjectID);
		newStream = objectContext.StartPDFStream();
		primitivesWriter.SetStreamForWriting(newStream->GetWriteStream());

		if (newEncapsulatingObjectID != 0) {
			primitivesWriter.WriteKeyword("Q");
		}

		vector<string>::iterator it = formResourcesNames.begin();
		for (; it != formResourcesNames.end(); ++it)
		{
			primitivesWriter.WriteKeyword("q");
			primitivesWriter.WriteInteger(1);
			primitivesWriter.WriteInteger(0);
			primitivesWriter.WriteInteger(0);
			primitivesWriter.WriteInteger(1);
			primitivesWriter.WriteInteger(0);
			primitivesWriter.WriteInteger(0);
			primitivesWriter.WriteKeyword("cm");
			primitivesWriter.WriteName(*it);
			primitivesWriter.WriteKeyword("Do");
			primitivesWriter.WriteKeyword("Q");
		}

		objectContext.EndPDFStream(newStream);
	} while (false);

	return status;
}
EStatusCodeAndObjectIDType PDFCommentWriter::WriteCommentsTree(PDFComment* inComment)
{
	EStatusCodeAndObjectIDType result;
	ObjectIDType repliedTo = 0;

	// if already written, return
	PDFCommentToObjectIDTypeMap::iterator it = mCommentsForNextPage.find(inComment);
	if(it != mCommentsForNextPage.end())
	{
		result.first = eSuccess;
		result.second = it->second;
		return result;
	}

	// if has a referred comment, write it first
	if(inComment->ReplyTo != NULL)
	{
		EStatusCodeAndObjectIDType repliedtoResult = WriteCommentsTree(inComment->ReplyTo);

		if(repliedtoResult.first != eSuccess)
		{
			result.first = eFailure;
			result.second = 0;
			return result;
		}
		else
			repliedTo = repliedtoResult.second;
	}

	do
	{
		ObjectsContext& objectsContext = mPDFWriter->GetObjectsContext();

		// Start new InDirect object for annotation dictionary
		result.second = objectsContext.StartNewIndirectObject();
		
		DictionaryContext* dictionaryContext = objectsContext.StartDictionary();


		// Type
		dictionaryContext->WriteKey("Type");
		dictionaryContext->WriteNameValue("Annot");

		// SubType
		dictionaryContext->WriteKey("Subtype");
		dictionaryContext->WriteNameValue("Text");

		// Rect
		dictionaryContext->WriteKey("Rect");
		dictionaryContext->WriteRectangleValue(
			PDFRectangle(inComment->FrameBoundings[0],
						 inComment->FrameBoundings[1],
						 inComment->FrameBoundings[2],
						 inComment->FrameBoundings[3]));

		// Contents 
		dictionaryContext->WriteKey("Contents");
		dictionaryContext->WriteLiteralStringValue(PDFTextString(inComment->Text).ToString());

		// C (color)
		dictionaryContext->WriteKey("C");
		objectsContext.StartArray();
		if(inComment->Color.UseCMYK)
		{
			objectsContext.WriteDouble((double)inComment->Color.CMYKComponents[0]/255);
			objectsContext.WriteDouble((double)inComment->Color.CMYKComponents[1]/255);
			objectsContext.WriteDouble((double)inComment->Color.CMYKComponents[2]/255);
			objectsContext.WriteDouble((double)inComment->Color.CMYKComponents[3]/255);
		}
		else
		{
			objectsContext.WriteDouble((double)inComment->Color.RGBComponents[0]/255);
			objectsContext.WriteDouble((double)inComment->Color.RGBComponents[1]/255);
			objectsContext.WriteDouble((double)inComment->Color.RGBComponents[2]/255);
		}
		objectsContext.EndArray(eTokenSeparatorEndLine);

		// T
		dictionaryContext->WriteKey("T");
		dictionaryContext->WriteLiteralStringValue(PDFTextString(inComment->CommentatorName).ToString());
		
		// M
		dictionaryContext->WriteKey("M");
		dictionaryContext->WriteLiteralStringValue(inComment->Time.ToString());

		if(inComment->ReplyTo != NULL)
		{
			// IRT
			dictionaryContext->WriteKey("IRT");
			dictionaryContext->WriteObjectReferenceValue(repliedTo);

			// RT (we're doing always "reply" at this point, being a reply to comment
			dictionaryContext->WriteKey("RT");
			dictionaryContext->WriteNameValue("R");
		}

		// Open (we'll have them all closed to begin with)
		dictionaryContext->WriteKey("Open");
		dictionaryContext->WriteBooleanValue(false);

		// Name
		dictionaryContext->WriteKey("Name");
		dictionaryContext->WriteNameValue("Comment");

		if(objectsContext.EndDictionary(dictionaryContext) != eSuccess)
		{
			result.first = eFailure;
			TRACE_LOG("PDFCommentWriter::WriteCommentsTree, Exception in ending comment dictionary");
			break;
		}
		objectsContext.EndIndirectObject();
	
		mCommentsForNextPage.insert(PDFCommentToObjectIDTypeMap::value_type(inComment,result.second));

		result.first = eSuccess;
	}while(false);
	
	return result;
}
EStatusCode DescendentFontWriter::WriteFont(	ObjectIDType inDecendentObjectID, 
												const string& inFontName,
												FreeTypeFaceWrapper& inFontInfo,
												const UIntAndGlyphEncodingInfoVector& inEncodedGlyphs,
												ObjectsContext* inObjectsContext,
												IDescendentFontWriter* inDescendentFontWriterHelper)
{
	EStatusCode status = PDFHummus::eSuccess;
	FontDescriptorWriter fontDescriptorWriter;
	inObjectsContext->StartNewIndirectObject(inDecendentObjectID);
	
	mFontInfo = &inFontInfo;
	mObjectsContext = inObjectsContext;
	mCIDSetObjectID = 0;

	do
	{
		DictionaryContext* fontContext = inObjectsContext->StartDictionary();

		// Type
		fontContext->WriteKey(scType);
		fontContext->WriteNameValue(scFont);

		// SubType
		fontContext->WriteKey(scSubtype);
		inDescendentFontWriterHelper->WriteSubTypeValue(fontContext);

		// BaseFont
		fontContext->WriteKey(scBaseFont);
		fontContext->WriteNameValue(inFontName);

		WriteWidths(inEncodedGlyphs,fontContext);

		// CIDSystemInfo
		fontContext->WriteKey(scCIDSystemInfo);
		ObjectIDType cidSystemInfoObjectID = mObjectsContext->GetInDirectObjectsRegistry().AllocateNewObjectID();
		fontContext->WriteObjectReferenceValue(cidSystemInfoObjectID);

		// FontDescriptor
		fontContext->WriteKey(scFontDescriptor);
		ObjectIDType fontDescriptorObjectID = mObjectsContext->GetInDirectObjectsRegistry().AllocateNewObjectID();
		fontContext->WriteObjectReferenceValue(fontDescriptorObjectID);

		// free dictionary end writing
		inDescendentFontWriterHelper->WriteAdditionalKeys(fontContext);

		status = inObjectsContext->EndDictionary(fontContext);
		if(status != PDFHummus::eSuccess)
		{
			TRACE_LOG("CFFANSIFontWriter::WriteFont, unexpected failure. Failed to end dictionary in font write.");
			break;
		}

		inObjectsContext->EndIndirectObject();	

		WriteCIDSystemInfo(cidSystemInfoObjectID); 
		mWriterHelper = inDescendentFontWriterHelper; // save the helper pointer, to write the font program reference in the descriptor
		fontDescriptorWriter.WriteFontDescriptor(fontDescriptorObjectID,inFontName,&inFontInfo,inEncodedGlyphs,inObjectsContext,this);

		if(mCIDSetObjectID) // set by descriptor writer callback
			WriteCIDSet(inEncodedGlyphs);
	}while(false);
	return status;	
}
Beispiel #21
0
EStatusCode PDFWriter::Shutdown(const std::string& inStateFilePath)
{
	EStatusCode status;

	do
	{
		StateWriter writer;

		status = writer.Start(inStateFilePath);
		if(status != eSuccess)
		{
			TRACE_LOG("PDFWriter::Shutdown, cant start state writing");
			break;
		}

		ObjectIDType rootObjectID = writer.GetObjectsWriter()->StartNewIndirectObject();
		DictionaryContext* pdfWriterDictionary = writer.GetObjectsWriter()->StartDictionary();

		pdfWriterDictionary->WriteKey("Type");
		pdfWriterDictionary->WriteNameValue("PDFWriter");

		ObjectIDType objectsContextID = writer.GetObjectsWriter()->GetInDirectObjectsRegistry().AllocateNewObjectID();
		ObjectIDType DocumentContextID = writer.GetObjectsWriter()->GetInDirectObjectsRegistry().AllocateNewObjectID();

		pdfWriterDictionary->WriteKey("mObjectsContext");
		pdfWriterDictionary->WriteNewObjectReferenceValue(objectsContextID);

		pdfWriterDictionary->WriteKey("mDocumentContext");
		pdfWriterDictionary->WriteNewObjectReferenceValue(DocumentContextID);

        pdfWriterDictionary->WriteKey("mIsModified");
        pdfWriterDictionary->WriteBooleanValue(mIsModified);
        
        if(mIsModified)
        {
            pdfWriterDictionary->WriteKey("mModifiedFileVersion");
            pdfWriterDictionary->WriteIntegerValue(mModifiedFileVersion);
        }
        
		writer.GetObjectsWriter()->EndDictionary(pdfWriterDictionary);
		writer.GetObjectsWriter()->EndIndirectObject();

		writer.SetRootObject(rootObjectID);

		status = mObjectsContext.WriteState(writer.GetObjectsWriter(),objectsContextID);
		if(status != eSuccess)
			break;

		status = mDocumentContext.WriteState(writer.GetObjectsWriter(),DocumentContextID);
		if(status != eSuccess)
			break;

		status = writer.Finish();
		if(status != eSuccess)
		{
			TRACE_LOG("PDFWriter::Shutdown, cant finish state writing");
		}

	}while(false);

	if(status != eSuccess)
	{
		mOutputFile.CloseFile();
		TRACE_LOG("PDFWriter::Shutdown, Could not end PDF");
	}
	else
		status = mOutputFile.CloseFile();
	//ReleaseLog();
	return status;
}
void FontDescriptorWriter::WriteFontDescriptor(	ObjectIDType inFontDescriptorObjectID,
												const string& inFontPostscriptName,
												FreeTypeFaceWrapper* inFontInfo,
												const UIntAndGlyphEncodingInfoVector& inEncodedGlyphs,
												ObjectsContext* inObjectsContext,
												IFontDescriptorHelper* inDescriptorHelper)
{
	DictionaryContext* fontDescriptorDictionary;

	inObjectsContext->StartNewIndirectObject(inFontDescriptorObjectID);
	fontDescriptorDictionary = inObjectsContext->StartDictionary();
	
	// FontName
	fontDescriptorDictionary->WriteKey(scFontName);
	fontDescriptorDictionary->WriteNameValue(inFontPostscriptName);

	// FontFamily
	fontDescriptorDictionary->WriteKey(scFontFamily);
	fontDescriptorDictionary->WriteLiteralStringValue((*inFontInfo)->family_name);

	// FontStretch
	fontDescriptorDictionary->WriteKey(scFontStretch);
	fontDescriptorDictionary->WriteNameValue(scFontStretchLabels[inFontInfo->GetFontStretch()]);

	// FontWeight
	fontDescriptorDictionary->WriteKey(scFontWeight);
	fontDescriptorDictionary->WriteIntegerValue(inFontInfo->GetFontWeight());

	// FontBBox
	fontDescriptorDictionary->WriteKey(scFontBBox);
	fontDescriptorDictionary->WriteRectangleValue(
											PDFRectangle(
												inFontInfo->GetInPDFMeasurements((*inFontInfo)->bbox.xMin),
												inFontInfo->GetInPDFMeasurements((*inFontInfo)->bbox.yMin),
												inFontInfo->GetInPDFMeasurements((*inFontInfo)->bbox.xMax),
												inFontInfo->GetInPDFMeasurements((*inFontInfo)->bbox.yMax)));

	// ItalicAngle
	fontDescriptorDictionary->WriteKey(scItalicAngle);
	fontDescriptorDictionary->WriteDoubleValue(inFontInfo->GetItalicAngle());

	// Ascent
	fontDescriptorDictionary->WriteKey(scAscent);
	fontDescriptorDictionary->WriteIntegerValue(inFontInfo->GetInPDFMeasurements((*inFontInfo)->ascender));

	// Descent
	fontDescriptorDictionary->WriteKey(scDescent);
	fontDescriptorDictionary->WriteIntegerValue(inFontInfo->GetInPDFMeasurements((*inFontInfo)->descender));

	// CapHeight
	BoolAndFTShort result =  inFontInfo->GetCapHeight();
	if(result.first)
	{
		fontDescriptorDictionary->WriteKey(scCapHeight);
		fontDescriptorDictionary->WriteIntegerValue(result.second);
	}

	// XHeight
	result = inFontInfo->GetxHeight();
	if(result.first)
	{
		fontDescriptorDictionary->WriteKey(scXHeight);
		fontDescriptorDictionary->WriteIntegerValue(result.second);
	}


	// StemV
	fontDescriptorDictionary->WriteKey(scStemV);
	fontDescriptorDictionary->WriteIntegerValue(inFontInfo->GetStemV());

	// ChartSet writing (variants according to ANSI/CID)
	inDescriptorHelper->WriteCharSet(fontDescriptorDictionary,inObjectsContext,inFontInfo,inEncodedGlyphs);

	// Flags
	fontDescriptorDictionary->WriteKey(scFlags);
	fontDescriptorDictionary->WriteIntegerValue(CalculateFlags(inFontInfo,inEncodedGlyphs));

	// font embedding [may not happen due to font embedding restrictions. helper is supposed to avoid reference as well]
	inDescriptorHelper->WriteFontFileReference(fontDescriptorDictionary,inObjectsContext);

	inObjectsContext->EndDictionary(fontDescriptorDictionary);
	inObjectsContext->EndIndirectObject();
}
Beispiel #23
0
EStatusCode CIDFontWriter::WriteFont(FreeTypeFaceWrapper& inFontInfo,
										WrittenFontRepresentation* inFontOccurrence,
										ObjectsContext* inObjectsContext,
										IDescendentFontWriter* inDescendentFontWriter)
{

	EStatusCode status = PDFHummus::eSuccess;
	inObjectsContext->StartNewIndirectObject(inFontOccurrence->mWrittenObjectID);

	mFontInfo = &inFontInfo;
	mFontOccurrence = inFontOccurrence;
	mObjectsContext = inObjectsContext;

	do
	{
		DictionaryContext* fontContext = inObjectsContext->StartDictionary();

		// Type
		fontContext->WriteKey(scType);
		fontContext->WriteNameValue(scFont);

		// SubType
		fontContext->WriteKey(scSubtype);
		fontContext->WriteNameValue(scType0);

		// BaseFont
		fontContext->WriteKey(scBaseFont);
		const char* postscriptFontName = FT_Get_Postscript_Name(inFontInfo);
		if(!postscriptFontName)
		{
			TRACE_LOG("CIDFontWriter::WriteFont, unexpected failure. no postscript font name for font");
			status = PDFHummus::eFailure;
			break;
		}
		std::string subsetFontName = inObjectsContext->GenerateSubsetFontPrefix() + scPlus + postscriptFontName;
		fontContext->WriteNameValue(subsetFontName);

		WriteEncoding(fontContext);

		// DescendantFonts 
		ObjectIDType descendantFontID = mObjectsContext->GetInDirectObjectsRegistry().AllocateNewObjectID();

		fontContext->WriteKey(scDescendantFonts);
		mObjectsContext->StartArray();
		mObjectsContext->WriteNewIndirectObjectReference(descendantFontID);
		mObjectsContext->EndArray(eTokenSeparatorEndLine);

		CalculateCharacterEncodingArray(); // put the charachter in the order of encoding, for the ToUnicode map

		// ToUnicode
		fontContext->WriteKey(scToUnicode);
		ObjectIDType toUnicodeMapObjectID = mObjectsContext->GetInDirectObjectsRegistry().AllocateNewObjectID();
		fontContext->WriteNewObjectReferenceValue(toUnicodeMapObjectID);
		
		status = inObjectsContext->EndDictionary(fontContext);
		if(status != PDFHummus::eSuccess)
		{
			TRACE_LOG("CIDFontWriter::WriteFont, unexpected failure. Failed to end dictionary in font write.");
			break;
		}
		inObjectsContext->EndIndirectObject();
		WriteToUnicodeMap(toUnicodeMapObjectID);

		// Write the descendant font
		status = inDescendentFontWriter->WriteFont(descendantFontID,subsetFontName,*mFontInfo,mCharactersVector,mObjectsContext);

	} while(false);

	return status;
}