package org.icepdf.core.pobjects.graphics; import org.icepdf.core.pobjects.ImageStream; import org.icepdf.core.pobjects.Page; import org.icepdf.core.pobjects.Resources; import org.icepdf.core.util.Defs; import org.icepdf.core.util.Library; import java.awt.image.BufferedImage; import java.awt.image.BufferedImageOp; import java.awt.image.ConvolveOp; import java.awt.image.Kernel; import java.util.concurrent.FutureTask; import java.util.logging.Level; import java.util.logging.Logger; /** * BlurredImageReference graph attempts to smooth out images using convolution. The implementation takes advantage of * the java.awt.image.Kernel class to apply the matrix that defines the convolution. The default blur factor is 3 which * seems to provide a nice balance, the value can go as low as 2 for just a light blur or as high as 25 for a very * blurred image result. This image refernce format is best suited for TIFF images that are hard to read at small zoom * levels. * <p> * The blur value can be set with the system property org.icepdf.core.imageReference.blurred.dimension and once again * the default value is 3. The blurring algorithm has a minimum image size associated with it. To small an image and * the blur effect looks less then ideal. The default values for minimum image size is 1800x2200 and can be set with either * org.icepdf.core.imageReference.blurred.minwidth or org.icepdf.core.imageReference.blurred.minheight. However * smaller values can lead to missing content on low res images. * * @since 6.2.4 */ public class BlurredImageReference extends CachedImageReference { private static final Logger logger = Logger.getLogger(ImageStreamReference.class.toString()); private static int dimension, minWidth, minHeight; static { dimension = Defs.intProperty("org.icepdf.core.imageReference.blurred.dimension", 3); minWidth = Defs.intProperty("org.icepdf.core.imageReference.blurred.minwidth", 1800); minHeight = Defs.intProperty("org.icepdf.core.imageReference.blurred.minheight", 2200); } private static float[] matrix; static { float size = dimension * dimension; matrix = new float[(int) size]; for (int i = 0; i < size; i++) { matrix[i] = 1.0f / size; } } protected BlurredImageReference(ImageStream imageStream, GraphicsState graphicsState, Resources resources, int imageIndex, Page page) { super(imageStream, graphicsState, resources, imageIndex, page); // kick off a new thread to load the image, if not already in pool. ImagePool imagePool = imageStream.getLibrary().getImagePool(); if (useProxy && imagePool.get(reference) == null) { futureTask = new FutureTask<BufferedImage>(this); Library.executeImage(futureTask); } else if (!useProxy && imagePool.get(reference) == null) { image = call(); } } public BufferedImage call() { BufferedImage image = null; long start = System.nanoTime(); try { image = imageStream.getImage(graphicsState, resources); if (image.getWidth() > minWidth && image.getHeight() > minHeight) { BufferedImageOp op = new ConvolveOp(new Kernel(dimension, dimension, matrix)); image = op.filter(image, null); } } catch (Throwable e) { logger.log(Level.WARNING, "Error loading image: " + imageStream.getPObjectReference() + " " + imageStream.toString(), e); } long end = System.nanoTime(); notifyImagePageEvents((end - start)); return image; } @Override public int getWidth() { return imageStream.getWidth(); } @Override public int getHeight() { return imageStream.getHeight(); } }