/*========================================================================= Program: Visualization Toolkit Module: vtkSVGContextDevice2D.h Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ /** * @class vtkSVGContextDevice2D * @brief vtkContextDevice2D implementation for use with vtkSVGExporter. * * Limitations: * - The Nearest/Linear texture properties are ignored, since SVG doesn't * provide any reliable control over interpolation. * - Embedded fonts are experimental and poorly tested. Viewer support is * lacking at the time of writing, hence the feature is largely useless. By * default, fonts are not embedded since they're basically useless bloat. * - TextAsPath is enabled by default, since viewers differ wildly in how they * handle text objects (eg. Inkscape renders at expected size, but webkit is * way too big). * - Pattern fills and markers are not shown on some viewers, e.g. KDE's okular * (Webkit seems to work, though). * - Clipping seems to be broken in most viewers. Webkit is buggy and forces the * clip coordinates to objectBoundingBox, even when explicitly set to * userSpaceOnUse. * - Many viewers anti-alias the output, leaving thin outlines around the * triangles that make up larger polygons. This is a viewer issue and there * not much we can do about it from the VTK side of things (and most viewers * don't seem to have an antialiasing toggle, either...). */ #ifndef vtkSVGContextDevice2D_h #define vtkSVGContextDevice2D_h #include "vtkIOExportModule.h" // For export macro #include "vtkContextDevice2D.h" #include "vtkNew.h" // For vtkNew! #include // For std::array! class vtkColor3ub; class vtkColor4ub; class vtkPath; class vtkRenderer; class vtkTransform; class vtkVector3f; class vtkXMLDataElement; class VTKIOEXPORT_EXPORT vtkSVGContextDevice2D: public vtkContextDevice2D { public: static vtkSVGContextDevice2D* New(); vtkTypeMacro(vtkSVGContextDevice2D, vtkContextDevice2D) void PrintSelf(ostream &os, vtkIndent indent) override; /** The svg container element to draw into, and the global definitions * element. */ void SetSVGContext(vtkXMLDataElement *context, vtkXMLDataElement *defs); /** * EXPERIMENTAL: If true, the font glyph information will be embedded in the * output. Default is false. * * @note This feature is experimental and not well tested, as most browsers * and SVG viewers do not support rendering embedded fonts. As such, enabling * this option typically just increases file size for no real benefit. * * @{ */ vtkSetMacro(EmbedFonts, bool) vtkGetMacro(EmbedFonts, bool) vtkBooleanMacro(EmbedFonts, bool) /**@}*/ /** * If true, draw all text as path objects rather than text objects. Enabling * this option will: * * - Improve portability (text will look exactly the same everywhere). * - Increase file size (text objects are much more compact than paths). * - Prevent text from being easily edited (text metadata is lost). * * Note that some text (e.g. MathText) is always rendered as a path. * * The default is true, as many browsers and SVG viewers render text objects * inconsistently. * * @{ */ vtkSetMacro(TextAsPath, bool) vtkGetMacro(TextAsPath, bool) vtkBooleanMacro(TextAsPath, bool) /**@}*/ /** * Set the threshold for subdividing gradient-shaded polygons/line. Default * value is 1, and lower values yield higher quality and larger files. Larger * values will reduce the number of primitives, but will decrease quality. * * A triangle / line will not be subdivided further if all of it's vertices * satisfy the equation: * * |v1 - v2|^2 < thresh * * e.g. the squared norm of the vector between any verts must be greater than * the threshold for subdivision to occur. * * @{ */ vtkSetMacro(SubdivisionThreshold, float) vtkGetMacro(SubdivisionThreshold, float) /**@}*/ /** * Write any definition information (fonts, images, etc) that are accumulated * between actors. */ void GenerateDefinitions(); void Begin(vtkViewport*) override; void End() override; void DrawPoly(float *points, int n, unsigned char *colors = nullptr, int nc_comps = 0) override; void DrawLines(float *f, int n, unsigned char *colors = nullptr, int nc_comps = 0) override; void DrawPoints(float *points, int n, unsigned char* colors = nullptr, int nc_comps = 0) override; void DrawPointSprites(vtkImageData *sprite, float *points, int n, unsigned char *colors = nullptr, int nc_comps = 0) override; void DrawMarkers(int shape, bool highlight, float *points, int n, unsigned char *colors = nullptr, int nc_comps = 0) override; void DrawQuad(float *, int) override; void DrawQuadStrip(float *, int) override; void DrawPolygon(float *, int) override; void DrawColoredPolygon(float *points, int numPoints, unsigned char *colors = nullptr, int nc_comps = 0) override; void DrawEllipseWedge(float x, float y, float outRx, float outRy, float inRx, float inRy, float startAngle, float stopAngle) override; void DrawEllipticArc(float x, float y, float rX, float rY, float startAngle, float stopAngle) override; void DrawString(float *point, const vtkStdString &string) override; void ComputeStringBounds(const vtkStdString &string, float bounds[4]) override; void DrawString(float *point, const vtkUnicodeString &string) override; void ComputeStringBounds(const vtkUnicodeString &string, float bounds[4]) override; void ComputeJustifiedStringBounds(const char* string, float bounds[4]) override; void DrawMathTextString(float *point, const vtkStdString &str) override; void DrawImage(float p[2], float scale, vtkImageData *image) override; void DrawImage(const vtkRectf& pos, vtkImageData *image) override; void SetColor4(unsigned char color[4]) override; void SetTexture(vtkImageData* image, int properties) override; void SetPointSize(float size) override; void SetLineWidth(float width) override; void SetLineType(int type) override; void SetMatrix(vtkMatrix3x3 *m) override; void GetMatrix(vtkMatrix3x3 *m) override; void MultiplyMatrix(vtkMatrix3x3 *m) override; void PushMatrix() override; void PopMatrix() override; void SetClipping(int *x) override; void EnableClipping(bool enable) override; protected: vtkSVGContextDevice2D(); ~vtkSVGContextDevice2D() override; void SetViewport(vtkViewport*); void PushGraphicsState(); void PopGraphicsState(); // Apply clipping and transform information current active node. void SetupClippingAndTransform(); // pen -> stroke state void ApplyPenStateToNode(vtkXMLDataElement *node); void ApplyPenColorToNode(vtkXMLDataElement *node); void ApplyPenOpacityToNode(vtkXMLDataElement *node); void ApplyPenWidthToNode(vtkXMLDataElement *node); void ApplyPenStippleToNode(vtkXMLDataElement *node); // pen -> fill state void ApplyPenAsFillColorToNode(vtkXMLDataElement *node); void ApplyPenAsFillOpacityToNode(vtkXMLDataElement *node); // brush -> fill state void ApplyBrushStateToNode(vtkXMLDataElement *node); void ApplyBrushColorToNode(vtkXMLDataElement *node); void ApplyBrushOpacityToNode(vtkXMLDataElement *node); void ApplyBrushTextureToNode(vtkXMLDataElement *node); // tprop --> text state void ApplyTextPropertyStateToNode(vtkXMLDataElement *node, float x, float y); void ApplyTextPropertyStateToNodeForPath(vtkXMLDataElement *node, float x, float y); void ApplyTransform(); // Add marker symbols to defs, return symbol id. std::string AddCrossSymbol(bool highlight); std::string AddPlusSymbol(bool highlight); std::string AddSquareSymbol(bool highlight); std::string AddCircleSymbol(bool highlight); std::string AddDiamondSymbol(bool highlight); void DrawPath(vtkPath *path, std::ostream &out); void DrawLineGradient(const vtkVector2f &p1, const vtkColor4ub &c1, const vtkVector2f &p2, const vtkColor4ub &c2, bool useAlpha); void DrawTriangleGradient(const vtkVector2f &p1, const vtkColor4ub &c1, const vtkVector2f &p2, const vtkColor4ub &c2, const vtkVector2f &p3, const vtkColor4ub &c3, bool useAlpha); // Used by the Draw*Gradient methods to prevent subdividing triangles / lines // that are already really small. bool AreaLessThanTolerance(const vtkVector2f &p1, const vtkVector2f &p2, const vtkVector2f &p3); bool LengthLessThanTolerance(const vtkVector2f &p1, const vtkVector2f &p2); bool ColorsAreClose(const vtkColor4ub &c1, const vtkColor4ub &c2, bool useAlpha); bool ColorsAreClose(const vtkColor4ub &c1, const vtkColor4ub &c2, const vtkColor4ub &c3, bool useAlpha); void WriteFonts(); void WriteImages(); void WritePatterns(); void WriteClipRects(); void AdjustMatrixForSVG(const double in[9], double out[9]); void GetSVGMatrix(double svg[9]); static bool Transform2DEqual(const double mat3[9], const double mat4[16]); static void Matrix3ToMatrix4(const double mat3[9], double mat4[16]); static void Matrix4ToMatrix3(const double mat4[16], double mat3[9]); float GetScaledPenWidth(); void GetScaledPenWidth(float &x, float &y); void TransformSize(float &x, float &y); vtkImageData* PreparePointSprite(vtkImageData *in); struct Details; Details *Impl; vtkViewport *Viewport; vtkXMLDataElement *ContextNode; vtkXMLDataElement *ActiveNode; vtkXMLDataElement *DefinitionNode; // This is a 3D transform, the 2D version doesn't support push/pop. vtkNew Matrix; std::array ActiveNodeTransform; std::array ClipRect; // x, y, w, h std::array ActiveNodeClipRect; // x, y, w, h float CanvasHeight; // Used in y coordinate conversions. float SubdivisionThreshold; bool IsClipping; bool ActiveNodeIsClipping; bool EmbedFonts; bool TextAsPath; private: vtkSVGContextDevice2D(const vtkSVGContextDevice2D&) = delete; void operator=(const vtkSVGContextDevice2D&) = delete; }; #endif // vtkSVGContextDevice2D_h