mirror of
https://github.com/ONLYOFFICE/core.git
synced 2026-03-04 01:41:46 +08:00
Compare commits
40 Commits
v9.3.0.122
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 7043b36093 | |||
| 52f8640b10 | |||
| 8a1a45f403 | |||
| 2b46e0251f | |||
| 078a58772c | |||
| d54f0326cd | |||
| 269dd9b8bc | |||
| 9da0b82ead | |||
| e3334cbea5 | |||
| 01c928c724 | |||
| e5c1dc4bc3 | |||
| 2c5cd93ac5 | |||
| 1ff1334746 | |||
| de096d4229 | |||
| 6c9d795167 | |||
| 8116322018 | |||
| 5428c28874 | |||
| e389b4d799 | |||
| 8c607a429a | |||
| 00e80b68f6 | |||
| 377317892d | |||
| ef77688ea2 | |||
| eb756fab5c | |||
| 2d2bb7cee7 | |||
| 1abe5b2dcc | |||
| 2b4bdfdc05 | |||
| 007c70bcc0 | |||
| 017b43dd66 | |||
| 88a6760086 | |||
| 98a0551123 | |||
| 49cb1cdbca | |||
| 73e00a5096 | |||
| 462eeda60c | |||
| e1f81b6830 | |||
| d63a6e2ba4 | |||
| b9cf1bd204 | |||
| 81ec569f59 | |||
| 7d06219664 | |||
| e936b0e4e7 | |||
| a22f0bfb60 |
@ -188,7 +188,7 @@ namespace NSNetwork
|
||||
else
|
||||
{
|
||||
NSURL* url = [NSURL URLWithString:escapedURL];
|
||||
NSData* urlData = [NSData dataWithContentsOfURL:url];
|
||||
NSData* urlData = [[NSData alloc] initWithContentsOfURL:url];
|
||||
if ( urlData )
|
||||
{
|
||||
NSString* filePath = StringWToNSString(m_sDownloadFilePath);
|
||||
|
||||
@ -985,6 +985,8 @@ bool CPictFile::DecodeData()
|
||||
m_oImgData.m_pPixelData = (BYTE*)malloc(4 * m_oImgData.m_nHeight * m_oImgData.m_nWidth);
|
||||
if (m_oFrame.get_Data())
|
||||
memcpy(m_oImgData.m_pPixelData, m_oFrame.get_Data(), 4 * m_oImgData.m_nHeight * m_oImgData.m_nWidth);
|
||||
else
|
||||
memset(m_oImgData.m_pPixelData, 255, m_oImgData.m_nWidth * m_oImgData.m_nHeight * 4);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -1717,6 +1719,12 @@ void CPictFile::InitializeRenderer()
|
||||
return;
|
||||
|
||||
m_pFrameData = new BYTE[4 * m_oImgData.m_nWidth * m_oImgData.m_nHeight];
|
||||
unsigned int back = 0xffffff;
|
||||
unsigned int *pData32 = (unsigned int*)m_pFrameData;
|
||||
unsigned int *pData32End = pData32 + m_oImgData.m_nWidth * m_oImgData.m_nHeight;
|
||||
while (pData32 < pData32End)
|
||||
*pData32++ = back;
|
||||
|
||||
m_oFrame.put_Data(m_pFrameData);
|
||||
m_oFrame.put_Width(m_oImgData.m_nWidth);
|
||||
m_oFrame.put_Height(m_oImgData.m_nHeight);
|
||||
|
||||
@ -93,6 +93,7 @@ int CDocxRenderer::Convert(IOfficeDrawingFile* pFile, const std::wstring& sDst,
|
||||
m_pInternal->m_oDocument.m_oCurrentPage.m_bWriteStyleRaw = false;
|
||||
m_pInternal->m_bIsSupportShapeCommands = false;
|
||||
m_pInternal->m_oDocument.m_bIsRecord = true;
|
||||
m_pInternal->m_oDocument.m_oCurrentPage.m_bFirstParagraphLineCorrection = true;
|
||||
|
||||
if (bIsOutCompress)
|
||||
m_pInternal->m_oDocument.m_strTempDirectory = NSDirectory::CreateDirectoryWithUniqueName(m_pInternal->m_sTempDirectory);
|
||||
|
||||
@ -195,12 +195,14 @@ namespace NSDocxRenderer
|
||||
|
||||
if (!m_arShapes.empty())
|
||||
{
|
||||
auto& last_shape = m_arShapes.back();
|
||||
if (last_shape->IsEqual(top, bot, left, right) && rotation == last_shape->m_dRotation && lType != m_lLastType && m_lLastType != 0)
|
||||
auto& last_shape = m_arShapes.back();
|
||||
bool is_type_diff = lType == c_nStroke && (m_lLastType == c_nWindingFillMode || m_lLastType == c_nEvenOddFillMode);
|
||||
is_type_diff = is_type_diff || (m_lLastType == c_nStroke && (lType == c_nWindingFillMode || m_lLastType == c_nEvenOddFillMode));
|
||||
if (last_shape->IsEqual(top, bot, left, right) && rotation == last_shape->m_dRotation && is_type_diff && m_lLastType != 0)
|
||||
{
|
||||
set_fill_mode(last_shape);
|
||||
// Reset stroke/fill logic
|
||||
m_lLastType = 0;
|
||||
if (pInfo) DrawImage(last_shape, pInfo, image_vector);
|
||||
m_lLastType = 0; // reset stroke/fill logic
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -1659,7 +1661,11 @@ namespace NSDocxRenderer
|
||||
paragraph->m_dRightBorder = m_dWidth - paragraph->m_dRight;
|
||||
paragraph->m_dLeftBorder = min_left;
|
||||
|
||||
paragraph->m_dLineHeight = paragraph->m_dHeight / paragraph->m_arTextLines.size();
|
||||
if (paragraph->m_arTextLines.size() == 1)
|
||||
paragraph->m_dLineHeight = paragraph->m_dHeight;
|
||||
else
|
||||
paragraph->m_dLineHeight = (paragraph->m_dBot - firstLine->m_dBotWithMaxDescent) / (paragraph->m_arTextLines.size() - 1);
|
||||
|
||||
paragraph->m_bIsNeedFirstLineIndent = false;
|
||||
paragraph->m_dFirstLine = 0;
|
||||
paragraph->m_wsStyleId = m_oManagers.pParagraphStyleManager->GetDefaultParagraphStyleId(*paragraph);
|
||||
@ -1674,7 +1680,6 @@ namespace NSDocxRenderer
|
||||
{
|
||||
double offset = paragraph->m_dLineHeight - firstLine_height;
|
||||
paragraph->m_dTop -= offset;
|
||||
paragraph->m_dBot -= offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1682,9 +1687,10 @@ namespace NSDocxRenderer
|
||||
double newAscent = ascent * paragraph->m_dLineHeight / firstLine_height;
|
||||
double offset = ascent - newAscent;
|
||||
paragraph->m_dTop += offset;
|
||||
paragraph->m_dBot += offset;
|
||||
}
|
||||
paragraph->m_dHeight = paragraph->m_dBot - paragraph->m_dTop;
|
||||
}
|
||||
|
||||
// setting TextAlignmentType
|
||||
if (paragraph->m_arTextLines.size() > 1)
|
||||
{
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
#include "HTMLReader.h"
|
||||
|
||||
#include "../Common/Network/FileTransporter/include/FileTransporter.h"
|
||||
#include "../DesktopEditor/common/File.h"
|
||||
#include "../DesktopEditor/common/Path.h"
|
||||
|
||||
#include "../Common/3dParty/html/htmltoxhtml.h"
|
||||
@ -19,6 +18,9 @@
|
||||
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
|
||||
#include "../DesktopEditor/common/Directory.h"
|
||||
#include "../DesktopEditor/common/File.h"
|
||||
|
||||
namespace HTML
|
||||
{
|
||||
#define HTML_TAG(tag) GUMBO_TAG_##tag
|
||||
@ -261,18 +263,22 @@ inline bool UnreadableNode(const std::wstring& wsNodeName);
|
||||
inline bool TagIsUnprocessed(const std::wstring& wsTagName);
|
||||
|
||||
CHTMLReader::CHTMLReader()
|
||||
: m_pWriter(nullptr)
|
||||
: m_bIsTempDirOwner(true), m_pWriter(nullptr)
|
||||
{}
|
||||
|
||||
CHTMLReader::~CHTMLReader()
|
||||
{
|
||||
if (nullptr != m_pWriter)
|
||||
delete m_pWriter;
|
||||
|
||||
if (m_bIsTempDirOwner && !m_wsTempDirectory.empty())
|
||||
NSDirectory::DeleteDirectory(m_wsTempDirectory);
|
||||
}
|
||||
|
||||
void CHTMLReader::SetTempDirectory(const std::wstring& wsPath)
|
||||
{
|
||||
m_wsTempDirectory = wsPath;
|
||||
m_bIsTempDirOwner = m_wsTempDirectory.empty();
|
||||
}
|
||||
|
||||
void CHTMLReader::SetCoreDirectory(const std::wstring& wsPath)
|
||||
@ -327,7 +333,6 @@ void CHTMLReader::Clear()
|
||||
|
||||
m_mTags.clear();
|
||||
|
||||
m_wsTempDirectory.clear();
|
||||
m_wsSrcDirectory .clear();
|
||||
m_wsDstDirectory .clear();
|
||||
m_wsBaseDirectory.clear();
|
||||
@ -503,6 +508,11 @@ bool CHTMLReader::Convert(const std::wstring& wsPath, Convert_Func Convertation)
|
||||
if (nullptr == m_pWriter || !Convertation(wsPath, m_oLightReader) || !m_oLightReader.IsValid() || !IsHTML())
|
||||
return false;
|
||||
|
||||
if (m_wsTempDirectory.empty())
|
||||
{
|
||||
m_wsTempDirectory = NSDirectory::CreateDirectoryWithUniqueName(NSDirectory::GetTempPath());
|
||||
}
|
||||
|
||||
m_wsSrcDirectory = NSSystemPath::GetDirectoryName(wsPath);
|
||||
|
||||
m_oLightReader.MoveToStart();
|
||||
@ -1009,6 +1019,19 @@ bool CHTMLReader::ReadTable(std::vector<NSCSS::CNode>& arSelectors)
|
||||
if(m_oLightReader.IsEmptyNode())
|
||||
return false;
|
||||
|
||||
if (nullptr != m_pWriter && !m_pWriter->SupportNestedTables())
|
||||
{
|
||||
//Временно разруливаем это тут, так как по текущей логике мы сначала
|
||||
//читаем всю таблицу и её вложенные элементы, а потом приступаем к конвертации,
|
||||
//поэтому конвертору уже приходят вложенные таблицы, что в MD запрещено
|
||||
for (std::vector<NSCSS::CNode>::const_reverse_iterator itElement{arSelectors.crbegin() + 1}; itElement < arSelectors.crend(); ++itElement)
|
||||
if (L"table" == itElement->m_wsName)
|
||||
return false;
|
||||
|
||||
if (nullptr != dynamic_cast<CMDWriter*>(m_pWriter))
|
||||
((CMDWriter*)m_pWriter)->EnteredTable();
|
||||
}
|
||||
|
||||
CStorageTable oTable;
|
||||
|
||||
NSCSS::CCompiledStyle *pStyle = arSelectors.back().m_pCompiledStyle;
|
||||
@ -1100,6 +1123,9 @@ bool CHTMLReader::ReadTable(std::vector<NSCSS::CNode>& arSelectors)
|
||||
oTable.SetAlign(pStyle->m_oDisplay.GetHAlign().ToWString());
|
||||
//------
|
||||
|
||||
//TODO:: переписать работу с таблицами без предварительной конвертации ячеек и хранения их внутренних данных
|
||||
//Читаем содержимое таблицы -> считаем ячейки -> нормализуем таблицу -> конвертим таблицу
|
||||
|
||||
int nDeath = m_oLightReader.GetDepth();
|
||||
while(m_oLightReader.ReadNextSiblingNode(nDeath))
|
||||
{
|
||||
|
||||
@ -20,6 +20,7 @@ class CHTMLReader
|
||||
XmlUtils::CXmlLiteReader m_oLightReader; // SAX Reader
|
||||
NSCSS::CCssCalculator m_oCSSCalculator; // Css калькулятор
|
||||
|
||||
bool m_bIsTempDirOwner;
|
||||
std::wstring m_wsTempDirectory; // Temp папка
|
||||
std::wstring m_wsSrcDirectory; // Директория источника
|
||||
std::wstring m_wsDstDirectory; // Директория назначения
|
||||
|
||||
@ -53,7 +53,7 @@ bool CBold<CMDWriter>::Open(const std::vector<NSCSS::CNode>& arSelectors, const
|
||||
return true;
|
||||
|
||||
m_pWriter->WriteOpenSpecialString(L"**");
|
||||
m_pWriter->EneteredBold();
|
||||
m_pWriter->EnteredBold();
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -97,7 +97,7 @@ bool CItalic<CMDWriter>::Open(const std::vector<NSCSS::CNode>& arSelectors, cons
|
||||
return true;
|
||||
|
||||
m_pWriter->WriteOpenSpecialString(L"*");
|
||||
m_pWriter->EneteredItalic();
|
||||
m_pWriter->EnteredItalic();
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -124,7 +124,7 @@ bool CStrike<CMDWriter>::Open(const std::vector<NSCSS::CNode>& arSelectors, cons
|
||||
return true;
|
||||
|
||||
m_pWriter->WriteOpenSpecialString(L"~~");
|
||||
m_pWriter->EneteredStrike();
|
||||
m_pWriter->EnteredStrike();
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -309,7 +309,7 @@ CTable<CMDWriter>::CTable(CMDWriter* pWriter)
|
||||
|
||||
bool CTable<CMDWriter>::Open(const std::vector<NSCSS::CNode>& arSelectors, const boost::any& oExtraData)
|
||||
{
|
||||
if (!ValidWriter() || m_pWriter->InTable()) //В MD не поддерживаются вложенные таблицы
|
||||
if (!ValidWriter() /*|| m_pWriter->InTable()*/) //В MD не поддерживаются вложенные таблицы (пока разруливаем в парсере)
|
||||
return false;
|
||||
|
||||
m_pWriter->WriteBreakLine();
|
||||
|
||||
@ -28,6 +28,9 @@ public:
|
||||
virtual void RevertDataOutput() = 0; // Возвращаем место вывода к исходному
|
||||
|
||||
virtual XmlString* GetCurrentDocument() const = 0;
|
||||
|
||||
//TODO:: перенести разруливание вложенных таблиц в конвертацию после изменения принципа работы с таблицами
|
||||
virtual bool SupportNestedTables() const = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -202,6 +202,11 @@ XmlString* CMDWriter::GetCurrentDocument() const
|
||||
return m_arStates.top().m_pCurrentDocument;
|
||||
}
|
||||
|
||||
bool CMDWriter::SupportNestedTables() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void CMDWriter::WriteBreakLine(bool bNeedChecked)
|
||||
{
|
||||
if (bNeedChecked && !m_arStates.top().m_bNeedBreakLine)
|
||||
@ -229,7 +234,7 @@ void CMDWriter::WriteBreakLine(bool bNeedChecked)
|
||||
m_arStates.top().m_wsLastSpecialString.clear();
|
||||
}
|
||||
|
||||
void CMDWriter::EneteredBold()
|
||||
void CMDWriter::EnteredBold()
|
||||
{
|
||||
m_arStates.top().m_bBold = true;
|
||||
}
|
||||
@ -244,7 +249,7 @@ bool CMDWriter::IsBold()
|
||||
return m_arStates.top().m_bBold;
|
||||
}
|
||||
|
||||
void CMDWriter::EneteredItalic()
|
||||
void CMDWriter::EnteredItalic()
|
||||
{
|
||||
m_arStates.top().m_bItalic = true;
|
||||
}
|
||||
@ -259,7 +264,7 @@ bool CMDWriter::IsItalic()
|
||||
return m_arStates.top().m_bItalic;
|
||||
}
|
||||
|
||||
void CMDWriter::EneteredStrike()
|
||||
void CMDWriter::EnteredStrike()
|
||||
{
|
||||
m_arStates.top().m_bStrike = true;
|
||||
}
|
||||
|
||||
@ -65,17 +65,19 @@ public:
|
||||
|
||||
XmlString* GetCurrentDocument() const override;
|
||||
|
||||
bool SupportNestedTables() const override;
|
||||
|
||||
void WriteBreakLine(bool bNeedChecked = true);
|
||||
|
||||
void EneteredBold();
|
||||
void EnteredBold();
|
||||
void OutBold();
|
||||
bool IsBold();
|
||||
|
||||
void EneteredItalic();
|
||||
void EnteredItalic();
|
||||
void OutItalic();
|
||||
bool IsItalic();
|
||||
|
||||
void EneteredStrike();
|
||||
void EnteredStrike();
|
||||
void OutStrike();
|
||||
bool IsStrike();
|
||||
|
||||
|
||||
@ -1261,6 +1261,11 @@ XmlString* COOXMLWriter::GetCurrentDocument() const
|
||||
return m_arStates.top().m_pCurrentDocument;
|
||||
}
|
||||
|
||||
bool COOXMLWriter::SupportNestedTables() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
const NSCSS::NSProperties::CPage* COOXMLWriter::GetPageData() const
|
||||
{
|
||||
return &m_oPageData;
|
||||
|
||||
@ -200,6 +200,8 @@ public:
|
||||
XmlString& GetWebSettingsXml();
|
||||
XmlString* GetCurrentDocument() const override;
|
||||
|
||||
bool SupportNestedTables() const override;
|
||||
|
||||
const NSCSS::NSProperties::CPage* GetPageData() const;
|
||||
NSFonts::IApplicationFonts* GetFonts();
|
||||
|
||||
|
||||
@ -3840,6 +3840,8 @@ void BinaryDocumentTableWriter::WriteAltChunk(OOX::Media& oAltChunkFile, OOX::CS
|
||||
{
|
||||
OOX::CDocx oDocx = OOX::CDocx(OOX::CPath(sResultDocxDir));
|
||||
|
||||
OOX::IFileContainer* oldRels = m_pOfficeDrawingConverter->GetRelsPtr();
|
||||
|
||||
if (oDocx.m_oMain.document)
|
||||
{
|
||||
ParamsDocumentWriter oParamsDocumentWriterEmb(oDocx.m_oMain.document);
|
||||
@ -3875,6 +3877,9 @@ void BinaryDocumentTableWriter::WriteAltChunk(OOX::Media& oAltChunkFile, OOX::CS
|
||||
oParamsWriterEmb.m_pSettings = oDocx.m_oMain.settings;
|
||||
oParamsWriterEmb.m_pCurRels = oParamsDocumentWriterEmb.m_pRels;
|
||||
|
||||
m_pOfficeDrawingConverter->SetRelsPtr(oParamsDocumentWriterEmb.m_pRels);
|
||||
m_pOfficeDrawingConverter->Clear();
|
||||
|
||||
BinaryDocumentTableWriter oBinaryDocumentEmbTableWriter(oParamsWriterEmb, oParamsDocumentWriterEmb, &oParamsWriterEmb.m_mapIgnoreComments, NULL);
|
||||
|
||||
oBinaryDocumentEmbTableWriter.WriteDocumentContent(oDocx.m_oMain.document->m_arrItems);
|
||||
@ -3900,10 +3905,14 @@ void BinaryDocumentTableWriter::WriteAltChunk(OOX::Media& oAltChunkFile, OOX::CS
|
||||
oParamsWriterEmb.m_pEmbeddedStyles = oDocxFlat.m_pStyles.GetPointer();
|
||||
oParamsWriterEmb.m_pEmbeddedNumbering = oDocxFlat.m_pNumbering.GetPointer();
|
||||
|
||||
m_pOfficeDrawingConverter->SetRelsPtr(oParamsDocumentWriterEmb.m_pRels);
|
||||
m_pOfficeDrawingConverter->Clear();
|
||||
|
||||
BinaryDocumentTableWriter oBinaryDocumentEmbTableWriter(oParamsWriterEmb, oParamsDocumentWriterEmb, &oParamsWriterEmb.m_mapIgnoreComments, NULL);
|
||||
oBinaryDocumentEmbTableWriter.WriteDocumentContent(oDocxFlat.m_pDocument->m_arrItems);
|
||||
}
|
||||
}
|
||||
m_pOfficeDrawingConverter->SetRelsPtr(oldRels);
|
||||
}
|
||||
NSDirectory::DeleteDirectory(sResultDocxDir);
|
||||
}
|
||||
|
||||
@ -683,6 +683,7 @@ namespace NSBinPptxRW
|
||||
}
|
||||
else
|
||||
{
|
||||
m_arHandoutMasters_Theme.emplace_back();
|
||||
CreateDefaultHandoutMasters(m_arHandoutMasters_Theme[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -366,6 +366,9 @@ void pptx_text_context::Impl::ApplyListProperties(odf_reader::paragraph_format_p
|
||||
if (list_properties)
|
||||
{
|
||||
|
||||
if(list_properties->text_min_label_width_.has_value() && list_properties->text_min_label_width_->get_value() > 0 && (!propertiesOut.fo_text_indent_.has_value() || (propertiesOut.fo_text_indent_.has_value() && (propertiesOut.fo_text_indent_->get_length().get_value() == 0 || (propertiesOut.fo_margin_left_.has_value() && propertiesOut.fo_margin_left_->get_length().get_value() == 0 && propertiesOut.fo_text_indent_->get_length().get_value() < 0)))))
|
||||
propertiesOut.fo_text_indent_ = list_properties->text_min_label_width_;
|
||||
|
||||
if (list_properties->text_space_before_)
|
||||
{
|
||||
double spaceBeforeTwip;
|
||||
@ -386,9 +389,6 @@ void pptx_text_context::Impl::ApplyListProperties(odf_reader::paragraph_format_p
|
||||
else if(!propertiesOut.fo_margin_left_)
|
||||
propertiesOut.fo_margin_left_ = odf_types::length(0, odf_types::length::pt);
|
||||
|
||||
if(list_properties->text_min_label_width_.has_value() && list_properties->text_min_label_width_->get_value() > 0 && (!propertiesOut.fo_text_indent_.has_value() || (propertiesOut.fo_text_indent_.has_value() && propertiesOut.fo_text_indent_->get_length().get_value() == 0)))
|
||||
propertiesOut.fo_text_indent_ = list_properties->text_min_label_width_;
|
||||
|
||||
if (list_properties->fo_width_)
|
||||
{
|
||||
|
||||
|
||||
@ -535,7 +535,7 @@ void style_tab_stop::docx_convert(oox::docx_conversion_context & Context, bool c
|
||||
|
||||
length def_tab = length(1.0, length::cm);// в ms значение 0.8 не корректно оО
|
||||
|
||||
//double tab_pos_offset = (!Context.get_paragraph_state() || Context.is_table_content()) ? margin_left : 0;
|
||||
double tab_pos_offset = (!Context.get_paragraph_state() || Context.is_table_content()) ? margin_left : 0;
|
||||
|
||||
double tab_pos = 20.0 * style_position_.get_value_unit(length::pt);
|
||||
double min_tab_pos = 20.0 * def_tab.get_value_unit(length::pt) ;
|
||||
@ -586,15 +586,29 @@ void style_tab_stop::docx_convert(oox::docx_conversion_context & Context, bool c
|
||||
}
|
||||
}
|
||||
|
||||
if( style_type_.is_initialized() && style_type_->get_type() == style_type::Right )
|
||||
if( style_type_.is_initialized() )
|
||||
{
|
||||
double available_width = PageWidthTwips - LeftPageMarginTwips - RightPageMarginTwips;
|
||||
if ( available_width > 0 )
|
||||
switch ( style_type_->get_type() )
|
||||
{
|
||||
tab_pos = available_width;
|
||||
case style_type::Right:
|
||||
{
|
||||
int total_tabs = Context.get_tabs_context().tabs.size();
|
||||
|
||||
if( total_tabs <= 1 )
|
||||
{
|
||||
tab_pos += tab_pos_offset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double available_width = PageWidthTwips - LeftPageMarginTwips - RightPageMarginTwips;
|
||||
|
||||
if ( available_width > 0 && tab_pos > available_width )
|
||||
{
|
||||
tab_pos = available_width;
|
||||
}
|
||||
_pPr << L" w:val=\"" << val << "\"";
|
||||
_pPr << L" w:pos=\"" << static_cast<int>(tab_pos) << "\"";
|
||||
|
||||
|
||||
@ -973,7 +973,7 @@ void table_table_cell::xlsx_convert(oox::xlsx_conversion_context & Context)
|
||||
}
|
||||
if (attr.office_value_type_)
|
||||
{
|
||||
if (attr.office_value_type_.get() != num_format_type)
|
||||
if (attr.office_value_type_.get() != num_format_type && num_format_type != office_value_type::Custom)
|
||||
{// reset from cell
|
||||
num_format_type = attr.office_value_type_->get_type();
|
||||
num_format.clear();
|
||||
|
||||
@ -3452,8 +3452,12 @@ bool CPdfEditor::EditAnnot(int _nPageIndex, int nID)
|
||||
pAnnot = new PdfWriter::CPolygonLineAnnotation(pXref);
|
||||
else if (oType.isName("FreeText"))
|
||||
{
|
||||
std::map<std::wstring, std::wstring> mapFont = PdfReader::GetAnnotFont(pPDFDocument, m_pReader->GetFontManager(), pFontList, &oAnnotRef);
|
||||
m_mFonts.insert(mapFont.begin(), mapFont.end());
|
||||
std::vector<PdfReader::CAnnotFontInfo> arrFont = PdfReader::GetAnnotFontInfos(pPDFDocument, m_pReader->GetFontManager(), pFontList, &oAnnotRef);
|
||||
for (int i = 0; i < arrFont.size(); ++i)
|
||||
{
|
||||
PdfReader::CAnnotFontInfo oFontInfo = arrFont[i];
|
||||
m_mFonts.insert(std::make_pair(oFontInfo.wsFontName, oFontInfo.wsFontPath));
|
||||
}
|
||||
pAnnot = new PdfWriter::CFreeTextAnnotation(pXref);
|
||||
}
|
||||
else if (oType.isName("Caret"))
|
||||
@ -4011,7 +4015,8 @@ void CPdfEditor::ClearPage()
|
||||
{
|
||||
PDFDoc* pPDFDocument = NULL;
|
||||
PdfReader::CPdfFontList* pFontList = NULL;
|
||||
int nPageIndex = m_pReader->GetPageIndex(m_nEditPage, &pPDFDocument, &pFontList);
|
||||
int nStartRefID = 0;
|
||||
int nPageIndex = m_pReader->GetPageIndex(m_nEditPage, &pPDFDocument, &pFontList, &nStartRefID);
|
||||
PdfWriter::CDocument* pDoc = m_pWriter->GetDocument();
|
||||
if (nPageIndex < 0 || !pPDFDocument || !pDoc)
|
||||
return;
|
||||
@ -4074,7 +4079,7 @@ void CPdfEditor::ClearPage()
|
||||
if (pResources)
|
||||
{
|
||||
std::vector<int> arrUniqueResources;
|
||||
ScanAndProcessFonts(pPDFDocument, xref, pResources, 0, arrUniqueResources, pFontList);
|
||||
ScanAndProcessFonts(pPDFDocument, xref, pResources, 0, arrUniqueResources, pFontList, nStartRefID);
|
||||
m_pReader->SetFonts(m_nEditPage);
|
||||
}
|
||||
oAnnots.free();
|
||||
@ -4325,7 +4330,7 @@ std::vector<double> CPdfEditor::WriteRedact(const std::vector<std::wstring>& arr
|
||||
}
|
||||
return arrRes;
|
||||
}
|
||||
void CPdfEditor::ScanAndProcessFonts(PDFDoc* pPDFDocument, XRef* xref, Dict* pResources, int nDepth, std::vector<int>& arrUniqueResources, PdfReader::CPdfFontList* pFontList)
|
||||
void CPdfEditor::ScanAndProcessFonts(PDFDoc* pPDFDocument, XRef* xref, Dict* pResources, int nDepth, std::vector<int>& arrUniqueResources, PdfReader::CPdfFontList* pFontList, int nStartRefID)
|
||||
{
|
||||
if (nDepth > 5 || !pResources)
|
||||
return;
|
||||
@ -4384,7 +4389,12 @@ void CPdfEditor::ScanAndProcessFonts(PDFDoc* pPDFDocument, XRef* xref, Dict* pRe
|
||||
mCodeToGID[nIndex] = pFontEntry.pCodeToGID[nIndex];
|
||||
}
|
||||
m_pWriter->AddFont(L"Embedded: " + wsFontName, false, false, wsFileName, 0);
|
||||
PdfWriter::CObjectBase* pObj = m_mObjManager.GetObj(nFontRef.num);
|
||||
PdfWriter::CObjectBase* pObj = m_mObjManager.GetObj(nFontRef.num + nStartRefID);
|
||||
if (!pObj)
|
||||
{
|
||||
pObj = new PdfWriter::CObjectBase();
|
||||
pObj->SetRef(nFontRef.num, nFontRef.gen);
|
||||
}
|
||||
m_pWriter->GetDocument()->CreateFontEmbedded(wsFileName, 0, sFontKey, static_cast<PdfWriter::EFontType>(gfxFont->getType()), pObj, mCodeToWidth, mCodeToUnicode, mCodeToGID);
|
||||
}
|
||||
}
|
||||
@ -4400,7 +4410,7 @@ void CPdfEditor::ScanAndProcessFonts(PDFDoc* pPDFDocument, XRef* xref, Dict* pRe
|
||||
oFonts.free();
|
||||
|
||||
// Обработка XObject
|
||||
auto fScanFonts = [this, pPDFDocument, xref, nDepth, &arrUniqueResources, pFontList](Dict* pResources, const char* sName)
|
||||
auto fScanFonts = [this, pPDFDocument, xref, nDepth, &arrUniqueResources, pFontList, nStartRefID](Dict* pResources, const char* sName)
|
||||
{
|
||||
Object oObject;
|
||||
if (!pResources->lookup(sName, &oObject)->isDict())
|
||||
@ -4426,7 +4436,7 @@ void CPdfEditor::ScanAndProcessFonts(PDFDoc* pPDFDocument, XRef* xref, Dict* pRe
|
||||
arrUniqueResources.push_back(oRef.getRef().num);
|
||||
oXObj.free(); oRef.free();
|
||||
|
||||
ScanAndProcessFonts(pPDFDocument, xref, oResources.getDict(), nDepth + 1, arrUniqueResources, pFontList);
|
||||
ScanAndProcessFonts(pPDFDocument, xref, oResources.getDict(), nDepth + 1, arrUniqueResources, pFontList, nStartRefID);
|
||||
oResources.free();
|
||||
}
|
||||
oObject.free();
|
||||
@ -4465,7 +4475,7 @@ void CPdfEditor::ScanAndProcessFonts(PDFDoc* pPDFDocument, XRef* xref, Dict* pRe
|
||||
arrUniqueResources.push_back(oRef.getRef().num);
|
||||
oSMaskGroup.free(); oRef.free();
|
||||
|
||||
ScanAndProcessFonts(pPDFDocument, xref, oResources.getDict(), nDepth + 1, arrUniqueResources, pFontList);
|
||||
ScanAndProcessFonts(pPDFDocument, xref, oResources.getDict(), nDepth + 1, arrUniqueResources, pFontList, nStartRefID);
|
||||
oResources.free();
|
||||
}
|
||||
oExtGState.free();
|
||||
|
||||
@ -115,7 +115,7 @@ private:
|
||||
void GetPageTree(XRef* xref, Object* pPagesRefObj, PdfWriter::CPageTree* pPageParent = NULL);
|
||||
bool SplitPages(const int* arrPageIndex, unsigned int unLength, PDFDoc* _pDoc, int nStartRefID);
|
||||
bool ChangeFullNameParent(int nParent, const std::string& sPrefixForm, std::vector<int>& arrRename);
|
||||
void ScanAndProcessFonts(PDFDoc* pPDFDocument, XRef* xref, Dict* pResources, int nDepth, std::vector<int>& arrUniqueResources, PdfReader::CPdfFontList* pFontList);
|
||||
void ScanAndProcessFonts(PDFDoc* pPDFDocument, XRef* xref, Dict* pResources, int nDepth, std::vector<int>& arrUniqueResources, PdfReader::CPdfFontList* pFontList, int nStartRefID);
|
||||
|
||||
struct CRedactData
|
||||
{
|
||||
|
||||
@ -1095,17 +1095,16 @@ HRESULT CPdfFile::put_FontName(const std::wstring& wsName)
|
||||
size_t lastSpace = wsName.find_last_of(L' ');
|
||||
if (lastSpace != std::wstring::npos)
|
||||
{
|
||||
std::wstring numberStr = wsName.substr(lastSpace + 1);
|
||||
int nTargetCode = std::stoi(numberStr);
|
||||
std::wstring sTargetHash = wsName.substr(lastSpace + 1);
|
||||
const std::map<std::wstring, std::wstring>& mFonts = m_pInternal->pReader->GetFonts();
|
||||
auto it = std::find_if(mFonts.begin(), mFonts.end(), [nTargetCode](const std::pair<const std::wstring, std::wstring>& pair)
|
||||
std::map<std::wstring, std::wstring>::const_iterator it = std::find_if(mFonts.begin(), mFonts.end(), [&sTargetHash](const std::pair<const std::wstring, std::wstring>& pair)
|
||||
{
|
||||
const std::wstring& key = pair.first;
|
||||
size_t pos = key.rfind(L' ');
|
||||
if (pos != std::wstring::npos)
|
||||
{
|
||||
int keyCode = std::stoi(key.substr(pos + 1));
|
||||
return keyCode == nTargetCode;
|
||||
std::wstring sKeyHash = key.substr(pos + 1);
|
||||
return sKeyHash == sTargetHash;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
@ -218,6 +218,34 @@ bool CheckFontNameStyle(std::wstring& sName, const std::wstring& sStyle)
|
||||
}
|
||||
return bRet;
|
||||
}
|
||||
std::wstring Normalize(const std::wstring& wsName)
|
||||
{
|
||||
std::wstring s = wsName;
|
||||
bool bIsRemove = false;
|
||||
size_t lastSpace = s.find_last_of(L' ');
|
||||
if (lastSpace != std::wstring::npos)
|
||||
{
|
||||
bIsRemove = true;
|
||||
for (size_t nIndex = lastSpace + 1; nIndex < s.size(); ++nIndex)
|
||||
{
|
||||
wchar_t nChar = s.at(nIndex);
|
||||
if (nChar < '0' || nChar > 'F' || (nChar > '9' && nChar < 'A'))
|
||||
{
|
||||
bIsRemove = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (bIsRemove)
|
||||
s.erase(lastSpace + 1);
|
||||
}
|
||||
|
||||
bool bDummy1 = false, bDummy2 = false;
|
||||
PdfReader::CheckFontStylePDF(s, bDummy1, bDummy2);
|
||||
|
||||
NSStringExt::ToLower(s);
|
||||
s.erase(std::remove_if(s.begin(), s.end(), [](wchar_t c){ return c == L' ' || c == L'-' || c == L'_'; }), s.end());
|
||||
return s;
|
||||
};
|
||||
|
||||
namespace PdfReader
|
||||
{
|
||||
@ -692,18 +720,19 @@ bool FindFonts(Object* oStream, int nDepth, Object* oResFonts)
|
||||
oXObject.free(); oResources.free();
|
||||
return false;
|
||||
}
|
||||
std::map<std::wstring, std::wstring> GetAnnotFont(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CPdfFontList *pFontList, Object* oAnnotRef)
|
||||
std::vector<CAnnotFontInfo> GetAnnotFontInfos(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CPdfFontList* pFontList, Object* oAnnotRef)
|
||||
{
|
||||
std::vector<CAnnotFontInfo> result;
|
||||
|
||||
Object oAnnot, oObj;
|
||||
XRef* pXref = pdfDoc->getXRef();
|
||||
oAnnotRef->fetch(pXref, &oAnnot);
|
||||
std::map<std::wstring, std::wstring> mFontFreeText;
|
||||
|
||||
Object oAP, oN;
|
||||
if (!oAnnot.dictLookup("AP", &oAP)->isDict() || !oAP.dictLookup("N", &oN)->isStream())
|
||||
{
|
||||
oAP.free(); oN.free(); oAnnot.free();
|
||||
return mFontFreeText;
|
||||
return result;
|
||||
}
|
||||
oAP.free();
|
||||
|
||||
@ -711,13 +740,10 @@ std::map<std::wstring, std::wstring> GetAnnotFont(PDFDoc* pdfDoc, NSFonts::IFont
|
||||
if (!FindFonts(&oN, 0, &oFonts))
|
||||
{
|
||||
oN.free(); oFonts.free(); oAnnot.free();
|
||||
return mFontFreeText;
|
||||
return result;
|
||||
}
|
||||
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;
|
||||
@ -727,101 +753,132 @@ std::map<std::wstring, std::wstring> GetAnnotFont(PDFDoc* pdfDoc, NSFonts::IFont
|
||||
continue;
|
||||
}
|
||||
|
||||
CAnnotFontInfo info;
|
||||
std::string sFontName, sActualFontName;
|
||||
bool bBold = false, bItalic = false;
|
||||
std::wstring sFontPath = GetFontData(pdfDoc, pFontManager, pFontList, &oFontRef, sFontName, sActualFontName, bBold, bItalic);
|
||||
info.wsFontPath = GetFontData(pdfDoc, pFontManager, pFontList, &oFontRef, sFontName, sActualFontName, info.bBold, info.bItalic);
|
||||
oFontRef.free();
|
||||
if (sFontPath.empty() || IsBaseFont(sFontPath) || !sActualFontName.empty())
|
||||
|
||||
if (info.wsFontPath.empty() || IsBaseFont(info.wsFontPath))
|
||||
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<NSFonts::CFontInfo*>* 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;
|
||||
info.wsFontName = UTF8_TO_U(sFontName);
|
||||
if (!sActualFontName.empty())
|
||||
info.wsActualFontName = UTF8_TO_U(sActualFontName);
|
||||
|
||||
result.push_back(info);
|
||||
}
|
||||
|
||||
oFonts.free(); oAnnot.free();
|
||||
return mFontFreeText;
|
||||
return result;
|
||||
}
|
||||
int GetAnnotFontNamePenalty(const std::wstring& sCandNorm, const std::wstring& sReqNorm)
|
||||
{
|
||||
if (sReqNorm.empty())
|
||||
return 0;
|
||||
if (sCandNorm.empty())
|
||||
return 10000;
|
||||
|
||||
if (sCandNorm == sReqNorm)
|
||||
return 0;
|
||||
|
||||
bool bCandInReq = sReqNorm.find(sCandNorm) != std::wstring::npos;
|
||||
bool bReqInCand = sCandNorm.find(sReqNorm) != std::wstring::npos;
|
||||
if (bCandInReq || bReqInCand)
|
||||
return 500;
|
||||
|
||||
return 10000;
|
||||
}
|
||||
const CAnnotFontInfo* FindMatchInAnnotFonts(const std::vector<CAnnotFontInfo>& annotFonts, const std::wstring& wsRCName, bool bBold, bool bItalic)
|
||||
{
|
||||
std::wstring wsReqNorm = Normalize(wsRCName);
|
||||
|
||||
const CAnnotFontInfo* pBestMatch = nullptr;
|
||||
int nBestPenalty = INT_MAX;
|
||||
|
||||
for (const auto& fi : annotFonts)
|
||||
{
|
||||
int nNamePenalty = GetAnnotFontNamePenalty(Normalize(fi.wsFontName), wsReqNorm);
|
||||
if (!fi.wsActualFontName.empty())
|
||||
{
|
||||
int nActualPenalty = GetAnnotFontNamePenalty(Normalize(fi.wsActualFontName), wsReqNorm);
|
||||
if (nActualPenalty < nNamePenalty)
|
||||
nNamePenalty = nActualPenalty;
|
||||
}
|
||||
|
||||
if (nNamePenalty >= 5000)
|
||||
continue;
|
||||
|
||||
int nBoldPenalty = (fi.bBold != bBold) ? 1 : 0;
|
||||
int nItalicPenalty = (fi.bItalic != bItalic) ? 4 : 0;
|
||||
|
||||
int nTotalPenalty = nNamePenalty + nBoldPenalty + nItalicPenalty;
|
||||
|
||||
if (nTotalPenalty < nBestPenalty)
|
||||
{
|
||||
nBestPenalty = nTotalPenalty;
|
||||
pBestMatch = &fi;
|
||||
}
|
||||
|
||||
if (nTotalPenalty == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return pBestMatch;
|
||||
}
|
||||
|
||||
std::map<std::wstring, std::wstring> GetFreeTextFont(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CPdfFontList* pFontList, Object* oAnnotRef, std::vector<CAnnotMarkup::CFontData*>& arrRC)
|
||||
{
|
||||
std::map<std::wstring, std::wstring> mRes;
|
||||
|
||||
std::map<std::wstring, std::wstring> mFontFreeText = GetAnnotFont(pdfDoc, pFontManager, pFontList, oAnnotRef);
|
||||
std::vector<CAnnotFontInfo> annotFonts = GetAnnotFontInfos(pdfDoc, pFontManager, pFontList, oAnnotRef);
|
||||
|
||||
NSFonts::IFontsMemoryStorage* pMemoryStorage = NSFonts::NSApplicationFontStream::GetGlobalMemoryStorage();
|
||||
CFontList* pAppFontList = (CFontList*)pFontManager->GetApplication()->GetList();
|
||||
for (int i = 0; i < arrRC.size(); ++i)
|
||||
|
||||
for (int i = 0; i < (int)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 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";
|
||||
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";
|
||||
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);
|
||||
if (pMemoryStorage && !pMemoryStorage->Get(wsFontName))
|
||||
{
|
||||
const unsigned char* pData14 = NULL;
|
||||
unsigned int nSize14 = 0;
|
||||
if (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)
|
||||
for (int j = i; j < (int)arrRC.size(); ++j)
|
||||
{
|
||||
if (arrRC[j]->sFontFamily == sFontNameBefore && bBold == (bool)((arrRC[j]->unFontFlags >> 0) & 1) && bItalic == (bool)((arrRC[j]->unFontFlags >> 1) & 1))
|
||||
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;
|
||||
@ -830,47 +887,57 @@ std::map<std::wstring, std::wstring> GetFreeTextFont(PDFDoc* pdfDoc, NSFonts::IF
|
||||
}
|
||||
else
|
||||
{
|
||||
NSFonts::CFontSelectFormat oFontSelect;
|
||||
if (bBold)
|
||||
oFontSelect.bBold = new INT(1);
|
||||
if (bItalic)
|
||||
oFontSelect.bItalic = new INT(1);
|
||||
oFontSelect.wsName = new std::wstring(wsFontName);
|
||||
const CAnnotFontInfo* pMatch = FindMatchInAnnotFonts(annotFonts, wsFontName, bBold, bItalic);
|
||||
|
||||
NSFonts::CFontInfo* pFontInfo = pAppFontList->GetByParams(oFontSelect);
|
||||
if (pFontInfo && !pFontInfo->m_wsFontPath.empty())
|
||||
std::wstring wsResolvedName;
|
||||
std::wstring wsResolvedPath;
|
||||
bool bFoundInAnnot = false;
|
||||
|
||||
if (pMatch)
|
||||
{
|
||||
std::wstring sFontPath = pFontInfo->m_wsFontPath;
|
||||
bool bFindFreeText = false;
|
||||
for (std::map<std::wstring, std::wstring>::iterator it = mFontFreeText.begin(); it != mFontFreeText.end(); ++it)
|
||||
{
|
||||
if (it->second == sFontPath)
|
||||
{
|
||||
bFindFreeText = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::wstring wsFontBaseName = pFontInfo->m_wsFontName;
|
||||
EraseSubsetTag(wsFontBaseName);
|
||||
wsResolvedPath = pMatch->wsFontPath;
|
||||
wsResolvedName = pMatch->wsActualFontName.empty() ? pMatch->wsFontName : pMatch->wsActualFontName;
|
||||
EraseSubsetTag(wsResolvedName);
|
||||
bFoundInAnnot = 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);
|
||||
|
||||
if (bFindFreeText)
|
||||
NSFonts::CFontInfo* pFontInfo = pAppFontList->GetByParams(oFontSelect);
|
||||
if (pFontInfo && !pFontInfo->m_wsFontPath.empty())
|
||||
{
|
||||
arrRC[i]->sFontFamily = U_TO_UTF8(wsFontBaseName);
|
||||
mRes[wsFontBaseName] = pFontInfo->m_wsFontPath;
|
||||
wsResolvedPath = pFontInfo->m_wsFontPath;
|
||||
wsResolvedName = pFontInfo->m_wsFontName;
|
||||
EraseSubsetTag(wsResolvedName);
|
||||
}
|
||||
}
|
||||
|
||||
if (!wsResolvedName.empty())
|
||||
{
|
||||
if (bFoundInAnnot)
|
||||
{
|
||||
arrRC[i]->sFontFamily = U_TO_UTF8(wsResolvedName);
|
||||
mRes[wsResolvedName] = wsResolvedPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
arrRC[i]->unFontFlags |= (1 << 6);
|
||||
arrRC[i]->sActualFont = U_TO_UTF8(wsFontBaseName);
|
||||
arrRC[i]->sActualFont = U_TO_UTF8(wsResolvedName);
|
||||
}
|
||||
arrRC[i]->bFind = true;
|
||||
|
||||
std::string sFontNameNew = bFindFreeText ? arrRC[i]->sFontFamily : arrRC[i]->sActualFont;
|
||||
for (int j = i; j < arrRC.size(); ++j)
|
||||
std::string sFontNameNew = bFoundInAnnot ? arrRC[i]->sFontFamily : arrRC[i]->sActualFont;
|
||||
for (int j = i; j < (int)arrRC.size(); ++j)
|
||||
{
|
||||
if (arrRC[j]->sFontFamily == sFontName && bBold == (bool)((arrRC[j]->unFontFlags >> 0) & 1) && bItalic == (bool)((arrRC[j]->unFontFlags >> 1) & 1))
|
||||
if (arrRC[j]->sFontFamily == sFontName &&
|
||||
bBold == (bool)((arrRC[j]->unFontFlags >> 0) & 1) &&
|
||||
bItalic == (bool)((arrRC[j]->unFontFlags >> 1) & 1))
|
||||
{
|
||||
if (bFindFreeText)
|
||||
if (bFoundInAnnot)
|
||||
arrRC[j]->sFontFamily = sFontNameNew;
|
||||
else
|
||||
{
|
||||
|
||||
@ -46,13 +46,22 @@
|
||||
|
||||
namespace PdfReader
|
||||
{
|
||||
struct CAnnotFontInfo
|
||||
{
|
||||
std::wstring wsFontName;
|
||||
std::wstring wsFontPath;
|
||||
std::wstring wsActualFontName;
|
||||
bool bBold = false;
|
||||
bool bItalic = false;
|
||||
};
|
||||
|
||||
std::string GetRCFromDS(const std::string& sDS, Object* pContents, const std::vector<double>& arrCFromDA);
|
||||
bool IsNeedCMap(PDFDoc* pDoc);
|
||||
bool IsBaseFont(const std::wstring& wsName);
|
||||
std::map<std::wstring, std::wstring> GetAllFonts(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CPdfFontList* pFontList, bool bIsNeedCMap);
|
||||
std::wstring GetFontData(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CPdfFontList *pFontList, Object* oFontRef, std::string& sFontName, std::string& sActualFontName, bool& bBold, bool& bItalic, bool bIsNeedCMap = false);
|
||||
bool GetFontFromAP(PDFDoc* pdfDoc, AcroFormField* pField, Object* oFontRef, std::string& sFontKey);
|
||||
std::map<std::wstring, std::wstring> GetAnnotFont(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CPdfFontList *pFontList, Object* oAnnotRef);
|
||||
std::vector<CAnnotFontInfo> GetAnnotFontInfos(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CPdfFontList* pFontList, Object* oAnnotRef);
|
||||
std::map<std::wstring, std::wstring> GetFreeTextFont(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CPdfFontList* pFontList, Object* oAnnotRef, std::vector<CAnnotMarkup::CFontData*>& arrRC);
|
||||
bool FindFonts(Object* oStream, int nDepth, Object* oResFonts);
|
||||
void CollectFontWidths(GfxFont* gfxFont, Dict* pFontDict, std::map<unsigned int, unsigned int>& mGIDToWidth);
|
||||
|
||||
@ -44,6 +44,7 @@
|
||||
#include "../lib/xpdf/PDFDoc.h"
|
||||
#include "../lib/xpdf/CharCodeToUnicode.h"
|
||||
#include "../lib/xpdf/TextString.h"
|
||||
#include "../lib/xpdf/Decrypt.h"
|
||||
#include "XmlUtils.h"
|
||||
#include "PdfFont.h"
|
||||
|
||||
@ -101,6 +102,125 @@ namespace PdfReader
|
||||
{
|
||||
return (p[2]*77 + p[1]*150 + p[0]*29) >> 8;
|
||||
}
|
||||
std::wstring ComputeFontHash(XRef* pXref, GfxFont* pFont)
|
||||
{
|
||||
MD5State oMD5;
|
||||
md5Start(&oMD5);
|
||||
|
||||
Ref* pRef = pFont->getID();
|
||||
Object oRefObj, oFontObj;
|
||||
oRefObj.initRef(pRef->num, pRef->gen);
|
||||
oRefObj.fetch(pXref, &oFontObj);
|
||||
oRefObj.free();
|
||||
|
||||
if (oFontObj.isDict())
|
||||
{
|
||||
const char* aFontObjNames[] = { "Name", "Subtype", "BaseFont", "Encoding" };
|
||||
for (const char* sKey : aFontObjNames)
|
||||
{
|
||||
Object oItem;
|
||||
oFontObj.dictLookup(sKey, &oItem);
|
||||
if (oItem.isName())
|
||||
md5Append(&oMD5, (BYTE*)oItem.getName(), strlen(oItem.getName()));
|
||||
oItem.free();
|
||||
}
|
||||
|
||||
Object oDescObj, oDescendantFonts;
|
||||
oFontObj.dictLookup("FontDescriptor", &oDescObj);
|
||||
if (!oDescObj.isDict())
|
||||
{
|
||||
oDescObj.free();
|
||||
if (oFontObj.dictLookup("DescendantFonts", &oDescendantFonts)->isArray())
|
||||
{
|
||||
Object oDescendant;
|
||||
if (oDescendantFonts.arrayGet(0, &oDescendant)->isDict())
|
||||
oDescendant.dictLookup("FontDescriptor", &oDescObj);
|
||||
oDescendant.free();
|
||||
}
|
||||
oDescendantFonts.free();
|
||||
}
|
||||
|
||||
if (oDescObj.isDict())
|
||||
{
|
||||
Object oItem;
|
||||
|
||||
oDescObj.dictLookup("FontName", &oItem);
|
||||
if (oItem.isName())
|
||||
md5Append(&oMD5, (BYTE*)oItem.getName(), strlen(oItem.getName()));
|
||||
oItem.free();
|
||||
|
||||
const char* aMetricNames[] = {
|
||||
"Flags", "ItalicAngle", "Ascent", "Descent",
|
||||
"CapHeight", "XHeight", "StemV", "StemH"
|
||||
};
|
||||
for (const char* sName : aMetricNames)
|
||||
{
|
||||
oDescObj.dictLookup(sName, &oItem);
|
||||
if (oItem.isInt())
|
||||
{
|
||||
int nVal = oItem.getInt();
|
||||
md5Append(&oMD5, (BYTE*)&nVal, sizeof(int));
|
||||
}
|
||||
oItem.free();
|
||||
}
|
||||
|
||||
oDescObj.dictLookup("FontBBox", &oItem);
|
||||
if (oItem.isArray() && oItem.arrayGetLength() == 4)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
Object oCoord;
|
||||
if (oItem.arrayGet(i, &oCoord)->isInt())
|
||||
{
|
||||
int nVal = oCoord.getInt();
|
||||
md5Append(&oMD5, (BYTE*)&nVal, sizeof(int));
|
||||
}
|
||||
oCoord.free();
|
||||
}
|
||||
}
|
||||
oItem.free();
|
||||
}
|
||||
oDescObj.free();
|
||||
}
|
||||
oFontObj.free();
|
||||
|
||||
Ref oEmbRef;
|
||||
if (pFont->getEmbeddedFontID(&oEmbRef))
|
||||
{
|
||||
Object oRefObj, oStreamObj;
|
||||
oRefObj.initRef(oEmbRef.num, oEmbRef.gen);
|
||||
oRefObj.fetch(pXref, &oStreamObj);
|
||||
oRefObj.free();
|
||||
|
||||
if (oStreamObj.isStream())
|
||||
{
|
||||
oStreamObj.streamReset();
|
||||
const int nMaxBytes = 512;
|
||||
BYTE aBuf[nMaxBytes];
|
||||
int nRead = 0;
|
||||
int nChar;
|
||||
while (nRead < nMaxBytes && (nChar = oStreamObj.streamGetChar()) != EOF)
|
||||
aBuf[nRead++] = (BYTE)nChar;
|
||||
|
||||
oStreamObj.streamClose();
|
||||
md5Append(&oMD5, aBuf, nRead);
|
||||
}
|
||||
oStreamObj.free();
|
||||
}
|
||||
|
||||
md5Finish(&oMD5);
|
||||
|
||||
static const char aHexChars[] = "0123456789ABCDEF";
|
||||
std::string sHex;
|
||||
sHex.reserve(32);
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
sHex += aHexChars[(oMD5.digest[i] >> 4) & 0x0F];
|
||||
sHex += aHexChars[oMD5.digest[i] & 0x0F];
|
||||
}
|
||||
|
||||
return UTF8_TO_U(sHex);
|
||||
}
|
||||
}
|
||||
|
||||
class CMemoryFontStream
|
||||
@ -1463,8 +1583,8 @@ namespace PdfReader
|
||||
wsFontName = wsFontBaseName;
|
||||
if (bNotFullName)
|
||||
EraseSubsetTag(wsFontName);
|
||||
else if (!bFontBase14)
|
||||
wsFontName += (L" " + std::to_wstring(pFont->getID()->num));
|
||||
else if (!bFontBase14 && !bFontSubstitution)
|
||||
wsFontName += (L" " + ComputeFontHash(pXref, pFont));
|
||||
|
||||
pEntry->wsFilePath = wsFileName;
|
||||
pEntry->wsFontName = wsFontName;
|
||||
|
||||
@ -2267,4 +2267,13 @@ namespace PdfWriter
|
||||
{
|
||||
m_pCurPage->ClearContentFull(m_pXref);
|
||||
}
|
||||
CObjectBase* CDocument::FindObjByID(unsigned int nObjectId)
|
||||
{
|
||||
TXrefEntry* pRes = NULL;
|
||||
if (m_pLastXref)
|
||||
pRes = m_pLastXref->GetEntryByObjectId(nObjectId);
|
||||
if (!pRes)
|
||||
pRes = m_pXref->GetEntryByObjectId(nObjectId);
|
||||
return pRes? pRes->pObject : NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@ -226,6 +226,7 @@ namespace PdfWriter
|
||||
void RemoveObj(CObjectBase* pObj);
|
||||
void SetEncryption(CEncryptDict* pEncrypt, CObjectBase* pID);
|
||||
void AddNameTree(CStringObject* pName, CDestination* pDest);
|
||||
CObjectBase* FindObjByID(unsigned int nObjectId);
|
||||
private:
|
||||
|
||||
char* GetTTFontTag();
|
||||
|
||||
@ -142,4 +142,14 @@ namespace PdfWriter
|
||||
return pair.first;
|
||||
return 0;
|
||||
}
|
||||
CObjectBase* CFontEmbedded::GetObj()
|
||||
{
|
||||
if (m_pObj->GetType() != object_type_UNKNOWN)
|
||||
return m_pObj;
|
||||
return new PdfWriter::CProxyObject(m_pObj);
|
||||
}
|
||||
CObjectBase* CFontEmbedded::GetObj2()
|
||||
{
|
||||
return m_pObj;
|
||||
}
|
||||
}
|
||||
|
||||
@ -71,7 +71,8 @@ namespace PdfWriter
|
||||
unsigned int GetWidth(unsigned short ushCode);
|
||||
unsigned int EncodeUnicode(const unsigned int& unGID, const unsigned int& unUnicode);
|
||||
unsigned int EncodeGID(const unsigned int& unGID);
|
||||
CObjectBase* GetObj() { return m_pObj; }
|
||||
CObjectBase* GetObj();
|
||||
CObjectBase* GetObj2();
|
||||
const char* GetFontKey() const { return m_sFontKey.c_str(); }
|
||||
void UpdateKey(const std::string& sFontKey) { m_sFontKey = sFontKey; }
|
||||
|
||||
|
||||
@ -153,7 +153,7 @@ namespace PdfWriter
|
||||
typedef std::map<unsigned short, ByteList> UShortToByteList;
|
||||
struct EncodingsInfo
|
||||
{
|
||||
EncodingsInfo() { mEncoding = NULL; }
|
||||
EncodingsInfo() { mEncoding = NULL; mEncodingsCount = 0; }
|
||||
|
||||
long long mEncodingStart;
|
||||
long long mEncodingEnd;
|
||||
@ -4738,12 +4738,12 @@ namespace PdfWriter
|
||||
|
||||
// assuming that 0 is in the subset glyphs IDs, which does not require encoding
|
||||
// get the encodings count
|
||||
BYTE encodingGlyphsCount = std::min((BYTE)(inSubsetGlyphIDs.size() - 1), encodingInfo->mEncodingsCount);
|
||||
BYTE encodingGlyphsCount = inSubsetGlyphIDs.empty() ? 0 : std::min((BYTE)(inSubsetGlyphIDs.size() - 1), encodingInfo->mEncodingsCount);
|
||||
|
||||
mPrimitivesWriter->WriteCard8(encodingGlyphsCount);
|
||||
for (BYTE i = 0; i < encodingGlyphsCount; ++i)
|
||||
{
|
||||
if (inSubsetGlyphIDs[i + 1] < encodingInfo->mEncodingsCount)
|
||||
if (inSubsetGlyphIDs[i + 1] < encodingInfo->mEncodingsCount && inSubsetGlyphIDs[i + 1] > 0)
|
||||
mPrimitivesWriter->WriteCard8(encodingInfo->mEncoding[inSubsetGlyphIDs[i + 1] - 1]);
|
||||
else
|
||||
mPrimitivesWriter->WriteCard8(0);
|
||||
@ -4778,7 +4778,7 @@ namespace PdfWriter
|
||||
{
|
||||
int i = 1;
|
||||
for (; it != inSubsetGlyphIDs.end(); ++it, ++i)
|
||||
mPrimitivesWriter->WriteSID(inCIDMapping ? (*inCIDMapping)[i] : i);
|
||||
mPrimitivesWriter->WriteSID(inCIDMapping && i < (int)inCIDMapping->size() ? (*inCIDMapping)[i] : i);
|
||||
|
||||
}
|
||||
else
|
||||
|
||||
@ -891,10 +891,7 @@ namespace PdfWriter
|
||||
|
||||
while (pXref)
|
||||
{
|
||||
if (pXref->m_arrEntries.size() + pXref->m_unStartOffset <= nObjectId)
|
||||
return NULL;
|
||||
|
||||
if (pXref->m_unStartOffset <= nObjectId)
|
||||
if (pXref->m_unStartOffset <= nObjectId && pXref->m_arrEntries.size() + pXref->m_unStartOffset > nObjectId)
|
||||
{
|
||||
for (unsigned int unIndex = 0, nCount = pXref->m_arrEntries.size(); unIndex < nCount; unIndex++)
|
||||
{
|
||||
|
||||
@ -1818,7 +1818,7 @@ namespace PdfWriter
|
||||
return false;
|
||||
|
||||
m_vWords.push_back(pText);
|
||||
double dShift = (pLastText->m_dCurX - dX) * 1000 / dSize;
|
||||
double dShift = (pLastText->m_dCurX - dX) * 1000 / (dSize ? dSize : 1);
|
||||
m_vShifts.push_back(dShift);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -91,7 +91,7 @@ namespace PdfWriter
|
||||
}
|
||||
}
|
||||
|
||||
const char *sKey = m_pFonts->GetKey(pEmbedded ? pEmbedded->GetObj() : pFont);
|
||||
const char *sKey = m_pFonts->GetKey(pEmbedded ? pEmbedded->GetObj2() : pFont);
|
||||
if (!sKey)
|
||||
{
|
||||
// если фонт не зарегистрирован в ресурсах, тогда регистрируем его
|
||||
@ -108,7 +108,7 @@ namespace PdfWriter
|
||||
pPointer = (char*)StrCpy(sFontName, "F", pEndPointer);
|
||||
ItoA(pPointer, m_unFontsCount, pEndPointer);
|
||||
m_pFonts->Add(sFontName, pEmbedded ? pEmbedded->GetObj() : pFont);
|
||||
sKey = m_pFonts->GetKey(pEmbedded ? pEmbedded->GetObj() : pFont);
|
||||
sKey = m_pFonts->GetKey(pEmbedded ? pEmbedded->GetObj2() : pFont);
|
||||
if (sEmbeddedFontKey)
|
||||
pEmbedded->UpdateKey(sKey);
|
||||
}
|
||||
|
||||
@ -5104,15 +5104,42 @@ void Gfx::opEndIgnoreUndef(Object args[], int numArgs) {
|
||||
void Gfx::SkipBDC()
|
||||
{
|
||||
Object obj;
|
||||
// Стек аргументов (как в основном цикле обработки)
|
||||
Object args[maxArgs];
|
||||
int numArgs = 0;
|
||||
|
||||
getContentObj(&obj);
|
||||
while (!obj.isEOF()) {
|
||||
if (obj.isCmd("BMC") || obj.isCmd("BDC"))
|
||||
SkipBDC();
|
||||
else if (obj.isCmd("EMC"))
|
||||
break;
|
||||
obj.free();
|
||||
getContentObj(&obj);
|
||||
if (obj.isCmd("BMC") || obj.isCmd("BDC")) {
|
||||
// Сбрасываем накопленные аргументы перед рекурсией
|
||||
for (int i = 0; i < numArgs; ++i) args[i].free();
|
||||
numArgs = 0;
|
||||
SkipBDC();
|
||||
} else if (obj.isCmd("EMC")) {
|
||||
break;
|
||||
} else if (obj.isCmd("Tf")) {
|
||||
if (numArgs == 2) {
|
||||
opSetFont(args, numArgs);
|
||||
out->updateFont(state);
|
||||
}
|
||||
for (int i = 0; i < numArgs; ++i) args[i].free();
|
||||
numArgs = 0;
|
||||
} else if (obj.isCmd()) {
|
||||
// Любая другая команда — просто сбрасываем аргументы
|
||||
for (int i = 0; i < numArgs; ++i) args[i].free();
|
||||
numArgs = 0;
|
||||
} else {
|
||||
// Операнд — кладём в стек аргументов
|
||||
if (numArgs < maxArgs) {
|
||||
obj.copy(&args[numArgs]);
|
||||
++numArgs;
|
||||
}
|
||||
}
|
||||
obj.free();
|
||||
getContentObj(&obj);
|
||||
}
|
||||
|
||||
for (int i = 0; i < numArgs; ++i) args[i].free();
|
||||
obj.free();
|
||||
}
|
||||
void Gfx::opBeginMarkedContent(Object args[], int numArgs) {
|
||||
|
||||
@ -711,7 +711,7 @@ TEST_F(CPdfFileTest, EditPdfSign)
|
||||
|
||||
TEST_F(CPdfFileTest, PrintPdf)
|
||||
{
|
||||
//GTEST_SKIP();
|
||||
GTEST_SKIP();
|
||||
|
||||
LoadFromFile(wsDstFile);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user