1 /** 2 Generic 2D vector renderer. 3 4 Copyright: Guillaume Piolat 2018. 5 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 6 */ 7 module printed.canvas.irenderer; 8 9 public import printed.canvas.image; 10 11 /// Describes the `printed` 2D renderer. 12 /// 13 /// This is the law, specific implementation MUST obey this interface and 14 /// not the underlying implementation in PDF/SVG/whatever (and if necessary revise this spec). 15 /// 16 /// We are heavily influenced by the HTML5 Canvas 2D context API, for its familiarity. 17 /// See_also: https://www.w3.org/TR/2dcontext/ 18 interface IRenderingContext2D 19 { 20 // GRAPHICAL CONTEXT 21 22 /// Number of units in a page. 23 /// Return: Page width in millimeters. 24 float pageWidth(); 25 26 /// Number of units in a page. 27 /// Return: Page height in millimeters. 28 float pageHeight(); 29 30 /// Push state on state stack. 31 /// What this states contains: 32 /// - transformation matrices 33 void save(); 34 35 /// Pop state stack and restore state 36 void restore(); 37 38 /// Start a new page, finish the previous one. 39 /// This invalidates any transformation. 40 /// The origin (0, 0) becomes again the top-left point of each page. 41 void newPage(); 42 43 44 // TRANSFORMATIONS (default: transform is the identity matrix) 45 // The origin (0, 0) of the default is the top-left point of each page. 46 47 /// Changes the transformation matrix to apply a scaling transformation with the given characteristics. 48 void scale(float x, float y); 49 50 /// Changes the transformation matrix to apply a translation transformation with the given characteristics. 51 void translate(float dx, float dy); 52 53 /// Changes the transformation matrix to apply a rotation transformation with the given characteristics. 54 /// The angle is in radians, the direction is clockwise. 55 /// Params: 56 /// angle The rotation angle, in radians. 57 void rotate(float angle); 58 59 60 // IMAGES 61 62 /// Draws an image at the given position. 63 void drawImage(Image image, float x, float y); 64 65 /// Draws an image at the given position, with the given width and height. 66 /// Both `width` and `height` must be provided. 67 void drawImage(Image image, float x, float y, float width, float height); 68 69 // COLOURS 70 71 /// Changes the current fill brush. 72 /// Params: 73 /// color Any HTML color string. 74 void fillStyle(Brush brush); 75 76 /// Changes the current stroke brush. 77 /// Params: 78 /// color Any HTML color string. 79 void strokeStyle(Brush brush); 80 81 82 // BASIC SHAPES 83 84 /// 85 void fillRect(float x, float y, float width, float height); 86 void strokeRect(float x, float y, float width, float height); 87 88 /// Draw filled text. 89 void fillText(string text, float x, float y); 90 91 // PATHS 92 /// The context always has a current default path. 93 /// There is only one current path, it is not part of the drawing state. 94 95 /// Resets the current path, and move the cursor to (x, y). 96 void beginPath(float x, float y); 97 98 /// Change the width of a line. 99 /// The whole path has the same line width. 100 void lineWidth(float width); 101 102 /// Add a subpath forming a line. Its exact width is set when the path is drawn with `fill`, `stroke` or `fillAndStroke`. 103 void lineTo(float dx, float dy); 104 105 /// Fills the subpaths of the current path or the given path with the current fill style. 106 /// Uses the last set fill style, line width for the whole path. 107 void fill(); 108 109 /// Strokes the subpaths of the current path or the given path with the current stroke style. 110 /// Uses the last set fill style, line width for the whole path. 111 void stroke(); 112 113 /// Both fills and strokes the subpaths of the current path, in a more efficient way than calling 114 /// `fill` and `stroke` separately. 115 /// Uses the last set fill style, line width for the whole path. 116 void fillAndStroke(); 117 118 /// Close the path, returning to the initial first point. 119 /// TODO: specify exactly what it does. 120 void closePath(); 121 122 123 // FONTS 124 // The specific font will be lazily choosen across all available fonts, 125 // with a matching algorithm. 126 // See_also: `findBestMatchingFont`. 127 128 /// Changes font face (default = Helvetica) 129 void fontFace(string fontFace); 130 131 /// Changes font weight (Default = FontWeight.normal) 132 void fontWeight(FontWeight fontWeight); 133 134 /// Changes font style (default = FontStyle.normal) 135 void fontStyle(FontStyle fontStyle); 136 137 /// Changes font size in points (default = 11pt) 138 /// Warning: not millimeters. 139 void fontSize(float sizeInPt); 140 141 /// Changes text alignment (default = TextAlign.start) 142 void textAlign(TextAlign alignment); 143 144 /// Changes text baseline (default = TextBaseline.alphabetic) 145 void textBaseline(TextBaseline baseline); 146 147 /// Returns a `TextMetrics` struct that contains information about the measured text 148 /// (such as its width, for example). 149 TextMetrics measureText(string text); 150 } 151 152 enum TextAlign 153 { 154 /// Align to the start edge of the text (left side in left-to-right text, right side in right-to-left text). 155 /// This is the default. 156 start, 157 158 /// Align to the end edge of the text (right side in left-to-right text, left side in right-to-left text). 159 end, 160 161 /// Align to the left. 162 left, 163 164 /// Align to the right. 165 right, 166 167 /// Align to the center. 168 center 169 } 170 171 enum TextBaseline 172 { 173 top, 174 hanging, 175 middle, 176 alphabetic, // default 177 bottom 178 } 179 180 /// Font weight 181 enum FontWeight : int 182 { 183 thinest = 0, // Note: thinest doesn't exist in PostScript 184 thin = 100, 185 extraLight = 200, 186 light = 300, 187 normal = 400, 188 medium = 500, 189 semiBold = 600, 190 bold = 700, 191 extraBold = 800, 192 black = 900 193 } 194 195 /// Font style 196 enum FontStyle 197 { 198 normal, 199 italic, 200 oblique 201 } 202 203 /// Make a brush suitable for `fillStyle` and `strokeStyle`. 204 Brush brush(int r, int g, int b, int a) 205 { 206 return Brush(r, g, b, a); 207 } 208 209 ///ditto 210 Brush brush(int r, int g, int b) 211 { 212 return Brush(r, g, b); 213 } 214 215 ///ditto 216 Brush brush(string htmlColor) 217 { 218 return Brush(htmlColor); 219 } 220 221 struct Brush 222 { 223 ubyte[4] rgba; 224 225 this(int r, int g, int b) 226 { 227 rgba[0] = cast(ubyte)r; 228 rgba[1] = cast(ubyte)g; 229 rgba[2] = cast(ubyte)b; 230 rgba[3] = 255; 231 } 232 233 this(int r, int g, int b, int a) 234 { 235 rgba[0] = cast(ubyte)r; 236 rgba[1] = cast(ubyte)g; 237 rgba[2] = cast(ubyte)b; 238 rgba[3] = cast(ubyte)a; 239 } 240 241 this(string htmlColor) 242 { 243 import printed.htmlcolors; 244 rgba = parseHTMLColor(htmlColor); 245 } 246 247 bool isOpaque() 248 { 249 return rgba[3] == 255; 250 } 251 252 ubyte[4] toRGBAColor() 253 { 254 return rgba; 255 } 256 257 string toSVGColor() 258 { 259 import std..string; 260 // TODO: optimize 261 return format("rgba(%d,%d,%d,%f)", rgba[0], rgba[1], rgba[2], rgba[3] / 255.0f); 262 } 263 } 264 265 266 // Utility functions 267 268 float convertPointsToMillimeters(float pt) pure nothrow @nogc @safe 269 { 270 return pt * 0.35277777778f; 271 } 272 273 float convertMillimetersToPoints(float pt) pure nothrow @nogc @safe 274 { 275 return pt * 2.83464567f; 276 } 277 278 279 /// The `TextMetrics` interface represents the dimensions of a piece of text, 280 /// as created by the `measureText()` method. 281 struct TextMetrics 282 { 283 float width; /// Suggested horizontal advance to the next block of text. 284 float lineGap; /// Suggested offset to the next line, baseline to baseline. 285 } 286 287