Skapa konst genom att programmera

Med lite enkel programmering och mer eller mindre godtycklig matematik kan man skapa vackra mönster.

Programmering kan användas till mycket. En kul grej man kan göra är att skapa små konstverk genom att låta datorn generera fram abstrakta mönster med mer eller mindre godtyckligt valda operationer på färger. Jag skrev en liten testbänk för detta:

package com.westbahr.art;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class ArtPanel extends JPanel {
    
    private static final long serialVersionUID = 1L;
    
    private BufferedImage image;
    
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        int w = getWidth();
        int h = getHeight();
        BufferedImage image = getImage(w, h);
        g.drawImage(image, 0, 0, null);
    }
    
    private synchronized
            BufferedImage
            getImage(int w, int h) {
        if (image == null)
            createTheImage(w, h);
        return image;
    }
    
    private void createTheImage(final int w, final int h) {
        image =
                new BufferedImage(
                        w,
                        h,
                        BufferedImage.TYPE_INT_ARGB);
        new Thread() {
            
            public void run() {
                for (int x = 0; x < w; x++) {
                    for (int y = 0; y < h; y++) {
                        Color color =
                                getColorForPixel(w, h, x, y);
                        image.setRGB(x, y, color.getRGB());
                    }
                    repaint();
                }
            }
        }.start();
    }
    
    private Color getColorForPixel(
            int w,
            int h,
            int x,
            int y) {
        return getColorForPixel((x + 0.5) / w, (y + 0.5)
                / h);
    }
    
    private Color getColorForPixel(double x, double y) {
        double distanceFromCenter = 0.1;
        double angle0 = 0 * 2 * Math.PI / 3;
        double angle1 = 1 * 2 * Math.PI / 3;
        double angle2 = 2 * 2 * Math.PI / 3;
        int r =
                safeRange(128 + 128 * Math.cos(121 * Math
                        .pow(Math.hypot(x
                                - 0.5
                                + distanceFromCenter
                                * Math.cos(angle0), y
                                - 0.5
                                + distanceFromCenter
                                * Math.sin(angle0)), 2)));
        int g =
                safeRange(128 + 128 * Math.cos(121 * Math
                        .pow(Math.hypot(x
                                - 0.5
                                + distanceFromCenter
                                * Math.cos(angle1), y
                                - 0.5
                                + distanceFromCenter
                                * Math.sin(angle1)), 2)));
        int b =
                safeRange(128 + 128 * Math.cos(121 * Math
                        .pow(Math.hypot(x
                                - 0.5
                                + distanceFromCenter
                                * Math.cos(angle2), y
                                - 0.5
                                + distanceFromCenter
                                * Math.sin(angle2)), 2)));
        return new Color(r, g, b);
    }
    
    private int safeRange(double d) {
        return (int) Math.round(Math.max(
                0,
                Math.min(255, d)));
    }
    
    public static void main(String[] args) {
        JFrame frame = new JFrame("Java Art by Westbahr");
        final ArtPanel art = new ArtPanel();
        art.setPreferredSize(new Dimension(640, 640));
        frame
                .getContentPane()
                .add(art, BorderLayout.CENTER);
        frame
                .setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }
    
}

Operationerna i getColorForPixel(x, y) har jag bara testat mig fram och lekt lite för att se vad som händer. Jag landade till slut på koden ovan vilket producerade följande resultat:

Ganska snyggt, om jag får säga det själv! Det är bara att ändra lite hur som helst och se vad som händer för att få fram andra och kanske snyggare bilder.

Ännu roligare kan det bli om man inte bara betraktar färger som RGB (Red, Green, Blue) utan också uttrycker dem i HLS (Hue, Lightness, Saturation). Det är bara ett annat sätt att uttrycka samma färger där man istället för att uttrycka hur mycket det ska finnas av respektive grundfärg (rött, grönt och blått) specificerar en färg som sin nyans, ljushet och mättnad. Jag har skapat klassen DoubleColor, i vilken man kan  ange färger antingen med RGB, HLS eller en blandning av dessa. Den lagrar dessutom värdena i double-precision (mellan 0 och 1, inte mellan 0 och 255), vilket tar bort de avrundningsfel som annars kan byggas upp om man gör många komplicerade operationer.

Genom att använda DoubleColor testade jag vad som hände om jag inverterade mättnaden, vilket gav en ganska snygg effekt:

    private Color getColorForPixel(double x, double y) {
        double distanceFromCenter = 0.1;
        double angle0 = 0 * 2 * Math.PI / 3;
        double angle1 = 1 * 2 * Math.PI / 3;
        double angle2 = 2 * 2 * Math.PI / 3;
        double r =
                0.5 + 0.5 * Math.cos(64 * Math.pow(
                        Math.hypot(x
                                - 0.5
                                + distanceFromCenter
                                * Math.cos(angle0), y
                                - 0.5
                                + distanceFromCenter
                                * Math.sin(angle0)),
                        2));
        double g =
                0.5 + 0.5 * Math.cos(64 * Math.pow(
                        Math.hypot(x
                                - 0.5
                                + distanceFromCenter
                                * Math.cos(angle1), y
                                - 0.5
                                + distanceFromCenter
                                * Math.sin(angle1)),
                        2));
        double b =
                0.5 + 0.5 * Math.cos(64 * Math.pow(
                        Math.hypot(x
                                - 0.5
                                + distanceFromCenter
                                * Math.cos(angle2), y
                                - 0.5
                                + distanceFromCenter
                                * Math.sin(angle2)),
                        2));
        DoubleColor dc =
                new DoubleColor(r * g, g * b, b * r);
        double oldS = dc.getS();
        dc.setS(dc.getL());
        dc.setL(1 - oldS);
        return dc.getColor();
    }

Den kompletta klassen ArtPanel. Jag har också skapat ett litet galleri med olika bilder som skapats med klassen.

Skapa konst genom att programmera

Om bloggaren

Marcus Björkander

Marcus Björkander

Schlagernörd och småbarnspappa med tvångstankar som jobbar som utvecklare på Westbahr i Göteborg. Favoritspråket är Java, som han tidigare har undervisat i vid Chalmers i många år.

 

Nyckelord/tag moln