Я немного взломал exiv2, пытаясь расширить функции преобразования даты / времени между EXIF, IPTC и XMP. http://dev.exiv2.org/issues/864
Дата IPTC и время IPTC хранятся в отдельных полях, поэтому сначала я пытаюсь проанализировать дату IPTC, затем в своем коде я пытаюсь проанализировать время.
Я новичок в программировании, так что это будет довольно простой проблемой, но здесь все. Код добавляется в файл exiv2 convert.cpp внутри функции cnvIptcValue.
Точную ошибку я получаю из командной строки:
$ exiv2 -eiX iptc.jpg
Warning: Failed to convert Iptc.Application2.DateCreated to Xmp.photoshop.DateCreated, unable to parse '1944-09-08'
Warning: Failed to convert Iptc.Application2.DigitizationDate to Xmp.xmp.CreateDate, unable to parse '2015-03-06'
Сначала я подумал, что код преобразования даты не работает:
if (std::string(from) == "Iptc.Application2.DateCreated" || std::string(from) == "Iptc.Application2.DigitizationDate") {
int year, month, day, hour, min, sec, tzHour, tzMinute;
char tzSign;
char buf[30];if (sscanf(value.c_str(), "%d-%d-%d", &year, &month, &day) != 3) {
EXV_WARNING << "Failed to convert " << from << " to " << to
<< ", unable to parse '" << value << "'\n";
return;
}
Но дальнейшее тестирование показало, что это был код преобразования времени, который терпит неудачу:
const char* iptcTime = 0;
if (std::string(from) == "Iptc.Application2.DateCreated") {
iptcTime = "Iptc.Application2.TimeCreated";
}
else if (std::string(from) == "Iptc.Application2.DigitizationDate") {
iptcTime = "Iptc.Application2.DigitizationTime";
}
if (iptcTime) {
if (sscanf(value.c_str(), "%d:%d:%d%1c%d:%02d", &hour, &min, &sec, &tzSign, &tzHour, &tzMinute) != 6) {
EXV_WARNING << "Failed to convert " << from << " to " << to
<< ", unable to parse '" << value << "'\n";
return;
}
Поэтому временной код пытался проанализировать поле даты. Это было изменено в поле Time, добавив пару строк кода:
Exiv2::IptcData::iterator iptctime_pos = iptcData_->findKey(IptcKey(from));
std::string value = iptctime_pos->toString();
Я также расширил код сообщения об ошибке, чтобы увидеть, что было в поле Time. результат сейчас:
Warning: Failed to convert Iptc.Application2.TimeCreated to Xmp.photoshop.DateCreated, unable to parse '11:11:14+00:00'
Year Month Day: 1944 9 8
Hour Minute Second: 32767 36913992 1978972555
Zone Sign Hour Minute: "U+007F" -184143665 6457088
Warning: Failed to convert Iptc.Application2.DigitizationTime to Xmp.xmp.CreateDate, unable to parse '16:26:47+00:00'
Year Month Day: 2015 3 6
Hour Minute Second: 32767 36909480 36909144
Zone Sign Hour Minute: "U+007F" -184143665 6457088
Он правильно разбирает поле Date, но не Time. Почему это? Разве это неправильно?
Решено! Были два изменения, необходимые.
Первым делом нужно было проверить тот же ключ, который был установлен ранее. Мои попытки проб и ошибок заставляли меня сканировать из «iptctime», а не из «value», что дало ошибку разбора.
std::string value = iptctime_pos->toString();
if (sscanf(value.c_str(), "%d:%d:%d%1c%d:%d", &hour, &min, &sec, &tzSign, &tzHour, &tzMinute) != 6) {
Вторым было добавить else if
предотвращение перезаписи свойств DateTime с помощью общего кода назначения.
Полный рабочий результат:
if (std::string(from) == "Iptc.Application2.DateCreated" || std::string(from) == "Iptc.Application2.DigitizationDate") {
int year, month, day, hour, min, sec, tzHour, tzMinute;
char tzSign;
std::string iptctime;
char buf[30];(sscanf(value.c_str(), "%d-%d-%d", &year, &month, &day)
const char* iptcTime = 0;
if (std::string(from) == "Iptc.Application2.DateCreated") {
iptcTime = "Iptc.Application2.TimeCreated";
}
else if (std::string(from) == "Iptc.Application2.DigitizationDate") {
iptcTime = "Iptc.Application2.DigitizationTime";
}
if (iptcTime) {
Exiv2::IptcData::iterator iptctime_pos = iptcData_->findKey(IptcKey(iptcTime));
if (iptctime_pos == iptcData_->end()) return;
if (iptctime_pos->key() == iptcTime) {
std::string value = iptctime_pos->toString();
sscanf(value.c_str(), "%d:%d:%d%1c%d:%d", &hour, &min, &sec, &tzSign, &tzHour, &tzMinute)
}
}
snprintf(buf, sizeof(buf), "%04d-%02d-%02dT%02d:%02d:%02d%1c%02d:%02d",
year, month, day, hour, min, sec, tzSign, tzHour, tzMinute);
buf[sizeof(buf) - 1] = 0;
(*xmpData_)[to] = buf;
}
else if (std::string(from) != "Iptc.Application2.DateCreated" || std::string(from) != "Iptc.Application2.DigitizationDate") {
(*xmpData_)[to] = value;
}
Немного больше тестирования, и я выложу его в репозиторий exiv2, который будет представлен в следующем выпуске exiv2 0.25!
PS: Спасибо @tivn за вашу помощь.