I'm writing a program which reads and writes images that supports multiple pixel types (i.e. RGB, CMYK, greyscale etc.). These pixel types can use different types of components, sort of like this:
class (Storable c) => PixelComponent c where
blackWhite :: c -> (c, c)
toInt :: c -> Int
toRealFrac :: (RealFrac a) => c -> a
fromComponent :: (PixelComponent a) => a -> c
instance PixelComponent CUChar where
blackWhite x = (minBound x, maxBound x)
toInt = id
toRealFrac = fromIntegral
fromComponent x = ???
instance PixelComponent CFloat where
black = 0.0
white = 1.0
toInt = truncate
toReal = id
fromComponent x = ???
class (Storable pix) => Pixel pix where
red :: pix c -> c
green :: pix c -> c
blue :: pix c -> c
alpha :: pix c -> c
luminance :: pix c -> c
fromPixel :: (Pixel a) => a c -> pix c
The idea is that you should be able to do getPixel myImage (10, 23) :: RGB CUChar
or getPixel myImage (10, 23) :: RGB CFloat
depending on the pixel format you want. The problem is that I don't know how to implement fromComponent
in an efficient manner. Essentially, I would like unnecessary conversions such as fromComponent (1 :: CUChar) :: CUChar
and fromComponent (0.5 :: CFloat) :: CFloat
to be no-ops. I guessing that I'll have to rely on optimizations in any case.
Note: This might not be a good design anyway so if someone has a better suggestion I'm open to this. I'd still like to know how to make this solution work.