/* Copyright (c) 2001 - 2011 TOPP - www.openplans.org. All rights reserved.
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.gwc.layer;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.IOException;
import java.io.OutputStream;
import javax.media.jai.PlanarImage;
import org.geoserver.ows.Response;
import org.geoserver.wms.RasterCleaner;
import org.geoserver.wms.WMS;
import org.geoserver.wms.WMSMapContent;
import org.geoserver.wms.map.RenderedImageMap;
import org.geoserver.wms.map.RenderedImageMapResponse;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.resources.image.ImageUtilities;
import org.geowebcache.grid.BoundingBox;
import org.geowebcache.grid.GridSubset;
import org.geowebcache.io.Resource;
import org.geowebcache.layer.MetaTile;
import org.geowebcache.mime.FormatModifier;
import org.geowebcache.mime.ImageMime;
import org.geowebcache.mime.MimeType;
import org.springframework.util.Assert;
public class GeoServerMetaTile extends MetaTile {
private RenderedImageMap metaTileMap;
private final String layer;
private final CatalogConfiguration mediator;
public GeoServerMetaTile(final String layer, GridSubset gridSubset, MimeType responseFormat,
FormatModifier formatModifier, long[] tileGridPosition, int metaX, int metaY,
Integer gutter, CatalogConfiguration mediator) {
super(gridSubset, responseFormat, formatModifier, tileGridPosition, metaX, metaY, gutter);
this.layer = layer;
this.mediator = mediator;
}
public void setWebMap(RenderedImageMap webMap) {
this.metaTileMap = webMap;
if (webMap instanceof RenderedImageMap) {
setImage(((RenderedImageMap) webMap).getImage());
}
}
/**
* Overrides to return {@link WMS#getJPEGNativeAcceleration()} if the requested response format
* is image/jpeg, otherwise if it's set to false and native JAI is available JPEGMapResponse
* will assume the WMS setting and create repeated tiles because it will not get a
* BufferedImage.
*
* @see org.geowebcache.layer.MetaTile#nativeAccelAvailable()
*/
@Override
protected boolean nativeAccelAvailable() {
boolean useNativeAccel = super.nativeAccelAvailable();
if (useNativeAccel && ImageMime.jpeg.equals(responseFormat)) {
useNativeAccel = WMS.get().getJPEGNativeAcceleration();
}
return useNativeAccel;
}
/**
* Creates the {@link RenderedImage} corresponding to the tile at index {@code tileIdx} and uses
* a {@link RenderedImageMapResponse} to encode it into the {@link #getResponseFormat() response
* format}.
*
* @see org.geowebcache.layer.MetaTile#writeTileToStream(int, org.geowebcache.io.Resource)
* @see RenderedImageMapResponse#write
*
*/
@Override
public boolean writeTileToStream(final int tileIdx, Resource target) throws IOException {
Assert.notNull(metaTileMap, "webMap is not set");
if (!(metaTileMap instanceof RenderedImageMap)) {
throw new IllegalArgumentException("Only RenderedImageMaps are supported so far: "
+ metaTileMap.getClass().getName());
}
final RenderedImageMapResponse mapEncoder;
{
final Response responseEncoder = mediator.getResponseEncoder(responseFormat,
metaTileMap);
mapEncoder = (RenderedImageMapResponse) responseEncoder;
}
RenderedImage tile = metaTileMap.getImage();
WMSMapContent tileContext = metaTileMap.getMapContext();
if (this.tiles.length > 1) {
final Rectangle tileDim = this.tiles[tileIdx];
tile = createTile(tileDim.x, tileDim.y, tileDim.width, tileDim.height);
{
final WMSMapContent metaTileContext = metaTileMap.getMapContext();
// do not create tileContext with metaTileContext.getLayers() as the layer list.
// It is not needed at this stage and the constructor would force a
// MapLayer.getBounds() that might fail
tileContext = new WMSMapContent();
tileContext.setRequest(metaTileContext.getRequest());
tileContext.setBgColor(metaTileContext.getBgColor());
tileContext.setMapWidth(tileDim.width);
tileContext.setMapHeight(tileDim.height);
tileContext.setPaletteInverter(metaTileContext.getPaletteInverter());
tileContext.setTransparent(tileContext.isTransparent());
long[][] tileIndexes = getTilesGridPositions();
BoundingBox tileBounds = gridSubset.boundsFromIndex(tileIndexes[tileIdx]);
ReferencedEnvelope tilebbox = new ReferencedEnvelope(
metaTileContext.getCoordinateReferenceSystem());
tilebbox.init(tileBounds.getMinX(), tileBounds.getMaxX(), tileBounds.getMinY(),
tileBounds.getMaxY());
tileContext.getViewport().setBounds(tilebbox);
}
}
OutputStream outStream = target.getOutputStream();
try {
// call formatImageOuputStream instead of write to avoid disposition of rendered images
// when processing a tile from a metatile and instead defer it to this class' dispose()
// method
mapEncoder.formatImageOutputStream(tile, outStream, tileContext);
return true;
} finally {
outStream.close();
}
}
public void dispose() {
if (metaTileMap != null) {
RenderedImage image = metaTileMap.getImage();
// as in RenderedImageMapResponse.write: let go of the image chain as quick as possible
// to free memory
RasterCleaner.addImage(image);
metaTileMap.dispose();
metaTileMap = null;
}
}
}