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-2021 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/gdicmn.h>
29 #include <wx/mstream.h>
30 #include <wx/menu.h>
31 #include <wx/menuitem.h>
32 #include <wx/aui/auibar.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 <asset_archive.h>
41 #include <bitmaps.h>
42 #include <bitmap_store.h>
43 #include <bitmaps/bitmap_opaque.h> // for pcb_calculator compatibility shim
44 #include <pgm_base.h>
45 #include <eda_base_frame.h>
46 #include <eda_draw_frame.h>
47 #include <paths.h>
48 
49 
50 static std::unique_ptr<BITMAP_STORE> s_BitmapStore;
51 
52 
55  int scale;
56 
57  bool operator==( SCALED_BITMAP_ID const& other ) const noexcept
58  {
59  return bitmap == other.bitmap && scale == other.scale;
60  }
61 };
62 
63 
64 namespace std {
65  template<> struct hash<SCALED_BITMAP_ID>
66  {
68  typedef std::size_t result_type;
69 
70  result_type operator()( argument_type const& id ) const noexcept
71  {
72  static const bool sz64 = sizeof( uintptr_t ) == 8;
73  static const size_t mask = sz64 ? 0xF000000000000000uLL : 0xF0000000uL;
74  static const size_t offset = sz64 ? 60 : 28;
75 
76  // The hash only needs to be fast and simple, not necessarily accurate - a collision
77  // only makes things slower, not broken. BITMAPS is a pointer, so the most
78  // significant several bits are generally going to be the same for all. Just convert
79  // it to an integer and stuff the scale factor into those bits.
80  return
81  ( (uintptr_t)( id.bitmap ) & ~mask ) |
82  ( ( (uintptr_t)( id.scale ) & 0xF ) << offset );
83  }
84  };
85 }
86 
87 
88 static std::unordered_map<SCALED_BITMAP_ID, wxBitmap> s_ScaledBitmapCache;
89 
90 static std::mutex s_BitmapCacheMutex;
91 
92 
94 {
95  if( !s_BitmapStore )
96  {
97  wxFileName path( PATHS::GetStockDataPath() + wxT( "/resources" ), wxT( "images.zip" ) );
98  s_BitmapStore = std::make_unique<BITMAP_STORE>();
99  }
100 
101  return s_BitmapStore.get();
102 }
103 
104 
105 wxBitmap KiBitmap( BITMAPS aBitmap, int aHeightTag )
106 {
107  return GetBitmapStore()->GetBitmap( aBitmap, aHeightTag );
108 }
109 
110 
111 // TODO: Remove this once pcb_calculator images are moved into the main bitmap system
112 wxBitmap KiBitmap( const BITMAP_OPAQUE* aBitmap )
113 {
114  wxMemoryInputStream is( aBitmap->png, aBitmap->byteCount );
115  wxImage image( is, wxBITMAP_TYPE_PNG );
116  wxBitmap bitmap( image );
117 
118  return bitmap;
119 }
120 
121 
122 int KiIconScale( wxWindow* aWindow )
123 {
124  const int vert_size = aWindow->ConvertDialogToPixels( wxSize( 0, 8 ) ).y;
125 
126  // Autoscale won't exceed unity until the system has quite high resolution,
127  // because we don't want the icons to look obviously scaled on a system
128  // where it's easy to see it.
129 
130  if( vert_size > 34 ) return 8;
131  else if( vert_size > 29 ) return 7;
132  else if( vert_size > 24 ) return 6;
133  else return 4;
134 }
135 
136 
137 static int get_scale_factor( wxWindow* aWindow )
138 {
139  int requested_scale = Pgm().GetCommonSettings()->m_Appearance.icon_scale;
140 
141  if( requested_scale > 0 )
142  return requested_scale;
143  else
144  return KiIconScale( aWindow );
145 }
146 
147 
148 wxBitmap KiScaledBitmap( BITMAPS aBitmap, wxWindow* aWindow, int aHeight )
149 {
150  // Bitmap conversions are cached because they can be slow.
151  const int scale = get_scale_factor( aWindow );
152 
153  SCALED_BITMAP_ID id = { static_cast<BITMAPS>( aBitmap ), scale };
154 
155  std::lock_guard<std::mutex> guard( s_BitmapCacheMutex );
156  auto it = s_ScaledBitmapCache.find( id );
157 
158  if( it != s_ScaledBitmapCache.end() )
159  {
160  return it->second;
161  }
162  else
163  {
164  wxBitmap bitmap = GetBitmapStore()->GetBitmapScaled( aBitmap, scale, aHeight );
165  return s_ScaledBitmapCache.emplace( id, bitmap ).first->second;
166  }
167 }
168 
169 
171 {
172  std::lock_guard<std::mutex> guard( s_BitmapCacheMutex );
173  s_ScaledBitmapCache.clear();
174 }
175 
176 
177 wxBitmap KiScaledBitmap( const wxBitmap& aBitmap, wxWindow* aWindow )
178 {
179  const int scale = get_scale_factor( aWindow );
180 
181  if( scale == 4 )
182  {
183  return wxBitmap( aBitmap );
184  }
185  else
186  {
187  wxImage image = aBitmap.ConvertToImage();
188  image.Rescale( scale * image.GetWidth() / 4, scale * image.GetHeight() / 4,
189  wxIMAGE_QUALITY_BILINEAR );
190 
191  return wxBitmap( image );
192  }
193 }
194 
195 
196 wxBitmap* KiBitmapNew( BITMAPS aBitmap )
197 {
198  wxBitmap* bitmap = new wxBitmap( GetBitmapStore()->GetBitmap( aBitmap ) );
199 
200  return bitmap;
201 }
202 
203 
204 bool SaveCanvasImageToFile( EDA_DRAW_FRAME* aFrame, const wxString& aFileName,
205  BITMAP_TYPE aBitmapType )
206 {
207  wxCHECK( aFrame != nullptr, false );
208 
209  bool retv = true;
210 
211  // Make a screen copy of the canvas:
212  wxSize image_size = aFrame->GetCanvas()->GetClientSize();
213 
214  wxClientDC dc( aFrame->GetCanvas() );
215  wxBitmap bitmap( image_size.x, image_size.y );
216  wxMemoryDC memdc;
217 
218  memdc.SelectObject( bitmap );
219  memdc.Blit( 0, 0, image_size.x, image_size.y, &dc, 0, 0 );
220  memdc.SelectObject( wxNullBitmap );
221 
222  wxImage image = bitmap.ConvertToImage();
223 
224  wxBitmapType type = wxBITMAP_TYPE_PNG;
225  switch( aBitmapType )
226  {
227  case BITMAP_TYPE::PNG: type = wxBITMAP_TYPE_PNG; break;
228  case BITMAP_TYPE::BMP: type = wxBITMAP_TYPE_BMP; break;
229  case BITMAP_TYPE::JPG: type = wxBITMAP_TYPE_JPEG; break;
230  }
231 
232  if( !image.SaveFile( aFileName, type ) )
233  retv = false;
234 
235  image.Destroy();
236  return retv;
237 }
238 
239 
240 void AddBitmapToMenuItem( wxMenuItem* aMenu, const wxBitmap& aImage )
241 {
242  // Retrieve the global application show icon option:
243  bool useImagesInMenus = Pgm().GetCommonSettings()->m_Appearance.use_icons_in_menus;
244 
245  wxItemKind menu_type = aMenu->GetKind();
246 
247  if( useImagesInMenus && menu_type != wxITEM_CHECK && menu_type != wxITEM_RADIO )
248  {
249  aMenu->SetBitmap( aImage );
250  }
251 }
252 
253 
254 wxMenuItem* AddMenuItem( wxMenu* aMenu, int aId, const wxString& aText,
255  const wxBitmap& aImage, wxItemKind aType = wxITEM_NORMAL )
256 {
257  wxMenuItem* item = new wxMenuItem( aMenu, aId, aText, wxEmptyString, aType );
258  AddBitmapToMenuItem( item, aImage );
259 
260  aMenu->Append( item );
261 
262  return item;
263 }
264 
265 
266 wxMenuItem* AddMenuItem( wxMenu* aMenu, int aId, const wxString& aText,
267  const wxString& aHelpText, const wxBitmap& aImage,
268  wxItemKind aType = wxITEM_NORMAL )
269 {
270  wxMenuItem* item = new wxMenuItem( aMenu, aId, aText, aHelpText, aType );
271  AddBitmapToMenuItem( item, aImage );
272 
273  aMenu->Append( item );
274 
275  return item;
276 }
277 
278 
279 wxMenuItem* AddMenuItem( wxMenu* aMenu, wxMenu* aSubMenu, int aId,
280  const wxString& aText, const wxBitmap& aImage )
281 {
282  wxMenuItem* item = new wxMenuItem( aMenu, aId, aText );
283  item->SetSubMenu( aSubMenu );
284  AddBitmapToMenuItem( item, aImage );
285 
286  aMenu->Append( item );
287 
288  return item;
289 }
290 
291 
292 wxMenuItem* AddMenuItem( wxMenu* aMenu, wxMenu* aSubMenu, int aId,
293  const wxString& aText, const wxString& aHelpText,
294  const wxBitmap& aImage )
295 {
296  wxMenuItem* item = new wxMenuItem( aMenu, aId, aText, aHelpText );
297  item->SetSubMenu( aSubMenu );
298  AddBitmapToMenuItem( item, aImage );
299 
300  aMenu->Append( item );
301 
302  return item;
303 }
PNG memory record (file in memory).
Definition: bitmap_opaque.h:25
wxBitmap GetBitmapScaled(BITMAPS aBitmapId, int aScaleFactor, int aHeight=-1)
Retrieves a bitmap from the given bitmap id, scaled to a given factor.
static std::unordered_map< SCALED_BITMAP_ID, wxBitmap > s_ScaledBitmapCache
Definition: bitmap.cpp:88
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:254
static int get_scale_factor(wxWindow *aWindow)
Definition: bitmap.cpp:137
virtual EDA_DRAW_PANEL_GAL * GetCanvas() const
Return a pointer to GAL-based canvas of given EDA draw frame.
Helper to retrieve bitmaps while handling icon themes and scaling.
Definition: bitmap_store.h:43
int KiIconScale(wxWindow *aWindow)
Return the automatic scale factor that would be used for a given window by KiScaledBitmap and KiScale...
Definition: bitmap.cpp:122
BITMAP_TYPE
Definition: bitmap_types.h:41
Definition: bitmap.cpp:64
void ClearScaledBitmapCache()
Wipes out the scaled bitmap cache so that the icon theme can be changed.
Definition: bitmap.cpp:170
The base class for create windows for drawing purpose.
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:106
static wxString GetStockDataPath(bool aRespectRunFromBuildDir=true)
Gets the stock (install) data path, which is the base path for things like scripting,...
Definition: paths.cpp:141
const unsigned char * png
Definition: bitmap_opaque.h:27
result_type operator()(argument_type const &id) const noexcept
Definition: bitmap.cpp:70
static std::unique_ptr< BITMAP_STORE > s_BitmapStore
Definition: bitmap.cpp:50
void AddBitmapToMenuItem(wxMenuItem *aMenu, const wxBitmap &aImage)
Add a bitmap to a menuitem.
Definition: bitmap.cpp:240
bool SaveCanvasImageToFile(EDA_DRAW_FRAME *aFrame, const wxString &aFileName, BITMAP_TYPE aBitmapType)
Save the current view as an image file.
Definition: bitmap.cpp:204
SCALED_BITMAP_ID argument_type
Definition: bitmap.cpp:67
Base window classes and related definitions.
wxBitmap KiBitmap(BITMAPS aBitmap, int aHeightTag)
Construct a wxBitmap from an image identifier Returns the image from the active theme if the image ha...
Definition: bitmap.cpp:105
wxBitmap * KiBitmapNew(BITMAPS aBitmap)
Allocate a wxBitmap on heap from a memory record, held in a BITMAPS.
Definition: bitmap.cpp:196
BITMAPS bitmap
Definition: bitmap.cpp:54
const int scale
see class PGM_BASE
static std::mutex s_BitmapCacheMutex
Definition: bitmap.cpp:90
BITMAPS
A list of all bitmap identifiers.
Definition: bitmaps_list.h:32
wxBitmap GetBitmap(BITMAPS aBitmapId, int aHeight=-1)
Retrieves a bitmap from the given bitmap id.
bool operator==(SCALED_BITMAP_ID const &other) const noexcept
Definition: bitmap.cpp:57
wxBitmap KiScaledBitmap(BITMAPS aBitmap, wxWindow *aWindow, int aHeight)
Construct a wxBitmap from a memory record, scaling it if device DPI demands it.
Definition: bitmap.cpp:148
BITMAP_STORE * GetBitmapStore()
Definition: bitmap.cpp:93