fontembed.cpp

来自「Windows 图形编程 书籍」· C++ 代码 · 共 502 行

CPP
502
字号
//-----------------------------------------------------------------------------------//
//              Windows Graphics Programming: Win32 GDI and DirectDraw               //
//                             ISBN  0-13-086985-6                                   //
//                                                                                   //
//  Written            by  Yuan, Feng                             www.fengyuan.com   //
//  Copyright (c) 2000 by  Hewlett-Packard Company                www.hp.com         //
//  Published          by  Prentice Hall PTR, Prentice-Hall, Inc. www.phptr.com      //
//                                                                                   //
//  FileName   : fontembed.cpp					                                     //
//  Description: Font embedding demo program, Chapter 14                             //
//  Version    : 1.00.000, May 31, 2000                                              //
//-----------------------------------------------------------------------------------//

#define STRICT
#define _WIN32_WINNT 0x0500

#include <windows.h>
#include <tchar.h>
#include <string.h>
#include <assert.h>

#include "resource.h"
#include "..\..\include\Dialog.h"


#define FR_HIDDEN   0x01
#define FR_MEM		0x02


BOOL RemoveFont(const TCHAR * fontname, int option, HANDLE hFont)
{
	if ( option & FR_MEM )
	{
		return RemoveFontMemResourceEx(hFont);
	}
	
	TCHAR ttffile[MAX_PATH];
	TCHAR fotfile[MAX_PATH];

	GetCurrentDirectory(MAX_PATH-1, ttffile);
	_tcscpy(fotfile, ttffile);

	wsprintf(ttffile + _tcslen(ttffile), "\\%s.ttf", fontname);
	wsprintf(fotfile + _tcslen(fotfile), "\\%s.fot", fontname);

	BOOL rslt;

	switch ( option )
	{
		case 0:
		case FR_HIDDEN:
			rslt = RemoveFontResource(fotfile);
			break;

		case FR_PRIVATE:
		case FR_NOT_ENUM:
		case FR_PRIVATE | FR_NOT_ENUM:
			rslt = RemoveFontResourceEx(fotfile, option, NULL);
			break;

		default:
			assert(false);
			rslt = FALSE;
	}

	if ( ! DeleteFile(fotfile) )
		rslt = FALSE;

	if ( ! DeleteFile(ttffile) )
		rslt = FALSE;

	return rslt;
}


HANDLE InstallFont(void * fontdata, unsigned fontsize, const TCHAR * fontname, int option)
{
	if ( option & FR_MEM )
	{
		DWORD num;

		return AddFontMemResourceEx(fontdata, fontsize, NULL, & num);
	}

	TCHAR ttffile[MAX_PATH];
	TCHAR fotfile[MAX_PATH];

	GetCurrentDirectory(MAX_PATH-1, ttffile);
	_tcscpy(fotfile, ttffile);

	wsprintf(ttffile + _tcslen(ttffile), "\\%s.ttf", fontname);
	wsprintf(fotfile + _tcslen(fotfile), "\\%s.fot", fontname);

	HANDLE hFile = CreateFile(ttffile, GENERIC_WRITE, 0, NULL,
						CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, 0);

	if ( hFile==INVALID_HANDLE_VALUE )
		return NULL;

	DWORD dwWritten;
	WriteFile(hFile, fontdata, fontsize, & dwWritten, NULL);
	FlushFileBuffers(hFile);
	CloseHandle(hFile);

	if ( ! CreateScalableFontResource(option & FR_HIDDEN, fotfile, ttffile, NULL) )
		return NULL;

	switch ( option )
	{
		case 0:
		case FR_HIDDEN:
			return (HANDLE) AddFontResource(fotfile);

		case FR_PRIVATE:
		case FR_NOT_ENUM:
		case FR_PRIVATE | FR_NOT_ENUM:
			return (HANDLE) AddFontResourceEx(fotfile, option, NULL);

		default:
			assert(false);
			return NULL;
	}
}

const char key[4] = { 0x31, 0x41, 0x59, 0x26 }; // encryption key, pi

typedef struct
{
	char	Tag[4];			// font
	DWORD	size;			// size of attached font data
	char	FileName[56];
}	FontEmbed;


// Load/unload a document, install/uninstall the fonts embedded inside

