Combining Letter Images

At this point in the process we have a directory full of a full alphabet of letter images and we need to recombine them into a sprite sheet for use in Cocos2d-x, other game engines and elsewhere. We will use the TexturePacker program to create a sprite-sheet PNG file as well as a PLIST index file. Then we can change this PLIST file to a FNT file required by Cocos2d-x.

Creating the Sprite-Sheet:

TexturePacker will do most of the work here for us -- so this is the easy part.

Start up TexturePacker -- the free version will do all we need. Just select all our letter images and drag them to the left-hand-side window in TexturePacker and drop them there. You will see the file list with small images of each file beside their names. In the center window you will see the images arrayed into a sprite sheet.

NOTE: Record the order of the characters as they appear in the left window of TexturePacker. In my case the string is:

"A BCDEFGHIJKLMNOPQRSTUVWXYZ"

Save the sprite-sheet by pressing the "Publish Sprite Sheet" button at the top of the TexturePacker window and give the sprite-sheet a name (no extension). TexturePacker will generate the <filename>.png and <filename>.plist files.

Sprite sheet containing entire alphabet.

The following is the corresponding PLIST file which describes the locations and sizes of the individual images in the above sprite-sheet:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>frames</key>
        <dict>
            <key>CharImage_001.png</key>
            <dict>
                <key>aliases</key>
                <array/>
                <key>spriteOffset</key>
                <string>{0,0}</string>
                <key>spriteSize</key>
                <string>{214,217}</string>
                <key>spriteSourceSize</key>
                <string>{214,217}</string>
                <key>textureRect</key>
                <string>{{1396,217},{214,217}}</string>
                <key>textureRotated</key>
                <false/>
            </dict>
            <key>CharImage_002.png</key>
            <dict>
                <key>aliases</key>
                <array/>
                <key>spriteOffset</key>
                <string>{0,0}</string>
                <key>spriteSize</key>
                <string>{50,217}</string>
                <key>spriteSourceSize</key>
                <string>{50,217}</string>
                <key>textureRect</key>
                <string>{{0,0},{50,217}}</string>
                <key>textureRotated</key>
                <false/>
            </dict>
            <key>CharImage_003.png</key>
            <dict>
                <key>aliases</key>
                <array/>
                <key>spriteOffset</key>
                <string>{0,0}</string>
                <key>spriteSize</key>
                <string>{186,217}</string>
                <key>spriteSourceSize</key>
                <string>{186,217}</string>
                <key>textureRect</key>
                <string>{{0,217},{186,217}}</string>
                <key>textureRotated</key>
                <false/>
            </dict>
            <key>CharImage_004.png</key>
            <dict>
                <key>aliases</key>
                <array/>
                <key>spriteOffset</key>
                <string>{0,0}</string>
                <key>spriteSize</key>
                <string>{146,217}</string>
                <key>spriteSourceSize</key>
                <string>{146,217}</string>
                <key>textureRect</key>
                <string>{{185,0},{146,217}}</string>
                <key>textureRotated</key>
                <false/>
            </dict>
            <key>CharImage_005.png</key>
            <dict>
                <key>aliases</key>
                <array/>
                <key>spriteOffset</key>
                <string>{0,0}</string>
                <key>spriteSize</key>
                <string>{202,217}</string>
                <key>spriteSourceSize</key>
                <string>{202,217}</string>
                <key>textureRect</key>
                <string>{{572,217},{202,217}}</string>
                <key>textureRotated</key>
                <false/>
            </dict>
            <key>CharImage_006.png</key>
            <dict>
                <key>aliases</key>
                <array/>
                <key>spriteOffset</key>
                <string>{0,0}</string>
                <key>spriteSize</key>
                <string>{165,217}</string>
                <key>spriteSourceSize</key>
                <string>{165,217}</string>
                <key>textureRect</key>
                <string>{{958,0},{165,217}}</string>
                <key>textureRotated</key>
                <false/>
            </dict>
            <key>CharImage_007.png</key>
            <dict>
                <key>aliases</key>
                <array/>
                <key>spriteOffset</key>
                <string>{0,0}</string>
                <key>spriteSize</key>
                <string>{203,217}</string>
                <key>spriteSourceSize</key>
                <string>{203,217}</string>
                <key>textureRect</key>
                <string>{{774,217},{203,217}}</string>
                <key>textureRotated</key>
                <false/>
            </dict>
            <key>CharImage_008.png</key>
            <dict>
                <key>aliases</key>
                <array/>
                <key>spriteOffset</key>
                <string>{0,0}</string>
                <key>spriteSize</key>
                <string>{153,217}</string>
                <key>spriteSourceSize</key>
                <string>{153,217}</string>
                <key>textureRect</key>
                <string>{{331,0},{153,217}}</string>
                <key>textureRotated</key>
                <false/>
            </dict>
            <key>CharImage_009.png</key>
            <dict>
                <key>aliases</key>
                <array/>
                <key>spriteOffset</key>
                <string>{0,0}</string>
                <key>spriteSize</key>
                <string>{299,217}</string>
                <key>spriteSourceSize</key>
                <string>{299,217}</string>
                <key>textureRect</key>
                <string>{{1203,434},{299,217}}</string>
                <key>textureRotated</key>
                <false/>
            </dict>
            <key>CharImage_010.png</key>
            <dict>
                <key>aliases</key>
                <array/>
                <key>spriteOffset</key>
                <string>{0,0}</string>
                <key>spriteSize</key>
                <string>{135,217}</string>
                <key>spriteSourceSize</key>
                <string>{135,217}</string>
                <key>textureRect</key>
                <string>{{50,0},{135,217}}</string>
                <key>textureRotated</key>
                <false/>
            </dict>
            <key>CharImage_011.png</key>
            <dict>
                <key>aliases</key>
                <array/>
                <key>spriteOffset</key>
                <string>{0,0}</string>
                <key>spriteSize</key>
                <string>{164,217}</string>
                <key>spriteSourceSize</key>
                <string>{164,217}</string>
                <key>textureRect</key>
                <string>{{794,0},{164,217}}</string>
                <key>textureRotated</key>
                <false/>
            </dict>
            <key>CharImage_012.png</key>
            <dict>
                <key>aliases</key>
                <array/>
                <key>spriteOffset</key>
                <string>{0,0}</string>
                <key>spriteSize</key>
                <string>{210,217}</string>
                <key>spriteSourceSize</key>
                <string>{210,217}</string>
                <key>textureRect</key>
                <string>{{1186,217},{210,217}}</string>
                <key>textureRotated</key>
                <false/>
            </dict>
            <key>CharImage_013.png</key>
            <dict>
                <key>aliases</key>
                <array/>
                <key>spriteOffset</key>
                <string>{0,0}</string>
                <key>spriteSize</key>
                <string>{182,217}</string>
                <key>spriteSourceSize</key>
                <string>{182,217}</string>
                <key>textureRect</key>
                <string>{{1296,0},{182,217}}</string>
                <key>textureRotated</key>
                <false/>
            </dict>
            <key>CharImage_014.png</key>
            <dict>
                <key>aliases</key>
                <array/>
                <key>spriteOffset</key>
                <string>{0,0}</string>
                <key>spriteSize</key>
                <string>{270,217}</string>
                <key>spriteSourceSize</key>
                <string>{270,217}</string>
                <key>textureRect</key>
                <string>{{933,434},{270,217}}</string>
                <key>textureRotated</key>
                <false/>
            </dict>
            <key>CharImage_015.png</key>
            <dict>
                <key>aliases</key>
                <array/>
                <key>spriteOffset</key>
                <string>{0,0}</string>
                <key>spriteSize</key>
                <string>{315,217}</string>
                <key>spriteSourceSize</key>
                <string>{315,217}</string>
                <key>textureRect</key>
                <string>{{1502,434},{315,217}}</string>
                <key>textureRotated</key>
                <false/>
            </dict>
            <key>CharImage_016.png</key>
            <dict>
                <key>aliases</key>
                <array/>
                <key>spriteOffset</key>
                <string>{0,0}</string>
                <key>spriteSize</key>
                <string>{153,217}</string>
                <key>spriteSourceSize</key>
                <string>{153,217}</string>
                <key>textureRect</key>
                <string>{{484,0},{153,217}}</string>
                <key>textureRotated</key>
                <false/>
            </dict>
            <key>CharImage_017.png</key>
            <dict>
                <key>aliases</key>
                <array/>
                <key>spriteOffset</key>
                <string>{0,0}</string>
                <key>spriteSize</key>
                <string>{191,217}</string>
                <key>spriteSourceSize</key>
                <string>{191,217}</string>
                <key>textureRect</key>
                <string>{{186,217},{191,217}}</string>
                <key>textureRotated</key>
                <false/>
            </dict>
            <key>CharImage_018.png</key>
            <dict>
                <key>aliases</key>
                <array/>
                <key>spriteOffset</key>
                <string>{0,0}</string>
                <key>spriteSize</key>
                <string>{229,217}</string>
                <key>spriteSourceSize</key>
                <string>{229,217}</string>
                <key>textureRect</key>
                <string>{{447,434},{229,217}}</string>
                <key>textureRotated</key>
                <false/>
            </dict>
            <key>CharImage_019.png</key>
            <dict>
                <key>aliases</key>
                <array/>
                <key>spriteOffset</key>
                <string>{0,0}</string>
                <key>spriteSize</key>
                <string>{209,217}</string>
                <key>spriteSourceSize</key>
                <string>{209,217}</string>
                <key>textureRect</key>
                <string>{{977,217},{209,217}}</string>
                <key>textureRotated</key>
                <false/>
            </dict>
            <key>CharImage_020.png</key>
            <dict>
                <key>aliases</key>
                <array/>
                <key>spriteOffset</key>
                <string>{0,0}</string>
                <key>spriteSize</key>
                <string>{157,217}</string>
                <key>spriteSourceSize</key>
                <string>{157,217}</string>
                <key>textureRect</key>
                <string>{{637,0},{157,217}}</string>
                <key>textureRotated</key>
                <false/>
            </dict>
            <key>CharImage_021.png</key>
            <dict>
                <key>aliases</key>
                <array/>
                <key>spriteOffset</key>
                <string>{0,0}</string>
                <key>spriteSize</key>
                <string>{195,217}</string>
                <key>spriteSourceSize</key>
                <string>{195,217}</string>
                <key>textureRect</key>
                <string>{{377,217},{195,217}}</string>
                <key>textureRotated</key>
                <false/>
            </dict>
            <key>CharImage_022.png</key>
            <dict>
                <key>aliases</key>
                <array/>
                <key>spriteOffset</key>
                <string>{0,0}</string>
                <key>spriteSize</key>
                <string>{185,217}</string>
                <key>spriteSourceSize</key>
                <string>{185,217}</string>
                <key>textureRect</key>
                <string>{{1478,0},{185,217}}</string>
                <key>textureRotated</key>
                <false/>
            </dict>
            <key>CharImage_023.png</key>
            <dict>
                <key>aliases</key>
                <array/>
                <key>spriteOffset</key>
                <string>{0,0}</string>
                <key>spriteSize</key>
                <string>{218,217}</string>
                <key>spriteSourceSize</key>
                <string>{218,217}</string>
                <key>textureRect</key>
                <string>{{0,434},{218,217}}</string>
                <key>textureRotated</key>
                <false/>
            </dict>
            <key>CharImage_024.png</key>
            <dict>
                <key>aliases</key>
                <array/>
                <key>spriteOffset</key>
                <string>{0,0}</string>
                <key>spriteSize</key>
                <string>{257,217}</string>
                <key>spriteSourceSize</key>
                <string>{257,217}</string>
                <key>textureRect</key>
                <string>{{676,434},{257,217}}</string>
                <key>textureRotated</key>
                <false/>
            </dict>
            <key>CharImage_025.png</key>
            <dict>
                <key>aliases</key>
                <array/>
                <key>spriteOffset</key>
                <string>{0,0}</string>
                <key>spriteSize</key>
                <string>{229,217}</string>
                <key>spriteSourceSize</key>
                <string>{229,217}</string>
                <key>textureRect</key>
                <string>{{218,434},{229,217}}</string>
                <key>textureRotated</key>
                <false/>
            </dict>
            <key>CharImage_026.png</key>
            <dict>
                <key>aliases</key>
                <array/>
                <key>spriteOffset</key>
                <string>{0,0}</string>
                <key>spriteSize</key>
                <string>{173,217}</string>
                <key>spriteSourceSize</key>
                <string>{173,217}</string>
                <key>textureRect</key>
                <string>{{1123,0},{173,217}}</string>
                <key>textureRotated</key>
                <false/>
            </dict>
            <key>CharImage_027.png</key>
            <dict>
                <key>aliases</key>
                <array/>
                <key>spriteOffset</key>
                <string>{0,0}</string>
                <key>spriteSize</key>
                <string>{216,217}</string>
                <key>spriteSourceSize</key>
                <string>{216,217}</string>
                <key>textureRect</key>
                <string>{{1610,217},{216,217}}</string>
                <key>textureRotated</key>
                <false/>
            </dict>
        </dict>
        <key>metadata</key>
        <dict>
            <key>format</key>
            <integer>3</integer>
            <key>pixelFormat</key>
            <string>RGBA8888</string>
            <key>premultiplyAlpha</key>
            <false/>
            <key>realTextureFileName</key>
            <string>GoldLetterAlphabet.png.png</string>
            <key>size</key>
            <string>{1826,651}</string>
            <key>smartupdate</key>
            <string>$TexturePacker:SmartUpdate:fe5424a4b480ef76ea4dba00751e813d:e17928c76e957c872b5c8c905f73e949:1f6fb27ef0b0da7790b28c03eb8fa82b$</string>
            <key>textureFileName</key>
            <string>GoldLetterAlphabet.png.png</string>
        </dict>
    </dict>
