#include "stdafx.h" #include #include #include #include #include "MemoryUtils.h" #include "Object.h" #include "Dict.h" #include "GlobalParams.h" #include "CMap.h" #include "CharCodeToUnicode.h" #include "EncodingTables.h" #include "BuiltinFontTables.h" #include "FontFileType1.h" #include "FontFileType1C.h" #include "FontFileTrueType.h" #include "GFont.h" #include "File.h" //------------------------------------------------------------------------ struct StandardFontMapEntry { char *sAlternativeName; char *sProperName; }; // PDF поддерживает 14 стандартных фонтов(Type1) без указаниях ширин и FontDescriptor, // поэтому мы состовляем карту отображающую стандартные фонты в 14 основных фонтов PDF. // Эта таблица составлена на основе "implementation note 44 in the PDF 1.4 spec", с // небольшими добавками. static StandardFontMapEntry c_sStandardFontMap[] = { { "Arial", "Helvetica" }, { "Arial,Bold", "Helvetica-Bold" }, { "Arial,BoldItalic", "Helvetica-BoldOblique" }, { "Arial,Italic", "Helvetica-Oblique" }, { "Arial-Bold", "Helvetica-Bold" }, { "Arial-BoldItalic", "Helvetica-BoldOblique" }, { "Arial-BoldItalicMT", "Helvetica-BoldOblique" }, { "Arial-BoldMT", "Helvetica-Bold" }, { "Arial-Italic", "Helvetica-Oblique" }, { "Arial-ItalicMT", "Helvetica-Oblique" }, { "ArialMT", "Helvetica" }, { "Courier,Bold", "Courier-Bold" }, { "Courier,BoldItalic", "Courier-BoldOblique" }, { "Courier,Italic", "Courier-Oblique" }, { "CourierNew", "Courier" }, { "CourierNew,Bold", "Courier-Bold" }, { "CourierNew,BoldItalic", "Courier-BoldOblique" }, { "CourierNew,Italic", "Courier-Oblique" }, { "CourierNew-Bold", "Courier-Bold" }, { "CourierNew-BoldItalic", "Courier-BoldOblique" }, { "CourierNew-Italic", "Courier-Oblique" }, { "CourierNewPS-BoldItalicMT", "Courier-BoldOblique" }, { "CourierNewPS-BoldMT", "Courier-Bold" }, { "CourierNewPS-ItalicMT", "Courier-Oblique" }, { "CourierNewPSMT", "Courier" }, { "Helvetica,Bold", "Helvetica-Bold" }, { "Helvetica,BoldItalic", "Helvetica-BoldOblique" }, { "Helvetica,Italic", "Helvetica-Oblique" }, { "Helvetica-BoldItalic", "Helvetica-BoldOblique" }, { "Helvetica-Italic", "Helvetica-Oblique" }, { "Symbol,Bold", "Symbol" }, { "Symbol,BoldItalic", "Symbol" }, { "Symbol,Italic", "Symbol" }, { "TimesNewRoman", "Times-Roman" }, { "TimesNewRoman,Bold", "Times-Bold" }, { "TimesNewRoman,BoldItalic", "Times-BoldItalic" }, { "TimesNewRoman,Italic", "Times-Italic" }, { "TimesNewRoman-Bold", "Times-Bold" }, { "TimesNewRoman-BoldItalic", "Times-BoldItalic" }, { "TimesNewRoman-Italic", "Times-Italic" }, { "TimesNewRomanPS", "Times-Roman" }, { "TimesNewRomanPS-Bold", "Times-Bold" }, { "TimesNewRomanPS-BoldItalic", "Times-BoldItalic" }, { "TimesNewRomanPS-BoldItalicMT", "Times-BoldItalic" }, { "TimesNewRomanPS-BoldMT", "Times-Bold" }, { "TimesNewRomanPS-Italic", "Times-Italic" }, { "TimesNewRomanPS-ItalicMT", "Times-Italic" }, { "TimesNewRomanPSMT", "Times-Roman" }, { "TimesNewRomanPSMT,Bold", "Times-Bold" }, { "TimesNewRomanPSMT,BoldItalic", "Times-BoldItalic" }, { "TimesNewRomanPSMT,Italic", "Times-Italic" } }; //------------------------------------------------------------------------ // GrFont //------------------------------------------------------------------------ GrFont *GrFont::MakeFont(XRef *pXref, char *sTag, Ref oID, Dict *pFontDict, GlobalParams *pGlobalParams) { // Считываем название шрифта StringExt *seName = NULL; Object oTemp; pFontDict->Search( "BaseFont", &oTemp); if ( oTemp.IsName() ) { seName = new StringExt( oTemp.GetName() ); } oTemp.Free(); // Тип шрифта GrFont *pFont = NULL; pFontDict->Search( "Subtype", &oTemp ); if ( oTemp.IsName("Type1") || oTemp.IsName("MMType1") ) { pFont = new Gr8BitFont( pXref, sTag, oID, seName, fontType1, pFontDict, pGlobalParams); } else if ( oTemp.IsName("Type1C") ) { pFont = new Gr8BitFont( pXref, sTag, oID, seName, fontType1C, pFontDict, pGlobalParams); } else if ( oTemp.IsName("Type3") ) { pFont = new Gr8BitFont( pXref, sTag, oID, seName, fontType3, pFontDict, pGlobalParams); } else if ( oTemp.IsName("TrueType") ) { pFont = new Gr8BitFont( pXref, sTag, oID, seName, fontTrueType, pFontDict, pGlobalParams); } else if ( oTemp.IsName("Type0") ) { pFont = new GrCIDFont( pXref, sTag, oID, seName, pFontDict, pGlobalParams); } else { // TO DO: Error "Unknown font type" pFont = new Gr8BitFont( pXref, sTag, oID, seName, fontUnknownType, pFontDict, pGlobalParams); } oTemp.Free(); return pFont; } GrFont::GrFont(char *sTag, Ref oID, StringExt *seName, GlobalParams *pGlobalParams) { m_pGlobalParams = pGlobalParams; m_bValid = FALSE; m_seTag = new StringExt( sTag ); m_oID = oID; m_seName = seName; m_seOriginalName = seName; m_seEmbeddedFontName = NULL; m_wsExternalFontFilePath = _T(""); } GrFont::~GrFont() { if ( m_seTag ) { delete m_seTag; } if ( m_seOriginalName && m_seOriginalName != m_seName ) { delete m_seOriginalName; } if ( m_seName ) { delete m_seName; } if ( m_seEmbeddedFontName ) { delete m_seEmbeddedFontName; } } void GrFont::ReadFontDescriptor(XRef *pXref, Dict *pFontDict) { m_nFlags = fontSerif; m_oEmbFontFileRef.nNum = -1; m_oEmbFontFileRef.nGen = -1; m_dMissingWidth = 0; Object oFontDescriptor; if ( pFontDict->Search("FontDescriptor", &oFontDescriptor)->IsDict() ) { // Flags Object oDictItem; if ( oFontDescriptor.DictLookup("Flags", &oDictItem)->IsInt() ) { m_nFlags = oDictItem.GetInt(); } oDictItem.Free(); // FontName oFontDescriptor.DictLookup("FontName", &oDictItem); if ( oDictItem.IsName() ) { m_seEmbeddedFontName = new StringExt( oDictItem.GetName()); } oDictItem.Free(); // Ищем внедренный FontFile if ( oFontDescriptor.DictLookupAndCopy("FontFile", &oDictItem)->IsRef() ) { m_oEmbFontFileRef = oDictItem.GetRef(); if ( m_eType != fontType1 ) { // TO DO: Error "Mismatch between font type and embedded font file" m_eType = fontType1; } } oDictItem.Free(); if ( m_oEmbFontFileRef.nNum == -1 && oFontDescriptor.DictLookupAndCopy("FontFile2", &oDictItem)->IsRef() ) { m_oEmbFontFileRef = oDictItem.GetRef(); if ( m_eType != fontTrueType && m_eType != fontCIDType2 ) { // TO DO: Error "Mismatch between font type and embedded font file" m_eType = (m_eType == fontCIDType0 ? fontCIDType2 : fontTrueType); } } oDictItem.Free(); if ( m_oEmbFontFileRef.nNum == -1 && oFontDescriptor.DictLookupAndCopy("FontFile3", &oDictItem)->IsRef() ) { Object oStream; if ( oDictItem.Fetch( pXref, &oStream)->IsStream() ) { Object oTemp; oStream.StreamGetDict()->Search("Subtype", &oTemp); if ( oTemp.IsName("Type1") ) { m_oEmbFontFileRef = oDictItem.GetRef(); if ( m_eType != fontType1 ) { // TO DO: Error "Mismatch between font type and embedded font file" m_eType = fontType1; } } else if ( oTemp.IsName("Type1C") ) { m_oEmbFontFileRef = oDictItem.GetRef(); if ( m_eType != fontType1 && m_eType != fontType1C) { // TO DO: Error "Mismatch between font type and embedded font file" } m_eType = fontType1C; } else if ( oTemp.IsName("TrueType") ) { m_oEmbFontFileRef = oDictItem.GetRef(); if ( m_eType != fontTrueType ) { // TO DO: Error "Mismatch between font type and embedded font file" m_eType = fontTrueType; } } else if ( oTemp.IsName("CIDFontType0C") ) { m_oEmbFontFileRef = oDictItem.GetRef(); if ( m_eType != fontCIDType0 ) { // TO DO: Error "Mismatch between font type and embedded font file" } m_eType = fontCIDType0C; } else if ( oTemp.IsName("OpenType") ) { m_oEmbFontFileRef = oDictItem.GetRef(); if ( m_eType == fontTrueType ) { m_eType = fontTrueTypeOT; } else if ( m_eType == fontType1 ) { m_eType = fontType1COT; } else if ( m_eType == fontCIDType0 ) { m_eType = fontCIDType0COT; } else if ( m_eType == fontCIDType2 ) { m_eType = fontCIDType2OT; } else { // TO DO: Error "Mismatch between font type and embedded font file" } } else { // TO DO: Error "Unknown embedded font type" } oTemp.Free(); } oStream.Free(); } oDictItem.Free(); // MissingWidth oFontDescriptor.DictLookup("MissingWidth", &oDictItem); if ( oDictItem.IsNum() ) { m_dMissingWidth = oDictItem.GetNum(); } oDictItem.Free(); double dTemp = 0; // Ascent oFontDescriptor.DictLookup("Ascent", &oDictItem); if ( oDictItem.IsNum() ) { dTemp = 0.001 * oDictItem.GetNum(); // Некоторые неправильнае шрифты устанавливают Ascent и Descent равными 0 if ( dTemp != 0 ) { m_dAscent = dTemp; } } oDictItem.Free(); // Descent oFontDescriptor.DictLookup("Descent", &oDictItem); if ( oDictItem.IsNum() ) { dTemp = 0.001 * oDictItem.GetNum(); // Некоторые неправильнае шрифты устанавливают Ascent и Descent равными 0 if ( dTemp != 0 ) { m_dDescent = dTemp; } // Descent должно быть отрицательным значением if ( m_dDescent > 0 ) { m_dDescent = -m_dDescent; } } oDictItem.Free(); // FontBBox if ( oFontDescriptor.DictLookup("FontBBox", &oDictItem)->IsArray() ) { for ( int nIndex = 0; nIndex < 4 && nIndex < oDictItem.ArrayGetLength(); ++nIndex ) { Object oTemp; if ( oDictItem.ArrayGet( nIndex, &oTemp)->IsNum() ) { m_arrFontBBox[nIndex] = 0.001 * oTemp.GetNum(); } oTemp.Free(); } } oDictItem.Free(); } oFontDescriptor.Free(); } CharCodeToUnicode *GrFont::ReadToUnicodeCMap(Dict *pFontDict, int nBitsCount, CharCodeToUnicode *pCharToUnicode) { Object oTemp; if ( !pFontDict->Search("ToUnicode", &oTemp)->IsStream() ) { oTemp.Free(); return NULL; } StringExt *seBuffer = new StringExt(); oTemp.StreamReset(); int nChar = 0; while ( ( nChar = oTemp.StreamGetChar() ) != EOF ) { seBuffer->Append( nChar ); } oTemp.StreamClose(); oTemp.Free(); if ( pCharToUnicode ) { pCharToUnicode->MergeCMap( seBuffer, nBitsCount, m_pGlobalParams ); } else { pCharToUnicode = CharCodeToUnicode::ParseCMap( seBuffer, nBitsCount, m_pGlobalParams ); } delete seBuffer; return pCharToUnicode; } void GrFont::FindExternalFontFile() { static wchar_t *c_wsType1Ext[] = { _T(".pfa"), _T(".pfb"), _T(".ps"), _T(""), NULL }; static wchar_t *c_wsTTFExts[] = { _T(".ttf"), NULL }; if ( m_pGlobalParams && m_seName ) { if ( m_eType == fontType1 ) { m_wsExternalFontFilePath = m_pGlobalParams->FindFontFile( m_seName, c_wsType1Ext ); } else if ( m_eType == fontTrueType ) { m_wsExternalFontFilePath = m_pGlobalParams->FindFontFile( m_seName, c_wsTTFExts ); } } } char *GrFont::ReadExternalFontFile(int *pnLen) { FILE *pFile = NULL; if ( !( pFile = _wfopen( m_wsExternalFontFilePath.GetBuffer(), _T("rb") ) ) ) { // TO DO: Error "External font file vanished" return NULL; } fseek( pFile, 0, SEEK_END); *pnLen = (int)ftell( pFile ); fseek( pFile, 0, SEEK_SET); char *sBuffer = (char *)MemUtilsMalloc( *pnLen ); if ( (int)fread( sBuffer, 1, *pnLen, pFile) != *pnLen ) { // TO DO: Error "Error reading external font file" } fclose( pFile ); return sBuffer; } char *GrFont::ReadEmbeddedFontFile(XRef *pXref, int *pnLen) { Object oFontFile; oFontFile.InitRef( m_oEmbFontFileRef.nNum, m_oEmbFontFileRef.nGen ); Object oStream; oFontFile.Fetch( pXref, &oStream ); if ( !oStream.IsStream() ) { // TO DO: Error "Embedded font file is not a stream" oStream.Free(); oFontFile.Free(); m_oEmbFontFileRef.nNum = -1; return NULL; } Stream *pStream = oStream.GetStream(); char *sBuffer = NULL; int nSize = 0; int nIndex = 0; pStream->Reset(); int nChar = 0; while ( ( nChar = pStream->GetChar() ) != EOF ) { if ( nIndex == nSize ) { nSize += 4096; sBuffer = (char *)MemUtilsRealloc( sBuffer, nSize); } sBuffer[nIndex++] = nChar; } *pnLen = nIndex; pStream->Close(); oStream.Free(); oFontFile.Free(); return sBuffer; } //------------------------------------------------------------------------ // Gr8BitFont //------------------------------------------------------------------------ Gr8BitFont::Gr8BitFont(XRef *pXref, char *sTag, Ref oID, StringExt *seName, GrFontType eType, Dict *pFontDict, GlobalParams *pGlobalParams): GrFont(sTag, oID, seName, pGlobalParams) { m_eType = eType; m_pCharToUnicode = NULL; if ( m_seName ) { StringExt *seName2 = m_seName->Copy(); int nIndex = 0; while ( nIndex < seName2->GetLength() ) { if ( seName2->GetAt(nIndex) == ' ' ) { seName2->Delete(nIndex); } else { ++nIndex; } } int nFirst = 0; int nLast = sizeof(c_sStandardFontMap) / sizeof(StandardFontMapEntry); // Поиск методом деления отрезка пополам while ( nLast - nFirst > 1 ) { int nMiddle = (nFirst + nLast) / 2; if ( seName2->Compare( c_sStandardFontMap[nMiddle].sAlternativeName) >= 0 ) { nFirst = nMiddle; } else { nLast = nMiddle; } } if ( !seName2->Compare( c_sStandardFontMap[nFirst].sAlternativeName ) ) { m_seName = new StringExt( c_sStandardFontMap[nFirst].sProperName ); } delete seName2; } // Смотрим является ли наш фонт одним из 14 стандартных BuiltinFont *pBuiltinFont = NULL; if ( m_seName ) { for ( int nIndex = 0; nIndex < BuiltinFontsCount; ++nIndex ) { if ( !m_seName->Compare( c_arrBuiltinFonts[nIndex].sName ) ) { pBuiltinFont = &c_arrBuiltinFonts[nIndex]; break; } } } // Выставляем стандартные значения для Ascent/Descent/BBox if ( pBuiltinFont ) { m_dAscent = 0.001 * pBuiltinFont->nAscent; m_dDescent = 0.001 * pBuiltinFont->nDescent; m_arrFontBBox[0] = 0.001 * pBuiltinFont->arrBBox[0]; m_arrFontBBox[1] = 0.001 * pBuiltinFont->arrBBox[1]; m_arrFontBBox[2] = 0.001 * pBuiltinFont->arrBBox[2]; m_arrFontBBox[3] = 0.001 * pBuiltinFont->arrBBox[3]; } else { m_dAscent = 0.95; m_dDescent = -0.35; m_arrFontBBox[0] = m_arrFontBBox[1] = m_arrFontBBox[2] = m_arrFontBBox[3] = 0; } // Считываем данные из FontDescriptor ReadFontDescriptor( pXref, pFontDict); // Для стандартных фонтов выставляем стандартные значения Ascent/Descent/BBox if ( pBuiltinFont && m_oEmbFontFileRef.nNum < 0 ) { m_dAscent = 0.001 * pBuiltinFont->nAscent; m_dDescent = 0.001 * pBuiltinFont->nDescent; m_arrFontBBox[0] = 0.001 * pBuiltinFont->arrBBox[0]; m_arrFontBBox[1] = 0.001 * pBuiltinFont->arrBBox[1]; m_arrFontBBox[2] = 0.001 * pBuiltinFont->arrBBox[2]; m_arrFontBBox[3] = 0.001 * pBuiltinFont->arrBBox[3]; } // Ищем внешний FontFile FindExternalFontFile(); // FontMatrix m_arrFontMatrix[0] = m_arrFontMatrix[3] = 1; m_arrFontMatrix[1] = m_arrFontMatrix[2] = m_arrFontMatrix[4] = m_arrFontMatrix[5] = 0; Object oDictItem; if ( pFontDict->Search("FontMatrix", &oDictItem)->IsArray() ) { for ( int nIndex = 0; nIndex < 6 && nIndex < oDictItem.ArrayGetLength(); ++nIndex ) { Object oTemp; if ( oDictItem.ArrayGet( nIndex, &oTemp)->IsNum() ) { m_arrFontMatrix[nIndex] = oTemp.GetNum(); } oTemp.Free(); } } oDictItem.Free(); // Считываем данные, характерные для шрифта Type 3 if ( m_eType == fontType3 ) { if ( pFontDict->Search("FontBBox", &oDictItem)->IsArray() ) { for ( int nIndex = 0; nIndex < 4 && nIndex < oDictItem.ArrayGetLength(); ++nIndex ) { Object oTemp; if ( oDictItem.ArrayGet( nIndex, &oTemp)->IsNum() ) { m_arrFontBBox[nIndex] = oTemp.GetNum(); } oTemp.Free(); } } oDictItem.Free(); if ( !pFontDict->Search("CharProcs", &m_oCharProcs)->IsDict() ) { // TO DO: Error "Missing or invalid CharProcs dictionary in Type 3 font" m_oCharProcs.Free(); } if ( !pFontDict->Search("Resources", &m_oResources)->IsDict() ) { m_oResources.Free(); } } //----- Строим Encoding ----- // Encodings начинается с BaseEncoding, которую мы можем найти в // (в порядке приоритета): // 1. pFontDict.Encoding or pFontDict.Encoding.BaseEncoding // - MacRoman / MacExpert / WinAnsi / Standard // 2. Во внедренном или внешнем FontFile // 3. Стандартные значения(если до этого не нашли): // - Builtin --> Builtin encoding // - TrueType --> WinAnsiEncoding // - Остальные --> StandardEncoding // Ищем BaseEncoding в pFontDict m_bHasEncoding = FALSE; m_bUsesMacRomanEncoding = FALSE; char **ppBaseEncoding = NULL; BOOL bBaseEncodingFromFontFile = FALSE; pFontDict->Search("Encoding", &oDictItem); if ( oDictItem.IsDict() ) { Object oTemp; oDictItem.DictLookup("BaseEncoding", &oTemp); if ( oTemp.IsName("MacRomanEncoding") ) { m_bHasEncoding = TRUE; m_bUsesMacRomanEncoding = TRUE; ppBaseEncoding = c_arrMacRomanEncoding; } else if ( oTemp.IsName("MacExpertEncoding") ) { m_bHasEncoding = TRUE; ppBaseEncoding = c_arrMacExpertEncoding; } else if ( oTemp.IsName("WinAnsiEncoding") ) { m_bHasEncoding = TRUE; ppBaseEncoding = c_arrWinAnsiEncoding; } oTemp.Free(); } else if ( oDictItem.IsName("MacRomanEncoding") ) { m_bHasEncoding = TRUE; m_bUsesMacRomanEncoding = TRUE; ppBaseEncoding = c_arrMacRomanEncoding; } else if ( oDictItem.IsName("MacExpertEncoding") ) { m_bHasEncoding = TRUE; ppBaseEncoding = c_arrMacExpertEncoding; } else if ( oDictItem.IsName("WinAnsiEncoding") ) { m_bHasEncoding = TRUE; ppBaseEncoding = c_arrWinAnsiEncoding; } // Ищем BaseEncoding в FontFile(только для Type1) CFontFileType1 *pFFT1 = NULL; CFontFileType1C *pFFT1C = NULL; char *sBuffer = NULL; int nLen = 0; if ( m_eType == fontType1 && ( _T("") != m_wsExternalFontFilePath || m_oEmbFontFileRef.nNum >= 0 ) ) { if ( _T("") != m_wsExternalFontFilePath ) { pFFT1 = CFontFileType1::LoadFromFile( m_wsExternalFontFilePath.GetBuffer() ); } else { sBuffer = ReadEmbeddedFontFile( pXref, &nLen); pFFT1 = CFontFileType1::LoadFromBuffer( sBuffer, nLen); } if ( pFFT1 ) { if ( pFFT1->GetName() ) { if ( m_seEmbeddedFontName ) { delete m_seEmbeddedFontName; } m_seEmbeddedFontName = new StringExt( pFFT1->GetName() ); } if ( !ppBaseEncoding ) { ppBaseEncoding = pFFT1->GetEncoding(); bBaseEncodingFromFontFile = TRUE; } } } else if ( m_eType == fontType1C && ( _T("") != m_wsExternalFontFilePath || m_oEmbFontFileRef.nNum >= 0 ) ) { if ( _T("") != m_wsExternalFontFilePath ) { pFFT1C = CFontFileType1C::LoadFromFile( m_wsExternalFontFilePath.GetBuffer() ); } else { sBuffer = ReadEmbeddedFontFile( pXref, &nLen); pFFT1C = CFontFileType1C::LoadFromBuffer( sBuffer, nLen); } if ( pFFT1C ) { if ( pFFT1C->GetName() ) { if ( m_seEmbeddedFontName ) { delete m_seEmbeddedFontName; } m_seEmbeddedFontName = new StringExt( pFFT1C->GetName() ); } if ( !ppBaseEncoding ) { ppBaseEncoding = pFFT1C->GetEncoding(); bBaseEncodingFromFontFile = TRUE; } } } if ( sBuffer ) { MemUtilsFree( sBuffer ); } // Стандартные значения BaseEncoding if ( !ppBaseEncoding ) { if ( pBuiltinFont && m_oEmbFontFileRef.nNum < 0 ) { ppBaseEncoding = pBuiltinFont->ppDefaultBaseEncoding; m_bHasEncoding = TRUE; } else if ( m_eType == fontTrueType ) { ppBaseEncoding = c_arrWinAnsiEncoding; } else { ppBaseEncoding = c_arrStandardEncoding; } } // copy the base encoding for ( int nIndex = 0; nIndex < 256; ++nIndex ) { m_ppEncoding[nIndex] = ppBaseEncoding[nIndex]; if ( ( m_arrEncFree[nIndex] = bBaseEncodingFromFontFile ) && m_ppEncoding[nIndex] ) { m_ppEncoding[nIndex] = CopyString( ppBaseEncoding[nIndex] ); } } // Некоторые Type 1C Font Files имею пустые кодировки, что может навредить конвертации T1C->T1, // поэтому мы заполняем все пустые места из StandardEncoding if ( m_eType == fontType1C && ( _T("") != m_wsExternalFontFilePath || m_oEmbFontFileRef.nNum >= 0 ) && bBaseEncodingFromFontFile ) { for ( int nIndex = 0; nIndex < 256; ++nIndex ) { if ( !m_ppEncoding[nIndex] && c_arrStandardEncoding[nIndex] ) { m_ppEncoding[nIndex] = c_arrStandardEncoding[nIndex]; m_arrEncFree[nIndex] = FALSE; } } } // Differences if ( oDictItem.IsDict() ) { Object oDifferences; oDictItem.DictLookup("Differences", &oDifferences); if ( oDifferences.IsArray() ) { m_bHasEncoding = TRUE; int nCode = 0; for ( int nIndex = 0; nIndex < oDifferences.ArrayGetLength(); ++nIndex ) { Object oTemp; oDifferences.ArrayGet( nIndex, &oTemp); if ( oTemp.IsInt() ) { nCode = oTemp.GetInt(); } else if ( oTemp.IsName() ) { if ( nCode >= 0 && nCode < 256 ) { if ( m_arrEncFree[nCode] ) { MemUtilsFree( m_ppEncoding[nCode] ); } m_ppEncoding[nCode] = CopyString( oTemp.GetName() ); m_arrEncFree[nCode] = TRUE; } ++nCode; } else { // TO DO: Error "Wrong type in font encoding resource differences" } oTemp.Free(); } } oDifferences.Free(); } oDictItem.Free(); if ( pFFT1 ) { delete pFFT1; } if ( pFFT1C ) { delete pFFT1C; } //----- build the mapping to Unicode ----- // Шаг 1: Используем соответствие Name-to-Unicode BOOL bMissing = FALSE, bHex = FALSE; char *sCharName; Unicode arrToUnicode[256]; for ( int nCode = 0; nCode < 256; ++nCode ) { if ( ( sCharName = m_ppEncoding[nCode] ) ) { if ( m_pGlobalParams && !( arrToUnicode[nCode] = m_pGlobalParams->MapNameToUnicode(sCharName) ) && strcmp( sCharName, ".notdef") ) { // Если данного символа не было в таблице Name-to-Unicode table, проверяем // как выглядит Name. ( либо 'Axx', либо 'xx', где 'A' - произвольная буква // и 'xx' - два шестнадцатиричных числа if ( ( strlen(sCharName) == 3 && isalpha(sCharName[0]) && isxdigit(sCharName[1]) && isxdigit(sCharName[2]) && (( sCharName[1] >= 'a' && sCharName[1] <= 'f' ) || ( sCharName[1] >= 'A' && sCharName[1] <= 'F' ) || ( sCharName[2] >= 'a' && sCharName[2] <= 'f' ) || ( sCharName[2] >= 'A' && sCharName[2] <= 'F' ) ) ) || ( strlen(sCharName) == 2 && isxdigit(sCharName[0]) && isxdigit(sCharName[1]) && (( sCharName[0] >= 'a' && sCharName[0] <= 'f' ) || ( sCharName[0] >= 'A' && sCharName[0] <= 'F' ) || ( sCharName[1] >= 'a' && sCharName[1] <= 'f' ) || ( sCharName[1] >= 'A' && sCharName[1] <= 'F' ) ) ) ) { bHex = TRUE; } bMissing = TRUE; } } else { arrToUnicode[nCode] = 0; } } // Шаг 2: Заполняем пропущенные символы, ищем имена одного из видов // 'Axx', 'xx', 'Ann', 'ABnn' или 'nn', где 'A' и 'B' - любые буквы, // 'xx' - два шестнадцатиричных числа, и 'nn' - 2-4 десятичных числа if ( bMissing && m_pGlobalParams && m_pGlobalParams->GetMapNumericCharNames() ) { for ( int nCode = 0; nCode < 256; ++nCode ) { if ( ( sCharName = m_ppEncoding[nCode] ) && !arrToUnicode[nCode] && strcmp(sCharName, ".notdef") ) { int nCount = strlen(sCharName); int nCode2 = -1; if ( bHex && nCount == 3 && isalpha(sCharName[0]) && isxdigit(sCharName[1]) && isxdigit(sCharName[2]) ) { sscanf(sCharName + 1, "%x", &nCode2); } else if ( bHex && nCount == 2 && isxdigit(sCharName[0]) && isxdigit(sCharName[1]) ) { sscanf(sCharName, "%x", &nCode2); } else if ( !bHex && nCount >= 2 && nCount <= 4 && isdigit(sCharName[0]) && isdigit(sCharName[1]) ) { nCode2 = atoi(sCharName); } else if ( nCount >= 3 && nCount <= 5 && isdigit(sCharName[1]) && isdigit(sCharName[2]) ) { nCode2 = atoi(sCharName + 1); } else if ( nCount >= 4 && nCount <= 6 && isdigit(sCharName[2]) && isdigit(sCharName[3]) ) { nCode2 = atoi(sCharName + 2); } if ( nCode2 >= 0 && nCode2 <= 0xff ) { arrToUnicode[nCode] = (Unicode)nCode2; } } } } else if ( bMissing && m_pGlobalParams && m_pGlobalParams->GetMapUnknownCharNames() ) // Если установлен флаг 'mapUnknownCharNames' { for ( int nCode = 0; nCode < 256; ++nCode ) { if ( !arrToUnicode[nCode] ) { arrToUnicode[nCode] = nCode; } } } m_pCharToUnicode = CharCodeToUnicode::Make8BitToUnicode( arrToUnicode ); // ToUnicode CMap ReadToUnicodeCMap( pFontDict, 8, m_pCharToUnicode); // Ищем Unicode-to-Unicode CharCodeToUnicode *pUnicodeToUnicode, *pCharToUnicode; if ( m_seName && m_pGlobalParams && ( pUnicodeToUnicode = m_pGlobalParams->GetUnicodeToUnicode(m_seName) ) ) { for ( int nIndex = 0; nIndex < 256; ++nIndex ) { arrToUnicode[nIndex] = 0; } pCharToUnicode = CharCodeToUnicode::Make8BitToUnicode( arrToUnicode ); for ( int nIndex = 0; nIndex < 256; ++nIndex ) { Unicode arrUnicodeBuf[8]; int nCount = m_pCharToUnicode->MapToUnicode( (CharCode)nIndex, arrUnicodeBuf, 8); if ( nCount >= 1 ) { nCount = pUnicodeToUnicode->MapToUnicode( (CharCode)arrUnicodeBuf[0], arrUnicodeBuf, 8); if ( nCount >= 1 ) { pCharToUnicode->SetMapping( (CharCode)nIndex, arrUnicodeBuf, nCount); } } } pUnicodeToUnicode->Release(); if ( m_pCharToUnicode ) delete m_pCharToUnicode; m_pCharToUnicode = pCharToUnicode; } // Widths for ( int nCode = 0; nCode < 256; ++nCode ) { m_arrWidths[nCode] = m_dMissingWidth * 0.001; } // Используем шириные из pFontDict, если они там заданы pFontDict->Search("FirstChar", &oDictItem); int nFirstChar = oDictItem.IsInt() ? oDictItem.GetInt() : 0; oDictItem.Free(); if ( nFirstChar < 0 || nFirstChar > 255 ) { nFirstChar = 0; } pFontDict->Search("LastChar", &oDictItem); int nLastChar = oDictItem.IsInt() ? oDictItem.GetInt() : 255; oDictItem.Free(); if ( nLastChar < 0 || nLastChar > 255 ) { nLastChar = 255; } double dMult = ( m_eType == fontType3 ) ? m_arrFontMatrix[0] : 0.001; pFontDict->Search("Widths", &oDictItem); if ( oDictItem.IsArray() ) { m_nFlags |= fontFixedWidth; if ( oDictItem.ArrayGetLength() < nLastChar - nFirstChar + 1 ) { nLastChar = nFirstChar + oDictItem.ArrayGetLength() - 1; } for ( int nCode = nFirstChar; nCode <= nLastChar; ++nCode ) { Object oTemp; oDictItem.ArrayGet( nCode - nFirstChar, &oTemp); if ( oTemp.IsNum() ) { m_arrWidths[nCode] = oTemp.GetNum() * dMult; if ( m_arrWidths[nCode] != m_arrWidths[nFirstChar] ) { m_nFlags &= ~fontFixedWidth; } } oTemp.Free(); } } else if ( pBuiltinFont ) // Используем ширины из Built-in шрифта { // Некорректные PDF-файлы кодируют символ с номером 32 как .notdef(хотя это пробел) unsigned short unWidth = 0; if ( BuiltinFontGetWidth( pBuiltinFont, "space", &unWidth ) ) { m_arrWidths[32] = 0.001 * unWidth; } for ( int nCode = 0; nCode < 256; ++nCode ) { if ( m_ppEncoding[nCode] && BuiltinFontGetWidth( pBuiltinFont, m_ppEncoding[nCode], &unWidth ) ) { m_arrWidths[nCode] = 0.001 * unWidth; } } } else // Ширины не заданы - заполняем стандартными значениями { int nIndex = 0; if ( IsFixedWidth() ) { nIndex = 0; } else if ( IsSerif() ) { nIndex = 8; } else { nIndex = 4; } if ( IsBold() ) { nIndex += 2; } if ( IsItalic() ) { nIndex += 1; } pBuiltinFont = c_arrBuiltinFontSubset[nIndex]; // Некорректные PDF-файлы кодируют символ с номером 32 как .notdef(хотя это пробел) unsigned short unWidth = 0; if ( BuiltinFontGetWidth( pBuiltinFont, "space", &unWidth ) ) { m_arrWidths[32] = 0.001 * unWidth; } for ( int nCode = 0; nCode < 256; ++nCode ) { if ( m_ppEncoding[nCode] && BuiltinFontGetWidth( pBuiltinFont, m_ppEncoding[nCode], &unWidth ) ) { m_arrWidths[nCode] = 0.001 * unWidth; } } } oDictItem.Free(); m_bValid = TRUE; } Gr8BitFont::~Gr8BitFont() { for ( int nIndex = 0; nIndex < 256; ++nIndex ) { if ( m_arrEncFree[nIndex] && m_ppEncoding[nIndex] ) { MemUtilsFree(m_ppEncoding[nIndex]); } } m_pCharToUnicode->Release(); if ( m_oCharProcs.IsDict() ) { m_oCharProcs.Free(); } if ( m_oResources.IsDict() ) { m_oResources.Free(); } } int Gr8BitFont::GetNextChar(char *sText, int nLen, CharCode *punCode, Unicode *punUnicode, int uSize, int *uLen, double *pdDx, double *pdDy, double *pdVx, double *pdVy) { CharCode nCharCode; *punCode = nCharCode = (CharCode)(*sText & 0xff); *uLen = m_pCharToUnicode->MapToUnicode( nCharCode, punUnicode, uSize); *pdDx = m_arrWidths[nCharCode]; *pdDy = *pdVx = *pdVy = 0; return 1; } CharCodeToUnicode *Gr8BitFont::GetToUnicode() { m_pCharToUnicode->AddRef(); return m_pCharToUnicode; } unsigned short *Gr8BitFont::GetCodeToGIDMap(CFontFileTrueType *pTTF) { unsigned short *pMap = (unsigned short *)MemUtilsMallocArray( 256, sizeof(unsigned short) ); for ( int nIndex = 0; nIndex < 256; ++nIndex ) { pMap[nIndex] = 0; } // 1. Если в PDF задана кодировка: // 1a. Если в PDF шрифте определна кодировка MacRomanEncoding и // TrueType-шрифт имеет Macintosh Roman CMap, используем его, // и получем обатно по именам коды символов. // 1b. Если TrueType-шрифт имеет Microsoft Unicode CMap или // non-Microsoft Unicode CMap, используем его, и используем // юникодные номера, а не коды символов. // 1c. Если PDF-шрифт - Symbolic и TrueType-шрифт имеет // Microsoft Symbol CMap, используем его, и используем сами // коды символов (возможно со сдвигом 0xf000). // 1d. Если TrueType-шрифт имеет Macintosh Roman CMap, используем // его как и в случае 1a. // 2. Если PDF-шрифт не имеет кодировки или PDF-шрифт - Symbolic: // 2a. Если TrueType-шрифт имеет Macintosh Roman CMap, используем // его, и используем сами коды символов (возможно со сдвигом // 0xf000). // 2b. Если TrueType-шрифт имеет Microsoft Symbol CMap, используем // его, и используем сами коды символов (возможно со сдвигом // 0xf000). // 3. Если не один из этих случаев не применим, тогда используем первый // CMap. (но такого не должно происходить) // TO DO: Возможна ситуация, когда одинаковых кодировок несколько, и в они содерржат // разные символы. В таких случаях надо бы делать общую кодировку, а не считывать // одну конкретную. int nUnicodeCmap = -1, nMacRomanCmap = -1, nMSSymbolCmap = -1; int nCmapPlatform = 0, nCmapEncoding = 0; for ( int nIndex = 0; nIndex < pTTF->GetCmapsCount(); ++nIndex ) { nCmapPlatform = pTTF->GetCmapPlatform(nIndex); nCmapEncoding = pTTF->GetCmapEncoding(nIndex); if ( ( nCmapPlatform == 3 && nCmapEncoding == 1 ) || nCmapPlatform == 0 ) { nUnicodeCmap = nIndex; } else if ( nCmapPlatform == 1 && nCmapEncoding == 0 ) { nMacRomanCmap = nIndex; } else if ( nCmapPlatform == 3 && nCmapEncoding == 0 ) { nMSSymbolCmap = nIndex; } } int nCmap = 0; BOOL bUseMacRoman = FALSE; BOOL bUseUnicode = FALSE; if ( m_bHasEncoding ) { if ( m_bUsesMacRomanEncoding && nMacRomanCmap >= 0) { nCmap = nMacRomanCmap; bUseMacRoman = TRUE; } else if ( nUnicodeCmap >= 0 ) { nCmap = nUnicodeCmap; bUseUnicode = TRUE; } else if ( ( m_nFlags & fontSymbolic ) && nMSSymbolCmap >= 0 ) { nCmap = nMSSymbolCmap; } else if ( ( m_nFlags & fontSymbolic ) && nMacRomanCmap >= 0 ) { nCmap = nMacRomanCmap; } else if ( nMacRomanCmap >= 0 ) { nCmap = nMacRomanCmap; bUseMacRoman = TRUE; } } else { if ( nMSSymbolCmap >= 0 ) { nCmap = nMSSymbolCmap; } else if ( nMacRomanCmap >= 0 ) { nCmap = nMacRomanCmap; } } char *sCharName; int nCode = 0; if ( bUseMacRoman ) { for ( int nIndex = 0; nIndex < 256; ++nIndex ) { if ( ( sCharName = m_ppEncoding[nIndex] ) ) { if ( m_pGlobalParams && ( nCode = m_pGlobalParams->GetMacRomanCharCode(sCharName) ) ) { pMap[nIndex] = pTTF->MapCodeToGID( nCmap, nCode); } } } } else if ( bUseUnicode ) { for ( int nIndex = 0; nIndex < 256; ++nIndex ) { int nLen = 0; Unicode nUnicode = 0; if ( ( ( sCharName = m_ppEncoding[nIndex] ) && ( m_pGlobalParams ) && ( nUnicode = m_pGlobalParams->MapNameToUnicode(sCharName) ) ) || ( nLen = m_pCharToUnicode->MapToUnicode((CharCode)nIndex, &nUnicode, 1) ) ) { pMap[nIndex] = pTTF->MapCodeToGID( nCmap, nUnicode); } } } else { for ( int nIndex = 0; nIndex < 256; ++nIndex ) { if ( !( pMap[nIndex] = pTTF->MapCodeToGID( nCmap, nIndex) ) ) { pMap[nIndex] = pTTF->MapCodeToGID( nCmap, 0xf000 + nIndex); } } } for ( int nIndex = 0; nIndex < 256; ++nIndex ) { if ( !pMap[nIndex] && ( sCharName = m_ppEncoding[nIndex] ) ) { pMap[nIndex] = (unsigned short)(int)pTTF->MapNameToGID(sCharName); } } return pMap; } Dict *Gr8BitFont::GetCharProcs() { return m_oCharProcs.IsDict() ? m_oCharProcs.GetDict() : (Dict *)NULL; } Object *Gr8BitFont::GetCharProc(int nCode, Object *pProc) { if ( m_ppEncoding[nCode] && m_oCharProcs.IsDict() ) { m_oCharProcs.DictLookup( m_ppEncoding[nCode], pProc); } else { pProc->InitNull(); } return pProc; } Dict *Gr8BitFont::GetResources() { return m_oResources.IsDict() ? m_oResources.GetDict() : (Dict *)NULL; } //------------------------------------------------------------------------ // GrCIDFont //------------------------------------------------------------------------ static int CompareWidthExceptions(const void *pWidth1, const void *pWidth2) { return ((GrFontCIDWidthException *)pWidth1)->nFirst - ((GrFontCIDWidthException *)pWidth2)->nFirst; } static int CompareWidthExceptionsV(const void *pWidth1, const void *pWidth2) { return ((GrFontCIDWidthExceptionV *)pWidth1)->nFirst - ((GrFontCIDWidthExceptionV *)pWidth2)->nFirst; } GrCIDFont::GrCIDFont(XRef *pXref, char *sTag, Ref oID, StringExt *seName, Dict *pFontDict, GlobalParams *pGlobalParams): GrFont(sTag, oID, seName, pGlobalParams) { m_dAscent = 0.95; m_dDescent = -0.35; m_arrFontBBox[0] = m_arrFontBBox[1] = m_arrFontBBox[2] = m_arrFontBBox[3] = 0; m_pCMap = NULL; m_pCharToUnicode = NULL; m_oWidths.dDefaultWidth = 1.0; m_oWidths.dDefaultHeight = -1.0; m_oWidths.dDefaultV = 0.880; m_oWidths.pExceptions = NULL; m_oWidths.nExceptionsCount = 0; m_oWidths.pExceptionsV = NULL; m_oWidths.nExceptionsVCount = 0; m_pCidToGID = NULL; m_nCidToGIDLen = 0; // Descendant font Object oDictItem; if ( !pFontDict->Search("DescendantFonts", &oDictItem)->IsArray() ) { // TO DO: Error "Missing DescendantFonts entry in Type 0 font" oDictItem.Free(); return; } Object oDescendantObject; if ( !oDictItem.ArrayGet(0, &oDescendantObject)->IsDict() ) { // TO DO: Error "Bad descendant font in Type 0 font" oDescendantObject.Free(); oDictItem.Free(); return; } oDictItem.Free(); Dict *pDescendantDict = oDescendantObject.GetDict(); // Subtype if ( !pDescendantDict->Search("Subtype", &oDictItem) ) { // TO DO: Error "Missing Subtype entry in Type 0 descendant font" oDescendantObject.Free(); oDictItem.Free(); return; } if ( oDictItem.IsName("CIDFontType0") ) { m_eType = fontCIDType0; } else if ( oDictItem.IsName("CIDFontType2") ) { m_eType = fontCIDType2; } else { // TO DO: Error "Unknown Type 0 descendant font type" oDictItem.Free(); oDescendantObject.Free(); return; } oDictItem.Free(); ReadFontDescriptor( pXref, pDescendantDict); // Ищем внешний FontFile FindExternalFontFile(); // Кодировка // Char collection if ( !pDescendantDict->Search("CIDSystemInfo", &oDictItem)->IsDict() ) { // TO DO: Error "Missing CIDSystemInfo dictionary in Type 0 descendant font" oDescendantObject.Free(); oDictItem.Free(); return; } Object oRegistry; oDictItem.DictLookup("Registry", &oRegistry); Object oOrdering; oDictItem.DictLookup("Ordering", &oOrdering); if ( !oRegistry.IsString() || !oOrdering.IsString() ) { // TO DO: Error "Invalid CIDSystemInfo dictionary in Type 0 descendant font" oRegistry.Free(); oOrdering.Free(); oDescendantObject.Free(); oDictItem.Free(); return; } StringExt *seCollection = oRegistry.GetString()->Copy()->Append('-')->Append( oOrdering.GetString() ); oOrdering.Free(); oRegistry.Free(); oDictItem.Free(); // ToUnicode CMap if ( !( m_pCharToUnicode = ReadToUnicodeCMap( pFontDict, 16, NULL) ) ) { // "Adobe-Identity" и "Adobe-UCS" collections не имеют файлов СidToUnicode if ( seCollection->Compare("Adobe-Identity") && seCollection->Compare("Adobe-UCS") ) { // Ищем файлы cidToUnicode, данные извне if ( m_pGlobalParams && !( m_pCharToUnicode = m_pGlobalParams->GetCIDToUnicode(seCollection) ) ) { // TO DO: Error "Unknown character collection" } } } // Ищем Unicode-to-Unicode CharCodeToUnicode *pUnicodeToUnicode = NULL; if ( m_seName && m_pGlobalParams && ( pUnicodeToUnicode = m_pGlobalParams->GetUnicodeToUnicode(m_seName) ) ) { if ( m_pCharToUnicode ) { for ( CharCode nCharCode = 0; nCharCode < m_pCharToUnicode->GetLength(); ++nCharCode ) { Unicode arrUnicodeBuffer[8]; int nCount = m_pCharToUnicode->MapToUnicode( nCharCode, arrUnicodeBuffer, 8); if ( nCount >= 1 ) { nCount = pUnicodeToUnicode->MapToUnicode((CharCode)arrUnicodeBuffer[0], arrUnicodeBuffer, 8); if ( nCount >= 1) { m_pCharToUnicode->SetMapping( nCharCode, arrUnicodeBuffer, nCount); } } } pUnicodeToUnicode->Release(); } else { m_pCharToUnicode = pUnicodeToUnicode; } } // Кодировка (т.е. CMap) pFontDict->Search("Encoding", &oDictItem); if ( oDictItem.IsName() ) { StringExt *seCMapName = new StringExt( oDictItem.GetName() ); if ( m_pGlobalParams && !( m_pCMap = m_pGlobalParams->GetCMap( seCollection, seCMapName ) ) ) { // TO DO: Error "Unknown CMap for character collection" if ( seCollection ) delete seCollection; if ( seCMapName ) delete seCMapName; oDictItem.Free(); oDescendantObject.Free(); return; } if ( seCMapName ) delete seCMapName; } else if ( oDictItem.IsStream() ) { Stream *pStream = oDictItem.GetStream(); Dict *pEncDict = pStream->GetDict(); Object oEncItem; pEncDict->Search("CMapName", &oEncItem); if ( !oEncItem.IsName() ) { if ( seCollection ) delete seCollection; oEncItem.Free(); oDictItem.Free(); oDescendantObject.Free(); return; } StringExt *seCMapName = new StringExt( oEncItem.GetName() ); oEncItem.Free(); CString wsTempFile; FILE *pFile = NULL; if ( !OpenTempFile( &wsTempFile, &pFile, _T("wb"), _T(".cmap"), m_pGlobalParams->GetTempFolder() ) ) { if ( seCollection ) delete seCollection; if ( seCMapName ) delete seCMapName; oDictItem.Free(); oDescendantObject.Free(); return; } pStream->Reset(); int nChar = 0; while ( EOF != ( nChar = pStream->GetChar() ) ) { ::fputc( nChar, pFile ); } fclose( pFile ); if ( !(m_pCMap = pGlobalParams->GetCMap( seCollection, seCMapName, wsTempFile.GetBuffer() ) ) ) { _wunlink( wsTempFile.GetBuffer() ); if ( seCollection ) delete seCollection; if ( seCMapName ) delete seCMapName; oDictItem.Free(); oDescendantObject.Free(); return; } _wunlink( wsTempFile.GetBuffer() ); if ( seCMapName ) delete seCMapName; } else { // TO DO: Error "Missing or invalid Encoding entry in Type 0 font" if ( seCollection ) delete seCollection; oDictItem.Free(); oDescendantObject.Free(); return; } oDictItem.Free(); if ( seCollection ) delete seCollection; // CIDToGIDMap (для внедренных шрифтов-TrueType) if ( m_eType == fontCIDType2 ) { pDescendantDict->Search("CIDToGIDMap", &oDictItem); if ( oDictItem.IsStream() ) { int nChar1 = 0, nChar2 = 0; m_nCidToGIDLen = 0; int nLen = 64; m_pCidToGID = (unsigned short *)MemUtilsMallocArray( nLen, sizeof(unsigned short)); oDictItem.StreamReset(); while ( ( nChar1 = oDictItem.StreamGetChar() ) != EOF && ( nChar2 = oDictItem.StreamGetChar() ) != EOF ) { if ( m_nCidToGIDLen == nLen ) { nLen *= 2; m_pCidToGID = (unsigned short *)MemUtilsReallocArray(m_pCidToGID, nLen, sizeof(unsigned short)); } m_pCidToGID[ m_nCidToGIDLen++ ] = (unsigned short)((nChar1 << 8) + nChar2); } } else if ( !oDictItem.IsName("Identity") && !oDictItem.IsNull() ) { // TO DO: Error "Invalid CIDToGIDMap entry in CID font" } oDictItem.Free(); } // Метрики // Стандартное значение ширин if ( pDescendantDict->Search("DW", &oDictItem)->IsInt() ) { m_oWidths.dDefaultWidth = oDictItem.GetInt() * 0.001; } oDictItem.Free(); // Исключения if ( pDescendantDict->Search("W", &oDictItem)->IsArray() ) { int nExceptionsSize = 0; int nCounter = 0; while ( nCounter + 1 < oDictItem.ArrayGetLength() ) { Object oFirst, oSecond; oDictItem.ArrayGet( nCounter, &oFirst); oDictItem.ArrayGet( nCounter + 1, &oSecond); if ( oFirst.IsInt() && oSecond.IsInt() && nCounter + 2 < oDictItem.ArrayGetLength() ) { // формат: C_first C_last W Object oWidth; if ( oDictItem.ArrayGet( nCounter + 2, &oWidth)->IsNum() ) { if ( m_oWidths.nExceptionsCount == nExceptionsSize ) { nExceptionsSize += 16; m_oWidths.pExceptions = (GrFontCIDWidthException *)MemUtilsReallocArray( m_oWidths.pExceptions, nExceptionsSize, sizeof(GrFontCIDWidthException)); } m_oWidths.pExceptions[m_oWidths.nExceptionsCount].nFirst = oFirst.GetInt(); m_oWidths.pExceptions[m_oWidths.nExceptionsCount].nLast = oSecond.GetInt(); m_oWidths.pExceptions[m_oWidths.nExceptionsCount].dWidth = oWidth.GetNum() * 0.001; ++m_oWidths.nExceptionsCount; } else { // TO DO: Error "Bad widths array in Type 0 font" } oWidth.Free(); nCounter += 3; } else if ( oFirst.IsInt() && oSecond.IsArray() ) { // Формат: c [ w1 w2 … wn ] if ( m_oWidths.nExceptionsCount + oSecond.ArrayGetLength() > nExceptionsSize ) { nExceptionsSize = ( m_oWidths.nExceptionsCount + oSecond.ArrayGetLength() + 15) & ~15; m_oWidths.pExceptions = (GrFontCIDWidthException *) MemUtilsReallocArray( m_oWidths.pExceptions, nExceptionsSize, sizeof(GrFontCIDWidthException)); } int nCurFirst = oFirst.GetInt(); for ( int nArrayIndex = 0; nArrayIndex < oSecond.ArrayGetLength(); ++nArrayIndex ) { Object oTemp; if ( oSecond.ArrayGet( nArrayIndex, &oTemp)->IsNum() ) { m_oWidths.pExceptions[m_oWidths.nExceptionsCount].nFirst = nCurFirst; m_oWidths.pExceptions[m_oWidths.nExceptionsCount].nLast = nCurFirst; m_oWidths.pExceptions[m_oWidths.nExceptionsCount].dWidth = oTemp.GetNum() * 0.001; ++nCurFirst; ++m_oWidths.nExceptionsCount; } else { // TO DO: Error "Bad widths array in Type 0 font" } oTemp.Free(); } nCounter += 2; } else { // TO DO: Error "Bad widths array in Type 0 font"); ++nCounter; } oSecond.Free(); oFirst.Free(); } qsort(m_oWidths.pExceptions, m_oWidths.nExceptionsCount, sizeof(GrFontCIDWidthException), &CompareWidthExceptions); } oDictItem.Free(); // Стандартные метрики по вертикали if ( pDescendantDict->Search("DW2", &oDictItem)->IsArray() && oDictItem.ArrayGetLength() == 2 ) { Object oTemp; if ( oDictItem.ArrayGet( 0, &oTemp)->IsNum() ) { m_oWidths.dDefaultV = oTemp.GetNum() * 0.001; } oTemp.Free(); if ( oDictItem.ArrayGet( 1, &oTemp)->IsNum() ) { m_oWidths.dDefaultHeight = oTemp.GetNum() * 0.001; } oTemp.Free(); } oDictItem.Free(); // Исключения if ( pDescendantDict->Search("W2", &oDictItem)->IsArray() ) { int nExceptionsSize = 0; int nCounter = 0; while ( nCounter + 1 < oDictItem.ArrayGetLength() ) { Object oFirst, oSecond; oDictItem.ArrayGet( nCounter, &oFirst); oDictItem.ArrayGet( nCounter + 1, &oSecond); if ( oFirst.IsInt() && oSecond.IsInt() && nCounter + 4 < oDictItem.ArrayGetLength() ) { // Формат: С_first С_last W11y V1x V1y Object oHeight, oVx, oVy; if ( oDictItem.ArrayGet( nCounter + 2, &oHeight)->IsNum() && oDictItem.ArrayGet( nCounter + 3, &oVx)->IsNum() && oDictItem.ArrayGet( nCounter + 4, &oVy)->IsNum() ) { if ( m_oWidths.nExceptionsVCount == nExceptionsSize ) { nExceptionsSize += 16; m_oWidths.pExceptionsV = (GrFontCIDWidthExceptionV *) MemUtilsReallocArray(m_oWidths.pExceptionsV, nExceptionsSize, sizeof(GrFontCIDWidthExceptionV)); } m_oWidths.pExceptionsV[m_oWidths.nExceptionsVCount].nFirst = oFirst.GetInt(); m_oWidths.pExceptionsV[m_oWidths.nExceptionsVCount].nLast = oSecond.GetInt(); m_oWidths.pExceptionsV[m_oWidths.nExceptionsVCount].dHeight = oHeight.GetNum() * 0.001; m_oWidths.pExceptionsV[m_oWidths.nExceptionsVCount].dVx = oVx.GetNum() * 0.001; m_oWidths.pExceptionsV[m_oWidths.nExceptionsVCount].dVy = oVy.GetNum() * 0.001; ++m_oWidths.nExceptionsVCount; } else { // TO DO: Error "Bad widths (W2) array in Type 0 font" } oVy.Free(); oVx.Free(); oHeight.Free(); nCounter += 5; } else if ( oFirst.IsInt() && oSecond.IsArray() ) { if ( m_oWidths.nExceptionsVCount + oSecond.ArrayGetLength() / 3 > nExceptionsSize ) { nExceptionsSize = ( m_oWidths.nExceptionsVCount + oSecond.ArrayGetLength() / 3 + 15 ) & ~15; m_oWidths.pExceptionsV = (GrFontCIDWidthExceptionV *) MemUtilsReallocArray( m_oWidths.pExceptionsV, nExceptionsSize, sizeof(GrFontCIDWidthExceptionV)); } int nCurFirst = oFirst.GetInt(); for ( int nArrayIndex = 0; nArrayIndex < oSecond.ArrayGetLength(); nArrayIndex += 3 ) { Object oHeight, oVx, oVy; if ( oSecond.ArrayGet( nArrayIndex, &oHeight)->IsNum() && oSecond.ArrayGet( nArrayIndex + 1, &oVx)->IsNum() && oSecond.ArrayGet( nArrayIndex + 2, &oVy)->IsNum() ) { // TO DO: Здесь было исправлено!!! неправильные индексы передавались -> вместо nExceptionsVCount передавались nExceptionsCount m_oWidths.pExceptionsV[m_oWidths.nExceptionsVCount].nFirst = nCurFirst; m_oWidths.pExceptionsV[m_oWidths.nExceptionsVCount].nLast = nCurFirst; m_oWidths.pExceptionsV[m_oWidths.nExceptionsVCount].dHeight = oHeight.GetNum() * 0.001; m_oWidths.pExceptionsV[m_oWidths.nExceptionsVCount].dVx = oVx.GetNum() * 0.001; m_oWidths.pExceptionsV[m_oWidths.nExceptionsVCount].dVy = oVy.GetNum() * 0.001; ++nCurFirst; ++m_oWidths.nExceptionsVCount; } else { // TO DO: Error "Bad widths (W2) array in Type 0 font" } oVy.Free(); oVx.Free(); oHeight.Free(); } nCounter += 2; } else { // TO DO: Error "Bad widths (W2) array in Type 0 font" ++nCounter; } oSecond.Free(); oFirst.Free(); } qsort( m_oWidths.pExceptionsV, m_oWidths.nExceptionsVCount, sizeof(GrFontCIDWidthExceptionV), &CompareWidthExceptionsV); } oDictItem.Free(); oDescendantObject.Free(); m_bValid = TRUE; return; } GrCIDFont::~GrCIDFont() { if ( m_pCMap ) { m_pCMap->Release(); } if ( m_pCharToUnicode ) { m_pCharToUnicode->Release(); } MemUtilsFree(m_oWidths.pExceptions); MemUtilsFree(m_oWidths.pExceptionsV); if ( m_pCidToGID ) { MemUtilsFree(m_pCidToGID); } } int GrCIDFont::GetNextChar(char *sText, int nLen, CharCode *punCode, Unicode *punUnicode, int uSize, int *uLen, double *pdDx, double *pdDy, double *pdVx, double *pdVy) { CID nCID = 0; int nCount = 0; if ( !m_pCMap ) { *punCode = 0; *uLen = 0; *pdDx = *pdDy = 0; return 1; } *punCode = (CharCode)( nCID = m_pCMap->GetCID( sText, nLen, &nCount) ); // Временно *uLen = nCount; if ( 1 == nCount ) *punUnicode = sText[0]; else if ( 2 == nCount ) { *punUnicode = 0; *punUnicode |= sText[0] & 0xFF; *punUnicode <<= 8; *punUnicode |= sText[1] & 0xFF; } else { *uLen = 0; *punUnicode = 0; } //if ( m_pCharToUnicode ) //{ // *uLen = m_pCharToUnicode->MapToUnicode( nCID, punUnicode, uSize); //} //else //{ // *uLen = 0; //} double dWidth = 0, dHeight = 0, dVx = 0, dVy = 0; // Horizontal if ( m_pCMap->GetWMode() == 0) { dWidth = m_oWidths.dDefaultWidth; dHeight = dVx = dVy = 0; if ( m_oWidths.nExceptionsCount > 0 && nCID >= m_oWidths.pExceptions[0].nFirst ) { int nFirst = 0; int nLast = m_oWidths.nExceptionsCount; while ( nLast - nFirst > 1 ) { int nMiddle = (nFirst + nLast) / 2; if ( m_oWidths.pExceptions[nMiddle].nFirst <= nCID ) { nFirst = nMiddle; } else { nLast = nMiddle; } } if ( nCID <= m_oWidths.pExceptions[nFirst].nLast ) { dWidth = m_oWidths.pExceptions[nFirst].dWidth; } } } else // Vertical { dWidth = 0; dHeight = m_oWidths.dDefaultHeight; dVx = m_oWidths.dDefaultWidth / 2; dVy = m_oWidths.dDefaultV; if ( m_oWidths.nExceptionsVCount > 0 && nCID >= m_oWidths.pExceptionsV[0].nFirst ) { int nFirst = 0; int nLast = m_oWidths.nExceptionsVCount; while ( nLast - nFirst > 1 ) { int nMiddle = (nFirst + nLast) / 2; if ( m_oWidths.pExceptionsV[nMiddle].nLast <= nCID ) { nFirst = nMiddle; } else { nLast = nMiddle; } } if ( nCID <= m_oWidths.pExceptionsV[nFirst].nLast ) { dHeight = m_oWidths.pExceptionsV[nFirst].dHeight; dVx = m_oWidths.pExceptionsV[nFirst].dVx; dVy = m_oWidths.pExceptionsV[nFirst].dVy; } } } *pdDx = dWidth; *pdDy = dHeight; *pdVx = dVx; *pdVy = dVy; return nCount; } int GrCIDFont::GetWMode() { return m_pCMap ? m_pCMap->GetWMode() : 0; } CharCodeToUnicode *GrCIDFont::GetToUnicode() { if ( m_pCharToUnicode ) { m_pCharToUnicode->AddRef(); } return m_pCharToUnicode; } StringExt *GrCIDFont::GetCollection() { return m_pCMap ? m_pCMap->GetCollection() : (StringExt *)NULL; } //------------------------------------------------------------------------ // GrFontDict //------------------------------------------------------------------------ GrFontDict::GrFontDict(XRef *pXref, Ref *pFontDictRef, Dict *pFontDict, GlobalParams *pGlobalParams) { m_pGlobalParams = pGlobalParams; Ref oRef; m_nFontsCount = pFontDict->GetEntryCount(); m_ppFonts = (GrFont **)MemUtilsMallocArray( m_nFontsCount, sizeof(GrFont *)); for ( int nIndex = 0; nIndex < m_nFontsCount; ++nIndex ) { Object oFontRef, oFont; pFontDict->GetValueCopy( nIndex, &oFontRef); oFontRef.Fetch( pXref, &oFont); if ( oFont.IsDict() ) { if ( oFontRef.IsRef()) { oRef = oFontRef.GetRef(); } else { // Нет ссылки на данный шрифт, но ссылка нам нужна как идентефикатор, поэтому выбираем некотый уникальный номер // (поскольку корректное версионное число состоит из 5 цифр, поэтому любое 6-циферное число будет безопасным решением) oRef.nNum = nIndex; if ( pFontDictRef ) { oRef.nGen = 100000 + pFontDictRef->nNum; } else { oRef.nGen = 999999; } } m_ppFonts[nIndex] = GrFont::MakeFont( pXref, pFontDict->GetKey(nIndex), oRef, oFont.GetDict(), pGlobalParams ); if ( m_ppFonts[nIndex] && !m_ppFonts[nIndex]->CheckValidate() ) { if ( m_ppFonts[nIndex] ) delete m_ppFonts[nIndex]; m_ppFonts[nIndex] = NULL; } } else { // TO DO: Error "font resource is not a dictionary" m_ppFonts[nIndex] = NULL; } oFontRef.Free(); oFont.Free(); } } GrFontDict::~GrFontDict() { for ( int nIndex = 0; nIndex < m_nFontsCount; ++nIndex ) { if ( m_ppFonts[nIndex] ) { delete m_ppFonts[nIndex]; } } MemUtilsFree(m_ppFonts); } GrFont *GrFontDict::Search(char *sTag) { for ( int nIndex = 0; nIndex < m_nFontsCount; ++nIndex ) { if ( m_ppFonts[nIndex] && m_ppFonts[nIndex]->CheckTag(sTag) ) { return m_ppFonts[nIndex]; } } return NULL; }