Home

PowerShell Convert Text to Braille Image

Leave a comment

Braille characters are small rectangular blocks called cells that contain tiny palpable bumps called raised dots. The number and arrangement of these dots distinguish one character from another. This script calls a Web Service from webservicex.net which translates text into an image of the Braille cells.

Text2Braille

The images created are interesting. They contain randomness but with a certain pattern because of the limited number of cells that can be formed.

Text2Braille_20150104_164737

The script starts with defining the main WinForms Form.

Add-Type -AssemblyName System.Windows.Forms
$scriptPath = split-path -parent $MyInvocation.MyCommand.Definition
$global:outFile = ""

# Main Form 
$mainForm = New-Object System.Windows.Forms.Form
$mainForm.Location = "200, 200"
$mainForm.Font = "Comic Sans MS,9"
$mainForm.FormBorderStyle = "FixedDialog"
$mainForm.Text = " Convert Text to Braille Image"
$mainForm.ForeColor = "White"
$mainForm.BackColor = "Wheat"
$mainForm.Size = "610, 410"

Next is added the Input TextBox and its Label.

# Input Text Label
$inputTextLabel = New-Object System.Windows.Forms.Label
$inputTextLabel.Location = "100,8"
$inputTextLabel.ForeColor = "MediumBlue"
$inputTextLabel.Size = "50, 22"
$inputTextLabel.Text = "Text"
$mainForm.Controls.Add($inputTextLabel)

# Input Text TextBox
$inputTextTextBox = New-Object System.Windows.Forms.TextBox
$inputTextTextBox.Location = "20,30"
$inputTextTextBox.Size = "230,330"
$inputTextTextBox.MultiLine = $true
$inputTextTextBox.ForeColor = "MediumBlue"
$inputTextTextBox.BackColor = "White"
$inputTextTextBox.Text = ""
$mainForm.Controls.Add($inputTextTextBox)

The PictureBox for outputting the returned image is created.

# PictureBox
$pictureBox = New-Object System.Windows.Forms.PictureBox
$pictureBox.Location = "260, 30"
$pictureBox.ClientSize = "230, 330"
$pictureBox.BackColor = "Black"
$pictureBox.SizeMode = "StretchImage"
$mainForm.Controls.Add($pictureBox)

# PictureBox Label
$PictureBoxLabel = New-Object System.Windows.Forms.Label
$PictureBoxLabel.Location = "350,8"
$PictureBoxLabel.ForeColor = "MediumBlue"
$PictureBoxLabel.Size = "110, 22"
$PictureBoxLabel.Text = "Braille"
$mainForm.Controls.Add($PictureBoxLabel)

Another TextBox for the Font Size is setup. Font Size in this context is the size of the Braille cells.

# Font Size Label
$fontSizeLabel = New-Object System.Windows.Forms.Label
$fontSizeLabel.Location = "500,130"
$fontSizeLabel.ForeColor = "MediumBlue"
$fontSizeLabel.Size = "60, 22"
$fontSizeLabel.Text = "Font Size"
$mainForm.Controls.Add($fontSizeLabel)

# Font Size TextBox
$fontSizeTextBox = New-Object System.Windows.Forms.TextBox
$fontSizeTextBox.Location = "560,130"
$fontSizeTextBox.Size = "30,20"
$fontSizeTextBox.ForeColor = "MediumBlue"
$fontSizeTextBox.BackColor = "White"
$fontSizeTextBox.Text = "18"
$mainForm.Controls.Add($fontSizeTextBox)

Finally three Buttons are defined, one each for calling the Web Service function, displaying the image and exiting the script.

# Generate Button
$generateButton = New-Object System.Windows.Forms.Button 
$generateButton.Location = "510,30"
$generateButton.Size = "75,28"
$generateButton.ForeColor = "DarkBlue"
$generateButton.BackColor = "White"
$generateButton.Text = "Convert"
$generateButton.add_Click({GetBraille($scriptPath)})
$mainForm.Controls.Add($generateButton)

# Display Button
$displayButton = New-Object System.Windows.Forms.Button
$displayButton.Location = "510,60"
$displayButton.Size = "75, 28"
$displayButton.BackColor = "White"
$displayButton.ForeColor = "DarkBlue" 
$displayButton.Text = "Display"
$displayButton.add_Click({DisplayImage})
$mainForm.Controls.Add($displayButton)

# Exit Button 
$exitButton = New-Object System.Windows.Forms.Button
$exitButton.Location = "510,90"
$exitButton.Size = "75,28"
$exitButton.ForeColor = "Red"
$exitButton.BackColor = "White"
$exitButton.Text = "Exit"
$exitButton.add_Click({$mainForm.close()})
$mainForm.Controls.Add($exitButton)

The Function calling the Web Service starts with resetting the $error variable. I define the Web Service call using New-WebServiceProxy with the URI pointing to the services WSDL address. I receive the returned image by making the call, passing the text and font size. I set a unique output filename and create the file using Set-Content, inputting a byte stream. Lastly the $error variable s checked for a successful call, translate and file write with the result written.

Function GetBraille {
    $error.clear()
    $getBraille = New-WebServiceProxy -uri "http://www.webservicex.net/braille.asmx?WSDL"
    $returnedImage = $getBraille.BrailleText($inputTextTextBox.Text, $fontSizeTextBox.Text)
    $global:outFile = $scriptPath + "\"  + "Text2Braille_" + (Get-Date -UFormat %Y%m%d_%H%M%S) + ".jpg"
    Set-Content -Path $global:outFile -Value $returnedImage -Encoding Byte
    If($error.count -gt 0) {
        $completedLabel.Text = "Error!"
        $completedLabel.ForeColor = "Red"
    }
    Else {
        $completedLabel.Text = "Success!"
        $completedLabel.ForeColor = "Green"
    }
    PictureBox($global:outFile)
    $getBraille.Dispose()
}

The image is displayed in the PictureBox using the previously written file. If desired, the image can be displayed external of the script using the default system image viewer called with Invoke-Item.

Function PictureBox {
    $file = (Get-Item $global:outFile)
    $image = [System.Drawing.Image]::Fromfile($file)
    $pictureBox.Image = $image
}

