All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
tesseract::StringRenderer Class Reference

#include <stringrenderer.h>

Public Member Functions

 StringRenderer (const string &font_desc, int page_width, int page_height)
 
 ~StringRenderer ()
 
int RenderToImage (const char *text, int text_length, Pix **pix)
 
int RenderToGrayscaleImage (const char *text, int text_length, Pix **pix)
 
int RenderToBinaryImage (const char *text, int text_length, int threshold, Pix **pix)
 
int RenderAllFontsToImage (double min_coverage, const char *text, int text_length, string *font_used, Pix **pix)
 
bool set_font (const string &desc)
 
void set_char_spacing (double char_spacing)
 
void set_leading (int leading)
 
void set_resolution (const int resolution)
 
void set_vertical_text (bool vertical_text)
 
void set_gravity_hint_strong (bool gravity_hint_strong)
 
void set_render_fullwidth_latin (bool render_fullwidth_latin)
 
void set_underline_start_prob (const double frac)
 
void set_underline_continuation_prob (const double frac)
 
void set_underline_style (const PangoUnderline style)
 
void set_page (int page)
 
void set_box_padding (int val)
 
void set_drop_uncovered_chars (bool val)
 
void set_strip_unrenderable_words (bool val)
 
void set_output_word_boxes (bool val)
 
void set_add_ligatures (bool add_ligatures)
 
void set_pen_color (double r, double g, double b)
 
void set_h_margin (const int h_margin)
 
void set_v_margin (const int v_margin)
 
const PangoFontInfofont () const
 
const int h_margin () const
 
const int v_margin () const
 
const vector< BoxChar * > & GetBoxes () const
 
Boxa * GetPageBoxes () const
 
void RotatePageBoxes (float rotation)
 
void ClearBoxes ()
 
void WriteAllBoxes (const string &filename)
 
int StripUnrenderableWords (string *utf8_text) const
 

Static Public Member Functions

static string InsertWordJoiners (const string &text)
 
static string ConvertBasicLatinToFullwidthLatin (const string &text)
 
static string ConvertFullwidthLatinToBasicLatin (const string &text)
 

Protected Member Functions

void InitPangoCairo ()
 
void FreePangoCairo ()
 
void SetLayoutProperties ()
 
void SetWordUnderlineAttributes (const string &page_text)
 
void ComputeClusterBoxes ()
 
void CorrectBoxPositionsToLayout (vector< BoxChar * > *boxchars)
 
bool GetClusterStrings (vector< string > *cluster_text)
 
int FindFirstPageBreakOffset (const char *text, int text_length)
 

Protected Attributes

PangoFontInfo font_
 
int page_width_
 
int page_height_
 
int h_margin_
 
int v_margin_
 
int pen_color_ [3]
 
double char_spacing_
 
int leading_
 
int resolution_
 
bool vertical_text_
 
bool gravity_hint_strong_
 
bool render_fullwidth_latin_
 
double underline_start_prob_
 
double underline_continuation_prob_
 
PangoUnderline underline_style_
 
bool drop_uncovered_chars_
 
bool strip_unrenderable_words_
 
bool add_ligatures_
 
bool output_word_boxes_
 
cairo_surface_t * surface_
 
cairo_t * cr_
 
PangoLayout * layout_
 
int start_box_
 
int page_
 
vector< BoxChar * > boxchars_
 
int box_padding_
 
Boxa * page_boxes_
 
hash_map< char32, inT64char_map_
 
int total_chars_
 
int font_index_
 
int last_offset_
 

Detailed Description

Definition at line 48 of file stringrenderer.h.

Constructor & Destructor Documentation

tesseract::StringRenderer::StringRenderer ( const string &  font_desc,
int  page_width,
int  page_height 
)

Definition at line 97 of file stringrenderer.cpp.

99  : page_width_(page_width),
100  page_height_(page_height),
101  h_margin_(50),
102  v_margin_(50),
103  char_spacing_(0),
104  leading_(0),
105  vertical_text_(false),
106  gravity_hint_strong_(false),
110  underline_style_(PANGO_UNDERLINE_SINGLE),
111  drop_uncovered_chars_(true),
113  add_ligatures_(false),
114  output_word_boxes_(false),
115  surface_(NULL),
116  cr_(NULL),
117  layout_(NULL),
118  start_box_(0),
119  page_(0),
120  box_padding_(0),
121  total_chars_(0),
122  font_index_(0),
123  last_offset_(0) {
124  pen_color_[0] = 0.0;
125  pen_color_[1] = 0.0;
126  pen_color_[2] = 0.0;
127  set_font(font_desc);
128  set_resolution(kDefaultOutputResolution);
129  page_boxes_ = NULL;
130 }
cairo_surface_t * surface_
PangoUnderline underline_style_
void set_resolution(const int resolution)
bool set_font(const string &desc)
#define NULL
Definition: host.h:144
tesseract::StringRenderer::~StringRenderer ( )

Definition at line 151 of file stringrenderer.cpp.

151  {
152  ClearBoxes();
153  FreePangoCairo();
154 }

Member Function Documentation

void tesseract::StringRenderer::ClearBoxes ( )

Definition at line 334 of file stringrenderer.cpp.

334  {
335  for (int i = 0; i < boxchars_.size(); ++i)
336  delete boxchars_[i];
337  boxchars_.clear();
338  boxaDestroy(&page_boxes_);
339 }
vector< BoxChar * > boxchars_
void tesseract::StringRenderer::ComputeClusterBoxes ( )
protected

Definition at line 454 of file stringrenderer.cpp.

