6 changed files with 193 additions and 0 deletions
@ -0,0 +1,25 @@ |
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00 |
||||||
|
# Visual Studio 15 |
||||||
|
VisualStudioVersion = 15.0.28010.2016 |
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1 |
||||||
|
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "SmoulderingBeachBall", "SmoulderingBeachBall\SmoulderingBeachBall.fsproj", "{DFC3CBCA-3DA7-4CF4-A8BC-BCCB740FA6CD}" |
||||||
|
EndProject |
||||||
|
Global |
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution |
||||||
|
Debug|Any CPU = Debug|Any CPU |
||||||
|
Release|Any CPU = Release|Any CPU |
||||||
|
EndGlobalSection |
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution |
||||||
|
{DFC3CBCA-3DA7-4CF4-A8BC-BCCB740FA6CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
||||||
|
{DFC3CBCA-3DA7-4CF4-A8BC-BCCB740FA6CD}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||||
|
{DFC3CBCA-3DA7-4CF4-A8BC-BCCB740FA6CD}.Release|Any CPU.ActiveCfg = Release|Any CPU |
||||||
|
{DFC3CBCA-3DA7-4CF4-A8BC-BCCB740FA6CD}.Release|Any CPU.Build.0 = Release|Any CPU |
||||||
|
EndGlobalSection |
||||||
|
GlobalSection(SolutionProperties) = preSolution |
||||||
|
HideSolutionNode = FALSE |
||||||
|
EndGlobalSection |
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution |
||||||
|
SolutionGuid = {78F0A77D-F78C-476F-A7C5-64E5579E9EB4} |
||||||
|
EndGlobalSection |
||||||
|
EndGlobal |
@ -0,0 +1,21 @@ |
|||||||
|
namespace SmoulderingBeachBall.Domain |
||||||
|
|
||||||
|
[<AutoOpen>] |
||||||
|
module DomainTypes = |
||||||
|
|
||||||
|
open System.Drawing |
||||||
|
|
||||||
|
type OverlayType = |
||||||
|
| Border |
||||||
|
| Full |
||||||
|
|
||||||
|
type OverlaySpec = |
||||||
|
{ colour: Brush; |
||||||
|
overlayType: OverlayType } |
||||||
|
|
||||||
|
type ImageSpec = |
||||||
|
{ width: int; |
||||||
|
height: int; |
||||||
|
colour: Brush; |
||||||
|
filePath: string; |
||||||
|
overlay: OverlaySpec option } |
@ -0,0 +1,65 @@ |
|||||||
|
module internal InternalServices |
||||||
|
|
||||||
|
open System.IO |
||||||
|
open System.Drawing |
||||||
|
open SmoulderingBeachBall.Domain |
||||||
|
|
||||||
|
module Validation = |
||||||
|
|
||||||
|
let validateDimension dimension = |
||||||
|
match dimension with |
||||||
|
| dimension when dimension <= 0 -> |
||||||
|
invalidArg "dimension" "The width and height must be greater than 0." |
||||||
|
| _ -> () |
||||||
|
|
||||||
|
let validateDirectory filePath = |
||||||
|
let path = Path.GetDirectoryName filePath |
||||||
|
match (Directory.Exists path) with |
||||||
|
| false -> invalidArg "filePath" "Unable to save to the specified location because it does not exist." |
||||||
|
| true -> () |
||||||
|
|
||||||
|
module Drawing = |
||||||
|
|
||||||
|
let penOffset penWidth = int (penWidth / (float32 2)) |
||||||
|
|
||||||
|
let createBorderPath penWidth spec = |
||||||
|
let offset = penOffset penWidth |
||||||
|
[|Point (0, offset); // Essentially (0, 0) |
||||||
|
Point ((spec.width - offset), offset); |
||||||
|
Point ((spec.width - offset), (spec.height - offset)); |
||||||
|
Point (offset, (spec.height - offset)); |
||||||
|
Point (offset, 0)|] |
||||||
|
|
||||||
|
let drawBorder (graphics: Graphics) (pen: Pen) spec = |
||||||
|
printfn "[INFO.] Adding border to image..." |
||||||
|
let penPath = createBorderPath pen.Width spec |
||||||
|
graphics.DrawLines (pen, penPath) |
||||||
|
|
||||||
|
|
||||||
|
let drawFullOverlay (graphics: Graphics) (pen: Pen) spec = |
||||||
|
drawBorder graphics pen spec |
||||||
|
printfn "[INFO.] Adding full overlay to image..." |
||||||
|
let offset = penOffset pen.Width |
||||||
|
// Draws line from top-left to bottom-right of square. |
||||||
|
graphics.DrawLine (pen, offset, offset, (spec.width - offset), (spec.height - offset)) |
||||||
|
// Draws line from top-right to bottom-left of square. |
||||||
|
graphics.DrawLine (pen, (spec.width - offset), offset, offset, (spec.height - offset)) |
||||||
|
|
||||||
|
let addOverlayToImage graphics spec = |
||||||
|
let overlay = spec.overlay.Value |
||||||
|
let pen = new Pen (overlay.colour, Width = 10.0f) |
||||||
|
match overlay.overlayType with |
||||||
|
| Border -> drawBorder graphics pen spec |
||||||
|
| Full -> drawFullOverlay graphics pen spec |
||||||
|
|
||||||
|
let drawImage spec = |
||||||
|
let bitmap = new Bitmap (spec.width, spec.height) |
||||||
|
let graphics = Graphics.FromImage (bitmap) |
||||||
|
let rectangle = Rectangle (0, 0, spec.width, spec.height) |
||||||
|
graphics.FillRectangle (spec.colour, rectangle) |
||||||
|
match spec.overlay.IsSome with |
||||||
|
| true -> addOverlayToImage graphics spec |
||||||
|
| false -> printfn "[INFO.] No overlay specified. Creating image without one." |
||||||
|
bitmap.Save (spec.filePath) |
||||||
|
bitmap.Dispose() |
||||||
|
graphics.Dispose() |
@ -0,0 +1,41 @@ |
|||||||
|
#load "Domain.fs" |
||||||
|
#load "InternalServices.fs" |
||||||
|
#load "Services.fs" |
||||||
|
|
||||||
|
open System.Drawing |
||||||
|
open System.Drawing.Imaging |
||||||
|
open SmoulderingBeachBall.Domain.DomainTypes |
||||||
|
open SmoulderingBeachBall.Services |
||||||
|
|
||||||
|
// INITIAL IDEA =============================================================== |
||||||
|
|
||||||
|
let width = 500 |
||||||
|
let height = 500 |
||||||
|
let colour = Brushes.BurlyWood |
||||||
|
let testPath = "C:/users/craig/desktop/test.png" |
||||||
|
let draw () = |
||||||
|
use bmp = new Bitmap(width, height) |
||||||
|
use gr = Graphics.FromImage(bmp) |
||||||
|
gr.FillRectangle(colour, new Rectangle(0, 0, bmp.Width, bmp.Height)) |
||||||
|
gr.DrawImage(bmp, 0, 0) |
||||||
|
bmp.Save(testPath, ImageFormat.Png) |
||||||
|
|
||||||
|
// Smouldering Beach Ball Library Code ======================================== |
||||||
|
|
||||||
|
let borderOverlay = |
||||||
|
{ colour = Brushes.BlueViolet; |
||||||
|
overlayType = Border } |
||||||
|
|
||||||
|
let fullOverlay = |
||||||
|
{ colour = Brushes.Fuchsia; |
||||||
|
overlayType = Full } |
||||||
|
|
||||||
|
let imageSpec = |
||||||
|
{ width = 500; |
||||||
|
height = 500; |
||||||
|
colour = Brushes.Yellow; |
||||||
|
filePath = "C:/users/craig/desktop/test.png"; |
||||||
|
// Change this to flip between border/full overlay or None. |
||||||
|
overlay = Some fullOverlay } |
||||||
|
|
||||||
|
makeImage imageSpec |> Async.RunSynchronously |
@ -0,0 +1,23 @@ |
|||||||
|
namespace SmoulderingBeachBall |
||||||
|
|
||||||
|
module Services = |
||||||
|
|
||||||
|
open System |
||||||
|
open SmoulderingBeachBall.Domain.DomainTypes |
||||||
|
open InternalServices.Validation |
||||||
|
open InternalServices.Drawing |
||||||
|
|
||||||
|
let makeImage (spec: ImageSpec) = |
||||||
|
async { |
||||||
|
try |
||||||
|
printfn "[INFO.] Attempting to make image..." |
||||||
|
validateDimension spec.width |
||||||
|
validateDimension spec.height |
||||||
|
validateDirectory spec.filePath |
||||||
|
drawImage spec |
||||||
|
printfn "[SUCCESS] Image creation attempt complete." |
||||||
|
return () |
||||||
|
with |
||||||
|
| :? ArgumentException as ex -> printfn "%s" ex.Message |
||||||
|
| _ as ex -> printfn "%s" ex.Message |
||||||
|
} |
@ -0,0 +1,18 @@ |
|||||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||||
|
|
||||||
|
<PropertyGroup> |
||||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||||
|
</PropertyGroup> |
||||||
|
|
||||||
|
<ItemGroup> |
||||||
|
<Compile Include="Domain.fs" /> |
||||||
|
<Compile Include="InternalServices.fs" /> |
||||||
|
<Compile Include="Services.fs" /> |
||||||
|
<None Include="ScratchPad.fsx" /> |
||||||
|
</ItemGroup> |
||||||
|
|
||||||
|
<ItemGroup> |
||||||
|
<PackageReference Include="Microsoft.Windows.Compatibility" Version="2.0.1" /> |
||||||
|
</ItemGroup> |
||||||
|
|
||||||
|
</Project> |
Loading…
Reference in new issue