25#include "androidUTIL.h"
29#include <wx/filename.h>
33#ifndef ocpnUSE_wxBitmapBundle
36#include <wx/bmpbndl.h>
46#define SVG_IN_TO_PT 72
47#define SVG_IN_TO_PX 96
48#define SVG_PT_TO_IN 1 / 72
49#define SVG_PX_TO_IN 1 / 96
50#define SVG_PT_TO_PX 96 / 72
51#define SVG_MM_TO_PX 3.7795275591
52#define SVG_PX_TO_MM 0.2645833333
53#define SVG_MM_TO_PT 2.8346456693
54#define SVG_PT_TO_MM 0.3527777778
55#define SVG_CM_TO_PX 37.795275591
56#define SVG_CM_TO_PT 28.346456693
57#define SVG_MM_TO_IN 25.4
59wxBitmap
LoadSVG(
const wxString filename,
const unsigned int width,
60 const unsigned int height, wxBitmap* default_bitmap,
63#ifndef ocpnUSE_wxBitmapBundle
65 return loadAndroidSVG(filename, width, height);
68 if (svgDoc.Load(filename))
69 return wxBitmap(svgDoc.Render(width, height, NULL,
true,
true));
71 return wxBitmap(width, height);
75 return loadAndroidSVG(filename, width, height);
77 wxSize s(width, height);
78 if (wxFileExists(filename)) {
81 if (use_cache && SVGBitmapCache::GetInstance().HasKey(
82 key = SVGBitmapCache::GetInstance().MakeKey(
83 filename, width, height))) {
84 bmp = SVGBitmapCache::GetInstance().Get(key);
86 bmp = wxBitmapBundle::FromSVGFile(filename, s).GetBitmap(s);
88 SVGBitmapCache::GetInstance().Add(key, bmp);
96 return *default_bitmap;
103 return wxBitmap(width, height);
108int str_ends_with(
const char* str,
const char* suffix) {
109 if (str == NULL || suffix == NULL)
return 0;
111 size_t str_len = strlen(str);
112 size_t suffix_len = strlen(suffix);
114 if (suffix_len > str_len)
return 0;
116 return 0 == strncmp(str + str_len - suffix_len, suffix, suffix_len);
123unsigned int get_px_length(
const char* val) {
126 num = std::stoi(val);
127 }
catch (std::invalid_argument&) {
129 }
catch (std::out_of_range&) {
136 if (str_ends_with(val,
"mm")) {
137 return (
unsigned int)((float)num * SVG_MM_TO_PX);
138 }
else if (str_ends_with(val,
"cm")) {
139 return (
unsigned int)((float)num * SVG_CM_TO_PX);
140 }
else if (str_ends_with(val,
"in")) {
141 return (
unsigned int)((float)num * SVG_CM_TO_PX);
142 }
else if (str_ends_with(val,
"pt")) {
143 return (
unsigned int)((float)num * SVG_PT_TO_PX);
149 unsigned int& height) {
152 float viewBoxWidth = 0, viewBoxHeight = 0;
154 if (svgDoc.load_file(filename.fn_str())) {
158 if (
const char* viewBox = svgNode.attribute(
"viewBox").value()) {
159 std::istringstream iss(viewBox);
161 iss >> minX >> minY >> viewBoxWidth >> viewBoxHeight;
166 attr = attr.next_attribute()) {
167 const char* pca = attr.name();
168 if (!strcmp(pca,
"width")) {
169 width = get_px_length(attr.as_string());
170 }
else if (!strcmp(pca,
"height")) {
171 height = get_px_length(attr.as_string());
175 if (width == 0 && height == 0) {
176 if (viewBoxWidth > 0 && viewBoxHeight > 0) {
178 width = viewBoxWidth;
179 height = viewBoxHeight;
185 }
else if (width == 0) {
186 if (viewBoxWidth > 0 && viewBoxHeight > 0) {
187 width = height * (viewBoxWidth / viewBoxHeight);
191 }
else if (height == 0) {
192 if (viewBoxWidth > 0 && viewBoxHeight > 0) {
193 height = width * (viewBoxHeight / viewBoxWidth);
203 return g_BasePlatform->GetDisplayDPmm() * SVG_MM_TO_IN / SVG_IN_TO_PX *
209 auto path = fs::path(
g_BasePlatform->GetSharedDataDir().ToStdString()) /
210 "uidata" /
"MUI_flat" / svg_file;
212 return LoadSVG(path.string(), size, size);
215SVGBitmapCache::SVGBitmapCache() {
216 wxFileName iconcachedir;
217 iconcachedir.SetName(
"iconCacheSVG");
220 if (!wxDir::Exists(iconcachedir.GetFullPath())) {
221 wxFileName::Mkdir(iconcachedir.GetFullPath());
223 cache_directory = iconcachedir.GetFullPath();
226std::string SVGBitmapCache::MakeKey(wxString file_path,
const int width,
228 std::replace(file_path.begin(), file_path.end(),
':',
'_');
229 std::replace(file_path.begin(), file_path.end(),
'/',
'_');
230 std::replace(file_path.begin(), file_path.end(),
'\\',
'_');
231 std::replace(file_path.begin(), file_path.end(),
'>',
'_');
232 std::replace(file_path.begin(), file_path.end(),
'<',
'_');
233 std::replace(file_path.begin(), file_path.end(),
'"',
'_');
234 std::replace(file_path.begin(), file_path.end(),
'|',
'_');
235 std::replace(file_path.begin(), file_path.end(),
'?',
'_');
236 std::replace(file_path.begin(), file_path.end(),
'*',
'_');
238 std::ostringstream ss;
239 ss << file_path <<
"_" << width <<
"x" << height;
243void SVGBitmapCache::Add(
const wxString key,
const wxBitmap bmp) {
248 items.emplace(key, bmp);
251 fn.SetPath(cache_directory);
252 bmp.SaveFile(fn.GetFullPath(), wxBITMAP_TYPE_PNG);
256wxBitmap SVGBitmapCache::Get(
const wxString key) {
257 wxBitmap bmp = wxNullBitmap;
259 std::unordered_map<std::string, wxBitmap>::const_iterator i =
260 items.find(key.ToStdString());
261 if (i != items.end()) {
266 fn.SetPath(cache_directory);
267 if (fn.FileExists()) {
268 bmp.LoadFile(fn.GetFullPath(), wxBITMAP_TYPE_PNG);
270 items.emplace(key, bmp);
280bool SVGBitmapCache::HasKey(
const wxString key) {
283 if (items.find(key.ToStdString()) != items.end()) {
288 fn.SetPath(cache_directory);
289 if (fn.FileExists()) {
292 bmp.LoadFile(fn.GetFullPath(), wxBITMAP_TYPE_PNG);
294 items.emplace(key, bmp);
float g_ChartScaleFactorExp
Global instance.
wxBitmap LoadSVG(const wxString filename, const unsigned int width, const unsigned int height, wxBitmap *default_bitmap, bool use_cache)
Load SVG file and return it's bitmap representation of requested size In case file can't be loaded an...
wxBitmap LoadSvgStdIcon(const std::string &svg_file, const wxWindow *w, bool touch)
Load an svg icon from standard path, roughly scaled to the height of a char.
bool SVGDocumentPixelSize(const wxString filename, unsigned int &width, unsigned int &height)
Return the size of the SVG document in standard 96 DPI pixels https://developer.mozilla....
unsigned int SVGPixelsToDisplay(unsigned int svg_px)
Recalculate the length in standard 96 DPI pixels to actual display pixels.