3

我刚开始学习 Haskell,所以我可能遗漏了一些非常琐碎的东西。我正在尝试使用 Haskell 图像处理生成图像。我正在从文档的示例片段中调整代码。我的代码如下。

{-# 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)

当我尝试构建它时,我得到以下信息

• 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)

似乎无法弄清楚我做错了什么。

4

1 回答 1

2

HIP 包广泛使用类型系统来处理多种外部图像格式和内部图像布局。特别是,该writeImage函数具有签名:

writeImage
  :: (Array VS cs e, Array arr cs e, Writable (Image VS cs e) OutputFormat)  
  => FilePath   
  -> Image arr cs e 
  -> IO ()

这里的关键点是,如果你想Image arr cs e使用这个函数编写一个,该类型必须遵守约束(即,有一个类型类实例):

Writable (Image VS cs e) OutputFormat

要查看该库提供了哪些可用实例,您可以查看Writable包含大量可用实例的文档。但是,唯一具有等于的Writable x y实例(这意味着“编译时未知的一般格式”)是:yOutputFormat

instance AllWritable arr cs => Writable (Image arr cs Double) OutputFormat   

这意味着只有Image arr cs ee等于是Double兼容的writeImage功能。这背后的原因可能是,因为该writeImage函数仅识别要在运行时写入的文件类型(通过检查提供的文件路径的文件扩展名),它只想接受通道数据已经处于高位的图像精度类型(例如,Double),以防它确定最终格式可以处理高精度通道数据;您可能会争辩说,这种限制实际上并没有多大意义,但事实就是如此。

因此,正如@DanielWagner 指出的那样,您需要提供writeImage具有Double通道数据的图像。或者,您可以使用writeImageExactwhich 在编译时指定格式并允许将任何Writable实例用于适当的格式。因此,例如,将writeImage调用替换为:

writeImageExact PNG [] "image.png" image

本来可以正常工作的,因为它有一个合适的实例:

instance Writable (Image VS RGB Word8) PNG
于 2019-06-29T18:24:52.400 回答