8 Commits
1.2 ... 1.4

13 changed files with 106 additions and 19 deletions

View File

@ -3,8 +3,8 @@ Qt image plugin for displaying Mapbox vector tiles
## Description ## Description
QtPBFImagePlugin is a Qt image plugin that enables applications capable of QtPBFImagePlugin is a Qt image plugin that enables applications capable of
displaying raster MBTiles maps or raster XYZ online maps to also display PBF displaying raster MBTiles maps or raster XYZ online maps to also display
vector tiles without (almost, see usage) any application modifications. PBF(MVT) vector tiles without (almost, see usage) any application modifications.
Standard Mapbox GL Styles are used for styling the maps. Most relevant style Standard Mapbox GL Styles are used for styling the maps. Most relevant style
features used by [Maputnik](http://editor.openmaptiles.org) are supported. features used by [Maputnik](http://editor.openmaptiles.org) are supported.

View File

@ -1,4 +1,4 @@
{ {
"Keys": [ "pbf" ], "Keys": [ "mvt" ],
"MimeTypes": [ "image/pbf" ] "MimeTypes": [ "application/vnd.mapbox-vector-tile" ]
} }

9
pkg/pbfplugin.xml Normal file
View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
<mime-type type="application/vnd.mapbox-vector-tile">
<comment>Mapbox Vector Tile</comment>
<sub-class-of type="application/octet-stream"/>
<generic-icon name="application/octet-stream"/>
<glob pattern="*.mvt"/>
</mime-type>
</mime-info>

View File

@ -13,9 +13,7 @@ QColor Color::fromJsonString(const QString &str)
{ {
QColor ret; QColor ret;
if (str.startsWith('#')) if (str.startsWith("rgb(")) {
return QColor(str);
else if (str.startsWith("rgb(")) {
QStringList comp(str.mid(4, str.size() - 5).split(',')); QStringList comp(str.mid(4, str.size() - 5).split(','));
if (comp.size() != 3) if (comp.size() != 3)
return QColor(); return QColor();
@ -39,7 +37,8 @@ QColor Color::fromJsonString(const QString &str)
return QColor(); return QColor();
ret = QColor::fromHslF(comp.at(0).toFloat() / 360.0, pval(comp.at(1)), ret = QColor::fromHslF(comp.at(0).toFloat() / 360.0, pval(comp.at(1)),
pval(comp.at(2)), comp.at(3).toFloat()); pval(comp.at(2)), comp.at(3).toFloat());
} } else
ret = QColor(str);
if (!ret.isValid()) if (!ret.isValid())
qWarning() << str << ": invalid color"; qWarning() << str << ": invalid color";

View File

@ -1,9 +1,5 @@
#include "pbf.h" #include "pbf.h"
#define POLYGON vector_tile::Tile_GeomType_POLYGON
#define LINESTRING vector_tile::Tile_GeomType_LINESTRING
#define POINT vector_tile::Tile_GeomType_POINT
#define MOVE_TO 1 #define MOVE_TO 1
#define LINE_TO 2 #define LINE_TO 2
#define CLOSE_PATH 7 #define CLOSE_PATH 7

View File

@ -21,7 +21,7 @@ QImageIOPlugin::Capabilities PBFPlugin::capabilities(QIODevice *device,
const QByteArray &format) const const QByteArray &format) const
{ {
if (device == 0) if (device == 0)
return (format == "pbf") ? Capabilities(CanRead) : Capabilities(); return (format == "mvt") ? Capabilities(CanRead) : Capabilities();
else else
return (device->isReadable() && PBFHandler::canRead(device)) return (device->isReadable() && PBFHandler::canRead(device))
? Capabilities(CanRead) : Capabilities(); ? Capabilities(CanRead) : Capabilities();

View File

@ -230,6 +230,9 @@ Style::Layer::Paint::Paint(const QJsonObject &json)
// text // text
_textColor = FunctionC(json["text-color"]); _textColor = FunctionC(json["text-color"]);
_textHaloColor = FunctionC(json["text-halo-color"], QColor());
_textHaloWidth = FunctionF(json["text-halo-width"]);
_textHaloBlur = FunctionF(json["text-halo-blur"]);
} }
QPen Style::Layer::Paint::pen(Type type, int zoom) const QPen Style::Layer::Paint::pen(Type type, int zoom) const
@ -511,6 +514,7 @@ void Style::Layer::setTextProperties(Tile &tile) const
t.setFont(_layout.font(zoom)); t.setFont(_layout.font(zoom));
t.setSymbolPlacement(_layout.symbolPlacement(zoom)); t.setSymbolPlacement(_layout.symbolPlacement(zoom));
t.setRotationAlignment(_layout.textRotationAlignment(zoom)); t.setRotationAlignment(_layout.textRotationAlignment(zoom));
t.setHalo(_paint.halo(zoom));
} }
void Style::Layer::addSymbol(Tile &tile, const QPainterPath &path, void Style::Layer::addSymbol(Tile &tile, const QPainterPath &path,

View File

@ -137,9 +137,13 @@ private:
const; 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;
Text::Halo halo(int zoom) const
{return Text::Halo(_textHaloColor.value(zoom),
_textHaloWidth.value(zoom), _textHaloBlur.value(zoom));}
private: private:
FunctionC _textColor; FunctionC _textColor;
FunctionC _textHaloColor;
FunctionC _lineColor; FunctionC _lineColor;
FunctionC _fillColor; FunctionC _fillColor;
FunctionC _fillOutlineColor; FunctionC _fillOutlineColor;
@ -147,6 +151,8 @@ private:
FunctionF _fillOpacity; FunctionF _fillOpacity;
FunctionF _lineOpacity; FunctionF _lineOpacity;
FunctionF _lineWidth; FunctionF _lineWidth;
FunctionF _textHaloWidth;
FunctionF _textHaloBlur;
FunctionB _fillAntialias; FunctionB _fillAntialias;
QVector<qreal> _lineDasharray; QVector<qreal> _lineDasharray;
FunctionS _fillPattern; FunctionS _fillPattern;

View File

@ -56,6 +56,7 @@ void Text::addLabel(const QString &text, const QImage &icon,
} }
ti->setPen(_pen); ti->setPen(_pen);
ti->setHalo(_halo);
addItem(ti); addItem(ti);
QList<TextItem*> ci = collidingItems(ti); QList<TextItem*> ci = collidingItems(ti);

View File

@ -34,6 +34,22 @@ public:
Auto Auto
}; };
class Halo {
public:
Halo() : _width(0), _blur(0) {}
Halo(const QColor &color, qreal width, qreal blur)
: _color(color), _width(width), _blur(blur) {}
const QColor &color() const {return _color;}
qreal width() const {return _width;}
qreal blur() const {return _blur;}
private:
QColor _color;
qreal _width;
qreal _blur;
};
Text(const QSize &size) : _sceneRect(QRectF(QPointF(0, 0), size)) {} Text(const QSize &size) : _sceneRect(QRectF(QPointF(0, 0), size)) {}
~Text(); ~Text();
@ -45,6 +61,7 @@ public:
void setSymbolPlacement(SymbolPlacement placement); void setSymbolPlacement(SymbolPlacement placement);
void setRotationAlignment(RotationAlignment alignment) void setRotationAlignment(RotationAlignment alignment)
{_alignment = alignment;} {_alignment = alignment;}
void setHalo(const Halo &halo) {_halo = halo;}
void addLabel(const QString &text, const QImage &icon, void addLabel(const QString &text, const QImage &icon,
const QPainterPath &path); const QPainterPath &path);
@ -65,6 +82,7 @@ private:
RotationAlignment _alignment; RotationAlignment _alignment;
QFont _font; QFont _font;
QPen _pen; QPen _pen;
Halo _halo;
}; };
#endif // TEXT_H #endif // TEXT_H

