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"
50wxBitmap 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);
99int 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);
114unsigned 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);
139bool SVGDocumentPixelSize(
const wxString filename,
unsigned int& width,
140 unsigned int& height) {
143 float viewBoxWidth = 0, viewBoxHeight = 0;
145 if (svgDoc.load_file(filename.fn_str())) {
149 if (
const char* viewBox = svgNode.attribute(
"viewBox").value()) {
150 std::istringstream iss(viewBox);
152 iss >> minX >> minY >> viewBoxWidth >> viewBoxHeight;
157 attr = attr.next_attribute()) {
158 const char* pca = attr.name();
159 if (!strcmp(pca,
"width")) {
160 width = get_px_length(attr.as_string());
161 }
else if (!strcmp(pca,
"height")) {
162 height = get_px_length(attr.as_string());
166 if (width == 0 && height == 0) {
167 if (viewBoxWidth > 0 && viewBoxHeight > 0) {
169 width = viewBoxWidth;
170 height = viewBoxHeight;
176 }
else if (width == 0) {
177 if (viewBoxWidth > 0 && viewBoxHeight > 0) {
178 width = height * (viewBoxWidth / viewBoxHeight);
182 }
else if (height == 0) {
183 if (viewBoxWidth > 0 && viewBoxHeight > 0) {
184 height = width * (viewBoxHeight / viewBoxWidth);
195unsigned int SVGPixelsToDisplay(
unsigned int svg_px) {
196 return g_BasePlatform->GetDisplayDPmm() * SVG_MM_TO_IN / SVG_IN_TO_PX *
197 svg_px * g_ChartScaleFactorExp;
200SVGBitmapCache::SVGBitmapCache() {
201 wxFileName iconcachedir;
202 iconcachedir.SetName(
"iconCacheSVG");
205 if (!wxDir::Exists(iconcachedir.GetFullPath())) {
206 wxFileName::Mkdir(iconcachedir.GetFullPath());
208 cache_directory = iconcachedir.GetFullPath();
211std::string SVGBitmapCache::MakeKey(wxString file_path,
const int width,
213 std::replace(file_path.begin(), file_path.end(),
':',
'_');
214 std::replace(file_path.begin(), file_path.end(),
'/',
'_');
215 std::replace(file_path.begin(), file_path.end(),
'\\',
'_');
216 std::replace(file_path.begin(), file_path.end(),
'>',
'_');
217 std::replace(file_path.begin(), file_path.end(),
'<',
'_');
218 std::replace(file_path.begin(), file_path.end(),
'"',
'_');
219 std::replace(file_path.begin(), file_path.end(),
'|',
'_');
220 std::replace(file_path.begin(), file_path.end(),
'?',
'_');
221 std::replace(file_path.begin(), file_path.end(),
'*',
'_');
223 std::ostringstream ss;
224 ss << file_path <<
"_" << width <<
"x" << height;
228void SVGBitmapCache::Add(
const wxString key,
const wxBitmap bmp) {
233 items.emplace(key, bmp);
236 fn.SetPath(cache_directory);
237 bmp.SaveFile(fn.GetFullPath(), wxBITMAP_TYPE_PNG);
241wxBitmap SVGBitmapCache::Get(
const wxString key) {
242 wxBitmap bmp = wxNullBitmap;
244 std::unordered_map<std::string, wxBitmap>::const_iterator i =
245 items.find(key.ToStdString());
246 if (i != items.end()) {
251 fn.SetPath(cache_directory);
252 if (fn.FileExists()) {
253 bmp.LoadFile(fn.GetFullPath(), wxBITMAP_TYPE_PNG);
255 items.emplace(key, bmp);
265bool SVGBitmapCache::HasKey(
const wxString key) {
268 if (items.find(key.ToStdString()) != items.end()) {
273 fn.SetPath(cache_directory);
274 if (fn.FileExists()) {
277 bmp.LoadFile(fn.GetFullPath(), wxBITMAP_TYPE_PNG);
279 items.emplace(key, bmp);