/* * Copyright (c) 2016 Fraunhofer IGD * * All rights reserved. This program and the accompanying materials are made * available under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * You should have received a copy of the GNU Lesser General Public License * along with this distribution. If not, see <http://www.gnu.org/licenses/>. * * Contributors: * Fraunhofer IGD <http://www.igd.fraunhofer.de/> */ package de.fhg.igd.mapviewer.marker; import java.awt.AlphaComposite; import java.awt.Composite; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.image.BufferedImage; import java.lang.ref.SoftReference; import org.jdesktop.swingx.graphics.GraphicsUtilities; /** * A painter caching its result in a {@link BufferedImage} * * @param <T> the painter context type * @author Simon Templer */ public abstract class CachingPainter<T> { private transient SoftReference<BufferedImage> cachedImage; private int originX = 0; private int originY = 0; private boolean dirty = false; private boolean antialiasing = true; private static Graphics2D graphicsDummy = null; /** * Paint on a graphics device * * @param g the graphics device * @param context the painting context * @param x the x coordinate of position to paint at * @param y the y coordinate of position to paint at */ public void paint(Graphics2D g, T context, int x, int y) { if (dirty || cachedImage == null || cachedImage.get() == null) { // paint on image doPaint(context); } BufferedImage img = cachedImage.get(); if (img != null) { configureGraphics(g); g.drawImage(img, x - originX, y - originY, null); } /* * test g.setColor(Color.WHITE); g.drawRect(-2, -2, 4, 4); */ } /** * Do the painting. Implementations of this method must call * {@link #beginPainting(int, int, int, int)} to get a graphics object and * {@link #endPainting(Graphics2D)} to finish painting. * * @param context the painting context */ protected abstract void doPaint(T context); /** * Start the painting by creating a graphics object to paint on * * @param width the desired width * @param height the desired height * @param originX the translation of the origin in x-direction * @param originY the translation of the origin in y-direction * @return the graphics device to use for painting */ protected Graphics2D beginPainting(int width, int height, int originX, int originY) { this.originX = originX; this.originY = originY; BufferedImage img = (cachedImage == null) ? (null) : (cachedImage.get()); clearCache(); boolean clear = true; if (img == null || img.getWidth() != width || img.getHeight() != height) { img = GraphicsUtilities.createCompatibleTranslucentImage(width, height); cachedImage = new SoftReference<BufferedImage>(img); clear = false; } Graphics2D gfx = img.createGraphics(); gfx.setClip(0, 0, width, height); if (clear) { Composite composite = gfx.getComposite(); gfx.setComposite(AlphaComposite.Clear); gfx.fillRect(0, 0, width, height); gfx.setComposite(composite); } gfx.translate(originX, originY); configureGraphics(gfx); return gfx; } /** * Finishes the painting, must be called always after calling * {@link #beginPainting(int, int, int, int)} when painting is done. * * @param gfx the graphics object */ protected void endPainting(Graphics2D gfx) { gfx.dispose(); dirty = false; } /** * Mark the painter as dirty, it will be repainted on the next call to * {@link #paint(Graphics2D, Object, int, int)} */ public void markDirty() { if (!dirty) { clearCache(); dirty = true; } } /** * @param antialiasing the anti-aliasing to set */ public void setAntialiasing(boolean antialiasing) { this.antialiasing = antialiasing; } /** * Clears the cached image */ protected void clearCache() { if (cachedImage != null) { BufferedImage img = cachedImage.get(); if (img != null) { img.flush(); } } } /** * Configure the given graphics * * @param gfx the graphics device */ protected void configureGraphics(Graphics2D gfx) { if (antialiasing) { gfx.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); } else { gfx.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); } } /** * Get the dummy graphics device * * @return the dummy graphics device */ protected Graphics2D getGraphicsDummy() { if (graphicsDummy == null) { BufferedImage image = GraphicsUtilities.createCompatibleTranslucentImage(32, 32); graphicsDummy = image.createGraphics(); } configureGraphics(graphicsDummy); return graphicsDummy; } }