</plist>

However, Cocos2d-x likes FNT files instead of PLIST files so we have to convert this. I've developed a quick and dirty little program (plist2fnt.cpp) to convert PLIST --> FNT file. This program requires the files to be named CharImage_%03d.png". Here's the program:

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <cassert>
#include <queue>

#include "tinyxml2.h"

using namespace tinyxml2;
using namespace std;

typedef long unsigned addr;

int chrcnt=0;
char chridx[512];
const char* indentstr="                                                  ";
int idsz=50;
int indent=0;
void ind(){ printf("%s",indentstr+idsz-indent); };

#define cp(n) printf("CheckPoint(%d)\n",n);

//-----------------------------------------------------------------------------
// BMFont routines.
//-----------------------------------------------------------------------------




typedef struct INFO{
    const char* name;
    int size;
    bool bold;
    bool italic;
}t_bmfont_info;

typedef struct COMMON{
    int lineHeight;
    int base;
    int scaleW;
    int scaleH;
}t_bmfont_common;

typedef struct PAGE{
    const char* name;
}t_bmfont_page;

typedef struct COUNT{
    int chars;
}t_bmfont_count;

typedef struct CHAR {
    char chr;
    int ofsx;
    int ofsy;
    int w;
    int h;
    int yoffset;
}t_bmfont_chr;

