Browse Source

Merge pull request #8 from CraigOates/0.7

0.7.1
master
Craig Oates 5 years ago committed by GitHub
parent
commit
ab0d9f1427
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      DeathSocket/ColourServices.fs
  2. 10
      DeathSocket/DeathSocket.fsproj
  3. 99
      DeathSocket/Domain.fs
  4. 256
      DeathSocket/GridPainter.fs
  5. 70
      DeathSocket/ImagePrep.fs
  6. 135
      DeathSocket/ImageServices.fs
  7. 27
      DeathSocket/ScratchPad.fsx
  8. 20
      DeathSocket/Validation.fs
  9. 31
      DeathSocket/ValidationServices.fs
  10. 4
      TestCentre/AssemblyInfo.fs
  11. 229
      TestCentre/LibraryTests.fs
  12. BIN
      TestCentre/LoadingTestArea/RequiredInfo/ImageTest1.png
  13. BIN
      TestCentre/LoadingTestArea/RequiredInfo/ImageTest2.png
  14. BIN
      TestCentre/LoadingTestArea/RequiredInfo/ImageTest3.png
  15. BIN
      TestCentre/LoadingTestArea/RequiredInfo/Skia-599x336.png
  16. BIN
      TestCentre/LoadingTestArea/RequiredInfo/SystemDrawing-338x307.png

2
DeathSocket/ColourServices.fs

@ -2,8 +2,6 @@
open System.Drawing open System.Drawing
open DeathSocket.Domain open DeathSocket.Domain
open System
open SkiaSharp
let makeBrushFromRGBASpec (spec: RGBASpec) = let makeBrushFromRGBASpec (spec: RGBASpec) =
let a = int spec.alpha let a = int spec.alpha

10
DeathSocket/DeathSocket.fsproj

@ -4,7 +4,7 @@
<TargetFramework>netstandard2.0</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild> <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance> <PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<Version>0.6-alpha</Version> <Version>0.7.1-alpha</Version>
<Authors>Craig Oates</Authors> <Authors>Craig Oates</Authors>
<Product>Death Socket</Product> <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> <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,15 +15,17 @@
<RepositoryUrl>https://github.com/CraigOates/Death-Socket/tree/master</RepositoryUrl> <RepositoryUrl>https://github.com/CraigOates/Death-Socket/tree/master</RepositoryUrl>
<RepositoryType>Git</RepositoryType> <RepositoryType>Git</RepositoryType>
<PackageTags>deathsocket craig oates image overlay f#</PackageTags> <PackageTags>deathsocket craig oates image overlay f#</PackageTags>
<PackageReleaseNotes>This release deprecated the "applyGrid" functions and refactored them into one single function.</PackageReleaseNotes> <PackageReleaseNotes>This release fixes the pen thickness scaling bugs in 0.7.</PackageReleaseNotes>
<AssemblyVersion>0.6.0.0</AssemblyVersion> <AssemblyVersion>0.7.1.0</AssemblyVersion>
<PackageIconUrl>https://github.com/CraigOates/Death-Socket/blob/master/.github/Images/death-socket-logo.png</PackageIconUrl> <PackageIconUrl>https://github.com/CraigOates/Death-Socket/blob/master/.github/Images/death-socket-logo.png</PackageIconUrl>
<FileVersion>0.7.1.0</FileVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Domain.fs" /> <Compile Include="Domain.fs" />
<Compile Include="Validation.fs" /> <Compile Include="ValidationServices.fs" />
<Compile Include="ColourServices.fs" /> <Compile Include="ColourServices.fs" />
<Compile Include="ImagePrep.fs" />
<Compile Include="ImageServices.fs" /> <Compile Include="ImageServices.fs" />
<Compile Include="GridPainter.fs" /> <Compile Include="GridPainter.fs" />
<None Include="ScratchPad.fsx" /> <None Include="ScratchPad.fsx" />

99
DeathSocket/Domain.fs

