From 7482e88ec7767529384f18d676b5c0ea035d8c46 Mon Sep 17 00:00:00 2001 From: Alexander Lisovenko Date: Fri, 23 Oct 2015 11:04:04 +0300 Subject: [PATCH] Create tiles for NextGIS Mobile --- Makefile | 2 +- i18n/{qtiles_ru.ts => qtiles_ru_RU.ts} | 144 ++++++++++++------ icons/ngm_index_24x24.png | Bin 0 -> 1103 bytes metadata.txt | 9 +- qtilesdialog.py | 120 ++++++++++++--- resources.qrc | 1 + tilingthread.py | 2 +- ui/qtilesdialogbase.ui | 194 +++++++++++++++++++------ 8 files changed, 358 insertions(+), 114 deletions(-) rename i18n/{qtiles_ru.ts => qtiles_ru_RU.ts} (74%) create mode 100644 icons/ngm_index_24x24.png diff --git a/Makefile b/Makefile index 3b7a396..4055863 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ $(UI_FILES): $(UI_PATH)/ui_%.py: $(UI_PATH)/%.ui pyuic4 -o $@ $< $(LANG_FILES): $(LANG_PATH)/%.qm: $(LANG_PATH)/%.ts - lrelease-qt4 $< + lrelease $< $(RES_FILES): $(RES_PATH)/%_rc.py: $(RES_PATH)/%.qrc pyrcc4 -o $@ $< diff --git a/i18n/qtiles_ru.ts b/i18n/qtiles_ru_RU.ts similarity index 74% rename from i18n/qtiles_ru.ts rename to i18n/qtiles_ru_RU.ts index 8785063..e00fdbb 100644 --- a/i18n/qtiles_ru.ts +++ b/i18n/qtiles_ru_RU.ts @@ -1,5 +1,6 @@ - + + AboutDialog @@ -60,18 +61,23 @@ specification. Output tiles can be saved in directory or as zip archive.</p&g <p>Generate tiles from QGIS project.</p><p>Plugin generates raster tiles from QGIS project corresponding to <a href="http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames">Slippy Map</a> specification. Output tiles can be saved in directory or as zip archive.</p><p><strong>Developers</strong>: (<a href="http://nextgis.org">NextGIS</a>), portions of code by Andrew Naplavkov and Giovanni Allegri.</p><p><strong>Homepage</strong>: <a href="https://github.com/nextgis/QTiles">https://github.com/nextgis/QTiles/issues</a></p><p>Please report bugs at <a href="https://github.com/nextgis/QTiles/issues">bugtracker</a></p> - <p>Создание набора тайлов из проектов QGIS.</p><p>Модуль создаёт набор растровых тайлов из проекта QGIS в соответствии со спецификацией <a href="http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames">Slippy Map</a>. Полученные тайлы могут быть записаны в каталог или упакованы в zip архив.</p><p><strong>Разработчики</strong>: (<a href="http://nextgis.org">NextGIS</a>), фрагменты кода Andrew Naplavkov and Giovanni Allegri.</p><p><strong>Домашняя страница</strong>: <a href="https://github.com/nextgis/QTiles">https://github.com/nextgis/QTiles/issues</a></p><p>Please report bugs at <a href="https://github.com/nextgis/QTiles/issues">bugtracker</a></p> + <p>Создание набора тайлов из проектов QGIS.</p><p>Модуль создаёт набор растровых тайлов из проекта QGIS в соответствии со спецификацией <a href="http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames">Slippy Map</a>. Полученные тайлы могут быть записаны в каталог или упакованы в zip архив.</p><p><strong>Разработчики</strong>: (<a href="http://nextgis.org">NextGIS</a>), фрагменты кода Andrew Naplavkov and Giovanni Allegri.</p><p><strong>Домашняя страница</strong>: <a href="https://github.com/nextgis/QTiles">https://github.com/nextgis/QTiles/issues</a></p><p>Please report bugs at <a href="https://github.com/nextgis/QTiles/issues">bugtracker</a></p> + + + + <p>Generate tiles from QGIS project.</p><p>Plugin generates raster tiles from QGIS project corresponding to <a href="http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames">Slippy Map</a> specification. Output tiles can be saved in directory or as zip archive.</p><p><strong>Developers</strong>: (<a href="http://nextgis.org">NextGIS</a>), portions of code by Andrew Naplavkov and Giovanni Allegri.</p><p><strong>Homepage</strong>: <a href="https://github.com/nextgis/QTiles">https://github.com/nextgis/QTiles</a></p><p>Please report bugs at <a href="https://github.com/nextgis/QTiles/issues">bugtracker</a></p> + Dialog - + QTiles - + Output Результат @@ -81,67 +87,67 @@ specification. Output tiles can be saved in directory or as zip archive.</p&g ZIP архив - + Browse... Обзор... - + Directory Каталог - + Extent Охват - + Canvas extent Охват карты - + Full extent Полный охват - + Layer extent Охват слоя - + Zoom Масштаб - + Minimum zoom Минимальный масштаб - + Maximum zoom Максимальный масштаб - + Parameters Параметры - + Tile width Ширина тайла - + Lock 1:1 ratio Зафиксировать соотношение сторон 1:1 - + Tile height Высота тайла @@ -174,12 +180,12 @@ p, li { white-space: pre-wrap; } - + Tileset name Название набора - + Make lines appear less jagged at the expence of some drawing performance Рисовать сглаженные линии (снижает скорость отрисовки) @@ -189,40 +195,90 @@ p, li { white-space: pre-wrap; } Использовать спецификацию TMS (по умолчанию Slippy Maps) - + Write .mapurl file Создать файл .mapurl - + Write Leaflet-based viewer Создать просмотрщик на Leaflet - + Use TMS tiles convention (Slippy Map by default) Использовать спецификацию TMS (по умолчанию Slippy Map) - + File Файл - + Background transparency Прозрачность фона Suffix - Суффикс + Суффикс + + + + NGM + + + + + Prepare package for NextGIS Mobile + Подготовить пакет для NextGIS Mobile + + + + Use MBTiles compression + Использовать сжатие MBTiles + + + + Write .json metadata + Сохранить метаданные в файл .json + + + + Write overview image file + Создаить файл обзорноого изображения карты + + + + Format + Формат + + + + Quality + Качество + + + + (0-100) + + + + + PNG + + + + + JPG + QTiles - + Error Ошибка @@ -240,12 +296,12 @@ Plugin will not be enabled. Модуль не будет загружен. - + QTiles - + About QTiles... О QTiles... @@ -261,7 +317,7 @@ Plugin will not be enabled. Эта версия QTiles требует наличия QGIS 1.9.0. Модуль не будет загружен. - + QGIS %s detected. Обнаружена QGIS %s. @@ -272,7 +328,7 @@ Plugin will not be enabled. Эта версия QTiles требует наличия QGIS 2.0. Модуль не будет загружен. - + This version of QTiles requires at least QGIS 2.0. Plugin will not be enabled. Эта версия QTiles требует наличия QGIS 2.0 и выше. Модуль не может быть загружен. @@ -280,62 +336,62 @@ Plugin will not be enabled. QTilesDialog - + No output Не указан путь - + Output path is not set. Please enter correct path and try again. Не указан путь назначения. Пожалуйста, введите правильный путь и попробуйте ещё раз. - + Directory not empty Каталог не пуст - + Selected directory is not empty. Continue? Каталог назначения не пуст. Продолжить? - + Wrong zoom Неверный масштаб - + Maximum zoom value is lower than minimum. Please correct this and try again. Значение максимального масштаба меньше минимального. Пожалуйста, исправьте ошибку и попробуйте ещё раз. - + Cancel Отменить - + Close Закрыть - + Save to file Сохранить файл - + ZIP archives (*.zip *.ZIP) ZIP архивы (*.zip *.ZIP) - + Save to directory Выбрать каталог - + MBTiles databases (*.mbtiles *.MBTILES) База MBTiles (*.mbtiles *.MBTILES) @@ -343,12 +399,12 @@ Plugin will not be enabled. TilingThread - + Searching tiles... Поиск тайлов... - + Rendering: %v from %m (%p%) Отрисовка: %v из %m (%p%) diff --git a/icons/ngm_index_24x24.png b/icons/ngm_index_24x24.png new file mode 100644 index 0000000000000000000000000000000000000000..046e58dacc69e9da2366ae1bd91cb596b42c2e4d GIT binary patch literal 1103 zcmV-V1hD&wP)X)_+7uyD5Q;9`NQG7q z3<_OzVHL!c3N1x(O@LMY0gF1xdB7QoGTHTAF_*Y1&C_GLy-hckglW z-n>jQuNNN7+z0SEfKxxc%B0F%`QzgN~+s5dBwHVZiq zCdi9i01vD?&kK9{IJT#c{$h}U2vCU}pI%$y)U^tM2v%}QB*+6-z&)!=mR%LXk z%=fdmxlpOm6__mJwhV;CF^6~cWN!IovC8pFbF9Xmp3u+}8fwmS;?f*vZ&V4=un+C( zq2V{IoJ-(U>9mG@<&JFci|fl+5ju>)DL93qF$5xfd3`CnH(V~VEfD+`+ioTR3Pvb} zCMAT0dfeuBr%Gsq`Ffo7Mk%xujo`PKVM~dU2pee;jlhngCH9JGQP2p)s_ZBRS&1UA z#Jb_aTmmDo<~*~tMz%LPRHp6~r%E6~Ac9k~edx&u+GStAfZQB;#Nr;1nbBpv?Y)e1i?tkM(O zHt<{m0FmV2}N&N--+Nq&ad+Rl|_0(d#ACDN$tOBd4&!uEYuskbbf~U zdW;p)MoYji+^TW>(i{bo8)F7#fO`5TZq>&rbO)Ae)rh0#rkSipSV^+Dyj7GGrfU&L#;3V*d!31ubzVF_!`bpE3zy~ri zHUaP`@G|f;u)QS`2N)}2YO$wWFjx^Pk)zWJUh!#(EgKV}0(=X61pFGLI-Cc71Nu^u zqrhWL8#`6)48+%BwTjYd#d%HM0&H0S9PkP7O-hoy719hWfGVzKtr{-#= z)_gTg0$%~20he2JXqLz|2{MPKhaORnO7rpo;26pCCIrp`r+^=TYKtRHTGmXN{{ia~ V()}n@9iIRI002ovPDHLkV1hTd1=9ck literal 0 HcmV?d00001 diff --git a/metadata.txt b/metadata.txt index 176567d..fe1c7af 100644 --- a/metadata.txt +++ b/metadata.txt @@ -2,13 +2,18 @@ name=QTiles description=Generate tiles from QGIS project category=Plugins -version=1.5.0 +version=1.5.1 qgisMinimumVersion=2.0 author=NextGIS email=info@nextgis.com -changelog=1.5.0 +changelog=1.5.1 + * create tiles for NextGIS Mobile + * add mbtiles compression + * add export metatdata to .json file + * add an image overview + 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 diff --git a/qtilesdialog.py b/qtilesdialog.py index ced480e..b6cbf54 100644 --- a/qtilesdialog.py +++ b/qtilesdialog.py @@ -36,28 +36,39 @@ class QTilesDialog(QDialog, Ui_Dialog): + def __init__(self, iface): QDialog.__init__(self) self.setupUi(self) 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.tr('ZIP archives (*.zip *.ZIP)'): '.zip', + self.tr('MBTiles databases (*.mbtiles *.MBTILES)'): '.mbtiles'} + self.settings = QSettings('NextGIS', 'QTiles') self.grpParameters.setSettings(self.settings) self.btnOk = self.buttonBox.button(QDialogButtonBox.Ok) self.btnClose = self.buttonBox.button(QDialogButtonBox.Close) - self.rbOutputZip.toggled.connect(self.__toggleZipTarget) self.rbExtentLayer.toggled.connect(self.__toggleLayerSelector) self.chkLockRatio.stateChanged.connect(self.__toggleHeightEdit) self.spnTileWidth.valueChanged.connect(self.__updateTileSize) - self.btnBrowse.clicked.connect(self.__selectOutput) + self.btnBrowse.clicked.connect(self.__select_output) self.cmbFormat.activated.connect(self.formatChanged) + + self.rbOutputZip.toggled.connect(self.__toggleTarget) + self.rbOutputDir.toggled.connect(self.__toggleTarget) + self.rbNGM.toggled.connect(self.__toggleTarget) + self.rbNGM.setIcon(QIcon(':/icons/ngm_index_24x24.png')) + self.manageGui() def formatChanged(self): - if self.cmbFormat.currentText()=='JPG': + if self.cmbFormat.currentText() == 'JPG': self.spnTransparency.setEnabled(False) self.spnQuality.setEnabled(True) else: @@ -65,8 +76,6 @@ def formatChanged(self): self.spnQuality.setEnabled(False) def manageGui(self): - self.leDirectoryName.setText(self.settings.value('lastUsedDir', '.')) - layers = utils.getMapLayers() relations = self.iface.legendInterface().groupLayerRelationship() for layer in sorted(layers.iteritems(), cmp=locale.strcoll, key=operator.itemgetter(1)): @@ -75,12 +84,28 @@ def manageGui(self): self.cmbLayers.addItem(layer[1], layer[0]) else: self.cmbLayers.addItem('%s - %s' % (layer[1], groupName), layer[0]) + self.rbOutputZip.setChecked(self.settings.value('outputToZip', True, type=bool)) self.rbOutputDir.setChecked(self.settings.value('outputToDir', False, type=bool)) + self.rbNGM.setChecked(self.settings.value('outputToNGM', False, type=bool)) if self.rbOutputZip.isChecked(): self.leDirectoryName.setEnabled(False) + self.leTilesFroNGM.setEnabled(False) + elif self.rbOutputDir.isChecked(): + self.leZipFileName.setEnabled(False) + self.leTilesFroNGM.setEnabled(False) + elif self.rbNGM.isChecked(): + self.leZipFileName.setEnabled(False) + self.leDirectoryName.setEnabled(False) else: self.leZipFileName.setEnabled(False) + self.leDirectoryName.setEnabled(False) + self.leTilesFroNGM.setEnabled(False) + + self.leZipFileName.setText(self.settings.value('outputToZip_Path', '.')) + self.leDirectoryName.setText(self.settings.value('outputToDir_Path', '.')) + self.leTilesFroNGM.setText(self.settings.value('outputToNGM_Path', '.')) + self.cmbLayers.setEnabled(False) self.leRootDir.setText(self.settings.value('rootDir', 'Mapnik')) self.rbExtentCanvas.setChecked(self.settings.value('extentCanvas', True, type=bool)) @@ -101,15 +126,20 @@ 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.formatChanged() def reject(self): QDialog.reject(self) + def accept(self): if self.rbOutputZip.isChecked(): output = self.leZipFileName.text() - else: + elif self.rbOutputDir.isChecked(): output = self.leDirectoryName.text() + elif self.rbNGM.isChecked(): + output = self.leTilesFroNGM.text() + if not output: QMessageBox.warning(self, self.tr('No output'), self.tr('Output path is not set. Please enter correct path and try again.')) return @@ -124,6 +154,7 @@ def accept(self): self.settings.setValue('rootDir', self.leRootDir.text()) self.settings.setValue('outputToZip', self.rbOutputZip.isChecked()) self.settings.setValue('outputToDir', self.rbOutputDir.isChecked()) + self.settings.setValue('outputToNGM', self.rbNGM.isChecked()) self.settings.setValue('extentCanvas', self.rbExtentCanvas.isChecked()) self.settings.setValue('extentFull', self.rbExtentFull.isChecked()) self.settings.setValue('extentLayer', self.rbExtentLayer.isChecked()) @@ -132,7 +163,7 @@ def accept(self): self.settings.setValue('keepRatio', self.chkLockRatio.isChecked()) self.settings.setValue('tileWidth', self.spnTileWidth.value()) self.settings.setValue('tileHeight', self.spnTileHeight.value()) - self.settings.setValue('format', self.cmbFormat.currentIndex ()) + self.settings.setValue('format', self.cmbFormat.currentIndex()) self.settings.setValue('transparency', self.spnTransparency.value()) self.settings.setValue('quality', self.spnQuality.value()) self.settings.setValue('enable_antialiasing', self.chkAntialiasing.isChecked()) @@ -208,13 +239,46 @@ def restoreGui(self): self.btnClose.clicked.disconnect(self.stopProcessing) self.btnClose.setText(self.tr('Close')) self.btnOk.setEnabled(True) - def __toggleZipTarget(self, checked): - self.leZipFileName.setEnabled(checked) - self.leDirectoryName.setEnabled(not checked) - self.chkWriteMapurl.setEnabled(not checked) - self.chkWriteViewer.setEnabled(not checked) + + def __toggleTarget(self, checked): + if checked: + if self.sender() is self.rbOutputZip: + self.leZipFileName.setEnabled(True) + self.leDirectoryName.setEnabled(False) + self.leTilesFroNGM.setEnabled(False) + self.chkWriteMapurl.setEnabled(False) + self.chkWriteViewer.setEnabled(False) + + self.spnTileWidth.setEnabled(True) + self.chkLockRatio.setEnabled(True) + self.cmbFormat.setEnabled(True) + elif self.sender() is self.rbOutputDir: + self.leZipFileName.setEnabled(False) + self.leDirectoryName.setEnabled(True) + self.leTilesFroNGM.setEnabled(False) + self.chkWriteMapurl.setEnabled(True) + self.chkWriteViewer.setEnabled(True) + + self.spnTileWidth.setEnabled(True) + self.chkLockRatio.setEnabled(True) + self.cmbFormat.setEnabled(True) + elif self.sender() is self.rbNGM: + self.leZipFileName.setEnabled(False) + self.leDirectoryName.setEnabled(False) + self.leTilesFroNGM.setEnabled(True) + self.chkWriteMapurl.setEnabled(False) + self.chkWriteViewer.setEnabled(False) + + self.spnTileWidth.setValue(256) + self.spnTileWidth.setEnabled(False) + self.chkLockRatio.setCheckState(Qt.Checked) + self.chkLockRatio.setEnabled(False) + self.cmbFormat.setCurrentIndex(0) + self.cmbFormat.setEnabled(False) + def __toggleLayerSelector(self, checked): self.cmbLayers.setEnabled(checked) + def __toggleHeightEdit(self, state): if state == Qt.Checked: self.lblHeight.setEnabled(False) @@ -223,22 +287,38 @@ def __toggleHeightEdit(self, state): else: self.lblHeight.setEnabled(True) self.spnTileHeight.setEnabled(True) + @pyqtSlot(int) def __updateTileSize(self, value): if self.chkLockRatio.isChecked(): self.spnTileHeight.setValue(value) - def __selectOutput(self): - lastDirectory = QFileInfo(self.settings.value('lastUsedDir', '.')).absoluteDir().absolutePath() + + def __select_output(self): if self.rbOutputZip.isChecked(): - outPath, outFilter = QFileDialog.getSaveFileNameAndFilter(self, self.tr('Save to file'), lastDirectory, ';;'.join(self.FORMATS.iterkeys()), self.FORMATS.keys()[self.FORMATS.values().index('.zip')]) + 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')]) if not outPath: return if not outPath.lower().endswith(self.FORMATS[outFilter]): outPath += self.FORMATS[outFilter] self.leZipFileName.setText(outPath) - else: - outPath = QFileDialog.getExistingDirectory(self, self.tr('Save to directory'), lastDirectory, QFileDialog.ShowDirsOnly) + self.settings.setValue('outputToZip_Path', QFileInfo(outPath).absoluteFilePath()) + + elif self.rbOutputDir.isChecked(): + dir_directory = QFileInfo(self.settings.value('outputToDir_Path', '.')).absolutePath() + outPath = QFileDialog.getExistingDirectory(self, self.tr('Save to directory'), dir_directory, QFileDialog.ShowDirsOnly) if not outPath: return self.leDirectoryName.setText(outPath) - self.settings.setValue('lastUsedDir', QFileInfo(outPath).absoluteFilePath()) + self.settings.setValue('outputToDir_Path', QFileInfo(outPath).absoluteFilePath()) + + elif self.rbNGM.isChecked(): + zip_directory = QFileInfo(self.settings.value('outputToNGM_Path', '.')).absolutePath() + formats = {self.FORMATS.keys()[self.FORMATS.values().index(value)]: value for value in ['.zip']} + outPath, outFilter = QFileDialog.getSaveFileNameAndFilter(self, self.tr('Save to file'), zip_directory, ';;'.join(formats.iterkeys())) + if not outPath: + return + if not outPath.lower().endswith(self.FORMATS[outFilter]): + outPath += self.FORMATS[outFilter] + self.leZipFileName.setText(outPath) + self.settings.setValue('outputToNGM_Path', QFileInfo(outPath).absoluteFilePath()) diff --git a/resources.qrc b/resources.qrc index 36c9116..c980138 100644 --- a/resources.qrc +++ b/resources.qrc @@ -2,6 +2,7 @@ icons/qtiles.png icons/about.png + icons/ngm_index_24x24.png resources/viewer.html diff --git a/tilingthread.py b/tilingthread.py index cfb8506..bb204dd 100644 --- a/tilingthread.py +++ b/tilingthread.py @@ -175,7 +175,7 @@ def writeOverviewFile(self): job = QgsMapRendererCustomPainterJob(self.settings, painter) job.renderSynchronously() painter.end() - + filePath = '%s.%s' % (self.output.absoluteFilePath(), self.format.lower()) if self.mode == 'DIR': filePath = '%s/%s.%s' % (self.output.absoluteFilePath(), self.rootDir, self.format.lower()) diff --git a/ui/qtilesdialogbase.ui b/ui/qtilesdialogbase.ui index 1c91ae4..7c7ea22 100644 --- a/ui/qtilesdialogbase.ui +++ b/ui/qtilesdialogbase.ui @@ -6,8 +6,8 @@ 0 0 - 724 - 671 + 478 + 681 @@ -20,7 +20,19 @@ QTiles - + + 9 + + + 9 + + + 0 + + + 9 + + 0 @@ -36,17 +48,45 @@ 0 0 - 724 - 607 + 443 + 622 + + valign:top + + + 0 + + + 6 + + + 0 + + + 6 + Output + + 9 + + + 6 + + + + + NGM + + + @@ -54,16 +94,12 @@ + + + - - - - Browse... - - - @@ -71,19 +107,33 @@ - - - - + Tileset name - + + + + + + + + Prepare package for NextGIS Mobile + + + + + + + Browse... + + + @@ -93,17 +143,20 @@ Extent - - + + 6 + + + - Canvas extent + Full extent - - + + - Full extent + Canvas extent @@ -129,32 +182,59 @@ + + + 0 + 0 + + Zoom - - + + 9 + + + 6 + + + + + margin-left:50 + - Minimum zoom + Maximum zoom + + + 0 + 0 + + 40 - - + + + + + 0 + 0 + + - Maximum zoom + Minimum zoom - + 0 @@ -167,6 +247,19 @@ + + + + Qt::Horizontal + + + + 40 + 20 + + + + @@ -175,13 +268,16 @@ Parameters - + true - + true + + 6 + @@ -291,20 +387,6 @@ - - - - - PNG - - - - - JPG - - - - @@ -349,6 +431,20 @@ + + + + + PNG + + + + + JPG + + + + @@ -361,6 +457,12 @@ 0 + + true + + + false +