typedef struct KERNING{
    int dummy;
}t_bmfont_kern;

t_bmfont_info   bmfont_info;
t_bmfont_common bmfont_common;
t_bmfont_page   bmfont_page;
t_bmfont_count  bmfont_count;
t_bmfont_chr    bmfont_chr;

class mycomparison
{
    bool reverse;
  public:
    bool operator() (t_bmfont_chr& lhs, t_bmfont_chr& rhs) const
    {
        return (lhs.chr>rhs.chr);
    }
};
typedef std::priority_queue<int,std::vector<t_bmfont_chr>,mycomparison> mypq_type;
mypq_type myqueue;

void init_BMFont(){
    bmfont_info.name="Unknown";
    bmfont_info.size=0;
    bmfont_info.bold=0;
    bmfont_info.italic=0;

    bmfont_common.lineHeight=0;
    bmfont_common.base=0;
    bmfont_common.scaleW=0;
    bmfont_common.scaleH=0;

    bmfont_page.name="Unknown";

    bmfont_count.chars=0;

    bmfont_chr.chr=0;
    bmfont_chr.ofsx=0;
    bmfont_chr.ofsy=0;
    bmfont_chr.w=0;
    bmfont_chr.h=0;
    bmfont_chr.yoffset=0;
}

void put_BMFont_info(const char *face,int size,bool bold,bool italic)
{
    fprintf(stderr,"info face="%s" size=%d bold=%d italic=%d charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=1,1\n",
        face,size,(bold)?1:0,(italic)?1:0);
}

