| /* ==================================================================== |
| 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() { |
| } |
| } |
| } |