Last active
December 13, 2015 16:49
-
-
Save calebegg/4942742 to your computer and use it in GitHub Desktop.
Code used to automatically generate some wallpapers I use. Here are four examples: http://imgur.com/a/7b7z2
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import javax.imageio.ImageIO; | |
import javax.swing.*; | |
import java.awt.*; | |
import java.awt.event.MouseAdapter; | |
import java.awt.event.MouseEvent; | |
import java.awt.image.BufferedImage; | |
import java.io.File; | |
import java.io.IOException; | |
import java.util.Random; | |
class Wallpaper extends JComponent { | |
private final int SIZE = 40; | |
private Color[][][] colors = new Color[SIZE][SIZE][2]; | |
private boolean[][] orient = new boolean[SIZE][SIZE]; | |
private float hue1, hue2; | |
private final int width; | |
private final int height; | |
public Wallpaper(int width, int height) { | |
this.width = width; | |
this.height = height; | |
setPreferredSize(new Dimension(1366, 768)); | |
generateWallpaper(); | |
addMouseListener(new MouseAdapter() { | |
@Override | |
public void mouseClicked(MouseEvent mouseEvent) { | |
generateWallpaper(); | |
repaint(); | |
} | |
}); | |
} | |
public void generateWallpaper() { | |
colors = new Color[SIZE][SIZE][2]; | |
Random rng = new Random(); | |
float hueDiff = .3f; | |
hue1 = rng.nextFloat() * (1 - hueDiff); | |
hue2 = hue1 + rng.nextFloat() * hueDiff; | |
int randomFactor = 4; // Higher for more similarity along the row or column. | |
final float satLowerBound = .2f; | |
for (int i = 0; i < SIZE; i++) { | |
float[] sats = new float[] { rng.nextFloat(), rng.nextFloat() }; | |
float[] lums = new float[] { rng.nextFloat(), rng.nextFloat() }; | |
for (int j = 0; j < SIZE; j++) { | |
for (int k = 0; k < 2; k++) { | |
// Do this twice; once for row x, and once for column x. | |
boolean b = k == 0; | |
int x, y; | |
if (b) { | |
x = i; | |
y = j; | |
} else { | |
x = j; | |
y = i; | |
} | |
Color oldColor = colors[x][y][0]; | |
Color newColor = Color.getHSBColor(b ? hue1 : hue2, sats[k], lums[k]); | |
newColor = average(oldColor, newColor); | |
colors[x][y][0] = newColor; | |
float[] newParts = Color.RGBtoHSB(newColor.getRed(), newColor.getGreen(), | |
newColor.getBlue(), | |
new float[3]); | |
float newLum = newParts[2]; | |
// Other half of square has same hue + sat, but slightly different | |
// brightness. | |
colors[x][y][1] = Color.getHSBColor(newParts[0], newParts[1], | |
newLum + (newLum > .5 ? -.1f : .1f)); | |
sats[k] += rng.nextFloat() / randomFactor - .5 / randomFactor; | |
lums[k] += rng.nextFloat() / randomFactor - .5 / randomFactor; | |
// Sat and lum values should be bounded. | |
if (sats[k] > 1) sats[k] = 1; | |
if (sats[k] < satLowerBound) sats[k] = satLowerBound; | |
if (lums[k] > 1) lums[k] = 1; | |
if (lums[k] < 0) lums[k] = 0; | |
} | |
orient[j][i] = rng.nextBoolean(); | |
} | |
} | |
} | |
private Color average(Color a, Color b) { | |
// Combines two colors in a reasonable way; weighted average of hues, | |
// average saturation, and the max brightness. | |
if (a == null) return b; | |
if (b == null) return a; | |
float[] aComp = new float[3]; | |
float[] bComp = new float[3]; | |
Color.RGBtoHSB(a.getRed(), a.getGreen(), a.getBlue(), aComp); | |
Color.RGBtoHSB(b.getRed(), b.getGreen(), b.getBlue(), bComp); | |
float aHue = aComp[0]; | |
float bHue = bComp[0]; | |
float aSat = aComp[1]; | |
float bSat = bComp[1]; | |
float newHue = (aHue * aSat + bHue * bSat) / (aSat + bSat); // Average, weighted by sat | |
if (newHue > 1) newHue = 1; | |
return Color.getHSBColor(newHue, | |
(aSat + bSat) / 2, Math.max(aComp[2], bComp[2])); | |
} | |
@Override public void paintComponent(Graphics gOld) { | |
Graphics2D g = (Graphics2D) gOld; | |
int maxdim = Math.max(width, height); | |
int spacing = maxdim * 2 / SIZE; | |
g.translate(maxdim / 2, -maxdim / 2); | |
g.rotate(Math.PI / 4); | |
for (int r = 0; r < SIZE; r++) { | |
for (int c = 0; c < SIZE; c++) { | |
int top = r * spacing; | |
int bottom = (r + 1) * spacing; | |
int left = c * spacing; | |
int right = (c + 1) * spacing; | |
g.setColor(colors[r][c][0]); | |
g.fillPolygon(new int[] {left, left, right}, | |
new int[] {top, bottom, orient[r][c] ? bottom : top}, 3); | |
g.setColor(colors[r][c][1]); | |
g.fillPolygon(new int[] {left, right, right}, | |
new int[] {orient[r][c] ? top : bottom, top, bottom}, 3); | |
} | |
} | |
g.rotate(-Math.PI / 4); | |
g.translate(-maxdim / 2, maxdim / 2); | |
// Paint some swatches of the fully-saturated hues used to generate this wall. | |
// g.setColor(Color.getHSBColor(hue1, 1, 1)); | |
// g.fill(new Ellipse2D.Double(0, 0, 30, 30)); | |
// g.setColor(Color.getHSBColor(hue2, 1, 1)); | |
// g.fill(new Ellipse2D.Double(0, 30, 30, 30)); | |
} | |
} | |
public class Main { | |
private static boolean GENERATE_FILES = false; | |
public static void main(String[] args) { | |
int width = 1366; | |
int height = 768; | |
Wallpaper w = new Wallpaper(width, height); | |
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); | |
if (GENERATE_FILES) { | |
try { | |
for (int i = 0; i < 50; i++) { | |
w.generateWallpaper(); | |
w.paintComponent(bi.getGraphics()); | |
ImageIO.write(bi, "png", new File("wallpaper_" + i + ".png")); | |
} | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} | |
} else { | |
JFrame f = new JFrame("Wallpaper"); | |
f.add(w); | |
f.pack(); | |
f.setVisible(true); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment