First 100 Numbers Poster C# Generator
This simple C# program generates some nice posters containing numbers, e.g. from 1 to 100, highlighting specific numbers like powers of 2, primes and fibonacci numbers. Inspiration for this mini-project were two little kids and a wooden hundred-board with numbers, then the idea was extrapolated and this is how such generated PNGs look like:
Larger PNG images for download: 100-deca-only , 256-hexa-only , 100-deca-special , 256-hexa-special
You can download the project (Visual Studio 2017 Windows Forms application) ZIP file here: hundredBoard.zip
If you like the generator, you can adapt it and print some nice large posters on a fancy color printer. This is how you can customize some input parameters:
See the code below for more details (you can create new project in VS and paste this code to replace Form.cs):
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Drawing.Text;
using System.Linq;
using System.Windows.Forms;
namespace hundredBoard
{
public partial class NumbersForm : Form
{
public bool GenerateHexa = false; //whether generate 100 board e.g. from 1 to 100, or generate 256 hexa board e.g. from 0 do FF (255)
public bool DrawSpecialNumbers = true; //whether display primes, fibonaccis and powers of 2
public int SettingResizeFactor = 100; //for large bitmaps (e.g. for printing), use 200
public int SettingStroke = 4; //percentage how thick the stroke effect is
public int TotalLines;
public int NumbersPerLine;
public int NumberShift;
public int SettingTextSizeFactor;
public Bitmap GeneratedBitmap;
public readonly SortedSet FibonacciListInt32 = new SortedSet
{
0, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229,
832040, 1346269, 2178309, 3524578, 5702887, 9227465, 14930352, 24157817, 39088169, 63245986, 102334155, 165580141, 267914296, 433494437, 701408733,
1134903170, 1836311903 // 2971215073 is already too big for int32 (and is a prime number)
};
public NumbersForm()
{
InitializeComponent();
//set these values to display desired numbers
TotalLines = 10;
NumbersPerLine = 10;
NumberShift = 1; //we start from 1 (don't go over 1000)
if (GenerateHexa)
{
TotalLines = 16;
NumbersPerLine = 16;
NumberShift = 0; //when generating hexa, let's start from 0 (and the last number will be e.g. FF)
}
//set dimension of the generated image
generatedPictureBox.Width = 1 + (NumbersPerLine * 200 * SettingResizeFactor) / 100;
generatedPictureBox.Height = 1 + (TotalLines * 200 * SettingResizeFactor) / 100;
GeneratedBitmap = new Bitmap(generatedPictureBox.Width, generatedPictureBox.Height);
var graphics = Graphics.FromImage(GeneratedBitmap);
graphics.SmoothingMode = SmoothingMode.AntiAlias;
DrawStuff(graphics); //generate image
GeneratedBitmap.Save(GenerateHexa ? "hexaBoard.png" : "decaBoard.png", ImageFormat.Png); //save image to file
panel1.AutoScroll = true; //display image
generatedPictureBox.SizeMode = PictureBoxSizeMode.AutoSize;
generatedPictureBox.Image = GeneratedBitmap;
}
//Draws numbers table (core method)
public void DrawStuff(Graphics g)
{
g.TextRenderingHint = TextRenderingHint.AntiAlias;
var sf = new StringFormat
{
LineAlignment = StringAlignment.Center,
Alignment = StringAlignment.Center
};
//calculate some settings for positioning of elements
SettingTextSizeFactor = 90;
var fontNormal = new Font("calibri", (float)SettingTextSizeFactor * SettingResizeFactor / 100, FontStyle.Bold);
if (GenerateHexa)
{
fontNormal = new Font("calibri", (float)SettingTextSizeFactor * SettingResizeFactor / 120, FontStyle.Bold);
}
var font100 = new Font("calibri", (float)SettingTextSizeFactor * SettingResizeFactor / 150, FontStyle.Bold);
var fontMini = new Font("calibri", (float)SettingTextSizeFactor * SettingResizeFactor / 200, FontStyle.Bold);
//drawing squares
for (var i = 0; i < NumbersPerLine; i++)
{
for (var j = 0; j < TotalLines; j++)
{
int number = i + j * NumbersPerLine + NumberShift; //which number is being drawn
string decnumber = number.ToString();
string hexnumber = number.ToString("X").ToUpper();
string displaynumber = decnumber;
if (GenerateHexa) displaynumber = hexnumber;
int x = (200 * i * SettingResizeFactor) / 100; //x position
int y = (200 * j * SettingResizeFactor) / 100; //y position
int stroke0 = (SettingStroke * SettingResizeFactor) / 100; //outside stroke effect
Font font = fontNormal;
if (number >= NumbersPerLine * NumbersPerLine)
{
font = font100;
}
//render square inside
Brush brush = Brushes.CornflowerBlue;
if (GenerateHexa)
{
brush = Brushes.LimeGreen;
}
g.FillRectangle(brush, x, y, (200 * SettingResizeFactor) / 100, (200 * SettingResizeFactor) / 100);
//if prime
if (IsPrime(number))
{
var brush2 = GenerateHexa ? Brushes.DarkGreen : Brushes.DarkBlue;
g.FillRectangle(brush2, x + (10 * SettingResizeFactor) / 100, y + (10 * SettingResizeFactor) / 100, (180 * SettingResizeFactor) / 100, (180 * SettingResizeFactor) / 100);
}
int size2n = 64;
//render 2^n background
if (GenerateHexa)
{
if (IsPowerOfTwo(Convert.ToUInt64(number)))
{
Brush brush3 = Brushes.Red;
Pen pen3 = new Pen(Color.Red, 0);
DrawAndFillRoundedRectangle(g, pen3, brush3,
new Rectangle(x + ((200 - 10 - size2n) * SettingResizeFactor) / 100, y + (10 * SettingResizeFactor) / 100, (size2n * SettingResizeFactor) / 100, (size2n * SettingResizeFactor) / 100),
(32 * SettingResizeFactor) / 100, (32 * SettingResizeFactor) / 100, RectAngles.All);
}
//if fibonacci
if (DrawSpecialNumbers)
{
if (FibonacciListInt32.Contains(number))
{
Brush brush3 = new SolidBrush(Color.FromArgb(255, 255, 48, 0));
Pen pen3 = new Pen(Color.FromArgb(255, 255, 48, 0), 0);
DrawAndFillRoundedRectangle(g, pen3, brush3,
new Rectangle(x + ((10) * SettingResizeFactor) / 100, y + (10 * SettingResizeFactor) / 100, (size2n * SettingResizeFactor) / 100, (size2n * SettingResizeFactor) / 100),
(32 * SettingResizeFactor) / 100, (32 * SettingResizeFactor) / 100, RectAngles.All);
}
}
}
//render square frame
Pen pen = new Pen(Color.Black, 1);
g.DrawRectangle(pen, x, y, (200 * SettingResizeFactor) / 100, (200 * SettingResizeFactor) / 100);
//if 2^n
if (IsPowerOfTwo(Convert.ToUInt64(number)))
{
Brush brush2N = Brushes.White;
if (GenerateHexa)
{
brush2N = Brushes.Yellow;
}
if (GenerateHexa)
{
g.DrawString("2", fontMini, brush2N, new Rectangle(x + (133 * SettingResizeFactor) / 100, y + (5 * SettingResizeFactor) / 100, (200 * SettingResizeFactor) / 100, (200 * SettingResizeFactor) / 100));
}
else
{
g.DrawString("2", fontMini, brush2N, new Rectangle(x + (133 * SettingResizeFactor) / 100, y + (5 * SettingResizeFactor) / 100, (200 * SettingResizeFactor) / 100, (200 * SettingResizeFactor) / 100));
Pen pen2 = new Pen(Color.White, 2 * (float)SettingResizeFactor / 100);
DrawRoundedRectangle(g, pen2, x + ((200 - 10 - size2n) * SettingResizeFactor) / 100, y + (10 * SettingResizeFactor) / 100, (size2n * SettingResizeFactor) / 100, (size2n * SettingResizeFactor) / 100, (8 * SettingResizeFactor) / 100, (8 * SettingResizeFactor) / 100);
}
}
//if fibonacci (up to int32)
if (DrawSpecialNumbers)
{
if (FibonacciListInt32.Any(item => item == number))
{
Brush brush2N = Brushes.White;
if (GenerateHexa)
{
brush2N = new SolidBrush(Color.FromArgb(255, 255, 192, 96));
}
if (GenerateHexa)
{
g.DrawString("F", fontMini, brush2N,
new Rectangle(x + (17 * SettingResizeFactor) / 100,
y + (5 * SettingResizeFactor) / 100, (200 * SettingResizeFactor) / 100,
(200 * SettingResizeFactor) / 100));
}
else
{
g.DrawString("F", fontMini, brush2N,
new Rectangle(x + (17 * SettingResizeFactor) / 100,
y + (5 * SettingResizeFactor) / 100, (200 * SettingResizeFactor) / 100,
(200 * SettingResizeFactor) / 100));
Pen pen2 = new Pen(Color.White, 2 * (float)SettingResizeFactor / 100);
DrawRoundedRectangle(g, pen2, x + ((10) * SettingResizeFactor) / 100,
y + (10 * SettingResizeFactor) / 100, (size2n * SettingResizeFactor) / 100,
(size2n * SettingResizeFactor) / 100, (8 * SettingResizeFactor) / 100,
(8 * SettingResizeFactor) / 100);
}
}
}
//y has to be moved a bit lower
y = ((200 * j + 5) * SettingResizeFactor) / 100; //y
if (GenerateHexa)
{
y = ((200 * j) * SettingResizeFactor) / 100;
}
//render stroke effect0
if (stroke0 > 0)
{
for (var k = 0; k < stroke0; k++)
{
for (var m = 0; m < stroke0; m++)
{
if (k * k + m * m <= stroke0 * stroke0)
{
g.DrawString(displaynumber, font, Brushes.Black, new Rectangle(x + k, y + m, (200 * SettingResizeFactor) / 100, (200 * SettingResizeFactor) / 100), sf);
g.DrawString(displaynumber, font, Brushes.Black, new Rectangle(x + k, y - m, (200 * SettingResizeFactor) / 100, (200 * SettingResizeFactor) / 100), sf);
g.DrawString(displaynumber, font, Brushes.Black, new Rectangle(x - k, y + m, (200 * SettingResizeFactor) / 100, (200 * SettingResizeFactor) / 100), sf);
g.DrawString(displaynumber, font, Brushes.Black, new Rectangle(x - k, y - m, (200 * SettingResizeFactor) / 100, (200 * SettingResizeFactor) / 100), sf);
}
}
}
}
//render main text
g.DrawString(displaynumber, font, Brushes.White, new Rectangle(x, y, (200 * SettingResizeFactor) / 100, (200 * SettingResizeFactor) / 100), sf);
//render dec text in case of hex
if (GenerateHexa)
{
g.DrawString(decnumber, fontMini, Brushes.White, new Rectangle(x, y + (63 * SettingResizeFactor) / 100, (200 * SettingResizeFactor) / 100, (200 * SettingResizeFactor) / 100), sf);
}
}
}
}
//Calculates whether number is a prime number
private bool IsPrime(int number)
{
if (DrawSpecialNumbers)
{
if (number < 2) return false;
if (number % 2 == 0) return (number == 2);
var root = (int) Math.Sqrt(number);
for (var i = 3; i <= root; i += 2)
{
if (number % i == 0) return false;
}
return true;
}
return false;
}
//Calculates whether number is a power of 2 (elegant)
private bool IsPowerOfTwo(ulong x)
{
if (DrawSpecialNumbers)
{
return x != 0 && (x & (x - 1)) == 0;
}
return false;
}
//Draws rounded rectangle
private void DrawRoundedRectangle(Graphics g, Pen p, int x, int y, int w, int h, int rx, int ry)
{
GraphicsPath path = new GraphicsPath();
path.AddArc(x, y, rx + rx, ry + ry, 180, 90);
path.AddLine(x + rx, y, x + w - rx, y);
path.AddArc(x + w - 2 * rx, y, 2 * rx, 2 * ry, 270, 90);
path.AddLine(x + w, y + ry, x + w, y + h - ry);
path.AddArc(x + w - 2 * rx, y + h - 2 * ry, rx + rx, ry + ry, 0, 91);
path.AddLine(x + rx, y + h, x + w - rx, y + h);
path.AddArc(x, y + h - 2 * ry, 2 * rx, 2 * ry, 90, 91);
path.CloseFigure();
g.DrawPath(p, path);
}
private void Form1_Resize(object sender, EventArgs e)
{
panel1.Width = Width - 40;
panel1.Height = Height - 63;
}
[Flags]
public enum RectAngles
{
None = 0,
TopLeft = 1,
TopRight = 2,
BottomLeft = 4,
BottomRight = 8,
All = TopLeft | TopRight | BottomLeft | BottomRight
}
//Draws and fills rounded rectangle (source: probably stackoverflow :)
public void DrawAndFillRoundedRectangle(Graphics g, Pen p, Brush b, Rectangle r, int horizontalDiameter, int verticalDiameter, RectAngles rectAngles)
{
int x = r.X;
int y = r.Y;
int width = r.Width;
int height = r.Height;
// adapt horizontal and vertical diameter if the rectangle is too little
if (width < horizontalDiameter)
horizontalDiameter = width;
if (height < verticalDiameter)
verticalDiameter = height;
/*
* the drawing is as follows:
*
* a
* P______________Q
* h / \ b
* W / \R
* | |
* g | | c
* V| |S
* f\ / d
* U\______________/T
* e
*/
bool tl = (rectAngles & RectAngles.TopLeft) != 0,
tr = (rectAngles & RectAngles.TopRight) != 0,
br = (rectAngles & RectAngles.BottomRight) != 0,
bl = (rectAngles & RectAngles.BottomLeft) != 0;
Point pointP = tl ?
new Point(x + horizontalDiameter / 2, y) :
new Point(x, y);
Point pointQ = tr ?
new Point(x + width - horizontalDiameter / 2 - 1, y) :
new Point(x + width - 1, y);
Point pointR = tr ?
new Point(x + width - 1, y + verticalDiameter / 2) :
pointQ;
Point pointS = br ?
new Point(x + width - 1, y + height - verticalDiameter / 2 - 1) :
new Point(x + width - 1, y + height - 1);
Point pointT = br ?
new Point(x + width - horizontalDiameter / 2 - 1, y + height - 1) :
pointS;
Point pointU = bl ?
new Point(x + horizontalDiameter / 2, y + height - 1) :
new Point(x, y + height - 1);
Point pointV = bl ?
new Point(x, y + height - verticalDiameter / 2 - 1) :
pointU;
Point pointW = tl ?
new Point(x, y + verticalDiameter / 2) :
pointP;
using (GraphicsPath gp = new GraphicsPath())
{
// a
gp.AddLine(pointP, pointQ);
// b
if (tr)
gp.AddArc(x + width - horizontalDiameter - 1, y, horizontalDiameter, verticalDiameter, 270, 90);
// c
gp.AddLine(pointR, pointS);
// d
if (br)
gp.AddArc(x + width - horizontalDiameter - 1, y + height - verticalDiameter - 1, horizontalDiameter, verticalDiameter, 0, 90);
// e
gp.AddLine(pointT, pointU);
// f
if (bl)
gp.AddArc(x, y + height - verticalDiameter - 1, horizontalDiameter, verticalDiameter, 90, 90);
// g
gp.AddLine(pointV, pointW);
// h
if (tl)
gp.AddArc(x, y, horizontalDiameter, verticalDiameter, 180, 90);
// end
gp.CloseFigure();
// draw
if (b != null)
g.FillPath(b, gp);
if (p != null)
g.DrawPath(p, gp);
}
}
}
}