mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2025-04-18 14:55:49 -04:00
Merge 1dd3a5f154eb7c114091afb0a63b945557e18368 into 86f74a00d0fb1a5ea351649450c12bb85772e496
This commit is contained in:
commit
e5764bcffb
2
.github/workflows/codeql.yml
vendored
2
.github/workflows/codeql.yml
vendored
@ -37,7 +37,7 @@ jobs:
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install build-essential cmake g++
|
||||
sudo apt install qtbase5-dev qtbase5-private-dev qttools5-dev qttools5-dev-tools libqt5svg5-dev libargon2-dev libkeyutils-dev libminizip-dev libbotan-2-dev libqrencode-dev zlib1g-dev asciidoctor libreadline-dev libpcsclite-dev libusb-1.0-0-dev libxi-dev libxtst-dev libqt5x11extras5-dev
|
||||
sudo apt install qtbase5-dev qtbase5-private-dev qttools5-dev qttools5-dev-tools libqt5svg5-dev libargon2-dev libkeyutils-dev libminizip-dev libbotan-2-dev libqrencode-dev zlib1g-dev asciidoctor libreadline-dev libpcsclite-dev libusb-1.0-0-dev libxi-dev libxtst-dev libqt5x11extras5-dev libpoppler-cpp-dev
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
|
@ -7252,6 +7252,26 @@ Do you want to overwrite it?</source>
|
||||
<source>Image format not supported</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Failed to load the PDF</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Failed to render the PDF page</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>The file is locked and cannot be processed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>The document contains no pages</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Unable to create the first page of the document</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QMessageBox</name>
|
||||
|
@ -390,6 +390,12 @@ target_link_libraries(keepassxc_gui
|
||||
${keeshare_LIB}
|
||||
${sshagent_LIB})
|
||||
|
||||
# Find Poppler
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(POPPLER_CPP REQUIRED IMPORTED_TARGET poppler-cpp)
|
||||
|
||||
target_link_libraries(keepassxc_gui PkgConfig::POPPLER_CPP)
|
||||
|
||||
if(APPLE)
|
||||
target_link_libraries(keepassxc_gui "-framework Foundation -framework AppKit -framework Carbon -framework Security -framework LocalAuthentication -framework ScreenCaptureKit")
|
||||
if(Qt5MacExtras_FOUND)
|
||||
|
@ -486,7 +486,9 @@ namespace Tools
|
||||
"application/x-yaml",
|
||||
"application/protobuf",
|
||||
};
|
||||
|
||||
static QStringList imageFormats = {"image/"};
|
||||
static QStringList pdfFormats = {"application/pdf"};
|
||||
|
||||
static auto isCompatible = [](const QString& format, const QStringList& list) {
|
||||
return std::any_of(
|
||||
@ -501,6 +503,10 @@ namespace Tools
|
||||
return MimeType::PlainText;
|
||||
}
|
||||
|
||||
if (isCompatible(mimeName, pdfFormats)) {
|
||||
return MimeType::Pdf;
|
||||
}
|
||||
|
||||
return MimeType::Unknown;
|
||||
}
|
||||
} // namespace Tools
|
||||
|
@ -119,6 +119,7 @@ namespace Tools
|
||||
{
|
||||
Image,
|
||||
PlainText,
|
||||
Pdf,
|
||||
Unknown
|
||||
};
|
||||
|
||||
|
@ -24,6 +24,13 @@
|
||||
#include <QTextCursor>
|
||||
#include <QtDebug>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <poppler-document.h>
|
||||
#include <poppler-image.h>
|
||||
#include <poppler-page-renderer.h>
|
||||
#include <poppler-page.h>
|
||||
|
||||
PreviewEntryAttachmentsDialog::PreviewEntryAttachmentsDialog(QWidget* parent)
|
||||
: QDialog(parent)
|
||||
, m_ui(new Ui::EntryAttachmentsDialog)
|
||||
@ -76,9 +83,80 @@ void PreviewEntryAttachmentsDialog::update()
|
||||
updateImageAttachment(m_data);
|
||||
} else if (m_type == Tools::MimeType::PlainText) {
|
||||
updateTextAttachment(m_data);
|
||||
} else if (m_type == Tools::MimeType::Pdf) {
|
||||
updatePdfAttachment(m_data);
|
||||
}
|
||||
}
|
||||
|
||||
void PreviewEntryAttachmentsDialog::updatePdfAttachment(const QByteArray& data)
|
||||
{
|
||||
if (!m_hashedImage.contains(data)) {
|
||||
poppler::byte_array array{std::cbegin(data), std::cend(data)};
|
||||
|
||||
auto doc = std::unique_ptr<poppler::document>(poppler::document::load_from_data(&array));
|
||||
if (!doc) {
|
||||
updateTextAttachment(tr("Failed to load the PDF").toUtf8());
|
||||
return;
|
||||
}
|
||||
|
||||
// Locked PDF files are not supported
|
||||
if (doc->is_locked()) {
|
||||
updateTextAttachment(tr("The file is locked and cannot be processed").toUtf8());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!doc->pages()) {
|
||||
updateTextAttachment(tr("The document contains no pages").toUtf8());
|
||||
return;
|
||||
}
|
||||
|
||||
// Preview the first page of the document.
|
||||
auto page = std::unique_ptr<poppler::page>(doc->create_page(0));
|
||||
if (!page) {
|
||||
updateTextAttachment(tr("Unable to create the first page of the document").toUtf8());
|
||||
return;
|
||||
}
|
||||
|
||||
poppler::page_renderer renderer{};
|
||||
renderer.set_image_format(poppler::image::format_argb32);
|
||||
|
||||
// Use a resolution of 150 DPI for the preview.
|
||||
constexpr int Dpi = 150;
|
||||
auto popplerImage = renderer.render_page(page.get(), Dpi, Dpi);
|
||||
if (!popplerImage.is_valid()) {
|
||||
updateTextAttachment(tr("Failed to render the PDF page").toUtf8());
|
||||
return;
|
||||
}
|
||||
|
||||
QImage image(reinterpret_cast<const uchar*>(popplerImage.const_data()),
|
||||
popplerImage.width(),
|
||||
popplerImage.height(),
|
||||
popplerImage.bytes_per_row(),
|
||||
QImage::Format_ARGB32);
|
||||
|
||||
if (image.isNull()) {
|
||||
updateTextAttachment(tr("Failed to render the PDF page").toUtf8());
|
||||
return;
|
||||
}
|
||||
|
||||
// Make a copy of the image to prevent data corruption once the Poppler image is destroyed.
|
||||
m_hashedImage.insert(data, image.copy());
|
||||
}
|
||||
|
||||
updateImageAttachment(m_hashedImage.value(data));
|
||||
}
|
||||
|
||||
QSize PreviewEntryAttachmentsDialog::calcucateImageSize()
|
||||
{
|
||||
// Scale the image to the contents rect minus another set of margins to avoid scrollbars
|
||||
auto margins = m_ui->attachmentTextEdit->contentsMargins();
|
||||
auto size = m_ui->attachmentTextEdit->contentsRect().size();
|
||||
size.setWidth(size.width() - margins.left() - margins.right());
|
||||
size.setHeight(size.height() - margins.top() - margins.bottom());
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void PreviewEntryAttachmentsDialog::updateTextAttachment(const QByteArray& data)
|
||||
{
|
||||
m_ui->attachmentTextEdit->setPlainText(QString::fromUtf8(data));
|
||||
@ -86,23 +164,26 @@ void PreviewEntryAttachmentsDialog::updateTextAttachment(const QByteArray& data)
|
||||
|
||||
void PreviewEntryAttachmentsDialog::updateImageAttachment(const QByteArray& data)
|
||||
{
|
||||
QImage image{};
|
||||
if (!image.loadFromData(data)) {
|
||||
updateTextAttachment(tr("Image format not supported").toUtf8());
|
||||
return;
|
||||
if (!m_hashedImage.contains(data)) {
|
||||
|
||||
QImage image{};
|
||||
if (!image.loadFromData(data)) {
|
||||
updateTextAttachment(tr("Image format not supported").toUtf8());
|
||||
return;
|
||||
}
|
||||
|
||||
m_hashedImage.insert(data, std::move(image));
|
||||
}
|
||||
|
||||
updateImageAttachment(m_hashedImage.value(data));
|
||||
}
|
||||
|
||||
void PreviewEntryAttachmentsDialog::updateImageAttachment(const QImage& image)
|
||||
{
|
||||
m_ui->attachmentTextEdit->clear();
|
||||
auto cursor = m_ui->attachmentTextEdit->textCursor();
|
||||
|
||||
// Scale the image to the contents rect minus another set of margins to avoid scrollbars
|
||||
auto margins = m_ui->attachmentTextEdit->contentsMargins();
|
||||
auto size = m_ui->attachmentTextEdit->contentsRect().size();
|
||||
size.setWidth(size.width() - margins.left() - margins.right());
|
||||
size.setHeight(size.height() - margins.top() - margins.bottom());
|
||||
image = image.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
|
||||
cursor.insertImage(image);
|
||||
cursor.insertImage(image.scaled(calcucateImageSize(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
||||
}
|
||||
|
||||
Tools::MimeType PreviewEntryAttachmentsDialog::attachmentType(const QByteArray& data) const
|
||||
@ -117,7 +198,5 @@ void PreviewEntryAttachmentsDialog::resizeEvent(QResizeEvent* event)
|
||||
{
|
||||
QDialog::resizeEvent(event);
|
||||
|
||||
if (m_type == Tools::MimeType::Image) {
|
||||
update();
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
@ -50,10 +50,16 @@ private:
|
||||
void update();
|
||||
void updateTextAttachment(const QByteArray& data);
|
||||
void updateImageAttachment(const QByteArray& data);
|
||||
void updatePdfAttachment(const QByteArray& data);
|
||||
void updateImageAttachment(const QImage& image);
|
||||
|
||||
QSize calcucateImageSize();
|
||||
|
||||
QScopedPointer<Ui::EntryAttachmentsDialog> m_ui;
|
||||
|
||||
QString m_name;
|
||||
QByteArray m_data;
|
||||
Tools::MimeType m_type{Tools::MimeType::Unknown};
|
||||
|
||||
QHash<QByteArray, QImage> m_hashedImage{};
|
||||
};
|
||||
|
@ -301,10 +301,13 @@ void TestTools::testMimeTypes()
|
||||
"image/svg+xml" // SVG images
|
||||
};
|
||||
|
||||
const QStringList pdfMimeType = {
|
||||
"application/pdf", // PDF documents
|
||||
};
|
||||
|
||||
const QStringList UnknownMimeTypes = {
|
||||
"audio/mpeg", // MPEG audio files
|
||||
"video/mp4", // MP4 video files
|
||||
"application/pdf", // PDF documents
|
||||
"application/zip", // ZIP archives
|
||||
"application/x-tar", // TAR archives
|
||||
"application/x-rar-compressed", // RAR archives
|
||||
@ -327,15 +330,15 @@ void TestTools::testMimeTypes()
|
||||
"application/x-shellscript", // Shell scripts
|
||||
};
|
||||
|
||||
for (const auto& mime : TextMimeTypes) {
|
||||
QCOMPARE(Tools::toMimeType(mime), Tools::MimeType::PlainText);
|
||||
}
|
||||
auto compare = [](const QStringList& mimeList, Tools::MimeType exptectedType) {
|
||||
for (const auto& mime : mimeList) {
|
||||
QCOMPARE(Tools::toMimeType(mime), exptectedType);
|
||||
}
|
||||
};
|
||||
|
||||
for (const auto& mime : ImageMimeTypes) {
|
||||
QCOMPARE(Tools::toMimeType(mime), Tools::MimeType::Image);
|
||||
}
|
||||
compare(TextMimeTypes, Tools::MimeType::PlainText);
|
||||
compare(ImageMimeTypes, Tools::MimeType::Image);
|
||||
compare(pdfMimeType, Tools::MimeType::Pdf);
|
||||
|
||||
for (const auto& mime : UnknownMimeTypes) {
|
||||
QCOMPARE(Tools::toMimeType(mime), Tools::MimeType::Unknown);
|
||||
}
|
||||
compare(UnknownMimeTypes, Tools::MimeType::Unknown);
|
||||
}
|
||||
|
@ -76,6 +76,10 @@
|
||||
{
|
||||
"name": "zlib",
|
||||
"version>=": "1.3"
|
||||
},
|
||||
{
|
||||
"name": "poppler",
|
||||
"version>=": "23.1.0"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user