1 /**********************************************************************
2  * File:        stringrenderer.h
3  * Description: Class for rendering UTF-8 text to an image, and retrieving
4  *              bounding boxes around each grapheme cluster.
5  *
6  *              Instances are created using a font description string
7  *              (eg. "Arial Italic 12"; see pango_font_info.h for the format)
8  *              and the page dimensions. Other renderer properties such as
9  *              spacing, ligaturization, as well a preprocessing behavior such
10  *              as removal of unrenderable words and a special n-gram mode may
11  *              be set using respective set_* methods.
12  *
13  * Author:      Ranjith Unnikrishnan
14  *
15  * (C) Copyright 2013, Google Inc.
16  * Licensed under the Apache License, Version 2.0 (the "License");
17  * you may not use this file except in compliance with the License.
18  * You may obtain a copy of the License at
19  * http://www.apache.org/licenses/LICENSE-2.0
20  * Unless required by applicable law or agreed to in writing, software
21  * distributed under the License is distributed on an "AS IS" BASIS,
22  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23  * See the License for the specific language governing permissions and
24  * limitations under the License.
25  *
26  **********************************************************************/
27 
28 #ifndef TESSERACT_TRAINING_STRINGRENDERER_H_
29 #define TESSERACT_TRAINING_STRINGRENDERER_H_
30 
31 #include "export.h"
32 
33 #include "pango/pango-layout.h"
34 #include "pango/pangocairo.h"
35 #include "pango_font_info.h"
36 
37 #include "image.h"
38 
39 #include <string>
40 #include <unordered_map>
41 #include <vector>
42 
43 struct Boxa;
44 struct Pix;
45 
46 namespace tesseract {
47 
48 class BoxChar;
49 
50 class TESS_PANGO_TRAINING_API StringRenderer {
51 public:
52   StringRenderer(const std::string &font_desc, int page_width, int page_height);
53   ~StringRenderer();
54 
55   // Renders the text with the chosen font and returns the byte offset up to
56   // which the text could be rendered so as to fit the specified page
57   // dimensions.
58   int RenderToImage(const char *text, int text_length, Image *pix);
59   int RenderToGrayscaleImage(const char *text, int text_length, Image *pix);
60   int RenderToBinaryImage(const char *text, int text_length, int threshold, Image *pix);
61   // Renders a line of text with all available fonts that were able to render
62   // at least min_coverage fraction of the input text. Use 1.0 to require that
63   // a font be able to render all the text.
64   int RenderAllFontsToImage(double min_coverage, const char *text, int text_length,
65                             std::string *font_used, Image *pix);
66 
67   bool set_font(const std::string &desc);
68   // Char spacing is in PIXELS!!!!.
set_char_spacing(int char_spacing)69   void set_char_spacing(int char_spacing) {
70     char_spacing_ = char_spacing;
71   }
set_leading(int leading)72   void set_leading(int leading) {
73     leading_ = leading;
74   }
75   void set_resolution(const int resolution);
set_vertical_text(bool vertical_text)76   void set_vertical_text(bool vertical_text) {
77     vertical_text_ = vertical_text;
78   }
set_gravity_hint_strong(bool gravity_hint_strong)79   void set_gravity_hint_strong(bool gravity_hint_strong) {
80     gravity_hint_strong_ = gravity_hint_strong;
81   }
set_render_fullwidth_latin(bool render_fullwidth_latin)82   void set_render_fullwidth_latin(bool render_fullwidth_latin) {
83     render_fullwidth_latin_ = render_fullwidth_latin;
84   }
85   // Sets the probability (value in [0, 1]) of starting to render a word with an
86   // underline. This implementation consider words to be space-delimited
87   // sequences of characters.
88   void set_underline_start_prob(const double frac);
89   // Set the probability (value in [0, 1]) of continuing a started underline to
90   // the next word.
91   void set_underline_continuation_prob(const double frac);
set_underline_style(const PangoUnderline style)92   void set_underline_style(const PangoUnderline style) {
93     underline_style_ = style;
94   }
set_features(const char * features)95   void set_features(const char *features) {
96     features_ = features;
97   }
set_page(int page)98   void set_page(int page) {
99     page_ = page;
100   }
set_box_padding(int val)101   void set_box_padding(int val) {
102     box_padding_ = val;
103   }
set_drop_uncovered_chars(bool val)104   void set_drop_uncovered_chars(bool val) {
105     drop_uncovered_chars_ = val;
106   }
set_strip_unrenderable_words(bool val)107   void set_strip_unrenderable_words(bool val) {
108     strip_unrenderable_words_ = val;
109   }
set_output_word_boxes(bool val)110   void set_output_word_boxes(bool val) {
111     output_word_boxes_ = val;
112   }
113   // Before rendering the string, replace latin characters with their optional
114   // ligatured forms (such as "fi", "ffi" etc.) if the font_ covers those
115   // unicodes.
set_add_ligatures(bool add_ligatures)116   void set_add_ligatures(bool add_ligatures) {
117     add_ligatures_ = add_ligatures;
118   }
119   // Set the rgb value of the text ink. Values range in [0, 1.0]
set_pen_color(double r,double g,double b)120   void set_pen_color(double r, double g, double b) {
121     pen_color_[0] = r;
122     pen_color_[1] = g;
123     pen_color_[2] = b;
124   }
set_h_margin(const int h_margin)125   void set_h_margin(const int h_margin) {
126     h_margin_ = h_margin;
127   }
set_v_margin(const int v_margin)128   void set_v_margin(const int v_margin) {
129     v_margin_ = v_margin;
130   }
font()131   const PangoFontInfo &font() const {
132     return font_;
133   }
h_margin()134   int h_margin() const {
135     return h_margin_;
136   }
v_margin()137   int v_margin() const {
138     return v_margin_;
139   }
140 
141   // Get the boxchars of all clusters rendered thus far (or since the last call
142   // to ClearBoxes()).
143   const std::vector<BoxChar *> &GetBoxes() const;
144   // Get the rendered page bounding boxes of all pages created thus far (or
145   // since last call to ClearBoxes()).
146   Boxa *GetPageBoxes() const;
147 
148   // Rotate the boxes on the most recent page by the given rotation.
149   void RotatePageBoxes(float rotation);
150   // Delete all boxes.
151   void ClearBoxes();
152   // Returns the boxes in a boxfile string.
153   std::string GetBoxesStr();
154   // Writes the boxes to a boxfile.
155   void WriteAllBoxes(const std::string &filename);
156   // Removes space-delimited words from the string that are not renderable by
157   // the current font and returns the count of such words.
158   int StripUnrenderableWords(std::string *utf8_text) const;
159 
160   // Insert a Word Joiner symbol (U+2060) between adjacent characters, excluding
161   // spaces and combining types, in each word before rendering to ensure words
162   // are not broken across lines. The output boxchars will not contain the
163   // joiner.
164   static std::string InsertWordJoiners(const std::string &text);
165 
166   // Helper functions to convert fullwidth Latin and halfwidth Basic Latin.
167   static std::string ConvertBasicLatinToFullwidthLatin(const std::string &text);
168   static std::string ConvertFullwidthLatinToBasicLatin(const std::string &text);
169 
170 protected:
171   // Init and free local renderer objects.
172   void InitPangoCairo();
173   void FreePangoCairo();
174   // Set rendering properties.
175   void SetLayoutProperties();
176   void SetWordUnderlineAttributes(const std::string &page_text);
177   // Compute bounding boxes around grapheme clusters.
178   void ComputeClusterBoxes();
179   void CorrectBoxPositionsToLayout(std::vector<BoxChar *> *boxchars);
180   bool GetClusterStrings(std::vector<std::string> *cluster_text);
181   int FindFirstPageBreakOffset(const char *text, int text_length);
182 
183   PangoFontInfo font_;
184   // Page properties
185   int page_width_, page_height_, h_margin_, v_margin_;
186   // Text rendering properties
187   double pen_color_[3];
188   int char_spacing_;
189   int leading_, resolution_;
190   bool vertical_text_;
191   bool gravity_hint_strong_;
192   bool render_fullwidth_latin_;
193   double underline_start_prob_;
194   double underline_continuation_prob_;
195   PangoUnderline underline_style_;
196   std::string features_;
197   // Text filtering options
198   bool drop_uncovered_chars_;
199   bool strip_unrenderable_words_;
200   bool add_ligatures_;
201   bool output_word_boxes_;
202   // Pango and cairo specific objects
203   cairo_surface_t *surface_;
204   cairo_t *cr_;
205   PangoLayout *layout_;
206   // Internal state of current page number, updated on successive calls to
207   // RenderToImage()
208   int start_box_;
209   int page_;
210   // Boxes and associated text for all pages rendered with RenderToImage() since
211   // the last call to ClearBoxes().
212   std::vector<BoxChar *> boxchars_;
213   int box_padding_;
214   // Bounding boxes for pages since the last call to ClearBoxes().
215   Boxa *page_boxes_;
216 
217   // Objects cached for subsequent calls to RenderAllFontsToImage()
218   std::unordered_map<char32, int64_t> char_map_; // Time-saving char histogram.
219   int total_chars_;                              // Number in the string to be rendered.
220   unsigned int font_index_;                      // Index of next font to use in font list.
221   int last_offset_;                              // Offset returned from last successful rendering
222 
223 private:
224   StringRenderer(const StringRenderer &) = delete;
225   void operator=(const StringRenderer &) = delete;
226 };
227 } // namespace tesseract
228 
229 #endif // THIRD_PARTY_TESSERACT_TRAINING_STRINGRENDERER_H_
230