454  {
455  const char* text = pango_layout_get_text(layout_);
456  PangoLayoutIter* cluster_iter = pango_layout_get_iter(layout_);
457 
458  // Do a first pass to store cluster start indexes.
459  vector<int> cluster_start_indices;
460  do {
461  cluster_start_indices.push_back(pango_layout_iter_get_index(cluster_iter));
462  tlog(3, "Added %d\n", cluster_start_indices.back());
463  } while (pango_layout_iter_next_cluster(cluster_iter));
464  pango_layout_iter_free(cluster_iter);
465  cluster_start_indices.push_back(strlen(text));
466  tlog(3, "Added last index %d\n", cluster_start_indices.back());
467  // Sort the indices and create a map from start to end indices.
468  sort(cluster_start_indices.begin(), cluster_start_indices.end());
469  map<int, int> cluster_start_to_end_index;
470  for (int i = 0; i < cluster_start_indices.size() - 1; ++i) {
471  cluster_start_to_end_index[cluster_start_indices[i]]
472  = cluster_start_indices[i + 1];
473  }
474 
475  // Iterate again to compute cluster boxes and their text with the obtained
476  // cluster extent information.
477  cluster_iter = pango_layout_get_iter(layout_);
478  // Store BoxChars* sorted by their byte start positions
479  map<int, BoxChar*> start_byte_to_box;
480  do {
481  PangoRectangle cluster_rect;
482  pango_layout_iter_get_cluster_extents(cluster_iter, &cluster_rect,
483  NULL);
484  pango_extents_to_pixels(&cluster_rect, NULL);
485  const int start_byte_index = pango_layout_iter_get_index(cluster_iter);
486  const int end_byte_index = cluster_start_to_end_index[start_byte_index];
487  string cluster_text = string(text + start_byte_index,
488  end_byte_index - start_byte_index);
489  if (cluster_text.size() && cluster_text[0] == '\n') {
490  tlog(2, "Skipping newlines at start of text.\n");
491  continue;
492  }
493  if (!cluster_rect.width || !cluster_rect.height ||
494  IsUTF8Whitespace(cluster_text.c_str())) {
495  tlog(2, "Skipping whitespace with boxdim (%d,%d) '%s'\n",
496  cluster_rect.width, cluster_rect.height, cluster_text.c_str());
497  BoxChar* boxchar = new BoxChar(" ", 1);
498  boxchar->set_page(page_);
499  start_byte_to_box[start_byte_index] = boxchar;
500  continue;
501  }
502  // Prepare a boxchar for addition at this byte position.
503  tlog(2, "[%d %d], %d, %d : start_byte=%d end_byte=%d : '%s'\n",
504  cluster_rect.x, cluster_rect.y,
505  cluster_rect.width, cluster_rect.height,
506  start_byte_index, end_byte_index,
507  cluster_text.c_str());
508  ASSERT_HOST_MSG(cluster_rect.width,
509  "cluster_text:%s start_byte_index:%d\n",
510  cluster_text.c_str(), start_byte_index);
511  ASSERT_HOST_MSG(cluster_rect.height,
512  "cluster_text:%s start_byte_index:%d\n",
513  cluster_text.c_str(), start_byte_index);
514  if (box_padding_) {
515  cluster_rect.x = max(0, cluster_rect.x - box_padding_);
516  cluster_rect.width += 2 * box_padding_;
517  cluster_rect.y = max(0, cluster_rect.y - box_padding_);
518  cluster_rect.height += 2 * box_padding_;
519  }
520  if (add_ligatures_) {
521  // Make sure the output box files have ligatured text in case the font
522  // decided to use an unmapped glyph.
523  cluster_text = LigatureTable::Get()->AddLigatures(cluster_text, NULL);
524  }
525  BoxChar* boxchar = new BoxChar(cluster_text.c_str(), cluster_text.size());
526  boxchar->set_page(page_);
527  boxchar->AddBox(cluster_rect.x, cluster_rect.y,
528  cluster_rect.width, cluster_rect.height);
529  start_byte_to_box[start_byte_index] = boxchar;
530  } while (pango_layout_iter_next_cluster(cluster_iter));
531  pango_layout_iter_free(cluster_iter);
532 
533  // There is a subtle bug in the cluster text reported by the PangoLayoutIter
534  // on ligatured characters (eg. The word "Lam-Aliph" in arabic). To work
535  // around this, we use text reported using the PangoGlyphIter which is
536  // accurate.
537  // TODO(ranjith): Revisit whether this is still needed in newer versions of
538  // pango.
539  vector<string> cluster_text;
540  if (GetClusterStrings(&cluster_text)) {
541  ASSERT_HOST(cluster_text.size() == start_byte_to_box.size());
542  int ind = 0;
543  for (map<int, BoxChar*>::iterator it = start_byte_to_box.begin();
544  it != start_byte_to_box.end(); ++it, ++ind) {
545  it->second->mutable_ch()->swap(cluster_text[ind]);
546  }
547  }
548 
549  // Append to the boxchars list in byte order.
550  vector<BoxChar*> page_boxchars;
551  page_boxchars.reserve(start_byte_to_box.size());
552  string last_ch;
553  for (map<int, BoxChar*>::const_iterator it = start_byte_to_box.begin();
554  it != start_byte_to_box.end(); ++it) {
555  if (it->second->ch() == kWordJoinerUTF8) {
556  // Skip zero-width joiner characters (ZWJs) here.
557  delete it->second;
558  } else {
559  page_boxchars.push_back(it->second);
560  }
561  }
562  CorrectBoxPositionsToLayout(&page_boxchars);
563 
565  for (map<int, BoxChar*>::iterator it = start_byte_to_box.begin();
566  it != start_byte_to_box.end(); ++it) {
567  // Convert fullwidth Latin characters to their halfwidth forms.
568  string half(ConvertFullwidthLatinToBasicLatin(it->second->ch()));
569  it->second->mutable_ch()->swap(half);
570  }
571  }
572 
573  // Merge the character boxes into word boxes if we are rendering n-grams.
574  if (output_word_boxes_) {
575  MergeBoxCharsToWords(&page_boxchars);
576  }
577 
578  boxchars_.insert(boxchars_.end(), page_boxchars.begin(), page_boxchars.end());
579 
580  // Compute the page bounding box
581  Box* page_box = NULL;
582  Boxa* all_boxes = NULL;
583  for (int i = 0; i < page_boxchars.size(); ++i) {
584  if (page_boxchars[i]->box() == NULL) continue;
585  if (all_boxes == NULL)
586  all_boxes = boxaCreate(0);
587  boxaAddBox(all_boxes, page_boxchars[i]->mutable_box(), L_CLONE);
588  }
589  boxaGetExtent(all_boxes, NULL, NULL, &page_box);
590  boxaDestroy(&all_boxes);
591  if (page_boxes_ == NULL)
592  page_boxes_ = boxaCreate(0);
593  boxaAddBox(page_boxes_, page_box, L_INSERT);
594 }
string AddLigatures(const string &str, const PangoFontInfo *font) const
bool IsUTF8Whitespace(const char *text)
Definition: normstrngs.cpp:182
#define ASSERT_HOST_MSG(x, msg...)
Definition: errcode.h:98
vector< BoxChar * > boxchars_
#define ASSERT_HOST(x)
Definition: errcode.h:84
static LigatureTable * Get()
bool GetClusterStrings(vector< string > *cluster_text)
static string ConvertFullwidthLatinToBasicLatin(const string &text)
#define tlog(level,...)
Definition: tlog.h:33
#define NULL
Definition: host.h:144
void CorrectBoxPositionsToLayout(vector< BoxChar * > *boxchars)
string tesseract::StringRenderer::ConvertBasicLatinToFullwidthLatin ( const string &  text)
static

