// FontManager.h : Declaration of the CFontManager #pragma once #include "resource.h" // main symbols #include "Registration.h" #include "Consts.h" #include "WinFont.h" #include "Errors.h" #include "FontUtils.h" #include "FontEngine.h" #include "FT_Font.h" #include "Path.h" #include FT_ADVANCES_H #include FT_GLYPH_H #if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA) #error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms." #endif // IFontManager [ object, uuid("8C0DA859-68A6-4CDB-9C48-8B6D66EFAC1F"), dual, helpstring("IFontManager Interface"), pointer_default(unique) ] __interface IFontManager : IDispatch { //----- Открытие/закрытие шрифта -------------------------------------------------------------------- [id(001)] HRESULT Initialize([in] BSTR bsXmlOptions); [id(002)] HRESULT LoadFontFromFile([in]BSTR bsSrcPath, [in] float fEmSize, [in] unsigned int unHorDPI, [in] unsigned int unVerDPI, [in] long lFaceIndex = 0); [id(003)] HRESULT LoadFontByName([in]BSTR bsFamilyName, [in] float fEmSize, [in] long lStyle, [in] unsigned int unHorDPI, [in]unsigned int unVerDPI); [id(004)] HRESULT GetFontType([out, retval] BSTR *pbsType); [id(005)] HRESULT SetDefaultFont([in] BSTR bsFamilyName); //----- Функции аналогичные методам классов Font и FontFamily в GDI+ -------------------------------- [id(101)] HRESULT GetCellAscent([out, retval] unsigned short *pusAscent); [id(102)] HRESULT GetCellDescent([out, retval] unsigned short *pusDescent); [id(103)] HRESULT GetEmHeight([out, retval] unsigned short *pusEmHeight); [id(104)] HRESULT GetFamilyName([out, retval] BSTR *pbsFamilyName); [id(105)] HRESULT GetLineSpacing([out, retval] unsigned short *pusLineSpacing); [id(106)] HRESULT IsStyleAvailable([in] long lStyle, [out, retval] BOOL *pbAvailable); [id(107)] HRESULT GetHeight([in] float fDPI, [out, retval] float *pfHeight); //----- Чтение глобальных параметров шрифта --------------------------------------------------------- [id(201)] HRESULT GetFacesCount([out, retval] long *plFacesCount); [id(202)] HRESULT GetFaceIndex([out, retval] long *plFaceIndex); [id(203)] HRESULT GetGlyphsCount([out, retval] long *plGlyphsCount); [id(205)] HRESULT GetStyleName([out, retval] BSTR *pbsStyleName); [id(206)] HRESULT IsCharAvailable([in] long lUnicode, [out, retval] BOOL *pbAvailable); [id(207)] HRESULT GetUnderlinePosition([out, retval] short *pshUnderPos); [id(208)] HRESULT GetUnderlineThickness([out, retval] short *pshUnderThick); [id(209)] HRESULT GetMaxAdvanceWidth([out, retval] short *pshMaxAdvWidth); [id(210)] HRESULT GetMaxAdvanceHeight([out, retval] short *pshMaxAdvHeight); [id(211)] HRESULT GetBBox([out] long *plMinX, [out] long *plMinY, [out] long *plMaxX, [out] long *plMaxY); [id(212)] HRESULT IsUnicodeRangeAvailable([in] unsigned long ulBit, [in] unsigned int unLongIndex, [out ,retval] VARIANT_BOOL *pvbSuccess); //----- Работа с глифами ---------------------------------------------------------------------------- [id(301)] HRESULT GetGlyphPath([in] long lUnicode, [out, retval] BSTR *pbsXmlPath); [id(302)] HRESULT GetStringPath([in] BSTR bsString, [out, retval] BSTR *pbsXmlPath); [id(303)] HRESULT GetGlyphBitmap([in] long lUnicode, [out, retval]IUnknown **ppImage); [id(304)] HRESULT GetStringBitmap([in] BSTR bsString, [out, retval] IUnknown **ppImage); [id(305)] HRESULT LoadString([in] BSTR bsString); [id(306)] HRESULT GetNextChar([out] IUnknown **ppImage, [out] float *pfX, [out] float *pfY, [out, retval] VARIANT_BOOL *pvbSuccess); [id(307)] HRESULT GetCharBBox([out] float *pfLeft, [out] float *pfTop, [out] float *pfRight, [out] float *pfBottom); [id(308)] HRESULT MeasureString([out] float *pfLeft, [out] float *pfTop, [out] float *pfRight, [out] float *pfBottom); [id(309)] HRESULT ApplyTransform([in] float fA, [in] float fB, [in] float fC, [in] float fD, [in] float fE, [in] float fF); //----- Работа со шрифтами Windows ------------------------------------------------------------------ [id(501)] HRESULT GetWinFontsCount([out, retval] long *plCount); [id(502)] HRESULT GetWinFont([in] long nIndex, [out] BSTR *pbsFontName, [out] BSTR *pbsFontStyle, [out] BSTR *pbsFontPath, [out] long *plIndex, [out] BOOL *pbBold, [out] BOOL *pbItalic); }; // CFontManager [ coclass, default(IFontManager), threading(apartment), vi_progid("AVSOfficeFontManager.FontManager"), progid("AVSOfficeFontManager.FontManager.1"), version(1.0), uuid("0FF37CE6-DD3C-488F-8319-13D9E392F1D8"), helpstring("FontManager Class") ] class ATL_NO_VTABLE CFontManager : public IFontManager { public: private: float m_fEmSize; long m_lUnit; TGlyph *m_pGlyphsBuffer; // Для работы со строкой unsigned int m_nGlyphsCount; // Количество символов в строке unsigned int m_nGlyphIndex; // Номер текущего символа CFontEngine *m_pFontEngine; // Класс для работы со шрифтами (установленные шрифты, кэш шрифтов и т.д.) CFont *m_pFont; // Текущий шрифт public: CFontManager() { } DECLARE_PROTECT_FINAL_CONSTRUCT() HRESULT FinalConstruct() { m_pFontEngine = NULL; m_pFont = NULL; m_pGlyphsBuffer = NULL; m_nGlyphsCount = 0; m_nGlyphIndex = -1; return S_OK; } void FinalRelease() { if ( m_pFontEngine ) { delete m_pFontEngine; } } private: public: //----- Открытие/закрытие шрифта -------------------------------------------------------------------- STDMETHOD(Initialize)(BSTR bsXmlOptions) { m_pFontEngine = new CFontEngine(TRUE); return S_OK; } STDMETHOD(LoadFontFromFile)(BSTR bsSrcPath, float fEmSize, unsigned int unHorDpi, unsigned int unVerDpi, long lFaceIndex) { if ( !m_pFontEngine ) return S_FALSE; CFontFile *pFontFile = NULL; if ( !( pFontFile = m_pFontEngine->GetFontFile( bsSrcPath, lFaceIndex ) ) ) { pFontFile = m_pFontEngine->LoadFont( bsSrcPath, lFaceIndex ); } if ( !pFontFile ) return AVS_OFFICEFONTMANAGER_ERROR_FONT_OPEN_ERROR; m_pFont = m_pFontEngine->GetFont( pFontFile ); if ( !m_pFont ) return S_FALSE; UpdateStyles( m_pFont, FALSE, FALSE ); m_pFont->SetDefaultFont( m_pFontEngine->GetDefaultFont( FALSE, FALSE ) ); m_pFont->SetSizeAndDpi( fEmSize, unHorDpi, unVerDpi ); return S_OK; } STDMETHOD(LoadFontByName)(BSTR bsFamilyName, float fEmSize, long lStyle, unsigned int unHorDpi, unsigned int unVerDpi) { if ( !m_pFontEngine ) return S_FALSE; BOOL bBold = FALSE; BOOL bItalic = FALSE; switch (lStyle) { case FontConstants::FontStyle::FontStyleRegular: bBold = FALSE; bItalic = FALSE; break; case FontConstants::FontStyle::FontStyleItalic: bBold = FALSE; bItalic = TRUE; break; case FontConstants::FontStyle::FontStyleBold: bBold = TRUE; bItalic = FALSE; break; case FontConstants::FontStyle::FontStyleBoldItalic: bBold = TRUE; bItalic = TRUE; break; } CFontFile *pFontFile = NULL; if ( !( pFontFile = m_pFontEngine->GetFontFile( bsFamilyName, bBold, bItalic ) ) ) { pFontFile = m_pFontEngine->LoadFont( bsFamilyName, bBold, bItalic ); } if ( !pFontFile ) return AVS_OFFICEFONTMANAGER_ERROR_WIN_FONT_NOT_FOUND; m_pFont = m_pFontEngine->GetFont( pFontFile ); if ( !m_pFont ) return S_FALSE; UpdateStyles( m_pFont, bBold, bItalic ); m_pFont->SetDefaultFont( m_pFontEngine->GetDefaultFont( bBold, bItalic ) ); m_pFont->SetSizeAndDpi( fEmSize, unHorDpi, unVerDpi ); return S_OK; } STDMETHOD(GetFontType)(BSTR *pbsType) { CStringW wsType = _T(""); if ( !m_pFont ) { *pbsType = wsType.AllocSysString(); return AVS_OFFICEFONTMANAGER_ERROR_FONT_WASNT_LOAD; } wsType = m_pFont->GetFontFormat(); *pbsType = wsType.AllocSysString(); return S_OK; } STDMETHOD(SetDefaultFont)(BSTR bsFamilyName) { if ( !m_pFontEngine ) return S_FALSE; m_pFontEngine->SetDefaultFont( bsFamilyName ); return S_OK; } //----- Функции аналогичные методам классов Font и FontFamily в GDI+ -------------------------------- STDMETHOD(GetCellAscent)(unsigned short *pusAscent) { if ( !m_pFont ) { *pusAscent = 0; return AVS_OFFICEFONTMANAGER_ERROR_FONT_WASNT_LOAD; } *pusAscent = m_pFont->GetAscender(); return S_OK; } STDMETHOD(GetCellDescent)(unsigned short *pusDescent) { if ( !m_pFont ) { *pusDescent = 0; return AVS_OFFICEFONTMANAGER_ERROR_FONT_WASNT_LOAD; } *pusDescent = fabs( m_pFont->GetDescender() ); return S_OK; } STDMETHOD(GetEmHeight)(unsigned short *pusEmHeight) { if ( !m_pFont ) { *pusEmHeight = 0; return AVS_OFFICEFONTMANAGER_ERROR_FONT_WASNT_LOAD; } *pusEmHeight = m_pFont->GetUnitsPerEm(); return S_OK; } STDMETHOD(GetFamilyName)(BSTR *pbsFamilyName) { if ( !m_pFont ) { CString sFamilyName( _T("") ); *pbsFamilyName = sFamilyName.AllocSysString(); return AVS_OFFICEFONTMANAGER_ERROR_FONT_WASNT_LOAD; } CString sFamilyName( m_pFont->GetFamilyName() ); *pbsFamilyName = sFamilyName.AllocSysString(); return S_OK; } STDMETHOD(GetLineSpacing)(unsigned short *pusLineSpacing) { if ( !m_pFont ) { *pusLineSpacing = 0; return AVS_OFFICEFONTMANAGER_ERROR_FONT_WASNT_LOAD; } *pusLineSpacing = m_pFont->GetLineSpacing(); return S_OK; } STDMETHOD(IsStyleAvailable)(long lStyle, BOOL *pbAvailable) { if ( !m_pFontEngine || !m_pFont ) { *pbAvailable = FALSE; return S_OK; } *pbAvailable = m_pFontEngine->IsStyleAvailable( CStringW( m_pFont->GetFamilyName() ).GetBuffer(), lStyle ); return S_OK; } STDMETHOD(GetHeight)(float fDPI, float *pfHeight) { if ( !m_pFont ) { *pfHeight = 0.0f; return AVS_OFFICEFONTMANAGER_ERROR_FONT_WASNT_LOAD; } unsigned short usEmHeight = 0; unsigned short usLineSpacing = 0; HRESULT hRes = S_OK; if ( FAILED( hRes = GetEmHeight( &usEmHeight ) ) || usEmHeight <= 0.0001 ) return hRes; if ( FAILED( hRes = GetLineSpacing( &usLineSpacing ) ) ) return hRes; float fKoef = 1.0f; switch( m_lUnit ) { case FontConstants::UnitPoint: fKoef = fDPI / 72; break; case FontConstants::UnitInch: fKoef = fDPI; break; case FontConstants::UnitDocument: fKoef = fDPI / 300; break; case FontConstants::UnitMillimeter: fKoef = fDPI / 25.4; break; } *pfHeight = usLineSpacing * ( m_fEmSize / usEmHeight ) * fKoef; return S_OK; } //----- Чтение глобальных параметров шрифта --------------------------------------------------------- STDMETHOD(GetFacesCount)(long *plFacesCount) { if ( !m_pFont ) { *plFacesCount = 0; return S_FALSE; } *plFacesCount = m_pFont->GetFacesCount(); return S_OK; } STDMETHOD(GetFaceIndex)(long *plFaceIndex) { if ( !m_pFont ) { *plFaceIndex = 0; return S_FALSE; } *plFaceIndex = m_pFont->GetFaceIndex(); return S_OK; } STDMETHOD(GetGlyphsCount)(long *plGlyphsCount) { if ( !m_pFont ) { *plGlyphsCount = 0; return S_FALSE; } *plGlyphsCount = m_pFont->GetGlyphsCount(); return S_OK; } STDMETHOD(GetStyleName)(BSTR *pbsStyleName) { if ( !m_pFont ) { CString sStyleName( _T("") ); *pbsStyleName = sStyleName.AllocSysString(); return S_FALSE; } CString sStyleName( m_pFont->GetStyleName() ); *pbsStyleName = sStyleName.AllocSysString(); return S_OK; } STDMETHOD(IsCharAvailable)(long lUnicode, BOOL *pbAvailable) { if ( !m_pFont ) return S_FALSE; *pbAvailable = m_pFont->IsCharAvailable( lUnicode ); return S_OK; } STDMETHOD(GetUnderlinePosition)(short *pshUnderPos) { if ( !m_pFont ) { *pshUnderPos = 0; return AVS_OFFICEFONTMANAGER_ERROR_FONT_WASNT_LOAD; } *pshUnderPos = m_pFont->GetUnderlinePosition(); return S_OK; } STDMETHOD(GetUnderlineThickness)(short *pshUnderThick) { if ( !m_pFont ) { *pshUnderThick = 0; return AVS_OFFICEFONTMANAGER_ERROR_FONT_WASNT_LOAD; } *pshUnderThick = m_pFont->GetUnderlineThickness(); return S_OK; } STDMETHOD(GetMaxAdvanceWidth)(short *pshMaxAdvWidth) { if ( !m_pFont ) { *pshMaxAdvWidth = 0; return AVS_OFFICEFONTMANAGER_ERROR_FONT_WASNT_LOAD; } *pshMaxAdvWidth = m_pFont->GetMaxAdvanceWidth(); return S_OK; } STDMETHOD(GetMaxAdvanceHeight)(short *pshMaxAdvHeight) { if ( !m_pFont ) { *pshMaxAdvHeight = 0; return AVS_OFFICEFONTMANAGER_ERROR_FONT_WASNT_LOAD; } *pshMaxAdvHeight = m_pFont->GetMaxAdvanceHeight(); return S_OK; } STDMETHOD(GetBBox)(long *plMinX, long *plMinY, long *plMaxX, long *plMaxY) { if ( !m_pFont ) { *plMinX = 0; *plMinY = 0; *plMaxX = 0; *plMaxY = 0; return AVS_OFFICEFONTMANAGER_ERROR_FONT_WASNT_LOAD; } m_pFont->GetBBox( plMinX, plMinY, plMaxX, plMaxY ); return S_OK; } STDMETHOD(IsUnicodeRangeAvailable)(unsigned long ulBit, unsigned int unLongIndex, VARIANT_BOOL *pvbSuccess) { *pvbSuccess = VARIANT_FALSE; if ( !m_pFont ) return AVS_OFFICEFONTMANAGER_ERROR_FONT_WASNT_LOAD; if ( m_pFont->IsUnicodeRangeAvailable( ulBit, unLongIndex ) > 0 ) *pvbSuccess = VARIANT_TRUE; return S_OK; } //----- Работа с глифами ---------------------------------------------------------------------------- STDMETHOD(GetGlyphPath)(long lUnicode, BSTR *pbsXmlPath) { if ( !m_pFont ) { CString sXml( _T("") ); *pbsXmlPath = sXml.AllocSysString(); return S_FALSE; } CPath *pPath = m_pFont->GetGlyphPath( lUnicode ); if ( !pPath ) return S_FALSE; *pbsXmlPath = pPath->ToXmlString().AllocSysString(); return S_OK; } STDMETHOD(GetStringPath)(BSTR bsString, BSTR *pbsXmlPath) { if ( !m_pFont ) { CString sXml( _T("") ); *pbsXmlPath = sXml.AllocSysString(); return S_FALSE; } CStringW wsString( bsString ); CPath *pPath = m_pFont->GetStringPath( wsString.GetBuffer(), wsString.GetLength() ); if ( !pPath ) return S_FALSE; *pbsXmlPath = pPath->ToXmlString().AllocSysString(); return S_OK; } STDMETHOD(GetGlyphBitmap)(long lUnicode, IUnknown **ppImage) { if ( !m_pFont ) return S_FALSE; TGlyphBitmap oBitmap; m_pFont->GetGlyph( lUnicode, 0, 0, &oBitmap ); // Подготавливаем pInterface IUnknown **pInterface = (IUnknown**)ppImage; if ( !pInterface ) return S_FALSE; // create result interface *pInterface = NULL; HRESULT hRes = CoCreateInstance( MediaCore::CLSID_CAVSUncompressedVideoFrame, NULL, CLSCTX_ALL, MediaCore::IID_IAVSUncompressedVideoFrame, (void**)pInterface ); if ( hRes != S_OK || NULL == *pInterface ) return S_FALSE; MediaCore::IAVSUncompressedVideoFrame* pMediaData = (MediaCore::IAVSUncompressedVideoFrame*)*pInterface; int nWidth = oBitmap.nWidth; int nHeight = oBitmap.nHeight; int nBufferSize = 4 * nWidth * nHeight; if ( nBufferSize < 1 ) return S_FALSE; pMediaData->put_ColorSpace( ( 1 << 6) || ( 1 << 31 ) ); // CPS_BGRA | CPS_FLIP pMediaData->put_Width( nWidth ); pMediaData->put_Height( nHeight ); pMediaData->put_AspectRatioX( nWidth ); pMediaData->put_AspectRatioY( nHeight ); pMediaData->put_Interlaced( VARIANT_FALSE ); pMediaData->put_Stride( 0, 4 * nWidth ); pMediaData->AllocateBuffer( nBufferSize ); unsigned char *pBufferPtr = NULL; long nCreatedBufferSize = 0; pMediaData->get_Buffer( &pBufferPtr ); pMediaData->get_BufferSize( &nCreatedBufferSize ); pMediaData->put_Plane( 0, pBufferPtr ); if ( !pBufferPtr || nCreatedBufferSize != nBufferSize ) return S_FALSE; *pInterface = pMediaData; // Пишем данные в pBufferPtr for ( int nY = 0; nY < nHeight; nY++ ) { for ( int nX = 0; nX < nWidth; nX++ ) { unsigned char nG = 255 - oBitmap.pData[nWidth * nY + nX ]; pBufferPtr[0] = nG; pBufferPtr[1] = nG; pBufferPtr[2] = nG; pBufferPtr[3] = 255; pBufferPtr += 4; } } return S_OK; } STDMETHOD(GetStringBitmap)(BSTR bsString, IUnknown **ppImage) { if ( !m_pFont ) return S_FALSE; CStringW wsString( bsString ); TGlyphBitmap *pBitmaps = new TGlyphBitmap[ wsString.GetLength() ]; if ( !pBitmaps ) return S_FALSE; int nHeight = 0; int nWidth = 0; for ( int nIndex = 0; nIndex < wsString.GetLength(); nIndex++ ) { long lUnicode = wsString.GetAt( nIndex ); m_pFont->GetGlyph( lUnicode, 0, 0, &(pBitmaps[nIndex]) ); if ( nHeight < pBitmaps[nIndex].nHeight ) nHeight = pBitmaps[nIndex].nHeight; nWidth += pBitmaps[nIndex].nWidth; } // Подготавливаем pInterface IUnknown **pInterface = (IUnknown**)ppImage; if ( !pInterface ) return S_FALSE; // create result interface *pInterface = NULL; HRESULT hRes = CoCreateInstance( MediaCore::CLSID_CAVSUncompressedVideoFrame, NULL, CLSCTX_ALL, MediaCore::IID_IAVSUncompressedVideoFrame, (void**)pInterface ); if ( hRes != S_OK || NULL == *pInterface ) return S_FALSE; MediaCore::IAVSUncompressedVideoFrame* pMediaData = (MediaCore::IAVSUncompressedVideoFrame*)*pInterface; int nBufferSize = 4 * nWidth * nHeight; if ( nBufferSize < 1 ) return S_FALSE; pMediaData->put_ColorSpace( ( 1 << 6) ); // CPS_BGRA pMediaData->put_Width( nWidth ); pMediaData->put_Height( nHeight ); pMediaData->put_AspectRatioX( nWidth ); pMediaData->put_AspectRatioY( nHeight ); pMediaData->put_Interlaced( VARIANT_FALSE ); pMediaData->put_Stride( 0, 4 * nWidth ); pMediaData->AllocateBuffer( nBufferSize ); unsigned char *pBufferPtr = NULL; long nCreatedBufferSize = 0; pMediaData->get_Buffer( &pBufferPtr ); pMediaData->get_BufferSize( &nCreatedBufferSize ); pMediaData->put_Plane( 0, pBufferPtr ); if ( !pBufferPtr || nCreatedBufferSize != nBufferSize ) return S_FALSE; *pInterface = pMediaData; // Пишем данные в pBufferPtr int nShiftX = 0; for ( int nGlyphIndex = 0; nGlyphIndex < wsString.GetLength(); nGlyphIndex++ ) { for ( int nY = 0; nY < nHeight; nY++ ) { if ( nHeight - nY < pBitmaps[nGlyphIndex].nHeight ) { for ( int nX = 0; nX < pBitmaps[nGlyphIndex].nWidth; nX++ ) { int nCurY = nY - ( nHeight - pBitmaps[nGlyphIndex].nHeight ); unsigned char nG = 255 - pBitmaps[nGlyphIndex].pData[pBitmaps[nGlyphIndex].nWidth * nCurY + nX ]; int nIndex = (nX + nShiftX + nY * nWidth) * 4; pBufferPtr[nIndex + 0] = nG; pBufferPtr[nIndex + 1] = nG; pBufferPtr[nIndex + 2] = nG; pBufferPtr[nIndex + 3] = 255; } } else { for ( int nX = 0; nX < pBitmaps[nGlyphIndex].nWidth; nX++ ) { int nIndex = (nX + nShiftX + nY * nWidth) * 4; pBufferPtr[nIndex + 0] = 255; pBufferPtr[nIndex + 1] = 255; pBufferPtr[nIndex + 2] = 255; pBufferPtr[nIndex + 3] = 255; } } } nShiftX += pBitmaps[nGlyphIndex].nWidth; } delete []pBitmaps; return S_OK; } STDMETHOD(LoadString)(BSTR bsString) { if ( !m_pFont ) return FALSE; CStringW wsBuffer = CStringW( bsString ); m_nGlyphsCount = wsBuffer.GetLength(); if ( m_pGlyphsBuffer ) delete []m_pGlyphsBuffer; m_pGlyphsBuffer = new TGlyph[m_nGlyphsCount]; m_nGlyphIndex = -1; for ( int nIndex = 0; nIndex < m_nGlyphsCount; nIndex++ ) { m_pGlyphsBuffer[nIndex].lUnicode = wsBuffer.GetAt( nIndex ); } m_pFont->GetString( m_pGlyphsBuffer, m_nGlyphsCount ); return S_OK; } STDMETHOD(GetNextChar)(IUnknown **ppImage, float *pfX, float *pfY, VARIANT_BOOL *pvbSuccess) { *pvbSuccess = VARIANT_FALSE; m_nGlyphIndex++; if ( m_nGlyphIndex >= m_nGlyphsCount ) { *ppImage = NULL; *pfX = -0xFFFF; *pfY = -0xFFFF; return S_OK; } if ( !m_pFont || !m_pGlyphsBuffer ) return S_FALSE; if ( glyphstateNormal == m_pGlyphsBuffer[m_nGlyphIndex].eState || ( glyphstateDeafault == m_pGlyphsBuffer[m_nGlyphIndex].eState && NULL != m_pFont->GetDefaultFont() ) ) { long lUnicode = m_pGlyphsBuffer[m_nGlyphIndex].lUnicode; TGlyphBitmap oBitmap; CFont *pCurFont = NULL; if ( glyphstateNormal == m_pGlyphsBuffer[m_nGlyphIndex].eState ) pCurFont = m_pFont; else pCurFont = m_pFont->GetDefaultFont(); pCurFont->GetGlyph( lUnicode, 0, 0, &oBitmap ); if ( oBitmap.nWidth > 0 && oBitmap.nHeight > 0 ) { // Подготавливаем pInterface IUnknown **pInterface = (IUnknown**)ppImage; if ( !pInterface ) return S_FALSE; // create result interface *pInterface = NULL; HRESULT hRes = CoCreateInstance( MediaCore::CLSID_CAVSUncompressedVideoFrame, NULL, CLSCTX_ALL, MediaCore::IID_IAVSUncompressedVideoFrame, (void**)pInterface ); if ( hRes != S_OK || NULL == *pInterface ) return S_FALSE; MediaCore::IAVSUncompressedVideoFrame* pMediaData = (MediaCore::IAVSUncompressedVideoFrame*)*pInterface; int nWidth = oBitmap.nWidth; int nHeight = oBitmap.nHeight; if ( pCurFont->GetBold() ) nWidth++; int nBufferSize = 4 * nWidth * nHeight; if ( nBufferSize < 1 ) return S_FALSE; pMediaData->put_ColorSpace( 1 << 6 ); // CPS_BGRA pMediaData->put_Width( nWidth ); pMediaData->put_Height( nHeight ); pMediaData->put_AspectRatioX( nWidth ); pMediaData->put_AspectRatioY( nHeight ); pMediaData->put_Interlaced( VARIANT_FALSE ); pMediaData->put_Stride( 0, 4 * nWidth ); pMediaData->AllocateBuffer( nBufferSize ); unsigned char *pBufferPtr = NULL; long nCreatedBufferSize = 0; pMediaData->get_Buffer( &pBufferPtr ); pMediaData->get_BufferSize( &nCreatedBufferSize ); pMediaData->put_Plane( 0, pBufferPtr ); if ( !pBufferPtr || nCreatedBufferSize != nBufferSize ) return S_FALSE; *pInterface = pMediaData; // Пишем данные в pBufferPtr if ( !pCurFont->GetBold() ) { for ( int nY = 0; nY < nHeight; nY++ ) { for ( int nX = 0; nX < nWidth; nX++ ) { unsigned char nG = 255 - oBitmap.pData[nWidth * nY + nX ]; //pBufferPtr[0] = nG; //pBufferPtr[1] = nG; //pBufferPtr[2] = nG; //pBufferPtr[3] = 255; pBufferPtr[0] = 0;//nG; pBufferPtr[1] = 0;//nG; pBufferPtr[2] = 0;//nG; pBufferPtr[3] = 255 - nG; pBufferPtr += 4; } } } else { // Здесь (nWidth = oBitmap.nWidth + 1) for ( int nY = 0; nY < nHeight; nY++ ) { for ( int nX = nWidth - 1; nX >= 0; nX-- ) { int nDstIndex = nY * nWidth * 4 + nX * 4; int nSrcIndex = nY * oBitmap.nWidth + nX; if ( 0 != nX ) { int nFirstByte, nSecondByte; if ( nWidth - 1 == nX ) nFirstByte = 255; else nFirstByte = 255 - oBitmap.pData[nSrcIndex]; nSecondByte = 255 - oBitmap.pData[nSrcIndex - 1]; pBufferPtr[nDstIndex + 0] = 0;//nG; pBufferPtr[nDstIndex + 1] = 0;//nG; pBufferPtr[nDstIndex + 2] = 0;//nG; pBufferPtr[nDstIndex + 3] = min( 255, 510 - (nFirstByte + nSecondByte) ); } else { pBufferPtr[nDstIndex + 0] = 0; pBufferPtr[nDstIndex + 1] = 0; pBufferPtr[nDstIndex + 2] = 0; pBufferPtr[nDstIndex + 3] = oBitmap.pData[nSrcIndex]; } } } } } else { *ppImage = NULL; } *pfX = m_pGlyphsBuffer[m_nGlyphIndex].fX + oBitmap.nX; *pfY = m_pGlyphsBuffer[m_nGlyphIndex].fY + oBitmap.nY - oBitmap.nHeight; // Отдаем координату левого верхнего угла } else { // Символ не найден, ничего не рисуем *ppImage = NULL; *pfX = m_pGlyphsBuffer[m_nGlyphIndex].fX; *pfY = m_pGlyphsBuffer[m_nGlyphIndex].fY; } *pvbSuccess = VARIANT_TRUE; return S_OK; } STDMETHOD(GetCharBBox)(float *pfLeft, float *pfTop, float *pfRight, float *pfBottom) { if ( !m_pGlyphsBuffer || m_nGlyphsCount <= 0 || m_nGlyphIndex < 0 || m_nGlyphIndex >= m_nGlyphsCount ) { *pfBottom = 0; *pfRight = 0; *pfLeft = 0; *pfTop = 0; return S_FALSE; } *pfBottom = m_pGlyphsBuffer[m_nGlyphIndex].fBottom; *pfRight = m_pGlyphsBuffer[m_nGlyphIndex].fRight + m_pGlyphsBuffer[m_nGlyphIndex].fX; *pfLeft = m_pGlyphsBuffer[m_nGlyphIndex].fLeft + m_pGlyphsBuffer[m_nGlyphIndex].fX; *pfTop = m_pGlyphsBuffer[m_nGlyphIndex].fTop; return S_OK; } STDMETHOD(GetNextChar2)(BSTR *pbsTempPath, float *pfX, float *pfY, VARIANT_BOOL *pvbSuccess) { *pvbSuccess = VARIANT_FALSE; if ( m_nGlyphIndex >= m_nGlyphsCount ) { CStringW wsTemp = _T(""); *pbsTempPath = wsTemp.AllocSysString(); *pfX = -0xFFFF; *pfY = -0xFFFF; return S_OK; } if ( !m_pFont || !m_pGlyphsBuffer ) return S_FALSE; long lUnicode = m_pGlyphsBuffer[m_nGlyphIndex].lUnicode; int nX = (int)floor( (double)m_pGlyphsBuffer[m_nGlyphIndex].fX ); int nFracX = (int)floor( (double)(m_pGlyphsBuffer[m_nGlyphIndex].fX - nX) * FONT_FRACTION ); int nY = (int)floor( (double)m_pGlyphsBuffer[m_nGlyphIndex].fY ); int nFracY = (int)floor( (double)(m_pGlyphsBuffer[m_nGlyphIndex].fY - nY) * FONT_FRACTION ); TGlyphBitmap oBitmap; m_pFont->GetGlyph( lUnicode, nFracX, nFracY, &oBitmap ); int nWidth = oBitmap.nWidth; int nHeight = oBitmap.nHeight; CStringW wsFileName = _T( "C:\\Temp.bmp" ); *pbsTempPath = wsFileName.AllocSysString(); FILE *pFile = NULL; if ( !( pFile = ::_wfopen( wsFileName, _T("wb") ) ) ) return S_FALSE; int nSize = 0, nStride; BYTE *pBuffer = NULL, *pBufPointer; BITMAPFILEHEADER oFileHeader; BITMAPINFOHEADER oInfoHeader; oFileHeader.bfType = 'M' * 256 + 'B'; oFileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + nHeight * nWidth * 4; oFileHeader.bfReserved1 = 0; oFileHeader.bfReserved2 = 0; oFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); oInfoHeader.biSize = sizeof(BITMAPINFOHEADER); oInfoHeader.biWidth = nWidth; oInfoHeader.biHeight = nHeight; oInfoHeader.biPlanes = 1; oInfoHeader.biBitCount = 32; oInfoHeader.biCompression = BI_RGB; oInfoHeader.biSizeImage = nHeight * nWidth * 4; oInfoHeader.biXPelsPerMeter = 0; oInfoHeader.biYPelsPerMeter = 0; oInfoHeader.biClrUsed = 0; oInfoHeader.biClrImportant = 0; ::fwrite( &oFileHeader, 1, sizeof(BITMAPFILEHEADER), pFile ); ::fwrite( &oInfoHeader, 1, sizeof(BITMAPINFOHEADER), pFile ); nSize = nHeight * nWidth * 4; pBuffer = new BYTE[nSize]; if ( !pBuffer ) { return S_FALSE; } pBufPointer = pBuffer; for ( int nY = 0; nY < nHeight; nY++ ) { for ( int nX = 0; nX < nWidth; nX++, pBufPointer += 4 ) { unsigned char nG = oBitmap.pData[nWidth * nY + nX ]; float fAlpha = nG / 255.f; pBufPointer[0] = ( 1 - fAlpha ) * 216; pBufPointer[1] = ( 1 - fAlpha ) * 236; pBufPointer[2] = ( 1 - fAlpha ) * 236; pBufPointer[3] = 255 * fAlpha; } } pBufPointer = pBuffer; nStride = nWidth * 4; pBufPointer += (nHeight - 1) * nStride; nStride = -nStride; for( int nRow = nHeight; nRow > 0 ; --nRow, pBufPointer += nStride ) { ::fwrite( pBufPointer, 1, abs( nStride ), pFile ); } delete []pBuffer; fclose( pFile ); *pfX = m_pGlyphsBuffer[m_nGlyphIndex].fX - oBitmap.nX; *pfY = m_pGlyphsBuffer[m_nGlyphIndex].fY - oBitmap.nY; m_nGlyphIndex++; *pvbSuccess = VARIANT_TRUE; return S_OK; } STDMETHOD(MeasureString)(float *pfLeft, float *pfTop, float *pfRight, float *pfBottom) { if ( !m_pGlyphsBuffer || m_nGlyphsCount <= 0 ) { *pfBottom = 0; *pfRight = 0; *pfLeft = 0; *pfTop = 0; return S_FALSE; } // Учитываем, что мы используем перевернутю систему (т.е. матрица преобразования был [1 0 0 -1 0 0]) // И то что сама система координат тоже перевернута float fTop = -0xFFFF, fBottom = 0xFFFF, fLeft = 0xFFFF, fRight = -0xFFFF; for ( int nIndex = 0; nIndex < m_nGlyphsCount; nIndex++ ) { if ( fBottom > m_pGlyphsBuffer[nIndex].fBottom ) fBottom = m_pGlyphsBuffer[nIndex].fBottom; if ( fTop < m_pGlyphsBuffer[nIndex].fTop ) fTop = m_pGlyphsBuffer[nIndex].fTop; } fLeft = m_pGlyphsBuffer[0].fLeft; fRight = m_pGlyphsBuffer[m_nGlyphsCount - 1].fRight + m_pGlyphsBuffer[m_nGlyphsCount - 1].fX; *pfBottom = fBottom; *pfRight = fRight; *pfLeft = fLeft; *pfTop = fTop; return S_OK; } STDMETHOD(ApplyTransform)(float fA, float fB, float fC, float fD, float fE, float fF) { if ( !m_pFont ) { return S_FALSE; } m_pFont->ResetTransform(); m_pFont->ApplyTransform( fA, fB, fC, fD, fE, fF ); return S_OK; } //----- Работа со шрифтами Windows ------------------------------------------------------------------ STDMETHOD(GetWinFontsCount)(long *plCount) { if ( !m_pFontEngine ) { *plCount = 0; return S_OK; } *plCount = m_pFontEngine->GetInstalledFontsCount(); return S_OK; } STDMETHOD(GetWinFont)(long nIndex, BSTR *pbsFontName, BSTR *pbsFontStyle, BSTR *pbsFontPath, long *plIndex, BOOL *pbBold, BOOL *pbItalic) { if ( !m_pFontEngine ) { *pbsFontName = CStringW( _T("") ).AllocSysString(); *pbsFontStyle = CStringW( _T("") ).AllocSysString(); *pbsFontPath = CStringW( _T("") ).AllocSysString(); *plIndex = 0; return S_OK; } CWinFontInfo *pFontInfo = m_pFontEngine->GetInstalledFont( nIndex ); *pbsFontName = CStringW( pFontInfo->m_wsFontName ).AllocSysString(); *pbsFontStyle = CStringW( pFontInfo->m_wsStyle ).AllocSysString(); *pbsFontPath = CStringW( pFontInfo->m_wsFontPath ).AllocSysString(); *plIndex = pFontInfo->m_lIndex; *pbBold = pFontInfo->m_bBold; *pbItalic = pFontInfo->m_bItalic; return S_OK; } };