Skip to content

Commit

Permalink
Add PNG extractor
Browse files Browse the repository at this point in the history
Textual information, such as author information, creator software,
and a description can be stored in a PNG's tEXt, zTXt, and
iTXt chunks, [1].

libexiv2 can extract EXIF information out of PNGs but does not
support PNG Textual Information, see [2], however Qt's PNG handler
makes this information readily available as textKeys.

Unfortunately, the "Description" key is used by QImage to keep
track of the QImageIOHandler's Description and overrides the actual
PNG "Description" text, making it useless.

[1] https://www.w3.org/TR/PNG/#11keywords
[2] Exiv2/exiv2#1343
  • Loading branch information
kbroulik committed Jul 18, 2022
1 parent c665c74 commit 138880a
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 0 deletions.
11 changes: 11 additions & 0 deletions src/extractors/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -255,3 +255,14 @@ if(libappimage_FOUND AND KF5Config_FOUND AND Qt${QT_MAJOR_VERSION}Gui_FOUND)
TARGETS kfilemetadata_appimageextractor
DESTINATION ${KDE_INSTALL_PLUGINDIR}/kf${QT_MAJOR_VERSION}/kfilemetadata)
endif()

add_library(kfilemetadata_pngextractor MODULE pngextractor.cpp )
target_link_libraries(kfilemetadata_pngextractor
KF5::FileMetaData
Qt${QT_MAJOR_VERSION}::Gui
)

set_target_properties(kfilemetadata_pngextractor PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/kf${QT_MAJOR_VERSION}/kfilemetadata")
install(
TARGETS kfilemetadata_pngextractor
DESTINATION ${KDE_INSTALL_PLUGINDIR}/kf${QT_MAJOR_VERSION}/kfilemetadata)
90 changes: 90 additions & 0 deletions src/extractors/pngextractor.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
SPDX-FileCopyrightText: 2022 Kai Uwe Broulik <kde@broulik.de>
SPDX-License-Identifier: LGPL-2.1-or-later
*/

#include "pngextractor.h"
#include "propertyinfo.h"

#include <QImageReader>

using namespace KFileMetaData;

// Keywords specified in https://www.w3.org/TR/PNG/#11keywords
static const struct {
QString key;
Property::Property property;
} s_textMapping[] = {
// Short (one line) title or caption for image
{QStringLiteral("Title"), Property::Title},
// Name of image's creator
{QStringLiteral("Author"), Property::Author},
// Description of image (possibly long)
// Unfortunately, QImage puts all text keys with spaces, such as
// "Raw profile type exif", into the "Description" key,
// (cf. qt_getImageTextFromDescription), overriding the actual
// PNG description, and making it useless.
//{QStringLiteral("Description"), Property::Description},
// Copyright notice
{QStringLiteral("Copyright"), Property::Copyright},
// Time of original image creation
{QStringLiteral("Creation Time"), Property::CreationDate},
// Software used to create the image
{QStringLiteral("Software"), Property::Generator},
// Disclaimer - Legal disclaimer
// Warning - Warning of nature of content
// Source - Device used to create the image
// Miscellaneous comment
{QStringLiteral("Comment"), Property::Comment},
};

PngExtractor::PngExtractor(QObject* parent)
: ExtractorPlugin(parent)
{
}

QStringList PngExtractor::mimetypes() const
{
return {
QStringLiteral("image/png")
};
}

void PngExtractor::extract(ExtractionResult* result)
{
QImageReader reader(result->inputUrl(), "png");
if (!reader.canRead()) {
return;
}

result->addType(Type::Image);

for (const auto &mapping : s_textMapping) {
QString text = reader.text(mapping.key);
if (text.isEmpty()) {
// Spec says, keywords are case-sensitive but of course the real world looks different.
text = reader.text(mapping.key.toLower());
}
if (text.isEmpty()) {
continue;
}

const auto propertyInfo = PropertyInfo(mapping.property);

if (propertyInfo.valueType() == QVariant::DateTime) {
// "For the Creation Time keyword, the date format defined in section 5.2.14 of RFC 1123 is suggested"
// which in turn references RFC822...
const QDateTime dt = QDateTime::fromString(text, Qt::RFC2822Date);

if (!dt.isValid()) {
continue;
}

result->add(mapping.property, dt);
continue;
}

result->add(mapping.property, text);
}
}
31 changes: 31 additions & 0 deletions src/extractors/pngextractor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
SPDX-FileCopyrightText: 2022 Kai Uwe Broulik <kde@broulik.de>
SPDX-License-Identifier: LGPL-2.1-or-later
*/

#ifndef PNGEXTRACTOR_H
#define PNGEXTRACTOR_H

#include "extractorplugin.h"

namespace KFileMetaData
{

class PngExtractor : public ExtractorPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.kde.kf5.kfilemetadata.ExtractorPlugin"
FILE "pngextractor.json")
Q_INTERFACES(KFileMetaData::ExtractorPlugin)

public:
explicit PngExtractor(QObject *parent = nullptr);

void extract(ExtractionResult *result) override;
QStringList mimetypes() const override;
};

} // namespace KFileMetaData

#endif // PNGEXTRACTOR_H
7 changes: 7 additions & 0 deletions src/extractors/pngextractor.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"Name" : "PngExtractor",
"Id" : "org.kde.pngextractor",
"MimeTypes" : {
"image/png" : { "version" : "0.0" }
}
}

0 comments on commit 138880a

Please sign in to comment.