1 #ifndef LASI_H 2 #define LASI_H 3 4 /** @file 5 * Defines oPostscriptStream and PostscriptDocument and various 6 * stream manipulators. 7 */ 8 9 #include <string> 10 #include <ostream> 11 #include <sstream> 12 #include <map> 13 #include <pango/pango.h> 14 #include <ft2build.h> 15 #include FT_GLYPH_H 16 17 class FreetypeGlyphMgr; 18 class ContextMgr; 19 20 // These macros are needed for Visual C++ and other Windows compilers as well 21 // as gcc 4.x or higher with -fvisibility=hidden option. 22 // All functions/classes marked with LASIDLLIMPEXP can be imported 23 // from/exported to the Windows dll/gcc shared library. 24 // Has no impact on other platforms. 25 // Details handled identically to PLplot include/pldll.h(.in) 26 #if defined ( WIN32 ) 27 /* Visual C/C++, Borland, MinGW and Watcom */ 28 #if defined ( __VISUALC__ ) || defined ( _MSC_VER ) || defined ( __BORLANDC__ ) || defined ( __GNUC__ ) || defined ( __WATCOMC__ ) 29 #define LASIDLLEXPORT __declspec( dllexport ) 30 #define LASIDLLIMPORT __declspec( dllimport ) 31 #else 32 #define LASIDLLEXPORT 33 #define LASIDLLIMPORT 34 #endif 35 #elif defined ( __CYGWIN__ ) 36 #define LASIDLLEXPORT __declspec( dllexport ) 37 #define LASIDLLIMPORT __declspec( dllimport ) 38 #elif defined ( __GNUC__ ) && __GNUC__ > 3 39 // Follow ideas in http://gcc.gnu.org/wiki/Visibility for GCC version 4.x 40 // The following forces exported symbols specifically designated with 41 // LASIDLLEXPORT to be visible. 42 #define LASIDLLEXPORT __attribute__ ( ( visibility( "default" ) ) ) 43 #define LASIDLLIMPORT 44 #endif 45 46 // For an unknown compiler or static built we clear the macros. 47 #ifndef LASIDLLEXPORT 48 #define LASIDLLEXPORT 49 #define LASIDLLIMPORT 50 #endif 51 52 #if defined(LASi_EXPORTS) 53 #define LASIDLLIMPEXP LASIDLLEXPORT 54 #define LASIDLLIMPEXP_DATA(type) LASIDLLEXPORT type 55 #elif defined(LASi_DLL) 56 #define LASIDLLIMPEXP LASIDLLIMPORT 57 #define LASIDLLIMPEXP_DATA(type) LASIDLLIMPORT type 58 #else 59 #define LASIDLLIMPEXP 60 #define LASIDLLIMPEXP_DATA(type) type 61 #endif 62 63 namespace LASi { 64 65 enum FontStyle{ 66 NORMAL_STYLE, 67 OBLIQUE, 68 ITALIC 69 }; 70 71 enum FontWeight{ 72 ULTRALIGHT, 73 LIGHT, 74 NORMAL_WEIGHT, 75 BOLD, 76 ULTRABOLD, 77 HEAVY 78 }; 79 80 enum FontVariant{ 81 NORMAL_VARIANT, 82 SMALLCAPS 83 }; 84 85 enum FontStretch{ 86 ULTRACONDENSED, 87 EXTRACONDENSED, 88 CONDENSED, 89 SEMICONDENSED, 90 NORMAL_STRETCH, 91 SEMIEXPANDED, 92 EXPANDED, 93 EXTRAEXPANDED, 94 ULTRAEXPANDED 95 }; 96 97 class PostscriptDocument; 98 class write_glyph_routine_to_stream; 99 100 /** Just like any ordinary ostringstream, 101 * but maintains a reference to the PostscriptDocument. 102 */ 103 class LASIDLLIMPEXP oPostscriptStream : public std::ostringstream { 104 public: 105 friend class PostscriptDocument; 106 friend class show; 107 friend class setFont; 108 friend class setFontSize; 109 oPostscriptStream(PostscriptDocument & psDoc)110 oPostscriptStream(PostscriptDocument& psDoc) : _psDoc(psDoc) {} 111 112 protected: doc()113 PostscriptDocument& doc() {return _psDoc;} 114 115 private: 116 PostscriptDocument& _psDoc; 117 }; 118 119 template<class T> 120 inline oPostscriptStream& operator<<(oPostscriptStream& os, T t) { 121 static_cast<std::ostream&>(os) << t; 122 return os; 123 } 124 125 /** Composes Postscript document as three separate and independant streams 126 * for header, body and footer. Body and footer streams respond to 127 * LASi::show applicator which generates Postscript commands to display a 128 * string by using glyph routines instead of a Postscript font. 129 */ 130 class LASIDLLIMPEXP PostscriptDocument { 131 public: 132 friend class write_glyph_routine_to_stream; // helper class 133 friend class show; 134 135 PostscriptDocument(); 136 ~PostscriptDocument(); 137 138 /** Sets the font that all subsequent text written 139 * to bodyStream() or footerStream() will be rendered with. 140 */ 141 void setFont( 142 const char* const family = "sans", 143 LASi::FontStyle = LASi::NORMAL_STYLE, 144 LASi::FontWeight = LASi::NORMAL_WEIGHT, 145 LASi::FontVariant = LASi::NORMAL_VARIANT, 146 LASi::FontStretch = LASi::NORMAL_STRETCH 147 ); 148 149 /** Sets the font size, in points, that all subsequent text written 150 * to bodyStream() or footerStream() will be rendered with. 151 */ setFontSize(const double size)152 void setFontSize(const double size) {_fontSize = size;} 153 154 /** Returns stream for Postscript header. 155 */ osHeader()156 std::ostringstream& osHeader() {return _osHeader;} 157 158 /** Returns stream for Postscript body. 159 */ osBody()160 oPostscriptStream& osBody() {return _osBody;} 161 162 /** Returns stream for Postscript footer. 163 */ osFooter()164 oPostscriptStream& osFooter() {return _osFooter;} 165 166 /** Closes all streams and writes completed Postscript document to os. 167 * Header will include glyph routines for all text glyphs in body and footer. 168 * 169 * 2006.05.01.ET Addendum: To create an EPS document, just include the 170 * the four BoundingBox coordinates llx, lly, urx, ury (dimensions in points). 171 * These are optional parameters -- When not included, you'll get a regular PS 172 * document. When included, you'll get an EPS document. 173 * 174 */ 175 void write(std::ostream& os, double llx=0, double lly=0, double urx=0, double ury=0); 176 177 /** Return string dimensions: 178 * lineSpacing: inter-line spacing 179 * xAdvance: width of the string 180 * yMin: y-coordinate bounding the lowest descender, Indic under-consonantal vowel, etc. 181 * yMax: y-coordinate bounding the highest ascender, diacritic, Indic over-letter vowel, etc. 182 */ 183 void get_dimensions(const char* s, double *lineSpacing, double *xAdvance=NULL, double *yMin=NULL, double *yMax=NULL); 184 void get_dimensions(std::string s, double *lineSpacing, double *xAdvance=NULL, double *yMin=NULL, double *yMax=NULL); 185 186 protected: 187 /** For internal use only. 188 * @internal 189 * A unique id for a glyph that is composed of its font face and a unique integer. 190 */ 191 class GlyphId { 192 public: 193 friend bool operator==(const GlyphId id1, const GlyphId id2) { 194 return id1._str == id2._str; 195 } 196 197 friend bool operator<(const GlyphId id1, const GlyphId id2) { 198 return id1._str < id2._str; 199 } 200 GlyphId()201 GlyphId() {} 202 GlyphId(FT_Face, const FT_UInt, uint32_t unichar); 203 204 /** @return string representation of glyph id */ str()205 std::string str() const {return _str;} 206 207 private: 208 /** @return string representation of glyph id */ 209 std::string _str; 210 }; 211 212 /** Maps glyph routine name to FT_Glyph instance. 213 */ 214 typedef std::map<GlyphId, FreetypeGlyphMgr> GlyphMap; 215 216 /** Pointer to a function that takes a reference to a glyph 217 * and to x and y coordinates. 218 * May return new x and y coordinates. 219 */ 220 typedef void (PostscriptDocument::*GLYPH_FUNC)( 221 const GlyphMap::value_type&, void* contextData); 222 223 void invoke_glyph_routine(const GlyphMap::value_type&, void* contextData); 224 225 void accrue_dimensions( const GlyphMap::value_type&, void* contextData); 226 227 /** For a decomposed PangoItem (that can be rendered with a single 228 * font face) that is generated by for_each_glyph_do, 229 * apply GLYPH_FUNC to each glyph in that PangoItem. 230 */ 231 FT_Error PangoItem_do(const char* s, PangoItem* const pItem, 232 const GLYPH_FUNC func, void* contextData, 233 bool applyOffset = false); 234 235 /** Decomposes string into glyphs and applies GLYPH_FUNC to each glyph. 236 */ 237 void for_each_glyph_do(const std::string& s, const GLYPH_FUNC func, void* contextData, 238 bool applyOffset = false); 239 240 PangoContext* pangoContext() const; 241 242 /** @returns name of Postscript glyph routine 243 */ 244 std::string glyphProcName() const; 245 246 /** @return font size in points (1/72 in.) 247 */ getFontSize()248 double getFontSize() {return _fontSize;} 249 250 /** For internal use only. 251 */ 252 class write_glyph_routine_to_stream { 253 private: 254 std::ostream& os; 255 PangoContext* pangoCtx; 256 257 public: write_glyph_routine_to_stream(std::ostream & os,PangoContext * pangoCtx)258 write_glyph_routine_to_stream(std::ostream& os, PangoContext* pangoCtx) 259 : os(os), pangoCtx(pangoCtx) {} 260 void operator()(PostscriptDocument::GlyphMap::value_type v); 261 }; 262 263 private: 264 GlyphMap _glyphMap; 265 266 static const unsigned int DRAWING_SCALE; 267 268 // Use pointers instead of objects in order to minimize namespace pollution of .h file user 269 // Requires fwd declarations above. 270 ContextMgr* _pContextMgr; // manage PangoContext* 271 double _fontSize; // font size to be used when rendering next show() 272 std::ostringstream _osHeader; // Postscript header 273 oPostscriptStream _osBody; // Postscript body 274 oPostscriptStream _osFooter; // Postscript footer 275 }; 276 277 /** stream manipulator applied to oPostscriptStream. 278 */ 279 class LASIDLLIMPEXP setFont { 280 public: 281 /** Stream inserter for 'setFont' stream manipulator 282 */ 283 friend inline oPostscriptStream& operator<<(oPostscriptStream& os, const setFont& x) { 284 x.apply(os); 285 return os; 286 } 287 288 /** Usage: 289 * os << setFont("Vera Sans",LASi::ITALIC,LASi::BOLD) << ... 290 */ 291 setFont( 292 const char* const family = "sans", 293 const LASi::FontStyle style = LASi::NORMAL_STYLE, 294 const LASi::FontWeight weight = LASi::NORMAL_WEIGHT, 295 const LASi::FontVariant variant = LASi::NORMAL_VARIANT, 296 const LASi::FontStretch stretch = LASi::NORMAL_STRETCH ) _family(family)297 : _family(family), _style(style), _weight(weight), _variant(variant), _stretch(stretch) 298 {} 299 300 protected: apply(oPostscriptStream & os)301 void apply(oPostscriptStream& os) const { 302 os.doc().setFont(_family, _style,_weight, _variant, _stretch); 303 } 304 305 private: 306 const char* const _family; 307 const LASi::FontStyle _style; 308 const LASi::FontWeight _weight; 309 const LASi::FontVariant _variant; 310 const LASi::FontStretch _stretch; 311 312 }; 313 314 /** stream manipulator applied to oPostscriptStream. 315 */ 316 class LASIDLLIMPEXP setFontSize { 317 public: 318 /** Stream inserter for 'setFontSize' stream manipulator 319 */ 320 friend inline oPostscriptStream& operator<<(oPostscriptStream& os, const setFontSize& x) { 321 x.apply(os); 322 return os; 323 } 324 325 /** Usage: 326 * os << setFontSize(12) << ... 327 * @param size size in points 328 */ setFontSize(double size)329 setFontSize(double size) : _size(size) {} 330 331 protected: apply(oPostscriptStream & os)332 void apply(oPostscriptStream& os) const { 333 os.doc().setFontSize(_size); 334 } 335 336 private: 337 double _size; 338 }; 339 340 /** stream applicator applied to oPostscriptStream. 341 */ 342 class LASIDLLIMPEXP show{ 343 public: 344 /** stream inserter for 'show' stream applicator 345 */ 346 friend inline oPostscriptStream& operator<<(oPostscriptStream& os, const show& x) { 347 x.apply(os); 348 return os; 349 } 350 351 /** Usage: 352 * os << show("some UTF-8 text") << ... 353 */ show(const char * c_str)354 show(const char* c_str ) : _str(c_str ) {} show(std::string stl_str)355 show(std::string stl_str ) : _str(stl_str) {} 356 357 protected: 358 void apply(oPostscriptStream& os) const; 359 360 private: 361 std::string _str; 362 }; 363 } 364 #endif 365 366 /** @mainpage 367 * @section purpose Purpose 368 * 369 * LASi is Copyright (C) 2003, 2004, 2006 by Larry Siden. 370 * 371 * LASi is hosted on http://www.unifont.org 372 * 373 * LASi provides a C++ output stream interface for writing Postscript 374 * documents containing any of the world's scripts supported by Unicode 375 * 4.0 and by Pango. Right-to-left scripts like Hebrew and Arabic are 376 * accomodated as easily as left-to-right scripts. Complex text layout (CTL) 377 * scripts such as Devanagari, Thai, Lao and Tibetan are supported to the 378 * extent provided by Pango and by the OpenType fonts installed on your system. 379 * 380 * Postscript's <b>show</b> operator and font dictionaries can 381 * only provide glyphs for up to 255 code points and thus are hopelessly 382 * inadequate for many of the world's scripts, much less any kind of 383 * multilingual or scientific text encoded in Unicode. 384 * 385 * LASi works around the limitations of Postscript's built-in font technology 386 * by generating a Postscript routine for each glyph in a string. 387 * A LASi user writes a Postscript program much as he or she may have done in the 388 * past, but now uses LASi's <b>show()</b> method instead of the Postscript 389 * <b>show</b> operator. The user simply passes UTF-8 text strings 390 * directly to LASi's show() method. 391 * 392 * To draw the text string, LASi generates a sequence of calls 393 * to LASi-generated Postscript glyph routines. Glyph routines are only 394 * generated for glyphs that are actually used in the text. In this respect, 395 * LASi is efficient even for Chinese, Japanese, or Korean (CJK). 396 * 397 * In addition to being efficient, the Postscript code and routines 398 * created by LASi are intelligible to human readers which facilitates 399 * debugging of Postscript programs. 400 * 401 * @section usage Usage 402 * 403 * Please view the examples provided in the <b>examples</b> directory to see how LASi is used. 404 * The only header your program need include is <b>LASi.h</b>. 405 * View the examples' <b>Makefiles</b> to see how a program may link with libLASi. 406 * 407 */ 408