YOU CAN CODE!

 

With The Case Of UCanCode.net  Release The Power OF  Visual C++ !   HomeProducts | PurchaseSupport | Downloads  
Download Evaluation
Pricing & Purchase?
E-XD++Visual C++/ MFC Products
Overview
Features Tour 
Electronic Form Solution
Visualization & HMI Solution
Power system HMI Solution
CAD Drawing and Printing Solution

Bar code labeling Solution
Workflow Solution

Coal industry HMI Solution
Instrumentation Gauge Solution

Report Printing Solution
Graphical modeling Solution
GIS mapping solution

Visio graphics solution
Industrial control SCADA &HMI Solution
BPM business process Solution

Industrial monitoring Solution
Flowchart and diagramming Solution
Organization Diagram Solution

Graphic editor Source Code
UML drawing editor Source Code
Map Diagramming Solution

Architectural Graphic Drawing Solution
Request Evaluation
Purchase
ActiveX COM Products
Overview
Download
Purchase
Technical Support
  General Q & A
Discussion Board
Contact Us

Links

Get Ready to Unleash the Power of UCanCode .NET


UCanCode Software focuses on general application software development. We provide complete solution for developers. No matter you want to develop a simple database workflow application, or an large flow/diagram based system, our product will provide a complete solution for you. Our product had been used by hundreds of top companies around the world!

"100% source code provided! Free you from not daring to use components because of unable to master the key technology of components!"


VC++ Example: Read font from file name, TTF Font name CFile and Open

 
 

Code Snippet

Data types definition

A TTF file consists of several tables, each table represent some data, regarding of its type. Some tables are required, some are not. We actually need only one of them, called "name", e.g. names table. This is the place where the font information is stored, like font name, copyright, trademark and more.

Collapse Copy Code
//This is TTF file header
typedef struct _tagTT_OFFSET_TABLE{
    USHORT uMajorVersion;
    USHORT uMinorVersion;
    USHORT uNumOfTables;
    USHORT uSearchRange;
    USHORT uEntrySelector;
    USHORT uRangeShift;
}TT_OFFSET_TABLE;

//Tables in TTF file and there placement and name (tag)
typedef struct _tagTT_TABLE_DIRECTORY{
    char szTag[4]; //table name
    ULONG uCheckSum; //Check sum
    ULONG uOffset; //Offset from beginning of file
    ULONG uLength; //length of the table in bytes
}TT_TABLE_DIRECTORY;

//Header of names table
typedef struct _tagTT_NAME_TABLE_HEADER{
    USHORT uFSelector; //format selector. Always 0
    USHORT uNRCount; //Name Records count
    USHORT uStorageOffset; //Offset for strings storage, 
                           //from start of the table
}TT_NAME_TABLE_HEADER;

//Record in names table
typedef struct _tagTT_NAME_RECORD{
    USHORT uPlatformID;
    USHORT uEncodingID;
    USHORT uLanguageID;
    USHORT uNameID;
    USHORT uStringLength;
    USHORT uStringOffset; //from start of storage area
}TT_NAME_RECORD;
Macros

Now only thing left is macros I was talking before. The macros definition looks like:

Collapse Copy Code
#define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
#define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))

Now what is that? The reason we need those macros is that TTF files are stored in Big-Endian format, unlike in Windows systems, where all files are in Little Endian. Yeah I know it sounds silly with all those "endians" :). Big Endian is used by Motorolla processors for example, where the higher byte is stored first, while in Little Endian (for Intel processors) the higher byte is the last. For example you have an integer variable 1 (which is 4 bytes long). Try to save it to file and open in any hexadecimal editor, you will see:

Collapse Copy Code
01 00 00 00    //Little Endian - Intel

This is Little Endian system (Intel). But for Big-Endian (Motorolla), the number will be stored vise versa:

Collapse Copy Code
00 00 00 01    //Big Endian - Motorolla

