/************************************************************************* ** PsSpecialHandler.hpp ** ** ** ** This file is part of dvisvgm -- a fast DVI to SVG converter ** ** Copyright (C) 2005-2024 Martin Gieseking ** ** ** ** This program is free software; you can redistribute it and/or ** ** modify it under the terms of the GNU General Public License as ** ** published by the Free Software Foundation; either version 3 of ** ** the License, or (at your option) any later version. ** ** ** ** This program is distributed in the hope that it will be useful, but ** ** WITHOUT ANY WARRANTY; without even the implied warranty of ** ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** ** GNU General Public License for more details. ** ** ** ** You should have received a copy of the GNU General Public License ** ** along with this program; if not, see . ** *************************************************************************/ #ifndef PSSPECIALHANDLER_HPP #define PSSPECIALHANDLER_HPP #include #include #include #include #include #include "GraphicsPath.hpp" #include "PDFHandler.hpp" #include "PSInterpreter.hpp" #include "Opacity.hpp" #include "PSPattern.hpp" #include "PSPreviewHandler.hpp" #include "SpecialHandler.hpp" class PSPattern; class SVGElement; class XMLElement; class PsSpecialHandler : public SpecialHandler, protected PSActions { using Path = GraphicsPath; using ColorSpace = Color::ColorSpace; /** Helper class storing the clipping paths currently present on the graphics context stack. * Since PS operator 'clippath' only delivers a linearly approximated version of the paths * that are sometimes too imprecise for direct usage in SVG, we keep the possibly curved * clipping paths and compute their intersections locally if necessary. */ class ClippingStack { public: void pushEmptyPath (); void push (const Path &path, int saveID=-1); bool replace (const Path &path); void dup (int saveID=-1); void pop (int saveID=-1, bool grestore=false); void clear (); bool empty () const {return _stack.empty();} void setPrependedPath (); const Path* path () const; const Path* prependedPath () const; void removePrependedPath (); int topID () const {return _stack.empty() ? 0 : _stack.top().pathID;} private: struct Entry { std::shared_ptr path; ///< pointer to current clipping path std::shared_ptr prependedPath=nullptr; int pathID; ///< ID of current clipping path int saveID; ///< if >=0, path was pushed by 'save', and saveID holds the ID of the PS memory object Entry () : Entry(-1) {} Entry (const Path &p, int pid, int sid) : path(std::make_shared(p)), pathID(pid), saveID(sid) {} explicit Entry (int sid) : path(nullptr), pathID(0), saveID(sid) {} Entry (const Entry &entry) =default; Entry (Entry &&entry) =default; }; size_t _maxID=0; std::stack _stack; ///< stack holding the clipping information of the current graphics context }; struct ImageNode { ImageNode () : matrix(1) {} explicit ImageNode (std::unique_ptr elem) : element(std::move(elem)), matrix(1) {} ImageNode (std::unique_ptr elem, const Matrix &m) : element(std::move(elem)), matrix(m) {} std::unique_ptr element; Matrix matrix; }; enum PsSection {PS_NONE, PS_HEADERS, PS_BODY}; enum class FileType {EPS, PDF, SVG, BITMAP}; public: PsSpecialHandler (); ~PsSpecialHandler () override; void preprocess (const std::string &prefix, std::istream &is, SpecialActions &actions) override; bool process (const std::string &prefix, std::istream &is, SpecialActions &actions) override; const char* info () const override {return "dvips PostScript specials";} const char* name () const override {return handlerName();} static const char* handlerName () {return "ps";} std::vector prefixes () const override; void setDviScaleFactor (double dvi2bp) override {_previewHandler.setDviScaleFactor(dvi2bp);} void enterBodySection (); PSInterpreter& psInterpreter () {return _psi;} public: static bool COMPUTE_CLIPPATHS_INTERSECTIONS; static bool SHADING_SEGMENT_OVERLAP; static int SHADING_SEGMENT_SIZE; static double SHADING_SIMPLIFY_DELTA; static std::string BITMAP_FORMAT; static bool EMBED_BITMAP_DATA; protected: void initialize (); void initgraphics (); void moveToDVIPos (); void executeAndSync (std::istream &is, bool updatePos); void processHeaderFile (const char *fname); void imgfile (FileType type, const std::string &fname, const std::map &attr); ImageNode createImageNode (FileType type, const std::string &fname, int pageno, BoundingBox bbox, bool clip); ImageNode createBitmapNode (const std::string &fname, const std::string &path, int pageno, BoundingBox bbox); ImageNode createPSNode (const std::string &fname, const std::string &path, int pageno, BoundingBox bbox, bool clip); ImageNode createPDFNode (const std::string &fname, const std::string &path, int pageno, BoundingBox bbox, bool clip); void dviBeginPage (unsigned int pageno, SpecialActions &actions) override; void dviEndPage (unsigned pageno, SpecialActions &actions) override; void clip (Path path, bool evenodd); void processSequentialPatchMesh (int shadingTypeID, ColorSpace cspace, VectorIterator &it); void processLatticeTriangularPatchMesh (ColorSpace colorSpace, VectorIterator &it); /// scale given value by current PS scale factors double scale (double v) const {return v*(_sx*(1-_cos*_cos) + _sy*_cos*_cos);} void applyscalevals (std::vector &p) override {_sx = p[0]; _sy = p[1]; _cos = p[2];} void clip (std::vector &p) override {clip(p, false);} void clip (std::vector &p, bool evenodd); void clippath (std::vector &p) override; void closepath (std::vector &p) override; void curveto (std::vector &p) override; void eoclip (std::vector &p) override {clip(p, true);} void eofill (std::vector &p) override {fill(p, true);} void fill (std::vector &p, bool evenodd); void fill (std::vector &p) override {fill(p, false);} void grestore (std::vector &p) override; void grestoreall (std::vector &p) override; void gsave (std::vector &p) override; void image (std::vector &p) override; void initclip (std::vector &p) override; void lineto (std::vector &p) override; void makepattern (std::vector &p) override; void moveto (std::vector &p) override; void newpath (std::vector &p) override; void querypos (std::vector &p) override {_currentpoint = DPair(p[0], p[1]);} void restore (std::vector &p) override; void rotate (std::vector &p) override; void save (std::vector &p) override; void scale (std::vector &p) override; void setalphaisshape (std::vector &p) override { _isshapealpha = bool(p[0]);} void setblendmode (std::vector &p) override; void setcolorspace (std::vector &p) override {_patternEnabled = bool(p[0]);} void setcmykcolor (std::vector &cmyk) override; void setdash (std::vector &p) override; void setfillconstantalpha (std::vector &p) override; void setgray (std::vector &p) override; void sethsbcolor (std::vector &hsb) override; void setlinecap (std::vector &p) override {_linecap = uint8_t(p[0]);} void setlinejoin (std::vector &p) override {_linejoin = uint8_t(p[0]);} void setlinewidth (std::vector &p) override {_linewidth = scale(p[0] ? p[0] : 0.5);} void setmatrix (std::vector &p) override; void setmiterlimit (std::vector &p) override {_miterlimit = p[0];} void setnulldevice (std::vector &p) override; void setpagedevice (std::vector &p) override; void setpattern (std::vector &p) override; void setrgbcolor (std::vector &rgb) override; void setstrokeconstantalpha (std::vector &p) override; void shfill (std::vector &p) override; void stroke (std::vector &p) override; void translate (std::vector &p) override; void executed () override; private: PSInterpreter _psi; PDFHandler _pdfHandler; SpecialActions *_actions=nullptr; PSPreviewHandler _previewHandler; ///< extracts information generated by the preview package PsSection _psSection=PS_NONE; ///< current section processed (nothing yet, headers, or body specials) XMLElement *_xmlnode=nullptr; ///< if != 0, created SVG elements are appended to this node XMLElement *_savenode=nullptr; ///< pointer to temporaryly store _xmlnode std::string _headerCode; ///< collected literal PS header code Path _path; DPair _currentpoint; ///< current PS position in bp units Color _currentcolor; ///< current stroke/fill color double _sx, _sy; ///< horizontal and vertical scale factors retrieved by operator "applyscalevals" double _cos; ///< cosine of angle between (1,0) and transform(1,0) double _linewidth; ///< current line width in bp units double _miterlimit; ///< current miter limit in bp units bool _isshapealpha; ///< if true, opacity operators act on shape component, otherwise on constant component Opacity _opacity; uint8_t _linecap : 2; ///< current line cap (0=butt, 1=round, 2=projecting square) uint8_t _linejoin : 2; ///< current line join (0=miter, 1=round, 2=bevel) double _dashoffset; ///< current dash offset std::vector _dashpattern; ClippingStack _clipStack; int _imgClipCount=0; ///< current number of clip paths assigned to images bool _makingPattern=false; ///< true if executing makepattern operator std::map> _patterns; PSTilingPattern *_pattern; ///< current pattern bool _patternEnabled; ///< true if active color space is a pattern std::string _pdfProc; ///< tool to process PDF files ("gs" or "mutool") }; #endif