Forums > Java

Drawing into a BufferedImage

June 10, 2006 | 4:00 pm

There weren’t many mxj examples of how to draw into a BufferedImage,
so I decided to supply one. Hope it’s useful–I’m sure what MaxMSP
most needs are business charts, so it can compete with Excel.

– Paul

#P window setfont "Sans Serif" 9.;
#P window linecount 2;
#P comment 155 22 100 196617 list in right inlet is stored in pieValues;
#P button 407 47 15 12;
#P window linecount 1;
#P newex 367 107 50 196617 print list;
#P button 257 47 15 12;
#P newex 257 81 160 196617 mxj buf2jmTest @pieValues 4. 8.;
#P message 154 47 97 196617 5.5 8.9 1.3 2.1 3.4;
#P message 56 47 91 196617 1. 2. 3. 4. 5. 6. 7.;
#P button 33 47 15 12;
#P message 278 57 62 196617 viewsource;
#P newex 75 197 49 196617 deferlow;
#P newex 117 128 96 196617 jit.matrix piegraph;
#P newex 163 197 65 196617 prepend size;
#P newex 163 175 52 196617 route dim;
#P message 75 129 39 196617 getdim;
#P newex 33 105 95 196617 t b b s;
#P newex 75 152 98 196617 jit.matrix piegraph;
#P user jit.pwindow 74 225 214 202 0 0 0 0 1 0;
#P newex 33 81 83 196617 mxj buf2jmTest;
#P window linecount 2;
#P comment 233 197 165 196617 Note: deferlow used here to handle the
resizing of jit.pwindow;
#P comment 56 22 100 196617 list in left inlet triggers output;
#P comment 359 22 100 196617 bang outputs list to right outlet;
#P comment 256 22 100 196617 bang outputs matrix to left outlet;
#P window linecount 12;
#P comment 296 280 166 196617 Creates a pie graph in a BufferedImage
and then pops it into a JittterMatrix for output. List of numbers in
left inlet sets pieValues attribute , draws graph , triggers output
at left outlet. List of numbers in right inlet sets pieValues
attribute. Bang in left inlet triggers output if pieValues attribute
contains numeric values. Bang in right inlet outputs pieValues at info
outlet.;
#P window setfont "Sans Serif" 12.;
#P window linecount 1;
#P comment 296 257 114 196620 buf2jmTest.java;
#P connect 17 0 6 0;
#P connect 16 0 6 0;
#P fasten 19 0 9 0 262 101 38 101;
#P connect 6 0 9 0;
#P connect 9 1 10 0;
#P connect 10 0 8 0;
#P fasten 9 0 8 0 38 148 80 148;
#P connect 8 0 14 0;
#P connect 14 0 7 0;
#P fasten 12 0 7 0 168 220 80 220;
#P fasten 18 0 6 1 159 69 111 69;
#P connect 9 2 13 0;
#P connect 8 1 11 0;
#P connect 11 0 12 0;
#P fasten 15 0 19 0 283 76 262 76;
#P connect 20 0 19 0;
#P fasten 19 1 21 0 412 102 372 102;
#P connect 22 0 19 1;
#P window clipboard copycount 24;

import com.cycling74.max.*;
import com.cycling74.jitter.*;
import java.awt.*;
import javax.swing.*;
import java.awt.geom.*;
import java.awt.image.BufferedImage;

// created by Ignotus, June 9, 2006.

