Here is an experimental runnable example,
There are 2 java files with 2 executable main methods one for a LOCAL implementation of PApplet one for the OUT “output” to the implementation of paint interface .
The PixelPaintForProcessingStandAlone.java file contains the processing sketch code in a separate class, and has a very simple “if” boolean way to switch between a LOCAL implementation of the PApplet window and the OUT implementation that tries to pass the PImage results to a class that implements paint.
ThePanel class acts as a medium jpanel that use paintComponent in order to fill the 2D space with processing PImage… pixels.
all together 3 files → 5 classes.
At PixelPaintForProcessingStandAlone.java
Switch modes true/false at
public boolean enableParametersForLocalProcessing = false; // true=>LOCAL , false=OUT
public boolean enableParametersForOutProcessing = true; // true=>OUT , false=LOCAL
in order to select LOCAL or OUT mode.
comment or uncomment code after this, in order to see the errors in “public void setup”
//Exception in thread “AWT-EventQueue-0” java.lang.NullPointerException: Cannot invoke “processing.core.PGraphics.colorMode(int, float, float, float, float)” because “this.g” is null
TheTest.java tries to output the code in OUT mode.
PixelPaintForProcessingStandAlone runs the code in LOCAL mode.
There might be useless experimental code in there but the example is fully functional in netbeans by just adding the files. I m not an experienced coder, neither in java or processing, hopefully the code will work ok as a minimal starting point in order to reveal the goal and the errors.
processing sketch code borrowed from:
https://discourse.processing.org/t/psychedelic-noise-in-jrubyart
JAVA FILE 1
/*
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
*/
package com.jan.processing.v4.paint;
/*
* Based on code from:
* A quick example of how to implement java.awt.Paint
*/
// http://asserttrue.blogspot.com/2010/01/how-to-iimplement-custom-paint-in-50.html
//import com.jan.noise.NoiseGenerator;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.PaintContext;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.image.ColorModel;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.awt.Color;
import java.awt.image.BufferedImage;
import processing.core.PApplet;
import static processing.core.PConstants.JAVA2D;
import processing.core.PGraphics;
import processing.core.PImage;
//PART I: NATIVE JAVA - Call from TheTest java file
public class PixelPaintForProcessingStandAlone implements Paint {
private AffineTransform transformPixel;
static final AffineTransform defaultXForm = AffineTransform.getScaleInstance(3.5, 3.5);
private int imageWidth = 200; //init non final non static
private int imageHeight = 200;
// constructor 1
public PixelPaintForProcessingStandAlone() {
transformPixel = defaultXForm;
}
// constructor 2
public PixelPaintForProcessingStandAlone(int image_w, int image_h) {
//
this.imageWidth = image_w;
this.imageHeight = image_h;
transformPixel = defaultXForm;
}
public PaintContext createContext(ColorModel cm,
Rectangle deviceBounds,
Rectangle2D userBounds,
AffineTransform xform,
RenderingHints hints) {
return new Context(cm, xform);
}
public int getTransparency() {
return java.awt.Transparency.TRANSLUCENT;
}
class Context implements PaintContext {
public Context(ColorModel cm_, AffineTransform xform_) {
}
public void dispose() {
}
public ColorModel getColorModel() {
return ColorModel.getRGBdefault(); // Or any other color model
}
private BufferedImage getImage() {
SeamlessNoiseOpenPro432548Bi processingObject = new SeamlessNoiseOpenPro432548Bi();
processingObject.setup();
processingObject.draw();
// BufferedImage image = (BufferedImage) processingObject.img.getNative();
BufferedImage bufferedimage = processingObject.createBufferedImage();
PImage pimage = processingObject.bi2pi(bufferedimage);
PImage pimage2 = processingObject.img;
BufferedImage bufferedimageThroughPimage = processingObject.pi2bi(pimage);
return bufferedimageThroughPimage;
}
// FINALY GET RASTER
public Raster getRaster(int xOffset, int yOffset, int w, int h) {
// WritableRaster raster = getColorModel().createCompatibleWritableRaster(w, h);
BufferedImage image = getImage();
WritableRaster rasterWr = image.getRaster();
return rasterWr;
} // getRaster()
} // Context
} //implements Paint class
// PART II - PROCESSING IN PURE JAVA extends PApplet, has a main method to show the applet window
class SeamlessNoiseOpenPro432548Bi extends PApplet {
PImage img /*= createImage(264, 264, ARGB);*/ ; // image used to draw the pattern
PGraphics pg;
PGraphics pg2;
// BOOLEAN group for LOCAL Applet
// public boolean enableParametersForLocalProcessing = true;
// public boolean enableParametersForOutProcessing = false;
// if used then OUT -->
// EXAMPLE ERROR --> Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException: Cannot invoke "processing.core.PGraphics.colorMode(int, float, float, float, float)" because "this.g" is null
// LOCAL -->OK
// BOOLEAN group for EXTERNAL OUTPUT
public boolean enableParametersForLocalProcessing = false; // true=>LOCAL , false=OUT
public boolean enableParametersForOutProcessing = true; // true=>OUT , false=LOCAL
// if used then LOCAL window --> EMPTY
// OUT --> OK
//pattern --> if (enableParametersForLocalProcessing) {}
BufferedImage bi;
int[] c, c2; // aray of colors
// Convert a PImage to a java.awtBufferedImage
public BufferedImage pi2bi(PImage pi) {
BufferedImage bi = new BufferedImage(pi.width, pi.height, BufferedImage.TYPE_INT_ARGB);
pi.loadPixels();
bi.setRGB(0, 0, pi.width, pi.height, pi.pixels, 0, pi.width);
return bi;
}
// Convert a BufferedImage to a PImage
public PImage bi2pi(BufferedImage bi) {
int biw = bi.getWidth(), bih = bi.getHeight();
PImage pi = new PImage(biw, bih, ARGB);
pi.loadPixels();
bi.getRGB(0, 0, biw, bih, pi.pixels, 0, biw);
pi.updatePixels();
return pi;
}
/*-------------*/
public BufferedImage createBufferedImage() {
bi = (BufferedImage) img.getNative(); // casting Object to BufferedImage
return bi;
}
public void settings() {
size(1200, 1200, JAVA2D);
smooth(4);
if (enableParametersForLocalProcessing) {
// PGraphics g2 = new PGraphics();
size(600, 600, JAVA2D);
smooth(4);
}
}//settings()
/*-------------*/
public void setup() {
//Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException: Cannot invoke "processing.core.PGraphics.colorMode(int, float, float, float, float)" because "this.g" is null
// this.colorMode(RGB, 255, 255, 255, 255);
img = createImage(1 * width, 1 * height / 1, RGB); // RGB
if (enableParametersForLocalProcessing) {
//Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException: Cannot invoke "processing.core.PGraphics.colorMode(int, float, float, float, float)" because "this.g" is null
// this.colorMode(RGB, 255, 255, 255, 255);
img = createImage(1 * width, 1 * height / 1, RGB); // RGB
}
//colorMode(ARGB);
// the dimensions of the image are twice the dimentions of
// the canvas to add antialiasing when the image is reduced
if (enableParametersForOutProcessing) {
//// ARGB ONLY !!!!!!!!!
// img = createImage(1 * width / 1, 1 * height / 1, ARGB); // Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: Raster IntegerInterleavedRaster: width = 100 height = 6 #Bands = 3 xOff = 0 yOff = 0 dataOffset[0] 0 is incompatible with ColorModel DirectColorModel: rmask=ff0000 gmask=ff00 bmask=ff amask=ff000000
}
int lod = (int) map(mouseY, 0, height, 0, random(1, 5f));
float falloff = map(mouseX, 0, width, 0, random(0, 1f));
noiseDetail(1, 0.3f);
// noiseDetail(lod, falloff);
// noise detail is changed to make the pattern smooth
// noiseDetail(lod, falloff);
//Noise Detail
c = new int[255]; // the array has 255 colors, one color for each possible grayscale color
c2 = new int[255]; // the array has 255 colors, one color for each possible grayscale color
// fill the array with random colors
for (int i = 0; i < c.length; i += 1) {
c[i] = color(random(0, 255), random(0, 255), random(0, 255), random(0, 255));
}
for (int i = 0; i < c2.length; i += 1) {
c2[i] = color(random(0, 255), random(0, 255), random(0, 255), random(0, 255));
}
noLoop();
}
/*-------------*/
float nx, ny, nz;
float theta = 0;
float phi = 0;
float R = random(5, 10), r = random(1, 2);
public void draw() {
// create pattern
img.loadPixels();
// OpenSimplexNoise osn = new OpenSimplexNoise();
// NoiseGenerator ngen = new NoiseGenerator(); // custom generator?
for (int x = 0; x < img.width; x += 1) {
for (int y = 0; y < img.height; y += 1) {
// map x and y to angles between 0 and TWO_PI
theta = map(x, 0, img.width, 0, TWO_PI);
phi = map(y, 0, img.height, 0, TWO_PI);
// calculate the parameters of noise with the equation of a torus
// this is used to make the pattern seamless
// nx = (R+r*cos(theta))*cos(phi);
// ny = (R+r*cos(phi))*sin(theta);
nx = (R + r * cos(phi)) * cos(theta);
ny = (R + r * cos(phi)) * sin(theta);
nz = r * sin(phi);
// normalize noise parameters so that the de pattern has homogeneous dimensions
nx = norm(nx, 0, R + r);
ny = norm(ny, 0, R + r);
nz = norm(nz, 0, r);
// // apply noise twice and use the equivalent color on the pallete
// img.pixels[x + y * img.width] = c[floor((float) (16 * noise(floor((float) (200 * ngen.smoothNoise(nx, ny, nz))), 0, 0)))];
// img.pixels[x + y * img.width] = c2[floor((float) (4 * noise(floor((float) (25 * ngen.smoothNoise(nx, ny, nz))), 0, 0)))];
//
//
// apply noise twice and use the equivalent color on the pallete
img.pixels[x + y * img.width] = c[floor((float) (16 * noise(floor((float) (200 * noise(nx, ny, nz))), 0, 0)))];
img.pixels[x + y * img.width] = c2[floor((float) (4 * noise(floor((float) (25 * noise(nx, ny, nz))), 0, 0)))];
// img.pixels[x + y*img.width] = c[floor((float) (25*noise(floor((float) (25*ngen.smoothNoise(nx, ny, nz))), 0, 0)))];
// image(pg, 50, 50);
}
}
img.updatePixels(); //? not need
// display pattern
if (enableParametersForLocalProcessing) {
image(img.get(), 0, 0, width, height); // the image is reduce to the size of the canvas to make it smooth
}
if (enableParametersForOutProcessing) {
// image(img.get(), 0, 0, width, height); // the image is reduce to the size of the canvas to make it smooth
}
// https://processing.github.io/processing-javadocs/core/index.html?processing/awt/PGraphicsJava2D.html
//Subclass for PGraphics that implements the graphics API using Java2D.
//To get access to the Java 2D "Graphics2D" object for the default renderer, use:
// Graphics2D g2 = (Graphics2D) g.getNative();
//This will let you do Graphics2D calls directly, but is not supported in any way shape or form. Which just means "have fun, but don't complain if it breaks."
if (enableParametersForLocalProcessing) {
Graphics2D g2 = (Graphics2D) g.getNative();
g2.create();
g2.setColor(new Color(128, 128, 128, 128));
g2.fillOval(0, 0, 100, 100);
g2.fillOval(0, 250, 100, 100);
g2.fillOval(250, 250, 100, 100);
g2.fillOval(250, 0, 100, 100);
g2.fillOval(500, 500, 100, 100);
g2.fillOval(500, 0, 100, 100);
g2.fillOval(500, 500, 100, 100);
g2.fillOval(0, 500, 100, 100);
g2.fillOval(250, 500, 100, 100);
g2.fillOval(500, 250, 100, 100);
g2.fillOval(0, 0, 600, 600);
}
if (enableParametersForLocalProcessing) {
PGraphics pg = createGraphics(300, 300, JAVA2D);// global
pg.beginDraw();
pg.background(100, 100, 100, 128);
pg.stroke(255);
pg.line(pg.width * 0.5f, pg.height * 0.5f, mouseX, mouseY);
pg.endDraw();
image(pg, 150, 150);
}
}
public void mousePressed() {
//noiseSeed(random(0xFFFFFF));
// img.set(0, 0, get());
// img.resize(1000, 1000);
noiseSeed((long) random(0.1f, 1000f)); // edited to work on openProcessing beta
println(frameRate);
redraw();
}
/*-------------*/
public void keyPressed() {
// save("image.png");
}
public static void main(String[] args) {
String[] processingArgs = {"MySketch"};
SeamlessNoiseOpenPro432548Bi mySketch = new SeamlessNoiseOpenPro432548Bi();
PApplet.runSketch(processingArgs, mySketch);
}
}
JAVA FILE 2
package com.jan.processing.v4.paint;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.Rectangle2D;
// MyPanel extends JPanel, which will eventually be placed in a JFrame
public class ThePanel extends JPanel {
// custom painting is performed by the paintComponent method
@Override
public void paintComponent(Graphics g){
// clear the previous painting
super.paintComponent(g);
// cast Graphics to Graphics2D
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.gray); // sets Graphics2D color
// draw the rectangle
Rectangle2D rect = new Rectangle2D.Double (0,0,200,200);
// g2.draw(rect); // drawRect(x-position, y-position, width, height)
// g2.setColor(Color.blue);
PixelPaintForProcessingStandAlone pixelPaintForProcessing = new PixelPaintForProcessingStandAlone(200,200);
// graphics.setPaint(pixelpaint);
g2.setPaint(pixelPaintForProcessing);
// graphics.setPaint(color);
g2.setPaintMode();
g2.fill(rect);
}
}
JAVA FILE 3
package com.jan.processing.v4.paint;
import javax.swing.*;
import java.awt.*;
public class TheTest { //the Class by which we display our rectangle
JFrame f;
ThePanel p;
public TheTest(){
f = new JFrame();
// get the content area of Panel.
Container c = f.getContentPane();
// set the LayoutManager
c.setLayout(new BorderLayout());
p = new ThePanel();
// add MyPanel object into container
c.add(p);
// set the size of the JFrame
f.setSize(400,400);
// make the JFrame visible
f.setVisible(true);
// sets close behavior; EXIT_ON_CLOSE invokes System.exit(0) on closing the JFrame
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String args[ ]){
TheTest t = new TheTest();
}
}