Browse Source

Merge pull request #4 from CraigOates/0.3

0.3
master
Craig Oates 6 years ago committed by GitHub
parent
commit
579e48070e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 29
      DeathSocket/Domain.fs
  2. 53
      DeathSocket/GridPainter.fs
  3. 20
      DeathSocket/ImageServices.fs
  4. 13
      DeathSocket/Validation.fs
  5. 8
      DeathSocketCLI/Commands.fs
  6. 4
      DeathSocketCLI/Validation.fs
  7. 44
      TestCentre/LibraryTests.fs
  8. 2
      TestCentre/Script.fsx

29
DeathSocket/Domain.fs

@ -1,23 +1,24 @@
namespace DeathSocket namespace DeathSocket
/// The domain types used by Death Socket.
[<AutoOpen>] [<AutoOpen>]
module Domain = module Domain =
open System.Drawing open System.Drawing
open System.Drawing.Imaging
/// <summary>
/// The specification used by Death Socket when adding a grid to an image.
/// </summary>
type ImageSpec = type ImageSpec =
{ originalPath: string; { /// The original path of the image which the grid is being added to.
savePath: string; originalPath: string
colour: Brush; /// The location of the new gridded image.
penWidth: float32 savePath: string
rows: int; /// The (System.Drawing) brush used to draw the grid. This determines the colour.
columns: int } colour: Brush
/// The thickness of the line on the grid.
type StreamSpec = penWidth: float32
{ imagePath: string; /// The number of rows the grid will have.
format: ImageFormat; rows: int
colour: Brush; ///The number of columns the grid will have.
penWidth: float32
rows: int;
columns: int } columns: int }

53
DeathSocket/GridPainter.fs

@ -2,16 +2,61 @@ namespace DeathSocket
open System.IO open System.IO
/// 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.
module GridPainter = module GridPainter =
open Validation open Validation
open ImageServices open ImageServices
let applyGrid spec = /// <summary>
/// Uses the information included in spec and creates a gridded image.
/// It then asynchronously saves it.
/// Please stick to .bmp, .jpg or .png files.
/// The others (image) file types have not been tested.
/// </summary>
/// <param name="spec">
/// The specification used to generate the new gridded image
/// </param>
/// <exeption cref="System.IO.FileNotFoundException">
/// If the file the grid is being applied to cannot be found,
/// a FileNotFoundException will be thrown.
/// </exception>
/// <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 applyGridAsync spec =
async { async {
try try
validateFilePath |> ignore validateFilePath spec.originalPath |> ignore
validatFileType spec.savePath |> ignore
drawGrid spec |> ignore drawGrid spec |> ignore
with with
| :? FileNotFoundException as ex -> printfn "File could not be found at %s" ex.Message | :? FileNotFoundException as ex ->
} printfn "File could not be found at %s" ex.Message
}
/// <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.
/// </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
/// <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.
/// </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

20
DeathSocket/ImageServices.fs

@ -17,15 +17,17 @@
Point ((interval * point), height)|]|] Point ((interval * point), height)|]|]
let drawGrid spec = let drawGrid spec =
let img = Bitmap.FromFile spec.originalPath // The temp. file is used as a way to convert images with indexed pixels.
let graphics = Graphics.FromImage img use original = Bitmap.FromFile spec.originalPath
let pen = new Pen (spec.colour, width = spec.penWidth) 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 (spec.colour, width = spec.penWidth)
graphics.DrawImage(original,new Rectangle(0, 0, clone.Width, clone.Height))
let horizontalLines = let horizontalLines =
createHorizontalLines (img.Size.Width) (img.Size.Height) (spec.columns) createHorizontalLines (clone.Size.Width) (clone.Size.Height) (spec.rows)
let verticalLines = createVerticalLines (img.Size.Width) (img.Size.Height) (spec.columns) let verticalLines =
createVerticalLines (clone.Size.Width) (clone.Size.Height) (spec.columns)
for line in horizontalLines do graphics.DrawLines (pen, line) for line in horizontalLines do graphics.DrawLines (pen, line)
for line in verticalLines do graphics.DrawLines (pen, line) for line in verticalLines do graphics.DrawLines (pen, line)
img.Save (spec.savePath, ImageFormat.Png) clone.Save (spec.savePath)
img.Dispose ()
graphics.Dispose ()
pen.Dispose ()