void put_BMFont_common(int lineHeight,int base,int scaleW,int scaleH)
{
    fprintf(stderr,"common lineHeight=%d base=%d scaleW=%d scaleH=%d pages=1 packed=0 alphaChnl=1 redChnl=0 greenChnl=0 blueChnl=0\n",
        lineHeight,base,scaleW,scaleH);
}

void put_BMFont_page(const char* pngName)
{
    fprintf(stderr,"page id=0 file="%s"\n",pngName);
}

void put_BMFont_count(int chars)
{
    fprintf(stderr,"chars count=%d\n",chars);
}

void put_BMFont_char(char chr,int ofsx,int ofsy,int w,int h,int yoffset)
{
    fprintf(stderr,"char id=%d x=%d y=%d width=%d height=%d xoffset=0 yoffset=%d xadvance=%d page=0 chnl=0 letter="%c"\n",
        chr,ofsx,ofsy,w,h,yoffset,w+1,chr);
}

void put_BMFont_end(int kerns)
{
    fprintf(stderr,"kernings count=0\n");
}




bool iskey(XMLNode* node) { return (strncmp("key",node->Value(),3)==0)?true:false; };
bool isdict(XMLNode* node) { return (strncmp("dict",node->Value(),4)==0)?true:false; };
bool isarray(XMLNode* node) { return (strncmp("array",node->Value(),5)==0)?true:false; };
bool isstr(XMLNode* node) { return (strncmp("string",node->Value(),6)==0)?true:false; };
bool istrue(XMLNode* node) { return (strncmp("true",node->Value(),4)==0)?true:false; };
bool isfalse(XMLNode* node) { return (strncmp("false",node->Value(),5)==0)?true:false; };


