/* * (c) Copyright Ascensio System SIA 2010-2023 * * This program is a free software product. You can redistribute it and/or * modify it under the terms of the GNU Affero General Public License (AGPL) * version 3 as published by the Free Software Foundation. In accordance with * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect * that Ascensio System SIA expressly excludes the warranty of non-infringement * of any third-party rights. * * This program is distributed WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html * * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish * street, Riga, Latvia, EU, LV-1050. * * The interactive user interfaces in modified source and object code versions * of the Program must display Appropriate Legal Notices, as required under * Section 5 of the GNU AGPL version 3. * * Pursuant to Section 7(b) of the License you must retain the original Product * logo when distributing the program. Pursuant to Section 7(e) we decline to * grant you any rights under trademark law for use of our trademarks. * * All the Product's GUI elements, including illustrations and icon sets, as * well as technical writing content are licensed under the terms of the * Creative Commons Attribution-ShareAlike 4.0 International. See the License * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode * */ #include "PdfAnnot.h" #include "RendererOutputDev.h" #include "Adaptors.h" #include "../lib/xpdf/TextString.h" #include "../lib/xpdf/Link.h" #include "../lib/xpdf/Annot.h" #include "../lib/xpdf/GfxFont.h" #include "../lib/xpdf/Lexer.h" #include "../lib/xpdf/Parser.h" #include "../lib/goo/GList.h" #include "../Resources/BaseFonts.h" #include "../../DesktopEditor/common/Types.h" #include "../../DesktopEditor/common/StringExt.h" #include "../../DesktopEditor/xml/include/xmlutils.h" #include "../../DesktopEditor/fontengine/ApplicationFonts.h" #include "../../DesktopEditor/graphics/pro/Fonts.h" #include namespace PdfReader { double ArrGetNum(Object* pArr, int nI) { double dRes = 0.0; Object oObj; if (pArr->arrayGet(nI, &oObj)->isNum()) dRes = oObj.getNum(); oObj.free(); return dRes; } TextString* getFullFieldName(Object* oField) { TextString* sResName = NULL; if (!oField || !oField->isDict()) return sResName; Object oName; if (oField->dictLookup("T", &oName)->isString()) sResName = new TextString(oName.getString()); else { oName.free(); return sResName; } oName.free(); Object oParent, oParent2; oField->dictLookup("Parent", &oParent); int nDepth = 0; while (oParent.isDict() && nDepth < 50) { if (oParent.dictLookup("T", &oName)->isString()) { if (sResName->getLength()) sResName->insert(0, (Unicode)'.'); sResName->insert(0, oName.getString()); } oName.free(); oParent.dictLookup("Parent", &oParent2); oParent.free(); oParent = oParent2; ++nDepth; } oParent.free(); return sResName; } CAction* getAction(PDFDoc* pdfDoc, Object* oAction) { Object oActType; std::string sSName; if (oAction->dictLookup("S", &oActType)->isName()) sSName = oActType.getName(); oActType.free(); LinkAction* oAct = LinkAction::parseAction(oAction); if (!oAct) return NULL; CAction* pRes = NULL; LinkActionKind kind = oAct->getKind(); switch (kind) { // Переход внутри файла case actionGoTo: { GString* str = ((LinkGoTo*)oAct)->getNamedDest(); LinkDest* pLinkDest = str ? pdfDoc->findDest(str) : ((LinkGoTo*)oAct)->getDest(); if (!pLinkDest) break; CActionGoTo* ppRes = new CActionGoTo(); if (pLinkDest->isPageRef()) { Ref pageRef = pLinkDest->getPageRef(); ppRes->unPage = pdfDoc->findPage(pageRef.num, pageRef.gen); } else ppRes->unPage = pLinkDest->getPageNum(); if (ppRes->unPage > 0) --ppRes->unPage; ppRes->nKind = pLinkDest->getKind(); PDFRectangle* pCropBox = pdfDoc->getCatalog()->getPage(ppRes->unPage + 1)->getCropBox(); double dHeight = pCropBox->y2; double dX = pCropBox->x1; switch (ppRes->nKind) { case destXYZ: case destFitH: case destFitBH: case destFitV: case destFitBV: { ppRes->unKindFlag = 0; // 0 - left if (pLinkDest->getChangeLeft()) { ppRes->unKindFlag |= (1 << 0); ppRes->pRect[0] = pLinkDest->getLeft() - dX; } // 1 - top if (pLinkDest->getChangeTop()) { ppRes->unKindFlag |= (1 << 1); ppRes->pRect[1] = dHeight - pLinkDest->getTop(); } // 2 - zoom if (pLinkDest->getChangeZoom() && pLinkDest->getZoom()) { ppRes->unKindFlag |= (1 << 2); ppRes->pRect[2] = pLinkDest->getZoom(); } break; } case destFitR: { ppRes->pRect[0] = pLinkDest->getLeft() - dX; ppRes->pRect[1] = dHeight - pLinkDest->getTop(); ppRes->pRect[2] = pLinkDest->getRight() - dX; ppRes->pRect[3] = dHeight - pLinkDest->getBottom(); break; } case destFit: case destFitB: default: break; } if (str) RELEASEOBJECT(pLinkDest); pRes = ppRes; break; } // Переход к внешнему файлу case actionGoToR: { break; } // Запуск стороннего приложения case actionLaunch: { break; } // Внешняя ссылка case actionURI: { CActionURI* ppRes = new CActionURI(); TextString* s = new TextString(((LinkURI*)oAct)->getURI()); ppRes->sURI = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength()); delete s; pRes = ppRes; break; } // Нестандартно именованные действия case actionNamed: { CActionNamed* ppRes = new CActionNamed(); TextString* s = new TextString(((LinkNamed*)oAct)->getName()); ppRes->sNamed = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength()); delete s; pRes = ppRes; break; } // Воспроизведение фильма case actionMovie: { break; } // JavaScript case actionJavaScript: { CActionJavaScript* ppRes = new CActionJavaScript(); TextString* s = new TextString(((LinkJavaScript*)oAct)->getJS()); ppRes->sJavaScript = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength()); delete s; pRes = ppRes; break; } // Отправка формы case actionSubmitForm: { break; } // Скрытие аннотаций case actionHide: { CActionHide* ppRes = new CActionHide(); ppRes->bHideFlag = ((LinkHide*)oAct)->getHideFlag(); Object* oHideObj = ((LinkHide*)oAct)->getFields(); int nHide = 1, k = 0; if (oHideObj->isArray()) nHide = oHideObj->arrayGetLength(); Object oHide; oHideObj->copy(&oHide); do { TextString* s = NULL; if (oHideObj->isArray()) { oHide.free(); oHideObj->arrayGet(k, &oHide); } if (oHide.isString()) s = new TextString(oHide.getString()); else if (oHide.isDict()) s = getFullFieldName(&oHide); if (s) { std::string sStr = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength()); ppRes->arrAnnotName.push_back(sStr); delete s; } k++; } while (k < nHide); oHide.free(); pRes = ppRes; break; } // Неизвестное действие case actionUnknown: default: { if (sSName == "ResetForm") { CActionResetForm* ppRes = new CActionResetForm(); Object oObj; if (oAction->dictLookup("Flags", &oObj)->isInt()) ppRes->unFlags = oObj.getInt(); oObj.free(); if (oAction->dictLookup("Fields", &oObj)->isArray()) { for (int j = 0; j < oObj.arrayGetLength(); ++j) { Object oField; oObj.arrayGet(j, &oField); TextString* s = NULL; if (oField.isString()) s = new TextString(oField.getString()); else if (oField.isDict()) s = getFullFieldName(&oField); if (s) { std::string sStr = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength()); ppRes->arrAnnotName.push_back(sStr); delete s; } oField.free(); } } oObj.free(); pRes = ppRes; } break; } } if (pRes) pRes->pNext = NULL; Object oNextAction; if (pRes && oAction->dictLookup("Next", &oNextAction)->isDict()) pRes->pNext = getAction(pdfDoc, &oNextAction); oNextAction.free(); RELEASEOBJECT(oAct); return pRes; }; std::string getValue(Object* oV, bool bArray = true) { std::string sRes; if (oV->isName()) sRes = oV->getName(); else if (oV->isString() || oV->isDict() || oV->isArray()) { TextString* s = NULL; if (oV->isString()) s = new TextString(oV->getString()); else if (oV->isDict()) { Object oContents; if (oV->dictLookup("Contents", &oContents)->isString()) s = new TextString(oContents.getString()); oContents.free(); } else if (bArray && oV->isArray()) { Object oContents; if (oV->arrayGet(0, &oContents)->isString()) s = new TextString(oContents.getString()); oContents.free(); } if (s) { sRes = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength()); delete s; } } return sRes; } void DrawAppearance(PDFDoc* pdfDoc, int nPage, AcroFormField* pField, Gfx* gfx, const char* sAPName, const char* sASName) { XRef* xref = pdfDoc->getXRef(); Object oFieldRef, oField; pField->getFieldRef(&oFieldRef); oFieldRef.fetch(xref, &oField); Object kidsObj, annotRef, annotObj; if (oField.dictLookup("Kids", &kidsObj)->isArray()) { for (int j = 0; j < kidsObj.arrayGetLength(); ++j) { kidsObj.arrayGetNF(j, &annotRef); annotRef.fetch(xref, &annotObj); pField->drawAnnot(nPage, gfx, gFalse, &annotRef, &annotObj, sAPName, sASName, gFalse); annotObj.free(); annotRef.free(); } } else pField->drawAnnot(nPage, gfx, gFalse, &oFieldRef, &oField, sAPName, sASName, gFalse); kidsObj.free(); oFieldRef.free(); oField.free(); } BYTE getLE(Object* oObj) { BYTE nLE = 5; // None if (oObj->isName("Square")) nLE = 0; else if (oObj->isName("Circle")) nLE = 1; else if (oObj->isName("Diamond")) nLE = 2; else if (oObj->isName("OpenArrow")) nLE = 3; else if (oObj->isName("ClosedArrow")) nLE = 4; else if (oObj->isName("Butt")) nLE = 6; else if (oObj->isName("ROpenArrow")) nLE = 7; else if (oObj->isName("RClosedArrow")) nLE = 8; else if (oObj->isName("Slash")) nLE = 9; return nLE; } CAnnotFileAttachment::CEmbeddedFile* getEF(Object* oObj) { CAnnotFileAttachment::CEmbeddedFile* pRes = new CAnnotFileAttachment::CEmbeddedFile(); Object oObj2; Dict* pImDict = oObj->streamGetDict(); if (pImDict->lookup("Length", &oObj2)->isInt()) pRes->nLength = oObj2.getInt(); oObj2.free(); if (pImDict->lookup("DL", &oObj2)->isInt()) pRes->nLength = oObj2.getInt(); oObj2.free(); Stream* pFile = oObj->getStream(); pFile->reset(); pRes->pFile = new BYTE[pRes->nLength]; BYTE* pBufferPtr = pRes->pFile; for (int nI = 0; nI < pRes->nLength; ++nI) *pBufferPtr++ = (BYTE)pFile->getChar(); return pRes; } GList* tokenize(GString *s) { GList *toks; int i, j; toks = new GList(); i = 0; while (i < s->getLength()) { while (i < s->getLength() && Lexer::isSpace(s->getChar(i))) { ++i; } if (i < s->getLength()) { for (j = i + 1; j < s->getLength() && !Lexer::isSpace(s->getChar(j)); ++j) ; toks->append(new GString(s, i, j - i)); i = j; } } return toks; } CAnnot::CBorderType* getBorder(Object* oBorder, bool bBSorBorder) { // Границы и Dash Pattern - Border/BS CAnnot::CBorderType* pBorderType = new CAnnot::CBorderType(); if (!oBorder) return pBorderType; if (bBSorBorder) { pBorderType->nType = annotBorderSolid; Object oV; if (oBorder->dictLookup("S", &oV)->isName()) { if (oV.isName("S")) pBorderType->nType = annotBorderSolid; else if (oV.isName("D")) pBorderType->nType = annotBorderDashed; else if (oV.isName("B")) pBorderType->nType = annotBorderBeveled; else if (oV.isName("I")) pBorderType->nType = annotBorderInset; else if (oV.isName("U")) pBorderType->nType = annotBorderUnderlined; } oV.free(); if (oBorder->dictLookup("W", &oV)->isNum()) pBorderType->dWidth = oV.getNum(); oV.free(); if (oBorder->dictLookup("D", &oV)->isArray()) { for (int j = 0; j < oV.arrayGetLength(); ++j) { Object oObj2; if (oV.arrayGet(j, &oObj2)->isNum()) pBorderType->arrDash.push_back(oObj2.getNum()); oObj2.free(); } } oV.free(); } else { pBorderType->nType = annotBorderSolid; pBorderType->dWidth = ArrGetNum(oBorder, 2); if (!pBorderType->dWidth) pBorderType->dWidth = 1.0; Object oObj; if (oBorder->arrayGetLength() > 3 && oBorder->arrayGet(3, &oObj)->isArray() && oObj.arrayGetLength() > 1) { pBorderType->nType = annotBorderDashed; for (int j = 0; j < oObj.arrayGetLength(); ++j) { Object oObj2; if (oObj.arrayGet(j, &oObj2)->isNum()) pBorderType->arrDash.push_back(oObj2.getNum()); oObj2.free(); } } oObj.free(); } return pBorderType; } std::string GetRCFromDS(const std::string& sDS, Object* pContents, const std::vector& arrCFromDA) { NSStringUtils::CStringBuilder oRC; oRC += L"

"; TextString* s = new TextString(pContents->getString()); std::wstring wsContents = NSStringExt::CConverter::GetUnicodeFromUTF32(s->getUnicode(), s->getLength()); delete s; oRC.WriteEncodeXmlString(wsContents); oRC += L"