Function DisplayImage {
    If ($global:outFile.Length -gt 0) {
        Invoke-Item $global:outFile
    }
}

Download the complete script here – Text2Braille.ps1

Advertisements

PowerShell Random Geometric Patterns v2

1 Comment

This script is an update to the Random Geometric Patterns Image Maker script. The original script had 12 patterns while the new version has 33 different pattern/fill combos. There are new patterns like Points, Squares, Stars and Triangles. The patterns now have a variety of fill types including Solid, Gradient and Hatch.

Here are some examples starting with Ellipses filled with (Skewed) Gradient colors.

EllipsesGradient_20140810_141957

These are Pie Shapes filled with Hatches.

PiesHatch_20140810_141525

Here are Squares filled with a Gradient.

SquaresGradient_20140810_140839

These are Random Stars.

Stars_20140815_194426

And these are Random Triangles with thick lines on a transparent background.

Triangles_20140810_141258

Lastly are Polygons with a Gradient fill.

PolygonsGradient_20140714_195930

This script interface and core functions are the same as in the original script, just the pattern options available are expanded. The only other changes are expanding the output image size options and changing that size text parser to split instead of substring for more flexibility. Also the Squares and Rectangles max size is set to 25% of the image size instead of being fixed. I’ll only describe using the fills and the new patterns which are the major changes in version 2.

The Hatch fills use one of 53 available Hatch Styles. I start by filling the array $hatchStyle with all the Styles in Drawing.Drawing2D.HatchStyle.

# Select Hatch Style
$maxHatchStyle = 53
$hatchStyle = @()
For ($i = [Convert]::ToInt32([Drawing.Drawing2D.HatchStyle]::Min); $i -lt $maxHatchStyle; $i++) {
    $hatchStyle += ([Drawing.Drawing2D.HatchStyle] $i)
}

The Hatch Styles are used in the HatchBrush Class. I setup the Brush with a random style and random colors. The Brush is then used in the Fill calls, like $bitmapGraphics.FillEllipse.