const char* keytext(XMLNode* node) {
    auto elem=node->ToElement();
    assert((elem!=nullptr)||(!"ERROR: node was not XMLElement"));
    return(elem->ToElement()->GetText());
};

const char* get_keytext(XMLNode* node)
{
    const char* rtn="";
    if(iskey(node)){
        rtn=keytext(node);
    }
    return(rtn);
};

XMLNode* get_keyvalue(XMLNode* node)
{
    node=node->NextSibling();
    return(node);
};

void get_dict(XMLNode* dict)
{
    const char* lastkey="none";
    indent+=2;
    auto child=dict->FirstChildElement("key");
    while(child!=nullptr){
        auto keytxt=get_keytext(child);
        ind(); printf("key='%s'\n",keytxt);
        if(strncmp("CharImage",keytxt,6)==0){
            int idx;
            chrcnt++;
            char buff[100];
            strncpy(buff,keytxt,99);
            char* token=strtok(buff,"_.");
            printf("token='%s'\n",token);
            token=strtok(nullptr,"_.");
            printf("token='%s'(%d)\n",token,atoi(token));
           
            if(atoi(token)==90){
                bmfont_chr.chr='?';
            }else{
                bmfont_chr.chr=chridx[atoi(token)-1];
            }
            printf("bmfont_chr.chr='%c(%d)'\n",bmfont_chr.chr,bmfont_chr.chr);
        }
        lastkey=keytxt;

        auto keyvalue=get_keyvalue(child);
        if(isdict(keyvalue)){
            ind();printf("dict\n");
            get_dict(keyvalue);

        }else if(isarray(keyvalue)){
            ind();printf("array\n");

        }else if(isstr(keyvalue)){
            const char* kv=keytext(keyvalue);
            ind();printf("str:'%s'\n",kv);
            if(strncmp("textureRect",lastkey,11)==0){
                char buf[100];
                strcpy(buf,kv);
                const char* flt="{}, ";
                int x=0,y=0,w=0,h=0,yoffset=0;
                char* trp=strtok(buf,flt);
                x=atoi(trp);
                trp=strtok(nullptr,flt);
                y=atoi(trp);
                trp=strtok(nullptr,flt);
                w=atoi(trp);
                trp=strtok(nullptr,flt);
                h=atoi(trp);

                bmfont_common.lineHeight = max(bmfont_common.lineHeight,h);

                bmfont_chr.ofsx=x;
                bmfont_chr.ofsy=y;
                bmfont_chr.w=w;
                bmfont_chr.h=h;
                bmfont_chr.yoffset=yoffset;
                myqueue.push(bmfont_chr);

            }

        }else if(istrue(keyvalue)){
            ind();printf("true\n");

        }else if(isfalse(keyvalue)){
            ind();printf("false\n");

        }else{
            ind();printf("unknown\n");
        }
        child=child->NextSiblingElement("key");
    }
    indent-=2;
}


