Leptonica 1.68
C Image Processing Library
|
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. Å {{{ */ 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