Allow multiple format image saving
- Keep original image data. When loading JPEG, this avoid recompression that changes file data and decreases image quality - Allow schematic and page layout editors to store non-PNG data as well - Move page layout editor to store base64 instead of hex-coded data
This commit is contained in:
parent
0e382669d0
commit
f9b745f3d2
|
@ -30,6 +30,10 @@
|
||||||
#include <richio.h>
|
#include <richio.h>
|
||||||
#include <wx/bitmap.h> // for wxBitmap
|
#include <wx/bitmap.h> // for wxBitmap
|
||||||
#include <wx/mstream.h>
|
#include <wx/mstream.h>
|
||||||
|
#include <wx/stream.h> // for wxInputStream, wxOutputStream
|
||||||
|
#include <wx/string.h> // for wxString
|
||||||
|
#include <wx/wfstream.h> // for wxFileInputStream
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
BITMAP_BASE::BITMAP_BASE( const VECTOR2I& pos )
|
BITMAP_BASE::BITMAP_BASE( const VECTOR2I& pos )
|
||||||
|
@ -65,22 +69,13 @@ BITMAP_BASE::BITMAP_BASE( const BITMAP_BASE& aSchBitmap )
|
||||||
m_image = new wxImage( *aSchBitmap.m_image );
|
m_image = new wxImage( *aSchBitmap.m_image );
|
||||||
m_bitmap = new wxBitmap( *m_image );
|
m_bitmap = new wxBitmap( *m_image );
|
||||||
m_originalImage = new wxImage( *aSchBitmap.m_originalImage );
|
m_originalImage = new wxImage( *aSchBitmap.m_originalImage );
|
||||||
|
m_imageType = aSchBitmap.m_imageType;
|
||||||
|
m_imageData = aSchBitmap.m_imageData;
|
||||||
m_imageId = aSchBitmap.m_imageId;
|
m_imageId = aSchBitmap.m_imageId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void BITMAP_BASE::SetImage( wxImage* aImage )
|
|
||||||
{
|
|
||||||
delete m_image;
|
|
||||||
m_image = aImage;
|
|
||||||
delete m_originalImage;
|
|
||||||
m_originalImage = new wxImage( *aImage );
|
|
||||||
rebuildBitmap();
|
|
||||||
updatePPI();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void BITMAP_BASE::rebuildBitmap( bool aResetID )
|
void BITMAP_BASE::rebuildBitmap( bool aResetID )
|
||||||
{
|
{
|
||||||
if( m_bitmap )
|
if( m_bitmap )
|
||||||
|
@ -90,6 +85,7 @@ void BITMAP_BASE::rebuildBitmap( bool aResetID )
|
||||||
|
|
||||||
if( aResetID )
|
if( aResetID )
|
||||||
m_imageId = KIID();
|
m_imageId = KIID();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -120,42 +116,34 @@ void BITMAP_BASE::ImportData( BITMAP_BASE* aItem )
|
||||||
m_isMirroredX = aItem->m_isMirroredX;
|
m_isMirroredX = aItem->m_isMirroredX;
|
||||||
m_isMirroredY = aItem->m_isMirroredY;
|
m_isMirroredY = aItem->m_isMirroredY;
|
||||||
m_rotation = aItem->m_rotation;
|
m_rotation = aItem->m_rotation;
|
||||||
|
m_imageType = aItem->m_imageType;
|
||||||
|
m_imageData = aItem->m_imageData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool BITMAP_BASE::ReadImageFile( wxInputStream& aInStream )
|
bool BITMAP_BASE::ReadImageFile( wxInputStream& aInStream )
|
||||||
{
|
{
|
||||||
|
// Store the original image data in m_imageData
|
||||||
|
size_t dataSize = aInStream.GetLength();
|
||||||
|
m_imageData.SetBufSize( dataSize );
|
||||||
|
aInStream.Read( m_imageData.GetData(), dataSize );
|
||||||
|
m_imageData.SetDataLen( dataSize );
|
||||||
|
|
||||||
std::unique_ptr<wxImage> new_image = std::make_unique<wxImage>();
|
std::unique_ptr<wxImage> new_image = std::make_unique<wxImage>();
|
||||||
|
|
||||||
if( !new_image->LoadFile( aInStream ) )
|
// Load the image from the stream into new_image
|
||||||
|
wxMemoryInputStream mem_stream( m_imageData.GetData(), dataSize );
|
||||||
|
if( !new_image->LoadFile( mem_stream ) )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
delete m_image;
|
delete m_image;
|
||||||
m_image = new_image.release();
|
|
||||||
delete m_originalImage;
|
|
||||||
m_originalImage = new wxImage( *m_image );
|
|
||||||
rebuildBitmap();
|
|
||||||
updatePPI();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool BITMAP_BASE::ReadImageFile( const wxString& aFullFilename )
|
|
||||||
{
|
|
||||||
wxImage* new_image = new wxImage();
|
|
||||||
|
|
||||||
if( !new_image->LoadFile( aFullFilename ) )
|
|
||||||
{
|
|
||||||
delete new_image;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_imageType = new_image->GetType();
|
m_imageType = new_image->GetType();
|
||||||
delete m_image;
|
m_image = new_image.release();
|
||||||
m_image = new_image;
|
|
||||||
|
// Create a new wxImage object from m_image
|
||||||
delete m_originalImage;
|
delete m_originalImage;
|
||||||
m_originalImage = new wxImage( *m_image );
|
m_originalImage = new wxImage( *m_image );
|
||||||
|
|
||||||
rebuildBitmap();
|
rebuildBitmap();
|
||||||
updatePPI();
|
updatePPI();
|
||||||
|
|
||||||
|
@ -163,78 +151,69 @@ bool BITMAP_BASE::ReadImageFile( const wxString& aFullFilename )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool BITMAP_BASE::SaveData( FILE* aFile ) const
|
bool BITMAP_BASE::ReadImageFile( wxMemoryBuffer& aBuf )
|
||||||
{
|
{
|
||||||
if( m_image )
|
// Store the original image data in m_imageData
|
||||||
|
m_imageData = aBuf;
|
||||||
|
|
||||||
|
std::unique_ptr<wxImage> new_image = std::make_unique<wxImage>();
|
||||||
|
|
||||||
|
// Load the image from the buffer into new_image
|
||||||
|
wxMemoryInputStream mem_stream( m_imageData.GetData(), m_imageData.GetBufSize() );
|
||||||
|
|
||||||
|
if( !new_image->LoadFile( mem_stream ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
delete m_image;
|
||||||
|
m_imageType = new_image->GetType();
|
||||||
|
m_image = new_image.release();
|
||||||
|
|
||||||
|
// Create a new wxImage object from m_image
|
||||||
|
delete m_originalImage;
|
||||||
|
m_originalImage = new wxImage( *m_image );
|
||||||
|
|
||||||
|
rebuildBitmap();
|
||||||
|
updatePPI();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool BITMAP_BASE::ReadImageFile(const wxString& aFullFilename)
|
||||||
|
{
|
||||||
|
wxFileInputStream file_stream(aFullFilename);
|
||||||
|
|
||||||
|
// Check if the file could be opened successfully
|
||||||
|
if (!file_stream.IsOk())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return ReadImageFile(file_stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool BITMAP_BASE::SaveImageData( wxOutputStream& aOutStream ) const
|
||||||
|
{
|
||||||
|
if( m_imageData.IsEmpty() )
|
||||||
{
|
{
|
||||||
wxMemoryOutputStream stream;
|
// If m_imageData is empty, use wxImage::Save() method to write m_image contents to the stream.
|
||||||
|
wxBitmapType type = m_imageType == wxBITMAP_TYPE_JPEG ? wxBITMAP_TYPE_JPEG : wxBITMAP_TYPE_PNG;
|
||||||
|
|
||||||
if( m_imageType == wxBITMAP_TYPE_JPEG )
|
if( !m_image->SaveFile( aOutStream, type ) )
|
||||||
m_image->SaveFile( stream, wxBITMAP_TYPE_JPEG );
|
|
||||||
else
|
|
||||||
// Save as PNG (default
|
|
||||||
m_image->SaveFile( stream, wxBITMAP_TYPE_PNG );
|
|
||||||
|
|
||||||
// Write binary data in hexadecimal form (ASCII)
|
|
||||||
wxStreamBuffer* buffer = stream.GetOutputStreamBuffer();
|
|
||||||
char* begin = (char*) buffer->GetBufferStart();
|
|
||||||
|
|
||||||
for( int ii = 0; begin < buffer->GetBufferEnd(); begin++, ii++ )
|
|
||||||
{
|
{
|
||||||
if( ii >= 32 )
|
return false;
|
||||||
{
|
|
||||||
ii = 0;
|
|
||||||
|
|
||||||
if( fprintf( aFile, "\n" ) == EOF )
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( fprintf( aFile, "%2.2X ", *begin & 0xFF ) == EOF )
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Write the contents of m_imageData to the stream.
|
||||||
|
aOutStream.Write( m_imageData.GetData(), m_imageData.GetBufSize() );
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void BITMAP_BASE::SaveData( wxArrayString& aPngStrings ) const
|
bool BITMAP_BASE::LoadLegacyData( LINE_READER& aLine, wxString& aErrorMsg )
|
||||||
{
|
|
||||||
if( m_image )
|
|
||||||
{
|
|
||||||
wxMemoryOutputStream stream;
|
|
||||||
|
|
||||||
if( m_imageType == wxBITMAP_TYPE_JPEG )
|
|
||||||
m_image->SaveFile( stream, wxBITMAP_TYPE_JPEG );
|
|
||||||
else
|
|
||||||
// Save as PNG (default
|
|
||||||
m_image->SaveFile( stream, wxBITMAP_TYPE_PNG );
|
|
||||||
|
|
||||||
// Write binary data in hexadecimal form (ASCII)
|
|
||||||
wxStreamBuffer* buffer = stream.GetOutputStreamBuffer();
|
|
||||||
char* begin = (char*) buffer->GetBufferStart();
|
|
||||||
wxString line;
|
|
||||||
|
|
||||||
for( int ii = 0; begin < buffer->GetBufferEnd(); begin++, ii++ )
|
|
||||||
{
|
|
||||||
if( ii >= 32 )
|
|
||||||
{
|
|
||||||
ii = 0;
|
|
||||||
aPngStrings.Add( line );
|
|
||||||
line.Empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
line << wxString::Format( wxT( "%2.2X " ), *begin & 0xFF );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add last line:
|
|
||||||
if( !line.IsEmpty() )
|
|
||||||
aPngStrings.Add( line );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool BITMAP_BASE::LoadData( LINE_READER& aLine, wxString& aErrorMsg )
|
|
||||||
{
|
{
|
||||||
wxMemoryOutputStream stream;
|
wxMemoryOutputStream stream;
|
||||||
char* line;
|
char* line;
|
||||||
|
@ -258,6 +237,7 @@ bool BITMAP_BASE::LoadData( LINE_READER& aLine, wxString& aErrorMsg )
|
||||||
m_image->LoadFile( istream, wxBITMAP_TYPE_ANY );
|
m_image->LoadFile( istream, wxBITMAP_TYPE_ANY );
|
||||||
m_bitmap = new wxBitmap( *m_image );
|
m_bitmap = new wxBitmap( *m_image );
|
||||||
m_originalImage = new wxImage( *m_image );
|
m_originalImage = new wxImage( *m_image );
|
||||||
|
UpdateImageDataBuffer();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -450,6 +430,7 @@ void BITMAP_BASE::Mirror( bool aVertically )
|
||||||
m_isMirroredX = !m_isMirroredX;
|
m_isMirroredX = !m_isMirroredX;
|
||||||
|
|
||||||
rebuildBitmap( false );
|
rebuildBitmap( false );
|
||||||
|
UpdateImageDataBuffer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -474,6 +455,7 @@ void BITMAP_BASE::Rotate( bool aRotateCCW )
|
||||||
|
|
||||||
m_rotation += ( aRotateCCW ? -ANGLE_90 : ANGLE_90 );
|
m_rotation += ( aRotateCCW ? -ANGLE_90 : ANGLE_90 );
|
||||||
rebuildBitmap( false );
|
rebuildBitmap( false );
|
||||||
|
UpdateImageDataBuffer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -485,6 +467,7 @@ void BITMAP_BASE::ConvertToGreyscale()
|
||||||
*m_image = m_image->ConvertToGreyscale();
|
*m_image = m_image->ConvertToGreyscale();
|
||||||
*m_originalImage = m_originalImage->ConvertToGreyscale();
|
*m_originalImage = m_originalImage->ConvertToGreyscale();
|
||||||
rebuildBitmap();
|
rebuildBitmap();
|
||||||
|
UpdateImageDataBuffer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -502,3 +485,20 @@ void BITMAP_BASE::PlotImage( PLOTTER* aPlotter, const VECTOR2I& aPos,
|
||||||
aPlotter->SetCurrentLineWidth( aDefaultPensize );
|
aPlotter->SetCurrentLineWidth( aDefaultPensize );
|
||||||
aPlotter->PlotImage( *m_image, aPos, GetScalingFactor() );
|
aPlotter->PlotImage( *m_image, aPos, GetScalingFactor() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BITMAP_BASE::UpdateImageDataBuffer()
|
||||||
|
{
|
||||||
|
if( m_image )
|
||||||
|
{
|
||||||
|
wxMemoryOutputStream stream;
|
||||||
|
wxBitmapType type = m_imageType == wxBITMAP_TYPE_JPEG ? wxBITMAP_TYPE_JPEG : wxBITMAP_TYPE_PNG;
|
||||||
|
|
||||||
|
if( !m_image->SaveFile( stream, type ) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_imageData.GetWriteBuf( stream.GetLength() );
|
||||||
|
stream.CopyTo( m_imageData.GetData(), stream.GetLength() );
|
||||||
|
m_imageData.SetDataLen( stream.GetLength() );
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,8 +24,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <charconv>
|
#include <charconv>
|
||||||
|
#include <wx/base64.h>
|
||||||
#include <wx/ffile.h>
|
#include <wx/ffile.h>
|
||||||
#include <wx/log.h>
|
#include <wx/log.h>
|
||||||
|
|
||||||
#include <eda_item.h>
|
#include <eda_item.h>
|
||||||
#include <locale_io.h>
|
#include <locale_io.h>
|
||||||
#include <string_utils.h>
|
#include <string_utils.h>
|
||||||
|
@ -512,6 +514,33 @@ void DRAWING_SHEET_PARSER::parseBitmap( DS_DATA_ITEM_BITMAP * aItem )
|
||||||
NeedRIGHT();
|
NeedRIGHT();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case T_data:
|
||||||
|
{
|
||||||
|
token = NextTok();
|
||||||
|
|
||||||
|
wxString data;
|
||||||
|
|
||||||
|
// Reserve 512K because most image files are going to be larger than the default
|
||||||
|
// 1K that wxString reserves.
|
||||||
|
data.reserve( 1 << 19 );
|
||||||
|
|
||||||
|
while( token != T_RIGHT )
|
||||||
|
{
|
||||||
|
if( !IsSymbol( token ) )
|
||||||
|
Expecting( "base64 image data" );
|
||||||
|
|
||||||
|
data += FromUTF8();
|
||||||
|
token = NextTok();
|
||||||
|
}
|
||||||
|
|
||||||
|
wxMemoryBuffer buffer = wxBase64Decode( data );
|
||||||
|
|
||||||
|
if( !aItem->m_ImageBitmap->ReadImageFile( buffer ) )
|
||||||
|
THROW_IO_ERROR( _( "Failed to read image data." ) );
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case T_pngdata:
|
case T_pngdata:
|
||||||
readPngdata( aItem );
|
readPngdata( aItem );
|
||||||
break;
|
break;
|
||||||
|
@ -556,7 +585,7 @@ void DRAWING_SHEET_PARSER::readPngdata( DS_DATA_ITEM_BITMAP * aItem )
|
||||||
wxString msg;
|
wxString msg;
|
||||||
STRING_LINE_READER str_reader( tmp, wxT("Png kicad_wks data") );
|
STRING_LINE_READER str_reader( tmp, wxT("Png kicad_wks data") );
|
||||||
|
|
||||||
if( ! aItem->m_ImageBitmap->LoadData( str_reader, msg ) )
|
if( ! aItem->m_ImageBitmap->LoadLegacyData( str_reader, msg ) )
|
||||||
wxLogMessage(msg);
|
wxLogMessage(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include <drawing_sheet/ds_file_versions.h>
|
#include <drawing_sheet/ds_file_versions.h>
|
||||||
#include <font/font.h>
|
#include <font/font.h>
|
||||||
|
|
||||||
|
#include <wx/base64.h>
|
||||||
#include <wx/msgdlg.h>
|
#include <wx/msgdlg.h>
|
||||||
|
|
||||||
using namespace DRAWINGSHEET_T;
|
using namespace DRAWINGSHEET_T;
|
||||||
|
@ -417,16 +418,26 @@ void DS_DATA_MODEL_IO::format( DS_DATA_ITEM_BITMAP* aItem, int aNestLevel ) cons
|
||||||
m_out->Print( 0, " (comment %s)\n", m_out->Quotew( aItem->m_Info ).c_str() );
|
m_out->Print( 0, " (comment %s)\n", m_out->Quotew( aItem->m_Info ).c_str() );
|
||||||
|
|
||||||
// Write image in png readable format
|
// Write image in png readable format
|
||||||
m_out->Print( aNestLevel, "(pngdata\n" );
|
m_out->Print( aNestLevel, "(data" );
|
||||||
wxArrayString pngStrings;
|
|
||||||
aItem->m_ImageBitmap->SaveData( pngStrings );
|
|
||||||
|
|
||||||
for( unsigned ii = 0; ii < pngStrings.GetCount(); ii++ )
|
wxString out = wxBase64Encode( aItem->m_ImageBitmap->GetImageDataBuffer() );
|
||||||
m_out->Print( aNestLevel+1, "(data \"%s\")\n", TO_UTF8(pngStrings[ii]) );
|
|
||||||
|
|
||||||
m_out->Print( aNestLevel+1, ")\n" );
|
// Apparently the MIME standard character width for base64 encoding is 76 (unconfirmed)
|
||||||
|
// so use it in a vain attempt to be standard like.
|
||||||
|
#define MIME_BASE64_LENGTH 76
|
||||||
|
|
||||||
m_out->Print( aNestLevel, ")\n" );
|
size_t first = 0;
|
||||||
|
|
||||||
|
while( first < out.Length() )
|
||||||
|
{
|
||||||
|
m_out->Print( 0, "\n" );
|
||||||
|
m_out->Print( aNestLevel + 1, "%s", TO_UTF8( out( first, MIME_BASE64_LENGTH ) ) );
|
||||||
|
first += MIME_BASE64_LENGTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_out->Print( 0, "\n" );
|
||||||
|
m_out->Print( aNestLevel, ")\n" ); // Closes data token.
|
||||||
|
m_out->Print( aNestLevel, ")\n" ); // Closes bitmap token.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -92,13 +92,6 @@ bool SCH_BITMAP::ReadImageFile( const wxString& aFullFilename )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SCH_BITMAP::SetImage( wxImage* aImage )
|
|
||||||
{
|
|
||||||
m_bitmapBase->SetImage( aImage );
|
|
||||||
m_bitmapBase->SetPixelSizeIu( 254000.0 / m_bitmapBase->GetPPI() );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
EDA_ITEM* SCH_BITMAP::Clone() const
|
EDA_ITEM* SCH_BITMAP::Clone() const
|
||||||
{
|
{
|
||||||
return new SCH_BITMAP( *this );
|
return new SCH_BITMAP( *this );
|
||||||
|
|
|
@ -58,8 +58,6 @@ public:
|
||||||
return m_bitmapBase;
|
return m_bitmapBase;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetImage( wxImage* aImage );
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the image "zoom" value.
|
* @return the image "zoom" value.
|
||||||
* scale = 1.0 = original size of bitmap.
|
* scale = 1.0 = original size of bitmap.
|
||||||
|
|
|
@ -3056,11 +3056,10 @@ SCH_BITMAP* SCH_SEXPR_PARSER::parseImage()
|
||||||
}
|
}
|
||||||
|
|
||||||
wxMemoryBuffer buffer = wxBase64Decode( data );
|
wxMemoryBuffer buffer = wxBase64Decode( data );
|
||||||
wxMemoryOutputStream stream( buffer.GetData(), buffer.GetBufSize() );
|
|
||||||
wxImage* image = new wxImage();
|
if( !bitmap->GetImage()->ReadImageFile( buffer ) )
|
||||||
wxMemoryInputStream istream( stream );
|
THROW_IO_ERROR( _( "Failed to read image data." ) );
|
||||||
image->LoadFile( istream, wxBITMAP_TYPE_PNG );
|
|
||||||
bitmap->SetImage( image );
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -952,13 +952,7 @@ void SCH_SEXPR_PLUGIN::saveBitmap( SCH_BITMAP* aBitmap, int aNestLevel )
|
||||||
|
|
||||||
m_out->Print( aNestLevel + 1, "(data" );
|
m_out->Print( aNestLevel + 1, "(data" );
|
||||||
|
|
||||||
wxMemoryOutputStream stream;
|
wxString out = wxBase64Encode( aBitmap->GetImage()->GetImageDataBuffer() );
|
||||||
|
|
||||||
image->SaveFile( stream, wxBITMAP_TYPE_PNG );
|
|
||||||
|
|
||||||
// Write binary data in hexadecimal form (ASCII)
|
|
||||||
wxStreamBuffer* buffer = stream.GetOutputStreamBuffer();
|
|
||||||
wxString out = wxBase64Encode( buffer->GetBufferStart(), buffer->GetBufferSize() );
|
|
||||||
|
|
||||||
// Apparently the MIME standard character width for base64 encoding is 76 (unconfirmed)
|
// Apparently the MIME standard character width for base64 encoding is 76 (unconfirmed)
|
||||||
// so use it in a vein attempt to be standard like.
|
// so use it in a vein attempt to be standard like.
|
||||||
|
|
|
@ -676,7 +676,7 @@ SCH_BITMAP* SCH_LEGACY_PLUGIN::loadBitmap( LINE_READER& aReader )
|
||||||
}
|
}
|
||||||
else if( strCompare( "Data", line, &line ) )
|
else if( strCompare( "Data", line, &line ) )
|
||||||
{
|
{
|
||||||
wxMemoryOutputStream stream;
|
wxMemoryBuffer buffer;
|
||||||
|
|
||||||
while( line )
|
while( line )
|
||||||
{
|
{
|
||||||
|
@ -688,12 +688,7 @@ SCH_BITMAP* SCH_LEGACY_PLUGIN::loadBitmap( LINE_READER& aReader )
|
||||||
if( strCompare( "EndData", line ) )
|
if( strCompare( "EndData", line ) )
|
||||||
{
|
{
|
||||||
// all the PNG date is read.
|
// all the PNG date is read.
|
||||||
// We expect here m_image and m_bitmap are void
|
bitmap->GetImage()->ReadImageFile( buffer );
|
||||||
wxImage* image = new wxImage();
|
|
||||||
wxMemoryInputStream istream( stream );
|
|
||||||
image->LoadFile( istream, wxBITMAP_TYPE_PNG );
|
|
||||||
|
|
||||||
bitmap->SetImage( image );
|
|
||||||
|
|
||||||
// Legacy file formats assumed 300 image PPI at load.
|
// Legacy file formats assumed 300 image PPI at load.
|
||||||
BITMAP_BASE* bitmapImage = bitmap->GetImage();
|
BITMAP_BASE* bitmapImage = bitmap->GetImage();
|
||||||
|
@ -716,7 +711,7 @@ SCH_BITMAP* SCH_LEGACY_PLUGIN::loadBitmap( LINE_READER& aReader )
|
||||||
int value = 0;
|
int value = 0;
|
||||||
|
|
||||||
if( sscanf( line, "%X", &value ) == 1 )
|
if( sscanf( line, "%X", &value ) == 1 )
|
||||||
stream.PutC( (char) value );
|
buffer.AppendByte( (char) value );
|
||||||
else
|
else
|
||||||
THROW_IO_ERROR( "invalid PNG data" );
|
THROW_IO_ERROR( "invalid PNG data" );
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,8 +69,6 @@ public:
|
||||||
|
|
||||||
const wxImage* GetOriginalImageData() const { return m_originalImage; }
|
const wxImage* GetOriginalImageData() const { return m_originalImage; }
|
||||||
|
|
||||||
void SetImage( wxImage* aImage );
|
|
||||||
|
|
||||||
double GetScale() const { return m_scale; }
|
double GetScale() const { return m_scale; }
|
||||||
void SetScale( double aScale ) { m_scale = aScale; }
|
void SetScale( double aScale ) { m_scale = aScale; }
|
||||||
|
|
||||||
|
@ -159,25 +157,27 @@ public:
|
||||||
bool ReadImageFile( wxInputStream& aInStream );
|
bool ReadImageFile( wxInputStream& aInStream );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write the bitmap data to \a aFile.
|
* Reads and stores in memory an image file.
|
||||||
*
|
*
|
||||||
* The file format is png, in hexadecimal form. If the hexadecimal data is converted to
|
* Initialize the bitmap format used to draw this item.
|
||||||
* binary it gives exactly a .png image data.
|
|
||||||
*
|
*
|
||||||
* @param aFile The FILE to write to.
|
* Supported images formats are format supported by wxImage if all handlers are loaded.
|
||||||
* @return true if success writing else false.
|
* By default, .png, .jpeg are always loaded.
|
||||||
|
*
|
||||||
|
* @param aBuf a memory buffer containing the file data.
|
||||||
|
* @return true if success reading else false.
|
||||||
*/
|
*/
|
||||||
bool SaveData( FILE* aFile ) const;
|
bool ReadImageFile( wxMemoryBuffer& aBuf );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write the bitmap data to an array string.
|
* Write the bitmap data to \a aOutStream.
|
||||||
*
|
*
|
||||||
* The format is png, in Hexadecimal form. If the hexadecimal data is converted to binary
|
* This writes binary data, not hexadecimal strings
|
||||||
* it gives exactly a .png image data.
|
*
|
||||||
*
|
* @param aOutStream The output stream to write to.
|
||||||
* @param aPngStrings The wxArrayString to write to.
|
* @return true if success writing else false.
|
||||||
*/
|
*/
|
||||||
void SaveData( wxArrayString& aPngStrings ) const;
|
bool SaveImageData( wxOutputStream& aOutStream ) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load an image data saved by #SaveData.
|
* Load an image data saved by #SaveData.
|
||||||
|
@ -189,7 +189,7 @@ public:
|
||||||
* png bitmap data.
|
* png bitmap data.
|
||||||
* @return true if the bitmap loaded successfully.
|
* @return true if the bitmap loaded successfully.
|
||||||
*/
|
*/
|
||||||
bool LoadData( LINE_READER& aLine, wxString& aErrorMsg );
|
bool LoadLegacyData( LINE_READER& aLine, wxString& aErrorMsg );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mirror image vertically (i.e. relative to its horizontal X axis ) or horizontally (i.e
|
* Mirror image vertically (i.e. relative to its horizontal X axis ) or horizontally (i.e
|
||||||
|
@ -234,6 +234,16 @@ public:
|
||||||
*/
|
*/
|
||||||
void SetImageType( wxBitmapType aType ) { m_imageType = aType; }
|
void SetImageType( wxBitmapType aType ) { m_imageType = aType; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the image data buffer.
|
||||||
|
*/
|
||||||
|
const wxMemoryBuffer& GetImageDataBuffer() const { return m_imageData; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the image data buffer using the current image data.
|
||||||
|
*/
|
||||||
|
void UpdateImageDataBuffer();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/*
|
/*
|
||||||
* Rebuild the internal bitmap used to draw/plot image.
|
* Rebuild the internal bitmap used to draw/plot image.
|
||||||
|
@ -248,8 +258,10 @@ private:
|
||||||
|
|
||||||
double m_scale; // The scaling factor of the bitmap
|
double m_scale; // The scaling factor of the bitmap
|
||||||
// With m_pixelSizeIu, controls the actual draw size
|
// With m_pixelSizeIu, controls the actual draw size
|
||||||
wxImage* m_image; // the raw image data
|
wxMemoryBuffer m_imageData; // The original image data, in its original format
|
||||||
wxBitmapType m_imageType; // the image type (png, jpeg, etc.)
|
wxBitmapType m_imageType; // the image type (png, jpeg, etc.)
|
||||||
|
|
||||||
|
wxImage* m_image; // the raw, uncompressed image data
|
||||||
wxImage* m_originalImage; // Raw image data, not transformed by rotate/mirror
|
wxImage* m_originalImage; // Raw image data, not transformed by rotate/mirror
|
||||||
wxBitmap* m_bitmap; // the bitmap used to draw/plot image
|
wxBitmap* m_bitmap; // the bitmap used to draw/plot image
|
||||||
double m_pixelSizeIu; // The scaling factor of the bitmap
|
double m_pixelSizeIu; // The scaling factor of the bitmap
|
||||||
|
|
|
@ -31,4 +31,5 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//#define SEXPR_WORKSHEET_FILE_VERSION 20210606 // Initial version.
|
//#define SEXPR_WORKSHEET_FILE_VERSION 20210606 // Initial version.
|
||||||
#define SEXPR_WORKSHEET_FILE_VERSION 20220228 // Font support.
|
//#define SEXPR_WORKSHEET_FILE_VERSION 20220228 // Font support.
|
||||||
|
#define SEXPR_WORKSHEET_FILE_VERSION 20230607 // Save images as base64.
|
||||||
|
|
|
@ -82,13 +82,6 @@ PCB_BITMAP& PCB_BITMAP::operator=( const BOARD_ITEM& aItem )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PCB_BITMAP::SetImage( wxImage* aImage )
|
|
||||||
{
|
|
||||||
m_bitmapBase->SetImage( aImage );
|
|
||||||
m_bitmapBase->SetPixelSizeIu( (float) pcbIUScale.MilsToIU( 1000 ) / m_bitmapBase->GetPPI() );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool PCB_BITMAP::ReadImageFile( const wxString& aFullFilename )
|
bool PCB_BITMAP::ReadImageFile( const wxString& aFullFilename )
|
||||||
{
|
{
|
||||||
if( m_bitmapBase->ReadImageFile( aFullFilename ) )
|
if( m_bitmapBase->ReadImageFile( aFullFilename ) )
|
||||||
|
@ -101,6 +94,18 @@ bool PCB_BITMAP::ReadImageFile( const wxString& aFullFilename )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool PCB_BITMAP::ReadImageFile( wxMemoryBuffer& aBuffer )
|
||||||
|
{
|
||||||
|
if( m_bitmapBase->ReadImageFile( aBuffer ) )
|
||||||
|
{
|
||||||
|
m_bitmapBase->SetPixelSizeIu( (float) pcbIUScale.MilsToIU( 1000 ) / m_bitmapBase->GetPPI() );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
EDA_ITEM* PCB_BITMAP::Clone() const
|
EDA_ITEM* PCB_BITMAP::Clone() const
|
||||||
{
|
{
|
||||||
return new PCB_BITMAP( *this );
|
return new PCB_BITMAP( *this );
|
||||||
|
|
|
@ -65,8 +65,6 @@ public:
|
||||||
return m_bitmapBase;
|
return m_bitmapBase;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetImage( wxImage* aImage );
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the image "zoom" value.
|
* @return the image "zoom" value.
|
||||||
* scale = 1.0 = original size of bitmap.
|
* scale = 1.0 = original size of bitmap.
|
||||||
|
@ -111,6 +109,16 @@ public:
|
||||||
*/
|
*/
|
||||||
bool ReadImageFile( const wxString& aFullFilename );
|
bool ReadImageFile( const wxString& aFullFilename );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read and store an image file.
|
||||||
|
*
|
||||||
|
* Initialize the bitmap used to draw this item format.
|
||||||
|
*
|
||||||
|
* @param aBuf is the memory buffer containing the image file to read.
|
||||||
|
* @return true if success reading else false.
|
||||||
|
*/
|
||||||
|
bool ReadImageFile( wxMemoryBuffer& aBuf );
|
||||||
|
|
||||||
void Move( const VECTOR2I& aMoveVector ) override { m_pos += aMoveVector; }
|
void Move( const VECTOR2I& aMoveVector ) override { m_pos += aMoveVector; }
|
||||||
|
|
||||||
void Flip( const VECTOR2I& aCentre, bool aFlipLeftRight ) override;
|
void Flip( const VECTOR2I& aCentre, bool aFlipLeftRight ) override;
|
||||||
|
|
|
@ -2967,9 +2967,9 @@ PCB_BITMAP* PCB_PARSER::parsePCB_BITMAP( BOARD_ITEM* aParent )
|
||||||
|
|
||||||
wxString data;
|
wxString data;
|
||||||
|
|
||||||
// Reserve 128K because most image files are going to be larger than the default
|
// Reserve 512K because most image files are going to be larger than the default
|
||||||
// 1K that wxString reserves.
|
// 1K that wxString reserves.
|
||||||
data.reserve( 1 << 17 );
|
data.reserve( 1 << 19 );
|
||||||
|
|
||||||
while( token != T_RIGHT )
|
while( token != T_RIGHT )
|
||||||
{
|
{
|
||||||
|
@ -2981,12 +2981,10 @@ PCB_BITMAP* PCB_PARSER::parsePCB_BITMAP( BOARD_ITEM* aParent )
|
||||||
}
|
}
|
||||||
|
|
||||||
wxMemoryBuffer buffer = wxBase64Decode( data );
|
wxMemoryBuffer buffer = wxBase64Decode( data );
|
||||||
wxMemoryOutputStream stream( buffer.GetData(), buffer.GetBufSize() );
|
|
||||||
wxImage* image = new wxImage();
|
if( !bitmap->ReadImageFile( buffer ) )
|
||||||
wxMemoryInputStream istream( stream );
|
THROW_IO_ERROR( _( "Failed to read image data." ) );
|
||||||
image->LoadFile( istream );
|
|
||||||
bitmap->SetImage( image );
|
|
||||||
bitmap->MutableImage()->SetImageType( image->GetType() );
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1040,19 +1040,7 @@ void PCB_PLUGIN::format( const PCB_BITMAP* aBitmap, int aNestLevel ) const
|
||||||
|
|
||||||
m_out->Print( aNestLevel + 1, "(data" );
|
m_out->Print( aNestLevel + 1, "(data" );
|
||||||
|
|
||||||
wxMemoryOutputStream stream;
|
wxString out = wxBase64Encode( aBitmap->GetImage()->GetImageDataBuffer() );
|
||||||
wxBitmapType type = wxBITMAP_TYPE_PNG;
|
|
||||||
|
|
||||||
// Save the image in the same format as the original file
|
|
||||||
// if it was a JPEG. Otherwise, save it as a PNG.
|
|
||||||
if( aBitmap->GetImage()->GetImageType() == wxBITMAP_TYPE_JPEG )
|
|
||||||
type = wxBITMAP_TYPE_JPEG;
|
|
||||||
|
|
||||||
image->SaveFile( stream, type );
|
|
||||||
|
|
||||||
// Write binary data in hexadecimal form (ASCII)
|
|
||||||
wxStreamBuffer* buffer = stream.GetOutputStreamBuffer();
|
|
||||||
wxString out = wxBase64Encode( buffer->GetBufferStart(), buffer->GetBufferSize() );
|
|
||||||
|
|
||||||
// Apparently the MIME standard character width for base64 encoding is 76 (unconfirmed)
|
// Apparently the MIME standard character width for base64 encoding is 76 (unconfirmed)
|
||||||
// so use it in a vain attempt to be standard like.
|
// so use it in a vain attempt to be standard like.
|
||||||
|
|
Loading…
Reference in New Issue