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-2021 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 <bitmap2cmp_settings.h>
28 #include <bitmap_io.h>
29 #include <bitmaps.h>
30 #include <kiface_i.h>
31 #include <math/util.h> // for KiROUND
32 #include <kiway.h>
33 #include <pgm_base.h>
34 #include <potracelib.h>
36 #include <wx/clipbrd.h>
37 #include <wx/rawbmp.h>
38 
39 #include "bitmap2cmp_gui_base.h"
40 
41 
42 #define DEFAULT_DPI 300 // the image DPI used in formats that do not define a DPI
43 
45 {
46  m_outputSize = 0.0;
50 }
51 
52 
54 {
55  // Safety-check to guarantee no divide-by-zero
56  m_originalDPI = std::max( 1, m_originalDPI );
57 
58  // Set the m_outputSize value from the m_originalSizePixels and the selected unit
60  {
62  }
63  else if( m_unit == EDA_UNITS::INCHES )
64  {
66  }
67  else
68  {
70  }
71 
72 }
73 
74 
76 {
77  int outputDPI;
78 
80  {
81  outputDPI = GetOriginalSizePixels() / ( m_outputSize / 25.4 );
82  }
83  else if( m_unit == EDA_UNITS::INCHES )
84  {
85  outputDPI = GetOriginalSizePixels() / m_outputSize;
86  }
87  else
88  {
89  outputDPI = KiROUND( m_outputSize );
90  }
91 
92  // Zero is not a DPI, and may cause divide-by-zero errors...
93  outputDPI = std::max( 1, outputDPI );
94 
95  return outputDPI;
96 }
97 
98 
100 {
101  // Set the unit used for m_outputSize, and convert the old m_outputSize value
102  // to the value in new unit
103  if( aUnit == m_unit )
104  return;
105 
106  // Convert m_outputSize to mm:
107  double size_mm;
108 
110  {
111  size_mm = m_outputSize;
112  }
113  else if( m_unit == EDA_UNITS::INCHES )
114  {
115  size_mm = m_outputSize * 25.4;
116  }
117  else
118  {
119  // m_outputSize is the DPI, not an image size
120  // the image size is m_originalSizePixels / m_outputSize (in inches)
121  if( m_outputSize )
122  size_mm = m_originalSizePixels / m_outputSize * 25.4;
123  else
124  size_mm = 0;
125  }
126 
127  // Convert m_outputSize to new value:
128  if( aUnit == EDA_UNITS::MILLIMETRES )
129  {
130  m_outputSize = size_mm;
131  }
132  else if( aUnit == EDA_UNITS::INCHES )
133  {
134  m_outputSize = size_mm / 25.4;
135  }
136  else
137  {
138  if( size_mm )
139  m_outputSize = m_originalSizePixels / size_mm * 25.4;
140  else
141  m_outputSize = 0;
142  }
143 
144  m_unit = aUnit;
145 }
146 
147 
148 
149 BM2CMP_FRAME::BM2CMP_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
150  BM2CMP_FRAME_BASE( aParent )
151 {
152  SetKiway( this, aKiway );
153 
154  for( wxString unit : { _( "mm" ), _( "Inch" ), _( "DPI" ) } )
155  m_PixelUnit->Append( unit );
156 
157  LoadSettings( config() );
158 
163 
166 
167  //Set icon for aspect ratio
168  m_AspectRatioLocked = true;
169  m_AspectRatio = 1;
171 
172  // Give an icon
173  wxIcon icon;
174  wxIconBundle icon_bundle;
175 
176  icon.CopyFromBitmap( KiBitmap( icon_bitmap2component_xpm ) );
177  icon_bundle.AddIcon( icon );
178  icon.CopyFromBitmap( KiBitmap( icon_bitmap2component_32_xpm ) );
179  icon_bundle.AddIcon( icon );
180  icon.CopyFromBitmap( KiBitmap( icon_bitmap2component_16_xpm ) );
181  icon_bundle.AddIcon( icon );
182 
183  SetIcons( icon_bundle );
184 
185  GetSizer()->SetSizeHints( this );
186 
187  m_buttonExportFile->Enable( false );
188  m_buttonExportClipboard->Enable( false );
189 
190  SetSize( m_framePos.x, m_framePos.y, m_frameSize.x, m_frameSize.y );
191 
192  if ( m_framePos == wxDefaultPosition )
193  Centre();
194 }
195 
196 
198 {
199  SaveSettings( config() );
200  /*
201  * This needed for OSX: avoids further OnDraw processing after this
202  * destructor and before the native window is destroyed
203  */
204  Freeze();
205 }
206 
207 
209 {
210  return m_Notebook->GetCurrentPage();
211 }
212 
213 
215 {
217 
218  auto cfg = static_cast<BITMAP2CMP_SETTINGS*>( aCfg );
219 
220  m_BitmapFileName = cfg->m_BitmapFileName;
221  m_ConvertedFileName = cfg->m_ConvertedFileName;
222 
223  int u_select = cfg->m_Units;
224 
225  if( u_select < 0 || u_select > 2 ) // Validity control
226  u_select = 0;
227 
228  m_PixelUnit->SetSelection( u_select );
229 
230  m_sliderThreshold->SetValue( cfg->m_Threshold );
231 
232  m_Negative = cfg->m_Negative;
233  m_checkNegative->SetValue( cfg->m_Negative );
234  m_exportToClipboard = false;
235  m_AspectRatioLocked = false;
236 
237  int format = cfg->m_LastFormat;
238 
239  if( format < 0 || format > FINAL_FMT )
240  format = PCBNEW_KICAD_MOD;
241 
242  m_rbOutputFormat->SetSelection( format );
243 
244  if( format == PCBNEW_KICAD_MOD )
245  m_rbPCBLayer->Enable( true );
246  else
247  m_rbPCBLayer->Enable( false );
248 
249  int last_layer = cfg->m_LastModLayer;
250 
251  if( last_layer > static_cast<int>( MOD_LYR_FINAL ) ) // Out of range
252  m_rbPCBLayer->SetSelection( MOD_LYR_FSILKS );
253  else
254  m_rbPCBLayer->SetSelection( last_layer );
255 }
256 
257 
259 {
261 
262  auto cfg = static_cast<BITMAP2CMP_SETTINGS*>( aCfg );
263 
264  cfg->m_BitmapFileName = m_BitmapFileName;
265  cfg->m_ConvertedFileName = m_ConvertedFileName;
266  cfg->m_Threshold = m_sliderThreshold->GetValue();
267  cfg->m_Negative = m_checkNegative->IsChecked();
268  cfg->m_LastFormat = m_rbOutputFormat->GetSelection();
269  cfg->m_LastModLayer = m_rbPCBLayer->GetSelection();
270  cfg->m_Units = m_PixelUnit->GetSelection();
271 }
272 
273 
274 void BM2CMP_FRAME::OnPaintInit( wxPaintEvent& event )
275 {
276 #ifdef __WXMAC__
277  // Otherwise fails due: using wxPaintDC without being in a native paint event
278  wxClientDC pict_dc( m_InitialPicturePanel );
279 #else
280  wxPaintDC pict_dc( m_InitialPicturePanel );
281 #endif
282 
283  m_InitialPicturePanel->PrepareDC( pict_dc );
284 
285  // OSX crashes with empty bitmaps (on initial refreshes)
286  if( m_Pict_Bitmap.IsOk() )
287  pict_dc.DrawBitmap( m_Pict_Bitmap, 0, 0, !!m_Pict_Bitmap.GetMask() );
288 
289  event.Skip();
290 }
291 
292 
293 void BM2CMP_FRAME::OnPaintGreyscale( wxPaintEvent& event )
294 {
295 #ifdef __WXMAC__
296  // Otherwise fails due: using wxPaintDC without being in a native paint event
297  wxClientDC greyscale_dc( m_GreyscalePicturePanel );
298 #else
299  wxPaintDC greyscale_dc( m_GreyscalePicturePanel );
300 #endif
301 
302  m_GreyscalePicturePanel->PrepareDC( greyscale_dc );
303 
304  // OSX crashes with empty bitmaps (on initial refreshes)
305  if( m_Greyscale_Bitmap.IsOk() )
306  greyscale_dc.DrawBitmap( m_Greyscale_Bitmap, 0, 0, !!m_Greyscale_Bitmap.GetMask() );
307 
308  event.Skip();
309 }
310 
311 
312 void BM2CMP_FRAME::OnPaintBW( wxPaintEvent& event )
313 {
314 #ifdef __WXMAC__
315  // Otherwise fails due: using wxPaintDC without being in a native paint event
316  wxClientDC nb_dc( m_BNPicturePanel );
317 #else
318  wxPaintDC nb_dc( m_BNPicturePanel );
319 #endif
320 
321  m_BNPicturePanel->PrepareDC( nb_dc );
322 
323  if( m_BN_Bitmap.IsOk() )
324  nb_dc.DrawBitmap( m_BN_Bitmap, 0, 0, !!m_BN_Bitmap.GetMask() );
325 
326  event.Skip();
327 }
328 
329 
330 void BM2CMP_FRAME::OnLoadFile( wxCommandEvent& event )
331 {
332  wxFileName fn( m_BitmapFileName );
333  wxString path = fn.GetPath();
334 
335  if( path.IsEmpty() || !wxDirExists( path ) )
336  path = m_mruPath;
337 
338  wxFileDialog fileDlg( this, _( "Choose Image" ), path, wxEmptyString,
339  _( "Image Files" ) + wxS( " " )+ wxImage::GetImageExtWildcard(),
340  wxFD_OPEN | wxFD_FILE_MUST_EXIST );
341 
342  int diag = fileDlg.ShowModal();
343 
344  if( diag != wxID_OK )
345  return;
346 
347  wxString fullFilename = fileDlg.GetPath();
348 
349  if( !OpenProjectFiles( std::vector<wxString>( 1, fullFilename ) ) )
350  return;
351 
352  fn = fullFilename;
353  m_mruPath = fn.GetPath();
354  SetStatusText( fullFilename );
355  Refresh();
356 }
357 
358 
359 bool BM2CMP_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, int aCtl )
360 {
361  m_Pict_Image.Destroy();
362  m_BitmapFileName = aFileSet[0];
363 
364  if( !m_Pict_Image.LoadFile( m_BitmapFileName ) )
365  {
366  // LoadFile has its own UI, no need for further failure notification here
367  return false;
368  }
369 
370  m_Pict_Bitmap = wxBitmap( m_Pict_Image );
371 
372  // Determine image resolution in DPI (does not existing in all formats).
373  // the resolution can be given in bit per inches or bit per cm in file
374 
375  int imageDPIx = m_Pict_Image.GetOptionInt( wxIMAGE_OPTION_RESOLUTIONX );
376  int imageDPIy = m_Pict_Image.GetOptionInt( wxIMAGE_OPTION_RESOLUTIONY );
377 
378  if( imageDPIx > 1 && imageDPIy > 1 )
379  {
380  if( m_Pict_Image.GetOptionInt( wxIMAGE_OPTION_RESOLUTIONUNIT ) == wxIMAGE_RESOLUTION_CM )
381  {
382  imageDPIx = KiROUND( imageDPIx * 2.54 );
383  imageDPIy = KiROUND( imageDPIy * 2.54 );
384  }
385  }
386  else // fallback to a default value (DEFAULT_DPI)
387  {
388  imageDPIx = imageDPIy = DEFAULT_DPI;
389  }
390 
391  m_InputXValueDPI->SetLabel( wxString::Format( wxT( "%d" ), imageDPIx ) );
392  m_InputYValueDPI->SetLabel( wxString::Format( wxT( "%d" ), imageDPIy ) );
393 
394  int h = m_Pict_Bitmap.GetHeight();
395  int w = m_Pict_Bitmap.GetWidth();
396  m_AspectRatio = (double) w / h;
397 
398  m_outputSizeX.SetOriginalDPI( imageDPIx );
400  m_outputSizeY.SetOriginalDPI( imageDPIy );
402 
403  // Update display to keep aspect ratio
404  auto fakeEvent = wxCommandEvent();
405  OnSizeChangeX( fakeEvent );
406 
407  updateImageInfo();
408 
409  m_InitialPicturePanel->SetVirtualSize( w, h );
410  m_GreyscalePicturePanel->SetVirtualSize( w, h );
411  m_BNPicturePanel->SetVirtualSize( w, h );
412 
413  m_Greyscale_Image.Destroy();
414  m_Greyscale_Image = m_Pict_Image.ConvertToGreyscale( );
415 
416  if( m_Pict_Bitmap.GetMask() )
417  {
418  for( int x = 0; x < m_Pict_Bitmap.GetWidth(); x++ )
419  {
420  for( int y = 0; y < m_Pict_Bitmap.GetHeight(); y++ )
421  {
422  if( m_Pict_Image.GetRed( x, y ) == m_Pict_Image.GetMaskRed() &&
423  m_Pict_Image.GetGreen( x, y ) == m_Pict_Image.GetMaskGreen() &&
424  m_Pict_Image.GetBlue( x, y ) == m_Pict_Image.GetMaskBlue() )
425  {
426  m_Greyscale_Image.SetRGB( x, y, 255, 255, 255 );
427  }
428  }
429  }
430  }
431 
432  if( m_Negative )
434 
437  Binarize( (double) m_sliderThreshold->GetValue()/m_sliderThreshold->GetMax() );
438 
439  m_buttonExportFile->Enable( true );
440  m_buttonExportClipboard->Enable( true );
441 
446 
447  return true;
448 }
449 
450 
451 // return a string giving the output size, according to the selected unit
452 wxString BM2CMP_FRAME::FormatOutputSize( double aSize )
453 {
454  wxString text;
455 
457  {
458  text.Printf( "%.1f", aSize );
459  }
461  {
462  text.Printf( "%.2f", aSize );
463  }
464  else
465  {
466  text.Printf( "%d", KiROUND( aSize ) );
467  }
468 
469  return text;
470 }
471 
473 {
474  // Note: the image resolution text controls are not modified
475  // here, to avoid a race between text change when entered by user and
476  // a text change if it is modified here.
477 
478  if( m_Pict_Bitmap.IsOk() )
479  {
480  int h = m_Pict_Bitmap.GetHeight();
481  int w = m_Pict_Bitmap.GetWidth();
482  int nb = m_Pict_Bitmap.GetDepth();
483 
484  m_SizeXValue->SetLabel( wxString::Format( wxT( "%d" ), w ) );
485  m_SizeYValue->SetLabel( wxString::Format( wxT( "%d" ), h ) );
486  m_BPPValue->SetLabel( wxString::Format( wxT( "%d" ), nb ) );
487  }
488 }
489 
490 
492 {
493  // return the EDA_UNITS from the m_PixelUnit choice
494  switch( m_PixelUnit->GetSelection() )
495  {
496  case 1:
497  return EDA_UNITS::INCHES;
498 
499  case 2:
500  return EDA_UNITS::UNSCALED;
501 
502  case 0:
503  default:
504  break;
505  }
506 
507  return EDA_UNITS::MILLIMETRES;
508 }
509 
510 
511 void BM2CMP_FRAME::OnSizeChangeX( wxCommandEvent& event )
512 {
513  double new_size;
514 
515  if( m_UnitSizeX->GetValue().ToDouble( &new_size ) )
516  {
517  if( m_AspectRatioLocked )
518  {
519  double calculatedY = new_size / m_AspectRatio;
520 
522  {
523  // for units in DPI, keeping aspect ratio cannot use m_AspectRatioLocked.
524  // just rescale the other dpi
525  double ratio = new_size / m_outputSizeX.GetOutputSize();
526  calculatedY = m_outputSizeY.GetOutputSize() * ratio;
527  }
528 
531  }
532 
534  }
535 
536  updateImageInfo();
537 }
538 
539 
540 void BM2CMP_FRAME::OnSizeChangeY( wxCommandEvent& event )
541 {
542  double new_size;
543 
544  if( m_UnitSizeY->GetValue().ToDouble( &new_size ) )
545  {
546  if( m_AspectRatioLocked )
547  {
548  double calculatedX = new_size * m_AspectRatio;
549 
551  {
552  // for units in DPI, keeping aspect ratio cannot use m_AspectRatioLocked.
553  // just rescale the other dpi
554  double ratio = new_size / m_outputSizeX.GetOutputSize();
555  calculatedX = m_outputSizeX.GetOutputSize() * ratio;
556  }
557 
560  }
561 
563  }
564 
565  updateImageInfo();
566 }
567 
568 
569 void BM2CMP_FRAME::OnSizeUnitChange( wxCommandEvent& event )
570 {
573  updateImageInfo();
574 
577 }
578 
579 
580 void BM2CMP_FRAME::ToggleAspectRatioLock( wxCommandEvent& event )
581 {
583 
584  if( m_AspectRatioLocked )
585  {
587  //Force display update when aspect ratio is locked
588  auto fakeEvent = wxCommandEvent();
589  OnSizeChangeX( fakeEvent );
590  }
591 
592  else
593  {
595  }
596 }
597 
598 
599 void BM2CMP_FRAME::Binarize( double aThreshold )
600 {
601  int h = m_Greyscale_Image.GetHeight();
602  int w = m_Greyscale_Image.GetWidth();
603  unsigned char threshold = aThreshold * 255;
604  unsigned char alpha_thresh = 0.7 * threshold;
605 
606  for( int y = 0; y < h; y++ )
607  for( int x = 0; x < w; x++ )
608  {
609  unsigned char pixout;
610  auto pixin = m_Greyscale_Image.GetGreen( x, y );
611  auto alpha = m_Greyscale_Image.HasAlpha() ?
612  m_Greyscale_Image.GetAlpha( x, y ) : wxALPHA_OPAQUE;
613 
614  if( pixin < threshold && alpha > alpha_thresh )
615  pixout = 0;
616  else
617  pixout = 255;
618 
619  m_NB_Image.SetRGB( x, y, pixout, pixout, pixout );
620 
621  }
622 
623  m_BN_Bitmap = wxBitmap( m_NB_Image );
624 
625 }
626 
627 
629 {
630  unsigned char pix;
631  int h = m_Greyscale_Image.GetHeight();
632  int w = m_Greyscale_Image.GetWidth();
633 
634  for( int y = 0; y < h; y++ )
635  for( int x = 0; x < w; x++ )
636  {
637  pix = m_Greyscale_Image.GetGreen( x, y );
638  pix = ~pix;
639  m_Greyscale_Image.SetRGB( x, y, pix, pix, pix );
640  }
641 }
642 
643 
644 void BM2CMP_FRAME::OnNegativeClicked( wxCommandEvent& )
645 {
646  if( m_checkNegative->GetValue() != m_Negative )
647  {
649 
651  Binarize( (double)m_sliderThreshold->GetValue()/m_sliderThreshold->GetMax() );
652  m_Negative = m_checkNegative->GetValue();
653 
654  Refresh();
655  }
656 }
657 
658 
659 void BM2CMP_FRAME::OnThresholdChange( wxScrollEvent& event )
660 {
661  Binarize( (double)m_sliderThreshold->GetValue()/m_sliderThreshold->GetMax() );
662  Refresh();
663 }
664 
665 
666 void BM2CMP_FRAME::OnExportToFile( wxCommandEvent& event )
667 {
668  m_exportToClipboard = false;
669  // choices of m_rbOutputFormat are expected to be in same order as
670  // OUTPUT_FMT_ID. See bitmap2component.h
671  OUTPUT_FMT_ID format = (OUTPUT_FMT_ID) m_rbOutputFormat->GetSelection();
672  exportBitmap( format );
673 }
674 
675 
676 void BM2CMP_FRAME::OnExportToClipboard( wxCommandEvent& event )
677 {
678  m_exportToClipboard = true;
679  // choices of m_rbOutputFormat are expected to be in same order as
680  // OUTPUT_FMT_ID. See bitmap2component.h
681  OUTPUT_FMT_ID format = (OUTPUT_FMT_ID) m_rbOutputFormat->GetSelection();
682 
683  std::string buffer;
684  ExportToBuffer( buffer, format );
685 
686  wxLogNull doNotLog; // disable logging of failed clipboard actions
687 
688  // Write buffer to the clipboard
689  if (wxTheClipboard->Open())
690  {
691  // This data objects are held by the clipboard,
692  // so do not delete them in the app.
693  wxTheClipboard->SetData( new wxTextDataObject( buffer.c_str() ) );
694  wxTheClipboard->Close();
695  }
696  else
697  wxMessageBox( _( "Unable to export to the Clipboard") );
698 }
699 
700 
702 {
703  switch( aFormat )
704  {
705  case EESCHEMA_FMT:
707  break;
708 
709  case PCBNEW_KICAD_MOD:
711  break;
712 
713  case POSTSCRIPT_FMT:
715  break;
716 
717  case KICAD_LOGO:
718  OnExportLogo();
719  break;
720  }
721 }
722 
723 
725 {
726  wxFileName fn( m_ConvertedFileName );
727  wxString path = fn.GetPath();
728 
729  if( path.IsEmpty() || !wxDirExists(path) )
730  path = ::wxGetCwd();
731 
732  wxFileDialog fileDlg( this, _( "Create Logo File" ), path, wxEmptyString,
734  wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
735  int diag = fileDlg.ShowModal();
736 
737  if( diag != wxID_OK )
738  return;
739 
740  fn = fileDlg.GetPath();
741  fn.SetExt( PageLayoutDescrFileExtension );
742  m_ConvertedFileName = fn.GetFullPath();
743 
744  FILE* outfile;
745  outfile = wxFopen( m_ConvertedFileName, wxT( "w" ) );
746 
747  if( outfile == NULL )
748  {
749  wxString msg;
750  msg.Printf( _( "File \"%s\" could not be created." ), m_ConvertedFileName );
751  wxMessageBox( msg );
752  return;
753  }
754 
755  std::string buffer;
756  ExportToBuffer( buffer, KICAD_LOGO );
757  fputs( buffer.c_str(), outfile );
758  fclose( outfile );
759 }
760 
761 
763 {
764  wxFileName fn( m_ConvertedFileName );
765  wxString path = fn.GetPath();
766 
767  if( path.IsEmpty() || !wxDirExists( path ) )
768  path = ::wxGetCwd();
769 
770  wxFileDialog fileDlg( this, _( "Create PostScript File" ),
771  path, wxEmptyString,
772  PSFileWildcard(),
773  wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
774 
775  int diag = fileDlg.ShowModal();
776 
777  if( diag != wxID_OK )
778  return;
779 
780  fn = fileDlg.GetPath();
781  fn.SetExt( wxT( "ps" ) );
782  m_ConvertedFileName = fn.GetFullPath();
783 
784  FILE* outfile;
785  outfile = wxFopen( m_ConvertedFileName, wxT( "w" ) );
786 
787  if( outfile == NULL )
788  {
789  wxString msg;
790  msg.Printf( _( "File \"%s\" could not be created." ), m_ConvertedFileName );
791  wxMessageBox( msg );
792  return;
793  }
794 
795  std::string buffer;
796  ExportToBuffer( buffer, POSTSCRIPT_FMT );
797  fputs( buffer.c_str(), outfile );
798  fclose( outfile );
799 }
800 
801 
803 {
804  wxFileName fn( m_ConvertedFileName );
805  wxString path = fn.GetPath();
806 
807  if( path.IsEmpty() || !wxDirExists(path) )
808  path = ::wxGetCwd();
809 
810  wxFileDialog fileDlg( this, _( "Create Symbol Library" ),
811  path, wxEmptyString,
813  wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
814 
815  int diag = fileDlg.ShowModal();
816 
817  if( diag != wxID_OK )
818  return;
819 
820  fn = fileDlg.GetPath();
821  fn.SetExt( LegacySymbolLibFileExtension );
822  m_ConvertedFileName = fn.GetFullPath();
823 
824  FILE* outfile = wxFopen( m_ConvertedFileName, wxT( "w" ) );
825 
826  if( outfile == NULL )
827  {
828  wxString msg;
829  msg.Printf( _( "File \"%s\" could not be created." ), m_ConvertedFileName );
830  wxMessageBox( msg );
831  return;
832  }
833 
834  std::string buffer;
835  ExportToBuffer( buffer, EESCHEMA_FMT );
836  fputs( buffer.c_str(), outfile );
837  fclose( outfile );
838 }
839 
840 
842 {
843  wxFileName fn( m_ConvertedFileName );
844  wxString path = fn.GetPath();
845 
846  if( path.IsEmpty() || !wxDirExists( path ) )
847  path = m_mruPath;
848 
849  wxFileDialog fileDlg( this, _( "Create Footprint Library" ),
850  path, wxEmptyString,
852  wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
853 
854  int diag = fileDlg.ShowModal();
855 
856  if( diag != wxID_OK )
857  return;
858 
859  fn = fileDlg.GetPath();
860  fn.SetExt( KiCadFootprintFileExtension );
861  m_ConvertedFileName = fn.GetFullPath();
862 
863  FILE* outfile = wxFopen( m_ConvertedFileName, wxT( "w" ) );
864 
865  if( outfile == NULL )
866  {
867  wxString msg;
868  msg.Printf( _( "File \"%s\" could not be created." ), m_ConvertedFileName );
869  wxMessageBox( msg );
870  return;
871  }
872 
873  std::string buffer;
874  ExportToBuffer( buffer, PCBNEW_KICAD_MOD );
875  fputs( buffer.c_str(), outfile );
876  fclose( outfile );
877  m_mruPath = fn.GetPath();
878 }
879 
880 
881 void BM2CMP_FRAME::ExportToBuffer( std::string& aOutput, OUTPUT_FMT_ID aFormat )
882 {
883  // Create a potrace bitmap
884  int h = m_NB_Image.GetHeight();
885  int w = m_NB_Image.GetWidth();
886  potrace_bitmap_t* potrace_bitmap = bm_new( w, h );
887 
888  if( !potrace_bitmap )
889  {
890  wxString msg;
891  msg.Printf( _( "Error allocating memory for potrace bitmap" ) );
892  wxMessageBox( msg );
893  return;
894  }
895 
896  /* fill the bitmap with data */
897  for( int y = 0; y < h; y++ )
898  {
899  for( int x = 0; x < w; x++ )
900  {
901  auto pix = m_NB_Image.GetGreen( x, y );
902  BM_PUT( potrace_bitmap, x, y, pix ? 0 : 1 );
903  }
904  }
905 
906  // choices of m_rbPCBLayer are expected to be in same order as
907  // BMP2CMP_MOD_LAYER. See bitmap2component.h
909 
910  if( aFormat == PCBNEW_KICAD_MOD )
911  modLayer = (BMP2CMP_MOD_LAYER) m_rbPCBLayer->GetSelection();
912 
913  BITMAPCONV_INFO converter( aOutput );
914  converter.ConvertBitmap( potrace_bitmap, aFormat, m_outputSizeX.GetOutputDPI(),
915  m_outputSizeY.GetOutputDPI(), modLayer );
916 
917  if( !converter.GetErrorMessages().empty() )
918  wxMessageBox( converter.GetErrorMessages().c_str(), _( "Errors" ) );
919 }
920 
921 
922 void BM2CMP_FRAME::OnFormatChange( wxCommandEvent& event )
923 {
924  if( m_rbOutputFormat->GetSelection() == PCBNEW_KICAD_MOD )
925  m_rbPCBLayer->Enable( true );
926  else
927  m_rbPCBLayer->Enable( false );
928 }
wxBitmap m_Greyscale_Bitmap
wxString PageLayoutDescrFileWildcard()
std::string & GetErrorMessages()
void SetKiway(wxWindow *aDest, KIWAY *aKiway)
It is only used for debugging, since "this" is not a wxWindow*.
EDA_UNITS m_unit
wxImage m_Greyscale_Image
wxString m_mruPath
void OnExportToFile(wxCommandEvent &event) override
wxTextCtrl * m_UnitSizeY
virtual APP_SETTINGS_BASE * config() const
Returns the settings object used in SaveSettings(), and is overloaded in KICAD_MANAGER_FRAME.
void exportPcbnewFormat()
Generate a footprint in S expr format.
wxBitmap m_BN_Bitmap
virtual void SaveSettings(APP_SETTINGS_BASE *aCfg)
Save common frame parameters to a configuration data file.
const std::string KiCadFootprintFileExtension
void OnPaintInit(wxPaintEvent &event) override
const std::string LegacySymbolLibFileExtension
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)
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
wxString m_ConvertedFileName
double GetOutputSize()
void LoadSettings(APP_SETTINGS_BASE *aCfg) override
Load common frame parameters from a configuration file.
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:82
wxTextCtrl * m_UnitSizeX
wxString PSFileWildcard()
const BITMAP_OPAQUE icon_bitmap2component_32_xpm[1]
void SetOriginalDPI(int aDPI)
wxStaticText * m_SizeXValue
APP_SETTINGS_BASE is a settings class that should be derived for each standalone KiCad application.
Definition: app_settings.h:99
#define NULL
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 OnFormatChange(wxCommandEvent &event) override
void OnThresholdChange(wxScrollEvent &event) override
void OnLoadFile(wxCommandEvent &event) override
Definition of file extensions used in Kicad.
void exportEeschemaFormat()
Generate a schematic library which contains one component: the logo.
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
Definition: kiway.h:260
wxSlider * m_sliderThreshold
const BITMAP_OPAQUE unlocked_xpm[1]
Definition: unlocked.cpp:30
wxCheckBox * m_checkNegative
wxString FormatOutputSize(double aSize)
void OnSizeUnitChange(wxCommandEvent &event) override
void OnSizeChangeY(wxCommandEvent &event) override
wxString LegacySymbolLibFileWildcard()
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
wxButton * m_buttonExportFile
void ToggleAspectRatioLock(wxCommandEvent &event) override
wxImage m_Pict_Image
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
EDA_UNITS
Definition: eda_units.h:38
void NegateGreyscaleImage()
void SaveSettings(APP_SETTINGS_BASE *aCfg) override
Save common frame parameters to a configuration data file.
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
Open a project or set of files given by aFileList.
const BITMAP_OPAQUE locked_xpm[1]
Definition: locked.cpp:30
#define _(s)
Definition: 3d_actions.cpp:33
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:68
double m_AspectRatio
wxWindow * GetToolCanvas() const override
Canvas access.
wxBitmap m_Pict_Bitmap
OUTPUT_FMT_ID
wxImage m_NB_Image
const BITMAP_OPAQUE icon_bitmap2component_16_xpm[1]
#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.
wxString KiCadFootprintLibFileWildcard()
void updateImageInfo()
void exportPostScriptFormat()
Generate a postscript file.
virtual void LoadSettings(APP_SETTINGS_BASE *aCfg)
Load common frame parameters from a configuration file.
void OnNegativeClicked(wxCommandEvent &event) override
wxScrolledWindow * m_BNPicturePanel