Twinside / Juicy.Pixels

Haskell library to load & save pictures

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Foldable and Traversable instances of Image, or specialized fold/traverse functions

sdroege opened this issue · comments

Hi,

it would be great if Image had Foldable or Traversable instances so one could fold over all pixels of an image for example. As the direction would have to be recorded there (line by line, or column by column) this would probably always do line by line.

So additionally it might make sense to also have specialized fold functions, or some kind of "view" newtype around Image that allows to fold/traverse by column instead of by line.

Maybe also specialized fold functions that don't just pass the component but also its position would be useful.

Currently one could do that on the contained Vector, but that's not so convenient as it would iterate over the words for the components instead of complete pixels.

If there's some interest in this and there's a consent on how the API should look like, I can write a patch.

Well there already is:

While reading your ticket, I thought that I could implement a Foldable instance, but sadly, not, the best shot is:

imageFoldMap :: forall m px. (Pixel px, Monoid m) => (px -> m) -> Image px -> m
imageFoldMap f Image { imageWidth = w, imageHeight = h, imageData = vec } = folder 0
  where
    compCount = componentCount (undefined :: px)
    maxi = w * h * compCount

    folder idx | idx >= maxi = mempty
    folder idx = f (unsafePixelAt vec idx) <> folder (idx + compCount)

instance Foldable Image where
  foldMap = imageFoldMap -- error here missing Pixel constraint, sadly

A Traversable is also impossible because the Image type is not
a Functor due to the Pixel restriction on the output of the mapping function
(like in pixelMap), and this restriction cannot be easily lifted due
to the use of Storable vector.

Due to the strong constraint of the Pixel type class to let us store pixels efficiently, we cannot directly write general instances.

If you want to implement more helper functions, they would be greatly accepted as a pull request.

Thanks, not sure how I missed those functions. That's exactly what I needed, and implemented myself in the end :) Let's close this then

Just one question: why do you use unsafePixelAt for pixelFoldMap, but pixelAt for the others?

And thanks for adding pixelFoldMap!

I may have implemented them in a hurry, thanks for spotting this, it will make a nice little performance enhancement