Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package ghc-JuicyPixels for openSUSE:Factory 
checked in at 2024-06-14 19:02:31
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/ghc-JuicyPixels (Old)
 and      /work/SRC/openSUSE:Factory/.ghc-JuicyPixels.new.19518 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "ghc-JuicyPixels"

Fri Jun 14 19:02:31 2024 rev:36 rq:1180780 version:3.3.9

Changes:
--------
--- /work/SRC/openSUSE:Factory/ghc-JuicyPixels/ghc-JuicyPixels.changes  
2024-04-21 20:30:43.701512941 +0200
+++ 
/work/SRC/openSUSE:Factory/.ghc-JuicyPixels.new.19518/ghc-JuicyPixels.changes   
    2024-06-14 19:07:04.514397418 +0200
@@ -1,0 +2,9 @@
+Thu Jun  6 18:35:17 UTC 2024 - Peter Simons <psim...@suse.com>
+
+- Update JuicyPixels to version 3.3.9.
+  v3.3.9 June 2024
+  ----------------
+
+   * Something something compilation
+
+-------------------------------------------------------------------

Old:
----
  JuicyPixels-3.3.8.tar.gz
  JuicyPixels.cabal

New:
----
  JuicyPixels-3.3.9.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ ghc-JuicyPixels.spec ++++++
--- /var/tmp/diff_new_pack.vGXGfq/_old  2024-06-14 19:07:05.022415557 +0200
+++ /var/tmp/diff_new_pack.vGXGfq/_new  2024-06-14 19:07:05.026415701 +0200
@@ -19,13 +19,12 @@
 %global pkg_name JuicyPixels
 %global pkgver %{pkg_name}-%{version}
 Name:           ghc-%{pkg_name}
-Version:        3.3.8
+Version:        3.3.9
 Release:        0
 Summary:        Picture loading/serialization (in png, jpeg, bitmap, gif, tga, 
tiff and radiance)
 License:        BSD-3-Clause
 URL:            https://hackage.haskell.org/package/%{pkg_name}
 Source0:        
https://hackage.haskell.org/package/%{pkg_name}-%{version}/%{pkg_name}-%{version}.tar.gz
-Source1:        
https://hackage.haskell.org/package/%{pkg_name}-%{version}/revision/2.cabal#/%{pkg_name}.cabal
 BuildRequires:  ghc-Cabal-devel
 BuildRequires:  ghc-base-devel
 BuildRequires:  ghc-base-prof
@@ -82,7 +81,6 @@
 
 %prep
 %autosetup -n %{pkg_name}-%{version}
-cp -p %{SOURCE1} %{pkg_name}.cabal
 
 %build
 %ghc_lib_build

++++++ JuicyPixels-3.3.8.tar.gz -> JuicyPixels-3.3.9.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/JuicyPixels-3.3.8/JuicyPixels.cabal 
new/JuicyPixels-3.3.9/JuicyPixels.cabal
--- old/JuicyPixels-3.3.8/JuicyPixels.cabal     2022-07-17 21:36:36.000000000 
+0200
+++ new/JuicyPixels-3.3.9/JuicyPixels.cabal     2024-06-06 20:35:02.000000000 
+0200
@@ -1,5 +1,5 @@
 Name:                JuicyPixels
-Version:             3.3.8
+Version:             3.3.9
 Synopsis:            Picture loading/serialization (in png, jpeg, bitmap, gif, 
tga, tiff and radiance)
 Description:
     
<<data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMAAAADABAMAAACg8nE0AAAAElBMVEUAAABJqDSTWEL/qyb///8AAABH/1GTAAAAAXRSTlMAQObYZgAAAN5JREFUeF7s1sEJgFAQxFBbsAV72v5bEVYWPwT/XDxmCsi7zvHXavYREBDI3XP2GgICqBBYuwIC+/rVayPUAyAg0HvIXBcQoDFDGnUBgWQQ2Bx3AYFaRoBpAQHWb3bt2ARgGAiCYFFuwf3X5HA/McgGJWI2FdykCv4aBYzmKwDwvl6NVmUAAK2vlwEALK7fo88GANB6HQsAAAAAAAAA7P94AQCzswEAAAAAAAAAAAAAAAAAAICzh4UAO4zWAYBfRutHA4Bn5C69JhowAMGoBaMWDG0wCkbBKBgFo2AUAACPmegUST/IJAAAAABJRU5ErkJggg==>>
@@ -14,11 +14,21 @@
 Category:            Codec, Graphics, Image
 Stability:           Stable
 Build-type:          Simple
+cabal-version: 1.18
+tested-with:
+  GHC == 9.8.1
+  GHC == 9.6.4
+  GHC == 9.4.8
+  GHC == 9.2.8
+  GHC == 9.0.2
+  GHC == 8.10.7
+  GHC == 8.8.4
+  GHC == 8.6.5
+  GHC == 8.4.4
+  GHC == 8.2.2
+  GHC == 8.0.2
 
