namespace DeathSocket open System.IO open ColourServices /// Provides functions which help draw gridded overlays onto images. /// Death Socket, uses System.Drawing's brushes and colours. /// If you are using System.Media brushes and colour, you will need to /// convert them. Death Socket, also, uses SkiaSharp for cross platform /// functionality. If you are using Death Socket on Windows Desktop, use /// functions which do not include "Skia" in their name. If you are using /// Death Socket in a Xamarin/UWP project you should use the SkiaSharp /// functions. module GridPainter = open ValidationServices open ImagePrep open ImageServices open SkiaSharp /// /// Uses the information included in spec to create a gridded image. /// 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. /// /// /// The specification used to generate the new gridded image. The /// ImageSpec is a discriminated union, consisting of a Brush, RGBA, /// Skia or SkiaRGB spec. /// /// /// 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. /// let applyGridToImageAsync (spec: ImageSpec) = async { try match spec with | Brush b -> validateIO b.originalPath b.savePath |> ignore drawBrushSpecGrid b | RGBA r -> validateIO r.originalPath r.savePath |> ignore drawRGBAGrid r | Skia s -> validateIO s.originalPath s.savePath |> ignore drawSkiaGrid s | SkiaRGB sR -> validateIO sR.originalPath sR.savePath |> ignore drawSkiaRGBGrid sR | _ -> printfn "[DEATH SOCKET INFO] Inappropriate ImageSpec used here. Please use none buffer-based spec's when using this function." with | :? FileNotFoundException as ex -> printfn "File could not be found at %s" ex.Message } /// /// 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. /// /// /// The width or height of the image when previewed (I.E. in a GUI). /// /// /// The width or height of the actual image. /// /// /// The thickness of the pen used to draw the grid line. /// /// /// 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. /// let scaleLineThickness (previewDimensions: int * int) (actualDimensions: int * int) (lineThickness: double) = validateDimensions previewDimensions |> ignore validateDimensions actualDimensions |> ignore validateLineThickness |> ignore adjustLineThickness previewDimensions actualDimensions lineThickness /// /// Reads an (jpg or png) image and return its width and height as a /// tuple, (width * hight). /// /// /// The name of the graphics library used to read and determine the /// images dimensions. /// /// /// 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. /// 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 ==================================================================== *) /// /// 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. /// Use this function when targeting .Net/Mono). /// /// 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: int) (height: int) (rows: int) = 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. /// Use this function when targeting Windows Desktop (or Mono). /// /// 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: int) (height: int) (columns: int) = createVerticalLines width height columns /// /// Creates a Sytsem.Drawing SolidBrush from the individual RGBA values. /// Use this function when targeting .Net/Mono). /// /// The red value. /// The green value. /// The blue value. /// The alpha value. /// /// Death Socket uses System.Drawing and not System.Media for colours /// and brushes. /// let makeSolidBrushFromRGBA (r: int) (g: int) (b:int) (a: int) = makeBrushFromRGBA r g b a /// /// Creates a System.Drawing SolidBrush from a RGBASpec. /// Use this function when targeting .Net/Mono). /// /// /// The specification which the brush is made from. /// /// /// Death Socket uses System.Drawing and not System.Media for colours /// and brushes. /// let makeSolidBrushFromRGBASpec (spec: RGBASpec) = makeBrushFromRGBASpec spec (* SkiaSharp Functions ==================================================================== *) /// /// 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. /// /// /// The specification used to generate the new SKData buffer. The /// ImageSpec is a discriminated union, consisting of a SkiaBuffer and /// a SkiaRGBBuffer spec. /// /// /// 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. /// 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 } /// /// Determines the (SKPoints) points needed to draw the appropriate /// number of horizontal lines (I.E. rows). Each item in the array /// included a start and end co-ordinate (SKPoint) for each line. /// Use this function when targeting Xamarin/UWP/.Net Core (SkiaSharp). /// /// The width of the image. /// The height of the image. /// The number of rows the grid should have. /// /// This function is part of the SkiaSharp functions provided /// by Death Socket. /// let determineSKHorizontalLines (width: int) (height: int) (rows: int) = createSKHorizontalLines width height rows /// /// Determines the (SKPoints) points needed to draw the appropriate /// number of vertical lines (I.E. columns). Each item in the array /// included a start and end co-ordinate (SKPoint) for each line. /// Use this function when targeting Xamarin/UWP/.Net Core (SkiaSharp). /// /// The width of the image. /// The height of the image. /// The number of columns the grid should have. /// /// /// This function is part of the SkiaSharp functions provided by Death /// Socket. /// let determineSKVerticalLines (width: int) (height: int) (columns: int) = createSKVerticalLines width height columns