#FEATURE by cg
authorClaus Gittinger <cg@exept.de>
Fri, 25 Aug 2017 11:20:04 +0200
changeset 3977 c78bab5f36f2
parent 3976 5eda7dd4846b
child 3978 3cf74e1b8c21
#FEATURE by cg class: TIFFReader added: #readSGI24TiffImageData #readSGI32TiffImageData comment/format in: #decodeTiffTag:numberType:length: changed: #fromStream: #readCCITTGroup3TiffImageData #readLZWTiffImageData #readPackbitsTiffImageData #readTiffImageData class: TIFFReader class comment/format in: #documentation changed: #isValidImageFile:
TIFFReader.st
--- a/TIFFReader.st	Fri Aug 25 01:14:06 2017 +0200
+++ b/TIFFReader.st	Fri Aug 25 11:20:04 2017 +0200
@@ -48,12 +48,12 @@
 
 documentation
 "
-    This class knows how to read TIFF files and how to
-    write uncompressed TIFF files.
+    This class knows how to read TIFF files and how to write uncompressed TIFF files.
 
     Implemented & Missing Features:
 
       - Only single image files are supported.
+
       - Not all formats are implemented, and of those that are, not all are tested.
         It should read with most rgb, palette, mono and greyscale images, 
         although the alpha channel is currently not supported and ignored.
@@ -63,16 +63,20 @@
       - Only writing of uncompressed images is currently implemented.
         It should write (at least) mono, 8-bit palette and 24 bit rgb formats.
 
-    More formats will come... (will they ever be needed ?)
+      - bigTiff is supported
+
+    More formats will come... (will they ever be needed?)
 
-    TODO (?): since I don't want to spend all of my life adding more formats here and
-    reinventing the wheel, this code should be changed to use the tiff library.
-    That would give us most formats and also writing capabilities for free.
-    Late note: 
-        I hate C and interfacing to C libraries: it almost always leads to trouble
-        w.r.t. memory leaks, non-reentrancy, non-interruptability etc.
-        (we recently fixed a malloc-non-reentrant bug for some architecture...)
-        So its robably better to do it all in a real programming language ;-)
+    TODO (?): 
+        since I don't want to spend all of my life adding more formats here and
+        reinventing the wheel, this code should be changed to use the tiff library.
+        That would give us most formats and also writing capabilities for free.
+
+        Late note: 
+            I hate C and interfacing to C libraries: it almost always leads to trouble
+            w.r.t. memory leaks, non-reentrancy, non-interruptability etc.
+            (we recently fixed a malloc-non-reentrant bug for some architecture...)
+            So its probably better to do it all in a real programming language ;-)
 
     [author:]
         Claus Gittinger
@@ -130,8 +134,10 @@
     version := inStream nextInt16MSB:(char1 == $M).
     inStream close.
 
-    (version ~~ 42) ifTrue:[^ false].
-    ^ true
+    "/ 43 is bigTiff
+    ^ (version == 42) or:[ (version == 43) ]
+
+    "Modified: / 25-08-2017 / 08:39:20 / cg"
 ! !
 
 !TIFFReader methodsFor:'private'!
@@ -268,15 +274,17 @@
             "/      LZW             -> 5
             "/      OJPEG           -> 6
             "/      JPEG            -> 7
-            "/      NEXT            -> 32766
+            "/      NEXT            -> 32766 (NeXT 2-bit encoding)
             "/      CCITTRLEW       -> 32771
             "/      PACKBITS        -> 32773
-            "/      THUNDERSCAN     -> 32809
+            "/      THUNDERSCAN     -> 32809 (ThunderScan 4-bit encoding)
             "/      PIXARFILM       -> 32908
-            "/      PIXARLOG        -> 32909
-            "/      DEFLATE         -> 32946
+            "/      PIXARLOG        -> 32909 (Pixar companded 11-bit ZIP encoding)
+            "/      DEFLATE         -> 32946 (PKZIP-style Deflate encoding)
             "/      DCS             -> 32947
             "/      JBIG            -> 34661
+            "/      SGI32           -> 34676 (SGI 32-bit Log Luminance encoding)
+            "/      SGI24           -> 34677 (SGI 24-bit Log Luminance encoding)
             
             compression := value.
 