/**
* Creates a pie graph in a BufferedImage and then pops it into a
* JittterMatrix for output.
* List of numbers in left inlet sets pieValues
attribute, draws graph
* and triggers output at left outlet.
* List of numbers in right inlet sets pieValues attribute.
* Bang in left inlet triggers output if pieValues attribute
* contains numeric values.
* Bang in right inlet outputs pieValues at info outlet.
*/
public class buf2jmTest extends MaxObject
{

private static final String[] INLET_ASSIST = new String[]{
"Bang or list of numbers", "List of numbers"
};
private static final String[] OUTLET_ASSIST = new String[]{
"Jitter Matrix"
};

String useMessage = "Enter a list of positive numbers in inlet 1 or
2, or set the pieValues attribute.";
public float[] pieValues = new float[0];

public buf2jmTest(Atom[] args) {
declareInlets(new int[]{DataTypes.ALL, DataTypes.ALL});
declareOutlets(new int[]{DataTypes.ALL});
setInletAssist(INLET_ASSIST);
setOutletAssist(OUTLET_ASSIST);
declareAttribute("pieValues", "pieValues", "setPieValues");
}

public void bang() {
int inletNum = getInlet();
if ( 0 == inletNum ) {
if (0 == pieValues.length) {
post("You must supply a list of positive numbers first, or set
the pieValues attribute.");
} else {
outputPieChart();
}
} else {
Atom[] outputList = Atom.newAtom(pieValues());
int infoOutletNum = getInfoIdx();
outlet( infoOutletNum, "list", outputList );
}
}

public void list(Atom[] list) {
int inletNum = getInlet();
boolean goodInput = true;
// check for the right sort of list
if ( list.length < 1 ) {
post(useMessage);
return;
}
Atom atom;
float[] valueList = new float[list.length];
for ( int i = 0; i < list.length; i++ ) {
atom = list[i];
if ( !atom.isInt() && !atom.isFloat() ) {
goodInput = false;
break;
}
valueList[i] = atom.getFloat();
if ( valueList[i] < 0 ) {
goodInput = false;
break;
}
}
if ( goodInput ) {
setPieValues(valueList);
if ( 0 == inletNum ) {
outputPieChart();
}
} else {
post(useMessage);
}
}

private float[] pieValues() {
return pieValues;
}
private void setPieValues(float[] newPieValues) {
pieValues = newPieValues;
}

public static BufferedImage makeBufferedImage(Image image) {
BufferedImage bufferedImage = new BufferedImage(
image.getWidth(null), image.getHeight(null),
BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = bufferedImage.createGraphics();
g2.drawImage(image, null, null);
return bufferedImage;
}

public static float sum( float[] values ) {
float sum = 0.0f;
for ( int i = 0; i < values.length; i++ ) {
sum += values[i];
}
return sum;
}

public BufferedImage bakePieGraph() {
int imageWidth = 212;
int imageHeight = 200;
Color bgColor = new Color(255, 248, 228); // fff8e4
Color colors [] = {Color.blue,
Color.green,
Color.red,
Color.cyan,
Color.magenta,
Color.gray,
Color.yellow,
Color.pink,
Color.orange,
Color.white,
new Color(89, 55, 233)};
Color penColor = Color.black;
Frame frame = new Frame ();
// addNotify () is required to create an image (this will call
Toolkit.getDefaultToolkit ())
// addNotify "creates the frame’s peer, its actual resource in
whatever native window toolkit you’re working on"
// cf. p. 188 Java 2D Graphics, Jonathon Knudsen, O’Reilly Pub.
frame.addNotify ();
Image pieImage = frame.createImage(imageWidth, imageHeight);
// use a Graphics2D to get better imaging
Graphics2D gc = (Graphics2D)pieImage.getGraphics ();
gc.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
// fill and outline the background
Shape bgRect = new Rectangle2D.Double(0, 0, imageWidth, imageHeight);
gc.setPaint(bgColor);
gc.fill(bgRect);
gc.setPaint(new Color(128, 128, 128));
gc.setStroke(new BasicStroke(2)); // 2 pixel wide stroke
gc.draw(bgRect);
// Draw whole pie in background color with a gray drop shadow
Stroke stroke_1px = new BasicStroke(1); // 1 pixel wide stroke
gc.setStroke(stroke_1px);
int inset = 16;
Shape pie = new Ellipse2D.Double(10, 8, imageHeight – inset,
imageHeight – inset);
Shape pieShadow = new Ellipse2D.Double(16, 11, imageHeight -
inset, imageHeight – inset);
gc.setPaint(new Color(192, 192, 192));
gc.fill(pieShadow);
gc.draw(pieShadow);
gc.setPaint(bgColor);
gc.fill(pie);
gc.setPaint(penColor);
gc.draw(pie);
// Compute the sum of all values
float sum = sum( pieValues() );
// define an arc shape for slices
Rectangle2D pieBounds = pie.getBounds2D();
Arc2D pieArc = new Arc2D.Double(pieBounds, 0, 15, Arc2D.PIE);
// step pie values and draw pie slices
// note that graphics state is set to 1 pixel stroke
for (int accum = 0, i = 0; i < pieValues.length; i++) {
float answerValue = pieValues[i];
float startAngle = accum * 360.0f / sum;
float angle = answerValue * 360.0f / sum;
// Fill the pie slice for current range
pieArc.setArc(pieBounds, startAngle, angle, Arc2D.PIE);
gc.setPaint (colors [i % colors.length]);
gc.fill(pieArc);
gc.setPaint(penColor);
gc.draw(pieArc);
accum += answerValue;
}
return makeBufferedImage(pieImage);
}

public void outputPieChart() {
// the drawing code is probably very low impact, but it’s still a
// good idea to wrap it in a Thread to free up processor time.
(new Thread() {
public void run() {
BufferedImage bim = bakePieGraph();
JitterMatrix jim = new JitterMatrix(bim);
outlet(0, "jit_matrix", jim.getName());
}
}).start();
}

}


—– |(*,+,#,=)(#,=,*,+)(=,#,+,*)(+,*,=,#)| —–


February 3, 2007 | 2:31 am

Wow!
First time i’ve copied and pasted anything more complicated than Hello World and it’s worked first time! :-) (after a bit of live wrapping)

Thanks! You’re right – there aren’t many examples of this!

jonny



Val
July 7, 2010 | 5:57 pm

Thanks for posting the code for making pie charts. I know it was many years ago and things might have changed. I tried to use it on the latest version of MAX/MSP/Jitter 5.14 running on a mac and got the following errors after I copied and pasted the code in a new patcher:

Could not load class ‘buf2jmTest’
Could not load class ‘buf2jmTest’
import: no such object
import: no such object
import: no such object
import: no such object
import: no such object
import: no such object
//: no such object
June: no such object
…etc.

Would you have any suggestions on how I should proceed to make this work?

Val

http://www.musicalskates.com/mediawiki



efe
July 7, 2010 | 8:05 pm

You will need to compile the class. Are you using OSX or windows?

in the case you are on 10.6.4 here’s a compiled version.

Hope it helps!

Attachments:
  1. buf2jmTest1.zip


Val
July 7, 2010 | 9:34 pm

Thank you, I am using OSX 10.6.4 and it worked fine. Much appreciated.

Val


Viewing 5 posts - 1 through 5 (of 5 total)