From 1432c7b07ee8c14506465f7548401b3d95dfd727 Mon Sep 17 00:00:00 2001 From: Svetlana Kulikova Date: Tue, 23 Jan 2024 18:44:36 +0300 Subject: [PATCH] Fix pdf write --- PdfFile/PdfFile.cpp | 111 ++++++++++++---------- PdfFile/PdfWriter.cpp | 43 +++++---- PdfFile/SrcWriter/Annotation.cpp | 38 +++++++- PdfFile/SrcWriter/Document.cpp | 23 +++-- PdfFile/SrcWriter/Document.h | 1 + PdfFile/SrcWriter/Field.cpp | 13 ++- PdfFile/SrcWriter/ResourcesDictionary.cpp | 26 +++++ PdfFile/SrcWriter/ResourcesDictionary.h | 1 + 8 files changed, 169 insertions(+), 87 deletions(-) diff --git a/PdfFile/PdfFile.cpp b/PdfFile/PdfFile.cpp index 4732e653c1..b6f8d53ee2 100644 --- a/PdfFile/PdfFile.cpp +++ b/PdfFile/PdfFile.cpp @@ -400,48 +400,6 @@ void CPdfFile::RotatePage(int nRotate) m_pInternal->pWriter->PageRotate(nRotate); } #ifndef BUILDING_WASM_MODULE -PdfWriter::CDictObject* GetAcroForm(Object* oAcroForm) -{ - if (!oAcroForm || !oAcroForm->isDict()) - return NULL; - - PdfWriter::CDictObject* pAcroForm = new PdfWriter::CDictObject(); - - for (int nIndex = 0; nIndex < oAcroForm->dictGetLength(); ++nIndex) - { - Object oTemp2; - char* chKey = oAcroForm->dictGetKey(nIndex); - if (strcmp("DR", chKey) == 0) - { - oAcroForm->dictGetVal(nIndex, &oTemp2); - /* - if (!oTemp2.isDict()) - { - oTemp2.free(); - continue; - } - - PdfWriter::CResourcesDict* pDR = new PdfWriter::CResourcesDict(NULL, true, false); - pAcroForm->Add(chKey, pDR); - for (int nIndex = 0; nIndex < oTemp2.dictGetLength(); ++nIndex) - { - - } - oTemp2.free(); - continue; - */ - } - else - oAcroForm->dictGetValNF(nIndex, &oTemp2); - DictToCDictObject(&oTemp2, pAcroForm, false, chKey); - oTemp2.free(); - } - - if (!pAcroForm->Get("Fields")) - pAcroForm->Add("Fields", new PdfWriter::CArrayObject()); - - return pAcroForm; -} bool CPdfFile::EditPdf(const std::wstring& wsDstFile) { if (wsDstFile.empty()) @@ -522,25 +480,71 @@ bool CPdfFile::EditPdf(const std::wstring& wsDstFile) return false; } pXref->Add(pCatalog, catRef.gen); + PdfWriter::CResourcesDict* pDR = NULL; + PdfWriter::CXref* pDRXref = NULL; for (int nIndex = 0; nIndex < catDict.dictGetLength(); ++nIndex) { - Object oTemp; + Object oAcroForm; char* chKey = catDict.dictGetKey(nIndex); if (strcmp("AcroForm", chKey) == 0) { - catDict.dictGetVal(nIndex, &oTemp); - PdfWriter::CDictObject* pAcroForm = GetAcroForm(&oTemp); - oTemp.free(); - if (pAcroForm) + catDict.dictGetVal(nIndex, &oAcroForm); + PdfWriter::CDictObject* pAcroForm = new PdfWriter::CDictObject(); + + for (int nIndex = 0; nIndex < oAcroForm.dictGetLength(); ++nIndex) { - pCatalog->Add(chKey, pAcroForm); + Object oTemp2; + char* chKey = oAcroForm.dictGetKey(nIndex); + if (strcmp("DR", chKey) == 0) + { + oAcroForm.dictGetVal(nIndex, &oTemp2); + if (!oTemp2.isDict()) + { + oTemp2.free(); + continue; + } + + Object oDR; + oAcroForm.dictGetValNF(nIndex, &oDR); + int nDRxrefNum = oDR.isRef() ? oDR.getRefNum() : xref->getNumObjects(); + int nDRxrefGen = oDR.isRef() ? oDR.getRefGen() : 0; + oDR.free(); + pDRXref = new PdfWriter::CXref(pDoc, nDRxrefNum); + + pDR = new PdfWriter::CResourcesDict(NULL, true, false); + pDRXref->Add(pDR, nDRxrefGen); + + pAcroForm->Add(chKey, pDR); + for (int nIndex2 = 0; nIndex2 < oTemp2.dictGetLength(); ++nIndex2) + { + Object oTemp; + char* chKey = oTemp2.dictGetKey(nIndex2); + oTemp2.dictGetVal(nIndex2, &oTemp); + DictToCDictObject(&oTemp, pDR, false, chKey); + oTemp.free(); + } + oTemp2.free(); + + pDR->Fix(); + continue; + } + else + oAcroForm.dictGetValNF(nIndex, &oTemp2); + DictToCDictObject(&oTemp2, pAcroForm, false, chKey); + oTemp2.free(); } + + if (!pAcroForm->Get("Fields")) + pAcroForm->Add("Fields", new PdfWriter::CArrayObject()); + + oAcroForm.free(); + pCatalog->Add(chKey, pAcroForm); continue; } else - catDict.dictGetValNF(nIndex, &oTemp); - DictToCDictObject(&oTemp, pCatalog, false, chKey); - oTemp.free(); + catDict.dictGetValNF(nIndex, &oAcroForm); + DictToCDictObject(&oAcroForm, pCatalog, false, chKey); + oAcroForm.free(); } catDict.free(); @@ -614,12 +618,15 @@ bool CPdfFile::EditPdf(const std::wstring& wsDstFile) } // Применение редактирования для writer - bool bRes = pDoc->EditPdf(wsDstFile, xref->getLastXRefPos(), xref->getNumObjects(), pXref, pCatalog, pEncryptDict, nFormField); + bool bRes = pDoc->EditPdf(wsDstFile, xref->getLastXRefPos(), xref->getNumObjects() + 1, pXref, pCatalog, pEncryptDict, nFormField); if (bRes) { // Воспроизведение дерева страниц во writer m_pInternal->GetPageTree(xref, &pagesRefObj); m_pInternal->bEdit = true; + + if (pDR && pDRXref) + bRes = pDoc->EditResources(pDRXref, pDR); } pagesRefObj.free(); return bRes; diff --git a/PdfFile/PdfWriter.cpp b/PdfFile/PdfWriter.cpp index 5f3c2d1aff..b3e2efd8df 100644 --- a/PdfFile/PdfWriter.cpp +++ b/PdfFile/PdfWriter.cpp @@ -1707,8 +1707,9 @@ HRESULT CPdfWriter::AddAnnotField(NSFonts::IApplicationFonts* pAppFonts, CAnnotF pAnnot->SetAnnotFlag(oInfo.GetAnnotFlag()); double dX1, dY1, dX2, dY2; + double dPageHeight = pPage->GetHeight(); oInfo.GetBounds(dX1, dY1, dX2, dY2); - PdfWriter::TRect oRect(dX1, pPage->GetHeight() - dY1, dX2, pPage->GetHeight() - dY2); + PdfWriter::TRect oRect(dX1, dPageHeight - dY1, dX2, dPageHeight - dY2); pAnnot->SetRect(oRect); int nFlags = oInfo.GetFlag(); @@ -2016,7 +2017,7 @@ HRESULT CPdfWriter::AddAnnotField(NSFonts::IApplicationFonts* pAppFonts, CAnnotF { case 0: { - pDest->SetXYZ(pAction->dD[0], pAction->dD[1], pAction->dD[2]); + pDest->SetXYZ(pAction->dD[0], dPageHeight - pAction->dD[1], pAction->dD[2]); break; } case 1: @@ -2026,7 +2027,7 @@ HRESULT CPdfWriter::AddAnnotField(NSFonts::IApplicationFonts* pAppFonts, CAnnotF } case 2: { - pDest->SetFitH(pAction->dD[1]); + pDest->SetFitH(dPageHeight - pAction->dD[1]); break; } case 3: @@ -2036,7 +2037,7 @@ HRESULT CPdfWriter::AddAnnotField(NSFonts::IApplicationFonts* pAppFonts, CAnnotF } case 4: { - pDest->SetFitR(pAction->dD[0], pAction->dD[1], pAction->dD[2], pAction->dD[3]); + pDest->SetFitR(pAction->dD[0], dPageHeight - pAction->dD[1], pAction->dD[2], dPageHeight - pAction->dD[3]); break; } case 5: @@ -2046,7 +2047,7 @@ HRESULT CPdfWriter::AddAnnotField(NSFonts::IApplicationFonts* pAppFonts, CAnnotF } case 6: { - pDest->SetFitBH(pAction->dD[1]); + pDest->SetFitBH(dPageHeight - pAction->dD[1]); break; } case 7: @@ -2325,11 +2326,11 @@ HRESULT CPdfWriter::EditWidgetParents(NSFonts::IApplicationFonts* pAppFonts, CWi int nFlags = pParent->nFlags; if (nFlags & (1 << 0)) - pParentObj->Add("T", new PdfWriter::CStringObject((U_TO_UTF8(pParent->sName)).c_str())); + pParentObj->Add("T", new PdfWriter::CStringObject((U_TO_UTF8(pParent->sName)).c_str(), true)); if (nFlags & (1 << 1)) { std::string sV = U_TO_UTF8(pParent->sV); - pParentObj->Add("V", new PdfWriter::CStringObject(sV.c_str())); + pParentObj->Add("V", new PdfWriter::CStringObject(sV.c_str(), true)); PdfWriter::CObjectBase* pKids = pParentObj->Get("Kids"); if (pKids && pKids->GetType() == PdfWriter::object_type_ARRAY) @@ -2363,7 +2364,7 @@ HRESULT CPdfWriter::EditWidgetParents(NSFonts::IApplicationFonts* pAppFonts, CWi } } if (nFlags & (1 << 2)) - pParentObj->Add("DV", new PdfWriter::CStringObject((U_TO_UTF8(pParent->sDV)).c_str())); + pParentObj->Add("DV", new PdfWriter::CStringObject((U_TO_UTF8(pParent->sDV)).c_str(), true)); if (nFlags & (1 << 3)) { PdfWriter::CArrayObject* pArray = new PdfWriter::CArrayObject(); @@ -2382,7 +2383,7 @@ HRESULT CPdfWriter::EditWidgetParents(NSFonts::IApplicationFonts* pAppFonts, CWi PdfWriter::CArrayObject* pArray = new PdfWriter::CArrayObject(); pParentObj->Add("V", pArray); for (int i = 0; i < pParent->arrV.size(); ++i) - pArray->Add(new PdfWriter::CStringObject(U_TO_UTF8(pParent->arrV[i]).c_str())); + pArray->Add(new PdfWriter::CStringObject(U_TO_UTF8(pParent->arrV[i]).c_str(), true)); PdfWriter::CObjectBase* pKids = pParentObj->Get("Kids"); if (pKids && pKids->GetType() == PdfWriter::object_type_ARRAY) { @@ -2415,6 +2416,7 @@ HRESULT CPdfWriter::EditWidgetParents(NSFonts::IApplicationFonts* pAppFonts, CWi arrForm.push_back(NULL); continue; } + wsPath = L"E:/test.png"; std::wstring sTempImagePath = GetDownloadFile(wsPath, wsTempDirectory); std::wstring wsImagePath = sTempImagePath.empty() ? wsPath : sTempImagePath; @@ -3284,14 +3286,15 @@ void CPdfWriter::DrawTextWidget(NSFonts::IApplicationFonts* pAppFonts, PdfWriter m_oLinesManager.Init(pCodes2, pWidths, unLen, ushSpaceCode, ushNewLineCode, pFontTT->GetLineHeight(), pFontTT->GetAscent()); - double dLineHeight = pFontTT->GetLineHeight() * dFontSize / 1000.0; + double dKoef = dFontSize / pFontTT->m_dUnitsPerEm; + double dLineHeight = (pFontTT->m_dAscent + std::abs(pFontTT->m_dDescent)) * dKoef; m_oLinesManager.CalculateLines(dFontSize, dWidth); pTextWidget->StartAP(); unsigned int unLinesCount = m_oLinesManager.GetLinesCount(); - double dLineShiftY = dHeight - pFontTT->GetLineHeight() * dFontSize / 1000.0 - dShiftBorder; + double dLineShiftY = dHeight - dShiftBorder * 2 - dLineHeight; for (unsigned int unIndex = 0; unIndex < unLinesCount; ++unIndex) { unsigned int unLineStart = m_oLinesManager.GetLineStartPos(unIndex); @@ -3355,23 +3358,27 @@ void CPdfWriter::DrawTextWidget(NSFonts::IApplicationFonts* pAppFonts, PdfWriter } else if (1 == nAlign || 2 == nAlign) { - double dSumWidth = 0; + double dLineWidth = 0; for (unsigned int unIndex = 0; unIndex < unLen; ++unIndex) { unsigned short ushCode = pCodes[unIndex]; double dLetterWidth = ppFonts[unIndex]->GetWidth(ushCode) / 1000.0 * dFontSize; - dSumWidth += dLetterWidth; + dLineWidth += dLetterWidth; } if (2 == nAlign) - dShiftX = dWidth - dSumWidth - dShiftBorder * 2; + dShiftX = dWidth - dLineWidth - dShiftBorder * 2; else if (1 == nAlign) - dShiftX = (dWidth - dSumWidth) / 2; + dShiftX = (dWidth - dLineWidth) / 2; } double dBaseLine = (dHeight - dFontSize) / 2.0 - dShiftBorder; if (pFontTT) - dBaseLine = (dHeight - pFontTT->m_dHeight * dFontSize / pFontTT->m_dUnitsPerEm) / 2.0 + std::abs(pFontTT->m_dDescent * dFontSize / pFontTT->m_dUnitsPerEm); + { + double dKoef = dFontSize / pFontTT->m_dUnitsPerEm; + double dLineHeight = (pFontTT->m_dAscent + std::abs(pFontTT->m_dDescent)) * dKoef;; + dBaseLine = (dHeight - dLineHeight) / 2.0 + std::abs(pFontTT->m_dDescent * dKoef); + } pTextWidget->SetAP(wsValue, pCodes, unLen, dShiftX, dBaseLine, ppFonts, pShifts); RELEASEARRAYOBJECTS(pShifts); @@ -3551,9 +3558,9 @@ void CPdfWriter::DrawButtonWidget(NSFonts::IApplicationFonts* pAppFonts, PdfWrit if (nAP == 0) wsValue = pButtonWidget->GetCA(); else if (nAP == 1) - wsValue = pButtonWidget->GetRC(); + wsValue = pButtonWidget->GetRC().empty() ? pButtonWidget->GetCA() : pButtonWidget->GetRC(); else - wsValue = pButtonWidget->GetAC(); + wsValue = pButtonWidget->GetAC().empty() ? pButtonWidget->GetCA() : pButtonWidget->GetAC(); if (!pButtonWidget->HaveBorder()) { diff --git a/PdfFile/SrcWriter/Annotation.cpp b/PdfFile/SrcWriter/Annotation.cpp index 19dd6870f3..bc21d428ba 100644 --- a/PdfFile/SrcWriter/Annotation.cpp +++ b/PdfFile/SrcWriter/Annotation.cpp @@ -907,6 +907,13 @@ namespace PdfWriter { if (!m_pMK) { + CObjectBase* pMK = Get("MK"); + if (pMK && pMK->GetType() == object_type_DICT) + { + m_pMK = (CDictObject*)pMK; + return; + } + m_pMK = new CDictObject(); Add("MK", m_pMK); } @@ -1235,9 +1242,36 @@ namespace PdfWriter } void CPushButtonWidget::SetAP(CXObject* pForm, BYTE nAP, unsigned short* pCodes, unsigned int unCount, double dX, double dY, double dLineW, double dLineH, CFontCidTrueType** ppFonts) { - m_pAppearance = new CAnnotAppearance(m_pXref, this); if (!m_pAppearance) - return; + { + m_pAppearance = new CAnnotAppearance(m_pXref, this); + CObjectBase* pAP = Get("AP"); + if (pAP && pAP->GetType() == object_type_DICT) + { + CDictObject* pDAP = (CDictObject*)pAP; + CObjectBase* pAPi = pDAP->Get("N"); + if (pAPi) + { + CProxyObject* pNewAPi = new CProxyObject(pAPi->Copy(), true); + pNewAPi->Get()->SetRef(pAPi->GetObjId(), pAPi->GetGenNo()); + m_pAppearance->Add("N", pNewAPi); + } + pAPi = pDAP->Get("D"); + if (pAPi) + { + CProxyObject* pNewAPi = new CProxyObject(pAPi->Copy(), true); + pNewAPi->Get()->SetRef(pAPi->GetObjId(), pAPi->GetGenNo()); + m_pAppearance->Add("D", pNewAPi); + } + pAPi = pDAP->Get("R"); + if (pAPi) + { + CProxyObject* pNewAPi = new CProxyObject(pAPi->Copy(), true); + pNewAPi->Get()->SetRef(pAPi->GetObjId(), pAPi->GetGenNo()); + m_pAppearance->Add("R", pNewAPi); + } + } + } CAnnotAppearanceObject* pAppearance = NULL; if (nAP == 0) diff --git a/PdfFile/SrcWriter/Document.cpp b/PdfFile/SrcWriter/Document.cpp index 9421856714..b755bd31ef 100644 --- a/PdfFile/SrcWriter/Document.cpp +++ b/PdfFile/SrcWriter/Document.cpp @@ -1338,17 +1338,6 @@ namespace PdfWriter if (pAcroForm && pAcroForm->GetType() == object_type_DICT) m_pAcroForm = (CDictObject*)pAcroForm; - if (m_pAcroForm) - { - CObjectBase* pFieldsResources = m_pAcroForm->Get("DR"); - if (pFieldsResources && pFieldsResources->GetType() == object_type_DICT) - { - // TODO необходимо перенести текущие поля DR - m_pFieldsResources = new CResourcesDict(m_pXref, false, true); - m_pAcroForm->Add("DR", m_pFieldsResources); - } - } - if (pEncrypt) { m_pEncryptDict = pEncrypt; @@ -1359,6 +1348,16 @@ namespace PdfWriter m_wsFilePath = wsPath; return true; } + bool CDocument::EditResources(CXref* pXref, CResourcesDict* pResources) + { + if (!pResources || !EditXref(pXref)) + return false; + + CheckAcroForm(); + m_pAcroForm->Add("DR", pResources); + m_pFieldsResources = pResources; + return true; + } std::pair CDocument::GetPageRef(int nPageIndex) { std::pair pRes = std::make_pair(0, 0); @@ -1589,7 +1588,7 @@ namespace PdfWriter m_pTrailer->Remove("W"); bNeedStreamXRef = true; - m_pLastXref->WriteToStream(pStream, pEncrypt, bNeedStreamXRef); + m_pLastXref->WriteToStream(pStream, pEncrypt); } else m_pLastXref->WriteToStream(pStream, pEncrypt); diff --git a/PdfFile/SrcWriter/Document.h b/PdfFile/SrcWriter/Document.h index 14c12b9818..f8a1dbead2 100644 --- a/PdfFile/SrcWriter/Document.h +++ b/PdfFile/SrcWriter/Document.h @@ -181,6 +181,7 @@ namespace PdfWriter bool CreatePageTree(CXref* pXref, CPageTree* pPageTree); bool EditPdf(const std::wstring& wsPath, int nPosLastXRef, int nSizeXRef, CXref* pXref, CCatalog* pCatalog, CEncryptDict* pEncrypt, int nFormField); + bool EditResources(CXref* pXref, CResourcesDict* pResources); std::pair GetPageRef(int nPageIndex); bool EditPage(CXref* pXref, CPage* pPage, int nPageIndex); CPage* AddPage(int nPageIndex); diff --git a/PdfFile/SrcWriter/Field.cpp b/PdfFile/SrcWriter/Field.cpp index 29276b2982..21f94a686e 100644 --- a/PdfFile/SrcWriter/Field.cpp +++ b/PdfFile/SrcWriter/Field.cpp @@ -1533,14 +1533,21 @@ namespace PdfWriter m_pAnnot = pAnnot; m_pField = NULL; - m_pNormal = new CAnnotAppearanceObject(pXref, pAnnot); + m_pNormal = NULL; m_pRollover = NULL; m_pDown = NULL; - - Add("N", m_pNormal); } CAnnotAppearanceObject* CAnnotAppearance::GetNormal() { + if (!m_pNormal) + { + if (m_pField) + m_pNormal = new CAnnotAppearanceObject(m_pXref, m_pField); + else if (m_pAnnot) + m_pNormal = new CAnnotAppearanceObject(m_pXref, m_pAnnot); + Add("N", m_pNormal); + } + return m_pNormal; } CAnnotAppearanceObject* CAnnotAppearance::GetRollover() diff --git a/PdfFile/SrcWriter/ResourcesDictionary.cpp b/PdfFile/SrcWriter/ResourcesDictionary.cpp index 7c8da0ea99..fdca7a9e50 100644 --- a/PdfFile/SrcWriter/ResourcesDictionary.cpp +++ b/PdfFile/SrcWriter/ResourcesDictionary.cpp @@ -162,4 +162,30 @@ namespace PdfWriter m_pXObjects->Add(sXObjName, pObject); } + void CResourcesDict::Fix() + { + // Инициализация текущего fonts + CObjectBase* pFonts = Get("Font"); + if (pFonts && pFonts->GetType() == object_type_DICT) + { + m_pFonts = (CDictObject*)pFonts; + m_unFontsCount = m_pFonts->GetSize(); + } + + // Инициализация текущего ExtGStates + CObjectBase* pExtGStates = Get("ExtGState"); + if (pExtGStates && pExtGStates->GetType() == object_type_DICT) + { + m_pExtGStates = (CDictObject*)pExtGStates; + m_unExtGStatesCount = m_pExtGStates->GetSize(); + } + + // Инициализация текущего XObject + CObjectBase* pXObject = Get("XObject"); + if (pXObject && pXObject->GetType() == object_type_DICT) + { + m_pXObjects = (CDictObject*)pXObject; + m_unXObjectsCount = m_pXObjects->GetSize(); + } + } } diff --git a/PdfFile/SrcWriter/ResourcesDictionary.h b/PdfFile/SrcWriter/ResourcesDictionary.h index 82bdbb03f0..251789ee2d 100644 --- a/PdfFile/SrcWriter/ResourcesDictionary.h +++ b/PdfFile/SrcWriter/ResourcesDictionary.h @@ -50,6 +50,7 @@ namespace PdfWriter const char* GetExtGrStateName(CExtGrState* pState); const char* GetXObjectName(CXObject* pXObject); void AddXObjectWithName(const char* sXObjectName, CXObject* pXObject); + void Fix(); private: