在为链接生成缺失的 documentId 和 InstanceIds 后,需要为 .indd 元信息添加 documentId 和 instanceId 标签

need to add documentId and instanceId tags for .indd meta info after generating missing documentId and InstanceIds for the links

使用 ExtendScript,我正在为 Indesign (.indd) 文件的链接更新缺失的 DocumentIdInstanceId,使用 。这工作正常并正确更新每个缺少 DoumentIdInstanceId 的链接。但我现在面临的问题是,.indd 文件本身具有元信息,其中这些新生成的 DocumentIdInstanceId 对于特定链接丢失了。

请参考以下包含四个资源的.indd文件的元信息,以便更好地理解。这里它有四个资源,两个 .psd 文件和两个 .ai 文件。 .indd 文件元信息包含两个 .ai 资源的 <stRef:instanceID><stRef:documentID>,其中缺少这些标签(<stRef:instanceID><stRef:documentID>)对于其他两个 .psd 资源。即使在为 .psd 文件生成缺失的 DocumentIdInstanceId 之后,在这两个资源的 .indd 文件元信息中,这两个标签 <stRef:instanceID><stRef:documentID> 仍然缺失。即使在 .indd 文件元信息中,我如何更新这些缺失链接的 DocumentId 和 InstanceId?

<xmpMM:Manifest>
  <rdf:Bag>
    <rdf:li rdf:parseType="Resource">
      <stMfs:linkForm>ReferenceStream</stMfs:linkForm>
      <xmpMM:placedXResolution>300.00</xmpMM:placedXResolution>
      <xmpMM:placedYResolution>300.00</xmpMM:placedYResolution>
      <xmpMM:placedResolutionUnit>Inches</xmpMM:placedResolutionUnit>
      <stMfs:reference rdf:parseType="Resource">
        <stRef:lastURL>file:///Users/superadmin/Downloads/266x165mm_VPA_WS_SP_M-1F/Links/6604_RGB.psd</stRef:lastURL>
      </stMfs:reference>
    </rdf:li>
    <rdf:li rdf:parseType="Resource">
      <stMfs:linkForm>ReferenceStream</stMfs:linkForm>
      <xmpMM:placedXResolution>72.00</xmpMM:placedXResolution>
      <xmpMM:placedYResolution>72.00</xmpMM:placedYResolution>
      <xmpMM:placedResolutionUnit>Inches</xmpMM:placedResolutionUnit>
      <stMfs:reference rdf:parseType="Resource">
        <stRef:lastURL>file:///Users/superadmin/Downloads/266x165mm_VPA_WS_SP_M-1F/Links/Silver_001_RGB.psd</stRef:lastURL>
      </stMfs:reference>
    </rdf:li>
    <rdf:li rdf:parseType="Resource">
      <stMfs:linkForm>ReferenceStream</stMfs:linkForm>
      <xmpMM:placedXResolution>72.00</xmpMM:placedXResolution>
      <xmpMM:placedYResolution>72.00</xmpMM:placedYResolution>
      <xmpMM:placedResolutionUnit>Inches</xmpMM:placedResolutionUnit>
      <stMfs:reference rdf:parseType="Resource">
        <stRef:instanceID>uuid:d34cbf16-4c87-4344-a0db-6cf67ffe6f84</stRef:instanceID>
        <stRef:documentID>xmp.did:fd9d95eb-fe2d-4fca-92a2-1906d98a10f4</stRef:documentID>
        <stRef:lastURL>file:///Users/superadmin/Downloads/266x165mm_VPA_WS_SP_M-1F/Links/bkgd_rgb_en.ai</stRef:lastURL>
    </stMfs:reference>
    </rdf:li>
    <rdf:li rdf:parseType="Resource">
      <stMfs:linkForm>ReferenceStream</stMfs:linkForm>
      <xmpMM:placedXResolution>72.00</xmpMM:placedXResolution>
      <xmpMM:placedYResolution>72.00</xmpMM:placedYResolution>
      <xmpMM:placedResolutionUnit>Inches</xmpMM:placedResolutionUnit>
      <stMfs:reference rdf:parseType="Resource">
        <stRef:instanceID>uuid:afd031b3-018a-434a-989f-c0e35ff0cebb</stRef:instanceID>
        <stRef:documentID>xmp.did:f4cbc476-258f-4807-8734-d8afc200fbfb</stRef:documentID>
        <stRef:lastURL>file:///Users/superadmin/Downloads/266x165mm_VPA_WS_SP_M-1F/Links/bax_logo_whitebox_cmyk.ai</stRef:lastURL>
      </stMfs:reference>
    </rdf:li>
  </rdf:Bag>