@ -6,10 +6,11 @@
open System.Drawing open System.Drawing
open SkiaSharp open SkiaSharp
open System.Threading
/// The specification used to note the orignial file's location and the /// This specification is used to note the orignial file's location and
/// changes the user would like to make to it. (including the save /// 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 /// location of the modified version). Use this spec. if you are using
/// System.Drawing. /// System.Drawing.
type BrushSpec = type BrushSpec =
{ /// The original path of the image which the grid is being added to. { /// The original path of the image which the grid is being added to.
@ -26,11 +27,11 @@
///The number of columns the grid will have. ///The number of columns the grid will have.
columns: int } columns: int }
/// The specification used to note the orignial file's location and the /// This specification is used to note the orignial file's location and
/// changes the user would like to make to it (including the save /// the changes the user would like to make to it (including the save
/// location of the modified version). This specification includes /// location of the modified version). This specification includes
/// individual RGBA values to describe the grid's colour. Use this spec. /// individual RGBA values to describe the grid's colour. Use this
/// if you are using System.Drawing. /// spec. if you are using System.Drawing.
type RGBASpec = type RGBASpec =
{ /// The original path of the image which the grid is being added to. { /// The original path of the image which the grid is being added to.
originalPath: string originalPath: string
@ -52,10 +53,10 @@
///The number of columns the grid will have. ///The number of columns the grid will have.
columns: int } columns: int }
/// The specification used to note the orignial file's location and the /// This specification is used to note the orignial file's location and
/// changes the user would like to make to it (including the save /// 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 /// location of the modified version). Use this spec. if you are using
/// the Skia-Sharp library. /// the SkiaSharp library.
type SkiaSpec = type SkiaSpec =
{ /// The original path of the image which the grid is being added to. { /// The original path of the image which the grid is being added to.
originalPath: string originalPath: string
@ -70,11 +71,53 @@
///The number of columns the grid will have. ///The number of columns the grid will have.
columns: int } columns: int }
/// The specification used to note the orignial file's location and the /// This specification is used to create a gridded image as an SKData
/// changes the user would like to make to it (including the save /// buffer. This spec. allows you to use one of the pre-formed
/// SKColors. This makes it quicker and easier to develop your code
/// when compared to SkiaRGBStream. That requires setting individual
/// RGB values. You this spec. if you are using the SkiaSharp library.
type SkiaBufferSpec =
{ /// The location of the image the grid will be applied to
filePath: 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 }
/// This specification is used to create a gridded image as a SKData
/// buffer. This spec. allows you to specify the colour of the grid
/// using individual RGB values. This gives you greater control of your
/// colour choice than a SkiaStreamSpec, which requires a pre-formed
/// SKColor value. you this spec. if you are using the SkiaSharp
/// library.
type SkiaRGBBufferSpec =
{ /// The location of the image the grid will be applied to
filePath: 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 }
/// This specification is 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 /// location of the modified version). This specification includes
/// individual RGB values to describe the grid's colour. Use this spec. /// individual RGB values to describe the grid's colour. Use this spec.
/// if you are using the Skia-Sharp library. /// if you are using the SkiaSharp library.
type SkiaRGBSpec = type SkiaRGBSpec =
{ /// The original path of the image which the grid is being added to. { /// The original path of the image which the grid is being added to.
originalPath: string originalPath: string
@ -96,10 +139,36 @@
///The number of columns the grid will have. ///The number of columns the grid will have.
columns: int } columns: int }
/// Discriminated Union representing the various specification types /// A Discriminated Union representing the various specification types
/// Death Socket can use to apply a grid to an image. /// Death Socket can use to apply a grid to an image.
type ImageSpec = type ImageSpec =
/// Spec. which uses System.Drawing and its built-in (colour) Brush.
| Brush of BrushSpec | Brush of BrushSpec
/// Spec. which uses System.Drawing and individual RGBA values.
| RGBA of RGBASpec | RGBA of RGBASpec
/// Spec. which uses SkiaSharp and its built-in SKColors.
| Skia of SkiaSpec | Skia of SkiaSpec
| SkiaRGB of SkiaRGBSpec /// Spec. which uses SkiaSharp and individual RGB values.
| SkiaRGB of SkiaRGBSpec
/// Spec. which uses SkiaSharp and its built-in SKColors.
| SkiaBuffer of SkiaBufferSpec
/// Spec. which uses SkiaSharp and individual RGB values.
| SkiaRGBBuffer of SkiaRGBBufferSpec
/// A Discriminated Union denoting a type of image. The type refers
/// to the graphics library used to read the image file.
/// The graphics library determines how the image is read and
/// manipulated in memory and the functions you can perform on it.
/// When creating an ImageType, pass in the file path of the image
/// as a string. If you are on Windows or using Mono, SystemDrawing is
/// the recommended choice. If you using Xamarin, SkiaSharp is the
/// recommended choice.
type ImageType =
/// Denotes an image created using SkiaSharp
| SkiaSharp of string
/// Denotes an image created using System.Drawing
| SystemDrawing of string
type internal longestDimension =
| Width
| Height

256
DeathSocket/GridPainter.fs