# Setup Brush
$brush = New-Object System.Drawing.Drawing2D.HatchBrush( `
[System.Drawing.Drawing2D.HatchStyle] $hatchStyle[(Get-Random -minimum 0 -maximum 52)], `
[System.Drawing.Color]::FromArgb((Get-Random -minimum 0 -maximum 255),(Get-Random -minimum 0 -maximum 255),(Get-Random -minimum 0 -maximum 255)), `
[System.Drawing.Color]::FromArgb((Get-Random -minimum 0 -maximum 255),(Get-Random -minimum 0 -maximum 255),(Get-Random -minimum 0 -maximum 255)))
# Draw the Ellipse
$bitmapGraphics.FillEllipse($brush, $upperLeftX, $upperLeftY, $width, $height)

Gradient Fills use the Drawing.Drawing2D.LinearGradientBrush Brush. The Brush uses a Start and End Point of the linear gradient. The Start Point is the upper left corner and the End Point is random. Also defined are the Starting and Ending colors, which are randomized.

# Setup Brush
$pointStart = New-Object System.Drawing.Point
$pointStart.X = $upperLeftX
$pointStart.Y = $upperLeftY
$pointStop = New-Object System.Drawing.Point
$pointStop.X = $random1
$pointStop.Y = $random2
$brush = New-Object System.Drawing.Drawing2D.LinearGradientBrush($pointStart, $pointStop,  `
    [System.Drawing.Color]::FromArgb((Get-Random -minimum 0 -maximum 255),(Get-Random -minimum 0 -maximum 255),(Get-Random -minimum 0 -maximum 255)), `
    [System.Drawing.Color]::FromArgb((Get-Random -minimum 0 -maximum 255),(Get-Random -minimum 0 -maximum 255),(Get-Random -minimum 0 -maximum 255)))
# Draw the Ellipse
$bitmapGraphics.FillEllipse($brush, $upperLeftX, $upperLeftY, $width, $height)

The Solid Fills use a Brush defined with three colors, which are random.

$red   = (Get-Random -minimum 0 -maximum 255)
$green = (Get-Random -minimum 0 -maximum 255)
$blue  = (Get-Random -minimum 0 -maximum 255)

# Setup Brush
$brushColor = [System.Drawing.Color]::FromArgb($red, $green, $blue)
$brush = New-Object System.Drawing.SolidBrush $brushColor

Stars use some trigonometry to calculate the points which form the Star. I got the base algorithm from a blog discussion about drawing a 5 pointed star in Java.

# Randomize Position and Define the Stars Points
$x = (Get-Random -minimum -100 -maximum $global:imageWidth)
$y = (Get-Random -minimum -100 -maximum $global:imageHeight)
$width = (Get-Random -minimum 0 -maximum 100)
$height = $width
$ax = [int](($width/2) + $x)
$ay = [int]$y
$bx = [int]($width+$x)
$by = [int](.374*[double]($height)+[double]($y))
$cx = [int](.825*[double]($width)+[double]($x))
$cy = [int]($height+$y)
$dx = [int](.175*[double]($height)+[double]($x))
$dy = [int]($height+$y)
$ex = [int]$x
$ey = [int]$by
# Draw the Star
$bitmapGraphics.DrawLine($pen, $ax, $ay, $cx, $cy)
$bitmapGraphics.DrawLine($pen, $bx, $by, $dx, $dy)
$bitmapGraphics.DrawLine($pen, $cx, $cy, $ex, $ey)
$bitmapGraphics.DrawLine($pen, $dx, $dy, $ax, $ay)
$bitmapGraphics.DrawLine($pen, $ex, $ey, $bx, $by)

Triangles are drawn by defining  three random points and drawing a line from the first point to the second, then the third and back to the first.

# Randomize Position and Define the Triangle Points
$startX = (Get-Random -minimum 0 -maximum $global:imageWidth)
$startY = (Get-Random -minimum 0 -maximum $global:imageHeight)
$secondX = (Get-Random -minimum 0 -maximum $global:imageWidth)
$secondY = (Get-Random -minimum 0 -maximum $global:imageHeight)
$thirdX = (Get-Random -minimum 0 -maximum $global:imageWidth)
$thirdY = (Get-Random -minimum 0 -maximum $global:imageHeight)
$saveX = $startX
$saveY = $startY
# Draw the Triangle
$bitmapGraphics.DrawLine($pen, $startX, $startY, $secondX, $secondY)
$bitmapGraphics.DrawLine($pen, $secondX, $secondY, $thirdX, $thirdY)
$bitmapGraphics.DrawLine($pen, $thirdX, $thirdY, $saveX, $saveY)

GeometricPatterns2

Download the complete script here – GeometricPatterns2.ps1

PowerShell Draw Random Characters

Leave a comment

This script uses the Graphics.DrawString Method to randomly draw characters in an image. The characters are randomly placed, using a randomly selected font and a random color and size. You can also use only the WingDings and WebDings fonts in the image. The background can be black, white, random or transparent.
 
Here are a couple examples from the script –
 
RandomCharacters_20140322_161815
 
RandomCharacters_20140325_195955
 
And “Dings” only –
 
RandomCharacters_20140330_202136
 
I defined a WinForms Form and set some values like script path.
 

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

# Main Form
$mainForm = New-Object Windows.Forms.Form
$mainForm.BackColor = "White"
$mainForm.Font = “Comic Sans MS,8.25"
$mainForm.Text = "Draw Random Characters"
$mainForm.size = "580,210"

# Global Values
$scriptPath = split-path -parent $MyInvocation.MyCommand.Definition
$global:numberValue = 1000

 
I defined a TrackBar and its Label to collect the Number of Characters.
 

# Number of Characters TrackBar
$numberTrackBar = New-Object Windows.Forms.TrackBar
$numberTrackBar.Location = "180,20"
$numberTrackBar.Orientation = "Horizontal"
$numberTrackBar.Width = 350
$numberTrackBar.Height = 40
$numberTrackBar.LargeChange = 500
$numberTrackBar.SmallChange = 10
$numberTrackBar.TickFrequency = 500
$numberTrackBar.TickStyle = "TopLeft"
$numberTrackBar.SetRange(1, 5000)
$numberTrackBar.Value = 1000
$numberTrackBarValue = 1000
$numberTrackBar.add_ValueChanged({
    $numberTrackBarValue = $numberTrackBar.Value
    $numberTrackBarLabel.Text = "Number Characters ($numberTrackBarValue)"
    $global:numberValue = $numberTrackBarValue
})
$mainForm.Controls.add($numberTrackBar)

# Object Number Label
$numberTrackBarLabel = New-Object System.Windows.Forms.Label 
$numberTrackBarLabel.Location = "10,20"
$numberTrackBarLabel.Size = "160,23"
$numberTrackBarLabel.ForeColor = "MediumBlue"
$numberTrackBarLabel.Text = "Number Characters ($numberTrackBarValue)"
$mainForm.Controls.Add($numberTrackBarLabel)

 
I setup two ComboBoxes with Labels to collect the Character Type and Background Color.
 

# Type ComboBox
$typeComboBox = New-Object System.Windows.Forms.ComboBox
$typeComboBox.Location = "320,80"
$typeComboBox.Size = "120,20"
$typeComboBox.ForeColor = "Indigo"
$typeComboBox.BackColor = "White"
[void]$typeComboBox.items.add("All Fonts")
[void]$typeComboBox.items.add("Dings Only")        
$typeComboBox.SelectedIndex = 0
$mainForm.Controls.Add($typeComboBox)

# Type ComboBox Label
$typeComboBoxLabel = New-Object System.Windows.Forms.Label 
$typeComboBoxLabel.Location = "200,80"
$typeComboBoxLabel.Size = "100,23"
$typeComboBoxLabel.ForeColor = "MediumBlue"
$typeComboBoxLabel.Text = "Character Type"
$mainForm.Controls.Add($typeComboBoxLabel)

# Background ComboBox
$backgroundComboBox = New-Object System.Windows.Forms.ComboBox
$backgroundComboBox.Location = "320,120"
$backgroundComboBox.Size = "120,20"
$backgroundComboBox.ForeColor = "Indigo"
$backgroundComboBox.BackColor = "White"
[void]$backgroundComboBox.items.add("Black")
[void]$backgroundComboBox.items.add("White")
[void]$backgroundComboBox.items.add("Random")
[void]$backgroundComboBox.items.add("Transparent")               
$backgroundComboBox.SelectedIndex = 0
$mainForm.Controls.Add($backgroundComboBox)

# Background ComboBox Label
$backgroundComboBoxLabel = New-Object System.Windows.Forms.Label 
$backgroundComboBoxLabel.Location = "200,120"
$backgroundComboBoxLabel.Size = "100,23"
$backgroundComboBoxLabel.ForeColor = "MediumBlue"
$backgroundComboBoxLabel.Text = "Background Color"
$mainForm.Controls.Add($backgroundComboBoxLabel)

 
Lastly are a couple Buttons for Execute and Exit.
 

# Draw Button
$drawButton = New-Object System.Windows.Forms.Button 
$drawButton.Location = "40,80"
$drawButton.Size = "75,23"
$drawButton.ForeColor = "SeaGreen"
$drawButton.BackColor = "White"
$drawButton.Text = "Draw"
$drawButton.add_Click({DrawIt})
$mainForm.Controls.Add($drawButton)

# Exit Button
$exitButton = New-Object System.Windows.Forms.Button
$exitButton.Location = "40,120"
$exitButton.Size = "75,23"
$exitButton.ForeColor = "Red"
$exitButton.BackColor = "White"
$exitButton.Text = "Exit"
$exitButton.add_Click({$mainForm.close()})
$mainForm.Controls.Add($exitButton)

 
In the Drawing Function first I define the Output Image and set the background color as selected.
 

# Draw the Object
Function DrawIt {
    $Global:outFile = ""
    # Setup Image
    $bitmap = new-object System.Drawing.Bitmap 1024,768
    $bitmapGraphics = [System.Drawing.Graphics]::FromImage($bitmap) 
    # Image Background Color
    If ($backgroundComboBox.Text -eq "Transparent") {
        $bitmap.MakeTransparent()
    } Else {
        If ($backgroundComboBox.Text -eq "Random") {
            $red   = (Get-Random -minimum 0 -maximum 255)
            $green = (Get-Random -minimum 0 -maximum 255)
            $blue  = (Get-Random -minimum 0 -maximum 255)
            $backColor = [System.Drawing.Color]::FromArgb($red, $green, $blue)
            $bitmapGraphics.Clear($backColor)
        } Else {
            $bitmapGraphics.Clear($backgroundComboBox.Text)
        }
    }

 
I load all the installed font names into an array. If Dings Only is selected then I load only them.
 

    # Add All Installed Font Names into an Array
    $fontFamilies = @()
    $fontsCollection = New-Object System.Drawing.Text.InstalledFontCollection
    If ($typeComboBox.Text -eq "All Fonts") {
        $fontFamilies = $fontsCollection.Families
    } Else {
        If ($typeComboBox.Text -eq "Dings Only") {
            For($i=0; $i -le $fontsCollection.Families.length-1) {
                If ($fontsCollection.Families[$i].Name -like "Wingdings") {
                    $fontFamilies += $fontsCollection.Families[$i].Name
                }
                If ($fontsCollection.Families[$i].Name -like "Webdings") {
                    $fontFamilies += $fontsCollection.Families[$i].Name
                }
                $i++
            }
        }
    }

 
Inside the loop which write the character to the image I randomize and load a Font. Then I randomize the font color and location. Finally the character is drawn.
 

    $i = 0
    While ($i -le $global:numberValue) { $i++
        # Randomize Font Name and Size
        $fontSelector = (Get-Random -minimum 0 -maximum $fontFamilies.Length)
        $fontName = $fontFamilies[$fontSelector]
        $size = (Get-Random -minimum 4 -maximum 60)
        Try {
        $font = new-object System.Drawing.Font $fontName,$size
        }
        Catch {
        Write-Host "Unable to load Font -" $fontName
        }
        # Randomize Foreground Color
        $red  = (Get-Random -minimum 1 -maximum 255)
        $green = (Get-Random -minimum 1 -maximum 255)
        $blue  = (Get-Random -minimum 1 -maximum 255)
        $brushColorFg = [System.Drawing.Color]::FromArgb($red, $green, $blue)
        $brushFg = New-Object System.Drawing.SolidBrush $brushColorFg
        # Randomize Position
        $pointX = (Get-Random -minimum -10 -maximum 1034)
        $pointY = (Get-Random -minimum -10 -maximum 778)
        $letter = (Get-Random -minimum 33 -maximum 136)
        # Draw the Letter
        $bitmapGraphics.DrawString(([char]($letter)),$font,$brushFg,$pointX,$pointY)
    }

 
The image file is written to disk with a random name where the script is located. The image is displayed using the system default image viewer. Lastly the image is disposed of, ready for the next run.
 

    # Display Image
    $Global:outFile = $scriptPath + "\"  + "RandomCharacters_" + (Get-Date -UFormat %Y%m%d_%H%M%S) + ".bmp"
    $bitmap.Save($Global:outFile)
    Invoke-Item $Global:outFile
    # Cleanup
    $bitmapGraphics.Dispose()  
}

 
DrawStringRandom
 
Download the complete script here – DrawStringRandom.ps1

PowerShell Random Geometric Patterns Image Maker

Leave a comment

I find that randomly displayed geometric objects like lines, circles, rectangles and Beziers make real interesting images. I enjoy the cool designs and like to find pattern in randomness. I put together a script which lets you create an image and randomly fill it with geometric objects. You can control the type and number of objects, image background color, output image size as well as drawing pen size and color. The image is saved to disk and displayed.
 
Here are a few examples generated from this script starting with Bezier Splines
 
Beziers1
 
Beziers2
 
Beziers3
 
and Connected Beziers
 
ConnectedBeziers1
 
ConnectedBeziers2
 
Lines
 
Lines1
 
Lines2
 
Connected Lines
 
ConnectedLines1
 
ConnectedLines2
 
Cornerbusrt Lines
 
LineCornerburst1
 
Starburst Lines
 
StarburstLine1
 
Rectangles
 
Rectangles1
 
Rectangles2
 
Ellipses
 
Ellipses1
 
Arcs
 
Arcs1
 
Pie Shapes
 
Pies1
 
Curves
 
Curves1
 
I setup a WinForms Form to collect the objects and pattern info. I defined some global values to be used in later functions.
 

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

# Main Form
$mainForm = New-Object Windows.Forms.Form
$mainForm.Location = "200,200"
$mainForm.FormBorderStyle = "FixedDialog"
$mainForm.BackColor = "Cornsilk"
$mainForm.Font = “Comic Sans MS,8.25"
$mainForm.Text = "Draw Random Geometric Patterns"
$mainForm.Size = "580,550"

# Global Values
$scriptPath = split-path -parent $MyInvocation.MyCommand.Definition
$global:numberObjects = 100
$global:penWidth = 1
$global:colorText = "Multi(Random)"
$global:backgroundText = "Black"
$global:selectedObject = "Beziers"
$global:imageWidth = 1024
$global:imageHeight = 768

 
I setup 12 RadioButtons to select the geometric object with.
 
GeometricPatterns1
 

# Arcs Object
$radioButtonArcs = New-Object System.Windows.Forms.RadioButton
$radioButtonArcs.Location = "80,30"
$radioButtonArcs.ForeColor = "Indigo"
$radioButtonArcs.Text = "Arcs"
$radioButtonArcs.add_Click({
    $global:selectedObject = "Arcs"
})
$mainForm.Controls.Add($radioButtonArcs)

# Beziers Object
$radioButtonBeziers = New-Object System.Windows.Forms.RadioButton
$radioButtonBeziers.Location = "80,60"
$radioButtonBeziers.ForeColor = "Indigo"
$radioButtonBeziers.Text = "Beziers"
$radioButtonBeziers.add_Click({
    $global:selectedObject = "Beziers"
})
$mainForm.Controls.Add($radioButtonBeziers)

 
I next added two TrackBar Controls with Labels to select the Number of Objects and Pen Size.
 
GeometricPatterns2
 

# Number of Objects TrackBar
$numberTrackBar = New-Object Windows.Forms.TrackBar
$numberTrackBar.Location = "180,280"
$numberTrackBar.Orientation = "Horizontal"
$numberTrackBar.Width = 350
$numberTrackBar.Height = 40
$numberTrackBar.LargeChange = 500
$numberTrackBar.SmallChange = 10
$numberTrackBar.TickFrequency = 500
$numberTrackBar.TickStyle = "TopLeft"
$numberTrackBar.SetRange(1, 5000)
$numberTrackBar.Value = 200
$numberTrackBarValue = 200
$numberTrackBar.add_ValueChanged({
    $numberTrackBarValue = $numberTrackBar.Value
    $numberTrackBarLabel.Text = "Number Objects ($numberTrackBarValue)"
    $global:numberObjects = $numberTrackBarValue
})
$mainForm.Controls.add($numberTrackBar)

# Object Number Label
$numberTrackBarLabel = New-Object System.Windows.Forms.Label 
$numberTrackBarLabel.Location = "10,280"
$numberTrackBarLabel.Size = "160,23"
$numberTrackBarLabel.ForeColor = "MediumBlue"
$numberTrackBarLabel.Text = "Number Objects ($numberTrackBarValue)"
$mainForm.Controls.Add($numberTrackBarLabel)

 
Three ComboBoxes Controls with Labels are added for Object and Background Color and Output Image Size.
 
GeometricPatterns3
 

# Background ComboBox
$backgroundComboBox = New-Object System.Windows.Forms.ComboBox
$backgroundComboBox.Location = "350,420"
$backgroundComboBox.Size = "120,20"
$backgroundComboBox.ForeColor = "Indigo"
$backgroundComboBox.BackColor = "White"
[void]$backgroundComboBox.items.add("Black")
[void]$backgroundComboBox.items.add("White")
[void]$backgroundComboBox.items.add("Random")         
$backgroundComboBox.SelectedIndex = 0
$mainForm.Controls.Add($backgroundComboBox)

# Background ComboBox Label
$backgroundComboBoxLabel = New-Object System.Windows.Forms.Label 
$backgroundComboBoxLabel.Location = "200,420"
$backgroundComboBoxLabel.Size = "100,23"
$backgroundComboBoxLabel.ForeColor = "MediumBlue"
$backgroundComboBoxLabel.Text = "Background Color"
$mainForm.Controls.Add($backgroundComboBoxLabel)

 
To comlete the Form I added a Draw and Exit button. Draw will call the appropriate function to draw the selected object. Exit closes the Form.
 
GeometricPatterns4
 

# Draw Button
$drawButton = New-Object System.Windows.Forms.Button 
$drawButton.Location = "40,420"
$drawButton.Size = "75,23"
$drawButton.ForeColor = "Green"
$drawButton.BackColor = "White"
$drawButton.Text = "Draw"
$drawButton.add_Click({DrawIt})
$mainForm.Controls.Add($drawButton)

# Exit Button
$exitButton = New-Object System.Windows.Forms.Button
$exitButton.Location = "40,460"
$exitButton.Size = "75,23"
$exitButton.ForeColor = "Red"
$exitButton.BackColor = "White"
$exitButton.Text = "Exit"
$exitButton.add_Click({$mainForm.close()})
$mainForm.Controls.Add($exitButton)

 
As an example drawing function I selected Beziers. The Draw Button calls the DrawIt Function where the output image Width and Height variables are set from the ComboBox values. The appropriate drawing function is called from the value selected with the RadioButtons using Invoke-Expression.
 

Function DrawIt {
    $global:imageWidth = $imageComboBox.Text.Substring(0,4)
    $global:imageHeight = $imageComboBox.Text.Substring(5,4)
    Invoke-Expression $global:selectedObject
}

 
A default random color is set. The bitmap image is defined using System.Drawing.Bitmap and that images graphic properties exposed with System.Drawing.Graphics. The images background color is set depending on the ComboBox selection.
 

Function Beziers {
    # Default Random Color
    $red   = (Get-Random -minimum 0 -maximum 255)
    $green = (Get-Random -minimum 0 -maximum 255)
    $blue  = (Get-Random -minimum 0 -maximum 255)
    # Create Image
    $bitmap = New-Object System.Drawing.Bitmap([int]$global:imageWidth, [int]$global:imageHeight)
    $bitmapGraphics = [System.Drawing.Graphics]::FromImage($bitmap)
    # Image Background Color
    If ($backgroundComboBox.Text -eq "Random") {
        $red   = (Get-Random -minimum 0 -maximum 255)
        $green = (Get-Random -minimum 0 -maximum 255)
        $blue  = (Get-Random -minimum 0 -maximum 255)
        $backColor = [System.Drawing.Color]::FromArgb($red, $green, $blue)
        $bitmapGraphics.Clear($backColor)
    } Else {
        $bitmapGraphics.Clear($backgroundComboBox.Text)
    }

 
Next is a loop with an iteration equal to the number of objects. A drawing pen color is set by using the default random color or a new random color for each loop iteration. The pen is defined with using the selected color and width. Next the four x/y coordinates defining the Bezier spline are set using randomly selected points. Finally the Bezier is drawn onto the image with the DrawBezier method.
 

    # Main Loop
    $i = 0
    While ($i -le $global:numberObjects) { $i++
        # Get Random Color if Selected
        If ($colorsComboBox.Text -eq "MultiColored") {
            $red   = (Get-Random -minimum 0 -maximum 255)
            $green = (Get-Random -minimum 0 -maximum 255)
            $blue  = (Get-Random -minimum 0 -maximum 255)
        }
        # Setup Pen
        $penColor = [System.Drawing.Color]::FromArgb($red, $green, $blue)
        $pen = New-Object Drawing.Pen $penColor
        $pen.Width = $global:penWidth
        # Randomize All 4 Points of the Bezier
        $point1X = (Get-Random -minimum 0 -maximum $global:imageWidth)
        $point1Y = (Get-Random -minimum 0 -maximum $global:imageHeight)
        $point2X = (Get-Random -minimum 0 -maximum $global:imageWidth)
        $point2Y = (Get-Random -minimum 0 -maximum $global:imageHeight)
        $point3X = (Get-Random -minimum 0 -maximum $global:imageWidth)
        $point3Y = (Get-Random -minimum 0 -maximum $global:imageHeight)
        $point4X = (Get-Random -minimum 0 -maximum $global:imageWidth)
        $point4Y = (Get-Random -minimum 0 -maximum $global:imageHeight)
        # Draw Bezier Curve
        $bitmapGraphics.DrawBezier($pen, $point1X, $point1Y, $point2X, $point2Y, $point3X, $point3Y, $point4X, $point4Y)
    }

 
When the drawing loop has completed the image is saved to disk and displayed with the default Windows image viewer. The file name is made unique by post pending the date and time. The image files are written to the same folder where the script resides. When all processing has completed the image COM object is disposed of.
 

   
# Save Image to File and Display
    $outFile = $scriptPath + "\"  + "Beziers_" + (Get-Date -UFormat %Y%m%d_%H%M%S) + ".bmp"
    $bitmap.Save($outFile)
    Invoke-Item $outFile

    # Dispose of the image
    $bitmap.Dispose()
}

 
All the drawing functions are quite similar. They all use System.Drawing.Graphics methods like DrawLine, DrawEllipse, DrawCurve, DrawRectangle, DrawArc, DrawPie, etc. They vary by the way the points are defined, how many points there are and how the are positioned. The Connected objects, Lines and Beziers, are obviously not totally random as one end of each object connects to the previously drawn object. Polygons are the same as Connected Lines except they are randomized building the input array instead of by each line end point and since they are drawn in one continuous processing of the array, you only get a single drawing color. Curves are similar to Connected Beziers in the same way. The Starburst and Cornerburst Lines are also not totally random as they have a fixed point as well as a random point.
 
Some images I felt looked best with the all the objects being drawn within the image boundaries, such as both the Beziers and Connected Lines. Other images I thought were best looking with the drawing range of the objects expanding beyond the image boundaries like Arcs, Ellipses, Lines and Rectangles. The partial objects extending within the image edges adds to the randomness and pattern, I think. While with Connected Lines and Beziers, I think the sharp angles and continuousness were important and so I keep the objects within the image. With Arcs and Pie Shapes I put limits on the shapes so that Arcs and Pies are distinctly shaped and not just almost circles.
 
GeometricPatterns
 
Download the complete script here – GeometricPatterns.ps1

There is a new Version 2 of Geometric Patterns Maker here.

PowerShell Draw and Save Tiled Pattern Images

Leave a comment

This script uses a mathematical algorithm to define the X and Y coordinates for each pixel in the image. The result is a complex pattern which is repeated like tiles on a floor for an interesting final image. These patterns are fractal like insomuch as they have repeating patterns but lack a fractal dimension and are static.
 
I will credit the author of the original algorithm when I figure out who it was. I got the outline of the process from a QuickBasic program I wrote long, long ago. I didn’t have the credit in the code but I think it was from some fractal books I have and hope to find again one day.
 
Here is an example Tiled Pattern image –
 
TiledPatternExample
 
And a closeup of the pattern –
TiledPatternExampleCloseUp
 
Here are a few other examples from this Tiled Patterns script-
 
TiledPatterns_20131120_192034
 
TiledPatterns_20131127_213942
 
TiledPatterns30131121_184757
 
The are five variables which are used to control the pattern, so in a WinForms Form I defined five TrackBar controls for Alpha, Beta1, Beta2, Gamma and Modulus. I also added the Labels for each TrackBar and set the initial variable values and gathered the script path.
 

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

# Main Form
$mainForm = New-Object Windows.Forms.Form
$mainForm.BackColor = "White"
$mainForm.Font = “Comic Sans MS,8.25"
$mainForm.Text = "Tiled Pattern"
$mainForm.size = "500,350"

# Global Values
$scriptPath = split-path -parent $MyInvocation.MyCommand.Definition
$global:alphaValue = 2
$global:beta1Value = 4
$global:beta2Value = 4
$global:gammaValue = 134
$global:modulusValue = 2

# Alpha TrackBar
$alphaTrackBar = New-Object Windows.Forms.TrackBar
$alphaTrackBar.Location = "100,20"
$alphaTrackBar.Orientation = "Horizontal"
$alphaTrackBar.Width = 350
$alphaTrackBar.Height = 40
$alphaTrackBar.LargeChange = 5
$alphaTrackBar.SmallChange = 1
$alphaTrackBar.TickFrequency = 1
$alphaTrackBar.TickStyle = "TopLeft"
$alphaTrackBar.SetRange(1, 10)
$alphaTrackBar.Value = 4
$alphaTrackBarValue = 4
#Alpha TrackBar Event Handler
$alphaTrackBar.add_ValueChanged({
    $alphaTrackBarValue = $alphaTrackBar.Value
    $alphaLabel.Text = "Alpha ($alphaTrackBarValue)"
    $global:alphaValue = $alphaTrackBarValue
})
$mainForm.Controls.add($alphaTrackBar)

# Alpha Label
$alphaLabel = New-Object System.Windows.Forms.Label 
$alphaLabel.Location = "10,20"
$alphaLabel.Size = "120,23"
$alphaLabel.Text = "Alpha ($alphaTrackBarValue)"
$mainForm.Controls.Add($alphaLabel)

 
Next was added the two Buttons. One to call the DrawIt function to plot the pattern and one to close the Form.
 

# Draw Button
$DrawButton = New-Object System.Windows.Forms.Button 
$DrawButton.Location = "160,270"
$DrawButton.Size = "75,23"
$DrawButton.Text = "Draw"
$DrawButton.add_Click({DrawIt})
$mainForm.Controls.Add($DrawButton)

# Exit Button
$exitButton = New-Object System.Windows.Forms.Button
$exitButton.Location = "280,270"
$exitButton.Size = "75,23"
$exitButton.Text = "Exit"
$exitButton.add_Click({$mainForm.close()})
$mainForm.Controls.Add($exitButton)

 
In the main plotting function I first output a line on the host console to show processing has begun. Next I setup the output image file with a black background. I then get the values of the variable from the TrackBar selection (or initial values if not selected from TrackBar). The loop counters are initialized. The first processing steps percentage is set and a random color selected. During this function for each X position a Y is calculated. So in a X loop I first check for percent of processing done by looking for every one 100 pixels completed(this assumes the 1023 width so each 100 is close to 10% complete) and output to the host console. I then start a loop to plot the Y position. I make sure the pixel is positioned within the image and then apply the mathematical algorithm to get the Y position. Many values are generated but only the ones which have the modulus selected are used. Once Y is determined the pixel is written to the image using the previously selected random color. Lastly, after the image is fully created it is written to disk in the folder where the script resides. To keep the file names unique I concatenate the file name with the date and time. The newly written file is then displayed with the system default image viewer for that file type and a completion line is written to the host console.
 

# Draw the Pattern
Function DrawIt {
    Write-Host "Running . . ."

    # Output Bitmap Image
    $bitmap = New-Object System.Drawing.Bitmap(1024, 768)
    $bitmapGraphics = [System.Drawing.Graphics]::FromImage($bitmap) 
    $bitmapGraphics.Clear("black")

    $alpha = $global:alphaValue
    $beta1 = $global:beta1Value
    $beta2 = $global:beta2Value
    $gamma = $global:gammaValue
    $modulus  = $global:modulusValue

    $xPixel = 0; $yPixel = 0
    $percent = 10
    $totalPixels = 1023
    $red =   (Get-Random -minimum 0 -maximum 255)
    $green = (Get-Random -minimum 0 -maximum 255)
    $blue =  (Get-Random -minimum 0 -maximum 255)

    while ($xPixel -le $totalPixels) {
        $xPixel++ ; $yPixel = 1
        if (($xPixel % 100) -eq 0) {
            Write-Host "Processing" $percent"%"
            $percent = $percent + 10
        }
        while ($yPixel -le $totalPixels) { 
            $yPixel++
            if ($xPixel -ge 0) {
                if ($yPixel -ge 0) {
                    if ($xPixel -le 1023) {       
                        if ($yPixel -le 767) { 
                            $x=$beta1+($gamma*$xPixel)
                            $y=$beta2+($gamma*$yPixel)
                            $z=($alpha*([math]::sin($x))+[math]::sin($y))
                            $c=[math]::truncate($z)
                            if ($c % $modulus -eq 0) {
	                            $bitmap.SetPixel($xPixel, $yPixel, [System.Drawing.Color]::FromArgb($red, $green, $blue))
                            }
                        }
                    }
                }
            }
        }
    }

    $outFile = $scriptPath + "\"  + "TiledPatterns_" + (Get-Date -UFormat %Y%m%d_%H%M%S) + ".bmp"
    $bitmap.Save($outFile)
    Invoke-Item $outFile
    $bitmap.Dispose()
    $bitmapGraphics.Dispose()
    Write-Host "Complete"
}

 
TitledPatterns
 
Download – TiledPatterns.ps1

PowerShell Plot and Save Mira Orbital Fractal

Leave a comment

Fractals are infinitely self-similar, iterated and detailed mathematical constructs. Plotting them into an image can produce fantastic results. One type of Fractal is an Orbital Fractal or an Escape-Time Fractal, in which each point in space is calculated from a formula. One type of Orbital Fractal is the Mira Fractal. The Mira equation was developed at the CERN research centre in 1980 by I. Gumowski and C. Mira. It was not designed to create fractals, but to calculate the trajectories of sub-atomic particles. The algorithm used in this script originally came from ‘Fractals’ by Hans Lauwerier.

Here are some images generated from the below script –

Mira_20131123_172513

Mira_20131119_202343

Mira_20131123_165657

Mira_20131120_173238

Mira_20131122_175334

There are two values which control how the fractal is generated. I made a WinForms Form with TrackBar controls to provide those options. I setup the Main Form and defined some Global Values.

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

# Main Form
$mainForm = New-Object Windows.Forms.Form
$mainForm.BackColor = "White"
$mainForm.Font = “Comic Sans MS,8.25"
$mainForm.Text = "Mira Orbital Fractal"
$mainForm.size = "500,260"

# Global Values
$scriptPath = split-path -parent $MyInvocation.MyCommand.Definition
$global:colorsValue = 0
$global:iterationsValue = 0

I next setup the TrackBars defining thier orientation, location, size and tick properties. Moving the TrackBar feeds the counter on the Label using the valueChanged Event. The LargeChange and SmallChange properties move the pointer along the TrackBar like a tab when clicking on the bar. I then set the inital values for the TrackBar. The other properties and the Event Handler I discussed in a previous WinForms TrackBar blog.

# Iterations TrackBar
$iterationsTrackBar = New-Object Windows.Forms.TrackBar
$iterationsTrackBar.Location = "70,15"
$iterationsTrackBar.Orientation = "Horizontal"
$iterationsTrackBar.Width = 350
$iterationsTrackBar.Height = 40
$iterationsTrackBar.LargeChange = 25000
$iterationsTrackBar.SmallChange = 5000
$iterationsTrackBar.TickFrequency = 5000
$iterationsTrackBar.TickStyle = "TopLeft"
$iterationsTrackBar.SetRange(5000, 150000)
$iterationsTrackBar.Value = 30000
$iterTrackBarValue = 30000
#Iterations TrackBar Event Handler
$iterationsTrackBar.add_ValueChanged({
    $iterTrackBarValue = $iterationsTrackBar.Value
    $iterationsLabel.Text = "Iterations ($iterTrackBarValue)"
    $global:iterationsValue = $iterTrackBarValue
})
$mainForm.Controls.add($iterationsTrackBar)

# Colors Change TrackBar
$colorsTrackBar = New-Object Windows.Forms.TrackBar
$colorsTrackBar.Location = "70,130"
$colorsTrackBar.Orientation = "Horizontal"
$colorsTrackBar.Width = 350
$colorsTrackBar.Height = 40
$colorsTrackBar.LargeChange = 5000
$colorsTrackBar.SmallChange = 1000
$colorsTrackBar.TickFrequency = 1000
$colorsTrackBar.TickStyle = "BottomRight"
$colorsTrackBar.SetRange(1000, 20000)
$colorsTrackBarValue = 3000
$colorsTrackBar.Value = 3000
#Colors TrackBar Event Handler
$colorsTrackBar.add_ValueChanged({
$colorsTrackBarValue = $colorsTrackBar.Value
    $colorsLabel.Text = "Color Change ($colorsTrackBarValue)"
    $global:colorsValue = $colorsTrackBarValue
})
$mainForm.Controls.add($colorsTrackBar)

I then setup the Labels which provide a title for the TrackBars and show the counters.

# Iterations Label
$iterationsLabel = New-Object System.Windows.Forms.Label
$iterationsLabel.Location = "170,60"
$iterationsLabel.Size = "120,23"
$iterationsLabel.Text = "Iterations ($iterTrackBarValue)"
$mainForm.Controls.Add($iterationsLabel)

# Colors Label
$colorsLabel = New-Object System.Windows.Forms.Label
$colorsLabel.Location = "170,100"
$colorsLabel.Size = "160,23"
$colorsLabel.Text = "Color Change Point ($colorsTrackBarValue)"
$mainForm.Controls.Add($colorsLabel)

# Line Label
$lineLabel = New-Object System.Windows.Forms.Label
$lineLabel.Location = "170,75"
$lineLabel.Size = "150,20"
$lineLabel.Text = "______________________________________"
$mainForm.Controls.Add($lineLabel)

The “Plot” Button calls the PlotIt Function which will draw the image.

# Plot Button
$plotButton = New-Object System.Windows.Forms.Button
$plotButton.Location = "120,185"
$plotButton.Size = "75,23"
$plotButton.Text = "Plot"
$plotButton.add_Click({PlotIt})
$mainForm.Controls.Add($plotButton)

To plot the fractal I first define the bitmap image. I set the backgroup of that image to black. I write a line to the host to show processing has started.

# Plot the Fractal
Function PlotIt {
    Write-Host "Running . . ."

    # Output Bitmap Image
    $bitmap = New-Object System.Drawing.Bitmap(1024, 768)
    $bitmapGraphics = [System.Drawing.Graphics]::FromImage($bitmap)
    $bitmapGraphics.Clear("black")

The values used in the fractal formula are initialized. A Random component is setup so all the fractals will be unique.

    $a = (Get-Random -minimum .0001 -maximum .9999)
    $b = .9998
    $c = 2-(2*$a)
    $x = 0
    $y = 12.1
    $w = (($a*$x)+($c*$x*$x))/(1+($x*$x))

The values which control the appearance are setup. The Multiplier resizes the image from the tiny format the formula generates. At a 25 $multiplier most fractals are full size within the image but some will span the image boundary and so be partially cut off. The $colorChange value controls at which interation the color value changes during processing. When the colors change, a proessing status line is written to the host. The $iterations value control how many cycles are ran. The image is generated from the outside to the inside so using a very high number of iterations will result in more “solid center(s)” in the fractal. After much over 150k there isn’t any significant change in the image since those few pixels have all been colored. You can keep running higher iterations and more detail will be generated, however at this resolution it is not visible. There is not a limit to the iterations, which gives Mira it’s Fractal Dimension. A small number will result in more “airy” images without “solid” sections. The below image was generated at 15k interations changing colors every 1000 cycles to show the difference.

    $multiplier = 25
    $colorChange = $global:colorsValue
    $maxIterations = $global:iterationsValue

Mira_20131123_185325

I initatize the counter and setup the centering values. The original formula uses a Cartesian coordinates system for plotting the points. That places point 0,0 in the center of the screen. But for this bitmap image 0,0 is the upper left corner. So I add half the screen, minus the original size, back to each value on each side to (generally) center it. I select random values for the first color.

    $counter = 1
    $xCentering = 470
    $yCentering = 380
    $red =   (Get-Random -minimum 0 -maximum 255)
    $green = (Get-Random -minimum 0 -maximum 255)
    $blue =  (Get-Random -minimum 0 -maximum 255)

I initiate the While loop, incrementing the $counter and testing for $colorChange. If $colorChange then I write a line to the host and set a random color for the next cycles.
The pixels are then expanded with $multiplier and centered (relatively) within the bitmp. The pixels are tested to fit within the bitmap and the pixel is drawn with SetPixel Method of the System.Drawing.Bitmap Class. After the pixel has been painted the next round of fractal calculation is processed and the While loop continues.

    while ($counter -le $maxIterations) { $counter++
        if (($counter % $colorChange) -eq 0) {
            Write-Host $counter "Cycles"
            $red =   (Get-Random -minimum 0 -maximum 255)
            $green = (Get-Random -minimum 0 -maximum 255)
            $blue =  (Get-Random -minimum 0 -maximum 255)
        }
        $xPixel = ($x * $multiplier) + $xCentering
        $yPixel = ($y * $multiplier) + $yCentering
        if ($xPixel -ge 0) {
            if ($yPixel -ge 0) {
                if ($xPixel -le 1023) {
                    if ($yPixel -le 767) {
                        $bitmap.SetPixel($xPixel, $yPixel, [System.Drawing.Color]::FromArgb($red, $green, $blue))
                    }
                }
            }
        }
        $z = $x
        $x = ($b*$y)+$w
        $u = $x*$x
        $w = ($a*$x)+($c*$u)/(1+$u)
        $y = $w-$z
    }

When the fractal has been fully plotted the file is written to the disk. I select as the file location the same folder where the script resides. The file name is made unique by postpending the date and time to the name “Mira”.
The bitmap is displayed from the newly created file using the default image viewer on the system by calling Invoke-Item.
I then dispose of the $bitmap COM objects to clear them and write a completion line to the host.

    $outFile = $scriptPath + "\"  + "Mira_" + (Get-Date -UFormat %Y%m%d_%H%M%S) + ".bmp"
    $bitmap.Save($outFile)
    Invoke-Item $outFile
    $bitmap.Dispose()
    $bitmapGraphics.Dispose()
    Write-Host "Complete"
}

The last step is an Exit Button to close the Main Form.

# Exit Button
$exitButton = New-Object System.Windows.Forms.Button
$exitButton.Location = "300,185"
$exitButton.Size = "75,23"
$exitButton.Text = "Exit"
$exitButton.add_Click({$mainForm.close()})
$mainForm.Controls.Add($exitButton)

The Main Form –

Mira<

Download – Mira.ps1

%d bloggers like this: