-#include "image.h"
+#include "imager.h"
+#include "imrender.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
+#ifdef HAVE_LIBT1
+#include <t1lib.h>
+#endif
+
+
/*
=head1 NAME
mm_log((1,"Initializing fonts\n"));
#ifdef HAVE_LIBT1
- i_init_t1(t1log);
-#endif
-
-#ifdef HAVE_LIBTT
- i_init_tt();
-#endif
-
-#ifdef HAVE_FT2
- if (!i_ft2_init())
+ if (i_init_t1(t1log))
return 0;
#endif
-
+
return(1); /* FIXME: Always true - check the return values of the init_t1 and init_tt functions */
}
#ifdef HAVE_LIBT1
static int t1_get_flags(char const *flags);
-static char *t1_from_utf8(char const *in, int len, int *outlen);
+static char *t1_from_utf8(char const *in, size_t len, int *outlen);
static void t1_push_error(void);
+static int t1_active_fonts = 0;
+static int t1_initialized = 0;
+
/*
=item i_init_t1(t1log)
i_init_t1(int t1log) {
int init_flags = IGNORE_CONFIGFILE|IGNORE_FONTDATABASE;
mm_log((1,"init_t1()\n"));
+
+ i_clear_error();
+
+ if (t1_active_fonts) {
+ mm_log((1, "Cannot re-initialize T1 - active fonts\n"));
+ i_push_error(0, "Cannot re-initialize T1 - active fonts");
+ return 1;
+ }
+
+ if (t1_initialized) {
+ T1_CloseLib();
+ }
if (t1log)
init_flags |= LOGFILE;
if ((T1_InitLib(init_flags) == NULL)){
mm_log((1,"Initialization of t1lib failed\n"));
+ i_push_error(0, "T1_InitLib failed");
return(1);
}
T1_SetLogLevel(T1LOG_DEBUG);
i_t1_set_aa(1); /* Default Antialias value */
+
+ ++t1_initialized;
+
return(0);
}
void
i_close_t1(void) {
T1_CloseLib();
+ t1_initialized = 0;
}
i_t1_new(char *pfb,char *afm) {
int font_id;
+ i_clear_error();
+
+ if (!t1_initialized && i_init_t1(0))
+ return -1;
+
mm_log((1,"i_t1_new(pfb %s,afm %s)\n",pfb,(afm?afm:"NULL")));
font_id = T1_AddFont(pfb);
if (font_id<0) {
if (T1_SetAfmFileName(font_id,afm)<0) mm_log((1,"i_t1_new: afm loading of '%s' failed.\n",afm));
}
+ ++t1_active_fonts;
+
return font_id;
}
int
i_t1_destroy(int font_id) {
mm_log((1,"i_t1_destroy(font_id %d)\n",font_id));
+
+ --t1_active_fonts;
+
return T1_DeleteFont(font_id);
}
*/
undef_int
-i_t1_cp(i_img *im,int xb,int yb,int channel,int fontnum,float points,char* str,int len,int align, int utf8, char const *flags) {
+i_t1_cp(i_img *im,int xb,int yb,int channel,int fontnum,float points,char* str,size_t len,int align, int utf8, char const *flags) {
GLYPH *glyph;
int xsize,ysize,x,y;
i_color val;
return 1;
}
+static void
+t1_fix_bbox(BBox *bbox, const char *str, size_t len, int advance,
+ int space_position) {
+ /* never called with len == 0 */
+ if (str[0] == space_position && bbox->llx > 0)
+ bbox->llx = 0;
+ if (str[len-1] == space_position && bbox->urx < advance)
+ bbox->urx = advance;
+ if (bbox->lly > bbox->ury)
+ bbox->lly = bbox->ury = 0;
+}
/*
=item i_t1_bbox(handle, fontnum, points, str, len, cords)
*/
int
-i_t1_bbox(int fontnum,float points,char *str,int len,int cords[6], int utf8,char const *flags) {
+i_t1_bbox(int fontnum,float points,const char *str,size_t len,int cords[6], int utf8,char const *flags) {
BBox bbox;
BBox gbbox;
int mod_flags = t1_get_flags(flags);
int advance;
+ int space_position = T1_GetEncodingIndex(fontnum, "space");
mm_log((1,"i_t1_bbox(fontnum %d,points %.2f,str '%.*s', len %d)\n",fontnum,points,len,str,len));
T1_LoadFont(fontnum); /* FIXME: Here a return code is ignored - haw haw haw */
- if (utf8) {
- int worklen;
- char *work = t1_from_utf8(str, len, &worklen);
- bbox = T1_GetStringBBox(fontnum,work,worklen,0,mod_flags);
- myfree(work);
+
+ if (len == 0) {
+ /* len == 0 has special meaning to T1lib, but it means there's
+ nothing to draw, so return that */
+ bbox.llx = bbox.lly = bbox.urx = bbox.ury = 0;
+ advance = 0;
}
else {
- bbox = T1_GetStringBBox(fontnum,str,len,0,mod_flags);
+ if (utf8) {
+ int worklen;
+ char *work = t1_from_utf8(str, len, &worklen);
+ advance = T1_GetStringWidth(fontnum, work, worklen, 0, mod_flags);
+ bbox = T1_GetStringBBox(fontnum,work,worklen,0,mod_flags);
+ t1_fix_bbox(&bbox, work, worklen, advance, space_position);
+ myfree(work);
+ }
+ else {
+ advance = T1_GetStringWidth(fontnum, (char *)str, len, 0, mod_flags);
+ bbox = T1_GetStringBBox(fontnum,(char *)str,len,0,mod_flags);
+ t1_fix_bbox(&bbox, str, len, advance, space_position);
+ }
}
gbbox = T1_GetFontBBox(fontnum);
- advance = T1_GetStringWidth(fontnum, str, len, 0, mod_flags);
mm_log((1,"bbox: (%d,%d,%d,%d)\n",
(int)(bbox.llx*points/1000),
*/
undef_int
-i_t1_text(i_img *im,int xb,int yb,i_color *cl,int fontnum,float points,char* str,int len,int align, int utf8, char const *flags) {
+i_t1_text(i_img *im,int xb,int yb,const i_color *cl,int fontnum,float points,const char* str,size_t len,int align, int utf8, char const *flags) {
GLYPH *glyph;
- int xsize,ysize,x,y,ch;
- i_color val;
- unsigned char c,i;
+ int xsize,ysize,y;
int mod_flags = t1_get_flags(flags);
+ i_render r;
if (im == NULL) { mm_log((1,"i_t1_cp: Null image in input\n")); return(0); }
myfree(work);
}
else {
- glyph=T1_AASetString( fontnum, str, len, 0, mod_flags, points, NULL);
+ /* T1_AASetString() accepts a char * not a const char */
+ glyph=T1_AASetString( fontnum, (char *)str, len, 0, mod_flags, points, NULL);
}
if (glyph == NULL)
return 0;
mm_log((1,"width: %d height: %d\n",xsize,ysize));
if (align==1) { xb+=glyph->metrics.leftSideBearing; yb-=glyph->metrics.ascent; }
-
- for(y=0;y<ysize;y++) for(x=0;x<xsize;x++) {
- c=glyph->bits[y*xsize+x];
- i=255-c;
- i_gpix(im,x+xb,y+yb,&val);
- for(ch=0;ch<im->channels;ch++) val.channel[ch]=(c*cl->channel[ch]+i*val.channel[ch])/255;
- i_ppix(im,x+xb,y+yb,&val);
+
+ i_render_init(&r, im, xsize);
+ for(y=0;y<ysize;y++) {
+ i_render_color(&r, xb, yb+y, xsize, (unsigned char *)glyph->bits+y*xsize, cl);
}
+ i_render_done(&r);
+
return 1;
}
}
/*
-=item t1_from_utf8(char const *in, int len, int *outlen)
+=item t1_from_utf8(char const *in, size_t len, int *outlen)
Produces an unencoded version of I<in> by dropping any Unicode
character over 255.
*/
static char *
-t1_from_utf8(char const *in, int len, int *outlen) {
- char *out = mymalloc(len+1);
+t1_from_utf8(char const *in, size_t len, int *outlen) {
+ /* at this point len is from a perl SV, so can't approach MAXINT */
+ char *out = mymalloc(len+1); /* checked 5Nov05 tonyc */
char *p = out;
unsigned long c;
*/
int
-i_t1_has_chars(int font_num, const char *text, int len, int utf8,
+i_t1_has_chars(int font_num, const char *text, size_t len, int utf8,
char *out) {
int count = 0;
/* Truetype font support */
#ifdef HAVE_LIBTT
-/* This is enabled by default when configuring Freetype 1.x
+/* These are enabled by default when configuring Freetype 1.x
I haven't a clue how to reliably detect it at compile time.
We need a compilation probe in Makefile.PL
*/
#define FTXPOST 1
+#define FTXERR18 1
#include <freetype.h>
#define TT_CHC 5
#include <ftxpost.h>
#endif
+#ifdef FTXERR18
+#include <ftxerr18.h>
+#endif
+
/* some versions of FT1.x don't seem to define this - it's font defined
so it won't change */
#ifndef TT_MS_LANGID_ENGLISH_GENERAL
#define USTRCT(x) ((x).z)
#define TT_VALID( handle ) ( ( handle ).z != NULL )
+static void i_tt_push_error(TT_Error rc);
/* Prototypes */
static int
i_tt_render_all_glyphs( TT_Fonthandle *handle, int inst, TT_Raster_Map *bit,
TT_Raster_Map *small_bit, int cords[6],
- char const* txt, int len, int smooth, int utf8 );
-static void i_tt_dump_raster_map2( i_img* im, TT_Raster_Map* bit, int xb, int yb, i_color *cl, int smooth );
+ char const* txt, size_t len, int smooth, int utf8 );
+static void i_tt_dump_raster_map2( i_img* im, TT_Raster_Map* bit, int xb, int yb, const i_color *cl, int smooth );
static void i_tt_dump_raster_map_channel( i_img* im, TT_Raster_Map* bit, int xb, int yb, int channel, int smooth );
static int
i_tt_rasterize( TT_Fonthandle *handle, TT_Raster_Map *bit, int cords[6],
- float points, char const* txt, int len, int smooth, int utf8 );
-static undef_int i_tt_bbox_inst( TT_Fonthandle *handle, int inst ,const char *txt, int len, int cords[6], int utf8 );
+ float points, char const* txt, size_t len, int smooth, int utf8 );
+static undef_int i_tt_bbox_inst( TT_Fonthandle *handle, int inst ,const char *txt, size_t len, int cords[6], int utf8 );
/* static globals needed */
+static int TT_initialized = 0;
static TT_Engine engine;
static int LTT_dpi = 72; /* FIXME: this ought to be a part of the call interface */
static int LTT_hinted = 1; /* FIXME: this too */
*/
undef_int
-i_init_tt() {
+i_init_tt(void) {
TT_Error error;
+ TT_Byte palette[] = { 0, 64, 127, 191, 255 };
+
+ i_clear_error();
+
mm_log((1,"init_tt()\n"));
error = TT_Init_FreeType( &engine );
if ( error ){
mm_log((1,"Initialization of freetype failed, code = 0x%x\n",error));
+ i_tt_push_error(error);
+ i_push_error(0, "Could not initialize freetype 1.x");
return(1);
}
error = TT_Init_Post_Extension( engine );
if (error) {
mm_log((1, "Initialization of Post extension failed = 0x%x\n", error));
+
+ i_tt_push_error(error);
+ i_push_error(0, "Could not initialize FT 1.x POST extension");
return 1;
}
#endif
+ error = TT_Set_Raster_Gray_Palette(engine, palette);
+ if (error) {
+ mm_log((1, "Initialization of gray levels failed = 0x%x\n", error));
+ i_tt_push_error(error);
+ i_push_error(0, "Could not initialize FT 1.x POST extension");
+ return 1;
+ }
+
+ TT_initialized = 1;
+
return(0);
}
*/
TT_Fonthandle*
-i_tt_new(char *fontname) {
+i_tt_new(const char *fontname) {
TT_Error error;
TT_Fonthandle *handle;
unsigned short i,n;
unsigned short platform,encoding;
+
+ if (!TT_initialized && i_init_tt()) {
+ i_push_error(0, "Could not initialize FT1 engine");
+ return NULL;
+ }
+
+ i_clear_error();
mm_log((1,"i_tt_new(fontname '%s')\n",fontname));
/* allocate memory for the structure */
- handle = mymalloc( sizeof(TT_Fonthandle) );
+ handle = mymalloc( sizeof(TT_Fonthandle) ); /* checked 5Nov05 tonyc */
/* load the typeface */
error = TT_Open_Face( engine, fontname, &handle->face );
mm_log((1, "Error while opening %s, error code = 0x%x.\n",fontname,
error ));
}
+ i_tt_push_error(error);
return NULL;
}
bit->cols = ( bit->width + 7 ) / 8; /* convert to # of bytes */
bit->size = bit->rows * bit->cols; /* number of bytes in buffer */
}
+
+ /* rows can be 0 for some glyphs, for example ' ' */
+ if (bit->rows && bit->size / bit->rows != bit->cols) {
+ i_fatal(0, "Integer overflow calculating bitmap size (%d, %d)\n",
+ bit->width, bit->rows);
+ }
mm_log((1,"i_tt_init_raster_map: bit->width %d, bit->cols %d, bit->rows %d, bit->size %d)\n", bit->width, bit->cols, bit->rows, bit->size ));
- bit->bitmap = (void *) mymalloc( bit->size );
- if ( !bit->bitmap ) m_fatal(0,"Not enough memory to allocate bitmap (%d)!\n",bit->size );
+ bit->bitmap = (void *) mymalloc( bit->size ); /* checked 6Nov05 tonyc */
+ if ( !bit->bitmap ) i_fatal(0,"Not enough memory to allocate bitmap (%d)!\n",bit->size );
}
i_tt_blit_or( TT_Raster_Map *dst, TT_Raster_Map *src,int x_off, int y_off ) {
int x, y;
int x1, x2, y1, y2;
- char *s, *d;
+ unsigned char *s, *d;
x1 = x_off < 0 ? -x_off : 0;
y1 = y_off < 0 ? -y_off : 0;
/* do the real work now */
for ( y = y1; y < y2; ++y ) {
- s = ( (char*)src->bitmap ) + y * src->cols + x1;
- d = ( (char*)dst->bitmap ) + ( y + y_off ) * dst->cols + x1 + x_off;
+ s = ( (unsigned char*)src->bitmap ) + y * src->cols + x1;
+ d = ( (unsigned char*)dst->bitmap ) + ( y + y_off ) * dst->cols + x1 + x_off;
for ( x = x1; x < x2; ++x ) {
if (*s > *d)
*/
int
-i_tt_has_chars(TT_Fonthandle *handle, char const *text, int len, int utf8,
+i_tt_has_chars(TT_Fonthandle *handle, char const *text, size_t len, int utf8,
char *out) {
int count = 0;
mm_log((1, "i_tt_has_chars(handle %p, text %p, len %d, utf8 %d)\n",
int
i_tt_render_all_glyphs( TT_Fonthandle *handle, int inst, TT_Raster_Map *bit,
TT_Raster_Map *small_bit, int cords[6],
- char const* txt, int len, int smooth, int utf8 ) {
+ char const* txt, size_t len, int smooth, int utf8 ) {
unsigned long j;
TT_F26Dot6 x,y;
static
void
-i_tt_dump_raster_map2( i_img* im, TT_Raster_Map* bit, int xb, int yb, i_color *cl, int smooth ) {
- char *bmap;
- i_color val;
- int c, i, ch, x, y;
+i_tt_dump_raster_map2( i_img* im, TT_Raster_Map* bit, int xb, int yb, const i_color *cl, int smooth ) {
+ unsigned char *bmap;
+ int x, y;
mm_log((1,"i_tt_dump_raster_map2(im 0x%x, bit 0x%X, xb %d, yb %d, cl 0x%X)\n",im,bit,xb,yb,cl));
- bmap = (char *)bit->bitmap;
+ bmap = bit->bitmap;
if ( smooth ) {
- for(y=0;y<bit->rows;y++) for(x=0;x<bit->width;x++) {
- c=(255*bmap[y*(bit->cols)+x])/4;
- i=255-c;
- i_gpix(im,x+xb,y+yb,&val);
- for(ch=0;ch<im->channels;ch++) val.channel[ch]=(c*cl->channel[ch]+i*val.channel[ch])/255;
- i_ppix(im,x+xb,y+yb,&val);
+ i_render r;
+ i_render_init(&r, im, bit->cols);
+ for(y=0;y<bit->rows;y++) {
+#if 0
+ for(x=0;x<bit->width;x++) {
+ c = (unsigned char)bmap[y*(bit->cols)+x];
+ i=255-c;
+ i_gpix(im,x+xb,y+yb,&val);
+ for(ch=0;ch<im->channels;ch++)
+ val.channel[ch] = (c*cl->channel[ch]+i*val.channel[ch])/255;
+ i_ppix(im,x+xb,y+yb,&val);
+ }
+#else
+ i_render_color(&r, xb, yb+y, bit->cols, bmap + y*bit->cols, cl);
+#endif
}
-
+ i_render_done(&r);
} else {
-
- for(y=0;y<bit->rows;y++) for(x=0;x<bit->width;x++) {
- c=( bmap[y*bit->cols+x/8] & (128>>(x%8)) ) ? 255 : 0;
- i=255-c;
- i_gpix(im,x+xb,y+yb,&val);
- for(ch=0;ch<im->channels;ch++) val.channel[ch]=(c*cl->channel[ch]+i*val.channel[ch])/255;
- i_ppix(im,x+xb,y+yb,&val);
+ for(y=0;y<bit->rows;y++) {
+ unsigned mask = 0x80;
+ unsigned char *p = bmap + y * bit->cols;
+
+ for(x = 0; x < bit->width; x++) {
+ if (*p & mask) {
+ i_ppix(im, x+xb, y+yb, cl);
+ }
+ mask >>= 1;
+ if (!mask) {
+ mask = 0x80;
+ ++p;
+ }
+ }
}
}
static
void
i_tt_dump_raster_map_channel( i_img* im, TT_Raster_Map* bit, int xb, int yb, int channel, int smooth ) {
- char *bmap;
+ unsigned char *bmap;
i_color val;
int c,x,y;
+ int old_mask = im->ch_mask;
+ im->ch_mask = 1 << channel;
mm_log((1,"i_tt_dump_raster_channel(im 0x%x, bit 0x%X, xb %d, yb %d, channel %d)\n",im,bit,xb,yb,channel));
- bmap = (char *)bit->bitmap;
+ bmap = bit->bitmap;
if ( smooth ) {
for(y=0;y<bit->rows;y++) for(x=0;x<bit->width;x++) {
- c=(255*bmap[y*(bit->cols)+x])/4;
- i_gpix(im,x+xb,y+yb,&val);
- val.channel[channel]=c;
+ c = bmap[y*(bit->cols)+x];
+ val.channel[channel] = c;
i_ppix(im,x+xb,y+yb,&val);
}
} else {
- for(y=0;y<bit->rows;y++) for(x=0;x<bit->width;x++) {
- c=( bmap[y*bit->cols+x/8] & (128>>(x%8)) ) ? 255 : 0;
- i_gpix(im,x+xb,y+yb,&val);
- val.channel[channel]=c;
- i_ppix(im,x+xb,y+yb,&val);
+ for(y=0;y<bit->rows;y++) {
+ unsigned mask = 0x80;
+ unsigned char *p = bmap + y * bit->cols;
+
+ for(x=0;x<bit->width;x++) {
+ val.channel[channel] = (*p & mask) ? 255 : 0;
+ i_ppix(im,x+xb,y+yb,&val);
+
+ mask >>= 1;
+ if (!mask) {
+ ++p;
+ mask = 0x80;
+ }
+ }
}
}
+ im->ch_mask = old_mask;
}
static
int
-i_tt_rasterize( TT_Fonthandle *handle, TT_Raster_Map *bit, int cords[6], float points, char const* txt, int len, int smooth, int utf8 ) {
+i_tt_rasterize( TT_Fonthandle *handle, TT_Raster_Map *bit, int cords[6], float points, char const* txt, size_t len, int smooth, int utf8 ) {
int inst;
int width, height;
TT_Raster_Map small_bit;
*/
undef_int
-i_tt_cp( TT_Fonthandle *handle, i_img *im, int xb, int yb, int channel, float points, char const* txt, int len, int smooth, int utf8, int align ) {
+i_tt_cp( TT_Fonthandle *handle, i_img *im, int xb, int yb, int channel, float points, char const* txt, size_t len, int smooth, int utf8, int align ) {
int cords[BOUNDING_BOX_COUNT];
int ascent, st_offset, y;
*/
undef_int
-i_tt_text( TT_Fonthandle *handle, i_img *im, int xb, int yb, i_color *cl, float points, char const* txt, int len, int smooth, int utf8, int align) {
+i_tt_text( TT_Fonthandle *handle, i_img *im, int xb, int yb, const i_color *cl, float points, char const* txt, size_t len, int smooth, int utf8, int align) {
int cords[BOUNDING_BOX_COUNT];
int ascent, st_offset, y;
TT_Raster_Map bit;
static
undef_int
-i_tt_bbox_inst( TT_Fonthandle *handle, int inst ,const char *txt, int len, int cords[BOUNDING_BOX_COUNT], int utf8 ) {
+i_tt_bbox_inst( TT_Fonthandle *handle, int inst ,const char *txt, size_t len, int cords[BOUNDING_BOX_COUNT], int utf8 ) {
int upm, casc, cdesc, first;
int start = 0;
*/
undef_int
-i_tt_bbox( TT_Fonthandle *handle, float points,char *txt,int len,int cords[6], int utf8) {
+i_tt_bbox( TT_Fonthandle *handle, float points,const char *txt,size_t len,int cords[6], int utf8) {
int inst;
i_clear_error();
printf("'%s'\n", name);
}
}
+ fflush(stdout);
}
int
}
if (handle->load_cond) {
- i_push_errorf(rc, "error loading names (%d)", handle->load_cond);
+ i_push_errorf(handle->load_cond, "error loading names (%d)", handle->load_cond);
return 0;
}
#endif
}
+/*
+=item i_tt_push_error(code)
+
+Push an error message and code onto the Imager error stack.
+
+=cut
+*/
+static void
+i_tt_push_error(TT_Error rc) {
+#ifdef FTXERR18
+ TT_String const *msg = TT_ErrToString18(rc);
+
+ i_push_error(rc, msg);
+#else
+ i_push_errorf(rc, "Error code 0x%04x", (unsigned)rc);
+#endif
+}
+
#endif /* HAVE_LIBTT */