[links-list] TTF font rasterizer to use with links2
Sergey V. Karpov
karpov at sai.msu.su
Sun Nov 16 04:38:11 MST 2003
Hi all.
Due to frequent requests of ttf-to-png fonts rasterizer on this list I
decided to post source code of my solution for this problem. It is dirty
and a bit hackish, but sotetimes works as it has to ;-)
Source code of rasterizer.c attached. You may compile it by typing
something like this:
gcc rasterizer.c -o rasterizer -lgd -lfreetype -I/usr/include/freetype2
You need to have freetype2 and libgd
(http://www.boutell.com/gd/http/gd-2.0.15.tar.gz) installed.
Usage is very simple - ./rasterizer dump_all=1 fontfile.ttf
It will create ./tmp dir and place all available chars from your ttf in it
as properly named pngs.
Thanks,
Sergey
-------------- next part --------------
/*
Simple Unicode TTF rasterizer
(part of Hacked Links project)
Usage: ./rasterizer <options> font_file.ttf
Where options are:
height=120
transform_x=1
transform_y=1
blur_pix=1
blurs=1
dump_all=0
dump_first=0
dump_last=65535
it will create directory tmp/ and place char pngs to it
*/
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H
#include FT_TRUETYPE_TABLES_H
/* You need libGD to compile this! */
#include <gd.h>
#include <stdio.h>
#include <stdlib.h>
/* Dump to text files instead of PNG */
#undef TEXT
/* Pixmap size */
#define HEIGHT 120
/* Transformation coefficients */
#define TRANSFORM_X 1
#define TRANSFORM_Y 1
/* Additional smoothing */
#define BLUR_PIX 1
#define BLURS 1
/* Whether to dump all lower Unicode */
#define DUMP_ALL 0
int height=HEIGHT;
double transform_x=TRANSFORM_X;
double transform_y=TRANSFORM_Y;
int blur_pix=BLUR_PIX;
int blurs=BLURS;
int dump_all=DUMP_ALL;
int dump_first=0;
int dump_last=65535;
int pixel_height;
int baseline;
struct chars_to_dump {
int n1;
int n2;
};
/* UNICODE sets to rasterize, just comment out or add what you want */
struct chars_to_dump chars[]={
{ 0x0000,0x00ff }, /* Latin-1 */
{ 0x0100,0x024f }, /* Latin Extended */
{ 0x0250,0x02af }, /* IPA Extensions */
{ 0x02b0,0x036f }, /* Spacings and Diacritics */
{ 0x0370,0x0400 }, /* Greek */
{ 0x0401,0x052f }, /* Cyrillic */
{ 0x0590,0x05ff }, /* Hebrew */
{ 0x0600,0x06ff }, /* Arabic */
{ 0x1e00,0x06ff }, /* Latin extended additional */
{ 0x1f00,0x1fff }, /* Greek extended */
{ 0x2000,0x20ff }, /* Punctuations, sub/supscripts, currencies */
{ 0x2100,0x21ff }, /* misc. */
{ 0,0 }, /* Must be the last!!! */
};
void blur_x(int *buffer,int width, int height)
{
int x,y;
int *buf=(int*)malloc(width*height*sizeof(int));
for(y=0;y<height;y++)
for(x=0;x<width;x++){
int sum=0;
int xmin=(x-blur_pix>0)?(x-blur_pix):0;
int xmax=(x+blur_pix<width)?(x+blur_pix):width-1;
double k=1./(xmax-xmin+1);
int xxx;
for(xxx=xmin;xxx<=xmax;xxx++)
sum+=k*buffer[y*width+xxx];
buf[y*width+x]=sum;
}
memcpy(buffer,buf,sizeof(int)*width*height);
free(buf);
}
void blur_y(int *buffer,int width, int height)
{
int x,y;
int *buf=(int*)malloc(width*height*sizeof(int));
for(x=0;x<width;x++)
for(y=0;y<height;y++){
int sum=0;
int ymin=(y-blur_pix>0)?(y-blur_pix):0;
int ymax=(y+blur_pix<height)?(y+blur_pix):height-1;
double k=1./(ymax-ymin+1);
int yyy;
for(yyy=ymin;yyy<=ymax;yyy++)
sum+=k*buffer[yyy*width+x];
buf[y*width+x]=sum;
}
memcpy(buffer,buf,sizeof(int)*width*height);
free(buf);
}
void dump_bitmap(int ch,unsigned char *buffer, int width, int height, int x0, int y0, int cols, int rows)
{
char *filename=(char*)malloc(50);
int x,y,i;
int *bitmap=(int*)calloc(height*width,sizeof(int));
snprintf(filename,49,"tmp/%04x.png",ch);
printf(" -> %s\n",filename);
if(width>0 && !(ch!=32 && rows==0)) {
for(y=0;y<rows;y++){
for(x=0;x<cols;x++){
int l=y*cols+x;
int d=(y+y0)*width+x+x0;
if(buffer[l] && x+x0>0 && x+x0<width && y+y0>0 && y+y0<height)
bitmap[d]=buffer[l];
}
}
for(i=0;i<BLURS;i++){
blur_x(bitmap,width,height);
blur_y(bitmap,width,height);
}
#ifdef TEXT
{
FILE *f=fopen(filename,"w");
for(y=0;y<height;y++){
for(x=0;x<width;x++){
fprintf(f,"%d ",bitmap[y*width+x]);
}
fprintf(f,"\n");
}
fclose(f);
}
#else
{
gdImagePtr im=gdImageCreate(width,height);
FILE *f;
int *color=(int*)malloc(256*sizeof(int));
int d;
int x,y;
for(d=0;d<256;d++)
color[d]=gdImageColorAllocate(im,d,d,d);
for(y=0;y<height;y++)
for(x=0;x<width;x++)
gdImageSetPixel(im,x,y,color[bitmap[y*width+x]]);
f=fopen(filename,"wb");
gdImagePng(im,f);
fclose(f);
gdImageDestroy(im);
free(color);
}
#endif
}
free(filename);
free(bitmap);
}
void look_at_char(FT_Face face,int ch)
{
FT_GlyphSlot slot = face->glyph; // a small shortcut
int glyph = FT_Get_Char_Index( face, ch );
int width;
if(glyph==0) return;
printf("char %d -> glyph %d ",ch,glyph);
FT_Load_Char(face, ch, FT_LOAD_DEFAULT|FT_LOAD_RENDER|FT_LOAD_NO_HINTING);
width=slot->advance.x >> 6;
{
FT_GlyphSlot slot = face->glyph; // a small shortcut
FT_Bitmap bitmap=slot->bitmap;
int rows=bitmap.rows;
int pitch=bitmap.pitch;
int cols=bitmap.width;
int bitmap_top=slot->bitmap_top;
int bitmap_left=slot->bitmap_left;
int x0=bitmap_left;
int y0=baseline-bitmap_top;
int ngrays=bitmap.num_grays;
printf("%d %d, %d %d, %d %d, %d", width, height, cols, rows, x0, y0, ngrays);
dump_bitmap(ch,bitmap.buffer,width,height,x0,y0,cols,rows);
}
}
int main(int argc, char** argv)
{
FT_Library library;
FT_Face face;
char *filename=NULL;
int d;
int font_ascend;
int font_descend;
int font_height;
TT_HoriHeader *hhea;
if(FT_Init_FreeType( &library ))
return 1;
if(argc<2){
printf("Usage: %s <options> font_file\n",argv[0]);
printf("Where options are:\n");
printf("\theight=%d\n",height);
printf("\ttransform_x=%g\n",transform_x);
printf("\ttransform_y=%g\n",transform_y);
printf("\tblur_pix=%d\n",blur_pix);
printf("\tblurs=%d\n",blurs);
printf("\tdump_all=%d\n",dump_all);
printf("\tdump_first=%d\n",dump_first);
printf("\tdump_last=%d\n",dump_last);
return 1;
}
for(d=1;d<argc;d++)
if(!strncmp(argv[d],"height=",7))
sscanf(argv[d],"height=%d",&height);
else if(!strncmp(argv[d],"transform_x=",12))
sscanf(argv[d],"transform_x=%lf",&transform_x);
else if(!strncmp(argv[d],"transform_y=",12))
sscanf(argv[d],"transform_y=%lf",&transform_x);
else if(!strncmp(argv[d],"blur_pix=",9))
sscanf(argv[d],"blur_pix=%d",&blur_pix);
else if(!strncmp(argv[d],"blurs=",6))
sscanf(argv[d],"blurs=%d",&blurs);
else if(!strncmp(argv[d],"dump_all=",9))
sscanf(argv[d],"dump_all=%d",&dump_all);
else if(!strncmp(argv[d],"dump_first=",11))
sscanf(argv[d],"dump_first=%d",&dump_first);
else if(!strncmp(argv[d],"dump_last=",10))
sscanf(argv[d],"dump_last=%d",&dump_last);
else
filename=argv[d];
if(!filename)
return 1;
printf("Trying %s\n",filename);
if(FT_New_Face(library, filename,0,&face))
return;
printf("Ok, %s, %s\n",face->family_name,face->style_name);
hhea = FT_Get_Sfnt_Table(face, ft_sfnt_hhea);
font_ascend = face->ascender;
font_descend = face->descender;
font_height = face->height;
/* Quick fix for freetype 2.1.5 un-handling of zero line_gap */
if(font_height == font_ascend - font_descend)
font_height *= 1.15;
printf("Ascend %d, descend %d, height %d\n",font_ascend,font_descend,font_height);
printf("Vertical BBox is %d - %d\n",face->bbox.yMin,face->bbox.yMax);
pixel_height=(double)height*(font_ascend-font_descend)/(double)font_height;
baseline=(double)height*(font_height+font_descend)/(double)font_height;
printf("Our baseline will be at %d\n",baseline);
FT_Set_Pixel_Sizes(face,0,pixel_height);
{
FT_Matrix matrix; // transformation matrix
FT_Vector origin;
matrix.xx=(FT_Fixed)(transform_x*0x10000);
matrix.xy=0;
matrix.yx=0;
matrix.yy=(FT_Fixed)(transform_y*0x10000);
origin.x=0;
origin.y=0;
FT_Set_Transform(face,&matrix,&origin);
}
system("rm -rf tmp");
system("mkdir tmp");
if(dump_all){
/* Dumping all lower Unicode */
printf("Dumping all available UNICODE range...\n");
for(d=dump_first;d<=dump_last;d++)
look_at_char(face,d);
}
else {
d=0;
while(chars[d].n2){
int ch;
int n1=chars[d].n1;
int n2=chars[d].n2;
printf("Processing UNICODE chars from %d till %d...\n",n1,n2);
for(ch=n1;ch<=n2;ch++)
look_at_char(face,ch);
d++;
}
}
return 1;
}
More information about the links-list
mailing list