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

  • Ticketsysteme sind lebende Wesen

    29.03.2020

    Hier zunächst wieder eine Triggerwarnung: Dieser Artikel wird meine Meinung abbilden. es kann sein, dass sie dem einen oder anderen nicht gefällt - das ist mir aber egal. Und wenn hier irgendwelche Schneeflocken mitlesen, dann sind die selber schuld.

    Weiterlesen...

Neueste Artikel

  • Weitere Experimente mit dem Clifford-Attractor

    Ich berichtete hier bereits über Experimente mit dem Clifford-Attractor, allerdings war ich noch Experimente unter geringfügig geänderten Parametern schuldig...

    Weiterlesen
  • Neues Feature in meinem Static Site Generator: externe URLs

    Es wurde wieder einmal Zeit für ein neues Feature in meinem Static Site Generator mittels dessen ich ja auch meine Heimatseite im Zwischennetz gestalte und verwalte...

    Weiterlesen
  • Eine Bestandsaufnahme

    Es kamen mehrere Faktoren zusammen: die Tatsache, dass ich nicht mehr ganz so kürzlich die 50 überschritten habe hatte ebenso darauf Einfluss wie das heutige trübe Wetter und auch der Fakt, dass ich bereits beinahe alle Wochenendpflichten erledigt habe. Der letzte Stein des Anstoßes war dann aber, dass sich heute zum 125. Mal der Geburtstag von Erich Fromm jährt.

    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.