32#ifndef ocpnUSE_wxBitmapBundle
35#include <wx/bmpbndl.h>
38#include <wx/filename.h>
41#ifdef __OCPN__ANDROID__
42#include "androidUTIL.h"
47#include "base_platform.h"
49wxBitmap LoadSVG(
const wxString filename,
const unsigned int width,
50 const unsigned int height, wxBitmap* default_bitmap,
53#ifndef ocpnUSE_wxBitmapBundle
54#ifdef __OCPN__ANDROID__
55 return loadAndroidSVG(filename, width, height);
58 if (svgDoc.Load(filename))
59 return wxBitmap(svgDoc.Render(width, height, NULL,
true,
true));
61 return wxBitmap(width, height);
64#ifdef __OCPN__ANDROID__
65 return loadAndroidSVG(filename, width, height);
67 wxSize s(width, height);
68 if (wxFileExists(filename)) {
71 if (use_cache && SVGBitmapCache::GetInstance().HasKey(
72 key = SVGBitmapCache::GetInstance().MakeKey(
73 filename, width, height))) {
74 bmp = SVGBitmapCache::GetInstance().Get(key);
76 bmp = wxBitmapBundle::FromSVGFile(filename, s).GetBitmap(s);
78 SVGBitmapCache::GetInstance().Add(key, bmp);
86 return *default_bitmap;
93 return wxBitmap(width, height);
98int str_ends_with(
const char* str,
const char* suffix) {
99 if (str == NULL || suffix == NULL)
return 0;
101 size_t str_len = strlen(str);
102 size_t suffix_len = strlen(suffix);
104 if (suffix_len > str_len)
return 0;
106 return 0 == strncmp(str + str_len - suffix_len, suffix, suffix_len);
113unsigned int get_px_length(
const char* val) {
116 num = std::stoi(val);
117 }
catch (std::invalid_argument
const& ex) {
119 }
catch (std::out_of_range
const& ex) {
126 if (str_ends_with(val,
"mm")) {
127 return (
unsigned int)((float)num * SVG_MM_TO_PX);
128 }
else if (str_ends_with(val,
"cm")) {
129 return (
unsigned int)((float)num * SVG_CM_TO_PX);
130 }
else if (str_ends_with(val,
"in")) {
131 return (
unsigned int)((float)num * SVG_CM_TO_PX);
132 }
else if (str_ends_with(val,
"pt")) {
133 return (
unsigned int)((float)num * SVG_PT_TO_PX);
138bool SVGDocumentPixelSize(
const wxString filename,
unsigned int& width,
139 unsigned int& height) {
140 pugi::xml_document svgDoc;
141 if (svgDoc.load_file(filename.fn_str())) {
142 pugi::xml_node svgNode = svgDoc.child(
"svg");
143 for (pugi::xml_attribute attr = svgNode.first_attribute(); attr;
144 attr = attr.next_attribute()) {
145 const char* pca = attr.name();
146 if (!strcmp(pca,
"width")) {
147 width = get_px_length(attr.as_string());
148 }
else if (!strcmp(pca,
"height")) {
149 height = get_px_length(attr.as_string());
157extern float g_ChartScaleFactorExp;
159unsigned int SVGPixelsToDisplay(
unsigned int svg_px) {
160 return g_BasePlatform->GetDisplayDPmm() * SVG_MM_TO_IN / SVG_IN_TO_PX * svg_px *
161 g_ChartScaleFactorExp;
164SVGBitmapCache::SVGBitmapCache() {
165 wxFileName iconcachedir;
166 iconcachedir.SetName(
"iconCache");
167 iconcachedir.SetPath(g_BasePlatform->GetPrivateDataDir());
169 if (!wxDir::Exists(iconcachedir.GetFullPath())) {
170 wxFileName::Mkdir(iconcachedir.GetFullPath());
172 cache_directory = iconcachedir.GetFullPath();
175std::string SVGBitmapCache::MakeKey(wxString file_path,
const int width,
177 std::replace(file_path.begin(), file_path.end(),
':',
'_');
178 std::replace(file_path.begin(), file_path.end(),
'/',
'_');
179 std::replace(file_path.begin(), file_path.end(),
'\\',
'_');
180 std::replace(file_path.begin(), file_path.end(),
'>',
'_');
181 std::replace(file_path.begin(), file_path.end(),
'<',
'_');
182 std::replace(file_path.begin(), file_path.end(),
'"',
'_');
183 std::replace(file_path.begin(), file_path.end(),
'|',
'_');
184 std::replace(file_path.begin(), file_path.end(),
'?',
'_');
185 std::replace(file_path.begin(), file_path.end(),
'*',
'_');
187 std::ostringstream ss;
188 ss << file_path <<
"_" << width <<
"x" << height;
192void SVGBitmapCache::Add(
const wxString key,
const wxBitmap bmp) {
197 items.emplace(key, bmp);
200 fn.SetPath(cache_directory);
201 bmp.SaveFile(fn.GetFullPath(), wxBITMAP_TYPE_PNG);
205wxBitmap SVGBitmapCache::Get(
const wxString key) {
206 wxBitmap bmp = wxNullBitmap;
208 std::unordered_map<std::string, wxBitmap>::const_iterator i =
209 items.find(key.ToStdString());
210 if (i != items.end()) {
215 fn.SetPath(cache_directory);
216 if (fn.FileExists()) {
217 bmp.LoadFile(fn.GetFullPath(), wxBITMAP_TYPE_PNG);
219 items.emplace(key, bmp);
229bool SVGBitmapCache::HasKey(
const wxString key) {
232 if (items.find(key.ToStdString()) != items.end()) {
237 fn.SetPath(cache_directory);
238 if (fn.FileExists()) {
241 bmp.LoadFile(fn.GetFullPath(), wxBITMAP_TYPE_PNG);
243 items.emplace(key, bmp);