void get_alphabet(const char* fn_alphabet)
{
    FILE* fh=fopen(fn_alphabet,"r");
    if(fh==nullptr){
        perror("Opening alpahbet file");
        exit(1);
    }else{

        int i=0;
        int chr=0;
        while((chr=getc(fh))!=EOF){
            printf("chr=0x%02x ",chr);
            if(chr>=' '){
                printf("chridx[%d]='%c'\n",i,chr);
                chridx[i++]=(char)chr;
            }
        }
        chridx[i]=0;

        fclose(fh);
    }
}

void dump_alphabet()
{
    printf("Alphabet:");
    for(int i=0;(i<511)&&(chridx[i]!=0);i++){
        if((i%20)==0) printf("\n    ");
        printf("%c",chridx[i]);
    }
    printf("\n");
}


int main(int argc,char* argv[]){

    const char* FontFile=argv[1];
    const int   FontSize=atoi(argv[2]);
    const int   FontFileSzW=atoi(argv[3]);
    const int   FontFileSzH=atoi(argv[4]);
    const char* AlphaFile="alphabet.txt";

    char buff[100];
    char fontname[30];
    char pagename[35];

    XMLDocument doc;

    get_alphabet(AlphaFile);
    dump_alphabet();

    init_BMFont();

    strcpy(buff,FontFile);
    char* token=strtok(buff,".");
    sprintf(fontname,"%s",token);
    sprintf(pagename,"%s.png",token);
    bmfont_info.name=fontname;
    bmfont_page.name=pagename;

    doc.LoadFile(FontFile);
    //doc.LoadFile( "a.plist" );
    //doc.SaveFile( "a.out.xml" );


    // Get the documents first child to start things off.
    // First find the plist node.
    auto plist = doc.FirstChildElement("plist");  // At line 003 below
    if(plist!=nullptr){

        // Once we have the plist look for the dict child
        auto dict=plist->FirstChildElement("dict");  // At line 004 below
        if(dict!=nullptr){
            printf("Got dict\n");

            // Now look at all keys in that dict.
            auto child=dict->FirstChildElement("key"); // At line 005 or 023 below
            while(child!=nullptr){
                // The one labelled "frames" is the one we want.
                if(strncmp("frames",child->GetText(),5)==0){    // This is the key at line 005
                    printf("    Key='%s'\n",child->GetText());
                    auto dict=child->NextSibling();
                    if(dict!=nullptr){
                        printf("Got value='%s'\n",dict->Value());
                        get_dict(dict);                         // Process the dict(ionary) at line 008 to 022
                    }
                }
                child=child->NextSiblingElement("key");
            }
        }
    }

    put_BMFont_info(fontname,FontSize,false,false);
    put_BMFont_common(bmfont_common.lineHeight,25,FontFileSzW,FontFileSzH);
    put_BMFont_page(pagename);
    put_BMFont_count(chrcnt);
    while(!myqueue.empty()){
        t_bmfont_chr bmfont_chr=myqueue.top();
        put_BMFont_char(bmfont_chr.chr,bmfont_chr.ofsx,bmfont_chr.ofsy,bmfont_chr.w,bmfont_chr.h,bmfont_chr.yoffset);
        myqueue.pop();
    }
    put_BMFont_end(0);
}

