📄 xmpnormalizer.java
字号:
.getAliasForm().toPropertyOptions()); baseSchema.addChild(baseNode); transplantArrayItemAlias (propertyIt, currProp, baseNode); } } else if (info.getAliasForm().isSimple()) { // The base node does exist and this is a top-to-top alias. // Check for conflicts if strict aliasing is on. // Remove and delete the alias subtree. if (strictAliasing) { compareAliasedSubtrees (currProp, baseNode, true); } propertyIt.remove(); } else { // This is an alias to an array item and the array exists. // Look for the aliased item. // Then transplant or check & delete as appropriate. XMPNode itemNode = null; if (info.getAliasForm().isArrayAltText()) { int xdIndex = XMPNodeUtils.lookupLanguageItem(baseNode, XMPConst.X_DEFAULT); if (xdIndex != -1) { itemNode = baseNode.getChild(xdIndex); } } else if (baseNode.hasChildren()) { itemNode = baseNode.getChild(1); } if (itemNode == null) { transplantArrayItemAlias (propertyIt, currProp, baseNode); } else { if (strictAliasing) { compareAliasedSubtrees (currProp, itemNode, true); } propertyIt.remove(); } } } } currSchema.setHasAliases(false); } } /** * Moves an alias node of array form to another schema into an array * @param propertyIt the property iterator of the old schema (used to delete the property) * @param childNode the node to be moved * @param baseArray the base array for the array item * @throws XMPException Forwards XMP errors */ private static void transplantArrayItemAlias(Iterator propertyIt, XMPNode childNode, XMPNode baseArray) throws XMPException { if (baseArray.getOptions().isArrayAltText()) { if (childNode.getOptions().getHasLanguage()) { throw new XMPException("Alias to x-default already has a language qualifier", XMPError.BADXMP); } XMPNode langQual = new XMPNode(XMPConst.XML_LANG, XMPConst.X_DEFAULT, null); childNode.addQualifier(langQual); } propertyIt.remove(); childNode.setName(XMPConst.ARRAY_ITEM_NAME); baseArray.addChild(childNode); } /** * Fixes the GPS Timestamp in EXIF. * @param exifSchema the EXIF schema node * @throws XMPException Thrown if the date conversion fails. */ private static void fixGPSTimeStamp(XMPNode exifSchema) throws XMPException { // Note: if dates are not found the convert-methods throws an exceptions, // and this methods returns. XMPNode gpsDateTime = XMPNodeUtils.findChildNode(exifSchema, "exif:GPSTimeStamp", false); if (gpsDateTime == null) { return; } try { XMPDateTime binGPSStamp; XMPDateTime binOtherDate; binGPSStamp = XMPUtils.convertToDate(gpsDateTime.getValue()); if (binGPSStamp.getYear() != 0 || binGPSStamp.getMonth() != 0 || binGPSStamp.getDay() != 0) { return; } XMPNode otherDate = XMPNodeUtils.findChildNode(exifSchema, "exif:DateTimeOriginal", false); if (otherDate == null) { otherDate = XMPNodeUtils.findChildNode(exifSchema, "exif:DateTimeDigitized", false); } binOtherDate = XMPUtils.convertToDate(otherDate.getValue()); Calendar cal = binGPSStamp.getCalendar(); cal.set(Calendar.YEAR, binOtherDate.getYear()); cal.set(Calendar.MONTH, binOtherDate.getMonth()); cal.set(Calendar.DAY_OF_MONTH, binOtherDate.getDay()); binGPSStamp = new XMPDateTimeImpl(cal); gpsDateTime.setValue(XMPUtils.convertFromDate (binGPSStamp)); } catch (XMPException e) { // Don't let a missing or bad date stop other things. return; } } /** * Remove all empty schemas from the metadata tree that were generated during the rdf parsing. * @param tree the root of the metadata tree */ private static void deleteEmptySchemas(XMPNode tree) { // Delete empty schema nodes. Do this last, other cleanup can make empty // schema. for (Iterator it = tree.iterateChildren(); it.hasNext();) { XMPNode schema = (XMPNode) it.next(); if (!schema.hasChildren()) { it.remove(); } } } /** * The outermost call is special. The names almost certainly differ. The * qualifiers (and hence options) will differ for an alias to the x-default * item of a langAlt array. * * @param aliasNode the alias node * @param baseNode the base node of the alias * @param outerCall marks the outer call of the recursion * @throws XMPException Forwards XMP errors */ private static void compareAliasedSubtrees(XMPNode aliasNode, XMPNode baseNode, boolean outerCall) throws XMPException { if (!aliasNode.getValue().equals(baseNode.getValue()) || aliasNode.getChildrenLength() != baseNode.getChildrenLength()) { throw new XMPException("Mismatch between alias and base nodes", XMPError.BADXMP); } if ( !outerCall && (!aliasNode.getName().equals(baseNode.getName()) || !aliasNode.getOptions().equals(baseNode.getOptions()) || aliasNode.getQualifierLength() != baseNode.getQualifierLength()) ) { throw new XMPException("Mismatch between alias and base nodes", XMPError.BADXMP); } for (Iterator an = aliasNode.iterateChildren(), bn = baseNode.iterateChildren(); an.hasNext() && bn.hasNext();) { XMPNode aliasChild = (XMPNode) an.next(); XMPNode baseChild = (XMPNode) bn.next(); compareAliasedSubtrees (aliasChild, baseChild, false); } for (Iterator an = aliasNode.iterateQualifier(), bn = baseNode.iterateQualifier(); an.hasNext() && bn.hasNext();) { XMPNode aliasQual = (XMPNode) an.next(); XMPNode baseQual = (XMPNode) bn.next(); compareAliasedSubtrees (aliasQual, baseQual, false); } } /** * The initial support for WAV files mapped a legacy ID3 audio copyright * into a new xmpDM:copyright property. This is special case code to migrate * that into dc:rights['x-default']. The rules: * * <pre> * 1. If there is no dc:rights array, or an empty array - * Create one with dc:rights['x-default'] set from double linefeed and xmpDM:copyright. * * 2. If there is a dc:rights array but it has no x-default item - * Create an x-default item as a copy of the first item then apply rule #3. * * 3. If there is a dc:rights array with an x-default item, * Look for a double linefeed in the value. * A. If no double linefeed, compare the x-default value to the xmpDM:copyright value. * A1. If they match then leave the x-default value alone. * A2. Otherwise, append a double linefeed and * the xmpDM:copyright value to the x-default value. * B. If there is a double linefeed, compare the trailing text to the xmpDM:copyright value. * B1. If they match then leave the x-default value alone. * B2. Otherwise, replace the trailing x-default text with the xmpDM:copyright value. * * 4. In all cases, delete the xmpDM:copyright property. * </pre> * * @param xmp the metadata object * @param dmCopyright the "dm:copyright"-property */ private static void migrateAudioCopyright (XMPMeta xmp, XMPNode dmCopyright) { try { XMPNode dcSchema = XMPNodeUtils.findSchemaNode( ((XMPMetaImpl) xmp).getRoot(), XMPConst.NS_DC, true); String dmValue = dmCopyright.getValue(); String doubleLF = "\n\n"; XMPNode dcRightsArray = XMPNodeUtils.findChildNode (dcSchema, "dc:rights", false); if (dcRightsArray == null || !dcRightsArray.hasChildren()) { // 1. No dc:rights array, create from double linefeed and xmpDM:copyright. dmValue = doubleLF + dmValue; xmp.setLocalizedText(XMPConst.NS_DC, "rights", "", XMPConst.X_DEFAULT, dmValue, null); } else { int xdIndex = XMPNodeUtils.lookupLanguageItem(dcRightsArray, XMPConst.X_DEFAULT); if (xdIndex < 0) { // 2. No x-default item, create from the first item. String firstValue = dcRightsArray.getChild(1).getValue(); xmp.setLocalizedText (XMPConst.NS_DC, "rights", "", XMPConst.X_DEFAULT, firstValue, null); xdIndex = XMPNodeUtils.lookupLanguageItem(dcRightsArray, XMPConst.X_DEFAULT); } // 3. Look for a double linefeed in the x-default value. XMPNode defaultNode = dcRightsArray.getChild(xdIndex); String defaultValue = defaultNode.getValue(); int lfPos = defaultValue.indexOf(doubleLF); if (lfPos < 0) { // 3A. No double LF, compare whole values. if (!dmValue.equals(defaultValue)) { // 3A2. Append the xmpDM:copyright to the x-default // item. defaultNode.setValue(defaultValue + doubleLF + dmValue); } } else { // 3B. Has double LF, compare the tail. if (!defaultValue.substring(lfPos + 2).equals(dmValue)) { // 3B2. Replace the x-default tail. defaultNode.setValue(defaultValue.substring(0, lfPos + 2) + dmValue); } } } // 4. Get rid of the xmpDM:copyright. dmCopyright.getParent().removeChild(dmCopyright); } catch (XMPException e) { // Don't let failures (like a bad dc:rights form) stop other // cleanup. } } /** * Initializes the map that contains the known arrays, that are fixed by * {@link XMPNormalizer#normalizeDCArrays(XMPNode)}. */ private static void initDCArrays() { dcArrayForms = new HashMap(); // Properties supposed to be a "Bag". PropertyOptions bagForm = new PropertyOptions(); bagForm.setArray(true); dcArrayForms.put("dc:contributor", bagForm); dcArrayForms.put("dc:language", bagForm); dcArrayForms.put("dc:publisher", bagForm); dcArrayForms.put("dc:relation", bagForm); dcArrayForms.put("dc:subject", bagForm); dcArrayForms.put("dc:type", bagForm); // Properties supposed to be a "Seq". PropertyOptions seqForm = new PropertyOptions(); seqForm.setArray(true); seqForm.setArrayOrdered(true); dcArrayForms.put("dc:creator", seqForm); dcArrayForms.put("dc:date", seqForm); // Properties supposed to be an "Alt" in alternative-text form. PropertyOptions altTextForm = new PropertyOptions(); altTextForm.setArray(true); altTextForm.setArrayOrdered(true); altTextForm.setArrayAlternate(true); altTextForm.setArrayAltText(true); dcArrayForms.put("dc:description", altTextForm); dcArrayForms.put("dc:rights", altTextForm); dcArrayForms.put("dc:title", altTextForm); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -