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 <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 rescale 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 rescale 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  // choices of m_rbOutputFormat are expected to be in same order as
675  // OUTPUT_FMT_ID. See bitmap2component.h
676  OUTPUT_FMT_ID format = (OUTPUT_FMT_ID) m_rbOutputFormat->GetSelection();
677  exportBitmap( format );
678 }
679 
680 
681 void BM2CMP_FRAME::OnExportToClipboard( wxCommandEvent& event )
682 {
683  m_exportToClipboard = true;
684  // choices of m_rbOutputFormat are expected to be in same order as
685  // OUTPUT_FMT_ID. See bitmap2component.h
686  OUTPUT_FMT_ID format = (OUTPUT_FMT_ID) m_rbOutputFormat->GetSelection();
687 
688  std::string buffer;
689  ExportToBuffer( buffer, format );
690 
691  wxLogNull doNotLog; // disable logging of failed clipboard actions
692 
693  // Write buffer to the clipboard
694  if (wxTheClipboard->Open())
695  {
696  // This data objects are held by the clipboard,
697  // so do not delete them in the app.
698  wxTheClipboard->SetData( new wxTextDataObject( buffer.c_str() ) );
699  wxTheClipboard->Flush(); // Allow data to be available after closing KiCad
700  wxTheClipboard->Close();
701  }
702  else
703  wxMessageBox( _( "Unable to export to the Clipboard") );
704 }
705 
706 
708 {
709  switch( aFormat )
710  {
711  case EESCHEMA_FMT:
713  break;
714 
715  case PCBNEW_KICAD_MOD:
717  break;
718 
719  case POSTSCRIPT_FMT:
721  break;
722 
723  case KICAD_LOGO:
724  OnExportLogo();
725  break;
726  }
727 }
728 
729 
731 {
732  wxFileName fn( m_ConvertedFileName );
733  wxString path = fn.GetPath();
734 
735  if( path.IsEmpty() || !wxDirExists(path) )
736  path = ::wxGetCwd();
737 
738  wxFileDialog fileDlg( this, _( "Create Logo File" ), path, wxEmptyString,
739  DrawingSheetFileWildcard(), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
740  int diag = fileDlg.ShowModal();
741 
742  if( diag != wxID_OK )
743  return;
744 
745  fn = fileDlg.GetPath();
746  fn.SetExt( DrawingSheetFileExtension );
747  m_ConvertedFileName = fn.GetFullPath();
748 
749  FILE* outfile;
750  outfile = wxFopen( m_ConvertedFileName, wxT( "w" ) );
751 
752  if( outfile == NULL )
753  {
754  wxString msg;
755  msg.Printf( _( "File '%s' could not be created." ), m_ConvertedFileName );
756  wxMessageBox( msg );
757  return;
758  }
759 
760  std::string buffer;
761  ExportToBuffer( buffer, KICAD_LOGO );
762  fputs( buffer.c_str(), outfile );
763  fclose( outfile );
764 }
765 
766 
768 {
769  wxFileName fn( m_ConvertedFileName );
770  wxString path = fn.GetPath();
771 
772  if( path.IsEmpty() || !wxDirExists( path ) )
773  path = ::wxGetCwd();
774 
775  wxFileDialog fileDlg( this, _( "Create PostScript File" ),
776  path, wxEmptyString,
777  PSFileWildcard(),
778  wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
779 
780  int diag = fileDlg.ShowModal();
781 
782  if( diag != wxID_OK )
783  return;
784 
785  fn = fileDlg.GetPath();
786  fn.SetExt( wxT( "ps" ) );
787  m_ConvertedFileName = fn.GetFullPath();
788 
789  FILE* outfile;
790  outfile = wxFopen( m_ConvertedFileName, wxT( "w" ) );
791 
792  if( outfile == NULL )
793  {
794  wxString msg;
795  msg.Printf( _( "File '%s' could not be created." ), m_ConvertedFileName );
796  wxMessageBox( msg );
797  return;
798  }
799 
800  std::string buffer;
801  ExportToBuffer( buffer, POSTSCRIPT_FMT );
802  fputs( buffer.c_str(), outfile );
803  fclose( outfile );
804 }
805 
806 
808 {
809  wxFileName fn( m_ConvertedFileName );
810  wxString path = fn.GetPath();
811 
812  if( path.IsEmpty() || !wxDirExists(path) )
813  path = ::wxGetCwd();
814 
815  wxFileDialog fileDlg( this, _( "Create Symbol Library" ),
816  path, wxEmptyString,
818  wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
819 
820  int diag = fileDlg.ShowModal();
821 
822  if( diag != wxID_OK )
823  return;
824 
825  fn = fileDlg.GetPath();
826  fn.SetExt( LegacySymbolLibFileExtension );
827  m_ConvertedFileName = fn.GetFullPath();
828 
829  FILE* outfile = wxFopen( m_ConvertedFileName, wxT( "w" ) );
830 
831  if( outfile == NULL )
832  {
833  wxString msg;
834  msg.Printf( _( "File '%s' could not be created." ), m_ConvertedFileName );
835  wxMessageBox( msg );
836  return;
837  }
838 
839  std::string buffer;
840  ExportToBuffer( buffer, EESCHEMA_FMT );
841  fputs( buffer.c_str(), outfile );
842  fclose( outfile );
843 }
844 
845 
847 {
848  wxFileName fn( m_ConvertedFileName );
849  wxString path = fn.GetPath();
850 
851  if( path.IsEmpty() || !wxDirExists( path ) )
852  path = m_mruPath;
853 
854  wxFileDialog fileDlg( this, _( "Create Footprint Library" ),
855  path, wxEmptyString,
857  wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
858 
859  int diag = fileDlg.ShowModal();
860 
861  if( diag != wxID_OK )
862  return;
863 
864  fn = fileDlg.GetPath();
865  fn.SetExt( KiCadFootprintFileExtension );
866  m_ConvertedFileName = fn.GetFullPath();
867 
868  FILE* outfile = wxFopen( m_ConvertedFileName, wxT( "w" ) );
869 
870  if( outfile == NULL )
871  {
872  wxString msg;
873  msg.Printf( _( "File '%s' could not be created." ), m_ConvertedFileName );
874  wxMessageBox( msg );
875  return;
876  }
877 
878  std::string buffer;
879  ExportToBuffer( buffer, PCBNEW_KICAD_MOD );
880  fputs( buffer.c_str(), outfile );
881  fclose( outfile );
882  m_mruPath = fn.GetPath();
883 }
884 
885 
886 void BM2CMP_FRAME::ExportToBuffer( std::string& aOutput, OUTPUT_FMT_ID aFormat )
887 {
888  // Create a potrace bitmap
889  int h = m_NB_Image.GetHeight();
890  int w = m_NB_Image.GetWidth();
891  potrace_bitmap_t* potrace_bitmap = bm_new( w, h );
892 
893  if( !potrace_bitmap )
894  {
895  wxString msg;
896  msg.Printf( _( "Error allocating memory for potrace bitmap" ) );
897  wxMessageBox( msg );
898  return;
899  }
900 
901  /* fill the bitmap with data */
902  for( int y = 0; y < h; y++ )
903  {
904  for( int x = 0; x < w; x++ )
905  {
906  auto pix = m_NB_Image.GetGreen( x, y );
907  BM_PUT( potrace_bitmap, x, y, pix ? 0 : 1 );
908  }
909  }
910 
911  // choices of m_rbPCBLayer are expected to be in same order as
912  // BMP2CMP_MOD_LAYER. See bitmap2component.h
914 
915  if( aFormat == PCBNEW_KICAD_MOD )
916  modLayer = (BMP2CMP_MOD_LAYER) m_rbPCBLayer->GetSelection();
917 
918  BITMAPCONV_INFO converter( aOutput );
919  converter.ConvertBitmap( potrace_bitmap, aFormat, m_outputSizeX.GetOutputDPI(),
920  m_outputSizeY.GetOutputDPI(), modLayer );
921 
922  if( !converter.GetErrorMessages().empty() )
923  wxMessageBox( converter.GetErrorMessages().c_str(), _( "Errors" ) );
924 }
925 
926 
927 void BM2CMP_FRAME::OnFormatChange( wxCommandEvent& event )
928 {
929  if( m_rbOutputFormat->GetSelection() == PCBNEW_KICAD_MOD )
930  m_rbPCBLayer->Enable( true );
931  else
932  m_rbPCBLayer->Enable( false );
933 }
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
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 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
#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:258
#define _(s)
wxSlider * m_sliderThreshold
wxCheckBox * m_checkNegative
wxString FormatOutputSize(double aSize)
void OnSizeUnitChange(wxCommandEvent &event) override
void OnSizeChangeY(wxCommandEvent &event) override
wxString LegacySymbolLibFileWildcard()
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:70
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