#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:
Andreas Beeker 2020-11-27 22:41:06 +00:00
parent c6b408b232
commit 3f83c76321
8 changed files with 1132 additions and 348 deletions

View 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"));
}
}

View 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));
}
}

View File

@ -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() {
}
}
}

View File

@ -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() {
}
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}
}

View File

@ -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);
}
}
}
}