mirror of
https://github.com/tumic0/QtPBFImagePlugin.git
synced 2024-11-23 19:25:55 +01:00
Added support for HiDPI sprites
This commit is contained in:
parent
0d868f2f2a
commit
08509f0930
@ -3,5 +3,7 @@
|
|||||||
<file>style/style.json</file>
|
<file>style/style.json</file>
|
||||||
<file>style/sprite.json</file>
|
<file>style/sprite.json</file>
|
||||||
<file>style/sprite.png</file>
|
<file>style/sprite.png</file>
|
||||||
|
<file>style/sprite@2x.json</file>
|
||||||
|
<file>style/sprite@2x.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
15
src/pbf.cpp
15
src/pbf.cpp
@ -156,18 +156,20 @@ static void drawFeature(const Feature &feature, Style *style, int styleLayer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void drawLayer(const Layer &layer, Style *style, int styleLayer,
|
static void drawLayer(const Layer &layer, Style *style, int styleLayer,
|
||||||
Tile &tile, const QPointF &scale)
|
Tile &tile)
|
||||||
{
|
{
|
||||||
if (layer.data()->version() > 2)
|
if (layer.data()->version() > 2)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QSizeF factor(tile.size().width() / scale.x() / (qreal)layer.data()->extent(),
|
QSizeF factor(tile.size().width() / tile.scale().x() /
|
||||||
tile.size().height() / scale.y() / (qreal)layer.data()->extent());
|
(qreal)layer.data()->extent(), tile.size().height() / tile.scale().y()
|
||||||
|
/ (qreal)layer.data()->extent());
|
||||||
|
|
||||||
|
tile.painter().save();
|
||||||
style->setupLayer(tile, styleLayer);
|
style->setupLayer(tile, styleLayer);
|
||||||
|
|
||||||
for (int i = 0; i < layer.features().size(); i++)
|
for (int i = 0; i < layer.features().size(); i++)
|
||||||
drawFeature(layer.features().at(i), style, styleLayer, factor, tile);
|
drawFeature(layer.features().at(i), style, styleLayer, factor, tile);
|
||||||
|
tile.painter().restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PBF::render(const QByteArray &data, int zoom, Style *style,
|
bool PBF::render(const QByteArray &data, int zoom, Style *style,
|
||||||
@ -192,8 +194,6 @@ bool PBF::render(const QByteArray &data, int zoom, Style *style,
|
|||||||
layers.insert(name, Layer(&layer));
|
layers.insert(name, Layer(&layer));
|
||||||
}
|
}
|
||||||
|
|
||||||
t.painter().save();
|
|
||||||
|
|
||||||
// Process source layers in order of style layers
|
// Process source layers in order of style layers
|
||||||
for (int i = 0; i < style->sourceLayers().size(); i++) {
|
for (int i = 0; i < style->sourceLayers().size(); i++) {
|
||||||
QMap<QString, Layer>::const_iterator it = layers.find(
|
QMap<QString, Layer>::const_iterator it = layers.find(
|
||||||
@ -201,10 +201,9 @@ bool PBF::render(const QByteArray &data, int zoom, Style *style,
|
|||||||
if (it == layers.constEnd())
|
if (it == layers.constEnd())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
drawLayer(*it, style, i, t, scale);
|
drawLayer(*it, style, i, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
t.painter().restore();
|
|
||||||
t.text().render(&t.painter());
|
t.text().render(&t.painter());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -9,12 +9,19 @@
|
|||||||
Loading the sprites atlas image must be deferred until all image plugins
|
Loading the sprites atlas image must be deferred until all image plugins
|
||||||
are loaded, otherwise reading the image will cause a deadlock!
|
are loaded, otherwise reading the image will cause a deadlock!
|
||||||
*/
|
*/
|
||||||
static QImage &atlas(const QString &fileName)
|
static const QImage *atlas(const QString &fileName)
|
||||||
{
|
{
|
||||||
static QImage *img = new QImage(fileName);
|
static QImage *img = new QImage(fileName);
|
||||||
return *img;
|
return img;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const QImage *atlas2x(const QString &fileName)
|
||||||
|
{
|
||||||
|
static QImage *img = new QImage(fileName);
|
||||||
|
return img;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Sprites::Sprite::Sprite(const QJsonObject &json)
|
Sprites::Sprite::Sprite(const QJsonObject &json)
|
||||||
{
|
{
|
||||||
int x, y, width, height;
|
int x, y, width, height;
|
||||||
@ -42,7 +49,17 @@ Sprites::Sprite::Sprite(const QJsonObject &json)
|
|||||||
bool Sprites::load(const QString &jsonFile, const QString &imageFile)
|
bool Sprites::load(const QString &jsonFile, const QString &imageFile)
|
||||||
{
|
{
|
||||||
_imageFile = imageFile;
|
_imageFile = imageFile;
|
||||||
|
return load(jsonFile, _sprites);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Sprites::load2x(const QString &jsonFile, const QString &imageFile)
|
||||||
|
{
|
||||||
|
_image2xFile = imageFile;
|
||||||
|
return load(jsonFile, _sprites2x);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Sprites::load(const QString &jsonFile, QMap<QString, Sprite> &map)
|
||||||
|
{
|
||||||
QFile file(jsonFile);
|
QFile file(jsonFile);
|
||||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
qCritical() << jsonFile << ": error opening file";
|
qCritical() << jsonFile << ": error opening file";
|
||||||
@ -64,7 +81,7 @@ bool Sprites::load(const QString &jsonFile, const QString &imageFile)
|
|||||||
if (val.isObject()) {
|
if (val.isObject()) {
|
||||||
Sprite s(val.toObject());
|
Sprite s(val.toObject());
|
||||||
if (s.rect().isValid())
|
if (s.rect().isValid())
|
||||||
_sprites.insert(it.key(), s);
|
map.insert(it.key(), s);
|
||||||
else
|
else
|
||||||
qWarning() << it.key() << ": invalid sprite definition";
|
qWarning() << it.key() << ": invalid sprite definition";
|
||||||
} else
|
} else
|
||||||
@ -74,20 +91,36 @@ bool Sprites::load(const QString &jsonFile, const QString &imageFile)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QImage Sprites::icon(const QString &name) const
|
QImage Sprites::icon(const QString &name, bool hidpi) const
|
||||||
{
|
{
|
||||||
if (_imageFile.isNull())
|
qreal ratio;
|
||||||
return QImage();
|
const QImage *img;
|
||||||
const QImage &img = atlas(_imageFile);
|
const QMap<QString, Sprite> *map;
|
||||||
if (img.isNull())
|
|
||||||
|
if (hidpi && !_image2xFile.isNull()) {
|
||||||
|
img = atlas2x(_image2xFile);
|
||||||
|
map = &_sprites2x;
|
||||||
|
ratio = 2;
|
||||||
|
} else if (!_imageFile.isNull()) {
|
||||||
|
img = atlas(_imageFile);
|
||||||
|
map = &_sprites;
|
||||||
|
ratio = 1;
|
||||||
|
} else
|
||||||
return QImage();
|
return QImage();
|
||||||
|
|
||||||
QMap<QString, Sprite>::const_iterator it = _sprites.find(name);
|
if (img->isNull())
|
||||||
if (it == _sprites.constEnd())
|
|
||||||
return QImage();
|
return QImage();
|
||||||
|
|
||||||
if (!img.rect().contains(it->rect()))
|
|
||||||
|
QMap<QString, Sprite>::const_iterator it = map->find(name);
|
||||||
|
if (it == map->constEnd())
|
||||||
return QImage();
|
return QImage();
|
||||||
|
|
||||||
return img.copy(it->rect());
|
if (!img->rect().contains(it->rect()))
|
||||||
|
return QImage();
|
||||||
|
|
||||||
|
QImage ret(img->copy(it->rect()));
|
||||||
|
ret.setDevicePixelRatio(ratio);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,9 @@ class Sprites
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
bool load(const QString &jsonFile, const QString &imageFile);
|
bool load(const QString &jsonFile, const QString &imageFile);
|
||||||
|
bool load2x(const QString &jsonFile, const QString &imageFile);
|
||||||
|
|
||||||
QImage icon(const QString &name) const;
|
QImage icon(const QString &name, bool hidpi) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class Sprite {
|
class Sprite {
|
||||||
@ -22,8 +23,10 @@ private:
|
|||||||
QRect _rect;
|
QRect _rect;
|
||||||
};
|
};
|
||||||
|
|
||||||
QMap<QString, Sprite> _sprites;
|
bool load(const QString &jsonFile, QMap<QString, Sprite> &map);
|
||||||
QString _imageFile;
|
|
||||||
|
QMap<QString, Sprite> _sprites, _sprites2x;
|
||||||
|
QString _imageFile, _image2xFile;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SPRITES_H
|
#endif // SPRITES_H
|
||||||
|
@ -223,7 +223,8 @@ QPen Style::Layer::Paint::pen(Type type, int zoom) const
|
|||||||
return pen;
|
return pen;
|
||||||
}
|
}
|
||||||
|
|
||||||
QBrush Style::Layer::Paint::brush(Type type, int zoom, const Sprites &sprites) const
|
QBrush Style::Layer::Paint::brush(Type type, int zoom, const Sprites &sprites,
|
||||||
|
bool hidpi) const
|
||||||
{
|
{
|
||||||
QColor color;
|
QColor color;
|
||||||
QBrush brush(Qt::NoBrush);
|
QBrush brush(Qt::NoBrush);
|
||||||
@ -236,7 +237,7 @@ QBrush Style::Layer::Paint::brush(Type type, int zoom, const Sprites &sprites) c
|
|||||||
brush = QBrush(color);
|
brush = QBrush(color);
|
||||||
pattern = _fillPattern.value(zoom);
|
pattern = _fillPattern.value(zoom);
|
||||||
if (!pattern.isNull())
|
if (!pattern.isNull())
|
||||||
brush.setTextureImage(sprites.icon(pattern));
|
brush.setTextureImage(sprites.icon(pattern, hidpi));
|
||||||
break;
|
break;
|
||||||
case Background:
|
case Background:
|
||||||
color = _backgroundColor.value(zoom);
|
color = _backgroundColor.value(zoom);
|
||||||
@ -244,7 +245,7 @@ QBrush Style::Layer::Paint::brush(Type type, int zoom, const Sprites &sprites) c
|
|||||||
brush = QBrush(color);
|
brush = QBrush(color);
|
||||||
pattern = _fillPattern.value(zoom);
|
pattern = _fillPattern.value(zoom);
|
||||||
if (!pattern.isNull())
|
if (!pattern.isNull())
|
||||||
brush.setTextureImage(sprites.icon(pattern));
|
brush.setTextureImage(sprites.icon(pattern, hidpi));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -448,7 +449,8 @@ void Style::Layer::setPathPainter(Tile &tile, const Sprites &sprites) const
|
|||||||
pen.setJoinStyle(_layout.lineJoin(zoom));
|
pen.setJoinStyle(_layout.lineJoin(zoom));
|
||||||
pen.setCapStyle(_layout.lineCap(zoom));
|
pen.setCapStyle(_layout.lineCap(zoom));
|
||||||
|
|
||||||
QBrush brush(_paint.brush(_type, zoom, sprites));
|
bool hidpi = qMax(tile.scale().x(), tile.scale().y()) > 1.0 ? true : false;
|
||||||
|
QBrush brush(_paint.brush(_type, zoom, sprites, hidpi));
|
||||||
|
|
||||||
p.setRenderHint(QPainter::Antialiasing, _paint.antialias(_type, zoom));
|
p.setRenderHint(QPainter::Antialiasing, _paint.antialias(_type, zoom));
|
||||||
p.setPen(pen);
|
p.setPen(pen);
|
||||||
@ -478,7 +480,8 @@ void Style::Layer::addSymbol(Tile &tile, const QPainterPath &path,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
QString icon = _layout.icon(tile.zoom(), tags);
|
QString icon = _layout.icon(tile.zoom(), tags);
|
||||||
tile.text().addLabel(text, sprites.icon(icon), path);
|
bool hidpi = qMax(tile.scale().x(), tile.scale().y()) > 1.0 ? true : false;
|
||||||
|
tile.text().addLabel(text, sprites.icon(icon, hidpi), path);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Style::load(const QString &fileName)
|
bool Style::load(const QString &fileName)
|
||||||
@ -509,7 +512,9 @@ bool Style::load(const QString &fileName)
|
|||||||
for (int i = 0; i < _layers.size(); i++)
|
for (int i = 0; i < _layers.size(); i++)
|
||||||
_sourceLayers.append(_layers.at(i).sourceLayer());
|
_sourceLayers.append(_layers.at(i).sourceLayer());
|
||||||
|
|
||||||
|
|
||||||
QDir styleDir = QFileInfo(fileName).absoluteDir();
|
QDir styleDir = QFileInfo(fileName).absoluteDir();
|
||||||
|
|
||||||
QString spritesJSON(styleDir.filePath("sprite.json"));
|
QString spritesJSON(styleDir.filePath("sprite.json"));
|
||||||
if (QFileInfo::exists(spritesJSON)) {
|
if (QFileInfo::exists(spritesJSON)) {
|
||||||
QString spritesImg(styleDir.filePath("sprite.png"));
|
QString spritesImg(styleDir.filePath("sprite.png"));
|
||||||
@ -519,6 +524,15 @@ bool Style::load(const QString &fileName)
|
|||||||
qCritical() << spritesImg << ": no such file";
|
qCritical() << spritesImg << ": no such file";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString sprites2xJSON(styleDir.filePath("sprite@2x.json"));
|
||||||
|
if (QFileInfo::exists(sprites2xJSON)) {
|
||||||
|
QString sprites2xImg(styleDir.filePath("sprite@2x.png"));
|
||||||
|
if (QFileInfo::exists(sprites2xImg))
|
||||||
|
_sprites.load2x(sprites2xJSON, sprites2xImg);
|
||||||
|
else
|
||||||
|
qCritical() << sprites2xImg << ": no such file";
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,7 +136,8 @@ private:
|
|||||||
Paint(const QJsonObject &json);
|
Paint(const QJsonObject &json);
|
||||||
|
|
||||||
QPen pen(Layer::Type type, int zoom) const;
|
QPen pen(Layer::Type type, int zoom) const;
|
||||||
QBrush brush(Layer::Type type, int zoom, const Sprites &sprites) const;
|
QBrush brush(Layer::Type type, int zoom, const Sprites &sprites,
|
||||||
|
bool hidpi) const;
|
||||||
qreal opacity(Layer::Type type, int zoom) const;
|
qreal opacity(Layer::Type type, int zoom) const;
|
||||||
bool antialias(Layer::Type type, int zoom) const;
|
bool antialias(Layer::Type type, int zoom) const;
|
||||||
QString fillPattern(int zoom) const
|
QString fillPattern(int zoom) const
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#include <QFontMetrics>
|
#include <QFontMetrics>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include "text.h"
|
#include "text.h"
|
||||||
#include "textpointitem.h"
|
#include "textpointitem.h"
|
||||||
|
@ -34,8 +34,7 @@ public:
|
|||||||
Auto
|
Auto
|
||||||
};
|
};
|
||||||
|
|
||||||
Text(const QSize &size)
|
Text(const QSize &size) : _sceneRect(QRectF(QPointF(0, 0), size)) {}
|
||||||
: _sceneRect(QRectF(QPointF(0, 0), size)) {}
|
|
||||||
~Text();
|
~Text();
|
||||||
|
|
||||||
void setFont(const QFont &font) {_font = font;}
|
void setFont(const QFont &font) {_font = font;}
|
||||||
|
@ -71,7 +71,8 @@ QRectF TextPointItem::fuzzyBoundingRect(const QString &str,
|
|||||||
|
|
||||||
QRectF TextPointItem::computeTextRect(BoundingRectFunction brf) const
|
QRectF TextPointItem::computeTextRect(BoundingRectFunction brf) const
|
||||||
{
|
{
|
||||||
QRectF iconRect = _icon.isNull() ? QRectF() : _icon.rect();
|
QRectF iconRect = _icon.isNull() ? QRectF()
|
||||||
|
: QRectF(QPointF(0, 0), QSizeF(_icon.size()) / _icon.devicePixelRatioF());
|
||||||
QRectF textRect = brf(text(), font(), _maxWidth);
|
QRectF textRect = brf(text(), font(), _maxWidth);
|
||||||
|
|
||||||
switch (_anchor) {
|
switch (_anchor) {
|
||||||
@ -108,7 +109,8 @@ TextPointItem::TextPointItem(const QString &text, const QPointF &pos,
|
|||||||
_boundingRect = computeTextRect(fuzzyBoundingRect);
|
_boundingRect = computeTextRect(fuzzyBoundingRect);
|
||||||
|
|
||||||
if (!_icon.isNull()) {
|
if (!_icon.isNull()) {
|
||||||
QRectF iconRect(_icon.rect());
|
QRectF iconRect(QPointF(0, 0), QSizeF(_icon.size())
|
||||||
|
/ _icon.devicePixelRatioF());
|
||||||
iconRect.moveCenter(pos);
|
iconRect.moveCenter(pos);
|
||||||
_boundingRect |= iconRect;
|
_boundingRect |= iconRect;
|
||||||
}
|
}
|
||||||
@ -125,8 +127,9 @@ void TextPointItem::paint(QPainter *painter) const
|
|||||||
|
|
||||||
if (!_icon.isNull()) {
|
if (!_icon.isNull()) {
|
||||||
textRect = computeTextRect(exactBoundingRect);
|
textRect = computeTextRect(exactBoundingRect);
|
||||||
painter->drawImage(_pos - QPointF(_icon.width() / 2,
|
painter->drawImage(_pos - QPointF(_icon.width()
|
||||||
_icon.height() / 2), _icon);
|
/ _icon.devicePixelRatioF() / 2, _icon.height()
|
||||||
|
/ _icon.devicePixelRatioF() / 2), _icon);
|
||||||
} else
|
} else
|
||||||
textRect = computeTextRect(fuzzyBoundingRect);
|
textRect = computeTextRect(fuzzyBoundingRect);
|
||||||
|
|
||||||
|
10
src/tile.h
10
src/tile.h
@ -8,18 +8,22 @@
|
|||||||
class Tile {
|
class Tile {
|
||||||
public:
|
public:
|
||||||
Tile(QImage *img, int zoom, const QPointF &scale)
|
Tile(QImage *img, int zoom, const QPointF &scale)
|
||||||
: _zoom(zoom), _size(img->size()), _text(QSize(img->size().width()
|
: _zoom(zoom), _size(img->size()), _scale(scale),
|
||||||
/ scale.x(), img->size().height() / scale.y())), _painter(img)
|
_text(QSize(img->size().width() / scale.x(),
|
||||||
|
img->size().height() / scale.y())), _painter(img)
|
||||||
{_painter.scale(scale.x(), scale.y());}
|
{_painter.scale(scale.x(), scale.y());}
|
||||||
|
|
||||||
int zoom() const {return _zoom;}
|
int zoom() const {return _zoom;}
|
||||||
QSize size() const {return _size;}
|
const QSize &size() const {return _size;}
|
||||||
|
const QPointF &scale() const {return _scale;}
|
||||||
|
|
||||||
Text &text() {return _text;}
|
Text &text() {return _text;}
|
||||||
QPainter &painter() {return _painter;}
|
QPainter &painter() {return _painter;}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int _zoom;
|
int _zoom;
|
||||||
QSize _size;
|
QSize _size;
|
||||||
|
QPointF _scale;
|
||||||
Text _text;
|
Text _text;
|
||||||
QPainter _painter;
|
QPainter _painter;
|
||||||
};
|
};
|
||||||
|
1682
style/sprite@2x.json
Normal file
1682
style/sprite@2x.json
Normal file
File diff suppressed because it is too large
Load Diff
BIN
style/sprite@2x.png
Normal file
BIN
style/sprite@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 114 KiB |
Loading…
Reference in New Issue
Block a user