KiCad PCB EDA Suite
PDF_plotter.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 <eda_base_frame.h>
34 #include <base_struct.h>
35 #include <common.h>
36 #include <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 
191  // If diameter is less than width, switch to filled mode
192  if( aFill == NO_FILL && diametre < width )
193  {
194  aFill = FILLED_SHAPE;
195  SetCurrentLineWidth( 0 );
196 
197  radius = userToDeviceSize( ( diametre / 2.0 ) + ( width / 2.0 ) );
198  }
199 
200  double magic = radius * 0.551784; // You don't want to know where this come from
201 
202  // This is the convex hull for the bezier approximated circle
203  fprintf( workFile, "%g %g m "
204  "%g %g %g %g %g %g c "
205  "%g %g %g %g %g %g c "
206  "%g %g %g %g %g %g c "
207  "%g %g %g %g %g %g c %c\n",
208  pos_dev.x - radius, pos_dev.y,
209 
210  pos_dev.x - radius, pos_dev.y + magic,
211  pos_dev.x - magic, pos_dev.y + radius,
212  pos_dev.x, pos_dev.y + radius,
213 
214  pos_dev.x + magic, pos_dev.y + radius,
215  pos_dev.x + radius, pos_dev.y + magic,
216  pos_dev.x + radius, pos_dev.y,
217 
218  pos_dev.x + radius, pos_dev.y - magic,
219  pos_dev.x + magic, pos_dev.y - radius,
220  pos_dev.x, pos_dev.y - radius,
221 
222  pos_dev.x - magic, pos_dev.y - radius,
223  pos_dev.x - radius, pos_dev.y - magic,
224  pos_dev.x - radius, pos_dev.y,
225 
226  aFill == NO_FILL ? 's' : 'b' );
227 }
228 
229 
234 void PDF_PLOTTER::Arc( const wxPoint& centre, double StAngle, double EndAngle, int radius,
235  FILL_T fill, int width )
236 {
237  wxASSERT( workFile );
238  if( radius <= 0 )
239  {
240  Circle( centre, width, FILLED_SHAPE, 0 );
241  return;
242  }
243 
244  /* Arcs are not so easily approximated by beziers (in the general case),
245  so we approximate them in the old way */
246  wxPoint start, end;
247  const int delta = 50; // increment (in 0.1 degrees) to draw circles
248 
249  if( StAngle > EndAngle )
250  std::swap( StAngle, EndAngle );
251 
252  SetCurrentLineWidth( width );
253 
254  // Usual trig arc plotting routine...
255  start.x = centre.x + KiROUND( cosdecideg( radius, -StAngle ) );
256  start.y = centre.y + KiROUND( sindecideg( radius, -StAngle ) );
257  DPOINT pos_dev = userToDeviceCoordinates( start );
258  fprintf( workFile, "%g %g m ", pos_dev.x, pos_dev.y );
259  for( int ii = StAngle + delta; ii < EndAngle; ii += delta )
260  {
261  end.x = centre.x + KiROUND( cosdecideg( radius, -ii ) );
262  end.y = centre.y + KiROUND( sindecideg( radius, -ii ) );
263  pos_dev = userToDeviceCoordinates( end );
264  fprintf( workFile, "%g %g l ", pos_dev.x, pos_dev.y );
265  }
266 
267  end.x = centre.x + KiROUND( cosdecideg( radius, -EndAngle ) );
268  end.y = centre.y + KiROUND( sindecideg( radius, -EndAngle ) );
269  pos_dev = userToDeviceCoordinates( end );
270  fprintf( workFile, "%g %g l ", pos_dev.x, pos_dev.y );
271 
272  // The arc is drawn... if not filled we stroke it, otherwise we finish
273  // closing the pie at the center
274  if( fill == NO_FILL )
275  {
276  fputs( "S\n", workFile );
277  }
278  else
279  {
280  pos_dev = userToDeviceCoordinates( centre );
281  fprintf( workFile, "%g %g l b\n", pos_dev.x, pos_dev.y );
282  }
283 }
284 
285 
289 void PDF_PLOTTER::PlotPoly( const std::vector< wxPoint >& aCornerList,
290  FILL_T aFill, int aWidth, void * aData )
291 {
292  wxASSERT( workFile );
293  if( aCornerList.size() <= 1 )
294  return;
295 
296  SetCurrentLineWidth( aWidth );
297 
298  DPOINT pos = userToDeviceCoordinates( aCornerList[0] );
299  fprintf( workFile, "%g %g m\n", pos.x, pos.y );
300 
301  for( unsigned ii = 1; ii < aCornerList.size(); ii++ )
302  {
303  pos = userToDeviceCoordinates( aCornerList[ii] );
304  fprintf( workFile, "%g %g l\n", pos.x, pos.y );
305  }
306 
307  // Close path and stroke(/fill)
308  fprintf( workFile, "%c\n", aFill == NO_FILL ? 'S' : 'b' );
309 }
310 
311 
312 void PDF_PLOTTER::PenTo( const wxPoint& pos, char plume )
313 {
314  wxASSERT( workFile );
315  if( plume == 'Z' )
316  {
317  if( penState != 'Z' )
318  {
319  fputs( "S\n", workFile );
320  penState = 'Z';
321  penLastpos.x = -1;
322  penLastpos.y = -1;
323  }
324  return;
325  }
326 
327  if( penState != plume || pos != penLastpos )
328  {
329  DPOINT pos_dev = userToDeviceCoordinates( pos );
330  fprintf( workFile, "%g %g %c\n",
331  pos_dev.x, pos_dev.y,
332  ( plume=='D' ) ? 'l' : 'm' );
333  }
334  penState = plume;
335  penLastpos = pos;
336 }
337 
341 void PDF_PLOTTER::PlotImage( const wxImage & aImage, const wxPoint& aPos,
342  double aScaleFactor )
343 {
344  wxASSERT( workFile );
345  wxSize pix_size( aImage.GetWidth(), aImage.GetHeight() );
346 
347  // Requested size (in IUs)
348  DPOINT drawsize( aScaleFactor * pix_size.x,
349  aScaleFactor * pix_size.y );
350 
351  // calculate the bitmap start position
352  wxPoint start( aPos.x - drawsize.x / 2,
353  aPos.y + drawsize.y / 2);
354 
355  DPOINT dev_start = userToDeviceCoordinates( start );
356 
357  /* PDF has an uhm... simplified coordinate system handling. There is
358  *one* operator to do everything (the PS concat equivalent). At least
359  they kept the matrix stack to save restore environments. Also images
360  are always emitted at the origin with a size of 1x1 user units.
361  What we need to do is:
362  1) save the CTM end estabilish the new one
363  2) plot the image
364  3) restore the CTM
365  4) profit
366  */
367  fprintf( workFile, "q %g 0 0 %g %g %g cm\n", // Step 1
368  userToDeviceSize( drawsize.x ),
369  userToDeviceSize( drawsize.y ),
370  dev_start.x, dev_start.y );
371 
372  /* An inline image is a cross between a dictionary and a stream.
373  A real ugly construct (compared with the elegance of the PDF
374  format). Also it accepts some 'abbreviations', which is stupid
375  since the content stream is usually compressed anyway... */
376  fprintf( workFile,
377  "BI\n"
378  " /BPC 8\n"
379  " /CS %s\n"
380  " /W %d\n"
381  " /H %d\n"
382  "ID\n", colorMode ? "/RGB" : "/G", pix_size.x, pix_size.y );
383 
384  /* Here comes the stream (in binary!). I *could* have hex or ascii84
385  encoded it, but who cares? I'll go through zlib anyway */
386  for( int y = 0; y < pix_size.y; y++ )
387  {
388  for( int x = 0; x < pix_size.x; x++ )
389  {
390  unsigned char r = aImage.GetRed( x, y ) & 0xFF;
391  unsigned char g = aImage.GetGreen( x, y ) & 0xFF;
392  unsigned char b = aImage.GetBlue( x, y ) & 0xFF;
393  // As usual these days, stdio buffering has to suffeeeeerrrr
394  if( colorMode )
395  {
396  putc( r, workFile );
397  putc( g, workFile );
398  putc( b, workFile );
399  }
400  else
401  {
402  // Grayscale conversion
403  putc( (r + g + b) / 3, workFile );
404  }
405  }
406  }
407 
408  fputs( "EI Q\n", workFile ); // Finish step 2 and do step 3
409 }
410 
411 
418 {
419  xrefTable.push_back( 0 );
420  return xrefTable.size() - 1;
421 }
422 
423 
429 {
430  wxASSERT( outputFile );
431  wxASSERT( !workFile );
432 
433  if( handle < 0)
434  handle = allocPdfObject();
435 
436  xrefTable[handle] = ftell( outputFile );
437  fprintf( outputFile, "%d 0 obj\n", handle );
438  return handle;
439 }
440 
441 
446 {
447  wxASSERT( outputFile );
448  wxASSERT( !workFile );
449  fputs( "endobj\n", outputFile );
450 }
451 
452 
460 {
461  wxASSERT( outputFile );
462  wxASSERT( !workFile );
463  handle = startPdfObject( handle );
464 
465  // This is guaranteed to be handle+1 but needs to be allocated since
466  // you could allocate more object during stream preparation
468  fprintf( outputFile,
469  "<< /Length %d 0 R /Filter /FlateDecode >>\n" // Length is deferred
470  "stream\n", handle + 1 );
471 
472  // Open a temporary file to accumulate the stream
473  workFilename = filename + wxT(".tmp");
474  workFile = wxFopen( workFilename, wxT( "w+b" ));
475  wxASSERT( workFile );
476  return handle;
477 }
478 
479 
484 {
485  wxASSERT( workFile );
486 
487  long stream_len = ftell( workFile );
488 
489  if( stream_len < 0 )
490  {
491  wxASSERT( false );
492  return;
493  }
494 
495  // Rewind the file, read in the page stream and DEFLATE it
496  fseek( workFile, 0, SEEK_SET );
497  unsigned char *inbuf = new unsigned char[stream_len];
498 
499  int rc = fread( inbuf, 1, stream_len, workFile );
500  wxASSERT( rc == stream_len );
501  (void) rc;
502 
503  // We are done with the temporary file, junk it
504  fclose( workFile );
505  workFile = 0;
506  ::wxRemoveFile( workFilename );
507 
508  // NULL means memos owns the memory, but provide a hint on optimum size needed.
509  wxMemoryOutputStream memos( NULL, std::max( 2000l, stream_len ) ) ;
510 
511  {
512  /* Somewhat standard parameters to compress in DEFLATE. The PDF spec is
513  * misleading, it says it wants a DEFLATE stream but it really want a ZLIB
514  * stream! (a DEFLATE stream would be generated with -15 instead of 15)
515  * rc = deflateInit2( &zstrm, Z_BEST_COMPRESSION, Z_DEFLATED, 15,
516  * 8, Z_DEFAULT_STRATEGY );
517  */
518 
519  wxZlibOutputStream zos( memos, wxZ_BEST_COMPRESSION, wxZLIB_ZLIB );
520 
521  zos.Write( inbuf, stream_len );
522 
523  delete[] inbuf;
524 
525  } // flush the zip stream using zos destructor
526 
527  wxStreamBuffer* sb = memos.GetOutputStreamBuffer();
528 
529  unsigned out_count = sb->Tell();
530 
531  fwrite( sb->GetBufferStart(), 1, out_count, outputFile );
532 
533  fputs( "endstream\n", outputFile );
534  closePdfObject();
535 
536  // Writing the deferred length as an indirect object
538  fprintf( outputFile, "%u\n", out_count );
539  closePdfObject();
540 }
541 
546 {
547  wxASSERT( outputFile );
548  wxASSERT( !workFile );
549 
550  // Compute the paper size in IUs
552  paperSize.x *= 10.0 / iuPerDeviceUnit;
553  paperSize.y *= 10.0 / iuPerDeviceUnit;
554 
555  // Open the content stream; the page object will go later
557 
558  /* Now, until ClosePage *everything* must be wrote in workFile, to be
559  compressed later in closePdfStream */
560 
561  // Default graphic settings (coordinate system, default color and line style)
562  fprintf( workFile,
563  "%g 0 0 %g 0 0 cm 1 J 1 j 0 0 0 rg 0 0 0 RG %g w\n",
564  0.0072 * plotScaleAdjX, 0.0072 * plotScaleAdjY,
566 }
567 
572 {
573  wxASSERT( workFile );
574 
575  // Close the page stream (and compress it)
576  closePdfStream();
577 
578  // Emit the page object and put it in the page list for later
579  pageHandles.push_back( startPdfObject() );
580 
581  /* Page size is in 1/72 of inch (default user space units)
582  Works like the bbox in postscript but there is no need for
583  swapping the sizes, since PDF doesn't require a portrait page.
584  We use the MediaBox but PDF has lots of other less used boxes
585  to use */
586 
587  const double BIGPTsPERMIL = 0.072;
588  wxSize psPaperSize = pageInfo.GetSizeMils();
589 
590  fprintf( outputFile,
591  "<<\n"
592  "/Type /Page\n"
593  "/Parent %d 0 R\n"
594  "/Resources <<\n"
595  " /ProcSet [/PDF /Text /ImageC /ImageB]\n"
596  " /Font %d 0 R >>\n"
597  "/MediaBox [0 0 %d %d]\n"
598  "/Contents %d 0 R\n"
599  ">>\n",
602  int( ceil( psPaperSize.x * BIGPTsPERMIL ) ),
603  int( ceil( psPaperSize.y * BIGPTsPERMIL ) ),
605  closePdfObject();
606 
607  // Mark the page stream as idle
608  pageStreamHandle = 0;
609 }
610 
617 {
618  wxASSERT( outputFile );
619 
620  // First things first: the customary null object
621  xrefTable.clear();
622  xrefTable.push_back( 0 );
623 
624  /* The header (that's easy!). The second line is binary junk required
625  to make the file binary from the beginning (the important thing is
626  that they must have the bit 7 set) */
627  fputs( "%PDF-1.5\n%\200\201\202\203\n", outputFile );
628 
629  /* Allocate an entry for the page tree root, it will go in every page
630  parent entry */
632 
633  /* In the same way, the font resource dictionary is used by every page
634  (it *could* be inherited via the Pages tree */
636 
637  /* Now, the PDF is read from the end, (more or less)... so we start
638  with the page stream for page 1. Other more important stuff is written
639  at the end */
640  StartPage();
641  return true;
642 }
643 
644 
646 {
647  wxASSERT( outputFile );
648 
649  // Close the current page (often the only one)
650  ClosePage();
651 
652  /* We need to declare the resources we're using (fonts in particular)
653  The useful standard one is the Helvetica family. Adding external fonts
654  is *very* involved! */
655  struct {
656  const char *psname;
657  const char *rsname;
658  int font_handle;
659  } fontdefs[4] = {
660  { "/Helvetica", "/KicadFont", 0 },
661  { "/Helvetica-Oblique", "/KicadFontI", 0 },
662  { "/Helvetica-Bold", "/KicadFontB", 0 },
663  { "/Helvetica-BoldOblique", "/KicadFontBI", 0 }
664  };
665 
666  /* Declare the font resources. Since they're builtin fonts, no descriptors (yay!)
667  We'll need metrics anyway to do any aligment (these are in the shared with
668  the postscript engine) */
669  for( int i = 0; i < 4; i++ )
670  {
671  fontdefs[i].font_handle = startPdfObject();
672  fprintf( outputFile,
673  "<< /BaseFont %s\n"
674  " /Type /Font\n"
675  " /Subtype /Type1\n"
676 
677  /* Adobe is so Mac-based that the nearest thing to Latin1 is
678  the Windows ANSI encoding! */
679  " /Encoding /WinAnsiEncoding\n"
680  ">>\n",
681  fontdefs[i].psname );
682  closePdfObject();
683  }
684 
685  // Named font dictionary (was allocated, now we emit it)
687  fputs( "<<\n", outputFile );
688  for( int i = 0; i < 4; i++ )
689  {
690  fprintf( outputFile, " %s %d 0 R\n",
691  fontdefs[i].rsname, fontdefs[i].font_handle );
692  }
693  fputs( ">>\n", outputFile );
694  closePdfObject();
695 
696  /* The page tree: it's a B-tree but luckily we only have few pages!
697  So we use just an array... The handle was allocated at the beginning,
698  now we instantiate the corresponding object */
700  fputs( "<<\n"
701  "/Type /Pages\n"
702  "/Kids [\n", outputFile );
703 
704  for( unsigned i = 0; i < pageHandles.size(); i++ )
705  fprintf( outputFile, "%d 0 R\n", pageHandles[i] );
706 
707  fprintf( outputFile,
708  "]\n"
709  "/Count %ld\n"
710  ">>\n", (long) pageHandles.size() );
711  closePdfObject();
712 
713 
714  // The info dictionary
715  int infoDictHandle = startPdfObject();
716  char date_buf[250];
717  time_t ltime = time( NULL );
718  strftime( date_buf, 250, "D:%Y%m%d%H%M%S",
719  localtime( &ltime ) );
720 
721  if( title.IsEmpty() )
722  {
723  // Windows uses '\' and other platforms ue '/' as sepatator
724  title = filename.AfterLast('\\');
725  title = title.AfterLast('/');
726  }
727 
728  fprintf( outputFile,
729  "<<\n"
730  "/Producer (KiCAD PDF)\n"
731  "/CreationDate (%s)\n"
732  "/Creator (%s)\n"
733  "/Title (%s)\n"
734  "/Trapped false\n",
735  date_buf,
736  TO_UTF8( creator ),
737  TO_UTF8( title ) );
738 
739  fputs( ">>\n", outputFile );
740  closePdfObject();
741 
742  // The catalog, at last
743  int catalogHandle = startPdfObject();
744  fprintf( outputFile,
745  "<<\n"
746  "/Type /Catalog\n"
747  "/Pages %d 0 R\n"
748  "/Version /1.5\n"
749  "/PageMode /UseNone\n"
750  "/PageLayout /SinglePage\n"
751  ">>\n", pageTreeHandle );
752  closePdfObject();
753 
754  /* Emit the xref table (format is crucial to the byte, each entry must
755  be 20 bytes long, and object zero must be done in that way). Also
756  the offset must be kept along for the trailer */
757  long xref_start = ftell( outputFile );
758  fprintf( outputFile,
759  "xref\n"
760  "0 %ld\n"
761  "0000000000 65535 f \n", (long) xrefTable.size() );
762  for( unsigned i = 1; i < xrefTable.size(); i++ )
763  {
764  fprintf( outputFile, "%010ld 00000 n \n", xrefTable[i] );
765  }
766 
767  // Done the xref, go for the trailer
768  fprintf( outputFile,
769  "trailer\n"
770  "<< /Size %lu /Root %d 0 R /Info %d 0 R >>\n"
771  "startxref\n"
772  "%ld\n" // The offset we saved before
773  "%%%%EOF\n",
774  (unsigned long) xrefTable.size(), catalogHandle, infoDictHandle, xref_start );
775 
776  fclose( outputFile );
777  outputFile = NULL;
778 
779  return true;
780 }
781 
782 void PDF_PLOTTER::Text( const wxPoint& aPos,
783  const COLOR4D aColor,
784  const wxString& aText,
785  double aOrient,
786  const wxSize& aSize,
787  enum EDA_TEXT_HJUSTIFY_T aH_justify,
788  enum EDA_TEXT_VJUSTIFY_T aV_justify,
789  int aWidth,
790  bool aItalic,
791  bool aBold,
792  bool aMultilineAllowed,
793  void* aData )
794 {
795  // PDF files do not like 0 sized texts which create broken files.
796  if( aSize.x == 0 || aSize.y == 0 )
797  return;
798 
799  // Fix me: see how to use PDF text mode for multiline texts
800  if( aMultilineAllowed && !aText.Contains( wxT( "\n" ) ) )
801  aMultilineAllowed = false; // the text has only one line.
802 
803  // Emit native PDF text (if requested)
804  // Currently: is not supported, because only our stroke font is alloxed: disable it
805  // However, shadowed texts (searchable texts) works reasonably well because
806  // pixel accurate precision is not requested, so we add searchable texts
807  // behind our stroked font texts
808  bool use_native_font = false;
809  // render_mode 0 shows the text, render_mode 3 is invisible
810  int render_mode = use_native_font ? 0 : 3;
811 
812  const char *fontname = aItalic ? (aBold ? "/KicadFontBI" : "/KicadFontI")
813  : (aBold ? "/KicadFontB" : "/KicadFont");
814 
815  // Compute the copious tranformation parameters of the Curent Transform Matrix
816  double ctm_a, ctm_b, ctm_c, ctm_d, ctm_e, ctm_f;
817  double wideningFactor, heightFactor;
818 
819  computeTextParameters( aPos, aText, aOrient, aSize, m_plotMirror, aH_justify,
820  aV_justify, aWidth, aItalic, aBold,
821  &wideningFactor, &ctm_a, &ctm_b, &ctm_c,
822  &ctm_d, &ctm_e, &ctm_f, &heightFactor );
823 
824  SetColor( aColor );
825  SetCurrentLineWidth( aWidth, aData );
826 
827  /* We use the full CTM instead of the text matrix because the same
828  coordinate system will be used for the overlining. Also the %f
829  for the trig part of the matrix to avoid %g going in exponential
830  format (which is not supported)
831  render_mode 0 shows the text, render_mode 3 is invisible */
832  fprintf( workFile, "q %f %f %f %f %g %g cm BT %s %g Tf %d Tr %g Tz ",
833  ctm_a, ctm_b, ctm_c, ctm_d, ctm_e, ctm_f,
834  fontname, heightFactor, render_mode,
835  wideningFactor * 100 );
836 
837  // The text must be escaped correctly
839  fputs( " Tj ET\n", workFile );
840 
841  // We are in text coordinates, plot the overbars, if we're not doing phantom text
842  if( use_native_font )
843  {
844  std::vector<int> pos_pairs;
845  postscriptOverlinePositions( aText, aSize.x, aItalic, aBold, &pos_pairs );
846  int overbar_y = KiROUND( aSize.y * 1.1 );
847  for( unsigned i = 0; i < pos_pairs.size(); i += 2)
848  {
849  /* This is a nontrivial situation: we are *not* in the user
850  coordinate system, so the userToDeviceCoordinates function
851  can't be used! Strange as it may seem, the userToDeviceSize
852  is the right function to use here... */
853  DPOINT dev_from = userToDeviceSize( wxSize( pos_pairs[i], overbar_y ) );
854  DPOINT dev_to = userToDeviceSize( wxSize( pos_pairs[i + 1], overbar_y ) );
855  fprintf( workFile, "%g %g m %g %g l ",
856  dev_from.x, dev_from.y, dev_to.x, dev_to.y );
857  }
858  }
859 
860  // Stroke and restore the CTM
861  fputs( "S Q\n", workFile );
862 
863  // Plot the stroked text (if requested)
864  if( !use_native_font )
865  {
866  PLOTTER::Text( aPos, aColor, aText, aOrient, aSize, aH_justify, aV_justify,
867  aWidth, aItalic, aBold, aMultilineAllowed );
868  }
869 }
870 
void closePdfStream()
Finish the current PDF stream (writes the deferred length, too)
EDA_TEXT_HJUSTIFY_T
Definition: eda_text.h:62
static int KiROUND(double v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: common.h:120
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.
int pageTreeHandle
Definition: plotter.h:891
virtual void PenTo(const wxPoint &pos, char plume) override
moveto/lineto primitive, moves the &#39;pen&#39; 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
Definition: plotter.cpp:136
std::vector< int > pageHandles
Font resource dictionary.
Definition: plotter.h:893
bool colorMode
Definition: plotter.h:557
char penState
Current pen state: &#39;U&#39;, &#39;D&#39; or &#39;Z&#39; (see PenTo)
Definition: plotter.h:562
double m_IUsPerDecimil
Definition: plotter.h:539
wxPoint plotOffset
Plot offset (in IUs)
Definition: plotter.h:545
wxPoint penLastpos
Last pen positions; set to -1,-1 when the pen is at rest.
Definition: plotter.h:564
static const int delta[8][2]
Definition: solve.cpp:112
PAGE_INFO pageInfo
Definition: plotter.h:568
This file contains miscellaneous commonly used macros and functions.
const wxSize & GetSizeMils() const
Definition: page_info.h:142
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.
wxString workFilename
Handle to the deferred stream length.
Definition: plotter.h:896
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: plotter.h:895
bool m_plotMirror
X axis orientation (SVG) and plot mirrored (only for PS, PDF HPGL and SVG)
Definition: plotter.h:549
virtual void SetDefaultLineWidth(int width) override
Set the default line width.
Definition: PS_plotter.cpp:52
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&#39;t directly plot arcs, it uses the base emulation.
double plotScaleAdjY
Definition: plotter.h:747
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...
Definition: page_info.h:54
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.
Definition: PDF_plotter.cpp:69
virtual void SetColor(COLOR4D color) override
The SetColor implementation is split with the subclasses: The PSLIKE computes the rgb values...
Definition: PS_plotter.cpp:59
Base window classes and related definitions.
double plotScale
Plot scale - chosen by the user (even implicitly with &#39;fit in a4&#39;)
Definition: plotter.h:533
FILE * workFile
Definition: plotter.h:897
virtual DPOINT userToDeviceSize(const wxSize &size)
Modifies size according to the plotter scale factors (wxSize version, returns a DPOINT) ...
Definition: plotter.cpp:121
void closePdfObject()
Close the current PDF object.
EDA_TEXT_VJUSTIFY_T
Definition: eda_text.h:69
wxString title
Definition: plotter.h:567
virtual DPOINT userToDeviceCoordinates(const wxPoint &aCoordinate)
Modifies coordinates according to the orientation, scale factor, and offsets trace.
Definition: plotter.cpp:96
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: plotter.h:892
double cosdecideg(double r, double a)
Circle generation utility: computes r * cos(a) Where a is in decidegrees, not in radians.
Definition: trigo.h:354
double sindecideg(double r, double a)
Circle generation utility: computes r * sin(a) Where a is in decidegrees, not in radians.
Definition: trigo.h:345
void fputsPostscriptString(FILE *fout, const wxString &txt)
Write on a stream a string escaped for postscript/PDF.
Definition: PS_plotter.cpp:305
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: plotter.h:898
int currentPenWidth
Definition: plotter.h:560
#define max(a, b)
Definition: auxiliary.h:86
int defaultPenWidth
true to generate a negative image (PS mode mainly)
Definition: plotter.h:559
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: plotter.h:747
size_t i
Definition: json11.cpp:597
FILE * outputFile
true if the Y axis is top to bottom (SVG)
Definition: plotter.h:554
double GetDashGapLenIU() const
Definition: plotter.cpp:148
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:54
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.
Definition: PS_plotter.cpp:373
virtual bool OpenFile(const wxString &aFullFilename) override
Open or create the plot file aFullFilename.
Definition: PDF_plotter.cpp:49
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 ...
Definition: PS_plotter.cpp:426
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...
Definition: PDF_plotter.cpp:64
double GetDashMarkLenIU() const
Definition: plotter.cpp:142
virtual bool StartPlot() override
The PDF engine supports multiple pages; the first one is opened &#39;for free&#39; the following are to be cl...
double iuPerDeviceUnit
Device scale (from IUs to plotter device units - usually decimils)
Definition: plotter.h:542
wxString filename
Definition: plotter.h:566
int allocPdfObject()
Allocate a new handle in the table of the PDF object.
int pageStreamHandle
Handles to the page objects.
Definition: plotter.h:894
wxString creator
Definition: plotter.h:565
wxSize paperSize
Paper size in IU - not in mils.
Definition: plotter.h:570
virtual void SetCurrentLineWidth(int width, void *aData=NULL) override
Pen width setting for PDF.
Definition: PDF_plotter.cpp:95
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...