/** use FS45 images*/
private boolean fs45;
+ private boolean maskEnabled;
/** the current page */
private transient AFPPagePaintingState pagePaintingState;
}
+ public boolean isMaskEnabled() {
+ return maskEnabled;
+ }
+
+ public void setMaskEnabled(boolean maskEnabled) {
+ this.maskEnabled = maskEnabled;
+ }
/** {@inheritDoc} */
@Override
0x00 // reserved
};
final int lengthOffset = 2;
- if (ideSize == 24) {
+ if (ideSize <= 8) {
+ dataHeader[4] = (byte) 0x01;
+ writeChunksToStream(data, dataHeader, lengthOffset, MAX_DATA_LEN, os);
+ } else if (ideSize == 24) {
byte[] red = new byte[data.length / 3];
byte[] green = new byte[data.length / 3];
byte[] blue = new byte[data.length / 3];
ImageDataDescriptor imageDataDescriptor
= factory.createImageDataDescriptor(dataWidth, dataHeight, dataWidthRes, dataHeightRes);
- if (MimeConstants.MIME_AFP_IOCA_FS45.equals(imageObjectInfo.getMimeType())) {
- imageDataDescriptor.setFunctionSet(ImageDataDescriptor.FUNCTION_SET_FS45);
- if (imageObjectInfo.getBitsPerPixel() == 32) {
+ boolean hasTransparencyMask = imageObjectInfo.getTransparencyMask() != null;
+ boolean fs45 = MimeConstants.MIME_AFP_IOCA_FS45.equals(imageObjectInfo.getMimeType());
+ if (hasTransparencyMask || fs45) {
+ if (fs45) {
+ imageDataDescriptor.setFunctionSet(ImageDataDescriptor.FUNCTION_SET_FS45);
+ }
+ if (hasTransparencyMask || imageObjectInfo.getBitsPerPixel() == 32) {
Tile tile = factory.createTile();
TilePosition tilePosition = factory.createTilePosition();
TileSize tileSize = factory.createTileSize(dataWidth, dataHeight, dataWidthRes, dataHeightRes);
paintingState.setFS45(fs45);
}
+ public void setMaskEnabled(boolean maskEnabled) {
+ paintingState.setMaskEnabled(maskEnabled);
+ }
+
/** {@inheritDoc} */
public boolean getWrapPSeg() {
return paintingState.getWrapPSeg();
package org.apache.fop.render.afp;
+import java.awt.Color;
import java.awt.Dimension;
import java.awt.Rectangle;
+import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
boolean included = afpContext.getResourceManager().tryIncludeObject(imageObjectInfo);
if (!included) {
long start = System.currentTimeMillis();
+ RenderedImage ri = imageRend.getRenderedImage();
+ if (ri.getColorModel().hasAlpha()) {
+ byte[] maskImage = buildMaskImage((BufferedImage) ri, afpContext.getPaintingState());
+ imageObjectInfo.setTransparencyMask(maskImage);
+ }
+
//encode only if the same image has not been encoded, yet
encoder.encodeImage(imageObjectInfo, paintingState);
if (log.isDebugEnabled()) {
}
}
+ private byte[] buildMaskImage(BufferedImage image, AFPPaintingState paintingState) {
+ if (!paintingState.isMaskEnabled()) {
+ return null;
+ }
+ BufferedImage mask = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB);
+ int white = Color.WHITE.getRGB();
+ boolean noalpha = true;
+ for (int i = 0; i < image.getWidth(); i++) {
+ for (int j = 0; j < image.getHeight(); j++) {
+ int alpha = (image.getRGB(i, j) >> 24) & 0xff;
+ if (alpha != 0) {
+ mask.setRGB(i, j, white);
+ } else {
+ noalpha = false;
+ }
+ }
+ }
+ if (noalpha) {
+ return null;
+ }
+ RenderedImage renderedImage =
+ BitmapImageUtil.convertToMonochrome(mask, new Dimension(mask.getWidth(), mask.getHeight()), 1);
+ DataBufferByte bufferByte = (DataBufferByte) renderedImage.getData().getDataBuffer();
+ return bufferByte.getData();
+ }
+
/** {@inheritDoc} */
public boolean isCompatible(RenderingContext targetContext, Image image) {
return (image == null || image instanceof ImageRendered)
import static org.apache.fop.render.afp.AFPRendererOption.IMAGES_FS45;
import static org.apache.fop.render.afp.AFPRendererOption.IMAGES_JPEG;
import static org.apache.fop.render.afp.AFPRendererOption.IMAGES_MAPPING_OPTION;
+import static org.apache.fop.render.afp.AFPRendererOption.IMAGES_MASK_ENABLED;
import static org.apache.fop.render.afp.AFPRendererOption.IMAGES_MODE;
import static org.apache.fop.render.afp.AFPRendererOption.IMAGES_NATIVE;
import static org.apache.fop.render.afp.AFPRendererOption.IMAGES_WRAP_PSEG;
return getParam(IMAGES_FS45, Boolean.class);
}
+ public Boolean isMaskEnabled() {
+ return getParam(IMAGES_MASK_ENABLED, Boolean.class);
+ }
+
public Boolean allowJpegEmbedding() {
return getParam(JPEG_ALLOW_JPEG_EMBEDDING, Boolean.class);
}
setParam(IMAGES_WRAP_PSEG,
imagesCfg.getAttributeAsBoolean(IMAGES_WRAP_PSEG.getName(), false));
setParam(IMAGES_FS45, imagesCfg.getAttributeAsBoolean(IMAGES_FS45.getName(), false));
+ setParam(IMAGES_MASK_ENABLED, imagesCfg.getAttributeAsBoolean(IMAGES_MASK_ENABLED.getName(), false));
if ("scale-to-fit".equals(imagesCfg.getAttribute(IMAGES_MAPPING_OPTION.getName(), null))) {
setParam(IMAGES_MAPPING_OPTION, MappingOptionTriplet.SCALE_TO_FILL);
} else {
if (config.isFs45() != null) {
documentHandler.setFS45(config.isFs45());
}
+ if (config.isMaskEnabled() != null) {
+ documentHandler.setMaskEnabled(config.isMaskEnabled());
+ }
if (config.allowJpegEmbedding() != null) {
documentHandler.canEmbedJpeg(config.allowJpegEmbedding());
}
IMAGES_JPEG("jpeg", null),
IMAGES_DITHERING_QUALITY("dithering-quality", Float.class),
IMAGES_FS45("fs45", Boolean.class),
+ IMAGES_MASK_ENABLED("mask-enabled", Boolean.class),
IMAGES_MAPPING_OPTION("mapping_option", Byte.class),
IMAGES_MODE("mode", Boolean.class),
IMAGES_NATIVE("native", Boolean.class),
import java.awt.BasicStroke;
import java.awt.Rectangle;
+import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
+import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.io.File;
import java.io.IOException;
+import javax.imageio.ImageIO;
+
import org.junit.Assert;
import org.junit.Test;
import org.apache.xmlgraphics.java2d.GraphicContext;
import org.apache.fop.afp.modca.GraphicsObject;
+import org.apache.fop.afp.modca.ObjectAreaDescriptor;
+import org.apache.fop.afp.parser.MODCAParser;
+import org.apache.fop.afp.parser.UnparsedStructuredField;
+import org.apache.fop.apps.FOUserAgent;
+import org.apache.fop.apps.FopFactory;
import org.apache.fop.fonts.FontInfo;
public class AFPGraphics2DTestCase {
verify(gObject).setLineWidth(correctedLineWidth);
}
+ @Test
+ public void testDrawImageMask() throws IOException {
+ BufferedImage image = ImageIO.read(new File("test/resources/images/fop-logo-color-palette-8bit.png"));
+ byte[] data = getAFPField("Data Image", image, true);
+ ByteArrayInputStream bis = new ByteArrayInputStream(data);
+ bis.skip(56);
+ Assert.assertEquals(bis.read(), 0x8E); //start mask
+ bis.skip(20);
+ byte[] firstchunk = new byte[5272];
+ bis.read(firstchunk);
+ int maskbytes = 0;
+ for (byte b : firstchunk) {
+ if (b != 0) {
+ maskbytes++;
+ }
+ }
+ Assert.assertEquals(maskbytes, 333);
+ bis.skip(38117 - 57 - 20 - firstchunk.length);
+ Assert.assertEquals(bis.read(), 0x8F); //end mask
+ Assert.assertEquals(bis.available(), 302498);
+ }
+
+ private byte[] getAFPField(String field, BufferedImage image, boolean maskEnabled) throws IOException {
+ FOUserAgent foUserAgent = FopFactory.newInstance(new File(".").toURI()).newFOUserAgent();
+ AFPResourceManager afpResourceManager = new AFPResourceManager(foUserAgent.getResourceResolver());
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ DataStream dataStream = afpResourceManager.createDataStream(null, byteArrayOutputStream);
+ dataStream.startDocument();
+ dataStream.startPage(1, 1, 0, 1, 1);
+ AFPPaintingState paintingState = new AFPPaintingState();
+ paintingState.setMaskEnabled(maskEnabled);
+ graphics2D = new AFPGraphics2D(false, paintingState, afpResourceManager, resourceInfo, fontInfo);
+ graphics2D.setGraphicContext(new GraphicContext());
+ GraphicsObject graphicsObject = new GraphicsObject(new Factory(), null);
+ graphics2D.setGraphicsObject(graphicsObject);
+ graphicsObject.getObjectEnvironmentGroup().setObjectAreaDescriptor(new ObjectAreaDescriptor(1, 1, 1, 1));
+ graphics2D.drawRenderedImage(image, AffineTransform.getTranslateInstance(1000, 1000));
+ dataStream.endPage();
+ dataStream.endDocument();
+ afpResourceManager.writeToStream();
+ MODCAParser parser = new MODCAParser(new ByteArrayInputStream(byteArrayOutputStream.toByteArray()));
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ UnparsedStructuredField structuredField;
+ while ((structuredField = parser.readNextStructuredField()) != null) {
+ if (structuredField.toString().contains(field)) {
+ bos.write(structuredField.getData());
+ }
+ }
+ return bos.toByteArray();
+ }
+
@Test
public void testDrawGraphicsFillet() throws IOException {
GraphicContext gc = new GraphicContext();
import static org.apache.fop.render.afp.AFPRendererOption.IMAGES_FS45;
import static org.apache.fop.render.afp.AFPRendererOption.IMAGES_JPEG;
import static org.apache.fop.render.afp.AFPRendererOption.IMAGES_MAPPING_OPTION;
+import static org.apache.fop.render.afp.AFPRendererOption.IMAGES_MASK_ENABLED;
import static org.apache.fop.render.afp.AFPRendererOption.IMAGES_MODE;
import static org.apache.fop.render.afp.AFPRendererOption.IMAGES_NATIVE;
import static org.apache.fop.render.afp.AFPRendererOption.IMAGES_WRAP_PSEG;
return setAttribute(IMAGES_FS45, value);
}
+ public ImagesBuilder setMaskEnabled(boolean value) {
+ return setAttribute(IMAGES_MASK_ENABLED, value);
+ }
+
public ImagesBuilder setMappingOption(String value) {
return setAttribute(IMAGES_MAPPING_OPTION, value);
}
assertEquals(true, conf.isFs45());
}
+ @Test
+ public void testMaskEnabled() throws Exception {
+ parseConfig();
+ assertEquals(false, conf.isMaskEnabled());
+ parseConfig(createRenderer().startImages().setMaskEnabled(true).endImages());
+ assertEquals(true, conf.isMaskEnabled());
+ }
+
@Test
public void tesPseg() throws Exception {
parseConfig();