Files
core/ASCOfficePDFReader/Graphics.cpp

5014 lines
143 KiB
C++

#include "stdafx.h"
#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"
#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
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
char sFileName[MAX_PATH];
sprintf( sFileName, "E:\\Output\\PDF Dump\\DumpPDF_Page%d.bin", nPageNumber );
m_pDumpFile = NULL;
m_pDumpFile = ::fopen( sFileName, "wb" );
#endif
m_pGlobalParams = pGlobalParams;
m_pXref = pXref;
m_bSubPage = FALSE;
m_bPrintCommands = ( m_pGlobalParams ? m_pGlobalParams->GetPrintCommands() : 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;
m_bPrintCommands = ( m_pGlobalParams ? m_pGlobalParams->GetPrintCommands() : FALSE );
// 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 );
}
//if ( m_bPrintCommands )
//{
// oTemp.Print( stdout );
// for ( int nIndex = 0; nIndex < nArgumentsCount; ++nIndex )
// {
// printf(" ");
// arrArguments[nIndex].Print(stdout);
// }
// printf("\n");
// fflush(stdout);
//}
#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 );
}
//if ( m_bPrintCommands )
//{
// printf("throwing away arg: ");
// oTemp.Print(stdout);
// printf("\n");
// fflush(stdout);
//}
#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 );
}
//if ( m_bPrintCommands )
//{
// printf("%d leftovers:", nArgumentsCount);
// for ( int nIndex = 0; nIndex < nArgumentsCount; ++nIndex )
// {
// printf(" ");
// arrArguments[nIndex].Print(stdout);
// }
// printf("\n");
// fflush(stdout);
//}
#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;
}
if ( m_bPrintCommands )
{
//printf(" gfx state dict: ");
//oDict.Print();
//printf("\n");
}
// Ïðîçðà÷íîñòü
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
{
bool bIsSupportSmartTiling = m_pOut->IsSupportFuture(_T("TilingHtmlPattern"));
if (true == bIsSupportSmartTiling)
{
m_pOut->ClipAttack(m_pGState);
m_pOut->BeginCommand(c_nPDFTilingFill);
CString strXml = _T("");
strXml.Format(_T("<htmltiling x=\"%.2lf\" y=\"%.2lf\" countx=\"%.2lf\" county=\"%.2lf\" stepx=\"%.2lf\" stepy=\"%.2lf\">\
<bbox x=\"%.2lf\" y=\"%.2lf\" r=\"%.2lf\" b=\"%.2lf\" />\
<transform m1=\"%.2lf\" m2=\"%.2lf\" m3=\"%.2lf\" m4=\"%.2lf\" m5=\"%.2lf\" m6=\"%.2lf\" />\
</htmltiling>"), nX0, nY0, nX1 - nX0, nY1 - nY0, dStepX, dStepY,
dXMin, dYMin, dXMax, dYMax,
pTempMatrix[0], pTempMatrix[1], pTempMatrix[2], pTempMatrix[3], pTempMatrix[4], pTempMatrix[5]);
VARIANT var;
var.vt = VT_BSTR;
var.bstrVal = strXml.AllocSysString();
m_pOut->SetAdditionalParam(_T("TilingHtmlPattern"), var);
SysFreeString(var.bstrVal);
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->EndCommand(c_nPDFTilingFill);
}
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->BeginCommand(c_nPDFTilingFillIteration);
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->EndCommand(c_nPDFTilingFillIteration);
}
}
}
}
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 );
}
//if ( m_bPrintCommands )
//{
// printf(" font: tag=%s name='%s' %g\n", pFont->GetTag()->GetBuffer(), pFont->GetBaseName() ? pFont->GetBaseName()->GetBuffer() : "???", arrArguments[1].GetNum());
// fflush(stdout);
//}
#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)
{
if ( m_bPrintCommands )
{
//printf(" marked content: %s ", arrArguments[0].GetName());
//if ( nArgumentsCount == 2)
// arrArguments[2].Print(stdout);
//printf("\n");
//fflush(stdout);
}
}
// EMC
void Graphics::OperatorEndMarkedContent(Object arrArguments[], int nArgumentsCount)
{
}
// DP/MP
void Graphics::OperatorMarkPoint(Object arrArguments[], int nArgumentsCount)
{
if ( m_bPrintCommands )
{
//printf(" mark point: %s ", arrArguments[0].GetName());
//if ( nArgumentsCount == 2 )
// arrArguments[2].Print(stdout);
//printf("\n");
//fflush(stdout);
}
}
//-------------------------------------------------------------------------------------------------------------------------------
// Äîïîëíèòåëüíûå ôóíêöèè
//-------------------------------------------------------------------------------------------------------------------------------
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;
}