From 242a137411392cdb1b84c52ab7f0b7309ca2dce7 Mon Sep 17 00:00:00 2001 From: ptaillandier Date: Tue, 29 Oct 2024 11:05:02 +0700 Subject: [PATCH 1/3] add an operator to send a GAMAimage to websocket using base64 --- .../gama/core/kernel/root/PlatformAgent.java | 6 ++- .../runtime/server/GamaServerMessage.java | 5 +++ .../gama/extension/image/ImageOperators.java | 39 +++++++++++++++++++ 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/gama.core/src/gama/core/kernel/root/PlatformAgent.java b/gama.core/src/gama/core/kernel/root/PlatformAgent.java index 31a22146c2..ce2c1bd095 100644 --- a/gama.core/src/gama/core/kernel/root/PlatformAgent.java +++ b/gama.core/src/gama/core/kernel/root/PlatformAgent.java @@ -534,6 +534,10 @@ public Object sendMessageThroughServer(final IScope scope) { * @date 3 nov. 2023 */ public void sendMessage(final IScope scope, final Object message) { + sendMessage(scope,GamaServerMessage.Type.SimulationOutput); + } + + public void sendMessage(final IScope scope, final Object message, final gama.core.runtime.server.GamaServerMessage.Type type) { try { var socket = scope.getServerConfiguration().socket(); // try to get the socket in platformAgent if the request is too soon before agent.schedule() @@ -543,7 +547,7 @@ public void sendMessage(final IScope scope, final Object message) { + message); return; } - socket.send(jsonEncoder.valueOf(new GamaServerMessage(GamaServerMessage.Type.SimulationOutput, message, + socket.send(jsonEncoder.valueOf(new GamaServerMessage(type, message, scope.getServerConfiguration().expId())).toString()); } catch (Exception ex) { ex.printStackTrace(); diff --git a/gama.core/src/gama/core/runtime/server/GamaServerMessage.java b/gama.core/src/gama/core/runtime/server/GamaServerMessage.java index b27805f03c..22b73021b0 100644 --- a/gama.core/src/gama/core/runtime/server/GamaServerMessage.java +++ b/gama.core/src/gama/core/runtime/server/GamaServerMessage.java @@ -60,6 +60,11 @@ public enum Type { */ SimulationOutput, + /** + * Used to send a image of a display of a running simulation + */ + SimulationImage, + /** * Used to describe the content printed using the debug statement in a running simulation */ diff --git a/gama.extension.image/src/gama/extension/image/ImageOperators.java b/gama.extension.image/src/gama/extension/image/ImageOperators.java index 36a815e4e8..6f185ded74 100644 --- a/gama.extension.image/src/gama/extension/image/ImageOperators.java +++ b/gama.extension.image/src/gama/extension/image/ImageOperators.java @@ -23,6 +23,13 @@ import java.awt.image.ColorModel; import java.awt.image.RescaleOp; import java.awt.image.WritableRaster; +import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.util.Base64; + +import javax.imageio.ImageIO; import gama.annotations.precompiler.GamlAnnotations.doc; import gama.annotations.precompiler.GamlAnnotations.example; @@ -33,11 +40,14 @@ import gama.core.common.interfaces.IDisplaySurface; import gama.core.common.interfaces.IKeyword; import gama.core.kernel.experiment.ITopLevelAgent; +import gama.core.kernel.root.PlatformAgent; import gama.core.metamodel.agent.IAgent; import gama.core.metamodel.shape.GamaPoint; import gama.core.outputs.IOutput; import gama.core.outputs.LayeredDisplayOutput; +import gama.core.runtime.GAMA; import gama.core.runtime.IScope; +import gama.core.runtime.server.GamaServerMessage; import gama.core.util.GamaColor; import gama.core.util.matrix.GamaIntMatrix; import gama.core.util.matrix.IMatrix; @@ -157,6 +167,35 @@ public static GamaImage snapshot(final IScope scope, final IAgent exp, final Str IDisplaySurface surface = ldo.getSurface(); return SnapshotMaker.getInstance().captureImage(surface, customDimensions); } + + public static String imgToBase64String(final GamaImage img, final String formatName) + { + final ByteArrayOutputStream os = new ByteArrayOutputStream(); + + try + { + ImageIO.write(img, formatName, os); + return Base64.getEncoder().encodeToString(os.toByteArray()); + } + catch (final IOException ioe) + { + throw new UncheckedIOException(ioe); + } + } + + @operator ( + value = "send_image_to_websocket", + can_be_const = false) + @doc ("Takes a snapshot of the display whose name is passed in parameter and returns the image. " + + "The search for the display begins in the agent passed in parameter and, if not found, its experiment. A custom size (a point representing width x height) can be given " + + "Returns nil if no display can be found or the snapshot cannot be taken.") + @no_test + public static GamaImage sendImageWebsocket(final IScope scope, final GamaImage image) { + PlatformAgent pa = GAMA.getPlatformAgent(); + + pa.sendMessage(scope, imgToBase64String(image, "png"), GamaServerMessage.Type.SimulationImage); + return image; + } /** * Grayscale. From 9cb044b3fadf1b9e50948bb3ed49fc15d126c16b Mon Sep 17 00:00:00 2001 From: ptaillandier Date: Tue, 29 Oct 2024 11:52:51 +0700 Subject: [PATCH 2/3] fixes an infinite loop error and the doc --- gama.core/src/gama/core/kernel/root/PlatformAgent.java | 2 +- .../src/gama/extension/image/ImageOperators.java | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/gama.core/src/gama/core/kernel/root/PlatformAgent.java b/gama.core/src/gama/core/kernel/root/PlatformAgent.java index ce2c1bd095..e74a2420e4 100644 --- a/gama.core/src/gama/core/kernel/root/PlatformAgent.java +++ b/gama.core/src/gama/core/kernel/root/PlatformAgent.java @@ -534,7 +534,7 @@ public Object sendMessageThroughServer(final IScope scope) { * @date 3 nov. 2023 */ public void sendMessage(final IScope scope, final Object message) { - sendMessage(scope,GamaServerMessage.Type.SimulationOutput); + sendMessage(scope, message,GamaServerMessage.Type.SimulationOutput); } public void sendMessage(final IScope scope, final Object message, final gama.core.runtime.server.GamaServerMessage.Type type) { diff --git a/gama.extension.image/src/gama/extension/image/ImageOperators.java b/gama.extension.image/src/gama/extension/image/ImageOperators.java index 6f185ded74..461aaaaf89 100644 --- a/gama.extension.image/src/gama/extension/image/ImageOperators.java +++ b/gama.extension.image/src/gama/extension/image/ImageOperators.java @@ -186,9 +186,7 @@ public static String imgToBase64String(final GamaImage img, final String formatN @operator ( value = "send_image_to_websocket", can_be_const = false) - @doc ("Takes a snapshot of the display whose name is passed in parameter and returns the image. " - + "The search for the display begins in the agent passed in parameter and, if not found, its experiment. A custom size (a point representing width x height) can be given " - + "Returns nil if no display can be found or the snapshot cannot be taken.") + @doc ("Send the given image to the websocket using Base64.") @no_test public static GamaImage sendImageWebsocket(final IScope scope, final GamaImage image) { PlatformAgent pa = GAMA.getPlatformAgent(); From d81e988045ed8d82ddc0893647f69cc540d30e07 Mon Sep 17 00:00:00 2001 From: Baptiste Lesquoy Date: Mon, 4 Nov 2024 21:22:52 +0700 Subject: [PATCH 3/3] [GS] adds the possibility to set the format for send_image_to_websocket --- .../gama/extension/image/ImageOperators.java | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/gama.extension.image/src/gama/extension/image/ImageOperators.java b/gama.extension.image/src/gama/extension/image/ImageOperators.java index 461aaaaf89..ff5eb0317f 100644 --- a/gama.extension.image/src/gama/extension/image/ImageOperators.java +++ b/gama.extension.image/src/gama/extension/image/ImageOperators.java @@ -186,15 +186,28 @@ public static String imgToBase64String(final GamaImage img, final String formatN @operator ( value = "send_image_to_websocket", can_be_const = false) - @doc ("Send the given image to the websocket using Base64.") + @doc ("Send the given image to the websocket in Base64 using the given format.") @no_test - public static GamaImage sendImageWebsocket(final IScope scope, final GamaImage image) { + public static GamaImage sendImageWebsocket(final IScope scope, final GamaImage image, final String format) { + PlatformAgent pa = GAMA.getPlatformAgent(); - pa.sendMessage(scope, imgToBase64String(image, "png"), GamaServerMessage.Type.SimulationImage); + pa.sendMessage(scope, imgToBase64String(image, format), GamaServerMessage.Type.SimulationImage); return image; } + + + @operator ( + value = "send_image_to_websocket", + can_be_const = false) + @doc ("Send the given image to the websocket using Base64 assuming the format is png.") + @no_test + public static GamaImage sendImageWebsocket(final IScope scope, final GamaImage image) { + return sendImageWebsocket(scope, image, "png"); + } + + /** * Grayscale. *