int CFontGen::SaveFont(const char *szFile) { if( isWorking ) return -1; // The pages must be generated first if( !arePagesGenerated ) return -1; // Create a memory dc HDC dc = CreateCompatibleDC(0); HFONT font = CreateFont(0); HFONT oldFont = (HFONT)SelectObject(dc, font); // Determine the size needed for the char int height, base; TEXTMETRIC tm; GetTextMetrics(dc, &tm); // Round up to make sure fractional pixels are covered height = (int)ceil(float(tm.tmHeight)/aa); base = (int)ceil(float(tm.tmAscent)/aa); // Save the character attributes FILE *f; string filename = szFile; if( _stricmp(filename.substr(filename.length() - 4).c_str(), ".fnt") == 0 ) filename = filename.substr(0, filename.length() - 4); errno_t e = fopen_s(&f, (filename + ".fnt").c_str(), "wb"); if( e != 0 || f == 0 ) return -1; // Get the filename without path int r = filename.rfind('\\'); string filenameonly; if( r != -1 ) filenameonly = filename.substr(r+1); else filenameonly = filename; if( outBitDepth != 32 ) fourChnlPacked = false; int numPages = pages.size(); // Determine the number of digits needed for the page file id int numDigits = numPages > 1 ? int(log10(float(numPages-1))+1) : 1; if( fontDescFormat == 1 ) { fprintf(f, "<?xml version=\"1.0\"?>\r\n"); fprintf(f, "<font>\r\n"); fprintf(f, " <info face=\"%s\" size=\"%d\" bold=\"%d\" italic=\"%d\" charset=\"%s\" unicode=\"%d\" stretchH=\"%d\" smooth=\"%d\" aa=\"%d\" padding=\"%d,%d,%d,%d\" spacing=\"%d,%d\" outline=\"%d\"/>\r\n", fontName.c_str(), fontSize, isBold, isItalic, useUnicode ? "" : GetCharSetName(charSet).c_str(), useUnicode, scaleH, useSmoothing, aa, paddingUp, paddingRight, paddingDown, paddingLeft, spacingHoriz, spacingVert, outlineThickness); fprintf(f, " <common lineHeight=\"%d\" base=\"%d\" scaleW=\"%d\" scaleH=\"%d\" pages=\"%d\" packed=\"%d\" alphaChnl=\"%d\" redChnl=\"%d\" greenChnl=\"%d\" blueChnl=\"%d\"/>\r\n", int(ceilf(height*float(scaleH)/100.0f)), int(ceilf(base*float(scaleH)/100.0f)), outWidth, outHeight, numPages, fourChnlPacked, alphaChnl, redChnl, greenChnl, blueChnl); fprintf(f, " <pages>\r\n"); for( int n = 0; n < numPages; n++ ) fprintf(f, " <page id=\"%d\" file=\"%s_%0*d.%s\" />\r\n", n, filenameonly.c_str(), numDigits, n, textureFormat.c_str()); fprintf(f, " </pages>\r\n"); } else if( fontDescFormat == 0 ) { fprintf(f, "info face=\"%s\" size=%d bold=%d italic=%d charset=\"%s\" unicode=%d stretchH=%d smooth=%d aa=%d padding=%d,%d,%d,%d spacing=%d,%d outline=%d\r\n", fontName.c_str(), fontSize, isBold, isItalic, useUnicode ? "" : GetCharSetName(charSet).c_str(), useUnicode, scaleH, useSmoothing, aa, paddingUp, paddingRight, paddingDown, paddingLeft, spacingHoriz, spacingVert, outlineThickness); fprintf(f, "common lineHeight=%d base=%d scaleW=%d scaleH=%d pages=%d packed=%d alphaChnl=%d redChnl=%d greenChnl=%d blueChnl=%d\r\n", int(ceilf(height*float(scaleH)/100.0f)), int(ceilf(base*float(scaleH)/100.0f)), outWidth, outHeight, numPages, fourChnlPacked, alphaChnl, redChnl, greenChnl, blueChnl); for( int n = 0; n < numPages; n++ ) fprintf(f, "page id=%d file=\"%s_%0*d.%s\"\r\n", n, filenameonly.c_str(), numDigits, n, textureFormat.c_str()); } else { // Write the magic word and file version fwrite("BMF", 3, 1, f); fputc(3, f); // Write the info block #pragma pack(push) #pragma pack(1) struct infoBlock { int blockSize; unsigned short fontSize; char reserved :4; char bold :1; char italic :1; char unicode :1; char smooth :1; unsigned char charSet; unsigned short stretchH; char aa; unsigned char paddingUp; unsigned char paddingRight; unsigned char paddingDown; unsigned char paddingLeft; unsigned char spacingHoriz; unsigned char spacingVert; unsigned char outline; char fontName[1]; } info; #pragma pack(pop) info.blockSize = sizeof(info) + fontName.length() - 4; info.fontSize = fontSize; info.reserved = 0; info.bold = isBold; info.italic = isItalic; info.unicode = useUnicode; info.smooth = useSmoothing; info.charSet = charSet; info.stretchH = scaleH; info.aa = aa; info.paddingUp = paddingUp; info.paddingRight = paddingRight; info.paddingDown = paddingDown; info.paddingLeft = paddingLeft; info.spacingHoriz = spacingHoriz; info.spacingVert = spacingVert; info.outline = outlineThickness; fputc(1, f); fwrite(&info, sizeof(info)-1, 1, f); fwrite(fontName.c_str(), fontName.length()+1, 1, f); // Write the common block #pragma pack(push) #pragma pack(1) struct commonBlock { int blockSize; unsigned short lineHeight; unsigned short base; unsigned short scaleW; unsigned short scaleH; unsigned short pages; unsigned char packed:1; unsigned char reserved:7; unsigned char alphaChnl; unsigned char redChnl; unsigned char greenChnl; unsigned char blueChnl; } common; #pragma pack(pop) common.blockSize = sizeof(common) - 4; common.lineHeight = int(ceilf(height*float(scaleH)/100.0f)); common.base = int(ceilf(base*float(scaleH)/100.0f)); common.scaleW = outWidth; common.scaleH = outHeight; common.pages = numPages; common.reserved = 0; common.packed = fourChnlPacked; common.alphaChnl = alphaChnl; common.redChnl = redChnl; common.greenChnl = greenChnl; common.blueChnl = blueChnl; fputc(2, f); fwrite(&common, sizeof(common), 1, f); // Write the page block fputc(3, f); int size = (filenameonly.length() + numDigits + 2 + textureFormat.length() + 1)*numPages; fwrite(&size, sizeof(size), 1, f); for( int n = 0; n < numPages; n++ ) { fprintf(f, "%s_%0*d.%s", filenameonly.c_str(), numDigits, n, textureFormat.c_str()); fputc(0, f); } } const int maxChars = useUnicode ? maxUnicodeChar+1 : 256; // Count the number of characters that will be written int numChars = 0; int n; for( n = 0; n < maxChars; n++ ) if( chars[n] ) numChars++; if( invalidCharGlyph ) numChars++; if( fontDescFormat == 0 ) fprintf(f, "chars count=%d\r\n", numChars); else if( fontDescFormat == 1 ) fprintf(f, " <chars count=\"%d\">\r\n", numChars); else if( fontDescFormat == 2 ) { fputc(4, f); // Determine the size of this block int size = (4+2+2+2+2+2+2+2+1+1)*numChars; fwrite(&size, 4, 1, f); } if( invalidCharGlyph ) { if( fontDescFormat == 1 ) fprintf(f, " <char id=\"%d\" x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" xoffset=\"%d\" yoffset=\"%d\" xadvance=\"%d\" page=\"%d\" chnl=\"%d\" />\r\n", -1, invalidCharGlyph->m_x, invalidCharGlyph->m_y, invalidCharGlyph->m_width, invalidCharGlyph->m_height, invalidCharGlyph->m_xoffset, invalidCharGlyph->m_yoffset, invalidCharGlyph->m_advance, invalidCharGlyph->m_page, invalidCharGlyph->m_chnl); else if( fontDescFormat == 0 ) fprintf(f, "char id=%-4d x=%-5d y=%-5d width=%-5d height=%-5d xoffset=%-5d yoffset=%-5d xadvance=%-5d page=%-2d chnl=%-2d\r\n", -1, invalidCharGlyph->m_x, invalidCharGlyph->m_y, invalidCharGlyph->m_width, invalidCharGlyph->m_height, invalidCharGlyph->m_xoffset, invalidCharGlyph->m_yoffset, invalidCharGlyph->m_advance, invalidCharGlyph->m_page, invalidCharGlyph->m_chnl); else { #pragma pack(push) #pragma pack(1) struct charBlock { DWORD id; WORD x; WORD y; WORD width; WORD height; short xoffset; short yoffset; short xadvance; char page; char channel; } charInfo; #pragma pack(pop) charInfo.id = -1; charInfo.x = invalidCharGlyph->m_x; charInfo.y = invalidCharGlyph->m_y; charInfo.width = invalidCharGlyph->m_width; charInfo.height = invalidCharGlyph->m_height; charInfo.xoffset = invalidCharGlyph->m_xoffset; charInfo.yoffset = invalidCharGlyph->m_yoffset; charInfo.xadvance = invalidCharGlyph->m_advance; charInfo.page = invalidCharGlyph->m_page; charInfo.channel = invalidCharGlyph->m_chnl; fwrite(&charInfo, sizeof(charInfo), 1, f); } } for( n = 0; n < maxChars; n++ ) { if( chars[n] ) { int page, chnl; page = chars[n]->m_page; chnl = chars[n]->m_chnl; if( fontDescFormat == 1 ) fprintf(f, " <char id=\"%d\" x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" xoffset=\"%d\" yoffset=\"%d\" xadvance=\"%d\" page=\"%d\" chnl=\"%d\" />\r\n", n, chars[n]->m_x, chars[n]->m_y, chars[n]->m_width, chars[n]->m_height, chars[n]->m_xoffset, chars[n]->m_yoffset, chars[n]->m_advance, page, chnl); else if( fontDescFormat == 0 ) fprintf(f, "char id=%-4d x=%-5d y=%-5d width=%-5d height=%-5d xoffset=%-5d yoffset=%-5d xadvance=%-5d page=%-2d chnl=%-2d\r\n", n, chars[n]->m_x, chars[n]->m_y, chars[n]->m_width, chars[n]->m_height, chars[n]->m_xoffset, chars[n]->m_yoffset, chars[n]->m_advance, page, chnl); else { #pragma pack(push) #pragma pack(1) struct charBlock { DWORD id; WORD x; WORD y; WORD width; WORD height; short xoffset; short yoffset; short xadvance; char page; char channel; } charInfo; #pragma pack(pop) charInfo.id = n; charInfo.x = chars[n]->m_x; charInfo.y = chars[n]->m_y; charInfo.width = chars[n]->m_width; charInfo.height = chars[n]->m_height; charInfo.xoffset = chars[n]->m_xoffset; charInfo.yoffset = chars[n]->m_yoffset; charInfo.xadvance = chars[n]->m_advance; charInfo.page = page; charInfo.channel = chnl; fwrite(&charInfo, sizeof(charInfo), 1, f); } } } if( fontDescFormat == 1 ) fprintf(f, " </chars>\r\n"); // Save the kerning pairs as well vector<KERNINGPAIR> pairs; if( useUnicode ) { // TODO: How do I obtain the kerning pairs for // the characters in the higher planes? int num = GetKerningPairsW(dc, 0, 0); if( num > 0 ) { pairs.resize(num); GetKerningPairsW(dc, num, &pairs[0]); } } else { int num = GetKerningPairs(dc, 0, 0); if( num > 0 ) { pairs.resize(num); GetKerningPairs(dc, num, &pairs[0]); } } if( pairs.size() == 0 ) { // Build a list of all selected chars vector<UINT> chars; chars.reserve(GetNumCharsSelected()); for( UINT n = 0; n <= maxUnicodeChar; n++ ) { if( selected[n] ) { chars.push_back(n); if( chars.size() == GetNumCharsSelected() ) break; } } GetKerningPairsFromGPOS(dc, pairs, chars); } if( pairs.size() > 0 ) { // Count the number of kerning pairs int count = 0; for( unsigned int n = 0; n < pairs.size(); n++ ) { if( pairs[n].wFirst < maxChars && pairs[n].wSecond < maxChars && !disabled[pairs[n].wFirst] && !disabled[pairs[n].wSecond] && selected[pairs[n].wFirst] && selected[pairs[n].wSecond] && pairs[n].iKernAmount/aa ) { count++; } } if( fontDescFormat == 0 ) fprintf(f, "kernings count=%d\r\n", count); else if( fontDescFormat == 1 ) fprintf(f, " <kernings count=\"%d\">\r\n", count); else if( fontDescFormat == 2 ) { fputc(5, f); // Determine the size of the block int size = count*10; fwrite(&size, 4, 1, f); } } // It's been reported that for Chinese WinXP the kerning pairs for // non-unicode charsets may contain characters > 255, so we need to // filter for this. for( unsigned int n = 0; n < pairs.size(); n++ ) { if( pairs[n].wFirst < maxChars && pairs[n].wSecond < maxChars && !disabled[pairs[n].wFirst] && !disabled[pairs[n].wSecond] && selected[pairs[n].wFirst] && selected[pairs[n].wSecond] && pairs[n].iKernAmount/aa ) { if( fontDescFormat == 1 ) fprintf(f, " <kerning first=\"%d\" second=\"%d\" amount=\"%d\" />\r\n", pairs[n].wFirst, pairs[n].wSecond, pairs[n].iKernAmount/aa); else if( fontDescFormat == 0 ) fprintf(f, "kerning first=%-3d second=%-3d amount=%-4d\r\n", pairs[n].wFirst, pairs[n].wSecond, pairs[n].iKernAmount/aa); else { #pragma pack(push) #pragma pack(1) struct kerningBlock { DWORD first; DWORD second; short amount; } kerning; #pragma pack(pop) kerning.first = pairs[n].wFirst; kerning.second = pairs[n].wSecond; kerning.amount = pairs[n].iKernAmount/aa; fwrite(&kerning, sizeof(kerning), 1, f); } } } if( pairs.size() > 0 && fontDescFormat == 1 ) fprintf(f, " </kernings>\r\n"); if( fontDescFormat == 1 ) fprintf(f, "</font>\r\n"); fclose(f); SelectObject(dc, oldFont); DeleteObject(font); DeleteDC(dc); // Save the image file for( n = 0; n < (signed)pages.size(); n++ ) { string str = acStringFormat("%s_%0*d.%s", filename.c_str(), numDigits, n, textureFormat.c_str()); acImage::Image image; image.width = outWidth; image.height = outHeight; if( outBitDepth == 32 ) { image.pitch = image.width*4; image.format = acImage::PF_A8R8G8B8; } else { image.pitch = image.width; image.format = acImage::PF_A8; } image.data = new BYTE[image.pitch * image.height]; // Generate the output texture for saving pages[n]->GenerateOutputTexture(); cImage *page = pages[n]->GetPageImage(); if( outBitDepth == 8 ) { // Write image data for( int y = 0; y < outHeight; y++ ) { for( int x = 0; x < outWidth; x++ ) { DWORD pixel = page->pixels[y*outWidth + x]; image.data[y*image.pitch + x] = (BYTE)(pixel>>24); } } } else { // Write image data for( int y = 0; y < outHeight; y++ ) { for( int x = 0; x < outWidth; x++ ) { DWORD pixel = page->pixels[y*outWidth + x]; *(DWORD*)&image.data[y*image.pitch + x*4] = pixel; } } } if( textureFormat == "tga" ) acImage::SaveTga(str.c_str(), image); else if( textureFormat == "png" ) acImage::SavePng(str.c_str(), image); else if( textureFormat == "dds" ) acImage::SaveDds(str.c_str(), image, textureCompression); }
void nsLatin1Prober::DumpStatus() { printf(" Latin1Prober: %1.3f [%s]\r\n", GetConfidence(), GetCharSetName()); }
void nsSingleByteCharSetProber::DumpStatus() { printf(" SBCS: %1.3f [%s]\r\n", GetConfidence(), GetCharSetName()); }