⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 main.cpp

📁 bdf2bmf 在windML实现汉字的字符驱动,能够在液晶等显示界面上实现.
💻 CPP
字号:
/*
    bmfgen: Bitmapfont generator for the BMF_Font library.
    Copyright (C) 2003-2005  Trenkwalder Markus

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    Trenkwalder Markus
    trenki2@gmx.net
*/

#include "SDL.h"
#include "SDL_ttf.h"

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

/******************************************************************************/

#define PTSIZE(size) ((int)(size * (96.0/72.0)))
//#define PTSIZE(size) size


struct CmdLineArgs {
	string fontname;
	int ptsize;
	int texturesize;
	bool solid;
	bool grid;
	bool bmp;
	bool italic;
	bool underline;
	bool bold;
	
	bool useExtendedCharset;
};


/******************************************************************************/

int hostIsLittleEndian() {
	static union {
		unsigned short sh;
		char ch[2];
	} endian_test = { 0x0102 };
	
	return endian_test.ch[0] == 0x02;
}

Uint16 swap16(Uint16 D) {
	return hostIsLittleEndian() ? D : ((D<<8)|(D>>8));
}

Uint32 swap32(Uint32 D) {
	return hostIsLittleEndian() ? D : ((D<<24)|((D<<8)&0x00FF0000)|((D>>8)&0x0000FF00)|(D>>24));
}

/******************************************************************************/

void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
{
    int bpp = surface->format->BytesPerPixel;
    /* Here p is the address to the pixel we want to set */
    Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;

    switch(bpp) {
    case 1:
        *p = pixel;
        break;

    case 2:
        *(Uint16 *)p = pixel;
        break;

    case 3:
        if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
            p[0] = (pixel >> 16) & 0xff;
            p[1] = (pixel >> 8) & 0xff;
            p[2] = pixel & 0xff;
        } else {
            p[0] = pixel & 0xff;
            p[1] = (pixel >> 8) & 0xff;
            p[2] = (pixel >> 16) & 0xff;
        }
        break;

    case 4:
        *(Uint32 *)p = pixel;
        break;
    }
}

/******************************************************************************/

// Draws a yellow grid into the surface
void DrawGrid(SDL_Surface *surface) {
	int advance = surface->w / 16;
	Uint32 color = SDL_MapRGB( surface->format, 255, 255, 0 );
	for ( int x = 0; x < surface->w; x++ ) {
		for ( int y = 0; y < surface->h; y++ ) {
			if ( !(x % advance && y % advance) ) {
				putpixel( surface, x, y, color );
			}
		}
	}

}

/******************************************************************************/

bool GetArgs(int argc, char* argv[], CmdLineArgs* cmdargs) {

	if ( argc < 4 ) {
		cout << "Usage: bmfgen <font.ttf> <ptsize> <texture_size> [options]" << endl;
		cout << "Example: bmfgen verdana.ttf 12 256" << endl;
		cout << "Available options:" << endl;
		cout << " -i            Render italic text" << endl;
		cout << " -u            Render underlined text" << endl;
		cout << " -b            Render bold text" << endl;
		cout << " -solid        Render text without antialiasing" << endl;
		cout << " -grid         Draw a grid in the .bmp file" << endl;
		cout << " -bmp          Create a .bmp file" << endl;
		cout << " -ext-charset  Also ouput extended ASCII characters" << endl;
		return false;
	}

	cmdargs->fontname = argv[1];

	cmdargs->ptsize = atoi( argv[2] );
	if ( cmdargs->ptsize <= 0 || cmdargs->ptsize > 150 ) {
		cout << "point size must be within 1 and 150" << endl;
		return false;
	}

	cmdargs->texturesize = atoi( argv[3] );
	if ( cmdargs->texturesize < 128 || cmdargs->texturesize > 2048 ) {
		cout << "wrong parameter: texture size" << endl;
		return false;
	}

	int val = 1;
	while ( val < cmdargs->texturesize )
		val <<= 1;

	if ( val != cmdargs->texturesize ) {
		cout << "texture size is not a power of two" << endl;
		return false;
	}

	string option;
	
	cmdargs->solid = false;
	cmdargs->grid = false;
	cmdargs->bmp = false;
	cmdargs->italic = false;
	cmdargs->underline = false;
	cmdargs->bold = false;
	cmdargs->useExtendedCharset = false;

	for ( int i = 4; i < argc; i++ ) {
		option = argv[i];
		if ( option == "-solid" ) {
			cmdargs->solid = true;
		} else if ( option == "-grid" ) {
			cmdargs->grid = true;
		} else if ( option == "-bmp" ) {
			cmdargs->bmp = true;
		} else if ( option == "-i" ) {
			cmdargs->italic = true;
		} else if ( option == "-u" ) {
			cmdargs->underline = true;
		} else if ( option == "-b" ) {
			cmdargs->bold = true;
		} else if ( option == "-ext-charset" ) {
			cmdargs->useExtendedCharset = true;
		} else {
			cout << "wrong option: " << option << endl;
			return false;
		}
	}

	return true;
}