13
DeathSocket/Validation.fs

@ -1,9 +1,20 @@
module internal Validation module internal Validation
open System.IO open System.IO
let validateFilePath path = let validateFilePath path =
match File.Exists path with match File.Exists path with
| true -> () | true -> ()
| false -> raise (new FileNotFoundException (path + " could not be found.")) | false -> raise (new FileNotFoundException (path + " could not be found."))
let validatFileType 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."

8
DeathSocketCLI/Commands.fs

@ -38,8 +38,8 @@
try try
printfn "[INFO.] Adding default grid to image..." printfn "[INFO.] Adding default grid to image..."
buildDefaultSpec imgPath newPath buildDefaultSpec imgPath newPath
|> applyGrid |> applyGridAsync
|> Async.RunSynchronously |> Async.Start
showEndOfCommandMessage showEndOfCommandMessage
with with
| :? FileNotFoundException as ex -> "[ERROR] No file was found at " + ex.FileName | :? FileNotFoundException as ex -> "[ERROR] No file was found at " + ex.FileName
@ -57,8 +57,8 @@
try try
printfn "[INFO.] Adding grid to image..." printfn "[INFO.] Adding grid to image..."
buildSpec imgPath numRows numColumns pWidth colour newPath buildSpec imgPath numRows numColumns pWidth colour newPath
|> applyGrid |> applyGridAsync
|> Async.RunSynchronously |> Async.Start
showEndOfCommandMessage showEndOfCommandMessage
with with
| :? FileNotFoundException as ex -> "[ERROR] No file was found at " + ex.FileName | :? FileNotFoundException as ex -> "[ERROR] No file was found at " + ex.FileName

4
DeathSocketCLI/Validation.fs

