package jnpf.fileStorage.dms; import jnpf.exception.DataException; import org.w3c.dom.Element; import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; /** Correct only this job's drawings; existing table images retain their original layout policy. */ final class DmsPageWatermarkAnchors { private static final String WP = "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"; private static final String A = "http://schemas.openxmlformats.org/drawingml/2006/main"; static byte[] fix(byte[] source, String prefix, int expected) throws Exception { int changed = 0; ByteArrayOutputStream output = new ByteArrayOutputStream(); try (ZipInputStream zip = new ZipInputStream(new ByteArrayInputStream(source)); ZipOutputStream result = new ZipOutputStream(output)) { ZipEntry entry; long expanded = 0; while ((entry = zip.getNextEntry()) != null) { byte[] bytes = zip.readNBytes(100 * 1024 * 1024 + 1); expanded += bytes.length; if (expanded > 100L * 1024 * 1024) throw new DataException("水印文档解压后超过处理上限"); if ("word/document.xml".equals(entry.getName())) { DocumentBuilderFactory factory = DocumentBuilderFactory.newDefaultInstance(); factory.setNamespaceAware(true); factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); org.w3c.dom.Document document = factory.newDocumentBuilder().parse(new ByteArrayInputStream(bytes)); org.w3c.dom.NodeList anchors = document.getElementsByTagNameNS(WP, "anchor"); for (int i = 0; i < anchors.getLength(); i++) { Element anchor = (Element) anchors.item(i); org.w3c.dom.NodeList properties = anchor.getElementsByTagNameNS("*", "*"); boolean matches = false; for (int p = 0; p < properties.getLength(); p++) { Element property = (Element) properties.item(p); if (("docPr".equals(property.getLocalName()) || "cNvPr".equals(property.getLocalName())) && property.getAttribute("name").startsWith(prefix + "_")) { matches = true; break; } } if (matches) { anchor.setAttribute("layoutInCell", "0"); anchor.setAttribute("locked", "1"); anchor.setAttribute("simplePos", "0"); resetSimplePosition(anchor); normalizePagePosition(anchor, "positionH"); normalizePagePosition(anchor, "positionV"); lockDrawing(document, anchor); changed++; } } TransformerFactory transformer = TransformerFactory.newDefaultInstance(); transformer.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); transformer.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, ""); ByteArrayOutputStream xml = new ByteArrayOutputStream(); transformer.newTransformer().transform(new DOMSource(document), new StreamResult(xml)); bytes = xml.toByteArray(); } result.putNextEntry(new ZipEntry(entry.getName())); result.write(bytes); result.closeEntry(); } } if (changed != expected) throw new DataException("指定页水印图片数量不匹配,已停止生成"); return output.toByteArray(); } private static void resetSimplePosition(Element anchor) { org.w3c.dom.NodeList positions = anchor.getElementsByTagNameNS(WP, "simplePos"); if (positions.getLength() == 0) return; Element position = (Element) positions.item(0); position.setAttribute("x", "0"); position.setAttribute("y", "0"); } private static void normalizePagePosition(Element anchor, String name) { org.w3c.dom.NodeList positions = anchor.getElementsByTagNameNS(WP, name); if (positions.getLength() == 0) { throw new DataException("指定页水印图片缺少页面坐标,已停止生成"); } Element position = (Element) positions.item(0); position.setAttribute("relativeFrom", "page"); org.w3c.dom.NodeList offsets = position.getElementsByTagNameNS(WP, "posOffset"); if (offsets.getLength() == 0) { throw new DataException("指定页水印图片缺少页面偏移,已停止生成"); } if (!offsets.item(0).getTextContent().trim().matches("-?\\d+")) { throw new DataException("指定页水印图片页面偏移无效,已停止生成"); } } private static void lockDrawing(org.w3c.dom.Document document, Element anchor) { org.w3c.dom.NodeList locks = anchor.getElementsByTagNameNS(A, "graphicFrameLocks"); Element lock; if (locks.getLength() > 0) { lock = (Element) locks.item(0); } else { org.w3c.dom.NodeList frames = anchor.getElementsByTagNameNS(WP, "cNvGraphicFramePr"); if (frames.getLength() == 0) return; lock = document.createElementNS(A, "a:graphicFrameLocks"); frames.item(0).appendChild(lock); } lock.setAttribute("noSelect", "1"); lock.setAttribute("noMove", "1"); lock.setAttribute("noResize", "1"); lock.setAttribute("noChangeAspect", "1"); } private DmsPageWatermarkAnchors() { } }