Definition at line 688 of file stringrenderer.cpp.

688  {
689  string full_str;
690  const UNICHAR::const_iterator it_end = UNICHAR::end(str.c_str(),
691  str.length());
692  for (UNICHAR::const_iterator it = UNICHAR::begin(str.c_str(), str.length());
693  it != it_end; ++it) {
694  // Convert printable and non-space 7-bit ASCII characters to
695  // their fullwidth forms.
696  if (IsInterchangeValid7BitAscii(*it) && isprint(*it) && !isspace(*it)) {
697  // Convert by adding 0xFEE0 to the codepoint of 7-bit ASCII.
698  char32 full_char = *it + 0xFEE0;
699  full_str.append(EncodeAsUTF8(full_char));
700  } else {
701  full_str.append(it.utf8_data(), it.utf8_len());
702  }
703  }
704  return full_str;
705 }
static const_iterator begin(const char *utf8_str, const int byte_length)
Definition: unichar.cpp:200
signed int char32
Definition: normstrngs.h:27
static const_iterator end(const char *utf8_str, const int byte_length)
Definition: unichar.cpp:204
bool IsInterchangeValid7BitAscii(const char32 ch)
Definition: normstrngs.cpp:232
string tesseract::StringRenderer::ConvertFullwidthLatinToBasicLatin ( const string &  text)
static

Definition at line 708 of file stringrenderer.cpp.

708  {
709  string half_str;
710  UNICHAR::const_iterator it_end = UNICHAR::end(str.c_str(), str.length());
711  for (UNICHAR::const_iterator it = UNICHAR::begin(str.c_str(), str.length());
712  it != it_end; ++it) {
713  char32 half_char = FullwidthToHalfwidth(*it);
714  // Convert fullwidth Latin characters to their halfwidth forms
715  // only if halfwidth forms are printable and non-space 7-bit ASCII.
716  if (IsInterchangeValid7BitAscii(half_char) &&
717  isprint(half_char) && !isspace(half_char)) {
718  half_str.append(EncodeAsUTF8(half_char));
719  } else {
720  half_str.append(it.utf8_data(), it.utf8_len());
721  }
722  }
723  return half_str;
724 }
static const_iterator begin(const char *utf8_str, const int byte_length)
Definition: unichar.cpp:200
signed int char32
Definition: normstrngs.h:27
char32 FullwidthToHalfwidth(const char32 ch)
Definition: normstrngs.cpp:239
static const_iterator end(const char *utf8_str, const int byte_length)
Definition: unichar.cpp:204
bool IsInterchangeValid7BitAscii(const char32 ch)
Definition: normstrngs.cpp:232
void tesseract::StringRenderer::CorrectBoxPositionsToLayout ( vector< BoxChar * > *  boxchars)
protected

Definition at line 597 of file stringrenderer.cpp.

597  {
598  if (vertical_text_) {
599  const double rotation = - pango_gravity_to_rotation(
600  pango_context_get_base_gravity(pango_layout_get_context(layout_)));
603  0, boxchars->size(), boxchars);
604  } else {
606  }
607 }
static void TranslateBoxes(int xshift, int yshift, vector< BoxChar * > *boxes)
Definition: boxchar.cpp:52
static void RotateBoxes(float rotation, int xcenter, int ycenter, int start_box, int end_box, vector< BoxChar * > *boxes)
Definition: boxchar.cpp:272
int tesseract::StringRenderer::FindFirstPageBreakOffset ( const char *  text,
int  text_length 
)
protected

Definition at line 276 of file stringrenderer.cpp.