// 000
// 001 <?xml version="1.0" encoding="UTF-8"?>
// 002 <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
// 003 <plist version="1.0">
// 004     <dict>
// 005         <key>frames</key>
// 006         <dict>
// 007             <key>Letter_001.png</key>
// 008             <dict>
// 009                 <key>aliases</key>
// 010                 <array/>
// 011                 <key>spriteOffset</key>
// 012                 <string>{0,0}</string>
// 013                 <key>spriteSize</key>
// 014                 <string>{89,115}</string>
// 015                 <key>spriteSourceSize</key>
// 016                 <string>{89,115}</string>
// 017                 <key>textureRect</key>
// 018                 <string>{{82,920},{89,115}}</string>
// 019                 <key>textureRotated</key>
// 020                 <false/>
// 021             </dict>
// 022         </dict>
// 023         <key>metadata</key>
// 024         <dict>
// 025             <key>format</key>
// 026             <integer>3</integer>
// 027             <key>pixelFormat</key>
// 028             <string>RGBA8888</string>
// 029             <key>premultiplyAlpha</key>
// 030             <false/>
// 031             <key>realTextureFileName</key>
// 032             <string>RoyalsGold.png</string>
// 033             <key>size</key>
// 034             <string>{505,1495}</string>
// 035             <key>smartupdate</key>
// 036             <string>$TexturePacker:SmartUpdate:bae076a86c994950c23db26de5b903c7:bca835b522c805074e19afa28009f159:13f59389bf20a876b22003b1a56f184c$</string>
// 037             <key>textureFileName</key>
// 038             <string>RoyalsGold.png</string>
// 039         </dict>
// 040     </dict>
// 041 </plist>

The plist2fnt program can be run with the following grammar:

plist2fnt <filename>.plist <font-size> <pngfile-width> <pngfile-height>

For example for my GoldLetterAlphabet sprite sheet which is 1826 x 621 pixels in dimension (cmd: file GoldLetterAlphabet.png):

plist2fnt GoldLetterAlphabet.plist 200 1826 621 2>GoldLetterAlphabet.fnt

NOTE: The FNT file output is to stderr so that needs to be captured instead of stdout.

And this is the resultant FNT file:

