public void render(Image image, Parameters params) {
        int width = image.getWidth(null);
        int height = image.getHeight(null);
        if (width == -1 || height == -1) {
            // Image is not ready yet.
            throw new IllegalArgumentException("image not loaded");
        }
        Graphics g = image.getGraphics();

        double minX = params.getMinX().doubleValue();
        double maxX = params.getMaxX().doubleValue();
        double minY = params.getMinY().doubleValue();
        double maxY = params.getMaxY().doubleValue();
        double dx = (maxX - minX) / width;
        double dy = (maxY - minY) / height;
        int dwellLimit = 100;
        // avoid using sqrt() repeatedly by squaring the escape radius.
        double escapeRadius = 4.0; // 2.0 ^ 2
        boolean interrupted = false;
        for (int x = 0; x < width; x++) {
            double cr = dx * x + minX;
            for (int y = 0; y < height; y++) {
                double ci = dy * y + minY;
                double zr = cr;
                double zi = ci;
                double m;
                int iter = 1;

                do {
                    // z = z * z + c
                    double r = zr * zr - zi * zi;
                    zi = 2.0 * zr * zi + ci;
                    zr = r + cr;
                    // magnitude (would use sqrt() normally)
                    m = zr * zr + zi * zi;
                    iter++;
                } while (m < escapeRadius && iter < dwellLimit);

                float h = (float) iter / (float) dwellLimit;
                float b = 1.0f - h * h;
                g.setColor(Color.getHSBColor(h, 0.8f, b));
                g.drawLine(x, y, x, y);
            }

            if (Thread.interrupted()) {
                interrupted = true;
                break;
            }
            if (x % 25 == 0) {
                fireUpdate(100 * x / width);
            }
        }

        if (!interrupted) {
            fireUpdate(100);
        }
    }