diff --git a/mbutils.py b/mbutils.py index 0c27380..9df4fde 100644 --- a/mbutils.py +++ b/mbutils.py @@ -9,7 +9,8 @@ # for additional reference on schema see: # https://github.com/mapbox/node-mbtiles/blob/master/lib/schema.sql -import sqlite3, uuid, sys, logging, time, os, json, zlib, re +import sqlite3, sys, logging, time, os, json, zlib, re + logger = logging.getLogger(__name__) @@ -34,13 +35,14 @@ def mbtiles_setup(cur): cur.execute("""create unique index tile_index on tiles (zoom_level, tile_column, tile_row);""") -def mbtiles_connect(mbtiles_file): +def mbtiles_connect(mbtiles_file, silent=True): try: - con = sqlite3.connect(mbtiles_file, check_same_thread=False) + con = sqlite3.connect(mbtiles_file) return con - except Exception, e: - logger.error("Could not connect to database") - logger.exception(e) + except Exception as e: + if not silent: + logger.error("Could not connect to database") + logger.exception(e) sys.exit(1) def optimize_connection(cur): @@ -48,42 +50,58 @@ def optimize_connection(cur): cur.execute("""PRAGMA locking_mode=EXCLUSIVE""") cur.execute("""PRAGMA journal_mode=DELETE""") -def compression_prepare(cur, con): +def compression_prepare(cur, silent): + if not silent: + logger.debug('Prepare database compression.') cur.execute(""" CREATE TABLE if not exists images ( tile_data blob, - tile_id VARCHAR(256)); + tile_id integer); """) cur.execute(""" CREATE TABLE if not exists map ( zoom_level integer, tile_column integer, tile_row integer, - tile_id VARCHAR(256)); + tile_id integer); """) -def optimize_database(cur): - logger.debug('analyzing db') +def optimize_database(cur, silent=True): + if not silent: + logger.debug('analyzing db') cur.execute("""ANALYZE;""") - logger.debug('cleaning db') + if not silent: + logger.debug('cleaning db') + + # Workaround for python>=3.6.0,python<3.6.2 + # https://bugs.python.org/issue28518 + cur.isolation_level = None cur.execute("""VACUUM;""") + cur.isolation_level = '' # reset default value of isolation_level -def compression_do(cur, con, chunk): + +def compression_do(cur, con, chunk, silent=True): + if not silent: + logger.debug('Making database compression.') overlapping = 0 unique = 0 total = 0 cur.execute("select count(zoom_level) from tiles") res = cur.fetchone() total_tiles = res[0] - logging.debug("%d total tiles to fetch" % total_tiles) - for i in range(total_tiles / chunk + 1): - logging.debug("%d / %d rounds done" % (i, (total_tiles / chunk))) + last_id = 0 + if not silent: + logging.debug("%d total tiles to fetch" % total_tiles) + for i in range(total_tiles // chunk + 1): + if not silent: + logging.debug("%d / %d rounds done" % (i, (total_tiles / chunk))) ids = [] files = [] start = time.time() cur.execute("""select zoom_level, tile_column, tile_row, tile_data from tiles where rowid > ? and rowid <= ?""", ((i * chunk), ((i + 1) * chunk))) - logger.debug("select: %s" % (time.time() - start)) + if not silent: + logger.debug("select: %s" % (time.time() - start)) rows = cur.fetchall() for r in rows: total = total + 1 @@ -93,30 +111,35 @@ def compression_do(cur, con, chunk): query = """insert into map (zoom_level, tile_column, tile_row, tile_id) values (?, ?, ?, ?)""" - logger.debug("insert: %s" % (time.time() - start)) + if not silent: + logger.debug("insert: %s" % (time.time() - start)) cur.execute(query, (r[0], r[1], r[2], ids[files.index(r[3])])) else: unique = unique + 1 - id = str(uuid.uuid4()) + last_id += 1 - ids.append(id) + ids.append(last_id) files.append(r[3]) start = time.time() query = """insert into images (tile_id, tile_data) values (?, ?)""" - cur.execute(query, (str(id), sqlite3.Binary(r[3]))) - logger.debug("insert into images: %s" % (time.time() - start)) + cur.execute(query, (str(last_id), sqlite3.Binary(r[3]))) + if not silent: + logger.debug("insert into images: %s" % (time.time() - start)) start = time.time() query = """insert into map (zoom_level, tile_column, tile_row, tile_id) values (?, ?, ?, ?)""" - cur.execute(query, (r[0], r[1], r[2], id)) - logger.debug("insert into map: %s" % (time.time() - start)) + cur.execute(query, (r[0], r[1], r[2], last_id)) + if not silent: + logger.debug("insert into map: %s" % (time.time() - start)) con.commit() -def compression_finalize(cur): +def compression_finalize(cur, con, silent=True): + if not silent: + logger.debug('Finalizing database compression.') cur.execute("""drop table tiles;""") cur.execute("""create view tiles as select map.zoom_level as zoom_level, @@ -130,102 +153,150 @@ def compression_finalize(cur): cur.execute(""" CREATE UNIQUE INDEX images_id on images (tile_id);""") + + # Workaround for python>=3.6.0,python<3.6.2 + # https://bugs.python.org/issue28518 + con.isolation_level = None cur.execute("""vacuum;""") + con.isolation_level = '' # reset default value of isolation_level + cur.execute("""analyze;""") -def getDirs(path): +def get_dirs(path): return [name for name in os.listdir(path) if os.path.isdir(os.path.join(path, name))] def disk_to_mbtiles(directory_path, mbtiles_file, **kwargs): - logger.info("Importing disk to MBTiles") - logger.debug("%s --> %s" % (directory_path, mbtiles_file)) - con = mbtiles_connect(mbtiles_file) + + silent = kwargs.get('silent') + + if not silent: + logger.info("Importing disk to MBTiles") + logger.debug("%s --> %s" % (directory_path, mbtiles_file)) + + con = mbtiles_connect(mbtiles_file, silent) cur = con.cursor() optimize_connection(cur) mbtiles_setup(cur) #~ image_format = 'png' image_format = kwargs.get('format', 'png') + try: metadata = json.load(open(os.path.join(directory_path, 'metadata.json'), 'r')) image_format = kwargs.get('format') for name, value in metadata.items(): cur.execute('insert into metadata (name, value) values (?, ?)', (name, value)) - logger.info('metadata from metadata.json restored') + if not silent: + logger.info('metadata from metadata.json restored') except IOError: - logger.warning('metadata.json not found') + if not silent: + logger.warning('metadata.json not found') count = 0 start_time = time.time() - msg = "" - for zoomDir in getDirs(directory_path): + for zoom_dir in get_dirs(directory_path): if kwargs.get("scheme") == 'ags': - if not "L" in zoomDir: - logger.warning("You appear to be using an ags scheme on an non-arcgis Server cache.") - z = int(zoomDir.replace("L", "")) + if not "L" in zoom_dir: + if not silent: + logger.warning("You appear to be using an ags scheme on an non-arcgis Server cache.") + z = int(zoom_dir.replace("L", "")) + elif kwargs.get("scheme") == 'gwc': + z=int(zoom_dir[-2:]) else: - if "L" in zoomDir: - logger.warning("You appear to be using a %s scheme on an arcgis Server cache. Try using --scheme=ags instead" % kwargs.get("scheme")) - z = int(zoomDir) - for rowDir in getDirs(os.path.join(directory_path, zoomDir)): + if "L" in zoom_dir: + if not silent: + logger.warning("You appear to be using a %s scheme on an arcgis Server cache. Try using --scheme=ags instead" % kwargs.get("scheme")) + z = int(zoom_dir) + for row_dir in get_dirs(os.path.join(directory_path, zoom_dir)): if kwargs.get("scheme") == 'ags': - y = flip_y(z, int(rowDir.replace("R", ""), 16)) + y = flip_y(z, int(row_dir.replace("R", ""), 16)) + elif kwargs.get("scheme") == 'gwc': + pass + elif kwargs.get("scheme") == 'zyx': + y = flip_y(int(z), int(row_dir)) else: - x = int(rowDir) - for current_file in os.listdir(os.path.join(directory_path, zoomDir, rowDir)): - file_name, ext = current_file.split('.', 1) - f = open(os.path.join(directory_path, zoomDir, rowDir, current_file), 'rb') - file_content = f.read() - f.close() - if kwargs.get('scheme') == 'xyz': - y = flip_y(int(z), int(file_name)) - elif kwargs.get("scheme") == 'ags': - x = int(file_name.replace("C", ""), 16) + x = int(row_dir) + for current_file in os.listdir(os.path.join(directory_path, zoom_dir, row_dir)): + if current_file == ".DS_Store" and not silent: + logger.warning("Your OS is MacOS,and the .DS_Store file will be ignored.") else: - y = int(file_name) - - if (ext == image_format): - logger.debug(' Read tile from Zoom (z): %i\tCol (x): %i\tRow (y): %i' % (z, x, y)) - cur.execute("""insert into tiles (zoom_level, - tile_column, tile_row, tile_data) values - (?, ?, ?, ?);""", - (z, x, y, sqlite3.Binary(file_content))) - count = count + 1 - if (count % 100) == 0: - for c in msg: sys.stdout.write(chr(8)) - msg = "%s tiles inserted (%d tiles/sec)" % (count, count / (time.time() - start_time)) - sys.stdout.write(msg) - elif (ext == 'grid.json'): - logger.debug(' Read grid from Zoom (z): %i\tCol (x): %i\tRow (y): %i' % (z, x, y)) - # Remove potential callback with regex - has_callback = re.match(r'[\w\s=+-/]+\(({(.|\n)*})\);?', file_content) - if has_callback: - file_content = has_callback.group(1) - utfgrid = json.loads(file_content) - - data = utfgrid.pop('data') - compressed = zlib.compress(json.dumps(utfgrid)) - cur.execute("""insert into grids (zoom_level, tile_column, tile_row, grid) values (?, ?, ?, ?) """, (z, x, y, sqlite3.Binary(compressed))) - grid_keys = [k for k in utfgrid['keys'] if k != ""] - for key_name in grid_keys: - key_json = data[key_name] - cur.execute("""insert into grid_data (zoom_level, tile_column, tile_row, key_name, key_json) values (?, ?, ?, ?, ?);""", (z, x, y, key_name, json.dumps(key_json))) - - logger.debug('tiles (and grids) inserted.') - optimize_database(con) + file_name, ext = current_file.split('.',1) + f = open(os.path.join(directory_path, zoom_dir, row_dir, current_file), 'rb') + file_content = f.read() + f.close() + if kwargs.get('scheme') == 'xyz': + y = flip_y(int(z), int(file_name)) + elif kwargs.get("scheme") == 'ags': + x = int(file_name.replace("C", ""), 16) + elif kwargs.get("scheme") == 'gwc': + x, y = file_name.split('_') + x = int(x) + y = int(y) + elif kwargs.get("scheme") == 'zyx': + x = int(file_name) + else: + y = int(file_name) + + if (ext == image_format): + if not silent: + logger.debug(' Read tile from Zoom (z): %i\tCol (x): %i\tRow (y): %i' % (z, x, y)) + cur.execute("""insert into tiles (zoom_level, + tile_column, tile_row, tile_data) values + (?, ?, ?, ?);""", + (z, x, y, sqlite3.Binary(file_content))) + count = count + 1 + if (count % 100) == 0 and not silent: + logger.info(" %s tiles inserted (%d tiles/sec)" % (count, count / (time.time() - start_time))) + elif (ext == 'grid.json'): + if not silent: + logger.debug(' Read grid from Zoom (z): %i\tCol (x): %i\tRow (y): %i' % (z, x, y)) + # Remove potential callback with regex + file_content = file_content.decode('utf-8') + has_callback = re.match(r'[\w\s=+-/]+\(({(.|\n)*})\);?', file_content) + if has_callback: + file_content = has_callback.group(1) + utfgrid = json.loads(file_content) + + data = utfgrid.pop('data') + compressed = zlib.compress(json.dumps(utfgrid).encode()) + cur.execute("""insert into grids (zoom_level, tile_column, tile_row, grid) values (?, ?, ?, ?) """, (z, x, y, sqlite3.Binary(compressed))) + grid_keys = [k for k in utfgrid['keys'] if k != ""] + for key_name in grid_keys: + key_json = data[key_name] + cur.execute("""insert into grid_data (zoom_level, tile_column, tile_row, key_name, key_json) values (?, ?, ?, ?, ?);""", (z, x, y, key_name, json.dumps(key_json))) + + if not silent: + logger.debug('tiles (and grids) inserted.') + + if kwargs.get('compression', False): + compression_prepare(cur, silent) + compression_do(cur, con, 256, silent) + compression_finalize(cur, con, silent) + + optimize_database(con, silent) + +def mbtiles_metadata_to_disk(mbtiles_file, **kwargs): + silent = kwargs.get('silent') + if not silent: + logger.debug("Exporting MBTiles metatdata from %s" % (mbtiles_file)) + con = mbtiles_connect(mbtiles_file, silent) + metadata = dict(con.execute('select name, value from metadata;').fetchall()) + if not silent: + logger.debug(json.dumps(metadata, indent=2)) def mbtiles_to_disk(mbtiles_file, directory_path, **kwargs): - logger.debug("Exporting MBTiles to disk") - logger.debug("%s --> %s" % (mbtiles_file, directory_path)) - con = mbtiles_connect(mbtiles_file) + silent = kwargs.get('silent') + if not silent: + logger.debug("Exporting MBTiles to disk") + logger.debug("%s --> %s" % (mbtiles_file, directory_path)) + con = mbtiles_connect(mbtiles_file, silent) os.mkdir("%s" % directory_path) metadata = dict(con.execute('select name, value from metadata;').fetchall()) json.dump(metadata, open(os.path.join(directory_path, 'metadata.json'), 'w'), indent=4) count = con.execute('select count(zoom_level) from tiles;').fetchone()[0] done = 0 - msg = '' base_path = directory_path if not os.path.isdir(base_path): os.makedirs(base_path) @@ -233,9 +304,9 @@ def mbtiles_to_disk(mbtiles_file, directory_path, **kwargs): # if interactivity formatter = metadata.get('formatter') if formatter: - layer_json = os.path.join(base_path,'layer.json') + layer_json = os.path.join(base_path, 'layer.json') formatter_json = {"formatter":formatter} - open(layer_json,'w').write('grid(' + json.dumps(formatter_json) + ')') + open(layer_json, 'w').write(json.dumps(formatter_json)) tiles = con.execute('select zoom_level, tile_column, tile_row, tile_data from tiles;') t = tiles.fetchone() @@ -245,7 +316,8 @@ def mbtiles_to_disk(mbtiles_file, directory_path, **kwargs): y = t[2] if kwargs.get('scheme') == 'xyz': y = flip_y(z,y) - print 'flipping' + if not silent: + logger.debug('flipping') tile_dir = os.path.join(base_path, str(z), str(x)) elif kwargs.get('scheme') == 'wms': tile_dir = os.path.join(base_path, @@ -267,14 +339,13 @@ def mbtiles_to_disk(mbtiles_file, directory_path, **kwargs): f.write(t[3]) f.close() done = done + 1 - for c in msg: sys.stdout.write(chr(8)) - logger.info('%s / %s tiles exported' % (done, count)) + if not silent: + logger.info('%s / %s tiles exported' % (done, count)) t = tiles.fetchone() # grids callback = kwargs.get('callback') done = 0 - msg = '' try: count = con.execute('select count(zoom_level) from grids;').fetchone()[0] grids = con.execute('select zoom_level, tile_column, tile_row, grid from grids;') @@ -297,7 +368,7 @@ def mbtiles_to_disk(mbtiles_file, directory_path, **kwargs): os.makedirs(grid_dir) grid = os.path.join(grid_dir,'%s.grid.json' % (y)) f = open(grid, 'w') - grid_json = json.loads(zlib.decompress(g[3])) + grid_json = json.loads(zlib.decompress(g[3]).decode('utf-8')) # join up with the grid 'data' which is in pieces when stored in mbtiles file grid_data = grid_data_cursor.fetchone() data = {} @@ -311,6 +382,6 @@ def mbtiles_to_disk(mbtiles_file, directory_path, **kwargs): f.write('%s(%s);' % (callback, json.dumps(grid_json))) f.close() done = done + 1 - for c in msg: sys.stdout.write(chr(8)) - logger.info('%s / %s grids exported' % (done, count)) + if not silent: + logger.info('%s / %s grids exported' % (done, count)) g = grids.fetchone() diff --git a/metadata.txt b/metadata.txt index b581b84..7b1a2d6 100644 --- a/metadata.txt +++ b/metadata.txt @@ -1,31 +1,12 @@ [general] -name=QTiles -description=Generate tiles from QGIS project +name=QTiles3 +description=Generate tiles from QGIS project. Ported to QGIS 3 with sponsorship by Gamaya SA (https://gamaya.com/). Enhanced by Nacho Urenda (nurenda@bcn.cat, Barcelona City Council). category=Plugins -version=1.5.2 -qgisMinimumVersion=2.0 +version=1.7.1 +qgisMinimumVersion=3.0 -author=NextGIS -email=info@nextgis.com - -changelog=1.5.2 - * Removed the limitation of the maximum zoom - * Host css+js in local repository for LeafLet preview - 1.5.1: - * create tiles for NextGIS Mobile - * add MBTiles compression - * add export MBTiles metadata to .json file - * add image overview for MBTiles - * add option for skiping tiles outside of layers extents (within combined extent) - 1.5.0: - * change MBTiles parameters vаlues: format in lower case, description is 'Created with QTiles' - * tiles are now produced correctly when transparency is set - * geojson is now rendered correctly - * CRS shift when using 3857 is fixed - 1.4.6: - * works fine now with non-english characters in folder names - * add MBTiles initialize arguments for Geopaparazzi4 - * take into account the actual zoom level when generating tiles +author=NextGIS, Alexander Bruy, Nacho Urenda +email=nurenda@bcn.cat icon=icons/qtiles.png @@ -33,9 +14,9 @@ tags=raster,tiles homepage=https://github.com/nextgis/QTiles tracker=https://github.com/nextgis/QTiles/issues -repository=https://github.com/nextgis/QTiles +repository=https://github.com/nextgis/qtiles experimental=True deprecated=False -about=Generates raster tiles from QGIS project for selected zoom levels and tile naming conventions (Slippy Map or TMS). It can also package tiles for variety of formats and applications, NextGIS Mobile, GeoPaparazzi, simple Leaflet-based viewer and MBTiles. +about=Generates raster tiles from QGIS project for selected zoom levels and tile naming conventions (Slippy Map or TMS). It can also package tiles for variety of formats and applications, GeoPaparazzi, simple Leaflet-based viewer and MBTiles. This is an ampliation of the QTiles3 original plugin with blank tiles detection and increased performance. diff --git a/qtiles.py b/qtiles.py index f65ed39..6d09876 100644 --- a/qtiles.py +++ b/qtiles.py @@ -7,6 +7,7 @@ # Generates tiles from QGIS project # # Copyright (C) 2012-2014 NextGIS (info@nextgis.org) +# Copyright (C) 2019 Alexander Bruy (alexander.bruy@gmail.com) # # This source is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free @@ -25,32 +26,30 @@ # #****************************************************************************** +from qgis.PyQt.QtCore import QFileInfo, QLocale, QTranslator, QCoreApplication +from qgis.PyQt.QtGui import QIcon +from qgis.PyQt.QtWidgets import QMessageBox, QAction +from qgis.core import Qgis, QgsApplication, QgsSettings -from PyQt4.QtCore import * -from PyQt4.QtGui import * - -from qgis.core import * - -import qtilesdialog -import aboutdialog - -import resources_rc +from . import resources_rc +from .aboutdialog import AboutDialog +from .qtilesdialog import QTilesDialog class QTilesPlugin: def __init__(self, iface): self.iface = iface - self.qgsVersion = unicode(QGis.QGIS_VERSION_INT) + self.qgsVersion = str(Qgis.QGIS_VERSION_INT) - userPluginPath = QFileInfo(QgsApplication.qgisUserDbFilePath()).path() + '/python/plugins/qtiles' + userPluginPath = QFileInfo(QgsApplication.qgisUserDatabaseFilePath()).path() + '/python/plugins/qtiles' systemPluginPath = QgsApplication.prefixPath() + '/python/plugins/qtiles' - overrideLocale = QSettings().value('locale/overrideFlag', False, type=bool) + overrideLocale = QgsSettings().value('locale/overrideFlag', False, type=bool) if not overrideLocale: localeFullName = QLocale.system().name() else: - localeFullName = QSettings().value('locale/userLocale', '') + localeFullName = QgsSettings().value('locale/userLocale', '') if QFileInfo(userPluginPath).exists(): translationPath = userPluginPath + '/i18n/qtiles_' + localeFullName + '.qm' @@ -92,10 +91,10 @@ def unload(self): self.iface.removePluginMenu(QCoreApplication.translate('QTiles', 'QTiles'), self.actionAbout) def run(self): - d = qtilesdialog.QTilesDialog(self.iface) + d = QTilesDialog(self.iface) d.show() d.exec_() def about(self): - d = aboutdialog.AboutDialog() + d = AboutDialog() d.exec_() diff --git a/qtiles_utils.py b/qtiles_utils.py index 7572e0a..d1a335b 100644 --- a/qtiles_utils.py +++ b/qtiles_utils.py @@ -7,6 +7,7 @@ # Generates tiles from QGIS project # # Copyright (C) 2012-2014 NextGIS (info@nextgis.org) +# Copyright (C) 2019 Alexander Bruy (alexander.bruy@gmail.com) # # This source is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free @@ -25,42 +26,27 @@ # #****************************************************************************** - -from PyQt4.QtCore import * - -from qgis.core import * +from qgis.core import QgsProject, QgsMapLayer def getMapLayers(): - layerMap = QgsMapLayerRegistry.instance().mapLayers() + layerMap = QgsProject.instance().mapLayers() layers = dict() - for name, layer in layerMap.iteritems(): + for name, layer in layerMap.items(): if layer.type() == QgsMapLayer.VectorLayer: if layer.id() not in layers.keys(): - layers[layer.id()] = unicode(layer.name()) + layers[layer.id()] = layer.name() if layer.type() == QgsMapLayer.RasterLayer and layer.providerType() == 'gdal': if layer.id() not in layers.keys(): - layers[layer.id()] = unicode(layer.name()) + layers[layer.id()] = layer.name() return layers def getLayerById(layerId): - layerMap = QgsMapLayerRegistry.instance().mapLayers() - for name, layer in layerMap.iteritems(): + layerMap = QgsProject.instance().mapLayers() + for name, layer in layerMap.items(): if layer.id() == layerId: if layer.isValid(): return layer else: return None - - -def getLayerGroup(relations, layerId): - group = None - - for item in relations: - group = unicode(item[0]) - for lid in item[1]: - if unicode(lid) == unicode(layerId): - return group - - return group diff --git a/qtilesdialog.py b/qtilesdialog.py index 801a978..be1d866 100644 --- a/qtilesdialog.py +++ b/qtilesdialog.py @@ -7,6 +7,7 @@ # Generates tiles from QGIS project # # Copyright (C) 2012-2014 NextGIS (info@nextgis.org) +# Copyright (C) 2019 Alexander Bruy (alexander.bruy@gmail.com) # # This source is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free @@ -24,26 +25,34 @@ # MA 02110-1335 USA. # #****************************************************************************** -import os -import locale import math import operator -from PyQt4.QtCore import * -from PyQt4.QtGui import * -from qgis.core import * -import tilingthread -from ui.ui_qtilesdialogbase import Ui_Dialog -import qtiles_utils as utils +import os +import time + +from qgis.PyQt.QtCore import QFileInfo, QDir, Qt, pyqtSlot +from qgis.PyQt.QtGui import QIcon +from qgis.PyQt.QtWidgets import QDialog, QDialogButtonBox, QMessageBox, QFileDialog +from qgis.core import QgsCoordinateTransform, QgsCoordinateReferenceSystem, QgsRectangle, QgsProject, QgsSettings + +from . import qtiles_utils as utils +from .tilingthread import TilingThread +from .ui.ui_qtilesdialogbase import Ui_Dialog +#↓import locale +#import functools class QTilesDialog(QDialog, Ui_Dialog): # MAX_ZOOM_LEVEL = 18 MIN_ZOOM_LEVEL = 0 - def __init__(self, iface): + def __init__(self, iface: object) -> object: QDialog.__init__(self) self.setupUi(self) + #self.skipBlankTiles = False; + #self.macroTile = 1 + self.btnOk = self.buttonBox.addButton(self.tr("Run"), QDialogButtonBox.AcceptRole) # self.spnZoomMax.setMaximum(self.MAX_ZOOM_LEVEL) @@ -56,16 +65,14 @@ def __init__(self, iface): self.iface = iface - self.verticalLayout_2.setAlignment(Qt.AlignTop) - self.workThread = None self.FORMATS = { self.tr('ZIP archives (*.zip *.ZIP)'): '.zip', self.tr('MBTiles databases (*.mbtiles *.MBTILES)'): '.mbtiles'} - self.settings = QSettings('NextGIS', 'QTiles') - self.grpParameters.setSettings(self.settings) + self.settings = QgsSettings('NextGIS', 'QTiles') +# self.grpParameters.setSettings(self.settings) self.btnClose = self.buttonBox.button(QDialogButtonBox.Close) self.rbExtentLayer.toggled.connect(self.__toggleLayerSelector) self.chkLockRatio.stateChanged.connect(self.__toggleHeightEdit) @@ -81,10 +88,12 @@ def __init__(self, iface): self.lInfoIconOutputZip.linkActivated.connect(self.show_output_info) self.lInfoIconOutputDir.linkActivated.connect(self.show_output_info) self.lInfoIconOutputNGM.linkActivated.connect(self.show_output_info) + + self.lInfoIconMacroTile.linkActivated.connect(self.show_output_info) self.manageGui() - def show_output_info(self, href): + def show_output_info(self): title = self.tr("Output type info") message = "" if self.sender() is self.lInfoIconOutputZip: @@ -100,17 +109,21 @@ def show_output_info(self, href): %s \ \ " % self.tr("Prepare package for NextGIS Mobile ") + elif self.sender() is self.lInfoIconMacroTile: + title = self.tr("Render tile sets") + message = self.tr("Rendering a set of many adjacent tiles at once\nsaves process time, at the expense of system memory") - # QMessageBox.information( - # self, - # title, - # message - # ) msgBox = QMessageBox() msgBox.setWindowTitle(title) msgBox.setText(message) msgBox.exec_() + def format_time_hhmmss(self, seconds): + m, s = divmod(seconds, 60) + h, m = divmod(m, 60) + time_str = "%02d:%02d:%02d" % (h, m, s) + return time_str + def formatChanged(self): if self.cmbFormat.currentText() == 'JPG': self.spnTransparency.setEnabled(False) @@ -121,13 +134,13 @@ def formatChanged(self): def manageGui(self): layers = utils.getMapLayers() - relations = self.iface.legendInterface().groupLayerRelationship() - for layer in sorted(layers.iteritems(), cmp=locale.strcoll, key=operator.itemgetter(1)): - groupName = utils.getLayerGroup(relations, layer[0]) - if groupName == '': + root = QgsProject.instance().layerTreeRoot() + for layer in sorted(layers.items(), key=operator.itemgetter(1)): + node = root.findLayer(layer[0]) + if node.parent() == root: self.cmbLayers.addItem(layer[1], layer[0]) else: - self.cmbLayers.addItem('%s - %s' % (layer[1], groupName), layer[0]) + self.cmbLayers.addItem('%s - %s' % (layer[1], node.parent().name()), layer[0]) self.rbOutputZip.setChecked(self.settings.value('outputToZip', True, type=bool)) self.rbOutputDir.setChecked(self.settings.value('outputToDir', False, type=bool)) @@ -162,6 +175,7 @@ def manageGui(self): self.spnTileHeight.setValue(self.settings.value('tileHeight', 256, type=int)) self.spnTransparency.setValue(self.settings.value('transparency', 255, type=int)) self.spnQuality.setValue(self.settings.value('quality', 70, type=int)) + self.spnMacroTile.setValue(self.settings.value('macroTile', 1, type=int)) self.cmbFormat.setCurrentIndex(int(self.settings.value('format', 0))) self.chkAntialiasing.setChecked(self.settings.value('enable_antialiasing', False, type=bool)) self.chkTMSConvention.setChecked(self.settings.value('use_tms_filenames', False, type=bool)) @@ -170,7 +184,9 @@ def manageGui(self): self.chkWriteOverview.setChecked(self.settings.value("write_overview", False, type=bool)) self.chkWriteMapurl.setChecked(self.settings.value("write_mapurl", False, type=bool)) self.chkWriteViewer.setChecked(self.settings.value("write_viewer", False, type=bool)) - self.chkRenderOutsideTiles.setChecked(self.settings.value("renderOutsideTiles", True, type=bool)) +# self.chkRenderOutsideTiles.setChecked(self.settings.value("renderOutsideTiles", True, type=bool)) + self.chkMsgDialogs.setChecked(self.settings.value("chkMsgDialogs", True, type=bool)) + self.chkSkipBlankTiles.setChecked(self.settings.value("skipBlankTiles", False, type=bool)) self.formatChanged() @@ -178,6 +194,10 @@ def reject(self): QDialog.reject(self) def accept(self): + self.startTime = time.time(); + self.tileCount = 0 + self.blankCount = 0 + if self.rbOutputZip.isChecked(): output = self.leZipFileName.text() elif self.rbOutputDir.isChecked(): @@ -219,14 +239,16 @@ def accept(self): self.settings.setValue('format', self.cmbFormat.currentIndex()) self.settings.setValue('transparency', self.spnTransparency.value()) self.settings.setValue('quality', self.spnQuality.value()) + self.settings.setValue('macroTile', self.spnMacroTile.value()) self.settings.setValue('enable_antialiasing', self.chkAntialiasing.isChecked()) self.settings.setValue('use_tms_filenames', self.chkTMSConvention.isChecked()) + self.settings.setValue('skipBlankTiles', self.chkSkipBlankTiles.isChecked()) self.settings.setValue('use_mbtiles_compression', self.chkMBTilesCompression.isChecked()) self.settings.setValue('write_json', self.chkWriteJson.isChecked()) self.settings.setValue('write_overview', self.chkWriteOverview.isChecked()) self.settings.setValue('write_mapurl', self.chkWriteMapurl.isChecked()) self.settings.setValue('write_viewer', self.chkWriteViewer.isChecked()) - self.settings.setValue('renderOutsideTiles', self.chkRenderOutsideTiles.isChecked()) + self.settings.setValue('chkMsgDialogs', self.chkMsgDialogs.isChecked()) canvas = self.iface.mapCanvas() if self.rbExtentCanvas.isChecked(): extent = canvas.extent() @@ -234,20 +256,21 @@ def accept(self): extent = canvas.fullExtent() else: layer = utils.getLayerById(self.cmbLayers.itemData(self.cmbLayers.currentIndex())) - extent = canvas.mapRenderer().layerExtentToOutputExtent(layer, layer.extent()) - extent = QgsCoordinateTransform(canvas.mapRenderer().destinationCrs(), QgsCoordinateReferenceSystem('EPSG:4326')).transform(extent) + extent = canvas.mapSettings().layerExtentToOutputExtent(layer, layer.extent()) + extent = QgsCoordinateTransform(canvas.mapSettings().destinationCrs(), QgsCoordinateReferenceSystem('EPSG:4326'), QgsProject.instance()).transform(extent) arctanSinhPi = math.degrees(math.atan(math.sinh(math.pi))) extent = extent.intersect(QgsRectangle(-180, -arctanSinhPi, 180, arctanSinhPi)) layers = canvas.layers() writeMapurl = self.chkWriteMapurl.isEnabled() and self.chkWriteMapurl.isChecked() writeViewer = self.chkWriteViewer.isEnabled() and self.chkWriteViewer.isChecked() - self.workThread = tilingthread.TilingThread( + self.workThread = TilingThread( layers, extent, self.spnZoomMin.value(), self.spnZoomMax.value(), self.spnTileWidth.value(), self.spnTileHeight.value(), + self.spnMacroTile.value(), self.spnTransparency.value(), self.spnQuality.value(), self.cmbFormat.currentText(), @@ -258,7 +281,8 @@ def accept(self): self.chkMBTilesCompression.isChecked(), self.chkWriteJson.isChecked(), self.chkWriteOverview.isChecked(), - self.chkRenderOutsideTiles.isChecked(), +# self.chkRenderOutsideTiles.isChecked(), + self.chkSkipBlankTiles.isChecked(), writeMapurl, writeViewer ) @@ -291,14 +315,22 @@ def setProgressRange(self, message, value): self.progressBar.setFormat(message) self.progressBar.setRange(0, value) - def updateProgress(self): + def updateProgress(self, tileCount, blankCount ): + self.tileCount = tileCount + self.blankCount = blankCount self.progressBar.setValue(self.progressBar.value() + 1) def processInterrupted(self): + if self.chkMsgDialogs.isChecked(): QMessageBox.warning(self,"Qtiles","Process interrupted!") self.restoreGui() def processFinished(self): self.stopProcessing() + elapsedTime = time.time() - self.startTime + txt = "Process finished normally.\nElapsed time: %s.\nTiles written: %d." % (self.format_time_hhmmss(elapsedTime), self.tileCount) + if self.blankCount > 0: + txt = "%s\nBlank tiles: %d." % (txt, self.blankCount) + if self.chkMsgDialogs.isChecked(): QMessageBox.information(self,"Qtiles", txt) self.restoreGui() def stopProcessing(self): @@ -366,7 +398,6 @@ def __toggleTarget(self, checked): self.chkWriteJson.setChecked(False) self.chkWriteJson.setEnabled(False) - def __toggleLayerSelector(self, checked): self.cmbLayers.setEnabled(checked) @@ -387,7 +418,7 @@ def __updateTileSize(self, value): def __select_output(self): if self.rbOutputZip.isChecked(): file_directory = QFileInfo(self.settings.value('outputToZip_Path', '.')).absolutePath() - outPath, outFilter = QFileDialog.getSaveFileNameAndFilter(self, self.tr('Save to file'), file_directory, ';;'.join(self.FORMATS.iterkeys()), self.FORMATS.keys()[self.FORMATS.values().index('.zip')]) + outPath, outFilter = QFileDialog.getSaveFileName(self, self.tr('Save to file'), file_directory, ';;'.join(list(self.FORMATS.keys())), list(self.FORMATS.keys())[list(self.FORMATS.values()).index('.zip')]) if not outPath: return if not outPath.lower().endswith(self.FORMATS[outFilter]): @@ -405,10 +436,11 @@ def __select_output(self): elif self.rbOutputNGM.isChecked(): zip_directory = QFileInfo(self.settings.value('outputToNGM_Path', '.')).absolutePath() - outPath, outFilter = QFileDialog.getSaveFileNameAndFilter(self, self.tr('Save to file'), zip_directory, 'ngrc') + outPath, outFilter = QFileDialog.getSaveFileName(self, self.tr('Save to file'), zip_directory, 'ngrc') if not outPath: return if not outPath.lower().endswith('ngrc'): outPath += '.ngrc' self.leTilesFroNGM.setText(outPath) self.settings.setValue('outputToNGM_Path', QFileInfo(outPath).absoluteFilePath()) + diff --git a/tile.py b/tile.py index 50c422c..619bfa5 100644 --- a/tile.py +++ b/tile.py @@ -1,12 +1,13 @@ # -*- coding: utf-8 -*- -#****************************************************************************** +# ****************************************************************************** # # QTiles # --------------------------------------------------------- # Generates tiles from QGIS project # # Copyright (C) 2012-2014 NextGIS (info@nextgis.org) +# Copyright (C) 2019 Alexander Bruy (alexander.bruy@gmail.com) # # This source is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free @@ -23,16 +24,16 @@ # to the Free Software Foundation, 51 Franklin Street, Suite 500 Boston, # MA 02110-1335 USA. # -#****************************************************************************** +# ****************************************************************************** import math -from qgis.core import * +from qgis.core import QgsPointXY, QgsRectangle class Tile: - def __init__(self, x=0, y=0, z=0, tms=1): + def __init__(self, x=0, y=0, z=0, tms=False): self.x = x self.y = y self.z = z @@ -40,9 +41,35 @@ def __init__(self, x=0, y=0, z=0, tms=1): def toPoint(self): n = math.pow(2, self.z) + if (self.tms): + tms_f = -1 + else: + tms_f = 1 longitude = float(self.x) / n * 360.0 - 180.0 - latitude = self.tms * math.degrees(math.atan(math.sinh(math.pi * (1.0 - 2.0 * float(self.y) / n)))) - return QgsPoint(longitude, latitude) + latitude = tms_f * math.degrees(math.atan(math.sinh(math.pi * (1.0 - 2.0 * float(self.y) / n)))) + return QgsPointXY(longitude, latitude) def toRectangle(self): return QgsRectangle(self.toPoint(), Tile(self.x + 1, self.y + 1, self.z, self.tms).toPoint()) + + def toExpandedRectangle(self): + return QgsRectangle(Tile(self.x-1, self.y-1, self.z, self.tms).toPoint(), + Tile(self.x+2, self.y+2, self.z, self.tms).toPoint()) + + +class TileLevelInfo: + def __init__(self, zoomLevel, firstCol, firstRow, lastCol, lastRow): + self.zoomLevel = zoomLevel + self.firstCol = firstCol + self.firstRow = firstRow + self.lastCol = lastCol + self.lastRow = lastRow + + +def tileFromLatLon(lat_deg, lon_deg, zoom): + lat_rad = math.radians(lat_deg) + n = 2.0 ** zoom + xtile = int((lon_deg + 180.0) / 360.0 * n) + ytile = int((1.0 - math.log(math.tan(lat_rad) + (1 / math.cos(lat_rad))) / math.pi) / 2.0 * n) + return Tile(xtile, ytile, zoom) + diff --git a/tilingthread.py b/tilingthread.py index ec8cc11..817121d 100644 --- a/tilingthread.py +++ b/tilingthread.py @@ -7,6 +7,8 @@ # Generates tiles from QGIS project # # Copyright (C) 2012-2014 NextGIS (info@nextgis.org) +# Copyright (C) 2019 Alexander Bruy (alexander.bruy@gmail.com) +# Copyright (C) 2019 Nacho Urenda (nurenda@gmail.com) # # This source is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free @@ -24,51 +26,69 @@ # MA 02110-1335 USA. # #****************************************************************************** -import time import codecs import json from string import Template -from PyQt4.QtCore import * -from PyQt4.QtGui import * -from qgis.core import * -from tile import Tile -from writers import * -import resources_rc +import time +import datetime + +import sys +import os + +from qgis.PyQt.QtCore import QCoreApplication, QThread, pyqtSignal, QMutex, Qt, QFile, QIODevice, QRect, QSize +from qgis.PyQt.QtGui import QColor, QImage, QPainter, QBrush +from qgis.core import QgsProject, QgsCoordinateTransform, QgsCoordinateReferenceSystem, QgsMapRendererCustomPainterJob, QgsScaleCalculator, QgsMapSettings, QgsRectangle +from . import resources_rc +from .tile import Tile, TileLevelInfo, tileFromLatLon +from .writers import DirectoryWriter, ZipWriter, NGMArchiveWriter, MBTilesWriter + +# sys.path.append("C:\Python37\Lib\site-packages") +# import pydevd class TilingThread(QThread): rangeChanged = pyqtSignal(str, int) - updateProgress = pyqtSignal() + updateProgress = pyqtSignal(int, int) processFinished = pyqtSignal() processInterrupted = pyqtSignal() threshold = pyqtSignal(int) - warring_threshold_tiles_count = 10000 - - def __init__(self, layers, extent, minZoom, maxZoom, width, height, transp, quality, format, outputPath, rootDir, antialiasing, tmsConvention, mbtilesCompression, jsonFile, overview, renderOutsideTiles, mapUrl, viewer): + warning_threshold_tiles_count = 10000 + + def __init__(self, layers, extent, minZoom, maxZoom, width, height, macroTileSize, + transp, quality, fileFormat, outputPath, rootDir, antialiasing, tmsConvention, + mbtilesCompression, jsonFile, overview, skipBlankTiles, mapUrl, viewer): QThread.__init__(self, QThread.currentThread()) + self.mutex = QMutex() self.confirmMutex = QMutex() + self.tileLevelInfoList = [] self.stopMe = 0 self.interrupted = False + self.tile_count = 0 + self.blank_count = 0 + self.numTiles = 0 self.layers = layers self.extent = extent self.minZoom = minZoom self.maxZoom = maxZoom self.output = outputPath self.width = width + self.height = height + self.macroTileSize = macroTileSize + self.transp = transp if rootDir: self.rootDir = rootDir else: - self.rootDir = 'tileset_%s' % unicode(time.time()).split('.')[0] + self.rootDir = 'tileset_%s' % str(time.time()).split('.')[0] self.antialias = antialiasing self.tmsConvention = tmsConvention self.mbtilesCompression = mbtilesCompression - self.format = format + self.fileFormat = fileFormat self.quality = quality self.jsonFile = jsonFile self.overview = overview - self.renderOutsideTiles = renderOutsideTiles + self.skipBlankTiles = skipBlankTiles self.mapurl = mapUrl self.viewer = viewer if self.output.isDir(): @@ -81,28 +101,30 @@ def __init__(self, layers, extent, minZoom, maxZoom, width, height, transp, qual self.mode = 'MBTILES' self.tmsConvention = True self.interrupted = False - self.tiles = [] self.layersId = [] for layer in self.layers: self.layersId.append(layer.id()) myRed = QgsProject.instance().readNumEntry('Gui', '/CanvasColorRedPart', 255)[0] myGreen = QgsProject.instance().readNumEntry('Gui', '/CanvasColorGreenPart', 255)[0] myBlue = QgsProject.instance().readNumEntry('Gui', '/CanvasColorBluePart', 255)[0] - self.color = QColor(myRed, myGreen, myBlue, transp) - image = QImage(width, height, QImage.Format_ARGB32_Premultiplied) - self.projector = QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:4326'), QgsCoordinateReferenceSystem('EPSG:3395')) + self.color = QColor(myRed, myGreen, myBlue, self.transp) + + h = (self.height*self.macroTileSize) + (self.height*2) + w = self.width + (self.width*2) + image = QImage(w, h, QImage.Format_ARGB32_Premultiplied) + image.fill(Qt.transparent) + + self.projector = QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:4326'), QgsCoordinateReferenceSystem('EPSG:3857'), QgsProject.instance()) self.scaleCalc = QgsScaleCalculator() self.scaleCalc.setDpi(image.logicalDpiX()) - self.scaleCalc.setMapUnits(QgsCoordinateReferenceSystem('EPSG:3395').mapUnits()) + self.scaleCalc.setMapUnits(QgsCoordinateReferenceSystem('EPSG:3857').mapUnits()) self.settings = QgsMapSettings() self.settings.setBackgroundColor(self.color) - self.settings.setCrsTransformEnabled(True) self.settings.setOutputDpi(image.logicalDpiX()) self.settings.setOutputImageFormat(QImage.Format_ARGB32_Premultiplied) - self.settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3395')) + self.settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) self.settings.setOutputSize(image.size()) - self.settings.setLayers(self.layersId) - self.settings.setMapUnits(QgsCoordinateReferenceSystem('EPSG:3395').mapUnits()) + self.settings.setLayers(self.layers) if self.antialias: self.settings.setFlag(QgsMapSettings.Antialiasing, True) else: @@ -123,47 +145,38 @@ def run(self): elif self.mode == 'NGM': self.writer = NGMArchiveWriter(self.output, self.rootDir) elif self.mode == 'MBTILES': - self.writer = MBTilesWriter(self.output, self.rootDir, self.format, self.minZoom, self.maxZoom, self.extent, self.mbtilesCompression) + self.writer = MBTilesWriter(self.output, self.rootDir, self.fileFormat, self.minZoom, self.maxZoom, self.extent, self.mbtilesCompression) if self.jsonFile: self.writeJsonFile() if self.overview: self.writeOverviewFile() - self.rangeChanged.emit(self.tr('Searching tiles...'), 0) - useTMS = 1 - if self.tmsConvention: - useTMS = -1 - self.countTiles(Tile(0, 0, 0, useTMS)) - if self.interrupted: - del self.tiles[:] - self.tiles = None - self.processInterrupted.emit() - self.rangeChanged.emit(self.tr('Rendering: %v from %m (%p%)'), len(self.tiles)) + self.numTiles = self.calculateTileSets() + + self.rangeChanged.emit(self.tr('Rendering: %v from %m (%p%)'), self.numTiles) - if len(self.tiles) > self.warring_threshold_tiles_count: + if self.numTiles > self.warning_threshold_tiles_count: self.confirmMutex.lock() - self.threshold.emit(self.warring_threshold_tiles_count) + self.threshold.emit(self.warning_threshold_tiles_count) self.confirmMutex.lock() if self.interrupted: self.processInterrupted.emit() return - for t in self.tiles: - self.render(t) - self.updateProgress.emit() - self.mutex.lock() - s = self.stopMe - self.mutex.unlock() - if s == 1: - self.interrupted = True - break + self.renderMacroTiles() self.writer.finalize() + + self.mutex.lock() if not self.interrupted: self.processFinished.emit() + self.mutex.unlock() + return else: self.processInterrupted.emit() + self.mutex.unlock() + return def stop(self): self.mutex.lock() @@ -184,7 +197,7 @@ def writeJsonFile(self): filePath = '%s/%s.json' % (self.output.absoluteFilePath(), self.rootDir) info = { 'name': self.rootDir, - 'format': self.format.lower(), + 'format': self.fileFormat.lower(), 'minZoom': self.minZoom, 'maxZoom': self.maxZoom, 'bounds': str(self.extent.xMinimum()) + ',' + str(self.extent.yMinimum()) + ',' + str(self.extent.xMaximum()) + ','+ str(self.extent.yMaximum()) @@ -193,29 +206,54 @@ def writeJsonFile(self): f.write( json.dumps(info) ) def writeOverviewFile(self): - self.settings.setExtent(self.projector.transform(self.extent)) - - image = QImage(self.settings.outputSize(), QImage.Format_ARGB32) +# image = QImage(self.settings.outputSize(), QImage.Format_ARGB32) + image = QImage(QSize(self.width, self.height), QImage.Format_ARGB32) image.fill(Qt.transparent) dpm = self.settings.outputDpi() / 25.4 * 1000 image.setDotsPerMeterX(dpm) image.setDotsPerMeterY(dpm) - # job = QgsMapRendererSequentialJob(self.settings) - # job.start() - # job.waitForFinished() - # image = job.renderedImage() + self.settings.setBackgroundColor(self.color) + self.settings.setOutputDpi(image.logicalDpiX()) + self.settings.setOutputImageFormat(QImage.Format_ARGB32_Premultiplied) + self.settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + self.settings.setOutputSize(image.size()) + self.settings.setLayers(self.layers) + if self.antialias: + self.settings.setFlag(QgsMapSettings.Antialiasing, True) + else: + self.settings.setFlag(QgsMapSettings.DrawLabeling, True) + + self.settings.setExtent(self.projector.transform(self.extent)) painter = QPainter(image) job = QgsMapRendererCustomPainterJob(self.settings, painter) job.renderSynchronously() + # This increases plugin stability with very little impact on performance + QCoreApplication.processEvents() + # QCoreApplication.sendPostedEvents() painter.end() - filePath = '%s.%s' % (self.output.absoluteFilePath(), self.format.lower()) + filePath = '%s.%s' % (self.output.absoluteFilePath(), self.fileFormat.lower()) if self.mode == 'DIR': - filePath = '%s/%s.%s' % (self.output.absoluteFilePath(), self.rootDir, self.format.lower()) - image.save(filePath, self.format, self.quality) + filePath = '%s/%s.%s' % (self.output.absoluteFilePath(), self.rootDir, self.fileFormat.lower()) + image.save(filePath, self.fileFormat, self.quality) + + h = (self.height*self.macroTileSize) + (self.height*2) + w = self.width + (self.width*2) + image = QImage(w, h, QImage.Format_ARGB32_Premultiplied) + self.settings.setBackgroundColor(self.color) + self.settings.setOutputDpi(image.logicalDpiX()) + self.settings.setOutputImageFormat(QImage.Format_ARGB32_Premultiplied) + self.settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + self.settings.setOutputSize(image.size()) + self.settings.setLayers(self.layers) + if self.antialias: + self.settings.setFlag(QgsMapSettings.Antialiasing, True) + else: + self.settings.setFlag(QgsMapSettings.DrawLabeling, True) + def writeMapurlFile(self): filePath = '%s/%s.mapurl' % (self.output.absoluteFilePath(), self.rootDir) @@ -230,13 +268,13 @@ def writeMapurlFile(self): def writeLeafletViewer(self): templateFile = QFile(':/resources/viewer.html') if templateFile.open(QIODevice.ReadOnly | QIODevice.Text): - viewer = MyTemplate(unicode(templateFile.readAll())) + viewer = MyTemplate(str(templateFile.readAll(), 'utf-8')) tilesDir = '%s/%s' % (self.output.absoluteFilePath(), self.rootDir) useTMS = 'true' if self.tmsConvention else 'false' substitutions = { 'tilesdir': tilesDir, - 'tilesext': self.format.lower(), + 'tilesext': self.fileFormat.lower(), 'tilesetname': self.rootDir, 'tms': useTMS, 'centerx': self.extent.center().x(), @@ -250,56 +288,152 @@ def writeLeafletViewer(self): fOut.write(viewer.substitute(substitutions)) templateFile.close() - def countTiles(self, tile): - if self.interrupted or not self.extent.intersects(tile.toRectangle()): - return - if self.minZoom <= tile.z and tile.z <= self.maxZoom: - if not self.renderOutsideTiles: - for layer in self.layers: - if layer.extent().intersects(tile.toRectangle()): - self.tiles.append(tile) - break - else: - self.tiles.append(tile) - if tile.z < self.maxZoom: - for x in xrange(2 * tile.x, 2 * tile.x + 2, 1): - for y in xrange(2 * tile.y, 2 * tile.y + 2, 1): - self.mutex.lock() - s = self.stopMe - self.mutex.unlock() - if s == 1: - self.interrupted = True - return - subTile = Tile(x, y, tile.z + 1, tile.tms) - self.countTiles(subTile) - - def render(self, tile): - # scale = self.scaleCalc.calculate( - # self.projector.transform(tile.toRectangle()), self.width) - - self.settings.setExtent(self.projector.transform(tile.toRectangle())) - - image = QImage(self.settings.outputSize(), QImage.Format_ARGB32) - image.fill(Qt.transparent) - - dpm = self.settings.outputDpi() / 25.4 * 1000 - image.setDotsPerMeterX(dpm) - image.setDotsPerMeterY(dpm) - - # job = QgsMapRendererSequentialJob(self.settings) - # job.start() - # job.waitForFinished() - # image = job.renderedImage() - - painter = QPainter(image) - job = QgsMapRendererCustomPainterJob(self.settings, painter) - job.renderSynchronously() - painter.end() - self.writer.writeTile(tile, image, self.format, self.quality) - + def calculateTileSets(self): + totalTiles = 0 + self.tileLevelInfoList.clear() + + lat_min = self.extent.yMinimum() + lon_min = self.extent.xMinimum() + lat_max = self.extent.yMaximum() + lon_max = self.extent.xMaximum() + + for zoom in range(self.minZoom, self.maxZoom+1): + tileMin = tileFromLatLon(lat_min, lon_min, zoom) + tileMax = tileFromLatLon(lat_max, lon_max, zoom) + + self.tileLevelInfoList.append(TileLevelInfo(zoom, tileMin.x, tileMin.y, tileMax.x, tileMax.y)) + + ncols = (tileMax.x - tileMin.x) + 1 + nrows = abs(tileMax.y - tileMin.y) + 1 + levelTiles = ncols * nrows + totalTiles += levelTiles + + return totalTiles + + def renderMacroTiles(self): + try: + # trace("Start: %s" % datetime.datetime.now()) + if self.skipBlankTiles: + # Prepare a blank image to compare + # Initialize a temporal image + tmpImage = QImage(self.settings.outputSize(), QImage.Format_ARGB32) + tmpImage.fill(Qt.transparent) + # set parameters coomon to tile images + dpm = self.settings.outputDpi() / 25.4 * 1000 + tmpImage.setDotsPerMeterX(dpm) + tmpImage.setDotsPerMeterY(dpm) + # Draw image background whit the canvas color + p = QPainter(tmpImage) + p.fillRect(QRect(0, 0, self.width, self.height), QBrush(self.color)) + # return blank image + blank_image = tmpImage.copy(0, 0, self.width, self.height) + + # zoom level loop + for tli in self.tileLevelInfoList: + # establish parameters common to all zoom levels + # tms = False + z = tli.zoomLevel + dpm = self.settings.outputDpi() / 25.4 * 1000 + + # column loop + x = tli.firstCol + + while x <= tli.lastCol: + #row loop + y = min(tli.firstRow, tli.lastRow) + ymax = max(tli.firstRow, tli.lastRow) + + while y <= ymax: + # Calculate drawing window + xini = x - 1 + yini = y - 1 + xfin = x + 1 + 1 + yfin = y + self.macroTileSize + 1 + + # iniPoint = Tile(xini, yini, z, tms).toPoint() + # endPoint = Tile(xfin, yfin, z, tms).toPoint() + iniPoint = Tile(xini, yini, z).toPoint() + endPoint = Tile(xfin, yfin, z).toPoint() + + # Establish drawing window + self.settings.setExtent(self.projector.transform(QgsRectangle(iniPoint, endPoint))) + + # Create and initialize image + image = QImage(self.settings.outputSize(), QImage.Format_ARGB32) + image.fill(Qt.transparent) + image.setDotsPerMeterX(dpm) + image.setDotsPerMeterY(dpm) + + # Paint map + painter = QPainter(image) + job = QgsMapRendererCustomPainterJob(self.settings, painter) + job.renderSynchronously() + # This increases plugin stability with very little impact on performance + QCoreApplication.processEvents() + # QCoreApplication.sendPostedEvents() + painter.end() + + # MacroTile loop + i = 0 + while i < self.macroTileSize: + # Test for interrupt in MacroTile loop + self.mutex.lock() + s = self.stopMe + self.mutex.unlock() + if s == 1: + self.interrupted = True + return + + if (y + i > ymax): + break + else: + tmpImage = image.copy(self.width, self.height + (self.height*i), self.width, self.height) + + if self.skipBlankTiles: + is_blank = (tmpImage == blank_image) + else: + is_blank = False + + if is_blank: + self.blank_count += 1 + else: + tile_y = y+i + if self.tmsConvention: + tile_y = (1 << z) - tile_y - 1 + self.writer.writeTile(Tile(x, tile_y, z), tmpImage, self.fileFormat, self.quality) + self.tile_count += 1 + + self.updateProgress.emit(self.tile_count, self.blank_count) + del tmpImage + + i += 1 + + # end of MacroTile loop + + y += i + + # end of row loop + + x += 1 + # end of column loop + + #end of zoom level loop + except: + trace("At: %s" % datetime.datetime.now()) + trace("Unexpected error: %s" % sys.exc_info()[0]) + raise + return + + +def trace(msg): + traceFile = "%s/qtiles_trace.txt" % os.path.dirname(os.path.realpath(__file__)) + with open(traceFile, 'a') as output: + output.write("%s\n" % msg) + output.close() + class MyTemplate(Template): - delimiter = '@' + delimiter = '@@' def __init__(self, templateString): Template.__init__(self, templateString) diff --git a/ui/qtilesdialogbase.ui b/ui/qtilesdialogbase.ui index 6ebc6dc..5fde157 100644 --- a/ui/qtilesdialogbase.ui +++ b/ui/qtilesdialogbase.ui @@ -6,68 +6,258 @@ 0 0 - 400 - 480 + 480 + 703 - + 0 0 - 400 - 480 + 480 + 680 QTiles - - - 9 + + + + + + true - - 9 + + + 9 + 314 + 462 + 341 + - - 9 + + + 0 + 0 + - - 9 + + + 0 + 325 + - - 0 + + + 0 + 330 + - - - - - 0 - 0 - - - - QFrame::NoFrame - - - Qt::ScrollBarAlwaysOff + + Parameters + + + false + + + false + + + + + 10 + 220 + 371 + 17 + + + + + 0 + 0 + + + + Use TMS tiles convention (Slippy Map / XYZTiles by default) + + + + + + 220 + 280 + 221 + 17 + + + + Write .mapurl file + + + + + + 10 + 320 + 441 + 17 + + + + MessageBox on process end or abort + + + true + + + + + + 10 + 260 + 201 + 17 + + + + + 0 + 0 + + + + Use MBTiles compression + + + + + + 220 + 260 + 221 + 17 + + + + Write overview image file + + + + + + 220 + 240 + 221 + 17 + + + + Write .json metadata + + + + + + 220 + 300 + 221 + 17 + + + + Write Leaflet-based viewer + + + + + true + + + + 10 + 200 + 421 + 17 + + + + + 0 + 0 + + + + Make lines appear less jagged at the expense of some drawing performance + + + true + + + + + + 20 + 20 + 421 + 166 + + + + + 8 - - true + + 4 - - - - 0 - 0 - 367 - 429 - - - + + + + + 0 + 0 + + + + + 60 + 0 + + + + + PNG + + + + + JPG + + + + + + + + + 0 + 0 + + + + Background opacity + + + + + + + 0 + 0 @@ -75,933 +265,937 @@ 0 - 6 + 0 0 - - - 0 + + + margin-left:2 + + + - - - - - 0 - 0 - - - - - 75 - true - - - - margin-left:24 - - - Tileset name - - - - - - - + - + - + 0 0 - - Output + + Lock 1:1 ratio - - - 0 - - - 6 - - - 0 - - - 9 - - - - - 3 - - - 0 - - - - - - - - - - - - - - - PointingHandCursor - - - <a href="infoOutpuZip"><img src=":/icons/info.png"/></a> - - - false - - - - - - - - 0 - 0 - - - - Directory - - - - - - - true - - - - 0 - 0 - - - - PointingHandCursor - - - <a href="infoOutpuZip"><img src=":/icons/info.png"/></a> - - - Qt::RichText - - - false - - - - - - - - 0 - 0 - - - - NGM - - - - :/icons/ngm_index_24x24.png:/icons/ngm_index_24x24.png - - - - - - - - - - 0 - 0 - - - - - - - - - - - 0 - 0 - - - - - - - File - - - - - - - PointingHandCursor - - - <a href="infoOutpuZip"><img src=":/icons/info.png"/></a> - - - false - - - - - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - ... - - - - - - - margin-left:2 - - - - - - Qt::AlignCenter - - - - - - - margin-left:2 - - - - - - Qt::AlignCenter - - - - - - - - - - 0 - 0 - - - - false + + + margin-left:2 - - Extent + + - - - 3 - - - 0 - - - 6 - - - 0 - - - 9 - - - - - - 0 - 0 - - - - Canvas extent - - - - - - - - 0 - 0 - - - - Full extent - - - - - - - - - - 0 - 0 - - - - Layer extent - - - - - - - - 0 - 0 - - - - - - - + + + + + + + 0 + 0 + + + + Quality + + + + + + + + 0 + 0 + + + + + 60 + 0 + + + + 255 + + + 255 + + + + + + + + 0 + 0 + + + + + 60 + 0 + + + + 100 + + + + + + + + 0 + 0 + + + + (0-100) + + + + + + + + 0 + 0 + + + + Format + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 5 + + + QLayout::SetMinimumSize + + + 5 + + + 5 + - - - - 0 - 0 - + + + + 60 + 20 + - - Zoom + + 128 + + + 2048 + + + 256 - - - 0 - - - 6 - - - 0 - - - 9 - - - - - 24 - - - 5 - - - 5 - - - 5 - - - 3 - - - - - - 0 - 0 - - - - 40 - - - - - - - - 0 - 0 - - - - Maximum zoom - - - - - - - - 0 - 0 - - - - Minimum zoom - - - - - - - - 0 - 0 - - - - 0 - - - 40 - - - 18 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - 0 - 0 - + + + true - - - 75 - true - + + + 60 + 20 + - - QgsCollapsibleGroupBoxBasic::title, QgsCollapsibleGroupBox::title { subcontrol-origin: margin; subcontrol-position: top left; margin-left: 20px; top: 1px;}, + + 128 - - Parameters + + 2048 - - true + + 256 - - true + + + + + + + + 4 + + + QLayout::SetMinimumSize + + + 0 + + + + + + 0 + 0 + - - true + + Tile width - - - 3 - - - 0 - - - 6 - - - 0 - - - 9 - - - - - 24 - - - 6 - - - 3 - - - - - - 0 - 0 - - - - Quality - - - - - - - - 0 - 0 - - - - - 60 - 0 - - - - 255 - - - 255 - - - - - - - - 0 - 0 - - - - - 60 - 0 - - - - 100 - - - - - - - - 0 - 0 - - - - Format - - - - - - - 0 - - - 0 - - - - - margin-left:2 - - - - - - - - - - - 0 - 0 - - - - Lock 1:1 ratio - - - - - - - margin-left:2 - - - - - - - - - - - - - 0 - 0 - - - - Background transparency - - - - - - - - 0 - 0 - - - - - 60 - 0 - - - - - PNG - - - - - JPG - - - - - - - - 3 - - - - - - 60 - 0 - - - - 128 - - - 2048 - - - 256 - - - - - - - true - - - - 60 - 0 - - - - 128 - - - 2048 - - - 256 - - - - - - - - - 8 - - - - - - 0 - 0 - - - - Tile width - - - - - - - true - - - - 0 - 0 - - - - Tile height - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 0 - 0 - - - - (0-100) - - - - - - - - - - 0 - 0 - - - - Make lines appear less jagged at the expence of some drawing performance - - - - - - - - 0 - 0 - - - - Use TMS tiles convention (Slippy Map by default) - - - - - - - true - - - - 0 - 0 - - - - Render tiles outside of layers extents (within combined extent) - - - true - - - - - - - - 0 - 0 - - - - Use MBTiles compression - - - - - - - Write .json metadata - - - - - - - Write overview image file - - - - - - - Write .mapurl file - - - - - - - Write Leaflet-based viewer - - - - - - - Qt::Vertical + + + true - - - 20 - 5 - + + + 0 + 0 + - + + Tile height + + - - - - - - - 0 - - - 0 - - - 0 - - - 6 - - - - - 0 - - - true - - - false + + + + + (0: Transparent +255: Opaque) - - - - - 0 - 0 - + + + + Render sets of up to - - Qt::Horizontal + + + + + + 1 - - QDialogButtonBox::Close + + 20 + + + + + + tiles at once + + + + + + + PointingHandCursor + + + <a href="infoOutpuZip"><img src=":/icons/info.png"/></a> + + + false + + + + + - - - horizontalLayoutWidget_2 - scrollArea + + + + + 10 + 240 + 201 + 17 + + + + Skip blank tiles + + + true + + + + + + + 10 + 10 + 461 + 22 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 75 + true + + + + margin-left:24 + + + Tileset name + + + + + + + + + + + + 10 + 660 + 461 + 31 + + + + + 0 + + + 0 + + + 0 + + + 6 + + + + + 0 + + + true + + + false + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + QDialogButtonBox::Close + + + + + + + + + 10 + 236 + 461 + 68 + + + + + 0 + 0 + + + + + 50 + false + + + + Zoom + + + false + + + + 0 + + + 4 + + + 0 + + + 4 + + + + + 24 + + + 0 + + + 5 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 50 + false + + + + 40 + + + + + + + + 0 + 0 + + + + + 50 + false + + + + Maximum zoom + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 50 + false + + + + Minimum zoom + + + + + + + + 0 + 0 + + + + + 50 + false + + + + 0 + + + 40 + + + 18 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + 10 + 137 + 461 + 93 + + + + + 0 + 0 + + + + + 50 + false + + + + false + + + Extent + + + false + + + + 3 + + + 0 + + + 4 + + + 0 + + + 4 + + + + + 6 + + + + + + 0 + 0 + + + + + 50 + false + + + + Canvas extent + + + + + + + + 0 + 0 + + + + + 50 + false + + + + Full extent + + + + + + + + + + 0 + 0 + + + + + 50 + false + + + + Layer extent + + + + + + + + 0 + 0 + + + + + + + + + + + + + + 10 + 38 + 461 + 93 + + + + + 0 + 0 + + + + + 50 + false + + + + Output + + + false + + + + 0 + + + 4 + + + 0 + + + 4 + + + + + 6 + + + 3 + + + + + + + + + + + + + + + PointingHandCursor + + + <a href="infoOutpuZip"><img src=":/icons/info.png"/></a> + + + false + + + + + + + + 0 + 0 + + + + + 50 + false + + + + Directory + + + + + + + true + + + + 0 + 0 + + + + PointingHandCursor + + + <a href="infoOutpuZip"><img src=":/icons/info.png"/></a> + + + Qt::RichText + + + false + + + + + + + + 0 + 0 + + + + + 50 + false + + + + NGM + + + + :/icons/ngm_index_24x24.png:/icons/ngm_index_24x24.png + + + + + + + + + + 0 + 0 + + + + + + + + + + + 0 + 0 + + + + + 50 + false + + + + + + + File + + + + + + + PointingHandCursor + + + <a href="infoOutpuZip"><img src=":/icons/info.png"/></a> + + + false + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + ... + + + + + + + margin-left:2 + + + + + + Qt::AlignCenter + + + + + + + margin-left:2 + + + + + + Qt::AlignCenter + + + + + + + - - - QgsCollapsibleGroupBox - QGroupBox -
qgscollapsiblegroupbox.h
- 1 -
-
diff --git a/ui/ui_aboutdialogbase.py b/ui/ui_aboutdialogbase.py new file mode 100644 index 0000000..469b73f --- /dev/null +++ b/ui/ui_aboutdialogbase.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'ui/aboutdialogbase.ui' +# +# Created by: PyQt5 UI code generator 5.10.1 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Dialog(object): + def setupUi(self, Dialog): + Dialog.setObjectName("Dialog") + Dialog.resize(400, 240) + self.gridLayout = QtWidgets.QGridLayout(Dialog) + self.gridLayout.setObjectName("gridLayout") + self.lblLogo = QtWidgets.QLabel(Dialog) + self.lblLogo.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop) + self.lblLogo.setObjectName("lblLogo") + self.gridLayout.addWidget(self.lblLogo, 0, 0, 1, 1) + self.label = QtWidgets.QLabel(Dialog) + self.label.setAlignment(QtCore.Qt.AlignCenter) + self.label.setObjectName("label") + self.gridLayout.addWidget(self.label, 0, 1, 1, 1) + self.lblVersion = QtWidgets.QLabel(Dialog) + self.lblVersion.setAlignment(QtCore.Qt.AlignCenter) + self.lblVersion.setObjectName("lblVersion") + self.gridLayout.addWidget(self.lblVersion, 1, 0, 1, 2) + self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Close|QtWidgets.QDialogButtonBox.Help) + self.buttonBox.setObjectName("buttonBox") + self.gridLayout.addWidget(self.buttonBox, 3, 0, 1, 2) + self.textBrowser = QtWidgets.QTextBrowser(Dialog) + self.textBrowser.setReadOnly(True) + self.textBrowser.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse) + self.textBrowser.setObjectName("textBrowser") + self.gridLayout.addWidget(self.textBrowser, 2, 0, 1, 2) + self.gridLayout.setColumnStretch(1, 5) + + self.retranslateUi(Dialog) + self.buttonBox.accepted.connect(Dialog.accept) + self.buttonBox.rejected.connect(Dialog.reject) + QtCore.QMetaObject.connectSlotsByName(Dialog) + + def retranslateUi(self, Dialog): + _translate = QtCore.QCoreApplication.translate + Dialog.setWindowTitle(_translate("Dialog", "About QTiles")) + self.lblLogo.setText(_translate("Dialog", "TextLabel")) + self.label.setText(_translate("Dialog", "\n" +"\n" +"

