Commit 5ea774f4 authored by Dennis Nienhüser's avatar Dennis Nienhüser

Use .svg icons instead of .png for (most of) Vector OSM

GeoDataIconStyle still caches bitmap versions of icons for efficiency,
but for vector formats a size hint can now be set. This results in
sharp bitmap versions of vector images for both icon().size() and
scaledIcon().size() sizes.
parent 3770fe69
......@@ -13,13 +13,19 @@ FILE (GLOB BITMAP_FILES bitmaps/*.png)
install (FILES ${BITMAP_FILES}
DESTINATION ${MARBLE_DATA_INSTALL_PATH}/bitmaps)
INSTALL (DIRECTORY svg/osmcarto/svg
DESTINATION ${MARBLE_DATA_INSTALL_PATH}/svg/osmcarto
FILES_MATCHING PATTERN "*.svg"
PATTERN "svgorig" EXCLUDE)
FILE (GLOB BITMAP_EDITARROW_FILES bitmaps/editarrows/*.png)
install (FILES ${BITMAP_EDITARROW_FILES}
DESTINATION ${MARBLE_DATA_INSTALL_PATH}/bitmaps/editarrows)
install (DIRECTORY bitmaps/osmcarto
DESTINATION ${MARBLE_DATA_INSTALL_PATH}/bitmaps
PATTERN "LICENSE.txt" EXCLUDE)
PATTERN "LICENSE.txt" EXCLUDE
PATTERN "symbols" EXCLUDE)
FILE (GLOB BITMAP_STAR_FILES bitmaps/stars/*.png)
install (FILES ${BITMAP_STAR_FILES}
......
......@@ -17,6 +17,8 @@
#include "GeoDataTypes.h"
#include "GeoDataPlacemark.h"
#include "OsmPresetLibrary.h"
#include <QScreen>
#include <QApplication>
#include <QDebug>
......@@ -57,27 +59,30 @@ public:
GeoDataStyle::Ptr StyleBuilder::Private::s_defaultStyle[GeoDataFeature::LastIndex];
bool StyleBuilder::Private::s_defaultStyleInitialized = false;
GeoDataStyle::Ptr StyleBuilder::Private::createOsmPOIStyle( const QFont &font, const QString &bitmap,
GeoDataStyle::Ptr StyleBuilder::Private::createOsmPOIStyle( const QFont &font, const QString &imagePath,
const QColor &textColor, const QColor &color, const QColor &outline)
{
GeoDataStyle::Ptr style = createStyle(1, 0, color, outline, true, true, Qt::SolidPattern, Qt::SolidLine, Qt::RoundCap, false);
QString const imagePath = MarbleDirs::path( "bitmaps/osmcarto/symbols/48/" + bitmap + ".png" );
style->setIconStyle( GeoDataIconStyle( imagePath) );
style->iconStyle().setScale(0.67);
QString const path = MarbleDirs::path( "svg/osmcarto/svg/" + imagePath + ".svg" );
style->setIconStyle( GeoDataIconStyle( path) );
auto const screen = QApplication::screens().first();
double const physicalSize = 6.0; // mm
int const pixelSize = qRound(physicalSize * screen->physicalDotsPerInch() / (IN2M * M2MM));
style->iconStyle().setSize(QSize(pixelSize, pixelSize));
style->setLabelStyle( GeoDataLabelStyle( font, textColor ) );
style->labelStyle().setAlignment(GeoDataLabelStyle::Center);
return style;
}
GeoDataStyle::Ptr StyleBuilder::Private::createHighwayStyle( const QString &bitmap, const QColor& color, const QColor& outlineColor,
GeoDataStyle::Ptr StyleBuilder::Private::createHighwayStyle( const QString &imagePath, const QColor& color, const QColor& outlineColor,
const QFont& font, const QColor& fontColor, qreal width, qreal realWidth, Qt::PenStyle penStyle,
Qt::PenCapStyle capStyle, bool lineBackground)
{
GeoDataStyle::Ptr style = createStyle( width, realWidth, color, outlineColor, true, true,
Qt::SolidPattern, penStyle, capStyle, lineBackground, QVector< qreal >(),
font, fontColor );
if( !bitmap.isEmpty() ) {
style->setIconStyle( GeoDataIconStyle( MarbleDirs::path( "bitmaps/" + bitmap + ".png" ) ) );
if( !imagePath.isEmpty() ) {
style->setIconStyle( GeoDataIconStyle( MarbleDirs::path( "svg/osmcarto/svg/" + imagePath + ".svg" ) ) );
}
return style;
}
......@@ -696,8 +701,8 @@ GeoDataStyle::ConstPtr StyleBuilder::createStyle(const StyleParameters &paramete
if (!season.isEmpty()) {
GeoDataIconStyle iconStyle = style->iconStyle();
QString const bitmap = QString("bitmaps/osmcarto/symbols/48/individual/tree-29-%1.png").arg(season);
iconStyle.setIconPath(MarbleDirs::path(bitmap));
QString const image = QString("svg/osmcarto/svg/individual/tree-29-%1.svg").arg(season);
iconStyle.setIconPath(MarbleDirs::path(image));
GeoDataStyle::Ptr newStyle(new GeoDataStyle(*style));
newStyle->setIconStyle(iconStyle);
......
......@@ -18,6 +18,8 @@
#include "GeoDataTypes.h"
#include <QImageReader>
namespace Marble
{
......@@ -26,6 +28,7 @@ class GeoDataIconStylePrivate
public:
GeoDataIconStylePrivate()
: m_scale( 1.0 ),
m_size(0, 0),
m_iconPath(),
m_heading( 0 )
{
......@@ -33,6 +36,7 @@ class GeoDataIconStylePrivate
GeoDataIconStylePrivate( const QString& iconPath, const QPointF &hotSpot )
: m_scale( 1.0 ),
m_size(0, 0),
m_iconPath( iconPath ),
m_hotSpot( hotSpot ),
m_heading( 0 )
......@@ -52,7 +56,7 @@ class GeoDataIconStylePrivate
QSize scaledSize(const QSize &size) const
{
QSize iconSize = size;
QSize iconSize = size.isNull() ? m_icon.size() : size;
// Scaling the placemark's icon based on its size, scale, and maximum icon size.
if ( iconSize.width()*m_scale > s_maximumIconSize.width()
|| iconSize.height()*m_scale > s_maximumIconSize.height() ) {
......@@ -65,12 +69,44 @@ class GeoDataIconStylePrivate
else {
iconSize *= m_scale;
}
return iconSize;
}
QImage loadIcon(const QString &path, const QSize &size) const
{
if (!path.isEmpty()) {
// Icons from the local file system
if (!size.isNull()) {
QImageReader imageReader;
imageReader.setScaledSize(size);
imageReader.setFileName(path);
QImage icon = imageReader.read();
if (icon.isNull()) {
mDebug() << "GeoDataIconStyle: Failed to read image " << path << ": " << imageReader.errorString();
}
return icon;
}
QImage icon = QImage(path);
if (!icon.isNull()) {
return icon;
}
}
if(QUrl(m_iconPath).isValid() ) {
// if image is not found on disk, check whether the icon is
// at remote location. If yes then go for remote icon loading
return remoteIconLoader()->load(m_iconPath);
}
mDebug() << "Unable to open style icon at: " << path;
return QImage();
}
float m_scale;
QImage m_icon;
QSize m_size;
QImage m_scaledIcon;
QString m_iconPath;
GeoDataHotSpot m_hotSpot;
......@@ -112,6 +148,7 @@ bool GeoDataIconStyle::operator==( const GeoDataIconStyle &other ) const
return d->m_scale == other.d->m_scale &&
d->m_icon == other.d->m_icon &&
d->m_size == other.d->m_size &&
d->m_iconPath == other.d->m_iconPath &&
d->m_hotSpot == other.d->m_hotSpot &&
d->m_heading == other.d->m_heading;
......@@ -157,20 +194,7 @@ QImage GeoDataIconStyle::icon() const
return d->m_icon;
}
else if ( !d->m_iconPath.isEmpty() ) {
d->m_icon = QImage( resolvePath( d->m_iconPath ) );
if( d->m_icon.isNull() ) {
// if image is not found on disk, check whether the icon is
// at remote location. If yes then go for remote icon loading
QUrl remoteLocation = QUrl( d->m_iconPath );
if( remoteLocation.isValid() ) {
d->m_icon = d->remoteIconLoader()->load( d->m_iconPath );
}
else {
mDebug() << "Unable to open style icon at: " << d->m_iconPath;
}
}
return d->m_icon;
return d->loadIcon(resolvePath(d->m_iconPath), d->m_size);
}
else
return QImage();
......@@ -188,6 +212,28 @@ QPointF GeoDataIconStyle::hotSpot( GeoDataHotSpot::Units &xunits, GeoDataHotSpot
return d->m_hotSpot.hotSpot( xunits, yunits );
}
void GeoDataIconStyle::setSize(const QSize &size)
{
if (size == d->m_size) {
return;
}
d->m_size = size;
if (!size.isNull() && !d->m_icon.isNull()) {
// Resize existing icon that cannot be restored from an image path
d->m_icon = d->m_icon.scaled(size);
} else if (!d->m_iconPath.isEmpty()) {
// Lazily reload the icons
d->m_icon = QImage();
d->m_scaledIcon = QImage();
}
}
QSize GeoDataIconStyle::size() const
{
return d->m_size;
}
void GeoDataIconStyle::setScale( const float &scale )
{
d->m_scale = scale;
......@@ -213,10 +259,16 @@ QImage GeoDataIconStyle::scaledIcon() const
return icon();
}
QImage const image = icon();
if (!image.isNull()) {
QSize iconSize = d->scaledSize(image.size());
d->m_scaledIcon = image.scaled( iconSize, Qt::KeepAspectRatio, Qt::SmoothTransformation ) ;
// Try to load it
d->m_scaledIcon = d->loadIcon(resolvePath(d->m_iconPath), d->scaledSize(d->m_size));
if (d->m_scaledIcon.isNull()) {
// Direct loading failed, try to scale the icon as a last resort
QImage const image = icon();
if (!image.isNull()) {
QSize iconSize = d->scaledSize(image.size());
d->m_scaledIcon = image.scaled( iconSize, Qt::KeepAspectRatio, Qt::SmoothTransformation ) ;
}
}
return d->m_scaledIcon;
}
......
......@@ -67,6 +67,22 @@ class GEODATA_EXPORT GeoDataIconStyle : public GeoDataColorStyle
void setHotSpot( const QPointF& hotSpot, GeoDataHotSpot::Units xunits, GeoDataHotSpot::Units yunits );
QPointF hotSpot( GeoDataHotSpot::Units& xunits, GeoDataHotSpot::Units& yunits ) const;
/**
* @brief setSize Change the size of @see icon(). A null size (0, 0) is treated as a request to keep
* the original icon size. Otherwise the icon will be scaled to the given size. This is especially useful
* for vector graphics like .svg or to keep the memory footprint low when loading large images.
* @param size Size in pixel that @see icon() should have. When the icon was previously set by @setIcon,
* it is resized unless a null size is passed. Otherwise icon() will be scaled to the given size.
*/
void setSize(const QSize &size);
/**
* @brief size Returns the size @see icon() will have if it can be loaded from @see iconPath.
* A null size (default) is returned to indicate that the original size of the icon is used.
* @return size specified by @see setSize
*/
QSize size() const;
void setScale( const float &scale );
float scale() const;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment