KiCad PCB EDA Suite
common_plotPDF_functions.cpp
Go to the documentation of this file.
1 
6 /*
7  * This program source code file is part of KiCad, a free EDA CAD application.
8  *
9  * Copyright (C) 1992-2012 Lorenzo Marcantonio, l.marcantonio@logossrl.com
10  * Copyright (C) 1992-2017 KiCad Developers, see AUTHORS.txt for contributors.
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, you may find one here:
24  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
25  * or you may search the http://www.gnu.org website for the version 2 license,
26  * or you may write to the Free Software Foundation, Inc.,
27  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
28  */
29 
30 #include <fctsys.h>
31 #include <pgm_base.h>
32 #include <trigo.h>
33 #include <wxstruct.h>
34 #include <base_struct.h>
35 #include <common.h>
36 #include <plot_common.h>
37 #include <macros.h>
38 #include <kicad_string.h>
39 #include <wx/zstream.h>
40 #include <wx/mstream.h>
41 
42 
43 /*
44  * Open or create the plot file aFullFilename
45  * return true if success, false if the file cannot be created/opened
46  *
47  * Opens the PDF file in binary mode
48  */
49 bool PDF_PLOTTER::OpenFile( const wxString& aFullFilename )
50 {
51  filename = aFullFilename;
52 
53  wxASSERT( !outputFile );
54 
55  // Open the PDF file in binary mode
56  outputFile = wxFopen( filename, wxT( "wb" ) );
57 
58  if( outputFile == NULL )
59  return false ;
60 
61  return true;
62 }
63 
64 void PDF_PLOTTER::SetPageSettings( const PAGE_INFO& aPageSettings )
65 {
66  wxASSERT( !workFile );
67  pageInfo = aPageSettings;
68 }
69 
70 void PDF_PLOTTER::SetViewport( const wxPoint& aOffset, double aIusPerDecimil,
71  double aScale, bool aMirror )
72 {
73  wxASSERT( !workFile );
74  m_plotMirror = aMirror;
75  plotOffset = aOffset;
76  plotScale = aScale;
77  m_IUsPerDecimil = aIusPerDecimil;
78 
79  // The CTM is set to 1 user unit per decimil
80  iuPerDeviceUnit = 1.0 / aIusPerDecimil;
81 
82  SetDefaultLineWidth( 100 / iuPerDeviceUnit ); // arbitrary default
83 
84  /* The paper size in this engined is handled page by page
85  Look in the StartPage function */
86 }
87 
88 
97 void PDF_PLOTTER::SetCurrentLineWidth( int width, void* aData )
98 {
99  wxASSERT( workFile );
100  int pen_width;
101 
102  if( width > 0 )
103  pen_width = width;
104  else if( width == 0 )
105  pen_width = 1;
106  else
107  pen_width = defaultPenWidth;
108 
109  if( pen_width != currentPenWidth )
110  fprintf( workFile, "%g w\n",
111  userToDeviceSize( pen_width ) );
112 
113  currentPenWidth = pen_width;
114 }
115 
116 
126 void PDF_PLOTTER::emitSetRGBColor( double r, double g, double b )
127 {
128  wxASSERT( workFile );
129  fprintf( workFile, "%g %g %g rg %g %g %g RG\n",
130  r, g, b, r, g, b );
131 }
132 
136 void PDF_PLOTTER::SetDash( bool dashed )
137 {
138  wxASSERT( workFile );
139  if( dashed )
140  fprintf( workFile, "[%d %d] 0 d\n",
141  (int) GetDashMarkLenIU(), (int) GetDashGapLenIU() );
142  else
143  fputs( "[] 0 d\n", workFile );
144 }
145 
146 
150 void PDF_PLOTTER::Rect( const wxPoint& p1, const wxPoint& p2, FILL_T fill, int width )
151 {
152  wxASSERT( workFile );
153  DPOINT p1_dev = userToDeviceCoordinates( p1 );
154  DPOINT p2_dev = userToDeviceCoordinates( p2 );
155 
156  SetCurrentLineWidth( width );
157  fprintf( workFile, "%g %g %g %g re %c\n", p1_dev.x, p1_dev.y,
158  p2_dev.x - p1_dev.x, p2_dev.y - p1_dev.y,
159  fill == NO_FILL ? 'S' : 'B' );
160 }
161 
162 
166 void PDF_PLOTTER::Circle( const wxPoint& pos, int diametre, FILL_T aFill, int width )
167 {
168  wxASSERT( workFile );
169  DPOINT pos_dev = userToDeviceCoordinates( pos );
170  double radius = userToDeviceSize( diametre / 2.0 );
171 
172  /* OK. Here's a trick. PDF doesn't support circles or circular angles, that's
173  a fact. You'll have to do with cubic beziers. These *can't* represent
174  circular arcs (NURBS can, beziers don't). But there is a widely known
175  approximation which is really good
176  */
177 
178  SetCurrentLineWidth( width );
179  double magic = radius * 0.551784; // You don't want to know where this come from
180 
181  // This is the convex hull for the bezier approximated circle
182  fprintf( workFile, "%g %g m "
183  "%g %g %g %g %g %g c "
184  "%g %g %g %g %g %g c "
185  "%g %g %g %g %g %g c "
186  "%g %g %g %g %g %g c %c\n",
187  pos_dev.x - radius, pos_dev.y,
188 
189  pos_dev.x - radius, pos_dev.y + magic,
190  pos_dev.x - magic, pos_dev.y + radius,
191  pos_dev.x, pos_dev.y + radius,
192 
193  pos_dev.x + magic, pos_dev.y + radius,
194  pos_dev.x + radius, pos_dev.y + magic,
195  pos_dev.x + radius, pos_dev.y,
196 
197  pos_dev.x + radius, pos_dev.y - magic,
198  pos_dev.x + magic, pos_dev.y - radius,
199  pos_dev.x, pos_dev.y - radius,
200 
201  pos_dev.x - magic, pos_dev.y - radius,
202  pos_dev.x - radius, pos_dev.y - magic,
203  pos_dev.x - radius, pos_dev.y,
204 
205  aFill == NO_FILL ? 's' : 'b' );
206 }
207 
208 
213 void PDF_PLOTTER::Arc( const wxPoint& centre, double StAngle, double EndAngle, int radius,
214  FILL_T fill, int width )
215 {
216  wxASSERT( workFile );
217  if( radius <= 0 )
218  return;
219 
220  /* Arcs are not so easily approximated by beziers (in the general case),
221  so we approximate them in the old way */
222  wxPoint start, end;
223  const int delta = 50; // increment (in 0.1 degrees) to draw circles
224 
225  if( StAngle > EndAngle )
226  std::swap( StAngle, EndAngle );
227 
228  SetCurrentLineWidth( width );
229 
230  // Usual trig arc plotting routine...
231  start.x = centre.x + KiROUND( cosdecideg( radius, -StAngle ) );
232  start.y = centre.y + KiROUND( sindecideg( radius, -StAngle ) );
233  DPOINT pos_dev = userToDeviceCoordinates( start );
234  fprintf( workFile, "%g %g m ", pos_dev.x, pos_dev.y );
235  for( int ii = StAngle + delta; ii < EndAngle; ii += delta )
236  {
237  end.x = centre.x + KiROUND( cosdecideg( radius, -ii ) );
238  end.y = centre.y + KiROUND( sindecideg( radius, -ii ) );
239  pos_dev = userToDeviceCoordinates( end );
240  fprintf( workFile, "%g %g l ", pos_dev.x, pos_dev.y );
241  }
242 
243  end.x = centre.x + KiROUND( cosdecideg( radius, -EndAngle ) );
244  end.y = centre.y + KiROUND( sindecideg( radius, -EndAngle ) );
245  pos_dev = userToDeviceCoordinates( end );
246  fprintf( workFile, "%g %g l ", pos_dev.x, pos_dev.y );
247 
248  // The arc is drawn... if not filled we stroke it, otherwise we finish
249  // closing the pie at the center
250  if( fill == NO_FILL )
251  {
252  fputs( "S\n", workFile );
253  }
254  else
255  {
256  pos_dev = userToDeviceCoordinates( centre );
257  fprintf( workFile, "%g %g l b\n", pos_dev.x, pos_dev.y );
258  }
259 }
260 
261 
265 void PDF_PLOTTER::PlotPoly( const std::vector< wxPoint >& aCornerList,
266  FILL_T aFill, int aWidth, void * aData )
267 {
268  wxASSERT( workFile );
269  if( aCornerList.size() <= 1 )
270  return;
271 
272  SetCurrentLineWidth( aWidth );
273 
274  DPOINT pos = userToDeviceCoordinates( aCornerList[0] );
275  fprintf( workFile, "%g %g m\n", pos.x, pos.y );
276 
277  for( unsigned ii = 1; ii < aCornerList.size(); ii++ )
278  {
279  pos = userToDeviceCoordinates( aCornerList[ii] );
280  fprintf( workFile, "%g %g l\n", pos.x, pos.y );
281  }
282 
283  // Close path and stroke(/fill)
284  fprintf( workFile, "%c\n", aFill == NO_FILL ? 'S' : 'b' );
285 }
286 
287 
288 void PDF_PLOTTER::PenTo( const wxPoint& pos, char plume )
289 {
290  wxASSERT( workFile );
291  if( plume == 'Z' )
292  {
293  if( penState != 'Z' )
294  {
295  fputs( "S\n", workFile );
296  penState = 'Z';
297  penLastpos.x = -1;
298  penLastpos.y = -1;
299  }
300  return;
301  }
302 
303  if( penState != plume || pos != penLastpos )
304  {
305  DPOINT pos_dev = userToDeviceCoordinates( pos );
306  fprintf( workFile, "%g %g %c\n",
307  pos_dev.x, pos_dev.y,
308  ( plume=='D' ) ? 'l' : 'm' );
309  }
310  penState = plume;
311  penLastpos = pos;
312 }
313 
317 void PDF_PLOTTER::PlotImage( const wxImage & aImage, const wxPoint& aPos,
318  double aScaleFactor )
319 {
320  wxASSERT( workFile );
321  wxSize pix_size( aImage.GetWidth(), aImage.GetHeight() );
322 
323  // Requested size (in IUs)
324  DPOINT drawsize( aScaleFactor * pix_size.x,
325  aScaleFactor * pix_size.y );
326 
327  // calculate the bitmap start position
328  wxPoint start( aPos.x - drawsize.x / 2,
329  aPos.y + drawsize.y / 2);
330 
331  DPOINT dev_start = userToDeviceCoordinates( start );
332 
333  /* PDF has an uhm... simplified coordinate system handling. There is
334  *one* operator to do everything (the PS concat equivalent). At least
335  they kept the matrix stack to save restore environments. Also images
336  are always emitted at the origin with a size of 1x1 user units.
337  What we need to do is:
338  1) save the CTM end estabilish the new one
339  2) plot the image
340  3) restore the CTM
341  4) profit
342  */
343  fprintf( workFile, "q %g 0 0 %g %g %g cm\n", // Step 1
344  userToDeviceSize( drawsize.x ),
345  userToDeviceSize( drawsize.y ),
346  dev_start.x, dev_start.y );
347 
348  /* An inline image is a cross between a dictionary and a stream.
349  A real ugly construct (compared with the elegance of the PDF
350  format). Also it accepts some 'abbreviations', which is stupid
351  since the content stream is usually compressed anyway... */
352  fprintf( workFile,
353  "BI\n"
354  " /BPC 8\n"
355  " /CS %s\n"
356  " /W %d\n"
357  " /H %d\n"
358  "ID\n", colorMode ? "/RGB" : "/G", pix_size.x, pix_size.y );
359 
360  /* Here comes the stream (in binary!). I *could* have hex or ascii84
361  encoded it, but who cares? I'll go through zlib anyway */
362  for( int y = 0; y < pix_size.y; y++ )
363  {
364  for( int x = 0; x < pix_size.x; x++ )
365  {
366  unsigned char r = aImage.GetRed( x, y ) & 0xFF;
367  unsigned char g = aImage.GetGreen( x, y ) & 0xFF;
368  unsigned char b = aImage.GetBlue( x, y ) & 0xFF;
369  // As usual these days, stdio buffering has to suffeeeeerrrr
370  if( colorMode )
371  {
372  putc( r, workFile );
373  putc( g, workFile );
374  putc( b, workFile );
375  }
376  else
377  {
378  // Grayscale conversion
379  putc( (r + g + b) / 3, workFile );
380  }
381  }
382  }
383 
384  fputs( "EI Q\n", workFile ); // Finish step 2 and do step 3
385 }
386 
387 
394 {
395  xrefTable.push_back( 0 );
396  return xrefTable.size() - 1;
397 }
398 
399 
405 {
406  wxASSERT( outputFile );
407  wxASSERT( !workFile );
408  if( handle < 0)
409  handle = allocPdfObject();
410 
411  xrefTable[handle] = ftell( outputFile );
412  fprintf( outputFile, "%d 0 obj\n", handle );
413  return handle;
414 }
415 
416 
421 {
422  wxASSERT( outputFile );
423  wxASSERT( !workFile );
424  fputs( "endobj\n", outputFile );
425 }
426 
427 
435 {
436  wxASSERT( outputFile );
437  wxASSERT( !workFile );
438  handle = startPdfObject( handle );
439 
440  // This is guaranteed to be handle+1 but needs to be allocated since
441  // you could allocate more object during stream preparation
443  fprintf( outputFile,
444  "<< /Length %d 0 R /Filter /FlateDecode >>\n" // Length is deferred
445  "stream\n", handle + 1 );
446 
447  // Open a temporary file to accumulate the stream
448  workFilename = filename + wxT(".tmp");
449  workFile = wxFopen( workFilename, wxT( "w+b" ));
450  wxASSERT( workFile );
451  return handle;
452 }
453 
454 
459 {
460  wxASSERT( workFile );
461 
462  long stream_len = ftell( workFile );
463 
464  if( stream_len < 0 )
465  {
466  wxASSERT( false );
467  return;
468  }
469 
470  // Rewind the file, read in the page stream and DEFLATE it
471  fseek( workFile, 0, SEEK_SET );
472  unsigned char *inbuf = new unsigned char[stream_len];
473 
474  int rc = fread( inbuf, 1, stream_len, workFile );
475  wxASSERT( rc == stream_len );
476  (void) rc;
477 
478  // We are done with the temporary file, junk it
479  fclose( workFile );
480  workFile = 0;
481  ::wxRemoveFile( workFilename );
482 
483  // NULL means memos owns the memory, but provide a hint on optimum size needed.
484  wxMemoryOutputStream memos( NULL, std::max( 2000l, stream_len ) ) ;
485 
486  {
487  /* Somewhat standard parameters to compress in DEFLATE. The PDF spec is
488  * misleading, it says it wants a DEFLATE stream but it really want a ZLIB
489  * stream! (a DEFLATE stream would be generated with -15 instead of 15)
490  * rc = deflateInit2( &zstrm, Z_BEST_COMPRESSION, Z_DEFLATED, 15,
491  * 8, Z_DEFAULT_STRATEGY );
492  */
493 
494  wxZlibOutputStream zos( memos, wxZ_BEST_COMPRESSION, wxZLIB_ZLIB );
495 
496  zos.Write( inbuf, stream_len );
497 
498  delete[] inbuf;
499 
500  } // flush the zip stream using zos destructor
501 
502  wxStreamBuffer* sb = memos.GetOutputStreamBuffer();
503 
504  unsigned out_count = sb->Tell();
505 
506  fwrite( sb->GetBufferStart(), 1, out_count, outputFile );
507 
508  fputs( "endstream\n", outputFile );
509  closePdfObject();
510 
511  // Writing the deferred length as an indirect object
513  fprintf( outputFile, "%u\n", out_count );
514  closePdfObject();
515 }
516 
521 {
522  wxASSERT( outputFile );
523  wxASSERT( !workFile );
524 
525  // Compute the paper size in IUs
527  paperSize.x *= 10.0 / iuPerDeviceUnit;
528  paperSize.y *= 10.0 / iuPerDeviceUnit;
529 
530  // Open the content stream; the page object will go later
532 
533  /* Now, until ClosePage *everything* must be wrote in workFile, to be
534  compressed later in closePdfStream */
535 
536  // Default graphic settings (coordinate system, default color and line style)
537  fprintf( workFile,
538  "%g 0 0 %g 0 0 cm 1 J 1 j 0 0 0 rg 0 0 0 RG %g w\n",
539  0.0072 * plotScaleAdjX, 0.0072 * plotScaleAdjY,
541 }
542 
547 {
548  wxASSERT( workFile );
549 
550  // Close the page stream (and compress it)
551  closePdfStream();
552 
553  // Emit the page object and put it in the page list for later
554  pageHandles.push_back( startPdfObject() );
555 
556  /* Page size is in 1/72 of inch (default user space units)
557  Works like the bbox in postscript but there is no need for
558  swapping the sizes, since PDF doesn't require a portrait page.
559  We use the MediaBox but PDF has lots of other less used boxes
560  to use */
561 
562  const double BIGPTsPERMIL = 0.072;
563  wxSize psPaperSize = pageInfo.GetSizeMils();
564 
565  fprintf( outputFile,
566  "<<\n"
567  "/Type /Page\n"
568  "/Parent %d 0 R\n"
569  "/Resources <<\n"
570  " /ProcSet [/PDF /Text /ImageC /ImageB]\n"
571  " /Font %d 0 R >>\n"
572  "/MediaBox [0 0 %d %d]\n"
573  "/Contents %d 0 R\n"
574  ">>\n",
577  int( ceil( psPaperSize.x * BIGPTsPERMIL ) ),
578  int( ceil( psPaperSize.y * BIGPTsPERMIL ) ),
580  closePdfObject();
581 
582  // Mark the page stream as idle
583  pageStreamHandle = 0;
584 }
585 
592 {
593  wxASSERT( outputFile );
594 
595  // First things first: the customary null object
596  xrefTable.clear();
597  xrefTable.push_back( 0 );
598 
599  /* The header (that's easy!). The second line is binary junk required
600  to make the file binary from the beginning (the important thing is
601  that they must have the bit 7 set) */
602  fputs( "%PDF-1.5\n%\200\201\202\203\n", outputFile );
603 
604  /* Allocate an entry for the page tree root, it will go in every page
605  parent entry */
607 
608  /* In the same way, the font resource dictionary is used by every page
609  (it *could* be inherited via the Pages tree */
611 
612  /* Now, the PDF is read from the end, (more or less)... so we start
613  with the page stream for page 1. Other more important stuff is written
614  at the end */
615  StartPage();
616  return true;
617 }
618 
619 
621 {
622  wxASSERT( outputFile );
623 
624  // Close the current page (often the only one)
625  ClosePage();
626 
627  /* We need to declare the resources we're using (fonts in particular)
628  The useful standard one is the Helvetica family. Adding external fonts
629  is *very* involved! */
630  struct {
631  const char *psname;
632  const char *rsname;
633  int font_handle;
634  } fontdefs[4] = {
635  { "/Helvetica", "/KicadFont", 0 },
636  { "/Helvetica-Oblique", "/KicadFontI", 0 },
637  { "/Helvetica-Bold", "/KicadFontB", 0 },
638  { "/Helvetica-BoldOblique", "/KicadFontBI", 0 }
639  };
640 
641  /* Declare the font resources. Since they're builtin fonts, no descriptors (yay!)
642  We'll need metrics anyway to do any aligment (these are in the shared with
643  the postscript engine) */
644  for( int i = 0; i < 4; i++ )
645  {
646  fontdefs[i].font_handle = startPdfObject();
647  fprintf( outputFile,
648  "<< /BaseFont %s\n"
649  " /Type /Font\n"
650  " /Subtype /Type1\n"
651 
652  /* Adobe is so Mac-based that the nearest thing to Latin1 is
653  the Windows ANSI encoding! */
654  " /Encoding /WinAnsiEncoding\n"
655  ">>\n",
656  fontdefs[i].psname );
657  closePdfObject();
658  }
659 
660  // Named font dictionary (was allocated, now we emit it)
662  fputs( "<<\n", outputFile );
663  for( int i = 0; i < 4; i++ )
664  {
665  fprintf( outputFile, " %s %d 0 R\n",
666  fontdefs[i].rsname, fontdefs[i].font_handle );
667  }
668  fputs( ">>\n", outputFile );
669  closePdfObject();
670 
671  /* The page tree: it's a B-tree but luckily we only have few pages!
672  So we use just an array... The handle was allocated at the beginning,
673  now we instantiate the corresponding object */
675  fputs( "<<\n"
676  "/Type /Pages\n"
677  "/Kids [\n", outputFile );
678 
679  for( unsigned i = 0; i < pageHandles.size(); i++ )
680  fprintf( outputFile, "%d 0 R\n", pageHandles[i] );
681 
682  fprintf( outputFile,
683  "]\n"
684  "/Count %ld\n"
685  ">>\n", (long) pageHandles.size() );
686  closePdfObject();
687 
688 
689  // The info dictionary
690  int infoDictHandle = startPdfObject();
691  char date_buf[250];
692  time_t ltime = time( NULL );
693  strftime( date_buf, 250, "D:%Y%m%d%H%M%S",
694  localtime( &ltime ) );
695 
696  if( title.IsEmpty() )
697  {
698  // Windows uses '\' and other platforms ue '/' as sepatator
699  title = filename.AfterLast('\\');
700  title = title.AfterLast('/');
701  }
702 
703  fprintf( outputFile,
704  "<<\n"
705  "/Producer (KiCAD PDF)\n"
706  "/CreationDate (%s)\n"
707  "/Creator (%s)\n"
708  "/Title (%s)\n"
709  "/Trapped false\n",
710  date_buf,
711  TO_UTF8( creator ),
712  TO_UTF8( title ) );
713 
714  fputs( ">>\n", outputFile );
715  closePdfObject();
716 
717  // The catalog, at last
718  int catalogHandle = startPdfObject();
719  fprintf( outputFile,
720  "<<\n"
721  "/Type /Catalog\n"
722  "/Pages %d 0 R\n"
723  "/Version /1.5\n"
724  "/PageMode /UseNone\n"
725  "/PageLayout /SinglePage\n"
726  ">>\n", pageTreeHandle );
727  closePdfObject();
728 
729  /* Emit the xref table (format is crucial to the byte, each entry must
730  be 20 bytes long, and object zero must be done in that way). Also
731  the offset must be kept along for the trailer */
732  long xref_start = ftell( outputFile );
733  fprintf( outputFile,
734  "xref\n"
735  "0 %ld\n"
736  "0000000000 65535 f \n", (long) xrefTable.size() );
737  for( unsigned i = 1; i < xrefTable.size(); i++ )
738  {
739  fprintf( outputFile, "%010ld 00000 n \n", xrefTable[i] );
740  }
741 
742  // Done the xref, go for the trailer
743  fprintf( outputFile,
744  "trailer\n"
745  "<< /Size %lu /Root %d 0 R /Info %d 0 R >>\n"
746  "startxref\n"
747  "%ld\n" // The offset we saved before
748  "%%%%EOF\n",
749  (unsigned long) xrefTable.size(), catalogHandle, infoDictHandle, xref_start );
750 
751  fclose( outputFile );
752  outputFile = NULL;
753 
754  return true;
755 }
756 
757 void PDF_PLOTTER::Text( const wxPoint& aPos,
758  const COLOR4D aColor,
759  const wxString& aText,
760  double aOrient,
761  const wxSize& aSize,
762  enum EDA_TEXT_HJUSTIFY_T aH_justify,
763  enum EDA_TEXT_VJUSTIFY_T aV_justify,
764  int aWidth,
765  bool aItalic,
766  bool aBold,
767  bool aMultilineAllowed,
768  void* aData )
769 {
770  // PDF files do not like 0 sized texts which create broken files.
771  if( aSize.x == 0 || aSize.y == 0 )
772  return;
773 
774  // Fix me: see how to use PDF text mode for multiline texts
775  if( aMultilineAllowed && !aText.Contains( wxT( "\n" ) ) )
776  aMultilineAllowed = false; // the text has only one line.
777 
778  // Emit native PDF text (if requested)
779  if( m_textMode != PLOTTEXTMODE_STROKE && !aMultilineAllowed )
780  {
781  const char *fontname = aItalic ? (aBold ? "/KicadFontBI" : "/KicadFontI")
782  : (aBold ? "/KicadFontB" : "/KicadFont");
783 
784  // Compute the copious tranformation parameters
785  double ctm_a, ctm_b, ctm_c, ctm_d, ctm_e, ctm_f;
786  double wideningFactor, heightFactor;
787  computeTextParameters( aPos, aText, aOrient, aSize, aH_justify,
788  aV_justify, aWidth, aItalic, aBold,
789  &wideningFactor, &ctm_a, &ctm_b, &ctm_c,
790  &ctm_d, &ctm_e, &ctm_f, &heightFactor );
791 
792  SetColor( aColor );
793  SetCurrentLineWidth( aWidth, aData );
794 
795  /* We use the full CTM instead of the text matrix because the same
796  coordinate system will be used for the overlining. Also the %f
797  for the trig part of the matrix to avoid %g going in exponential
798  format (which is not supported)
799  Rendermode 0 shows the text, rendermode 3 is invisible */
800  fprintf( workFile, "q %f %f %f %f %g %g cm BT %s %g Tf %d Tr %g Tz ",
801  ctm_a, ctm_b, ctm_c, ctm_d, ctm_e, ctm_f,
802  fontname, heightFactor,
803  (m_textMode == PLOTTEXTMODE_NATIVE) ? 0 : 3,
804  wideningFactor * 100 );
805 
806  // The text must be escaped correctly
808  fputs( " Tj ET\n", workFile );
809 
810  /* We are still in text coordinates, plot the overbars (if we're
811  * not doing phantom text) */
813  {
814  std::vector<int> pos_pairs;
815  postscriptOverlinePositions( aText, aSize.x, aItalic, aBold, &pos_pairs );
816  int overbar_y = KiROUND( aSize.y * 1.1 );
817  for( unsigned i = 0; i < pos_pairs.size(); i += 2)
818  {
819  /* This is a nontrivial situation: we are *not* in the user
820  coordinate system, so the userToDeviceCoordinates function
821  can't be used! Strange as it may seem, the userToDeviceSize
822  is the right function to use here... */
823  DPOINT dev_from = userToDeviceSize( wxSize( pos_pairs[i], overbar_y ) );
824  DPOINT dev_to = userToDeviceSize( wxSize( pos_pairs[i + 1], overbar_y ) );
825  fprintf( workFile, "%g %g m %g %g l ",
826  dev_from.x, dev_from.y, dev_to.x, dev_to.y );
827  }
828  }
829 
830  // Stroke and restore the CTM
831  fputs( "S Q\n", workFile );
832  }
833 
834  // Plot the stroked text (if requested)
835  if( m_textMode != PLOTTEXTMODE_NATIVE || aMultilineAllowed )
836  {
837  PLOTTER::Text( aPos, aColor, aText, aOrient, aSize, aH_justify, aV_justify,
838  aWidth, aItalic, aBold, aMultilineAllowed );
839  }
840 }
841 
void closePdfStream()
Finish the current PDF stream (writes the deferred length, too)
EDA_TEXT_HJUSTIFY_T
Definition: eda_text.h:47
static int KiROUND(double v)
KiROUND rounds a floating point number to an int using "round halfway cases away from zero"...
Definition: common.h:128
virtual bool EndPlot() override
virtual void StartPage()
Starts a new page in the PDF document.
int pageTreeHandle
Definition: plot_common.h:868
virtual void PenTo(const wxPoint &pos, char plume) override
moveto/lineto primitive, moves the 'pen' to the specified direction
virtual void Text(const wxPoint &aPos, const COLOR4D aColor, const wxString &aText, double aOrient, const wxSize &aSize, enum EDA_TEXT_HJUSTIFY_T aH_justify, enum EDA_TEXT_VJUSTIFY_T aV_justify, int aWidth, bool aItalic, bool aBold, bool aMultilineAllowed=false, void *aData=NULL) override
Draws text with the plotter.
std::vector< int > pageHandles
Font resource dictionary.
Definition: plot_common.h:870
bool colorMode
Definition: plot_common.h:537
char penState
Current pen state: 'U', 'D' or 'Z' (see PenTo)
Definition: plot_common.h:542
double m_IUsPerDecimil
Definition: plot_common.h:519
wxPoint plotOffset
Plot offset (in IUs)
Definition: plot_common.h:525
wxPoint penLastpos
Last pen positions; set to -1,-1 when the pen is at rest.
Definition: plot_common.h:544
static const int delta[8][2]
Definition: solve.cpp:112
PAGE_INFO pageInfo
Definition: plot_common.h:548
virtual void SetDash(bool dashed) override
PDF supports dashed lines.
This file contains miscellaneous commonly used macros and functions.
const wxSize & GetSizeMils() const
virtual void Text(const wxPoint &aPos, const COLOR4D aColor, const wxString &aText, double aOrient, const wxSize &aSize, enum EDA_TEXT_HJUSTIFY_T aH_justify, enum EDA_TEXT_VJUSTIFY_T aV_justify, int aWidth, bool aItalic, bool aBold, bool aMultilineAllowed=false, void *aData=NULL)
Draws text with the plotter.
Definition: drawtxt.cpp:227
wxString workFilename
Handle to the deferred stream length.
Definition: plot_common.h:873
virtual void PlotPoly(const std::vector< wxPoint > &aCornerList, FILL_T aFill, int aWidth=USE_DEFAULT_LINE_WIDTH, void *aData=NULL) override
Polygon plotting for PDF.
#define TO_UTF8(wxstring)
Macro TO_UTF8 converts a wxString to a UTF8 encoded C string for all wxWidgets build modes...
Definition: macros.h:47
virtual void ClosePage()
Close the current page in the PDF document (and emit its compressed stream)
int streamLengthHandle
Handle of the page content object.
Definition: plot_common.h:872
bool m_plotMirror
X axis orientation (SVG) and plot mirrored (only for PS, PDF HPGL and SVG)
Definition: plot_common.h:529
virtual void SetDefaultLineWidth(int width) override
Set the default line width.
virtual void Arc(const wxPoint &centre, double StAngle, double EndAngle, int rayon, FILL_T fill, int width=USE_DEFAULT_LINE_WIDTH) override
The PDF engine can't directly plot arcs, it uses the base emulation.
Base window classes and related definitions.
double plotScaleAdjY
Definition: plot_common.h:724
int startPdfStream(int handle=-1)
Starts a PDF stream (for the page).
Class PAGE_INFO describes the page size and margins of a paper page on which to eventually print or p...
int startPdfObject(int handle=-1)
Open a new PDF object and returns the handle if the parameter is -1.
virtual void SetViewport(const wxPoint &aOffset, double aIusPerDecimil, double aScale, bool aMirror) override
Set the plot offset and scaling for the current plot.
virtual void SetColor(COLOR4D color) override
The SetColor implementation is split with the subclasses: The PSLIKE computes the rgb values...
double plotScale
Plot scale - chosen by the user (even implicitly with 'fit in a4')
Definition: plot_common.h:513
Common plot library Plot settings, and plotting engines (Postscript, Gerber, HPGL and DXF) ...
FILE * workFile
Definition: plot_common.h:874
virtual DPOINT userToDeviceSize(const wxSize &size)
Modifies size according to the plotter scale factors (wxSize version, returns a DPOINT) ...
void closePdfObject()
Close the current PDF object.
EDA_TEXT_VJUSTIFY_T
Definition: eda_text.h:54
wxString title
Definition: plot_common.h:547
virtual DPOINT userToDeviceCoordinates(const wxPoint &aCoordinate)
Modifies coordinates according to the orientation, scale factor, and offsets trace.
virtual void Rect(const wxPoint &p1, const wxPoint &p2, FILL_T fill, int width=USE_DEFAULT_LINE_WIDTH) override
Rectangles in PDF.
int fontResDictHandle
Handle to the root of the page tree object.
Definition: plot_common.h:869
double cosdecideg(double r, double a)
Circle generation utility: computes r * cos(a) Where a is in decidegrees, not in radians.
Definition: trigo.h:311
double sindecideg(double r, double a)
Circle generation utility: computes r * sin(a) Where a is in decidegrees, not in radians.
Definition: trigo.h:302
void fputsPostscriptString(FILE *fout, const wxString &txt)
Write on a stream a string escaped for postscript/PDF.
virtual void emitSetRGBColor(double r, double g, double b) override
PDF supports colors fully.
see class PGM_BASE
std::vector< long > xrefTable
Temporary file to costruct the stream before zipping.
Definition: plot_common.h:875
int currentPenWidth
Definition: plot_common.h:540
#define max(a, b)
Definition: auxiliary.h:86
int defaultPenWidth
true to generate a negative image (PS mode mainly)
Definition: plot_common.h:539
virtual void Circle(const wxPoint &pos, int diametre, FILL_T fill, int width=USE_DEFAULT_LINE_WIDTH) override
Circle drawing for PDF.
double plotScaleAdjX
Fine user scale adjust ( = 1.0 if no correction)
Definition: plot_common.h:724
FILE * outputFile
true if the Y axis is top to bottom (SVG)
Definition: plot_common.h:534
double GetDashGapLenIU() const
The common library.
FILL_T
Enum FILL_T is the set of fill types used in plotting or drawing enclosed areas.
Definition: base_struct.h:56
void postscriptOverlinePositions(const wxString &aText, int aXSize, bool aItalic, bool aBold, std::vector< int > *pos_pairs)
Computes the x coordinates for the overlining in a string of text.
virtual bool OpenFile(const wxString &aFullFilename) override
Open or create the plot file aFullFilename.
Basic classes for most KiCad items.
virtual void SetPageSettings(const PAGE_INFO &aPageSettings) override
PDF can have multiple pages, so SetPageSettings can be called with the outputFile open (but not insid...
double GetDashMarkLenIU() const
virtual bool StartPlot() override
The PDF engine supports multiple pages; the first one is opened 'for free' the following are to be cl...
double iuPerDeviceUnit
Device scale (from IUs to plotter device units - usually decimils)
Definition: plot_common.h:522
wxString filename
Definition: plot_common.h:546
PlotTextMode m_textMode
How to draw text.
Definition: plot_common.h:727
int allocPdfObject()
Allocate a new handle in the table of the PDF object.
void computeTextParameters(const wxPoint &aPos, const wxString &aText, int aOrient, const wxSize &aSize, enum EDA_TEXT_HJUSTIFY_T aH_justify, enum EDA_TEXT_VJUSTIFY_T aV_justify, int aWidth, bool aItalic, bool aBold, double *wideningFactor, double *ctm_a, double *ctm_b, double *ctm_c, double *ctm_d, double *ctm_e, double *ctm_f, double *heightFactor)
This is the core for postscript/PDF text alignment It computes the transformation matrix to generate ...
int pageStreamHandle
Handles to the page objects.
Definition: plot_common.h:871
wxString creator
Definition: plot_common.h:545
wxSize paperSize
Paper size in IU - not in mils.
Definition: plot_common.h:550
virtual void SetCurrentLineWidth(int width, void *aData=NULL) override
Pen width setting for PDF.
Class COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:39
virtual void PlotImage(const wxImage &aImage, const wxPoint &aPos, double aScaleFactor) override
PDF images are handles as inline, not XObject streams...