@ -48,8 +48,8 @@
columns = numColumns } columns = numColumns }
let buildDefaultSpec imgPath newPath = let buildDefaultSpec imgPath newPath =
let stream = new FileStream (imgPath, FileMode.Open) use stream = new FileStream (imgPath, FileMode.Open)
let image = Image.FromStream (stream, false, false) use image = Image.FromStream (stream, false, false)
let spec = let spec =
{ originalPath = imgPath { originalPath = imgPath
savePath = newPath savePath = newPath

44
TestCentre/LibraryTests.fs

@ -21,9 +21,12 @@
open System.Reflection open System.Reflection
open System.IO open System.IO
let rand = Random ()
(* These are duplicates from ConsoleTests.fs (both of them). See point (* These are duplicates from ConsoleTests.fs (both of them). See point
about helpers. Tests for checking these locations can be found in about helpers. Tests for checking these locations can be found in
ConsoleTests.fs.*) ConsoleTests.fs. *)
let loadLocation = __SOURCE_DIRECTORY__ + "/LoadingTestArea" let loadLocation = __SOURCE_DIRECTORY__ + "/LoadingTestArea"
let saveLocation = __SOURCE_DIRECTORY__ + "/SavingTestArea" let saveLocation = __SOURCE_DIRECTORY__ + "/SavingTestArea"
@ -35,14 +38,18 @@
|> Seq.toArray |> Seq.toArray
let randomBrush () = let randomBrush () =
let item = allColours.[Random().Next(allColours.Length)] let item = allColours.[rand.Next(allColours.Length)]
item.GetValue(null, null) item.GetValue(null, null)
(* Max. value is arbitrary (change for performance).
Min. value is to stop divide by zero exceptions.
Intended for horizontal and vertical line tests. *)
let newNum () = rand.Next(1, 1000)
let imagesInLoadingTestArea = let imagesInLoadingTestArea =
Directory.GetFileSystemEntries (loadLocation, "*.png") Directory.GetFileSystemEntries (loadLocation, "*.png")
let generateLoadPath () = let generateLoadPath () =
let rand = Random ()
let files = imagesInLoadingTestArea let files = imagesInLoadingTestArea
files.[rand.Next(files.Length)] files.[rand.Next(files.Length)]
@ -51,7 +58,7 @@
saveLocation + "/" + fileName saveLocation + "/" + fileName
(* To "manually" clear out the SavingTestArea folder, use this function (* To "manually" clear out the SavingTestArea folder, use this function
in script.fsx. More information can be found there, also.*) in script.fsx. More information can be found there, also. *)
let resetSavingTestArea () = let resetSavingTestArea () =
let files = Directory.GetFileSystemEntries(saveLocation, "*.png") let files = Directory.GetFileSystemEntries(saveLocation, "*.png")
match files.Length with match files.Length with
@ -68,13 +75,14 @@
open DeathSocket.GridPainter open DeathSocket.GridPainter
open TestingHelpers open TestingHelpers
open System.IO open System.IO
open System
[<Property>] [<Property>]
let ``Can apply grid to image and save it`` () = let ``Can apply grid to image and save it`` () =
(* You should end up with one image left over in SavingTestArea. (* You should end up with one image left over in SavingTestArea.
Comment out the "reset" function to see all the images produced, Comment out the "reset" function to see all the images produced,
by this test. This will mean you will need to manually delete the by this test. This will mean you will need to manually delete the
images yourself if you do.*) images yourself if you do. *)
resetSavingTestArea () resetSavingTestArea ()
let oPath = generateLoadPath () let oPath = generateLoadPath ()
let sPath = generateSavePath oPath let sPath = generateSavePath oPath
@ -85,14 +93,26 @@
penWidth = float32 1 penWidth = float32 1
rows = 10 rows = 10
columns = 10 } columns = 10 }
applyGrid spec applyGridAsync spec
|> Async.RunSynchronously |> Async.RunSynchronously
(File.Exists sPath) = true (File.Exists sPath) = true
[<Property>]
let ``Can return a collection of points which represent a grids horizontal lines`` () =
let result = determineHorizontalLines (newNum()) (newNum()) (newNum())
result.Length > 0
[<Property>]
let ``Can return a collection of points which represent a grids vertical lines`` () =
let result = determineVerticalLines (newNum()) (newNum()) (newNum())
result.Length > 0
module UnitTests = module UnitTests =
open TestingHelpers open TestingHelpers
open Xunit open Xunit
open DeathSocket
open System
(* This test is a precaution (a test for the tests if you will...). (* This test is a precaution (a test for the tests if you will...).
It is here to make sure the property test has what it needs to run. It is here to make sure the property test has what it needs to run.
@ -103,4 +123,14 @@
let ``LoadingTestArea contains at least 100 test images`` () = let ``LoadingTestArea contains at least 100 test images`` () =
let length = imagesInLoadingTestArea.Length let length = imagesInLoadingTestArea.Length
let imagesAreThere = if length < 100 then false else true let imagesAreThere = if length < 100 then false else true
Assert.True imagesAreThere Assert.True imagesAreThere
[<Fact>]
let ``Divide By Zero Exception is thrown when 0 rows is used when determining horizontal lines`` () =
let result () = GridPainter.determineHorizontalLines 100 100 0
Assert.Throws<DivideByZeroException>(fun () -> result () |> ignore)
[<Fact>]
let ``Divide By Zero Exception is thrown when 0 columns is used when determining vertical lines`` () =
let result () = GridPainter.determineVerticalLines 100 100 0
Assert.Throws<DivideByZeroException>(fun () -> result () |> ignore)

2
TestCentre/Script.fsx

@ -44,7 +44,7 @@ resetLoadingTestArea ()
(* Populating LoadingTestArea Folder Scripts (* Populating LoadingTestArea Folder Scripts
=============================================================================== ===============================================================================
The following scripts are to help you populate a test folder of images. The following scripts are to help you populate a test folder with test images.
You can then use these images in LibraryTests.fs -- Property Tests. You can then use these images in LibraryTests.fs -- Property Tests.
The tests consists of loading images from LoadingTestArea, transforming them The tests consists of loading images from LoadingTestArea, transforming them
and saving them in SavingTestArea. *) and saving them in SavingTestArea. *)

Loading…
Cancel
Save