Browse Source

Merge pull request #6 from CraigOates/0.5

0.5
master
Craig Oates 5 years ago committed by GitHub
parent
commit
adaf331038
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. BIN
      .github/Images/death-socket-logo.png
  2. 5
      DeathSocket/ColourServices.fs
  3. 14
      DeathSocket/DeathSocket.fsproj
  4. 60
      DeathSocket/Domain.fs
  5. 144
      DeathSocket/GridPainter.fs
  6. 109
      DeathSocket/ImageServices.fs
  7. 20
      DeathSocket/ScratchPad.fsx
  8. 8
      DeathSocket/Validation.fs
  9. 4
      DeathSocketCLI/AssemblyInfo.fs
  10. 32
      DeathSocketCLI/Commands.fs
  11. 16
      DeathSocketCLI/DeathSocketCLI.fsproj
  12. 79
      DeathSocketCLI/Validation.fs
  13. 5
      DeathSocketCLI/packages.config
  14. 50
      TestCentre/ConsoleTests.fs
  15. 93
      TestCentre/LibraryTests.fs
  16. 6
      TestCentre/Script.fsx
  17. 31
      TestCentre/TestCentre.fsproj
  18. 21
      TestCentre/packages.config

BIN
.github/Images/death-socket-logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

5
DeathSocket/ColourServices.fs

@ -2,6 +2,8 @@
open System.Drawing
open DeathSocket.Domain
open System
open SkiaSharp
let makeBrushFromRGBASpec (spec: RGBASpec) =
let a = int spec.alpha
@ -13,5 +15,4 @@
let makeBrushFromRGBA r g b a =
let colour = Color.FromArgb (a, r, g, b)
new SolidBrush (colour)
new SolidBrush (colour)

14
DeathSocket/DeathSocket.fsproj

@ -4,7 +4,7 @@
<TargetFramework>netstandard2.0</TargetFramework>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<Version>0.4-alpha</Version>
<Version>0.5-alpha</Version>
<Authors>Craig Oates</Authors>
<Product>Death Socket</Product>
<Description>A .Net Standard library which you can plug into to project and draw gridded overlays onto you images. Please note, Death Socket uses System.Drawing brushes and not System.Media brushes. For futher information, visit the projects repository on GitHub. To get a sense of what Death Socket can do, there is a console program you can download seperately (on GitHub).</Description>
@ -15,8 +15,9 @@
<RepositoryUrl>https://github.com/CraigOates/Death-Socket/tree/master</RepositoryUrl>
<RepositoryType>Git</RepositoryType>
<PackageTags>deathsocket craig oates image overlay f#</PackageTags>
<PackageReleaseNotes>This release has renamed the ImageSpec to BrushSpec and added a new RGBASpec type. The RGBASpec allows the user to pass in individual RGBA values instead of creating a SolidBrush before adding it to the BrushSpec.
New functions have been added so you can now create a SolidBrush using individual RGBA values or an RGBASpec -- you do not need to do it yourself. Another "apply grid" function has been added , as well, which uses the new RGBASpec.</PackageReleaseNotes>
<PackageReleaseNotes>With this release comes the ability to draw grids with SkiaSharp, alongside System.Drawing.</PackageReleaseNotes>
<AssemblyVersion>0.5.0.0</AssemblyVersion>
<PackageIconUrl>https://github.com/CraigOates/Death-Socket/blob/master/.github/Images/death-socket-logo.png</PackageIconUrl>
</PropertyGroup>
<ItemGroup>
@ -29,7 +30,12 @@ New functions have been added so you can now create a SolidBrush using individua
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Drawing.Common" Version="4.5.0" />
<PackageReference Include="SkiaSharp" Version="1.60.3" />
<PackageReference Include="System.Drawing.Common" Version="4.5.1" />
</ItemGroup>
<ItemGroup>
<PackageReference Update="FSharp.Core" Version="4.5.4" />
</ItemGroup>
</Project>

60
DeathSocket/Domain.fs

@ -5,14 +5,19 @@
module Domain =
open System.Drawing
open SkiaSharp
/// The specification which uses System.Drawing brush to draw a grid.
/// The specification used to note the orignial file's location and the
/// changes the user would like to make to it. (including the save
/// location of the modified version). Use this spec if you are using
/// System.Drawing.
type BrushSpec =
{ /// The original path of the image which the grid is being added to.
originalPath: string
/// The location of the new gridded image.
savePath: string
/// The (System.Drawing) brush used to draw the grid. This determines the colour.
/// The (System.Drawing) brush used to draw the grid.
/// This determines the colour of the grid.
colour: Brush
/// The thickness of the line on the grid.
penWidth: float32
@ -21,8 +26,11 @@
///The number of columns the grid will have.
columns: int }
/// The specification which uses includes individual RGBA values to
/// draw a grid.
/// The specification used to note the orignial file's location and the
/// changes the user would like to make to it (including the save
/// location of the modified version). This specification includes
/// individual RGBA values to describe the grid's colour. Use this spec.
/// if you are using System.Drawing.
type RGBASpec =
{ /// The original path of the image which the grid is being added to.
originalPath: string
@ -42,4 +50,48 @@
/// The number of rows the grid will have.
rows: int
///The number of columns the grid will have.
columns: int }
/// The specification used to note the orignial file's location and the
/// changes the user would like to make to it (including the save
/// location of the modified version). Use this spec. if you are using
/// the Skia-Sharp library.
type SkiaSpec =
{ /// The original path of the image which the grid is being added to.
originalPath: string
/// The location of the new gridded image.
savePath: string
/// The (SkiaSharp) colour used to draw the grid.
skColour: SKColor
/// The thickness of the line on the grid.
penWidth: float32
/// The number of rows the grid will have.
rows: int
///The number of columns the grid will have.
columns: int }
/// The specification used to note the orignial file's location and the
/// changes the user would like to make to it (including the save
/// location of the modified version). This specification includes
/// individual RGB values to describe the grid's colour. Use this spec.
/// if you are using the Skia-Sharp library.
type SkiaRGBSpec =
{ /// The original path of the image which the grid is being added to.
originalPath: string
/// The location of the new gridded image.
savePath: string
/// The amount of red (RGB) the grid's line will have.
/// (0 = no red, 255 = red turned up to eleven).
red: float32
/// The amount of green (RGB) the grid's line will have.
/// (0 = no green, 255 = green turned up to eleven).
green: float32
/// The amount of blue (RGB) the grid's line will have.
/// (0 = no blue, 255 = blue turned up to eleven).
blue: float32
/// The thickness of the line on the grid.
penWidth: float32
/// The number of rows the grid will have.
rows: int
///The number of columns the grid will have.
columns: int }

