From eed83ac85a7193ff6eead9ec527b7aebc600790a Mon Sep 17 00:00:00 2001
From: ksuprynowicz <ksuprynowicz@post.pl>
Date: Fri, 22 Jul 2022 23:23:46 +0200
Subject: [PATCH 1/5] Added screenshot format selection with PNG, JPEG and WEBM
 support

---
 interface/src/ui/PreferencesDialog.cpp | 22 ++++++++++++
 interface/src/ui/Snapshot.cpp          | 47 ++++++++++++++++++++++++--
 interface/src/ui/Snapshot.h            | 46 +++++++++++++++++++++++++
 3 files changed, 112 insertions(+), 3 deletions(-)

diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp
index adeb0d1dcd..3a3eb0d801 100644
--- a/interface/src/ui/PreferencesDialog.cpp
+++ b/interface/src/ui/PreferencesDialog.cpp
@@ -258,6 +258,28 @@ void setupPreferences() {
         preferences->addPreference(new CheckPreference(SNAPSHOTS, "Display snapshot notifications", getter, setter));
     }
 
+    {
+        auto getter = []()->int { return DependencyManager::get<Snapshot>()->getAvailableSnapshotFormats().indexOf(DependencyManager::get<Snapshot>()->getSnapshotFormat()); };
+        auto setter = [](int value) { DependencyManager::get<Snapshot>()->setSnapshotFormat(DependencyManager::get<Snapshot>()->getAvailableSnapshotFormats()[value]); };
+        auto preference = new RadioButtonsPreference(SNAPSHOTS, "Snapshot format", getter, setter);
+        QStringList items;
+        items << DependencyManager::get<Snapshot>()->getAvailableSnapshotFormats();
+        preference->setHeading("Snapshot format");
+        preference->setItems(items);
+        preferences->addPreference(preference);
+    }
+
+    {
+        auto getter = []()->int { return DependencyManager::get<Snapshot>()->getAvailableAnimatedSnapshotFormats().indexOf(DependencyManager::get<Snapshot>()->getAnimatedSnapshotFormat()); };
+        auto setter = [](int value) { DependencyManager::get<Snapshot>()->setAnimatedSnapshotFormat(DependencyManager::get<Snapshot>()->getAvailableAnimatedSnapshotFormats()[value]); };
+        auto preference = new RadioButtonsPreference(SNAPSHOTS, "Animated snapshot format", getter, setter);
+        QStringList items;
+        items << DependencyManager::get<Snapshot>()->getAvailableAnimatedSnapshotFormats();
+        preference->setHeading("Animated snapshot format");
+        preference->setItems(items);
+        preferences->addPreference(preference);
+    }
+    
     {
         auto getter = []()->bool { return !Menu::getInstance()->isOptionChecked(MenuOption::DisableActivityLogger); };
         auto setter = [](bool value) { Menu::getInstance()->setIsOptionChecked(MenuOption::DisableActivityLogger, !value); };
diff --git a/interface/src/ui/Snapshot.cpp b/interface/src/ui/Snapshot.cpp
index e736ed9430..d26eaf8545 100644
--- a/interface/src/ui/Snapshot.cpp
+++ b/interface/src/ui/Snapshot.cpp
@@ -4,6 +4,7 @@
 //
 //  Created by Stojce Slavkovski on 1/26/14.
 //  Copyright 2014 High Fidelity, Inc.
+//  Copyright 2022 Overte e.V.
 //
 //  Distributed under the Apache License, Version 2.0.
 //  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@@ -44,12 +45,13 @@
 
 // filename format: overte-snap-by-%username%-on-%date%_%time%_@-%location%.png
 // %1 <= username, %2 <= date and time, %3 <= current location
-const QString FILENAME_PATH_FORMAT = "overte-snap-by-%1-on-%2.png";
+const QString FILENAME_PATH_FORMAT = "overte-snap-by-%1-on-%2";
+const QString DEFAULT_FORMAT = "png";
 const QString DATETIME_FORMAT = "yyyy-MM-dd_hh-mm-ss";
 const QString SNAPSHOTS_DIRECTORY = "Snapshots";
 const QString URL = "overte_url";
 static const int SNAPSHOT_360_TIMER_INTERVAL = 350;
-static const QList<QString> SUPPORTED_IMAGE_FORMATS = { "jpg", "jpeg", "png" };
+static const QList<QString> SUPPORTED_IMAGE_FORMATS = { "jpg", "jpeg", "png", "webp" };
 
 Snapshot::Snapshot() {
     _snapshotTimer.setSingleShot(false);
@@ -110,6 +112,7 @@ QString Snapshot::saveSnapshot(QImage image, const QString& filename, const QStr
     return "";
 }
 
+
 static const float CUBEMAP_SIDE_PIXEL_DIMENSION = 2048.0f;
 static const float SNAPSHOT_360_FOV = 90.0f;
 static const float SNAPSHOT_360_NEARCLIP = 0.3f;
@@ -389,7 +392,11 @@ QFile* Snapshot::savedFileForSnapshot(QImage& shot,
             imageQuality = 50;
         }
     } else {
-        filename = FILENAME_PATH_FORMAT.arg(username, now.toString(DATETIME_FORMAT));
+        QString selectedFormat(DEFAULT_FORMAT);
+        if (_snapshotFormat.get() != "") {
+            selectedFormat = _snapshotFormat.get();
+        }
+        filename = FILENAME_PATH_FORMAT.arg(username, now.toString(DATETIME_FORMAT)) + "." + selectedFormat;
         QFileInfo snapshotFileInfo(filename);
         QString filenameSuffix = snapshotFileInfo.suffix();
         filenameSuffix = filenameSuffix.toLower();
@@ -516,3 +523,37 @@ QString Snapshot::getSnapshotsLocation() {
 void Snapshot::setSnapshotsLocation(const QString& location) {
     _snapshotsLocation.set(location);
 }
+
+QString Snapshot::getSnapshotFormat(){
+    return _snapshotFormat.get();
+}
+
+void Snapshot::setSnapshotFormat(const QString& format){
+    if (getAvailableSnapshotFormats().contains(format)) {
+        _snapshotFormat.set(format);
+        qDebug() << "Snapshot format set: " << format;
+    } else {
+        qDebug() << "Snapshot format not supported: " << format;
+    }
+}
+
+QString Snapshot::getAnimatedSnapshotFormat(){
+    return _animatedSnapshotFormat.get();
+}
+
+void Snapshot::setAnimatedSnapshotFormat(const QString& format){
+    if (getAvailableAnimatedSnapshotFormats().contains(format)) {
+        _animatedSnapshotFormat.set(format);
+        qDebug() << "Snapshot format set: " << format;
+    } else {
+        qDebug() << "Snapshot format not supported: " << format;
+    }
+}
+
+QStringList Snapshot::getAvailableSnapshotFormats() {
+    return QStringList({"png", "jpg", "webp"});
+}
+
+QStringList Snapshot::getAvailableAnimatedSnapshotFormats() {
+    return QStringList({"gif"});
+}
diff --git a/interface/src/ui/Snapshot.h b/interface/src/ui/Snapshot.h
index f6c57b0e42..ad55186be4 100644
--- a/interface/src/ui/Snapshot.h
+++ b/interface/src/ui/Snapshot.h
@@ -65,6 +65,8 @@ public:
 
     Setting::Handle<QString> _snapshotsLocation{ "snapshotsLocation" };
     Setting::Handle<bool> _snapshotNotifications{ "snapshotNotifications", true };
+    Setting::Handle<QString> _snapshotFormat{ "snapshotFormat" };
+    Setting::Handle<QString> _animatedSnapshotFormat{ "animatedSnapshotFormat" };
     void uploadSnapshot(const QString& filename, const QUrl& href = QUrl(""));
 
 signals:
@@ -97,6 +99,50 @@ public slots:
      * @param {String} location - The path to save snapshots to.
      */
     Q_INVOKABLE void setSnapshotsLocation(const QString& location);
+    
+    /*@jsdoc
+     * Gets the currently selected snapshot format.
+     * @function Snapshot.getSnapshotFormat
+     * @returns {string} Currently selected snapshot format.
+     */
+    Q_INVOKABLE QString getSnapshotFormat();
+
+    /*@jsdoc
+     * Sets the snapshot format.
+     * @function Snapshot.setSnapshotFormat
+     * @param {String} format - one of the format names returned by Snapshot.getAvailableSnapshotFormats().
+     */
+    Q_INVOKABLE void setSnapshotFormat(const QString& format);
+
+    /*@jsdoc
+     * Gets the currently selected animated snapshot format.
+     * @function Snapshot.getAnimatedSnapshotFormat
+     * @returns {Array.<string>} Currently selected snapshot format.
+     */
+    Q_INVOKABLE QString getAnimatedSnapshotFormat();
+
+    /*@jsdoc
+     * Sets the snapshot format.
+     * @function Snapshot.setAnimatedSnapshotFormat
+     * @param {String} format - one of the format names returned by Snapshot.getAvailableSnapshotFormats().
+     */
+    Q_INVOKABLE void setAnimatedSnapshotFormat(const QString& format);
+
+    /*@jsdoc
+     * Returns a list of supported snapshot formats.
+     * @function Snapshot.getAvailableSnapshotFormats
+     * @returns {Array.<string>} List of supported snapshot formats.
+     */
+    Q_INVOKABLE QStringList getAvailableSnapshotFormats();
+
+    /*@jsdoc
+     * Returns a list of supported animated snapshot formats.
+     * @function Snapshot.getAvailableAnimatedSnapshotFormats
+     * @returns {Array.<string>} List of supported animated snapshot formats.
+     */
+    Q_INVOKABLE QStringList getAvailableAnimatedSnapshotFormats();
+    
+    
 
 private slots:
     void takeNextSnapshot();

From c2572000e2788c96b9d5ca859fb3696522d30654 Mon Sep 17 00:00:00 2001
From: ksuprynowicz <ksuprynowicz@post.pl>
Date: Fri, 22 Jul 2022 23:37:11 +0200
Subject: [PATCH 2/5] Removed excessive debug messages

---
 interface/src/ui/Snapshot.cpp | 2 --
 1 file changed, 2 deletions(-)

diff --git a/interface/src/ui/Snapshot.cpp b/interface/src/ui/Snapshot.cpp
index d26eaf8545..aaffbade3c 100644
--- a/interface/src/ui/Snapshot.cpp
+++ b/interface/src/ui/Snapshot.cpp
@@ -531,7 +531,6 @@ QString Snapshot::getSnapshotFormat(){
 void Snapshot::setSnapshotFormat(const QString& format){
     if (getAvailableSnapshotFormats().contains(format)) {
         _snapshotFormat.set(format);
-        qDebug() << "Snapshot format set: " << format;
     } else {
         qDebug() << "Snapshot format not supported: " << format;
     }
@@ -544,7 +543,6 @@ QString Snapshot::getAnimatedSnapshotFormat(){
 void Snapshot::setAnimatedSnapshotFormat(const QString& format){
     if (getAvailableAnimatedSnapshotFormats().contains(format)) {
         _animatedSnapshotFormat.set(format);
-        qDebug() << "Snapshot format set: " << format;
     } else {
         qDebug() << "Snapshot format not supported: " << format;
     }

From df56e047f300ea9e0ad8595c077bbd436d0a85bb Mon Sep 17 00:00:00 2001
From: ksuprynowicz <ksuprynowicz@post.pl>
Date: Sat, 30 Jul 2022 16:24:45 +0200
Subject: [PATCH 3/5] Reordered snapshot options

---
 interface/src/ui/PreferencesDialog.cpp | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp
index 3a3eb0d801..36df5c93f4 100644
--- a/interface/src/ui/PreferencesDialog.cpp
+++ b/interface/src/ui/PreferencesDialog.cpp
@@ -238,15 +238,6 @@ void setupPreferences() {
         auto preference = new BrowsePreference(SNAPSHOTS, "Put my snapshots here", getter, setter);
         preferences->addPreference(preference);
     }
-    {
-        auto getter = []()->float { return SnapshotAnimated::snapshotAnimatedDuration.get(); };
-        auto setter = [](float value) { SnapshotAnimated::snapshotAnimatedDuration.set(value); };
-        auto preference = new SpinnerPreference(SNAPSHOTS, "Animated Snapshot Duration", getter, setter);
-        preference->setMin(1);
-        preference->setMax(5);
-        preference->setStep(1);
-        preferences->addPreference(preference);
-    }
     
     {
         auto getter = []()->bool { 
@@ -280,6 +271,16 @@ void setupPreferences() {
         preferences->addPreference(preference);
     }
     
+    {
+        auto getter = []()->float { return SnapshotAnimated::snapshotAnimatedDuration.get(); };
+        auto setter = [](float value) { SnapshotAnimated::snapshotAnimatedDuration.set(value); };
+        auto preference = new SpinnerPreference(SNAPSHOTS, "Animated Snapshot Duration", getter, setter);
+        preference->setMin(1);
+        preference->setMax(5);
+        preference->setStep(1);
+        preferences->addPreference(preference);
+    }
+
     {
         auto getter = []()->bool { return !Menu::getInstance()->isOptionChecked(MenuOption::DisableActivityLogger); };
         auto setter = [](bool value) { Menu::getInstance()->setIsOptionChecked(MenuOption::DisableActivityLogger, !value); };

From 0ca8545c203e91fc6669878a98148db2ffb82c1d Mon Sep 17 00:00:00 2001
From: SilverfishVR <53531160+SilverfishVR@users.noreply.github.com>
Date: Thu, 1 Sep 2022 22:23:07 +0200
Subject: [PATCH 4/5] Update API docs to reflect changes

---
 .../src/scripting/WindowScriptingInterface.h  | 22 +++++++++----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h
index 3b54112f6c..0167ec0035 100644
--- a/interface/src/scripting/WindowScriptingInterface.h
+++ b/interface/src/scripting/WindowScriptingInterface.h
@@ -334,9 +334,9 @@ public slots:
      *     dimensions is adjusted in order to match the aspect ratio.
      * @param {string} [filename=""] - If a filename is not provided, the image is saved as "overte-snap-by-&lt;user 
      *     name&gt;-on-YYYY-MM-DD_HH-MM-SS".
-     *     <p>Still images are saved in JPEG or PNG format according to the extension provided &mdash; <code>".jpg"</code>, 
-     *     <code>".jpeg"</code>, or <code>".png"</code> &mdash; or if not provided then in JPEG format with an extension of 
-     *     <code>".jpg"</code>. Animated images are saved in GIF format.</p>
+     *     <p>Still images are saved in JPEG, PNG or WEBP format according to the extension provided &mdash; <code>".jpg"</code>, 
+     *     <code>".jpeg"</code>, <code>".png"</code>, or <code>".webp"</code> &mdash; or if not provided then in the format chosen in general settings, 
+     *     Default is PNG. Animated images are saved in GIF format.</p>
      *
      * @example <caption>Using the snapshot function and signals.</caption>
      * function onStillSnapshotTaken(path, notify) {
@@ -371,11 +371,11 @@ public slots:
      * @function Window.takeSecondaryCameraSnapshot
      * @param {boolean} [notify=true] - This value is passed on through the {@link Window.stillSnapshotTaken|stillSnapshotTaken}
      *     signal.
-     * @param {string} [filename=""] - If a filename is not provided, the image is saved as "overte-snap-by-&lt;user
+     * @param {string} [filename=""] - If a filename is not provided, the image is saved as "overte-snap-by-&lt;user 
      *     name&gt;-on-YYYY-MM-DD_HH-MM-SS".
-     *     <p>Images are saved in JPEG or PNG format according to the extension provided &mdash; <code>".jpg"</code>,
-     *     <code>".jpeg"</code>, or <code>".png"</code> &mdash; or if not provided then in JPEG format with an extension of
-     *     <code>".jpg"</code>.</p>
+     *     <p>Still images are saved in JPEG, PNG or WEBP format according to the extension provided &mdash; <code>".jpg"</code>, 
+     *     <code>".jpeg"</code>, <code>".png"</code>, or <code>".webp"</code> &mdash; or if not provided then in the format chosen in general settings, 
+     *     Default is PNG. Animated images are saved in GIF format.</p>
      */
     void takeSecondaryCameraSnapshot(const bool& notify = true, const QString& filename = QString());
 
@@ -390,11 +390,11 @@ public slots:
      *     otherwise it is saved as an equirectangular image.
      * @param {boolean} [notify=true] - This value is passed on through the {@link Window.stillSnapshotTaken|stillSnapshotTaken}
      *     signal.
-     * @param {string} [filename=""] - If a filename is not provided, the image is saved as "overte-snap-by-&lt;user
+     * @param {string} [filename=""] - If a filename is not provided, the image is saved as "overte-snap-by-&lt;user 
      *     name&gt;-on-YYYY-MM-DD_HH-MM-SS".
-     *     <p>Images are saved in JPEG or PNG format according to the extension provided &mdash; <code>".jpg"</code>,
-     *     <code>".jpeg"</code>, or <code>".png"</code> &mdash; or if not provided then in JPEG format with an extension of
-     *     <code>".jpg"</code>.</p>
+     *     <p>Still images are saved in JPEG, PNG or WEBP format according to the extension provided &mdash; <code>".jpg"</code>, 
+     *     <code>".jpeg"</code>, <code>".png"</code>, or <code>".webp"</code> &mdash; or if not provided then in the format chosen in general settings, 
+     *     Default is PNG. Animated images are saved in GIF format.</p>
      */
     void takeSecondaryCamera360Snapshot(const glm::vec3& cameraPosition, const bool& cubemapOutputFormat = false, const bool& notify = true, const QString& filename = QString());
 

From ad8da103b4055b6412d84a1071b88f78d79edf07 Mon Sep 17 00:00:00 2001
From: ksuprynowicz <ksuprynowicz@post.pl>
Date: Sun, 11 Sep 2022 15:55:30 +0200
Subject: [PATCH 5/5] Fixed default preference selection bug for screenshot
 formats and added short descriptions

---
 interface/src/ui/PreferencesDialog.cpp | 16 ++++++++++++----
 interface/src/ui/Snapshot.cpp          |  8 ++++++++
 interface/src/ui/Snapshot.h            | 14 ++++++++++++++
 3 files changed, 34 insertions(+), 4 deletions(-)

diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp
index 36df5c93f4..6d13f586d4 100644
--- a/interface/src/ui/PreferencesDialog.cpp
+++ b/interface/src/ui/PreferencesDialog.cpp
@@ -250,22 +250,30 @@ void setupPreferences() {
     }
 
     {
-        auto getter = []()->int { return DependencyManager::get<Snapshot>()->getAvailableSnapshotFormats().indexOf(DependencyManager::get<Snapshot>()->getSnapshotFormat()); };
+        auto getter = []()->int {
+            if (!DependencyManager::get<Snapshot>()->_snapshotFormat.isSet()) {
+                DependencyManager::get<Snapshot>()->setSnapshotFormat(DependencyManager::get<Snapshot>()->getAvailableSnapshotFormats()[0]);
+            }
+            return DependencyManager::get<Snapshot>()->getAvailableSnapshotFormats().indexOf(DependencyManager::get<Snapshot>()->getSnapshotFormat()); };
         auto setter = [](int value) { DependencyManager::get<Snapshot>()->setSnapshotFormat(DependencyManager::get<Snapshot>()->getAvailableSnapshotFormats()[value]); };
         auto preference = new RadioButtonsPreference(SNAPSHOTS, "Snapshot format", getter, setter);
         QStringList items;
-        items << DependencyManager::get<Snapshot>()->getAvailableSnapshotFormats();
+        items << DependencyManager::get<Snapshot>()->getAvailableSnapshotFormatsWithDescriptions();
         preference->setHeading("Snapshot format");
         preference->setItems(items);
         preferences->addPreference(preference);
     }
 
     {
-        auto getter = []()->int { return DependencyManager::get<Snapshot>()->getAvailableAnimatedSnapshotFormats().indexOf(DependencyManager::get<Snapshot>()->getAnimatedSnapshotFormat()); };
+        auto getter = []()->int {
+            if (!DependencyManager::get<Snapshot>()->_animatedSnapshotFormat.isSet()) {
+                DependencyManager::get<Snapshot>()->setAnimatedSnapshotFormat(DependencyManager::get<Snapshot>()->getAvailableAnimatedSnapshotFormats()[0]);
+            }
+            return DependencyManager::get<Snapshot>()->getAvailableAnimatedSnapshotFormats().indexOf(DependencyManager::get<Snapshot>()->getAnimatedSnapshotFormat()); };
         auto setter = [](int value) { DependencyManager::get<Snapshot>()->setAnimatedSnapshotFormat(DependencyManager::get<Snapshot>()->getAvailableAnimatedSnapshotFormats()[value]); };
         auto preference = new RadioButtonsPreference(SNAPSHOTS, "Animated snapshot format", getter, setter);
         QStringList items;
-        items << DependencyManager::get<Snapshot>()->getAvailableAnimatedSnapshotFormats();
+        items << DependencyManager::get<Snapshot>()->getAvailableAnimatedSnapshotFormatsWithDescriptions();
         preference->setHeading("Animated snapshot format");
         preference->setItems(items);
         preferences->addPreference(preference);
diff --git a/interface/src/ui/Snapshot.cpp b/interface/src/ui/Snapshot.cpp
index aaffbade3c..2884574767 100644
--- a/interface/src/ui/Snapshot.cpp
+++ b/interface/src/ui/Snapshot.cpp
@@ -552,6 +552,14 @@ QStringList Snapshot::getAvailableSnapshotFormats() {
     return QStringList({"png", "jpg", "webp"});
 }
 
+QStringList Snapshot::getAvailableSnapshotFormatsWithDescriptions() {
+    return QStringList({"PNG - lossless, large file size", "JPG - lossy, fast compression", "WEBP - lossy, higher quality and file size than JPG"});
+}
+
 QStringList Snapshot::getAvailableAnimatedSnapshotFormats() {
     return QStringList({"gif"});
 }
+
+QStringList Snapshot::getAvailableAnimatedSnapshotFormatsWithDescriptions() {
+    return QStringList({"GIF"});
+}
diff --git a/interface/src/ui/Snapshot.h b/interface/src/ui/Snapshot.h
index ad55186be4..61af735af7 100644
--- a/interface/src/ui/Snapshot.h
+++ b/interface/src/ui/Snapshot.h
@@ -135,12 +135,26 @@ public slots:
      */
     Q_INVOKABLE QStringList getAvailableSnapshotFormats();
 
+    /*@jsdoc
+     * Returns a list of supported snapshot formats with short descriptions.
+     * @function Snapshot.getAvailableSnapshotFormatsWithDescriptions
+     * @returns {Array.<string>} List of supported snapshot formats with short descriptions.
+     */
+    Q_INVOKABLE QStringList getAvailableSnapshotFormatsWithDescriptions();
+
     /*@jsdoc
      * Returns a list of supported animated snapshot formats.
      * @function Snapshot.getAvailableAnimatedSnapshotFormats
      * @returns {Array.<string>} List of supported animated snapshot formats.
      */
     Q_INVOKABLE QStringList getAvailableAnimatedSnapshotFormats();
+
+    /*@jsdoc
+     * Returns a list of supported animated snapshot formats with short descriptions.
+     * @function Snapshot.getAvailableAnimatedSnapshotFormatsWithDescriptions
+     * @returns {Array.<string>} List of supported animated snapshot formats with short descriptions.
+     */
+    Q_INVOKABLE QStringList getAvailableAnimatedSnapshotFormatsWithDescriptions();