277  {
278  if (!text_length) return 0;
279  const int max_height = (page_height_ - 2 * v_margin_);
280  const int max_width = (page_width_ - 2 * h_margin_);
281  const int max_layout_height = vertical_text_ ? max_width : max_height;
282 
283  UNICHAR::const_iterator it = UNICHAR::begin(text, text_length);
284  const UNICHAR::const_iterator it_end = UNICHAR::end(text, text_length);
285  const int kMaxUnicodeBufLength = 15000;
286  for (int i = 0; i < kMaxUnicodeBufLength && it != it_end; ++it, ++i);
287  int buf_length = it.utf8_data() - text;
288  tlog(1, "len = %d buf_len = %d\n", text_length, buf_length);
289  pango_layout_set_text(layout_, text, buf_length);
290 
291  PangoLayoutIter* line_iter = NULL;
292  { // Fontconfig caches some info here that is not freed before exit.
294  line_iter = pango_layout_get_iter(layout_);
295  }
296  bool first_page = true;
297  int page_top = 0;
298  int offset = buf_length;
299  do {
300  // Get bounding box of the current line
301  PangoRectangle line_ink_rect;
302  pango_layout_iter_get_line_extents(line_iter, &line_ink_rect, NULL);
303  pango_extents_to_pixels(&line_ink_rect, NULL);
304  PangoLayoutLine* line = pango_layout_iter_get_line_readonly(line_iter);
305  if (first_page) {
306  page_top = line_ink_rect.y;
307  first_page = false;
308  }
309  int line_bottom = line_ink_rect.y + line_ink_rect.height;
310  if (line_bottom - page_top > max_layout_height) {
311  offset = line->start_index;
312  tlog(1, "Found offset = %d\n", offset);
313  break;
314  }
315  } while (pango_layout_iter_next_line(line_iter));
316  pango_layout_iter_free(line_iter);
317  return offset;
318 }
#define DISABLE_HEAP_LEAK_CHECK
Definition: util.h:63
static const_iterator begin(const char *utf8_str, const int byte_length)
Definition: unichar.cpp:200
#define tlog(level,...)
Definition: tlog.h:33
#define NULL
Definition: host.h:144
const char * utf8_data() const
Definition: unichar.h:130
static const_iterator end(const char *utf8_str, const int byte_length)
Definition: unichar.cpp:204
const PangoFontInfo& tesseract::StringRenderer::font ( ) const
inline

Definition at line 126 of file stringrenderer.h.

126  {
127  return font_;
128  }
void tesseract::StringRenderer::FreePangoCairo ( )
protected

Definition at line 215 of file stringrenderer.cpp.

215  {
216  if (layout_) {
217  g_object_unref(layout_);
218  layout_ = NULL;
219  }
220  if (cr_) {
221  cairo_destroy(cr_);
222  cr_ = NULL;
223  }
224  if (surface_) {
225  cairo_surface_destroy(surface_);
226  surface_ = NULL;
227  }
228 }
cairo_surface_t * surface_
#define NULL
Definition: host.h:144
const vector< BoxChar * > & tesseract::StringRenderer::GetBoxes ( ) const

Definition at line 320 of file stringrenderer.cpp.

320  {
321  return boxchars_;
322 }
vector< BoxChar * > boxchars_
bool tesseract::StringRenderer::GetClusterStrings ( vector< string > *  cluster_text)
protected

Definition at line 347 of file stringrenderer.cpp.

347  {
348  map<int, string> start_byte_to_text;
349  PangoLayoutIter* run_iter = pango_layout_get_iter(layout_);
350  const char* full_text = pango_layout_get_text(layout_);
351  do {
352  PangoLayoutRun* run = pango_layout_iter_get_run_readonly(run_iter);
353  if (!run) {
354  // End of line NULL run marker
355  tlog(2, "Found end of line marker\n");
356  continue;
357  }
358  PangoGlyphItemIter cluster_iter;
359  gboolean have_cluster;
360  for (have_cluster = pango_glyph_item_iter_init_start(&cluster_iter,
361  run, full_text);
362  have_cluster;
363  have_cluster = pango_glyph_item_iter_next_cluster(&cluster_iter)) {
364  const int start_byte_index = cluster_iter.start_index;
365  const int end_byte_index = cluster_iter.end_index;
366  string text = string(full_text + start_byte_index,
367  end_byte_index - start_byte_index);
368  if (IsUTF8Whitespace(text.c_str())) {
369  tlog(2, "Found whitespace\n");
370  text = " ";
371  }
372  tlog(2, "start_byte=%d end_byte=%d : '%s'\n", start_byte_index,
373  end_byte_index, text.c_str());
374  if (add_ligatures_) {
375  // Make sure the output box files have ligatured text in case the font
376  // decided to use an unmapped glyph.
377  text = LigatureTable::Get()->AddLigatures(text, NULL);
378  }
379  start_byte_to_text[start_byte_index] = text;
380  }
381  } while (pango_layout_iter_next_run(run_iter));
382  pango_layout_iter_free(run_iter);
383 
384  cluster_text->clear();
385  for (map<int, string>::const_iterator it = start_byte_to_text.begin();
386  it != start_byte_to_text.end(); ++it) {
387  cluster_text->push_back(it->second);
388  }
389  return cluster_text->size();
390 }
string AddLigatures(const string &str, const PangoFontInfo *font) const
bool IsUTF8Whitespace(const char *text)
Definition: normstrngs.cpp:182
static LigatureTable * Get()
#define tlog(level,...)
Definition: tlog.h:33
#define NULL
Definition: host.h:144
Boxa * tesseract::StringRenderer::GetPageBoxes ( ) const

Definition at line 324 of file stringrenderer.cpp.

324  {
325  return page_boxes_;
326 }
const int tesseract::StringRenderer::h_margin ( ) const
inline

Definition at line 129 of file stringrenderer.h.

129  {
130  return h_margin_;
131  }
void tesseract::StringRenderer::InitPangoCairo ( )
protected

Definition at line 156 of file stringrenderer.cpp.

156  {
157  FreePangoCairo();
158  surface_ = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, page_width_,
159  page_height_);
160  cr_ = cairo_create(surface_);
161  {
163  layout_ = pango_cairo_create_layout(cr_);
164  }
165 
166  if (vertical_text_) {
167  PangoContext* context = pango_layout_get_context(layout_);
168  pango_context_set_base_gravity(context, PANGO_GRAVITY_EAST);
169  if (gravity_hint_strong_) {
170  pango_context_set_gravity_hint(context, PANGO_GRAVITY_HINT_STRONG);
171  }
172  pango_layout_context_changed(layout_);
173  }
174 
176 }
cairo_surface_t * surface_
#define DISABLE_HEAP_LEAK_CHECK
Definition: util.h:63
string tesseract::StringRenderer::InsertWordJoiners ( const string &  text)
static

Definition at line 665 of file stringrenderer.cpp.

