diff --git a/SmoulderingBeachBall.sln b/SmoulderingBeachBall.sln index d7de6b3..8328c68 100644 --- a/SmoulderingBeachBall.sln +++ b/SmoulderingBeachBall.sln @@ -3,7 +3,9 @@ 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}" +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "SmoulderingBeachBall", "SmoulderingBeachBall\SmoulderingBeachBall.fsproj", "{DFC3CBCA-3DA7-4CF4-A8BC-BCCB740FA6CD}" +EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "SmoulderingBeachBallCLI", "SmoulderingBeachBallCLI\SmoulderingBeachBallCLI.fsproj", "{5C00D583-EF09-4FE6-A3FE-EB01454C0607}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -15,6 +17,10 @@ Global {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 + {5C00D583-EF09-4FE6-A3FE-EB01454C0607}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5C00D583-EF09-4FE6-A3FE-EB01454C0607}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5C00D583-EF09-4FE6-A3FE-EB01454C0607}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5C00D583-EF09-4FE6-A3FE-EB01454C0607}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/SmoulderingBeachBall/InternalServices.fs b/SmoulderingBeachBall/InternalServices.fs index ac0df8f..260e608 100644 --- a/SmoulderingBeachBall/InternalServices.fs +++ b/SmoulderingBeachBall/InternalServices.fs @@ -9,21 +9,30 @@ let validateDimension dimension = match dimension with | dimension when dimension <= 0 -> - invalidArg "dimension" "The width and height must be greater than 0." + invalidArg "dimension" "[ERROR] The images height and width 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." + | false -> + invalidArg "filePath" "[ERROR] Unable to save to the specified location because it could not be found." | true -> () module Drawing = + open System.Text let penOffset penWidth = int (penWidth / (float32 2)) + let setPenWidth imgWidth imgHeight = + let width = float32 imgWidth + let height = float32 imgHeight + if (width >= height) then + height * (float32 0.05) + else width * (float32 0.05) + let createBorderPath penWidth spec = - let offset = penOffset penWidth + let offset = penOffset penWidth [|Point (0, offset); // Essentially (0, 0) Point ((spec.width - offset), offset); Point ((spec.width - offset), (spec.height - offset)); @@ -47,11 +56,21 @@ let addOverlayToImage graphics spec = let overlay = spec.overlay.Value - let pen = new Pen (overlay.colour, Width = 10.0f) + let pen = + new Pen (overlay.colour, width = (setPenWidth spec.width spec.height)) match overlay.overlayType with | Border -> drawBorder graphics pen spec | Full -> drawFullOverlay graphics pen spec + let buildFileName spec = + let sb = new StringBuilder () + sb.Append (spec.width.ToString ()) |> ignore + sb.Append "x" |> ignore + sb.Append (spec.height.ToString ()) |> ignore + sb.Append ".png" |> ignore + (sb.ToString ()) + + let drawImage spec = let bitmap = new Bitmap (spec.width, spec.height) let graphics = Graphics.FromImage (bitmap) @@ -60,6 +79,6 @@ 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() \ No newline at end of file + bitmap.Save (Path.Combine (spec.filePath, (buildFileName spec))) + graphics.Dispose() + bitmap.Dispose() \ No newline at end of file diff --git a/SmoulderingBeachBallCLI/App.config b/SmoulderingBeachBallCLI/App.config new file mode 100644 index 0000000..787dcbe --- /dev/null +++ b/SmoulderingBeachBallCLI/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/SmoulderingBeachBallCLI/AppIcon.rc b/SmoulderingBeachBallCLI/AppIcon.rc new file mode 100644 index 0000000..eb1ecab --- /dev/null +++ b/SmoulderingBeachBallCLI/AppIcon.rc @@ -0,0 +1 @@ +1 ICON icon.ico \ No newline at end of file diff --git a/SmoulderingBeachBallCLI/AppIcon.res b/SmoulderingBeachBallCLI/AppIcon.res new file mode 100644 index 0000000..1bd6c6c Binary files /dev/null and b/SmoulderingBeachBallCLI/AppIcon.res differ diff --git a/SmoulderingBeachBallCLI/AssemblyInfo.fs b/SmoulderingBeachBallCLI/AssemblyInfo.fs new file mode 100644 index 0000000..1fedc7e --- /dev/null +++ b/SmoulderingBeachBallCLI/AssemblyInfo.fs @@ -0,0 +1,41 @@ +namespace SmoulderingBeachBallCLI.AssemblyInfo + +open System.Reflection +open System.Runtime.CompilerServices +open System.Runtime.InteropServices + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[] +[] +[] +[] +[] +[] +[] +[] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [] +[] +[] + +do + () \ No newline at end of file diff --git a/SmoulderingBeachBallCLI/ConsoleCommands.fs b/SmoulderingBeachBallCLI/ConsoleCommands.fs new file mode 100644 index 0000000..9e47ed9 --- /dev/null +++ b/SmoulderingBeachBallCLI/ConsoleCommands.fs @@ -0,0 +1,114 @@ +namespace Commands + + module ConsoleCommands = + + open System + open Console.Waterworks + open Console.Waterworks.Attributes + open SmoulderingBeachBall.Services + open Validation + open System.IO + + let showEndOfCommandMessage = "[INFO.] Execution completed." + + [] + [] + [] + [] + let test () = "[SUCCESS] Smouldering Beach Ball CLI seems to be working." + + [] + [] + [] + [] + let help () = CW_Liaison().RequestHelpDocumentation("Commands") + + [] + [] + [] + [] + let cheat () = + try + printfn "[INFO] Attempting to save cheat sheet to the desktop..." + let cheatSheetPath = __SOURCE_DIRECTORY__ + "/cheat-sheet.pdf" + let savePath = getDesktopPath + "/smouldering-beach-ball-cheat-sheet.pdf" + File.Copy (cheatSheetPath, savePath, true) + showEndOfCommandMessage + with + | :? FileNotFoundException as ex -> ex.Message + | _ as ex -> ex.Message + + [] + [] + [] + [] + let exit () = Environment.Exit (Environment.ExitCode) + + [] + [] + [] + [] + let ``draw-default`` imgWidth imgHeight = + try + buildDefaultSpec imgWidth imgHeight + |> makeImage + |> Async.RunSynchronously + showEndOfCommandMessage + with + | :? ArgumentException as ex -> ex.Message + | _ as ex -> ex.Message + + [] + [] + [] + [] + let ``draw-image`` imgWidth imgHeight mainColour oColour oType path = + try + buildSpec imgWidth imgHeight mainColour oColour oType path + |> makeImage + |> Async.RunSynchronously + showEndOfCommandMessage + with + | :? ArgumentException as ex -> ex.Message + | _ as ex -> ex.Message + + [] + [] + [] + [] + let ``list-colours`` () = + printfn "[INFO.] Listing available colours..." + for item in colourList do + printfn "%s" item.Key + showEndOfCommandMessage + + (* ALIASES + ======================================================================= + These command-methods will not show up in the help section. + Before adding extra aliases, make sure the main version is as clear and + helpful to someone new to the program as possible. Aliases should be + treated as commands for experienced users and documented on the wiki, + hosted alongside the repository on GitHub. + URL: https://github.com/CraigOates/Smouldering-Beach-Ball/wiki *) + + let dd imgWidth imgHeight = + ``draw-default`` imgWidth imgHeight + + let di imgWidth imgHeight mainColour oColour oType path = + ``draw-image`` imgWidth imgHeight mainColour oColour oType path + + let lc () = ``list-colours`` () diff --git a/SmoulderingBeachBallCLI/Program.fs b/SmoulderingBeachBallCLI/Program.fs new file mode 100644 index 0000000..c43a2d1 --- /dev/null +++ b/SmoulderingBeachBallCLI/Program.fs @@ -0,0 +1,7 @@ +open Console.Waterworks + +[] +let main argv = + let liaison = new CW_Liaison () + liaison.Run ("Commands", true) + 0 // return an integer exit code diff --git a/SmoulderingBeachBallCLI/SmoulderingBeachBallCLI.fsproj b/SmoulderingBeachBallCLI/SmoulderingBeachBallCLI.fsproj new file mode 100644 index 0000000..9ff9e29 --- /dev/null +++ b/SmoulderingBeachBallCLI/SmoulderingBeachBallCLI.fsproj @@ -0,0 +1,96 @@ + + + + + Debug + AnyCPU + 2.0 + 5c00d583-ef09-4fe6-a3fe-eb01454c0607 + Exe + SmoulderingBeachBallCLI + SmoulderingBeachBallCLI + v4.7.1 + true + true + SmoulderingBeachBallCLI + ..\SmoulderingBeachBallCLI\AppIcon.res + + + true + full + false + false + bin\$(Configuration)\ + DEBUG;TRACE + 3 + AnyCPU + + + false + + + + + pdbonly + true + true + bin\$(Configuration)\ + TRACE + 3 + AnyCPU + + + true + + + 11 + + + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets + + + + + + + + + + + + + + + + ..\packages\Console.Waterworks.0.1.0.0-alpha1\lib\Console.Waterworks.dll + + + ..\packages\FSharp.Core.4.5.2\lib\net45\FSharp.Core.dll + + + + + + + ..\packages\System.Drawing.Common.4.5.0\lib\net461\System.Drawing.Common.dll + + + + True + + + + + SmoulderingBeachBall + {dfc3cbca-3da7-4cf4-a8bc-bccb740fa6cd} + True + + + + \ No newline at end of file diff --git a/SmoulderingBeachBallCLI/Validation.fs b/SmoulderingBeachBallCLI/Validation.fs new file mode 100644 index 0000000..3820173 --- /dev/null +++ b/SmoulderingBeachBallCLI/Validation.fs @@ -0,0 +1,85 @@ +module internal Validation + + open System.Drawing + open SmoulderingBeachBall.Domain.DomainTypes + open System + + let colourList = + [ "blue", Brushes.AliceBlue; + "brown", Brushes.Brown; + "black", Brushes.Black; + "gray", Brushes.Gray; + "green", Brushes.Green; + "purple", Brushes.Purple; + "red", Brushes.Red; + "white", Brushes.White; + "yellow", Brushes.Yellow;] + |> Map.ofList + + let isColourValid (colour: string) = + colourList + |> Map.containsKey (colour.ToLower()) + + let parseColour colour = + match (isColourValid colour) with + | true -> + colourList + |> Map.find (colour.ToLower()) + | false -> + invalidArg "Colour" + (String.Concat("[ERROR] The colour specifed is invalid.\n", + "Please use the 'list-colours' command to see what you can use.")) + + let getDesktopPath = + Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + + let parsePath (path: string) = + match path with + | path when ((path.ToLower()).Equals "desktop") -> getDesktopPath + | path when ((path.ToLower()).Equals "d") -> getDesktopPath + | _ -> path + + let buildDefaultSpec iWidth iHeight = + let oSpec = + { colour = Brushes.Black + overlayType = Full } + let spec = + { width = iWidth + height = iHeight + colour = Brushes.AntiqueWhite + filePath = getDesktopPath + overlay = Some oSpec + } + spec + + let parseOverlay (oType: string) = + match oType.ToLower() with + | "border" -> Border + | "b" -> Border + | "full" -> Full + | "f" -> Full + | _ -> invalidArg "Overlay Type" "The overlay type must be either 'border' or 'full'." + + let buildOverlaySpec oColour (oType: string) = + let oSpec = + { colour = parseColour oColour; + overlayType = parseOverlay oType } + oSpec + + let buildMainSpec iWidth iHeight mainColour path oSpec = + let spec = + { width = iWidth; + height = iHeight; + colour = parseColour mainColour + filePath = parsePath path + overlay = oSpec } + spec + + let buildSpec iWidth iHeight mainColour oColour (oType: string) path = + let spec = + match oType.ToLower() with + | "none" | "n" -> buildMainSpec iWidth iHeight mainColour path option.None + | _ -> + let oSpec = buildOverlaySpec oColour oType + buildMainSpec iWidth iHeight mainColour path (Some oSpec) + spec diff --git a/SmoulderingBeachBallCLI/cheat-sheet.pdf b/SmoulderingBeachBallCLI/cheat-sheet.pdf new file mode 100644 index 0000000..379d99b Binary files /dev/null and b/SmoulderingBeachBallCLI/cheat-sheet.pdf differ diff --git a/SmoulderingBeachBallCLI/icon.ico b/SmoulderingBeachBallCLI/icon.ico new file mode 100644 index 0000000..5d6956f Binary files /dev/null and b/SmoulderingBeachBallCLI/icon.ico differ diff --git a/SmoulderingBeachBallCLI/packages.config b/SmoulderingBeachBallCLI/packages.config new file mode 100644 index 0000000..45c38e7 --- /dev/null +++ b/SmoulderingBeachBallCLI/packages.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file