// // Snapshot.cpp // interface/src/ui // // Created by Stojce Slavkovski on 1/26/14. // Copyright 2014 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Application.h" #include "Snapshot.h" #include "SnapshotUploader.h" // filename format: hifi-snap-by-%username%-on-%date%_%time%_@-%location%.jpg // %1 <= username, %2 <= date and time, %3 <= current location const QString FILENAME_PATH_FORMAT = "hifi-snap-by-%1-on-%2.jpg"; const QString DATETIME_FORMAT = "yyyy-MM-dd_hh-mm-ss"; const QString SNAPSHOTS_DIRECTORY = "Snapshots"; const QString URL = "highfidelity_url"; Setting::Handle Snapshot::snapshotsLocation("snapshotsLocation"); SnapshotMetaData* Snapshot::parseSnapshotData(QString snapshotPath) { if (!QFile(snapshotPath).exists()) { return NULL; } QUrl url; if (snapshotPath.right(3) == "jpg") { QImage shot(snapshotPath); // no location data stored if (shot.text(URL).isEmpty()) { return NULL; } // parsing URL url = QUrl(shot.text(URL), QUrl::ParsingMode::StrictMode); } else { return NULL; } SnapshotMetaData* data = new SnapshotMetaData(); data->setURL(url); return data; } QString Snapshot::saveSnapshot(QImage image, const QString& filename) { QFile* snapshotFile = savedFileForSnapshot(image, false, filename); // we don't need the snapshot file, so close it, grab its filename and delete it snapshotFile->close(); QString snapshotPath = QFileInfo(*snapshotFile).absoluteFilePath(); delete snapshotFile; return snapshotPath; } QTemporaryFile* Snapshot::saveTempSnapshot(QImage image) { // return whatever we get back from saved file for snapshot return static_cast(savedFileForSnapshot(image, true)); } QFile* Snapshot::savedFileForSnapshot(QImage & shot, bool isTemporary, const QString& userSelectedFilename) { // adding URL to snapshot QUrl currentURL = DependencyManager::get()->currentPublicAddress(); shot.setText(URL, currentURL.toString()); QString username = DependencyManager::get()->getAccountInfo().getUsername(); // normalize username, replace all non alphanumeric with '-' username.replace(QRegExp("[^A-Za-z0-9_]"), "-"); QDateTime now = QDateTime::currentDateTime(); // If user has requested specific filename then use it, else create the filename // 'jpg" is appended, as the image is saved in jpg format. This is the case for all snapshots // (see definition of FILENAME_PATH_FORMAT) QString filename; if (!userSelectedFilename.isNull()) { filename = userSelectedFilename + ".jpg"; } else { filename = FILENAME_PATH_FORMAT.arg(username, now.toString(DATETIME_FORMAT)); } const int IMAGE_QUALITY = 100; if (!isTemporary) { QString snapshotFullPath = snapshotsLocation.get(); if (snapshotFullPath.isEmpty()) { snapshotFullPath = OffscreenUi::getExistingDirectory(nullptr, "Choose Snapshots Directory", QStandardPaths::writableLocation(QStandardPaths::DesktopLocation)); snapshotsLocation.set(snapshotFullPath); } if (!snapshotFullPath.isEmpty()) { // not cancelled if (!snapshotFullPath.endsWith(QDir::separator())) { snapshotFullPath.append(QDir::separator()); } snapshotFullPath.append(filename); QFile* imageFile = new QFile(snapshotFullPath); imageFile->open(QIODevice::WriteOnly); shot.save(imageFile, 0, IMAGE_QUALITY); imageFile->close(); return imageFile; } } // Either we were asked for a tempororary, or the user didn't set a directory. QTemporaryFile* imageTempFile = new QTemporaryFile(QDir::tempPath() + "/XXXXXX-" + filename); if (!imageTempFile->open()) { qDebug() << "Unable to open QTemporaryFile for temp snapshot. Will not save."; return NULL; } imageTempFile->setAutoRemove(isTemporary); shot.save(imageTempFile, 0, IMAGE_QUALITY); imageTempFile->close(); return imageTempFile; } void Snapshot::uploadSnapshot(const QString& filename, const QUrl& href) { const QString SNAPSHOT_UPLOAD_URL = "/api/v1/snapshots"; QUrl url = href; if (url.isEmpty()) { SnapshotMetaData* snapshotData = Snapshot::parseSnapshotData(filename); if (snapshotData) { url = snapshotData->getURL(); } delete snapshotData; } if (url.isEmpty()) { url = QUrl(DependencyManager::get()->currentShareableAddress()); } SnapshotUploader* uploader = new SnapshotUploader(url, filename); QFile* file = new QFile(filename); Q_ASSERT(file->exists()); file->open(QIODevice::ReadOnly); QHttpPart imagePart; if (filename.right(3) == "gif") { imagePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/gif")); } else { imagePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg")); } imagePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"image\"; filename=\"" + file->fileName() + "\"")); imagePart.setBodyDevice(file); QHttpMultiPart* multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType); file->setParent(multiPart); // we cannot delete the file now, so delete it with the multiPart multiPart->append(imagePart); auto accountManager = DependencyManager::get(); JSONCallbackParameters callbackParams(uploader, "uploadSuccess", uploader, "uploadFailure"); accountManager->sendRequest(SNAPSHOT_UPLOAD_URL, AccountManagerAuth::Required, QNetworkAccessManager::PostOperation, callbackParams, nullptr, multiPart); } QString Snapshot::getSnapshotsLocation() { return snapshotsLocation.get(""); } void Snapshot::setSnapshotsLocation(const QString& location) { snapshotsLocation.set(location); }