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