"; std::wstring wsRC = oRC.GetData(); return U_TO_UTF8(wsRC); } //------------------------------------------------------------------------ // Fonts //------------------------------------------------------------------------ bool CAnnotFonts::IsBaseFont(const std::wstring& wsName) { return wsName == L"Courier" || wsName == L"Courier-Bold" || wsName == L"Courier-BoldOblique" || wsName == L"Courier-Oblique" || wsName == L"Helvetica" || wsName == L"Helvetica-Bold" || wsName == L"Helvetica-BoldOblique" || wsName == L"Helvetica-Oblique" || wsName == L"Symbol" || wsName == L"Times-Bold" || wsName == L"Times-BoldItalic" || wsName == L"Times-Italic" || wsName == L"Times-Roman" || wsName == L"ZapfDingbats"; } std::map CAnnotFonts::GetAllFonts(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CPdfFontList* pFontList, bool bIsNeedCMap) { std::map mFonts; AcroForm* pAcroForms = pdfDoc->getCatalog()->getForm(); if (pAcroForms) { std::vector arrUniqueFontsRef; for (int nField = 0, nNum = pAcroForms->getNumFields(); nField < nNum; ++nField) { AcroFormField* pField = pAcroForms->getField(nField); if (!pField) continue; // Шрифт и размер шрифта - из DA Ref fontID; double dFontSize = 0; pField->getFont(&fontID, &dFontSize); Object oFontRef; if (fontID.num < 0) { std::string sFontKey; if (!GetFontFromAP(pdfDoc, pField, &oFontRef, sFontKey)) { oFontRef.free(); continue; } } else oFontRef.initRef(fontID.num, fontID.gen); if (std::find(arrUniqueFontsRef.begin(), arrUniqueFontsRef.end(), oFontRef.getRefNum()) != arrUniqueFontsRef.end()) { oFontRef.free(); continue; } std::string sFontName; std::string sActualFontName; std::wstring wsFileName; bool bBold = false, bItalic = false; wsFileName = GetFontData(pdfDoc, pFontManager, pFontList, &oFontRef, sFontName, sActualFontName, bBold, bItalic, bIsNeedCMap); if (!sActualFontName.empty()) { oFontRef.free(); continue; } if (!sFontName.empty()) { std::wstring wsFontName = UTF8_TO_U(sFontName); if (mFonts.find(wsFontName) == mFonts.end()) { arrUniqueFontsRef.push_back(oFontRef.getRefNum()); mFonts[wsFontName] = wsFileName; } } oFontRef.free(); if (pField->getAcroFormFieldType() == acroFormFieldPushbutton && fontID.num >= 0) { std::string sFontKey; if (GetFontFromAP(pdfDoc, pField, &oFontRef, sFontKey) && std::find(arrUniqueFontsRef.begin(), arrUniqueFontsRef.end(), oFontRef.getRefNum()) == arrUniqueFontsRef.end()) { wsFileName = GetFontData(pdfDoc, pFontManager, pFontList, &oFontRef, sFontName, sActualFontName, bBold, bItalic, bIsNeedCMap); std::wstring wsFontName = UTF8_TO_U(sFontName); if (sActualFontName.empty() && mFonts.find(wsFontName) == mFonts.end()) { arrUniqueFontsRef.push_back(oFontRef.getRefNum()); mFonts[wsFontName] = wsFileName; } } } oFontRef.free(); } } for (int nPage = 0, nLastPage = pdfDoc->getNumPages(); nPage < nLastPage; ++nPage) { Page* pPage = pdfDoc->getCatalog()->getPage(nPage + 1); if (!pPage) continue; Object oAnnots; if (!pPage->getAnnots(&oAnnots)->isArray()) { oAnnots.free(); continue; } for (int i = 0, nNum = oAnnots.arrayGetLength(); i < nNum; ++i) { Object oAnnot; if (!oAnnots.arrayGet(i, &oAnnot)->isDict()) { oAnnot.free(); continue; } Object oSubtype; if (!oAnnot.dictLookup("Subtype", &oSubtype)->isName("FreeText")) { oSubtype.free(); oAnnot.free(); continue; } oSubtype.free(); std::string sRC; Object oObj; if (!oAnnot.dictLookup("RC", &oObj)->isString()) { oObj.free(); if (oAnnot.dictLookup("Contents", &oObj)->isString() && oObj.getString()->getLength()) { std::string sDS; Object oObj2; if (oAnnot.dictLookup("DS", &oObj2)->isString()) { TextString* s = new TextString(oObj2.getString()); sDS = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength()); delete s; } oObj2.free(); sRC = GetRCFromDS(sDS, &oObj, {}); if (sRC.find("font-family:Helvetica") != std::string::npos) { const unsigned char* pData14 = NULL; unsigned int nSize14 = 0; std::wstring wsFontName = L"Helvetica"; NSFonts::IFontsMemoryStorage* pMemoryStorage = NSFonts::NSApplicationFontStream::GetGlobalMemoryStorage(); if (pMemoryStorage && !pMemoryStorage->Get(wsFontName) && GetBaseFont(wsFontName, pData14, nSize14)) pMemoryStorage->Add(wsFontName, (BYTE*)pData14, nSize14, false); mFonts[L"Helvetica"] = L"Helvetica"; } } } else { TextString* s = new TextString(oObj.getString()); sRC = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength()); delete s; } oObj.free(); oAnnot.free(); Object oAnnotRef; oAnnots.arrayGetNF(i, &oAnnotRef); std::vector arrRC = CAnnotMarkup::ReadRC(sRC); std::map mFreeText = GetFreeTextFont(pdfDoc, pFontManager, pFontList, &oAnnotRef, arrRC); for (std::map::iterator it = mFreeText.begin(); it != mFreeText.end(); ++it) { if (mFonts.find(it->first) != mFonts.end()) continue; mFonts[it->first] = it->second; } oAnnotRef.free(); for (int j = 0; j < arrRC.size(); ++j) RELEASEOBJECT(arrRC[j]); } oAnnots.free(); } return mFonts; } std::wstring CAnnotFonts::GetFontData(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CPdfFontList *pFontList, Object* oFontRef, std::string& sFontName, std::string& sActualFontName, bool& bBold, bool& bItalic, bool bIsNeedCMap) { bBold = false, bItalic = false; XRef* xref = pdfDoc->getXRef(); Object oFont; if (!xref->fetch(oFontRef->getRefNum(), oFontRef->getRefGen(), &oFont)->isDict()) { oFont.free(); return L""; } GfxFont* gfxFont = GfxFont::makeFont(xref, "F", oFontRef->getRef(), oFont.getDict()); oFont.free(); if (!gfxFont) return L""; Ref oEmbRef; std::wstring wsFontBaseName = NSStrings::GetStringFromUTF32(gfxFont->getName()); std::wstring wsFileName; if (gfxFont->getEmbeddedFontID(&oEmbRef) || IsBaseFont(wsFontBaseName)) { std::wstring wsFontName; RendererOutputDev::GetFont(xref, pFontManager, pFontList, gfxFont, wsFileName, wsFontName); sFontName = U_TO_UTF8(wsFontName); RendererOutputDev::CheckFontStylePDF(wsFontName, bBold, bItalic); if (!bBold) bBold = gfxFont->isBold(); if (!bItalic) bItalic = gfxFont->isItalic(); } else { std::wstring wsFBN = wsFontBaseName; NSFonts::CFontInfo* pFontInfo = RendererOutputDev::GetFontByParams(xref, pFontManager, gfxFont, wsFBN); if (pFontInfo && !pFontInfo->m_wsFontPath.empty()) { if (wsFontBaseName.length() > 7 && wsFontBaseName.at(6) == '+') { bool bIsRemove = true; for (int nIndex = 0; nIndex < 6; nIndex++) { wchar_t nChar = wsFontBaseName.at(nIndex); if (nChar < 'A' || nChar > 'Z') { bIsRemove = false; break; } } if (bIsRemove) wsFontBaseName.erase(0, 7); } wsFileName = pFontInfo->m_wsFontPath; sFontName = U_TO_UTF8(wsFontBaseName); sActualFontName = U_TO_UTF8(pFontInfo->m_wsFontName); bBold = pFontInfo->m_bBold; bItalic = pFontInfo->m_bItalic; } } RELEASEOBJECT(gfxFont); return wsFileName; } bool CAnnotFonts::GetFontFromAP(PDFDoc* pdfDoc, AcroFormField* pField, Object* oFontRef, std::string& sFontKey) { bool bFindResources = false; Object oAP, oN; XRef* xref = pdfDoc->getXRef(); if (pField->fieldLookup("AP", &oAP)->isDict() && oAP.dictLookup("N", &oN)->isStream()) { Parser* parser = new Parser(xref, new Lexer(xref, &oN), gFalse); bool bFindFont = false; Object oObj1, oObj2, oObj3; parser->getObj(&oObj1); while (!oObj1.isEOF()) { if (oObj1.isName()) { parser->getObj(&oObj2); if (oObj2.isEOF()) break; if (oObj2.isNum()) { parser->getObj(&oObj3); if (oObj3.isEOF()) break; if (oObj3.isCmd("Tf")) { bFindFont = true; break; } } } if (oObj2.isName()) { oObj1.free(); oObj2.copy(&oObj1); oObj2.free(); oObj3.free(); continue; } if (oObj3.isName()) { oObj1.free(); oObj3.copy(&oObj1); oObj3.free(); oObj2.free(); continue; } oObj1.free(); oObj2.free(); oObj3.free(); parser->getObj(&oObj1); } if (bFindFont && oObj1.isName()) { Object oR, oFonts; bFindResources = oN.streamGetDict()->lookup("Resources", &oR)->isDict() && oR.dictLookup("Font", &oFonts)->isDict() && oFonts.dictLookupNF(oObj1.getName(), oFontRef)->isRef(); sFontKey = oObj1.getName(); oR.free(); oFonts.free(); } oObj1.free(); oObj2.free(); oObj3.free(); RELEASEOBJECT(parser); } oAP.free(); oN.free(); return bFindResources; } bool CAnnotFonts::FindFonts(Object* oStream, int nDepth, Object* oResFonts) { if (nDepth > 5) return false; Object oResources; if (!oStream->streamGetDict()->lookup("Resources", &oResources)->isDict()) { oResources.free(); return false; } if (oResources.dictLookup("Font", oResFonts)->isDict()) { oResources.free(); return true; } Object oXObject; if (oResources.dictLookup("XObject", &oXObject)->isDict()) { for (int i = 0, nLength = oXObject.dictGetLength(); i < nLength; ++i) { Object oXObj; if (!oXObject.dictGetVal(i, &oXObj)->isStream()) { oXObj.free(); continue; } if (FindFonts(&oXObj, nDepth + 1, oResFonts)) { oXObj.free(); oXObject.free(); oResources.free(); return true; } oXObj.free(); } } oXObject.free(); oResources.free(); return false; } std::map CAnnotFonts::GetAnnotFont(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CPdfFontList *pFontList, Object* oAnnotRef) { Object oAnnot, oObj; XRef* pXref = pdfDoc->getXRef(); oAnnotRef->fetch(pXref, &oAnnot); std::map mFontFreeText; Object oAP, oN; if (!oAnnot.dictLookup("AP", &oAP)->isDict() || !oAP.dictLookup("N", &oN)->isStream()) { oAP.free(); oN.free(); oAnnot.free(); return mFontFreeText; } oAP.free(); Object oFonts; if (!FindFonts(&oN, 0, &oFonts)) { oN.free(); oFonts.free(); oAnnot.free(); return mFontFreeText; } oN.free(); CFontList* pAppFontList = (CFontList*)pFontManager->GetApplication()->GetList(); NSFonts::IFontsMemoryStorage* pMemoryStorage = NSFonts::NSApplicationFontStream::GetGlobalMemoryStorage(); for (int i = 0, nFonts = oFonts.dictGetLength(); i < nFonts; ++i) { Object oFontRef; if (!oFonts.dictGetValNF(i, &oFontRef)->isRef()) { oFontRef.free(); continue; } std::string sFontName, sActualFontName; bool bBold = false, bItalic = false; std::wstring sFontPath = GetFontData(pdfDoc, pFontManager, pFontList, &oFontRef, sFontName, sActualFontName, bBold, bItalic); oFontRef.free(); if (sFontPath.empty() || IsBaseFont(sFontPath) || !sActualFontName.empty()) continue; std::wstring wsFontName = UTF8_TO_U(sFontName); NSFonts::IFontStream* pFontStream = NULL; bool bRemoveStream = false; if (pMemoryStorage) pFontStream = (NSFonts::IFontStream*)pMemoryStorage->Get(sFontPath); else { pFontStream = NSFonts::NSStream::Create(); pFontStream->CreateFromFile(sFontPath); bRemoveStream = true; } if (pFontStream) { bool bNew = true; std::vector* arrFontList = pAppFontList->GetFonts(); for (int nIndex = 0; nIndex < arrFontList->size(); ++nIndex) { if (((*arrFontList)[nIndex]->m_wsFontPath == sFontPath || (*arrFontList)[nIndex]->m_wsFontName == wsFontName) && (*arrFontList)[nIndex]->m_bBold == (bBold ? 1 : 0) && (*arrFontList)[nIndex]->m_bItalic == (bItalic ? 1 : 0)) { bNew = false; break; } } if (bNew) pAppFontList->Add(sFontPath, pFontStream); } if (bRemoveStream) RELEASEINTERFACE(pFontStream); mFontFreeText[wsFontName] = sFontPath; } oFonts.free(); oAnnot.free(); return mFontFreeText; } std::map CAnnotFonts::GetFreeTextFont(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CPdfFontList* pFontList, Object* oAnnotRef, std::vector& arrRC) { std::map mRes; std::map mFontFreeText = GetAnnotFont(pdfDoc, pFontManager, pFontList, oAnnotRef); CFontList* pAppFontList = (CFontList*)pFontManager->GetApplication()->GetList(); for (int i = 0; i < arrRC.size(); ++i) { if (arrRC[i]->bFind) continue; std::string sFontName = arrRC[i]->sFontFamily; std::wstring wsFontName = UTF8_TO_U(sFontName); bool bBold = (bool)((arrRC[i]->unFontFlags >> 0) & 1); bool bItalic = (bool)((arrRC[i]->unFontFlags >> 1) & 1); if (IsBaseFont(wsFontName)) { if (sFontName == "Times-Roman") { if (bBold && bItalic) sFontName = "Times-BoldItalic"; else if (bBold) sFontName = "Times-Bold"; else if (bItalic) sFontName = "Times-Italic"; } else if (sFontName == "Courier" || sFontName == "Helvetica") { if (bBold && bItalic) sFontName += "-BoldOblique"; else if (bBold) sFontName += "-Bold"; else if (bItalic) sFontName += "-Oblique"; } wsFontName = UTF8_TO_U(sFontName); const unsigned char* pData14 = NULL; unsigned int nSize14 = 0; NSFonts::IFontsMemoryStorage* pMemoryStorage = NSFonts::NSApplicationFontStream::GetGlobalMemoryStorage(); if (pMemoryStorage && !pMemoryStorage->Get(wsFontName) && GetBaseFont(wsFontName, pData14, nSize14)) pMemoryStorage->Add(wsFontName, (BYTE*)pData14, nSize14, false); std::string sFontNameBefore = arrRC[i]->sFontFamily; arrRC[i]->sFontFamily = sFontName; arrRC[i]->bFind = true; mRes[wsFontName] = wsFontName; for (int j = i; j < arrRC.size(); ++j) { if (arrRC[j]->sFontFamily == sFontNameBefore && bBold == (bool)((arrRC[j]->unFontFlags >> 0) & 1) && bItalic == (bool)((arrRC[j]->unFontFlags >> 1) & 1)) { arrRC[j]->sFontFamily = sFontName; arrRC[j]->bFind = true; } } } else { NSFonts::CFontSelectFormat oFontSelect; if (bBold) oFontSelect.bBold = new INT(1); if (bItalic) oFontSelect.bItalic = new INT(1); oFontSelect.wsName = new std::wstring(wsFontName); NSFonts::CFontInfo* pFontInfo = pAppFontList->GetByParams(oFontSelect); if (pFontInfo && !pFontInfo->m_wsFontPath.empty()) { std::wstring sFontPath = pFontInfo->m_wsFontPath; bool bFindFreeText = false; for (std::map::iterator it = mFontFreeText.begin(); it != mFontFreeText.end(); ++it) { if (it->second == sFontPath) { bFindFreeText = true; break; } } std::wstring wsFontBaseName = pFontInfo->m_wsFontName; if (wsFontBaseName.length() > 7 && wsFontBaseName.at(6) == '+') { bool bIsRemove = true; for (int nIndex = 0; nIndex < 6; nIndex++) { wchar_t nChar = wsFontBaseName.at(nIndex); if (nChar < 'A' || nChar > 'Z') { bIsRemove = false; break; } } if (bIsRemove) wsFontBaseName.erase(0, 7); } if (bFindFreeText) { arrRC[i]->sFontFamily = U_TO_UTF8(wsFontBaseName); mRes[wsFontBaseName] = pFontInfo->m_wsFontPath; } else { arrRC[i]->unFontFlags |= (1 << 6); arrRC[i]->sActualFont = U_TO_UTF8(wsFontBaseName); } arrRC[i]->bFind = true; std::string sFontNameNew = bFindFreeText ? arrRC[i]->sFontFamily : arrRC[i]->sActualFont; for (int j = i; j < arrRC.size(); ++j) { if (arrRC[j]->sFontFamily == sFontName && bBold == (bool)((arrRC[j]->unFontFlags >> 0) & 1) && bItalic == (bool)((arrRC[j]->unFontFlags >> 1) & 1)) { if (bFindFreeText) arrRC[j]->sFontFamily = sFontNameNew; else { arrRC[j]->unFontFlags |= (1 << 6); arrRC[j]->sActualFont = sFontNameNew; } arrRC[j]->bFind = true; } } } } } return mRes; } //------------------------------------------------------------------------ // Widget //------------------------------------------------------------------------ CAnnotWidgetBtn::CAnnotWidgetBtn(PDFDoc* pdfDoc, AcroFormField* pField, int nStartRefID) : CAnnotWidget(pdfDoc, pField, nStartRefID) { m_unIFFlag = 0; Object oObj; Object oFieldRef, oField; pField->getFieldRef(&oFieldRef); oFieldRef.fetch(pdfDoc->getXRef(), &oField); oFieldRef.free(); // 9 - Значение поля - V if (oField.dictLookup("V", &oObj)) { m_sV = getValue(&oObj); if (!m_sV.empty()) m_unFlags |= (1 << 9); } oObj.free(); oField.free(); if (pField->fieldLookup("AS", &oObj)->isName()) { m_sV = oObj.getName(); m_unFlags |= (1 << 9); } oObj.free(); Object oMK; AcroFormFieldType oType = pField->getAcroFormFieldType(); m_nStyle = (oType == acroFormFieldRadioButton ? 3 : 0); if (pField->fieldLookup("MK", &oMK)->isDict()) { if (oType == acroFormFieldPushbutton) { // 10 - Заголовок - СА m_sCA = DictLookupString(&oMK, "CA", 10); // 11 - Заголовок прокрутки - RC m_sRC = DictLookupString(&oMK, "RC", 11); // 12 - Альтернативный заголовок - AC m_sAC = DictLookupString(&oMK, "AC", 12); } else { if (oMK.dictLookup("CA", &oObj)->isString()) { std::string sCA(oObj.getString()->getCString()); if (sCA == "l") // кружок m_nStyle = 3; else if (sCA == "4") // галка m_nStyle = 0; else if (sCA == "8") // крест m_nStyle = 1; else if (sCA == "u") // ромб m_nStyle = 2; else if (sCA == "n") // квадрат m_nStyle = 5; else if (sCA == "H") // звезда m_nStyle = 4; } oObj.free(); } // 13 - Положение заголовка - TP if (oMK.dictLookup("TP", &oObj)->isInt()) { m_nTP = oObj.getInt(); m_unFlags |= (1 << 13); } oObj.free(); Object oIF; if (oMK.dictLookup("IF", &oIF)->isDict()) { m_unIFFlag = 1; // 1 - Масштабирование - SW if (oIF.dictLookup("SW", &oObj)->isName()) { m_unIFFlag |= (1 << 1); std::string sName(oObj.getName()); m_nSW = 0; // Default: A if (sName == "B") m_nSW = 2; else if (sName == "S") m_nSW = 3; else if (sName == "N") m_nSW = 1; } oObj.free(); // 2 - Тип масштабирования - S if (oIF.dictLookup("S", &oObj)->isName()) { m_unIFFlag |= (1 << 2); std::string sName(oObj.getName()); m_nS = 0; // Default: P if (sName == "A") m_nS = 1; } oObj.free(); // 3 - Смещение - A if (oIF.dictLookup("A", &oObj)->isArray()) { m_dA1 = 0.5, m_dA2 = 0.5; Object oObj2; m_unIFFlag |= (1 << 3); m_dA1 = ArrGetNum(&oObj, 0); m_dA2 = ArrGetNum(&oObj, 1); } oObj.free(); // 4 - Полное соответствие - FB if (oIF.dictLookup("FB", &oObj)->isBool() && oObj.getBool()) m_unIFFlag |= (1 << 4); oObj.free(); } oIF.free(); } oMK.free(); Object oOpt; pField->fieldLookup("Opt", &oOpt); // 14 - Имя вкл состояния - AP - N - Yes Object oNorm; if (pField->fieldLookup("AP", &oObj)->isDict() && oObj.dictLookup("N", &oNorm)->isDict() && oOpt.isNull()) { for (int j = 0, nNormLength = oNorm.dictGetLength(); j < nNormLength; ++j) { std::string sNormName(oNorm.dictGetKey(j)); if (sNormName != "Off") { m_unFlags |= (1 << 14); m_sAP_N_Yes = sNormName; break; } } } oNorm.free(); oObj.free(); oOpt.free(); } CAnnotWidgetTx::CAnnotWidgetTx(PDFDoc* pdfDoc, AcroFormField* pField, int nStartRefID) : CAnnotWidget(pdfDoc, pField, nStartRefID) { Object oObj; Object oFieldRef, oField; pField->getFieldRef(&oFieldRef); oFieldRef.fetch(pdfDoc->getXRef(), &oField); oFieldRef.free(); // 9 - Значение - V if (oField.dictLookup("V", &oObj)) { m_sV = getValue(&oObj); if (!m_sV.empty()) m_unFlags |= (1 << 9); } oObj.free(); oField.free(); // 10 - Максимальное количество символов в Tx - MaxLen if (oField.dictLookup("MaxLen", &oObj)->isInt()) { m_unFlags |= (1 << 10); m_unMaxLen = oObj.getInt(); } oObj.free(); // 11 - Расширенный текст RV - RichText if (pField->getFlags() & (1 << 25)) m_sRV = FieldLookupString(pField, "RV", 11); } CAnnotWidgetCh::CAnnotWidgetCh(PDFDoc* pdfDoc, AcroFormField* pField, int nStartRefID) : CAnnotWidget(pdfDoc, pField, nStartRefID) { Object oObj; Object oFieldRef, oField; pField->getFieldRef(&oFieldRef); oFieldRef.fetch(pdfDoc->getXRef(), &oField); oFieldRef.free(); // 9 - Значение if (oField.dictLookup("V", &oObj)) { m_sV = getValue(&oObj, false); if (!m_sV.empty()) m_unFlags |= (1 << 9); } oObj.free(); Object oOpt; // 10 - Список значений if (oField.dictLookup("Opt", &oOpt)->isArray()) { m_unFlags |= (1 << 10); int nOptLength = oOpt.arrayGetLength(); for (int j = 0; j < nOptLength; ++j) { Object oOptJ; if (!oOpt.arrayGet(j, &oOptJ) || !(oOptJ.isString() || oOptJ.isArray())) { oOptJ.free(); continue; } std::string sOpt1, sOpt2; if (oOptJ.isArray() && oOptJ.arrayGetLength() > 1) { Object oOptJ2; if (oOptJ.arrayGet(0, &oOptJ2)->isString()) { TextString* s = new TextString(oOptJ2.getString()); sOpt1 = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength()); delete s; } oOptJ2.free(); if (oOptJ.arrayGet(1, &oOptJ2)->isString()) { TextString* s = new TextString(oOptJ2.getString()); sOpt2 = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength()); delete s; } oOptJ2.free(); } else if (oOptJ.isString()) { TextString* s = new TextString(oOptJ.getString()); sOpt2 = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength()); delete s; } m_arrOpt.push_back(std::make_pair(sOpt1, sOpt2)); oOptJ.free(); } } oOpt.free(); // 11 - Индекс верхнего элемента - TI if (pField->fieldLookup("TI", &oObj)->isInt()) { m_unFlags |= (1 << 11); m_unTI = oObj.getInt(); } oObj.free(); // 12 - Выбранные индексы - I if (oField.dictLookup("I", &oOpt)->isArray()) { m_unFlags |= (1 << 12); for (int j = 0; j < oOpt.arrayGetLength(); ++j) { if (oOpt.arrayGet(j, &oObj)->isInt()) m_arrI.push_back(oObj.getInt()); oObj.free(); } } oOpt.free(); // 13 - Массив значений if (oField.dictLookup("V", &oOpt)->isArray()) { m_unFlags |= (1 << 13); int nVLength = oOpt.arrayGetLength(); for (int j = 0; j < nVLength; ++j) { if (oOpt.arrayGet(j, &oObj)->isString()) { TextString* s = new TextString(oObj.getString()); m_arrV.push_back(NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength())); delete s; } oObj.free(); } } oOpt.free(); oField.free(); } CAnnotWidgetSig::CAnnotWidgetSig(PDFDoc* pdfDoc, AcroFormField* pField, int nStartRefID) : CAnnotWidget(pdfDoc, pField, nStartRefID) { Object oObj; Object oFieldRef, oField; pField->getFieldRef(&oFieldRef); oFieldRef.fetch(pdfDoc->getXRef(), &oField); oFieldRef.free(); // 9 - Значение if (oField.dictLookup("V", &oObj)->isDict()) m_unFlags |= (1 << 9); oObj.free(); oField.free(); } CAnnotWidget::CAnnotWidget(PDFDoc* pdfDoc, AcroFormField* pField, int nStartRefID) : CAnnot(pdfDoc, pField, nStartRefID) { Object oObj, oField; XRef* xref = pdfDoc->getXRef(); pField->getFieldRef(&oObj); oObj.fetch(xref, &oField); oObj.free(); m_bChangeFullName = false; m_dFontSize = 0.0; m_unFontStyle = 0; // Цвет текста - из DA int nSpace; GList *arrColors = pField->getColorSpace(&nSpace); for (int j = 0; j < nSpace; ++j) m_arrTC.push_back(*(double*)arrColors->get(j)); deleteGList(arrColors, double); // Выравнивание текста - Q m_nQ = 0; if (pField->fieldLookup("Q", &oObj)->isInt()) m_nQ = oObj.getInt(); oObj.free(); // Тип - FT + флаги AcroFormFieldType oType = pField->getAcroFormFieldType(); m_nType = 26; // Unknown switch (oType) { case acroFormFieldPushbutton: m_nType = 27; break; case acroFormFieldRadioButton: m_nType = 28; break; case acroFormFieldCheckbox: m_nType = 29; break; case acroFormFieldFileSelect: m_nType = 30; break; case acroFormFieldMultilineText: m_nType = 30; break; case acroFormFieldText: m_nType = 30; break; case acroFormFieldBarcode: m_nType = 30; break; case acroFormFieldComboBox: m_nType = 31; break; case acroFormFieldListBox: m_nType = 32; break; case acroFormFieldSignature: m_nType = 33; break; default: m_nType = 26; break; } // Флаг - Ff m_unFieldFlag = -1; if (oField.dictLookup("Ff", &oObj)->isInt()) m_unFieldFlag = oObj.getInt(); oObj.free(); // 0 - Альтернативное имя поля, используется во всплывающей подсказке и сообщениях об ошибке - TU if (oField.dictLookup("TU", &oObj)) { m_sTU = getValue(&oObj); if (!m_sTU.empty()) m_unFlags |= (1 << 0); } oObj.free(); // 1 - Строка стиля по умолчанию - DS m_sDS = FieldLookupString(pField, "DS", 1); // 3 - Режим выделения - H if (pField->fieldLookup("H", &oObj)->isName()) { m_unFlags |= (1 << 3); std::string sName(oObj.getName()); m_nH = 1; // Default: I if (sName == "N") m_nH = 0; else if (sName == "O") m_nH = 3; else if (sName == "P" || sName == "T") m_nH = 2; } oObj.free(); Object oMK; if (pField->fieldLookup("MK", &oMK)->isDict()) { // 5 - Цвет границ - BC. Даже если граница не задана BS/Border, то при наличии BC предоставляется граница по-умолчанию (сплошная, толщиной 1) if (oMK.dictLookup("BC", &oObj)->isArray()) { m_unFlags |= (1 << 5); int nBCLength = oObj.arrayGetLength(); for (int j = 0; j < nBCLength; ++j) { Object oBCj; m_arrBC.push_back(oObj.arrayGet(j, &oBCj)->isNum() ? oBCj.getNum() : 0.0); oBCj.free(); } } oObj.free(); // 6 - Поворот аннотации относительно страницы - R if (oMK.dictLookup("R", &oObj)->isInt()) { m_unFlags |= (1 << 6); m_unR = oObj.getInt(); } oObj.free(); // 7 - Цвет фона - BG if (oMK.dictLookup("BG", &oObj)->isArray()) { m_unFlags |= (1 << 7); int nBGLength = oObj.arrayGetLength(); for (int j = 0; j < nBGLength; ++j) { Object oBGj; m_arrBG.push_back(oObj.arrayGet(j, &oBGj)->isNum() ? oBGj.getNum() : 0.0); oBGj.free(); } } oObj.free(); } oMK.free(); // 8 - Значение по-умолчанию if (oField.dictLookup("DV", &oObj)) { m_sDV = getValue(&oObj); if (!m_sDV.empty()) m_unFlags |= (1 << 8); } oObj.free(); // 17 - Родитель - Parent m_unRefNumParent = 0; if (oField.dictLookupNF("Parent", &oObj)->isRef()) { m_unRefNumParent = oObj.getRefNum() + nStartRefID; m_unFlags |= (1 << 17); } oObj.free(); // 18 - Частичное имя поля - T m_sT = DictLookupString(&oField, "T", 18); m_sFullName = m_sT; // 21 - MEOptions if (oField.dictLookup("MEOptions", &oObj)->isInt()) { m_unFlags |= (1 << 21); m_unMEOptions = oObj.getInt(); } oObj.free(); // Action - A Object oAction; if (oField.dictLookup("A", &oAction)->isDict()) { std::string sAA = "A"; CAction* pA = getAction(pdfDoc, &oAction); if (pA) { pA->sType = sAA; m_arrAction.push_back(pA); } } oAction.free(); // Actions - AA Object oAA; if (oField.dictLookup("AA", &oAA)->isDict()) { for (int j = 0; j < oAA.dictGetLength(); ++j) { if (oAA.dictGetVal(j, &oAction)->isDict()) { std::string sAA(oAA.dictGetKey(j)); CAction* pA = getAction(pdfDoc, &oAction); if (pA) { pA->sType = sAA; m_arrAction.push_back(pA); } } oAction.free(); } } oAA.free(); oField.free(); } CAnnotWidget::~CAnnotWidget() { ClearActions(); } std::string CAnnotWidget::FieldLookupString(AcroFormField* pField, const char* sName, int nByte) { std::string sRes; Object oObj; if (pField->fieldLookup(sName, &oObj)->isString()) { m_unFlags |= (1 << nByte); TextString* s = new TextString(oObj.getString()); sRes = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength()); delete s; } oObj.free(); return sRes; } void CAnnotWidget::SetFont(PDFDoc* pdfDoc, AcroFormField* pField, NSFonts::IFontManager* pFontManager, CPdfFontList *pFontList) { // Шрифт и размер шрифта - из DA Ref fontID; pField->getFont(&fontID, &m_dFontSize); m_unFontStyle = 0; Object oFontRef; if (fontID.num < 0) { if (!CAnnotFonts::GetFontFromAP(pdfDoc, pField, &oFontRef, m_sFontKey)) { oFontRef.free(); return; } } else oFontRef.initRef(fontID.num, fontID.gen); bool bBold = false, bItalic = false; CAnnotFonts::GetFontData(pdfDoc, pFontManager, pFontList, &oFontRef, m_sFontName, m_sActualFontName, bBold, bItalic); oFontRef.free(); // 2 - Актуальный шрифт if (!m_sActualFontName.empty()) m_unFlags |= (1 << 2); // 4 - Уникальный идентификатор шрифта if (!m_sFontKey.empty()) m_unFlags |= (1 << 4); if (bBold) m_unFontStyle |= (1 << 0); if (bItalic) m_unFontStyle |= (1 << 1); } void CAnnotWidget::SetButtonFont(PDFDoc* pdfDoc, AcroFormField* pField, NSFonts::IFontManager* pFontManager, CPdfFontList *pFontList) { // Неполный шрифт во внешнем виде pushbutton Object oFontRef; if (!CAnnotFonts::GetFontFromAP(pdfDoc, pField, &oFontRef, m_sFontKey)) { oFontRef.free(); return; } bool bBold = false, bItalic = false; CAnnotFonts::GetFontData(pdfDoc, pFontManager, pFontList, &oFontRef, m_sButtonFontName, m_sButtonFontName, bBold, bItalic); if (!m_sButtonFontName.empty()) m_unFlags |= (1 << 19); oFontRef.free(); } bool CAnnotWidget::ChangeFullName(const std::string& sPrefixForm) { m_bChangeFullName = true; if (m_unFlags & (1 << 18)) { m_sT += sPrefixForm; m_sFullName += sPrefixForm; return true; } return false; } void CAnnotWidget::ClearActions() { for (int i = 0; i < m_arrAction.size(); ++i) RELEASEOBJECT(m_arrAction[i]); m_arrAction.clear(); } //------------------------------------------------------------------------ // Popup //------------------------------------------------------------------------ CAnnotPopup::CAnnotPopup(PDFDoc* pdfDoc, Object* oAnnotRef, int nPageIndex, int nStartRefID) : CAnnot(pdfDoc, oAnnotRef, nPageIndex, nStartRefID) { m_unFlags = 0; Object oAnnot, oObj; XRef* pXref = pdfDoc->getXRef(); oAnnotRef->fetch(pXref, &oAnnot); // 0 - Отображаться открытой - Open if (oAnnot.dictLookup("Open", &oObj)->isBool() && oObj.getBool()) m_unFlags |= (1 << 0); oObj.free(); // 1 - Родитель - Parent if (oAnnot.dictLookupNF("Parent", &oObj)->isRef()) { m_unFlags |= (1 << 1); m_unRefNumParent = oObj.getRefNum() + nStartRefID; } oObj.free(); oAnnot.free(); } //------------------------------------------------------------------------ // Text //------------------------------------------------------------------------ CAnnotText::CAnnotText(PDFDoc* pdfDoc, Object* oAnnotRef, int nPageIndex, int nStartRefID) : CAnnotMarkup(pdfDoc, oAnnotRef, nPageIndex, nStartRefID) { Object oAnnot, oObj; XRef* pXref = pdfDoc->getXRef(); oAnnotRef->fetch(pXref, &oAnnot); // 15 - Отображаться открытой - Open if (oAnnot.dictLookup("Open", &oObj)->isBool() && oObj.getBool()) m_unFlags |= (1 << 15); oObj.free(); // 16 - Иконка - Name m_unFlags |= (1 << 16); m_nName = 10; // Default: Note if (oAnnot.dictLookup("Name", &oObj)->isName()) { std::string sName(oObj.getName()); std::vector arrName = {"Check", "Checkmark", "Circle", "Comment", "Cross", "CrossHairs", "Help", "Insert", "Key", "NewParagraph", "Note", "Paragraph", "RightArrow", "RightPointer", "Star", "UpArrow", "UpLeftArrow"}; std::vector::iterator p = std::find(arrName.begin(), arrName.end(), sName); if (p != arrName.end()) m_nName = p - arrName.begin(); } oObj.free(); // 17 - Модель состояния - StateModel if (oAnnot.dictLookup("StateModel", &oObj)->isString()) { m_unFlags |= (1 << 17); TextString* s = new TextString(oObj.getString()); std::string sStateModel = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength()); delete s; m_nStateModel = 1; // Review if (sStateModel == "Marked") m_nStateModel = 0; } oObj.free(); // 18 - Состояние - State if (oAnnot.dictLookup("State", &oObj)->isString()) { m_unFlags |= (1 << 18); TextString* s = new TextString(oObj.getString()); std::string sState = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength()); delete s; m_nState = 6; // None if (sState == "Marked") m_nState = 0; else if (sState == "Unmarked") m_nState = 1; else if (sState == "Accepted") m_nState = 2; else if (sState == "Rejected") m_nState = 3; else if (sState == "Cancelled") m_nState = 4; else if (sState == "Completed") m_nState = 5; } oObj.free(); oAnnot.free(); } //------------------------------------------------------------------------ // Ink //------------------------------------------------------------------------ CAnnotInk::CAnnotInk(PDFDoc* pdfDoc, Object* oAnnotRef, int nPageIndex, int nStartRefID) : CAnnotMarkup(pdfDoc, oAnnotRef, nPageIndex, nStartRefID) { Object oAnnot, oObj, oObj2; XRef* pXref = pdfDoc->getXRef(); oAnnotRef->fetch(pXref, &oAnnot); // Путь - InkList if (oAnnot.dictLookup("InkList", &oObj)->isArray()) { for (int j = 0; j < oObj.arrayGetLength(); ++j) { if (oObj.arrayGet(j, &oObj2)->isArray()) { std::vector arrLine; for (int k = 0; k < oObj2.arrayGetLength(); ++k) { Object oObj1; if (oObj2.arrayGet(k, &oObj1)->isNum()) arrLine.push_back(k % 2 == 0 ? oObj1.getNum() - m_dX : m_dHeight - oObj1.getNum()); else arrLine.push_back(0.0); oObj1.free(); } if (!arrLine.empty()) m_arrInkList.push_back(arrLine); } } } oObj.free(); oAnnot.free(); } //------------------------------------------------------------------------ // Line //------------------------------------------------------------------------ CAnnotLine::CAnnotLine(PDFDoc* pdfDoc, Object* oAnnotRef, int nPageIndex, int nStartRefID) : CAnnotMarkup(pdfDoc, oAnnotRef, nPageIndex, nStartRefID) { Object oAnnot, oObj, oObj2; XRef* pXref = pdfDoc->getXRef(); oAnnotRef->fetch(pXref, &oAnnot); // Координаты линии - L if (oAnnot.dictLookup("L", &oObj)->isArray()) { m_pL[0] = ArrGetNum(&oObj, 0) - m_dX; m_pL[1] = m_dHeight - ArrGetNum(&oObj, 1); m_pL[2] = ArrGetNum(&oObj, 2) - m_dX; m_pL[3] = m_dHeight - ArrGetNum(&oObj, 3); } oObj.free(); // 15 - Стили окончания линии - LE if (oAnnot.dictLookup("LE", &oObj)->isArray()) { m_unFlags |= (1 << 15); m_nLE[0] = 5; m_nLE[1] = 5; // None for (int i = 0; i < oObj.arrayGetLength() && i < 2; ++i) { if (oObj.arrayGet(i, &oObj2)->isName()) m_nLE[i] = getLE(&oObj2); oObj2.free(); } } oObj.free(); // 16 - Цвет окончаний линии - IC if (oAnnot.dictLookup("IC", &oObj)->isArray()) { m_unFlags |= (1 << 16); for (int j = 0; j < oObj.arrayGetLength(); ++j) { m_arrIC.push_back(oObj.arrayGet(j, &oObj2)->isNum() ? oObj2.getNum() : 0.0); oObj2.free(); } } oObj.free(); // 17 - Длина линий выноски - LL if (oAnnot.dictLookup("LL", &oObj)->isNum()) { m_unFlags |= (1 << 17); m_dLL = oObj.getNum(); } oObj.free(); // 18 - Продолжение линий выноски - LLE if (oAnnot.dictLookup("LLE", &oObj)->isNum()) { m_unFlags |= (1 << 18); m_dLLE = oObj.getNum(); } oObj.free(); // 19 - Местоположение заголовка - Cap if (oAnnot.dictLookup("Cap", &oObj)->isBool()) m_unFlags |= (1 << 19); oObj.free(); // 20 - Назначение аннотации - IT if (oAnnot.dictLookup("IT", &oObj)->isName()) { m_unFlags |= (1 << 20); m_nIT = 0; // LineDimension if (oObj.isName("LineArrow")) m_nIT = 1; } oObj.free(); // 21 - Длина смещения выноски - LLO if (oAnnot.dictLookup("LLO", &oObj)->isNum()) { m_unFlags |= (1 << 21); m_dLLO = oObj.getNum(); } oObj.free(); // 22 - Расположение заголовка аннотации - CP if (oAnnot.dictLookup("CP", &oObj)->isName()) { m_unFlags |= (1 << 22); m_nCP = 0; // Inline if (oObj.isName("Top")) m_nCP = 1; } oObj.free(); // 23 - Смещение текста подписи - CO m_pCO[0] = 0.0; m_pCO[1] = 0.0; if (oAnnot.dictLookup("CO", &oObj)->isArray()) { m_unFlags |= (1 << 23); m_pCO[0] = ArrGetNum(&oObj, 0); m_pCO[1] = ArrGetNum(&oObj, 1); } oObj.free(); oAnnot.free(); } //------------------------------------------------------------------------ // TextMarkup: Highlight, Underline, Squiggly, StrikeOut //------------------------------------------------------------------------ CAnnotTextMarkup::CAnnotTextMarkup(PDFDoc* pdfDoc, Object* oAnnotRef, int nPageIndex, int nStartRefID) : CAnnotMarkup(pdfDoc, oAnnotRef, nPageIndex, nStartRefID) { Object oAnnot, oObj, oObj2; XRef* pXref = pdfDoc->getXRef(); oAnnotRef->fetch(pXref, &oAnnot); // Координаты - QuadPoints if (oAnnot.dictLookup("QuadPoints", &oObj)->isArray()) { for (int i = 0; i < oObj.arrayGetLength(); ++i) { if (oObj.arrayGet(i, &oObj2)->isNum()) m_arrQuadPoints.push_back(i % 2 == 0 ? oObj2.getNum() - m_dX : m_dHeight - oObj2.getNum()); oObj2.free(); } } oObj.free(); // Подтип - Subtype std::string sType; if (oAnnot.dictLookup("Subtype", &oObj)->isName()) sType = oObj.getName(); oObj.free(); if (sType == "Highlight") m_nSubtype = 8; else if (sType == "Underline") m_nSubtype = 9; else if (sType == "Squiggly") m_nSubtype = 10; else if (sType == "StrikeOut") m_nSubtype = 11; oAnnot.free(); } //------------------------------------------------------------------------ // Square, Circle //------------------------------------------------------------------------ CAnnotSquareCircle::CAnnotSquareCircle(PDFDoc* pdfDoc, Object* oAnnotRef, int nPageIndex, int nStartRefID) : CAnnotMarkup(pdfDoc, oAnnotRef, nPageIndex, nStartRefID) { Object oAnnot, oObj, oObj2; XRef* pXref = pdfDoc->getXRef(); oAnnotRef->fetch(pXref, &oAnnot); // Подтип - Subtype std::string sType; if (oAnnot.dictLookup("Subtype", &oObj)->isName()) sType = oObj.getName(); oObj.free(); if (sType == "Square") m_nSubtype = 4; else if (sType == "Circle") m_nSubtype = 5; // 15 - Различия Rect и фактического размера - RD if (oAnnot.dictLookup("RD", &oObj)->isArray()) { m_unFlags |= (1 << 15); m_pRD[0] = ArrGetNum(&oObj, 0); m_pRD[3] = ArrGetNum(&oObj, 1); m_pRD[2] = ArrGetNum(&oObj, 2); m_pRD[1] = ArrGetNum(&oObj, 3); } oObj.free(); // 16 - Цвет заполнения - IC if (oAnnot.dictLookup("IC", &oObj)->isArray()) { m_unFlags |= (1 << 16); for (int j = 0; j < oObj.arrayGetLength(); ++j) { m_arrIC.push_back(oObj.arrayGet(j, &oObj2)->isNum() ? oObj2.getNum() : 0.0); oObj2.free(); } } oObj.free(); oAnnot.free(); } //------------------------------------------------------------------------ // Polygon, PolyLine //------------------------------------------------------------------------ CAnnotPolygonLine::CAnnotPolygonLine(PDFDoc* pdfDoc, Object* oAnnotRef, int nPageIndex, int nStartRefID) : CAnnotMarkup(pdfDoc, oAnnotRef, nPageIndex, nStartRefID) { Object oAnnot, oObj, oObj2; XRef* pXref = pdfDoc->getXRef(); oAnnotRef->fetch(pXref, &oAnnot); // Подтип - Subtype std::string sType; if (oAnnot.dictLookup("Subtype", &oObj)->isName()) sType = oObj.getName(); oObj.free(); if (sType == "Polygon") m_nSubtype = 6; else if (sType == "PolyLine") m_nSubtype = 7; // Координаты вершин - Vertices if (oAnnot.dictLookup("Vertices", &oObj)->isArray()) { for (int j = 0; j < oObj.arrayGetLength(); ++j) { if (oObj.arrayGet(j, &oObj2)->isNum()) m_arrVertices.push_back(j % 2 == 0 ? oObj2.getNum() - m_dX : m_dHeight - oObj2.getNum()); else m_arrVertices.push_back(0.0); oObj2.free(); } } oObj.free(); // 15 - Стили окончания линии - LE if (oAnnot.dictLookup("LE", &oObj)->isArray()) { m_unFlags |= (1 << 15); m_nLE[0] = 5; m_nLE[1] = 5; // None for (int i = 0; i < oObj.arrayGetLength() && i < 2; ++i) { if (oObj.arrayGet(i, &oObj2)->isName()) m_nLE[i] = getLE(&oObj2); oObj2.free(); } } oObj.free(); // 16 - Цвет заполнения - IC if (oAnnot.dictLookup("IC", &oObj)->isArray()) { m_unFlags |= (1 << 16); for (int j = 0; j < oObj.arrayGetLength(); ++j) { m_arrIC.push_back(oObj.arrayGet(j, &oObj2)->isNum() ? oObj2.getNum() : 0.0); oObj2.free(); } } oObj.free(); // 20 - Назначение аннотации - IT if (oAnnot.dictLookup("IT", &oObj)->isName()) { m_unFlags |= (1 << 20); m_nIT = 0; // PolygonCloud if (oObj.isName("PolyLineDimension")) m_nIT = 1; else if (oObj.isName("PolygonDimension")) m_nIT = 2; } oObj.free(); oAnnot.free(); } //------------------------------------------------------------------------ // FreeText //------------------------------------------------------------------------ CAnnotFreeText::CAnnotFreeText(PDFDoc* pdfDoc, Object* oAnnotRef, int nPageIndex, int nStartRefID) : CAnnotMarkup(pdfDoc, oAnnotRef, nPageIndex, nStartRefID) { Object oAnnot, oObj, oObj2; XRef* pXref = pdfDoc->getXRef(); oAnnotRef->fetch(pXref, &oAnnot); // Выравнивание текста - Q m_nQ = 0; if (oAnnot.dictLookup("Q", &oObj)->isInt()) m_nQ = oObj.getInt(); oObj.free(); m_nRotate = 0; if (oAnnot.dictLookup("Rotate", &oObj)->isInt()) m_nRotate = oObj.getInt(); oObj.free(); // 15 - Различия Rect и фактического размера - RD if (oAnnot.dictLookup("RD", &oObj)->isArray()) { m_unFlags |= (1 << 15); m_pRD[0] = ArrGetNum(&oObj, 0); m_pRD[3] = ArrGetNum(&oObj, 1); m_pRD[2] = ArrGetNum(&oObj, 2); m_pRD[1] = ArrGetNum(&oObj, 3); } oObj.free(); // 16 - Координаты выноски - CL if (oAnnot.dictLookup("CL", &oObj)->isArray()) { m_unFlags |= (1 << 16); for (int j = 0; j < oObj.arrayGetLength(); ++j) { if (oObj.arrayGet(j, &oObj2)->isNum()) m_arrCL.push_back(j % 2 == 0 ? oObj2.getNum() - m_dX : m_dHeight - oObj2.getNum()); else m_arrCL.push_back(0.0); oObj2.free(); } } oObj.free(); // 17 - Строка стиля по умолчанию - DS m_sDS = DictLookupString(&oAnnot, "DS", 17); // 18 - Стили окончания линии - LE if (oAnnot.dictLookup("LE", &oObj)->isName()) { m_unFlags |= (1 << 18); m_nLE = getLE(&oObj); } oObj.free(); // 20 - Назначение аннотации - IT if (oAnnot.dictLookup("IT", &oObj)->isName()) { m_unFlags |= (1 << 20); m_nIT = 0; // FreeText if (oObj.isName("FreeTextCallout")) m_nIT = 1; else if (oObj.isName("FreeTextTypeWriter")) m_nIT = 2; } oObj.free(); // 21 - Цвет границы - color from DA if (oAnnot.dictLookup("DA", &oObj)->isString()) { m_unFlags |= (1 << 21); int nSpace; GList *arrColors = new GList(); // parse the default appearance string GList* daToks = tokenize(oObj.getString()); for (int i = daToks->getLength() - 1; i > 0; --i) { // handle the g operator if (!((GString *)daToks->get(i))->cmp("g")) { arrColors->append(new double(atof(((GString *)daToks->get(i - 1))->getCString()))); break; // handle the rg operator } else if (i >= 3 && !((GString *)daToks->get(i))->cmp("rg")) { arrColors->append(new double(atof(((GString *)daToks->get(i - 3))->getCString()))); arrColors->append(new double(atof(((GString *)daToks->get(i - 2))->getCString()))); arrColors->append(new double(atof(((GString *)daToks->get(i - 1))->getCString()))); break; } else if (i >= 4 && !((GString *)daToks->get(i))->cmp("k")) { arrColors->append(new double(atof(((GString *)daToks->get(i - 4))->getCString()))); arrColors->append(new double(atof(((GString *)daToks->get(i - 3))->getCString()))); arrColors->append(new double(atof(((GString *)daToks->get(i - 2))->getCString()))); arrColors->append(new double(atof(((GString *)daToks->get(i - 1))->getCString()))); break; } } deleteGList(daToks, GString); nSpace = arrColors->getLength(); for (int j = 0; j < nSpace; ++j) m_arrCFromDA.push_back(*(double*)arrColors->get(j)); deleteGList(arrColors, double); } oObj.free(); if (oAnnot.dictLookup("RC", &oObj2)->isNull() && oAnnot.dictLookup("Contents", &oObj)->isString() && oObj.getString()->getLength()) { m_arrRC = CAnnotMarkup::ReadRC(GetRCFromDS(m_sDS, &oObj, m_arrCFromDA)); if (m_arrRC.empty()) m_unFlags &= ~(1 << 3); else m_unFlags |= (1 << 3); } oObj.free(); oObj2.free(); oAnnot.free(); } //------------------------------------------------------------------------ // Caret //------------------------------------------------------------------------ CAnnotCaret::CAnnotCaret(PDFDoc* pdfDoc, Object* oAnnotRef, int nPageIndex, int nStartRefID) : CAnnotMarkup(pdfDoc, oAnnotRef, nPageIndex, nStartRefID) { Object oAnnot, oObj, oObj2; XRef* pXref = pdfDoc->getXRef(); oAnnotRef->fetch(pXref, &oAnnot); // 15 - Различия Rect и фактического размера - RD if (oAnnot.dictLookup("RD", &oObj)->isArray() && oObj.arrayGetLength() == 4) { m_unFlags |= (1 << 15); m_pRD[0] = ArrGetNum(&oObj, 0); m_pRD[3] = ArrGetNum(&oObj, 1); m_pRD[2] = ArrGetNum(&oObj, 2); m_pRD[1] = ArrGetNum(&oObj, 3); } oObj.free(); // 16 - Связанный символ - Sy if (oAnnot.dictLookup("Sy", &oObj)->isName()) { m_unFlags |= (1 << 16); m_nSy = 0; // None if (oObj.isName("P")) m_nSy = 1; if (oObj.isName("S")) m_nSy = 2; } oObj.free(); oAnnot.free(); } //------------------------------------------------------------------------ // FileAttachment //------------------------------------------------------------------------ CAnnotFileAttachment::CAnnotFileAttachment(PDFDoc* pdfDoc, Object* oAnnotRef, int nPageIndex, int nStartRefID) : CAnnotMarkup(pdfDoc, oAnnotRef, nPageIndex, nStartRefID) { m_pEF = NULL; Object oAnnot, oObj, oObj2; XRef* pXref = pdfDoc->getXRef(); oAnnotRef->fetch(pXref, &oAnnot); // 15 - Иконка - Name if (oAnnot.dictLookup("Name", &oObj)->isName()) { m_unFlags |= (1 << 15); m_sName = oObj.getName(); } oObj.free(); Object oFS; if (!oAnnot.dictLookup("FS", &oFS)->isDict()) { oFS.free(); oAnnot.free(); return; } // 16 - Файловая система - FS if (oFS.dictLookup("FS", &oObj)->isName()) { m_unFlags |= (1 << 16); m_sFS = oObj.getName(); } oObj.free(); // 17 - Спецификация файла - F m_sF = DictLookupString(&oFS, "F", 17); // 18 - Спецификация файла - UF m_sUF = DictLookupString(&oFS, "UF", 18); // 19 - Спецификация файла - DOS m_sDOS = DictLookupString(&oFS, "DOS", 19); // 20 - Спецификация файла - Mac m_sMac = DictLookupString(&oFS, "Mac", 20); // 21 - Спецификация файла - Unix m_sUnix = DictLookupString(&oFS, "Unix", 21); // 22 - Идентификатор файла - ID if (oFS.dictLookup("ID", &oObj)->isArray() && oObj.arrayGetLength() == 2) { m_unFlags |= (1 << 22); if (oObj.arrayGet(0, &oObj2)->isString()) { TextString* s = new TextString(oObj2.getString()); m_sID.first = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength()); delete s; } oObj2.free(); if (oObj.arrayGet(1, &oObj2)->isString()) { TextString* s = new TextString(oObj2.getString()); m_sID.second = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength()); delete s; } oObj2.free(); } oObj.free(); // 23 - Изменчивость файла - V if (oFS.dictLookup("V", &oObj)->isBool() && oObj.getBool()) m_unFlags |= (1 << 23); oObj.free(); // 24 - Встроенные файловые потоки - EF Object oEF; if (oFS.dictLookup("EF", &oEF)->isDict()) { m_unFlags |= (1 << 24); m_pEF = new CEmbeddedFiles(); if (oEF.dictLookup("F", &oObj)->isStream()) m_pEF->m_pF = getEF(&oObj); oObj.free(); if (oEF.dictLookup("UF", &oObj)->isStream()) m_pEF->m_pUF = getEF(&oObj); oObj.free(); if (oEF.dictLookup("DOS", &oObj)->isStream()) m_pEF->m_pDOS = getEF(&oObj); oObj.free(); if (oEF.dictLookup("Mac", &oObj)->isStream()) m_pEF->m_pMac = getEF(&oObj); oObj.free(); if (oEF.dictLookup("Unix", &oObj)->isStream()) m_pEF->m_pUnix = getEF(&oObj); oObj.free(); } oEF.free(); // 25 - Встроенные файловые потоки - RF if (oFS.dictLookup("RF", &oObj)->isDict()) m_unFlags |= (1 << 25); oObj.free(); // 26 - Описание файла - Desc m_sDesc = DictLookupString(&oFS, "Desc", 26); // 27 - Коллекция - Cl if (oFS.dictLookup("Cl", &oObj)->isDict()) m_unFlags |= (1 << 27); oObj.free(); oFS.free(); oAnnot.free(); } CAnnotFileAttachment::~CAnnotFileAttachment() { RELEASEOBJECT(m_pEF); } //------------------------------------------------------------------------ // Stamp //------------------------------------------------------------------------ CAnnotStamp::CAnnotStamp(PDFDoc* pdfDoc, Object* oAnnotRef, int nPageIndex, int nStartRefID) : CAnnotMarkup(pdfDoc, oAnnotRef, nPageIndex, nStartRefID) { Object oAnnot, oObj; XRef* pXref = pdfDoc->getXRef(); oAnnotRef->fetch(pXref, &oAnnot); // Иконка - Name if (oAnnot.dictLookup("Name", &oObj)->isName()) m_sName = oObj.getName(); oObj.free(); m_dRotate = 0; if (oAnnot.dictLookup("Rotate", &oObj)->isNum()) m_dRotate = oObj.getNum(); oObj.free(); double m[6] = { 1, 0, 0, 1, 0, 0 }, bbox[4] = { 0, 0, 0, 0 }; Object oAP, oObj2; if (oAnnot.dictLookup("AP", &oAP)->isDict() && oAP.dictLookup("N", &oObj2)->isStream()) { Object oObj1; if (oObj2.streamGetDict()->lookup("BBox", &oObj)->isArray() && oObj.arrayGetLength() == 4) { for (int i = 0; i < 4; ++i) { oObj.arrayGet(i, &oObj1); bbox[i] = oObj1.isNum() ? oObj1.getNum() : 0; oObj1.free(); } } oObj.free(); if (oObj2.streamGetDict()->lookup("Matrix", &oObj)->isArray() && oObj.arrayGetLength() == 6) { for (int i = 0; i < 6; ++i) { oObj.arrayGet(i, &oObj1); m[i] = oObj1.getNum(); oObj1.free(); } } } else { m_dX1 = 0; m_dY1 = 0; m_dX2 = 0; m_dY2 = 0; m_dX3 = 0; m_dY3 = 0; m_dX4 = 0; m_dY4 = 0; return; } oAP.free(); oObj2.free(); oObj.free(); double formXMin, formYMin, formXMax, formYMax, x, y, sx, sy; x = bbox[0] * m[0] + bbox[1] * m[2] + m[4]; y = bbox[0] * m[1] + bbox[1] * m[3] + m[5]; formXMin = formXMax = x; formYMin = formYMax = y; x = bbox[0] * m[0] + bbox[3] * m[2] + m[4]; y = bbox[0] * m[1] + bbox[3] * m[3] + m[5]; if (x < formXMin) formXMin = x; else if (x > formXMax) formXMax = x; if (y < formYMin) formYMin = y; else if (y > formYMax) formYMax = y; x = bbox[2] * m[0] + bbox[1] * m[2] + m[4]; y = bbox[2] * m[1] + bbox[1] * m[3] + m[5]; if (x < formXMin) formXMin = x; else if (x > formXMax) formXMax = x; if (y < formYMin) formYMin = y; else if (y > formYMax) formYMax = y; x = bbox[2] * m[0] + bbox[3] * m[2] + m[4]; y = bbox[2] * m[1] + bbox[3] * m[3] + m[5]; if (x < formXMin) formXMin = x; else if (x > formXMax) formXMax = x; if (y < formYMin) formYMin = y; else if (y > formYMax) formYMax = y; if (formXMin == formXMax) sx = 1; else sx = (m_pRect[2] - m_pRect[0]) / (formXMax - formXMin); if (formYMin == formYMax) sy = 1; else sy = (m_pRect[3] - m_pRect[1]) / (formYMax - formYMin); double tx = -formXMin * sx + m_pRect[0]; double ty = -formYMin * sy - m_pRect[3] + m_dHeight; m[0] *= sx; m[1] *= sy; m[2] *= sx; m[3] *= sy; m[4] = m[4] * sx + tx; m[5] = m[5] * sy + ty; m_dX1 = bbox[0] * m[0] + bbox[1] * m[2] + m[4]; m_dY1 = m_dHeight - (bbox[0] * m[1] + bbox[1] * m[3] + m[5]); m_dX2 = bbox[0] * m[0] + bbox[3] * m[2] + m[4]; m_dY2 = m_dHeight - (bbox[0] * m[1] + bbox[3] * m[3] + m[5]); m_dX3 = bbox[2] * m[0] + bbox[3] * m[2] + m[4]; m_dY3 = m_dHeight - (bbox[2] * m[1] + bbox[3] * m[3] + m[5]); m_dX4 = bbox[2] * m[0] + bbox[1] * m[2] + m[4]; m_dY4 = m_dHeight - (bbox[2] * m[1] + bbox[1] * m[3] + m[5]); oAnnot.free(); } //------------------------------------------------------------------------ // Redact //------------------------------------------------------------------------ CAnnotRedact::CAnnotRedact(PDFDoc* pdfDoc, Object* oAnnotRef, int nPageIndex, int nStartRefID) : CAnnotMarkup(pdfDoc, oAnnotRef, nPageIndex, nStartRefID) { Object oAnnot, oObj, oObj2; XRef* pXref = pdfDoc->getXRef(); oAnnotRef->fetch(pXref, &oAnnot); // 15 - Координаты - QuadPoints if (oAnnot.dictLookup("QuadPoints", &oObj)->isArray()) { m_unFlags |= (1 << 15); for (int i = 0; i < oObj.arrayGetLength(); ++i) { if (oObj.arrayGet(i, &oObj2)->isNum()) m_arrQuadPoints.push_back(i % 2 == 0 ? oObj2.getNum() - m_dX : m_dHeight - oObj2.getNum()); oObj2.free(); } } oObj.free(); // 16 - Цвет заполнения - IC if (oAnnot.dictLookup("IC", &oObj)->isArray()) { m_unFlags |= (1 << 16); for (int j = 0; j < oObj.arrayGetLength(); ++j) { m_arrIC.push_back(oObj.arrayGet(j, &oObj2)->isNum() ? oObj2.getNum() : 0.0); oObj2.free(); } } oObj.free(); // RO во внешних видах // 17 - Текст наложения - OverlayText m_sOverlayText = DictLookupString(&oAnnot, "OverlayText", 17); // 18 - Повторять текст - Repeat if (oAnnot.dictLookup("Repeat", &oObj)->isBool() && oObj.getBool()) m_unFlags |= (1 << 18); // 19 - Выравнивание текста - Q m_nQ = 0; if (oAnnot.dictLookup("Q", &oObj)->isInt()) { m_unFlags |= (1 << 19); m_nQ = oObj.getInt(); } oObj.free(); // Замена C: 3 - Цвет - C if (oAnnot.dictLookup("OC", &oObj)->isArray()) { m_unAFlags |= (1 << 3); int nBCLength = oObj.arrayGetLength(); m_arrC.clear(); for (int j = 0; j < nBCLength; ++j) { m_arrC.push_back(oObj.arrayGet(j, &oObj2)->isNum() ? oObj2.getNum() : 0.0); oObj2.free(); } } oObj.free(); oAnnot.free(); } void CAnnotRedact::SetFont(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CPdfFontList *pFontList, Object* oAnnotRef) { Object oAnnot, oObj; XRef* pXref = pdfDoc->getXRef(); oAnnotRef->fetch(pXref, &oAnnot); // 20 - Шрифт, размер, цвет текста замены - DA if (oAnnot.dictLookup("DA", &oObj)->isString()) { m_unFlags |= (1 << 20); // parse the default appearance string GList* daToks = tokenize(oObj.getString()); for (int i = daToks->getLength() - 1; i > 0; --i) { // handle the g operator if (!((GString *)daToks->get(i))->cmp("G") && m_arrCFromDA.empty()) { m_arrCFromDA.push_back(atof(((GString *)daToks->get(i - 1))->getCString())); } // handle the rg operator else if (i >= 3 && !((GString *)daToks->get(i))->cmp("RG") && m_arrCFromDA.empty()) { m_arrCFromDA.push_back(atof(((GString *)daToks->get(i - 3))->getCString())); m_arrCFromDA.push_back(atof(((GString *)daToks->get(i - 2))->getCString())); m_arrCFromDA.push_back(atof(((GString *)daToks->get(i - 1))->getCString())); } // handle the k operator else if (i >= 4 && !((GString *)daToks->get(i))->cmp("K") && m_arrCFromDA.empty()) { m_arrCFromDA.push_back(atof(((GString *)daToks->get(i - 4))->getCString())); m_arrCFromDA.push_back(atof(((GString *)daToks->get(i - 3))->getCString())); m_arrCFromDA.push_back(atof(((GString *)daToks->get(i - 2))->getCString())); m_arrCFromDA.push_back(atof(((GString *)daToks->get(i - 1))->getCString())); } else if (i >= 2 && !((GString *)daToks->get(i))->cmp("Tf")) { m_dFontSize = atof(((GString *)daToks->get(i - 1))->getCString()); m_unFontStyle = 0; } } deleteGList(daToks, GString); } oObj.free(); Object oAP, oN; if (!oAnnot.dictLookup("RO", &oN)->isStream()) { oN.free(); if (!oAnnot.dictLookup("AP", &oAP)->isDict() || !oAP.dictLookup("D", &oN)->isStream()) { oAP.free(); oN.free(); oAnnot.free(); return; } } oAP.free(); Object oFonts; if (!CAnnotFonts::FindFonts(&oN, 0, &oFonts)) { oN.free(); oFonts.free(); oAnnot.free(); return; } oN.free(); for (int i = 0, nFonts = oFonts.dictGetLength(); i < nFonts; ++i) { Object oFontRef; if (!oFonts.dictGetValNF(i, &oFontRef)->isRef()) { oFontRef.free(); continue; } std::string sFontName, sActualFontName; bool bBold = false, bItalic = false; std::wstring sFontPath = CAnnotFonts::GetFontData(pdfDoc, pFontManager, pFontList, &oFontRef, m_sFontName, m_sActualFontName, bBold, bItalic); oFontRef.free(); m_unFontStyle = 0; if (bBold) m_unFontStyle |= (1 << 0); if (bItalic) m_unFontStyle |= (1 << 1); } oFonts.free(); oAnnot.free(); } //------------------------------------------------------------------------ // Annots //------------------------------------------------------------------------ CAnnots::CAnnots(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CPdfFontList *pFontList, int nStartPage, int nStartRefID) { Object oObj1, oObj2; XRef* xref = pdfDoc->getXRef(); AcroForm* pAcroForms = pdfDoc->getCatalog()->getForm(); // Порядок вычислений - CO Object* oAcroForm = pAcroForms->getAcroFormObj(); if (oAcroForm->dictLookup("CO", &oObj1)->isArray()) { for (int j = 0; j < oObj1.arrayGetLength(); ++j) { if (oObj1.arrayGetNF(j, &oObj2)->isRef()) m_arrCO.push_back(oObj2.getRefNum() + nStartRefID); oObj2.free(); } } oObj1.free(); // Fields for (int i = 0, nNum = pAcroForms->getNumFields(); i < nNum; ++i) { AcroFormField* pField = pAcroForms->getField(i); Object oFieldRef, oField; if (!pField || !pField->getFieldRef(&oFieldRef)->isRef() || !oFieldRef.fetch(xref, &oField)->isDict()) { oField.free(); oFieldRef.free(); continue; } if (pField->getPageNum() < 1) { oField.free(); oFieldRef.free(); std::vector::iterator it = std::find(m_arrCO.begin(), m_arrCO.end(), oFieldRef.getRefNum() + nStartRefID); if (it != m_arrCO.end()) m_arrCO.erase(it); continue; } // Родители Object oParentRefObj; if (oField.dictLookupNF("Parent", &oParentRefObj)->isRef()) getParents(pdfDoc, &oParentRefObj, nStartRefID); oParentRefObj.free(); oField.free(); oFieldRef.free(); CAnnotWidget* pAnnot = NULL; AcroFormFieldType oType = pField->getAcroFormFieldType(); switch (oType) { case acroFormFieldPushbutton: case acroFormFieldRadioButton: case acroFormFieldCheckbox: { pAnnot = new CAnnotWidgetBtn(pdfDoc, pField, nStartRefID); break; } case acroFormFieldFileSelect: case acroFormFieldMultilineText: case acroFormFieldText: case acroFormFieldBarcode: { pAnnot = new CAnnotWidgetTx(pdfDoc, pField, nStartRefID); break; } case acroFormFieldComboBox: case acroFormFieldListBox: { pAnnot = new CAnnotWidgetCh(pdfDoc, pField, nStartRefID); break; } case acroFormFieldSignature: { pAnnot = new CAnnotWidgetSig(pdfDoc, pField, nStartRefID); break; } default: break; } if (pAnnot) { pAnnot->SetFont(pdfDoc, pField, pFontManager, pFontList); if (pField->getAcroFormFieldType() == acroFormFieldPushbutton) pAnnot->SetButtonFont(pdfDoc, pField, pFontManager, pFontList); pAnnot->SetPage(nStartPage + pField->getPageNum()); unsigned int unRefNumParent = pAnnot->GetRefNumParent(); if (unRefNumParent) { std::vector::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); } } } CAnnots::~CAnnots() { for (int i = 0; i < m_arrParents.size(); ++i) RELEASEOBJECT(m_arrParents[i]); for (int i = 0; i < m_arrAnnots.size(); ++i) RELEASEOBJECT(m_arrAnnots[i]); } void CAnnots::getParents(PDFDoc* pdfDoc, Object* oFieldRef, int nStartRefID) { if (!oFieldRef || !pdfDoc || !oFieldRef->isRef() || std::find_if(m_arrParents.begin(), m_arrParents.end(), [oFieldRef, nStartRefID] (CAnnotParent* pAP) { return oFieldRef->getRefNum() + nStartRefID == pAP->unRefNum; }) != m_arrParents.end()) return; Object oField; CAnnotParent* pAnnotParent = new CAnnotParent(); if (!pAnnotParent || !oFieldRef->fetch(pdfDoc->getXRef(), &oField)->isDict()) { oField.free(); RELEASEOBJECT(pAnnotParent); return; } pAnnotParent->unRefNum = oFieldRef->getRefNum() + nStartRefID; Object oObj; if (oField.dictLookup("T", &oObj)->isString()) { TextString* s = new TextString(oObj.getString()); std::string sStr = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength()); pAnnotParent->unFlags |= (1 << 0); pAnnotParent->sT = sStr; pAnnotParent->sFullName = sStr; delete s; } oObj.free(); if (oField.dictLookup("V", &oObj)) { pAnnotParent->sV = getValue(&oObj, false); if (!pAnnotParent->sV.empty()) pAnnotParent->unFlags |= (1 << 1); if (oObj.isArray()) { pAnnotParent->unFlags |= (1 << 5); int nVLength = oObj.arrayGetLength(); for (int j = 0; j < nVLength; ++j) { Object oObj2; if (oObj.arrayGet(j, &oObj2)->isString()) { TextString* s = new TextString(oObj2.getString()); pAnnotParent->arrV.push_back(NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength())); delete s; } oObj2.free(); } } } oObj.free(); if (oField.dictLookup("DV", &oObj)) { pAnnotParent->sDV = getValue(&oObj); if (!pAnnotParent->sDV.empty()) pAnnotParent->unFlags |= (1 << 2); } oObj.free(); Object oI; if (oField.dictLookup("I", &oI)->isArray()) { int nILength = oI.arrayGetLength(); for (int j = 0; j < nILength; ++j) { if (oI.arrayGet(j, &oObj)->isInt()) pAnnotParent->arrI.push_back(oObj.getInt()); oObj.free(); } if (!pAnnotParent->arrI.empty()) pAnnotParent->unFlags |= (1 << 3); } oI.free(); Object oOpt; // 6 - Opt if (oField.dictLookup("Opt", &oOpt)->isArray()) { int nOptLength = oOpt.arrayGetLength(); for (int j = 0; j < nOptLength; ++j) { Object oOptJ; if (!oOpt.arrayGet(j, &oOptJ) || !(oOptJ.isString() || oOptJ.isArray())) { oOptJ.free(); continue; } std::string sOpt1, sOpt2; if (oOptJ.isArray() && oOptJ.arrayGetLength() > 1) { Object oOptJ2; if (oOptJ.arrayGet(0, &oOptJ2)->isString()) { TextString* s = new TextString(oOptJ2.getString()); sOpt1 = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength()); delete s; } oOptJ2.free(); if (oOptJ.arrayGet(1, &oOptJ2)->isString()) { TextString* s = new TextString(oOptJ2.getString()); sOpt2 = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength()); delete s; } oOptJ2.free(); } else if (oOptJ.isString()) { TextString* s = new TextString(oOptJ.getString()); sOpt2 = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength()); delete s; } pAnnotParent->arrOpt.push_back(std::make_pair(sOpt1, sOpt2)); oOptJ.free(); } if (!pAnnotParent->arrOpt.empty()) pAnnotParent->unFlags |= (1 << 6); } oOpt.free(); // 7 - Флаг - Ff if (oField.dictLookup("Ff", &oObj)->isInt()) { pAnnotParent->unFieldFlag = oObj.getInt(); pAnnotParent->unFlags |= (1 << 7); } oObj.free(); // 8 - Actions - A/AA Object oAction; if (oField.dictLookup("A", &oAction)->isDict()) { std::string sAA = "A"; CAction* pA = getAction(pdfDoc, &oAction); if (pA) { pA->sType = sAA; pAnnotParent->arrAction.push_back(pA); pAnnotParent->unFlags |= (1 << 8); } } oAction.free(); Object oAA; if (oField.dictLookup("AA", &oAA)->isDict()) { for (int j = 0; j < oAA.dictGetLength(); ++j) { if (oAA.dictGetVal(j, &oAction)->isDict()) { std::string sAA(oAA.dictGetKey(j)); CAction* pA = getAction(pdfDoc, &oAction); if (pA) { pA->sType = sAA; pAnnotParent->arrAction.push_back(pA); pAnnotParent->unFlags |= (1 << 8); } } oAction.free(); } } oAA.free(); // 9 - MaxLen if (oField.dictLookup("MaxLen", &oObj)->isInt()) { pAnnotParent->unMaxLen = oObj.getInt(); pAnnotParent->unFlags |= (1 << 9); } oObj.free(); // 10 - TU if (oField.dictLookup("TU", &oObj)->isString()) { TextString* s = new TextString(oObj.getString()); std::string sStr = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength()); pAnnotParent->unFlags |= (1 << 10); pAnnotParent->sTU = sStr; delete s; } oObj.free(); // 11 - MEOptions if (oField.dictLookup("MEOptions", &oObj)->isInt()) { pAnnotParent->unFlags |= (1 << 11); pAnnotParent->unMEOptions = oObj.getInt(); } oObj.free(); m_arrParents.push_back(pAnnotParent); Object oParentRefObj; if (oField.dictLookupNF("Parent", &oParentRefObj)->isRef()) { pAnnotParent->unFlags |= (1 << 4); pAnnotParent->unRefNumParent = oParentRefObj.getRefNum() + nStartRefID; getParents(pdfDoc, &oParentRefObj, nStartRefID); unsigned int unRefNumParent = pAnnotParent->unRefNumParent; std::vector::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->m_bChangeFullName) return true; unsigned int unRefNumParent = pWidget->GetRefNumParent(); if (unRefNumParent) { std::vector::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)) { const std::string& sFullNameChild = pWidget->GetFullName(); if (sFullNameChild.empty()) pWidget->SetFullName((*it)->sFullName); else pWidget->SetFullName((*it)->sFullName + "." + sFullNameChild); pWidget->m_bChangeFullName = true; return true; } } return pWidget->ChangeFullName(sPrefixForm); } 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->bChangeFullName) return true; if (pParent->unFlags & (1 << 4)) { unsigned int unRefNumParent = pParent->unRefNumParent; std::vector::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)) { if (pParent->sT.empty()) pParent->sFullName = (*it)->sFullName; else pParent->sFullName = (*it)->sFullName + "." + sPrefixForm; pParent->bChangeFullName = true; return true; } } else if (pParent->unFlags & (1 << 0)) { pParent->sT += sPrefixForm; pParent->sFullName += sPrefixForm; pParent->bChangeFullName = true; 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 //------------------------------------------------------------------------ CAnnotMarkup::CAnnotMarkup(PDFDoc* pdfDoc, Object* oAnnotRef, int nPageIndex, int nStartRefID) : CAnnot(pdfDoc, oAnnotRef, nPageIndex, nStartRefID) { m_unFlags = 0; Object oAnnot, oObj; XRef* pXref = pdfDoc->getXRef(); oAnnotRef->fetch(pXref, &oAnnot); // 0 - Всплывающая аннотация - Popup if (oAnnot.dictLookupNF("Popup", &oObj)->isRef()) { m_unFlags |= (1 << 0); m_unRefNumPopup = oObj.getRefNum() + nStartRefID; } // 1 - Текстовая метка пользователя - T m_sT = DictLookupString(&oAnnot, "T", 1); // 2 - Значение непрозрачности - CA if (oAnnot.dictLookup("CA", &oObj)->isNum()) { m_unFlags |= (1 << 2); m_dCA = oObj.getNum(); } oObj.free(); // 3 - Форматированный текст - RC std::string sRC = DictLookupString(&oAnnot, "RC", 3); // std::cout << sRC << std::endl; // if (oAnnot.dictLookup("RC", &oObj)->isStream()) // TODO streamGetBlock m_arrRC = CAnnotMarkup::ReadRC(sRC); if (m_arrRC.empty()) m_unFlags &= ~(1 << 3); else m_unFlags |= (1 << 3); // 4 - Дата создания - CreationDate m_sCreationDate = DictLookupString(&oAnnot, "CreationDate", 4); // 5 - Ссылка на аннотацию ответ - IRT if (oAnnot.dictLookupNF("IRT", &oObj)->isRef()) { m_unFlags |= (1 << 5); m_unAFlags &= ~(1 << 6); // IRT аннотации не отображаются m_unRefNumIRT = oObj.getRefNum() + nStartRefID; } oObj.free(); // 6 - Тип аннотации ответа - RT if (oAnnot.dictLookup("RT", &oObj)->isName()) { m_unFlags |= (1 << 6); m_nRT = 1; // Group if (oObj.isName("R")) m_nRT = 0; } oObj.free(); // 7 - Краткое описание - Subj m_sSubj = DictLookupString(&oAnnot, "Subj", 7); oAnnot.free(); } CAnnotMarkup::~CAnnotMarkup() { for (int i = 0; i < m_arrRC.size(); ++i) RELEASEOBJECT(m_arrRC[i]); } void ReadFontData(const std::string& sData, CAnnotMarkup::CFontData* pFont) { size_t nSemicolon = 0; size_t nColon = sData.find(':'); while (nColon != std::string::npos && nColon > nSemicolon) { std::string sProperty = sData.substr(nSemicolon, nColon - nSemicolon); nSemicolon = sData.find(';', nSemicolon); nColon++; std::string sValue = sData.substr(nColon, nSemicolon - nColon); nColon = sData.find(':', nSemicolon); nSemicolon++; if (sProperty == "font-size") pFont->dFontSise = std::stod(sValue); else if (sProperty == "text-align") { // 0 start / left if (sValue == "center" || sValue == "middle") pFont->nAlign = 1; else if (sValue == "right" || sValue == "end") pFont->nAlign = 2; else if (sValue == "justify") pFont->nAlign = 3; } else if (sProperty == "color") { if (sValue[0] == '#') { sValue = sValue.substr(1); BYTE nColor1 = 0, nColor2 = 0, nColor3 = 0; if (sValue.length() == 6) sscanf(sValue.c_str(), "%2hhx%2hhx%2hhx", &nColor1, &nColor2, &nColor3); else if (sValue.length() == 3) { sscanf(sValue.c_str(), "%1hhx%1hhx%1hhx", &nColor1, &nColor2, &nColor3); nColor1 *= 17; nColor2 *= 17; nColor3 *= 17; } pFont->dColor[0] = (double)nColor1 / 255.0; pFont->dColor[1] = (double)nColor2 / 255.0; pFont->dColor[2] = (double)nColor3 / 255.0; } } else if (sProperty == "font-weight") { // 0 normal / 300 / 400 / 500 if (sValue == "normal" || sValue == "300" || sValue == "400" || sValue == "500") pFont->unFontFlags &= ~(1 << 0); else if (sValue == "bold" || sValue == "bolder" || sValue == "600" || sValue == "700" || sValue == "800" || sValue == "900") pFont->unFontFlags |= (1 << 0); } else if (sProperty == "font-style") { // 0 normal if (sValue == "normal") pFont->unFontFlags &= ~(1 << 1); else if (sValue == "italic" || sValue.find("oblique") != std::string::npos) pFont->unFontFlags |= (1 << 1); } else if (sProperty == "font-family") pFont->sFontFamily = sValue[0] == '\'' ? sValue.substr(1, sValue.length() - 2) : sValue; else if (sProperty == "text-decoration") { if (sValue.find("line-through") != std::string::npos) pFont->unFontFlags |= (1 << 3); if (sValue.find("word") != std::string::npos || sValue.find("underline") != std::string::npos) pFont->unFontFlags |= (1 << 4); if (sValue.find("none") != std::string::npos) { pFont->unFontFlags &= ~(1 << 3); pFont->unFontFlags &= ~(1 << 4); } } else if (sProperty == "vertical-align") { pFont->unFontFlags |= (1 << 5); pFont->dVAlign = std::stod(sValue); if (pFont->dVAlign == 0 && sValue[0] == '-') pFont->dVAlign = -0.01; } // font-stretch } } std::vector CAnnotMarkup::ReadRC(const std::string& sRC) { std::vector arrRC; XmlUtils::CXmlLiteReader oLightReader; if (sRC.empty() || !oLightReader.FromStringA(sRC) || !oLightReader.ReadNextNode() || oLightReader.GetNameA() != "body") return arrRC; CAnnotMarkup::CFontData oFontBase; while (oLightReader.MoveToNextAttribute()) { if (oLightReader.GetNameA() == "style") { ReadFontData(oLightReader.GetTextA(), &oFontBase); break; } } oLightReader.MoveToElement(); int nDepthP = oLightReader.GetDepth(); while (oLightReader.ReadNextSiblingNode2(nDepthP)) { if (oLightReader.GetNameA() != "p") continue; bool bRTL = false; while (oLightReader.MoveToNextAttribute()) { if (oLightReader.GetNameA() == "dir" && oLightReader.GetTextA() == "rtl") { bRTL = true; break; } } oLightReader.MoveToElement(); int nDepthSpan = oLightReader.GetDepth(); if (oLightReader.IsEmptyNode() || !oLightReader.ReadNextSiblingNode2(nDepthSpan)) continue; do { std::string sName = oLightReader.GetNameA(); if (sName == "span") { CAnnotMarkup::CFontData* pFont = new CAnnotMarkup::CFontData(oFontBase); while (oLightReader.MoveToNextAttribute()) { if (oLightReader.GetNameA() == "style") { ReadFontData(oLightReader.GetTextA(), pFont); break; } } oLightReader.MoveToElement(); if (bRTL) pFont->unFontFlags |= (1 << 7); pFont->sText = oLightReader.GetText2A(); arrRC.push_back(pFont); } else if (sName == "#text") { CAnnotMarkup::CFontData* pFont = new CAnnotMarkup::CFontData(oFontBase); if (bRTL) pFont->unFontFlags |= (1 << 7); pFont->sText = oLightReader.GetTextA(); arrRC.push_back(pFont); } } while (oLightReader.ReadNextSiblingNode2(nDepthSpan)); } return arrRC; } void CAnnotMarkup::SetFont(PDFDoc* pdfDoc, Object* oAnnotRef, NSFonts::IFontManager* pFontManager, CPdfFontList *pFontList) { CAnnotFonts::GetFreeTextFont(pdfDoc, pFontManager, pFontList, oAnnotRef, m_arrRC); } //------------------------------------------------------------------------ // Annot //------------------------------------------------------------------------ CAnnot::CAnnot(PDFDoc* pdfDoc, AcroFormField* pField, int nStartRefID) { m_pBorder = NULL; m_unAnnotFlag = 0; m_unAFlags = 0; m_unFlags = 0; Object oObj; pField->getFieldRef(&oObj); m_unRefNum = oObj.getRefNum() + nStartRefID; oObj.free(); // Флаг аннотации - F if (pField->fieldLookup("F", &oObj)->isInt()) m_unAnnotFlag = oObj.getInt(); oObj.free(); // Номер страницы - P m_unPage = pField->getPageNum(); // Координаты - Rect pField->getBBox(&m_pRect[0], &m_pRect[1], &m_pRect[2], &m_pRect[3]); PDFRectangle* pCropBox = pdfDoc->getCatalog()->getPage(m_unPage)->getCropBox(); m_dHeight = pCropBox->y2; m_dX = pCropBox->x1; double dTemp = m_pRect[1]; m_pRect[0] = m_pRect[0] - m_dX; m_pRect[1] = m_dHeight - m_pRect[3]; m_pRect[2] = m_pRect[2] - m_dX; m_pRect[3] = m_dHeight - dTemp; // 0 - Уникальное имя - NM if (pField->fieldLookup("NM", &oObj)->isString()) { m_unAFlags |= (1 << 0); TextString* s = new TextString(oObj.getString()); m_sNM = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength()); delete s; } oObj.free(); // 1 - Альтернативный текст - Contents if (pField->fieldLookup("Contents", &oObj)->isString()) { m_unAFlags |= (1 << 1); TextString* s = new TextString(oObj.getString()); m_sContents = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength()); delete s; } oObj.free(); // 2 - Эффекты границы - BE if (pField->fieldLookup("BE", &oObj)->isDict()) { Object oBorderBE; m_unAFlags |= (1 << 2); m_pBE.first = 0; if (oObj.dictLookup("S", &oBorderBE)->isName("C")) m_pBE.first = 1; oBorderBE.free(); m_pBE.second = 0; if (oObj.dictLookup("I", &oBorderBE)->isNum()) m_pBE.second = oBorderBE.getNum(); oBorderBE.free(); } oObj.free(); // 3 - Специальный цвет для аннотации - C if (pField->fieldLookup("C", &oObj)->isArray()) { m_unAFlags |= (1 << 3); int nCLength = oObj.arrayGetLength(); for (int j = 0; j < nCLength; ++j) { Object oCj; m_arrC.push_back(oObj.arrayGet(j, &oCj)->isNum() ? oCj.getNum() : 0.0); oCj.free(); } } oObj.free(); // 4 - Границы и Dash Pattern - Border/BS m_pBorder = NULL; if (pField->fieldLookup("BS", &oObj)->isDict()) m_pBorder = getBorder(&oObj, true); else { oObj.free(); if (pField->fieldLookup("Border", &oObj)->isArray() && oObj.arrayGetLength() > 2) m_pBorder = getBorder(&oObj, false); } oObj.free(); if (m_pBorder && m_pBorder->nType != 5) m_unAFlags |= (1 << 4); // 5 - Дата последнего изменения - M if (pField->fieldLookup("M", &oObj)->isString()) { m_unAFlags |= (1 << 5); TextString* s = new TextString(oObj.getString()); m_sM = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength()); delete s; } oObj.free(); // 6 - Наличие/Отсутствие внешнего вида if (std::abs(m_pRect[2] - m_pRect[0]) * std::abs(m_pRect[3] - m_pRect[1]) < 1073741824.0 / 3.0 && pField->fieldLookup("AP", &oObj)->isDict() && oObj.dictGetLength()) m_unAFlags |= (1 << 6); oObj.free(); // 7 - User ID if (pField->fieldLookup("OUserID", &oObj)->isString()) { m_unAFlags |= (1 << 7); TextString* s = new TextString(oObj.getString()); m_sOUserID = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength()); delete s; } oObj.free(); // 9 - OO метаданные форм - OMetadata if (pField->fieldLookup("OMetadata", &oObj)->isString()) { m_unAFlags |= (1 << 9); TextString* s = new TextString(oObj.getString()); m_sOMetadata = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength()); delete s; } oObj.free(); } CAnnot::CAnnot(PDFDoc* pdfDoc, Object* oAnnotRef, int nPageIndex, int nStartRefID) { m_pBorder = NULL; m_unAnnotFlag = 0; m_unAFlags = 0; m_unFlags = 0; Object oAnnot, oObj, oObj2; XRef* pXref = pdfDoc->getXRef(); oAnnotRef->fetch(pXref, &oAnnot); // Номер объекта аннотации m_unRefNum = oAnnotRef->getRefNum() + nStartRefID; // Флаг аннотации - F if (oAnnot.dictLookup("F", &oObj)->isInt()) m_unAnnotFlag = oObj.getInt(); oObj.free(); // Номер страницы - P m_unPage = nPageIndex; PDFRectangle* pCropBox = pdfDoc->getCatalog()->getPage(m_unPage)->getCropBox(); m_dHeight = pCropBox->y2; m_dX = pCropBox->x1; // Координаты - Rect m_pRect[0] = 0.0, m_pRect[1] = 0.0, m_pRect[2] = 0.0, m_pRect[3] = 0.0; if (oAnnot.dictLookup("Rect", &oObj)->isArray() && oObj.arrayGetLength() == 4) { m_pRect[0] = ArrGetNum(&oObj, 0) - m_dX; m_pRect[1] = m_dHeight - ArrGetNum(&oObj, 3); m_pRect[2] = ArrGetNum(&oObj, 2) - m_dX; m_pRect[3] = m_dHeight - ArrGetNum(&oObj, 1); } oObj.free(); // 0 - Уникальное имя - NM if (oAnnot.dictLookup("NM", &oObj)->isString()) { m_unAFlags |= (1 << 0); TextString* s = new TextString(oObj.getString()); m_sNM = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength()); delete s; } oObj.free(); // 1 - Альтернативный текст - Contents if (oAnnot.dictLookup("Contents", &oObj)->isString()) { m_unAFlags |= (1 << 1); TextString* s = new TextString(oObj.getString()); m_sContents = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength()); delete s; } oObj.free(); // 2 - Эффекты границы - BE if (oAnnot.dictLookup("BE", &oObj)->isDict()) { Object oBorderBE; m_unAFlags |= (1 << 2); m_pBE.first = 0; if (oObj.dictLookup("S", &oBorderBE)->isName("C")) m_pBE.first = 1; oBorderBE.free(); m_pBE.second = 0; if (oObj.dictLookup("I", &oBorderBE)->isNum()) m_pBE.second = oBorderBE.getNum(); oBorderBE.free(); } oObj.free(); // 3 - Цвет - C if (oAnnot.dictLookup("C", &oObj)->isArray()) { m_unAFlags |= (1 << 3); int nBCLength = oObj.arrayGetLength(); for (int j = 0; j < nBCLength; ++j) { m_arrC.push_back(oObj.arrayGet(j, &oObj2)->isNum() ? oObj2.getNum() : 0.0); oObj2.free(); } } oObj.free(); // 4 - Границы и Dash Pattern - Border/BS m_pBorder = NULL; if (oAnnot.dictLookup("BS", &oObj)->isDict()) m_pBorder = getBorder(&oObj, true); else { oObj.free(); if (oAnnot.dictLookup("Border", &oObj)->isArray() && oObj.arrayGetLength() > 2) m_pBorder = getBorder(&oObj, false); } oObj.free(); if (m_pBorder && m_pBorder->nType != 5) m_unAFlags |= (1 << 4); // 5 - Дата последнего изменения - M if (oAnnot.dictLookup("M", &oObj)->isString()) { m_unAFlags |= (1 << 5); TextString* s = new TextString(oObj.getString()); m_sM = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength()); delete s; } oObj.free(); // 6 - Наличие/Отсутствие внешнего вида if (std::abs(m_pRect[2] - m_pRect[0]) * std::abs(m_pRect[3] - m_pRect[1]) < 1073741824.0 / 3.0 && oAnnot.dictLookup("AP", &oObj)->isDict() && oObj.dictGetLength()) m_unAFlags |= (1 << 6); oObj.free(); // 7 - User ID if (oAnnot.dictLookup("OUserID", &oObj)->isString()) { m_unAFlags |= (1 << 7); TextString* s = new TextString(oObj.getString()); m_sOUserID = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength()); delete s; } oObj.free(); // 9 - OO метаданные форм - OMetadata if (oAnnot.dictLookup("OMetadata", &oObj)->isString()) { m_unAFlags |= (1 << 9); TextString* s = new TextString(oObj.getString()); m_sOMetadata = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength()); delete s; } oObj.free(); oAnnot.free(); } CAnnot::~CAnnot() { RELEASEOBJECT(m_pBorder); } std::string CAnnot::DictLookupString(Object* pObj, const char* sName, int nByte) { std::string sRes; Object oObj; if (pObj->dictLookup(sName, &oObj)->isString()) { m_unFlags |= (1 << nByte); TextString* s = new TextString(oObj.getString()); sRes = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength()); delete s; } oObj.free(); return sRes; } //------------------------------------------------------------------------ // AP //------------------------------------------------------------------------ CAnnotAP::CAnnotAP(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CPdfFontList* pFontList, int nRasterW, int nRasterH, int nBackgroundColor, int nPageIndex, const char* sView, const char* sButtonView, AcroFormField* pField, int nStartRefID) { m_gfx = NULL; m_pFrame = NULL; m_pRendererOut = NULL; m_pRenderer = NULL; m_dRWScale = 1; m_dRHScale = 1; m_bIsStamp = false; Object oAP; if (pField->fieldLookup("AP", &oAP)->isDict() && oAP.dictGetLength()) { // Номер аннотации для сопоставления с AP Object oRef; pField->getFieldRef(&oRef); m_unRefNum = oRef.getRefNum() + nStartRefID; oRef.free(); // Координаты - BBox pField->getBBox(&m_dx1, &m_dy1, &m_dx2, &m_dy2); if (std::abs(m_dx2 - m_dx1) * std::abs(m_dy2 - m_dy1) < 1073741824.0 / 3.0) { Init(pdfDoc, pFontManager, pFontList, nRasterW, nRasterH, nBackgroundColor, nPageIndex); Draw(pdfDoc, &oAP, nRasterH, nBackgroundColor, nPageIndex, pField, sView, sButtonView); } } oAP.free(); Clear(); } CAnnotAP::CAnnotAP(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CPdfFontList* pFontList, int nRasterW, int nRasterH, int nBackgroundColor, int nPageIndex, const char* sView, Object* oAnnotRef, int nStartRefID) { m_gfx = NULL; m_pFrame = NULL; m_pRendererOut = NULL; m_pRenderer = NULL; m_dRWScale = 1; m_dRHScale = 1; Object oAnnot, oAP, oSubtype; XRef* xref = pdfDoc->getXRef(); oAnnotRef->fetch(xref, &oAnnot); m_bIsStamp = oAnnot.dictLookup("Subtype", &oSubtype)->isName("Stamp") == gTrue; if (oAnnot.dictLookup("AP", &oAP)->isDict()) { m_unRefNum = oAnnotRef->getRefNum() + nStartRefID; Init(&oAnnot); if (std::abs(m_dx2 - m_dx1) * std::abs(m_dy2 - m_dy1) < 1073741824.0 / 3.0) { Init(pdfDoc, pFontManager, pFontList, nRasterW, nRasterH, nBackgroundColor, nPageIndex); Draw(pdfDoc, &oAP, nRasterH, nBackgroundColor, oAnnotRef, sView); } } oAP.free(); oAnnot.free(); oSubtype.free(); Clear(); } CAnnotAP::~CAnnotAP() { Clear(); for (int i = 0; i < m_arrAP.size(); ++i) { RELEASEOBJECT(m_arrAP[i]); } } void CAnnotAP::Clear() { RELEASEOBJECT(m_gfx); RELEASEOBJECT(m_pFrame); RELEASEOBJECT(m_pRendererOut); RELEASEOBJECT(m_pRenderer); } void CAnnotAP::Init(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CPdfFontList* pFontList, int nRasterW, int nRasterH, int nBackgroundColor, int nPageIndex) { Page* pPage = pdfDoc->getCatalog()->getPage(nPageIndex); PDFRectangle* pCropBox = pPage->getCropBox(); m_dCropX = pCropBox->x1; m_dCropY = pCropBox->y1; double dWidth = round(pdfDoc->getPageCropWidth(nPageIndex)); double dHeight = round(pdfDoc->getPageCropHeight(nPageIndex)); double dRasterW = (double)nRasterW * m_dRWScale; double dRasterH = (double)nRasterH * m_dRHScale; m_dWScale = dRasterW / dWidth; m_dHScale = dRasterH / dHeight; m_nWidth = (int)round((m_dx2 - m_dx1) * m_dWScale); m_nHeight = (int)round((m_dy2 - m_dy1) * m_dHScale); m_dWTale = m_nWidth - (m_dx2 - m_dx1) * m_dWScale; m_dHTale = m_nHeight - (m_dy2 - m_dy1) * m_dHScale; m_nWidth += 2; m_nHeight += 2; // Отрисовка на прозрачном холсте с заданым цветом фона BYTE* pBgraData = new BYTE[m_nWidth * m_nHeight * 4]; unsigned int nColor = (unsigned int)nBackgroundColor; unsigned int nSize = (unsigned int)(m_nWidth * m_nHeight); unsigned int* pTemp = (unsigned int*)pBgraData; for (unsigned int i = 0; i < nSize; ++i) *pTemp++ = nColor; m_pFrame = new CBgraFrame(); m_pFrame->put_Data(pBgraData); m_pFrame->put_Width(m_nWidth); m_pFrame->put_Height(m_nHeight); m_pFrame->put_Stride(4 * m_nWidth); m_pRenderer = NSGraphics::Create(); m_pRenderer->SetFontManager(pFontManager); m_pRenderer->CreateFromBgraFrame(m_pFrame); m_pRenderer->SetSwapRGB(true); m_pRenderer->put_Width ((m_dx2 - m_dx1 + (2 + m_dWTale) * dWidth / dRasterW) * 25.4 / 72.0); m_pRenderer->put_Height((m_dy2 - m_dy1 + (2 + m_dHTale) * dHeight / dRasterH) * 25.4 / 72.0); if (nBackgroundColor != 0xFFFFFF) m_pRenderer->CommandLong(c_nDarkMode, 1); m_pRenderer->CommandLong(c_nPenWidth0As1px, 1); m_pRendererOut = new RendererOutputDev(m_pRenderer, pFontManager, pFontList); m_pRendererOut->NewPDF(pdfDoc->getXRef()); // Создание Gfx GBool crop = gTrue; PDFRectangle box; // Поворот не требуется pPage->makeBox(72.0, 72.0, 0, gFalse, m_pRendererOut->upsideDown(), -1, -1, -1, -1, &box, &crop); PDFRectangle* cropBox = pPage->getCropBox(); m_gfx = new Gfx(pdfDoc, m_pRendererOut, nPageIndex, pPage->getAttrs()->getResourceDict(), 72.0, 72.0, &box, crop ? cropBox : (PDFRectangle *)NULL, 0, NULL, NULL); // Координаты внешнего вида m_dRx1 = (m_dx1 - m_dCropX) * m_dWScale - 1; m_dRy1 = (pdfDoc->getPageCropHeight(nPageIndex) - m_dy2 + m_dCropY) * m_dHScale - 1; } void CAnnotAP::Init(Object* oAnnot) { Object oObj, oObj2; if (oAnnot->dictLookup("Rect", &oObj)->isArray() && oObj.arrayGetLength() == 4) { m_dx1 = ArrGetNum(&oObj, 0); m_dy1 = ArrGetNum(&oObj, 1); m_dx2 = ArrGetNum(&oObj, 2); m_dy2 = ArrGetNum(&oObj, 3); if (m_bIsStamp) { double m[6] = { 1, 0, 0, 1, 0, 0 }, bbox[4] = { m_dx1, m_dy1, m_dx2, m_dy2 }; oObj.free(); Object oAP; if (oAnnot->dictLookup("AP", &oAP)->isDict() && oAP.dictLookup("N", &oObj2)->isStream()) { Object oObj1; if (oObj2.streamGetDict()->lookup("BBox", &oObj)->isArray() && oObj.arrayGetLength() == 4) { for (int i = 0; i < 4; ++i) { oObj.arrayGet(i, &oObj1); bbox[i] = oObj1.isNum() ? oObj1.getNum() : 0; oObj1.free(); } } oObj.free(); if (oObj2.streamGetDict()->lookup("Matrix", &oObj)->isArray() && oObj.arrayGetLength() == 6) { for (int i = 0; i < 6; ++i) { oObj.arrayGet(i, &oObj1); m[i] = oObj1.getNum(); oObj1.free(); } } } oAP.free(); oObj2.free(); double formXMin, formYMin, formXMax, formYMax, x, y, sx, sy; x = bbox[0] * m[0] + bbox[1] * m[2] + m[4]; y = bbox[0] * m[1] + bbox[1] * m[3] + m[5]; formXMin = formXMax = x; formYMin = formYMax = y; x = bbox[0] * m[0] + bbox[3] * m[2] + m[4]; y = bbox[0] * m[1] + bbox[3] * m[3] + m[5]; if (x < formXMin) formXMin = x; else if (x > formXMax) formXMax = x; if (y < formYMin) formYMin = y; else if (y > formYMax) formYMax = y; x = bbox[2] * m[0] + bbox[1] * m[2] + m[4]; y = bbox[2] * m[1] + bbox[1] * m[3] + m[5]; if (x < formXMin) formXMin = x; else if (x > formXMax) formXMax = x; if (y < formYMin) formYMin = y; else if (y > formYMax) formYMax = y; x = bbox[2] * m[0] + bbox[3] * m[2] + m[4]; y = bbox[2] * m[1] + bbox[3] * m[3] + m[5]; if (x < formXMin) formXMin = x; else if (x > formXMax) formXMax = x; if (y < formYMin) formYMin = y; else if (y > formYMax) formYMax = y; if (formXMin == formXMax) sx = 1; else sx = (m_dx2 - m_dx1) / (formXMax - formXMin); if (formYMin == formYMax) sy = 1; else sy = (m_dy2 - m_dy1) / (formYMax - formYMin); m_dx1 = bbox[0]; m_dy1 = bbox[1]; m_dx2 = bbox[2]; m_dy2 = bbox[3]; m_dRWScale = sx; m_dRHScale = sy; } double dTemp; if (m_dx1 > m_dx2) { dTemp = m_dx1; m_dx1 = m_dx2; m_dx2 = dTemp; } if (m_dy1 > m_dy2) { dTemp = m_dy1; m_dy1 = m_dy2; m_dy2 = dTemp; } } oObj.free(); } void CAnnotAP::Draw(PDFDoc* pdfDoc, Object* oAP, int nRasterH, int nBackgroundColor, int nPageIndex, AcroFormField* pField, const char* sView, const char* sButtonView) { // Отрисовка внешних видов аннотации AcroFormFieldType oType = pField->getAcroFormFieldType(); ((GlobalParamsAdaptor*)globalParams)->setDrawFormField(true); double dOffsetX = -(m_dx1 - m_dCropX) * m_dWScale + 1 + m_dWTale / 2; double dOffsetY = (m_dy2 - m_dCropY) * m_dHScale - nRasterH + 1 + m_dHTale / 2; std::vector arrAPName { "N", "D", "R" }; for (unsigned int j = 0; j < arrAPName.size(); ++j) { if (sView && strcmp(sView, arrAPName[j]) != 0) continue; Object oObj; if (oAP->dictLookup(arrAPName[j], &oObj)->isDict()) { for (int k = 0; k < oObj.dictGetLength(); ++k) { if (sButtonView) { if (strcmp(sButtonView, "Off") == 0 && strcmp(oObj.dictGetKey(k), "Off") != 0) continue; if (strcmp(sButtonView, "Yes") == 0 && strcmp(oObj.dictGetKey(k), "Off") == 0) continue; } CAnnotAPView* pView = new CAnnotAPView(); pView->sAPName = arrAPName[j]; pView->sASName = oObj.dictGetKey(k); if ((oType == acroFormFieldRadioButton || oType == acroFormFieldCheckbox) && pView->sASName != "Off") pView->sASName = "Yes"; m_pRenderer->SetCoordTransformOffset(dOffsetX, dOffsetY); DrawAppearance(pdfDoc, nPageIndex, pField, m_gfx, arrAPName[j], pView->sASName.c_str()); WriteAppearance(nBackgroundColor, pView); pView->nBlendMode = GetBlendMode(); m_arrAP.push_back(pView); } } else if (!oObj.isNull()) { CAnnotAPView* pView = new CAnnotAPView(); pView->sAPName = arrAPName[j]; m_pRenderer->SetCoordTransformOffset(dOffsetX, dOffsetY); DrawAppearance(pdfDoc, nPageIndex, pField, m_gfx, arrAPName[j], NULL); WriteAppearance(nBackgroundColor, pView); pView->nBlendMode = GetBlendMode(); m_arrAP.push_back(pView); } oObj.free(); } ((GlobalParamsAdaptor*)globalParams)->setDrawFormField(false); } void CAnnotAP::Draw(PDFDoc* pdfDoc, Object* oAP, int nRasterH, int nBackgroundColor, Object* oAnnotRef, const char* sView) { ((GlobalParamsAdaptor*)globalParams)->setDrawFormField(true); // Отрисовка внешних видов аннотации Object oAnnot; XRef* xref = pdfDoc->getXRef(); oAnnotRef->fetch(xref, &oAnnot); double dOffsetX = -(m_dx1 - m_dCropX) * m_dWScale + 1 + m_dWTale / 2; double dOffsetY = (m_dy2 - m_dCropY) * m_dHScale - (double)nRasterH * m_dRHScale + 1 + m_dHTale / 2; std::vector arrAPName { "N", "D", "R" }; for (unsigned int j = 0; j < arrAPName.size(); ++j) { if (sView && strcmp(sView, arrAPName[j]) != 0) continue; Object oObj; if (oAP->dictLookup(arrAPName[j], &oObj)->isStream()) { CAnnotAPView* pView = new CAnnotAPView(); pView->sAPName = arrAPName[j]; m_pRenderer->SetCoordTransformOffset(dOffsetX, dOffsetY); Ref ref = oAnnotRef->getRef(); Annot* annot = new Annot(pdfDoc, oAnnot.getDict(), &ref, arrAPName[j]); if (annot) { annot->generateAnnotAppearance(); annot->draw(m_gfx, gFalse); } RELEASEOBJECT(annot); WriteAppearance(nBackgroundColor, pView); pView->nBlendMode = GetBlendMode(); m_arrAP.push_back(pView); } oObj.free(); } oAnnot.free(); ((GlobalParamsAdaptor*)globalParams)->setDrawFormField(false); } void CAnnotAP::WriteAppearance(unsigned int nColor, CAnnotAPView* pView) { BYTE* pSubMatrix = new BYTE[m_nWidth * m_nHeight * 4]; int p = 0; unsigned int* pTemp = (unsigned int*)m_pFrame->get_Data(); unsigned int* pSubTemp = (unsigned int*)pSubMatrix; for (int y = 0; y < m_nHeight; ++y) { for (int x = 0; x < m_nWidth; ++x) { pSubTemp[p++] = pTemp[y * m_nWidth + x]; pTemp[y * m_nWidth + x] = nColor; } } pView->pAP = pSubMatrix; } BYTE CAnnotAP::GetBlendMode() { return 0; } //------------------------------------------------------------------------ // ToWASM //------------------------------------------------------------------------ void CAnnotAP::ToWASM(NSWasm::CData& oRes) { if (m_arrAP.empty()) return; oRes.AddInt(m_unRefNum); oRes.AddDouble(m_dRx1); oRes.AddDouble(m_dRy1); oRes.AddInt(m_nWidth); oRes.AddInt(m_nHeight); oRes.AddInt((unsigned int)m_arrAP.size()); for (int i = 0; i < m_arrAP.size(); ++i) { oRes.WriteString(m_arrAP[i]->sAPName); oRes.WriteString(m_arrAP[i]->sASName); unsigned long long npSubMatrix = (unsigned long long)m_arrAP[i]->pAP; unsigned int npSubMatrix1 = npSubMatrix & 0xFFFFFFFF; oRes.AddInt(npSubMatrix1); oRes.AddInt(npSubMatrix >> 32); oRes.WriteBYTE(m_arrAP[i]->nBlendMode); } } void CAnnots::ToWASM(NSWasm::CData& oRes) { // Порядок вычислений - CO oRes.AddInt(m_arrCO.size()); for (int i = 0; i < m_arrCO.size(); ++i) oRes.AddInt(m_arrCO[i]); // Родительские Fields oRes.AddInt(m_arrParents.size()); for (int i = 0; i < m_arrParents.size(); ++i) m_arrParents[i]->ToWASM(oRes); oRes.AddInt(m_arrAnnots.size()); for (int i = 0; i < m_arrAnnots.size(); ++i) m_arrAnnots[i]->ToWASM(oRes); } void CAnnots::CAnnotParent::ToWASM(NSWasm::CData& oRes) { oRes.AddInt(unRefNum); oRes.AddInt(unFlags); if (unFlags & (1 << 0)) oRes.WriteString(sT); if (unFlags & (1 << 1)) oRes.WriteString(sV); if (unFlags & (1 << 2)) oRes.WriteString(sDV); if (unFlags & (1 << 3)) { oRes.AddInt((unsigned int)arrI.size()); for (int i = 0; i < arrI.size(); ++i) oRes.AddInt(arrI[i]); } if (unFlags & (1 << 4)) oRes.AddInt(unRefNumParent); if (unFlags & (1 << 5)) { oRes.AddInt((unsigned int)arrV.size()); for (int i = 0; i < arrV.size(); ++i) oRes.WriteString(arrV[i]); } if (unFlags & (1 << 6)) { oRes.AddInt(arrOpt.size()); for (int i = 0; i < arrOpt.size(); ++i) { oRes.WriteString(arrOpt[i].first); oRes.WriteString(arrOpt[i].second); } } if (unFlags & (1 << 7)) oRes.AddInt(unFieldFlag); if (unFlags & (1 << 8)) { oRes.AddInt(arrAction.size()); for (int i = 0; i < arrAction.size(); ++i) { oRes.WriteString(arrAction[i]->sType); arrAction[i]->ToWASM(oRes); } } if (unFlags & (1 << 9)) oRes.AddInt(unMaxLen); if (unFlags & (1 << 10)) oRes.WriteString(sTU); if (unFlags & (1 << 11)) oRes.AddInt(unMEOptions); } void CAnnot::ToWASM(NSWasm::CData& oRes) { oRes.AddInt(m_unRefNum); oRes.AddInt(m_unAnnotFlag); oRes.AddInt(m_unPage - 1); for (int i = 0; i < 4; ++i) oRes.WriteDouble(m_pRect[i]); oRes.AddInt(m_unAFlags); if (m_unAFlags & (1 << 0)) oRes.WriteString(m_sNM); if (m_unAFlags & (1 << 1)) oRes.WriteString(m_sContents); if (m_unAFlags & (1 << 2)) { oRes.WriteBYTE(m_pBE.first); oRes.AddDouble(m_pBE.second); } if (m_unAFlags & (1 << 3)) { oRes.AddInt((unsigned int)m_arrC.size()); for (int i = 0; i < m_arrC.size(); ++i) oRes.WriteDouble(m_arrC[i]); } if (m_pBorder && (m_unAFlags & (1 << 4))) m_pBorder->ToWASM(oRes); if (m_unAFlags & (1 << 5)) oRes.WriteString(m_sM); if (m_unAFlags & (1 << 7)) oRes.WriteString(m_sOUserID); if (m_unAFlags & (1 << 9)) oRes.WriteString(m_sOMetadata); } void CAnnot::CBorderType::ToWASM(NSWasm::CData& oRes) { BYTE nBP = nType; if (nBP == 1) nBP = 2; else if (nBP == 2) nBP = 1; oRes.WriteBYTE(nBP); oRes.AddDouble(dWidth); if (nType == annotBorderDashed) { oRes.AddInt(arrDash.size()); for (int i = 0; i < arrDash.size(); ++i) oRes.AddDouble(arrDash[i]); } } void CAnnotWidget::ToWASM(NSWasm::CData& oRes) { oRes.WriteBYTE(m_nType); CAnnot::ToWASM(oRes); oRes.WriteString(m_sFontName); oRes.AddDouble(m_dFontSize); oRes.AddInt(m_unFontStyle); oRes.AddInt(m_arrTC.size()); for (int i = 0; i < m_arrTC.size(); ++i) oRes.WriteDouble(m_arrTC[i]); oRes.WriteBYTE(m_nQ); oRes.AddInt(m_unFieldFlag); oRes.AddInt(m_unFlags); if (m_unFlags & (1 << 0)) oRes.WriteString(m_sTU); if (m_unFlags & (1 << 1)) oRes.WriteString(m_sDS); if (m_unFlags & (1 << 2)) oRes.WriteString(m_sActualFontName); if (m_unFlags & (1 << 3)) oRes.WriteBYTE(m_nH); if (m_unFlags & (1 << 4)) oRes.WriteString(m_sFontKey); if (m_unFlags & (1 << 5)) { oRes.AddInt(m_arrBC.size()); for (int i = 0; i < m_arrBC.size(); ++i) oRes.WriteDouble(m_arrBC[i]); } if (m_unFlags & (1 << 6)) oRes.AddInt(m_unR); if (m_unFlags & (1 << 7)) { oRes.AddInt(m_arrBG.size()); for (int i = 0; i < m_arrBG.size(); ++i) oRes.WriteDouble(m_arrBG[i]); } if (m_unFlags & (1 << 8)) oRes.WriteString(m_sDV); if (m_unFlags & (1 << 17)) oRes.AddInt(m_unRefNumParent); if (m_unFlags & (1 << 18)) oRes.WriteString(m_sT); if (m_unFlags & (1 << 19)) oRes.WriteString(m_sButtonFontName); if (m_unFlags & (1 << 21)) oRes.AddInt(m_unMEOptions); oRes.AddInt(m_arrAction.size()); for (int i = 0; i < m_arrAction.size(); ++i) { oRes.WriteString(m_arrAction[i]->sType); m_arrAction[i]->ToWASM(oRes); } } void CActionGoTo::ToWASM(NSWasm::CData& oRes) { oRes.WriteBYTE(1); oRes.AddInt(unPage); oRes.WriteBYTE(nKind); switch (nKind) { case destXYZ: case destFitH: case destFitBH: case destFitV: case destFitBV: { oRes.WriteBYTE(unKindFlag); if (unKindFlag & (1 << 0)) oRes.AddDouble(pRect[0]); if (unKindFlag & (1 << 1)) oRes.AddDouble(pRect[1]); if (unKindFlag & (1 << 2)) oRes.AddDouble(pRect[3]); break; } case destFitR: { oRes.AddDouble(pRect[0]); oRes.AddDouble(pRect[1]); oRes.AddDouble(pRect[2]); oRes.AddDouble(pRect[3]); break; } case destFit: case destFitB: default: break; } CAction::ToWASM(oRes); } void CActionURI::ToWASM(NSWasm::CData& oRes) { oRes.WriteBYTE(6); oRes.WriteString(sURI); CAction::ToWASM(oRes); } void CActionNamed::ToWASM(NSWasm::CData& oRes) { oRes.WriteBYTE(10); oRes.WriteString(sNamed); CAction::ToWASM(oRes); } void CActionJavaScript::ToWASM(NSWasm::CData& oRes) { oRes.WriteBYTE(14); oRes.WriteString(sJavaScript); CAction::ToWASM(oRes); } void CActionHide::ToWASM(NSWasm::CData& oRes) { oRes.WriteBYTE(9); oRes.WriteBYTE(bHideFlag ? 1 : 0); oRes.AddInt(arrAnnotName.size()); for (int i = 0; i < arrAnnotName.size(); ++i) oRes.WriteString(arrAnnotName[i]); CAction::ToWASM(oRes); } void CActionResetForm::ToWASM(NSWasm::CData& oRes) { oRes.WriteBYTE(12); oRes.AddInt(unFlags); oRes.AddInt(arrAnnotName.size()); for (int i = 0; i < arrAnnotName.size(); ++i) oRes.WriteString(arrAnnotName[i]); CAction::ToWASM(oRes); } void CAction::ToWASM(NSWasm::CData& oRes) { if (pNext) { oRes.WriteBYTE(1); pNext->ToWASM(oRes); } else oRes.WriteBYTE(0); } void CAnnotWidgetBtn::ToWASM(NSWasm::CData& oRes) { CAnnotWidget::ToWASM(oRes); if (m_unFlags & (1 << 9)) oRes.WriteString(m_sV); if (m_nType == 27) { oRes.AddInt(m_unIFFlag); if (m_unFlags & (1 << 10)) oRes.WriteString(m_sCA); if (m_unFlags & (1 << 11)) oRes.WriteString(m_sRC); if (m_unFlags & (1 << 12)) oRes.WriteString(m_sAC); if (m_unFlags & (1 << 13)) oRes.WriteBYTE(m_nTP); if (m_unIFFlag & (1 << 0)) { if (m_unIFFlag & (1 << 1)) oRes.WriteBYTE(m_nSW); if (m_unIFFlag & (1 << 2)) oRes.WriteBYTE(m_nS); if (m_unIFFlag & (1 << 3)) { oRes.AddDouble(m_dA1); oRes.AddDouble(m_dA2); } } } else { oRes.WriteBYTE(m_nStyle); if (m_unFlags & (1 << 14)) oRes.WriteString(m_sAP_N_Yes); } } void CAnnotWidgetTx::ToWASM(NSWasm::CData& oRes) { CAnnotWidget::ToWASM(oRes); if (m_unFlags & (1 << 9)) oRes.WriteString(m_sV); if (m_unFlags & (1 << 10)) oRes.AddInt(m_unMaxLen); if (m_unFlags & (1 << 11)) oRes.WriteString(m_sRV); } void CAnnotWidgetCh::ToWASM(NSWasm::CData& oRes) { CAnnotWidget::ToWASM(oRes); if (m_unFlags & (1 << 9)) oRes.WriteString(m_sV); if (m_unFlags & (1 << 10)) { oRes.AddInt(m_arrOpt.size()); for (int i = 0; i < m_arrOpt.size(); ++i) { oRes.WriteString(m_arrOpt[i].first); oRes.WriteString(m_arrOpt[i].second); } } if (m_unFlags & (1 << 11)) oRes.AddInt(m_unTI); if (m_unFlags & (1 << 12)) { oRes.AddInt(m_arrI.size()); for (int i = 0; i < m_arrI.size(); ++i) oRes.AddInt(m_arrI[i]); } if (m_unFlags & (1 << 13)) { oRes.AddInt(m_arrV.size()); for (int i = 0; i < m_arrV.size(); ++i) oRes.WriteString(m_arrV[i]); } } void CAnnotWidgetSig::ToWASM(NSWasm::CData& oRes) { CAnnotWidget::ToWASM(oRes); } void CAnnotMarkup::ToWASM(NSWasm::CData& oRes) { CAnnot::ToWASM(oRes); oRes.AddInt(m_unFlags); if (m_unFlags & (1 << 0)) oRes.AddInt(m_unRefNumPopup); if (m_unFlags & (1 << 1)) oRes.WriteString(m_sT); if (m_unFlags & (1 << 2)) oRes.AddDouble(m_dCA); if (m_unFlags & (1 << 3)) { oRes.AddInt(m_arrRC.size()); for (int i = 0; i < m_arrRC.size(); ++i) { oRes.WriteBYTE(m_arrRC[i]->nAlign); oRes.AddInt(m_arrRC[i]->unFontFlags); if (m_arrRC[i]->unFontFlags & (1 << 5)) oRes.AddDouble(m_arrRC[i]->dVAlign); if (m_arrRC[i]->unFontFlags & (1 << 6)) oRes.WriteString(m_arrRC[i]->sActualFont); oRes.AddDouble(m_arrRC[i]->dFontSise); oRes.WriteDouble(m_arrRC[i]->dColor[0]); oRes.WriteDouble(m_arrRC[i]->dColor[1]); oRes.WriteDouble(m_arrRC[i]->dColor[2]); oRes.WriteString(m_arrRC[i]->sFontFamily); oRes.WriteString(m_arrRC[i]->sText); } } if (m_unFlags & (1 << 4)) oRes.WriteString(m_sCreationDate); if (m_unFlags & (1 << 5)) oRes.AddInt(m_unRefNumIRT); if (m_unFlags & (1 << 6)) oRes.WriteBYTE(m_nRT); if (m_unFlags & (1 << 7)) oRes.WriteString(m_sSubj); } void CAnnotText::ToWASM(NSWasm::CData& oRes) { oRes.WriteBYTE(0); // Text CAnnotMarkup::ToWASM(oRes); if (m_unFlags & (1 << 16)) oRes.WriteBYTE(m_nName); if (m_unFlags & (1 << 17)) oRes.WriteBYTE(m_nStateModel); if (m_unFlags & (1 << 18)) oRes.WriteBYTE(m_nState); } void CAnnotPopup::ToWASM(NSWasm::CData& oRes) { oRes.WriteBYTE(15); // Popup CAnnot::ToWASM(oRes); oRes.AddInt(m_unFlags); if (m_unFlags & (1 << 1)) oRes.AddInt(m_unRefNumParent); } void CAnnotInk::ToWASM(NSWasm::CData& oRes) { oRes.WriteBYTE(14); // Ink CAnnotMarkup::ToWASM(oRes); oRes.AddInt(m_arrInkList.size()); for (int i = 0; i < m_arrInkList.size(); ++i) { oRes.AddInt(m_arrInkList[i].size()); for (int j = 0; j < m_arrInkList[i].size(); ++j) oRes.AddDouble(m_arrInkList[i][j]); } } void CAnnotLine::ToWASM(NSWasm::CData& oRes) { oRes.WriteBYTE(3); // Line CAnnotMarkup::ToWASM(oRes); for (int i = 0; i < 4; ++i) oRes.AddDouble(m_pL[i]); if (m_unFlags & (1 << 15)) { oRes.WriteBYTE(m_nLE[0]); oRes.WriteBYTE(m_nLE[1]); } if (m_unFlags & (1 << 16)) { oRes.AddInt((unsigned int)m_arrIC.size()); for (int i = 0; i < m_arrIC.size(); ++i) oRes.WriteDouble(m_arrIC[i]); } if (m_unFlags & (1 << 17)) oRes.AddDouble(m_dLL); if (m_unFlags & (1 << 18)) oRes.AddDouble(m_dLLE); if (m_unFlags & (1 << 20)) oRes.WriteBYTE(m_nIT); if (m_unFlags & (1 << 21)) oRes.AddDouble(m_dLLO); if (m_unFlags & (1 << 22)) oRes.WriteBYTE(m_nCP); if (m_unFlags & (1 << 23)) { oRes.AddDouble(m_pCO[0]); oRes.AddDouble(m_pCO[1]); } } void CAnnotTextMarkup::ToWASM(NSWasm::CData& oRes) { oRes.WriteBYTE(m_nSubtype); // Highlight, Underline, Squiggly, StrikeOut CAnnotMarkup::ToWASM(oRes); oRes.AddInt((unsigned int)m_arrQuadPoints.size()); for (int i = 0; i < m_arrQuadPoints.size(); ++i) oRes.AddDouble(m_arrQuadPoints[i]); } void CAnnotSquareCircle::ToWASM(NSWasm::CData& oRes) { oRes.WriteBYTE(m_nSubtype); // Square, Circle CAnnotMarkup::ToWASM(oRes); if (m_unFlags & (1 << 15)) { for (int i = 0; i < 4; ++i) oRes.AddDouble(m_pRD[i]); } if (m_unFlags & (1 << 16)) { oRes.AddInt((unsigned int)m_arrIC.size()); for (int i = 0; i < m_arrIC.size(); ++i) oRes.WriteDouble(m_arrIC[i]); } } void CAnnotPolygonLine::ToWASM(NSWasm::CData& oRes) { oRes.WriteBYTE(m_nSubtype); // Polygon, PolyLine CAnnotMarkup::ToWASM(oRes); oRes.AddInt((unsigned int)m_arrVertices.size()); for (int i = 0; i < m_arrVertices.size(); ++i) oRes.AddDouble(m_arrVertices[i]); if (m_unFlags & (1 << 15)) { oRes.WriteBYTE(m_nLE[0]); oRes.WriteBYTE(m_nLE[1]); } if (m_unFlags & (1 << 16)) { oRes.AddInt((unsigned int)m_arrIC.size()); for (int i = 0; i < m_arrIC.size(); ++i) oRes.WriteDouble(m_arrIC[i]); } if (m_unFlags & (1 << 20)) oRes.WriteBYTE(m_nIT); } void CAnnotFreeText::ToWASM(NSWasm::CData& oRes) { oRes.WriteBYTE(2); // FreeText CAnnotMarkup::ToWASM(oRes); oRes.WriteBYTE(m_nQ); oRes.AddInt(m_nRotate); if (m_unFlags & (1 << 15)) { for (int i = 0; i < 4; ++i) oRes.AddDouble(m_pRD[i]); } if (m_unFlags & (1 << 16)) { oRes.AddInt((unsigned int)m_arrCL.size()); for (int i = 0; i < m_arrCL.size(); ++i) oRes.AddDouble(m_arrCL[i]); } if (m_unFlags & (1 << 17)) oRes.WriteString(m_sDS); if (m_unFlags & (1 << 18)) oRes.WriteBYTE(m_nLE); if (m_unFlags & (1 << 20)) oRes.WriteBYTE(m_nIT); if (m_unFlags & (1 << 21)) { oRes.AddInt((unsigned int)m_arrCFromDA.size()); for (int i = 0; i < m_arrCFromDA.size(); ++i) oRes.WriteDouble(m_arrCFromDA[i]); } } void CAnnotCaret::ToWASM(NSWasm::CData& oRes) { oRes.WriteBYTE(13); // Caret CAnnotMarkup::ToWASM(oRes); if (m_unFlags & (1 << 15)) { for (int i = 0; i < 4; ++i) oRes.AddDouble(m_pRD[i]); } if (m_unFlags & (1 << 16)) oRes.WriteBYTE(m_nSy); } void CAnnotFileAttachment::ToWASM(NSWasm::CData& oRes) { oRes.WriteBYTE(16); // FileAttachment CAnnotMarkup::ToWASM(oRes); if (m_unFlags & (1 << 15)) oRes.WriteString(m_sName); if (m_unFlags & (1 << 16)) oRes.WriteString(m_sFS); if (m_unFlags & (1 << 17)) oRes.WriteString(m_sF); if (m_unFlags & (1 << 18)) oRes.WriteString(m_sUF); if (m_unFlags & (1 << 19)) oRes.WriteString(m_sDOS); if (m_unFlags & (1 << 20)) oRes.WriteString(m_sMac); if (m_unFlags & (1 << 21)) oRes.WriteString(m_sUnix); if (m_unFlags & (1 << 22)) { oRes.WriteString(m_sID.first); oRes.WriteString(m_sID.second); } if (m_unFlags & (1 << 24)) { int nFlag = 0; int nPos = oRes.GetSize(); oRes.AddInt(nFlag); auto fWriteEF = [&oRes](CAnnotFileAttachment::CEmbeddedFile* pEF) { oRes.AddInt(pEF->nLength); unsigned long long npSubMatrix = (unsigned long long)pEF->pFile; unsigned int npSubMatrix1 = npSubMatrix & 0xFFFFFFFF; oRes.AddInt(npSubMatrix1); oRes.AddInt(npSubMatrix >> 32); pEF->bFree = false; }; // Освобождение памяти необходимо вызвать с js стороны if (m_pEF->m_pF) { nFlag |= (1 << 0); fWriteEF(m_pEF->m_pF); } if (m_pEF->m_pUF) { nFlag |= (1 << 1); fWriteEF(m_pEF->m_pUF); } if (m_pEF->m_pDOS) { nFlag |= (1 << 2); fWriteEF(m_pEF->m_pDOS); } if (m_pEF->m_pMac) { nFlag |= (1 << 3); fWriteEF(m_pEF->m_pMac); } if (m_pEF->m_pUnix) { nFlag |= (1 << 4); fWriteEF(m_pEF->m_pUnix); } oRes.AddInt(nFlag, nPos); } if (m_unFlags & (1 << 25)) { } if (m_unFlags & (1 << 26)) oRes.WriteString(m_sDesc); if (m_unFlags & (1 << 27)) { } } void CAnnotStamp::ToWASM(NSWasm::CData& oRes) { oRes.WriteBYTE(12); // Stamp CAnnotMarkup::ToWASM(oRes); oRes.WriteString(m_sName); oRes.WriteDouble(m_dRotate); oRes.WriteDouble(m_dX1); oRes.WriteDouble(m_dY1); oRes.WriteDouble(m_dX2); oRes.WriteDouble(m_dY2); oRes.WriteDouble(m_dX3); oRes.WriteDouble(m_dY3); oRes.WriteDouble(m_dX4); oRes.WriteDouble(m_dY4); } void CAnnotRedact::ToWASM(NSWasm::CData& oRes) { oRes.WriteBYTE(25); // Redact CAnnotMarkup::ToWASM(oRes); if (m_unFlags & (1 << 15)) { oRes.AddInt((unsigned int)m_arrQuadPoints.size()); for (int i = 0; i < m_arrQuadPoints.size(); ++i) oRes.AddDouble(m_arrQuadPoints[i]); } if (m_unFlags & (1 << 16)) { oRes.AddInt((unsigned int)m_arrIC.size()); for (int i = 0; i < m_arrIC.size(); ++i) oRes.WriteDouble(m_arrIC[i]); } if (m_unFlags & (1 << 17)) oRes.WriteString(m_sOverlayText); if (m_unFlags & (1 << 19)) oRes.WriteBYTE(m_nQ); if (m_unFlags & (1 << 20)) { oRes.AddInt((unsigned int)m_arrCFromDA.size()); for (int i = 0; i < m_arrCFromDA.size(); ++i) oRes.WriteDouble(m_arrCFromDA[i]); oRes.AddDouble(m_dFontSize); oRes.WriteString(m_sFontName); oRes.WriteString(m_sActualFontName); oRes.AddInt(m_unFontStyle); } } }