Fix spacing problem

This commit is contained in:
Alexey Nagaev
2026-01-16 13:33:11 +03:00
parent 4a605d2424
commit e3f77e11e0
8 changed files with 80 additions and 95 deletions

View File

@ -92,6 +92,7 @@ int CDocxRenderer::Convert(IOfficeDrawingFile* pFile, const std::wstring& sDst,
m_pInternal->m_oDocument.m_oCurrentPage.m_bUseDefaultFont = false;
m_pInternal->m_oDocument.m_oCurrentPage.m_bWriteStyleRaw = false;
m_pInternal->m_bIsSupportShapeCommands = false;
m_pInternal->m_oDocument.m_bIsRecord = true;
if (bIsOutCompress)
m_pInternal->m_oDocument.m_strTempDirectory = NSDirectory::CreateDirectoryWithUniqueName(m_pInternal->m_sTempDirectory);
@ -130,6 +131,7 @@ std::vector<std::wstring> CDocxRenderer::ScanPage(IOfficeDrawingFile* pFile, siz
m_pInternal->m_oDocument.m_oCurrentPage.m_bUseDefaultFont = true;
m_pInternal->m_oDocument.m_oCurrentPage.m_bWriteStyleRaw = true;
m_pInternal->m_bIsSupportShapeCommands = false;
m_pInternal->m_oDocument.m_bIsRecord = false;
DrawPage(pFile, nPage);
@ -146,6 +148,7 @@ std::vector<std::wstring> CDocxRenderer::ScanPagePptx(IOfficeDrawingFile* pFile,
m_pInternal->m_oDocument.m_oCurrentPage.m_bWriteStyleRaw = true;
m_pInternal->m_oDocument.m_oCurrentPage.m_bCollectMetaInfo = true;
m_pInternal->m_bIsSupportShapeCommands = true;
m_pInternal->m_oDocument.m_bIsRecord = false;
m_pInternal->m_eShapeSerializeType = ShapeSerializeType::sstXml;
DrawPage(pFile, nPage);

View File

@ -572,8 +572,11 @@ namespace NSDocxRenderer
m_oPageBuilder.ClearNoAttack();
m_oCurrentPage.Analyze();
m_oCurrentPage.Record(m_oPageBuilder, m_lPageNum >= m_lNumberPages - 1);
m_arXmlString.push_back(NSFile::CUtf8Converter::GetUtf8StringFromUnicode2(m_oPageBuilder.GetBuffer(), (LONG)m_oPageBuilder.GetCurSize()));
if (m_bIsRecord)
{
m_oCurrentPage.Record(m_oPageBuilder, m_lPageNum >= m_lNumberPages - 1);
m_arXmlString.push_back(NSFile::CUtf8Converter::GetUtf8StringFromUnicode2(m_oPageBuilder.GetBuffer(), (LONG)m_oPageBuilder.GetCurSize()));
}
if (m_oPageBuilder.GetCurSize() > 100000000/*100Mb*/)
m_oPageBuilder.Clear();

View File

@ -40,6 +40,7 @@ namespace NSDocxRenderer
LONG m_lNumberPages{0};
bool m_bIsDisablePageCommand {false}; // disable commands inside draw function
bool m_bIsRecord {true};
NSStringUtils::CStringBuilder m_oPageBuilder;
std::list<std::string> m_arXmlString;

View File

@ -327,13 +327,15 @@ namespace NSDocxRenderer
m_oManagers.pFontManager->SetStringGid(0);
m_oManagers.pFontManager->MeasureStringGids(pUnicodes, nCount, dTextX, dTextY, _x, _y, _w, _h, CFontManager::mtPosition);
}
_h = m_oManagers.pFontManager->GetFontHeight();
double baseline = dTextY + fBaseLineOffset;
double top = baseline - _h;
double left = dTextX;
double right = left + _w;
double right = dTextR;
if (left == right) // XPS
right = left + _w;
// use forced fold option
const auto& oParams = m_oManagers.pFontManager->GetFontSelectParams();
@ -641,20 +643,8 @@ namespace NSDocxRenderer
{
for (auto& line : m_arTextLines)
for (auto& cont : line->m_arConts)
{
if (cont && cont->m_oSelectedSizes.dHeight == 0.0 && cont->m_oSelectedSizes.dWidth == 0.0)
{
if (m_bUseDefaultFont)
{
cont->m_oSelectedSizes.dHeight = cont->m_dHeight;
cont->m_oSelectedSizes.dWidth = cont->m_dWidth;
}
else
{
cont->CalcSelected();
}
}
}
if (cont && !m_bUseDefaultFont)
cont->CalcSelected();
}
void CPage::AnalyzeShapes()
@ -835,7 +825,8 @@ namespace NSDocxRenderer
// шейпы из буквиц
for (auto&& drop_cap : drop_caps)
{
drop_cap->CalcSelected();
if (!m_bUseDefaultFont)
drop_cap->CalcSelected();
auto line = std::make_shared<CTextLine>();
line->AddCont(drop_cap);
@ -1359,7 +1350,9 @@ namespace NSDocxRenderer
const auto center = pFirst->m_dTop + height / 2;
for (const auto& line : ver_lines)
if (line.pos > pFirst->m_dLeft && line.pos < pFirst->m_dRight && line.min <= center && line.max >= center)
if (line.pos - pFirst->m_dLeft > c_dGRAPHICS_ERROR_IN_LINES_MM &&
pFirst->m_dRight - line.pos > c_dGRAPHICS_ERROR_IN_LINES_MM &&
line.min <= center && line.max >= center)
return true;
return false;
@ -1547,18 +1540,6 @@ namespace NSDocxRenderer
v_type == eVerticalCrossingType::vctNoCrossingCurrentBelowNext;
};
auto calc_selected = [this] (cont_ptr_t cont) {
if (m_bUseDefaultFont)
{
cont->m_oSelectedSizes.dHeight = cont->m_dHeight;
cont->m_oSelectedSizes.dWidth = cont->m_dWidth;
}
else
{
cont->CalcSelected();
}
};
// линии из которых сделаем шейпы
for (size_t index = 0; index < m_arTextLines.size(); ++index)
{
@ -1583,10 +1564,12 @@ namespace NSDocxRenderer
curr_line->CalcFirstWordWidth();
for (auto& cont : prev_line->m_arConts)
calc_selected(cont);
if (!m_bUseDefaultFont)
cont->CalcSelected();
for (auto& cont : curr_line->m_arConts)
calc_selected(cont);
if (!m_bUseDefaultFont)
cont->CalcSelected();
m_arShapes.push_back(CreateSingleLineShape(prev_line));
m_arShapes.push_back(CreateSingleLineShape(curr_line));
@ -2568,7 +2551,7 @@ namespace NSDocxRenderer
pParagraph->m_dLeft = pLine->m_dLeft;
pParagraph->m_dTop = pLine->m_dTopWithMaxAscent;
pParagraph->m_dBot = pLine->m_dBot + (pLine->m_dTopWithMaxAscent - pLine->m_dTop);
pParagraph->m_dWidth = pLine->m_dWidth;
pParagraph->m_dWidth = pLine->m_dWidth * 1.05;
pParagraph->m_dHeight = pLine->m_dHeight;
pParagraph->m_dRight = pLine->m_dRight;
pParagraph->m_dLineHeight = pParagraph->m_dHeight;

View File

@ -92,6 +92,7 @@ namespace NSDocxRenderer
m_arOriginLefts[i] = rCont.m_arOriginLefts[i];
m_bFontSubstitution = rCont.m_bFontSubstitution;
m_dSpacing = rCont.m_dSpacing;
return *this;
}
@ -100,7 +101,6 @@ namespace NSDocxRenderer
{
if (!m_pFontStyle->wsFontName.empty() && !m_oText.empty())
{
// нужно перемерять...
if (m_oSelectedFont.Path.empty())
m_pManager->LoadFontByName(m_oSelectedFont);
else
@ -121,6 +121,7 @@ namespace NSDocxRenderer
m_oSelectedSizes.dWidth = dBoxWidth;
m_oSelectedSizes.dHeight = dBoxHeight;
m_dSpacing = (m_dWidth - m_oSelectedSizes.dWidth) / (m_oText.length());
}
}
@ -258,18 +259,11 @@ namespace NSDocxRenderer
LONG lCalculatedSpacing = 0;
// mm to points * 20
if (!m_oText.empty())
{
double dSpacing = (m_dWidth - m_oSelectedSizes.dWidth) / (m_oText.length());
dSpacing *= c_dMMToDx;
lCalculatedSpacing = static_cast<LONG>(m_dSpacing * c_dMMToDx);
//mm to points * 20
lCalculatedSpacing = static_cast<LONG>(dSpacing);
}
// принудительно уменьшаем spacing чтобы текстовые линии не выходили за правую границу
lCalculatedSpacing -= 1;
if (lCalculatedSpacing != 0)
{
oWriter.WriteString(L"<w:spacing w:val=\"");
@ -396,14 +390,7 @@ namespace NSDocxRenderer
LONG lCalculatedSpacing = 0;
if (!m_oText.empty())
{
double dSpacing = (m_dWidth - m_oSelectedSizes.dWidth) / (m_oText.length());
dSpacing *= c_dMMToPt * 100;
lCalculatedSpacing = static_cast<LONG>(dSpacing);
}
// принудительно уменьшаем spacing чтобы текстовые линии не выходили за правую границу
lCalculatedSpacing -= 15;
lCalculatedSpacing = static_cast<LONG>(m_dSpacing * c_dMMToPt * 100);
oWriter.WriteString(L" spc=\"");
oWriter.AddInt(lCalculatedSpacing);
@ -541,12 +528,7 @@ namespace NSDocxRenderer
{
int lCalculatedSpacing = 0;
if (!m_oText.empty())
{
double dSpacing = (m_dWidth - m_oSelectedSizes.dWidth) / (m_oText.length());
dSpacing *= c_dMMToPt * 100;
lCalculatedSpacing = static_cast<LONG>(dSpacing);
}
lCalculatedSpacing -= 15;
lCalculatedSpacing = static_cast<LONG>(m_dSpacing * c_dMMToPt * 100);
const BYTE kPARRUN_TYPE_RUN = 1;
oWriter.StartRecord(kPARRUN_TYPE_RUN);
@ -754,14 +736,14 @@ namespace NSDocxRenderer
continue;
}
m_arSymWidths.push_back(w);
m_dWidth += w;
m_oText += oText.at(i);
m_arOriginLefts.push_back(arOriginLefts[i]);
m_dRight = arOriginLefts[i] + w;
if (!arGids.empty() && m_bCollectMetaInfo)
m_arGids.push_back(arGids[i]);
}
m_dRight = m_dLeft + m_dWidth;
m_dWidth = m_dRight - m_dLeft;
}
void CContText::AddTextFront(const NSStringUtils::CStringUTF32& oText,
const std::vector<double>& arSymWidths,
@ -770,18 +752,11 @@ namespace NSDocxRenderer
{
m_oText = oText + m_oText;
double addtitional_width = 0;
for (auto& w : arSymWidths)
addtitional_width += w;
auto ar_sym_w = m_arSymWidths;
m_arSymWidths = arSymWidths;
for (auto& w : ar_sym_w)
m_arSymWidths.push_back(w);
m_dWidth += addtitional_width;
m_dLeft = m_dRight - m_dWidth;
if (!arGids.empty() && m_bCollectMetaInfo)
{
auto ar_gids = m_arGids;
@ -794,6 +769,9 @@ namespace NSDocxRenderer
m_arOriginLefts = arOriginLefts;
for (auto& left : ar_lefts)
m_arOriginLefts.push_back(left);
m_dLeft = m_arOriginLefts.back();
m_dWidth = m_dRight - m_dLeft;
}
void CContText::SetText(const NSStringUtils::CStringUTF32& oText,
const std::vector<double>& arSymWidths,
@ -834,8 +812,8 @@ namespace NSDocxRenderer
m_arGids.push_back(nGid);
}
}
m_dWidth += dWidth;
m_dRight = m_dLeft + m_dWidth;
m_dRight = dLeft + dWidth;
m_dWidth = m_dRight - m_dLeft;
}
void CContText::AddSymFront(uint32_t cSym, double dWidth, double dLeft, unsigned int nGid)
{
@ -844,7 +822,7 @@ namespace NSDocxRenderer
text += m_oText;
m_oText = text;
m_dLeft -= dWidth;
m_dLeft = dLeft;
m_dWidth = m_dRight - m_dLeft;
m_arSymWidths.insert(m_arSymWidths.begin(), dWidth);
@ -878,11 +856,16 @@ namespace NSDocxRenderer
void CContText::RemoveLastSym()
{
m_oText = m_oText.substr(0, m_oText.length() - 1);
m_dWidth -= m_arSymWidths[m_arSymWidths.size() - 1];
m_dRight = m_dLeft + m_dWidth;
m_arSymWidths.resize(m_arSymWidths.size() - 1);
m_arOriginLefts.resize(m_arOriginLefts.size() - 1);
if (!m_arOriginLefts.empty())
m_dRight = m_arOriginLefts.back() + m_arSymWidths.back();
else
m_dRight = m_dLeft;
m_dWidth = m_dRight - m_dLeft;
if (!m_arGids.empty() && m_bCollectMetaInfo)
m_arGids.resize(m_arGids.size() - 1);
}
@ -899,7 +882,7 @@ namespace NSDocxRenderer
{
return m_arSymWidths;
}
const std::vector<double> CContText::GetSymLefts() const noexcept
const std::vector<double>& CContText::GetSymLefts() const noexcept
{
return m_arOriginLefts;
}
@ -1174,22 +1157,25 @@ namespace NSDocxRenderer
oText.length() == 1 && CContText::IsUnicodeDiacriticalMark(oText.at(0))) &&
bFontSubstitution == m_pCurrCont->m_bFontSubstitution)
{
double avg_width = dWidth / oText.length();
for (size_t i = 0; i < oText.length(); ++i)
if (oText.at(i) == c_SPACE_SYM)
m_pCurrCont->m_pFontStyle->UpdateAvgSpaceWidth(avg_width);
double avg_space_width = m_pCurrCont->m_pFontStyle->GetAvgSpaceWidth();
double space_width =
avg_space_width != 0.0 ?
avg_space_width * c_dAVERAGE_SPACE_WIDTH_COEF :
m_pCurrCont->CalculateSpace() * c_dSPACE_WIDTH_COEF;
double spacing = dLeft - m_dPrevRight;
bool is_added = false;
bool diff_spacing = false;
// set spacing at the second symbol
if (m_pCurrCont->GetLength() == 1)
m_pCurrCont->m_dSpacing = spacing;
if (fabs(spacing - m_pCurrCont->m_dSpacing) > c_dTHE_SAME_SPACING_ERROR)
diff_spacing = true;
// some_text+more_text
if (fabs(m_pCurrCont->m_dRight - dLeft) < space_width && dRight > m_pCurrCont->m_dRight)
if (!diff_spacing && fabs(m_pCurrCont->m_dRight - dLeft) < space_width && dRight > m_pCurrCont->m_dRight)
{
double left_avg_width = (dRight - m_pCurrCont->m_dRight) / oText.length();
std::vector<double> ar_widths;
@ -1201,7 +1187,7 @@ namespace NSDocxRenderer
}
// more_text+some_text
else if (fabs(m_pCurrCont->m_dLeft - dRight) < space_width && dLeft < m_pCurrCont->m_dLeft)
else if (diff_spacing && fabs(m_pCurrCont->m_dLeft - dRight) < space_width && dLeft < m_pCurrCont->m_dLeft)
{
double right_avg_width = (m_pCurrCont->m_dLeft - dLeft) / oText.length();
std::vector<double> ar_widths;
@ -1219,6 +1205,7 @@ namespace NSDocxRenderer
m_pCurrCont->m_dHeight = m_pCurrCont->m_dBot - m_pCurrCont->m_dTop;
m_pCurrCont->m_dWidth = m_pCurrCont->m_dRight - m_pCurrCont->m_dLeft;
m_pCurrCont->m_nOrder = nOrder;
m_dPrevRight = dRight;
return;
}
}
@ -1242,14 +1229,14 @@ namespace NSDocxRenderer
m_pFontSelector->IsSelectedItalic(),
m_pFontSelector->IsSelectedBold() || bForcedBold);
// just in case if oText contains more than 1 symbol
std::vector<double> ar_widths;
double avg_width = abs(dRight - dLeft) / oText.length();
double avg_width = dWidth / oText.length();
for (size_t i = 0; i < oText.length(); ++i)
if (oText.at(i) == c_SPACE_SYM)
pCont->m_pFontStyle->UpdateAvgSpaceWidth(avg_width);
std::vector<double> ar_widths;
for (size_t i = 0; i < oText.length(); ++i)
{
if (oText.at(i) == c_SPACE_SYM) pCont->m_pFontStyle->UpdateAvgSpaceWidth(avg_width);
ar_widths.push_back(avg_width);
}
pCont->m_bCollectMetaInfo = bCollectMetaInfo;
pCont->SetText(oText, ar_widths, std::move(gids), std::move(origin_lefts));
@ -1299,6 +1286,7 @@ namespace NSDocxRenderer
m_pCurrCont = pCont;
m_oPrevFont = oFont;
m_oPrevBrush = oBrush;
m_dPrevRight = dRight;
}
void CContTextBuilder::NullCurrCont()