View File

@ -6,6 +6,7 @@
#include <QPen> #include <QPen>
#include <QFont> #include <QFont>
#include <QRectF> #include <QRectF>
#include "text.h"
class QPainter; class QPainter;
@ -19,7 +20,9 @@ public:
const QString &text() const {return _text;} const QString &text() const {return _text;}
const QFont &font() const {return _font;} const QFont &font() const {return _font;}
const QPen &pen() const {return _pen;} const QPen &pen() const {return _pen;}
const Text::Halo &halo() const {return _halo;}
void setPen(const QPen &pen) {_pen = pen;} void setPen(const QPen &pen) {_pen = pen;}
void setHalo(const Text::Halo &halo) {_halo = halo;}
virtual QPainterPath shape() const = 0; virtual QPainterPath shape() const = 0;
virtual QRectF boundingRect() const = 0; virtual QRectF boundingRect() const = 0;
@ -37,6 +40,7 @@ private:
QString _text; QString _text;
QFont _font; QFont _font;
QPen _pen; QPen _pen;
Text::Halo _halo;
bool _visible; bool _visible;
}; };

View File

@ -166,10 +166,35 @@ void TextPathItem::paint(QPainter *painter) const
qreal percent = (1.0 - factor) / 2.0; qreal percent = (1.0 - factor) / 2.0;
painter->setFont(font()); painter->setFont(font());
painter->setPen(pen());
QTransform t = painter->transform(); QTransform t = painter->transform();
if (halo().color().isValid() && halo().width() > 0) {
painter->setPen(halo().color());
for (int i = 0; i < text().size(); i++) {
QPointF point = _path.pointAtPercent(percent);
qreal angle = _path.angleAtPercent(percent);
painter->translate(point);
painter->rotate(-angle);
painter->drawText(QPoint(-1, fm.descent() - 1), text().at(i));
painter->drawText(QPoint(1, fm.descent() + 1), text().at(i));
painter->drawText(QPoint(-1, fm.descent() + 1), text().at(i));
painter->drawText(QPoint(1, fm.descent() -1), text().at(i));
painter->drawText(QPoint(0, fm.descent() - 1), text().at(i));
painter->drawText(QPoint(0, fm.descent() + 1), text().at(i));
painter->drawText(QPoint(-1, fm.descent()), text().at(i));
painter->drawText(QPoint(1, fm.descent()), text().at(i));
painter->setTransform(t);
int width = fm.charWidth(text(), i);
percent += ((qreal)width / (qreal)textWidth) * factor;
}
percent = (1.0 - factor) / 2.0;
}
painter->setPen(pen());
for (int i = 0; i < text().size(); i++) { for (int i = 0; i < text().size(); i++) {
QPointF point = _path.pointAtPercent(percent); QPointF point = _path.pointAtPercent(percent);
qreal angle = _path.angleAtPercent(percent); qreal angle = _path.angleAtPercent(percent);

View File

@ -128,9 +128,10 @@ void TextPointItem::paint(QPainter *painter) const
//painter->drawRect(_boundingRect); //painter->drawRect(_boundingRect);
QRectF textRect; QRectF textRect;
bool hasHalo = halo().color().isValid() && halo().width() > 0;
if (!_icon.isNull()) { if (!_icon.isNull()) {
textRect = (_anchor != Text::Center) textRect = (_anchor != Text::Center || hasHalo)
? computeTextRect(true) : _boundingRect; ? computeTextRect(true) : _boundingRect;
#ifdef ENABLE_HIDPI #ifdef ENABLE_HIDPI
painter->drawImage(_pos - QPointF(_icon.width() painter->drawImage(_pos - QPointF(_icon.width()
@ -141,9 +142,33 @@ void TextPointItem::paint(QPainter *painter) const
_icon.height() / 2), _icon); _icon.height() / 2), _icon);
#endif // ENABLE_HIDPI #endif // ENABLE_HIDPI
} else } else
textRect = _boundingRect; textRect = hasHalo ? computeTextRect(true) : _boundingRect;
painter->setFont(font());
painter->setPen(pen()); if (hasHalo) {
painter->drawText(textRect, FLAGS, text()); QRect ir(textRect.toRect());
QImage img(ir.size(), QImage::Format_ARGB32_Premultiplied);
img.fill(Qt::transparent);
QPainter ip(&img);
ip.setPen(halo().color());
ip.setFont(font());
ip.drawText(img.rect(), FLAGS, text());
painter->drawImage(ir.x() - 1, ir.y() - 1, img);
painter->drawImage(ir.x() + 1, ir.y() + 1, img);
painter->drawImage(ir.x() - 1, ir.y() + 1, img);
painter->drawImage(ir.x() + 1, ir.y() - 1, img);
painter->drawImage(ir.x(), ir.y() - 1, img);
painter->drawImage(ir.x(), ir.y() + 1, img);
painter->drawImage(ir.x() - 1, ir.y(), img);
painter->drawImage(ir.x() + 1, ir.y(), img);
painter->setFont(font());
painter->setPen(pen());
painter->drawText(ir, FLAGS, text());
} else {
painter->setFont(font());
painter->setPen(pen());
painter->drawText(textRect, FLAGS, text());
}
} }