665  {
666  string out_str;
667  const UNICHAR::const_iterator it_end = UNICHAR::end(text.c_str(),
668  text.length());
669  for (UNICHAR::const_iterator it = UNICHAR::begin(text.c_str(), text.length());
670  it != it_end; ++it) {
671  // Add the symbol to the output string.
672  out_str.append(it.utf8_data(), it.utf8_len());
673  // Check the next symbol.
674  UNICHAR::const_iterator next_it = it;
675  ++next_it;
676  bool next_char_is_boundary = (next_it == it_end || *next_it == ' ');
677  bool next_char_is_combiner = (next_it == it_end) ?
678  false : IsCombiner(*next_it);
679  if (*it != ' ' && *it != '\n' && !next_char_is_boundary &&
680  !next_char_is_combiner) {
681  out_str += kWordJoinerUTF8;
682  }
683  }
684  return out_str;
685 }
static const_iterator begin(const char *utf8_str, const int byte_length)
Definition: unichar.cpp:200
static const_iterator end(const char *utf8_str, const int byte_length)
Definition: unichar.cpp:204
int tesseract::StringRenderer::RenderAllFontsToImage ( double  min_coverage,
const char *  text,
int  text_length,
string *  font_used,
Pix **  pix 
)

Definition at line 827 of file stringrenderer.cpp.

829  {
830  *image = NULL;
831  // Select a suitable font to render the title with.
832  const char kTitleTemplate[] = "%s : %d hits = %.2f%%, raw = %d = %.2f%%";
833  string title_font;
834  if (!FontUtils::SelectFont(kTitleTemplate, strlen(kTitleTemplate),
835  &title_font, NULL)) {
836  tprintf("WARNING: Could not find a font to render image title with!\n");
837  title_font = "Arial";
838  }
839  title_font += " 8";
840  tlog(1, "Selected title font: %s\n", title_font.c_str());
841  if (font_used) font_used->clear();
842 
843  string orig_font = font_.DescriptionName();
844  if (char_map_.empty()) {
845  total_chars_ = 0;
846  // Fill the hash table and use that for computing which fonts to use.
847  for (UNICHAR::const_iterator it = UNICHAR::begin(text, text_length);
848  it != UNICHAR::end(text, text_length); ++it) {
849  ++total_chars_;
850  ++char_map_[*it];
851  }
852  tprintf("Total chars = %d\n", total_chars_);
853  }
854  const vector<string>& all_fonts = FontUtils::ListAvailableFonts();
855  for (int i = font_index_; i < all_fonts.size(); ++i) {
856  ++font_index_;
857  int raw_score = 0;
858  int ok_chars = FontUtils::FontScore(char_map_, all_fonts[i], &raw_score,
859  NULL);
860  if (ok_chars > 0 && ok_chars >= total_chars_ * min_coverage) {
861  set_font(all_fonts[i]);
862  int offset = RenderToBinaryImage(text, text_length, 128, image);
863  ClearBoxes(); // Get rid of them as they are garbage.
864  const int kMaxTitleLength = 1024;
865  char title[kMaxTitleLength];
866  snprintf(title, kMaxTitleLength, kTitleTemplate,
867  all_fonts[i].c_str(), ok_chars,
868  100.0 * ok_chars / total_chars_, raw_score,
869  100.0 * raw_score / char_map_.size());
870  tprintf("%s\n", title);
871  // This is a good font! Store the offset to return once we've tried all
872  // the fonts.
873  if (offset) {
874  last_offset_ = offset;
875  if (font_used) *font_used = all_fonts[i];
876  }
877  // Add the font to the image.
878  set_font(title_font);
879  v_margin_ /= 8;
880  Pix* title_image = NULL;
881  RenderToBinaryImage(title, strlen(title), 128, &title_image);
882  pixOr(*image, *image, title_image);
883  pixDestroy(&title_image);
884 
885  v_margin_ *= 8;
886  set_font(orig_font);
887  // We return the real offset only after cycling through the list of fonts.
888  return 0;
889  } else {
890  tprintf("Font %s failed with %d hits = %.2f%%\n",
891  all_fonts[i].c_str(), ok_chars, 100.0 * ok_chars / total_chars_);
892  }
893  }
894  font_index_ = 0;
895  char_map_.clear();
896  return last_offset_ == 0 ? -1 : last_offset_;
897 }
#define tprintf(...)
Definition: tprintf.h:31
static bool SelectFont(const char *utf8_word, const int utf8_len, string *font_name, vector< string > *graphemes)
int RenderToBinaryImage(const char *text, int text_length, int threshold, Pix **pix)
string DescriptionName() const
hash_map< char32, inT64 > char_map_
static const_iterator begin(const char *utf8_str, const int byte_length)
Definition: unichar.cpp:200
bool set_font(const string &desc)
static int FontScore(const unordered_map< char32, inT64 > &ch_map, const string &fontname, int *raw_score, vector< bool > *ch_flags)
#define tlog(level,...)
Definition: tlog.h:33
#define NULL
Definition: host.h:144
static const vector< string > & ListAvailableFonts()
static const_iterator end(const char *utf8_str, const int byte_length)
Definition: unichar.cpp:204
int tesseract::StringRenderer::RenderToBinaryImage ( const char *  text,
int  text_length,
int  threshold,
Pix **  pix 
)

Definition at line 647 of file stringrenderer.cpp.

648  {
649  Pix *orig_pix = NULL;
650  int offset = RenderToImage(text, text_length, &orig_pix);
651  if (orig_pix) {
652  Pix* gray_pix = pixConvertTo8(orig_pix, false);
653  pixDestroy(&orig_pix);
654  *pix = pixThresholdToBinary(gray_pix, threshold);
655  pixDestroy(&gray_pix);
656  } else {
657  *pix = orig_pix;
658  }
659  return offset;
660 }
#define NULL
Definition: host.h:144
int RenderToImage(const char *text, int text_length, Pix **pix)
int tesseract::StringRenderer::RenderToGrayscaleImage ( const char *  text,
int  text_length,
Pix **  pix 
)

Definition at line 636 of file stringrenderer.cpp.