View File

@ -67,6 +67,7 @@ namespace NSDocxRenderer
// sizes
double m_dSpaceWidthMM{0};
double m_dSpacing{0};
CSelectedSizes m_oSelectedSizes{};
double m_dTopWithAscent{0};
@ -121,7 +122,7 @@ namespace NSDocxRenderer
const NSStringUtils::CStringUTF32& GetText() const noexcept;
const std::vector<double>& GetSymWidths() const noexcept;
const std::vector<double> GetSymLefts() const noexcept;
const std::vector<double>& GetSymLefts() const noexcept;
std::shared_ptr<CContText> Split(size_t index);
std::shared_ptr<CContText> Split(double dLeft);
@ -198,8 +199,8 @@ namespace NSDocxRenderer
void NullCurrCont();
void Clear();
private:
std::vector<cont_ptr_t> m_arConts;
std::vector<cont_ptr_t> m_arDiacs;
@ -210,5 +211,6 @@ namespace NSDocxRenderer
CFontStyleManager* m_pFontStyleManager {nullptr};
CFontSelector* m_pFontSelector {nullptr};
double m_dPrevRight = 0;
};
}

View File

@ -194,16 +194,20 @@ namespace NSDocxRenderer
continue;
const auto& text = cont->GetText();
auto ar_widths = cont->GetSymWidths();
auto ar_lefts = cont->GetSymLefts();
auto ar_width = cont->GetSymWidths();
for (size_t i = 0; i < text.length(); ++i)
{
if (text.at(i) == c_SPACE_SYM)
{
m_dFirstWordWidth = width;
if (i == 0)
m_dFirstWordWidth = cont->m_dLeft - m_dLeft;
else
m_dFirstWordWidth = ar_lefts[i - 1] - m_dLeft + ar_width[i - 1];
is_done = true;
break;
}
width += ar_widths[i];
}
if (is_done)
break;

View File

@ -24,8 +24,9 @@ constexpr double c_dPtToEMU = 12700.0;
constexpr double c_dDegreeToAngle = 60000.0;
const double c_dSTANDART_STRING_HEIGHT_MM = 4.2333333333333334;
const double c_dTHE_SAME_STRING_Y_PRECISION_MM = 0.02;
const double c_dTHE_SAME_STRING_X_PRECISION_MM = 0.02;
const double c_dTHE_SAME_STRING_Y_PRECISION_MM = 0.03;
const double c_dTHE_SAME_STRING_X_PRECISION_MM = 0.03;
const double c_dTHE_SAME_SPACING_ERROR = 0.1;
const double c_dLINE_DISTANCE_ERROR_MM = 0.3;
const double c_dERROR_OF_PARAGRAPH_BORDERS_MM = 1.0;
const double c_dCENTER_POSITION_ERROR_MM = 1.5;