Skip to content

Instantly share code, notes, and snippets.

@fabiomolinar
Created December 13, 2021 20:37
Show Gist options
  • Save fabiomolinar/301d7ea6628d4687203bf5ffa450afa2 to your computer and use it in GitHub Desktop.
Save fabiomolinar/301d7ea6628d4687203bf5ffa450afa2 to your computer and use it in GitHub Desktop.
First version of my Haskell code which I used to create an image with an array of colorful squares.
{-|
Module : Degrade
Description : Creates an image with multiple squares of different colors.
Copyright : (c) Fabio Thomaz MOlinar, 2021
Maintainer : fabiomolinar@gmail.com
Stability : experimental
This was my first attempt at creating a module that would be able to create an
image with multiple squares of different colors. Although it works, the efficiency
is __TERRIBLE__.
By profiling the code, I found out that a lot of time was spent at the call which
searches a multidimensional list by index:
> defaultColor = c!!(j - 1)!!(i - 1)
-}
module Squares.Degrade where
import Graphics.Image
-- |Returns a white canvas with a certain width and height
makeCanvas :: Int -- ^ Width
-> Int -- ^ Height
-> [[Pixel RGB Double]]
makeCanvas w h = [[PixelRGB 255 255 255 | _ <- [1..w]] | _ <- [1..h]]
-- |Ads a red square to a given position on a canvas
addSquareToCanvas :: [[Pixel RGB Double]] -- ^ The canvas
-> Int -- ^ X position
-> Int -- ^ Y position
-> Int -- ^ Width
-> Int -- ^ Height
-> Pixel RGB Double -- ^ Color
-> [[Pixel RGB Double]]
addSquareToCanvas c x y w h rgb = [[selectedColor i j | i <- [1..canvasWidth]] | j <- [1..canvasHeight]]
where
canvasWidth = getCanvasWidth c
canvasHeight = getCanvasHeight c
selectedColor i j =
if inRange i j
then rgb
else defaultColor
where
defaultColor = c!!(j - 1)!!(i - 1)
inRange i j =
i >= x &&
i <= x + w - 1 &&
j >= y &&
j <= y + h - 1
getCanvasWidth :: [[Pixel RGB Double]] -> Int
getCanvasWidth c = length $ head c
getCanvasHeight :: [[Pixel RGB Double]] -> Int
getCanvasHeight = length
-- | Since color functions below use Double precision, need to recal each value will range from 0.0 to 1.0
redColor :: [[Pixel RGB Double]] -- ^ Canvas
-> Int -- ^ X
-> Int -- ^ Y
-> Pixel RGB Double
redColor c x y = PixelRGB 1.0 0.0 0.0
linearDegradeColor :: [[Pixel RGB Double]] -- ^ Canvas
-> Int -- ^ X
-> Int -- ^ Y
-> Pixel RGB Double
linearDegradeColor c x y = PixelRGB (fromIntegral x) (fromIntegral y) 0.0 / fromIntegral (max (getCanvasWidth c) (getCanvasHeight c))
addSquareXTimesHorizontally :: Int -- ^ Number of times
-> Int -- ^ X0
-> Int -- ^ Y0
-> Int -- ^ Spacing
-> Int -- ^ Square width
-> Int -- ^ Square height
-> ([[Pixel RGB Double]] -> Int -> Int -> Pixel RGB Double) -- ^ Coloring function
-> [[Pixel RGB Double]] -- ^ Canvas
-> [[Pixel RGB Double]]
addSquareXTimesHorizontally 0 x0 y0 s w h rgb c = c
addSquareXTimesHorizontally n x0 y0 s w h rgb c =
addSquareXTimesHorizontally (n - 1) x0 y0 s w h rgb $ addSquareToCanvas
c
(x0 + (w + s) * (n - 1))
y0
w
h
color
where
color = rgb c (x0 + (w + s) * (n - 1)) y0
addSquareXY :: Int -- ^ Squares in Y
-> Int -- ^ Squares in X
-> Int -- ^ Margin
-> Int -- ^ Spacing
-> Int -- ^ Square width
-> Int -- ^ Square height
-> ([[Pixel RGB Double]] -> Int -> Int -> Pixel RGB Double) -- ^ Coloring function
-> [[Pixel RGB Double]] -- ^ Canvas
-> [[Pixel RGB Double]]
addSquareXY 0 x m s w h rgb c = c
addSquareXY y x m s w h rgb c =
addSquareXY (y - 1) x m s w h rgb $ addSquareXTimesHorizontally
x
(m + 1)
(m + 1 + (h + s) * (y - 1))
s
w
h
rgb
c
-- | Code used for testing
makeThreeSquares :: Int -- ^ Margin
-> Int -- ^ Spacing
-> Int -- ^ Width
-> Int -- ^ Height
-> [[Pixel RGB Double]]
makeThreeSquares m s w h =
let
canvas = makeCanvas (2*m+2*s+3*w) (2*m+h)
in addSquareXTimesHorizontally 3 (m + 1) (m + 1) s w h redColor canvas
-- |Makes a red square of a given width and height
makeRedSquare :: Int -- ^ Width
-> Int -- ^ Height
-> [[Pixel RGB Double]]
makeRedSquare w h = [[PixelRGB 255 0 0 | _ <- [1..w]] | _ <- [1..h]]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment