Added support for image scaling

+ improved text path items performance
This commit is contained in:
Martin Tůma 2018-11-12 22:05:55 +01:00
parent f8d5a9b6cd
commit f41ac3bd54
9 changed files with 62 additions and 33 deletions

View File

@ -114,7 +114,7 @@ static inline QPoint parameters(quint32 v1, quint32 v2)
} }
static void drawFeature(const Feature &feature, Style *style, int styleLayer, static void drawFeature(const Feature &feature, Style *style, int styleLayer,
qreal factor, Tile &tile) const QSizeF &factor, Tile &tile)
{ {
if (!style->match(styleLayer, feature.tags())) if (!style->match(styleLayer, feature.tags()))
return; return;
@ -133,7 +133,8 @@ static void drawFeature(const Feature &feature, Style *style, int styleLayer,
feature.data()->geometry(i+2)); feature.data()->geometry(i+2));
i += 2; i += 2;
cursor += offset; cursor += offset;
path.moveTo(QPointF(cursor) / factor); path.moveTo(QPointF(cursor.x() * factor.width(),
cursor.y() * factor.height()));
} }
} else if (cmdId == LINE_TO) { } else if (cmdId == LINE_TO) {
for (unsigned j = 0; j < cmdCount; j++) { for (unsigned j = 0; j < cmdCount; j++) {
@ -141,7 +142,8 @@ static void drawFeature(const Feature &feature, Style *style, int styleLayer,
feature.data()->geometry(i+2)); feature.data()->geometry(i+2));
i += 2; i += 2;
cursor += offset; cursor += offset;
path.lineTo(QPointF(cursor) / factor); path.lineTo(QPointF(cursor.x() * factor.width(),
cursor.y() * factor.height()));
} }
} else if (cmdId == CLOSE_PATH) { } else if (cmdId == CLOSE_PATH) {
path.closeSubpath(); path.closeSubpath();
@ -158,21 +160,23 @@ static void drawLayer(const Layer &layer, Style *style, int styleLayer,
if (layer.data()->version() > 2) if (layer.data()->version() > 2)
return; return;
qreal factor = layer.data()->extent() / (qreal)tile.size(); QSizeF factor(tile.size().width() / (qreal)layer.data()->extent(),
tile.size().height() / (qreal)layer.data()->extent());
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);
} }
QImage PBF::image(const QByteArray &data, int zoom, Style *style, int size) bool PBF::render(const QByteArray &data, int zoom, Style *style, qreal scale,
QImage *image)
{ {
vector_tile::Tile tile; vector_tile::Tile tile;
if (!tile.ParseFromArray(data.constData(), data.size())) { if (!tile.ParseFromArray(data.constData(), data.size())) {
qCritical() << "Invalid tile protocol buffer data"; qCritical() << "Invalid tile protocol buffer data";
return QImage(); return false;
} }
Tile t(size); Tile t(image, scale);
style->setZoom(zoom); style->setZoom(zoom);
style->drawBackground(t); style->drawBackground(t);
@ -196,5 +200,7 @@ QImage PBF::image(const QByteArray &data, int zoom, Style *style, int size)
drawLayer(*it, style, i, t); drawLayer(*it, style, i, t);
} }
return t.render(); t.render();
return true;
} }

View File

@ -8,7 +8,8 @@ class Style;
namespace PBF namespace PBF
{ {
QImage image(const QByteArray &data, int zoom, Style *style, int size); bool render(const QByteArray &data, int zoom, Style *style, qreal scale,
QImage *render);
} }
#endif // PBF_H #endif // PBF_H

View File

@ -47,12 +47,10 @@ bool PBFHandler::canRead(QIODevice *device)
bool PBFHandler::read(QImage *image) bool PBFHandler::read(QImage *image)
{ {
quint32 magic; quint32 magic;
qint64 size = device()->peek((char*)&magic, sizeof(magic)); if (device()->peek((char*)&magic, sizeof(magic)) != sizeof(magic))
if (size != sizeof(magic))
return false; return false;
QByteArray ba; QByteArray ba;
if (isGZIPPBF(magic)) if (isGZIPPBF(magic))
ba = Gzip::uncompress(device()->readAll()); ba = Gzip::uncompress(device()->readAll());
else if (isPlainPBF(magic)) else if (isPlainPBF(magic))
@ -62,14 +60,28 @@ bool PBFHandler::read(QImage *image)
bool ok; bool ok;
int zoom = format().toInt(&ok); int zoom = format().toInt(&ok);
*image = PBF::image(ba, ok ? zoom : -1, _style, TILE_SIZE);
return !image->isNull(); QSize size = _scaledSize.isValid()
? _scaledSize : QSize(TILE_SIZE, TILE_SIZE);
qreal scale = _scaledSize.isValid()
? qMax(_scaledSize.width() / TILE_SIZE, _scaledSize.height() / TILE_SIZE)
: 1.0;
*image = QImage(size, QImage::Format_ARGB32);
return PBF::render(ba, ok ? zoom : -1, _style, scale, image);
} }
bool PBFHandler::supportsOption(ImageOption option) const bool PBFHandler::supportsOption(ImageOption option) const
{ {
return (option == Size); return (option == Size || option == ScaledSize);
}
void PBFHandler::setOption(QImageIOHandler::ImageOption option,
const QVariant &value)
{
if (option == ScaledSize)
_scaledSize = value.toSize();
} }
QVariant PBFHandler::option(ImageOption option) const QVariant PBFHandler::option(ImageOption option) const

