Preprocess images before passport upload.

This commit is contained in:
John Preston 2018-04-20 21:34:51 +04:00
parent ab5f35e952
commit ab797b4dff
6 changed files with 114 additions and 6 deletions

View file

@ -1612,6 +1612,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_passport_stop" = "Stop";
"lng_passport_restart_sure" = "Unexpected error has occurred. Perhaps some changes were done from a different Telegram application. Would you like to restart this authorization?";
"lng_passport_restart" = "Restart";
"lng_passport_error_too_large" = "This file is too large.";
"lng_passport_error_bad_size" = "This image has bad dimensions.";
"lng_passport_error_cant_read" = "Can't read this file. Please choose an image.";
// Wnd specific

View file

@ -54,5 +54,9 @@ inline QString PassportCorruptedResetSure() {
return qsl("Are you sure you want to reset your Telegram Passport data?");
}
inline QString UnknownSecureScanError() {
return qsl("Unknown scan read error.");
}
} // namespace Hard
} // namespace Lang

View file

@ -843,9 +843,27 @@ void PanelController::editWithUpload(int index, int documentIndex) {
base::take(_scopeDocumentTypeBox);
editScope(index, documentIndex);
uploadScan(std::move(content));
}, [=](ReadScanError error) {
readScanError(error);
});
}
void PanelController::readScanError(ReadScanError error) {
show(Box<InformBox>([&] {
switch (error) {
case ReadScanError::FileTooLarge:
return lang(lng_passport_error_too_large);
case ReadScanError::BadImageSize:
return lang(lng_passport_error_bad_size);
case ReadScanError::CantReadImage:
return lang(lng_passport_error_cant_read);
case ReadScanError::Unknown:
return Lang::Hard::UnknownSecureScanError();
}
Unexpected("Error type in PanelController::readScanError.");
}()));
}
void PanelController::editScope(int index, int documentIndex) {
Expects(_panel != nullptr);
Expects(index >= 0 && index < _scopes.size());

View file

@ -18,6 +18,8 @@ class Panel;
struct EditDocumentScheme;
struct EditContactScheme;
enum class ReadScanError;
EditDocumentScheme GetDocumentScheme(
Scope::Type type,
base::optional<Value::Type> scansType = base::none);
@ -84,6 +86,7 @@ public:
void restoreSelfie();
rpl::producer<ScanInfo> scanUpdated() const;
rpl::producer<ScopeError> saveErrors() const;
void readScanError(ReadScanError error);
base::optional<rpl::producer<QString>> deleteValueLabel() const;
void deleteValue();

View file

@ -20,9 +20,49 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "core/file_utilities.h"
#include "lang/lang_keys.h"
#include "boxes/abstract_box.h"
#include "storage/storage_media_prepare.h"
#include "styles/style_passport.h"
namespace Passport {
namespace {
constexpr auto kMaxDimensions = 2048;
constexpr auto kMaxSize = 10 * 1024 * 1024;
constexpr auto kJpegQuality = 89;
static_assert(kMaxSize <= UseBigFilesFrom);
base::variant<ReadScanError, QByteArray> ProcessImage(QByteArray &&bytes) {
auto image = App::readImage(base::take(bytes));
if (image.isNull()) {
return ReadScanError::CantReadImage;
} else if (!Storage::ValidateThumbDimensions(image.width(), image.height())) {
return ReadScanError::BadImageSize;
}
if (std::max(image.width(), image.height()) > kMaxDimensions) {
image = std::move(image).scaled(
kMaxDimensions,
kMaxDimensions,
Qt::KeepAspectRatio,
Qt::SmoothTransformation);
}
auto result = QByteArray();
{
QBuffer buffer(&result);
if (!image.save(&buffer, QByteArray("JPG"), kJpegQuality)) {
return ReadScanError::Unknown;
}
base::take(image);
}
if (result.isEmpty()) {
return ReadScanError::Unknown;
} else if (result.size() > kMaxSize) {
return ReadScanError::FileTooLarge;
}
return result;
}
} // namespace
class ScanButton : public Ui::AbstractButton {
public:
@ -496,39 +536,71 @@ void EditScans::chooseScan() {
}
ChooseScan(this, [=](QByteArray &&content) {
_controller->uploadScan(std::move(content));
}, [=](ReadScanError error) {
_controller->readScanError(error);
});
}
void EditScans::chooseSelfie() {
ChooseScan(this, [=](QByteArray &&content) {
_controller->uploadSelfie(std::move(content));
}, [=](ReadScanError error) {
_controller->readScanError(error);
});
}
void EditScans::ChooseScan(
QPointer<QWidget> parent,
base::lambda<void(QByteArray&&)> callback) {
base::lambda<void(QByteArray&&)> doneCallback,
base::lambda<void(ReadScanError)> errorCallback) {
Expects(parent != nullptr);
const auto filter = FileDialog::AllFilesFilter()
+ qsl(";;Image files (*")
+ cImgExtensions().join(qsl(" *"))
+ qsl(")");
const auto guardedCallback = base::lambda_guarded(parent, callback);
const auto guardedCallback = base::lambda_guarded(parent, doneCallback);
const auto guardedError = base::lambda_guarded(parent, errorCallback);
const auto onMainCallback = [=](QByteArray content) {
crl::on_main([=, bytes = std::move(content)]() mutable {
guardedCallback(std::move(bytes));
});
};
const auto onMainError = [=](ReadScanError error) {
crl::on_main([=] {
guardedError(error);
});
};
const auto processImage = [=](QByteArray &&content) {
crl::async([=, bytes = std::move(content)]() mutable {
auto result = ProcessImage(std::move(bytes));
if (const auto error = base::get_if<ReadScanError>(&result)) {
onMainError(*error);
} else {
auto content = base::get_if<QByteArray>(&result);
Assert(content != nullptr);
onMainCallback(std::move(*content));
}
});
};
const auto processFile = [=](FileDialog::OpenResult &&result) {
if (result.paths.size() == 1) {
auto content = [&] {
QFile f(result.paths.front());
if (!f.open(QIODevice::ReadOnly)) {
if (f.size() > App::kImageSizeLimit) {
guardedError(ReadScanError::FileTooLarge);
return QByteArray();
} else if (!f.open(QIODevice::ReadOnly)) {
guardedError(ReadScanError::CantReadImage);
return QByteArray();
}
return f.readAll();
}();
if (!content.isEmpty()) {
guardedCallback(std::move(content));
processImage(std::move(content));
}
} else if (!result.remoteContent.isEmpty()) {
guardedCallback(std::move(result.remoteContent));
processImage(std::move(result.remoteContent));
}
};
FileDialog::GetOpenPath(

View file

@ -30,6 +30,13 @@ class PanelController;
class ScanButton;
struct ScanInfo;
enum class ReadScanError {
FileTooLarge,
CantReadImage,
BadImageSize,
Unknown,
};
class EditScans : public Ui::RpWidget {
public:
EditScans(
@ -44,7 +51,8 @@ public:
static void ChooseScan(
QPointer<QWidget> parent,
base::lambda<void(QByteArray&&)> callback);
base::lambda<void(QByteArray&&)> doneCallback,
base::lambda<void(ReadScanError)> errorCallback);
private:
void setupContent(const QString &header);