28   : mFilename( filename )
 
   38   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   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   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 )
 
  165     QgsDebugMsg( QStringLiteral( 
"MBTile not found: z=%1 x=%2 y=%3" ).arg( z ).arg( x ).arg( y ) );
 
  175   QByteArray tileBlob = 
tileData( z, x, y );
 
  176   if ( !tileImage.loadFromData( tileBlob ) )
 
  178     QgsDebugMsg( QStringLiteral( 
"MBTile data failed to load: z=%1 x=%2 y=%3" ).arg( z ).arg( x ).arg( y ) );
 
  188     QgsDebugMsg( QStringLiteral( 
"MBTiles database not open: " ) + mFilename );
 
  193   QString sql = QStringLiteral( 
"insert into tiles values (%1, %2, %3, ?)" ).arg( z ).arg( x ).arg( y );
 
  195   if ( result != SQLITE_OK )
 
  197     QgsDebugMsg( QStringLiteral( 
"MBTile failed to prepare statement: " ) + sql );
 
  201   sqlite3_bind_blob( preparedStatement.get(), 1, data.constData(), data.size(), SQLITE_TRANSIENT );
 
  203   if ( preparedStatement.
step() != SQLITE_DONE )
 
  205     QgsDebugMsg( QStringLiteral( 
"MBTile tile failed to be set: %1,%2,%3" ).arg( z ).arg( x ).arg( y ) );
 
  212   unsigned char *bytesInPtr = 
reinterpret_cast<unsigned char *
>( 
const_cast<char *
>( bytesIn.constData() ) );
 
  213   uint bytesInLeft = 
static_cast<uint
>( bytesIn.count() );
 
  215   const uint CHUNK = 16384;
 
  216   unsigned char out[CHUNK];
 
  217   const int DEC_MAGIC_NUM_FOR_GZIP = 16;
 
  221   strm.zalloc = Z_NULL;
 
  223   strm.opaque = Z_NULL;
 
  225   strm.next_in = Z_NULL;
 
  227   int ret = inflateInit2( &strm, MAX_WBITS + DEC_MAGIC_NUM_FOR_GZIP );
 
  231   while ( ret != Z_STREAM_END ) 
 
  234     uint bytesToProcess = std::min( CHUNK, bytesInLeft );
 
  235     strm.next_in = bytesInPtr;
 
  236     strm.avail_in = bytesToProcess;
 
  237     bytesInPtr += bytesToProcess;
 
  238     bytesInLeft -= bytesToProcess;
 
  240     if ( bytesToProcess == 0 )
 
  246       strm.avail_out = CHUNK;
 
  248       ret = inflate( &strm, Z_NO_FLUSH );
 
  249       Q_ASSERT( ret != Z_STREAM_ERROR ); 
 
  250       if ( ret == Z_NEED_DICT || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR )
 
  255       unsigned have = CHUNK - strm.avail_out;
 
  256       bytesOut.append( QByteArray::fromRawData( 
reinterpret_cast<const char *
>( out ), 
static_cast<int>( have ) ) );
 
  258     while ( strm.avail_out == 0 );
 
  262   return ret == Z_STREAM_END;
 
  268   unsigned char *bytesInPtr = 
reinterpret_cast<unsigned char *
>( 
const_cast<char *
>( bytesIn.constData() ) );
 
  269   uint bytesInLeft = 
static_cast<uint
>( bytesIn.count() );
 
  271   const uint CHUNK = 16384;
 
  272   unsigned char out[CHUNK];
 
  273   const int DEC_MAGIC_NUM_FOR_GZIP = 16;
 
  277   strm.zalloc = Z_NULL;
 
  279   strm.opaque = Z_NULL;
 
  281   int ret = deflateInit2( &strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, MAX_WBITS + DEC_MAGIC_NUM_FOR_GZIP, 8, Z_DEFAULT_STRATEGY );
 
  285   strm.avail_in = bytesInLeft;
 
  286   strm.next_in = bytesInPtr;
 
  292     strm.avail_out = CHUNK;
 
  294     ret = deflate( &strm, Z_FINISH );  
 
  295     Q_ASSERT( ret != Z_STREAM_ERROR ); 
 
  297     unsigned have = CHUNK - strm.avail_out;
 
  298     bytesOut.append( QByteArray::fromRawData( 
reinterpret_cast<const char *
>( out ), 
static_cast<int>( have ) ) );
 
  300   while ( strm.avail_out == 0 );
 
  301   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.