/******************************************************************************* * Copyright (c) 2007, 2010 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.g2d.image.impl; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Shape; import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; import java.util.ArrayList; import java.util.Arrays; import java.util.EnumSet; import java.util.HashMap; import java.util.List; import java.util.Map; import org.simantics.g2d.image.Image; import org.simantics.scenegraph.Node; import org.simantics.scenegraph.g2d.G2DParentNode; import org.simantics.scenegraph.utils.QualityHints; /** * Video-ram cache suitable for rasterized PaintableSymbols scalable vector graphics. *

* This implementation rasterizes the same symbol from different mip map levels. * * @see VRamBufferedImage * @author Toni Kalajainen */ public class MipMapBufferedImage extends ImageProxy implements Image { /** Extra margin to the bounds reported by batik*/ public static final double MARGIN_PERCENT = 3; public static final double MAX_DIMENSION = 800; public static final double MIN_DIMENSION = 4; Shape outline; double [] resolutions; Map rasters = new HashMap(); double minResolution, maxResolution; EnumSet caps; public MipMapBufferedImage(Image original) { super(original); this.source = original; // Init rasters - they are built on-demand double maxResolution = maxResolution(); double minResolution = minResolution(); double resolution = maxResolution; List resolutions = new ArrayList(); while (resolution>minResolution) { Raster r = new Raster(resolution); rasters.put(resolution, r); resolutions.add(resolution); resolution /= 2; } // arraylist -> array this.resolutions = new double[resolutions.size()]; for (int i=0; i=0) return resolutions[index]; index = -(index+1); if (index>=resolutions.length) index = resolutions.length-1; if (index<0) index = 0; return resolutions[index]; } @Override public Node init(G2DParentNode parent) { return null; // Graphics2D g = gc.getGraphics2D(); // // Quality rendering requested, do not render from cache // //QualityHints.HIGH_QUALITY_HINTS.setQuality(g); // if (g.getRenderingHint(RenderingHints.KEY_RENDERING) == RenderingHints.VALUE_RENDER_QUALITY) // { // source.paint(gc); // return; // } // // double requiredResolution = requiredResolution(g.getTransform()); // if (requiredResolution > maxResolution) // { // g = gc.createClone(); // g.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED); // g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); // g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); // g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); // g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED); // g.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_DISABLE); // gc = new GraphicsContextImpl(g, gc.getBounds(), gc.getNode()); // source.paint(gc); // return; // } // // double closestResolution = findClosestResolution(requiredResolution); // // Raster raster = rasters.get(closestResolution); // // Object origInterpolationHint = g.getRenderingHint(RenderingHints.KEY_INTERPOLATION); // if (origInterpolationHint==null) // origInterpolationHint = RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR; // g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); // try { // raster.paint( gc ); // } finally { // g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, origInterpolationHint); // } } public Image getOriginalPaintableSymbol() { return source; } synchronized void releaseRaster() { for (Raster r : rasters.values()) r.image = null; } @Override protected void notifyChanged() { releaseRaster(); super.notifyChanged(); } class Raster implements Comparable { java.awt.image.BufferedImage image; double resolution; // int widMargin, heiMargin; int wid, hei; Raster(double resolution) { Rectangle2D bounds = source.getBounds(); this.resolution = resolution; double wid = bounds.getWidth(); double hei = bounds.getHeight(); this.wid = (int) (wid * resolution); this.hei = (int) (hei * resolution); // widMargin = (int) (wid * resolution * (MARGIN_PERCENT/100)) +1; // heiMargin = (int) (hei * resolution * (MARGIN_PERCENT/100)) +1; } synchronized java.awt.image.BufferedImage getOrCreate() { if (image!=null) return image; Rectangle2D bounds = source.getBounds(); image = new java.awt.image.BufferedImage( (wid+0*2+1), (hei+0*2+1), java.awt.image.BufferedImage.TYPE_INT_ARGB); Graphics2D target = image.createGraphics(); target.setBackground(new Color(255,255,255,0)); target.clearRect(0, 0, image.getWidth(), image.getHeight()); QualityHints.HIGH_QUALITY_HINTS.setQuality(target); // target.setRenderingHint(RenderingHintsKeyExt.KEY_BUFFERED_IMAGE, new WeakReference(image)); // target.translate(widMargin, heiMargin); target.scale(resolution, resolution); target.translate(-bounds.getMinX(), -bounds.getMinY()); source.init(null); // new GraphicsContextImpl(new Rectangle2D.Double(0,0, image.getWidth(), image.getHeight()), null) // ); target.dispose(); return image; } // public void paint(GraphicsContext gc) { // Rectangle2D bounds = source.getBounds(); // java.awt.image.BufferedImage image = getOrCreate(); // if (image==null) // { // source.paint(gc); // return; // } // Graphics2D g = gc.getGraphics2D(); // AffineTransform af = g.getTransform(); // Object rh = g.getRenderingHint(RenderingHints.KEY_INTERPOLATION); // try { // /// Bicubic interpolation is very slow with opengl pipeline // if (rh == RenderingHints.VALUE_INTERPOLATION_BICUBIC) // g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, // RenderingHints.VALUE_INTERPOLATION_BILINEAR); // g.translate(bounds.getMinX(), bounds.getMinY()); // g.scale(1/resolution, 1/resolution); //// g.translate(-widMargin, -heiMargin); // g.drawImage(image, 0, 0, null); // } finally { // g.setTransform(af); // g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, rh); // } // } @Override public int compareTo(Raster other) { if (other.resolutionresolution) return 1; return 0; } } @Override public EnumSet getFeatures() { return caps; } public Image getSource() { return source; } }