Add support for JPEG encoding option for HDMaps

This commit is contained in:
Mike Primm 2011-08-12 14:44:49 +08:00 committed by mikeprimm
parent 49b38c10b7
commit d008548306
11 changed files with 72 additions and 33 deletions

View File

@ -107,9 +107,10 @@ public class DynmapWorld {
private static class PNGFileFilter implements FilenameFilter { private static class PNGFileFilter implements FilenameFilter {
String prefix; String prefix;
public PNGFileFilter(String pre) { prefix = pre; } String suffix;
public PNGFileFilter(String pre, MapType.ImageFormat fmt) { prefix = pre; suffix = "." + fmt.getFileExt(); }
public boolean accept(File f, String n) { public boolean accept(File f, String n) {
if(n.endsWith(".png") && n.startsWith(prefix)) { if(n.endsWith(suffix) && n.startsWith(prefix)) {
File fn = new File(f, n); File fn = new File(f, n);
return fn.isFile(); return fn.isFile();
} }
@ -147,6 +148,7 @@ public class DynmapWorld {
String zfnprefix; String zfnprefix;
int bigworldshift; int bigworldshift;
boolean isbigmap; boolean isbigmap;
MapType.ImageFormat fmt;
} }
public boolean freshenZoomOutFilesByLevel(int zoomlevel) { public boolean freshenZoomOutFilesByLevel(int zoomlevel) {
@ -253,6 +255,7 @@ public class DynmapWorld {
pd.zoomprefix = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz".substring(0, zoomlevel); pd.zoomprefix = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz".substring(0, zoomlevel);
pd.bigworldshift = bigworldshift; pd.bigworldshift = bigworldshift;
pd.isbigmap = mt.isBigWorldMap(this); pd.isbigmap = mt.isBigWorldMap(this);
pd.fmt = mt.getImageFormat();
if(pd.isbigmap) { if(pd.isbigmap) {
if(zoomlevel > 0) { if(zoomlevel > 0) {
pd.zoomprefix += "_"; pd.zoomprefix += "_";
@ -283,15 +286,15 @@ public class DynmapWorld {
private String makeFilePath(PrefixData pd, int x, int y, boolean zoomed) { private String makeFilePath(PrefixData pd, int x, int y, boolean zoomed) {
if(pd.isbigmap) if(pd.isbigmap)
return pd.baseprefix + "/" + (x >> pd.bigworldshift) + "_" + (y >> pd.bigworldshift) + "/" + (zoomed?pd.zfnprefix:pd.fnprefix) + x + "_" + y + ".png"; return pd.baseprefix + "/" + (x >> pd.bigworldshift) + "_" + (y >> pd.bigworldshift) + "/" + (zoomed?pd.zfnprefix:pd.fnprefix) + x + "_" + y + "." + pd.fmt.getFileExt();
else else
return (zoomed?pd.zfnprefix:pd.fnprefix) + "_" + x + "_" + y + ".png"; return (zoomed?pd.zfnprefix:pd.fnprefix) + "_" + x + "_" + y + "." + pd.fmt.getFileExt();
} }
private int processZoomDirectory(File dir, PrefixData pd) { private int processZoomDirectory(File dir, PrefixData pd) {
Debug.debug("processZoomDirectory(" + dir.getPath() + "," + pd.baseprefix + ")"); Debug.debug("processZoomDirectory(" + dir.getPath() + "," + pd.baseprefix + ")");
HashMap<String, ProcessTileRec> toprocess = new HashMap<String, ProcessTileRec>(); HashMap<String, ProcessTileRec> toprocess = new HashMap<String, ProcessTileRec>();
String[] files = dir.list(new PNGFileFilter(pd.fnprefix)); String[] files = dir.list(new PNGFileFilter(pd.fnprefix, pd.fmt));
if(files == null) if(files == null)
return 0; return 0;
for(String fn : files) { for(String fn : files) {
@ -435,7 +438,7 @@ public class DynmapWorld {
try { try {
if(!zf.getParentFile().exists()) if(!zf.getParentFile().exists())
zf.getParentFile().mkdirs(); zf.getParentFile().mkdirs();
FileLockManager.imageIOWrite(zIm, "png", zf); FileLockManager.imageIOWrite(zIm, pd.fmt.getFileExt(), zf);
Debug.debug("Saved zoom-out tile at " + zf.getPath()); Debug.debug("Saved zoom-out tile at " + zf.getPath());
} catch (IOException e) { } catch (IOException e) {
Debug.error("Failed to save zoom-out tile: " + zf.getName(), e); Debug.error("Failed to save zoom-out tile: " + zf.getName(), e);

View File

@ -1,20 +1,27 @@
package org.dynmap; package org.dynmap;
import java.io.File;
import java.util.List; import java.util.List;
import org.bukkit.Location; import org.bukkit.Location;
import org.dynmap.utils.MapChunkCache;
import org.json.simple.JSONObject; import org.json.simple.JSONObject;
public abstract class MapType { public abstract class MapType {
public enum ImageFormat {
FORMAT_PNG("png"),
FORMAT_JPG("jpg");
String ext;
ImageFormat(String ext) {
this.ext = ext;
}
public String getFileExt() { return ext; }
};
public abstract MapTile[] getTiles(Location l); public abstract MapTile[] getTiles(Location l);
public abstract MapTile[] getAdjecentTiles(MapTile tile); public abstract MapTile[] getAdjecentTiles(MapTile tile);
public abstract List<DynmapChunk> getRequiredChunks(MapTile tile); public abstract List<DynmapChunk> getRequiredChunks(MapTile tile);
public abstract boolean render(MapChunkCache cache, MapTile tile, File outputFile);
public void buildClientConfiguration(JSONObject worldObject, DynmapWorld w) { public void buildClientConfiguration(JSONObject worldObject, DynmapWorld w) {
} }
@ -41,6 +48,9 @@ public abstract class MapType {
public abstract boolean isBigWorldMap(DynmapWorld w); public abstract boolean isBigWorldMap(DynmapWorld w);
/* Return number of zoom levels needed by this map (before extra levels from extrazoomout) */ /* Return number of zoom levels needed by this map (before extra levels from extrazoomout) */
public int getMapZoomOutLevels() { return 0; } public int getMapZoomOutLevels() { return 0; }
public ImageFormat getImageFormat() { return ImageFormat.FORMAT_PNG; }
/** /**
* Step sequence for creating zoomed file: first index is top-left, second top-right, third bottom-left, forth bottom-right * Step sequence for creating zoomed file: first index is top-left, second top-right, third bottom-left, forth bottom-right
* Values correspond to tile X,Y (0), X+step,Y (1), X,Y+step (2), X+step,Y+step (3) * Values correspond to tile X,Y (0), X+step,Y (1), X,Y+step (2), X+step,Y+step (3)

View File

@ -124,7 +124,6 @@ public class FlatMap extends MapType {
return result; return result;
} }
@Override
public boolean render(MapChunkCache cache, MapTile tile, File outputFile) { public boolean render(MapChunkCache cache, MapTile tile, File outputFile) {
FlatMapTile t = (FlatMapTile) tile; FlatMapTile t = (FlatMapTile) tile;
World w = t.getWorld(); World w = t.getWorld();

View File

@ -19,6 +19,7 @@ import org.dynmap.utils.MapChunkCache;
import org.json.simple.JSONObject; import org.json.simple.JSONObject;
public class HDMap extends MapType { public class HDMap extends MapType {
private String name; private String name;
private String prefix; private String prefix;
private HDPerspective perspective; private HDPerspective perspective;
@ -26,6 +27,11 @@ public class HDMap extends MapType {
private HDLighting lighting; private HDLighting lighting;
private ConfigurationNode configuration; private ConfigurationNode configuration;
private int mapzoomout; private int mapzoomout;
private MapType.ImageFormat imgformat;
public static final String IMGFORMAT_PNG = "png";
public static final String IMGFORMAT_JPG = "jpg";
public HDMap(ConfigurationNode configuration) { public HDMap(ConfigurationNode configuration) {
name = configuration.getString("name", null); name = configuration.getString("name", null);
@ -83,6 +89,12 @@ public class HDMap extends MapType {
mapzoomout++; mapzoomout++;
scale = scale / 2.0; scale = scale / 2.0;
} }
String fmt = configuration.getString("image-format", "png");
/* Only allow png or jpg */
if(fmt.equals(IMGFORMAT_PNG))
imgformat = ImageFormat.FORMAT_PNG;
else
imgformat = ImageFormat.FORMAT_JPG;
} }
public HDShader getShader() { return shader; } public HDShader getShader() { return shader; }
@ -104,14 +116,6 @@ public class HDMap extends MapType {
return perspective.getRequiredChunks(tile); return perspective.getRequiredChunks(tile);
} }
@Override
public boolean render(MapChunkCache cache, MapTile tile, File bogus) {
if(tile instanceof HDMapTile)
return perspective.render(cache, (HDMapTile)tile);
else
return false;
}
@Override @Override
public List<String> baseZoomFilePrefixes() { public List<String> baseZoomFilePrefixes() {
ArrayList<String> s = new ArrayList<String>(); ArrayList<String> s = new ArrayList<String>();
@ -181,6 +185,8 @@ public class HDMap extends MapType {
return lst; return lst;
} }
@Override
public ImageFormat getImageFormat() { return imgformat; }
@Override @Override
public void buildClientConfiguration(JSONObject worldObject, DynmapWorld world) { public void buildClientConfiguration(JSONObject worldObject, DynmapWorld world) {
@ -197,6 +203,7 @@ public class HDMap extends MapType {
s(o, "bigmap", true); s(o, "bigmap", true);
s(o, "mapzoomout", (world.getExtraZoomOutLevels()+mapzoomout)); s(o, "mapzoomout", (world.getExtraZoomOutLevels()+mapzoomout));
s(o, "mapzoomin", c.getInteger("mapzoomin", 2)); s(o, "mapzoomin", c.getInteger("mapzoomin", 2));
s(o, "image-format", imgformat.getFileExt());
perspective.addClientConfiguration(o); perspective.addClientConfiguration(o);
shader.addClientConfiguration(o); shader.addClientConfiguration(o);
lighting.addClientConfiguration(o); lighting.addClientConfiguration(o);

View File

@ -3,6 +3,7 @@ package org.dynmap.hdmap;
import org.dynmap.DynmapChunk; import org.dynmap.DynmapChunk;
import org.dynmap.DynmapWorld; import org.dynmap.DynmapWorld;
import org.dynmap.MapManager; import org.dynmap.MapManager;
import org.dynmap.MapType;
import java.util.List; import java.util.List;
import org.dynmap.MapTile; import org.dynmap.MapTile;
@ -21,20 +22,20 @@ public class HDMapTile extends MapTile {
@Override @Override
public String getFilename() { public String getFilename() {
return getFilename("hdmap"); return getFilename("hdmap", MapType.ImageFormat.FORMAT_PNG);
} }
public String getFilename(String prefix) { public String getFilename(String prefix, MapType.ImageFormat format) {
return prefix + "/" + (tx >> 5) + '_' + (ty >> 5) + '/' + tx + "_" + ty + ".png"; return prefix + "/" + (tx >> 5) + '_' + (ty >> 5) + '/' + tx + "_" + ty + "." + format.getFileExt();
} }
@Override @Override
public String getDayFilename() { public String getDayFilename() {
return getDayFilename("hdmap"); return getDayFilename("hdmap", MapType.ImageFormat.FORMAT_PNG);
} }
public String getDayFilename(String prefix) { public String getDayFilename(String prefix, MapType.ImageFormat format) {
return prefix + "_day/" + (tx >> 5) + '_' + (ty >> 5) + '/' + tx + "_" + ty + ".png"; return prefix + "_day/" + (tx >> 5) + '_' + (ty >> 5) + '/' + tx + "_" + ty + "." + format.getFileExt();
} }
@Override @Override

View File

@ -21,6 +21,7 @@ import org.dynmap.DynmapChunk;
import org.dynmap.Log; import org.dynmap.Log;
import org.dynmap.MapManager; import org.dynmap.MapManager;
import org.dynmap.MapTile; import org.dynmap.MapTile;
import org.dynmap.MapType;
import org.dynmap.TileHashManager; import org.dynmap.TileHashManager;
import org.dynmap.debug.Debug; import org.dynmap.debug.Debug;
import org.dynmap.utils.MapIterator.BlockStep; import org.dynmap.utils.MapIterator.BlockStep;
@ -967,7 +968,8 @@ public class IsoHDPerspective implements HDPerspective {
String prefix = shaderstate[i].getMap().getPrefix(); String prefix = shaderstate[i].getMap().getPrefix();
if(rendered[i]) { if(rendered[i]) {
renderone = true; renderone = true;
String fname = tile.getFilename(prefix); MapType.ImageFormat fmt = shaderstate[i].getMap().getImageFormat();
String fname = tile.getFilename(prefix, fmt);
File f = new File(tile.getDynmapWorld().worldtilepath, fname); File f = new File(tile.getDynmapWorld().worldtilepath, fname);
FileLockManager.getWriteLock(f); FileLockManager.getWriteLock(f);
try { try {
@ -977,7 +979,7 @@ public class IsoHDPerspective implements HDPerspective {
if(!f.getParentFile().exists()) if(!f.getParentFile().exists())
f.getParentFile().mkdirs(); f.getParentFile().mkdirs();
try { try {
FileLockManager.imageIOWrite(im[i].buf_img, "png", f); FileLockManager.imageIOWrite(im[i].buf_img, fmt.getFileExt(), f);
} catch (IOException e) { } catch (IOException e) {
Debug.error("Failed to save image: " + f.getPath(), e); Debug.error("Failed to save image: " + f.getPath(), e);
} catch (java.lang.NullPointerException e) { } catch (java.lang.NullPointerException e) {
@ -998,7 +1000,7 @@ public class IsoHDPerspective implements HDPerspective {
MapManager.mapman.updateStatistics(tile, prefix, true, tile_update, !rendered[i]); MapManager.mapman.updateStatistics(tile, prefix, true, tile_update, !rendered[i]);
/* Handle day image, if needed */ /* Handle day image, if needed */
if(dayim[i] != null) { if(dayim[i] != null) {
fname = tile.getDayFilename(prefix); fname = tile.getDayFilename(prefix, fmt);
f = new File(tile.getDynmapWorld().worldtilepath, fname); f = new File(tile.getDynmapWorld().worldtilepath, fname);
FileLockManager.getWriteLock(f); FileLockManager.getWriteLock(f);
prefix = prefix+"_day"; prefix = prefix+"_day";
@ -1010,7 +1012,7 @@ public class IsoHDPerspective implements HDPerspective {
if(!f.getParentFile().exists()) if(!f.getParentFile().exists())
f.getParentFile().mkdirs(); f.getParentFile().mkdirs();
try { try {
FileLockManager.imageIOWrite(dayim[i].buf_img, "png", f); FileLockManager.imageIOWrite(dayim[i].buf_img, fmt.getFileExt(), f);
} catch (IOException e) { } catch (IOException e) {
Debug.error("Failed to save image: " + f.getPath(), e); Debug.error("Failed to save image: " + f.getPath(), e);
} catch (java.lang.NullPointerException e) { } catch (java.lang.NullPointerException e) {

View File

@ -213,7 +213,6 @@ public class KzedMap extends MapType {
} }
} }
@Override
public boolean render(MapChunkCache cache, MapTile tile, File outputFile) { public boolean render(MapChunkCache cache, MapTile tile, File outputFile) {
if (tile instanceof KzedMapTile) { if (tile instanceof KzedMapTile) {
return ((KzedMapTile) tile).renderer.render(cache, (KzedMapTile) tile, outputFile); return ((KzedMapTile) tile).renderer.render(cache, (KzedMapTile) tile, outputFile);

View File

@ -6,6 +6,8 @@ import java.io.FileOutputStream;
import java.io.RandomAccessFile; import java.io.RandomAccessFile;
import java.util.HashMap; import java.util.HashMap;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.awt.image.DirectColorModel;
import java.awt.image.WritableRaster;
import java.io.IOException; import java.io.IOException;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
@ -145,7 +147,21 @@ public class FileLockManager {
byte[] rslt; byte[] rslt;
synchronized(baos_lock) { synchronized(baos_lock) {
baos.reset(); baos.reset();
ImageIO.write(img, type, baos); /* Write to byte array stream - prevent bogus I/O errors */ if(type.equals("jpg")) {
WritableRaster raster = img.getRaster();
WritableRaster newRaster = raster.createWritableChild(0, 0, img.getWidth(),
img.getHeight(), 0, 0, new int[] {0, 1, 2});
DirectColorModel cm = (DirectColorModel)img.getColorModel();
DirectColorModel newCM = new DirectColorModel(cm.getPixelSize(),
cm.getRedMask(), cm.getGreenMask(), cm.getBlueMask());
// now create the new buffer that is used ot write the image:
BufferedImage rgbBuffer = new BufferedImage(newCM, newRaster, false, null);
ImageIO.write(rgbBuffer, type, baos); /* Write to byte array stream - prevent bogus I/O errors */
rgbBuffer.flush();
}
else {
ImageIO.write(img, type, baos); /* Write to byte array stream - prevent bogus I/O errors */
}
rslt = baos.toByteArray(); rslt = baos.toByteArray();
} }
while(!done) { while(!done) {

View File

@ -27,6 +27,7 @@ public abstract class FileHandler implements HttpHandler {
mimes.put(".htm", "text/html"); mimes.put(".htm", "text/html");
mimes.put(".js", "text/javascript"); mimes.put(".js", "text/javascript");
mimes.put(".png", "image/png"); mimes.put(".png", "image/png");
mimes.put(".jpg", "image/jpeg");
mimes.put(".css", "text/css"); mimes.put(".css", "text/css");
mimes.put(".txt", "text/plain"); mimes.put(".txt", "text/plain");
} }

View File

@ -260,7 +260,8 @@ var DynmapTileLayer = L.TileLayer.extend({
zoom: this.zoomprefix(zoomoutlevel), zoom: this.zoomprefix(zoomoutlevel),
zoomprefix: (zoomoutlevel==0)?"":(this.zoomprefix(zoomoutlevel)+"_"), zoomprefix: (zoomoutlevel==0)?"":(this.zoomprefix(zoomoutlevel)+"_"),
x: x, x: x,
y: y y: y,
fmt: this.options['image-format'] || 'png'
}; };
} }
}); });

View File

@ -36,7 +36,7 @@ var HDMapType = DynmapTileLayer.extend({
// Y is inverted for HD-map. // Y is inverted for HD-map.
info.y = -info.y; info.y = -info.y;
info.scaledy = info.y >> 5; info.scaledy = info.y >> 5;
return namedReplace('{prefix}{nightday}/{scaledx}_{scaledy}/{zoom}{x}_{y}.png', info); return namedReplace('{prefix}{nightday}/{scaledx}_{scaledy}/{zoom}{x}_{y}.{fmt}', info);
}, },
zoomprefix: function(amount) { zoomprefix: function(amount) {
// amount == 0 -> '' // amount == 0 -> ''