# Mandelbrot Set II

Over a year ago, I published my first Mandelbrot Set viewer, a Python program using pygame. Since then, I have published a rather short program highlighting errors that can occur when calculating the set (Mandelbrot Set Miscalculations).
Since my first viewer was in Python, which is an interpreted programming language, and I wanted to make my viewer faster, I decided to write one in Java. I was hoping for a speed increase since Java is compiled and thus should run at higher speeds. I was not disappointed. The new Java-based viewer runs noticeably faster and additionally I added a lot of new features, all listed below.

#### Controls

• Left-clicking and dragging draws a zoom frame, single left-clicking removes the frame
• Right clicking (and optionally dragging) moves the zoom frame
• Space zooms into the zoom frame
• F1 moves one step back the zoom history
• F2 shows the path a complex number at the cursor’s position follows when the function is iteratively applied
• F3 shows the $\mathbb{R}$ and $\mathbb{R}i$ axis
• F4 displays the current cursor’s corresponding complex number
• F5 toggles between showing and hiding the menu (text in the left upper corner describing the viewer’s functions and current states)
• F6 increments the exponent (going from $f_c(z)=z^2+c$ to $f_c(z)=z^5+c$ in whole-number steps)
• F7 toggles between the Mandelbrot set and the filled Julia set
• F8 toggles between previewing a small filled Julia set at the cursor’s position based upon the cursor’s complex number
• F9 completely resets the zoom and zoom history
• F11 (or F) toggles between fullscreen and windowed mode
• F12 quits the application
• L increases the color depth (starting at $256$ and increasing in steps of $256$)
• Q saves the current image to disk

To use this application, you can either trust me and download the .jar-file or view the source code listed below, verify it and compile the program yourself.
The program will start in fullscreen mode, to change to windowed mode, just press F11 (as listed above).

```// Java Code
// Jonathan Frech 14th of September, 2016
//         edited 15th of September, 2016
//         edited 16th of September, 2016
//         edited 17th of September, 2016
//         edited 18th of September, 2016
//         edited 19th of September, 2016
//         edited 23rd of September, 2016
//         edited 24th of September, 2016
//         edited 26th of September, 2016
//         edited 27th of September, 2016
//         edited 28th of September, 2016
//         edited 29th of September, 2016
//         edited 30th of September, 2016
//         edited  1st of October  , 2016
//         edited  2nd of October  , 2016
//         edited  3rd of October  , 2016
//         edited  4th of October  , 2016
//         edited 21st of November , 2016
//         edited 23rd of November , 2016
//         edited 14th of December , 2016
//         edited 13th of January  , 2017```