@@ -495,7 +503,7 @@
             ^ self
         ].
         (tagType == 292) ifTrue:[
-            "/ group3options
+            "/ group3options (now called T4Options)
             "/      2DENCODING      -> 1
             "/      UNCOMPRESSED    -> 2
             "/      FILLBITS        -> 4
@@ -505,7 +513,7 @@
             ^ self
         ].
         (tagType == 293) ifTrue:[
-            "/ group4options
+            "/ group4options (now called T6Options)
             "/      UNCOMPRESSED    -> 2
 
             "group4options := value."
@@ -977,6 +985,7 @@
 
     "Modified (format): / 23-05-2017 / 16:12:58 / mawalch"
     "Modified: / 25-08-2017 / 00:24:44 / cg"
+    "Modified (format): / 25-08-2017 / 11:16:19 / cg"
 ! !
 
 !TIFFReader methodsFor:'private-data reading'!
@@ -1003,23 +1012,23 @@
      bytesPerStrip "{ Class: SmallInteger }" |
 
     nPlanes := samplesPerPixel.
-    (nPlanes == 2) ifTrue:[
-        'TIFFReader [info]: ignoring alpha plane' infoPrintCR.
-        nPlanes := 1
-    ].
-
     (nPlanes ~~ 1) ifTrue:[
-        ^ self fileFormatError:'only monochrome/greyscale ccitt3supported'.
+        (nPlanes == 2) ifTrue:[
+            (planarConfiguration ~~ 2) ifTrue:[
+                ^ self fileFormatError:'only separate planes are supported'.
+            ].
+            'TIFFReader [info]: ignoring alpha plane' infoPrintCR.
+            nPlanes := 1
+        ] ifFalse:[
+            ^ self fileFormatError:'only monochrome/greyscale ccitt3supported'.
+        ].   
     ].
 
-    stripByteCounts isNil ifTrue:[
-        ^ self fileFormatError:'currently require stripByteCounts'.
-    ].
-    (rowsPerStrip ~~ 1) isNil ifTrue:[
-        ^ self fileFormatError:'currently require rowsPerStrip to be 1'.
-    ].
+"/    (rowsPerStrip ~~ 1) ifTrue:[
+"/        ^ self fileFormatError:'currently require rowsPerStrip to be 1'.
+"/    ].
 
-"/    'TIFFReader: decompressing CCITT-3 ...' infoPrintNL.
+    "/ 'TIFFReader: decompressing CCITT-3 ...' infoPrintNL.
 
     bitsPerRow := width * (bitsPerSample at:1).
     bytesPerRow := bitsPerRow // 8.
@@ -1028,6 +1037,21 @@
     ].
 
     data := ByteArray new:(bytesPerRow * height).
+
+    "/ if the number of rows per strip is unknown (-1),
+    "/ make it one big strip and decompress that
+    rowsPerStrip = 16rFFFFFFFF ifTrue:[
+        compressedStrip := ByteArray uninitializedNew:(stripByteCounts sum).
+        self positionToStrip:1.
+        inStream nextBytes:(compressedStrip size) into:compressedStrip.
+        self class 
+            decompressCCITT3From:compressedStrip
+            into:data
+            startingAt:1
+            count:compressedStrip size.
+        ^ self 
+    ].
+    
     compressedStrip := ByteArray uninitializedNew:bytesPerRow.
 
     offset := 1.
@@ -1039,15 +1063,16 @@
         stripNr := stripNr + 1.
         self positionToStrip:stripNr.
         inStream nextBytes:(stripByteCounts at:stripNr) into:compressedStrip.
-        self class decompressCCITT3From:compressedStrip
-                                   into:data
-                             startingAt:offset
-                                  count:width.
+        self class 
+            decompressCCITT3From:compressedStrip
+            into:data
+            startingAt:offset
+            count:width.
         offset := offset + bytesPerStrip.
         row := row + rowsPerStrip
     ]
 
-    "Modified: / 3.2.1998 / 18:04:21 / cg"
+    "Modified: / 25-08-2017 / 11:09:02 / cg"
 !
 
 readCCITTGroup4TiffImageData
@@ -1085,11 +1110,11 @@
 !
 
 readLZWTiffImageData
-    "read LZW compressed tiff data; this method only
-     handles 3x8 rgb and 1x2 or 2x2 greyscale images.
-     For 2x2 greyscale images, the alpha plane is ignored.
-     (maybe other formats work also - its simply not
-      tested)"
+    "read LZW compressed tiff data; 
+     this method only handles 8+8+8 and 8+8+8+8 rgb 
+     and 2bit or 2+2bit greyscale images.
+     For 2+2bit greyscale images, the alpha plane is ignored.
+     (maybe other formats work also - but simply not tested)"
 
     |bytesPerRow compressedStrip nPlanes overAllBytes
      bytesPerStrip "{ Class: SmallInteger }"
