Add multiple quality levels for JPG encoding - adjust default to 0.85

This commit is contained in:
Mike Primm 2011-08-16 12:26:28 +08:00 committed by mikeprimm
parent e978745f79
commit a3015f78d2
8 changed files with 69 additions and 41 deletions

View file

@ -6,7 +6,6 @@ import java.util.List;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.Location; import org.bukkit.Location;
import org.dynmap.debug.Debug; import org.dynmap.debug.Debug;
import org.dynmap.kzedmap.KzedMap;
import org.dynmap.utils.DynmapBufferedImage; import org.dynmap.utils.DynmapBufferedImage;
import org.dynmap.utils.FileLockManager; import org.dynmap.utils.FileLockManager;
import org.dynmap.utils.MapChunkCache; import org.dynmap.utils.MapChunkCache;
@ -447,7 +446,7 @@ public class DynmapWorld {
try { try {
if(!zf.getParentFile().exists()) if(!zf.getParentFile().exists())
zf.getParentFile().mkdirs(); zf.getParentFile().mkdirs();
FileLockManager.imageIOWrite(zIm, pd.fmt.getFileExt(), zf); FileLockManager.imageIOWrite(zIm, pd.fmt, 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

@ -7,14 +7,26 @@ import org.json.simple.JSONObject;
public abstract class MapType { public abstract class MapType {
public enum ImageFormat { public enum ImageFormat {
FORMAT_PNG("png"), FORMAT_PNG("png", "png", 0.0f),
FORMAT_JPG("jpg"); FORMAT_JPG75("jpg-q75", "jpg", 0.75f),
FORMAT_JPG80("jpg-q80", "jpg", 0.80f),
FORMAT_JPG85("jpg-q85", "jpg", 0.85f),
FORMAT_JPG("jpg", "jpg", 0.85f),
FORMAT_JPG90("jpg-q90", "jpg", 0.90f),
FORMAT_JPG95("jpg-q95", "jpg", 0.95f),
FORMAT_JPG100("jpg-q100", "jpg", 1.00f);
String id;
String ext; String ext;
ImageFormat(String ext) { float qual;
ImageFormat(String id, String ext, float quality) {
this.id = id;
this.ext = ext; this.ext = ext;
this.qual = quality;
} }
public String getID() { return id; }
public String getFileExt() { return ext; } public String getFileExt() { return ext; }
public float getQuality() { return qual; }
}; };
public abstract MapTile[] getTiles(Location l); public abstract MapTile[] getTiles(Location l);

View file

@ -9,8 +9,6 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import javax.imageio.ImageIO;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.World.Environment; import org.bukkit.World.Environment;
@ -23,9 +21,7 @@ import org.dynmap.MapManager;
import org.dynmap.TileHashManager; import org.dynmap.TileHashManager;
import org.dynmap.MapTile; import org.dynmap.MapTile;
import org.dynmap.MapType; import org.dynmap.MapType;
import org.dynmap.MapType.MapStep;
import org.dynmap.debug.Debug; import org.dynmap.debug.Debug;
import org.dynmap.kzedmap.KzedMap;
import org.dynmap.utils.DynmapBufferedImage; import org.dynmap.utils.DynmapBufferedImage;
import org.dynmap.utils.FileLockManager; import org.dynmap.utils.FileLockManager;
import org.dynmap.utils.MapChunkCache; import org.dynmap.utils.MapChunkCache;
@ -312,7 +308,7 @@ public class FlatMap extends MapType {
if(!outputFile.getParentFile().exists()) if(!outputFile.getParentFile().exists())
outputFile.getParentFile().mkdirs(); outputFile.getParentFile().mkdirs();
try { try {
FileLockManager.imageIOWrite(im.buf_img, "png", outputFile); FileLockManager.imageIOWrite(im.buf_img, ImageFormat.FORMAT_PNG, outputFile);
} catch (IOException e) { } catch (IOException e) {
Debug.error("Failed to save image: " + outputFile.getPath(), e); Debug.error("Failed to save image: " + outputFile.getPath(), e);
} catch (java.lang.NullPointerException e) { } catch (java.lang.NullPointerException e) {
@ -343,7 +339,7 @@ public class FlatMap extends MapType {
if(!dayfile.getParentFile().exists()) if(!dayfile.getParentFile().exists())
dayfile.getParentFile().mkdirs(); dayfile.getParentFile().mkdirs();
try { try {
FileLockManager.imageIOWrite(im_day.buf_img, "png", dayfile); FileLockManager.imageIOWrite(im_day.buf_img, ImageFormat.FORMAT_PNG, dayfile);
} catch (IOException e) { } catch (IOException e) {
Debug.error("Failed to save image: " + dayfile.getPath(), e); Debug.error("Failed to save image: " + dayfile.getPath(), e);
} catch (java.lang.NullPointerException e) { } catch (java.lang.NullPointerException e) {
@ -447,7 +443,7 @@ public class FlatMap extends MapType {
public String getPrefix() { public String getPrefix() {
return prefix; return prefix;
} }
/* Get maps rendered concurrently with this map in this world */ /* Get maps rendered concurrently with this map in this world */
public List<MapType> getMapsSharingRender(DynmapWorld w) { public List<MapType> getMapsSharingRender(DynmapWorld w) {
return Collections.singletonList((MapType)this); return Collections.singletonList((MapType)this);
@ -585,6 +581,7 @@ public class FlatMap extends MapType {
s(o, "mapzoomin", c.getInteger("mapzoomin", 3)); s(o, "mapzoomin", c.getInteger("mapzoomin", 3));
s(o, "mapzoomout", world.getExtraZoomOutLevels()); s(o, "mapzoomout", world.getExtraZoomOutLevels());
s(o, "compassview", "S"); /* Always from south */ s(o, "compassview", "S"); /* Always from south */
s(o, "image-format", ImageFormat.FORMAT_PNG.getFileExt());
a(worldObject, "maps", o); a(worldObject, "maps", o);
} }
} }

View file

@ -91,11 +91,17 @@ public class HDMap extends MapType {
} }
String fmt = configuration.getString("image-format", "png"); String fmt = configuration.getString("image-format", "png");
/* Only allow png or jpg */ /* Only allow png or jpg */
if(fmt.equals(IMGFORMAT_PNG)) for(ImageFormat f : ImageFormat.values()) {
if(fmt.equals(f.getID())) {
imgformat = f;
break;
}
}
if(imgformat == null) {
Log.severe("HDMap '"+name+"' set invalid image-format: " + fmt);
imgformat = ImageFormat.FORMAT_PNG; imgformat = ImageFormat.FORMAT_PNG;
else }
imgformat = ImageFormat.FORMAT_JPG; }
}
public HDShader getShader() { return shader; } public HDShader getShader() { return shader; }
public HDPerspective getPerspective() { return perspective; } public HDPerspective getPerspective() { return perspective; }

View file

@ -1041,7 +1041,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, fmt.getFileExt(), f); FileLockManager.imageIOWrite(im[i].buf_img, fmt, 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) {
@ -1074,7 +1074,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, fmt.getFileExt(), f); FileLockManager.imageIOWrite(dayim[i].buf_img, fmt, 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

@ -18,6 +18,7 @@ import org.dynmap.ColorScheme;
import org.dynmap.ConfigurationNode; import org.dynmap.ConfigurationNode;
import org.dynmap.DynmapWorld; import org.dynmap.DynmapWorld;
import org.dynmap.MapManager; import org.dynmap.MapManager;
import org.dynmap.MapType.ImageFormat;
import org.dynmap.TileHashManager; import org.dynmap.TileHashManager;
import org.dynmap.debug.Debug; import org.dynmap.debug.Debug;
import org.dynmap.utils.DynmapBufferedImage; import org.dynmap.utils.DynmapBufferedImage;
@ -276,7 +277,7 @@ public class DefaultTileRenderer implements MapTileRenderer {
if(!fname.getParentFile().exists()) if(!fname.getParentFile().exists())
fname.getParentFile().mkdirs(); fname.getParentFile().mkdirs();
try { try {
FileLockManager.imageIOWrite(img.buf_img, "png", fname); FileLockManager.imageIOWrite(img.buf_img, ImageFormat.FORMAT_PNG, fname);
} catch (IOException e) { } catch (IOException e) {
Debug.error("Failed to save image: " + fname.getPath(), e); Debug.error("Failed to save image: " + fname.getPath(), e);
} catch (java.lang.NullPointerException e) { } catch (java.lang.NullPointerException e) {
@ -306,7 +307,7 @@ public class DefaultTileRenderer implements MapTileRenderer {
if(!dfname.getParentFile().exists()) if(!dfname.getParentFile().exists())
dfname.getParentFile().mkdirs(); dfname.getParentFile().mkdirs();
try { try {
FileLockManager.imageIOWrite(img_day.buf_img, "png", dfname); FileLockManager.imageIOWrite(img_day.buf_img, ImageFormat.FORMAT_PNG, dfname);
} catch (IOException e) { } catch (IOException e) {
Debug.error("Failed to save image: " + dfname.getPath(), e); Debug.error("Failed to save image: " + dfname.getPath(), e);
} catch (java.lang.NullPointerException e) { } catch (java.lang.NullPointerException e) {
@ -390,7 +391,7 @@ public class DefaultTileRenderer implements MapTileRenderer {
zoomFile.getParentFile().mkdirs(); zoomFile.getParentFile().mkdirs();
try { try {
FileLockManager.imageIOWrite(zIm, "png", zoomFile); FileLockManager.imageIOWrite(zIm, ImageFormat.FORMAT_PNG, zoomFile);
Debug.debug("Saved zoom-out tile at " + zoomFile.getName()); Debug.debug("Saved zoom-out tile at " + zoomFile.getName());
} catch (IOException e) { } catch (IOException e) {
Debug.error("Failed to save zoom-out tile: " + zoomFile.getName(), e); Debug.error("Failed to save zoom-out tile: " + zoomFile.getName(), e);
@ -589,6 +590,7 @@ public class DefaultTileRenderer implements MapTileRenderer {
s(o, "mapzoomin", c.getInteger("mapzoomin", 2)); s(o, "mapzoomin", c.getInteger("mapzoomin", 2));
s(o, "mapzoomout", world.getExtraZoomOutLevels()+1); s(o, "mapzoomout", world.getExtraZoomOutLevels()+1);
s(o, "compassview", "SE"); /* Always from southeast */ s(o, "compassview", "SE"); /* Always from southeast */
s(o, "image-format", ImageFormat.FORMAT_PNG.getFileExt());
a(worldObject, "maps", o); a(worldObject, "maps", o);
} }
} }

View file

@ -1,14 +1,9 @@
package org.dynmap.kzedmap; package org.dynmap.kzedmap;
import org.dynmap.DynmapWorld; import org.dynmap.DynmapWorld;
import java.awt.image.BufferedImage;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -19,16 +14,8 @@ 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.MapType;
import org.dynmap.MapType.MapStep;
import org.dynmap.utils.DynmapBufferedImage;
import org.dynmap.utils.MapChunkCache; import org.dynmap.utils.MapChunkCache;
import org.dynmap.utils.Vector3D;
import org.json.simple.JSONObject; import org.json.simple.JSONObject;
import java.awt.image.DataBufferInt;
import java.awt.image.DataBuffer;
import java.awt.image.WritableRaster;
import java.awt.image.ColorModel;
import java.awt.image.Raster;
public class KzedMap extends MapType { public class KzedMap extends MapType {
protected static final Logger log = Logger.getLogger("Minecraft"); protected static final Logger log = Logger.getLogger("Minecraft");

View file

@ -1,17 +1,22 @@
package org.dynmap.utils; package org.dynmap.utils;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.RandomAccessFile; import java.io.RandomAccessFile;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.awt.image.DirectColorModel; import java.awt.image.DirectColorModel;
import java.awt.image.WritableRaster; import java.awt.image.WritableRaster;
import java.io.IOException; import java.io.IOException;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
import org.dynmap.Log; import org.dynmap.Log;
import org.dynmap.MapType.ImageFormat;
import org.dynmap.debug.Debug; import org.dynmap.debug.Debug;
/** /**
* Implements soft-locks for prevent concurrency issues with file updates * Implements soft-locks for prevent concurrency issues with file updates
@ -141,13 +146,13 @@ public class FileLockManager {
/** /**
* Wrapper for IOImage.write - implements retries for busy files * Wrapper for IOImage.write - implements retries for busy files
*/ */
public static void imageIOWrite(BufferedImage img, String type, File fname) throws IOException { public static void imageIOWrite(BufferedImage img, ImageFormat fmt, File fname) throws IOException {
int retrycnt = 0; int retrycnt = 0;
boolean done = false; boolean done = false;
byte[] rslt; byte[] rslt;
synchronized(baos_lock) { synchronized(baos_lock) {
baos.reset(); baos.reset();
if(type.equals("jpg")) { if(fmt.getFileExt().equals("jpg")) {
WritableRaster raster = img.getRaster(); WritableRaster raster = img.getRaster();
WritableRaster newRaster = raster.createWritableChild(0, 0, img.getWidth(), WritableRaster newRaster = raster.createWritableChild(0, 0, img.getWidth(),
img.getHeight(), 0, 0, new int[] {0, 1, 2}); img.getHeight(), 0, 0, new int[] {0, 1, 2});
@ -156,11 +161,31 @@ public class FileLockManager {
cm.getRedMask(), cm.getGreenMask(), cm.getBlueMask()); cm.getRedMask(), cm.getGreenMask(), cm.getBlueMask());
// now create the new buffer that is used ot write the image: // now create the new buffer that is used ot write the image:
BufferedImage rgbBuffer = new BufferedImage(newCM, newRaster, false, null); BufferedImage rgbBuffer = new BufferedImage(newCM, newRaster, false, null);
ImageIO.write(rgbBuffer, type, baos); /* Write to byte array stream - prevent bogus I/O errors */
// Find a jpeg writer
ImageWriter writer = null;
Iterator iter = ImageIO.getImageWritersByFormatName("jpg");
if (iter.hasNext()) {
writer = (ImageWriter)iter.next();
}
if(writer == null) {
Log.severe("No JPEG ENCODER - Java VM does not support JPEG encoding");
return;
}
ImageWriteParam iwp = writer.getDefaultWriteParam();
iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
iwp.setCompressionQuality(fmt.getQuality());
ImageOutputStream ios = ImageIO.createImageOutputStream(baos);
writer.setOutput(ios);
writer.write(null, new IIOImage(rgbBuffer, null, null), iwp);
writer.dispose();
rgbBuffer.flush(); rgbBuffer.flush();
} }
else { else {
ImageIO.write(img, type, baos); /* Write to byte array stream - prevent bogus I/O errors */ ImageIO.write(img, fmt.getFileExt(), baos); /* Write to byte array stream - prevent bogus I/O errors */
} }
rslt = baos.toByteArray(); rslt = baos.toByteArray();
} }