637  {
638  Pix *orig_pix = NULL;
639  int offset = RenderToImage(text, text_length, &orig_pix);
640  if (orig_pix) {
641  *pix = pixConvertTo8(orig_pix, false);
642  pixDestroy(&orig_pix);
643  }
644  return offset;
645 }
#define NULL
Definition: host.h:144
int RenderToImage(const char *text, int text_length, Pix **pix)
int tesseract::StringRenderer::RenderToImage ( const char *  text,
int  text_length,
Pix **  pix 
)

Definition at line 727 of file stringrenderer.cpp.

728  {
729  if (pix && *pix) pixDestroy(pix);
730  InitPangoCairo();
731 
732  const int page_offset = FindFirstPageBreakOffset(text, text_length);
733  if (!page_offset) {
734  return 0;
735  }
736  start_box_ = boxchars_.size();
737 
738  if (!vertical_text_) {
739  // Translate by the specified margin
740  cairo_translate(cr_, h_margin_, v_margin_);
741  } else {
742  // Vertical text rendering is achieved by a two-step process of first
743  // performing regular horizontal layout with character orientation set to
744  // EAST, and then translating and rotating the layout before rendering onto
745  // the desired image surface. The settings required for the former step are
746  // done within InitPangoCairo().
747  //
748  // Translate to the top-right margin of page
749  cairo_translate(cr_, page_width_ - h_margin_, v_margin_);
750  // Rotate the layout
751  double rotation = - pango_gravity_to_rotation(
752  pango_context_get_base_gravity(pango_layout_get_context(layout_)));
753  tlog(2, "Rotating by %f radians\n", rotation);
754  cairo_rotate(cr_, rotation);
755  pango_cairo_update_layout(cr_, layout_);
756  }
757  string page_text(text, page_offset);
759  // Convert Basic Latin to their fullwidth forms.
760  page_text = ConvertBasicLatinToFullwidthLatin(page_text);
761  }
763  StripUnrenderableWords(&page_text);
764  }
765  if (drop_uncovered_chars_ &&
766  !font_.CoversUTF8Text(page_text.c_str(), page_text.length())) {
767  int num_dropped = font_.DropUncoveredChars(&page_text);
768  if (num_dropped) {
769  tprintf("WARNING: Dropped %d uncovered characters\n", num_dropped);
770  }
771  }
772  if (add_ligatures_) {
773  // Add ligatures wherever possible, including custom ligatures.
774  page_text = LigatureTable::Get()->AddLigatures(page_text, &font_);
775  }
776  if (underline_start_prob_ > 0) {
777  SetWordUnderlineAttributes(page_text);
778  }
779 
780  pango_layout_set_text(layout_, page_text.c_str(), page_text.length());
781 
782  if (pix) {
783  // Set a white background for the target image surface.
784  cairo_set_source_rgb(cr_, 1.0, 1.0, 1.0); // sets drawing colour to white
785  // Fill the surface with the active colour (if you don't do this, you will
786  // be given a surface with a transparent background to draw on)
787  cairo_paint(cr_);
788  // Set the ink color to black
789  cairo_set_source_rgb(cr_, pen_color_[0], pen_color_[1], pen_color_[2]);
790  // If the target surface or transformation properties of the cairo instance
791  // have changed, update the pango layout to reflect this
792  pango_cairo_update_layout(cr_, layout_);
793  {
794  DISABLE_HEAP_LEAK_CHECK; // for Fontconfig
795  // Draw the pango layout onto the cairo surface
796  pango_cairo_show_layout(cr_, layout_);
797  }
799  }
801  FreePangoCairo();
802  // Update internal state variables.
803  ++page_;
804  return page_offset;
805 }
cairo_surface_t * surface_
#define DISABLE_HEAP_LEAK_CHECK
Definition: util.h:63
string AddLigatures(const string &str, const PangoFontInfo *font) const
bool CoversUTF8Text(const char *utf8_text, int byte_length) const
#define tprintf(...)
Definition: tprintf.h:31
int DropUncoveredChars(string *utf8_text) const
vector< BoxChar * > boxchars_
int StripUnrenderableWords(string *utf8_text) const
static LigatureTable * Get()
int FindFirstPageBreakOffset(const char *text, int text_length)
void SetWordUnderlineAttributes(const string &page_text)
static string ConvertBasicLatinToFullwidthLatin(const string &text)
Pix * CairoARGB32ToPixFormat(cairo_surface_t *surface)
#define tlog(level,...)
Definition: tlog.h:33
void tesseract::StringRenderer::RotatePageBoxes ( float  rotation)

Definition at line 328 of file stringrenderer.cpp.

328  {
329  BoxChar::RotateBoxes(rotation, page_width_ / 2, page_height_ / 2,
330  start_box_, boxchars_.size(), &boxchars_);
331 }
vector< BoxChar * > boxchars_
static void RotateBoxes(float rotation, int xcenter, int ycenter, int start_box, int end_box, vector< BoxChar * > *boxes)
Definition: boxchar.cpp:272
void tesseract::StringRenderer::set_add_ligatures ( bool  add_ligatures)
inline

Definition at line 111 of file stringrenderer.h.

111  {
112  add_ligatures_ = add_ligatures;
113  }
void tesseract::StringRenderer::set_box_padding ( int  val)
inline

Definition at line 96 of file stringrenderer.h.

96  {
97  box_padding_ = val;
98  }
void tesseract::StringRenderer::set_char_spacing ( double  char_spacing)
inline

Definition at line 67 of file stringrenderer.h.

67  {
68  char_spacing_ = char_spacing;
69  }
void tesseract::StringRenderer::set_drop_uncovered_chars ( bool  val)
inline

Definition at line 99 of file stringrenderer.h.

99  {
100  drop_uncovered_chars_ = val;
101  }
bool tesseract::StringRenderer::set_font ( const string &  desc)

Definition at line 132 of file stringrenderer.cpp.

132  {
133  bool success = font_.ParseFontDescriptionName(desc);
135  return success;
136 }
bool ParseFontDescriptionName(const string &name)
void set_resolution(const int resolution)
void tesseract::StringRenderer::set_gravity_hint_strong ( bool  gravity_hint_strong)
inline