View File

@ -4,6 +4,7 @@
#include <QImageIOHandler> #include <QImageIOHandler>
#include <QImage> #include <QImage>
#include <QVariant> #include <QVariant>
#include <QSize>
class Style; class Style;
@ -19,11 +20,13 @@ public:
QByteArray name() const; QByteArray name() const;
QVariant option(ImageOption option) const; QVariant option(ImageOption option) const;
bool supportsOption(ImageOption option) const; bool supportsOption(ImageOption option) const;
void setOption(QImageIOHandler::ImageOption option, const QVariant &value);
static bool canRead(QIODevice *device); static bool canRead(QIODevice *device);
private: private:
Style *_style; Style *_style;
QSize _scaledSize;
}; };
#endif // PBFHANDLER_H #endif // PBFHANDLER_H

View File

@ -473,7 +473,7 @@ void Style::drawFeature(int layer, const QPainterPath &path,
void Style::drawBackground(Tile &tile) void Style::drawBackground(Tile &tile)
{ {
QRectF rect(0, 0, tile.size(), tile.size()); QRectF rect(QPointF(0, 0), tile.size());
QPainterPath path; QPainterPath path;
path.addRect(rect); path.addRect(rect);

View File

@ -155,7 +155,15 @@ void Text::addLabel(const QString &text, const QPointF &pos, const QFont &font,
if (text.isEmpty()) if (text.isEmpty())
return; return;
TextPointItem *ti = new TextPointItem(text, pos, font, maxTextWidth); TextPointItem *ti;
if (_fontScale != 1.0) {
QFont scaledFont(font);
scaledFont.setPixelSize(font.pixelSize() * _fontScale);
ti = new TextPointItem(text, pos, scaledFont, maxTextWidth);
} else
ti = new TextPointItem(text, pos, font, maxTextWidth);
ti->setPen(pen); ti->setPen(pen);
addItem(ti); addItem(ti);
QList<TextItem*> ci = collidingItems(ti); QList<TextItem*> ci = collidingItems(ti);
@ -171,19 +179,20 @@ void Text::addLabel(const QString &text, const QPainterPath &path,
if (text.isEmpty()) if (text.isEmpty())
return; return;
QFontMetrics fm(font); QFont scaledFont(font);
int textWidth = fm.width(text); scaledFont.setPixelSize(font.pixelSize() * _fontScale);
int textWidth = text.size() * scaledFont.pixelSize() * 0.6;
if (textWidth > path.length()) if (textWidth > path.length())
return; return;
QPainterPath tp(textPath(path, textWidth, maxAngle, fm.averageCharWidth(), QPainterPath tp(textPath(path, textWidth, maxAngle,
_sceneRect)); scaledFont.pixelSize() / 2, _sceneRect));
if (tp.isEmpty()) if (tp.isEmpty())
return; return;
TextPathItem *pi = new TextPathItem(text, reverse(tp) ? tp.toReversed() TextPathItem *pi = new TextPathItem(text, reverse(tp) ? tp.toReversed()
: tp, font); : tp, scaledFont);
if (!_sceneRect.contains(pi->boundingRect())) { if (!_sceneRect.contains(pi->boundingRect())) {
delete pi; delete pi;
return; return;

View File

@ -6,7 +6,8 @@
class Text class Text
{ {
public: public:
Text(int size) : _sceneRect(QRectF(0, 0, size, size)) {} Text(const QSize &size, qreal scale)
: _sceneRect(QRectF(QPointF(0, 0), size)), _fontScale(scale) {}
~Text(); ~Text();
void render(QPainter *painter); void render(QPainter *painter);
@ -21,6 +22,7 @@ private:
QList<TextItem *> collidingItems(const TextItem *item) const; QList<TextItem *> collidingItems(const TextItem *item) const;
QRectF _sceneRect; QRectF _sceneRect;
qreal _fontScale;
QList<TextItem *> _items; QList<TextItem *> _items;
}; };

View File

@ -6,9 +6,8 @@
TextPathItem::TextPathItem(const QString &text, const QPainterPath &path, TextPathItem::TextPathItem(const QString &text, const QPainterPath &path,
const QFont &font) : _text(text), _path(path), _font(font) const QFont &font) : _text(text), _path(path), _font(font)
{ {
QFontMetrics fm(font);
QPainterPathStroker s; QPainterPathStroker s;
s.setWidth(fm.height()); s.setWidth(font.pixelSize());
s.setCapStyle(Qt::FlatCap); s.setCapStyle(Qt::FlatCap);
_shape = s.createStroke(path).simplified(); _shape = s.createStroke(path).simplified();
_boundingRect = _shape.boundingRect(); _boundingRect = _shape.boundingRect();

View File

@ -7,20 +7,17 @@
class Tile { class Tile {
public: public:
Tile(int size) : _background(size, size, QImage::Format_ARGB32), Tile(QImage *img, qreal scale)
_text(size), _painter(&_background) {} : _size(img->size()), _text(img->size(), scale), _painter(img) {}
int size() const {return _background.width();} QSize size() const {return _size;}
Text &text() {return _text;} Text &text() {return _text;}
QPainter &painter() {return _painter;} QPainter &painter() {return _painter;}
const QImage &render() { void render() {_text.render(&_painter);}
_text.render(&painter());
return _background;
}
private: private:
QImage _background; QSize _size;
Text _text; Text _text;
QPainter _painter; QPainter _painter;
}; };