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 <gr_basic.h>
32 #include <math/util.h> // for KiROUND
33 #include <memory> // for make_unique, unique_ptr
34 #include <plotters/plotter.h>
35 #include <richio.h>
36 #include <wx/bitmap.h> // for wxBitmap
37 #include <wx/mstream.h>
38 
39 
40 BITMAP_BASE::BITMAP_BASE( const wxPoint& pos )
41 {
42  m_scale = 1.0; // 1.0 = original bitmap size
43  m_bitmap = nullptr;
44  m_image = nullptr;
45  m_ppi = 300; // the bitmap definition. the default is 300PPI
46  m_pixelSizeIu = 254000.0 / m_ppi; // a pixel size value OK for bitmaps using 300 PPI
47  // for Eeschema which uses currently 254000PPI
48 }
49 
50 
52 {
53  m_scale = aSchBitmap.m_scale;
54  m_ppi = aSchBitmap.m_ppi;
55  m_pixelSizeIu = aSchBitmap.m_pixelSizeIu;
56 
57  m_image = nullptr;
58  m_bitmap = nullptr;
59 
60  if( aSchBitmap.m_image )
61  {
62  m_image = new wxImage( *aSchBitmap.m_image );
63  m_bitmap = new wxBitmap( *m_image );
64  }
65 }
66 
67 
69 {
70  *m_image = *aItem->m_image;
71  *m_bitmap = *aItem->m_bitmap;
72  m_scale = aItem->m_scale;
73  m_ppi = aItem->m_ppi;
75 }
76 
77 
78 bool BITMAP_BASE::ReadImageFile( wxInputStream& aInStream )
79 {
80  auto new_image = std::make_unique<wxImage>();
81 
82  if( !new_image->LoadFile( aInStream ) )
83  {
84  return false;
85  }
86 
87  delete m_image;
88  m_image = new_image.release();
89  m_bitmap = new wxBitmap( *m_image );
90 
91  return true;
92 }
93 
94 
95 bool BITMAP_BASE::ReadImageFile( const wxString& aFullFilename )
96 {
97  wxImage* new_image = new wxImage();
98 
99  if( !new_image->LoadFile( aFullFilename ) )
100  {
101  delete new_image;
102  return false;
103  }
104 
105  delete m_image;
106  m_image = new_image;
107  m_bitmap = new wxBitmap( *m_image );
108 
109  return true;
110 }
111 
112 
113 bool BITMAP_BASE::SaveData( FILE* aFile ) const
114 {
115  if( m_image )
116  {
117  wxMemoryOutputStream stream;
118  m_image->SaveFile( stream, wxBITMAP_TYPE_PNG );
119 
120  // Write binary data in hexadecimal form (ASCII)
121  wxStreamBuffer* buffer = stream.GetOutputStreamBuffer();
122  char* begin = (char*) buffer->GetBufferStart();
123 
124  for( int ii = 0; begin < buffer->GetBufferEnd(); begin++, ii++ )
125  {
126  if( ii >= 32 )
127  {
128  ii = 0;
129 
130  if( fprintf( aFile, "\n" ) == EOF )
131  return false;
132  }
133 
134  if( fprintf( aFile, "%2.2X ", *begin & 0xFF ) == EOF )
135  return false;
136  }
137  }
138 
139  return true;
140 }
141 
142 
143 void BITMAP_BASE::SaveData( wxArrayString& aPngStrings ) const
144 {
145  if( m_image )
146  {
147  wxMemoryOutputStream stream;
148  m_image->SaveFile( stream, wxBITMAP_TYPE_PNG );
149 
150  // Write binary data in hexadecimal form (ASCII)
151  wxStreamBuffer* buffer = stream.GetOutputStreamBuffer();
152  char* begin = (char*) buffer->GetBufferStart();
153  wxString line;
154 
155  for( int ii = 0; begin < buffer->GetBufferEnd(); begin++, ii++ )
156  {
157  if( ii >= 32 )
158  {
159  ii = 0;
160  aPngStrings.Add( line );
161  line.Empty();
162  }
163 
164  line << wxString::Format( wxT( "%2.2X " ), *begin & 0xFF );
165  }
166 
167  // Add last line:
168  if( !line.IsEmpty() )
169  aPngStrings.Add( line );
170  }
171 }
172 
173 
174 bool BITMAP_BASE::LoadData( LINE_READER& aLine, wxString& aErrorMsg )
175 {
176  wxMemoryOutputStream stream;
177  char* line;
178 
179  while( true )
180  {
181  if( !aLine.ReadLine() )
182  {
183  aErrorMsg = wxT("Unexpected end of data");
184  return false;
185  }
186 
187  line = aLine.Line();
188 
189  if( strncasecmp( line, "EndData", 4 ) == 0 )
190  {
191  // all the PNG date is read.
192  // We expect here m_image and m_bitmap are void
193  m_image = new wxImage();
194  wxMemoryInputStream istream( stream );
195  m_image->LoadFile( istream, wxBITMAP_TYPE_PNG );
196  m_bitmap = new wxBitmap( *m_image );
197  break;
198  }
199 
200  // Read PNG data, stored in hexadecimal,
201  // each byte = 2 hexadecimal digits and a space between 2 bytes
202  // and put it in memory stream buffer
203  int len = strlen( line );
204 
205  for( ; len > 0; len -= 3, line += 3 )
206  {
207  int value = 0;
208 
209  if( sscanf( line, "%X", &value ) == 1 )
210  stream.PutC( (char) value );
211  else
212  break;
213  }
214  }
215 
216  return true;
217 }
218 
219 
221 {
222  EDA_RECT rect;
223 
224  wxSize size = GetSize();
225 
226  rect.Inflate( size.x / 2, size.y / 2 );
227 
228  return rect;
229 }
230 
231 
232 void BITMAP_BASE::DrawBitmap( wxDC* aDC, const wxPoint& aPos )
233 {
234  if( m_bitmap == nullptr )
235  return;
236 
237  wxPoint pos = aPos;
238  wxSize size = GetSize();
239 
240  // This fixes a bug in OSX that should be fixed in the 3.0.3 version or later.
241  if( ( size.x == 0 ) || ( size.y == 0 ) )
242  return;
243 
244  // To draw the bitmap, pos is the upper left corner position
245  pos.x -= size.x / 2;
246  pos.y -= size.y / 2;
247 
248  double scale;
249  int logicalOriginX, logicalOriginY;
250  aDC->GetUserScale( &scale, &scale );
251  aDC->GetLogicalOrigin( &logicalOriginX, &logicalOriginY );
252 
253  bool useTransform = aDC->CanUseTransformMatrix();
254  wxAffineMatrix2D init_matrix = aDC->GetTransformMatrix();
255 
256  if( useTransform )
257  {
258  wxAffineMatrix2D matrix = aDC->GetTransformMatrix();
259  matrix.Translate( pos.x, pos.y );
260  matrix.Scale( GetScalingFactor(), GetScalingFactor() );
261  aDC->SetTransformMatrix( matrix );
262  pos.x = pos.y = 0;
263  }
264  else
265  {
266  aDC->SetUserScale( scale * GetScalingFactor(), scale * GetScalingFactor() );
267  aDC->SetLogicalOrigin( logicalOriginX / GetScalingFactor(),
268  logicalOriginY / GetScalingFactor() );
269 
270  pos.x = KiROUND( pos.x / GetScalingFactor() );
271  pos.y = KiROUND( pos.y / GetScalingFactor() );
272  }
273 
275  {
276  wxBitmap result( m_bitmap->ConvertToImage().ConvertToGreyscale() );
277  aDC->DrawBitmap( result, pos.x, pos.y, true );
278  }
279  else
280  {
281  aDC->DrawBitmap( *m_bitmap, pos.x, pos.y, true );
282  }
283 
284  if( useTransform )
285  aDC->SetTransformMatrix( init_matrix );
286  else
287  {
288  aDC->SetUserScale( scale, scale );
289  aDC->SetLogicalOrigin( logicalOriginX, logicalOriginY );
290  }
291 }
292 
293 
294 wxSize BITMAP_BASE::GetSize() const
295 {
296  wxSize size;
297 
298  if( m_bitmap )
299  {
300  size.x = m_bitmap->GetWidth();
301  size.y = m_bitmap->GetHeight();
302 
303  size.x = KiROUND( size.x * GetScalingFactor() );
304  size.y = KiROUND( size.y * GetScalingFactor() );
305  }
306 
307  return size;
308 }
309 
310 
311 void BITMAP_BASE::Mirror( bool aVertically )
312 {
313  if( m_image )
314  {
315  *m_image = m_image->Mirror( not aVertically );
316  RebuildBitmap();
317  }
318 }
319 
320 
321 void BITMAP_BASE::Rotate( bool aRotateCCW )
322 {
323  if( m_image )
324  {
325  *m_image = m_image->Rotate90( aRotateCCW );
326  RebuildBitmap();
327  }
328 }
329 
330 
332  const wxPoint& aPos,
333  const COLOR4D& aDefaultColor,
334  int aDefaultPensize ) const
335 {
336  if( m_image == nullptr )
337  return;
338 
339  // These 2 lines are useful only for plotters that cannot plot a bitmap
340  // and plot a rectangle instead of.
341  aPlotter->SetColor( aDefaultColor );
342  aPlotter->SetCurrentLineWidth( aDefaultPensize );
343  aPlotter->PlotImage( *m_image, aPos, GetScalingFactor() );
344 }
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:40
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 PlotImage(PLOTTER *aPlotter, const wxPoint &aPos, const KIGFX::COLOR4D &aDefaultColor, int aDefaultPensize) const
Plot bitmap on plotter.
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:68
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:95
bool GetGRForceBlackPenState(void)
Definition: gr_basic.cpp:196
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