554 lines
15 KiB
C++
554 lines
15 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-2010 Kicad Developers, see change_log.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 <appl_wxstruct.h>
|
|
#include <wxstruct.h>
|
|
#include <confirm.h>
|
|
#include <gestfich.h>
|
|
|
|
#include <wx/wx.h>
|
|
#include <wx/config.h>
|
|
#include <wx/filename.h>
|
|
|
|
#include <bitmap2cmp_gui_base.h>
|
|
|
|
#include <potracelib.h>
|
|
#include <bitmap_io.h>
|
|
|
|
#include <colors_selection.h>
|
|
#include <build_version.h>
|
|
#include <menus_helpers.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_BINARY_THRESHOLD wxT( "Threshold" )
|
|
#define KEYWORD_BW_NEGATIVE wxT( "Negative_choice" )
|
|
|
|
extern int bitmap2component( potrace_bitmap_t* aPotrace_bitmap, FILE* aOutfile, int aFormat );
|
|
|
|
/* Class BM2CMP_FRAME_BASE
|
|
This 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;
|
|
wxString m_BitmapFileName;
|
|
wxString m_ConvertedFileName;
|
|
wxSize m_FrameSize;
|
|
wxPoint m_FramePos;
|
|
wxConfig * m_Config;
|
|
|
|
public:
|
|
BM2CMP_FRAME();
|
|
~BM2CMP_FRAME();
|
|
|
|
private:
|
|
|
|
// Event handlers
|
|
void OnPaint( wxPaintEvent& event );
|
|
void OnLoadFile( wxCommandEvent& event );
|
|
bool LoadFile( wxString& aFullFileName );
|
|
void OnExport( wxCommandEvent& event );
|
|
|
|
/**
|
|
* Generate a schematic library which comtains one component:
|
|
* the logo
|
|
*/
|
|
void OnExportEeschema();
|
|
|
|
/**
|
|
* Depending on the option:
|
|
* Legacy format: generate a module library which comtains one component
|
|
* New kicad_mod format: generate a module in S expr format
|
|
*/
|
|
void OnExportPcbnew( bool aLegacyFormat );
|
|
|
|
/**
|
|
* Generate a postscript file
|
|
*/
|
|
void OnExportPostScript();
|
|
|
|
/**
|
|
* 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 OnOptionsSelection( wxCommandEvent& event );
|
|
void OnThresholdChange( wxScrollEvent& event );
|
|
void NegateGreyscaleImage( );
|
|
void ExportFile( FILE* aOutfile, int aFormat );
|
|
};
|
|
|
|
|
|
BM2CMP_FRAME::BM2CMP_FRAME() : BM2CMP_FRAME_BASE( NULL )
|
|
{
|
|
int tmp;
|
|
m_Config = new wxConfig();
|
|
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 );
|
|
if( m_Config->Read( KEYWORD_BW_NEGATIVE, &tmp ) )
|
|
m_rbOptions->SetSelection( tmp ? 1 : 0 );
|
|
|
|
m_Config->Read( KEYWORD_LAST_FORMAT, &tmp );
|
|
m_radioBoxFormat->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_buttonExport->Enable( false );
|
|
|
|
if ( m_FramePos == wxDefaultPosition )
|
|
Centre();
|
|
}
|
|
|
|
|
|
BM2CMP_FRAME::~BM2CMP_FRAME()
|
|
{
|
|
if( ( m_Config == NULL ) || 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_rbOptions->GetSelection() );
|
|
m_Config->Write( KEYWORD_LAST_FORMAT, m_radioBoxFormat->GetSelection() );
|
|
|
|
delete m_Config;
|
|
|
|
/* This needed for OSX: avoids further OnDraw processing after this
|
|
* destructor and before the native window is destroyed
|
|
*/
|
|
this->Freeze( );
|
|
}
|
|
|
|
|
|
void BM2CMP_FRAME::OnPaint( wxPaintEvent& event )
|
|
{
|
|
#ifdef __WXMAC__
|
|
// Otherwise fails due: using wxPaintDC without being in a native paint event
|
|
wxClientDC pict_dc( m_InitialPicturePanel );
|
|
wxClientDC greyscale_dc( m_GreyscalePicturePanel );
|
|
wxClientDC nb_dc( m_BNPicturePanel );
|
|
#else
|
|
wxPaintDC pict_dc( m_InitialPicturePanel );
|
|
wxPaintDC greyscale_dc( m_GreyscalePicturePanel );
|
|
wxPaintDC nb_dc( m_BNPicturePanel );
|
|
#endif
|
|
|
|
m_InitialPicturePanel->PrepareDC( pict_dc );
|
|
m_GreyscalePicturePanel->PrepareDC( greyscale_dc );
|
|
m_BNPicturePanel->PrepareDC( nb_dc );
|
|
|
|
// OSX crashes with empty bitmaps (on initial refreshes)
|
|
if(m_Pict_Bitmap.IsOk() && m_Greyscale_Bitmap.IsOk() && m_BN_Bitmap.IsOk())
|
|
{
|
|
pict_dc.DrawBitmap( m_Pict_Bitmap, 0, 0, false );
|
|
greyscale_dc.DrawBitmap( m_Greyscale_Bitmap, 0, 0, false );
|
|
nb_dc.DrawBitmap( m_BN_Bitmap, 0, 0, false );
|
|
}
|
|
}
|
|
|
|
|
|
/* Called to load a bitmap file
|
|
*/
|
|
void BM2CMP_FRAME::OnLoadFile( wxCommandEvent& event )
|
|
{
|
|
wxFileName fn(m_BitmapFileName);
|
|
wxString path = fn.GetPath();
|
|
|
|
if( path.IsEmpty() || !wxDirExists(path) )
|
|
path = wxGetCwd();
|
|
|
|
wxFileDialog FileDlg( this, _( "Choose Image" ), path, wxEmptyString,
|
|
_( "Image Files " ) + wxImage::GetImageExtWildcard(),
|
|
wxFD_OPEN );
|
|
int diag = FileDlg.ShowModal();
|
|
|
|
if( diag != wxID_OK )
|
|
return;
|
|
|
|
wxString fullFilename = FileDlg.GetPath();
|
|
|
|
if( ! LoadFile( fullFilename ) )
|
|
return;
|
|
|
|
m_buttonExport->Enable( true );
|
|
SetStatusText( fullFilename );
|
|
Refresh();
|
|
}
|
|
|
|
|
|
bool BM2CMP_FRAME::LoadFile( wxString& aFullFileName )
|
|
{
|
|
m_BitmapFileName = aFullFileName;
|
|
|
|
if( !m_Pict_Image.LoadFile( m_BitmapFileName ) )
|
|
{
|
|
wxMessageBox( _( "Couldn't load image from <%s>" ), m_BitmapFileName.c_str() );
|
|
return false;
|
|
}
|
|
|
|
m_Pict_Bitmap = wxBitmap( m_Pict_Image );
|
|
|
|
int h = m_Pict_Bitmap.GetHeight();
|
|
int w = m_Pict_Bitmap.GetWidth();
|
|
int nb = m_Pict_Bitmap.GetDepth();
|
|
|
|
wxString msg;
|
|
msg.Printf( wxT( "%d" ), w );
|
|
m_SizeXValue->SetLabel(msg);
|
|
msg.Printf( wxT( "%d" ), h );
|
|
m_SizeYValue->SetLabel(msg);
|
|
msg.Printf( wxT( "%d" ), nb );
|
|
m_BPPValue->SetLabel(msg);
|
|
|
|
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_rbOptions->GetSelection() > 0 )
|
|
NegateGreyscaleImage( );
|
|
m_Greyscale_Bitmap = wxBitmap( m_Greyscale_Image );
|
|
|
|
m_NB_Image = m_Greyscale_Image;
|
|
Binarize( (double)m_sliderThreshold->GetValue()/m_sliderThreshold->GetMax() );
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void BM2CMP_FRAME::Binarize( double aThreshold )
|
|
{
|
|
unsigned int pixin;
|
|
unsigned char pixout;
|
|
int h = m_Greyscale_Image.GetHeight();
|
|
int w = m_Greyscale_Image.GetWidth();
|
|
unsigned int threshold = (int)(aThreshold * 256);
|
|
|
|
for( int y = 0; y < h; y++ )
|
|
for( int x = 0; x < w; x++ )
|
|
{
|
|
pixin = m_Greyscale_Image.GetGreen( x, y );
|
|
|
|
if( pixin < threshold )
|
|
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 );
|
|
}
|
|
}
|
|
|
|
/* Called on Normal/Negative change option */
|
|
void BM2CMP_FRAME::OnOptionsSelection( wxCommandEvent& event )
|
|
{
|
|
NegateGreyscaleImage( );
|
|
m_Greyscale_Bitmap = wxBitmap( m_Greyscale_Image );
|
|
Binarize( (double)m_sliderThreshold->GetValue()/m_sliderThreshold->GetMax() );
|
|
Refresh();
|
|
}
|
|
|
|
void BM2CMP_FRAME::OnThresholdChange( wxScrollEvent& event )
|
|
{
|
|
Binarize( (double)m_sliderThreshold->GetValue()/m_sliderThreshold->GetMax() );
|
|
Refresh();
|
|
}
|
|
|
|
void BM2CMP_FRAME::OnExport( wxCommandEvent& event )
|
|
{
|
|
int sel = m_radioBoxFormat->GetSelection();
|
|
|
|
switch( sel )
|
|
{
|
|
case 0:
|
|
OnExportEeschema();
|
|
break;
|
|
|
|
case 1:
|
|
OnExportPcbnew( true );
|
|
break;
|
|
|
|
case 2:
|
|
OnExportPcbnew( false );
|
|
break;
|
|
|
|
case 3:
|
|
OnExportPostScript();
|
|
break;
|
|
|
|
case 4:
|
|
OnExportLogo();
|
|
break;
|
|
}
|
|
}
|
|
|
|
void BM2CMP_FRAME::OnExportLogo()
|
|
{
|
|
wxFileName fn(m_ConvertedFileName);
|
|
wxString path = fn.GetPath();
|
|
|
|
if( path.IsEmpty() || !wxDirExists(path) )
|
|
path = ::wxGetCwd();
|
|
|
|
wxString msg = _( "Logo file (*.kicad_wks)|*.kicad_wks" );
|
|
wxFileDialog FileDlg( this, _( "Create a logo file" ), path, wxEmptyString,
|
|
msg,
|
|
wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
|
|
int diag = FileDlg.ShowModal();
|
|
|
|
if( diag != wxID_OK )
|
|
return;
|
|
|
|
m_ConvertedFileName = FileDlg.GetPath();
|
|
|
|
FILE* outfile;
|
|
outfile = wxFopen( m_ConvertedFileName, wxT( "w" ) );
|
|
|
|
if( outfile == NULL )
|
|
{
|
|
wxString msg;
|
|
msg.Printf( _( "File %s could not be created" ), m_ConvertedFileName.c_str() );
|
|
wxMessageBox( msg );
|
|
return;
|
|
}
|
|
|
|
ExportFile( outfile, 4 );
|
|
fclose( outfile );
|
|
}
|
|
|
|
void BM2CMP_FRAME::OnExportPostScript()
|
|
{
|
|
wxFileName fn(m_ConvertedFileName);
|
|
wxString path = fn.GetPath();
|
|
|
|
if( path.IsEmpty() || !wxDirExists(path) )
|
|
path = ::wxGetCwd();
|
|
|
|
wxString msg = _( "Postscript file (*.ps)|*.ps" );
|
|
wxFileDialog FileDlg( this, _( "Create a Postscript file" ), path, wxEmptyString,
|
|
msg,
|
|
wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
|
|
int diag = FileDlg.ShowModal();
|
|
|
|
if( diag != wxID_OK )
|
|
return;
|
|
|
|
m_ConvertedFileName = FileDlg.GetPath();
|
|
|
|
FILE* outfile;
|
|
outfile = wxFopen( m_ConvertedFileName, wxT( "w" ) );
|
|
|
|
if( outfile == NULL )
|
|
{
|
|
wxString msg;
|
|
msg.Printf( _( "File %s could not be created" ), m_ConvertedFileName.c_str() );
|
|
wxMessageBox( msg );
|
|
return;
|
|
}
|
|
|
|
ExportFile( outfile, 3 );
|
|
fclose( outfile );
|
|
}
|
|
|
|
void BM2CMP_FRAME::OnExportEeschema()
|
|
{
|
|
wxFileName fn(m_ConvertedFileName);
|
|
wxString path = fn.GetPath();
|
|
|
|
if( path.IsEmpty() || !wxDirExists(path) )
|
|
path = ::wxGetCwd();
|
|
|
|
wxString msg = _( "Schematic lib file (*.lib)|*.lib" );
|
|
wxFileDialog FileDlg( this, _( "Create a lib file for Eeschema" ), path, wxEmptyString,
|
|
msg,
|
|
wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
|
|
int diag = FileDlg.ShowModal();
|
|
|
|
if( diag != wxID_OK )
|
|
return;
|
|
|
|
m_ConvertedFileName = FileDlg.GetPath();
|
|
|
|
FILE* outfile;
|
|
outfile = wxFopen( m_ConvertedFileName, wxT( "w" ) );
|
|
|
|
if( outfile == NULL )
|
|
{
|
|
wxString msg;
|
|
msg.Printf( _( "File %s could not be created" ), m_ConvertedFileName.c_str() );
|
|
wxMessageBox( msg );
|
|
return;
|
|
}
|
|
|
|
ExportFile( outfile, 2 );
|
|
fclose( outfile );
|
|
}
|
|
|
|
|
|
void BM2CMP_FRAME::OnExportPcbnew( bool aLegacyFormat )
|
|
{
|
|
wxFileName fn(m_ConvertedFileName);
|
|
wxString path = fn.GetPath();
|
|
|
|
if( path.IsEmpty() || !wxDirExists(path) )
|
|
path = ::wxGetCwd();
|
|
|
|
wxString msg = aLegacyFormat ?
|
|
_( "Footprint file (*.emp)|*.emp" ) :
|
|
_( "Footprint file (*.kicad_mod)|*.kicad_mod" );
|
|
wxFileDialog FileDlg( this, _( "Create a footprint file for PcbNew" ),
|
|
path, wxEmptyString,
|
|
msg,
|
|
wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
|
|
int diag = FileDlg.ShowModal();
|
|
|
|
if( diag != wxID_OK )
|
|
return;
|
|
|
|
m_ConvertedFileName = FileDlg.GetPath();
|
|
|
|
|
|
FILE* outfile;
|
|
outfile = wxFopen( m_ConvertedFileName, wxT( "w" ) );
|
|
|
|
if( outfile == NULL )
|
|
{
|
|
wxString msg;
|
|
msg.Printf( _( "File %s could not be created" ), m_ConvertedFileName.c_str() );
|
|
wxMessageBox( msg );
|
|
return;
|
|
}
|
|
|
|
ExportFile( outfile, aLegacyFormat ? 0 : 1 );
|
|
fclose( outfile );
|
|
}
|
|
|
|
void BM2CMP_FRAME::ExportFile( FILE* aOutfile, int 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( wxT( "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++ )
|
|
{
|
|
unsigned char pix = m_NB_Image.GetGreen( x, y );
|
|
BM_PUT( potrace_bitmap, x, y, pix ? 1 : 0 );
|
|
}
|
|
}
|
|
|
|
bitmap2component( potrace_bitmap, aOutfile, aFormat );
|
|
}
|
|
|
|
|
|
// EDA_APP
|
|
|
|
IMPLEMENT_APP( EDA_APP )
|
|
|
|
///-----------------------------------------------------------------------------
|
|
// EDA_APP
|
|
// main program
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool EDA_APP::OnInit()
|
|
{
|
|
wxInitAllImageHandlers();
|
|
|
|
InitEDA_Appl( wxT( "BMP2CMP" ) );
|
|
|
|
wxFrame* frame = new BM2CMP_FRAME();
|
|
SetTopWindow( frame );
|
|
frame->Show( true );
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void EDA_APP::MacOpenFile( const wxString& aFileName )
|
|
{
|
|
}
|