@ -13,24 +13,23 @@ namespace DeathSocket
/// functions. /// functions.
module GridPainter = module GridPainter =
open Validation open ValidationServices
open ImagePrep
open ImageServices open ImageServices
open System open SkiaSharp
/// <summary> /// <summary>
/// Uses the information included in spec to create a gridded image. /// Uses the information included in spec to create a gridded image.
/// It then asynchronously saves it. Uses .jpg or .png formats only. /// It then asynchronously saves it. Uses .jpg or .png formats only.
/// Please note: Any buffer-based spec's (E.G. SkiaBufferSpec) will be
/// ignored by this function.
/// </summary> /// </summary>
/// <param name="spec"> /// <param name="spec">
/// The specification used to generate the new gridded image. The /// The specification used to generate the new gridded image. The
/// ImageSpec is a discriminated union, consisting of a Brush, RGBA, /// ImageSpec is a discriminated union, consisting of a Brush, RGBA,
/// Skia or SkiaRGB spec. /// Skia or SkiaRGB spec.
/// </param> /// </param>
/// <exeption cref="System.IO.FileNotFoundException"> /// <remarks>
/// 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, /// Make sure the image, which is having the overlay added to it,
/// is not in use or needed by another program/process. /// is not in use or needed by another program/process.
/// This is because it is locked whilst in this function. /// This is because it is locked whilst in this function.
@ -51,13 +50,70 @@ namespace DeathSocket
| SkiaRGB sR -> | SkiaRGB sR ->
validateIO sR.originalPath sR.savePath |> ignore validateIO sR.originalPath sR.savePath |> ignore
drawSkiaRGBGrid sR drawSkiaRGBGrid sR
| _ -> printfn "[DEATH SOCKET INFO] Inappropriate ImageSpec used here. Please use none buffer-based spec's when using this function."
with with
| :? FileNotFoundException as ex -> | :? FileNotFoundException as ex ->
printfn "File could not be found at %s" ex.Message printfn "File could not be found at %s" ex.Message
} }
// System.Drawing Functions // NOT TESTED.
// ======================================================================== /// <summary>
/// Determines the current scale an image is viewed at (E.G. scaled
/// preview in image viewer). The (pen) line thickness is then updated
/// to match this preview scale and can be used when drawing a grid
/// line on the scaled preview of the image.
/// </summary>
/// <param name="previewDimension">
/// The width or height of the image when previewed (I.E. in a GUI).
/// </param>
/// <param name="actualDimension">
/// The width or height of the actual image.
/// </param>
/// <param name="lineThickness">
/// The thickness of the pen used to draw the grid line.
/// </param>
/// <remarks>
/// You should find you only need this function when dealing with
/// previewing an image in a GUI. Another thing to note is the
/// SkiaSharp based functions already scale the grid lines for you. So,
/// you should not need to use this function when using them.
/// </remarks>
let scaleLineThickness (previewDimensions: int * int) (actualDimensions: int * int) (lineThickness: double) =
validateDimensions previewDimensions |> ignore
validateDimensions actualDimensions |> ignore
validateLineThickness |> ignore
adjustLineThickness previewDimensions actualDimensions lineThickness
/// <summary>
/// Reads an (jpg or png) image and return its width and height as a
/// tuple, (width * hight).
/// </summary>
/// <param name="imageType">
/// The name of the graphics library used to read and determine the
/// images dimensions.
/// </param>
/// <remarks>
/// The image type is determined by the graphics library used. It is
/// called "ImageType" and not "GraphicsLibUsed" because the image/file
/// information is the thing this function cares about most of all. How
/// it is read and what library it uses it secondary.
///</remarks>
let determineImageDimensions (imgType: ImageType) =
try
match imgType with
| SkiaSharp s ->
validateFilePath s |> ignore
determineSkiaDimensions s
| SystemDrawing d ->
validateFilePath d |> ignore
determineSystemDrawingDimensions d
with
| :? FileNotFoundException as ex ->
printfn "%s" ex.Message
reraise ()
(* System.Drawing Functions
==================================================================== *)
/// <summary> /// <summary>
/// Determines the (Pen) points needed to draw the appropriate number /// Determines the (Pen) points needed to draw the appropriate number
@ -68,7 +124,9 @@ namespace DeathSocket
/// <param name="width">The width of the image.</param> /// <param name="width">The width of the image.</param>
/// <param name="height">The height 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> /// <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> /// <remarks>
/// You will probably only need these when dealing with GUI's.
/// </remarks>
let determineHorizontalLines (width: int) (height: int) (rows: int) = let determineHorizontalLines (width: int) (height: int) (rows: int) =
createHorizontalLines width height rows createHorizontalLines width height rows
@ -80,68 +138,14 @@ namespace DeathSocket
/// </summary> /// </summary>
/// <param name="width">The width of the image.</param> /// <param name="width">The width of the image.</param>
/// <param name="height">The height 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> /// <param name="columns">
/// <remarks>You will probably only need these when dealing with GUI's.</remarks> /// The number of columns the grid should have.
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. 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
/// </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>
[<Obsolete("Method is deprecated, use applyGridToImage instead.")>]
let applyBrushSpecGridAsync (spec: BrushSpec) =
async {
try
validateFilePath spec.originalPath |> ignore
validateSaveFileType spec.savePath |> ignore
drawBrushSpecGrid spec |> ignore
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 .Net/Mono).
/// </summary>
/// <param name="spec">
/// The specification used to generate the gridded image.
/// </param> /// </param>
/// <exeption cref="System.IO.FileNotFoundException"> /// <remarks>
/// If the file the grid is being applied to cannot be found, /// You will probably only need these when dealing with GUI's.
/// 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> /// </remarks>
[<Obsolete("Method is deprecated, use applyGridToImage instead.")>] let determineVerticalLines (width: int) (height: int) (columns: int) =
let applyRGBAGridAsync (spec: RGBASpec) = createVerticalLines width height columns
async {
try
validateFilePath spec.originalPath |> ignore
validateSaveFileType spec.savePath |> ignore
drawRGBAGrid spec
with
| :? FileNotFoundException as ex ->
printfn "File could not be found at %s" ex.Message
}
/// <summary> /// <summary>
/// Creates a Sytsem.Drawing SolidBrush from the individual RGBA values. /// Creates a Sytsem.Drawing SolidBrush from the individual RGBA values.
@ -163,8 +167,8 @@ namespace DeathSocket
/// Use this function when targeting .Net/Mono). /// Use this function when targeting .Net/Mono).
/// </summary> /// </summary>
/// <param name="spec"> /// <param name="spec">
///The specification which the brush is made from. /// The specification which the brush is made from.
///</param> /// </param>
/// <remarks> /// <remarks>
/// Death Socket uses System.Drawing and not System.Media for colours /// Death Socket uses System.Drawing and not System.Media for colours
/// and brushes. /// and brushes.
@ -172,8 +176,44 @@ namespace DeathSocket
let makeSolidBrushFromRGBASpec (spec: RGBASpec) = let makeSolidBrushFromRGBASpec (spec: RGBASpec) =
makeBrushFromRGBASpec spec makeBrushFromRGBASpec spec
// SkiaSharp Functions (* SkiaSharp Functions
// ======================================================================== ==================================================================== *)
/// <summary>
/// Uses the information included in spec to create a SKData buffer.
/// The buffer will contain a gridded image which you can then use in
/// any way you see fit. Accepted image formats are limited to .jpg
/// and .png. Please note: Any non buffer-based spec's (E.G. SkiaSpec)
/// will be ignored by this function.
/// </summary>
/// <param name="spec">
/// The specification used to generate the new SKData buffer. The
/// ImageSpec is a discriminated union, consisting of a SkiaBuffer and
/// a SkiaRGBBuffer spec.
/// </param>
/// <remarks>
/// Make sure the image, which is used to create the SKData buffer,
/// is not in use or needed by another program/process.
/// This is because it is locked whilst in this function.
/// </remarks>
let createSKDataAsync (spec: ImageSpec) =
async {
try
match spec with
| SkiaBuffer s ->
validateFilePath s.filePath |> ignore
return createSkiaBuffer s
| SkiaRGBBuffer sR ->
validateFilePath sR.filePath |> ignore
return createSkiaRGBBuffer sR
| _ ->
printfn "[DEATH SOCKET INFO] Inappropriate ImageSpec used here. Please use buffer-based spec's when using this function. Returning an empty SKData object."
return SKData.Empty
with
| :? FileNotFoundException as ex ->
printfn "%s" ex.Message |> ignore
return SKData.Empty
}
/// <summary> /// <summary>
/// Determines the (SKPoints) points needed to draw the appropriate /// Determines the (SKPoints) points needed to draw the appropriate
@ -184,8 +224,10 @@ namespace DeathSocket
/// <param name="width">The width of the image.</param> /// <param name="width">The width of the image.</param>
/// <param name="height">The height 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> /// <param name="rows">The number of rows the grid should have.</param>
/// <remarks>This function is part of the SkiaSharp functions provided /// <remarks>
/// by Death Socket.</remarks> /// This function is part of the SkiaSharp functions provided
/// by Death Socket.
/// </remarks>
let determineSKHorizontalLines (width: int) (height: int) (rows: int) = let determineSKHorizontalLines (width: int) (height: int) (rows: int) =
createSKHorizontalLines width height rows createSKHorizontalLines width height rows
@ -199,61 +241,9 @@ namespace DeathSocket
/// <param name="height">The height 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 name="columns">The number of columns the grid should have.
/// </param> /// </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>
[<Obsolete("Method is deprecated, use applyGridToImage instead.")>]
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> /// <remarks>
/// Make sure the image, which is having the overlay added to it, /// This function is part of the SkiaSharp functions provided by Death
/// is not in use or needed by another program/process. /// Socket.
/// This is because it is locked whilst in this function.
/// </remarks> /// </remarks>
[<Obsolete("Method is deprecated, use applyGridToImage instead.")>] let determineSKVerticalLines (width: int) (height: int) (columns: int) =
let applySkiaRGBGridAsync (spec: SkiaRGBSpec) = createSKVerticalLines width height columns
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
}

