mirror of
https://github.com/apache/poi.git
synced 2026-02-27 20:40:08 +08:00
#64716 - wmf display error
prepare binary raster operations git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1883882 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
c6b408b232
commit
3f83c76321
106
src/examples/src/org/apache/poi/examples/hwmf/ROP2Table.java
Normal file
106
src/examples/src/org/apache/poi/examples/hwmf/ROP2Table.java
Normal file
@ -0,0 +1,106 @@
|
||||
/* ====================================================================
|
||||
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.examples.hwmf;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Composite;
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import org.apache.poi.hwmf.draw.HwmfROP2Composite;
|
||||
import org.apache.poi.hwmf.record.HwmfBinaryRasterOp;
|
||||
import org.apache.poi.util.Units;
|
||||
|
||||
/**
|
||||
* Generates an image table describing the various binary raster operations
|
||||
*
|
||||
* inspired from http://www.fengyuan.com/sample/samplech8.html
|
||||
*/
|
||||
public final class ROP2Table {
|
||||
private static final Color[] COLORS = {
|
||||
new Color(0,0,0),
|
||||
new Color(128,0,0),
|
||||
new Color(0,128,0),
|
||||
new Color(128,128,0),
|
||||
new Color(0,0,128),
|
||||
new Color(128,0,128),
|
||||
new Color(0,128,128),
|
||||
new Color(192,192,192),
|
||||
new Color(255,255,255),
|
||||
new Color(128,128,128),
|
||||
new Color(255,0,0),
|
||||
new Color(0,255,0),
|
||||
new Color(255,255,0),
|
||||
new Color(0,0,255),
|
||||
new Color(255,0,255),
|
||||
new Color(0,255,255)
|
||||
};
|
||||
|
||||
private ROP2Table() {
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
int square = 800;
|
||||
BufferedImage bi = new BufferedImage(square + 500, square, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g = bi.createGraphics();
|
||||
double space = 0.2;
|
||||
double hbar = square / (COLORS.length + space);
|
||||
double vbar = square / (COLORS.length + space);
|
||||
double y = hbar * space;
|
||||
double x = vbar * space;
|
||||
double w = square - 2*x;
|
||||
double h = square - 2*y;
|
||||
|
||||
Rectangle2D vrect = new Rectangle2D.Double(x, y, vbar * (1-space), h);
|
||||
for (Color c : COLORS) {
|
||||
g.setColor(c);
|
||||
g.fill(vrect);
|
||||
g.translate(vbar, 0);
|
||||
}
|
||||
|
||||
g.setTransform(new AffineTransform());
|
||||
g.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, (int) Units.pixelToPoints(hbar * 0.8)));
|
||||
|
||||
Composite comp = g.getComposite();
|
||||
|
||||
Rectangle2D hrect = new Rectangle2D.Double(x, y, w, hbar * (1-space));
|
||||
int idx = 0;
|
||||
for (HwmfBinaryRasterOp op : HwmfBinaryRasterOp.values()) {
|
||||
g.setComposite(comp);
|
||||
g.setColor(Color.BLACK);
|
||||
g.drawString(op.name(), (int)(square+vbar), (int)(hbar*0.8));
|
||||
g.setComposite(new HwmfROP2Composite(op));
|
||||
g.setColor(Color.RED);
|
||||
g.fill(hrect);
|
||||
g.translate(0, hbar);
|
||||
idx++;
|
||||
}
|
||||
|
||||
g.dispose();
|
||||
ImageIO.write(bi, "PNG", new File("rop2.png"));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
168
src/examples/src/org/apache/poi/examples/hwmf/ROP3Table.java
Normal file
168
src/examples/src/org/apache/poi/examples/hwmf/ROP3Table.java
Normal file
@ -0,0 +1,168 @@
|
||||
/* ====================================================================
|
||||
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.examples.hwmf;
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Shape;
|
||||
import java.awt.TexturePaint;
|
||||
import java.awt.font.TextLayout;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.IndexColorModel;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import org.apache.poi.hwmf.draw.HwmfROP3Composite;
|
||||
import org.apache.poi.hwmf.record.HwmfTernaryRasterOp;
|
||||
|
||||
/**
|
||||
* Generates an image table describing the various ternary raster operations
|
||||
*
|
||||
* inspired from http://www.evmsoft.net/en/roptest.html
|
||||
*/
|
||||
public final class ROP3Table {
|
||||
private ROP3Table() {
|
||||
}
|
||||
|
||||
private static byte[] PATTERN = {
|
||||
1, 0, 1, 0, 1, 0, 1, 0,
|
||||
0, 1, 0, 1, 0, 1, 0, 1,
|
||||
1, 0, 1, 1, 1, 0, 1, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 1,
|
||||
1, 0, 1, 0, 1, 0, 1, 0,
|
||||
0, 1, 0, 1, 0, 1, 0, 1,
|
||||
1, 0, 1, 1, 1, 0, 1, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 1,
|
||||
};
|
||||
|
||||
private static final HwmfTernaryRasterOp[] OPS = HwmfTernaryRasterOp.values();
|
||||
private static final int COLS = 16;
|
||||
private static final double BOX = 100, SCALE = 1, HEADER = 1.1;
|
||||
|
||||
private static final Rectangle2D RECT = new Rectangle2D.Double(0.05* BOX, 0.05* BOX, 0.90* BOX, 0.90* BOX);
|
||||
private static final Shape CIRCLE_BIG = new Ellipse2D.Double(0.15* BOX, 0.15* BOX, 0.70* BOX, 0.70* BOX);
|
||||
private static final Shape CIRCLE_SMALL = new Ellipse2D.Double(0.40* BOX, 0.40* BOX, 0.20* BOX, 0.20* BOX);
|
||||
private static final Shape LABEL_BOX = new Rectangle.Double(0.06* BOX, 0.85* BOX, 0.88* BOX, 0.10* BOX);
|
||||
|
||||
private static final AlphaComposite SRC_OVER = AlphaComposite.getInstance(AlphaComposite.SRC_OVER);
|
||||
|
||||
private static final AffineTransform INIT_AT = AffineTransform.getScaleInstance(SCALE, SCALE);
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
BufferedImage pattern = getPattern();
|
||||
BufferedImage source = getSource();
|
||||
|
||||
BufferedImage dest = new BufferedImage(
|
||||
(int)(BOX * COLS * SCALE),
|
||||
(int)(BOX *(Math.max(OPS.length/COLS,1) + HEADER)* SCALE),
|
||||
BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g = dest.createGraphics();
|
||||
|
||||
g.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 10));
|
||||
|
||||
g.setTransform(INIT_AT);
|
||||
g.setColor(Color.BLACK);
|
||||
|
||||
for (int i=0; i<3; i++) {
|
||||
String str = new String[]{"Dest:","Source:","Pattern:"}[i];
|
||||
TextLayout t = new TextLayout(str, g.getFont(), g.getFontRenderContext());
|
||||
Rectangle2D b = t.getBounds();
|
||||
g.drawString(str, (float)(((i*2+0.95)*BOX - b.getWidth())), (float)(0.55 * BOX));
|
||||
}
|
||||
|
||||
g.translate(BOX, 0);
|
||||
fillDest(g);
|
||||
g.translate(2*BOX, 0);
|
||||
g.drawImage(source, 0, 0, null);
|
||||
g.translate(2*BOX, 0);
|
||||
g.setPaint(new TexturePaint(pattern, RECT));
|
||||
g.fill(RECT);
|
||||
|
||||
int idx=0;
|
||||
for (HwmfTernaryRasterOp op : OPS) {
|
||||
g.setTransform(INIT_AT);
|
||||
g.translate(0, HEADER * BOX);
|
||||
g.translate(BOX*(idx%COLS), BOX*(idx/COLS));
|
||||
|
||||
fillDest(g);
|
||||
fillPattern(g, op, pattern, source);
|
||||
fillLabel(g, op);
|
||||
idx++;
|
||||
}
|
||||
|
||||
g.dispose();
|
||||
ImageIO.write(dest, "PNG", new File("rop3.png"));
|
||||
}
|
||||
|
||||
private static BufferedImage getPattern() {
|
||||
byte[] bw = { 0, -1 };
|
||||
BufferedImage pattern = new BufferedImage(8, 8, BufferedImage.TYPE_BYTE_INDEXED, new IndexColorModel(1, 2, bw, bw, bw));
|
||||
pattern.getRaster().setDataElements(0, 0, 8, 8, PATTERN);
|
||||
return pattern;
|
||||
}
|
||||
|
||||
private static BufferedImage getSource() {
|
||||
BufferedImage checker = new BufferedImage((int) BOX, (int) BOX, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D cg = checker.createGraphics();
|
||||
cg.setColor(Color.PINK);
|
||||
cg.fill(new Rectangle2D.Double(0.05* BOX, 0.05* BOX, 0.90* BOX, 0.90* BOX));
|
||||
cg.setColor(new Color(0xE6E6FA, false));
|
||||
cg.fill(new Rectangle2D.Double(0.05* BOX, 0.05* BOX, 0.45* BOX, 0.45* BOX));
|
||||
cg.fill(new Rectangle2D.Double(0.50* BOX, 0.50* BOX, 0.45* BOX, 0.45* BOX));
|
||||
cg.dispose();
|
||||
return checker;
|
||||
}
|
||||
|
||||
private static void fillDest(Graphics2D g) {
|
||||
g.setComposite(SRC_OVER);
|
||||
g.setColor(Color.LIGHT_GRAY);
|
||||
g.fill(RECT);
|
||||
g.setColor(new Color(0xDAA520, false));
|
||||
g.fill(CIRCLE_BIG);
|
||||
g.setColor(Color.RED);
|
||||
g.fill(CIRCLE_SMALL);
|
||||
}
|
||||
|
||||
private static void fillPattern(Graphics2D g, HwmfTernaryRasterOp op, BufferedImage pattern, BufferedImage source) {
|
||||
g.setComposite(new HwmfROP3Composite(g.getTransform(), RECT, op, pattern, Color.YELLOW, Color.BLUE));
|
||||
g.setClip(RECT);
|
||||
g.drawImage(source, 0, 0, null);
|
||||
g.setClip(null);
|
||||
g.setComposite(SRC_OVER);
|
||||
}
|
||||
|
||||
private static void fillLabel(Graphics2D g, HwmfTernaryRasterOp op) {
|
||||
g.setColor(Color.WHITE);
|
||||
g.fill(LABEL_BOX);
|
||||
g.setColor(Color.BLACK);
|
||||
|
||||
TextLayout t = new TextLayout(op.name(), g.getFont(), g.getFontRenderContext());
|
||||
Rectangle2D b = t.getBounds();
|
||||
g.drawString(op.name(), (float)((BOX -b.getWidth())/2.), (float)(0.94* BOX));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,72 @@
|
||||
/* ====================================================================
|
||||
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.draw;
|
||||
|
||||
import java.awt.Composite;
|
||||
import java.awt.CompositeContext;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.Raster;
|
||||
import java.awt.image.WritableRaster;
|
||||
|
||||
import org.apache.poi.hwmf.record.HwmfBinaryRasterOp;
|
||||
|
||||
/**
|
||||
* HWMFs Raster Operation for Binary arguments (Source / Destination)
|
||||
*/
|
||||
public class HwmfROP2Composite implements Composite {
|
||||
|
||||
private final HwmfBinaryRasterOp op;
|
||||
|
||||
public HwmfROP2Composite(HwmfBinaryRasterOp op) {
|
||||
this.op = op;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompositeContext createContext(ColorModel srcColorModel, ColorModel dstColorModel, RenderingHints hints) {
|
||||
return new ROP2Context(op);
|
||||
}
|
||||
|
||||
private static class ROP2Context implements CompositeContext {
|
||||
private final HwmfBinaryRasterOp op;
|
||||
|
||||
public ROP2Context(HwmfBinaryRasterOp op) {
|
||||
this.op = op;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(Raster src, Raster dstIn, WritableRaster dstOut) {
|
||||
int w = Math.min(src.getWidth(), dstIn.getWidth());
|
||||
int h = Math.min(src.getHeight(), dstIn.getHeight());
|
||||
|
||||
int[] srcPixels = new int[w];
|
||||
int[] dstPixels = new int[w];
|
||||
|
||||
for (int y = 0; y < h; y++) {
|
||||
src.getDataElements(0, y, w, 1, srcPixels);
|
||||
dstIn.getDataElements(0, y, w, 1, dstPixels);
|
||||
op.process(srcPixels, dstPixels);
|
||||
dstOut.setDataElements(0, y, w, 1, dstPixels);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,125 @@
|
||||
/* ====================================================================
|
||||
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.draw;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Composite;
|
||||
import java.awt.CompositeContext;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.Shape;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.Raster;
|
||||
import java.awt.image.WritableRaster;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
|
||||
import org.apache.poi.hwmf.record.HwmfTernaryRasterOp;
|
||||
|
||||
/**
|
||||
* HWMFs Raster Operation for Ternary arguments (Source / Destination / Pattern)
|
||||
*/
|
||||
public class HwmfROP3Composite implements Composite {
|
||||
private final HwmfTernaryRasterOp rop3;
|
||||
private final byte[] mask;
|
||||
private final int mask_width;
|
||||
private final int mask_height;
|
||||
private final int foreground;
|
||||
private final int background;
|
||||
private final Point2D startPnt;
|
||||
private final boolean hasPattern;
|
||||
|
||||
public HwmfROP3Composite(AffineTransform at, Shape shape, HwmfTernaryRasterOp rop3, BufferedImage bitmap, Color background, Color foreground) {
|
||||
this.rop3 = rop3;
|
||||
if (bitmap == null) {
|
||||
mask_width = 1;
|
||||
mask_height = 1;
|
||||
mask = new byte[]{1};
|
||||
} else {
|
||||
mask_width = bitmap.getWidth();
|
||||
mask_height = bitmap.getHeight();
|
||||
mask = new byte[mask_width * mask_height];
|
||||
bitmap.getRaster().getDataElements(0, 0, mask_width, mask_height, mask);
|
||||
}
|
||||
this.background = background.getRGB();
|
||||
this.foreground = foreground.getRGB();
|
||||
|
||||
Rectangle2D bnds = at.createTransformedShape(shape.getBounds2D()).getBounds2D();
|
||||
startPnt = new Point2D.Double(bnds.getMinX(),bnds.getMinY());
|
||||
hasPattern = rop3.calcCmd().contains("P");
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompositeContext createContext(ColorModel srcColorModel, ColorModel dstColorModel, RenderingHints hints) {
|
||||
return new Rop3Context();
|
||||
}
|
||||
|
||||
private class Rop3Context implements CompositeContext {
|
||||
private final Deque<int[]> stack = new ArrayDeque<>();
|
||||
// private Integer origOffsetX, origOffsetY;
|
||||
|
||||
@Override
|
||||
public void compose(Raster src, Raster dstIn, WritableRaster dstOut) {
|
||||
int w = Math.min(src.getWidth(), dstIn.getWidth());
|
||||
int h = Math.min(src.getHeight(), dstIn.getHeight());
|
||||
|
||||
int startX = (int)startPnt.getX();
|
||||
int startY = (int)startPnt.getY();
|
||||
int offsetY = dstIn.getSampleModelTranslateY();
|
||||
int offsetX = dstIn.getSampleModelTranslateX();
|
||||
|
||||
final int[] srcPixels = new int[w];
|
||||
final int[] dstPixels = new int[w];
|
||||
final int[] patPixels = hasPattern ? new int[w] : null;
|
||||
|
||||
for (int y = 0; y < h; y++) {
|
||||
dstIn.getDataElements(0, y, w, 1, dstPixels);
|
||||
src.getDataElements(0, y, w, 1, srcPixels);
|
||||
|
||||
fillPattern(patPixels, y, startX, startY, offsetX, offsetY);
|
||||
|
||||
rop3.process(stack, dstPixels, srcPixels, patPixels);
|
||||
assert(stack.size() == 1);
|
||||
|
||||
int[] dstOutPixels = stack.pop();
|
||||
|
||||
dstOut.setDataElements(0, y, w, 1, dstOutPixels);
|
||||
}
|
||||
}
|
||||
|
||||
private void fillPattern(int[] patPixels, int y, int startX, int startY, int offsetX, int offsetY) {
|
||||
if (patPixels != null) {
|
||||
int offY2 = (startY+y+offsetY) % mask_height;
|
||||
offY2 = (offY2 < 0) ? mask_height + offY2 : offY2;
|
||||
int maskBase = offY2 * mask_width;
|
||||
for (int i=0; i<patPixels.length; i++) {
|
||||
int offX2 = (startX+i+offsetX) % mask_width;
|
||||
offX2 = (offX2 < 0) ? mask_width + offX2 : offX2;
|
||||
patPixels[i] = mask[maskBase + offX2] == 0 ? background : foreground;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -17,6 +17,9 @@
|
||||
|
||||
package org.apache.poi.hwmf.record;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
/**
|
||||
* The BinaryRasterOperation Enumeration section lists the binary raster-operation codes.
|
||||
* Rasteroperation codes define how metafile processing combines the bits from the selected
|
||||
@ -62,42 +65,44 @@ package org.apache.poi.hwmf.record;
|
||||
*/
|
||||
public enum HwmfBinaryRasterOp {
|
||||
/** 0, Pixel is always 0 */
|
||||
R2_BLACK(0x0001),
|
||||
R2_BLACK(0x0001, HwmfBinaryRasterOp::R2_BLACK),
|
||||
/** DPon, Pixel is the inverse of the R2_MERGEPEN color. */
|
||||
R2_NOTMERGEPEN(0x0002),
|
||||
R2_NOTMERGEPEN(0x0002, HwmfBinaryRasterOp::R2_NOTMERGEPEN),
|
||||
/** DPna, Pixel is a combination of the screen color and the inverse of the pen color. */
|
||||
R2_MASKNOTPEN(0x0003),
|
||||
R2_MASKNOTPEN(0x0003, HwmfBinaryRasterOp::R2_MASKNOTPEN),
|
||||
/** Pn, Pixel is the inverse of the pen color. */
|
||||
R2_NOTCOPYPEN(0x0004),
|
||||
R2_NOTCOPYPEN(0x0004, HwmfBinaryRasterOp::R2_NOTCOPYPEN),
|
||||
/** PDna, Pixel is a combination of the colors common to both the pen and the inverse of the screen. */
|
||||
R2_MASKPENNOT(0x0005),
|
||||
R2_MASKPENNOT(0x0005, HwmfBinaryRasterOp::R2_MASKPENNOT),
|
||||
/** Dn, Pixel is the inverse of the screen color. */
|
||||
R2_NOT(0x0006),
|
||||
R2_NOT(0x0006, HwmfBinaryRasterOp::R2_NOT),
|
||||
/** DPx, Pixel is a combination of the colors in the pen or in the screen, but not in both. */
|
||||
R2_XORPEN(0x0007),
|
||||
R2_XORPEN(0x0007, HwmfBinaryRasterOp::R2_XORPEN),
|
||||
/** DPan, Pixel is the inverse of the R2_MASKPEN color. */
|
||||
R2_NOTMASKPEN(0x0008),
|
||||
R2_NOTMASKPEN(0x0008, HwmfBinaryRasterOp::R2_NOTMASKPEN),
|
||||
/** DPa, Pixel is a combination of the colors common to both the pen and the screen. */
|
||||
R2_MASKPEN(0x0009),
|
||||
R2_MASKPEN(0x0009, HwmfBinaryRasterOp::R2_MASKPEN),
|
||||
/** DPxn, Pixel is the inverse of the R2_XORPEN color. */
|
||||
R2_NOTXORPEN(0x000A),
|
||||
R2_NOTXORPEN(0x000A, HwmfBinaryRasterOp::R2_NOTXORPEN),
|
||||
/** D, Pixel remains unchanged. */
|
||||
R2_NOP(0x000B),
|
||||
R2_NOP(0x000B, HwmfBinaryRasterOp::R2_NOP),
|
||||
/** DPno, Pixel is a combination of the colors common to both the screen and the inverse of the pen. */
|
||||
R2_MERGENOTPEN(0x000C),
|
||||
R2_MERGENOTPEN(0x000C, HwmfBinaryRasterOp::R2_MERGENOTPEN),
|
||||
/** P, Pixel is the pen color. */
|
||||
R2_COPYPEN(0x000D),
|
||||
R2_COPYPEN(0x000D, HwmfBinaryRasterOp::R2_COPYPEN),
|
||||
/** PDno, Pixel is a combination of the pen color and the inverse of the screen color.*/
|
||||
R2_MERGEPENNOT(0x000E),
|
||||
R2_MERGEPENNOT(0x000E, HwmfBinaryRasterOp::R2_MERGEPENNOT),
|
||||
/** DPo, Pixel is a combination of the pen color and the screen color. */
|
||||
R2_MERGEPEN(0x000F),
|
||||
R2_MERGEPEN(0x000F, HwmfBinaryRasterOp::R2_MERGEPEN),
|
||||
/** 1, Pixel is always 1 */
|
||||
R2_WHITE(0x0010);
|
||||
R2_WHITE(0x0010, HwmfBinaryRasterOp::R2_WHITE);
|
||||
|
||||
int opIndex;
|
||||
public int opIndex;
|
||||
private BiConsumer<int[],int[]> op;
|
||||
|
||||
HwmfBinaryRasterOp(int opIndex) {
|
||||
this.opIndex=opIndex;
|
||||
HwmfBinaryRasterOp(int opIndex, BiConsumer<int[],int[]> op) {
|
||||
this.opIndex = opIndex;
|
||||
this.op = op;
|
||||
}
|
||||
|
||||
public static HwmfBinaryRasterOp valueOf(int opIndex) {
|
||||
@ -109,4 +114,111 @@ public enum HwmfBinaryRasterOp {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void process(int[] srcPixels, int[] dstPixels) {
|
||||
op.accept(srcPixels, dstPixels);
|
||||
}
|
||||
|
||||
/** 0, Pixel is always 0 */
|
||||
private static void R2_BLACK(int[] srcPixels, int[] dstPixels) {
|
||||
Arrays.fill(dstPixels, 0xFF000000);
|
||||
}
|
||||
|
||||
/** DPon, Pixel is the inverse of the R2_MERGEPEN color */
|
||||
private static void R2_NOTMERGEPEN(int[] srcPixels, int[] dstPixels) {
|
||||
for (int x = 0; x < srcPixels.length; x++) {
|
||||
dstPixels[x] = (dstPixels[x] & 0xFF000000) | (~(dstPixels[x] | srcPixels[x]) & 0x00FFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
/** DPna, Pixel is a combination of the screen color and the inverse of the pen color. */
|
||||
private static void R2_MASKNOTPEN(int[] srcPixels, int[] dstPixels) {
|
||||
for (int x = 0; x < srcPixels.length; x++) {
|
||||
dstPixels[x] = (dstPixels[x] & 0xFF000000) | ((dstPixels[x] & ~srcPixels[x]) & 0x00FFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
/** Pn, Pixel is the inverse of the pen color. */
|
||||
private static void R2_NOTCOPYPEN(int[] srcPixels, int[] dstPixels) {
|
||||
for (int x = 0; x < srcPixels.length; x++) {
|
||||
dstPixels[x] = (dstPixels[x] & 0xFF000000) | (~srcPixels[x] & 0x00FFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
/** PDna, Pixel is a combination of the colors common to both the pen and the inverse of the screen. */
|
||||
private static void R2_MASKPENNOT(int[] srcPixels, int[] dstPixels) {
|
||||
for (int x = 0; x < srcPixels.length; x++) {
|
||||
dstPixels[x] = (dstPixels[x] & 0xFF000000) | ((srcPixels[x] & ~dstPixels[x]) & 0x00FFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
/** Dn, Pixel is the inverse of the screen color. */
|
||||
private static void R2_NOT(int[] srcPixels, int[] dstPixels) {
|
||||
for (int x = 0; x < srcPixels.length; x++) {
|
||||
dstPixels[x] = (dstPixels[x] & 0xFF000000) | (~dstPixels[x] & 0x00FFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
/** DPx, Pixel is a combination of the colors in the pen or in the screen, but not in both. */
|
||||
private static void R2_XORPEN(int[] srcPixels, int[] dstPixels) {
|
||||
for (int x = 0; x < srcPixels.length; x++) {
|
||||
dstPixels[x] = (dstPixels[x] & 0xFF000000) | ((dstPixels[x] ^ srcPixels[x]) & 0x00FFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
/** DPan, Pixel is the inverse of the R2_MASKPEN color. */
|
||||
private static void R2_NOTMASKPEN(int[] srcPixels, int[] dstPixels) {
|
||||
for (int x = 0; x < srcPixels.length; x++) {
|
||||
dstPixels[x] = (dstPixels[x] & 0xFF000000) | (~(dstPixels[x] & srcPixels[x]) & 0x00FFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
/** DPa, Pixel is a combination of the colors common to both the pen and the screen. */
|
||||
private static void R2_MASKPEN(int[] srcPixels, int[] dstPixels) {
|
||||
for (int x = 0; x < srcPixels.length; x++) {
|
||||
dstPixels[x] = (dstPixels[x] & 0xFF000000) | ((dstPixels[x] & srcPixels[x]) & 0x00FFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
/** DPxn, Pixel is the inverse of the R2_XORPEN color. */
|
||||
private static void R2_NOTXORPEN(int[] srcPixels, int[] dstPixels) {
|
||||
for (int x = 0; x < srcPixels.length; x++) {
|
||||
dstPixels[x] = (dstPixels[x] & 0xFF000000) | (~(dstPixels[x] ^ srcPixels[x]) & 0x00FFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
/** D, Pixel remains unchanged. */
|
||||
private static void R2_NOP(int[] srcPixels, int[] dstPixels) {
|
||||
}
|
||||
|
||||
/** DPno, Pixel is a combination of the colors common to both the screen and the inverse of the pen. */
|
||||
private static void R2_MERGENOTPEN(int[] srcPixels, int[] dstPixels) {
|
||||
for (int x = 0; x < srcPixels.length; x++) {
|
||||
dstPixels[x] = (dstPixels[x] & 0xFF000000) | ((dstPixels[x] | ~srcPixels[x]) & 0x00FFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
/** P, Pixel is the pen color. */
|
||||
private static void R2_COPYPEN(int[] srcPixels, int[] dstPixels) {
|
||||
// TODO: keep targets alpha?
|
||||
System.arraycopy(srcPixels, 0, dstPixels, 0, srcPixels.length);
|
||||
}
|
||||
|
||||
/** PDno, Pixel is a combination of the pen color and the inverse of the screen color. */
|
||||
private static void R2_MERGEPENNOT(int[] srcPixels, int[] dstPixels) {
|
||||
for (int x = 0; x < srcPixels.length; x++) {
|
||||
dstPixels[x] = (dstPixels[x] & 0xFF000000) | ((srcPixels[x] & ~dstPixels[x]) & 0x00FFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
/** DPo, Pixel is a combination of the pen color and the screen color. */
|
||||
private static void R2_MERGEPEN(int[] srcPixels, int[] dstPixels) {
|
||||
for (int x = 0; x < srcPixels.length; x++) {
|
||||
dstPixels[x] = (dstPixels[x] & 0xFF000000) | ((dstPixels[x] | srcPixels[x]) & 0x00FFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
/** 1, Pixel is always 1 */
|
||||
private static void R2_WHITE(int[] srcPixels, int[] dstPixels) {
|
||||
Arrays.fill(dstPixels, 0xFFFFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,7 +66,7 @@ public class HwmfFill {
|
||||
*/
|
||||
byte[] getBMPData();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The ColorUsage Enumeration (a 16-bit unsigned integer) specifies whether a color table
|
||||
* exists in a device-independent bitmap (DIB) and how to interpret its values,
|
||||
@ -100,13 +100,13 @@ public class HwmfFill {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The META_FILLREGION record fills a region using a specified brush.
|
||||
*/
|
||||
public static class WmfFillRegion implements HwmfRecord {
|
||||
|
||||
|
||||
/**
|
||||
* A 16-bit unsigned integer used to index into the WMF Object Table to get
|
||||
* the region to be filled.
|
||||
@ -118,12 +118,12 @@ public class HwmfFill {
|
||||
* brush to use for filling the region.
|
||||
*/
|
||||
protected int brushIndex;
|
||||
|
||||
|
||||
@Override
|
||||
public HwmfRecordType getWmfRecordType() {
|
||||
return HwmfRecordType.fillRegion;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
|
||||
regionIndex = leis.readUShort();
|
||||
@ -135,7 +135,7 @@ public class HwmfFill {
|
||||
public void draw(HwmfGraphics ctx) {
|
||||
ctx.applyObjectTableEntry(regionIndex);
|
||||
ctx.applyObjectTableEntry(brushIndex);
|
||||
|
||||
|
||||
Shape region = ctx.getProperties().getRegion();
|
||||
if (region != null) {
|
||||
ctx.fill(region);
|
||||
@ -164,7 +164,7 @@ public class HwmfFill {
|
||||
* defined in the playback device context.
|
||||
*/
|
||||
public static class WmfPaintRegion implements HwmfRecord {
|
||||
|
||||
|
||||
/**
|
||||
* A 16-bit unsigned integer used to index into the WMF Object Table to get
|
||||
* the region to be painted.
|
||||
@ -174,7 +174,7 @@ public class HwmfFill {
|
||||
public HwmfRecordType getWmfRecordType() {
|
||||
return HwmfRecordType.paintRegion;
|
||||
}
|
||||
|
||||
|
||||
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
|
||||
regionIndex = leis.readUShort();
|
||||
return LittleEndianConsts.SHORT_SIZE;
|
||||
@ -187,7 +187,7 @@ public class HwmfFill {
|
||||
Shape region = ctx.getProperties().getRegion();
|
||||
if (region != null) {
|
||||
ctx.fill(region);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getRegionIndex() {
|
||||
@ -199,14 +199,14 @@ public class HwmfFill {
|
||||
return GenericRecordUtil.getGenericProperties("regionIndex", this::getRegionIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The META_FLOODFILL record fills an area of the output surface with the brush that
|
||||
* is defined in the playback device context.
|
||||
*/
|
||||
public static class WmfFloodFill implements HwmfRecord {
|
||||
|
||||
|
||||
/** A 32-bit ColorRef Object that defines the color value. */
|
||||
protected final HwmfColorRef colorRef = new HwmfColorRef();
|
||||
|
||||
@ -217,7 +217,7 @@ public class HwmfFill {
|
||||
public HwmfRecordType getWmfRecordType() {
|
||||
return HwmfRecordType.floodFill;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
|
||||
int size = colorRef.init(leis);
|
||||
@ -227,7 +227,7 @@ public class HwmfFill {
|
||||
|
||||
@Override
|
||||
public void draw(HwmfGraphics ctx) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
public HwmfColorRef getColorRef() {
|
||||
@ -287,12 +287,12 @@ public class HwmfFill {
|
||||
* This MUST be one of the values: ALTERNATE = 0x0001, WINDING = 0x0002
|
||||
*/
|
||||
protected HwmfPolyfillMode polyFillMode;
|
||||
|
||||
|
||||
@Override
|
||||
public HwmfRecordType getWmfRecordType() {
|
||||
return HwmfRecordType.setPolyFillMode;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
|
||||
polyFillMode = HwmfPolyfillMode.valueOf(leis.readUShort() & 3);
|
||||
@ -341,12 +341,12 @@ public class HwmfFill {
|
||||
}
|
||||
|
||||
protected HwmfFloodFillMode mode;
|
||||
|
||||
|
||||
@Override
|
||||
public HwmfRecordType getWmfRecordType() {
|
||||
return HwmfRecordType.extFloodFill;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
|
||||
// A 16-bit unsigned integer that defines the fill operation to be performed. This
|
||||
@ -357,7 +357,7 @@ public class HwmfFill {
|
||||
|
||||
@Override
|
||||
public void draw(HwmfGraphics ctx) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
public HwmfFloodFillMode getMode() {
|
||||
@ -374,18 +374,18 @@ public class HwmfFill {
|
||||
* The META_INVERTREGION record draws a region in which the colors are inverted.
|
||||
*/
|
||||
public static class WmfInvertRegion implements HwmfRecord {
|
||||
|
||||
|
||||
/**
|
||||
* A 16-bit unsigned integer used to index into the WMF Object Table to get
|
||||
* the region to be inverted.
|
||||
*/
|
||||
private int regionIndex;
|
||||
|
||||
|
||||
@Override
|
||||
public HwmfRecordType getWmfRecordType() {
|
||||
return HwmfRecordType.invertRegion;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
|
||||
regionIndex = leis.readUShort();
|
||||
@ -394,7 +394,7 @@ public class HwmfFill {
|
||||
|
||||
@Override
|
||||
public void draw(HwmfGraphics ctx) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
public int getRegionIndex() {
|
||||
@ -406,7 +406,7 @@ public class HwmfFill {
|
||||
return GenericRecordUtil.getGenericProperties("regionIndex", this::getRegionIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The META_PATBLT record paints a specified rectangle using the brush that is defined in the playback
|
||||
@ -414,20 +414,20 @@ public class HwmfFill {
|
||||
* raster operation.
|
||||
*/
|
||||
public static class WmfPatBlt implements HwmfRecord {
|
||||
|
||||
|
||||
/**
|
||||
* A 32-bit unsigned integer that defines the raster operation code.
|
||||
* This code MUST be one of the values in the Ternary Raster Operation enumeration table.
|
||||
*/
|
||||
private HwmfTernaryRasterOp rasterOperation;
|
||||
|
||||
|
||||
private final Rectangle2D bounds = new Rectangle2D.Double();
|
||||
|
||||
@Override
|
||||
public HwmfRecordType getWmfRecordType() {
|
||||
return HwmfRecordType.patBlt;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
|
||||
rasterOperation = readRasterOperation(leis);
|
||||
@ -436,7 +436,7 @@ public class HwmfFill {
|
||||
|
||||
@Override
|
||||
public void draw(HwmfGraphics ctx) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
public HwmfTernaryRasterOp getRasterOperation() {
|
||||
@ -469,7 +469,7 @@ public class HwmfFill {
|
||||
public static class WmfStretchBlt implements HwmfRecord {
|
||||
/**
|
||||
* A 32-bit unsigned integer that defines how the source pixels, the current brush
|
||||
* in the playback device context, and the destination pixels are to be combined to form the new
|
||||
* in the playback device context, and the destination pixels are to be combined to form the new
|
||||
* image. This code MUST be one of the values in the Ternary Raster Operation Enumeration
|
||||
*/
|
||||
protected HwmfTernaryRasterOp rasterOperation;
|
||||
@ -485,13 +485,13 @@ public class HwmfFill {
|
||||
* This object MUST be specified, even if the raster operation does not require a source.
|
||||
*/
|
||||
protected HwmfBitmap16 target;
|
||||
|
||||
|
||||
@Override
|
||||
public HwmfRecordType getWmfRecordType() {
|
||||
return HwmfRecordType.stretchBlt;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
|
||||
final boolean hasBitmap = hasBitmap(recordSize, recordFunction);
|
||||
@ -513,13 +513,13 @@ public class HwmfFill {
|
||||
target = new HwmfBitmap16();
|
||||
size += target.init(leis);
|
||||
}
|
||||
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(HwmfGraphics ctx) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -582,17 +582,17 @@ public class HwmfFill {
|
||||
protected final Rectangle2D dstBounds = new Rectangle2D.Double();
|
||||
|
||||
/**
|
||||
* A variable-sized DeviceIndependentBitmap Object (section 2.2.2.9) that is the
|
||||
* A variable-sized DeviceIndependentBitmap Object (section 2.2.2.9) that is the
|
||||
* source of the color data.
|
||||
*/
|
||||
protected final HwmfBitmapDib bitmap = new HwmfBitmapDib();
|
||||
|
||||
|
||||
@Override
|
||||
public HwmfRecordType getWmfRecordType() {
|
||||
return HwmfRecordType.stretchDib;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
|
||||
rasterOperation = readRasterOperation(leis);
|
||||
@ -606,7 +606,7 @@ public class HwmfFill {
|
||||
size += bitmap.init(leis, (int)(recordSize-6-size));
|
||||
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(HwmfGraphics ctx) {
|
||||
@ -666,14 +666,14 @@ public class HwmfFill {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class WmfBitBlt extends WmfStretchBlt {
|
||||
|
||||
@Override
|
||||
public HwmfRecordType getWmfRecordType() {
|
||||
return HwmfRecordType.bitBlt;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
|
||||
final boolean hasBitmap = hasBitmap(recordSize/2, recordFunction);
|
||||
@ -698,7 +698,7 @@ public class HwmfFill {
|
||||
}
|
||||
|
||||
srcBounds.setRect(srcPnt.getX(), srcPnt.getY(), dstBounds.getWidth(), dstBounds.getHeight());
|
||||
|
||||
|
||||
return size;
|
||||
}
|
||||
}
|
||||
@ -715,7 +715,7 @@ public class HwmfFill {
|
||||
* A 16-bit unsigned integer that defines whether the Colors field of the
|
||||
* DIB contains explicit RGB values or indexes into a palette.
|
||||
*/
|
||||
private ColorUsage colorUsage;
|
||||
private ColorUsage colorUsage;
|
||||
/**
|
||||
* A 16-bit unsigned integer that defines the number of scan lines in the source.
|
||||
*/
|
||||
@ -723,7 +723,7 @@ public class HwmfFill {
|
||||
/**
|
||||
* A 16-bit unsigned integer that defines the starting scan line in the source.
|
||||
*/
|
||||
private int startScan;
|
||||
private int startScan;
|
||||
|
||||
/** the source rectangle */
|
||||
protected final Rectangle2D srcBounds = new Rectangle2D.Double();
|
||||
@ -734,14 +734,14 @@ public class HwmfFill {
|
||||
/**
|
||||
* A variable-sized DeviceIndependentBitmap Object that is the source of the color data.
|
||||
*/
|
||||
private HwmfBitmapDib dib;
|
||||
|
||||
|
||||
private HwmfBitmapDib dib;
|
||||
|
||||
|
||||
@Override
|
||||
public HwmfRecordType getWmfRecordType() {
|
||||
return HwmfRecordType.setDibToDev;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
|
||||
colorUsage = ColorUsage.valueOf(leis.readUShort());
|
||||
@ -761,16 +761,16 @@ public class HwmfFill {
|
||||
srcBounds.setRect(srcPnt.getX(), srcPnt.getY(), dstBounds.getWidth(), dstBounds.getHeight());
|
||||
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(HwmfGraphics ctx) {
|
||||
ctx.addObjectTableEntry(this);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void applyObject(HwmfGraphics ctx) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -822,7 +822,7 @@ public class HwmfFill {
|
||||
public HwmfRecordType getWmfRecordType() {
|
||||
return HwmfRecordType.dibBitBlt;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
|
||||
final boolean hasBitmap = hasBitmap(recordSize/2, recordFunction);
|
||||
@ -885,7 +885,7 @@ public class HwmfFill {
|
||||
public HwmfRecordType getWmfRecordType() {
|
||||
return HwmfRecordType.dibStretchBlt;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
|
||||
final boolean hasBitmap = hasBitmap(recordSize, recordFunction);
|
||||
@ -905,7 +905,7 @@ public class HwmfFill {
|
||||
target = new HwmfBitmapDib();
|
||||
size += target.init(leis, (int)(recordSize-6-size));
|
||||
}
|
||||
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
@ -983,7 +983,7 @@ public class HwmfFill {
|
||||
int rasterOpIndex = leis.readUShort();
|
||||
|
||||
HwmfTernaryRasterOp rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);
|
||||
assert(rasterOperation != null && rasterOpCode == rasterOperation.opCode);
|
||||
assert(rasterOperation != null && rasterOpCode == rasterOperation.getOpCode());
|
||||
return rasterOperation;
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,6 +17,9 @@
|
||||
|
||||
package org.apache.poi.hwmf.record;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Deque;
|
||||
|
||||
/**
|
||||
* Each ternary raster operation code represents a Boolean operation in which the values of the pixels in
|
||||
* the source, the selected brush, and the destination are combined. Following are the three operands
|
||||
@ -41,17 +44,17 @@ package org.apache.poi.hwmf.record;
|
||||
* All Boolean operations are presented in reverse Polish notation. For example, the following operation
|
||||
* replaces the values of the pixels in the destination bitmap with a combination of the pixel values of the
|
||||
* source and brush: PSo.
|
||||
*
|
||||
*
|
||||
* The following operation combines the values of the pixels in the source and brush with the pixel values
|
||||
* of the destination bitmap: DPSoo (there are alternative spellings of some functions, so although a
|
||||
* particular spelling MAY NOT be listed in the enumeration, an equivalent form SHOULD be).
|
||||
*
|
||||
*
|
||||
* Each raster operation code is a 32-bit integer whose high-order word is a Boolean operation index and
|
||||
* whose low-order word is the operation code. The 16-bit operation index is a zero-extended, 8-bit
|
||||
* value that represents the result of the Boolean operation on predefined brush, source, and destination
|
||||
* values. For example, the operation indexes for the PSo and DPSoo operations are shown in the
|
||||
* following list.
|
||||
*
|
||||
*
|
||||
* <table>
|
||||
* <tr><th>P</th><th>S</th><th>D</th><th>DPo</th><th>DPan</th></tr>
|
||||
* <tr><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td></tr>
|
||||
@ -63,304 +66,338 @@ package org.apache.poi.hwmf.record;
|
||||
* <tr><td>1</td><td>1</td><td>0</td><td>1</td><td>1</td></tr>
|
||||
* <tr><td>1</td><td>1</td><td>1</td><td>1</td><td>1</td></tr>
|
||||
* </table>
|
||||
*
|
||||
*
|
||||
* The operation indexes are determined by reading the binary values in a column of the table from the
|
||||
* bottom up. For example, in the PSo column, the binary value is 11111100, which is equivalent to 00FC
|
||||
* (hexadecimal is implicit for these values), which is the operation index for PSo.
|
||||
*
|
||||
*
|
||||
* Using this method, DPSoo can be seen to have the operation index 00FE. Operation indexes define the
|
||||
* locations of corresponding raster operation codes in the preceding enumeration. The PSo operation is
|
||||
* in line 252 (0x00FC) of the enumeration; DPSoo is in line 254 (0x00FE).
|
||||
*
|
||||
*
|
||||
* The most commonly used raster operations have been given explicit enumeration names, which
|
||||
* SHOULD be used; examples are PATCOPY and WHITENESS.
|
||||
*
|
||||
*
|
||||
* When the source and destination bitmaps are monochrome, a bit value of 0 represents a black pixel
|
||||
* and a bit value of 1 represents a white pixel. When the source and the destination bitmaps are color,
|
||||
* those colors are represented with red green blue (RGB) values.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public enum HwmfTernaryRasterOp {
|
||||
BLACKNESS(0x0000,0x0042,"0"),
|
||||
DPSOON(0x0001,0x0289,"DPSoon"),
|
||||
DPSONA(0x0002,0x0C89,"DPSona"),
|
||||
PSON(0x0003,0x00AA,"PSon"),
|
||||
SDPONA(0x0004,0x0C88,"SDPona"),
|
||||
DPON(0x0005,0x00A9,"DPon"),
|
||||
PDSXNON(0x0006,0x0865,"PDSxnon"),
|
||||
PDSAON(0x0007,0x02C5,"PDSaon"),
|
||||
SDPNAA(0x0008,0x0F08,"SDPnaa"),
|
||||
PDSXON(0x0009,0x0245,"PDSxon"),
|
||||
DPNA(0x000A,0x0329,"DPna"),
|
||||
PSDNAON(0x000B,0x0B2A,"PSDnaon"),
|
||||
SPNA(0x000C,0x0324,"SPna"),
|
||||
PDSNAON(0x000D,0x0B25,"PDSnaon"),
|
||||
PDSONON(0x000E,0x08A5,"PDSonon"),
|
||||
PN(0x000F,0x0001,"Pn"),
|
||||
PDSONA(0x0010,0x0C85,"PDSona"),
|
||||
NOTSRCERASE(0x0011,0x00A6,"DSon"),
|
||||
SDPXNON(0x0012,0x0868,"SDPxnon"),
|
||||
SDPAON(0x0013,0x02C8,"SDPaon"),
|
||||
DPSXNON(0x0014,0x0869,"DPSxnon"),
|
||||
DPSAON(0x0015,0x02C9,"DPSaon"),
|
||||
PSDPSANAXX(0x0016,0x5CCA,"PSDPSanaxx"),
|
||||
SSPXDSXAXN(0x0017,0x1D54,"SSPxDSxaxn"),
|
||||
SPXPDXA(0x0018,0x0D59,"SPxPDxa"),
|
||||
SDPSANAXN(0x0019,0x1CC8,"SDPSanaxn"),
|
||||
PDSPAOX(0x001A,0x06C5,"PDSPaox"),
|
||||
SDPSXAXN(0x001B,0x0768,"SDPSxaxn"),
|
||||
PSDPAOX(0x001C,0x06CA,"PSDPaox"),
|
||||
DSPDXAXN(0x001D,0x0766,"DSPDxaxn"),
|
||||
PDSOX(0x001E,0x01A5,"PDSox"),
|
||||
PDSOAN(0x001F,0x0385,"PDSoan"),
|
||||
DPSNAA(0x0020,0x0F09,"DPSnaa"),
|
||||
SDPXON(0x0021,0x0248,"SDPxon"),
|
||||
DSNA(0x0022,0x0326,"DSna"),
|
||||
SPDNAON(0x0023,0x0B24,"SPDnaon"),
|
||||
SPXDSXA(0x0024,0x0D55,"SPxDSxa"),
|
||||
PDSPANAXN(0x0025,0x1CC5,"PDSPanaxn"),
|
||||
SDPSAOX(0x0026,0x06C8,"SDPSaox"),
|
||||
SDPSXNOX(0x0027,0x1868,"SDPSxnox"),
|
||||
DPSXA(0x0028,0x0369,"DPSxa"),
|
||||
PSDPSAOXXN(0x0029,0x16CA,"PSDPSaoxxn"),
|
||||
DPSANA(0x002A,0x0CC9,"DPSana"),
|
||||
SSPXPDXAXN(0x002B,0x1D58,"SSPxPDxaxn"),
|
||||
SPDSOAX(0x002C,0x0784,"SPDSoax"),
|
||||
PSDNOX(0x002D,0x060A,"PSDnox"),
|
||||
PSDPXOX(0x002E,0x064A,"PSDPxox"),
|
||||
PSDNOAN(0x002F,0x0E2A,"PSDnoan"),
|
||||
PSNA(0x0030,0x032A,"PSna"),
|
||||
SDPNAON(0x0031,0x0B28,"SDPnaon"),
|
||||
SDPSOOX(0x0032,0x0688,"SDPSoox"),
|
||||
NOTSRCCOPY(0x0033,0x0008,"Sn"),
|
||||
SPDSAOX(0x0034,0x06C4,"SPDSaox"),
|
||||
SPDSXNOX(0x0035,0x1864,"SPDSxnox"),
|
||||
SDPOX(0x0036,0x01A8,"SDPox"),
|
||||
SDPOAN(0x0037,0x0388,"SDPoan"),
|
||||
PSDPOAX(0x0038,0x078A,"PSDPoax"),
|
||||
SPDNOX(0x0390,0x604,"SPDnox"),
|
||||
SPDSXOX(0x003A,0x0644,"SPDSxox"),
|
||||
SPDNOAN(0x003B,0x0E24,"SPDnoan"),
|
||||
PSX(0x003C,0x004A,"PSx"),
|
||||
SPDSONOX(0x003D,0x18A4,"SPDSonox"),
|
||||
SPDSNAOX(0x003E,0x1B24,"SPDSnaox"),
|
||||
PSAN(0x003F,0x00EA,"PSan"),
|
||||
PSDNAA(0x0040,0x0F0A,"PSDnaa"),
|
||||
DPSXON(0x0041,0x0249,"DPSxon"),
|
||||
SDXPDXA(0x0042,0x0D5D,"SDxPDxa"),
|
||||
SPDSANAXN(0x0043,0x1CC4,"SPDSanaxn"),
|
||||
SRCERASE(0x0044,0x0328,"SDna"),
|
||||
DPSNAON(0x0045,0x0B29,"DPSnaon"),
|
||||
DSPDAOX(0x0046,0x06C6,"DSPDaox"),
|
||||
PSDPXAXN(0x0047,0x076A,"PSDPxaxn"),
|
||||
SDPXA(0x0048,0x0368,"SDPxa"),
|
||||
PDSPDAOXXN(0x0049,0x16C5,"PDSPDaoxxn"),
|
||||
DPSDOAX(0x004A,0x0789,"DPSDoax"),
|
||||
PDSNOX(0x004B,0x0605,"PDSnox"),
|
||||
SDPANA(0x004C,0x0CC8,"SDPana"),
|
||||
SSPXDSXOXN(0x004D,0x1954,"SSPxDSxoxn"),
|
||||
PDSPXOX(0x004E,0x0645,"PDSPxox"),
|
||||
PDSNOAN(0x004F,0x0E25,"PDSnoan"),
|
||||
PDNA(0x0050,0x0325,"PDna"),
|
||||
DSPNAON(0x0051,0x0B26,"DSPnaon"),
|
||||
DPSDAOX(0x0052,0x06C9,"DPSDaox"),
|
||||
SPDSXAXN(0x0053,0x0764,"SPDSxaxn"),
|
||||
DPSONON(0x0054,0x08A9,"DPSonon"),
|
||||
DSTINVERT(0x0055,0x0009,"Dn"),
|
||||
DPSOX(0x0056,0x01A9,"DPSox"),
|
||||
DPSOAN(0x0005,0x70389,"DPSoan"),
|
||||
PDSPOAX(0x0058,0x0785,"PDSPoax"),
|
||||
DPSNOX(0x0059,0x0609,"DPSnox"),
|
||||
PATINVERT(0x005A,0x0049,"DPx"),
|
||||
DPSDONOX(0x005B,0x18A9,"DPSDonox"),
|
||||
DPSDXOX(0x005C,0x0649,"DPSDxox"),
|
||||
DPSNOAN(0x005D,0x0E29,"DPSnoan"),
|
||||
DPSDNAOX(0x005E,0x1B29,"DPSDnaox"),
|
||||
DPAN(0x005F,0x00E9,"DPan"),
|
||||
PDSXA(0x0060,0x0365,"PDSxa"),
|
||||
DSPDSAOXXN(0x0061,0x16C6,"DSPDSaoxxn"),
|
||||
DSPDOAX(0x0062,0x0786,"DSPDoax"),
|
||||
SDPNOX(0x0063,0x0608,"SDPnox"),
|
||||
SDPSOAX(0x0064,0x0788,"SDPSoax"),
|
||||
DSPNOX(0x0065,0x0606,"DSPnox"),
|
||||
SRCINVERT(0x0066,0x0046,"DSx"),
|
||||
SDPSONOX(0x0067,0x18A8,"SDPSonox"),
|
||||
DSPDSONOXXN(0x0068,0x58A6,"DSPDSonoxxn"),
|
||||
PDSXXN(0x0069,0x0145,"PDSxxn"),
|
||||
DPSAX(0x006A,0x01E9,"DPSax"),
|
||||
PSDPSOAXXN(0x006B,0x178A,"PSDPSoaxxn"),
|
||||
SDPAX(0x006C,0x01E8,"SDPax"),
|
||||
PDSPDOAXXN(0x006D,0x1785,"PDSPDoaxxn"),
|
||||
SDPSNOAX(0x006E,0x1E28,"SDPSnoax"),
|
||||
// PDXNAN(0x006F,0x0C65,"PDXnan"), // invalid combo
|
||||
PDSANA(0x0070,0x0CC5,"PDSana"),
|
||||
SSDXPDXAXN(0x0071,0x1D5C,"SSDxPDxaxn"),
|
||||
SDPSXOX(0x0072,0x0648,"SDPSxox"),
|
||||
SDPNOAN(0x0073,0x0E28,"SDPnoan"),
|
||||
DSPDXOX(0x0074,0x0646,"DSPDxox"),
|
||||
DSPNOAN(0x0075,0x0E26,"DSPnoan"),
|
||||
SDPSNAOX(0x0076,0x1B28,"SDPSnaox"),
|
||||
DSAN(0x0077,0x00E6,"DSan"),
|
||||
PDSAX(0x0078,0x01E5,"PDSax"),
|
||||
DSPDSOAXXN(0x0079,0x1786,"DSPDSoaxxn"),
|
||||
DPSDNOAX(0x007A,0x1E29,"DPSDnoax"),
|
||||
SDPXNAN(0x007B,0x0C68,"SDPxnan"),
|
||||
SPDSNOAX(0x007C,0x1E24,"SPDSnoax"),
|
||||
DPSXNAN(0x007D,0x0C69,"DPSxnan"),
|
||||
SPXDSXO(0x007E,0x0955,"SPxDSxo"),
|
||||
DPSAAN(0x007F,0x03C9,"DPSaan"),
|
||||
DPSAA(0x0080,0x03E9,"DPSaa"),
|
||||
SPXDSXON(0x0081,0x0975,"SPxDSxon"),
|
||||
DPSXNA(0x0082,0x0C49,"DPSxna"),
|
||||
SPDSNOAXN(0x0083,0x1E04,"SPDSnoaxn"),
|
||||
SDPXNA(0x0084,0x0C48,"SDPxna"),
|
||||
PDSPNOAXN(0x0085,0x1E05,"PDSPnoaxn"),
|
||||
DSPDSOAXX(0x0086,0x17A6,"DSPDSoaxx"),
|
||||
PDSAXN(0x0087,0x01C5,"PDSaxn"),
|
||||
SRCAND(0x0088,0x00C6,"DSa"),
|
||||
SDPSNAOXN(0x0089,0x1B08,"SDPSnaoxn"),
|
||||
DSPNOA(0x008A,0x0E06,"DSPnoa"),
|
||||
DSPDXOXN(0x008B,0x0666,"DSPDxoxn"),
|
||||
SDPNOA(0x008C,0x0E08,"SDPnoa"),
|
||||
SDPSXOXN(0x008D,0x0668,"SDPSxoxn"),
|
||||
SSDXPDXAX(0x008E,0x1D7C,"SSDxPDxax"),
|
||||
PDSANAN(0x008F,0x0CE5,"PDSanan"),
|
||||
PDSXNA(0x0090,0x0C45,"PDSxna"),
|
||||
SDPSNOAXN(0x0091,0x1E08,"SDPSnoaxn"),
|
||||
DPSDPOAXX(0x0092,0x17A9,"DPSDPoaxx"),
|
||||
SPDAXN(0x0093,0x01C4,"SPDaxn"),
|
||||
PSDPSOAXX(0x0094,0x17AA,"PSDPSoaxx"),
|
||||
DPSAXN(0x0095,0x01C9,"DPSaxn"),
|
||||
DPSXX(0x0096,0x0169,"DPSxx"),
|
||||
PSDPSONOXX(0x0097,0x588A,"PSDPSonoxx"),
|
||||
SDPSONOXN(0x0098,0x1888,"SDPSonoxn"),
|
||||
DSXN(0x0099,0x0066,"DSxn"),
|
||||
DPSNAX(0x009A,0x0709,"DPSnax"),
|
||||
SDPSOAXN(0x009B,0x07A8,"SDPSoaxn"),
|
||||
SPDNAX(0x009C,0x0704,"SPDnax"),
|
||||
DSPDOAXN(0x009D,0x07A6,"DSPDoaxn"),
|
||||
DSPDSAOXX(0x009E,0x16E6,"DSPDSaoxx"),
|
||||
PDSXAN(0x009F,0x0345,"PDSxan"),
|
||||
DPA(0x00A0,0x00C9,"DPa"),
|
||||
PDSPNAOXN(0x00A1,0x1B05,"PDSPnaoxn"),
|
||||
DPSNOA(0x00A2,0x0E09,"DPSnoa"),
|
||||
DPSDXOXN(0x00A3,0x0669,"DPSDxoxn"),
|
||||
PDSPONOXN(0x00A4,0x1885,"PDSPonoxn"),
|
||||
PDXN(0x00A5,0x0065,"PDxn"),
|
||||
DSPNAX(0x00A6,0x0706,"DSPnax"),
|
||||
PDSPOAXN(0x00A7,0x07A5,"PDSPoaxn"),
|
||||
DPSOA(0x00A8,0x03A9,"DPSoa"),
|
||||
DPSOXN(0x00A9,0x0189,"DPSoxn"),
|
||||
D(0x00AA,0x0029,"D"),
|
||||
DPSONO(0x00AB,0x0889,"DPSono"),
|
||||
SPDSXAX(0x00AC,0x0744,"SPDSxax"),
|
||||
DPSDAOXN(0x00AD,0x06E9,"DPSDaoxn"),
|
||||
DSPNAO(0x00AE,0x0B06,"DSPnao"),
|
||||
DPNO(0x00AF,0x0229,"DPno"),
|
||||
PDSNOA(0x00B0,0x0E05,"PDSnoa"),
|
||||
PDSPXOXN(0x00B1,0x0665,"PDSPxoxn"),
|
||||
SSPXDSXOX(0x00B2,0x1974,"SSPxDSxox"),
|
||||
SDPANAN(0x00B3,0x0CE8,"SDPanan"),
|
||||
PSDNAX(0x00B4,0x070A,"PSDnax"),
|
||||
DPSDOAXN(0x00B5,0x07A9,"DPSDoaxn"),
|
||||
DPSDPAOXX(0x00B6,0x16E9,"DPSDPaoxx"),
|
||||
SDPXAN(0x00B7,0x0348,"SDPxan"),
|
||||
PSDPXAX(0x00B8,0x074A,"PSDPxax"),
|
||||
DSPDAOXN(0x00B9,0x06E6,"DSPDaoxn"),
|
||||
DPSNAO(0x00BA,0x0B09,"DPSnao"),
|
||||
MERGEPAINT(0x00BB,0x0226,"DSno"),
|
||||
SPDSANAX(0x00BC,0x1CE4,"SPDSanax"),
|
||||
SDXPDXAN(0x00BD,0x0D7D,"SDxPDxan"),
|
||||
DPSXO(0x00BE,0x0269,"DPSxo"),
|
||||
DPSANO(0x00BF,0x08C9,"DPSano"),
|
||||
MERGECOPY(0x00C0,0x00CA,"PSa"),
|
||||
SPDSNAOXN(0x00C1,0x1B04,"SPDSnaoxn"),
|
||||
SPDSONOXN(0x00C2,0x1884,"SPDSonoxn"),
|
||||
PSXN(0x00C3,0x006A,"PSxn"),
|
||||
SPDNOA(0x00C4,0x0E04,"SPDnoa"),
|
||||
SPDSXOXN(0x00C5,0x0664,"SPDSxoxn"),
|
||||
SDPNAX(0x00C6,0x0708,"SDPnax"),
|
||||
PSDPOAXN(0x00C7,0x07AA,"PSDPoaxn"),
|
||||
SDPOA(0x00C8,0x03A8,"SDPoa"),
|
||||
SPDOXN(0x00C9,0x0184,"SPDoxn"),
|
||||
DPSDXAX(0x00CA,0x0749,"DPSDxax"),
|
||||
SPDSAOXN(0x00CB,0x06E4,"SPDSaoxn"),
|
||||
SRCCOPY(0x00CC,0x0020,"S"),
|
||||
SDPONO(0x00CD,0x0888,"SDPono"),
|
||||
SDPNAO(0x00CE,0x0B08,"SDPnao"),
|
||||
SPNO(0x00CF,0x0224,"SPno"),
|
||||
PSDNOA(0x00D0,0x0E0A,"PSDnoa"),
|
||||
PSDPXOXN(0x00D1,0x066A,"PSDPxoxn"),
|
||||
PDSNAX(0x00D2,0x0705,"PDSnax"),
|
||||
SPDSOAXN(0x00D3,0x07A4,"SPDSoaxn"),
|
||||
SSPXPDXAX(0x00D4,0x1D78,"SSPxPDxax"),
|
||||
DPSANAN(0x00D5,0x0CE9,"DPSanan"),
|
||||
PSDPSAOXX(0x00D6,0x16EA,"PSDPSaoxx"),
|
||||
DPSXAN(0x00D7,0x0349,"DPSxan"),
|
||||
PDSPXAX(0x00D8,0x0745,"PDSPxax"),
|
||||
SDPSAOXN(0x00D9,0x06E8,"SDPSaoxn"),
|
||||
DPSDANAX(0x00DA,0x1CE9,"DPSDanax"),
|
||||
SPXDSXAN(0x00DB,0x0D75,"SPxDSxan"),
|
||||
SPDNAO(0x00DC,0x0B04,"SPDnao"),
|
||||
SDNO(0x00DD,0x0228,"SDno"),
|
||||
SDPXO(0x00DE,0x0268,"SDPxo"),
|
||||
SDPANO(0x00DF,0x08C8,"SDPano"),
|
||||
PDSOA(0x00E0,0x03A5,"PDSoa"),
|
||||
PDSOXN(0x00E1,0x0185,"PDSoxn"),
|
||||
DSPDXAX(0x00E2,0x0746,"DSPDxax"),
|
||||
PSDPAOXN(0x00E3,0x06EA,"PSDPaoxn"),
|
||||
SDPSXAX(0x00E4,0x0748,"SDPSxax"),
|
||||
PDSPAOXN(0x00E5,0x06E5,"PDSPaoxn"),
|
||||
SDPSANAX(0x00E6,0x1CE8,"SDPSanax"),
|
||||
SPXPDXAN(0x00E7,0x0D79,"SPxPDxan"),
|
||||
SSPXDSXAX(0x00E8,0x1D74,"SSPxDSxax"),
|
||||
DSPDSANAXXN(0x00E9,0x5CE6,"DSPDSanaxxn"),
|
||||
DPSAO(0x00EA,0x02E9,"DPSao"),
|
||||
DPSXNO(0x00EB,0x0849,"DPSxno"),
|
||||
SDPAO(0x00EC,0x02E8,"SDPao"),
|
||||
SDPXNO(0x00ED,0x0848,"SDPxno"),
|
||||
SRCPAINT(0x00EE,0x0086,"DSo"),
|
||||
SDPNOO(0x00EF,0x0A08,"SDPnoo"),
|
||||
PATCOPY(0x00F0,0x0021,"P"),
|
||||
PDSONO(0x00F1,0x0885,"PDSono"),
|
||||
PDSNAO(0x00F2,0x0B05,"PDSnao"),
|
||||
PSNO(0x00F3,0x022A,"PSno"),
|
||||
PSDNAO(0x00F4,0x0B0A,"PSDnao"),
|
||||
PDNO(0x00F5,0x0225,"PDno"),
|
||||
PDSXO(0x00F6,0x0265,"PDSxo"),
|
||||
PDSANO(0x00F7,0x08C5,"PDSano"),
|
||||
PDSAO(0x00F8,0x02E5,"PDSao"),
|
||||
PDSXNO(0x00F9,0x0845,"PDSxno"),
|
||||
DPO(0x00FA,0x0089,"DPo"),
|
||||
PATPAINT(0x00FB,0x0A09,"DPSnoo"),
|
||||
PSO(0x00FC,0x008A,"PSo"),
|
||||
PSDNOO(0x00FD,0x0A0A,"PSDnoo"),
|
||||
DPSOO(0x00FE,0x02A9,"DPSoo"),
|
||||
WHITENESS(0x00FF,0x0062,"1");
|
||||
/** Fills the destination rectangle with black */
|
||||
BLACKNESS(0x00000042),
|
||||
DPSOON(0x00010289),
|
||||
DPSONA(0x00020C89),
|
||||
PSON(0x000300AA),
|
||||
SDPONA(0x00040C88),
|
||||
DPON(0x000500A9),
|
||||
PDSXNON(0x00060865),
|
||||
PDSAON(0x000702C5),
|
||||
SDPNAA(0x00080F08),
|
||||
PDSXON(0x00090245),
|
||||
DPNA(0x000A0329),
|
||||
PSDNAON(0x000B0B2A),
|
||||
SPNA(0x000C0324),
|
||||
PDSNAON(0x000D0B25),
|
||||
PDSONON(0x000E08A5),
|
||||
PN(0x000F0001),
|
||||
PDSONA(0x00100C85),
|
||||
/** Fills the destination area with (not (Dst or Src)) */
|
||||
NOTSRCERASE(0x001100A6),
|
||||
SDPXNON(0x00120868),
|
||||
SDPAON(0x001302C8),
|
||||
DPSXNON(0x00140869),
|
||||
DPSAON(0x001502C9),
|
||||
PSDPSANAXX(0x00165CCA),
|
||||
SSPXDSXAXN(0x00171D54),
|
||||
SPXPDXA(0x00180D59),
|
||||
SDPSANAXN(0x00191CC8),
|
||||
PDSPAOX(0x001A06C5),
|
||||
SDPSXAXN(0x001B0768),
|
||||
PSDPAOX(0x001C06CA),
|
||||
DSPDXAXN(0x001D0766),
|
||||
PDSOX(0x001E01A5),
|
||||
PDSOAN(0x001F0385),
|
||||
DPSNAA(0x00200F09),
|
||||
SDPXON(0x00210248),
|
||||
DSNA(0x00220326),
|
||||
SPDNAON(0x00230B24),
|
||||
SPXDSXA(0x00240D55),
|
||||
PDSPANAXN(0x00251CC5),
|
||||
SDPSAOX(0x002606C8),
|
||||
SDPSXNOX(0x00271868),
|
||||
DPSXA(0x00280369),
|
||||
PSDPSAOXXN(0x002916CA),
|
||||
DPSANA(0x002A0CC9),
|
||||
SSPXPDXAXN(0x002B1D58),
|
||||
SPDSOAX(0x002C0784),
|
||||
PSDNOX(0x002D060A),
|
||||
PSDPXOX(0x002E064A),
|
||||
PSDNOAN(0x002F0E2A),
|
||||
PSNA(0x0030032A),
|
||||
SDPNAON(0x00310B28),
|
||||
SDPSOOX(0x00320688),
|
||||
/** Fills the destination area with (not Src) */
|
||||
NOTSRCCOPY(0x00330008),
|
||||
SPDSAOX(0x003406C4),
|
||||
SPDSXNOX(0x00351864),
|
||||
SDPOX(0x003601A8),
|
||||
SDPOAN(0x00370388),
|
||||
PSDPOAX(0x0038078A),
|
||||
SPDNOX(0x0390604),
|
||||
SPDSXOX(0x003A0644),
|
||||
SPDNOAN(0x003B0E24),
|
||||
PSX(0x003C004A),
|
||||
SPDSONOX(0x003D18A4),
|
||||
SPDSNAOX(0x003E1B24),
|
||||
PSAN(0x003F00EA),
|
||||
PSDNAA(0x00400F0A),
|
||||
DPSXON(0x00410249),
|
||||
SDXPDXA(0x00420D5D),
|
||||
SPDSANAXN(0x00431CC4),
|
||||
/** Fills the destination area with ((not Dst) and Src) */
|
||||
SRCERASE(0x00440328),
|
||||
DPSNAON(0x00450B29),
|
||||
DSPDAOX(0x004606C6),
|
||||
PSDPXAXN(0x0047076A),
|
||||
SDPXA(0x00480368),
|
||||
PDSPDAOXXN(0x004916C5),
|
||||
DPSDOAX(0x004A0789),
|
||||
PDSNOX(0x004B0605),
|
||||
SDPANA(0x004C0CC8),
|
||||
SSPXDSXOXN(0x004D1954),
|
||||
PDSPXOX(0x004E0645),
|
||||
PDSNOAN(0x004F0E25),
|
||||
PDNA(0x00500325),
|
||||
DSPNAON(0x00510B26),
|
||||
DPSDAOX(0x005206C9),
|
||||
SPDSXAXN(0x00530764),
|
||||
DPSONON(0x005408A9),
|
||||
/** Inverts the colors of the destination area */
|
||||
DSTINVERT(0x00550009),
|
||||
DPSOX(0x005601A9),
|
||||
DPSOAN(0x000570389),
|
||||
PDSPOAX(0x00580785),
|
||||
DPSNOX(0x00590609),
|
||||
/** Fills the destination area with (Dst xor Pattern) */
|
||||
PATINVERT(0x005A0049),
|
||||
DPSDONOX(0x005B18A9),
|
||||
DPSDXOX(0x005C0649),
|
||||
DPSNOAN(0x005D0E29),
|
||||
DPSDNAOX(0x005E1B29),
|
||||
DPAN(0x005F00E9),
|
||||
PDSXA(0x00600365),
|
||||
DSPDSAOXXN(0x006116C6),
|
||||
DSPDOAX(0x00620786),
|
||||
SDPNOX(0x00630608),
|
||||
SDPSOAX(0x00640788),
|
||||
DSPNOX(0x00650606),
|
||||
/** Fills the destination area with (Dst xor Src) */
|
||||
SRCINVERT(0x00660046),
|
||||
SDPSONOX(0x006718A8),
|
||||
DSPDSONOXXN(0x006858A6),
|
||||
PDSXXN(0x00690145),
|
||||
DPSAX(0x006A01E9),
|
||||
PSDPSOAXXN(0x006B178A),
|
||||
SDPAX(0x006C01E8),
|
||||
PDSPDOAXXN(0x006D1785),
|
||||
SDPSNOAX(0x006E1E28),
|
||||
PDSXNAN(0x006F0C65),
|
||||
PDSANA(0x00700CC5),
|
||||
SSDXPDXAXN(0x00711D5C),
|
||||
SDPSXOX(0x00720648),
|
||||
SDPNOAN(0x00730E28),
|
||||
DSPDXOX(0x00740646),
|
||||
DSPNOAN(0x00750E26),
|
||||
SDPSNAOX(0x00761B28),
|
||||
DSAN(0x007700E6),
|
||||
PDSAX(0x007801E5),
|
||||
DSPDSOAXXN(0x00791786),
|
||||
DPSDNOAX(0x007A1E29),
|
||||
SDPXNAN(0x007B0C68),
|
||||
SPDSNOAX(0x007C1E24),
|
||||
DPSXNAN(0x007D0C69),
|
||||
SPXDSXO(0x007E0955),
|
||||
DPSAAN(0x007F03C9),
|
||||
DPSAA(0x008003E9),
|
||||
SPXDSXON(0x00810975),
|
||||
DPSXNA(0x00820C49),
|
||||
SPDSNOAXN(0x00831E04),
|
||||
SDPXNA(0x00840C48),
|
||||
PDSPNOAXN(0x00851E05),
|
||||
DSPDSOAXX(0x008617A6),
|
||||
PDSAXN(0x008701C5),
|
||||
/** Fills the destination area with (Dst and Src) */
|
||||
SRCAND(0x008800C6),
|
||||
SDPSNAOXN(0x00891B08),
|
||||
DSPNOA(0x008A0E06),
|
||||
DSPDXOXN(0x008B0666),
|
||||
SDPNOA(0x008C0E08),
|
||||
SDPSXOXN(0x008D0668),
|
||||
SSDXPDXAX(0x008E1D7C),
|
||||
PDSANAN(0x008F0CE5),
|
||||
PDSXNA(0x00900C45),
|
||||
SDPSNOAXN(0x00911E08),
|
||||
DPSDPOAXX(0x009217A9),
|
||||
SPDAXN(0x009301C4),
|
||||
PSDPSOAXX(0x009417AA),
|
||||
DPSAXN(0x009501C9),
|
||||
DPSXX(0x00960169),
|
||||
PSDPSONOXX(0x0097588A),
|
||||
SDPSONOXN(0x00981888),
|
||||
DSXN(0x00990066),
|
||||
DPSNAX(0x009A0709),
|
||||
SDPSOAXN(0x009B07A8),
|
||||
SPDNAX(0x009C0704),
|
||||
DSPDOAXN(0x009D07A6),
|
||||
DSPDSAOXX(0x009E16E6),
|
||||
PDSXAN(0x009F0345),
|
||||
DPA(0x00A000C9),
|
||||
PDSPNAOXN(0x00A11B05),
|
||||
DPSNOA(0x00A20E09),
|
||||
DPSDXOXN(0x00A30669),
|
||||
PDSPONOXN(0x00A41885),
|
||||
PDXN(0x00A50065),
|
||||
DSPNAX(0x00A60706),
|
||||
PDSPOAXN(0x00A707A5),
|
||||
DPSOA(0x00A803A9),
|
||||
DPSOXN(0x00A90189),
|
||||
D(0x00AA0029),
|
||||
DPSONO(0x00AB0889),
|
||||
SPDSXAX(0x00AC0744),
|
||||
DPSDAOXN(0x00AD06E9),
|
||||
DSPNAO(0x00AE0B06),
|
||||
DPNO(0x00AF0229),
|
||||
PDSNOA(0x00B00E05),
|
||||
PDSPXOXN(0x00B10665),
|
||||
SSPXDSXOX(0x00B21974),
|
||||
SDPANAN(0x00B30CE8),
|
||||
PSDNAX(0x00B4070A),
|
||||
DPSDOAXN(0x00B507A9),
|
||||
DPSDPAOXX(0x00B616E9),
|
||||
SDPXAN(0x00B70348),
|
||||
PSDPXAX(0x00B8074A),
|
||||
DSPDAOXN(0x00B906E6),
|
||||
DPSNAO(0x00BA0B09),
|
||||
/** Fills the destination area with (Dst or not Src) */
|
||||
MERGEPAINT(0x00BB0226),
|
||||
SPDSANAX(0x00BC1CE4),
|
||||
SDXPDXAN(0x00BD0D7D),
|
||||
DPSXO(0x00BE0269),
|
||||
DPSANO(0x00BF08C9),
|
||||
/** Fills the destination area with (Src and Pattern) */
|
||||
MERGECOPY(0x00C000CA),
|
||||
SPDSNAOXN(0x00C11B04),
|
||||
SPDSONOXN(0x00C21884),
|
||||
PSXN(0x00C3006A),
|
||||
SPDNOA(0x00C40E04),
|
||||
SPDSXOXN(0x00C50664),
|
||||
SDPNAX(0x00C60708),
|
||||
PSDPOAXN(0x00C707AA),
|
||||
SDPOA(0x00C803A8),
|
||||
SPDOXN(0x00C90184),
|
||||
DPSDXAX(0x00CA0749),
|
||||
SPDSAOXN(0x00CB06E4),
|
||||
/** Fills the destination area with Src */
|
||||
SRCCOPY(0x00CC0020),
|
||||
SDPONO(0x00CD0888),
|
||||
SDPNAO(0x00CE0B08),
|
||||
SPNO(0x00CF0224),
|
||||
PSDNOA(0x00D00E0A),
|
||||
PSDPXOXN(0x00D1066A),
|
||||
PDSNAX(0x00D20705),
|
||||
SPDSOAXN(0x00D307A4),
|
||||
SSPXPDXAX(0x00D41D78),
|
||||
DPSANAN(0x00D50CE9),
|
||||
PSDPSAOXX(0x00D616EA),
|
||||
DPSXAN(0x00D70349),
|
||||
PDSPXAX(0x00D80745),
|
||||
SDPSAOXN(0x00D906E8),
|
||||
DPSDANAX(0x00DA1CE9),
|
||||
SPXDSXAN(0x00DB0D75),
|
||||
SPDNAO(0x00DC0B04),
|
||||
SDNO(0x00DD0228),
|
||||
SDPXO(0x00DE0268),
|
||||
SDPANO(0x00DF08C8),
|
||||
PDSOA(0x00E003A5),
|
||||
PDSOXN(0x00E10185),
|
||||
DSPDXAX(0x00E20746),
|
||||
PSDPAOXN(0x00E306EA),
|
||||
SDPSXAX(0x00E40748),
|
||||
PDSPAOXN(0x00E506E5),
|
||||
SDPSANAX(0x00E61CE8),
|
||||
SPXPDXAN(0x00E70D79),
|
||||
SSPXDSXAX(0x00E81D74),
|
||||
DSPDSANAXXN(0x00E95CE6),
|
||||
DPSAO(0x00EA02E9),
|
||||
DPSXNO(0x00EB0849),
|
||||
SDPAO(0x00EC02E8),
|
||||
SDPXNO(0x00ED0848),
|
||||
/** Combines the colors of the source and the destination using the operator OR on each pixel */
|
||||
SRCPAINT(0x00EE0086),
|
||||
SDPNOO(0x00EF0A08),
|
||||
/** Fills the destination area with (Pattern) */
|
||||
PATCOPY(0x00F00021),
|
||||
PDSONO(0x00F10885),
|
||||
PDSNAO(0x00F20B05),
|
||||
PSNO(0x00F3022A),
|
||||
PSDNAO(0x00F40B0A),
|
||||
PDNO(0x00F50225),
|
||||
PDSXO(0x00F60265),
|
||||
PDSANO(0x00F708C5),
|
||||
PDSAO(0x00F802E5),
|
||||
PDSXNO(0x00F90845),
|
||||
DPO(0x00FA0089),
|
||||
/** Fills the destination area with (Dst or (not Src) or Pattern) */
|
||||
PATPAINT(0x00FB0A09),
|
||||
PSO(0x00FC008A),
|
||||
PSDNOO(0x00FD0A0A),
|
||||
DPSOO(0x00FE02A9),
|
||||
/** Fills the destination rectangle with white */
|
||||
WHITENESS(0x00FF0062);
|
||||
|
||||
int opIndex;
|
||||
int opCode;
|
||||
String opCmd;
|
||||
|
||||
HwmfTernaryRasterOp(int opIndex, int opCode, String opCmd) {
|
||||
this.opIndex=opIndex;
|
||||
this.opCode=opCode;
|
||||
this.opCmd=opCmd;
|
||||
private static final String[] ARG_ORDER = {
|
||||
"SSSSSS","PPPPPP","DDDDDD",null,
|
||||
"SPDSPD","PDSPDS","DSPDSP",null,
|
||||
"SDPSDP","DPSDPS","PSDPSD",null,
|
||||
null, null, null, null,
|
||||
null, null, null, null,
|
||||
"SSP.DS", "SP.DS", null, null,
|
||||
"SSP.PD", "SP.PD", null, null,
|
||||
"SSD.PD", "SD.PD", null, null
|
||||
};
|
||||
|
||||
private static final String OPS = "nxoa";
|
||||
|
||||
public int opValue;
|
||||
|
||||
HwmfTernaryRasterOp(int opValue) {
|
||||
this.opValue=opValue;
|
||||
}
|
||||
|
||||
public static HwmfTernaryRasterOp valueOf(int opIndex) {
|
||||
for (HwmfTernaryRasterOp bb : HwmfTernaryRasterOp.values()) {
|
||||
if (bb.opIndex == opIndex) {
|
||||
if (bb.getOpIndex() == opIndex) {
|
||||
return bb;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getOpIndex() {
|
||||
return opValue >>> 16;
|
||||
}
|
||||
|
||||
public int getOpCode() {
|
||||
return opValue & 0xFF;
|
||||
}
|
||||
|
||||
public String describeCmd() {
|
||||
String[] stack = new String[10];
|
||||
int stackPnt = 0;
|
||||
|
||||
for (char c : opCmd.toCharArray()) {
|
||||
for (char c : calcCmd().toCharArray()) {
|
||||
switch (c) {
|
||||
case 'S':
|
||||
case 'D':
|
||||
@ -395,4 +432,133 @@ public enum HwmfTernaryRasterOp {
|
||||
|
||||
return stack[--stackPnt];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String calcCmd() {
|
||||
// taken from https://wiki.winehq.org/Ternary_Raster_Ops
|
||||
|
||||
// bit 0-4: Specify the order of arguments to the raster operation
|
||||
String argOrder = ARG_ORDER[this.opValue & 0x001F];
|
||||
assert(argOrder != null);
|
||||
|
||||
// The boolean operators, 1st (6-7 bit), 2nd (8-9 bit), 3rd (a-b bit), 4th (c-d bit), 5th (e-f bit)
|
||||
int nbrOfOps = 0;
|
||||
int[] opArr = new int[5];
|
||||
for (int i=0, bit=6; i<opArr.length; i++, bit+=2) {
|
||||
if ((opArr[i] = (this.opValue >>> bit) & 0x03) != 0) {
|
||||
nbrOfOps = i+1;
|
||||
}
|
||||
}
|
||||
|
||||
StringBuilder sbArg = new StringBuilder(), sbOp = new StringBuilder();
|
||||
sbArg.append(argOrder.charAt(0));
|
||||
for (int opIdx=0,argIdx=1; opIdx < nbrOfOps; opIdx++) {
|
||||
char opCh = OPS.charAt(opArr[opIdx]);
|
||||
char ch = argOrder.charAt(argIdx);
|
||||
sbOp.append(opCh);
|
||||
if (ch == '.') {
|
||||
sbArg.insert(argIdx, sbOp.charAt(0));
|
||||
sbOp.deleteCharAt(0);
|
||||
}
|
||||
if (opCh == 'n') {
|
||||
continue;
|
||||
}
|
||||
sbArg.append(ch == '.' ? argOrder.charAt(++argIdx) : ch);
|
||||
argIdx++;
|
||||
}
|
||||
sbArg.append(sbOp);
|
||||
|
||||
// bit 5: Used to apply the NOT operator to the results of the other operations
|
||||
// if 0, there are a ODD number of operations, even number otherwise
|
||||
if ((nbrOfOps % 2) == ((this.opValue >>> 0x05) & 1)) {
|
||||
sbArg.append('n');
|
||||
}
|
||||
|
||||
String ret = sbArg.toString();
|
||||
return ret.startsWith("DDx") ? "DDx".equals(ret) ? "0" : "1" : ret;
|
||||
}
|
||||
|
||||
public void process(Deque<int[]> stack, int[] dst, int[] src, int[] pat) {
|
||||
for (char op : calcCmd().toCharArray()) {
|
||||
switch (op) {
|
||||
case 'S': opS(stack, dst, src, pat); break;
|
||||
case 'P': opP(stack, dst, src, pat); break;
|
||||
case 'D': opD(stack, dst, src, pat); break;
|
||||
case 'n': opN(stack, dst, src, pat); break;
|
||||
case 'a': opA(stack, dst, src, pat); break;
|
||||
case 'o': opO(stack, dst, src, pat); break;
|
||||
case 'x': opX(stack, dst, src, pat); break;
|
||||
case '1': op1(stack, dst, src, pat); break;
|
||||
case '0': op0(stack, dst, src, pat); break;
|
||||
default: throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void opS(Deque<int[]> stack, int[] dst, int[] src, int[] pat) {
|
||||
stack.push(src);
|
||||
}
|
||||
|
||||
private static void opP(Deque<int[]> stack, int[] dst, int[] src, int[] pat) {
|
||||
stack.push(pat);
|
||||
}
|
||||
|
||||
private static void opD(Deque<int[]> stack, int[] dst, int[] src, int[] pat) {
|
||||
stack.push(dst);
|
||||
}
|
||||
|
||||
private static void opN(Deque<int[]> stack, int[] dst, int[] src, int[] pat) {
|
||||
int[] oper = checkClone(stack.pop(), dst, src, pat, true);
|
||||
for (int i=0; i<oper.length; i++) {
|
||||
oper[i] = (oper[i]&0xFF000000) | (~oper[i] & 0x00FFFFFF);
|
||||
}
|
||||
stack.push(oper);
|
||||
}
|
||||
|
||||
private static void opA(Deque<int[]> stack, int[] dst, int[] src, int[] pat) {
|
||||
int[] oper1 = checkClone(stack.pop(), dst, src, pat, true);
|
||||
int[] oper2 = checkClone(stack.pop(), dst, src, pat, false);
|
||||
for (int i=0; i<oper1.length; i++) {
|
||||
oper1[i] = (oper1[i]&0xFF000000) | ((oper1[i] & oper2[i]) & 0x00FFFFFF);
|
||||
}
|
||||
stack.push(oper1);
|
||||
}
|
||||
|
||||
private static void opO(Deque<int[]> stack, int[] dst, int[] src, int[] pat) {
|
||||
int[] oper1 = checkClone(stack.pop(), dst, src, pat, true);
|
||||
int[] oper2 = checkClone(stack.pop(), dst, src, pat, false);
|
||||
for (int i=0; i<oper1.length; i++) {
|
||||
oper1[i] = (oper1[i]&0xFF000000) | ((oper1[i] | oper2[i]) & 0x00FFFFFF);
|
||||
}
|
||||
stack.push(oper1);
|
||||
}
|
||||
|
||||
private static void opX(Deque<int[]> stack, int[] dst, int[] src, int[] pat) {
|
||||
int[] oper1 = checkClone(stack.pop(), dst, src, pat, true);
|
||||
int[] oper2 = checkClone(stack.pop(), dst, src, pat, false);
|
||||
for (int i=0; i<oper1.length; i++) {
|
||||
oper1[i] = (oper1[i]&0xFF000000) | ((oper1[i] ^ oper2[i]) & 0x00FFFFFF);
|
||||
}
|
||||
stack.push(oper1);
|
||||
}
|
||||
|
||||
private static void op1(Deque<int[]> stack, int[] dst, int[] src, int[] pat) {
|
||||
int[] oper = new int[dst.length];
|
||||
Arrays.fill(oper, 0xFFFFFFFF);
|
||||
stack.push(oper);
|
||||
}
|
||||
|
||||
private static void op0(Deque<int[]> stack, int[] dst, int[] src, int[] pat) {
|
||||
int[] oper = new int[dst.length];
|
||||
Arrays.fill(oper, 0xFF000000);
|
||||
stack.push(oper);
|
||||
}
|
||||
|
||||
private static int[] checkClone(int[] oper, int[] dst, int[] src, int[] pat, boolean force) {
|
||||
if (force && (oper == src || oper == pat || oper == dst)) {
|
||||
return oper.clone();
|
||||
} else {
|
||||
return oper;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
/* ====================================================================
|
||||
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;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.apache.poi.hwmf.record.HwmfTernaryRasterOp;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestRasterOp {
|
||||
@Test
|
||||
public void checkTertiaryCalcCmd() {
|
||||
for (HwmfTernaryRasterOp op : HwmfTernaryRasterOp.values()) {
|
||||
String cmd = op.calcCmd();
|
||||
if (HwmfTernaryRasterOp.SSPXDSXOXN == op) {
|
||||
assertEquals("SSPxDSxoxn", cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user