OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
ossimFreeTypeFont.cpp
Go to the documentation of this file.
1 //*******************************************************************
2 // Copyright (C) 2000 ImageLinks Inc.
3 //
4 // License: See top level LICENSE.txt file.
5 //
6 // Author: Garrett Potts
7 //
8 //********************************************************************
9 // $Id: ossimFreeTypeFont.cpp 21518 2012-08-22 21:15:56Z dburken $
10 
11 // ossimFreeTypeFont.h should be load prior to checking for OSSIM_HAS_FREETYPE.
13 
14 #if OSSIM_HAS_FREETYPE
15 # include <ossim/matrix/newmatio.h>
18 # include <ossim/base/ossimTrace.h>
19 # include <cstring> // for memset
20 # ifndef NULL
21 # include <stddef.h>
22 # endif
23 
24 static ossimTrace traceDebug ("ossimFreeTypeFont:debug");
25 
26 RTTI_DEF1(ossimFreeTypeFont, "ossimFreeTypeFont", ossimFont);
27 
28 ossimFreeTypeFont::ossimFreeTypeFont(const ossimFilename& fontFile)
29  :ossimFont(),
30  theFontFace(NULL),
31  theLibrary(NULL),
32  theFontFile(fontFile),
33  theOutputBuffer(NULL),
34  theBufferSize(0),
35  theKerningEnabledFlag(true),
36  theNeedToLayoutGlyphsFlag(true),
37  theBoundingRectIsValid(false)
38 {
39  int error;
40  if(fontFile.exists())
41  {
42  error = FT_Init_FreeType(&theLibrary);
43  if(error)
44  {
45  ossimNotify(ossimNotifyLevel_WARN) << "WARNING ossimFreeTypeFont::ossimFreeTypeFont: Can't initialize freetype" << std::endl;
46  setErrorStatus();
47  }
48  if(getErrorStatus() == ossimErrorCodes::OSSIM_OK)
49  {
50  error = FT_New_Face( theLibrary,
51  fontFile.c_str(),
52  0,
53  &theFontFace );
54  if (error == FT_Err_Unknown_File_Format)
55  {
56  if (traceDebug())
57  {
59  << "WARNING ossimFreeTypeFont::ossimFreeTypeFont: Unable to create a font face for file = "
60  << fontFile
61  << std::endl;
62  }
63  FT_Done_Library(theLibrary);
64  theLibrary = NULL;
65  setErrorStatus();
66  }
67  else
68  {
69  setBaseClassInformation();
70  }
71  }
72  }
73  else
74  {
75  setErrorStatus();
76  }
77 }
78 
79 ossimFreeTypeFont::ossimFreeTypeFont(const ossimFreeTypeFont& rhs)
80  :ossimFont(rhs),
81  theMatrix(rhs.theMatrix),
82  theFontFile(rhs.theFontFile),
83  theOutputBuffer(NULL),
84  theBufferSize(0),
85  theKerningEnabledFlag(rhs.theKerningEnabledFlag),
86  theNeedToLayoutGlyphsFlag(rhs.theNeedToLayoutGlyphsFlag),
87  theStringCenter(rhs.theStringCenter),
88  theShift(rhs.theShift),
89  thePrecomputedBoundingRect(rhs.thePrecomputedBoundingRect),
90  theBoundingRectIsValid(rhs.theBoundingRectIsValid)
91 {
92  if(rhs.getErrorStatus())
93  {
94  setErrorStatus();
95  }
96  else
97  {
98  int error;
99  error = FT_Init_FreeType(&theLibrary);
100 
101  if(error)
102  {
103  ossimNotify(ossimNotifyLevel_WARN) << "WARNING ossimFreeTypeFoont::ossimFreeTypeFont: Can't initialize freetype in copy constructor" <<std::endl;
104  setErrorStatus();
105  }
106  if(getErrorStatus() == ossimErrorCodes::OSSIM_OK)
107  {
108  error = FT_New_Face( theLibrary,
109  rhs.theFontFile.c_str(),
110  0,
111  &theFontFace );
112  if(error == FT_Err_Unknown_File_Format)
113  {
114  if (traceDebug())
115  {
117  << "WARNING ossimFreeTypeFoont::ossimFreeTypeFont: Unable to create a font face for file = "
118  << rhs.theFontFile
119  << std::endl;
120  }
121 
122  FT_Done_Library(theLibrary);
123  theLibrary = NULL;
124  setErrorStatus();
125  }
126  else
127  {
128  if(rhs.theBufferSize)
129  {
130  theBufferSize = rhs.theBufferSize;
131  theOutputBuffer = new ossim_uint8[theBufferSize];
132  memcpy(theOutputBuffer, rhs.theOutputBuffer, theBufferSize);
133  setBaseClassInformation();
134  theNeedToLayoutGlyphsFlag = true;
135  layoutGlyphs(theStringToRasterize);
136  }
137  }
138  }
139  }
140 }
141 
142 ossimFreeTypeFont::~ossimFreeTypeFont()
143 {
144  if(theOutputBuffer)
145  {
146  delete [] theOutputBuffer;
147  theOutputBuffer = NULL;
148  }
149  if(theFontFace)
150  {
151  FT_Done_Face(theFontFace);
152  theFontFace = NULL;
153  }
154  if(theLibrary)
155  {
156  FT_Done_FreeType(theLibrary);
157  theLibrary = NULL;
158  }
159 }
160 
161 void ossimFreeTypeFont::layoutGlyphs(const ossimString& s )
162 {
163  if(!theNeedToLayoutGlyphsFlag||!theFontFace)
164  {
165  return;
166  }
167 
168 
169  int n;
170  FT_Vector origin;
171  FT_Pos origin_x = 0;
172  // FT_UInt load_flags;
173  // FT_UInt num_grays;
174  FT_UInt prev_index = 0;
175  FT_UInt num_glyphs = (FT_UInt)s.size();
176  int error = 0;
177 
178  deleteGlyphs(theStringLayout);
179  theStringLayout.resize(s.size());
180 
181  theMatrix.xx = (FT_Fixed)(theAffineTransform[0][0]*0x10000);
182  theMatrix.xy = (FT_Fixed)(theAffineTransform[1][0]*0x10000);
183  theMatrix.yx = (FT_Fixed)(theAffineTransform[0][1]*0x10000);
184  theMatrix.yy = (FT_Fixed)(theAffineTransform[1][1]*0x10000);
185 
186  int hasKerning = FT_HAS_KERNING(theFontFace);
187 
188  // load_flags = FT_LOAD_DEFAULT;
189  // num_grays = 256;
190 
191  const char* c = s.c_str();
192  for ( n = 0; n < (int)num_glyphs; n++)
193  {
194  long charOffset = c[n];
195 
196  FT_ULong charIndex = 0;
197 
198  if(charOffset < 0)
199  {
200  charIndex = (charOffset + 256);
201  }
202  else
203  {
204  charIndex = charOffset;
205  }
206  theStringLayout[n].glyph_index = FT_Get_Char_Index( theFontFace,
207  charIndex );
208  theStringLayout[n].image = NULL;
209  /* compute glyph origin */
210  if (hasKerning&&theKerningEnabledFlag&&prev_index)
211  {
212  FT_Vector kern;
213 
214 
215  FT_Get_Kerning( theFontFace,
216  prev_index,
217  theStringLayout[n].glyph_index,
218  ft_kerning_default,
219  &kern );
220 
221  origin_x += (kern.x);
222  }
223 
224  origin.x = origin_x;
225  origin.y = 0;
226 
227 
228  /* load the glyph image (in its native format); */
229  /* for now, we take a monochrome glyph bitmap */
230  error = FT_Load_Glyph( theFontFace,
231  theStringLayout[n].glyph_index,
232  FT_LOAD_DEFAULT);
233  if ( error )
234  {
235  continue;
236  }
237 
238  error = FT_Get_Glyph ( theFontFace->glyph, &theStringLayout[n].image );
239 
240  if ( error )
241  {
242  continue;
243  }
244 
245  theStringLayout[n].pos = origin;
246 
247  origin_x += (theFontFace->glyph->advance.x);
248  prev_index = theStringLayout[n].glyph_index;
249  }
250 
251  theStringCenter.x = origin_x / 2;
252  theStringCenter.y = 0;
253 
254  FT_Vector_Transform( &theStringCenter, &theMatrix );
255  theNeedToLayoutGlyphsFlag = false;
256 }
257 
258 const ossim_uint8* ossimFreeTypeFont::rasterize()
259 {
260  allocateBuffer();
261  setupForRasterization();
262  layoutGlyphs(theStringToRasterize);
263 
264  int num_glyphs = (int)theStringLayout.size();
265  int n;
266  FT_Vector delta;
267  int error;
268 
269  /* first of all, we must compute the general delta for the glyph set */
270  delta.x = -theStringCenter.x;
271  delta.y = 0;
272 
273  memset(theOutputBuffer, 0, theBufferSize);
274  for ( n = 0; n < num_glyphs; n++)
275  {
276  FT_Glyph image;
277  FT_Vector vec;
278 
279 
280  if ( !theStringLayout[n].image )
281  {
282  continue;
283  }
284 
285  /* copy image */
286  error = FT_Glyph_Copy( theStringLayout[n].image, &image );
287  if ( error )
288  continue;
289 
290  /* transform it */
291  vec = theStringLayout[n].pos;
292  FT_Vector_Transform( &vec, &theMatrix );
293  vec.x += (delta.x);
294  vec.y += (delta.y);
295  error = FT_Glyph_Transform( image, &theMatrix, &vec );
296  if ( !error )
297  {
298  FT_BBox bbox;
299  /* check bounding box; if it is not within the display surface, */
300  /* we don't need to render it */
301 
302  FT_Glyph_Get_CBox( image, ft_glyph_bbox_pixels, &bbox );
303 
304  // since freetype coordinates are right handed we will
305  // adjust the rects so they are right handed before passing
306  // them to our rendering system.
307  //
308  ossimIrect box(bbox.xMin,
309  bbox.yMax,
310  bbox.xMax,
311  bbox.yMin,
313  ossimIrect bufRect;
314  ossimIrect boundingBox;;
315  getBufferRect(bufRect);
316  getBoundingBox(boundingBox);
317 
318  bufRect = ossimIrect(bufRect.ul().x,
319  boundingBox.lr().y - bufRect.ul().y,
320  bufRect.lr().x,
321  boundingBox.lr().y - bufRect.lr().y,
323  box += ossimIpt(-theShift.x,
324  -theShift.y);
325  if(bufRect.intersects(box))
326  {
327  // now let's convert it to a bitmap
328  error = FT_Glyph_To_Bitmap( &image,
329  ft_render_mode_normal,
330  0,
331  1 );
332  if ( !error )
333  {
334  // cast it
335  FT_BitmapGlyph bitmap = (FT_BitmapGlyph)image;
336 
337  ossimIpt ul(bitmap->left -theShift.x,
338  bitmap->top -theShift.y);
339 
340  // the bounding char box does not coorespond to the
341  // buffer rect of rfreetype's internal sorage.
342  // We will need to adjust the box and then render it
343  //
344  box = ossimIrect(ul.x,
345  ul.y,
346  ul.x + bitmap->bitmap.width-1,
347  ul.y - (bitmap->bitmap.rows-1),
349 
350  // draw the sub rect within our buffer.
351  drawBitmap(&bitmap->bitmap,
352  bufRect,
353  box);
354  }
355  }
356  }
357  FT_Done_Glyph( image );
358  }
359 
360  return theOutputBuffer;
361 }
362 
363 void ossimFreeTypeFont::getBoundingBox(ossimIrect& box)
364 {
365 
366  if(theBoundingRectIsValid)
367  {
368  box = thePrecomputedBoundingRect;
369  return;
370  }
371  setupForRasterization();
372  layoutGlyphs(theStringToRasterize);
373 
374  int num_glyphs = (int)theStringLayout.size();
375  int n;
376  FT_Vector delta;
377  int error;
378  bool firstBoxSet = false;
379  /* first of all, we must compute the general delta for the glyph set */
380  delta.x = -theStringCenter.x;
381  delta.y = 0;
382 
383  for ( n = 0; n < num_glyphs; n++)
384  {
385  FT_Glyph image;
386  FT_Vector vec;
387 
388 
389  if ( !theStringLayout[n].image )
390  {
391  continue;
392  }
393 
394  /* copy image */
395  error = FT_Glyph_Copy( theStringLayout[n].image, &image );
396  if ( error )
397  continue;
398 
399  /* transform it */
400  vec = theStringLayout[n].pos;
401  FT_Vector_Transform( &vec, &theMatrix );
402  vec.x += (delta.x);
403  vec.y += (delta.y);
404  error = FT_Glyph_Transform( image, &theMatrix, &vec );
405  if ( !error )
406  {
407  FT_BBox bbox;
408  /* check bounding box; if it is not within the display surface, */
409  /* we don't need to render it */
410 
411  FT_Glyph_Get_CBox( image, ft_glyph_bbox_pixels, &bbox );
412  ossimIrect charBox(bbox.xMin,
413  bbox.yMin,
414  bbox.xMax,
415  bbox.yMax);
416 
417  if(firstBoxSet)
418  {
419  box = box.combine(charBox);
420  }
421  else
422  {
423  firstBoxSet = true;
424  box = charBox;
425  }
426  }
427  FT_Done_Glyph( image );
428  }
429 
430  theShift = box.ul();
431 
432  box += ossimIpt(-theShift.x,
433  -theShift.y);
434 
435  thePrecomputedBoundingRect = box;
436 }
437 
438 void ossimFreeTypeFont::computeGlyphBox(FT_Glyph /* slot */,
439  ossimIrect& box)const
440 {
441  long yBearing = theFontFace->glyph->metrics.horiBearingY/64;
442  long h = theFontFace->glyph->metrics.height/64;
443  long w = theFontFace->glyph->metrics.width/64;
444 
445  if(h&&w)
446  {
447  box = ossimIrect(0,
448  yBearing-(h-1),
449  (w-1),
450  yBearing);
451  }
452  else
453  {
454  box = ossimIrect(0,0,0,0);
455  }
456 }
457 
458 void ossimFreeTypeFont::drawBitmap(FT_Bitmap* bitmap,
459  const ossimIrect& bufRect,
460  const ossimIrect& glyphBox)
461 {
462  if(bufRect.intersects(glyphBox))
463  {
464  unsigned char* buf = bitmap->buffer;
465  if(!theOutputBuffer||!buf) return;
466 
467  ossimIrect intersectionRect = bufRect.clipToRect(glyphBox);
468 
469 
470  long difInX = intersectionRect.ul().x - glyphBox.ul().x;
471  long difInY = glyphBox.ul().y - intersectionRect.ul().y;
472 
473  long difOutX = intersectionRect.ul().x - bufRect.ul().x;
474  long difOutY = bufRect.ul().y - intersectionRect.ul().y;
475 
476 
477 
478  long startInOffset = bitmap->width*difInY + difInX;
479  long startOutOffset = bufRect.width()*difOutY + difOutX;
480 
481  long outBufW = bufRect.width();
482  long inBufW = bitmap->width;
483 
484  // let's just make sure that the increment will not exceed the input
485  // buffers width and height.
486  //
487  long height = std::min((long)intersectionRect.height(), (long)glyphBox.height());
488  long width = std::min((long)intersectionRect.width(), (long)glyphBox.width());
489 
490  for(long rows = 0 ; rows < height; ++rows)
491  {
492  for(long cols = 0; cols < width; ++cols)
493  {
494  if(buf[startInOffset+cols])
495  {
496  theOutputBuffer[startOutOffset + cols] = buf[startInOffset+cols];
497  }
498  }
499  startInOffset+=inBufW;
500  startOutOffset+=outBufW;
501  }
502  }
503 }
504 
505 void ossimFreeTypeFont::setupForRasterization()
506 {
507  int error=0;
508  if(!theFontFace) return;
509 
510  if(!theFontFace->charmap)
511  {
512  error = FT_Select_Charmap(theFontFace, /* target face object */
513  ft_encoding_big5 ); /* encoding.. */
514  }
515 
516  error = FT_Set_Char_Size(theFontFace,
517  theHorizontalPixelSize*64,
518  theVerticalPixelSize*64,
519  theHorizontalDeviceUnits,
520  theVerticalDeviceUnits);
521  if(error)
522  {
523  ossimNotify(ossimNotifyLevel_WARN) << "WARNING ossimFreeTypeFont::setupForRasterization: Cant set the pixel size" <<std::endl;
524  }
525 }
526 
527 void ossimFreeTypeFont::setBaseClassInformation()
528 {
529  if(theFontFace)
530  {
531  theFamilyName = theFontFace->family_name;
532 
533  if(isFixed())
534  {
535  vector<ossimIpt> initialPointList;
536  getFixedSizes(initialPointList);
537 
538  theHorizontalPixelSize = initialPointList[0].x;
539  theVerticalPixelSize = initialPointList[0].y;
540  }
541  else
542  {
543  theHorizontalPixelSize = 8;
544  theVerticalPixelSize = 8;
545  }
546  if((theFontFace->style_flags & FT_STYLE_FLAG_BOLD) &&
547  (theFontFace->style_flags&FT_STYLE_FLAG_ITALIC))
548  {
549  theStyleName = "bold italic";
550  }
551  else if(theFontFace->style_flags & FT_STYLE_FLAG_BOLD)
552  {
553  theStyleName = "bold";
554  }
555  else if(theFontFace->style_flags & FT_STYLE_FLAG_ITALIC)
556  {
557  theStyleName = "italic";
558  }
559  else
560  {
561  theStyleName = "normal";
562  }
563  }
564 }
565 
566 
567 void ossimFreeTypeFont::setCurrentFace(long index)
568 {
569  int error;
570  if(theFontFace)
571  {
572  if((index >0) && (index < theFontFace->num_faces))
573  {
574  FT_Done_Face(theFontFace);
575  theFontFace = NULL;
576 
577  error = FT_New_Face( theLibrary,
578  theFontFile.c_str(),
579  index,
580  &theFontFace );
581  if((error == FT_Err_Unknown_File_Format)||error)
582  {
583  setErrorStatus();
584  }
585  else
586  {
587  setBaseClassInformation();
588  }
589  theBoundingRectIsValid = false;
590  }
591  }
592 }
593 
594 void ossimFreeTypeFont::getFixedSizes(vector<ossimIpt>& sizeArray)const
595 {
596  if(theFontFace)
597  {
598  sizeArray.clear();
599  int i = 0;
600 
601  for(i = 0; i < theFontFace->num_fixed_sizes; ++i)
602  {
603  sizeArray.push_back(ossimIpt(theFontFace->available_sizes[i].width,
604  theFontFace->available_sizes[i].height));
605  }
606  }
607 }
608 
609 void ossimFreeTypeFont::allocateBuffer()
610 {
611  ossimIrect box;
612  setupForRasterization();
613  getBoundingClipBox(box);
614  long bufferSize = box.width()*box.height();
615  if(bufferSize != theBufferSize)
616  {
617  theBufferSize = bufferSize;
618 
619  if(theOutputBuffer)
620  {
621  delete theOutputBuffer;
622  theOutputBuffer = NULL;
623  }
624  if(!theOutputBuffer&&theBufferSize)
625  {
626  theOutputBuffer = new ossim_uint8[theBufferSize];
627  }
628  }
629 }
630 
631 void ossimFreeTypeFont::deleteGlyphs(vector<TGlyph>& glyphs)
632 {
633  int i = 0;
634 
635  for(i = 0; i < (int)glyphs.size(); ++i)
636  {
637  if(glyphs[i].image)
638  {
639  FT_Done_Glyph(glyphs[i].image);
640  }
641  }
642 
643  glyphs.clear();
644 }
645 
646 #endif /* #if OSSIM_HAS_FREETYPE */
static const ossimErrorCode OSSIM_OK
ossim_uint32 height() const
Definition: ossimIrect.h:487
const ossimIpt & ul() const
Definition: ossimIrect.h:274
bool intersects(const ossimIrect &rect) const
Definition: ossimIrect.cpp:183
bool exists() const
std::string::size_type size() const
Definition: ossimString.h:405
os2<< "> n<< " > nendobj n
const ossimIpt & lr() const
Definition: ossimIrect.h:276
ossim_uint32 width() const
Definition: ossimIrect.h:500
ossimIrect clipToRect(const ossimIrect &rect) const
Definition: ossimIrect.cpp:501
ossim_int32 y
Definition: ossimIpt.h:142
const char * c_str() const
Returns a pointer to a null-terminated array of characters representing the string&#39;s contents...
Definition: ossimString.h:396
ossim_int32 x
Definition: ossimIpt.h:141
#define RTTI_DEF1(cls, name, b1)
Definition: ossimRtti.h:485
ossimIrect combine(const ossimIrect &rect) const
Definition: ossimIrect.cpp:543
unsigned char ossim_uint8
OSSIMDLLEXPORT std::ostream & ossimNotify(ossimNotifyLevel level=ossimNotifyLevel_WARN)
#define min(a, b)
Definition: auxiliary.h:75