#include "Document.h" #include "../../../Common/DocxFormat/Source/SystemUtility/FileSystem/Directory.h" #include "../../../DesktopEditor/graphics/Image.h" unsigned long WriteHeader (Doc pPDF, StreamRecPtr pStream) { unsigned int nIndex = (int)pPDF->ePdfVersion; if ( OK != StreamWriteStr( pStream, VERSION_STR[ nIndex ] ) ) return pPDF->oError.nErrorNo; return OK; } unsigned int DocGetTempFile (Doc pPDF, CString *pwsTempFileName) { unsigned int unRet = 0; // Создаем временный файл CString pathTemp = CString( pPDF->wsTempDir ); if ( pathTemp.GetLength() < 1) { pathTemp = FileSystem::Directory::GetTempPath(); } *pwsTempFileName = FileSystem::Directory::CreateTempFileWithUniqueName(pathTemp, _T("PDF")); if (pwsTempFileName->GetLength() != 0) return 1; return unRet; } unsigned long InitCMapEncoding (EncoderRecPtr pEncoder) { //CMapEncoderAttr pAttr = (CMapEncoderAttr)pEncoder->pAttr; pEncoder->eType = EncoderTypeToUnicode; return OK; } unsigned long PrepareTrailer (Doc pPDF) { if ( OK != DictAdd( pPDF->pTrailer, "Root", pPDF->pCatalog ) ) return pPDF->oError.nErrorNo; if ( OK != DictAdd( pPDF->pTrailer, "Info", pPDF->pInfo ) ) return pPDF->oError.nErrorNo; return OK; } //----------------- Функции для работы с ToUnicode ------------------------------------------------- PToUnicode DocFindToUnicode (Doc pPDF, const char *sToUnicodeName) { List pList = pPDF->pToUnicodeList; for ( unsigned int nIndex = 0; nIndex < pList->nCount; nIndex++) { PToUnicode pToUnicode = (PToUnicode)ListItemAt( pList, nIndex ); if ( 0 == UtilsStrCmp( sToUnicodeName, pToUnicode->sName ) ) { return pToUnicode; } } return NULL; } PToUnicode DocFindToUnicode (Doc pPDF, unsigned short *pUnicode, unsigned int unSize) { List pList = pPDF->pToUnicodeList; for ( unsigned int nIndex = 0; nIndex < pList->nCount; nIndex++) { PToUnicode pToUnicode = (PToUnicode)ListItemAt( pList, nIndex ); if ( ToUnicodeBuilt == pToUnicode->eType ) { // Проверяем все ли значения из pUnicode есть в данной кодировке ToUnicode bool bGood = true; for ( unsigned int unCharIndex = 0; unCharIndex < unSize; unCharIndex++ ) { if ( 0xFFFF == ToUnicodeToCode( pToUnicode, pUnicode[unCharIndex] ) ) { bGood = false; break; } } if ( bGood ) return pToUnicode; } } return NULL; } PToUnicode DocFindToUnicode (Doc pPDF, BYTE *pBuffer, unsigned int unSize) { List pList = pPDF->pToUnicodeList; for ( unsigned int nIndex = 0; nIndex < pList->nCount; nIndex++) { PToUnicode pToUnicode = (PToUnicode)ListItemAt( pList, nIndex ); if ( ToUnicodeStream == pToUnicode->eType ) { // Проверяем совпадение по чексумме буффера CRC32 oCRC; oCRC.ProcessCRC( (void*)pBuffer, unSize ); ToUnicodeStreamAttr pAttr = (ToUnicodeStreamAttr)pToUnicode->pAttr; if ( pAttr->pStream->nCheckSum == oCRC.m_nCRC32 ) return pToUnicode; } } return NULL; } PToUnicode GetToUnicode (Doc pPDF, const char *sToUnicodeName) { if ( !HasDoc( pPDF ) ) return NULL; PToUnicode pToUnicode = DocFindToUnicode( pPDF, sToUnicodeName ); return pToUnicode; } PToUnicode GetToUnicode (Doc pPDF, unsigned short *pUnicode, unsigned int unSize) { if ( !HasDoc( pPDF) || NULL == pUnicode || 0 == unSize ) return NULL; // возможно кодировка, в которой есть все данные символы уже присутствует PToUnicode pToUnicode = DocFindToUnicode( pPDF, pUnicode, unSize ); unsigned long nRet = OK; if ( NULL == pToUnicode ) { // Попробуем дополнить последнюю кодировку pToUnicode = pPDF->pLastToUnicodeBuilt; if ( NULL != pToUnicode && ToUnicodeUpdateUnicodeArray( pToUnicode, pUnicode, unSize ) ) return pToUnicode; // Дополнить не получилось, значит состовляем новую кодировку pPDF->nToUnicodeBuiltCount++; char sToUnicodeBuiltName[LIMIT_MAX_NAME_LEN + 1]; sprintf( sToUnicodeBuiltName, "CMap%d", pPDF->nToUnicodeBuiltCount ); pToUnicode = ToUnicodeBuiltNew( pPDF->oMMgr, sToUnicodeBuiltName, 8 ); if ( !pToUnicode ) { CheckError( &pPDF->oError ); return NULL; } // Обычные шрифты в PDF поддерживают до 256 символов. ( 0 символ зарезервирован ) unSize = ( unSize >= 256 ? 255 : unSize ); ToUnicodeBuiltAttr pAttr = (ToUnicodeBuiltAttr)pToUnicode->pAttr; pAttr->nFirstChar = 0; pAttr->nLastChar = 0; // Внутри данной функции сразу идет проверка на дублирование символов ToUnicodeUpdateUnicodeArray( pToUnicode, pUnicode, unSize ); if ( OK != ( nRet = ListAdd( pPDF->pToUnicodeList, pToUnicode ) ) ) { ToUnicodeFree( pToUnicode ); RaiseError( &pPDF->oError, nRet, 0); return NULL; } pPDF->pLastToUnicodeBuilt = pToUnicode; pPDF->pCurToUnicode = pToUnicode; } return pToUnicode; } PToUnicode GetToUnicode (Doc pPDF, BYTE *pBuffer, unsigned int unSize) { if ( !HasDoc( pPDF) || NULL == pBuffer || 0 == unSize ) return NULL; // возможно кодировка, в которой есть все данные символы уже присутствует PToUnicode pToUnicode = DocFindToUnicode( pPDF, pBuffer, unSize ); unsigned long nRet = OK; if ( NULL == pToUnicode ) { pPDF->nToUnicodeStreamCount++; char sToUnicodeBuiltName[LIMIT_MAX_NAME_LEN + 1]; sprintf( sToUnicodeBuiltName, "Stream%d", pPDF->nToUnicodeStreamCount ); pToUnicode = ToUnicodeStreamNew( pPDF->oMMgr, pBuffer, unSize, sToUnicodeBuiltName ); if ( !pToUnicode ) { CheckError( &pPDF->oError ); return NULL; } if ( OK != ( nRet = ListAdd( pPDF->pToUnicodeList, pToUnicode ) ) ) { ToUnicodeFree( pToUnicode ); RaiseError( &pPDF->oError, nRet, 0); return NULL; } pPDF->pCurToUnicode = pToUnicode; } return pToUnicode; } PToUnicode DocGetCurrentToUnicode(Doc pPDF) { if ( !HasDoc( pPDF ) ) return NULL; return pPDF->pCurToUnicode; } void FreeToUnicodeList (Doc pPDF) { List pList = pPDF->pToUnicodeList; for ( unsigned int nIndex = 0; nIndex < pList->nCount; nIndex++) { PToUnicode pToUnicode = (PToUnicode)ListItemAt( pList, nIndex ); ToUnicodeFree( pToUnicode ); } ListFree( pList ); pPDF->pToUnicodeList = NULL; } PToUnicode FindToUnicodeForString(Doc pPDF, std::wstring sSrc) { unsigned short *aUnicodeMap = new unsigned short[sSrc.length() + 1]; for ( int nIndex = 0; nIndex < sSrc.length(); nIndex++ ) { aUnicodeMap[nIndex] = (unsigned short)sSrc.at(nIndex); } aUnicodeMap[sSrc.length()] = 0xFFFF; unsigned int unSize = sSrc.length(); PToUnicode pToUnicode = GetToUnicode( pPDF, aUnicodeMap, unSize ); delete []aUnicodeMap; return pToUnicode; } //----------------- Функции для работы с кодировками ----------------------------------------------- EncoderRecPtr DocFindEncoder (Doc pPDF, const char *sEncodingName, unsigned short *pUnicode /*= NULL*/, int nCount/* = 0*/) { if ( NULL == pUnicode ) { List pList = pPDF->pEncoderList; for ( unsigned int nIndex = 0; nIndex < pList->nCount; nIndex++) { EncoderRecPtr pEncoder = (EncoderRecPtr)ListItemAt( pList, nIndex ); if ( 0 == UtilsStrCmp( sEncodingName, pEncoder->sName ) ) { // если кодировка не инициализирована, тогда вызываем функцию InitFn if ( EncoderTypeUninitialized == pEncoder->eType ) { if ( !pEncoder->pInitFn || OK != pEncoder->pInitFn( pEncoder ) ) return NULL; } return pEncoder; } } return NULL; } else { // Тут надо сделать поиск кодировки с данным pUnicode return NULL; } } unsigned long DocRegisterEncoder (Doc pPDF, EncoderRecPtr pEncoder) { unsigned long nRet = OK; if ( !pEncoder ) return SetError( &pPDF->oError, AVS_OFFICEPDFWRITER_ERROR_INVALID_OBJECT, 0); if ( NULL != DocFindEncoder( pPDF, pEncoder->sName ) ) { EncoderFree( pEncoder ); return SetError( &pPDF->oError, AVS_OFFICEPDFWRITER_ERROR_DUPLICATE_REGISTRATION, 0 ); } if ( OK != ( nRet = ListAdd( pPDF->pEncoderList, pEncoder ) ) ) { EncoderFree( pEncoder ); return SetError( &pPDF->oError, nRet, 0 ); } return OK; } EncoderRecPtr GetEncoder (Doc pPDF, const char *sEncodingName, unsigned short *pUnicode/* = NULL*/, int nCount/* = 0*/) { if ( NULL == pUnicode ) { if ( !HasDoc( pPDF ) ) return NULL; EncoderRecPtr pEncoder = DocFindEncoder( pPDF, sEncodingName ); unsigned long nRet = OK; if ( !pEncoder ) { pEncoder = BasicEncoderNew( pPDF->oMMgr, sEncodingName ); if ( !pEncoder ) { CheckError( &pPDF->oError ); return NULL; } if ( OK != ( nRet = ListAdd( pPDF->pEncoderList, pEncoder ) ) ) { EncoderFree( pEncoder ); RaiseError( &pPDF->oError, nRet, 0); return NULL; } } return pEncoder; } else { if ( !HasDoc( pPDF) ) return NULL; // возможно кодировка, в которой есть все данные символы уже присутствует EncoderRecPtr pEncoder = DocFindEncoder( pPDF, sEncodingName, pUnicode, nCount ); unsigned long nRet = OK; if ( !pEncoder ) { pPDF->nCMapCount++; char sEncodingName[100]; sprintf( sEncodingName, "CMap%d", pPDF->nCMapCount ); pEncoder = CMapEncoderNew( pPDF->oMMgr, sEncodingName, &InitCMapEncoding ); if ( !pEncoder ) { CheckError( &pPDF->oError ); return NULL; } pEncoder->eType = EncoderTypeToUnicode; CMapEncoderInitAttr( pEncoder ); // Обычные шрифты в PDF поддерживают до 256 символов. ( 0 символ зарезервирован ) nCount = ( nCount >= 256 ? 255 : nCount ); UtilsUIntArrayClearRepeat( &pUnicode, &nCount ); UnicodeMapRec *aUnicodeMap = new UnicodeMapRec[nCount + 2]; // первый и последний символы зарезервированы aUnicodeMap[0].nCode = 0; aUnicodeMap[0].nUnicode = 0x0000; for ( int nIndex = 1; nIndex <= nCount; nIndex++ ) { aUnicodeMap[nIndex].nCode = nIndex; aUnicodeMap[nIndex].nUnicode = pUnicode[nIndex - 1]; } aUnicodeMap[nCount + 1].nCode = nCount + 1; aUnicodeMap[nCount + 1].nUnicode = 0xffff; // Таким образом мы обозначаем конец массива CMapEncoderSetUnicodeArray( pEncoder, aUnicodeMap ); delete []aUnicodeMap; CMapEncoderAttr pAttr = (CMapEncoderAttr)pEncoder->pAttr; pAttr->nFirstChar = 0; pAttr->nLastChar = nCount; if ( OK != ( nRet = ListAdd( pPDF->pEncoderList, pEncoder ) ) ) { EncoderFree( pEncoder ); RaiseError( &pPDF->oError, nRet, 0); return NULL; } pPDF->pLastCMapEncoder = pEncoder; } return pEncoder; } } EncoderRecPtr DocGetCurrentEncoder(Doc pPDF) { if ( !HasDoc( pPDF ) ) return NULL; return pPDF->pCurEncoder; } unsigned long DocSetCurrentEncoder(Doc pPDF, const char *sEncodingName) { if ( !HasDoc( pPDF ) ) return GetError( pPDF ); EncoderRecPtr pEncoder = GetEncoder( pPDF, sEncodingName ); pPDF->pCurEncoder = pEncoder; if ( !pPDF ) return GetError( pPDF ); return OK; } void FreeEncoderList (Doc pPDF) { List pList = pPDF->pEncoderList; for ( unsigned int nIndex = 0; nIndex < pList->nCount; nIndex++) { EncoderRecPtr pEncoder = (EncoderRecPtr)ListItemAt( pList, nIndex ); EncoderFree( pEncoder ); } ListFree( pList ); pPDF->pEncoderList = NULL; } EncoderRecPtr FindEncoderForString(Doc pPDF, CString sSrc, bool *pbNew) { *pbNew = false; // Среди всех кодировок, имеющихся в документе, ищем ту, в которой можно написать заданную строку List pEncoderList = pPDF->pEncoderList; for ( int nIndex = 0; nIndex < pEncoderList->nCount; nIndex++ ) { EncoderRecPtr pCurEncoder = (EncoderRecPtr)ListItemAt( pEncoderList, nIndex ); if ( EncoderTypeToUnicode != pCurEncoder->eType ) continue; bool bResult = false; CString sDst; if ( NULL != pCurEncoder ) bResult = EncoderWCharToString( pCurEncoder, sSrc, &sDst ); if ( bResult ) { return pCurEncoder; } } // Среди имеющихся кодировок нужной кодировки нет, поэтому попробуем дополнить pLastCMapEncoder unsigned short *aUnicodeMap = new unsigned short[sSrc.GetAllocLength() + 1]; for ( int nIndex = 0; nIndex < sSrc.GetLength(); nIndex++ ) { aUnicodeMap[nIndex] = (unsigned short)sSrc.GetAt(nIndex); } aUnicodeMap[sSrc.GetLength()] = 0xFFFF; int nCount = sSrc.GetLength(); UtilsUIntArrayClearRepeat( &aUnicodeMap, &nCount ); if ( pPDF->pLastCMapEncoder && CMapEncoderUpdateUnicodeArray( pPDF->pLastCMapEncoder, aUnicodeMap ) ) { delete []aUnicodeMap; return pPDF->pLastCMapEncoder; } else { EncoderRecPtr pNewEncoder = GetEncoder( pPDF, "", aUnicodeMap, nCount ); delete []aUnicodeMap; *pbNew = true; return pNewEncoder; } } //----------------- Функции для работы с фонтами --------------------------------------------------- //----------------- FontDef ------------------------------------------------------------------------ void FreeFontDefList (Doc pPDF) { List pList = pPDF->pFontDefList; for ( unsigned int nIndex = 0; nIndex < pList->nCount; nIndex++) { FontDef pDef = (FontDef)ListItemAt( pList, nIndex ); FontDefFree( pDef ); } ListFree( pList ); pPDF->pFontDefList = NULL; } void CleanupFontDefList(Doc pPDF) { List pList = pPDF->pFontDefList; for ( unsigned int nIndex = 0; nIndex < pList->nCount; nIndex++) { FontDef pDef = (FontDef)ListItemAt( pList, nIndex ); FontDefCleanup( pDef ); } } FontDef DocFindFontDef (Doc pPDF, const char *sFontName, const char *sToUnicodeName /*= NULL*/) { List pList = pPDF->pFontDefList; for ( unsigned int nIndex = 0; nIndex < pList->nCount; nIndex++) { FontDef pDef = (FontDef)ListItemAt( pList, nIndex ); if ( FontDefTrueType == pDef->eType && NULL != sToUnicodeName ) { TTFontDefAttrRecPtr pAttr = (TTFontDefAttrRecPtr)pDef->pAttr; if ( 0 == UtilsStrCmp( sFontName, pDef->sBaseFont) && 0 == UtilsStrCmp( sToUnicodeName, pAttr->sToUnicodeName ) ) { if ( FontDefUninitialized == pDef->eType ) { if ( !pDef->pInitFn || OK != pDef->pInitFn( pDef ) ) return NULL; } return pDef; } } else { if ( 0 == UtilsStrCmp( sFontName, pDef->sBaseFont ) ) { if ( FontDefUninitialized == pDef->eType ) { if ( !pDef->pInitFn || OK != pDef->pInitFn( pDef ) ) return NULL; } return pDef; } } } return NULL; } unsigned long DocRegisterFontDef (Doc pPDF, FontDef pFontDef) { unsigned long nRet = OK; if ( !pFontDef ) return SetError( &pPDF->oError, AVS_OFFICEPDFWRITER_ERROR_INVALID_OBJECT, 0); if ( NULL != DocFindFontDef( pPDF, pFontDef->sBaseFont ) ) { FontDefFree( pFontDef ); return SetError( &pPDF->oError, AVS_OFFICEPDFWRITER_ERROR_DUPLICATE_REGISTRATION, 0 ); } if ( OK != ( nRet = ListAdd( pPDF->pFontDefList, pFontDef ) ) ) { FontDefFree( pFontDef ); return SetError( &pPDF->oError, nRet, 0); } return OK; } FontDef GetFontDef (Doc pPDF, const char *sFontName, const char *sToUnicode /*= NULL*/) { unsigned long nRet = OK; if ( !HasDoc( pPDF ) ) return NULL; FontDef pDef = DocFindFontDef( pPDF, sFontName, sToUnicode ); if ( !pDef ) { pDef = Base14FontDefNew( pPDF->oMMgr, sFontName); if ( !pDef ) { pDef = BaseFontDefNew( pPDF->oMMgr, sFontName ); if ( !pDef ) return NULL; } if ( OK != ( nRet = ListAdd( pPDF->pFontDefList, pDef ) ) ) { FontDefFree( pDef ); RaiseError( &pPDF->oError, nRet, 0 ); pDef = NULL; } } return pDef; } //----------------- Font ---------------------------------------------------------------------------- FontDict DocFindFont (Doc pPDF, const char *sFontName, const char *sEncodingName, const char *sToUnicodeName /*= NULL*/) { FontDict pFont = NULL; for ( unsigned int nIndex = 0; nIndex < pPDF->pFontManager->nCount; nIndex++) { pFont = (FontDict)ListItemAt( pPDF->pFontManager, nIndex); FontAttr pAttr = (FontAttr)pFont->pAttr; // Строка sToUnicodeName может быть NULL. Функция UtilsStrCmp безопасно работает в данном случае if ( NULL != pAttr->pToUnicode ) { if ( 0 == UtilsStrCmp( pAttr->pFontDef->sBaseFont, sFontName ) && 0 == UtilsStrCmp( pAttr->pEncoder->sName, sEncodingName ) && 0 == UtilsStrCmp( pAttr->pToUnicode->sName, sToUnicodeName ) ) return pFont; } else if ( NULL == pAttr->pToUnicode && NULL == sToUnicodeName ) { if ( 0 == UtilsStrCmp( pAttr->pFontDef->sBaseFont, sFontName ) && 0 == UtilsStrCmp( pAttr->pEncoder->sName, sEncodingName ) ) return pFont; } } return NULL; } FontDict GetFont (Doc pPDF, const char *sFontName, const char *sEncodingName, const char *sToUnicodeName /*= NULL*/, unsigned short *pUnicode /*= NULL*/, int nCount/* = 0*/) { if ( !HasDoc( pPDF ) ) return NULL; if ( !sFontName ) { RaiseError( &pPDF->oError, AVS_OFFICEPDFWRITER_ERROR_INVALID_FONT_NAME, 0 ); return NULL; } FontDef pFontDef = NULL; EncoderRecPtr pEncoder = NULL; FontDict pFont = NULL; PToUnicode pToUnicode = NULL; // если кодировка не определена, тогда ищем стандартную кодировку для данного фонта if ( !sEncodingName ) { pFontDef = GetFontDef( pPDF, sFontName, sToUnicodeName ); if ( pFontDef ) { if ( FontDefTrueType == pFontDef->eType ) pEncoder = GetEncoder( pPDF, ENCODING_FONT_SPECIFIC ); else if ( FontDefType1 == pFontDef->eType ) { Type1FontDefAttr pAttr = (Type1FontDefAttr)pFontDef->pAttr; if ( FontDefType1 == pFontDef->eType && 0 == UtilsStrCmp( pAttr->sEncodingScheme, ENCODING_FONT_SPECIFIC ) ) pEncoder = GetEncoder( pPDF, ENCODING_FONT_SPECIFIC ); else pEncoder = GetEncoder( pPDF, ENCODING_WIN_ANSI/*ENCODING_STANDARD*/, pUnicode, nCount ); } } else { CheckError( &pPDF->oError ); return NULL; } pFont = DocFindFont( pPDF, sFontName, pEncoder->sName, sToUnicodeName ); } else pFont = DocFindFont( pPDF, sFontName, sEncodingName, sToUnicodeName ); if ( pFont ) return pFont; if ( !pFontDef ) { pFontDef = GetFontDef( pPDF, sFontName, sToUnicodeName ); if ( !pFontDef ) { CheckError( &pPDF->oError ); return NULL; } } if ( !pEncoder ) { pEncoder = GetEncoder( pPDF, sEncodingName, pUnicode, nCount ); if ( !pEncoder ) return NULL; } if ( !pToUnicode ) { pToUnicode = GetToUnicode( pPDF, sToUnicodeName ); } switch ( pFontDef->eType ) { case FontDefType1: pFont = Type1FontNew( pPDF->oMMgr, pFontDef, pEncoder, pPDF->pXref, pToUnicode ); if ( pFont ) ListAdd( pPDF->pFontManager, pFont); break; case FontDefTrueType: if ( EncoderTypeDoubleByteBuilt == pEncoder->eType ) pFont = Type0FontNew( pPDF->oMMgr, pFontDef, pEncoder, pPDF->pXref, pToUnicode ); else pFont = TTFontNew( pPDF->oMMgr, pFontDef, pEncoder, pPDF->pXref, pToUnicode); if ( pFont ) ListAdd( pPDF->pFontManager, pFont); break; case FontDefCID: pFont = Type0FontNew( pPDF->oMMgr, pFontDef, pEncoder, pPDF->pXref, pToUnicode ); if ( pFont ) ListAdd( pPDF->pFontManager, pFont); break; case FontBase: pFont = BaseFontNew( pPDF->oMMgr, pFontDef, pEncoder, pPDF->pXref, pToUnicode ); if ( pFont ) ListAdd( pPDF->pFontManager, pFont ); break; default: RaiseError( &pPDF->oError, AVS_OFFICEPDFWRITER_ERROR_UNSUPPORTED_FONT_TYPE, 0); return NULL; } if ( !pFont ) CheckError( &pPDF->oError ); #ifdef FILTER_FLATE_DECODE_ENABLED if ( pFont && ( pPDF->nCompressionMode & COMP_METADATA ) ) pFont->nFilter |= STREAM_FILTER_FLATE_DECODE; #endif return pFont; } const char* LoadType1FontFromFile (Doc pPDF, std::wstring & wsAFMFileName, std::wstring & wsDataFileName, short nType/* = 0*/) { StreamRecPtr pAFM = NULL; StreamRecPtr pData = NULL; const char *sRet; if ( !HasDoc( pPDF ) ) return NULL; // создаем поток pAFM = FileReaderNew( pPDF->oMMgr, wsAFMFileName ); if ( wsDataFileName.length() > 0 ) pData = FileReaderNew( pPDF->oMMgr, wsDataFileName ); if ( StreamValidate( pAFM ) && ( wsDataFileName.length() > 0 || StreamValidate( pData ) ) ) sRet = LoadType1FontFromStream( pPDF, pAFM, pData, nType ); else sRet = NULL; // удаляем поток if ( pAFM ) StreamFree( pAFM ); if ( pData ) StreamFree( pData ); if ( !sRet ) CheckError( &pPDF->oError ); return sRet; } const char* LoadType1FontFromStream (Doc pPDF, StreamRecPtr pAFMData, StreamRecPtr pPFMData, short nType) { if ( !HasDoc( pPDF ) ) return NULL; FontDef pDef = Type1FontDefLoad( pPDF->oMMgr, pAFMData, pPFMData, nType ); if ( pDef ) { FontDef pTempDef = DocFindFontDef( pPDF, pDef->sBaseFont ); if ( pTempDef ) { FontDefFree( pDef ); SetError( &pPDF->oError, AVS_OFFICEPDFWRITER_ERROR_FONT_EXISTS, 0); return pTempDef->sBaseFont; } if ( OK != ListAdd( pPDF->pFontDefList, pDef ) ) { FontDefFree( pDef ); return NULL; } } return pDef->sBaseFont; } const char* LoadTTFontFromFile (Doc pPDF, std::wstring & wsFileName, bool bEmbedding, const char* sEncodingName/* = NULL*/, const char *sPrefix /*= NULL*/) { if ( !HasDoc( pPDF ) ) return NULL; const char *sRet = LoadTTFontFromStream( pPDF, bEmbedding, wsFileName, sEncodingName, sPrefix ); if ( !sRet ) CheckError( &pPDF->oError ); return sRet; } const char* LoadTTFontFromStream (Doc pPDF, bool bEmbedding, std::wstring & wsFileName, const char *sEncodingName, const char *sPrefix) { FontDef pDef = TTFontDefLoad( pPDF->oMMgr, wsFileName, bEmbedding, sEncodingName, false, false, false, true ); if ( pDef ) { if ( NULL != sPrefix ) strcat( pDef->sBaseFont, sPrefix ); FontDef pTempDef = DocFindFontDef( pPDF, pDef->sBaseFont, sEncodingName ); if ( pTempDef ) { FontDefFree( pDef ); SetError( &pPDF->oError, AVS_OFFICEPDFWRITER_ERROR_FONT_EXISTS, 0); return pTempDef->sBaseFont; } else { FontDefFree(pDef); pDef = TTFontDefLoad( pPDF->oMMgr, wsFileName, bEmbedding, sEncodingName, false, false, false, false ); if ( NULL != sPrefix ) strcat( pDef->sBaseFont, sPrefix ); } if ( OK != ListAdd( pPDF->pFontDefList, pDef ) ) { FontDefFree( pDef ); return NULL; } } else return NULL; if ( bEmbedding ) { if ( 0 == pPDF->aTTFontTag[0] ) { UtilsMemCpy( pPDF->aTTFontTag, (BYTE*)"BAAAAA", 6); } else { for ( unsigned int nIndex = 0; nIndex <= 5; nIndex++) { pPDF->aTTFontTag[nIndex] += 1; if ( pPDF->aTTFontTag[nIndex] > 'Z') pPDF->aTTFontTag[nIndex] = 'A'; else break; } } TTFontDefSetTagName( pDef, (char*)pPDF->aTTFontTag ); } return pDef->sBaseFont; } const char* LoadTTFontFromFile2 (Doc pPDF, std::wstring & wsFileName, unsigned int nIndex, bool bEmbedding) { if ( !HasDoc( pPDF ) ) return NULL; const char *sRet = LoadTTFontFromStream2( pPDF, nIndex, bEmbedding, wsFileName ); if ( !sRet ) CheckError( &pPDF->oError ); return sRet; } const char* LoadTTFontFromStream2 (Doc pPDF, unsigned int nIndex, bool bEmbedding, std::wstring & wsFileName) { FontDef pDef = TTFontDefLoad2( pPDF->oMMgr, wsFileName, nIndex, bEmbedding ); if ( pDef ) { FontDef pTempDef = DocFindFontDef( pPDF, pDef->sBaseFont ); if ( pTempDef ) { FontDefFree( pDef ); SetError( &pPDF->oError, AVS_OFFICEPDFWRITER_ERROR_FONT_EXISTS, 0); return NULL; } if ( OK != ListAdd( pPDF->pFontDefList, pDef ) ) { FontDefFree( pDef ); return NULL; } } else return NULL; if ( bEmbedding ) { if ( 0 == pPDF->aTTFontTag[0] ) UtilsMemCpy( pPDF->aTTFontTag, (BYTE*)"AVSAAA", 6); else { for ( unsigned int nIndex = 5; nIndex >= 0; nIndex--) { pPDF->aTTFontTag[nIndex] += 1; if ( pPDF->aTTFontTag[nIndex] > 'Z' ) pPDF->aTTFontTag[nIndex] = 'A'; else break; } } TTFontDefSetTagName( pDef, (char*)pPDF->aTTFontTag ); } return pDef->sBaseFont; } ////----------------- Images -------------------------------------------------------------------------- //ImageDict LoadRawImageFromFile (Doc pPDF, const wchar_t *wsFileName, unsigned int nWidth, unsigned int nHeight, ColorSpace eColorSpace) //{ // ImageDict pImage = NULL; // // if ( !HasDoc( pPDF ) ) // return NULL; // // // создаем файловый поток // Stream pImageData = FileReaderNew( pPDF->oMMgr, wsFileName ); // // if ( StreamValidate( pImageData ) ) // pImage = ImageLoadRawImage( pPDF->oMMgr, pImageData, pPDF->pXref, nWidth, nHeight, eColorSpace); // else // pImage = NULL; // // // удаялем поток // StreamFree( pImageData ); // // if ( !pImage ) // CheckError( &pPDF->oError ); // //#ifdef FILTER_FLATE_DECODE_ENABLED // if ( pPDF->nCompressionMode & COMP_IMAGE ) // pImage->nFilter = STREAM_FILTER_FLATE_DECODE; //#endif // // return pImage; //} // //ImageDict LoadRawImageFromMem (Doc pPDF, const BYTE *pBuffer, unsigned int nWidth, unsigned int nHeight, ColorSpace eColorSpace, unsigned int nBitsPerComponent, bool bAlpha = false, const BYTE *pAlphaBuffer = NULL) //{ // if ( !HasDoc( pPDF )) // return NULL; // // ImageDict pImage = ImageLoadRawImageFromMem( pPDF->oMMgr, pBuffer, pPDF->pXref, nWidth, nHeight, eColorSpace, nBitsPerComponent, bAlpha, pAlphaBuffer ); // // if ( !pImage ) // CheckError( &pPDF->oError ); // //#ifdef FILTER_FLATE_DECODE_ENABLED // if ( pPDF->nCompressionMode & COMP_IMAGE ) // pImage->nFilter = STREAM_FILTER_FLATE_DECODE; //#endif // // return pImage; //} ImageDict LoadJbig2ImageFromMem(Doc pPDF, BYTE *pBuffer, unsigned int nWidth, unsigned int nHeight, unsigned int unImageCheckSum) { ImageDict pImage = NULL; if ( !(HasDoc(pPDF)) ) return NULL; // Создаем временный файл CString wsTempFile; if ( 0 == DocGetTempFile( pPDF, &wsTempFile ) ) { SetError( pPDF->oMMgr->oError, AVS_OFFICEPDFWRITER_ERROR_FILE_WRITE_ERROR, errno ); return NULL; } // Записываем во временный файл картинку в формате JBig2 Aggplus::CImage image; int BitsPerSample = 3;//alfa отдельно oO ??? image.Create(pBuffer,nWidth, nHeight, - BitsPerSample * nWidth);//+ flip image.m_bExternalBuffer = true; image.SaveFile(string2std_string(wsTempFile), 21/*JBig2*/); image.Destroy(); //монохромные с альфой ??? //if ( bAlpha ) //{ // // Создаем темповый файл для записи туда альфа-канала // if ( 0 == DocGetTempFile( pPDF, &wsTempAlpha ) ) // { // SetError( pPDF->oMMgr->oError, AVS_OFFICEPDFWRITER_ERROR_FILE_WRITE_ERROR, errno ); // return NULL; // } // CEncoderLZW oLZW( pAlphaBuffer, nWidth * nHeight, false ); // oLZW.Encode( wsTempAlpha.GetBuffer() ); //} pImage = ImageLoadJBig2Image( pPDF->oMMgr, wsTempFile, pPDF->pXref, nWidth, nHeight, unImageCheckSum ); // Декодирование во Flate картинок в формате JBig2 отключено, из-за того что Acrobat // может плохо прочитать такие картинки. #ifdef FILTER_FLATE_DECODE_ENABLED //if ( pPDF->nCompressionMode & COMP_IMAGE ) // pImage->nFilter |= STREAM_FILTER_FLATE_DECODE; #endif return pImage; } ImageDict LoadJpegImageFromFile(Doc pPDF, std::wstring wsFileName) { ImageDict pImage = NULL; if ( !HasDoc( pPDF ) ) return NULL; // Создаем файловый поток StreamRecPtr pImageData = FileReaderNew( pPDF->oMMgr, wsFileName ); if ( StreamValidate(pImageData) ) pImage = ImageLoadJpegImage( pPDF->oMMgr, pImageData, pPDF->pXref ); else pImage = NULL; // освобождаем файловый поток StreamFree( pImageData ); if ( !pImage ) CheckError( &pPDF->oError ); return pImage; } ImageDict LoadJpxImageFromFile (Doc pPDF, std::wstring wsFileName, long nOpacityFlag) { ImageDict pImage = NULL; if ( !(HasDoc(pPDF) ) ) return NULL; // Создаем файловый поток StreamRecPtr pImageData = FileReaderNew( pPDF->oMMgr, wsFileName ); if ( StreamValidate( pImageData ) ) pImage = ImageLoadJpxImage( pPDF->oMMgr, pImageData, pPDF->pXref, nOpacityFlag ); else pImage = NULL; // Освобождаем файлоый поток StreamFree( pImageData ); if ( !pImage ) CheckError( &pPDF->oError ); return pImage; } //ImageDict LoadJpxImageFromMem (Doc pPDF, const BYTE *pBuffer, unsigned int nWidth, unsigned int nHeight, unsigned int unImageCheckSum, bool bAlpha = false, const BYTE *pAlphaBuffer = NULL, unsigned int unAlphaCheckSum = 0) //{ //#ifdef BUILD_CONFIG_OPENSOURCE_VERSION // return NULL; //#else // if ( !HasDoc( pPDF )) // return NULL; // // // Переводим Image -> IAVSUncompressedVideoFrame // MediaCore::IAVSUncompressedVideoFrame *pInterface = NULL; // HRESULT hRes = CoCreateInstance( MediaCore::CLSID_CAVSUncompressedVideoFrame, NULL, CLSCTX_ALL, MediaCore::IID_IAVSUncompressedVideoFrame, (void**)&pInterface ); // if ( hRes != S_OK ) // return NULL; // // int nBufferSize = 4 * nWidth * nHeight; // if ( nBufferSize < 1 ) // return NULL; // // pInterface->put_ColorSpace( 1 << 6 ); // CPS_BGRA // pInterface->put_Width( nWidth ); // pInterface->put_Height( nHeight ); // pInterface->put_AspectRatioX( nWidth ); // pInterface->put_AspectRatioY( nHeight ); // pInterface->put_Interlaced( VARIANT_FALSE ); // pInterface->put_Stride( 0, 4 * nWidth ); // pInterface->AllocateBuffer( nBufferSize ); // // unsigned char *pBufferPtr = NULL; // long nCreatedBufferSize = 0; // // pInterface->get_Buffer( &pBufferPtr ); // pInterface->get_BufferSize( &nCreatedBufferSize ); // pInterface->put_Plane( 0, pBufferPtr ); // // if ( !pBufferPtr || nCreatedBufferSize != nBufferSize ) // return NULL; // // // Пишем данные в pBufferPtr // // for ( int nIndex = 0; nIndex < nWidth * nHeight; nIndex++, pBufferPtr += 4, pBuffer += 3 ) // { // pBufferPtr[0] = pBuffer[ 2 ]; // pBufferPtr[1] = pBuffer[ 1 ]; // pBufferPtr[2] = pBuffer[ 0 ]; // pBufferPtr[3] = 255; // } // // // Создаем темповый файл для записи туда Jpx // CString wsTempFile, wsTempAlpha; // if ( 0 == DocGetTempFile( pPDF, &wsTempFile ) ) // { // SetError( pPDF->oMMgr->oError, AVS_OFFICEPDFWRITER_ERROR_FILE_WRITE_ERROR, errno ); // return NULL; // } // // // Записываем во временный файл картинку в формате Jpx // Jpx::IJ2kFile *pJpx = NULL; // ::CoCreateInstance( __uuidof( Jpx::CJ2kFile ), NULL, CLSCTX_ALL, __uuidof( Jpx::IJ2kFile ), (void**)&pJpx ); // // if ( !pJpx ) // return NULL; // // CString sOptions; // sOptions.Format( _T("" ), nWidth, nHeight ); // // BSTR bsTempFile = ::SysAllocString( wsTempFile ); // BSTR bsOptions = sOptions.AllocSysString(); // pJpx->InterfaceToJ2k( (IUnknown **)&pInterface, bsTempFile, bsOptions ); // // ::SysFreeString( bsTempFile ); // ::SysFreeString( bsOptions ); // // RELEASEINTERFACE( pInterface ); // RELEASEINTERFACE( pJpx ); // // if ( bAlpha ) // { // // Переводим Image -> IAVSUncompressedVideoFrame // pInterface = NULL; // hRes = CoCreateInstance( MediaCore::CLSID_CAVSUncompressedVideoFrame, NULL, CLSCTX_ALL, MediaCore::IID_IAVSUncompressedVideoFrame, (void**)&pInterface ); // if ( hRes != S_OK ) // return NULL; // // pInterface->put_ColorSpace( ( 1 << 6 ) ); // CPS_BGRA // pInterface->put_Width( nWidth ); // pInterface->put_Height( nHeight ); // pInterface->put_AspectRatioX( nWidth ); // pInterface->put_AspectRatioY( nHeight ); // pInterface->put_Interlaced( VARIANT_FALSE ); // pInterface->put_Stride( 0, 4 * nWidth ); // pInterface->AllocateBuffer( nBufferSize ); // // pBufferPtr = NULL; // nCreatedBufferSize = 0; // // pInterface->get_Buffer( &pBufferPtr ); // pInterface->get_BufferSize( &nCreatedBufferSize ); // pInterface->put_Plane( 0, pBufferPtr ); // // if ( !pBufferPtr || nCreatedBufferSize != nBufferSize ) // return NULL; // // // Пишем данные в pBufferPtr // // for ( int nIndex = 0; nIndex < nWidth * nHeight; nIndex++, pBufferPtr += 4 ) // { // pBufferPtr[0] = pAlphaBuffer[ nIndex ]; // pBufferPtr[1] = pAlphaBuffer[ nIndex ]; // pBufferPtr[2] = pAlphaBuffer[ nIndex ]; // pBufferPtr[3] = 255; // } // // if ( 0 == DocGetTempFile( pPDF, &wsTempAlpha ) ) // { // SetError( pPDF->oMMgr->oError, AVS_OFFICEPDFWRITER_ERROR_FILE_WRITE_ERROR, errno ); // return NULL; // } // // // // Записываем во временный файл картинку в формате Jpx // Jpx::IJ2kFile *pJpx = NULL; // ::CoCreateInstance( __uuidof( Jpx::CJ2kFile ), NULL, CLSCTX_ALL, __uuidof( Jpx::IJ2kFile ), (void**)&pJpx ); // // if ( !pJpx ) // return NULL; // // CString sOptions; // sOptions.Format( _T("" ), nWidth, nHeight ); // // BSTR bsTempFile = ::SysAllocString( wsTempAlpha ); // BSTR bsOptions = sOptions.AllocSysString(); // pJpx->InterfaceToJ2k( (IUnknown **)&pInterface, bsTempFile, bsOptions ); // // ::SysFreeString( bsTempFile ); // ::SysFreeString( bsOptions ); // // RELEASEINTERFACE( pInterface ); // RELEASEINTERFACE( pJpx ); // } // // ImageDict pImage = ImageLoadJpxImage ( pPDF->oMMgr, wsTempFile.GetBuffer(), pPDF->pXref, nWidth, nHeight, unImageCheckSum, bAlpha, wsTempAlpha.GetBuffer(), unAlphaCheckSum ); // // if ( !pImage ) // CheckError( &pPDF->oError ); // //#ifdef FILTER_FLATE_DECODE_ENABLED // if ( pPDF->nCompressionMode & COMP_IMAGE ) // pImage->nFilter |= STREAM_FILTER_FLATE_DECODE; //#endif // // return pImage; //#endif //} ImageDict LoadJpegImageFromMem (Doc pPDF, BYTE *pBuffer, unsigned int nWidth, unsigned int nHeight, unsigned int unImageCheckSum, bool bAlpha/* = false*/, const BYTE *pAlphaBuffer/* = NULL*/, unsigned int unAlphaCheckSum/* = 0*/) { if ( !HasDoc( pPDF )) return NULL; // Создаем темповый файл для записи туда Jpeg CString wsTempFile, wsTempAlpha; if ( 0 == DocGetTempFile( pPDF, &wsTempFile ) ) { SetError( pPDF->oMMgr->oError, AVS_OFFICEPDFWRITER_ERROR_FILE_WRITE_ERROR, errno ); return NULL; } // Записываем во временный файл картинку в формате Jpg Aggplus::CImage image; int BitsPerSample = 3;//alfa отдельно oO ??? image.Create(pBuffer,nWidth, nHeight, - BitsPerSample * nWidth);//+ flip image.m_bExternalBuffer = true; image.SaveFile(string2std_string(wsTempFile), 3/*Jpeg*/); image.Destroy(); if ( bAlpha ) { // Создаем темповый файл для записи туда альфа-канала if ( 0 == DocGetTempFile( pPDF, &wsTempAlpha ) ) { SetError( pPDF->oMMgr->oError, AVS_OFFICEPDFWRITER_ERROR_FILE_WRITE_ERROR, errno ); return NULL; } CEncoderLZW oLZW( pAlphaBuffer, nWidth * nHeight, false ); oLZW.Encode( wsTempAlpha.GetBuffer() ); } ImageDict pImage = ImageLoadJpegImage ( pPDF->oMMgr, wsTempFile.GetBuffer(), pPDF->pXref, nWidth, nHeight, unImageCheckSum, bAlpha, wsTempAlpha.GetBuffer(), unAlphaCheckSum ); if ( !pImage ) CheckError( &pPDF->oError ); #ifdef FILTER_FLATE_DECODE_ENABLED if (pImage && pPDF->nCompressionMode & COMP_IMAGE ) pImage->nFilter |= STREAM_FILTER_FLATE_DECODE; #endif return pImage; } //----------------- Catalog ------------------------------------------------------------------------- PageLayout GetPageLayout (Doc pPDF) { if ( !HasDoc( pPDF ) ) return PLSingle; return CatalogGetPageLayout( pPDF->pCatalog ); } unsigned long SetPageLayout (Doc pPDF, PageLayout eLayout) { unsigned long nRet = OK; if ( !HasDoc( pPDF ) ) return AVS_OFFICEPDFWRITER_ERROR_INVALID_DOCUMENT; if ( eLayout < 0 || eLayout >= PLEOF ) return RaiseError( &pPDF->oError, AVS_OFFICEPDFWRITER_ERROR_PAGE_LAYOUT_OUT_OF_RANGE, (unsigned long)eLayout); nRet = CatalogSetPageLayout( pPDF->pCatalog, eLayout); if ( OK != nRet ) CheckError( &pPDF->oError ); return OK; } PageMode GetPageMode (Doc pPDF) { if ( !HasDoc( pPDF ) ) return PageModeUseNone; return CatalogGetPageMode( pPDF->pCatalog ); } unsigned long SetPageMode (Doc pPDF, PageMode eMode) { unsigned long nRet = OK; if ( !HasDoc( pPDF ) ) return AVS_OFFICEPDFWRITER_ERROR_INVALID_DOCUMENT; if ( eMode < 0 || eMode >= PageModeEOF ) return RaiseError( &pPDF->oError, AVS_OFFICEPDFWRITER_ERROR_PAGE_MODE_OUT_OF_RANGE, (unsigned long)eMode); nRet = CatalogSetPageMode( pPDF->pCatalog, eMode); if ( OK != nRet ) return CheckError( &pPDF->oError); return OK; } unsigned long SetOpenAction (Doc pPDF, Destination pOpenAction) { unsigned long nRet = OK; if ( !HasDoc( pPDF ) ) return AVS_OFFICEPDFWRITER_ERROR_INVALID_DOCUMENT; if ( pOpenAction && !DestinationValidate( pOpenAction ) ) return RaiseError( &pPDF->oError, AVS_OFFICEPDFWRITER_ERROR_INVALID_DESTINATION, 0); nRet = CatalogSetOpenAction( pPDF->pCatalog, pOpenAction ); if ( OK != nRet ) return CheckError( &pPDF->oError); return OK; } unsigned int GetViewerPreference (Doc pPDF) { if ( !HasDoc( pPDF ) ) return 0; return CatalogGetViewerPreference( pPDF->pCatalog ); } unsigned long SetViewerPreference (Doc pPDF, unsigned int nValue) { unsigned long nRet = OK; if ( !HasDoc( pPDF ) ) return AVS_OFFICEPDFWRITER_ERROR_INVALID_DOCUMENT; nRet = CatalogSetViewerPreference( pPDF->pCatalog, nValue ); if ( OK != nRet ) return CheckError( &pPDF->oError); return OK; } unsigned long AddPageLabel (Doc pPDF, unsigned int nPageNum, PageNumStyle eStyle, unsigned int nFirstPage, const char *sPrefix) { Dict pPageLabel = NULL; unsigned long nRet = OK; if ( !HasDoc( pPDF ) ) return AVS_OFFICEPDFWRITER_ERROR_INVALID_DOCUMENT; pPageLabel = PageLabelNew( pPDF, eStyle, nFirstPage, sPrefix ); if ( !pPageLabel ) return CheckError( &pPDF->oError); if ( eStyle < 0 || eStyle >= PageNumStyleEOF ) return RaiseError( &pPDF->oError, AVS_OFFICEPDFWRITER_ERROR_PAGE_NUM_STYLE_OUT_OF_RANGE, (unsigned long)eStyle ); nRet = CatalogAddPageLabel( pPDF->pCatalog, nPageNum, pPageLabel); if ( OK != nRet ) return CheckError( &pPDF->oError); return OK; } //----------------- Info ----------------------------------------------------------------------------- Dict GetInfo (Doc pPDF) { if ( !HasDoc( pPDF ) ) return NULL; if ( !pPDF->pInfo ) { pPDF->pInfo = DictNew( pPDF->oMMgr ); if ( !pPDF->pInfo || XrefAdd( pPDF->pXref, pPDF->pInfo ) != OK ) pPDF->pInfo = NULL; } return pPDF->pInfo; } unsigned long SetInfoAttr (Doc pPDF, InfoType eType, const char *sValue) { unsigned long nRet = OK; Dict pInfo = GetInfo( pPDF ); if ( !pInfo ) return CheckError( &pPDF->oError ); nRet = InfoSetInfoAttr( pInfo, eType, sValue, pPDF->pCurEncoder ); if ( OK != nRet ) return CheckError( &pPDF->oError ); return nRet; } const char* GetInfoAttr (Doc pPDF, InfoType eType) { const char *sRes = NULL; Dict pInfo = GetInfo( pPDF ); if ( pInfo ) sRes = InfoGetInfoAttr( pInfo, eType); else CheckError( &pPDF->oError ); return sRes; } unsigned long SetInfoDateAttr (Doc pPDF, InfoType eType, TDate oDate) { unsigned long nRet = OK; Dict pInfo = GetInfo( pPDF ); if ( !pInfo ) return CheckError( &pPDF->oError ); nRet = InfoSetInfoDateAttr( pInfo, eType, oDate ); if ( OK != nRet ) return CheckError( &pPDF->oError ); return nRet; } Outline CreateOutline (Doc pPDF, Outline pParent, const char *sTitle, EncoderRecPtr pEncoder) { Outline pOutline = NULL; if ( !HasDoc( pPDF ) ) return NULL; if ( !pParent ) { if ( pPDF->pOutlines ) { pParent = pPDF->pOutlines; } else { pPDF->pOutlines = OutlineRootNew( pPDF->oMMgr, pPDF->pXref ); if ( pPDF->pOutlines ) { unsigned long nRet = DictAdd( pPDF->pCatalog, "Outlines", pPDF->pOutlines ); if ( OK != nRet ) { CheckError( &pPDF->oError ); pPDF->pOutlines = NULL; return NULL; } pParent = pPDF->pOutlines; } else { CheckError( &pPDF->oError ); return NULL; } } } if ( !OutlineValidate( pParent ) || pPDF->oMMgr != pParent->oMMgr ) { RaiseError( &pPDF->oError, AVS_OFFICEPDFWRITER_ERROR_INVALID_OUTLINE, 0); return NULL; } pOutline = OutlineNew( pPDF->oMMgr, pParent, sTitle, pEncoder, pPDF->pXref ); if ( !pOutline ) CheckError( &pPDF->oError ); return pOutline; } ExtGState CreateExtGState (Doc pPDF) { ExtGState pExtGState = NULL; if ( !HasDoc( pPDF ) ) return NULL; pPDF->ePdfVersion = PDF_1_4; pExtGState = ExtGStateNew( pPDF->oMMgr, pPDF->pXref ); if (!pExtGState) CheckError( &pPDF->oError ); return pExtGState; } ExtGState FindExtGState (Doc pPDF, float fAlphaStroke/* = -1*/, float fAlphaFill/* = -1*/, BlendMode eMode/* = BMEOF*/, int nStrokeAdjustment/* = -1*/) { ExtGState pExtGState = NULL; for ( unsigned int nIndex = 0; nIndex < pPDF->pExtGStateList->nCount; nIndex++) { pExtGState = (ExtGState)ListItemAt( pPDF->pExtGStateList, nIndex); // Сравниваем CA Real pAlphaStroke = (Real)DictGetItem( (Dict)pExtGState, "CA", OCLASS_REAL ); if ( NULL == pAlphaStroke ) { if ( -1 != fAlphaStroke ) continue; } else { if ( -1 == fAlphaStroke || pAlphaStroke->fValue != fAlphaStroke ) continue; } // Сравниваем ca Real pAlphaFill = (Real)DictGetItem( (Dict)pExtGState, "ca", OCLASS_REAL ); if ( NULL == pAlphaFill ) { if ( -1 != fAlphaFill ) continue; } else { if ( -1 == fAlphaFill || pAlphaFill->fValue != fAlphaFill ) continue; } // Сравниваем BlendMode Name pBlendMode = (Name)DictGetItem( (Dict)pExtGState, "BM", OCLASS_NAME ); if ( NULL == pBlendMode ) { if ( BMEOF != eMode ) continue; } else { if ( BMEOF == eMode || 0 != UtilsStrCmp( pBlendMode->sValue, BM_NAMES[ (int)eMode ] ) ) continue; } // Сравниваем StrokeAdjustment BooleanRecPtr pSA = (BooleanRecPtr)DictGetItem( (Dict)pExtGState, "SA", OCLASS_BOOLEAN ); if ( NULL == pSA ) { if ( -1 != nStrokeAdjustment ) continue; } else { if ( -1 == nStrokeAdjustment || ( 0 == nStrokeAdjustment && true == pSA->bValue ) || ( 1 == nStrokeAdjustment && false == pSA->bValue ) ) continue; } return pExtGState; } return NULL; } ExtGState GetExtGState (Doc pPDF, float fAlphaStroke/* = -1*/, float fAlphaFill/* = -1*/, BlendMode eMode/* = BMEOF*/, int nStrokeAdjustment /*= -1*/) { ExtGState pExtGState = FindExtGState( pPDF, fAlphaStroke, fAlphaFill, eMode, nStrokeAdjustment ); if ( NULL == pExtGState ) { pExtGState = CreateExtGState( pPDF ); if ( NULL == pExtGState ) return NULL; if ( -1 != fAlphaStroke ) ExtGStateSetAlphaStroke( pExtGState, fAlphaStroke ); if ( -1 != fAlphaFill ) ExtGStateSetAlphaFill( pExtGState, fAlphaFill ); if ( BMEOF != eMode ) ExtGStateSetBlendMode( pExtGState, eMode ); if ( -1 != nStrokeAdjustment ) ExtGStateSetStrokeAdjustment( pExtGState, (bool)nStrokeAdjustment ); ListAdd( pPDF->pExtGStateList, pExtGState ); } return pExtGState; } unsigned long SetCompressionMode (Doc pPDF, unsigned int nMode) { if ( !DocValidate( pPDF ) ) return AVS_OFFICEPDFWRITER_ERROR_INVALID_DOCUMENT; if ( nMode != ( nMode & COMP_MASK ) ) return RaiseError( &pPDF->oError, AVS_OFFICEPDFWRITER_ERROR_INVALID_COMPRESSION_MODE, 0); #ifndef NOZLIB pPDF->nCompressionMode = nMode; return OK; #else /* NOZLIB */ return AVS_OFFICEPDFWRITER_ERROR_INVALID_COMPRESSION_MODE; #endif /* NOZLIB */ } unsigned long GetError (Doc pPDF) { if ( !DocValidate( pPDF ) ) return AVS_OFFICEPDFWRITER_ERROR_INVALID_DOCUMENT; return ErrorGetCode( &pPDF->oError ); } unsigned long GetErrorDetail (Doc pPDF) { if ( !DocValidate( pPDF ) ) return AVS_OFFICEPDFWRITER_ERROR_INVALID_DOCUMENT; return ErrorGetDetailCode( &pPDF->oError ); } void ResetError (Doc pPDF) { if ( !DocValidate( pPDF ) ) return; ErrorReset( &pPDF->oError ); } //----------------- Основные функции ----------------------------------------------------------------- bool DocValidate (Doc pPDF) { if ( !pPDF || pPDF->nSigBytes != SIG_BYTES ) return false; else return true; } bool HasDoc (Doc pPDF) { if ( !pPDF || pPDF->nSigBytes != SIG_BYTES ) return false; if ( !pPDF->pCatalog/* || pPDF->oError.nErrorNo != NOERROR*/) { RaiseError( &pPDF->oError, AVS_OFFICEPDFWRITER_ERROR_INVALID_DOCUMENT, 0 ); return false; } else return true; } void FreeDoc (Doc pPDF) { if ( DocValidate( pPDF ) ) { if ( pPDF->pXref ) { XrefFree( pPDF->pXref ); pPDF->pXref = NULL; } if ( pPDF->pFontManager ) { ListFree( pPDF->pFontManager ); pPDF->pFontManager = NULL; } if ( pPDF->pFontDefList ) CleanupFontDefList( pPDF ); UtilsMemSet( pPDF->aTTFontTag, 0, 6); pPDF->ePdfVersion = PDF_1_3; pPDF->pOutlines = NULL; pPDF->pCatalog = NULL; pPDF->pRootPages = NULL; pPDF->pCurPages = NULL; pPDF->pCurPage = NULL; pPDF->bEncryptOn = false; pPDF->nCurPageNum = 0; pPDF->pCurEncoder = NULL; pPDF->pDefEncoder = NULL; pPDF->nPagePerPages = 0; if ( pPDF->pPageList ) { ListFree( pPDF->pPageList ); pPDF->pPageList = NULL; } if ( pPDF->pExtGStateList ) { ListFree( pPDF->pExtGStateList ); pPDF->pExtGStateList = NULL; } pPDF->pEncryptDict = NULL; pPDF->pInfo = NULL; ErrorReset( &pPDF->oError ); if ( pPDF->pStream ) { StreamFree( pPDF->pStream ); pPDF->pStream = NULL; } ::memset( pPDF->wsTempDir, 0x00, MAX_PATH ); } } void FreeDocAll (Doc pPDF) { if ( DocValidate( pPDF ) ) { FreeDoc( pPDF ); if ( pPDF->pFontDefList ) FreeFontDefList( pPDF ); if ( pPDF->pEncoderList ) FreeEncoderList( pPDF ); if ( pPDF->pToUnicodeList ) FreeToUnicodeList( pPDF ); pPDF->nCompressionMode = COMP_NONE; ErrorReset( &pPDF->oError ); } } void Free (Doc pPDF) { if ( pPDF ) { MMgr oMMgr = pPDF->oMMgr; FreeDocAll( pPDF ); pPDF->nSigBytes = 0; FreeMem( oMMgr, pPDF ); MMgrFree( oMMgr ); } } unsigned long NewDoc (Doc pPDF) { if ( !DocValidate( pPDF ) ) return AVS_OFFICEPDFWRITER_ERROR_DOC_INVALID_OBJECT; FreeDoc( pPDF ); pPDF->pXref = XrefNew( pPDF->oMMgr, 0); if ( !pPDF->pXref ) return CheckError( &pPDF->oError ); pPDF->pTrailer = pPDF->pXref->oTrailer; pPDF->pFontManager = ListNew( pPDF->oMMgr, DEF_ITEMS_PER_BLOCK ); if ( !pPDF->pFontManager ) return CheckError( &pPDF->oError ); if ( !pPDF->pFontDefList ) { pPDF->pFontDefList = ListNew( pPDF->oMMgr, DEF_ITEMS_PER_BLOCK); if ( !pPDF->pFontDefList ) return CheckError( &pPDF->oError ); } if ( !pPDF->pEncoderList ) { pPDF->pEncoderList = ListNew( pPDF->oMMgr, DEF_ITEMS_PER_BLOCK ); if ( !pPDF->pEncoderList ) return CheckError( &pPDF->oError ); } if ( !pPDF->pToUnicodeList ) { pPDF->pToUnicodeList = ListNew( pPDF->oMMgr, DEF_ITEMS_PER_BLOCK ); if ( !pPDF->pToUnicodeList ) return CheckError( &pPDF->oError ); } if ( !pPDF->pExtGStateList ) { pPDF->pExtGStateList = ListNew( pPDF->oMMgr, DEF_ITEMS_PER_BLOCK ); if ( !pPDF->pExtGStateList ) return CheckError( &pPDF->oError ); } pPDF->pCatalog = CatalogNew( pPDF->oMMgr, pPDF->pXref ); if ( !pPDF->pCatalog) return CheckError( &pPDF->oError ); pPDF->pRootPages = CatalogGetRoot( pPDF->pCatalog ); if ( !pPDF->pRootPages ) return CheckError( &pPDF->oError ); pPDF->pPageList = ListNew( pPDF->oMMgr, DEF_PAGE_LIST_NUM ); if ( !pPDF->pPageList ) return CheckError( &pPDF->oError ); pPDF->pCurPages = pPDF->pRootPages; char sBuf[TEMP_BUFFER_SIZE]; char *pPointer = sBuf; char *pEndPointer = sBuf + TEMP_BUFFER_SIZE - 1; const char *sVersion; pPointer = (char *)UtilsStrCpy( pPointer, "Ascensio System SIA Copyright (c) 2013", pEndPointer); //sVersion = STRVER; // UtilsStrCpy( pPointer, sVersion, pEndPointer); if ( OK != SetInfoAttr( pPDF, InfoProducer, sBuf ) ) return CheckError( &pPDF->oError ); //pPDF->resources = CreateExtGState(pPDF); // список ресурсов ( в атрибут Resources если записывать данные то Adobe просмотрщик не видит их ) return OK; } Doc NewEx (ErrorHandler pUserErrorFn, AllocFunc pUserAllocFn, FreeFunc pUserFreeFn, unsigned int nMemPoolBufSize, void *pUserData) { ErrorRec oTempError; // инициализируем временный объект описания ошибок ErrorInit( &oTempError, pUserData ); // создаем объект для управления памятью MMgr oMMgr = MMgrNew( &oTempError, nMemPoolBufSize, pUserAllocFn, pUserFreeFn ); if ( !oMMgr ) { CheckError( &oTempError ); return NULL; } // создаем объект - документ Doc pPDF = (Doc)GetMem( oMMgr, sizeof (DocRec) ); if ( !pPDF ) { MMgrFree( oMMgr ); CheckError( &oTempError ); return NULL; } oMMgr->pDoc = pPDF; UtilsMemSet( pPDF, 0, sizeof( DocRec ) ); pPDF->nSigBytes = SIG_BYTES; pPDF->oMMgr = oMMgr; pPDF->ePdfVersion = PDF_1_3; pPDF->nCompressionMode = COMP_NONE; // копируем данные из oTempError в объект для ошибок, содержащийся в структуре Doc pPDF->oError = oTempError; // меням указатель на объект Error для MemoryManager oMMgr->oError = &pPDF->oError; if ( OK != NewDoc( pPDF ) ) { Free( pPDF ); CheckError( &oTempError ); return NULL; } pPDF->oError.ErrorFn = pUserErrorFn; pPDF->nCMapCount = 0; return pPDF; } Doc New (ErrorHandler pUserErrorFn, void *pUserData) { return NewEx( pUserErrorFn, NULL, NULL, 0, pUserData); } Doc New (void) { return New( NULL, NULL); } unsigned long SetPagesConfiguration (Doc pPDF, unsigned int nPagePerPages) { if ( !HasDoc( pPDF ) ) return AVS_OFFICEPDFWRITER_ERROR_INVALID_DOCUMENT; if ( pPDF->pCurPage ) return RaiseError( &pPDF->oError, AVS_OFFICEPDFWRITER_ERROR_INVALID_DOCUMENT_STATE, 0); if ( nPagePerPages > LIMIT_MAX_ARRAY ) return RaiseError( &pPDF->oError, AVS_OFFICEPDFWRITER_ERROR_INVALID_PARAMETER, 0); if ( pPDF->pCurPages == pPDF->pRootPages ) { pPDF->pCurPages = DocAddPagesTo( pPDF, pPDF->pRootPages ); if ( !pPDF->pCurPages ) return pPDF->oError.nErrorNo; pPDF->nCurPageNum = 0; } pPDF->nPagePerPages = nPagePerPages; return OK; } unsigned long DocSetEncryptOn (Doc pPDF) { if ( pPDF->bEncryptOn ) return OK; if ( !pPDF->pEncryptDict ) return SetError( &pPDF->oError, AVS_OFFICEPDFWRITER_ERROR_DOC_ENCRYPTDICT_NOT_FOUND, 0); if ( OTYPE_NONE == pPDF->pEncryptDict->pHeader.nObjClass ) if ( OK != XrefAdd( pPDF->pXref, pPDF->pEncryptDict ) ) return pPDF->oError.nErrorNo; if ( OK != DictAdd( pPDF->pTrailer, "EncryptRecPtr", pPDF->pEncryptDict ) ) return pPDF->oError.nErrorNo; pPDF->bEncryptOn = true; return OK; } unsigned long SetPassword (Doc pPDF, const char *sOwnerPassword, const char *sUserPassword) { if ( !HasDoc( pPDF ) ) return AVS_OFFICEPDFWRITER_ERROR_DOC_INVALID_OBJECT; if ( !pPDF->pEncryptDict ) { pPDF->pEncryptDict = EncryptDictNew( pPDF->oMMgr, pPDF->pXref ); if ( !pPDF->pEncryptDict ) return CheckError( &pPDF->oError ); } if ( OK != EncryptDictSetPassword( pPDF->pEncryptDict, sOwnerPassword, sUserPassword ) ) return CheckError( &pPDF->oError ); return DocSetEncryptOn( pPDF ); } unsigned long SetPermission (Doc pPDF, unsigned int nPermission) { if ( !HasDoc( pPDF ) ) return AVS_OFFICEPDFWRITER_ERROR_DOC_INVALID_OBJECT; EncryptRecPtr pEncrypt = EncryptDictGetAttr( pPDF->pEncryptDict ); if ( !pEncrypt ) return RaiseError( &pPDF->oError, AVS_OFFICEPDFWRITER_ERROR_DOC_ENCRYPTDICT_NOT_FOUND, 0); else pEncrypt->nPermission = nPermission; return OK; } unsigned long SetEncryptionMode (Doc pPDF, EncryptMode eMode, unsigned int nKeyLen) { if ( !HasDoc( pPDF ) ) return AVS_OFFICEPDFWRITER_ERROR_DOC_INVALID_OBJECT; EncryptRecPtr pEncrypt = EncryptDictGetAttr( pPDF->pEncryptDict ); if ( !pEncrypt ) return RaiseError( &pPDF->oError, AVS_OFFICEPDFWRITER_ERROR_DOC_ENCRYPTDICT_NOT_FOUND, 0); else { if ( EncryptR2 == eMode ) pEncrypt->nKeyLen = 5; else { pPDF->ePdfVersion = PDF_1_4; if ( nKeyLen >= 5 && nKeyLen <= 16 ) pEncrypt->nKeyLen = nKeyLen; else if ( 0 == nKeyLen ) pEncrypt->nKeyLen = 16; else return RaiseError( &pPDF->oError, AVS_OFFICEPDFWRITER_ERROR_INVALID_ENCRYPT_KEY_LEN, 0 ); } pEncrypt->eMode = eMode; } return OK; } unsigned long DocSetEncryptOff (Doc pPDF) { if ( !pPDF->bEncryptOn ) return OK; // Если EncryptDict зарегистрирован в cross-reference-table, заменяем его нулевым объектом. // Кроме этого, удаляем EncryptDict из трайлера. if ( pPDF->pEncryptDict ) { unsigned int nObjId = pPDF->pEncryptDict->pHeader.nObjId; if ( nObjId & OTYPE_INDIRECT ) { DictRemoveElement( pPDF->pTrailer, "EncryptRecPtr" ); XrefEntry pEntry = XrefGetEntryByObjectId( pPDF->pXref, nObjId & 0x00FFFFFF ); if ( !pEntry ) return SetError( &pPDF->oError, AVS_OFFICEPDFWRITER_ERROR_DOC_ENCRYPTDICT_NOT_FOUND, 0); Null pNull = NullNew( pPDF->oMMgr ); if ( !pNull ) return pPDF->oError.nErrorNo; pEntry->pObj = pNull; pNull->pHeader.nObjId = nObjId | OTYPE_INDIRECT; pPDF->pEncryptDict->pHeader.nObjId = OTYPE_NONE; } } pPDF->bEncryptOn = false; return OK; } unsigned long DocPrepareEncryption (Doc pPDF) { EncryptRecPtr pEncrypt = EncryptDictGetAttr( pPDF->pEncryptDict ); Dict pInfo = GetInfo( pPDF ); if ( !pEncrypt ) return AVS_OFFICEPDFWRITER_ERROR_DOC_ENCRYPTDICT_NOT_FOUND; if ( !pInfo ) return pPDF->oError.nErrorNo; if ( OK != EncryptDictPrepare( pPDF->pEncryptDict, pInfo, pPDF->pXref ) ) return pPDF->oError.nErrorNo; Array pID = (Array)DictGetItem( pPDF->pTrailer, "ID", OCLASS_ARRAY ); if ( !pID ) { pID = ArrayNew( pPDF->oMMgr ); if ( !pID || OK != DictAdd( pPDF->pTrailer, "ID", pID ) ) return pPDF->oError.nErrorNo; } else ArrayClear( pID ); if ( OK != ArrayAdd( pID, BinaryNew( pPDF->oMMgr, pEncrypt->anEncryptID, ID_LEN ) ) ) return pPDF->oError.nErrorNo; if ( OK != ArrayAdd( pID, BinaryNew( pPDF->oMMgr, pEncrypt->anEncryptID, ID_LEN ) ) ) return pPDF->oError.nErrorNo; return OK; } unsigned long SaveToStream (Doc pPDF) { if ( !HasDoc( pPDF ) ) return AVS_OFFICEPDFWRITER_ERROR_INVALID_DOCUMENT; if ( !pPDF->pStream ) pPDF->pStream = MemStreamNew( pPDF->oMMgr, STREAM_BUF_SIZ ); if ( !StreamValidate( pPDF->pStream ) ) return RaiseError( &pPDF->oError, AVS_OFFICEPDFWRITER_ERROR_INVALID_STREAM, 0); MemStreamFreeData( pPDF->pStream ); if ( OK != InternalSaveToStream( pPDF, pPDF->pStream ) ) return CheckError( &pPDF->oError ); return OK; } unsigned long InternalSaveToStream (Doc pPDF, StreamRecPtr pStream) { unsigned long nRet = OK; // пишем заголовок if ( OK != ( nRet = WriteHeader( pPDF, pStream ) ) ) return nRet; // подготовка trailer if ( OK != ( nRet = PrepareTrailer( pPDF ) ) ) return nRet; // подготовка шифрования if ( pPDF->bEncryptOn ) { EncryptRecPtr pEncrypt = EncryptDictGetAttr( pPDF->pEncryptDict ); if ( OK != ( nRet = DocPrepareEncryption( pPDF ) ) ) return nRet; if ( OK != ( nRet = XrefWriteToStream( pPDF->pXref, pStream, pEncrypt ) ) ) return nRet; } else { if ( OK != ( nRet = XrefWriteToStream( pPDF->pXref, pStream, NULL ) ) ) return nRet; } return OK; } //const char* LoadType1FontFromStream(Doc pPDF, StreamRecPtr pAfmData, StreamRecPtr pPfmData, short nType/* = 0*/); //const char* LoadTTFontFromStream (Doc pPDF, bool bEmbedding, std::wstring & wsFileName, const char *sEncodingName = NULL, const char *sPrefix = NULL); //const char* LoadTTFontFromStream2 (Doc pPDF, unsigned int nIndex, bool bEmbedding, std::wstring & wsFileName); unsigned int GetStreamSize (Doc pPDF) { if ( !HasDoc( pPDF ) ) return AVS_OFFICEPDFWRITER_ERROR_INVALID_DOCUMENT; if ( !StreamValidate( pPDF->pStream ) ) return 0; return StreamSize( pPDF->pStream ); } unsigned long ReadFromStream (Doc pPDF, BYTE *pBuf, unsigned int *pnSize) { unsigned int nSize = *pnSize; unsigned long nRet = OK; if ( !HasDoc( pPDF ) ) return AVS_OFFICEPDFWRITER_ERROR_INVALID_DOCUMENT; if ( !StreamValidate( pPDF->pStream ) ) return RaiseError( &pPDF->oError, AVS_OFFICEPDFWRITER_ERROR_INVALID_OPERATION, 0); if ( *pnSize == 0 ) return RaiseError( &pPDF->oError, AVS_OFFICEPDFWRITER_ERROR_INVALID_PARAMETER, 0); nRet = StreamRead( pPDF->pStream, pBuf, &nSize ); *pnSize = nSize; if ( OK != nRet ) CheckError( &pPDF->oError ); return nRet; } unsigned long ResetStream (Doc pPDF) { if ( !HasDoc( pPDF ) ) return AVS_OFFICEPDFWRITER_ERROR_INVALID_DOCUMENT; if ( !StreamValidate( pPDF->pStream ) ) return RaiseError( &pPDF->oError, AVS_OFFICEPDFWRITER_ERROR_INVALID_OPERATION, 0); return StreamSeek( pPDF->pStream, 0, SeekSet ); } unsigned long SaveDocToFile (Doc pPDF, std::wstring & wsFileName) { if ( !HasDoc( pPDF ) ) return AVS_OFFICEPDFWRITER_ERROR_INVALID_DOCUMENT; StreamRecPtr pStream = FileWriterNew( pPDF->oMMgr, wsFileName, true ); if ( !pStream ) return CheckError( &pPDF->oError ); InternalSaveToStream( pPDF, pStream ); StreamFree( pStream ); return CheckError( &pPDF->oError ); } Page GetCurrentPage (Doc pPDF) { if ( !HasDoc( pPDF ) ) return NULL; return pPDF->pCurPage; } Page GetPageByIndex (Doc pPDF, unsigned int nIndex) { Page pRes = NULL; if ( !HasDoc( pPDF ) ) return NULL; pRes = (Page)ListItemAt( pPDF->pPageList, nIndex ); if ( !pRes ) { RaiseError( &pPDF->oError, AVS_OFFICEPDFWRITER_ERROR_INVALID_PAGE_INDEX, 0 ); return NULL; } return pRes; } Pages DocGetCurrentPages (Doc pPDF) { if ( !HasDoc( pPDF ) ) return NULL; return pPDF->pCurPages; } unsigned long DocSetCurrentPages (Doc pPDF, Pages pPages) { if ( !HasDoc( pPDF ) ) return AVS_OFFICEPDFWRITER_ERROR_INVALID_DOCUMENT; if ( !PagesValidate( pPages ) ) return SetError( &pPDF->oError, AVS_OFFICEPDFWRITER_ERROR_INVALID_PAGES, 0 ); // проверяем принадлежит ли объект pPages нашему pdf - документу if ( pPDF->oMMgr != pPages->oMMgr ) return SetError( &pPDF->oError, AVS_OFFICEPDFWRITER_ERROR_INVALID_PAGES, 0 ); pPDF->pCurPages = pPages; return OK; } unsigned long DocSetCurrentPage (Doc pPDF, Page pPage) { if ( !HasDoc( pPDF ) ) return AVS_OFFICEPDFWRITER_ERROR_INVALID_DOCUMENT; if ( !PageValidate( pPage ) ) return SetError( &pPDF->oError, AVS_OFFICEPDFWRITER_ERROR_INVALID_PAGE, 0); // проверяем принадлежит ли объект pPage нашему pdf - документу if ( pPDF->oMMgr != pPage->oMMgr ) return SetError( &pPDF->oError, AVS_OFFICEPDFWRITER_ERROR_INVALID_PAGE, 0 ); pPDF->pCurPage = pPage; return OK; } unsigned long DocSetTempDir (Doc pPDF, wchar_t *wsTempDir) { if ( !HasDoc( pPDF ) ) return AVS_OFFICEPDFWRITER_ERROR_INVALID_DOCUMENT; wcscpy( pPDF->wsTempDir, wsTempDir ); return OK; } Page AddPage (Doc pPDF) { if ( !HasDoc( pPDF ) ) return NULL; Page pPage; unsigned long nRet = OK; if ( pPDF->nPagePerPages ) { if ( pPDF->nPagePerPages <= pPDF->nCurPageNum ) { pPDF->pCurPages = DocAddPagesTo( pPDF, pPDF->pRootPages ); if ( !pPDF->pCurPages ) return NULL; pPDF->nCurPageNum = 0; } } pPage = PageNew( pPDF->oMMgr, pPDF->pXref ); if ( !pPage ) { CheckError( &pPDF->oError ); return NULL; } if ( OK != ( nRet = PagesAddKids( pPDF->pCurPages, pPage ) ) ) { RaiseError( &pPDF->oError, nRet, 0); return NULL; } if ( OK != ( nRet = ListAdd( pPDF->pPageList, pPage ) ) ) { RaiseError( &pPDF->oError, nRet, 0); return NULL; } pPDF->pCurPage = pPage; #ifdef FILTER_FLATE_DECODE_ENABLED if ( pPDF->nCompressionMode & COMP_TEXT ) PageSetFilter( pPage, STREAM_FILTER_FLATE_DECODE ); #endif pPDF->nCurPageNum++; return pPage; } Pages DocAddPagesTo (Doc pPDF, Pages pParent) { Pages pPages = NULL; if ( !HasDoc( pPDF ) ) return NULL; if ( !PagesValidate( pParent ) ) { RaiseError( &pPDF->oError, AVS_OFFICEPDFWRITER_ERROR_INVALID_PAGES, 0); return NULL; } // проверяем принадлежит ли страница нашему PDF документу if ( pPDF->oMMgr != pParent->oMMgr ) { RaiseError( &pPDF->oError, AVS_OFFICEPDFWRITER_ERROR_INVALID_PAGES, 0); return NULL; } pPages = PagesNew( pPDF->oMMgr, pParent, pPDF->pXref ); if ( pPages ) pPDF->pCurPages = pPages; else CheckError( &pPDF->oError ); return pPages; } Page InsertPage (Doc pPDF, Page pTarget) { Page pPage = NULL; unsigned long nRet = OK; if ( !HasDoc( pPDF ) ) return NULL; if ( !PageValidate( pTarget ) ) { RaiseError( &pPDF->oError, AVS_OFFICEPDFWRITER_ERROR_INVALID_PAGE, 0); return NULL; } // проверяем принадлежит ли объект pTarget нашему pdf - документу if ( pPDF->oMMgr != pTarget->oMMgr ) { RaiseError( &pPDF->oError, AVS_OFFICEPDFWRITER_ERROR_INVALID_PAGE, 0); return NULL; } pPage = PageNew( pPDF->oMMgr, pPDF->pXref ); if ( !pPage ) { CheckError( &pPDF->oError ); return NULL; } if ( OK != ( nRet = PageInsertBefore( pPage, pTarget ) ) ) { RaiseError( &pPDF->oError, nRet, 0 ); return NULL; } if ( OK != ( nRet = ListInsert( pPDF->pPageList, pTarget, pPage ) ) ) { RaiseError( &pPDF->oError, nRet, 0 ); return NULL; } #ifdef FILTER_FLATE_DECODE_ENABLED if ( pPDF->nCompressionMode & COMP_TEXT ) PageSetFilter( pPage, STREAM_FILTER_FLATE_DECODE ); #endif return pPage; } unsigned long SetErrorHandler (Doc pPDF, ErrorHandler pUserErrorFn) { if ( !DocValidate( pPDF ) ) return AVS_OFFICEPDFWRITER_ERROR_INVALID_DOCUMENT; pPDF->oError.ErrorFn = pUserErrorFn; return OK; }