Skip to content

Package: WangAnnotations

WangAnnotations

nameinstructionbranchcomplexitylinemethod
WangAnnotations(byte[])
M: 141 C: 0
0%
M: 16 C: 0
0%
M: 9 C: 0
0%
M: 33 C: 0
0%
M: 1 C: 0
0%
render(EditableImage)
M: 16 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
static {...}
M: 1 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /*
2: * *********************************************************************************************************************
3: *
4: * Mistral: open source imaging engine
5: * http://tidalwave.it/projects/mistral
6: *
7: * Copyright (C) 2003 - 2023 by Tidalwave s.a.s. (http://tidalwave.it)
8: *
9: * *********************************************************************************************************************
10: *
11: * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
12: * the License. You may obtain a copy of the License at
13: *
14: * http://www.apache.org/licenses/LICENSE-2.0
15: *
16: * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
17: * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
18: * specific language governing permissions and limitations under the License.
19: *
20: * *********************************************************************************************************************
21: *
22: * git clone https://bitbucket.org/tidalwave/mistral-src
23: * git clone https://github.com/tidalwave-it/mistral-src
24: *
25: * *********************************************************************************************************************
26: */
27: package it.tidalwave.image.metadata;
28:
29: import java.util.ArrayList;
30: import java.util.List;
31: import java.io.ByteArrayInputStream;
32: import java.io.IOException;
33: import java.nio.ByteOrder;
34: import javax.imageio.ImageIO;
35: import java.awt.BasicStroke;
36: import java.awt.Color;
37: import java.awt.Font;
38: import java.awt.Graphics2D;
39: import it.tidalwave.image.EditableImage;
40: import it.tidalwave.image.op.DrawOp;
41:
42: /***********************************************************************************************************************
43: *
44: * http://support.global360.com/content/I4W/documentation/annospec.htm
45: *
46: * @author Fabrizio Giudici
47: *
48: **********************************************************************************************************************/
49: public class WangAnnotations
50: {
51: public static class Attributes
52: {
53: // http://msdn2.microsoft.com/en-us/library/ms533931(VS.85).aspx
54: public static class LogFont
55: {
56: private final int height;
57: private final int width;
58: private final int escapement;
59: private final int orientation;
60: private final int weight;
61: private final byte italic;
62: private final byte underline;
63: private final byte strikeout;
64: private final byte charset;
65: private final byte outprec;
66: private final byte clipprec;
67: private final byte quality;
68: private final byte pitch;
69: private final String faceName;
70:
71: protected LogFont (final byte[] buffer)
72: throws IOException
73: {
74: final var iis = ImageIO.createImageInputStream(new ByteArrayInputStream(buffer));
75: iis.setByteOrder(ByteOrder.LITTLE_ENDIAN);
76: height = iis.readInt();
77: width = iis.readInt();
78: escapement = iis.readInt();
79: orientation = iis.readInt();
80: weight = iis.readInt();
81: italic = iis.readByte();
82: underline = iis.readByte();
83: strikeout = iis.readByte();
84: charset = iis.readByte();
85: outprec = iis.readByte();
86: clipprec = iis.readByte();
87: quality = iis.readByte();
88: pitch = iis.readByte();
89: final var bytes = new byte[16]; // FIXME
90: iis.read(bytes);
91: faceName = new String(bytes);
92: iis.close();
93: }
94:
95: public Font createFont()
96: {
97: return new Font(faceName, (weight < 700) ? Font.PLAIN : Font.BOLD, 40 * height / 15); // FIXME
98: }
99:
100: @Override
101: public String toString()
102: {
103: return String.format("LogFont[height: %d, weight: %d, face: %s]", height, weight, faceName);
104: }
105: }
106:
107: private final int type;
108: private final int x1;
109: private final int y1;
110: private final int x2;
111: private final int y2;
112: private final byte highlight;
113: private final byte transparent;
114: private final int lineSize;
115: private final LogFont logFont;
116: private final int timeStamp;
117: private final byte visible;
118:
119: protected Attributes (final byte[] buffer)
120: throws IOException
121: {
122: final var iis = ImageIO.createImageInputStream(new ByteArrayInputStream(buffer));
123: iis.setByteOrder(ByteOrder.LITTLE_ENDIAN);
124: type = iis.readInt();
125: x1 = iis.readInt();
126: y1 = iis.readInt();
127: x2 = iis.readInt();
128: y2 = iis.readInt();
129:
130: iis.skipBytes(3); // color1
131: iis.skipBytes(3); // color2
132: highlight = iis.readByte();
133: transparent = iis.readByte();
134: lineSize = iis.readInt();
135:
136: iis.readLong(); // reserved 1
137: iis.readLong(); // reserved 2
138: final var logFontBuffer = new byte[64];
139: iis.read(logFontBuffer);
140: logFont = new LogFont(logFontBuffer);
141: timeStamp = iis.readInt();
142: visible = iis.readByte();
143: iis.skipBytes(8); // reserved 4
144: iis.close();
145: }
146:
147: public int getType()
148: {
149: return type;
150: }
151:
152: public void drawString (final Graphics2D g, final EditableImage image, final String text)
153: {
154: g.setColor(Color.BLACK);
155: // g.setStroke(new BasicStroke(3));
156: // drawRectangle(g, image);
157: g.setFont(logFont.createFont());
158: g.drawString(text, (float)x1, (float)y1 + g.getFontMetrics().getAscent());
159: // System.err.println(String.format("Rendered %s at %d, %d", text, xx, yy));
160: }
161:
162: public void drawRectangle (final Graphics2D g, final EditableImage image)
163: {
164: final var ww = Math.abs(x2 - x1);
165: final var hh = Math.abs(y2 - y1);
166: // g.setColor(Color.WHITE);
167: // g.fillRect(xx2, yy2, ww, hh);
168: g.setStroke(new BasicStroke(3));
169: g.setColor(Color.BLACK);
170: g.drawRect(x1, y1, ww, hh);
171: System.err.println(String.format(">>>> Rendered rectangle: %d,%d,%d,%d - %dx%d", x1, y1, x2, y2, ww, hh));
172: // System.err.println(String.format("Rendered %s at %f, %f", text, xx, yy));
173: }
174:
175: @Override
176: public String toString()
177: {
178: return String.format("Attributes [%d %d,%d,%d,%d visible: %d font: %s]",
179: type,
180: x1,
181: y1,
182: x2,
183: y2,
184: visible,
185: logFont);
186: }
187: }
188:
189: public abstract static class Internal
190: {
191: protected final Attributes attributes;
192:
193: public Internal (final Attributes attributes)
194: {
195: this.attributes = attributes;
196: }
197:
198: public abstract void render (EditableImage image);
199: }
200:
201: public static class OiAnText extends Internal
202: {
203: private final double orientation;
204: private final double resolution;
205: private final String text;
206:
207: protected OiAnText (final Attributes attributes, final byte[] buffer)
208: throws IOException
209: {
210: super(attributes);
211: final var iis = ImageIO.createImageInputStream(new ByteArrayInputStream(buffer));
212: iis.setByteOrder(ByteOrder.LITTLE_ENDIAN);
213: orientation = iis.readInt() / 10.0;
214: final var d1000 = iis.readInt();
215: resolution = 72000.0 / iis.readInt();
216: final var len = iis.readInt();
217: final var bytes = new byte[len];
218: iis.read(bytes);
219: final var stringLength = (bytes[len - 1]) == 0 ? len - 1 : len;
220: text = new String(bytes, 0, stringLength, "CP1252");
221: iis.close();
222: }
223:
224: @Override
225: public void render (final EditableImage image)
226: {
227: image.execute(new DrawOp((g, image1) -> attributes.drawString(g, image1, text)));
228: }
229:
230: @Override
231: public String toString()
232: {
233: return String.format("OiAnText[angle: %f resolution: %f text: %s, %s]",
234: orientation,
235: resolution,
236: text,
237: attributes);
238: }
239: }
240:
241: public static class OiHilite extends Internal
242: {
243: protected OiHilite (final Attributes attributes)
244: {
245: super(attributes);
246: System.err.println(String.format("OiHilite"));
247: }
248:
249: @Override
250: public void render (final EditableImage image)
251: {
252: image.execute(new DrawOp(attributes::drawRectangle));
253: }
254:
255: @Override
256: public String toString()
257: {
258: return String.format("OiHilite[%s]", attributes);
259: }
260: }
261:
262: private final List<Internal> internals = new ArrayList<>();
263:
264: public WangAnnotations (final byte[] buffer)
265: throws IOException
266: {
267: final var bais = new ByteArrayInputStream(buffer);
268: final var iis = ImageIO.createImageInputStream(bais);
269: iis.setByteOrder(ByteOrder.LITTLE_ENDIAN);
270:
271: final var header = iis.readInt();
272: final var intSize = iis.readInt();
273:• assert intSize == 1;
274: Attributes attributes = null;
275:
276:• while (iis.getStreamPosition() < buffer.length)
277: {
278: final var dataType = iis.readInt();
279: final var dataSize = iis.readInt();
280: // System.err.println(String.format("dataType: %d size: %d", dataType, dataSize));
281:
282:• if ((dataType == 2) || (dataType == 6))
283: {
284:• System.err.println((dataType == 2) ? "DEFAULT NAMED BLOCK" : "PART OF PRECEDING");
285: final var bytes = new byte[8];
286: iis.read(bytes);
287: final var name = new String(bytes);
288: // System.err.println(String.format("named block: %s", name));
289: final var size = iis.readInt();
290: final var block = new byte[size];
291: iis.read(block);
292:
293:• if (name.startsWith("OiAnText"))
294: {
295: internals.add(new OiAnText(attributes, block));
296: }
297:• if (name.startsWith("OiHilite"))
298: {
299: internals.add(new OiHilite(attributes));
300: }
301: else
302: {
303: System.err.println(String.format("unmanaged named block: %s", name));
304: }
305: }
306:
307:• else if (dataType == 5)
308: {
309: final var block = new byte[dataSize];
310: iis.read(block);
311: attributes = new Attributes(block);
312: }
313: }
314:
315: System.err.println(internals);
316: }
317:
318: public void render (final EditableImage image)
319: {
320:• for (final var internal : internals)
321: {
322: internal.render(image);
323: }
324: }
325: }