Пример #1
0
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;
}
Пример #2
0
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;	
}
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;
}
Пример #4
0
EStatusCode PDFWriter::Shutdown(const string& inStateFilePath)
{
	EStatusCode status;

	do
	{
		StateWriter writer;

		status = writer.Start(inStateFilePath);
		if(status != PDFHummus::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->WriteObjectReferenceValue(objectsContextID);

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

		writer.GetObjectsWriter()->EndDictionary(pdfWriterDictionary);
		writer.GetObjectsWriter()->EndIndirectObject();

		writer.SetRootObject(rootObjectID);

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

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

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

	}while(false);

	if(status != PDFHummus::eSuccess)
	{
		mOutputFile.CloseFile();
		TRACE_LOG("PDFWriter::Shutdown, Could not end PDF");
	}
	else
		status = mOutputFile.CloseFile();
	ReleaseLog();
	return status;
}
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;	
}
Пример #6
0
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;
}