28 : mFilename( filename )
38 const int result = mDatabase.
open_v2( mFilename, SQLITE_OPEN_READONLY,
nullptr );
39 if ( result != SQLITE_OK )
49 return bool( mDatabase );
57 if ( QFile::exists( mFilename ) )
61 int result = mDatabase.
open_v2( mFilename, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
nullptr );
62 if ( result != SQLITE_OK )
69 "CREATE TABLE metadata (name text, value text);" \
70 "CREATE TABLE tiles (zoom_level integer, tile_column integer, tile_row integer, tile_data blob);" \
71 "CREATE UNIQUE INDEX tile_index on tiles (zoom_level, tile_column, tile_row);";
73 result = mDatabase.
exec( sql, errorMessage );
74 if ( result != SQLITE_OK )
76 QgsDebugMsg( QStringLiteral(
"Failed to initialize MBTiles database: " ) + errorMessage );
87 QgsDebugMsg( QStringLiteral(
"MBTiles database not open: " ) + mFilename );
92 const QString sql = QStringLiteral(
"select value from metadata where name='%1'" ).arg( key );
94 if ( result != SQLITE_OK )
96 QgsDebugMsg( QStringLiteral(
"MBTile failed to prepare statement: " ) + sql );
100 if ( preparedStatement.
step() != SQLITE_ROW )
102 QgsDebugMsg( QStringLiteral(
"MBTile metadata value not found: " ) + key );
113 QgsDebugMsg( QStringLiteral(
"MBTiles database not open: " ) + mFilename );
120 if ( result != SQLITE_OK )
122 QgsDebugMsg( QStringLiteral(
"MBTile failed to prepare statement: " ) + sql );
126 if ( preparedStatement.
step() != SQLITE_DONE )
128 QgsDebugMsg( QStringLiteral(
"MBTile metadata value failed to be set: " ) + key );
136 if ( boundsStr.isEmpty() )
138 QStringList boundsArray = boundsStr.split(
',' );
139 if ( boundsArray.count() != 4 )
142 return QgsRectangle( boundsArray[0].toDouble(), boundsArray[1].toDouble(),
143 boundsArray[2].toDouble(), boundsArray[3].toDouble() );
150 QgsDebugMsg( QStringLiteral(
"MBTiles database not open: " ) + mFilename );
155 const QString sql = QStringLiteral(
"select tile_data from tiles where zoom_level=%1 and tile_column=%2 and tile_row=%3" ).arg( z ).arg( x ).arg( y );
157 if ( result != SQLITE_OK )
159 QgsDebugMsg( QStringLiteral(
"MBTile failed to prepare statement: " ) + sql );
163 if ( preparedStatement.
step() != SQLITE_ROW )
166 QgsDebugMsgLevel( QStringLiteral(
"MBTile not found: z=%1 x=%2 y=%3" ).arg( z ).arg( x ).arg( y ), 2 );
176 const QByteArray tileBlob =
tileData( z, x, y );
177 if ( !tileImage.loadFromData( tileBlob ) )
179 QgsDebugMsg( QStringLiteral(
"MBTile data failed to load: z=%1 x=%2 y=%3" ).arg( z ).arg( x ).arg( y ) );
189 QgsDebugMsg( QStringLiteral(
"MBTiles database not open: " ) + mFilename );
194 const QString sql = QStringLiteral(
"insert into tiles values (%1, %2, %3, ?)" ).arg( z ).arg( x ).arg( y );
196 if ( result != SQLITE_OK )
198 QgsDebugMsg( QStringLiteral(
"MBTile failed to prepare statement: " ) + sql );
202 sqlite3_bind_blob( preparedStatement.get(), 1, data.constData(), data.size(), SQLITE_TRANSIENT );
204 if ( preparedStatement.
step() != SQLITE_DONE )
206 QgsDebugMsg( QStringLiteral(
"MBTile tile failed to be set: %1,%2,%3" ).arg( z ).arg( x ).arg( y ) );
213 unsigned char *bytesInPtr =
reinterpret_cast<unsigned char *
>(
const_cast<char *
>( bytesIn.constData() ) );
214 uint bytesInLeft =
static_cast<uint
>( bytesIn.count() );
216 const uint CHUNK = 16384;
217 unsigned char out[CHUNK];
218 const int DEC_MAGIC_NUM_FOR_GZIP = 16;
222 strm.zalloc = Z_NULL;
224 strm.opaque = Z_NULL;
226 strm.next_in = Z_NULL;
228 int ret = inflateInit2( &strm, MAX_WBITS + DEC_MAGIC_NUM_FOR_GZIP );
232 while ( ret != Z_STREAM_END )
235 const uint bytesToProcess = std::min( CHUNK, bytesInLeft );
236 strm.next_in = bytesInPtr;
237 strm.avail_in = bytesToProcess;
238 bytesInPtr += bytesToProcess;
239 bytesInLeft -= bytesToProcess;
241 if ( bytesToProcess == 0 )
247 strm.avail_out = CHUNK;
249 ret = inflate( &strm, Z_NO_FLUSH );
250 Q_ASSERT( ret != Z_STREAM_ERROR );
251 if ( ret == Z_NEED_DICT || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR )
256 const unsigned have = CHUNK - strm.avail_out;
257 bytesOut.append( QByteArray::fromRawData(
reinterpret_cast<const char *
>( out ),
static_cast<int>( have ) ) );
259 while ( strm.avail_out == 0 );
263 return ret == Z_STREAM_END;
269 unsigned char *bytesInPtr =
reinterpret_cast<unsigned char *
>(
const_cast<char *
>( bytesIn.constData() ) );
270 const uint bytesInLeft =
static_cast<uint
>( bytesIn.count() );
272 const uint CHUNK = 16384;
273 unsigned char out[CHUNK];
274 const int DEC_MAGIC_NUM_FOR_GZIP = 16;
278 strm.zalloc = Z_NULL;
280 strm.opaque = Z_NULL;
282 int ret = deflateInit2( &strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, MAX_WBITS + DEC_MAGIC_NUM_FOR_GZIP, 8, Z_DEFAULT_STRATEGY );
286 strm.avail_in = bytesInLeft;
287 strm.next_in = bytesInPtr;
293 strm.avail_out = CHUNK;
295 ret = deflate( &strm, Z_FINISH );
296 Q_ASSERT( ret != Z_STREAM_ERROR );
298 const unsigned have = CHUNK - strm.avail_out;
299 bytesOut.append( QByteArray::fromRawData(
reinterpret_cast<const char *
>( out ),
static_cast<int>( have ) ) );
301 while ( strm.avail_out == 0 );
302 Q_ASSERT( ret == Z_STREAM_END );
bool create()
Creates a new MBTiles file and initializes it with metadata and tiles tables.
QImage tileDataAsImage(int z, int x, int y)
Returns tile decoded as a raster image (if stored in a known format like JPG or PNG)
QgsMbTiles(const QString &filename)
Constructs MBTiles reader (but it does not open the file yet)
bool open()
Tries to open the file, returns true on success.
QByteArray tileData(int z, int x, int y)
Returns raw tile data for given tile.
static bool decodeGzip(const QByteArray &bytesIn, QByteArray &bytesOut)
Decodes gzip byte stream, returns true on success. Useful for reading vector tiles.
bool isOpen() const
Returns whether the MBTiles file is currently opened.
void setTileData(int z, int x, int y, const QByteArray &data)
Adds tile data for the given tile coordinates.
QString metadataValue(const QString &key)
Requests metadata value for the given key.
QgsRectangle extent()
Returns bounding box from metadata, given in WGS 84 (if available)
static bool encodeGzip(const QByteArray &bytesIn, QByteArray &bytesOut)
Encodes gzip byte stream, returns true on success. Useful for writing vector tiles.
void setMetadataValue(const QString &key, const QString &value)
Sets metadata value for the given key.
A rectangle specified with double values.
static QString quotedValue(const QVariant &value)
Returns a properly quoted and escaped version of value for use in SQL strings.
Unique pointer for sqlite3 databases, which automatically closes the database when the pointer goes o...
sqlite3_statement_unique_ptr prepare(const QString &sql, int &resultCode) const
Prepares a sql statement, returning the result.
QString errorMessage() const
Returns the most recent error message encountered by the database.
int open_v2(const QString &path, int flags, const char *zVfs)
Opens the database at the specified file path.
int exec(const QString &sql, QString &errorMessage) const
Executes the sql command in the database.
Unique pointer for sqlite3 prepared statements, which automatically finalizes the statement when the ...
QString columnAsText(int column) const
Returns the column value from the current statement row as a string.
int step()
Steps to the next record in the statement, returning the sqlite3 result code.
QByteArray columnAsBlob(int column) const
Returns the column value from the current statement row as raw byte array.
#define QgsDebugMsgLevel(str, level)