8#include "microexif_p.h"
12#include <QCoreApplication>
18#define TIFF_IMAGEWIDTH 0x100
19#define TIFF_IMAGEHEIGHT 0x101
20#define TIFF_BITSPERSAMPLE 0x102
21#define TIFF_IMAGEDESCRIPTION 0x10E
22#define TIFF_MAKE 0x10F
23#define TIFF_MODEL 0x110
24#define TIFF_ORIENT 0x0112
25#define TIFF_XRES 0x011A
26#define TIFF_YRES 0x011B
27#define TIFF_URES 0x0128
28#define TIFF_SOFTWARE 0x0131
29#define TIFF_ARTIST 0x013B
30#define TIFF_DATETIME 0x0132
31#define TIFF_COPYRIGHT 0x8298
33#define TIFF_VAL_URES_NOABSOLUTE 1
34#define TIFF_VAL_URES_INCH 2
35#define TIFF_VAL_URES_CENTIMETER 3
38#define EXIF_EXIFIFD 0x8769
39#define EXIF_GPSIFD 0x8825
40#define EXIF_OFFSETTIME 0x9010
41#define EXIF_COLORSPACE 0xA001
42#define EXIF_PIXELXDIM 0xA002
43#define EXIF_PIXELYDIM 0xA003
44#define EXIF_IMAGEUNIQUEID 0xA420
45#define EXIF_BODYSERIALNUMBER 0xA431
46#define EXIF_LENSMAKE 0xA433
47#define EXIF_LENSMODEL 0xA434
48#define EXIF_LENSSERIALNUMBER 0xA435
49#define EXIF_IMAGETITLE 0xA436
50#define EXIF_EXIFVERSION 0x9000
52#define EXIF_VAL_COLORSPACE_SRGB 1
53#define EXIF_VAL_COLORSPACE_UNCAL 0xFFFF
55#define GPS_GPSVERSION 0
56#define GPS_LATITUDEREF 1
58#define GPS_LONGITUDEREF 3
59#define GPS_LONGITUDE 4
60#define GPS_ALTITUDEREF 5
63#define EXIF_TAG_VALUE(n, byteSize) (((n) << 6) | ((byteSize) & 0x3F))
64#define EXIF_TAG_SIZEOF(dataType) (quint16(dataType) & 0x3F)
65#define EXIF_TAG_DATATYPE(dataType) (quint16(dataType) >> 6)
67enum class ExifTagType : quint16 {
69 Byte = EXIF_TAG_VALUE(1, 1),
70 Ascii = EXIF_TAG_VALUE(2, 1),
71 Short = EXIF_TAG_VALUE(3, 2),
72 Long = EXIF_TAG_VALUE(4, 4),
73 Rational = EXIF_TAG_VALUE(5, 8),
76 SByte = EXIF_TAG_VALUE(6, 1),
77 Undefined = EXIF_TAG_VALUE(7, 1),
78 SShort = EXIF_TAG_VALUE(8, 2),
79 SLong = EXIF_TAG_VALUE(9, 4),
80 SRational = EXIF_TAG_VALUE(10, 8),
82 Float = EXIF_TAG_VALUE(11, 4),
83 Double = EXIF_TAG_VALUE(12, 8),
84 Ifd = EXIF_TAG_VALUE(13, 4),
87 Long8 = EXIF_TAG_VALUE(16, 8),
88 SLong8 = EXIF_TAG_VALUE(17, 8),
89 Ifd8 = EXIF_TAG_VALUE(18, 8),
92 Utf8 = EXIF_TAG_VALUE(129, 1)
97using TagInfo = std::pair<quint16, ExifTagType>;
105static const KnownTags staticTagTypes = {
106 TagInfo(TIFF_IMAGEWIDTH, ExifTagType::Long),
107 TagInfo(TIFF_IMAGEHEIGHT, ExifTagType::Long),
108 TagInfo(TIFF_BITSPERSAMPLE, ExifTagType::Short),
109 TagInfo(TIFF_IMAGEDESCRIPTION, ExifTagType::Ascii),
110 TagInfo(TIFF_MAKE, ExifTagType::Ascii),
111 TagInfo(TIFF_MODEL, ExifTagType::Ascii),
112 TagInfo(TIFF_ORIENT, ExifTagType::Short),
113 TagInfo(TIFF_XRES, ExifTagType::Rational),
114 TagInfo(TIFF_YRES, ExifTagType::Rational),
115 TagInfo(TIFF_URES, ExifTagType::Short),
116 TagInfo(TIFF_SOFTWARE, ExifTagType::Ascii),
117 TagInfo(TIFF_ARTIST, ExifTagType::Ascii),
118 TagInfo(TIFF_DATETIME, ExifTagType::Ascii),
119 TagInfo(TIFF_COPYRIGHT, ExifTagType::Ascii),
120 TagInfo(EXIF_EXIFIFD, ExifTagType::Long),
121 TagInfo(EXIF_GPSIFD, ExifTagType::Long),
122 TagInfo(EXIF_OFFSETTIME, ExifTagType::Ascii),
123 TagInfo(EXIF_COLORSPACE, ExifTagType::Short),
124 TagInfo(EXIF_PIXELXDIM, ExifTagType::Long),
125 TagInfo(EXIF_PIXELYDIM, ExifTagType::Long),
126 TagInfo(EXIF_IMAGEUNIQUEID, ExifTagType::Ascii),
127 TagInfo(EXIF_BODYSERIALNUMBER, ExifTagType::Ascii),
128 TagInfo(EXIF_LENSMAKE, ExifTagType::Ascii),
129 TagInfo(EXIF_LENSMODEL, ExifTagType::Ascii),
130 TagInfo(EXIF_LENSSERIALNUMBER, ExifTagType::Ascii),
131 TagInfo(EXIF_IMAGETITLE, ExifTagType::Ascii),
132 TagInfo(EXIF_EXIFVERSION, ExifTagType::Undefined)
140static const KnownTags staticGpsTagTypes = {
141 TagInfo(GPS_GPSVERSION, ExifTagType::Byte),
142 TagInfo(GPS_LATITUDEREF, ExifTagType::Ascii),
143 TagInfo(GPS_LATITUDE, ExifTagType::Rational),
144 TagInfo(GPS_LONGITUDEREF, ExifTagType::Ascii),
145 TagInfo(GPS_LONGITUDE, ExifTagType::Rational),
146 TagInfo(GPS_ALTITUDEREF, ExifTagType::Byte),
147 TagInfo(GPS_ALTITUDE, ExifTagType::Rational)
157 std::pair<quint16, QString>(TIFF_IMAGEDESCRIPTION, QStringLiteral(META_KEY_DESCRIPTION)),
158 std::pair<quint16, QString>(TIFF_ARTIST, QStringLiteral(META_KEY_AUTHOR)),
159 std::pair<quint16, QString>(TIFF_SOFTWARE, QStringLiteral(META_KEY_SOFTWARE)),
160 std::pair<quint16, QString>(TIFF_COPYRIGHT, QStringLiteral(META_KEY_COPYRIGHT)),
161 std::pair<quint16, QString>(TIFF_MAKE, QStringLiteral(META_KEY_MANUFACTURER)),
162 std::pair<quint16, QString>(TIFF_MODEL, QStringLiteral(META_KEY_MODEL))
172 std::pair<quint16, QString>(EXIF_BODYSERIALNUMBER, QStringLiteral(META_KEY_SERIALNUMBER)),
173 std::pair<quint16, QString>(EXIF_LENSMAKE, QStringLiteral(META_KEY_LENS_MANUFACTURER)),
174 std::pair<quint16, QString>(EXIF_LENSMODEL, QStringLiteral(META_KEY_LENS_MODEL)),
175 std::pair<quint16, QString>(EXIF_LENSSERIALNUMBER, QStringLiteral(META_KEY_LENS_SERIALNUMBER)),
176 std::pair<quint16, QString>(EXIF_IMAGETITLE, QStringLiteral(META_KEY_TITLE)),
185static qint16 timeOffset(
const QString& offset)
187 if (offset.
size() != 6 || offset.
at(3) != u
':')
193 auto mm = offset.
mid(4, 2).
toInt(&ok) * (hh < 0 ? -1 : 1);
196 return qint16(hh * 60 + mm);
204static QString timeOffset(qint16 offset)
206 auto absOff = quint16(std::abs(offset));
207 return QStringLiteral(
"%1%2:%3")
208 .arg(offset < 0 ? QStringLiteral(
"-") : QStringLiteral(
"+"))
209 .arg(absOff / 60, 2, 10,
QChar(u
'0'))
210 .arg(absOff % 60, 2, 10,
QChar(u
'0'));
223 if (order == 0x4949) {
225 }
else if (order == 0x4d4d) {
264static qint32 countBytes(
const ExifTagType &dataType,
const QVariant &value)
267 if (dataType == ExifTagType::Ascii) {
269 }
else if (dataType == ExifTagType::Utf8) {
271 }
else if (dataType == ExifTagType::Undefined) {
273 }
else if (dataType == ExifTagType::Byte) {
275 }
else if (dataType == ExifTagType::Short) {
277 }
else if (dataType == ExifTagType::Long || dataType == ExifTagType::Ifd) {
279 }
else if (dataType == ExifTagType::SByte) {
281 }
else if (dataType == ExifTagType::SShort) {
283 }
else if (dataType == ExifTagType::SLong) {
285 }
else if (dataType == ExifTagType::Rational || dataType == ExifTagType::SRational || dataType == ExifTagType::Double) {
287 }
else if (dataType == ExifTagType::Float) {
290 return std::max(1, count);
299 for (;l.size() < qsizetype(4 /
sizeof(T));)
305inline qint32 rationalPrecision(
double v)
308 return 8 - qBound(0, v < 1 ? 8 :
int(std::log10(v)), 8);
318 auto den = std::pow(10, rationalPrecision(v));
319 ds << T(qRound(v * den));
328 for (
auto n = ba.size(); n < 4; ++n)
334 if (dataType == ExifTagType::Ascii) {
336 }
else if (dataType == ExifTagType::Utf8) {
338 }
else if (dataType == ExifTagType::Undefined) {
340 }
else if (dataType == ExifTagType::Byte) {
341 writeList<quint8>(ds, value);
342 }
else if (dataType == ExifTagType::SByte) {
343 writeList<qint8>(ds, value);
344 }
else if (dataType == ExifTagType::Short) {
345 writeList<quint16>(ds, value);
346 }
else if (dataType == ExifTagType::SShort) {
347 writeList<qint16>(ds, value);
348 }
else if (dataType == ExifTagType::Long || dataType == ExifTagType::Ifd) {
349 writeList<quint32>(ds, value);
350 }
else if (dataType == ExifTagType::SLong) {
351 writeList<qint32>(ds, value);
352 }
else if (dataType == ExifTagType::Rational) {
353 writeRationalList<quint32>(ds, value);
354 }
else if (dataType == ExifTagType::SRational) {
355 writeRationalList<qint32>(ds, value);
367static bool writeIfd(
QDataStream &ds,
const MicroExif::Tags &tags, TagPos &positions, quint32 pos = 0,
const KnownTags &knownTags = staticTagTypes)
371 if (!updatePos(ds, pos))
374 auto keys = tags.keys();
375 auto entries = quint16(keys.size());
377 for (
auto &&key : keys) {
378 if (!knownTags.contains(key)) {
381 auto value = tags.
value(key);
382 auto dataType = knownTags.value(key);
383 auto count = countBytes(dataType, value);
386 ds << quint16(EXIF_TAG_DATATYPE(dataType));
387 ds << quint32(count);
389 auto valueSize = count * EXIF_TAG_SIZEOF(dataType);
393 writeData(ds, value, dataType);
400 for (
auto &&key : keys) {
401 if (!knownTags.contains(key)) {
405 auto value = tags.
value(key);
406 auto dataType = knownTags.value(key);
407 auto count = countBytes(dataType, value);
408 auto valueSize = count * EXIF_TAG_SIZEOF(dataType);
411 if (!updatePos(ds, positions.
value(key)))
413 writeData(ds, value, dataType);
424 for (quint32 i = 0; i < count; ++i) {
428 for (
auto n = count; n < quint32(4 /
sizeof(T)); ++n) {
438 for (quint32 i = 0; i < count; ++i) {
443 l.
append(den == 0 ? 0 :
double(num) /
double(den));
455 for (quint32 i = 0; i < count; ++i) {
459 if (asciiz && l.
at(l.
size() - 1) == 0) {
462 for (
auto n = count; n < 4; ++n) {
477static bool readIfd(
QDataStream &ds, MicroExif::Tags &tags, quint32 pos = 0,
const KnownTags &knownTags = staticTagTypes, quint32 *nextIfd =
nullptr)
479 auto localNextIfd = quint32();
480 if (nextIfd ==
nullptr)
481 nextIfd = &localNextIfd;
484 auto device = ds.
device();
485 if (pos && !device->seek(pos))
493 for (quint16 i = 0; i < entries; ++i) {
504 if (!knownTags.contains(tagId)) {
511 auto toRead = qint64(count) * EXIF_TAG_SIZEOF(knownTags.value(tagId));
512 if (toRead > qint64(device->size()))
515 auto curPos = qint64();
519 curPos = device->pos();
520 if (!device->seek(value))
524 if (dataType == EXIF_TAG_DATATYPE(ExifTagType::Ascii) || dataType == EXIF_TAG_DATATYPE(ExifTagType::Utf8)) {
525 auto l = readBytes(ds, count,
true);
528 }
else if (dataType == EXIF_TAG_DATATYPE(ExifTagType::Undefined)) {
529 auto l = readBytes(ds, count,
false);
531 tags.insert(tagId, l);
532 }
else if (dataType == EXIF_TAG_DATATYPE(ExifTagType::Byte)) {
533 auto l = readList<quint8>(ds, count);
535 }
else if (dataType == EXIF_TAG_DATATYPE(ExifTagType::SByte)) {
536 auto l = readList<qint8>(ds, count);
538 }
else if (dataType == EXIF_TAG_DATATYPE(ExifTagType::Short)) {
539 auto l = readList<quint16>(ds, count);
541 }
else if (dataType == EXIF_TAG_DATATYPE(ExifTagType::SShort)) {
542 auto l = readList<qint16>(ds, count);
544 }
else if (dataType == EXIF_TAG_DATATYPE(ExifTagType::Long) || dataType == EXIF_TAG_DATATYPE(ExifTagType::Ifd)) {
545 auto l = readList<quint32>(ds, count);
547 }
else if (dataType == EXIF_TAG_DATATYPE(ExifTagType::SLong)) {
548 auto l = readList<qint32>(ds, count);
550 }
else if (dataType == EXIF_TAG_DATATYPE(ExifTagType::Rational)) {
551 auto l = readRationalList<quint32>(ds, count);
553 }
else if (dataType == EXIF_TAG_DATATYPE(ExifTagType::SRational)) {
554 auto l = readRationalList<qint32>(ds, count);
558 if (curPos > 0 && !device->seek(curPos))
566MicroExif::MicroExif()
571void MicroExif::clear()
578bool MicroExif::isEmpty()
const
580 return m_tiffTags.isEmpty() && m_exifTags.isEmpty() && m_gpsTags.isEmpty();
583double MicroExif::horizontalResolution()
const
585 auto u = m_tiffTags.value(TIFF_URES).toUInt();
586 auto v = m_tiffTags.value(TIFF_XRES).toDouble();
587 if (u == TIFF_VAL_URES_CENTIMETER)
592void MicroExif::setHorizontalResolution(
double hres)
594 auto u = m_tiffTags.value(TIFF_URES).toUInt();
595 if (u == TIFF_VAL_URES_CENTIMETER) {
597 }
else if (u < TIFF_VAL_URES_INCH) {
598 m_tiffTags.insert(TIFF_URES, TIFF_VAL_URES_INCH);
600 m_tiffTags.insert(TIFF_XRES, hres);
603double MicroExif::verticalResolution()
const
605 auto u = m_tiffTags.value(TIFF_URES).toUInt();
606 auto v = m_tiffTags.value(TIFF_YRES).toDouble();
607 if (u == TIFF_VAL_URES_CENTIMETER)
612void MicroExif::setVerticalResolution(
double vres)
614 auto u = m_tiffTags.value(TIFF_URES).toUInt();
615 if (u == TIFF_VAL_URES_CENTIMETER) {
617 }
else if (u < TIFF_VAL_URES_INCH) {
618 m_tiffTags.insert(TIFF_URES, TIFF_VAL_URES_INCH);
620 m_tiffTags.insert(TIFF_YRES, vres);
625 if (m_exifTags.value(EXIF_COLORSPACE).toUInt() == EXIF_VAL_COLORSPACE_SRGB)
627 return QColorSpace();
630void MicroExif::setColorSpace(
const QColorSpace &cs)
632 auto srgb = cs.
transferFunction() == QColorSpace::TransferFunction::SRgb && cs.
primaries() == QColorSpace::Primaries::SRgb;
633 m_exifTags.insert(EXIF_COLORSPACE, srgb ? EXIF_VAL_COLORSPACE_SRGB : EXIF_VAL_COLORSPACE_UNCAL);
639 m_exifTags.insert(EXIF_COLORSPACE, srgb ? EXIF_VAL_COLORSPACE_SRGB : EXIF_VAL_COLORSPACE_UNCAL);
642qint32 MicroExif::width()
const
644 return m_tiffTags.value(TIFF_IMAGEWIDTH).toUInt();
647void MicroExif::setWidth(qint32 w)
649 m_tiffTags.insert(TIFF_IMAGEWIDTH, w);
650 m_exifTags.insert(EXIF_PIXELXDIM, w);
653qint32 MicroExif::height()
const
655 return m_tiffTags.value(TIFF_IMAGEHEIGHT).toUInt();
658void MicroExif::setHeight(qint32 h)
660 m_tiffTags.insert(TIFF_IMAGEHEIGHT, h);
661 m_exifTags.insert(EXIF_PIXELYDIM, h);
664quint16 MicroExif::orientation()
const
666 return m_tiffTags.value(TIFF_ORIENT).toUInt();
669void MicroExif::setOrientation(quint16 orient)
671 if (orient < 1 || orient > 8)
672 m_tiffTags.remove(TIFF_ORIENT);
674 m_tiffTags.insert(TIFF_ORIENT, orient);
679 switch (orientation()) {
735QString MicroExif::software()
const
737 return tiffString(TIFF_SOFTWARE);
740void MicroExif::setSoftware(
const QString &s)
742 setTiffString(TIFF_SOFTWARE, s);
745QString MicroExif::description()
const
747 return tiffString(TIFF_IMAGEDESCRIPTION);
750void MicroExif::setDescription(
const QString &s)
752 setTiffString(TIFF_IMAGEDESCRIPTION, s);
755QString MicroExif::artist()
const
757 return tiffString(TIFF_ARTIST);
760void MicroExif::setArtist(
const QString &s)
762 setTiffString(TIFF_ARTIST, s);
765QString MicroExif::copyright()
const
767 return tiffString(TIFF_COPYRIGHT);
770void MicroExif::setCopyright(
const QString &s)
772 setTiffString(TIFF_COPYRIGHT, s);
777 return tiffString(TIFF_MAKE);
780void MicroExif::setMake(
const QString &s)
782 setTiffString(TIFF_MAKE, s);
785QString MicroExif::model()
const
787 return tiffString(TIFF_MODEL);
790void MicroExif::setModel(
const QString &s)
792 setTiffString(TIFF_MODEL, s);
795QString MicroExif::serialNumber()
const
797 return tiffString(EXIF_BODYSERIALNUMBER);
800void MicroExif::setSerialNumber(
const QString &s)
802 setTiffString(EXIF_BODYSERIALNUMBER, s);
805QString MicroExif::lensMake()
const
807 return tiffString(EXIF_LENSMAKE);
810void MicroExif::setLensMake(
const QString &s)
812 setTiffString(EXIF_LENSMAKE, s);
815QString MicroExif::lensModel()
const
817 return tiffString(EXIF_LENSMODEL);
820void MicroExif::setLensModel(
const QString &s)
822 setTiffString(EXIF_LENSMODEL, s);
825QString MicroExif::lensSerialNumber()
const
827 return tiffString(EXIF_LENSSERIALNUMBER);
830void MicroExif::setLensSerialNumber(
const QString &s)
832 setTiffString(EXIF_LENSSERIALNUMBER, s);
838 auto ofTag = exifString(EXIF_OFFSETTIME);
839 if (dt.isValid() && !ofTag.isEmpty())
844void MicroExif::setDateTime(
const QDateTime &dt)
847 m_tiffTags.remove(TIFF_DATETIME);
848 m_exifTags.remove(EXIF_OFFSETTIME);
851 setTiffString(TIFF_DATETIME, dt.
toString(QStringLiteral(
"yyyy:MM:dd HH:mm:ss")));
852 setExifString(EXIF_OFFSETTIME, timeOffset(dt.
offsetFromUtc() / 60));
855QString MicroExif::title()
const
857 return exifString(EXIF_IMAGETITLE);
860void MicroExif::setImageTitle(
const QString &s)
862 setExifString(EXIF_IMAGETITLE, s);
865QUuid MicroExif::uniqueId()
const
867 auto s = exifString(EXIF_IMAGEUNIQUEID);
868 if (s.length() == 32) {
869 auto tmp = QStringLiteral(
"%1-%2-%3-%4-%5").arg(s.left(8), s.mid(8, 4), s.mid(12, 4), s.mid(16, 4), s.mid(20));
875void MicroExif::setUniqueId(
const QUuid &uuid)
878 setExifString(EXIF_IMAGEUNIQUEID, QString());
883double MicroExif::latitude()
const
885 auto ref = gpsString(GPS_LATITUDEREF).toUpper();
886 if (ref != QStringLiteral(
"N") && ref != QStringLiteral(
"S"))
888 auto lat = m_gpsTags.value(GPS_LATITUDE).value<QList<double>>();
891 auto degree = lat.at(0) + lat.at(1) / 60 + lat.at(2) / 3600;
892 if (degree < -90.0 || degree > 90.0)
894 return ref == QStringLiteral(
"N") ? degree : -degree;
897void MicroExif::setLatitude(
double degree)
899 if (degree < -90.0 || degree > 90.0)
901 auto adeg = qAbs(degree);
902 auto min = (adeg - int(adeg)) * 60;
903 auto sec = (min - int(min)) * 60;
904 m_gpsTags.insert(GPS_LATITUDEREF, degree < 0 ? QStringLiteral(
"S") : QStringLiteral(
"N"));
905 m_gpsTags.insert(GPS_LATITUDE,
QVariant::fromValue(QList<double>() <<
int(adeg) <<
int(min) << sec));
908double MicroExif::longitude()
const
910 auto ref = gpsString(GPS_LONGITUDEREF).toUpper();
911 if (ref != QStringLiteral(
"E") && ref != QStringLiteral(
"W"))
913 auto lon = m_gpsTags.value(GPS_LONGITUDE).value<QList<double>>();
916 auto degree = lon.at(0) + lon.at(1) / 60 + lon.at(2) / 3600;
917 if (degree < -180.0 || degree > 180.0)
919 return ref == QStringLiteral(
"E") ? degree : -degree;
922void MicroExif::setLongitude(
double degree)
924 if (degree < -180.0 || degree > 180.0)
926 auto adeg = qAbs(degree);
927 auto min = (adeg - int(adeg)) * 60;
928 auto sec = (min - int(min)) * 60;
929 m_gpsTags.insert(GPS_LONGITUDEREF, degree < 0 ? QStringLiteral(
"W") : QStringLiteral(
"E"));
930 m_gpsTags.insert(GPS_LONGITUDE,
QVariant::fromValue(QList<double>() <<
int(adeg) <<
int(min) << sec));
933double MicroExif::altitude()
const
935 auto ref = m_gpsTags.value(GPS_ALTITUDEREF);
938 auto alt = m_gpsTags.value(GPS_ALTITUDE).toDouble();
939 return (ref.toInt() == 0 || ref.toInt() == 2) ? alt : -alt;
942void MicroExif::setAltitude(
double meters)
944 m_gpsTags.insert(GPS_ALTITUDEREF, quint8(meters < 0 ? 1 : 0));
945 m_gpsTags.insert(GPS_ALTITUDE, meters);
953 if (!write(&buf, byteOrder))
961 if (device ==
nullptr || device->
isSequential() || isEmpty())
964 QDataStream ds(device);
966 if (!writeHeader(ds))
975void MicroExif::toImageMetadata(
QImage &targetImage,
bool replaceExisting)
const
978 for (
auto &&p : tiffStrMap) {
979 if (!replaceExisting && !targetImage.
text(p.second).
isEmpty())
981 auto s = tiffString(p.first);
983 targetImage.
setText(p.second, s);
987 for (
auto &&p : exifStrMap) {
988 if (!replaceExisting && !targetImage.
text(p.second).
isEmpty())
990 auto s = exifString(p.first);
992 targetImage.
setText(p.second, s);
996 if (replaceExisting || targetImage.
text(QStringLiteral(META_KEY_CREATIONDATE)).isEmpty()) {
997 auto dt = dateTime();
1003 if (replaceExisting || targetImage.
text(QStringLiteral(META_KEY_ALTITUDE)).isEmpty()) {
1004 auto v = altitude();
1006 targetImage.
setText(QStringLiteral(META_KEY_ALTITUDE), QStringLiteral(
"%1").arg(v, 0,
'g', 9));
1008 if (replaceExisting || targetImage.
text(QStringLiteral(META_KEY_LATITUDE)).isEmpty()) {
1009 auto v = latitude();
1011 targetImage.
setText(QStringLiteral(META_KEY_LATITUDE), QStringLiteral(
"%1").arg(v, 0,
'g', 9));
1013 if (replaceExisting || targetImage.
text(QStringLiteral(META_KEY_LONGITUDE)).isEmpty()) {
1014 auto v = longitude();
1016 targetImage.
setText(QStringLiteral(META_KEY_LONGITUDE), QStringLiteral(
"%1").arg(v, 0,
'g', 9));
1020MicroExif MicroExif::fromByteArray(
const QByteArray &ba)
1024 return fromDevice(&buf);
1027MicroExif MicroExif::fromDevice(
QIODevice *device)
1034 QDataStream ds(device);
1035 if (!checkHeader(ds))
1041 if (!readIfd(ds, exif.m_tiffTags))
1045 if (
auto pos = exif.m_tiffTags.value(EXIF_EXIFIFD).toUInt()) {
1046 if (!readIfd(ds, exif.m_exifTags, pos))
1051 if (
auto pos = exif.m_tiffTags.value(EXIF_GPSIFD).toUInt()) {
1052 if (!readIfd(ds, exif.m_gpsTags, pos, staticGpsTagTypes))
1059MicroExif MicroExif::fromImage(
const QImage &image)
1066 exif.setWidth(image.
width());
1067 exif.setHeight(image.
height());
1068 exif.setHorizontalResolution(image.
dotsPerMeterX() * 25.4 / 1000);
1069 exif.setVerticalResolution(image.
dotsPerMeterY() * 25.4 / 1000);
1073 for (
auto &&p : tiffStrMap) {
1074 exif.setTiffString(p.first, image.
text(p.second));
1078 for (
auto &&p : exifStrMap) {
1079 exif.setExifString(p.first, image.
text(p.second));
1083 if (exif.software().isEmpty()) {
1086 if (!sw.isEmpty() && !ver.isEmpty())
1087 sw.append(QStringLiteral(
" %1").arg(ver));
1088 exif.setSoftware(sw.trimmed());
1095 exif.setDateTime(dt);
1099 auto alt = image.
text(QStringLiteral(META_KEY_ALTITUDE)).
toDouble(&ok);
1101 exif.setAltitude(alt);
1102 auto lat = image.
text(QStringLiteral(META_KEY_LATITUDE)).
toDouble(&ok);
1104 exif.setLatitude(lat);
1105 auto lon = image.
text(QStringLiteral(META_KEY_LONGITUDE)).
toDouble(&ok);
1107 exif.setLongitude(lon);
1112void MicroExif::setTiffString(quint16 tagId,
const QString &s)
1114 MicroExif::setString(m_tiffTags, tagId, s);
1117QString MicroExif::tiffString(quint16 tagId)
const
1119 return MicroExif::string(m_tiffTags, tagId);
1122void MicroExif::setExifString(quint16 tagId,
const QString &s)
1124 MicroExif::setString(m_exifTags, tagId, s);
1127QString MicroExif::exifString(quint16 tagId)
const
1129 return MicroExif::string(m_exifTags, tagId);
1132void MicroExif::setGpsString(quint16 tagId,
const QString &s)
1134 MicroExif::setString(m_gpsTags, tagId, s);
1137QString MicroExif::gpsString(quint16 tagId)
const
1139 return MicroExif::string(m_gpsTags, tagId);
1145 ds << quint16(0x4949);
1147 ds << quint16(0x4d4d);
1148 ds << quint16(0x002a);
1155 auto tiffTags = m_tiffTags;
1156 auto exifTags = m_exifTags;
1157 auto gpsTags = m_gpsTags;
1158 updateTags(tiffTags, exifTags, gpsTags);
1161 if (!writeIfd(ds, tiffTags, positions))
1163 if (!writeIfd(ds, exifTags, positions, positions.
value(EXIF_EXIFIFD)))
1165 if (!writeIfd(ds, gpsTags, positions, positions.
value(EXIF_GPSIFD), staticGpsTagTypes))
1170void MicroExif::updateTags(Tags &tiffTags, Tags &exifTags, Tags &gpsTags)
const
1172 if (exifTags.isEmpty()) {
1173 tiffTags.remove(EXIF_EXIFIFD);
1175 tiffTags.insert(EXIF_EXIFIFD, quint32());
1176 exifTags.insert(EXIF_EXIFVERSION, QByteArray(
"0300"));
1178 if (gpsTags.isEmpty()) {
1179 tiffTags.remove(EXIF_GPSIFD);
1181 tiffTags.insert(EXIF_GPSIFD, quint32());
1182 gpsTags.insert(GPS_GPSVERSION, QByteArray(
"2400"));
1186void MicroExif::setString(Tags &tags, quint16 tagId,
const QString &s)
1191 tags.insert(tagId, s);
1194QString MicroExif::string(
const Tags &tags, quint16 tagId)
1196 return tags.value(tagId).toString();
NETWORKMANAGERQT_EXPORT QString version()
void setData(const QByteArray &data)
QByteArray & append(QByteArrayView data)
char at(qsizetype i) const const
QByteArray first(qsizetype n) const const
bool isEmpty() const const
QByteArray & removeLast()
qsizetype size() const const
Primaries primaries() const const
TransferFunction transferFunction() const const
ByteOrder byteOrder() const const
QIODevice * device() const const
void setByteOrder(ByteOrder bo)
Status status() const const
QDateTime currentDateTime()
QDateTime fromString(QStringView string, QStringView format, QCalendar cal)
bool isValid() const const
int offsetFromUtc() const const
QString toString(QStringView format, QCalendar cal) const const
iterator insert(const Key &key, const T &value)
bool remove(const Key &key)
T value(const Key &key) const const
QColorSpace colorSpace() const const
int dotsPerMeterX() const const
int dotsPerMeterY() const const
bool isNull() const const
void setText(const QString &key, const QString &text)
QString text(const QString &key) const const
virtual bool isSequential() const const
virtual bool open(QIODeviceBase::OpenMode mode)
virtual qint64 pos() const const
void append(QList< T > &&value)
const QChar at(qsizetype position) const const
QString fromLatin1(QByteArrayView str)
QString fromUtf8(QByteArrayView str)
bool isEmpty() const const
QString left(qsizetype n) const const
QString mid(qsizetype position, qsizetype n) const const
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
qsizetype size() const const
double toDouble(bool *ok) const const
int toInt(bool *ok, int base) const const
QByteArray toLatin1() const const
QByteArray toUtf8() const const
QTimeZone fromSecondsAheadOfUtc(int offset)
bool isNull() const const
QString toString(StringFormat mode) const const
QVariant fromValue(T &&value)
QByteArray toByteArray() const const
double toDouble(bool *ok) const const
int toInt(bool *ok) const const
QString toString() const const