Definition at line 77 of file stringrenderer.h.

77  {
78  gravity_hint_strong_ = gravity_hint_strong;
79  }
void tesseract::StringRenderer::set_h_margin ( const int  h_margin)
inline

Definition at line 120 of file stringrenderer.h.

120  {
122  }
const int h_margin() const
void tesseract::StringRenderer::set_leading ( int  leading)
inline

Definition at line 70 of file stringrenderer.h.

70  {
71  leading_ = leading;
72  }
void tesseract::StringRenderer::set_output_word_boxes ( bool  val)
inline

Definition at line 105 of file stringrenderer.h.

105  {
106  output_word_boxes_ = val;
107  }
void tesseract::StringRenderer::set_page ( int  page)
inline

Definition at line 93 of file stringrenderer.h.

93  {
94  page_ = page;
95  }
void tesseract::StringRenderer::set_pen_color ( double  r,
double  g,
double  b 
)
inline

Definition at line 115 of file stringrenderer.h.

115  {
116  pen_color_[0] = r;
117  pen_color_[1] = g;
118  pen_color_[2] = b;
119  }
void tesseract::StringRenderer::set_render_fullwidth_latin ( bool  render_fullwidth_latin)
inline

Definition at line 80 of file stringrenderer.h.

80  {
81  render_fullwidth_latin_ = render_fullwidth_latin;
82  }
void tesseract::StringRenderer::set_resolution ( const int  resolution)

Definition at line 138 of file stringrenderer.cpp.

138  {
139  resolution_ = resolution;
140  font_.set_resolution(resolution);
141 }
void set_resolution(const int resolution)
void tesseract::StringRenderer::set_strip_unrenderable_words ( bool  val)
inline

Definition at line 102 of file stringrenderer.h.

102  {
104  }
void tesseract::StringRenderer::set_underline_continuation_prob ( const double  frac)

Definition at line 147 of file stringrenderer.cpp.

147  {
148  underline_continuation_prob_ = min(max(frac, 0.0), 1.0);
149 }
void tesseract::StringRenderer::set_underline_start_prob ( const double  frac)

Definition at line 143 of file stringrenderer.cpp.

143  {
144  underline_start_prob_ = min(max(frac, 0.0), 1.0);
145 }
void tesseract::StringRenderer::set_underline_style ( const PangoUnderline  style)
inline

Definition at line 90 of file stringrenderer.h.

90  {
91  underline_style_ = style;
92  }
PangoUnderline underline_style_
void tesseract::StringRenderer::set_v_margin ( const int  v_margin)
inline

Definition at line 123 of file stringrenderer.h.

123  {
125  }
const int v_margin() const
void tesseract::StringRenderer::set_vertical_text ( bool  vertical_text)
inline

Definition at line 74 of file stringrenderer.h.

74  {
75  vertical_text_ = vertical_text;
76  }
void tesseract::StringRenderer::SetLayoutProperties ( )
protected

Definition at line 178 of file stringrenderer.cpp.

178  {
179  string font_desc = font_.DescriptionName();
180  // Specify the font via a description name
181  PangoFontDescription *desc =
182  pango_font_description_from_string(font_desc.c_str());
183  // Assign the font description to the layout
184  pango_layout_set_font_description(layout_, desc);
185  pango_font_description_free(desc); // free the description
186  pango_cairo_context_set_resolution(pango_layout_get_context(layout_),
187  resolution_);
188 
189  int max_width = page_width_ - 2 * h_margin_;
190  int max_height = page_height_ - 2 * v_margin_;
191  tlog(3, "max_width = %d, max_height = %d\n", max_width, max_height);
192  if (vertical_text_) {
193  swap(max_width, max_height);
194  }
195  pango_layout_set_width(layout_, max_width * PANGO_SCALE);
196  pango_layout_set_wrap(layout_, PANGO_WRAP_WORD);
197 
198  // Adjust character spacing
199  PangoAttrList* attr_list = pango_attr_list_new();
200  if (char_spacing_) {
201  PangoAttribute* spacing_attr = pango_attr_letter_spacing_new(
202  static_cast<int>(char_spacing_ * PANGO_SCALE + 0.5));
203  spacing_attr->start_index = 0;
204  spacing_attr->end_index = static_cast<guint>(-1);
205  pango_attr_list_change(attr_list, spacing_attr);
206  }
207  pango_layout_set_attributes(layout_, attr_list);
208  pango_attr_list_unref(attr_list);
209  // Adjust line spacing
210  if (leading_) {
211  pango_layout_set_spacing(layout_, leading_ * PANGO_SCALE);
212  }
213 }
string DescriptionName() const
#define tlog(level,...)
Definition: tlog.h:33
void tesseract::StringRenderer::SetWordUnderlineAttributes ( const string &  page_text)
protected

Definition at line 230 of file stringrenderer.cpp.

230  {
231  if (underline_start_prob_ == 0) return;
232  PangoAttrList* attr_list = pango_layout_get_attributes(layout_);
233 
234  const char* text = page_text.c_str();
235  int offset = 0;
236  TRand rand;
237  bool started_underline = false;
238  PangoAttribute* und_attr = nullptr;
239 
240  while (offset < page_text.length()) {
241  offset += SpanUTF8Whitespace(text + offset);
242  if (offset == page_text.length()) break;
243 
244  int word_start = offset;
245  int word_len = SpanUTF8NotWhitespace(text + offset);
246  offset += word_len;
247  if (started_underline) {
248  // Should we continue the underline to the next word?
249  if (RandBool(underline_continuation_prob_, &rand)) {
250  // Continue the current underline to this word.
251  und_attr->end_index = word_start + word_len;
252  } else {
253  // Otherwise end the current underline attribute at the end of the
254  // previous word.
255  pango_attr_list_insert(attr_list, und_attr);
256  started_underline = false;
257  und_attr = nullptr;
258  }
259  }
260  if (!started_underline && RandBool(underline_start_prob_, &rand)) {
261  // Start a new underline attribute
262  und_attr = pango_attr_underline_new(underline_style_);
263  und_attr->start_index = word_start;
264  und_attr->end_index = word_start + word_len;
265  started_underline = true;
266  }
267  }
268  // Finish the current underline attribute at the end of the page.
269  if (started_underline) {
270  und_attr->end_index = page_text.length();
271  pango_attr_list_insert(attr_list, und_attr);
272  }
273 }
PangoUnderline underline_style_
int SpanUTF8Whitespace(const char *text)
Definition: normstrngs.cpp:186
int SpanUTF8NotWhitespace(const char *text)
Definition: normstrngs.cpp:197
int tesseract::StringRenderer::StripUnrenderableWords ( string *  utf8_text) const

