mirror of
https://github.com/ONLYOFFICE/core.git
synced 2026-02-10 18:05:41 +08:00
5032 lines
155 KiB
C++
5032 lines
155 KiB
C++
/*
|
||
* (c) Copyright Ascensio System SIA 2010-2023
|
||
*
|
||
* This program is a free software product. You can redistribute it and/or
|
||
* modify it under the terms of the GNU Affero General Public License (AGPL)
|
||
* version 3 as published by the Free Software Foundation. In accordance with
|
||
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
|
||
* that Ascensio System SIA expressly excludes the warranty of non-infringement
|
||
* of any third-party rights.
|
||
*
|
||
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
|
||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
|
||
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||
*
|
||
* You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish
|
||
* street, Riga, Latvia, EU, LV-1050.
|
||
*
|
||
* The interactive user interfaces in modified source and object code versions
|
||
* of the Program must display Appropriate Legal Notices, as required under
|
||
* Section 5 of the GNU AGPL version 3.
|
||
*
|
||
* Pursuant to Section 7(b) of the License you must retain the original Product
|
||
* logo when distributing the program. Pursuant to Section 7(e) we decline to
|
||
* grant you any rights under trademark law for use of our trademarks.
|
||
*
|
||
* All the Product's GUI elements, including illustrations and icon sets, as
|
||
* well as technical writing content are licensed under the terms of the
|
||
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
|
||
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||
*
|
||
*/
|
||
|
||
#include "Adaptors.h"
|
||
#include "../lib/xpdf/ErrorCodes.h"
|
||
#include "../lib/xpdf/GfxState.h"
|
||
#include "../lib/xpdf/GfxFont.h"
|
||
#include "../lib/fofi/FoFiTrueType.h"
|
||
#include "../lib/fofi/FoFiType1C.h"
|
||
#include "../lib/fofi/FoFiIdentifier.h"
|
||
#include "../lib/xpdf/Page.h"
|
||
#include "../lib/xpdf/Dict.h"
|
||
#include "../lib/xpdf/Stream.h"
|
||
#include "../lib/xpdf/PDFDoc.h"
|
||
#include "../lib/xpdf/CharCodeToUnicode.h"
|
||
#include "RendererOutputDev.h"
|
||
#include "XmlUtils.h"
|
||
|
||
#include "../../DesktopEditor/graphics/Image.h"
|
||
#include "../../DesktopEditor/graphics/pro/Fonts.h"
|
||
#include "../../DesktopEditor/common/File.h"
|
||
#include "../../DesktopEditor/common/Path.h"
|
||
#include "../../DesktopEditor/common/Array.h"
|
||
#include "../../DesktopEditor/graphics/BaseThread.h"
|
||
#include "../../DesktopEditor/graphics/commands/DocInfo.h"
|
||
#include "../../DesktopEditor/graphics/AlphaMask.h"
|
||
#include "../Resources/BaseFonts.h"
|
||
#include <new>
|
||
|
||
#ifndef BUILDING_WASM_MODULE
|
||
#define FONTS_USE_AFM_SETTINGS
|
||
#else
|
||
#include "../../DesktopEditor/graphics/pro/js/wasm/src/serialize.h"
|
||
#include "FontsWasm.h"
|
||
#define FONTS_USE_ONLY_MEMORY_STREAMS
|
||
#endif
|
||
|
||
#if defined(_MSC_VER)
|
||
#define OO_INLINE __forceinline
|
||
#else
|
||
#define OO_INLINE inline
|
||
#endif
|
||
|
||
namespace PdfReader
|
||
{
|
||
bool CheckFontNameStyle(std::wstring& sName, const std::wstring& sStyle)
|
||
{
|
||
size_t nPos = 0;
|
||
size_t nLenReplace = sStyle.length();
|
||
bool bRet = false;
|
||
|
||
std::wstring sName2 = sName;
|
||
NSStringExt::ToLower(sName2);
|
||
|
||
while (std::wstring::npos != (nPos = sName2.find(sStyle, nPos)))
|
||
{
|
||
size_t nOffset = 0;
|
||
if ((nPos > 0) && (sName2.at(nPos - 1) == '-' || sName2.at(nPos - 1) == ','))
|
||
{
|
||
--nPos;
|
||
++nOffset;
|
||
}
|
||
|
||
bRet = true;
|
||
sName.erase(nPos, nLenReplace + nOffset);
|
||
sName2.erase(nPos, nLenReplace + nOffset);
|
||
}
|
||
return bRet;
|
||
}
|
||
|
||
void RendererOutputDev::CheckFontStylePDF(std::wstring& sName, bool& bBold, bool& bItalic)
|
||
{
|
||
if (sName.length() > 7 && sName.at(6) == '+')
|
||
{
|
||
bool bIsRemove = true;
|
||
for (int nIndex = 0; nIndex < 6; nIndex++)
|
||
{
|
||
wchar_t nChar = sName.at(nIndex);
|
||
if (nChar < 'A' || nChar > 'Z')
|
||
{
|
||
bIsRemove = false;
|
||
break;
|
||
}
|
||
}
|
||
if (bIsRemove)
|
||
{
|
||
sName.erase(0, 7);
|
||
}
|
||
}
|
||
|
||
CheckFontNameStyle(sName, L"condensedbold");
|
||
CheckFontNameStyle(sName, L"semibold");
|
||
CheckFontNameStyle(sName, L"regular");
|
||
|
||
CheckFontNameStyle(sName, L"ultraexpanded");
|
||
CheckFontNameStyle(sName, L"extraexpanded");
|
||
CheckFontNameStyle(sName, L"semiexpanded");
|
||
CheckFontNameStyle(sName, L"expanded");
|
||
|
||
CheckFontNameStyle(sName, L"ultracondensed");
|
||
CheckFontNameStyle(sName, L"extracondensed");
|
||
CheckFontNameStyle(sName, L"semicondensed");
|
||
CheckFontNameStyle(sName, L"condensedlight");
|
||
CheckFontNameStyle(sName, L"condensed");
|
||
//CheckFontNameStyle(sName, L"light");
|
||
|
||
if (CheckFontNameStyle(sName, L"bold_italic")) { bBold = true; bItalic = true; }
|
||
if (CheckFontNameStyle(sName, L"bold_oblique")) { bBold = true; bItalic = true; }
|
||
|
||
if (CheckFontNameStyle(sName, L"boldmt")) bBold = true;
|
||
if (CheckFontNameStyle(sName, L"bold")) bBold = true;
|
||
|
||
if (CheckFontNameStyle(sName, L"italicmt")) bItalic = true;
|
||
if (CheckFontNameStyle(sName, L"italic")) bItalic = true;
|
||
if (CheckFontNameStyle(sName, L"oblique")) bItalic = true;
|
||
|
||
//if (CheckFontNameStyle(sName, L"bolditalicmt")) { bBold = true; bItalic = true; }
|
||
//if (CheckFontNameStyle(sName, L"bolditalic")) { bBold = true; bItalic = true; }
|
||
//if (CheckFontNameStyle(sName, L"boldoblique")) { bBold = true; bItalic = true; }
|
||
}
|
||
|
||
void CheckFontNamePDF(std::wstring& sName, NSFonts::CFontSelectFormat* format)
|
||
{
|
||
bool bBold = false;
|
||
bool bItalic = false;
|
||
|
||
RendererOutputDev::CheckFontStylePDF(sName, bBold, bItalic);
|
||
|
||
if (format)
|
||
{
|
||
if (bBold)
|
||
format->bBold = new INT(1);
|
||
if (bItalic)
|
||
format->bItalic = new INT(1);
|
||
}
|
||
}
|
||
}
|
||
|
||
class CMemoryFontStream
|
||
{
|
||
public:
|
||
BYTE* m_pData;
|
||
int m_nSize;
|
||
int m_nPos;
|
||
bool m_bIsAttach;
|
||
|
||
CMemoryFontStream()
|
||
{
|
||
m_pData = NULL;
|
||
m_nSize = 0;
|
||
m_nPos = 0;
|
||
m_bIsAttach = false;
|
||
}
|
||
~CMemoryFontStream()
|
||
{
|
||
if (NULL != m_pData && !m_bIsAttach)
|
||
RELEASEARRAYOBJECTS(m_pData);
|
||
}
|
||
|
||
void fromStream(std::wstring& sStreamName)
|
||
{
|
||
NSFonts::IFontStream* pStream = NSFonts::NSApplicationFontStream::GetGlobalMemoryStorage()->Get(sStreamName);
|
||
if (pStream)
|
||
{
|
||
LONG lSize = 0;
|
||
pStream->GetMemory(m_pData, lSize);
|
||
m_nSize = (int)lSize;
|
||
m_nPos = 0;
|
||
m_bIsAttach = true;
|
||
}
|
||
}
|
||
|
||
void fromBuffer(BYTE* pData, int nSize)
|
||
{
|
||
if (pData)
|
||
{
|
||
m_pData = pData;
|
||
m_nSize = nSize;
|
||
m_nPos = 0;
|
||
m_bIsAttach = true;
|
||
}
|
||
}
|
||
|
||
void load(Object& oStreamObject)
|
||
{
|
||
int nCurrentSize = 0xFFFF;
|
||
int nCurrentPos = 0;
|
||
BYTE* pStream = new BYTE[nCurrentSize];
|
||
|
||
int nChar;
|
||
while ((nChar = oStreamObject.streamGetChar()) != EOF)
|
||
{
|
||
if (nCurrentPos >= nCurrentSize)
|
||
{
|
||
int nNewSize = 2 * nCurrentSize;
|
||
BYTE* pNewBuffer = new BYTE[nNewSize];
|
||
memcpy(pNewBuffer, pStream, nCurrentSize);
|
||
RELEASEARRAYOBJECTS(pStream);
|
||
pStream = pNewBuffer;
|
||
nCurrentSize = nNewSize;
|
||
}
|
||
pStream[nCurrentPos++] = nChar;
|
||
}
|
||
|
||
m_pData = pStream;
|
||
m_nSize = nCurrentPos;
|
||
m_nPos = 0;
|
||
}
|
||
|
||
int getChar()
|
||
{
|
||
if (m_nPos >= m_nSize)
|
||
return EOF;
|
||
return m_pData[m_nPos++];
|
||
}
|
||
|
||
void toStart()
|
||
{
|
||
m_nPos = 0;
|
||
}
|
||
};
|
||
|
||
static int readFromMemoryStream(void* data)
|
||
{
|
||
return ((CMemoryFontStream*)data)->getChar();
|
||
}
|
||
|
||
// TODO: 1. Реализовать по-нормальному градиентные заливки (Axial и Radial)
|
||
// 2. m_pRenderer->SetAdditionalParam(L"TilingHtmlPattern", oWriter.GetXmlString());
|
||
// 3. Подбор шрифтов необходимо перенести в GlobalParams->FindFontFile
|
||
// 4. В идентефикацию шрифта к путю добавить номер шрифта в файле
|
||
|
||
namespace PdfReader
|
||
{
|
||
//--------------------------------------------------------------------------------------
|
||
// CFontList
|
||
//--------------------------------------------------------------------------------------
|
||
CPdfFontList::CPdfFontList()
|
||
{
|
||
m_oCS.InitializeCriticalSection();
|
||
m_oFontMap.clear();
|
||
}
|
||
CPdfFontList::~CPdfFontList()
|
||
{
|
||
m_oCS.DeleteCriticalSection();
|
||
Clear();
|
||
}
|
||
void CPdfFontList::LoadFromFile(std::wstring wsDirPath)
|
||
{
|
||
return;
|
||
//Clear();
|
||
|
||
//CStringW wsFilePath = wsDirPath + CStringW( _T("/FontList.rsc") );
|
||
//XmlUtils::CXmlNode oMainNode;
|
||
|
||
//if ( !oMainNode.FromXmlFile( wsFilePath ) )
|
||
// return;
|
||
|
||
//if ( _T("PDFFontList") == oMainNode.getName() )
|
||
//{
|
||
// std::vector<XmlUtils::CXmlNode> oFonts;
|
||
// oMainNode.GetNodes( _T("Font"), oFonts );
|
||
// for ( int nIndex = 0; nIndex < oFonts.GetCount(); nIndex++ )
|
||
// {
|
||
// XmlUtils::CXmlNode oFont;
|
||
// Ref oRef;
|
||
// CStringW sFilePath;
|
||
// int nLength = 0;
|
||
// unsigned short *pCodeToGid = NULL, *pCodeToUnicode = NULL;
|
||
|
||
// if ( oFonts.GetAt( nIndex, oFont ) )
|
||
// {
|
||
// XmlUtils::CXmlNode oNode;
|
||
// CStringW sValue;
|
||
|
||
// if ( oFont.GetNode( _T("ID"), oNode ) )
|
||
// {
|
||
// sValue = oNode.GetAttribute( _T("num") );
|
||
// oRef.num = XmlUtils::GetInteger( sValue );
|
||
// sValue = oNode.GetAttribute( _T("gen") );
|
||
// oRef.gen = XmlUtils::GetInteger( sValue );
|
||
// }
|
||
|
||
// if ( oFont.GetNode( _T("FilePath"), oNode ) )
|
||
// {
|
||
// sFilePath = oNode.GetAttribute( _T("value") );
|
||
// }
|
||
// if ( oFont.GetNode( _T("CodeToGid"), oNode ) )
|
||
// {
|
||
// sValue = oNode.GetAttribute( _T("length") );
|
||
// nLength = XmlUtils::GetInteger( sValue );
|
||
// pCodeToGid = (unsigned short *)MemUtilsMalloc( sizeof(unsigned short) * nLength );
|
||
// if ( !pCodeToGid )
|
||
// return;
|
||
|
||
// std::vector<XmlUtils::CXmlNode> oArray;
|
||
// oNode.GetNodes( _T("Entry"), oArray );
|
||
// for ( int nCurIndex = 0; nCurIndex < oArray.GetCount() && nCurIndex < nLength; nCurIndex++ )
|
||
// {
|
||
// XmlUtils::CXmlNode oArrayItem;
|
||
// if ( oArray.GetAt( nCurIndex, oArrayItem ) )
|
||
// {
|
||
// sValue = oArrayItem.GetAttribute( _T("value") );
|
||
// pCodeToGid[nCurIndex] = XmlUtils::GetInteger( sValue );
|
||
// }
|
||
// else
|
||
// pCodeToGid[nCurIndex] = 0;
|
||
// }
|
||
// }
|
||
// if ( oFont.GetNode( _T("CodeToUnicode"), oNode ) )
|
||
// {
|
||
// sValue = oNode.GetAttribute( _T("length") );
|
||
// nLength = XmlUtils::GetInteger( sValue );
|
||
// pCodeToUnicode = (int *)MemUtilsMalloc( sizeof(int) * nLength );
|
||
// if ( !pCodeToUnicode )
|
||
// return;
|
||
|
||
// std::vector<XmlUtils::CXmlNode> oArray;
|
||
// oNode.GetNodes( _T("Entry"), oArray );
|
||
// for ( int nCurIndex = 0; nCurIndex < oArray.GetCount() && nCurIndex < nLength; nCurIndex++ )
|
||
// {
|
||
// XmlUtils::CXmlNode oArrayItem;
|
||
// if ( oArray.GetAt( nCurIndex, oArrayItem ) )
|
||
// {
|
||
// sValue = oArrayItem.GetAttribute( _T("value") );
|
||
// pCodeToUnicode[nCurIndex] = XmlUtils::GetInteger( sValue );
|
||
// }
|
||
// else
|
||
// pCodeToUnicode[nCurIndex] = 0;
|
||
// }
|
||
// }
|
||
|
||
// }
|
||
|
||
// Add( oRef, sFilePath, pCodeToGid, pCodeToUnicode, nLength );
|
||
// }
|
||
//}
|
||
}
|
||
void CPdfFontList::SaveToFile(std::wstring wsDirPath)
|
||
{
|
||
return;
|
||
//CStringW wsFilePath = wsDirPath + CStringW( _T("/FontList.rsc") );
|
||
//XmlUtils::CXmlWriter oWriter;
|
||
|
||
//oWriter.WriteNodeBegin( _T("PDFFontList") );
|
||
|
||
//for ( int nIndex = 0; nIndex < (int)m_arrList.GetCount(); nIndex++ )
|
||
//{
|
||
// TFontEntry oEntry = m_arrList.GetAt( nIndex );
|
||
// oWriter.WriteNodeBegin( _T("Font") );
|
||
|
||
|
||
// oWriter.WriteNodeBegin( _T("ID"), true );
|
||
// oWriter.WriteAttribute( _T("num"), oEntry.oRef.num );
|
||
// oWriter.WriteAttribute( _T("gen"), oEntry.oRef.gen );
|
||
// oWriter.WriteNodeEnd( _T("ID"), true, true );
|
||
|
||
// oWriter.WriteNodeBegin( _T("FilePath"), true );
|
||
// oWriter.WriteAttribute( _T("value"), oEntry.wsFilePath );
|
||
// oWriter.WriteNodeEnd( _T("FilePath"), true, true );
|
||
|
||
// if ( NULL != oEntry.pCodeToGID )
|
||
// {
|
||
// oWriter.WriteNodeBegin( _T("CodeToGid"), true );
|
||
// oWriter.WriteAttribute( _T("length"), oEntry.nLen );
|
||
// oWriter.WriteNodeEnd( _T("CodeToGid"), true, false );
|
||
// for ( int nCurIndex = 0; nCurIndex < oEntry.nLen; nCurIndex++ )
|
||
// {
|
||
// oWriter.WriteNodeBegin( _T("Entry"), true );
|
||
// oWriter.WriteAttribute( _T("value"), oEntry.pCodeToGID[nCurIndex] );
|
||
// oWriter.WriteNodeEnd( _T("Entry"), true, true );
|
||
// }
|
||
// oWriter.WriteNodeEnd( _T("CodeToGid") );
|
||
// }
|
||
|
||
// if ( NULL != oEntry.pCodeToUnicode )
|
||
// {
|
||
// oWriter.WriteNodeBegin( _T("CodeToUnicode"), true );
|
||
// oWriter.WriteAttribute( _T("length"), oEntry.nLen );
|
||
// oWriter.WriteNodeEnd( _T("CodeToUnicode"), true, false );
|
||
// for ( int nCurIndex = 0; nCurIndex < oEntry.nLen; nCurIndex++ )
|
||
// {
|
||
// oWriter.WriteNodeBegin( _T("Entry"), true );
|
||
// oWriter.WriteAttribute( _T("value"), oEntry.pCodeToUnicode[nCurIndex] );
|
||
// oWriter.WriteNodeEnd( _T("Entry"), true, true );
|
||
// }
|
||
// oWriter.WriteNodeEnd( _T("CodeToUnicode") );
|
||
// }
|
||
|
||
// oWriter.WriteNodeEnd( _T("Font") );
|
||
//}
|
||
//oWriter.WriteNodeEnd( _T("PDFFontList") );
|
||
|
||
//oWriter.SaveToFile( wsFilePath );
|
||
}
|
||
bool CPdfFontList::Find(Ref oRef, TFontEntry *pEntry)
|
||
{
|
||
CTemporaryCS* pCS = new CTemporaryCS(&m_oCS);
|
||
|
||
bool bResult = (NULL != (pEntry = Lookup(oRef)));
|
||
|
||
if (bResult)
|
||
{
|
||
// Шрифт нашелся, но пока им пользоваться нельзя, потому что он загружается в параллельном потоке
|
||
while (!pEntry->bAvailable)
|
||
NSThreads::Sleep(10);
|
||
}
|
||
|
||
RELEASEOBJECT(pCS);
|
||
|
||
return bResult;
|
||
}
|
||
bool CPdfFontList::Find2(Ref oRef, TFontEntry **ppEntry)
|
||
{
|
||
CTemporaryCS* pCS = new CTemporaryCS(&m_oCS);
|
||
|
||
bool bResult = (NULL != ((*ppEntry) = Lookup(oRef)));
|
||
|
||
if (bResult)
|
||
{
|
||
// Шрифт нашелся, но пока им пользоваться нельзя, потому что он загружается в параллельном потоке
|
||
while (!(*ppEntry)->bAvailable)
|
||
NSThreads::Sleep(10);
|
||
}
|
||
|
||
if (!bResult)
|
||
{
|
||
(*ppEntry) = Add(oRef, L"", NULL, NULL, 0, 0);
|
||
(*ppEntry)->bAvailable = false;
|
||
}
|
||
|
||
RELEASEOBJECT(pCS);
|
||
|
||
return bResult;
|
||
}
|
||
TFontEntry* CPdfFontList::Add(Ref oRef, std::wstring wsFileName, int *pCodeToGID, int *pCodeToUnicode, unsigned int unLenGID, unsigned int unLenUnicode)
|
||
{
|
||
// Данная функция приходит только из Find2, поэтому проверять есть ли данный шрифт уже не надо
|
||
CTemporaryCS* pCS = new CTemporaryCS(&m_oCS);
|
||
|
||
TFontEntry *pNewEntry = new TFontEntry;
|
||
pNewEntry->oRef.gen = oRef.gen;
|
||
pNewEntry->oRef.num = oRef.num;
|
||
pNewEntry->wsFilePath = wsFileName;
|
||
pNewEntry->pCodeToGID = pCodeToGID;
|
||
pNewEntry->pCodeToUnicode = pCodeToUnicode;
|
||
pNewEntry->unLenGID = unLenGID;
|
||
pNewEntry->unLenUnicode = unLenUnicode;
|
||
|
||
Add(oRef, pNewEntry);
|
||
|
||
RELEASEOBJECT(pCS);
|
||
|
||
return pNewEntry;
|
||
}
|
||
void CPdfFontList::Remove(Ref oRef)
|
||
{
|
||
CRefFontMap::iterator oPos = m_oFontMap.find(oRef);
|
||
if (m_oFontMap.end() != oPos)
|
||
{
|
||
TFontEntry *pEntry = oPos->second;
|
||
if (NULL != pEntry)
|
||
{
|
||
MemUtilsFree(pEntry->pCodeToGID);
|
||
MemUtilsFree(pEntry->pCodeToUnicode);
|
||
}
|
||
delete pEntry;
|
||
m_oFontMap.erase(oPos);
|
||
}
|
||
}
|
||
void CPdfFontList::Clear()
|
||
{
|
||
for (auto const &oIt : m_oFontMap)
|
||
{
|
||
TFontEntry *pEntry = oIt.second;
|
||
if (NULL != pEntry)
|
||
{
|
||
MemUtilsFree(pEntry->pCodeToGID);
|
||
MemUtilsFree(pEntry->pCodeToUnicode);
|
||
}
|
||
delete pEntry;
|
||
}
|
||
m_oFontMap.clear();
|
||
}
|
||
bool CPdfFontList::GetFont(Ref *pRef, TFontEntry *pEntry)
|
||
{
|
||
TFontEntry* pFindEntry = Lookup(*pRef);
|
||
if (NULL == pFindEntry)
|
||
return false;
|
||
|
||
*pEntry = *pFindEntry;
|
||
return true;
|
||
}
|
||
//--------------------------------------------------------------------------------------
|
||
// RendererOutputDev
|
||
//--------------------------------------------------------------------------------------
|
||
RendererOutputDev::RendererOutputDev(IRenderer *pRenderer, NSFonts::IFontManager* pFontManager, CPdfFontList *pFontList)
|
||
{
|
||
m_pFontManager = pFontManager;
|
||
m_pFontManager = pFontManager;
|
||
m_pFontList = pFontList;
|
||
|
||
m_bTiling = false;
|
||
|
||
m_lRendererType = c_nUnknownRenderer;
|
||
m_pRenderer = pRenderer;
|
||
|
||
if (NULL != m_pRenderer)
|
||
{
|
||
m_pRenderer->put_PenColor(0);
|
||
m_pRenderer->put_PenAlpha(255);
|
||
m_pRenderer->put_PenSize(1);
|
||
|
||
m_pRenderer->put_FontName(L"Arial");
|
||
m_pRenderer->put_FontStyle(0);
|
||
m_pRenderer->put_FontSize(10.0);
|
||
|
||
m_pRenderer->get_Type(&m_lRendererType);
|
||
}
|
||
|
||
m_pbBreak = NULL;
|
||
|
||
m_bDrawOnlyText = false;
|
||
m_bClipChanged = true;
|
||
}
|
||
RendererOutputDev::~RendererOutputDev()
|
||
{
|
||
m_pRenderer = NULL;
|
||
|
||
// if (m_sClip) tmpchange
|
||
// delete m_sClip;
|
||
|
||
// if (m_pBufferTextClip) tmpchange
|
||
// delete m_pBufferTextClip;
|
||
|
||
}
|
||
void RendererOutputDev::startPage(int nPageIndex, GfxState *pGState)
|
||
{
|
||
if (nPageIndex < 0)
|
||
return;
|
||
|
||
m_pRenderer->BeginCommand(c_nPageType);
|
||
|
||
// Переводим пункты в миллиметры
|
||
m_arrMatrix[0] = 1; m_arrMatrix[1] = 0;
|
||
m_arrMatrix[2] = 0; m_arrMatrix[3] = 1;
|
||
m_arrMatrix[4] = 0; m_arrMatrix[5] = 0;
|
||
|
||
if (c_nHtmlRendrerer2 == m_lRendererType)
|
||
m_bDrawOnlyText = S_OK == m_pRenderer->CommandLong(c_nCommandLongTypeOnlyText, 0);
|
||
else if (c_nHtmlRendrererText == m_lRendererType)
|
||
m_bDrawOnlyText = true;
|
||
else
|
||
m_bDrawOnlyText = false;
|
||
}
|
||
void RendererOutputDev::endPage()
|
||
{
|
||
m_pRenderer->EndCommand(c_nResetMaskType);
|
||
m_pRenderer->EndCommand(c_nPageType);
|
||
}
|
||
void RendererOutputDev::saveState(GfxState *pGState)
|
||
{
|
||
m_sClip.push_back(GfxClip());
|
||
m_bClipChanged = true;
|
||
updateAll(pGState);
|
||
|
||
Aggplus::CAlphaMask* pAlphaMask = NULL;
|
||
GfxState* pGStateSoftMask = NULL;
|
||
if (!m_sStates.empty() && m_sStates.back().pAlphaMask)
|
||
{
|
||
pAlphaMask = m_sStates.back().pAlphaMask;
|
||
pGStateSoftMask = m_sStates.back().pGStateSoftMask;
|
||
}
|
||
m_sStates.push_back(GfxOutputState());
|
||
m_sStates.back().pGState = pGState;
|
||
m_sStates.back().pAlphaMask = pAlphaMask;
|
||
m_sStates.back().pGStateSoftMask = pGStateSoftMask;
|
||
}
|
||
void RendererOutputDev::restoreState(GfxState *pGState)
|
||
{
|
||
NSGraphics::IGraphicsRenderer* GRenderer = dynamic_cast<NSGraphics::IGraphicsRenderer*>(m_pRenderer);
|
||
if (GRenderer)
|
||
{
|
||
if (m_sStates.back().pAlphaMask && !GRenderer->GetAlphaMask())
|
||
GRenderer->SetAlphaMask(m_sStates.back().pAlphaMask);
|
||
if (m_sStates.back().pGStateSoftMask == pGState)
|
||
{
|
||
m_pRenderer->EndCommand(c_nResetMaskType);
|
||
RELEASEINTERFACE(m_sStates.back().pAlphaMask);
|
||
}
|
||
}
|
||
if (!m_sClip.empty())
|
||
m_sClip.pop_back();
|
||
m_bClipChanged = true;
|
||
updateAll(pGState);
|
||
|
||
m_sStates.pop_back();
|
||
}
|
||
void RendererOutputDev::updateCTM(GfxState *pGState, double dMatrix11, double dMatrix12, double dMatrix21, double dMatrix22, double dMatrix31, double dMatrix32)
|
||
{
|
||
}
|
||
void RendererOutputDev::updateLineDash(GfxState *pGState)
|
||
{
|
||
double *pDash = NULL;
|
||
int nSize = 0;
|
||
double dStart = 0;
|
||
pGState->getLineDash(&pDash, &nSize, &dStart);
|
||
bool bOffCopy = nSize == 1;
|
||
if (bOffCopy)
|
||
{
|
||
double* pDashTemp = new double[2];
|
||
pDashTemp[0] = pDash[0];
|
||
pDashTemp[1] = pDash[0];
|
||
pDash = pDashTemp;
|
||
nSize = 2;
|
||
}
|
||
|
||
if (0 == nSize) // Solid
|
||
{
|
||
m_pRenderer->put_PenDashStyle(Aggplus::DashStyleSolid);
|
||
m_pRenderer->put_PenDashOffset(0);
|
||
}
|
||
else
|
||
{
|
||
for (int nIndex = 0; nIndex < nSize; ++nIndex)
|
||
{
|
||
pDash[nIndex] = PDFCoordsToMM(pDash[nIndex]);
|
||
}
|
||
|
||
m_pRenderer->PenDashPattern(pDash, (long)nSize);
|
||
m_pRenderer->put_PenDashStyle(Aggplus::DashStyleCustom);
|
||
m_pRenderer->put_PenDashOffset(PDFCoordsToMM(dStart));
|
||
}
|
||
if (bOffCopy)
|
||
delete[] pDash;
|
||
}
|
||
void RendererOutputDev::updateFlatness(GfxState *pGState)
|
||
{
|
||
}
|
||
void RendererOutputDev::updateLineJoin(GfxState *pGState)
|
||
{
|
||
int nJoinStyle = pGState->getLineJoin();
|
||
if (1 == nJoinStyle)
|
||
nJoinStyle = 2;
|
||
else if (2 == nJoinStyle)
|
||
nJoinStyle = 1;
|
||
|
||
m_pRenderer->put_PenLineJoin(nJoinStyle);
|
||
}
|
||
void RendererOutputDev::updateLineCap(GfxState *pGState)
|
||
{
|
||
int nCapStyle = pGState->getLineCap();
|
||
if (1 == nCapStyle)
|
||
nCapStyle = 2;
|
||
else if (2 == nCapStyle)
|
||
nCapStyle = 1;
|
||
|
||
m_pRenderer->put_PenLineStartCap(nCapStyle);
|
||
m_pRenderer->put_PenLineEndCap(nCapStyle);
|
||
}
|
||
void RendererOutputDev::updateMiterLimit(GfxState *pGState)
|
||
{
|
||
m_pRenderer->put_PenMiterLimit(PDFCoordsToMM(pGState->getMiterLimit()));
|
||
}
|
||
void RendererOutputDev::updateLineWidth(GfxState *pGState)
|
||
{
|
||
m_pRenderer->put_PenSize(PDFCoordsToMM(pGState->getLineWidth()));
|
||
}
|
||
void RendererOutputDev::updateStrokeAdjust(GfxState *pGState)
|
||
{
|
||
}
|
||
void RendererOutputDev::updateFillColor(GfxState *pGState)
|
||
{
|
||
GfxColor *pColor = pGState->getFillColor();
|
||
GfxColorSpace *pColorSpace = pGState->getFillColorSpace();
|
||
|
||
GfxRGB c;
|
||
|
||
pColorSpace->getRGB(pColor, &c, GfxRenderingIntent::gfxRenderingIntentAbsoluteColorimetric);
|
||
DWORD dwColor = colToByte(c.r) + colToByte(c.g) * 0x100 + colToByte(c.b) * 0x100 * 0x100;
|
||
m_pRenderer->put_BrushColor1(dwColor);
|
||
m_pRenderer->put_BrushColor2(dwColor);
|
||
}
|
||
void RendererOutputDev::updateStrokeColor(GfxState *pGState)
|
||
{
|
||
GfxColor *pColor = pGState->getStrokeColor();
|
||
GfxColorSpace *pColorSpace = pGState->getStrokeColorSpace();
|
||
|
||
GfxRGB c;
|
||
|
||
pColorSpace->getRGB(pColor, &c, GfxRenderingIntent::gfxRenderingIntentAbsoluteColorimetric);
|
||
DWORD dwColor = colToByte(c.r) + colToByte(c.g) * 0x100 + colToByte(c.b) * 0x100 * 0x100;
|
||
|
||
m_pRenderer->put_PenColor(dwColor);
|
||
}
|
||
void RendererOutputDev::updateBlendMode(GfxState *pGState)
|
||
{
|
||
NSGraphics::IGraphicsRenderer* GRenderer = dynamic_cast<NSGraphics::IGraphicsRenderer*>(m_pRenderer);
|
||
if (((GlobalParamsAdaptor*)globalParams)->getDrawFormField() || !GRenderer)
|
||
return;
|
||
|
||
switch (pGState->getBlendMode())
|
||
{
|
||
case gfxBlendNormal:
|
||
GRenderer->put_BlendMode(3);
|
||
// agg::comp_op_src_over
|
||
break;
|
||
case gfxBlendMultiply:
|
||
GRenderer->put_BlendMode(14);
|
||
// agg::comp_op_multiply
|
||
break;
|
||
case gfxBlendScreen:
|
||
GRenderer->put_BlendMode(15);
|
||
// agg::comp_op_screen
|
||
break;
|
||
case gfxBlendOverlay:
|
||
GRenderer->put_BlendMode(16);
|
||
// agg::comp_op_overlay
|
||
break;
|
||
case gfxBlendDarken:
|
||
GRenderer->put_BlendMode(17);
|
||
// agg::comp_op_darken
|
||
break;
|
||
case gfxBlendLighten:
|
||
GRenderer->put_BlendMode(18);
|
||
// agg::comp_op_lighten
|
||
break;
|
||
case gfxBlendColorDodge:
|
||
GRenderer->put_BlendMode(19);
|
||
// agg::comp_op_color_dodge
|
||
break;
|
||
case gfxBlendColorBurn:
|
||
GRenderer->put_BlendMode(20);
|
||
// agg::comp_op_color_burn
|
||
break;
|
||
case gfxBlendHardLight:
|
||
GRenderer->put_BlendMode(21);
|
||
// agg::comp_op_hard_light
|
||
break;
|
||
case gfxBlendSoftLight:
|
||
GRenderer->put_BlendMode(22);
|
||
// agg::comp_op_soft_light
|
||
break;
|
||
case gfxBlendDifference:
|
||
GRenderer->put_BlendMode(23);
|
||
// agg::comp_op_difference
|
||
break;
|
||
case gfxBlendExclusion:
|
||
GRenderer->put_BlendMode(24);
|
||
// agg::comp_op_exclusion
|
||
break;
|
||
case gfxBlendHue:
|
||
case gfxBlendSaturation:
|
||
case gfxBlendColor:
|
||
case gfxBlendLuminosity:
|
||
default:
|
||
GRenderer->put_BlendMode(3);
|
||
// agg::comp_op_src_over
|
||
break;
|
||
}
|
||
}
|
||
void RendererOutputDev::updateFillOpacity(GfxState *pGState)
|
||
{
|
||
m_pRenderer->put_BrushAlpha1(std::min(255, std::max(0, int(pGState->getFillOpacity() * 255))));
|
||
m_pRenderer->put_BrushAlpha2(std::min(255, std::max(0, int(pGState->getFillOpacity() * 255))));
|
||
}
|
||
void RendererOutputDev::updateStrokeOpacity(GfxState *pGState)
|
||
{
|
||
m_pRenderer->put_PenAlpha(std::min(255, std::max(0, int(pGState->getStrokeOpacity() * 255))));
|
||
}
|
||
void RendererOutputDev::updateAll(GfxState *pGState)
|
||
{
|
||
updateCTM(pGState, pGState->getCTM()[0], pGState->getCTM()[1], pGState->getCTM()[2], pGState->getCTM()[3], pGState->getCTM()[4], pGState->getCTM()[5]);
|
||
updateLineDash(pGState);
|
||
updateFlatness(pGState);
|
||
updateLineJoin(pGState);
|
||
updateLineCap(pGState);
|
||
updateMiterLimit(pGState);
|
||
updateLineWidth(pGState);
|
||
updateStrokeAdjust(pGState);
|
||
updateFillColorSpace(pGState);
|
||
updateFillColor(pGState);
|
||
updateStrokeColorSpace(pGState);
|
||
updateStrokeColor(pGState);
|
||
updateBlendMode(pGState);
|
||
updateFillOpacity(pGState);
|
||
updateStrokeOpacity(pGState);
|
||
updateFont(pGState);
|
||
updateClip(pGState);
|
||
}
|
||
void RendererOutputDev::updateRender(GfxState *pGState)
|
||
{
|
||
|
||
}
|
||
NSFonts::CFontInfo* RendererOutputDev::GetFontByParams(XRef* pXref, NSFonts::IFontManager* pFontManager, GfxFont* pFont, std::wstring& wsFontBaseName)
|
||
{
|
||
NSFonts::CFontInfo* pFontInfo = NULL;
|
||
if (!pFontManager)
|
||
return pFontInfo;
|
||
|
||
Ref *pRef = pFont->getID();
|
||
Object oRefObject, oFontObject;
|
||
oRefObject.initRef(pRef->num, pRef->gen);
|
||
oRefObject.fetch(pXref, &oFontObject);
|
||
oRefObject.free();
|
||
|
||
NSFonts::CFontSelectFormat oFontSelect;
|
||
CheckFontNamePDF(wsFontBaseName, &oFontSelect);
|
||
if (oFontObject.isDict())
|
||
{
|
||
Dict *pFontDict = oFontObject.getDict();
|
||
Object oFontDescriptor;
|
||
if (pFontDict->lookup("FontDescriptor", &oFontDescriptor)->isDict())
|
||
{
|
||
Object oDictItem;
|
||
// FontName
|
||
oFontDescriptor.dictLookup("FontName", &oDictItem);
|
||
if (oDictItem.isName())
|
||
oFontSelect.wsName = AStringToPWString(oDictItem.getName());
|
||
else
|
||
oFontSelect.wsName = new std::wstring(wsFontBaseName);
|
||
oDictItem.free();
|
||
|
||
// FontFamily
|
||
oFontDescriptor.dictLookup("FontFamily", &oDictItem);
|
||
oDictItem.free();
|
||
|
||
// FontStretch
|
||
oFontDescriptor.dictLookup("FontStretch", &oDictItem);
|
||
oDictItem.free();
|
||
|
||
// FontWeight
|
||
oFontDescriptor.dictLookup("FontWeight", &oDictItem);
|
||
oDictItem.free();
|
||
|
||
// FontBBox
|
||
oFontDescriptor.dictLookup("FontBBox", &oDictItem);
|
||
oDictItem.free();
|
||
|
||
// ItalicAngle
|
||
oFontDescriptor.dictLookup("ItalicAngle", &oDictItem);
|
||
if (oDictItem.isInt() && 0 != oDictItem.getInt())
|
||
{
|
||
if (oFontSelect.bItalic) RELEASEOBJECT(oFontSelect.bItalic);
|
||
oFontSelect.bItalic = new INT(1);
|
||
}
|
||
oDictItem.free();
|
||
|
||
// Ascent
|
||
oFontDescriptor.dictLookup("Ascent", &oDictItem);
|
||
if (oDictItem.isInt()) oFontSelect.shAscent = new SHORT(oDictItem.getInt());
|
||
oDictItem.free();
|
||
|
||
// Leading
|
||
oFontDescriptor.dictLookup("Leading", &oDictItem);
|
||
if (oDictItem.isInt()) oFontSelect.shLineGap = new SHORT(oDictItem.getInt());
|
||
oDictItem.free();
|
||
|
||
// CapHeight
|
||
oFontDescriptor.dictLookup("CapHeight", &oDictItem);
|
||
if (oDictItem.isInt()) oFontSelect.shCapHeight = new SHORT(oDictItem.getInt());
|
||
oDictItem.free();
|
||
|
||
// XHeight
|
||
oFontDescriptor.dictLookup("XHeight", &oDictItem);
|
||
if (oDictItem.isInt()) oFontSelect.shXHeight = new SHORT(oDictItem.getInt());
|
||
oDictItem.free();
|
||
|
||
// StemV
|
||
oFontDescriptor.dictLookup("StemV", &oDictItem);
|
||
if (oDictItem.isNum())
|
||
{
|
||
double dStemV = oDictItem.getNum();
|
||
if (dStemV > 50.5)
|
||
oFontSelect.usWeight = new USHORT(sqrt(oDictItem.getNum() - 50.5) * 65);
|
||
}
|
||
oDictItem.free();
|
||
|
||
// StemH
|
||
oFontDescriptor.dictLookup("StemH", &oDictItem);
|
||
oDictItem.free();
|
||
|
||
// Descent
|
||
oFontDescriptor.dictLookup("Descent", &oDictItem);
|
||
if (oDictItem.isInt()) oFontSelect.shDescent = new SHORT(oDictItem.getInt());
|
||
oDictItem.free();
|
||
|
||
// AvgWidth
|
||
oFontDescriptor.dictLookup("AvgWidth", &oDictItem);
|
||
if (oDictItem.isInt()) oFontSelect.shAvgCharWidth = new SHORT(oDictItem.getInt());
|
||
oDictItem.free();
|
||
|
||
// MaxWidth
|
||
oFontDescriptor.dictLookup("MaxWidth", &oDictItem);
|
||
oDictItem.free();
|
||
|
||
// MissingWidth
|
||
oFontDescriptor.dictLookup("MissingWidth", &oDictItem);
|
||
oDictItem.free();
|
||
|
||
}
|
||
else
|
||
oFontSelect.wsName = new std::wstring(wsFontBaseName);
|
||
oFontDescriptor.free();
|
||
}
|
||
else
|
||
oFontSelect.wsName = new std::wstring(wsFontBaseName);
|
||
|
||
pFontInfo = pFontManager->GetFontInfoByParams(oFontSelect);
|
||
return pFontInfo;
|
||
}
|
||
void RendererOutputDev::GetFont(XRef* pXref, NSFonts::IFontManager* pFontManager, CPdfFontList *pFontList, GfxFont* pFont, std::wstring& wsFileName, std::wstring& wsFontName)
|
||
{
|
||
wsFileName = L"";
|
||
wsFontName = L"";
|
||
TFontEntry *pEntry = NULL;
|
||
// MEMERR string dealocation pEntry
|
||
if (!pFontList->Find2((*pFont->getID()), &pEntry))
|
||
{
|
||
GfxFontType eFontType = pFont->getType();
|
||
if (fontType3 == eFontType) // FontType3 обрабатывается отдельной командой
|
||
{
|
||
pEntry->bAvailable = true;
|
||
return;
|
||
}
|
||
|
||
std::wstring wsTempFileName = L"";
|
||
Ref oEmbRef;
|
||
bool bFontSubstitution = false;
|
||
std::wstring wsFontBaseName = NSStrings::GetStringFromUTF32(pFont->getName());
|
||
if (wsFontBaseName.empty())
|
||
wsFontBaseName = L"Helvetica";
|
||
const unsigned char* pData14 = NULL;
|
||
unsigned int nSize14 = 0;
|
||
#ifdef FONTS_USE_ONLY_MEMORY_STREAMS
|
||
CMemoryFontStream oMemoryFontStream;
|
||
#endif
|
||
// 1. Если шрифт внедренный, тогда скидываем его в темповый файл.
|
||
// 2. Если шрифт лежит вне пдф, а в самом пдф есть ссылка на него, тогда используем эту ссылку.
|
||
// 3. В противном случае подбираем шрифт.
|
||
|
||
if (pFont->getEmbeddedFontID(&oEmbRef))
|
||
{
|
||
std::wstring wsExt;
|
||
switch (pFont->getType())
|
||
{
|
||
case fontType1: wsExt = L".pfb_t1"; break;
|
||
case fontType1C: wsExt = L".pfb_t1c"; break;
|
||
case fontType1COT: wsExt = L".pfb_t1cot"; break;
|
||
case fontTrueType: wsExt = L".ttf"; break;
|
||
case fontTrueTypeOT: wsExt = L".otf"; break;
|
||
case fontCIDType0: wsExt = L".cid_0"; break;
|
||
case fontCIDType0C: wsExt = L".cid_0c"; break;
|
||
case fontCIDType0COT: wsExt = L".cid_0cot"; break;
|
||
case fontCIDType2: wsExt = L".cid_2"; break;
|
||
case fontCIDType2OT: wsExt = L".cid_2ot"; break;
|
||
}
|
||
|
||
#ifdef FONTS_USE_ONLY_MEMORY_STREAMS
|
||
if (NSFonts::NSApplicationFontStream::GetGlobalMemoryStorage())
|
||
{
|
||
wsTempFileName = NSFonts::NSApplicationFontStream::GetGlobalMemoryStorage()->GenerateId();
|
||
}
|
||
#else
|
||
FILE* pTempFile = NULL;
|
||
if (!NSFile::CFileBinary::OpenTempFile(&wsTempFileName, &pTempFile, L"wb", (wchar_t*)wsExt.c_str(),
|
||
(wchar_t*)((GlobalParamsAdaptor *)globalParams)->GetTempFolder().c_str(), NULL))
|
||
{
|
||
if (L"" != wsTempFileName)
|
||
NSFile::CFileBinary::Remove(wsTempFileName);
|
||
|
||
pEntry->bAvailable = true;
|
||
return;
|
||
}
|
||
wsTempFileName = UTF8_TO_U(NSSystemPath::NormalizePath(U_TO_UTF8(wsTempFileName)));
|
||
#endif
|
||
|
||
Object oReferenceObject, oStreamObject;
|
||
oReferenceObject.initRef(oEmbRef.num, oEmbRef.gen);
|
||
oReferenceObject.fetch(pXref, &oStreamObject);
|
||
oReferenceObject.free();
|
||
if (!oStreamObject.isStream())
|
||
{
|
||
// Внедренный шрифт неправильно записан
|
||
oStreamObject.free();
|
||
|
||
#ifndef FONTS_USE_ONLY_MEMORY_STREAMS
|
||
fclose(pTempFile);
|
||
|
||
if (L"" != wsTempFileName)
|
||
NSFile::CFileBinary::Remove(wsTempFileName);
|
||
#endif
|
||
|
||
pEntry->bAvailable = true;
|
||
return;
|
||
}
|
||
oStreamObject.streamReset();
|
||
|
||
#ifdef FONTS_USE_ONLY_MEMORY_STREAMS
|
||
oMemoryFontStream.load(oStreamObject);
|
||
NSFonts::NSApplicationFontStream::GetGlobalMemoryStorage()->Add(wsTempFileName, oMemoryFontStream.m_pData, (LONG)oMemoryFontStream.m_nSize, true);
|
||
#else
|
||
int nChar;
|
||
while ((nChar = oStreamObject.streamGetChar()) != EOF)
|
||
{
|
||
fputc(nChar, pTempFile);
|
||
}
|
||
fclose(pTempFile);
|
||
#endif
|
||
|
||
oStreamObject.streamClose();
|
||
oStreamObject.free();
|
||
wsFileName = wsTempFileName;
|
||
|
||
#ifdef FONTS_USE_AFM_SETTINGS
|
||
// Для шрифтов типа Type1 нужно дописать Afm файл с метриками
|
||
if (fontType1 == pFont->getType() || fontType1C == pFont->getType() || fontType1COT == pFont->getType())
|
||
{
|
||
std::wstring wsSplitFileName, wsSplitFileExt;
|
||
SpitPathExt(wsFileName, &wsSplitFileName, &wsSplitFileExt);
|
||
std::wstring wsAfmPath = wsSplitFileName + L".afm";
|
||
|
||
FILE* pFile = NSFile::CFileBinary::OpenFileNative(wsAfmPath, L"wb");
|
||
if (pFile)
|
||
{
|
||
Ref *pRef = pFont->getID();
|
||
Object oRefObject, oFontObject;
|
||
oRefObject.initRef(pRef->num, pRef->gen);
|
||
oRefObject.fetch(pXref, &oFontObject);
|
||
oRefObject.free();
|
||
|
||
if (oFontObject.isDict())
|
||
{
|
||
std::string sFontName, sFontFamily;
|
||
int nFontWeight = 0, nItalicAngle = 0, nAscent = 0, nDescent = 0;
|
||
int nCapHeight = 0, nXHeight = 0, nStemV = 0, nStemH = 0, nMissingWidth = 0;
|
||
int arrBBox[4] = { 0, 0, 0, 0 };
|
||
|
||
Object oFontDescriptor;
|
||
if (oFontObject.dictLookup("FontDescriptor", &oFontDescriptor)->isDict())
|
||
{
|
||
Object oDictItem;
|
||
// FontName
|
||
oFontDescriptor.dictLookup("FontName", &oDictItem);
|
||
if (oDictItem.isName()) sFontName = oDictItem.getName();
|
||
oDictItem.free();
|
||
|
||
// FontFamily
|
||
oFontDescriptor.dictLookup("FontFamily", &oDictItem);
|
||
if (oDictItem.isName()) sFontFamily = oDictItem.getName();
|
||
oDictItem.free();
|
||
|
||
// FontWeight
|
||
oFontDescriptor.dictLookup("FontWeight", &oDictItem);
|
||
if (oDictItem.isInt()) nFontWeight = oDictItem.getInt();
|
||
oDictItem.free();
|
||
|
||
// FontBBox
|
||
if (oFontDescriptor.dictLookup("FontBBox", &oDictItem)->isArray() && oDictItem.arrayGetLength() == 4)
|
||
{
|
||
for (int nIndex = 0; nIndex < 4; nIndex++)
|
||
{
|
||
Object oArrayItem;
|
||
if (oDictItem.arrayGet(nIndex, &oArrayItem)->isInt())
|
||
arrBBox[nIndex] = oArrayItem.getInt();
|
||
oArrayItem.free();
|
||
}
|
||
}
|
||
oDictItem.free();
|
||
|
||
// ItalicAngle
|
||
oFontDescriptor.dictLookup("ItalicAngle", &oDictItem);
|
||
if (oDictItem.isInt()) nItalicAngle = oDictItem.getInt();
|
||
oDictItem.free();
|
||
|
||
// Ascent
|
||
oFontDescriptor.dictLookup("Ascent", &oDictItem);
|
||
if (oDictItem.isInt()) nAscent = oDictItem.getInt();
|
||
oDictItem.free();
|
||
|
||
// CapHeight
|
||
oFontDescriptor.dictLookup("CapHeight", &oDictItem);
|
||
if (oDictItem.isInt()) nCapHeight = oDictItem.getInt();
|
||
oDictItem.free();
|
||
|
||
// XHeight
|
||
oFontDescriptor.dictLookup("XHeight", &oDictItem);
|
||
if (oDictItem.isInt()) nXHeight = oDictItem.getInt();
|
||
oDictItem.free();
|
||
|
||
// StemV
|
||
oFontDescriptor.dictLookup("StemV", &oDictItem);
|
||
if (oDictItem.isInt()) nStemV = oDictItem.getInt();
|
||
oDictItem.free();
|
||
|
||
// StemH
|
||
oFontDescriptor.dictLookup("StemH", &oDictItem);
|
||
if (oDictItem.isInt()) nStemH = oDictItem.getInt();
|
||
oDictItem.free();
|
||
|
||
// Descent
|
||
oFontDescriptor.dictLookup("Descent", &oDictItem);
|
||
if (oDictItem.isInt()) nDescent = oDictItem.getInt();
|
||
oDictItem.free();
|
||
|
||
// MissingWidth
|
||
oFontDescriptor.dictLookup("MissingWidth", &oDictItem);
|
||
if (oDictItem.isInt()) nMissingWidth = oDictItem.getInt();
|
||
oDictItem.free();
|
||
|
||
}
|
||
oFontDescriptor.free();
|
||
|
||
fprintf(pFile, "StartFontMetrics 3.0\n");
|
||
if (!sFontName.empty()) fprintf(pFile, "FontName %s\n", sFontName.c_str());
|
||
if (!sFontFamily.empty()) fprintf(pFile, "FamilyName %s\n", sFontFamily.c_str());
|
||
if (nFontWeight >= 550) fprintf(pFile, "Weight Bold\n");
|
||
|
||
fprintf(pFile, "ItalicAngle %d\n", nItalicAngle);
|
||
|
||
fprintf(pFile, "FontBBox %d %d %d %d\n", arrBBox[0], arrBBox[1], arrBBox[2], arrBBox[3]);
|
||
|
||
fprintf(pFile, "CapHeight %d\n", nCapHeight);
|
||
fprintf(pFile, "XHeight %d\n", nXHeight);
|
||
fprintf(pFile, "Ascender %d\n", nAscent);
|
||
fprintf(pFile, "Descender %d\n", nDescent);
|
||
fprintf(pFile, "StdHW %d\n", nStemH);
|
||
fprintf(pFile, "StdHV %d\n", nStemV);
|
||
|
||
int nFirstChar = 0;
|
||
Object oDictItem;
|
||
if (oFontObject.dictLookup("FirstChar", &oDictItem)->isInt()) nFirstChar = oDictItem.getInt();
|
||
oDictItem.free();
|
||
|
||
Gfx8BitFont *pT1Font = (Gfx8BitFont *)pFont;
|
||
if (oFontObject.dictLookup("Widths", &oDictItem)->isArray())
|
||
{
|
||
int nWidthsCount = oDictItem.arrayGetLength();
|
||
fprintf(pFile, "StartCharMetrics %d\n", nWidthsCount);
|
||
for (int nIndex = 0; nIndex < nWidthsCount; nIndex++)
|
||
{
|
||
int nWidth = nMissingWidth;
|
||
Object oArrayItem;
|
||
if (oDictItem.arrayGet(nIndex, &oArrayItem)->isInt()) nWidth = oArrayItem.getInt();
|
||
oArrayItem.free();
|
||
|
||
char **ppEncoding = pT1Font->getEncoding();
|
||
|
||
if (ppEncoding && ppEncoding[nIndex])
|
||
fprintf(pFile, "C %d ; WX %d ; N %s ;\n", nIndex + nFirstChar, nWidth, ppEncoding[nIndex]);
|
||
else
|
||
fprintf(pFile, "C %d ; WX %d ;\n", nIndex + nFirstChar, nWidth);
|
||
}
|
||
fprintf(pFile, "EndCharMetrics\n");
|
||
}
|
||
oDictItem.free();
|
||
}
|
||
oFontObject.free();
|
||
}
|
||
fclose(pFile);
|
||
}
|
||
#endif
|
||
|
||
// Загрузим сам файл со шрифтом, чтобы точно определить его тип
|
||
if (!pFontManager->LoadFontFromFile(wsFileName, 0, 10, 72, 72))
|
||
{
|
||
pEntry->bAvailable = true;
|
||
return;
|
||
}
|
||
|
||
std::wstring wsFontType = pFontManager->GetFontType();
|
||
if (L"TrueType" == wsFontType)
|
||
{
|
||
if (eFontType != fontType1COT && eFontType != fontTrueType
|
||
&& eFontType != fontTrueTypeOT && eFontType != fontCIDType0COT
|
||
&& eFontType != fontCIDType2 && eFontType != fontCIDType2OT)
|
||
{
|
||
if (eFontType == fontType1 || eFontType == fontType1C)
|
||
eFontType = fontType1COT;
|
||
else if (eFontType == fontCIDType0 || eFontType == fontCIDType0C)
|
||
eFontType = fontCIDType0COT;
|
||
}
|
||
}
|
||
else if (L"Type 1" == wsFontType)
|
||
{
|
||
if (eFontType != fontType1 && eFontType != fontType1C)
|
||
{
|
||
eFontType = fontType1;
|
||
}
|
||
}
|
||
else if (L"CID Type 1" == wsFontType)
|
||
{
|
||
if (eFontType != fontCIDType0 && eFontType != fontCIDType0C
|
||
&& eFontType != fontCIDType2OT && eFontType != fontCIDType0COT)
|
||
{
|
||
eFontType = fontCIDType0;
|
||
}
|
||
}
|
||
else if (L"CFF" == wsFontType)
|
||
{
|
||
if (eFontType != fontType1C && eFontType != fontType1COT
|
||
&& eFontType != fontTrueTypeOT && eFontType != fontCIDType0C
|
||
&& eFontType != fontCIDType0COT && eFontType != fontCIDType2OT
|
||
&& eFontType != fontCIDType2)
|
||
{
|
||
if (eFontType == fontType1 || eFontType == fontTrueType)
|
||
eFontType = fontType1C;
|
||
else if (eFontType == fontCIDType0)
|
||
eFontType = fontCIDType0C;
|
||
}
|
||
}
|
||
}
|
||
#ifndef FONTS_USE_ONLY_MEMORY_STREAMS
|
||
else if (PdfReader::GetBaseFont(wsFontBaseName, pData14, nSize14))
|
||
{
|
||
FILE* pFile = NULL;
|
||
if (!NSFile::CFileBinary::OpenTempFile(&wsTempFileName, &pFile, L"wb", L".base",
|
||
(wchar_t*)((GlobalParamsAdaptor*)globalParams)->GetTempFolder().c_str(), NULL))
|
||
{
|
||
if (!wsTempFileName.empty())
|
||
NSFile::CFileBinary::Remove(wsTempFileName);
|
||
|
||
pEntry->bAvailable = true;
|
||
return;
|
||
}
|
||
fclose(pFile);
|
||
NSFile::CFileBinary oFile;
|
||
oFile.CreateFileW(wsTempFileName);
|
||
oFile.WriteFile((BYTE*)pData14, nSize14);
|
||
oFile.CloseFile();
|
||
wsFileName = wsTempFileName;
|
||
|
||
eFontType = fontTrueType;
|
||
}
|
||
#else
|
||
else if ([&oMemoryFontStream, wsFontBaseName]()
|
||
{
|
||
const unsigned char* pData14 = NULL;
|
||
unsigned int nSize14 = 0;
|
||
if (PdfReader::GetBaseFont(wsFontBaseName, pData14, nSize14))
|
||
{
|
||
oMemoryFontStream.fromBuffer((BYTE*)pData14, nSize14);
|
||
return true;
|
||
}
|
||
return false;
|
||
}())
|
||
{
|
||
wsFileName = wsFontBaseName;
|
||
NSFonts::NSApplicationFontStream::GetGlobalMemoryStorage()->Add(wsFileName, oMemoryFontStream.m_pData, (LONG)oMemoryFontStream.m_nSize, true);
|
||
}
|
||
#endif
|
||
else if (!pFont->locateFont(pXref, false) ||
|
||
(wsFileName = NSStrings::GetStringFromUTF32(pFont->locateFont(pXref, false)->path)).length() == 0)
|
||
{
|
||
NSFonts::CFontInfo* pFontInfo = GetFontByParams(pXref, pFontManager, pFont, wsFontBaseName);
|
||
|
||
if (pFontInfo && L"" != pFontInfo->m_wsFontPath)
|
||
{
|
||
wsFileName = pFontInfo->m_wsFontPath;
|
||
eFontType = pFont->isCIDFont() ? fontCIDType2 : fontTrueType;
|
||
|
||
#ifdef FONTS_USE_ONLY_MEMORY_STREAMS
|
||
if (NSWasm::IsJSEnv())
|
||
wsFileName = pFontInfo->m_wsFontName;
|
||
|
||
if (!wsFileName.empty())
|
||
{
|
||
wsFileName = NSWasm::LoadFont(wsFileName, pFontInfo->m_bBold, pFontInfo->m_bItalic);
|
||
if (wsFileName.empty())
|
||
{
|
||
pFontList->Remove(*pFont->getID());
|
||
return;
|
||
}
|
||
}
|
||
oMemoryFontStream.fromStream(wsFileName);
|
||
#endif
|
||
|
||
bFontSubstitution = true;
|
||
}
|
||
else // В крайнем случае, в данном шрифте просто не пишем ничего
|
||
{
|
||
pEntry->bAvailable = true;
|
||
return;
|
||
}
|
||
|
||
// Записываем файл с кодировкой. (Специально для перезаписи в PDF)
|
||
/*
|
||
if (c_nPDFWriter == m_lRendererType)
|
||
{
|
||
std::wstring wsExt;
|
||
if (!pFont->isCIDFont())
|
||
{
|
||
wsExt = L".non";
|
||
}
|
||
else if (pFont->isCIDFont())
|
||
{
|
||
wsExt = L".cid_non";
|
||
}
|
||
|
||
FILE* pTempFile = NULL;
|
||
if (!NSFile::CFileBinary::OpenTempFile(&wsTempFileName, &pTempFile, L"wb", (wchar_t*)wsExt.c_str(),
|
||
(wchar_t*)((GlobalParamsAdaptor*)globalParams)->GetTempFolder().c_str(), NULL))
|
||
{
|
||
if (L"" != wsTempFileName)
|
||
NSFile::CFileBinary::Remove(wsTempFileName);
|
||
|
||
pEntry->bAvailable = true;
|
||
return;
|
||
}
|
||
fclose(pTempFile);
|
||
|
||
// Копируем файл, для создания уникального имени, чтобы связать с файлом с кодировкой
|
||
if (NSFile::CFileBinary::Copy(wsFileName, wsTempFileName))
|
||
{
|
||
wsFileName = wsTempFileName;
|
||
}
|
||
else
|
||
{
|
||
NSFile::CFileBinary::Remove(wsTempFileName);
|
||
wsTempFileName = L"";
|
||
}
|
||
|
||
if (L"" != wsTempFileName)
|
||
{
|
||
std::wstring wsSplitFileName, wsSplitFileExt;
|
||
SpitPathExt(wsFileName, &wsSplitFileName, &wsSplitFileExt);
|
||
std::wstring wsEncodingPath = wsSplitFileName + L".enc";
|
||
|
||
CXmlWriter oXmlWriter;
|
||
|
||
Ref *pRef = pFont->getID();
|
||
Object oRefObject, oFontObject;
|
||
oRefObject.initRef(pRef->num, pRef->gen);
|
||
oRefObject.fetch(m_pXref, &oFontObject);
|
||
oRefObject.free();
|
||
|
||
if (oFontObject.isDict())
|
||
{
|
||
Dict *pFontDict = oFontObject.getDict();
|
||
|
||
int nEncodingType = -1; // Объекта Encoding нет
|
||
int nBaseEncoding = -1;
|
||
|
||
Object oDictItem;
|
||
pFontDict->lookup("Encoding", &oDictItem);
|
||
if (oDictItem.isDict())
|
||
{
|
||
nEncodingType = 1; // Encoding - идет отдельным объектом
|
||
|
||
Object oTemp;
|
||
oDictItem.dictLookup("BaseEncoding", &oTemp);
|
||
|
||
if (oTemp.isName("MacRomanEncoding"))
|
||
nBaseEncoding = 0;
|
||
else if (oTemp.isName("MacExpertEncoding"))
|
||
nBaseEncoding = 1;
|
||
else if (oTemp.isName("WinAnsiEncoding"))
|
||
nBaseEncoding = 2;
|
||
|
||
oTemp.free();
|
||
}
|
||
else if (oDictItem.isName("MacRomanEncoding"))
|
||
{
|
||
nEncodingType = 0;
|
||
nBaseEncoding = 0;
|
||
}
|
||
else if (oDictItem.isName("MacExpertEncoding"))
|
||
{
|
||
nEncodingType = 0;
|
||
nBaseEncoding = 1;
|
||
}
|
||
else if (oDictItem.isName("WinAnsiEncoding"))
|
||
{
|
||
nEncodingType = 0;
|
||
nBaseEncoding = 2;
|
||
}
|
||
else
|
||
{
|
||
nEncodingType = -1;
|
||
}
|
||
|
||
oXmlWriter.WriteNodeBegin(L"Encoding", true);
|
||
oXmlWriter.WriteAttribute(L"type", nEncodingType);
|
||
oXmlWriter.WriteAttribute(L"base", nBaseEncoding);
|
||
oXmlWriter.WriteNodeEnd(L"Encoding", true, false);
|
||
|
||
// Differences
|
||
if (oDictItem.isDict())
|
||
{
|
||
Object oDifferences;
|
||
oDictItem.dictLookup("Differences", &oDifferences);
|
||
if (oDifferences.isArray())
|
||
{
|
||
int nArrayLen = oDifferences.arrayGetLength();
|
||
oXmlWriter.WriteNodeBegin(L"Differences", true);
|
||
oXmlWriter.WriteAttribute(L"count", nArrayLen);
|
||
oXmlWriter.WriteNodeEnd(L"Differences", true, false);
|
||
|
||
for (int nIndex = 0; nIndex < nArrayLen; ++nIndex)
|
||
{
|
||
Object oTemp;
|
||
oDifferences.arrayGet(nIndex, &oTemp);
|
||
if (oTemp.isInt())
|
||
{
|
||
int nCode = oTemp.getInt();
|
||
oXmlWriter.WriteNodeBegin(L"Code", true);
|
||
oXmlWriter.WriteAttribute(L"value", nCode);
|
||
oXmlWriter.WriteNodeEnd(L"Code", true, true);
|
||
}
|
||
else if (oTemp.isName())
|
||
{
|
||
char *sName = oTemp.getName();
|
||
oXmlWriter.WriteNodeBegin(L"Name", true);
|
||
oXmlWriter.WriteAttribute(L"value", AStringToWString(sName));
|
||
oXmlWriter.WriteNodeEnd(L"Name", true, true);
|
||
}
|
||
else
|
||
{
|
||
// TODO: Неправильный тип записи
|
||
}
|
||
oTemp.free();
|
||
}
|
||
|
||
oXmlWriter.WriteNodeEnd(L"Differences");
|
||
}
|
||
oDifferences.free();
|
||
}
|
||
oDictItem.free();
|
||
oXmlWriter.WriteNodeEnd(L"Encoding");
|
||
}
|
||
oFontObject.free();
|
||
oXmlWriter.SaveToFile(wsEncodingPath);
|
||
}
|
||
}
|
||
*/
|
||
}
|
||
// Здесь мы грузим кодировки
|
||
int *pCodeToGID = NULL, *pCodeToUnicode = NULL;
|
||
int nLen = 0;
|
||
FoFiTrueType *pTTFontFile = NULL;
|
||
FoFiType1C *pT1CFontFile = NULL;
|
||
#ifdef FONTS_USE_ONLY_MEMORY_STREAMS
|
||
FoFiIdentifierType fofiType = FoFiIdentifier::identifyStream(&readFromMemoryStream, &oMemoryFontStream);
|
||
oMemoryFontStream.toStart();
|
||
#else
|
||
FoFiIdentifierType fofiType = FoFiIdentifier::identifyFile((char*)U_TO_UTF8(wsFileName).c_str());
|
||
#endif
|
||
|
||
switch (eFontType)
|
||
{
|
||
case fontType1:
|
||
case fontType1C:
|
||
case fontType1COT:
|
||
{
|
||
Gfx8BitFont* pFont8bit = NULL;
|
||
if (fofiType == fofiIdTrueType)
|
||
{
|
||
#ifdef FONTS_USE_ONLY_MEMORY_STREAMS
|
||
pTTFontFile = FoFiTrueType::make((char*)oMemoryFontStream.m_pData, oMemoryFontStream.m_nSize, 0);
|
||
#else
|
||
pTTFontFile = FoFiTrueType::load((char*)U_TO_UTF8(wsFileName).c_str(), 0);
|
||
#endif
|
||
|
||
if (pTTFontFile)
|
||
{
|
||
pCodeToGID = ((Gfx8BitFont *)pFont)->getCodeToGIDMap(pTTFontFile);
|
||
nLen = 256;
|
||
|
||
delete pTTFontFile;
|
||
pTTFontFile = NULL;
|
||
}
|
||
else
|
||
{
|
||
pCodeToGID = NULL;
|
||
nLen = 0;
|
||
}
|
||
}
|
||
else if (L"" != wsFileName && (pFont8bit = dynamic_cast<Gfx8BitFont*>(pFont)))
|
||
{
|
||
char **ppEncoding = pFont8bit->getEncoding();
|
||
if (!ppEncoding)
|
||
break;
|
||
|
||
if (!pFontManager)
|
||
break;
|
||
|
||
pFontManager->LoadFontFromFile(wsFileName, 0, 1, 72, 72);
|
||
pCodeToGID = (int *)MemUtilsMallocArray(256, sizeof(int));
|
||
if (!pCodeToGID)
|
||
break;
|
||
|
||
nLen = 256;
|
||
for (int nIndex = 0; nIndex < 256; ++nIndex)
|
||
{
|
||
pCodeToGID[nIndex] = 0;
|
||
char* sName = NULL;
|
||
if ((sName = ppEncoding[nIndex]))
|
||
{
|
||
unsigned short ushGID = pFontManager->GetNameIndex(AStringToWString(sName));
|
||
pCodeToGID[nIndex] = ushGID;
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case fontTrueType:
|
||
case fontTrueTypeOT:
|
||
{
|
||
if (fofiType == fofiIdType1PFB)
|
||
{
|
||
Gfx8BitFont* pFont8bit = dynamic_cast<Gfx8BitFont*>(pFont);
|
||
if (L"" != wsFileName && pFont8bit && pFont8bit->getHasEncoding())
|
||
{
|
||
char **ppEncoding = pFont8bit->getEncoding();
|
||
if (!ppEncoding)
|
||
break;
|
||
|
||
if (!pFontManager)
|
||
break;
|
||
|
||
pFontManager->LoadFontFromFile(wsFileName, 0, 1, 72, 72);
|
||
pCodeToGID = (int *)MemUtilsMallocArray(256, sizeof(int));
|
||
if (!pCodeToGID)
|
||
break;
|
||
|
||
nLen = 256;
|
||
for (int nIndex = 0; nIndex < 256; ++nIndex)
|
||
{
|
||
pCodeToGID[nIndex] = 0;
|
||
char* sName = NULL;
|
||
if ((sName = ppEncoding[nIndex]))
|
||
{
|
||
unsigned short ushGID = pFontManager->GetNameIndex(AStringToWString(sName));
|
||
pCodeToGID[nIndex] = ushGID;
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
|
||
#ifdef FONTS_USE_ONLY_MEMORY_STREAMS
|
||
pTTFontFile = FoFiTrueType::make((char*)oMemoryFontStream.m_pData, oMemoryFontStream.m_nSize, 0);
|
||
#else
|
||
pTTFontFile = FoFiTrueType::load((char*)U_TO_UTF8(wsFileName).c_str(), 0);
|
||
#endif
|
||
if (pTTFontFile)
|
||
{
|
||
pCodeToGID = ((Gfx8BitFont *)pFont)->getCodeToGIDMap(pTTFontFile);
|
||
nLen = 256;
|
||
|
||
delete pTTFontFile;
|
||
pTTFontFile = NULL;
|
||
}
|
||
else
|
||
{
|
||
pCodeToGID = NULL;
|
||
nLen = 0;
|
||
|
||
if (pFontManager->LoadFontFromFile(wsFileName, 0, 10, 72, 72))
|
||
{
|
||
INT* pCodes = NULL;
|
||
nLen = 256;
|
||
pCodeToGID = (int*)MemUtilsMallocArray(nLen, sizeof(int));
|
||
for (int nCode = 0; nCode < nLen; ++nCode)
|
||
{
|
||
pCodeToGID[nCode] = pFontManager->GetGIDByUnicode(nCode);
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case fontCIDType0:
|
||
case fontCIDType0C:
|
||
{
|
||
/*
|
||
GfxCIDFont* pFontCID = dynamic_cast<GfxCIDFont*>(pFont);
|
||
if (!bFontSubstitution && pFontCID && pFontCID->getCIDToGID())
|
||
{
|
||
nLen = pFontCID->getCIDToGIDLen();
|
||
if (!nLen)
|
||
break;
|
||
pCodeToGID = (int*)MemUtilsMallocArray(nLen, sizeof(int));
|
||
if (!pCodeToGID)
|
||
{
|
||
nLen = 0;
|
||
break;
|
||
}
|
||
memcpy(pCodeToGID, ((GfxCIDFont*)pFont)->getCIDToGID(), nLen * sizeof(int));
|
||
break;
|
||
}
|
||
#ifdef FONTS_USE_ONLY_MEMORY_STREAMS
|
||
pT1CFontFile = FoFiType1C::make((char*)oMemoryFontStream.m_pData, oMemoryFontStream.m_nSize);
|
||
#else
|
||
pT1CFontFile = FoFiType1C::load((char*)U_TO_UTF8(wsFileName).c_str());
|
||
#endif
|
||
if (pT1CFontFile)
|
||
{
|
||
pCodeToGID = pT1CFontFile->getCIDToGIDMap(&nLen);
|
||
|
||
delete pT1CFontFile;
|
||
pT1CFontFile = NULL;
|
||
}
|
||
else
|
||
{
|
||
pCodeToGID = NULL;
|
||
nLen = 0;
|
||
}
|
||
*/
|
||
pCodeToGID = NULL;
|
||
nLen = 0;
|
||
break;
|
||
}
|
||
case fontCIDType0COT:
|
||
{
|
||
GfxCIDFont* pFontCID = dynamic_cast<GfxCIDFont*>(pFont);
|
||
if (!bFontSubstitution && pFontCID && pFontCID->getCIDToGID())
|
||
{
|
||
nLen = pFontCID->getCIDToGIDLen();
|
||
if (!nLen)
|
||
break;
|
||
pCodeToGID = (int*)MemUtilsMallocArray(nLen, sizeof(int));
|
||
if (!pCodeToGID)
|
||
{
|
||
nLen = 0;
|
||
break;
|
||
}
|
||
memcpy(pCodeToGID, ((GfxCIDFont*)pFont)->getCIDToGID(), nLen * sizeof(int));
|
||
break;
|
||
}
|
||
#ifdef FONTS_USE_ONLY_MEMORY_STREAMS
|
||
pTTFontFile = FoFiTrueType::make((char*)oMemoryFontStream.m_pData, oMemoryFontStream.m_nSize, 0);
|
||
#else
|
||
pTTFontFile = FoFiTrueType::load((char*)U_TO_UTF8(wsFileName).c_str(), 0);
|
||
#endif
|
||
|
||
if (pTTFontFile)
|
||
{
|
||
if (pTTFontFile->isOpenTypeCFF())
|
||
{
|
||
pCodeToGID = pTTFontFile->getCIDToGIDMap(&nLen);
|
||
}
|
||
else
|
||
{
|
||
pCodeToGID = NULL;
|
||
nLen = 0;
|
||
}
|
||
delete pTTFontFile;
|
||
pTTFontFile = NULL;
|
||
}
|
||
else
|
||
{
|
||
pCodeToGID = NULL;
|
||
nLen = 0;
|
||
}
|
||
break;
|
||
}
|
||
case fontCIDType2:
|
||
case fontCIDType2OT:
|
||
{
|
||
// Создаем карту CID-to-GID
|
||
// Если у нас шрифт был не встроен и подбирался и есть мап ToUnicode, тогда на основе его читаем из файла гиды по юникодным значениям.
|
||
// Для встроенных шрифтов используем мап CIDtoGID
|
||
pCodeToGID = NULL;
|
||
nLen = 0;
|
||
if (L"" != wsFileName && bFontSubstitution)
|
||
{
|
||
CharCodeToUnicode *pCodeToUnicode = NULL;
|
||
if ((pCodeToUnicode = ((GfxCIDFont *)pFont)->getToUnicode()))
|
||
{
|
||
#ifdef FONTS_USE_ONLY_MEMORY_STREAMS
|
||
pTTFontFile = FoFiTrueType::make((char*)oMemoryFontStream.m_pData, oMemoryFontStream.m_nSize, 0);
|
||
#else
|
||
pTTFontFile = FoFiTrueType::load((char*)U_TO_UTF8(wsFileName).c_str(), 0);
|
||
#endif
|
||
if (pTTFontFile)
|
||
{
|
||
// Ищем Unicode Cmap
|
||
std::vector<int> arrCMapIndex;
|
||
for (int nCMapIndex = 0; nCMapIndex < pTTFontFile->getNumCmaps(); ++nCMapIndex)
|
||
{
|
||
if ((pTTFontFile->getCmapPlatform(nCMapIndex) == 3 && pTTFontFile->getCmapEncoding(nCMapIndex) == 1) || pTTFontFile->getCmapPlatform(nCMapIndex) == 0)
|
||
{
|
||
arrCMapIndex.push_back(nCMapIndex);
|
||
}
|
||
}
|
||
if (arrCMapIndex.size() > 0)
|
||
{
|
||
// CID -> Unicode -> GID
|
||
nLen = pCodeToUnicode->getLength();
|
||
pCodeToGID = (int *)MemUtilsMallocArray(nLen, sizeof(int));
|
||
for (int nCode = 0; nCode < nLen; ++nCode)
|
||
{
|
||
Unicode arrUnicodeBuffer[8];
|
||
if (pCodeToUnicode->mapToUnicode(nCode, arrUnicodeBuffer, 8) > 0)
|
||
{
|
||
pCodeToGID[nCode] = pTTFontFile->mapCodeToGID(arrCMapIndex[0], arrUnicodeBuffer[0]);
|
||
for (size_t nIndex = 1; nIndex < arrCMapIndex.size(); nIndex++)
|
||
{
|
||
if (0 == pCodeToGID[nCode])
|
||
pCodeToGID[nCode] = pTTFontFile->mapCodeToGID(arrCMapIndex[nIndex], arrUnicodeBuffer[0]);
|
||
else
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
pCodeToGID[nCode] = 0;
|
||
}
|
||
}
|
||
}
|
||
delete pTTFontFile;
|
||
pTTFontFile = NULL;
|
||
}
|
||
pCodeToUnicode->decRefCnt();
|
||
}
|
||
}
|
||
else if (((GfxCIDFont *)pFont)->getCIDToGID())
|
||
{
|
||
nLen = ((GfxCIDFont *)pFont)->getCIDToGIDLen();
|
||
pCodeToGID = (int *)MemUtilsMallocArray(nLen, sizeof(int));
|
||
if (!pCodeToGID)
|
||
break;
|
||
|
||
memcpy(pCodeToGID, ((GfxCIDFont *)pFont)->getCIDToGID(), nLen * sizeof(int));
|
||
}
|
||
|
||
break;
|
||
}
|
||
default:
|
||
{
|
||
// Такого не должно произойти
|
||
#ifndef FONTS_USE_ONLY_MEMORY_STREAMS
|
||
if (L"" != wsTempFileName)
|
||
NSFile::CFileBinary::Remove(wsTempFileName);
|
||
#endif
|
||
break;
|
||
}
|
||
}
|
||
// Составляем таблицу Code -> Unicode
|
||
int nToUnicodeLen = 0;
|
||
if (pFont->isCIDFont())
|
||
{
|
||
GfxCIDFont *pCIDFont = (GfxCIDFont *)pFont;
|
||
CharCodeToUnicode *pToUnicode = pCIDFont->getToUnicode();
|
||
if (NULL != pToUnicode)
|
||
{
|
||
nToUnicodeLen = pToUnicode->getLength();
|
||
pCodeToUnicode = (int *)MemUtilsMallocArray(nToUnicodeLen, sizeof(int));
|
||
|
||
if (pCodeToUnicode)
|
||
{
|
||
for (int nIndex = 0; nIndex < nToUnicodeLen; ++nIndex)
|
||
{
|
||
Unicode aUnicode[2];
|
||
if (pToUnicode->mapToUnicode(nIndex, aUnicode, 2))
|
||
pCodeToUnicode[nIndex] = (unsigned short)aUnicode[0];
|
||
else
|
||
pCodeToUnicode[nIndex] = 0;
|
||
}
|
||
}
|
||
|
||
pToUnicode->decRefCnt();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// memory troubles here
|
||
|
||
CharCodeToUnicode *pToUnicode = ((Gfx8BitFont *)pFont)->getToUnicode();
|
||
if (NULL != pToUnicode)
|
||
{
|
||
nToUnicodeLen = pToUnicode->getLength();
|
||
pCodeToUnicode = (int *)MemUtilsMallocArray(nToUnicodeLen, sizeof(int));//literally here
|
||
|
||
if (pCodeToUnicode)
|
||
{
|
||
for (int nIndex = 0; nIndex < nToUnicodeLen; ++nIndex)
|
||
{
|
||
Unicode nUnicode = 0;
|
||
if (pToUnicode->mapToUnicode(nIndex, &nUnicode, 1))
|
||
pCodeToUnicode[nIndex] = (unsigned short)nUnicode;
|
||
else
|
||
pCodeToUnicode[nIndex] = nIndex;
|
||
}
|
||
}
|
||
pToUnicode->decRefCnt();
|
||
}
|
||
}
|
||
|
||
// Записываем файл с настройками шрифта (Специально для перезаписи в PDF)
|
||
/*
|
||
if (L"" != wsFileName && c_nPDFWriter == m_lRendererType)
|
||
{
|
||
std::wstring wsSplitFileName, wsSplitFileExt;
|
||
SpitPathExt(wsFileName, &wsSplitFileName, &wsSplitFileExt);
|
||
std::wstring wsEncodingPath = wsSplitFileName + L".enc";
|
||
|
||
GfxFontType eFontType = pFont->getType();
|
||
if (fontType1 == eFontType || fontType1C == eFontType || fontType1COT == eFontType || fontTrueType == eFontType || fontTrueTypeOT == eFontType)
|
||
{
|
||
// Запись информации для простых шрифтов
|
||
CXmlWriter oXmlWriter;
|
||
|
||
Ref *pRef = pFont->getID();
|
||
Object oRefObject, oFontObject;
|
||
oRefObject.initRef(pRef->num, pRef->gen);
|
||
oRefObject.fetch(m_pXref, &oFontObject);
|
||
oRefObject.free();
|
||
|
||
if (oFontObject.isDict())
|
||
{
|
||
Dict *pFontDict = oFontObject.getDict();
|
||
|
||
int nEncodingType = -1; // Объекта Encoding нет
|
||
int nBaseEncoding = -1;
|
||
|
||
Object oDictItem;
|
||
pFontDict->lookup("Encoding", &oDictItem);
|
||
if (oDictItem.isDict())
|
||
{
|
||
nEncodingType = 1; // Encoding - идет отдельным объектом
|
||
|
||
Object oTemp;
|
||
oDictItem.dictLookup("BaseEncoding", &oTemp);
|
||
|
||
if (oTemp.isName("MacRomanEncoding"))
|
||
nBaseEncoding = 0;
|
||
else if (oTemp.isName("MacExpertEncoding"))
|
||
nBaseEncoding = 1;
|
||
else if (oTemp.isName("WinAnsiEncoding"))
|
||
nBaseEncoding = 2;
|
||
|
||
oTemp.free();
|
||
}
|
||
else if (oDictItem.isName("MacRomanEncoding"))
|
||
{
|
||
nEncodingType = 0;
|
||
nBaseEncoding = 0;
|
||
}
|
||
else if (oDictItem.isName("MacExpertEncoding"))
|
||
{
|
||
nEncodingType = 0;
|
||
nBaseEncoding = 1;
|
||
}
|
||
else if (oDictItem.isName("WinAnsiEncoding"))
|
||
{
|
||
nEncodingType = 0;
|
||
nBaseEncoding = 2;
|
||
}
|
||
else
|
||
{
|
||
nEncodingType = -1;
|
||
}
|
||
|
||
oXmlWriter.WriteNodeBegin(L"PDF-resources");
|
||
oXmlWriter.WriteNodeBegin(L"Encoding", true);
|
||
oXmlWriter.WriteAttribute(L"type", nEncodingType);
|
||
oXmlWriter.WriteAttribute(L"base", nBaseEncoding);
|
||
oXmlWriter.WriteNodeEnd(L"Encoding", true, false);
|
||
|
||
// Differences
|
||
if (oDictItem.isDict())
|
||
{
|
||
Object oDifferences;
|
||
oDictItem.dictLookup("Differences", &oDifferences);
|
||
if (oDifferences.isArray())
|
||
{
|
||
int nArrayLen = oDifferences.arrayGetLength();
|
||
oXmlWriter.WriteNodeBegin(L"Differences", true);
|
||
oXmlWriter.WriteAttribute(L"count", nArrayLen);
|
||
oXmlWriter.WriteNodeEnd(L"Differences", true, false);
|
||
|
||
for (int nIndex = 0; nIndex < nArrayLen; ++nIndex)
|
||
{
|
||
Object oTemp;
|
||
oDifferences.arrayGet(nIndex, &oTemp);
|
||
if (oTemp.isInt())
|
||
{
|
||
int nCode = oTemp.getInt();
|
||
oXmlWriter.WriteNodeBegin(L"Code", true);
|
||
oXmlWriter.WriteAttribute(L"value", nCode);
|
||
oXmlWriter.WriteNodeEnd(L"Code", true, true);
|
||
}
|
||
else if (oTemp.isName())
|
||
{
|
||
char* sName = oTemp.getName();
|
||
oXmlWriter.WriteNodeBegin(L"Name", true);
|
||
oXmlWriter.WriteAttribute(L"value", AStringToWString(sName));
|
||
oXmlWriter.WriteNodeEnd(L"Name", true, true);
|
||
}
|
||
else
|
||
{
|
||
// TO DO: Error "Wrong type in font encoding resource differences"
|
||
}
|
||
oTemp.free();
|
||
}
|
||
|
||
oXmlWriter.WriteNodeEnd(L"Differences");
|
||
}
|
||
oDifferences.free();
|
||
}
|
||
oDictItem.free();
|
||
oXmlWriter.WriteNodeEnd(L"Encoding");
|
||
|
||
pFontDict->lookup("BaseFont", &oDictItem);
|
||
if (oDictItem.isName())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"FontBase", true);
|
||
oXmlWriter.WriteAttribute(L"value", AStringToWString(oDictItem.getName()));
|
||
oXmlWriter.WriteNodeEnd(L"FontBase", true, true);
|
||
}
|
||
oDictItem.free();
|
||
|
||
pFontDict->lookup("ToUnicode", &oDictItem);
|
||
if (oDictItem.isStream())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"ToUnicode");
|
||
|
||
std::string sBuffer;
|
||
if (true)
|
||
{
|
||
oDictItem.streamReset();
|
||
int nChar = 0;
|
||
while ((nChar = oDictItem.streamGetChar()) != EOF)
|
||
{
|
||
sBuffer+=(char)nChar;
|
||
}
|
||
oDictItem.streamClose();
|
||
|
||
CBase64 oBase64;
|
||
oBase64.Encode((unsigned char*)sBuffer.c_str(), sBuffer.length());
|
||
|
||
oXmlWriter.WriteString(AStringToWString(oBase64.GetCString()));
|
||
}
|
||
|
||
oXmlWriter.WriteNodeEnd(L"ToUnicode");
|
||
}
|
||
oDictItem.free();
|
||
|
||
|
||
oXmlWriter.WriteNodeBegin(L"FontDescriptor");
|
||
|
||
Object oFontDescriptor;
|
||
if (pFontDict->lookup("FontDescriptor", &oFontDescriptor)->isDict())
|
||
{
|
||
// FontName
|
||
oFontDescriptor.dictLookup("FontName", &oDictItem);
|
||
if (oDictItem.isName())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"FontName", true);
|
||
oXmlWriter.WriteAttribute(L"value", AStringToWString(oDictItem.getName()));
|
||
oXmlWriter.WriteNodeEnd(L"FontName", true);
|
||
}
|
||
oDictItem.free();
|
||
|
||
// FontFamily
|
||
oFontDescriptor.dictLookup("FontFamily", &oDictItem);
|
||
if (oDictItem.isName())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"FontFamily", true);
|
||
oXmlWriter.WriteAttribute(L"value", AStringToWString(oDictItem.getName()));
|
||
oXmlWriter.WriteNodeEnd(L"FontFamily", true);
|
||
}
|
||
oDictItem.free();
|
||
|
||
// FontStretch
|
||
oFontDescriptor.dictLookup("FontStretch", &oDictItem);
|
||
if (oDictItem.isName())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"FontStretch", true);
|
||
oXmlWriter.WriteAttribute(L"value", AStringToWString(oDictItem.getName()));
|
||
oXmlWriter.WriteNodeEnd(L"FontStretch", true);
|
||
}
|
||
oDictItem.free();
|
||
|
||
// FontWeight
|
||
oFontDescriptor.dictLookup("FontWeight", &oDictItem);
|
||
if (oDictItem.isInt())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"FontWeight", true);
|
||
oXmlWriter.WriteAttribute(L"value", oDictItem.getInt());
|
||
oXmlWriter.WriteNodeEnd(L"FontWeight", true);
|
||
}
|
||
oDictItem.free();
|
||
|
||
// FontWeight
|
||
oFontDescriptor.dictLookup("Flags", &oDictItem);
|
||
if (oDictItem.isInt())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"Flags", true);
|
||
oXmlWriter.WriteAttribute(L"value", oDictItem.getInt());
|
||
oXmlWriter.WriteNodeEnd(L"Flags", true);
|
||
}
|
||
oDictItem.free();
|
||
|
||
// FontBBox
|
||
oFontDescriptor.dictLookup("FontBBox", &oDictItem);
|
||
if (oDictItem.isArray())
|
||
{
|
||
Array *pBBox = oDictItem.getArray();
|
||
if (NULL != pBBox && 4 == pBBox->getLength())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"FontBBox", true);
|
||
for (int nIndex = 0; nIndex < 4; nIndex++)
|
||
{
|
||
Object oArrayItem;
|
||
pBBox->get(nIndex, &oArrayItem);
|
||
if (oArrayItem.isInt())
|
||
{
|
||
std::wstring wsValue = L"value" + std::to_wstring(nIndex);
|
||
oXmlWriter.WriteAttribute(wsValue, oArrayItem.getInt());
|
||
}
|
||
|
||
oArrayItem.free();
|
||
}
|
||
oXmlWriter.WriteNodeEnd(L"FontBBox", true);
|
||
}
|
||
}
|
||
oDictItem.free();
|
||
|
||
// ItalicAngle
|
||
oFontDescriptor.dictLookup("ItalicAngle", &oDictItem);
|
||
if (oDictItem.isInt())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"ItalicAngle", true);
|
||
oXmlWriter.WriteAttribute(L"value", oDictItem.getInt());
|
||
oXmlWriter.WriteNodeEnd(L"ItalicAngle", true);
|
||
}
|
||
oDictItem.free();
|
||
|
||
// Ascent
|
||
oFontDescriptor.dictLookup("Ascent", &oDictItem);
|
||
if (oDictItem.isInt())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"Ascent", true);
|
||
oXmlWriter.WriteAttribute(L"value", oDictItem.getInt());
|
||
oXmlWriter.WriteNodeEnd(L"Ascent", true);
|
||
}
|
||
oDictItem.free();
|
||
|
||
// Leading
|
||
oFontDescriptor.dictLookup("Leading", &oDictItem);
|
||
if (oDictItem.isInt())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"Leading", true);
|
||
oXmlWriter.WriteAttribute(L"value", oDictItem.getInt());
|
||
oXmlWriter.WriteNodeEnd(L"Leading", true);
|
||
}
|
||
oDictItem.free();
|
||
|
||
// CapHeight
|
||
oFontDescriptor.dictLookup("CapHeight", &oDictItem);
|
||
if (oDictItem.isInt())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"CapHeight", true);
|
||
oXmlWriter.WriteAttribute(L"value", oDictItem.getInt());
|
||
oXmlWriter.WriteNodeEnd(L"CapHeight", true);
|
||
}
|
||
oDictItem.free();
|
||
|
||
// XHeight
|
||
oFontDescriptor.dictLookup("XHeight", &oDictItem);
|
||
if (oDictItem.isInt())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"XHeight", true);
|
||
oXmlWriter.WriteAttribute(L"value", oDictItem.getInt());
|
||
oXmlWriter.WriteNodeEnd(L"XHeight", true);
|
||
}
|
||
oDictItem.free();
|
||
|
||
// StemV
|
||
oFontDescriptor.dictLookup("StemV", &oDictItem);
|
||
if (oDictItem.isInt())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"StemV", true);
|
||
oXmlWriter.WriteAttribute(L"value", oDictItem.getInt());
|
||
oXmlWriter.WriteNodeEnd(L"StemV", true);
|
||
}
|
||
oDictItem.free();
|
||
|
||
// StemH
|
||
oFontDescriptor.dictLookup("StemH", &oDictItem);
|
||
if (oDictItem.isInt())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"StemH", true);
|
||
oXmlWriter.WriteAttribute(L"value", oDictItem.getInt());
|
||
oXmlWriter.WriteNodeEnd(L"StemH", true);
|
||
}
|
||
oDictItem.free();
|
||
|
||
// Descent
|
||
oFontDescriptor.dictLookup("Descent", &oDictItem);
|
||
if (oDictItem.isInt())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"Descent", true);
|
||
oXmlWriter.WriteAttribute(L"value", oDictItem.getInt());
|
||
oXmlWriter.WriteNodeEnd(L"Descent", true);
|
||
}
|
||
oDictItem.free();
|
||
|
||
// AvgWidth
|
||
oFontDescriptor.dictLookup("AvgWidth", &oDictItem);
|
||
if (oDictItem.isInt())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"AvgWidth", true);
|
||
oXmlWriter.WriteAttribute(L"value", oDictItem.getInt());
|
||
oXmlWriter.WriteNodeEnd(L"AvgWidth", true);
|
||
}
|
||
oDictItem.free();
|
||
|
||
// MaxWidth
|
||
oFontDescriptor.dictLookup("MaxWidth", &oDictItem);
|
||
if (oDictItem.isInt())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"MaxWidth", true);
|
||
oXmlWriter.WriteAttribute(L"value", oDictItem.getInt());
|
||
oXmlWriter.WriteNodeEnd(L"MaxWidth", true);
|
||
}
|
||
oDictItem.free();
|
||
|
||
// MissingWidth
|
||
oFontDescriptor.dictLookup("MissingWidth", &oDictItem);
|
||
if (oDictItem.isInt())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"MissingWidth", true);
|
||
oXmlWriter.WriteAttribute(L"value", oDictItem.getInt());
|
||
oXmlWriter.WriteNodeEnd(L"MissingWidth", true);
|
||
}
|
||
oDictItem.free();
|
||
|
||
}
|
||
oFontDescriptor.free();
|
||
oXmlWriter.WriteNodeEnd(L"FontDescriptor");
|
||
|
||
int nFirstChar = 0;
|
||
pFontDict->lookup("FirstChar", &oDictItem);
|
||
if (oDictItem.isInt()) nFirstChar = oDictItem.getInt();
|
||
oDictItem.free();
|
||
|
||
int nLastChar = 0;
|
||
pFontDict->lookup("LastChar", &oDictItem);
|
||
if (oDictItem.isInt()) nLastChar = oDictItem.getInt();
|
||
oDictItem.free();
|
||
|
||
Array *pWidths = NULL;
|
||
pFontDict->lookup("Widths", &oDictItem);
|
||
if (oDictItem.isArray())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"Widths", true);
|
||
oXmlWriter.WriteAttribute(L"FirstChar", nFirstChar);
|
||
oXmlWriter.WriteAttribute(L"LastChar", nLastChar);
|
||
oXmlWriter.WriteNodeEnd(L"Widths", true, false);
|
||
|
||
Array *pWidths = oDictItem.getArray();
|
||
int nWidthsCount = pWidths->getLength();
|
||
for (int nIndex = 0; nIndex < nWidthsCount; nIndex++)
|
||
{
|
||
Object oArrayItem;
|
||
pWidths->get(nIndex, &oArrayItem);
|
||
if (oArrayItem.isInt())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"Width", true);
|
||
oXmlWriter.WriteAttribute(L"value", oArrayItem.getInt());
|
||
oXmlWriter.WriteNodeEnd(L"Width", true);
|
||
}
|
||
oArrayItem.free();
|
||
}
|
||
oXmlWriter.WriteNodeEnd(L"Widths");
|
||
}
|
||
oDictItem.free();
|
||
oXmlWriter.WriteNodeEnd(L"PDF-resources");
|
||
}
|
||
oFontObject.free();
|
||
oXmlWriter.SaveToFile(wsEncodingPath);
|
||
}
|
||
else if (fontCIDType0 == eFontType || fontCIDType0C == eFontType || fontCIDType0COT == eFontType || fontCIDType2 == eFontType || fontCIDType2OT == eFontType)
|
||
{
|
||
// Пишем файл с кодировкой CMap
|
||
std::wstring wsCMapPath = wsSplitFileName + L".cmap";
|
||
if (pFont->isCIDFont())
|
||
{
|
||
GfxCIDFont *pCIDFont = (GfxCIDFont *)pFont;
|
||
// if (NULL != pCIDFont->GetCMap()) todo toxml
|
||
// pCIDFont->GetCMap()->ToXml(wsCMapPath);
|
||
}
|
||
|
||
CXmlWriter oXmlWriter;
|
||
Ref *pRef = pFont->getID();
|
||
Object oRefObject, oFontObject;
|
||
oRefObject.initRef(pRef->num, pRef->gen);
|
||
oRefObject.fetch(m_pXref, &oFontObject);
|
||
oRefObject.free();
|
||
if (oFontObject.isDict())
|
||
{
|
||
Dict *pFontDict = oFontObject.getDict();
|
||
oXmlWriter.WriteNodeBegin(L"PDF-resources");
|
||
Object oDictItem;
|
||
pFontDict->lookup("BaseFont", &oDictItem);
|
||
if (oDictItem.isName())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"Type0", true);
|
||
oXmlWriter.WriteAttribute(L"value", AStringToWString(oDictItem.getName()));
|
||
oXmlWriter.WriteNodeEnd(L"Type0", true, false);
|
||
}
|
||
else
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"Type0");
|
||
}
|
||
oDictItem.free();
|
||
|
||
pFontDict->lookup("ToUnicode", &oDictItem);
|
||
if (oDictItem.isStream())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"ToUnicode");
|
||
|
||
std::string sBuffer;
|
||
oDictItem.streamReset();
|
||
int nChar = 0;
|
||
while ((nChar = oDictItem.streamGetChar()) != EOF)
|
||
{
|
||
sBuffer+=(char)nChar;
|
||
}
|
||
oDictItem.streamClose();
|
||
|
||
CBase64 oBase64;
|
||
oBase64.Encode((unsigned char*)sBuffer.c_str(), sBuffer.length());
|
||
|
||
oXmlWriter.WriteString(AStringToWString(oBase64.GetCString()));
|
||
oXmlWriter.WriteNodeEnd(L"ToUnicode");
|
||
}
|
||
oDictItem.free();
|
||
|
||
pFontDict->lookup("Encoding", &oDictItem);
|
||
if (oDictItem.isName())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"Encoding", true);
|
||
oXmlWriter.WriteAttribute(L"name", AStringToWString(oDictItem.getName()));
|
||
oXmlWriter.WriteNodeEnd(L"Encoding", true, true);
|
||
}
|
||
else if (oDictItem.isStream())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"Encoding");
|
||
|
||
Dict *pEncodingDict = oDictItem.streamGetDict();
|
||
if (NULL != pEncodingDict)
|
||
{
|
||
Object oEncItem;
|
||
pEncodingDict->lookup("CMapName", &oEncItem);
|
||
if (oEncItem.isName())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"CMapName", true);
|
||
oXmlWriter.WriteAttribute(L"name", AStringToWString(oEncItem.getName()));
|
||
oXmlWriter.WriteNodeEnd(L"CMapName", true, true);
|
||
}
|
||
oEncItem.free();
|
||
|
||
pEncodingDict->lookup("CIDSystemInfo", &oEncItem);
|
||
if (oEncItem.isDict())
|
||
{
|
||
Dict *pCIDInfo = oEncItem.getDict();
|
||
|
||
if (NULL != pCIDInfo)
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"CIDSystemInfo");
|
||
|
||
Object oCIDInfoItem;
|
||
pCIDInfo->lookup("Registry", &oCIDInfoItem);
|
||
if (oCIDInfoItem.isString())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"Registry", true);
|
||
oXmlWriter.WriteAttribute(L"string", AStringToWString(oCIDInfoItem.getString()->getCString()));
|
||
oXmlWriter.WriteNodeEnd(L"Registry", true, true);
|
||
}
|
||
oCIDInfoItem.free();
|
||
|
||
pCIDInfo->lookup("Ordering", &oCIDInfoItem);
|
||
if (oCIDInfoItem.isString())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"Ordering", true);
|
||
oXmlWriter.WriteAttribute(L"string", AStringToWString(oCIDInfoItem.getString()->getCString()));
|
||
oXmlWriter.WriteNodeEnd(L"Ordering", true, true);
|
||
}
|
||
oCIDInfoItem.free();
|
||
|
||
pCIDInfo->lookup("Supplement", &oCIDInfoItem);
|
||
if (oCIDInfoItem.isInt())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"Supplement", true);
|
||
oXmlWriter.WriteAttribute(L"integer", oCIDInfoItem.getInt());
|
||
oXmlWriter.WriteNodeEnd(L"Supplement", true, true);
|
||
}
|
||
oCIDInfoItem.free();
|
||
|
||
oXmlWriter.WriteNodeEnd(L"CIDSystemInfo");
|
||
}
|
||
}
|
||
oEncItem.free();
|
||
|
||
pEncodingDict->lookup("WMode", &oEncItem);
|
||
if (oEncItem.isInt())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"WMode", true);
|
||
oXmlWriter.WriteAttribute(L"integer", oEncItem.getInt());
|
||
oXmlWriter.WriteNodeEnd(L"WMode", true, true);
|
||
}
|
||
oEncItem.free();
|
||
|
||
pEncodingDict->lookup("UseCMap", &oEncItem);
|
||
if (oEncItem.isName())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"UseCMap", true);
|
||
oXmlWriter.WriteAttribute(L"name", AStringToWString(oEncItem.getName()));
|
||
oXmlWriter.WriteNodeEnd(L"UseCMap", true, true);
|
||
}
|
||
else if (oEncItem.isStream())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"UseCMap");
|
||
|
||
std::string sBuffer;
|
||
oEncItem.streamReset();
|
||
int nChar = 0;
|
||
while ((nChar = oEncItem.streamGetChar()) != EOF)
|
||
{
|
||
sBuffer+=(char)nChar;
|
||
}
|
||
oEncItem.streamClose();
|
||
|
||
CBase64 oBase64;
|
||
oBase64.Encode((unsigned char*)sBuffer.c_str(), sBuffer.length());
|
||
|
||
oXmlWriter.WriteString(AStringToWString(oBase64.GetCString()));
|
||
|
||
oXmlWriter.WriteNodeEnd(L"UseCMap");
|
||
}
|
||
oEncItem.free();
|
||
}
|
||
|
||
oXmlWriter.WriteNodeBegin(L"Stream");
|
||
std::string sBuffer;
|
||
oDictItem.streamReset();
|
||
int nChar = 0;
|
||
while ((nChar = oDictItem.streamGetChar()) != EOF)
|
||
{
|
||
sBuffer+=(char)nChar;
|
||
}
|
||
oDictItem.streamClose();
|
||
|
||
CBase64 oBase64;
|
||
oBase64.Encode((unsigned char*)sBuffer.c_str(), sBuffer.length());
|
||
|
||
oXmlWriter.WriteString(AStringToWString(oBase64.GetCString()));
|
||
|
||
oXmlWriter.WriteNodeEnd(L"Stream");
|
||
oXmlWriter.WriteNodeEnd(L"Encoding");
|
||
}
|
||
oDictItem.free();
|
||
|
||
pFontDict->lookup("DescendantFonts", &oDictItem);
|
||
if (oDictItem.isArray())
|
||
{
|
||
Array *pArray = oDictItem.getArray();
|
||
if (1 == pArray->getLength())
|
||
{
|
||
Object oDescFont;
|
||
pArray->get(0, &oDescFont);
|
||
|
||
if (oDescFont.isDict())
|
||
{
|
||
Dict *pDescFont = oDescFont.getDict();
|
||
if (NULL != pDescFont)
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"DescendantFonts");
|
||
|
||
Object oFontItem;
|
||
pDescFont->lookup("Subtype", &oFontItem);
|
||
if (oFontItem.isName())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"Subtype", true);
|
||
oXmlWriter.WriteAttribute(L"name", AStringToWString(oFontItem.getName()));
|
||
oXmlWriter.WriteNodeEnd(L"Subtype", true, true);
|
||
}
|
||
oFontItem.free();
|
||
|
||
pDescFont->lookup("BaseFont", &oFontItem);
|
||
if (oFontItem.isName())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"BaseFont", true);
|
||
oXmlWriter.WriteAttribute(L"name", AStringToWString(oFontItem.getName()));
|
||
oXmlWriter.WriteNodeEnd(L"BaseFont", true, true);
|
||
}
|
||
oFontItem.free();
|
||
|
||
pDescFont->lookup("CIDSystemInfo", &oFontItem);
|
||
if (oFontItem.isDict())
|
||
{
|
||
Dict *pCIDInfo = oFontItem.getDict();
|
||
if (NULL != pCIDInfo)
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"CIDSystemInfo");
|
||
|
||
Object oCIDInfoItem;
|
||
pCIDInfo->lookup("Registry", &oCIDInfoItem);
|
||
if (oCIDInfoItem.isString())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"Registry", true);
|
||
oXmlWriter.WriteAttribute(L"string", AStringToWString(oCIDInfoItem.getString()->getCString()));
|
||
oXmlWriter.WriteNodeEnd(L"Registry", true, true);
|
||
}
|
||
oCIDInfoItem.free();
|
||
|
||
pCIDInfo->lookup("Ordering", &oCIDInfoItem);
|
||
if (oCIDInfoItem.isString())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"Ordering", true);
|
||
oXmlWriter.WriteAttribute(L"string", AStringToWString(oCIDInfoItem.getString()->getCString()));
|
||
oXmlWriter.WriteNodeEnd(L"Ordering", true, true);
|
||
}
|
||
oCIDInfoItem.free();
|
||
|
||
pCIDInfo->lookup("Supplement", &oCIDInfoItem);
|
||
if (oCIDInfoItem.isInt())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"Supplement", true);
|
||
oXmlWriter.WriteAttribute(L"integer", oCIDInfoItem.getInt());
|
||
oXmlWriter.WriteNodeEnd(L"Supplement", true, true);
|
||
}
|
||
oCIDInfoItem.free();
|
||
|
||
oXmlWriter.WriteNodeEnd(L"CIDSystemInfo");
|
||
}
|
||
}
|
||
oFontItem.free();
|
||
|
||
pDescFont->lookup("FontDescriptor", &oFontItem);
|
||
if (oFontItem.isDict())
|
||
{
|
||
Dict *pFontDescriptor = oFontItem.getDict();
|
||
if (NULL != pFontDescriptor)
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"FontDescriptor");
|
||
Object oItemFD;
|
||
|
||
pFontDescriptor->lookup("FontName", &oItemFD);
|
||
if (oItemFD.isName())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"FontName", true);
|
||
oXmlWriter.WriteAttribute(L"name", AStringToWString(oItemFD.getName()));
|
||
oXmlWriter.WriteNodeEnd(L"FontName", true, true);
|
||
}
|
||
oItemFD.free();
|
||
|
||
pFontDescriptor->lookup("FontStretch", &oItemFD);
|
||
if (oItemFD.isName())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"FontStretch", true);
|
||
oXmlWriter.WriteAttribute(L"name", AStringToWString(oItemFD.getName()));
|
||
oXmlWriter.WriteNodeEnd(L"FontStretch", true, true);
|
||
}
|
||
oItemFD.free();
|
||
|
||
pFontDescriptor->lookup("FontWeight", &oItemFD);
|
||
if (oItemFD.isInt())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"FontWeight", true);
|
||
oXmlWriter.WriteAttribute(L"number", oItemFD.getInt());
|
||
oXmlWriter.WriteNodeEnd(L"FontWeight", true, true);
|
||
}
|
||
oItemFD.free();
|
||
|
||
pFontDescriptor->lookup("Flags", &oItemFD);
|
||
if (oItemFD.isInt())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"Flags", true);
|
||
oXmlWriter.WriteAttribute(L"integer", oItemFD.getInt());
|
||
oXmlWriter.WriteNodeEnd(L"Flags", true, true);
|
||
}
|
||
oItemFD.free();
|
||
|
||
pFontDescriptor->lookup("FontBBox", &oItemFD);
|
||
if (oItemFD.isArray())
|
||
{
|
||
Array *pBBox = oItemFD.getArray();
|
||
if (NULL != pBBox && 4 == pBBox->getLength())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"FontBBox", true);
|
||
for (int nIndex = 0; nIndex < 4; nIndex++)
|
||
{
|
||
Object oArrayItem;
|
||
pBBox->get(nIndex, &oArrayItem);
|
||
if (oArrayItem.isInt())
|
||
{
|
||
std::wstring wsValue = L"value" + std::to_wstring(nIndex);
|
||
oXmlWriter.WriteAttribute(wsValue, oArrayItem.getInt());
|
||
}
|
||
|
||
oArrayItem.free();
|
||
}
|
||
oXmlWriter.WriteNodeEnd(L"FontBBox", true);
|
||
}
|
||
}
|
||
oItemFD.free();
|
||
|
||
pFontDescriptor->lookup("ItalicAngle", &oItemFD);
|
||
if (oItemFD.isInt())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"ItalicAngle", true);
|
||
oXmlWriter.WriteAttribute(L"number", oItemFD.getInt());
|
||
oXmlWriter.WriteNodeEnd(L"ItalicAngle", true, true);
|
||
}
|
||
oItemFD.free();
|
||
|
||
pFontDescriptor->lookup("Ascent", &oItemFD);
|
||
if (oItemFD.isInt())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"Ascent", true);
|
||
oXmlWriter.WriteAttribute(L"number", oItemFD.getInt());
|
||
oXmlWriter.WriteNodeEnd(L"Ascent", true, true);
|
||
}
|
||
oItemFD.free();
|
||
|
||
pFontDescriptor->lookup("Descent", &oItemFD);
|
||
if (oItemFD.isInt())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"Descent", true);
|
||
oXmlWriter.WriteAttribute(L"number", oItemFD.getInt());
|
||
oXmlWriter.WriteNodeEnd(L"Descent", true, true);
|
||
}
|
||
oItemFD.free();
|
||
|
||
pFontDescriptor->lookup("Leading", &oItemFD);
|
||
if (oItemFD.isInt())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"Leading", true);
|
||
oXmlWriter.WriteAttribute(L"number", oItemFD.getInt());
|
||
oXmlWriter.WriteNodeEnd(L"Leading", true, true);
|
||
}
|
||
oItemFD.free();
|
||
|
||
pFontDescriptor->lookup("CapHeight", &oItemFD);
|
||
if (oItemFD.isInt())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"CapHeight", true);
|
||
oXmlWriter.WriteAttribute(L"number", oItemFD.getInt());
|
||
oXmlWriter.WriteNodeEnd(L"CapHeight", true, true);
|
||
}
|
||
oItemFD.free();
|
||
|
||
pFontDescriptor->lookup("XHeight", &oItemFD);
|
||
if (oItemFD.isInt())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"XHeight", true);
|
||
oXmlWriter.WriteAttribute(L"number", oItemFD.getInt());
|
||
oXmlWriter.WriteNodeEnd(L"XHeight", true, true);
|
||
}
|
||
oItemFD.free();
|
||
|
||
pFontDescriptor->lookup("StemV", &oItemFD);
|
||
if (oItemFD.isInt())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"StemV", true);
|
||
oXmlWriter.WriteAttribute(L"number", oItemFD.getInt());
|
||
oXmlWriter.WriteNodeEnd(L"StemV", true, true);
|
||
}
|
||
oItemFD.free();
|
||
|
||
pFontDescriptor->lookup("StemH", &oItemFD);
|
||
if (oItemFD.isInt())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"StemH", true);
|
||
oXmlWriter.WriteAttribute(L"number", oItemFD.getInt());
|
||
oXmlWriter.WriteNodeEnd(L"StemH", true, true);
|
||
}
|
||
oItemFD.free();
|
||
|
||
pFontDescriptor->lookup("AvgWidth", &oItemFD);
|
||
if (oItemFD.isInt())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"AvgWidth", true);
|
||
oXmlWriter.WriteAttribute(L"number", oItemFD.getInt());
|
||
oXmlWriter.WriteNodeEnd(L"AvgWidth", true, true);
|
||
}
|
||
oItemFD.free();
|
||
|
||
pFontDescriptor->lookup("MaxWidth", &oItemFD);
|
||
if (oItemFD.isInt())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"MaxWidth", true);
|
||
oXmlWriter.WriteAttribute(L"number", oItemFD.getInt());
|
||
oXmlWriter.WriteNodeEnd(L"MaxWidth", true, true);
|
||
}
|
||
oItemFD.free();
|
||
|
||
pFontDescriptor->lookup("MissingWidth", &oItemFD);
|
||
if (oItemFD.isInt())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"MissingWidth", true);
|
||
oXmlWriter.WriteAttribute(L"number", oItemFD.getInt());
|
||
oXmlWriter.WriteNodeEnd(L"MissingWidth", true, true);
|
||
}
|
||
oItemFD.free();
|
||
|
||
// TODO: Тут надо реализовать чтени полей /Style, /Lang, /FD, /CIDSet
|
||
|
||
oXmlWriter.WriteNodeEnd(L"FontDescriptor");
|
||
}
|
||
}
|
||
oFontItem.free();
|
||
|
||
pDescFont->lookup("DW", &oFontItem);
|
||
if (oFontItem.isInt())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"DW", true);
|
||
oXmlWriter.WriteAttribute(L"integer", oFontItem.getInt());
|
||
oXmlWriter.WriteNodeEnd(L"DW", true, true);
|
||
}
|
||
oFontItem.free();
|
||
|
||
pDescFont->lookup("W", &oFontItem);
|
||
if (oFontItem.isArray())
|
||
{
|
||
Array *pArray = oFontItem.getArray();
|
||
if (NULL != pArray)
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"W");
|
||
|
||
for (int nIndex = 0; nIndex < pArray->getLength(); nIndex++)
|
||
{
|
||
Object oArrayItem;
|
||
pArray->get(nIndex, &oArrayItem);
|
||
if (oArrayItem.isInt())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"Int", true);
|
||
oXmlWriter.WriteAttribute(L"value", oArrayItem.getInt());
|
||
oXmlWriter.WriteNodeEnd(L"Int", true, true);
|
||
}
|
||
else if (oArrayItem.isArray())
|
||
{
|
||
Array *pWArray = oArrayItem.getArray();
|
||
if (NULL != pWArray)
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"Array");
|
||
for (int nWIndex = 0; nWIndex < pWArray->getLength(); nWIndex++)
|
||
{
|
||
Object oWArrayItem;
|
||
pWArray->get(nWIndex, &oWArrayItem);
|
||
if (oWArrayItem.isInt())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"Int", true);
|
||
oXmlWriter.WriteAttribute(L"value", oWArrayItem.getInt());
|
||
oXmlWriter.WriteNodeEnd(L"Int", true, true);
|
||
}
|
||
oWArrayItem.free();
|
||
}
|
||
oXmlWriter.WriteNodeEnd(L"Array");
|
||
}
|
||
}
|
||
oArrayItem.free();
|
||
}
|
||
|
||
oXmlWriter.WriteNodeEnd(L"W");
|
||
}
|
||
}
|
||
oFontItem.free();
|
||
|
||
pDescFont->lookup("DW2", &oFontItem);
|
||
if (oFontItem.isArray())
|
||
{
|
||
Array *pArray = oFontItem.getArray();
|
||
if (NULL != pArray && 2 == pArray->getLength())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"DW2", true);
|
||
|
||
Object oArrayItem;
|
||
pArray->get(0, &oArrayItem);
|
||
if (oArrayItem.isInt())
|
||
{
|
||
oXmlWriter.WriteAttribute(L"value0", oArrayItem.getInt());
|
||
}
|
||
oArrayItem.free();
|
||
|
||
pArray->get(1, &oArrayItem);
|
||
if (oArrayItem.isInt())
|
||
{
|
||
oXmlWriter.WriteAttribute(L"value1", oArrayItem.getInt());
|
||
}
|
||
oArrayItem.free();
|
||
|
||
oXmlWriter.WriteNodeEnd(L"DW2", true, true);
|
||
}
|
||
}
|
||
oFontItem.free();
|
||
|
||
pDescFont->lookup("W2", &oFontItem);
|
||
if (oFontItem.isArray())
|
||
{
|
||
Array *pArray = oFontItem.getArray();
|
||
if (NULL != pArray)
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"W2");
|
||
|
||
for (int nIndex = 0; nIndex < pArray->getLength(); nIndex++)
|
||
{
|
||
Object oArrayItem;
|
||
pArray->get(nIndex, &oArrayItem);
|
||
if (oArrayItem.isInt())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"Int", true);
|
||
oXmlWriter.WriteAttribute(L"value", oArrayItem.getInt());
|
||
oXmlWriter.WriteNodeEnd(L"Int", true, true);
|
||
}
|
||
else if (oArrayItem.isArray())
|
||
{
|
||
Array *pWArray = oArrayItem.getArray();
|
||
if (NULL != pWArray)
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"Array");
|
||
for (int nWIndex = 0; nWIndex < pWArray->getLength(); nWIndex++)
|
||
{
|
||
Object oWArrayItem;
|
||
pWArray->get(nWIndex, &oWArrayItem);
|
||
if (oWArrayItem.isInt())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"Int", true);
|
||
oXmlWriter.WriteAttribute(L"value", oWArrayItem.getInt());
|
||
oXmlWriter.WriteNodeEnd(L"Int", true, true);
|
||
}
|
||
oWArrayItem.free();
|
||
}
|
||
oXmlWriter.WriteNodeEnd(L"Array");
|
||
}
|
||
}
|
||
oArrayItem.free();
|
||
}
|
||
|
||
oXmlWriter.WriteNodeEnd(L"W2");
|
||
}
|
||
}
|
||
oFontItem.free();
|
||
|
||
pDescFont->lookup("CIDToGIDMap", &oFontItem);
|
||
if (oFontItem.isName())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"CIDToGIDMap", true);
|
||
oXmlWriter.WriteAttribute(L"name", AStringToWString(oFontItem.getName()));
|
||
oXmlWriter.WriteNodeEnd(L"CIDToGIDMap", true, true);
|
||
}
|
||
else if (oFontItem.isStream())
|
||
{
|
||
oXmlWriter.WriteNodeBegin(L"CIDToGIDMap");
|
||
|
||
std::string sBuffer;
|
||
oFontItem.streamReset();
|
||
int nChar = 0;
|
||
while ((nChar = oFontItem.streamGetChar()) != EOF)
|
||
{
|
||
sBuffer+=(char)nChar;
|
||
}
|
||
oFontItem.streamClose();
|
||
|
||
CBase64 oBase64;
|
||
oBase64.Encode((unsigned char*)sBuffer.c_str(), sBuffer.length());
|
||
|
||
oXmlWriter.WriteString(AStringToWString(oBase64.GetCString()));
|
||
|
||
oXmlWriter.WriteNodeEnd(L"CIDToGIDMap");
|
||
}
|
||
oFontItem.free();
|
||
|
||
|
||
oXmlWriter.WriteNodeEnd(L"DescendantFonts");
|
||
}
|
||
}
|
||
oDescFont.free();
|
||
}
|
||
}
|
||
oDictItem.free();
|
||
|
||
oXmlWriter.WriteNodeEnd(L"Type0");
|
||
oXmlWriter.WriteNodeEnd(L"PDF-resources");
|
||
}
|
||
oFontObject.free();
|
||
|
||
oXmlWriter.SaveToFile(wsEncodingPath);
|
||
}
|
||
}
|
||
*/
|
||
|
||
// Обрежем индекс у FontName, если он есть
|
||
if (wsFontName.empty())
|
||
wsFontName = wsFontBaseName;
|
||
if (wsFontName.length() > 7)
|
||
{
|
||
bool bIsIndex = true;
|
||
if ('+' != wsFontName.at(6))
|
||
bIsIndex = false;
|
||
|
||
if (bIsIndex)
|
||
{
|
||
for (int nIndex = 0; nIndex < 6; nIndex++)
|
||
{
|
||
int nChar = wsFontName.at(nIndex);
|
||
if (nChar < 'A' || nChar > 'Z')
|
||
{
|
||
bIsIndex = false;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (bIsIndex)
|
||
{
|
||
wsFontName.erase(0, 7);
|
||
}
|
||
}
|
||
|
||
pEntry->wsFilePath = wsFileName;
|
||
pEntry->wsFontName = wsFontName;
|
||
pEntry->pCodeToGID = pCodeToGID;
|
||
pEntry->pCodeToUnicode = pCodeToUnicode;
|
||
pEntry->unLenGID = (unsigned int)nLen;
|
||
pEntry->unLenUnicode = (unsigned int)nToUnicodeLen;
|
||
pEntry->bAvailable = true;
|
||
}
|
||
else if (NULL != pEntry)
|
||
{
|
||
wsFileName = pEntry->wsFilePath;
|
||
wsFontName = pEntry->wsFontName;
|
||
}
|
||
}
|
||
void RendererOutputDev::updateFont(GfxState *pGState)
|
||
{
|
||
// Проверяем наличие списка со шрифтами
|
||
if (NULL == m_pFontList)
|
||
return;
|
||
|
||
GfxFont *pFont = pGState->getFont();
|
||
if (NULL == pFont)
|
||
return;
|
||
|
||
m_pRenderer->put_FontSize(pGState->getFontSize());
|
||
|
||
std::wstring wsFileName = L"";
|
||
std::wstring wsFontName = L"";
|
||
GetFont(m_pXref, m_pFontManager, m_pFontList, pFont, wsFileName, wsFontName);
|
||
|
||
if (L"" != wsFileName)
|
||
{
|
||
m_pRenderer->put_FontPath(wsFileName);
|
||
m_pRenderer->put_FontName(wsFontName);
|
||
}
|
||
}
|
||
void RendererOutputDev::stroke(GfxState *pGState)
|
||
{
|
||
if (m_bDrawOnlyText)
|
||
return;
|
||
|
||
DoPath(pGState, pGState->getPath(), pGState->getPageHeight(), pGState->getCTM());
|
||
m_pRenderer->DrawPath(c_nStroke);
|
||
|
||
m_pRenderer->EndCommand(c_nPathType);
|
||
}
|
||
void RendererOutputDev::fill(GfxState *pGState)
|
||
{
|
||
if (m_bDrawOnlyText)
|
||
return;
|
||
|
||
DoPath(pGState, pGState->getPath(), pGState->getPageHeight(), pGState->getCTM());
|
||
m_pRenderer->DrawPath(c_nWindingFillMode);
|
||
m_pRenderer->EndCommand(c_nPathType);
|
||
}
|
||
void RendererOutputDev::eoFill(GfxState *pGState)
|
||
{
|
||
if (m_bDrawOnlyText)
|
||
return;
|
||
|
||
DoPath(pGState, pGState->getPath(), pGState->getPageHeight(), pGState->getCTM());
|
||
m_pRenderer->DrawPath(c_nEvenOddFillMode);
|
||
|
||
m_pRenderer->EndCommand(c_nPathType);
|
||
}
|
||
void RendererOutputDev::FillStroke(GfxState *pGState)
|
||
{
|
||
if (m_bDrawOnlyText)
|
||
return;
|
||
|
||
DoPath(pGState, pGState->getPath(), pGState->getPageHeight(), pGState->getCTM());
|
||
m_pRenderer->DrawPath(c_nStroke | c_nWindingFillMode);
|
||
|
||
m_pRenderer->EndCommand(c_nPathType);
|
||
}
|
||
void RendererOutputDev::EoFillStroke(GfxState *pGState)
|
||
{
|
||
if (m_bDrawOnlyText)
|
||
return;
|
||
|
||
DoPath(pGState, pGState->getPath(), pGState->getPageHeight(), pGState->getCTM());
|
||
m_pRenderer->DrawPath(c_nStroke | c_nEvenOddFillMode);
|
||
|
||
m_pRenderer->EndCommand(c_nPathType);
|
||
}
|
||
void RendererOutputDev::tilingPatternFill(GfxState *pGState, Gfx *gfx, Object *pStream, int nPaintType, int nTilingType, Dict *pResourcesDict, double *matrix, double *pBBox,
|
||
int nX0, int nY0, int nX1, int nY1, double dXStep, double dYStep)
|
||
{
|
||
if (m_bDrawOnlyText)
|
||
return;
|
||
|
||
if (nX1 - nX0 == 1 && nY1 - nY0 == 1) // Одно изображение, tilingPattern не требуется
|
||
{
|
||
gfx->drawForm(pStream, pResourcesDict, matrix, pBBox);
|
||
return;
|
||
}
|
||
|
||
if (abs(pBBox[2] - pBBox[0] - dXStep) > 0.001 || abs(pBBox[3] - pBBox[1] - dYStep) > 0.001)
|
||
return;
|
||
|
||
double dWidth, dHeight, dDpiX, dDpiY;
|
||
m_pRenderer->get_Width(&dWidth);
|
||
m_pRenderer->get_Height(&dHeight);
|
||
m_pRenderer->get_DpiX(&dDpiX);
|
||
m_pRenderer->get_DpiY(&dDpiY);
|
||
dWidth = dWidth * dDpiX / 25.4;
|
||
dHeight = dHeight * dDpiY / 25.4;
|
||
|
||
dWidth *= (dXStep / pGState->getPageWidth());
|
||
dHeight *= (dYStep / pGState->getPageHeight());
|
||
|
||
int nWidth = round(dWidth);
|
||
int nHeight = round(dHeight);
|
||
|
||
BYTE* pBgraData = new BYTE[nWidth * nHeight * 4];
|
||
memset(pBgraData, 0, nWidth * nHeight * 4);
|
||
|
||
CBgraFrame* pFrame = new CBgraFrame();
|
||
pFrame->put_Data(pBgraData);
|
||
pFrame->put_Width(nWidth);
|
||
pFrame->put_Height(nHeight);
|
||
pFrame->put_Stride(-4 * nWidth);
|
||
|
||
NSGraphics::IGraphicsRenderer* pRenderer = NSGraphics::Create();
|
||
pRenderer->SetFontManager(m_pFontManager);
|
||
pRenderer->CreateFromBgraFrame(pFrame);
|
||
pRenderer->put_Width (dWidth * 25.4 / 72.0);
|
||
pRenderer->put_Height(dHeight * 25.4 / 72.0);
|
||
pRenderer->CommandLong(c_nPenWidth0As1px, 1);
|
||
pRenderer->SetSwapRGB(false);
|
||
|
||
PDFRectangle box;
|
||
box.x1 = pBBox[0];
|
||
box.y1 = pBBox[1];
|
||
box.x2 = pBBox[2];
|
||
box.y2 = pBBox[3];
|
||
|
||
RendererOutputDev* m_pRendererOut = new RendererOutputDev(pRenderer, m_pFontManager, m_pFontList);
|
||
m_pRendererOut->NewPDF(gfx->getDoc()->getXRef());
|
||
|
||
Gfx* m_gfx = new Gfx(gfx->getDoc(), m_pRendererOut, -1, pResourcesDict, dDpiX, dDpiY, &box, NULL, 0);
|
||
m_gfx->display(pStream);
|
||
|
||
pFrame->ClearNoAttack();
|
||
RELEASEOBJECT(m_gfx);
|
||
RELEASEOBJECT(pRenderer);
|
||
RELEASEOBJECT(m_pRendererOut);
|
||
RELEASEOBJECT(pFrame);
|
||
|
||
Aggplus::CImage* oImage = new Aggplus::CImage();
|
||
oImage->Create(pBgraData, nWidth, nHeight, 4 * nWidth);
|
||
|
||
double xMin, yMin, xMax, yMax;
|
||
Transform(matrix, pBBox[0], pBBox[1], &xMin, &yMin);
|
||
Transform(matrix, pBBox[2], pBBox[3], &xMax, &yMax);
|
||
double dW = xMax - xMin;
|
||
double dH = yMax - yMin;
|
||
xMin += (double)nX0 * dW;
|
||
xMax += (double)nX1 * dW;
|
||
yMin += (double)nY0 * dH;
|
||
yMax += (double)nY1 * dH;
|
||
pGState->moveTo(xMin, yMin);
|
||
pGState->lineTo(xMax, yMin);
|
||
pGState->lineTo(xMax, yMax);
|
||
pGState->lineTo(xMin, yMax);
|
||
pGState->closePath();
|
||
|
||
DoPath(pGState, pGState->getPath(), pGState->getPageHeight(), pGState->getCTM());
|
||
|
||
long brush;
|
||
m_pRenderer->get_BrushType(&brush);
|
||
|
||
int alpha = pGState->getFillOpacity() * 255;
|
||
m_pRenderer->put_BrushType(c_BrushTypeTexture);
|
||
m_pRenderer->put_BrushTextureImage(oImage);
|
||
m_pRenderer->put_BrushTextureMode(c_BrushTextureModeTile);
|
||
m_pRenderer->put_BrushTextureAlpha(alpha);
|
||
m_pRenderer->BeginCommand(c_nImageType);
|
||
|
||
m_pRenderer->DrawPath(c_nWindingFillMode);
|
||
|
||
m_pRenderer->PathCommandEnd();
|
||
m_pRenderer->EndCommand(c_nImageType);
|
||
m_pRenderer->put_BrushType(brush);
|
||
m_pRenderer->put_BrushTextureImage(NULL);
|
||
|
||
pGState->clearPath();
|
||
RELEASEINTERFACE(oImage);
|
||
}
|
||
void RendererOutputDev::StartTilingFill(GfxState *pGState)
|
||
{
|
||
if (m_bDrawOnlyText)
|
||
return;
|
||
|
||
m_pRenderer->BeginCommand(c_nComplexFigureType);
|
||
m_bTiling = true;
|
||
}
|
||
void RendererOutputDev::EndTilingFill()
|
||
{
|
||
if (m_bDrawOnlyText)
|
||
return;
|
||
|
||
m_pRenderer->EndCommand(c_nComplexFigureType);
|
||
m_bTiling = false;
|
||
}
|
||
|
||
GBool RendererOutputDev::shadedFill(GfxState *pGState, GfxShading *pShading)
|
||
{
|
||
double x0, y0, x1, x2, y1, y2, r1, r2;
|
||
double xmin, xmax, ymin, ymax, r;
|
||
double *matrix;
|
||
|
||
int nTriangles = 0, nPatches = 0;
|
||
switch (pShading->getType())
|
||
{
|
||
case 1:
|
||
((GfxFunctionShading *)pShading)->getDomain(&x0, &y0, &x1, &y1);
|
||
matrix = ((GfxFunctionShading *)pShading)->getMatrix();
|
||
pGState->moveTo(x0 * matrix[0] + y0 * matrix[2] + matrix[4],
|
||
x0 * matrix[1] + y0 * matrix[3] + matrix[5]);
|
||
pGState->lineTo(x1 * matrix[0] + y0 * matrix[2] + matrix[4],
|
||
x1 * matrix[1] + y0 * matrix[3] + matrix[5]);
|
||
pGState->lineTo(x1 * matrix[0] + y1 * matrix[2] + matrix[4],
|
||
x1 * matrix[1] + y1 * matrix[3] + matrix[5]);
|
||
pGState->lineTo(x0 * matrix[0] + y1 * matrix[2] + matrix[4],
|
||
x0 * matrix[1] + y1 * matrix[3] + matrix[5]);
|
||
pGState->closePath();
|
||
FunctionShadedFill(pGState, (GfxFunctionShading *) pShading);
|
||
return true;
|
||
case 2:
|
||
pGState->getUserClipBBox(&xmin, &ymin, &xmax, &ymax);
|
||
//pGState->clearPath();
|
||
|
||
|
||
pGState->moveTo(xmin, ymin);
|
||
pGState->lineTo(xmin, ymax);
|
||
pGState->lineTo(xmax, ymax);
|
||
pGState->lineTo(xmax, ymin);
|
||
pGState->closePath();
|
||
AxialShadedFill(pGState, (GfxAxialShading* )pShading);
|
||
return true;
|
||
case 3:
|
||
((GfxRadialShading *)pShading)->getCoords(&x1, &y1, &r1, &x2, &y2, &r2);
|
||
|
||
r = std::max(r1,r2);
|
||
xmin = std::min(x1, x2) - 2 * r;
|
||
ymin = std::min(y1, y2) - 2 * r;
|
||
xmax = std::max(x1, x2) + 2 * r;
|
||
ymax = std::max(y1, y2) + 2 * r;
|
||
|
||
pGState->moveTo(xmin, ymin);
|
||
pGState->lineTo(xmin, ymax);
|
||
pGState->lineTo(xmax, ymax);
|
||
pGState->lineTo(xmax, ymin);
|
||
pGState->closePath();
|
||
RadialShadedFill(pGState, (GfxRadialShading*) pShading);
|
||
return true;
|
||
case 4:
|
||
case 5:
|
||
nTriangles = ((GfxGouraudTriangleShading *) pShading)->getNTriangles();
|
||
|
||
for (int i = 0; i < nTriangles; i++) {
|
||
int nComps = ((GfxGouraudTriangleShading *) pShading)->getNComps();
|
||
double x1,x2,x3,y1,y2,y3;
|
||
double *c1 = new double[nComps];
|
||
double *c2 = new double[nComps];
|
||
double *c3 = new double[nComps];
|
||
|
||
GfxColor col1, col2, col3;
|
||
|
||
((GfxGouraudTriangleShading *) pShading)->getTriangle(i, &x1, &y1, c1, &x2, &y2, c2, &x3, &y3, c3);
|
||
((GfxGouraudTriangleShading *) pShading)->getColor(c1, &col1);
|
||
((GfxGouraudTriangleShading *) pShading)->getColor(c2, &col2);
|
||
((GfxGouraudTriangleShading *) pShading)->getColor(c3, &col3);
|
||
|
||
pGState->clearPath();
|
||
|
||
pGState->moveTo(x1, y1);
|
||
pGState->lineTo(x2, y2);
|
||
pGState->lineTo(x3, y3);
|
||
|
||
pGState->closePath();
|
||
|
||
GouraundTriangleFill(pGState, {&col1, &col2, &col3}, {{x1,y1},{x2,y2},{x3,y3}});
|
||
delete[] c1;
|
||
delete[] c2;
|
||
delete[] c3;
|
||
}
|
||
return true;
|
||
case 6:
|
||
case 7:
|
||
int nComps = ((GfxPatchMeshShading *) pShading)->getNComps();
|
||
int nPatches = ((GfxPatchMeshShading *) pShading)->getNPatches();
|
||
for (int i = 0; i < nPatches; i++) {
|
||
GfxPatch *patch = ((GfxPatchMeshShading *) pShading)->getPatch(i);
|
||
pGState->clearPath();
|
||
pGState->moveTo(patch->x[0][0], patch->y[0][0]);
|
||
pGState->curveTo(patch->x[0][1], patch->y[0][1],
|
||
patch->x[0][2], patch->y[0][2],
|
||
patch->x[0][3], patch->y[0][3]);
|
||
pGState->curveTo(patch->x[1][3], patch->y[1][3],
|
||
patch->x[2][3], patch->y[2][3],
|
||
patch->x[3][3], patch->y[3][3]);
|
||
pGState->curveTo(patch->x[3][2], patch->y[3][2],
|
||
patch->x[3][1], patch->y[3][1],
|
||
patch->x[3][0], patch->y[3][0]);
|
||
pGState->curveTo(patch->x[2][0], patch->y[2][0],
|
||
patch->x[1][0], patch->y[1][0],
|
||
patch->x[0][0], patch->y[0][0]);
|
||
pGState->closePath();
|
||
PatchMeshFill(pGState, patch, (GfxPatchMeshShading *) pShading);
|
||
}
|
||
return true;
|
||
|
||
}
|
||
return false;
|
||
}
|
||
|
||
bool RendererOutputDev::FunctionShadedFill(GfxState *pGState, GfxFunctionShading *pShading)
|
||
{
|
||
if (m_bDrawOnlyText)
|
||
return true;
|
||
|
||
DoPath(pGState, pGState->getPath(), pGState->getPageHeight(), pGState->getCTM());
|
||
long brush;
|
||
int alpha = pGState->getFillOpacity() * 255;
|
||
m_pRenderer->get_BrushType(&brush);
|
||
m_pRenderer->put_BrushType(c_BrushTypeMyTestGradient);
|
||
double x1,x2,y1,y2;
|
||
pShading->getDomain(&x1, &y1, &x2, &y2);
|
||
std::vector<float> mapping(6);
|
||
for (int i = 0; i < 6; i++)
|
||
{
|
||
mapping[i] = PDFCoordsToMM(pShading->getMatrix()[i]);
|
||
}
|
||
NSStructures::GradientInfo info = NSStructures::GInfoConstructor::get_functional(x1, x2, y1, y2, mapping);
|
||
|
||
float cur_x = 0, cur_y = 0;
|
||
float delta_x = (x2 - x1) / info.shading.function.get_resolution();
|
||
float delta_y = (y2 - y1) / info.shading.function.get_resolution();
|
||
|
||
GfxColorSpace *ColorSpace = pShading->getColorSpace();
|
||
|
||
for (size_t i = 0; i < info.shading.function.get_resolution(); i++)
|
||
{
|
||
cur_x = 0;
|
||
for (size_t j = 0; j < info.shading.function.get_resolution(); j++)
|
||
{
|
||
GfxColor c;
|
||
pShading->getColor(cur_x, cur_y, &c);
|
||
|
||
GfxRGB draw_color;
|
||
// RenderingIntent in this case does nothing but it's an obligatory arguments
|
||
ColorSpace->getRGB(&c, &draw_color, gfxRenderingIntentAbsoluteColorimetric);
|
||
info.shading.function.set_color(j, i, colToByte(draw_color.b),
|
||
colToByte(draw_color.g), colToByte(draw_color.r), alpha);
|
||
cur_x += delta_x;
|
||
}
|
||
cur_y += delta_y;
|
||
}
|
||
|
||
if (NSGraphics::IGraphicsRenderer* GRenderer = dynamic_cast<NSGraphics::IGraphicsRenderer*>(m_pRenderer))
|
||
{
|
||
GRenderer->put_BrushGradInfo(info);
|
||
m_pRenderer->DrawPath(c_nWindingFillMode);
|
||
}
|
||
|
||
m_pRenderer->EndCommand(c_nPathType);
|
||
m_pRenderer->put_BrushType(brush);
|
||
pGState->clearPath();
|
||
return true;
|
||
}
|
||
bool RendererOutputDev::AxialShadedFill(GfxState *pGState, GfxAxialShading *pShading)
|
||
{
|
||
if (m_bDrawOnlyText)
|
||
return true;
|
||
|
||
double x1, x2, y1, y2;
|
||
double t0, t1;
|
||
|
||
long brush;
|
||
m_pRenderer->get_BrushType(&brush);
|
||
|
||
/*
|
||
IRenderer* pLastRenderer = m_pRenderer;
|
||
BYTE* pBgraData = NULL;
|
||
CBgraFrame* pFrame = NULL;
|
||
double dpi, dWidth, dHeight;
|
||
m_pRenderer->get_DpiX(&dpi);
|
||
// TODO что если размеры не равны размерам m_pSoftMask
|
||
pLastRenderer->get_Width(&dWidth);
|
||
pLastRenderer->get_Height(&dHeight);
|
||
int nWidth = dWidth * 96 / dpi;
|
||
int nHeight = dHeight * 96 / dpi;
|
||
if (m_pSoftMask)
|
||
{
|
||
NSGraphics::IGraphicsRenderer* pRenderer = NSGraphics::Create();
|
||
m_pRenderer = pRenderer;
|
||
|
||
pBgraData = new BYTE[nWidth * nHeight * 4];
|
||
memset(pBgraData, 0xff, nWidth * nHeight * 4);
|
||
|
||
pFrame = new CBgraFrame();
|
||
pFrame->put_Data(pBgraData);
|
||
pFrame->put_Width(nWidth);
|
||
pFrame->put_Height(nHeight);
|
||
// TODO bIsFlip = true ~ 4
|
||
pFrame->put_Stride(-4 * nWidth);
|
||
|
||
pRenderer->CreateFromBgraFrame(pFrame);
|
||
// TODO проверить
|
||
pRenderer->SetSwapRGB(true);
|
||
|
||
pRenderer->put_Width(dWidth);
|
||
pRenderer->put_Height(dHeight);
|
||
}
|
||
*/
|
||
|
||
DoPath(pGState, pGState->getPath(), pGState->getPageHeight(), pGState->getCTM());
|
||
|
||
double dAlphaKoef = pGState->getFillOpacity();
|
||
m_pRenderer->put_BrushType(c_BrushTypePathNewLinearGradient);
|
||
|
||
pShading->getCoords(&x1, &y1, &x2, &y2);
|
||
t0 = pShading->getDomain0();
|
||
t1 = pShading->getDomain1();
|
||
|
||
x1 = PDFCoordsToMM(x1);
|
||
x2 = PDFCoordsToMM(x2);
|
||
y1 = PDFCoordsToMM(y1);
|
||
y2 = PDFCoordsToMM(y2);
|
||
|
||
NSStructures::GradientInfo info = NSStructures::GInfoConstructor::get_linear({x1, y1}, {x2, y2}, t0, t1,
|
||
pShading->getExtend0(), pShading->getExtend1());
|
||
|
||
GfxColorSpace *ColorSpace = pShading->getColorSpace();
|
||
float delta = (t1 - t0) / info.shading.function.get_resolution();
|
||
float t = t0;
|
||
for (size_t i = 0; i < info.shading.function.get_resolution(); i++)
|
||
{
|
||
GfxColor c;
|
||
pShading->getColor(t, &c);
|
||
|
||
GfxRGB draw_color;
|
||
GfxGray draw_alpha;
|
||
|
||
// RenderingIntent in this case does nothing but it's an obligatory arguments
|
||
ColorSpace->getRGB(&c, &draw_color, gfxRenderingIntentAbsoluteColorimetric);
|
||
ColorSpace->getGray(&c, &draw_alpha, gfxRenderingIntentAbsoluteColorimetric);
|
||
info.shading.function.set_color(i, colToByte(draw_color.b),
|
||
colToByte(draw_color.g), colToByte(draw_color.r), dAlphaKoef * 255.0);
|
||
t+=delta;
|
||
}
|
||
|
||
if (NSGraphics::IGraphicsRenderer* GRenderer = dynamic_cast<NSGraphics::IGraphicsRenderer*>(m_pRenderer))
|
||
{
|
||
GRenderer->put_BrushGradInfo(info);
|
||
m_pRenderer->DrawPath(c_nWindingFillMode);
|
||
}
|
||
|
||
m_pRenderer->EndCommand(c_nPathType);
|
||
|
||
/*
|
||
if (m_pSoftMask)
|
||
{
|
||
for (int nY = m_nSoftMaskHeight - 1; nY >= 0; nY--)
|
||
{
|
||
int nIndex = 4 * nY * m_nSoftMaskWidth;
|
||
for (int nX = 0; nX < m_nSoftMaskWidth; nX++)
|
||
{
|
||
if (m_pSoftMask[nIndex + 3])
|
||
{
|
||
m_pSoftMask[nIndex + 0] = pBgraData[nIndex + 0];
|
||
m_pSoftMask[nIndex + 1] = pBgraData[nIndex + 1];
|
||
m_pSoftMask[nIndex + 2] = pBgraData[nIndex + 2];
|
||
}
|
||
nIndex += 4;
|
||
}
|
||
}
|
||
|
||
pFrame->SaveFile(NSFile::GetProcessDirectory() + L"/res3.png", _CXIMAGE_FORMAT_PNG);
|
||
RELEASEOBJECT(m_pRenderer);
|
||
m_pRenderer = pLastRenderer;
|
||
|
||
Aggplus::CImage oImage;
|
||
oImage.Create(m_pSoftMask, m_nSoftMaskWidth, m_nSoftMaskHeight, -4 * m_nSoftMaskWidth, true);
|
||
|
||
double arrMatrix[6];
|
||
double* pCTM = m_pCTMSoftMask;
|
||
|
||
// Исходное предобразование
|
||
// |1 0 0| |pCTM[0] pCTM[1] 0|
|
||
// arrMattrix = |0 -1 0| * |pCTM[2] pCTM[3] 0|
|
||
// |0 1 1| |pCTM[4] pCTM[5] 1|
|
||
|
||
arrMatrix[0] = pCTM[0];
|
||
arrMatrix[1] = -pCTM[1];
|
||
arrMatrix[2] = -pCTM[2];
|
||
arrMatrix[3] = -(-pCTM[3]);
|
||
arrMatrix[4] = pCTM[2] + pCTM[4];
|
||
arrMatrix[5] = -(pCTM[3] + pCTM[5]) + pGState->getPageHeight();
|
||
|
||
double dShiftX = 0, dShiftY = 0;
|
||
DoTransform(arrMatrix, &dShiftX, &dShiftY, true);
|
||
m_pRenderer->DrawImage(&oImage, 0 + dShiftX, 0 + dShiftY, PDFCoordsToMM(1), PDFCoordsToMM(1));
|
||
oImage.SaveFile(NSFile::GetProcessDirectory() + L"/res2.png", _CXIMAGE_FORMAT_PNG);
|
||
}
|
||
*/
|
||
|
||
m_pRenderer->put_BrushType(brush);
|
||
|
||
pGState->clearPath();
|
||
return true;
|
||
}
|
||
bool RendererOutputDev::RadialShadedFill(GfxState *pGState, GfxRadialShading *pShading)
|
||
{
|
||
if (m_bDrawOnlyText)
|
||
return true;
|
||
|
||
DoPath(pGState, pGState->getPath(), pGState->getPageHeight(), pGState->getCTM());
|
||
|
||
long brush;
|
||
int alpha = pGState->getFillOpacity() * 255;
|
||
m_pRenderer->get_BrushType(&brush);
|
||
m_pRenderer->put_BrushType(c_BrushTypePathRadialGradient);
|
||
|
||
double x1, x2, y1, y2, r1, r2;
|
||
double t0, t1;
|
||
pShading->getCoords(&x1, &y1, &r1, &x2, &y2, &r2);
|
||
t0 = pShading->getDomain0();
|
||
t1 = pShading->getDomain1();
|
||
|
||
x1 = PDFCoordsToMM(x1);
|
||
x2 = PDFCoordsToMM(x2);
|
||
y1 = PDFCoordsToMM(y1);
|
||
y2 = PDFCoordsToMM(y2);
|
||
r1 = PDFCoordsToMM(r1);
|
||
r2 = PDFCoordsToMM(r2);
|
||
|
||
NSStructures::GradientInfo info = NSStructures::GInfoConstructor::get_radial({x1, y1}, {x2, y2}, r1, r2,
|
||
t0, t1, pShading->getExtend0(), pShading->getExtend1());
|
||
|
||
GfxColorSpace *ColorSpace = pShading->getColorSpace();;
|
||
float delta = (t1 - t0) / info.shading.function.get_resolution();
|
||
float t = t0;
|
||
for (size_t i = 0; i < info.shading.function.get_resolution(); i++)
|
||
{
|
||
GfxColor c;
|
||
pShading->getColor(t, &c);
|
||
GfxRGB draw_color;
|
||
// RenderingIntent in this case does nothing but it's an obligatory arguments
|
||
ColorSpace->getRGB(&c, &draw_color, gfxRenderingIntentAbsoluteColorimetric);
|
||
info.shading.function.set_color(i, colToByte(draw_color.b),
|
||
colToByte(draw_color.g), colToByte(draw_color.r), alpha);
|
||
t+=delta;
|
||
}
|
||
|
||
if (NSGraphics::IGraphicsRenderer* GRenderer = dynamic_cast<NSGraphics::IGraphicsRenderer*>(m_pRenderer))
|
||
{
|
||
GRenderer->put_BrushGradInfo(info);
|
||
m_pRenderer->DrawPath(c_nWindingFillMode);
|
||
}
|
||
m_pRenderer->EndCommand(c_nPathType);
|
||
m_pRenderer->put_BrushType(brush);
|
||
pGState->clearPath();
|
||
return true;
|
||
}
|
||
bool RendererOutputDev::GouraundTriangleFill(GfxState *pGState, const std::vector<GfxColor*> &colors, const std::vector<NSStructures::Point> &points)
|
||
{
|
||
if (m_bDrawOnlyText)
|
||
return true;
|
||
|
||
DoPath(pGState, pGState->getPath(), pGState->getPageHeight(), pGState->getCTM());
|
||
|
||
long brush;
|
||
int alpha = pGState->getFillOpacity() * 255;
|
||
m_pRenderer->get_BrushType(&brush);
|
||
m_pRenderer->put_BrushType(c_BrushTypeTriagnleMeshGradient);
|
||
|
||
std::vector<NSStructures::Point> pixel_points;
|
||
std::vector<agg::rgba8> rgba8_colors;
|
||
GfxCalRGBColorSpace ColorSpace;
|
||
|
||
for (int i = 0; i < 3; i++)
|
||
{
|
||
GfxColor c = *colors[i];
|
||
GfxRGB draw_color;
|
||
// RenderingIntent in this case does nothing but it's an obligatory arguments
|
||
ColorSpace.getRGB(&c, &draw_color, gfxRenderingIntentAbsoluteColorimetric);
|
||
rgba8_colors.push_back({colToByte(draw_color.b), colToByte(draw_color.g), colToByte(draw_color.r), (unsigned)alpha});
|
||
double x = points[i].x;
|
||
double y = points[i].y;
|
||
x = PDFCoordsToMM(x);
|
||
y = PDFCoordsToMM(y);
|
||
pixel_points.push_back({x, y});
|
||
}
|
||
|
||
NSStructures::GradientInfo info = NSStructures::GInfoConstructor::get_triangle(pixel_points, rgba8_colors, {}, false);
|
||
|
||
if (NSGraphics::IGraphicsRenderer* GRenderer = dynamic_cast<NSGraphics::IGraphicsRenderer*>(m_pRenderer))
|
||
{
|
||
GRenderer->put_BrushGradInfo(info);
|
||
m_pRenderer->DrawPath(c_nWindingFillMode);
|
||
}
|
||
pGState->clearPath();
|
||
m_pRenderer->EndCommand(c_nPathType);
|
||
m_pRenderer->put_BrushType(brush);
|
||
return true;
|
||
}
|
||
bool RendererOutputDev::PatchMeshFill(GfxState *pGState, GfxPatch *patch, GfxPatchMeshShading *pShading)
|
||
{
|
||
if (m_bDrawOnlyText)
|
||
return true;
|
||
|
||
DoPath(pGState, pGState->getPath(), pGState->getPageHeight(), pGState->getCTM());
|
||
|
||
long brush;
|
||
int alpha = pGState->getFillOpacity() * 255;
|
||
m_pRenderer->get_BrushType(&brush);
|
||
m_pRenderer->put_BrushType(c_BrushTypeTensorCurveGradient);
|
||
|
||
std::vector<std::vector<NSStructures::Point>> points(4, std::vector<NSStructures::Point>(4));
|
||
for (int i = 0; i < 4; i++)
|
||
{
|
||
for (int j = 0; j < 4; j++)
|
||
{
|
||
double x = patch->x[i][j];
|
||
double y = patch->y[i][j];
|
||
|
||
x = PDFCoordsToMM(x);
|
||
y = PDFCoordsToMM(y);
|
||
points[i][j].x = x;
|
||
points[i][j].y = y;
|
||
}
|
||
}
|
||
std::vector<std::vector<agg::rgba8>> colors(2, std::vector<agg::rgba8>(2));
|
||
GfxDeviceRGBColorSpace ColorSpace;
|
||
for (int i = 0; i < 2; i ++)
|
||
{
|
||
for (int j = 0; j < 2; j++)
|
||
{
|
||
GfxColor c;
|
||
pShading->getColor(patch->color[i][j], &c);
|
||
GfxRGB draw_color;
|
||
// RenderingIntent in this case does nothing but it's an obligatory arguments
|
||
ColorSpace.getRGB(&c, &draw_color, gfxRenderingIntentAbsoluteColorimetric);
|
||
colors[j][i] = {colToByte(draw_color.b), colToByte(draw_color.g), colToByte(draw_color.r), (unsigned)alpha};
|
||
}
|
||
}
|
||
NSStructures::GradientInfo info = NSStructures::GInfoConstructor::get_tensor_curve(points,
|
||
{},
|
||
colors,
|
||
false
|
||
);
|
||
|
||
if (NSGraphics::IGraphicsRenderer* GRenderer = dynamic_cast<NSGraphics::IGraphicsRenderer*>(m_pRenderer))
|
||
{
|
||
GRenderer->put_BrushGradInfo(info);
|
||
m_pRenderer->DrawPath(c_nWindingFillMode);
|
||
}
|
||
|
||
m_pRenderer->EndCommand(c_nPathType);
|
||
m_pRenderer->put_BrushType(brush);
|
||
pGState->clearPath();
|
||
return true;
|
||
}
|
||
void RendererOutputDev::StartShadedFill(GfxState *pGState)
|
||
{
|
||
if (m_bDrawOnlyText)
|
||
return;
|
||
|
||
m_pRenderer->BeginCommand(c_nComplexFigureType);
|
||
}
|
||
void RendererOutputDev::EndShadedFill()
|
||
{
|
||
if (m_bDrawOnlyText)
|
||
return;
|
||
|
||
m_pRenderer->EndCommand(c_nComplexFigureType);
|
||
}
|
||
void RendererOutputDev::StartTilingFillIteration()
|
||
{
|
||
if (m_bDrawOnlyText)
|
||
return;
|
||
|
||
m_pRenderer->BeginCommand(c_nPDFTilingFillIteration);
|
||
}
|
||
void RendererOutputDev::EndTilingFillIteration()
|
||
{
|
||
if (m_bDrawOnlyText)
|
||
return;
|
||
|
||
m_pRenderer->EndCommand(c_nPDFTilingFillIteration);
|
||
}
|
||
void RendererOutputDev::StartSimpleTilingFill(GfxState *pGState, int nX0, int nY0, int nX1, int nY1, double dStepX, double dStepY, double dXMin, double dYMin, double dXMax, double dYMax, double* pMatrix)
|
||
{
|
||
if (m_bDrawOnlyText)
|
||
return;
|
||
|
||
this->clipAttack(pGState);
|
||
|
||
m_pRenderer->BeginCommand(c_nPDFTilingFill);
|
||
|
||
CXmlWriter oWriter;
|
||
oWriter.WriteNodeBegin(L"htmltiling", true);
|
||
oWriter.WriteAttribute(L"x", nX0);
|
||
oWriter.WriteAttribute(L"y", nY0);
|
||
oWriter.WriteAttribute(L"countx", nX1 - nX0);
|
||
oWriter.WriteAttribute(L"county", nY1 - nY0);
|
||
oWriter.WriteAttribute(L"stepx", dStepX);
|
||
oWriter.WriteAttribute(L"stepy", dStepY);
|
||
oWriter.WriteNodeEnd(L"htmltiling", true, false);
|
||
|
||
oWriter.WriteNodeBegin(L"bbox", true);
|
||
oWriter.WriteAttribute(L"x", dXMin);
|
||
oWriter.WriteAttribute(L"y", dYMin);
|
||
oWriter.WriteAttribute(L"r", dXMax);
|
||
oWriter.WriteAttribute(L"b", dYMax);
|
||
oWriter.WriteNodeEnd(L"bbox", true, true);
|
||
|
||
oWriter.WriteNodeBegin(L"transform", true);
|
||
oWriter.WriteAttribute(L"m1", pMatrix[0]);
|
||
oWriter.WriteAttribute(L"m2", pMatrix[1]);
|
||
oWriter.WriteAttribute(L"m3", pMatrix[2]);
|
||
oWriter.WriteAttribute(L"m4", pMatrix[3]);
|
||
oWriter.WriteAttribute(L"m5", pMatrix[4]);
|
||
oWriter.WriteAttribute(L"m6", pMatrix[5]);
|
||
oWriter.WriteNodeEnd(L"transform", true, true);
|
||
|
||
oWriter.WriteNodeEnd(L"htmltiling", false);
|
||
// TODO: m_pRenderer->SetAdditionalParam(L"TilingHtmlPattern", oWriter.GetXmlString());
|
||
}
|
||
void RendererOutputDev::EndSimpleTilingFill()
|
||
{
|
||
if (m_bDrawOnlyText)
|
||
return;
|
||
|
||
m_pRenderer->EndCommand(c_nPDFTilingFill);
|
||
}
|
||
void RendererOutputDev::clip(GfxState *pGState)
|
||
{
|
||
if (m_bDrawOnlyText)
|
||
return;
|
||
|
||
if (m_sClip.empty())
|
||
{
|
||
m_sClip.push_back(GfxClip());
|
||
}
|
||
m_sClip.back().AddPath(pGState->getPath(), pGState->getCTM(), false);
|
||
m_bClipChanged = true;
|
||
updateClip(pGState);
|
||
}
|
||
void RendererOutputDev::eoClip(GfxState *pGState)
|
||
{
|
||
if (m_bDrawOnlyText)
|
||
return;
|
||
|
||
if (m_sClip.empty())
|
||
{
|
||
m_sClip.push_back(GfxClip());
|
||
}
|
||
m_sClip.back().AddPath(pGState->getPath(), pGState->getCTM(), true);
|
||
m_bClipChanged = true;
|
||
updateClip(pGState);
|
||
}
|
||
void RendererOutputDev::clipToStrokePath(GfxState *pGState)
|
||
{
|
||
if (m_bDrawOnlyText)
|
||
return;
|
||
|
||
if (m_sClip.empty())
|
||
{
|
||
m_sClip.push_back(GfxClip());
|
||
}
|
||
m_sClip.back().AddPath(pGState->getPath(), pGState->getCTM(), false);
|
||
m_bClipChanged = true;
|
||
updateClip(pGState);
|
||
}
|
||
void RendererOutputDev::clipToPath(GfxState *pGState, GfxPath *pPath, double *pMatrix, bool bEO)
|
||
{
|
||
if (m_bDrawOnlyText)
|
||
return;
|
||
|
||
int nClipFlag = bEO ? c_nClipRegionTypeEvenOdd : c_nClipRegionTypeWinding;
|
||
nClipFlag |= c_nClipRegionIntersect;
|
||
|
||
m_pRenderer->BeginCommand(c_nClipType);
|
||
m_pRenderer->put_ClipMode(nClipFlag);
|
||
DoPath(pGState, pPath, pGState->getPageHeight(), pMatrix);
|
||
m_pRenderer->EndCommand(c_nPathType);
|
||
m_pRenderer->EndCommand(c_nClipType);
|
||
}
|
||
void RendererOutputDev::ClipToText(const std::wstring& wsFontName, const std::wstring& wsFontPath, double dFontSize, int nFontStyle, double *pMatrix, const std::wstring& wsText, double dX, double dY, double dWidth, double dHeight, double dBaseLineOffset)
|
||
{
|
||
if (m_bDrawOnlyText)
|
||
return;
|
||
|
||
m_pRenderer->put_FontName(wsFontName);
|
||
m_pRenderer->put_FontPath(wsFontPath);
|
||
m_pRenderer->put_FontSize(dFontSize);
|
||
m_pRenderer->put_FontStyle((long)nFontStyle);
|
||
|
||
double dShiftX = 0, dShiftY = 0;
|
||
DoTransform(pMatrix, &dShiftX, &dShiftY, true);
|
||
|
||
// TODO: нужна нормальная конвертация
|
||
int nLen = (int)wsText.length();
|
||
const wchar_t* pDataSrc = wsText.c_str();
|
||
if (1 == wsText.length())
|
||
m_pRenderer->PathCommandTextExCHAR(0, (LONG)pDataSrc[0], PDFCoordsToMM(dX), PDFCoordsToMM(dY), PDFCoordsToMM(dWidth), PDFCoordsToMM(dHeight));
|
||
else if (0 != nLen)
|
||
{
|
||
unsigned int* pGids = new unsigned int[nLen];
|
||
for (int nIndex = 0; nIndex < nLen; ++nIndex)
|
||
pGids[nIndex] = (unsigned int)pDataSrc[nIndex];
|
||
|
||
m_pRenderer->PathCommandTextEx(L"", pGids, nLen, PDFCoordsToMM(dX), PDFCoordsToMM(dY), PDFCoordsToMM(dWidth), PDFCoordsToMM(dHeight));
|
||
|
||
RELEASEARRAYOBJECTS(pGids);
|
||
}
|
||
}
|
||
void RendererOutputDev::endTextObject(GfxState *pGState)
|
||
{
|
||
// if (NULL != m_pBufferTextClip) tmpchange
|
||
// {
|
||
// updateClip(pGState);
|
||
//
|
||
// RELEASEOBJECT(m_pBufferTextClip);
|
||
// }
|
||
}
|
||
void RendererOutputDev::beginStringOp(GfxState *pGState)
|
||
{
|
||
m_pRenderer->BeginCommand(c_nTextType);
|
||
|
||
int nRenderMode = pGState->getRender();
|
||
|
||
// Обработка Clip
|
||
// if (nRenderMode >= 4) tmpchange
|
||
// {
|
||
// RELEASEOBJECT(m_pBufferTextClip);
|
||
// m_pBufferTextClip = new GfxTextClip();
|
||
// }
|
||
|
||
// Обработка Stroke
|
||
if (1 == nRenderMode || 2 == nRenderMode || 5 == nRenderMode || 6 == nRenderMode)
|
||
{
|
||
// Painter::CPen oPen;
|
||
//
|
||
// m_pRenderer->put_PenSize( PDFCoordsToMM( pGState->getFontSize() ) * 0.05 );
|
||
// m_pRenderer->put_PenAlpha( 255 );
|
||
// oPen.SetColor( m_oPen.GetColor() );
|
||
//
|
||
// BSTR bsPen = oPen.ToXmlString().AllocSysString();
|
||
// m_pRenderer->SetPen( bsPen );
|
||
// ::SysFreeString( bsPen );
|
||
}
|
||
}
|
||
void RendererOutputDev::endStringOp(GfxState *pGState)
|
||
{
|
||
|
||
int nRenderMode = pGState->getRender();
|
||
|
||
// Добавляем в Clipping Path текст
|
||
if (nRenderMode >= 4)
|
||
{
|
||
// if (m_pBufferTextClip) tmpchange
|
||
// pGState->GetClip()->AppendTextClip(m_pBufferTextClip);
|
||
|
||
updateFont(pGState);
|
||
}
|
||
|
||
// Возвращаем параметры для Stroke
|
||
if (1 == nRenderMode || 2 == nRenderMode || 5 == nRenderMode || 6 == nRenderMode)
|
||
{
|
||
//BSTR bsPen = m_oPen.ToXmlString().AllocSysString();
|
||
//m_pRenderer->SetPen( bsPen );
|
||
//::SysFreeString( bsPen );
|
||
}
|
||
|
||
m_pRenderer->EndCommand(c_nTextType);
|
||
}
|
||
void RendererOutputDev::drawString(GfxState *pGState, GString *seString)
|
||
{
|
||
// Проверяем наличие списка со шрифтами
|
||
if (NULL == m_pFontList)
|
||
return;
|
||
|
||
// Проверяем наличие текущего шрифта
|
||
TFontEntry oEntry;
|
||
if (!m_pFontList->GetFont(pGState->getFont()->getID(), &oEntry))
|
||
return;
|
||
|
||
int nRendererMode = pGState->getRender();
|
||
|
||
if (3 == nRendererMode) // Невидимый текст
|
||
return;
|
||
|
||
double *pCTM = pGState->getCTM();
|
||
double *pTm = pGState->getTextMat();
|
||
GfxFont *pFont = pGState->getFont();
|
||
|
||
unsigned int unGidsCount = seString->getLength();
|
||
unsigned int* pGids = new unsigned int[unGidsCount];
|
||
if (!pGids)
|
||
return;
|
||
|
||
std::wstring wsUnicodeText;
|
||
for (int nIndex = 0; nIndex < seString->getLength(); nIndex++)
|
||
{
|
||
char nChar = seString->getChar(nIndex);
|
||
|
||
if (NULL != oEntry.pCodeToUnicode)
|
||
{
|
||
unsigned short unUnicode = oEntry.pCodeToUnicode[nChar];
|
||
wsUnicodeText += (wchar_t(unUnicode));
|
||
}
|
||
|
||
if (NULL != oEntry.pCodeToGID)
|
||
pGids[nIndex] = oEntry.pCodeToGID[nChar];
|
||
else
|
||
pGids[nIndex] = (0 == nChar ? 65534 : nChar);
|
||
|
||
}
|
||
|
||
m_pRenderer->CommandDrawTextEx(wsUnicodeText, pGids, unGidsCount, PDFCoordsToMM(100), PDFCoordsToMM(100), 0, PDFCoordsToMM(0));
|
||
RELEASEARRAYOBJECTS(pGids);
|
||
}
|
||
void RendererOutputDev::drawChar(GfxState *pGState, double dX, double dY, double dDx, double dDy, double dOriginX, double dOriginY, CharCode nCode, int nBytesCount, Unicode *pUnicode, int nUnicodeLen)
|
||
{
|
||
// Проверяем наличие списка со шрифтами
|
||
if (NULL == m_pFontList)
|
||
return;
|
||
|
||
// Проверяем наличие текущего шрифта
|
||
TFontEntry oEntry;
|
||
if (!m_pFontList->GetFont(pGState->getFont()->getID(), &oEntry))
|
||
return;
|
||
|
||
int nRenderMode = pGState->getRender();
|
||
|
||
if (3 == nRenderMode && !m_bDrawOnlyText) // Невидимый текст
|
||
{
|
||
return;
|
||
}
|
||
|
||
double* pCTM = pGState->getCTM();
|
||
double* pTm = pGState->getTextMat();
|
||
GfxFont* pFont = pGState->getFont();
|
||
|
||
double pNewTm[6], arrMatrix[6];
|
||
|
||
double dTextScale = std::min(sqrt(pTm[2] * pTm[2] + pTm[3] * pTm[3]), sqrt(pTm[0] * pTm[0] + pTm[1] * pTm[1]));
|
||
double dITextScale = 1 / dTextScale;
|
||
double dOldSize = 10.0;
|
||
m_pRenderer->get_FontSize(&dOldSize);
|
||
if (dOldSize * dTextScale > 0)
|
||
{
|
||
m_pRenderer->put_FontSize(dOldSize * dTextScale);
|
||
|
||
pNewTm[0] = pTm[0] * dITextScale * pGState->getHorizScaling();
|
||
pNewTm[1] = pTm[1] * dITextScale * pGState->getHorizScaling();
|
||
pNewTm[2] = -pTm[2] * dITextScale;
|
||
pNewTm[3] = -pTm[3] * dITextScale;
|
||
pNewTm[4] = dX - dOriginX;
|
||
pNewTm[5] = dY - dOriginY;
|
||
}
|
||
else
|
||
{
|
||
m_pRenderer->put_FontSize(-dOldSize * dTextScale);
|
||
|
||
pNewTm[0] = -pTm[0] * dITextScale * pGState->getHorizScaling();
|
||
pNewTm[1] = -pTm[1] * dITextScale * pGState->getHorizScaling();
|
||
pNewTm[2] = pTm[2] * dITextScale;
|
||
pNewTm[3] = pTm[3] * dITextScale;
|
||
pNewTm[4] = dX;
|
||
pNewTm[5] = dY;
|
||
}
|
||
|
||
|
||
arrMatrix[0] = pNewTm[0] * pCTM[0] + pNewTm[1] * pCTM[2];
|
||
arrMatrix[1] = -(pNewTm[0] * pCTM[1] + pNewTm[1] * pCTM[3]);
|
||
arrMatrix[2] = pNewTm[2] * pCTM[0] + pNewTm[3] * pCTM[2];
|
||
arrMatrix[3] = -(pNewTm[2] * pCTM[1] + pNewTm[3] * pCTM[3]);
|
||
arrMatrix[4] = pNewTm[4] * pCTM[0] + pNewTm[5] * pCTM[2] + pCTM[4];
|
||
arrMatrix[5] = -(pNewTm[4] * pCTM[1] + pNewTm[5] * pCTM[3] + pCTM[5]) + pGState->getPageHeight();
|
||
|
||
if (true)
|
||
{
|
||
double dNorma = std::min(sqrt(arrMatrix[0] * arrMatrix[0] + arrMatrix[1] * arrMatrix[1]), sqrt(arrMatrix[2] * arrMatrix[2] + arrMatrix[3] * arrMatrix[3]));
|
||
if (dNorma > 0.001)
|
||
{
|
||
arrMatrix[0] /= dNorma;
|
||
arrMatrix[1] /= dNorma;
|
||
arrMatrix[2] /= dNorma;
|
||
arrMatrix[3] /= dNorma;
|
||
|
||
double dSize = 1;
|
||
m_pRenderer->get_FontSize(&dSize);
|
||
m_pRenderer->put_FontSize(dSize * dNorma);
|
||
}
|
||
}
|
||
|
||
double dShiftX = 0, dShiftY = 0;
|
||
DoTransform(arrMatrix, &dShiftX, &dShiftY, true);
|
||
|
||
// Здесь мы посылаем координаты текста в пунктах
|
||
double dPageHeight = pGState->getPageHeight();
|
||
|
||
std::wstring wsUnicodeText;
|
||
|
||
bool isCIDFont = pFont->isCIDFont();
|
||
|
||
if (NULL != oEntry.pCodeToUnicode && nCode < oEntry.unLenUnicode)
|
||
{
|
||
unsigned short unUnicode = oEntry.pCodeToUnicode[nCode];
|
||
wsUnicodeText = (wchar_t(unUnicode));
|
||
}
|
||
else
|
||
{
|
||
if (isCIDFont)
|
||
{
|
||
// Значит кодировка была Identity-H или Identity-V, что означает, что иходные коды и есть юникодные значения
|
||
wsUnicodeText = (wchar_t(nCode));
|
||
}
|
||
else
|
||
{
|
||
// Договорились, что если нельзя точно составить юникодные значения, тогда отдаем NULL
|
||
if (pFont->getType() == fontType3)
|
||
wsUnicodeText = NSStringExt::CConverter::GetUnicodeFromUTF32(pUnicode, nUnicodeLen);
|
||
else
|
||
wsUnicodeText = L"";
|
||
}
|
||
}
|
||
|
||
unsigned int unGidsCount = 0;
|
||
unsigned int unGid = 0;
|
||
if (NULL != oEntry.pCodeToGID && nCode < oEntry.unLenGID)
|
||
{
|
||
if (0 == (unGid = oEntry.pCodeToGID[nCode]))
|
||
unGidsCount = 0;
|
||
else
|
||
unGidsCount = 1;
|
||
}
|
||
else
|
||
{
|
||
if ((isCIDFont && (((GfxCIDFont*)pFont)->usesIdentityEncoding() || ((GfxCIDFont*)pFont)->usesIdentityCIDToGID() || ((GfxCIDFont*)pFont)->ctuUsesCharCodeToUnicode() || pFont->getType() == fontCIDType0C))
|
||
|| (!isCIDFont && wsUnicodeText.empty()))
|
||
{
|
||
int nCurCode = (0 == nCode ? 65534 : nCode);
|
||
unGid = (unsigned int)nCurCode;
|
||
unGidsCount = 1;
|
||
}
|
||
}
|
||
|
||
if (nRenderMode == 0 || nRenderMode == 4 || nRenderMode == 6 || m_bDrawOnlyText)
|
||
{
|
||
bool bReplace = false;
|
||
std::wstring sFontPath;
|
||
#ifdef BUILDING_WASM_MODULE
|
||
m_pRenderer->get_FontPath(&sFontPath);
|
||
if (!unGid && !wsUnicodeText.empty() && !sFontPath.empty())
|
||
{
|
||
unsigned int lUnicode = (unsigned int)wsUnicodeText[0];
|
||
long lStyle;
|
||
m_pRenderer->get_FontStyle(&lStyle);
|
||
m_pFontManager->LoadFontFromFile(sFontPath, 0, dOldSize, 72, 72);
|
||
|
||
NSFonts::IFontFile* pFontFile = m_pFontManager->GetFile();
|
||
if (pFontFile)
|
||
{
|
||
int nCMapIndex = 0;
|
||
int GID = pFontFile->SetCMapForCharCode(lUnicode, &nCMapIndex);
|
||
if (GID <= 0 && lUnicode < 0xF000)
|
||
GID = pFontFile->SetCMapForCharCode(lUnicode + 0xF000, &nCMapIndex);
|
||
|
||
if (GID <= 0)
|
||
{
|
||
std::wstring sName = m_pFontManager->GetApplication()->GetFontBySymbol(lUnicode);
|
||
int bBold = lStyle & 0x01 ? 1 : 0;
|
||
int bItalic = lStyle & 0x02 ? 1 : 0;
|
||
|
||
if (!sName.empty())
|
||
{
|
||
if (!NSWasm::IsJSEnv())
|
||
{
|
||
NSFonts::CFontSelectFormat oFormat;
|
||
oFormat.wsName = new std::wstring(sName);
|
||
oFormat.bBold = new INT(bBold);
|
||
oFormat.bItalic = new INT(bItalic);
|
||
NSFonts::CFontInfo* pFontInfo = m_pFontManager->GetFontInfoByParams(oFormat);
|
||
|
||
sName = pFontInfo->m_wsFontPath;
|
||
}
|
||
|
||
std::wstring wsFileName = NSWasm::LoadFont(sName, bBold, bItalic);
|
||
if (wsFileName.empty())
|
||
{
|
||
m_pFontList->Remove(*pGState->getFont()->getID());
|
||
return;
|
||
}
|
||
m_pRenderer->put_FontPath(wsFileName);
|
||
bReplace = true;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
#endif
|
||
m_pRenderer->CommandDrawTextEx(wsUnicodeText, &unGid, unGidsCount, PDFCoordsToMM(dShiftX), PDFCoordsToMM(dShiftY), PDFCoordsToMM(dDx), PDFCoordsToMM(dDy));
|
||
if (bReplace)
|
||
m_pRenderer->put_FontPath(sFontPath);
|
||
}
|
||
|
||
LONG lRendererType = 0;
|
||
m_pRenderer->get_Type(&lRendererType);
|
||
|
||
bool bIsEmulateBold = false;
|
||
if (c_nDocxWriter == lRendererType && 2 == nRenderMode)
|
||
bIsEmulateBold = (S_OK == m_pRenderer->CommandLong(c_nSupportPathTextAsText, 0)) ? true : false;
|
||
|
||
if (bIsEmulateBold)
|
||
{
|
||
m_pRenderer->BeginCommand(c_nStrokeTextType);
|
||
|
||
LONG lOldStyle = 0;
|
||
m_pRenderer->get_FontStyle(&lOldStyle);
|
||
LONG lNewStyle = lOldStyle;
|
||
|
||
if ((lNewStyle & 0x01) == 0)
|
||
{
|
||
lNewStyle |= 0x01;
|
||
m_pRenderer->put_FontStyle(lNewStyle);
|
||
}
|
||
|
||
if (unGid)
|
||
m_pRenderer->CommandDrawTextEx(wsUnicodeText, &unGid, unGidsCount, PDFCoordsToMM(dShiftX), PDFCoordsToMM(dShiftY), PDFCoordsToMM(dDx), PDFCoordsToMM(dDy));
|
||
else
|
||
m_pRenderer->CommandDrawText(wsUnicodeText, PDFCoordsToMM(dShiftX), PDFCoordsToMM(dShiftY), PDFCoordsToMM(dDx), PDFCoordsToMM(dDy));
|
||
|
||
if (lOldStyle != lNewStyle)
|
||
m_pRenderer->put_FontStyle(lOldStyle);
|
||
|
||
m_pRenderer->EndCommand(c_nStrokeTextType);
|
||
}
|
||
else if (nRenderMode == 1 || nRenderMode == 2 || nRenderMode == 5 || nRenderMode == 6)
|
||
{
|
||
m_pRenderer->BeginCommand(c_nStrokeTextType);
|
||
|
||
m_pRenderer->PathCommandEnd();
|
||
if (unGid)
|
||
m_pRenderer->PathCommandTextEx(wsUnicodeText, &unGid, unGidsCount, PDFCoordsToMM(dShiftX), PDFCoordsToMM(dShiftY), PDFCoordsToMM(dDx), PDFCoordsToMM(dDy));
|
||
else
|
||
m_pRenderer->PathCommandText(wsUnicodeText, PDFCoordsToMM(dShiftX), PDFCoordsToMM(dShiftY), PDFCoordsToMM(dDx), PDFCoordsToMM(dDy));
|
||
|
||
long lDrawPath = c_nStroke;
|
||
if (nRenderMode == 2)
|
||
lDrawPath |= c_nWindingFillMode;
|
||
|
||
m_pRenderer->DrawPath(lDrawPath);
|
||
|
||
m_pRenderer->EndCommand(c_nStrokeTextType);
|
||
}
|
||
|
||
if (4 <= nRenderMode)
|
||
{
|
||
std::wstring wsTempFontName, wsTempFontPath;
|
||
std::wstring wsClipText; wsClipText += (wchar_t)(unGid);
|
||
double dTempFontSize;
|
||
long lTempFontStyle;
|
||
m_pRenderer->get_FontName(&wsTempFontName);
|
||
m_pRenderer->get_FontPath(&wsTempFontPath);
|
||
m_pRenderer->get_FontSize(&dTempFontSize);
|
||
m_pRenderer->get_FontStyle(&lTempFontStyle);
|
||
// tmpchange
|
||
if (m_sClip.empty())
|
||
{
|
||
m_sClip.push_back(GfxClip());
|
||
}
|
||
m_sClip.back().GetTextClip()->ClipToText(wsTempFontName, wsTempFontPath, dTempFontSize, (int)lTempFontStyle, arrMatrix, wsClipText, 0 + dShiftX, /*-fabs(pFont->getFontBBox()[3]) * dTfs*/ + dShiftY, 0, 0, 0);
|
||
m_bClipChanged = true;
|
||
}
|
||
|
||
m_pRenderer->put_FontSize(dOldSize);
|
||
}
|
||
|
||
GBool RendererOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen)
|
||
{
|
||
if (!m_bDrawOnlyText)
|
||
return false;
|
||
|
||
//drawChar(state, x, y, dx, dy, 0, 0, code, 1, u, uLen);
|
||
|
||
return false;
|
||
}
|
||
void RendererOutputDev::endType3Char(GfxState *pGState)
|
||
{
|
||
return;
|
||
}
|
||
void RendererOutputDev::Type3D0(GfxState *pGState, double dWx, double dWy)
|
||
{
|
||
return;
|
||
}
|
||
void RendererOutputDev::Type3D1(GfxState *pGState, double dWx, double dWy, double dBLx, double dBLy, double dTRx, double dTRy)
|
||
{
|
||
return;
|
||
}
|
||
GBool RendererOutputDev::beginMarkedContent(GfxState *state, GString* s)
|
||
{
|
||
return gFalse;
|
||
}
|
||
GBool RendererOutputDev::beginMCOShapes(GfxState *state, GString *s, Object *ref)
|
||
{
|
||
IAdvancedCommand::AdvancedCommandType eAdvancedCommandType = IAdvancedCommand::AdvancedCommandType::ShapeStart;
|
||
if (m_pRenderer->IsSupportAdvancedCommand(eAdvancedCommandType) == S_OK)
|
||
{
|
||
CShapeStart* pCommand = new CShapeStart();
|
||
pCommand->SetShapeXML(s->getCString());
|
||
|
||
Object oIm;
|
||
if (ref && ref->isRef() && ref->fetch(m_pXref, &oIm)->isStream())
|
||
{
|
||
Dict *oImDict = oIm.streamGetDict();
|
||
|
||
int nLength = 0;
|
||
Object oLength;
|
||
if (oImDict->lookup("Length", &oLength)->isInt())
|
||
nLength = oLength.getInt();
|
||
oLength.free();
|
||
if (oImDict->lookup("DL", &oLength)->isInt())
|
||
nLength = oLength.getInt();
|
||
oLength.free();
|
||
|
||
Stream* pImage = oIm.getStream()->getUndecodedStream();
|
||
pImage->reset();
|
||
|
||
BYTE* pBuffer = new BYTE[nLength];
|
||
BYTE* pBufferPtr = pBuffer;
|
||
for (int nI = 0; nI < nLength; ++nI)
|
||
*pBufferPtr++ = (BYTE)pImage->getChar();
|
||
|
||
CBgraFrame oFrame;
|
||
if (oFrame.Decode(pBuffer, nLength))
|
||
{
|
||
pCommand->SetShapeImage(oFrame.get_Data(), oFrame.get_Width(), oFrame.get_Height());
|
||
oFrame.ClearNoAttack();
|
||
}
|
||
}
|
||
oIm.free();
|
||
bool bRes = m_pRenderer->AdvancedCommand(pCommand) == S_OK;
|
||
RELEASEOBJECT(pCommand);
|
||
if (bRes)
|
||
return gTrue;
|
||
}
|
||
return gFalse;
|
||
}
|
||
void RendererOutputDev::endMarkedContent(GfxState *state)
|
||
{
|
||
IAdvancedCommand::AdvancedCommandType eAdvancedCommandType = IAdvancedCommand::AdvancedCommandType::ShapeEnd;
|
||
if (m_pRenderer->IsSupportAdvancedCommand(eAdvancedCommandType) == S_OK)
|
||
{
|
||
CEmptyComand* pCommand = new CEmptyComand(IAdvancedCommand::AdvancedCommandType::ShapeEnd);
|
||
m_pRenderer->AdvancedCommand(pCommand);
|
||
RELEASEOBJECT(pCommand);
|
||
}
|
||
}
|
||
void RendererOutputDev::drawImageMask(GfxState *pGState, Object *pRef, Stream *pStream, int nWidth, int nHeight,GBool bInvert, GBool bInlineImage, GBool interpolate)
|
||
{
|
||
if (m_bDrawOnlyText)
|
||
return;
|
||
|
||
if (pGState->getFillColorSpace()->isNonMarking())
|
||
{
|
||
return;
|
||
}
|
||
|
||
double dPageHeight = pGState->getPageHeight();
|
||
|
||
int nBufferSize = 4 * nWidth * nHeight;
|
||
if (nBufferSize < 1)
|
||
return;
|
||
|
||
unsigned char *pBufferPtr = new(std::nothrow) unsigned char[nBufferSize];
|
||
if (!pBufferPtr)
|
||
return;
|
||
|
||
Aggplus::CImage oImage;
|
||
oImage.Create(pBufferPtr, nWidth, nHeight, -4 * nWidth);
|
||
|
||
// Пишем данные в pBufferPtr
|
||
ImageStream *pImageStream = new ImageStream(pStream, nWidth, 1, 1);
|
||
|
||
pImageStream->reset();
|
||
|
||
GfxColorSpace* pColorSpace = pGState->getFillColorSpace();
|
||
GfxRGB oRGB;
|
||
pColorSpace->getRGB(pGState->getFillColor(), &oRGB, GfxRenderingIntent::gfxRenderingIntentAbsoluteColorimetric);
|
||
|
||
unsigned char r = colToByte(oRGB.r);
|
||
unsigned char g = colToByte(oRGB.g);
|
||
unsigned char b = colToByte(oRGB.b);
|
||
|
||
unsigned char unAlpha = std::min(255, std::max(0, int(pGState->getFillOpacity() * 255)));
|
||
int nInvert = (bInvert ? 1 : 0);
|
||
for (int nY = nHeight - 1; nY >= 0; nY--)
|
||
{
|
||
unsigned char *pMask = NULL;
|
||
int nX = 0;
|
||
for (nX = 0, pMask = pImageStream->getLine(); nX < nWidth; nX++)
|
||
{
|
||
int nIndex = 4 * (nX + nY * nWidth);
|
||
unsigned char unPixel = *pMask++ ^ nInvert;
|
||
pBufferPtr[nIndex + 0] = unPixel ? 255 : b;
|
||
pBufferPtr[nIndex + 1] = unPixel ? 255 : g;
|
||
pBufferPtr[nIndex + 2] = unPixel ? 255 : r;
|
||
pBufferPtr[nIndex + 3] = unPixel ? 0 : unAlpha;
|
||
}
|
||
}
|
||
|
||
delete pImageStream;
|
||
|
||
double arrMatrix[6];
|
||
double *pCTM = pGState->getCTM();
|
||
|
||
// Исходное предобразование
|
||
// |1 0 0| |pCTM[0] pCTM[1] 0|
|
||
// arrMattrix = |0 -1 0| * |pCTM[2] pCTM[3] 0|
|
||
// |0 1 1| |pCTM[4] pCTM[5] 1|
|
||
|
||
arrMatrix[0] = pCTM[0];
|
||
arrMatrix[1] = -pCTM[1];
|
||
arrMatrix[2] = -pCTM[2];
|
||
arrMatrix[3] = -(-pCTM[3]);
|
||
arrMatrix[4] = pCTM[2] + pCTM[4];
|
||
arrMatrix[5] = -(pCTM[3] + pCTM[5]) + dPageHeight;
|
||
|
||
double dShiftX = 0, dShiftY = 0;
|
||
DoTransform(arrMatrix, &dShiftX, &dShiftY, true);
|
||
m_pRenderer->DrawImage(&oImage, 0 + dShiftX, 0 + dShiftY, PDFCoordsToMM(1), PDFCoordsToMM(1));
|
||
}
|
||
void RendererOutputDev::setSoftMaskFromImageMask(GfxState *pGState, Object *pRef, Stream *pStream, int nWidth, int nHeight, GBool bInvert, GBool bInlineImage, GBool interpolate)
|
||
{
|
||
if (m_bDrawOnlyText)
|
||
return;
|
||
|
||
if (pGState->getFillColorSpace()->isNonMarking())
|
||
{
|
||
return;
|
||
}
|
||
|
||
double dPageHeight = pGState->getPageHeight();
|
||
|
||
int nBufferSize = 4 * nWidth * nHeight;
|
||
if (nBufferSize < 1)
|
||
return;
|
||
|
||
unsigned char *pBufferPtr = new(std::nothrow) unsigned char[nBufferSize];
|
||
if (!pBufferPtr)
|
||
return;
|
||
|
||
double bbox[4] = { 0, 0, 1, 1 };
|
||
beginTransparencyGroup(pGState, bbox, pGState->getFillColorSpace(), true, false, true);
|
||
|
||
Aggplus::CImage oImage;
|
||
oImage.Create(pBufferPtr, nWidth, nHeight, -4 * nWidth, true);
|
||
|
||
// Пишем данные в pBufferPtr
|
||
ImageStream *pImageStream = new ImageStream(pStream, nWidth, 1, 1);
|
||
|
||
pImageStream->reset();
|
||
|
||
GfxColorSpace* pColorSpace = pGState->getFillColorSpace();
|
||
GfxRGB oRGB;
|
||
pColorSpace->getRGB(pGState->getFillColor(), &oRGB, GfxRenderingIntent::gfxRenderingIntentAbsoluteColorimetric);
|
||
GfxPattern* pPattern = pGState->getFillPattern();
|
||
if (pPattern && pPattern->getType() == 2)
|
||
{
|
||
GfxShading *pShading = ((GfxShadingPattern*)pPattern)->getShading();
|
||
pColorSpace = pShading->getColorSpace();
|
||
if (pShading->getHasBackground())
|
||
pColorSpace->getRGB(pShading->getBackground(), &oRGB, GfxRenderingIntent::gfxRenderingIntentAbsoluteColorimetric);
|
||
}
|
||
|
||
unsigned char r = colToByte(oRGB.r);
|
||
unsigned char g = colToByte(oRGB.g);
|
||
unsigned char b = colToByte(oRGB.b);
|
||
|
||
double dAlphaKoef = pGState->getFillOpacity();
|
||
int nInvert = (bInvert ? 1 : 0);
|
||
for (int nY = nHeight - 1; nY >= 0; nY--)
|
||
{
|
||
unsigned char *pMask = NULL;
|
||
int nX = 0;
|
||
int nIndex = 4 * nY * nWidth;
|
||
for (nX = 0, pMask = pImageStream->getLine(); nX < nWidth; nX++)
|
||
{
|
||
unsigned char unPixel = *pMask++ ^ nInvert;
|
||
pBufferPtr[nIndex + 0] = unPixel ? 255 : b;
|
||
pBufferPtr[nIndex + 1] = unPixel ? 255 : g;
|
||
pBufferPtr[nIndex + 2] = unPixel ? 255 : r;
|
||
pBufferPtr[nIndex + 3] = unPixel ? 0 : (unsigned char)(255.0 * dAlphaKoef);
|
||
nIndex += 4;
|
||
}
|
||
}
|
||
|
||
delete pImageStream;
|
||
|
||
double arrMatrix[6];
|
||
double *pCTM = pGState->getCTM();
|
||
|
||
// Исходное предобразование
|
||
// |1 0 0| |pCTM[0] pCTM[1] 0|
|
||
// arrMattrix = |0 -1 0| * |pCTM[2] pCTM[3] 0|
|
||
// |0 1 1| |pCTM[4] pCTM[5] 1|
|
||
|
||
arrMatrix[0] = pCTM[0];
|
||
arrMatrix[1] = -pCTM[1];
|
||
arrMatrix[2] = -pCTM[2];
|
||
arrMatrix[3] = -(-pCTM[3]);
|
||
arrMatrix[4] = pCTM[2] + pCTM[4];
|
||
arrMatrix[5] = -(pCTM[3] + pCTM[5]) + dPageHeight;
|
||
|
||
double dShiftX = 0, dShiftY = 0;
|
||
DoTransform(arrMatrix, &dShiftX, &dShiftY, true);
|
||
m_pRenderer->DrawImage(&oImage, 0 + dShiftX, 0 + dShiftY, PDFCoordsToMM(1), PDFCoordsToMM(1));
|
||
|
||
setSoftMask(pGState, bbox, 0, NULL, NULL);
|
||
}
|
||
|
||
OO_INLINE bool CheckMask(const int& nComponentsCount, const int* pMaskColors, const unsigned char* pLine)
|
||
{
|
||
bool isMask = true;
|
||
for (int nCompIndex = 0; nCompIndex < nComponentsCount; ++nCompIndex)
|
||
{
|
||
if (pMaskColors[nCompIndex * 2] > pLine[nCompIndex] || pLine[nCompIndex] > pMaskColors[nCompIndex * 2 + 1])
|
||
{
|
||
isMask = false;
|
||
break;
|
||
}
|
||
}
|
||
|
||
return isMask;
|
||
}
|
||
|
||
void RendererOutputDev::drawImage(GfxState *pGState, Object *pRef, Stream *pStream, int nWidth, int nHeight, GfxImageColorMap *pColorMap, int *pMaskColors, GBool bInlineImg, GBool interpolate)
|
||
{
|
||
if (m_bDrawOnlyText)
|
||
return;
|
||
|
||
double dPageHeight = pGState->getPageHeight();
|
||
|
||
int nBufferSize = 4 * nWidth * nHeight;
|
||
if (nBufferSize < 1)
|
||
return;
|
||
|
||
unsigned char *pBufferPtr = new(std::nothrow) unsigned char[nBufferSize];
|
||
if (!pBufferPtr)
|
||
return;
|
||
|
||
int nComponentsCount = pColorMap->getNumPixelComps();
|
||
|
||
// Пишем данные в pBufferPtr
|
||
ImageStream *pImageStream = new ImageStream(pStream, nWidth, nComponentsCount, pColorMap->getBits());
|
||
pImageStream->reset();
|
||
|
||
unsigned char unAlpha = std::min(255, std::max(0, int(pGState->getFillOpacity() * 255)));
|
||
|
||
int nStride = pImageStream->getVals();
|
||
int nComps = pImageStream->getComps();
|
||
int nWidthMax = nStride / nComps;
|
||
int nCheckWidth = std::min(nWidth, nWidthMax);
|
||
|
||
// fast realization for some colorspaces (for wasm module)
|
||
int nColorMapType = pColorMap->getFillType();
|
||
GfxColorComp** pColorMapLookup = pColorMap->getLookup();
|
||
if (!pColorMapLookup)
|
||
nColorMapType = 0;
|
||
|
||
for (int nY = nHeight - 1; nY >= 0; --nY)
|
||
{
|
||
unsigned char* pLine = pImageStream->getLine();
|
||
unsigned char* pLineDst = pBufferPtr + 4 * nWidth * nY;
|
||
|
||
if (!pLine)
|
||
{
|
||
memset(pLineDst, 0, 4 * nWidth);
|
||
continue;
|
||
}
|
||
|
||
for (int nX = 0; nX < nCheckWidth; ++nX)
|
||
{
|
||
if (2 == nColorMapType)
|
||
{
|
||
pLineDst[2] = colToByte(clip01(pColorMapLookup[0][pLine[0]]));
|
||
pLineDst[1] = colToByte(clip01(pColorMapLookup[1][pLine[1]]));
|
||
pLineDst[0] = colToByte(clip01(pColorMapLookup[2][pLine[2]]));
|
||
}
|
||
else if (1 == nColorMapType)
|
||
{
|
||
pLineDst[0] = pLineDst[1] = pLineDst[2] = colToByte(clip01(pColorMapLookup[0][pLine[0]]));
|
||
}
|
||
else
|
||
{
|
||
GfxRGB oRGB;
|
||
pColorMap->getRGB(pLine, &oRGB, gfxRenderingIntentAbsoluteColorimetric);
|
||
pLineDst[0] = colToByte(oRGB.b);
|
||
pLineDst[1] = colToByte(oRGB.g);
|
||
pLineDst[2] = colToByte(oRGB.r);
|
||
}
|
||
|
||
if (pMaskColors && CheckMask(nComponentsCount, pMaskColors, pLine))
|
||
pLineDst[3] = 0;
|
||
else
|
||
pLineDst[3] = unAlpha;
|
||
|
||
pLine += nComps;
|
||
pLineDst += 4;
|
||
}
|
||
}
|
||
|
||
Aggplus::CImage oImage;
|
||
oImage.Create(pBufferPtr, nWidth, nHeight, -4 * nWidth);
|
||
|
||
pImageStream->close();
|
||
delete pImageStream;
|
||
|
||
double arrMatrix[6];
|
||
double *pCTM = pGState->getCTM();
|
||
// Исходное предобразование
|
||
// |1 0 0| |pCTM[0] pCTM[1] 0|
|
||
// arrMatrix = |0 -1 0| * |pCTM[2] pCTM[3] 0|
|
||
// |0 1 1| |pCTM[4] pCTM[5] 1|
|
||
arrMatrix[0] = pCTM[0];
|
||
arrMatrix[1] = -pCTM[1];
|
||
arrMatrix[2] = -pCTM[2];
|
||
arrMatrix[3] = -(-pCTM[3]);
|
||
arrMatrix[4] = pCTM[2] + pCTM[4];
|
||
arrMatrix[5] = -(pCTM[3] + pCTM[5]) + dPageHeight;
|
||
|
||
double dShiftX = 0, dShiftY = 0;
|
||
DoTransform(arrMatrix, &dShiftX, &dShiftY, true);
|
||
m_pRenderer->DrawImage(&oImage, 0 + dShiftX, 0 + dShiftY, PDFCoordsToMM(1), PDFCoordsToMM(1));
|
||
}
|
||
void RendererOutputDev::drawMaskedImage(GfxState *pGState, Object *pRef, Stream *pStream, int nWidth, int nHeight, GfxImageColorMap *pColorMap, Object* pStreamRef, Stream *pMaskStream, int nMaskWidth, int nMaskHeight, GBool bMaskInvert, GBool interpolate)
|
||
{
|
||
if (m_bDrawOnlyText)
|
||
return;
|
||
|
||
if (nMaskWidth <= 0 || nMaskHeight <= 0)
|
||
drawImage(pGState, pRef, pStream, nWidth, nHeight, pColorMap, NULL, false, interpolate);
|
||
|
||
if (nMaskWidth > nWidth || nMaskHeight > nHeight)
|
||
{
|
||
// If the mask is higher resolution than the image, use
|
||
// drawSoftMaskedImage() instead.
|
||
|
||
GfxImageColorMap *maskColorMap;
|
||
Object maskDecode, decodeLow, decodeHigh;
|
||
|
||
decodeLow.initInt(bMaskInvert ? 0 : 1);
|
||
decodeHigh.initInt(bMaskInvert ? 1 : 0);
|
||
maskDecode.initArray(m_pXref);
|
||
maskDecode.arrayAdd(&decodeLow);
|
||
maskDecode.arrayAdd(&decodeHigh);
|
||
maskColorMap = new GfxImageColorMap(1, &maskDecode, new GfxDeviceGrayColorSpace());
|
||
maskDecode.free();
|
||
drawSoftMaskedImage(pGState, pRef, pStream, nWidth, nHeight,
|
||
pColorMap, pStreamRef, pMaskStream, nMaskWidth, nMaskHeight, maskColorMap, NULL, interpolate);
|
||
delete maskColorMap;
|
||
return;
|
||
}
|
||
|
||
double dPageHeight = pGState->getPageHeight();
|
||
|
||
int nBufferSize = 4 * nWidth * nHeight;
|
||
if (nBufferSize < 1)
|
||
return;
|
||
|
||
unsigned char *pBufferPtr = new(std::nothrow) unsigned char[nBufferSize];
|
||
if (!pBufferPtr)
|
||
return;
|
||
|
||
Aggplus::CImage oImage;
|
||
oImage.Create(pBufferPtr, nWidth, nHeight, -4 * nWidth);
|
||
|
||
// Пишем данные в pBufferPtr
|
||
ImageStream *pImageStream = new ImageStream(pStream, nWidth, pColorMap->getNumPixelComps(), pColorMap->getBits());
|
||
ImageStream *pMask = new ImageStream(pMaskStream, nMaskWidth, 1, 1);
|
||
|
||
pMask->reset();
|
||
pImageStream->reset();
|
||
|
||
BYTE nAlpha = pGState->getFillOpacity() * 255;
|
||
if (nWidth != nMaskWidth || nHeight != nMaskHeight)
|
||
{
|
||
unsigned char *pMaskBuffer = new(std::nothrow) unsigned char[nMaskWidth * nMaskHeight];
|
||
if (!pMaskBuffer)
|
||
{
|
||
delete pMask;
|
||
delete pImageStream;
|
||
return;
|
||
}
|
||
|
||
unsigned char unMask = 0;
|
||
for (int nY = nMaskHeight - 1; nY >= 0; nY--)
|
||
{
|
||
int nIndex = nY * nMaskWidth;
|
||
for (int nX = 0; nX < nMaskWidth; nX++)
|
||
{
|
||
pMask->getPixel(&unMask);
|
||
pMaskBuffer[nIndex++] = unMask;
|
||
}
|
||
}
|
||
|
||
double dScaleWidth = (double)nWidth / (double)nMaskWidth;
|
||
double dScaleHeight = (double)nHeight / (double)nMaskHeight;
|
||
|
||
unsigned char unPixel[4] ={ 0, 0, 0, 0 };
|
||
for (int nY = nHeight - 1; nY >= 0; nY--)
|
||
{
|
||
int nIndex = 4 * nY * nWidth;
|
||
for (int nX = 0; nX < nWidth; nX++)
|
||
{
|
||
pImageStream->getPixel(unPixel);
|
||
|
||
int nNearestY = (std::min)((int)(nY / dScaleHeight), nMaskHeight - 1);
|
||
int nNearestX = (std::min)((int)(nX / dScaleWidth), nMaskWidth - 1);
|
||
unMask = pMaskBuffer[nNearestY * nMaskWidth + nNearestX];
|
||
|
||
GfxRGB oRGB;
|
||
pColorMap->getRGB(unPixel, &oRGB, GfxRenderingIntent::gfxRenderingIntentAbsoluteColorimetric);
|
||
pBufferPtr[nIndex + 0] = colToByte(oRGB.b);
|
||
pBufferPtr[nIndex + 1] = colToByte(oRGB.g);
|
||
pBufferPtr[nIndex + 2] = colToByte(oRGB.r);
|
||
|
||
if (unMask && !bMaskInvert)
|
||
pBufferPtr[nIndex + 3] = 0;
|
||
else
|
||
pBufferPtr[nIndex + 3] = nAlpha;
|
||
|
||
nIndex += 4;
|
||
}
|
||
}
|
||
|
||
delete[] pMaskBuffer;
|
||
}
|
||
else
|
||
{
|
||
unsigned char unPixel[4] ={ 0, 0, 0, 0 };
|
||
unsigned char unMask = 0;
|
||
for (int nY = nHeight - 1; nY >= 0; nY--)
|
||
{
|
||
int nIndex = 4 * nY * nWidth;
|
||
for (int nX = 0; nX < nWidth; nX++)
|
||
{
|
||
pImageStream->getPixel(unPixel);
|
||
pMask->getPixel(&unMask);
|
||
GfxRGB oRGB;
|
||
pColorMap->getRGB(unPixel, &oRGB, GfxRenderingIntent::gfxRenderingIntentAbsoluteColorimetric);
|
||
pBufferPtr[nIndex + 0] = colToByte(oRGB.b);
|
||
pBufferPtr[nIndex + 1] = colToByte(oRGB.g);
|
||
pBufferPtr[nIndex + 2] = colToByte(oRGB.r);
|
||
|
||
if (unMask && !bMaskInvert)
|
||
pBufferPtr[nIndex + 3] = 0;
|
||
else
|
||
pBufferPtr[nIndex + 3] = nAlpha;
|
||
|
||
nIndex += 4;
|
||
}
|
||
}
|
||
}
|
||
|
||
delete pMask;
|
||
delete pImageStream;
|
||
|
||
double arrMatrix[6];
|
||
double *pCTM = pGState->getCTM();
|
||
// Исходное предобразование
|
||
// |1 0 0| |pCTM[0] pCTM[1] 0|
|
||
// arrMatrix = |0 -1 0| * |pCTM[2] pCTM[3] 0|
|
||
// |0 1 1| |pCTM[4] pCTM[5] 1|
|
||
arrMatrix[0] = pCTM[0];
|
||
arrMatrix[1] = -pCTM[1];
|
||
arrMatrix[2] = -pCTM[2];
|
||
arrMatrix[3] = -(-pCTM[3]);
|
||
arrMatrix[4] = pCTM[2] + pCTM[4];
|
||
arrMatrix[5] = -(pCTM[3] + pCTM[5]) + dPageHeight;
|
||
|
||
double dShiftX = 0, dShiftY = 0;
|
||
DoTransform(arrMatrix, &dShiftX, &dShiftY, true);
|
||
m_pRenderer->DrawImage(&oImage, 0 + dShiftX, 0 + dShiftY, PDFCoordsToMM(1), PDFCoordsToMM(1));
|
||
}
|
||
void RendererOutputDev::drawSoftMaskedImage(GfxState *pGState, Object *pRef, Stream *pStream,
|
||
int nWidth, int nHeight,
|
||
GfxImageColorMap *pColorMap,
|
||
Object *maskRef, Stream *pMaskStream,
|
||
int nMaskWidth, int nMaskHeight,
|
||
GfxImageColorMap *pMaskColorMap,
|
||
double *pMatteColor, GBool interpolate)
|
||
{
|
||
if (m_bDrawOnlyText)
|
||
return;
|
||
|
||
double dPageHeight = pGState->getPageHeight();
|
||
|
||
int nBufferSize = 4 * nWidth * nHeight;
|
||
if (nBufferSize < 1)
|
||
return;
|
||
|
||
unsigned char *pBufferPtr = new(std::nothrow) unsigned char[nBufferSize];
|
||
if (!pBufferPtr)
|
||
return;
|
||
|
||
Aggplus::CImage oImage;
|
||
oImage.Create(pBufferPtr, nWidth, nHeight, -4 * nWidth);
|
||
|
||
// Пишем данные в pBufferPtr
|
||
ImageStream *pImageStream = new ImageStream(pStream, nWidth, pColorMap->getNumPixelComps(), pColorMap->getBits());
|
||
pImageStream->reset();
|
||
|
||
double dAlphaKoef = pGState->getFillOpacity();
|
||
unsigned char unPixel[4] = { 0, 0, 0, 0 };
|
||
for (int nY = nHeight - 1; nY >= 0; nY--)
|
||
{
|
||
int nIndex = 4 * nY * nWidth;
|
||
for (int nX = 0; nX < nWidth; nX++)
|
||
{
|
||
pImageStream->getPixel(unPixel);
|
||
GfxRGB oRGB;
|
||
pColorMap->getRGB(unPixel, &oRGB, gfxRenderingIntentAbsoluteColorimetric);
|
||
pBufferPtr[nIndex + 0] = colToByte(oRGB.b);
|
||
pBufferPtr[nIndex + 1] = colToByte(oRGB.g);
|
||
pBufferPtr[nIndex + 2] = colToByte(oRGB.r);
|
||
pBufferPtr[nIndex + 3] = 255;
|
||
|
||
nIndex += 4;
|
||
}
|
||
}
|
||
delete pImageStream;
|
||
|
||
if (nWidth != nMaskWidth || nHeight != nMaskHeight)
|
||
{
|
||
// TO DO: Здесь сделан элементарный вариант масштабирования маски.
|
||
// Надо улучшить алгоритм.
|
||
|
||
bool bResize = true;
|
||
|
||
if (0 != nWidth && 0 != nMaskHeight && 0 != nHeight && 0 != nMaskWidth)
|
||
{
|
||
ImageStream *pSMaskStream = new ImageStream(pMaskStream, nMaskWidth, pMaskColorMap->getNumPixelComps(), pMaskColorMap->getBits());
|
||
unsigned char *pAlpha = new(std::nothrow) unsigned char[nMaskWidth * nMaskHeight];
|
||
if (pSMaskStream && pAlpha)
|
||
{
|
||
pSMaskStream->reset();
|
||
|
||
unsigned char unAlpha = 0;
|
||
for (int i = 0, nCount = nMaskWidth * nMaskHeight; i < nCount; ++i)
|
||
{
|
||
pSMaskStream->getPixel(&unAlpha);
|
||
GfxGray oGray;
|
||
pMaskColorMap->getGray(&unAlpha, &oGray, GfxRenderingIntent::gfxRenderingIntentAbsoluteColorimetric);
|
||
pAlpha[i] = colToByte(oGray);
|
||
}
|
||
delete pSMaskStream;
|
||
|
||
int nMaxW = (std::max)(nWidth, nMaskWidth);
|
||
int nMaxH = (std::max)(nHeight, nMaskHeight);
|
||
|
||
double dAlphaScaleWidth = (double)nMaskWidth / (double)nMaxW;
|
||
double dAlphaScaleHeight = (double)nMaskHeight / (double)nMaxH;
|
||
|
||
if (nWidth != nMaxW || nHeight != nMaxH)
|
||
{
|
||
unsigned char* pImageBuffer = pBufferPtr;
|
||
pBufferPtr = new(std::nothrow) unsigned char[4 * nMaxW * nMaxH];
|
||
if (!pBufferPtr)
|
||
{
|
||
delete[] pImageBuffer;
|
||
delete[] pAlpha;
|
||
return;
|
||
}
|
||
|
||
oImage.Create(pBufferPtr, nMaxW, nMaxH, -4 * nMaxW);
|
||
|
||
double dImageScaleWidth = (double)nWidth / (double)nMaxW;
|
||
double dImageScaleHeight = (double)nHeight / (double)nMaxH;
|
||
|
||
for (int nY = nMaxH - 1; nY >= 0; nY--)
|
||
{
|
||
int nIndex = 4 * nY * nMaxW;
|
||
for (int nX = 0; nX < nMaxW; nX++)
|
||
{
|
||
int nNearestAlphaMatch = (((int)((nMaxH - 1 - nY) * dAlphaScaleHeight) * nMaskWidth) + ((int)(nX * dAlphaScaleWidth)));
|
||
int nNearestImageMatch = 4 * (((int)(nY * dImageScaleHeight) * nWidth) + ((int)(nX * dImageScaleWidth)));
|
||
|
||
pBufferPtr[nIndex + 0] = pImageBuffer[nNearestImageMatch + 0];
|
||
pBufferPtr[nIndex + 1] = pImageBuffer[nNearestImageMatch + 1];
|
||
pBufferPtr[nIndex + 2] = pImageBuffer[nNearestImageMatch + 2];
|
||
pBufferPtr[nIndex + 3] = (unsigned char)(pAlpha[nNearestAlphaMatch] * dAlphaKoef);
|
||
nIndex += 4;
|
||
}
|
||
}
|
||
|
||
delete[] pImageBuffer;
|
||
}
|
||
else
|
||
{
|
||
for (int nY = nHeight - 1; nY >= 0; nY--)
|
||
{
|
||
int nIndex = 4 * nY * nWidth;
|
||
for (int nX = 0; nX < nWidth; nX++)
|
||
{
|
||
int nNearestAlphaMatch = (((int)((nHeight - 1 - nY) * dAlphaScaleHeight) * nMaskWidth) + ((int)(nX * dAlphaScaleWidth)));
|
||
|
||
pBufferPtr[nIndex + 3] = (unsigned char)(pAlpha[nNearestAlphaMatch] * dAlphaKoef);
|
||
nIndex += 4;
|
||
}
|
||
}
|
||
}
|
||
|
||
delete[] pAlpha;
|
||
}
|
||
else
|
||
{
|
||
if (pAlpha)
|
||
delete[] pAlpha;
|
||
|
||
if (pSMaskStream)
|
||
delete pSMaskStream;
|
||
|
||
bResize = false;
|
||
}
|
||
}
|
||
else
|
||
bResize = false;
|
||
|
||
if (!bResize && dAlphaKoef < 1.0)
|
||
{
|
||
for (int i = 3, nCount = nWidth * nHeight * 4; i < nCount; i += 4)
|
||
{
|
||
pBufferPtr[i] = (unsigned char)(255.0 * dAlphaKoef);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
ImageStream *pSMaskStream = new ImageStream(pMaskStream, nMaskWidth, pMaskColorMap->getNumPixelComps(), pMaskColorMap->getBits());
|
||
pSMaskStream->reset();
|
||
|
||
unsigned char unAlpha = 0;
|
||
for (int nY = nHeight - 1; nY >= 0; nY--)
|
||
{
|
||
int nIndex = 4 * nY * nWidth;
|
||
for (int nX = 0; nX < nWidth; nX++)
|
||
{
|
||
pSMaskStream->getPixel(&unAlpha);
|
||
GfxGray oGray;
|
||
pMaskColorMap->getGray(&unAlpha, &oGray, GfxRenderingIntent::gfxRenderingIntentAbsoluteColorimetric);
|
||
pBufferPtr[nIndex + 3] = (unsigned char)(colToByte(oGray) * dAlphaKoef);
|
||
nIndex += 4;
|
||
}
|
||
}
|
||
delete pSMaskStream;
|
||
}
|
||
|
||
// Undo preblend
|
||
if (pMatteColor)
|
||
{
|
||
GfxRGB oMatteRGB;
|
||
GfxColor oColor;
|
||
for (int i = 0; i < pColorMap->getNumPixelComps(); ++i) {
|
||
oColor.c[i] = dblToCol(pMatteColor[i]);
|
||
}
|
||
pColorMap->getColorSpace()->getRGB(&oColor, &oMatteRGB, gfxRenderingIntentAbsoluteColorimetric);
|
||
|
||
unsigned char unMatteR = colToByte(oMatteRGB.r);
|
||
unsigned char unMatteG = colToByte(oMatteRGB.g);
|
||
unsigned char unMatteB = colToByte(oMatteRGB.b);
|
||
|
||
for (int nIndex = 0; nIndex < nHeight * nWidth * 4; nIndex += 4)
|
||
{
|
||
unsigned char unA = pBufferPtr[nIndex + 3];
|
||
|
||
if (0 == unA)
|
||
{
|
||
pBufferPtr[nIndex + 0] = 255;
|
||
pBufferPtr[nIndex + 1] = 255;
|
||
pBufferPtr[nIndex + 2] = 255;
|
||
}
|
||
else
|
||
{
|
||
double dK = 255.0 / unA;
|
||
|
||
pBufferPtr[nIndex + 0] = std::max(0, std::min(255, int((pBufferPtr[nIndex + 0] - unMatteB) * dK + unMatteB)));
|
||
pBufferPtr[nIndex + 1] = std::max(0, std::min(255, int((pBufferPtr[nIndex + 1] - unMatteG) * dK + unMatteG)));
|
||
pBufferPtr[nIndex + 2] = std::max(0, std::min(255, int((pBufferPtr[nIndex + 2] - unMatteR) * dK + unMatteR)));
|
||
}
|
||
}
|
||
}
|
||
|
||
double arrMatrix[6];
|
||
double *pCTM = pGState->getCTM();
|
||
// Исходное предобразование
|
||
// |1 0 0| |pCTM[0] pCTM[1] 0|
|
||
// arrMattrix = |0 -1 0| * |pCTM[2] pCTM[3] 0|
|
||
// |0 1 1| |pCTM[4] pCTM[5] 1|
|
||
arrMatrix[0] = pCTM[0];
|
||
arrMatrix[1] = -pCTM[1];
|
||
arrMatrix[2] = -pCTM[2];
|
||
arrMatrix[3] = -(-pCTM[3]);
|
||
arrMatrix[4] = pCTM[2] + pCTM[4];
|
||
arrMatrix[5] = -(pCTM[3] + pCTM[5]) + dPageHeight;
|
||
|
||
double dShiftX = 0, dShiftY = 0;
|
||
DoTransform(arrMatrix, &dShiftX, &dShiftY, true);
|
||
m_pRenderer->DrawImage(&oImage, 0 + dShiftX, 0 + dShiftY, PDFCoordsToMM(1), PDFCoordsToMM(1));
|
||
}
|
||
void RendererOutputDev::beginTransparencyGroup(GfxState *pGState, double *pBBox, GfxColorSpace *pBlendingColorSpace, GBool bIsolated, GBool bKnockout, GBool bForSoftMask)
|
||
{
|
||
NSGraphics::IGraphicsRenderer* GRenderer = dynamic_cast<NSGraphics::IGraphicsRenderer*>(m_pRenderer);
|
||
if (!GRenderer)
|
||
return;
|
||
|
||
if (bForSoftMask)
|
||
{
|
||
m_pRenderer->BeginCommand(c_nMaskType);
|
||
m_pRenderer->put_AlphaMaskIsolated(bIsolated);
|
||
}
|
||
else
|
||
{
|
||
if (!GRenderer->GetAlphaMask())
|
||
{
|
||
m_pRenderer->BeginCommand(c_nLayerType);
|
||
//m_pRenderer->put_LayerIsolated(bIsolated);
|
||
}
|
||
}
|
||
}
|
||
void RendererOutputDev::endTransparencyGroup(GfxState *pGState)
|
||
{
|
||
}
|
||
void RendererOutputDev::paintTransparencyGroup(GfxState *pGState, double *pBBox)
|
||
{
|
||
NSGraphics::IGraphicsRenderer* GRenderer = dynamic_cast<NSGraphics::IGraphicsRenderer*>(m_pRenderer);
|
||
if (!GRenderer)
|
||
return;
|
||
|
||
double dOpacity = std::min(1.0, std::max(0.0, pGState->getFillOpacity()));
|
||
m_pRenderer->put_LayerOpacity(dOpacity);
|
||
if (m_sStates.back().pAlphaMask && !GRenderer->GetAlphaMask())
|
||
GRenderer->SetAlphaMask(m_sStates.back().pAlphaMask);
|
||
m_pRenderer->EndCommand(c_nLayerType);
|
||
}
|
||
void RendererOutputDev::setSoftMask(GfxState *pGState, double *pBBox, GBool bAlpha, Function *pTransferFunc, GfxColor *pBackdropColor)
|
||
{
|
||
NSGraphics::IGraphicsRenderer* GRenderer = dynamic_cast<NSGraphics::IGraphicsRenderer*>(m_pRenderer);
|
||
if (!GRenderer)
|
||
return;
|
||
|
||
m_pRenderer->EndCommand(c_nMaskType);
|
||
if (bAlpha)
|
||
GRenderer->put_AlphaMaskType(Aggplus::EMaskDataType::Alpha4Buffer);
|
||
m_sStates.back().pGStateSoftMask = m_sStates.back().pGState;
|
||
m_sStates.back().pAlphaMask = GRenderer->GetAlphaMask();
|
||
m_sStates.back().pAlphaMask->AddRef();
|
||
}
|
||
void RendererOutputDev::clearSoftMask(GfxState *pGState)
|
||
{
|
||
NSGraphics::IGraphicsRenderer* GRenderer = dynamic_cast<NSGraphics::IGraphicsRenderer*>(m_pRenderer);
|
||
if (!GRenderer)
|
||
return;
|
||
|
||
GRenderer->SetAlphaMask(NULL);
|
||
m_sStates.back().pAlphaMask = NULL;
|
||
m_sStates.back().pGStateSoftMask = NULL;
|
||
}
|
||
void RendererOutputDev::NewPDF(XRef *pXref)
|
||
{
|
||
m_pXref = pXref;
|
||
}
|
||
void RendererOutputDev::Transform(double *pMatrix, double dUserX, double dUserY, double *pdDeviceX, double *pdDeviceY)
|
||
{
|
||
Distance(pMatrix, dUserX, dUserY, pdDeviceX, pdDeviceY);
|
||
*pdDeviceX += pMatrix[4];
|
||
*pdDeviceY += pMatrix[5];
|
||
}
|
||
void RendererOutputDev::Distance(double *pMatrix, double dUserX, double dUserY, double *pdDeviceX, double *pdDeviceY)
|
||
{
|
||
*pdDeviceX = dUserX * pMatrix[0] + dUserY * pMatrix[2];
|
||
*pdDeviceY = dUserX * pMatrix[1] + dUserY * pMatrix[3];
|
||
}
|
||
void RendererOutputDev::DoPath(GfxState *pGState, GfxPath *pPath, double dPageHeight, double *pCTM, GfxClipMatrix* pCTM2)
|
||
{
|
||
if (m_bDrawOnlyText)
|
||
return;
|
||
|
||
double arrMatrix[6];
|
||
//double *pCTM = pGState->getCTM();
|
||
arrMatrix[0] = pCTM[0];
|
||
arrMatrix[1] = -pCTM[1];
|
||
arrMatrix[2] = pCTM[2];
|
||
arrMatrix[3] = -pCTM[3];
|
||
arrMatrix[4] = pCTM[4];
|
||
arrMatrix[5] = -pCTM[5] + dPageHeight;
|
||
if (pCTM2)
|
||
{
|
||
arrMatrix[0] = pCTM2->dA;
|
||
arrMatrix[1] = -pCTM2->dB;
|
||
arrMatrix[2] = pCTM2->dC;
|
||
arrMatrix[3] = -pCTM2->dD;
|
||
arrMatrix[4] = pCTM2->dE;
|
||
arrMatrix[5] = -pCTM2->dF + dPageHeight;
|
||
}
|
||
|
||
double dShiftX = 0, dShiftY = 0;
|
||
DoTransform(arrMatrix, &dShiftX, &dShiftY);
|
||
|
||
m_pRenderer->BeginCommand(c_nPathType);
|
||
m_pRenderer->PathCommandEnd();
|
||
|
||
for (int nSubPathIndex = 0, nSubPathCount = pPath->getNumSubpaths(); nSubPathIndex < nSubPathCount; ++nSubPathIndex)
|
||
{
|
||
GfxSubpath *pSubpath = pPath->getSubpath(nSubPathIndex);
|
||
int nPointsCount = pSubpath->getNumPoints();
|
||
|
||
m_pRenderer->PathCommandMoveTo(PDFCoordsToMM(pSubpath->getX(0) + dShiftX), PDFCoordsToMM(pSubpath->getY(0) + dShiftY));
|
||
|
||
int nCurPointIndex = 1;
|
||
while (nCurPointIndex < nPointsCount)
|
||
{
|
||
if (pSubpath->getCurve(nCurPointIndex))
|
||
{
|
||
m_pRenderer->PathCommandCurveTo(PDFCoordsToMM(pSubpath->getX(nCurPointIndex) + dShiftX), PDFCoordsToMM(pSubpath->getY(nCurPointIndex) + dShiftY),
|
||
PDFCoordsToMM(pSubpath->getX(nCurPointIndex + 1) + dShiftX), PDFCoordsToMM(pSubpath->getY(nCurPointIndex + 1) + dShiftY),
|
||
PDFCoordsToMM(pSubpath->getX(nCurPointIndex + 2) + dShiftX), PDFCoordsToMM(pSubpath->getY(nCurPointIndex + 2) + dShiftY));
|
||
nCurPointIndex += 3;
|
||
}
|
||
else
|
||
{
|
||
m_pRenderer->PathCommandLineTo(PDFCoordsToMM(pSubpath->getX(nCurPointIndex) + dShiftX), PDFCoordsToMM(pSubpath->getY(nCurPointIndex) + dShiftY));
|
||
++nCurPointIndex;
|
||
}
|
||
}
|
||
if (pSubpath->isClosed())
|
||
{
|
||
m_pRenderer->PathCommandClose();
|
||
}
|
||
}
|
||
}
|
||
void RendererOutputDev::updateClip(GfxState *pGState)
|
||
{
|
||
if (m_bDrawOnlyText)
|
||
return;
|
||
|
||
if (m_bTiling)
|
||
return;
|
||
|
||
updateClipAttack(pGState);
|
||
}
|
||
void RendererOutputDev::updateClipAttack(GfxState *pGState)
|
||
{
|
||
if (!m_bClipChanged)
|
||
return;
|
||
|
||
m_pRenderer->BeginCommand(c_nResetClipType);
|
||
m_pRenderer->EndCommand(c_nResetClipType);
|
||
|
||
if (m_sClip.empty())
|
||
return;
|
||
|
||
//for (int i = m_sClip.size() - 1; i >= 0; i--)
|
||
for (int i = 0; i < m_sClip.size(); i++)
|
||
{
|
||
for (int nIndex = 0; nIndex < m_sClip[i].GetPathNum(); nIndex++)
|
||
{
|
||
GfxPath *pPath = m_sClip[i].GetPath(nIndex);
|
||
bool bFlag = m_sClip[i].GetClipEo(nIndex);
|
||
|
||
int nClipFlag = bFlag ? c_nClipRegionTypeEvenOdd : c_nClipRegionTypeWinding;
|
||
nClipFlag |= c_nClipRegionIntersect;
|
||
|
||
m_pRenderer->BeginCommand(c_nClipType);
|
||
m_pRenderer->put_ClipMode(nClipFlag);
|
||
DoPath(pGState, pPath, pGState->getPageHeight(), pGState->getCTM(), &m_sClip[i].m_vMatrix[nIndex]);
|
||
m_pRenderer->EndCommand(c_nPathType);
|
||
m_pRenderer->EndCommand(c_nClipType);
|
||
m_pRenderer->PathCommandEnd();
|
||
}
|
||
|
||
int nTextClipCount = m_sClip[i].GetTextClip()->GetTextsCount();
|
||
if (nTextClipCount > 0)
|
||
{
|
||
m_pRenderer->BeginCommand(c_nClipType);
|
||
m_pRenderer->put_ClipMode(c_nClipRegionTypeWinding | c_nClipRegionIntersect);
|
||
m_pRenderer->StartConvertCoordsToIdentity();
|
||
|
||
for (int nIndex = 0; nIndex < nTextClipCount; nIndex++)
|
||
{
|
||
wchar_t *wsFontName, *wsFontPath;
|
||
int lFontStyle;
|
||
double dFontSize = 10, dX = 0, dY = 0, dWidth = 0, dHeight = 0, dBaseLineOffset = 0;
|
||
wchar_t *wsText = m_sClip[i].GetTextClip()->GetText(nIndex, &dX, &dY, &dWidth, &dHeight, &dBaseLineOffset, &wsFontName, &wsFontPath, &dFontSize, &lFontStyle);
|
||
|
||
m_pRenderer->put_FontName(wsFontName);
|
||
m_pRenderer->put_FontPath(wsFontPath);
|
||
m_pRenderer->put_FontSize(dFontSize);
|
||
m_pRenderer->put_FontStyle(lFontStyle);
|
||
|
||
double dShiftX = 0, dShiftY = 0;
|
||
DoTransform(m_sClip[i].GetTextClip()->GetMatrix(nIndex), &dShiftX, &dShiftY, true);
|
||
|
||
// TODO: нужна нормальная конвертация
|
||
int nLen = 0;
|
||
wchar_t *wsTextTmp = wsText;
|
||
if (wsTextTmp)
|
||
{
|
||
while (*wsTextTmp)
|
||
++wsTextTmp;
|
||
|
||
nLen = (int)(wsTextTmp - wsText);
|
||
}
|
||
|
||
if (1 == nLen)
|
||
m_pRenderer->PathCommandTextExCHAR(0, (LONG)wsText[0], PDFCoordsToMM(dX), PDFCoordsToMM(dY), PDFCoordsToMM(dWidth), PDFCoordsToMM(dHeight));
|
||
else if (0 != nLen)
|
||
{
|
||
unsigned int* pGids = new unsigned int[nLen];
|
||
for (int nIndex = 0; nIndex < nLen; ++nIndex)
|
||
pGids[nIndex] = (unsigned int)wsText[nIndex];
|
||
|
||
m_pRenderer->PathCommandTextEx(L"", pGids, nLen, PDFCoordsToMM(dX), PDFCoordsToMM(dY), PDFCoordsToMM(dWidth), PDFCoordsToMM(dHeight));
|
||
|
||
RELEASEARRAYOBJECTS(pGids);
|
||
}
|
||
|
||
}
|
||
|
||
m_pRenderer->EndCommand(c_nPathType);
|
||
m_pRenderer->EndCommand(c_nClipType);
|
||
m_pRenderer->PathCommandEnd();
|
||
m_pRenderer->EndConvertCoordsToIdentity();
|
||
}
|
||
}
|
||
|
||
m_bClipChanged = false;
|
||
|
||
|
||
updateFont(pGState);
|
||
}
|
||
void RendererOutputDev::DoTransform(double *pMatrix, double *pdShiftX, double *pdShiftY, bool bText)
|
||
{
|
||
if (1 == pMatrix[0] && 0 == pMatrix[1] && 0 == pMatrix[2] && 1 == pMatrix[3] && !bText)
|
||
{
|
||
if (0 == pMatrix[4] && 0 == pMatrix[5])
|
||
{
|
||
m_pRenderer->ResetTransform();
|
||
m_arrMatrix[0] = 1; m_arrMatrix[1] = 0;
|
||
m_arrMatrix[2] = 0; m_arrMatrix[3] = 1;
|
||
m_arrMatrix[4] = 0; m_arrMatrix[5] = 0;
|
||
}
|
||
else
|
||
{
|
||
*pdShiftX = pMatrix[4];
|
||
*pdShiftY = pMatrix[5];
|
||
m_pRenderer->ResetTransform();
|
||
m_arrMatrix[0] = 1; m_arrMatrix[1] = 0;
|
||
m_arrMatrix[2] = 0; m_arrMatrix[3] = 1;
|
||
m_arrMatrix[4] = 0; m_arrMatrix[5] = 0;
|
||
}
|
||
}
|
||
else if (m_arrMatrix[0] == pMatrix[0] && m_arrMatrix[1] == pMatrix[1] && m_arrMatrix[2] == pMatrix[2] && m_arrMatrix[3] == pMatrix[3]
|
||
&& m_arrMatrix[4] == pMatrix[4] && m_arrMatrix[5] == pMatrix[5] && !bText)
|
||
{
|
||
double dNewX = pMatrix[4], dNewY = pMatrix[5];
|
||
double dIDet = 1 / (pMatrix[0] * pMatrix[3] - pMatrix[1] * pMatrix[2]);
|
||
|
||
*pdShiftX = ((dNewX - m_arrMatrix[4]) * m_arrMatrix[3] - (dNewY - m_arrMatrix[5]) * m_arrMatrix[1]) * dIDet;
|
||
*pdShiftY = ((dNewY - m_arrMatrix[5]) * m_arrMatrix[0] - (dNewX - m_arrMatrix[4]) * m_arrMatrix[2]) * dIDet;
|
||
}
|
||
else
|
||
{
|
||
m_pRenderer->SetTransform(pMatrix[0], pMatrix[1], pMatrix[2], pMatrix[3], PDFCoordsToMM(pMatrix[4]), PDFCoordsToMM(pMatrix[5]));
|
||
m_arrMatrix[0] = pMatrix[0]; m_arrMatrix[1] = pMatrix[1];
|
||
m_arrMatrix[2] = pMatrix[2]; m_arrMatrix[3] = pMatrix[3];
|
||
m_arrMatrix[4] = pMatrix[4]; m_arrMatrix[5] = pMatrix[5];
|
||
}
|
||
return;
|
||
}
|
||
}
|