144
DeathSocket/GridPainter.fs

@ -4,18 +4,51 @@ namespace DeathSocket
open ColourServices
/// Provides functions which help draw gridded overlays onto images.
/// Grid Painter, and all of Death Socket, uses the System.Drawing brushes/colours.
/// If you are using System.Media brushes and colour, you will need to convert them.
/// Death Socket, uses System.Drawing's brushes and colours.
/// If you are using System.Media brushes and colour, you will need to
/// convert them. Death Socket, also, uses SkiaSharp for cross platform
/// functionality. If you are using Death Socket on Windows Desktop, use
/// functions which do not include "Skia" in their name. If you are using
/// Death Socket in a Xamarin/UWP project you should use the SkiaSharp
/// functions.
module GridPainter =
open Validation
open ImageServices
// System.Drawing Functions
// ========================================================================
/// <summary>
/// Determines the (Pen) points needed to draw the appropriate number
/// of horizontal lines (I.E. rows). Each item in the array includes a
/// start and end co-ordinate (point) for each line.
/// Use this function when targeting .Net/Mono).
/// </summary>
/// <param name="width">The width of the image.</param>
/// <param name="height">The height of the image.</param>
/// <param name="rows">The number of rows the grid should have.</param>
/// <remarks>You will probably only need these when dealing with GUI's.</remarks>
let determineHorizontalLines (width: int) (height: int) (rows: int) =
createHorizontalLines width height rows
/// <summary>
/// Determines the (Pen) points needed to draw the appropriate number
/// of vertical lines (I.E. columns). Each item in the array includes a
/// start and end co-ordinate (point) for each line.
/// Use this function when targeting Windows Desktop (or Mono).
/// </summary>
/// <param name="width">The width of the image.</param>
/// <param name="height">The height of the image.</param>
/// <param name="columns">The number of columns the grid should have.</param>
/// <remarks>You will probably only need these when dealing with GUI's.</remarks>
let determineVerticalLines (width: int) (height: int) (columns: int) =
createVerticalLines width height columns
/// <summary>
/// Uses the information included in spec to create a gridded image.
/// It then asynchronously saves it.
/// Please stick to .bmp, .jpg or .png files.
/// The other (image) file types have not been tested.
/// It then asynchronously saves it. Uses .jpg or .png formats only.
/// Use this function when targeting .Net/Mono).
/// </summary>
/// <param name="spec">
/// The specification used to generate the new gridded image
@ -33,7 +66,7 @@ namespace DeathSocket
async {
try
validateFilePath spec.originalPath |> ignore
validatFileType spec.savePath |> ignore
validateSaveFileType spec.savePath |> ignore
drawBrushSpecGrid spec |> ignore
with
| :? FileNotFoundException as ex ->
@ -42,8 +75,8 @@ namespace DeathSocket
/// <summary>
/// Uses the information included in spec to create a gridded image. It
/// then asynchronously saves it. Please stick to .bmp, .jpg or .png
/// files. The other (image) file types have not been tested.
/// then asynchronously saves it. Uses .jpg or .png formats only.
/// Use this function when targeting .Net/Mono).
/// </summary>
/// <param name="spec">
/// The specification used to generate the gridded image.
@ -61,7 +94,7 @@ namespace DeathSocket
async {
try
validateFilePath spec.originalPath |> ignore
validatFileType spec.savePath |> ignore
validateSaveFileType spec.savePath |> ignore
drawRGBAGrid spec
with
| :? FileNotFoundException as ex ->
@ -70,6 +103,7 @@ namespace DeathSocket
/// <summary>
/// Creates a Sytsem.Drawing SolidBrush from the individual RGBA values.
/// Use this function when targeting .Net/Mono).
/// </summary>
/// <param name="r">The red value.</param>
/// <param name="g">The green value.</param>
@ -79,10 +113,12 @@ namespace DeathSocket
/// Death Socket uses System.Drawing and not System.Media for colours
/// and brushes.
/// </remarks>
let makeSolidBrushFromRGBA r g b a = makeBrushFromRGBA r g b a
let makeSolidBrushFromRGBA (r: int) (g: int) (b:int) (a: int) =
makeBrushFromRGBA r g b a
/// <summary>
/// Creates a System.Drawing SolidBrush from a RGBASpec.
/// Use this function when targeting .Net/Mono).
/// </summary>
/// <param name="spec">
///The specification which the brush is made from.
@ -91,26 +127,90 @@ namespace DeathSocket
/// Death Socket uses System.Drawing and not System.Media for colours
/// and brushes.
/// </remarks>
let makeSolidBrushFromRGBASpec spec = makeBrushFromRGBASpec spec
let makeSolidBrushFromRGBASpec (spec: RGBASpec) =
makeBrushFromRGBASpec spec
// SkiaSharp Functions
// ========================================================================
/// <summary>
/// Determines the (Pen) points needed to draw the appropriate number of horizontal lines (I.E. rows).
/// Each item in the array includes a start and end co-ordinate (point) for each line.
/// Determines the (SKPoints) points needed to draw the appropriate
/// number of horizontal lines (I.E. rows). Each item in the array
/// included a start and end co-ordinate (SKPoint) for each line.
/// Use this function when targeting Xamarin/UWP/.Net Core (SkiaSharp).
/// </summary>
/// <param name="width">The width of the image.</param>
/// <param name="height">The height of the image.</param>
/// <param name="rows">The number of rows the grid should have.</param>
/// <remarks>You will probably only need these when dealing with GUI's.</remarks>
let determineHorizontalLines width height rows =
createHorizontalLines width height rows
/// <remarks>This function is part of the SkiaSharp functions provided
/// by Death Socket.</remarks>
let determineSKHorizontalLines (width: int) (height: int) (rows: int) =
createSKHorizontalLines width height rows
/// <summary>
/// Determines the (Pen) points needed to draw the appropriate number of vertical lines (I.E. columns).
/// Each item in the array includes a start and end co-ordinate (point) for each line.
/// Determines the (SKPoints) points needed to draw the appropriate
/// number of vertical lines (I.E. columns). Each item in the array
/// included a start and end co-ordinate (SKPoint) for each line.
/// Use this function when targeting Xamarin/UWP/.Net Core (SkiaSharp).
/// </summary>
/// <param name="width">The width of the image.</param>
/// <param name="height">The height of the image.</param>
/// <param name="columns">The number of columns the grid should have.</param>
/// <remarks>You will probably only need these when dealing with GUI's.</remarks>
let determineVerticalLines width height columns =
createVerticalLines width height columns
/// <param name="columns">The number of columns the grid should have.
/// </param>
/// <remarks>This function is part of the SkiaSharp functions provided
/// by Death Socket.</remarks>
let determineSKVerticalLines (width: int) (height: int) (columns: int) =
createSKVerticalLines width height columns
/// <summary>
/// Uses the information included in spec to create a gridded image.
/// It then asynchronously saves it. Uses .jpg or .png formats only.
/// Use this function when targeting Xamarin/UWP/.Net Core.
/// </summary>
/// <param name="spec">
/// Used to note the orignial file's location and the
/// changes the user would like to make to it (including the save
/// location of the modified version).
/// </param>
/// <remarks>
/// Make sure the image, which is having the overlay added to it,
/// is not in use or needed by another program/process.
/// This is because it is locked whilst in this function.
/// </remarks>
let applySkiaGridAsync (spec: SkiaSpec) =
async {
try
validateFilePath spec.originalPath |> ignore
validateSaveFileType spec.savePath |> ignore
drawSkiaGrid spec
with
| :? FileNotFoundException as ex ->
printfn "File could not be found at %s" ex.Message
}
/// <summary>
/// Uses the information included in spec to create a gridded image.
/// It then asynchronously saves it. Uses .jpg or .png formats only.
/// Use this function when targeting Xamarin/UWP/.Net Core.
/// </summary>
/// <param name="spec">
/// Used to note the orignial file's location and the
/// changes the user would like to make to it (including the save
/// location of the modified version).
/// </param>
/// <remarks>
/// Make sure the image, which is having the overlay added to it,
/// is not in use or needed by another program/process.
/// This is because it is locked whilst in this function.
/// </remarks>
let applySkiaRGBGridAsync (spec: SkiaRGBSpec) =
async {
try
validateFilePath spec.originalPath |> ignore
validateSaveFileType spec.savePath |> ignore
drawSkiaRGBGrid spec
with
| :? FileNotFoundException as ex ->
printfn "File could not be found at %s" ex.Message
}

109
DeathSocket/ImageServices.fs

@ -1,9 +1,106 @@
module internal ImageServices
open System.IO
open System.Drawing
open System.Drawing.Imaging
open DeathSocket
open ColourServices
open SkiaSharp
// SkiaSharp Functions
// ========================================================================
let createSKHorizontalLines width height rows =
let interval = float32 (height / rows)
[|for point in 1 .. (rows - 1) ->
[| SKPoint ((float32 0), (interval * (float32 point)))
SKPoint ((float32 width), (interval * (float32 point)))|]|]
let createSKVerticalLines width height columns =
let interval = float32 (width / columns)
[| for point in 1 .. (columns - 1) ->
[| SKPoint ((interval * (float32 point)), (float32 0))
SKPoint ((interval * (float32 point)), (float32 height))|]|]
let drawSkiaGrid (spec: SkiaSpec) =
use fileStream = File.Open (spec.originalPath, FileMode.Open)
use skStream = new SKManagedStream (fileStream)
use bitmap = SKBitmap.Decode (skStream)
use shader =
SKShader.CreateBitmap (bitmap, SKShaderTileMode.Mirror, SKShaderTileMode.Mirror)
let imageInfo = new SKImageInfo (bitmap.Width, bitmap.Height)
use surface = SKSurface.Create (imageInfo)
use canvas = surface.Canvas
canvas.Clear (SKColors.White)
use imageFill = new SKPaint ()
imageFill.Style <- SKPaintStyle.Fill
imageFill.Shader <- shader
canvas.DrawPaint (imageFill)
use stroke = new SKPaint ()
stroke.Style <- SKPaintStyle.Stroke
stroke.StrokeWidth <- spec.penWidth
stroke.Color <- spec.skColour
let horizontalLines =
createSKHorizontalLines (bitmap.Width) (bitmap.Height) (spec.rows)
let verticalLines =
createSKVerticalLines (bitmap.Width) (bitmap.Height) (spec.columns)
for hLine in horizontalLines do
canvas.DrawLine (hLine.[0], hLine.[1], stroke)
for vLine in verticalLines do
canvas.DrawLine (vLine.[0], vLine.[1], stroke)
use snapshot = surface.Snapshot ()
use data =
match Path.GetExtension (spec.savePath) with
| ".jpg" | ".JPG" -> snapshot.Encode (SKEncodedImageFormat.Jpeg, 100)
| ".png"| ".PNG" -> snapshot.Encode (SKEncodedImageFormat.Png, 100)
| _ -> invalidArg "savePath" "The file type must be a .jpg or .png file."
use saveStream = File.OpenWrite (spec.savePath)
data.SaveTo (saveStream)
let drawSkiaRGBGrid spec =
use fileStream = File.Open (spec.originalPath, FileMode.Open)
use skStream = new SKManagedStream (fileStream)
use bitmap = SKBitmap.Decode (skStream)
use shader =
SKShader.CreateBitmap (bitmap, SKShaderTileMode.Mirror, SKShaderTileMode.Mirror)
let imageInfo = new SKImageInfo (bitmap.Width, bitmap.Height)
use surface = SKSurface.Create (imageInfo)
use canvas = surface.Canvas
canvas.Clear (SKColors.White)
use imageFill = new SKPaint ()
imageFill.Style <- SKPaintStyle.Fill
imageFill.Shader <- shader
canvas.DrawPaint (imageFill)
use stroke = new SKPaint ()
stroke.Style <- SKPaintStyle.Stroke
stroke.StrokeWidth <- spec.penWidth
stroke.Color <-
new SKColor ((byte spec.red), (byte spec.green), (byte spec.blue))
let horizontalLines =
createSKHorizontalLines (bitmap.Width) (bitmap.Height) (spec.rows)
let verticalLines =
createSKVerticalLines (bitmap.Width) (bitmap.Height) (spec.columns)
for hLine in horizontalLines do
canvas.DrawLine (hLine.[0], hLine.[1], stroke)
for vLine in verticalLines do
canvas.DrawLine (vLine.[0], vLine.[1], stroke)
use snapshot = surface.Snapshot ()
use data =
match Path.GetExtension (spec.savePath) with
| ".jpg" | ".JPG" -> snapshot.Encode (SKEncodedImageFormat.Jpeg, 100)
| ".png"| ".PNG" -> snapshot.Encode (SKEncodedImageFormat.Png, 100)
| _ -> invalidArg "savePath" "The file type must be a .jpg or .png file."
use saveStream = File.OpenWrite (spec.savePath)
data.SaveTo (saveStream)
// System.Drawing Functions
// ========================================================================
let createHorizontalLines width height rows =
let interval = height / rows
@ -17,10 +114,10 @@
[| Point ((interval * point), 0)
Point ((interval * point), height)|]|]
(* Note on Use of Temp File in Functions which Add A Grid Overlay
(* Note on Use of Temp. File in Functions which Add A Grid Overlay
===========================================================================
The temp. file is used in the functions below are there to convert images
with indexed pixels. Instead of listig them all, just assume any function
with indexed pixels. Instead of listing them all, just assume any function
with a "*Spec" type as a parameter will use this "temp" file. *)
let drawBrushSpecGrid (spec: BrushSpec) =
@ -40,15 +137,15 @@
let drawRGBAGrid (spec: RGBASpec) =
use original = Bitmap.FromFile spec.originalPath
use temp = new Bitmap(original)
use clone = temp.Clone(new Rectangle(0, 0, temp.Width, temp.Height), PixelFormat.Format32bppArgb)
use temp = new Bitmap (original)
use clone = temp.Clone (new Rectangle(0, 0, temp.Width, temp.Height), PixelFormat.Format32bppArgb)
use graphics = Graphics.FromImage(clone)
use pen = new Pen ((makeBrushFromRGBASpec spec), width = spec.penWidth)
graphics.DrawImage(original,new Rectangle(0, 0, clone.Width, clone.Height))
graphics.DrawImage (original,new Rectangle(0, 0, clone.Width, clone.Height))
let horizontalLines =
createHorizontalLines (clone.Size.Width) (clone.Size.Height) (spec.rows)
let verticalLines =
createVerticalLines (clone.Size.Width) (clone.Size.Height) (spec.columns)
for line in horizontalLines do graphics.DrawLines (pen, line)
for line in verticalLines do graphics.DrawLines (pen, line)
clone.Save (spec.savePath)
clone.Save (spec.savePath)

20
DeathSocket/ScratchPad.fsx

@ -1,5 +1,9 @@
#load "Domain.fs"
#r @"C:\Users\craig\.nuget\packages\skiasharp\1.60.3\lib\netstandard1.3\SkiaSharp.dll"
#r @"C:\Users\craig\.nuget\packages\skiasharp\1.60.3\lib\net45\SkiaSharp.dll"
#load "Domain.fs"
#load "Validation.fs"
#load "ColourServices.fs"
#load "ImageServices.fs"
#load "GridPainter.fs"
@ -30,7 +34,7 @@ let verticalLines = createVerticalLines 300 600 10
Death Socket assumes either JPEG or PNG files so use other files at your own
risk. Cannot guarantee they will work. Also, either in this spec. can be
changed to suit your needs. *)
let spec :ImageSpec =
let spec: BrushSpec =
{ originalPath = desktop + "/test.jpg"
savePath = desktop + "/grid.png"
colour = Brushes.Chartreuse
@ -39,4 +43,14 @@ let spec :ImageSpec =
columns = 10 }
// Run this when you have finished building the spec.
GridPainter.applyGridAsync spec |> Async.RunSynchronously
GridPainter.applyBrushSpecGridAsync spec |> Async.RunSynchronously
//*****************************************************************************
(* Skia Sharp Draft
===============================================================================
The code below here will eventually be worked into the main codebase or thrown
away. It is here acting as a first draft for integrating the Skia Sharp NuGet
package into Death Socket. *)
drawSkiaGrid()

8
DeathSocket/Validation.fs

@ -7,14 +7,10 @@
| true -> ()
| false -> raise (new FileNotFoundException (path + " could not be found."))
let validatFileType file =
let validateSaveFileType file =
match Path.GetExtension file with
| ".bmp" -> ()
| ".BMP" -> ()
| ".jpg" -> ()
| ".JPG" -> ()
| ".png" -> ()
| ".PNG" -> ()
| ".tif" -> ()
| ".TIF" -> ()
| _ -> invalidArg "savePath" "The file type must be a .bmp, .jpg, .png or .tif file."
| _ -> invalidArg "savePath" "The file type must be a .jpg or .png file."

4
DeathSocketCLI/AssemblyInfo.fs

@ -38,8 +38,8 @@ open System.Runtime.InteropServices
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [<assembly: AssemblyVersion("1.0.*")>]
[<assembly: AssemblyVersion("0.4.0.0")>]
[<assembly: AssemblyFileVersion("0.4.0.0")>]
[<assembly: AssemblyVersion("0.5.0.0")>]
[<assembly: AssemblyFileVersion("0.5.0.0")>]
do
()

32
DeathSocketCLI/Commands.fs

@ -1,6 +1,7 @@
namespace Commands
module ConsoleCommands =
open System
open DeathSocket.GridPainter
open DeathSocketCLI.Validation
@ -90,4 +91,33 @@
let ag imgPath numRows numColumns pWidth colour newPath =
``add-grid`` imgPath numRows numColumns pWidth colour newPath
let lc () =``list-colours`` ()
let lc () =``list-colours`` ()
(* SkiaSharp Command-Methods -- NOT FOR MASS CONSUMPTION
=======================================================================
These command-methods will not show up in the help section. These
command-methods are here for testing purposes. They mimic the command-
methods above, apart from using SkiaSharp. So, including these command-
methods will create a sense of duplicated functionality. Seeing as you
are reading this, it is assumed you can understand it. If so, please
feel free to use them -- just keep their exposure to a minimum.*)
let ``list-skia-colours`` () =
printfn "[INFO.] Listing available SkiaSharp colours..."
for item in skiaColourList do
printfn "%s" item.Key
showEndOfCommandMessage
let``add-skia-grid`` imgPath numRows numColumns pWidth colour newPath =
printfn "[INFO.] Adding SkiaSharp grid to image..."
buildSkiaSpec imgPath numRows numColumns pWidth colour newPath
|> applySkiaGridAsync
|> Async.Start
showEndOfCommandMessage
let``add-skia-rgb-grid`` imgPath numRows numColumns pWidth r g b newPath =
printfn "[INFO.] Adding SkiaSharp grid to image..."
buildSkiaRGBSpec imgPath numRows numColumns pWidth r g b newPath
|> applySkiaRGBGridAsync
|> Async.Start
showEndOfCommandMessage

16
DeathSocketCLI/DeathSocketCLI.fsproj

@ -14,6 +14,8 @@
<UseStandardResourceNames>True</UseStandardResourceNames>
<Name>DeathSocketCLI</Name>
<Win32Resource>..\DeathSocketCLI\resources.res</Win32Resource>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -60,14 +62,17 @@
<HintPath>..\packages\Console.Waterworks.0.1.0.0-alpha1\lib\Console.Waterworks.dll</HintPath>
</Reference>
<Reference Include="FSharp.Core">
<HintPath>..\packages\FSharp.Core.4.5.2\lib\net45\FSharp.Core.dll</HintPath>
<HintPath>..\packages\FSharp.Core.4.5.4\lib\net45\FSharp.Core.dll</HintPath>
</Reference>
<Reference Include="mscorlib" />
<Reference Include="SkiaSharp">
<HintPath>..\packages\SkiaSharp.1.60.3\lib\net45\SkiaSharp.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Drawing.Common">
<HintPath>..\packages\System.Drawing.Common.4.5.0\lib\net461\System.Drawing.Common.dll</HintPath>
<HintPath>..\packages\System.Drawing.Common.4.5.1\lib\net461\System.Drawing.Common.dll</HintPath>
</Reference>
<Reference Include="System.Numerics" />
<Reference Include="System.ValueTuple">
@ -81,6 +86,13 @@
<Private>True</Private>
</ProjectReference>
</ItemGroup>
<Import Project="..\packages\SkiaSharp.1.60.3\build\net45\SkiaSharp.targets" Condition="Exists('..\packages\SkiaSharp.1.60.3\build\net45\SkiaSharp.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\SkiaSharp.1.60.3\build\net45\SkiaSharp.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\SkiaSharp.1.60.3\build\net45\SkiaSharp.targets'))" />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">

79
DeathSocketCLI/Validation.fs

@ -4,6 +4,19 @@
open System.Drawing
open System
open System.IO
open SkiaSharp
(* This function creates a consistent line width amoung different image
sizes. Use this when the user has no means to specify a pen width. *)
let setPenWidth imgWidth imgHeight =
let width = float32 imgWidth
let height = float32 imgHeight
if (width >= height) then
height * (float32 0.002)
else width * (float32 0.002)
// System.Drawing Functions
// ========================================================================
let colourList =
[ "blue", Brushes.AliceBlue
@ -32,16 +45,7 @@
(String.Concat("The colour specifed is invalid.\n",
"Please use the 'list-colours' command to see what you can use."))
(* This function creates a consistent line width amoung different image
sizes. Use this when the user has no means to specify a pen width. *)
let setPenWidth imgWidth imgHeight =
let width = float32 imgWidth
let height = float32 imgHeight
if (width >= height) then
height * (float32 0.002)
else width * (float32 0.002)
let buildSpec imgPath numRows numColumns pWidth colour newPath =
let buildSpec (imgPath) (numRows) (numColumns) (pWidth) (colour) (newPath) : BrushSpec =
{ originalPath = imgPath
savePath = newPath
colour = parseColour colour
@ -52,13 +56,60 @@
let buildDefaultSpec imgPath newPath =
use stream = new FileStream (imgPath, FileMode.Open)
use image = Image.FromStream (stream, false, false)
let spec =
let spec : BrushSpec =
{ originalPath = imgPath
savePath = newPath
colour = Brushes.White
penWidth = setPenWidth (image.Width) (image.Height)
rows = 10
columns = 10 }
stream.Dispose ()
image.Dispose ()
spec
spec
// SkiaSharp Functions
// ========================================================================
let skiaColourList =
[ "blue", SKColors.AliceBlue
"brown", SKColors.Brown
"black", SKColors.Black
"gray", SKColors.Gray
"grey", SKColors.Gray
"green", SKColors.Green
"purple", SKColors.Purple
"red", SKColors.Red
"white", SKColors.White
"yellow", SKColors.Yellow ]
|> Map.ofList
let isSkiaColourValid (colour: string) =
skiaColourList
|> Map.containsKey (colour.ToLower())
let parseSkiaColour colour =
match (isSkiaColourValid colour) with
| true ->
skiaColourList
|> Map.find (colour.ToLower())
| false ->
invalidArg "Colour"
(String.Concat("The colour specifed is invalid.\n",
"Please use the 'list-skia-colours' command to see what you can use."))
let buildSkiaSpec imgPath numRows numColumns pWidth colour newPath =
let colour = parseSkiaColour colour
{ originalPath = imgPath
savePath = newPath
skColour = colour
penWidth = pWidth
rows = numRows
columns = numColumns }
let buildSkiaRGBSpec imgPath numRows numColumns pWidth r g b newPath =
{ originalPath = imgPath
savePath = newPath
red = (float32 r)
green = (float32 g)
blue = (float32 b)
penWidth = pWidth
rows = numRows
columns = numColumns }

5
DeathSocketCLI/packages.config

@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Console.Waterworks" version="0.1.0.0-alpha1" targetFramework="net471" />
<package id="FSharp.Core" version="4.5.2" targetFramework="net471" />
<package id="System.Drawing.Common" version="4.5.0" targetFramework="net471" />
<package id="FSharp.Core" version="4.5.4" targetFramework="net471" />
<package id="SkiaSharp" version="1.60.3" targetFramework="net471" />
<package id="System.Drawing.Common" version="4.5.1" targetFramework="net471" />
<package id="System.ValueTuple" version="4.5.0" targetFramework="net471" />
</packages>

50
TestCentre/ConsoleTests.fs

@ -88,6 +88,45 @@
buildSpec loadPath randRows randCols pWidth colourString savePath
intendedSpec = spec
[<Property>]
let ``Can build a SkiaSpec as intended`` () =
let colourString = randomColourString ()
let colour = parseSkiaColour colourString
let pWidth = float32 (Random().Next())
let randRows = (Random().Next())
let randCols = (Random().Next())
let intendedSpec =
{ originalPath = loadPath
savePath = savePath
skColour = colour
penWidth = pWidth
rows =randRows
columns = randCols }
let spec =
buildSkiaSpec loadPath randRows randCols pWidth colourString savePath
intendedSpec = spec
[<Property>]
let ``Can build a SkiaRGBSpec as intended`` () =
let r = (Random().Next())
let g = (Random().Next())
let b = (Random().Next())
let pWidth = float32 (Random().Next())
let randRows = (Random().Next())
let randCols = (Random().Next())
let intendedSpec =
{ originalPath = loadPath
savePath = savePath
red = (float32 r)
green = (float32 g)
blue = (float32 b)
penWidth = pWidth
rows =randRows
columns = randCols }
let spec =
buildSkiaRGBSpec loadPath randRows randCols pWidth r g b savePath
intendedSpec = spec
module UnitTests =
open System.IO
@ -110,4 +149,13 @@
[<Fact>]
let ``Exception thrown when invalid colour is used`` () =
Assert.Throws<System.ArgumentException>
(fun () -> parseColour "not a valid colour" |> ignore)
(fun () -> parseColour "not a valid colour" |> ignore)
[<Fact>]
let ``Skia colour list is not empty`` () =
Assert.False (skiaColourList.IsEmpty)
[<Fact>]
let ``Exception thrown when invalid skia-colour is used`` () =
Assert.Throws<System.ArgumentException>
(fun () -> parseSkiaColour "not a valid colour" |> ignore)

93
TestCentre/LibraryTests.fs

@ -21,6 +21,7 @@
open System.Reflection
open System.IO
open DeathSocket.Domain
open SkiaSharp
let rand = Random ()
@ -42,7 +43,18 @@
let randomBrush () =
let item = allColours.[rand.Next(allColours.Length)]
item.GetValue(null, null)
item.GetValue (null, null)
let allSKColours =
let properties =
typeof<SKColors>.GetFields
(BindingFlags.Static ||| BindingFlags.Public)
seq {for prop in properties -> prop}
|> Seq.toArray
let randomSKColour () =
let item = allSKColours.[rand.Next(allSKColours.Length)]
item.GetValue (null) :?> SKColor
(* Max. value is arbitrary (change for performance).
Min. value is to stop divide by zero exceptions.
@ -93,6 +105,7 @@
open DeathSocket.GridPainter
open TestingHelpers
open System.IO
open SkiaSharp
(* With regards to the "saving images" tests, you should end up with
one image left over in the SavingTestArea folder. Comment out the
@ -104,14 +117,13 @@
resetSavingTestArea ()
let oPath = generateLoadPath ()
let sPath = generateSavePath oPath
let (spec: BrushSpec) =
{ originalPath = oPath
savePath = sPath
colour = randomBrush () :?> Brush
penWidth = float32 (newPenWidth())
rows = 10
columns = 10 }
applyBrushSpecGridAsync spec
{ originalPath = oPath
savePath = sPath
colour = randomBrush () :?> Brush
penWidth = float32 (newPenWidth())
rows = 10
columns = 10 }
|> applyBrushSpecGridAsync
|> Async.RunSynchronously
(File.Exists sPath) = true
@ -120,17 +132,16 @@
resetSavingTestArea ()
let oPath = generateLoadPath ()
let sPath = generateSavePath oPath
let (spec: RGBASpec) =
{ originalPath = oPath
savePath = sPath
alpha = float (newRGBANum ())
red = float (newRGBANum ())
green = float (newRGBANum ())
blue = float (newRGBANum ())
penWidth = float32 (newPenWidth())
rows = 10
columns = 10 }
applyRGBAGridAsync spec
{ originalPath = oPath
savePath = sPath
alpha = float (newRGBANum ())
red = float (newRGBANum ())
green = float (newRGBANum ())
blue = float (newRGBANum ())
penWidth = float32 (newPenWidth())
rows = 10
columns = 10 }
|> applyRGBAGridAsync
|> Async.RunSynchronously
(File.Exists sPath) = true
@ -165,6 +176,48 @@
let result = determineVerticalLines (newNum()) (newNum()) (newNum())
result.Length > 0
[<Property>]
let ``Can apply grid to image and save it using SkiaSpec`` () =
resetSavingTestArea()
let oPath = generateLoadPath ()
let sPath = generateSavePath oPath
{ originalPath = oPath
savePath= sPath
skColour = randomSKColour ()
penWidth = float32 (newPenWidth())
rows = newNum ()
columns = newNum () }
|> applySkiaGridAsync
|> Async.RunSynchronously
(File.Exists sPath) = true
[<Property>]
let ``Can apply grid to image and save it using SkiaRGBSpec`` () =
resetSavingTestArea()
let oPath = generateLoadPath ()
let sPath = generateSavePath oPath
{ originalPath = oPath
savePath= sPath
red = float32 (newRGBANum ())
green = float32 (newRGBANum ())
blue = float32 (newRGBANum ())
penWidth = float32 (newPenWidth())
rows = newNum ()
columns = newNum () }
|> applySkiaRGBGridAsync
|> Async.RunSynchronously
(File.Exists sPath) = true
[<Property>]
let ``Can return a collection of SKPoints which represent a grids horizontal lines`` () =
let result = determineSKHorizontalLines (newNum()) (newNum()) (newNum())
result.Length > 0
[<Property>]
let ``Can return a collection of SKPoints which represent a grids vertical lines`` () =
let result = determineSKVerticalLines (newNum()) (newNum()) (newNum())
result.Length > 0
module UnitTests =
open TestingHelpers

6
TestCentre/Script.fsx

@ -100,7 +100,7 @@ populateLoadingTestArea ()
This bit of code is for creating the SavingTestArea folder which Test Centre
will use when it runs its tests. You will normally only need to run this code
when you have just cloned this repository or you accidently deleted said
fodler. In other words, you should only need to use it once. *)
folder. In other words, you should only need to use it once. *)
let createSavingTestArea () =
match Directory.Exists saveLocation with
@ -109,6 +109,6 @@ let createSavingTestArea () =
printfn "SavingTestArea created."
| _ -> printfn "SavingTestArea already exists."
(* Before calling this function, make sure the test checking this folder exists
is failing first. *)
(* Before calling this function, make sure the test checking to see if this
folder exists is failing first. *)
createSavingTestArea ()

31
TestCentre/TestCentre.fsproj

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\xunit.core.2.4.0\build\xunit.core.props" Condition="Exists('..\packages\xunit.core.2.4.0\build\xunit.core.props')" />
<Import Project="..\packages\xunit.runner.visualstudio.2.4.0\build\net20\xunit.runner.visualstudio.props" Condition="Exists('..\packages\xunit.runner.visualstudio.2.4.0\build\net20\xunit.runner.visualstudio.props')" />
<Import Project="..\packages\xunit.runner.visualstudio.2.4.1\build\net20\xunit.runner.visualstudio.props" Condition="Exists('..\packages\xunit.runner.visualstudio.2.4.1\build\net20\xunit.runner.visualstudio.props')" />
<Import Project="..\packages\xunit.core.2.4.1\build\xunit.core.props" Condition="Exists('..\packages\xunit.core.2.4.1\build\xunit.core.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@ -53,15 +53,18 @@
</ItemGroup>
<ItemGroup>
<Reference Include="FsCheck">
<HintPath>..\packages\FsCheck.2.11.0\lib\net452\FsCheck.dll</HintPath>
<HintPath>..\packages\FsCheck.2.13.0\lib\net452\FsCheck.dll</HintPath>
</Reference>
<Reference Include="FsCheck.Xunit">
<HintPath>..\packages\FsCheck.Xunit.2.11.0\lib\net452\FsCheck.Xunit.dll</HintPath>
<HintPath>..\packages\FsCheck.Xunit.2.13.0\lib\net452\FsCheck.Xunit.dll</HintPath>
</Reference>
<Reference Include="FSharp.Core">
<HintPath>..\packages\FSharp.Core.4.5.2\lib\net45\FSharp.Core.dll</HintPath>
<HintPath>..\packages\FSharp.Core.4.5.4\lib\net45\FSharp.Core.dll</HintPath>
</Reference>
<Reference Include="mscorlib" />
<Reference Include="SkiaSharp">
<HintPath>..\packages\SkiaSharp.1.60.3\lib\net45\SkiaSharp.dll</HintPath>
</Reference>
<Reference Include="SmoulderingBeachBall">
<HintPath>..\packages\SmoulderingBeachBall.0.4.0-alpha1\lib\netstandard2.0\SmoulderingBeachBall.dll</HintPath>
</Reference>
@ -69,7 +72,7 @@
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Drawing.Common">
<HintPath>..\packages\System.Drawing.Common.4.5.0\lib\net461\System.Drawing.Common.dll</HintPath>
<HintPath>..\packages\System.Drawing.Common.4.5.1\lib\net461\System.Drawing.Common.dll</HintPath>
</Reference>
<Reference Include="System.Numerics" />
<Reference Include="System.ValueTuple">
@ -79,13 +82,13 @@
<HintPath>..\packages\xunit.abstractions.2.0.3\lib\net35\xunit.abstractions.dll</HintPath>
</Reference>
<Reference Include="xunit.assert">
<HintPath>..\packages\xunit.assert.2.4.0\lib\netstandard2.0\xunit.assert.dll</HintPath>
<HintPath>..\packages\xunit.assert.2.4.1\lib\netstandard1.1\xunit.assert.dll</HintPath>
</Reference>
<Reference Include="xunit.core">
<HintPath>..\packages\xunit.extensibility.core.2.4.0\lib\net452\xunit.core.dll</HintPath>
<HintPath>..\packages\xunit.extensibility.core.2.4.1\lib\net452\xunit.core.dll</HintPath>
</Reference>
<Reference Include="xunit.execution.desktop">
<HintPath>..\packages\xunit.extensibility.execution.2.4.0\lib\net452\xunit.execution.desktop.dll</HintPath>
<HintPath>..\packages\xunit.extensibility.execution.2.4.1\lib\net452\xunit.execution.desktop.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
@ -104,11 +107,13 @@
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\xunit.runner.visualstudio.2.4.0\build\net20\xunit.runner.visualstudio.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\xunit.runner.visualstudio.2.4.0\build\net20\xunit.runner.visualstudio.props'))" />
<Error Condition="!Exists('..\packages\xunit.core.2.4.0\build\xunit.core.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\xunit.core.2.4.0\build\xunit.core.props'))" />
<Error Condition="!Exists('..\packages\xunit.core.2.4.0\build\xunit.core.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\xunit.core.2.4.0\build\xunit.core.targets'))" />
<Error Condition="!Exists('..\packages\xunit.core.2.4.1\build\xunit.core.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\xunit.core.2.4.1\build\xunit.core.props'))" />
<Error Condition="!Exists('..\packages\xunit.core.2.4.1\build\xunit.core.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\xunit.core.2.4.1\build\xunit.core.targets'))" />
<Error Condition="!Exists('..\packages\xunit.runner.visualstudio.2.4.1\build\net20\xunit.runner.visualstudio.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\xunit.runner.visualstudio.2.4.1\build\net20\xunit.runner.visualstudio.props'))" />
<Error Condition="!Exists('..\packages\SkiaSharp.1.60.3\build\net45\SkiaSharp.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\SkiaSharp.1.60.3\build\net45\SkiaSharp.targets'))" />
</Target>
<Import Project="..\packages\xunit.core.2.4.0\build\xunit.core.targets" Condition="Exists('..\packages\xunit.core.2.4.0\build\xunit.core.targets')" />
<Import Project="..\packages\xunit.core.2.4.1\build\xunit.core.targets" Condition="Exists('..\packages\xunit.core.2.4.1\build\xunit.core.targets')" />
<Import Project="..\packages\SkiaSharp.1.60.3\build\net45\SkiaSharp.targets" Condition="Exists('..\packages\SkiaSharp.1.60.3\build\net45\SkiaSharp.targets')" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">

21
TestCentre/packages.config

@ -1,17 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="FsCheck" version="2.11.0" targetFramework="net471" />
<package id="FsCheck.Xunit" version="2.11.0" targetFramework="net471" />
<package id="FSharp.Core" version="4.5.2" targetFramework="net471" />
<package id="FsCheck" version="2.13.0" targetFramework="net471" />
<package id="FsCheck.Xunit" version="2.13.0" targetFramework="net471" />
<package id="FSharp.Core" version="4.5.4" targetFramework="net471" />
<package id="SkiaSharp" version="1.60.3" targetFramework="net471" />
<package id="SmoulderingBeachBall" version="0.4.0-alpha1" targetFramework="net471" />
<package id="System.Drawing.Common" version="4.5.0" targetFramework="net471" />
<package id="System.Drawing.Common" version="4.5.1" targetFramework="net471" />
<package id="System.ValueTuple" version="4.5.0" targetFramework="net471" />
<package id="xunit" version="2.4.0" targetFramework="net471" />
<package id="xunit" version="2.4.1" targetFramework="net471" />
<package id="xunit.abstractions" version="2.0.3" targetFramework="net471" />
<package id="xunit.analyzers" version="0.10.0" targetFramework="net471" />
<package id="xunit.assert" version="2.4.0" targetFramework="net471" />
<package id="xunit.core" version="2.4.0" targetFramework="net471" />
<package id="xunit.extensibility.core" version="2.4.0" targetFramework="net471" />
<package id="xunit.extensibility.execution" version="2.4.0" targetFramework="net471" />
<package id="xunit.runner.visualstudio" version="2.4.0" targetFramework="net471" developmentDependency="true" />
<package id="xunit.assert" version="2.4.1" targetFramework="net471" />
<package id="xunit.core" version="2.4.1" targetFramework="net471" />
<package id="xunit.extensibility.core" version="2.4.1" targetFramework="net471" />
<package id="xunit.extensibility.execution" version="2.4.1" targetFramework="net471" />
<package id="xunit.runner.visualstudio" version="2.4.1" targetFramework="net471" developmentDependency="true" />
</packages>
Loading…
Cancel
Save