Created
November 5, 2012 04:44
-
-
Save sushovande/4015383 to your computer and use it in GitHub Desktop.
Create a checkered background image
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
// example output: http://imgur.com/dSix8 | |
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.Threading.Tasks; | |
using System.Drawing; | |
namespace CreateColorfulBackgrounds | |
{ | |
class Program | |
{ | |
/// <summary> | |
/// The dimensions of the checkers | |
/// </summary> | |
const int squareSide = 70; | |
/// <summary> | |
/// The color of the square on the top middle | |
/// </summary> | |
static Color squareStartColor = Color.FromArgb(145, 211, 20); | |
/// <summary> | |
/// The color of the square on the bottom edges | |
/// </summary> | |
static Color squareEndColor = Color.FromArgb(22, 55, 10); | |
/// <summary> | |
/// The color of the edge of the square on the top-middle | |
/// </summary> | |
static Color borderStartColor = Color.FromArgb(121, 187, 0); | |
/// <summary> | |
/// The color of the edge on the bottom fringes | |
/// </summary> | |
static Color borderEndColor = Color.FromArgb(14, 45, 3); | |
/// <summary> | |
/// Smoothing factor for the gradient. Higher values give a sharper transition. | |
/// </summary> | |
const double smoothingFactor = 3; | |
/// <summary> | |
/// How much the colors vary in the checkers. | |
/// </summary> | |
const double randomness = 0.15; | |
/// <summary> | |
/// Although the randomness was supposed to be 0-biased, I found that giving it a small offset helped. | |
/// </summary> | |
const double randomnessDcOffset = 0.2; | |
static Random rnd = new Random(); | |
static void Main(string[] args) | |
{ | |
CreateBackground(1680, 1050); | |
} | |
/// <summary> | |
/// Creates a background of the specified width and height | |
/// </summary> | |
static void CreateBackground(int width, int height) | |
{ | |
Bitmap bmp = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb); | |
var bmp_data = bmp.LockBits(new Rectangle(0, 0, width, height), | |
System.Drawing.Imaging.ImageLockMode.WriteOnly, | |
bmp.PixelFormat); | |
int bytes = Math.Abs(bmp_data.Stride) * height; | |
byte[] rgbValues = new byte[bytes]; | |
FillValues(rgbValues, width, height, bmp_data.Stride); | |
System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, bmp_data.Scan0, bytes); | |
bmp.Save("foo.png", System.Drawing.Imaging.ImageFormat.Png); | |
} | |
/// <summary> | |
/// First creates a smooth radial gradient to serve as the dark borders, then fills the image with checkers | |
/// </summary> | |
/// <param name="rgbValues">The array of bytes that form the image</param> | |
/// <param name="width">width of the image</param> | |
/// <param name="height">height of the image</param> | |
/// <param name="stride">The stride of the bitmap bits</param> | |
private static void FillValues(byte[] rgbValues, int width, int height, int stride) | |
{ | |
GradientFillRect(new Rectangle(0, 0, width, height), new Point(width / 2, 0), new Point(0, height), borderStartColor, borderEndColor, rgbValues, stride); | |
CheckerFillSquares(rgbValues, width, height, stride); | |
} | |
/// <summary> | |
/// Fills an area of the bitmap with a series of squares, randomly colored | |
/// </summary> | |
/// <param name="rgbValues">The array of bytes that form the image</param> | |
/// <param name="width">width of the image</param> | |
/// <param name="height">height of the image</param> | |
/// <param name="stride">The stride of the bitmap bits</param> | |
private static void CheckerFillSquares(byte[] rgbValues, int width, int height, int stride) | |
{ | |
int midx = width / squareSide / 2; // the starting point of the radial gradient | |
int midy = -4; | |
double maxt = GetDist(midx, midy, 0, height / squareSide); // the maximum possible param value we will have | |
for (int y = 0; y < height / squareSide; y++) | |
{ | |
for (int x = 0; x < width / squareSide; x++) | |
{ | |
double t = Shape(GetDist(midx, midy, x, y) / maxt); // find the interpolation parameter | |
t += (rnd.NextDouble() - 0.5) * randomness - randomnessDcOffset; | |
Color tcol = Color.FromArgb( | |
(byte)(squareStartColor.R * (1 - t) + squareEndColor.R * t), | |
(byte)(squareStartColor.G * (1 - t) + squareEndColor.G * t), | |
(byte)(squareStartColor.B * (1 - t) + squareEndColor.B * t)); // find the interpolated color | |
FillRect(new Rectangle(x * squareSide + 1, y * squareSide + 1, squareSide - 2, squareSide - 2), rgbValues, stride, tcol); | |
} | |
} | |
} | |
/// <summary> | |
/// Fills a rectangle with a radial gradient | |
/// </summary> | |
/// <param name="rectangle">The rectangle to fill. Not bounds checked.</param> | |
/// <param name="point1">The starting point of the radial gradient</param> | |
/// <param name="point2">The ending point of the radial gradient</param> | |
/// <param name="color1">The color of the first point of the radial gradient</param> | |
/// <param name="color2">The color of the second point of the radial gradient</param> | |
/// <param name="rgbValues">The array of bytes that form image</param> | |
/// <param name="stride">The stride of the bitmap bits</param> | |
private static void GradientFillRect(Rectangle rectangle, Point point1, Point point2, Color color1, Color color2, byte[] rgbValues, int stride) | |
{ | |
double maxt = GetDist(point1.X, point1.Y, point2.X, point2.Y); | |
for (int y = rectangle.Top; y < rectangle.Bottom; y++) | |
{ | |
for (int x = rectangle.Left; x < rectangle.Right; x++) | |
{ | |
double t = Shape(GetDist(x, y, point1.X, point1.Y) / maxt); | |
Color tcol = Color.FromArgb( | |
(byte)(color1.R * (1 - t) + color2.R * t), | |
(byte)(color1.G * (1 - t) + color2.G * t), | |
(byte)(color1.B * (1 - t) + color2.B * t)); // find the interpolated color | |
rgbValues[y * stride + 4 * x + 0] = tcol.B; | |
rgbValues[y * stride + 4 * x + 1] = tcol.G; | |
rgbValues[y * stride + 4 * x + 2] = tcol.R; | |
rgbValues[y * stride + 4 * x + 3] = 255; | |
} | |
} | |
} | |
/// <summary> | |
/// Shaping function for the parameter, smooths it using a sigmoid function | |
/// </summary> | |
/// <param name="p">The parameter to shape, between 0 and 1</param> | |
/// <returns>a new smoothed param, between 0 and 1</returns> | |
private static double Shape(double p) | |
{ | |
return 1.0 / (1 + Math.Exp(-smoothingFactor * (p - 0.5) * 2)); | |
} | |
/// <summary> | |
/// FInds the Euclidean distance between two points | |
/// </summary> | |
private static double GetDist(int x1, int y1, int x2, int y2) | |
{ | |
int d2 = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2); | |
return Math.Sqrt(d2); | |
} | |
/// <summary> | |
/// Fills in a rectangle with a single color | |
/// </summary> | |
/// <param name="rectangle">The area of the bits to fill. NOT bounds checked.</param> | |
/// <param name="rgbValues">an array of bytes locked from the bitmap</param> | |
/// <param name="stride">stride of the bitmap</param> | |
/// <param name="color">the color to fill it with</param> | |
private static void FillRect(Rectangle rectangle, byte[] rgbValues, int stride, Color color) | |
{ | |
for (int y = rectangle.Top; y < rectangle.Bottom; y++) | |
{ | |
for (int x = rectangle.Left; x < rectangle.Right; x++) | |
{ | |
rgbValues[y * stride + 4 * x + 0] = color.B; | |
rgbValues[y * stride + 4 * x + 1] = color.G; | |
rgbValues[y * stride + 4 * x + 2] = color.R; | |
rgbValues[y * stride + 4 * x + 3] = color.A; | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment