improve gif export

This commit is contained in:
martin 2022-10-03 22:15:27 +02:00
parent 787e9c27be
commit ec1fb2444d
5 changed files with 78 additions and 20 deletions

View File

@ -3,6 +3,7 @@ package org.jzy3d.io;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
@ -152,11 +153,13 @@ public abstract class AbstractImageExporter implements AWTImageExporter {
protected void scheduleImageExport(BufferedImage image, boolean isLastImage) {
// try {
numberSubmittedImages.incrementAndGet();
executor.execute(new Runnable() {
@Override
public void run() {
numberSubmittedImages.incrementAndGet();
numberOfPendingImages.incrementAndGet();
// System.out.println("Adding image to GIF (pending tasks " + pendingTasks.get() + ")");
@ -170,8 +173,12 @@ public abstract class AbstractImageExporter implements AWTImageExporter {
* image.getHeight()-20); graphics.dispose();
*/
doAddFrameByRunnable(image, isLastImage);
try {
doAddFrameByRunnable(image, isLastImage);
}
catch(Exception e) {
throw new RuntimeException(e);
}
numberOfPendingImages.decrementAndGet();
}
@ -183,9 +190,9 @@ public abstract class AbstractImageExporter implements AWTImageExporter {
*/
}
protected abstract void doAddFrameByRunnable(BufferedImage image, boolean isLastImage);
protected abstract void doAddFrameByRunnable(BufferedImage image, boolean isLastImage) throws IOException;
protected abstract void closeOutput();
protected abstract void closeOutput() throws IOException;
public TicToc getTimer() {
return timer;

View File

@ -176,21 +176,23 @@ public class AnimatedGifEncoder {
/**
* Flushes any pending data and closes output file. If writing to an
* OutputStream, the stream is not closed.
* @throws IOException
*/
public boolean finish() {
public boolean finish() throws IOException {
if (!started)
return false;
boolean ok = true;
started = false;
try {
//try {
out.write(0x3b); // gif trailer
out.flush();
if (closeStream) {
out.close();
}
} catch (IOException e) {
ok = false;
}
//} catch (IOException e) {
// ok = false;
//}
// reset for subsequent use
transIndex = 0;

View File

@ -1,16 +1,30 @@
package org.jzy3d.io.gif;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.concurrent.Executors;
import java.io.IOException;
import org.jzy3d.io.AWTImageExporter;
import org.jzy3d.io.AbstractImageExporter;
import org.jzy3d.maths.TicToc;
import org.jzy3d.maths.Utils;
/**
* An image exporter able to create a gif animation out of frame exported by a renderer.
*
* Delay between frames should remain superior to 50 miliseconds.
*
* @see {@link AbstractImageExporter}
*
* @author Martin Pernollet
*
*/
public class GifExporter extends AbstractImageExporter implements AWTImageExporter {
protected File outputFile;
protected AnimatedGifEncoder encoder;
protected boolean applyWhiteBackground = true;
protected TicToc timer = new TicToc();
public GifExporter(File outputFile) {
@ -21,6 +35,10 @@ public class GifExporter extends AbstractImageExporter implements AWTImageExport
super(gifFrameRateMs);
this.outputFile = outputFile;
if(!outputFile.getParentFile().exists()) {
outputFile.getParentFile().mkdirs();
}
this.encoder = new AnimatedGifEncoder();
this.encoder.start(outputFile.getAbsolutePath());
@ -32,14 +50,25 @@ public class GifExporter extends AbstractImageExporter implements AWTImageExport
}
@Override
protected void doAddFrameByRunnable(BufferedImage image, boolean isLastImage) {
protected void doAddFrameByRunnable(BufferedImage image, boolean isLastImage) throws IOException {
if (debug) {
timer.toc();
System.out.println("GifExporter : Adding image to GIF " + numberSubmittedImages.get() + " at " + timer.elapsedSecond());
}
encoder.addFrame(image);
if(applyWhiteBackground) {
BufferedImage imageWithBg = new BufferedImage(image.getWidth(), image.getHeight(), image.getType());
Graphics2D g = (Graphics2D)imageWithBg.getGraphics();
g.fillRect(0, 0, image.getWidth(), image.getHeight());
g.drawImage(image, 0, 0, null);
g.dispose();
encoder.addFrame(imageWithBg);
}
else {
encoder.addFrame(image);
}
if (debug) {
timer.toc();
@ -54,7 +83,7 @@ public class GifExporter extends AbstractImageExporter implements AWTImageExport
}
@Override
protected void closeOutput() {
protected void closeOutput() throws IOException {
encoder.finish();
if (debug)
@ -65,6 +94,21 @@ public class GifExporter extends AbstractImageExporter implements AWTImageExport
public File getOutputFile() {
return outputFile;
}
public double progress() {
int submit = getNumberSubmittedImages().intValue();
int saved = getNumberOfSavedImages().intValue();
return 100f * saved / submit;
}
public void progressToConsole() {
int submit = getNumberSubmittedImages().intValue();
int saved = getNumberOfSavedImages().intValue();
double progress = 100f * saved / submit;
System.out.println(Utils.num2str(progress, 3) + " % progress : " + saved + " saved " + submit + " submit");
}
}

View File

@ -12,6 +12,8 @@ import org.jzy3d.painters.IPainter;
* @author Martin Pernollet
*/
public class Rotate implements Transformer {
protected float angle;
protected Coord3d rotate;
/**
* Initialize a Rotation of angle degrees around the vector (x,y,z)
@ -62,7 +64,4 @@ public class Rotate implements Transformer {
public void setRotate(Coord3d rotate) {
this.rotate = rotate;
}
private float angle;
private Coord3d rotate;
}

View File

@ -5,10 +5,12 @@ 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);
animator = new FPSAnimator(canvas, 10);
animator = new FPSAnimator(canvas, DEFAULT_FRAME_PER_SECOND);
}
@Override
@ -21,7 +23,11 @@ public class NativeAnimator implements IAnimator {
animator.stop();
}
public FPSAnimator getAnimator() {
return (FPSAnimator)animator;
public com.jogamp.opengl.util.AnimatorBase getAnimator() {
return animator;
}
public void setAnimator(com.jogamp.opengl.util.Animator animator) {
this.animator = animator;
}
}