1197 lines
37 KiB
C++
1197 lines
37 KiB
C++
/*
|
||
* (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 "RedactOutputDev.h"
|
||
#include "Types.h"
|
||
#include "Streams.h"
|
||
#include "Utils.h"
|
||
|
||
#include "../lib/xpdf/GfxFont.h"
|
||
#include "../lib/xpdf/XRef.h"
|
||
|
||
#include "../../DesktopEditor/graphics/GraphicsPath.h"
|
||
|
||
namespace PdfWriter
|
||
{
|
||
void Transform(double* pMatrix, double dUserX, double dUserY, double* pdDeviceX, double* pdDeviceY)
|
||
{
|
||
*pdDeviceX = dUserX * pMatrix[0] + dUserY * pMatrix[2] + pMatrix[4];
|
||
*pdDeviceY = dUserX * pMatrix[1] + dUserY * pMatrix[3] + pMatrix[5];
|
||
}
|
||
|
||
//----- constructor/destructor
|
||
RedactOutputDev::RedactOutputDev(CPdfWriter* pRenderer)
|
||
{
|
||
m_pXref = NULL;
|
||
|
||
m_pRenderer = pRenderer;
|
||
m_pDoc = m_pRenderer->GetDocument();
|
||
m_pPage = NULL;
|
||
|
||
m_bUpdateAll = false;
|
||
}
|
||
RedactOutputDev::~RedactOutputDev()
|
||
{
|
||
m_pRenderer = NULL;
|
||
m_pDoc = NULL;
|
||
m_pPage = NULL;
|
||
}
|
||
void RedactOutputDev::SetRedact(const std::vector<double>& arrQuadPoints)
|
||
{
|
||
m_arrQuadPoints = arrQuadPoints;
|
||
for (int i = 0; i < m_arrQuadPoints.size(); i += 8)
|
||
{
|
||
m_oPathRedact.StartFigure();
|
||
m_oPathRedact.MoveTo(m_arrQuadPoints[i + 0], m_arrQuadPoints[i + 1]);
|
||
m_oPathRedact.LineTo(m_arrQuadPoints[i + 2], m_arrQuadPoints[i + 3]);
|
||
m_oPathRedact.LineTo(m_arrQuadPoints[i + 4], m_arrQuadPoints[i + 5]);
|
||
m_oPathRedact.LineTo(m_arrQuadPoints[i + 6], m_arrQuadPoints[i + 7]);
|
||
m_oPathRedact.CloseFigure();
|
||
}
|
||
}
|
||
void RedactOutputDev::NewPDF(XRef* pXref)
|
||
{
|
||
m_pXref = pXref;
|
||
}
|
||
//----- initialization and control
|
||
void RedactOutputDev::setDefaultCTM(double *ctm)
|
||
{
|
||
memcpy(m_arrMatrix, ctm, 6 * sizeof(double));
|
||
if (m_pPage)
|
||
m_pPage->StartTransform(m_arrMatrix[0], m_arrMatrix[1], m_arrMatrix[2], m_arrMatrix[3], m_arrMatrix[4], m_arrMatrix[5]);
|
||
}
|
||
void RedactOutputDev::startPage(int nPageIndex, GfxState *pGState)
|
||
{
|
||
m_pPage = m_pDoc->GetEditPage(nPageIndex);
|
||
m_pRenderer->EditPage(m_pPage);
|
||
m_pDoc->SetCurPage(m_pPage);
|
||
m_pDoc->ClearPageFull();
|
||
}
|
||
void RedactOutputDev::endPage()
|
||
{
|
||
m_pRenderer->m_oCommandManager.Flush();
|
||
m_pPage = NULL;
|
||
}
|
||
//----- save/restore graphics state
|
||
void RedactOutputDev::saveState(GfxState *pGState)
|
||
{
|
||
m_pRenderer->m_oCommandManager.Flush();
|
||
DoStateOp();
|
||
m_pPage->GrSave();
|
||
m_sStates.push_back(GfxRedactState());
|
||
updateAll(pGState);
|
||
}
|
||
void RedactOutputDev::restoreState(GfxState *pGState)
|
||
{
|
||
m_pRenderer->m_oCommandManager.Flush();
|
||
m_pPage->GrRestore();
|
||
updateAll(pGState);
|
||
|
||
if (m_sStates.empty())
|
||
return; // Несбалансированный q/Q - сломанный файл
|
||
m_sStates.pop_back();
|
||
}
|
||
//----- update graphics state
|
||
void RedactOutputDev::updateAll(GfxState *pGState)
|
||
{
|
||
m_bUpdateAll = true;
|
||
updateLineDash(pGState);
|
||
updateFlatness(pGState);
|
||
updateLineJoin(pGState);
|
||
updateLineCap(pGState);
|
||
updateMiterLimit(pGState);
|
||
updateLineWidth(pGState);
|
||
// updateStrokeAdjust(pGState);
|
||
// updateFillColorSpace(pGState);
|
||
// updateFillColor(pGState);
|
||
// updateStrokeColorSpace(pGState);
|
||
// updateStrokeColor(pGState);
|
||
updateRenderingIntent(pGState);
|
||
// updateBlendMode(pGState);
|
||
// updateFillOpacity(pGState);
|
||
// updateStrokeOpacity(pGState);
|
||
updateFont(pGState);
|
||
updateCharSpace(pGState);
|
||
updateRender(pGState);
|
||
updateRise(pGState);
|
||
updateWordSpace(pGState);
|
||
updateHorizScaling(pGState);
|
||
m_bUpdateAll = false;
|
||
}
|
||
void RedactOutputDev::updateLineDash(GfxState *pGState)
|
||
{
|
||
double* pDash = NULL;
|
||
int nSize = 0;
|
||
double dStart = 0;
|
||
pGState->getLineDash(&pDash, &nSize, &dStart);
|
||
|
||
if (0 == nSize) // Solid
|
||
{
|
||
m_pRenderer->put_PenDashOffset(0);
|
||
m_pRenderer->put_PenDashStyle(Aggplus::DashStyleSolid);
|
||
}
|
||
else
|
||
{
|
||
m_pRenderer->m_oPen.SetDashPattern(pDash, nSize);
|
||
m_pRenderer->m_oPen.SetDashOffset(dStart);
|
||
m_pRenderer->m_oPen.SetDashStyle(Aggplus::DashStyleCustom);
|
||
}
|
||
|
||
if (m_bUpdateAll || m_sStates.empty())
|
||
return;
|
||
std::string sOp = "[ ";
|
||
for (int i = 0; i < nSize; ++i)
|
||
sOp += (std::to_string(pDash[i]) + " ");
|
||
sOp += "] " + std::to_string(dStart);
|
||
m_sStates.back().m_arrOp.push_back(std::make_pair(sOp, "d"));
|
||
}
|
||
void RedactOutputDev::updateFlatness(GfxState *pGState)
|
||
{
|
||
m_pRenderer->m_oPen.SetFlatness(pGState->getFlatness());
|
||
if (!m_bUpdateAll && !m_sStates.empty())
|
||
m_sStates.back().m_arrOp.push_back(std::make_pair(std::to_string(pGState->getFlatness()), "i"));
|
||
}
|
||
void RedactOutputDev::updateLineJoin(GfxState *pGState)
|
||
{
|
||
m_pRenderer->m_oPen.SetJoinStyle(pGState->getLineJoin());
|
||
if (!m_bUpdateAll && !m_sStates.empty())
|
||
m_sStates.back().m_arrOp.push_back(std::make_pair(std::to_string(pGState->getLineJoin()), "j"));
|
||
}
|
||
void RedactOutputDev::updateLineCap(GfxState *pGState)
|
||
{
|
||
m_pRenderer->m_oPen.SetStartCapStyle(pGState->getLineCap());
|
||
if (!m_bUpdateAll && !m_sStates.empty())
|
||
m_sStates.back().m_arrOp.push_back(std::make_pair(std::to_string(pGState->getLineCap()), "J"));
|
||
}
|
||
void RedactOutputDev::updateMiterLimit(GfxState *pGState)
|
||
{
|
||
m_pRenderer->m_oPen.SetMiter(pGState->getMiterLimit());
|
||
if (!m_bUpdateAll && !m_sStates.empty())
|
||
m_sStates.back().m_arrOp.push_back(std::make_pair(std::to_string(pGState->getMiterLimit()), "M"));
|
||
}
|
||
void RedactOutputDev::updateLineWidth(GfxState *pGState)
|
||
{
|
||
m_pRenderer->m_oPen.SetSize(pGState->getLineWidth());
|
||
if (!m_bUpdateAll && !m_sStates.empty())
|
||
m_sStates.back().m_arrOp.push_back(std::make_pair(std::to_string(pGState->getLineWidth()), "w"));
|
||
}
|
||
void RedactOutputDev::updateFillColor(GfxState *pGState)
|
||
{
|
||
if (m_sStates.empty())
|
||
return;
|
||
GfxColorSpace* pColorSpace = pGState->getFillColorSpace();
|
||
GfxColorSpaceMode eMode = pColorSpace->getMode();
|
||
GfxColor* pColor = pGState->getFillColor();
|
||
std::string sOp;
|
||
std::string sOp2;
|
||
switch (eMode)
|
||
{
|
||
case csDeviceGray:
|
||
{
|
||
sOp = std::to_string(colToDbl(pColor->c[0]));
|
||
sOp2 = "g";
|
||
break;
|
||
}
|
||
case csDeviceRGB:
|
||
{
|
||
sOp = std::to_string(colToDbl(pColor->c[0])) + " " + std::to_string(colToDbl(pColor->c[1])) + " " + std::to_string(colToDbl(pColor->c[2]));
|
||
sOp2 = "rg";
|
||
break;
|
||
}
|
||
case csDeviceCMYK:
|
||
{
|
||
sOp = std::to_string(colToDbl(pColor->c[0])) + " " + std::to_string(colToDbl(pColor->c[1])) + " " + std::to_string(colToDbl(pColor->c[2])) + " " + std::to_string(colToDbl(pColor->c[3]));
|
||
sOp2 = "k";
|
||
break;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
m_sStates.back().m_arrOp.push_back(std::make_pair(sOp, sOp2));
|
||
}
|
||
void RedactOutputDev::updateStrokeColor(GfxState *pGState)
|
||
{
|
||
if (m_sStates.empty())
|
||
return;
|
||
GfxColorSpace* pColorSpace = pGState->getStrokeColorSpace();
|
||
GfxColorSpaceMode eMode = pColorSpace->getMode();
|
||
GfxColor* pColor = pGState->getStrokeColor();
|
||
std::string sOp;
|
||
std::string sOp2;
|
||
switch (eMode)
|
||
{
|
||
case csDeviceGray:
|
||
{
|
||
sOp = std::to_string(colToDbl(pColor->c[0]));
|
||
sOp2 = "G";
|
||
break;
|
||
}
|
||
case csDeviceRGB:
|
||
{
|
||
sOp = std::to_string(colToDbl(pColor->c[0])) + " " + std::to_string(colToDbl(pColor->c[1])) + " " + std::to_string(colToDbl(pColor->c[2]));
|
||
sOp2 = "RG";
|
||
break;
|
||
}
|
||
case csDeviceCMYK:
|
||
{
|
||
sOp = std::to_string(colToDbl(pColor->c[0])) + " " + std::to_string(colToDbl(pColor->c[1])) + " " + std::to_string(colToDbl(pColor->c[2])) + " " + std::to_string(colToDbl(pColor->c[3]));
|
||
sOp2 = "K";
|
||
break;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
m_sStates.back().m_arrOp.push_back(std::make_pair(sOp, sOp2));
|
||
}
|
||
void RedactOutputDev::updateRenderingIntent(GfxState *pGState)
|
||
{
|
||
if (m_bUpdateAll || m_sStates.empty())
|
||
return;
|
||
std::string sOp = "/";
|
||
|
||
GfxRenderingIntent eRI = pGState->getRenderingIntent();
|
||
switch (eRI)
|
||
{
|
||
case GfxRenderingIntent::gfxRenderingIntentAbsoluteColorimetric:
|
||
sOp += "AbsoluteColorimetric";
|
||
break;
|
||
case GfxRenderingIntent::gfxRenderingIntentRelativeColorimetric:
|
||
sOp += "RelativeColorimetric";
|
||
break;
|
||
case GfxRenderingIntent::gfxRenderingIntentSaturation:
|
||
sOp += "Saturation";
|
||
break;
|
||
case GfxRenderingIntent::gfxRenderingIntentPerceptual:
|
||
default:
|
||
sOp += "Perceptual";
|
||
break;
|
||
}
|
||
m_sStates.back().m_arrOp.push_back(std::make_pair(sOp, "ri"));
|
||
}
|
||
//----- update text state
|
||
void RedactOutputDev::updateFont(GfxState *pGState)
|
||
{
|
||
GfxFont* pFont = pGState->getFont();
|
||
if (pFont)
|
||
{
|
||
m_pRenderer->m_oFont.SetSize(pGState->getFontSize());
|
||
m_pRenderer->put_FontName(NSFile::CUtf8Converter::GetUnicodeStringFromUTF8((BYTE*)pFont->getTag()->getCString(), pFont->getTag()->getLength()));
|
||
}
|
||
else
|
||
m_pRenderer->put_FontName(L"");
|
||
}
|
||
void RedactOutputDev::updateCharSpace(GfxState *pGState)
|
||
{
|
||
m_pRenderer->m_oFont.SetCharSpace(pGState->getCharSpace());
|
||
}
|
||
void RedactOutputDev::updateRender(GfxState *pGState)
|
||
{
|
||
int nRender = pGState->getRender();
|
||
m_pRenderer->m_oFont.SetRenderMode(nRender);
|
||
}
|
||
void RedactOutputDev::updateRise(GfxState *pGState)
|
||
{
|
||
m_pRenderer->m_oFont.SetRise(pGState->getRise());
|
||
}
|
||
void RedactOutputDev::updateWordSpace(GfxState *pGState)
|
||
{
|
||
m_pRenderer->m_oFont.SetWordSpace(pGState->getWordSpace());
|
||
}
|
||
void RedactOutputDev::updateHorizScaling(GfxState *pGState)
|
||
{
|
||
m_pRenderer->m_oFont.SetHorizontalScaling(pGState->getHorizScaling() * 100);
|
||
}
|
||
//----- path painting
|
||
void RedactOutputDev::stroke(GfxState *pGState)
|
||
{
|
||
DoPathRedact(pGState, pGState->getPath(), pGState->getCTM(), true);
|
||
DrawPath(c_nStroke);
|
||
}
|
||
void RedactOutputDev::fill(GfxState *pGState)
|
||
{
|
||
DoPathRedact(pGState, pGState->getPath(), pGState->getCTM());
|
||
DrawPath(c_nWindingFillMode);
|
||
}
|
||
void RedactOutputDev::eoFill(GfxState *pGState)
|
||
{
|
||
DoPathRedact(pGState, pGState->getPath(), pGState->getCTM(), false, true);
|
||
DrawPath(c_nEvenOddFillMode);
|
||
}
|
||
void RedactOutputDev::tilingPatternFill(GfxState *pGState, Gfx *gfx, Object *pStream, int nPaintType, int nTilingType, Dict *pResourcesDict,
|
||
double *pMatrix, double *pBBox, int nX0, int nY0, int nX1, int nY1, double dXStep, double dYStep)
|
||
{
|
||
}
|
||
//----- path clipping
|
||
void RedactOutputDev::clip(GfxState *pGState)
|
||
{
|
||
if (m_sStates.empty())
|
||
return;
|
||
|
||
if (!m_sStates.back().m_pClip)
|
||
m_sStates.back().m_pClip = new GfxClip();
|
||
int nClipFlag = c_nClipRegionIntersect | c_nClipRegionTypeWinding;
|
||
m_sStates.back().m_pClip->AddPath(pGState->getPath(), pGState->getCTM(), nClipFlag);
|
||
AddClip(pGState, &m_sStates.back(), m_sStates.back().m_pClip->GetPathNum() - 1);
|
||
}
|
||
void RedactOutputDev::eoClip(GfxState *pGState)
|
||
{
|
||
if (m_sStates.empty())
|
||
return;
|
||
|
||
if (!m_sStates.back().m_pClip)
|
||
m_sStates.back().m_pClip = new GfxClip();
|
||
int nClipFlag = c_nClipRegionIntersect | c_nClipRegionTypeEvenOdd;
|
||
m_sStates.back().m_pClip->AddPath(pGState->getPath(), pGState->getCTM(), nClipFlag);
|
||
AddClip(pGState, &m_sStates.back(), m_sStates.back().m_pClip->GetPathNum() - 1);
|
||
}
|
||
void RedactOutputDev::clipToStrokePath(GfxState *pGState)
|
||
{
|
||
if (m_sStates.empty())
|
||
return;
|
||
|
||
if (!m_sStates.back().m_pClip)
|
||
m_sStates.back().m_pClip = new GfxClip();
|
||
int nClipFlag = c_nClipRegionIntersect | c_nClipRegionTypeWinding | c_nClipToStrokePath;
|
||
m_sStates.back().m_pClip->AddPath(pGState->getPath(), pGState->getCTM(), nClipFlag);
|
||
AddClip(pGState, &m_sStates.back(), m_sStates.back().m_pClip->GetPathNum() - 1);
|
||
}
|
||
//----- text drawing
|
||
void RedactOutputDev::beginStringOp(GfxState *pGState)
|
||
{
|
||
m_pRenderer->m_oCommandManager.Flush();
|
||
DoStateOp();
|
||
}
|
||
void RedactOutputDev::drawChar(GfxState *pGState, double dX, double dY, double dDx, double dDy, double dOriginX, double dOriginY,
|
||
CharCode nCode, int nBytesCount, Unicode *pUnicode, int nUnicodeLen)
|
||
{
|
||
double* pCTM = pGState->getCTM();
|
||
double* pTm = pGState->getTextMat();
|
||
double pNewTm[6], arrMatrix[6];
|
||
|
||
double dTextScale = std::min(sqrt(pTm[2] * pTm[2] + pTm[3] * pTm[3]), sqrt(pTm[0] * pTm[0] + pTm[1] * pTm[1]));
|
||
double dITextScale = 1 / dTextScale;
|
||
double dOldSize = 10.0;
|
||
m_pRenderer->get_FontSize(&dOldSize);
|
||
if (dOldSize * dTextScale > 0)
|
||
{
|
||
m_pRenderer->put_FontSize(dOldSize * dTextScale);
|
||
|
||
pNewTm[0] = pTm[0] * dITextScale * pGState->getHorizScaling();
|
||
pNewTm[1] = pTm[1] * dITextScale * pGState->getHorizScaling();
|
||
pNewTm[2] = pTm[2] * dITextScale;
|
||
pNewTm[3] = pTm[3] * dITextScale;
|
||
pNewTm[4] = dX - dOriginX;
|
||
pNewTm[5] = dY - dOriginY;
|
||
}
|
||
else
|
||
{
|
||
m_pRenderer->put_FontSize(-dOldSize * dTextScale);
|
||
|
||
pNewTm[0] = pTm[0] * dITextScale * pGState->getHorizScaling();
|
||
pNewTm[1] = pTm[1] * dITextScale * pGState->getHorizScaling();
|
||
pNewTm[2] = pTm[2] * dITextScale;
|
||
pNewTm[3] = pTm[3] * dITextScale;
|
||
pNewTm[4] = dX;
|
||
pNewTm[5] = dY;
|
||
}
|
||
|
||
arrMatrix[0] = pNewTm[0] * pCTM[0] + pNewTm[1] * pCTM[2];
|
||
arrMatrix[1] = pNewTm[0] * pCTM[1] + pNewTm[1] * pCTM[3];
|
||
arrMatrix[2] = pNewTm[2] * pCTM[0] + pNewTm[3] * pCTM[2];
|
||
arrMatrix[3] = pNewTm[2] * pCTM[1] + pNewTm[3] * pCTM[3];
|
||
arrMatrix[4] = pNewTm[4] * pCTM[0] + pNewTm[5] * pCTM[2] + pCTM[4];
|
||
arrMatrix[5] = pNewTm[4] * pCTM[1] + pNewTm[5] * pCTM[3] + pCTM[5];
|
||
|
||
double dSize = 1;
|
||
if (true)
|
||
{
|
||
double dNorma = std::min(sqrt(arrMatrix[0] * arrMatrix[0] + arrMatrix[1] * arrMatrix[1]), sqrt(arrMatrix[2] * arrMatrix[2] + arrMatrix[3] * arrMatrix[3]));
|
||
if (dNorma > 0 && dNorma != 1)
|
||
{
|
||
arrMatrix[0] /= dNorma;
|
||
arrMatrix[1] /= dNorma;
|
||
arrMatrix[2] /= dNorma;
|
||
arrMatrix[3] /= dNorma;
|
||
|
||
m_pRenderer->get_FontSize(&dSize);
|
||
dSize *= dNorma;
|
||
m_pRenderer->put_FontSize(dSize);
|
||
}
|
||
}
|
||
|
||
double dShiftX = 0, dShiftY = 0;
|
||
DoTransform(arrMatrix, &dShiftX, &dShiftY, true);
|
||
|
||
double startX, startY, endX, endY;
|
||
pGState->transform(dX, dY, &startX, &startY);
|
||
pGState->transform(dX + dDx, dY + dDy, &endX, &endY);
|
||
double dCenterX = (startX + endX) / 2;
|
||
double dCenterY = (startY + endY) / 2;
|
||
for (int i = 0; i < m_arrQuadPoints.size(); i += 8)
|
||
{
|
||
double x1 = m_arrQuadPoints[i + 0];
|
||
double y1 = m_arrQuadPoints[i + 1];
|
||
double x2 = m_arrQuadPoints[i + 2];
|
||
double y2 = m_arrQuadPoints[i + 3];
|
||
double x3 = m_arrQuadPoints[i + 4];
|
||
double y3 = m_arrQuadPoints[i + 5];
|
||
double x4 = m_arrQuadPoints[i + 6];
|
||
double y4 = m_arrQuadPoints[i + 7];
|
||
|
||
if (isPointInQuad(dCenterX, dCenterY, x1, y1, x2, y2, x3, y3, x4, y4))
|
||
{
|
||
m_pRenderer->put_FontSize(dOldSize);
|
||
return;
|
||
}
|
||
}
|
||
|
||
BYTE* pCodes = new BYTE[2];
|
||
pCodes[0] = (nCode >> 8) & 0xFF;
|
||
pCodes[1] = nCode & 0xFF;
|
||
|
||
m_pRenderer->m_oCommandManager.SetTransform(m_arrMatrix[0], m_arrMatrix[1], m_arrMatrix[2], m_arrMatrix[3], m_arrMatrix[4], m_arrMatrix[5]);
|
||
|
||
CRendererTextCommand* pText = m_pRenderer->m_oCommandManager.AddText(pCodes, 2, dShiftX, dShiftY);
|
||
pText->SetName(m_pRenderer->m_oFont.GetName());
|
||
pText->SetSize(m_pRenderer->m_oFont.GetSize());
|
||
pText->SetType((EFontType)pGState->getFont()->getType());
|
||
pText->SetCharSpace(m_pRenderer->m_oFont.GetCharSpace());
|
||
pText->SetMode(m_pRenderer->m_oFont.GetRenderMode());
|
||
pText->SetRise(m_pRenderer->m_oFont.GetRise());
|
||
pText->SetWordSpace(m_pRenderer->m_oFont.GetWordSpace());
|
||
pText->SetHorScaling(m_pRenderer->m_oFont.GetHorizontalScaling());
|
||
pText->SetWidth(dDx);
|
||
|
||
m_pRenderer->put_FontSize(dOldSize);
|
||
}
|
||
//----- additional
|
||
GBool RedactOutputDev::useNameOp()
|
||
{
|
||
return gTrue;
|
||
}
|
||
void RedactOutputDev::setExtGState(const char* name)
|
||
{
|
||
if (m_sStates.empty())
|
||
return;
|
||
std::string sOp = "/" + std::string(name);
|
||
m_sStates.back().m_arrOp.push_back(std::make_pair(sOp, "gs"));
|
||
}
|
||
void RedactOutputDev::setFillColorSpace(const char* name)
|
||
{
|
||
if (m_sStates.empty())
|
||
return;
|
||
std::string sOp = "/" + std::string(name);
|
||
m_sStates.back().m_arrOp.push_back(std::make_pair(sOp, "cs"));
|
||
}
|
||
void RedactOutputDev::setFillColor(Object* args, int numArgs)
|
||
{
|
||
if (m_sStates.empty())
|
||
return;
|
||
std::string sOp;
|
||
for (int i = 0; i < numArgs; ++i)
|
||
{
|
||
if (args[i].isName())
|
||
sOp += ("/" + std::string(args[i].getName()) + " ");
|
||
else if (args[i].isInt())
|
||
sOp += (std::to_string(args[i].getInt()) + " ");
|
||
else if (args[i].isReal())
|
||
sOp += (std::to_string(args[i].getReal()) + " ");
|
||
}
|
||
m_sStates.back().m_arrOp.push_back(std::make_pair(sOp, "sc"));
|
||
}
|
||
void RedactOutputDev::setFillColorN(Object* args, int numArgs)
|
||
{
|
||
if (m_sStates.empty())
|
||
return;
|
||
std::string sOp;
|
||
for (int i = 0; i < numArgs; ++i)
|
||
{
|
||
if (args[i].isName())
|
||
sOp += ("/" + std::string(args[i].getName()) + " ");
|
||
else if (args[i].isInt())
|
||
sOp += (std::to_string(args[i].getInt()) + " ");
|
||
else if (args[i].isReal())
|
||
sOp += (std::to_string(args[i].getReal()) + " ");
|
||
}
|
||
m_sStates.back().m_arrOp.push_back(std::make_pair(sOp, "scn"));
|
||
}
|
||
void RedactOutputDev::setStrokeColorSpace(const char* name)
|
||
{
|
||
if (m_sStates.empty())
|
||
return;
|
||
std::string sOp = "/" + std::string(name);
|
||
m_sStates.back().m_arrOp.push_back(std::make_pair(sOp, "CS"));
|
||
}
|
||
void RedactOutputDev::setStrokeColor(Object* args, int numArgs)
|
||
{
|
||
if (m_sStates.empty())
|
||
return;
|
||
std::string sOp;
|
||
for (int i = 0; i < numArgs; ++i)
|
||
{
|
||
if (args[i].isName())
|
||
sOp += ("/" + std::string(args[i].getName()) + " ");
|
||
else if (args[i].isInt())
|
||
sOp += (std::to_string(args[i].getInt()) + " ");
|
||
else if (args[i].isReal())
|
||
sOp += (std::to_string(args[i].getReal()) + " ");
|
||
}
|
||
m_sStates.back().m_arrOp.push_back(std::make_pair(sOp, "SC"));
|
||
}
|
||
void RedactOutputDev::setStrokeColorN(Object* args, int numArgs)
|
||
{
|
||
if (m_sStates.empty())
|
||
return;
|
||
std::string sOp;
|
||
for (int i = 0; i < numArgs; ++i)
|
||
{
|
||
if (args[i].isName())
|
||
sOp += ("/" + std::string(args[i].getName()) + " ");
|
||
else if (args[i].isInt())
|
||
sOp += (std::to_string(args[i].getInt()) + " ");
|
||
else if (args[i].isReal())
|
||
sOp += (std::to_string(args[i].getReal()) + " ");
|
||
}
|
||
m_sStates.back().m_arrOp.push_back(std::make_pair(sOp, "SCN"));
|
||
}
|
||
void RedactOutputDev::setShading(GfxState *pGState, const char* name)
|
||
{
|
||
m_pRenderer->m_oCommandManager.Flush();
|
||
DoStateOp();
|
||
|
||
double dShiftX = 0, dShiftY = 0;
|
||
DoTransform(pGState->getCTM(), &dShiftX, &dShiftY, true);
|
||
|
||
// TODO Нужно проверять Shading на отсечение?
|
||
|
||
m_pPage->GrSave();
|
||
UpdateTransform();
|
||
DoStateOp();
|
||
CStream* pStream = m_pPage->GetStream();
|
||
pStream->WriteEscapeName(name);
|
||
pStream->WriteChar(' ');
|
||
pStream->WriteStr("sh");
|
||
pStream->WriteStr("\012");
|
||
m_pPage->GrRestore();
|
||
}
|
||
//----- image drawing
|
||
void RedactOutputDev::drawImageMask(GfxState *pGState, Object *pRef, Stream *pStream, int nWidth, int nHeight, GBool bInvert, GBool bInlineImage, GBool interpolate)
|
||
{
|
||
|
||
}
|
||
void RedactOutputDev::setSoftMaskFromImageMask(GfxState *pGState, Object *pRef, Stream *pStream, int nWidth, int nHeight, GBool bInvert, GBool bInlineImage, GBool interpolate)
|
||
{
|
||
|
||
}
|
||
void RedactOutputDev::drawImage(GfxState *pGState, Object *pRef, Stream *pStream, int nWidth, int nHeight, GfxImageColorMap *pColorMap, int *pMaskColors, GBool bInlineImg, GBool interpolate)
|
||
{
|
||
|
||
}
|
||
void RedactOutputDev::drawMaskedImage(GfxState *pGState, Object *pRef, Stream *pStream, int nWidth, int nHeight, GfxImageColorMap *pColorMap,
|
||
Object* pMaskRef, Stream *pMaskStream, int nMaskWidth, int nMaskHeight, GBool bMaskInvert, GBool interpolate)
|
||
{
|
||
|
||
}
|
||
void RedactOutputDev::drawSoftMaskedImage(GfxState *pGState, Object *pRef, Stream *pStream, int nWidth, int nHeight, GfxImageColorMap *pColorMap,
|
||
Object *maskRef, Stream *pMaskStream, int nMaskWidth, int nMaskHeight, GfxImageColorMap *pMaskColorMap, double *pMatte, GBool interpolate)
|
||
{
|
||
|
||
}
|
||
//----- Type 3 font operators
|
||
void RedactOutputDev::type3D0(GfxState *pGState, double wx, double wy)
|
||
{
|
||
|
||
}
|
||
void RedactOutputDev::type3D1(GfxState *pGState, double wx, double wy, double llx, double lly, double urx, double ury)
|
||
{
|
||
|
||
}
|
||
//----- form XObjects
|
||
void RedactOutputDev::drawForm(GfxState *pGState, Ref id, const char* name)
|
||
{
|
||
m_pRenderer->m_oCommandManager.Flush();
|
||
DoStateOp();
|
||
|
||
double dShiftX = 0, dShiftY = 0;
|
||
DoTransform(pGState->getCTM(), &dShiftX, &dShiftY, true);
|
||
|
||
// TODO пока что исключается всё изображение
|
||
Object oForm;
|
||
if (!m_pXref->fetch(id.num, id.gen, &oForm)->isStream())
|
||
{
|
||
oForm.free();
|
||
return;
|
||
}
|
||
|
||
double dXmin = 0, dYmin = 0, dXmax = 0, dYmax = 0;
|
||
double dX1 = 0, dY1 = 0, dX2 = 0, dY2 = 1, dX3 = 1, dY3 = 1, dX4 = 1, dY4 = 0;
|
||
Object oObj;
|
||
if (oForm.streamGetDict()->lookup("BBox", &oObj)->isArray() && oObj.arrayGetLength() == 4)
|
||
{
|
||
Object oNum;
|
||
if (oObj.arrayGet(0, &oNum)->isNum())
|
||
dXmin = oNum.getNum();
|
||
oNum.free();
|
||
if (oObj.arrayGet(1, &oNum)->isNum())
|
||
dYmin = oNum.getNum();
|
||
oNum.free();
|
||
if (oObj.arrayGet(2, &oNum)->isNum())
|
||
dXmax = oNum.getNum();
|
||
oNum.free();
|
||
if (oObj.arrayGet(3, &oNum)->isNum())
|
||
dYmax = oNum.getNum();
|
||
oNum.free(); oObj.free();
|
||
|
||
dX1 = dXmin, dY1 = dYmin;
|
||
dX2 = dXmin, dY2 = dYmax;
|
||
dX3 = dXmax, dY3 = dYmax;
|
||
dX4 = dXmax, dY4 = dYmin;
|
||
|
||
double oMatrix[6] = { 1, 0, 0, 1, 0, 0 };
|
||
if (oForm.streamGetDict()->lookup("Matrix", &oObj)->isArray() && oObj.arrayGetLength() == 6)
|
||
{
|
||
Object oObj2;
|
||
for (int i = 0; i < 6; ++i)
|
||
{
|
||
oMatrix[i] = oObj.arrayGet(i, &oObj2)->getNum();
|
||
oObj2.free();
|
||
}
|
||
}
|
||
|
||
Transform(oMatrix, dX1, dY1, &dX1, &dY1);
|
||
Transform(oMatrix, dX2, dY2, &dX2, &dY2);
|
||
Transform(oMatrix, dX3, dY3, &dX3, &dY3);
|
||
Transform(oMatrix, dX4, dY4, &dX4, &dY4);
|
||
|
||
Transform(m_arrMatrix, dX1, dY1, &dX1, &dY1);
|
||
Transform(m_arrMatrix, dX2, dY2, &dX2, &dY2);
|
||
Transform(m_arrMatrix, dX3, dY3, &dX3, &dY3);
|
||
Transform(m_arrMatrix, dX4, dY4, &dX4, &dY4);
|
||
}
|
||
oObj.free();
|
||
|
||
std::vector<CPoint> poly2 =
|
||
{
|
||
CPoint(dX1, dY1),
|
||
CPoint(dX2, dY2),
|
||
CPoint(dX3, dY3),
|
||
CPoint(dX4, dY4)
|
||
};
|
||
for (int i = 0; i < m_arrQuadPoints.size(); i += 8)
|
||
{
|
||
std::vector<CPoint> poly1 =
|
||
{
|
||
CPoint(m_arrQuadPoints[i + 0], m_arrQuadPoints[i + 1]),
|
||
CPoint(m_arrQuadPoints[i + 2], m_arrQuadPoints[i + 3]),
|
||
CPoint(m_arrQuadPoints[i + 4], m_arrQuadPoints[i + 5]),
|
||
CPoint(m_arrQuadPoints[i + 6], m_arrQuadPoints[i + 7])
|
||
};
|
||
|
||
if (PdfWriter::SAT(poly1, poly2))
|
||
return;
|
||
}
|
||
|
||
m_pPage->GrSave();
|
||
UpdateTransform();
|
||
m_pPage->ExecuteXObject(name);
|
||
m_pPage->GrRestore();
|
||
}
|
||
void RedactOutputDev::drawImage(GfxState *pGState, Ref id, const char* name)
|
||
{
|
||
m_pRenderer->m_oCommandManager.Flush();
|
||
DoStateOp();
|
||
|
||
double dShiftX = 0, dShiftY = 0;
|
||
DoTransform(pGState->getCTM(), &dShiftX, &dShiftY, true);
|
||
|
||
// TODO пока что исключается всё изображение
|
||
|
||
double dX1 = 0, dY1 = 0, dX2 = 0, dY2 = 1, dX3 = 1, dY3 = 1, dX4 = 1, dY4 = 0;
|
||
Transform(m_arrMatrix, dX1, dY1, &dX1, &dY1);
|
||
Transform(m_arrMatrix, dX2, dY2, &dX2, &dY2);
|
||
Transform(m_arrMatrix, dX3, dY3, &dX3, &dY3);
|
||
Transform(m_arrMatrix, dX4, dY4, &dX4, &dY4);
|
||
|
||
std::vector<CPoint> poly2 =
|
||
{
|
||
CPoint(dX1, dY1),
|
||
CPoint(dX2, dY2),
|
||
CPoint(dX3, dY3),
|
||
CPoint(dX4, dY4)
|
||
};
|
||
for (int j = 0; j < m_arrQuadPoints.size(); j += 8)
|
||
{
|
||
std::vector<CPoint> poly1 =
|
||
{
|
||
CPoint(m_arrQuadPoints[j + 0], m_arrQuadPoints[j + 1]),
|
||
CPoint(m_arrQuadPoints[j + 2], m_arrQuadPoints[j + 3]),
|
||
CPoint(m_arrQuadPoints[j + 4], m_arrQuadPoints[j + 5]),
|
||
CPoint(m_arrQuadPoints[j + 6], m_arrQuadPoints[j + 7])
|
||
};
|
||
|
||
if (PdfWriter::SAT(poly1, poly2))
|
||
return;
|
||
}
|
||
|
||
m_pPage->GrSave();
|
||
UpdateTransform();
|
||
m_pPage->ExecuteXObject(name);
|
||
m_pPage->GrRestore();
|
||
}
|
||
//----- transparency groups and soft masks
|
||
void RedactOutputDev::beginTransparencyGroup(GfxState *pGState, double *pBBox, GfxColorSpace *pBlendingColorSpace, GBool bIsolated, GBool bKnockout, GBool bForSoftMask)
|
||
{
|
||
|
||
}
|
||
void RedactOutputDev::endTransparencyGroup(GfxState *pGState)
|
||
{
|
||
|
||
}
|
||
void RedactOutputDev::paintTransparencyGroup(GfxState *pGState, double *pBBox)
|
||
{
|
||
|
||
}
|
||
void RedactOutputDev::setSoftMask(GfxState *pGState, double *pBBox, GBool bAlpha, Function *pTransferFunc, GfxColor *pBackdropColor)
|
||
{
|
||
|
||
}
|
||
void RedactOutputDev::clearSoftMask(GfxState *pGState)
|
||
{
|
||
|
||
}
|
||
|
||
bool SkipPath(const std::vector<CSegment>& arrForStroke, const CPoint& P1, const CPoint& P2)
|
||
{
|
||
for (int i = 0; i < arrForStroke.size(); ++i)
|
||
{
|
||
CPoint P3 = arrForStroke[i].start;
|
||
CPoint P4 = arrForStroke[i].end;
|
||
// Вычисляем коэффициенты A, B, C для уравнения прямой P3P4: Ax + By + C = 0
|
||
double A = P4.y - P3.y;
|
||
double B = P3.x - P4.x;
|
||
double C = P4.x * P3.y - P3.x * P4.y;
|
||
|
||
// Проверяем, лежит ли точка P1 на прямой P3P4
|
||
double check1 = A * P1.x + B * P1.y + C;
|
||
|
||
// Проверяем, лежит ли точка P2 на прямой P3P4
|
||
double check2 = A * P2.x + B * P2.y + C;
|
||
|
||
// Если обе проверки близки к нулю (в пределах эпсилон), то лежит
|
||
if ((std::abs(check1) < 0.006) && (std::abs(check2) < 0.006))
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
void RedactOutputDev::DrawPathRedact(Aggplus::CGraphicsPath* oPath, bool bStroke, const std::vector<CSegment>& arrForStroke)
|
||
{
|
||
CMatrix oMatrix(m_arrMatrix[0], m_arrMatrix[1], m_arrMatrix[2], m_arrMatrix[3], m_arrMatrix[4], m_arrMatrix[5]);
|
||
CMatrix oInverse = oMatrix.Inverse();
|
||
|
||
size_t length = oPath->GetPointCount(), compound = oPath->GetCloseCount();
|
||
std::vector<Aggplus::PointD> points = oPath->GetPoints(0, length + compound);
|
||
|
||
double dXStart = -1, dYStart = -1, dXCur = -1, dYCur = -1;
|
||
bool bBreak = false;
|
||
for (size_t i = 0; i < length + compound; i++)
|
||
{
|
||
if (oPath->IsCurvePoint(i))
|
||
{
|
||
double dX = points[i].X;
|
||
double dY = points[i].Y;
|
||
oInverse.Apply(dX, dY);
|
||
double dX2 = points[i + 1].X;
|
||
double dY2 = points[i + 1].Y;
|
||
oInverse.Apply(dX2, dY2);
|
||
double dX3 = points[i + 2].X;
|
||
double dY3 = points[i + 2].Y;
|
||
if (bBreak)
|
||
{
|
||
bBreak = false;
|
||
double dXCI = dXCur, dYCI = dYCur;
|
||
oInverse.Apply(dXCI, dYCI);
|
||
m_pRenderer->m_oPath.MoveTo(dXCI, dYCI);
|
||
}
|
||
dXCur = dX3; dYCur = dY3;
|
||
oInverse.Apply(dX3, dY3);
|
||
m_pRenderer->m_oPath.CurveTo(dX, dY, dX2, dY2, dX3, dY3);
|
||
|
||
i += 2;
|
||
}
|
||
else if (oPath->IsMovePoint(i))
|
||
{
|
||
double dX = points[i].X, dY = points[i].Y;
|
||
dXStart = dX; dYStart = dY; dXCur = dX; dYCur = dY;
|
||
if (bStroke)
|
||
bBreak = true;
|
||
else
|
||
{
|
||
oInverse.Apply(dX, dY);
|
||
m_pRenderer->m_oPath.MoveTo(dX, dY);
|
||
}
|
||
}
|
||
else if (oPath->IsLinePoint(i))
|
||
{
|
||
double dX = points[i].X, dY = points[i].Y;
|
||
if (bStroke && SkipPath(arrForStroke, CPoint(dXCur, dYCur), CPoint(dX, dY)))
|
||
{
|
||
dXCur = dX; dYCur = dY;
|
||
bBreak = true;
|
||
continue;
|
||
}
|
||
if (bBreak)
|
||
{
|
||
bBreak = false;
|
||
double dXCI = dXCur, dYCI = dYCur;
|
||
oInverse.Apply(dXCI, dYCI);
|
||
m_pRenderer->m_oPath.MoveTo(dXCI, dYCI);
|
||
}
|
||
dXCur = dX; dYCur = dY;
|
||
oInverse.Apply(dX, dY);
|
||
m_pRenderer->m_oPath.LineTo(dX, dY);
|
||
}
|
||
else if (oPath->IsClosePoint(i))
|
||
{
|
||
if (bStroke && (std::abs(dXCur - dXStart) > EPS || std::abs(dYCur - dYStart) > EPS) && SkipPath(arrForStroke, CPoint(dXCur, dYCur), CPoint(dXStart, dYStart)))
|
||
{
|
||
dXCur = dXStart; dYCur = dYStart;
|
||
bBreak = true;
|
||
continue;
|
||
}
|
||
if (bStroke || bBreak)
|
||
{
|
||
if (std::abs(dXCur - dXStart) > EPS || std::abs(dYCur - dYStart) > EPS)
|
||
{
|
||
bBreak = false;
|
||
double dXCI = dXCur, dYCI = dYCur;
|
||
oInverse.Apply(dXCI, dYCI);
|
||
double dXSI = dXStart, dYSI = dYStart;
|
||
oInverse.Apply(dXSI, dYSI);
|
||
m_pRenderer->m_oPath.MoveTo(dXCI, dYCI);
|
||
m_pRenderer->m_oPath.LineTo(dXSI, dYSI);
|
||
}
|
||
}
|
||
else
|
||
m_pRenderer->m_oPath.Close();
|
||
}
|
||
}
|
||
}
|
||
void RedactOutputDev::DoPathRedact(GfxState* pGState, GfxPath* pPath, double* pCTM, bool bStroke, bool bEoFill)
|
||
{
|
||
double arrMatrix[6];
|
||
arrMatrix[0] = pCTM[0];
|
||
arrMatrix[1] = pCTM[1];
|
||
arrMatrix[2] = pCTM[2];
|
||
arrMatrix[3] = pCTM[3];
|
||
arrMatrix[4] = pCTM[4];
|
||
arrMatrix[5] = pCTM[5];
|
||
|
||
double dShiftX = 0, dShiftY = 0;
|
||
DoTransform(arrMatrix, &dShiftX, &dShiftY, true);
|
||
m_pRenderer->m_oPath.Clear();
|
||
|
||
CMatrix oMatrix(m_arrMatrix[0], m_arrMatrix[1], m_arrMatrix[2], m_arrMatrix[3], m_arrMatrix[4], m_arrMatrix[5]);
|
||
CMatrix oInverse = oMatrix.Inverse();
|
||
|
||
std::vector<CSegment> arrForStroke;
|
||
Aggplus::CGraphicsPath oPath, oPathResult;
|
||
if (bEoFill)
|
||
oPath.SetRuler(true);
|
||
|
||
if (bStroke)
|
||
{
|
||
std::vector<std::vector<CPoint>> rectangles;
|
||
for (int i = 0; i < m_arrQuadPoints.size(); i += 8)
|
||
{
|
||
arrForStroke.push_back(CSegment(CPoint(m_arrQuadPoints[i + 0], m_arrQuadPoints[i + 1]), CPoint(m_arrQuadPoints[i + 2], m_arrQuadPoints[i + 3])));
|
||
arrForStroke.push_back(CSegment(CPoint(m_arrQuadPoints[i + 2], m_arrQuadPoints[i + 3]), CPoint(m_arrQuadPoints[i + 4], m_arrQuadPoints[i + 5])));
|
||
arrForStroke.push_back(CSegment(CPoint(m_arrQuadPoints[i + 4], m_arrQuadPoints[i + 5]), CPoint(m_arrQuadPoints[i + 6], m_arrQuadPoints[i + 7])));
|
||
arrForStroke.push_back(CSegment(CPoint(m_arrQuadPoints[i + 6], m_arrQuadPoints[i + 7]), CPoint(m_arrQuadPoints[i + 0], m_arrQuadPoints[i + 1])));
|
||
|
||
std::vector<CPoint> rectangle = { CPoint(m_arrQuadPoints[i + 0], m_arrQuadPoints[i + 1]), CPoint(m_arrQuadPoints[i + 2], m_arrQuadPoints[i + 3]),
|
||
CPoint(m_arrQuadPoints[i + 4], m_arrQuadPoints[i + 5]), CPoint(m_arrQuadPoints[i + 6], m_arrQuadPoints[i + 7]) };
|
||
rectangles.push_back(rectangle);
|
||
}
|
||
|
||
for (int nSubPathIndex = 0, nSubPathCount = pPath->getNumSubpaths(); nSubPathIndex < nSubPathCount; ++nSubPathIndex)
|
||
{
|
||
GfxSubpath* pSubpath = pPath->getSubpath(nSubPathIndex);
|
||
int nPointsCount = pSubpath->getNumPoints();
|
||
|
||
double dX = pSubpath->getX(0), dY = pSubpath->getY(0);
|
||
oMatrix.Apply(dX, dY);
|
||
double dXStart = dX, dYStart = dY, dXCur = dX, dYCur = dY;
|
||
|
||
int nCurPointIndex = 1;
|
||
while (nCurPointIndex < nPointsCount)
|
||
{
|
||
if (pSubpath->getCurve(nCurPointIndex))
|
||
{
|
||
dX = pSubpath->getX(nCurPointIndex);
|
||
dY = pSubpath->getY(nCurPointIndex);
|
||
oMatrix.Apply(dX, dY);
|
||
double dX2 = pSubpath->getX(nCurPointIndex + 1);
|
||
double dY2 = pSubpath->getY(nCurPointIndex + 1);
|
||
oMatrix.Apply(dX2, dY2);
|
||
double dX3 = pSubpath->getX(nCurPointIndex + 2);
|
||
double dY3 = pSubpath->getY(nCurPointIndex + 2);
|
||
oMatrix.Apply(dX3, dY3);
|
||
nCurPointIndex += 3;
|
||
|
||
oPath.StartFigure();
|
||
oPath.MoveTo(dXCur, dYCur);
|
||
oPath.CurveTo(dX, dY, dX2, dY2, dX3, dY3);
|
||
oPath.CloseFigure();
|
||
|
||
arrForStroke.push_back(CSegment(CPoint(dXCur, dYCur), CPoint(dX3, dY3)));
|
||
dXCur = dX3, dYCur = dY3;
|
||
|
||
oPathResult = Aggplus::CalcBooleanOperation(oPath, m_oPathRedact, Aggplus::BooleanOpType::Subtraction);
|
||
DrawPathRedact(&oPathResult, bStroke, arrForStroke);
|
||
oPathResult.Reset(); oPath.Reset();
|
||
}
|
||
else
|
||
{
|
||
dX = pSubpath->getX(nCurPointIndex);
|
||
dY = pSubpath->getY(nCurPointIndex);
|
||
oMatrix.Apply(dX, dY);
|
||
++nCurPointIndex;
|
||
|
||
CSegment line(CPoint(dXCur, dYCur), CPoint(dX, dY));
|
||
dXCur = dX; dYCur = dY;
|
||
auto visibleSegments = RectangleIntersection::findSegmentsOutsideRectangles(line, rectangles);
|
||
|
||
for (int i = 0; i < visibleSegments.size(); ++i)
|
||
{
|
||
double dX1 = visibleSegments[i].start.x, dY1 = visibleSegments[i].start.y;
|
||
double dX2 = visibleSegments[i].end.x, dY2 = visibleSegments[i].end.y;
|
||
oInverse.Apply(dX1, dY1);
|
||
m_pRenderer->m_oPath.MoveTo(dX1, dY1);
|
||
oInverse.Apply(dX2, dY2);
|
||
m_pRenderer->m_oPath.LineTo(dX2, dY2);
|
||
}
|
||
}
|
||
}
|
||
if (pSubpath->isClosed())
|
||
{
|
||
CSegment line(CPoint(dXCur, dYCur), CPoint(dXStart, dYStart));
|
||
auto visibleSegments = RectangleIntersection::findSegmentsOutsideRectangles(line, rectangles);
|
||
for (int i = 0; i < visibleSegments.size(); ++i)
|
||
{
|
||
double dX1 = visibleSegments[i].start.x, dY1 = visibleSegments[i].start.y;
|
||
double dX2 = visibleSegments[i].end.x, dY2 = visibleSegments[i].end.y;
|
||
oInverse.Apply(dX1, dY1);
|
||
m_pRenderer->m_oPath.MoveTo(dX1, dY1);
|
||
oInverse.Apply(dX2, dY2);
|
||
m_pRenderer->m_oPath.LineTo(dX2, dY2);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
for (int nSubPathIndex = 0, nSubPathCount = pPath->getNumSubpaths(); nSubPathIndex < nSubPathCount; ++nSubPathIndex)
|
||
{
|
||
GfxSubpath* pSubpath = pPath->getSubpath(nSubPathIndex);
|
||
int nPointsCount = pSubpath->getNumPoints();
|
||
|
||
oPath.StartFigure();
|
||
|
||
double dX = pSubpath->getX(0), dY = pSubpath->getY(0);
|
||
oMatrix.Apply(dX, dY);
|
||
oPath.MoveTo(dX, dY);
|
||
|
||
int nCurPointIndex = 1;
|
||
while (nCurPointIndex < nPointsCount)
|
||
{
|
||
if (pSubpath->getCurve(nCurPointIndex))
|
||
{
|
||
dX = pSubpath->getX(nCurPointIndex);
|
||
dY = pSubpath->getY(nCurPointIndex);
|
||
oMatrix.Apply(dX, dY);
|
||
double dX2 = pSubpath->getX(nCurPointIndex + 1);
|
||
double dY2 = pSubpath->getY(nCurPointIndex + 1);
|
||
oMatrix.Apply(dX2, dY2);
|
||
double dX3 = pSubpath->getX(nCurPointIndex + 2);
|
||
double dY3 = pSubpath->getY(nCurPointIndex + 2);
|
||
oMatrix.Apply(dX3, dY3);
|
||
oPath.CurveTo(dX, dY, dX2, dY2, dX3, dY3);
|
||
nCurPointIndex += 3;
|
||
}
|
||
else
|
||
{
|
||
dX = pSubpath->getX(nCurPointIndex);
|
||
dY = pSubpath->getY(nCurPointIndex);
|
||
oMatrix.Apply(dX, dY);
|
||
oPath.LineTo(dX, dY);
|
||
++nCurPointIndex;
|
||
}
|
||
}
|
||
// if (pSubpath->isClosed()) Принудительное замыкание фигур для CGraphicsPath
|
||
oPath.CloseFigure();
|
||
}
|
||
|
||
oPathResult = Aggplus::CalcBooleanOperation(oPath, m_oPathRedact, Aggplus::BooleanOpType::Subtraction);
|
||
DrawPathRedact(&oPathResult, bStroke);
|
||
}
|
||
}
|
||
void RedactOutputDev::DoPath(GfxState* pGState, GfxPath* pPath, double* pCTM)
|
||
{
|
||
double arrMatrix[6];
|
||
arrMatrix[0] = pCTM[0];
|
||
arrMatrix[1] = pCTM[1];
|
||
arrMatrix[2] = pCTM[2];
|
||
arrMatrix[3] = pCTM[3];
|
||
arrMatrix[4] = pCTM[4];
|
||
arrMatrix[5] = pCTM[5];
|
||
|
||
double dShiftX = 0, dShiftY = 0;
|
||
DoTransform(arrMatrix, &dShiftX, &dShiftY, true);
|
||
|
||
m_pRenderer->m_oPath.Clear();
|
||
|
||
for (int nSubPathIndex = 0, nSubPathCount = pPath->getNumSubpaths(); nSubPathIndex < nSubPathCount; ++nSubPathIndex)
|
||
{
|
||
GfxSubpath* pSubpath = pPath->getSubpath(nSubPathIndex);
|
||
int nPointsCount = pSubpath->getNumPoints();
|
||
|
||
double dX = pSubpath->getX(0), dY = pSubpath->getY(0);
|
||
m_pRenderer->m_oPath.MoveTo(dX, dY);
|
||
|
||
int nCurPointIndex = 1;
|
||
while (nCurPointIndex < nPointsCount)
|
||
{
|
||
if (pSubpath->getCurve(nCurPointIndex))
|
||
{
|
||
dX = pSubpath->getX(nCurPointIndex);
|
||
dY = pSubpath->getY(nCurPointIndex);
|
||
double dX2 = pSubpath->getX(nCurPointIndex + 1);
|
||
double dY2 = pSubpath->getY(nCurPointIndex + 1);
|
||
double dX3 = pSubpath->getX(nCurPointIndex + 2);
|
||
double dY3 = pSubpath->getY(nCurPointIndex + 2);
|
||
m_pRenderer->m_oPath.CurveTo(dX, dY, dX2, dY2, dX3, dY3);
|
||
nCurPointIndex += 3;
|
||
}
|
||
else
|
||
{
|
||
dX = pSubpath->getX(nCurPointIndex);
|
||
dY = pSubpath->getY(nCurPointIndex);
|
||
m_pRenderer->m_oPath.LineTo(dX, dY);
|
||
++nCurPointIndex;
|
||
}
|
||
}
|
||
if (pSubpath->isClosed())
|
||
m_pRenderer->m_oPath.Close();
|
||
}
|
||
}
|
||
void RedactOutputDev::DoTransform(double* pMatrix, double* pdShiftX, double* pdShiftY, bool bActual)
|
||
{
|
||
if (1 == pMatrix[0] && 0 == pMatrix[1] && 0 == pMatrix[2] && 1 == pMatrix[3] && !bActual)
|
||
{
|
||
if (pMatrix[4] || pMatrix[5])
|
||
{
|
||
*pdShiftX = pMatrix[4];
|
||
*pdShiftY = pMatrix[5];
|
||
}
|
||
m_pRenderer->ResetTransform();
|
||
m_arrMatrix[0] = 1; m_arrMatrix[1] = 0;
|
||
m_arrMatrix[2] = 0; m_arrMatrix[3] = 1;
|
||
m_arrMatrix[4] = 0; m_arrMatrix[5] = 0;
|
||
}
|
||
else if (m_arrMatrix[0] == pMatrix[0] && m_arrMatrix[1] == pMatrix[1] && m_arrMatrix[2] == pMatrix[2] && m_arrMatrix[3] == pMatrix[3]
|
||
&& m_arrMatrix[4] == pMatrix[4] && m_arrMatrix[5] == pMatrix[5] && !bActual)
|
||
{
|
||
double dIDet = 1 / (pMatrix[0] * pMatrix[3] - pMatrix[1] * pMatrix[2]);
|
||
*pdShiftX = ((pMatrix[4] - m_arrMatrix[4]) * m_arrMatrix[3] - (pMatrix[5] - m_arrMatrix[5]) * m_arrMatrix[1]) * dIDet;
|
||
*pdShiftY = ((pMatrix[5] - m_arrMatrix[5]) * m_arrMatrix[0] - (pMatrix[4] - m_arrMatrix[4]) * m_arrMatrix[2]) * dIDet;
|
||
}
|
||
else
|
||
{
|
||
m_pRenderer->SetTransform(pMatrix[0], pMatrix[1], pMatrix[2], pMatrix[3], pMatrix[4], pMatrix[5]);
|
||
m_arrMatrix[0] = pMatrix[0]; m_arrMatrix[1] = pMatrix[1];
|
||
m_arrMatrix[2] = pMatrix[2]; m_arrMatrix[3] = pMatrix[3];
|
||
m_arrMatrix[4] = pMatrix[4]; m_arrMatrix[5] = pMatrix[5];
|
||
}
|
||
}
|
||
void RedactOutputDev::DrawPath(const LONG& lType)
|
||
{
|
||
m_pRenderer->m_oCommandManager.Flush();
|
||
DoStateOp();
|
||
|
||
bool bStroke = lType & c_nStroke;
|
||
bool bFill = lType & c_nWindingFillMode;
|
||
bool bEoFill = lType & c_nEvenOddFillMode;
|
||
|
||
m_pPage->GrSave();
|
||
UpdateTransform();
|
||
m_pRenderer->m_oPath.Draw(m_pPage, bStroke, bFill, bEoFill);
|
||
m_pPage->GrRestore();
|
||
}
|
||
void RedactOutputDev::UpdateTransform()
|
||
{
|
||
m_pPage->SetTransform(m_arrMatrix[0], m_arrMatrix[1], m_arrMatrix[2], m_arrMatrix[3], m_arrMatrix[4], m_arrMatrix[5]);
|
||
}
|
||
void RedactOutputDev::AddClip(GfxState* pGState, GfxRedactState* pState, int nIndex)
|
||
{
|
||
m_pRenderer->m_oCommandManager.Flush();
|
||
DoStateOp();
|
||
|
||
GfxClip* pClip = pState->m_pClip;
|
||
GfxPath* pPath = pClip->GetPath(nIndex);
|
||
int nClipFlag = pClip->GetClipFlag(nIndex);;
|
||
|
||
m_pRenderer->m_lClipMode = nClipFlag;
|
||
GfxClipMatrix oMatrix = pClip->m_vMatrix[nIndex];
|
||
double pMatrix[6] = { oMatrix.dA, oMatrix.dB, oMatrix.dC, oMatrix.dD, oMatrix.dE, oMatrix.dF };
|
||
DoPath(pGState, pPath, pMatrix);
|
||
UpdateTransform();
|
||
m_pRenderer->m_oPath.Clip(m_pPage, c_nClipRegionTypeEvenOdd & m_pRenderer->m_lClipMode);
|
||
m_pRenderer->m_oPath.Clear();
|
||
}
|
||
void RedactOutputDev::DoStateOp()
|
||
{
|
||
if (m_sStates.empty() || m_sStates.back().m_arrOp.empty())
|
||
return;
|
||
|
||
CStream* pStream = m_pPage->GetStream();
|
||
for (int i = 0; i < m_sStates.back().m_arrOp.size(); ++i)
|
||
{
|
||
auto arrOp = m_sStates.back().m_arrOp;
|
||
pStream->WriteStr(arrOp[i].first.c_str());
|
||
pStream->WriteChar(' ');
|
||
pStream->WriteStr(arrOp[i].second.c_str());
|
||
pStream->WriteStr("\012");
|
||
}
|
||
m_sStates.back().m_arrOp.clear();
|
||
}
|
||
}
|