EStatusCode WrittenFontCFF::ReadState(PDFParser* inStateReader,ObjectIDType inObjectID) { PDFObjectCastPtr<PDFDictionary> writtenFontState(inStateReader->ParseNewObject(inObjectID)); PDFObjectCastPtr<PDFInteger> availablePositionsCount(writtenFontState->QueryDirectObject("mAvailablePositionsCount")); mAvailablePositionsCount = (unsigned char)availablePositionsCount->GetValue(); mFreeList.clear(); PDFObjectCastPtr<PDFArray> freeListState(writtenFontState->QueryDirectObject("mFreeList")); SingleValueContainerIterator<PDFObjectVector> it = freeListState->GetIterator(); PDFObjectCastPtr<PDFInteger> item; UCharAndUChar aPair; while(it.MoveNext()) { item = it.GetItem(); aPair.first = (unsigned char)item->GetValue(); it.MoveNext(); item = it.GetItem(); aPair.second = (unsigned char)item->GetValue(); mFreeList.push_back(aPair); } PDFObjectCastPtr<PDFArray> assignedPositionsState(writtenFontState->QueryDirectObject("mAssignedPositions")); it = assignedPositionsState->GetIterator(); int i=0; PDFObjectCastPtr<PDFInteger> assignedPositionItem; while(it.MoveNext()) { assignedPositionItem = it.GetItem(); mAssignedPositions[i] = (unsigned int)assignedPositionItem->GetValue(); ++i; } PDFObjectCastPtr<PDFBoolean> isCIDState(writtenFontState->QueryDirectObject("mIsCID")); mIsCID = isCIDState->GetValue(); return AbstractWrittenFont::ReadState(inStateReader,writtenFontState.GetPtr()); }
void showXObjectsPerPageInfo(PDFParser& parser,PDFObjectCastPtr<PDFDictionary> xobjects) { RefCountPtr<PDFName> key; PDFObjectCastPtr<PDFIndirectObjectReference> value; MapIterator<PDFNameToPDFObjectMap> it = xobjects->GetIterator(); while(it.MoveNext()) { key = it.GetKey(); value = it.GetValue(); cout << "XObject named " << key->GetValue().c_str() << " is object " << value->mObjectID << " of type "; PDFObjectCastPtr<PDFStreamInput> xobject(parser.ParseNewObject(value->mObjectID)); PDFObjectCastPtr<PDFDictionary> xobjectDictionary(xobject->QueryStreamDictionary()); PDFObjectCastPtr<PDFName> typeOfXObject = xobjectDictionary->QueryDirectObject("Subtype"); cout << typeOfXObject->GetValue().c_str() << "\n"; } }
void showPageContent(PDFParser& parser, RefCountPtr<PDFObject> contents, InputFile& pdfFile) { if(contents->GetType() == ePDFObjectArray) { PDFObjectCastPtr<PDFIndirectObjectReference> streamReferences; SingleValueContainerIterator<PDFObjectVector> itContents = ((PDFArray*)contents.GetPtr())->GetIterator(); // array of streams while(itContents.MoveNext()) { streamReferences = itContents.GetItem(); PDFObjectCastPtr<PDFStreamInput> stream = parser.ParseNewObject(streamReferences->mObjectID); showContentStream(stream.GetPtr(),pdfFile.GetInputStream(),parser); } } else { // stream showContentStream((PDFStreamInput*)contents.GetPtr(),pdfFile.GetInputStream(),parser); } }
ObjectIDType DCTDecodeFilterTest::FindDCTDecodedImageObject(PDFParser* inParser) { ObjectIDType imageObject = 0; do { // find image by looking for the first image in the first page RefCountPtr<PDFDictionary> firstPage = inParser->ParsePage(0); if(!firstPage) break; PDFObjectCastPtr<PDFDictionary> resourceDictionary(inParser->QueryDictionaryObject(firstPage.GetPtr(),"Resources")); if(!resourceDictionary) break; PDFObjectCastPtr<PDFDictionary> xobjectDictionary(inParser->QueryDictionaryObject(resourceDictionary.GetPtr(), "XObject")); if(!xobjectDictionary) break; MapIterator<PDFNameToPDFObjectMap> it = xobjectDictionary->GetIterator(); while(it.MoveNext()) { if(it.GetValue()->GetType() == PDFObject::ePDFObjectIndirectObjectReference) { PDFObjectCastPtr<PDFStreamInput> image( inParser->ParseNewObject(((PDFIndirectObjectReference*)it.GetValue())->mObjectID)); RefCountPtr<PDFDictionary> imageDictionary = image->QueryStreamDictionary(); PDFObjectCastPtr<PDFName> objectType = imageDictionary->QueryDirectObject("Subtype"); if(!objectType || objectType->GetValue() != "Image") continue; RefCountPtr<PDFObject> filters = imageDictionary->QueryDirectObject("Filter"); if(!filters) break; if(filters->GetType() == PDFObject::ePDFObjectName && ((PDFName*)filters.GetPtr())->GetValue() == "DCTDecode") { imageObject = ((PDFIndirectObjectReference*)it.GetValue())->mObjectID; break; } PDFArray* filtersArray = (PDFArray*)filters.GetPtr(); if(filtersArray->GetLength() == 1) { PDFObjectCastPtr<PDFName> firstDecoder(filtersArray->QueryObject(0)); if(firstDecoder->GetValue() == "DCTDecode") { imageObject = ((PDFIndirectObjectReference*)it.GetValue())->mObjectID; break; } } } } } while (false); return imageObject; }
EStatusCode UsedFontsRepository::ReadState(PDFParser* inStateReader,ObjectIDType inObjectID) { EStatusCode status = PDFHummus::eSuccess; // clear current state StringAndLongToPDFUsedFontMap::iterator itUsedFonts = mUsedFonts.begin(); for(; itUsedFonts != mUsedFonts.end();++itUsedFonts) delete (itUsedFonts->second); mUsedFonts.clear(); PDFObjectCastPtr<PDFDictionary> usedFontsRepositoryState(inStateReader->ParseNewObject(inObjectID)); mOptionaMetricsFiles.clear(); PDFObjectCastPtr<PDFArray> optionalMetricsState(usedFontsRepositoryState->QueryDirectObject("mOptionaMetricsFiles")); SingleValueContainerIterator<PDFObjectVector> it = optionalMetricsState->GetIterator(); PDFObjectCastPtr<PDFLiteralString> aStringValue; while(it.MoveNext()) { PDFTextString aKey; aStringValue = it.GetItem(); aKey = aStringValue->GetValue(); PDFTextString aValue; it.MoveNext(); aStringValue = it.GetItem(); aValue = aStringValue->GetValue(); mOptionaMetricsFiles.insert(StringToStringMap::value_type(aKey.ToUTF8String(),aValue.ToUTF8String())); } PDFObjectCastPtr<PDFArray> usedFontsState(usedFontsRepositoryState->QueryDirectObject("mUsedFonts")); it = usedFontsState->GetIterator(); PDFObjectCastPtr<PDFLiteralString> keyStringItem; PDFObjectCastPtr<PDFInteger> keyIndexItem; PDFObjectCastPtr<PDFIndirectObjectReference> valueItem; if(!mInputFontsInformation) mInputFontsInformation = new FreeTypeWrapper(); while(it.MoveNext() && PDFHummus::eSuccess == status) { keyStringItem = it.GetItem(); it.MoveNext(); keyIndexItem = it.GetItem(); it.MoveNext(); valueItem = it.GetItem(); PDFTextString aTextString(keyStringItem->GetValue()); std::string filePath = aTextString.ToUTF8String(); long fontIndex = (long)keyIndexItem->GetValue(); FT_Face face; face = mInputFontsInformation->NewFace(filePath,fontIndex); if(!face) { TRACE_LOG2("UsedFontsRepository::ReadState, Failed to load font from %s at index %ld",filePath.c_str(),fontIndex); status = PDFHummus::eFailure; break; } PDFUsedFont* usedFont; StringToStringMap::iterator itOptionlMetricsFile = mOptionaMetricsFiles.find(filePath); if(itOptionlMetricsFile != mOptionaMetricsFiles.end()) usedFont = new PDFUsedFont(face,filePath,itOptionlMetricsFile->second,fontIndex,mObjectsContext); else usedFont = new PDFUsedFont(face,filePath,"",fontIndex,mObjectsContext); if(!usedFont->IsValid()) { TRACE_LOG2("UsedFontsRepository::ReadState, Unreckognized font format for font in %s at index %ld",filePath.c_str(),fontIndex); delete usedFont; usedFont = NULL; status = PDFHummus::eFailure; break; } usedFont->ReadState(inStateReader,valueItem->mObjectID); mUsedFonts.insert(StringAndLongToPDFUsedFontMap::value_type(StringAndLong(filePath,fontIndex),usedFont)); } 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; }