module Codec.Picture.Blp.Internal.Convert(
    toPngRepresentable
  , toBlpUncompressable
  , toBlpCMYK8
  ) where

import Codec.Picture
import Codec.Picture.Types
import Data.Word

toPngRepresentable :: DynamicImage -> DynamicImage
toPngRepresentable i = case i of
  ImageY8 _ -> i
  ImageY16 _ -> i
  ImageYF p -> ImageRGB16 . convertFloatImage16 . promoteImage $ p
  ImageYA8 _ -> i
  ImageYA16 _ -> i
  ImageRGB8 _ -> i
  ImageRGB16 _ -> i
  ImageRGBF p -> ImageRGB16 . convertFloatImage16 $ p
  ImageRGBA8 _ -> i
  ImageRGBA16 _ -> i
  ImageYCbCr8 p -> ImageRGB8 . convertImage $ p
  ImageCMYK8 p -> ImageRGBA8 . convertCMYK8Image $ p
  ImageCMYK16 p -> ImageRGBA16 . convertCMYK16Image $ p

toBlpUncompressable :: DynamicImage -> Image PixelRGBA8
toBlpUncompressable i = case i of
  ImageY8 p -> toBlpRGB8 (promoteImage p :: Image PixelRGB8)
  ImageY16 p -> toBlpRGB8 (dropBits (promoteImage p :: Image PixelRGB16) :: Image PixelRGB8)
  ImageYF p -> toBlpRGB8 (convertFloatImage8 (promoteImage p :: Image PixelRGBF) :: Image PixelRGB8)
  ImageYA8 p -> toBlpRGBA8 (promoteImage p :: Image PixelRGBA8)
  ImageYA16 p -> toBlpRGBA8 (dropBitsA (promoteImage p :: Image PixelRGBA16) :: Image PixelRGBA8)
  ImageRGB8 p -> toBlpRGB8 p
  ImageRGB16 p -> toBlpRGB8 (dropBits p :: Image PixelRGB8)
  ImageRGBF p -> toBlpRGB8 (convertFloatImage8 p :: Image PixelRGB8)
  ImageRGBA8 p -> toBlpRGBA8 p
  ImageRGBA16 p -> toBlpRGBA8 (dropBitsA p :: Image PixelRGBA8)
  ImageYCbCr8 p -> toBlpRGB8 (convertImage p :: Image PixelRGB8)
  ImageCMYK8 p -> toBlpRGB8 (convertImage p :: Image PixelRGB8)
  ImageCMYK16 p -> toBlpRGB8 (dropBits (convertImage p :: Image PixelRGB16) :: Image PixelRGB8)

dropBits :: Image PixelRGB16 -> Image PixelRGB8
dropBits = pixelMap $ \(PixelRGB16 r g b) -> PixelRGB8 (f r) (f g) (f b)
  where
    f :: Word16 -> Word8
    f x = round $ 255 * (fromIntegral x :: Double) / 65535

dropBitsA :: Image PixelRGBA16 -> Image PixelRGBA8
dropBitsA = pixelMap $ \(PixelRGBA16 r g b a) -> PixelRGBA8 (f r) (f g) (f b) (f a)
  where
    f :: Word16 -> Word8
    f x = round $ 255 * (fromIntegral x :: Double) / 65535

convertFloatImage8 :: Image PixelRGBF -> Image PixelRGB8
convertFloatImage8 = pixelMap convert
  where
    convert (PixelRGBF rf gf bf) = PixelRGB8
      (round $ 255 * rf)
      (round $ 255 * gf)
      (round $ 255 * bf)

convertFloatImage16 :: Image PixelRGBF -> Image PixelRGB16
convertFloatImage16 = pixelMap convert
  where
    convert (PixelRGBF rf gf bf) = PixelRGB16
      (round $ 65535 * rf)
      (round $ 65535 * gf)
      (round $ 65535 * bf)

convertCMYK8Image :: Image PixelCMYK8 -> Image PixelRGBA8
convertCMYK8Image = pixelMap convert
  where
  clampWord8 = fromIntegral . max 0 . min 255 . (`div` 256)
  convert (PixelCMYK8 c m y k) =
      PixelRGBA8 (clampWord8 r) (clampWord8 g) (clampWord8 b) k
    where
    ik :: Int
    ik = fromIntegral k
    r = fromIntegral y * ik
    g = fromIntegral m * ik
    b = fromIntegral c * ik

toBlpCMYK8 :: Image PixelRGBA8 -> Image PixelCMYK8
toBlpCMYK8 = pixelMap convert
  where
  clampWord8 = fromIntegral . max 0 . min 255
  convert (PixelRGBA8 r g b a) = PixelCMYK8 (clampWord8 c) (clampWord8 m) (clampWord8 y) a
    where
    ik = fromIntegral a :: Double
    c, m, y :: Int
    c = round $ 256 * fromIntegral b / ik
    m = round $ 256 * fromIntegral g / ik
    y = round $ 256 * fromIntegral r / ik

toBlpRGBA8 :: Image PixelRGBA8 -> Image PixelRGBA8
toBlpRGBA8 = pixelMap convert
  where
  convert (PixelRGBA8 r g b a) = PixelRGBA8 b g r a

toBlpRGB8 :: Image PixelRGB8 -> Image PixelRGBA8
toBlpRGB8 = pixelMap convert
  where
  convert (PixelRGB8 r g b) = PixelRGBA8 b g r 0

convertCMYK16Image :: Image PixelCMYK16 -> Image PixelRGBA16
convertCMYK16Image = pixelMap convert
  where
  convert (PixelCMYK16 c m y k) =
      PixelRGBA16 (clampWord16 r) (clampWord16 g) (clampWord16 b) 65535
    where
    clampWord16 = fromIntegral . max 0 . min 65535 . (`div` 65535)

    ik :: Int
    ik = fromIntegral k
    r = fromIntegral y * ik
    g = fromIntegral m * ik
    b = fromIntegral c * ik