</xmpMM:Manifest>

<xmpMM:Manifest><rdf:Bag> 中的 <stRef:instanceID><stRef:documentID> 未反映在 indd 文件元中的问题是在以下任一情况下遇到的:

  • 通过单击 InDesign 的链接面板中的 "Update Links" 手动更新链接。
  • 或者根本不更新链接状态。

在将缺少的 DocumentIDInstanceID 添加到链接资源后,您需要通过脚本以编程方式更新 InDesign 链接状态。您可以使用以下函数来执行此操作:

/**
 * Update all document links whose state is outdated.
 * @param {Object} doc - A reference to the .indd to update.
 */
function updateOutdatedLinks(doc) {
  for (var i = 0, len = doc.links.length; i < len; i++) {
    var link = doc.links[i];
    if (link.status === LinkStatus.LINK_OUT_OF_DATE) {
      link.update();
    }
  }
}

script.jsx

下面是一个完整的工作版本,它将添加任何缺失的 DocumentID and/or InstanceID 到相关链接,然后在 .indd

#target indesign

$.level=0;

// Warn if there are no documents open.
if (!app.documents.length) {
  alert('Open a document and try again.', 'Missing Document', false);
  exit();
}

var doc = app.activeDocument;

/**
 * Loads the AdobeXMPScript library.
 * @returns {Boolean} True if the library loaded successfully, otherwise false.
 */
function loadXMPLibrary() {
  if (!ExternalObject.AdobeXMPScript) {
    try {
      ExternalObject.AdobeXMPScript = new ExternalObject('lib:AdobeXMPScript');
    } catch (e) {
      alert('Failed loading AdobeXMPScript library\n' + e.message, 'Error', true);
      return false;
    }
  }
  return true;
}

/**
 * Checks the status of all Indesign links, and exits if the state is not OK.
 * @param {Object} doc - A reference to the .indd to check.
 * @returns {Boolean} True if the state of all links are OK, otherwise false.
 */
function linksStatusCheck(doc) {
  for (var i = 0, len = doc.links.length; i < len; i++) {
    if (doc.links[i].status !== LinkStatus.NORMAL) {
      alert('The status of all links must be OK \nPlease update link status ' +
          'via the Links panel and try again', 'Link Status', true);
      exit();
    }
  }
  return true;
}

/**
 * Generate a unique identifier (UUID/GUID). Note this runs on macOS only.
 * @returns {String} - The generated unique identifier.
 */
function generateUUID() {
  var cmd = 'do shell script "uuidgen | tr -d " & quoted form of "-"';
  return app.doScript(cmd, ScriptLanguage.applescriptLanguage);
}

/**
 * Add an XMP property and value to a given file.
 * @param {String} filePath - Path to the file/asset to add the XMP metadata.
 * @param {String} xmpProperty - Name of the XMP property.
 * @param {String} xmpValue - Value to assign to the XMP property.
 */
function addXmpPropertyAndValue(filePath, xmpProperty, xmpValue) {
  var xmpFile = new XMPFile(filePath, XMPConst.FILE_UNKNOWN, XMPConst.OPEN_FOR_UPDATE);
  var xmp = xmpFile.getXMP();

  xmp.setProperty(XMPConst.NS_XMP_MM, xmpProperty, xmpValue);

  if (xmpFile.canPutXMP(xmp)) {
    xmpFile.putXMP(xmp);
  }

  xmpFile.closeFile(XMPConst.CLOSE_UPDATE_SAFELY);
}

/**
 * Add an `instanceID` to the XMP packet of a file/asset.
 * @param {String} filePath - Path to the file/asset to add the XMP metadata.
 * @param {String} uuid - The unique identifier (UUID/GUID) value to add.
 */
function addInstanceID(filePath, uuid) {
  addXmpPropertyAndValue(filePath, 'InstanceID', 'xmp.iid:' + uuid);
}