@@ -1120,11 +1145,7 @@
         bytesPerRow := (width * (bitsPerSample at:1) + 7) // 8.
     ].
 
-    stripByteCounts isNil ifTrue:[
-        ^ self fileFormatError:'currently require stripByteCounts'.
-    ].
-
-"/    'TIFFReader: decompressing LZW ...' infoPrintNL.
+    "/ 'TIFFReader: decompressing LZW ...' infoPrintNL.
 
     overAllBytes := bytesPerRow * height.
     bytesPerRow == width ifTrue:[
@@ -1156,11 +1177,10 @@
     ].
 
     (predictor == 2) ifTrue:[
-        self class decodeDelta:3 in:data width:width height:height
+        self class decodeDelta:nPlanes in:data width:width height:height
     ]
 
-    "Modified: / 24-08-2017 / 20:58:59 / cg"
-    "Modified (format): / 24-08-2017 / 22:16:41 / cg"
+    "Modified: / 25-08-2017 / 10:09:03 / cg"
 !
 
 readNeXTJPEGTiffImageData
@@ -1250,14 +1270,14 @@
             buffer := ByteArray uninitializedNew:nBytes.
         ].
         inStream nextBytes:nBytes into:buffer.
-
-        nDecompressedBytes := self class decompressPackBits:nBytes from:buffer to:data startingAt:offset.
+        nDecompressedBytes := self class decompressPackBitsFrom:buffer at:1 to:data at:offset count:nBytes.
+        "/ nDecompressedBytes := self class decompressPackBits:nBytes from:buffer to:data startingAt:offset.
 
         offset := offset + nDecompressedBytes.
         row := row + rowsPerStrip
     ]
 
-    "Modified: / 12.8.1998 / 13:57:34 / cg"
+    "Modified: / 25-08-2017 / 02:02:20 / cg"
 !
 
 readPixarFilmTiffImageData
@@ -1272,6 +1292,18 @@
     "Modified: / 3.2.1998 / 18:11:53 / cg"
 !
 
+readSGI24TiffImageData
+    ^ self fileFormatError:'SGI 24-bit Log Luminance encoding not implemented' .
+
+    "Created: / 25-08-2017 / 11:17:25 / cg"
+!
+
+readSGI32TiffImageData
+    ^ self fileFormatError:'SGI 32-bit Log Luminance encoding not implemented' .
+
+    "Created: / 25-08-2017 / 11:17:21 / cg"
+!
+
 readThunderScanTiffImageData
     ^ self fileFormatError:'thunderScan compression not implemented' .
 
@@ -1331,11 +1363,17 @@
     (compression == 34661) ifTrue:[
         ^ self readJBIGTiffImageData.
     ].
+    (compression == 34676) ifTrue:[
+        ^ self readSGI32TiffImageData.
+    ].
+    (compression == 34677) ifTrue:[
+        ^ self readSGI24TiffImageData.
+    ].
 
     ^ self fileFormatError:('compression type ' , compression printString , ' not known').
 
-    "Created: / 11.4.1997 / 00:19:44 / cg"
-    "Modified: / 3.2.1998 / 18:12:36 / cg"
+    "Created: / 11-04-1997 / 00:19:44 / cg"
+    "Modified: / 25-08-2017 / 11:17:25 / cg"
 !
 
 readTiledLZWTiffImageData
@@ -2367,7 +2405,7 @@
             and:[(metaData includesKey:#TileOffsets)
             and:[(metaData includesKey:#TileByteCounts) ]]]]
         ) ifFalse:[    
-            ^ self fileFormatError:'missing stripOffsets tag'.
+            ^ self fileFormatError:'missing stripOffsets or tileOffsets tag'.
         ].
         self reportDimension.
         result := self readTiledTiffImageData.
@@ -2376,7 +2414,7 @@
             stripOffsets size == 1 ifTrue:[
                 stripByteCounts := Array with:(self bitsPerPixel // 8) * width * height
             ] ifFalse:[
-                ^ self fileFormatError:'missing stripByteCounts tag'.
+                ^ self fileFormatError:'missing stripByteCounts'.
             ].    
         ].
         self reportDimension.
@@ -2413,7 +2451,7 @@
 
     ^ result
 
-    "Modified: / 25-08-2017 / 00:20:58 / cg"
+    "Modified: / 25-08-2017 / 10:08:30 / cg"
 ! !
 
 !TIFFReader methodsFor:'writing'!