/* ==================================================================== | |
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.poi.hwmf.record; | |
import java.awt.Shape; | |
import java.awt.geom.Area; | |
import java.awt.geom.Rectangle2D; | |
import java.io.IOException; | |
import org.apache.poi.hwmf.draw.HwmfGraphics; | |
import org.apache.poi.util.LittleEndianConsts; | |
import org.apache.poi.util.LittleEndianInputStream; | |
public class HwmfWindowing { | |
/** | |
* The META_SETVIEWPORTORG record defines the viewport origin in the playback device context. | |
*/ | |
public static class WmfSetViewportOrg implements HwmfRecord { | |
/** | |
* A 16-bit signed integer that defines the vertical offset, in device units. | |
*/ | |
private int y; | |
/** | |
* A 16-bit signed integer that defines the horizontal offset, in device units. | |
*/ | |
private int x; | |
@Override | |
public HwmfRecordType getRecordType() { | |
return HwmfRecordType.setViewportOrg; | |
} | |
@Override | |
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException { | |
y = leis.readShort(); | |
x = leis.readShort(); | |
return 2*LittleEndianConsts.SHORT_SIZE; | |
} | |
@Override | |
public void draw(HwmfGraphics ctx) { | |
ctx.getProperties().setViewportOrg(x, y); | |
} | |
} | |
/** | |
* The META_SETVIEWPORTEXT record sets the horizontal and vertical extents | |
* of the viewport in the playback device context. | |
*/ | |
public static class WmfSetViewportExt implements HwmfRecord { | |
/** | |
* A 16-bit signed integer that defines the vertical extent | |
* of the viewport in device units. | |
*/ | |
private int height; | |
/** | |
* A 16-bit signed integer that defines the horizontal extent | |
* of the viewport in device units. | |
*/ | |
private int width; | |
@Override | |
public HwmfRecordType getRecordType() { | |
return HwmfRecordType.setViewportExt; | |
} | |
@Override | |
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException { | |
height = leis.readShort(); | |
width = leis.readShort(); | |
return 2*LittleEndianConsts.SHORT_SIZE; | |
} | |
@Override | |
public void draw(HwmfGraphics ctx) { | |
ctx.getProperties().setViewportExt(width, height); | |
} | |
} | |
/** | |
* The META_OFFSETVIEWPORTORG record moves the viewport origin in the playback device context | |
* by specified horizontal and vertical offsets. | |
*/ | |
public static class WmfOffsetViewportOrg implements HwmfRecord { | |
/** | |
* A 16-bit signed integer that defines the vertical offset, in device units. | |
*/ | |
private int yOffset; | |
/** | |
* A 16-bit signed integer that defines the horizontal offset, in device units. | |
*/ | |
private int xOffset; | |
@Override | |
public HwmfRecordType getRecordType() { | |
return HwmfRecordType.offsetViewportOrg; | |
} | |
@Override | |
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException { | |
yOffset = leis.readShort(); | |
xOffset = leis.readShort(); | |
return 2*LittleEndianConsts.SHORT_SIZE; | |
} | |
@Override | |
public void draw(HwmfGraphics ctx) { | |
Rectangle2D viewport = ctx.getProperties().getViewport(); | |
double x = (viewport == null) ? 0 : viewport.getX(); | |
double y = (viewport == null) ? 0 : viewport.getY(); | |
ctx.getProperties().setViewportOrg(x+xOffset, y+yOffset); | |
} | |
} | |
/** | |
* The META_SETWINDOWORG record defines the output window origin in the playback device context. | |
*/ | |
public static class WmfSetWindowOrg implements HwmfRecord { | |
/** | |
* A 16-bit signed integer that defines the y-coordinate, in logical units. | |
*/ | |
private int y; | |
/** | |
* A 16-bit signed integer that defines the x-coordinate, in logical units. | |
*/ | |
private int x; | |
@Override | |
public HwmfRecordType getRecordType() { | |
return HwmfRecordType.setWindowOrg; | |
} | |
@Override | |
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException { | |
y = leis.readShort(); | |
x = leis.readShort(); | |
return 2*LittleEndianConsts.SHORT_SIZE; | |
} | |
@Override | |
public void draw(HwmfGraphics ctx) { | |
ctx.getProperties().setWindowOrg(x, y); | |
ctx.updateWindowMapMode(); | |
} | |
public int getY() { | |
return y; | |
} | |
public int getX() { | |
return x; | |
} | |
} | |
/** | |
* The META_SETWINDOWEXT record defines the horizontal and vertical extents | |
* of the output window in the playback device context. | |
*/ | |
public static class WmfSetWindowExt implements HwmfRecord { | |
/** | |
* A 16-bit signed integer that defines the vertical extent of | |
* the window in logical units. | |
*/ | |
private int height; | |
/** | |
* A 16-bit signed integer that defines the horizontal extent of | |
* the window in logical units. | |
*/ | |
private int width; | |
@Override | |
public HwmfRecordType getRecordType() { | |
return HwmfRecordType.setWindowExt; | |
} | |
@Override | |
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException { | |
height = leis.readShort(); | |
width = leis.readShort(); | |
return 2*LittleEndianConsts.SHORT_SIZE; | |
} | |
@Override | |
public void draw(HwmfGraphics ctx) { | |
ctx.getProperties().setWindowExt(width, height); | |
ctx.updateWindowMapMode(); | |
} | |
public int getHeight() { | |
return height; | |
} | |
public int getWidth() { | |
return width; | |
} | |
} | |
/** | |
* The META_OFFSETWINDOWORG record moves the output window origin in the | |
* playback device context by specified horizontal and vertical offsets. | |
*/ | |
public static class WmfOffsetWindowOrg implements HwmfRecord { | |
/** | |
* A 16-bit signed integer that defines the vertical offset, in device units. | |
*/ | |
private int yOffset; | |
/** | |
* A 16-bit signed integer that defines the horizontal offset, in device units. | |
*/ | |
private int xOffset; | |
@Override | |
public HwmfRecordType getRecordType() { | |
return HwmfRecordType.offsetWindowOrg; | |
} | |
@Override | |
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException { | |
yOffset = leis.readShort(); | |
xOffset = leis.readShort(); | |
return 2*LittleEndianConsts.SHORT_SIZE; | |
} | |
@Override | |
public void draw(HwmfGraphics ctx) { | |
Rectangle2D window = ctx.getProperties().getWindow(); | |
ctx.getProperties().setWindowOrg(window.getX()+xOffset, window.getY()+yOffset); | |
ctx.updateWindowMapMode(); | |
} | |
} | |
/** | |
* The META_OFFSETWINDOWORG record moves the output window origin in the | |
* playback device context by specified horizontal and vertical offsets. | |
*/ | |
public static class WmfScaleWindowExt implements HwmfRecord { | |
/** | |
* A 16-bit signed integer that defines the amount by which to divide the | |
* result of multiplying the current y-extent by the value of the yNum member. | |
*/ | |
private int yDenom; | |
/** | |
* A 16-bit signed integer that defines the amount by which to multiply the | |
* current y-extent. | |
*/ | |
private int yNum; | |
/** | |
* A 16-bit signed integer that defines the amount by which to divide the | |
* result of multiplying the current x-extent by the value of the xNum member. | |
*/ | |
private int xDenom; | |
/** | |
* A 16-bit signed integer that defines the amount by which to multiply the | |
* current x-extent. | |
*/ | |
private int xNum; | |
@Override | |
public HwmfRecordType getRecordType() { | |
return HwmfRecordType.scaleWindowExt; | |
} | |
@Override | |
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException { | |
yDenom = leis.readShort(); | |
yNum = leis.readShort(); | |
xDenom = leis.readShort(); | |
xNum = leis.readShort(); | |
return 4*LittleEndianConsts.SHORT_SIZE; | |
} | |
@Override | |
public void draw(HwmfGraphics ctx) { | |
Rectangle2D window = ctx.getProperties().getWindow(); | |
double width = window.getWidth() * xNum / xDenom; | |
double height = window.getHeight() * yNum / yDenom; | |
ctx.getProperties().setWindowExt(width, height); | |
ctx.updateWindowMapMode(); | |
} | |
} | |
/** | |
* The META_SCALEVIEWPORTEXT record scales the horizontal and vertical extents of the viewport | |
* that is defined in the playback device context by using the ratios formed by the specified | |
* multiplicands and divisors. | |
*/ | |
public static class WmfScaleViewportExt implements HwmfRecord { | |
/** | |
* A 16-bit signed integer that defines the amount by which to divide the | |
* result of multiplying the current y-extent by the value of the yNum member. | |
*/ | |
private int yDenom; | |
/** | |
* A 16-bit signed integer that defines the amount by which to multiply the | |
* current y-extent. | |
*/ | |
private int yNum; | |
/** | |
* A 16-bit signed integer that defines the amount by which to divide the | |
* result of multiplying the current x-extent by the value of the xNum member. | |
*/ | |
private int xDenom; | |
/** | |
* A 16-bit signed integer that defines the amount by which to multiply the | |
* current x-extent. | |
*/ | |
private int xNum; | |
@Override | |
public HwmfRecordType getRecordType() { | |
return HwmfRecordType.scaleViewportExt; | |
} | |
@Override | |
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException { | |
yDenom = leis.readShort(); | |
yNum = leis.readShort(); | |
xDenom = leis.readShort(); | |
xNum = leis.readShort(); | |
return 4*LittleEndianConsts.SHORT_SIZE; | |
} | |
@Override | |
public void draw(HwmfGraphics ctx) { | |
Rectangle2D viewport = ctx.getProperties().getViewport(); | |
if (viewport == null) { | |
viewport = ctx.getProperties().getWindow(); | |
} | |
double width = viewport.getWidth() * xNum / xDenom; | |
double height = viewport.getHeight() * yNum / yDenom; | |
ctx.getProperties().setViewportExt(width, height); | |
} | |
} | |
/** | |
* The META_OFFSETCLIPRGN record moves the clipping region in the playback device context by the | |
* specified offsets. | |
*/ | |
public static class WmfOffsetClipRgn implements HwmfRecord, HwmfObjectTableEntry { | |
/** | |
* A 16-bit signed integer that defines the number of logical units to move up or down. | |
*/ | |
private int yOffset; | |
/** | |
* A 16-bit signed integer that defines the number of logical units to move left or right. | |
*/ | |
private int xOffset; | |
@Override | |
public HwmfRecordType getRecordType() { | |
return HwmfRecordType.offsetClipRgn; | |
} | |
@Override | |
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException { | |
yOffset = leis.readShort(); | |
xOffset = leis.readShort(); | |
return 2*LittleEndianConsts.SHORT_SIZE; | |
} | |
@Override | |
public void draw(HwmfGraphics ctx) { | |
ctx.addObjectTableEntry(this); | |
} | |
@Override | |
public void applyObject(HwmfGraphics ctx) { | |
} | |
} | |
/** | |
* The META_EXCLUDECLIPRECT record sets the clipping region in the playback device context to the | |
* existing clipping region minus the specified rectangle. | |
*/ | |
public static class WmfExcludeClipRect implements HwmfRecord, HwmfObjectTableEntry { | |
/** | |
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the | |
* lower-right corner of the rectangle. | |
*/ | |
private int bottom; | |
/** | |
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the | |
* lower-right corner of the rectangle. | |
*/ | |
private int right; | |
/** | |
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the | |
* upper-left corner of the rectangle. | |
*/ | |
private int top; | |
/** | |
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the | |
* upper-left corner of the rectangle. | |
*/ | |
private int left; | |
@Override | |
public HwmfRecordType getRecordType() { | |
return HwmfRecordType.excludeClipRect; | |
} | |
@Override | |
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException { | |
bottom = leis.readShort(); | |
right = leis.readShort(); | |
top = leis.readShort(); | |
left = leis.readShort(); | |
return 4*LittleEndianConsts.SHORT_SIZE; | |
} | |
@Override | |
public void draw(HwmfGraphics ctx) { | |
ctx.addObjectTableEntry(this); | |
} | |
@Override | |
public void applyObject(HwmfGraphics ctx) { | |
} | |
} | |
/** | |
* The META_INTERSECTCLIPRECT record sets the clipping region in the playback device context to the | |
* intersection of the existing clipping region and the specified rectangle. | |
*/ | |
public static class WmfIntersectClipRect implements HwmfRecord, HwmfObjectTableEntry { | |
/** | |
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the | |
* lower-right corner of the rectangle. | |
*/ | |
private int bottom; | |
/** | |
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the | |
* lower-right corner of the rectangle. | |
*/ | |
private int right; | |
/** | |
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the | |
* upper-left corner of the rectangle. | |
*/ | |
private int top; | |
/** | |
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the | |
* upper-left corner of the rectangle. | |
*/ | |
private int left; | |
@Override | |
public HwmfRecordType getRecordType() { | |
return HwmfRecordType.intersectClipRect; | |
} | |
@Override | |
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException { | |
bottom = leis.readShort(); | |
right = leis.readShort(); | |
top = leis.readShort(); | |
left = leis.readShort(); | |
return 4*LittleEndianConsts.SHORT_SIZE; | |
} | |
@Override | |
public void draw(HwmfGraphics ctx) { | |
ctx.addObjectTableEntry(this); | |
} | |
@Override | |
public void applyObject(HwmfGraphics ctx) { | |
} | |
} | |
/** | |
* The META_SELECTCLIPREGION record specifies a Region Object to be the current clipping region. | |
*/ | |
public static class WmfSelectClipRegion implements HwmfRecord { | |
/** | |
* A 16-bit unsigned integer used to index into the WMF Object Table to get | |
* the region to be clipped. | |
*/ | |
private int region; | |
@Override | |
public HwmfRecordType getRecordType() { | |
return HwmfRecordType.selectClipRegion; | |
} | |
@Override | |
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException { | |
region = leis.readShort(); | |
return LittleEndianConsts.SHORT_SIZE; | |
} | |
@Override | |
public void draw(HwmfGraphics ctx) { | |
} | |
} | |
public static class WmfScanObject { | |
/** | |
* A 16-bit unsigned integer that specifies the number of horizontal (x-axis) | |
* coordinates in the ScanLines array. This value MUST be a multiple of 2, since left and right | |
* endpoints are required to specify each scanline. | |
*/ | |
private int count; | |
/** | |
* A 16-bit unsigned integer that defines the vertical (y-axis) coordinate, in logical units, of the top scanline. | |
*/ | |
private int top; | |
/** | |
* A 16-bit unsigned integer that defines the vertical (y-axis) coordinate, in logical units, of the bottom scanline. | |
*/ | |
private int bottom; | |
/** | |
* A 16-bit unsigned integer that defines the horizontal (x-axis) coordinate, | |
* in logical units, of the left endpoint of the scanline. | |
*/ | |
private int left_scanline[]; | |
/** | |
* A 16-bit unsigned integer that defines the horizontal (x-axis) coordinate, | |
* in logical units, of the right endpoint of the scanline. | |
*/ | |
private int right_scanline[]; | |
/** | |
* A 16-bit unsigned integer that MUST be the same as the value of the Count | |
* field; it is present to allow upward travel in the structure. | |
*/ | |
private int count2; | |
public int init(LittleEndianInputStream leis) { | |
count = leis.readUShort(); | |
top = leis.readUShort(); | |
bottom = leis.readUShort(); | |
int size = 3*LittleEndianConsts.SHORT_SIZE; | |
left_scanline = new int[count/2]; | |
right_scanline = new int[count/2]; | |
for (int i=0; i<count/2; i++) { | |
left_scanline[i] = leis.readUShort(); | |
right_scanline[i] = leis.readUShort(); | |
size += 2*LittleEndianConsts.SHORT_SIZE; | |
} | |
count2 = leis.readUShort(); | |
size += LittleEndianConsts.SHORT_SIZE; | |
return size; | |
} | |
} | |
public static class WmfCreateRegion implements HwmfRecord, HwmfObjectTableEntry { | |
/** | |
* A 16-bit signed integer. A value that MUST be ignored. | |
*/ | |
private int nextInChain; | |
/** | |
* A 16-bit signed integer that specifies the region identifier. It MUST be 0x0006. | |
*/ | |
private int objectType; | |
/** | |
* A 32-bit unsigned integer. A value that MUST be ignored. | |
*/ | |
private int objectCount; | |
/** | |
* A 16-bit signed integer that defines the size of the region in bytes plus the size of aScans in bytes. | |
*/ | |
private int regionSize; | |
/** | |
* A 16-bit signed integer that defines the number of scanlines composing the region. | |
*/ | |
private int scanCount; | |
/** | |
* A 16-bit signed integer that defines the maximum number of points in any one scan in this region. | |
*/ | |
private int maxScan; | |
/** | |
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the | |
* lower-right corner of the rectangle. | |
*/ | |
private int bottom; | |
/** | |
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the | |
* lower-right corner of the rectangle. | |
*/ | |
private int right; | |
/** | |
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the | |
* upper-left corner of the rectangle. | |
*/ | |
private int top; | |
/** | |
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the | |
* upper-left corner of the rectangle. | |
*/ | |
private int left; | |
/** | |
* An array of Scan objects that define the scanlines in the region. | |
*/ | |
private WmfScanObject scanObjects[]; | |
@Override | |
public HwmfRecordType getRecordType() { | |
return HwmfRecordType.createRegion; | |
} | |
@Override | |
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException { | |
nextInChain = leis.readShort(); | |
objectType = leis.readShort(); | |
objectCount = leis.readInt(); | |
regionSize = leis.readShort(); | |
scanCount = leis.readShort(); | |
maxScan = leis.readShort(); | |
left = leis.readShort(); | |
top = leis.readShort(); | |
right = leis.readShort(); | |
bottom = leis.readShort(); | |
int size = 9*LittleEndianConsts.SHORT_SIZE+LittleEndianConsts.INT_SIZE; | |
scanObjects = new WmfScanObject[scanCount]; | |
for (int i=0; i<scanCount; i++) { | |
size += (scanObjects[i] = new WmfScanObject()).init(leis); | |
} | |
return size; | |
} | |
@Override | |
public void draw(HwmfGraphics ctx) { | |
ctx.addObjectTableEntry(this); | |
} | |
@Override | |
public void applyObject(HwmfGraphics ctx) { | |
Rectangle2D lastRect = null; | |
Area scanLines = new Area(); | |
int count = 0; | |
for (WmfScanObject so : scanObjects) { | |
int y = Math.min(so.top, so.bottom); | |
int h = Math.abs(so.top - so.bottom - 1); | |
for (int i=0; i<so.count/2; i++) { | |
int x = Math.min(so.left_scanline[i], so.right_scanline[i]); | |
int w = Math.abs(so.right_scanline[i] - so.left_scanline[i] - 1); | |
lastRect = new Rectangle2D.Double(x,y,w,h); | |
scanLines.add(new Area(lastRect)); | |
count++; | |
} | |
} | |
Shape region = null; | |
if (count > 0) { | |
region = (count == 1) ? lastRect : scanLines; | |
} | |
ctx.getProperties().setRegion(region); | |
} | |
} | |
} |