如何使用 JuicyPixels (Haskell) 编辑 DynamicImage 的像素?

How can I edit pixels of DynamicImage using JuicyPixels (Haskell)?

除了DynamicImageexample <- 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 (不是动态)类型一起使用。 我知道 JuicyPixels 提供的 dynamicPixelMap 功能,但我并不真正了解如何使用它。如果有人能解释一下就好了。

更新: 我找到了简单的 解决方案:

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 存在的原因。只要看一下定义就足以说明这一点:图像中的颜色数据有 lot 种不同的格式。 JuicyPixels 提供的输入例程保留了颜色数据在文件中的存储方式。但是 Image 类型将颜色数据格式放入类型中。这是 Haskell 中的一个问题 - 如果您将函数设为多态,则 调用者 会选择具体类型,而不是函数本身。没有办法说“this returns some Image type, depending on input”。所以 DynamicImage 存在 - 它对每种支持的颜色数据格式都有不同的构造函数。构造函数上的匹配会告诉您正在使用的 Image 的类型,因此您无法在不知道数据是什么类型的情况下获取数据。

由于构造函数是 public,您可以匹配它们以获得 Image 并在其上使用 pixelMap...但我不会。 JPEG 文件有时是 CMYK space,而不是 RGB。 space 的逻辑 完全 不同 - 它是减法 space,而不是加法。 JuicyPixels 提供了一些工具来帮助您。 convertRGBA8 函数采用 DynamicImage 并进行任何必要的颜色 space 转换以获得 Image PixelRBGA8。在某些情况下,转换会丢失详细信息,但它会为您提供您提供的示例中的格式。