/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2006-2008, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotools.gui.swing.map.map2d.stream.strategy; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GraphicsConfiguration; import java.awt.GraphicsEnvironment; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.image.BufferedImage; import java.awt.image.VolatileImage; import java.util.HashMap; import java.util.Map; import javax.swing.JComponent; import javax.swing.SwingUtilities; import org.geotools.map.MapContext; import org.geotools.map.MapLayer; import org.geotools.map.event.MapLayerListEvent; import org.geotools.renderer.GTRenderer; import org.geotools.renderer.shape.ShapefileRenderer; import com.vividsolutions.jts.geom.Envelope; import java.lang.ref.WeakReference; /** * Optimize Strategy for edition. high memory needed * * @author Johann Sorel * * @source $URL$ */ public class MergeBufferedImageStrategy extends AbstractRenderingStrategy { private GTRenderer renderer ; private DrawingThread thread ; private BufferComponent comp ; private MapContext buffercontext ; private GraphicsConfiguration GC ; boolean mustupdate ; Map<MapLayer, BufferedImage> stock ; @Override protected JComponent init() { renderer = new ShapefileRenderer(); thread = new DrawingThread(this); comp = new BufferComponent(); buffercontext = new OneLayerContext(); GC = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration(); mustupdate = false; stock = new HashMap<MapLayer, BufferedImage>(); opimizeRenderer(); thread.start(); return comp; } private void opimizeRenderer() { Map rendererParams = new HashMap(); rendererParams.put("optimizedDataLoadingEnabled", new Boolean(true)); rendererParams.put("maxFiltersToSendToDatastore", new Integer(20)); //rendererParams.put(ShapefileRenderer.TEXT_RENDERING_KEY, ShapefileRenderer.TEXT_RENDERING_STRING); // rendererParams.put(ShapefileRenderer.TEXT_RENDERING_KEY, ShapefileRenderer.TEXT_RENDERING_OUTLINE); rendererParams.put(ShapefileRenderer.SCALE_COMPUTATION_METHOD_KEY, ShapefileRenderer.SCALE_OGC); renderer.setRendererHints(rendererParams); RenderingHints rh; rh = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); rh.add(new RenderingHints(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON)); rh.add(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED)); rh.add(new RenderingHints(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_SPEED)); rh.add(new RenderingHints(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_OFF)); rh.add(new RenderingHints(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_DISABLE)); renderer.setJava2DHints(rh); } private synchronized VolatileImage createBackBuffer() { Rectangle newRect = comp.getBounds(); Rectangle mapRectangle = new Rectangle(newRect.width, newRect.height); if (mapRectangle.width > 0 && mapRectangle.height > 0) { return GC.createCompatibleVolatileImage(mapRectangle.width, mapRectangle.height, VolatileImage.TRANSLUCENT); } else { return GC.createCompatibleVolatileImage(1, 1, VolatileImage.TRANSLUCENT); } } void mergeBuffers() { VolatileImage vi = createBackBuffer(); Graphics2D g2d = (Graphics2D) vi.getGraphics(); MapLayer[] layers = getContext().getLayers(); for (int i = 0, max = layers.length; i < max; i++) { // for (int i= layers.length-1; i>=0; i--){ MapLayer layer = layers[i]; BufferedImage img = stock.get(layer); if (img != null) { g2d.drawImage(img, null, 0, 0); } } comp.setBuffer(vi); } //-----------------abstract------------------------------------------------- public synchronized BufferedImage createBufferImage(MapLayer layer) { try { buffercontext.setCoordinateReferenceSystem(getContext().getCoordinateReferenceSystem()); } catch (Exception e) { } buffercontext.addLayer(layer); BufferedImage buf = createBufferImage(buffercontext); buffercontext.clearLayerList(); return buf; } public synchronized BufferedImage createBufferImage(MapContext context) { synchronized (renderer) { Rectangle newRect = comp.getBounds(); Rectangle mapRectangle = new Rectangle(newRect.width, newRect.height); if (mapRectangle.width > 0 && mapRectangle.height > 0) { //NOT OPTIMIZED // BufferedImage buf = new BufferedImage(mapRectangle.width, mapRectangle.height, BufferedImage.TYPE_INT_ARGB); // Graphics2D ig = buf.createGraphics(); //GraphicsConfiguration ACCELERATION BufferedImage buf = GC.createCompatibleImage(mapRectangle.width, mapRectangle.height, BufferedImage.TRANSLUCENT); Graphics2D ig = buf.createGraphics(); renderer.stopRendering(); renderer.setContext(context); Envelope env = getMapArea(); if (isValidEnvelope(env)) { try { renderer.paint((Graphics2D) ig, mapRectangle, env); } catch (Exception e) { e.printStackTrace(); } } return buf; } else { return null; } } } @Override public BufferedImage getSnapShot() { return comp.getBuffer(); } @Override public void refresh() { try { mapArea = fixAspectRatio(comp.getBounds(), getMapArea()); } catch (Exception e) { } mustupdate = true; thread.wake(); } @Override public void dispose(){ super.dispose(); thread.dispose(); } //-------------layer events------------------------------------------------- public void layerAdded(MapLayerListEvent event) { MapLayer layer = event.getLayer(); stock.put(layer, createBufferImage(layer)); mergeBuffers(); MapContext context = getContext(); // if (context.getLayerCount() == 1) { // try { // ReferencedEnvelope env = context.getLayerBounds(); // // if (env != null) { // setMapArea(env); // } // } catch (IOException ex) { // ex.printStackTrace(); // } // } } public void layerRemoved(MapLayerListEvent event) { stock.remove(event.getLayer()); mergeBuffers(); } public void layerChanged(MapLayerListEvent event) { MapLayer layer = event.getLayer(); stock.put(layer, createBufferImage(layer)); mergeBuffers(); } public void layerMoved(MapLayerListEvent event) { mergeBuffers(); } //----------private classes------------------------------------------------- private class BufferComponent extends JComponent { private VolatileImage img = null; public void setBuffer(VolatileImage buf) { img = buf; SwingUtilities.invokeLater(new Runnable() { public void run() { repaint(); } }); } public BufferedImage getBuffer() { if (img != null) { return img.getSnapshot(); } else { return null; } } @Override public void paintComponent(Graphics g) { if (img != null) { g.drawImage(img, 0, 0, this); } } } } class DrawingThread extends Thread { private boolean dispose = false; private final WeakReference<MergeBufferedImageStrategy> ref; DrawingThread(MergeBufferedImageStrategy strategy){ this.ref = new WeakReference<MergeBufferedImageStrategy>(strategy); } public void dispose(){ dispose = true; wake(); } @Override public void run() { while (true && !dispose) { MergeBufferedImageStrategy st = ref.get(); if(dispose || st == null){ break; } if (st.mustupdate) { st.setPainting(true); st.stock.clear(); MapLayer[] layers = st.getContext().getLayers(); for (MapLayer layer : layers) { st.stock.put(layer, st.createBufferImage(layer)); st.mergeBuffers(); } st.mustupdate = false; st.setPainting(false); } block(); } } public synchronized void wake() { notifyAll(); } private synchronized void block() { try { wait(); } catch (InterruptedException ex) { ex.printStackTrace(); } } }