diff --git a/DeathSocket/Domain.fs b/DeathSocket/Domain.fs index 04be768..34cc817 100644 --- a/DeathSocket/Domain.fs +++ b/DeathSocket/Domain.fs @@ -1,23 +1,24 @@ namespace DeathSocket + /// The domain types used by Death Socket. [] module Domain = open System.Drawing - open System.Drawing.Imaging + /// + /// The specification used by Death Socket when adding a grid to an image. + /// type ImageSpec = - { originalPath: string; - savePath: string; - colour: Brush; - penWidth: float32 - rows: int; - columns: int } - - type StreamSpec = - { imagePath: string; - format: ImageFormat; - colour: Brush; - penWidth: float32 - rows: int; + { /// 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. + colour: Brush + /// 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 } \ No newline at end of file diff --git a/DeathSocket/GridPainter.fs b/DeathSocket/GridPainter.fs index 088c846..fbb3bba 100644 --- a/DeathSocket/GridPainter.fs +++ b/DeathSocket/GridPainter.fs @@ -2,16 +2,61 @@ namespace DeathSocket 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 = open Validation open ImageServices - let applyGrid spec = + /// + /// 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. + /// + /// + /// The specification used to generate the new gridded image + /// + /// + /// If the file the grid is being applied to cannot be found, + /// a FileNotFoundException will be thrown. + /// + /// + let applyGridAsync spec = async { try - validateFilePath |> ignore + validateFilePath spec.originalPath |> ignore + validatFileType spec.savePath |> ignore drawGrid spec |> ignore with - | :? FileNotFoundException as ex -> printfn "File could not be found at %s" ex.Message - } \ No newline at end of file + | :? FileNotFoundException as ex -> + printfn "File could not be found at %s" ex.Message + } + + /// + /// 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. + /// + /// The width of the image. + /// The height of the image. + /// The number of rows the grid should have. + /// You will probably only need these when dealing with GUI's. + let determineHorizontalLines width height rows = + createHorizontalLines width height rows + + /// + /// 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. + /// + /// The width of the image. + /// The height of the image. + /// The number of columns the grid should have. + /// You will probably only need these when dealing with GUI's. + let determineVerticalLines width height columns = + createVerticalLines width height columns \ No newline at end of file diff --git a/DeathSocket/ImageServices.fs b/DeathSocket/ImageServices.fs index ca5830b..b6219ed 100644 --- a/DeathSocket/ImageServices.fs +++ b/DeathSocket/ImageServices.fs @@ -17,15 +17,17 @@ Point ((interval * point), height)|]|] let drawGrid spec = - let img = Bitmap.FromFile spec.originalPath - let graphics = Graphics.FromImage img - let pen = new Pen (spec.colour, width = spec.penWidth) + // The temp. file is used as a way to convert images with indexed pixels. + 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 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 = - createHorizontalLines (img.Size.Width) (img.Size.Height) (spec.columns) - let verticalLines = createVerticalLines (img.Size.Width) (img.Size.Height) (spec.columns) + 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) - img.Save (spec.savePath, ImageFormat.Png) - img.Dispose () - graphics.Dispose () - pen.Dispose () \ No newline at end of file + clone.Save (spec.savePath) \ No newline at end of file diff --git a/DeathSocket/Validation.fs b/DeathSocket/Validation.fs index 1931f22..a192a9b 100644 --- a/DeathSocket/Validation.fs +++ b/DeathSocket/Validation.fs @@ -1,9 +1,20 @@ module internal Validation -open System.IO + open System.IO let validateFilePath path = match File.Exists path with | true -> () | 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." \ No newline at end of file diff --git a/DeathSocketCLI/Commands.fs b/DeathSocketCLI/Commands.fs index aad33ee..53fbc9c 100644 --- a/DeathSocketCLI/Commands.fs +++ b/DeathSocketCLI/Commands.fs @@ -38,8 +38,8 @@ try printfn "[INFO.] Adding default grid to image..." buildDefaultSpec imgPath newPath - |> applyGrid - |> Async.RunSynchronously + |> applyGridAsync + |> Async.Start showEndOfCommandMessage with | :? FileNotFoundException as ex -> "[ERROR] No file was found at " + ex.FileName @@ -57,8 +57,8 @@ try printfn "[INFO.] Adding grid to image..." buildSpec imgPath numRows numColumns pWidth colour newPath - |> applyGrid - |> Async.RunSynchronously + |> applyGridAsync + |> Async.Start showEndOfCommandMessage with | :? FileNotFoundException as ex -> "[ERROR] No file was found at " + ex.FileName diff --git a/DeathSocketCLI/Validation.fs b/DeathSocketCLI/Validation.fs index c798351..1225133 100644 --- a/DeathSocketCLI/Validation.fs +++ b/DeathSocketCLI/Validation.fs @@ -48,8 +48,8 @@ columns = numColumns } let buildDefaultSpec imgPath newPath = - let stream = new FileStream (imgPath, FileMode.Open) - let image = Image.FromStream (stream, false, false) + use stream = new FileStream (imgPath, FileMode.Open) + use image = Image.FromStream (stream, false, false) let spec = { originalPath = imgPath savePath = newPath diff --git a/TestCentre/LibraryTests.fs b/TestCentre/LibraryTests.fs index deaf25a..4d15747 100644 --- a/TestCentre/LibraryTests.fs +++ b/TestCentre/LibraryTests.fs @@ -21,9 +21,12 @@ open System.Reflection open System.IO + let rand = Random () + + (* These are duplicates from ConsoleTests.fs (both of them). See point about helpers. Tests for checking these locations can be found in - ConsoleTests.fs.*) + ConsoleTests.fs. *) let loadLocation = __SOURCE_DIRECTORY__ + "/LoadingTestArea" let saveLocation = __SOURCE_DIRECTORY__ + "/SavingTestArea" @@ -35,14 +38,18 @@ |> Seq.toArray let randomBrush () = - let item = allColours.[Random().Next(allColours.Length)] + let item = allColours.[rand.Next(allColours.Length)] 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 = Directory.GetFileSystemEntries (loadLocation, "*.png") let generateLoadPath () = - let rand = Random () let files = imagesInLoadingTestArea files.[rand.Next(files.Length)] @@ -51,7 +58,7 @@ saveLocation + "/" + fileName (* 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 files = Directory.GetFileSystemEntries(saveLocation, "*.png") match files.Length with @@ -68,13 +75,14 @@ open DeathSocket.GridPainter open TestingHelpers open System.IO + open System [] let ``Can apply grid to image and save it`` () = (* You should end up with one image left over in SavingTestArea. Comment out the "reset" function to see all the images produced, by this test. This will mean you will need to manually delete the - images yourself if you do.*) + images yourself if you do. *) resetSavingTestArea () let oPath = generateLoadPath () let sPath = generateSavePath oPath @@ -85,14 +93,26 @@ penWidth = float32 1 rows = 10 columns = 10 } - applyGrid spec + applyGridAsync spec |> Async.RunSynchronously (File.Exists sPath) = true + [] + let ``Can return a collection of points which represent a grids horizontal lines`` () = + let result = determineHorizontalLines (newNum()) (newNum()) (newNum()) + result.Length > 0 + + [] + let ``Can return a collection of points which represent a grids vertical lines`` () = + let result = determineVerticalLines (newNum()) (newNum()) (newNum()) + result.Length > 0 + module UnitTests = open TestingHelpers open Xunit + open DeathSocket + open System (* 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. @@ -103,4 +123,14 @@ let ``LoadingTestArea contains at least 100 test images`` () = let length = imagesInLoadingTestArea.Length let imagesAreThere = if length < 100 then false else true - Assert.True imagesAreThere \ No newline at end of file + Assert.True imagesAreThere + + [] + 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(fun () -> result () |> ignore) + + [] + 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(fun () -> result () |> ignore) \ No newline at end of file diff --git a/TestCentre/Script.fsx b/TestCentre/Script.fsx index 7c24da5..e053c75 100644 --- a/TestCentre/Script.fsx +++ b/TestCentre/Script.fsx @@ -44,7 +44,7 @@ resetLoadingTestArea () (* 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. The tests consists of loading images from LoadingTestArea, transforming them and saving them in SavingTestArea. *)