/
AbstractWMFReader.java
473 lines (411 loc) · 14.5 KB
/
AbstractWMFReader.java
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
/*
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package org.apache.batik.transcoder.wmf.tosvg;
import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.List;
import java.util.ArrayList;
import org.apache.batik.transcoder.wmf.WMFConstants;
import org.apache.batik.util.Platform;
/**
* This class provides a general framework to read WMF Metafiles.
* @version $Id$
*/
public abstract class AbstractWMFReader {
public static final float PIXEL_PER_INCH = Platform.getScreenResolution();
public static final float MM_PER_PIXEL = 25.4f / Platform.getScreenResolution();
protected int left, right, top, bottom, width, height, inch;
protected float scaleX, scaleY, scaleXY;
protected int vpW, vpH, vpX, vpY;
// the sign values for X and Y, will be modified depending on the VIEWPORT values
protected int xSign = 1;
protected int ySign = 1;
protected volatile boolean bReading = false;
protected boolean isAldus = false;
protected boolean isotropic = true;
protected int mtType, mtHeaderSize, mtVersion, mtSize, mtNoObjects;
protected int mtMaxRecord, mtNoParameters;
protected int windowWidth, windowHeight;
protected int numObjects;
protected List objectVector;
public int lastObjectIdx;
public AbstractWMFReader() {
scaleX = 1;
scaleY = 1;
scaleXY = 1f;
left = -1;
top = -1;
width = -1;
height = -1;
right = left + width;
bottom = top + height;
numObjects = 0;
objectVector = new ArrayList();
}
public AbstractWMFReader(int width, int height) {
this();
this.width = width;
this.height = height;
}
/**
* Read the next short (2 bytes) value in the DataInputStream.
*/
protected short readShort(DataInputStream is) throws IOException {
byte js[] = new byte[ 2 ];
is.readFully(js);
int iTemp = ((0xff) & js[ 1 ] ) << 8;
short i = (short)(0xffff & iTemp);
i |= ((0xff) & js[ 0 ] );
return i;
}
/**
* Read the next int (4 bytes) value in the DataInputStream.
*/
protected int readInt( DataInputStream is) throws IOException {
byte js[] = new byte[ 4 ];
is.readFully(js);
int i = ((0xff) & js[ 3 ] ) << 24;
i |= ((0xff) & js[ 2 ] ) << 16;
i |= ((0xff) & js[ 1 ] ) << 8;
i |= ((0xff) & js[ 0 ] );
return i;
}
/**
* Returns the viewport width, in Metafile Units
*/
public float getViewportWidthUnits() {
return vpW;
}
/**
* Returns the viewport height, in Metafile Units
*/
public float getViewportHeightUnits() {
return vpH;
}
/**
* Returns the viewport width, in inches.
*/
public float getViewportWidthInch() {
return (float)vpW / (float)inch;
}
/**
* Returns the viewport height, in inches.
*/
public float getViewportHeightInch() {
return (float)vpH / (float)inch;
}
/** Return the number of pixels per unit.
*/
public float getPixelsPerUnit() {
return PIXEL_PER_INCH / (float)inch;
}
/**
* Returns the viewport width, in pixels.
*/
public int getVpW() {
return (int)(PIXEL_PER_INCH * (float)vpW / (float)inch);
}
/**
* Returns the viewport height, in pixels.
*/
public int getVpH() {
return (int)(PIXEL_PER_INCH * (float)vpH / (float)inch);
}
/** get the left units in the WMF Metafile. This value is given
* in the Aldus Placable Metafile.
*/
public int getLeftUnits() {
return left;
}
/** get the right units in the WMF Metafile. This value is given
* in the Aldus Placable Header.
*/
public int getRightUnits() {
return right;
}
/** get the top units in the WMF Metafile. This value is given
* in the Aldus Placable Header.
*/
public int getTopUnits() {
return top;
}
/** get the width units in the WMF Metafile. This value is given
* in the Aldus Placable Header.
*/
public int getWidthUnits() {
return width;
}
/** get the height units in the WMF Metafile. This value is given
* in the Aldus Placable Header.
*/
public int getHeightUnits() {
return height;
}
/** get the bottom units in the WMF Metafile. This value is given
* in the Aldus Placable Header.
*/
public int getBottomUnits() {
return bottom;
}
/** get the number of Metafile units per inch in the WMF Metafile.
* This value is given in the Aldus Placable Header.
*/
public int getMetaFileUnitsPerInch() {
return inch;
}
/** get the Rectangle defining the viewport of the WMF Metafile, in Metafile units.
* This viewport is defined in the Aldus Placable Header, by its left, top, bottom, right
* components.
* @see #getRightUnits()
* @see #getLeftUnits()
* @see #getTopUnits()
* @see #getBottomUnits()
*/
public Rectangle getRectangleUnits() {
Rectangle rec = new Rectangle(left, top, width, height);
return rec;
}
/** get the Rectangle defining the viewport of the WMF Metafile, in pixels.
*/
public Rectangle2D getRectanglePixel() {
float _left = PIXEL_PER_INCH * (float)left / (float)inch;
float _right = PIXEL_PER_INCH * (float)right / (float)inch;
float _top = PIXEL_PER_INCH * (float)top / (float)inch;
float _bottom = PIXEL_PER_INCH * (float)bottom / (float)inch;
Rectangle2D.Float rec = new Rectangle2D.Float(_left, _top, _right - _left, _bottom - _top);
return rec;
}
/** get the Rectangle defining the viewport of the WMF Metafile, in inchs.
*/
public Rectangle2D getRectangleInch() {
float _left = (float)left / (float)inch;
float _right = (float)right / (float)inch;
float _top = (float)top / (float)inch;
float _bottom = (float)bottom / (float)inch;
Rectangle2D.Float rec = new Rectangle2D.Float(_left, _top, _right - _left, _bottom - _top);
return rec;
}
/** get the width of the WMF Metafile, in pixels.
*/
public int getWidthPixels() {
return (int)(PIXEL_PER_INCH * (float)width / (float)inch);
}
/** get the factor to transform Metafile dimensions in pixels
*/
public float getUnitsToPixels() {
return (PIXEL_PER_INCH / (float)inch);
}
/** get the factor to transform logical units width in pixels
*/
public float getVpWFactor() {
return (PIXEL_PER_INCH * (float)width / (float)inch) / (float)vpW;
}
/** get the factor to transform logical units height in pixels
*/
public float getVpHFactor() {
return (PIXEL_PER_INCH * (float)height / (float)inch) / (float)vpH;
}
/** get the height of the WMF Metafile, in pixels.
*/
public int getHeightPixels() {
return (int)(PIXEL_PER_INCH * (float)height / (float)inch);
}
/** Return the sign of X coordinates. It is equal to 1 by default, but can be -1 if
* all X coordinates are inversed.
*/
public int getXSign() {
return xSign;
}
/** Return the sign of Y coordinates. It is equal to 1 by default, but can be -1 if
* all Y coordinates are inversed.
*/
public int getYSign() {
return ySign;
}
protected synchronized void setReading( boolean state ){
bReading = state;
}
/** @return true if the reader is currently reading an InputStream.
*/
public synchronized boolean isReading(){
return bReading;
}
/** resets this WMFReader.
*/
public abstract void reset();
/** Read this InputStream records. The aldus placeable header have already been
* read (see {@link #read(DataInputStream)}). The behavior of this method is left
* to the subclass.
* <p>Each Metafile record is composed of :
* <ul>
* <li>the size of the Record in int (32 bits)</li>
* <li>the function ID for the Record on a short word (16 bits)</li>
* <li>the function parameters, according to the WMF Metafile specification.
* the remaining size in short words (16 bits) for the parameters is equal to
* the total size for the record minus 3 short words (= 16 + 32 bits)</li>
* </ul>
* </p>
* <p>Example :</p>
* <pre>while (functionId > 0) {
* recSize = readInt( is );
* // Subtract size in 16-bit words of recSize and functionId;
* recSize -= 3;
* functionId = readShort( is );
* if ( functionId <= 0 )
* break;
* switch ( functionId ) {
* case WMFConstants.<a WMF function ID> {
* do something when this function is encountered
* }
* break;
*
* default:
* for ( int j = 0; j < recSize; j++ )
* readShort(is);
* break;
* </pre>
* @see WMFConstants
*/
protected abstract boolean readRecords(DataInputStream is) throws IOException;
/** Reads the WMF file from the specified Stream, read it and set the following
* properties:
* <ul>
* <li>{@link #mtType} : File type (0 : memory, 1 : disk)</li>
* <li>{@link #mtHeaderSize} : Size of header in WORDS (always 9)</li>
* <li>{@link #mtVersion} : Version of Microsoft Windows used</li>
* <li>{@link #mtSize} : Total size of the metafile in WORDs</li>
* <li>{@link #mtNoObjects} : Number of objects in the file</li>
* <li>{@link #mtMaxRecord} : The size of largest record in WORDs</li>
* <li>{@link #mtNoParameters} : Not Used (always 0)</li>
* </ul>
* If the file contains an APM
* (aldus placeable header), this method read these additionnal properties :
* <ul>
* <li>{@link #left} : Left coordinate in metafile units</li>
* <li>{@link #right} : Right coordinate in metafile units</li>
* <li>{@link #top} : Top coordinate in metafile units</li>
* <li>{@link #bottom} : Bottom coordinate in metafile units</li>
* <li>{@link #inch} : Number of metafile units per inch</li>
* </ul>
* <p>Then it calls the {@link #readRecords(DataInputStream)} abstract method,
* whose behavior is left to the subclass</p>.
*/
public void read(DataInputStream is) throws IOException {
reset();
setReading( true );
int dwIsAldus = readInt( is );
if ( dwIsAldus == WMFConstants.META_ALDUS_APM ) {
// Read the aldus placeable header.
int key = dwIsAldus;
isAldus = true;
readShort( is ); // metafile handle, always zero
left = readShort( is );
top = readShort( is );
right = readShort( is );
bottom = readShort( is );
inch = readShort( is );
int reserved = readInt( is );
short checksum = readShort( is );
// inverse values if left > right or top > bottom
if (left > right) {
int _i = right;
right = left;
left = _i;
xSign = -1;
}
if (top > bottom) {
int _i = bottom;
bottom = top;
top = _i;
ySign = -1;
}
width = right - left;
height = bottom - top;
// read the beginning of the header
mtType = readShort( is );
mtHeaderSize = readShort( is );
} else {
// read the beginning of the header, the first int corresponds to the first two parameters
mtType = ((dwIsAldus << 16) >> 16);
mtHeaderSize = dwIsAldus >> 16;
}
mtVersion = readShort( is );
mtSize = readInt( is );
mtNoObjects = readShort( is );
mtMaxRecord = readInt( is );
mtNoParameters = readShort( is );
numObjects = mtNoObjects;
List tempList = new ArrayList( numObjects );
for ( int i = 0; i < numObjects; i++ ) {
tempList.add( new GdiObject( i, false ));
}
objectVector.addAll( tempList );
boolean ret = readRecords(is);
is.close();
if (!ret) throw new IOException("Unhandled exception while reading records");
}
public int addObject( int type, Object obj ){
int startIdx = 0;
// if ( type == Wmf.PEN ) {
// startIdx = 2;
// }
for ( int i = startIdx; i < numObjects; i++ ) {
GdiObject gdi = (GdiObject)objectVector.get( i );
if ( ! gdi.used ) {
gdi.Setup( type, obj );
lastObjectIdx = i;
break;
}
}
return lastObjectIdx;
}
/**
* Adds a GdiObject to the internal handle table.
* Wmf files specify the index as given in EMF records such as
* EMRCREATEPENINDIRECT whereas WMF files always use 0.
*
* This function should not normally be called by an application.
* @return the object index
*/
public int addObjectAt( int type, Object obj, int idx ) {
if (( idx == 0 ) || ( idx > numObjects )) {
addObject( type, obj );
return lastObjectIdx;
}
lastObjectIdx = idx;
for ( int i = 0; i < numObjects; i++ ) {
GdiObject gdi = (GdiObject)objectVector.get( i );
if ( i == idx ) {
gdi.Setup( type, obj );
break;
}
}
return idx;
}
/**
* Returns a GdiObject from the handle table
*/
public GdiObject getObject( int idx ) {
return (GdiObject)objectVector.get( idx );
}
/**
* Returns the number of GdiObjects in the handle table
*/
public int getNumObjects() {
return numObjects;
}
}