info face="GoldLetterAlphabet" size=200 bold=0 italic=0 charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=1,1
common lineHeight=217 base=25 scaleW=1826 scaleH=651 pages=1 packed=0 alphaChnl=1 redChnl=0 greenChnl=0 blueChnl=0
page id=0 file="GoldLetterAlphabet.png"
chars count=27
char id=32 x=0 y=0 width=50 height=217 xoffset=0 yoffset=0 xadvance=51 page=0 chnl=0 letter=" "
char id=65 x=1396 y=217 width=214 height=217 xoffset=0 yoffset=0 xadvance=215 page=0 chnl=0 letter="A"
char id=66 x=0 y=217 width=186 height=217 xoffset=0 yoffset=0 xadvance=187 page=0 chnl=0 letter="B"
char id=67 x=185 y=0 width=146 height=217 xoffset=0 yoffset=0 xadvance=147 page=0 chnl=0 letter="C"
char id=68 x=572 y=217 width=202 height=217 xoffset=0 yoffset=0 xadvance=203 page=0 chnl=0 letter="D"
char id=69 x=958 y=0 width=165 height=217 xoffset=0 yoffset=0 xadvance=166 page=0 chnl=0 letter="E"
char id=70 x=774 y=217 width=203 height=217 xoffset=0 yoffset=0 xadvance=204 page=0 chnl=0 letter="F"
char id=71 x=331 y=0 width=153 height=217 xoffset=0 yoffset=0 xadvance=154 page=0 chnl=0 letter="G"
char id=72 x=1203 y=434 width=299 height=217 xoffset=0 yoffset=0 xadvance=300 page=0 chnl=0 letter="H"
char id=73 x=50 y=0 width=135 height=217 xoffset=0 yoffset=0 xadvance=136 page=0 chnl=0 letter="I"
char id=74 x=794 y=0 width=164 height=217 xoffset=0 yoffset=0 xadvance=165 page=0 chnl=0 letter="J"
char id=75 x=1186 y=217 width=210 height=217 xoffset=0 yoffset=0 xadvance=211 page=0 chnl=0 letter="K"
char id=76 x=1296 y=0 width=182 height=217 xoffset=0 yoffset=0 xadvance=183 page=0 chnl=0 letter="L"
char id=77 x=933 y=434 width=270 height=217 xoffset=0 yoffset=0 xadvance=271 page=0 chnl=0 letter="M"
char id=78 x=1502 y=434 width=315 height=217 xoffset=0 yoffset=0 xadvance=316 page=0 chnl=0 letter="N"
char id=79 x=484 y=0 width=153 height=217 xoffset=0 yoffset=0 xadvance=154 page=0 chnl=0 letter="O"
char id=80 x=186 y=217 width=191 height=217 xoffset=0 yoffset=0 xadvance=192 page=0 chnl=0 letter="P"
char id=81 x=447 y=434 width=229 height=217 xoffset=0 yoffset=0 xadvance=230 page=0 chnl=0 letter="Q"
char id=82 x=977 y=217 width=209 height=217 xoffset=0 yoffset=0 xadvance=210 page=0 chnl=0 letter="R"
char id=83 x=637 y=0 width=157 height=217 xoffset=0 yoffset=0 xadvance=158 page=0 chnl=0 letter="S"
char id=84 x=377 y=217 width=195 height=217 xoffset=0 yoffset=0 xadvance=196 page=0 chnl=0 letter="T"
char id=85 x=1478 y=0 width=185 height=217 xoffset=0 yoffset=0 xadvance=186 page=0 chnl=0 letter="U"
char id=86 x=0 y=434 width=218 height=217 xoffset=0 yoffset=0 xadvance=219 page=0 chnl=0 letter="V"
char id=87 x=676 y=434 width=257 height=217 xoffset=0 yoffset=0 xadvance=258 page=0 chnl=0 letter="W"
char id=88 x=218 y=434 width=229 height=217 xoffset=0 yoffset=0 xadvance=230 page=0 chnl=0 letter="X"
char id=89 x=1123 y=0 width=173 height=217 xoffset=0 yoffset=0 xadvance=174 page=0 chnl=0 letter="Y"
char id=90 x=1610 y=217 width=216 height=217 xoffset=0 yoffset=0 xadvance=217 page=0 chnl=0 letter="Z"
kernings count=0

Next:

Now that we have the sprite-sheet and it's corresponding FNT file generated we go on to generating a Cocos2d-x (v3.x) project that uses this bitmap file.