KiCad PCB EDA Suite
bitmap.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2011 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
5  * Copyright (C) 2017-2018 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
25 
26 #include <wx/image.h>
27 #include <wx/bitmap.h>
28 #include <wx/mstream.h>
29 #include <wx/menu.h>
30 #include <wx/menuitem.h>
31 #include <wx/aui/auibar.h>
32 #include <wx/dc.h>
33 #include <wx/dcclient.h>
34 #include <wx/dcmemory.h>
35 
36 #include <cstdint>
37 #include <mutex>
38 #include <unordered_map>
39 
40 #include <bitmaps.h>
41 #include <pgm_base.h>
42 #include <eda_base_frame.h>
43 #include <eda_draw_frame.h>
45 
46 
49  int scale;
50 
51  bool operator==( SCALED_BITMAP_ID const& other ) const noexcept
52  {
53  return bitmap == other.bitmap && scale == other.scale;
54  }
55 };
56 
57 
58 namespace std {
59  template<> struct hash<SCALED_BITMAP_ID>
60  {
62  typedef std::size_t result_type;
63 
64  result_type operator()( argument_type const& id ) const noexcept
65  {
66  static const bool sz64 = sizeof( uintptr_t ) == 8;
67  static const size_t mask = sz64 ? 0xF000000000000000uLL : 0xF0000000uL;
68  static const size_t offset = sz64 ? 60 : 28;
69 
70  // The hash only needs to be fast and simple, not necessarily accurate - a collision
71  // only makes things slower, not broken. BITMAP_DEF is a pointer, so the most
72  // significant several bits are generally going to be the same for all. Just convert
73  // it to an integer and stuff the scale factor into those bits.
74  return
75  ( (uintptr_t)( id.bitmap ) & ~mask ) |
76  ( ( (uintptr_t)( id.scale ) & 0xF ) << offset );
77  }
78  };
79 }
80 
81 
82 wxBitmap KiBitmap( BITMAP_DEF aBitmap )
83 {
84  wxMemoryInputStream is( aBitmap->png, aBitmap->byteCount );
85  wxImage image( is, wxBITMAP_TYPE_PNG );
86  wxBitmap bitmap( image );
87 
88  return bitmap;
89 }
90 
91 
92 int KiIconScale( wxWindow* aWindow )
93 {
94  const int vert_size = aWindow->ConvertDialogToPixels( wxSize( 0, 8 ) ).y;
95 
96  // Autoscale won't exceed unity until the system has quite high resolution,
97  // because we don't want the icons to look obviously scaled on a system
98  // where it's easy to see it.
99 
100  if( vert_size > 34 ) return 8;
101  else if( vert_size > 29 ) return 7;
102  else if( vert_size > 24 ) return 6;
103  else return 4;
104 }
105 
106 
107 static int get_scale_factor( wxWindow* aWindow )
108 {
109  int requested_scale = Pgm().GetCommonSettings()->m_Appearance.icon_scale;
110 
111  if( requested_scale > 0 )
112  return requested_scale;
113  else
114  return KiIconScale( aWindow );
115 }
116 
117 
118 wxBitmap KiScaledBitmap( BITMAP_DEF aBitmap, wxWindow* aWindow )
119 {
120  // Bitmap conversions are cached because they can be slow.
121  static std::unordered_map<SCALED_BITMAP_ID, wxBitmap> bitmap_cache;
122  static std::mutex bitmap_cache_mutex;
123  const int scale = get_scale_factor( aWindow );
124 
125  SCALED_BITMAP_ID id = { aBitmap, scale };
126 
127  std::lock_guard<std::mutex> guard( bitmap_cache_mutex );
128  auto it = bitmap_cache.find( id );
129 
130  if( it != bitmap_cache.end() )
131  {
132  return it->second;
133  }
134  else
135  {
136  wxMemoryInputStream is( aBitmap->png, aBitmap->byteCount );
137  wxImage image( is, wxBITMAP_TYPE_PNG );
138 
139  // Bilinear seems to genuinely look better for these line-drawing icons
140  // than bicubic, despite claims in the wx documentation that bicubic is
141  // "highest quality". I don't recommend changing this. Bicubic looks
142  // blurry and makes me want an eye exam.
143  image.Rescale( scale * image.GetWidth() / 4, scale * image.GetHeight() / 4,
144  wxIMAGE_QUALITY_BILINEAR );
145  return bitmap_cache.emplace( id, wxBitmap( image ) ).first->second;
146  }
147 }
148 
149 
150 wxBitmap KiScaledBitmap( const wxBitmap& aBitmap, wxWindow* aWindow )
151 {
152  const int scale = get_scale_factor( aWindow );
153 
154  if( scale == 4)
155  {
156  return wxBitmap( aBitmap );
157  }
158  else
159  {
160  wxImage image = aBitmap.ConvertToImage();
161  image.Rescale( scale * image.GetWidth() / 4, scale * image.GetHeight() / 4,
162  wxIMAGE_QUALITY_BILINEAR );
163 
164  return wxBitmap( image );
165  }
166 }
167 
168 
169 wxBitmap* KiBitmapNew( BITMAP_DEF aBitmap )
170 {
171  wxMemoryInputStream is( aBitmap->png, aBitmap->byteCount );
172  wxImage image( is, wxBITMAP_TYPE_PNG );
173  wxBitmap* bitmap = new wxBitmap( image );
174 
175  return bitmap;
176 }
177 
178 
179 bool SaveCanvasImageToFile( EDA_DRAW_FRAME* aFrame, const wxString& aFileName,
180  wxBitmapType aBitmapType )
181 {
182  wxCHECK( aFrame != nullptr, false );
183 
184  bool retv = true;
185 
186  // Make a screen copy of the canvas:
187  wxSize image_size = aFrame->GetCanvas()->GetClientSize();
188 
189  wxClientDC dc( aFrame->GetCanvas() );
190  wxBitmap bitmap( image_size.x, image_size.y );
191  wxMemoryDC memdc;
192 
193  memdc.SelectObject( bitmap );
194  memdc.Blit( 0, 0, image_size.x, image_size.y, &dc, 0, 0 );
195  memdc.SelectObject( wxNullBitmap );
196 
197  wxImage image = bitmap.ConvertToImage();
198 
199  if( !image.SaveFile( aFileName, aBitmapType ) )
200  retv = false;
201 
202  image.Destroy();
203  return retv;
204 }
205 
206 
207 void AddBitmapToMenuItem( wxMenuItem* aMenu, const wxBitmap& aImage )
208 {
209  // Retrieve the global applicaton show icon option:
210  bool useImagesInMenus = Pgm().GetCommonSettings()->m_Appearance.use_icons_in_menus;
211 
212  wxItemKind menu_type = aMenu->GetKind();
213 
214  if( useImagesInMenus && menu_type != wxITEM_CHECK && menu_type != wxITEM_RADIO )
215  {
216  aMenu->SetBitmap( aImage );
217  }
218 }
219 
220 
221 wxMenuItem* AddMenuItem( wxMenu* aMenu, int aId, const wxString& aText,
222  const wxBitmap& aImage, wxItemKind aType = wxITEM_NORMAL )
223 {
224  wxMenuItem* item = new wxMenuItem( aMenu, aId, aText, wxEmptyString, aType );
225  AddBitmapToMenuItem( item, aImage );
226 
227  aMenu->Append( item );
228 
229  return item;
230 }
231 
232 
233 wxMenuItem* AddMenuItem( wxMenu* aMenu, int aId, const wxString& aText,
234  const wxString& aHelpText, const wxBitmap& aImage,
235  wxItemKind aType = wxITEM_NORMAL )
236 {
237  wxMenuItem* item = new wxMenuItem( aMenu, aId, aText, aHelpText, aType );
238  AddBitmapToMenuItem( item, aImage );
239 
240  aMenu->Append( item );
241 
242  return item;
243 }
244 
245 
246 wxMenuItem* AddMenuItem( wxMenu* aMenu, wxMenu* aSubMenu, int aId,
247  const wxString& aText, const wxBitmap& aImage )
248 {
249  wxMenuItem* item = new wxMenuItem( aMenu, aId, aText );
250  item->SetSubMenu( aSubMenu );
251  AddBitmapToMenuItem( item, aImage );
252 
253  aMenu->Append( item );
254 
255  return item;
256 }
257 
258 
259 wxMenuItem* AddMenuItem( wxMenu* aMenu, wxMenu* aSubMenu, int aId,
260  const wxString& aText, const wxString& aHelpText,
261  const wxBitmap& aImage )
262 {
263  wxMenuItem* item = new wxMenuItem( aMenu, aId, aText, aHelpText );
264  item->SetSubMenu( aSubMenu );
265  AddBitmapToMenuItem( item, aImage );
266 
267  aMenu->Append( item );
268 
269  return item;
270 }
PNG memory record (file in memory).
Definition: bitmap_def.h:29
bool SaveCanvasImageToFile(EDA_DRAW_FRAME *aFrame, const wxString &aFileName, wxBitmapType aBitmapType)
Save the current view as an image file.
Definition: bitmap.cpp:179
wxMenuItem * AddMenuItem(wxMenu *aMenu, int aId, const wxString &aText, const wxBitmap &aImage, wxItemKind aType=wxITEM_NORMAL)
Create and insert a menu item with an icon into aMenu.
Definition: bitmap.cpp:221
static int get_scale_factor(wxWindow *aWindow)
Definition: bitmap.cpp:107
virtual EDA_DRAW_PANEL_GAL * GetCanvas() const
Return a pointer to GAL-based canvas of given EDA draw frame.
int KiIconScale(wxWindow *aWindow)
Return the automatic scale factor that would be used for a given window by KiScaledBitmap and KiScale...
Definition: bitmap.cpp:92
Definition: bitmap.cpp:58
The base class for create windows for drawing purpose.
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:106
wxBitmap KiScaledBitmap(BITMAP_DEF aBitmap, wxWindow *aWindow)
Construct a wxBitmap from a memory record, scaling it if device DPI demands it.
Definition: bitmap.cpp:118
const unsigned char * png
Definition: bitmap_def.h:31
wxBitmap KiBitmap(BITMAP_DEF aBitmap)
Construct a wxBitmap from a memory record, held in a BITMAP_DEF.
Definition: bitmap.cpp:82
result_type operator()(argument_type const &id) const noexcept
Definition: bitmap.cpp:64
wxBitmap * KiBitmapNew(BITMAP_DEF aBitmap)
Allocate a wxBitmap on heap from a memory record, held in a BITMAP_DEF.
Definition: bitmap.cpp:169
void AddBitmapToMenuItem(wxMenuItem *aMenu, const wxBitmap &aImage)
Add a bitmap to a menuitem.
Definition: bitmap.cpp:207
SCALED_BITMAP_ID argument_type
Definition: bitmap.cpp:61
Base window classes and related definitions.
BITMAP_DEF bitmap
Definition: bitmap.cpp:48
const int scale
see class PGM_BASE
bool operator==(SCALED_BITMAP_ID const &other) const noexcept
Definition: bitmap.cpp:51