```// import
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.*;
import java.util.List;
import java.io.File;

// J-Utilities
class jutil {
// map x from a to b to be y from c to d
static double map   (double x, double a, double b, double c, double d) { return        c+(d-c)*((x-a)/(b-a)) ; }
static int    mapint(double x, double a, double b, double c, double d) { return (int) (c+(d-c)*((x-a)/(b-a))); }

// get a color int from red, green and blue
static int color(int r, int g, int b) { return ((r << 16) | (g << 8) | b); }

// get a color object from color int
static Color color(int c) {
int r = (c                       ) >> 16;
int g = (c - (r << 16)           ) >>  8;
int b = (c - (r << 16) - (g << 8))      ;
return new Color(r, g, b);
}

// display a list of strings as a block
static void textblock(Graphics2D g, String[] strs) {
for (int s = 0; s < strs.length; s++) {
g.drawString(strs[s], 5, 15 + 20 * s);
}
}
}

// main
public class Main {
// version
private String version = "Mandelbrot Set";

// dimensions
private int width;
private int height;
private boolean fullscreen = true;

// JFrame
private JFrame frame;

// keys
int key_quit       = KeyEvent.VK_F12;
int key_switch     = KeyEvent.VK_F7;
int key_fullscreen = KeyEvent.VK_F11;
int key_fullscreen2 = KeyEvent.VK_F;
int key_save       = KeyEvent.VK_Q;

// canvas and label
private ImageIcon canvas;
private JLabel label;

// fractals
private Fractal fractal_mandelbrot;
private Fractal fractal_julia;
private Fractal[] fractals;
private int fractalid;

// refresh img
void refresh(BufferedImage img) {
canvas.setImage(img);
frame.repaint();
}

// save img
private void save() {
String path = "./img/";

// generate 'out' directory
File dir = new File(path);
if (!dir.exists()) {
dir.mkdir();
}
try {
String name = path + "img" + dir.listFiles().length + " [" + fractal().getname() + "]" + ".png";
File f = new File(name);
ImageIO.write(fractal().getfimg(), "PNG", f);
}
catch(IOException e) {}
}

// return current fractal
private Fractal fractal() {
return fractals[fractalid];
}

// restart the frame
private void restart() {
// clear old frame
frame.dispose();

// determine size
if (!fullscreen) {
width = 1080;
height = 720;
} else {
width  = (int) Toolkit.getDefaultToolkit().getScreenSize().getWidth();
height = (int) Toolkit.getDefaultToolkit().getScreenSize().getHeight();
}

// init frame
frame = new JFrame(version);
frame.setResizable(false);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());

if (!fullscreen) {
frame.setUndecorated(false);
frame.setLocationRelativeTo(null);
} else {
frame.setUndecorated(true);
frame.setLocation(0, 0);
}

// other
canvas = new ImageIcon();
label = new JLabel(canvas);
fractal_mandelbrot = new Fractal("mandelbrot", width, height, this);
fractal_julia      = new Fractal("julia"     , width, height, this);

fractals = new Fractal[] {fractal_mandelbrot, fractal_julia};
fractalid = 0;
fractal().initzoom();

// listeners
initlisteners();

// final
frame.setSize(width, height);
frame.setVisible(true);
frame.pack();
}

// init
private Main() {
frame = new JFrame(version);
restart();
}

private void initlisteners() {
// keys
@Override
public void keyPressed(KeyEvent e) {
// quit
if (e.getKeyCode() == key_quit) {
frame.dispose();
}

// switch screen
else if(e.getKeyCode() == key_switch) {
// old fractal
Fractal f = fractal();

// new fractal
fractalid = (fractalid+1)%2;
fractal().setexp(f.getexp());

fractal().setcolordepth(f.getcolordepth());
fractal().setcolormode(f.getcolormode());
fractal().initcolors();

// refresh
if (fractal().isfractal("julia")) {
fractal().setCD(f.cursorposcomplexC(), f.cursorposcomplexD());
fractal().initzoom();
} else {
fractal().newfractal();
fractal().refresh();
}

}

// change fullscreen
else if (e.getKeyCode() == key_fullscreen || e.getKeyCode() == key_fullscreen2) {
fullscreen = !fullscreen;
restart();
}

// save
else if (e.getKeyCode() == key_save) {
save();
}

// handle key by screen
else {
fractal().keyPressed(e);
}
}
});

// mouse listeners are added to content pane so that they are not relative to
// the top left window corner, but the top left content pane corner!

// mouse dragment / movement
@Override
public void mouseDragged(MouseEvent e) {
fractal().mouseDragged(e);
}

@Override
public void mouseMoved(MouseEvent e) {
fractal().mouseMoved(e);
}

});

// mouse click
@Override
public void mousePressed(MouseEvent e) {
fractal().mousePressed(e);
}

});
}

// main main
public static void main(String[] args) {
new Main();
}
}

// fractal class
class Fractal {
// parent
private Main parent;

// type
private String type;

// dimensions
private int width, height;

// box, fixed box and cursor position
private int b1x;
private int b1y;
private int b2x;
private int b2y;
private double fixed_b1x;
private double fixed_b1y;
private double fixed_b2x;
private double fixed_b2y;
private int cursorx;
private int cursory;

// complex numbers (p for position)
// define the the upper left and lower right corners
private double p1y;
private double p2y;
private double p1x;
private double p2x;

// standard zoom
private double std_p1y;
private double std_p2y;
private double std_p1x;
private double std_p2x;

// color
private int[] colors;
private int colordepth = 256;
private int textcolor;
private String colormode = "b&w";

// history
private List<double[]> history;

// keys
private int key_zoom        = KeyEvent.VK_SPACE;
private int key_historyback = KeyEvent.VK_F1;
private int key_zoomreset   = KeyEvent.VK_F9;
private int key_show_path   = KeyEvent.VK_F2;
private int key_show_axes   = KeyEvent.VK_F3;
private int key_show_number = KeyEvent.VK_F4;
private int key_show_julia  = KeyEvent.VK_F8;

private int key_increment_exp = KeyEvent.VK_F6;
private int key_increment_colordepth = KeyEvent.VK_L;
private int key_switch_colormode = KeyEvent.VK_C;

// f_c(z) == z**exp+c
private int exp = new int[] {2, 3, 4, 5}[0];
private boolean show_path = false;
private boolean show_axes = false;
private boolean show_number = false;
private boolean show_julia = false;

// julia set
private double C = 0;
private double D = 0;

// main image, fractal image
private BufferedImage img;
private BufferedImage fimg;

// constructor
Fractal(String type, int width, int height, Main parent) {
// parent
this.parent = parent;

// dimensions
this.width = width;
this.height = height;

// type
this.type = type;

img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

// colors and dimensions
initcolors();
}

// update fimg variables
void newfractal() {
fimg = fractalimg(type, width, height, p1x, p1y, p2x, p2y, C, D);
}

// get fractal's type
boolean isfractal(String t) {
return type.equals(t);
}

// set C and D (only relevant for julia)
void setCD(double c, double d) {
C = c;
D = d;
}

int getcolordepth() {
return colordepth;
}
String getcolormode() {
return colormode;
}
void setcolordepth(int depth) {
colordepth = depth;
}
void setcolormode(String mode) {
colormode = mode;
}

// get C and D from current mouse position
double cursorposcomplexC() {
return jutil.map(cursorx, 0, width, p1x, p2x);
}
double cursorposcomplexD() {
return -jutil.map(cursory, 0, height, p1y, p2y);
}

// get / set exponent
int getexp() {
return exp;
}
void setexp(int e) {
exp = e;
}

// return fractal image
BufferedImage getfimg() {
return fimg;
}

// return current fractal's name
String getname() {
return type + (isfractal("julia") ? ("(c=" + C + (D<0 ? "":"+") + D + "i)"):"") + ",tl=" + p1x + (p1y<0 ? "":"+") + p1y + "i,br=" + p2x + (p2y<0 ? "":"+") + p2y + "i";
}

// listeners
void keyPressed  (KeyEvent   e) {
// move back in time
if (e.getKeyCode() == key_historyback) {
if (history.size() > 0) {
p1x = history.get(history.size()-1)[0];
p1y = history.get(history.size()-1)[1];
p2x = history.get(history.size()-1)[2];
p2y = history.get(history.size()-1)[3];
history.remove(history.size()-1);
newfractal();
}
}

// zoom
else if (e.getKeyCode() == key_zoomreset) {initzoom();}
else if (e.getKeyCode() == key_zoom     ) {zoom();}

// show
else if (e.getKeyCode() == key_show_path  ) {show_path   = !show_path;  }
else if (e.getKeyCode() == key_show_axes  ) {show_axes   = !show_axes;  }
else if (e.getKeyCode() == key_show_number) {show_number = !show_number;}
else if (e.getKeyCode() == key_show_julia && type.equals("mandelbrot")) {show_julia  = !show_julia; }

else if (e.getKeyCode() == key_increment_colordepth) {
colordepth += 256;
initcolors();
newfractal();
}

else if (e.getKeyCode() == key_switch_colormode) {
if (colormode.equals("random")) {
colormode = "b&w";
}
else if (colormode.equals("b&w")) {
colormode = "b|w";
}

else {
colormode = "random";
}
initcolors();
newfractal();
}

// increment exponent
if (e.getKeyCode() == key_increment_exp && type.equals("mandelbrot")) {
exp++;
if (exp > 5) {exp = 2;}
newfractal();
refresh();
}

// refresh
refresh();
}

// handle mouse dragged
void mouseDragged(MouseEvent e) {
// move box point two
if (SwingUtilities.isLeftMouseButton(e)) {
b2x = e.getX();
b2y = e.getY();
fixbox();
}

// center box
else if (SwingUtilities.isRightMouseButton(e)) {
centerbox(e.getX(), e.getY());
}

// update cursor pos
cursorx = e.getX();
cursory = e.getY();

// refresh
refresh();
}

// handle mouse moved
void mouseMoved  (MouseEvent e) {
// update cursor pos
cursorx = e.getX();
cursory = e.getY();

// refresh
refresh();
}

// handle mouse pressed
void mousePressed(MouseEvent e) {
// reset box
if (SwingUtilities.isLeftMouseButton(e)) {
b1x = e.getX();
b1y = e.getY();
b2x = e.getX();
b2y = e.getY();
}

// center box
else if (SwingUtilities.isRightMouseButton(e)) {
centerbox(e.getX(), e.getY());
}

refresh();
}

// initialize colors
void initcolors() {
// pseudo-randomly generated colors
if (colormode.equals("random")) {
colors = new int[colordepth];

int r = 255 / 2;

int g = 255 / 2;
int b = 255 / 2;
colors[0] = jutil.color(r, g, b);
int a;

for (int i = 1; i < colordepth; i++) {
a = (int) (Math.random()*4);
if (a == 0) {
r += (((int) (Math.random() * 2)) * 2 - 1) * 10;
} else if (a == 1) {
g += (((int) (Math.random() * 2)) * 2 - 1) * 10;
} else if (a == 2) {
b += (((int) (Math.random() * 2)) * 2 - 1) * 10;
}

if (r < 0) r = 0;
if (r > 255) r = 255;
if (g < 0) g = 0;
if (g > 255) g = 255;
if (b < 0) b = 0;
if (b > 255) b = 255;

colors[i] = jutil.color(r, g, b);
}

colors[colors.length - 1] = 0;

textcolor = jutil.color(255, 255, 255);
}

else if (colormode.equals("b&w")) {
colors = new int[colordepth];
int k = 0;
for (int i = 0; i < colordepth; i++) {
colors[i] = jutil.color(k, k, k);
k++;
if (k > 255) {
k = 0;
}
}

textcolor = jutil.color(255, 0, 0);
}

else if (colormode.equals("b|w")) {
colors = new int[colordepth];
for (int i = 0; i < colordepth-1; i++) {
colors[i] = jutil.color(0, 0, 0);
}
colors[colordepth-1] = jutil.color(255, 255, 255);

textcolor = jutil.color(255, 0, 0);
}
}

// set zoom to default
void initzoom() {
// reset history
history = new ArrayList<>();

// standard zoom
std_p1y = -2;
std_p2y =  2;
std_p1x = -(std_p2y-std_p1y)/2.*width/height;
std_p2x =  (std_p2y-std_p1y)/2.*width/height;

// reset complex numbers
p1x = std_p1x;
p2x = std_p2x;
p1y = std_p1y;
p2y = std_p2y;

// refresh
newfractal();
refresh();
}

// center the box on (X, Y)
private void centerbox(int X, int Y) {
// make sure box has correct ratio
fixbox();

// center
int x = (int) ((fixed_b2x-fixed_b1x)/2);
int y = (int) ((fixed_b2y-fixed_b1y)/2);
fixed_b1x = X-x;
fixed_b1y = Y-y;
fixed_b2x = X+x;
fixed_b2y = Y+y;
}

// fix box's ratio
private void fixbox() {
// correct ratio
fixed_b1x = b1x;
fixed_b1y = b1y;
fixed_b2x = b2x;
fixed_b2y = b2y;

// make sure 1x/1y are top left and 2x/2y are bottom right
double t;
if (fixed_b1x > fixed_b2x) {t = fixed_b1x;fixed_b1x = fixed_b2x;fixed_b2x = t;}
if (fixed_b1y > fixed_b2y) {t = fixed_b1y;fixed_b1y = fixed_b2y;fixed_b2y = t;}

// determine height based on current ratio, current width and ideal ratio
fixed_b2y = fixed_b1y+(int) (1.*(fixed_b2x-fixed_b1x)*height/width);
}

// check if box's size is 0 in any dimension
private boolean validbox() { return (b1x != b2x && b1y != b2y); }

// convert cursor positions into complex numbers
private void zoom() {
// you can only zoom with a valid box
if (validbox()) {
// put old zoom in history
double[] h = {p1x, p1y, p2x, p2y};

// turn cursor pos into complex numbers
double x1 = fixed_b1x / width;
double y1 = fixed_b1y / height;
double x2 = fixed_b2x / width;
double y2 = fixed_b2y / height;
double x = p2x - p1x;
double y = p2y - p1y;
double _1x = x1 * x + p1x;
double _1y = y1 * y + p1y;
double _2x = x2 * x + p1x;
double _2y = y2 * y + p1y;

// update
p1x = _1x;
p1y = _1y;
p2x = _2x;
p2y = _2y;

// update fractal image
newfractal();
}
}

// refresh the JLabel's image
void refresh() {
Graphics2D g = img.createGraphics();

//g.setFont(new Font("Courier", Font.PLAIN, 20));
g.setColor(jutil.color(textcolor));

// draw fractal image
g.drawImage(fimg, null, 0, 0);

// draw julia set
if (show_julia && type.equals("mandelbrot")) {
g.drawImage(juliaimg(jutil.map(cursorx, 0, width, p1x, p2x), -jutil.map(cursory, 0, height, p1y, p2y), (int) (width * .1), (int) (height * .1), std_p1x, std_p1y, std_p2x, std_p2y), null, cursorx, cursory);
}

// draw box
if (validbox()) {
/*g.setStroke(new BasicStroke(3, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0, new float[]{9}, 0));
g.drawLine(b1x, b1y, b2x, b1y);
g.drawLine(b1x, b1y, b1x, b2y);
g.drawLine(b2x, b2y, b2x, b1y);
g.drawLine(b2x, b2y, b1x, b2y);*/

g.setStroke(new BasicStroke());
g.drawLine((int) fixed_b1x, (int) fixed_b1y, (int) fixed_b2x, (int) fixed_b1y);
g.drawLine((int) fixed_b1x, (int) fixed_b1y, (int) fixed_b1x, (int) fixed_b2y);
g.drawLine((int) fixed_b2x, (int) fixed_b2y, (int) fixed_b2x, (int) fixed_b1y);
g.drawLine((int) fixed_b2x, (int) fixed_b2y, (int) fixed_b1x, (int) fixed_b2y);

}

// MANDELBROT / JULIA SET CALCULATIONS
// on the JFrame y gets higher going down, on the complex plane it is the opposite
double a =   jutil.map(cursorx, 0, width , p1x, p2x);
double b =  -jutil.map(cursory, 0, height, p1y, p2y);
double c =   jutil.map(cursorx, 0, width , p1x, p2x);
double d =  -jutil.map(cursory, 0, height, p1y, p2y);

// draw the number's path
// last position
int lx = cursorx;
int ly = cursory;
int px;
int py;

int i = 0;

// Z and C
if (type.equals("mandelbrot")) {
a = 0;
b = 0;
} else {
c = C;
d = D;
}
double asqr = a*a;
double bsqr = b*b;

// test for abs(Z) <= 2
while (asqr+bsqr <= 4.0) {
// Z -> Z**exp + C
if (exp == 2) {
b = 2*a*b+d;
a = asqr-bsqr+c;
}
else if (exp == 3) {
b = 3*asqr*b-bsqr*b+d;
a = asqr*a-3*a*bsqr+c;
}
else if (exp == 4) {
b = 4*asqr*a*b-4*a*bsqr*b+d;
a = asqr*asqr-6*asqr*bsqr+bsqr*bsqr+c;
}
else if (exp == 5) {
b = 5*asqr*asqr*b-10*asqr*bsqr*b+bsqr*bsqr*b+d;
a = asqr*asqr*a-10*asqr*a*bsqr+5*a*bsqr*bsqr+c;
}

// do not do squaring calculations too often, use variables instead
asqr = a*a;
bsqr = b*b;

// draw line
if (show_path) {
px = (int) jutil.map(a, p1x, p2x, 0, width);

py = (int) jutil.map(-b, p1y, p2y, 0, height);
g.drawLine(lx, ly, px, py);
lx = px;
ly = py;
}

// one more iteration needed
i++;

// too many iterations needed, close enough to being inside the set
if (i > 254) {
break;
}
}

// axes
if (show_axes) {
g.drawLine(jutil.mapint( 0, p1x, p2x, 0, width), jutil.mapint( 10, p1y, p2y, 0, height), jutil.mapint(  0, p1x, p2x, 0, width), (int) jutil.map( -10, p1y, p2y, 0, height));
g.drawLine(jutil.mapint(10, p1x, p2x, 0, width), jutil.mapint(  0, p1y, p2y, 0, height), jutil.mapint(-10, p1x, p2x, 0, width), (int) jutil.map(   0, p1y, p2y, 0, height));
g.drawLine(jutil.mapint(-2, p1x, p2x, 0, width), jutil.mapint(.01, p1y, p2y, 0, height), jutil.mapint( -2, p1x, p2x, 0, width), (int) jutil.map(-.01, p1y, p2y, 0, height));
g.drawLine(jutil.mapint( 2, p1x, p2x, 0, width), jutil.mapint(.01, p1y, p2y, 0, height), jutil.mapint(  2, p1x, p2x, 0, width), (int) jutil.map(-.01, p1y, p2y, 0, height));
}

// draw current complex number
if (show_number) {
g.drawString(c + (d<0 ? " - ":" + ") + (d<0 ? -d:d) + "i" + (i<255 ? " (outside)":" (inside)"), cursorx + 10, cursory - 5);
}

String[] strs = {};
// mandelbrot set
if (isfractal("mandelbrot")) {
strs = new String[] {
"f_c(z) = z^" + exp + " + c; " + type,
"tl = " + p1x + (p1y<0 ? "":"+") + p1y + "i",
"br = " + p2x + (p2y<0 ? "":"+") + p2y + "i",
"",
"decrement history length [" + KeyEvent.getKeyText(key_historyback) + " back]: " + history.size(),
"show path [" + KeyEvent.getKeyText(key_show_path) + "]: " + show_path,
"show axes [" + KeyEvent.getKeyText(key_show_axes) + "]: " + show_axes,
"show number [" + KeyEvent.getKeyText(key_show_number) + "]: " + show_number,
"",
"increment exponent [" + KeyEvent.getKeyText(key_increment_exp) + "]: " + exp,
"switch fractal [" + KeyEvent.getKeyText(parent.key_switch) + "]: " + type,
"show julia [" + KeyEvent.getKeyText(key_show_julia) + "]: " + show_julia,
"increment color depth [" + KeyEvent.getKeyText(key_increment_colordepth) + "]: " + colordepth,
"switch color mode [" + KeyEvent.getKeyText(key_switch_colormode) + "]: " + colormode,
"",
"save image [" + KeyEvent.getKeyText(parent.key_save) + "]",
"zoom reset [" + KeyEvent.getKeyText(key_zoomreset) + "]",
"swap fullscreen [" + KeyEvent.getKeyText(parent.key_fullscreen) + "/" +  KeyEvent.getKeyText(parent.key_fullscreen2) + "], resolution (" + width + "x" + height + ")",
"",
"quit [" + KeyEvent.getKeyText(parent.key_quit) + "]"
};
}

// filled julia set
else {
strs = new String[] {
"f_c(z) = z^" + exp + " + c; " + type + "; c = " + C + (D<0 ? "":"+") + D + "i",
"tl = " + p1x + (p1y<0 ? "":"+") + p1y + "i",
"br = " + p2x + (p2y<0 ? "":"+") + p2y + "i",
"",
"decrement history length [" + KeyEvent.getKeyText(key_historyback) + " back]: " + history.size(),
"show path [" + KeyEvent.getKeyText(key_show_path) + "]: " + show_path,
"show axes [" + KeyEvent.getKeyText(key_show_axes) + "]: " + show_axes,
"show number [" + KeyEvent.getKeyText(key_show_number) + "]: " + show_number,
"",
"//",
"switch fractal [" + KeyEvent.getKeyText(parent.key_switch) + "]: " + type,
"//",
"increment color depth [" + KeyEvent.getKeyText(key_increment_colordepth) + "]: " + colordepth,
"switch color mode [" + KeyEvent.getKeyText(key_switch_colormode) + "]: " + colormode,
"",
"save image [" + KeyEvent.getKeyText(parent.key_save) + "]",
"zoom reset [" + KeyEvent.getKeyText(key_zoomreset) + "]",
"swap fullscreen [" + KeyEvent.getKeyText(parent.key_fullscreen) + "/" +  KeyEvent.getKeyText(parent.key_fullscreen2) + "], resolution (" + width + "x"+ height + ")",
"",
"quit [" + KeyEvent.getKeyText(parent.key_quit) + "]"
};
}

jutil.textblock(g, strs);
}

// destroy graphics object
g.dispose();

// refresh jframe
parent.refresh(img);
}

// generate filled julia set image (used for preview)
private BufferedImage juliaimg(double C, double D, int width, int height, double p1x, double p1y, double p2x, double p2y) {
return fractalimg("julia", width, height, p1x, p1y, p2x, p2y, C, D);
}

// generate the full-sized fractal image
private BufferedImage fractalimg(String type, int width, int height, double p1x, double p1y, double p2x, double p2y, double C, double D) {
// init image
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

// map pixel coordinate to complex number
double facx = (p2x-p1x)/ width;
double facy = (p2y-p1y)/height;

// Z, a**2, b**2, C, iterations needed
double a, b, asqr, bsqr, c, d;
int i;

// go through the whole pixel space
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
// iterations
i = 0;
if (type.equals("mandelbrot")) {
i--;
}
a = 0;
b = 0;
c = C;
d = D;

// Z, a**2 and b**2
if (type.equals("mandelbrot")) {
}
else if (type.equals("julia")) {
}
asqr = a*a;
bsqr = b*b;

// test for abs(Z) <= 2
while (asqr+bsqr <= 4.0) {
// Z -> Z**exp + C
if (exp == 2) {
b = 2*a*b+d;
a = asqr-bsqr+c;
}
else if (exp == 3) {
b = 3*asqr*b-bsqr*b+d;
a = asqr*a-3*a*bsqr+c;
}
else if (exp == 4) {
b = 4*asqr*a*b-4*a*bsqr*b+d;
a = asqr*asqr-6*asqr*bsqr+bsqr*bsqr+c;
}
else if (exp == 5) {
b = 5*asqr*asqr*b-10*asqr*bsqr*b+bsqr*bsqr*b+d;
a = asqr*asqr*a-10*asqr*a*bsqr+5*a*bsqr*bsqr+c;
}

// do not do squaring calculations too often, use variables instead
asqr = a*a;
bsqr = b*b;

// one more iteration needed
i++;

// too many iterations needed, close enough to being inside the set
if (i >= colordepth-1) {
break;
}
}
// set the pixel
img.setRGB(x, y, colors[i]);
}
}

// return the image
return img;
}
}```