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

View File

@ -8,7 +8,8 @@ class Style;
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

View File

@ -47,12 +47,10 @@ bool PBFHandler::canRead(QIODevice *device)
bool PBFHandler::read(QImage *image)
{
quint32 magic;
qint64 size = device()->peek((char*)&magic, sizeof(magic));
if (size != sizeof(magic))
if (device()->peek((char*)&magic, sizeof(magic)) != sizeof(magic))
return false;
QByteArray ba;
if (isGZIPPBF(magic))
ba = Gzip::uncompress(device()->readAll());
else if (isPlainPBF(magic))
@ -62,14 +60,28 @@ bool PBFHandler::read(QImage *image)
bool 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
{
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

View File

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

View File

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

View File

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

View File

@ -6,7 +6,8 @@
class Text
{
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();
void render(QPainter *painter);
@ -21,6 +22,7 @@ private:
QList<TextItem *> collidingItems(const TextItem *item) const;
QRectF _sceneRect;
qreal _fontScale;
QList<TextItem *> _items;
};

View File

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

View File

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