diff options
author | Simon Steiner <ssteiner@apache.org> | 2024-07-24 13:08:11 +0100 |
---|---|---|
committer | Simon Steiner <ssteiner@apache.org> | 2024-07-24 13:08:11 +0100 |
commit | 1ce1125e8560afa59b629ba1e9217ceac13f2792 (patch) | |
tree | 1612af6f1b4fd0c211af9a83ac2e2f414bec22fe /fop-core/src/main | |
parent | f9404c6f4a07e15a45f00db456f55259844a960c (diff) | |
download | xmlgraphics-fop-1ce1125e8560afa59b629ba1e9217ceac13f2792.tar.gz xmlgraphics-fop-1ce1125e8560afa59b629ba1e9217ceac13f2792.zip |
FOP-3194: Add image mask option for AFP
Diffstat (limited to 'fop-core/src/main')
8 files changed, 67 insertions, 4 deletions
diff --git a/fop-core/src/main/java/org/apache/fop/afp/AFPPaintingState.java b/fop-core/src/main/java/org/apache/fop/afp/AFPPaintingState.java index 3b1354d91..017fc076d 100644 --- a/fop-core/src/main/java/org/apache/fop/afp/AFPPaintingState.java +++ b/fop-core/src/main/java/org/apache/fop/afp/AFPPaintingState.java @@ -99,6 +99,7 @@ public class AFPPaintingState extends org.apache.fop.util.AbstractPaintingState /** use FS45 images*/ private boolean fs45; + private boolean maskEnabled; /** the current page */ private transient AFPPagePaintingState pagePaintingState; @@ -443,6 +444,13 @@ public class AFPPaintingState extends org.apache.fop.util.AbstractPaintingState } + public boolean isMaskEnabled() { + return maskEnabled; + } + + public void setMaskEnabled(boolean maskEnabled) { + this.maskEnabled = maskEnabled; + } /** {@inheritDoc} */ @Override diff --git a/fop-core/src/main/java/org/apache/fop/afp/ioca/Tile.java b/fop-core/src/main/java/org/apache/fop/afp/ioca/Tile.java index 617a962ba..6bab81121 100644 --- a/fop-core/src/main/java/org/apache/fop/afp/ioca/Tile.java +++ b/fop-core/src/main/java/org/apache/fop/afp/ioca/Tile.java @@ -69,7 +69,10 @@ public class Tile extends AbstractStructuredObject { 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]; diff --git a/fop-core/src/main/java/org/apache/fop/afp/modca/ImageObject.java b/fop-core/src/main/java/org/apache/fop/afp/modca/ImageObject.java index 0697e427c..1239b1223 100644 --- a/fop-core/src/main/java/org/apache/fop/afp/modca/ImageObject.java +++ b/fop-core/src/main/java/org/apache/fop/afp/modca/ImageObject.java @@ -79,9 +79,13 @@ public class ImageObject extends AbstractDataObject { 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); diff --git a/fop-core/src/main/java/org/apache/fop/render/afp/AFPDocumentHandler.java b/fop-core/src/main/java/org/apache/fop/render/afp/AFPDocumentHandler.java index a711282d2..2a2b8803b 100644 --- a/fop-core/src/main/java/org/apache/fop/render/afp/AFPDocumentHandler.java +++ b/fop-core/src/main/java/org/apache/fop/render/afp/AFPDocumentHandler.java @@ -545,6 +545,10 @@ public class AFPDocumentHandler extends AbstractBinaryWritingIFDocumentHandler paintingState.setFS45(fs45); } + public void setMaskEnabled(boolean maskEnabled) { + paintingState.setMaskEnabled(maskEnabled); + } + /** {@inheritDoc} */ public boolean getWrapPSeg() { return paintingState.getWrapPSeg(); diff --git a/fop-core/src/main/java/org/apache/fop/render/afp/AFPImageHandlerRenderedImage.java b/fop-core/src/main/java/org/apache/fop/render/afp/AFPImageHandlerRenderedImage.java index 57a5143f6..25bfd635e 100644 --- a/fop-core/src/main/java/org/apache/fop/render/afp/AFPImageHandlerRenderedImage.java +++ b/fop-core/src/main/java/org/apache/fop/render/afp/AFPImageHandlerRenderedImage.java @@ -19,8 +19,10 @@ 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; @@ -131,6 +133,12 @@ public class AFPImageHandlerRenderedImage extends AFPImageHandler implements Ima 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()) { @@ -143,6 +151,32 @@ public class AFPImageHandlerRenderedImage extends AFPImageHandler implements Ima } } + 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) diff --git a/fop-core/src/main/java/org/apache/fop/render/afp/AFPRendererConfig.java b/fop-core/src/main/java/org/apache/fop/render/afp/AFPRendererConfig.java index 4eac4bae3..db8162da9 100644 --- a/fop-core/src/main/java/org/apache/fop/render/afp/AFPRendererConfig.java +++ b/fop-core/src/main/java/org/apache/fop/render/afp/AFPRendererConfig.java @@ -54,6 +54,7 @@ import static org.apache.fop.render.afp.AFPRendererOption.IMAGES_DITHERING_QUALI 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; @@ -175,6 +176,10 @@ public final class AFPRendererConfig implements RendererConfig { 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); } @@ -315,6 +320,7 @@ public final class AFPRendererConfig implements RendererConfig { 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 { diff --git a/fop-core/src/main/java/org/apache/fop/render/afp/AFPRendererConfigurator.java b/fop-core/src/main/java/org/apache/fop/render/afp/AFPRendererConfigurator.java index 46320779b..99a015fcc 100644 --- a/fop-core/src/main/java/org/apache/fop/render/afp/AFPRendererConfigurator.java +++ b/fop-core/src/main/java/org/apache/fop/render/afp/AFPRendererConfigurator.java @@ -99,6 +99,9 @@ public class AFPRendererConfigurator extends PrintRendererConfigurator { if (config.isFs45() != null) { documentHandler.setFS45(config.isFs45()); } + if (config.isMaskEnabled() != null) { + documentHandler.setMaskEnabled(config.isMaskEnabled()); + } if (config.allowJpegEmbedding() != null) { documentHandler.canEmbedJpeg(config.allowJpegEmbedding()); } diff --git a/fop-core/src/main/java/org/apache/fop/render/afp/AFPRendererOption.java b/fop-core/src/main/java/org/apache/fop/render/afp/AFPRendererOption.java index b85ecf20b..cdd6fba73 100644 --- a/fop-core/src/main/java/org/apache/fop/render/afp/AFPRendererOption.java +++ b/fop-core/src/main/java/org/apache/fop/render/afp/AFPRendererOption.java @@ -31,6 +31,7 @@ public enum AFPRendererOption implements RendererConfigOption { 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), |