Compare commits
18 Commits
Author | SHA1 | Date |
---|---|---|
Rémi BERTHO | e3537e148b | |
Rémi BERTHO | 440d4bd83a | |
Rémi BERTHO | 90d0eacca6 | |
Rémi BERTHO | 1681188214 | |
Rémi BERTHO | 68860aad80 | |
Rémi BERTHO | d1fe41cbee | |
Rémi BERTHO | b6b1b8eeed | |
Rémi BERTHO | 3f366c4e31 | |
Rémi BERTHO | f481105fd9 | |
Rémi BERTHO | bda259cf14 | |
Rémi BERTHO | 4c598da07a | |
Rémi BERTHO | 83fa2c6864 | |
Rémi BERTHO | f389faef03 | |
Rémi BERTHO | 80e2e6da9e | |
Rémi BERTHO | ad8eca522f | |
Rémi BERTHO | ac4bd3c0e2 | |
Rémi BERTHO | 3558d2b34e | |
Rémi BERTHO | dfcbd9cecf |
|
@ -1,99 +1,3 @@
|
|||
# ---> Python
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
env/
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
#*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*,cover
|
||||
.hypothesis/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# celery beat schedule file
|
||||
celerybeat-schedule
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# dotenv
|
||||
.env
|
||||
|
||||
# virtualenv
|
||||
.venv
|
||||
venv/
|
||||
ENV/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# Images
|
||||
*.jpg
|
||||
*.jpeg
|
||||
|
@ -102,3 +6,25 @@ ENV/
|
|||
# Others
|
||||
*.db
|
||||
*.db:encryptable
|
||||
|
||||
# ---> Rust
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
debug/
|
||||
target/
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
|
||||
# MSVC Windows builds of rustc generate these, which store debugging information
|
||||
*.pdb
|
||||
|
||||
# IDE
|
||||
.idea
|
||||
|
||||
# Git
|
||||
.git
|
||||
|
||||
# Dist
|
||||
/dist
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,18 @@
|
|||
[package]
|
||||
name = "simple_panorama_viewer"
|
||||
version = "2.0.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
log = "0.4"
|
||||
simplelog = "0.12"
|
||||
wry = "0.34"
|
||||
native-dialog = "0.7"
|
||||
rust-embed = "8"
|
||||
directories = "5"
|
||||
clap = "4"
|
||||
warp = "0.3"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
portpicker = "0.1"
|
||||
rand = "0.8"
|
|
@ -0,0 +1,24 @@
|
|||
#!/usr/bin/env -S just --justfile
|
||||
set windows-shell := ["powershell.exe", "-NoLogo", "-Command"]
|
||||
|
||||
alias b := build
|
||||
|
||||
build:
|
||||
cargo build
|
||||
|
||||
dist_linux:
|
||||
rm -Rf ./dist
|
||||
mkdir dist
|
||||
cargo build --release
|
||||
smc bin_linux files
|
||||
smc sources
|
||||
|
||||
dist_win:
|
||||
coreutils rm -Rf ./dist
|
||||
coreutils mkdir dist
|
||||
cargo build --release
|
||||
smc bin_win files
|
||||
smc sources
|
||||
pandoc -i LICENSE.md -s -o LICENSE.rtf
|
||||
Start-Process -FilePath "C:\Program Files (x86)\Inno Setup 6\compil32.exe" -ArgumentList "/cc", "win-setup.iss" -Wait
|
||||
Start-Process -WorkingDirectory dist coreutils -ArgumentList sha512sum, -b, "SimplePanoramaViewer-2.0.0-x86_64-pc-windows-msvc-setup.exe" -RedirectStandardOutput "dist/SimplePanoramaViewer-2.0.0-x86_64-pc-windows-msvc-setup.exe.sha512sum"
|
|
@ -1,7 +1,7 @@
|
|||
The MIT License (MIT)
|
||||
=====================
|
||||
|
||||
Copyright © 2018 Rémi BERTHO
|
||||
Copyright © 2018-2022 Rémi BERTHO
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
# SimplePanoramaViewer
|
||||
|
||||
This is a simple panorama viewer based on [Photo Sphere Viewer](http://photo-sphere-viewer.js.org) which is based on [Three.js](https://threejs.org/), [D.js](https://malko.github.io/D.js/), [uEvenet](https://github.com/mistic100/uEvent) and [doT.js](https://olado.github.io/doT/).
|
||||
This is a simple panorama viewer based on [Photo Sphere Viewer](http://photo-sphere-viewer.js.org) which is based on [Three.js](https://threejs.org/).
|
|
@ -1,49 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import sys
|
||||
from os import path
|
||||
from pathlib import Path
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
from PyQt5.QtCore import *
|
||||
from PyQt5.QtGui import *
|
||||
from PyQt5.QtWidgets import *
|
||||
from PyQt5.QtWebEngine import *
|
||||
from PyQt5.QtWebEngineWidgets import *
|
||||
|
||||
app = QApplication(sys.argv)
|
||||
app.setApplicationName("SimplePanoramaViewer")
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
img_dialog = QFileDialog.getOpenFileName(None, "Open image", str(Path.home()), "JPG Images (*.jpg *.JPG *.jpeg *.pjpeg *.pjpg *.PJPG)")
|
||||
img = img_dialog[0]
|
||||
else:
|
||||
img = path.abspath(sys.argv[1])
|
||||
|
||||
if img == "":
|
||||
exit(0)
|
||||
|
||||
img = img.replace("\\", "/")
|
||||
img = img.replace("'", "\\'")
|
||||
|
||||
if getattr( sys, 'frozen', False ) :
|
||||
exe_dir = path.realpath(sys._MEIPASS)
|
||||
else :
|
||||
exe_dir = path.dirname(path.realpath(__file__))
|
||||
os.chdir(exe_dir)
|
||||
|
||||
try:
|
||||
with open("html/index.html", "r", encoding="utf8") as file:
|
||||
html = file.read()
|
||||
except OSError as exception:
|
||||
print("Error: HTML file not found: " + str(exception))
|
||||
html = html.replace("__IMG_PATH__", img)
|
||||
|
||||
web = QWebEngineView()
|
||||
url = QUrl.fromLocalFile(exe_dir + "/index.html")
|
||||
web.setHtml(html,url)
|
||||
web.setWindowTitle(img)
|
||||
web.showMaximized()
|
||||
web.show()
|
||||
|
||||
sys.exit(app.exec_())
|
|
@ -1,39 +0,0 @@
|
|||
# -*- mode: python -*-
|
||||
|
||||
block_cipher = None
|
||||
|
||||
added_files = [
|
||||
( 'README.md', '.' ),
|
||||
( 'LICENSE.md', '.' ),
|
||||
( 'css', 'css' ),
|
||||
( 'html', 'html' ),
|
||||
( 'js', 'js' )
|
||||
]
|
||||
|
||||
a = Analysis(['SimplePanoramaViewer'],
|
||||
pathex=['./SimplePanoramaViewer'],
|
||||
binaries=[],
|
||||
datas=added_files,
|
||||
hiddenimports=[],
|
||||
hookspath=[],
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
win_no_prefer_redirects=False,
|
||||
win_private_assemblies=False,
|
||||
cipher=block_cipher,
|
||||
noarchive=False)
|
||||
pyz = PYZ(a.pure, a.zipped_data,
|
||||
cipher=block_cipher)
|
||||
exe = EXE(pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.zipfiles,
|
||||
a.datas,
|
||||
[],
|
||||
name='SimplePanoramaViewer',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
runtime_tmpdir=None,
|
||||
console=False )
|
|
@ -1,43 +0,0 @@
|
|||
# -*- mode: python -*-
|
||||
|
||||
block_cipher = None
|
||||
|
||||
added_files = [
|
||||
( 'README.md', '.' ),
|
||||
( 'LICENSE.md', '.' ),
|
||||
( 'css', 'css' ),
|
||||
( 'html', 'html' ),
|
||||
( 'js', 'js' )
|
||||
]
|
||||
|
||||
a = Analysis(['SimplePanoramaViewer'],
|
||||
pathex=['./SimplePanoramaViewer'],
|
||||
binaries=[],
|
||||
datas=added_files,
|
||||
hiddenimports=[],
|
||||
hookspath=[],
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
win_no_prefer_redirects=False,
|
||||
win_private_assemblies=False,
|
||||
cipher=block_cipher,
|
||||
noarchive=False)
|
||||
pyz = PYZ(a.pure, a.zipped_data,
|
||||
cipher=block_cipher)
|
||||
exe = EXE(pyz,
|
||||
a.scripts,
|
||||
[],
|
||||
exclude_binaries=True,
|
||||
name='SimplePanoramaViewer',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
console=False )
|
||||
coll = COLLECT(exe,
|
||||
a.binaries,
|
||||
a.zipfiles,
|
||||
a.datas,
|
||||
strip=False,
|
||||
upx=True,
|
||||
name='SimplePanoramaViewer')
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,43 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Panorama viewer</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<link rel="stylesheet" href="css/photo-sphere-viewer.min.css">
|
||||
|
||||
<style>
|
||||
html, body {
|
||||
width: 100%; height: 100%; overflow: hidden; margin: 0; padding:
|
||||
0;
|
||||
}
|
||||
|
||||
#photosphere {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<!-- the viewer container must have a defined size -->
|
||||
<div id="photosphere" style="width: 100vw; height: 100vh;"></div>
|
||||
|
||||
<script src="js/three.min.js"></script>
|
||||
<script src="js/photo-sphere-viewer-core.min.js"></script>
|
||||
|
||||
<script>
|
||||
var PSV = new PhotoSphereViewer.Viewer({
|
||||
container: 'photosphere',
|
||||
panorama: 'img',
|
||||
caption: 'Panorama displayed with Photo Sphere Viewer V5.5.0',
|
||||
defaultZoomLvl: 40,
|
||||
minFov: 5,
|
||||
maxFov: 75,
|
||||
navbar: [
|
||||
'zoom',
|
||||
'caption'
|
||||
]
|
||||
});
|
||||
</script>
|
||||
</html>
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
20
generate.ps1
20
generate.ps1
|
@ -1,20 +0,0 @@
|
|||
$version="1.1"
|
||||
|
||||
if (Test-Path dist\"SimplePanoramaViewer-$version-win64.exe")
|
||||
{
|
||||
Remove-Item dist\"SimplePanoramaViewer-$version-win64.exe" -Force -Recurse
|
||||
}
|
||||
if (Test-Path dist\SimplePanoramaViewer)
|
||||
{
|
||||
Remove-Item dist\SimplePanoramaViewer -Force -Recurse
|
||||
}
|
||||
|
||||
pandoc -i LICENSE.md -s -o LICENSE.rtf
|
||||
pyinstaller SimplePanoramaViewer_folder.spec
|
||||
Start-Process -FilePath "C:\Program Files (x86)\Inno Setup 6\compil32.exe" -ArgumentList "/cc", "win-setup.iss" -Wait
|
||||
Remove-Item dist\SimplePanoramaViewer -Force -Recurse
|
||||
Get-FileHash "dist/SimplePanoramaViewer-$version-win64-setup.exe" -Algorithm SHA512 | Select-Object -ExpandProperty Hash | Out-File "dist/SimplePanoramaViewer-$version-win64-setup.exe.sha512sum"
|
||||
|
||||
pyinstaller SimplePanoramaViewer_file.spec
|
||||
Rename-Item -Path "dist\SimplePanoramaViewer.exe" -NewName "SimplePanoramaViewer-$version-win64.exe"
|
||||
Get-FileHash "dist/SimplePanoramaViewer-$version-win64.exe" -Algorithm SHA512 | Select-Object -ExpandProperty Hash | Out-File "dist/SimplePanoramaViewer-$version-win64.exe.sha512sum"
|
|
@ -1,66 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Panorama viewer</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<link rel="stylesheet" href="css/photo-sphere-viewer.min.css">
|
||||
|
||||
<style>
|
||||
html, body {
|
||||
width: 100%; height: 100%; overflow: hidden; margin: 0; padding:
|
||||
0;
|
||||
}
|
||||
|
||||
#photosphere {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.psv-button.custom-button {
|
||||
font-size: 22px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.demo-label {
|
||||
color: white;
|
||||
font-size: 20px;
|
||||
font-family: Helvetica, sans-serif;
|
||||
text-align: center;
|
||||
padding: 5px;
|
||||
border: 1px solid white;
|
||||
background: rgba(0,0,0,0.4);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="photosphere"></div>
|
||||
|
||||
<script src="js/three.min.js"></script>
|
||||
<script src="js/D.min.js"></script>
|
||||
<script src="js/uevent.min.js"></script>
|
||||
<script src="js/doT.min.js"></script>
|
||||
<script src="js/photo-sphere-viewer.min.js"></script>
|
||||
|
||||
<h1>Panorama</h1>>
|
||||
<script>
|
||||
var PSV = new PhotoSphereViewer({
|
||||
container: 'photosphere',
|
||||
panorama: '__IMG_PATH__',
|
||||
caption: 'Panorama displayed with Photo Sphere Viewer V3.5.1',
|
||||
time_anim: false,
|
||||
default_fov: 40,
|
||||
min_fov: 5,
|
||||
max_fov: 75,
|
||||
navbar: [
|
||||
'autorotate',
|
||||
'zoom',
|
||||
'caption'
|
||||
]
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -4,9 +4,9 @@ Type=Application
|
|||
Name=SimplePanoramaViewer
|
||||
Comment=Simple web based panoram viewer
|
||||
Icon=emblem-photos
|
||||
Exec=SimplePanoramaViewer
|
||||
Exec=simple_panorama_viewer
|
||||
NoDisplay=false
|
||||
Categories=Graphics;Viewer
|
||||
StartupNotify=false
|
||||
Terminal=false
|
||||
MimeType=image/jpeg;image/pjpg
|
||||
MimeType=image/jpeg;image/pjpg;image/webp;image/avif
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
|
||||
<mime-type type="image/pjpg">
|
||||
<comment>Panoramic JPEG image</comment>
|
||||
<comment xml:lang="fr">Image JPEG panoramique</comment>
|
||||
<glob pattern="*.pjpeg"/>
|
||||
<glob pattern="*.pjpg"/>
|
||||
<glob pattern="*.pjpe"/>
|
||||
</mime-type>
|
||||
</mime-info>
|
|
@ -1,2 +0,0 @@
|
|||
/* (c) Jonathan Gotti - licence: https://github.com/malko/d.js/LICENCE.txt @version 0.7.5*/
|
||||
!function(a){"use strict";function b(a){l(function(){throw a})}function c(b){return this.then(b,a)}function d(b){return this.then(a,b)}function e(b,c){return this.then(function(a){return m(b)?b.apply(null,n(a)?a:[a]):v.onlyFuncs?a:b},c||a)}function f(a){function b(){a()}return this.then(b,b),this}function g(a){return this.then(function(b){return m(a)?a.apply(null,n(b)?b.splice(0,0,void 0)&&b:[void 0,b]):v.onlyFuncs?b:a},function(b){return a(b)})}function h(c){return this.then(a,c?function(a){throw c(a),a}:b)}function i(a,b){var c=q(a);if(1===c.length&&n(c[0])){if(!c[0].length)return v.fulfilled([]);c=c[0]}var d=[],e=v(),f=c.length;if(f)for(var g=function(a){c[a]=v.promisify(c[a]),c[a].then(function(g){d[a]=b?c[a]:g,--f||e.resolve(d)},function(g){b?(d[a]=c[a],--f||e.resolve(d)):e.reject(g)})},h=0,i=f;i>h;h++)g(h);else e.resolve(d);return e.promise}function j(a,b){return a.then(m(b)?b:function(){return b})}function k(a){var b=q(a);1===b.length&&n(b[0])&&(b=b[0]);for(var c=v(),d=0,e=b.length,f=v.resolved();e>d;d++)f=j(f,b[d]);return c.resolve(f),c.promise}var l,m=function(a){return"function"==typeof a},n=function(a){return Array.isArray?Array.isArray(a):a instanceof Array},o=function(a){return!(!a||!(typeof a).match(/function|object/))},p=function(b){return b===!1||b===a||null===b},q=function(a,b){return[].slice.call(a,b)},r="undefined",s=typeof TypeError===r?Error:TypeError;if(typeof process!==r&&process.nextTick)l=process.nextTick;else if(typeof MessageChannel!==r){var t=new MessageChannel,u=[];t.port1.onmessage=function(){u.length&&u.shift()()},l=function(a){u.push(a),t.port2.postMessage(0)}}else l=function(a){setTimeout(a,0)};var v=function(b){function i(){if(0!==r){var a,b=t,c=0,d=b.length,e=~r?0:1;for(t=[];d>c;c++)(a=b[c][e])&&a(n)}}function j(a){function b(a){return function(b){return c?void 0:(c=!0,a(b))}}var c=!1;if(r)return this;try{var d=o(a)&&a.then;if(m(d)){if(a===u)throw new s("Promise can't resolve itself");return d.call(a,b(j),b(k)),this}}catch(e){return b(k)(e),this}return q(function(){n=a,r=1,i()}),this}function k(a){return r||q(function(){try{throw a}catch(b){n=b}r=-1,i()}),this}var n,q=(a!==b?b:v.alwaysAsync)?l:function(a){a()},r=0,t=[],u={then:function(a,b){var c=v();return t.push([function(b){try{p(a)?c.resolve(b):c.resolve(m(a)?a(b):v.onlyFuncs?b:a)}catch(d){c.reject(d)}},function(a){if((p(b)||!m(b)&&v.onlyFuncs)&&c.reject(a),b)try{c.resolve(m(b)?b(a):b)}catch(d){c.reject(d)}}]),0!==r&&q(i),c.promise},success:c,error:d,otherwise:d,apply:e,spread:e,ensure:f,nodify:g,rethrow:h,isPending:function(){return 0===r},getStatus:function(){return r}};return u.toSource=u.toString=u.valueOf=function(){return n===a?this:n},{promise:u,resolve:j,fulfill:j,reject:k}};if(v.deferred=v.defer=v,v.nextTick=l,v.alwaysAsync=!0,v.onlyFuncs=!0,v.resolve=v.resolved=v.fulfilled=function(a){return v(!0).resolve(a).promise},v.reject=v.rejected=function(a){return v(!0).reject(a).promise},v.wait=function(a){var b=v();return setTimeout(b.resolve,a||0),b.promise},v.delay=function(a,b){var c=v();return setTimeout(function(){try{c.resolve(m(a)?a.apply(null):a)}catch(b){c.reject(b)}},b||0),c.promise},v.promisify=function(a){return a&&m(a.then)?a:v.resolved(a)},v.all=function(){return i(arguments,!1)},v.resolveAll=function(){return i(arguments,!0)},v.sequence=function(){return k(arguments)},v.nodeCapsule=function(a,b){return b||(b=a,a=void 0),function(){var c=v(),d=q(arguments);d.push(function(a,b){a?c.reject(a):c.resolve(arguments.length>2?q(arguments,1):b)});try{b.apply(a,d)}catch(e){c.reject(e)}return c.promise}},"function"==typeof define&&define.amd)define("D.js",[],function(){return v});else if(typeof module!==r&&module.exports)module.exports=v;else if(typeof window!==r){var w=window.D;v.noConflict=function(){return window.D=w,v},window.D=v}}();
|
|
@ -1,2 +0,0 @@
|
|||
/* Laura Doktorova https://github.com/olado/doT */
|
||||
!function(){"use strict";function e(n,t,r){return("string"==typeof t?t:t.toString()).replace(n.define||a,function(e,t,o,a){return 0===t.indexOf("def.")&&(t=t.substring(4)),t in r||(":"===o?(n.defineParams&&a.replace(n.defineParams,function(e,n,o){r[t]={arg:n,text:o}}),t in r||(r[t]=a)):new Function("def","def['"+t+"']="+a)(r)),""}).replace(n.use||a,function(t,o){n.useParams&&(o=o.replace(n.useParams,function(e,n,t,o){if(r[t]&&r[t].arg&&o){var a=(t+":"+o).replace(/'|\\/g,"_");return r.__exp=r.__exp||{},r.__exp[a]=r[t].text.replace(new RegExp("(^|[^\\w$])"+r[t].arg+"([^\\w$])","g"),"$1"+o+"$2"),n+"def.__exp['"+a+"']"}}));var a=new Function("def","return "+o)(r);return a?e(n,a,r):a})}function n(e){return e.replace(/\\('|\\)/g,"$1").replace(/[\r\t\n]/g," ")}var t,r={name:"doT",version:"1.1.1",templateSettings:{evaluate:/\{\{([\s\S]+?(\}?)+)\}\}/g,interpolate:/\{\{=([\s\S]+?)\}\}/g,encode:/\{\{!([\s\S]+?)\}\}/g,use:/\{\{#([\s\S]+?)\}\}/g,useParams:/(^|[^\w$])def(?:\.|\[[\'\"])([\w$\.]+)(?:[\'\"]\])?\s*\:\s*([\w$\.]+|\"[^\"]+\"|\'[^\']+\'|\{[^\}]+\})/g,define:/\{\{##\s*([\w\.$]+)\s*(\:|=)([\s\S]+?)#\}\}/g,defineParams:/^\s*([\w$]+):([\s\S]+)/,conditional:/\{\{\?(\?)?\s*([\s\S]*?)\s*\}\}/g,iterate:/\{\{~\s*(?:\}\}|([\s\S]+?)\s*\:\s*([\w$]+)\s*(?:\:\s*([\w$]+))?\s*\}\})/g,varname:"it",strip:!0,append:!0,selfcontained:!1,doNotSkipEncoded:!1},template:void 0,compile:void 0,log:!0};r.encodeHTMLSource=function(e){var n={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"},t=e?/[&<>"'\/]/g:/&(?!#?\w+;)|<|>|"|'|\//g;return function(e){return e?e.toString().replace(t,function(e){return n[e]||e}):""}},t=function(){return this||(0,eval)("this")}(),"undefined"!=typeof module&&module.exports?module.exports=r:"function"==typeof define&&define.amd?define(function(){return r}):t.doT=r;var o={append:{start:"'+(",end:")+'",startencode:"'+encodeHTML("},split:{start:"';out+=(",end:");out+='",startencode:"';out+=encodeHTML("}},a=/$^/;r.template=function(c,i,u){i=i||r.templateSettings;var d,s,p=i.append?o.append:o.split,l=0,f=i.use||i.define?e(i,c,u||{}):c;f=("var out='"+(i.strip?f.replace(/(^|\r|\n)\t* +| +\t*(\r|\n|$)/g," ").replace(/\r|\n|\t|\/\*[\s\S]*?\*\//g,""):f).replace(/'|\\/g,"\\$&").replace(i.interpolate||a,function(e,t){return p.start+n(t)+p.end}).replace(i.encode||a,function(e,t){return d=!0,p.startencode+n(t)+p.end}).replace(i.conditional||a,function(e,t,r){return t?r?"';}else if("+n(r)+"){out+='":"';}else{out+='":r?"';if("+n(r)+"){out+='":"';}out+='"}).replace(i.iterate||a,function(e,t,r,o){return t?(l+=1,s=o||"i"+l,t=n(t),"';var arr"+l+"="+t+";if(arr"+l+"){var "+r+","+s+"=-1,l"+l+"=arr"+l+".length-1;while("+s+"<l"+l+"){"+r+"=arr"+l+"["+s+"+=1];out+='"):"';} } out+='"}).replace(i.evaluate||a,function(e,t){return"';"+n(t)+"out+='"})+"';return out;").replace(/\n/g,"\\n").replace(/\t/g,"\\t").replace(/\r/g,"\\r").replace(/(\s|;|\}|^|\{)out\+='';/g,"$1").replace(/\+''/g,""),d&&(i.selfcontained||!t||t._encodeHTML||(t._encodeHTML=r.encodeHTMLSource(i.doNotSkipEncoded)),f="var encodeHTML = typeof _encodeHTML !== 'undefined' ? _encodeHTML : ("+r.encodeHTMLSource.toString()+"("+(i.doNotSkipEncoded||"")+"));"+f);try{return new Function(i.varname,f)}catch(e){throw"undefined"!=typeof console&&console.log("Could not create a template function: "+f),e}},r.compile=function(e,n){return r.template(e,null,n)}}();
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,7 +0,0 @@
|
|||
/*!
|
||||
* uEvent 1.0.0 - to make any js object an event emitter
|
||||
* Copyright 2011 Jerome Etienne (http://jetienne.com)
|
||||
* Copyright 2015-2016 Damien "Mistic" Sorel (http://www.strangeplanet.fr)
|
||||
* Licensed under MIT (http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
!function(a,b){"undefined"!=typeof module&&module.exports?module.exports=b():"function"==typeof define&&define.amd?define([],b):a.uEvent=b()}(this,function(){"use strict";var a=function(){return!0},b=function(){return!1},c=function(){};return c.Event=function(a,b){var c=a,d=b;Object.defineProperties(this,{type:{get:function(){return c},set:function(a){},enumerable:!0},args:{get:function(){return d},set:function(a){},enumerable:!0}})},c.Event.prototype={constructor:c.Event,isDefaultPrevented:b,isPropagationStopped:b,preventDefault:function(){this.isDefaultPrevented=a},stopPropagation:function(){this.isPropagationStopped=a}},c.prototype={constructor:c,on:function(a,b){if(this.__events=this.__events||{},"object"==typeof a)for(var c in a)a.hasOwnProperty(c)&&(this.__events[c]=this.__events[c]||[],this.__events[c].push(a[c]));else a.split(" ").forEach(function(a){this.__events[a]=this.__events[a]||[],this.__events[a].push(b)},this);return this},off:function(a,b){if(this.__events=this.__events||{},"object"==typeof a){for(var c in a)if(a.hasOwnProperty(c)&&c in this.__events){var d=this.__events[c].indexOf(a[c]);-1!==d&&this.__events[c].splice(d,1)}}else a?a.split(" ").forEach(function(a){if(a in this.__events)if(b){var c=this.__events[a].indexOf(b);-1!==c&&this.__events[a].splice(c,1)}else this.__events[a].length=0},this):this.__events={};return this},once:function(a,b){if(this.__once=this.__once||{},"object"==typeof a)for(var c in a)a.hasOwnProperty(c)&&(this.__once[c]=this.__once[c]||[],this.__once[c].push(a[c]));else a.split(" ").forEach(function(a){this.__once[a]=this.__once[a]||[],this.__once[a].push(b)},this);return this},trigger:function(a){var b,d,e,f=Array.prototype.slice.call(arguments,1),g=new c.Event(a,f);if(f.push(g),this.__events&&a in this.__events)for(b=0,d=this.__events[a].length;d>b;b++)if(e=this.__events[a][b],"object"==typeof e?e.handleEvent(g):e.apply(this,f),g.isPropagationStopped())return g;if(this.__once&&a in this.__once){for(b=0,d=this.__once[a].length;d>b;b++)if(e=this.__once[a][b],"object"==typeof e?e.handleEvent(g):e.apply(this,f),g.isPropagationStopped())return delete this.__once[a],g;delete this.__once[a]}return g},change:function(a,b){var d,e,f,g=Array.prototype.slice.call(arguments,1),h=new c.Event(a,g);if(g.push(h),this.__events&&a in this.__events)for(d=0,e=this.__events[a].length;e>d;d++)if(g[0]=b,f=this.__events[a][d],b="object"==typeof f?f.handleEvent(h):f.apply(this,g),h.isPropagationStopped())return b;return b}},c.mixin=function(a,b){b=b||{},a="function"==typeof a?a.prototype:a,["on","off","once","trigger","change"].forEach(function(d){var e=b[d]||d;a[e]=c.prototype[d]}),Object.defineProperties(a,{__events:{value:null,writable:!0},__once:{value:null,writable:!0}})},c});
|
|
@ -0,0 +1,30 @@
|
|||
[profiles]
|
||||
[profiles.bin_linux]
|
||||
output = "./dist/SimplePanoramaViewer-2.0.0-x86_64-unknown-linux-gnu$EXT"
|
||||
directory = "target/release/"
|
||||
files = ["simple_panorama_viewer"]
|
||||
container = "Tar"
|
||||
compression = "Zstd"
|
||||
compression_level = 15
|
||||
signatures = ["Sha512"]
|
||||
|
||||
[profiles.bin_win]
|
||||
output = "./dist/SimplePanoramaViewer-2.0.0-x86_64-pc-windows-msvc$EXT"
|
||||
directory = "target/release/"
|
||||
files = ["simple_panorama_viewer.exe"]
|
||||
container = "Zip"
|
||||
compression = "Deflate"
|
||||
compression_level = 9
|
||||
signatures = ["Sha512"]
|
||||
|
||||
[profiles.files]
|
||||
files = ["README.md", "LICENSE.md"]
|
||||
|
||||
[profiles.sources]
|
||||
paths = ["./"]
|
||||
output = "./dist/SimplePanoramaViewer-2.0.0-src$EXT"
|
||||
container = "Tar"
|
||||
compression = "Zstd"
|
||||
compression_level = 15
|
||||
hidden = true
|
||||
signatures = ["Sha512"]
|
|
@ -0,0 +1,164 @@
|
|||
#![windows_subsystem = "windows"]
|
||||
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use clap::{Arg, Command};
|
||||
use log::info;
|
||||
use native_dialog::{FileDialog, MessageDialog};
|
||||
use rand::distributions::DistString;
|
||||
use rust_embed::RustEmbed;
|
||||
use simplelog::{ColorChoice, ConfigBuilder, LevelFilter, TermLogger, TerminalMode};
|
||||
use std::{borrow::Cow, path::PathBuf, thread::JoinHandle};
|
||||
use warp::Filter;
|
||||
use wry::{
|
||||
application::{
|
||||
event::{Event, StartCause, WindowEvent},
|
||||
event_loop::{ControlFlow, EventLoop},
|
||||
window::WindowBuilder,
|
||||
},
|
||||
webview::{WebContext, WebViewBuilder},
|
||||
};
|
||||
|
||||
#[derive(RustEmbed)]
|
||||
#[folder = "embed/"]
|
||||
struct Embed;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
// Init log
|
||||
TermLogger::init(
|
||||
LevelFilter::Info,
|
||||
ConfigBuilder::new()
|
||||
.set_time_offset_to_local()
|
||||
.unwrap()
|
||||
.build(),
|
||||
TerminalMode::Mixed,
|
||||
ColorChoice::Auto,
|
||||
)?;
|
||||
|
||||
let cmd = Command::new("Simple panorama viewer")
|
||||
.version(env!("CARGO_PKG_VERSION"))
|
||||
.author(env!("CARGO_PKG_AUTHORS"))
|
||||
.about(env!("CARGO_PKG_DESCRIPTION"))
|
||||
.arg(
|
||||
Arg::new("filename")
|
||||
.value_parser(clap::value_parser!(PathBuf))
|
||||
.help("Image path"),
|
||||
)
|
||||
.get_matches();
|
||||
|
||||
let img_path = if let Some(img_path) = cmd.get_one::<PathBuf>("filename") {
|
||||
Cow::Borrowed(img_path)
|
||||
} else {
|
||||
let user_dirs = directories::UserDirs::new().unwrap();
|
||||
let dir = if let Some(img_dir) = user_dirs.picture_dir() {
|
||||
img_dir
|
||||
} else {
|
||||
user_dirs.home_dir()
|
||||
};
|
||||
Cow::Owned(
|
||||
FileDialog::new()
|
||||
.add_filter(
|
||||
"Images",
|
||||
&[
|
||||
"jpg", "JPG", "jpeg", "pjpeg", "pjpg", "PJPG", "webp", "avif",
|
||||
],
|
||||
)
|
||||
.set_location(dir)
|
||||
.show_open_single_file()?
|
||||
.ok_or_else(|| anyhow!("No file"))?,
|
||||
)
|
||||
};
|
||||
|
||||
if !img_path.exists() {
|
||||
MessageDialog::new()
|
||||
.set_title("Image error")
|
||||
.set_text(&format!("Image `{}` does not exist", img_path.display()))
|
||||
.set_type(native_dialog::MessageType::Error)
|
||||
.show_alert()?;
|
||||
bail!("File `{}` does not exist !", img_path.display());
|
||||
}
|
||||
|
||||
info!("Run server");
|
||||
let port = portpicker::pick_unused_port().ok_or_else(|| anyhow!("Cannot find ununsed port"))?;
|
||||
let user_agent = rand::distributions::Alphanumeric.sample_string(&mut rand::thread_rng(), 32);
|
||||
run_server(img_path.to_path_buf(), port, user_agent.clone());
|
||||
|
||||
info!("Create webview");
|
||||
let event_loop = EventLoop::new();
|
||||
let window = WindowBuilder::new()
|
||||
.with_title("Simple panorama viewer")
|
||||
.with_maximized(true)
|
||||
.build(&event_loop)?;
|
||||
let data_dir = directories::ProjectDirs::from("fr", "dalan", "SimplePanoramaViwer").unwrap();
|
||||
let _webview = WebViewBuilder::new(window)?
|
||||
.with_url(&format!("http://127.0.0.1:{}/index.html", port))?
|
||||
.with_user_agent(&user_agent)
|
||||
.with_web_context(&mut WebContext::new(Some(
|
||||
data_dir.cache_dir().to_path_buf(),
|
||||
)))
|
||||
.build()?;
|
||||
|
||||
info!("Event loop");
|
||||
event_loop.run(move |event, _, control_flow| {
|
||||
*control_flow = ControlFlow::Wait;
|
||||
|
||||
match event {
|
||||
Event::NewEvents(StartCause::Init) => info!("Panorama open"),
|
||||
Event::WindowEvent {
|
||||
event: WindowEvent::CloseRequested,
|
||||
..
|
||||
} => {
|
||||
info!("Close");
|
||||
*control_flow = ControlFlow::Exit
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn run_server(img_path: PathBuf, port: u16, user_agent: String) -> JoinHandle<()> {
|
||||
std::thread::spawn(move || {
|
||||
info!("Create runtime");
|
||||
let async_runtime = tokio::runtime::Builder::new_current_thread()
|
||||
.enable_all()
|
||||
.build()
|
||||
.unwrap();
|
||||
info!("Create response");
|
||||
let index = warp::path("index.html").map(|| {
|
||||
info!("Request `index.html`");
|
||||
let datas = get_file_data("index.html");
|
||||
warp::reply::html(datas)
|
||||
});
|
||||
let css = warp::path!("css" / String).map(move |val: String| {
|
||||
info!("Request css `{}`", &val);
|
||||
let datas = get_file_data(&format!("css/{}", val));
|
||||
warp::http::Response::builder().body(datas)
|
||||
});
|
||||
let js = warp::path!("js" / String).map(move |val: String| {
|
||||
info!("Request js `{}`", &val);
|
||||
let datas = get_file_data(&format!("js/{}", val));
|
||||
warp::http::Response::builder().body(datas)
|
||||
});
|
||||
let img = warp::path!("img")
|
||||
.and(warp::header("user-agent"))
|
||||
.map(move |agent: String| {
|
||||
if agent == user_agent {
|
||||
std::fs::read(&img_path).unwrap()
|
||||
} else {
|
||||
Vec::new()
|
||||
}
|
||||
});
|
||||
info!("Launch webserver");
|
||||
async_runtime
|
||||
.block_on(warp::serve(img.or(index).or(css).or(js)).run(([127, 0, 0, 1], port)));
|
||||
})
|
||||
}
|
||||
|
||||
fn get_file_data(filename: &str) -> String {
|
||||
if let Some(file) = Embed::get(filename) {
|
||||
std::str::from_utf8(file.data.as_ref())
|
||||
.unwrap_or("")
|
||||
.to_string()
|
||||
} else {
|
||||
"".to_string()
|
||||
}
|
||||
}
|
101
utility.sh
101
utility.sh
|
@ -1,101 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
print_help()
|
||||
{
|
||||
echo "SimplePanoramaViewer utility script"
|
||||
echo
|
||||
echo "Use:"
|
||||
echo " bash utility.sh OPTION [PATH_TO_INSTALL_DIR]"
|
||||
echo
|
||||
echo "Options:"
|
||||
echo " -i, --install Install SimplePanoramaViewer in PATH_TO_INSTALL_DIR"
|
||||
echo " -u, --uninstall Uninstall SimplePanoramaViewer from PATH_TO_INSTALL_DIR"
|
||||
echo " -p, --package Generate a package for SimplePanoramaViewer"
|
||||
}
|
||||
|
||||
check_dir()
|
||||
{
|
||||
if [ -z "$1" ]; then
|
||||
echo "You need to pass a directory"
|
||||
exit
|
||||
fi
|
||||
}
|
||||
|
||||
install()
|
||||
{
|
||||
DESTDIR=$1
|
||||
check_dir "$DESTDIR"
|
||||
if [ -z "$2" ]; then
|
||||
PREFIX=$DESTDIR
|
||||
else
|
||||
PREFIX="$2"
|
||||
DESTDIR=$DESTDIR$PREFIX
|
||||
echo $DESTDIR
|
||||
fi
|
||||
|
||||
mkdir -p "$DESTDIR/share/SimplePanoramaViewer/"
|
||||
mkdir -p "$DESTDIR/bin/"
|
||||
mkdir -p "$DESTDIR/share/applications"
|
||||
mkdir -p "$DESTDIR/share/mime/image"
|
||||
cp SimplePanoramaViewer "$DESTDIR/share/SimplePanoramaViewer"
|
||||
cp -r css "$DESTDIR/share/SimplePanoramaViewer"
|
||||
cp -r html "$DESTDIR/share/SimplePanoramaViewer"
|
||||
cp -r js "$DESTDIR/share/SimplePanoramaViewer"
|
||||
cp install/SimplePanoramaViewer.desktop "$DESTDIR/share/applications"
|
||||
cp install/pjpg.xml "$DESTDIR/share/mime/image"
|
||||
echo "#!/bin/bash
|
||||
$PREFIX/share/SimplePanoramaViewer/SimplePanoramaViewer \"\$@\"" > "$DESTDIR/bin/SimplePanoramaViewer"
|
||||
chmod a+x "$DESTDIR/bin/SimplePanoramaViewer"
|
||||
chmod -R a+r "$DESTDIR/share/SimplePanoramaViewer"
|
||||
}
|
||||
|
||||
uninstall()
|
||||
{
|
||||
DIR=$1
|
||||
check_dir "$DIR"
|
||||
|
||||
rm "$DIR/bin/SimplePanoramaViewer"
|
||||
rm -r "$DIR/share/SimplePanoramaViewer/"
|
||||
rm "$DIR/share/applications/SimplePanoramaViewer.desktop"
|
||||
rm "$DIR/share/mime/image/pjpg.xml"
|
||||
}
|
||||
|
||||
package()
|
||||
{
|
||||
DIR="/tmp/SimplePanoramaViewer"
|
||||
|
||||
mkdir "$DIR"
|
||||
cp SimplePanoramaViewer "$DIR"
|
||||
cp -r css "$DIR"
|
||||
cp -r html "$DIR"
|
||||
cp -r js "$DIR"
|
||||
chmod a+x "$DIR/SimplePanoramaViewer"
|
||||
|
||||
mkdir -p dist
|
||||
cd /tmp || exit
|
||||
tar Jcvf "SimplePanoramaViewer.tar.xz" "SimplePanoramaViewer"
|
||||
|
||||
cd - || exit
|
||||
cp -f "$DIR.tar.xz" dist
|
||||
|
||||
rm -r "$DIR"
|
||||
rm "$DIR.tar.xz"
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
"-h" | "--help")
|
||||
print_help
|
||||
;;
|
||||
"-i" | "--install")
|
||||
install "$2" "$3"
|
||||
;;
|
||||
"-u" | "--uninstall")
|
||||
uninstall "$2"
|
||||
;;
|
||||
"-p" | "--package")
|
||||
package
|
||||
;;
|
||||
*)
|
||||
print_help
|
||||
;;
|
||||
esac
|
|
@ -2,10 +2,10 @@
|
|||
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
|
||||
|
||||
#define MyAppName "SimplePanoramaViewer"
|
||||
#define MyAppVersion "1.1"
|
||||
#define MyAppVersion "2.0.0"
|
||||
#define MyAppPublisher "Dalan"
|
||||
#define MyAppURL "https://www.dalan.fr"
|
||||
#define MyAppExeName "SimplePanoramaViewer.exe"
|
||||
#define MyAppExeName "simple_panorama_viewer.exe"
|
||||
|
||||
[Setup]
|
||||
; NOTE: The value of AppId uniquely identifies this application.
|
||||
|
@ -19,12 +19,12 @@ AppPublisher={#MyAppPublisher}
|
|||
AppPublisherURL={#MyAppURL}
|
||||
AppSupportURL={#MyAppURL}
|
||||
AppUpdatesURL={#MyAppURL}
|
||||
DefaultDirName={pf}\{#MyAppName}
|
||||
DefaultDirName={commonpf}\{#MyAppName}
|
||||
DisableProgramGroupPage=yes
|
||||
LicenseFile=LICENSE.rtf
|
||||
OutputBaseFilename={#MyAppName}-{#MyAppVersion}-win64-setup
|
||||
OutputBaseFilename={#MyAppName}-{#MyAppVersion}-x86_64-pc-windows-msvc-setup
|
||||
OutputDir=dist
|
||||
Compression=lzma
|
||||
Compression=lzma2
|
||||
SolidCompression=yes
|
||||
ArchitecturesAllowed=x64
|
||||
ArchitecturesInstallIn64BitMode=x64
|
||||
|
@ -37,7 +37,7 @@ Name: "french"; MessagesFile: "compiler:Languages\French.isl"
|
|||
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
|
||||
|
||||
[Files]
|
||||
Source: "dist\SimplePanoramaViewer\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
|
||||
Source: "target\release\simple_panorama_viewer.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||
|
||||
[Icons]
|
||||
Name: "{commonprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
|
||||
|
|
Loading…
Reference in New Issue