From 30fda467b32aaf154fad340468e013efd6d371d5 Mon Sep 17 00:00:00 2001 From: Svetlana Kulikova Date: Wed, 11 Oct 2023 18:25:20 +0300 Subject: [PATCH] Widget Edit --- PdfFile/PdfFile.cpp | 68 +++++++++++++++++ PdfFile/PdfWriter.cpp | 8 +- PdfFile/SrcWriter/Annotation.cpp | 126 ++++++++++++++++++++++++++----- PdfFile/SrcWriter/Annotation.h | 22 +++++- PdfFile/SrcWriter/Document.cpp | 37 ++++++--- PdfFile/SrcWriter/Document.h | 5 +- PdfFile/SrcWriter/Pages.cpp | 5 +- PdfFile/test/test.cpp | 7 ++ 8 files changed, 243 insertions(+), 35 deletions(-) diff --git a/PdfFile/PdfFile.cpp b/PdfFile/PdfFile.cpp index ffa15824e2..2822ab0555 100644 --- a/PdfFile/PdfFile.cpp +++ b/PdfFile/PdfFile.cpp @@ -685,6 +685,57 @@ bool CPdfFile::AddPage(int nPageIndex) } return bRes; } +PdfWriter::CDictObject* GetWidgetParent(PDFDoc* pdfDoc, PdfWriter::CDocument* pDoc, Object* pParentRef) +{ + PdfWriter::CDictObject* pParent = NULL; + + if (!pParentRef || !pParentRef->isRef() || !pdfDoc) + return pParent; + XRef* xref = pdfDoc->getXRef(); + Object oParent; + if (!pParentRef->fetch(xref, &oParent)->isDict()) + { + oParent.free(); + return pParent; + } + + PdfWriter::CXref* pXref = new PdfWriter::CXref(pDoc, pParentRef->getRefNum()); + pParent = new PdfWriter::CDictObject(); + pXref->Add(pParent); + if (!pDoc->EditParent(pXref, pParent, pParentRef->getRefNum())) + { + RELEASEOBJECT(pXref); + oParent.free(); + return NULL; + } + + for (int i = 0; i < oParent.dictGetLength(); ++i) + { + char* chKey = oParent.dictGetKey(i); + if (strcmp("Parent", chKey) == 0) + { + Object oParentRef; + oParent.dictGetValNF(i, &oParentRef); + PdfWriter::CDictObject* pParent2 = GetWidgetParent(pdfDoc, pDoc, &oParentRef); + if (pParent2) + { + pParent->Add("Parent", pParent2); + oParentRef.free(); + continue; + } + oParentRef.free(); + } + Object oTemp; + oParent.dictGetValNF(i, &oTemp); + DictToCDictObject(&oTemp, pParent, false, chKey); + oTemp.free(); + } + pParent->SetRef(pParentRef->getRefNum(), pParentRef->getRefGen()); + + oParent.free(); + + return pParent; +} bool CPdfFile::EditAnnot(int nPageIndex, int nID) { // Проверка режима редактирования @@ -742,6 +793,7 @@ bool CPdfFile::EditAnnot(int nPageIndex, int nID) return false; } + bool bIsWidget = false; PdfWriter::CAnnotation* pAnnot = NULL; if (oType.isName("Text")) pAnnot = new PdfWriter::CTextAnnotation(pXref); @@ -763,6 +815,7 @@ bool CPdfFile::EditAnnot(int nPageIndex, int nID) pAnnot = new PdfWriter::CPopupAnnotation(pXref); else if (oType.isName("Widget")) { + bIsWidget = true; char* sName = NULL; Object oFT; if (oAnnot.dictLookup("FT", &oFT)->isName()) @@ -830,6 +883,20 @@ bool CPdfFile::EditAnnot(int nPageIndex, int nID) } continue; } + if (strcmp("Parent", chKey) == 0 && bIsWidget) + { + Object oParentRef; + oAnnot.dictGetValNF(nIndex, &oParentRef); + PdfWriter::CDictObject* pParent = GetWidgetParent(pPDFDocument, pDoc, &oParentRef); + + if (pParent) + { + ((PdfWriter::CWidgetAnnotation*)pAnnot)->SetParent(pParent); + oParentRef.free(); + continue; + } + oParentRef.free(); + } Object oTemp; oAnnot.dictGetValNF(nIndex, &oTemp); DictToCDictObject(&oTemp, pAnnot, false, chKey); @@ -844,6 +911,7 @@ bool CPdfFile::EditAnnot(int nPageIndex, int nID) RELEASEOBJECT(pXref); return false; } + bool CPdfFile::DeleteAnnot(int nID) { // Проверка режима редактирования diff --git a/PdfFile/PdfWriter.cpp b/PdfFile/PdfWriter.cpp index 67426a17f7..d95718c98e 100644 --- a/PdfFile/PdfWriter.cpp +++ b/PdfFile/PdfWriter.cpp @@ -1813,7 +1813,7 @@ HRESULT CPdfWriter::AddAnnotField(NSFonts::IApplicationFonts* pAppFonts, CAnnotF } } } - if (!pPopupAnnot) + if (!pPopupAnnot && !oInfo.IsFreeText()) { pPopupAnnot = pMarkupAnnot->CreatePopup(); pPage->AddAnnotation(pPopupAnnot); @@ -2016,8 +2016,6 @@ HRESULT CPdfWriter::AddAnnotField(NSFonts::IApplicationFonts* pAppFonts, CAnnotF pWidgetAnnot->SetBG(pPr->GetBG()); if (nFlags & (1 << 8)) pWidgetAnnot->SetDV(pPr->GetDV()); - if (nFlags & (1 << 17)) - pWidgetAnnot->SetParentID(pPr->GetParentID()); if (nFlags & (1 << 18)) pWidgetAnnot->SetT(pPr->GetT()); @@ -2026,6 +2024,8 @@ HRESULT CPdfWriter::AddAnnotField(NSFonts::IApplicationFonts* pAppFonts, CAnnotF CAnnotFieldInfo::CWidgetAnnotPr::CButtonWidgetPr* pPr = oInfo.GetWidgetAnnotPr()->GetButtonWidgetPr(); PdfWriter::CButtonWidget* pButtonWidget = (PdfWriter::CButtonWidget*)pAnnot; + if (nFlags & (1 << 14)) + pButtonWidget->SetAP_N_Yes(pPr->GetAP_N_Yes()); pButtonWidget->SetV(nFlags & (1 << 9)); int nIFFlags = pPr->GetIFFlag(); pButtonWidget->SetIFFlag(nIFFlags); @@ -2056,8 +2056,6 @@ HRESULT CPdfWriter::AddAnnotField(NSFonts::IApplicationFonts* pAppFonts, CAnnotF pButtonWidget->SetA(d1, d2); } } - if (nFlags & (1 << 14)) - pButtonWidget->SetAP_N_Yes(pPr->GetAP_N_Yes()); } else if (oInfo.IsTextWidget()) { diff --git a/PdfFile/SrcWriter/Annotation.cpp b/PdfFile/SrcWriter/Annotation.cpp index 2ed1dcd0c4..dc0a49ba2d 100644 --- a/PdfFile/SrcWriter/Annotation.cpp +++ b/PdfFile/SrcWriter/Annotation.cpp @@ -33,6 +33,7 @@ #include "Pages.h" #include "Utils.h" #include "ResourcesDictionary.h" +#include "Streams.h" #include "../../DesktopEditor/common/File.h" @@ -202,6 +203,10 @@ namespace PdfWriter void CAnnotation::SetC(const std::vector& arrC) { AddToVectorD(this, "C", arrC); + } + void CAnnotation::CreateAP() + { + } //---------------------------------------------------------------------------------------- // CMarkupAnnotation @@ -257,6 +262,10 @@ namespace PdfWriter void CMarkupAnnotation::SetIRTID(CAnnotation* pAnnot) { Add("IRT", pAnnot); + } + void CMarkupAnnotation::CreateAP() + { + } //---------------------------------------------------------------------------------------- // CLinkAnnotation @@ -306,10 +315,8 @@ namespace PdfWriter //---------------------------------------------------------------------------------------- CTextAnnotation::CTextAnnotation(CXref* pXref) : CMarkupAnnotation(pXref, AnnotText) { + m_nName = 10; Add("Name", "Comment"); - - if (!Get("C")) - SetC({ 1.0, 0.8, 0.0 }); } void CTextAnnotation::SetOpen(bool bOpen) { @@ -317,6 +324,7 @@ namespace PdfWriter } void CTextAnnotation::SetName(BYTE nName) { + m_nName = nName; Add("Name", c_sAnnotIconNames[nName]); } void CTextAnnotation::SetState(BYTE nState) @@ -355,6 +363,25 @@ namespace PdfWriter Add("StateModel", new CStringObject(sValue.c_str())); } + void CTextAnnotation::CreateAP() + { + switch (m_nName) + { + case 3: + { + CAnnotationAppearance* pAP = new CAnnotationAppearance(m_pXref, {0, 0, 20, 20}); + Add("AP", pAP); + + pAP->DrawTextComment(); + break; + } + case 10: + default: + { + break; + } + } + } //---------------------------------------------------------------------------------------- // CUriLinkAnnotation //---------------------------------------------------------------------------------------- @@ -776,6 +803,23 @@ namespace PdfWriter Add("DA", new CStringObject(sDA.c_str(), false, true)); } + CDictObject* CWidgetAnnotation::GetObjOwnValue(const std::string& sV) + { + if (Get(sV)) + return this; + CDictObject* pParent = m_pParent; + while (pParent) + { + if (pParent->Get(sV)) + return pParent; + CObjectBase* pParent2 = pParent->Get("Parent"); + if (pParent2 && pParent2->GetType() == object_type_DICT) + pParent = (CDictObject*)pParent2; + else + return NULL; + } + return NULL; + } void CWidgetAnnotation::CheckMK() { if (!m_pMK) @@ -815,9 +859,12 @@ namespace PdfWriter { Add("Ff", nFlag); } - void CWidgetAnnotation::SetParentID(const int& nParentID) + void CWidgetAnnotation::SetParent(CDictObject* pParent) { - + if (!pParent) + return; + m_pParent = pParent; + Add("Parent", pParent); } void CWidgetAnnotation::SetTU(const std::wstring& wsTU) { @@ -868,8 +915,22 @@ namespace PdfWriter } void CButtonWidget::SetV(bool bV) { - Add("V", (bV ? "Yes" : "Off")); - Add("AS", (bV ? "Yes" : "Off")); + CDictObject* pOwner = GetObjOwnValue("V"); + if (!pOwner) + { + if (m_pParent) + { + if (bV) + m_pParent->Add("V", m_sAP_N_Yes.c_str()); + } + else + Add("V", (bV ? m_sAP_N_Yes.c_str() : "Off")); + } + else if (bV) + pOwner->Add("V", m_sAP_N_Yes.c_str()); + + // TODO + // Add("AS", (bV ? m_sAP_N_Yes.c_str() : "Off")); } void CButtonWidget::SetDV(const std::wstring& wsDV) { @@ -979,20 +1040,14 @@ namespace PdfWriter } void CButtonWidget::SetAP_N_Yes(const std::wstring& wsAP_N_Yes) { - CNameObject* pV = (CNameObject*)Get("V"); - if (pV && 0 == StrCmp(pV->Get(), "Yes")) - { - std::string sValue = U_TO_UTF8(wsAP_N_Yes); - Add("V", new CStringObject(sValue.c_str())); - Add("AS", new CStringObject(sValue.c_str())); - } + std::string sValue = U_TO_UTF8(wsAP_N_Yes); + m_sAP_N_Yes = sValue; } //---------------------------------------------------------------------------------------- // CTextWidget //---------------------------------------------------------------------------------------- CTextWidget::CTextWidget(CXref* pXref) : CWidgetAnnotation(pXref, AnnotWidget) { - Add("FT", "Tx"); } void CTextWidget::SetMaxLen(const int& nMaxLen) { @@ -1007,7 +1062,12 @@ namespace PdfWriter void CTextWidget::SetV(const std::wstring& wsV) { std::string sValue = U_TO_UTF8(wsV); - Add("V", new CStringObject(sValue.c_str())); + CDictObject* pOwner = GetObjOwnValue("V"); + if (!pOwner) + pOwner = GetObjOwnValue("FT"); + if (!pOwner) + pOwner = this; + pOwner->Add("V", new CStringObject(sValue.c_str())); } void CTextWidget::SetRV(const std::wstring& wsRV) { @@ -1028,7 +1088,12 @@ namespace PdfWriter void CChoiceWidget::SetV(const std::wstring& wsV) { std::string sValue = U_TO_UTF8(wsV); - Add("V", new CStringObject(sValue.c_str())); + CDictObject* pOwner = GetObjOwnValue("V"); + if (!pOwner) + pOwner = GetObjOwnValue("FT"); + if (!pOwner) + pOwner = this; + pOwner->Add("V", new CStringObject(sValue.c_str())); } void CChoiceWidget::SetOpt(const std::vector< std::pair >& arrOpt) { @@ -1064,4 +1129,31 @@ namespace PdfWriter CSignatureWidget::CSignatureWidget(CXref* pXref) : CWidgetAnnotation(pXref, AnnotWidget) { } + //---------------------------------------------------------------------------------------- + // CAnnotationAppearance + //---------------------------------------------------------------------------------------- + CAnnotationAppearance::CAnnotationAppearance(CXref* pXref, const TRect& oRect) + { + m_pXref = pXref; + m_pStream = new CMemoryStream(); + + SetStream(m_pXref, m_pStream); + + Add("Type", "XObject"); + Add("Subtype", "Form"); + + CArrayObject* pArray = new CArrayObject(); + if (!pArray) + return; + + Add("BBox", pArray); + pArray->Add(0); + pArray->Add(0); + pArray->Add(oRect.fRight - oRect.fLeft); + pArray->Add(oRect.fBottom - oRect.fTop); + } + void CAnnotationAppearance::DrawTextComment() + { + m_pStream->WriteStr(""); + } } diff --git a/PdfFile/SrcWriter/Annotation.h b/PdfFile/SrcWriter/Annotation.h index 434add92b0..3850499738 100644 --- a/PdfFile/SrcWriter/Annotation.h +++ b/PdfFile/SrcWriter/Annotation.h @@ -129,6 +129,7 @@ namespace PdfWriter void SetLM(const std::wstring& wsLM); void SetC(const std::vector& arrC); // TODO AP Необходимо генерировать внешний вид аннотации как у Widget + virtual void CreateAP(); }; class CPopupAnnotation : public CAnnotation { @@ -163,6 +164,7 @@ namespace PdfWriter void SetIRTID(CAnnotation* pAnnot); CPopupAnnotation* CreatePopup(); + virtual void CreateAP() override; }; class CLinkAnnotation : public CAnnotation { @@ -177,6 +179,8 @@ namespace PdfWriter }; class CTextAnnotation : public CMarkupAnnotation { + private: + BYTE m_nName; public: CTextAnnotation(CXref* pXref); EAnnotType GetAnnotationType() const override @@ -188,6 +192,8 @@ namespace PdfWriter void SetName(BYTE nName); void SetState(BYTE nState); void SetStateModel(BYTE nStateModel); + + void CreateAP() override; }; class CUriLinkAnnotation : public CAnnotation { @@ -310,6 +316,7 @@ namespace PdfWriter CDictObject* m_pParent; CDocument* m_pDocument; + CDictObject* GetObjOwnValue(const std::string& sV); void CheckMK(); public: @@ -322,7 +329,7 @@ namespace PdfWriter void SetH(const BYTE& nH); void SetR(const int& nR); void SetFlag (const int& nFlag); - void SetParentID(const int& nParentID); + void SetParent(CDictObject* pParent); void SetTU(const std::wstring& wsTU); void SetDS(const std::wstring& wsDS); virtual void SetDV(const std::wstring& wsDV); @@ -335,6 +342,7 @@ namespace PdfWriter private: EAnnotType m_nSubtype; CDictObject* m_pIF; + std::string m_sAP_N_Yes; void CheckIF(); @@ -402,5 +410,17 @@ namespace PdfWriter return m_nSubtype; } }; + + class CAnnotationAppearance : public CDictObject + { + public: + CAnnotationAppearance(CXref* pXref, const TRect& oRect); + + void DrawTextComment(); + + private: + CXref* m_pXref; + CStream* m_pStream; + }; } #endif // _PDF_WRITER_SRC_ANNOTATION_H diff --git a/PdfFile/SrcWriter/Document.cpp b/PdfFile/SrcWriter/Document.cpp index 0c7cf026c0..1441464a3e 100644 --- a/PdfFile/SrcWriter/Document.cpp +++ b/PdfFile/SrcWriter/Document.cpp @@ -555,7 +555,9 @@ namespace PdfWriter } CAnnotation* CDocument::CreateTextAnnot() { - return new CTextAnnotation(m_pXref); + CTextAnnotation* pNew = new CTextAnnotation(m_pXref); + pNew->SetC({ 1.0, 0.8, 0.0 }); + return pNew; } CAnnotation* CDocument::CreateLinkAnnot(const TRect& oRect, CDestination* pDest) { @@ -611,7 +613,9 @@ namespace PdfWriter } CAnnotation* CDocument::CreateTextWidget() { - return new CTextWidget(m_pXref); + CAnnotation* pNew = new CTextWidget(m_pXref); + pNew->Add("FT", "Tx"); + return pNew; } CAnnotation* CDocument::CreateChoiceWidget() { @@ -1168,15 +1172,13 @@ namespace PdfWriter } bool CDocument::CreatePageTree(CXref* pXref, CPageTree* pPageTree) { - if (!pXref || !pPageTree) + if (!pPageTree || !EditXref(pXref)) return false; if (!m_pPageTree) m_pPageTree = pPageTree; else m_pPageTree->Join(pPageTree); - pXref->SetPrev(m_pLastXref); - m_pLastXref = pXref; return true; } @@ -1242,7 +1244,7 @@ namespace PdfWriter } bool CDocument::EditPage(CXref* pXref, CPage* pPage, int nPageIndex) { - if (!pXref || !pPage) + if (!pPage || !EditXref(pXref)) return false; pPage->AddContents(m_pXref); @@ -1251,8 +1253,6 @@ namespace PdfWriter pPage->SetFilter(STREAM_FILTER_FLATE_DECODE); #endif - pXref->SetPrev(m_pLastXref); - m_pLastXref = pXref; m_pCurPage = pPage; m_mEditPages[nPageIndex] = pPage; @@ -1260,12 +1260,29 @@ namespace PdfWriter } bool CDocument::EditAnnot(CXref* pXref, CAnnotation* pAnnot, int nID) { - if (!pXref || !pAnnot) + if (!pAnnot || !EditXref(pXref)) + return false; + + m_mAnnotations[nID] = pAnnot; + + return true; + } + bool CDocument::EditParent(CXref* pXref, CDictObject* pParent, int nID) + { + if (!pParent || !EditXref(pXref)) + return false; + + m_mParents[nID] = pParent; + + return true; + } + bool CDocument::EditXref(CXref* pXref) + { + if (!pXref) return false; pXref->SetPrev(m_pLastXref); m_pLastXref = pXref; - m_mAnnotations[nID] = pAnnot; return true; } diff --git a/PdfFile/SrcWriter/Document.h b/PdfFile/SrcWriter/Document.h index 4f4238c421..273c2d991d 100644 --- a/PdfFile/SrcWriter/Document.h +++ b/PdfFile/SrcWriter/Document.h @@ -180,7 +180,8 @@ namespace PdfWriter bool AddToFile(CXref* pXref, CDictObject* pTrailer, CXref* pInfoXref, CInfoDict* pInfo); void Sign(const TRect& oRect, CImageDict* pImage, ICertificate* pCert); std::wstring GetEditPdfPath() { return m_wsFilePath; } - bool EditAnnot(CXref* pXref, CAnnotation* pAnnot, int nID); + bool EditAnnot (CXref* pXref, CAnnotation* pAnnot, int nID); + bool EditParent(CXref* pXref, CDictObject* pParent, int nID); bool DeleteAnnot(int nID); CAnnotation* GetAnnot(int nID); CPage* GetCurPage() { return m_pCurPage; } @@ -200,6 +201,7 @@ namespace PdfWriter bool CheckAcroForm(); CRadioGroupField* FindRadioGroupField(const std::wstring& wsGroupName); void Sign(const std::wstring& wsPath, unsigned int nSizeXRef, bool bNeedStreamXRef = false); + bool EditXref(CXref* pXref); private: @@ -267,6 +269,7 @@ namespace PdfWriter std::vector m_vRadioGroups; std::map m_mFields; std::map m_mAnnotations; + std::map m_mParents; std::map m_mEditPages; friend class CFontCidTrueType; diff --git a/PdfFile/SrcWriter/Pages.cpp b/PdfFile/SrcWriter/Pages.cpp index b63f33c1b2..ac5ef7437a 100644 --- a/PdfFile/SrcWriter/Pages.cpp +++ b/PdfFile/SrcWriter/Pages.cpp @@ -547,7 +547,10 @@ namespace PdfWriter // Если объект Resources нулевой, тогда ищем Resources у родительского объекта рекурсивно if (!pObject) { - CPageTree* pPageTree = (CPageTree*)Get("Parent"); + CPageTree* pPageTree = NULL; + CObjectBase* pObj = Get("Parent"); + if (pObj->GetType() == object_type_DICT) + pPageTree = (CPageTree*)pObj; while (pPageTree) { pObject = Get("Resources"); diff --git a/PdfFile/test/test.cpp b/PdfFile/test/test.cpp index ac2b193b5b..0a35e6e44e 100644 --- a/PdfFile/test/test.cpp +++ b/PdfFile/test/test.cpp @@ -247,6 +247,13 @@ int main() RELEASEARRAYOBJECTS(pBuffer); RELEASEARRAYOBJECTS(pFileContent); } + else if (false) + { + if (pdfFile.EditPage(0)) + { + pdfFile.EditAnnot(0, 99); + } + } else { if (pdfFile.EditPage(0))