module internal ImageServices open System.IO open System.Drawing open System.Drawing.Imaging open DeathSocket open ColourServices open SkiaSharp open System let setLineThickness pDimension aDimension lineWidth = if (pDimension <= 0.0 || aDimension <= 0.0 || lineWidth <= 0.0) then raise (new DivideByZeroException ("[ERROR] The images height and width must be greater than 0.")) else lineWidth / (pDimension / aDimension) // 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) // Does not work when using SkiaSharp NuGet v. 1.68 let drawSkiaGrid (spec: SkiaSpec) = use fileStream = File.Open (spec.originalPath, 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 () use data = match Path.GetExtension (spec.savePath) with | ".jpg" | ".JPG" -> snapshot.Encode (SKEncodedImageFormat.Jpeg, 100) | ".png"| ".PNG" -> snapshot.Encode (SKEncodedImageFormat.Png, 100) | _ -> invalidArg "savePath" "The file type must be a .jpg or .png file." use saveStream = File.OpenWrite (spec.savePath) data.SaveTo (saveStream) // Does not work when using SkiaSharp NuGet v. 1.68 let drawSkiaRGBGrid spec = use fileStream = File.Open (spec.originalPath, 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 <- 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 () use data = match Path.GetExtension (spec.savePath) with | ".jpg" | ".JPG" -> snapshot.Encode (SKEncodedImageFormat.Jpeg, 100) | ".png"| ".PNG" -> snapshot.Encode (SKEncodedImageFormat.Png, 100) | _ -> invalidArg "savePath" "The file type must be a .jpg or .png file." use saveStream = File.OpenWrite (spec.savePath) data.SaveTo (saveStream) // 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) (* 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 with indexed pixels. Instead of listing them all, just assume any function with a "*Spec" type as a parameter will use this "temp" file. *) let drawBrushSpecGrid (spec: BrushSpec) = 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 (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) clone.Save (spec.savePath) let drawRGBAGrid (spec: RGBASpec) = 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 ((makeBrushFromRGBASpec spec), width = spec.penWidth) graphics.DrawImage (original,new Rectangle(0, 0, clone.Width, clone.Height)) let horizontalLines = 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) clone.Save (spec.savePath)