10 Commits
2.1 ... 2.2

7 changed files with 122 additions and 58 deletions

View File

@ -10,6 +10,7 @@ env:
before_install:
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get -qq update; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi
install:
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install qt protobuf; fi

View File

@ -8,12 +8,7 @@ PBF(MVT) vector tiles without (almost, see usage) any application modifications.
Standard Mapbox GL Styles are used for styling the maps. Most relevant style
features used by [Maputnik](http://editor.openmaptiles.org) are supported.
The style is loaded from the
[$AppDataLocation](http://doc.qt.io/qt-5/qstandardpaths.html)/style/style.json
file on plugin load. If the style uses a sprite, the sprite JSON file must
be named sprite.json and the sprite image sprite.png and both files must be
placed in the same directory as the style itself. A default fallback style
(OSM-Liberty) for OpenMapTiles is part of the plugin.
A default fallback style (OSM-Liberty) for OpenMapTiles is part of the plugin.
"Plain" PBF files as well as gzip compressed files (as used in MBTiles) are
supported by the plugin. The tile size is (since version 2.0 of the plugin) 512px
@ -39,6 +34,18 @@ reader.read(&image);
```
you will get 1024x1024px tiles with a pixel ratio of 2 (= HiDPI tiles).
## Styles
The map style is loaded from the
[$AppDataLocation](http://doc.qt.io/qt-5/qstandardpaths.html)/style/style.json
file on plugin load. If the style uses a sprite, the sprite JSON file must
be named `sprite.json` and the sprite image `sprite.png` and both files must be
placed in the same directory as the style itself. *A style compatible with the
tiles data schema (Mapbox, OpenMapTiles, Tilezen) must be used.*
For a list of "ready to use" styles see the
[QtPBFImagePlugin-styles](https://github.com/tumic0/QtPBFImagePlugin-styles)
repository.
## Build
### Requirements
* Qt >= 5.4 (5.6 for HiDPI support)
@ -73,26 +80,45 @@ for most common distros available on OBS.
style are ignored.
* Text PBF features must have a unique id (OpenMapTiles >= v3.7) for the text layout
algorithm to work properly.
* Expressions not supported in the styles, only property functions are implemented.
* Expressions are not supported in the styles, only property functions are implemented.
## Changelog
[Changelog](https://build.opensuse.org/package/view_file/home:tumic:QtPBFImagePlugin/QtPBFImagePlugin/libqt5-qtpbfimageformat.changes)
## Status
A picture is worth a thousand words. Data and styles from https://openmaptiles.org.
#### OSM-liberty
![osm-liberty 2](https://tumic0.github.io/QtPBFImagePlugin/images/osm-liberty-2.png)
A picture is worth a thousand words.
#### OpenMapTiles
* Data: [MapTiler](https://github.com/tumic0/GPXSee-maps/blob/master/World/MapTiler.tpl)
* Style: [OSM-liberty](https://github.com/tumic0/QtPBFImagePlugin-styles/blob/master/OpenMapTiles/osm-liberty/style.json)
![osm-liberty 5](https://tumic0.github.io/QtPBFImagePlugin/images/osm-liberty-5.png)
![osm-liberty 8](https://tumic0.github.io/QtPBFImagePlugin/images/osm-liberty-8.png)
![osm-liberty 11](https://tumic0.github.io/QtPBFImagePlugin/images/osm-liberty-11.png)
![osm-liberty 12](https://tumic0.github.io/QtPBFImagePlugin/images/osm-liberty-12.png)
![osm-liberty 14](https://tumic0.github.io/QtPBFImagePlugin/images/osm-liberty-14.png)
![osm-liberty 15](https://tumic0.github.io/QtPBFImagePlugin/images/osm-liberty-15.png)
#### Klokantech-basic
![klokantech-basic 2](https://tumic0.github.io/QtPBFImagePlugin/images/klokantech-basic-2.png)
![klokantech-basic 4](https://tumic0.github.io/QtPBFImagePlugin/images/klokantech-basic-4.png)
![klokantech-basic 8](https://tumic0.github.io/QtPBFImagePlugin/images/klokantech-basic-8.png)
![klokantech-basic 13](https://tumic0.github.io/QtPBFImagePlugin/images/klokantech-basic-13.png)
![klokantech-basic 14](https://tumic0.github.io/QtPBFImagePlugin/images/klokantech-basic-14.png)
#### Mapbox
* Data: [Mapbox](https://github.com/tumic0/GPXSee-maps/blob/master/World/Mapbox.tpl)
* Style: [Bright](https://github.com/tumic0/QtPBFImagePlugin-styles/blob/master/Mapbox/bright/style.json)
![bright 4](https://tumic0.github.io/QtPBFImagePlugin/images/bright-4.png)
![bright 6](https://tumic0.github.io/QtPBFImagePlugin/images/bright-6.png)
![bright 13](https://tumic0.github.io/QtPBFImagePlugin/images/bright-13.png)
![bright 15](https://tumic0.github.io/QtPBFImagePlugin/images/bright-15.png)
![bright 17](https://tumic0.github.io/QtPBFImagePlugin/images/bright-17.png)
#### Tilezen
* Data: [HERE](https://github.com/tumic0/GPXSee-maps/blob/master/World/here-vector.tpl)
* Style: [Apollo-Bright](https://github.com/tumic0/QtPBFImagePlugin-styles/blob/master/Tilezen/apollo-bright/style.json)
![apollo-bright 4](https://tumic0.github.io/QtPBFImagePlugin/images/apollo-bright-4.png)
![apollo-bright 6](https://tumic0.github.io/QtPBFImagePlugin/images/apollo-bright-6.png)
![apollo-bright 12](https://tumic0.github.io/QtPBFImagePlugin/images/apollo-bright-12.png)
![apollo-bright 15](https://tumic0.github.io/QtPBFImagePlugin/images/apollo-bright-15.png)
![apollo-bright 16](https://tumic0.github.io/QtPBFImagePlugin/images/apollo-bright-16.png)
## Applications using QtPBFImagePlugin
* [GPXSee](https://www.gpxsee.org)

View File

@ -37,6 +37,8 @@ SOURCES += src/pbfplugin.cpp \
src/textitem.cpp
RESOURCES += pbfplugin.qrc
DEFINES += QT_NO_DEPRECATED_WARNINGS
unix:!macx{
LIBS += -lprotobuf-lite \
-lz

View File

@ -1,35 +1,58 @@
#include <QtEndian>
#include <QDebug>
#include <QIODevice>
#include <zlib.h>
#include "gzip.h"
#define CHUNK 16384
QByteArray Gzip::uncompress(const QByteArray &data)
QByteArray Gzip::uncompress(QIODevice *device, int limit)
{
int ret;
z_stream strm;
unsigned char in[CHUNK];
unsigned char out[CHUNK];
qint64 rs;
QByteArray uba;
z_stream stream;
quint32 *size = (quint32*)(data.constData() + data.size() - sizeof(quint32));
uba.resize(qFromLittleEndian(*size));
stream.zalloc = Z_NULL;
stream.zfree = Z_NULL;
stream.opaque = Z_NULL;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = 0;
strm.next_in = Z_NULL;
if (inflateInit2(&strm, MAX_WBITS + 16) != Z_OK)
return QByteArray();
stream.next_in = (Bytef*)data.constData();
stream.avail_in = data.size();
stream.next_out = (Bytef*)uba.data();
stream.avail_out = uba.size();
do {
rs = device->read((char*)in, CHUNK);
if (rs < 0) {
(void)inflateEnd(&strm);
return QByteArray();
} else if (rs == 0)
break;
else
strm.avail_in = (uInt)rs;
strm.next_in = in;
if (inflateInit2(&stream, MAX_WBITS + 16) != Z_OK)
return uba;
do {
strm.avail_out = CHUNK;
strm.next_out = out;
ret = inflate(&strm, Z_NO_FLUSH);
Q_ASSERT(ret != Z_STREAM_ERROR);
switch (ret) {
case Z_NEED_DICT:
case Z_DATA_ERROR:
case Z_MEM_ERROR:
(void)inflateEnd(&strm);
return QByteArray();
}
uba.append((char*)out, CHUNK - strm.avail_out);
if (limit && uba.size() >= limit) {
(void)inflateEnd(&strm);
return uba;
}
} while (!strm.avail_out);
} while (ret != Z_STREAM_END);
if (inflate(&stream, Z_NO_FLUSH) != Z_STREAM_END) {
qCritical() << "Invalid gzip data";
uba = QByteArray();
}
inflateEnd(&stream);
return uba;
(void)inflateEnd(&strm);
return (ret == Z_STREAM_END) ? uba : QByteArray();
}

View File

@ -3,9 +3,11 @@
#include <QByteArray>
class QIODevice;
namespace Gzip
{
QByteArray uncompress(const QByteArray &data);
QByteArray uncompress(QIODevice *device, int limit = 0);
}
#endif // GZIP_H

View File

@ -10,22 +10,22 @@
#define TILE_SIZE 512
#define GZIP_MAGIC 0x1F8B0800
#define GZIP_MAGIC_MASK 0xFFFFFF00
#define PBF_MAGIC 0x1A000000
#define PBF_MAGIC_MASK 0xFF000000
#define GZIP_MAGIC 0x1F8B
#define GZIP_MAGIC_MASK 0xFFFF
#define PBF_MAGIC 0x1A00
#define PBF_MAGIC_MASK 0xFF00
static bool isMagic(quint32 magic, quint32 mask, quint32 value)
static bool isMagic(quint16 magic, quint16 mask, quint16 value)
{
return ((qFromBigEndian(value) & mask) == magic);
}
static bool isGZIPPBF(quint32 magic)
static bool isGZIPPBF(quint16 magic)
{
return isMagic(GZIP_MAGIC, GZIP_MAGIC_MASK, magic);
}
static bool isPlainPBF(quint32 magic)
static bool isPlainPBF(quint16 magic)
{
return isMagic(PBF_MAGIC, PBF_MAGIC_MASK, magic);
}
@ -34,7 +34,7 @@ static bool isPlainPBF(quint32 magic)
bool PBFHandler::canRead() const
{
if (canRead(device())) {
setFormat("pbf");
setFormat("mvt");
return true;
} else
return false;
@ -42,27 +42,37 @@ bool PBFHandler::canRead() const
bool PBFHandler::canRead(QIODevice *device)
{
quint32 magic;
quint16 magic;
qint64 size = device->peek((char*)&magic, sizeof(magic));
if (size != sizeof(magic))
return false;
return (isGZIPPBF(magic) || isPlainPBF(magic));
if (isPlainPBF(magic))
return true;
else if (isGZIPPBF(magic)) {
QByteArray ba(Gzip::uncompress(device, sizeof(magic)));
if (ba.size() < (int)sizeof(magic))
return false;
return isPlainPBF(*((quint16*)ba.constData()));
} else
return false;
}
bool PBFHandler::read(QImage *image)
{
quint32 magic;
quint16 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))
if (isGZIPPBF(magic)) {
ba = Gzip::uncompress(device());
if (ba.isNull()) {
qCritical() << "Invalid gzip data";
return false;
}
} else if (isPlainPBF(magic))
ba = device()->readAll();
if (ba.isNull())
return false;
vector_tile::Tile data;
if (!data.ParseFromArray(ba.constData(), ba.size())) {
qCritical() << "Invalid PBF data";

View File

@ -172,7 +172,7 @@ bool Style::Layer::Filter::match(const PBF::Feature &feature) const
return true;
return false;
case GeometryType:
return feature.type() == _kv.second.toUInt();
return feature.type() == _kv.second.toInt();
default:
return false;
}