KiCad PCB EDA Suite
bitmap2cmp_gui.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KICAD, a free EDA CAD application.
3  *
4  * Copyright (C) 1992-2010 jean-pierre.charras
5  * Copyright (C) 1992-2019 Kicad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
25 #include "bitmap2cmp_gui.h"
26 #include "bitmap2component.h"
27 #include <bitmap_io.h>
28 #include <bitmaps.h>
29 #include <kiface_i.h>
30 #include <math/util.h> // for KiROUND
31 #include <kiway.h>
32 #include <pgm_base.h>
33 #include <potracelib.h>
35 #include <wx/clipbrd.h>
36 #include <wx/rawbmp.h>
37 
38 #include "bitmap2cmp_gui_base.h"
39 
40 
41 #define KEYWORD_FRAME_POSX wxT( "Bmconverter_Pos_x" )
42 #define KEYWORD_FRAME_POSY wxT( "Bmconverter_Pos_y" )
43 #define KEYWORD_FRAME_SIZEX wxT( "Bmconverter_Size_x" )
44 #define KEYWORD_FRAME_SIZEY wxT( "Bmconverter_Size_y" )
45 #define KEYWORD_LAST_INPUT_FILE wxT( "Last_input" )
46 #define KEYWORD_LAST_OUTPUT_FILE wxT( "Last_output" )
47 #define KEYWORD_LAST_FORMAT wxT( "Last_format" )
48 #define KEYWORD_LAST_MODLAYER wxT( "Last_modlayer" )
49 #define KEYWORD_BINARY_THRESHOLD wxT( "Threshold" )
50 #define KEYWORD_BW_NEGATIVE wxT( "Negative_choice" )
51 #define KEYWORD_UNIT_SELECTION wxT( "Unit_selection" )
52 
53 #define DEFAULT_DPI 300 // the image DPI used in formats that do not define a DPI
54 
56 {
57  m_outputSize = 0.0;
61 }
62 
63 
65 {
66  // Safety-check to guarantee no divide-by-zero
67  m_originalDPI = std::max( 1, m_originalDPI );
68 
69  // Set the m_outputSize value from the m_originalSizePixels and the selected unit
71  {
73  }
74  else if( m_unit == EDA_UNITS::INCHES )
75  {
77  }
78  else
79  {
81  }
82 
83 }
84 
85 
87 {
88  int outputDPI;
89 
91  {
92  outputDPI = GetOriginalSizePixels() / ( m_outputSize / 25.4 );
93  }
94  else if( m_unit == EDA_UNITS::INCHES )
95  {
96  outputDPI = GetOriginalSizePixels() / m_outputSize;
97  }
98  else
99  {
100  outputDPI = KiROUND( m_outputSize );
101  }
102 
103  // Zero is not a DPI, and may cause divide-by-zero errors...
104  outputDPI = std::max( 1, outputDPI );
105 
106  return outputDPI;
107 }
108 
109 
111 {
112  // Set the unit used for m_outputSize, and convert the old m_outputSize value
113  // to the value in new unit
114  if( aUnit == m_unit )
115  return;
116 
117  // Convert m_outputSize to mm:
118  double size_mm;
119 
121  {
122  size_mm = m_outputSize;
123  }
124  else if( m_unit == EDA_UNITS::INCHES )
125  {
126  size_mm = m_outputSize * 25.4;
127  }
128  else
129  {
130  // m_outputSize is the DPI, not an image size
131  // the image size is m_originalSizePixels / m_outputSize (in inches)
132  if( m_outputSize )
133  size_mm = m_originalSizePixels / m_outputSize * 25.4;
134  else
135  size_mm = 0;
136  }
137 
138  // Convert m_outputSize to new value:
139  if( aUnit == EDA_UNITS::MILLIMETRES )
140  {
141  m_outputSize = size_mm;
142  }
143  else if( aUnit == EDA_UNITS::INCHES )
144  {
145  m_outputSize = size_mm / 25.4;
146  }
147  else
148  {
149  if( size_mm )
150  m_outputSize = m_originalSizePixels / size_mm * 25.4;
151  else
152  m_outputSize = 0;
153  }
154 
155  m_unit = aUnit;
156 }
157 
158 
159 
160 BM2CMP_FRAME::BM2CMP_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
161  BM2CMP_FRAME_BASE( aParent )
162 {
163  SetKiway( this, aKiway );
164  m_config = GetNewConfig( Pgm().App().GetAppName() );
165 
166  wxString unitList[] =
167  {
168  _("mm"), _("Inch"), _("DPI")
169  };
170 
171  for( int ii = 0; ii < 3; ii++ )
172  m_PixelUnit->Append( unitList[ii] );
173 
174  LoadSettings( m_config.get() );
175 
180 
183 
184  //Set icon for aspect ratio
185  m_AspectRatioLocked = true;
186  m_AspectRatio = 1;
188 
189  // Give an icon
190  wxIcon icon;
191  icon.CopyFromBitmap( KiBitmap( icon_bitmap2component_xpm ) );
192  SetIcon( icon );
193 
194  GetSizer()->SetSizeHints( this );
195 
196  SetSize( m_framePos.x, m_framePos.y, m_frameSize.x, m_frameSize.y );
197 
198  m_buttonExportFile->Enable( false );
199  m_buttonExportClipboard->Enable( false );
200 
201 
202  if ( m_framePos == wxDefaultPosition )
203  Centre();
204 }
205 
206 
208 {
209  SaveSettings( m_config.get() );
210  /*
211  * This needed for OSX: avoids further OnDraw processing after this
212  * destructor and before the native window is destroyed
213  */
214  this->Freeze( );
215 }
216 
217 
218 void BM2CMP_FRAME::LoadSettings( wxConfigBase* aCfg )
219 {
220  int tmp;
221  aCfg->Read( KEYWORD_FRAME_POSX, & m_framePos.x, -1 );
222  aCfg->Read( KEYWORD_FRAME_POSY, & m_framePos.y, -1 );
223  aCfg->Read( KEYWORD_FRAME_SIZEX, & m_frameSize.x, -1 );
224  aCfg->Read( KEYWORD_FRAME_SIZEY, & m_frameSize.y, -1 );
227 
228  int u_select = 0;
229  aCfg->Read( KEYWORD_UNIT_SELECTION, &u_select, 0 );
230 
231  if( u_select < 0 || u_select > 2 ) // Validity control
232  u_select = 0;
233 
234  m_PixelUnit->SetSelection( u_select );
235 
236  if( aCfg->Read( KEYWORD_BINARY_THRESHOLD, &tmp ) )
237  m_sliderThreshold->SetValue( tmp );
238 
239  aCfg->Read( KEYWORD_BW_NEGATIVE, &tmp, 0 );
240  m_Negative = tmp != 0;
241  m_checkNegative->SetValue( m_Negative );
242  m_exportToClipboard = false;
243  m_AspectRatioLocked = false;
244 
245  if( aCfg->Read( KEYWORD_LAST_FORMAT, &tmp ) )
246  {
247  if( tmp < 0 || tmp > FINAL_FMT )
248  tmp = PCBNEW_KICAD_MOD;
249 
250  m_rbOutputFormat->SetSelection( tmp );
251  }
252 
253  if( tmp == PCBNEW_KICAD_MOD )
254  m_rbPCBLayer->Enable( true );
255  else
256  m_rbPCBLayer->Enable( false );
257 
258  if( aCfg->Read( KEYWORD_LAST_MODLAYER, &tmp ) )
259  {
260  if( (unsigned) tmp > MOD_LYR_FINAL ) // Out of range
261  m_rbPCBLayer->SetSelection( MOD_LYR_FSILKS );
262  else
263  m_rbPCBLayer->SetSelection( tmp );
264  }
265 }
266 
267 
268 void BM2CMP_FRAME::SaveSettings( wxConfigBase* aCfg )
269 {
270  if( !aCfg )
271  return;
272 
273  m_frameSize = GetSize();
274  m_framePos = GetPosition();
275 
276  if( !IsIconized() )
277  {
278  aCfg->Write( KEYWORD_FRAME_POSX, (long) m_framePos.x );
279  aCfg->Write( KEYWORD_FRAME_POSY, (long) m_framePos.y );
280  aCfg->Write( KEYWORD_FRAME_SIZEX, (long) m_frameSize.x );
281  aCfg->Write( KEYWORD_FRAME_SIZEY, (long) m_frameSize.y );
282  }
283 
286  aCfg->Write( KEYWORD_BINARY_THRESHOLD, m_sliderThreshold->GetValue() );
287  aCfg->Write( KEYWORD_BW_NEGATIVE, m_checkNegative->IsChecked() ? 1 : 0 );
288  aCfg->Write( KEYWORD_LAST_FORMAT, m_rbOutputFormat->GetSelection() );
289  aCfg->Write( KEYWORD_LAST_MODLAYER, m_rbPCBLayer->GetSelection() );
290  aCfg->Write( KEYWORD_UNIT_SELECTION, m_PixelUnit->GetSelection() );
291 }
292 
293 
294 void BM2CMP_FRAME::OnPaintInit( wxPaintEvent& event )
295 {
296 #ifdef __WXMAC__
297  // Otherwise fails due: using wxPaintDC without being in a native paint event
298  wxClientDC pict_dc( m_InitialPicturePanel );
299 #else
300  wxPaintDC pict_dc( m_InitialPicturePanel );
301 #endif
302 
303  m_InitialPicturePanel->PrepareDC( pict_dc );
304 
305  // OSX crashes with empty bitmaps (on initial refreshes)
306  if( m_Pict_Bitmap.IsOk() )
307  pict_dc.DrawBitmap( m_Pict_Bitmap, 0, 0, !!m_Pict_Bitmap.GetMask() );
308 
309  event.Skip();
310 }
311 
312 
313 void BM2CMP_FRAME::OnPaintGreyscale( wxPaintEvent& event )
314 {
315 #ifdef __WXMAC__
316  // Otherwise fails due: using wxPaintDC without being in a native paint event
317  wxClientDC greyscale_dc( m_GreyscalePicturePanel );
318 #else
319  wxPaintDC greyscale_dc( m_GreyscalePicturePanel );
320 #endif
321 
322  m_GreyscalePicturePanel->PrepareDC( greyscale_dc );
323 
324  // OSX crashes with empty bitmaps (on initial refreshes)
325  if( m_Greyscale_Bitmap.IsOk() )
326  greyscale_dc.DrawBitmap( m_Greyscale_Bitmap, 0, 0, !!m_Greyscale_Bitmap.GetMask() );
327 
328  event.Skip();
329 }
330 
331 
332 void BM2CMP_FRAME::OnPaintBW( wxPaintEvent& event )
333 {
334 #ifdef __WXMAC__
335  // Otherwise fails due: using wxPaintDC without being in a native paint event
336  wxClientDC nb_dc( m_BNPicturePanel );
337 #else
338  wxPaintDC nb_dc( m_BNPicturePanel );
339 #endif
340 
341  m_BNPicturePanel->PrepareDC( nb_dc );
342 
343  if( m_BN_Bitmap.IsOk() )
344  nb_dc.DrawBitmap( m_BN_Bitmap, 0, 0, !!m_BN_Bitmap.GetMask() );
345 
346  event.Skip();
347 }
348 
349 
350 void BM2CMP_FRAME::OnLoadFile( wxCommandEvent& event )
351 {
352  wxFileName fn( m_BitmapFileName );
353  wxString path = fn.GetPath();
354 
355  if( path.IsEmpty() || !wxDirExists( path ) )
356  path = m_mruPath;
357 
358  wxFileDialog fileDlg( this, _( "Choose Image" ), path, wxEmptyString,
359  _( "Image Files " ) + wxImage::GetImageExtWildcard(),
360  wxFD_OPEN | wxFD_FILE_MUST_EXIST );
361 
362  int diag = fileDlg.ShowModal();
363 
364  if( diag != wxID_OK )
365  return;
366 
367  wxString fullFilename = fileDlg.GetPath();
368 
369  if( !OpenProjectFiles( std::vector<wxString>( 1, fullFilename ) ) )
370  return;
371 
372  fn = fullFilename;
373  m_mruPath = fn.GetPath();
374  SetStatusText( fullFilename );
375  Refresh();
376 }
377 
378 
379 bool BM2CMP_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, int aCtl )
380 {
381  m_Pict_Image.Destroy();
382  m_BitmapFileName = aFileSet[0];
383 
384  if( !m_Pict_Image.LoadFile( m_BitmapFileName ) )
385  {
386  // LoadFile has its own UI, no need for further failure notification here
387  return false;
388  }
389 
390  m_Pict_Bitmap = wxBitmap( m_Pict_Image );
391 
392  // Determine image resolution in DPI (does not existing in all formats).
393  // the resolution can be given in bit per inches or bit per cm in file
394 
395  int imageDPIx = m_Pict_Image.GetOptionInt( wxIMAGE_OPTION_RESOLUTIONX );
396  int imageDPIy = m_Pict_Image.GetOptionInt( wxIMAGE_OPTION_RESOLUTIONY );
397 
398  if( imageDPIx > 1 && imageDPIy > 1 )
399  {
400  if( m_Pict_Image.GetOptionInt( wxIMAGE_OPTION_RESOLUTIONUNIT ) == wxIMAGE_RESOLUTION_CM )
401  {
402  imageDPIx = KiROUND( imageDPIx * 2.54 );
403  imageDPIy = KiROUND( imageDPIy * 2.54 );
404  }
405  }
406  else // fallback to a default value (DEFAULT_DPI)
407  {
408  imageDPIx = imageDPIy = DEFAULT_DPI;
409  }
410 
411  m_InputXValueDPI->SetLabel( wxString::Format( wxT( "%d" ), imageDPIx ) );
412  m_InputYValueDPI->SetLabel( wxString::Format( wxT( "%d" ), imageDPIy ) );
413 
414  int h = m_Pict_Bitmap.GetHeight();
415  int w = m_Pict_Bitmap.GetWidth();
416  m_AspectRatio = (double) w / h;
417 
418  m_outputSizeX.SetOriginalDPI( imageDPIx );
420  m_outputSizeY.SetOriginalDPI( imageDPIy );
422 
423  // Update display to keep aspect ratio
424  auto fakeEvent = wxCommandEvent();
425  OnSizeChangeX( fakeEvent );
426 
427  updateImageInfo();
428 
429  m_InitialPicturePanel->SetVirtualSize( w, h );
430  m_GreyscalePicturePanel->SetVirtualSize( w, h );
431  m_BNPicturePanel->SetVirtualSize( w, h );
432 
433  m_Greyscale_Image.Destroy();
434  m_Greyscale_Image = m_Pict_Image.ConvertToGreyscale( );
435 
436  if( m_Pict_Bitmap.GetMask() )
437  {
438  for( int x = 0; x < m_Pict_Bitmap.GetWidth(); x++ )
439  {
440  for( int y = 0; y < m_Pict_Bitmap.GetHeight(); y++ )
441  {
442  if( m_Pict_Image.GetRed( x, y ) == m_Pict_Image.GetMaskRed() &&
443  m_Pict_Image.GetGreen( x, y ) == m_Pict_Image.GetMaskGreen() &&
444  m_Pict_Image.GetBlue( x, y ) == m_Pict_Image.GetMaskBlue() )
445  {
446  m_Greyscale_Image.SetRGB( x, y, 255, 255, 255 );
447  }
448  }
449  }
450  }
451 
452  if( m_Negative )
454 
457  Binarize( (double) m_sliderThreshold->GetValue()/m_sliderThreshold->GetMax() );
458 
459  m_buttonExportFile->Enable( true );
460  m_buttonExportClipboard->Enable( true );
461 
466 
467  return true;
468 }
469 
470 
471 // return a string giving the output size, according to the selected unit
472 wxString BM2CMP_FRAME::FormatOutputSize( double aSize )
473 {
474  wxString text;
475 
477  {
478  text.Printf( "%.1f", aSize );
479  }
481  {
482  text.Printf( "%.2f", aSize );
483  }
484  else
485  {
486  text.Printf( "%d", KiROUND( aSize ) );
487  }
488 
489  return text;
490 }
491 
493 {
494  // Note: the image resolution text controls are not modified
495  // here, to avoid a race between text change when entered by user and
496  // a text change if it is modified here.
497 
498  if( m_Pict_Bitmap.IsOk() )
499  {
500  int h = m_Pict_Bitmap.GetHeight();
501  int w = m_Pict_Bitmap.GetWidth();
502  int nb = m_Pict_Bitmap.GetDepth();
503 
504  m_SizeXValue->SetLabel( wxString::Format( wxT( "%d" ), w ) );
505  m_SizeYValue->SetLabel( wxString::Format( wxT( "%d" ), h ) );
506  m_BPPValue->SetLabel( wxString::Format( wxT( "%d" ), nb ) );
507  }
508 }
509 
510 
512 {
513  // return the EDA_UNITS from the m_PixelUnit choice
514  switch( m_PixelUnit->GetSelection() )
515  {
516  case 1:
517  return EDA_UNITS::INCHES;
518 
519  case 2:
520  return EDA_UNITS::UNSCALED;
521 
522  case 0:
523  default:
524  break;
525  }
526 
527  return EDA_UNITS::MILLIMETRES;
528 }
529 
530 
531 void BM2CMP_FRAME::OnSizeChangeX( wxCommandEvent& event )
532 {
533  double new_size;
534 
535  if( m_UnitSizeX->GetValue().ToDouble( &new_size ) )
536  {
537  if( m_AspectRatioLocked )
538  {
539  double calculatedY = new_size / m_AspectRatio;
540 
542  {
543  // for units in DPI, keeping aspect ratio cannot use m_AspectRatioLocked.
544  // just rescale the other dpi
545  double ratio = new_size / m_outputSizeX.GetOutputSize();
546  calculatedY = m_outputSizeY.GetOutputSize() * ratio;
547  }
548 
551  }
552 
554  }
555 
556  updateImageInfo();
557 }
558 
559 
560 void BM2CMP_FRAME::OnSizeChangeY( wxCommandEvent& event )
561 {
562  double new_size;
563 
564  if( m_UnitSizeY->GetValue().ToDouble( &new_size ) )
565  {
566  if( m_AspectRatioLocked )
567  {
568  double calculatedX = new_size * m_AspectRatio;
569 
571  {
572  // for units in DPI, keeping aspect ratio cannot use m_AspectRatioLocked.
573  // just rescale the other dpi
574  double ratio = new_size / m_outputSizeX.GetOutputSize();
575  calculatedX = m_outputSizeX.GetOutputSize() * ratio;
576  }
577 
580  }
581 
583  }
584 
585  updateImageInfo();
586 }
587 
588 
589 void BM2CMP_FRAME::OnSizeUnitChange( wxCommandEvent& event )
590 {
593  updateImageInfo();
594 
597 }
598 
599 
600 void BM2CMP_FRAME::ToggleAspectRatioLock( wxCommandEvent& event )
601 {
603 
604  if( m_AspectRatioLocked )
605  {
607  //Force display update when aspect ratio is locked
608  auto fakeEvent = wxCommandEvent();
609  OnSizeChangeX( fakeEvent );
610  }
611 
612  else
613  {
615  }
616 }
617 
618 
619 void BM2CMP_FRAME::Binarize( double aThreshold )
620 {
621  int h = m_Greyscale_Image.GetHeight();
622  int w = m_Greyscale_Image.GetWidth();
623  unsigned char threshold = aThreshold * 255;
624  unsigned char alpha_thresh = 0.7 * threshold;
625 
626  for( int y = 0; y < h; y++ )
627  for( int x = 0; x < w; x++ )
628  {
629  unsigned char pixout;
630  auto pixin = m_Greyscale_Image.GetGreen( x, y );
631  auto alpha = m_Greyscale_Image.HasAlpha() ?
632  m_Greyscale_Image.GetAlpha( x, y ) : wxALPHA_OPAQUE;
633 
634  if( pixin < threshold && alpha > alpha_thresh )
635  pixout = 0;
636  else
637  pixout = 255;
638 
639  m_NB_Image.SetRGB( x, y, pixout, pixout, pixout );
640 
641  }
642 
643  m_BN_Bitmap = wxBitmap( m_NB_Image );
644 
645 }
646 
647 
649 {
650  unsigned char pix;
651  int h = m_Greyscale_Image.GetHeight();
652  int w = m_Greyscale_Image.GetWidth();
653 
654  for( int y = 0; y < h; y++ )
655  for( int x = 0; x < w; x++ )
656  {
657  pix = m_Greyscale_Image.GetGreen( x, y );
658  pix = ~pix;
659  m_Greyscale_Image.SetRGB( x, y, pix, pix, pix );
660  }
661 }
662 
663 
664 void BM2CMP_FRAME::OnNegativeClicked( wxCommandEvent& )
665 {
666  if( m_checkNegative->GetValue() != m_Negative )
667  {
669 
671  Binarize( (double)m_sliderThreshold->GetValue()/m_sliderThreshold->GetMax() );
672  m_Negative = m_checkNegative->GetValue();
673 
674  Refresh();
675  }
676 }
677 
678 
679 void BM2CMP_FRAME::OnThresholdChange( wxScrollEvent& event )
680 {
681  Binarize( (double)m_sliderThreshold->GetValue()/m_sliderThreshold->GetMax() );
682  Refresh();
683 }
684 
685 
686 void BM2CMP_FRAME::OnExportToFile( wxCommandEvent& event )
687 {
688  m_exportToClipboard = false;
689  // choices of m_rbOutputFormat are expected to be in same order as
690  // OUTPUT_FMT_ID. See bitmap2component.h
691  OUTPUT_FMT_ID format = (OUTPUT_FMT_ID) m_rbOutputFormat->GetSelection();
692  exportBitmap( format );
693 }
694 
695 
696 void BM2CMP_FRAME::OnExportToClipboard( wxCommandEvent& event )
697 {
698  m_exportToClipboard = true;
699  // choices of m_rbOutputFormat are expected to be in same order as
700  // OUTPUT_FMT_ID. See bitmap2component.h
701  OUTPUT_FMT_ID format = (OUTPUT_FMT_ID) m_rbOutputFormat->GetSelection();
702 
703  std::string buffer;
704  ExportToBuffer( buffer, format );
705 
706  // Write buffer to the clipboard
707  if (wxTheClipboard->Open())
708  {
709  // This data objects are held by the clipboard,
710  // so do not delete them in the app.
711  wxTheClipboard->SetData( new wxTextDataObject( buffer.c_str() ) );
712  wxTheClipboard->Close();
713  }
714  else
715  wxMessageBox( _( "Unable to export to the Clipboard") );
716 }
717 
718 
720 {
721  switch( aFormat )
722  {
723  case EESCHEMA_FMT:
725  break;
726 
727  case PCBNEW_KICAD_MOD:
729  break;
730 
731  case POSTSCRIPT_FMT:
733  break;
734 
735  case KICAD_LOGO:
736  OnExportLogo();
737  break;
738  }
739 }
740 
741 
743 {
744  wxFileName fn( m_ConvertedFileName );
745  wxString path = fn.GetPath();
746 
747  if( path.IsEmpty() || !wxDirExists(path) )
748  path = ::wxGetCwd();
749 
750  wxFileDialog fileDlg( this, _( "Create Logo File" ), path, wxEmptyString,
752  wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
753  int diag = fileDlg.ShowModal();
754 
755  if( diag != wxID_OK )
756  return;
757 
758  fn = fileDlg.GetPath();
759  fn.SetExt( PageLayoutDescrFileExtension );
760  m_ConvertedFileName = fn.GetFullPath();
761 
762  FILE* outfile;
763  outfile = wxFopen( m_ConvertedFileName, wxT( "w" ) );
764 
765  if( outfile == NULL )
766  {
767  wxString msg;
768  msg.Printf( _( "File \"%s\" could not be created." ), m_ConvertedFileName );
769  wxMessageBox( msg );
770  return;
771  }
772 
773  std::string buffer;
774  ExportToBuffer( buffer, KICAD_LOGO );
775  fputs( buffer.c_str(), outfile );
776  fclose( outfile );
777 }
778 
779 
781 {
782  wxFileName fn( m_ConvertedFileName );
783  wxString path = fn.GetPath();
784 
785  if( path.IsEmpty() || !wxDirExists( path ) )
786  path = ::wxGetCwd();
787 
788  wxFileDialog fileDlg( this, _( "Create Postscript File" ),
789  path, wxEmptyString,
790  PSFileWildcard(),
791  wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
792 
793  int diag = fileDlg.ShowModal();
794 
795  if( diag != wxID_OK )
796  return;
797 
798  fn = fileDlg.GetPath();
799  fn.SetExt( wxT( "ps" ) );
800  m_ConvertedFileName = fn.GetFullPath();
801 
802  FILE* outfile;
803  outfile = wxFopen( m_ConvertedFileName, wxT( "w" ) );
804 
805  if( outfile == NULL )
806  {
807  wxString msg;
808  msg.Printf( _( "File \"%s\" could not be created." ), m_ConvertedFileName );
809  wxMessageBox( msg );
810  return;
811  }
812 
813  std::string buffer;
814  ExportToBuffer( buffer, POSTSCRIPT_FMT );
815  fputs( buffer.c_str(), outfile );
816  fclose( outfile );
817 }
818 
819 
821 {
822  wxFileName fn( m_ConvertedFileName );
823  wxString path = fn.GetPath();
824 
825  if( path.IsEmpty() || !wxDirExists(path) )
826  path = ::wxGetCwd();
827 
828  wxFileDialog fileDlg( this, _( "Create Symbol Library" ),
829  path, wxEmptyString,
831  wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
832 
833  int diag = fileDlg.ShowModal();
834 
835  if( diag != wxID_OK )
836  return;
837 
838  fn = fileDlg.GetPath();
839  fn.SetExt( SchematicLibraryFileExtension );
840  m_ConvertedFileName = fn.GetFullPath();
841 
842  FILE* outfile = wxFopen( m_ConvertedFileName, wxT( "w" ) );
843 
844  if( outfile == NULL )
845  {
846  wxString msg;
847  msg.Printf( _( "File \"%s\" could not be created." ), m_ConvertedFileName );
848  wxMessageBox( msg );
849  return;
850  }
851 
852  std::string buffer;
853  ExportToBuffer( buffer, EESCHEMA_FMT );
854  fputs( buffer.c_str(), outfile );
855  fclose( outfile );
856 }
857 
858 
860 {
861  wxFileName fn( m_ConvertedFileName );
862  wxString path = fn.GetPath();
863 
864  if( path.IsEmpty() || !wxDirExists( path ) )
865  path = m_mruPath;
866 
867  wxFileDialog fileDlg( this, _( "Create Footprint Library" ),
868  path, wxEmptyString,
870  wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
871 
872  int diag = fileDlg.ShowModal();
873 
874  if( diag != wxID_OK )
875  return;
876 
877  fn = fileDlg.GetPath();
878  fn.SetExt( KiCadFootprintFileExtension );
879  m_ConvertedFileName = fn.GetFullPath();
880 
881  FILE* outfile = wxFopen( m_ConvertedFileName, wxT( "w" ) );
882 
883  if( outfile == NULL )
884  {
885  wxString msg;
886  msg.Printf( _( "File \"%s\" could not be created." ), m_ConvertedFileName );
887  wxMessageBox( msg );
888  return;
889  }
890 
891  std::string buffer;
892  ExportToBuffer( buffer, PCBNEW_KICAD_MOD );
893  fputs( buffer.c_str(), outfile );
894  fclose( outfile );
895  m_mruPath = fn.GetPath();
896 }
897 
898 
899 void BM2CMP_FRAME::ExportToBuffer( std::string& aOutput, OUTPUT_FMT_ID aFormat )
900 {
901  // Create a potrace bitmap
902  int h = m_NB_Image.GetHeight();
903  int w = m_NB_Image.GetWidth();
904  potrace_bitmap_t* potrace_bitmap = bm_new( w, h );
905 
906  if( !potrace_bitmap )
907  {
908  wxString msg;
909  msg.Printf( _( "Error allocating memory for potrace bitmap" ) );
910  wxMessageBox( msg );
911  return;
912  }
913 
914  /* fill the bitmap with data */
915  for( int y = 0; y < h; y++ )
916  {
917  for( int x = 0; x < w; x++ )
918  {
919  auto pix = m_NB_Image.GetGreen( x, y );
920  BM_PUT( potrace_bitmap, x, y, pix ? 0 : 1 );
921  }
922  }
923 
924  // choices of m_rbPCBLayer are expected to be in same order as
925  // BMP2CMP_MOD_LAYER. See bitmap2component.h
927 
928  if( aFormat == PCBNEW_KICAD_MOD )
929  modLayer = (BMP2CMP_MOD_LAYER) m_rbPCBLayer->GetSelection();
930 
931  BITMAPCONV_INFO converter( aOutput );
932  converter.ConvertBitmap( potrace_bitmap, aFormat, m_outputSizeX.GetOutputDPI(),
933  m_outputSizeY.GetOutputDPI(), modLayer );
934 
935  if( !converter.GetErrorMessages().empty() )
936  wxMessageBox( converter.GetErrorMessages().c_str(), _( "Errors" ) );
937 }
938 
939 
940 void BM2CMP_FRAME::OnFormatChange( wxCommandEvent& event )
941 {
942  if( m_rbOutputFormat->GetSelection() == PCBNEW_KICAD_MOD )
943  m_rbPCBLayer->Enable( true );
944  else
945  m_rbPCBLayer->Enable( false );
946 }
EDA_UNITS
Definition: common.h:72
wxBitmap m_Greyscale_Bitmap
wxString PageLayoutDescrFileWildcard()
std::string & GetErrorMessages()
void SetKiway(wxWindow *aDest, KIWAY *aKiway)
Function SetKiway.
EDA_UNITS m_unit
#define KEYWORD_LAST_INPUT_FILE
wxImage m_Greyscale_Image
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:98
wxString m_mruPath
void OnExportToFile(wxCommandEvent &event) override
wxTextCtrl * m_UnitSizeY
void exportPcbnewFormat()
Generate a module in S expr format.
wxBitmap m_BN_Bitmap
std::unique_ptr< wxConfigBase > GetNewConfig(const wxString &aProgName)
Create a new wxConfig so we can put configuration files in a more proper place for each platform.
Definition: common.cpp:231
const std::string KiCadFootprintFileExtension
void OnPaintInit(wxPaintEvent &event) override
#define KEYWORD_FRAME_POSY
void SetOriginalSizePixels(int aPixels)
wxStaticText * m_BPPValue
Class BM2CMP_FRAME_BASE.
void OnExportLogo()
Generate a file suitable to be copied into a page layout description file (.kicad_wks file.
void SetUnit(EDA_UNITS aUnit)
wxString SchematicLibraryFileWildcard()
void OnPaintGreyscale(wxPaintEvent &event) override
wxRadioBox * m_rbPCBLayer
bool m_exportToClipboard
const BITMAP_OPAQUE icon_bitmap2component_xpm[1]
wxButton * m_buttonExportClipboard
bool m_AspectRatioLocked
int GetOriginalSizePixels()
int GetOutputDPI()
IMAGE_SIZE m_outputSizeY
#define KEYWORD_FRAME_SIZEX
wxString m_ConvertedFileName
#define KEYWORD_LAST_MODLAYER
double GetOutputSize()
#define KEYWORD_LAST_FORMAT
void SetOutputSize(double aSize, EDA_UNITS aUnit)
wxStaticText * m_InputXValueDPI
void OnExportToClipboard(wxCommandEvent &event) override
void OnPaintBW(wxPaintEvent &event) override
wxBitmap KiBitmap(BITMAP_DEF aBitmap)
Construct a wxBitmap from a memory record, held in a BITMAP_DEF.
Definition: bitmap.cpp:79
wxTextCtrl * m_UnitSizeX
wxString PSFileWildcard()
#define KEYWORD_FRAME_POSX
void SetOriginalDPI(int aDPI)
wxStaticText * m_SizeXValue
#define NULL
#define KEYWORD_LAST_OUTPUT_FILE
void Refresh()
Update the board display after modifying it by a python script (note: it is automatically called by a...
int m_originalSizePixels
BMP2CMP_MOD_LAYER
void SaveSettings(wxConfigBase *aCfg) override
Saves common frame parameters to a configuration data file.
const std::string SchematicLibraryFileExtension
void OnFormatChange(wxCommandEvent &event) override
void OnThresholdChange(wxScrollEvent &event) override
void OnLoadFile(wxCommandEvent &event) override
Definition of file extensions used in Kicad.
void LoadSettings(wxConfigBase *aCfg) override
Load common frame parameters from a configuration file.
void exportEeschemaFormat()
Generate a schematic library which contains one component: the logo.
KIWAY is a minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the s...
Definition: kiway.h:274
wxSlider * m_sliderThreshold
const BITMAP_OPAQUE unlocked_xpm[1]
Definition: unlocked.cpp:32
wxCheckBox * m_checkNegative
wxString FormatOutputSize(double aSize)
void OnSizeUnitChange(wxCommandEvent &event) override
void OnSizeChangeY(wxCommandEvent &event) override
wxRadioBox * m_rbOutputFormat
EDA_UNITS getUnitFromSelection()
BM2CMP_FRAME(KIWAY *aKiway, wxWindow *aParent)
IMAGE_SIZE m_outputSizeX
wxStaticText * m_InputYValueDPI
const std::string PageLayoutDescrFileExtension
void OnSizeChangeX(wxCommandEvent &event) override
#define KEYWORD_BW_NEGATIVE
wxButton * m_buttonExportFile
void ToggleAspectRatioLock(wxCommandEvent &event) override
wxImage m_Pict_Image
wxPoint m_framePos
void NegateGreyscaleImage()
wxSize m_frameSize
#define KEYWORD_BINARY_THRESHOLD
wxString m_BitmapFileName
void Binarize(double aThreshold)
wxBitmapButton * m_AspectRatioLockButton
void SetOutputSizeFromInitialImageSize()
see class PGM_BASE
void exportBitmap(OUTPUT_FMT_ID aFormat)
bool OpenProjectFiles(const std::vector< wxString > &aFilenames, int aCtl=0) override
Function OpenProjectFiles is abstract, and opens a project or set of files given by aFileList.
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
const BITMAP_OPAQUE locked_xpm[1]
Definition: locked.cpp:42
#define _(s)
Definition: 3d_actions.cpp:31
wxScrolledWindow * m_GreyscalePicturePanel
wxScrolledWindow * m_InitialPicturePanel
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:61
#define KEYWORD_FRAME_SIZEY
std::unique_ptr< wxConfigBase > m_config
double m_AspectRatio
wxBitmap m_Pict_Bitmap
OUTPUT_FMT_ID
wxImage m_NB_Image
#define DEFAULT_DPI
double m_outputSize
void ExportToBuffer(std::string &aOutput, OUTPUT_FMT_ID aFormat)
generate a export data of the current bitmap.
wxStaticText * m_SizeYValue
int ConvertBitmap(potrace_bitmap_t *aPotrace_bitmap, OUTPUT_FMT_ID aFormat, int aDpi_X, int aDpi_Y, BMP2CMP_MOD_LAYER aModLayer)
Run the conversion of the bitmap.
#define KEYWORD_UNIT_SELECTION
wxString KiCadFootprintLibFileWildcard()
void updateImageInfo()
void exportPostScriptFormat()
Generate a postscript file.
void OnNegativeClicked(wxCommandEvent &event) override
wxScrolledWindow * m_BNPicturePanel