Files
core/ASCOfficePDFReader/SImage.cpp
Oleg.Korshul 9c419c93e4 (1.0.0.74) ASC version full
git-svn-id: svn://fileserver/activex/AVS/Sources/TeamlabOffice/trunk/ServerComponents@52670 954022d7-b5bf-4e40-9824-e11837661b57
2016-05-20 22:31:30 +03:00

3132 lines
83 KiB
C++

#include "stdafx.h"
#include "../Common/PaintStruct.h"
#include <stdlib.h>
#include <string.h>
#include "MemoryUtils.h"
#include "SErrorCodes.h"
#include "SMathExt.h"
#include "SBitmap.h"
#include "SState.h"
#include "SPath.h"
#include "SXPath.h"
#include "SXPathScanner.h"
#include "SPattern.h"
#include "SScreen.h"
#include "SFont.h"
#include "SGlyphBitmap.h"
#include "SImage.h"
//-------------------------------------------------------------------------------------------------------------------------------
// Ðàññòîÿíèå îò öåíòðà äî êîíòðîëüíûõ òî÷åê Áåçüå äëÿ àïïðîêñèìàöèè îêðóæíîñòè = (4 * (sqrt(2) - 1) / 3) * r
static const double c_dKappa = ((double)0.55228475);
static const double c_dKappa_2 = ((double)(0.5 * 0.55228475));
// Äåëèì 16-áèòíîå çíà÷åíèå [0, 255*255] íà 255, âîçâðàùàåì 8-áèòíîå çíà÷åíèå.
static inline unsigned char Div255(int nValue)
{
return (unsigned char)((nValue + (nValue >> 8) + 0x80) >> 8);
}
//-------------------------------------------------------------------------------------------------------------------------------
// SPipe
//-------------------------------------------------------------------------------------------------------------------------------
#define PipeMaxStages 9
struct SPipe
{
int nX; // Êîîðäèíàòû
int nY; //
SPattern *pPattern; // Source Pattern
double dAlphaInput; //
BOOL bUsesShape; //
unsigned char unAlphaSrc; // Source Alpha
SColorPointer pColorSrc; // Source Color
SColor arrColorSrcVal; //
unsigned char *pAlpha0; // Àëüôà-êàíàë äëÿ Non-isolated ãðóïï
SColorPointer pSMask; // Soft Mask
SColorPointer pColorDst; // Destination Color
int nColorMaskDst; // Destination Color Mask
unsigned char *pAlphaDst; // Destination Alpha
double dShape; // Shape
BOOL bNoTransparency; //
int nNonIsolatedGroup;// Non-isolated group correction
SPipeResultColorCtrl eResultColorCtrl;
};
SPipeResultColorCtrl SImage::m_arrePipeResultColorNoAlphaBlend[] =
{
PipeResultColorNoAlphaBlendMono, // 1 bit
PipeResultColorNoAlphaBlendMono, // 8 bit
PipeResultColorNoAlphaBlendRGB, // 24 bit RGB
PipeResultColorNoAlphaBlendRGB // 24 bit BGR
};
SPipeResultColorCtrl SImage::m_arrePipeResultColorAlphaNoBlend[] =
{
PipeResultColorAlphaNoBlendMono, // 1 bit
PipeResultColorAlphaNoBlendMono, // 8 bit
PipeResultColorAlphaNoBlendRGB, // 24 bit RGB
PipeResultColorAlphaNoBlendRGB
};
SPipeResultColorCtrl SImage::m_arrePipeResultColorAlphaBlend[] =
{
PipeResultColorAlphaBlendMono, // 1 bit
PipeResultColorAlphaBlendMono, // 8 bit
PipeResultColorAlphaBlendRGB, // 24 bit RGB
PipeResultColorAlphaBlendRGB // 24 bit BGR
};
//-------------------------------------------------------------------------------------------------------------------------------
static void BlendXor(SColorPointer pSrc, SColorPointer pDest, SColorPointer pBlend, SColorMode eColorMode)
{
for ( int nIndex = 0; nIndex < SColorModeNComps[eColorMode]; ++nIndex )
{
pBlend[nIndex] = pSrc[nIndex] ^ pDest[nIndex];
}
}
//-------------------------------------------------------------------------------------------------------------------------------
// Modified Region
//-------------------------------------------------------------------------------------------------------------------------------
void SImage::ClearModRegion()
{
m_nModRegMinX = m_pBitmap->GetWidth();
m_nModRegMinY = m_pBitmap->GetHeight();
m_nModRegMaxX = -1;
m_nModRegMaxY = -1;
}
inline void SImage::UpdateModX(int nX)
{
if ( nX < m_nModRegMinX )
{
m_nModRegMinX = nX;
}
if ( nX > m_nModRegMaxX )
{
m_nModRegMaxX = nX;
}
}
inline void SImage::UpdateModY(int nY)
{
if ( nY < m_nModRegMinY )
{
m_nModRegMinY = nY;
}
if ( nY > m_nModRegMaxY )
{
m_nModRegMaxY = nY;
}
}
//-------------------------------------------------------------------------------------------------------------------------------
// Pipeline
//-------------------------------------------------------------------------------------------------------------------------------
inline void SImage::PipeInit(SPipe *pPipe, int nX, int nY, SPattern *pPattern, SColorPointer pColorSrc, double dAlphaInput, BOOL bUsesShape, BOOL bNonIsolatedGroup)
{
PipeSetXY( pPipe, nX, nY );
pPipe->pPattern = NULL;
// Source color
if ( pPattern )
{
if ( pPattern->IsStatic() )
{
pPattern->GetColor( nX, nY, pPipe->arrColorSrcVal );
}
else
{
pPipe->pPattern = pPattern;
}
pPipe->pColorSrc = pPipe->arrColorSrcVal;
}
else
{
pPipe->pColorSrc = pColorSrc;
}
// Source alpha
pPipe->dAlphaInput = dAlphaInput;
if ( !m_pState->m_pSoftMask )
{
if ( bUsesShape )
{
pPipe->dAlphaInput *= 255;
}
else
{
pPipe->unAlphaSrc = (unsigned char)round( pPipe->dAlphaInput * 255 );
}
}
pPipe->bUsesShape = bUsesShape;
// Result Alpha
if ( dAlphaInput == 1 && !m_pState->m_pSoftMask && !bUsesShape && !m_pState->m_bInNonIsolatedGroup )
{
pPipe->bNoTransparency = TRUE;
}
else
{
pPipe->bNoTransparency = FALSE;
}
// Result Color
if ( pPipe->bNoTransparency )
{
pPipe->eResultColorCtrl = m_arrePipeResultColorNoAlphaBlend[m_pBitmap->m_eMode];
}
else if ( !m_pState->m_pBlendFunction )
{
pPipe->eResultColorCtrl = m_arrePipeResultColorAlphaNoBlend[m_pBitmap->m_eMode];
}
else
{
pPipe->eResultColorCtrl = m_arrePipeResultColorAlphaBlend[m_pBitmap->m_eMode];
}
// Non-isolated group correction
if ( bNonIsolatedGroup )
{
pPipe->nNonIsolatedGroup = SColorModeNComps[m_pBitmap->m_eMode];
}
else
{
pPipe->nNonIsolatedGroup = 0;
}
}
inline void SImage::PipeRun(SPipe *pPipe)
{
unsigned char aSrc, aDest, alpha2, alpha0, aResult;
SColor cDest, cBlend;
unsigned char cResult0, cResult1, cResult2, cResult3;
//----- source color
// static pattern: handled in pipeInit
// dynamic pattern
if ( pPipe->pPattern )
{
pPipe->pPattern->GetColor( pPipe->nX, pPipe->nY, pPipe->arrColorSrcVal );
}
if ( pPipe->bNoTransparency && !m_pState->m_pBlendFunction )
{
//----- write destination pixel
switch ( m_pBitmap->m_eMode )
{
case colorModeMono1:
cResult0 = pPipe->pColorSrc[0];
if ( m_pState->m_pScreen->GetGrayPixel( pPipe->nX, pPipe->nY, cResult0 ) )
{
*pPipe->pColorDst |= pPipe->nColorMaskDst;
}
else
{
*pPipe->pColorDst &= ~pPipe->nColorMaskDst;
}
if ( !(pPipe->nColorMaskDst >>= 1) )
{
pPipe->nColorMaskDst = 0x80;
++pPipe->pColorDst;
}
break;
case colorModeMono8:
*pPipe->pColorDst++ = pPipe->pColorSrc[0];
break;
case colorModeRGB8:
*pPipe->pColorDst++ = pPipe->pColorSrc[0];
*pPipe->pColorDst++ = pPipe->pColorSrc[1];
*pPipe->pColorDst++ = pPipe->pColorSrc[2];
break;
case colorModeBGR8:
*pPipe->pColorDst++ = pPipe->pColorSrc[2];
*pPipe->pColorDst++ = pPipe->pColorSrc[1];
*pPipe->pColorDst++ = pPipe->pColorSrc[0];
break;
}
if ( pPipe->pAlphaDst )
{
*pPipe->pAlphaDst++ = 255;
}
}
else
{
//----- read destination pixel
switch ( m_pBitmap->m_eMode )
{
case colorModeMono1:
cDest[0] = (*pPipe->pColorDst & pPipe->nColorMaskDst) ? 0xff : 0x00;
break;
case colorModeMono8:
cDest[0] = *pPipe->pColorDst;
break;
case colorModeRGB8:
cDest[0] = pPipe->pColorDst[0];
cDest[1] = pPipe->pColorDst[1];
cDest[2] = pPipe->pColorDst[2];
break;
case colorModeBGR8:
cDest[0] = pPipe->pColorDst[2];
cDest[1] = pPipe->pColorDst[1];
cDest[2] = pPipe->pColorDst[0];
break;
}
if ( pPipe->pAlphaDst )
{
aDest = *pPipe->pAlphaDst;
}
else
{
aDest = 0xff;
}
//----- blend function
if ( m_pState->m_pBlendFunction )
{
(*m_pState->m_pBlendFunction)( pPipe->pColorSrc, cDest, cBlend, m_pBitmap->m_eMode );
}
//----- source alpha
if ( m_pState->m_pSoftMask )
{
if ( pPipe->bUsesShape )
{
aSrc = (unsigned char)round( pPipe->dAlphaInput * *pPipe->pSMask++ * pPipe->dShape );
}
else
{
aSrc = (unsigned char)round( pPipe->dAlphaInput * *pPipe->pSMask++ );
}
}
else if ( pPipe->bUsesShape )
{
aSrc = (unsigned char)round( pPipe->dAlphaInput * pPipe->dShape );
}
else
{
aSrc = pPipe->unAlphaSrc;
}
//----- result alpha and non-isolated group element correction
if ( pPipe->bNoTransparency )
{
alpha2 = aResult = 255;
}
else
{
aResult = aSrc + aDest - Div255(aSrc * aDest);
if ( pPipe->pAlpha0 )
{
alpha0 = *pPipe->pAlpha0++;
alpha2 = aResult + alpha0 - Div255(aResult * alpha0);
}
else
{
alpha2 = aResult;
}
}
//----- result color
cResult0 = cResult1 = cResult2 = cResult3 = 0;
switch ( pPipe->eResultColorCtrl )
{
case PipeResultColorNoAlphaBlendRGB:
cResult2 = Div255((255 - aDest) * pPipe->pColorSrc[2] + aDest * cBlend[2]);
cResult1 = Div255((255 - aDest) * pPipe->pColorSrc[1] + aDest * cBlend[1]);
case PipeResultColorNoAlphaBlendMono:
cResult0 = Div255((255 - aDest) * pPipe->pColorSrc[0] + aDest * cBlend[0]);
break;
case PipeResultColorAlphaNoBlendMono:
if ( alpha2 == 0 )
{
cResult0 = 0;
}
else
{
cResult0 = (unsigned char)(((alpha2 - aSrc) * cDest[0] + aSrc * pPipe->pColorSrc[0]) / alpha2);
}
break;
case PipeResultColorAlphaNoBlendRGB:
if ( alpha2 == 0 )
{
cResult0 = 0;
cResult1 = 0;
cResult2 = 0;
}
else
{
cResult0 = (unsigned char)(((alpha2 - aSrc) * cDest[0] + aSrc * pPipe->pColorSrc[0]) / alpha2);
cResult1 = (unsigned char)(((alpha2 - aSrc) * cDest[1] + aSrc * pPipe->pColorSrc[1]) / alpha2);
cResult2 = (unsigned char)(((alpha2 - aSrc) * cDest[2] + aSrc * pPipe->pColorSrc[2]) / alpha2);
}
break;
case PipeResultColorAlphaBlendMono:
if ( alpha2 == 0 )
{
cResult0 = 0;
}
else
{
cResult0 = (unsigned char)(((alpha2 - aSrc) * cDest[0] + aSrc * ((255 - aDest) * pPipe->pColorSrc[0] + aDest * cBlend[0]) / 255) / alpha2);
}
break;
case PipeResultColorAlphaBlendRGB:
if ( alpha2 == 0 )
{
cResult0 = 0;
cResult1 = 0;
cResult2 = 0;
}
else
{
cResult0 = (unsigned char)(((alpha2 - aSrc) * cDest[0] + aSrc * ((255 - aDest) * pPipe->pColorSrc[0] + aDest * cBlend[0]) / 255) / alpha2);
cResult1 = (unsigned char)(((alpha2 - aSrc) * cDest[1] + aSrc * ((255 - aDest) * pPipe->pColorSrc[1] + aDest * cBlend[1]) / 255) / alpha2);
cResult2 = (unsigned char)(((alpha2 - aSrc) * cDest[2] + aSrc * ((255 - aDest) * pPipe->pColorSrc[2] + aDest * cBlend[2]) / 255) / alpha2);
}
break;
}
//----- non-isolated group correction
if ( aResult != 0 )
{
switch ( pPipe->nNonIsolatedGroup )
{
case 3:
cResult2 += (cResult2 - cDest[2]) * aDest * (255 - aResult) / (255 * aResult);
cResult1 += (cResult1 - cDest[1]) * aDest * (255 - aResult) / (255 * aResult);
case 1:
cResult0 += (cResult0 - cDest[0]) * aDest * (255 - aResult) / (255 * aResult);
case 0:
break;
}
}
//----- write destination pixel
switch ( m_pBitmap->m_eMode )
{
case colorModeMono1:
if ( m_pState->m_pScreen->GetGrayPixel(pPipe->nX, pPipe->nY, cResult0) )
{
*pPipe->pColorDst |= pPipe->nColorMaskDst;
}
else
{
*pPipe->pColorDst &= ~pPipe->nColorMaskDst;
}
if ( !( pPipe->nColorMaskDst >>= 1 ) )
{
pPipe->nColorMaskDst = 0x80;
++pPipe->pColorDst;
}
break;
case colorModeMono8:
*pPipe->pColorDst++ = cResult0;
break;
case colorModeRGB8:
*pPipe->pColorDst++ = cResult0;
*pPipe->pColorDst++ = cResult1;
*pPipe->pColorDst++ = cResult2;
break;
case colorModeBGR8:
*pPipe->pColorDst++ = cResult2;
*pPipe->pColorDst++ = cResult1;
*pPipe->pColorDst++ = cResult0;
break;
}
if ( pPipe->pAlphaDst )
{
*pPipe->pAlphaDst++ = aResult;
}
}
++pPipe->nX;
}
inline void SImage::PipeSetXY(SPipe *pPipe, int nX, int nY)
{
pPipe->nX = nX;
pPipe->nY = nY;
if ( m_pState->m_pSoftMask )
{
pPipe->pSMask = &m_pState->m_pSoftMask->m_pData[nY * m_pState->m_pSoftMask->m_nStride + nX];
}
switch ( m_pBitmap->m_eMode )
{
case colorModeMono1:
pPipe->pColorDst = &m_pBitmap->m_pData[nY * m_pBitmap->m_nStride + (nX >> 3)];
pPipe->nColorMaskDst = 0x80 >> (nX & 7);
break;
case colorModeMono8:
pPipe->pColorDst = &m_pBitmap->m_pData[nY * m_pBitmap->m_nStride + nX];
break;
case colorModeRGB8:
case colorModeBGR8:
pPipe->pColorDst = &m_pBitmap->m_pData[nY * m_pBitmap->m_nStride + 3 * nX];
break;
}
if ( m_pBitmap->m_pAlpha )
{
pPipe->pAlphaDst = &m_pBitmap->m_pAlpha[nY * m_pBitmap->m_nWidth + nX];
}
else
{
pPipe->pAlphaDst = NULL;
}
if ( m_pState->m_bInNonIsolatedGroup && m_pAlpha0Bitmap->m_pAlpha )
{
pPipe->pAlpha0 = &m_pAlpha0Bitmap->m_pAlpha[( m_nAlpha0Y + nY ) * m_pAlpha0Bitmap->m_nWidth + ( m_nAlpha0X + nX )];
}
else
{
pPipe->pAlpha0 = NULL;
}
}
inline void SImage::PipeIncreaseX(SPipe *pPipe)
{
++pPipe->nX;
if ( m_pState->m_pSoftMask )
{
++pPipe->pSMask;
}
switch ( m_pBitmap->m_eMode )
{
case colorModeMono1:
if ( !( pPipe->nColorMaskDst >>= 1 ) )
{
pPipe->nColorMaskDst = 0x80;
++pPipe->pColorDst;
}
break;
case colorModeMono8:
++pPipe->pColorDst;
break;
case colorModeRGB8:
case colorModeBGR8:
pPipe->pColorDst += 3;
break;
}
if ( pPipe->pAlphaDst )
{
++pPipe->pAlphaDst;
}
if ( pPipe->pAlpha0 )
{
++pPipe->pAlpha0;
}
}
inline void SImage::DrawPixel(SPipe *pPipe, int nX, int nY, BOOL bNoClip)
{
if ( bNoClip || m_pState->m_pClip->IsInsideClip( nX, nY ) )
{
PipeSetXY( pPipe, nX, nY );
PipeRun( pPipe );
UpdateModX( nX );
UpdateModY( nY );
}
}
inline void SImage::DrawAAPixelInit()
{
m_nAABufferY = -1;
}
inline void SImage::DrawAAPixel(SPipe *pPipe, int nX, int nY)
{
static int arrnBitCount4[16] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
if ( nX < 0 || nX >= m_pBitmap->m_nWidth || nY < m_pState->m_pClip->GetMinY() || nY > m_pState->m_pClip->GetMaxY() )
{
return;
}
// Ïåðåñ÷èòûâàåì m_nAABufferY
if ( nY != m_nAABufferY )
{
memset( m_pAABuffer->GetData(), 0xff, m_pAABuffer->GetStride() * m_pAABuffer->GetHeight() );
int nX0 = 0;
int nX1 = m_pBitmap->m_nWidth - 1;
m_pState->m_pClip->ClipAALine( m_pAABuffer, &nX0, &nX1, nY );
m_nAABufferY = nY;
}
SColorPointer pColor = m_pAABuffer->GetData() + (nX >> 1);
int nStride = m_pAABuffer->GetStride();
int nTemp = 0;
if ( nX & 1 )
{
nTemp = arrnBitCount4[*pColor & 0x0f] + arrnBitCount4[pColor[nStride] & 0x0f] + arrnBitCount4[pColor[2 * nStride] & 0x0f] + arrnBitCount4[pColor[3 * nStride] & 0x0f];
}
else
{
nTemp = arrnBitCount4[*pColor >> 4] + arrnBitCount4[pColor[nStride] >> 4] + arrnBitCount4[pColor[2 * nStride] >> 4] + arrnBitCount4[pColor[3 * nStride] >> 4];
}
// Ðèñóåì äàííûé ïèêñåëü
if ( nTemp != 0 )
{
PipeSetXY( pPipe, nX, nY );
pPipe->dShape *= m_arrdAAGamma[nTemp];
PipeRun( pPipe );
UpdateModX( nX );
UpdateModY( nY );
}
}
inline void SImage::DrawSpan(SPipe *pPipe, int nX0, int nX1, int nY, BOOL bNoClip)
{
PipeSetXY( pPipe, nX0, nY );
if ( bNoClip )
{
for ( int nX = nX0; nX <= nX1; ++nX )
{
PipeRun( pPipe );
}
UpdateModX( nX0 );
UpdateModX( nX1 );
UpdateModY( nY );
}
else
{
for ( int nX = nX0; nX <= nX1; ++nX )
{
if ( m_pState->m_pClip->IsInsideClip( nX, nY ) )
{
PipeRun( pPipe );
UpdateModX( nX );
UpdateModY( nY );
}
else
{
PipeIncreaseX( pPipe );
}
}
}
}
inline void SImage::DrawAALine(SPipe *pPipe, int nX0, int nX1, int nY)
{
static int arrnBitCount4[16] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
SColorPointer pLine0 = m_pAABuffer->GetData() + (nX0 >> 1);
SColorPointer pLine1 = pLine0 + m_pAABuffer->GetStride();
SColorPointer pLine2 = pLine1 + m_pAABuffer->GetStride();
SColorPointer pLine3 = pLine2 + m_pAABuffer->GetStride();
PipeSetXY( pPipe, nX0, nY );
for ( int nX = nX0; nX <= nX1; ++nX )
{
int nTemp = 0;
if ( nX & 1 )
{
nTemp = arrnBitCount4[*pLine0 & 0x0f] + arrnBitCount4[*pLine1 & 0x0f] + arrnBitCount4[*pLine2 & 0x0f] + arrnBitCount4[*pLine3 & 0x0f];
++pLine0; ++pLine1; ++pLine2; ++pLine3;
}
else
{
nTemp = arrnBitCount4[*pLine0 >> 4] + arrnBitCount4[*pLine1 >> 4] + arrnBitCount4[*pLine2 >> 4] + arrnBitCount4[*pLine3 >> 4];
}
if ( nTemp != 0 )
{
pPipe->dShape = m_arrdAAGamma[nTemp];
PipeRun( pPipe );
UpdateModX( nX );
UpdateModY( nY );
}
else
{
PipeIncreaseX( pPipe );
}
}
}
//-------------------------------------------------------------------------------------------------------------------------------
// Ïîëüçîâàòåëüñêèå êîîðäèíàòû -> êîîðäèíàòû óñòðîéñòâà.
inline void SImage::Transform(double *pMatrix, double dUserX, double dUserY, double *pdDeviceX, double *pdDeviceY)
{
*pdDeviceX = dUserX * pMatrix[0] + dUserY * pMatrix[2] + pMatrix[4];
*pdDeviceY = dUserX * pMatrix[1] + dUserY * pMatrix[3] + pMatrix[5];
}
//-------------------------------------------------------------------------------------------------------------------------------
// SImage
//-------------------------------------------------------------------------------------------------------------------------------
SImage::SImage(SBitmap *pBitmap, BOOL bVectorAA, SScreenParams *pScreenParams)
{
m_pBitmap = pBitmap;
m_bVectorAA = bVectorAA;
m_pState = new SState( m_pBitmap->m_nWidth, m_pBitmap->m_nHeight, m_bVectorAA, pScreenParams );
if ( m_bVectorAA )
{
m_pAABuffer = new SBitmap( AntiAliasingSize * m_pBitmap->m_nWidth, AntiAliasingSize, 1, colorModeMono1, FALSE );
for ( int nIndex = 0; nIndex <= AntiAliasingSize * AntiAliasingSize; ++nIndex )
{
m_arrdAAGamma[nIndex] = pow((double)nIndex / (double)(AntiAliasingSize * AntiAliasingSize), 1.5);
}
}
else
{
m_pAABuffer = NULL;
}
ClearModRegion();
}
SImage::SImage(SBitmap *pBitmap, BOOL bVectorAA, SScreen *pScreen)
{
m_pBitmap = pBitmap;
m_bVectorAA = bVectorAA;
m_pState = new SState( m_pBitmap->m_nWidth, m_pBitmap->m_nHeight, m_bVectorAA, pScreen );
if ( m_bVectorAA )
{
m_pAABuffer = new SBitmap( AntiAliasingSize * m_pBitmap->m_nWidth, AntiAliasingSize, 1, colorModeMono1, FALSE );
for ( int nIndex = 0; nIndex <= AntiAliasingSize * AntiAliasingSize; ++nIndex )
{
m_arrdAAGamma[nIndex] = pow( (double)nIndex / (double)(AntiAliasingSize * AntiAliasingSize), 1.5);
}
}
else
{
m_pAABuffer = NULL;
}
ClearModRegion();
}
SImage::~SImage()
{
while ( m_pState->m_pNext )
{
RestoreState();
}
if ( m_pState )
delete m_pState;
if ( m_bVectorAA && m_pAABuffer )
delete m_pAABuffer;
}
//-------------------------------------------------------------------------------------------------------------------------------
// Ñ÷èòûâàåì äàííûå èç òåêóùåãî SState
//-------------------------------------------------------------------------------------------------------------------------------
double *SImage::GetMatrix()
{
return m_pState->m_arrdMatrix;
}
SPattern *SImage::GetStrokePattern()
{
return m_pState->m_pStrokePattern;
}
SPattern *SImage::GetFillPattern()
{
return m_pState->m_pFillPattern;
}
SScreen *SImage::GetScreen()
{
return m_pState->m_pScreen;
}
SBlendFunc SImage::GetBlendFunc()
{
return m_pState->m_pBlendFunction;
}
double SImage::GetStrokeAlpha()
{
return m_pState->m_dStrokeAlpha;
}
double SImage::GetFillAlpha()
{
return m_pState->m_dFillAlpha;
}
double SImage::GetLineWidth()
{
return m_pState->m_dLineWidth;
}
int SImage::GetLineCap()
{
return m_pState->m_nLineCap;
}
int SImage::GetLineJoin()
{
return m_pState->m_nLineJoin;
}
double SImage::GetMiterLimit()
{
return m_pState->m_dMiterLimit;
}
double SImage::GetFlatness()
{
return m_pState->m_dFlatness;
}
double *SImage::GetLineDash()
{
return m_pState->m_pdLineDash;
}
int SImage::GetLineDashLength()
{
return m_pState->m_nLineDashCount;
}
double SImage::GetLineDashPhase()
{
return m_pState->m_dLineDashPhase;
}
SClip *SImage::GetClip()
{
return m_pState->m_pClip;
}
SBitmap *SImage::GetSoftMask()
{
return m_pState->m_pSoftMask;
}
BOOL SImage::GetInNonIsolatedGroup()
{
return m_pState->m_bInNonIsolatedGroup;
}
//-------------------------------------------------------------------------------------------------------------------------------
// Èçìåíÿåì ïàðàìåòðû òåêóùåãî SState
//-------------------------------------------------------------------------------------------------------------------------------
void SImage::SetMatrix(double *pMatrix)
{
memcpy( m_pState->m_arrdMatrix, pMatrix, 6 * sizeof(double) );
}
void SImage::SetStrokePattern(SPattern *pPattern)
{
m_pState->SetStrokePattern( pPattern );
}
void SImage::SetFillPattern(SPattern *pPattern)
{
m_pState->SetFillPattern( pPattern );
}
void SImage::SetScreen(SScreen *pScreen)
{
m_pState->SetScreen( pScreen );
}
void SImage::SetBlendFunc(SBlendFunc pFunction)
{
m_pState->m_pBlendFunction = pFunction;
}
void SImage::SetStrokeAlpha(double dAlpha)
{
m_pState->m_dStrokeAlpha = dAlpha;
}
void SImage::SetFillAlpha(double dAlpha)
{
m_pState->m_dFillAlpha = dAlpha;
}
void SImage::SetLineWidth(double dLineWidth)
{
m_pState->m_dLineWidth = dLineWidth;
}
void SImage::SetLineCap(int nLineCap)
{
m_pState->m_nLineCap = nLineCap;
}
void SImage::SetLineJoin(int nLineJoin)
{
m_pState->m_nLineJoin = nLineJoin;
}
void SImage::SetMiterLimit(double dMiterLimit)
{
m_pState->m_dMiterLimit = dMiterLimit;
}
void SImage::SetFlatness(double dFlatness)
{
if ( dFlatness < 1 )
{
m_pState->m_dFlatness = 1;
}
else
{
m_pState->m_dFlatness = dFlatness;
}
}
void SImage::SetLineDash(double *pLineDash, int nLineDashLength, double dLineDashPhase)
{
m_pState->SetLineDash( pLineDash, nLineDashLength, dLineDashPhase );
}
void SImage::SetStrokeAdjust(BOOL bStrokeAdjust)
{
m_pState->m_bStrokeAdjust = bStrokeAdjust;
}
void SImage::ClipResetToRect(double dX0, double dY0, double dX1, double dY1)
{
m_pState->m_pClip->ResetToRect( dX0, dY0, dX1, dY1 );
}
int SImage::ClipToRect(double dX0, double dY0, double dX1, double dY1)
{
return m_pState->m_pClip->ClipToRect( dX0, dY0, dX1, dY1 );
}
int SImage::ClipToPath(SPath *pPath, BOOL bEo)
{
return m_pState->m_pClip->ClipToPath( pPath, m_pState->m_arrdMatrix, m_pState->m_dFlatness, bEo );
}
void SImage::SetSoftMask(SBitmap *pSMask)
{
m_pState->SetSoftMask( pSMask );
}
void SImage::SetInNonIsolatedGroup(SBitmap *pAlpha0Bitmap, int nAlpha0X, int nAlpha0Y)
{
m_pAlpha0Bitmap = pAlpha0Bitmap;
m_nAlpha0X = nAlpha0X;
m_nAlpha0Y = nAlpha0Y;
m_pState->m_bInNonIsolatedGroup = TRUE;
}
//-------------------------------------------------------------------------------------------------------------------------------
// Ñîõðàíÿåì/âîññòàíàâëèâàåì SState (èìååòñÿ ââèäó ñòåê îáúåêòîâ SState)
//-------------------------------------------------------------------------------------------------------------------------------
void SImage::SaveState()
{
SState *pNewState = m_pState->Copy();
pNewState->m_pNext = m_pState;
m_pState = pNewState;
}
int SImage::RestoreState()
{
if ( !m_pState->m_pNext )
{
return SErrorNoSaveState;
}
SState *pOldState = m_pState;
m_pState = m_pState->m_pNext;
delete pOldState;
return SNoError;
}
//-------------------------------------------------------------------------------------------------------------------------------
// Ôóíêöèè ðèñîâàíèÿ
//-------------------------------------------------------------------------------------------------------------------------------
void SImage::Clear(SColorPointer pColor, unsigned char unAlpha)
{
unsigned char unMono;
switch ( m_pBitmap->m_eMode )
{
case colorModeMono1:
unMono = (pColor[0] & 0x80) ? 0xff : 0x00;
if ( m_pBitmap->m_nStride < 0 )
{
memset( m_pBitmap->m_pData + m_pBitmap->m_nStride * (m_pBitmap->m_nHeight - 1), unMono, -m_pBitmap->m_nStride * m_pBitmap->m_nHeight );
}
else
{
memset( m_pBitmap->m_pData, unMono, m_pBitmap->m_nStride * m_pBitmap->m_nHeight);
}
break;
case colorModeMono8:
if ( m_pBitmap->m_nStride < 0 )
{
memset( m_pBitmap->m_pData + m_pBitmap->m_nStride * (m_pBitmap->m_nHeight - 1), pColor[0], -m_pBitmap->m_nStride * m_pBitmap->m_nHeight );
}
else
{
memset( m_pBitmap->m_pData, pColor[0], m_pBitmap->m_nStride * m_pBitmap->m_nHeight );
}
break;
case colorModeRGB8:
if ( pColor[0] == pColor[1] && pColor[1] == pColor[2] )
{
if ( m_pBitmap->m_nStride < 0 )
{
memset( m_pBitmap->m_pData + m_pBitmap->m_nStride * (m_pBitmap->m_nHeight - 1), pColor[0], -m_pBitmap->m_nStride * m_pBitmap->m_nHeight );
}
else
{
memset( m_pBitmap->m_pData, pColor[0], m_pBitmap->m_nStride * m_pBitmap->m_nHeight );
}
}
else
{
SColorPointer pLine = m_pBitmap->m_pData;
for ( int nY = 0; nY < m_pBitmap->m_nHeight; ++nY )
{
SColorPointer pCur = pLine;
for ( int nX = 0; nX < m_pBitmap->m_nWidth; ++nX )
{
*pCur++ = pColor[2];
*pCur++ = pColor[1];
*pCur++ = pColor[0];
}
pLine += m_pBitmap->m_nStride;
}
}
break;
case colorModeBGR8:
if ( pColor[0] == pColor[1] && pColor[1] == pColor[2] )
{
if ( m_pBitmap->m_nStride < 0 )
{
memset( m_pBitmap->m_pData + m_pBitmap->m_nStride * (m_pBitmap->m_nHeight - 1), pColor[0], -m_pBitmap->m_nStride * m_pBitmap->m_nHeight );
}
else
{
memset( m_pBitmap->m_pData, pColor[0], m_pBitmap->m_nStride * m_pBitmap->m_nHeight );
}
}
else
{
SColorPointer pLine = m_pBitmap->m_pData;
for ( int nY = 0; nY < m_pBitmap->m_nHeight; ++nY )
{
SColorPointer pCur = pLine;
for ( int nX = 0; nX < m_pBitmap->m_nWidth; ++nX )
{
*pCur++ = pColor[0];
*pCur++ = pColor[1];
*pCur++ = pColor[2];
}
pLine += m_pBitmap->m_nStride;
}
}
break;
}
if ( m_pBitmap->m_pAlpha )
{
memset( m_pBitmap->m_pAlpha, unAlpha, m_pBitmap->m_nWidth * m_pBitmap->m_nHeight );
}
UpdateModX( 0 );
UpdateModY( 0 );
UpdateModX( m_pBitmap->m_nWidth - 1 );
UpdateModY( m_pBitmap->m_nHeight - 1 );
}
int SImage::Stroke(SPath *pPath)
{
m_pOpClipRes = clipAllOutside;
if ( pPath->m_nPointsCount == 0 )
{
return SErrorEmptyPath;
}
SPath *pResultPath = FlattenPath( pPath, m_pState->m_arrdMatrix, m_pState->m_dFlatness );
if ( !pResultPath )
return SErrorMemory;
if ( m_pState->m_nLineDashCount > 0 )
{
SPath *pDashPath = MakeDashedPath( pResultPath );
delete pResultPath;
pResultPath = pDashPath;
}
if ( m_pState->m_dLineWidth == 0 )
{
StrokeNarrow( pResultPath );
}
else
{
StrokeWide( pResultPath );
}
delete pResultPath;
return SNoError;
}
void SImage::StrokeNarrow(SPath *pPath)
{
SClipResult eClipResult;
int arrnClipRes[3];
arrnClipRes[0] = arrnClipRes[1] = arrnClipRes[2] = 0;
SXPath *pXPath = new SXPath( pPath, m_pState->m_arrdMatrix, m_pState->m_dFlatness, FALSE );
if ( !pXPath )
return;
SPipe oPipe;
PipeInit( &oPipe, 0, 0, m_pState->m_pStrokePattern, NULL, m_pState->m_dStrokeAlpha, FALSE, FALSE );
int nSegmentIndex;
SXPathSegment *pSegment = NULL;
for ( nSegmentIndex = 0, pSegment = pXPath->m_pSegments; nSegmentIndex < pXPath->m_nSegmentsCount; ++nSegmentIndex, ++pSegment )
{
int nX0 = (int)floor( pSegment->dFirstX );
int nX1 = (int)floor( pSegment->dSecondX );
int nY0 = (int)floor( pSegment->dFirstY );
int nY1 = (int)floor( pSegment->dSecondY );
// ãîðèçîíòàëüíûé ñåãìåíò
if ( nY0 == nY1 )
{
if ( nX0 > nX1 )
{
int nTemp = nX0;
nX0 = nX1;
nX1 = nTemp;
}
if ( ( eClipResult = m_pState->m_pClip->CheckSpan( nX0, nX1, nY0 ) ) != clipAllOutside )
{
DrawSpan( &oPipe, nX0, nX1, nY0, eClipResult == clipAllInside );
}
}
else if ( fabs(pSegment->dDxDy) > 1) // |dDx| > |dDy|
{
double dDx = pSegment->dSecondX - pSegment->dFirstX;
double dDy = pSegment->dSecondY - pSegment->dFirstY;
double dDxDy = pSegment->dDxDy;
if ( nY0 > nY1 )
{
int nTemp = nY0;
nY0 = nY1;
nY1 = nTemp;
nTemp = nX0;
nX0 = nX1;
nX1 = nTemp;
dDx = -dDx;
dDy = -dDy;
}
if ( ( eClipResult = m_pState->m_pClip->CheckRectangle( nX0 <= nX1 ? nX0 : nX1, nY0, nX0 <= nX1 ? nX1 : nX0, nY1) ) != clipAllOutside )
{
if ( dDx > 0 )
{
int nX2 = nX0;
int nX3 = (int)floor( pSegment->dFirstX + ((double)nY0 + 1 - pSegment->dFirstY) * dDxDy );
DrawSpan( &oPipe, nX2, (nX2 <= nX3 - 1) ? nX3 - 1 : nX2, nY0, eClipResult == clipAllInside );
nX2 = nX3;
for ( int nY = nY0 + 1; nY <= nY1 - 1; ++nY )
{
nX3 = (int)floor( pSegment->dFirstX + ((double)nY + 1 - pSegment->dFirstY) * dDxDy );
DrawSpan( &oPipe, nX2, nX3 - 1, nY, eClipResult == clipAllInside );
nX2 = nX3;
}
DrawSpan( &oPipe, nX2, nX2 <= nX1 ? nX1 : nX2, nY1, eClipResult == clipAllInside );
}
else
{
int nX2 = nX0;
int nX3 = (int)floor( pSegment->dFirstX + ((double)nY0 + 1 - pSegment->dFirstY) * dDxDy );
DrawSpan( &oPipe, (nX3 + 1 <= nX2) ? nX3 + 1 : nX2, nX2, nY0, eClipResult == clipAllInside );
nX2 = nX3;
for ( int nY = nY0 + 1; nY <= nY1 - 1; ++nY )
{
nX3 = (int)floor( pSegment->dFirstX + ((double)nY + 1 - pSegment->dFirstY) * dDxDy );
DrawSpan( &oPipe, nX3 + 1, nX2, nY, eClipResult == clipAllInside );
nX2 = nX3;
}
DrawSpan( &oPipe, nX1, (nX1 <= nX2) ? nX2 : nX1, nY1, eClipResult == clipAllInside );
}
}
}
else // |dDy| > |dDx|
{
double dDxDy = pSegment->dDxDy;
if ( nY0 > nY1 )
{
int nTemp = nX0;
nX0 = nX1;
nX1 = nTemp;
nTemp = nY0;
nY0 = nY1;
nY1 = nTemp;
}
if ( ( eClipResult = m_pState->m_pClip->CheckRectangle( nX0 <= nX1 ? nX0 : nX1, nY0, nX0 <= nX1 ? nX1 : nX0, nY1) ) != clipAllOutside )
{
DrawPixel( &oPipe, nX0, nY0, eClipResult == clipAllInside );
for ( int nY = nY0 + 1; nY <= nY1 - 1; ++nY )
{
int nX = (int)floor(pSegment->dFirstX + ((double)nY - pSegment->dFirstY) * dDxDy);
DrawPixel( &oPipe, nX, nY, eClipResult == clipAllInside );
}
DrawPixel( &oPipe, nX1, nY1, eClipResult == clipAllInside );
}
}
++arrnClipRes[eClipResult];
}
if ( arrnClipRes[clipPartial] || ( arrnClipRes[clipAllInside] && arrnClipRes[clipAllOutside] ) )
{
m_pOpClipRes = clipPartial;
}
else if ( arrnClipRes[clipAllInside] )
{
m_pOpClipRes = clipAllInside;
}
else
{
m_pOpClipRes = clipAllOutside;
}
delete pXPath;
}
void SImage::StrokeWide(SPath *pPath)
{
SPath *pStrokePath = MakeStrokePath( pPath, FALSE );
if ( !pStrokePath )
return;
FillWithPattern( pStrokePath, FALSE, m_pState->m_pStrokePattern, m_pState->m_dStrokeAlpha );
delete pStrokePath;
}
SPath *SImage::FlattenPath(SPath *pPath, double *pMatrix, double dFlatness)
{
SPath *pFlatPath = new SPath();
double dFlatness_2 = dFlatness * dFlatness;
int nPointIndex = 0;
while ( nPointIndex < pPath->m_nPointsCount )
{
unsigned char unFlag = pPath->m_pFlags[nPointIndex];
if ( unFlag & SPathFirst )
{
pFlatPath->MoveTo( pPath->m_pPoints[nPointIndex].dX, pPath->m_pPoints[nPointIndex].dY );
++nPointIndex;
}
else
{
if ( unFlag & SPathCurve )
{
FlattenCurve( pPath->m_pPoints[nPointIndex - 1].dX, pPath->m_pPoints[nPointIndex - 1].dY, pPath->m_pPoints[nPointIndex].dX, pPath->m_pPoints[nPointIndex].dY, pPath->m_pPoints[nPointIndex + 1].dX, pPath->m_pPoints[nPointIndex + 1].dY, pPath->m_pPoints[nPointIndex + 2].dX, pPath->m_pPoints[nPointIndex + 2].dY, pMatrix, dFlatness_2, pFlatPath );
nPointIndex += 3;
}
else
{
pFlatPath->LineTo( pPath->m_pPoints[nPointIndex].dX, pPath->m_pPoints[nPointIndex].dY );
++nPointIndex;
}
if ( pPath->m_pFlags[nPointIndex - 1] & SPathClosed )
{
pFlatPath->Close();
}
}
}
return pFlatPath;
}
void SImage::FlattenCurve(double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3, double *matrix, double dFlatness_2, SPath *fPath)
{
double arrSegX[MaxCurveSplits + 1][3];
double arrSegY[MaxCurveSplits + 1][3];
int arrNext[MaxCurveSplits + 1];
double xl0, xl1, xl2, xr0, xr1, xr2, xr3, xx1, xx2, xh;
double yl0, yl1, yl2, yr0, yr1, yr2, yr3, yy1, yy2, yh;
double dx, dy, mx, my, tx, ty, d1, d2;
// Íà÷àëüíûé ñåãìåíò
int nPart1 = 0, nPart2 = MaxCurveSplits;
arrSegX[nPart1][0] = x0; arrSegY[nPart1][0] = y0;
arrSegX[nPart1][1] = x1; arrSegY[nPart1][1] = y1;
arrSegX[nPart1][2] = x2; arrSegY[nPart1][2] = y2;
arrSegX[nPart2][0] = x3; arrSegY[nPart2][0] = y3;
arrNext[nPart1] = nPart2;
while ( nPart1 < MaxCurveSplits )
{
// Ñëåäóþùèé ñåãìåíò
xl0 = arrSegX[nPart1][0]; yl0 = arrSegY[nPart1][0];
xx1 = arrSegX[nPart1][1]; yy1 = arrSegY[nPart1][1];
xx2 = arrSegX[nPart1][2]; yy2 = arrSegY[nPart1][2];
nPart2 = arrNext[nPart1];
xr3 = arrSegX[nPart2][0]; yr3 = arrSegY[nPart2][0];
// Âû÷èñëÿåì ðàññòîÿíèå îò êîíòðîëüíûõ òî÷åê äî ñðåäíèõ òî÷åê ïðÿìîé ëèíèè. (Âû÷èñëåíèå íå ñîâñåì òî÷íîå, íî áûñòðîå)
Transform( matrix, (xl0 + xr3) * 0.5, (yl0 + yr3) * 0.5, &mx, &my );
Transform( matrix, xx1, yy1, &tx, &ty );
dx = tx - mx;
dy = ty - my;
d1 = dx*dx + dy*dy;
Transform(matrix, xx2, yy2, &tx, &ty);
dx = tx - mx;
dy = ty - my;
d2 = dx*dx + dy*dy;
// Åñëè ñåãìåíò óæå äîñòàòî÷íî ïëîñêèé èëè áîëüøå äåëåíèé íåâîçîìæíî ñäåëàòü, äîáàâëÿåì ïðÿìóþ ëèíèþ
if ( nPart2 - nPart1 == 1 || ( d1 <= dFlatness_2 && d2 <= dFlatness_2 ) )
{
fPath->LineTo( xr3, yr3 );
nPart1 = nPart2;
}
else // otherwise, subdivide the curve
{
xl1 = (xl0 + xx1) * 0.5;
yl1 = (yl0 + yy1) * 0.5;
xh = (xx1 + xx2) * 0.5;
yh = (yy1 + yy2) * 0.5;
xl2 = (xl1 + xh) * 0.5;
yl2 = (yl1 + yh) * 0.5;
xr2 = (xx2 + xr3) * 0.5;
yr2 = (yy2 + yr3) * 0.5;
xr1 = (xh + xr2) * 0.5;
yr1 = (yh + yr2) * 0.5;
xr0 = (xl2 + xr1) * 0.5;
yr0 = (yl2 + yr1) * 0.5;
// add the new subdivision points
int nPart3 = (nPart1 + nPart2) / 2;
arrSegX[nPart1][1] = xl1; arrSegY[nPart1][1] = yl1;
arrSegX[nPart1][2] = xl2; arrSegY[nPart1][2] = yl2;
arrNext[nPart1] = nPart3;
arrSegX[nPart3][0] = xr0; arrSegY[nPart3][0] = yr0;
arrSegX[nPart3][1] = xr1; arrSegY[nPart3][1] = yr1;
arrSegX[nPart3][2] = xr2; arrSegY[nPart3][2] = yr2;
arrNext[nPart3] = nPart2;
}
}
}
SPath *SImage::MakeDashedPath(SPath *pPath)
{
double dLineDashTotal = 0;
int nIndex = 0;
for ( nIndex = 0; nIndex < m_pState->m_nLineDashCount; ++nIndex )
{
dLineDashTotal += m_pState->m_pdLineDash[nIndex];
}
double dLineDashStartPhase = m_pState->m_dLineDashPhase;
nIndex = (int)floor( dLineDashStartPhase / dLineDashTotal );
dLineDashStartPhase -= (double)nIndex * dLineDashTotal;
BOOL bLineDashStartOn = TRUE;
int nLineDashStartIndex = 0;
while ( dLineDashStartPhase >= m_pState->m_pdLineDash[nLineDashStartIndex] )
{
bLineDashStartOn = !bLineDashStartOn;
dLineDashStartPhase -= m_pState->m_pdLineDash[nLineDashStartIndex];
++nLineDashStartIndex;
}
SPath *pDashPath = new SPath();
nIndex = 0;
while ( nIndex < pPath->m_nPointsCount )
{
// Èùåì îêîí÷àíèå äàííîãî SupPath
int nEndIndex;
for ( nEndIndex = nIndex; nEndIndex < pPath->m_nPointsCount - 1 && !(pPath->m_pFlags[nEndIndex] & SPathLast); ++nEndIndex) ;
// Îáíóëÿåì ïàðàìåòðû
BOOL bLineDashOn = bLineDashStartOn;
int nLineDashIndex = nLineDashStartIndex;
double dLineDashDist = m_pState->m_pdLineDash[nLineDashIndex] - dLineDashStartPhase;
// Ðàáîòàåì ñ ÷àñòÿìè SupPath
BOOL bNewPath = TRUE;
for ( int nK = nIndex; nK < nEndIndex; ++nK )
{
// Çàáèðàåì ñåãìåíò
double dX0 = pPath->m_pPoints[nK].dX;
double dY0 = pPath->m_pPoints[nK].dY;
double dX1 = pPath->m_pPoints[nK + 1].dX;
double dY1 = pPath->m_pPoints[nK + 1].dY;
double dSegLen = distance( dX0, dY0, dX1, dY1 );
while ( dSegLen > 0 )
{
if ( dLineDashDist >= dSegLen )
{
if ( bLineDashOn )
{
if ( bNewPath )
{
pDashPath->MoveTo( dX0, dY0 );
bNewPath = FALSE;
}
pDashPath->LineTo( dX1, dY1 );
}
dLineDashDist -= dSegLen;
dSegLen = 0;
}
else
{
double dTempX = dX0 + (dLineDashDist / dSegLen) * (dX1 - dX0);
double dTempY = dY0 + (dLineDashDist / dSegLen) * (dY1 - dY0);
if ( bLineDashOn )
{
if ( bNewPath )
{
pDashPath->MoveTo( dX0, dY0 );
bNewPath = FALSE;
}
pDashPath->LineTo( dTempX, dTempY );
}
dX0 = dTempX;
dY0 = dTempY;
dSegLen -= dLineDashDist;
dLineDashDist = 0;
}
if ( dLineDashDist <= 0 )
{
bLineDashOn = !bLineDashOn;
if ( ++nLineDashIndex == m_pState->m_nLineDashCount )
{
nLineDashIndex = 0;
}
dLineDashDist = m_pState->m_pdLineDash[nLineDashIndex];
bNewPath = TRUE;
}
}
}
nIndex = nEndIndex + 1;
}
return pDashPath;
}
int SImage::Fill(SPath *pPath, BOOL bEO)
{
return FillWithPattern( pPath, bEO, m_pState->m_pFillPattern, m_pState->m_dFillAlpha );
}
int SImage::FillWithPattern(SPath *pPath, BOOL bEO, SPattern *pPattern, double dAlpha)
{
int nX0, nX1;
if ( pPath->m_nPointsCount == 0 )
{
return SErrorEmptyPath;
}
SXPath *pXPath = new SXPath( pPath, m_pState->m_arrdMatrix, m_pState->m_dFlatness, TRUE );
if ( !pXPath )
return SErrorMemory;
if ( m_bVectorAA )
{
pXPath->AntiAliasingScale();
}
pXPath->Sort();
SXPathScanner *pScanner = new SXPathScanner( pXPath, bEO );
if ( !pScanner )
return SErrorMemory;
int nMinX, nMinY, nMaxX, nMaxY;
if ( m_bVectorAA )
{
pScanner->GetBBoxAA( &nMinX, &nMinY, &nMaxX, &nMaxY );
}
else
{
pScanner->GetBBox( &nMinX, &nMinY, &nMaxX, &nMaxY );
}
SClipResult eClipResult;
if ( ( eClipResult = m_pState->m_pClip->CheckRectangle( nMinX, nMinY, nMaxX, nMaxY) ) != clipAllOutside )
{
if ( nMinY < m_pState->m_pClip->GetMinY() )
{
nMinY = m_pState->m_pClip->GetMinY();
}
if ( nMaxY > m_pState->m_pClip->GetMaxY() )
{
nMaxY = m_pState->m_pClip->GetMaxY();
}
SPipe oPipe;
PipeInit( &oPipe, 0, nMinY, pPattern, NULL, dAlpha, m_bVectorAA, FALSE );
if ( m_bVectorAA )
{
for ( int nY = nMinY; nY <= nMaxY; ++nY )
{
pScanner->RenderAALine( m_pAABuffer, &nX0, &nX1, nY );
if ( eClipResult != clipAllInside )
{
m_pState->m_pClip->ClipAALine( m_pAABuffer, &nX0, &nX1, nY );
}
DrawAALine( &oPipe, nX0, nX1, nY );
}
}
else
{
for ( int nY = nMinY; nY <= nMaxY; ++nY )
{
while ( pScanner->GetNextSpan( nY, &nX0, &nX1) )
{
if ( eClipResult == clipAllInside )
{
DrawSpan( &oPipe, nX0, nX1, nY, TRUE );
}
else
{
// limit the x range
if ( nX0 < m_pState->m_pClip->GetMinX() )
{
nX0 = m_pState->m_pClip->GetMinX();
}
if ( nX1 > m_pState->m_pClip->GetMaxX() )
{
nX1 = m_pState->m_pClip->GetMaxX();
}
SClipResult eTempClipRes = m_pState->m_pClip->CheckSpan( nX0, nX1, nY );
DrawSpan( &oPipe, nX0, nX1, nY, eTempClipRes == clipAllInside );
}
}
}
}
}
m_pOpClipRes = eClipResult;
delete pScanner;
delete pXPath;
return SNoError;
}
int SImage::XorFill(SPath *pPath, BOOL bEO)
{
int nX0, nX1;
if ( pPath->m_nPointsCount == 0 )
{
return SErrorEmptyPath;
}
SXPath *pXPath = new SXPath( pPath, m_pState->m_arrdMatrix, m_pState->m_dFlatness, TRUE);
if ( !pXPath )
return SErrorMemory;
pXPath->Sort();
SXPathScanner *pScanner = new SXPathScanner( pXPath, bEO );
if ( !pScanner )
return SErrorMemory;
int nMinX, nMinY, nMaxX, nMaxY;
pScanner->GetBBox( &nMinX, &nMinY, &nMaxX, &nMaxY );
SClipResult eClipResult;
if ( ( eClipResult = m_pState->m_pClip->CheckRectangle( nMinX, nMinY, nMaxX, nMaxY) ) != clipAllOutside )
{
if ( nMinY < m_pState->m_pClip->GetMinY() )
{
nMinY = m_pState->m_pClip->GetMinY();
}
if ( nMaxY > m_pState->m_pClip->GetMaxY() )
{
nMaxY = m_pState->m_pClip->GetMaxY();
}
SBlendFunc pOrigBlendFunc = m_pState->m_pBlendFunction;
m_pState->m_pBlendFunction = &BlendXor;
SPipe oPipe;
PipeInit( &oPipe, 0, nMinY, m_pState->m_pFillPattern, NULL, 1, FALSE, FALSE );
for ( int nY = nMinY; nY <= nMaxY; ++nY )
{
while ( pScanner->GetNextSpan( nY, &nX0, &nX1 ) )
{
if ( eClipResult == clipAllInside )
{
DrawSpan( &oPipe, nX0, nX1, nY, TRUE );
}
else
{
if ( nX0 < m_pState->m_pClip->GetMinX() )
{
nX0 = m_pState->m_pClip->GetMinX();
}
if ( nX1 > m_pState->m_pClip->GetMaxX() )
{
nX1 = m_pState->m_pClip->GetMaxX();
}
SClipResult eTempClipRes = m_pState->m_pClip->CheckSpan( nX0, nX1, nY );
DrawSpan( &oPipe, nX0, nX1, nY, eTempClipRes == clipAllInside);
}
}
}
m_pState->m_pBlendFunction = pOrigBlendFunc;
}
m_pOpClipRes = eClipResult;
delete pScanner;
delete pXPath;
return SNoError;
}
int SImage::FillChar(double dX, double dY, int nCode, SFont *pFont)
{
double dTransformX, dTransformY;
Transform( m_pState->m_arrdMatrix, dX, dY, &dTransformX, &dTransformY );
int nX = (int)floor( dTransformX );
int nFracX = (int)floor( (dTransformX - nX) * sfontFraction );
int nY = (int)floor( dTransformY );
int nFracY = (int)floor( (dTransformY - nY) * sfontFraction );
SGlyphBitmap oGlyph;
if ( !pFont->GetGlyph( nCode, nFracX, nFracY, &oGlyph ) )
{
return SErrorNoGlyph;
}
int nError = FillGlyph2( nX, nY, &oGlyph );
if ( oGlyph.bFreeData )
{
MemUtilsFree( oGlyph.pData );
}
return nError;
}
int SImage::FillGlyph(double dX, double dY, SGlyphBitmap *pGlyph)
{
double dTransformX, dTransformY;
Transform( m_pState->m_arrdMatrix, dX, dY, &dTransformX, &dTransformY );
int nX = (int)floor( dTransformX );
int nY = (int)floor( dTransformY );
return FillGlyph2( nX, nY, pGlyph);
}
int SImage::FillGlyph2(int nX, int nY, SGlyphBitmap *pGlyph)
{
SPipe oPipe;
SClipResult eClipResult;
if ( ( eClipResult = m_pState->m_pClip->CheckRectangle( nX - pGlyph->nX, nY - pGlyph->nY, nX - pGlyph->nX + pGlyph->nWidth - 1, nY - pGlyph->nY + pGlyph->nHeight - 1 ) ) != clipAllOutside )
{
BOOL bNoClip = (eClipResult == clipAllInside);
if ( bNoClip )
{
if ( pGlyph->bAA )
{
PipeInit( &oPipe, nX - pGlyph->nX, nY - pGlyph->nY, m_pState->m_pFillPattern, NULL, m_pState->m_dFillAlpha, TRUE, FALSE );
unsigned char *pData = pGlyph->pData;
for ( int nYY = 0, nY1 = nY - pGlyph->nY; nYY < pGlyph->nHeight; ++nYY, ++nY1 )
{
PipeSetXY( &oPipe, nX - pGlyph->nX, nY1 );
for ( int nXX = 0, nX1 = nX - pGlyph->nX; nXX < pGlyph->nWidth; ++nXX, ++nX1 )
{
int nAlpha = *pData++;
if ( nAlpha != 0 )
{
oPipe.dShape = (double)(nAlpha / 255.0);
PipeRun( &oPipe );
UpdateModX( nX1 );
UpdateModY( nY1 );
}
else
{
PipeIncreaseX( &oPipe );
}
}
}
}
else
{
PipeInit( &oPipe, nX - pGlyph->nX, nY - pGlyph->nY, m_pState->m_pFillPattern, NULL, m_pState->m_dFillAlpha, FALSE, FALSE );
unsigned char *pData = pGlyph->pData;
for ( int nYY = 0, nY1 = nY - pGlyph->nY; nYY < pGlyph->nHeight; ++nYY, ++nY1 )
{
PipeSetXY( &oPipe, nX - pGlyph->nX, nY1);
for ( int nXX = 0, nX1 = nX - pGlyph->nX; nXX < pGlyph->nWidth; nXX += 8 )
{
int nAlpha0 = *pData++;
for ( int nXX1 = 0; nXX1 < 8 && nXX + nXX1 < pGlyph->nWidth; ++nXX1, ++nX1 )
{
if ( nAlpha0 & 0x80 )
{
PipeRun( &oPipe );
UpdateModX( nX1 );
UpdateModY( nY1 );
}
else
{
PipeIncreaseX( &oPipe );
}
nAlpha0 <<= 1;
}
}
}
}
}
else
{
if ( pGlyph->bAA )
{
PipeInit( &oPipe, nX - pGlyph->nX, nY - pGlyph->nY, m_pState->m_pFillPattern, NULL, m_pState->m_dFillAlpha, TRUE, FALSE );
unsigned char *pData = pGlyph->pData;
for ( int nYY = 0, nY1 = nY - pGlyph->nY; nYY < pGlyph->nHeight; ++nYY, ++nY1 )
{
PipeSetXY( &oPipe, nX - pGlyph->nX, nY1 );
for ( int nXX = 0, nX1 = nX - pGlyph->nX; nXX < pGlyph->nWidth; ++nXX, ++nX1 )
{
if ( m_pState->m_pClip->IsInsideClip( nX1, nY1 ) )
{
int nAlpha = *pData++;
if ( nAlpha != 0 )
{
oPipe.dShape = (double)(nAlpha / 255.0);
PipeRun( &oPipe );
UpdateModX( nX1 );
UpdateModY( nY1 );
}
else
{
PipeIncreaseX( &oPipe );
}
}
else
{
PipeIncreaseX( &oPipe );
++pData;
}
}
}
}
else
{
PipeInit( &oPipe, nX - pGlyph->nX, nY - pGlyph->nY, m_pState->m_pFillPattern, NULL, m_pState->m_dFillAlpha, FALSE, FALSE );
unsigned char *pData = pGlyph->pData;
for ( int nYY = 0, nY1 = nY - pGlyph->nY; nYY < pGlyph->nHeight; ++nYY, ++nY1 )
{
PipeSetXY( &oPipe, nX - pGlyph->nX, nY1 );
for ( int nXX = 0, nX1 = nX - pGlyph->nX; nXX < pGlyph->nWidth; nXX += 8 )
{
int nAlpha0 = *pData++;
for ( int nXX1 = 0; nXX1 < 8 && nXX + nXX1 < pGlyph->nWidth; ++nXX1, ++nX1 )
{
if ( m_pState->m_pClip->IsInsideClip( nX1, nY1 ) )
{
if ( nAlpha0 & 0x80 )
{
PipeRun( &oPipe );
UpdateModX( nX1 );
UpdateModY( nY1 );
}
else
{
PipeIncreaseX( &oPipe );
}
}
else
{
PipeIncreaseX( &oPipe );
}
nAlpha0 <<= 1;
}
}
}
}
}
}
m_pOpClipRes = eClipResult;
return SNoError;
}
int SImage::FillImageMask(SImageMaskSource pSrc, void *pSrcData, int nWidth, int nHeight, double *pMatrix, BOOL bGlyphMode)
{
// Ïðîâåðÿåì ìàòðèöó íà íåâûðîæäåííîñòü
if ( fabs( pMatrix[0] * pMatrix[3] - pMatrix[1] * pMatrix[2] ) < 0.000001 )
{
return SErrorSingularMatrix;
}
// Âû÷èñÿëåì ðàñòÿæåíèå, ñäâèã, ïîâîðîò è ïåðåíîñ
BOOL bRotate = fabs( pMatrix[1] ) > fabs( pMatrix[0] );
double dScaleX, dScaleY, dShearX, dShearY;
if ( bRotate )
{
dScaleX = -pMatrix[1];
dScaleY = pMatrix[2] - ( pMatrix[0] * pMatrix[3] ) / pMatrix[1];
dShearX = -pMatrix[3] / dScaleY;
dShearY = -pMatrix[0] / pMatrix[1];
}
else
{
dScaleX = pMatrix[0];
dScaleY = pMatrix[3] - ( pMatrix[1] * pMatrix[2] ) / pMatrix[0];
dShearX = pMatrix[2] / dScaleY;
dShearY = pMatrix[1] / pMatrix[0];
}
int nTransX, nTransY, nTransX2, nTransY2;
if ( bGlyphMode )
{
if ( dScaleX >= 0 )
{
nTransX = round( pMatrix[4] );
nTransX2 = round( pMatrix[4] + dScaleX ) - 1;
}
else
{
nTransX = round( pMatrix[4] ) - 1;
nTransX2 = round( pMatrix[4] + dScaleX );
}
}
else
{
if ( dScaleX >= 0 )
{
nTransX = (int)floor( pMatrix[4] - 0.01 );
nTransX2 = (int)floor( pMatrix[4] + dScaleX + 0.01 );
}
else
{
nTransX = (int)floor( pMatrix[4] + 0.01 );
nTransX2 = (int)floor( pMatrix[4] + dScaleX - 0.01 );
}
}
int nScaledWidth = abs( nTransX2 - nTransX ) + 1;
if ( bGlyphMode )
{
if ( dScaleY >= 0 )
{
nTransY = round( pMatrix[5] );
nTransY2 = round( pMatrix[5] + dScaleY ) - 1;
}
else
{
nTransY = round( pMatrix[5] ) - 1;
nTransY2 = round( pMatrix[5] + dScaleY );
}
}
else
{
if ( dScaleY >= 0 )
{
nTransY = (int)floor( pMatrix[5] - 0.01 );
nTransY2 = (int)floor( pMatrix[5] + dScaleY + 0.01 );
}
else
{
nTransY = (int)floor( pMatrix[5] + 0.01 );
nTransY2 = (int)floor( pMatrix[5] + dScaleY - 0.01 );
}
}
int nScaledHeight = abs( nTransY2 - nTransY ) + 1;
int nSignX = ( dScaleX < 0 ) ? -1 : 1;
int nSignY = ( dScaleY < 0 ) ? -1 : 1;
double dShearY1 = (double)nSignX * dShearY;
// Clipping
int nTLx1 = 0; // Top-Left-x
int nTLy1 = 0; // Top-Left-y
int nTRx1 = nSignX * ( nScaledWidth - 1 ); // Top-Right-x
int nTRy1 = (int)( dShearY * nTRx1 ); // Top-Right-y
int nBLx1 = round( dShearX * nSignY * ( nScaledHeight - 1 )); // Bottom-Left-x
int nBLy1 = nSignY * ( nScaledHeight - 1 ) + (int)( dShearY * nBLx1 ); // Bottom-Left-y
int nBRx1 = nSignX * ( nScaledWidth - 1 ) + round( dShearX * nSignY * ( nScaledHeight - 1 )); // Bottom-Right-x
int nBRy1 = nSignY * ( nScaledHeight - 1 ) + (int)( dShearY * nBRx1 ); // Bottom-Right-y
int nTLx, nTLy, nTRx, nTRy, nBLx, nBLy, nBRx, nBRy;
if ( bRotate )
{
nTLx = nTransX + nTLy1; nTLy = nTransY - nTLx1;
nTRx = nTransX + nTRy1; nTRy = nTransY - nTRx1;
nBLx = nTransX + nBLy1; nBLy = nTransY - nBLx1;
nBRx = nTransX + nBRy1; nBRy = nTransY - nBRx1;
}
else
{
nTLx = nTransX + nTLx1; nTLy = nTransY + nTLy1;
nTRx = nTransX + nTRx1; nTRy = nTransY + nTRy1;
nBLx = nTransX + nBLx1; nBLy = nTransY + nBLy1;
nBRx = nTransX + nBRx1; nBRy = nTransY + nBRy1;
}
int nMinX = (nTLx < nTRx) ? (nTLx < nBLx) ? (nTLx < nBRx) ? nTLx : nBRx : (nBLx < nBRx) ? nBLx : nBRx : (nTRx < nBLx) ? (nTRx < nBRx) ? nTRx : nBRx : (nBLx < nBRx) ? nBLx : nBRx;
int nMaxX = (nTLx > nTRx) ? (nTLx > nBLx) ? (nTLx > nBRx) ? nTLx : nBRx : (nBLx > nBRx) ? nBLx : nBRx : (nTRx > nBLx) ? (nTRx > nBRx) ? nTRx : nBRx : (nBLx > nBRx) ? nBLx : nBRx;
int nMinY = (nTLy < nTRy) ? (nTLy < nBLy) ? (nTLy < nBRy) ? nTLy : nBRy : (nBLy < nBRy) ? nBLy : nBRy : (nTRy < nBLy) ? (nTRy < nBRy) ? nTRy : nBRy : (nBLy < nBRy) ? nBLy : nBRy;
int nMaxY = (nTLy > nTRy) ? (nTLy > nBLy) ? (nTLy > nBRy) ? nTLy : nBRy : (nBLy > nBRy) ? nBLy : nBRy : (nTRy > nBLy) ? (nTRy > nBRy) ? nTRy : nBRy : (nBLy > nBRy) ? nBLy : nBRy;
SClipResult eClipResult = m_pState->m_pClip->CheckRectangle( nMinX, nMinY, nMaxX, nMaxY);
m_pOpClipRes = eClipResult;
// Âû÷èñëÿåì ïàðàìåòðû Áðåçåíõåìà äëÿ ðàñòÿæåíèÿ ïî X è Y
int nYp = nHeight / nScaledHeight;
int nYq = nHeight % nScaledHeight;
int nXp = nWidth / nScaledWidth;
int nXq = nWidth % nScaledWidth;
// Âûäåëÿåì ïàìÿòü
SColorPointer pPixels = (SColorPointer)MemUtilsMalloc( ( nYp + 1 ) * nWidth );
if ( !pPixels )
return SErrorMemory;
// Íà÷èíàåì Pipeline äëÿ ïèêñåëåé
SPipe oPipe;
PipeInit( &oPipe, 0, 0, m_pState->m_pFillPattern, NULL, m_pState->m_dFillAlpha, TRUE, FALSE );
if ( m_bVectorAA )
{
DrawAAPixelInit();
}
int nYt = 0;
int nLastStepY = 1;
for ( int nY = 0; nY < nScaledHeight; ++nY )
{
int nStepY = nYp;
nYt += nYq;
if ( nYt >= nScaledHeight )
{
nYt -= nScaledHeight;
++nStepY;
}
// Ñ÷èòûâàåì ëèíèþ(ëèíèè) èç pSrc
int nLen = ( nYp > 0 ) ? nStepY : nLastStepY;
if ( nLen > 0 )
{
SColorPointer pCur = pPixels;
for ( int nIndex = 0; nIndex < nLen; ++nIndex )
{
(*pSrc)( pSrcData, pCur );
pCur += nWidth;
}
}
nLastStepY = nStepY;
int nKoef = round( dShearX * nSignY * nY );
// Ïðîâåðÿåì Clipping
SClipResult eClipResult2;
if ( eClipResult != clipAllInside && !bRotate && (int)( dShearY * nKoef ) == (int)( dShearY * ( nSignX * ( nScaledWidth - 1 ) + nKoef ) ) )
{
int nSpanMinX, nSpanMaxX;
if ( nSignX > 0 )
{
nSpanMinX = nTransX + nKoef;
nSpanMaxX = nSpanMinX + ( nScaledWidth - 1 );
}
else
{
nSpanMaxX = nTransX + nKoef;
nSpanMinX = nSpanMaxX - ( nScaledWidth - 1 );
}
int nSpanY = nTransY + nSignY * nY + (int)( dShearY * nKoef );
eClipResult2 = m_pState->m_pClip->CheckSpan( nSpanMinX, nSpanMaxX, nSpanY );
if ( eClipResult2 == clipAllOutside )
{
continue;
}
}
else
{
eClipResult2 = eClipResult;
}
int nXt = 0;
int nSrcX = 0;
int nX1 = nKoef;
double dY1 = (double)nSignY * nY + dShearY * nX1;
// Åñëè dShearY1 îòðèöàòåëüíî, òîãäà (int)y1 èçìåíèòñÿ ñðàçó ïîñëå ïåðâîãî ïèêñåëÿ, ýòîãî íóæíî èçáåæàòü
if ( dShearY1 < 0 )
{
dY1 += 0.999;
}
nLen = ( nStepY > 0 ) ? nStepY : 1;
for ( int nX = 0; nX < nScaledWidth; ++nX )
{
int nStepX = nXp;
nXt += nXq;
if ( nXt >= nScaledWidth )
{
nXt -= nScaledWidth;
++nStepX;
}
// Ïîâîðîò
int nX2, nY2;
if ( bRotate )
{
nX2 = (int)dY1;
nY2 = -nX1;
}
else
{
nX2 = nX1;
nY2 = (int)dY1;
}
// Âû÷èñëèì çíà÷åíèå àëüôà äëÿ òî÷êè (x,y) ïîñëå îïåðàöèé ðàñòÿæåíèÿ
int nM = ( nStepX > 0 ) ? nStepX : 1;
SColorPointer pCur = pPixels + nSrcX;
int nPixAcc = 0;
for ( int nIndex = 0; nIndex < nLen; ++nIndex )
{
for ( int nJ = 0; nJ < nM; ++nJ )
{
nPixAcc += *pCur++;
}
pCur += nWidth - nM;
}
if ( nPixAcc != 0 )
{
oPipe.dShape = ( nPixAcc == nLen * nM ) ? (double)1 : (double)nPixAcc / (double)( nLen * nM );
if ( m_bVectorAA && eClipResult2 != clipAllInside )
{
DrawAAPixel( &oPipe, nTransX + nX2, nTransY + nY2 );
}
else
{
DrawPixel( &oPipe, nTransX + nX2, nTransY + nY2, eClipResult2 == clipAllInside );
}
}
nSrcX += nStepX;
// ñäâèã ïî x
nX1 += nSignX;
// ñäâèã ïî y
dY1 += dShearY1;
}
}
// Îñâîáîæäàåì ïàìÿòü
MemUtilsFree( pPixels );
return SNoError;
}
int SImage::DrawImage(SImageSource pSrc, void *pSrcData, SColorMode eColorMode, BOOL bAlpha, int nWidth, int nHeight, double *pMatrix)
{
// Ïðîâåðÿåì êîððåêòíîñòü
BOOL bValidMode = FALSE;
int nComponentsCount = 0;
switch ( m_pBitmap->m_eMode )
{
case colorModeMono1:
case colorModeMono8:
bValidMode = ( eColorMode == colorModeMono8 );
nComponentsCount = 1;
break;
case colorModeRGB8:
bValidMode = ( eColorMode == colorModeRGB8 );
nComponentsCount = 3;
break;
case colorModeBGR8:
bValidMode = ( eColorMode == colorModeBGR8 );
nComponentsCount = 3;
break;
}
if ( !bValidMode )
{
return SErrorColorModeMismatch;
}
// Ïðîâåðÿåì ìàòðèöó íà íåâûðîæäåííîñòü
if ( fabs( pMatrix[0] * pMatrix[3] - pMatrix[1] * pMatrix[2] ) < 0.000001 )
{
return SErrorSingularMatrix;
}
// Âû÷èñÿëåì ðàñòÿæåíèå, ñäâèã, ïîâîðîò è ïåðåíîñ
BOOL bRotate = fabs( pMatrix[1] ) > fabs( pMatrix[0] );
double dScaleX, dScaleY, dShearX, dShearY;
if ( bRotate )
{
dScaleX = -pMatrix[1];
dScaleY = pMatrix[2] - ( pMatrix[0] * pMatrix[3] ) / pMatrix[1];
dShearX = -pMatrix[3] / dScaleY;
dShearY = -pMatrix[0] / pMatrix[1];
}
else
{
dScaleX = pMatrix[0];
dScaleY = pMatrix[3] - ( pMatrix[1] * pMatrix[2] ) / pMatrix[0];
dShearX = pMatrix[2] / dScaleY;
dShearY = pMatrix[1] / pMatrix[0];
}
int nTransX, nTransY, nTransX2, nTransY2;
if ( dScaleX >= 0 )
{
nTransX = (int)floor( pMatrix[4] - 0.01 );
nTransX2 = (int)floor( pMatrix[4] + dScaleX + 0.01 );
}
else
{
nTransX = (int)floor( pMatrix[4] + 0.01 );
nTransX2 = (int)floor( pMatrix[4] + dScaleX - 0.01 );
}
int nScaledWidth = abs( nTransX2 - nTransX ) + 1;
if ( dScaleY >= 0 )
{
nTransY = (int)floor( pMatrix[5] - 0.01 );
nTransY2 = (int)floor( pMatrix[5] + dScaleY + 0.01 );
}
else
{
nTransY = (int)floor( pMatrix[5] + 0.01 );
nTransY2 = (int)floor( pMatrix[5] + dScaleY - 0.01 );
}
int nScaledHeight = abs( nTransY2 - nTransY ) + 1;
int nSignX = ( dScaleX < 0 ) ? -1 : 1;
int nSignY = ( dScaleY < 0 ) ? -1 : 1;
double dShearY1 = (double)nSignX * dShearY;
// Clipping
int nTLx1 = 0; // Top-Left-x
int nTLy1 = 0; // Top-Left-y
int nTRx1 = nSignX * ( nScaledWidth - 1 ); // Top-Right-x
int nTRy1 = (int)( dShearY * nTRx1 ); // Top-Right-y
int nBLx1 = round( dShearX * nSignY * ( nScaledHeight - 1 ) ); // Bottom-Left-x
int nBLy1 = nSignY * ( nScaledHeight - 1 ) + (int)( dShearY * nBLx1 ); // Bottom-Left-y
int nBRx1 = nSignX * ( nScaledWidth - 1 ) + round( dShearX * nSignY * ( nScaledHeight - 1 ) ); // Bottom-Right-x
int nBRy1 = nSignY * ( nScaledHeight - 1 ) + (int)( dShearY * nBRx1 ); // Bottom-Right-y
int nTLx, nTLy, nTRx, nTRy, nBLx, nBLy, nBRx, nBRy;
if ( bRotate )
{
nTLx = nTransX + nTLy1; nTLy = nTransY - nTLx1;
nTRx = nTransX + nTRy1; nTRy = nTransY - nTRx1;
nBLx = nTransX + nBLy1; nBLy = nTransY - nBLx1;
nBRx = nTransX + nBRy1; nBRy = nTransY - nBRx1;
}
else
{
nTLx = nTransX + nTLx1; nTLy = nTransY + nTLy1;
nTRx = nTransX + nTRx1; nTRy = nTransY + nTRy1;
nBLx = nTransX + nBLx1; nBLy = nTransY + nBLy1;
nBRx = nTransX + nBRx1; nBRy = nTransY + nBRy1;
}
int nMinX = (nTLx < nTRx) ? (nTLx < nBLx) ? (nTLx < nBRx) ? nTLx : nBRx : (nBLx < nBRx) ? nBLx : nBRx : (nTRx < nBLx) ? (nTRx < nBRx) ? nTRx : nBRx : (nBLx < nBRx) ? nBLx : nBRx;
int nMaxX = (nTLx > nTRx) ? (nTLx > nBLx) ? (nTLx > nBRx) ? nTLx : nBRx : (nBLx > nBRx) ? nBLx : nBRx : (nTRx > nBLx) ? (nTRx > nBRx) ? nTRx : nBRx : (nBLx > nBRx) ? nBLx : nBRx;
int nMinY = (nTLy < nTRy) ? (nTLy < nBLy) ? (nTLy < nBRy) ? nTLy : nBRy : (nBLy < nBRy) ? nBLy : nBRy : (nTRy < nBLy) ? (nTRy < nBRy) ? nTRy : nBRy : (nBLy < nBRy) ? nBLy : nBRy;
int nMaxY = (nTLy > nTRy) ? (nTLy > nBLy) ? (nTLy > nBRy) ? nTLy : nBRy : (nBLy > nBRy) ? nBLy : nBRy : (nTRy > nBLy) ? (nTRy > nBRy) ? nTRy : nBRy : (nBLy > nBRy) ? nBLy : nBRy;
SClipResult eClipResult = m_pState->m_pClip->CheckRectangle( nMinX, nMinY, nMaxX, nMaxY );
m_pOpClipRes = eClipResult;
if ( eClipResult == clipAllOutside )
{
return SNoError;
}
// Âû÷èñëÿåì ïàðàìåòðû Áðåçåíõåìà äëÿ ðàñòÿæåíèÿ ïî X è Y
int nYp = nHeight / nScaledHeight;
int nYq = nHeight % nScaledHeight;
int nXp = nWidth / nScaledWidth;
int nXq = nWidth % nScaledWidth;
// Âûäåëÿåì ïàìÿòü
SColorPointer pPixels = (SColorPointer)MemUtilsMalloc( ( nYp + 1 ) * nWidth * nComponentsCount );
if ( !pPixels )
return SErrorMemory;
unsigned char *pAlphaBuffer;
if ( bAlpha )
{
pAlphaBuffer = (unsigned char *)MemUtilsMalloc( ( nYp + 1 ) * nWidth );
if ( !pAlphaBuffer )
{
MemUtilsFree( pPixels );
return SErrorMemory;
}
}
else
{
pAlphaBuffer = NULL;
}
int nPixAcc0 = 0, nPixAcc1 = 0, nPixAcc2 = 0;
// Íà÷èíàåì Pipeline äëÿ ïèêñåëåé
SPipe oPipe;
SColor pPixelColor;
PipeInit( &oPipe, 0, 0, NULL, pPixelColor, m_pState->m_dFillAlpha, bAlpha || ( m_bVectorAA && eClipResult != clipAllInside ), FALSE );
if ( m_bVectorAA )
{
DrawAAPixelInit();
}
SColorPointer pCur;
unsigned char *pCurAlpha;
double dPixMul, dAlphaMul, dAlpha;
int nX1, nX2, nY2;
double dY1;
int nLen, nM;
if ( bAlpha )
{
int nYt = 0;
int nLastStepY = 1;
for ( int nY = 0; nY < nScaledHeight; ++nY )
{
int nStepY = nYp;
nYt += nYq;
if ( nYt >= nScaledHeight )
{
nYt -= nScaledHeight;
++nStepY;
}
// Ñ÷èòûâàåì îäíó ëèíèþ èç pSrcData
nLen = ( nYp > 0 ) ? nStepY : nLastStepY;
if ( nLen > 0 )
{
pCur = pPixels;
pCurAlpha = pAlphaBuffer;
for ( int nIndex = 0; nIndex < nLen; ++nIndex )
{
(*pSrc)( pSrcData, pCur, pCurAlpha );
pCur += nWidth * nComponentsCount;
pCurAlpha += nWidth;
}
}
nLastStepY = nStepY;
int nKoef = round( dShearX * nSignY * nY );
// Ïðîâåðÿåì Clipping
SClipResult eClipResult2;
if ( eClipResult != clipAllInside && !bRotate && (int)( dShearY * nKoef ) == (int)( dShearY * ( nSignX * ( nScaledWidth - 1 ) + nKoef ) ) )
{
int nSpanMinX, nSpanMaxX;
if ( nSignX > 0 )
{
nSpanMinX = nTransX + nKoef;
nSpanMaxX = nSpanMinX + ( nScaledWidth - 1 );
}
else
{
nSpanMaxX = nTransX + nKoef;
nSpanMinX = nSpanMaxX - ( nScaledWidth - 1 );
}
int nSpanY = nTransY + nSignY * nY + (int)( dShearY * nKoef );
eClipResult2 = m_pState->m_pClip->CheckSpan( nSpanMinX, nSpanMaxX, nSpanY );
if ( eClipResult2 == clipAllOutside )
{
continue;
}
}
else
{
eClipResult2 = eClipResult;
}
int nXt = 0;
int nSrcX = 0;
// Ñäâèã ïî x
nX1 = nKoef;
// Ñäâèã ïî y
dY1 = (double)nSignY * nY + dShearY * nX1;
// Åñëè dShearY1 îòðèöàòåëüíî, òîãäà (int)y1 èçìåíèòñÿ ñðàçó ïîñëå ïåðâîãî ïèêñåëÿ, ýòîãî íóæíî èçáåæàòü
if ( dShearY1 < 0 )
{
dY1 += 0.999;
}
nLen = ( nStepY > 0 ) ? nStepY : 1;
switch ( eColorMode )
{
case colorModeMono1:
case colorModeMono8:
for ( int nX = 0; nX < nScaledWidth; ++nX )
{
int nStepX = nXp;
nXt += nXq;
if ( nXt >= nScaledWidth )
{
nXt -= nScaledWidth;
++nStepX;
}
// Ïîâîðîò
if ( bRotate )
{
nX2 = (int)dY1;
nY2 = -nX1;
}
else
{
nX2 = nX1;
nY2 = (int)dY1;
}
nM = ( nStepX > 0 ) ? nStepX : 1;
int nAlphaAcc = 0;
pCur = pPixels + nSrcX;
pCurAlpha = pAlphaBuffer + nSrcX;
nPixAcc0 = 0;
for ( int nIndex = 0; nIndex < nLen; ++nIndex )
{
for ( int nJ = 0; nJ < nM; ++nJ )
{
nPixAcc0 += *pCur++;
nAlphaAcc += *pCurAlpha++;
}
pCur += nWidth - nM;
pCurAlpha += nWidth - nM;
}
dPixMul = (double)1 / (double)(nLen * nM);
dAlphaMul = dPixMul * (1.0 / 255.0);
dAlpha = (double)nAlphaAcc * dAlphaMul;
if ( dAlpha > 0 )
{
pPixelColor[0] = (int)((double)nPixAcc0 * dPixMul);
oPipe.dShape = dAlpha;
if ( m_bVectorAA && eClipResult != clipAllInside )
{
DrawAAPixel( &oPipe, nTransX + nX2, nTransY + nY2 );
}
else
{
DrawPixel( &oPipe, nTransX + nX2, nTransY + nY2, eClipResult2 == clipAllInside );
}
}
nSrcX += nStepX;
// Ñäâèã ïî x
nX1 += nSignX;
// Ñäâèã ïî y
dY1 += dShearY1;
}
break;
case colorModeRGB8:
case colorModeBGR8:
for ( int nX = 0; nX < nScaledWidth; ++nX )
{
int nStepX = nXp;
nXt += nXq;
if ( nXt >= nScaledWidth )
{
nXt -= nScaledWidth;
++nStepX;
}
// Ïîâîðîò
if ( bRotate )
{
nX2 = (int)dY1;
nY2 = -nX1;
}
else
{
nX2 = nX1;
nY2 = (int)dY1;
}
nM = ( nStepX > 0 ) ? nStepX : 1;
int nAlphaAcc = 0;
pCur = pPixels + nSrcX * 3;
pCurAlpha = pAlphaBuffer + nSrcX;
nPixAcc0 = nPixAcc1 = nPixAcc2 = 0;
for ( int nIndex = 0; nIndex < nLen; ++nIndex )
{
for ( int nJ = 0; nJ < nM; ++nJ )
{
nPixAcc0 += *pCur++;
nPixAcc1 += *pCur++;
nPixAcc2 += *pCur++;
nAlphaAcc += *pCurAlpha++;
}
pCur += 3 * (nWidth - nM);
pCurAlpha += nWidth - nM;
}
dPixMul = (double)1 / (double)(nLen * nM);
dAlphaMul = dPixMul * (1.0 / 255.0);
dAlpha = (double)nAlphaAcc * dAlphaMul;
if ( dAlpha > 0 )
{
pPixelColor[0] = (int)((double)nPixAcc0 * dPixMul);
pPixelColor[1] = (int)((double)nPixAcc1 * dPixMul);
pPixelColor[2] = (int)((double)nPixAcc2 * dPixMul);
oPipe.dShape = dAlpha;
if ( m_bVectorAA && eClipResult != clipAllInside )
{
DrawAAPixel( &oPipe, nTransX + nX2, nTransY + nY2 );
}
else
{
DrawPixel( &oPipe, nTransX + nX2, nTransY + nY2, eClipResult2 == clipAllInside );
}
}
nSrcX += nStepX;
// Ñäâèã ïî X
nX1 += nSignX;
// Ñäâèã ïî Y
dY1 += dShearY1;
}
break;
}
}
}
else
{
int nYt = 0;
int nLastStepY = 1;
for ( int nY = 0; nY < nScaledHeight; ++nY )
{
int nStepY = nYp;
nYt += nYq;
if ( nYt >= nScaledHeight )
{
nYt -= nScaledHeight;
++nStepY;
}
// Ñ÷èòûâàåì îäíó ëèíèþ èç pSrcData
nLen = ( nYp > 0 ) ? nStepY : nLastStepY;
if ( nLen > 0 )
{
pCur = pPixels;
for ( int nIndex = 0; nIndex < nLen; ++nIndex )
{
(*pSrc)( pSrcData, pCur, NULL );
pCur += nWidth * nComponentsCount;
}
}
nLastStepY = nStepY;
int nKoef = round( dShearX * nSignY * nY );
// Ïðîâåðÿåì Clipping
SClipResult eClipResult2;
if ( eClipResult != clipAllInside && !bRotate && (int)( dShearY * nKoef ) == (int)( dShearY * ( nSignX * ( nScaledWidth - 1 ) + nKoef ) ) )
{
int nSpanMinX, nSpanMaxX;
if ( nSignX > 0 )
{
nSpanMinX = nTransX + nKoef;
nSpanMaxX = nSpanMinX + ( nScaledWidth - 1 );
}
else
{
nSpanMaxX = nTransX + nKoef;
nSpanMinX = nSpanMaxX - ( nScaledWidth - 1 );
}
int nSpanY = nTransY + nSignY * nY + (int)( dShearY * nKoef );
eClipResult2 = m_pState->m_pClip->CheckSpan( nSpanMinX, nSpanMaxX, nSpanY );
if ( eClipResult2 == clipAllOutside )
{
continue;
}
}
else
{
eClipResult2 = eClipResult;
}
int nXt = 0;
int nSrcX = 0;
// Ñäâèã ïî x
nX1 = nKoef;
// Ñäâèã ïî y
dY1 = (double)nSignY * nY + dShearY * nX1;
// Åñëè dShearY1 îòðèöàòåëüíî, òîãäà (int)y1 èçìåíèòñÿ ñðàçó ïîñëå ïåðâîãî ïèêñåëÿ, ýòîãî íóæíî èçáåæàòü
if ( dShearY1 < 0 )
{
dY1 += 0.999;
}
nLen = ( nStepY > 0 ) ? nStepY : 1;
switch ( eColorMode )
{
case colorModeMono1:
case colorModeMono8:
for ( int nX = 0; nX < nScaledWidth; ++nX )
{
int nStepX = nXp;
nXt += nXq;
if ( nXt >= nScaledWidth )
{
nXt -= nScaledWidth;
++nStepX;
}
// Ïîâîðîò
if ( bRotate )
{
nX2 = (int)dY1;
nY2 = -nX1;
}
else
{
nX2 = nX1;
nY2 = (int)dY1;
}
nM = ( nStepX > 0 ) ? nStepX : 1;
pCur = pPixels + nSrcX;
nPixAcc0 = 0;
for ( int nIndex = 0; nIndex < nLen; ++nIndex )
{
for ( int nJ = 0; nJ < nM; ++nJ )
{
nPixAcc0 += *pCur++;
}
pCur += nWidth - nM;
}
dPixMul = (double)1 / (double)(nLen * nM);
pPixelColor[0] = (int)((double)nPixAcc0 * dPixMul);
if ( m_bVectorAA && eClipResult != clipAllInside )
{
oPipe.dShape = (double)1;
DrawAAPixel( &oPipe, nTransX + nX2, nTransY + nY2 );
}
else
{
DrawPixel( &oPipe, nTransX + nX2, nTransY + nY2, eClipResult2 == clipAllInside );
}
nSrcX += nStepX;
// Ñäâèã ïî x
nX1 += nSignX;
// Ñäâèã ïî y
dY1 += dShearY1;
}
break;
case colorModeRGB8:
case colorModeBGR8:
for ( int nX = 0; nX < nScaledWidth; ++nX )
{
int nStepX = nXp;
nXt += nXq;
if ( nXt >= nScaledWidth )
{
nXt -= nScaledWidth;
++nStepX;
}
// Ïîâîðîò
if ( bRotate )
{
nX2 = (int)dY1;
nY2 = -nX1;
}
else
{
nX2 = nX1;
nY2 = (int)dY1;
}
nM = ( nStepX > 0 ) ? nStepX : 1;
pCur = pPixels + nSrcX * 3;
nPixAcc0 = nPixAcc1 = nPixAcc2 = 0;
for ( int nIndex = 0; nIndex < nLen; ++nIndex )
{
for ( int nJ = 0; nJ < nM; ++nJ )
{
nPixAcc0 += *pCur++;
nPixAcc1 += *pCur++;
nPixAcc2 += *pCur++;
}
pCur += 3 * (nWidth - nM);
}
dPixMul = (double)1 / (double)(nLen * nM);
pPixelColor[0] = (int)((double)nPixAcc0 * dPixMul);
pPixelColor[1] = (int)((double)nPixAcc1 * dPixMul);
pPixelColor[2] = (int)((double)nPixAcc2 * dPixMul);
if ( m_bVectorAA && eClipResult != clipAllInside )
{
oPipe.dShape = (double)1;
DrawAAPixel( &oPipe, nTransX + nX2, nTransY + nY2 );
}
else
{
DrawPixel( &oPipe, nTransX + nX2, nTransY + nY2, eClipResult2 == clipAllInside );
}
nSrcX += nStepX;
// Ñäâèã ïî x
nX1 += nSignX;
// Ñäâèã ïî y
dY1 += dShearY1;
}
break;
}
}
}
MemUtilsFree( pPixels );
MemUtilsFree( pAlphaBuffer );
return SNoError;
}
int SImage::Composite(SBitmap *pSrc, int nSrcX, int nSrcY, int nDestX, int nDestY, int nWidth, int nHeight, BOOL bNoClip, BOOL bNonIsolated)
{
if ( pSrc->m_eMode != m_pBitmap->m_eMode )
{
return SErrorColorModeMismatch;
}
SPipe oPipe;
SColor pPixelColor;
if ( pSrc->m_pAlpha )
{
PipeInit( &oPipe, nDestX, nDestY, NULL, pPixelColor, m_pState->m_dFillAlpha, TRUE, bNonIsolated );
for ( int nY = 0; nY < nHeight; ++nY )
{
PipeSetXY( &oPipe, nDestX, nDestY + nY );
unsigned char *pAlpha = pSrc->GetAlpha() + ( nSrcY + nY ) * pSrc->GetWidth() + nSrcX;
for ( int nX = 0; nX < nWidth; ++nX )
{
pSrc->GetPixel( nSrcX + nX, nSrcY + nY, pPixelColor );
unsigned char unAlpha = *pAlpha++;
if ( bNoClip || m_pState->m_pClip->IsInsideClip( nDestX + nX, nDestY + nY ) )
{
// Èñïîëüçóåì dShape âñìåñòî àëüôû(âîîáùå ãîâîðÿ, ýòî íåïðàâèëüíî, íî ðàáîòàåò)
oPipe.dShape = (double)(unAlpha / 255.0);
PipeRun( &oPipe );
UpdateModX( nDestX + nX );
UpdateModY( nDestY + nY );
}
else
{
PipeIncreaseX( &oPipe );
}
}
}
}
else
{
PipeInit( &oPipe, nDestX, nDestY, NULL, pPixelColor, m_pState->m_dFillAlpha, FALSE, bNonIsolated );
for ( int nY = 0; nY < nHeight; ++nY )
{
PipeSetXY( &oPipe, nDestX, nDestY + nY );
for ( int nX = 0; nX < nWidth; ++nX )
{
pSrc->GetPixel( nSrcX + nX, nSrcY + nY, pPixelColor );
if ( bNoClip || m_pState->m_pClip->IsInsideClip( nDestX + nX, nDestY + nY ) )
{
PipeRun( &oPipe );
UpdateModX( nDestX + nX );
UpdateModY( nDestY + nY );
}
else
{
PipeIncreaseX( &oPipe );
}
}
}
}
return SNoError;
}
void SImage::CompositeBackground(SColorPointer pColor)
{
SColorPointer pCurPixel;
unsigned char *pCurAlpha;
unsigned char unAlpha, unAlpha1, unColor0, unColor1, unColor2;
switch ( m_pBitmap->m_eMode )
{
case colorModeMono1:
unColor0 = pColor[0];
for ( int nY = 0; nY < m_pBitmap->m_nHeight; ++nY )
{
pCurPixel = &m_pBitmap->m_pData[nY * m_pBitmap->m_nStride];
pCurAlpha = &m_pBitmap->m_pAlpha[nY * m_pBitmap->m_nWidth];
int nMask = 0x80;
for ( int nX = 0; nX < m_pBitmap->m_nWidth; ++nX )
{
unAlpha = *pCurAlpha++;
unAlpha1 = 255 - unAlpha;
unsigned char unChar = (*pCurPixel & nMask) ? 0xff : 0x00;
unChar = Div255( unAlpha1 * unColor0 + unAlpha * unChar );
if ( unChar & 0x80 )
{
*pCurPixel |= nMask;
}
else
{
*pCurPixel &= ~nMask;
}
if ( !( nMask >>= 1 ) )
{
nMask = 0x80;
++pCurPixel;
}
}
}
break;
case colorModeMono8:
unColor0 = pColor[0];
for ( int nY = 0; nY < m_pBitmap->m_nHeight; ++nY )
{
pCurPixel = &m_pBitmap->m_pData[nY * m_pBitmap->m_nStride];
pCurAlpha = &m_pBitmap->m_pAlpha[nY * m_pBitmap->m_nWidth];
for ( int nX = 0; nX < m_pBitmap->m_nWidth; ++nX )
{
unAlpha = *pCurAlpha++;
unAlpha1 = 255 - unAlpha;
pCurPixel[0] = Div255( unAlpha1 * unColor0 + unAlpha * pCurPixel[0] );
++pCurPixel;
}
}
break;
case colorModeRGB8:
case colorModeBGR8:
unColor0 = pColor[0];
unColor1 = pColor[1];
unColor2 = pColor[2];
for ( int nY = 0; nY < m_pBitmap->m_nHeight; ++nY )
{
pCurPixel = &m_pBitmap->m_pData[nY * m_pBitmap->m_nStride];
pCurAlpha = &m_pBitmap->m_pAlpha[nY * m_pBitmap->m_nWidth];
for ( int nX = 0; nX < m_pBitmap->m_nWidth; ++nX )
{
unAlpha = *pCurAlpha++;
unAlpha1 = 255 - unAlpha;
pCurPixel[0] = Div255( unAlpha1 * unColor0 + unAlpha * pCurPixel[0] );
pCurPixel[1] = Div255( unAlpha1 * unColor1 + unAlpha * pCurPixel[1] );
pCurPixel[2] = Div255( unAlpha1 * unColor2 + unAlpha * pCurPixel[2] );
pCurPixel += 3;
}
}
break;
}
memset( m_pBitmap->m_pAlpha, 255, m_pBitmap->m_nWidth * m_pBitmap->m_nHeight );
}
int SImage::BlitTransparent(SBitmap *pSrc, int nSrcX, int nSrcY, int nDestX, int nDestY, int nWidth, int nHeight)
{
if ( pSrc->m_eMode != m_pBitmap->m_eMode )
{
return SErrorColorModeMismatch;
}
SColor pPixelColor;
SColorPointer pCurPixel;
switch ( m_pBitmap->m_eMode )
{
case colorModeMono1:
for ( int nY = 0; nY < nHeight; ++nY )
{
pCurPixel = &m_pBitmap->m_pData[(nDestY + nY) * m_pBitmap->m_nStride + (nDestX >> 3)];
int nMask = 0x80 >> (nDestX & 7);
for ( int nX = 0; nX < nWidth; ++nX )
{
pSrc->GetPixel( nSrcX + nX, nSrcY + nY, pPixelColor );
if ( pPixelColor[0] )
{
*pCurPixel |= nMask;
}
else
{
*pCurPixel &= ~nMask;
}
if ( !(nMask >>= 1) )
{
nMask = 0x80;
++pCurPixel;
}
}
}
break;
case colorModeMono8:
for ( int nY = 0; nY < nHeight; ++nY )
{
pCurPixel = &m_pBitmap->m_pData[(nDestY + nY) * m_pBitmap->m_nStride + nDestX];
for ( int nX = 0; nX < nWidth; ++nX )
{
pSrc->GetPixel( nSrcX + nX, nSrcY + nY, pPixelColor );
*pCurPixel++ = pPixelColor[0];
}
}
break;
case colorModeRGB8:
case colorModeBGR8:
for ( int nY = 0; nY < nHeight; ++nY )
{
pCurPixel = &m_pBitmap->m_pData[(nDestY + nY) * m_pBitmap->m_nStride + 3 * nDestX];
for ( int nX = 0; nX < nWidth; ++nX )
{
pSrc->GetPixel( nSrcX + nX, nSrcY + nY, pPixelColor );
*pCurPixel++ = pPixelColor[0];
*pCurPixel++ = pPixelColor[1];
*pCurPixel++ = pPixelColor[2];
}
}
break;
}
if ( m_pBitmap->m_pAlpha )
{
for ( int nY = 0; nY < nHeight; ++nY )
{
unsigned char *pCurAlpha = &m_pBitmap->m_pAlpha[(nDestY + nY) * m_pBitmap->m_nWidth + nDestX];
for ( int nX = 0; nX < nWidth; ++nX )
{
*pCurAlpha++ = 0x00;
}
}
}
return SNoError;
}
SPath *SImage::MakeStrokePath(SPath *pPath, BOOL bFlatten)
{
SPath *pPathIn, *pPathOut;
if ( bFlatten )
{
pPathIn = FlattenPath( pPath, m_pState->m_arrdMatrix, m_pState->m_dFlatness );
if ( m_pState->m_nLineDashCount > 0 )
{
pPathOut = MakeDashedPath( pPathIn );
delete pPathIn;
pPathIn = pPathOut;
}
}
else
{
pPathIn = pPath;
}
int nSubpathStart = 0;
BOOL bClosed = FALSE;
int nLeft0 = 0, nLeft1 = 0, nRight0 = 0, nRight1 = 0, nJoin0 = 0, nJoin1 = 0, nLeft2, nRight2, nJoin2;
int nLeftFirst = 0, nRightFirst = 0, nFirstPoint = 0;
pPathOut = new SPath();
double dWidth = m_pState->m_dLineWidth;
for ( int nIndex = 0; nIndex < pPathIn->m_nPointsCount - 1; ++nIndex )
{
if ( pPathIn->m_pFlags[nIndex] & SPathLast )
{
continue;
}
BOOL bFirst;
if ( ( bFirst = pPathIn->m_pFlags[nIndex] & SPathFirst ) )
{
nSubpathStart = nIndex;
bClosed = pPathIn->m_pFlags[nIndex] & SPathClosed;
}
BOOL bLast = pPathIn->m_pFlags[nIndex + 1] & SPathLast;
// Âû÷èñëèì äèàãîíàëü ñåãìåíòà ( nIndex, nIndex + 1 )
double dDist = distance( pPathIn->m_pPoints[nIndex].dX, pPathIn->m_pPoints[nIndex].dY, pPathIn->m_pPoints[nIndex + 1].dX, pPathIn->m_pPoints[nIndex + 1].dY );
double dDx, dDy;
if ( dDist == 0 )
{
dDx = 0;
dDy = 1;
}
else
{
dDist = (double)1 / dDist;
dDx = dDist * ( pPathIn->m_pPoints[nIndex + 1].dX - pPathIn->m_pPoints[nIndex].dX );
dDy = dDist * ( pPathIn->m_pPoints[nIndex + 1].dY - pPathIn->m_pPoints[nIndex].dY );
}
double dWidthDx = (double)0.5 * dWidth * dDx;
double dWidthDy = (double)0.5 * dWidth * dDy;
// Âû÷èñëèì äèàãîíàëü ñåãìåíòà ( nIndex + 1, nNext )
int nNext = bLast ? nSubpathStart + 1 : nIndex + 2;
dDist = distance( pPathIn->m_pPoints[nIndex + 1].dX, pPathIn->m_pPoints[nIndex + 1].dY, pPathIn->m_pPoints[nNext].dX, pPathIn->m_pPoints[nNext].dY );
double dNextDx, dNextDy;
if ( dDist == 0 )
{
dNextDx = 0;
dNextDy = 1;
}
else
{
dDist = (double)1 / dDist;
dNextDx = dDist * ( pPathIn->m_pPoints[nNext].dX - pPathIn->m_pPoints[nIndex + 1].dX );
dNextDy = dDist * ( pPathIn->m_pPoints[nNext].dY - pPathIn->m_pPoints[nIndex + 1].dY );
}
double dWidthNextDx = (double)0.5 * dWidth * dNextDx;
double dWidthNextDy = (double)0.5 * dWidth * dNextDy;
// Ðèñóåì íà÷àëî ëèíèè
pPathOut->MoveTo( pPathIn->m_pPoints[nIndex].dX - dWidthDy, pPathIn->m_pPoints[nIndex].dY + dWidthDx );
if ( nIndex == nSubpathStart )
{
nFirstPoint = pPathOut->m_nPointsCount - 1;
}
if ( bFirst && !bClosed )
{
switch ( m_pState->m_nLineCap )
{
case LineCapButt:
pPathOut->LineTo( pPathIn->m_pPoints[nIndex].dX + dWidthDy, pPathIn->m_pPoints[nIndex].dY - dWidthDx );
break;
case LineCapRound:
pPathOut->CurveTo( pPathIn->m_pPoints[nIndex].dX - dWidthDy - c_dKappa * dWidthDx, pPathIn->m_pPoints[nIndex].dY + dWidthDx - c_dKappa * dWidthDy, pPathIn->m_pPoints[nIndex].dX - dWidthDx - c_dKappa * dWidthDy, pPathIn->m_pPoints[nIndex].dY - dWidthDy + c_dKappa * dWidthDx, pPathIn->m_pPoints[nIndex].dX - dWidthDx, pPathIn->m_pPoints[nIndex].dY - dWidthDy );
pPathOut->CurveTo( pPathIn->m_pPoints[nIndex].dX - dWidthDx + c_dKappa * dWidthDy, pPathIn->m_pPoints[nIndex].dY - dWidthDy - c_dKappa * dWidthDx, pPathIn->m_pPoints[nIndex].dX + dWidthDy - c_dKappa * dWidthDx, pPathIn->m_pPoints[nIndex].dY - dWidthDx - c_dKappa * dWidthDy, pPathIn->m_pPoints[nIndex].dX + dWidthDy, pPathIn->m_pPoints[nIndex].dY - dWidthDx );
break;
case LineCapProjecting:
pPathOut->LineTo( pPathIn->m_pPoints[nIndex].dX - dWidthDx - dWidthDy, pPathIn->m_pPoints[nIndex].dY + dWidthDx - dWidthDy );
pPathOut->LineTo( pPathIn->m_pPoints[nIndex].dX - dWidthDx + dWidthDy, pPathIn->m_pPoints[nIndex].dY - dWidthDx - dWidthDy );
pPathOut->LineTo( pPathIn->m_pPoints[nIndex].dX + dWidthDy, pPathIn->m_pPoints[nIndex].dY - dWidthDx );
break;
}
}
else
{
pPathOut->LineTo( pPathIn->m_pPoints[nIndex].dX + dWidthDy, pPathIn->m_pPoints[nIndex].dY - dWidthDx );
}
// Ðèñóåì ëåâóþ ñòîðîíóþ äëÿ ïðÿìîóãîëüíèêà ñåãìåíòà
nLeft2 = pPathOut->m_nPointsCount - 1;
pPathOut->LineTo( pPathIn->m_pPoints[nIndex + 1].dX + dWidthDy, pPathIn->m_pPoints[nIndex + 1].dY - dWidthDx );
// Ðèñóåì îêîí÷àíèå ëèíèè
if ( bLast && !bClosed )
{
switch (m_pState->m_nLineCap)
{
case LineCapButt:
pPathOut->LineTo( pPathIn->m_pPoints[nIndex + 1].dX - dWidthDy, pPathIn->m_pPoints[nIndex + 1].dY + dWidthDx );
break;
case LineCapRound:
pPathOut->CurveTo( pPathIn->m_pPoints[nIndex + 1].dX + dWidthDy + c_dKappa * dWidthDx, pPathIn->m_pPoints[nIndex + 1].dY - dWidthDx + c_dKappa * dWidthDy, pPathIn->m_pPoints[nIndex + 1].dX + dWidthDx + c_dKappa * dWidthDy, pPathIn->m_pPoints[nIndex + 1].dY + dWidthDy - c_dKappa * dWidthDx, pPathIn->m_pPoints[nIndex + 1].dX + dWidthDx, pPathIn->m_pPoints[nIndex + 1].dY + dWidthDy );
pPathOut->CurveTo( pPathIn->m_pPoints[nIndex + 1].dX + dWidthDx - c_dKappa * dWidthDy, pPathIn->m_pPoints[nIndex + 1].dY + dWidthDy + c_dKappa * dWidthDx, pPathIn->m_pPoints[nIndex + 1].dX - dWidthDy + c_dKappa * dWidthDx, pPathIn->m_pPoints[nIndex + 1].dY + dWidthDx + c_dKappa * dWidthDy, pPathIn->m_pPoints[nIndex + 1].dX - dWidthDy, pPathIn->m_pPoints[nIndex + 1].dY + dWidthDx );
break;
case LineCapProjecting:
pPathOut->LineTo( pPathIn->m_pPoints[nIndex + 1].dX + dWidthDy + dWidthDx, pPathIn->m_pPoints[nIndex + 1].dY - dWidthDx + dWidthDy );
pPathOut->LineTo( pPathIn->m_pPoints[nIndex + 1].dX - dWidthDy + dWidthDx, pPathIn->m_pPoints[nIndex + 1].dY + dWidthDx + dWidthDy );
pPathOut->LineTo( pPathIn->m_pPoints[nIndex + 1].dX - dWidthDy, pPathIn->m_pPoints[nIndex + 1].dY + dWidthDx );
break;
}
}
else
{
pPathOut->LineTo( pPathIn->m_pPoints[nIndex + 1].dX - dWidthDy, pPathIn->m_pPoints[nIndex + 1].dY + dWidthDx );
}
// Ðèñóåì ïðàâóþ ñòîðîíóþ äëÿ ïðÿìîóãîëüíèêà ñåãìåíòà
nRight2 = pPathOut->m_nPointsCount - 1;
pPathOut->Close();
// Ðèñóåì ñîåäèíåíèå
nJoin2 = pPathOut->m_nPointsCount;
if ( !bLast || bClosed )
{
double dCrossprod = dDx * dNextDy - dDy * dNextDx;
double dDotprod = -(dDx * dNextDx + dDy * dNextDy);
double dMiter, dMit;
if ( dDotprod > 0.99999 )
{
// Äëÿ èçáåæàíèÿ äåëåíèé íà íîëü
dMiter = ( m_pState->m_dMiterLimit + 1 ) * ( m_pState->m_dMiterLimit + 1 );
dMit = 0;
}
else
{
dMiter = (double)2 / ((double)1 - dDotprod);
if ( dMiter < 1 )
{
dMiter = 1;
}
dMit = sqrt( dMiter - 1 );
}
// Ñêðóãëåííîå ñîåäèíåíèå
if ( m_pState->m_nLineJoin == LineJoinRound )
{
pPathOut->MoveTo ( pPathIn->m_pPoints[nIndex + 1].dX + (double)0.5 * dWidth, pPathIn->m_pPoints[nIndex + 1].dY );
pPathOut->CurveTo( pPathIn->m_pPoints[nIndex + 1].dX + (double)0.5 * dWidth, pPathIn->m_pPoints[nIndex + 1].dY + c_dKappa_2 * dWidth, pPathIn->m_pPoints[nIndex + 1].dX + c_dKappa_2 * dWidth, pPathIn->m_pPoints[nIndex + 1].dY + (double)0.5 * dWidth, pPathIn->m_pPoints[nIndex + 1].dX, pPathIn->m_pPoints[nIndex + 1].dY + (double)0.5 * dWidth );
pPathOut->CurveTo( pPathIn->m_pPoints[nIndex + 1].dX - c_dKappa_2 * dWidth, pPathIn->m_pPoints[nIndex + 1].dY + (double)0.5 * dWidth, pPathIn->m_pPoints[nIndex + 1].dX - (double)0.5 * dWidth, pPathIn->m_pPoints[nIndex + 1].dY + c_dKappa_2 * dWidth, pPathIn->m_pPoints[nIndex + 1].dX - (double)0.5 * dWidth, pPathIn->m_pPoints[nIndex + 1].dY );
pPathOut->CurveTo( pPathIn->m_pPoints[nIndex + 1].dX - (double)0.5 * dWidth, pPathIn->m_pPoints[nIndex + 1].dY - c_dKappa_2 * dWidth, pPathIn->m_pPoints[nIndex + 1].dX - c_dKappa_2 * dWidth, pPathIn->m_pPoints[nIndex + 1].dY - (double)0.5 * dWidth, pPathIn->m_pPoints[nIndex + 1].dX, pPathIn->m_pPoints[nIndex + 1].dY - (double)0.5 * dWidth );
pPathOut->CurveTo( pPathIn->m_pPoints[nIndex + 1].dX + c_dKappa_2 * dWidth, pPathIn->m_pPoints[nIndex + 1].dY - (double)0.5 * dWidth, pPathIn->m_pPoints[nIndex + 1].dX + (double)0.5 * dWidth, pPathIn->m_pPoints[nIndex + 1].dY - c_dKappa_2 * dWidth, pPathIn->m_pPoints[nIndex + 1].dX + (double)0.5 * dWidth, pPathIn->m_pPoints[nIndex + 1].dY );
}
else
{
pPathOut->MoveTo( pPathIn->m_pPoints[nIndex + 1].dX, pPathIn->m_pPoints[nIndex + 1].dY );
if ( dCrossprod < 0 ) // Óãîë < 180
{
pPathOut->LineTo( pPathIn->m_pPoints[nIndex + 1].dX - dWidthNextDy, pPathIn->m_pPoints[nIndex + 1].dY + dWidthNextDx );
if ( m_pState->m_nLineJoin == LineJoinMiter && sqrt( dMiter ) <= m_pState->m_dMiterLimit ) // òèï ñîåäèíåíèÿ = LineJoinMiter è dMiter ìåíüøå dMiterLimit
{
pPathOut->LineTo( pPathIn->m_pPoints[nIndex + 1].dX - dWidthDy + dWidthDx * dMit, pPathIn->m_pPoints[nIndex + 1].dY + dWidthDx + dWidthDy * dMit );
pPathOut->LineTo( pPathIn->m_pPoints[nIndex + 1].dX - dWidthDy, pPathIn->m_pPoints[nIndex + 1].dY + dWidthDx );
}
else // ëèáî òèï ñîåäèíåíèÿ = LineJoinBevel, ëèáî dMiter áîëüøå dMiterLimit
{
pPathOut->LineTo( pPathIn->m_pPoints[nIndex + 1].dX - dWidthDy, pPathIn->m_pPoints[nIndex + 1].dY + dWidthDx );
}
}
else // Óãîë >= 180
{
pPathOut->LineTo( pPathIn->m_pPoints[nIndex + 1].dX + dWidthDy, pPathIn->m_pPoints[nIndex + 1].dY - dWidthDx );
if ( m_pState->m_nLineJoin == LineJoinMiter && sqrt( dMiter ) <= m_pState->m_dMiterLimit ) // òèï ñîåäèíåíèÿ = LineJoinMiter è dMiter ìåíüøå dMiterLimit
{
pPathOut->LineTo( pPathIn->m_pPoints[nIndex + 1].dX + dWidthDy + dWidthDx * dMit, pPathIn->m_pPoints[nIndex + 1].dY - dWidthDx + dWidthDy * dMit );
pPathOut->LineTo( pPathIn->m_pPoints[nIndex + 1].dX + dWidthNextDy, pPathIn->m_pPoints[nIndex + 1].dY - dWidthNextDx );
}
else // ëèáî òèï ñîåäèíåíèÿ = LineJoinBevel, ëèáî dMiter áîëüøå dMiterLimit
{
pPathOut->LineTo( pPathIn->m_pPoints[nIndex + 1].dX + dWidthNextDy, pPathIn->m_pPoints[nIndex + 1].dY - dWidthNextDx );
}
}
}
pPathOut->Close();
}
if ( m_pState->m_bStrokeAdjust )
{
if ( nIndex >= nSubpathStart + 1 )
{
if ( nIndex >= nSubpathStart + 2 )
{
pPathOut->AddStrokeAdjustHint( nLeft1, nRight1, nLeft0 + 1, nRight0 );
pPathOut->AddStrokeAdjustHint( nLeft1, nRight1, nJoin0, nLeft2 );
}
else
{
pPathOut->AddStrokeAdjustHint( nLeft1, nRight1, nFirstPoint, nLeft2 );
}
pPathOut->AddStrokeAdjustHint( nLeft1, nRight1, nRight2 + 1, nRight2 + 1 );
}
nLeft0 = nLeft1;
nLeft1 = nLeft2;
nRight0 = nRight1;
nRight1 = nRight2;
nJoin0 = nJoin1;
nJoin1 = nJoin2;
if ( nIndex == nSubpathStart )
{
nLeftFirst = nLeft2;
nRightFirst = nRight2;
}
if ( bLast )
{
if ( nIndex >= nSubpathStart + 2 )
{
pPathOut->AddStrokeAdjustHint( nLeft1, nRight1, nLeft0 + 1, nRight0 );
pPathOut->AddStrokeAdjustHint( nLeft1, nRight1, nJoin0, pPathOut->m_nPointsCount - 1 );
}
else
{
pPathOut->AddStrokeAdjustHint( nLeft1, nRight1, nFirstPoint, pPathOut->m_nPointsCount - 1 );
}
if ( bClosed )
{
pPathOut->AddStrokeAdjustHint( nLeft1, nRight1, nFirstPoint, nLeftFirst );
pPathOut->AddStrokeAdjustHint( nLeft1, nRight1, nRightFirst + 1, nRightFirst + 1 );
pPathOut->AddStrokeAdjustHint( nLeftFirst, nRightFirst, nLeft1 + 1, nRight1 );
pPathOut->AddStrokeAdjustHint( nLeftFirst, nRightFirst, nJoin1, pPathOut->m_nPointsCount - 1 );
}
}
}
}
if ( pPathIn != pPath )
{
delete pPathIn;
}
return pPathOut;
}