This script uses Graphics.Fill methods with a Brush containing pieces of an image to repaint that image. Adding a Border you get a Mosaic style image. You get different effects using Graphics.FillRectangle, Graphics.FillEllipse, Graphics.FillClosedCurve and Graphics.FillPolygon. The image the Brush is filling with and the new image have the same dimensions so if you painted with enough random fills to cover the entire image you would have the original image back again, providing you have no border. You pick an image and then select the style and number of random image pieces to paint as well as border and background characteristics.
 
Below are some examples. The first is an image fully covered by random squares with a thin border.
 
ImageSquares_20140126_142121
 
This image is fully covered by Ellipses with a thicker border.
 
MosaicEllipses_20140622_142705
 
This image had fewer squares painted on it so the new image is not fully covered. The background was random and a thin border.
 
MosaicSquares_20140622_143637
 
This image is similar to the above except with a transparent background color.
 
MosaicSquares_20140622_143627
 
This image has a few Curves selected and transparent background. ClosedCurves (and Polygons) are made from a list of points and filled and so the below image is made from a single object.
 
MosaicCurves_20140622_153121
 
The image was created by a large amount of Polygons with a black background.
 
MosaicCurves_20140622_143757
 
I started by defining a WinForms Form and setting some Global Variables. I added the Form Title.
 

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

# Global Values
$scriptPath = split-path -parent $MyInvocation.MyCommand.Definition
$global:numberObjects = 1000
$global:backgroundText = "Black"
$global:outFile = ""

# WinForm Setup
$mainForm = New-Object System.Windows.Forms.Form
$mainForm.Location = "200, 200"
$mainForm.Font = "Comic Sans MS,8.5"
$mainForm.FormBorderStyle = "FixedDialog"
$mainForm.ForeColor = "Black"
$mainForm.BackColor = "Cornsilk"
$mainForm.Text = " Mosaic Image Patterns"
$mainForm.Width = 1030
$mainForm.Height = 500

#Title Label
$titleLabel = New-Object System.Windows.Forms.Label
$titleLabel.Location = "400, 5"
$titleLabel.Font = "Comic Sans MS,11"
$titleLabel.Size = "300, 23"
$titleLabel.ForeColor = "DarkRed" 
$titleLabel.Text = "Mosaic Image Patterns"
$mainForm.Controls.Add($titleLabel)

 
The Brush Style is collected with RadioButtons. The default is Square, where I set the .Checked = $true value.
 

# Curves Object
$radioButtonCurves = New-Object System.Windows.Forms.RadioButton
$radioButtonCurves.Location = "15,35"
$radioButtonCurves.ForeColor = "Indigo"
$radioButtonCurves.Size = "80,23"
$radioButtonCurves.Text = "Curves"
$radioButtonCurves.add_Click({
    $global:selectedObject = "Curves"
})
$mainForm.Controls.Add($radioButtonCurves)

 
Next is gathered the Input Image filename. I add a TextBox to display the result. A Label and a Button to initiate the selectFiles Function. Lastly I use System.Windows.Forms.OpenFileDialog Control to open a File Browse dialog to select the file.
 

# Input Box
$textBoxIn = New-Object System.Windows.Forms.TextBox
$textBoxIn.Location = "15, 90"
$textBoxIn.Size = "460, 20"
$mainForm.Controls.Add($textBoxIn)

# Input Box Label
$inputLabel = New-Object System.Windows.Forms.Label
$inputLabel.Location = "15, 67"
$inputLabel.Size = "300, 23"
$inputLabel.ForeColor = "MediumBlue" 
$inputLabel.Text = "Input Image File"
$mainForm.Controls.Add($inputLabel)

# Browse Input Button
$buttonBrowse = New-Object System.Windows.Forms.Button
$buttonBrowse.Location = "560, 80"
$buttonBrowse.Size = "75, 23"
$buttonBrowse.ForeColor = "MediumBlue" 
$buttonBrowse.Text = "Browse"
$buttonBrowse.add_Click({selectFiles})
$mainForm.Controls.Add($buttonBrowse)