QTiles

")) + self.lblVersion.setText(_translate("Dialog", "TextLabel")) + self.textBrowser.setHtml(_translate("Dialog", "\n" +"\n" +"


")) + diff --git a/ui/ui_qtilesdialogbase.py b/ui/ui_qtilesdialogbase.py new file mode 100644 index 0000000..d24d472 --- /dev/null +++ b/ui/ui_qtilesdialogbase.py @@ -0,0 +1,610 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'qtilesdialogbase.ui' +# +# Created by: PyQt5 UI code generator 5.12.1 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Dialog(object): + def setupUi(self, Dialog): + Dialog.setObjectName("Dialog") + Dialog.resize(480, 703) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(Dialog.sizePolicy().hasHeightForWidth()) + Dialog.setSizePolicy(sizePolicy) + Dialog.setMinimumSize(QtCore.QSize(480, 680)) + Dialog.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates)) + self.groupBox_4 = QtWidgets.QGroupBox(Dialog) + self.groupBox_4.setEnabled(True) + self.groupBox_4.setGeometry(QtCore.QRect(9, 314, 462, 341)) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.groupBox_4.sizePolicy().hasHeightForWidth()) + self.groupBox_4.setSizePolicy(sizePolicy) + self.groupBox_4.setMinimumSize(QtCore.QSize(0, 325)) + self.groupBox_4.setBaseSize(QtCore.QSize(0, 330)) + self.groupBox_4.setFlat(False) + self.groupBox_4.setCheckable(False) + self.groupBox_4.setObjectName("groupBox_4") + self.chkTMSConvention = QtWidgets.QCheckBox(self.groupBox_4) + self.chkTMSConvention.setGeometry(QtCore.QRect(10, 220, 371, 17)) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.chkTMSConvention.sizePolicy().hasHeightForWidth()) + self.chkTMSConvention.setSizePolicy(sizePolicy) + self.chkTMSConvention.setObjectName("chkTMSConvention") + self.chkWriteMapurl = QtWidgets.QCheckBox(self.groupBox_4) + self.chkWriteMapurl.setGeometry(QtCore.QRect(220, 280, 221, 17)) + self.chkWriteMapurl.setObjectName("chkWriteMapurl") + self.chkMsgDialogs = QtWidgets.QCheckBox(self.groupBox_4) + self.chkMsgDialogs.setGeometry(QtCore.QRect(10, 320, 441, 17)) + self.chkMsgDialogs.setChecked(True) + self.chkMsgDialogs.setObjectName("chkMsgDialogs") + self.chkMBTilesCompression = QtWidgets.QCheckBox(self.groupBox_4) + self.chkMBTilesCompression.setGeometry(QtCore.QRect(10, 260, 201, 17)) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.chkMBTilesCompression.sizePolicy().hasHeightForWidth()) + self.chkMBTilesCompression.setSizePolicy(sizePolicy) + self.chkMBTilesCompression.setObjectName("chkMBTilesCompression") + self.chkWriteOverview = QtWidgets.QCheckBox(self.groupBox_4) + self.chkWriteOverview.setGeometry(QtCore.QRect(220, 260, 221, 17)) + self.chkWriteOverview.setObjectName("chkWriteOverview") + self.chkWriteJson = QtWidgets.QCheckBox(self.groupBox_4) + self.chkWriteJson.setGeometry(QtCore.QRect(220, 240, 221, 17)) + self.chkWriteJson.setObjectName("chkWriteJson") + self.chkWriteViewer = QtWidgets.QCheckBox(self.groupBox_4) + self.chkWriteViewer.setGeometry(QtCore.QRect(220, 300, 221, 17)) + self.chkWriteViewer.setObjectName("chkWriteViewer") + self.chkAntialiasing = QtWidgets.QCheckBox(self.groupBox_4) + self.chkAntialiasing.setEnabled(True) + self.chkAntialiasing.setGeometry(QtCore.QRect(10, 200, 421, 17)) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.chkAntialiasing.sizePolicy().hasHeightForWidth()) + self.chkAntialiasing.setSizePolicy(sizePolicy) + self.chkAntialiasing.setChecked(True) + self.chkAntialiasing.setObjectName("chkAntialiasing") + self.layoutWidget = QtWidgets.QWidget(self.groupBox_4) + self.layoutWidget.setGeometry(QtCore.QRect(20, 20, 421, 166)) + self.layoutWidget.setObjectName("layoutWidget") + self.gridLayout_5 = QtWidgets.QGridLayout(self.layoutWidget) + self.gridLayout_5.setContentsMargins(0, 8, 0, 0) + self.gridLayout_5.setVerticalSpacing(4) + self.gridLayout_5.setObjectName("gridLayout_5") + self.cmbFormat = QtWidgets.QComboBox(self.layoutWidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.cmbFormat.sizePolicy().hasHeightForWidth()) + self.cmbFormat.setSizePolicy(sizePolicy) + self.cmbFormat.setMinimumSize(QtCore.QSize(60, 0)) + self.cmbFormat.setObjectName("cmbFormat") + self.cmbFormat.addItem("") + self.cmbFormat.addItem("") + self.gridLayout_5.addWidget(self.cmbFormat, 1, 1, 1, 1) + self.label_14 = QtWidgets.QLabel(self.layoutWidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_14.sizePolicy().hasHeightForWidth()) + self.label_14.setSizePolicy(sizePolicy) + self.label_14.setObjectName("label_14") + self.gridLayout_5.addWidget(self.label_14, 2, 0, 1, 1) + self.verticalLayout_10 = QtWidgets.QVBoxLayout() + self.verticalLayout_10.setContentsMargins(0, 0, 0, 0) + self.verticalLayout_10.setSpacing(0) + self.verticalLayout_10.setObjectName("verticalLayout_10") + self.label_15 = QtWidgets.QLabel(self.layoutWidget) + self.label_15.setStyleSheet("margin-left:2") + self.label_15.setObjectName("label_15") + self.verticalLayout_10.addWidget(self.label_15) + self.chkLockRatio = QtWidgets.QCheckBox(self.layoutWidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.chkLockRatio.sizePolicy().hasHeightForWidth()) + self.chkLockRatio.setSizePolicy(sizePolicy) + self.chkLockRatio.setObjectName("chkLockRatio") + self.verticalLayout_10.addWidget(self.chkLockRatio) + self.label_16 = QtWidgets.QLabel(self.layoutWidget) + self.label_16.setStyleSheet("margin-left:2") + self.label_16.setObjectName("label_16") + self.verticalLayout_10.addWidget(self.label_16) + self.gridLayout_5.addLayout(self.verticalLayout_10, 0, 2, 1, 1) + self.label_17 = QtWidgets.QLabel(self.layoutWidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_17.sizePolicy().hasHeightForWidth()) + self.label_17.setSizePolicy(sizePolicy) + self.label_17.setObjectName("label_17") + self.gridLayout_5.addWidget(self.label_17, 3, 0, 1, 1) + self.spnTransparency = QtWidgets.QSpinBox(self.layoutWidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.spnTransparency.sizePolicy().hasHeightForWidth()) + self.spnTransparency.setSizePolicy(sizePolicy) + self.spnTransparency.setMinimumSize(QtCore.QSize(60, 0)) + self.spnTransparency.setMaximum(255) + self.spnTransparency.setProperty("value", 255) + self.spnTransparency.setObjectName("spnTransparency") + self.gridLayout_5.addWidget(self.spnTransparency, 2, 1, 1, 1) + self.spnQuality = QtWidgets.QSpinBox(self.layoutWidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.spnQuality.sizePolicy().hasHeightForWidth()) + self.spnQuality.setSizePolicy(sizePolicy) + self.spnQuality.setMinimumSize(QtCore.QSize(60, 0)) + self.spnQuality.setMaximum(100) + self.spnQuality.setObjectName("spnQuality") + self.gridLayout_5.addWidget(self.spnQuality, 3, 1, 1, 1) + self.label_18 = QtWidgets.QLabel(self.layoutWidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_18.sizePolicy().hasHeightForWidth()) + self.label_18.setSizePolicy(sizePolicy) + self.label_18.setObjectName("label_18") + self.gridLayout_5.addWidget(self.label_18, 3, 2, 1, 1) + self.label_19 = QtWidgets.QLabel(self.layoutWidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_19.sizePolicy().hasHeightForWidth()) + self.label_19.setSizePolicy(sizePolicy) + self.label_19.setObjectName("label_19") + self.gridLayout_5.addWidget(self.label_19, 1, 0, 1, 1) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.gridLayout_5.addItem(spacerItem, 0, 3, 1, 1) + self.verticalLayout_11 = QtWidgets.QVBoxLayout() + self.verticalLayout_11.setSizeConstraint(QtWidgets.QLayout.SetMinimumSize) + self.verticalLayout_11.setContentsMargins(-1, 5, -1, 5) + self.verticalLayout_11.setSpacing(5) + self.verticalLayout_11.setObjectName("verticalLayout_11") + self.spnTileWidth = QtWidgets.QSpinBox(self.layoutWidget) + self.spnTileWidth.setMinimumSize(QtCore.QSize(60, 20)) + self.spnTileWidth.setMinimum(128) + self.spnTileWidth.setMaximum(2048) + self.spnTileWidth.setProperty("value", 256) + self.spnTileWidth.setObjectName("spnTileWidth") + self.verticalLayout_11.addWidget(self.spnTileWidth) + self.spnTileHeight = QtWidgets.QSpinBox(self.layoutWidget) + self.spnTileHeight.setEnabled(True) + self.spnTileHeight.setMinimumSize(QtCore.QSize(60, 20)) + self.spnTileHeight.setMinimum(128) + self.spnTileHeight.setMaximum(2048) + self.spnTileHeight.setProperty("value", 256) + self.spnTileHeight.setObjectName("spnTileHeight") + self.verticalLayout_11.addWidget(self.spnTileHeight) + self.gridLayout_5.addLayout(self.verticalLayout_11, 0, 1, 1, 1) + self.verticalLayout_12 = QtWidgets.QVBoxLayout() + self.verticalLayout_12.setSizeConstraint(QtWidgets.QLayout.SetMinimumSize) + self.verticalLayout_12.setContentsMargins(-1, 0, -1, -1) + self.verticalLayout_12.setSpacing(4) + self.verticalLayout_12.setObjectName("verticalLayout_12") + self.label_20 = QtWidgets.QLabel(self.layoutWidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_20.sizePolicy().hasHeightForWidth()) + self.label_20.setSizePolicy(sizePolicy) + self.label_20.setObjectName("label_20") + self.verticalLayout_12.addWidget(self.label_20) + self.lblHeight = QtWidgets.QLabel(self.layoutWidget) + self.lblHeight.setEnabled(True) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.lblHeight.sizePolicy().hasHeightForWidth()) + self.lblHeight.setSizePolicy(sizePolicy) + self.lblHeight.setObjectName("lblHeight") + self.verticalLayout_12.addWidget(self.lblHeight) + self.gridLayout_5.addLayout(self.verticalLayout_12, 0, 0, 1, 1) + self.label_21 = QtWidgets.QLabel(self.layoutWidget) + self.label_21.setObjectName("label_21") + self.gridLayout_5.addWidget(self.label_21, 2, 2, 1, 1) + self.label_22 = QtWidgets.QLabel(self.layoutWidget) + self.label_22.setObjectName("label_22") + self.gridLayout_5.addWidget(self.label_22, 4, 0, 1, 1) + self.spnMacroTile = QtWidgets.QSpinBox(self.layoutWidget) + self.spnMacroTile.setMinimum(1) + self.spnMacroTile.setMaximum(20) + self.spnMacroTile.setObjectName("spnMacroTile") + self.gridLayout_5.addWidget(self.spnMacroTile, 4, 1, 1, 1) + self.horizontalLayout_3 = QtWidgets.QHBoxLayout() + self.horizontalLayout_3.setObjectName("horizontalLayout_3") + self.label_23 = QtWidgets.QLabel(self.layoutWidget) + self.label_23.setObjectName("label_23") + self.horizontalLayout_3.addWidget(self.label_23) + self.lInfoIconMacroTile = QtWidgets.QLabel(self.layoutWidget) + self.lInfoIconMacroTile.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor)) + self.lInfoIconMacroTile.setOpenExternalLinks(False) + self.lInfoIconMacroTile.setObjectName("lInfoIconMacroTile") + self.horizontalLayout_3.addWidget(self.lInfoIconMacroTile) + self.gridLayout_5.addLayout(self.horizontalLayout_3, 4, 2, 1, 1) + self.chkSkipBlankTiles = QtWidgets.QCheckBox(self.groupBox_4) + self.chkSkipBlankTiles.setGeometry(QtCore.QRect(10, 240, 201, 17)) + self.chkSkipBlankTiles.setChecked(True) + self.chkSkipBlankTiles.setObjectName("chkSkipBlankTiles") + self.layoutWidget1 = QtWidgets.QWidget(Dialog) + self.layoutWidget1.setGeometry(QtCore.QRect(10, 10, 461, 22)) + self.layoutWidget1.setObjectName("layoutWidget1") + self.horizontalLayout = QtWidgets.QHBoxLayout(self.layoutWidget1) + self.horizontalLayout.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout.setObjectName("horizontalLayout") + self.label_4 = QtWidgets.QLabel(self.layoutWidget1) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_4.sizePolicy().hasHeightForWidth()) + self.label_4.setSizePolicy(sizePolicy) + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + self.label_4.setFont(font) + self.label_4.setStyleSheet("margin-left:24") + self.label_4.setObjectName("label_4") + self.horizontalLayout.addWidget(self.label_4) + self.leRootDir = QtWidgets.QLineEdit(self.layoutWidget1) + self.leRootDir.setObjectName("leRootDir") + self.horizontalLayout.addWidget(self.leRootDir) + self.layoutWidget2 = QtWidgets.QWidget(Dialog) + self.layoutWidget2.setGeometry(QtCore.QRect(10, 660, 461, 31)) + self.layoutWidget2.setObjectName("layoutWidget2") + self.horizontalLayout_5 = QtWidgets.QHBoxLayout(self.layoutWidget2) + self.horizontalLayout_5.setContentsMargins(0, 0, 0, 6) + self.horizontalLayout_5.setObjectName("horizontalLayout_5") + self.progressBar = QtWidgets.QProgressBar(self.layoutWidget2) + self.progressBar.setProperty("value", 0) + self.progressBar.setTextVisible(True) + self.progressBar.setInvertedAppearance(False) + self.progressBar.setObjectName("progressBar") + self.horizontalLayout_5.addWidget(self.progressBar) + self.buttonBox = QtWidgets.QDialogButtonBox(self.layoutWidget2) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.buttonBox.sizePolicy().hasHeightForWidth()) + self.buttonBox.setSizePolicy(sizePolicy) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Close) + self.buttonBox.setObjectName("buttonBox") + self.horizontalLayout_5.addWidget(self.buttonBox) + self.groupBox_3 = QtWidgets.QGroupBox(Dialog) + self.groupBox_3.setGeometry(QtCore.QRect(10, 236, 461, 68)) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.groupBox_3.sizePolicy().hasHeightForWidth()) + self.groupBox_3.setSizePolicy(sizePolicy) + font = QtGui.QFont() + font.setBold(False) + font.setWeight(50) + self.groupBox_3.setFont(font) + self.groupBox_3.setFlat(False) + self.groupBox_3.setObjectName("groupBox_3") + self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.groupBox_3) + self.verticalLayout_6.setContentsMargins(0, 4, 0, 4) + self.verticalLayout_6.setObjectName("verticalLayout_6") + self.gridLayout_3 = QtWidgets.QGridLayout() + self.gridLayout_3.setContentsMargins(24, 0, 5, 0) + self.gridLayout_3.setVerticalSpacing(0) + self.gridLayout_3.setObjectName("gridLayout_3") + self.spnZoomMin = QtWidgets.QSpinBox(self.groupBox_3) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.spnZoomMin.sizePolicy().hasHeightForWidth()) + self.spnZoomMin.setSizePolicy(sizePolicy) + font = QtGui.QFont() + font.setBold(False) + font.setWeight(50) + self.spnZoomMin.setFont(font) + self.spnZoomMin.setMaximum(40) + self.spnZoomMin.setObjectName("spnZoomMin") + self.gridLayout_3.addWidget(self.spnZoomMin, 0, 1, 1, 1) + self.label_2 = QtWidgets.QLabel(self.groupBox_3) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_2.sizePolicy().hasHeightForWidth()) + self.label_2.setSizePolicy(sizePolicy) + font = QtGui.QFont() + font.setBold(False) + font.setWeight(50) + self.label_2.setFont(font) + self.label_2.setObjectName("label_2") + self.gridLayout_3.addWidget(self.label_2, 1, 0, 1, 1) + self.label = QtWidgets.QLabel(self.groupBox_3) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth()) + self.label.setSizePolicy(sizePolicy) + self.label.setBaseSize(QtCore.QSize(0, 0)) + font = QtGui.QFont() + font.setBold(False) + font.setWeight(50) + self.label.setFont(font) + self.label.setObjectName("label") + self.gridLayout_3.addWidget(self.label, 0, 0, 1, 1) + self.spnZoomMax = QtWidgets.QSpinBox(self.groupBox_3) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.spnZoomMax.sizePolicy().hasHeightForWidth()) + self.spnZoomMax.setSizePolicy(sizePolicy) + font = QtGui.QFont() + font.setBold(False) + font.setWeight(50) + self.spnZoomMax.setFont(font) + self.spnZoomMax.setMinimum(0) + self.spnZoomMax.setMaximum(40) + self.spnZoomMax.setProperty("value", 18) + self.spnZoomMax.setObjectName("spnZoomMax") + self.gridLayout_3.addWidget(self.spnZoomMax, 1, 1, 1, 1) + spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.gridLayout_3.addItem(spacerItem1, 0, 2, 1, 1) + self.verticalLayout_6.addLayout(self.gridLayout_3) + self.groupBox_2 = QtWidgets.QGroupBox(Dialog) + self.groupBox_2.setGeometry(QtCore.QRect(10, 137, 461, 93)) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.groupBox_2.sizePolicy().hasHeightForWidth()) + self.groupBox_2.setSizePolicy(sizePolicy) + font = QtGui.QFont() + font.setBold(False) + font.setWeight(50) + self.groupBox_2.setFont(font) + self.groupBox_2.setAutoFillBackground(False) + self.groupBox_2.setFlat(False) + self.groupBox_2.setObjectName("groupBox_2") + self.verticalLayout_7 = QtWidgets.QVBoxLayout(self.groupBox_2) + self.verticalLayout_7.setContentsMargins(0, 4, 0, 4) + self.verticalLayout_7.setSpacing(3) + self.verticalLayout_7.setObjectName("verticalLayout_7") + self.verticalLayout_9 = QtWidgets.QVBoxLayout() + self.verticalLayout_9.setContentsMargins(6, -1, -1, -1) + self.verticalLayout_9.setObjectName("verticalLayout_9") + self.rbExtentCanvas = QtWidgets.QRadioButton(self.groupBox_2) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.rbExtentCanvas.sizePolicy().hasHeightForWidth()) + self.rbExtentCanvas.setSizePolicy(sizePolicy) + font = QtGui.QFont() + font.setBold(False) + font.setWeight(50) + self.rbExtentCanvas.setFont(font) + self.rbExtentCanvas.setObjectName("rbExtentCanvas") + self.verticalLayout_9.addWidget(self.rbExtentCanvas) + self.rbExtentFull = QtWidgets.QRadioButton(self.groupBox_2) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.rbExtentFull.sizePolicy().hasHeightForWidth()) + self.rbExtentFull.setSizePolicy(sizePolicy) + font = QtGui.QFont() + font.setBold(False) + font.setWeight(50) + self.rbExtentFull.setFont(font) + self.rbExtentFull.setObjectName("rbExtentFull") + self.verticalLayout_9.addWidget(self.rbExtentFull) + self.horizontalLayout_4 = QtWidgets.QHBoxLayout() + self.horizontalLayout_4.setObjectName("horizontalLayout_4") + self.rbExtentLayer = QtWidgets.QRadioButton(self.groupBox_2) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.rbExtentLayer.sizePolicy().hasHeightForWidth()) + self.rbExtentLayer.setSizePolicy(sizePolicy) + font = QtGui.QFont() + font.setBold(False) + font.setWeight(50) + self.rbExtentLayer.setFont(font) + self.rbExtentLayer.setObjectName("rbExtentLayer") + self.horizontalLayout_4.addWidget(self.rbExtentLayer) + self.cmbLayers = QtWidgets.QComboBox(self.groupBox_2) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.cmbLayers.sizePolicy().hasHeightForWidth()) + self.cmbLayers.setSizePolicy(sizePolicy) + self.cmbLayers.setObjectName("cmbLayers") + self.horizontalLayout_4.addWidget(self.cmbLayers) + self.verticalLayout_9.addLayout(self.horizontalLayout_4) + self.verticalLayout_7.addLayout(self.verticalLayout_9) + self.groupBox = QtWidgets.QGroupBox(Dialog) + self.groupBox.setGeometry(QtCore.QRect(10, 38, 461, 93)) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.groupBox.sizePolicy().hasHeightForWidth()) + self.groupBox.setSizePolicy(sizePolicy) + font = QtGui.QFont() + font.setBold(False) + font.setWeight(50) + self.groupBox.setFont(font) + self.groupBox.setFlat(False) + self.groupBox.setObjectName("groupBox") + self.verticalLayout_8 = QtWidgets.QVBoxLayout(self.groupBox) + self.verticalLayout_8.setContentsMargins(0, 4, 0, 4) + self.verticalLayout_8.setObjectName("verticalLayout_8") + self.gridLayout_4 = QtWidgets.QGridLayout() + self.gridLayout_4.setContentsMargins(6, -1, -1, -1) + self.gridLayout_4.setVerticalSpacing(3) + self.gridLayout_4.setObjectName("gridLayout_4") + self.leTilesFroNGM = QtWidgets.QLineEdit(self.groupBox) + self.leTilesFroNGM.setToolTip("") + self.leTilesFroNGM.setPlaceholderText("") + self.leTilesFroNGM.setObjectName("leTilesFroNGM") + self.gridLayout_4.addWidget(self.leTilesFroNGM, 2, 2, 1, 1) + self.lInfoIconOutputNGM = QtWidgets.QLabel(self.groupBox) + self.lInfoIconOutputNGM.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor)) + self.lInfoIconOutputNGM.setOpenExternalLinks(False) + self.lInfoIconOutputNGM.setObjectName("lInfoIconOutputNGM") + self.gridLayout_4.addWidget(self.lInfoIconOutputNGM, 2, 1, 1, 1) + self.rbOutputDir = QtWidgets.QRadioButton(self.groupBox) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.rbOutputDir.sizePolicy().hasHeightForWidth()) + self.rbOutputDir.setSizePolicy(sizePolicy) + font = QtGui.QFont() + font.setBold(False) + font.setWeight(50) + self.rbOutputDir.setFont(font) + self.rbOutputDir.setObjectName("rbOutputDir") + self.gridLayout_4.addWidget(self.rbOutputDir, 1, 0, 1, 1) + self.lInfoIconOutputZip = QtWidgets.QLabel(self.groupBox) + self.lInfoIconOutputZip.setEnabled(True) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.lInfoIconOutputZip.sizePolicy().hasHeightForWidth()) + self.lInfoIconOutputZip.setSizePolicy(sizePolicy) + self.lInfoIconOutputZip.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor)) + self.lInfoIconOutputZip.setText("") + self.lInfoIconOutputZip.setTextFormat(QtCore.Qt.RichText) + self.lInfoIconOutputZip.setOpenExternalLinks(False) + self.lInfoIconOutputZip.setObjectName("lInfoIconOutputZip") + self.gridLayout_4.addWidget(self.lInfoIconOutputZip, 0, 1, 1, 1) + self.rbOutputNGM = QtWidgets.QRadioButton(self.groupBox) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.rbOutputNGM.sizePolicy().hasHeightForWidth()) + self.rbOutputNGM.setSizePolicy(sizePolicy) + font = QtGui.QFont() + font.setBold(False) + font.setWeight(50) + self.rbOutputNGM.setFont(font) + icon = QtGui.QIcon() + icon.addPixmap(QtGui.QPixmap(":/icons/ngm_index_24x24.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.rbOutputNGM.setIcon(icon) + self.rbOutputNGM.setObjectName("rbOutputNGM") + self.gridLayout_4.addWidget(self.rbOutputNGM, 2, 0, 1, 1) + self.horizontalLayout_7 = QtWidgets.QHBoxLayout() + self.horizontalLayout_7.setObjectName("horizontalLayout_7") + self.leDirectoryName = QtWidgets.QLineEdit(self.groupBox) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.leDirectoryName.sizePolicy().hasHeightForWidth()) + self.leDirectoryName.setSizePolicy(sizePolicy) + self.leDirectoryName.setObjectName("leDirectoryName") + self.horizontalLayout_7.addWidget(self.leDirectoryName) + self.gridLayout_4.addLayout(self.horizontalLayout_7, 1, 2, 1, 1) + self.rbOutputZip = QtWidgets.QRadioButton(self.groupBox) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.rbOutputZip.sizePolicy().hasHeightForWidth()) + self.rbOutputZip.setSizePolicy(sizePolicy) + font = QtGui.QFont() + font.setBold(False) + font.setWeight(50) + self.rbOutputZip.setFont(font) + self.rbOutputZip.setStyleSheet("") + self.rbOutputZip.setObjectName("rbOutputZip") + self.gridLayout_4.addWidget(self.rbOutputZip, 0, 0, 1, 1) + self.lInfoIconOutputDir = QtWidgets.QLabel(self.groupBox) + self.lInfoIconOutputDir.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor)) + self.lInfoIconOutputDir.setOpenExternalLinks(False) + self.lInfoIconOutputDir.setObjectName("lInfoIconOutputDir") + self.gridLayout_4.addWidget(self.lInfoIconOutputDir, 1, 1, 1, 1) + self.leZipFileName = QtWidgets.QLineEdit(self.groupBox) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.leZipFileName.sizePolicy().hasHeightForWidth()) + self.leZipFileName.setSizePolicy(sizePolicy) + self.leZipFileName.setObjectName("leZipFileName") + self.gridLayout_4.addWidget(self.leZipFileName, 0, 2, 1, 1) + self.btnBrowse = QtWidgets.QToolButton(self.groupBox) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnBrowse.sizePolicy().hasHeightForWidth()) + self.btnBrowse.setSizePolicy(sizePolicy) + self.btnBrowse.setObjectName("btnBrowse") + self.gridLayout_4.addWidget(self.btnBrowse, 1, 3, 1, 1) + self.label_41 = QtWidgets.QLabel(self.groupBox) + self.label_41.setStyleSheet("margin-left:2") + self.label_41.setAlignment(QtCore.Qt.AlignCenter) + self.label_41.setObjectName("label_41") + self.gridLayout_4.addWidget(self.label_41, 0, 3, 1, 1) + self.label_42 = QtWidgets.QLabel(self.groupBox) + self.label_42.setStyleSheet("margin-left:2") + self.label_42.setAlignment(QtCore.Qt.AlignCenter) + self.label_42.setObjectName("label_42") + self.gridLayout_4.addWidget(self.label_42, 2, 3, 1, 1) + self.verticalLayout_8.addLayout(self.gridLayout_4) + + self.retranslateUi(Dialog) + self.buttonBox.accepted.connect(Dialog.accept) + self.buttonBox.rejected.connect(Dialog.reject) + QtCore.QMetaObject.connectSlotsByName(Dialog) + + def retranslateUi(self, Dialog): + _translate = QtCore.QCoreApplication.translate + Dialog.setWindowTitle(_translate("Dialog", "QTiles")) + self.groupBox_4.setTitle(_translate("Dialog", "Parameters")) + self.chkTMSConvention.setText(_translate("Dialog", "Use TMS tiles convention (Slippy Map / XYZTiles by default)")) + self.chkWriteMapurl.setText(_translate("Dialog", "Write .mapurl file")) + self.chkMsgDialogs.setText(_translate("Dialog", "MessageBox on process end or abort")) + self.chkMBTilesCompression.setText(_translate("Dialog", "Use MBTiles compression")) + self.chkWriteOverview.setText(_translate("Dialog", "Write overview image file")) + self.chkWriteJson.setText(_translate("Dialog", "Write .json metadata")) + self.chkWriteViewer.setText(_translate("Dialog", "Write Leaflet-based viewer")) + self.chkAntialiasing.setText(_translate("Dialog", "Make lines appear less jagged at the expense of some drawing performance")) + self.cmbFormat.setItemText(0, _translate("Dialog", "PNG")) + self.cmbFormat.setItemText(1, _translate("Dialog", "JPG")) + self.label_14.setText(_translate("Dialog", "Background opacity")) + self.label_15.setText(_translate("Dialog", "╮")) + self.chkLockRatio.setToolTip(_translate("Dialog", "Lock 1:1 ratio")) + self.label_16.setText(_translate("Dialog", "╯")) + self.label_17.setText(_translate("Dialog", "Quality")) + self.label_18.setText(_translate("Dialog", "(0-100)")) + self.label_19.setText(_translate("Dialog", "Format")) + self.label_20.setText(_translate("Dialog", "Tile width")) + self.lblHeight.setText(_translate("Dialog", "Tile height")) + self.label_21.setText(_translate("Dialog", "(0: Transparent\n" +"255: Opaque)")) + self.label_22.setText(_translate("Dialog", "Render sets of up to")) + self.label_23.setText(_translate("Dialog", "tiles at once")) + self.lInfoIconMacroTile.setText(_translate("Dialog", "")) + self.chkSkipBlankTiles.setText(_translate("Dialog", "Skip blank tiles")) + self.label_4.setText(_translate("Dialog", "Tileset name")) + self.groupBox_3.setTitle(_translate("Dialog", "Zoom")) + self.label_2.setText(_translate("Dialog", "Maximum zoom")) + self.label.setText(_translate("Dialog", "Minimum zoom")) + self.groupBox_2.setTitle(_translate("Dialog", "Extent")) + self.rbExtentCanvas.setText(_translate("Dialog", "Canvas extent")) + self.rbExtentFull.setText(_translate("Dialog", "Full extent")) + self.rbExtentLayer.setText(_translate("Dialog", "Layer extent")) + self.groupBox.setTitle(_translate("Dialog", "Output")) + self.lInfoIconOutputNGM.setText(_translate("Dialog", "")) + self.rbOutputDir.setText(_translate("Dialog", "Directory")) + self.rbOutputNGM.setText(_translate("Dialog", "NGM")) + self.rbOutputZip.setText(_translate("Dialog", "File")) + self.lInfoIconOutputDir.setText(_translate("Dialog", "")) + self.btnBrowse.setText(_translate("Dialog", "...")) + self.label_41.setText(_translate("Dialog", "╮")) + self.label_42.setText(_translate("Dialog", "╯")) + + diff --git a/ui/ui_qtilesdialogbase.py.ftf b/ui/ui_qtilesdialogbase.py.ftf new file mode 100644 index 0000000..f5174e9 --- /dev/null +++ b/ui/ui_qtilesdialogbase.py.ftf @@ -0,0 +1,543 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'ui/qtilesdialogbase.ui' +# +# Created by: PyQt5 UI code generator 5.10.1 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_Dialog(object): + def setupUi(self, Dialog): + Dialog.setObjectName("Dialog") + Dialog.resize(400, 480) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(Dialog.sizePolicy().hasHeightForWidth()) + Dialog.setSizePolicy(sizePolicy) + Dialog.setMinimumSize(QtCore.QSize(400, 480)) + self.verticalLayout = QtWidgets.QVBoxLayout(Dialog) + self.verticalLayout.setContentsMargins(9, 9, 9, 0) + self.verticalLayout.setSpacing(9) + self.verticalLayout.setObjectName("verticalLayout") + self.scrollArea = QtWidgets.QScrollArea(Dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.scrollArea.sizePolicy().hasHeightForWidth()) + self.scrollArea.setSizePolicy(sizePolicy) + self.scrollArea.setFrameShape(QtWidgets.QFrame.NoFrame) + self.scrollArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) + self.scrollArea.setWidgetResizable(True) + self.scrollArea.setObjectName("scrollArea") + self.scrollAreaWidgetContents = QtWidgets.QWidget() + self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 367, 429)) + self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents") + self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.scrollAreaWidgetContents) + self.verticalLayout_2.setContentsMargins(0, 0, 6, 0) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout.setObjectName("horizontalLayout") + self.label_4 = QtWidgets.QLabel(self.scrollAreaWidgetContents) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_4.sizePolicy().hasHeightForWidth()) + self.label_4.setSizePolicy(sizePolicy) + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + self.label_4.setFont(font) + self.label_4.setStyleSheet("margin-left:24") + self.label_4.setObjectName("label_4") + self.horizontalLayout.addWidget(self.label_4) + self.leRootDir = QtWidgets.QLineEdit(self.scrollAreaWidgetContents) + self.leRootDir.setObjectName("leRootDir") + self.horizontalLayout.addWidget(self.leRootDir) + self.verticalLayout_2.addLayout(self.horizontalLayout) + self.groupBox = QtWidgets.QGroupBox(self.scrollAreaWidgetContents) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.groupBox.sizePolicy().hasHeightForWidth()) + self.groupBox.setSizePolicy(sizePolicy) + self.groupBox.setObjectName("groupBox") + self.verticalLayout_8 = QtWidgets.QVBoxLayout(self.groupBox) + self.verticalLayout_8.setContentsMargins(0, 6, 0, 9) + self.verticalLayout_8.setObjectName("verticalLayout_8") + self.gridLayout_4 = QtWidgets.QGridLayout() + self.gridLayout_4.setContentsMargins(0, -1, -1, -1) + self.gridLayout_4.setVerticalSpacing(3) + self.gridLayout_4.setObjectName("gridLayout_4") + self.leTilesFroNGM = QtWidgets.QLineEdit(self.groupBox) + self.leTilesFroNGM.setToolTip("") + self.leTilesFroNGM.setPlaceholderText("") + self.leTilesFroNGM.setObjectName("leTilesFroNGM") + self.gridLayout_4.addWidget(self.leTilesFroNGM, 2, 2, 1, 1) + self.lInfoIconOutputNGM = QtWidgets.QLabel(self.groupBox) + self.lInfoIconOutputNGM.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor)) + self.lInfoIconOutputNGM.setOpenExternalLinks(False) + self.lInfoIconOutputNGM.setObjectName("lInfoIconOutputNGM") + self.gridLayout_4.addWidget(self.lInfoIconOutputNGM, 2, 1, 1, 1) + self.rbOutputDir = QtWidgets.QRadioButton(self.groupBox) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.rbOutputDir.sizePolicy().hasHeightForWidth()) + self.rbOutputDir.setSizePolicy(sizePolicy) + self.rbOutputDir.setObjectName("rbOutputDir") + self.gridLayout_4.addWidget(self.rbOutputDir, 1, 0, 1, 1) + self.lInfoIconOutputZip = QtWidgets.QLabel(self.groupBox) + self.lInfoIconOutputZip.setEnabled(True) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.lInfoIconOutputZip.sizePolicy().hasHeightForWidth()) + self.lInfoIconOutputZip.setSizePolicy(sizePolicy) + self.lInfoIconOutputZip.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor)) + self.lInfoIconOutputZip.setText("") + self.lInfoIconOutputZip.setTextFormat(QtCore.Qt.RichText) + self.lInfoIconOutputZip.setOpenExternalLinks(False) + self.lInfoIconOutputZip.setObjectName("lInfoIconOutputZip") + self.gridLayout_4.addWidget(self.lInfoIconOutputZip, 0, 1, 1, 1) + self.rbOutputNGM = QtWidgets.QRadioButton(self.groupBox) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.rbOutputNGM.sizePolicy().hasHeightForWidth()) + self.rbOutputNGM.setSizePolicy(sizePolicy) + icon = QtGui.QIcon() + icon.addPixmap(QtGui.QPixmap(":/icons/ngm_index_24x24.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.rbOutputNGM.setIcon(icon) + self.rbOutputNGM.setObjectName("rbOutputNGM") + self.gridLayout_4.addWidget(self.rbOutputNGM, 2, 0, 1, 1) + self.horizontalLayout_7 = QtWidgets.QHBoxLayout() + self.horizontalLayout_7.setObjectName("horizontalLayout_7") + self.leDirectoryName = QtWidgets.QLineEdit(self.groupBox) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.leDirectoryName.sizePolicy().hasHeightForWidth()) + self.leDirectoryName.setSizePolicy(sizePolicy) + self.leDirectoryName.setObjectName("leDirectoryName") + self.horizontalLayout_7.addWidget(self.leDirectoryName) + self.gridLayout_4.addLayout(self.horizontalLayout_7, 1, 2, 1, 1) + self.rbOutputZip = QtWidgets.QRadioButton(self.groupBox) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.rbOutputZip.sizePolicy().hasHeightForWidth()) + self.rbOutputZip.setSizePolicy(sizePolicy) + self.rbOutputZip.setStyleSheet("") + self.rbOutputZip.setObjectName("rbOutputZip") + self.gridLayout_4.addWidget(self.rbOutputZip, 0, 0, 1, 1) + self.lInfoIconOutputDir = QtWidgets.QLabel(self.groupBox) + self.lInfoIconOutputDir.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor)) + self.lInfoIconOutputDir.setOpenExternalLinks(False) + self.lInfoIconOutputDir.setObjectName("lInfoIconOutputDir") + self.gridLayout_4.addWidget(self.lInfoIconOutputDir, 1, 1, 1, 1) + self.leZipFileName = QtWidgets.QLineEdit(self.groupBox) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.leZipFileName.sizePolicy().hasHeightForWidth()) + self.leZipFileName.setSizePolicy(sizePolicy) + self.leZipFileName.setObjectName("leZipFileName") + self.gridLayout_4.addWidget(self.leZipFileName, 0, 2, 1, 1) + self.btnBrowse = QtWidgets.QToolButton(self.groupBox) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnBrowse.sizePolicy().hasHeightForWidth()) + self.btnBrowse.setSizePolicy(sizePolicy) + self.btnBrowse.setObjectName("btnBrowse") + self.gridLayout_4.addWidget(self.btnBrowse, 1, 3, 1, 1) + self.label_41 = QtWidgets.QLabel(self.groupBox) + self.label_41.setStyleSheet("margin-left:2") + self.label_41.setAlignment(QtCore.Qt.AlignCenter) + self.label_41.setObjectName("label_41") + self.gridLayout_4.addWidget(self.label_41, 0, 3, 1, 1) + self.label_42 = QtWidgets.QLabel(self.groupBox) + self.label_42.setStyleSheet("margin-left:2") + self.label_42.setAlignment(QtCore.Qt.AlignCenter) + self.label_42.setObjectName("label_42") + self.gridLayout_4.addWidget(self.label_42, 2, 3, 1, 1) + self.verticalLayout_8.addLayout(self.gridLayout_4) + self.verticalLayout_2.addWidget(self.groupBox) + self.groupBox_2 = QtWidgets.QGroupBox(self.scrollAreaWidgetContents) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.groupBox_2.sizePolicy().hasHeightForWidth()) + self.groupBox_2.setSizePolicy(sizePolicy) + self.groupBox_2.setAutoFillBackground(False) + self.groupBox_2.setObjectName("groupBox_2") + self.verticalLayout_7 = QtWidgets.QVBoxLayout(self.groupBox_2) + self.verticalLayout_7.setContentsMargins(0, 6, 0, 9) + self.verticalLayout_7.setSpacing(3) + self.verticalLayout_7.setObjectName("verticalLayout_7") + self.rbExtentCanvas = QtWidgets.QRadioButton(self.groupBox_2) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.rbExtentCanvas.sizePolicy().hasHeightForWidth()) + self.rbExtentCanvas.setSizePolicy(sizePolicy) + self.rbExtentCanvas.setObjectName("rbExtentCanvas") + self.verticalLayout_7.addWidget(self.rbExtentCanvas) + self.rbExtentFull = QtWidgets.QRadioButton(self.groupBox_2) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.rbExtentFull.sizePolicy().hasHeightForWidth()) + self.rbExtentFull.setSizePolicy(sizePolicy) + self.rbExtentFull.setObjectName("rbExtentFull") + self.verticalLayout_7.addWidget(self.rbExtentFull) + self.horizontalLayout_4 = QtWidgets.QHBoxLayout() + self.horizontalLayout_4.setObjectName("horizontalLayout_4") + self.rbExtentLayer = QtWidgets.QRadioButton(self.groupBox_2) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.rbExtentLayer.sizePolicy().hasHeightForWidth()) + self.rbExtentLayer.setSizePolicy(sizePolicy) + self.rbExtentLayer.setObjectName("rbExtentLayer") + self.horizontalLayout_4.addWidget(self.rbExtentLayer) + self.cmbLayers = QtWidgets.QComboBox(self.groupBox_2) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.cmbLayers.sizePolicy().hasHeightForWidth()) + self.cmbLayers.setSizePolicy(sizePolicy) + self.cmbLayers.setObjectName("cmbLayers") + self.horizontalLayout_4.addWidget(self.cmbLayers) + self.verticalLayout_7.addLayout(self.horizontalLayout_4) + self.verticalLayout_2.addWidget(self.groupBox_2) + self.groupBox_3 = QtWidgets.QGroupBox(self.scrollAreaWidgetContents) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.groupBox_3.sizePolicy().hasHeightForWidth()) + self.groupBox_3.setSizePolicy(sizePolicy) + self.groupBox_3.setObjectName("groupBox_3") + self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.groupBox_3) + self.verticalLayout_6.setContentsMargins(0, 6, 0, 9) + self.verticalLayout_6.setObjectName("verticalLayout_6") + self.gridLayout_3 = QtWidgets.QGridLayout() + self.gridLayout_3.setContentsMargins(24, 5, 5, 5) + self.gridLayout_3.setVerticalSpacing(3) + self.gridLayout_3.setObjectName("gridLayout_3") + self.spnZoomMin = QtWidgets.QSpinBox(self.groupBox_3) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.spnZoomMin.sizePolicy().hasHeightForWidth()) + self.spnZoomMin.setSizePolicy(sizePolicy) + self.spnZoomMin.setMaximum(40) + self.spnZoomMin.setObjectName("spnZoomMin") + self.gridLayout_3.addWidget(self.spnZoomMin, 0, 1, 1, 1) + self.label_2 = QtWidgets.QLabel(self.groupBox_3) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_2.sizePolicy().hasHeightForWidth()) + self.label_2.setSizePolicy(sizePolicy) + self.label_2.setObjectName("label_2") + self.gridLayout_3.addWidget(self.label_2, 1, 0, 1, 1) + self.label = QtWidgets.QLabel(self.groupBox_3) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth()) + self.label.setSizePolicy(sizePolicy) + self.label.setObjectName("label") + self.gridLayout_3.addWidget(self.label, 0, 0, 1, 1) + self.spnZoomMax = QtWidgets.QSpinBox(self.groupBox_3) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.spnZoomMax.sizePolicy().hasHeightForWidth()) + self.spnZoomMax.setSizePolicy(sizePolicy) + self.spnZoomMax.setMinimum(0) + self.spnZoomMax.setMaximum(40) + self.spnZoomMax.setProperty("value", 18) + self.spnZoomMax.setObjectName("spnZoomMax") + self.gridLayout_3.addWidget(self.spnZoomMax, 1, 1, 1, 1) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.gridLayout_3.addItem(spacerItem, 0, 2, 1, 1) + self.verticalLayout_6.addLayout(self.gridLayout_3) + self.verticalLayout_2.addWidget(self.groupBox_3) + self.grpParameters = QgsCollapsibleGroupBox(self.scrollAreaWidgetContents) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.grpParameters.sizePolicy().hasHeightForWidth()) + self.grpParameters.setSizePolicy(sizePolicy) + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + self.grpParameters.setFont(font) + self.grpParameters.setStyleSheet("QgsCollapsibleGroupBoxBasic::title, QgsCollapsibleGroupBox::title { subcontrol-origin: margin; subcontrol-position: top left; margin-left: 20px; top: 1px;}, ") + self.grpParameters.setCollapsed(True) + self.grpParameters.setScrollOnExpand(True) + self.grpParameters.setSaveCollapsedState(True) + self.grpParameters.setObjectName("grpParameters") + self.verticalLayout_9 = QtWidgets.QVBoxLayout(self.grpParameters) + self.verticalLayout_9.setContentsMargins(0, 6, 0, 9) + self.verticalLayout_9.setSpacing(3) + self.verticalLayout_9.setObjectName("verticalLayout_9") + self.gridLayout_7 = QtWidgets.QGridLayout() + self.gridLayout_7.setContentsMargins(24, -1, -1, -1) + self.gridLayout_7.setHorizontalSpacing(6) + self.gridLayout_7.setVerticalSpacing(3) + self.gridLayout_7.setObjectName("gridLayout_7") + self.label_7 = QtWidgets.QLabel(self.grpParameters) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_7.sizePolicy().hasHeightForWidth()) + self.label_7.setSizePolicy(sizePolicy) + self.label_7.setObjectName("label_7") + self.gridLayout_7.addWidget(self.label_7, 3, 0, 1, 1) + self.spnTransparency = QtWidgets.QSpinBox(self.grpParameters) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.spnTransparency.sizePolicy().hasHeightForWidth()) + self.spnTransparency.setSizePolicy(sizePolicy) + self.spnTransparency.setMinimumSize(QtCore.QSize(60, 0)) + self.spnTransparency.setMaximum(255) + self.spnTransparency.setProperty("value", 255) + self.spnTransparency.setObjectName("spnTransparency") + self.gridLayout_7.addWidget(self.spnTransparency, 2, 1, 1, 1) + self.spnQuality = QtWidgets.QSpinBox(self.grpParameters) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.spnQuality.sizePolicy().hasHeightForWidth()) + self.spnQuality.setSizePolicy(sizePolicy) + self.spnQuality.setMinimumSize(QtCore.QSize(60, 0)) + self.spnQuality.setMaximum(100) + self.spnQuality.setObjectName("spnQuality") + self.gridLayout_7.addWidget(self.spnQuality, 3, 1, 1, 1) + self.label_6 = QtWidgets.QLabel(self.grpParameters) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_6.sizePolicy().hasHeightForWidth()) + self.label_6.setSizePolicy(sizePolicy) + self.label_6.setObjectName("label_6") + self.gridLayout_7.addWidget(self.label_6, 1, 0, 1, 1) + self.verticalLayout_5 = QtWidgets.QVBoxLayout() + self.verticalLayout_5.setContentsMargins(0, 0, 0, 0) + self.verticalLayout_5.setSpacing(0) + self.verticalLayout_5.setObjectName("verticalLayout_5") + self.label_9 = QtWidgets.QLabel(self.grpParameters) + self.label_9.setStyleSheet("margin-left:2") + self.label_9.setObjectName("label_9") + self.verticalLayout_5.addWidget(self.label_9) + self.chkLockRatio = QtWidgets.QCheckBox(self.grpParameters) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.chkLockRatio.sizePolicy().hasHeightForWidth()) + self.chkLockRatio.setSizePolicy(sizePolicy) + self.chkLockRatio.setObjectName("chkLockRatio") + self.verticalLayout_5.addWidget(self.chkLockRatio) + self.label_10 = QtWidgets.QLabel(self.grpParameters) + self.label_10.setStyleSheet("margin-left:2") + self.label_10.setObjectName("label_10") + self.verticalLayout_5.addWidget(self.label_10) + self.gridLayout_7.addLayout(self.verticalLayout_5, 0, 2, 1, 1) + self.label_5 = QtWidgets.QLabel(self.grpParameters) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_5.sizePolicy().hasHeightForWidth()) + self.label_5.setSizePolicy(sizePolicy) + self.label_5.setObjectName("label_5") + self.gridLayout_7.addWidget(self.label_5, 2, 0, 1, 1) + self.cmbFormat = QtWidgets.QComboBox(self.grpParameters) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.cmbFormat.sizePolicy().hasHeightForWidth()) + self.cmbFormat.setSizePolicy(sizePolicy) + self.cmbFormat.setMinimumSize(QtCore.QSize(60, 0)) + self.cmbFormat.setObjectName("cmbFormat") + self.cmbFormat.addItem("") + self.cmbFormat.addItem("") + self.gridLayout_7.addWidget(self.cmbFormat, 1, 1, 1, 1) + self.verticalLayout_4 = QtWidgets.QVBoxLayout() + self.verticalLayout_4.setSpacing(3) + self.verticalLayout_4.setObjectName("verticalLayout_4") + self.spnTileWidth = QtWidgets.QSpinBox(self.grpParameters) + self.spnTileWidth.setMinimumSize(QtCore.QSize(60, 0)) + self.spnTileWidth.setMinimum(128) + self.spnTileWidth.setMaximum(2048) + self.spnTileWidth.setProperty("value", 256) + self.spnTileWidth.setObjectName("spnTileWidth") + self.verticalLayout_4.addWidget(self.spnTileWidth) + self.spnTileHeight = QtWidgets.QSpinBox(self.grpParameters) + self.spnTileHeight.setEnabled(True) + self.spnTileHeight.setMinimumSize(QtCore.QSize(60, 0)) + self.spnTileHeight.setMinimum(128) + self.spnTileHeight.setMaximum(2048) + self.spnTileHeight.setProperty("value", 256) + self.spnTileHeight.setObjectName("spnTileHeight") + self.verticalLayout_4.addWidget(self.spnTileHeight) + self.gridLayout_7.addLayout(self.verticalLayout_4, 0, 1, 1, 1) + self.verticalLayout_3 = QtWidgets.QVBoxLayout() + self.verticalLayout_3.setSpacing(8) + self.verticalLayout_3.setObjectName("verticalLayout_3") + self.label_3 = QtWidgets.QLabel(self.grpParameters) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_3.sizePolicy().hasHeightForWidth()) + self.label_3.setSizePolicy(sizePolicy) + self.label_3.setObjectName("label_3") + self.verticalLayout_3.addWidget(self.label_3) + self.lblHeight = QtWidgets.QLabel(self.grpParameters) + self.lblHeight.setEnabled(True) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.lblHeight.sizePolicy().hasHeightForWidth()) + self.lblHeight.setSizePolicy(sizePolicy) + self.lblHeight.setObjectName("lblHeight") + self.verticalLayout_3.addWidget(self.lblHeight) + self.gridLayout_7.addLayout(self.verticalLayout_3, 0, 0, 1, 1) + spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.gridLayout_7.addItem(spacerItem1, 0, 3, 1, 1) + self.label_8 = QtWidgets.QLabel(self.grpParameters) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_8.sizePolicy().hasHeightForWidth()) + self.label_8.setSizePolicy(sizePolicy) + self.label_8.setObjectName("label_8") + self.gridLayout_7.addWidget(self.label_8, 3, 2, 1, 1) + self.verticalLayout_9.addLayout(self.gridLayout_7) + self.chkAntialiasing = QtWidgets.QCheckBox(self.grpParameters) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.chkAntialiasing.sizePolicy().hasHeightForWidth()) + self.chkAntialiasing.setSizePolicy(sizePolicy) + self.chkAntialiasing.setObjectName("chkAntialiasing") + self.verticalLayout_9.addWidget(self.chkAntialiasing) + self.chkTMSConvention = QtWidgets.QCheckBox(self.grpParameters) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.chkTMSConvention.sizePolicy().hasHeightForWidth()) + self.chkTMSConvention.setSizePolicy(sizePolicy) + self.chkTMSConvention.setObjectName("chkTMSConvention") + self.verticalLayout_9.addWidget(self.chkTMSConvention) + self.chkRenderOutsideTiles = QtWidgets.QCheckBox(self.grpParameters) + self.chkRenderOutsideTiles.setEnabled(True) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.chkRenderOutsideTiles.sizePolicy().hasHeightForWidth()) + self.chkRenderOutsideTiles.setSizePolicy(sizePolicy) + self.chkRenderOutsideTiles.setChecked(True) + self.chkRenderOutsideTiles.setObjectName("chkRenderOutsideTiles") + self.verticalLayout_9.addWidget(self.chkRenderOutsideTiles) + self.chkMBTilesCompression = QtWidgets.QCheckBox(self.grpParameters) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.chkMBTilesCompression.sizePolicy().hasHeightForWidth()) + self.chkMBTilesCompression.setSizePolicy(sizePolicy) + self.chkMBTilesCompression.setObjectName("chkMBTilesCompression") + self.verticalLayout_9.addWidget(self.chkMBTilesCompression) + self.chkWriteJson = QtWidgets.QCheckBox(self.grpParameters) + self.chkWriteJson.setObjectName("chkWriteJson") + self.verticalLayout_9.addWidget(self.chkWriteJson) + self.chkWriteOverview = QtWidgets.QCheckBox(self.grpParameters) + self.chkWriteOverview.setObjectName("chkWriteOverview") + self.verticalLayout_9.addWidget(self.chkWriteOverview) + self.chkWriteMapurl = QtWidgets.QCheckBox(self.grpParameters) + self.chkWriteMapurl.setObjectName("chkWriteMapurl") + self.verticalLayout_9.addWidget(self.chkWriteMapurl) + self.chkWriteViewer = QtWidgets.QCheckBox(self.grpParameters) + self.chkWriteViewer.setObjectName("chkWriteViewer") + self.verticalLayout_9.addWidget(self.chkWriteViewer) + self.verticalLayout_2.addWidget(self.grpParameters) + spacerItem2 = QtWidgets.QSpacerItem(20, 5, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout_2.addItem(spacerItem2) + self.scrollArea.setWidget(self.scrollAreaWidgetContents) + self.verticalLayout.addWidget(self.scrollArea) + self.horizontalLayout_5 = QtWidgets.QHBoxLayout() + self.horizontalLayout_5.setContentsMargins(0, 0, 0, 6) + self.horizontalLayout_5.setObjectName("horizontalLayout_5") + self.progressBar = QtWidgets.QProgressBar(Dialog) + self.progressBar.setProperty("value", 0) + self.progressBar.setTextVisible(True) + self.progressBar.setInvertedAppearance(False) + self.progressBar.setObjectName("progressBar") + self.horizontalLayout_5.addWidget(self.progressBar) + self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.buttonBox.sizePolicy().hasHeightForWidth()) + self.buttonBox.setSizePolicy(sizePolicy) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Close) + self.buttonBox.setObjectName("buttonBox") + self.horizontalLayout_5.addWidget(self.buttonBox) + self.verticalLayout.addLayout(self.horizontalLayout_5) + self.scrollArea.raise_() + + self.retranslateUi(Dialog) + self.buttonBox.accepted.connect(Dialog.accept) + self.buttonBox.rejected.connect(Dialog.reject) + QtCore.QMetaObject.connectSlotsByName(Dialog) + + def retranslateUi(self, Dialog): + _translate = QtCore.QCoreApplication.translate + Dialog.setWindowTitle(_translate("Dialog", "QTiles")) + self.label_4.setText(_translate("Dialog", "Tileset name")) + self.groupBox.setTitle(_translate("Dialog", "Output")) + self.lInfoIconOutputNGM.setText(_translate("Dialog", "")) + self.rbOutputDir.setText(_translate("Dialog", "Directory")) + self.rbOutputNGM.setText(_translate("Dialog", "NGM")) + self.rbOutputZip.setText(_translate("Dialog", "File")) + self.lInfoIconOutputDir.setText(_translate("Dialog", "")) + self.btnBrowse.setText(_translate("Dialog", "...")) + self.label_41.setText(_translate("Dialog", "╮")) + self.label_42.setText(_translate("Dialog", "╯")) + self.groupBox_2.setTitle(_translate("Dialog", "Extent")) + self.rbExtentCanvas.setText(_translate("Dialog", "Canvas extent")) + self.rbExtentFull.setText(_translate("Dialog", "Full extent")) + self.rbExtentLayer.setText(_translate("Dialog", "Layer extent")) + self.groupBox_3.setTitle(_translate("Dialog", "Zoom")) + self.label_2.setText(_translate("Dialog", "Maximum zoom")) + self.label.setText(_translate("Dialog", "Minimum zoom")) + self.grpParameters.setTitle(_translate("Dialog", "Parameters")) + self.label_7.setText(_translate("Dialog", "Quality")) + self.label_6.setText(_translate("Dialog", "Format")) + self.label_9.setText(_translate("Dialog", "╮")) + self.chkLockRatio.setToolTip(_translate("Dialog", "Lock 1:1 ratio")) + self.label_10.setText(_translate("Dialog", "╯")) + self.label_5.setText(_translate("Dialog", "Background transparency")) + self.cmbFormat.setItemText(0, _translate("Dialog", "PNG")) + self.cmbFormat.setItemText(1, _translate("Dialog", "JPG")) + self.label_3.setText(_translate("Dialog", "Tile width")) + self.lblHeight.setText(_translate("Dialog", "Tile height")) + self.label_8.setText(_translate("Dialog", "(0-100)")) + self.chkAntialiasing.setText(_translate("Dialog", "Make lines appear less jagged at the expence of some drawing performance")) + self.chkTMSConvention.setText(_translate("Dialog", "Use TMS tiles convention (Slippy Map by default)")) + self.chkRenderOutsideTiles.setText(_translate("Dialog", "Render tiles outside of layers extents (within combined extent)")) + self.chkMBTilesCompression.setText(_translate("Dialog", "Use MBTiles compression")) + self.chkWriteJson.setText(_translate("Dialog", "Write .json metadata")) + self.chkWriteOverview.setText(_translate("Dialog", "Write overview image file")) + self.chkWriteMapurl.setText(_translate("Dialog", "Write .mapurl file")) + self.chkWriteViewer.setText(_translate("Dialog", "Write Leaflet-based viewer")) + +from qgscollapsiblegroupbox import QgsCollapsibleGroupBox diff --git a/writers.py b/writers.py index 4cf641d..be9e9fb 100644 --- a/writers.py +++ b/writers.py @@ -7,6 +7,7 @@ # Generates tiles from QGIS project # # Copyright (C) 2012-2014 NextGIS (info@nextgis.org) +# Copyright (C) 2019 Alexander Bruy (alexander.bruy@gmail.com) # # This source is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free @@ -25,14 +26,13 @@ # #****************************************************************************** +import json import sqlite3 import zipfile -import json -from PyQt4.QtCore import * -from PyQt4.QtGui import * +from qgis.PyQt.QtCore import QDir, QTemporaryFile, QIODevice, QByteArray, QBuffer -from mbutils import * +from . import mbutils class DirectoryWriter: @@ -40,11 +40,11 @@ def __init__(self, outputPath, rootDir): self.output = outputPath self.rootDir = rootDir - def writeTile(self, tile, image, format, quality): + def writeTile(self, tile, image, fileFormat, quality): path = '%s/%s/%s' % (self.rootDir, tile.z, tile.x) dirPath = '%s/%s' % (self.output.absoluteFilePath(), path) QDir().mkpath(dirPath) - image.save('%s/%s.%s' % (dirPath, tile.y, format.lower()), format, quality) + image.save('%s/%s.%s' % (dirPath, tile.y, fileFormat.lower()), fileFormat, quality) def finalize(self): pass @@ -55,19 +55,19 @@ def __init__(self, outputPath, rootDir): self.output = outputPath self.rootDir = rootDir - self.zipFile = zipfile.ZipFile(unicode(self.output.absoluteFilePath()), 'w') + self.zipFile = zipfile.ZipFile(self.output.absoluteFilePath(), 'w') self.tempFile = QTemporaryFile() self.tempFile.setAutoRemove(False) self.tempFile.open(QIODevice.WriteOnly) self.tempFileName = self.tempFile.fileName() self.tempFile.close() - def writeTile(self, tile, image, format, quality): + def writeTile(self, tile, image, fileFormat, quality): path = '%s/%s/%s' % (self.rootDir, tile.z, tile.x) - image.save(self.tempFileName, format, quality) - tilePath = '%s/%s.%s' % (path, tile.y, format.lower()) - self.zipFile.write(unicode(self.tempFileName), unicode(tilePath).encode('utf8')) + image.save(self.tempFileName, fileFormat, quality) + tilePath = '%s/%s.%s' % (path, tile.y, fileFormat.lower()) + self.zipFile.write(self.tempFileName, tilePath) def finalize(self): self.tempFile.close() @@ -81,8 +81,8 @@ def __init__(self, outputPath, rootDir): self.levels = {} self.__layerName = rootDir - def writeTile(self, tile, image, format, quality): - ZipWriter.writeTile(self, tile, image, format, quality) + def writeTile(self, tile, image, fileFormat, quality): + ZipWriter.writeTile(self, tile, image, fileFormat, quality) level = self.levels.get(tile.z, {"x": [], "y": []}) level["x"].append(tile.x) level["y"].append(tile.y) @@ -141,10 +141,10 @@ def __init__(self, outputPath, rootDir, formatext, minZoom, maxZoom, extent, com self.rootDir = rootDir self.compression = compression s = str(extent.xMinimum()) + ',' + str(extent.yMinimum()) + ',' + str(extent.xMaximum()) + ','+ str(extent.yMaximum()) - self.connection = mbtiles_connect(unicode(self.output.absoluteFilePath())) + self.connection = mbutils.mbtiles_connect(str(self.output.absoluteFilePath()), True) self.cursor = self.connection.cursor() - optimize_connection(self.cursor) - mbtiles_setup(self.cursor) + mbutils.optimize_connection(self.cursor) + mbutils.mbtiles_setup(self.cursor) self.cursor.execute('''INSERT INTO metadata(name, value) VALUES (?, ?);''', ('name', rootDir)) self.cursor.execute('''INSERT INTO metadata(name, value) VALUES (?, ?);''', ('description', 'Created with QTiles')) self.cursor.execute('''INSERT INTO metadata(name, value) VALUES (?, ?);''', ('format', formatext.lower())) @@ -154,27 +154,27 @@ def __init__(self, outputPath, rootDir, formatext, minZoom, maxZoom, extent, com self.cursor.execute('''INSERT INTO metadata(name, value) VALUES (?, ?);''', ('version', '1.1')) self.cursor.execute('''INSERT INTO metadata(name, value) VALUES (?, ?);''', ('bounds', s)) self.connection.commit() - - def writeTile(self, tile, image, format, quality): + + def writeTile(self, tile, image, fileFormat, quality): data = QByteArray() buff = QBuffer(data) - image.save(buff, format, quality) + image.save(buff, fileFormat, quality) self.cursor.execute('''INSERT INTO tiles(zoom_level, tile_column, tile_row, tile_data) VALUES (?, ?, ?, ?);''', (tile.z, tile.x, tile.y, sqlite3.Binary(buff.data()))) buff.close() def finalize(self): - optimize_database(self.connection) + mbutils.optimize_database(self.connection) self.connection.commit() if self.compression: # start compression - compression_prepare(self.cursor, self.connection) + mbutils.compression_prepare(self.cursor, self.connection) self.cursor.execute("select count(zoom_level) from tiles") res = self.cursor.fetchone() total_tiles = res[0] - compression_do(self.cursor, self.connection, total_tiles) - compression_finalize(self.cursor) - optimize_database(self.connection) + mbutils.compression_do(self.cursor, self.connection, total_tiles) + mbutils.compression_finalize(self.cursor) + mbutils.optimize_database(self.connection) self.connection.commit() # end compression self.connection.close()