Definition at line 609 of file stringrenderer.cpp.

609  {
610  string output_text;
611  const char* text = utf8_text->c_str();
612  int offset = 0;
613  int num_dropped = 0;
614  while (offset < utf8_text->length()) {
615  int space_len = SpanUTF8Whitespace(text + offset);
616  output_text.append(text + offset, space_len);
617  offset += space_len;
618  if (offset == utf8_text->length()) break;
619 
620  int word_len = SpanUTF8NotWhitespace(text + offset);
621  if (font_.CanRenderString(text + offset, word_len)) {
622  output_text.append(text + offset, word_len);
623  } else {
624  ++num_dropped;
625  }
626  offset += word_len;
627  }
628  utf8_text->swap(output_text);
629 
630  if (num_dropped > 0) {
631  tprintf("Stripped %d unrenderable words\n", num_dropped);
632  }
633  return num_dropped;
634 }
#define tprintf(...)
Definition: tprintf.h:31
int SpanUTF8Whitespace(const char *text)
Definition: normstrngs.cpp:186
int SpanUTF8NotWhitespace(const char *text)
Definition: normstrngs.cpp:197
bool CanRenderString(const char *utf8_word, int len, vector< string > *graphemes) const
const int tesseract::StringRenderer::v_margin ( ) const
inline

Definition at line 132 of file stringrenderer.h.

132  {
133  return v_margin_;
134  }
void tesseract::StringRenderer::WriteAllBoxes ( const string &  filename)

Definition at line 341 of file stringrenderer.cpp.

341  {
344 }
vector< BoxChar * > boxchars_
static void WriteTesseractBoxFile(const string &name, int height, const vector< BoxChar * > &boxes)
Definition: boxchar.cpp:292
static void PrepareToWrite(vector< BoxChar * > *boxes)
Definition: boxchar.cpp:65

Member Data Documentation

bool tesseract::StringRenderer::add_ligatures_
protected

Definition at line 191 of file stringrenderer.h.

int tesseract::StringRenderer::box_padding_
protected

Definition at line 204 of file stringrenderer.h.

vector<BoxChar*> tesseract::StringRenderer::boxchars_
protected

Definition at line 203 of file stringrenderer.h.

hash_map<char32, inT64> tesseract::StringRenderer::char_map_
protected

Definition at line 209 of file stringrenderer.h.

double tesseract::StringRenderer::char_spacing_
protected

Definition at line 180 of file stringrenderer.h.

cairo_t* tesseract::StringRenderer::cr_
protected

Definition at line 195 of file stringrenderer.h.

bool tesseract::StringRenderer::drop_uncovered_chars_
protected

Definition at line 189 of file stringrenderer.h.

PangoFontInfo tesseract::StringRenderer::font_
protected

Definition at line 175 of file stringrenderer.h.

int tesseract::StringRenderer::font_index_
protected

Definition at line 211 of file stringrenderer.h.

bool tesseract::StringRenderer::gravity_hint_strong_
protected

Definition at line 183 of file stringrenderer.h.

int tesseract::StringRenderer::h_margin_
protected

Definition at line 177 of file stringrenderer.h.

int tesseract::StringRenderer::last_offset_
protected

Definition at line 212 of file stringrenderer.h.

PangoLayout* tesseract::StringRenderer::layout_
protected

Definition at line 196 of file stringrenderer.h.

int tesseract::StringRenderer::leading_
protected

Definition at line 181 of file stringrenderer.h.

bool tesseract::StringRenderer::output_word_boxes_
protected

Definition at line 192 of file stringrenderer.h.

int tesseract::StringRenderer::page_
protected

Definition at line 200 of file stringrenderer.h.

Boxa* tesseract::StringRenderer::page_boxes_
protected

Definition at line 206 of file stringrenderer.h.

int tesseract::StringRenderer::page_height_
protected

Definition at line 177 of file stringrenderer.h.

int tesseract::StringRenderer::page_width_
protected

Definition at line 177 of file stringrenderer.h.

int tesseract::StringRenderer::pen_color_[3]
protected

Definition at line 179 of file stringrenderer.h.

bool tesseract::StringRenderer::render_fullwidth_latin_
protected

Definition at line 184 of file stringrenderer.h.

int tesseract::StringRenderer::resolution_
protected

Definition at line 181 of file stringrenderer.h.

int tesseract::StringRenderer::start_box_
protected

Definition at line 199 of file stringrenderer.h.

bool tesseract::StringRenderer::strip_unrenderable_words_
protected

Definition at line 190 of file stringrenderer.h.

cairo_surface_t* tesseract::StringRenderer::surface_
protected

Definition at line 194 of file stringrenderer.h.

int tesseract::StringRenderer::total_chars_
protected

Definition at line 210 of file stringrenderer.h.

double tesseract::StringRenderer::underline_continuation_prob_
protected

Definition at line 186 of file stringrenderer.h.

double tesseract::StringRenderer::underline_start_prob_
protected

Definition at line 185 of file stringrenderer.h.

PangoUnderline tesseract::StringRenderer::underline_style_
protected

Definition at line 187 of file stringrenderer.h.

int tesseract::StringRenderer::v_margin_
protected

Definition at line 177 of file stringrenderer.h.

bool tesseract::StringRenderer::vertical_text_
protected

Definition at line 182 of file stringrenderer.h.


The documentation for this class was generated from the following files: