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 <class_plotter.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  pageInfo = aPageSettings;
67 }
68 
69 void PDF_PLOTTER::SetViewport( const wxPoint& aOffset, double aIusPerDecimil,
70  double aScale, bool aMirror )
71 {
72  m_plotMirror = aMirror;
73  plotOffset = aOffset;
74  plotScale = aScale;
75  m_IUsPerDecimil = aIusPerDecimil;
76 
77  // The CTM is set to 1 user unit per decimil
78  iuPerDeviceUnit = 1.0 / aIusPerDecimil;
79 
80  SetDefaultLineWidth( 100 / iuPerDeviceUnit ); // arbitrary default
81 
82  /* The paper size in this engined is handled page by page
83  Look in the StartPage function */
84 }
85 
86 
95 void PDF_PLOTTER::SetCurrentLineWidth( int width, void* aData )
96 {
97  wxASSERT( workFile );
98  int pen_width;
99 
100  if( width > 0 )
101  pen_width = width;
102  else if( width == 0 )
103  pen_width = 1;
104  else
105  pen_width = defaultPenWidth;
106 
107  if( pen_width != currentPenWidth )
108  fprintf( workFile, "%g w\n",
109  userToDeviceSize( pen_width ) );
110 
111  currentPenWidth = pen_width;
112 }
113 
114 
124 void PDF_PLOTTER::emitSetRGBColor( double r, double g, double b )
125 {
126  wxASSERT( workFile );
127  fprintf( workFile, "%g %g %g rg %g %g %g RG\n",
128  r, g, b, r, g, b );
129 }
130 
134 void PDF_PLOTTER::SetDash( int dashed )
135 {
136  wxASSERT( workFile );
137  switch( dashed )
138  {
139  case PLOTDASHTYPE_DASH:
140  fprintf( workFile, "[%d %d] 0 d\n",
141  (int) GetDashMarkLenIU(), (int) GetDashGapLenIU() );
142  break;
143  case PLOTDASHTYPE_DOT:
144  fprintf( workFile, "[%d %d] 0 d\n",
145  (int) GetDotMarkLenIU(), (int) GetDashGapLenIU() );
146  break;
148  fprintf( workFile, "[%d %d %d %d] 0 d\n",
149  (int) GetDashMarkLenIU(), (int) GetDashGapLenIU(),
150  (int) GetDotMarkLenIU(), (int) GetDashGapLenIU() );
151  break;
152  default:
153  fputs( "[] 0 d\n", workFile );
154  }
155 }
156 
157 
161 void PDF_PLOTTER::Rect( const wxPoint& p1, const wxPoint& p2, FILL_T fill, int width )
162 {
163  wxASSERT( workFile );
164  DPOINT p1_dev = userToDeviceCoordinates( p1 );
165  DPOINT p2_dev = userToDeviceCoordinates( p2 );
166 
167  SetCurrentLineWidth( width );
168  fprintf( workFile, "%g %g %g %g re %c\n", p1_dev.x, p1_dev.y,
169  p2_dev.x - p1_dev.x, p2_dev.y - p1_dev.y,
170  fill == NO_FILL ? 'S' : 'B' );
171 }
172 
173 
177 void PDF_PLOTTER::Circle( const wxPoint& pos, int diametre, FILL_T aFill, int width )
178 {
179  wxASSERT( workFile );
180  DPOINT pos_dev = userToDeviceCoordinates( pos );
181  double radius = userToDeviceSize( diametre / 2.0 );
182 
183  /* OK. Here's a trick. PDF doesn't support circles or circular angles, that's
184  a fact. You'll have to do with cubic beziers. These *can't* represent
185  circular arcs (NURBS can, beziers don't). But there is a widely known
186  approximation which is really good
187  */
188 
189  SetCurrentLineWidth( width );
190  double magic = radius * 0.551784; // You don't want to know where this come from
191 
192  // This is the convex hull for the bezier approximated circle
193  fprintf( workFile, "%g %g m "
194  "%g %g %g %g %g %g c "
195  "%g %g %g %g %g %g c "
196  "%g %g %g %g %g %g c "
197  "%g %g %g %g %g %g c %c\n",
198  pos_dev.x - radius, pos_dev.y,
199 
200  pos_dev.x - radius, pos_dev.y + magic,
201  pos_dev.x - magic, pos_dev.y + radius,
202  pos_dev.x, pos_dev.y + radius,
203 
204  pos_dev.x + magic, pos_dev.y + radius,
205  pos_dev.x + radius, pos_dev.y + magic,
206  pos_dev.x + radius, pos_dev.y,
207 
208  pos_dev.x + radius, pos_dev.y - magic,
209  pos_dev.x + magic, pos_dev.y - radius,
210  pos_dev.x, pos_dev.y - radius,
211 
212  pos_dev.x - magic, pos_dev.y - radius,
213  pos_dev.x - radius, pos_dev.y - magic,
214  pos_dev.x - radius, pos_dev.y,
215 
216  aFill == NO_FILL ? 's' : 'b' );
217 }
218 
219 
224 void PDF_PLOTTER::Arc( const wxPoint& centre, double StAngle, double EndAngle, int radius,
225  FILL_T fill, int width )
226 {
227  wxASSERT( workFile );
228  if( radius <= 0 )
229  return;
230 
231  /* Arcs are not so easily approximated by beziers (in the general case),
232  so we approximate them in the old way */
233  wxPoint start, end;
234  const int delta = 50; // increment (in 0.1 degrees) to draw circles
235 
236  if( StAngle > EndAngle )
237  std::swap( StAngle, EndAngle );
238 
239  SetCurrentLineWidth( width );
240 
241  // Usual trig arc plotting routine...
242  start.x = centre.x + KiROUND( cosdecideg( radius, -StAngle ) );
243  start.y = centre.y + KiROUND( sindecideg( radius, -StAngle ) );
244  DPOINT pos_dev = userToDeviceCoordinates( start );
245  fprintf( workFile, "%g %g m ", pos_dev.x, pos_dev.y );
246  for( int ii = StAngle + delta; ii < EndAngle; ii += delta )
247  {
248  end.x = centre.x + KiROUND( cosdecideg( radius, -ii ) );
249  end.y = centre.y + KiROUND( sindecideg( radius, -ii ) );
250  pos_dev = userToDeviceCoordinates( end );
251  fprintf( workFile, "%g %g l ", pos_dev.x, pos_dev.y );
252  }
253 
254  end.x = centre.x + KiROUND( cosdecideg( radius, -EndAngle ) );
255  end.y = centre.y + KiROUND( sindecideg( radius, -EndAngle ) );
256  pos_dev = userToDeviceCoordinates( end );
257  fprintf( workFile, "%g %g l ", pos_dev.x, pos_dev.y );
258 
259  // The arc is drawn... if not filled we stroke it, otherwise we finish
260  // closing the pie at the center
261  if( fill == NO_FILL )
262  {
263  fputs( "S\n", workFile );
264  }
265  else
266  {
267  pos_dev = userToDeviceCoordinates( centre );
268  fprintf( workFile, "%g %g l b\n", pos_dev.x, pos_dev.y );
269  }
270 }
271 
272 
276 void PDF_PLOTTER::PlotPoly( const std::vector< wxPoint >& aCornerList,
277  FILL_T aFill, int aWidth, void * aData )
278 {
279  wxASSERT( workFile );
280  if( aCornerList.size() <= 1 )
281  return;
282 
283  SetCurrentLineWidth( aWidth );
284 
285  DPOINT pos = userToDeviceCoordinates( aCornerList[0] );
286  fprintf( workFile, "%g %g m\n", pos.x, pos.y );
287 
288  for( unsigned ii = 1; ii < aCornerList.size(); ii++ )
289  {
290  pos = userToDeviceCoordinates( aCornerList[ii] );
291  fprintf( workFile, "%g %g l\n", pos.x, pos.y );
292  }
293 
294  // Close path and stroke(/fill)
295  fprintf( workFile, "%c\n", aFill == NO_FILL ? 'S' : 'b' );
296 }
297 
298 
299 void PDF_PLOTTER::PenTo( const wxPoint& pos, char plume )
300 {
301  wxASSERT( workFile );
302  if( plume == 'Z' )
303  {
304  if( penState != 'Z' )
305  {
306  fputs( "S\n", workFile );
307  penState = 'Z';
308  penLastpos.x = -1;
309  penLastpos.y = -1;
310  }
311  return;
312  }
313 
314  if( penState != plume || pos != penLastpos )
315  {
316  DPOINT pos_dev = userToDeviceCoordinates( pos );
317  fprintf( workFile, "%g %g %c\n",
318  pos_dev.x, pos_dev.y,
319  ( plume=='D' ) ? 'l' : 'm' );
320  }
321  penState = plume;
322  penLastpos = pos;
323 }
324 
328 void PDF_PLOTTER::PlotImage( const wxImage & aImage, const wxPoint& aPos,
329  double aScaleFactor )
330 {
331  wxASSERT( workFile );
332  wxSize pix_size( aImage.GetWidth(), aImage.GetHeight() );
333 
334  // Requested size (in IUs)
335  DPOINT drawsize( aScaleFactor * pix_size.x,
336  aScaleFactor * pix_size.y );
337 
338  // calculate the bitmap start position
339  wxPoint start( aPos.x - drawsize.x / 2,
340  aPos.y + drawsize.y / 2);
341 
342  DPOINT dev_start = userToDeviceCoordinates( start );
343 
344  /* PDF has an uhm... simplified coordinate system handling. There is
345  *one* operator to do everything (the PS concat equivalent). At least
346  they kept the matrix stack to save restore environments. Also images
347  are always emitted at the origin with a size of 1x1 user units.
348  What we need to do is:
349  1) save the CTM end estabilish the new one
350  2) plot the image
351  3) restore the CTM
352  4) profit
353  */
354  fprintf( workFile, "q %g 0 0 %g %g %g cm\n", // Step 1
355  userToDeviceSize( drawsize.x ),
356  userToDeviceSize( drawsize.y ),
357  dev_start.x, dev_start.y );
358 
359  /* An inline image is a cross between a dictionary and a stream.
360  A real ugly construct (compared with the elegance of the PDF
361  format). Also it accepts some 'abbreviations', which is stupid
362  since the content stream is usually compressed anyway... */
363  fprintf( workFile,
364  "BI\n"
365  " /BPC 8\n"
366  " /CS %s\n"
367  " /W %d\n"
368  " /H %d\n"
369  "ID\n", colorMode ? "/RGB" : "/G", pix_size.x, pix_size.y );
370 
371  /* Here comes the stream (in binary!). I *could* have hex or ascii84
372  encoded it, but who cares? I'll go through zlib anyway */
373  for( int y = 0; y < pix_size.y; y++ )
374  {
375  for( int x = 0; x < pix_size.x; x++ )
376  {
377  unsigned char r = aImage.GetRed( x, y ) & 0xFF;
378  unsigned char g = aImage.GetGreen( x, y ) & 0xFF;
379  unsigned char b = aImage.GetBlue( x, y ) & 0xFF;
380  // As usual these days, stdio buffering has to suffeeeeerrrr
381  if( colorMode )
382  {
383  putc( r, workFile );
384  putc( g, workFile );
385  putc( b, workFile );
386  }
387  else
388  {
389  // Grayscale conversion
390  putc( (r + g + b) / 3, workFile );
391  }
392  }
393  }
394 
395  fputs( "EI Q\n", workFile ); // Finish step 2 and do step 3
396 }
397 
398 
405 {
406  xrefTable.push_back( 0 );
407  return xrefTable.size() - 1;
408 }
409 
410 
416 {
417  wxASSERT( outputFile );
418  wxASSERT( !workFile );
419 
420  if( handle < 0)
421  handle = allocPdfObject();
422 
423  xrefTable[handle] = ftell( outputFile );
424  fprintf( outputFile, "%d 0 obj\n", handle );
425  return handle;
426 }
427 
428 
433 {
434  wxASSERT( outputFile );
435  wxASSERT( !workFile );
436  fputs( "endobj\n", outputFile );
437 }
438 
439 
447 {
448  wxASSERT( outputFile );
449  wxASSERT( !workFile );
450  handle = startPdfObject( handle );
451 
452  // This is guaranteed to be handle+1 but needs to be allocated since
453  // you could allocate more object during stream preparation
455  fprintf( outputFile,
456  "<< /Length %d 0 R /Filter /FlateDecode >>\n" // Length is deferred
457  "stream\n", handle + 1 );
458 
459  // Open a temporary file to accumulate the stream
460  workFilename = filename + wxT(".tmp");
461  workFile = wxFopen( workFilename, wxT( "w+b" ));
462  wxASSERT( workFile );
463  return handle;
464 }
465 
466 
471 {
472  wxASSERT( workFile );
473 
474  long stream_len = ftell( workFile );
475 
476  if( stream_len < 0 )
477  {
478  wxASSERT( false );
479  return;
480  }
481 
482  // Rewind the file, read in the page stream and DEFLATE it
483  fseek( workFile, 0, SEEK_SET );
484  unsigned char *inbuf = new unsigned char[stream_len];
485 
486  int rc = fread( inbuf, 1, stream_len, workFile );
487  wxASSERT( rc == stream_len );
488  (void) rc;
489 
490  // We are done with the temporary file, junk it
491  fclose( workFile );
492  workFile = 0;
493  ::wxRemoveFile( workFilename );
494 
495  // NULL means memos owns the memory, but provide a hint on optimum size needed.
496  wxMemoryOutputStream memos( NULL, std::max( 2000l, stream_len ) ) ;
497 
498  {
499  /* Somewhat standard parameters to compress in DEFLATE. The PDF spec is
500  * misleading, it says it wants a DEFLATE stream but it really want a ZLIB
501  * stream! (a DEFLATE stream would be generated with -15 instead of 15)
502  * rc = deflateInit2( &zstrm, Z_BEST_COMPRESSION, Z_DEFLATED, 15,
503  * 8, Z_DEFAULT_STRATEGY );
504  */
505 
506  wxZlibOutputStream zos( memos, wxZ_BEST_COMPRESSION, wxZLIB_ZLIB );
507 
508  zos.Write( inbuf, stream_len );
509 
510  delete[] inbuf;
511 
512  } // flush the zip stream using zos destructor
513 
514  wxStreamBuffer* sb = memos.GetOutputStreamBuffer();
515 
516  unsigned out_count = sb->Tell();
517 
518  fwrite( sb->GetBufferStart(), 1, out_count, outputFile );
519 
520  fputs( "endstream\n", outputFile );
521  closePdfObject();
522 
523  // Writing the deferred length as an indirect object
525  fprintf( outputFile, "%u\n", out_count );
526  closePdfObject();
527 }
528 
533 {
534  wxASSERT( outputFile );
535  wxASSERT( !workFile );
536 
537  // Compute the paper size in IUs
539  paperSize.x *= 10.0 / iuPerDeviceUnit;
540  paperSize.y *= 10.0 / iuPerDeviceUnit;
541 
542  // Open the content stream; the page object will go later
544 
545  /* Now, until ClosePage *everything* must be wrote in workFile, to be
546  compressed later in closePdfStream */
547 
548  // Default graphic settings (coordinate system, default color and line style)
549  fprintf( workFile,
550  "%g 0 0 %g 0 0 cm 1 J 1 j 0 0 0 rg 0 0 0 RG %g w\n",
551  0.0072 * plotScaleAdjX, 0.0072 * plotScaleAdjY,
553 }
554 
559 {
560  wxASSERT( workFile );
561 
562  // Close the page stream (and compress it)
563  closePdfStream();
564 
565  // Emit the page object and put it in the page list for later
566  pageHandles.push_back( startPdfObject() );
567 
568  /* Page size is in 1/72 of inch (default user space units)
569  Works like the bbox in postscript but there is no need for
570  swapping the sizes, since PDF doesn't require a portrait page.
571  We use the MediaBox but PDF has lots of other less used boxes
572  to use */
573 
574  const double BIGPTsPERMIL = 0.072;
575  wxSize psPaperSize = pageInfo.GetSizeMils();
576 
577  fprintf( outputFile,
578  "<<\n"
579  "/Type /Page\n"
580  "/Parent %d 0 R\n"
581  "/Resources <<\n"
582  " /ProcSet [/PDF /Text /ImageC /ImageB]\n"
583  " /Font %d 0 R >>\n"
584  "/MediaBox [0 0 %d %d]\n"
585  "/Contents %d 0 R\n"
586  ">>\n",
589  int( ceil( psPaperSize.x * BIGPTsPERMIL ) ),
590  int( ceil( psPaperSize.y * BIGPTsPERMIL ) ),
592  closePdfObject();
593 
594  // Mark the page stream as idle
595  pageStreamHandle = 0;
596 }
597 
604 {
605  wxASSERT( outputFile );
606 
607  // First things first: the customary null object
608  xrefTable.clear();
609  xrefTable.push_back( 0 );
610 
611  /* The header (that's easy!). The second line is binary junk required
612  to make the file binary from the beginning (the important thing is
613  that they must have the bit 7 set) */
614  fputs( "%PDF-1.5\n%\200\201\202\203\n", outputFile );
615 
616  /* Allocate an entry for the page tree root, it will go in every page
617  parent entry */
619 
620  /* In the same way, the font resource dictionary is used by every page
621  (it *could* be inherited via the Pages tree */
623 
624  /* Now, the PDF is read from the end, (more or less)... so we start
625  with the page stream for page 1. Other more important stuff is written
626  at the end */
627  StartPage();
628  return true;
629 }
630 
631 
633 {
634  wxASSERT( outputFile );
635 
636  // Close the current page (often the only one)
637  ClosePage();
638 
639  /* We need to declare the resources we're using (fonts in particular)
640  The useful standard one is the Helvetica family. Adding external fonts
641  is *very* involved! */
642  struct {
643  const char *psname;
644  const char *rsname;
645  int font_handle;
646  } fontdefs[4] = {
647  { "/Helvetica", "/KicadFont", 0 },
648  { "/Helvetica-Oblique", "/KicadFontI", 0 },
649  { "/Helvetica-Bold", "/KicadFontB", 0 },
650  { "/Helvetica-BoldOblique", "/KicadFontBI", 0 }
651  };
652 
653  /* Declare the font resources. Since they're builtin fonts, no descriptors (yay!)
654  We'll need metrics anyway to do any aligment (these are in the shared with
655  the postscript engine) */
656  for( int i = 0; i < 4; i++ )
657  {
658  fontdefs[i].font_handle = startPdfObject();
659  fprintf( outputFile,
660  "<< /BaseFont %s\n"
661  " /Type /Font\n"
662  " /Subtype /Type1\n"
663 
664  /* Adobe is so Mac-based that the nearest thing to Latin1 is
665  the Windows ANSI encoding! */
666  " /Encoding /WinAnsiEncoding\n"
667  ">>\n",
668  fontdefs[i].psname );
669  closePdfObject();
670  }
671 
672  // Named font dictionary (was allocated, now we emit it)
674  fputs( "<<\n", outputFile );
675  for( int i = 0; i < 4; i++ )
676  {
677  fprintf( outputFile, " %s %d 0 R\n",
678  fontdefs[i].rsname, fontdefs[i].font_handle );
679  }
680  fputs( ">>\n", outputFile );
681  closePdfObject();
682 
683  /* The page tree: it's a B-tree but luckily we only have few pages!
684  So we use just an array... The handle was allocated at the beginning,
685  now we instantiate the corresponding object */
687  fputs( "<<\n"
688  "/Type /Pages\n"
689  "/Kids [\n", outputFile );
690 
691  for( unsigned i = 0; i < pageHandles.size(); i++ )
692  fprintf( outputFile, "%d 0 R\n", pageHandles[i] );
693 
694  fprintf( outputFile,
695  "]\n"
696  "/Count %ld\n"
697  ">>\n", (long) pageHandles.size() );
698  closePdfObject();
699 
700 
701  // The info dictionary
702  int infoDictHandle = startPdfObject();
703  char date_buf[250];
704  time_t ltime = time( NULL );
705  strftime( date_buf, 250, "D:%Y%m%d%H%M%S",
706  localtime( &ltime ) );
707 
708  if( title.IsEmpty() )
709  {
710  // Windows uses '\' and other platforms ue '/' as sepatator
711  title = filename.AfterLast('\\');
712  title = title.AfterLast('/');
713  }
714 
715  fprintf( outputFile,
716  "<<\n"
717  "/Producer (KiCAD PDF)\n"
718  "/CreationDate (%s)\n"
719  "/Creator (%s)\n"
720  "/Title (%s)\n"
721  "/Trapped false\n",
722  date_buf,
723  TO_UTF8( creator ),
724  TO_UTF8( title ) );
725 
726  fputs( ">>\n", outputFile );
727  closePdfObject();
728 
729  // The catalog, at last
730  int catalogHandle = startPdfObject();
731  fprintf( outputFile,
732  "<<\n"
733  "/Type /Catalog\n"
734  "/Pages %d 0 R\n"
735  "/Version /1.5\n"
736  "/PageMode /UseNone\n"
737  "/PageLayout /SinglePage\n"
738  ">>\n", pageTreeHandle );
739  closePdfObject();
740 
741  /* Emit the xref table (format is crucial to the byte, each entry must
742  be 20 bytes long, and object zero must be done in that way). Also
743  the offset must be kept along for the trailer */
744  long xref_start = ftell( outputFile );
745  fprintf( outputFile,
746  "xref\n"
747  "0 %ld\n"
748  "0000000000 65535 f \n", (long) xrefTable.size() );
749  for( unsigned i = 1; i < xrefTable.size(); i++ )
750  {
751  fprintf( outputFile, "%010ld 00000 n \n", xrefTable[i] );
752  }
753 
754  // Done the xref, go for the trailer
755  fprintf( outputFile,
756  "trailer\n"
757  "<< /Size %lu /Root %d 0 R /Info %d 0 R >>\n"
758  "startxref\n"
759  "%ld\n" // The offset we saved before
760  "%%%%EOF\n",
761  (unsigned long) xrefTable.size(), catalogHandle, infoDictHandle, xref_start );
762 
763  fclose( outputFile );
764  outputFile = NULL;
765 
766  return true;
767 }
768 
769 void PDF_PLOTTER::Text( const wxPoint& aPos,
770  const COLOR4D aColor,
771  const wxString& aText,
772  double aOrient,
773  const wxSize& aSize,
774  enum EDA_TEXT_HJUSTIFY_T aH_justify,
775  enum EDA_TEXT_VJUSTIFY_T aV_justify,
776  int aWidth,
777  bool aItalic,
778  bool aBold,
779  bool aMultilineAllowed,
780  void* aData )
781 {
782  // PDF files do not like 0 sized texts which create broken files.
783  if( aSize.x == 0 || aSize.y == 0 )
784  return;
785 
786  // Fix me: see how to use PDF text mode for multiline texts
787  if( aMultilineAllowed && !aText.Contains( wxT( "\n" ) ) )
788  aMultilineAllowed = false; // the text has only one line.
789 
790  // Emit native PDF text (if requested)
791  // Currently: is not supported, because only our stroke font is alloxed: disable it
792  // However, shadowed texts (searchable texts) works reasonably well because
793  // pixel accurate precision is not requested, so we add searchable texts
794  // behind our stroked font texts
795  bool use_native_font = false;
796  // render_mode 0 shows the text, render_mode 3 is invisible
797  int render_mode = use_native_font ? 0 : 3;
798 
799  const char *fontname = aItalic ? (aBold ? "/KicadFontBI" : "/KicadFontI")
800  : (aBold ? "/KicadFontB" : "/KicadFont");
801 
802  // Compute the copious tranformation parameters of the Curent Transform Matrix
803  double ctm_a, ctm_b, ctm_c, ctm_d, ctm_e, ctm_f;
804  double wideningFactor, heightFactor;
805 
806  computeTextParameters( aPos, aText, aOrient, aSize, m_plotMirror, aH_justify,
807  aV_justify, aWidth, aItalic, aBold,
808  &wideningFactor, &ctm_a, &ctm_b, &ctm_c,
809  &ctm_d, &ctm_e, &ctm_f, &heightFactor );
810 
811  SetColor( aColor );
812  SetCurrentLineWidth( aWidth, aData );
813 
814  /* We use the full CTM instead of the text matrix because the same
815  coordinate system will be used for the overlining. Also the %f
816  for the trig part of the matrix to avoid %g going in exponential
817  format (which is not supported)
818  render_mode 0 shows the text, render_mode 3 is invisible */
819  fprintf( workFile, "q %f %f %f %f %g %g cm BT %s %g Tf %d Tr %g Tz ",
820  ctm_a, ctm_b, ctm_c, ctm_d, ctm_e, ctm_f,
821  fontname, heightFactor, render_mode,
822  wideningFactor * 100 );
823 
824  // The text must be escaped correctly
826  fputs( " Tj ET\n", workFile );
827 
828  // We are in text coordinates, plot the overbars, if we're not doing phantom text
829  if( use_native_font )
830  {
831  std::vector<int> pos_pairs;
832  postscriptOverlinePositions( aText, aSize.x, aItalic, aBold, &pos_pairs );
833  int overbar_y = KiROUND( aSize.y * 1.1 );
834  for( unsigned i = 0; i < pos_pairs.size(); i += 2)
835  {
836  /* This is a nontrivial situation: we are *not* in the user
837  coordinate system, so the userToDeviceCoordinates function
838  can't be used! Strange as it may seem, the userToDeviceSize
839  is the right function to use here... */
840  DPOINT dev_from = userToDeviceSize( wxSize( pos_pairs[i], overbar_y ) );
841  DPOINT dev_to = userToDeviceSize( wxSize( pos_pairs[i + 1], overbar_y ) );
842  fprintf( workFile, "%g %g m %g %g l ",
843  dev_from.x, dev_from.y, dev_to.x, dev_to.y );
844  }
845  }
846 
847  // Stroke and restore the CTM
848  fputs( "S Q\n", workFile );
849 
850  // Plot the stroked text (if requested)
851  if( !use_native_font )
852  {
853  PLOTTER::Text( aPos, aColor, aText, aOrient, aSize, aH_justify, aV_justify,
854  aWidth, aItalic, aBold, aMultilineAllowed );
855  }
856 }
857 
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:106
virtual bool EndPlot() override
virtual void StartPage()
Starts a new page in the PDF document.
virtual void SetDash(int dashed) override
PDF supports dashed lines.
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.
double GetDotMarkLenIU() const
std::vector< int > pageHandles
Font resource dictionary.
bool colorMode
char penState
Current pen state: 'U', 'D' or 'Z' (see PenTo)
double m_IUsPerDecimil
wxPoint plotOffset
Plot offset (in IUs)
wxPoint penLastpos
Last pen positions; set to -1,-1 when the pen is at rest.
static const int delta[8][2]
Definition: solve.cpp:112
PAGE_INFO pageInfo
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:229
wxString workFilename
Handle to the deferred stream length.
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.
bool m_plotMirror
X axis orientation (SVG) and plot mirrored (only for PS, PDF HPGL and SVG)
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
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')
FILE * workFile
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
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.
double cosdecideg(double r, double a)
Circle generation utility: computes r * cos(a) Where a is in decidegrees, not in radians.
Definition: trigo.h:333
double sindecideg(double r, double a)
Circle generation utility: computes r * sin(a) Where a is in decidegrees, not in radians.
Definition: trigo.h:324
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.
int currentPenWidth
#define max(a, b)
Definition: auxiliary.h:86
int defaultPenWidth
true to generate a negative image (PS mode mainly)
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)
FILE * outputFile
true if the Y axis is top to bottom (SVG)
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:70
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.
void computeTextParameters(const wxPoint &aPos, const wxString &aText, int aOrient, const wxSize &aSize, bool aMirror, 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 ...
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)
wxString filename
int allocPdfObject()
Allocate a new handle in the table of the PDF object.
int pageStreamHandle
Handles to the page objects.
wxString creator
wxSize paperSize
Paper size in IU - not in mils.
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...