#ifndef LASI_H #define LASI_H /** @file * Defines oPostscriptStream and PostscriptDocument and various * stream manipulators. */ #include #include #include #include #include #include class FreetypeGlyphMgr; class ContextMgr; namespace LASi { enum FontStyle{ NORMAL_STYLE, OBLIQUE, ITALIC }; enum FontWeight{ ULTRALIGHT, LIGHT, NORMAL_WEIGHT, BOLD, ULTRABOLD, HEAVY }; enum FontVariant{ NORMAL_VARIANT, SMALLCAPS }; enum FontStretch{ ULTRACONDENSED, EXTRACONDENSED, CONDENSED, SEMICONDENSED, NORMAL_STRETCH, SEMIEXPANDED, EXPANDED, EXTRAEXPANDED, ULTRAEXPANDED }; class PostscriptDocument; class write_glyph_routine_to_stream; /** Just like any ordinary ostringstream, * but maintains a reference to the PostscriptDocument. */ class oPostscriptStream : public std::ostringstream { public: friend class PostscriptDocument; friend class show; friend class setFont; friend class setFontSize; oPostscriptStream(PostscriptDocument& psDoc) : _psDoc(psDoc) {} protected: PostscriptDocument& doc() {return _psDoc;} private: PostscriptDocument& _psDoc; }; template inline oPostscriptStream& operator<<(oPostscriptStream& os, T t) { static_cast(os) << t; return os; } /** Composes Postscript document as three separate and independant streams * for header, body and footer. Body and footer streams respond to * LASi::show applicator which generates Postscript commands to display a * string by using glyph routines instead of a Postscript font. */ class PostscriptDocument { public: friend class write_glyph_routine_to_stream; // helper class friend class show; PostscriptDocument(); ~PostscriptDocument(); /** Sets the font that all subsequent text written * to bodyStream() or footerStream() will be rendered with. */ void setFont( const char* const family = "sans", LASi::FontStyle = LASi::NORMAL_STYLE, LASi::FontWeight = LASi::NORMAL_WEIGHT, LASi::FontVariant = LASi::NORMAL_VARIANT, LASi::FontStretch = LASi::NORMAL_STRETCH ); /** Sets the font size, in points, that all subsequent text written * to bodyStream() or footerStream() will be rendered with. */ void setFontSize(const double size) {_fontSize = size;} /** Returns stream for Postscript header. */ std::ostringstream& osHeader() {return _osHeader;} /** Returns stream for Postscript body. */ oPostscriptStream& osBody() {return _osBody;} /** Returns stream for Postscript footer. */ oPostscriptStream& osFooter() {return _osFooter;} /** Closes all streams and writes completed Postscript document to os. * Header will include glyph routines for all text glyphs in body and footer. * * 2006.05.01.ET Addendum: To create an EPS document, just include the * the four BoundingBox coordinates llx, lly, urx, ury (dimensions in points). * These are optional parameters -- When not included, you'll get a regular PS * document. When included, you'll get an EPS document. * */ void write(std::ostream& os, double llx=0, double lly=0, double urx=0, double ury=0); /** Return string dimensions: * lineSpacing: inter-line spacing * xAdvance: width of the string * yMin: y-coordinate bounding the lowest descender, Indic under-consonantal vowel, etc. * yMax: y-coordinate bounding the highest ascender, diacritic, Indic over-letter vowel, etc. */ void get_dimensions(const char* s, double *lineSpacing, double *xAdvance=NULL, double *yMin=NULL, double *yMax=NULL); void get_dimensions(std::string s, double *lineSpacing, double *xAdvance=NULL, double *yMin=NULL, double *yMax=NULL); protected: /** For internal use only. * @internal * A unique id for a glyph that is composed of its font face and a unique integer. */ class GlyphId { public: friend bool operator==(const GlyphId id1, const GlyphId id2) { return id1._str == id2._str; } friend bool operator<(const GlyphId id1, const GlyphId id2) { return id1._str < id2._str; } GlyphId() {} GlyphId(FT_Face, const FT_UInt); /** @return string representation of glyph id */ std::string str() const {return _str;} private: /** @return string representation of glyph id */ std::string _str; }; /** Maps glyph routine name to FT_Glyph instance. */ typedef std::map GlyphMap; /** Pointer to a function that takes a reference to a glyph * and to x and y coordinates. * May return new x and y coordinates. */ typedef void (PostscriptDocument::*GLYPH_FUNC)( const GlyphMap::value_type&, void* contextData); void invoke_glyph_routine(const GlyphMap::value_type&, void* contextData); void accrue_dimensions( const GlyphMap::value_type&, void* contextData1); /** Decomposes string into glyphs and applies GLYPH_FUNC to each glyph. */ void for_each_glyph_do(const std::string&, const GLYPH_FUNC, void* contextData); PangoContext* pangoContext() const; /** @returns name of Postscript glyph routine */ std::string glyphProcName() const; /** @return font size in points (1/72 in.) */ double getFontSize() {return _fontSize;} /** For internal use only. */ class write_glyph_routine_to_stream { private: std::ostream& os; PangoContext* pangoCtx; public: write_glyph_routine_to_stream(std::ostream& os, PangoContext* pangoCtx) : os(os), pangoCtx(pangoCtx) {} void operator()(PostscriptDocument::GlyphMap::value_type v); }; private: GlyphMap _glyphMap; static const unsigned int DRAWING_SCALE; // Use pointers instead of objects in order to minimize namespace pollution of .h file user // Requires fwd declarations above. ContextMgr* _pContextMgr; // manage PangoContext* double _fontSize; // font size to be used when rendering next show() std::ostringstream _osHeader; // Postscript header oPostscriptStream _osBody; // Postscript body oPostscriptStream _osFooter; // Postscript footer }; /** stream manipulator applied to oPostscriptStream. */ class setFont { public: /** Stream inserter for 'setFont' stream manipulator */ friend inline oPostscriptStream& operator<<(oPostscriptStream& os, const setFont& x) { x.apply(os); return os; } /** Usage: * os << setFont("Vera Sans",LASi::ITALIC,LASi::BOLD) << ... */ setFont( const char* const family = "sans", const LASi::FontStyle style = LASi::NORMAL_STYLE, const LASi::FontWeight weight = LASi::NORMAL_WEIGHT, const LASi::FontVariant variant = LASi::NORMAL_VARIANT, const LASi::FontStretch stretch = LASi::NORMAL_STRETCH ) : _family(family), _style(style), _weight(weight), _variant(variant), _stretch(stretch) {} protected: void apply(oPostscriptStream& os) const { os.doc().setFont(_family, _style,_weight, _variant, _stretch); } private: const char* const _family; const LASi::FontStyle _style; const LASi::FontWeight _weight; const LASi::FontVariant _variant; const LASi::FontStretch _stretch; }; /** stream manipulator applied to oPostscriptStream. */ class setFontSize { public: /** Stream inserter for 'setFontSize' stream manipulator */ friend inline oPostscriptStream& operator<<(oPostscriptStream& os, const setFontSize& x) { x.apply(os); return os; } /** Usage: * os << setFontSize(12) << ... * @param size size in points */ setFontSize(double size) : _size(size) {} protected: void apply(oPostscriptStream& os) const { os.doc().setFontSize(_size); } private: double _size; }; /** stream applicator applied to oPostscriptStream. */ class show{ public: /** stream inserter for 'show' stream applicator */ friend inline oPostscriptStream& operator<<(oPostscriptStream& os, const show& x) { x.apply(os); return os; } /** Usage: * os << show("some UTF-8 text") << ... */ show(const char* c_str ) : _str(c_str ) {} show(std::string stl_str ) : _str(stl_str) {} protected: void apply(oPostscriptStream& os) const; private: std::string _str; }; } #endif /** @mainpage * @section purpose Purpose * * LASi is Copyright (C) 2003, 2004, 2006 by Larry Siden. * * LASi is hosted on http://www.unifont.org * * LASi provides a C++ output stream interface for writing Postscript * documents containing any of the world's scripts supported by Unicode * 4.0 and by Pango. Right-to-left scripts like Hebrew and Arabic are * accomodated as easily as left-to-right scripts. Complex text layout (CTL) * scripts such as Devanagari, Thai, Lao and Tibetan are supported to the * extent provided by Pango and by the OpenType fonts installed on your system. * * Postscript's show operator and font dictionaries can * only provide glyphs for up to 255 code points and thus are hopelessly * inadequate for many of the world's scripts, much less any kind of * multilingual or scientific text encoded in Unicode. * * LASi works around the limitations of Postscript's built-in font technology * by generating a Postscript routine for each glyph in a string. * A LASi user writes a Postscript program much as he or she may have done in the * past, but now uses LASi's show() method instead of the Postscript * show operator. The user simply passes UTF-8 text strings * directly to LASi's show() method. * * To draw the text string, LASi generates a sequence of calls * to LASi-generated Postscript glyph routines. Glyph routines are only * generated for glyphs that are actually used in the text. In this respect, * LASi is efficient even for Chinese, Japanese, or Korean (CJK). * * In addition to being efficient, the Postscript code and routines * created by LASi are intelligible to human readers which facilitates * debugging of Postscript programs. * * @section usage Usage * * Please view the examples provided in the examples directory to see how LASi is used. * The only header your program need include is LASi.h. * View the examples' Makefiles to see how a program may link with libLASi. * */