Compare commits

..

18 Commits

Author SHA1 Message Date
eada4b4ebe Merge pull request 'fix/bug79818' (#714) from fix/bug79818 into release/v9.4.0
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/core/pulls/714
2026-03-05 14:51:33 +00:00
57ca5da2c0 fix/bug79818
fix bug #79818
2026-03-05 13:36:32 +03:00
08bad0753a Merge pull request 'Fix bug 80374' (#713) from fix/bug80374 into release/v9.4.0
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/core/pulls/713
2026-03-05 10:11:56 +00:00
6224b6384d Fix prev 2026-03-05 12:59:26 +03:00
be1aed4cae Fix bug 80374 2026-03-05 12:27:40 +03:00
3676400e66 Merge branch release/v9.3.0 into release/v9.4.0 2026-03-04 09:17:05 +00:00
3b0c9cea7e Merge pull request 'Fix swap rgba for djvu' (#711) from fix/bug-75351 into release/v9.4.0
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/core/pulls/711
2026-03-03 13:34:27 +00:00
3dc0f482c8 Fix swap rgba for djvu 2026-03-03 16:21:20 +03:00
d17c22772f Merge pull request 'Fix bug 80395' (#708) from fix/bug-80395 into release/v9.4.0
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/core/pulls/708
2026-03-02 14:21:35 +00:00
2a09f9da90 Fix bug 80395 2026-03-02 17:05:50 +03:00
df576b6e99 Merge pull request 'fix/fix-bugs' (#703) from fix/fix-bugs into release/v9.4.0
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/core/pulls/703
2026-02-26 15:23:19 +00:00
b430c3f296 fix bug #78514 2026-02-26 14:26:41 +03:00
c21827825b fix bug #79266 2026-02-26 13:22:58 +03:00
0424c73db0 Merge pull request 'fix/fix-bugs' (#700) from fix/fix-bugs into release/v9.4.0
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/core/pulls/700
2026-02-25 16:54:14 +00:00
dc6a72892c Merge branch 'release/v9.4.0' into fix/fix-bugs 2026-02-25 19:47:12 +03:00
927f49291a Merge branch release/v9.3.0 into develop 2026-02-25 15:14:16 +00:00
cf72c836a1 fix bug #79708 2026-02-24 12:33:36 +03:00
b9a905f6b2 fix bug #80221 2026-02-24 11:37:37 +03:00
17 changed files with 369 additions and 75 deletions

View File

@ -726,7 +726,7 @@ unsigned char* CDjVuFileImplementation::ConvertToPixels(int nPageIndex, int nRas
GP<DjVuImage> pPage = m_pDoc->get_page(nPageIndex);
//pPage->wait_for_complete_decode();
pPage->set_rotate(0);
return ConvertToPixels(pPage, nRasterW, nRasterH, bIsFlip);
return ConvertToPixels(pPage, nRasterW, nRasterH, bIsFlip, true);
}
catch (...)
{
@ -734,11 +734,11 @@ unsigned char* CDjVuFileImplementation::ConvertToPixels(int nPageIndex, int nRas
return NULL;
}
unsigned char* CDjVuFileImplementation::ConvertToPixels(GP<DjVuImage>& pPage, int nImageW, int nImageH, bool bFlip)
unsigned char* CDjVuFileImplementation::ConvertToPixels(GP<DjVuImage>& pPage, int nImageW, int nImageH, bool bFlip, bool bIsSwapRGB)
{
BYTE* pBufferDst = NULL;
auto processPixmap = [&](GP<GPixmap> pImage, bool bFlip = false)
auto processPixmap = [&](GP<GPixmap> pImage, bool bFlip = false, bool bIsSwapRGB = false)
{
pBufferDst = new BYTE[4 * nImageW * nImageH];
@ -749,7 +749,10 @@ unsigned char* CDjVuFileImplementation::ConvertToPixels(GP<DjVuImage>& pPage, in
GPixel* pLine = pImage->operator[](nRow);
for (int i = 0; i < nImageW; ++i)
{
*pBuffer++ = 0xFF000000 | pLine->r << 16 | pLine->g << 8 | pLine->b;
if (bIsSwapRGB)
*pBuffer++ = 0xFF000000 | pLine->b << 16 | pLine->g << 8 | pLine->r;
else
*pBuffer++ = 0xFF000000 | pLine->r << 16 | pLine->g << 8 | pLine->b;
++pLine;
}
}
@ -790,7 +793,7 @@ unsigned char* CDjVuFileImplementation::ConvertToPixels(GP<DjVuImage>& pPage, in
if (pPage->is_legal_photo() || pPage->is_legal_compound())
{
GP<GPixmap> pImage = pPage->get_pixmap(oRectAll, oRectAll);
processPixmap(pImage, bFlip);
processPixmap(pImage, bFlip, bIsSwapRGB);
}
else if (pPage->is_legal_bilevel())
{
@ -802,7 +805,7 @@ unsigned char* CDjVuFileImplementation::ConvertToPixels(GP<DjVuImage>& pPage, in
GP<GPixmap> pImage = pPage->get_pixmap(oRectAll, oRectAll);
if (pImage)
{
processPixmap(pImage, bFlip);
processPixmap(pImage, bFlip, bIsSwapRGB);
}
else
{

View File

@ -83,7 +83,7 @@ public:
private:
unsigned char* ConvertToPixels(GP<DjVuImage>& pPage, int nRasterW, int nRasterH, bool bIsFlip = false);
unsigned char* ConvertToPixels(GP<DjVuImage>& pPage, int nRasterW, int nRasterH, bool bIsFlip = false, bool bIsSwapRGB = false);
void CreateFrame(IRenderer* pRenderer, GP<DjVuImage>& pImage, int nPage, XmlUtils::CXmlNode& oText);
void CreatePdfFrame(IRenderer* pRenderer, GP<DjVuImage>& pImage, int nPage, XmlUtils::CXmlNode& oText);

View File

@ -267,7 +267,7 @@ namespace SimpleTypes
std::wstring CGuid::ToString (bool braces) const
{
std::wstringstream sstream;
sstream << boost::wformat( L"%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X" ) % m_oGUID.a % m_oGUID.b % m_oGUID.c % m_oGUID.d % m_oGUID.e % m_oGUID.f % m_oGUID.g % m_oGUID.h % m_oGUID.i % m_oGUID.j % m_oGUID.k;
sstream << boost::wformat( L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" ) % m_oGUID.a % m_oGUID.b % m_oGUID.c % m_oGUID.d % m_oGUID.e % m_oGUID.f % m_oGUID.g % m_oGUID.h % m_oGUID.i % m_oGUID.j % m_oGUID.k;
std::wstring res = (braces ? L"{" : L"") + sstream.str() + (braces ? L"}" : L"");
return res;
}

View File

@ -227,7 +227,7 @@ namespace OOX
}
//------------------------------------------------------------------------------------------------------------------------
CDocument::CDocument(OOX::Document *pMain, OOX::FileType type)
: File(pMain), IFileContainer(pMain), WritingElement(pMain)
: File(pMain), IFileContainer(pMain), WritingElementWithChilds<>(pMain)
{
m_bMacroEnabled = false;
@ -254,7 +254,7 @@ namespace OOX
}
}
CDocument::CDocument(OOX::Document *pMain, const CPath& oRootPath, const CPath& oPath, OOX::FileType type)
: File(pMain), IFileContainer(pMain), WritingElement(pMain)
: File(pMain), IFileContainer(pMain), WritingElementWithChilds<>(pMain)
{
m_bMacroEnabled = false;
@ -302,13 +302,13 @@ namespace OOX
docx->m_bGlossaryRead = false;
}
}
CDocument::CDocument(XmlUtils::CXmlNode& oNode) : File(NULL), IFileContainer(NULL), WritingElement(NULL)
CDocument::CDocument(XmlUtils::CXmlNode& oNode) : File(NULL), IFileContainer(NULL), WritingElementWithChilds<>(NULL)
{
m_bMacroEnabled = false;
fromXML( oNode );
}
CDocument::CDocument(XmlUtils::CXmlLiteReader& oReader) : File(NULL), IFileContainer(NULL), WritingElement(NULL)
CDocument::CDocument(XmlUtils::CXmlLiteReader& oReader) : File(NULL), IFileContainer(NULL), WritingElementWithChilds<>(NULL)
{
m_bMacroEnabled = false;
@ -403,8 +403,7 @@ namespace OOX
{
if (document->m_arrSections.empty())
{
OOX::CDocument::_section section;
document->m_arrSections.push_back(section);
document->m_arrSections.emplace_back();
}
document->m_arrSections.back().sect = m_oSectPr.GetPointer();
document->m_arrSections.back().end_elm = document->m_arrItems.size(); //активный рутовый еще не добавлен
@ -492,11 +491,7 @@ namespace OOX
void CDocument::ClearItems()
{
for ( size_t i = 0; i < m_arrItems.size(); ++i)
{
if ( m_arrItems[i] )delete m_arrItems[i];
}
m_arrItems.clear();
WritingElementWithChilds<>::ClearItems();
//----------
m_arrSections.clear();
}

View File

@ -127,7 +127,7 @@ namespace OOX
//--------------------------------------------------------------------------------
// CDocument 17.2.3 (Part 1)
//--------------------------------------------------------------------------------
class CDocument : public OOX::File, public IFileContainer, public WritingElement
class CDocument : public OOX::File, public IFileContainer, public WritingElementWithChilds<>
{
public:
CDocument(OOX::Document *pMain = NULL, OOX::FileType type = OOX::FileTypes::Document);
@ -171,8 +171,6 @@ namespace OOX
nullable<OOX::Logic::CSectionProperty> m_oSectPr;
nullable<OOX::Logic::CBackground> m_oBackground;
std::vector<WritingElement*> m_arrItems;
//---------------------------------------------------------------------------------------------
struct _section
{

View File

@ -185,10 +185,10 @@ namespace OOX
{
if (m_oParagraphProperty)
{
CParagraphProperty prop2(oItem);
CParagraphProperty newProp = CParagraphProperty::Merge(*m_oParagraphProperty, prop2);
pItem = m_oParagraphProperty = new CParagraphProperty(newProp);
pItem = new CParagraphProperty(*m_oParagraphProperty);
pItem->fromXML(oItem);
m_oParagraphProperty = dynamic_cast<CParagraphProperty*>(pItem);
}
else
{
@ -331,12 +331,10 @@ namespace OOX
{// c копией .. для быстрого доступа/анализа
if (m_oParagraphProperty)
{
CParagraphProperty prop2(document);
prop2.fromXML(oReader);
pItem = new CParagraphProperty(*m_oParagraphProperty);
pItem->m_pMainDocument = document;
pItem = m_oParagraphProperty = new CParagraphProperty(CParagraphProperty::Merge(*m_oParagraphProperty, prop2));
m_arrItems.push_back( pItem );
continue;
m_oParagraphProperty = dynamic_cast<CParagraphProperty*>(pItem);
}
else
{
@ -383,9 +381,21 @@ namespace OOX
}
else if (L"p" == sName)
{
int nDepthChild = oReader.GetDepth();
fromXML(nDepthChild, oReader);
WritingElementWithChilds* parent = dynamic_cast<WritingElementWithChilds*>(m_oParent);
if (parent)
{
WritingElement* pItemUpper = new CParagraph(document, parent);
if (pItemUpper)
{
pItemUpper->fromXML(oReader);
parent->m_arrItems.push_back(pItemUpper);
}
}
else
{
int nDepthChild = oReader.GetDepth();
fromXML(nDepthChild, oReader);
}
}
if ( pItem )
{

View File

@ -582,7 +582,7 @@ namespace OOX
}
}
}
void CParagraphProperty::fromXML(XmlUtils::CXmlLiteReader& oReader)
void CParagraphProperty::fromXML(XmlUtils::CXmlLiteReader& oReader/*, bool bEmbedded*/)
{
if ( oReader.IsEmptyNode() )
return;
@ -659,15 +659,13 @@ namespace OOX
if (doc->m_arrSections.empty())
{
OOX::CDocument::_section section;
doc->m_arrSections.push_back(section);
doc->m_arrSections.emplace_back();
}
doc->m_arrSections.back().sect = m_oSectPr.GetPointer();
doc->m_arrSections.back().end_elm = doc->m_arrItems.size() + 1; // порядок выше - сначала читаем, потом добавляем
OOX::CDocument::_section section;
section.start_elm = doc->m_arrItems.size() + 1;
doc->m_arrSections.push_back(section);
doc->m_arrSections.emplace_back();
doc->m_arrSections.back().start_elm = doc->m_arrItems.size() + 1;
}
}
}

View File

@ -1225,6 +1225,7 @@ namespace OOX
}break;
case 1:
{
pReader->Skip(4); // size
content = pReader->GetString2();
}break;
default:

View File

@ -443,9 +443,10 @@ void embeddings::write(const std::wstring & RootPath)
items[i].type == typeControlProps ||
items[i].type == typeControl))
{
size_t pos_off = items[i].outputName.rfind(L"/");
size_t pos = items[i].outputName.rfind(L".");
int pos = items[i].outputName.rfind(L".");
std::wstring extension = pos >= 0 ? items[i].outputName.substr(pos + 1) : L"";
std::wstring extension = (pos != std::wstring::npos && pos > pos_off) ? items[i].outputName.substr(pos + 1) : L"";
content_types.add_or_find_default(extension);

View File

@ -160,7 +160,7 @@ void paragraph_format_properties::docx_convert(oox::docx_conversion_context & Co
}
if (Context.get_rtl()) //может быть он установился от стиля родителя !!
{
_pPr << L"<w:bidi/>";
_pPr << L"<w:bidi w:val=\"1\"/>";
}
odf_reader::list_style_container & list_styles = Context.root()->odf_context().listStyleContainer();
@ -233,6 +233,15 @@ void paragraph_format_properties::docx_convert(oox::docx_conversion_context & Co
case text_align::End: jc = Context.get_rtl() ? L"start": L"end"; break;
}
if( Context.get_rtl() )
{
switch(fo_text_align_->get_type())
{
case text_align::Left: jc = L"right"; break;
case text_align::Right: jc = L"left"; break;
}
}
if (!jc.empty()) CP_XML_NODE(L"w:jc"){CP_XML_ATTR(L"w:val", jc );}
}
else if (fo_keep_with_next_) //&& Context.get_drop_cap_context().state() != 2

View File

@ -155,11 +155,11 @@ namespace utils//////////////////////////////////////////// ОБЩАЯ хрен
{
nDate = boost::lexical_cast<__int64>(oox_date_time);
}
bool bPT = (nDate < 1);
std::wstring sDate, sTime;
if (dTime > 0)
{
sTime = convert_time(dTime, false);
sTime = convert_time(dTime, bPT);
}
if (nDate > 0)
{
@ -177,7 +177,14 @@ namespace utils//////////////////////////////////////////// ОБЩАЯ хрен
}
else
{
odf_date_time = sDate + (sTime.empty() ? L"" : L"T" + sTime);
if (bPT)
{
odf_date_time = L"PT" + sTime;
}
else
{
odf_date_time = sDate + (sTime.empty() ? L"" : L"T" + sTime);
}
}
return res;
}

View File

@ -416,7 +416,49 @@ PdfWriter::CObjectBase* DictToCDictObject2(Object* obj, PdfWriter::CDocument* pD
for (int nIndex = 0; nIndex < obj->dictGetLength(); ++nIndex)
{
char* chKey = obj->dictGetKey(nIndex);
obj->dictGetValNF(nIndex, &oTemp);
if (strcmp("Resources", chKey) == 0)
{
Ref oResourcesRef = { -1, -1 };
if (obj->dictGetValNF(nIndex, &oTemp)->isRef())
oResourcesRef = oTemp.getRef();
oTemp.free();
PdfWriter::CObjectBase* pObj = oResourcesRef.num > 0 ? pManager->GetObj(oResourcesRef.num + nStartRefID) : NULL;
if (pObj)
{
pDict->Add(chKey, pObj);
pManager->IncRefCount(oResourcesRef.num + nStartRefID);
continue;
}
if (obj->dictGetVal(nIndex, &oTemp)->isDict())
{
PdfWriter::CResourcesDict* pResDict = pDoc->CreateResourcesDict(oResourcesRef.num < 0, false);
if (oResourcesRef.num > 0)
pManager->AddObj(oResourcesRef.num + nStartRefID, pResDict);
pDict->Add(chKey, pResDict);
for (int nIndex2 = 0; nIndex2 < oTemp.dictGetLength(); ++nIndex2)
{
Object oRes;
char* chKey2 = oTemp.dictGetKey(nIndex2);
oTemp.dictGetValNF(nIndex2, &oRes);
pBase = DictToCDictObject2(&oRes, pDoc, xref, pManager, nStartRefID, 0, bUndecodedStream);
pResDict->Add(chKey2, pBase);
oRes.free();
}
pResDict->Fix();
oTemp.free();
continue;
}
else
{
oTemp.free();
obj->dictGetValNF(nIndex, &oTemp);
}
}
else
obj->dictGetValNF(nIndex, &oTemp);
pBase = DictToCDictObject2(&oTemp, pDoc, xref, pManager, nStartRefID, 0, bUndecodedStream);
pDict->Add(chKey, pBase);
oTemp.free();
@ -470,7 +512,49 @@ PdfWriter::CObjectBase* DictToCDictObject2(Object* obj, PdfWriter::CDocument* pD
oTemp.free();
continue;
}
pODict->getValNF(nIndex, &oTemp);
else if (strcmp("Resources", chKey) == 0)
{
Ref oResourcesRef = { -1, -1 };
if (pODict->getValNF(nIndex, &oTemp)->isRef())
oResourcesRef = oTemp.getRef();
oTemp.free();
PdfWriter::CObjectBase* pObj = oResourcesRef.num > 0 ? pManager->GetObj(oResourcesRef.num + nStartRefID) : NULL;
if (pObj)
{
pDict->Add(chKey, pObj);
pManager->IncRefCount(oResourcesRef.num + nStartRefID);
continue;
}
if (pODict->getVal(nIndex, &oTemp)->isDict())
{
PdfWriter::CResourcesDict* pResDict = pDoc->CreateResourcesDict(oResourcesRef.num < 0, false);
if (oResourcesRef.num > 0)
pManager->AddObj(oResourcesRef.num + nStartRefID, pResDict);
pDict->Add(chKey, pResDict);
for (int nIndex2 = 0; nIndex2 < oTemp.dictGetLength(); ++nIndex2)
{
Object oRes;
char* chKey2 = oTemp.dictGetKey(nIndex2);
oTemp.dictGetValNF(nIndex2, &oRes);
pBase = DictToCDictObject2(&oRes, pDoc, xref, pManager, nStartRefID, 0, bUndecodedStream);
pResDict->Add(chKey2, pBase);
oRes.free();
}
pResDict->Fix();
oTemp.free();
continue;
}
else
{
oTemp.free();
pODict->getValNF(nIndex, &oTemp);
}
}
else
pODict->getValNF(nIndex, &oTemp);
pBase = DictToCDictObject2(&oTemp, pDoc, xref, pManager, nStartRefID);
pDict->Add(chKey, pBase);
oTemp.free();
@ -2337,11 +2421,11 @@ bool CPdfEditor::SplitPages(const int* arrPageIndex, unsigned int unLength, PDFD
if (oResourcesRef.num > 0)
m_mObjManager.AddObj(oResourcesRef.num + nStartRefID, pDict);
pPage->Add(chKey, pDict);
for (int nIndex = 0; nIndex < oTemp.dictGetLength(); ++nIndex)
for (int nIndex2 = 0; nIndex2 < oTemp.dictGetLength(); ++nIndex2)
{
Object oRes;
char* chKey2 = oTemp.dictGetKey(nIndex);
oTemp.dictGetValNF(nIndex, &oRes);
char* chKey2 = oTemp.dictGetKey(nIndex2);
oTemp.dictGetValNF(nIndex2, &oRes);
PdfWriter::CObjectBase* pBase = DictToCDictObject2(&oRes, pDoc, xref, &m_mObjManager, nStartRefID);
pDict->Add(chKey2, pBase);
oRes.free();
@ -4051,7 +4135,35 @@ void CPdfEditor::ClearPage()
pageObj.free();
if (m_nMode == Mode::Split || m_nMode == Mode::WriteNew)
{
PdfWriter::CPage* pPage = pDoc->GetCurPage();
auto removeContentObj = [&](PdfWriter::CObjectBase* pObj)
{
if (pObj->GetType() == PdfWriter::object_type_DICT)
{
PdfWriter::CObjectBase* pLength = ((PdfWriter::CDictObject*)pObj)->Get("Length");
if (pLength)
{
int nLengthID = m_mObjManager.FindObj(pLength);
m_mObjManager.RemoveObj(nLengthID);
}
}
int nObjID = m_mObjManager.FindObj(pObj);
m_mObjManager.RemoveObj(nObjID);
};
PdfWriter::CObjectBase* pObjContents = pPage->Get("Contents");
if (pObjContents && pObjContents->GetType() == PdfWriter::object_type_ARRAY)
{
PdfWriter::CArrayObject* pContents = (PdfWriter::CArrayObject*)pObjContents;
for (int i = 0; i < pContents->GetCount(); ++i)
removeContentObj(pContents->Get(i));
}
else if (pObjContents)
removeContentObj(pObjContents);
pDoc->ClearPageFull();
}
else
pDoc->ClearPage();

View File

@ -521,6 +521,7 @@ void ApplyRedactToGray(const std::vector<double>& arrQuadPoints, BYTE* pImage, i
RedactOutputDev::RedactOutputDev(CPdfWriter* pRenderer, CObjectsManager* pObjMng, int nStartRefID)
{
m_pXref = NULL;
m_pResources = NULL;
m_pRenderer = pRenderer;
m_mObjManager = pObjMng;
@ -565,6 +566,32 @@ void RedactOutputDev::startPage(int nPageIndex, GfxState *pGState)
m_pPage = m_pDoc->GetEditPage(nPageIndex);
m_pRenderer->EditPage(m_pPage);
m_pDoc->SetCurPage(m_pPage);
auto removeContentObj = [&](PdfWriter::CObjectBase* pObj)
{
if (pObj->GetType() == PdfWriter::object_type_DICT)
{
PdfWriter::CObjectBase* pLength = ((PdfWriter::CDictObject*)pObj)->Get("Length");
if (pLength)
{
int nLengthID = m_mObjManager->FindObj(pLength);
m_mObjManager->RemoveObj(nLengthID);
}
}
int nObjID = m_mObjManager->FindObj(pObj);
m_mObjManager->RemoveObj(nObjID);
};
PdfWriter::CObjectBase* pObjContents = m_pPage->Get("Contents");
if (pObjContents && pObjContents->GetType() == PdfWriter::object_type_ARRAY)
{
PdfWriter::CArrayObject* pContents = (PdfWriter::CArrayObject*)pObjContents;
for (int i = 0; i < pContents->GetCount(); ++i)
removeContentObj(pContents->Get(i));
}
else if (pObjContents)
removeContentObj(pObjContents);
m_pDoc->ClearPageFull();
}
void RedactOutputDev::endPage()
@ -1374,11 +1401,16 @@ void RedactOutputDev::drawForm(GfxState *pGState, Gfx *gfx, Ref id, const char*
pObj = pOrigForm->Get("Matrix");
if (pObj)
pNewForm->Add("Matrix", pObj->Copy());
PdfWriter::CResourcesDict* pNewResources = NULL;
pObj = pOrigForm->Get("Resources");
if (pObj)
{
pNewForm->Add("Resources", pObj->Copy());
pNewResources = dynamic_cast<CResourcesDict*>(pNewForm->Get("Resources"));
}
PdfWriter::CResourcesDict* pResources = GetResources(gfx);
PdfWriter::CResourcesDict* pResources = GetResources(gfx, pNewForm);
if (pResources)
name = pResources->GetXObjectName(pNewForm);
@ -1391,6 +1423,7 @@ void RedactOutputDev::drawForm(GfxState *pGState, Gfx *gfx, Ref id, const char*
RedactOutputDev* pFormOutputDev = new RedactOutputDev(m_pRenderer, m_mObjManager, m_nStartRefID);
pFormOutputDev->NewPDF(m_pXref);
pFormOutputDev->m_pPage = pFakePage;
pFormOutputDev->m_pResources = pNewResources;
std::vector<double> arrFormQuadPoints;
double dInvMatrix[6] = { 1, 0, 0, 1, 0, 0 };
InvertMatrix(m_arrMatrix, dInvMatrix);
@ -1886,8 +1919,11 @@ CObjectBase* RedactOutputDev::CreateImage(Gfx *gfx, int nWidth, int nHeight, uns
return pObj;
}
CResourcesDict* RedactOutputDev::GetResources(Gfx *gfx)
CResourcesDict* RedactOutputDev::GetResources(Gfx *gfx, CDictObject* pNewForm)
{
if (m_pResources)
return m_pResources;
PdfWriter::CResourcesDict* pResources = NULL;
Object* pContent = gfx->getTopContentStreamStack();
if (pContent && pContent->isRef())
@ -1901,7 +1937,7 @@ CResourcesDict* RedactOutputDev::GetResources(Gfx *gfx)
if (!pResources)
{
pResources = new PdfWriter::CResourcesDict(NULL, true, false);
pDictForm->Add("Resources", pResources);
(pNewForm ? pNewForm : pDictForm)->Add("Resources", pResources);
}
}
}

View File

@ -201,11 +201,12 @@ namespace PdfWriter
void DoStateOp();
void DrawXObject(const char* name);
CObjectBase* CreateImage(Gfx *gfx, int nWidth, int nHeight, unsigned int nFilter, int nBPC, const char* sCS);
CResourcesDict* GetResources(Gfx *gfx);
CResourcesDict* GetResources(Gfx *gfx, CDictObject* pNewForm = NULL);
XRef* m_pXref;
std::vector<double> m_arrQuadPoints;
Aggplus::CGraphicsPath m_oPathRedact;
CResourcesDict* m_pResources;
CPdfWriter* m_pRenderer;
CObjectsManager* m_mObjManager;

View File

@ -67,6 +67,19 @@ namespace PdfWriter
pProcset->Add(new CNameObject("ImageI"));
}
}
CObjectBase* CResourcesDict::Copy(CObjectBase* pOut) const
{
CResourcesDict* pDict = pOut && pOut->GetType() == object_type_DICT ? dynamic_cast<CResourcesDict*>(pOut) : new CResourcesDict(NULL, true, false);
if (!pDict)
return NULL;
for (auto const &oIter : m_mList)
pDict->Add(oIter.first, oIter.second->Copy());
pDict->Fix();
return pDict;
}
const char* CResourcesDict::GetFontName(CFontDict* pFont)
{
if (!m_pFonts)

View File

@ -46,6 +46,8 @@ namespace PdfWriter
public:
CResourcesDict(CXref* pXref, bool bInline, bool bProcSet);
virtual CObjectBase* Copy(CObjectBase* pOut) const override;
const char* GetFontName(CFontDict* pFont);
const char* GetExtGrStateName(CExtGrState* pState);
const char* GetXObjectName(CObjectBase* pXObject);

View File

@ -46,6 +46,60 @@
namespace Txt2Docx
{
namespace
{
bool isEmoji(const std::string& utf8Char)
{
if (utf8Char.empty()) return false;
unsigned char c = utf8Char[0];
uint32_t codePoint = 0;
if ((c & 0xF8) == 0xF0 && utf8Char.length() >= 4)
{
codePoint = ((utf8Char[0] & 0x07) << 18) |
((utf8Char[1] & 0x3F) << 12) |
((utf8Char[2] & 0x3F) << 6) |
(utf8Char[3] & 0x3F);
}
else if ((c & 0xF0) == 0xE0 && utf8Char.length() >= 3)
{
codePoint = ((utf8Char[0] & 0x0F) << 12) |
((utf8Char[1] & 0x3F) << 6) |
(utf8Char[2] & 0x3F);
}
else
{
return false;
}
return (codePoint >= 0x1F300 && codePoint <= 0x1F9FF) ||
(codePoint >= 0x2600 && codePoint <= 0x27BF) ||
(codePoint >= 0x2B00 && codePoint <= 0x2BFF) ||
(codePoint >= 0xFE00 && codePoint <= 0xFE0F) ||
(codePoint >= 0x1F900 && codePoint <= 0x1F9FF) ||
codePoint == 0x00A9 || codePoint == 0x00AE;
}
std::string escapeXml(const std::string& text)
{
std::string result;
result.reserve(text.length() * 2);
for (char ch : text)
{
switch (ch)
{
case '&': result += "&amp;"; break;
case '<': result += "&lt;"; break;
case '>': result += "&gt;"; break;
case '"': result += "&quot;"; break;
case '\'': result += "&apos;"; break;
default: result += ch; break;
}
}
return result;
}
}
class Converter_Impl
{
public:
@ -158,8 +212,8 @@ namespace Txt2Docx
void Converter::write(NSStringUtils::CStringBuilderA &stringWriter)
{
const char* fontName = "Courier New";
const char* emojiFontName = "Segoe UI Emoji";
const char* defaultSpacing = "<w:spacing w:after=\"0\" w:line=\"240\" w:lineRule=\"auto\"/>";
for (const std::string &lineRaw : converter_->m_inputFile.m_listContentutf8)
{
std::string line = lineRaw;
@ -176,32 +230,86 @@ namespace Txt2Docx
stringWriter.WriteString(fontName);
stringWriter.WriteString("\"/></w:rPr></w:pPr>");
size_t start = 0;
while (true)
size_t i = 0;
while (i < line.length())
{
size_t pos = line.find('\x09', start);
std::string segment = (pos == std::string::npos) ? line.substr(start) : line.substr(start, pos - start);
unsigned char c = line[i];
if (!segment.empty())
if ((c & 0xF0) == 0xF0 || (c & 0xE0) == 0xE0)
{
stringWriter.WriteString("<w:r><w:rPr><w:rFonts w:ascii=\"");
stringWriter.WriteString(fontName);
stringWriter.WriteString("\" w:hAnsi=\"");
stringWriter.WriteString(fontName);
stringWriter.WriteString("\" w:cs=\"");
stringWriter.WriteString(fontName);
stringWriter.WriteString("\"/></w:rPr><w:t xml:space=\"preserve\">");
stringWriter.WriteString(segment.c_str());
stringWriter.WriteString("</w:t></w:r>");
int possibleLen = ((c & 0xF0) == 0xF0) ? 4 : 3;
if (i + possibleLen <= line.length())
{
std::string possible = line.substr(i, possibleLen);
if (isEmoji(possible))
{
stringWriter.WriteString("<w:r><w:rPr><w:rFonts w:ascii=\"");
stringWriter.WriteString(emojiFontName);
stringWriter.WriteString("\" w:hAnsi=\"");
stringWriter.WriteString(emojiFontName);
stringWriter.WriteString("\" w:cs=\"");
stringWriter.WriteString(emojiFontName);
stringWriter.WriteString("\"/></w:rPr><w:t xml:space=\"preserve\">");
stringWriter.WriteString(possible.c_str());
stringWriter.WriteString("</w:t></w:r>");
i += possibleLen;
continue;
}
}
}
if (pos == std::string::npos)
break;
size_t textStart = i;
while (i < line.length())
{
unsigned char next = line[i];
if ((next & 0xF0) == 0xF0 || (next & 0xE0) == 0xE0)
{
int checkLen = ((next & 0xF0) == 0xF0) ? 4 : 3;
if (i + checkLen <= line.length())
{
std::string check = line.substr(i, checkLen);
if (isEmoji(check))
break;
}
}
i++;
}
stringWriter.WriteString("<w:tab/>");
start = pos + 1;
std::string textSegment = line.substr(textStart, i - textStart);
size_t tabStart = 0;
while (true)
{
size_t tabPos = textSegment.find('\x09', tabStart);
std::string seg = (tabPos == std::string::npos) ?
textSegment.substr(tabStart) :
textSegment.substr(tabStart, tabPos - tabStart);
if (!seg.empty())
{
std::string escaped = escapeXml(seg);
stringWriter.WriteString("<w:r><w:rPr><w:rFonts w:ascii=\"");
stringWriter.WriteString(fontName);
stringWriter.WriteString("\" w:hAnsi=\"");
stringWriter.WriteString(fontName);
stringWriter.WriteString("\" w:cs=\"");
stringWriter.WriteString(fontName);
stringWriter.WriteString("\"/></w:rPr><w:t xml:space=\"preserve\">");
stringWriter.WriteString(escaped.c_str());
stringWriter.WriteString("</w:t></w:r>");
}
if (tabPos == std::string::npos)
break;
stringWriter.WriteString("<w:r><w:tab/></w:r>");
tabStart = tabPos + 1;
}
}
stringWriter.WriteString("</w:p>");
}
}