70
DeathSocket/ImagePrep.fs

@ -0,0 +1,70 @@
module internal ImagePrep
open System.IO
open DeathSocket
open SkiaSharp
open System.Drawing
let determineLongestDimension pDims aDims =
let width = (fst pDims) - (fst aDims)
let height = (snd pDims) - (snd aDims)
match width > height with
| true -> Width
| false -> Height
let determineImageScale pDimension aDimension =
(double aDimension) / (double pDimension)
let determineLineScale (lineWidth: double) (scale: double) =
lineWidth / scale
let adjustLineThickness pDimensions aDimensions lineWidth =
match (determineLongestDimension pDimensions aDimensions) with
| Width ->
let thickness =
determineImageScale (fst pDimensions) (fst aDimensions)
|> determineLineScale lineWidth
thickness
| Height ->
let thickness =
determineImageScale (snd pDimensions) (snd aDimensions)
|> determineLineScale lineWidth
thickness
(* 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 determineSkiaDimensions filePath =
use fileStream = File.Open (filePath, FileMode.Open)
use skStream = new SKManagedStream (fileStream)
use bitmap = SKBitmap.Decode (skStream)
(bitmap.Width, bitmap.Height)
(* System.Drawing Functions
======================================================================== *)
let createHorizontalLines width height rows =
let interval = height / rows
[| for point in 1 .. (rows - 1) ->
[|Point (0, (interval * point))
Point (width, (interval * point) )|]|]
let createVerticalLines width height columns =
let interval = width / columns
[| for point in 1 .. (columns - 1) ->
[| Point ((interval * point), 0)
Point ((interval * point), height)|]|]
let determineSystemDrawingDimensions filePath =
use bitmap = Bitmap.FromFile filePath
(bitmap.Width, bitmap.Height)

135
DeathSocket/ImageServices.fs

@ -5,23 +5,25 @@
open System.Drawing.Imaging open System.Drawing.Imaging
open DeathSocket open DeathSocket
open ColourServices open ColourServices
open ImagePrep
open SkiaSharp open SkiaSharp
// SkiaSharp Functions (* Note on the Use of Repeated Code
// ======================================================================== ===========================================================================
In this file, you will find code which seems duplicated. The areas in
let createSKHorizontalLines width height rows = question are mostly the graphics/drawing parts of the file. Before you
let interval = float32 (height / rows) consider refactoring this code, please note the memory footprint of this
[|for point in 1 .. (rows - 1) -> library. By using "use", the objects created are diposed of properly. This,
[| SKPoint ((float32 0), (interval * (float32 point))) also, means it is difficult to pass/return them from one function to the
SKPoint ((float32 width), (interval * (float32 point)))|]|] next. Therefore, the decision made was to accept the duplicated code in
exchange for a smaller memory footprint. Several (large) undisposed images
let createSKVerticalLines width height columns = lurking in an end users RAM can grind their computer to a halt. On top of
let interval = float32 (width / columns) that, they have no means to make alterations to the code. *)
[| for point in 1 .. (columns - 1) ->
[| SKPoint ((interval * (float32 point)), (float32 0)) (* SkiaSharp Functions
SKPoint ((interval * (float32 point)), (float32 height))|]|] ======================================================================== *)
// Does not work when using SkiaSharp NuGet v. 1.68
let drawSkiaGrid (spec: SkiaSpec) = let drawSkiaGrid (spec: SkiaSpec) =
use fileStream = File.Open (spec.originalPath, FileMode.Open) use fileStream = File.Open (spec.originalPath, FileMode.Open)
use skStream = new SKManagedStream (fileStream) use skStream = new SKManagedStream (fileStream)
@ -60,6 +62,7 @@
use saveStream = File.OpenWrite (spec.savePath) use saveStream = File.OpenWrite (spec.savePath)
data.SaveTo (saveStream) data.SaveTo (saveStream)
// Does not work when using SkiaSharp NuGet v. 1.68
let drawSkiaRGBGrid spec = let drawSkiaRGBGrid spec =
use fileStream = File.Open (spec.originalPath, FileMode.Open) use fileStream = File.Open (spec.originalPath, FileMode.Open)
use skStream = new SKManagedStream (fileStream) use skStream = new SKManagedStream (fileStream)
@ -99,31 +102,100 @@
use saveStream = File.OpenWrite (spec.savePath) use saveStream = File.OpenWrite (spec.savePath)
data.SaveTo (saveStream) data.SaveTo (saveStream)
// System.Drawing Functions // Does not work when using SkiaSharp NuGet v. 1.68
// ======================================================================== let createSkiaBuffer (spec: SkiaBufferSpec) =
use fileStream = File.Open (spec.filePath, 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 ()
let data =
match Path.GetExtension (spec.filePath) with
| ".jpg" | ".JPG" -> snapshot.Encode (SKEncodedImageFormat.Jpeg, 100)
| ".png"| ".PNG" -> snapshot.Encode (SKEncodedImageFormat.Png, 100)
| _ -> invalidArg "filePath" "The file type must be a .jpg or .png file."
// (data) Buffer returned -- does not dispose automatically.
data
// Does not work when using SkiaSharp NuGet v. 1.68
let createSkiaRGBBuffer (spec: SkiaRGBBufferSpec) =
use fileStream = File.Open (spec.filePath, 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)
let createHorizontalLines width height rows = use stroke = new SKPaint ()
let interval = height / rows stroke.Style <- SKPaintStyle.Stroke
[| for point in 1 .. (rows - 1) -> stroke.StrokeWidth <- spec.penWidth
[|Point (0, (interval * point)) stroke.Color <-
Point (width, (interval * point) )|]|] 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 ()
let data =
match Path.GetExtension (spec.filePath) with
| ".jpg" | ".JPG" -> snapshot.Encode (SKEncodedImageFormat.Jpeg, 100)
| ".png"| ".PNG" -> snapshot.Encode (SKEncodedImageFormat.Png, 100)
| _ -> invalidArg "filePath" "The file type must be a .jpg or .png file."
// (data) Buffer returned -- does not dispose automatically.
data
let createVerticalLines width height columns = (* System.Drawing Functions
let interval = width / columns ======================================================================== *)
[| for point in 1 .. (columns - 1) ->
[| 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 The temp. file is used in the functions below are there to convert images
with indexed pixels. Instead of listing them all, just assume any function with indexed pixels. Instead of listing them all (future additions), just
with a "*Spec" type as a parameter will use this "temp" file. *) assume any function with a "*Spec" type as a parameter will use this "temp"
file. *)
let drawBrushSpecGrid (spec: BrushSpec) = let drawBrushSpecGrid (spec: BrushSpec) =
use original = Bitmap.FromFile spec.originalPath use original = Bitmap.FromFile spec.originalPath
use temp = new Bitmap(original) use temp = new Bitmap(original)
use clone = temp.Clone(new Rectangle(0, 0, temp.Width, temp.Height), PixelFormat.Format32bppArgb) use clone =
temp.Clone(new Rectangle(0, 0, temp.Width, temp.Height), PixelFormat.Format32bppArgb)
use graphics = Graphics.FromImage(clone) use graphics = Graphics.FromImage(clone)
use pen = new Pen (spec.colour, width = spec.penWidth) use pen = new Pen (spec.colour, 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))
@ -138,7 +210,8 @@
let drawRGBAGrid (spec: RGBASpec) = let drawRGBAGrid (spec: RGBASpec) =
use original = Bitmap.FromFile spec.originalPath use original = Bitmap.FromFile spec.originalPath
use temp = new Bitmap (original) use temp = new Bitmap (original)
use clone = temp.Clone (new Rectangle(0, 0, temp.Width, temp.Height), PixelFormat.Format32bppArgb) use clone =
temp.Clone (new Rectangle(0, 0, temp.Width, temp.Height), PixelFormat.Format32bppArgb)
use graphics = Graphics.FromImage(clone) use graphics = Graphics.FromImage(clone)
use pen = new Pen ((makeBrushFromRGBASpec spec), width = spec.penWidth) 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))