So these formats are incompatible. And TTF file as I said, is stored in Motorolla style (Big Endian). That's why we need those 2 macros to rearrange bytes in variables retrieved from TrueType font file.

Reading the file

Now we are prepared to read the TTF file. So let's get started.

First of all we need to read the file header (TT_OFFSET_TABLE structure):

Collapse Copy Code
CFile f;
CString csRetVal;

//lpszFilePath is the path to our font file
if(f.Open(lpszFilePath, CFile::modeRead|CFile::shareDenyWrite)){

    //define and read file header
    TT_OFFSET_TABLE ttOffsetTable;
    f.Read(&ttOffsetTable, sizeof(TT_OFFSET_TABLE));

    //remember to rearrange bytes in the field you gonna use
    ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables);
    ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion);
    ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion);

    //check is this is a true type font and the version is 1.0
    if(ttOffsetTable.uMajorVersion != 1 || ttOffsetTable.uMinorVersion != 0)
        return csRetVal;

Right after the file header goes Offsets Table. You can find here an offset to interesting you table, "name" in our case.

Collapse Copy Code
    TT_TABLE_DIRECTORY tblDir;
    BOOL bFound = FALSE;
    CString csTemp;

    for(int i=0; i< ttOffsetTable.uNumOfTables; i++){
        f.Read(&tblDir, sizeof(TT_TABLE_DIRECTORY));
        csTemp.Empty();

        //table's tag cannot exceed 4 characters
        strncpy(csTemp.GetBuffer(4), tblDir.szTag, 4);
        csTemp.ReleaseBuffer();
        if(csTemp.CompareNoCase(_T("name")) == 0){
            //we found our table. Rearrange order and quit the loop
            bFound = TRUE;
            tblDir.uLength = SWAPLONG(tblDir.uLength);
            tblDir.uOffset = SWAPLONG(tblDir.uOffset);
            break;
        }
    }

We finally found the names table, so let's read its header:

Collapse Copy Code
    if(bFound){
        //move to offset we got from Offsets Table
        f.Seek(tblDir.uOffset, CFile::begin);
        TT_NAME_TABLE_HEADER ttNTHeader;
        f.Read(&ttNTHeader, sizeof(TT_NAME_TABLE_HEADER));

        //again, don't forget to swap bytes!
        ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount);
        ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset);
        TT_NAME_RECORD ttRecord;
        bFound = FALSE;

Right after the Names Table header, go records in it. So we need to run through all records to find information interesting to us - font name.

Collapse Copy Code
    for(int i=0; i<ttNTHeader.uNRCount; i++){
    f.Read(&ttRecord, sizeof(TT_NAME_RECORD));
    ttRecord.uNameID = SWAPWORD(ttRecord.uNameID);

    //1 says that this is font name. 0 for example determines copyright info
    if(ttRecord.uNameID == 1){
        ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength);
        ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset);

        //save file position, so we can return to continue with search
        int nPos = f.GetPosition();
        f.Seek(tblDir.uOffset + ttRecord.uStringOffset + 
                 ttNTHeader.uStorageOffset, CFile::begin);

        //bug fix: see the post by SimonSays to read more about it
        TCHAR lpszNameBuf = csTemp.GetBuffer(ttRecord.uStringLength + 1);
        ZeroMemory(lpszNameBuf, ttRecord.uStringLength + 1);
        f.Read(lpszNameBuf, ttRecord.uStringLength);
        csTemp.ReleaseBuffer();

        //yes, still need to check if the font name is not empty
        //if it is, continue the search
        if(csTemp.GetLength() > 0){
            csRetVal = csTemp;
            break;
        }
        f.Seek(nPos, CFile::begin);
    }
}

 

 

Copyright ?1998-2009 UCanCode.Net Software , all rights reserved.
Other product and company names herein may be the trademarks of their respective owners.

Please direct your questions or comments to webmaster@ucancode.net