View Javadoc

1   // Copyright 2001, FreeHEP.
2   package org.freehep.graphicsio.emf;
3   
4   import java.awt.Dimension;
5   import java.awt.Rectangle;
6   import java.io.IOException;
7   
8   /**
9    * EMF File Header.
10   * 
11   * @author Mark Donszelmann
12   * @version $Id: EMFHeader.java 10526 2007-02-12 08:14:31Z duns $
13   */
14  public class EMFHeader implements EMFConstants {
15      private static final Dimension screenMM = new Dimension(320, 240);
16  
17      private Rectangle bounds;
18  
19      private Rectangle frame;
20  
21      private String signature;
22  
23      private int versionMajor;
24  
25      private int versionMinor;
26  
27      private int bytes;
28  
29      private int records;
30  
31      private int handles;
32  
33      private String description;
34  
35      private int palEntries;
36  
37      private Dimension device;
38  
39      private Dimension millimeters;
40  
41      private Dimension micrometers;
42  
43      private boolean openGL;
44  
45      public EMFHeader(Rectangle bounds, int versionMajor, int versionMinor,
46              int bytes, int records, int handles, String application,
47              String name, Dimension device) {
48          this.bounds = bounds;
49  
50          // this assumes you use MM_ANISOTROPIC or MM_ISOTROPIC as MapMode
51          double pixelWidth = (double) screenMM.width / device.width;
52          double pixelHeight = (double) screenMM.height / device.height;
53          this.frame = new Rectangle((int) (bounds.x * 100 * pixelWidth),
54                  (int) (bounds.y * 100 * pixelHeight),
55                  (int) (bounds.width * 100 * pixelWidth),
56                  (int) (bounds.height * 100 * pixelHeight));
57  
58          this.signature = " EMF";
59          this.versionMajor = versionMajor;
60          this.versionMinor = versionMinor;
61          this.bytes = bytes;
62          this.records = records;
63          this.handles = handles;
64          this.description = application.trim() + "\0" + name.trim() + "\0\0";
65  
66          this.palEntries = 0;
67          this.device = device;
68          this.millimeters = screenMM;
69  
70          this.openGL = false;
71          this.micrometers = new Dimension(screenMM.width * 1000,
72                  screenMM.height * 1000);
73      }
74  
75      EMFHeader(EMFInputStream emf) throws IOException {
76          // FIXME: incomplete
77          emf.readUnsignedInt(); // 4
78  
79          int length = emf.readDWORD(); // 8
80  
81          bounds = emf.readRECTL(); // 24
82          frame = emf.readRECTL(); // 40
83          signature = new String(emf.readBYTE(4)); // 44
84  
85          int version = emf.readDWORD(); // 48
86          versionMajor = version >> 16;
87          versionMinor = version & 0xFFFF;
88          bytes = emf.readDWORD(); // 52
89          records = emf.readDWORD(); // 56
90          handles = emf.readWORD(); // 58
91          emf.readWORD(); // 60
92  
93          int dLen = emf.readDWORD(); // 64
94          int dOffset = emf.readDWORD(); // 68
95          palEntries = emf.readDWORD(); // 72
96          device = emf.readSIZEL(); // 80
97          millimeters = emf.readSIZEL(); // 88
98  
99          int bytesRead = 88;
100         if (dOffset > 88) {
101             emf.readDWORD(); // 92
102             emf.readDWORD(); // 96
103             openGL = (emf.readDWORD() != 0) ? true : false; // 100
104             bytesRead += 12;
105             if (dOffset > 100) {
106                 micrometers = emf.readSIZEL(); // 108
107                 bytesRead += 8;
108             }
109         }
110 
111         // Discard any bytes leading up to the description (usually zero, but safer not to assume.)
112         if (bytesRead < dOffset) {
113             emf.skipBytes(dOffset - bytesRead);
114             bytesRead = dOffset;
115         }
116 
117         description = emf.readWCHAR(dLen);
118         bytesRead += dLen * 2;
119 
120         // Discard bytes after the description up to the end of the header.
121         if (bytesRead < length) {
122             emf.skipBytes(length - bytesRead);
123         }
124     }
125 
126     public void write(EMFOutputStream emf) throws IOException {
127         int align = emf.getTagAlignment();
128         int padding = (align - (size() % align)) % align;
129         int alignedSize = size() + padding;
130 
131         emf.writeDWORD(0x00000001); // Header Type
132         emf.writeDWORD(alignedSize); // length of header
133         emf.writeRECTL(bounds); // inclusive bounds
134         emf.writeRECTL(frame); // inclusive picture
135 
136         emf.writeBYTE(signature.getBytes()); // signature ID EMF
137         emf.writeDWORD((versionMajor << 16) | versionMinor); // version
138         emf.writeDWORD(alignedSize + bytes); // file size
139         emf.writeDWORD(records); // # of records
140         emf.writeWORD(handles); // # of handles, 1 minimum
141         emf.writeWORD(0); // reserved
142         emf.writeDWORD(description.length()); // size of descriptor in WORDS
143         emf.writeDWORD(0x6C); // offset to descriptor
144         emf.writeDWORD(palEntries); // # of palette entries
145         emf.writeSIZEL(device); // size of ref device
146         emf.writeSIZEL(millimeters); // size of ref device in MM
147         emf.writeDWORD(0); // cbPixelFormat
148         emf.writeDWORD(0); // offPixelFormat
149         emf.writeDWORD(openGL); // bOpenGL
150         emf.writeSIZEL(micrometers); // size of ref device in microns
151 
152         // optional description
153         emf.writeWCHAR(description);
154 
155         // padding
156         for (int i = 0; i < padding; i++) {
157             emf.write(0);
158         }
159     }
160 
161     /**
162      * @return size of emf file in bytes ?
163      */
164     public int size() {
165         return 108 + (2 * description.length());
166     }
167 
168     public String toString() {
169         StringBuffer s = new StringBuffer("EMF Header\n");
170         s.append("  bounds: ").append(bounds).append("\n");
171         s.append("  frame: ").append(frame).append("\n");
172         s.append("  signature: ").append(signature).append("\n");
173         s.append("  versionMajor: ").append(versionMajor).append("\n");
174         s.append("  versionMinor: ").append(versionMinor).append("\n");
175         s.append("  #bytes: ").append(bytes).append("\n");
176         s.append("  #records: ").append(records).append("\n");
177         s.append("  #handles: ").append(handles).append("\n");
178         s.append("  description: ").append(description).append("\n");
179         s.append("  #palEntries: ").append(palEntries).append("\n");
180         s.append("  device: ").append(device).append("\n");
181         s.append("  millimeters: ").append(millimeters).append("\n");
182 
183         s.append("  openGL: ").append(openGL).append("\n");
184         s.append("  micrometers: ").append(micrometers);
185 
186         return s.toString();
187     }
188 
189     /**
190      * Specifies the dimensions, in device units, of the smallest rectangle that
191      * can be drawn around the picture stored in the metafile. This rectangle is
192      * supplied by graphics device interface (GDI). Its dimensions include the
193      * right and bottom edges.
194      * @return bounds of device
195      */
196     public Rectangle getBounds() {
197         return bounds;
198     }
199 
200     /**
201      * Specifies the dimensions, in .01 millimeter units, of a rectangle that
202      * surrounds the picture stored in the metafile. This rectangle must be
203      * supplied by the application that creates the metafile. Its dimensions
204      * include the right and bottom edges.
205      * @return bounds of frame
206      */
207     public Rectangle getFrame() {
208         return frame;
209     }
210 
211     /**
212      * Specifies a double word signature. This member must specify the value
213      * assigned to the ENHMETA_SIGNATURE constant.
214      * @return signature
215      */
216     public String getSignature() {
217         return signature;
218     }
219 
220     /**
221      * @return the description of the enhanced metafile's contents
222      */
223     public String getDescription() {
224         return description;
225     }
226 
227     /**
228      * Specifies the resolution of the reference device, in pixels.
229      * @return resolution of the reference device, in pixels
230      */
231     public Dimension getDevice() {
232         return device;
233     }
234 
235     /**
236      * Specifies the resolution of the reference device, in millimeters.
237      * @return size in millimeters
238      */
239     public Dimension getMillimeters() {
240         return millimeters;
241     }
242 
243     /**
244      * Windows 98/Me, Windows 2000/XP: Size of the reference device in
245      * micrometers.
246      * @return size in micrometers
247      */
248     public Dimension getMicrometers() {
249         return micrometers;
250     }
251 
252     /**
253      * Windows 95/98/Me, Windows NT 4.0 and later: Specifies whether any OpenGL
254      * records are present in a metafile. bOpenGL is a simple Boolean flag that
255      * you can use to determine whether an enhanced metafile requires OpenGL
256      * handling. When a metafile contains OpenGL records, bOpenGL is TRUE;
257      * otherwise it is FALSE.
258      *
259      * @return false is default
260      */
261     public boolean isOpenGL() {
262         return openGL;
263     }
264 }