29 #include "svg_utils.h"
32 #ifndef ocpnUSE_wxBitmapBundle
33 #include "wxSVG/svg.h"
35 #include <wx/bmpbndl.h>
38 #include <wx/filename.h>
41 #ifdef __OCPN__ANDROID__
42 #include "androidUTIL.h"
46 #include "pugixml.hpp"
47 #include "model/base_platform.h"
48 #include "model/routeman.h"
50 wxBitmap LoadSVG(
const wxString filename,
const unsigned int width,
51 const unsigned int height, wxBitmap* default_bitmap,
54 #ifndef ocpnUSE_wxBitmapBundle
55 #ifdef __OCPN__ANDROID__
56 return loadAndroidSVG(filename, width, height);
59 if (svgDoc.Load(filename))
60 return wxBitmap(svgDoc.Render(width, height, NULL,
true,
true));
62 return wxBitmap(width, height);
65 #ifdef __OCPN__ANDROID__
66 return loadAndroidSVG(filename, width, height);
68 wxSize s(width, height);
69 if (wxFileExists(filename)) {
72 if (use_cache && SVGBitmapCache::GetInstance().HasKey(
73 key = SVGBitmapCache::GetInstance().MakeKey(
74 filename, width, height))) {
75 bmp = SVGBitmapCache::GetInstance().Get(key);
77 bmp = wxBitmapBundle::FromSVGFile(filename, s).GetBitmap(s);
79 SVGBitmapCache::GetInstance().Add(key, bmp);
87 return *default_bitmap;
94 return wxBitmap(width, height);
99 int str_ends_with(
const char* str,
const char* suffix) {
100 if (str == NULL || suffix == NULL)
return 0;
102 size_t str_len = strlen(str);
103 size_t suffix_len = strlen(suffix);
105 if (suffix_len > str_len)
return 0;
107 return 0 == strncmp(str + str_len - suffix_len, suffix, suffix_len);
114 unsigned int get_px_length(
const char* val) {
117 num = std::stoi(val);
118 }
catch (std::invalid_argument&) {
120 }
catch (std::out_of_range& ) {
127 if (str_ends_with(val,
"mm")) {
128 return (
unsigned int)((float)num * SVG_MM_TO_PX);
129 }
else if (str_ends_with(val,
"cm")) {
130 return (
unsigned int)((float)num * SVG_CM_TO_PX);
131 }
else if (str_ends_with(val,
"in")) {
132 return (
unsigned int)((float)num * SVG_CM_TO_PX);
133 }
else if (str_ends_with(val,
"pt")) {
134 return (
unsigned int)((float)num * SVG_PT_TO_PX);
139 bool SVGDocumentPixelSize(
const wxString filename,
unsigned int& width,
140 unsigned int& height) {
143 pugi::xml_document svgDoc;
144 if (svgDoc.load_file(filename.fn_str())) {
145 pugi::xml_node svgNode = svgDoc.child(
"svg");
146 for (pugi::xml_attribute attr = svgNode.first_attribute(); attr;
147 attr = attr.next_attribute()) {
148 const char* pca = attr.name();
149 if (!strcmp(pca,
"width")) {
150 width = get_px_length(attr.as_string());
151 }
else if (!strcmp(pca,
"height")) {
152 height = get_px_length(attr.as_string());
161 unsigned int SVGPixelsToDisplay(
unsigned int svg_px) {
162 return g_BasePlatform->GetDisplayDPmm() * SVG_MM_TO_IN / SVG_IN_TO_PX * svg_px *
163 g_ChartScaleFactorExp;
166 SVGBitmapCache::SVGBitmapCache() {
167 wxFileName iconcachedir;
168 iconcachedir.SetName(
"iconCacheSVG");
171 if (!wxDir::Exists(iconcachedir.GetFullPath())) {
172 wxFileName::Mkdir(iconcachedir.GetFullPath());
174 cache_directory = iconcachedir.GetFullPath();
177 std::string SVGBitmapCache::MakeKey(wxString file_path,
const int width,
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(),
'|',
'_');
186 std::replace(file_path.begin(), file_path.end(),
'?',
'_');
187 std::replace(file_path.begin(), file_path.end(),
'*',
'_');
189 std::ostringstream ss;
190 ss << file_path <<
"_" << width <<
"x" << height;
194 void SVGBitmapCache::Add(
const wxString key,
const wxBitmap bmp) {
199 items.emplace(key, bmp);
202 fn.SetPath(cache_directory);
203 bmp.SaveFile(fn.GetFullPath(), wxBITMAP_TYPE_PNG);
207 wxBitmap SVGBitmapCache::Get(
const wxString key) {
208 wxBitmap bmp = wxNullBitmap;
210 std::unordered_map<std::string, wxBitmap>::const_iterator i =
211 items.find(key.ToStdString());
212 if (i != items.end()) {
217 fn.SetPath(cache_directory);
218 if (fn.FileExists()) {
219 bmp.LoadFile(fn.GetFullPath(), wxBITMAP_TYPE_PNG);
221 items.emplace(key, bmp);
231 bool SVGBitmapCache::HasKey(
const wxString key) {
234 if (items.find(key.ToStdString()) != items.end()) {
239 fn.SetPath(cache_directory);
240 if (fn.FileExists()) {
243 bmp.LoadFile(fn.GetFullPath(), wxBITMAP_TYPE_PNG);
245 items.emplace(key, bmp);