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-2020 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  icon.CopyFromBitmap( KiBitmap( icon_bitmap2component_xpm ) );
175  SetIcon( icon );
176 
177  GetSizer()->SetSizeHints( this );
178 
179  m_buttonExportFile->Enable( false );
180  m_buttonExportClipboard->Enable( false );
181 
182  SetSize( m_FramePos.x, m_FramePos.y, m_FrameSize.x, m_FrameSize.y );
183 
184  if ( m_FramePos == wxDefaultPosition )
185  Centre();
186 }
187 
188 
190 {
191  SaveSettings( config() );
192  /*
193  * This needed for OSX: avoids further OnDraw processing after this
194  * destructor and before the native window is destroyed
195  */
196  this->Freeze( );
197 }
198 
199 
201 {
202  return m_Notebook->GetCurrentPage();
203 }
204 
205 
207 {
209 
210  auto cfg = static_cast<BITMAP2CMP_SETTINGS*>( aCfg );
211 
212  m_BitmapFileName = cfg->m_BitmapFileName;
213  m_ConvertedFileName = cfg->m_ConvertedFileName;
214 
215  int u_select = cfg->m_Units;
216 
217  if( u_select < 0 || u_select > 2 ) // Validity control
218  u_select = 0;
219 
220  m_PixelUnit->SetSelection( u_select );
221 
222  m_sliderThreshold->SetValue( cfg->m_Threshold );
223 
224  m_Negative = cfg->m_Negative;
225  m_checkNegative->SetValue( cfg->m_Negative );
226  m_exportToClipboard = false;
227  m_AspectRatioLocked = false;
228 
229  int format = cfg->m_LastFormat;
230 
231  if( format < 0 || format > FINAL_FMT )
232  format = PCBNEW_KICAD_MOD;
233 
234  m_rbOutputFormat->SetSelection( format );
235 
236  if( format == PCBNEW_KICAD_MOD )
237  m_rbPCBLayer->Enable( true );
238  else
239  m_rbPCBLayer->Enable( false );
240 
241  int last_layer = cfg->m_LastModLayer;
242 
243  if( last_layer > static_cast<int>( MOD_LYR_FINAL ) ) // Out of range
244  m_rbPCBLayer->SetSelection( MOD_LYR_FSILKS );
245  else
246  m_rbPCBLayer->SetSelection( last_layer );
247 }
248 
249 
251 {
253 
254  auto cfg = static_cast<BITMAP2CMP_SETTINGS*>( aCfg );
255 
256  cfg->m_BitmapFileName = m_BitmapFileName;
257  cfg->m_ConvertedFileName = m_ConvertedFileName;
258  cfg->m_Threshold = m_sliderThreshold->GetValue();
259  cfg->m_Negative = m_checkNegative->IsChecked();
260  cfg->m_LastFormat = m_rbOutputFormat->GetSelection();
261  cfg->m_LastModLayer = m_rbPCBLayer->GetSelection();
262  cfg->m_Units = m_PixelUnit->GetSelection();
263 }
264 
265 
266 void BM2CMP_FRAME::OnPaintInit( wxPaintEvent& event )
267 {
268 #ifdef __WXMAC__
269  // Otherwise fails due: using wxPaintDC without being in a native paint event
270  wxClientDC pict_dc( m_InitialPicturePanel );
271 #else
272  wxPaintDC pict_dc( m_InitialPicturePanel );
273 #endif
274 
275  m_InitialPicturePanel->PrepareDC( pict_dc );
276 
277  // OSX crashes with empty bitmaps (on initial refreshes)
278  if( m_Pict_Bitmap.IsOk() )
279  pict_dc.DrawBitmap( m_Pict_Bitmap, 0, 0, !!m_Pict_Bitmap.GetMask() );
280 
281  event.Skip();
282 }
283 
284 
285 void BM2CMP_FRAME::OnPaintGreyscale( wxPaintEvent& event )
286 {
287 #ifdef __WXMAC__
288  // Otherwise fails due: using wxPaintDC without being in a native paint event
289  wxClientDC greyscale_dc( m_GreyscalePicturePanel );
290 #else
291  wxPaintDC greyscale_dc( m_GreyscalePicturePanel );
292 #endif
293 
294  m_GreyscalePicturePanel->PrepareDC( greyscale_dc );
295 
296  // OSX crashes with empty bitmaps (on initial refreshes)
297  if( m_Greyscale_Bitmap.IsOk() )
298  greyscale_dc.DrawBitmap( m_Greyscale_Bitmap, 0, 0, !!m_Greyscale_Bitmap.GetMask() );
299 
300  event.Skip();
301 }
302 
303 
304 void BM2CMP_FRAME::OnPaintBW( wxPaintEvent& event )
305 {
306 #ifdef __WXMAC__
307  // Otherwise fails due: using wxPaintDC without being in a native paint event
308  wxClientDC nb_dc( m_BNPicturePanel );
309 #else
310  wxPaintDC nb_dc( m_BNPicturePanel );
311 #endif
312 
313  m_BNPicturePanel->PrepareDC( nb_dc );
314 
315  if( m_BN_Bitmap.IsOk() )
316  nb_dc.DrawBitmap( m_BN_Bitmap, 0, 0, !!m_BN_Bitmap.GetMask() );
317 
318  event.Skip();
319 }
320 
321 
322 void BM2CMP_FRAME::OnLoadFile( wxCommandEvent& event )
323 {
324  wxFileName fn( m_BitmapFileName );
325  wxString path = fn.GetPath();
326 
327  if( path.IsEmpty() || !wxDirExists( path ) )
328  path = m_mruPath;
329 
330  wxFileDialog fileDlg( this, _( "Choose Image" ), path, wxEmptyString,
331  _( "Image Files " ) + wxImage::GetImageExtWildcard(),
332  wxFD_OPEN | wxFD_FILE_MUST_EXIST );
333 
334  int diag = fileDlg.ShowModal();
335 
336  if( diag != wxID_OK )
337  return;
338 
339  wxString fullFilename = fileDlg.GetPath();
340 
341  if( !OpenProjectFiles( std::vector<wxString>( 1, fullFilename ) ) )
342  return;
343 
344  fn = fullFilename;
345  m_mruPath = fn.GetPath();
346  SetStatusText( fullFilename );
347  Refresh();
348 }
349 
350 
351 bool BM2CMP_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, int aCtl )
352 {
353  m_Pict_Image.Destroy();
354  m_BitmapFileName = aFileSet[0];
355 
356  if( !m_Pict_Image.LoadFile( m_BitmapFileName ) )
357  {
358  // LoadFile has its own UI, no need for further failure notification here
359  return false;
360  }
361 
362  m_Pict_Bitmap = wxBitmap( m_Pict_Image );
363 
364  // Determine image resolution in DPI (does not existing in all formats).
365  // the resolution can be given in bit per inches or bit per cm in file
366 
367  int imageDPIx = m_Pict_Image.GetOptionInt( wxIMAGE_OPTION_RESOLUTIONX );
368  int imageDPIy = m_Pict_Image.GetOptionInt( wxIMAGE_OPTION_RESOLUTIONY );
369 
370  if( imageDPIx > 1 && imageDPIy > 1 )
371  {
372  if( m_Pict_Image.GetOptionInt( wxIMAGE_OPTION_RESOLUTIONUNIT ) == wxIMAGE_RESOLUTION_CM )
373  {
374  imageDPIx = KiROUND( imageDPIx * 2.54 );
375  imageDPIy = KiROUND( imageDPIy * 2.54 );
376  }
377  }
378  else // fallback to a default value (DEFAULT_DPI)
379  {
380  imageDPIx = imageDPIy = DEFAULT_DPI;
381  }
382 
383  m_InputXValueDPI->SetLabel( wxString::Format( wxT( "%d" ), imageDPIx ) );
384  m_InputYValueDPI->SetLabel( wxString::Format( wxT( "%d" ), imageDPIy ) );
385 
386  int h = m_Pict_Bitmap.GetHeight();
387  int w = m_Pict_Bitmap.GetWidth();
388  m_AspectRatio = (double) w / h;
389 
390  m_outputSizeX.SetOriginalDPI( imageDPIx );
392  m_outputSizeY.SetOriginalDPI( imageDPIy );
394 
395  // Update display to keep aspect ratio
396  auto fakeEvent = wxCommandEvent();
397  OnSizeChangeX( fakeEvent );
398 
399  updateImageInfo();
400 
401  m_InitialPicturePanel->SetVirtualSize( w, h );
402  m_GreyscalePicturePanel->SetVirtualSize( w, h );
403  m_BNPicturePanel->SetVirtualSize( w, h );
404 
405  m_Greyscale_Image.Destroy();
406  m_Greyscale_Image = m_Pict_Image.ConvertToGreyscale( );
407 
408  if( m_Pict_Bitmap.GetMask() )
409  {
410  for( int x = 0; x < m_Pict_Bitmap.GetWidth(); x++ )
411  {
412  for( int y = 0; y < m_Pict_Bitmap.GetHeight(); y++ )
413  {
414  if( m_Pict_Image.GetRed( x, y ) == m_Pict_Image.GetMaskRed() &&
415  m_Pict_Image.GetGreen( x, y ) == m_Pict_Image.GetMaskGreen() &&
416  m_Pict_Image.GetBlue( x, y ) == m_Pict_Image.GetMaskBlue() )
417  {
418  m_Greyscale_Image.SetRGB( x, y, 255, 255, 255 );
419  }
420  }
421  }
422  }
423 
424  if( m_Negative )
426 
429  Binarize( (double) m_sliderThreshold->GetValue()/m_sliderThreshold->GetMax() );
430 
431  m_buttonExportFile->Enable( true );
432  m_buttonExportClipboard->Enable( true );
433 
438 
439  return true;
440 }
441 
442 
443 // return a string giving the output size, according to the selected unit
444 wxString BM2CMP_FRAME::FormatOutputSize( double aSize )
445 {
446  wxString text;
447 
449  {
450  text.Printf( "%.1f", aSize );
451  }
453  {
454  text.Printf( "%.2f", aSize );
455  }
456  else
457  {
458  text.Printf( "%d", KiROUND( aSize ) );
459  }
460 
461  return text;
462 }
463 
465 {
466  // Note: the image resolution text controls are not modified
467  // here, to avoid a race between text change when entered by user and
468  // a text change if it is modified here.
469 
470  if( m_Pict_Bitmap.IsOk() )
471  {
472  int h = m_Pict_Bitmap.GetHeight();
473  int w = m_Pict_Bitmap.GetWidth();
474  int nb = m_Pict_Bitmap.GetDepth();
475 
476  m_SizeXValue->SetLabel( wxString::Format( wxT( "%d" ), w ) );
477  m_SizeYValue->SetLabel( wxString::Format( wxT( "%d" ), h ) );
478  m_BPPValue->SetLabel( wxString::Format( wxT( "%d" ), nb ) );
479  }
480 }
481 
482 
484 {
485  // return the EDA_UNITS from the m_PixelUnit choice
486  switch( m_PixelUnit->GetSelection() )
487  {
488  case 1:
489  return EDA_UNITS::INCHES;
490 
491  case 2:
492  return EDA_UNITS::UNSCALED;
493 
494  case 0:
495  default:
496  break;
497  }
498 
499  return EDA_UNITS::MILLIMETRES;
500 }
501 
502 
503 void BM2CMP_FRAME::OnSizeChangeX( wxCommandEvent& event )
504 {
505  double new_size;
506 
507  if( m_UnitSizeX->GetValue().ToDouble( &new_size ) )
508  {
509  if( m_AspectRatioLocked )
510  {
511  double calculatedY = new_size / m_AspectRatio;
512 
514  {
515  // for units in DPI, keeping aspect ratio cannot use m_AspectRatioLocked.
516  // just rescale the other dpi
517  double ratio = new_size / m_outputSizeX.GetOutputSize();
518  calculatedY = m_outputSizeY.GetOutputSize() * ratio;
519  }
520 
523  }
524 
526  }
527 
528  updateImageInfo();
529 }
530 
531 
532 void BM2CMP_FRAME::OnSizeChangeY( wxCommandEvent& event )
533 {
534  double new_size;
535 
536  if( m_UnitSizeY->GetValue().ToDouble( &new_size ) )
537  {
538  if( m_AspectRatioLocked )
539  {
540  double calculatedX = new_size * m_AspectRatio;
541 
543  {
544  // for units in DPI, keeping aspect ratio cannot use m_AspectRatioLocked.
545  // just rescale the other dpi
546  double ratio = new_size / m_outputSizeX.GetOutputSize();
547  calculatedX = m_outputSizeX.GetOutputSize() * ratio;
548  }
549 
552  }
553 
555  }
556 
557  updateImageInfo();
558 }
559 
560 
561 void BM2CMP_FRAME::OnSizeUnitChange( wxCommandEvent& event )
562 {
565  updateImageInfo();
566 
569 }
570 
571 
572 void BM2CMP_FRAME::ToggleAspectRatioLock( wxCommandEvent& event )
573 {
575 
576  if( m_AspectRatioLocked )
577  {
579  //Force display update when aspect ratio is locked
580  auto fakeEvent = wxCommandEvent();
581  OnSizeChangeX( fakeEvent );
582  }
583 
584  else
585  {
587  }
588 }
589 
590 
591 void BM2CMP_FRAME::Binarize( double aThreshold )
592 {
593  int h = m_Greyscale_Image.GetHeight();
594  int w = m_Greyscale_Image.GetWidth();
595  unsigned char threshold = aThreshold * 255;
596  unsigned char alpha_thresh = 0.7 * threshold;
597 
598  for( int y = 0; y < h; y++ )
599  for( int x = 0; x < w; x++ )
600  {
601  unsigned char pixout;
602  auto pixin = m_Greyscale_Image.GetGreen( x, y );
603  auto alpha = m_Greyscale_Image.HasAlpha() ?
604  m_Greyscale_Image.GetAlpha( x, y ) : wxALPHA_OPAQUE;
605 
606  if( pixin < threshold && alpha > alpha_thresh )
607  pixout = 0;
608  else
609  pixout = 255;
610 
611  m_NB_Image.SetRGB( x, y, pixout, pixout, pixout );
612 
613  }
614 
615  m_BN_Bitmap = wxBitmap( m_NB_Image );
616 
617 }
618 
619 
621 {
622  unsigned char pix;
623  int h = m_Greyscale_Image.GetHeight();
624  int w = m_Greyscale_Image.GetWidth();
625 
626  for( int y = 0; y < h; y++ )
627  for( int x = 0; x < w; x++ )
628  {
629  pix = m_Greyscale_Image.GetGreen( x, y );
630  pix = ~pix;
631  m_Greyscale_Image.SetRGB( x, y, pix, pix, pix );
632  }
633 }
634 
635 
636 void BM2CMP_FRAME::OnNegativeClicked( wxCommandEvent& )
637 {
638  if( m_checkNegative->GetValue() != m_Negative )
639  {
641 
643  Binarize( (double)m_sliderThreshold->GetValue()/m_sliderThreshold->GetMax() );
644  m_Negative = m_checkNegative->GetValue();
645 
646  Refresh();
647  }
648 }
649 
650 
651 void BM2CMP_FRAME::OnThresholdChange( wxScrollEvent& event )
652 {
653  Binarize( (double)m_sliderThreshold->GetValue()/m_sliderThreshold->GetMax() );
654  Refresh();
655 }
656 
657 
658 void BM2CMP_FRAME::OnExportToFile( wxCommandEvent& event )
659 {
660  m_exportToClipboard = false;
661  // choices of m_rbOutputFormat are expected to be in same order as
662  // OUTPUT_FMT_ID. See bitmap2component.h
663  OUTPUT_FMT_ID format = (OUTPUT_FMT_ID) m_rbOutputFormat->GetSelection();
664  exportBitmap( format );
665 }
666 
667 
668 void BM2CMP_FRAME::OnExportToClipboard( wxCommandEvent& event )
669 {
670  m_exportToClipboard = true;
671  // choices of m_rbOutputFormat are expected to be in same order as
672  // OUTPUT_FMT_ID. See bitmap2component.h
673  OUTPUT_FMT_ID format = (OUTPUT_FMT_ID) m_rbOutputFormat->GetSelection();
674 
675  std::string buffer;
676  ExportToBuffer( buffer, format );
677 
678  // Write buffer to the clipboard
679  if (wxTheClipboard->Open())
680  {
681  // This data objects are held by the clipboard,
682  // so do not delete them in the app.
683  wxTheClipboard->SetData( new wxTextDataObject( buffer.c_str() ) );
684  wxTheClipboard->Close();
685  }
686  else
687  wxMessageBox( _( "Unable to export to the Clipboard") );
688 }
689 
690 
692 {
693  switch( aFormat )
694  {
695  case EESCHEMA_FMT:
697  break;
698 
699  case PCBNEW_KICAD_MOD:
701  break;
702 
703  case POSTSCRIPT_FMT:
705  break;
706 
707  case KICAD_LOGO:
708  OnExportLogo();
709  break;
710  }
711 }
712 
713 
715 {
716  wxFileName fn( m_ConvertedFileName );
717  wxString path = fn.GetPath();
718 
719  if( path.IsEmpty() || !wxDirExists(path) )
720  path = ::wxGetCwd();
721 
722  wxFileDialog fileDlg( this, _( "Create Logo File" ), path, wxEmptyString,
724  wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
725  int diag = fileDlg.ShowModal();
726 
727  if( diag != wxID_OK )
728  return;
729 
730  fn = fileDlg.GetPath();
731  fn.SetExt( PageLayoutDescrFileExtension );
732  m_ConvertedFileName = fn.GetFullPath();
733 
734  FILE* outfile;
735  outfile = wxFopen( m_ConvertedFileName, wxT( "w" ) );
736 
737  if( outfile == NULL )
738  {
739  wxString msg;
740  msg.Printf( _( "File \"%s\" could not be created." ), m_ConvertedFileName );
741  wxMessageBox( msg );
742  return;
743  }
744 
745  std::string buffer;
746  ExportToBuffer( buffer, KICAD_LOGO );
747  fputs( buffer.c_str(), outfile );
748  fclose( outfile );
749 }
750 
751 
753 {
754  wxFileName fn( m_ConvertedFileName );
755  wxString path = fn.GetPath();
756 
757  if( path.IsEmpty() || !wxDirExists( path ) )
758  path = ::wxGetCwd();
759 
760  wxFileDialog fileDlg( this, _( "Create Postscript File" ),
761  path, wxEmptyString,
762  PSFileWildcard(),
763  wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
764 
765  int diag = fileDlg.ShowModal();
766 
767  if( diag != wxID_OK )
768  return;
769 
770  fn = fileDlg.GetPath();
771  fn.SetExt( wxT( "ps" ) );
772  m_ConvertedFileName = fn.GetFullPath();
773 
774  FILE* outfile;
775  outfile = wxFopen( m_ConvertedFileName, wxT( "w" ) );
776 
777  if( outfile == NULL )
778  {
779  wxString msg;
780  msg.Printf( _( "File \"%s\" could not be created." ), m_ConvertedFileName );
781  wxMessageBox( msg );
782  return;
783  }
784 
785  std::string buffer;
786  ExportToBuffer( buffer, POSTSCRIPT_FMT );
787  fputs( buffer.c_str(), outfile );
788  fclose( outfile );
789 }
790 
791 
793 {
794  wxFileName fn( m_ConvertedFileName );
795  wxString path = fn.GetPath();
796 
797  if( path.IsEmpty() || !wxDirExists(path) )
798  path = ::wxGetCwd();
799 
800  wxFileDialog fileDlg( this, _( "Create Symbol Library" ),
801  path, wxEmptyString,
803  wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
804 
805  int diag = fileDlg.ShowModal();
806 
807  if( diag != wxID_OK )
808  return;
809 
810  fn = fileDlg.GetPath();
811  fn.SetExt( LegacySymbolLibFileExtension );
812  m_ConvertedFileName = fn.GetFullPath();
813 
814  FILE* outfile = wxFopen( m_ConvertedFileName, wxT( "w" ) );
815 
816  if( outfile == NULL )
817  {
818  wxString msg;
819  msg.Printf( _( "File \"%s\" could not be created." ), m_ConvertedFileName );
820  wxMessageBox( msg );
821  return;
822  }
823 
824  std::string buffer;
825  ExportToBuffer( buffer, EESCHEMA_FMT );
826  fputs( buffer.c_str(), outfile );
827  fclose( outfile );
828 }
829 
830 
832 {
833  wxFileName fn( m_ConvertedFileName );
834  wxString path = fn.GetPath();
835 
836  if( path.IsEmpty() || !wxDirExists( path ) )
837  path = m_mruPath;
838 
839  wxFileDialog fileDlg( this, _( "Create Footprint Library" ),
840  path, wxEmptyString,
842  wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
843 
844  int diag = fileDlg.ShowModal();
845 
846  if( diag != wxID_OK )
847  return;
848 
849  fn = fileDlg.GetPath();
850  fn.SetExt( KiCadFootprintFileExtension );
851  m_ConvertedFileName = fn.GetFullPath();
852 
853  FILE* outfile = wxFopen( m_ConvertedFileName, wxT( "w" ) );
854 
855  if( outfile == NULL )
856  {
857  wxString msg;
858  msg.Printf( _( "File \"%s\" could not be created." ), m_ConvertedFileName );
859  wxMessageBox( msg );
860  return;
861  }
862 
863  std::string buffer;
864  ExportToBuffer( buffer, PCBNEW_KICAD_MOD );
865  fputs( buffer.c_str(), outfile );
866  fclose( outfile );
867  m_mruPath = fn.GetPath();
868 }
869 
870 
871 void BM2CMP_FRAME::ExportToBuffer( std::string& aOutput, OUTPUT_FMT_ID aFormat )
872 {
873  // Create a potrace bitmap
874  int h = m_NB_Image.GetHeight();
875  int w = m_NB_Image.GetWidth();
876  potrace_bitmap_t* potrace_bitmap = bm_new( w, h );
877 
878  if( !potrace_bitmap )
879  {
880  wxString msg;
881  msg.Printf( _( "Error allocating memory for potrace bitmap" ) );
882  wxMessageBox( msg );
883  return;
884  }
885 
886  /* fill the bitmap with data */
887  for( int y = 0; y < h; y++ )
888  {
889  for( int x = 0; x < w; x++ )
890  {
891  auto pix = m_NB_Image.GetGreen( x, y );
892  BM_PUT( potrace_bitmap, x, y, pix ? 0 : 1 );
893  }
894  }
895 
896  // choices of m_rbPCBLayer are expected to be in same order as
897  // BMP2CMP_MOD_LAYER. See bitmap2component.h
899 
900  if( aFormat == PCBNEW_KICAD_MOD )
901  modLayer = (BMP2CMP_MOD_LAYER) m_rbPCBLayer->GetSelection();
902 
903  BITMAPCONV_INFO converter( aOutput );
904  converter.ConvertBitmap( potrace_bitmap, aFormat, m_outputSizeX.GetOutputDPI(),
905  m_outputSizeY.GetOutputDPI(), modLayer );
906 
907  if( !converter.GetErrorMessages().empty() )
908  wxMessageBox( converter.GetErrorMessages().c_str(), _( "Errors" ) );
909 }
910 
911 
912 void BM2CMP_FRAME::OnFormatChange( wxCommandEvent& event )
913 {
914  if( m_rbOutputFormat->GetSelection() == PCBNEW_KICAD_MOD )
915  m_rbPCBLayer->Enable( true );
916  else
917  m_rbPCBLayer->Enable( false );
918 }
EDA_UNITS
Definition: common.h:198
wxBitmap m_Greyscale_Bitmap
wxString PageLayoutDescrFileWildcard()
std::string & GetErrorMessages()
void SetKiway(wxWindow *aDest, KIWAY *aKiway)
Function SetKiway.
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 module in S expr format.
wxBitmap m_BN_Bitmap
virtual void SaveSettings(APP_SETTINGS_BASE *aCfg)
Saves 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:80
wxTextCtrl * m_UnitSizeX
wxString PSFileWildcard()
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:92
#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.
KIWAY is a minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the s...
Definition: kiway.h:273
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
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 NegateGreyscaleImage()
void SaveSettings(APP_SETTINGS_BASE *aCfg) override
Saves 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
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: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
#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