Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How do I rotate a juicy pixel image at 180°

I’m trying to make snapshots of a opengl area in a haskell program using the glut library.

I found this snippet of code using the juicypixels library.

saveImage :: Window -> IO ()
saveImage window = do
  currentWindow $= Just window
  Size w h <- get windowSize
  let npixels = fromIntegral (w*h) :: Int
      nbytes  = 3*npixels
  fptr <- mallocForeignPtrArray nbytes :: IO (ForeignPtr Word8)
  withForeignPtr fptr $ \ptr -> do
    let pdata = PixelData RGB UnsignedByte ptr :: PixelData Word8
    readPixels (Position 0 0) (Size w h) pdata
  let fptr' = castForeignPtr fptr :: ForeignPtr (PixelBaseComponent PixelRGB8)
  let imgdata = unsafeFromForeignPtr0 fptr' npixels :: Vector (PixelBaseComponent PixelRGB8)
  let image = Image (fromIntegral w) (fromIntegral h) imgdata :: Image PixelRGB8
  writePng "test.png" image

This code is running well. Just a problem, it save the png image like this :

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

enter image description here

The image is rotated at 180°

So, I tried to rotate my image to get it in the right direction.

I found this function flipVertically and implemented it locally:

flipVertically :: Image PixelRGB8 -> Image PixelRGB8
flipVertically img@Image {..} =
  generateImage gen imageWidth imageHeight
  where
    gen x y = pixelAt img x (imageHeight - 1 - y)

When I use it

writePng "test.png" (rotate180 image)

My programm fail with the following error message

geometrix-cli_gl_snap: ./Data/Vector/Generic.hs:257 ((!)): index out of bounds (1079997,360000)
CallStack (from HasCallStack):
  error, called at ./Data/Vector/Internal/Check.hs:87:5 in vector-0.12.3.1-TXkE6leK98EdYcmdk29JF:Data.Vector.Internal.Check

It seems that it’s trying to access an index (1079997) out of my image (600*600=360000px).

as a juicypixels image is made with a vector, I tried to convert the vector to a list, reverse this list and reconvert it to a vector with the functions toList and fromList.

  let lst = (V.toList imgdata)
  let image = Image (fromIntegral w) (fromIntegral h) (V.fromList (reverse (lst))) :: Image PixelRGB8

the program is running but instead of my image in the right direction, I have this free style:

enter image description here

The top of the image seems to be correctly rotated, but the bottom is a non sense.

When I test the list length, I get 360000. So it contain the right amount of pixels for my image.

What did I do wrong in my function ?

How do I rotate a juicypixels image correctly ?

>Solution :

The culprit is where you convert the pointer into a Vector, you here make a Vector of essentially bytes with length npixels, whereas it should be nbytes, since PixelBaseComponent PixelRGB8 takes the byte size of one channel, indeed [Haskell-src]:

instance Pixel PixelRGB8 where
  type PixelBaseComponent PixelRGB8 = Word8
  -- …

It is possible that if you save an image, and it uses a pointer, that might still work, but the vector is here to essentially make sure you can not access data outside the bounds.

You thus should use:

saveImage :: Window -> IO ()
saveImage window = do
  currentWindow $= Just window
  Size w h <- get windowSize
  let npixels = fromIntegral (w * h) :: Int
      nbytes = 3 * npixels
  fptr <- mallocForeignPtrArray nbytes :: IO (ForeignPtr Word8)
  withForeignPtr fptr $ \ptr -> do
    let pdata = PixelData RGB UnsignedByte ptr :: PixelData Word8
    readPixels (Position 0 0) (Size w h) pdata
  let fptr' = castForeignPtr fptr :: ForeignPtr (PixelBaseComponent PixelRGB8)
  let imgdata = unsafeFromForeignPtr0 fptr' nbytes :: Vector (PixelBaseComponent PixelRGB8)
  let image = Image (fromIntegral w) (fromIntegral h) imgdata :: Image PixelRGB8
  writePng "test.png" (rotate180 image)
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading