Processing in Java

vorhergehende Artikel in: Java Komponenten OpenSource
31.01.2025

Ich habe bereits vor geraumer Zeit einen Artikel zum Thema Erzeugung von AnimGifs mittels Java veröffentlicht - hier erkläre ich nun, wie ich auf die Idee gekommen bin...

Ich bin in meiner Freizeit - und manchmal auf dem Weg zur Arbeit oder nach Hause - viel auf Mastodon - oder wie man heute moderner sagt: im Fediverse - unterwegs. Dort findet man immer wieder Beispiele generativer Programmierung, die kleine Kunstwerke ergibt.

Viele der dort zu findenden Beispiele wurden mittels Processing erstellt - und es sind häufig AnimGIFs, die hier geteilt werden. Daher also mein ursprüngliches Interesse an der Möglichkeit, Multimediainhalte in dieser Form mittels Java zu erstellen.

Mein letzter Ausflug in Richtung Programmierung und Erzeugung von Computergraphik war eine Vorstufe davon. Ich wollte aber mit Processing darüber hinaus gehen: Mir schwebte eine Komponente vor, die ich in eigene Anwendungen einbauen könnte, um damit meine Idee zu vervollkommnen.

Die Beschäftigung mit AnimGIFs resultierte unter anderem aus einem der zahlreichen sogenannten Templates zur Erzeugung von Animationen für Processing - wenn man das einfach nachnutzen könnte, wäre das schon toll.

Ich musste allerdings feststellen, dass dieses Template gar kein AnimGIF erzeugt sondern einfach nur eine Menge einzelner Bilder, die man hinterher erst noch zu einem AnimGIF konvertieren muss. Das musste doch auch anders gehen?

Ich fand processing-java und ging als nächstes auf die Suche nach einer Variante, echte .pde Dateien direkt in Java nutzen zu können - leider war dazu nichts zu finden. Man muss - meinem aktuellen Kenntnisstand zufolge - die Sourcen mittels Processing in Java-Quelltexte umwandeln und diese entstehenden Klassen kann man dann in Java benutzen. Und so ergibt die Umwandlung des Beispiels folgenden Code:

/* autogenerated by Processing revision 1293 on 2024-11-20 */
import processing.core.*;
import processing.data.*;
import processing.event.*;
import processing.opengl.*;

import java.util.HashMap; import java.util.ArrayList; import java.io.File; import java.io.BufferedReader; import java.io.PrintWriter; import java.io.InputStream; import java.io.OutputStream; import java.io.IOException;

public class fractalsquareorbits extends PApplet {

// Processing code by Etienne Jacob // motion blur template by beesandbombs, explanation/article: https://bleuje.com/tutorial6/ // See the license information at the end of this file.

////////////////////////////////////////////////////////////////////////////// // Start of template

int[][] result; // pixel colors buffer for motion blur float t; // time global variable in [0,1[ float c; // other global variable for testing things, controlled by mouse

//-----------------------------------

// ease in and out, [0,1] -> [0,1], with a parameter g: // https://patakk.tumblr.com/post/88602945835/heres-a-simple-function-you-can-use-for-easing public float ease(float p, float g) { if (p < 0.5f) return 0.5f * pow(2*p, g); else return 1 - 0.5f * pow(2*(1 - p), g); }

//-----------------------------------

public void draw() { if (!recording) // test mode... { t = (mouseX*1.3f/width)%1; c = mouseY*1.0f/height; if (mousePressed) println(c); draw_(); } else // render mode... { for (int i=0; i<width*height; i++) for (int a=0; a<3; a++) result[i][a] = 0;

c = 0; for (int sa=0; sa<samplesPerFrame; sa++) { t = map(frameCount-1 + sa*shutterAngle/samplesPerFrame, 0, numFrames, 0, 1); t %= 1; draw_(); loadPixels(); for (int i=0; i<pixels.length; i++) { result[i][0] += red(pixels[i]); result[i][1] += green(pixels[i]); result[i][2] += blue(pixels[i]); } }

loadPixels(); for (int i=0; i<pixels.length; i++) pixels[i] = 0xff << 24 | PApplet.parseInt(result[i][0]*1.0f/samplesPerFrame) << 16 | PApplet.parseInt(result[i][1]*1.0f/samplesPerFrame) << 8 | PApplet.parseInt(result[i][2]*1.0f/samplesPerFrame); updatePixels();

if (frameCount<=numFrames) { saveFrame("data/fr println(frameCount,"/",numFrames); }

if (frameCount==numFrames) stop(); } }

// End of template //////////////////////////////////////////////////////////////////////////////

// ... actual code omitted }

Hier sieht man auch die Methode saveFrame, die wie beschrieben die Einzelbilder speichert.

Zur direkten Erzeugung des AnimGIF als Resultat musste ich nun lediglich den erzeugten Code ein wenig ergänzen:

    Animator animator;

public void saveFrame(java.lang.String label) { PImage target = createImage(width,height, BufferedImage.TYPE_INT_ARGB); if (target != null) { int count = PApplet.min(pixels.length, target.pixels.length); System.arraycopy(pixels, 0, target.pixels, 0, count); animator.ch.put(de.elbosso.ui.image.Utilities.toBufferedImage(target.getImage(),BufferedImage.TYPE_INT_ARGB)); } }

static class Animator extends java.lang.Thread implements java.util.Iterator<java.awt.image.RenderedImage> { de.netsysit.util.threads.CubbyHole<java.awt.image.RenderedImage> ch=new SimpleBlockingCubbyHole(); Animator() { }

@Override public void run() { try { de.elbosso.ui.image.Utilities.writeAnimGif(23,2,this,new File("/tmp/te.gif")); } catch (IOException e) { throw new RuntimeException(e); } }

@Override public boolean hasNext() { return true; }

@Override public RenderedImage next() { try { return ch.get(); } catch (InterruptedException e) { throw new RuntimeException(e); } } }

Dieser Code wird durch die Ergänzung in der Methode setup() aktiviert:

    public void setup()
    {
    	//other setup stuff goes here

//activate AnimGIF creator animator=new Animator(); animator.start(); }

Und schließlich der Vollständigkeit halber hier die Methode, um einen Processing-Sketch in einer Java-Anwendung als Swing-Widget zu nutzen:

    public static void main(String... args)
    {
        // create your JFrame
        JFrame frame = new JFrame("JFrame Test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

// create your sketch fractalsquareorbits pt = new fractalsquareorbits();

// get the PSurface from the sketch PSurface ps = pt.initSurface();

// initialize the PSurface ps.setSize(800, 800);

// get the SmoothCanvas that holds the PSurface PSurfaceAWT.SmoothCanvas smoothCanvas = (PSurfaceAWT.SmoothCanvas) ps.getNative();

// SmoothCanvas can be used as a Component JPanel panel = new JPanel(); panel.setLayout(new BorderLayout()); panel.add(new Label("Quark was here."), BorderLayout.NORTH); panel.add(smoothCanvas, BorderLayout.CENTER); frame.add(panel); // Make the window visible frame.setSize(800, 800); frame.setVisible(true); panel.invalidate(); panel.validate(); panel.doLayout(); frame.pack();

// start your sketch ps.startThread(); }

Artikel, die hierher verlinken

Motion JPEG Erzeugung aus Java heraus

07.02.2025

Da ich mich in den letzten Wochen wieder einmal mit Javas Sicherheitsmechanismen und dem Erzeugen von Animationen beschäftigt habe, habe ich den Entschluss gefasst, die bisher mittels JMF AVIs in dWb+ zu erstetzen - nur wodurch?

Animationen mit Multi-Scale Truchet Patterns

07.02.2025

Ich hatte neulich hier einen Link zu Multi-Scale Truchet Patterns und habe seitdem den Algorithmus mit java umgesetzt und ihn als Teil meines Projekts zur Testdatengenerierung veröffentlicht.

Alle Artikel rss Wochenübersicht Monatsübersicht Codeberg Repositories Mastodon Über mich home xmpp


Vor 5 Jahren hier im Blog

  • OAuth und OTP

    16.02.2020

    Wie bereits beschrieben will ich mich demnächst näher mit OAuth befassen...

    Weiterlesen...

Neueste Artikel

  • Split von Filesets in Apache ANT

    Ich musste neulich darüber nachdenken, eine Parallelisierung für einen meiner ANT-Tasks in meinem Static Site Generator einzubauen.

    Weiterlesen
  • Ein Doclet zur Erzeugung von DocBook aus Javadoc

    Ich habe mich mit der Idee zu diesem Projekt Monate abgequält - hätte ich gewusst, was die eigentliche Implementierung für Qualen verursachen würde, hätte ich sie wahrscheinlich eingestampft.

    Weiterlesen
  • Motion JPEG Erzeugung aus Java heraus

    Da ich mich in den letzten Wochen wieder einmal mit Javas Sicherheitsmechanismen und dem Erzeugen von Animationen beschäftigt habe, habe ich den Entschluss gefasst, die bisher mittels JMF AVIs in dWb+ zu erstetzen - nur wodurch?

    Weiterlesen

Manche nennen es Blog, manche Web-Seite - ich schreibe hier hin und wieder über meine Erlebnisse, Rückschläge und Erleuchtungen bei meinen Hobbies.

Wer daran teilhaben und eventuell sogar davon profitieren möchte, muss damit leben, daß ich hin und wieder kleine Ausflüge in Bereiche mache, die nichts mit IT, Administration oder Softwareentwicklung zu tun haben.

Ich wünsche allen Lesern viel Spaß und hin und wieder einen kleinen AHA!-Effekt...

PS: Meine öffentlichen Codeberg-Repositories findet man hier.