I just started learning Haskell, so I am likely missing something very trivial. I am attempting to generate images using Haskell Image Processing. I am adapting the code from sample snippets from the docs. My code is as follows.
{-# LANGUAGE NoImplicitPrelude #-}
module Main where
import Prelude as P
import Graphics.Image as I
getPixel :: (Int, Int) -> Pixel RGB Word8
getPixel (i, j) = PixelRGB (fromIntegral i) (fromIntegral j) (fromIntegral (i + j))
getImage :: (Int, Int) -> Image VS RGB Word8
getImage (w, h) = makeImageR VS (w, h) getPixel
main :: IO ()
main = writeImage "image.png" image
where image = getImage (1024, 1024)
when I try to build it, I get the following
• No instance for (Writable (Image VS RGB Word8) OutputFormat)
arising from a use of ‘writeImage’
• In the expression: writeImage "image.png" image
In an equation for ‘main’:
main
= writeImage "image.png" image
where
image = getImage (1024, 1024)
Cannot seem to figure out what I am doing wrong.
The HIP package makes extensive use of the type system to handle multiple external image formats and internal image layouts. In particular, the writeImage
function has signature:
writeImage
:: (Array VS cs e, Array arr cs e, Writable (Image VS cs e) OutputFormat)
=> FilePath
-> Image arr cs e
-> IO ()
The key takeaway here is that, if you want to write an Image arr cs e
using this function, that type has to obey the constraint (i.e., have a type class instance for):
Writable (Image VS cs e) OutputFormat
To see what instances the library makes available, you can take a look at the documentation for Writable
which has a big list of available instances. However, the only Writable x y
instance with y
equal to OutputFormat
(which means "a general format unknown at compile time") is:
instance AllWritable arr cs => Writable (Image arr cs Double) OutputFormat
This means that only Image arr cs e
with e
equal to Double
are compatible with the writeImage
function. The reasoning behind this is probably that, because the writeImage
function only identifies the file type to be written at runtime (by inspecting the file extension of the supplied file path), it only wants to accept an image whose channel data is already in a high-precision type (e.g., Double
), in case it determines that the final format can handle high-precision channel data; you could argue that this restriction doesn't really make a whole lot of sense, but that's the way it is.
So, as @DanielWagner pointed out, you need to provide writeImage
with an image having Double
channel data. Alternatively, you could use writeImageExact
which specifies the format at compile time and allows the use of any Writable
instance for the appropriate format. So, for example, replacing the writeImage
call with:
writeImageExact PNG [] "image.png" image
would have worked fine, because there's an appropriate instance for it:
instance Writable (Image VS RGB Word8) PNG