KiCad PCB EDA Suite
bitmap_base.cpp
Go to the documentation of this file.
1 
5 /*
6  * This program source code file is part of KiCad, a free EDA CAD application.
7  *
8  * Copyright (C) 2017 jean-pierre.charras
9  * Copyright (C) 2011-2021 KiCad Developers, see AUTHORS.txt for contributors.
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, you may find one here:
23  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
24  * or you may search the http://www.gnu.org website for the version 2 license,
25  * or you may write to the Free Software Foundation, Inc.,
26  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
27  */
28 
29 #include <bitmap_base.h>
30 #include <eda_rect.h> // for EDA_RECT
31 #include <gal/color4d.h> // for COLOR4D
32 #include <gr_basic.h>
33 #include <math/util.h> // for KiROUND
34 #include <memory> // for make_unique, unique_ptr
35 #include <plotter.h>
36 #include <richio.h>
37 #include <wx/bitmap.h> // for wxBitmap
38 #include <wx/mstream.h>
39 
40 
41 BITMAP_BASE::BITMAP_BASE( const wxPoint& pos )
42 {
43  m_scale = 1.0; // 1.0 = original bitmap size
44  m_bitmap = nullptr;
45  m_image = nullptr;
46  m_ppi = 300; // the bitmap definition. the default is 300PPI
47  m_pixelSizeIu = 254000.0 / m_ppi; // a pixel size value OK for bitmaps using 300 PPI
48  // for Eeschema which uses currently 254000PPI
49 }
50 
51 
53 {
54  m_scale = aSchBitmap.m_scale;
55  m_ppi = aSchBitmap.m_ppi;
56  m_pixelSizeIu = aSchBitmap.m_pixelSizeIu;
57 
58  m_image = nullptr;
59  m_bitmap = nullptr;
60 
61  if( aSchBitmap.m_image )
62  {
63  m_image = new wxImage( *aSchBitmap.m_image );
64  m_bitmap = new wxBitmap( *m_image );
65  }
66 }
67 
68 
70 {
71  *m_image = *aItem->m_image;
72  *m_bitmap = *aItem->m_bitmap;
73  m_scale = aItem->m_scale;
74  m_ppi = aItem->m_ppi;
76 }
77 
78 
79 bool BITMAP_BASE::ReadImageFile( wxInputStream& aInStream )
80 {
81  auto new_image = std::make_unique<wxImage>();
82 
83  if( !new_image->LoadFile( aInStream ) )
84  {
85  return false;
86  }
87 
88  delete m_image;
89  m_image = new_image.release();
90  m_bitmap = new wxBitmap( *m_image );
91 
92  return true;
93 }
94 
95 
96 bool BITMAP_BASE::ReadImageFile( const wxString& aFullFilename )
97 {
98  wxImage* new_image = new wxImage();
99 
100  if( !new_image->LoadFile( aFullFilename ) )
101  {
102  delete new_image;
103  return false;
104  }
105 
106  delete m_image;
107  m_image = new_image;
108  m_bitmap = new wxBitmap( *m_image );
109 
110  return true;
111 }
112 
113 
114 bool BITMAP_BASE::SaveData( FILE* aFile ) const
115 {
116  if( m_image )
117  {
118  wxMemoryOutputStream stream;
119  m_image->SaveFile( stream, wxBITMAP_TYPE_PNG );
120 
121  // Write binary data in hexadecimal form (ASCII)
122  wxStreamBuffer* buffer = stream.GetOutputStreamBuffer();
123  char* begin = (char*) buffer->GetBufferStart();
124 
125  for( int ii = 0; begin < buffer->GetBufferEnd(); begin++, ii++ )
126  {
127  if( ii >= 32 )
128  {
129  ii = 0;
130 
131  if( fprintf( aFile, "\n" ) == EOF )
132  return false;
133  }
134 
135  if( fprintf( aFile, "%2.2X ", *begin & 0xFF ) == EOF )
136  return false;
137  }
138  }
139 
140  return true;
141 }
142 
143 
144 void BITMAP_BASE::SaveData( wxArrayString& aPngStrings ) const
145 {
146  if( m_image )
147  {
148  wxMemoryOutputStream stream;
149  m_image->SaveFile( stream, wxBITMAP_TYPE_PNG );
150 
151  // Write binary data in hexadecimal form (ASCII)
152  wxStreamBuffer* buffer = stream.GetOutputStreamBuffer();
153  char* begin = (char*) buffer->GetBufferStart();
154  wxString line;
155 
156  for( int ii = 0; begin < buffer->GetBufferEnd(); begin++, ii++ )
157  {
158  if( ii >= 32 )
159  {
160  ii = 0;
161  aPngStrings.Add( line );
162  line.Empty();
163  }
164 
165  line << wxString::Format( wxT( "%2.2X " ), *begin & 0xFF );
166  }
167 
168  // Add last line:
169  if( !line.IsEmpty() )
170  aPngStrings.Add( line );
171  }
172 }
173 
174 
175 bool BITMAP_BASE::LoadData( LINE_READER& aLine, wxString& aErrorMsg )
176 {
177  wxMemoryOutputStream stream;
178  char* line;
179 
180  while( true )
181  {
182  if( !aLine.ReadLine() )
183  {
184  aErrorMsg = wxT("Unexpected end of data");
185  return false;
186  }
187 
188  line = aLine.Line();
189 
190  if( strncasecmp( line, "EndData", 4 ) == 0 )
191  {
192  // all the PNG date is read.
193  // We expect here m_image and m_bitmap are void
194  m_image = new wxImage();
195  wxMemoryInputStream istream( stream );
196  m_image->LoadFile( istream, wxBITMAP_TYPE_PNG );
197  m_bitmap = new wxBitmap( *m_image );
198  break;
199  }
200 
201  // Read PNG data, stored in hexadecimal,
202  // each byte = 2 hexadecimal digits and a space between 2 bytes
203  // and put it in memory stream buffer
204  int len = strlen( line );
205 
206  for( ; len > 0; len -= 3, line += 3 )
207  {
208  int value = 0;
209 
210  if( sscanf( line, "%X", &value ) == 1 )
211  stream.PutC( (char) value );
212  else
213  break;
214  }
215  }
216 
217  return true;
218 }
219 
220 
222 {
223  EDA_RECT rect;
224 
225  wxSize size = GetSize();
226 
227  rect.Inflate( size.x / 2, size.y / 2 );
228 
229  return rect;
230 }
231 
232 
233 void BITMAP_BASE::DrawBitmap( wxDC* aDC, const wxPoint& aPos )
234 {
235  if( m_bitmap == nullptr )
236  return;
237 
238  wxPoint pos = aPos;
239  wxSize size = GetSize();
240 
241  // This fixes a bug in OSX that should be fixed in the 3.0.3 version or later.
242  if( ( size.x == 0 ) || ( size.y == 0 ) )
243  return;
244 
245  // To draw the bitmap, pos is the upper left corner position
246  pos.x -= size.x / 2;
247  pos.y -= size.y / 2;
248 
249  double scale;
250  int logicalOriginX, logicalOriginY;
251  aDC->GetUserScale( &scale, &scale );
252  aDC->GetLogicalOrigin( &logicalOriginX, &logicalOriginY );
253 
254  bool useTransform = aDC->CanUseTransformMatrix();
255  wxAffineMatrix2D init_matrix = aDC->GetTransformMatrix();
256 
257  if( useTransform )
258  {
259  wxAffineMatrix2D matrix = aDC->GetTransformMatrix();
260  matrix.Translate( pos.x, pos.y );
261  matrix.Scale( GetScalingFactor(), GetScalingFactor() );
262  aDC->SetTransformMatrix( matrix );
263  pos.x = pos.y = 0;
264  }
265  else
266  {
267  aDC->SetUserScale( scale * GetScalingFactor(), scale * GetScalingFactor() );
268  aDC->SetLogicalOrigin( logicalOriginX / GetScalingFactor(),
269  logicalOriginY / GetScalingFactor() );
270 
271  pos.x = KiROUND( pos.x / GetScalingFactor() );
272  pos.y = KiROUND( pos.y / GetScalingFactor() );
273  }
274 
276  {
277  wxBitmap result( m_bitmap->ConvertToImage().ConvertToGreyscale() );
278  aDC->DrawBitmap( result, pos.x, pos.y, true );
279  }
280  else
281  {
282  aDC->DrawBitmap( *m_bitmap, pos.x, pos.y, true );
283  }
284 
285  if( useTransform )
286  aDC->SetTransformMatrix( init_matrix );
287  else
288  {
289  aDC->SetUserScale( scale, scale );
290  aDC->SetLogicalOrigin( logicalOriginX, logicalOriginY );
291  }
292 }
293 
294 
295 wxSize BITMAP_BASE::GetSize() const
296 {
297  wxSize size;
298 
299  if( m_bitmap )
300  {
301  size.x = m_bitmap->GetWidth();
302  size.y = m_bitmap->GetHeight();
303 
304  size.x = KiROUND( size.x * GetScalingFactor() );
305  size.y = KiROUND( size.y * GetScalingFactor() );
306  }
307 
308  return size;
309 }
310 
311 
312 void BITMAP_BASE::Mirror( bool aVertically )
313 {
314  if( m_image )
315  {
316  *m_image = m_image->Mirror( not aVertically );
317  RebuildBitmap();
318  }
319 }
320 
321 
322 void BITMAP_BASE::Rotate( bool aRotateCCW )
323 {
324  if( m_image )
325  {
326  *m_image = m_image->Rotate90( aRotateCCW );
327  RebuildBitmap();
328  }
329 }
330 
331 
333  const wxPoint& aPos,
334  COLOR4D aDefaultColor,
335  int aDefaultPensize ) const
336 {
337  if( m_image == nullptr )
338  return;
339 
340  // These 2 lines are useful only for plotters that cannot plot a bitmap
341  // and plot a rectangle instead of.
342  aPlotter->SetColor( aDefaultColor );
343  aPlotter->SetCurrentLineWidth( aDefaultPensize );
344  aPlotter->PlotImage( *m_image, aPos, GetScalingFactor() );
345 }
double GetScalingFactor() const
This scaling factor depends on m_pixelSizeIu and m_scale.
Definition: bitmap_base.h:111
An abstract class from which implementation specific LINE_READERs may be derived to read single lines...
Definition: richio.h:80
Plot settings, and plotting engines (PostScript, Gerber, HPGL and DXF)
BITMAP_BASE(const wxPoint &pos=wxPoint(0, 0))
Definition: bitmap_base.cpp:41
char * Line() const
Return a pointer to the last line that was read in.
Definition: richio.h:117
bool SaveData(FILE *aFile) const
Write the bitmap data to aFile.
void RebuildBitmap()
Definition: bitmap_base.h:87
void Mirror(bool aVertically)
Mirror image vertically (i.e.
const EDA_RECT GetBoundingBox() const
Return the orthogonal, bounding box of this object for display purposes.
This class handle bitmap images in KiCad.
Definition: bitmap_base.h:51
double m_scale
Definition: bitmap_base.h:237
wxSize GetSize() const
wxBitmap * m_bitmap
Definition: bitmap_base.h:240
virtual void SetColor(const COLOR4D &color)=0
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
Base plotter engine class.
Definition: plotter.h:121
virtual void PlotImage(const wxImage &aImage, const wxPoint &aPos, double aScaleFactor)
Only PostScript plotters can plot bitmaps.
Definition: plotter.cpp:239
void ImportData(BITMAP_BASE *aItem)
Copy aItem image to this object and update m_bitmap.
Definition: bitmap_base.cpp:69
const int scale
virtual char * ReadLine()=0
Read a line of text into the buffer and increments the line number counter.
Handle the component boundary box.
Definition: eda_rect.h:42
bool LoadData(LINE_READER &aLine, wxString &aErrorMsg)
Load an image data saved by SaveData.
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:73
void DrawBitmap(wxDC *aDC, const wxPoint &aPos)
bool ReadImageFile(const wxString &aFullFilename)
Reads and stores in memory an image file.
Definition: bitmap_base.cpp:96
void PlotImage(PLOTTER *aPlotter, const wxPoint &aPos, KIGFX::COLOR4D aDefaultColor, int aDefaultPensize) const
Plot bitmap on plotter.
bool GetGRForceBlackPenState(void)
Definition: gr_basic.cpp:212
void Rotate(bool aRotateCCW)
Rotate image CW or CCW.
virtual void SetCurrentLineWidth(int width, void *aData=nullptr)=0
Set the line width for the next drawing.
double m_pixelSizeIu
Definition: bitmap_base.h:241
EDA_RECT & Inflate(wxCoord dx, wxCoord dy)
Inflate the rectangle horizontally by dx and vertically by dy.
Definition: eda_rect.cpp:364
wxImage * m_image
Definition: bitmap_base.h:239
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:103