* NEW: Added stretch and cover image resizing modes

This commit is contained in:
Adrien Prokopowicz 2018-02-24 04:09:40 +01:00
parent 47fb9737cb
commit 4653008e5a
No known key found for this signature in database
GPG Key ID: 752A4E1D70CABBE3
3 changed files with 123 additions and 58 deletions

View File

@ -21,6 +21,7 @@ package fr.moribus.imageonmap.commands.maptool;
import fr.moribus.imageonmap.Permissions;
import fr.moribus.imageonmap.commands.IoMCommand;
import fr.moribus.imageonmap.image.ImageRendererExecutor;
import fr.moribus.imageonmap.image.ImageUtils;
import fr.moribus.imageonmap.map.ImageMap;
import fr.zcraft.zlib.components.commands.CommandException;
import fr.zcraft.zlib.components.commands.CommandInfo;
@ -40,7 +41,7 @@ public class NewCommand extends IoMCommand
protected void run() throws CommandException
{
final Player player = playerSender();
boolean scaling = false;
ImageUtils.ScalingType scaling = ImageUtils.ScalingType.NONE;
URL url;
int width = 0, height = 0;
@ -58,17 +59,21 @@ public class NewCommand extends IoMCommand
if(args.length >= 2)
{
if(args[1].equals("resize")) {
scaling = true;
if(args.length >= 4) {
width = Integer.parseInt(args[2]);
height = Integer.parseInt(args[3]);
}
if(args.length >= 4) {
width = Integer.parseInt(args[2]);
height = Integer.parseInt(args[3]);
}
switch(args[1]) {
case "resize": scaling = ImageUtils.ScalingType.CONTAINED; break;
case "resize-stretched": scaling = ImageUtils.ScalingType.STRETCHED; break;
case "resize-covered": scaling = ImageUtils.ScalingType.COVERED; break;
default: throwInvalidArgument(I.t("Invalid Stretching mode.")); break;
}
}
info(I.t("Rendering..."));
ImageRendererExecutor.Render(url, scaling, player.getUniqueId(), width, height, new WorkerCallback<ImageMap>()
ImageRendererExecutor.render(url, scaling, player.getUniqueId(), width, height, new WorkerCallback<ImageMap>()
{
@Override
public void finished(ImageMap result)

View File

@ -27,7 +27,6 @@ import fr.zcraft.zlib.components.worker.WorkerCallback;
import fr.zcraft.zlib.components.worker.WorkerRunnable;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
@ -42,7 +41,7 @@ import java.util.concurrent.Future;
@WorkerAttributes (name = "Image Renderer", queriesMainThread = true)
public class ImageRendererExecutor extends Worker
{
static public void Render(final URL url, final boolean scaling, final UUID playerUUID, final int width, final int height, WorkerCallback<ImageMap> callback)
static public void render(final URL url, final ImageUtils.ScalingType scaling, final UUID playerUUID, final int width, final int height, WorkerCallback<ImageMap> callback)
{
submitQuery(new WorkerRunnable<ImageMap>()
{
@ -65,24 +64,20 @@ public class ImageRendererExecutor extends Worker
if (image == null) throw new IOException(I.t("The given URL is not a valid image"));
if (scaling) return RenderScaled(image, playerUUID, width, height);
else return RenderPoster(image, playerUUID);
if(scaling != ImageUtils.ScalingType.NONE && height <= 1 && width <= 1) {
return renderSingle(scaling.resize(image, ImageMap.WIDTH, ImageMap.HEIGHT), playerUUID);
}
final BufferedImage resizedImage = scaling.resize(image, ImageMap.WIDTH * width, ImageMap.HEIGHT * height);
return renderPoster(resizedImage, playerUUID);
}
}, callback);
}
static private ImageMap RenderScaled(final BufferedImage image, final UUID playerUUID, final int width, final int height) throws Throwable {
if(height <= 1 && width <= 1) {
return RenderSingle(image, playerUUID);
}
final BufferedImage finalImage = ResizeImage(image, ImageMap.WIDTH * width, ImageMap.HEIGHT * height);
return RenderPoster(finalImage, playerUUID);
}
static private ImageMap RenderSingle(final BufferedImage image, final UUID playerUUID) throws Throwable
static private ImageMap renderSingle(final BufferedImage image, final UUID playerUUID) throws Throwable
{
MapManager.checkMapLimit(1, playerUUID);
Future<Short> futureMapID = submitToMainThread(new Callable<Short>()
final Future<Short> futureMapID = submitToMainThread(new Callable<Short>()
{
@Override
public Short call() throws Exception
@ -90,27 +85,24 @@ public class ImageRendererExecutor extends Worker
return MapManager.getNewMapsIds(1)[0];
}
});
final BufferedImage finalImage = ResizeImage(image, ImageMap.WIDTH, ImageMap.HEIGHT);
final short mapID = futureMapID.get();
ImageIOExecutor.saveImage(mapID, finalImage);
ImageIOExecutor.saveImage(mapID, image);
submitToMainThread(new Callable<Void>()
{
@Override
public Void call() throws Exception
{
Renderer.installRenderer(finalImage, mapID);
Renderer.installRenderer(image, mapID);
return null;
}
});
return MapManager.createMap(playerUUID, mapID);
}
static private ImageMap RenderPoster(final BufferedImage image, final UUID playerUUID) throws Throwable
static private ImageMap renderPoster(final BufferedImage image, final UUID playerUUID) throws Throwable
{
final PosterImage poster = new PosterImage(image);
final int mapCount = poster.getImagesCount();
@ -144,33 +136,4 @@ public class ImageRendererExecutor extends Worker
return MapManager.createMap(poster, playerUUID, mapsIDs);
}
static private BufferedImage ResizeImage(BufferedImage source, int destinationW, int destinationH)
{
float ratioW = (float)destinationW / (float)source.getWidth();
float ratioH = (float)destinationH / (float)source.getHeight();
int finalW, finalH;
if(ratioW < ratioH)
{
finalW = destinationW;
finalH = (int)(source.getHeight() * ratioW);
}
else
{
finalW = (int)(source.getWidth() * ratioH);
finalH = destinationH;
}
int x, y;
x = (destinationW - finalW) / 2;
y = (destinationH - finalH) / 2;
BufferedImage newImage = new BufferedImage(destinationW, destinationH, BufferedImage.TYPE_INT_ARGB);
Graphics graphics = newImage.getGraphics();
graphics.drawImage(source, x, y, finalW, finalH, null);
graphics.dispose();
return newImage;
}
}

View File

@ -0,0 +1,97 @@
package fr.moribus.imageonmap.image;
import java.awt.*;
import java.awt.image.BufferedImage;
/**
* Various image-related utilities
*/
public class ImageUtils {
public enum ScalingType {
NONE,
CONTAINED,
COVERED,
STRETCHED,
;
public BufferedImage resize(BufferedImage source, int destinationW, int destinationH) {
switch(this) {
case CONTAINED: return ImageUtils.resize(source, destinationW, destinationH, false);
case COVERED: return ImageUtils.resize(source, destinationW, destinationH, true);
case STRETCHED: return resizeStretched(source, destinationW, destinationH);
default: return source;
}
}
}
/**
* Generates a resized buffer of the given source
* @param source
* @param destinationW
* @param destinationH
* @return
*/
static private BufferedImage resize(BufferedImage source, int destinationW, int destinationH, boolean covered)
{
float ratioW = (float)destinationW / (float)source.getWidth();
float ratioH = (float)destinationH / (float)source.getHeight();
int finalW, finalH;
int x, y;
if(covered ? ratioW > ratioH : ratioW < ratioH)
{
finalW = destinationW;
finalH = (int)(source.getHeight() * ratioW);
}
else
{
finalW = (int)(source.getWidth() * ratioH);
finalH = destinationH;
}
x = (destinationW - finalW) / 2;
y = (destinationH - finalH) / 2;
return drawImage(source,
destinationW, destinationH,
x, y, finalW, finalH);
}
/**
*
* @param source
* @param destinationW
* @param destinationH
* @return
*/
static private BufferedImage resizeStretched(BufferedImage source, int destinationW, int destinationH) {
return drawImage(source,
destinationW, destinationH,
0, 0, destinationW, destinationH);
}
/**
* Draws the source image on a new buffer, and returns it.
* The source buffer can be drawn at any size and position in the new buffer.
* @param source The source buffer to draw
* @param bufferW The width of the new buffer
* @param bufferH The height of the new buffer
* @param posX The X position of the source buffer
* @param posY The Y position of the source buffer
* @param sourceW The width of the source buffer
* @param sourceH The height of the source buffer
* @return The new buffer, with the source buffer drawn on it
*/
static private BufferedImage drawImage(BufferedImage source,
int bufferW, int bufferH,
int posX, int posY,
int sourceW, int sourceH) {
BufferedImage newImage = new BufferedImage(bufferW, bufferH, BufferedImage.TYPE_INT_ARGB);
Graphics graphics = newImage.getGraphics();
graphics.drawImage(source, posX, posY, sourceW, sourceH, null);
graphics.dispose();
return newImage;
}
}