File indexing completed on 2025-02-16 13:03:41
0001 /* 0002 SPDX-FileCopyrightText: 2018 Alexander Stippich <a.stippich@gmx.net> 0003 0004 SPDX-License-Identifier: LGPL-2.1-or-later 0005 */ 0006 0007 #include "formatstrings_p.h" 0008 0009 #include <math.h> 0010 #include <QDateTime> 0011 #include <KLocalizedString> 0012 #include <KFormat> 0013 0014 using namespace KFileMetaData; 0015 0016 /* 0017 * Calculates and returns the number of digits after the 0018 * comma to always show three significant digits for use 0019 * with KFormat::formatValue. 0020 */ 0021 int threeSignificantDigits(int value) 0022 { 0023 if (value == 0) { 0024 return 0; 0025 } 0026 int before_decimal_point = static_cast<int>(log10(value > 0 ? value : -value)) % 3; 0027 return 2 - before_decimal_point; 0028 } 0029 0030 QString FormatStrings::toStringFunction(const QVariant& value) 0031 { 0032 return value.toString(); 0033 } 0034 0035 QString FormatStrings::formatDouble(const QVariant& value) 0036 { 0037 return QLocale().toString(value.toDouble(),'g',3); 0038 } 0039 0040 QString FormatStrings::formatDate(const QVariant& value) 0041 { 0042 KFormat form; 0043 QDateTime dt; 0044 if (value.type() == QVariant::DateTime) { 0045 dt = value.toDateTime(); 0046 } else { 0047 dt = QDateTime::fromString(value.toString(), Qt::ISODate); 0048 } 0049 if (dt.isValid()) { 0050 return form.formatRelativeDateTime(dt, QLocale::LongFormat); 0051 } 0052 return QString(); 0053 } 0054 0055 QString FormatStrings::formatDuration(const QVariant& value) 0056 { 0057 KFormat form; 0058 return form.formatDuration(value.toInt() * 1000); 0059 } 0060 0061 QString FormatStrings::formatBitRate(const QVariant& value) 0062 { 0063 KFormat form; 0064 return i18nc("@label bitrate (per second)", "%1/s", form.formatValue(value.toInt(), 0065 KFormat::Unit::Bit, threeSignificantDigits(value.toInt()), KFormat::UnitPrefix::AutoAdjust, KFormat::MetricBinaryDialect)); 0066 } 0067 0068 QString FormatStrings::formatSampleRate(const QVariant& value) 0069 { 0070 KFormat form; 0071 return form.formatValue(value.toInt(), KFormat::Unit::Hertz, threeSignificantDigits(value.toInt()), KFormat::UnitPrefix::AutoAdjust, KFormat::MetricBinaryDialect); 0072 } 0073 0074 QString FormatStrings::formatOrientationValue(const QVariant& value) 0075 { 0076 QString string; 0077 switch (value.toInt()) { 0078 case 1: string = i18nc("Description of image orientation", "Unchanged"); break; 0079 case 2: string = i18nc("Description of image orientation", "Horizontally flipped"); break; 0080 case 3: string = i18nc("Description of image orientation", "180° rotated"); break; 0081 case 4: string = i18nc("Description of image orientation", "Vertically flipped"); break; 0082 case 5: string = i18nc("Description of image orientation", "Transposed"); break; 0083 case 6: string = i18nc("Description of image orientation, counter clock-wise rotated", "90° rotated CCW "); break; 0084 case 7: string = i18nc("Description of image orientation", "Transversed"); break; 0085 case 8: string = i18nc("Description of image orientation, counter clock-wise rotated", "270° rotated CCW"); break; 0086 default: 0087 break; 0088 } 0089 return string; 0090 } 0091 0092 QString FormatStrings::formatPhotoFlashValue(const QVariant& value) 0093 { 0094 // copied from exiv2 tags_int.cpp 0095 const QMap<int, QString> flashTranslation = { 0096 { 0x00, i18nc("Description of photo flash", "No flash") }, 0097 { 0x01, i18nc("Description of photo flash", "Fired") }, 0098 { 0x05, i18nc("Description of photo flash", "Fired, return light not detected") }, 0099 { 0x07, i18nc("Description of photo flash", "Fired, return light detected") }, 0100 { 0x08, i18nc("Description of photo flash", "Yes, did not fire") }, 0101 { 0x09, i18nc("Description of photo flash", "Yes, compulsory") }, 0102 { 0x0d, i18nc("Description of photo flash", "Yes, compulsory, return light not detected") }, 0103 { 0x0f, i18nc("Description of photo flash", "Yes, compulsory, return light detected") }, 0104 { 0x10, i18nc("Description of photo flash", "No, compulsory") }, 0105 { 0x14, i18nc("Description of photo flash", "No, did not fire, return light not detected") }, 0106 { 0x18, i18nc("Description of photo flash", "No, auto") }, 0107 { 0x19, i18nc("Description of photo flash", "Yes, auto") }, 0108 { 0x1d, i18nc("Description of photo flash", "Yes, auto, return light not detected") }, 0109 { 0x1f, i18nc("Description of photo flash", "Yes, auto, return light detected") }, 0110 { 0x20, i18nc("Description of photo flash", "No flash function") }, 0111 { 0x30, i18nc("Description of photo flash", "No, no flash function") }, 0112 { 0x41, i18nc("Description of photo flash", "Yes, red-eye reduction") }, 0113 { 0x45, i18nc("Description of photo flash", "Yes, red-eye reduction, return light not detected") }, 0114 { 0x47, i18nc("Description of photo flash", "Yes, red-eye reduction, return light detected") }, 0115 { 0x49, i18nc("Description of photo flash", "Yes, compulsory, red-eye reduction") }, 0116 { 0x4d, i18nc("Description of photo flash", "Yes, compulsory, red-eye reduction, return light not detected") }, 0117 { 0x4f, i18nc("Description of photo flash", "Yes, compulsory, red-eye reduction, return light detected") }, 0118 { 0x50, i18nc("Description of photo flash", "No, red-eye reduction") }, 0119 { 0x58, i18nc("Description of photo flash", "No, auto, red-eye reduction") }, 0120 { 0x59, i18nc("Description of photo flash", "Yes, auto, red-eye reduction") }, 0121 { 0x5d, i18nc("Description of photo flash", "Yes, auto, red-eye reduction, return light not detected") }, 0122 { 0x5f, i18nc("Description of photo flash", "Yes, auto, red-eye reduction, return light detected") } 0123 }; 0124 if (flashTranslation.contains(value.toInt())) { 0125 return flashTranslation.value(value.toInt()); 0126 } else { 0127 return i18n("Unknown"); 0128 } 0129 0130 } 0131 0132 QString FormatStrings::formatAsDegree(const QVariant& value) 0133 { 0134 return i18nc("Symbol of degree, no space", "%1°", QLocale().toString(value.toDouble())); 0135 } 0136 0137 QString FormatStrings::formatAsMeter(const QVariant& value) 0138 { 0139 KFormat form; 0140 return form.formatValue(value.toDouble(), KFormat::Unit::Meter, 1, KFormat::UnitPrefix::AutoAdjust, KFormat::MetricBinaryDialect); 0141 } 0142 0143 QString FormatStrings::formatAsMilliMeter(const QVariant& value) 0144 { 0145 return i18nc("Focal length given in mm", "%1 mm", QLocale().toString(value.toDouble(), 'g', 3)); 0146 } 0147 0148 QString FormatStrings::formatAsFrameRate(const QVariant& value) 0149 { 0150 return i18nc("Symbol of frames per second, with space", "%1 fps", QLocale().toString(round(value.toDouble() * 100) / 100)); 0151 } 0152 0153 QString FormatStrings::formatPhotoTime(const QVariant& value) 0154 { 0155 auto val = value.toDouble(); 0156 if (val < 0.3 && !qFuzzyIsNull(val)) { 0157 auto reciprocal = 1.0/val; 0158 auto roundedReciprocal = round(reciprocal); 0159 if (abs(reciprocal - roundedReciprocal) < 1e-3) { 0160 return i18nc("Time period given in seconds as rational number, denominator is given", "1/%1 s", roundedReciprocal); 0161 } 0162 } 0163 return i18nc("Time period given in seconds", "%1 s", QLocale().toString(value.toDouble(), 'g', 3)); 0164 } 0165 0166 QString FormatStrings::formatPhotoExposureBias(const QVariant& value) 0167 { 0168 QLocale locale; 0169 auto val = value.toDouble(); 0170 /* 0171 * Exposure values are mostly in steps of one half or third. 0172 * Try to construct a rational number from it. 0173 * Output as double when it is not possible. 0174 */ 0175 auto sixthParts = val * 6; 0176 int roundedSixthParts = static_cast<int>(round(sixthParts)); 0177 int fractional = roundedSixthParts % 6; 0178 if (fractional == 0 || abs(sixthParts - roundedSixthParts) > 1e-3) { 0179 return i18nc("Exposure bias/compensation in exposure value (EV)", "%1 EV", locale.toString(val, 'g', 3)); 0180 } 0181 int integral = roundedSixthParts / 6; 0182 int nominator = fractional; 0183 int denominator = 6; 0184 if (nominator % 2 == 0) { 0185 nominator = nominator / 2; 0186 denominator = denominator / 2; 0187 } else if (nominator % 3 == 0) { 0188 nominator = nominator / 3; 0189 denominator = denominator / 3; 0190 } 0191 if (integral != 0) { 0192 return i18nc("Exposure compensation given as integral with fraction, in exposure value (EV)", 0193 "%1 %2/%3 EV", locale.toString(integral), locale.toString(abs(nominator)), locale.toString(denominator)); 0194 } 0195 return i18nc("Exposure compensation given as rational, in exposure value (EV)", 0196 "%1/%2 EV", locale.toString(nominator), locale.toString(denominator)); 0197 } 0198 0199 QString FormatStrings::formatAspectRatio(const QVariant& value) 0200 { 0201 return i18nc("Aspect ratio, normalized to one", "%1:1", QLocale().toString(round(value.toDouble() * 100) / 100)); 0202 } 0203 0204 QString FormatStrings::formatAsFNumber(const QVariant& value) 0205 { 0206 return i18nc("F number for photographs", "f/%1", QLocale().toString(value.toDouble(), 'g', 2)); 0207 }