--- Constraint on the version of Cabal needed to build this package.
-Cabal-version:       1.18
-
-extra-source-files: changelog, docimages/*.png, docimages/*.svg, README.md
+extra-doc-files: changelog, docimages/*.png, docimages/*.svg, README.md
 extra-doc-files: docimages/*.png, docimages/*.svg
 
 Source-Repository head
@@ -28,7 +38,7 @@
 Source-Repository this
     Type:      git
     Location:  git://github.com/Twinside/Juicy.Pixels.git
-    Tag:       v3.3.7
+    Tag:       v3.3.8
 
 Flag Mmap
     Description: Enable the file loading via mmap (memory map)
@@ -37,6 +47,7 @@
 Library
   hs-source-dirs: src
   Default-Language: Haskell2010
+  default-extensions: TypeOperators
   Exposed-modules:  Codec.Picture,
                     Codec.Picture.Bitmap,
                     Codec.Picture.Gif,
@@ -66,16 +77,16 @@
                     Codec.Picture.Tiff.Internal.Types
 
   Ghc-options: -O3 -Wall
-  Build-depends: base                >= 4.8     && < 6,
-                 bytestring          >= 0.9     && < 0.12,
+  Build-depends: base                >= 4.8     && < 5,
+                 bytestring          >= 0.9     && < 0.13,
                  mtl                 >= 1.1     && < 2.4,
-                 binary              >= 0.8.1     && < 0.9,
-                 zlib                >= 0.5.3.1 && < 0.7,
+                 binary              >= 0.8.1   && < 0.9,
+                 zlib                >= 0.5.3.1 && < 0.8,
                  transformers        >= 0.2,
-                 vector              >= 0.13,
+                 vector              >= 0.12.3.1,
                  primitive           >= 0.4,
-                 deepseq             >= 1.1     && < 1.5,
-                 containers          >= 0.4.2   && < 0.7
+                 deepseq             >= 1.1     && < 1.6,
+                 containers          >= 0.4.2   && < 0.8
 
   -- Modules not exported by this package.
   Other-modules: Codec.Picture.BitWriter,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/JuicyPixels-3.3.8/changelog 
new/JuicyPixels-3.3.9/changelog
--- old/JuicyPixels-3.3.8/changelog     2022-07-17 21:34:19.000000000 +0200
+++ new/JuicyPixels-3.3.9/changelog     2024-06-06 20:34:05.000000000 +0200
@@ -1,6 +1,11 @@
 Change log
 ==========
 
+v3.3.9 June 2024
+----------------
+
+ * Something something compilation
+
 v3.3.7 July 2022
 ----------------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/JuicyPixels-3.3.8/src/Codec/Picture/ColorQuant.hs 
new/JuicyPixels-3.3.9/src/Codec/Picture/ColorQuant.hs
--- old/JuicyPixels-3.3.8/src/Codec/Picture/ColorQuant.hs       2022-03-09 
23:41:19.000000000 +0100
+++ new/JuicyPixels-3.3.9/src/Codec/Picture/ColorQuant.hs       2024-06-06 
20:34:05.000000000 +0200
@@ -278,7 +278,7 @@
 
 -- Based on the OCaml implementation:
 -- http://rosettacode.org/wiki/Color_quantization
--- which is in turn based on: www.leptonica.com/papers/mediancut.pdf.
+-- which is in turn based on: www.leptonica.org/papers/mediancut.pdf.
 -- We use the product of volume and population to determine the next cluster
 -- to split and determine the placement of each color by compating it to the
 -- mean of the parent cluster. So median cut is a bit of a misnomer, since one
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/JuicyPixels-3.3.8/src/Codec/Picture/InternalHelper.hs 
new/JuicyPixels-3.3.9/src/Codec/Picture/InternalHelper.hs
--- old/JuicyPixels-3.3.8/src/Codec/Picture/InternalHelper.hs   2016-09-04 
14:18:57.000000000 +0200
+++ new/JuicyPixels-3.3.9/src/Codec/Picture/InternalHelper.hs   2024-06-06 
20:34:05.000000000 +0200
@@ -1,51 +1,32 @@
-{-# LANGUAGE CPP #-}
-module Codec.Picture.InternalHelper ( runGet
-                                    , runGetStrict
-                                    , decode
-                                    , getRemainingBytes
-                                    , getRemainingLazyBytes ) where
-
-import qualified Data.ByteString as B
-import qualified Data.ByteString.Lazy as L
-import Data.Binary( Binary( get ) )
-import Data.Binary.Get( Get
-                      , getRemainingLazyByteString
-                      )
-import qualified Data.Binary.Get as G
-
-#if MIN_VERSION_binary(0,6,4)
-#else
-import Control.Applicative( (<$>) )
-import qualified Control.Exception as E
--- I feel so dirty. :(
-import System.IO.Unsafe( unsafePerformIO )
-#endif
-
-decode :: (Binary a) => B.ByteString -> Either String a
-decode = runGetStrict get
-
-runGet :: Get a -> L.ByteString -> Either String a
-#if MIN_VERSION_binary(0,6,4)
-runGet act = unpack . G.runGetOrFail act
-    where unpack (Left (_, _, str)) = Left str
-          unpack (Right (_, _, element)) = Right element
-#else
-runGet act str = unsafePerformIO $ E.catch
-    (Right <$> E.evaluate (G.runGet act str))
-    (\msg -> return . Left $ show (msg :: E.SomeException))
-#endif
-
-runGetStrict :: Get a -> B.ByteString -> Either String a
-runGetStrict act buffer = runGet act $ L.fromChunks [buffer]
-
-getRemainingBytes :: Get B.ByteString
-getRemainingBytes = do
-    rest <- getRemainingLazyByteString 
-    return $ case L.toChunks rest of
-        [] -> B.empty
-        [a] -> a
-        lst -> B.concat lst
-
-getRemainingLazyBytes :: Get L.ByteString
-getRemainingLazyBytes = getRemainingLazyByteString 
-
+{-# LANGUAGE CPP #-}
+module Codec.Picture.InternalHelper ( runGet
+                                    , runGetStrict
+                                    , decode
+                                    , getRemainingBytes
+                                    , getRemainingLazyBytes ) where
+
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Lazy as L
+import Data.Binary( Binary( get ) )
+import Data.Binary.Get( Get
+                      , getRemainingLazyByteString
+                      )
+import qualified Data.Binary.Get as G
+
+decode :: (Binary a) => B.ByteString -> Either String a
+decode = runGetStrict get
+
+runGet :: Get a -> L.ByteString -> Either String a
+runGet act = unpack . G.runGetOrFail act
+    where unpack (Left (_, _, str)) = Left str
+          unpack (Right (_, _, element)) = Right element
+
+runGetStrict :: Get a -> B.ByteString -> Either String a
+runGetStrict act buffer = runGet act $ L.fromChunks [buffer]
+
+getRemainingBytes :: Get B.ByteString
+getRemainingBytes = L.toStrict <$> getRemainingLazyByteString
+
+getRemainingLazyBytes :: Get L.ByteString
+getRemainingLazyBytes = getRemainingLazyByteString
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/JuicyPixels-3.3.8/src/Codec/Picture/Jpg/Internal/DefaultTable.hs 
new/JuicyPixels-3.3.9/src/Codec/Picture/Jpg/Internal/DefaultTable.hs
--- old/JuicyPixels-3.3.8/src/Codec/Picture/Jpg/Internal/DefaultTable.hs        
2018-12-16 22:36:06.000000000 +0100
+++ new/JuicyPixels-3.3.9/src/Codec/Picture/Jpg/Internal/DefaultTable.hs        
2024-06-06 20:34:05.000000000 +0200
@@ -1,3 +1,4 @@
+{-# LANGUAGE DeriveGeneric #-}
 {-# LANGUAGE TupleSections #-}
 {-# LANGUAGE FlexibleContexts #-}
 -- | Module used by the jpeg decoder internally, shouldn't be used
@@ -33,6 +34,7 @@
                                      , defaultDcLumaHuffmanTable
                                      ) where
 
+import Control.DeepSeq( NFData(..) )
 import Data.Int( Int16 )
 import Foreign.Storable ( Storable )
 import Control.Monad.ST( runST )
@@ -42,6 +44,7 @@
 import Data.Word( Word8, Word16 )
 import Data.List( foldl' )
 import qualified Data.Vector.Storable.Mutable as M
+import GHC.Generics( Generic )
 
 import Codec.Picture.BitWriter
 
@@ -108,7 +111,8 @@
 
 -- | Enumeration used to search in the tables for different components.
 data DctComponent = DcComponent | AcComponent
-    deriving (Eq, Show)
+    deriving (Eq, Show, Generic)
+instance NFData DctComponent
 
 -- | Transform parsed coefficients from the jpeg header to a
 -- tree which can be used to decode data.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/JuicyPixels-3.3.8/src/Codec/Picture/Jpg/Internal/Types.hs 
new/JuicyPixels-3.3.9/src/Codec/Picture/Jpg/Internal/Types.hs
--- old/JuicyPixels-3.3.8/src/Codec/Picture/Jpg/Internal/Types.hs       
2022-07-17 21:34:19.000000000 +0200
+++ new/JuicyPixels-3.3.9/src/Codec/Picture/Jpg/Internal/Types.hs       
2024-06-06 20:34:05.000000000 +0200
@@ -1,6 +1,13 @@
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE DeriveGeneric #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE TypeFamilies #-}
 {-# LANGUAGE CPP #-}
+
+-- | A good explanation of the JPEG format, including diagrams, is given at:
+-- <https://github.com/corkami/formats/blob/master/image/jpeg.md>
+--
+-- The full spec (excluding EXIF): https://www.w3.org/Graphics/JPEG/itu-t81.pdf
 module Codec.Picture.Jpg.Internal.Types( MutableMacroBlock
                               , createEmptyMutableMacroBlock
                               , printMacroBlock
@@ -21,8 +28,19 @@
                               , JpgAdobeApp14( .. )
                               , JpgJFIFApp0( .. )
                               , JFifUnit( .. )
+                              , TableList( .. )
+                              , RestartInterval( .. )
+                              , getJpgImage
                               , calculateSize
                               , dctBlockSize
+                              , parseECS
+                              , parseECS_simple
+                              , skipUntilFrames
+                              , skipFrameMarker
+                              , parseFrameOfKind
+                              , parseFrames
+                              , parseFrameKinds
+                              , parseToFirstFrameHeader
                               ) where
 
 
@@ -30,10 +48,13 @@
 import Control.Applicative( pure, (<*>), (<$>) )
 #endif
 
+import Control.DeepSeq( NFData(..) )
 import Control.Monad( when, replicateM, forM, forM_, unless )
 import Control.Monad.ST( ST )
 import Data.Bits( (.|.), (.&.), unsafeShiftL, unsafeShiftR )
 import Data.List( partition )
+import Data.Maybe( maybeToList )
+import GHC.Generics( Generic )
 
 #if !MIN_VERSION_base(4,11,0)
 import Data.Monoid( (<>) )
@@ -48,8 +69,9 @@
 import qualified Data.ByteString as B
 import qualified Data.ByteString.Char8 as BC
 import qualified Data.ByteString.Lazy as L
+import qualified Data.ByteString.Unsafe as BU
 
-import Data.Int( Int16 )
+import Data.Int( Int16, Int64 )
 import Data.Word(Word8, Word16 )
 import Data.Binary( Binary(..) )
 
@@ -59,7 +81,11 @@
                       , getByteString
                       , skip
                       , bytesRead
+                      , lookAhead
+                      , ByteOffset
+                      , getLazyByteString
                       )
+import qualified Data.Binary.Get.Internal as GetInternal
 
 import Data.Binary.Put( Put
                       , putWord8
@@ -75,7 +101,6 @@
 import Codec.Picture.Tiff.Internal.Metadata( exifOffsetIfd )
 import Codec.Picture.Metadata.Exif
 
-{-import Debug.Trace-}
 import Text.Printf
 
 -- | Type only used to make clear what kind of integer we are carrying
@@ -108,7 +133,8 @@
 
     | JpgRestartInterval
     | JpgRestartIntervalEnd Word8
-    deriving (Eq, Show)
+    deriving (Eq, Show, Generic)
+instance NFData JpgFrameKind
 
 data JpgFrame =
       JpgAppFrame        !Word8 B.ByteString
@@ -118,10 +144,11 @@
     | JpgExtension       !Word8 B.ByteString
     | JpgQuantTable      ![JpgQuantTableSpec]
     | JpgHuffmanTable    ![(JpgHuffmanTableSpec, HuffmanPackedTree)]
-    | JpgScanBlob        !JpgScanHeader !L.ByteString
+    | JpgScanBlob        !JpgScanHeader !L.ByteString -- ^ The @ByteString@ is 
the ECS (Entropy-Coded Segment), typically the largest part of compressed image 
data.
     | JpgScans           !JpgFrameKind !JpgFrameHeader
     | JpgIntervalRestart !Word16
-    deriving Show
+    deriving (Eq, Show, Generic)
+instance NFData JpgFrame
 
 data JpgColorSpace
   = JpgColorSpaceYCbCr
@@ -133,13 +160,15 @@
   | JpgColorSpaceCMYK
   | JpgColorSpaceRGB
   | JpgColorSpaceRGBA
-  deriving Show
+  deriving (Eq, Show, Generic)
+instance NFData JpgColorSpace
 
 data AdobeTransform
   = AdobeUnknown    -- ^ Value 0
   | AdobeYCbCr      -- ^ value 1
   | AdobeYCck       -- ^ value 2
-  deriving Show
+  deriving (Eq, Show, Generic)
+instance NFData AdobeTransform
 
 data JpgAdobeApp14 = JpgAdobeApp14
   { _adobeDctVersion :: !Word16
@@ -147,14 +176,16 @@
   , _adobeFlag1      :: !Word16
   , _adobeTransform  :: !AdobeTransform
   }
-  deriving Show
+  deriving (Eq, Show, Generic)
+instance NFData JpgAdobeApp14
 
 -- | Size: 1
 data JFifUnit
   = JFifUnitUnknown   -- ^ 0
   | JFifPixelsPerInch -- ^ 1
   | JFifPixelsPerCentimeter -- ^ 2
-  deriving Show
+  deriving (Eq, Show, Generic)
+instance NFData JFifUnit
 
 instance Binary JFifUnit where
   put v = putWord8 $ case v of
@@ -175,7 +206,8 @@
   , _jfifDpiY      :: !Word16
   , _jfifThumbnail :: !(Maybe {- (Image PixelRGB8) -} Int)
   }
-  deriving Show
+  deriving (Eq, Show, Generic)
+instance NFData JpgJFIFApp0
 
 instance Binary JpgJFIFApp0 where
   get = do
@@ -260,7 +292,8 @@
     , jpgImageComponentCount :: !Word8
     , jpgComponents          :: ![JpgComponent]
     }
-    deriving Show
+    deriving (Eq, Show, Generic)
+instance NFData JpgFrameHeader
 
 
 instance SizeCalculable JpgFrameHeader where
@@ -275,13 +308,15 @@
     , verticalSamplingFactor    :: !Word8
     , quantizationTableDest     :: !Word8
     }
-    deriving Show
+    deriving (Eq, Show, Generic)
+instance NFData JpgComponent
 
 instance SizeCalculable JpgComponent where
     calculateSize _ = 3
 
 data JpgImage = JpgImage { jpgFrame :: [JpgFrame] }
-    deriving Show
+    deriving (Eq, Show, Generic)
+instance NFData JpgImage
 
 data JpgScanSpecification = JpgScanSpecification
     { componentSelector :: !Word8
@@ -291,7 +326,8 @@
     , acEntropyCodingTable :: !Word8
 
     }
-    deriving Show
+    deriving (Eq, Show, Generic)
+instance NFData JpgScanSpecification
 
 instance SizeCalculable JpgScanSpecification where
     calculateSize _ = 2
@@ -310,7 +346,8 @@
       -- | Encoded as 4 bits
     , successiveApproxLow :: !Word8
     }
-    deriving Show
+    deriving (Eq, Show, Generic)
+instance NFData JpgScanHeader
 
 instance SizeCalculable JpgScanHeader where
     calculateSize hdr = 2 + 1
@@ -327,7 +364,8 @@
 
     , quantTable         :: MacroBlock Int16
     }
-    deriving Show
+    deriving (Eq, Show, Generic)
+instance NFData JpgQuantTableSpec
 
 class SizeCalculable a where
     calculateSize :: a -> Int
@@ -382,7 +420,8 @@
     , huffSizes :: !(VU.Vector Word8)
     , huffCodes :: !(V.Vector (VU.Vector Word8))
     }
-    deriving Show
+    deriving (Eq, Show, Generic)
+instance NFData JpgHuffmanTableSpec
 
 instance SizeCalculable JpgHuffmanTableSpec where
     calculateSize table = 1 + 16 + sum [fromIntegral e | e <- VU.toList $ 
huffSizes table]
@@ -416,15 +455,28 @@
         putWord8 0xFF >> putWord8 0xD8 >> mapM_ putFrame frames
             >> putWord8 0xFF >> putWord8 0xD9
 
+    -- | Consider using `getJpgImage` instead for a non-semi-lazy 
implementation.
     get = do
-        let startOfImageMarker = 0xD8
-            -- endOfImageMarker = 0xD9
-        checkMarker commonMarkerFirstByte startOfImageMarker
-        eatUntilCode
-        frames <- parseFrames
+        skipUntilFrames
+        frames <- parseFramesSemiLazy
+        -- let endOfImageMarker = 0xD9
         {-checkMarker commonMarkerFirstByte endOfImageMarker-}
         return JpgImage { jpgFrame = frames }
 
+-- | Like `get` from `instance Binary JpgImage`, but without the legacy
+-- semi-lazy implementation.
+getJpgImage :: Get JpgImage
+getJpgImage = do
+    skipUntilFrames
+    frames <- parseFrames
+    return JpgImage { jpgFrame = frames }
+
+skipUntilFrames :: Get ()
+skipUntilFrames = do
+    let startOfImageMarker = 0xD8
+    checkMarker commonMarkerFirstByte startOfImageMarker
+    eatUntilCode
+
 eatUntilCode :: Get ()
 eatUntilCode = do
     code <- getWord8
@@ -436,7 +488,7 @@
     getByteString (fromIntegral size - 2)
 
 putFrame :: JpgFrame -> Put
-putFrame (JpgAdobeAPP14 adobe) = 
+putFrame (JpgAdobeAPP14 adobe) =
     put (JpgAppSegment 14) >> putWord16be 14 >> put adobe
 putFrame (JpgJFIF jfif) =
     put (JpgAppSegment 0) >> putWord16be (14+2) >> put jfif
@@ -469,41 +521,162 @@
     when (rb1 /= b1 || rb2 /= b2)
          (fail "Invalid marker used")
 
-extractScanContent :: L.ByteString -> (L.ByteString, L.ByteString)
-extractScanContent str = aux 0
-  where maxi = fromIntegral $ L.length str - 1
-
-        aux n | n >= maxi = (str, L.empty)
-              | v == 0xFF && vNext /= 0 && not isReset = L.splitAt n str
-              | otherwise = aux (n + 1)
-            where v = str `L.index` n
-                  vNext = str `L.index` (n + 1)
-                  isReset = 0xD0 <= vNext && vNext <= 0xD7
-
-parseAdobe14 :: B.ByteString -> [JpgFrame] -> [JpgFrame]
-parseAdobe14 str lst = go where
-  go = case runGetStrict get str of
-    Left _err -> lst
-    Right app14 -> JpgAdobeAPP14 app14 : lst
+-- | Simpler implementation of `parseECS` to allow an easier understanding
+-- of the logic, and to provide a comparison for correctness.
+parseECS_simple :: Get L.ByteString
+parseECS_simple = do
+    -- There's no efficient way in `binary` to parse byte-by-byte while 
assembling a
+    -- resulting ByteString (without using `.Internal` modules, which is what
+    --  `parseECS` does), so instead first compute the length of the content
+    -- byte-by-byte inside a `lookAhead` (not advancing the parser offset), and
+    -- then efficiently take that long a ByteString (advancing the parser 
offset).
+    --
+    -- This is still slow compared to `parseECS` because parser functions
+    -- (`getWord8`) are used repeatedly, instead of plain loops over 
ByteString contents.
+    -- The slowdown is ~2x on GHC 8.10.7 on an Intel Core i7-7500U.
+    n <- lookAhead getContentLength
+    getLazyByteString n
+  where
+    getContentLength :: Get ByteOffset
+    getContentLength = do
+        bytesReadBeforeContent <- bytesRead
+        let loop :: Word8 -> Get ByteOffset
+            loop !v = do
+                vNext <- getWord8
+                let isReset = 0xD0 <= vNext && vNext <= 0xD7
+                let vIsSegmentMarker = v == 0xFF && vNext /= 0 && not isReset
+                if not vIsSegmentMarker
+                    then loop vNext
+                    else do
+                        bytesReadAfterContentPlus2 <- bytesRead -- "plus 2" 
because we've also read the segment marker (0xFF and `vNext`)
+                        let !contentLength = (bytesReadAfterContentPlus2 - 2) 
- bytesReadBeforeContent
+                        return contentLength
+
+        v_first <- getWord8
+        loop v_first
+
+-- Replace by `Data.ByteString.dropEnd` once we require `bytestring >= 
0.11.1.0`.
+bsDropEnd :: Int -> B.ByteString -> B.ByteString
+bsDropEnd n bs
+    | n <= 0    = bs
+    | n >= len  = B.empty
+    | otherwise = B.take (len - 1) bs
+  where
+    len = B.length bs
+{-# INLINE bsDropEnd #-}
+
+-- | Parses a Scan's ECS (Entropy-Coded Segment, the largest part of 
compressed image data)
+-- from the `Get` stream.
+--
+-- When this function is called, the parser's offset should be
+-- immediately behind the SOS tag.
+--
+-- As described on e.g. https://www.ccoderun.ca/programming/2017-01-31_jpeg/,
+--
+-- > To find the next segment after the SOS, you must keep reading until you
+-- > find a 0xFF bytes which is not immediately followed by 0x00 (see "byte 
stuffing")
+-- > [or a reset marker's byte: 0xD0 through 0xD7].
+-- > Normally, this will be the EOI segment that comes at the end of the file.
+--
+-- where the 0xFF is the next segment's marker.
+-- See 
https://github.com/corkami/formats/blob/master/image/jpeg.md#entropy-coded-segment
+-- for more details.
+--
+-- This function returns the ECS, not including the next segment's
+-- marker on its trailing end.
+parseECS :: Get L.ByteString
+parseECS = do
+    -- For a simpler but slower implementation of this function, see
+    -- `parseECS_simple`.
+
+    v_first <- getWord8
+    -- TODO: Compare with what `scan` from `binary-parsers` does.
+    --       Probably we cannot use it because it does not allow us to set the 
parser state
+    --       to be _before_ the segment marker which would be convenient to 
not have to
+    --       make a special case the function that calls this function.
+    --       But `scan` works on pointers into the bytestring chunks. Why, for 
performance?
+    --       I've asked on 
https://github.com/winterland1989/binary-parsers/issues/7
+    --       If that is for performance, we may want to replicate the same 
thing here.
+    --
+    --       An orthogonal idea is to use `Data.ByteString.elemIndex` to 
fast-forward
+    --       to the next 0xFF using `memchr`, but the `unsafe` call to 
`memchr` might
+    --       have too much overhead, since 0xFF bytes appear statistically 
every 256 bytes.
+    --       See 
https://stackoverflow.com/questions/14519905/how-much-does-it-cost-for-haskell-ffi-to-go-into-c-and-back
+
+    -- `withInputChunks` allows us to work on chunks of ByteStrings,
+    -- reducing the number of higher-overhead `Get` functions called.
+    -- It also allows to easily assemble the ByteString to return,
+    -- which may be cross-chunk.
+    -- `withInputChunks` terminates when we return a
+    --     Right (consumed :: ByteString, unconsumed :: ByteString)
+    -- from `consumeChunk`, setting the `Get` parser's offset to just before 
`unconsumed`.
+    -- Because the segment marker we seek may be the 2 bytes across chunk 
boundaries,
+    -- we need to keep a reference to the previous chunk (initialised as 
`B.empty`),
+    -- so that we can set `consumed` properly, because this function is 
supposed
+    -- to not consume the start of the segment marker (see code dropping the 
last
+    -- byte of the previous chunk below).
+    GetInternal.withInputChunks
+        (v_first, B.empty)
+        consumeChunk
+        (         L.fromChunks . (B.singleton v_first :)) -- `v_first` also 
belongs to the returned BS
+        (return . L.fromChunks . (B.singleton v_first :)) -- `v_first` also 
belongs to the returned BS
+  where
+    consumeChunk :: GetInternal.Consume (Word8, B.ByteString) -- which is: 
(Word8, B.ByteString) -> B.ByteString -> Either (Word8, B.ByteString) 
(B.ByteString, B.ByteString)
+    consumeChunk (!v_chunk_start, !prev_chunk) !chunk
+        -- If `withInputChunks` hands us an empty chunk (which `binary` 
probably
+        -- won't do, but since that's not documented, handle it anyway) then 
skip over it,
+        -- so that we always remember the last `prev_chunk` that actually has 
data in it,
+        -- since we `bsDropEnd 1 prev_chunk` in the `case` below.
+        | B.null chunk = Left (v_chunk_start, prev_chunk)
+        | otherwise = loop v_chunk_start 0
+          where
+            loop :: Word8 -> Int -> Either (Word8, B.ByteString) 
(B.ByteString, B.ByteString)
+            loop !v !offset_in_chunk
+                | offset_in_chunk >= B.length chunk = Left (v, chunk)
+                | otherwise =
+                    let !vNext = BU.unsafeIndex chunk offset_in_chunk -- 
bounds check is done above
+                        !isReset = 0xD0 <= vNext && vNext <= 0xD7
+                        !vIsSegmentMarker = v == 0xFF && vNext /= 0 && not 
isReset
+                    in
+                        if not vIsSegmentMarker
+                            then loop vNext (offset_in_chunk+1)
+                            else
+                                -- Set the parser state to _before_ the 
segment marker.
+                                -- The first case, where the segment marker's 
2 bytes are exactly
+                                -- at the chunk boundary, requires us to 
allocate a new BS with
+                                -- `B.cons`; luckily this case should be rare.
+                                let (!consumed, !unconsumed) = case () of
+                                     () | offset_in_chunk == 0 -> (bsDropEnd 1 
prev_chunk, v `B.cons` chunk) -- segment marker starts at `v`, which is the 
last byte of the previous chunk
+                                        | offset_in_chunk == 1 -> (B.empty, 
chunk) -- segment marker starts exactly at `chunk`
+                                        | otherwise            -> B.splitAt 
(offset_in_chunk - 1) chunk -- segment marker starts at `v`, which is 1 before 
`vNext` (which is at `offset_in_chunk`)
+                                in Right $! (consumed, unconsumed)
+
+
+
+parseAdobe14 :: B.ByteString -> Maybe JpgFrame
+parseAdobe14 str = case runGetStrict get str of
+    Left _err -> Nothing
+    Right app14 -> Just $! JpgAdobeAPP14 app14
 
 -- | Parse JFIF or JFXX information. Right now only JFIF.
-parseJF__  :: B.ByteString -> [JpgFrame] -> [JpgFrame]
-parseJF__  str lst = go where
-  go = case runGetStrict get str of
-    Left _err -> lst
-    Right jfif -> JpgJFIF jfif : lst
-
-parseExif :: B.ByteString -> [JpgFrame] -> [JpgFrame]
-parseExif str lst 
-  | exifHeader `B.isPrefixOf` str = go
-  | otherwise = lst
+parseJF__ :: B.ByteString -> Maybe JpgFrame
+parseJF__ str = case runGetStrict get str of
+    Left _err -> Nothing
+    Right jfif -> Just $! JpgJFIF jfif
+
+parseExif :: B.ByteString -> Maybe JpgFrame
+parseExif str
+  | exifHeader `B.isPrefixOf` str =
+      let
+        tiff = B.drop (B.length exifHeader) str
+      in
+        case runGetStrict (getP tiff) tiff of
+            Left _err -> Nothing
+            Right (_hdr :: TiffHeader, []) -> Nothing
+            Right (_hdr :: TiffHeader, ifds : _) -> Just $! JpgExif ifds
+  | otherwise = Nothing
   where
     exifHeader = BC.pack "Exif\0\0"
-    tiff = B.drop (B.length exifHeader) str
-    go = case runGetStrict (getP tiff) tiff of
-      Left _err -> lst
-      Right (_hdr :: TiffHeader, []) -> lst
-      Right (_hdr :: TiffHeader, ifds : _) -> JpgExif ifds : lst
 
 putExif :: [ImageFileDirectory] -> Put
 putExif ifds = putAll where
@@ -515,7 +688,7 @@
   ifdList = case partition (isInIFD0 . ifdIdentifier) ifds of
     (ifd0, []) -> [ifd0]
     (ifd0, ifdExif) -> [ifd0 <> pure exifOffsetIfd, ifdExif]
-  
+
   exifBlob = runPut $ do
     putByteString $ BC.pack "Exif\0\0"
     putP BC.empty (hdr, ifdList)
@@ -525,47 +698,190 @@
     putWord16be . fromIntegral $ L.length exifBlob + 2
     putLazyByteString exifBlob
 
-parseFrames :: Get [JpgFrame]
-parseFrames = do
-    kind <- get
-    let parseNextFrame = do
-            word <- getWord8
-            when (word /= 0xFF) $ do
-                readedData <- bytesRead
-                fail $ "Invalid Frame marker (" ++ show word
-                     ++ ", bytes read : " ++ show readedData ++ ")"
-            parseFrames
-
+skipFrameMarker :: Get ()
+skipFrameMarker = do
+    word <- getWord8
+    when (word /= 0xFF) $ do
+        readedData <- bytesRead
+        fail $ "Invalid Frame marker (" ++ show word
+                ++ ", bytes read : " ++ show readedData ++ ")"
+
+-- | Parses a single frame.
+--
+-- Returns `Nothing` when we encounter a frame we want to skip.
+parseFrameOfKind :: JpgFrameKind -> Get (Maybe JpgFrame)
+parseFrameOfKind kind = do
     case kind of
-        JpgEndOfImage -> return []
-        JpgAppSegment 0 ->
-            parseJF__ <$> takeCurrentFrame <*> parseNextFrame
-        JpgAppSegment 1 ->
-            parseExif <$> takeCurrentFrame <*> parseNextFrame
-        JpgAppSegment 14 ->
-            parseAdobe14 <$> takeCurrentFrame <*> parseNextFrame
-        JpgAppSegment c ->
-            (\frm lst -> JpgAppFrame c frm : lst) <$> takeCurrentFrame <*> 
parseNextFrame
-        JpgExtensionSegment c ->
-            (\frm lst -> JpgExtension c frm : lst) <$> takeCurrentFrame <*> 
parseNextFrame
+        JpgEndOfImage -> return Nothing
+        JpgAppSegment 0 -> parseJF__ <$> takeCurrentFrame
+        JpgAppSegment 1 -> parseExif <$> takeCurrentFrame
+        JpgAppSegment 14 -> parseAdobe14 <$> takeCurrentFrame
+        JpgAppSegment c -> Just . JpgAppFrame c <$> takeCurrentFrame
+        JpgExtensionSegment c -> Just . JpgExtension c <$> takeCurrentFrame
         JpgQuantizationTable ->
-            (\(TableList quants) lst -> JpgQuantTable quants : lst) <$> get 
<*> parseNextFrame
+            (\(TableList quants) -> Just $! JpgQuantTable quants) <$> get
         JpgRestartInterval ->
-            (\(RestartInterval i) lst -> JpgIntervalRestart i : lst) <$> get 
<*> parseNextFrame
+            (\(RestartInterval i) -> Just $! JpgIntervalRestart i) <$> get
         JpgHuffmanTableMarker ->
-            (\(TableList huffTables) lst ->
-                    JpgHuffmanTable [(t, packHuffmanTree . 
buildPackedHuffmanTree $ huffCodes t) | t <- huffTables] : lst)
-                    <$> get <*> parseNextFrame
-        JpgStartOfScan ->
-            (\frm imgData ->
-                let (d, other) = extractScanContent imgData
-                in
-                case runGet parseFrames (L.drop 1 other) of
-                  Left _ -> [JpgScanBlob frm d]
-                  Right lst -> JpgScanBlob frm d : lst
-            ) <$> get <*> getRemainingLazyBytes
+            (\(TableList huffTables) -> Just $!
+                    JpgHuffmanTable [(t, packHuffmanTree . 
buildPackedHuffmanTree $ huffCodes t) | t <- huffTables])
+                    <$> get
+        JpgStartOfScan -> do
+            scanHeader <- get
+            ecs <- parseECS
+            return $! Just $! JpgScanBlob scanHeader ecs
+        _ -> Just . JpgScans kind <$> get
+
+
+-- | Parse a list of `JpgFrame`s.
+--
+-- This function has various quirks; consider the below with great caution
+-- when using this function.
+--
+-- While @data JpgFrame = ... | JpgScanBlob !...` itself has strict fields,
+--
+-- This function is written in such a way that that it can construct
+-- the @[JpgFrame]@ "lazily" such that the expensive byte-by-byte traversal
+-- in `parseECS` to create a `JpgScanBlob` can be avoided if only
+-- list elements before that `JpgScanBlob` are evaluated.
+--
+-- That means the user can write code such as
+--
+-- > let mbFirstScan =
+-- >       case runGetOrFail (get @JPG.JpgImage) hugeImageByteString of -- 
(`get @JPG.JpgImage` uses `parseFramesSemiLazy`)
+-- >         Right (_restBs, _offset, res) ->
+-- >           find (\frame -> case frame of { JPG.JpgScans{} -> True; _ -> 
False }) (JPG.jpgFrame res)
+--
+-- with the guarantee that only the bytes before the ECS (large compressed 
image data)
+-- will be inspected, assuming that indeed there is at least 1 `JpgScan` in 
front
+-- of the `JpgScanBlob` that contains the ECS.
+--
+-- This guarantee can be useful to e.g. quickly read just the image
+-- dimensions (width, height) without traversing the large data.
+--
+-- Also note that this `Get` parser does not correctly maintain the parser 
byte offset
+-- (`Data.Binary.Get.bytesRead`), because as soon as a `JpgStartOfScan` is 
returned,
+-- it uses `Data.Binary.Get.getRemainingLazyBytes` to provide:
+--
+-- 1. the laziness described above, and
+-- 2. the ability to ignore any parser failure after the first 
successfully-parsed
+--    `JpgScanBlob` (it is debatable whether this behaviour is a desirable 
behaviour of this
+--    library, but it is historically so and existing exposed functions do not 
break
+--    this for backwards compatibility with existing uses of this library).
+--    This fact also means that even `parseNextFrameStrict` cannot maintain
+--    correct parser byte offsets.
+--
+-- Further note that if you are reading a huge JPEG image from disk strictly,
+-- this will already incur a full traversal (namely creation) of the 
`hugeImageByteString`.
+-- Thus, `parseNextFrameLazy` only provides any benefit if you:
+--
+-- - read the image from disk using lazy IO (not recommended!) such as via
+--   `Data.ByteString.Lazy.readFile`,
+-- - or do something similar, such as creating the `hugeImageByteString` via 
@mmap()@
+--
+-- This function is called "semi lazy" because only the first `JpgScanBlob` 
returned
+-- in the `[JpgFrame]` is returned lazily; frames of other types, or multiple
+-- `JpgScanBlob`s, are confusingly not dealt with lazily.
+--
+-- If as a caller you do not want to deal with any of these quirks,
+-- and use proper strict IO and/or via `Data.Binary.Get`'s incremental input 
interface:
+--
+-- - If you want the whole `[JpgFrame]`: use `parseFrames`.
+-- - If you want parsing to terminate early as in the example shown above,
+--   use in combination with just the right amount of `get :: Get 
JpgFrameKind`,
+--   `parseFrameOfKind`, and `skipFrameMarker`.
+parseFramesSemiLazy :: Get [JpgFrame]
+parseFramesSemiLazy = do
+    kind <- get
+    case kind of
+        -- The end-of-image case needs to be here because `_ ->` default case 
below
+        -- unconditionally uses `skipFrameMarker` which does not exist after 
`JpgEndOfImage`.
+        JpgEndOfImage -> pure []
+        JpgStartOfScan -> do
+            scanHeader <- get
+            remainingBytes <- getRemainingLazyBytes
+            -- It is after the above `getRemainingLazyBytes` that the `Get` 
parser lazily succeeds,
+            -- allowing consumers of `parseFramesSemiLazy` evaluate all 
`[JpgFrame]` list elements
+            -- until (excluding) the cons-cell around the `JpgScanBlob ...` we 
construct below.
+
+            return $ case runGet parseECS remainingBytes of
+                Left _ ->
+                    -- Construct invalid `JpgScanBlob` even when the 
compressed JPEG
+                    -- data is truncated or otherwise invalid, because that's 
what JuicyPixels's
+                    -- `parseFramesSemiLazy` function did in the past, for 
backwards compat.
+                    [JpgScanBlob scanHeader remainingBytes]
+                Right ecs ->
+                    JpgScanBlob scanHeader ecs
+                    :
+                    -- TODO Why `drop 1` instead of `runGet (skipFrameMarker 
*> parseFramesSemiLazy) remainingBytes` that would check that the dropped 1 
Byte is really a frame marker?
+                    case runGet parseFramesSemiLazy (L.drop (L.length ecs + 1) 
remainingBytes) of
+                        -- After we've encountered the first scan blob 
containing encoded image data,
+                        -- we accept anything else after to fail parsing, 
ignoring that failure,
+                        -- end emitting no further frames.
+                        -- TODO: Explain why JuicyPixel chose to use this 
logic, insteaed of failing.
+                        Left _ -> []
+                        Right remainingFrames -> remainingFrames
+        _ -> do
+            mbFrame <- parseFrameOfKind kind
+            skipFrameMarker
+            remainingFrames <- parseFramesSemiLazy
+            return $ maybeToList mbFrame ++ remainingFrames
 
-        _ -> (\hdr lst -> JpgScans kind hdr : lst) <$> get <*> parseNextFrame
+-- | Parse a list of `JpgFrame`s.
+parseFrames :: Get [JpgFrame]
+parseFrames = do
+    kind <- get
+    case kind of
+        JpgEndOfImage -> pure []
+        _ -> do
+            mbFrame <- parseFrameOfKind kind
+            skipFrameMarker
+            remainingFrames <- parseFrames
+            return $ maybeToList mbFrame ++ remainingFrames
+
+-- | Parse a list of `JpgFrameKind`s with their corresponding offsets and 
lengths
+-- (not counting the segment and frame markers into the lengths).
+--
+-- Useful for debugging.
+parseFrameKinds :: Get [(JpgFrameKind, Int64, Int64)]
+parseFrameKinds = do
+    kindMarkerOffset :: Int64 <- bytesRead
+    kind <- get
+    case kind of
+        JpgEndOfImage -> pure [(JpgEndOfImage, kindMarkerOffset, 0)]
+        _ -> do
+            parserOffsetBefore <- bytesRead
+            _ <- parseFrameOfKind kind
+            parserOffsetAfter <- bytesRead
+            let !segmentLengthWithoutMarker = parserOffsetAfter - 
parserOffsetBefore
+            skipFrameMarker
+            remainingKinds <- parseFrameKinds
+            return $ (kind, kindMarkerOffset, 
segmentLengthWithoutMarker):remainingKinds
+
+-- | Parses forward, returning the first scan header encountered.
+--
+-- Should be used after `skipUntilFrames`.
+--
+-- Fails parsing when an SOS segment marker (`JpgStartOfScan`, resulting
+-- in `JpgScanBlob`) is encountered before an SOF segment marker (that
+-- results in `JpgScans` carrying the `JpgFrameHeader`).
+parseToFirstFrameHeader :: Get (Maybe JpgFrameHeader)
+parseToFirstFrameHeader = do
+    kind <- get
+    case kind of
+        JpgEndOfImage -> return Nothing
+        JpgStartOfScan -> fail "parseToFirstFrameHeader: Encountered SOS frame 
marker before frame header that tells its dimensions"
+        _ -> do
+            mbFrame <- parseFrameOfKind kind
+            case mbFrame of
+                Nothing -> continueSearching
+                Just frame -> case frame of
+                    JpgScans _ frameHeader -> return $ Just $! frameHeader
+                    _ -> continueSearching
+  where
+    continueSearching = do
+        skipFrameMarker
+        parseToFirstFrameHeader
 
 buildPackedHuffmanTree :: V.Vector (VU.Vector Word8) -> HuffmanTree
 buildPackedHuffmanTree = buildHuffmanTree . map VU.toList . V.toList
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/JuicyPixels-3.3.8/src/Codec/Picture/Metadata/Exif.hs 
new/JuicyPixels-3.3.9/src/Codec/Picture/Metadata/Exif.hs
--- old/JuicyPixels-3.3.8/src/Codec/Picture/Metadata/Exif.hs    2017-11-11 
10:35:34.000000000 +0100
+++ new/JuicyPixels-3.3.9/src/Codec/Picture/Metadata/Exif.hs    2024-06-06 
20:34:05.000000000 +0200
@@ -1,3 +1,5 @@
+{-# LANGUAGE DeriveGeneric #-}
+
 -- | This module provide a totally partial and incomplete maping
 -- of Exif values. Used for Tiff parsing and reused for Exif extraction.
 module Codec.Picture.Metadata.Exif ( ExifTag( .. )
@@ -14,6 +16,7 @@
 import Data.Word( Word16, Word32 )
 import qualified Data.Vector as V
 import qualified Data.ByteString as B
+import GHC.Generics( Generic )
 
 -- | Tag values used for exif fields. Completly incomplete
 data ExifTag
@@ -72,7 +75,8 @@
 
   | TagExifOffset
   | TagUnknown !Word16
-  deriving (Eq, Ord, Show)
+  deriving (Eq, Ord, Show, Generic)
+instance NFData ExifTag
 
 -- | Convert a value to it's corresponding Exif tag.
 -- Will often be written as 'TagUnknown'
@@ -206,13 +210,5 @@
   | ExifRational  !Word32 !Word32
   | ExifSignedRational  !Int32 !Int32
   | ExifIFD       ![(ExifTag, ExifData)]
-  deriving Show
-
-instance NFData ExifTag where
-  rnf a = a `seq` ()
-
-instance NFData ExifData where
-  rnf (ExifIFD ifds) = rnf ifds `seq` ()
-  rnf (ExifLongs l) = rnf l `seq` ()
-  rnf (ExifShorts l) = rnf l `seq` ()
-  rnf a = a `seq` ()
+  deriving (Eq, Show, Generic)
+instance NFData ExifData
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/JuicyPixels-3.3.8/src/Codec/Picture/Metadata.hs 
new/JuicyPixels-3.3.9/src/Codec/Picture/Metadata.hs
--- old/JuicyPixels-3.3.8/src/Codec/Picture/Metadata.hs 2018-12-16 
22:36:06.000000000 +0100
+++ new/JuicyPixels-3.3.9/src/Codec/Picture/Metadata.hs 2024-06-06 
20:34:05.000000000 +0200
@@ -43,6 +43,8 @@
                              , dotsPerCentiMeterToDotPerInch
                              ) where
 
+import Prelude hiding (Foldable(..))
+
 #if !MIN_VERSION_base(4,8,0)
 import Data.Monoid( Monoid, mempty, mappend )
 import Data.Word( Word )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/JuicyPixels-3.3.8/src/Codec/Picture/Png/Internal/Type.hs 
new/JuicyPixels-3.3.9/src/Codec/Picture/Png/Internal/Type.hs
--- old/JuicyPixels-3.3.8/src/Codec/Picture/Png/Internal/Type.hs        
2018-12-16 22:36:06.000000000 +0100
+++ new/JuicyPixels-3.3.9/src/Codec/Picture/Png/Internal/Type.hs        
2024-06-06 20:34:05.000000000 +0200
@@ -14,6 +14,8 @@
                              , APngFrameControl( .. )
                              , parsePalette 
                              , pngComputeCrc
+                             , pngSignature
+                             , iHDRSignature
                              , pLTESignature
                              , iDATSignature
                              , iENDSignature
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/JuicyPixels-3.3.8/src/Codec/Picture/Png.hs 
new/JuicyPixels-3.3.9/src/Codec/Picture/Png.hs
--- old/JuicyPixels-3.3.8/src/Codec/Picture/Png.hs      2019-06-19 
21:11:57.000000000 +0200
+++ new/JuicyPixels-3.3.9/src/Codec/Picture/Png.hs      2024-06-06 
20:34:05.000000000 +0200
@@ -366,8 +366,8 @@
 deinterlacer :: PngIHdr -> B.ByteString -> ST s (Either (V.Vector Word8) 
(V.Vector Word16))
 deinterlacer (PngIHdr { width = w, height = h, colourType  = imgKind
                       , interlaceMethod = method, bitDepth = depth  }) str = do
-    let compCount = sampleCountOfImageType imgKind 
-        arraySize = fromIntegral $ w * h * compCount
+    let compCount = fromIntegral $ sampleCountOfImageType imgKind 
+        arraySize = (fromIntegral w) * (fromIntegral h) * compCount
         deinterlaceFunction = case method of
             PngNoInterlace -> scanLineInterleaving
             PngInterlaceAdam7 -> adam7Unpack
@@ -377,10 +377,9 @@
         imgArray <- M.new arraySize
         let mutableImage = MutableImage (fromIntegral w) (fromIntegral h) 
imgArray
         deinterlaceFunction iBitDepth 
-                            (fromIntegral compCount)
+                            compCount
                             (fromIntegral w, fromIntegral h)
-                            (scanlineUnpacker8 iBitDepth (fromIntegral 
compCount)
-                                                         mutableImage)
+                            (scanlineUnpacker8 iBitDepth compCount 
mutableImage)
                             str
         Left <$> V.unsafeFreeze imgArray
 
@@ -388,9 +387,9 @@
         imgArray <- M.new arraySize
         let mutableImage = MutableImage (fromIntegral w) (fromIntegral h) 
imgArray
         deinterlaceFunction iBitDepth 
-                            (fromIntegral compCount)
+                            compCount
                             (fromIntegral w, fromIntegral h)
-                            (shortUnpacker (fromIntegral compCount) 
mutableImage)
+                            (shortUnpacker compCount mutableImage)
                             str
         Right <$> V.unsafeFreeze imgArray
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/JuicyPixels-3.3.8/src/Codec/Picture/Tiff/Internal/Types.hs 
new/JuicyPixels-3.3.9/src/Codec/Picture/Tiff/Internal/Types.hs
--- old/JuicyPixels-3.3.8/src/Codec/Picture/Tiff/Internal/Types.hs      
2022-03-09 23:41:19.000000000 +0100
+++ new/JuicyPixels-3.3.9/src/Codec/Picture/Tiff/Internal/Types.hs      
2024-06-06 20:34:05.000000000 +0200
@@ -1,4 +1,5 @@
 {-# LANGUAGE CPP #-}
+{-# LANGUAGE DeriveGeneric #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE FlexibleContexts #-}
@@ -32,6 +33,7 @@
 import Control.Applicative( (<$>), (<*>), pure )
 #endif
 
+import Control.DeepSeq( NFData(..) )
 import Control.Monad( forM_, when, replicateM, )
 import Data.Bits( (.&.), unsafeShiftR )
 import Data.Binary( Binary( .. ) )
@@ -53,6 +55,7 @@
 import qualified Data.ByteString as B
 import Data.Int( Int32 )
 import Data.Word( Word8, Word16, Word32 )
+import GHC.Generics( Generic )
 
 import Codec.Picture.Metadata.Exif
 {-import Debug.Trace-}
@@ -154,7 +157,8 @@
   | TypeSignedRational
   | TypeFloat
   | TypeDouble
-  deriving Show
+  deriving (Eq, Show, Generic)
+instance NFData IfdType
 
 instance BinaryParam Endianness IfdType where
     getP endianness = getP endianness >>= conv where
@@ -403,7 +407,8 @@
   , ifdOffset     :: !Word32
   , ifdExtended   :: !ExifData
   }
-  deriving Show
+  deriving (Eq, Show, Generic)
+instance NFData ImageFileDirectory
 
 instance BinaryParam Endianness ImageFileDirectory where
   getP endianness =

Reply via email to