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-2022 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 <tool/tool_manager.h>
36#include <tool/common_control.h>
37#include <wx/clipbrd.h>
38#include <wx/rawbmp.h>
39#include <wx/filedlg.h>
40#include <wx/msgdlg.h>
41#include <wx/dcclient.h>
42#include <wx/log.h>
43
44
45#include "bitmap2cmp_gui_base.h"
46#include "pgm_base.h"
47
48#define DEFAULT_DPI 300 // the image DPI used in formats that do not define a DPI
49
51{
52 m_outputSize = 0.0;
56}
57
58
60{
61 // Safety-check to guarantee no divide-by-zero
62 m_originalDPI = std::max( 1, m_originalDPI );
63
64 // Set the m_outputSize value from the m_originalSizePixels and the selected unit
67 else if( m_unit == EDA_UNITS::INCHES )
69 else
71}
72
73
75{
76 int outputDPI;
77
79 outputDPI = GetOriginalSizePixels() / ( m_outputSize / 25.4 );
80 else if( m_unit == EDA_UNITS::INCHES )
81 outputDPI = GetOriginalSizePixels() / m_outputSize;
82 else
83 outputDPI = KiROUND( m_outputSize );
84
85 // Zero is not a DPI, and may cause divide-by-zero errors...
86 outputDPI = std::max( 1, outputDPI );
87
88 return outputDPI;
89}
90
91
93{
94 // Set the unit used for m_outputSize, and convert the old m_outputSize value
95 // to the value in new unit
96 if( aUnit == m_unit )
97 return;
98
99 // Convert m_outputSize to mm:
100 double size_mm;
101
103 {
104 size_mm = m_outputSize;
105 }
106 else if( m_unit == EDA_UNITS::INCHES )
107 {
108 size_mm = m_outputSize * 25.4;
109 }
110 else
111 {
112 // m_outputSize is the DPI, not an image size
113 // the image size is m_originalSizePixels / m_outputSize (in inches)
114 if( m_outputSize )
115 size_mm = m_originalSizePixels / m_outputSize * 25.4;
116 else
117 size_mm = 0;
118 }
119
120 // Convert m_outputSize to new value:
121 if( aUnit == EDA_UNITS::MILLIMETRES )
122 {
123 m_outputSize = size_mm;
124 }
125 else if( aUnit == EDA_UNITS::INCHES )
126 {
127 m_outputSize = size_mm / 25.4;
128 }
129 else
130 {
131 if( size_mm )
132 m_outputSize = m_originalSizePixels / size_mm * 25.4;
133 else
134 m_outputSize = 0;
135 }
136
137 m_unit = aUnit;
138}
139
140
141BEGIN_EVENT_TABLE( BM2CMP_FRAME, BM2CMP_FRAME_BASE )
142 EVT_MENU( wxID_EXIT, BM2CMP_FRAME::OnExit )
143 EVT_MENU( wxID_OPEN, BM2CMP_FRAME::OnLoadFile )
144END_EVENT_TABLE()
145
146
147BM2CMP_FRAME::BM2CMP_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
148 BM2CMP_FRAME_BASE( aParent )
149{
150 SetKiway( this, aKiway );
151
152 for( wxString unit : { _( "mm" ), _( "Inch" ), _( "DPI" ) } )
153 m_PixelUnit->Append( unit );
154
155 LoadSettings( config() );
156
157 m_outputSizeX.SetUnit( getUnitFromSelection() );
158 m_outputSizeY.SetUnit( getUnitFromSelection() );
159 m_outputSizeX.SetOutputSize( 0, getUnitFromSelection() );
160 m_outputSizeY.SetOutputSize( 0, getUnitFromSelection() );
161
162 m_UnitSizeX->ChangeValue( FormatOutputSize( m_outputSizeX.GetOutputSize() ) );
163 m_UnitSizeY->ChangeValue( FormatOutputSize( m_outputSizeY.GetOutputSize() ) );
164
165 // Give an icon
166 wxIcon icon;
167 wxIconBundle icon_bundle;
168
169 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_bitmap2component ) );
170 icon_bundle.AddIcon( icon );
171 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_bitmap2component_32 ) );
172 icon_bundle.AddIcon( icon );
173 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_bitmap2component_16 ) );
174 icon_bundle.AddIcon( icon );
175
176 SetIcons( icon_bundle );
177
178 ReCreateMenuBar();
179
180 GetSizer()->SetSizeHints( this );
181
182 m_buttonExportFile->Enable( false );
183 m_buttonExportClipboard->Enable( false );
184
185 SetSize( m_framePos.x, m_framePos.y, m_frameSize.x, m_frameSize.y );
186
187 if ( m_framePos == wxDefaultPosition )
188 Centre();
189}
190
191
193{
194 SaveSettings( config() );
195 /*
196 * This needed for OSX: avoids further OnDraw processing after this
197 * destructor and before the native window is destroyed
198 */
199 Freeze();
200}
201
202
204{
205 return m_Notebook->GetCurrentPage();
206}
207
208
210{
211 // wxWidgets handles the Mac Application menu behind the scenes, but that means
212 // we always have to start from scratch with a new wxMenuBar.
213 wxMenuBar* oldMenuBar = GetMenuBar();
214 wxMenuBar* menuBar = new wxMenuBar();
215
216 wxMenu* fileMenu = new wxMenu;
217
218 wxMenuItem* item = new wxMenuItem( fileMenu, wxID_OPEN, _( "Open..." ) + wxT( "\tCtrl+O" ),
219 _( "Load source image" ) );
220
221 fileMenu->Append( item );
222
223#ifndef __WXMAC__
224 // Mac moves Quit to the App menu so we don't need a separator on Mac
225 fileMenu->AppendSeparator();
226#endif
227
228 item = new wxMenuItem( fileMenu, wxID_EXIT, _( "Quit" ) + wxT( "\tCtrl+Q" ),
229 _( "Quit Image Converter" ) );
230
231 if( Pgm().GetCommonSettings()->m_Appearance.use_icons_in_menus )
232 item->SetBitmap( KiBitmap( BITMAPS::exit ) );
233
234 fileMenu->Append( item );
235
236 menuBar->Append( fileMenu, _( "&File" ) );
237
238 SetMenuBar( menuBar );
239 delete oldMenuBar;
240}
241
242
243void BM2CMP_FRAME::OnExit( wxCommandEvent& event )
244{
245 Destroy();
246}
247
248
250{
252
253 BITMAP2CMP_SETTINGS* cfg = static_cast<BITMAP2CMP_SETTINGS*>( aCfg );
254
257
258 int u_select = cfg->m_Units;
259
260 if( u_select < 0 || u_select > 2 ) // Validity control
261 u_select = 0;
262
263 m_PixelUnit->SetSelection( u_select );
264
265 m_sliderThreshold->SetValue( cfg->m_Threshold );
266
267 m_Negative = cfg->m_Negative;
268 m_checkNegative->SetValue( cfg->m_Negative );
269
270 m_AspectRatio = 1.0;
271 m_aspectRatioCheckbox->SetValue( true );
272
273 int format = cfg->m_LastFormat;
274
275 if( format < 0 || format > FINAL_FMT )
276 format = PCBNEW_KICAD_MOD;
277
278 m_rbOutputFormat->SetSelection( format );
279
280 if( format == PCBNEW_KICAD_MOD )
281 m_rbPCBLayer->Enable( true );
282 else
283 m_rbPCBLayer->Enable( false );
284
285 int last_layer = cfg->m_LastModLayer;
286
287 if( last_layer > static_cast<int>( MOD_LYR_FINAL ) ) // Out of range
288 m_rbPCBLayer->SetSelection( MOD_LYR_FSILKS );
289 else
290 m_rbPCBLayer->SetSelection( last_layer );
291}
292
293
295{
297
298 BITMAP2CMP_SETTINGS* cfg = static_cast<BITMAP2CMP_SETTINGS*>( aCfg );
299
302 cfg->m_Threshold = m_sliderThreshold->GetValue();
303 cfg->m_Negative = m_checkNegative->IsChecked();
304 cfg->m_LastFormat = m_rbOutputFormat->GetSelection();
305 cfg->m_LastModLayer = m_rbPCBLayer->GetSelection();
306 cfg->m_Units = m_PixelUnit->GetSelection();
307}
308
309
310void BM2CMP_FRAME::OnPaintInit( wxPaintEvent& event )
311{
312#ifdef __WXMAC__
313 // Otherwise fails due: using wxPaintDC without being in a native paint event
314 wxClientDC pict_dc( m_InitialPicturePanel );
315#else
316 wxPaintDC pict_dc( m_InitialPicturePanel );
317#endif
318
319 m_InitialPicturePanel->PrepareDC( pict_dc );
320
321 // OSX crashes with empty bitmaps (on initial refreshes)
322 if( m_Pict_Bitmap.IsOk() )
323 pict_dc.DrawBitmap( m_Pict_Bitmap, 0, 0, !!m_Pict_Bitmap.GetMask() );
324
325 event.Skip();
326}
327
328
329void BM2CMP_FRAME::OnPaintGreyscale( wxPaintEvent& event )
330{
331#ifdef __WXMAC__
332 // Otherwise fails due: using wxPaintDC without being in a native paint event
333 wxClientDC greyscale_dc( m_GreyscalePicturePanel );
334#else
335 wxPaintDC greyscale_dc( m_GreyscalePicturePanel );
336#endif
337
338 m_GreyscalePicturePanel->PrepareDC( greyscale_dc );
339
340 // OSX crashes with empty bitmaps (on initial refreshes)
341 if( m_Greyscale_Bitmap.IsOk() )
342 greyscale_dc.DrawBitmap( m_Greyscale_Bitmap, 0, 0, !!m_Greyscale_Bitmap.GetMask() );
343
344 event.Skip();
345}
346
347
348void BM2CMP_FRAME::OnPaintBW( wxPaintEvent& event )
349{
350#ifdef __WXMAC__
351 // Otherwise fails due: using wxPaintDC without being in a native paint event
352 wxClientDC nb_dc( m_BNPicturePanel );
353#else
354 wxPaintDC nb_dc( m_BNPicturePanel );
355#endif
356
357 m_BNPicturePanel->PrepareDC( nb_dc );
358
359 if( m_BN_Bitmap.IsOk() )
360 nb_dc.DrawBitmap( m_BN_Bitmap, 0, 0, !!m_BN_Bitmap.GetMask() );
361
362 event.Skip();
363}
364
365
366void BM2CMP_FRAME::OnLoadFile( wxCommandEvent& event )
367{
368 wxFileName fn( m_BitmapFileName );
369 wxString path = fn.GetPath();
370
371 if( path.IsEmpty() || !wxDirExists( path ) )
372 path = m_mruPath;
373
374 wxFileDialog fileDlg( this, _( "Choose Image" ), path, wxEmptyString,
375 _( "Image Files" ) + wxS( " " )+ wxImage::GetImageExtWildcard(),
376 wxFD_OPEN | wxFD_FILE_MUST_EXIST );
377
378 int diag = fileDlg.ShowModal();
379
380 if( diag != wxID_OK )
381 return;
382
383 wxString fullFilename = fileDlg.GetPath();
384
385 if( !OpenProjectFiles( std::vector<wxString>( 1, fullFilename ) ) )
386 return;
387
388 fn = fullFilename;
389 m_mruPath = fn.GetPath();
390 SetStatusText( fullFilename );
391 Refresh();
392}
393
394
395bool BM2CMP_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, int aCtl )
396{
397 m_Pict_Image.Destroy();
398 m_BitmapFileName = aFileSet[0];
399
400 if( !m_Pict_Image.LoadFile( m_BitmapFileName ) )
401 {
402 // LoadFile has its own UI, no need for further failure notification here
403 return false;
404 }
405
406 m_Pict_Bitmap = wxBitmap( m_Pict_Image );
407
408 // Determine image resolution in DPI (does not existing in all formats).
409 // the resolution can be given in bit per inches or bit per cm in file
410
411 int imageDPIx = m_Pict_Image.GetOptionInt( wxIMAGE_OPTION_RESOLUTIONX );
412 int imageDPIy = m_Pict_Image.GetOptionInt( wxIMAGE_OPTION_RESOLUTIONY );
413
414 if( imageDPIx > 1 && imageDPIy > 1 )
415 {
416 if( m_Pict_Image.GetOptionInt( wxIMAGE_OPTION_RESOLUTIONUNIT ) == wxIMAGE_RESOLUTION_CM )
417 {
418 imageDPIx = KiROUND( imageDPIx * 2.54 );
419 imageDPIy = KiROUND( imageDPIy * 2.54 );
420 }
421 }
422 else // fallback to a default value (DEFAULT_DPI)
423 {
424 imageDPIx = imageDPIy = DEFAULT_DPI;
425 }
426
427 m_InputXValueDPI->SetLabel( wxString::Format( wxT( "%d" ), imageDPIx ) );
428 m_InputYValueDPI->SetLabel( wxString::Format( wxT( "%d" ), imageDPIy ) );
429
430 int h = m_Pict_Bitmap.GetHeight();
431 int w = m_Pict_Bitmap.GetWidth();
432 m_AspectRatio = (double) w / h;
433
434 m_outputSizeX.SetOriginalDPI( imageDPIx );
436 m_outputSizeY.SetOriginalDPI( imageDPIy );
438
439 // Update display to keep aspect ratio
440 wxCommandEvent dummy;
442
444
445 m_InitialPicturePanel->SetVirtualSize( w, h );
446 m_GreyscalePicturePanel->SetVirtualSize( w, h );
447 m_BNPicturePanel->SetVirtualSize( w, h );
448
449 m_Greyscale_Image.Destroy();
450 m_Greyscale_Image = m_Pict_Image.ConvertToGreyscale( );
451
452 if( m_Pict_Bitmap.GetMask() )
453 {
454 for( int x = 0; x < m_Pict_Bitmap.GetWidth(); x++ )
455 {
456 for( int y = 0; y < m_Pict_Bitmap.GetHeight(); y++ )
457 {
458 if( m_Pict_Image.GetRed( x, y ) == m_Pict_Image.GetMaskRed() &&
459 m_Pict_Image.GetGreen( x, y ) == m_Pict_Image.GetMaskGreen() &&
460 m_Pict_Image.GetBlue( x, y ) == m_Pict_Image.GetMaskBlue() )
461 {
462 m_Greyscale_Image.SetRGB( x, y, 255, 255, 255 );
463 }
464 }
465 }
466 }
467
468 if( m_Negative )
470
473 Binarize( (double) m_sliderThreshold->GetValue() / m_sliderThreshold->GetMax() );
474
475 m_buttonExportFile->Enable( true );
476 m_buttonExportClipboard->Enable( true );
477
482
483 return true;
484}
485
486
487// return a string giving the output size, according to the selected unit
488wxString BM2CMP_FRAME::FormatOutputSize( double aSize )
489{
490 wxString text;
491
493 text.Printf( wxS( "%.1f" ), aSize );
495 text.Printf( wxS( "%.2f" ), aSize );
496 else
497 text.Printf( wxT( "%d" ), KiROUND( aSize ) );
498
499 return text;
500}
501
503{
504 // Note: the image resolution text controls are not modified here, to avoid a race between
505 // text change when entered by user and a text change if it is modified here.
506
507 if( m_Pict_Bitmap.IsOk() )
508 {
509 int h = m_Pict_Bitmap.GetHeight();
510 int w = m_Pict_Bitmap.GetWidth();
511 int nb = m_Pict_Bitmap.GetDepth();
512
513 m_SizeXValue->SetLabel( wxString::Format( wxT( "%d" ), w ) );
514 m_SizeYValue->SetLabel( wxString::Format( wxT( "%d" ), h ) );
515 m_BPPValue->SetLabel( wxString::Format( wxT( "%d" ), nb ) );
516 }
517}
518
519
521{
522 // return the EDA_UNITS from the m_PixelUnit choice
523 switch( m_PixelUnit->GetSelection() )
524 {
525 case 1: return EDA_UNITS::INCHES;
526 case 2: return EDA_UNITS::UNSCALED;
527 case 0:
528 default: return EDA_UNITS::MILLIMETRES;
529 }
530}
531
532
533void BM2CMP_FRAME::OnSizeChangeX( wxCommandEvent& event )
534{
535 double new_size;
536
537 if( m_UnitSizeX->GetValue().ToDouble( &new_size ) )
538 {
539 if( m_aspectRatioCheckbox->GetValue() )
540 {
541 double calculatedY = new_size / m_AspectRatio;
542
544 {
545 // for units in DPI, keeping aspect ratio cannot use m_AspectRatioLocked.
546 // just re-scale the other dpi
547 double ratio = new_size / m_outputSizeX.GetOutputSize();
548 calculatedY = m_outputSizeY.GetOutputSize() * ratio;
549 }
550
553 }
554
556 }
557
559}
560
561
562void BM2CMP_FRAME::OnSizeChangeY( wxCommandEvent& event )
563{
564 double new_size;
565
566 if( m_UnitSizeY->GetValue().ToDouble( &new_size ) )
567 {
568 if( m_aspectRatioCheckbox->GetValue() )
569 {
570 double calculatedX = new_size * m_AspectRatio;
571
573 {
574 // for units in DPI, keeping aspect ratio cannot use m_AspectRatioLocked.
575 // just re-scale the other dpi
576 double ratio = new_size / m_outputSizeX.GetOutputSize();
577 calculatedX = m_outputSizeX.GetOutputSize() * ratio;
578 }
579
582 }
583
585 }
586
588}
589
590
591void BM2CMP_FRAME::OnSizeUnitChange( wxCommandEvent& event )
592{
596
599}
600
601
602void BM2CMP_FRAME::ToggleAspectRatioLock( wxCommandEvent& event )
603{
604 if( m_aspectRatioCheckbox->GetValue() )
605 {
606 // Force display update when aspect ratio is locked
607 wxCommandEvent dummy;
609 }
610}
611
612
613void BM2CMP_FRAME::Binarize( double aThreshold )
614{
615 int h = m_Greyscale_Image.GetHeight();
616 int w = m_Greyscale_Image.GetWidth();
617 unsigned char threshold = aThreshold * 255;
618 unsigned char alpha_thresh = 0.7 * threshold;
619
620 for( int y = 0; y < h; y++ )
621 {
622 for( int x = 0; x < w; x++ )
623 {
624 unsigned char pixout;
625 unsigned char pixin = m_Greyscale_Image.GetGreen( x, y );
626 unsigned char alpha = m_Greyscale_Image.HasAlpha() ? m_Greyscale_Image.GetAlpha( x, y )
627 : wxALPHA_OPAQUE;
628
629 if( pixin < threshold && alpha > alpha_thresh )
630 pixout = 0;
631 else
632 pixout = 255;
633
634 m_NB_Image.SetRGB( x, y, pixout, pixout, pixout );
635 }
636 }
637
638 m_BN_Bitmap = wxBitmap( m_NB_Image );
639}
640
641
643{
644 unsigned char pix;
645 int h = m_Greyscale_Image.GetHeight();
646 int w = m_Greyscale_Image.GetWidth();
647
648 for( int y = 0; y < h; y++ )
649 {
650 for( int x = 0; x < w; x++ )
651 {
652 pix = m_Greyscale_Image.GetGreen( x, y );
653 pix = ~pix;
654 m_Greyscale_Image.SetRGB( x, y, pix, pix, pix );
655 }
656 }
657}
658
659
660void BM2CMP_FRAME::OnNegativeClicked( wxCommandEvent& )
661{
662 if( m_checkNegative->GetValue() != m_Negative )
663 {
665
667 Binarize( (double)m_sliderThreshold->GetValue()/m_sliderThreshold->GetMax() );
668 m_Negative = m_checkNegative->GetValue();
669
670 Refresh();
671 }
672}
673
674
675void BM2CMP_FRAME::OnThresholdChange( wxScrollEvent& event )
676{
677 Binarize( (double)m_sliderThreshold->GetValue()/m_sliderThreshold->GetMax() );
678 Refresh();
679}
680
681
682void BM2CMP_FRAME::OnExportToFile( wxCommandEvent& event )
683{
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 exportBitmap( format );
688}
689
690
691void BM2CMP_FRAME::OnExportToClipboard( wxCommandEvent& event )
692{
693 // choices of m_rbOutputFormat are expected to be in same order as
694 // OUTPUT_FMT_ID. See bitmap2component.h
695 OUTPUT_FMT_ID format = (OUTPUT_FMT_ID) m_rbOutputFormat->GetSelection();
696
697 std::string buffer;
698 ExportToBuffer( buffer, format );
699
700 wxLogNull doNotLog; // disable logging of failed clipboard actions
701
702 // Write buffer to the clipboard
703 if( wxTheClipboard->Open() )
704 {
705 // This data objects are held by the clipboard,
706 // so do not delete them in the app.
707 wxTheClipboard->SetData( new wxTextDataObject( buffer.c_str() ) );
708 wxTheClipboard->Flush(); // Allow data to be available after closing KiCad
709 wxTheClipboard->Close();
710 }
711 else
712 {
713 wxMessageBox( _( "Unable to export to the Clipboard") );
714 }
715}
716
717
719{
720 switch( aFormat )
721 {
722 case EESCHEMA_FMT: exportEeschemaFormat(); break;
725 case KICAD_WKS_LOGO: exportLogo(); 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 == nullptr )
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;
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" ), path, wxEmptyString,
776 PSFileWildcard(), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
777
778 if( fileDlg.ShowModal() != wxID_OK )
779 return;
780
781 fn = fileDlg.GetPath();
782 fn.SetExt( wxT( "ps" ) );
783 m_ConvertedFileName = fn.GetFullPath();
784
785 FILE* outfile;
786 outfile = wxFopen( m_ConvertedFileName, wxT( "w" ) );
787
788 if( outfile == nullptr )
789 {
790 wxString msg;
791 msg.Printf( _( "File '%s' could not be created." ), m_ConvertedFileName );
792 wxMessageBox( msg );
793 return;
794 }
795
796 std::string buffer;
798 fputs( buffer.c_str(), outfile );
799 fclose( outfile );
800}
801
802
804{
805 wxFileName fn( m_ConvertedFileName );
806 wxString path = fn.GetPath();
807
808 if( path.IsEmpty() || !wxDirExists(path) )
809 path = ::wxGetCwd();
810
811 wxFileDialog fileDlg( this, _( "Create Symbol Library" ), path, wxEmptyString,
812 KiCadSymbolLibFileWildcard(), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
813
814 if( fileDlg.ShowModal() != wxID_OK )
815 return;
816
817 fn = fileDlg.GetPath();
818 fn.SetExt( KiCadSymbolLibFileExtension );
819 m_ConvertedFileName = fn.GetFullPath();
820
821 FILE* outfile = wxFopen( m_ConvertedFileName, wxT( "w" ) );
822
823 if( outfile == nullptr )
824 {
825 wxString msg;
826 msg.Printf( _( "File '%s' could not be created." ), m_ConvertedFileName );
827 wxMessageBox( msg );
828 return;
829 }
830
831 std::string buffer;
832 ExportToBuffer( buffer, EESCHEMA_FMT );
833 fputs( buffer.c_str(), outfile );
834 fclose( outfile );
835}
836
837
839{
840 wxFileName fn( m_ConvertedFileName );
841 wxString path = fn.GetPath();
842
843 if( path.IsEmpty() || !wxDirExists( path ) )
844 path = m_mruPath;
845
846 wxFileDialog fileDlg( this, _( "Create Footprint Library" ), path, wxEmptyString,
847 KiCadFootprintLibFileWildcard(), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
848
849 if( fileDlg.ShowModal() != wxID_OK )
850 return;
851
852 fn = fileDlg.GetPath();
853 fn.SetExt( KiCadFootprintFileExtension );
854 m_ConvertedFileName = fn.GetFullPath();
855
856 FILE* outfile = wxFopen( m_ConvertedFileName, wxT( "w" ) );
857
858 if( outfile == nullptr )
859 {
860 wxString msg;
861 msg.Printf( _( "File '%s' could not be created." ), m_ConvertedFileName );
862 wxMessageBox( msg );
863 return;
864 }
865
866 std::string buffer;
868 fputs( buffer.c_str(), outfile );
869 fclose( outfile );
870 m_mruPath = fn.GetPath();
871}
872
873
874void BM2CMP_FRAME::ExportToBuffer( std::string& aOutput, OUTPUT_FMT_ID aFormat )
875{
876 // Create a potrace bitmap
877 int h = m_NB_Image.GetHeight();
878 int w = m_NB_Image.GetWidth();
879 potrace_bitmap_t* potrace_bitmap = bm_new( w, h );
880
881 if( !potrace_bitmap )
882 {
883 wxString msg;
884 msg.Printf( _( "Error allocating memory for potrace bitmap" ) );
885 wxMessageBox( msg );
886 return;
887 }
888
889 /* fill the bitmap with data */
890 for( int y = 0; y < h; y++ )
891 {
892 for( int x = 0; x < w; x++ )
893 {
894 unsigned char pix = m_NB_Image.GetGreen( x, y );
895 BM_PUT( potrace_bitmap, x, y, pix ? 0 : 1 );
896 }
897 }
898
899 // choices of m_rbPCBLayer are expected to be in same order as
900 // BMP2CMP_MOD_LAYER. See bitmap2component.h
902
903 if( aFormat == PCBNEW_KICAD_MOD )
904 modLayer = (BMP2CMP_MOD_LAYER) m_rbPCBLayer->GetSelection();
905
906 BITMAPCONV_INFO converter( aOutput );
907 converter.ConvertBitmap( potrace_bitmap, aFormat, m_outputSizeX.GetOutputDPI(),
908 m_outputSizeY.GetOutputDPI(), modLayer );
909
910 if( !converter.GetErrorMessages().empty() )
911 wxMessageBox( converter.GetErrorMessages().c_str(), _( "Errors" ) );
912}
913
914
915void BM2CMP_FRAME::OnFormatChange( wxCommandEvent& event )
916{
917 if( m_rbOutputFormat->GetSelection() == PCBNEW_KICAD_MOD )
918 m_rbPCBLayer->Enable( true );
919 else
920 m_rbPCBLayer->Enable( false );
921}
#define DEFAULT_DPI
BMP2CMP_MOD_LAYER
@ MOD_LYR_FSILKS
@ MOD_LYR_FINAL
OUTPUT_FMT_ID
@ FINAL_FMT
@ KICAD_WKS_LOGO
@ PCBNEW_KICAD_MOD
@ POSTSCRIPT_FMT
@ EESCHEMA_FMT
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
@ icon_bitmap2component
@ icon_bitmap2component_32
@ icon_bitmap2component_16
APP_SETTINGS_BASE is a settings class that should be derived for each standalone KiCad application.
Definition: app_settings.h:110
std::string & GetErrorMessages()
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.
Class BM2CMP_FRAME_BASE.
wxStaticText * m_InputYValueDPI
wxCheckBox * m_aspectRatioCheckbox
wxSlider * m_sliderThreshold
wxButton * m_buttonExportFile
wxTextCtrl * m_UnitSizeX
wxStaticText * m_SizeXValue
wxStaticText * m_BPPValue
wxStaticText * m_InputXValueDPI
wxScrolledWindow * m_GreyscalePicturePanel
wxCheckBox * m_checkNegative
wxScrolledWindow * m_InitialPicturePanel
wxScrolledWindow * m_BNPicturePanel
wxButton * m_buttonExportClipboard
wxRadioBox * m_rbPCBLayer
wxTextCtrl * m_UnitSizeY
wxRadioBox * m_rbOutputFormat
wxStaticText * m_SizeYValue
void OnSizeChangeX(wxCommandEvent &event) override
void LoadSettings(APP_SETTINGS_BASE *aCfg) override
Load common frame parameters from a configuration file.
void doReCreateMenuBar() override
void exportEeschemaFormat()
Generate a schematic library which contains one component: the logo.
wxImage m_Pict_Image
void exportPostScriptFormat()
Generate a postscript file.
void OnPaintBW(wxPaintEvent &event) override
wxString FormatOutputSize(double aSize)
double m_AspectRatio
IMAGE_SIZE m_outputSizeY
wxBitmap m_Greyscale_Bitmap
void OnThresholdChange(wxScrollEvent &event) override
void NegateGreyscaleImage()
void OnExportToFile(wxCommandEvent &event) override
IMAGE_SIZE m_outputSizeX
void OnLoadFile(wxCommandEvent &event) override
bool OpenProjectFiles(const std::vector< wxString > &aFilenames, int aCtl=0) override
Open a project or set of files given by aFileList.
wxBitmap m_Pict_Bitmap
void OnSizeUnitChange(wxCommandEvent &event) override
void OnNegativeClicked(wxCommandEvent &event) override
void OnPaintInit(wxPaintEvent &event) override
void Binarize(double aThreshold)
wxString m_BitmapFileName
void updateImageInfo()
wxImage m_NB_Image
void ToggleAspectRatioLock(wxCommandEvent &event) override
void exportLogo()
Generate a file suitable to be copied into a drawing sheet (.kicad_wks) file.
void OnSizeChangeY(wxCommandEvent &event) override
wxImage m_Greyscale_Image
wxString m_ConvertedFileName
void OnFormatChange(wxCommandEvent &event) override
void ExportToBuffer(std::string &aOutput, OUTPUT_FMT_ID aFormat)
generate a export data of the current bitmap.
wxWindow * GetToolCanvas() const override
Canvas access.
EDA_UNITS getUnitFromSelection()
void OnPaintGreyscale(wxPaintEvent &event) override
void OnExit(wxCommandEvent &event)
void OnExportToClipboard(wxCommandEvent &event) override
void exportPcbnewFormat()
Generate a footprint in S expr format.
void exportBitmap(OUTPUT_FMT_ID aFormat)
void SaveSettings(APP_SETTINGS_BASE *aCfg) override
Save common frame parameters to a configuration data file.
wxBitmap m_BN_Bitmap
virtual APP_SETTINGS_BASE * config() const
Returns the settings object used in SaveSettings(), and is overloaded in KICAD_MANAGER_FRAME.
virtual void LoadSettings(APP_SETTINGS_BASE *aCfg)
Load common frame parameters from a configuration file.
virtual void SaveSettings(APP_SETTINGS_BASE *aCfg)
Save common frame parameters to a configuration data file.
wxString m_mruPath
void SetUnit(EDA_UNITS aUnit)
double m_outputSize
double GetOutputSize()
EDA_UNITS m_unit
void SetOriginalDPI(int aDPI)
int GetOriginalSizePixels()
int m_originalSizePixels
int GetOutputDPI()
void SetOutputSizeFromInitialImageSize()
void SetOutputSize(double aSize, EDA_UNITS aUnit)
void SetOriginalSizePixels(int aPixels)
bool Destroy() override
Our version of Destroy() which is virtual from wxWidgets.
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
Definition: kiway.h:274
#define _(s)
EDA_UNITS
Definition: eda_units.h:43
const std::string KiCadSymbolLibFileExtension
const std::string KiCadFootprintFileExtension
const std::string DrawingSheetFileExtension
wxString KiCadFootprintLibFileWildcard()
wxString DrawingSheetFileWildcard()
wxString PSFileWildcard()
wxString KiCadSymbolLibFileWildcard()
void Refresh()
Update the board display after modifying it by a python script (note: it is automatically called by a...
see class PGM_BASE
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
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:111
std::vector< FAB_LAYER_COLOR > dummy
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:85
Definition of file extensions used in Kicad.