int ProcessDocument(const TCHAR * docname, int option, bool load, HANDLE hfont[])
{
	HANDLE handle = CreateFile(docname, GENERIC_READ, FILE_SHARE_READ, 
		NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	
	if ( handle == INVALID_HANDLE_VALUE )
		return 0;

	int       processed  = 0;
	DWORD	  dwRead;
	FontEmbed header;

	while ( ReadFile(handle, & header, sizeof(header), & dwRead, NULL) )
	{
		if ( dwRead!=sizeof(header) )
			break;

		if ( strncmp(header.Tag, "FONT", 4) )
			break;

		unsigned size = header.size - sizeof(header);

		BYTE * pData = new BYTE[size];

		if ( pData==NULL )
			break;

		ReadFile(handle, pData, size, & dwRead, NULL);

		// simple decryption
		for (unsigned i=0; i<size; i++)
			pData[i] ^= key[i % 4];

		if ( load )
			hfont[processed] = InstallFont(pData, size, header.FileName, option);
		else
			if ( ! RemoveFont(header.FileName, option, hfont[processed]) )
			{
				delete [] pData;
				break;
			}
		
		delete [] pData;

		if ( hfont[processed] )
			processed ++;
		else
			break;
	}

	CloseHandle(handle);

	return processed;
}

class KFileDialog
{
	void SetupOFN(OPENFILENAME & ofn, TCHAR Filter[], HWND hWnd, const TCHAR * pExtension, const TCHAR * pClass);

public:
	TCHAR	m_FileName[MAX_PATH];
	TCHAR	m_TitleName[MAX_PATH];
	
	// "bmp" "Bitmap Files"
	BOOL GetOpenFileName(HWND hWnd, const TCHAR * pExtension, const TCHAR * pClass);
	BOOL GetSaveFileName(HWND hWnd, const TCHAR * pExtension, const TCHAR * pClass);
};


void KFileDialog::SetupOFN(OPENFILENAME & ofn, TCHAR Filter[], HWND hWnd, const TCHAR * pExtension, const TCHAR * pClass)
{
	memset(& ofn, 0, sizeof(ofn));

	wsprintf(Filter, "%s (*.%s)%c*.%s%c", pClass, pExtension, 0, pExtension, 0);

	ofn.lStructSize		= sizeof(OPENFILENAME);
	ofn.hwndOwner		= hWnd;
	ofn.lpstrFilter		= Filter; // _T("Bitmaps (*.bmp)\0*.bmp\0\0");
	ofn.lpstrFile		= m_FileName;
	ofn.nMaxFile		= MAX_PATH;
	ofn.lpstrFileTitle	= m_TitleName;
	ofn.nMaxFileTitle	= MAX_PATH;
	ofn.lpstrDefExt		= pExtension; // _T("bmp");
	ofn.nFilterIndex	= 1;

	m_FileName[0] = 0;
}


BOOL KFileDialog::GetOpenFileName(HWND hWnd, const TCHAR * pExtension, const TCHAR * pClass)
{
	OPENFILENAME ofn;
	TCHAR Filter[MAX_PATH];

	SetupOFN(ofn, Filter, hWnd, pExtension, pClass);

	ofn.Flags	= OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
			
	return ::GetOpenFileName(&ofn);
}


BOOL KFileDialog::GetSaveFileName(HWND hWnd, const TCHAR * pExtension, const TCHAR * pClass)
{
	OPENFILENAME ofn;
	TCHAR Filter[MAX_PATH];

	SetupOFN(ofn, Filter, hWnd, pExtension, pClass);

	ofn.Flags  = OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT;
	
	return ::GetSaveFileName(&ofn);
}

// Generate a EMF file with fonts embedded as GDI commands


BOOL GenerateDoc(const TCHAR * docname)
{
	HANDLE out = CreateFile(docname, GENERIC_WRITE, FILE_SHARE_READ, 
		NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

	if ( out==INVALID_HANDLE_VALUE )
		return FALSE;

	KFileDialog fi;

	while ( fi.GetOpenFileName(NULL, "ttf", "TrueType fonts") )
	{
		HANDLE handle = CreateFile(fi.m_TitleName, GENERIC_READ, FILE_SHARE_READ, 
			NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	
		if ( handle == INVALID_HANDLE_VALUE )
			break;

		DWORD size = GetFileSize(handle, NULL);

		FontEmbed font;
		
		memset(&font, 0, sizeof(font));
		font.Tag[0] = 'F';
		font.Tag[1] = 'O';
		font.Tag[2] = 'N';
		font.Tag[3] = 'T';
		font.size   = sizeof(FontEmbed) + size;

		int len = strlen(fi.m_TitleName);

		for (int i=0; i<len; i++)
			if ( fi.m_TitleName[i]=='.')
				break;
			else
				font.FileName[i] = fi.m_TitleName[i];
		
		DWORD dwWritten, dwRead;

		// write header
		WriteFile(out, & font, sizeof(font), & dwWritten, NULL);

		char buffer[4096];

		// read, write the whole font file
		while ( ReadFile(handle, buffer, sizeof(buffer), & dwRead, NULL) )
		{
			if ( dwRead==0) 
				break;

			// simple encryption
			for (unsigned i=0; i<dwRead; i++)
				buffer[i] ^= key[i % 4];

			WriteFile(out, buffer, dwRead, & dwWritten, NULL);
		}

		CloseHandle(handle);
	}

	CloseHandle(out);

	return TRUE;
}

const TCHAR * FontList[] =
{
	"Euro Sign",
	"Ozzie Black",
	"Ozzie Black Italic",
	NULL
};


class KMyDialog : public KDialog
{
	HINSTANCE m_hInst;
	int		  m_nFontChange;
	HFONT	  m_font[10];
	int		  m_option;

	void GetOption(void)
	{			
		m_option = 0;

		if ( SendDlgItemMessage(m_hWnd, IDC_HIDDEN, BM_GETCHECK, 0, 0)==BST_CHECKED )
			m_option = FR_HIDDEN;

		if ( SendDlgItemMessage(m_hWnd, IDC_PRIVATE, BM_GETCHECK, 0, 0)==BST_CHECKED )
			m_option = FR_PRIVATE;

		if ( SendDlgItemMessage(m_hWnd, IDC_NOENUM, BM_GETCHECK, 0, 0)==BST_CHECKED )
			m_option = FR_NOT_ENUM;

		if ( SendDlgItemMessage(m_hWnd, IDC_MEM, BM_GETCHECK, 0, 0)==BST_CHECKED )
			m_option = FR_MEM;
	}

	void Update(void)
	{
		for (int i=0; FontList[i]; i++)
		{
			if ( m_font[i] )
				DeleteObject(m_font[i]);

			LOGFONT logfont = { - 20,
							 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, 
							 ANSI_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, 
							 PROOF_QUALITY, VARIABLE_PITCH };
			
			_tcscpy(logfont.lfFaceName, FontList[i]);

			if (i==2) 
				logfont.lfItalic = TRUE;

			if (i==0)
				logfont.lfCharSet = SYMBOL_CHARSET;

			m_font[i] = CreateFontIndirect(& logfont);

			HDC      hDC = GetDC(NULL);
			HGDIOBJ hOld = SelectObject(hDC, m_font[i]);

			OUTLINETEXTMETRIC outm[3];
			GetOutlineTextMetrics(hDC, sizeof(outm), outm);
			SelectObject(hDC, hOld);
			DeleteObject(hDC);

			TCHAR name[64];
			
			if ( i==0 )
				_tcscpy(name, "e");
			else
			{
				_tcscpy(name, (char *) outm + (int) outm[0].otmpFamilyName);
				_tcscat(name, " ");
				_tcscat(name, (char *) outm + (int) outm[0].otmpStyleName);
			}

			SetDlgItemText(m_hWnd, IDC_SAMPLE1 + i, name);

			SendDlgItemMessage(m_hWnd, IDC_SAMPLE1 + i, WM_SETFONT, (WPARAM) m_font[i], TRUE);
    	}
	}

	virtual BOOL OnInitDialog(HWND hWnd, WPARAM wParam, LPARAM lParam)
	{
		m_hWnd = hWnd;

		Update();

		return TRUE;
	}

	HANDLE hFont[32];

	virtual BOOL OnCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
	{
		switch ( LOWORD(wParam) )
		{
			case IDOK:
				EndDialog(hWnd, IDOK);
				return TRUE;

			case IDC_GENERATE:
				GenerateDoc("testdoc.tmp");
				return TRUE;

			case IDC_LOAD:
			{
				GetOption();
				int succeeded = ProcessDocument("testdoc.tmp", m_option, true, hFont);

				TCHAR mess[32];
				wsprintf(mess, "%d font(s) installed.", succeeded);
				MessageBox(NULL, mess, "Font Install", MB_OK);

				if ( succeeded )
                    if ( m_option==0 )
						SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);
					else
						Update();
			}
				return TRUE;

			case IDC_UNLOAD:
			{
				GetOption();
				int succeeded = ProcessDocument("testdoc.tmp", m_option, false, hFont);

				TCHAR mess[32];
				wsprintf(mess, "%d font(s) uninstalled.", succeeded);
				MessageBox(NULL, mess, "Font Install", MB_OK);

				if ( succeeded )
					if ( m_option==0 )
						SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);
					else
						Update();
			}
				return TRUE;
		}

		return FALSE;
	}

    virtual BOOL DlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
    	switch (uMsg)
	    {
		    case WM_INITDIALOG:
			    return OnInitDialog(hWnd, wParam, lParam);

		    case WM_COMMAND:
			    return OnCommand(hWnd, wParam, lParam);

			case WM_FONTCHANGE:
				{
					TCHAR mess[32];

					wsprintf(mess, "WM_FONTCHANGE %d", ++m_nFontChange);
					SetDlgItemText(hWnd, IDC_MESSAGE, mess);

					Update();
				}
				return TRUE;
	    }

	    return FALSE;
    }

public:
	KMyDialog(HINSTANCE hInst)
	{
		m_hInst       = hInst;
		m_nFontChange = 0;
		m_option      = 0;

		memset(m_font, 0, sizeof(m_font));
	}
};


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int)
{
	KMyDialog dialog(hInstance);

	return dialog.Dialogbox(hInstance, MAKEINTRESOURCE(IDD_FONT));
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?