除了DynamicImage
(example <- readImage "/filepath.png"
的结果(之外,我怎么能做类似的事情:
negative :: Image PixelRGBA8 -> Image PixelRGBA8
negative = pixelMap $ (PixelRGBA8 r g b a) -> PixelRGBA8 (255 - r) (255 - g) (255 - b) a
尽管有签名,但它是如何在没有任何争论的情况下工作的?我想这就是我所需要的,因为没有提供writeJpg
函数来处理Image
(而不是Dynamic(类型。我知道JuicyPixels提供的dynamicPixelMap
功能,但实际上我不知道如何使用它。如果有人能解释一下就好了。
UPD:我找到了简单的解决方案:
negative :: Image PixelRGBA8 -> Image PixelRGBA8
dynamicImage <- readImage filepath
let image = convertRGBA8 <$> dynamicImage
let modified = negative <$> image
case modified of
Left err -> print err
Right image -> saveJpgImage 100 outputFile $ ImageRGBA8 image
这是一个例子,我的代码更复杂。
让我们从DynamicImage
存在的原因开始。只要看一下定义就足以清楚地表明这一点:图像中的颜色数据有很多不同格式的。JuicyPixels提供的输入例程按照颜色数据存储在文件中的方式保留颜色数据。但是Image
类型将颜色数据格式放入该类型中。这是Haskell中的一个问题——如果您使函数具有多态性,则调用程序可以选择具体类型,而不是函数本身。没有办法说";这根据输入"返回一些Image
类型;。所以DynamicImage是存在的——它对每种支持的颜色数据格式都有不同的构造函数。构造函数上的匹配告诉你正在使用的Image
的类型,所以你不能在不知道它是什么类型的情况下获得数据
由于构造函数是公共的,您可以对它们进行匹配以获得Image
并在其上使用pixelMap
…但我不会。JPEG文件有时是CMYK空间,而不是RGB空间。这个空间中的逻辑是完全不同的——它是一个减法空间,而不是加法空间。JuicyPixels提供了一些工具来帮助您。convertRGBA8
函数获取DynamicImage
,并执行任何必要的颜色空间转换以获得Image PixelRBGA8
。在某些情况下,转换会丢失详细信息,但它会为您提供示例中的格式。