27
DeathSocket/ScratchPad.fsx

@ -1,26 +1,29 @@
// These two paths need adjusting to match your computer. // These paths need adjusting to match your computer.
#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/netstandard1.3/SkiaSharp.dll"
#r @"C:/Users/craig/.nuget/packages/skiasharp/1.60.3/lib/net45/SkiaSharp.dll" // Currently not working...
//#r @"C:/Users/craig/.nuget/packages/skiasharp/1.60.3/runtimes/win-x64/native/libSkiaSharp.dll"
#load "Domain.fs" #load "Domain.fs"
#load "Validation.fs" #load "ValidationServices.fs"
#load "ColourServices.fs" #load "ColourServices.fs"
#load "ImagePrep.fs"
#load "ImageServices.fs" #load "ImageServices.fs"
#load "GridPainter.fs" #load "GridPainter.fs"
open System.Drawing
open System open System
open DeathSocket open System.Drawing
open Validation
open ImageServices
open SkiaSharp open SkiaSharp
open ValidationServices
open ImagePrep
open ImageServices
open DeathSocket
(* Death Socket Scripts (* Death Socket Scripts
=============================================================================== ===============================================================================
The code in here can be use to create a gridded image without running the CLI. The code in here can be use to create a gridded image without running the CLI.
You can, also, run checks to see what Death Socket is doing when creating You can, also, run checks to see what Death Socket is doing when creating
a nerw image. *) a new image. *)
let desktop = Environment.GetFolderPath (Environment.SpecialFolder.Desktop) let desktop = Environment.GetFolderPath (Environment.SpecialFolder.Desktop)
@ -40,6 +43,14 @@ let skVerticalLines = createSKVerticalLines 120 450 22
(* You will need to provide the image and specify its load/save location. (* You will need to provide the image and specify its load/save location.
Death Socket assumes either JPEG or PNG files.*) Death Socket assumes either JPEG or PNG files.*)
let dimensions =
//SkiaSharp (desktop + "/test.jpg")
SystemDrawing (desktop + "/test.jpg")
|> GridPainter.determineImageDimensions
// Change the line thickness (the last parameter) to whatever you want.
let scaledPen = GridPainter.scaleLineThickness (100, 100) dimensions 8.0
// Brush Specification (uses System.Drawing) // Brush Specification (uses System.Drawing)
Brush ({ originalPath = desktop + "/test.jpg" Brush ({ originalPath = desktop + "/test.jpg"
savePath = desktop + "/grid.png" savePath = desktop + "/grid.png"

20
DeathSocket/Validation.fs

@ -1,20 +0,0 @@
module internal Validation
open System.IO
let validateFilePath path =
match File.Exists path with
| true -> ()
| false -> raise (new FileNotFoundException (path + " could not be found."))
let validateSaveFileType file =
match Path.GetExtension file with
| ".jpg" -> ()
| ".JPG" -> ()
| ".png" -> ()
| ".PNG" -> ()
| _ -> invalidArg "savePath" "The file type must be a .jpg or .png file."
let validateIO iPath oPath =
validateFilePath iPath
validateSaveFileType oPath

31
DeathSocket/ValidationServices.fs

@ -0,0 +1,31 @@
module internal ValidationServices
open System.IO
let validateFilePath path =
match File.Exists path with
| true -> ()
| false -> raise (new FileNotFoundException ("No file found at " + path))
let validateSaveFileType file =
match Path.GetExtension file with
| ".jpg" -> ()
| ".JPG" -> ()
| ".png" -> ()
| ".PNG" -> ()
| _ -> invalidArg "savePath" "The file type must be a .jpg or .png file."
let validateIO iPath oPath =
validateFilePath iPath
validateSaveFileType oPath
let validateDimensions dimensions =
match dimensions with
| (0, _) -> invalidArg "Width" "Width must be greater than 0."
| (_, 0) -> invalidArg "Height" "Height must be greater than 0."
| (_, _) -> ()
let validateLineThickness thickness =
match thickness with
| thickness when thickness <= 0.0 -> invalidArg "LineThickness" "LineThickness must be greater than 0."
| _ -> ()

4
TestCentre/AssemblyInfo.fs

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

229
TestCentre/LibraryTests.fs

@ -34,6 +34,18 @@
let loadLocation = __SOURCE_DIRECTORY__ + "/LoadingTestArea" let loadLocation = __SOURCE_DIRECTORY__ + "/LoadingTestArea"
let saveLocation = __SOURCE_DIRECTORY__ + "/SavingTestArea" let saveLocation = __SOURCE_DIRECTORY__ + "/SavingTestArea"
let validSkiaImagePath =
(loadLocation + "/RequiredInfo/Skia-599x336.png")
let validSystemDrawingImagePath =
(loadLocation + "/RequiredInfo/SystemDrawing-338x307.png")
let validImagePath =
(loadLocation + "/RequiredInfo/ImageTest1.png")
let validImagePath2 =
(loadLocation + "/RequiredInfo/ImageTest2.png")
let validImagePath3 =
(loadLocation + "/RequiredInfo/ImageTest3.png")
let invalidImagePath = "invalid.png"
let allColours = let allColours =
let properties = let properties =
typeof<Brushes>.GetProperties typeof<Brushes>.GetProperties
@ -99,12 +111,12 @@
module PropertyTests = module PropertyTests =
open FsCheck.Xunit open System.IO
open DeathSocket
open System.Drawing open System.Drawing
open DeathSocket
open DeathSocket.GridPainter open DeathSocket.GridPainter
open TestingHelpers open TestingHelpers
open System.IO open FsCheck.Xunit
(* With regards to the "saving images" tests, you should end up with (* With regards to the "saving images" tests, you should end up with
one image left over in the SavingTestArea folder. Comment out the one image left over in the SavingTestArea folder. Comment out the
@ -175,6 +187,7 @@
let result = determineVerticalLines (newNum()) (newNum()) (newNum()) let result = determineVerticalLines (newNum()) (newNum()) (newNum())
result.Length > 0 result.Length > 0
// This test fails when using SkiaSharp 1.68
[<Property>] [<Property>]
let ``Can apply grid to image and save it using SkiaSpec`` () = let ``Can apply grid to image and save it using SkiaSpec`` () =
resetSavingTestArea() resetSavingTestArea()
@ -190,6 +203,7 @@
|> Async.RunSynchronously |> Async.RunSynchronously
(File.Exists sPath) = true (File.Exists sPath) = true
// This test fails when using SkiaSharp 1.68
[<Property>] [<Property>]
let ``Can apply grid to image and save it using SkiaRGBSpec`` () = let ``Can apply grid to image and save it using SkiaRGBSpec`` () =
resetSavingTestArea() resetSavingTestArea()
@ -217,17 +231,188 @@
let result = determineSKVerticalLines (newNum()) (newNum()) (newNum()) let result = determineSKVerticalLines (newNum()) (newNum()) (newNum())
result.Length > 0 result.Length > 0
[<Property>]
let ``Can create a populated SKData buffer when calling createSKDataAsync with SkiaBuffer`` () =
let result () =
SkiaBuffer ({ filePath = validImagePath
skColour = randomSKColour ()
penWidth = float32 (newPenWidth())
rows = newNum ()
columns = newNum () })
|> createSKDataAsync
|> Async.RunSynchronously
(result ()).IsEmpty = false
[<Property>]
let ``Can create a populated SKData buffer when calling createSKDataAsync with SkiaRGBBuffer`` () =
let result () =
SkiaRGBBuffer ({ filePath = validImagePath3
red = float32 (newNum())
green = float32 (newNum())
blue = float32 (newNum())
penWidth = float32 (newPenWidth())
rows = newNum ()
columns = newNum () })
|> createSKDataAsync
|> Async.RunSynchronously
(result ()).IsEmpty = false
module UnitTests = module UnitTests =
open TestingHelpers
open Xunit
open DeathSocket
open System open System
open System.IO open System.IO
open System.Drawing
open Xunit
open DeathSocket
open SkiaSharp
open TestingHelpers
[<Fact>]
let ``An empty SKData object is returned when createSKDataAsync cannot find file when using SkiaBuffer`` () =
let result =
SkiaBuffer ({ filePath = invalidImagePath
penWidth = float32 1
skColour = SKColors.Empty
rows = 1
columns = 1 })
|> GridPainter.createSKDataAsync
|> Async.RunSynchronously
Assert.Equal(SKData.Empty, result)
[<Fact>]
let ``An empty SKData object is returned when createSKDataAsync cannot find file when using SkiaRGBBuffer`` () =
let result =
SkiaRGBBuffer ({ filePath = invalidImagePath
penWidth = float32 1
red = float32 1
green = float32 1
blue = float32 1
rows = 1
columns = 1 })
|> GridPainter.createSKDataAsync
|> Async.RunSynchronously
Assert.Equal(SKData.Empty, result)
[<Fact>]
let ``An empty SKData object is returned when calling createSKDataAsync with SkiaRGB`` () =
let result =
SkiaRGB ({ originalPath = validImagePath2
savePath= validImagePath
red = float32 1
green = float32 1
blue = float32 1
penWidth = float32 1
rows = 1
columns = 1})
|> GridPainter.createSKDataAsync
|> Async.RunSynchronously
Assert.Equal(SKData.Empty, result)
[<Fact>]
let ``An empty SKData object is returned when calling createSKDataAsync with Skia`` () =
let result =
Skia ({ originalPath = validImagePath3
savePath= validImagePath
skColour = SKColors.Empty
penWidth = float32 1
rows = 1
columns = 1 })
|> GridPainter.createSKDataAsync
|> Async.RunSynchronously
Assert.Equal(SKData.Empty, result)
[<Fact>]
let ``An empty SKData object is returned when calling createSKDataAsync with Brush`` () =
let result =
Brush ({ originalPath = validImagePath
savePath= validImagePath
colour = Brushes.AliceBlue
penWidth = float32 1
rows = 1
columns = 1 })
|> GridPainter.createSKDataAsync
|> Async.RunSynchronously
Assert.Equal(SKData.Empty, result)
[<Fact>]
let ``An empty SKData object is returned when calling createSKDataAsync with RGBA`` () =
let result =
RGBA ({ originalPath = validImagePath
savePath= validImagePath
red = float 1
green = float 1
blue = float 1
alpha = float 1
penWidth = float32 1
rows = 1
columns = 1 })
|> GridPainter.createSKDataAsync
|> Async.RunSynchronously
Assert.Equal(SKData.Empty, result)
[<Fact>]
let ``Argument Exception is thrown when actualDimensions are set to 0 when calling scaleLineThickness`` () =
let result () =
GridPainter.scaleLineThickness (1, 0) (0, 0) 1.0
Assert.Throws<ArgumentException>(fun () -> result () |> ignore)
[<Fact>]
let ``Argument Exception is thrown when lineThickness is set to 0 when calling scaleLineThickness`` () =
let result () =
GridPainter.scaleLineThickness (1, 0)(1, 0) 0.0
Assert.Throws<ArgumentException>(fun () -> result () |> ignore)
[<Fact>]
let ``Argument Exception is thrown when previewDimensions are set to 0 when calling scaleLineThickness`` () =
let result () =
GridPainter.scaleLineThickness (0, 0) (1, 0) 1.0
Assert.Throws<ArgumentException>(fun () -> result () |> ignore)
[<Fact>]
let ``Can determine image width using SkiaSharp`` () =
let dimensions =
SkiaSharp (validSkiaImagePath)
|> GridPainter.determineImageDimensions
let result () = (fst dimensions) = 599
Assert.True (result ())
[<Fact>]
let ``Can determine image height using SkiaSharp`` () =
let dimensions =
SkiaSharp (validSkiaImagePath)
|> GridPainter.determineImageDimensions
let result () = (snd dimensions) = 336
Assert.True (result ())
[<Fact>]
let ``Can determine image width using SystemDrawing`` () =
let dimensions =
SystemDrawing (validSystemDrawingImagePath)
|> GridPainter.determineImageDimensions
let result () = (fst dimensions) = 338
Assert.True (result ())
[<Fact>]
let ``Can determine image height using SystemDrawing`` () =
let dimensions =
SystemDrawing (validSystemDrawingImagePath)
|> GridPainter.determineImageDimensions
let result () = (snd dimensions) = 307
Assert.True (result ())
[<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)
(* This test is a pre-test test (a test for the tests if you will...). (* This test is a pre-test test (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.
If the property test fails, here is a good place to start. If the property tests fails, here is a good place to start.
See script.fs (in Test Centre) for information on populating the See script.fs (in Test Centre) for information on populating the
LoadingTestArea folder. *) LoadingTestArea folder. *)
[<Fact>] [<Fact>]
@ -236,6 +421,24 @@
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 ``Pen thickness scales down to match preview image dimensions`` () =
let result () =
GridPainter.scaleLineThickness (100, 100) (200, 200) 10.0
Assert.Equal (5.0, (result ()))
[<Fact>]
let ``Pen thickness scales up to match preview image dimensions`` () =
let result () =
GridPainter.scaleLineThickness (200, 200) (100, 100) 10.0
Assert.Equal (20.0, (result ()))
[<Fact>]
let ``Pen thickness remains the same when preview image matches actual dimensions`` () =
let result () =
GridPainter.scaleLineThickness (100, 100) (100, 100) 10.0
Assert.Equal (10.0, (result ()))
(* This test is a pre-test test. If the property tests fails, here is a (* This test is a pre-test test. If the property tests fails, here is a
good place to start. The easiest way to get this test to pass is to good place to start. The easiest way to get this test to pass is to
create a folder called "SavingTestArea" in this projects folder create a folder called "SavingTestArea" in this projects folder
@ -244,14 +447,4 @@
for extra context. *) for extra context. *)
[<Fact>] [<Fact>]
let ``SavingTestArea folder can be found`` () = let ``SavingTestArea folder can be found`` () =
Assert.True (Directory.Exists saveLocation) Assert.True (Directory.Exists saveLocation)
[<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)

BIN
TestCentre/LoadingTestArea/RequiredInfo/ImageTest1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
TestCentre/LoadingTestArea/RequiredInfo/ImageTest2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
TestCentre/LoadingTestArea/RequiredInfo/ImageTest3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
TestCentre/LoadingTestArea/RequiredInfo/Skia-599x336.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
TestCentre/LoadingTestArea/RequiredInfo/SystemDrawing-338x307.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Loading…
Cancel
Save