Allow configuring background color of GifExporter

This commit is contained in:
martin 2022-10-04 20:56:57 +02:00
parent 394386df52
commit 9bb0e35f3c
5 changed files with 59 additions and 37 deletions

View File

@ -36,43 +36,52 @@ public abstract class AbstractImageExporter implements AWTImageExporter {
protected AtomicInteger numberOfSkippedImages = new AtomicInteger(0);
protected AtomicInteger numberOfSavedImages = new AtomicInteger(0);
protected int frameRateMs;
protected int frameDelayMs;
protected boolean debug = false;
// protected int numberOfSubmittedImages = 0;
public AbstractImageExporter(int frameRateMs) {
this.frameRateMs = frameRateMs;
public AbstractImageExporter(int frameDelayMs) {
this.frameDelayMs = frameDelayMs;
this.timer = new TicToc();
this.executor = Executors.newSingleThreadExecutor();
}
@Override
public void export(BufferedImage image) {
// init timer
if (previousImage == null) {
// ---------------------------------------------------------------
// init timer
timer.tic();
scheduleImageExport(image);
}
// or check time spent since image changed
else {
// ---------------------------------------------------------------
// ... or check time spent since image changed
timer.toc();
double elapsed = timer.elapsedMilisecond();
// System.out.println("ELAPSED : " + elapsed);
int elapsedGifFrames = (int) Math.floor(elapsed / frameRateMs);
int elapsedGifFrames = (int) Math.floor(elapsed / frameDelayMs);
// Image pops too early
// ---------------------------------------------------------------
// Image pops too early, skip it
if (elapsedGifFrames == 0) {
previousImage = image;
numberOfSkippedImages.incrementAndGet();
}
// Image is in [gifFrameRateMs; 2*gifFrameRateMs]
// ---------------------------------------------------------------
// Image is in [gifFrameRateMs; 2*gifFrameRateMs], schedule export
else if (elapsedGifFrames == 1) {
scheduleImageExport(previousImage);
@ -80,7 +89,13 @@ public abstract class AbstractImageExporter implements AWTImageExporter {
timer.tic();
} else {
}
// ---------------------------------------------------------------
// Time as elapsed for more than 1 image, schedule multiple export
// of the same image to fill the gap
else {
for (int i = 0; i < elapsedGifFrames; i++) {
scheduleImageExport(previousImage);
}
@ -132,21 +147,12 @@ public abstract class AbstractImageExporter implements AWTImageExporter {
return true;
}
} catch (InterruptedException e1) {
e1.printStackTrace();
return false;
}
}
/**
* Wait for the process to finish and return when done.
*
* @return
*
* public boolean awaitTermination() { return terminate(0, null); }
*/
protected void scheduleImageExport(BufferedImage image) {
scheduleImageExport(image, false);
}
@ -160,8 +166,6 @@ public abstract class AbstractImageExporter implements AWTImageExporter {
@Override
public void run() {
numberOfPendingImages.incrementAndGet();
// System.out.println("Adding image to GIF (pending tasks " + pendingTasks.get() + ")");
// pendingTasks.incrementAndGet();
@ -179,7 +183,6 @@ public abstract class AbstractImageExporter implements AWTImageExporter {
catch(Exception e) {
throw new RuntimeException(e);
}
numberOfPendingImages.decrementAndGet();
}
@ -202,10 +205,6 @@ public abstract class AbstractImageExporter implements AWTImageExporter {
return numberSubmittedImages;
}
public AtomicInteger getNumberOfPendingImages() {
return numberOfPendingImages;
}
public AtomicInteger getNumberOfSkippedImages() {
return numberOfSkippedImages;
}

View File

@ -4,6 +4,8 @@ import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import org.jzy3d.colors.AWTColor;
import org.jzy3d.colors.Color;
import org.jzy3d.io.AWTImageExporter;
import org.jzy3d.io.AbstractImageExporter;
import org.jzy3d.maths.TicToc;
@ -23,7 +25,8 @@ public class GifExporter extends AbstractImageExporter implements AWTImageExport
protected File outputFile;
protected AnimatedGifEncoder encoder;
protected boolean applyWhiteBackground = true;
protected Color backgroundColor = null;
// protected boolean applyWhiteBackground = true;
protected TicToc timer = new TicToc();
@ -31,8 +34,8 @@ public class GifExporter extends AbstractImageExporter implements AWTImageExport
this(outputFile, DEFAULT_FRAME_RATE_MS); // 1 frame per sec
}
public GifExporter(File outputFile, int gifFrameRateMs) {
super(gifFrameRateMs);
public GifExporter(File outputFile, int gifFrameDelayMs) {
super(gifFrameDelayMs);
this.outputFile = outputFile;
@ -42,7 +45,7 @@ public class GifExporter extends AbstractImageExporter implements AWTImageExport
this.encoder = new AnimatedGifEncoder();
this.encoder.start(outputFile.getAbsolutePath());
this.encoder.setDelay(gifFrameRateMs);
this.encoder.setDelay(gifFrameDelayMs);
this.encoder.setRepeat(1000);
this.encoder.setQuality(8);
@ -69,17 +72,24 @@ public class GifExporter extends AbstractImageExporter implements AWTImageExport
+ timer.elapsedSecond());
}
if (applyWhiteBackground) {
// If a background color is defined, create an image with this background color before export
if (backgroundColor!=null) {
java.awt.Color awtColor = AWTColor.toAWT(backgroundColor);
BufferedImage imageWithBg =
new BufferedImage(image.getWidth(), image.getHeight(), image.getType());
Graphics2D g = (Graphics2D) imageWithBg.getGraphics();
g.setColor(awtColor);
g.fillRect(0, 0, image.getWidth(), image.getHeight());
g.drawImage(image, 0, 0, null);
g.dispose();
encoder.addFrame(imageWithBg);
} else {
encoder.addFrame(image);
}
image = imageWithBg;
}
// Do export as animated gif frame
encoder.addFrame(image);
if (debug) {
@ -88,10 +98,12 @@ public class GifExporter extends AbstractImageExporter implements AWTImageExport
+ timer.elapsedSecond());
}
// Close output if this is our last image
if (isLastImage) {
closeOutput();
}
// Update counters to monitor task progress
numberOfSavedImages.incrementAndGet();
}
@ -124,5 +136,15 @@ public class GifExporter extends AbstractImageExporter implements AWTImageExport
}
public Color getBackgroundColor() {
return backgroundColor;
}
public void setBackgroundColor(Color backgroundColor) {
this.backgroundColor = backgroundColor;
}
}

View File

@ -1,6 +1,8 @@
package org.jzy3d.chart;
public interface IAnimator {
public static final int DEFAULT_FRAME_PER_SECOND = 10;
public void start();
public void stop();

View File

@ -3,7 +3,7 @@ package org.jzy3d.chart;
import org.jzy3d.plot3d.rendering.canvas.EmulGLCanvas;
public class EmulGLAnimator implements IAnimator {
private static final int RENDERING_LOOP_PAUSE = 100;
private static final int RENDERING_LOOP_PAUSE = 1000/DEFAULT_FRAME_PER_SECOND;
protected EmulGLCanvas canvas;
protected Thread t;
protected boolean loop = false;

View File

@ -6,7 +6,6 @@ import com.jogamp.opengl.util.FPSAnimator;
public class NativeAnimator implements IAnimator {
protected com.jogamp.opengl.util.AnimatorBase animator;
public static final int DEFAULT_FRAME_PER_SECOND = 10;
public NativeAnimator(GLAutoDrawable canvas) {
// animator = new com.jogamp.opengl.util.Animator(canvas);