刘光辉
3 小时以前 06f314545ac3514d7ce28939920866ae8188d31c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
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() { }
}