Leptonica 1.68
C Image Processing Library

freetype.c

Go to the documentation of this file.
00001 /*====================================================================*
00002  -  Copyright (C) 2008 Leptonica.  All rights reserved.
00003  -  This software is distributed in the hope that it will be
00004  -  useful, but with NO WARRANTY OF ANY KIND.
00005  -  No author or distributor accepts responsibility to anyone for the
00006  -  consequences of using this software, or for whether it serves any
00007  -  particular purpose or works at all, unless he or she says so in
00008  -  writing.  Everyone is granted permission to copy, modify and
00009  -  redistribute this source code, for commercial or non-commercial
00010  -  purposes, with the following restrictions: (1) the origin of this
00011  -  source code must not be misrepresented; (2) modified versions must
00012  -  be plainly marked as such; and (3) this notice may not be removed
00013  -  or altered from any source or modified source distribution.
00014  *====================================================================*/
00015 
00016 /*
00017  * freetype.c
00018  *      static l_int32       ftUtfToUniChar()
00019  *      static PIX          *ftDrawBitmap()
00020  *             FT_LIBRARY   *ftInitLibrary()
00021  *             void          ftShutdownLibrary()
00022  *             PIX          *pixWriteTTFText()
00023  */
00024 
00025 #include <stdio.h>
00026 #include <stdlib.h>
00027 #include <string.h>
00028 #include <math.h>
00029 #include "allheaders.h"
00030 
00031 #include <ft2build.h>
00032 #include FT_FREETYPE_H
00033 #include FT_GLYPH_H
00034 
00035 #undef MAX
00036 #define MAX(a, b) (((a)>(b))?(a):(b))
00037 
00038 #define ROUNDUPDOWN(val, updown) (!updown) ? (val < 0 ? ((val - 63) >> 6) : val >> 6) : (val > 0 ? ((val + 63) >> 6) : val >> 6)
00039 
00040 struct ft_library_st {
00041         FT_Library library;
00042 };
00043 
00044 static l_int32
00045 ftUtfToUniChar(char     *str,
00046                l_int32  *chPtr)
00047 {
00048         l_int32 byte;
00049 
00050         /* HTML4.0 entities in decimal form, e.g. &#197; {{{ */
00051         byte = *((unsigned char *) str);
00052         if (byte == '&') { 
00053                 l_int32 i, n = 0;
00054 
00055                 byte = *((unsigned char *) (str+1));
00056                 if (byte == '#') {
00057                         for (i = 2; i < 8; i++) {
00058                                 byte = *((unsigned char *) (str+i));
00059                                 if (byte >= '0' && byte <= '9') {
00060                                         n = (n * 10) + (byte - '0');
00061                                 } else {
00062                                         break;
00063                                 }
00064                         }
00065                         if (byte == ';') {
00066                                 *chPtr = (l_int32) n;
00067                                 return ++i;
00068                         }
00069                 }
00070         }
00071         /* }}} */
00072 
00073         /* Unroll 1 to 3 byte UTF-8 sequences */
00074 
00075         byte = *((unsigned char *) str);
00076         if (byte < 0xC0) {
00077                 /*
00078                  * Handles properly formed UTF-8 characters between 0x01 and 0x7F.
00079                  * Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
00080                  * characters representing themselves.
00081                  */
00082 
00083                 *chPtr = (l_int32) byte;
00084                 return 1;
00085         } else if (byte < 0xE0) {
00086                 if ((str[1] & 0xC0) == 0x80) {
00087                         /* Two-byte-character lead-byte followed by a trail-byte. */
00088 
00089                         *chPtr = (l_int32) (((byte & 0x1F) << 6) | (str[1] & 0x3F));
00090                         return 2;
00091                 }
00092                 /*
00093                  * A two-byte-character lead-byte not followed by trail-byte
00094                  * represents itself.
00095                  */
00096 
00097                 *chPtr = (l_int32) byte;
00098                 return 1;
00099         } else if (byte < 0xF0) {
00100                 if (((str[1] & 0xC0) == 0x80) && ((str[2] & 0xC0) == 0x80)) {
00101                         /* Three-byte-character lead byte followed by two trail bytes. */
00102 
00103                         *chPtr = (l_int32) (((byte & 0x0F) << 12) | ((str[1] & 0x3F) << 6) | (str[2] & 0x3F));
00104                         return 3;
00105                 }
00106                 /* A three-byte-character lead-byte not followed by two trail-bytes represents itself. */
00107 
00108                 *chPtr = (l_int32) byte;
00109                 return 1;
00110         }
00111 
00112         *chPtr = (l_int32)byte;
00113         return 1;
00114 }
00115 /* }}} */
00116 
00117 static PIX *
00118 ftDrawBitmap(l_uint32  *datad,
00119              l_uint32   color,
00120              FT_Bitmap  bitmap,
00121              l_int32    pen_x,
00122              l_int32    pen_y,
00123              l_int32    width,
00124              l_int32    height)
00125 {
00126         l_uint32 *ppixel = NULL, pixel;
00127         l_int32 x, y, row, col, pc, pcr, i;
00128         l_uint8 tmp;
00129         
00130         PROCNAME("ftDrawBitmap");
00131 
00132         for (row = 0; row < bitmap.rows; row++) {
00133                 pc = row * bitmap.pitch;
00134                 pcr = pc;
00135                 y = pen_y + row;
00136 
00137                 /* clip if out of bounds */
00138                 if (y >= height || y < 0) {
00139                         continue;
00140                 }
00141 
00142                 for (col = 0; col < bitmap.width; col++, pc++) {
00143                         int level;
00144 
00145                         if (bitmap.pixel_mode == ft_pixel_mode_grays) {
00146                                 level = (bitmap.buffer[pc] * 127/ (bitmap.num_grays - 1));
00147                         } else if (bitmap.pixel_mode == ft_pixel_mode_mono) {
00148                                 level = ((bitmap.buffer[(col>>3)+pcr]) & (1<<(~col&0x07))) ? 127 : 0;
00149                         } else {
00150                                 return (PIX *)ERROR_PTR("unsupported ft_pixel mode", procName, NULL);
00151                         }
00152 
00153                         if (color >= 0) {
00154                                 level = level * (127 - GET_DATA_BYTE(&color, L_ALPHA_CHANNEL)) / 127;
00155                         }
00156 
00157                         level = 127 - level;
00158                         x = pen_x + col;
00159 
00160                         /* clip if out of bounds */
00161                         if (x >= width || x < 0) {
00162                                 continue;
00163                         }
00164 
00165                         ppixel = datad + y*width + x;
00166 
00167                         /* mix 2 colors using level as alpha */
00168                         if (level != 127) {
00169                                 l_uint8 new, old;
00170 
00171                                 pixel = *ppixel;
00172                                 for (i = 0; i < 3; i++) {
00173                                         new = GET_DATA_BYTE(&color, i);
00174                                         old = GET_DATA_BYTE(&pixel, i);
00175                                         tmp = (double)old * ((double)level/127) + (double)new * ((double)(127 - level)/127);
00176                                         SET_DATA_BYTE(ppixel, i, tmp);
00177                                 }
00178                         }
00179                 }
00180         }
00181         return NULL;
00182 }
00183 
00184 
00185 FT_LIBRARY *
00186 ftInitLibrary(void)
00187 {
00188         FT_Error err;
00189         FT_LIBRARY *lib_ptr;
00190         
00191         lib_ptr = CALLOC(1, sizeof(FT_LIBRARY));
00192 
00193         err = FT_Init_FreeType(&lib_ptr->library);
00194         if (err) {
00195                 FREE(lib_ptr);
00196                 return NULL;
00197         }
00198         return lib_ptr;
00199 }
00200 
00201 
00202 void
00203 ftShutdownLibrary(FT_LIBRARY  *lib_ptr)
00204 {
00205     if (lib_ptr) {
00206         FT_Done_FreeType(lib_ptr->library);
00207         FREE(lib_ptr);
00208     }
00209 }
00210 
00211 
00212 PIX *
00213 pixWriteTTFText(FT_LIBRARY  *lib_ptr,
00214                 PIX         *pixs,
00215                 l_float32    size,
00216                 l_float32    angle,
00217                 l_int32      x,
00218                 l_int32      y,
00219                 l_int32      letter_space,
00220                 l_uint32     color,
00221                 l_uint8     *fontfile,
00222                 l_uint8     *text,
00223                 l_int32      text_len,
00224                 l_int32     *brect)
00225 {
00226 PIX *pixd, *pixt = NULL;
00227 FT_Error err;
00228 FT_Face face;
00229 FT_Glyph image;
00230 FT_BitmapGlyph bitmap;
00231 FT_CharMap charmap;
00232 FT_Matrix matrix;
00233 FT_Vector pen, penf;
00234 FT_UInt glyph_index, previous;
00235 FT_BBox char_bbox, bbox;
00236 l_uint32 *datad, letter_space_x, letter_space_y;
00237 l_int32 i, found, len, ch, x1 = 0, y1 = 0, width, height;
00238 l_uint16 platform, encoding;
00239 char *next;
00240 l_float32 cos_a, sin_a;
00241 
00242         PROCNAME("pixWriteTTFText");
00243 
00244         if (pixGetDepth(pixs) != 32) {
00245                 pixt = pixConvertTo32(pixs);
00246                 if (!pixt) {
00247                         return (PIX *)ERROR_PTR("failed to convert pixs to 32bpp image", procName, NULL);
00248                 }
00249                 
00250                 pixd = pixCopy(NULL, pixt);
00251         } else {
00252                 pixd = pixCopy(NULL, pixs);
00253         }
00254 
00255         datad = pixGetData(pixd);
00256 
00257         if (!pixd) {
00258                 if (pixt) {
00259                         pixDestroy(&pixt);
00260                         pixDestroy(&pixd);
00261                 }
00262                 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00263         }
00264 
00265         width = pixGetWidth(pixd);
00266         height = pixGetHeight(pixd);
00267 
00268         err = FT_New_Face (lib_ptr->library, (char *)fontfile, 0, &face);
00269         if (err) {
00270                 if (pixt) {
00271                         pixDestroy(&pixt);
00272                         pixDestroy(&pixd);
00273                 }
00274                 return (PIX *)ERROR_PTR("failed to load font file", procName, NULL);
00275         }
00276 
00277         err = FT_Set_Char_Size(face, 0, (FT_F26Dot6) (size * 64), LEPTONICA_FT_RESOLUTION, LEPTONICA_FT_RESOLUTION);
00278         if (err) {
00279                 if (pixt) {
00280                         pixDestroy(&pixt);
00281                         pixDestroy(&pixd);
00282                 }
00283                 FT_Done_Face(face);
00284                 return (PIX *)ERROR_PTR("failed to set font size", procName, NULL);
00285         }
00286 
00287         found = 0;
00288 
00289         for (i = 0; i < face->num_charmaps; i++) {
00290                 charmap = face->charmaps[i];
00291                 platform = charmap->platform_id;
00292                 encoding = charmap->encoding_id;
00293 
00294                 if ((platform == 3 && encoding == 1)    /* Windows Unicode */
00295                         || (platform == 3 && encoding == 0) /* Windows Symbol */
00296                         || (platform == 2 && encoding == 1) /* ISO Unicode */
00297                         || (platform == 0))                 /* Apple Unicode */
00298                 {
00299                         found = 1;
00300                         break;
00301                 }
00302         }
00303 
00304         if (!found) {
00305                 if (pixt) {
00306                         pixDestroy(&pixt);
00307                         pixDestroy(&pixd);
00308                 }
00309                 FT_Done_Face(face);
00310                 return (PIX *)ERROR_PTR("could not find Unicode charmap", procName, NULL);
00311         }
00312 
00313         /* degrees to radians */
00314         angle = angle * (M_PI/180);
00315         sin_a = sin(angle);
00316         cos_a = cos(angle);
00317 
00318         matrix.xx = (FT_Fixed) (cos_a * (1 << 16));
00319         matrix.yx = (FT_Fixed) (sin_a * (1 << 16));
00320         matrix.xy = -matrix.yx;
00321         matrix.yy = matrix.xx;
00322 
00323         FT_Set_Transform(face, &matrix, NULL);
00324 
00325         penf.x = penf.y = 0;    /* running position of non-rotated string */
00326         pen.x = pen.y = 0;      /* running position of rotated string */
00327 
00328         previous = 0;
00329 
00330         next = (char *)text;
00331         i = 0;
00332         while (*next) {
00333                 if (i == 0) { /* use char spacing for 1+ characters */
00334                         letter_space_x = 0;
00335                         letter_space_y = 0;
00336                 } else {
00337                         letter_space_x = cos_a * letter_space * i;
00338                         letter_space_y = -sin_a * letter_space * i;
00339                 }
00340 
00341                 len = ftUtfToUniChar(next, &ch);
00342 //              ch |= 0xf000;
00343                 next += len;
00344 
00345                 glyph_index = FT_Get_Char_Index(face, ch);
00346 
00347                 err = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
00348                 if (err) {
00349                         if (pixt) {
00350                                 pixDestroy(&pixt);
00351                                 pixDestroy(&pixd);
00352                         }
00353                         FT_Done_Face(face);
00354                         return (PIX *)ERROR_PTR("could not load glyph into the slot", procName, NULL);
00355                 }
00356 
00357                 err = FT_Get_Glyph(face->glyph, &image);
00358                 if (err) {
00359                         if (pixt) {
00360                                 pixDestroy(&pixt);
00361                                 pixDestroy(&pixd);
00362                         }
00363                         FT_Done_Face(face);
00364                         return (PIX *)ERROR_PTR("could not extract glyph from a slot", procName, NULL);
00365                 }
00366 
00367                 if (brect) {
00368                         FT_Glyph_Get_CBox(image, ft_glyph_bbox_gridfit, &char_bbox);
00369 
00370                         char_bbox.xMin += penf.x;
00371                         char_bbox.yMin += penf.y;
00372                         char_bbox.xMax += penf.x;
00373                         char_bbox.yMax += penf.y;
00374 
00375                         if (i == 0) {
00376                                 bbox.xMin = char_bbox.xMin;
00377                                 bbox.yMin = char_bbox.yMin;
00378                                 bbox.xMax = char_bbox.xMax;
00379                                 bbox.yMax = char_bbox.yMax;
00380                         } else {
00381                                 if (bbox.xMin > char_bbox.xMin) {
00382                                         bbox.xMin = char_bbox.xMin;
00383                                 }
00384                                 if (bbox.yMin > char_bbox.yMin) {
00385                                         bbox.yMin = char_bbox.yMin;
00386                                 }
00387                                 if (bbox.xMax < char_bbox.xMax) {
00388                                         bbox.xMax = char_bbox.xMax;
00389                                 }
00390                                 if (bbox.yMax < char_bbox.yMax) {
00391                                         bbox.yMax = char_bbox.yMax;
00392                                 }
00393                         }
00394                 }
00395 
00396                 if (image->format != ft_glyph_format_bitmap && FT_Glyph_To_Bitmap(&image, ft_render_mode_normal, 0, 1)) {
00397                         if (pixt) {
00398                                 pixDestroy(&pixt);
00399                                 pixDestroy(&pixd);
00400                         }
00401                         FT_Done_Face(face);
00402                         return (PIX *)ERROR_PTR("could not convert glyph to bitmap", procName, NULL);
00403                 }
00404 
00405                 /* now, draw to our target surface */
00406                 bitmap = (FT_BitmapGlyph) image;
00407 
00408                 ftDrawBitmap(datad, color, bitmap->bitmap, letter_space_x + x + x1 + ((pen.x + 31) >> 6) + bitmap->left, letter_space_y + y - y1 + ((pen.y + 31) >> 6) - bitmap->top, width, height);
00409                 
00410                 /* record current glyph index for kerning */
00411                 previous = glyph_index;
00412 
00413                 /* increment pen position */
00414                 pen.x += image->advance.x >> 10;
00415                 pen.y -= image->advance.y >> 10;
00416 
00417                 penf.x += face->glyph->metrics.horiAdvance;
00418 
00419                 FT_Done_Glyph(image);
00420                 i++;
00421         }
00422 
00423         if (brect) {
00424                 double d1 = sin (angle + 0.78539816339744830962);
00425                 double d2 = sin (angle - 0.78539816339744830962);
00426 
00427                 /* rotate bounding rectangle */
00428                 brect[0] = (int) (bbox.xMin * cos_a - bbox.yMin * sin_a);
00429                 brect[1] = (int) (bbox.xMin * sin_a + bbox.yMin * cos_a);
00430                 brect[2] = (int) (bbox.xMax * cos_a - bbox.yMin * sin_a);
00431                 brect[3] = (int) (bbox.xMax * sin_a + bbox.yMin * cos_a);
00432                 brect[4] = (int) (bbox.xMax * cos_a - bbox.yMax * sin_a);
00433                 brect[5] = (int) (bbox.xMax * sin_a + bbox.yMax * cos_a);
00434                 brect[6] = (int) (bbox.xMin * cos_a - bbox.yMax * sin_a);
00435                 brect[7] = (int) (bbox.xMin * sin_a + bbox.yMax * cos_a);
00436 
00437                 /* scale, round and offset brect */
00438                 brect[0] = x + ROUNDUPDOWN(brect[0], d2 > 0);
00439                 brect[1] = y - ROUNDUPDOWN(brect[1], d1 < 0);
00440                 brect[2] = x + ROUNDUPDOWN(brect[2], d1 > 0);
00441                 brect[3] = y - ROUNDUPDOWN(brect[3], d2 > 0);
00442                 brect[4] = x + ROUNDUPDOWN(brect[4], d2 < 0);
00443                 brect[5] = y - ROUNDUPDOWN(brect[5], d1 > 0);
00444                 brect[6] = x + ROUNDUPDOWN(brect[6], d1 < 0);
00445                 brect[7] = y - ROUNDUPDOWN(brect[7], d2 < 0);
00446         }
00447 
00448         if (pixt) {
00449                 pixDestroy(&pixt);
00450         }
00451         return pixd;
00452 }
00453 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines