847 lines
24 KiB
C++
847 lines
24 KiB
C++
/*
|
|
* This program source code file is part of KICAD, a free EDA CAD application.
|
|
*
|
|
* Copyright (C) 1992-2010 jean-pierre.charras
|
|
* Copyright (C) 1992-2019 Kicad Developers, see AUTHORS.txt for contributors.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, you may find one here:
|
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
* or you may write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*/
|
|
|
|
#include <fctsys.h>
|
|
#include <macros.h>
|
|
#include <wx/clipbrd.h>
|
|
|
|
#include <pgm_base.h>
|
|
#include <confirm.h>
|
|
#include <gestfich.h>
|
|
#include <wildcards_and_files_ext.h>
|
|
#include <bitmap_io.h>
|
|
#include <build_version.h>
|
|
#include <menus_helpers.h>
|
|
#include <kiway.h>
|
|
#include <kiface_i.h>
|
|
|
|
#include <wx/rawbmp.h>
|
|
#include <potracelib.h>
|
|
|
|
#include "bitmap2component.h"
|
|
|
|
#include "bitmap2cmp_gui_base.h"
|
|
|
|
|
|
#define KEYWORD_FRAME_POSX wxT( "Bmconverter_Pos_x" )
|
|
#define KEYWORD_FRAME_POSY wxT( "Bmconverter_Pos_y" )
|
|
#define KEYWORD_FRAME_SIZEX wxT( "Bmconverter_Size_x" )
|
|
#define KEYWORD_FRAME_SIZEY wxT( "Bmconverter_Size_y" )
|
|
#define KEYWORD_LAST_INPUT_FILE wxT( "Last_input" )
|
|
#define KEYWORD_LAST_OUTPUT_FILE wxT( "Last_output" )
|
|
#define KEYWORD_LAST_FORMAT wxT( "Last_format" )
|
|
#define KEYWORD_LAST_MODLAYER wxT( "Last_modlayer" )
|
|
#define KEYWORD_BINARY_THRESHOLD wxT( "Threshold" )
|
|
#define KEYWORD_BW_NEGATIVE wxT( "Negative_choice" )
|
|
|
|
#define DEFAULT_DPI 300 // Default resolution in Bit per inches
|
|
|
|
|
|
/**
|
|
* Class BM2CMP_FRAME_BASE
|
|
* is the main frame for this application
|
|
*/
|
|
class BM2CMP_FRAME : public BM2CMP_FRAME_BASE
|
|
{
|
|
private:
|
|
wxImage m_Pict_Image;
|
|
wxBitmap m_Pict_Bitmap;
|
|
wxImage m_Greyscale_Image;
|
|
wxBitmap m_Greyscale_Bitmap;
|
|
wxImage m_NB_Image;
|
|
wxBitmap m_BN_Bitmap;
|
|
wxSize m_imageDPI; // The initial image resolution. When unknown,
|
|
// set to DEFAULT_DPI x DEFAULT_DPI per Inch
|
|
bool m_Negative;
|
|
wxString m_BitmapFileName;
|
|
wxString m_ConvertedFileName;
|
|
wxSize m_frameSize;
|
|
wxPoint m_framePos;
|
|
std::unique_ptr<wxConfigBase> m_config;
|
|
bool m_exportToClipboard;
|
|
|
|
public:
|
|
BM2CMP_FRAME( KIWAY* aKiway, wxWindow* aParent );
|
|
~BM2CMP_FRAME();
|
|
|
|
// overload KIWAY_PLAYER virtual
|
|
bool OpenProjectFiles( const std::vector<wxString>& aFilenames, int aCtl=0 ) override;
|
|
|
|
private:
|
|
|
|
// Event handlers
|
|
void OnPaintInit( wxPaintEvent& event ) override;
|
|
void OnPaintGreyscale( wxPaintEvent& event ) override;
|
|
void OnPaintBW( wxPaintEvent& event ) override;
|
|
void OnLoadFile( wxCommandEvent& event ) override;
|
|
void OnExportToFile( wxCommandEvent& event ) override;
|
|
void OnExportToClipboard( wxCommandEvent& event ) override;
|
|
|
|
/**
|
|
* Generate a schematic library which contains one component:
|
|
* the logo
|
|
*/
|
|
void exportEeschemaFormat();
|
|
|
|
/**
|
|
* Generate a module in S expr format
|
|
*/
|
|
void exportPcbnewFormat();
|
|
|
|
/**
|
|
* Generate a postscript file
|
|
*/
|
|
void exportPostScriptFormat();
|
|
|
|
/**
|
|
* Generate a file suitable to be copied into a page layout
|
|
* description file (.kicad_wks file
|
|
*/
|
|
void OnExportLogo();
|
|
|
|
void Binarize( double aThreshold ); // aThreshold = 0.0 (black level) to 1.0 (white level)
|
|
void OnNegativeClicked( wxCommandEvent& event ) override;
|
|
void OnThresholdChange( wxScrollEvent& event ) override;
|
|
void OnResolutionChange( wxCommandEvent& event ) override;
|
|
|
|
// called when texts controls which handle the image resolution
|
|
// lose the focus, to ensure the right values are displayed
|
|
// because the m_imageDPI are clipped to acceptable values, and
|
|
// the text displayed could be differ during text editing
|
|
// We are using ChangeValue here to avoid generating a wxEVT_TEXT event.
|
|
void UpdateDPITextValueX( wxMouseEvent& event )
|
|
{
|
|
m_DPIValueX->ChangeValue( wxString::Format( wxT( "%d" ), m_imageDPI.x ) );
|
|
}
|
|
|
|
void UpdateDPITextValueY( wxMouseEvent& event )
|
|
{
|
|
m_DPIValueY->ChangeValue( wxString::Format( wxT( "%d" ), m_imageDPI.y ) );
|
|
}
|
|
|
|
void NegateGreyscaleImage( );
|
|
/**
|
|
* generate a export data of the current bitmap.
|
|
* @param aOutput is a string buffer to fill with data
|
|
* @param aFormat is the format to generate
|
|
*/
|
|
void ExportToBuffer( std::string&aOutput, OUTPUT_FMT_ID aFormat );
|
|
|
|
void updateImageInfo();
|
|
void OnFormatChange( wxCommandEvent& event ) override;
|
|
void exportBitmap( OUTPUT_FMT_ID aFormat );
|
|
};
|
|
|
|
|
|
BM2CMP_FRAME::BM2CMP_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
|
|
BM2CMP_FRAME_BASE( aParent )
|
|
{
|
|
SetKiway( this, aKiway );
|
|
|
|
int tmp;
|
|
m_config = GetNewConfig( Pgm().App().GetAppName() );
|
|
m_config->Read( KEYWORD_FRAME_POSX, & m_framePos.x, -1 );
|
|
m_config->Read( KEYWORD_FRAME_POSY, & m_framePos.y, -1 );
|
|
m_config->Read( KEYWORD_FRAME_SIZEX, & m_frameSize.x, -1 );
|
|
m_config->Read( KEYWORD_FRAME_SIZEY, & m_frameSize.y, -1 );
|
|
m_config->Read( KEYWORD_LAST_INPUT_FILE, &m_BitmapFileName );
|
|
m_config->Read( KEYWORD_LAST_OUTPUT_FILE, &m_ConvertedFileName );
|
|
|
|
if( m_config->Read( KEYWORD_BINARY_THRESHOLD, &tmp ) )
|
|
m_sliderThreshold->SetValue( tmp );
|
|
|
|
m_config->Read( KEYWORD_BW_NEGATIVE, &tmp, 0 );
|
|
m_Negative = tmp != 0;
|
|
m_checkNegative->SetValue( m_Negative );
|
|
m_exportToClipboard = false;
|
|
|
|
if( m_config->Read( KEYWORD_LAST_FORMAT, &tmp ) )
|
|
{
|
|
if( tmp < 0 || tmp > FINAL_FMT )
|
|
tmp = PCBNEW_KICAD_MOD;
|
|
|
|
m_radioBoxFormat->SetSelection( tmp );
|
|
}
|
|
|
|
if( tmp == PCBNEW_KICAD_MOD )
|
|
m_radio_PCBLayer->Enable( true );
|
|
else
|
|
m_radio_PCBLayer->Enable( false );
|
|
|
|
if( m_config->Read( KEYWORD_LAST_MODLAYER, &tmp ) )
|
|
{
|
|
if( (unsigned) tmp > MOD_LYR_FINAL ) // Out of range
|
|
m_radio_PCBLayer->SetSelection( MOD_LYR_FSILKS );
|
|
else
|
|
m_radio_PCBLayer->SetSelection( tmp );
|
|
}
|
|
|
|
// Give an icon
|
|
wxIcon icon;
|
|
icon.CopyFromBitmap( KiBitmap( icon_bitmap2component_xpm ) );
|
|
SetIcon( icon );
|
|
|
|
GetSizer()->SetSizeHints( this );
|
|
|
|
SetSize( m_framePos.x, m_framePos.y, m_frameSize.x, m_frameSize.y );
|
|
|
|
m_buttonExportFile->Enable( false );
|
|
m_buttonExportClipboard->Enable( false );
|
|
|
|
m_imageDPI.x = m_imageDPI.y = DEFAULT_DPI; // Default resolution in Bit per inches
|
|
|
|
if ( m_framePos == wxDefaultPosition )
|
|
Centre();
|
|
}
|
|
|
|
|
|
BM2CMP_FRAME::~BM2CMP_FRAME()
|
|
{
|
|
if( !m_config || IsIconized() )
|
|
return;
|
|
|
|
m_frameSize = GetSize();
|
|
m_framePos = GetPosition();
|
|
|
|
m_config->Write( KEYWORD_FRAME_POSX, (long) m_framePos.x );
|
|
m_config->Write( KEYWORD_FRAME_POSY, (long) m_framePos.y );
|
|
m_config->Write( KEYWORD_FRAME_SIZEX, (long) m_frameSize.x );
|
|
m_config->Write( KEYWORD_FRAME_SIZEY, (long) m_frameSize.y );
|
|
m_config->Write( KEYWORD_LAST_INPUT_FILE, m_BitmapFileName );
|
|
m_config->Write( KEYWORD_LAST_OUTPUT_FILE, m_ConvertedFileName );
|
|
m_config->Write( KEYWORD_BINARY_THRESHOLD, m_sliderThreshold->GetValue() );
|
|
m_config->Write( KEYWORD_BW_NEGATIVE, m_checkNegative->IsChecked() ? 1 : 0 );
|
|
m_config->Write( KEYWORD_LAST_FORMAT, m_radioBoxFormat->GetSelection() );
|
|
m_config->Write( KEYWORD_LAST_MODLAYER, m_radio_PCBLayer->GetSelection() );
|
|
|
|
/* This needed for OSX: avoids further OnDraw processing after this
|
|
* destructor and before the native window is destroyed
|
|
*/
|
|
this->Freeze( );
|
|
}
|
|
|
|
|
|
void BM2CMP_FRAME::OnPaintInit( wxPaintEvent& event )
|
|
{
|
|
#ifdef __WXMAC__
|
|
// Otherwise fails due: using wxPaintDC without being in a native paint event
|
|
wxClientDC pict_dc( m_InitialPicturePanel );
|
|
#else
|
|
wxPaintDC pict_dc( m_InitialPicturePanel );
|
|
#endif
|
|
|
|
m_InitialPicturePanel->PrepareDC( pict_dc );
|
|
|
|
// OSX crashes with empty bitmaps (on initial refreshes)
|
|
if( m_Pict_Bitmap.IsOk() )
|
|
pict_dc.DrawBitmap( m_Pict_Bitmap, 0, 0, !!m_Pict_Bitmap.GetMask() );
|
|
|
|
event.Skip();
|
|
}
|
|
|
|
|
|
void BM2CMP_FRAME::OnPaintGreyscale( wxPaintEvent& event )
|
|
{
|
|
#ifdef __WXMAC__
|
|
// Otherwise fails due: using wxPaintDC without being in a native paint event
|
|
wxClientDC greyscale_dc( m_GreyscalePicturePanel );
|
|
#else
|
|
wxPaintDC greyscale_dc( m_GreyscalePicturePanel );
|
|
#endif
|
|
|
|
m_GreyscalePicturePanel->PrepareDC( greyscale_dc );
|
|
|
|
// OSX crashes with empty bitmaps (on initial refreshes)
|
|
if( m_Greyscale_Bitmap.IsOk() )
|
|
greyscale_dc.DrawBitmap( m_Greyscale_Bitmap, 0, 0, !!m_Greyscale_Bitmap.GetMask() );
|
|
|
|
event.Skip();
|
|
}
|
|
|
|
|
|
void BM2CMP_FRAME::OnPaintBW( wxPaintEvent& event )
|
|
{
|
|
#ifdef __WXMAC__
|
|
// Otherwise fails due: using wxPaintDC without being in a native paint event
|
|
wxClientDC nb_dc( m_BNPicturePanel );
|
|
#else
|
|
wxPaintDC nb_dc( m_BNPicturePanel );
|
|
#endif
|
|
|
|
m_BNPicturePanel->PrepareDC( nb_dc );
|
|
|
|
if( m_BN_Bitmap.IsOk() )
|
|
nb_dc.DrawBitmap( m_BN_Bitmap, 0, 0, !!m_BN_Bitmap.GetMask() );
|
|
|
|
event.Skip();
|
|
}
|
|
|
|
|
|
void BM2CMP_FRAME::OnLoadFile( wxCommandEvent& event )
|
|
{
|
|
wxFileName fn( m_BitmapFileName );
|
|
wxString path = fn.GetPath();
|
|
|
|
if( path.IsEmpty() || !wxDirExists( path ) )
|
|
path = m_mruPath;
|
|
|
|
wxFileDialog fileDlg( this, _( "Choose Image" ), path, wxEmptyString,
|
|
_( "Image Files " ) + wxImage::GetImageExtWildcard(),
|
|
wxFD_OPEN | wxFD_FILE_MUST_EXIST );
|
|
|
|
int diag = fileDlg.ShowModal();
|
|
|
|
if( diag != wxID_OK )
|
|
return;
|
|
|
|
wxString fullFilename = fileDlg.GetPath();
|
|
|
|
if( !OpenProjectFiles( std::vector<wxString>( 1, fullFilename ) ) )
|
|
return;
|
|
|
|
fn = fullFilename;
|
|
m_mruPath = fn.GetPath();
|
|
SetStatusText( fullFilename );
|
|
Refresh();
|
|
}
|
|
|
|
|
|
bool BM2CMP_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, int aCtl )
|
|
{
|
|
m_Pict_Image.Destroy();
|
|
m_BitmapFileName = aFileSet[0];
|
|
|
|
if( !m_Pict_Image.LoadFile( m_BitmapFileName ) )
|
|
{
|
|
// LoadFile has its own UI, no need for further failure notification here
|
|
return false;
|
|
}
|
|
|
|
m_Pict_Bitmap = wxBitmap( m_Pict_Image );
|
|
|
|
int h = m_Pict_Bitmap.GetHeight();
|
|
int w = m_Pict_Bitmap.GetWidth();
|
|
|
|
// Determine image resolution in DPI (does not existing in all formats).
|
|
// the resolution can be given in bit per inches or bit per cm in file
|
|
m_imageDPI.x = m_Pict_Image.GetOptionInt( wxIMAGE_OPTION_RESOLUTIONX );
|
|
m_imageDPI.y = m_Pict_Image.GetOptionInt( wxIMAGE_OPTION_RESOLUTIONY );
|
|
|
|
if( m_imageDPI.x > 1 && m_imageDPI.y > 1 )
|
|
{
|
|
if( m_Pict_Image.GetOptionInt( wxIMAGE_OPTION_RESOLUTIONUNIT ) == wxIMAGE_RESOLUTION_CM )
|
|
{
|
|
// When the initial resolution is given in bits per cm,
|
|
// experience shows adding 1.27 to the resolution converted in dpi
|
|
// before convert to int value reduce the conversion error
|
|
// but it is not perfect
|
|
m_imageDPI.x = m_imageDPI.x * 2.54 + 1.27;
|
|
m_imageDPI.y = m_imageDPI.y * 2.54 + 1.27;
|
|
}
|
|
}
|
|
else // fallback to the default value
|
|
m_imageDPI.x = m_imageDPI.y = DEFAULT_DPI;
|
|
|
|
// Display image info:
|
|
// We are using ChangeValue here to avoid generating a wxEVT_TEXT event.
|
|
m_DPIValueX->ChangeValue( wxString::Format( wxT( "%d" ), m_imageDPI.x ) );
|
|
m_DPIValueY->ChangeValue( wxString::Format( wxT( "%d" ), m_imageDPI.y ) );
|
|
updateImageInfo();
|
|
|
|
m_InitialPicturePanel->SetVirtualSize( w, h );
|
|
m_GreyscalePicturePanel->SetVirtualSize( w, h );
|
|
m_BNPicturePanel->SetVirtualSize( w, h );
|
|
|
|
m_Greyscale_Image.Destroy();
|
|
m_Greyscale_Image = m_Pict_Image.ConvertToGreyscale( );
|
|
|
|
if( m_Pict_Bitmap.GetMask() )
|
|
{
|
|
for( int x = 0; x < m_Pict_Bitmap.GetWidth(); x++ )
|
|
{
|
|
for( int y = 0; y < m_Pict_Bitmap.GetHeight(); y++ )
|
|
{
|
|
if( m_Pict_Image.GetRed( x, y ) == m_Pict_Image.GetMaskRed() &&
|
|
m_Pict_Image.GetGreen( x, y ) == m_Pict_Image.GetMaskGreen() &&
|
|
m_Pict_Image.GetBlue( x, y ) == m_Pict_Image.GetMaskBlue() )
|
|
{
|
|
m_Greyscale_Image.SetRGB( x, y, 255, 255, 255 );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if( m_Negative )
|
|
NegateGreyscaleImage( );
|
|
|
|
m_Greyscale_Bitmap = wxBitmap( m_Greyscale_Image );
|
|
m_NB_Image = m_Greyscale_Image;
|
|
Binarize( (double) m_sliderThreshold->GetValue()/m_sliderThreshold->GetMax() );
|
|
|
|
m_buttonExportFile->Enable( true );
|
|
m_buttonExportClipboard->Enable( true );
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void BM2CMP_FRAME::updateImageInfo()
|
|
{
|
|
// Note: the image resolution text controls are not modified
|
|
// here, to avoid a race between text change when entered by user and
|
|
// a text change if it is modified here.
|
|
int h = m_Pict_Bitmap.GetHeight();
|
|
int w = m_Pict_Bitmap.GetWidth();
|
|
int nb = m_Pict_Bitmap.GetDepth();
|
|
|
|
m_SizeXValue->SetLabel( wxString::Format( wxT( "%d" ), w ) );
|
|
m_SizeYValue->SetLabel( wxString::Format( wxT( "%d" ), h ) );
|
|
m_BPPValue->SetLabel( wxString::Format( wxT( "%d" ), nb ) );
|
|
|
|
m_SizeXValue_mm->SetLabel( wxString::Format( wxT( "%.1f" ),
|
|
(double) w / m_imageDPI.x * 25.4 ) );
|
|
m_SizeYValue_mm->SetLabel( wxString::Format( wxT( "%.1f" ),
|
|
(double) h / m_imageDPI.y * 25.4 ) );
|
|
}
|
|
|
|
|
|
void BM2CMP_FRAME::OnResolutionChange( wxCommandEvent& event )
|
|
{
|
|
long tmp;
|
|
|
|
if( m_DPIValueX->GetValue().ToLong( &tmp ) )
|
|
m_imageDPI.x = tmp;
|
|
|
|
if( m_DPIValueY->GetValue().ToLong( &tmp ) )
|
|
m_imageDPI.y = tmp;
|
|
|
|
if( m_imageDPI.x < 32 )
|
|
m_imageDPI.x = 32;
|
|
|
|
if( m_imageDPI.y < 32 )
|
|
m_imageDPI.y = 32;
|
|
|
|
updateImageInfo();
|
|
}
|
|
|
|
|
|
void BM2CMP_FRAME::Binarize( double aThreshold )
|
|
{
|
|
int h = m_Greyscale_Image.GetHeight();
|
|
int w = m_Greyscale_Image.GetWidth();
|
|
unsigned char threshold = aThreshold * 255;
|
|
unsigned char alpha_thresh = 0.7 * threshold;
|
|
|
|
for( int y = 0; y < h; y++ )
|
|
for( int x = 0; x < w; x++ )
|
|
{
|
|
unsigned char pixout;
|
|
auto pixin = m_Greyscale_Image.GetGreen( x, y );
|
|
auto alpha = m_Greyscale_Image.HasAlpha() ?
|
|
m_Greyscale_Image.GetAlpha( x, y ) : wxALPHA_OPAQUE;
|
|
|
|
if( pixin < threshold || alpha < alpha_thresh )
|
|
pixout = 0;
|
|
else
|
|
pixout = 255;
|
|
|
|
m_NB_Image.SetRGB( x, y, pixout, pixout, pixout );
|
|
|
|
}
|
|
|
|
m_BN_Bitmap = wxBitmap( m_NB_Image );
|
|
|
|
}
|
|
|
|
|
|
void BM2CMP_FRAME::NegateGreyscaleImage( )
|
|
{
|
|
unsigned char pix;
|
|
int h = m_Greyscale_Image.GetHeight();
|
|
int w = m_Greyscale_Image.GetWidth();
|
|
|
|
for( int y = 0; y < h; y++ )
|
|
for( int x = 0; x < w; x++ )
|
|
{
|
|
pix = m_Greyscale_Image.GetGreen( x, y );
|
|
pix = ~pix;
|
|
m_Greyscale_Image.SetRGB( x, y, pix, pix, pix );
|
|
}
|
|
}
|
|
|
|
|
|
void BM2CMP_FRAME::OnNegativeClicked( wxCommandEvent& )
|
|
{
|
|
if( m_checkNegative->GetValue() != m_Negative )
|
|
{
|
|
NegateGreyscaleImage();
|
|
|
|
m_Greyscale_Bitmap = wxBitmap( m_Greyscale_Image );
|
|
Binarize( (double)m_sliderThreshold->GetValue()/m_sliderThreshold->GetMax() );
|
|
m_Negative = m_checkNegative->GetValue();
|
|
|
|
Refresh();
|
|
}
|
|
}
|
|
|
|
|
|
void BM2CMP_FRAME::OnThresholdChange( wxScrollEvent& event )
|
|
{
|
|
Binarize( (double)m_sliderThreshold->GetValue()/m_sliderThreshold->GetMax() );
|
|
Refresh();
|
|
}
|
|
|
|
|
|
void BM2CMP_FRAME::OnExportToFile( wxCommandEvent& event )
|
|
{
|
|
m_exportToClipboard = false;
|
|
// choices of m_radioBoxFormat are expected to be in same order as
|
|
// OUTPUT_FMT_ID. See bitmap2component.h
|
|
OUTPUT_FMT_ID format = (OUTPUT_FMT_ID) m_radioBoxFormat->GetSelection();
|
|
exportBitmap( format );
|
|
}
|
|
|
|
|
|
void BM2CMP_FRAME::OnExportToClipboard( wxCommandEvent& event )
|
|
{
|
|
m_exportToClipboard = true;
|
|
// choices of m_radioBoxFormat are expected to be in same order as
|
|
// OUTPUT_FMT_ID. See bitmap2component.h
|
|
OUTPUT_FMT_ID format = (OUTPUT_FMT_ID) m_radioBoxFormat->GetSelection();
|
|
|
|
std::string buffer;
|
|
ExportToBuffer( buffer, format );
|
|
|
|
// Write buffer to the clipboard
|
|
if (wxTheClipboard->Open())
|
|
{
|
|
// This data objects are held by the clipboard,
|
|
// so do not delete them in the app.
|
|
wxTheClipboard->SetData( new wxTextDataObject( buffer.c_str() ) );
|
|
wxTheClipboard->Close();
|
|
}
|
|
else
|
|
wxMessageBox( _( " Unable to export to the Clipboard") );
|
|
}
|
|
|
|
|
|
void BM2CMP_FRAME::exportBitmap( OUTPUT_FMT_ID aFormat )
|
|
{
|
|
switch( aFormat )
|
|
{
|
|
case EESCHEMA_FMT:
|
|
exportEeschemaFormat();
|
|
break;
|
|
|
|
case PCBNEW_KICAD_MOD:
|
|
exportPcbnewFormat();
|
|
break;
|
|
|
|
case POSTSCRIPT_FMT:
|
|
exportPostScriptFormat();
|
|
break;
|
|
|
|
case KICAD_LOGO:
|
|
OnExportLogo();
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void BM2CMP_FRAME::OnExportLogo()
|
|
{
|
|
wxFileName fn( m_ConvertedFileName );
|
|
wxString path = fn.GetPath();
|
|
|
|
if( path.IsEmpty() || !wxDirExists(path) )
|
|
path = ::wxGetCwd();
|
|
|
|
wxFileDialog fileDlg( this, _( "Create Logo File" ), path, wxEmptyString,
|
|
PageLayoutDescrFileWildcard(),
|
|
wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
|
|
int diag = fileDlg.ShowModal();
|
|
|
|
if( diag != wxID_OK )
|
|
return;
|
|
|
|
fn = fileDlg.GetPath();
|
|
fn.SetExt( PageLayoutDescrFileExtension );
|
|
m_ConvertedFileName = fn.GetFullPath();
|
|
|
|
FILE* outfile;
|
|
outfile = wxFopen( m_ConvertedFileName, wxT( "w" ) );
|
|
|
|
if( outfile == NULL )
|
|
{
|
|
wxString msg;
|
|
msg.Printf( _( "File \"%s\" could not be created." ), GetChars( m_ConvertedFileName ) );
|
|
wxMessageBox( msg );
|
|
return;
|
|
}
|
|
|
|
std::string buffer;
|
|
ExportToBuffer( buffer, KICAD_LOGO );
|
|
fputs( buffer.c_str(), outfile );
|
|
fclose( outfile );
|
|
}
|
|
|
|
|
|
void BM2CMP_FRAME::exportPostScriptFormat()
|
|
{
|
|
wxFileName fn( m_ConvertedFileName );
|
|
wxString path = fn.GetPath();
|
|
|
|
if( path.IsEmpty() || !wxDirExists( path ) )
|
|
path = ::wxGetCwd();
|
|
|
|
wxFileDialog fileDlg( this, _( "Create Postscript File" ),
|
|
path, wxEmptyString,
|
|
PSFileWildcard(),
|
|
wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
|
|
|
|
int diag = fileDlg.ShowModal();
|
|
|
|
if( diag != wxID_OK )
|
|
return;
|
|
|
|
fn = fileDlg.GetPath();
|
|
fn.SetExt( wxT( "ps" ) );
|
|
m_ConvertedFileName = fn.GetFullPath();
|
|
|
|
FILE* outfile;
|
|
outfile = wxFopen( m_ConvertedFileName, wxT( "w" ) );
|
|
|
|
if( outfile == NULL )
|
|
{
|
|
wxString msg;
|
|
msg.Printf( _( "File \"%s\" could not be created." ), GetChars( m_ConvertedFileName ) );
|
|
wxMessageBox( msg );
|
|
return;
|
|
}
|
|
|
|
std::string buffer;
|
|
ExportToBuffer( buffer, POSTSCRIPT_FMT );
|
|
fputs( buffer.c_str(), outfile );
|
|
fclose( outfile );
|
|
}
|
|
|
|
|
|
void BM2CMP_FRAME::exportEeschemaFormat()
|
|
{
|
|
wxFileName fn( m_ConvertedFileName );
|
|
wxString path = fn.GetPath();
|
|
|
|
if( path.IsEmpty() || !wxDirExists(path) )
|
|
path = ::wxGetCwd();
|
|
|
|
wxFileDialog fileDlg( this, _( "Create Symbol Library" ),
|
|
path, wxEmptyString,
|
|
SchematicLibraryFileWildcard(),
|
|
wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
|
|
|
|
int diag = fileDlg.ShowModal();
|
|
|
|
if( diag != wxID_OK )
|
|
return;
|
|
|
|
fn = fileDlg.GetPath();
|
|
fn.SetExt( SchematicLibraryFileExtension );
|
|
m_ConvertedFileName = fn.GetFullPath();
|
|
|
|
FILE* outfile = wxFopen( m_ConvertedFileName, wxT( "w" ) );
|
|
|
|
if( outfile == NULL )
|
|
{
|
|
wxString msg;
|
|
msg.Printf( _( "File \"%s\" could not be created." ), GetChars( m_ConvertedFileName ) );
|
|
wxMessageBox( msg );
|
|
return;
|
|
}
|
|
|
|
std::string buffer;
|
|
ExportToBuffer( buffer, EESCHEMA_FMT );
|
|
fputs( buffer.c_str(), outfile );
|
|
fclose( outfile );
|
|
}
|
|
|
|
|
|
void BM2CMP_FRAME::exportPcbnewFormat()
|
|
{
|
|
wxFileName fn( m_ConvertedFileName );
|
|
wxString path = fn.GetPath();
|
|
|
|
if( path.IsEmpty() || !wxDirExists( path ) )
|
|
path = m_mruPath;
|
|
|
|
wxFileDialog fileDlg( this, _( "Create Footprint Library" ),
|
|
path, wxEmptyString,
|
|
KiCadFootprintLibFileWildcard(),
|
|
wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
|
|
|
|
int diag = fileDlg.ShowModal();
|
|
|
|
if( diag != wxID_OK )
|
|
return;
|
|
|
|
fn = fileDlg.GetPath();
|
|
fn.SetExt( KiCadFootprintFileExtension );
|
|
m_ConvertedFileName = fn.GetFullPath();
|
|
|
|
FILE* outfile = wxFopen( m_ConvertedFileName, wxT( "w" ) );
|
|
|
|
if( outfile == NULL )
|
|
{
|
|
wxString msg;
|
|
msg.Printf( _( "File \"%s\" could not be created." ), GetChars( m_ConvertedFileName ) );
|
|
wxMessageBox( msg );
|
|
return;
|
|
}
|
|
|
|
std::string buffer;
|
|
ExportToBuffer( buffer, PCBNEW_KICAD_MOD );
|
|
fputs( buffer.c_str(), outfile );
|
|
fclose( outfile );
|
|
m_mruPath = fn.GetPath();
|
|
}
|
|
|
|
|
|
void BM2CMP_FRAME::ExportToBuffer( std::string& aOutput, OUTPUT_FMT_ID aFormat )
|
|
{
|
|
// Create a potrace bitmap
|
|
int h = m_NB_Image.GetHeight();
|
|
int w = m_NB_Image.GetWidth();
|
|
potrace_bitmap_t* potrace_bitmap = bm_new( w, h );
|
|
|
|
if( !potrace_bitmap )
|
|
{
|
|
wxString msg;
|
|
msg.Printf( _( "Error allocating memory for potrace bitmap" ) );
|
|
wxMessageBox( msg );
|
|
return;
|
|
}
|
|
|
|
/* fill the bitmap with data */
|
|
for( int y = 0; y < h; y++ )
|
|
{
|
|
for( int x = 0; x < w; x++ )
|
|
{
|
|
auto pix = m_NB_Image.GetGreen( x, y );
|
|
BM_PUT( potrace_bitmap, x, y, pix ? 0 : 1 );
|
|
}
|
|
}
|
|
|
|
// choices of m_radio_PCBLayer are expected to be in same order as
|
|
// BMP2CMP_MOD_LAYER. See bitmap2component.h
|
|
BMP2CMP_MOD_LAYER modLayer = MOD_LYR_FSILKS;
|
|
|
|
if( aFormat == PCBNEW_KICAD_MOD )
|
|
modLayer = (BMP2CMP_MOD_LAYER) m_radio_PCBLayer->GetSelection();
|
|
|
|
BITMAPCONV_INFO converter( aOutput );
|
|
converter.ConvertBitmap( potrace_bitmap, aFormat, m_imageDPI.x, m_imageDPI.y, modLayer );
|
|
}
|
|
|
|
|
|
|
|
//-----<KIFACE>-----------------------------------------------------------------
|
|
|
|
namespace BMP2CMP {
|
|
|
|
static struct IFACE : public KIFACE_I
|
|
{
|
|
bool OnKifaceStart( PGM_BASE* aProgram, int aCtlBits ) override;
|
|
|
|
wxWindow* CreateWindow( wxWindow* aParent, int aClassId, KIWAY* aKiway, int aCtlBits = 0 ) override
|
|
{
|
|
return new BM2CMP_FRAME( aKiway, aParent );
|
|
}
|
|
|
|
/**
|
|
* Function IfaceOrAddress
|
|
* return a pointer to the requested object. The safest way to use this
|
|
* is to retrieve a pointer to a static instance of an interface, similar to
|
|
* how the KIFACE interface is exported. But if you know what you are doing
|
|
* use it to retrieve anything you want.
|
|
*
|
|
* @param aDataId identifies which object you want the address of.
|
|
*
|
|
* @return void* - and must be cast into the know type.
|
|
*/
|
|
void* IfaceOrAddress( int aDataId ) override
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
IFACE( const char* aDSOname, KIWAY::FACE_T aType ) :
|
|
KIFACE_I( aDSOname, aType )
|
|
{}
|
|
|
|
} kiface( "BMP2CMP", KIWAY::FACE_BMP2CMP );
|
|
|
|
} // namespace BMP2CMP
|
|
|
|
using namespace BMP2CMP;
|
|
|
|
static PGM_BASE* process;
|
|
|
|
KIFACE_I& Kiface()
|
|
{
|
|
return kiface;
|
|
}
|
|
|
|
|
|
// KIFACE_GETTER's actual spelling is a substitution macro found in kiway.h.
|
|
// KIFACE_GETTER will not have name mangling due to declaration in kiway.h.
|
|
KIFACE* KIFACE_GETTER( int* aKIFACEversion, int aKIWAYversion, PGM_BASE* aProgram )
|
|
{
|
|
process = (PGM_BASE*) aProgram;
|
|
return &kiface;
|
|
}
|
|
|
|
|
|
#if defined(BUILD_KIWAY_DLLS)
|
|
PGM_BASE& Pgm()
|
|
{
|
|
wxASSERT( process ); // KIFACE_GETTER has already been called.
|
|
return *process;
|
|
}
|
|
#endif
|
|
|
|
|
|
bool IFACE::OnKifaceStart( PGM_BASE* aProgram, int aCtlBits )
|
|
{
|
|
return start_common( aCtlBits );
|
|
}
|
|
|
|
|
|
void BM2CMP_FRAME::OnFormatChange( wxCommandEvent& event )
|
|
{
|
|
if( m_radioBoxFormat->GetSelection() == PCBNEW_KICAD_MOD )
|
|
m_radio_PCBLayer->Enable( true );
|
|
else
|
|
m_radio_PCBLayer->Enable( false );
|
|
|
|
event.Skip();
|
|
}
|