From 2d3d54471dc4a38b2df85f3d6e9ca7b1a230314d Mon Sep 17 00:00:00 2001 From: Julien Veyssier Date: Mon, 26 Jun 2017 12:53:47 +0200 Subject: [PATCH] refs #29 remove GpsBabel dependency, implement conversions in Php --- CHANGELOG.md | 6 + README.md | 2 +- appinfo/info.xml | 2 +- controller/conversion.php | 325 ++++++++++++++++++++++++++++++++++ controller/pagecontroller.php | 29 +-- 5 files changed, 340 insertions(+), 24 deletions(-) create mode 100644 controller/conversion.php diff --git a/CHANGELOG.md b/CHANGELOG.md index d669647..25daf2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,11 +12,17 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - dynamic URL and page title change after loading file or folder - support for WMS tile and overlay servers. base and user servers [#22](https://gitlab.com/eneiluj/gpxedit-oc/issues/22) @a15n +- add new metadata fields : track name, link url, link text + [#26](https://gitlab.com/eneiluj/gpxedit-oc/issues/26) @manudinovi ### Changed - change way to cut lines, hover the middle marker and press Del [#17](https://gitlab.com/eneiluj/gpxedit-oc/issues/17) @TheTiPi - update moment timezone js +- no more GpsBabel dependency, conversion is now done in Php + [#29](https://gitlab.com/eneiluj/gpxedit-oc/issues/29) @poVoq +- make custom tile server blocks foldable + [#27](https://gitlab.com/eneiluj/gpxedit-oc/issues/27) @a15n ### Fixed - modify cloneLatLng to avoid alt and time loss when L.draw makes layer backups diff --git a/README.md b/README.md index 23cc18b..5d831cb 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ GpxEdit : - allows you to add extra symbols in admin settings (section : additional) - works with server-side encryption. - works with shared files. -- loads GPX, KML, unicsv CSV, geotagged JPG files (requires Gpsbabel to convert files and import pictures) +- loads GPX, KML, unicsv CSV, geotagged JPG files (no more Gpsbabel dependency) - loads tracks, routes and waypoints - saves tracks, routes and waypoints - supports waypoint symbols diff --git a/appinfo/info.xml b/appinfo/info.xml index 634f5e9..3710741 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -42,7 +42,7 @@ GpxEdit : - allows you to add extra symbols in admin settings (section : additional) - works with server-side encryption. - works with shared files. -- loads GPX, KML, unicsv CSV, geotagged JPG files (requires Gpsbabel to convert files and import pictures) +- loads GPX, KML, unicsv CSV, geotagged JPG files (no more Gpsbabel dependency) - loads tracks, routes and waypoints - saves tracks, routes and waypoints - supports waypoint symbols diff --git a/controller/conversion.php b/controller/conversion.php new file mode 100644 index 0000000..188ddb2 --- /dev/null +++ b/controller/conversion.php @@ -0,0 +1,325 @@ + 0 ? exifCoordToNumber($exifCoord[0]) : 0; + $minutes = count($exifCoord) > 1 ? exifCoordToNumber($exifCoord[1]) : 0; + $seconds = count($exifCoord) > 2 ? exifCoordToNumber($exifCoord[2]) : 0; + + $flip = ($hemi === 'W' or $hemi === 'S') ? -1 : 1; + + return $flip * ($degrees + $minutes / 60 + $seconds / 3600); +} + +// parse the coordinate string to calculate the float value +function exifCoordToNumber($coordPart) { + $parts = explode('/', $coordPart); + + if (count($parts) <= 0) + return 0; + + if (count($parts) === 1) + return $parts[0]; + + return floatval($parts[0]) / floatval($parts[1]); +} + +function createDomGpxWithHeaders() { + $dom_gpx = new DOMDocument('1.0', 'UTF-8'); + $dom_gpx->formatOutput = true; + + //root node + $gpx = $dom_gpx->createElement('gpx'); + $gpx = $dom_gpx->appendChild($gpx); + + $gpx_version = $dom_gpx->createAttribute('version'); + $gpx->appendChild($gpx_version); + $gpx_version_text = $dom_gpx->createTextNode('1.0'); + $gpx_version->appendChild($gpx_version_text); + + $gpx_creator = $dom_gpx->createAttribute('creator'); + $gpx->appendChild($gpx_creator); + $gpx_creator_text = $dom_gpx->createTextNode('GpxPod conversion tool'); + $gpx_creator->appendChild($gpx_creator_text); + + $gpx_xmlns_xsi = $dom_gpx->createAttribute('xmlns:xsi'); + $gpx->appendChild($gpx_xmlns_xsi); + $gpx_xmlns_xsi_text = $dom_gpx->createTextNode('http://www.w3.org/2001/XMLSchema-instance'); + $gpx_xmlns_xsi->appendChild($gpx_xmlns_xsi_text); + + $gpx_xmlns = $dom_gpx->createAttribute('xmlns'); + $gpx->appendChild($gpx_xmlns); + $gpx_xmlns_text = $dom_gpx->createTextNode('http://www.topografix.com/GPX/1/0'); + $gpx_xmlns->appendChild($gpx_xmlns_text); + + $gpx_xsi_schemaLocation = $dom_gpx->createAttribute('xsi:schemaLocation'); + $gpx->appendChild($gpx_xsi_schemaLocation); + $gpx_xsi_schemaLocation_text = $dom_gpx->createTextNode('http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd'); + $gpx_xsi_schemaLocation->appendChild($gpx_xsi_schemaLocation_text); + + $gpx_time = $dom_gpx->createElement('time'); + $gpx_time = $gpx->appendChild($gpx_time); + $gpx_time_text = $dom_gpx->createTextNode(utcdate()); + $gpx_time->appendChild($gpx_time_text); + + return $dom_gpx; +} + +function jpgToGpx($jpgFilePath, $fileName) { + $result = ''; + $exif = \exif_read_data($jpgFilePath, 0, true); + if ( isset($exif['GPS']) + and isset($exif['GPS']['GPSLongitude']) + and isset($exif['GPS']['GPSLatitude']) + and isset($exif['GPS']['GPSLatitudeRef']) + and isset($exif['GPS']['GPSLongitudeRef']) + ) { + $lon = getDecimalCoords($exif['GPS']['GPSLongitude'], $exif['GPS']['GPSLongitudeRef']); + $lat = getDecimalCoords($exif['GPS']['GPSLatitude'], $exif['GPS']['GPSLatitudeRef']); + + $dom_gpx = createDomGpxWithHeaders(); + $gpx = $dom_gpx->getElementsByTagName('gpx')->item(0); + + $gpx_wpt = $dom_gpx->createElement('wpt'); + $gpx_wpt = $gpx->appendChild($gpx_wpt); + + $gpx_wpt_lat = $dom_gpx->createAttribute('lat'); + $gpx_wpt->appendChild($gpx_wpt_lat); + $gpx_wpt_lat_text = $dom_gpx->createTextNode($lat); + $gpx_wpt_lat->appendChild($gpx_wpt_lat_text); + + $gpx_wpt_lon = $dom_gpx->createAttribute('lon'); + $gpx_wpt->appendChild($gpx_wpt_lon); + $gpx_wpt_lon_text = $dom_gpx->createTextNode($lon); + $gpx_wpt_lon->appendChild($gpx_wpt_lon_text); + + $gpx_name = $dom_gpx->createElement('name'); + $gpx_name = $gpx_wpt->appendChild($gpx_name); + $gpx_name_text = $dom_gpx->createTextNode($fileName); + $gpx_name->appendChild($gpx_name_text); + + $gpx_symbol = $dom_gpx->createElement('sym'); + $gpx_symbol = $gpx_wpt->appendChild($gpx_symbol); + $gpx_symbol_text = $dom_gpx->createTextNode('Flag, Blue'); + $gpx_symbol->appendChild($gpx_symbol_text); + + $result = $dom_gpx->saveXML(); + } + return $result; +} + +function kmlToGpx($kmlFilePath) { + $kmlcontent = file_get_contents($kmlFilePath); + $dom_kml = new DOMDocument(); + $dom_kml->loadXML($kmlcontent); + + $dom_gpx = createDomGpxWithHeaders(); + $gpx = $dom_gpx->getElementsByTagName('gpx')->item(0); + + // placemarks + $names = array(); + foreach ($dom_kml->getElementsByTagName('Placemark') as $placemark) { + //name + foreach ($placemark->getElementsByTagName('name') as $name) { + $name = $name->nodeValue; + //check if the key exists + if (array_key_exists($name, $names)) { + //increment the value + ++$names[$name]; + $name = $name." ({$names[$name]})"; + } else { + $names[$name] = 0; + } + } + //description + foreach ($placemark->getElementsByTagName('description') as $description) { + $description = $description->nodeValue; + } + foreach ($placemark->getElementsByTagName('Point') as $point) { + foreach ($point->getElementsByTagName('coordinates') as $coordinates) { + //add the marker + $coordinate = $coordinates->nodeValue; + $coordinate = str_replace(" ", "", $coordinate);//trim white space + $latlng = explode(",", $coordinate); + + if (($lat = $latlng[1]) && ($lng = $latlng[0])) { + $gpx_wpt = $dom_gpx->createElement('wpt'); + $gpx_wpt = $gpx->appendChild($gpx_wpt); + + $gpx_wpt_lat = $dom_gpx->createAttribute('lat'); + $gpx_wpt->appendChild($gpx_wpt_lat); + $gpx_wpt_lat_text = $dom_gpx->createTextNode($lat); + $gpx_wpt_lat->appendChild($gpx_wpt_lat_text); + + $gpx_wpt_lon = $dom_gpx->createAttribute('lon'); + $gpx_wpt->appendChild($gpx_wpt_lon); + $gpx_wpt_lon_text = $dom_gpx->createTextNode($lng); + $gpx_wpt_lon->appendChild($gpx_wpt_lon_text); + + $gpx_time = $dom_gpx->createElement('time'); + $gpx_time = $gpx_wpt->appendChild($gpx_time); + $gpx_time_text = $dom_gpx->createTextNode(utcdate()); + $gpx_time->appendChild($gpx_time_text); + + $gpx_name = $dom_gpx->createElement('name'); + $gpx_name = $gpx_wpt->appendChild($gpx_name); + $gpx_name_text = $dom_gpx->createTextNode($name); + $gpx_name->appendChild($gpx_name_text); + + $gpx_desc = $dom_gpx->createElement('desc'); + $gpx_desc = $gpx_wpt->appendChild($gpx_desc); + $gpx_desc_text = $dom_gpx->createTextNode($description); + $gpx_desc->appendChild($gpx_desc_text); + + $gpx_sym = $dom_gpx->createElement('sym'); + $gpx_sym = $gpx_wpt->appendChild($gpx_sym); + $gpx_sym_text = $dom_gpx->createTextNode('Waypoint'); + $gpx_sym->appendChild($gpx_sym_text); + } + } + } + foreach ($placemark->getElementsByTagName('Polygon') as $lineString) { + $outbounds = $lineString->getElementsByTagName('outerBoundaryIs'); + foreach ($outbounds as $outbound) { + foreach ($outbound->getElementsByTagName('coordinates') as $coordinates) { + //add the new track + $gpx_trk = $dom_gpx->createElement('trk'); + $gpx_trk = $gpx->appendChild($gpx_trk); + + $gpx_name = $dom_gpx->createElement('name'); + $gpx_name = $gpx_trk->appendChild($gpx_name); + $gpx_name_text = $dom_gpx->createTextNode($name); + $gpx_name->appendChild($gpx_name_text); + + $gpx_trkseg = $dom_gpx->createElement('trkseg'); + $gpx_trkseg = $gpx_trk->appendChild($gpx_trkseg); + + $coordinates = trim($coordinates->nodeValue); + $coordinates = preg_split("/[\s\r\n]+/", $coordinates); //split the coords by new line + foreach ($coordinates as $coordinate) { + $latlng = explode(",", $coordinate); + + if (($lat = $latlng[1]) && ($lng = $latlng[0])) { + $gpx_trkpt = $dom_gpx->createElement('trkpt'); + $gpx_trkpt = $gpx_trkseg->appendChild($gpx_trkpt); + + $gpx_trkpt_lat = $dom_gpx->createAttribute('lat'); + $gpx_trkpt->appendChild($gpx_trkpt_lat); + $gpx_trkpt_lat_text = $dom_gpx->createTextNode($lat); + $gpx_trkpt_lat->appendChild($gpx_trkpt_lat_text); + + $gpx_trkpt_lon = $dom_gpx->createAttribute('lon'); + $gpx_trkpt->appendChild($gpx_trkpt_lon); + $gpx_trkpt_lon_text = $dom_gpx->createTextNode($lng); + $gpx_trkpt_lon->appendChild($gpx_trkpt_lon_text); + + $gpx_time = $dom_gpx->createElement('time'); + $gpx_time = $gpx_trkpt->appendChild($gpx_time); + $gpx_time_text = $dom_gpx->createTextNode(utcdate()); + $gpx_time->appendChild($gpx_time_text); + } + } + } + } + } + foreach ($placemark->getElementsByTagName('LineString') as $lineString) { + foreach ($lineString->getElementsByTagName('coordinates') as $coordinates) { + //add the new track + $gpx_trk = $dom_gpx->createElement('trk'); + $gpx_trk = $gpx->appendChild($gpx_trk); + + $gpx_name = $dom_gpx->createElement('name'); + $gpx_name = $gpx_trk->appendChild($gpx_name); + $gpx_name_text = $dom_gpx->createTextNode($name); + $gpx_name->appendChild($gpx_name_text); + + $gpx_trkseg = $dom_gpx->createElement('trkseg'); + $gpx_trkseg = $gpx_trk->appendChild($gpx_trkseg); + + $coordinates = trim($coordinates->nodeValue); + $coordinates = preg_split("/[\s\r\n]+/", $coordinates); //split the coords by new line + foreach ($coordinates as $coordinate) { + //echo 'NAME :'.$gpx_name_text->nodeValue.' AA "'.$coordinate."\" ZZ\n"; + $latlng = explode(",", $coordinate); + + if (($lat = $latlng[1]) && ($lng = $latlng[0])) { + $gpx_trkpt = $dom_gpx->createElement('trkpt'); + $gpx_trkpt = $gpx_trkseg->appendChild($gpx_trkpt); + + $gpx_trkpt_lat = $dom_gpx->createAttribute('lat'); + $gpx_trkpt->appendChild($gpx_trkpt_lat); + $gpx_trkpt_lat_text = $dom_gpx->createTextNode($lat); + $gpx_trkpt_lat->appendChild($gpx_trkpt_lat_text); + + $gpx_trkpt_lon = $dom_gpx->createAttribute('lon'); + $gpx_trkpt->appendChild($gpx_trkpt_lon); + $gpx_trkpt_lon_text = $dom_gpx->createTextNode($lng); + $gpx_trkpt_lon->appendChild($gpx_trkpt_lon_text); + + $gpx_time = $dom_gpx->createElement('time'); + $gpx_time = $gpx_trkpt->appendChild($gpx_time); + $gpx_time_text = $dom_gpx->createTextNode(utcdate()); + $gpx_time->appendChild($gpx_time_text); + } + } + } + } + } + + return $dom_gpx->saveXML(); +} + +function unicsvToGpx($csvFilePath) { + $result = ''; + $dom_gpx = createDomGpxWithHeaders(); + $gpx = $dom_gpx->getElementsByTagName('gpx')->item(0); + + $csv = array_map('str_getcsv', file($csvFilePath, FILE_SKIP_EMPTY_LINES)); + $keys = array_shift($csv); + + foreach ($csv as $i=>$row) { + $csv[$i] = array_combine($keys, $row); + } + + foreach ($csv as $line) { + $lat = $line['Latitude']; + $lon = $line['Longitude']; + + $gpx_wpt = $dom_gpx->createElement('wpt'); + $gpx_wpt = $gpx->appendChild($gpx_wpt); + + $gpx_wpt_lat = $dom_gpx->createAttribute('lat'); + $gpx_wpt->appendChild($gpx_wpt_lat); + $gpx_wpt_lat_text = $dom_gpx->createTextNode($lat); + $gpx_wpt_lat->appendChild($gpx_wpt_lat_text); + + $gpx_wpt_lon = $dom_gpx->createAttribute('lon'); + $gpx_wpt->appendChild($gpx_wpt_lon); + $gpx_wpt_lon_text = $dom_gpx->createTextNode($lon); + $gpx_wpt_lon->appendChild($gpx_wpt_lon_text); + + if (array_key_exists('Symbol', $line)) { + $gpx_symbol = $dom_gpx->createElement('sym'); + $gpx_symbol = $gpx_wpt->appendChild($gpx_symbol); + $gpx_symbol_text = $dom_gpx->createTextNode($line['Symbol']); + $gpx_symbol->appendChild($gpx_symbol_text); + } + if (array_key_exists('Name', $line)) { + $gpx_name = $dom_gpx->createElement('name'); + $gpx_name = $gpx_wpt->appendChild($gpx_name); + $gpx_name_text = $dom_gpx->createTextNode($line['Name']); + $gpx_name->appendChild($gpx_name_text); + } + + } + $result = $dom_gpx->saveXML(); + + return $result; +} + +?> diff --git a/controller/pagecontroller.php b/controller/pagecontroller.php index efdc205..b3ca2db 100644 --- a/controller/pagecontroller.php +++ b/controller/pagecontroller.php @@ -27,6 +27,8 @@ use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\Http\Response; use OCP\AppFramework\Controller; +require_once('conversion.php'); + function delTree($dir) { $files = array_diff(scandir($dir), array('.','..')); foreach ($files as $file) { @@ -184,6 +186,7 @@ class PageController extends Controller { * convert the given file (csv or kml) to gpx and return its content */ private function toGpx($file){ + $gpxContent = ''; $gpsbabel_path = getProgramPath('gpsbabel'); $data_folder = $this->userAbsoluteDataPath; $tempdir = $data_folder.'/../cache/'.rand(); @@ -192,39 +195,21 @@ class PageController extends Controller { $filename = $file->getName(); $filecontent = $file->getContent(); $file_clear_path = $tempdir.'/'.$filename; - $gpx_target_clear_path = $tempdir.'/'.$filename.'.gpx'; file_put_contents($file_clear_path, $filecontent); if (endswith($file->getName(), '.KML') or endswith($file->getName(), '.kml')){ - $fmt = 'kml'; + $gpxContent = kmlToGpx($file_clear_path); } else if (endswith($file->getName(), '.csv') or endswith($file->getName(), '.CSV')){ - $fmt = 'unicsv'; + $gpxContent = unicsvToGpx($file_clear_path); } else if (endswith($file->getName(), '.jpg') or endswith($file->getName(), '.JPG')){ - $fmt = 'exif'; - } - $args = Array('-i', $fmt, '-f', $file_clear_path, '-o', - 'gpx', '-F', $gpx_target_clear_path); - $cmdparams = ''; - foreach($args as $arg){ - $shella = escapeshellarg($arg); - $cmdparams .= " $shella"; - } - exec( - $gpsbabel_path.' '.$cmdparams, - $output, $returnvar - ); - if (file_exists($gpx_target_clear_path)){ - $gpx_clear_content = file_get_contents($gpx_target_clear_path); - } - else{ - $gpx_clear_content = ''; + $gpxContent = jpgToGpx($file_clear_path, $filename); } delTree($tempdir); - return $gpx_clear_content; + return $gpxContent; } /**