Add PrefixForm for rename same full names

This commit is contained in:
Svetlana Kulikova
2025-04-14 15:53:51 +03:00
parent 85c60f172c
commit f5f3d2572e
12 changed files with 202 additions and 31 deletions

View File

@ -2782,15 +2782,15 @@ void CPdfEditor::EndMarkedContent()
}
bool CPdfEditor::IsBase14(const std::wstring& wsFontName, bool& bBold, bool& bItalic, std::wstring& wsFontPath)
{
std::map<std::wstring, std::wstring>::iterator it = m_mFonts.find(wsFontName);
std::map<std::wstring, std::wstring>::const_iterator it = m_mFonts.find(wsFontName);
if (it != m_mFonts.end())
wsFontPath = it->second;
if (wsFontPath.empty())
{
std::map<std::wstring, std::wstring> mFonts = m_pReader->GetFonts();
it = mFonts.find(wsFontName);
if (it != mFonts.end())
wsFontPath = it->second;
const std::map<std::wstring, std::wstring>& mFonts = m_pReader->GetFonts();
std::map<std::wstring, std::wstring>::const_iterator it2 = mFonts.find(wsFontName);
if (it2 != mFonts.end())
wsFontPath = it2->second;
}
if (wsFontPath.empty())
return false;

View File

@ -336,11 +336,11 @@ void CPdfFile::GetPageInfo(int nPageIndex, double* pdWidth, double* pdHeight, do
else
m_pInternal->pReader->GetPageInfo(nPageIndex, pdWidth, pdHeight, pdDpiX, pdDpiY);
}
bool CPdfFile::MergePages(BYTE* data, DWORD length, int nMaxID)
bool CPdfFile::MergePages(BYTE* data, DWORD length, int nMaxID, const std::string& sPrefixForm)
{
if (!m_pInternal->pReader)
return false;
return m_pInternal->pReader->MergePages(data, length, L"", nMaxID) && (m_pInternal->pReader->GetError() == 0);
return m_pInternal->pReader->MergePages(data, length, L"", nMaxID, sPrefixForm) && (m_pInternal->pReader->GetError() == 0);
}
int CPdfFile::GetRotate(int nPageIndex)
{

View File

@ -127,7 +127,7 @@ public:
virtual BYTE* GetLinks(int nPageIndex);
bool ValidMetaData();
bool MergePages(BYTE* data, DWORD length, int nMaxID = 0);
bool MergePages(BYTE* data, DWORD length, int nMaxID = 0, const std::string& sPrefixForm = "");
int GetRotate(int nPageIndex);
int GetMaxRefID();
BYTE* GetWidgets();

View File

@ -565,7 +565,7 @@ bool CPdfReader::ValidMetaData()
oID.free(); oID2.free();
return bRes;
}
bool CPdfReader::MergePages(BYTE* pData, DWORD nLength, const std::wstring& wsPassword, int nMaxID)
bool CPdfReader::MergePages(BYTE* pData, DWORD nLength, const std::wstring& wsPassword, int nMaxID, const std::string& sPrefixForm)
{
if (m_eError)
return false;
@ -580,6 +580,7 @@ bool CPdfReader::MergePages(BYTE* pData, DWORD nLength, const std::wstring& wsPa
CPdfReaderContext* pContext = new CPdfReaderContext();
pContext->m_pDocument = new PDFDoc(str, owner_pswd, user_pswd);
pContext->m_pFontList = new PdfReader::CPdfFontList();
pContext->sPrefixForm = sPrefixForm;
if (nMaxID != 0)
pContext->m_nStartID = nMaxID;
else if (!m_vPDFContext.empty())
@ -603,7 +604,7 @@ bool CPdfReader::MergePages(BYTE* pData, DWORD nLength, const std::wstring& wsPa
return true;
}
bool CPdfReader::MergePages(const std::wstring& wsFile, const std::wstring& wsPassword, int nMaxID)
bool CPdfReader::MergePages(const std::wstring& wsFile, const std::wstring& wsPassword, int nMaxID, const std::string& sPrefixForm)
{
if (m_eError)
return false;
@ -615,9 +616,10 @@ bool CPdfReader::MergePages(const std::wstring& wsFile, const std::wstring& wsPa
CPdfReaderContext* pContext = new CPdfReaderContext();
pContext->m_pDocument = new PDFDoc((char*)sPathUtf8.c_str(), owner_pswd, user_pswd);
pContext->m_pFontList = new PdfReader::CPdfFontList();
pContext->sPrefixForm = sPrefixForm;
if (nMaxID != 0)
pContext->m_nStartID = nMaxID;
if (!m_vPDFContext.empty())
else if (!m_vPDFContext.empty())
pContext->m_nStartID = m_vPDFContext.back()->m_nStartID + m_vPDFContext.back()->m_pDocument->getXRef()->getNumObjects();
PDFDoc* pDoc = pContext->m_pDocument;
m_vPDFContext.push_back(pContext);
@ -1131,10 +1133,11 @@ BYTE* CPdfReader::GetWidgets()
NSWasm::CData oRes;
oRes.SkipLen();
std::map<std::string, std::string> mForms;
int nStartPage = 0;
for (CPdfReaderContext* pPDFContext : m_vPDFContext)
for (int iPDF = 0; iPDF < m_vPDFContext.size(); ++iPDF)
{
PDFDoc* pDoc = pPDFContext->m_pDocument;
PDFDoc* pDoc = m_vPDFContext[iPDF]->m_pDocument;
if (!pDoc || !pDoc->getCatalog())
continue;
if (!pDoc->getCatalog()->getForm() || !pDoc->getXRef())
@ -1143,9 +1146,35 @@ BYTE* CPdfReader::GetWidgets()
continue;
}
PdfReader::CAnnots* pAnnots = new PdfReader::CAnnots(pDoc, m_pFontManager, pPDFContext->m_pFontList, nStartPage, pPDFContext->m_nStartID);
PdfReader::CAnnots* pAnnots = new PdfReader::CAnnots(pDoc, m_pFontManager, m_vPDFContext[iPDF]->m_pFontList, nStartPage, m_vPDFContext[iPDF]->m_nStartID);
if (pAnnots)
{
const std::vector<PdfReader::CAnnotWidget*>& arrAnnots = pAnnots->GetAnnots();
for (int i = 0; i < arrAnnots.size(); ++i)
{
const std::string& sFullName = arrAnnots[i]->GetFullName();
std::map<std::string, std::string>::iterator it = mForms.find(sFullName);
if (it == mForms.end())
mForms[sFullName] = arrAnnots[i]->GetType();
else if (mForms[sFullName] != arrAnnots[i]->GetType())
{
if (iPDF == 0)
{
// error
// throw "Same full names for forms of different types within the same file";
}
else
{
int nPrefix = 0;
std::string sPrefix = m_vPDFContext[iPDF]->sPrefixForm + "_" + std::to_string(nPrefix);
while (!pAnnots->ChangeFullNameAnnot(i, sPrefix))
sPrefix = m_vPDFContext[iPDF]->sPrefixForm + "_" + std::to_string(++nPrefix);
}
}
}
pAnnots->ToWASM(oRes);
}
RELEASEOBJECT(pAnnots);
nStartPage += pDoc->getNumPages();
}

View File

@ -46,6 +46,7 @@ struct CPdfReaderContext
PDFDoc* m_pDocument;
PdfReader::CPdfFontList* m_pFontList;
unsigned int m_nStartID;
std::string sPrefixForm;
CPdfReaderContext() : m_pDocument(NULL), m_pFontList(NULL), m_nStartID(0) {}
CPdfReaderContext(PDFDoc* pDocument, PdfReader::CPdfFontList* pFontList, unsigned int nStartID) : m_pDocument(pDocument), m_pFontList(pFontList), m_nStartID(nStartID) {}
@ -77,8 +78,8 @@ public:
int GetMaxRefID();
int GetNumPages();
bool ValidMetaData();
bool MergePages(BYTE* pData, DWORD nLength, const std::wstring& wsPassword = L"", int nMaxID = 0);
bool MergePages(const std::wstring& wsFile, const std::wstring& wsPassword = L"", int nMaxID = 0);
bool MergePages(BYTE* pData, DWORD nLength, const std::wstring& wsPassword = L"", int nMaxID = 0, const std::string& sPrefixForm = "");
bool MergePages(const std::wstring& wsFile, const std::wstring& wsPassword = L"", int nMaxID = 0, const std::string& sPrefixForm = "");
void GetPageInfo(int nPageIndex, double* pdWidth, double* pdHeight, double* pdDpiX, double* pdDpiY);
void DrawPageOnRenderer(IRenderer* pRenderer, int nPageIndex, bool* pBreak);
std::wstring GetInfo();
@ -102,7 +103,7 @@ public:
BYTE* GetAPWidget (int nRasterW, int nRasterH, int nBackgroundColor, int nPageIndex, int nWidget = -1, const char* sView = NULL, const char* sBView = NULL);
BYTE* GetAPAnnots (int nRasterW, int nRasterH, int nBackgroundColor, int nPageIndex, int nAnnot = -1, const char* sView = NULL);
BYTE* GetButtonIcon(int nBackgroundColor, int nPageIndex, bool bBase64 = false, int nBWidget = -1, const char* sIView = NULL);
std::map<std::wstring, std::wstring> GetFonts() { return m_mFonts; }
const std::map<std::wstring, std::wstring>& GetFonts() { return m_mFonts; }
private:
void Clear();

View File

@ -1458,6 +1458,7 @@ CAnnotWidget::CAnnotWidget(PDFDoc* pdfDoc, AcroFormField* pField, int nStartRefI
oObj.free();
// 17 - Родитель - Parent
m_unRefNumParent = 0;
if (oField.dictLookupNF("Parent", &oObj)->isRef())
{
m_unRefNumParent = oObj.getRefNum() + nStartRefID;
@ -1467,6 +1468,7 @@ CAnnotWidget::CAnnotWidget(PDFDoc* pdfDoc, AcroFormField* pField, int nStartRefI
// 18 - Частичное имя поля - T
m_sT = DictLookupString(&oField, "T", 18);
m_sFullName = m_sT;
// 20 - OO метаданные форм - OMetadata
m_sOMetadata = DictLookupString(&oField, "OMetadata", 20);
@ -1510,8 +1512,7 @@ CAnnotWidget::CAnnotWidget(PDFDoc* pdfDoc, AcroFormField* pField, int nStartRefI
}
CAnnotWidget::~CAnnotWidget()
{
for (int i = 0; i < m_arrAction.size(); ++i)
RELEASEOBJECT(m_arrAction[i]);
ClearActions();
}
std::string CAnnotWidget::FieldLookupString(AcroFormField* pField, const char* sName, int nByte)
{
@ -1580,6 +1581,23 @@ void CAnnotWidget::SetButtonFont(PDFDoc* pdfDoc, AcroFormField* pField, NSFonts:
oFontRef.free();
}
bool CAnnotWidget::ChangeFullName(const std::string& sPrefixForm)
{
if (m_unFlags & (1 << 18))
{
m_sT += sPrefixForm;
m_sFullName += sPrefixForm;
// ClearActions();
return true;
}
return false;
}
void CAnnotWidget::ClearActions()
{
for (int i = 0; i < m_arrAction.size(); ++i)
RELEASEOBJECT(m_arrAction[i]);
m_arrAction.clear();
}
//------------------------------------------------------------------------
// Popup
@ -2485,6 +2503,21 @@ CAnnots::CAnnots(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CPdfFontLi
if (pField->getAcroFormFieldType() == acroFormFieldPushbutton)
pAnnot->SetButtonFont(pdfDoc, pField, pFontManager, pFontList);
pAnnot->SetPage(nStartPage + pField->getPageNum());
unsigned int unRefNumParent = pAnnot->GetRefNumParent();
if (unRefNumParent)
{
std::vector<CAnnotParent*>::iterator it = std::find_if(m_arrParents.begin(), m_arrParents.end(), [unRefNumParent](CAnnotParent* pP) { return pP->unRefNum == unRefNumParent; });
if (it != m_arrParents.end() && !((*it)->sFullName.empty()))
{
const std::string& sFullNameChild = pAnnot->GetFullName();
if (sFullNameChild.empty())
pAnnot->SetFullName((*it)->sFullName);
else
pAnnot->SetFullName((*it)->sFullName + "." + sFullNameChild);
}
}
m_arrAnnots.push_back(pAnnot);
}
}
@ -2521,6 +2554,7 @@ void CAnnots::getParents(PDFDoc* pdfDoc, Object* oFieldRef, int nStartRefID)
std::string sStr = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength());
pAnnotParent->unFlags |= (1 << 0);
pAnnotParent->sT = sStr;
pAnnotParent->sFullName = sStr;
delete s;
}
oObj.free();
@ -2673,11 +2707,75 @@ void CAnnots::getParents(PDFDoc* pdfDoc, Object* oFieldRef, int nStartRefID)
pAnnotParent->unFlags |= (1 << 4);
pAnnotParent->unRefNumParent = oParentRefObj.getRefNum() + nStartRefID;
getParents(pdfDoc, &oParentRefObj, nStartRefID);
unsigned int unRefNumParent = pAnnotParent->unRefNumParent;
std::vector<CAnnotParent*>::iterator it = std::find_if(m_arrParents.begin(), m_arrParents.end(), [unRefNumParent](CAnnotParent* pP) { return pP->unRefNum == unRefNumParent; });
if (it != m_arrParents.end() && !((*it)->sFullName.empty()))
{
if (pAnnotParent->sFullName.empty())
pAnnotParent->sFullName = (*it)->sFullName;
else
pAnnotParent->sFullName = (*it)->sFullName + "." + pAnnotParent->sFullName;
}
}
oParentRefObj.free();
oField.free();
}
bool CAnnots::ChangeFullNameAnnot(int nAnnot, const std::string& sPrefixForm)
{
if (nAnnot < 0 || nAnnot > m_arrAnnots.size())
return false;
CAnnotWidget* pWidget = m_arrAnnots[nAnnot];
if (pWidget->ChangeFullName(sPrefixForm))
return true;
unsigned int unRefNumParent = pWidget->GetRefNumParent();
if (unRefNumParent)
{
std::vector<CAnnotParent*>::iterator it = std::find_if(m_arrParents.begin(), m_arrParents.end(), [unRefNumParent](CAnnotParent* pP) { return pP->unRefNum == unRefNumParent; });
if (it != m_arrParents.end() && ChangeFullNameParent(std::distance(m_arrParents.begin(), it), sPrefixForm))
{
pWidget->AddFullName(sPrefixForm);
// pWidget->ClearActions();
return true;
}
}
return false;
}
bool CAnnots::ChangeFullNameParent(int nParent, const std::string& sPrefixForm)
{
if (nParent < 0 || nParent > m_arrParents.size())
return false;
CAnnotParent* pParent = m_arrParents[nParent];
if (pParent->unFlags & (1 << 0))
{
pParent->sT += sPrefixForm;
pParent->sFullName += sPrefixForm;
// pParent->ClearActions();
return true;
}
else if (pParent->unFlags & (1 << 4))
{
unsigned int unRefNumParent = pParent->unRefNumParent;
std::vector<CAnnotParent*>::iterator it = std::find_if(m_arrParents.begin(), m_arrParents.end(), [unRefNumParent](CAnnotParent* pP) { return pP->unRefNum == unRefNumParent; });
if (it != m_arrParents.end() && ChangeFullNameParent(std::distance(m_arrParents.begin(), it), sPrefixForm))
{
pParent->sFullName += sPrefixForm;
// pParent->ClearActions();
return true;
}
}
return false;
}
void CAnnots::CAnnotParent::ClearActions()
{
unFlags &= ~(1 << 8);
for (int i = 0; i < arrAction.size(); ++i)
RELEASEOBJECT(arrAction[i]);
arrAction.clear();
}
//------------------------------------------------------------------------
// Markup

View File

@ -219,12 +219,19 @@ public:
void SetFont(PDFDoc* pdfDoc, AcroFormField* pField, NSFonts::IFontManager* pFontManager, CPdfFontList *pFontList);
void SetButtonFont(PDFDoc* pdfDoc, AcroFormField* pField, NSFonts::IFontManager* pFontManager, CPdfFontList *pFontList);
unsigned int GetRefNumParent() { return m_unRefNumParent; }
const std::string& GetFullName() { return m_sFullName; }
void SetFullName(const std::string& sFullName) { m_sFullName = sFullName; }
void AddFullName(const std::string& sPrefixForm) { m_sFullName += sPrefixForm; }
bool ChangeFullName(const std::string& sPrefixForm);
void ClearActions();
virtual std::string GetType() = 0;
virtual void ToWASM(NSWasm::CData& oRes) override;
protected:
CAnnotWidget(PDFDoc* pdfDoc, AcroFormField* pField, int nStartRefID);
std::string FieldLookupString(AcroFormField* pField, const char* sName, int nByte);
virtual void ToWASM(NSWasm::CData& oRes) override;
BYTE m_nType; // Тип - FT + флаги
unsigned int m_unFieldFlag; // Флаг - Ff
@ -245,6 +252,7 @@ private:
std::string m_sDV; // Значение по-умолчанию - DV
std::string m_sT; // Частичное имя поля - T
std::string m_sFontKey; // Уникальный идентификатор шрифта
std::string m_sFullName; // Полное имя поля
std::string m_sFontName; // Имя шрифта - из DA
std::string m_sOMetadata; // OO метаданные формы
std::string m_sActualFontName; // Имя замененного шрифта
@ -255,6 +263,7 @@ class CAnnotWidgetBtn final : public CAnnotWidget
{
public:
CAnnotWidgetBtn(PDFDoc* pdfDoc, AcroFormField* pField, int nStartRefID);
virtual std::string GetType() override { return "Btn"; }
void ToWASM(NSWasm::CData& oRes) override;
private:
@ -275,6 +284,7 @@ class CAnnotWidgetTx final : public CAnnotWidget
{
public:
CAnnotWidgetTx(PDFDoc* pdfDoc, AcroFormField* pField, int nStartRefID);
virtual std::string GetType() override { return "Tx"; }
void ToWASM(NSWasm::CData& oRes) override;
private:
@ -287,6 +297,7 @@ class CAnnotWidgetCh final : public CAnnotWidget
{
public:
CAnnotWidgetCh(PDFDoc* pdfDoc, AcroFormField* pField, int nStartRefID);
virtual std::string GetType() override { return "Ch"; }
void ToWASM(NSWasm::CData& oRes) override;
private:
@ -301,6 +312,7 @@ class CAnnotWidgetSig final : public CAnnotWidget
{
public:
CAnnotWidgetSig(PDFDoc* pdfDoc, AcroFormField* pField, int nStartRefID);
virtual std::string GetType() override { return "Sig"; }
void ToWASM(NSWasm::CData& oRes) override;
};
@ -595,6 +607,9 @@ public:
~CAnnots();
void ToWASM(NSWasm::CData& oRes);
bool ChangeFullNameAnnot(int nAnnot, const std::string& sPrefixForm);
bool ChangeFullNameParent(int nParent, const std::string& sPrefixForm);
const std::vector<CAnnotWidget*>& GetAnnots() { return m_arrAnnots; }
private:
struct CAnnotParent final
@ -605,6 +620,11 @@ private:
unRefNum = 0;
unRefNumParent = 0;
}
~CAnnotParent()
{
ClearActions();
}
void ClearActions();
void ToWASM(NSWasm::CData& oRes);
@ -619,13 +639,14 @@ private:
std::string sT;
std::string sV;
std::string sDV;
std::string sFullName;
};
void getParents(PDFDoc* pdfDoc, Object* oFieldRef, int nStartRefID);
std::vector<int> m_arrCO; // Порядок вычислений - CO
std::vector<CAnnotParent*> m_arrParents; // Родительские Fields
std::vector<CAnnot*> m_arrAnnots;
std::vector<CAnnotWidget*> m_arrAnnots;
};
//------------------------------------------------------------------------