【问题标题】:"unable to parse" IPTC Date to XMP DateTime in exiv2exiv2 中的“无法解析”IPTC 日期到 XMP 日期时间
【发布时间】:2015-06-17 05:38:41
【问题描述】:

我对 exiv2 进行了一些修改,试图扩展它在 EXIF、IPTC 和 XMP 之间的日期/时间转换功能。 http://dev.exiv2.org/issues/864

IPTC 日期和 IPTC 时间存储在不同的字段中,所以首先我尝试解析 IPTC 日期,稍后在我的代码中我尝试解析时间。

我是编程的初级初学者,所以这看起来是一个非常基本的问题,但这里是这样。该代码正在添加到 cnvIptcValue 函数内的 exiv2 文件 convert.cpp 中。

我从命令行得到的确切错误:

$ 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;
    }

所以时间代码试图解析日期字段。通过添加几行代码将其更改为时间字段:

    Exiv2::IptcData::iterator iptctime_pos = iptcData_->findKey(IptcKey(from));
    std::string value = iptctime_pos->toString();

我还扩展了错误消息代码以查看时间字段中的内容。现在的结果是:

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

它正确解析了日期字段,但不是时间。为什么是这样?是不是解析错了?

【问题讨论】:

  • 我检查了dev.exiv2.org/projects/exiv2/repository/entry/trunk/src/…,发现它使用的是冒号:,而不是破折号-:if (sscanf(value.c_str(), "%d:%d:%d", &amp;year, &amp;month, &amp;day) != 3)。但是您的代码使用-。哪一个是正确的?
  • EXIF 使用冒号,IPTC 使用破折号。
  • 您确定警告是在 Converter::cnvIptcValue() 内部触发的,而不是在 Converter::cnvExifDate() 内部触发的吗?
  • 好的,我测试过,是的,它来自 Converter::cnvIptcValue()。但是从后面的部分尝试解析时间。我会修改问题。再次感谢。
  • 我认为正确的做法是基于cnvExifDate()创建新方法cnvIptcDate(),然后修改const Converter::Conversion Converter::conversion_[],使"Iptc.Application2.DateCreated"现在使用cnvIptcDate()而不是@987654339 @。可能你还需要在这个数组中包含Iptc.Application2.DigitizationDateIptc.Application2.TimeCreatedIptc.Application2.DigitizationTime,这也可以使用cnvIptcDate()

标签: c++ parsing xmp iptc exiv2


【解决方案1】:

解决了!需要进行两项更改。

首先是确保扫描与之前设置的相同的密钥。我的试错尝试让我从“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 的帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-01-01
    • 1970-01-01
    • 2014-01-29
    • 1970-01-01
    • 2012-10-14
    • 2023-02-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多