/**
 * Add an `documentID` to the XMP packet of a file/asset.
 * @param {String} filePath - Path to the file/asset to add the XMP metadata.
 * @param {String} uuid - The unique identifier (UUID/GUID) value to add.
 */
function addDocumentID(filePath, uuid) {
  addXmpPropertyAndValue(filePath, 'DocumentID', 'xmp.did:' + uuid);
  addXmpPropertyAndValue(filePath, 'OriginalDocumentID', 'xmp.did:' + uuid);
}

/**
 * Adds both `instanceID` and `documentID` to the XMP packet of a file/asset.
 * Note: Both properties share the same unique identifier (UUID/GUID).
 * @param {String} filePath - Path to the file/asset to add the XMP metadata.
 * @param {String} uuid - The unique identifier (UUID/GUID) value to add.
 */
function addDocumentIDAndInstanceID(filePath) {
  var uuid = generateUUID();
  addInstanceID(filePath, uuid);
  addDocumentID(filePath, uuid);
}

/**
 * Checks both XMP properties, `DocumentID` and `instanceID`, exist in each
 * linked file associated with an InDesign document (.indd). When a link does
 * not contain the aforementioned properties a new one is added.
 * @param {Object} doc - A reference to the .indd to check.
 */
function checkLinksXMP(doc) {
  for (var i = 0, len = doc.links.length; i < len; i++) {

    var link = doc.links[i];
    var linkFilepath = File(link.filePath).fsName;
    var linkFileName = link.name;

    var xmpFile = new XMPFile(linkFilepath, XMPConst.FILE_INDESIGN, XMPConst.OPEN_FOR_READ);
    var xmp = xmpFile.getXMP();

    // Retrieve values from external links XMP.
    var documentID = xmp.getProperty(XMPConst.NS_XMP_MM, 'DocumentID', XMPConst.STRING);
    var instanceID = xmp.getProperty(XMPConst.NS_XMP_MM, 'InstanceID', XMPConst.STRING);

    // Add missing XMP property/values...
    if (!documentID && !instanceID) {
      addDocumentIDAndInstanceID(linkFilepath);
    } else if (!documentID) {
      addDocumentID(linkFilepath, generateUUID());
    } else if (!instanceID) {
      addInstanceID(linkFilepath, generateUUID());
    }
  }
}

/**
 * Update all document links whose state is outdated.
 * @param {Object} doc - A reference to the .indd to update.
 */
function updateOutdatedLinks(doc) {
  for (var i = 0, len = doc.links.length; i < len; i++) {
    var link = doc.links[i];
    if (link.status === LinkStatus.LINK_OUT_OF_DATE) {
      link.update();
    }
  }
}

if (loadXMPLibrary() && linksStatusCheck(doc)) {
  checkLinksXMP(doc);
  updateOutdatedLinks(doc); // <-- Update status after.
}

备注:

  1. 注意在检查和更新任何缺失的 DocumentIDInstanceID 之后我们如何调用 updateOutdatedLinks 函数,即,请参阅脚本中的这一部分:

    // ...
    
    if (loadXMPLibrary() && linksStatusCheck(doc)) {
      checkLinksXMP(doc);
      updateOutdatedLinks(doc); // <-- Update status after.
    }
    
  2. 此外,(作为旁注),您可以看到在 checkLinksXMP 函数中我们包含以下条件逻辑,即下面的这一部分:

    // Add missing XMP property/values...
    if (!documentID && !instanceID) {
      addDocumentIDAndInstanceID(linkFilepath);
    } else if (!documentID) {
      addDocumentID(linkFilepath, generateUUID());
    } else if (!instanceID) {
      addInstanceID(linkFilepath, generateUUID());
    }
    

    注意如果 documentID && instanceID 都缺失(即上面的第一个条件),我们对两个值使用相同的 UUID/GUID。参考 addDocumentIDAndInstanceID 函数中的逻辑,您可以看到两个属性共享相同的 UUID/GUID。

  3. 除了上述脚本之外,您还需要添加更多功能来保存调用 updateOutdatedLinks 函数后对 .indd 所做的更改。例如

    if (loadXMPLibrary() && linksStatusCheck(doc)) {
      checkLinksXMP(doc);
      updateOutdatedLinks(doc);
      doc.save(); // <-- Also ddd this to save the `.indd`
    }
    
  4. .

  5. 替换 generateUUID 函数