/******************************************************************************/

SDL_Rect CalculateBlitPos(TTF_Font *font, int ch, int texturesize) {

	string str;
	str += (unsigned char)ch;
	int w, h;

	TTF_SizeText(font, str.c_str(), &w, &h);

	int x = (ch - ' ')%16 * texturesize/16;
	int y = (ch - ' ')/16 * texturesize/16;

	x += texturesize/32 - w/2;
	y += texturesize/32 - h/2;

	SDL_Rect result = { x, y, w, h };

	return result;
}

/******************************************************************************/

SDL_Surface* CreateBMFSurface(TTF_Font* font, int texsize, bool solid, bool extAscii) {

	int texheight = extAscii ? texsize : texsize / 2;
	
	// Create the texture surface
	SDL_Surface *texture = SDL_CreateRGBSurface(
		SDL_SWSURFACE,
		texsize,
		texheight,
		24,
		0x000000ff,
		0x0000ff00,
		0x00ff0000,
		0x00000000
	);

	if ( texture == NULL ) {
		cout << "Error creating texture surface" << endl;
		return NULL;
	}

	int numChars = extAscii ? 256 : 128;
	
	// loop through all characters from 32 to 127
	for( int ch = 32; ch < numChars; ch++ ) {
		SDL_Color fg = { 255, 255, 255, 0 };
		char text[2] = { (char)ch, 0 };

		SDL_Surface *glyph;
		if ( solid ) {
			glyph = TTF_RenderText_Solid(font, text, fg);
		} else {
			glyph = TTF_RenderText_Blended(font, text, fg);
		}

		// Calculate the blit position
		SDL_Rect blitpos = CalculateBlitPos(font, ch, texsize);

		// Blit the glyph onto the texture surface
		SDL_BlitSurface(glyph, NULL, texture, &blitpos);
		SDL_FreeSurface(glyph);
	}

	return texture;
}




/******************************************************************************/

/*
 * Return the pixel value at (x, y)
 * NOTE: The surface must be locked before calling this!
 */
Uint32 getpixel(SDL_Surface *surface, int x, int y)
{
    int bpp = surface->format->BytesPerPixel;
    /* Here p is the address to the pixel we want to retrieve */
    Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;

    switch(bpp) {
    case 1:
        return *p;

    case 2:
        return *(Uint16 *)p;

    case 3:
        //if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
				if ( !hostIsLittleEndian() )
            return p[0] << 16 | p[1] << 8 | p[2];
        else
            return p[0] | p[1] << 8 | p[2] << 16;

    case 4:
        return *(Uint32 *)p;

    default:
        return 0;       /* shouldn't happen, but avoids warnings */
    }
}

/******************************************************************************/

int encode_rle(Uint8* dest, Uint8* src, int src_size) {

	int src_idx;
	int dest_idx = 0;

	Uint8 count = 0;
	Uint8 value = src[0];

	for ( src_idx = 0 ; src_idx < src_size; src_idx++ ) {
		if ( src[src_idx] == value && count < 0xFF ) {
			count++;
		} else {
			dest[dest_idx++] = count; count = 1;
			dest[dest_idx++] = value; value = src[src_idx];
		}
	}

	return dest_idx;
}

/******************************************************************************/

