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() { }
|
}
|