📄 ftstring.c
字号:
/****************************************************************************/
/* */
/* The FreeType project -- a free and portable quality TrueType renderer. */
/* */
/* Copyright 1996-2002, 2003, 2004 by */
/* D. Turner, R.Wilhelm, and W. Lemberg */
/* */
/* */
/* ftstring.c - simple text string display */
/* */
/****************************************************************************/
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H
#include "common.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <math.h>
#include "graph.h"
#include "grfont.h"
#define DIM_X 500
#define DIM_Y 400
#define CENTER_X ( bit.width / 2 )
#define CENTER_Y ( bit.rows / 2 )
#define MAXPTSIZE 500 /* dtp */
static char Header[128];
static char* new_header = 0;
static char* Text = (char *)"The quick brown fox jumps over the lazy dog";
static FT_Library library; /* the FreeType library */
static FT_Face face; /* the font face */
static FT_Error error; /* error returned by FreeType? */
static FT_Encoding encoding = FT_ENCODING_UNICODE;
static grSurface* surface; /* current display surface */
static grBitmap bit; /* current display bitmap */
static int ptsize; /* current point size */
static int Num;
static int Rotation = 0;
static int Fail;
static int hinted = 1; /* is glyph hinting active? */
static int antialias = 1; /* is anti-aliasing active? */
static int use_sbits = 0; /* do we use embedded bitmaps? */
static int kerning = 2; /* 0: no kerning; */
/* 1: `kern' values */
/* 2: `kern' + side bearing errors */
static int autohint = 0; /* is forced hinting active? */
static int use_gamma = 0;
static int res = 72; /* default resolution in dpi */
static grColor fore_color = { 255 };
static int graph_init = 0;
static FT_Matrix trans_matrix;
static int transform = 0;
static FT_Vector string_center;
typedef struct TGlyph_
{
FT_UInt glyph_index; /* glyph index in face */
FT_Vector pos; /* position of glyph origin */
FT_Glyph image; /* glyph image */
} TGlyph, *PGlyph;
#define FLOOR( x ) ( (x) & -64 )
#define CEIL( x ) ( ( (x) + 63 ) & -64 )
#define TRUNC ( x) ( (x) >> 6 )
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
/**** ****/
/**** U T I L I T Y F U N C T I O N S ****/
/**** ****/
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
#define DEBUGxxx
#ifdef DEBUG
#define LOG( x ) LogMessage##x
#else
#define LOG( x ) /* empty */
#endif
#ifdef DEBUG
static void
LogMessage( const char* fmt, ... )
{
va_list ap;
va_start( ap, fmt );
vfprintf( stderr, fmt, ap );
va_end( ap );
}
#endif
/* PanicZ */
static void
PanicZ( const char* message )
{
fprintf( stderr, "%s\n error = 0x%04x\n", message, error );
exit( 1 );
}
static unsigned long
make_tag( char *s )
{
int i;
unsigned long l = 0;
for ( i = 0; i < 4; i++ )
{
if ( !s[i] )
break;
l <<= 8;
l += (unsigned long)s[i];
}
return l;
}
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
/**** ****/
/**** D I S P L A Y M A N A G E M E N T ****/
/**** ****/
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
#define MAX_GLYPHS 512
/*************************************************************************/
/* */
/* The following arrays are used to store the glyph set that makes */
/* up a string of text. */
/* */
/* */
static TGlyph glyphs[MAX_GLYPHS];
static int num_glyphs;
/*************************************************************************/
/* */
/* Gamma correction. */
/* */
/* */
static double gamma_value = 2.0f;
static FT_Byte gamma_ramp[256];
static void
init_gamma( void )
{
int i;
double gamma_inv = 1.0f / gamma_value;
for (i = 0; i < 256; i++)
gamma_ramp[i] = (FT_Byte)( pow((double)i / 255.0f, gamma_inv) * 255.0f );
}
static void
apply_gamma( grBitmap* bmp )
{
int i, j;
FT_Byte* buffer = (FT_Byte*) bmp->buffer;
for (i = 0; i < bmp->rows; i++)
{
for (j = 0; j < bmp->width; j++)
buffer[j] = (FT_Byte) gamma_ramp[buffer[j]];
buffer += bmp->pitch;
}
}
static void
draw_gamma_ramp( void )
{
int i, x, y;
long pitch = bit.pitch;
long start = 0;
if ( pitch < 0 )
start = -pitch*(bit.rows-1);
x = (bit.width - 256) / 2;
y = (bit.rows + 256) / 2;
for (i = 0; i < 256; i++, x++)
{
bit.buffer[start + pitch*(y - gamma_ramp[i]) + x ] = 80;
}
}
/*************************************************************************/
/* */
/* Initialize the display surface. */
/* */
/* */
static int
init_display( void )
{
grInitDevices();
bit.mode = gr_pixel_mode_gray;
bit.width = DIM_X;
bit.rows = DIM_Y;
bit.grays = 256;
surface = grNewSurface( 0, &bit );
if ( !surface )
PanicZ( "could not allocate display surface\n" );
graph_init = 1;
return 0;
}
/*************************************************************************/
/* */
/* Clear the display surface. */
/* */
/* */
static void
clear_display( void )
{
long size = (long)bit.pitch * bit.rows;
if ( size < 0 )
size = -size;
memset( bit.buffer, 0, size );
}
static void
reset_scale( int pointSize )
{
(void)FT_Set_Char_Size( face,
pointSize << 6,
pointSize << 6,
res,
res );
}
/*************************************************************************/
/* */
/* Layout a string of glyphs. The glyphs are untransformed. */
/* */
/* */
static void
layout_glyphs( void )
{
PGlyph glyph = glyphs;
int n;
FT_Vector origin;
FT_Pos origin_x = 0;
FT_UInt load_flags;
FT_UInt prev_index = 0;
FT_Pos prev_rsb_delta = 0;
load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
if ( !hinted )
load_flags |= FT_LOAD_NO_HINTING;
if ( !use_sbits )
load_flags |= FT_LOAD_NO_BITMAP;
if ( autohint )
load_flags |= FT_LOAD_FORCE_AUTOHINT;
for ( n = 0; n < num_glyphs; n++, glyph++ )
{
/* compute glyph origin */
if ( kerning )
{
if ( prev_index )
{
FT_Vector kern;
FT_Get_Kerning( face, prev_index, glyph->glyph_index,
hinted ? FT_KERNING_DEFAULT : FT_KERNING_UNFITTED,
&kern );
origin_x += kern.x;
}
prev_index = glyph->glyph_index;
}
/* clear existing image if there is one */
if ( glyph->image )
FT_Done_Glyph( glyph->image );
/* load the glyph image (in its native format) */
error = FT_Load_Glyph( face, glyph->glyph_index, load_flags );
if ( error )
continue;
if ( n && kerning > 1 )
{
if ( prev_rsb_delta - face->glyph->lsb_delta >= 32 )
origin_x -= 64;
else if ( prev_rsb_delta - face->glyph->lsb_delta < -32 )
origin_x += 64;
}
origin.x = origin_x;
origin.y = 0;
prev_rsb_delta = face->glyph->rsb_delta;
error = FT_Get_Glyph( face->glyph, &glyph->image );
if ( error )
continue;
glyph->pos = origin;
origin_x += face->glyph->advance.x;
}
string_center.x = ( origin_x / 2 ) & -64;
string_center.y = 0;
if ( transform && FT_IS_SCALABLE( face ) )
FT_Vector_Transform( &string_center, &trans_matrix );
}
/*************************************************************************/
/* */
/* Render a given glyph vector set. */
/* */
/* */
static void
render_string( FT_Pos x, FT_Pos y )
{
PGlyph glyph = glyphs;
grBitmap bit3;
int n;
FT_Vector delta;
/* first of all, we must compute the general delta for the glyph set */
delta.x = ( x << 6 ) - string_center.x;
delta.y = ( ( bit.rows - y ) << 6 ) - string_center.y;
for ( n = 0; n < num_glyphs; n++, glyph++ )
{
FT_Glyph image;
FT_Vector vec;
if ( !glyph->image )
continue;
/* copy image */
error = FT_Glyph_Copy( glyph->image, &image );
if ( error )
continue;
/* transform it */
vec = glyph->pos;
if ( FT_IS_SCALABLE( face ) )
FT_Vector_Transform( &vec, &trans_matrix );
vec.x += delta.x;
vec.y += delta.y;
if ( FT_IS_SCALABLE( face ) )
error = FT_Glyph_Transform( image, &trans_matrix, &vec );
if ( !error )
{
FT_BBox bbox;
/* check bounding box; if it is not within the display surface, */
/* we don't need to render it */
FT_Glyph_Get_CBox( image, FT_GLYPH_BBOX_PIXELS, &bbox );
if ( !FT_IS_SCALABLE( face ) )
{
vec.x = vec.x >> 6;
vec.y = vec.y >> 6;
bbox.xMin += vec.x;
bbox.xMax += vec.x;
bbox.yMin += vec.y;
bbox.yMax += vec.y;
}
#if 0
if ( n == 0 )
{
fprintf( stderr, "bbox = [%ld %ld %ld %ld]\n",
bbox.xMin, bbox.yMin, bbox.xMax, bbox.yMax );
}
#endif
if ( bbox.xMax > 0 && bbox.yMax > 0 &&
bbox.xMin < bit.width && bbox.yMin < bit.rows )
{
/* convert to a bitmap -- destroy native image */
error = FT_Glyph_To_Bitmap( &image,
antialias ? FT_RENDER_MODE_NORMAL
: FT_RENDER_MODE_MONO,
0, 1 );
if ( !error )
{
FT_BitmapGlyph bitmap = (FT_BitmapGlyph)image;
FT_Bitmap* source = &bitmap->bitmap;
FT_Pos x_top, y_top;
#if 0
if ( n == 0 )
{
fprintf( stderr, "bearing = [%d %d] dims = [%d %d]\n",
bitmap->left, bitmap->top, source->width, source->rows );
}
#endif
bit3.rows = source->rows;
bit3.width = source->width;
bit3.pitch = source->pitch;
bit3.buffer = source->buffer;
switch ( source->pixel_mode )
{
case FT_PIXEL_MODE_MONO:
bit3.mode = gr_pixel_mode_mono;
break;
case FT_PIXEL_MODE_GRAY:
bit3.mode = gr_pixel_mode_gray;
bit3.grays = source->num_grays;
if (use_gamma)
apply_gamma(&bit3);
break;
default:
continue;
}
/* now render the bitmap into the display surface */
if ( FT_IS_SCALABLE( face ) )
{
x_top = bitmap->left;
y_top = bit.rows - bitmap->top;
}
else
{
x_top = vec.x - bitmap->left;
y_top = vec.y - bitmap->top;
}
grBlitGlyphToBitmap( &bit, &bit3, x_top, y_top, fore_color );
}
}
}
FT_Done_Glyph( image );
}
}
/*************************************************************************/
/* */
/* Convert a string of text into a glyph vector. */
/* */
/* XXX: For now, we perform a trivial conversion. */
/* */
/* */
static void
prepare_text( const unsigned char* string )
{
const unsigned char* p = (const unsigned char*)string;
PGlyph glyph = glyphs;
FT_UInt glyph_index;
unsigned char in_code;
unsigned long codepoint = 0;
int expect;
if ( encoding )
{
error = FT_Select_Charmap( face, encoding );
if ( error )
PanicZ( "invalid charmap\n" );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -