1 /* 2 * This program source code file is part of KiCad, a free EDA CAD application. 3 * 4 * Copyright (C) 2016-2021 KiCad Developers, see AUTHORS.txt for contributors. 5 * 6 * This program is free software: you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License as published by the 8 * Free Software Foundation, either version 3 of the License, or (at your 9 * option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, but 12 * WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License along 17 * with this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 /** 21 * Plotting engines similar to ps (PostScript, Gerber, svg) 22 * 23 * @file plotters_pslike.h 24 */ 25 26 #pragma once 27 28 #include "plotter.h" 29 30 31 /** 32 * The PSLIKE_PLOTTER class is an intermediate class to handle common routines for engines 33 * working more or less with the postscript imaging model. 34 */ 35 class PSLIKE_PLOTTER : public PLOTTER 36 { 37 public: PSLIKE_PLOTTER()38 PSLIKE_PLOTTER() : 39 plotScaleAdjX( 1 ), 40 plotScaleAdjY( 1 ), 41 m_textMode( PLOT_TEXT_MODE::PHANTOM ) 42 { 43 } 44 45 /** 46 * PS and PDF fully implement native text (for the Latin-1 subset) 47 */ SetTextMode(PLOT_TEXT_MODE mode)48 virtual void SetTextMode( PLOT_TEXT_MODE mode ) override 49 { 50 if( mode != PLOT_TEXT_MODE::DEFAULT ) 51 m_textMode = mode; 52 } 53 54 /** 55 * Set the 'fine' scaling for the postscript engine 56 */ SetScaleAdjust(double scaleX,double scaleY)57 void SetScaleAdjust( double scaleX, double scaleY ) 58 { 59 plotScaleAdjX = scaleX; 60 plotScaleAdjY = scaleY; 61 } 62 63 // Pad routines are handled with lower level primitives 64 virtual void FlashPadCircle( const wxPoint& aPadPos, int aDiameter, 65 OUTLINE_MODE aTraceMode, void* aData ) override; 66 virtual void FlashPadOval( const wxPoint& aPadPos, const wxSize& aSize, double aPadOrient, 67 OUTLINE_MODE aTraceMode, void* aData ) override; 68 virtual void FlashPadRect( const wxPoint& aPadPos, const wxSize& aSize, double aPadOrient, 69 OUTLINE_MODE aTraceMode, void* aData ) override; 70 virtual void FlashPadRoundRect( const wxPoint& aPadPos, const wxSize& aSize, 71 int aCornerRadius, double aOrient, 72 OUTLINE_MODE aTraceMode, void* aData ) override; 73 virtual void FlashPadCustom( const wxPoint& aPadPos, const wxSize& aSize, double aOrient, 74 SHAPE_POLY_SET* aPolygons, 75 OUTLINE_MODE aTraceMode, void* aData ) override; 76 virtual void FlashPadTrapez( const wxPoint& aPadPos, const wxPoint *aCorners, 77 double aPadOrient, OUTLINE_MODE aTraceMode, void* aData ) override; 78 virtual void FlashRegularPolygon( const wxPoint& aShapePos, int aDiameter, int aCornerCount, 79 double aOrient, OUTLINE_MODE aTraceMode, 80 void* aData ) override; 81 82 /** 83 * The SetColor implementation is split with the subclasses: 84 * The PSLIKE computes the rgb values, the subclass emits the 85 * operator to actually do it 86 */ 87 virtual void SetColor( const COLOR4D& color ) override; 88 89 protected: 90 /** 91 * This is the core for postscript/PDF text alignment. 92 * 93 * It computes the transformation matrix to generate a user space 94 * system aligned with the text. Even the PS uses the concat 95 * operator to simplify PDF generation (concat is everything PDF 96 * has to modify the CTM. Lots of parameters, both in and out. 97 */ 98 void computeTextParameters( const wxPoint& aPos, 99 const wxString& aText, 100 int aOrient, 101 const wxSize& aSize, 102 bool aMirror, 103 enum EDA_TEXT_HJUSTIFY_T aH_justify, 104 enum EDA_TEXT_VJUSTIFY_T aV_justify, 105 int aWidth, 106 bool aItalic, 107 bool aBold, 108 double *wideningFactor, 109 double *ctm_a, 110 double *ctm_b, 111 double *ctm_c, 112 double *ctm_d, 113 double *ctm_e, 114 double *ctm_f, 115 double *heightFactor ); 116 117 /** 118 * Computes the x coordinates for the overlining in a string of text. 119 * Fills the passed vector with couples of (start, stop) values to be 120 * used in the text coordinate system (use computeTextParameters to 121 * obtain the parameters to establish such a system) 122 */ 123 void postscriptOverlinePositions( const wxString& aText, int aXSize, bool aItalic, bool aBold, 124 std::vector<int> *pos_pairs ); 125 126 /// convert a wxString unicode string to a char string compatible with the accepted 127 /// string plotter format (convert special chars and non ascii7 chars) 128 virtual std::string encodeStringForPlotter( const wxString& aUnicode ); 129 130 /// Virtual primitive for emitting the setrgbcolor operator 131 virtual void emitSetRGBColor( double r, double g, double b ) = 0; 132 133 /// Height of the postscript font (from the AFM) 134 static const double postscriptTextAscent; // = 0.718; 135 136 /** 137 * Sister function for the GraphicTextWidth in drawtxt.cpp 138 * Does the same processing (i.e. calculates a text string width) but 139 * using postscript metrics for the Helvetica font (optionally used for 140 * PS and PDF plotting 141 */ 142 int returnPostscriptTextWidth( const wxString& aText, int aXSize, bool aItalic, bool aBold ); 143 144 /// Fine user scale adjust ( = 1.0 if no correction) 145 double plotScaleAdjX, plotScaleAdjY; 146 147 /// How to draw text 148 PLOT_TEXT_MODE m_textMode; 149 }; 150 151 152 class PS_PLOTTER : public PSLIKE_PLOTTER 153 { 154 public: PS_PLOTTER()155 PS_PLOTTER() 156 { 157 // The phantom plot in postscript is an hack and reportedly 158 // crashes Adobe's own postscript interpreter! 159 m_textMode = PLOT_TEXT_MODE::STROKE; 160 } 161 GetDefaultFileExtension()162 static wxString GetDefaultFileExtension() 163 { 164 return wxString( wxT( "ps" ) ); 165 } 166 GetPlotterType()167 virtual PLOT_FORMAT GetPlotterType() const override 168 { 169 return PLOT_FORMAT::POST; 170 } 171 172 /** 173 * The code within this function (and the CloseFilePS function) 174 * creates postscript files whose contents comply with Adobe's 175 * Document Structuring Convention, as documented by assorted 176 * details described within the following URLs: 177 * 178 * http://en.wikipedia.org/wiki/Document_Structuring_Conventions 179 * http://partners.adobe.com/public/developer/en/ps/5001.DSC_Spec.pdf 180 * 181 * 182 * BBox is the boundary box (position and size of the "client rectangle" 183 * for drawings (page - margins) in mils (0.001 inch) 184 */ 185 virtual bool StartPlot() override; 186 virtual bool EndPlot() override; 187 188 /** 189 * Set the current line width (in IUs) for the next plot. 190 */ 191 virtual void SetCurrentLineWidth( int width, void* aData = nullptr ) override; 192 193 /** 194 * PostScript supports dashed lines. 195 */ 196 virtual void SetDash( PLOT_DASH_TYPE dashed ) override; 197 198 virtual void SetViewport( const wxPoint& aOffset, double aIusPerDecimil, 199 double aScale, bool aMirror ) override; 200 virtual void Rect( const wxPoint& p1, const wxPoint& p2, FILL_T fill, 201 int width = USE_DEFAULT_LINE_WIDTH ) override; 202 virtual void Circle( const wxPoint& pos, int diametre, FILL_T fill, 203 int width = USE_DEFAULT_LINE_WIDTH ) override; 204 virtual void Arc( const wxPoint& centre, double StAngle, double EndAngle, int rayon, 205 FILL_T fill, int width = USE_DEFAULT_LINE_WIDTH ) override; 206 207 virtual void PlotPoly( const std::vector< wxPoint >& aCornerList, FILL_T aFill, 208 int aWidth = USE_DEFAULT_LINE_WIDTH, void* aData = nullptr ) override; 209 210 /** 211 * PostScript-likes at the moment are the only plot engines supporting bitmaps. 212 */ 213 virtual void PlotImage( const wxImage& aImage, const wxPoint& aPos, 214 double aScaleFactor ) override; 215 216 virtual void PenTo( const wxPoint& pos, char plume ) override; 217 virtual void Text( const wxPoint& aPos, 218 const COLOR4D& aColor, 219 const wxString& aText, 220 double aOrient, 221 const wxSize& aSize, 222 enum EDA_TEXT_HJUSTIFY_T aH_justify, 223 enum EDA_TEXT_VJUSTIFY_T aV_justify, 224 int aWidth, 225 bool aItalic, 226 bool aBold, 227 bool aMultilineAllowed = false, 228 void* aData = nullptr ) override; 229 protected: 230 virtual void emitSetRGBColor( double r, double g, double b ) override; 231 }; 232 233 234 class PDF_PLOTTER : public PSLIKE_PLOTTER 235 { 236 public: PDF_PLOTTER()237 PDF_PLOTTER() : 238 pageTreeHandle( 0 ), 239 fontResDictHandle( 0 ), 240 pageStreamHandle( 0 ), 241 streamLengthHandle( 0 ), 242 workFile( nullptr ) 243 { 244 } 245 GetPlotterType()246 virtual PLOT_FORMAT GetPlotterType() const override 247 { 248 return PLOT_FORMAT::PDF; 249 } 250 GetDefaultFileExtension()251 static wxString GetDefaultFileExtension() 252 { 253 return wxString( wxT( "pdf" ) ); 254 } 255 256 /** 257 * Open or create the plot file aFullFilename. 258 * 259 * The base class open the file in text mode, so we should have this 260 * function overlaid for PDF files, which are binary files. 261 * 262 * @param aFullFilename is the full file name of the file to create. 263 * @return true if success, false if the file cannot be created/opened. 264 */ 265 virtual bool OpenFile( const wxString& aFullFilename ) override; 266 267 /** 268 * The PDF engine supports multiple pages; the first one is opened 'for free' the following 269 * are to be closed and reopened. Between each page parameters can be set. 270 */ 271 virtual bool StartPlot() override; 272 virtual bool EndPlot() override; 273 274 /** 275 * Start a new page in the PDF document. 276 */ 277 virtual void StartPage(); 278 279 /** 280 * Close the current page in the PDF document (and emit its compressed stream). 281 */ 282 virtual void ClosePage(); 283 284 /** 285 * Pen width setting for PDF. 286 * 287 * Since the specs *explicitly* says that a 0 width is a bad thing to use (since it 288 * results in 1 pixel traces), we convert such requests to the minimal width (like 1) 289 * Note pen width = 0 is used in plot polygons to plot filled polygons with no outline 290 * thickness. Use in this case pen width = 1 does not actually change the polygon. 291 */ 292 virtual void SetCurrentLineWidth( int width, void* aData = nullptr ) override; 293 294 /** 295 * PDF supports dashed lines 296 */ 297 virtual void SetDash( PLOT_DASH_TYPE dashed ) override; 298 299 /** 300 * PDF can have multiple pages, so SetPageSettings can be called 301 * with the outputFile open (but not inside a page stream!) 302 */ 303 virtual void SetViewport( const wxPoint& aOffset, double aIusPerDecimil, 304 double aScale, bool aMirror ) override; 305 306 /** 307 * Rectangles in PDF. Supported by the native operator. 308 */ 309 virtual void Rect( const wxPoint& p1, const wxPoint& p2, FILL_T fill, 310 int width = USE_DEFAULT_LINE_WIDTH ) override; 311 312 /** 313 * Circle drawing for PDF. They're approximated by curves, but fill is supported 314 */ 315 virtual void Circle( const wxPoint& pos, int diametre, FILL_T fill, 316 int width = USE_DEFAULT_LINE_WIDTH ) override; 317 318 /** 319 * The PDF engine can't directly plot arcs, it uses the base emulation. 320 * So no filled arcs (not a great loss... ) 321 */ 322 virtual void Arc( const wxPoint& centre, double StAngle, double EndAngle, int rayon, 323 FILL_T fill, int width = USE_DEFAULT_LINE_WIDTH ) override; 324 325 /** 326 * Polygon plotting for PDF. Everything is supported 327 */ 328 virtual void PlotPoly( const std::vector< wxPoint >& aCornerList, FILL_T aFill, 329 int aWidth = USE_DEFAULT_LINE_WIDTH, void* aData = nullptr ) override; 330 331 virtual void PenTo( const wxPoint& pos, char plume ) override; 332 333 virtual void Text( const wxPoint& aPos, 334 const COLOR4D& aColor, 335 const wxString& aText, 336 double aOrient, 337 const wxSize& aSize, 338 enum EDA_TEXT_HJUSTIFY_T aH_justify, 339 enum EDA_TEXT_VJUSTIFY_T aV_justify, 340 int aWidth, 341 bool aItalic, 342 bool aBold, 343 bool aMultilineAllowed = false, 344 void* aData = nullptr ) override; 345 /** 346 * PDF images are handles as inline, not XObject streams... 347 */ 348 virtual void PlotImage( const wxImage& aImage, const wxPoint& aPos, 349 double aScaleFactor ) override; 350 351 352 protected: 353 /// convert a wxString unicode string to a char string compatible with the accepted 354 /// string PDF format (convert special chars and non ascii7 chars) 355 std::string encodeStringForPlotter( const wxString& aUnicode ) override; 356 357 /** 358 * PDF supports colors fully. It actually has distinct fill and pen colors, 359 * but we set both at the same time. 360 * 361 * XXX Keeping them divided could result in a minor optimization in 362 * Eeschema filled shapes, but would propagate to all the other plot 363 * engines. Also arcs are filled as pies but only the arc is stroked so 364 * it would be difficult to handle anyway. 365 */ 366 virtual void emitSetRGBColor( double r, double g, double b ) override; 367 368 /** 369 * Allocate a new handle in the table of the PDF object. The 370 * handle must be completed using startPdfObject. It's an in-RAM operation 371 * only, no output is done. 372 */ 373 int allocPdfObject(); 374 375 /** 376 * Open a new PDF object and returns the handle if the parameter is -1. 377 * Otherwise fill in the xref entry for the passed object 378 */ 379 int startPdfObject(int handle = -1); 380 381 /** 382 * Close the current PDF object 383 */ 384 void closePdfObject(); 385 386 /** 387 * Starts a PDF stream (for the page). Returns the object handle opened 388 * Pass -1 (default) for a fresh object. Especially from PDF 1.5 streams 389 * can contain a lot of things, but for the moment we only handle page 390 * content. 391 */ 392 int startPdfStream(int handle = -1); 393 394 /** 395 * Finish the current PDF stream (writes the deferred length, too) 396 */ 397 void closePdfStream(); 398 399 int pageTreeHandle; /// Handle to the root of the page tree object 400 int fontResDictHandle; /// Font resource dictionary 401 std::vector<int> pageHandles;/// Handles to the page objects 402 int pageStreamHandle; /// Handle of the page content object 403 int streamLengthHandle; /// Handle to the deferred stream length 404 wxString workFilename; 405 FILE* workFile; /// Temporary file to construct the stream before zipping 406 std::vector<long> xrefTable; /// The PDF xref offset table 407 }; 408 409 410 class SVG_PLOTTER : public PSLIKE_PLOTTER 411 { 412 public: 413 SVG_PLOTTER(); 414 GetDefaultFileExtension()415 static wxString GetDefaultFileExtension() 416 { 417 return wxString( wxT( "svg" ) ); 418 } 419 GetPlotterType()420 virtual PLOT_FORMAT GetPlotterType() const override 421 { 422 return PLOT_FORMAT::SVG; 423 } 424 425 virtual void SetColor( const COLOR4D& color ) override; 426 427 /** 428 * Create SVG file header. 429 */ 430 virtual bool StartPlot() override; 431 virtual bool EndPlot() override; 432 433 /** 434 * Set the current line width (in IUs) for the next plot. 435 */ 436 virtual void SetCurrentLineWidth( int width, void* aData = nullptr ) override; 437 438 /** 439 * SVG supports dashed lines. 440 */ 441 virtual void SetDash( PLOT_DASH_TYPE dashed ) override; 442 443 virtual void SetViewport( const wxPoint& aOffset, double aIusPerDecimil, 444 double aScale, bool aMirror ) override; 445 virtual void Rect( const wxPoint& p1, const wxPoint& p2, FILL_T fill, 446 int width = USE_DEFAULT_LINE_WIDTH ) override; 447 virtual void Circle( const wxPoint& pos, int diametre, FILL_T fill, 448 int width = USE_DEFAULT_LINE_WIDTH ) override; 449 virtual void Arc( const wxPoint& centre, double StAngle, double EndAngle, int rayon, 450 FILL_T fill, int width = USE_DEFAULT_LINE_WIDTH ) override; 451 452 virtual void BezierCurve( const wxPoint& aStart, const wxPoint& aControl1, 453 const wxPoint& aControl2, const wxPoint& aEnd, 454 int aTolerance, 455 int aLineThickness = USE_DEFAULT_LINE_WIDTH ) override; 456 457 virtual void PlotPoly( const std::vector< wxPoint >& aCornerList, FILL_T aFill, 458 int aWidth = USE_DEFAULT_LINE_WIDTH, void * aData = nullptr ) override; 459 460 /** 461 * PostScript-likes at the moment are the only plot engines supporting bitmaps. 462 */ 463 virtual void PlotImage( const wxImage& aImage, const wxPoint& aPos, 464 double aScaleFactor ) override; 465 466 virtual void PenTo( const wxPoint& pos, char plume ) override; 467 468 /** 469 * Select SVG step size (number of digits needed for 1 mm or 1 inch ) 470 * 471 * Should be called only after SetViewport() is called 472 * 473 * @param aResolution = number of digits in mantissa of coordinate 474 * use a value from 3-6 475 * do not use value > 6 to avoid overflow in PCBNEW 476 * do not use value > 4 to avoid overflow for other parts 477 * @param aUseInches = true to use inches, false to use mm (default) 478 */ 479 virtual void SetSvgCoordinatesFormat( unsigned aResolution, bool aUseInches = false ) override; 480 481 /** 482 * Calling this function allows one to define the beginning of a group 483 * of drawing items (used in SVG format to separate components) 484 * @param aData should be a string for the SVG ID tag 485 */ 486 virtual void StartBlock( void* aData ) override; 487 488 /** 489 * Calling this function allows one to define the end of a group of drawing 490 * items the group is started by StartBlock() 491 * @param aData should be null 492 */ 493 virtual void EndBlock( void* aData ) override; 494 495 virtual void Text( const wxPoint& aPos, 496 const COLOR4D& aColor, 497 const wxString& aText, 498 double aOrient, 499 const wxSize& aSize, 500 enum EDA_TEXT_HJUSTIFY_T aH_justify, 501 enum EDA_TEXT_VJUSTIFY_T aV_justify, 502 int aWidth, 503 bool aItalic, 504 bool aBold, 505 bool aMultilineAllowed = false, 506 void* aData = nullptr ) override; 507 508 protected: 509 /** 510 * Initialize m_pen_rgb_color from reduced values r, g ,b 511 * ( reduced values are 0.0 to 1.0 ) 512 */ 513 virtual void emitSetRGBColor( double r, double g, double b ) override; 514 515 /** 516 * Output the string which define pen and brush color, shape, transparency 517 * 518 * @param aIsGroup If false, do not form a new group for the style. 519 * @param aExtraStyle If given, the string will be added into the style string before closing 520 */ 521 void setSVGPlotStyle( bool aIsGroup = true, const std::string& aExtraStyle = {} ); 522 523 /** 524 * Prepare parameters for setSVGPlotStyle() 525 */ 526 void setFillMode( FILL_T fill ); 527 528 FILL_T m_fillMode; // true if the current contour 529 // rect, arc, circle, polygon must be filled 530 long m_pen_rgb_color; // current rgb color value: each color has 531 // a value 0 ... 255, and the 3 colors are 532 // grouped in a 3x8 bits value 533 // (written in hex to svg files) 534 long m_brush_rgb_color; // same as m_pen_rgb_color, used to fill 535 // some contours. 536 bool m_graphics_changed; // true if a pen/brush parameter is modified 537 // color, pen size, fill mode ... 538 // the new SVG stype must be output on file 539 PLOT_DASH_TYPE m_dashed; // plot line style 540 bool m_useInch; // is 0 if the step size is 10**-n*mm 541 // is 1 if the step size is 10**-n*inch 542 // Where n is given from m_precision 543 unsigned m_precision; // How fine the step size is 544 // Use 3-6 (3 means um precision, 6 nm precision) in PcbNew 545 // 3-4 in other modules (avoid values >4 to avoid overflow) 546 // see also comment for m_useInch. 547 }; 548