1842 lines
53 KiB
C++
1842 lines
53 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 "Objects.h"
|
||
#include "Pages.h"
|
||
#include "Utils.h"
|
||
#include "GState.h"
|
||
#include "Streams.h"
|
||
#include "Annotation.h"
|
||
#include "Font.h"
|
||
#include "Image.h"
|
||
#include "Shading.h"
|
||
#include "Pattern.h"
|
||
#include "Document.h"
|
||
#include "Field.h"
|
||
#include "ResourcesDictionary.h"
|
||
|
||
#ifdef DrawText
|
||
#undef DrawText
|
||
#endif
|
||
|
||
#define MIN_HORIZONTALSCALING 0.01
|
||
#define MAX_HORIZONTALSCALING 1000
|
||
#define MIN_CHARSPACE -30
|
||
#define MAX_CHARSPACE 300
|
||
#define MAX_FONTSIZE 1000
|
||
|
||
#define STR_BUF 200
|
||
|
||
namespace PdfWriter
|
||
{
|
||
static const double c_dKappa = 0.552;
|
||
const static char* c_sRenderingIntent[] =
|
||
{
|
||
"AbsoluteColorimetric",
|
||
"RelativeColorimetric",
|
||
"Saturation",
|
||
"Perceptual"
|
||
};
|
||
static void QuarterEllipseA(CStream* pStream, double dX, double dY, double dXRad, double dYRad)
|
||
{
|
||
pStream->WriteReal(dX - dXRad);
|
||
pStream->WriteChar(' ');
|
||
pStream->WriteReal(dY + dYRad * c_dKappa);
|
||
pStream->WriteChar(' ');
|
||
pStream->WriteReal(dX - dXRad * c_dKappa);
|
||
pStream->WriteChar(' ');
|
||
pStream->WriteReal(dY + dYRad);
|
||
pStream->WriteChar(' ');
|
||
pStream->WriteReal(dX);
|
||
pStream->WriteChar(' ');
|
||
pStream->WriteReal(dY + dYRad);
|
||
pStream->WriteStr(" c\012");
|
||
}
|
||
static void QuarterEllipseB(CStream* pStream, double dX, double dY, double dXRad, double dYRad)
|
||
{
|
||
pStream->WriteReal(dX + dXRad * c_dKappa);
|
||
pStream->WriteChar(' ');
|
||
pStream->WriteReal(dY + dYRad);
|
||
pStream->WriteChar(' ');
|
||
pStream->WriteReal(dX + dXRad);
|
||
pStream->WriteChar(' ');
|
||
pStream->WriteReal(dY + dYRad * c_dKappa);
|
||
pStream->WriteChar(' ');
|
||
pStream->WriteReal(dX + dXRad);
|
||
pStream->WriteChar(' ');
|
||
pStream->WriteReal(dY);
|
||
pStream->WriteStr(" c\012");
|
||
}
|
||
static void QuarterEllipseC(CStream* pStream, double dX, double dY, double dXRad, double dYRad)
|
||
{
|
||
pStream->WriteReal(dX + dXRad);
|
||
pStream->WriteChar(' ');
|
||
pStream->WriteReal(dY - dYRad * c_dKappa);
|
||
pStream->WriteChar(' ');
|
||
pStream->WriteReal(dX + dXRad * c_dKappa);
|
||
pStream->WriteChar(' ');
|
||
pStream->WriteReal(dY - dYRad);
|
||
pStream->WriteChar(' ');
|
||
pStream->WriteReal(dX);
|
||
pStream->WriteChar(' ');
|
||
pStream->WriteReal(dY - dYRad);
|
||
pStream->WriteStr(" c\012");
|
||
}
|
||
static void QuarterEllipseD(CStream* pStream, double dX, double dY, double dXRad, double dYRad)
|
||
{
|
||
pStream->WriteReal(dX - dXRad * c_dKappa);
|
||
pStream->WriteChar(' ');
|
||
pStream->WriteReal(dY - dYRad);
|
||
pStream->WriteChar(' ');
|
||
pStream->WriteReal(dX - dXRad);
|
||
pStream->WriteChar(' ');
|
||
pStream->WriteReal(dY - dYRad * c_dKappa);
|
||
pStream->WriteChar(' ');
|
||
pStream->WriteReal(dX - dXRad);
|
||
pStream->WriteChar(' ');
|
||
pStream->WriteReal(dY);
|
||
pStream->WriteStr(" c\012");
|
||
}
|
||
static double AngToEllPrm(double dAngle, double dXRad, double dYRad)
|
||
{
|
||
// Функция для перевода реального угла в параметрическое задание эллписа
|
||
// т.е. x= a cos(t) y = b sin(t) - параметрическое задание эллписа.
|
||
// x = r cos(p), y = r sin(p) => t = atan2( sin(p) / b, cos(p) / a );
|
||
return atan2(sin(dAngle) / dYRad, cos(dAngle) / dXRad);
|
||
}
|
||
static void WriteEllipseArc(CStream* pStream, double dX, double dY, double dXRad, double dYRad, double dAngle1, double dAngle2, double& dXCur, double& dYCur, bool bClockDirection = false)
|
||
{
|
||
// Рассчитаем начальную, конечную и контрольные точки
|
||
double dX1 = 0.0, dX2 = 0.0, dY1 = 0.0, dY2 = 0.0;
|
||
double dCX1 = 0.0, dCX2 = 0.0, dCY1 = 0.0, dCY2 = 0.0;
|
||
|
||
double dAlpha = sin(dAngle2 - dAngle1) * (sqrt(4.0 + 3.0 * tan((dAngle2 - dAngle1) / 2.0) * tan((dAngle2 - dAngle1) / 2.0)) - 1.0) / 3.0;
|
||
|
||
dX1 = dX + dXRad * cos(dAngle1);
|
||
dY1 = dY + dYRad * sin(dAngle1);
|
||
|
||
dX2 = dX + dXRad * cos(dAngle2);
|
||
dY2 = dY + dYRad * sin(dAngle2);
|
||
|
||
dCX1 = dX1 - dAlpha * dXRad * sin(dAngle1);
|
||
dCY1 = dY1 + dAlpha * dYRad * cos(dAngle1);
|
||
|
||
dCX2 = dX2 + dAlpha * dXRad * sin(dAngle2);
|
||
dCY2 = dY2 - dAlpha * dYRad * cos(dAngle2);
|
||
|
||
if ( !bClockDirection )
|
||
{
|
||
pStream->WriteReal(dCX1);
|
||
pStream->WriteChar(' ');
|
||
pStream->WriteReal(dCY1);
|
||
pStream->WriteChar(' ');
|
||
pStream->WriteReal(dCX2);
|
||
pStream->WriteChar(' ');
|
||
pStream->WriteReal(dCY2);
|
||
pStream->WriteChar(' ');
|
||
pStream->WriteReal(dX2);
|
||
pStream->WriteChar(' ');
|
||
pStream->WriteReal(dY2);
|
||
dXCur = dX2;
|
||
dYCur = dY2;
|
||
}
|
||
else
|
||
{
|
||
pStream->WriteReal(dCX2);
|
||
pStream->WriteChar(' ');
|
||
pStream->WriteReal(dCY2);
|
||
pStream->WriteChar(' ');
|
||
pStream->WriteReal(dCX1);
|
||
pStream->WriteChar(' ');
|
||
pStream->WriteReal(dCY1);
|
||
pStream->WriteChar(' ');
|
||
pStream->WriteReal(dX1);
|
||
pStream->WriteChar(' ');
|
||
pStream->WriteReal(dY1);
|
||
dXCur = dX1;
|
||
dYCur = dY1;
|
||
}
|
||
pStream->WriteStr(" c\012");
|
||
}
|
||
//----------------------------------------------------------------------------------------
|
||
// CPageTree
|
||
//----------------------------------------------------------------------------------------
|
||
CPageTree::CPageTree(CXref* pXref)
|
||
{
|
||
pXref->Add(this);
|
||
|
||
m_pPages = new CArrayObject();
|
||
m_pCount = new CNumberObject(0);
|
||
|
||
Add("Type", "Pages");
|
||
Add("Kids", m_pPages);
|
||
Add("Count", m_pCount);
|
||
}
|
||
CPageTree::CPageTree()
|
||
{
|
||
m_pPages = NULL;
|
||
m_pCount = NULL;
|
||
}
|
||
void CPageTree::Fix()
|
||
{
|
||
// Инициализация текущего m_pPages
|
||
CObjectBase* pPages = Get("Kids");
|
||
if (pPages && pPages->GetType() == object_type_ARRAY)
|
||
m_pPages = (CArrayObject*)pPages;
|
||
else
|
||
{
|
||
m_pPages = new CArrayObject();
|
||
Add("Kids", m_pPages);
|
||
}
|
||
|
||
// Инициализация текущего m_pCount
|
||
CObjectBase* pCount = Get("Count");
|
||
if (pCount && pCount->GetType() == object_type_NUMBER)
|
||
m_pCount = (CNumberObject*)pCount;
|
||
else
|
||
{
|
||
m_pCount = new CNumberObject(0);
|
||
Add("Count", m_pCount);
|
||
}
|
||
|
||
CResourcesDict* pResources = (CResourcesDict*)Get("Resources");
|
||
if (pResources)
|
||
pResources->Fix();
|
||
}
|
||
void CPageTree::AddPage(CObjectBase* pObj)
|
||
{
|
||
m_pPages->Add(pObj);
|
||
(*m_pCount)++;
|
||
}
|
||
CObjectBase* CPageTree::GetObj(int nPageIndex)
|
||
{
|
||
int nI = 0;
|
||
return GetFromPageTree(nPageIndex, nI);
|
||
}
|
||
CPage* CPageTree::GetPage(int nPageIndex)
|
||
{
|
||
int nI = 0;
|
||
CObjectBase* pObj = GetFromPageTree(nPageIndex, nI);
|
||
if (pObj && pObj->GetType() == object_type_DICT && ((CDictObject*)pObj)->GetDictType() == dict_type_PAGE)
|
||
return (CPage*)pObj;
|
||
return NULL;
|
||
}
|
||
CObjectBase* CPageTree::RemovePage(int nPageIndex)
|
||
{
|
||
int nI = 0;
|
||
return GetFromPageTree(nPageIndex, nI, true);
|
||
}
|
||
bool CPageTree::InsertPage(int nPageIndex, CObjectBase* pPage)
|
||
{
|
||
if (nPageIndex >= m_pCount->Get())
|
||
{
|
||
AddPage(pPage);
|
||
if (pPage->GetType() == object_type_DICT && ((CDictObject*)pPage)->GetDictType() == dict_type_PAGE)
|
||
((CPage*)pPage)->Add("Parent", this);
|
||
return true;
|
||
}
|
||
int nI = 0;
|
||
CObjectBase* pObj = GetFromPageTree(nPageIndex, nI, false, true, pPage);
|
||
if (pObj)
|
||
return true;
|
||
return false;
|
||
}
|
||
bool CPageTree::ReplacePage(int nPageIndex, CPage* pPage)
|
||
{
|
||
if (nPageIndex >= m_pCount->Get())
|
||
return false;
|
||
int nI = 0;
|
||
CObjectBase* pObj = GetFromPageTree(nPageIndex, nI, true, true, pPage);
|
||
if (pObj)
|
||
return true;
|
||
return false;
|
||
}
|
||
bool CPageTree::Find(CPage* pPage, int& nI)
|
||
{
|
||
for (int i = 0, count = m_pPages->GetCount(); i < count; ++i)
|
||
{
|
||
CObjectBase* pObj = m_pPages->Get(i);
|
||
if (pObj->GetType() == object_type_DICT && ((CDictObject*)pObj)->GetDictType() == dict_type_PAGES && ((CPageTree*)pObj)->Find(pPage, nI))
|
||
return true;
|
||
else
|
||
{
|
||
if (pPage == pObj)
|
||
return true;
|
||
nI++;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
CObjectBase* CPageTree::GetFromPageTree(int nPageIndex, int& nI, bool bRemove, bool bInsert, CObjectBase* pPage)
|
||
{
|
||
for (int i = 0, count = m_pPages->GetCount(); i < count; ++i)
|
||
{
|
||
CObjectBase* pObj = m_pPages->Get(i);
|
||
CObjectBase* pRes = NULL;
|
||
if (pObj->GetType() == object_type_DICT && ((CDictObject*)pObj)->GetDictType() == dict_type_PAGES)
|
||
pRes = ((CPageTree*)pObj)->GetFromPageTree(nPageIndex, nI, bRemove, bInsert, pPage);
|
||
else
|
||
{
|
||
if (nPageIndex == nI)
|
||
{
|
||
pRes = pObj;
|
||
if (bRemove && bInsert)
|
||
{
|
||
m_pPages->Insert(pObj, pPage, true);
|
||
if (pPage->GetType() == object_type_DICT && ((CDictObject*)pPage)->GetDictType() == dict_type_PAGE)
|
||
((CPage*)pPage)->Add("Parent", this);
|
||
}
|
||
else if (bRemove)
|
||
pRes = m_pPages->Remove(i);
|
||
else if (bInsert)
|
||
{
|
||
m_pPages->Insert(pObj, pPage);
|
||
if (pPage->GetType() == object_type_DICT && ((CDictObject*)pPage)->GetDictType() == dict_type_PAGE)
|
||
((CPage*)pPage)->Add("Parent", this);
|
||
}
|
||
}
|
||
nI++;
|
||
}
|
||
if (pRes)
|
||
{
|
||
if (bRemove)
|
||
(*m_pCount)--;
|
||
if (bInsert)
|
||
(*m_pCount)++;
|
||
return pRes;
|
||
}
|
||
}
|
||
return NULL;
|
||
}
|
||
bool CPageTree::Join(CPageTree* pPageTree)
|
||
{
|
||
unsigned int nObjId = pPageTree->GetObjId();
|
||
unsigned int nGenNo = pPageTree->GetGenNo();
|
||
for (int i = 0, count = m_pPages->GetCount(); i < count; ++i)
|
||
{
|
||
CObjectBase* pObj = m_pPages->Get(i);
|
||
if (pObj->GetObjId() == nObjId && pObj->GetGenNo() == nGenNo)
|
||
{
|
||
m_pPages->Insert(pObj, pPageTree, true);
|
||
return true;
|
||
}
|
||
if (pObj->GetType() == object_type_DICT && ((CDictObject*)pObj)->GetDictType() == dict_type_PAGES && ((CPageTree*)pObj)->Join(pPageTree))
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
void CPageTree::CreateFakePages(int nPages, int nPageIndex)
|
||
{
|
||
for (int i = 0; i < nPages; ++i)
|
||
{
|
||
if (nPageIndex < 0)
|
||
m_pPages->Add(new CFakePage(i));
|
||
else
|
||
{
|
||
CObjectBase* pTarget = GetObj(nPageIndex);
|
||
if (pTarget)
|
||
m_pPages->Insert(pTarget, new CFakePage(nPageIndex));
|
||
else
|
||
m_pPages->Add(new CFakePage(m_pPages->GetCount()));
|
||
}
|
||
(*m_pCount)++;
|
||
}
|
||
}
|
||
void CPageTree::ClearFakePages()
|
||
{
|
||
for (int i = 0; i < GetCount(); ++i)
|
||
{
|
||
CObjectBase* pObj = GetObj(i);
|
||
if (pObj->GetType() == object_type_DICT && ((CDictObject*)pObj)->GetDictType() == dict_type_PAGE)
|
||
continue;
|
||
pObj = m_pPages->Remove(i);
|
||
delete pObj;
|
||
(*m_pCount)--;
|
||
--i;
|
||
}
|
||
}
|
||
//----------------------------------------------------------------------------------------
|
||
// CPage
|
||
//----------------------------------------------------------------------------------------
|
||
CPage::CPage(CDocument* pDocument)
|
||
{
|
||
Init(pDocument);
|
||
}
|
||
void CPage::Fix()
|
||
{
|
||
// Инициализация текущего contents
|
||
CObjectBase* pContents = Get("Contents");
|
||
if (pContents)
|
||
{
|
||
if (pContents->GetType() == object_type_ARRAY)
|
||
m_pContents = (CArrayObject*)pContents;
|
||
else if (pContents->GetType() == object_type_UNKNOWN)
|
||
{
|
||
CProxyObject* pNewContents = new CProxyObject(pContents->Copy(), true);
|
||
pNewContents->Get()->SetRef(pContents->GetObjId(), pContents->GetGenNo());
|
||
m_pContents = new CArrayObject();
|
||
m_pContents->Add(pNewContents);
|
||
Add("Contents", m_pContents);
|
||
}
|
||
else if (pContents->GetType() == object_type_DICT)
|
||
{
|
||
m_pContents = new CArrayObject();
|
||
m_pContents->Add(pContents);
|
||
Add("Contents", m_pContents);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
m_pContents = new CArrayObject();
|
||
Add("Contents", m_pContents);
|
||
}
|
||
|
||
// Инициализация текущего MediaBox
|
||
CObjectBase* pMediaBox = Get("MediaBox");
|
||
if (pMediaBox && pMediaBox->GetType() == object_type_ARRAY)
|
||
{
|
||
double dL = 0.0, dB = 0.0, dR = DEF_PAGE_WIDTH, dT = DEF_PAGE_HEIGHT;
|
||
|
||
CObjectBase* val = ((CArrayObject*)pMediaBox)->Get(0);
|
||
if (val && val->GetType() == object_type_NUMBER)
|
||
dL = ((CNumberObject*)val)->Get();
|
||
else if (val && val->GetType() == object_type_REAL)
|
||
dL = ((CRealObject*)val)->Get();
|
||
|
||
val = ((CArrayObject*)pMediaBox)->Get(1);
|
||
if (val && val->GetType() == object_type_NUMBER)
|
||
dB = ((CNumberObject*)val)->Get();
|
||
else if (val && val->GetType() == object_type_REAL)
|
||
dB = ((CRealObject*)val)->Get();
|
||
|
||
val = ((CArrayObject*)pMediaBox)->Get(2);
|
||
if (val && val->GetType() == object_type_NUMBER)
|
||
dR = ((CNumberObject*)val)->Get();
|
||
else if (val && val->GetType() == object_type_REAL)
|
||
dR = ((CRealObject*)val)->Get();
|
||
|
||
val = ((CArrayObject*)pMediaBox)->Get(3);
|
||
if (val && val->GetType() == object_type_NUMBER)
|
||
dT = ((CNumberObject*)val)->Get();
|
||
else if (val && val->GetType() == object_type_REAL)
|
||
dT = ((CRealObject*)val)->Get();
|
||
|
||
Add("MediaBox", CArrayObject::CreateBox(dL, dB, dR, dT));
|
||
}
|
||
else
|
||
Add("MediaBox", CArrayObject::CreateBox(0, 0, DEF_PAGE_WIDTH, DEF_PAGE_HEIGHT));
|
||
|
||
// Инициализация текущего Rotate
|
||
CObjectBase* pRotate = GetRotateItem();
|
||
if (pRotate && pRotate->GetType() == object_type_NUMBER)
|
||
Add("Rotate", ((CNumberObject*)pRotate)->Get() % 360);
|
||
|
||
CResourcesDict* pResources = GetResourcesItem();
|
||
if (pResources)
|
||
{
|
||
pResources->Fix();
|
||
|
||
// Инициализация текущего Shading
|
||
CObjectBase* pShading = pResources->Get("Shading");
|
||
if (pShading && pShading->GetType() == object_type_DICT)
|
||
{
|
||
m_pShadings = (CDictObject*)pShading;
|
||
m_unShadingsCount = m_pShadings->GetSize();
|
||
}
|
||
|
||
// Инициализация текущего Pattern
|
||
CObjectBase* pPattern = pResources->Get("Pattern");
|
||
if (pPattern && pPattern->GetType() == object_type_DICT)
|
||
{
|
||
m_pPatterns = (CDictObject*)pPattern;
|
||
m_unPatternsCount = m_pPatterns->GetSize();
|
||
}
|
||
}
|
||
|
||
m_pStream = NULL;
|
||
}
|
||
CPage::CPage(CXref* pXref, CPageTree* pParent, CDocument* pDocument)
|
||
{
|
||
pXref->Add(this);
|
||
Init(pDocument);
|
||
|
||
m_pContents = new CArrayObject();
|
||
CDictObject* pContent = new CDictObject(pXref);
|
||
m_pContents->Add(pContent);
|
||
m_pStream = pContent->GetStream();
|
||
|
||
Add("Parent", pParent);
|
||
Add("MediaBox", CArrayObject::CreateBox(0, 0, DEF_PAGE_WIDTH, DEF_PAGE_HEIGHT));
|
||
Add("Type", "Page");
|
||
Add("Contents", m_pContents);
|
||
AddResource();
|
||
}
|
||
CPage::~CPage()
|
||
{
|
||
CGrState* pGrState = m_pGrState, *pPrev = NULL;
|
||
while (pGrState)
|
||
{
|
||
pPrev = m_pGrState->GetPrev();
|
||
delete pGrState;
|
||
pGrState = pPrev;
|
||
}
|
||
}
|
||
void CPage::Init(CDocument* pDocument)
|
||
{
|
||
m_pDocument = pDocument;
|
||
m_eGrMode = grmode_PAGE;
|
||
m_pGrState = new CGrState(NULL);
|
||
|
||
m_pFont = NULL;
|
||
m_pShadings = NULL;
|
||
m_unShadingsCount = 0;
|
||
m_pPatterns = NULL;
|
||
m_unPatternsCount = 0;
|
||
m_eType = fontUnknownType;
|
||
}
|
||
void CPage::SetWidth(double dValue)
|
||
{
|
||
dValue = std::min(std::max(dValue, 1.0), 14400.0);
|
||
SetMediaBoxValue(2, dValue);
|
||
}
|
||
double CPage::GetWidth()
|
||
{
|
||
TBox oBox = GetMediaBox();
|
||
return oBox.fRight - oBox.fLeft;
|
||
}
|
||
void CPage::SetHeight(double dValue)
|
||
{
|
||
dValue = std::min(std::max(dValue, 1.0), 14400.0);
|
||
SetMediaBoxValue(3, dValue);
|
||
}
|
||
double CPage::GetHeight()
|
||
{
|
||
TBox oBox = GetMediaBox();
|
||
return oBox.fTop - oBox.fBottom;
|
||
}
|
||
TBox CPage::GetMediaBox()
|
||
{
|
||
TBox oMediaBox = TRect( 0, 0, 0, 0 );
|
||
|
||
CArrayObject* pArray = GetMediaBoxItem();
|
||
|
||
if (pArray)
|
||
{
|
||
CRealObject* pReal;
|
||
|
||
pReal = (CRealObject*)pArray->Get(0);
|
||
if (pReal)
|
||
oMediaBox.fLeft = pReal->Get();
|
||
|
||
pReal = (CRealObject*)pArray->Get(1);
|
||
if (pReal)
|
||
oMediaBox.fBottom = pReal->Get();
|
||
|
||
pReal = (CRealObject*)pArray->Get(2);
|
||
if (pReal)
|
||
oMediaBox.fRight = pReal->Get();
|
||
|
||
pReal = (CRealObject*)pArray->Get(3);
|
||
if (pReal)
|
||
oMediaBox.fTop = pReal->Get();
|
||
}
|
||
|
||
return oMediaBox;
|
||
}
|
||
void CPage::SetMediaBoxValue(unsigned int unIndex, double dValue)
|
||
{
|
||
CArrayObject* pArray = GetMediaBoxItem();
|
||
if (!pArray)
|
||
return;
|
||
|
||
CRealObject* pReal = (CRealObject*)pArray->Get(unIndex);
|
||
if (!pReal)
|
||
return;
|
||
|
||
pReal->Set(dValue);
|
||
}
|
||
CArrayObject* CPage::GetMediaBoxItem()
|
||
{
|
||
return (CArrayObject*)Get("MediaBox");
|
||
}
|
||
CResourcesDict* CPage::GetResourcesItem()
|
||
{
|
||
CObjectBase* pObject = Get("Resources");
|
||
|
||
// Если объект Resources нулевой, тогда ищем Resources у родительского объекта рекурсивно
|
||
if (!pObject)
|
||
{
|
||
CPageTree* pPageTree = NULL;
|
||
CObjectBase* pObj = Get("Parent");
|
||
if (pObj->GetType() == object_type_DICT)
|
||
pPageTree = (CPageTree*)pObj;
|
||
while (pPageTree)
|
||
{
|
||
pObject = pPageTree->Get("Resources");
|
||
|
||
if (pObject)
|
||
break;
|
||
|
||
pPageTree = (CPageTree*)pPageTree->Get("Parent");
|
||
}
|
||
}
|
||
|
||
return (CResourcesDict*)pObject;
|
||
}
|
||
CObjectBase* CPage::GetCropBoxItem()
|
||
{
|
||
return Get("CropBox");
|
||
}
|
||
CObjectBase* CPage::GetRotateItem()
|
||
{
|
||
return Get("Rotate");
|
||
}
|
||
void CPage::AddResource(CXref* pXref)
|
||
{
|
||
CResourcesDict* pResource = new CResourcesDict(pXref, !pXref, true);
|
||
if (!pResource)
|
||
return;
|
||
|
||
Add("Resources", pResource);
|
||
}
|
||
void CPage::BeforeWrite()
|
||
{
|
||
if (grmode_PATH == m_eGrMode)
|
||
EndPath();
|
||
|
||
if (grmode_TEXT == m_eGrMode)
|
||
EndText();
|
||
|
||
while (m_pGrState->GetPrev())
|
||
{
|
||
GrRestore();
|
||
}
|
||
}
|
||
void CPage::SetGrMode(EGrMode eMode)
|
||
{
|
||
m_eGrMode = eMode;
|
||
// TODO: Сделать проверку плохих ситуаций
|
||
}
|
||
void CPage::CheckGrMode(EGrMode eMode)
|
||
{
|
||
// TODO: Сделать проверку плохих ситуаций
|
||
}
|
||
void CPage::MoveTo (double dX, double dY)
|
||
{
|
||
// Operator : m
|
||
// Description: Начинаем новый subpath, передвигая текущий указатель в точку (x, y)(она же стартовая).
|
||
|
||
SetGrMode(grmode_PATH);
|
||
m_pStream->WriteReal(dX);
|
||
m_pStream->WriteChar(' ');
|
||
m_pStream->WriteReal(dY);
|
||
m_pStream->WriteStr(" m\012");
|
||
|
||
m_oCurPos.Set(dX, dY);
|
||
m_oStartPos = m_oCurPos;
|
||
}
|
||
void CPage::LineTo (double dX, double dY)
|
||
{
|
||
// Operator : l
|
||
// Description: Добавляем линию от текущей точки до точки (x, y). Текущую точку выставляем (х, у).
|
||
CheckGrMode(grmode_PATH);
|
||
|
||
m_pStream->WriteReal(dX);
|
||
m_pStream->WriteChar(' ');
|
||
m_pStream->WriteReal(dY);
|
||
m_pStream->WriteStr(" l\012");
|
||
|
||
m_oCurPos.Set(dX, dY);
|
||
}
|
||
void CPage::CurveTo(double dX1, double dY1, double dX2, double dY2, double dX3, double dY3)
|
||
{
|
||
// Operator : c
|
||
// Description: Добавляем кривую Безье(кубическую). Начинается кривая в текущей позиции, заканчивается
|
||
// в точке (x3, y3). (x1, y1) и (x2, y2) - контрольные точки. Текущую точку устанавливаем
|
||
// в (х3, у3).
|
||
CheckGrMode(grmode_PATH);
|
||
|
||
m_pStream->WriteReal(dX1);
|
||
m_pStream->WriteChar(' ');
|
||
m_pStream->WriteReal(dY1);
|
||
m_pStream->WriteChar(' ');
|
||
m_pStream->WriteReal(dX2);
|
||
m_pStream->WriteChar(' ');
|
||
m_pStream->WriteReal(dY2);
|
||
m_pStream->WriteChar(' ');
|
||
m_pStream->WriteReal(dX3);
|
||
m_pStream->WriteChar(' ');
|
||
m_pStream->WriteReal(dY3);
|
||
m_pStream->WriteStr(" c\012");
|
||
|
||
m_oCurPos.Set(dX3, dY3);
|
||
}
|
||
void CPage::Ellipse(double dX, double dY, double dXRay, double dYRay)
|
||
{
|
||
SetGrMode(grmode_PATH);
|
||
|
||
m_pStream->WriteReal(dX - dXRay);
|
||
m_pStream->WriteChar(' ');
|
||
m_pStream->WriteReal(dY);
|
||
m_pStream->WriteStr(" m\012");
|
||
|
||
QuarterEllipseA(m_pStream, dX, dY, dXRay, dYRay);
|
||
QuarterEllipseB(m_pStream, dX, dY, dXRay, dYRay);
|
||
QuarterEllipseC(m_pStream, dX, dY, dXRay, dYRay);
|
||
QuarterEllipseD(m_pStream, dX, dY, dXRay, dYRay);
|
||
|
||
m_oCurPos.Set(dX - dXRay, dY);
|
||
m_oStartPos = m_oCurPos;
|
||
}
|
||
void CPage::EllipseArc(double dX, double dY, double dXRad, double dYRad, double _dAngle1, double _dAngle2, bool bClockDirection)
|
||
{
|
||
CheckGrMode(grmode_PATH);
|
||
|
||
// переведем углы в радианы
|
||
double dAngle1 = _dAngle1 * 3.141592f / 180;
|
||
double dAngle2 = _dAngle2 * 3.141592f / 180;
|
||
|
||
// Выясним в каких четвертях находятся начальная и конечная точки
|
||
int nFirstPointQuard = int(_dAngle1) / 90 + 1;
|
||
int nSecondPointQuard = int(_dAngle2) / 90 + 1;
|
||
|
||
nSecondPointQuard = std::min(4, std::max(1, nSecondPointQuard));
|
||
nFirstPointQuard = std::min(4, std::max(1, nFirstPointQuard));
|
||
|
||
// Проведем линию в начальную точку дуги
|
||
double dStartX = 0.0, dStartY = 0.0, dEndX = 0.0, dEndY = 0.0;
|
||
|
||
dStartX = dX + dXRad * cos(AngToEllPrm(dAngle1, dXRad, dYRad));
|
||
dStartY = dY + dYRad * sin(AngToEllPrm(dAngle1, dXRad, dYRad));
|
||
|
||
//m_pStream->WriteReal(dStartX);
|
||
//m_pStream->WriteChar(' ');
|
||
//m_pStream->WriteReal(dStartY);
|
||
//m_pStream->WriteStr(" m\012");
|
||
|
||
// Дальше рисуем по четверям
|
||
double dCurX = dStartX, dCurY = dStartY;
|
||
double dStartAngle = dAngle1;
|
||
double dEndAngle = 0;
|
||
|
||
if ( !bClockDirection )
|
||
{
|
||
for (unsigned int nIndex = nFirstPointQuard; nIndex <= nSecondPointQuard; nIndex++)
|
||
{
|
||
if (nIndex == nSecondPointQuard)
|
||
dEndAngle = dAngle2;
|
||
else
|
||
dEndAngle = (90 * (nIndex)) * 3.141592f / 180;
|
||
if (!(nIndex == nFirstPointQuard))
|
||
dStartAngle = (90 * (nIndex - 1)) * 3.141592f / 180;
|
||
|
||
WriteEllipseArc(m_pStream, dX, dY, dXRad, dYRad, AngToEllPrm(dStartAngle, dXRad, dYRad), AngToEllPrm(dEndAngle, dXRad, dYRad), dEndX, dEndY, false);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
for( unsigned int nIndex = nFirstPointQuard; nIndex >= nSecondPointQuard; nIndex-- )
|
||
{
|
||
if ( nIndex == nFirstPointQuard )
|
||
dStartAngle = dAngle1;
|
||
else
|
||
dStartAngle = (90 * (nIndex ) ) * 3.141592f / 180;
|
||
if ( !( nIndex == nSecondPointQuard ) )
|
||
dEndAngle = (90 * (nIndex - 1 ) ) * 3.141592f / 180;
|
||
else
|
||
dEndAngle = dAngle2;
|
||
|
||
WriteEllipseArc(m_pStream, dX, dY, dXRad, dYRad, AngToEllPrm(dStartAngle, dXRad, dYRad), AngToEllPrm(dEndAngle, dXRad, dYRad), dEndX, dEndY, false);
|
||
}
|
||
}
|
||
|
||
m_oCurPos.Set(dEndX, dEndY);
|
||
m_oStartPos = m_oCurPos;
|
||
}
|
||
void CPage::EllipseArcTo(double dX, double dY, double dXRad, double dYRad, double _dAngle1, double _dAngle2, bool bClockDirection)
|
||
{
|
||
// Проверяем эллипс на невырожденность
|
||
if (dXRad < 0.001 || dYRad < 0.001)
|
||
{
|
||
double dAngle1 = _dAngle1 * 3.141592f / 180;
|
||
double dAngle2 = _dAngle2 * 3.141592f / 180;
|
||
|
||
if (dXRad < 0.001 && dYRad < 0.001)
|
||
LineTo(dX, dY);
|
||
else if (dXRad < 0.001)
|
||
{
|
||
LineTo(dX, dY + sin(dAngle1) * dYRad);
|
||
LineTo(dX, dY + sin(dAngle2) * dYRad);
|
||
}
|
||
else // if (dYRad < 0.001)
|
||
{
|
||
LineTo(dX + cos(dAngle1) * dXRad, dY);
|
||
LineTo(dX + cos(dAngle2) * dXRad, dY);
|
||
}
|
||
return;
|
||
}
|
||
|
||
|
||
while (_dAngle1 < 0)
|
||
_dAngle1 += 360;
|
||
|
||
while (_dAngle1 > 360)
|
||
_dAngle1 -= 360;
|
||
|
||
while (_dAngle2 < 0)
|
||
_dAngle2 += 360;
|
||
|
||
while (_dAngle2 > 360)
|
||
_dAngle2 -= 360;
|
||
|
||
if (!bClockDirection)
|
||
{
|
||
if (_dAngle1 <= _dAngle2)
|
||
EllipseArc(dX, dY, dXRad, dYRad, _dAngle1, _dAngle2, false);
|
||
else
|
||
{
|
||
EllipseArc(dX, dY, dXRad, dYRad, _dAngle1, 360, false);
|
||
EllipseArc(dX, dY, dXRad, dYRad, 0, _dAngle2, false);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (_dAngle1 >= _dAngle2)
|
||
EllipseArc(dX, dY, dXRad, dYRad, _dAngle1, _dAngle2, true);
|
||
else
|
||
{
|
||
EllipseArc(dX, dY, dXRad, dYRad, _dAngle1, 0, true);
|
||
EllipseArc(dX, dY, dXRad, dYRad, 360, _dAngle2, true);
|
||
}
|
||
}
|
||
}
|
||
void CPage::ClosePath()
|
||
{
|
||
// Operator : h
|
||
// Description: Закрываем subpath, соединяя текущую точку с начальной прямой линией. Если subpath
|
||
// уже закрыт, тогда ничего не делаем
|
||
CheckGrMode(grmode_PATH);
|
||
m_pStream->WriteStr("h\012");
|
||
m_oCurPos = m_oStartPos;
|
||
}
|
||
void CPage::Stroke()
|
||
{
|
||
// Operator : S
|
||
// Description: Обводим path.
|
||
|
||
SetGrMode(grmode_PAGE);
|
||
m_pStream->WriteStr("S\012");
|
||
m_oCurPos.Reset();
|
||
}
|
||
void CPage::Fill()
|
||
{
|
||
// Operator : f
|
||
// Description: Заливка path по правилу Nonzero Winding Number Rule(см. спецификацию PDF Part1: PDF 1.7
|
||
// стр. 136, закладка 8.5.3.3.2).
|
||
SetGrMode(grmode_PAGE);
|
||
m_pStream->WriteStr("f\012");
|
||
m_oCurPos.Reset();
|
||
}
|
||
void CPage::EoFill()
|
||
{
|
||
// Operator : f*
|
||
// Description: Заливка path по правилу Even-Odd Rule(см. спецификацию PDF Part1: PDF 1.7 стр. 137,
|
||
// закладка 8.5.3.3.3).
|
||
SetGrMode(grmode_PAGE);
|
||
m_pStream->WriteStr("f*\012");
|
||
m_oCurPos.Reset();
|
||
}
|
||
void CPage::FillStroke()
|
||
{
|
||
// Operator : B
|
||
// Description: Заливка и обоводка path, используя правило для заливки Nonzero Winding Number Rule(см.
|
||
// спецификацию PDF Part1: PDF 1.7 стр. 136, закладка 8.5.3.3.2). Этот оператор должен
|
||
// привести к тому же самому результату как строительство двух идентичных объектов path,
|
||
// применяя к первому оператор f и ко второму - S.
|
||
SetGrMode(grmode_PAGE);
|
||
m_pStream->WriteStr("B\012");
|
||
m_oCurPos.Reset();
|
||
}
|
||
void CPage::EoFillStroke()
|
||
{
|
||
// Operator : B*
|
||
// Description: Заливка и обоводка path, используя правило для заливки Even-Odd Rule(см.
|
||
// спецификацию PDF Part1: PDF 1.7 стр. 137, закладка 8.5.3.3.3). Этот оператор должен
|
||
// привести к тому же самому результату как строительство двух идентичных объектов path,
|
||
// применяя к первому оператор f* и ко второму - S.
|
||
SetGrMode(grmode_PAGE);
|
||
m_pStream->WriteStr("B*\012");
|
||
m_oCurPos.Reset();
|
||
}
|
||
void CPage::EndPath()
|
||
{
|
||
// Operator : n
|
||
// Description: Закрываем path, не заливая и не обводя его. Этот оператор используется прежде всего для
|
||
// изменения текущего path.
|
||
SetGrMode(grmode_PAGE);
|
||
m_pStream->WriteStr("n\012");
|
||
m_oCurPos.Reset();
|
||
}
|
||
void CPage::SetLineWidth(double dLineWidth)
|
||
{
|
||
// Operator : w
|
||
// Descriprion: устанавливаем толщину линии
|
||
|
||
dLineWidth = std::max(dLineWidth, 0.0);
|
||
m_pStream->WriteReal(dLineWidth);
|
||
m_pStream->WriteStr(" w\012");
|
||
m_pGrState->m_dLineWidth = dLineWidth;
|
||
}
|
||
void CPage::SetLineCap(ELineCapStyle eLineCap)
|
||
{
|
||
// Operator : J
|
||
// Descriprion: устанавливаем вид окончания линии (LineCapStyle)
|
||
|
||
eLineCap = std::max(linecap_Min, std::min(linecap_Max, eLineCap));
|
||
m_pStream->WriteInt((unsigned int)eLineCap);
|
||
m_pStream->WriteStr(" J\012");
|
||
m_pGrState->m_eLineCap = eLineCap;
|
||
}
|
||
void CPage::SetLineJoin(ELineJoinStyle eLineJoin)
|
||
{
|
||
// Operator : j
|
||
// Descriprion: устанавливаем вид соединения линий (LineJoinStyle)
|
||
eLineJoin = std::max(linejoin_Min, std::min(linejoin_Max, eLineJoin));
|
||
m_pStream->WriteInt((unsigned int)eLineJoin);
|
||
m_pStream->WriteStr(" j\012");
|
||
m_pGrState->m_eLineJoin = eLineJoin;
|
||
}
|
||
void CPage::SetMiterLimit(double dMiterLimit)
|
||
{
|
||
// Operator : M
|
||
// Descriprion: устанавливаем MiterLimit - константа, относящаяся к виду соединения линий
|
||
dMiterLimit = std::max(1.0, dMiterLimit);
|
||
m_pStream->WriteReal(dMiterLimit);
|
||
m_pStream->WriteStr(" M\012");
|
||
m_pGrState->m_dMiterLimit = dMiterLimit;
|
||
}
|
||
void CPage::SetDash(const double* pPattern, unsigned int unCount, double dPhase)
|
||
{
|
||
// Operator : d
|
||
// Descriprion: устанавливаем вид линий (DashMode)
|
||
|
||
if (0 == unCount || !pPattern)
|
||
return;
|
||
|
||
bool bFalseDash = true;
|
||
for (unsigned int unIndex = 0; unIndex < unCount; unIndex++)
|
||
{
|
||
if (0 != pPattern[unIndex])
|
||
{
|
||
bFalseDash = false;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (bFalseDash)
|
||
return;
|
||
|
||
m_pStream->WriteChar('[');
|
||
for (unsigned int unIndex = 0; unIndex < unCount; unIndex++)
|
||
{
|
||
m_pStream->WriteReal(pPattern[unIndex]);
|
||
m_pStream->WriteChar(' ');
|
||
}
|
||
m_pStream->WriteStr("] ");
|
||
m_pStream->WriteReal(dPhase);
|
||
m_pStream->WriteStr(" d\012");
|
||
|
||
m_pGrState->m_oDashMode.Set(pPattern, unCount, dPhase);
|
||
}
|
||
void CPage::SetFlat(double dFlatness)
|
||
{
|
||
// Operator : i
|
||
// Descriprion: устанавливаем порог ошибки линии (Flatness tolerance)
|
||
dFlatness = std::min(100.0, std::max(0.0, dFlatness));
|
||
m_pStream->WriteReal(dFlatness);
|
||
m_pStream->WriteStr(" i\012");
|
||
m_pGrState->m_dFlatness = dFlatness;
|
||
}
|
||
void CPage::GrSave()
|
||
{
|
||
// Operator : q
|
||
// Description: сохраняем текущий GState в графическом стеке
|
||
CheckGrMode(grmode_PAGE);
|
||
CGrState* pState = new CGrState(m_pGrState);
|
||
if (!pState)
|
||
return;
|
||
|
||
m_pStream->WriteStr("q\012");
|
||
m_pGrState = pState;
|
||
}
|
||
void CPage::GrRestore()
|
||
{
|
||
// Operator : Q
|
||
// Description: Восстанавливаем GState, удаляя самый последний GState, и делаем данный GState текущим
|
||
CheckGrMode(grmode_PAGE);
|
||
|
||
if (!m_pGrState->m_pPrev)
|
||
return;
|
||
|
||
CGrState* pPrev = m_pGrState->m_pPrev;
|
||
delete m_pGrState;
|
||
m_pGrState = pPrev;
|
||
|
||
m_pStream->WriteStr("Q\012");
|
||
}
|
||
void CPage::SetStrokeColor(unsigned char unR, unsigned char unG, unsigned char unB)
|
||
{
|
||
// Operator : RG
|
||
// Description: Устанавливаем цветовое пространтсво для обводки в DeviceRGB и устанавливаем цвет для
|
||
// операций связанных с обведением фигур.
|
||
|
||
double dR = unR / 255.0;
|
||
double dG = unG / 255.0;
|
||
double dB = unB / 255.0;
|
||
|
||
SetStrokeRGB(dR, dG, dB);
|
||
|
||
m_pGrState->m_oStrokeColor.r = dR;
|
||
m_pGrState->m_oStrokeColor.g = dG;
|
||
m_pGrState->m_oStrokeColor.b = dB;
|
||
}
|
||
void CPage::SetFillColor(unsigned char unR, unsigned char unG, unsigned char unB)
|
||
{
|
||
// Operator : rg
|
||
// Description: Устанавливаем цветовое пространтсво для заливки в DeviceRGB и устанавливаем цвет для
|
||
// операций связанных с заливкой фигур.
|
||
|
||
double dR = unR / 255.0;
|
||
double dG = unG / 255.0;
|
||
double dB = unB / 255.0;
|
||
|
||
SetFillRGB(dR, dG, dB);
|
||
|
||
m_pGrState->m_oFillColor.r = dR;
|
||
m_pGrState->m_oFillColor.g = dG;
|
||
m_pGrState->m_oFillColor.b = dB;
|
||
}
|
||
void CPage::SetStrokeG(double dG)
|
||
{
|
||
// Operator : G
|
||
// Description: Заливка в DeviceG
|
||
|
||
m_pStream->WriteReal(dG);
|
||
m_pStream->WriteStr(" G\012");
|
||
}
|
||
void CPage::SetStrokeRGB(double dR, double dG, double dB)
|
||
{
|
||
// Operator : RG
|
||
// Description: Обводка в DeviceRGB
|
||
|
||
m_pStream->WriteReal(dR);
|
||
m_pStream->WriteChar(' ');
|
||
m_pStream->WriteReal(dG);
|
||
m_pStream->WriteChar(' ');
|
||
m_pStream->WriteReal(dB);
|
||
m_pStream->WriteStr(" RG\012");
|
||
}
|
||
void CPage::SetStrokeCMYK(double dC, double dM, double dY, double dK)
|
||
{
|
||
// Operator : K
|
||
// Description: Обводка в DeviceCMYK
|
||
|
||
m_pStream->WriteReal(dC);
|
||
m_pStream->WriteChar(' ');
|
||
m_pStream->WriteReal(dM);
|
||
m_pStream->WriteChar(' ');
|
||
m_pStream->WriteReal(dY);
|
||
m_pStream->WriteChar(' ');
|
||
m_pStream->WriteReal(dK);
|
||
m_pStream->WriteStr(" K\012");
|
||
}
|
||
void CPage::SetFillG(double dG)
|
||
{
|
||
// Operator : g
|
||
// Description: Заливка в DeviceG
|
||
|
||
m_pStream->WriteReal(dG);
|
||
m_pStream->WriteStr(" g\012");
|
||
}
|
||
void CPage::SetFillRGB(double dR, double dG, double dB)
|
||
{
|
||
// Operator : rg
|
||
// Description: Заливка в DeviceRGB
|
||
|
||
m_pStream->WriteReal(dR);
|
||
m_pStream->WriteChar(' ');
|
||
m_pStream->WriteReal(dG);
|
||
m_pStream->WriteChar(' ');
|
||
m_pStream->WriteReal(dB);
|
||
m_pStream->WriteStr(" rg\012");
|
||
}
|
||
void CPage::SetFillCMYK(double dC, double dM, double dY, double dK)
|
||
{
|
||
// Operator : k
|
||
// Description: Заливка в DeviceCMYK
|
||
|
||
m_pStream->WriteReal(dC);
|
||
m_pStream->WriteChar(' ');
|
||
m_pStream->WriteReal(dM);
|
||
m_pStream->WriteChar(' ');
|
||
m_pStream->WriteReal(dY);
|
||
m_pStream->WriteChar(' ');
|
||
m_pStream->WriteReal(dK);
|
||
m_pStream->WriteStr(" k\012");
|
||
}
|
||
void CPage::Concat(double dM11, double dM12, double dM21, double dM22, double dX, double dY)
|
||
{
|
||
// Operator : cm
|
||
// Description: меняем матрицу преобразований (CTM - Current Transformation Matrix)
|
||
|
||
m_pStream->WriteReal(dM11);
|
||
m_pStream->WriteChar(' ');
|
||
m_pStream->WriteReal(dM12);
|
||
m_pStream->WriteChar(' ');
|
||
m_pStream->WriteReal(dM21);
|
||
m_pStream->WriteChar(' ');
|
||
m_pStream->WriteReal(dM22);
|
||
m_pStream->WriteChar(' ');
|
||
m_pStream->WriteReal(dX);
|
||
m_pStream->WriteChar(' ');
|
||
m_pStream->WriteReal(dY);
|
||
m_pStream->WriteStr(" cm\012");
|
||
|
||
CMatrix oCTM = m_pGrState->m_oMatrix;
|
||
|
||
// перемножаем матрицы oCTM(новая)= oCTM(преобразования(которая параметрами задана)) x oCTM(старая)
|
||
m_pGrState->m_oMatrix.m11 = dM11 * oCTM.m11 + dM12 * oCTM.m21;
|
||
m_pGrState->m_oMatrix.m12 = dM11 * oCTM.m12 + dM12 * oCTM.m22;
|
||
m_pGrState->m_oMatrix.m21 = dM21 * oCTM.m11 + dM22 * oCTM.m21;
|
||
m_pGrState->m_oMatrix.m22 = dM21 * oCTM.m12 + dM22 * oCTM.m22;
|
||
m_pGrState->m_oMatrix.x = dX * oCTM.m11 + dY * oCTM.m21 + oCTM.x;
|
||
m_pGrState->m_oMatrix.y = dX * oCTM.m12 + dY * oCTM.m22 + oCTM.y;
|
||
}
|
||
void CPage::StartTransform(double dM11, double dM12, double dM21, double dM22, double dX, double dY)
|
||
{
|
||
m_pGrState->m_oMatrix.m11 = dM11;
|
||
m_pGrState->m_oMatrix.m12 = dM12;
|
||
m_pGrState->m_oMatrix.m21 = dM21;
|
||
m_pGrState->m_oMatrix.m22 = dM22;
|
||
m_pGrState->m_oMatrix.x = dX;
|
||
m_pGrState->m_oMatrix.y = dY;
|
||
}
|
||
void CPage::SetTransform(double dM11, double dM12, double dM21, double dM22, double dX, double dY)
|
||
{
|
||
CMatrix oInverse = m_pGrState->m_oMatrix.Inverse();
|
||
|
||
CMatrix oResult;
|
||
oResult.m11 = dM11 * oInverse.m11 + dM12 * oInverse.m21;
|
||
oResult.m12 = dM11 * oInverse.m12 + dM12 * oInverse.m22;
|
||
oResult.m21 = dM21 * oInverse.m11 + dM22 * oInverse.m21;
|
||
oResult.m22 = dM21 * oInverse.m12 + dM22 * oInverse.m22;
|
||
oResult.x = dX * oInverse.m11 + dY * oInverse.m21 + oInverse.x;
|
||
oResult.y = dX * oInverse.m12 + dY * oInverse.m22 + oInverse.y;
|
||
|
||
if (!oResult.IsIdentity())
|
||
Concat(oResult.m11, oResult.m12, oResult.m21, oResult.m22, oResult.x, oResult.y);
|
||
}
|
||
void CPage::Clip()
|
||
{
|
||
// Operator : W
|
||
// Description: Изменяем текущий clipping path, пересакая его с текущим path, ипользуя правило Nonzero
|
||
// Winding Number Rule, для определения какие регионы лежат внутри clipping path.
|
||
SetGrMode(grmode_CLIP);
|
||
m_pStream->WriteStr("W\012");
|
||
}
|
||
void CPage::Eoclip()
|
||
{
|
||
// Operator : W*
|
||
// Description: Изменяем текущий clipping path, пересакая его с текущим path, ипользуя правило Even-Odd
|
||
// Rule, для определения какие регионы лежат внутри clipping path.
|
||
SetGrMode(grmode_CLIP);
|
||
m_pStream->WriteStr("W*\012");
|
||
}
|
||
void CPage::SetExtGrState(CExtGrState* pState)
|
||
{
|
||
if (!pState)
|
||
return;
|
||
|
||
// Operator : gs
|
||
// Description: устанавливаем сразу все настройки данного графического состояния(ExtGState)
|
||
|
||
CResourcesDict* pResources = GetResourcesItem();
|
||
if (!pResources)
|
||
return;
|
||
|
||
const char* sGsName = pResources->GetExtGrStateName(pState);
|
||
SetExtGrStateKey(sGsName);
|
||
}
|
||
void CPage::SetExtGrStateKey(const char* sKey)
|
||
{
|
||
// Operator : gs
|
||
// Description: устанавливаем сразу все настройки данного графического состояния(ExtGState)
|
||
|
||
if (!sKey)
|
||
return;
|
||
|
||
m_pStream->WriteEscapeName(sKey);
|
||
m_pStream->WriteStr(" gs\012");
|
||
}
|
||
void CPage::AddAnnotation(CDictObject* pAnnot)
|
||
{
|
||
CArrayObject* pArray = (CArrayObject*)Get("Annots");
|
||
if (!pArray)
|
||
{
|
||
pArray = new CArrayObject();
|
||
if (!pArray)
|
||
return;
|
||
|
||
Add("Annots", pArray);
|
||
}
|
||
|
||
return pArray->Add(pAnnot);
|
||
}
|
||
bool CPage::DeleteAnnotation(unsigned int nID)
|
||
{
|
||
CArrayObject* pArray = (CArrayObject*)Get("Annots");
|
||
if (!pArray)
|
||
return false;
|
||
|
||
for (int i = 0; i < pArray->GetCount(); i++)
|
||
{
|
||
CObjectBase* pObj = pArray->Get(i);
|
||
if (pObj->GetObjId() == nID)
|
||
{
|
||
CObjectBase* pDelete = pArray->Remove(i);
|
||
RELEASEOBJECT(pDelete);
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
void CPage::BeginText()
|
||
{
|
||
// Operator : BT
|
||
// Description: Начало текста
|
||
SetGrMode(grmode_TEXT);
|
||
m_pStream->WriteStr("BT\012");
|
||
|
||
m_oTextPos.Reset();
|
||
m_oTextMatrix.Reset();
|
||
}
|
||
void CPage::EndText()
|
||
{
|
||
// Operator : ET
|
||
// Description: Окончание текста
|
||
CheckGrMode(grmode_TEXT);
|
||
m_pStream->WriteStr("ET\012");
|
||
SetGrMode(grmode_PAGE);
|
||
}
|
||
void CPage::MoveTextPos(double dX, double dY)
|
||
{
|
||
// Operator : Td
|
||
// Description: Переходим к началу следующей линии, сдвигаясь от начала текущей на ( fX, fY ).
|
||
CheckGrMode(grmode_TEXT);
|
||
|
||
m_pStream->WriteReal(dX);
|
||
m_pStream->WriteChar(' ');
|
||
m_pStream->WriteReal(dY);
|
||
m_pStream->WriteStr(" Td\012");
|
||
|
||
m_oTextMatrix.x += dX * m_oTextMatrix.m11 + dY * m_oTextMatrix.m21;
|
||
m_oTextMatrix.y += dX * m_oTextMatrix.m12 + dY * m_oTextMatrix.m22;
|
||
m_oTextPos.Set(m_oTextMatrix.x, m_oTextMatrix.y);
|
||
}
|
||
void CPage::ShowText(const BYTE* sText, unsigned int unLen)
|
||
{
|
||
// Operator : Tj
|
||
// Description: Показать текстовую строку.
|
||
CheckGrMode(grmode_TEXT);
|
||
WriteText(sText, unLen);
|
||
m_pStream->WriteStr(" Tj\012");
|
||
}
|
||
void CPage::WriteText(const BYTE* sText, unsigned int unLen)
|
||
{
|
||
EFontType eType = m_eType != fontUnknownType ? m_eType : (m_pFont ? m_pFont->GetFontType() : fontCIDType0);
|
||
if (fontCIDType0 == eType || fontCIDType0C == eType || fontCIDType0COT == eType || fontCIDType2 == eType || fontCIDType2OT == eType)
|
||
{
|
||
m_pStream->WriteChar('<');
|
||
m_pStream->WriteBinary(sText, unLen, NULL);
|
||
m_pStream->WriteChar('>');
|
||
}
|
||
else
|
||
{
|
||
unLen = unLen / 2;
|
||
BYTE* sText2 = new BYTE[unLen];
|
||
for (int i = 0; i < unLen; ++i)
|
||
sText2[i] = sText[i * 2 + 1];
|
||
m_pStream->WriteChar('<');
|
||
m_pStream->WriteBinary(sText2, unLen, NULL);
|
||
m_pStream->WriteChar('>');
|
||
RELEASEARRAYOBJECTS(sText2);
|
||
}
|
||
}
|
||
void CPage::DrawText(double dXpos, double dYpos, const BYTE* sText, unsigned int unLen)
|
||
{
|
||
CheckGrMode(grmode_TEXT);
|
||
|
||
double dX = 0.0;
|
||
double dY = 0.0;
|
||
|
||
if (0 == m_oTextMatrix.m11)
|
||
{
|
||
dY = (dXpos - m_oTextMatrix.x) / m_oTextMatrix.m21;
|
||
dX = (dYpos - m_oTextMatrix.y - (dXpos - m_oTextMatrix.x) * m_oTextMatrix.m22 / m_oTextMatrix.m21) / m_oTextMatrix.m12;
|
||
}
|
||
else
|
||
{
|
||
dY = (dYpos - m_oTextMatrix.y - (dXpos - m_oTextMatrix.x) * m_oTextMatrix.m12 / m_oTextMatrix.m11) / (m_oTextMatrix.m22 - m_oTextMatrix.m21 * m_oTextMatrix.m12 / m_oTextMatrix.m11);
|
||
dX = (dXpos - m_oTextMatrix.x - dY * m_oTextMatrix.m21) / m_oTextMatrix.m11;
|
||
}
|
||
|
||
MoveTextPos(dX, dY);
|
||
ShowText(sText, unLen);
|
||
}
|
||
void CPage::DrawTextLine(const CTextLine* pTextLine)
|
||
{
|
||
if (!pTextLine)
|
||
return;
|
||
|
||
int nCount = pTextLine->m_vWords.size();
|
||
if (nCount <= 0)
|
||
return;
|
||
|
||
CheckGrMode(grmode_TEXT);
|
||
|
||
double dXpos = pTextLine->m_dX;
|
||
double dYpos = pTextLine->m_dY;
|
||
|
||
double dX = 0.0;
|
||
double dY = 0.0;
|
||
|
||
if (0 == m_oTextMatrix.m11)
|
||
{
|
||
dY = (dXpos - m_oTextMatrix.x) / m_oTextMatrix.m21;
|
||
dX = (dYpos - m_oTextMatrix.y - (dXpos - m_oTextMatrix.x) * m_oTextMatrix.m22 / m_oTextMatrix.m21) / m_oTextMatrix.m12;
|
||
}
|
||
else
|
||
{
|
||
dY = (dYpos - m_oTextMatrix.y - (dXpos - m_oTextMatrix.x) * m_oTextMatrix.m12 / m_oTextMatrix.m11) / (m_oTextMatrix.m22 - m_oTextMatrix.m21 * m_oTextMatrix.m12 / m_oTextMatrix.m11);
|
||
dX = (dXpos - m_oTextMatrix.x - dY * m_oTextMatrix.m21) / m_oTextMatrix.m11;
|
||
}
|
||
MoveTextPos(dX, dY);
|
||
|
||
if (1 == nCount)
|
||
{
|
||
CTextWord* pWord = pTextLine->m_vWords.at(0);
|
||
ShowText(pWord->m_pText, pWord->m_nIndex * 2);
|
||
}
|
||
else
|
||
{
|
||
CTextWord* pWord = NULL;
|
||
double dShift = 0;
|
||
m_pStream->WriteChar('[');
|
||
for (int nIndex = 0; nIndex < nCount; nIndex++)
|
||
{
|
||
pWord = pTextLine->m_vWords.at(nIndex);
|
||
WriteText(pWord->m_pText, pWord->m_nIndex * 2);
|
||
if (nIndex != nCount - 1)
|
||
{
|
||
dShift = pTextLine->m_vShifts.at(nIndex);
|
||
m_pStream->WriteReal(dShift);
|
||
}
|
||
}
|
||
m_pStream->WriteStr("]TJ\012");
|
||
}
|
||
}
|
||
void CPage::SetTextRise(double dS)
|
||
{
|
||
// Operator : Ts
|
||
// Description: Устанавливаем подъём текста
|
||
CheckGrMode(grmode_TEXT);
|
||
|
||
m_pStream->WriteReal(dS);
|
||
m_pStream->WriteStr(" Ts\012");
|
||
}
|
||
void CPage::SetCharSpace(double dValue)
|
||
{
|
||
// Operator : Tc
|
||
// Description: Устанавливаем расстояние между буквами
|
||
CheckGrMode(grmode_TEXT);
|
||
|
||
dValue = std::min((double)MAX_CHARSPACE, std::max((double)MIN_CHARSPACE, dValue));
|
||
m_pStream->WriteReal(dValue);
|
||
m_pStream->WriteStr(" Tc\012");
|
||
}
|
||
void CPage::SetWordSpace(double dValue)
|
||
{
|
||
// Operator : Tw
|
||
// Description: Устанавливаем расстояние между словами
|
||
CheckGrMode(grmode_TEXT);
|
||
|
||
m_pStream->WriteReal(dValue);
|
||
m_pStream->WriteStr(" Tw\012");
|
||
}
|
||
void CPage::SetHorizontalScaling(double dValue)
|
||
{
|
||
// Operator : Tz
|
||
// Description: Устанавливаем горизонтальное растяжение/сжатие
|
||
CheckGrMode(grmode_TEXT);
|
||
|
||
dValue = std::min((double)MAX_HORIZONTALSCALING, std::max((double)MIN_HORIZONTALSCALING, dValue));
|
||
m_pStream->WriteReal(dValue);
|
||
m_pStream->WriteStr(" Tz\012");
|
||
}
|
||
void CPage::SetFontAndSize(CFontDict* pFont, double dSize)
|
||
{
|
||
// Operator : Tf
|
||
// Description: Устанавливаем шрифт и размер шрифта
|
||
|
||
dSize = std::min((double)MAX_FONTSIZE, std::max(0.0, dSize));
|
||
CResourcesDict* pResources = GetResourcesItem();
|
||
if (!pResources)
|
||
return;
|
||
|
||
const char* sFontName = pResources->GetFontName(pFont);
|
||
if (!sFontName)
|
||
return;
|
||
|
||
m_pStream->WriteEscapeName(sFontName);
|
||
m_pStream->WriteChar(' ');
|
||
m_pStream->WriteReal(dSize);
|
||
m_pStream->WriteStr(" Tf\012");
|
||
|
||
m_pFont = pFont;
|
||
}
|
||
void CPage::SetFontKeyAndSize(const char* sKey, double dSize)
|
||
{
|
||
// Operator : Tf
|
||
// Description: Устанавливаем шрифт и размер шрифта
|
||
|
||
dSize = std::min((double)MAX_FONTSIZE, std::max(0.0, dSize));
|
||
if (!sKey)
|
||
return;
|
||
|
||
m_pStream->WriteEscapeName(sKey);
|
||
m_pStream->WriteChar(' ');
|
||
m_pStream->WriteReal(dSize);
|
||
m_pStream->WriteStr(" Tf\012");
|
||
}
|
||
void CPage::SetFontType(EFontType nType)
|
||
{
|
||
m_eType = nType;
|
||
}
|
||
void CPage::SetTextRenderingMode(ETextRenderingMode eMode)
|
||
{
|
||
// Operator : Tr
|
||
// Description: Устанавливаем тип закрашивания символов (TextRenderingMode)
|
||
CheckGrMode(grmode_TEXT);
|
||
m_pStream->WriteInt((int)eMode);
|
||
m_pStream->WriteStr(" Tr\012");
|
||
}
|
||
void CPage::SetTextMatrix(double dM11, double dM12, double dM21, double dM22, double dX, double dY)
|
||
{
|
||
// Operator : Tm
|
||
// Description: Устанавливаем матрицу преобразования для текста.
|
||
CheckGrMode(grmode_TEXT);
|
||
|
||
m_pStream->WriteReal(dM11);
|
||
m_pStream->WriteChar(' ');
|
||
m_pStream->WriteReal(dM12);
|
||
m_pStream->WriteChar(' ');
|
||
m_pStream->WriteReal(dM21);
|
||
m_pStream->WriteChar(' ');
|
||
m_pStream->WriteReal(dM22);
|
||
m_pStream->WriteChar(' ');
|
||
m_pStream->WriteReal(dX);
|
||
m_pStream->WriteChar(' ');
|
||
m_pStream->WriteReal(dY);
|
||
m_pStream->WriteStr(" Tm\012");
|
||
|
||
m_oTextMatrix.m11 = dM11;
|
||
m_oTextMatrix.m12 = dM12;
|
||
m_oTextMatrix.m21 = dM21;
|
||
m_oTextMatrix.m22 = dM22;
|
||
m_oTextMatrix.x = dX;
|
||
m_oTextMatrix.y = dY;
|
||
m_oTextPos.Set(m_oTextMatrix.x, m_oTextMatrix.y);
|
||
}
|
||
void CPage::ExecuteXObject(CXObject* pXObject)
|
||
{
|
||
CResourcesDict* pResources = GetResourcesItem();
|
||
if (!pResources)
|
||
return;
|
||
|
||
const char* sXObjectName = pResources->GetXObjectName(pXObject);
|
||
ExecuteXObject(sXObjectName);
|
||
}
|
||
void CPage::ExecuteXObject(const char* sXObjectName)
|
||
{
|
||
if (!sXObjectName)
|
||
return;
|
||
m_pStream->WriteEscapeName(sXObjectName);
|
||
m_pStream->WriteStr(" Do\012");
|
||
}
|
||
void CPage::DrawImage(CImageDict* pImage, double dX, double dY, double dWidth, double dHeight)
|
||
{
|
||
GrSave();
|
||
Concat(dWidth, 0, 0, dHeight, dX, dY);
|
||
ExecuteXObject(pImage);
|
||
GrRestore();
|
||
}
|
||
void CPage::DrawShading(CShading* pShading)
|
||
{
|
||
// Operator : sh
|
||
// Description: отрисовываем градиент
|
||
|
||
const char* sShadingName = GetLocalShadingName(pShading);
|
||
if (!sShadingName)
|
||
return;
|
||
|
||
m_pStream->WriteEscapeName(sShadingName);
|
||
m_pStream->WriteStr(" sh\012");
|
||
}
|
||
void CPage::SetStrokeAlpha(unsigned char unAlpha)
|
||
{
|
||
CExtGrState* pExtGrState = m_pDocument->GetStrokeAlpha((double)(unAlpha / 255.0));
|
||
if (pExtGrState)
|
||
SetExtGrState(pExtGrState);
|
||
}
|
||
void CPage::SetFillAlpha(unsigned char unAlpha)
|
||
{
|
||
CExtGrState* pExtGrState = m_pDocument->GetFillAlpha((double)(unAlpha / 255.0));
|
||
if (pExtGrState)
|
||
SetExtGrState(pExtGrState);
|
||
}
|
||
const char* CPage::GetLocalShadingName(CShading* pShading)
|
||
{
|
||
if (!m_pShadings)
|
||
{
|
||
CDictObject* pResources = GetResourcesItem();
|
||
if (!pResources)
|
||
return NULL;
|
||
|
||
m_pShadings = new CDictObject();
|
||
if (!m_pShadings)
|
||
return NULL;
|
||
|
||
pResources->Add("Shading", m_pShadings);
|
||
}
|
||
|
||
const char* sKey = m_pShadings->GetKey(pShading);
|
||
if (!sKey)
|
||
{
|
||
char sShadingName[LIMIT_MAX_NAME_LEN + 1];
|
||
char *pPointer;
|
||
char *pEndPointer = sShadingName + LIMIT_MAX_NAME_LEN;
|
||
|
||
++m_unShadingsCount;
|
||
while (m_unShadingsCount < LIMIT_MAX_DICT_ELEMENT)
|
||
{
|
||
if (m_pShadings->Get("S" + std::to_string(m_unShadingsCount)))
|
||
++m_unShadingsCount;
|
||
else
|
||
break;
|
||
}
|
||
|
||
pPointer = (char*)StrCpy(sShadingName, "S", pEndPointer);
|
||
ItoA(pPointer, m_unShadingsCount, pEndPointer);
|
||
m_pShadings->Add(sShadingName, pShading);
|
||
sKey = m_pShadings->GetKey(pShading);
|
||
}
|
||
|
||
return sKey;
|
||
}
|
||
const char* CPage::GetLocalPatternName(CImageTilePattern* pPattern)
|
||
{
|
||
if (!m_pPatterns)
|
||
{
|
||
CDictObject* pResources = GetResourcesItem();
|
||
if (!pResources)
|
||
return NULL;
|
||
|
||
m_pPatterns = new CDictObject();
|
||
if (!m_pPatterns)
|
||
return NULL;
|
||
|
||
pResources->Add("Pattern", m_pPatterns);
|
||
}
|
||
|
||
const char* sKey = m_pPatterns->GetKey(pPattern);
|
||
if (!sKey)
|
||
{
|
||
char sPatternName[LIMIT_MAX_NAME_LEN + 1];
|
||
char *pPointer;
|
||
char *pEndPointer = sPatternName + LIMIT_MAX_NAME_LEN;
|
||
|
||
++m_unPatternsCount;
|
||
while (m_unPatternsCount < LIMIT_MAX_DICT_ELEMENT)
|
||
{
|
||
if (m_pPatterns->Get("P" + std::to_string(m_unPatternsCount)))
|
||
++m_unPatternsCount;
|
||
else
|
||
break;
|
||
}
|
||
|
||
pPointer = (char*)StrCpy(sPatternName, "P", pEndPointer);
|
||
ItoA(pPointer, m_unPatternsCount, pEndPointer);
|
||
m_pPatterns->Add(sPatternName, pPattern);
|
||
sKey = m_pPatterns->GetKey(pPattern);
|
||
}
|
||
|
||
return sKey;
|
||
}
|
||
void CPage::SetPatternColorSpace(CImageTilePattern* pPattern)
|
||
{
|
||
// Operator : csn
|
||
// Description: задаем паттерн для рисования
|
||
|
||
const char* sPatternName = GetLocalPatternName(pPattern);
|
||
if (!sPatternName)
|
||
return;
|
||
|
||
m_pStream->WriteStr("/Pattern cs\012");
|
||
m_pStream->WriteEscapeName(sPatternName);
|
||
m_pStream->WriteStr(" scn\012");
|
||
}
|
||
void CPage::SetFilter(unsigned int unFiler)
|
||
{
|
||
if (m_pContents)
|
||
{
|
||
for (unsigned int unKidIndex = 0, unKidsCount = m_pContents->GetCount(); unKidIndex < unKidsCount; ++unKidIndex)
|
||
{
|
||
CObjectBase* pKid = m_pContents->Get(unKidIndex);
|
||
if (pKid->GetType() == object_type_DICT)
|
||
((CDictObject*)pKid)->SetFilter(unFiler);
|
||
}
|
||
}
|
||
}
|
||
CMatrix* CPage::GetTransform()
|
||
{
|
||
return &m_pGrState->m_oMatrix;
|
||
}
|
||
void CPage::AddGroup(CDictObject* pDict)
|
||
{
|
||
Add("Group", pDict);
|
||
}
|
||
void CPage::AddContents(CXref* pXref)
|
||
{
|
||
CDictObject* pContent = new CDictObject(pXref);
|
||
m_pContents->Add(pContent);
|
||
m_pStream = pContent->GetStream();
|
||
}
|
||
void CPage::SetRotate(int nRotate)
|
||
{
|
||
// The value shall be a multiple of 90
|
||
if (nRotate % 90 == 0)
|
||
Add("Rotate", nRotate % 360);
|
||
}
|
||
void CPage::ClearContent(CXref* pXref)
|
||
{
|
||
m_pContents = new CArrayObject();
|
||
Add("Contents", m_pContents);
|
||
AddContents(pXref);
|
||
#ifndef FILTER_FLATE_DECODE_DISABLED
|
||
SetFilter(STREAM_FILTER_FLATE_DECODE);
|
||
#endif
|
||
}
|
||
void CPage::ClearContentFull(CXref* pXref)
|
||
{
|
||
if (m_pContents)
|
||
{
|
||
for (int i = 0; i < m_pContents->GetCount(); ++i)
|
||
{
|
||
CObjectBase* pObj = m_pContents->Get(i);
|
||
if (pObj->GetType() == object_type_DICT)
|
||
{
|
||
CObjectBase* pLength = ((CDictObject*)pObj)->Get("Length");
|
||
pXref->Remove(pLength);
|
||
}
|
||
pXref->Remove(pObj);
|
||
}
|
||
}
|
||
ClearContent(pXref);
|
||
}
|
||
int CPage::GetRotate()
|
||
{
|
||
CNumberObject* pRotate = (CNumberObject*)GetRotateItem();
|
||
return pRotate ? pRotate->Get() : 0;
|
||
}
|
||
void CPage::BeginMarkedContent(const std::string& sName)
|
||
{
|
||
// Operator : BMC
|
||
// Description: Начало маркированного контента
|
||
|
||
m_pStream->WriteEscapeName(sName.c_str());
|
||
m_pStream->WriteStr(" BMC\012");
|
||
}
|
||
void CPage::BeginMarkedContentDict(const std::string& sName, CDictObject* pBDC)
|
||
{
|
||
// Operator : BDC
|
||
// Description: Начало маркированного контента со списком свойств
|
||
|
||
m_pStream->WriteEscapeName(sName.c_str());
|
||
m_pStream->WriteChar(' ');
|
||
m_pStream->Write(pBDC, NULL);
|
||
m_pStream->WriteStr(" BDC\012");
|
||
}
|
||
void CPage::EndMarkedContent()
|
||
{
|
||
// Operator : EMC
|
||
// Description: Конец маркированного контента
|
||
|
||
m_pStream->WriteStr("EMC\012");
|
||
}
|
||
void CPage::SetRenderingIntent(ERenderingIntent eRenderingIntent)
|
||
{
|
||
// Operator : ri
|
||
// Description: Способы рендеринга/цветопередачи
|
||
|
||
m_pStream->WriteEscapeName(c_sRenderingIntent[(int)eRenderingIntent]);
|
||
m_pStream->WriteStr(" ri\012");
|
||
}
|
||
|
||
CFakePage::CFakePage(int nOriginIndex) : m_nOriginIndex(nOriginIndex)
|
||
{
|
||
}
|
||
int CFakePage::GetOriginIndex()
|
||
{
|
||
return m_nOriginIndex;
|
||
}
|
||
//----------------------------------------------------------------------------------------
|
||
// CTextWord
|
||
//----------------------------------------------------------------------------------------
|
||
CTextWord::CTextWord()
|
||
{
|
||
m_nIndex = 0;
|
||
m_pText = (unsigned char*)malloc(STR_BUF);
|
||
m_nSize = STR_BUF;
|
||
}
|
||
CTextWord::~CTextWord()
|
||
{
|
||
if (m_pText)
|
||
free(m_pText);
|
||
}
|
||
void CTextWord::CheckBuffer()
|
||
{
|
||
if (2 * m_nIndex >= m_nSize)
|
||
{
|
||
m_nSize += STR_BUF;
|
||
m_pText = (unsigned char*)realloc(m_pText, m_nSize);
|
||
}
|
||
}
|
||
bool CTextWord::Add(unsigned char* pCodes, unsigned int unLen, double dX, double dY, double dWidth)
|
||
{
|
||
if (2 != unLen)
|
||
return false;
|
||
|
||
CheckBuffer();
|
||
|
||
if (0 == m_nIndex)
|
||
{
|
||
m_pText[0] = pCodes[0];
|
||
m_pText[1] = pCodes[1];
|
||
m_nIndex++;
|
||
m_dStartX = dX;
|
||
m_dStartY = dY;
|
||
|
||
m_dCurX = dX + dWidth;
|
||
}
|
||
else
|
||
{
|
||
if (fabs(dY - m_dStartY) > 0.001 || fabs(dX - m_dCurX) > 0.01)
|
||
return false;
|
||
|
||
m_pText[m_nIndex * 2 + 0] = pCodes[0];
|
||
m_pText[m_nIndex * 2 + 1] = pCodes[1];
|
||
m_nIndex++;
|
||
|
||
m_dCurX = dX + dWidth;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
//----------------------------------------------------------------------------------------
|
||
// CTextLine
|
||
//----------------------------------------------------------------------------------------
|
||
CTextLine::CTextLine()
|
||
{
|
||
}
|
||
CTextLine::~CTextLine()
|
||
{
|
||
Clear();
|
||
}
|
||
bool CTextLine::Add(unsigned char* pCodes, unsigned int unLen, double dX, double dY, double dWidth, double dSize)
|
||
{
|
||
if (2 != unLen)
|
||
return false;
|
||
|
||
if (0 == m_vWords.size())
|
||
{
|
||
CTextWord* pText = new CTextWord();
|
||
if (!pText || !pText->Add(pCodes, unLen, dX, dY, dWidth))
|
||
return false;
|
||
|
||
m_vWords.push_back(pText);
|
||
m_dX = dX;
|
||
m_dY = dY;
|
||
return true;
|
||
}
|
||
|
||
if (fabs(dY - m_dY) > 0.001)
|
||
return false;
|
||
|
||
CTextWord* pLastText = m_vWords.at(m_vWords.size() - 1);
|
||
if (pLastText->Add(pCodes, unLen, dX, dY, dWidth))
|
||
return true;
|
||
|
||
CTextWord* pText = new CTextWord();
|
||
if (!pText || !pText->Add(pCodes, unLen, dX, dY, dWidth))
|
||
return false;
|
||
|
||
m_vWords.push_back(pText);
|
||
double dShift = (pLastText->m_dCurX - dX) * 1000 / dSize;
|
||
m_vShifts.push_back(dShift);
|
||
return true;
|
||
}
|
||
void CTextLine::Flush(CPage* pPage)
|
||
{
|
||
pPage->DrawTextLine(this);
|
||
Clear();
|
||
}
|
||
void CTextLine::Clear()
|
||
{
|
||
for (int nIndex = 0, nCount = m_vWords.size(); nIndex < nCount; nIndex++)
|
||
{
|
||
CTextWord* pText = m_vWords.at(nIndex);
|
||
RELEASEOBJECT(pText);
|
||
}
|
||
m_vWords.clear();
|
||
m_vShifts.clear();
|
||
}
|
||
}
|