packages feed

cairo-image-0.1.0.0: src/Data/CairoImage/Internal.hs

{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE BlockArguments, LambdaCase #-}
{-# LANGUAGE TypeApplications, PatternSynonyms, ViewPatterns #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}

module Data.CairoImage.Internal (
	-- * Class Image and ImageMut
	Image(..), ImageMut(..),
	-- * Type CairoImage and CairoImageMut
	CairoImage(..), CairoImageMut(..), cairoImageFreeze, cairoImageThaw,
	-- * Image Format
	-- ** ARGB 32
	PixelArgb32(..),
	pattern PixelArgb32Premultiplied, pixelArgb32Premultiplied,
	pattern PixelArgb32Straight,
	pattern CairoImageArgb32, Argb32,
	pattern CairoImageMutArgb32, Argb32Mut,
	-- ** RGB 24
	PixelRgb24(..), pattern PixelRgb24,
	pattern CairoImageRgb24, Rgb24,
	pattern CairoImageMutRgb24, Rgb24Mut,
	-- ** A 8
	PixelA8(..),
	pattern CairoImageA8, A8,
	pattern CairoImageMutA8, A8Mut,
	-- ** A 1
	PixelA1(..), Bit(..), bit,
	pattern CairoImageA1, A1,
	pattern CairoImageMutA1, A1Mut,
	-- ** RGB 16 565
	PixelRgb16_565(..), pattern PixelRgb16_565,
	pattern CairoImageRgb16_565, Rgb16_565,
	pattern CairoImageMutRgb16_565, Rgb16_565Mut,
	-- ** RGB 30
	PixelRgb30(..), pattern PixelRgb30,
	pattern CairoImageRgb30, Rgb30,
	pattern CairoImageMutRgb30, Rgb30Mut,

	-- * CairoFormatT
	CairoFormatT(..),
	pattern CairoFormatArgb32, pattern CairoFormatRgb24,
	pattern CairoFormatA8, pattern CairoFormatA1,
	pattern CairoFormatRgb16_565, pattern CairoFormatRgb30 ) where

import Foreign.Ptr (Ptr, castPtr, plusPtr)
import Foreign.ForeignPtr (ForeignPtr, castForeignPtr)
import Foreign.Concurrent (newForeignPtr)
import Foreign.Marshal (mallocBytes, free, copyBytes)
import Foreign.Storable (Storable, peek, poke)
import Foreign.C.Types (CInt(..), CUChar)
import Control.Monad.Primitive (
	PrimMonad(..), PrimBase, unsafeIOToPrim, unsafePrimToIO )
import Control.Monad.ST (runST)
import Data.Foldable (for_)
import Data.List (foldl1')
import Data.Bool (bool)
import Data.Bits ((.|.), testBit, clearBit, setBit, shiftL, shiftR)
import Data.Word (Word8, Word16, Word32)
import Data.CairoImage.Parts
import System.IO.Unsafe (unsafePerformIO)
import System.TargetEndian (endian)

---------------------------------------------------------------------------

-- * CLASS IMAGE AND IMAGE MUTABLE
-- * TYPE CAIRO IMAGE AND CAIRO IMAGE MUTABLE
-- * ARGB 32
--	+ PIXEL
--	+ IMAGE
--	+ IMAGE MUTABLE
-- * RGB 24
--	+ PIXEL
--	+ IMAGE
--	+ IMAGE MUTABLE
-- * A 8
--	+ PIXEL
--	+ IMAGE
--	+ IMAGE MUTABLE
-- * A 1
--	+ PIXEL
--	+ IMAGE
--	+ IMAGE MUTABLE
-- * RGB 16 565
--	+ PIXEL
--	+ IMAGE
--	+ IMAGE MUTABLE
-- * RGB 30
--	+ PIXEL
--	+ IMAGE
--	+ IMAGE MUTABLE
-- * COMMON

---------------------------------------------------------------------------
-- CLASS IMAGE AND IMAGE MUTABLE
---------------------------------------------------------------------------

class Image i where
	type Pixel i
	imageSize :: i -> (CInt, CInt)
	pixelAt :: i -> CInt -> CInt -> Maybe (Pixel i)
	generateImage :: CInt -> CInt -> (CInt -> CInt -> Pixel i) -> i
	generateImagePrimM :: PrimBase m =>
		CInt -> CInt -> (CInt -> CInt -> m (Pixel i)) -> m i

	generateImage w h f =
		runST $ generateImagePrimM w h \x y -> pure $ f x y

class ImageMut im where
	type PixelMut im
	imageMutSize :: im s -> (CInt, CInt)
	getPixel :: PrimMonad m =>
		im (PrimState m) -> CInt -> CInt -> m (Maybe (PixelMut im))
	putPixel :: PrimMonad m =>
		im (PrimState m) -> CInt -> CInt -> PixelMut im -> m ()
	newImageMut :: PrimMonad m => CInt -> CInt -> m (im (PrimState m))

---------------------------------------------------------------------------
-- TYPE CAIRO IMAGE AND CAIRO IMAGE MUTABLE
---------------------------------------------------------------------------

data CairoImage = CairoImage {
	cairoImageFormat :: CairoFormatT,
	cairoImageWidth :: CInt, cairoImageHeight :: CInt,
	cairoImageStride :: CInt, cairoImageData :: ForeignPtr CUChar }
	deriving Show

instance Eq CairoImage where
	ci1 == ci2 = and [
		fmt1 == fmt2, w1 == w2, h1 == h2, str1 == str2,
		unsafePerformIO $ with fd1 \d1 -> with fd2 \d2 ->
			(EQ ==) <$> compareBytes d1 d2 (str1 * h1) ]
		where
		[fmt1, fmt2] = cairoImageFormat <$> [ci1, ci2]
		[w1, w2] = cairoImageWidth <$> [ci1, ci2]
		[h1, h2] = cairoImageHeight <$> [ci1, ci2]
		[str1, str2] = cairoImageStride <$> [ci1, ci2]
		[fd1, fd2] = cairoImageData <$> [ci1, ci2]

compareBytes :: (Ord n, Num n) => Ptr a -> Ptr a -> n -> IO Ordering
compareBytes _ _ n | n < 1 = pure EQ
compareBytes p1 p2 _ | p1 == p2 = pure EQ
compareBytes p1 p2 n = compare <$> peek pb1 <*> peek pb2 >>= \case
	EQ -> compareBytes p1 p2 (n - 1); o -> pure o
	where [pb1, pb2] = castPtr <$> [p1, p2] :: [Ptr Word8]

data CairoImageMut s = CairoImageMut {
	cairoImageMutFormat :: CairoFormatT,
	cairoImageMutWidth :: CInt, cairoImageMutHeight :: CInt,
	cairoImageMutStride :: CInt, cairoImageMutData :: ForeignPtr CUChar }
	deriving Show

cairoImageFreeze :: PrimMonad m => CairoImageMut (PrimState m) -> m CairoImage
cairoImageFreeze im = unsafeIOToPrim $ CairoImage f w h st <$> cidClone st h dt
	where
	f = cairoImageMutFormat im
	w = cairoImageMutWidth im; h = cairoImageMutHeight im
	st = cairoImageMutStride im; dt = cairoImageMutData im

cairoImageThaw :: PrimMonad m => CairoImage -> m (CairoImageMut (PrimState m))
cairoImageThaw i = unsafeIOToPrim $ CairoImageMut f w h st <$> cidClone st h dt
	where
	f = cairoImageFormat i
	w = cairoImageWidth i; h = cairoImageHeight i
	st = cairoImageStride i; dt = cairoImageData i

cidClone :: CInt -> CInt -> ForeignPtr CUChar -> IO (ForeignPtr CUChar)
cidClone st h fd = with fd \d -> mallocBytes n >>= \d' ->
	copyBytes d' d n >> newForeignPtr d' (free d')
	where n = fromIntegral $ st * h

---------------------------------------------------------------------------
-- ARGB 32
---------------------------------------------------------------------------

-- PIXEL

newtype PixelArgb32 = PixelArgb32Word32 Word32 deriving (Show, Storable)

{-# COMPLETE PixelArgb32Premultiplied #-}

pattern PixelArgb32Premultiplied ::
	Word8 -> Word8 -> Word8 -> Word8 -> PixelArgb32
pattern PixelArgb32Premultiplied a r g b <- (pixelArgb32ToArgb -> (a, r, g, b))

pixelArgb32Premultiplied ::
	Word8 -> Word8 -> Word8 -> Word8 -> Maybe PixelArgb32
pixelArgb32Premultiplied a r g b
	| r <= a, g <= a, b <= a = Just $ pixelArgb32FromArgb a r g b
	| otherwise = Nothing

pixelArgb32FromArgb :: Word8 -> Word8 -> Word8 -> Word8 -> PixelArgb32
pixelArgb32FromArgb
	(fromIntegral -> a) (fromIntegral -> r)
	(fromIntegral -> g) (fromIntegral -> b) = PixelArgb32Word32
	. foldl1' (.|.) $ zipWith shiftL [a, r, g, b] [24, 16, 8, 0]

pixelArgb32ToArgb :: PixelArgb32 -> (Word8, Word8, Word8, Word8)
pixelArgb32ToArgb (PixelArgb32Word32 w) = (
	fromIntegral $ w `shiftR` 24, fromIntegral $ w `shiftR` 16,
	fromIntegral $ w `shiftR` 8, fromIntegral w )

{-# COMPLETE PixelArgb32Straight #-}

pattern PixelArgb32Straight :: Word8 -> Word8 -> Word8 -> Word8 -> PixelArgb32
pattern PixelArgb32Straight a r g b <- (pixelArgb32ToArgbSt -> (a, r, g, b))
	where PixelArgb32Straight a r g b = pixelArgb32FromArgb
		a (r `unit` (a, 0xff)) (g `unit` (a, 0xff)) (b `unit` (a, 0xff))

pixelArgb32ToArgbSt :: PixelArgb32 -> (Word8, Word8, Word8, Word8)
pixelArgb32ToArgbSt p = let (a, r, g, b) = pixelArgb32ToArgb p in
	(a, r `unit` (0xff, a), g `unit` (0xff, a), b `unit` (0xff, a))

unit :: Word8 -> (Word8, Word8) -> Word8
(fromIntegral -> n) `unit` ((fromIntegral -> m), (fromIntegral -> d)) =
	fromIntegral @Word16 $ n * m `div'` d

infixl 7 `div'`

div' :: Integral n => n -> n -> n
div' n = \case 0 -> 0; m -> n `div` m

-- IMAGE

data Argb32 = Argb32 {
	argb32Width :: CInt, argb32Height :: CInt,
	argb32Stride :: CInt, argb32Data :: ForeignPtr PixelArgb32 }
	deriving Show

pattern CairoImageArgb32 :: Argb32 -> CairoImage
pattern CairoImageArgb32 a <- (cairoImageToArgb32 -> Just a) where
	CairoImageArgb32 (Argb32 w h s d) =
		CairoImage CairoFormatArgb32 w h s $ castForeignPtr d

cairoImageToArgb32 :: CairoImage -> Maybe Argb32
cairoImageToArgb32 = \case
	CairoImage CairoFormatArgb32 w h s d ->
		Just . Argb32 w h s $ castForeignPtr d
	_ -> Nothing

instance Image Argb32 where
	type Pixel Argb32 = PixelArgb32
	imageSize (Argb32 w h _ _) = (w, h)
	pixelAt (Argb32 w h s d) x y = unsafePerformIO $ with d \p ->
		maybe (pure Nothing) ((Just <$>) . peek) $ ptr w h s p x y
	generateImagePrimM w h f = stride CairoFormatArgb32 w >>= \s ->
		Argb32 w h s <$> gen w h s f

-- IMAGE MUTABLE

data Argb32Mut s = Argb32Mut {
	argb32MutWidth :: CInt, argb32MutHeight :: CInt,
	argb32MutStride :: CInt, argb32MutData :: ForeignPtr PixelArgb32 }
	deriving Show

pattern CairoImageMutArgb32 :: Argb32Mut s -> CairoImageMut s
pattern CairoImageMutArgb32 a <- (cairoImageMutToArgb32 -> Just a) where
	CairoImageMutArgb32 (Argb32Mut w h s d) =
		CairoImageMut CairoFormatArgb32 w h s $ castForeignPtr d

cairoImageMutToArgb32 :: CairoImageMut s -> Maybe (Argb32Mut s)
cairoImageMutToArgb32 = \case
	CairoImageMut CairoFormatArgb32 w h s d ->
		Just . Argb32Mut w h s $ castForeignPtr d
	_ -> Nothing

instance ImageMut Argb32Mut where
	type PixelMut Argb32Mut = PixelArgb32
	imageMutSize (Argb32Mut w h _ _) = (w, h)
	getPixel (Argb32Mut w h s d) x y = unsafeIOToPrim $ with d \p ->
		maybe (pure Nothing) ((Just <$>) . peek) $ ptr w h s p x y
	putPixel (Argb32Mut w h s d) x y px = unsafeIOToPrim $ with d \p ->
		maybe (pure ()) (`poke` px) $ ptr w h s p x y
	newImageMut w h =
		stride CairoFormatArgb32 w >>= \s -> Argb32Mut w h s <$> new s h

---------------------------------------------------------------------------
-- RGB 24
---------------------------------------------------------------------------

-- PIXEL

newtype PixelRgb24 = PixelRgb24Word32 Word32 deriving (Show, Storable)

{-# COMPLETE PixelRgb24 #-}

pattern PixelRgb24 :: Word8 -> Word8 -> Word8 -> PixelRgb24
pattern PixelRgb24 r g b <- (pixelRgb24ToRgb -> (r, g, b)) where
	PixelRgb24 (fromIntegral -> r) (fromIntegral -> g) (fromIntegral -> b) =
		PixelRgb24Word32
			. foldl1' (.|.) $ zipWith shiftL [r, g, b] [16, 8, 0]

pixelRgb24ToRgb :: PixelRgb24 -> (Word8, Word8, Word8)
pixelRgb24ToRgb (PixelRgb24Word32 w) = (
	fromIntegral $ w `shiftR` 16,
	fromIntegral $ w `shiftR` 8, fromIntegral w )

-- IMAGE

data Rgb24 = Rgb24 {
	rgb24Width :: CInt, rgb24Height :: CInt,
	rgb24Stride :: CInt, rgb24Data :: ForeignPtr PixelRgb24 }
	deriving Show

pattern CairoImageRgb24 :: Rgb24 -> CairoImage
pattern CairoImageRgb24 r <- (cairoImageToRgb24 -> Just r) where
	CairoImageRgb24 (Rgb24 w h s d) =
		CairoImage CairoFormatRgb24 w h s $ castForeignPtr d

cairoImageToRgb24 :: CairoImage -> Maybe Rgb24
cairoImageToRgb24 = \case
	CairoImage CairoFormatRgb24 w h s d ->
		Just . Rgb24 w h s $ castForeignPtr d
	_ -> Nothing

instance Image Rgb24 where
	type Pixel Rgb24 = PixelRgb24
	imageSize (Rgb24 w h _ _) = (w, h)
	pixelAt (Rgb24 w h s d) x y = unsafePerformIO $ with d \p ->
		maybe (pure Nothing) ((Just <$>) . peek) $ ptr w h s p x y
	generateImagePrimM w h f =
		stride CairoFormatRgb24 w >>= \s -> Rgb24 w h s <$> gen w h s f

-- IMAGE MUTABLE

data Rgb24Mut s = Rgb24Mut {
	rgb24MutWidth :: CInt, rgb24MutHeight :: CInt,
	rgb24MutStride :: CInt, rgb24MutData :: ForeignPtr PixelRgb24 }
	deriving Show

pattern CairoImageMutRgb24 :: Rgb24Mut s -> CairoImageMut s
pattern CairoImageMutRgb24 r <- (cairoImageMutToRgb24 -> Just r) where
	CairoImageMutRgb24 (Rgb24Mut w h s d) =
		CairoImageMut CairoFormatRgb24 w h s $ castForeignPtr d

cairoImageMutToRgb24 :: CairoImageMut s -> Maybe (Rgb24Mut s)
cairoImageMutToRgb24 = \case
	CairoImageMut CairoFormatRgb24 w h s d ->
		Just . Rgb24Mut w h s $ castForeignPtr d
	_ -> Nothing

instance ImageMut Rgb24Mut where
	type PixelMut Rgb24Mut = PixelRgb24
	imageMutSize (Rgb24Mut w h _ _) = (w, h)
	getPixel (Rgb24Mut w h s d) x y = unsafeIOToPrim $ with d \p ->
		maybe (pure Nothing) ((Just <$>) . peek) $ ptr w h s p x y
	putPixel (Rgb24Mut w h s d) x y px = unsafeIOToPrim $ with d \p ->
		maybe (pure ()) (`poke` px) $ ptr w h s p x y
	newImageMut w h =
		stride CairoFormatRgb24 w >>= \s -> Rgb24Mut w h s <$> new s h

---------------------------------------------------------------------------
-- A 8
---------------------------------------------------------------------------

-- PIXEL

newtype PixelA8 = PixelA8 Word8 deriving (Show, Storable)

-- IMAGE

data A8 = A8 {
	a8Width :: CInt, a8Height :: CInt,
	a8Stride :: CInt, a8Data :: ForeignPtr PixelA8 }
	deriving Show

pattern CairoImageA8 :: A8 -> CairoImage
pattern CairoImageA8 a <- (cairoImageToA8 -> Just a)
	where CairoImageA8 (A8 w h s d) =
		CairoImage CairoFormatA8 w h s $ castForeignPtr d

cairoImageToA8 :: CairoImage -> Maybe A8
cairoImageToA8 = \case
	CairoImage CairoFormatA8 w h s d -> Just . A8 w h s $ castForeignPtr d
	_ -> Nothing

instance Image A8 where
	type Pixel A8 = PixelA8
	imageSize (A8 w h _ _) = (w, h)
	pixelAt (A8 w h s d) x y = unsafePerformIO $ with d \p ->
		maybe (pure Nothing) ((Just <$>) . peek) $ ptr w h s p x y
	generateImagePrimM w h f =
		stride CairoFormatA8 w >>= \s -> A8 w h s <$> gen w h s f

-- IMAGE MUTABLE

data A8Mut s = A8Mut {
	a8MutWidth :: CInt, a8MutHeight :: CInt,
	a8MutStride :: CInt, a8MutData :: ForeignPtr PixelA8 }
	deriving Show

pattern CairoImageMutA8 :: A8Mut s -> CairoImageMut s
pattern CairoImageMutA8 a <- (cairoImageMutToA8 -> Just a)
	where CairoImageMutA8 (A8Mut w h s d) =
		CairoImageMut CairoFormatA8 w h s $ castForeignPtr d

cairoImageMutToA8 :: CairoImageMut s -> Maybe (A8Mut s)
cairoImageMutToA8 = \case
	CairoImageMut CairoFormatA8 w h s d ->
		Just . A8Mut w h s $ castForeignPtr d
	_ -> Nothing

instance ImageMut A8Mut where
	type PixelMut A8Mut = PixelA8
	imageMutSize (A8Mut w h _ _) = (w, h)
	getPixel (A8Mut w h s d) x y = unsafeIOToPrim $ with d \p ->
		maybe (pure Nothing) ((Just <$>) . peek) $ ptr w h s p x y
	putPixel (A8Mut w h s d) x y px = unsafeIOToPrim $ with d \p ->
		maybe (pure ()) (`poke` px) $ ptr w h s p x y
	newImageMut w h =
		stride CairoFormatA8 w >>= \s -> A8Mut w h s <$> new s h

---------------------------------------------------------------------------
-- A 1
---------------------------------------------------------------------------

-- PIXEL

newtype PixelA1 = PixelA1 Bit deriving Show

data Bit = O | I deriving (Show, Enum)

bit :: a -> a -> Bit -> a
bit x y = \case O -> x; I -> y

ptrA1 :: CInt -> CInt -> CInt ->
	Ptr PixelA1 -> CInt -> CInt -> Maybe (Ptr PixelA1, CInt)
ptrA1 w h s p x y
	| 0 <= x && x < w && 0 <= y && y < h = Just
		(p `plusPtr` fromIntegral (y * s + x `div` 32 * 4), x `mod` 32)
	| otherwise = Nothing

peA1 :: (Ptr PixelA1, CInt) -> IO PixelA1
peA1 ((castPtr -> p), (fromIntegral . $(endian [e| id |] [e| (31 -) |]) -> i)) =
	PixelA1 . bool O I . (`testBit` i) <$> peek @Word32 p

poA1 :: (Ptr PixelA1, CInt) -> PixelA1 -> IO ()
poA1 ((castPtr -> p), (fromIntegral . $(endian [e| id |] [e| (31 -) |]) -> i))
	(PixelA1 b) = poke p . flip (bit clearBit setBit b) i =<< peek @Word32 p

-- IMAGE

data A1 = A1 {
	a1Width :: CInt, a1Height :: CInt,
	a1Stride :: CInt, a1Data :: ForeignPtr PixelA1 }
	deriving Show

pattern CairoImageA1 :: A1 -> CairoImage
pattern CairoImageA1 a <- (cairoImageToA1 -> Just a)
	where CairoImageA1 (A1 w h s d) =
		CairoImage CairoFormatA1 w h s $ castForeignPtr d

cairoImageToA1 :: CairoImage -> Maybe A1
cairoImageToA1 = \case
	CairoImage CairoFormatA1 w h s d -> Just . A1 w h s $ castForeignPtr d
	_ -> Nothing

instance Image A1 where
	type Pixel A1 = PixelA1
	imageSize (A1 w h _ _) = (w, h)
	pixelAt (A1 w h s d) x y = unsafePerformIO $ with d \p ->
		maybe (pure Nothing) ((Just <$>) . peA1) $ ptrA1 w h s p x y
	generateImagePrimM = genA1

genA1 :: PrimBase m => CInt -> CInt -> (CInt -> CInt -> m PixelA1) -> m A1
genA1 w h f = unsafeIOToPrim $ stride CairoFormatA1 w >>= \s -> do
	d <- mallocBytes . fromIntegral $ s * h
	for_ [0 .. h - 1] \y -> for_ [0 .. w - 1] \x ->
		unsafePrimToIO (f x y) >>= \px ->
			maybe (pure ()) (`poA1` px) $ ptrA1 w h s d x y
	A1 w h s <$> newForeignPtr d (free d)

-- IMAGE MUTABLE

data A1Mut s = A1Mut {
	a1MutWidth :: CInt, a1MutHeight :: CInt,
	a1MutStride :: CInt, a1MutData :: ForeignPtr PixelA1 }
	deriving Show

pattern CairoImageMutA1 :: A1Mut s -> CairoImageMut s
pattern CairoImageMutA1 a <- (cairoImageMutToA1 -> Just a)
	where CairoImageMutA1 (A1Mut w h s d) =
		CairoImageMut CairoFormatA1 w h s $ castForeignPtr d

cairoImageMutToA1 :: CairoImageMut s -> Maybe (A1Mut s)
cairoImageMutToA1 = \case
	CairoImageMut CairoFormatA1 w h s d ->
		Just . A1Mut w h s $ castForeignPtr d
	_ -> Nothing

instance ImageMut A1Mut where
	type PixelMut A1Mut = PixelA1
	imageMutSize (A1Mut w h _ _) = (w, h)
	getPixel (A1Mut w h s d) x y = unsafeIOToPrim $ with d \p ->
		maybe (pure Nothing) ((Just <$>) . peA1) $ ptrA1 w h s p x y
	putPixel (A1Mut w h s d) x y px = unsafeIOToPrim $ with d \p ->
		maybe (pure ()) (`poA1` px) $ ptrA1 w h s p x y
	newImageMut w h =
		stride CairoFormatA1 w >>= \s -> A1Mut w h s <$> new s h

---------------------------------------------------------------------------
-- RGB 16 565
---------------------------------------------------------------------------

-- PIXEL

newtype PixelRgb16_565 = PixelRgb16_565Word16 Word16 deriving (Show, Storable)

{-# COMPLETE PixelRgb16_565 #-}

pattern PixelRgb16_565 :: Word8 -> Word8 -> Word8 -> PixelRgb16_565
pattern PixelRgb16_565 r g b <- (pixelRgb16_565ToRgb -> (r, g, b))
	where PixelRgb16_565
		(fromIntegral -> r) (fromIntegral -> g) (fromIntegral -> b) =
		PixelRgb16_565Word16 $ r' .|. g' .|. b'
		where
		r' = r `shiftR` 3 `shiftL` 11
		g' = g `shiftR` 2 `shiftL` 5
		b' = b `shiftR` 3

pixelRgb16_565ToRgb :: PixelRgb16_565 -> (Word8, Word8, Word8)
pixelRgb16_565ToRgb (PixelRgb16_565Word16 rgb) =
	(r .|. r `shiftR` 5, g .|. g `shiftR` 6, b .|. b `shiftR` 5)
	where
	r = fromIntegral $ rgb `shiftR` 11 `shiftL` 3
	g = fromIntegral $ rgb `shiftR` 5 `shiftL` 2
	b = fromIntegral $ rgb `shiftL` 3

-- IMAGE

data Rgb16_565 = Rgb16_565 {
	rgb16_565Width :: CInt, rgb16_565Height :: CInt,
	rgb16_565Stride :: CInt, rgb16_565Data :: ForeignPtr PixelRgb16_565 }
	deriving Show

pattern CairoImageRgb16_565 :: Rgb16_565 -> CairoImage
pattern CairoImageRgb16_565 r <- (cairoImageToRgb16_565 -> Just r)
	where CairoImageRgb16_565 (Rgb16_565 w h s d) =
		CairoImage CairoFormatRgb16_565 w h s $ castForeignPtr d

cairoImageToRgb16_565 :: CairoImage -> Maybe Rgb16_565
cairoImageToRgb16_565 = \case
	CairoImage CairoFormatRgb16_565 w h s d ->
		Just . Rgb16_565 w h s $ castForeignPtr d
	_ -> Nothing

instance Image Rgb16_565 where
	type Pixel Rgb16_565 = PixelRgb16_565
	imageSize (Rgb16_565 w h _ _) = (w, h)
	pixelAt (Rgb16_565 w h s d) x y = unsafePerformIO $ with d \p ->
		maybe (pure Nothing) ((Just <$>) . peek) $ ptr w h s p x y
	generateImagePrimM w h f = stride CairoFormatRgb16_565 w >>= \s ->
		Rgb16_565 w h s <$> gen w h s f

-- IMAGE MUTABLE

data Rgb16_565Mut s = Rgb16_565Mut {
	rgb16_565MutWidth :: CInt, rgb16_565MutHeight :: CInt,
	rgb16_565MutStride :: CInt,
	rgb16_565MutData :: ForeignPtr PixelRgb16_565 }
	deriving Show

pattern CairoImageMutRgb16_565 :: Rgb16_565Mut s -> CairoImageMut s
pattern CairoImageMutRgb16_565 r <- (cairoImageMutToRgb16_565 -> Just r)
	where CairoImageMutRgb16_565 (Rgb16_565Mut w h s d) =
		CairoImageMut CairoFormatRgb16_565 w h s $ castForeignPtr d

cairoImageMutToRgb16_565 :: CairoImageMut s -> Maybe (Rgb16_565Mut s)
cairoImageMutToRgb16_565 = \case
	CairoImageMut CairoFormatRgb16_565 w h s d ->
		Just . Rgb16_565Mut w h s $ castForeignPtr d
	_ -> Nothing

instance ImageMut Rgb16_565Mut where
	type PixelMut Rgb16_565Mut = PixelRgb16_565
	imageMutSize (Rgb16_565Mut w h _ _) = (w, h)
	getPixel (Rgb16_565Mut w h s d) x y = unsafeIOToPrim $ with d \p ->
		maybe (pure Nothing) ((Just <$>) . peek) $ ptr w h s p x y
	putPixel (Rgb16_565Mut w h s d) x y px = unsafeIOToPrim $ with d \p ->
		maybe (pure ()) (`poke` px) $ ptr w h s p x y
	newImageMut w h = stride CairoFormatRgb16_565 w >>= \s ->
		Rgb16_565Mut w h s <$> new s h

---------------------------------------------------------------------------
-- RGB 30
---------------------------------------------------------------------------

-- PIXEL

newtype PixelRgb30 = PixelRgb30Word32 Word32 deriving (Show, Storable)

{-# COMPLETE PixelRgb30 #-}

pattern PixelRgb30 :: Word16 -> Word16 -> Word16 -> PixelRgb30
pattern PixelRgb30 r g b <- (pixelRgb30ToRgb -> (r, g, b)) where
	PixelRgb30 (fromIntegral -> r) (fromIntegral -> g) (fromIntegral -> b) =
		PixelRgb30Word32 $ r' .|. g' .|. b'
		where
		r' = r `shiftR` 6 `shiftL` 20
		g' = g `shiftR` 6 `shiftL` 10
		b' = b `shiftR` 6

pixelRgb30ToRgb :: PixelRgb30 -> (Word16, Word16, Word16)
pixelRgb30ToRgb (PixelRgb30Word32 rgb) =
	(r .|. r `shiftR` 10, g .|. g `shiftR` 10, b .|. b `shiftR` 10)
	where
	r = fromIntegral $ rgb `shiftR` 20 `shiftL` 6
	g = fromIntegral $ rgb `shiftR` 10 `shiftL` 6
	b = fromIntegral $ rgb `shiftL` 6

-- IMAGE

data Rgb30 = Rgb30 {
	rgb30Width :: CInt, rgb30Height :: CInt,
	rgb30Stride :: CInt, rgb30Data :: ForeignPtr PixelRgb30 }
	deriving Show

pattern CairoImageRgb30 :: Rgb30 -> CairoImage
pattern CairoImageRgb30 r <- (cairoImageToRgb30 -> Just r)
	where CairoImageRgb30 (Rgb30 w h s d) =
		CairoImage CairoFormatRgb30 w h s $ castForeignPtr d

cairoImageToRgb30 :: CairoImage -> Maybe Rgb30
cairoImageToRgb30 = \case
	CairoImage CairoFormatRgb30 w h s d ->
		Just . Rgb30 w h s $ castForeignPtr d
	_ -> Nothing

instance Image Rgb30 where
	type Pixel Rgb30 = PixelRgb30
	imageSize (Rgb30 w h _ _) = (w, h)
	pixelAt (Rgb30 w h s d) x y = unsafePerformIO $ with d \p ->
		maybe (pure Nothing) ((Just <$>) . peek) $ ptr w h s p x y
	generateImagePrimM w h f =
		stride CairoFormatRgb30 w >>= \s -> Rgb30 w h s <$> gen w h s f

-- IMAGE MUTABLE

data Rgb30Mut s = Rgb30Mut {
	rgb30MutWidth :: CInt, rgb30MutHeight :: CInt,
	rgb30MutStride :: CInt, rgb30MutData :: ForeignPtr PixelRgb30 }
	deriving Show

pattern CairoImageMutRgb30 :: Rgb30Mut s -> CairoImageMut s
pattern CairoImageMutRgb30 r <- (cairoImageMutToRgb30 -> Just r)
	where CairoImageMutRgb30 (Rgb30Mut w h s d) =
		CairoImageMut CairoFormatRgb30 w h s $ castForeignPtr d

cairoImageMutToRgb30 :: CairoImageMut s -> Maybe (Rgb30Mut s)
cairoImageMutToRgb30 = \case
	CairoImageMut CairoFormatRgb30 w h s d ->
		Just . Rgb30Mut w h s $ castForeignPtr d
	_ -> Nothing

instance ImageMut Rgb30Mut where
	type PixelMut Rgb30Mut = PixelRgb30
	imageMutSize (Rgb30Mut w h _ _) = (w, h)
	getPixel (Rgb30Mut w h s d) x y = unsafeIOToPrim $ with d \p ->
		maybe (pure Nothing) ((Just <$>) . peek) $ ptr w h s p x y
	putPixel (Rgb30Mut w h s d) x y px = unsafeIOToPrim $ with d \p ->
		maybe (pure ()) (`poke` px) $ ptr w h s p x y
	newImageMut w h =
		stride CairoFormatRgb30 w >>= \s -> Rgb30Mut w h s <$> new s h