32#ifndef ocpnUSE_wxBitmapBundle
35#include <wx/bmpbndl.h>
38#include <wx/filename.h>
41#ifdef __OCPN__ANDROID__
42#include "androidUTIL.h"
47#include "model/base_platform.h"
48#include "model/routeman.h"
50#define SVG_IN_TO_PT 72
51#define SVG_IN_TO_PX 96
52#define SVG_PT_TO_IN 1 / 72
53#define SVG_PX_TO_IN 1 / 96
54#define SVG_PT_TO_PX 96 / 72
55#define SVG_MM_TO_PX 3.7795275591
56#define SVG_PX_TO_MM 0.2645833333
57#define SVG_MM_TO_PT 2.8346456693
58#define SVG_PT_TO_MM 0.3527777778
59#define SVG_CM_TO_PX 37.795275591
60#define SVG_CM_TO_PT 28.346456693
61#define SVG_MM_TO_IN 25.4
65wxBitmap LoadSVG(
const wxString filename,
const unsigned int width,
66 const unsigned int height, wxBitmap* default_bitmap,
69#ifndef ocpnUSE_wxBitmapBundle
71 return loadAndroidSVG(filename, width, height);
74 if (svgDoc.Load(filename))
75 return wxBitmap(svgDoc.Render(width, height, NULL,
true,
true));
77 return wxBitmap(width, height);
81 return loadAndroidSVG(filename, width, height);
83 wxSize s(width, height);
84 if (wxFileExists(filename)) {
87 if (use_cache && SVGBitmapCache::GetInstance().HasKey(
88 key = SVGBitmapCache::GetInstance().MakeKey(
89 filename, width, height))) {
90 bmp = SVGBitmapCache::GetInstance().Get(key);
92 bmp = wxBitmapBundle::FromSVGFile(filename, s).GetBitmap(s);
94 SVGBitmapCache::GetInstance().Add(key, bmp);
101 if (default_bitmap) {
102 return *default_bitmap;
109 return wxBitmap(width, height);
114int str_ends_with(
const char* str,
const char* suffix) {
115 if (str == NULL || suffix == NULL)
return 0;
117 size_t str_len = strlen(str);
118 size_t suffix_len = strlen(suffix);
120 if (suffix_len > str_len)
return 0;
122 return 0 == strncmp(str + str_len - suffix_len, suffix, suffix_len);
129unsigned int get_px_length(
const char* val) {
132 num = std::stoi(val);
133 }
catch (std::invalid_argument&) {
135 }
catch (std::out_of_range&) {
142 if (str_ends_with(val,
"mm")) {
143 return (
unsigned int)((float)num * SVG_MM_TO_PX);
144 }
else if (str_ends_with(val,
"cm")) {
145 return (
unsigned int)((float)num * SVG_CM_TO_PX);
146 }
else if (str_ends_with(val,
"in")) {
147 return (
unsigned int)((float)num * SVG_CM_TO_PX);
148 }
else if (str_ends_with(val,
"pt")) {
149 return (
unsigned int)((float)num * SVG_PT_TO_PX);
154bool SVGDocumentPixelSize(
const wxString filename,
unsigned int& width,
155 unsigned int& height) {
158 float viewBoxWidth = 0, viewBoxHeight = 0;
160 if (svgDoc.load_file(filename.fn_str())) {
164 if (
const char* viewBox = svgNode.attribute(
"viewBox").value()) {
165 std::istringstream iss(viewBox);
167 iss >> minX >> minY >> viewBoxWidth >> viewBoxHeight;
172 attr = attr.next_attribute()) {
173 const char* pca = attr.name();
174 if (!strcmp(pca,
"width")) {
175 width = get_px_length(attr.as_string());
176 }
else if (!strcmp(pca,
"height")) {
177 height = get_px_length(attr.as_string());
181 if (width == 0 && height == 0) {
182 if (viewBoxWidth > 0 && viewBoxHeight > 0) {
184 width = viewBoxWidth;
185 height = viewBoxHeight;
191 }
else if (width == 0) {
192 if (viewBoxWidth > 0 && viewBoxHeight > 0) {
193 width = height * (viewBoxWidth / viewBoxHeight);
197 }
else if (height == 0) {
198 if (viewBoxWidth > 0 && viewBoxHeight > 0) {
199 height = width * (viewBoxHeight / viewBoxWidth);
208unsigned int SVGPixelsToDisplay(
unsigned int svg_px) {
209 return g_BasePlatform->GetDisplayDPmm() * SVG_MM_TO_IN / SVG_IN_TO_PX *
210 svg_px * g_ChartScaleFactorExp;
213wxBitmap LoadSvgStdIcon(
const std::string& svg_file,
const wxWindow* w,
215 auto path = fs::path(g_BasePlatform->GetSharedDataDir().ToStdString()) /
216 "uidata" /
"MUI_flat" / svg_file;
218 return LoadSVG(path.string(), size, size);
221SVGBitmapCache::SVGBitmapCache() {
222 wxFileName iconcachedir;
223 iconcachedir.SetName(
"iconCacheSVG");
226 if (!wxDir::Exists(iconcachedir.GetFullPath())) {
227 wxFileName::Mkdir(iconcachedir.GetFullPath());
229 cache_directory = iconcachedir.GetFullPath();
232std::string SVGBitmapCache::MakeKey(wxString file_path,
const int width,
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(),
'\\',
'_');
237 std::replace(file_path.begin(), file_path.end(),
'>',
'_');
238 std::replace(file_path.begin(), file_path.end(),
'<',
'_');
239 std::replace(file_path.begin(), file_path.end(),
'"',
'_');
240 std::replace(file_path.begin(), file_path.end(),
'|',
'_');
241 std::replace(file_path.begin(), file_path.end(),
'?',
'_');
242 std::replace(file_path.begin(), file_path.end(),
'*',
'_');
244 std::ostringstream ss;
245 ss << file_path <<
"_" << width <<
"x" << height;
249void SVGBitmapCache::Add(
const wxString key,
const wxBitmap bmp) {
254 items.emplace(key, bmp);
257 fn.SetPath(cache_directory);
258 bmp.SaveFile(fn.GetFullPath(), wxBITMAP_TYPE_PNG);
262wxBitmap SVGBitmapCache::Get(
const wxString key) {
263 wxBitmap bmp = wxNullBitmap;
265 std::unordered_map<std::string, wxBitmap>::const_iterator i =
266 items.find(key.ToStdString());
267 if (i != items.end()) {
272 fn.SetPath(cache_directory);
273 if (fn.FileExists()) {
274 bmp.LoadFile(fn.GetFullPath(), wxBITMAP_TYPE_PNG);
276 items.emplace(key, bmp);
286bool SVGBitmapCache::HasKey(
const wxString key) {
289 if (items.find(key.ToStdString()) != items.end()) {
294 fn.SetPath(cache_directory);
295 if (fn.FileExists()) {
298 bmp.LoadFile(fn.GetFullPath(), wxBITMAP_TYPE_PNG);
300 items.emplace(key, bmp);