function selectFiles {
	$selectForm = New-Object System.Windows.Forms.OpenFileDialog
	$selectForm.Filter = "All Files (*.*)|*.*"
	$selectForm.InitialDirectory = ".\"
	$selectForm.Title = "Select a File to Process"
	$getKey = $selectForm.ShowDialog()
	If ($getKey -eq "OK") {
            $textBoxIn.Text = $selectForm.FileName
            $completeLabel.Text = "      "
            InputPicture($selectForm.FileName)
	}
} # End SelectFile

 
The input image is displayed in a PictureBox.
 

# Input PictureBox
$inputPicture = New-Object System.Windows.Forms.PictureBox
$inputPicture.Location = "90, 200"
$inputPicture.ClientSize = "320, 200"
$inputPicture.BackColor = "Black"
$inputPicture.SizeMode = "Zoom"
$mainForm.Controls.Add($inputPicture)

Function InputPicture {
    $file = (Get-Item $selectForm.FileName)
    $image = [System.Drawing.Image]::Fromfile($file)
    $inputPicture.Image = $image
}

 
I get the number of images to be painted with a TrackBar Control. I set label parameters and finally increment number is displayed in the Label.
 

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

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

 
Background Color and Border Width are gathered with ComboBoxes.
 

# Background ComboBox
$backgroundComboBox = New-Object System.Windows.Forms.ComboBox
$backgroundComboBox.Location = "590,30"
$backgroundComboBox.Size = "90,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 = "520,30"
$backgroundComboBoxLabel.Size = "80,20"
$backgroundComboBoxLabel.ForeColor = "MediumBlue"
$backgroundComboBoxLabel.Text = "Background"
$mainForm.Controls.Add($backgroundComboBoxLabel)

 
The Output Image file is written to the same folder where the script resides.
 

# Output Label
$outputLabel = New-Object System.Windows.Forms.Label
$outputLabel.Location = "15, 435"
$outputLabel.Size = "900, 20"
$outputLabel.ForeColor = "DarkBlue"
$outputLabel.Text = "Output Files Written to - " + $scriptPath
$mainForm.Controls.Add($outputLabel)

 
The last Form Controls are the Process, Display and Exit Buttons.
 

# Process Button
$buttonProcess = New-Object System.Windows.Forms.Button
$buttonProcess.Location = "665,80"
$buttonProcess.Size = "75, 23"
$buttonProcess.ForeColor = "Green" 
$buttonProcess.Text = "Process"
$buttonProcess.add_Click({ProcessButton})
$mainForm.Controls.Add($buttonProcess)

# Display Button
$buttonDisplay = New-Object System.Windows.Forms.Button
$buttonDisplay.Location = "770,80"
$buttonDisplay.Size = "75, 23"
$buttonDisplay.ForeColor = "Green" 
$buttonDisplay.Text = "Display"
$buttonDisplay.add_Click({DisplayImage})
$mainForm.Controls.Add($buttonDisplay)

# Exit Button
$buttonExit = New-Object System.Windows.Forms.Button
$buttonExit.Location = "870,80"
$buttonExit.Size = "75, 23"
$buttonExit.ForeColor = "Red" 
$buttonExit.Text = "Exit"
$buttonExit.add_Click({$mainForm.close()})
$mainForm.Controls.Add($buttonExit)

 
In the ProcessButton Function I first initialize $error and the $CompleteLabel values and set default colors. I define the Brush using the input image file as the Texture. I set the Brush to paint the image borders as Black. The output image is defined as the same size as the input image. The Graphics class object for the image is set. The image Background Color is set. Finally the selected function is called using Invoke-Expression.
 

