diff --git a/src/main/java/org/dynmap/DynmapWorld.java b/src/main/java/org/dynmap/DynmapWorld.java index 73238eb2..0b35544e 100644 --- a/src/main/java/org/dynmap/DynmapWorld.java +++ b/src/main/java/org/dynmap/DynmapWorld.java @@ -6,7 +6,6 @@ import java.util.List; import org.bukkit.World; import org.bukkit.Location; import org.dynmap.debug.Debug; -import org.dynmap.kzedmap.KzedMap; import org.dynmap.utils.DynmapBufferedImage; import org.dynmap.utils.FileLockManager; import org.dynmap.utils.MapChunkCache; @@ -447,7 +446,7 @@ public class DynmapWorld { try { if(!zf.getParentFile().exists()) 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()); } catch (IOException e) { Debug.error("Failed to save zoom-out tile: " + zf.getName(), e); diff --git a/src/main/java/org/dynmap/MapType.java b/src/main/java/org/dynmap/MapType.java index fe9ddd95..49e61553 100644 --- a/src/main/java/org/dynmap/MapType.java +++ b/src/main/java/org/dynmap/MapType.java @@ -7,14 +7,26 @@ import org.json.simple.JSONObject; public abstract class MapType { public enum ImageFormat { - FORMAT_PNG("png"), - FORMAT_JPG("jpg"); - + FORMAT_PNG("png", "png", 0.0f), + 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; - ImageFormat(String ext) { + float qual; + + ImageFormat(String id, String ext, float quality) { + this.id = id; this.ext = ext; + this.qual = quality; } + public String getID() { return id; } public String getFileExt() { return ext; } + public float getQuality() { return qual; } }; public abstract MapTile[] getTiles(Location l); diff --git a/src/main/java/org/dynmap/flat/FlatMap.java b/src/main/java/org/dynmap/flat/FlatMap.java index 8d9a61af..555e5030 100644 --- a/src/main/java/org/dynmap/flat/FlatMap.java +++ b/src/main/java/org/dynmap/flat/FlatMap.java @@ -9,8 +9,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import javax.imageio.ImageIO; - import org.bukkit.Location; import org.bukkit.World; import org.bukkit.World.Environment; @@ -23,9 +21,7 @@ import org.dynmap.MapManager; import org.dynmap.TileHashManager; import org.dynmap.MapTile; import org.dynmap.MapType; -import org.dynmap.MapType.MapStep; import org.dynmap.debug.Debug; -import org.dynmap.kzedmap.KzedMap; import org.dynmap.utils.DynmapBufferedImage; import org.dynmap.utils.FileLockManager; import org.dynmap.utils.MapChunkCache; @@ -312,7 +308,7 @@ public class FlatMap extends MapType { if(!outputFile.getParentFile().exists()) outputFile.getParentFile().mkdirs(); try { - FileLockManager.imageIOWrite(im.buf_img, "png", outputFile); + FileLockManager.imageIOWrite(im.buf_img, ImageFormat.FORMAT_PNG, outputFile); } catch (IOException e) { Debug.error("Failed to save image: " + outputFile.getPath(), e); } catch (java.lang.NullPointerException e) { @@ -343,7 +339,7 @@ public class FlatMap extends MapType { if(!dayfile.getParentFile().exists()) dayfile.getParentFile().mkdirs(); try { - FileLockManager.imageIOWrite(im_day.buf_img, "png", dayfile); + FileLockManager.imageIOWrite(im_day.buf_img, ImageFormat.FORMAT_PNG, dayfile); } catch (IOException e) { Debug.error("Failed to save image: " + dayfile.getPath(), e); } catch (java.lang.NullPointerException e) { @@ -447,7 +443,7 @@ public class FlatMap extends MapType { public String getPrefix() { return prefix; } - + /* Get maps rendered concurrently with this map in this world */ public List getMapsSharingRender(DynmapWorld w) { return Collections.singletonList((MapType)this); @@ -585,6 +581,7 @@ public class FlatMap extends MapType { s(o, "mapzoomin", c.getInteger("mapzoomin", 3)); s(o, "mapzoomout", world.getExtraZoomOutLevels()); s(o, "compassview", "S"); /* Always from south */ + s(o, "image-format", ImageFormat.FORMAT_PNG.getFileExt()); a(worldObject, "maps", o); } } diff --git a/src/main/java/org/dynmap/hdmap/HDMap.java b/src/main/java/org/dynmap/hdmap/HDMap.java index 1af608fb..73f1fbd5 100644 --- a/src/main/java/org/dynmap/hdmap/HDMap.java +++ b/src/main/java/org/dynmap/hdmap/HDMap.java @@ -91,11 +91,17 @@ public class HDMap extends MapType { } String fmt = configuration.getString("image-format", "png"); /* 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; - else - imgformat = ImageFormat.FORMAT_JPG; - } + } + } public HDShader getShader() { return shader; } public HDPerspective getPerspective() { return perspective; } diff --git a/src/main/java/org/dynmap/hdmap/IsoHDPerspective.java b/src/main/java/org/dynmap/hdmap/IsoHDPerspective.java index 837b14c1..6b6ad990 100644 --- a/src/main/java/org/dynmap/hdmap/IsoHDPerspective.java +++ b/src/main/java/org/dynmap/hdmap/IsoHDPerspective.java @@ -1041,7 +1041,7 @@ public class IsoHDPerspective implements HDPerspective { if(!f.getParentFile().exists()) f.getParentFile().mkdirs(); try { - FileLockManager.imageIOWrite(im[i].buf_img, fmt.getFileExt(), f); + FileLockManager.imageIOWrite(im[i].buf_img, fmt, f); } catch (IOException e) { Debug.error("Failed to save image: " + f.getPath(), e); } catch (java.lang.NullPointerException e) { @@ -1074,7 +1074,7 @@ public class IsoHDPerspective implements HDPerspective { if(!f.getParentFile().exists()) f.getParentFile().mkdirs(); try { - FileLockManager.imageIOWrite(dayim[i].buf_img, fmt.getFileExt(), f); + FileLockManager.imageIOWrite(dayim[i].buf_img, fmt, f); } catch (IOException e) { Debug.error("Failed to save image: " + f.getPath(), e); } catch (java.lang.NullPointerException e) { diff --git a/src/main/java/org/dynmap/kzedmap/DefaultTileRenderer.java b/src/main/java/org/dynmap/kzedmap/DefaultTileRenderer.java index 8e7d3bbd..8e948302 100644 --- a/src/main/java/org/dynmap/kzedmap/DefaultTileRenderer.java +++ b/src/main/java/org/dynmap/kzedmap/DefaultTileRenderer.java @@ -18,6 +18,7 @@ import org.dynmap.ColorScheme; import org.dynmap.ConfigurationNode; import org.dynmap.DynmapWorld; import org.dynmap.MapManager; +import org.dynmap.MapType.ImageFormat; import org.dynmap.TileHashManager; import org.dynmap.debug.Debug; import org.dynmap.utils.DynmapBufferedImage; @@ -276,7 +277,7 @@ public class DefaultTileRenderer implements MapTileRenderer { if(!fname.getParentFile().exists()) fname.getParentFile().mkdirs(); try { - FileLockManager.imageIOWrite(img.buf_img, "png", fname); + FileLockManager.imageIOWrite(img.buf_img, ImageFormat.FORMAT_PNG, fname); } catch (IOException e) { Debug.error("Failed to save image: " + fname.getPath(), e); } catch (java.lang.NullPointerException e) { @@ -306,7 +307,7 @@ public class DefaultTileRenderer implements MapTileRenderer { if(!dfname.getParentFile().exists()) dfname.getParentFile().mkdirs(); try { - FileLockManager.imageIOWrite(img_day.buf_img, "png", dfname); + FileLockManager.imageIOWrite(img_day.buf_img, ImageFormat.FORMAT_PNG, dfname); } catch (IOException e) { Debug.error("Failed to save image: " + dfname.getPath(), e); } catch (java.lang.NullPointerException e) { @@ -390,7 +391,7 @@ public class DefaultTileRenderer implements MapTileRenderer { zoomFile.getParentFile().mkdirs(); try { - FileLockManager.imageIOWrite(zIm, "png", zoomFile); + FileLockManager.imageIOWrite(zIm, ImageFormat.FORMAT_PNG, zoomFile); Debug.debug("Saved zoom-out tile at " + zoomFile.getName()); } catch (IOException 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, "mapzoomout", world.getExtraZoomOutLevels()+1); s(o, "compassview", "SE"); /* Always from southeast */ + s(o, "image-format", ImageFormat.FORMAT_PNG.getFileExt()); a(worldObject, "maps", o); } } diff --git a/src/main/java/org/dynmap/kzedmap/KzedMap.java b/src/main/java/org/dynmap/kzedmap/KzedMap.java index b15c3afe..a6689e01 100644 --- a/src/main/java/org/dynmap/kzedmap/KzedMap.java +++ b/src/main/java/org/dynmap/kzedmap/KzedMap.java @@ -1,14 +1,9 @@ package org.dynmap.kzedmap; import org.dynmap.DynmapWorld; -import java.awt.image.BufferedImage; import java.io.File; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; import java.util.List; import java.util.logging.Logger; @@ -19,16 +14,8 @@ import org.dynmap.Log; import org.dynmap.MapManager; import org.dynmap.MapTile; import org.dynmap.MapType; -import org.dynmap.MapType.MapStep; -import org.dynmap.utils.DynmapBufferedImage; import org.dynmap.utils.MapChunkCache; -import org.dynmap.utils.Vector3D; 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 { protected static final Logger log = Logger.getLogger("Minecraft"); diff --git a/src/main/java/org/dynmap/utils/FileLockManager.java b/src/main/java/org/dynmap/utils/FileLockManager.java index f257361c..94aa12b7 100644 --- a/src/main/java/org/dynmap/utils/FileLockManager.java +++ b/src/main/java/org/dynmap/utils/FileLockManager.java @@ -1,17 +1,22 @@ package org.dynmap.utils; import java.io.ByteArrayOutputStream; import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; import java.io.RandomAccessFile; import java.util.HashMap; +import java.util.Iterator; import java.awt.image.BufferedImage; import java.awt.image.DirectColorModel; import java.awt.image.WritableRaster; import java.io.IOException; + +import javax.imageio.IIOImage; import javax.imageio.ImageIO; +import javax.imageio.ImageWriteParam; +import javax.imageio.ImageWriter; +import javax.imageio.stream.ImageOutputStream; import org.dynmap.Log; +import org.dynmap.MapType.ImageFormat; import org.dynmap.debug.Debug; /** * 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 */ - 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; boolean done = false; byte[] rslt; synchronized(baos_lock) { baos.reset(); - if(type.equals("jpg")) { + if(fmt.getFileExt().equals("jpg")) { WritableRaster raster = img.getRaster(); WritableRaster newRaster = raster.createWritableChild(0, 0, img.getWidth(), img.getHeight(), 0, 0, new int[] {0, 1, 2}); @@ -156,11 +161,31 @@ public class FileLockManager { 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 */ + + // 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(); } 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(); }