📄 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 + -