bool SaveAsBMF(SDL_Surface* texture, TTF_Font* font, int ptsize, const string& filename, bool extAscii) {

	#pragma pack(push,1)
	struct Header {
		Uint32 ident;
		Uint16 version;
	} header;

	struct FontMetrics {
		Uint8 ptsize;
		Uint8 style;
		Uint8 height;
		Uint8 ascent;
		Sint8 descent;
		Uint8 lineskip;
	} font_metrics;

	int gw_size = extAscii ? 224 : 96;
	Uint8 *glyph_width = new Uint8 [gw_size];
	
	#pragma pack(pop)


	header.ident = 0x20464D42;	// "BMF "
	header.version = extAscii ? 0x0101 : 0x0100;	// v1.01 for files with extended characters

	font_metrics.ptsize = ptsize;
	font_metrics.style  = TTF_GetFontStyle(font);
	font_metrics.height = TTF_FontHeight(font);
	font_metrics.ascent = TTF_FontAscent(font);
	font_metrics.descent = TTF_FontDescent(font);
	font_metrics.lineskip = TTF_FontLineSkip(font);

	int numChars = extAscii ? 256 : 128;
	
	for( int i = 32; i < numChars; i++ ) {
		int w, h;
		char text[2] = { (char)i, 0 };
		TTF_SizeText(font, text, &w, &h);

		glyph_width[i - 32] = w;
	}

	ofstream file(filename.c_str(), ios::out | ios::binary);

	if ( !file ) {
		delete [] glyph_width;
		return false;
	}

	// get the pixel data to be stored to disk
	int datacount = texture->w * (extAscii ? texture->w : texture->w/2);

	Uint8 *data = new Uint8[datacount];

	for ( int i = 0; i < datacount; i++ ) {
		Uint32 color = getpixel(texture, i % texture->w, i / texture->w);

		// since the texture is a grayscale image it is not important which color
		// component is stored
		data[i] = color & 0x000000FF;
	}

	// allocate memory to hold the rle compressed data
	// (datacount bytes should always be enough)
	Uint8* rle_data = new Uint8[datacount];

	// encode the image
	datacount = encode_rle(rle_data, data, datacount);

	// account for big endian machines: swap the bytes in shorts and ints
	header.ident = swap32(header.ident);
	header.version = swap16(header.version);
	
	file.write((char*)&header, sizeof(header));
	file.write((char*)&font_metrics, sizeof(font_metrics));
	file.write((char*)glyph_width, extAscii ? 224 : 96);

	int w = swap32(texture->w);
	file.write((char*)&w, sizeof(w));

	int dc = swap32(datacount);
	file.write((char*)&dc, sizeof(dc));
	
	file.write((char*)rle_data, datacount);

	delete [] glyph_width;
	delete [] data;
	delete [] rle_data;


	file.close();

	return true;
}

/******************************************************************************/

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

	CmdLineArgs cmdargs;

	// Check the command line arguments
	if ( !GetArgs(argc, argv, &cmdargs) ) {
		// print usage
		return 1;
	}

	// Initialize SDL and SDL_ttf
	TTF_Init();
	SDL_Init(SDL_INIT_VIDEO);

	// Not even needed to set a video mode
	//SDL_Surface *screen = SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE);


	// Load the font
	TTF_Font *font = TTF_OpenFont( cmdargs.fontname.c_str(), PTSIZE(cmdargs.ptsize));

	if ( !font ) {
		cout << "Error loading font" << endl;
		return 1;
	}

	// Set the font style
	{
		int style = 0;

		if ( cmdargs.bold )			style |= TTF_STYLE_BOLD;
		if ( cmdargs.italic )		style |= TTF_STYLE_ITALIC;
		if ( cmdargs.underline )	style |= TTF_STYLE_UNDERLINE;

		TTF_SetFontStyle(font, style);
	}

	// Create the texture surface
	SDL_Surface *texture = CreateBMFSurface(font, cmdargs.texturesize, cmdargs.solid, cmdargs.useExtendedCharset);

	// Save the generated texture as a .bmf file
	{
		string fname = cmdargs.fontname.substr(0, cmdargs.fontname.rfind('.')) + ".bmf";
		if ( !SaveAsBMF(texture, font, cmdargs.ptsize, fname, cmdargs.useExtendedCharset) ) {
			cout << "Error saving .bmf file" << endl;
		}
	}


	if ( cmdargs.grid ) {
	    DrawGrid(texture);
	}

	if ( cmdargs.bmp ) {
		string fname = cmdargs.fontname.substr(0, cmdargs.fontname.rfind('.')) + ".bmp";
		SDL_SaveBMP(texture, fname.c_str());
	}

	// clean up
	SDL_Quit();

	TTF_CloseFont(font);
	TTF_Quit();
}


⌨️ 快捷键说明

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