Function ProcessButton {
    $error.clear()
    $completeLabel.Text = "        " 

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

    # Image Brush
    $image = [System.Drawing.Image]::FromFile($textBoxIn.Text)
    $brush = New-Object System.Drawing.TextureBrush($image, "Tile")
    $brushBlack = New-Object System.Drawing.SolidBrush("Black")

    # Create Image
    $bitmap = New-Object System.Drawing.Bitmap($image.Width,$image.Height)
    $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)
        }
    }

    # Call Selected Fill
    Invoke-Expression $global:selectedObject
} # End ProcessButton

 
As an example of the Brushes used to fill the image here is the Squares function. The image we are filling with and the output image are the same size so the position and size of the selected fill are in their original location. Within an iteration the size of the number of selected objects, the X, Y, Height and Width values are randomized. Since this is a square I simply make the height and width values the same. If a border has been selected (width > 0) then a black border is simulated by filling a rectangle in the same location but larger by the border size value. The fill image will overwrite all but the simulated border. The fill uses the FillRectangle method. After the fill iteration has completed the file is written to disk in the same folder as the script with a unique name containing the date, time and brush style. An error check confirms the process success and write a completed status label.
 

Function Squares {
    $i = 0
    While ($i -le $global:numberObjects) { $i++
        $pointX = (Get-Random -minimum -100 -maximum ([int]$image.width + 100))
        $pointY = (Get-Random -minimum -100 -maximum ([int]$image.height + 100))
        $width = (Get-Random -minimum 1 -maximum ([int]$image.height * .25))
        $height = $width
        If ([int]$frameComboBox.Text -ge 1) {
            $bitmapGraphics.FillRectangle($brushBlack, $pointX-$borderComboBox.Text, $pointY-$borderComboBox.Text, $width+([int]$borderComboBox.Text*2), $height+([int]$borderComboBox.Text*2))
        }
        $bitmapGraphics.FillRectangle($brush, $pointX, $pointY, $width, $height)
    }

    $global:outFile = $scriptPath + "\"  + "MosaicSquares_" + (Get-Date -UFormat %Y%m%d_%H%M%S) + ".bmp"
    $bitmap.Save($global:outFile)
    FinalPicture($global:outFile)

    $bitmap.Dispose()
    $bitmapGraphics.Dispose()
    If($error.count -gt 0) {
        $completeLabel.ForeColor = "Red"
        $completeLabel.Text = "Error!"
    } Else {
        $completeLabel.ForeColor = "Green"
        $completeLabel.Text = "Success!"
    }
} # End Squares

 
Polygons (and Curves) use a list of points to define the object to be filled. The list is built and then the object created and filled at once instead of creating a lot of individual fill objects.
 

Function Polygons {
    $i = 0; $polygon = @()
    While ($i -le $global:numberObjects) { $i++
        $polygonNext = New-Object System.Drawing.Point `
            ((Get-Random -minimum 0 -maximum 1023), (Get-Random -minimum 0 -maximum 767)((Get-Random -minimum 0 -maximum $image.width), (Get-Random -minimum 0 -maximum $image.height)))
        $polygon += $polygonNext
    }
    $bitmapGraphics.FillPolygon($brush, $polygon)

    $global:outFile = $scriptPath + "\"  + "MosaicPolygons_" + (Get-Date -UFormat %Y%m%d_%H%M%S) + ".bmp"
    $bitmap.Save($global:outFile)
    FinalPicture($global:outFile)

    $bitmap.Dispose()
    $bitmapGraphics.Dispose()
    If($error.count -gt 0) {
        $completeLabel.ForeColor = "Red"
        $completeLabel.Text = "Error!"
    } Else {
        $completeLabel.ForeColor = "Green"
        $completeLabel.Text = "Success!"
    }
} # End Polygons

 
The output image is displayed in a PictureBox.
 

# Final PictureBox
$finalPicture = New-Object System.Windows.Forms.PictureBox
$finalPicture.Location = "520, 125"
$finalPicture.ClientSize = "480, 300"
$finalPicture.BackColor = "Black"
$finalPicture.SizeMode = "Zoom"
$mainForm.Controls.Add($finalPicture)

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

 
The image can be displayed in a full sized viewer. This will invoke the system default image viewer and open the output file.
 

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

 
 
MosaicImagePatterns
 
Download the complete script here – MosaicImagePatterns.ps1

Advertisements