Files
core/PdfReader/Src/Graphics.cpp
Ilya.Kirillov eb965c1d6d Добавлен новый проект PdfReader для кроссплатформенного чтения Pdf.
git-svn-id: svn://fileserver/activex/AVS/Sources/TeamlabOffice/trunk/ServerComponents@62480 954022d7-b5bf-4e40-9824-e11837661b57
2016-05-21 00:01:53 +03:00

4943 lines
143 KiB
C++

#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include <math.h>
#include "MemoryUtils.h"
#include "GlobalParams.h"
#include "CharTypes.h"
#include "Object.h"
#include "Array.h"
#include "Dict.h"
#include "Stream.h"
#include "Lexer.h"
#include "Parser.h"
#include "GFont.h"
#include "GState.h"
#include "RendererOutputDev.h"
#include "OutputDevice.h"
#include "Page.h"
#include "Annot.h"
#include "Graphics.h"
// Ïîä âèíäîé ïåðåîïðåäåëÿåòñÿ
#ifdef GetObject
#undef GetObject
#endif
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
//-------------------------------------------------------------------------------------------------------------------------------
// Êîíñòàíòû
//-------------------------------------------------------------------------------------------------------------------------------
#define functionMaxDepth 6
#define functionColorDelta (DoubleToColor(1 / 256.0))
#define axialMaxSplits 256
#define axialColorDelta (DoubleToColor(1 / 256.0))
#define radialMaxSplits 256
#define radialColorDelta (DoubleToColor(1 / 256.0))
#define gouraudMaxDepth 1
#define gouraudColorDelta (DoubleToColor(1 / 256.0))
#define patchMaxDepth 6
#define patchColorDelta (DoubleToColor(1 / 256.0))
//-------------------------------------------------------------------------------------------------------------------------------
// Òàáëèöà ãðàôè÷åñêèõ îïåðàòîðîâ
//-------------------------------------------------------------------------------------------------------------------------------
#ifdef WIN32 // this works around a bug in the VC7 compiler
# pragma optimize("",off)
#endif
namespace PdfReader
{
Operator Graphics::OperatorsTable[] =
{
{ "\"", 3, { argNum, argNum, argString }, &Graphics::OperatorMoveSetShowText },
{ "'", 1, { argString }, &Graphics::OperatorMoveShowText },
{ "B", 0, { argNone }, &Graphics::OperatorFillStroke },
{ "B*", 0, { argNone }, &Graphics::OperatorEOFillStroke },
{ "BDC", 2, { argName, argProps }, &Graphics::OperatorBeginMarkedContent },
{ "BI", 0, { argNone }, &Graphics::OperatorBeginImage },
{ "BMC", 1, { argName }, &Graphics::OperatorBeginMarkedContent },
{ "BT", 0, { argNone }, &Graphics::OperatorBeginText },
{ "BX", 0, { argNone }, &Graphics::OperatorBeginIgnoreUndef },
{ "CS", 1, { argName }, &Graphics::OperatorSetStrokeColorSpace },
{ "DP", 2, { argName, argProps }, &Graphics::OperatorMarkPoint },
{ "Do", 1, { argName }, &Graphics::OperatorXObject },
{ "EI", 0, { argNone }, &Graphics::OperatorEndImage },
{ "EMC", 0, { argNone }, &Graphics::OperatorEndMarkedContent },
{ "ET", 0, { argNone }, &Graphics::OperatorEndText },
{ "EX", 0, { argNone }, &Graphics::OperatorEndIgnoreUndef },
{ "F", 0, { argNone }, &Graphics::OperatorFill },
{ "G", 1, { argNum }, &Graphics::OperatorSetStrokeGray },
{ "ID", 0, { argNone }, &Graphics::OperatorImageData },
{ "J", 1, { argInt }, &Graphics::OperatorSetLineCap },
{ "K", 4, { argNum, argNum, argNum, argNum }, &Graphics::OperatorSetStrokeCMYKColor },
{ "M", 1, { argNum }, &Graphics::OperatorSetMiterLimit },
{ "MP", 1, { argName }, &Graphics::OperatorMarkPoint },
{ "Q", 0, { argNone }, &Graphics::OperatorRestore },
{ "RG", 3, { argNum, argNum, argNum }, &Graphics::OperatorSetStrokeRGBColor },
{ "S", 0, { argNone }, &Graphics::OperatorStroke },
{ "SC", -4, { argNum, argNum, argNum, argNum }, &Graphics::OperatorSetStrokeColor },
{ "SCN", -33, { argSCN, argSCN, argSCN, argSCN, argSCN, argSCN,
argSCN, argSCN, argSCN, argSCN, argSCN, argSCN,
argSCN, argSCN, argSCN, argSCN, argSCN, argSCN,
argSCN, argSCN, argSCN, argSCN, argSCN, argSCN,
argSCN, argSCN, argSCN, argSCN, argSCN, argSCN,
argSCN, argSCN, argSCN }, &Graphics::OperatorSetStrokeColorN },
{ "T*", 0, { argNone }, &Graphics::OperatorTextNextLine },
{ "TD", 2, { argNum, argNum }, &Graphics::OperatorTextMoveSet },
{ "TJ", 1, { argArray }, &Graphics::OperatorShowSpaceText },
{ "TL", 1, { argNum }, &Graphics::OperatorSetTextLeading },
{ "Tc", 1, { argNum }, &Graphics::OperatorSetCharSpacing },
{ "Td", 2, { argNum, argNum }, &Graphics::OperatorTextMove },
{ "Tf", 2, { argName, argNum }, &Graphics::OperatorSetFont },
{ "Tj", 1, { argString }, &Graphics::OperatorShowText },
{ "Tm", 6, { argNum, argNum, argNum, argNum, argNum, argNum }, &Graphics::OperatorSetTextMatrix },
{ "Tr", 1, { argInt }, &Graphics::OperatorSetTextRender },
{ "Ts", 1, { argNum }, &Graphics::OperatorSetTextRise },
{ "Tw", 1, { argNum }, &Graphics::OperatorSetWordSpacing },
{ "Tz", 1, { argNum }, &Graphics::OperatorSetHorizScaling },
{ "W", 0, { argNone }, &Graphics::OperatorClip },
{ "W*", 0, { argNone }, &Graphics::OperatorEOClip },
{ "b", 0, { argNone }, &Graphics::OperatorCloseFillStroke },
{ "b*", 0, { argNone }, &Graphics::OperatorCloseEOFillStroke },
{ "c", 6, { argNum, argNum, argNum, argNum, argNum, argNum }, &Graphics::OperatorCurveTo },
{ "cm", 6, { argNum, argNum, argNum, argNum, argNum, argNum }, &Graphics::OperatorConcat },
{ "cs", 1, { argName }, &Graphics::OperatorSetFillColorSpace },
{ "d", 2, { argArray, argNum }, &Graphics::OperatorSetDash },
{ "d0", 2, { argNum, argNum }, &Graphics::OperatorSetCharWidth },
{ "d1", 6, { argNum, argNum, argNum, argNum, argNum, argNum }, &Graphics::OperatorSetCacheDevice },
{ "f", 0, { argNone }, &Graphics::OperatorFill },
{ "f*", 0, { argNone }, &Graphics::OperatorEOFill },
{ "g", 1, { argNum }, &Graphics::OperatorSetFillGray },
{ "gs", 1, { argName }, &Graphics::OperatorSetExtGState },
{ "h", 0, { argNone }, &Graphics::OperatorClosePath },
{ "i", 1, { argNum }, &Graphics::OperatorSetFlat },
{ "j", 1, { argInt }, &Graphics::OperatorSetLineJoin },
{ "k", 4, { argNum, argNum, argNum, argNum }, &Graphics::OperatorSetFillCMYKColor },
{ "l", 2, { argNum, argNum }, &Graphics::OperatorLineTo },
{ "m", 2, { argNum, argNum }, &Graphics::OperatorMoveTo },
{ "n", 0, { argNone }, &Graphics::OperatorEndPath },
{ "q", 0, { argNone }, &Graphics::OperatorSave },
{ "re", 4, { argNum, argNum, argNum, argNum }, &Graphics::OperatorRectangle },
{ "rg", 3, { argNum, argNum, argNum }, &Graphics::OperatorSetFillRGBColor },
{ "ri", 1, { argName }, &Graphics::OperatorSetRenderingIntent },
{ "s", 0, { argNone }, &Graphics::OperatorCloseStroke },
{ "sc", -4, { argNum, argNum, argNum, argNum }, &Graphics::OperatorSetFillColor },
{ "scn", -33, { argSCN, argSCN, argSCN, argSCN, argSCN, argSCN,
argSCN, argSCN, argSCN, argSCN, argSCN, argSCN,
argSCN, argSCN, argSCN, argSCN, argSCN, argSCN,
argSCN, argSCN, argSCN, argSCN, argSCN, argSCN,
argSCN, argSCN, argSCN, argSCN, argSCN, argSCN,
argSCN, argSCN, argSCN }, &Graphics::OperatorSetFillColorN },
{ "sh", 1, { argName }, &Graphics::OperatorShadingFill },
{ "v", 4, { argNum, argNum, argNum, argNum }, &Graphics::OperatorCurveTo1 },
{ "w", 1, { argNum }, &Graphics::OperatorSetLineWidth },
{ "y", 4, { argNum, argNum, argNum, argNum }, &Graphics::OperatorCurveTo2 },
};
#ifdef WIN32 // this works around a bug in the VC7 compiler
# pragma optimize("",on)
#endif
#define OperatorsCount (sizeof(OperatorsTable) / sizeof(Operator))
//-------------------------------------------------------------------------------------------------------------------------------
// GrResources
//-------------------------------------------------------------------------------------------------------------------------------
GrResources::GrResources(XRef *pXref, Dict *pResourcesDict, GrResources *pNext, GlobalParams *pGlobalParams)
{
m_pGlobalParams = pGlobalParams;
if (pResourcesDict)
{
// build font dictionary
m_pFonts = NULL;
Object oFont;
pResourcesDict->SearchAndCopy("Font", &oFont);
if (oFont.IsRef())
{
Object oTemp;
oFont.Fetch(pXref, &oTemp);
if (oTemp.IsDict())
{
Ref oRef = oFont.GetRef();
m_pFonts = new GrFontDict(pXref, &oRef, oTemp.GetDict(), pGlobalParams);
}
oTemp.Free();
}
else if (oFont.IsDict())
{
m_pFonts = new GrFontDict(pXref, NULL, oFont.GetDict(), pGlobalParams);
}
oFont.Free();
//XObject
pResourcesDict->Search("XObject", &m_oXObjectDict);
//ColorSpace
pResourcesDict->Search("ColorSpace", &m_oColorSpaceDict);
//Pattern
pResourcesDict->Search("Pattern", &m_oPatternDict);
//Shading
pResourcesDict->Search("Shading", &m_oShadingDict);
//ExtGState
pResourcesDict->Search("ExtGState", &m_oExtGStateDict);
}
else
{
m_pFonts = NULL;
m_oXObjectDict.InitNull();
m_oColorSpaceDict.InitNull();
m_oPatternDict.InitNull();
m_oShadingDict.InitNull();
m_oExtGStateDict.InitNull();
}
m_pNext = pNext;
}
GrResources::~GrResources()
{
if (m_pFonts)
{
delete m_pFonts;
}
m_oXObjectDict.Free();
m_oColorSpaceDict.Free();
m_oPatternDict.Free();
m_oShadingDict.Free();
m_oExtGStateDict.Free();
}
GrFont *GrResources::LookupFont(char *sName)
{
GrFont *pFont = NULL;
GrResources *pResources = NULL;
for (pResources = this; pResources; pResources = pResources->m_pNext)
{
if (pResources->m_pFonts)
{
if ((pFont = pResources->m_pFonts->Search(sName)))
return pFont;
}
}
// TO DO: Error "Unknown font tag"
return NULL;
}
bool GrResources::LookupXObject(char *sName, Object *pObject)
{
GrResources *pResources = NULL;
for (pResources = this; pResources; pResources = pResources->m_pNext)
{
if (pResources->m_oXObjectDict.IsDict())
{
if (!pResources->m_oXObjectDict.DictLookup(sName, pObject)->IsNull())
return true;
pObject->Free();
}
}
// TO DO: Error "XObject is unknown"
return false;
}
bool GrResources::LookupAndCopyXObject(char *sName, Object *pObject)
{
GrResources *pResources = NULL;
for (pResources = this; pResources; pResources = pResources->m_pNext)
{
if (pResources->m_oXObjectDict.IsDict())
{
if (!pResources->m_oXObjectDict.DictLookupAndCopy(sName, pObject)->IsNull())
return true;
pObject->Free();
}
}
// TO DO: Error "XObject is unknown"
return false;
}
void GrResources::LookupColorSpace(char *sName, Object *pObject)
{
GrResources *pResources = NULL;
for (pResources = this; pResources; pResources = pResources->m_pNext)
{
if (pResources->m_oColorSpaceDict.IsDict())
{
if (!pResources->m_oColorSpaceDict.DictLookup(sName, pObject)->IsNull())
{
return;
}
pObject->Free();
}
}
pObject->InitNull();
}
GrPattern *GrResources::LookupPattern(char *sName)
{
GrResources *pResources = NULL;
GrPattern *pPattern = NULL;
Object oTemp;
for (pResources = this; pResources; pResources = pResources->m_pNext)
{
if (pResources->m_oPatternDict.IsDict())
{
if (!pResources->m_oPatternDict.DictLookup(sName, &oTemp)->IsNull())
{
pPattern = GrPattern::Parse(&oTemp);
oTemp.Free();
return pPattern;
}
oTemp.Free();
}
}
// TO DO: Error "Unknown pattern"
return NULL;
}
GrShading *GrResources::LookupShading(char *sName)
{
GrResources *pResources = NULL;
GrShading *pShading = NULL;
Object oTemp;
for (pResources = this; pResources; pResources = pResources->m_pNext)
{
if (pResources->m_oShadingDict.IsDict())
{
if (!pResources->m_oShadingDict.DictLookup(sName, &oTemp)->IsNull())
{
pShading = GrShading::Parse(&oTemp);
oTemp.Free();
return pShading;
}
oTemp.Free();
}
}
// TO DO: Error "Unknown shading"
return NULL;
}
bool GrResources::LookupExtGState(char *sName, Object *pObject)
{
GrResources *pResources = NULL;
for (pResources = this; pResources; pResources = pResources->m_pNext)
{
if (pResources->m_oExtGStateDict.IsDict())
{
if (!pResources->m_oExtGStateDict.DictLookup(sName, pObject)->IsNull())
{
return true;
}
pObject->Free();
}
}
// TO DO: Error "ExtGState is unknown"
return false;
}
//-------------------------------------------------------------------------------------------------------------------------------
// Graphics
//-------------------------------------------------------------------------------------------------------------------------------
Graphics::Graphics(GlobalParams *pGlobalParams, XRef *pXref, OutputDev *pOut, int nPageNumber, Dict *pResorcesDict, double dHorDPI, double dVerDPI, PDFRectangle *pBox, PDFRectangle *pCropBox, int nRotate, bool(*pAbortCheckCallBack)(void *pData), void *pAbortCheckData)
{
#ifdef _DEBUG
std::wstring wsFileName = L"D:\\Output\\PDF Dump\\DumpPDF_Page" + std::to_wstring(nPageNumber) + L".bin";
NSFile::CFileBinary oFile;
if (!oFile.CreateFileW(wsFileName))
m_pDumpFile = NULL;
else
m_pDumpFile = oFile.GetFileNative();
#endif
m_pGlobalParams = pGlobalParams;
m_pXref = pXref;
m_bSubPage = false;
// Resource stack
m_pResources = new GrResources(m_pXref, pResorcesDict, NULL, m_pGlobalParams);
// Initialize
m_pOut = pOut;
m_pGState = new GrState(dHorDPI, dVerDPI, pBox, nRotate, m_pOut->UpSideDown());
m_bFontChanged = false;
m_eClip = clipNone;
m_nIgnoreUndef = 0;
m_pOut->StartPage(nPageNumber, m_pGState);
m_pOut->SetDefaultCTM(m_pGState->GetCTM());
m_pOut->UpdateAll(m_pGState);
for (int nIndex = 0; nIndex < 6; ++nIndex)
{
m_arrBaseMatrix[nIndex] = m_pGState->GetCTM()[nIndex];
}
m_nFormDepth = 0;
m_pAbortCheckCallBack = pAbortCheckCallBack;
m_pAbortCheckData = pAbortCheckData;
if (pCropBox)
{
m_pGState->MoveTo(pCropBox->m_dLeft, pCropBox->m_dBottom);
m_pGState->LineTo(pCropBox->m_dRight, pCropBox->m_dBottom);
m_pGState->LineTo(pCropBox->m_dRight, pCropBox->m_dTop);
m_pGState->LineTo(pCropBox->m_dLeft, pCropBox->m_dTop);
m_pGState->ClosePath();
m_pGState->Clip();
m_pGState->GetClip()->ClipToPath(m_pGState->GetPath()->Copy(), m_pGState->GetCTM(), false);
if (m_pOut->UseClipTo())
m_pOut->ClipToPath(m_pGState, m_pGState->GetPath(), m_pGState->GetCTM(), false);
else
m_pOut->Clip(m_pGState);
m_pGState->ClearPath();
}
}
Graphics::Graphics(GlobalParams *pGlobalParams, XRef *pXref, OutputDev *pOut, Dict *pResorcesDict, PDFRectangle *pBox, PDFRectangle *pCropBox, bool(*pAbortCheckCallBack)(void *pData), void *pAbortCheckData)
{
#ifdef _DEBUG
m_pDumpFile = NULL;
#endif
m_pGlobalParams = pGlobalParams;
m_pXref = pXref;
m_bSubPage = true;
// Resource stack
m_pResources = new GrResources(m_pXref, pResorcesDict, NULL, m_pGlobalParams);
// Initialize
m_pOut = pOut;
m_pGState = new GrState(72, 72, pBox, 0, false);
m_bFontChanged = false;
m_eClip = clipNone;
m_nIgnoreUndef = 0;
for (int nIndex = 0; nIndex < 6; ++nIndex)
{
m_arrBaseMatrix[nIndex] = m_pGState->GetCTM()[nIndex];
}
m_nFormDepth = 0;
m_pAbortCheckCallBack = pAbortCheckCallBack;
m_pAbortCheckData = pAbortCheckData;
if (pCropBox)
{
m_pGState->MoveTo(pCropBox->m_dLeft, pCropBox->m_dBottom);
m_pGState->LineTo(pCropBox->m_dRight, pCropBox->m_dBottom);
m_pGState->LineTo(pCropBox->m_dRight, pCropBox->m_dTop);
m_pGState->LineTo(pCropBox->m_dLeft, pCropBox->m_dTop);
m_pGState->ClosePath();
m_pGState->Clip();
m_pGState->GetClip()->ClipToPath(m_pGState->GetPath()->Copy(), m_pGState->GetCTM(), false);
if (m_pOut->UseClipTo())
m_pOut->ClipToPath(m_pGState, m_pGState->GetPath(), m_pGState->GetCTM(), false);
else
m_pOut->Clip(m_pGState);
m_pGState->ClearPath();
}
}
Graphics::~Graphics()
{
#ifdef _DEBUG
if (m_pDumpFile)
::fclose(m_pDumpFile);
#endif
while (m_pGState->HasSaves())
{
RestoreGState();
}
if (!m_bSubPage)
{
m_pOut->EndPage();
}
while (m_pResources)
{
PopResources();
}
if (m_pGState)
{
delete m_pGState;
}
}
void Graphics::Display(Object *pObject, bool bTopLevel)
{
if (pObject->IsArray())
{
for (int nIndex = 0; nIndex < pObject->ArrayGetLength(); ++nIndex)
{
Object oTemp;
pObject->ArrayGet(nIndex, &oTemp);
if (!oTemp.IsStream())
{
// TO DO: Error "Weird page contents"
oTemp.Free();
return;
}
oTemp.Free();
}
}
else if (!pObject->IsStream())
{
// TO DO: Error "Weird page contents"
return;
}
m_pParser = new Parser(m_pXref, new Lexer(m_pXref, pObject), false);
if (NULL == m_pParser)
return;
StartParse(bTopLevel);
delete m_pParser;
m_pParser = NULL;
}
void Graphics::StartParse(bool bTopLevel)
{
Object arrArguments[maxArgs];
int nArgumentsCount = 0;
int nLastAbortCheck = 0;
m_nUpdateLevel = 0;
Object oTemp;
m_pParser->GetObject(&oTemp);
while (!oTemp.IsEOF())
{
if (m_pOut && m_pOut->IsStopped())
break;
if (oTemp.IsCommand()) // Åñëè ïîëó÷èëè êîìàíäó, òîãäà âûïîëíÿåì åå
{
// Òóò ðàñïå÷àòûâàþòñÿ ïîñëàííûå êîìàíäû
#ifdef _DEBUG
if (m_pDumpFile)
{
oTemp.Print(m_pDumpFile);
for (int nIndex = 0; nIndex < nArgumentsCount; nIndex++)
{
::fprintf(m_pDumpFile, " ");
arrArguments[nIndex].Print(m_pDumpFile);
}
::fprintf(m_pDumpFile, "\n");
::fflush(m_pDumpFile);
}
#endif
ExecuteOperator(&oTemp, arrArguments, nArgumentsCount);
oTemp.Free();
for (int nIndex = 0; nIndex < nArgumentsCount; ++nIndex)
arrArguments[nIndex].Free();
nArgumentsCount = 0;
// Ïðîèçâîäèì ïåðåîäè÷åñêèå îáíîâëåíèÿ òîãî ÷òî âûâîäèì
if (++m_nUpdateLevel >= 20000)
{
m_pOut->Dump();
m_nUpdateLevel = 0;
}
// Ïðîâåðÿåì îòìåíó
if (m_pAbortCheckCallBack)
{
if (m_nUpdateLevel - nLastAbortCheck > 10)
{
if ((*m_pAbortCheckCallBack)(m_pAbortCheckData))
{
break;
}
nLastAbortCheck = m_nUpdateLevel;
}
}
}
else if (nArgumentsCount < maxArgs) // Ñ÷èòûâàåì àðãóìåíò
{
arrArguments[nArgumentsCount++] = oTemp;
}
else // Àðãóìåíòîâ ñëèøêîì ìíîãî, çíà÷èò ÷òî-òî íåïðàâèëüíî
{
// TO DO: Error "Too many args in content stream"
#ifdef _DEBUG
if (m_pDumpFile)
{
::fprintf(m_pDumpFile, "throwing away arg: ");
oTemp.Print(m_pDumpFile);
::fprintf(m_pDumpFile, "\n");
::fflush(m_pDumpFile);
}
#endif
oTemp.Free();
}
// Ñ÷èòûâàåì ñëåäóþùèé îáúåêò
m_pParser->GetObject(&oTemp);
}
oTemp.Free();
// args at end with no command
if (nArgumentsCount > 0)
{
// TO DO: Error "Leftover args in content stream"
#ifdef _DEBUG
if (m_pDumpFile)
{
::fprintf(m_pDumpFile, "%d leftovers:", nArgumentsCount);
for (int nIndex = 0; nIndex < nArgumentsCount; ++nIndex)
{
::fprintf(m_pDumpFile, " ");
arrArguments[nIndex].Print(m_pDumpFile);
}
::fprintf(m_pDumpFile, "\n");
::fflush(m_pDumpFile);
}
#endif
for (int nIndex = 0; nIndex < nArgumentsCount; ++nIndex)
arrArguments[nIndex].Free();
}
if (bTopLevel && m_nUpdateLevel > 0)
{
m_pOut->Dump();
}
}
void Graphics::ExecuteOperator(Object *pCommand, Object arrArguments[], int nArgumentsCount)
{
Operator *pOperator = NULL;
// Èùåì îïåðàòîð
char* sName = pCommand->GetCommand();
if (!(pOperator = FindOperator(sName)))
{
if (m_nIgnoreUndef == 0) // Ïðîâåðÿåì íàëè÷èå íåçàêðûòîãî îïåðàòîðà BX
{
// TO DO: Error "Unknown operator"
}
return;
}
// Ïðîâåðÿåì êîëè÷åñòâî àðãóìåíòîâ
Object *pArguments = arrArguments;
if (pOperator->nArgumentsCount >= 0)
{
if (nArgumentsCount < pOperator->nArgumentsCount)
{
// TO DO: Error "Too few args in operator"
return;
}
if (nArgumentsCount > pOperator->nArgumentsCount)
{
// TO DO: Error "Too many args in operator"
// Èñïîëüçóåì ïîñëåäíèå çíà÷åíèÿ â êà÷åñòå àðãóìåíòîâ
pArguments += nArgumentsCount - pOperator->nArgumentsCount;
nArgumentsCount = pOperator->nArgumentsCount;
}
}
else
{
if (nArgumentsCount > -pOperator->nArgumentsCount)
{
// TO DO: Error "Too many args in operator"
return;
}
}
// Ïðîâåðÿåì òèïû àðãóìåíòîâ
for (int nIndex = 0; nIndex < nArgumentsCount; ++nIndex)
{
if (!CheckArgumentType(&pArguments[nIndex], pOperator->arrArguments[nIndex]))
{
// TO DO: Error "Some argument is wrong type"
return;
}
}
// Âûïîëíÿåì ñàì îïåðàòîð
(this->*pOperator->pFunction)(pArguments, nArgumentsCount);
}
Operator *Graphics::FindOperator(char *sName)
{
int nCompareRes = 0;
int nStart = -1;
int nEnd = OperatorsCount;
// OperatorsTable[nStart] < sName < OperatorsTable[nEnd]
while (nEnd - nStart > 1)
{
int nMiddle = (nStart + nEnd) / 2;
nCompareRes = strcmp(OperatorsTable[nMiddle].sName, sName);
if (nCompareRes < 0)
nStart = nMiddle;
else if (nCompareRes > 0)
nEnd = nMiddle;
else
nStart = nEnd = nMiddle;
}
if (nCompareRes != 0)
return NULL;
return &OperatorsTable[nStart];
}
bool Graphics::CheckArgumentType(Object *pArgument, ArgType eType)
{
switch (eType)
{
case argBool: return pArgument->IsBool();
case argInt: return pArgument->IsInt();
case argNum: return pArgument->IsNum();
case argString: return pArgument->IsString();
case argName: return pArgument->IsName();
case argArray: return pArgument->IsArray();
case argProps: return pArgument->IsDict() || pArgument->IsName();
case argSCN: return pArgument->IsNum() || pArgument->IsName();
case argNone: return false;
}
return false;
}
int Graphics::GetPos()
{
return m_pParser ? m_pParser->GetPos() : -1;
}
//-------------------------------------------------------------------------------------------------------------------------------
// Graphics state
//-------------------------------------------------------------------------------------------------------------------------------
// q
void Graphics::OperatorSave(Object arrArguments[], int nArgumentsCount)
{
SaveGState();
}
// Q
void Graphics::OperatorRestore(Object arrArguments[], int nArgumentsCount)
{
RestoreGState();
}
// cm
void Graphics::OperatorConcat(Object arrArguments[], int nArgumentsCount)
{
m_pGState->ConcatCTM(arrArguments[0].GetNum(), arrArguments[1].GetNum(), arrArguments[2].GetNum(), arrArguments[3].GetNum(), arrArguments[4].GetNum(), arrArguments[5].GetNum());
m_pOut->UpdateCTM(m_pGState, arrArguments[0].GetNum(), arrArguments[1].GetNum(), arrArguments[2].GetNum(), arrArguments[3].GetNum(), arrArguments[4].GetNum(), arrArguments[5].GetNum());
m_bFontChanged = true;
}
// d
void Graphics::OperatorSetDash(Object arrArguments[], int nArgumentsCount)
{
double *pDash;
Array *pArray = arrArguments[0].GetArray();
int nCount = pArray->GetCount();
if (0 == nCount)
{
pDash = NULL;
}
else
{
pDash = (double *)MemUtilsMallocArray(nCount, sizeof(double));
for (int nIndex = 0; nIndex < nCount; ++nIndex)
{
Object oTemp;
pDash[nIndex] = pArray->Get(nIndex, &oTemp)->GetNum();
oTemp.Free();
}
}
m_pGState->SetLineDash(pDash, nCount, arrArguments[1].GetNum());
m_pOut->UpdateLineDash(m_pGState);
}
// i
void Graphics::OperatorSetFlat(Object arrArguments[], int nArgumentsCount)
{
m_pGState->SetFlatness((int)arrArguments[0].GetNum());
m_pOut->UpdateFlatness(m_pGState);
}
// j
void Graphics::OperatorSetLineJoin(Object arrArguments[], int nArgumentsCount)
{
m_pGState->SetLineJoin(arrArguments[0].GetInt());
m_pOut->UpdateLineJoin(m_pGState);
}
// J
void Graphics::OperatorSetLineCap(Object arrArguments[], int nArgumentsCount)
{
m_pGState->SetLineCap(arrArguments[0].GetInt());
m_pOut->UpdateLineCap(m_pGState);
}
// M
void Graphics::OperatorSetMiterLimit(Object arrArguments[], int nArgumentsCount)
{
m_pGState->SetMiterLimit(arrArguments[0].GetNum());
m_pOut->UpdateMiterLimit(m_pGState);
}
// w
void Graphics::OperatorSetLineWidth(Object arrArguments[], int nArgumentsCount)
{
m_pGState->SetLineWidth(arrArguments[0].GetNum());
m_pOut->UpdateLineWidth(m_pGState);
}
// ri
void Graphics::OperatorSetRenderingIntent(Object arrArguments[], int nArgumentsCount)
{
}
// gs
void Graphics::OperatorSetExtGState(Object arrArguments[], int nArgumentsCount)
{
Object oDict;
if (!m_pResources->LookupExtGState(arrArguments[0].GetName(), &oDict))
{
return;
}
if (!oDict.IsDict())
{
// TO DO: Error "ExtGState is wrong type"
oDict.Free();
return;
}
// Ïðîçðà÷íîñòü
Object oDictItem;
// BM (blend mode)
if (!oDict.DictLookup("BM", &oDictItem)->IsNull())
{
GraphicsBlendMode eMode;
if (m_pGState->ParseBlendMode(&oDictItem, &eMode))
{
m_pGState->SetBlendMode(eMode);
m_pOut->UpdateBlendMode(m_pGState);
}
else
{
// TO DO: Error "Invalid blend mode in ExtGState"
}
}
oDictItem.Free();
// ca (current alpha for filling)
if (oDict.DictLookup("ca", &oDictItem)->IsNum())
{
m_pGState->SetFillOpacity(oDictItem.GetNum());
m_pOut->UpdateFillOpacity(m_pGState);
}
oDictItem.Free();
// CA (current alpha for stroking)
if (oDict.DictLookup("CA", &oDictItem)->IsNum())
{
m_pGState->SetStrokeOpacity(oDictItem.GetNum());
m_pOut->UpdateStrokeOpacity(m_pGState);
}
oDictItem.Free();
// op (over print for filling)
bool bHaveFillOP;
if ((bHaveFillOP = (oDict.DictLookup("op", &oDictItem)->IsBool())))
{
m_pGState->SetFillOverprint(oDictItem.GetBool());
m_pOut->UpdateFillOverprint(m_pGState);
}
oDictItem.Free();
// OP (over print for stroking)
if (oDict.DictLookup("OP", &oDictItem)->IsBool())
{
m_pGState->SetStrokeOverprint(oDictItem.GetBool());
m_pOut->UpdateStrokeOverprint(m_pGState);
if (!bHaveFillOP)
{
m_pGState->SetFillOverprint(oDictItem.GetBool());
m_pOut->UpdateFillOverprint(m_pGState);
}
}
oDictItem.Free();
// SA (stroke adjustment)
if (oDict.DictLookup("SA", &oDictItem)->IsBool())
{
m_pGState->SetStrokeAdjust(oDictItem.GetBool());
m_pOut->UpdateStrokeAdjust(m_pGState);
}
oDictItem.Free();
// TR2/TR (transfer function)
// ïðèîðèòåòíîé ÿâëÿåòñÿ TR2
Function *ppFunctions[4];
if (oDict.DictLookup("TR2", &oDictItem)->IsNull())
{
oDictItem.Free();
oDict.DictLookup("TR", &oDictItem);
}
if (oDictItem.IsName("Default") || oDictItem.IsName("Identity"))
{
ppFunctions[0] = ppFunctions[1] = ppFunctions[2] = ppFunctions[3] = NULL;
m_pGState->SetTransfer(ppFunctions);
m_pOut->UpdateTransfer(m_pGState);
}
else if (oDictItem.IsArray() && oDictItem.ArrayGetLength() == 4)
{
int nIndex = 0;
for (nIndex = 0; nIndex < 4; ++nIndex)
{
Object oTemp;
oDictItem.ArrayGet(nIndex, &oTemp);
ppFunctions[nIndex] = Function::Parse(&oTemp);
oTemp.Free();
if (!ppFunctions[nIndex])
{
break;
}
}
if (4 == nIndex) // íîðìàëüíî ëè âñå ôóíêöèè ïðî÷èòàëèñü
{
m_pGState->SetTransfer(ppFunctions);
m_pOut->UpdateTransfer(m_pGState);
}
}
else if (oDictItem.IsName() || oDictItem.IsDict() || oDictItem.IsStream())
{
if ((ppFunctions[0] = Function::Parse(&oDictItem)))
{
ppFunctions[1] = ppFunctions[2] = ppFunctions[3] = NULL;
m_pGState->SetTransfer(ppFunctions);
m_pOut->UpdateTransfer(m_pGState);
}
}
else if (!oDictItem.IsNull())
{
// TO DO: Error "Invalid transfer function in ExtGState"
}
oDictItem.Free();
// SMask (soft mask)
if (!oDict.DictLookup("SMask", &oDictItem)->IsNull())
{
if (oDictItem.IsName("None"))
{
m_pOut->ClearSoftMask(m_pGState);
}
else if (oDictItem.IsDict())
{
Object oTemp;
bool bAlpha = false;
if (oDictItem.DictLookup("S", &oTemp)->IsName("Alpha"))
{
bAlpha = true;
}
else // "Luminosity"
{
bAlpha = false;
}
oTemp.Free();
ppFunctions[0] = NULL;
if (!oDictItem.DictLookup("TR", &oTemp)->IsNull())
{
ppFunctions[0] = Function::Parse(&oTemp);
if (ppFunctions[0]->GetInputSize() != 1 || ppFunctions[0]->GetOutputSize() != 1)
{
// TO DO: Error "Invalid transfer function in soft mask in ExtGState"
if (ppFunctions[0])
delete ppFunctions[0];
ppFunctions[0] = NULL;
}
}
oTemp.Free();
bool bHaveBackDropColor = false;
GrColor oBackDropColor;
if ((bHaveBackDropColor = oDictItem.DictLookup("BC", &oTemp)->IsArray()))
{
for (int nIndex = 0; nIndex < GrColorMaxComps; ++nIndex)
{
oBackDropColor.arrComp[nIndex] = 0;
}
for (int nIndex = 0; nIndex < oTemp.ArrayGetLength() && nIndex < GrColorMaxComps; ++nIndex)
{
Object oArrayItem;
oTemp.ArrayGet(nIndex, &oArrayItem);
if (oArrayItem.IsNum())
{
oBackDropColor.arrComp[nIndex] = DoubleToColor(oArrayItem.GetNum());
}
oArrayItem.Free();
}
}
oTemp.Free();
if (oDictItem.DictLookup("G", &oTemp)->IsStream())
{
Object oDict2;
if (oTemp.StreamGetDict()->Search("Group", &oDict2)->IsDict())
{
GrColorSpace *pBlendingColorSpace = NULL;
bool bIsolated = false, bKnockout = false;
Object oTemp2;
if (!oDict2.DictLookup("CS", &oTemp2)->IsNull())
{
pBlendingColorSpace = GrColorSpace::Parse(&oTemp2);
}
oTemp2.Free();
if (oDict2.DictLookup("I", &oTemp2)->IsBool())
{
bIsolated = oTemp2.GetBool();
}
oTemp2.Free();
if (oDict2.DictLookup("K", &oTemp2)->IsBool())
{
bKnockout = oTemp2.GetBool();
}
oTemp2.Free();
if (!bHaveBackDropColor)
{
if (pBlendingColorSpace)
{
pBlendingColorSpace->GetDefaultColor(&oBackDropColor);
}
else
{
for (int nIndex = 0; nIndex < GrColorMaxComps; ++nIndex)
{
oBackDropColor.arrComp[nIndex] = 0;
}
}
}
MakeSoftMask(&oTemp, bAlpha, pBlendingColorSpace, bIsolated, bKnockout, ppFunctions[0], &oBackDropColor);
if (ppFunctions[0])
{
delete ppFunctions[0];
}
}
else
{
// TO DO: Error "Invalid soft mask in ExtGState - missing group"
}
oDict2.Free();
}
else
{
// TO DO: Error "Invalid soft mask in ExtGState - missing group"
}
oTemp.Free();
}
else if (!oDictItem.IsNull())
{
// TO DO: Error "Invalid soft mask in ExtGState"
}
}
oDictItem.Free();
oDict.Free();
}
//-------------------------------------------------------------------------------------------------------------------------------
void Graphics::MakeSoftMask(Object *pStream, bool bAlpha, GrColorSpace *pBlendingColorSpace, bool bIsolated, bool bKnockout, Function *pTransferFunction, GrColor *pBackDropColor)
{
// Ïðîâåðÿåì íà ÷ðåçìåðíóþ ðåêóðñèþ
if (m_nFormDepth > 20)
{
return;
}
Dict *pDict = pStream->StreamGetDict();
// Form type
Object oDictItem;
pDict->Search("FormType", &oDictItem);
if (!(oDictItem.IsNull() || (oDictItem.IsInt() && oDictItem.GetInt() == 1)))
{
// TO DO: Error "Unknown form type"
}
oDictItem.Free();
// BBox
pDict->Search("BBox", &oDictItem);
if (!oDictItem.IsArray())
{
oDictItem.Free();
// TO DO: Error "Bad form bounding box"
return;
}
double arrBBox[4];
for (int nIndex = 0; nIndex < 4; ++nIndex)
{
Object oTemp;
oDictItem.ArrayGet(nIndex, &oTemp);
arrBBox[nIndex] = oTemp.GetNum();
oTemp.Free();
}
oDictItem.Free();
// Matrix
double arrMatrix[6];
pDict->Search("Matrix", &oDictItem);
if (oDictItem.IsArray())
{
for (int nIndex = 0; nIndex < 6; ++nIndex)
{
Object oTemp;
oDictItem.ArrayGet(nIndex, &oTemp);
arrMatrix[nIndex] = oTemp.GetNum();
oTemp.Free();
}
}
else
{
arrMatrix[0] = 1; arrMatrix[1] = 0;
arrMatrix[2] = 0; arrMatrix[3] = 1;
arrMatrix[4] = 0; arrMatrix[5] = 0;
}
oDictItem.Free();
// Resources
pDict->Search("Resources", &oDictItem);
Dict *pResourcesDict = (oDictItem.IsDict() ? oDictItem.GetDict() : (Dict *)NULL);
// Ðèñóåì
++m_nFormDepth;
DoForm(pStream, pResourcesDict, arrMatrix, arrBBox, true, true, pBlendingColorSpace, bIsolated, bKnockout, bAlpha, pTransferFunction, pBackDropColor);
--m_nFormDepth;
if (pBlendingColorSpace)
{
delete pBlendingColorSpace;
}
oDictItem.Free();
}
//-------------------------------------------------------------------------------------------------------------------------------
// Color and Color spaces
//-------------------------------------------------------------------------------------------------------------------------------
// g
void Graphics::OperatorSetFillGray(Object arrArguments[], int nArgumentsCount)
{
GrColor oColor;
m_pGState->SetFillPattern(NULL);
m_pGState->SetFillColorSpace(new GrDeviceGrayColorSpace());
m_pOut->UpdateFillColorSpace(m_pGState);
oColor.arrComp[0] = DoubleToColor(arrArguments[0].GetNum());
m_pGState->SetFillColor(&oColor);
m_pOut->UpdateFillColor(m_pGState);
}
// G
void Graphics::OperatorSetStrokeGray(Object arrArguments[], int nArgumentsCount)
{
GrColor oColor;
m_pGState->SetStrokePattern(NULL);
m_pGState->SetStrokeColorSpace(new GrDeviceGrayColorSpace());
m_pOut->UpdateStrokeColorSpace(m_pGState);
oColor.arrComp[0] = DoubleToColor(arrArguments[0].GetNum());
m_pGState->SetStrokeColor(&oColor);
m_pOut->UpdateStrokeColor(m_pGState);
}
// k
void Graphics::OperatorSetFillCMYKColor(Object arrArguments[], int nArgumentsCount)
{
m_pGState->SetFillPattern(NULL);
m_pGState->SetFillColorSpace(new GrDeviceCMYKColorSpace());
m_pOut->UpdateFillColorSpace(m_pGState);
GrColor oColor;
for (int nIndex = 0; nIndex < 4; ++nIndex)
{
oColor.arrComp[nIndex] = DoubleToColor(arrArguments[nIndex].GetNum());
}
m_pGState->SetFillColor(&oColor);
m_pOut->UpdateFillColor(m_pGState);
}
// K
void Graphics::OperatorSetStrokeCMYKColor(Object arrArguments[], int nArgumentsCount)
{
m_pGState->SetStrokePattern(NULL);
m_pGState->SetStrokeColorSpace(new GrDeviceCMYKColorSpace());
m_pOut->UpdateStrokeColorSpace(m_pGState);
GrColor oColor;
for (int nIndex = 0; nIndex < 4; ++nIndex)
{
oColor.arrComp[nIndex] = DoubleToColor(arrArguments[nIndex].GetNum());
}
m_pGState->SetStrokeColor(&oColor);
m_pOut->UpdateStrokeColor(m_pGState);
}
// rg
void Graphics::OperatorSetFillRGBColor(Object arrArguments[], int nArgumentsCount)
{
m_pGState->SetFillPattern(NULL);
m_pGState->SetFillColorSpace(new GrDeviceRGBColorSpace());
m_pOut->UpdateFillColorSpace(m_pGState);
GrColor oColor;
for (int nIndex = 0; nIndex < 3; ++nIndex)
{
oColor.arrComp[nIndex] = DoubleToColor(arrArguments[nIndex].GetNum());
}
m_pGState->SetFillColor(&oColor);
m_pOut->UpdateFillColor(m_pGState);
}
// RG
void Graphics::OperatorSetStrokeRGBColor(Object arrArguments[], int nArgumentsCount)
{
m_pGState->SetStrokePattern(NULL);
m_pGState->SetStrokeColorSpace(new GrDeviceRGBColorSpace());
m_pOut->UpdateStrokeColorSpace(m_pGState);
GrColor oColor;
for (int nIndex = 0; nIndex < 3; ++nIndex)
{
oColor.arrComp[nIndex] = DoubleToColor(arrArguments[nIndex].GetNum());
}
m_pGState->SetStrokeColor(&oColor);
m_pOut->UpdateStrokeColor(m_pGState);
}
// cs
void Graphics::OperatorSetFillColorSpace(Object arrArguments[], int nArgumentsCount)
{
m_pGState->SetFillPattern(NULL);
Object oTemp;
m_pResources->LookupColorSpace(arrArguments[0].GetName(), &oTemp);
GrColorSpace *pColorSpace = NULL;
if (oTemp.IsNull())
{
pColorSpace = GrColorSpace::Parse(&arrArguments[0]);
}
else
{
pColorSpace = GrColorSpace::Parse(&oTemp);
}
oTemp.Free();
if (pColorSpace)
{
m_pGState->SetFillColorSpace(pColorSpace);
m_pOut->UpdateFillColorSpace(m_pGState);
GrColor oColor;
pColorSpace->GetDefaultColor(&oColor);
m_pGState->SetFillColor(&oColor);
m_pOut->UpdateFillColor(m_pGState);
}
else
{
// TO DO: Error "Bad color space (fill)"
}
}
// CS
void Graphics::OperatorSetStrokeColorSpace(Object arrArguments[], int nArgumentsCount)
{
m_pGState->SetStrokePattern(NULL);
Object oTemp;
m_pResources->LookupColorSpace(arrArguments[0].GetName(), &oTemp);
GrColorSpace *pColorSpace = NULL;
if (oTemp.IsNull())
{
pColorSpace = GrColorSpace::Parse(&arrArguments[0]);
}
else
{
pColorSpace = GrColorSpace::Parse(&oTemp);
}
oTemp.Free();
if (pColorSpace)
{
m_pGState->SetStrokeColorSpace(pColorSpace);
m_pOut->UpdateStrokeColorSpace(m_pGState);
GrColor oColor;
pColorSpace->GetDefaultColor(&oColor);
m_pGState->SetStrokeColor(&oColor);
m_pOut->UpdateStrokeColor(m_pGState);
}
else
{
// TO DO: Error "Bad color space (stroke)"
}
}
// sc
void Graphics::OperatorSetFillColor(Object arrArguments[], int nArgumentsCount)
{
if (nArgumentsCount != m_pGState->GetFillColorSpace()->GetComponentsCount())
{
// TO DO: Error "Incorrect number of arguments in 'sc' command"
return;
}
m_pGState->SetFillPattern(NULL);
GrColor oColor;
for (int nIndex = 0; nIndex < nArgumentsCount; ++nIndex)
{
oColor.arrComp[nIndex] = DoubleToColor(arrArguments[nIndex].GetNum());
}
m_pGState->SetFillColor(&oColor);
m_pOut->UpdateFillColor(m_pGState);
}
// SC
void Graphics::OperatorSetStrokeColor(Object arrArguments[], int nArgumentsCount)
{
if (nArgumentsCount != m_pGState->GetStrokeColorSpace()->GetComponentsCount())
{
// TO DO: Error "Incorrect number of arguments in 'SC' command"
return;
}
m_pGState->SetStrokePattern(NULL);
GrColor oColor;
for (int nIndex = 0; nIndex < nArgumentsCount; ++nIndex)
{
oColor.arrComp[nIndex] = DoubleToColor(arrArguments[nIndex].GetNum());
}
m_pGState->SetStrokeColor(&oColor);
m_pOut->UpdateStrokeColor(m_pGState);
}
// scn
void Graphics::OperatorSetFillColorN(Object arrArguments[], int nArgumentsCount)
{
GrPattern *pPattern = NULL;
GrColor oColor;
if (m_pGState->GetFillColorSpace()->GetMode() == csPattern)
{
if (nArgumentsCount > 1)
{
if (!((GrPatternColorSpace *)m_pGState->GetFillColorSpace())->GetUnder() || nArgumentsCount - 1 != ((GrPatternColorSpace *)m_pGState->GetFillColorSpace())->GetUnder()->GetComponentsCount())
{
// TO DO: Error "Incorrect number of arguments in 'scn' command"
return;
}
for (int nIndex = 0; nIndex < nArgumentsCount - 1 && nIndex < GrColorMaxComps; ++nIndex)
{
if (arrArguments[nIndex].IsNum())
{
oColor.arrComp[nIndex] = DoubleToColor(arrArguments[nIndex].GetNum());
}
}
m_pGState->SetFillColor(&oColor);
m_pOut->UpdateFillColor(m_pGState);
}
if (arrArguments[nArgumentsCount - 1].IsName() && (pPattern = m_pResources->LookupPattern(arrArguments[nArgumentsCount - 1].GetName())))
{
m_pGState->SetFillPattern(pPattern);
}
}
else
{
if (nArgumentsCount != m_pGState->GetFillColorSpace()->GetComponentsCount())
{
// TO DO: Error "Incorrect number of arguments in 'scn' command"
return;
}
m_pGState->SetFillPattern(NULL);
for (int nIndex = 0; nIndex < nArgumentsCount && nIndex < GrColorMaxComps; ++nIndex)
{
if (arrArguments[nIndex].IsNum())
{
oColor.arrComp[nIndex] = DoubleToColor(arrArguments[nIndex].GetNum());
}
}
m_pGState->SetFillColor(&oColor);
m_pOut->UpdateFillColor(m_pGState);
}
}
// SCN
void Graphics::OperatorSetStrokeColorN(Object arrArguments[], int nArgumentsCount)
{
GrPattern *pPattern = NULL;
GrColor oColor;
if (m_pGState->GetStrokeColorSpace()->GetMode() == csPattern)
{
if (nArgumentsCount > 1)
{
if (!((GrPatternColorSpace *)m_pGState->GetStrokeColorSpace())->GetUnder() || nArgumentsCount - 1 != ((GrPatternColorSpace *)m_pGState->GetStrokeColorSpace())->GetUnder()->GetComponentsCount())
{
// TO DO: Error "Incorrect number of arguments in 'SCN' command"
return;
}
for (int nIndex = 0; nIndex < nArgumentsCount - 1 && nIndex < GrColorMaxComps; ++nIndex)
{
if (arrArguments[nIndex].IsNum())
{
oColor.arrComp[nIndex] = DoubleToColor(arrArguments[nIndex].GetNum());
}
}
m_pGState->SetStrokeColor(&oColor);
m_pOut->UpdateStrokeColor(m_pGState);
}
if (arrArguments[nArgumentsCount - 1].IsName() && (pPattern = m_pResources->LookupPattern(arrArguments[nArgumentsCount - 1].GetName())))
{
m_pGState->SetStrokePattern(pPattern);
}
}
else
{
if (nArgumentsCount != m_pGState->GetStrokeColorSpace()->GetComponentsCount())
{
// TO DO: Error "Incorrect number of arguments in 'SCN' command"
return;
}
m_pGState->SetStrokePattern(NULL);
for (int nIndex = 0; nIndex < nArgumentsCount && nIndex < GrColorMaxComps; ++nIndex)
{
if (arrArguments[nIndex].IsNum())
{
oColor.arrComp[nIndex] = DoubleToColor(arrArguments[nIndex].GetNum());
}
}
m_pGState->SetStrokeColor(&oColor);
m_pOut->UpdateStrokeColor(m_pGState);
}
}
//-------------------------------------------------------------------------------------------------------------------------------
// Path construction
//-------------------------------------------------------------------------------------------------------------------------------
// m
void Graphics::OperatorMoveTo(Object arrArguments[], int nArgumentsCount)
{
m_pGState->MoveTo(arrArguments[0].GetNum(), arrArguments[1].GetNum());
}
// l
void Graphics::OperatorLineTo(Object arrArguments[], int nArgumentsCount)
{
if (!m_pGState->IsCurPoint())
{
// TO DO: Error "No current point in lineto"
return;
}
m_pGState->LineTo(arrArguments[0].GetNum(), arrArguments[1].GetNum());
}
// c
void Graphics::OperatorCurveTo(Object arrArguments[], int nArgumentsCount)
{
if (!m_pGState->IsCurPoint())
{
// TO DO: Error "No current point in curveto"
return;
}
m_pGState->CurveTo((double)arrArguments[0].GetNum(), (double)arrArguments[1].GetNum(), (double)arrArguments[2].GetNum(), (double)arrArguments[3].GetNum(), (double)arrArguments[4].GetNum(), (double)arrArguments[5].GetNum());
}
// v
void Graphics::OperatorCurveTo1(Object arrArguments[], int nArgumentsCount)
{
if (!m_pGState->IsCurPoint())
{
// TO DO: Error "No current point in curveto1"
return;
}
m_pGState->CurveTo(m_pGState->GetCurX(), m_pGState->GetCurY(), (double)arrArguments[0].GetNum(), (double)arrArguments[1].GetNum(), (double)arrArguments[2].GetNum(), (double)arrArguments[3].GetNum());
}
// y
void Graphics::OperatorCurveTo2(Object arrArguments[], int nArgumentsCount)
{
if (!m_pGState->IsCurPoint())
{
// TO DO: Error "No current point in curveto2"
return;
}
m_pGState->CurveTo((double)arrArguments[0].GetNum(), (double)arrArguments[1].GetNum(), (double)arrArguments[2].GetNum(), (double)arrArguments[3].GetNum(), (double)arrArguments[2].GetNum(), (double)arrArguments[3].GetNum());
}
// re
void Graphics::OperatorRectangle(Object arrArguments[], int nArgumentsCount)
{
double dX = arrArguments[0].GetNum();
double dY = arrArguments[1].GetNum();
double dWidth = arrArguments[2].GetNum();
double dHeight = arrArguments[3].GetNum();
m_pGState->MoveTo(dX, dY);
m_pGState->LineTo(dX + dWidth, dY);
m_pGState->LineTo(dX + dWidth, dY + dHeight);
m_pGState->LineTo(dX, dY + dHeight);
m_pGState->ClosePath();
}
// h
void Graphics::OperatorClosePath(Object arrArguments[], int nArgumentsCount)
{
if (!m_pGState->IsCurPoint())
{
// TO DO: Error "No current point in closepath"
return;
}
m_pGState->ClosePath();
}
//-------------------------------------------------------------------------------------------------------------------------------
// path painting operators
//-------------------------------------------------------------------------------------------------------------------------------
// n
void Graphics::OperatorEndPath(Object arrArguments[], int nArgumentsCount)
{
DoEndPath();
}
// S
void Graphics::OperatorStroke(Object arrArguments[], int nArgumentsCount)
{
if (!m_pGState->IsCurPoint())
{
// TO DO: Error "No path in stroke"
return;
}
if (m_pGState->IsPathNonEmpty())
{
if (m_pGState->GetStrokeColorSpace()->GetMode() == csPattern)
{
DoPatternStroke();
}
else
{
m_pOut->Stroke(m_pGState);
}
}
DoEndPath();
}
// s
void Graphics::OperatorCloseStroke(Object arrArguments[], int nArgumentsCount)
{
if (!m_pGState->IsCurPoint())
{
// TO DO: Error "No path in closepath/stroke"
return;
}
if (m_pGState->IsPathNonEmpty())
{
m_pGState->ClosePath();
if (m_pGState->GetStrokeColorSpace()->GetMode() == csPattern)
{
DoPatternStroke();
}
else
{
m_pOut->Stroke(m_pGState);
}
}
DoEndPath();
}
// f/F
void Graphics::OperatorFill(Object arrArguments[], int nArgumentsCount)
{
if (!m_pGState->IsCurPoint())
{
// TO DO: Error "No path in fill"
return;
}
if (m_pGState->IsPathNonEmpty())
{
if (m_pGState->GetFillColorSpace()->GetMode() == csPattern)
{
DoPatternFill(false);
}
else
{
m_pOut->Fill(m_pGState);
}
}
DoEndPath();
}
// f*
void Graphics::OperatorEOFill(Object arrArguments[], int nArgumentsCount)
{
if (!m_pGState->IsCurPoint())
{
// TO DO: Error "No path in eofill"
return;
}
if (m_pGState->IsPathNonEmpty())
{
if (m_pGState->GetFillColorSpace()->GetMode() == csPattern)
{
DoPatternFill(true);
}
else
{
m_pOut->EoFill(m_pGState);
}
}
DoEndPath();
}
// B
void Graphics::OperatorFillStroke(Object arrArguments[], int nArgumentsCount)
{
if (!m_pGState->IsCurPoint())
{
// TO DO: Error "No path in fill/stroke"
return;
}
if (m_pGState->IsPathNonEmpty())
{
if (!(m_pGState->GetFillColorSpace()->GetMode() == csPattern) && !(m_pGState->GetStrokeColorSpace()->GetMode() == csPattern) && m_pOut->UseFillAndStroke())
{
m_pOut->FillStroke(m_pGState);
}
else
{
if (m_pGState->GetFillColorSpace()->GetMode() == csPattern)
{
DoPatternFill(false);
}
else
{
m_pOut->Fill(m_pGState);
}
if (m_pGState->GetStrokeColorSpace()->GetMode() == csPattern)
{
DoPatternStroke();
}
else
{
m_pOut->Stroke(m_pGState);
}
}
}
DoEndPath();
}
// b
void Graphics::OperatorCloseFillStroke(Object arrArguments[], int nArgumentsCount)
{
if (!m_pGState->IsCurPoint())
{
// TO DO: Error "No path in closepath/fill/stroke"
return;
}
if (m_pGState->IsPathNonEmpty())
{
m_pGState->ClosePath();
if (!(m_pGState->GetFillColorSpace()->GetMode() == csPattern) && !(m_pGState->GetStrokeColorSpace()->GetMode() == csPattern) && m_pOut->UseFillAndStroke())
{
m_pOut->FillStroke(m_pGState);
}
else
{
if (m_pGState->GetFillColorSpace()->GetMode() == csPattern)
{
DoPatternFill(false);
}
else
{
m_pOut->Fill(m_pGState);
}
if (m_pGState->GetStrokeColorSpace()->GetMode() == csPattern)
{
DoPatternStroke();
}
else
{
m_pOut->Stroke(m_pGState);
}
}
}
DoEndPath();
}
// B*
void Graphics::OperatorEOFillStroke(Object arrArguments[], int nArgumentsCount)
{
if (!m_pGState->IsCurPoint())
{
// TO DO: Error "No path in eofill/stroke"
return;
}
if (m_pGState->IsPathNonEmpty())
{
if (!(m_pGState->GetFillColorSpace()->GetMode() == csPattern) && !(m_pGState->GetStrokeColorSpace()->GetMode() == csPattern) && m_pOut->UseFillAndStroke())
{
m_pOut->EoFillStroke(m_pGState);
}
else
{
if (m_pGState->GetFillColorSpace()->GetMode() == csPattern)
{
DoPatternFill(true);
}
else
{
m_pOut->EoFill(m_pGState);
}
if (m_pGState->GetStrokeColorSpace()->GetMode() == csPattern)
{
DoPatternStroke();
}
else
{
m_pOut->Stroke(m_pGState);
}
}
}
DoEndPath();
}
// b*
void Graphics::OperatorCloseEOFillStroke(Object arrArguments[], int nArgumentsCount)
{
if (!m_pGState->IsCurPoint())
{
// TO DO: Error "No path in closepath/eofill/stroke"
return;
}
if (m_pGState->IsPathNonEmpty())
{
m_pGState->ClosePath();
if (!(m_pGState->GetFillColorSpace()->GetMode() == csPattern) && !(m_pGState->GetStrokeColorSpace()->GetMode() == csPattern) && m_pOut->UseFillAndStroke())
{
m_pOut->EoFillStroke(m_pGState);
}
else
{
if (m_pGState->GetFillColorSpace()->GetMode() == csPattern)
{
DoPatternFill(true);
}
else
{
m_pOut->EoFill(m_pGState);
}
if (m_pGState->GetStrokeColorSpace()->GetMode() == csPattern)
{
DoPatternStroke();
}
else
{
m_pOut->Stroke(m_pGState);
}
}
}
DoEndPath();
}
// sh
void Graphics::OperatorShadingFill(Object arrArguments[], int nArgumentsCount)
{
GrShading *pShading = NULL;
if (!(pShading = m_pResources->LookupShading(arrArguments[0].GetName())))
{
return;
}
// Ñîõðàíÿåì òåêóùèé GState
GrPath *pSavedPath = m_pGState->GetPath()->Copy();
SaveGState();
if (pShading->GetHasBBox())
{
double dXMin, dYMin, dXMax, dYMax;
pShading->GetBBox(&dXMin, &dYMin, &dXMax, &dYMax);
m_pGState->MoveTo(dXMin, dYMin);
m_pGState->LineTo(dXMax, dYMin);
m_pGState->LineTo(dXMax, dYMax);
m_pGState->LineTo(dXMin, dYMax);
m_pGState->ClosePath();
m_pGState->Clip();
m_pGState->GetClip()->ClipToPath(m_pGState->GetPath()->Copy(), m_pGState->GetCTM(), false);
if (m_pOut->UseClipTo())
m_pOut->ClipToPath(m_pGState, m_pGState->GetPath(), m_pGState->GetCTM(), false);
else
m_pOut->Clip(m_pGState);
m_pGState->ClearPath();
}
// Óñòàíàâëèâàåì öâåòîâîå ïðîñòðàíñòâî
m_pGState->SetFillColorSpace(pShading->GetColorSpace()->Copy());
m_pOut->UpdateFillColorSpace(m_pGState);
bool bAntialias = m_pOut->GetVectorAntialias();
if (bAntialias)
{
m_pOut->SetVectorAntialias(false);
}
m_pOut->StartShadedFill(m_pGState);
// Âûïîëíÿåì çàêðàñêó, â çàâèñèìîñòè îò òèïà Shading
switch (pShading->GetType())
{
case 1:
DoFunctionShadingFill((GrFunctionShading *)pShading);
break;
case 2:
DoAxialShadingFill((GrAxialShading *)pShading);
break;
case 3:
DoRadialShadingFill((GrRadialShading *)pShading);
break;
case 4:
case 5:
DoGouraudTriangleShadingFill((GrGouraudTriangleShading *)pShading);
break;
case 6:
case 7:
DoPatchMeshShadingFill((GrPatchMeshShading *)pShading);
break;
}
m_pOut->EndShadedFill();
if (bAntialias)
{
m_pOut->SetVectorAntialias(true);
}
// Âîññòàíàâëèâàåì GState
RestoreGState();
m_pGState->SetPath(pSavedPath);
delete pShading;
}
//-------------------------------------------------------------------------------------------------------------------------------
void Graphics::DoPatternFill(bool bEOFill)
{
// Ïðîïóñêàåì îáúåêò Patterns, åñëè ìû âûâîäèì òîëüêî òåêñò èç PDF
if (!m_pOut->NeedNonText())
{
return;
}
GrPattern *pPattern = NULL;
if (!(pPattern = m_pGState->GetFillPattern()))
{
return;
}
switch (pPattern->GetType())
{
case 1:
DoTilingPatternFill((GrTilingPattern *)pPattern, false, bEOFill);
break;
case 2:
DoShadingPatternFill((GrShadingPattern *)pPattern, false, bEOFill);
break;
default:
// TO DO: Error "Unimplemented pattern type in fill"
break;
}
}
void Graphics::DoPatternStroke()
{
// Ïðîïóñêàåì îáúåêò Patterns, åñëè ìû âûâîäèì òîëüêî òåêñò èç PDF
if (!m_pOut->NeedNonText())
{
return;
}
GrPattern *pPattern = NULL;
if (!(pPattern = m_pGState->GetStrokePattern()))
{
return;
}
switch (pPattern->GetType())
{
case 1:
DoTilingPatternFill((GrTilingPattern *)pPattern, true, false);
break;
case 2:
DoShadingPatternFill((GrShadingPattern *)pPattern, true, false);
break;
default:
// TO DO: Error "Unimplemented pattern type in stroke"
break;
}
}
void Graphics::DoTilingPatternFill(GrTilingPattern *pPattern, bool bStroke, bool bEOFill)
{
// Color space
GrPatternColorSpace *pPatternCS = (GrPatternColorSpace *)(bStroke ? m_pGState->GetStrokeColorSpace() : m_pGState->GetFillColorSpace());
// Ñòðîèì ìàòðèöó ïðåîáðàçîâàíèÿ (Pattern space) -> (Current space)
double *pCTM = m_pGState->GetCTM();
double *pBaseMatrix = m_arrBaseMatrix;
double *pTilingMatrix = pPattern->GetMatrix();
double dDet = 1 / (pCTM[0] * pCTM[3] - pCTM[1] * pCTM[2]);
// InvCTM = (CTM)^(-1)
double pInvCTM[6];
pInvCTM[0] = pCTM[3] * dDet;
pInvCTM[1] = -pCTM[1] * dDet;
pInvCTM[2] = -pCTM[2] * dDet;
pInvCTM[3] = pCTM[0] * dDet;
pInvCTM[4] = (pCTM[2] * pCTM[5] - pCTM[3] * pCTM[4]) * dDet;
pInvCTM[5] = (pCTM[1] * pCTM[4] - pCTM[0] * pCTM[5]) * dDet;
// TempMatrix = TilingMatrix * BaseMatrix
double pTempMatrix[6];
pTempMatrix[0] = pTilingMatrix[0] * pBaseMatrix[0] + pTilingMatrix[1] * pBaseMatrix[2];
pTempMatrix[1] = pTilingMatrix[0] * pBaseMatrix[1] + pTilingMatrix[1] * pBaseMatrix[3];
pTempMatrix[2] = pTilingMatrix[2] * pBaseMatrix[0] + pTilingMatrix[3] * pBaseMatrix[2];
pTempMatrix[3] = pTilingMatrix[2] * pBaseMatrix[1] + pTilingMatrix[3] * pBaseMatrix[3];
pTempMatrix[4] = pTilingMatrix[4] * pBaseMatrix[0] + pTilingMatrix[5] * pBaseMatrix[2] + pBaseMatrix[4];
pTempMatrix[5] = pTilingMatrix[4] * pBaseMatrix[1] + pTilingMatrix[5] * pBaseMatrix[3] + pBaseMatrix[5];
// Matrix = TempMatrix * InvCTM
double pMatrix[6];
pMatrix[0] = pTempMatrix[0] * pInvCTM[0] + pTempMatrix[1] * pInvCTM[2];
pMatrix[1] = pTempMatrix[0] * pInvCTM[1] + pTempMatrix[1] * pInvCTM[3];
pMatrix[2] = pTempMatrix[2] * pInvCTM[0] + pTempMatrix[3] * pInvCTM[2];
pMatrix[3] = pTempMatrix[2] * pInvCTM[1] + pTempMatrix[3] * pInvCTM[3];
pMatrix[4] = pTempMatrix[4] * pInvCTM[0] + pTempMatrix[5] * pInvCTM[2] + pInvCTM[4];
pMatrix[5] = pTempMatrix[4] * pInvCTM[1] + pTempMatrix[5] * pInvCTM[3] + pInvCTM[5];
// Ñòðîèì ìàòðèöó ïðåîáðàçîâàíèÿ (Device space) -> (Pattern space)
double pInvTemp[6];
dDet = 1 / (pTempMatrix[0] * pTempMatrix[3] - pTempMatrix[1] * pTempMatrix[2]);
pInvTemp[0] = pTempMatrix[3] * dDet;
pInvTemp[1] = -pTempMatrix[1] * dDet;
pInvTemp[2] = -pTempMatrix[2] * dDet;
pInvTemp[3] = pTempMatrix[0] * dDet;
pInvTemp[4] = (pTempMatrix[2] * pTempMatrix[5] - pTempMatrix[3] * pTempMatrix[4]) * dDet;
pInvTemp[5] = (pTempMatrix[1] * pTempMatrix[4] - pTempMatrix[0] * pTempMatrix[5]) * dDet;
// Ñîõðàíÿåì òåêóùèé GState
GrPath *pSavedPath = m_pGState->GetPath()->Copy();
SaveGState();
// Óñòàíàâëèâàåì öâåòîâîå ïðîñòðàíñòâî äëÿ ïîäêëàäêè (äëÿ íå öâåòîâûõ Tiling patterns);
// Óñòàíàâëèâàåì ðàçëèíûå ïàðàìåòðû (öâåò îáâîäêè, òîëùèíà ëèíèè)
GrColorSpace *pColorSpace = NULL;
if (pPattern->GetPaintType() == 2 && (pColorSpace = pPatternCS->GetUnder()))
{
m_pGState->SetFillColorSpace(pColorSpace->Copy());
m_pOut->UpdateFillColorSpace(m_pGState);
m_pGState->SetStrokeColorSpace(pColorSpace->Copy());
m_pOut->UpdateStrokeColorSpace(m_pGState);
m_pGState->SetStrokeColor(m_pGState->GetFillColor());
}
else
{
m_pGState->SetFillColorSpace(new GrDeviceGrayColorSpace());
m_pOut->UpdateFillColorSpace(m_pGState);
m_pGState->SetStrokeColorSpace(new GrDeviceGrayColorSpace());
m_pOut->UpdateStrokeColorSpace(m_pGState);
}
m_pGState->SetFillPattern(NULL);
m_pOut->UpdateFillColor(m_pGState);
m_pGState->SetStrokePattern(NULL);
m_pOut->UpdateStrokeColor(m_pGState);
if (!bStroke)
{
m_pGState->SetLineWidth(0);
m_pOut->UpdateLineWidth(m_pGState);
}
if (bStroke)
{
m_pGState->ClipToStrokePath();
m_pGState->GetClip()->ClipToPath(m_pGState->GetPath()->Copy(), m_pGState->GetCTM(), false);
if (m_pOut->UseClipTo())
m_pOut->ClipToPath(m_pGState, m_pGState->GetPath(), m_pGState->GetCTM(), false);
else
m_pOut->ClipToStrokePath(m_pGState);
}
else
{
m_pGState->Clip();
if (bEOFill)
{
m_pGState->GetClip()->ClipToPath(m_pGState->GetPath()->Copy(), m_pGState->GetCTM(), true);
if (m_pOut->UseClipTo())
m_pOut->ClipToPath(m_pGState, m_pGState->GetPath(), m_pGState->GetCTM(), true);
else
m_pOut->EoClip(m_pGState);
}
else
{
m_pGState->GetClip()->ClipToPath(m_pGState->GetPath()->Copy(), m_pGState->GetCTM(), false);
if (m_pOut->UseClipTo())
m_pOut->ClipToPath(m_pGState, m_pGState->GetPath(), m_pGState->GetCTM(), false);
else
m_pOut->Clip(m_pGState);
}
}
m_pGState->ClearPath();
double dClipXMin, dClipYMin, dClipXMax, dClipYMax;
m_pGState->GetClipBBox(&dClipXMin, &dClipYMin, &dClipXMax, &dClipYMax);
if (dClipXMin > dClipXMax || dClipYMin > dClipYMax)
{
RestoreGState();
m_pGState->SetPath(pSavedPath);
return;
}
double dXMin, dYMin, dXMax, dYMax;
dXMin = dXMax = dClipXMin * pInvTemp[0] + dClipYMin * pInvTemp[2] + pInvTemp[4];
dYMin = dYMax = dClipXMin * pInvTemp[1] + dClipYMin * pInvTemp[3] + pInvTemp[5];
double dTempX = dClipXMin * pInvTemp[0] + dClipYMax * pInvTemp[2] + pInvTemp[4];
double dTempY = dClipXMin * pInvTemp[1] + dClipYMax * pInvTemp[3] + pInvTemp[5];
if (dTempX < dXMin)
{
dXMin = dTempX;
}
else if (dTempX > dXMax)
{
dXMax = dTempX;
}
if (dTempY < dYMin)
{
dYMin = dTempY;
}
else if (dTempY > dYMax)
{
dYMax = dTempY;
}
dTempX = dClipXMax * pInvTemp[0] + dClipYMin * pInvTemp[2] + pInvTemp[4];
dTempY = dClipXMax * pInvTemp[1] + dClipYMin * pInvTemp[3] + pInvTemp[5];
if (dTempX < dXMin)
{
dXMin = dTempX;
}
else if (dTempX > dXMax)
{
dXMax = dTempX;
}
if (dTempY < dYMin)
{
dYMin = dTempY;
}
else if (dTempY > dYMax)
{
dYMax = dTempY;
}
dTempX = dClipXMax * pInvTemp[0] + dClipYMax * pInvTemp[2] + pInvTemp[4];
dTempY = dClipXMax * pInvTemp[1] + dClipYMax * pInvTemp[3] + pInvTemp[5];
if (dTempX < dXMin)
{
dXMin = dTempX;
}
else if (dTempX > dXMax)
{
dXMax = dTempX;
}
if (dTempY < dYMin)
{
dYMin = dTempY;
}
else if (dTempY > dYMax)
{
dYMax = dTempY;
}
double dStepX = fabs(pPattern->GetXStep());
double dStepY = fabs(pPattern->GetYStep());
int nX0 = (int)ceil((dXMin - pPattern->GetBBox()[2]) / dStepX);
int nX1 = (int)floor((dXMax - pPattern->GetBBox()[0]) / dStepX) + 1;
int nY0 = (int)ceil((dYMin - pPattern->GetBBox()[3]) / dStepY);
int nY1 = (int)floor((dYMax - pPattern->GetBBox()[1]) / dStepY) + 1;
for (int nIndex = 0; nIndex < 4; ++nIndex)
{
pTempMatrix[nIndex] = pMatrix[nIndex];
}
m_pOut->StartTilingFill(m_pGState);
if (m_pOut->UseTilingPatternFill())
{
pTempMatrix[4] = pMatrix[4];
pTempMatrix[5] = pMatrix[5];
m_pOut->TilingPatternFill(m_pGState, pPattern->GetContentStream(), pPattern->GetPaintType(), pPattern->GetResourcesDict(), pTempMatrix, pPattern->GetBBox(), nX0, nY0, nX1, nY1, dStepX, dStepY);
}
else
{
if (m_pOut->UseSimpleTilingPatternFill())
{
m_pOut->StartSimpleTilingFill(m_pGState, nX0, nY0, nX1, nY1, dStepX, dStepY, dXMin, dYMin, dXMax, dYMax, pTempMatrix);
for (int nY = nY0; nY < nY1; ++nY)
{
for (int nX = nX0; nX < nX1; ++nX)
{
double dX = nX * dStepX;
double dY = nY * dStepY;
pTempMatrix[4] = dX * pMatrix[0] + dY * pMatrix[2] + pMatrix[4];
pTempMatrix[5] = dX * pMatrix[1] + dY * pMatrix[3] + pMatrix[5];
DoForm(pPattern->GetContentStream(), pPattern->GetResourcesDict(), pTempMatrix, pPattern->GetBBox());
}
}
m_pOut->EndSimpleTilingFill();
}
else
{
for (int nY = nY0; nY < nY1; ++nY)
{
for (int nX = nX0; nX < nX1; ++nX)
{
if (m_pOut->IsStopped())
{
// Âîññòàíàâëèâàåì GState
RestoreGState();
m_pGState->SetPath(pSavedPath);
return;
}
m_pOut->StartTilingFillIteration();
double dX = nX * dStepX;
double dY = nY * dStepY;
pTempMatrix[4] = dX * pMatrix[0] + dY * pMatrix[2] + pMatrix[4];
pTempMatrix[5] = dX * pMatrix[1] + dY * pMatrix[3] + pMatrix[5];
DoForm(pPattern->GetContentStream(), pPattern->GetResourcesDict(), pTempMatrix, pPattern->GetBBox());
m_pOut->EndTilingFillIteration();
}
}
}
}
m_pOut->EndTilingFill();
// Âîññòàíàâëèâàåì GState
RestoreGState();
m_pGState->SetPath(pSavedPath);
}
void Graphics::DoShadingPatternFill(GrShadingPattern *pPattern, bool bStroke, bool bEOFill)
{
GrShading *pShading = pPattern->GetShading();
// Ñîõðàíÿåì òåêóùèé GState
GrPath *pSavedPath = m_pGState->GetPath()->Copy();
SaveGState();
if (pShading->GetHasBBox())
{
double dXMin, dYMin, dXMax, dYMax;
pShading->GetBBox(&dXMin, &dYMin, &dXMax, &dYMax);
m_pGState->MoveTo(dXMin, dYMin);
m_pGState->LineTo(dXMax, dYMin);
m_pGState->LineTo(dXMax, dYMax);
m_pGState->LineTo(dXMin, dYMax);
m_pGState->ClosePath();
m_pGState->Clip();
m_pGState->GetClip()->ClipToPath(m_pGState->GetPath()->Copy(), m_pGState->GetCTM(), false);
if (m_pOut->UseClipTo())
m_pOut->ClipToPath(m_pGState, m_pGState->GetPath(), m_pGState->GetCTM(), false);
else
m_pOut->Clip(m_pGState);
m_pGState->SetPath(pSavedPath->Copy());
}
if (bStroke)
{
m_pGState->ClipToStrokePath();
m_pGState->GetClip()->ClipToPath(m_pGState->GetPath()->Copy(), m_pGState->GetCTM(), false);
if (m_pOut->UseClipTo())
m_pOut->ClipToPath(m_pGState, m_pGState->GetPath(), m_pGState->GetCTM(), false);
else
m_pOut->ClipToStrokePath(m_pGState);
}
else
{
m_pGState->Clip();
if (bEOFill)
{
m_pGState->GetClip()->ClipToPath(m_pGState->GetPath()->Copy(), m_pGState->GetCTM(), true);
if (m_pOut->UseClipTo())
m_pOut->ClipToPath(m_pGState, m_pGState->GetPath(), m_pGState->GetCTM(), true);
else
m_pOut->EoClip(m_pGState);
}
else
{
m_pGState->GetClip()->ClipToPath(m_pGState->GetPath()->Copy(), m_pGState->GetCTM(), false);
if (m_pOut->UseClipTo())
m_pOut->ClipToPath(m_pGState, m_pGState->GetPath(), m_pGState->GetCTM(), false);
else
m_pOut->Clip(m_pGState);
}
}
// Óñòàíàâëèâàåì öâåòîâîå ïðîñòðàíñòâî
m_pGState->SetFillColorSpace(pShading->GetColorSpace()->Copy());
m_pOut->UpdateFillColorSpace(m_pGState);
// Çàäíèé ôîí
if (pShading->GetHasBackground())
{
m_pGState->SetFillColor(pShading->GetBackground());
m_pOut->UpdateFillColor(m_pGState);
m_pOut->Fill(m_pGState);
}
m_pGState->ClearPath();
// Ñòðîèì ìàòðèöó ïðåîáðàçîâàíèÿ (Pattern space) -> (Current space)
double *pCTM = m_pGState->GetCTM();
double *pBaseMatrix = m_arrBaseMatrix;
double *pPatternMatrix = pPattern->GetMatrix();
// InvCTM = (CTM)^(-1)
double pInvCTM[6];
double dDet = 1 / (pCTM[0] * pCTM[3] - pCTM[1] * pCTM[2]);
pInvCTM[0] = pCTM[3] * dDet;
pInvCTM[1] = -pCTM[1] * dDet;
pInvCTM[2] = -pCTM[2] * dDet;
pInvCTM[3] = pCTM[0] * dDet;
pInvCTM[4] = (pCTM[2] * pCTM[5] - pCTM[3] * pCTM[4]) * dDet;
pInvCTM[5] = (pCTM[1] * pCTM[4] - pCTM[0] * pCTM[5]) * dDet;
// TempMatrix = PatternMatrix * BaseMatrix
double pTempMatrix[6];
pTempMatrix[0] = pPatternMatrix[0] * pBaseMatrix[0] + pPatternMatrix[1] * pBaseMatrix[2];
pTempMatrix[1] = pPatternMatrix[0] * pBaseMatrix[1] + pPatternMatrix[1] * pBaseMatrix[3];
pTempMatrix[2] = pPatternMatrix[2] * pBaseMatrix[0] + pPatternMatrix[3] * pBaseMatrix[2];
pTempMatrix[3] = pPatternMatrix[2] * pBaseMatrix[1] + pPatternMatrix[3] * pBaseMatrix[3];
pTempMatrix[4] = pPatternMatrix[4] * pBaseMatrix[0] + pPatternMatrix[5] * pBaseMatrix[2] + pBaseMatrix[4];
pTempMatrix[5] = pPatternMatrix[4] * pBaseMatrix[1] + pPatternMatrix[5] * pBaseMatrix[3] + pBaseMatrix[5];
// Matrix = TempMatrix * InvCTM
double pMatrix[6];
pMatrix[0] = pTempMatrix[0] * pInvCTM[0] + pTempMatrix[1] * pInvCTM[2];
pMatrix[1] = pTempMatrix[0] * pInvCTM[1] + pTempMatrix[1] * pInvCTM[3];
pMatrix[2] = pTempMatrix[2] * pInvCTM[0] + pTempMatrix[3] * pInvCTM[2];
pMatrix[3] = pTempMatrix[2] * pInvCTM[1] + pTempMatrix[3] * pInvCTM[3];
pMatrix[4] = pTempMatrix[4] * pInvCTM[0] + pTempMatrix[5] * pInvCTM[2] + pInvCTM[4];
pMatrix[5] = pTempMatrix[4] * pInvCTM[1] + pTempMatrix[5] * pInvCTM[3] + pInvCTM[5];
// Óñòàíàâëèâàåì íîâóþ ìàòðèöó
m_pGState->ConcatCTM(pMatrix[0], pMatrix[1], pMatrix[2], pMatrix[3], pMatrix[4], pMatrix[5]);
m_pOut->UpdateCTM(m_pGState, pMatrix[0], pMatrix[1], pMatrix[2], pMatrix[3], pMatrix[4], pMatrix[5]);
bool bAntialias = m_pOut->GetVectorAntialias();
if (bAntialias)
{
m_pOut->SetVectorAntialias(false);
}
m_pOut->StartShadedFill(m_pGState);
// Âûïîëíÿåì çàêðàñêó, â çàâèñèìîñòè îò òèïà Shading
switch (pShading->GetType())
{
case 1:
DoFunctionShadingFill((GrFunctionShading *)pShading);
break;
case 2:
DoAxialShadingFill((GrAxialShading *)pShading);
break;
case 3:
DoRadialShadingFill((GrRadialShading *)pShading);
break;
case 4:
case 5:
DoGouraudTriangleShadingFill((GrGouraudTriangleShading *)pShading);
break;
case 6:
case 7:
DoPatchMeshShadingFill((GrPatchMeshShading *)pShading);
break;
}
m_pOut->EndShadedFill();
if (bAntialias)
{
m_pOut->SetVectorAntialias(true);
}
// Âîññòàíàâëèâàåì GState
RestoreGState();
m_pGState->SetPath(pSavedPath);
}
void Graphics::DoFunctionShadingFill(GrFunctionShading *pShading)
{
// Ñíà÷àëà ïðåäîñòàâëÿåì âîçìîæíîñòü OuputDevice ñàìîìó ñäåëàòü Shading
if (m_pOut->UseFunctionalShadedFills() && m_pOut->FunctionShadedFill(m_pGState, pShading))
{
return;
}
// Åñëè Output Device íå ïîääåðæèâàåò äàííûé ShadingType, òîãäà äåëàåì åãî ñàìè
// ñ ïîìîùüþ GrPath.
double dMinX, dMinY, dMaxX, dMaxY;
GrColor arrColors[4];
pShading->GetDomain(&dMinX, &dMinY, &dMaxX, &dMaxY);
pShading->GetColor(dMinX, dMinY, &arrColors[0]);
pShading->GetColor(dMinX, dMaxY, &arrColors[1]);
pShading->GetColor(dMaxX, dMinY, &arrColors[2]);
pShading->GetColor(dMaxX, dMaxY, &arrColors[3]);
DoFunctionShadingFill(pShading, dMinX, dMinY, dMaxX, dMaxY, arrColors, 0);
}
void Graphics::DoFunctionShadingFill(GrFunctionShading *pShading, double dMinX, double dMinY, double dMaxX, double dMaxY, GrColor *pColors, int nDepth)
{
if (m_pOut->IsStopped())
return;
int nComponentsCount = pShading->GetColorSpace()->GetComponentsCount();
// Ñðàâíèâàåì öâåòà â óãëàõ
int nColorIndex = 0;
for (nColorIndex = 0; nColorIndex < 4; ++nColorIndex)
{
int nComponentIndex;
for (nComponentIndex = 0; nComponentIndex < nComponentsCount; ++nComponentIndex)
{
if (abs(pColors[nColorIndex].arrComp[nComponentIndex] - pColors[(nColorIndex + 1) & 3].arrComp[nComponentIndex]) > functionColorDelta)
{
break;
}
}
if (nComponentIndex < nComponentsCount)
{
break;
}
}
double dCenterX = 0.5 * (dMinX + dMaxX);
double dCenterY = 0.5 * (dMinY + dMaxY);
// Óãëîâûå âåðøèíû ïðÿìîóãîëüíèêîâ äîñòàòî÷íî áëèçêè (èëè ìû äîñòèãëè ïðåäåëà êîëè÷åòñâó èòòåðàöèé)
// Çàëèâàåì ïðÿìîóãîëüíèê. Äàæå åñëè èçíà÷àëüíî âåðøèíû áëèçêè ïðîâîäèì îäíó èòòåðàöèþ äåëåíèÿ, ÷òîáû
// ñëó÷àÿ, êîãäà âñå 4 âåðøèíû èìåþò îäèíàêîâûé öâåò.
if ((nColorIndex == 4 && nDepth > 0) || nDepth == functionMaxDepth)
{
// Èñïîëüçóåì öâåò öåíòðà ïðÿìîóãîëüíèêà
GrColor oFillColor;
pShading->GetColor(dCenterX, dCenterY, &oFillColor);
m_pGState->SetFillColor(&oFillColor);
m_pOut->UpdateFillColor(m_pGState);
double *pMatrix = pShading->GetMatrix();
// Çàëèâêà ïðÿìîóãîëüíèêà
m_pGState->MoveTo(dMinX * pMatrix[0] + dMinY * pMatrix[2] + pMatrix[4], dMinX * pMatrix[1] + dMinY * pMatrix[3] + pMatrix[5]);
m_pGState->LineTo(dMaxX * pMatrix[0] + dMinY * pMatrix[2] + pMatrix[4], dMaxX * pMatrix[1] + dMinY * pMatrix[3] + pMatrix[5]);
m_pGState->LineTo(dMaxX * pMatrix[0] + dMaxY * pMatrix[2] + pMatrix[4], dMaxX * pMatrix[1] + dMaxY * pMatrix[3] + pMatrix[5]);
m_pGState->LineTo(dMinX * pMatrix[0] + dMaxY * pMatrix[2] + pMatrix[4], dMinX * pMatrix[1] + dMaxY * pMatrix[3] + pMatrix[5]);
m_pGState->ClosePath();
m_pOut->Fill(m_pGState);
m_pGState->ClearPath();
}
else // 4 óãëîâûå âåðøèíû íå äîñòàòî÷íî áëèçêè, äåëèì äàëüøå íà ïðÿìîóãîëüíèêè
{
// pColors[0] oColorCT pColors[2]
// (dMinX,dMinY) (dCenterX,dMinY) (dMaxX,dMinY)
// +---------------------+---------------------+
// | | |
// | Top Left | Top Right |
// oColorLC | oColorCC| | oColorRC
// +---------------------+---------------------+
// (dMinX,dCenterY) (dCenterX,dCenterY) (dMaxX,dCenterY)
// | Bottom Left | Bottom Right |
// | | |
// +---------------------+---------------------+
// (dMinX,dMaxY) (dCenterX,dMaxY) (dMaxX,dMaxY)
// pColors[1] oColorCB pColors[3]
GrColor oColorLC, oColorRC, oColorCT, oColorCB, oColorCC, arrSubColors[4];
pShading->GetColor(dMinX, dCenterY, &oColorLC);
pShading->GetColor(dMaxX, dCenterY, &oColorRC);
pShading->GetColor(dCenterX, dMinY, &oColorCT);
pShading->GetColor(dCenterX, dMaxY, &oColorCB);
pShading->GetColor(dCenterX, dCenterY, &oColorCC);
// Âåðõíèé ëåâûé ïðÿìîóãîëüíèê
arrSubColors[0] = pColors[0];
arrSubColors[1] = oColorLC;
arrSubColors[2] = oColorCT;
arrSubColors[3] = oColorCC;
DoFunctionShadingFill(pShading, dMinX, dMinY, dCenterX, dCenterY, arrSubColors, nDepth + 1);
// Ëåâûé íèæíèé ïðÿìîóãîëüíèê
arrSubColors[0] = oColorLC;
arrSubColors[1] = pColors[1];
arrSubColors[2] = oColorCC;
arrSubColors[3] = oColorCB;
DoFunctionShadingFill(pShading, dMinX, dCenterY, dCenterX, dMaxY, arrSubColors, nDepth + 1);
// Ïðàâûé âåðõíèé ïðÿìîóãîëüíèê
arrSubColors[0] = oColorCT;
arrSubColors[1] = oColorCC;
arrSubColors[2] = pColors[2];
arrSubColors[3] = oColorRC;
DoFunctionShadingFill(pShading, dCenterX, dMinY, dMaxX, dCenterY, arrSubColors, nDepth + 1);
// Ïðàâûé íèæíèé ïðÿìîóãîëüíèê
arrSubColors[0] = oColorCC;
arrSubColors[1] = oColorCB;
arrSubColors[2] = oColorRC;
arrSubColors[3] = pColors[3];
DoFunctionShadingFill(pShading, dCenterX, dCenterY, dMaxX, dMaxY, arrSubColors, nDepth + 1);
}
}
void Graphics::DoAxialShadingFill(GrAxialShading *pShading)
{
int nJ, nK, nKK;
// Ñíà÷àëà ïðåäîñòàâëÿåì âîçìîæíîñòü OuputDevice ñàìîìó ñäåëàòü Shading
if (m_pOut->UseAxialShadedFills() && m_pOut->AxialShadedFill(m_pGState, pShading))
{
return;
}
// get the clip region bbox
double dMinX, dMinY, dMaxX, dMaxY;
m_pGState->GetUserClipBBox(&dMinX, &dMinY, &dMaxX, &dMaxY);
// Âû÷èñëÿåì ìàêèìàëüíîå è ìèíèìàëüíîå çíà÷åíèÿ ïàðàìåòðà T
double dTmin, dTmax;
double dX0, dY0, dX1, dY1;
pShading->GetCoords(&dX0, &dY0, &dX1, &dY1);
double dDx = dX1 - dX0;
double dDy = dY1 - dY0;
bool bDxZero = fabs(dDx) < 0.01;
bool bDyZero = fabs(dDy) < 0.01;
if (bDxZero && bDyZero)
{
dTmin = dTmax = 0;
}
else
{
double dMult = 1 / (dDx * dDx + dDy * dDy);
dTmin = dTmax = ((dMinX - dX0) * dDx + (dMinY - dY0) * dDy) * dMult;
double dTemp = ((dMinX - dX0) * dDx + (dMaxY - dY0) * dDy) * dMult;
if (dTemp < dTmin)
{
dTmin = dTemp;
}
else if (dTemp > dTmax)
{
dTmax = dTemp;
}
dTemp = ((dMaxX - dX0) * dDx + (dMinY - dY0) * dDy) * dMult;
if (dTemp < dTmin)
{
dTmin = dTemp;
}
else if (dTemp > dTmax)
{
dTmax = dTemp;
}
dTemp = ((dMaxX - dX0) * dDx + (dMaxY - dY0) * dDy) * dMult;
if (dTemp < dTmin)
{
dTmin = dTemp;
}
else if (dTemp > dTmax)
{
dTmax = dTemp;
}
if (dTmin < 0 && !pShading->GetExtendStart())
{
dTmin = 0;
}
if (dTmax > 1 && !pShading->GetExtendEnd())
{
dTmax = 1;
}
}
// Ñ÷èòûâàåì ïðåäåëû ïàðàìåòðà T
double dT0 = pShading->GetDomain0();
double dT1 = pShading->GetDomain1();
// Äëÿ êàæäîé òî÷êè (Tx, Ty) îñè, ðàññìîòðèì ëèíèþ ,ïðîõîäÿþùóþ ÷åðåç äàííóþ òî÷êó ïåðïåíäèêóëÿðíî îñè:
//
// x(s) = Tx + s * -dDy --> s = (x - Tx) / -dDy
// y(s) = Ty + s * dDx --> s = (y - Ty) / dDx
//
// Ðàññìîòðèì òî÷êè ïåðåñå÷åíèÿ äàííîé ëèíèè ñ âíåøíèì ðåêòîì(â êîòîðîì âñå ðèñóåì Bbox).  îáùåì ñëó÷àå
// ìû èìååì 4 òî÷êè ïåðåñå÷åíèÿ:
//
// s0 = (dMinX - Tx) / -dDy
// s1 = (dMaxX - Tx) / -dDy
// s2 = (dMinY - Ty) / dDx
// s3 = (dMaxY - Ty) / dDx
//
// íàñ èíòåðåñóþò äâà ñðåäíèõ çíà÷åíèÿ s.
//
//  ñëó÷àå, êîãäà dDx = 0, âîçüìåì s0 è s1; â ñëó÷àå, êîãäà dDy = 0, âîçüìåì s2 è s3.
//
// Äàëåå êàæäûé ïîëèãîí, êîòîðûé ìû áóäåì çàïîëíÿòü áóäåò îãðàíè÷åí äâóìÿ òàêèìè ëèíèÿìè, ïåðïåíäèêóëÿðíûìè îñè.
//
// Äåëèì îñü òàêèì îáðàçîì äî òåõ ïîð, ïîêà ðàçíèöà öâåòîâ ìåæäó äâóìÿ ñîñåäíèìè ëèíèÿìè íå ñòàíåò äîñòàòî÷íî
// ìàëîé. Äàëåå êàæäû îòäåëüíûé ïîëèãîí çàêðàøèâàåì îäíèì öâåòîì.
// Äåëàåì êàê ìèíèìóì îäíó òàêóþ èòòåðàöèþ, ÷òîáû èçáåæàòü ïðîáëåì â ñëó÷àå, êîãäà îáà êîíöà îñè èìåþò
// îäèíàêîâûé öâåò.
int nComponentsCount = pShading->GetColorSpace()->GetComponentsCount();
double arrTa[axialMaxSplits + 1];
arrTa[0] = dTmin;
int arrNext[axialMaxSplits + 1];
arrNext[0] = axialMaxSplits / 2;
arrTa[axialMaxSplits / 2] = 0.5 * (dTmin + dTmax);
arrNext[axialMaxSplits / 2] = axialMaxSplits;
arrTa[axialMaxSplits] = dTmax;
// Âû÷èñëÿåì çíà÷åíèå öâåòà ïðè t = dTmin
double dTt = 0;
if (dTmin < 0)
{
dTt = dT0;
}
else if (dTmin > 1)
{
dTt = dT1;
}
else
{
dTt = dT0 + (dT1 - dT0) * dTmin;
}
GrColor oColor0, oColor1;
pShading->GetColor(dTt, &oColor0);
// Âû÷èñëÿåì êîîðäèíàòû òî÷êè, ëåæàùå íà îñè, ïðè çíà÷åíèè ïàðàìåòðà t = dTmin;
// ïîñëå ýòîãî âû÷èñëÿåì êîîðäèíàòû òî÷åê ïåðåñå÷åíèÿ äëÿ ëèíèè ïðè t = dTmin.
double dTx = dX0 + dTmin * dDx;
double dTy = dY0 + dTmin * dDy;
double arrS[4];
double dSmin, dSmax;
if (bDxZero && bDyZero)
{
dSmin = dSmax = 0;
}
else if (bDxZero)
{
dSmin = (dMinX - dTx) / -dDy;
dSmax = (dMaxX - dTx) / -dDy;
if (dSmin > dSmax)
{
double dTemp = dSmin;
dSmin = dSmax;
dSmax = dTemp;
}
}
else if (bDyZero)
{
dSmin = (dMinY - dTy) / dDx;
dSmax = (dMaxY - dTy) / dDx;
if (dSmin > dSmax)
{
double dTemp = dSmin;
dSmin = dSmax;
dSmax = dTemp;
}
}
else
{
arrS[0] = (dMinY - dTy) / dDx;
arrS[1] = (dMaxY - dTy) / dDx;
arrS[2] = (dMinX - dTx) / -dDy;
arrS[3] = (dMaxX - dTx) / -dDy;
for (nJ = 0; nJ < 3; ++nJ)
{
nKK = nJ;
for (nK = nJ + 1; nK < 4; ++nK)
{
if (arrS[nK] < arrS[nKK])
{
nKK = nK;
}
}
double dTemp = arrS[nJ];
arrS[nJ] = arrS[nKK];
arrS[nKK] = dTemp;
}
dSmin = arrS[1];
dSmax = arrS[2];
}
double dStartX0 = dTx - dSmin * dDy;
double dStartY0 = dTy + dSmin * dDx;
double dEndX0 = dTx - dSmax * dDy;
double dEndY0 = dTy + dSmax * dDx;
int nSplitsCount = 0;
while (nSplitsCount < axialMaxSplits)
{
if (m_pOut->IsStopped())
return;
// Äåëèì ïîêà ðàçíèöà öâåòîâ íå ñòàíåò äîñòàòî÷íîé ìàëåíüêîé èëè ïîêà ìû íå äîñòèãíåì ïðåäåëà êîëè÷åñòâó èòòåðàöèé
nJ = arrNext[nSplitsCount];
while (nJ > nSplitsCount + 1)
{
if (m_pOut->IsStopped())
return;
if (arrTa[nJ] < 0)
{
dTt = dT0;
}
else if (arrTa[nJ] > 1)
{
dTt = dT1;
}
else
{
dTt = dT0 + (dT1 - dT0) * arrTa[nJ];
}
pShading->GetColor(dTt, &oColor1);
for (nK = 0; nK < nComponentsCount; ++nK)
{
if (abs(oColor1.arrComp[nK] - oColor0.arrComp[nK]) > axialColorDelta)
{
break;
}
}
if (nK == nComponentsCount)
{
break;
}
nK = (nSplitsCount + nJ) / 2;
arrTa[nK] = 0.5 * (arrTa[nSplitsCount] + arrTa[nJ]);
arrNext[nSplitsCount] = nK;
arrNext[nK] = nJ;
nJ = nK;
}
// Èñïîëüçóåì ñðåäíåå çíà÷åíèå öâåòà
for (nK = 0; nK < nComponentsCount; ++nK)
{
oColor0.arrComp[nK] = (oColor0.arrComp[nK] + oColor1.arrComp[nK]) / 2;
}
// Âû÷èñëÿåì êîîðäèíàòû òî÷êè, ëåæàùå íà îñè, ïðè äàííîì çíà÷åíèè ïàðàìåòðà t;
// ïîñëå ýòîãî âû÷èñëÿåì êîîðäèíàòû òî÷åê ïåðåñå÷åíèÿ äëÿ ëèíèè äàííîì t.
dTx = dX0 + arrTa[nJ] * dDx;
dTy = dY0 + arrTa[nJ] * dDy;
if (bDxZero && bDyZero)
{
dSmin = dSmax = 0;
}
else if (bDxZero)
{
dSmin = (dMinX - dTx) / -dDy;
dSmax = (dMaxX - dTx) / -dDy;
if (dSmin > dSmax)
{
double dTemp = dSmin;
dSmin = dSmax;
dSmax = dTemp;
}
}
else if (bDyZero)
{
dSmin = (dMinY - dTy) / dDx;
dSmax = (dMaxY - dTy) / dDx;
if (dSmin > dSmax)
{
double dTemp = dSmin;
dSmin = dSmax;
dSmax = dTemp;
}
}
else
{
arrS[0] = (dMinY - dTy) / dDx;
arrS[1] = (dMaxY - dTy) / dDx;
arrS[2] = (dMinX - dTx) / -dDy;
arrS[3] = (dMaxX - dTx) / -dDy;
for (nJ = 0; nJ < 3; ++nJ)
{
nKK = nJ;
for (nK = nJ + 1; nK < 4; ++nK)
{
if (arrS[nK] < arrS[nKK])
{
nKK = nK;
}
}
double dTemp = arrS[nJ];
arrS[nJ] = arrS[nKK];
arrS[nKK] = dTemp;
}
dSmin = arrS[1];
dSmax = arrS[2];
}
double dStartX1 = dTx - dSmin * dDy;
double dStartY1 = dTy + dSmin * dDx;
double dEndX1 = dTx - dSmax * dDy;
double dEndY1 = dTy + dSmax * dDx;
// Óñòàíàâëèâàåì öâåò
m_pGState->SetFillColor(&oColor0);
m_pOut->UpdateFillColor(m_pGState);
// Çàêðàøèâàåì
m_pGState->MoveTo(dStartX0, dStartY0);
m_pGState->LineTo(dEndX0, dEndY0);
m_pGState->LineTo(dEndX1, dEndY1);
m_pGState->LineTo(dStartX1, dStartY1);
m_pGState->ClosePath();
m_pOut->Fill(m_pGState);
m_pGState->ClearPath();
// Íà÷àëüíûå çíà÷åíèÿ äëÿ ñëåäóþùåãî ïîëèãîíà
dStartX0 = dStartX1;
dStartY0 = dStartY1;
dEndX0 = dEndX1;
dEndY0 = dEndY1;
oColor0 = oColor1;
nSplitsCount = arrNext[nSplitsCount];
}
}
void Graphics::DoRadialShadingFill(GrRadialShading *pShading)
{
// Ñíà÷àëà ïðåäîñòàâëÿåì âîçìîæíîñòü OuputDevice ñàìîìó ñäåëàòü Shading
if (m_pOut->UseRadialShadedFills() && m_pOut->RadialShadedFill(m_pGState, pShading))
{
return;
}
// Åñëè Output Device íå ïîääåðæèâàåò äàííûé ShadingType, òîãäà äåëàåì åãî ñàìè
// ñ ïîìîùüþ GrPath.
double dFirstX, dFirstY, dFirstRad, dSecondX, dSecondY, dSecondRad;
pShading->GetCoords(&dFirstX, &dFirstY, &dFirstRad, &dSecondX, &dSecondY, &dSecondRad);
double dT0 = pShading->GetDomain0();
double dT1 = pShading->GetDomain1();
int nComponentsCount = pShading->GetColorSpace()->GetComponentsCount();
// Âû÷èñëÿåì òî÷êó, â êîòîðîé r(s) = 0; ïðîâåðÿìå âëîæåííîñòü îêðóæíîñòåé; è
// âû÷èñëÿåì óãëû òàíãåíöèàëüíûõ ëèíèé
bool bEnclosed = false;
double dTheta = 0, dAlpha = 0;;
double dZeroS = 0;
if (dFirstX == dSecondX && dFirstY == dSecondY)
{
bEnclosed = true;
dTheta = 0;
dZeroS = 0;
}
else if (dFirstRad == dSecondRad)
{
bEnclosed = false;
dTheta = 0;
dZeroS = 0;
}
else
{
dZeroS = -dFirstRad / (dSecondRad - dFirstRad);
double dZeroX = dFirstX + dZeroS * (dSecondX - dFirstX);
double dZeroY = dFirstY + dZeroS * (dSecondY - dFirstY);
bEnclosed = ((dZeroX - dFirstX) * (dZeroX - dFirstX) + (dZeroY - dFirstY) * (dZeroY - dFirstY) <= dFirstRad * dFirstRad);
dTheta = asin(dFirstRad / sqrt((dFirstX - dZeroX) * (dFirstX - dZeroX) + (dFirstY - dZeroY) * (dFirstY - dZeroY)));
if (dFirstRad > dSecondRad)
{
dTheta = -dTheta;
}
}
if (bEnclosed)
{
dAlpha = 0;
}
else
{
dAlpha = atan2(dSecondY - dFirstY, dSecondX - dFirstX);
}
double dXMin, dYMin, dXMax, dYMax;
m_pGState->GetUserClipBBox(&dXMin, &dYMin, &dXMax, &dYMax);
double dSmin, dSmax;
if (bEnclosed)
{
dSmin = 0;
dSmax = 1;
}
else
{
dSmin = 1;
dSmax = 0;
// x(s) + r(s) = dXMin
if ((dSecondX + dSecondRad) - (dFirstX + dFirstRad) != 0)
{
double dTempS = (dXMin - (dFirstX + dFirstRad)) / ((dSecondX + dSecondRad) - (dFirstX + dFirstRad));
if (dTempS < dSmin)
{
dSmin = dTempS;
}
else if (dTempS > dSmax)
{
dSmax = dTempS;
}
}
// x(s) - r(s) = dXMax
if ((dSecondX - dSecondRad) - (dFirstX - dFirstRad) != 0)
{
double dTempS = (dXMax - (dFirstX - dFirstRad)) / ((dSecondX - dSecondRad) - (dFirstX - dFirstRad));
if (dTempS < dSmin)
{
dSmin = dTempS;
}
else if (dTempS > dSmax)
{
dSmax = dTempS;
}
}
// y(s) + r(s) = dYMin
if ((dSecondY + dSecondRad) - (dFirstY + dFirstRad) != 0)
{
double dTempS = (dYMin - (dFirstY + dFirstRad)) / ((dSecondY + dSecondRad) - (dFirstY + dFirstRad));
if (dTempS < dSmin)
{
dSmin = dTempS;
}
else if (dTempS > dSmax)
{
dSmax = dTempS;
}
}
// y(s) - r(s) = dYMax
if ((dSecondY - dSecondRad) - (dFirstY - dFirstRad) != 0)
{
double dTempS = (dYMax - (dFirstY - dFirstRad)) / ((dSecondY - dSecondRad) - (dFirstY - dFirstRad));
if (dTempS < dSmin)
{
dSmin = dTempS;
}
else if (dTempS > dSmax)
{
dSmax = dTempS;
}
}
// Ïðîâåðÿåì îòíîñèòåëüíî dZeroS
if (dFirstRad < dSecondRad)
{
if (dSmin < dZeroS)
{
dSmin = dZeroS;
}
}
else if (dFirstRad > dSecondRad)
{
if (dSmax > dZeroS)
{
dSmax = dZeroS;
}
}
if (!pShading->GetExtendFirst() && dSmin < 0)
{
dSmin = 0;
}
if (!pShading->GetExtendSecond() && dSmax > 1)
{
dSmax = 1;
}
}
double *pCTM = m_pGState->GetCTM();
double dTemp = fabs(pCTM[0]);
if (fabs(pCTM[1]) > dTemp)
{
dTemp = fabs(pCTM[1]);
}
if (fabs(pCTM[2]) > dTemp)
{
dTemp = fabs(pCTM[2]);
}
if (fabs(pCTM[3]) > dTemp)
{
dTemp = fabs(pCTM[3]);
}
if (dFirstRad > dSecondRad)
{
dTemp *= dFirstRad;
}
else
{
dTemp *= dSecondRad;
}
int nStepsCount = 0;
if (dTemp < 1)
{
nStepsCount = 3;
}
else
{
nStepsCount = (int)(M_PI / acos(1 - 0.1 / dTemp));
if (nStepsCount < 3)
{
nStepsCount = 3;
}
else if (nStepsCount > 200)
{
nStepsCount = 200;
}
}
// Âåçäå äàëåå A - ïåðâàÿ îêðóæíîñòü, B - âòîðàÿ
int nIndexA = 0;
double dSA = dSmin;
double dTA = dT0 + dSA * (dT1 - dT0);
double dXA = dFirstX + dSA * (dSecondX - dFirstX);
double dYA = dFirstY + dSA * (dSecondY - dFirstY);
double dRadA = dFirstRad + dSA * (dSecondRad - dFirstRad);
double dAngle = 0;
int nCounter = 0;
GrColor oColorA;
if (dTA < dT0)
{
pShading->GetColor(dT0, &oColorA);
}
else if (dTA > dT1)
{
pShading->GetColor(dT1, &oColorA);
}
else
{
pShading->GetColor(dTA, &oColorA);
}
while (nIndexA < radialMaxSplits)
{
if (m_pOut->IsStopped())
return;
int nIndexB = radialMaxSplits;
double dSB = dSmax;
double dTB = dT0 + dSB * (dT1 - dT0);
GrColor oColorB;
if (dTB < dT0)
{
pShading->GetColor(dT0, &oColorB);
}
else if (dTB > dT1)
{
pShading->GetColor(dT1, &oColorB);
}
else
{
pShading->GetColor(dTB, &oColorB);
}
while (nIndexB - nIndexA > 1)
{
if (m_pOut->IsStopped())
return;
for (nCounter = 0; nCounter < nComponentsCount; ++nCounter)
{
if (abs(oColorB.arrComp[nCounter] - oColorA.arrComp[nCounter]) > radialColorDelta)
{
break;
}
}
if (nCounter == nComponentsCount && nIndexB < radialMaxSplits)
{
break;
}
nIndexB = (nIndexA + nIndexB) / 2;
dSB = dSmin + ((double)nIndexB / (double)radialMaxSplits) * (dSmax - dSmin);
dTB = dT0 + dSB * (dT1 - dT0);
if (dTB < dT0)
{
pShading->GetColor(dT0, &oColorB);
}
else if (dTB > dT1)
{
pShading->GetColor(dT1, &oColorB);
}
else
{
pShading->GetColor(dTB, &oColorB);
}
}
// Âû÷èñëèì öåíòð è ðàäèóñ îêðóæíîñòè
double dXB = dFirstX + dSB * (dSecondX - dFirstX);
double dYB = dFirstY + dSB * (dSecondY - dFirstY);
double dRadB = dFirstRad + dSB * (dSecondRad - dFirstRad);
// Èñïîëüçóåì ñðåäíåå çíà÷åíèå öâåòà äâóõ îêðóæíîñòåé
for (nCounter = 0; nCounter < nComponentsCount; ++nCounter)
{
oColorA.arrComp[nCounter] = (oColorA.arrComp[nCounter] + oColorB.arrComp[nCounter]) / 2;
}
m_pGState->SetFillColor(&oColorA);
m_pOut->UpdateFillColor(m_pGState);
if (bEnclosed)
{
// Ñòðîèì Path äëÿ ïåðâîé îêðóæíîñòè (ïðîòèâ ÷àñîâîé)
m_pGState->MoveTo(dXA + dRadA, dYA);
for (nCounter = 1; nCounter < nStepsCount; ++nCounter)
{
dAngle = ((double)nCounter / (double)nStepsCount) * 2 * M_PI;
m_pGState->LineTo(dXA + dRadA * cos(dAngle), dYA + dRadA * sin(dAngle));
}
m_pGState->ClosePath();
// Ñòðîèì Path äëÿ âòîðîé îêðóæíîñòè (ïî ÷àñîâîé)
m_pGState->MoveTo(dXB + dRadB, dYB);
for (nCounter = 1; nCounter < nStepsCount; ++nCounter)
{
dAngle = -((double)nCounter / (double)nStepsCount) * 2 * M_PI;
m_pGState->LineTo(dXB + dRadB * cos(dAngle), dYB + dRadB * sin(dAngle));
}
m_pGState->ClosePath();
}
else
{
// Ñòðîèì ïåðâûé subpath (ïî ÷àñîâîé)
m_pGState->MoveTo(dXA + dRadA * cos(dAlpha + dTheta + 0.5 * M_PI), dYA + dRadA * sin(dAlpha + dTheta + 0.5 * M_PI));
for (nCounter = 0; nCounter < nStepsCount; ++nCounter)
{
dAngle = dAlpha + dTheta + 0.5 * M_PI - ((double)nCounter / (double)nStepsCount) * (2 * dTheta + M_PI);
m_pGState->LineTo(dXB + dRadB * cos(dAngle), dYB + dRadB * sin(dAngle));
}
for (nCounter = 0; nCounter < nStepsCount; ++nCounter)
{
dAngle = dAlpha - dTheta - 0.5 * M_PI + ((double)nCounter / (double)nStepsCount) * (2 * dTheta - M_PI);
m_pGState->LineTo(dXA + dRadA * cos(dAngle), dYA + dRadA * sin(dAngle));
}
m_pGState->ClosePath();
// Ñòðîèì âòîðîé subpath (ïðîòèâ ÷àñîâîé)
m_pGState->MoveTo(dXA + dRadA * cos(dAlpha + dTheta + 0.5 * M_PI), dYA + dRadA * sin(dAlpha + dTheta + 0.5 * M_PI));
for (nCounter = 0; nCounter < nStepsCount; ++nCounter)
{
dAngle = dAlpha + dTheta + 0.5 * M_PI + ((double)nCounter / (double)nStepsCount) * (-2 * dTheta + M_PI);
m_pGState->LineTo(dXB + dRadB * cos(dAngle), dYB + dRadB * sin(dAngle));
}
for (nCounter = 0; nCounter < nStepsCount; ++nCounter)
{
dAngle = dAlpha - dTheta - 0.5 * M_PI + ((double)nCounter / (double)nStepsCount) * (2 * dTheta + M_PI);
m_pGState->LineTo(dXA + dRadA * cos(dAngle), dYA + dRadA * sin(dAngle));
}
m_pGState->ClosePath();
}
// Çàêðàøèâàåì
m_pOut->Fill(m_pGState);
m_pGState->ClearPath();
// Íà÷àëüíûå äàííûå äëÿ ñëåäóþùåãî øàãà
nIndexA = nIndexB;
dSA = dSB;
dTA = dTB;
dXA = dXB;
dYA = dYB;
dRadA = dRadB;
oColorA = oColorB;
}
// Åñëè âûñòàâëåíû ôëàãè ïðîäîëæàòü ðèñîâàòü çà ïðåäåëàìè äâóõ îêðóæíîñòåé
if (bEnclosed)
{
// Ïðîäîëæàåì çà ìåíüøóþ îêðóæíîñòü
if ((pShading->GetExtendFirst() && dFirstRad <= dSecondRad) || (pShading->GetExtendSecond() && dSecondRad < dFirstRad))
{
if (dFirstRad <= dSecondRad)
{
dTA = dT0;
dRadA = dFirstRad;
dXA = dFirstX;
dYA = dFirstY;
}
else
{
dTA = dT1;
dRadA = dSecondRad;
dXA = dSecondX;
dYA = dSecondY;
}
pShading->GetColor(dTA, &oColorA);
m_pGState->SetFillColor(&oColorA);
m_pOut->UpdateFillColor(m_pGState);
m_pGState->MoveTo(dXA + dRadA, dYA);
for (nCounter = 1; nCounter < nStepsCount; ++nCounter)
{
dAngle = ((double)nCounter / (double)nStepsCount) * 2 * M_PI;
m_pGState->LineTo(dXA + dRadA * cos(dAngle), dYA + dRadA * sin(dAngle));
}
m_pGState->ClosePath();
m_pOut->Fill(m_pGState);
m_pGState->ClearPath();
}
// Ïðîäîëæàåì çà áîëüøóþ îêðóæíîñòü
if ((pShading->GetExtendFirst() && dFirstRad > dSecondRad) || (pShading->GetExtendSecond() && dSecondRad >= dFirstRad))
{
if (dFirstRad > dSecondRad)
{
dTA = dT0;
dRadA = dFirstRad;
dXA = dFirstX;
dYA = dFirstY;
}
else
{
dTA = dT1;
dRadA = dSecondRad;
dXA = dSecondX;
dYA = dSecondY;
}
pShading->GetColor(dTA, &oColorA);
m_pGState->SetFillColor(&oColorA);
m_pOut->UpdateFillColor(m_pGState);
m_pGState->MoveTo(dXMin, dYMin);
m_pGState->LineTo(dXMin, dYMax);
m_pGState->LineTo(dXMax, dYMax);
m_pGState->LineTo(dXMax, dYMin);
m_pGState->ClosePath();
m_pGState->MoveTo(dXA + dRadA, dYA);
for (nCounter = 1; nCounter < nStepsCount; ++nCounter)
{
dAngle = ((double)nCounter / (double)nStepsCount) * 2 * M_PI;
m_pGState->LineTo(dXA + dRadA * cos(dAngle), dYA + dRadA * sin(dAngle));
}
m_pGState->ClosePath();
m_pOut->Fill(m_pGState);
m_pGState->ClearPath();
}
}
}
void Graphics::DoGouraudTriangleShadingFill(GrGouraudTriangleShading *pShading)
{
double dAx, dAy, dBx, dBy, dCx, dCy;
GrColor oColorA, oColorB, oColorC;
for (int nIndex = 0; nIndex < pShading->GetTrianglesCount(); ++nIndex)
{
pShading->GetTriangle(nIndex, &dAx, &dAy, &oColorA, &dBx, &dBy, &oColorB, &dCx, &dCy, &oColorC);
GouraudFillTriangle(dAx, dAy, &oColorA, dBx, dBy, &oColorB, dCx, dCy, &oColorC, pShading->GetColorSpace()->GetComponentsCount(), 0);
}
}
void Graphics::GouraudFillTriangle(double dAx, double dAy, GrColor *pColorA, double dBx, double dBy, GrColor *pColorB, double dCx, double dCy, GrColor *pColorC, int nComponentsCount, int nDepth)
{
if (m_pOut->IsStopped())
return;
double dABx, dABy, dBCx, dBCy, dACx, dACy;
GrColor oColorAB, oColorBC, oColorAC;
int nIndex;
for (nIndex = 0; nIndex < nComponentsCount; ++nIndex)
{
if (abs(pColorA->arrComp[nIndex] - pColorB->arrComp[nIndex]) > gouraudColorDelta || abs(pColorB->arrComp[nIndex] - pColorC->arrComp[nIndex]) > gouraudColorDelta)
{
break;
}
}
if (nIndex == nComponentsCount || nDepth == gouraudMaxDepth)
{
m_pGState->SetFillColor(pColorA);
m_pOut->UpdateFillColor(m_pGState);
m_pGState->MoveTo(dAx, dAy);
m_pGState->LineTo(dBx, dBy);
m_pGState->LineTo(dCx, dCy);
m_pGState->ClosePath();
m_pOut->Fill(m_pGState);
m_pGState->ClearPath();
}
else
{
dABx = 0.5 * (dAx + dBx);
dABy = 0.5 * (dAy + dBy);
dBCx = 0.5 * (dBx + dCx);
dBCy = 0.5 * (dBy + dCy);
dACx = 0.5 * (dCx + dAx);
dACy = 0.5 * (dCy + dAy);
for (nIndex = 0; nIndex < nComponentsCount; ++nIndex)
{
oColorAB.arrComp[nIndex] = (pColorA->arrComp[nIndex] + pColorB->arrComp[nIndex]) / 2;
oColorBC.arrComp[nIndex] = (pColorB->arrComp[nIndex] + pColorC->arrComp[nIndex]) / 2;
oColorAC.arrComp[nIndex] = (pColorC->arrComp[nIndex] + pColorA->arrComp[nIndex]) / 2;
}
GouraudFillTriangle(dAx, dAy, pColorA, dABx, dABy, &oColorAB, dACx, dACy, &oColorAC, nComponentsCount, nDepth + 1);
GouraudFillTriangle(dABx, dABy, &oColorAB, dBx, dBy, pColorB, dBCx, dBCy, &oColorBC, nComponentsCount, nDepth + 1);
GouraudFillTriangle(dABx, dABy, &oColorAB, dBCx, dBCy, &oColorBC, dACx, dACy, &oColorAC, nComponentsCount, nDepth + 1);
GouraudFillTriangle(dACx, dACy, &oColorAC, dBCx, dBCy, &oColorBC, dCx, dCy, pColorC, nComponentsCount, nDepth + 1);
}
}
void Graphics::DoPatchMeshShadingFill(GrPatchMeshShading *pShading)
{
// Óñòàíàâëèâàåì öâåòîâîå ïðîñòðàíñòâî
m_pGState->SetStrokeColorSpace(pShading->GetColorSpace()->Copy());
m_pOut->UpdateStrokeColorSpace(m_pGState);
int nStart;
if (pShading->GetPatchesCount() > 128)
{
nStart = 3;
}
else if (pShading->GetPatchesCount() > 64)
{
nStart = 2;
}
else if (pShading->GetPatchesCount() > 16)
{
nStart = 1;
}
else
{
nStart = 0;
}
for (int nIndex = 0; nIndex < pShading->GetPatchesCount(); ++nIndex)
{
MeshFillPatch(pShading->GetPatch(nIndex), pShading->GetColorSpace()->GetComponentsCount(), nStart);
}
}
void Graphics::MeshFillPatch(GrPatch *pPatch, int nComponentsCount, int nDepth)
{
if (m_pOut->IsStopped())
return;
GrPatch oPatch00, oPatch01, oPatch10, oPatch11;
double arrX[4][8], arrY[4][8];
double dMidX, dMidY;
int nIndex;
for (nIndex = 0; nIndex < nComponentsCount; ++nIndex)
{
if (abs(pPatch->arrColor[0][0].arrComp[nIndex] - pPatch->arrColor[0][1].arrComp[nIndex]) > patchColorDelta ||
abs(pPatch->arrColor[0][1].arrComp[nIndex] - pPatch->arrColor[1][1].arrComp[nIndex]) > patchColorDelta ||
abs(pPatch->arrColor[1][1].arrComp[nIndex] - pPatch->arrColor[1][0].arrComp[nIndex]) > patchColorDelta ||
abs(pPatch->arrColor[1][0].arrComp[nIndex] - pPatch->arrColor[0][0].arrComp[nIndex]) > patchColorDelta
)
{
break;
}
}
if (nIndex == nComponentsCount || nDepth == patchMaxDepth)
{
m_pGState->SetFillColor(&pPatch->arrColor[0][0]);
m_pGState->SetStrokeColor(&pPatch->arrColor[0][0]);
m_pOut->UpdateFillColor(m_pGState);
m_pOut->UpdateStrokeColor(m_pGState);
m_pGState->MoveTo(pPatch->arrX[0][0], pPatch->arrY[0][0]);
m_pGState->CurveTo(pPatch->arrX[0][1], pPatch->arrY[0][1], pPatch->arrX[0][2], pPatch->arrY[0][2], pPatch->arrX[0][3], pPatch->arrY[0][3]);
m_pGState->CurveTo(pPatch->arrX[1][3], pPatch->arrY[1][3], pPatch->arrX[2][3], pPatch->arrY[2][3], pPatch->arrX[3][3], pPatch->arrY[3][3]);
m_pGState->CurveTo(pPatch->arrX[3][2], pPatch->arrY[3][2], pPatch->arrX[3][1], pPatch->arrY[3][1], pPatch->arrX[3][0], pPatch->arrY[3][0]);
m_pGState->CurveTo(pPatch->arrX[2][0], pPatch->arrY[2][0], pPatch->arrX[1][0], pPatch->arrY[1][0], pPatch->arrX[0][0], pPatch->arrY[0][0]);
m_pGState->ClosePath();
m_pOut->FillStroke(m_pGState);
m_pGState->ClearPath();
}
else
{
for (nIndex = 0; nIndex < 4; ++nIndex)
{
arrX[nIndex][0] = pPatch->arrX[nIndex][0];
arrY[nIndex][0] = pPatch->arrY[nIndex][0];
arrX[nIndex][1] = 0.5 * (pPatch->arrX[nIndex][0] + pPatch->arrX[nIndex][1]);
arrY[nIndex][1] = 0.5 * (pPatch->arrY[nIndex][0] + pPatch->arrY[nIndex][1]);
dMidX = 0.5 * (pPatch->arrX[nIndex][1] + pPatch->arrX[nIndex][2]);
dMidY = 0.5 * (pPatch->arrY[nIndex][1] + pPatch->arrY[nIndex][2]);
arrX[nIndex][6] = 0.5 * (pPatch->arrX[nIndex][2] + pPatch->arrX[nIndex][3]);
arrY[nIndex][6] = 0.5 * (pPatch->arrY[nIndex][2] + pPatch->arrY[nIndex][3]);
arrX[nIndex][2] = 0.5 * (arrX[nIndex][1] + dMidX);
arrY[nIndex][2] = 0.5 * (arrY[nIndex][1] + dMidY);
arrX[nIndex][5] = 0.5 * (dMidX + arrX[nIndex][6]);
arrY[nIndex][5] = 0.5 * (dMidY + arrY[nIndex][6]);
arrX[nIndex][3] = arrX[nIndex][4] = 0.5 * (arrX[nIndex][2] + arrX[nIndex][5]);
arrY[nIndex][3] = arrY[nIndex][4] = 0.5 * (arrY[nIndex][2] + arrY[nIndex][5]);
arrX[nIndex][7] = pPatch->arrX[nIndex][3];
arrY[nIndex][7] = pPatch->arrY[nIndex][3];
}
for (nIndex = 0; nIndex < 4; ++nIndex)
{
oPatch00.arrX[0][nIndex] = arrX[0][nIndex];
oPatch00.arrY[0][nIndex] = arrY[0][nIndex];
oPatch00.arrX[1][nIndex] = 0.5 * (arrX[0][nIndex] + arrX[1][nIndex]);
oPatch00.arrY[1][nIndex] = 0.5 * (arrY[0][nIndex] + arrY[1][nIndex]);
dMidX = 0.5 * (arrX[1][nIndex] + arrX[2][nIndex]);
dMidY = 0.5 * (arrY[1][nIndex] + arrY[2][nIndex]);
oPatch10.arrX[2][nIndex] = 0.5 * (arrX[2][nIndex] + arrX[3][nIndex]);
oPatch10.arrY[2][nIndex] = 0.5 * (arrY[2][nIndex] + arrY[3][nIndex]);
oPatch00.arrX[2][nIndex] = 0.5 * (oPatch00.arrX[1][nIndex] + dMidX);
oPatch00.arrY[2][nIndex] = 0.5 * (oPatch00.arrY[1][nIndex] + dMidY);
oPatch10.arrX[1][nIndex] = 0.5 * (dMidX + oPatch10.arrX[2][nIndex]);
oPatch10.arrY[1][nIndex] = 0.5 * (dMidY + oPatch10.arrY[2][nIndex]);
oPatch00.arrX[3][nIndex] = 0.5 * (oPatch00.arrX[2][nIndex] + oPatch10.arrX[1][nIndex]);
oPatch00.arrY[3][nIndex] = 0.5 * (oPatch00.arrY[2][nIndex] + oPatch10.arrY[1][nIndex]);
oPatch10.arrX[0][nIndex] = oPatch00.arrX[3][nIndex];
oPatch10.arrY[0][nIndex] = oPatch00.arrY[3][nIndex];
oPatch10.arrX[3][nIndex] = arrX[3][nIndex];
oPatch10.arrY[3][nIndex] = arrY[3][nIndex];
}
for (nIndex = 4; nIndex < 8; ++nIndex)
{
oPatch01.arrX[0][nIndex - 4] = arrX[0][nIndex];
oPatch01.arrY[0][nIndex - 4] = arrY[0][nIndex];
oPatch01.arrX[1][nIndex - 4] = 0.5 * (arrX[0][nIndex] + arrX[1][nIndex]);
oPatch01.arrY[1][nIndex - 4] = 0.5 * (arrY[0][nIndex] + arrY[1][nIndex]);
dMidX = 0.5 * (arrX[1][nIndex] + arrX[2][nIndex]);
dMidY = 0.5 * (arrY[1][nIndex] + arrY[2][nIndex]);
oPatch11.arrX[2][nIndex - 4] = 0.5 * (arrX[2][nIndex] + arrX[3][nIndex]);
oPatch11.arrY[2][nIndex - 4] = 0.5 * (arrY[2][nIndex] + arrY[3][nIndex]);
oPatch01.arrX[2][nIndex - 4] = 0.5 * (oPatch01.arrX[1][nIndex - 4] + dMidX);
oPatch01.arrY[2][nIndex - 4] = 0.5 * (oPatch01.arrY[1][nIndex - 4] + dMidY);
oPatch11.arrX[1][nIndex - 4] = 0.5 * (dMidX + oPatch11.arrX[2][nIndex - 4]);
oPatch11.arrY[1][nIndex - 4] = 0.5 * (dMidY + oPatch11.arrY[2][nIndex - 4]);
oPatch01.arrX[3][nIndex - 4] = 0.5 * (oPatch01.arrX[2][nIndex - 4] + oPatch11.arrX[1][nIndex - 4]);
oPatch01.arrY[3][nIndex - 4] = 0.5 * (oPatch01.arrY[2][nIndex - 4] + oPatch11.arrY[1][nIndex - 4]);
oPatch11.arrX[0][nIndex - 4] = oPatch01.arrX[3][nIndex - 4];
oPatch11.arrY[0][nIndex - 4] = oPatch01.arrY[3][nIndex - 4];
oPatch11.arrX[3][nIndex - 4] = arrX[3][nIndex];
oPatch11.arrY[3][nIndex - 4] = arrY[3][nIndex];
}
for (nIndex = 0; nIndex < nComponentsCount; ++nIndex)
{
oPatch00.arrColor[0][0].arrComp[nIndex] = pPatch->arrColor[0][0].arrComp[nIndex];
oPatch00.arrColor[0][1].arrComp[nIndex] = (pPatch->arrColor[0][0].arrComp[nIndex] + pPatch->arrColor[0][1].arrComp[nIndex]) / 2;
oPatch01.arrColor[0][0].arrComp[nIndex] = oPatch00.arrColor[0][1].arrComp[nIndex];
oPatch01.arrColor[0][1].arrComp[nIndex] = pPatch->arrColor[0][1].arrComp[nIndex];
oPatch01.arrColor[1][1].arrComp[nIndex] = (pPatch->arrColor[0][1].arrComp[nIndex] + pPatch->arrColor[1][1].arrComp[nIndex]) / 2;
oPatch11.arrColor[0][1].arrComp[nIndex] = oPatch01.arrColor[1][1].arrComp[nIndex];
oPatch11.arrColor[1][1].arrComp[nIndex] = pPatch->arrColor[1][1].arrComp[nIndex];
oPatch11.arrColor[1][0].arrComp[nIndex] = (pPatch->arrColor[1][1].arrComp[nIndex] + pPatch->arrColor[1][0].arrComp[nIndex]) / 2;
oPatch10.arrColor[1][1].arrComp[nIndex] = oPatch11.arrColor[1][0].arrComp[nIndex];
oPatch10.arrColor[1][0].arrComp[nIndex] = pPatch->arrColor[1][0].arrComp[nIndex];
oPatch10.arrColor[0][0].arrComp[nIndex] = (pPatch->arrColor[1][0].arrComp[nIndex] + pPatch->arrColor[0][0].arrComp[nIndex]) / 2;
oPatch00.arrColor[1][0].arrComp[nIndex] = oPatch10.arrColor[0][0].arrComp[nIndex];
oPatch00.arrColor[1][1].arrComp[nIndex] = (oPatch00.arrColor[1][0].arrComp[nIndex] + oPatch01.arrColor[1][1].arrComp[nIndex]) / 2;
oPatch01.arrColor[1][0].arrComp[nIndex] = oPatch00.arrColor[1][1].arrComp[nIndex];
oPatch11.arrColor[0][0].arrComp[nIndex] = oPatch00.arrColor[1][1].arrComp[nIndex];
oPatch10.arrColor[0][1].arrComp[nIndex] = oPatch00.arrColor[1][1].arrComp[nIndex];
}
MeshFillPatch(&oPatch00, nComponentsCount, nDepth + 1);
MeshFillPatch(&oPatch10, nComponentsCount, nDepth + 1);
MeshFillPatch(&oPatch01, nComponentsCount, nDepth + 1);
MeshFillPatch(&oPatch11, nComponentsCount, nDepth + 1);
}
}
void Graphics::DoEndPath()
{
if (m_pGState->IsCurPoint() && m_eClip != clipNone)
{
m_pGState->Clip();
if (m_eClip == clipNormal)
{
m_pGState->GetClip()->ClipToPath(m_pGState->GetPath()->Copy(), m_pGState->GetCTM(), false);
if (m_pOut->UseClipTo())
m_pOut->ClipToPath(m_pGState, m_pGState->GetPath(), m_pGState->GetCTM(), false);
else
m_pOut->Clip(m_pGState);
}
else
{
m_pGState->GetClip()->ClipToPath(m_pGState->GetPath()->Copy(), m_pGState->GetCTM(), true);
if (m_pOut->UseClipTo())
m_pOut->ClipToPath(m_pGState, m_pGState->GetPath(), m_pGState->GetCTM(), true);
else
m_pOut->EoClip(m_pGState);
}
}
m_eClip = clipNone;
m_pGState->ClearPath();
}
//-------------------------------------------------------------------------------------------------------------------------------
// Clipping paths
//-------------------------------------------------------------------------------------------------------------------------------
// W
void Graphics::OperatorClip(Object arrArguments[], int nArgumentsCount)
{
m_eClip = clipNormal;
}
// W*
void Graphics::OperatorEOClip(Object arrArguments[], int nArgumentsCount)
{
m_eClip = clipEO;
}
//-------------------------------------------------------------------------------------------------------------------------------
// Text objects
//-------------------------------------------------------------------------------------------------------------------------------
// BT
void Graphics::OperatorBeginText(Object arrArguments[], int nArgumentsCount)
{
m_pOut->BegintTextObject(m_pGState);
m_pGState->SetTextMatrix(1, 0, 0, 1, 0, 0);
m_pGState->TextMoveTo(0, 0);
m_pOut->UpdateTextMatrix(m_pGState);
m_pOut->UpdateTextPos(m_pGState);
m_bFontChanged = true;
}
// ET
void Graphics::OperatorEndText(Object arrArguments[], int nArgumentsCount)
{
m_pOut->EndTextObject(m_pGState);
}
//-------------------------------------------------------------------------------------------------------------------------------
// Text state
//-------------------------------------------------------------------------------------------------------------------------------
// Tc
void Graphics::OperatorSetCharSpacing(Object arrArguments[], int nArgumentsCount)
{
m_pGState->SetCharSpace(arrArguments[0].GetNum());
m_pOut->UpdateCharSpace(m_pGState);
}
// Tf
void Graphics::OperatorSetFont(Object arrArguments[], int nArgumentsCount)
{
GrFont *pFont = NULL;
if (!(pFont = m_pResources->LookupFont(arrArguments[0].GetName())))
{
return;
}
#ifdef _DEBUG
if (m_pDumpFile)
{
::fprintf(m_pDumpFile, " Font:\n");
::fprintf(m_pDumpFile, " Tag = %s\n", pFont->GetTag()->GetBuffer());
::fprintf(m_pDumpFile, " Name = %s\n", pFont->GetBaseName() ? pFont->GetBaseName()->GetBuffer() : "???");
::fprintf(m_pDumpFile, " %g\n", arrArguments[1].GetNum());
::fflush(m_pDumpFile);
}
#endif
m_pGState->SetFont(pFont, arrArguments[1].GetNum());
m_bFontChanged = true;
}
// TL
void Graphics::OperatorSetTextLeading(Object arrArguments[], int nArgumentsCount)
{
m_pGState->SetLeading(arrArguments[0].GetNum());
}
// Tr
void Graphics::OperatorSetTextRender(Object arrArguments[], int nArgumentsCount)
{
m_pGState->SetRenderMode(arrArguments[0].GetInt());
m_pOut->UpdateRender(m_pGState);
}
// Ts
void Graphics::OperatorSetTextRise(Object arrArguments[], int nArgumentsCount)
{
m_pGState->SetRise(arrArguments[0].GetNum());
m_pOut->UpdateRise(m_pGState);
}
// Tw
void Graphics::OperatorSetWordSpacing(Object arrArguments[], int nArgumentsCount)
{
m_pGState->SetWordSpace(arrArguments[0].GetNum());
m_pOut->UpdateWordSpace(m_pGState);
}
// Tz
void Graphics::OperatorSetHorizScaling(Object arrArguments[], int nArgumentsCount)
{
m_pGState->SetHorizScaling(arrArguments[0].GetNum());
m_pOut->UpdateHorizScaling(m_pGState);
m_bFontChanged = true;
}
//-------------------------------------------------------------------------------------------------------------------------------
// Text positioning
//-------------------------------------------------------------------------------------------------------------------------------
// Td
void Graphics::OperatorTextMove(Object arrArguments[], int nArgumentsCount)
{
double dDX = m_pGState->GetTextLineX() + arrArguments[0].GetNum();
double dDy = m_pGState->GetTextLineY() + arrArguments[1].GetNum();
m_pGState->TextMoveTo(dDX, dDy);
m_pOut->UpdateTextPos(m_pGState);
}
// TD
void Graphics::OperatorTextMoveSet(Object arrArguments[], int nArgumentsCount)
{
double dDx = m_pGState->GetTextLineX() + arrArguments[0].GetNum();
double dDy = arrArguments[1].GetNum();
m_pGState->SetLeading(-dDy);
dDy += m_pGState->GetTextLineY();
m_pGState->TextMoveTo(dDx, dDy);
m_pOut->UpdateTextPos(m_pGState);
}
// Tm
void Graphics::OperatorSetTextMatrix(Object arrArguments[], int nArgumentsCount)
{
m_pGState->SetTextMatrix(arrArguments[0].GetNum(), arrArguments[1].GetNum(), arrArguments[2].GetNum(), arrArguments[3].GetNum(), arrArguments[4].GetNum(), arrArguments[5].GetNum());
m_pGState->TextMoveTo(0, 0);
m_pOut->UpdateTextMatrix(m_pGState);
m_pOut->UpdateTextPos(m_pGState);
m_bFontChanged = true;
}
// T*
void Graphics::OperatorTextNextLine(Object arrArguments[], int nArgumentsCount)
{
double dDx = m_pGState->GetTextLineX();
double dDy = m_pGState->GetTextLineY() - m_pGState->GetLeading();
m_pGState->TextMoveTo(dDx, dDy);
m_pOut->UpdateTextPos(m_pGState);
}
//-------------------------------------------------------------------------------------------------------------------------------
// Text showing
//-------------------------------------------------------------------------------------------------------------------------------
// Tj
void Graphics::OperatorShowText(Object arrArguments[], int nArgumentsCount)
{
if (!m_pGState->GetFont())
{
// TO DO: Error "No font in show")
return;
}
if (m_bFontChanged)
{
m_pOut->UpdateFont(m_pGState);
m_bFontChanged = false;
}
m_pOut->BeginStringOperator(m_pGState);
DoShowText(arrArguments[0].GetString());
m_pOut->EndStringOperator(m_pGState);
}
// '
void Graphics::OperatorMoveShowText(Object arrArguments[], int nArgumentsCount)
{
if (!m_pGState->GetFont())
{
// TO DO: Error "No font in move/show"
return;
}
if (m_bFontChanged)
{
m_pOut->UpdateFont(m_pGState);
m_bFontChanged = false;
}
double dDx = m_pGState->GetTextLineX();
double dDy = m_pGState->GetTextLineY() - m_pGState->GetLeading();
m_pGState->TextMoveTo(dDx, dDy);
m_pOut->UpdateTextPos(m_pGState);
m_pOut->BeginStringOperator(m_pGState);
DoShowText(arrArguments[0].GetString());
m_pOut->EndStringOperator(m_pGState);
}
// \
void Graphics::OperatorMoveSetShowText(Object arrArguments[], int nArgumentsCount)
{
if (m_pGState->GetFont())
{
// TO DO: Error "No font in move/set/show"
return;
}
if (m_bFontChanged)
{
m_pOut->UpdateFont(m_pGState);
m_bFontChanged = false;
}
m_pGState->SetWordSpace(arrArguments[0].GetNum());
m_pGState->SetCharSpace(arrArguments[1].GetNum());
double dDx = m_pGState->GetTextLineX();
double dDy = m_pGState->GetTextLineY() - m_pGState->GetLeading();
m_pGState->TextMoveTo(dDx, dDy);
m_pOut->UpdateWordSpace(m_pGState);
m_pOut->UpdateCharSpace(m_pGState);
m_pOut->UpdateTextPos(m_pGState);
m_pOut->BeginStringOperator(m_pGState);
DoShowText(arrArguments[2].GetString());
m_pOut->EndStringOperator(m_pGState);
}
// TJ
void Graphics::OperatorShowSpaceText(Object arrArguments[], int nArgumentsCount)
{
if (!m_pGState->GetFont())
{
// TO DO: Error "No font in show/space"
return;
}
if (m_bFontChanged)
{
m_pOut->UpdateFont(m_pGState);
m_bFontChanged = false;
}
m_pOut->BeginStringOperator(m_pGState);
int nWMode = m_pGState->GetFont()->GetWMode();
Array *pArray = arrArguments[0].GetArray();
for (int nIndex = 0; nIndex < pArray->GetCount(); ++nIndex)
{
Object oTemp;
pArray->Get(nIndex, &oTemp);
if (oTemp.IsNum())
{
if (nWMode)
{
m_pGState->TextShift(0, -oTemp.GetNum() * 0.001 * fabs(m_pGState->GetFontSize()));
}
else
{
m_pGState->TextShift(-oTemp.GetNum() * 0.001 * fabs(m_pGState->GetFontSize()), 0);
}
m_pOut->UpdateTextShift(m_pGState, oTemp.GetNum());
}
else if (oTemp.IsString())
{
DoShowText(oTemp.GetString());
}
else
{
// TO DO: Error "Element of show/space array must be number or string"
}
oTemp.Free();
}
m_pOut->EndStringOperator(m_pGState);
}
//-------------------------------------------------------------------------------------------------------------------------------
void Graphics::DoShowText(StringExt *seString)
{
CharCode nCode;
Unicode arrUnicode[8];
double x, y, dx, dy, dx2, dy2, tdx, tdy;
double originX, originY, tOriginX, tOriginY;
char *pBuffer;
int nLen, nCurLen, uLen;
GrFont *pFont = m_pGState->GetFont();
int nWMode = pFont->GetWMode();
if (m_pOut->UseDrawChar())
{
m_pOut->BeginString(m_pGState, seString);
}
// Îáðàáîòêà øðèôòà Type 3
if (pFont->GetType() == fontType3 && m_pOut->InterpretType3Chars())
{
double *pMatrix = m_pGState->GetCTM();
double pOldCTM[6], pNewCTM[6];
for (int nIndex = 0; nIndex < 6; ++nIndex)
{
pOldCTM[nIndex] = pMatrix[nIndex];
}
pMatrix = m_pGState->GetTextMatrix();
pNewCTM[0] = pMatrix[0] * pOldCTM[0] + pMatrix[1] * pOldCTM[2];
pNewCTM[1] = pMatrix[0] * pOldCTM[1] + pMatrix[1] * pOldCTM[3];
pNewCTM[2] = pMatrix[2] * pOldCTM[0] + pMatrix[3] * pOldCTM[2];
pNewCTM[3] = pMatrix[2] * pOldCTM[1] + pMatrix[3] * pOldCTM[3];
pMatrix = pFont->GetFontMatrix();
pNewCTM[0] = pMatrix[0] * pNewCTM[0] + pMatrix[1] * pNewCTM[2];
pNewCTM[1] = pMatrix[0] * pNewCTM[1] + pMatrix[1] * pNewCTM[3];
pNewCTM[2] = pMatrix[2] * pNewCTM[0] + pMatrix[3] * pNewCTM[2];
pNewCTM[3] = pMatrix[2] * pNewCTM[1] + pMatrix[3] * pNewCTM[3];
pNewCTM[0] *= m_pGState->GetFontSize();
pNewCTM[1] *= m_pGState->GetFontSize();
pNewCTM[2] *= m_pGState->GetFontSize();
pNewCTM[3] *= m_pGState->GetFontSize();
pNewCTM[0] *= m_pGState->GetHorizScaling();
pNewCTM[2] *= m_pGState->GetHorizScaling();
double dRiseX, dRiseY;
m_pGState->TextTransformDelta(0, m_pGState->GetRise(), &dRiseX, &dRiseY);
double dCurX = m_pGState->GetCurX();
double dCurY = m_pGState->GetCurY();
double dLineX = m_pGState->GetTextLineX();
double dLineY = m_pGState->GetTextLineY();
Parser *pOldParser = m_pParser;
pBuffer = seString->GetBuffer();
nLen = seString->GetLength();
while (nLen > 0)
{
nCurLen = pFont->GetNextChar(pBuffer, nLen, &nCode, arrUnicode, (int)(sizeof(arrUnicode) / sizeof(Unicode)), &uLen, &dx, &dy, &originX, &originY);
dx = dx * m_pGState->GetFontSize() + m_pGState->GetCharSpace();
if (nCurLen == 1 && *pBuffer == ' ')
{
dx += m_pGState->GetWordSpace();
}
dx *= m_pGState->GetHorizScaling();
dy *= m_pGState->GetFontSize();
m_pGState->TextTransformDelta(dx, dy, &tdx, &tdy);
m_pGState->Transform(dCurX + dRiseX, dCurY + dRiseY, &x, &y);
SaveGState();
m_pGState->SetCTM(pNewCTM[0], pNewCTM[1], pNewCTM[2], pNewCTM[3], x, y);
//Çíà÷åíèÿ CTM concat çäåñü íåïðàâèëüíûå (íî îíè íèêîãäà íå èñïîëüçóþòñÿ)
m_pOut->UpdateCTM(m_pGState, 1, 0, 0, 1, 0, 0);
if (!m_pOut->BeginType3Char(m_pGState, dCurX + dRiseX, dCurY + dRiseY, tdx, tdy, nCode, arrUnicode, uLen))
{
Object oCharProc;
((Gr8BitFont *)pFont)->GetCharProc(nCode, &oCharProc);
Dict *pResourcesDict;
if ((pResourcesDict = ((Gr8BitFont *)pFont)->GetResources()))
{
PushResources(pResourcesDict);
}
if (oCharProc.IsStream())
{
Display(&oCharProc, false);
}
else
{
// TO DO: Error "Missing or bad Type3 CharProc entry"
}
m_pOut->EndType3Char(m_pGState);
if (pResourcesDict)
{
PopResources();
}
oCharProc.Free();
}
RestoreGState();
// Ïîñêîëüêó ôóíêöèÿ RestoreGState() íå âîññòàíàâëèâàåò òåêóùåé ïîçèöèè,
// ïîýòîìó íàì íóæíî ñîõðàíÿòü è âîññòàíàâëèâàòü åå ñàìèì
dCurX += tdx;
dCurY += tdy;
m_pGState->MoveTo(dCurX, dCurY);
m_pGState->TextSetPos(dLineX, dLineY);
pBuffer += nCurLen;
nLen -= nCurLen;
}
m_pParser = pOldParser;
}
else if (m_pOut->UseDrawChar())
{
double dRiseX, dRiseY;
m_pGState->TextTransformDelta(0, m_pGState->GetRise(), &dRiseX, &dRiseY);
pBuffer = seString->GetBuffer();
nLen = seString->GetLength();
while (nLen > 0)
{
nCurLen = pFont->GetNextChar(pBuffer, nLen, &nCode, arrUnicode, (int)(sizeof(arrUnicode) / sizeof(Unicode)), &uLen, &dx, &dy, &originX, &originY);
if (nWMode)
{
dx *= m_pGState->GetFontSize();
dy = dy * m_pGState->GetFontSize() + m_pGState->GetCharSpace();
if (nCurLen == 1 && *pBuffer == ' ')
{
dy += m_pGState->GetWordSpace();
}
}
else
{
dx = dx * m_pGState->GetFontSize() + m_pGState->GetCharSpace();
if (nCurLen == 1 && *pBuffer == ' ')
{
dx += m_pGState->GetWordSpace();
}
dx *= m_pGState->GetHorizScaling();
dy *= m_pGState->GetFontSize();
}
m_pGState->TextTransformDelta(dx, dy, &tdx, &tdy);
originX *= m_pGState->GetFontSize();
originY *= m_pGState->GetFontSize();
m_pGState->TextTransformDelta(originX, originY, &tOriginX, &tOriginY);
m_pOut->DrawChar(m_pGState, m_pGState->GetCurX() + dRiseX, m_pGState->GetCurY() + dRiseY, tdx, tdy, tOriginX, tOriginY, nCode, nCurLen, arrUnicode, uLen);
m_pGState->Shift(tdx, tdy);
pBuffer += nCurLen;
nLen -= nCurLen;
}
}
else
{
dx = dy = 0;
pBuffer = seString->GetBuffer();
nLen = seString->GetLength();
int nCharsCount = 0, nSpacesCount = 0;
while (nLen > 0)
{
nCurLen = pFont->GetNextChar(pBuffer, nLen, &nCode, arrUnicode, (int)(sizeof(arrUnicode) / sizeof(Unicode)), &uLen, &dx2, &dy2, &originX, &originY);
dx += dx2;
dy += dy2;
if (nCurLen == 1 && *pBuffer == ' ')
{
++nSpacesCount;
}
++nCharsCount;
pBuffer += nCurLen;
nLen -= nCurLen;
}
if (nWMode)
{
dx *= m_pGState->GetFontSize();
dy = dy * m_pGState->GetFontSize() + nCharsCount * m_pGState->GetCharSpace() + nSpacesCount * m_pGState->GetWordSpace();
}
else
{
dx = dx * m_pGState->GetFontSize() + nCharsCount * m_pGState->GetCharSpace() + nSpacesCount * m_pGState->GetWordSpace();
dx *= m_pGState->GetHorizScaling();
dy *= m_pGState->GetFontSize();
}
m_pGState->TextTransformDelta(dx, dy, &tdx, &tdy);
m_pOut->DrawString(m_pGState, seString);
m_pGState->Shift(tdx, tdy);
}
if (m_pOut->UseDrawChar())
{
m_pOut->EndString(m_pGState);
}
m_nUpdateLevel += 10 * seString->GetLength();
}
//-------------------------------------------------------------------------------------------------------------------------------
// XObjects
//-------------------------------------------------------------------------------------------------------------------------------
// Do
void Graphics::OperatorXObject(Object arrArguments[], int nArgumentsCount)
{
char *sName = arrArguments[0].GetName();
Object oXObject;
if (!m_pResources->LookupXObject(sName, &oXObject))
{
return;
}
if (!oXObject.IsStream())
{
// TO DO: Error "XObject is wrong type"
oXObject.Free();
return;
}
#if OPI_SUPPORT
Object oOPI;
oXObject.streamGetDict()->lookup("OPI", &oOPI);
if ( oOPI.IsDict() )
{
m_pOut->opiBegin( state, oOPI.GetDict() );
}
#endif
Object oSub;
oXObject.StreamGetDict()->Search("Subtype", &oSub);
if (oSub.IsName("Image"))
{
if (m_pOut->NeedNonText())
{
Object oRef;
m_pResources->LookupAndCopyXObject(sName, &oRef);
DoImage(&oRef, oXObject.GetStream(), false);
oRef.Free();
}
}
else if (oSub.IsName("Form"))
{
Object oRef;
m_pResources->LookupAndCopyXObject(sName, &oRef);
if (m_pOut->UseDrawForm() && oRef.IsRef())
{
m_pOut->DrawForm(oRef.GetRef());
}
else
{
DoForm(&oXObject);
}
oRef.Free();
}
else if (oSub.IsName("PS"))
{
Object oLevel;
oXObject.StreamGetDict()->Search("Level1", &oLevel);
m_pOut->PSXObject(oXObject.GetStream(), oLevel.IsStream() ? oLevel.GetStream() : (Stream *)NULL);
// Äîáàâëåííî
oLevel.Free();
}
else if (oSub.IsName())
{
// TO DO: Error "Unknown XObject subtype"
}
else
{
// TO DO: Error "XObject subtype is missing or wrong type"
}
oSub.Free();
#if OPI_SUPPORT
if ( oOPI.IsDict() )
{
m_pOut->opiEnd( state, oOPI.GetDict() );
}
oOPI.Free();
#endif
oXObject.Free();
}
void Graphics::DoImage(Object *pRef, Stream *pStream, bool bInlineImage)
{
// Ñ÷èòûâàåì èíôîðìàöèþ èç ïîòîêà
int nBitsPerComponent = 0;
StreamColorSpaceMode eCSMode = streamCSNone;
pStream->GetImageParams(&nBitsPerComponent, &eCSMode);
Dict *pDict = pStream->GetDict();
// Width
Object oDictItem;
pDict->Search("Width", &oDictItem);
if (oDictItem.IsNull())
{
oDictItem.Free();
pDict->Search("W", &oDictItem);
}
if (!oDictItem.IsInt())
{
oDictItem.Free();
// TO DO: Error "Bad image parameters"
return;
}
int nWidth = oDictItem.GetInt();
oDictItem.Free();
// Height
pDict->Search("Height", &oDictItem);
if (oDictItem.IsNull())
{
oDictItem.Free();
pDict->Search("H", &oDictItem);
}
if (!oDictItem.IsInt())
{
oDictItem.Free();
// TO DO: Error "Bad image parameters"
return;
}
int nHeight = oDictItem.GetInt();
oDictItem.Free();
// Ïðîâåðÿåì: ìîæåò áûòü ýòî ìàñêà?
pDict->Search("ImageMask", &oDictItem);
if (oDictItem.IsNull())
{
oDictItem.Free();
pDict->Search("IM", &oDictItem);
}
bool bMask = false;
if (oDictItem.IsBool())
{
bMask = oDictItem.GetBool();
}
else if (!oDictItem.IsNull())
{
oDictItem.Free();
// TO DO: Error "Bad image parameters"
return;
}
oDictItem.Free();
// BitsPerComponent
if (nBitsPerComponent == 0)
{
pDict->Search("BitsPerComponent", &oDictItem);
if (oDictItem.IsNull())
{
oDictItem.Free();
pDict->Search("BPC", &oDictItem);
}
if (oDictItem.IsInt())
{
nBitsPerComponent = oDictItem.GetInt();
}
else if (bMask)
{
nBitsPerComponent = 1;
}
else
{
oDictItem.Free();
// TO DO: Error "Bad image parameters"
return;
}
oDictItem.Free();
}
if (bMask)
{
// Ó ìàñêè ýòî çíà÷åíèå nBitsPerComponent äîëæíî áûòü 1
if (nBitsPerComponent != 1)
{
// TO DO: Error "Bad image parameters"
return;
}
bool bInvert = false;
pDict->Search("Decode", &oDictItem);
if (oDictItem.IsNull())
{
oDictItem.Free();
pDict->Search("D", &oDictItem);
}
if (oDictItem.IsArray())
{
Object oTemp;
oDictItem.ArrayGet(0, &oTemp);
if (oTemp.IsInt() && oTemp.GetInt() == 1)
bInvert = true;
oTemp.Free();
}
else if (!oDictItem.IsNull())
{
oDictItem.Free();
// TO DO: Error "Bad image parameters"
return;
}
oDictItem.Free();
// Ðèñóåì ìàñêó
m_pOut->DrawImageMask(m_pGState, pRef, pStream, nWidth, nHeight, bInvert, bInlineImage);
}
else
{
// ColorSpace
pDict->Search("ColorSpace", &oDictItem);
if (oDictItem.IsNull())
{
oDictItem.Free();
pDict->Search("CS", &oDictItem);
}
if (oDictItem.IsName())
{
Object oTemp;
m_pResources->LookupColorSpace(oDictItem.GetName(), &oTemp);
if (!oTemp.IsNull())
{
oDictItem.Free();
oDictItem = oTemp;
}
else
{
oTemp.Free();
}
}
GrColorSpace *pColorSpace;
if (!oDictItem.IsNull())
{
pColorSpace = GrColorSpace::Parse(&oDictItem);
}
else if (eCSMode == streamCSDeviceGray)
{
pColorSpace = new GrDeviceGrayColorSpace();
}
else if (eCSMode == streamCSDeviceRGB)
{
pColorSpace = new GrDeviceRGBColorSpace();
}
else if (eCSMode == streamCSDeviceCMYK)
{
pColorSpace = new GrDeviceCMYKColorSpace();
}
else
{
pColorSpace = NULL;
}
oDictItem.Free();
if (!pColorSpace)
{
// TO DO: Error "Bad image parameters"
return;
}
// Decode
pDict->Search("Decode", &oDictItem);
if (oDictItem.IsNull())
{
oDictItem.Free();
pDict->Search("D", &oDictItem);
}
GrImageColorMap *pColorMap = new GrImageColorMap(nBitsPerComponent, &oDictItem, pColorSpace);
oDictItem.Free();
if (!pColorMap->IsValid())
{
delete pColorMap;
// TO DO: Error "Bad image parameters"
return;
}
// Mask/SMask
bool bHaveColorKeyMask = false, bHaveExplicitMask = false, bHaveSoftMask = false;
Stream *pMaskStream = NULL;
int nMaskWidth = 0, nMaskHeight = 0;
bool bMaskInvert = false;
GrImageColorMap *pMaskColorMap = NULL;
int arrMaskColors[2 * GrColorMaxComps];
Object oMask, oSMask;
pDict->Search("Mask", &oMask);
pDict->Search("SMask", &oSMask);
Dict *pMaskDict = NULL;
if (oSMask.IsStream())
{
if (bInlineImage)
{
// Òóò íàâåðíîå íóæíî îñâîáîäèòü ïàìÿòü oMask, oSMask
// TO DO: Error "Bad image parameters"
return;
}
pMaskStream = oSMask.GetStream();
pMaskDict = oSMask.StreamGetDict();
// Width
pMaskDict->Search("Width", &oDictItem);
if (oDictItem.IsNull())
{
oDictItem.Free();
pMaskDict->Search("W", &oDictItem);
}
if (!oDictItem.IsInt())
{
oDictItem.Free();
// TO DO: Error "Bad image parameters"
return;
}
nMaskWidth = oDictItem.GetInt();
oDictItem.Free();
// Height
pMaskDict->Search("Height", &oDictItem);
if (oDictItem.IsNull())
{
oDictItem.Free();
pMaskDict->Search("H", &oDictItem);
}
if (!oDictItem.IsInt())
{
oDictItem.Free();
// TO DO: Error "Bad image parameters"
return;
}
nMaskHeight = oDictItem.GetInt();
oDictItem.Free();
// BitsPerComponent
pMaskDict->Search("BitsPerComponent", &oDictItem);
if (oDictItem.IsNull())
{
oDictItem.Free();
pMaskDict->Search("BPC", &oDictItem);
}
if (!oDictItem.IsInt())
{
oDictItem.Free();
// TO DO: Error "Bad image parameters"
return;
}
int nMaskBitsPerComponent = oDictItem.GetInt();
oDictItem.Free();
// ColorSpace
pMaskDict->Search("ColorSpace", &oDictItem);
if (oDictItem.IsNull())
{
oDictItem.Free();
pMaskDict->Search("CS", &oDictItem);
}
if (oDictItem.IsName())
{
Object oTemp;
m_pResources->LookupColorSpace(oDictItem.GetName(), &oTemp);
if (!oTemp.IsNull())
{
oDictItem.Free();
oDictItem = oTemp;
}
else
{
oTemp.Free();
}
}
GrColorSpace *pMaskColorSpace = GrColorSpace::Parse(&oDictItem);
oDictItem.Free();
if (!pMaskColorSpace || pMaskColorSpace->GetMode() != csDeviceGray)
{
// TO DO: Error "Bad image parameters"
return;
}
// Decode
pMaskDict->Search("Decode", &oDictItem);
if (oDictItem.IsNull())
{
oDictItem.Free();
pMaskDict->Search("D", &oDictItem);
}
pMaskColorMap = new GrImageColorMap(nMaskBitsPerComponent, &oDictItem, pMaskColorSpace);
oDictItem.Free();
if (!pMaskColorMap->IsValid())
{
delete pMaskColorMap;
// TO DO: Error "Bad image parameters"
return;
}
bHaveSoftMask = true;
}
else if (oMask.IsArray())
{
for (int nIndex = 0; nIndex < oMask.ArrayGetLength() && nIndex < 2 * GrColorMaxComps; ++nIndex)
{
Object oTemp;
oMask.ArrayGet(nIndex, &oTemp);
arrMaskColors[nIndex] = oTemp.GetInt();
oTemp.Free();
}
bHaveColorKeyMask = true;
}
else if (oMask.IsStream())
{
if (bInlineImage)
{
// TO DO: Error "Bad image parameters"
return;
}
pMaskStream = oMask.GetStream();
pMaskDict = oMask.StreamGetDict();
// Width
pMaskDict->Search("Width", &oDictItem);
if (oDictItem.IsNull())
{
oDictItem.Free();
pMaskDict->Search("W", &oDictItem);
}
if (!oDictItem.IsInt())
{
oDictItem.Free();
// TO DO: Error "Bad image parameters"
return;
}
nMaskWidth = oDictItem.GetInt();
oDictItem.Free();
// Height
pMaskDict->Search("Height", &oDictItem);
if (oDictItem.IsNull())
{
oDictItem.Free();
pMaskDict->Search("H", &oDictItem);
}
if (!oDictItem.IsInt())
{
oDictItem.Free();
// TO DO: Error "Bad image parameters"
return;
}
nMaskHeight = oDictItem.GetInt();
oDictItem.Free();
// ImageMask
pMaskDict->Search("ImageMask", &oDictItem);
if (oDictItem.IsNull())
{
oDictItem.Free();
pMaskDict->Search("IM", &oDictItem);
}
if (!oDictItem.IsBool() || !oDictItem.GetBool())
{
oDictItem.Free();
// TO DO: Error "Bad image parameters"
return;
}
oDictItem.Free();
// Decode
bMaskInvert = false;
pMaskDict->Search("Decode", &oDictItem);
if (oDictItem.IsNull())
{
oDictItem.Free();
pMaskDict->Search("D", &oDictItem);
}
if (oDictItem.IsArray())
{
Object oTemp;
oDictItem.ArrayGet(0, &oTemp);
if (oTemp.IsInt() && oTemp.GetInt() == 1)
{
bMaskInvert = true;
}
oTemp.Free();
}
else if (!oDictItem.IsNull())
{
oDictItem.Free();
// TO DO: Error "Bad image parameters"
return;
}
oDictItem.Free();
bHaveExplicitMask = true;
}
// Ðèñóåì
if (bHaveSoftMask)
{
m_pOut->DrawSoftMaskedImage(m_pGState, pRef, pStream, nWidth, nHeight, pColorMap, pMaskStream, nMaskWidth, nMaskHeight, pMaskColorMap);
delete pMaskColorMap;
}
else if (bHaveExplicitMask)
{
m_pOut->DrawMaskedImage(m_pGState, pRef, pStream, nWidth, nHeight, pColorMap, pMaskStream, nMaskWidth, nMaskHeight, bMaskInvert);
}
else
{
m_pOut->DrawImage(m_pGState, pRef, pStream, nWidth, nHeight, pColorMap, bHaveColorKeyMask ? arrMaskColors : (int *)NULL, bInlineImage);
}
delete pColorMap;
oMask.Free();
oSMask.Free();
}
int nUpdater = 0;
if ((nUpdater = nWidth * nHeight) > 1000)
{
nUpdater = 1000;
}
m_nUpdateLevel += nUpdater;
return;
}
void Graphics::DoForm(Object *pStream)
{
double arrMatrix[6], arrBBox[4];
// Ïðîâåðÿåì ãëóáèíó ðåêóðñèè
if (m_nFormDepth > 20)
{
return;
}
Dict *pDict = pStream->StreamGetDict();
Object oDictItem;
// FormType
pDict->Search("FormType", &oDictItem);
if (!(oDictItem.IsNull() || (oDictItem.IsInt() && oDictItem.GetInt() == 1)))
{
// TO DO: Error "Unknown form type"
}
oDictItem.Free();
// BBox
Object oBBox;
pDict->Search("BBox", &oBBox);
if (!oBBox.IsArray())
{
oBBox.Free();
// TO DO: Error "Bad form bounding box"
return;
}
for (int nIndex = 0; nIndex < 4; ++nIndex)
{
Object oTemp;
oBBox.ArrayGet(nIndex, &oTemp);
arrBBox[nIndex] = oTemp.GetNum();
oTemp.Free();
}
oBBox.Free();
// Matrix
Object oMatrix;
pDict->Search("Matrix", &oMatrix);
if (oMatrix.IsArray())
{
for (int nIndex = 0; nIndex < 6; ++nIndex)
{
Object oTemp;
oMatrix.ArrayGet(nIndex, &oTemp);
arrMatrix[nIndex] = oTemp.GetNum();
oTemp.Free();
}
}
else
{
arrMatrix[0] = 1; arrMatrix[1] = 0;
arrMatrix[2] = 0; arrMatrix[3] = 1;
arrMatrix[4] = 0; arrMatrix[5] = 0;
}
oMatrix.Free();
// Resources
Object oResources;
pDict->Search("Resources", &oResources);
Dict *pResourcesDict = oResources.IsDict() ? oResources.GetDict() : (Dict *)NULL;
// Transparency Group
bool bTranspGroup = false, bIsolated = false, bKnockout = false;
GrColorSpace *pBlendingColorSpace = NULL;
if (pDict->Search("Group", &oDictItem)->IsDict())
{
Object oTransp;
if (oDictItem.DictLookup("S", &oTransp)->IsName("Transparency"))
{
bTranspGroup = true;
Object oTemp;
if (!oDictItem.DictLookup("CS", &oTemp)->IsNull())
{
pBlendingColorSpace = GrColorSpace::Parse(&oTemp);
}
oTemp.Free();
if (oDictItem.DictLookup("I", &oTemp)->IsBool())
{
bIsolated = oTemp.GetBool();
}
oTemp.Free();
if (oDictItem.DictLookup("K", &oTemp)->IsBool())
{
bKnockout = oTemp.GetBool();
}
oTemp.Free();
}
oTransp.Free();
}
oDictItem.Free();
// Ðèñóåì
++m_nFormDepth;
DoForm(pStream, pResourcesDict, arrMatrix, arrBBox, bTranspGroup, false, pBlendingColorSpace, bIsolated, bKnockout);
--m_nFormDepth;
if (pBlendingColorSpace)
{
delete pBlendingColorSpace;
}
oResources.Free();
}
void Graphics::DoForm(Object *pStream, Dict *pResourcesDict, double *pMatrix, double *pBBox, bool bTranspGroup, bool bSMask, GrColorSpace *pBlendingColorSpace, bool bIsolated, bool bKnockout, bool bAlpha, Function *pTransferFunctions, GrColor *pBackdropColor)
{
// Çàïèñûâàåì òåêóùóþ äèðåêòîðèþ ðåñóðñîâ â ñòåê
PushResources(pResourcesDict);
// Ñîõðàíÿåì òåêóùèé GState
SaveGState();
// Î÷èùàåì Path(åñëè òàì ÷òî-òî áûëî)
m_pGState->ClearPath();
// Ñîõðàíÿåì òåêóùèé ïàðñåð
Parser *pOldParser = m_pParser;
// CTM
m_pGState->ConcatCTM(pMatrix[0], pMatrix[1], pMatrix[2], pMatrix[3], pMatrix[4], pMatrix[5]);
m_pOut->UpdateCTM(m_pGState, pMatrix[0], pMatrix[1], pMatrix[2], pMatrix[3], pMatrix[4], pMatrix[5]);
// BBox
m_pGState->MoveTo(pBBox[0], pBBox[1]);
m_pGState->LineTo(pBBox[2], pBBox[1]);
m_pGState->LineTo(pBBox[2], pBBox[3]);
m_pGState->LineTo(pBBox[0], pBBox[3]);
m_pGState->ClosePath();
m_pGState->Clip();
m_pGState->GetClip()->ClipToPath(m_pGState->GetPath()->Copy(), m_pGState->GetCTM(), false);
if (m_pOut->UseClipTo())
m_pOut->ClipToPath(m_pGState, m_pGState->GetPath(), m_pGState->GetCTM(), false);
else
m_pOut->Clip(m_pGState);
m_pGState->ClearPath();
if (bSMask || bTranspGroup)
{
if (m_pGState->GetBlendMode() != grBlendNormal)
{
m_pGState->SetBlendMode(grBlendNormal);
m_pOut->UpdateBlendMode(m_pGState);
}
if (!m_pOut->UseSimpleTransparentGroup())
{
if (m_pGState->GetFillOpacity() != 1)
{
m_pGState->SetFillOpacity(1);
m_pOut->UpdateFillOpacity(m_pGState);
}
if (m_pGState->GetStrokeOpacity() != 1)
{
m_pGState->SetStrokeOpacity(1);
m_pOut->UpdateStrokeOpacity(m_pGState);
}
}
m_pOut->ClearSoftMask(m_pGState);
m_pOut->BeginTransparencyGroup(m_pGState, pBBox, pBlendingColorSpace, bIsolated, bKnockout, bSMask);
}
double arrOldBaseMatrix[6];
for (int nIndex = 0; nIndex < 6; ++nIndex)
{
arrOldBaseMatrix[nIndex] = m_arrBaseMatrix[nIndex];
m_arrBaseMatrix[nIndex] = m_pGState->GetCTM()[nIndex];
}
// Ðèñóåì ñàìó ôîðìó
Display(pStream, false);
if (bSMask || bTranspGroup)
{
m_pOut->EndTransparencyGroup(m_pGState);
}
for (int nIndex = 0; nIndex < 6; ++nIndex)
{
m_arrBaseMatrix[nIndex] = arrOldBaseMatrix[nIndex];
}
// Âîññòàíàâëèâàåì íà÷àëüíûå äàííûå
m_pParser = pOldParser;
RestoreGState();
PopResources();
if (bSMask)
{
m_pOut->SetSoftMask(m_pGState, pBBox, bAlpha, pTransferFunctions, pBackdropColor);
}
else if (bTranspGroup)
{
m_pOut->PaintTransparencyGroup(m_pGState, pBBox);
}
return;
}
//-------------------------------------------------------------------------------------------------------------------------------
// Inline images
//-------------------------------------------------------------------------------------------------------------------------------
// BI
void Graphics::OperatorBeginImage(Object arrArguments[], int nArgumentsCount)
{
Stream *pStream = BuildImageStream();
if (pStream)
{
DoImage(NULL, pStream, true);
// Èùåì îïåðàòîð EI
int nChar1 = pStream->GetUndecodedStream()->GetChar();
int nChar2 = pStream->GetUndecodedStream()->GetChar();
while (!(nChar1 == 'E' && nChar2 == 'I') && nChar2 != EOF)
{
nChar1 = nChar2;
nChar2 = pStream->GetUndecodedStream()->GetChar();
}
delete pStream;
}
}
// ID
void Graphics::OperatorImageData(Object arrArguments[], int nArgumentsCount)
{
// TO DO: Error "Internal: got 'ID' operator"
}
// EI
void Graphics::OperatorEndImage(Object arrArguments[], int nArgumentsCount)
{
// TO DO: Error "Internal: got 'EI' operator"
}
//-------------------------------------------------------------------------------------------------------------------------------
Stream *Graphics::BuildImageStream()
{
Object oDict;
oDict.InitDict(m_pXref);
Object oObject;
m_pParser->GetObject(&oObject);
while (!oObject.IsCommand("ID") && !oObject.IsEOF())
{
if (!oObject.IsName())
{
// TO DO: Error "Inline image dictionary key must be a name object"
oObject.Free();
}
else
{
char* sKey = CopyString(oObject.GetName());
oObject.Free();
m_pParser->GetObject(&oObject);
if (oObject.IsEOF() || oObject.IsError())
{
MemUtilsFree(sKey);
break;
}
oDict.DictAdd(sKey, &oObject);
}
m_pParser->GetObject(&oObject);
}
if (oObject.IsEOF())
{
// TO DO: Error "End of file in inline image"
oObject.Free();
oDict.Free();
return NULL;
}
oObject.Free();
Stream *pStream = new EmbedStream(m_pParser->GetStream(), &oDict, false, 0);
pStream = pStream->AddFilters(&oDict);
return pStream;
}
//-------------------------------------------------------------------------------------------------------------------------------
// Type 3 fonts
//-------------------------------------------------------------------------------------------------------------------------------
// d0
void Graphics::OperatorSetCharWidth(Object arrArguments[], int nArgumentsCount)
{
m_pOut->Type3D0(m_pGState, arrArguments[0].GetNum(), arrArguments[1].GetNum());
}
// d1
void Graphics::OperatorSetCacheDevice(Object arrArguments[], int nArgumentsCount)
{
m_pOut->Type3D1(m_pGState, arrArguments[0].GetNum(), arrArguments[1].GetNum(), arrArguments[2].GetNum(), arrArguments[3].GetNum(), arrArguments[4].GetNum(), arrArguments[5].GetNum());
}
//-------------------------------------------------------------------------------------------------------------------------------
// Compatibility
//-------------------------------------------------------------------------------------------------------------------------------
// BX
void Graphics::OperatorBeginIgnoreUndef(Object arrArguments[], int nArgumentsCount)
{
++m_nIgnoreUndef;
}
// EX
void Graphics::OperatorEndIgnoreUndef(Object arrArguments[], int nArgumentsCount)
{
if (m_nIgnoreUndef > 0)
--m_nIgnoreUndef;
}
//-------------------------------------------------------------------------------------------------------------------------------
// Marked content
//-------------------------------------------------------------------------------------------------------------------------------
// BDC/BMC
void Graphics::OperatorBeginMarkedContent(Object arrArguments[], int nArgumentsCount)
{
}
// EMC
void Graphics::OperatorEndMarkedContent(Object arrArguments[], int nArgumentsCount)
{
}
// DP/MP
void Graphics::OperatorMarkPoint(Object arrArguments[], int nArgumentsCount)
{
}
//-------------------------------------------------------------------------------------------------------------------------------
// Äîïîëíèòåëüíûå ôóíêöèè
//-------------------------------------------------------------------------------------------------------------------------------
void Graphics::DrawAnnotation(Object *pStream, AnnotBorderStyle *pBorderStyle, double dMinX, double dMinY, double dMaxX, double dMaxY)
{
double dX, dY;
// Ïðåîáðàçîâûâàåì Annotation BBox èç ñòàíäàðòíîãî ïîëüçîâàòåëüñêîãî ïðîñòðàíñòâà â
// òåêóùåå ïîëüçîâàòåëüñêîå ïðîñòðàíñòâî: (BBox * BaseMatrix) * InvCTM
double *pCTM = m_pGState->GetCTM();
double dDet = 1 / (pCTM[0] * pCTM[3] - pCTM[1] * pCTM[2]);
double arrInvCTM[6];
arrInvCTM[0] = pCTM[3] * dDet;
arrInvCTM[1] = -pCTM[1] * dDet;
arrInvCTM[2] = -pCTM[2] * dDet;
arrInvCTM[3] = pCTM[0] * dDet;
arrInvCTM[4] = (pCTM[2] * pCTM[5] - pCTM[3] * pCTM[4]) * dDet;
arrInvCTM[5] = (pCTM[1] * pCTM[4] - pCTM[0] * pCTM[5]) * dDet;
dX = m_arrBaseMatrix[0] * dMinX + m_arrBaseMatrix[2] * dMinY + m_arrBaseMatrix[4];
dY = m_arrBaseMatrix[1] * dMinX + m_arrBaseMatrix[3] * dMinY + m_arrBaseMatrix[5];
double dAnnotX0 = arrInvCTM[0] * dX + arrInvCTM[2] * dY + arrInvCTM[4];
double dAnnotY0 = arrInvCTM[1] * dX + arrInvCTM[3] * dY + arrInvCTM[5];
dX = m_arrBaseMatrix[0] * dMaxX + m_arrBaseMatrix[2] * dMaxY + m_arrBaseMatrix[4];
dY = m_arrBaseMatrix[1] * dMaxX + m_arrBaseMatrix[3] * dMaxY + m_arrBaseMatrix[5];
double dAnnotX1 = arrInvCTM[0] * dX + arrInvCTM[2] * dY + arrInvCTM[4];
double dAnnotY1 = arrInvCTM[1] * dX + arrInvCTM[3] * dY + arrInvCTM[5];
if (dAnnotX0 > dAnnotX1)
{
dX = dAnnotX0;
dAnnotX0 = dAnnotX1;
dAnnotX1 = dX;
}
if (dAnnotY0 > dAnnotY1)
{
dY = dAnnotY0;
dAnnotY0 = dAnnotY1;
dAnnotY1 = dY;
}
if (pStream->IsStream())
{
Dict *pDict = pStream->StreamGetDict();
// BBox
Object oBBox;
pDict->Search("BBox", &oBBox);
double arrBBox[4];
if (!oBBox.IsArray())
{
oBBox.Free();
// TO DO: Error "Bad form bounding box"
return;
}
for (int nIndex = 0; nIndex < 4; ++nIndex)
{
Object oTemp;
oBBox.ArrayGet(nIndex, &oTemp);
arrBBox[nIndex] = oTemp.GetNum();
oTemp.Free();
}
oBBox.Free();
// Matrix
Object oMatrix;
pDict->Search("Matrix", &oMatrix);
double arrMatrix[6];
if (oMatrix.IsArray())
{
for (int nIndex = 0; nIndex < 6; ++nIndex)
{
Object oTemp;
oMatrix.ArrayGet(nIndex, &oTemp);
arrMatrix[nIndex] = oTemp.GetNum();
oTemp.Free();
}
}
else
{
arrMatrix[0] = 1; arrMatrix[1] = 0;
arrMatrix[2] = 0; arrMatrix[3] = 1;
arrMatrix[4] = 0; arrMatrix[5] = 0;
}
oMatrix.Free();
double dFormX0 = arrBBox[0] * arrMatrix[0] + arrBBox[1] * arrMatrix[2] + arrMatrix[4];
double dFormY0 = arrBBox[0] * arrMatrix[1] + arrBBox[1] * arrMatrix[3] + arrMatrix[5];
double dFormX1 = arrBBox[2] * arrMatrix[0] + arrBBox[3] * arrMatrix[2] + arrMatrix[4];
double dFormY1 = arrBBox[2] * arrMatrix[1] + arrBBox[3] * arrMatrix[3] + arrMatrix[5];
if (dFormX0 > dFormX1)
{
dX = dFormX0;
dFormX0 = dFormX1;
dFormX1 = dX;
}
if (dFormY0 > dFormY1)
{
dY = dFormY0;
dFormY0 = dFormY1;
dFormY1 = dY;
}
// Ðàñòÿãèâàåì äî ðàçìåðîâ Annotation BBox
double dScaleX, dScaleY;
if (dFormX1 == dFormX0)
{
// Òàêîãî íå äîëæíî áûòü
dScaleX = 1;
}
else
{
dScaleX = (dAnnotX1 - dAnnotX0) / (dFormX1 - dFormX0);
}
if (dFormY1 == dFormY0)
{
// Òàêîãî íå äîëæíî áûòü
dScaleY = 1;
}
else
{
dScaleY = (dAnnotY1 - dAnnotY0) / (dFormY1 - dFormY0);
}
arrMatrix[0] *= dScaleX;
arrMatrix[2] *= dScaleX;
arrMatrix[4] = (arrMatrix[4] - dFormX0) * dScaleX + dAnnotX0;
arrMatrix[1] *= dScaleY;
arrMatrix[3] *= dScaleY;
arrMatrix[5] = (arrMatrix[5] - dFormY0) * dScaleY + dAnnotY0;
// Resources
Object oResources;
pDict->Search("Resources", &oResources);
Dict *pResourcesDict = oResources.IsDict() ? oResources.GetDict() : (Dict *)NULL;
// Ðèñóåì
DoForm(pStream, pResourcesDict, arrMatrix, arrBBox);
oResources.Free();
}
// Ðèñóåì ðàìêó
if (pBorderStyle && pBorderStyle->GetWidth() > 0)
{
if (m_pGState->GetStrokeColorSpace()->GetMode() != csDeviceRGB)
{
m_pGState->SetStrokePattern(NULL);
m_pGState->SetStrokeColorSpace(new GrDeviceRGBColorSpace());
m_pOut->UpdateStrokeColorSpace(m_pGState);
}
double dR, dG, dB;
pBorderStyle->GetColor(&dR, &dG, &dB);
GrColor oColor;
oColor.arrComp[0] = DoubleToColor(dR);
oColor.arrComp[1] = DoubleToColor(dG);
oColor.arrComp[2] = DoubleToColor(dB);
m_pGState->SetStrokeColor(&oColor);
m_pOut->UpdateStrokeColor(m_pGState);
dX = (m_arrBaseMatrix[0] + m_arrBaseMatrix[2]) * arrInvCTM[0] + (m_arrBaseMatrix[1] + m_arrBaseMatrix[3]) * arrInvCTM[2];
dY = (m_arrBaseMatrix[0] + m_arrBaseMatrix[2]) * arrInvCTM[1] + (m_arrBaseMatrix[1] + m_arrBaseMatrix[3]) * arrInvCTM[3];
dX = sqrt(0.5 * (dX * dX + dY * dY));
m_pGState->SetLineWidth(dX * pBorderStyle->GetWidth());
m_pOut->UpdateLineWidth(m_pGState);
double *pDash;
int nDashLength;
pBorderStyle->GetDash(&pDash, &nDashLength);
if (pBorderStyle->GetType() == annotBorderDashed && nDashLength > 0)
{
double *pDashNew = (double *)MemUtilsMallocArray(nDashLength, sizeof(double));
for (int nIndex = 0; nIndex < nDashLength; ++nIndex)
{
pDashNew[nIndex] = dX * pDash[nIndex];
}
m_pGState->SetLineDash(pDashNew, nDashLength, 0);
m_pOut->UpdateLineDash(m_pGState);
}
m_pGState->ClearPath();
m_pGState->MoveTo(dAnnotX0, m_pOut->UpSideDown() ? dAnnotY1 : dAnnotY0);
m_pGState->LineTo(dAnnotX1, m_pOut->UpSideDown() ? dAnnotY1 : dAnnotY0);
if (pBorderStyle->GetType() != annotBorderUnderlined)
{
m_pGState->LineTo(dAnnotX1, m_pOut->UpSideDown() ? dAnnotY0 : dAnnotY1);
m_pGState->LineTo(dAnnotX0, m_pOut->UpSideDown() ? dAnnotY0 : dAnnotY1);
m_pGState->ClosePath();
}
m_pOut->Stroke(m_pGState);
}
}
//-------------------------------------------------------------------------------------------------------------------------------
// Ðàáîòàåì ñî ñòåêàìè GState è ResourcesDict
//-------------------------------------------------------------------------------------------------------------------------------
void Graphics::SaveGState()
{
m_pOut->SaveGState(m_pGState);
m_pGState = m_pGState->Save();
}
void Graphics::RestoreGState()
{
m_pGState = m_pGState->Restore();
m_pOut->RestoreGState(m_pGState);
}
void Graphics::PushResources(Dict *pResourcesDict)
{
m_pResources = new GrResources(m_pXref, pResourcesDict, m_pResources, m_pGlobalParams);
}
void Graphics::PopResources()
{
if (m_pResources)
{
GrResources *pResourcesNext = m_pResources->GetNext();
delete m_pResources;
m_pResources = pResourcesNext;
}
else
m_pResources = NULL;
}
}