diff --git a/ImportPhotos.py b/ImportPhotos.py index 5312511..1e1405b 100644 --- a/ImportPhotos.py +++ b/ImportPhotos.py @@ -213,18 +213,28 @@ def initGui(self): self.toolMouseClick = MouseClick(self.canvas, self) self.fields = ['ID', 'Name', 'Date', 'Time', 'Lon', 'Lat', 'Altitude', 'North', 'Azimuth', 'Camera Maker', - 'Camera Model', 'Path'] + 'Camera Model', 'Path', 'RelPath', 'Timestamp'] self.extension_switch = { + "ESRI Shapefile (*.shp *.SHP)": ".shp", + "GeoJSON (*.geojson *.GEOJSON)": ".geojson", + "GeoPackage (*.gpkg *.GPKG)":".gpkg", + "Comma Separated Value (*.csv *.CSV)": ".csv", + "Keyhole Markup Language (*.kml *.KML)": ".kml", + "Mapinfo TAB (*.tab *.TAB)": ".tab" + } + + self.extension_switch_types = { ".shp": "ESRI Shapefile", ".geojson": "GeoJSON", ".gpkg":"GPKG", ".csv": "CSV", ".kml": "KML", - ".tab": "MapInfo File", - ".ods": "ODS" + ".tab": "MapInfo File" } + self.all_extensions = [".shp", ".geojson", ".gpkg", ".csv", ".kml", ".tab"] + def mouseClick(self): try: self.iface.setActiveLayer(self.canvas.layers()[0]) @@ -257,7 +267,8 @@ def close(self): self.dlg.close() def toolButtonOut(self): - typefiles = 'ESRI Shapefile (*.shp *.SHP);; GeoJSON (*.geojson *.GEOJSON);; GeoPackage (*.gpkg *.GPKG);; Comma Separated Value (*.csv *.CSV);; Keyhole Markup Language (*.kml *.KML);; Mapinfo TAB (*.tab *.TAB);; Open Document Spreadsheet (*.ods *.ODS)' + typefiles = 'ESRI Shapefile (*.shp *.SHP);; GeoJSON (*.geojson *.GEOJSON);; GeoPackage (*.gpkg *.GPKG);; Comma Separated Value (*.csv *.CSV);; Keyhole Markup Language (*.kml *.KML);; Mapinfo TAB (*.tab *.TAB)' + if platform.system() == 'Linux': try: self.outputPath, self.extension = QFileDialog.getSaveFileNameAndFilter(None, 'Save File', os.path.join( @@ -272,13 +283,25 @@ def toolButtonOut(self): os.path.join(os.path.expanduser('~')), 'Desktop'), typefiles) + self.extension_type = self.outputPath[1] self.outputPath = self.outputPath[0] + if self.extension_type: + self.extension = self.extension_switch[self.extension_type] + self.dlg.out.setText(self.outputPath) def toolButtonImport(self): self.directoryPhotos = QFileDialog.getExistingDirectory(None, 'Select a folder:', os.path.join(os.path.join(os.path.expanduser('~')), 'Desktop'), QFileDialog.ShowDirsOnly) + self.selected_folder = self.directoryPhotos; p = '/' + if '/' in self.directoryPhotos: + self.selected_folder = self.directoryPhotos.split('/')[-1]; p = '/' + if '\\' in self.directoryPhotos: + self.selected_folder = self.directoryPhotos.split('\\')[-1]; p = '\\' + if '//' in self.directoryPhotos: + self.selected_folder = self.directoryPhotos.split('//')[-1]; p = '//' + self.selected_folder = './' + self.selected_folder + p self.dlg.imp.setText(self.directoryPhotos) def selectDir(self): @@ -313,18 +336,19 @@ def ok(self): if self.selectOutp(): return - if platform.system() == 'Linux': - self.lphoto = os.path.basename(self.outputPath) - try: - self.extension = '.'+self.extension.split()[-1][2:-1].lower() - except: - self.extension = '.shp' #hack line, temporary + tmpname = os.path.basename(self.outputPath) + self.lphoto = os.path.splitext(tmpname)[0] + + isin = False + for ext in self.all_extensions: + if ext in self.outputPath: + isin = True + + if not isin: + self.outputPath = self.dlg.out.text() + self.extension else: - _ , self.extension = os.path.splitext(self.outputPath) - basename = os.path.basename(self.outputPath) - self.lphoto = basename[:-len(self.extension)] + self.outputPath = self.dlg.out.text() - self.outputPath = self.dlg.out.text() self.directoryPhotos = self.dlg.imp.text() self.outDirectoryPhotosGeoJSON = self.plugin_dir + '/tmp.geojson' @@ -337,7 +361,7 @@ def ok(self): extens = ['jpg', 'jpeg', 'JPG', 'JPEG'] self.photos = [] for root, dirs, files in os.walk(self.directoryPhotos): - self.photos.extend(os.path.join(root, name) for name in files + self.photos.extend(name for name in files if name.lower().endswith(tuple(extens))) self.initphotos = len(self.photos) @@ -363,19 +387,13 @@ def ok(self): else: self.layernamePhotos.append(self.lphoto) - if platform.system() == 'Linux': - self.outputPath = self.outputPath + self.extension - self.extension = self.extension_switch[self.extension] - else: - self.extension = self.extension_switch[self.extension.lower()] - self.exifread_module = False self.pil_module = False if CHECK_MODULE == '': self.showMessage('Python Modules', 'Please install python module "exifread" or "PIL".' , 'Warning') - #self.import_photos_task('', '') + #self.import_photos_task('','') self.call_import_photos() self.dlg.close() @@ -420,8 +438,9 @@ def completed(self, exception, result=None): self.layerPhotos = QgsVectorLayer(self.outDirectoryPhotosGeoJSON, self.lphoto, "ogr") QgsVectorFileWriter.writeAsVectorFormat(self.layerPhotos, self.outputPath, "utf-8", - QgsCoordinateReferenceSystem(self.layerPhotos.crs().authid()), - self.extension) + QgsCoordinateReferenceSystem(self.layerPhotos.crs().authid()), + self.extension_switch_types[self.extension]) + self.layerPhotos_final = QgsVectorLayer(self.outputPath, self.lphoto, "ogr") # clear temp.geojson file @@ -475,9 +494,10 @@ def completed(self, exception, result=None): int(noLocationPhotosCounter)) + ' photo(s) skipped (because of missing location).' self.showMessage(title, msg, 'Information') - self.Qpr_inst.addMapLayers([self.layerPhotos_final]) - - self.taskPhotos.destroyed() + g = self.Qpr_inst.layerTreeRoot().insertGroup(0, self.lphoto) + self.Qpr_inst.addMapLayer(self.layerPhotos_final, False) + nn = QgsLayerTreeLayer(self.layerPhotos_final) + g.insertChildNode(0, nn) def stopped(self, task): QgsMessageLog.logMessage( @@ -489,13 +509,15 @@ def import_photos_task(self, task, wait_time): self.geoPhotos = [] self.lon = [] self.lat = [] - for count, imgpath in enumerate(self.photos): + for count, name_img in enumerate(self.photos): try: - name = os.path.basename(imgpath) + RelPath = self.selected_folder + name_img + original_path = self.directoryPhotos + '\\' + name_img + name = os.path.basename(original_path) if CHECK_MODULE == 'exifread' and not self.pil_module: self.exifread_module = True self.taskPhotos.setProgress(count/self.initphotos) - with open(imgpath, 'rb') as imgpathF: + with open(original_path, 'rb') as imgpathF: tags = exifread.process_file(imgpathF, details=False) if not tags.keys() & {"GPS GPSLongitude", "GPS GPSLatitude"}: continue @@ -543,7 +565,7 @@ def import_photos_task(self, task, wait_time): if CHECK_MODULE == 'PIL' and not self.exifread_module: self.pil_module = True a = {} - info = Image.open(imgpath) + info = Image.open(original_path) info = info._getexif() if info == None: @@ -610,7 +632,7 @@ def import_photos_task(self, task, wait_time): 'Lon': lon, 'Lat': lat, 'Altitude': altitude, 'North': north, 'Azimuth': azimuth, - 'Camera Maker': str(maker), 'Camera Model': str(model), 'Path': imgpath, + 'Camera Maker': str(maker), 'Camera Model': str(model), 'Path': original_path, 'RelPath': RelPath, 'Timestamp': timestamp}, "geometry": {"coordinates": [lon, lat], "type": "Point"}} self.geoPhotos.append(geo_info) diff --git a/MouseClick.py b/MouseClick.py index 44cdec7..efd10ad 100644 --- a/MouseClick.py +++ b/MouseClick.py @@ -23,7 +23,7 @@ from qgis.PyQt.QtWidgets import * from qgis.PyQt.QtGui import * from qgis.PyQt.QtCore import * -from qgis.core import QgsRectangle +from qgis.core import QgsRectangle, QgsProject from qgis.gui import QgsMapTool, QgsRubberBand from .PhotosViewer import PhotoWindow import os @@ -93,9 +93,14 @@ def canvasDoubleClickEvent(self, event): return try: - if os.path.exists(imPath) == False: - c = self.drawSelf.noImageFound() - if c: return + if not os.path.exists(imPath): + prj = QgsProject.instance() + if prj.fileName(): + imPath = QFileInfo(prj.fileName()).absolutePath() + \ + feature.attributes()[feature.fieldNameIndex('RelPath')] + else: + c = self.drawSelf.noImageFound() + if c: return except: c = self.drawSelf.noImageFound() if c: return diff --git a/PhotosViewer.py b/PhotosViewer.py index a3dc8e2..4c24298 100644 --- a/PhotosViewer.py +++ b/PhotosViewer.py @@ -22,8 +22,9 @@ """ from PyQt5.QtWidgets import (QGraphicsView, QGraphicsScene, QVBoxLayout, QHBoxLayout, QWidget, \ QLineEdit, QLabel, QSizePolicy, QPushButton, QFrame) -from PyQt5.QtCore import (Qt, pyqtSignal, QRectF, QRect, QSize) +from PyQt5.QtCore import (Qt, pyqtSignal, QRectF, QRect, QSize, QFileInfo) from PyQt5.QtGui import (QPainterPath, QIcon, QPixmap, QImage) +from qgis.core import QgsProject import os.path @@ -50,7 +51,7 @@ def __init__(self, selfwindow): self.leftClick.setIcon(QIcon(self.selfwindow.path+'//svg//arrowLeft.png')) self.leftClick.clicked.connect(self.selfwindow.leftClickButton) self.leftClick.setToolTip('Show previous photo') - self.leftClick.setStyleSheet("QPushButton{background: transparent;}") + self.leftClick.setStyleSheet("QPushButton{border: 0px;}") self.leftClick.setIconSize(QSize(size, size)) self.leftClick.setFocusPolicy(Qt.NoFocus) @@ -58,7 +59,7 @@ def __init__(self, selfwindow): self.rightClick.setIcon(QIcon(self.selfwindow.path+'//svg//arrowRight.png')) self.rightClick.clicked.connect(self.selfwindow.rightClickButton) self.rightClick.setToolTip('Show next photo') - self.rightClick.setStyleSheet("QPushButton{background: transparent;}") + self.rightClick.setStyleSheet("QPushButton{border: 0px;}") self.rightClick.setIconSize(QSize(size, size)) self.rightClick.setFocusPolicy(Qt.NoFocus) @@ -185,6 +186,12 @@ def __init__(self, drawSelf): except: timeTrue = str(f.attributes()[f.fieldNameIndex('Time')]) + if not os.path.exists(imPath): + prj = QgsProject.instance() + if prj.fileName(): + imPath = QFileInfo(prj.fileName()).absolutePath() + \ + f.attributes()[f.fieldNameIndex('RelPath')] + azimuth = f.attributes()[f.fieldNameIndex('Azimuth')] self.allpictures.append(f.attributes()[f.fieldNameIndex('Name')]) self.allpicturesdates.append(dateTrue) @@ -380,4 +387,4 @@ def extentbutton(self): self.viewer.panSelect = False self.viewer.zoomSelect = False self.viewer.setCursor(Qt.ArrowCursor) - self.viewer.setDragMode(QGraphicsView.NoDrag) \ No newline at end of file + self.viewer.setDragMode(QGraphicsView.NoDrag) diff --git a/metadata.txt b/metadata.txt index 0a7cb56..8cd4329 100644 --- a/metadata.txt +++ b/metadata.txt @@ -11,11 +11,11 @@ name=ImportPhotos qgisMinimumVersion=2.99 qgisMaximumVersion=3.99 description=Import Photos -version=1.8 +version=1.9 author=Marios S. Kyriakou, George A. Christou, Panayiotis S. Kolios, KIOS Research and Innovation Center of Excellence (KIOS CoE) email=mariosmsk@gmail.com, george.a.christou@gmail.com, panayiotis.kolios@gmail.com -about= This tool can be used to import Geo-Tagged photos (jpg or jpeg) as points to QGIS. The user is able to select a folder with photos and only the geo-tagged photos will be taken. Then a geoJSON point file will be created which will contain the name of the picture, its directory, the date and time taken, altitude, longitude, latitude, azimuth, north and camera maker and model. The plug-in doesn’t need any third party applications to work. It has two buttons; the one is to import geotagged photos, and the other one is to be able to click on a point and display the photo along with information regarding the date time and altitude. Supported GeoJSON, SHP, GPKG, CSV, KML, TAB, ODS type of files. Mac users please refer to the Read Me file for further guidance. +about= This tool can be used to import Geo-Tagged photos (jpg or jpeg) as points to QGIS. The user is able to select a folder with photos and only the geo-tagged photos will be taken. Then a layer will be created which it will contain the name of the picture, its directory, the date and time taken, altitude, longitude, latitude, azimuth, north, camera maker and model and relative path. The plug-in doesn’t need any third party applications to work. It has two buttons; the one is to import geotagged photos, and the other one is to be able to click on a point and display the photo along with information regarding the date time and altitude. The user can create one of the following file types: GeoJSON, SHP, GPKG, CSV, KML, TAB. When the user saves a project and wants to reopen it, the folder with the pictures should stay at the original file location or moved at the same location of the project (e.g. *.qgz) in order to be able to view the pictures. Mac users please refer to the Read Me file for further guidance. tracker=https://github.com/KIOS-Research/ImportPhotos/issues/ repository=https://github.com/KIOS-Research/ImportPhotos/ @@ -23,7 +23,12 @@ repository=https://github.com/KIOS-Research/ImportPhotos/ # Recommended items: # Uncomment the following line and add your changelog: -changelog=2018-11-28 ImportPhotos 1.8: +changelog=2019-01-25 ImportPhotos 1.9: + Add group with layer + Fix issue in right/left transparent + Fix issue with python key error + Remove ods + 2018-11-28 ImportPhotos 1.8: Drop update for qgis 2 Add QgsTask for the ImportPhotos Change main ui file