MacOSXIconReader.st
changeset 3910 553aa2bad2e0
parent 3908 366f0a76e9e3
child 3911 57fffd545c0b
--- a/MacOSXIconReader.st	Wed Feb 22 11:01:18 2017 +0100
+++ b/MacOSXIconReader.st	Wed Feb 22 12:06:45 2017 +0100
@@ -52,6 +52,51 @@
     caveat:
         only a subset of the possibly formats are supported.
 
+    supported formats:
+    
+    support   format   length                pixels  OS-version  description
+    -----------------------------------------------------------------------------   
+    r           ICON    128                     32      1.0     32×32 1-bit mono icon
+    r           ICN#    256                     32      6.0     32×32 1-bit mono icon with 1-bit mask
+                icm#    48                      16      6.0     16×12 1 bit mono icon with 1-bit mask
+                icm4    96                      16      7.0     16×12 4 bit icon
+                icm8    192                     16      7.0     16×12 8 bit icon
+    r           ics#    64 (32 img + 32 mask)   16      6.0     16×16 1-bit mask
+    r           ics4    128                     16      7.0     16×16 4-bit icon
+    r           ics8    256                     16      7.0     16x16 8 bit icon
+                is32    varies (768)            16      8.5     16×16 24-bit icon
+    r           s8mk    256                     16      8.5     16x16 8-bit mask
+    r           icl4    512                     32      7.0     32×32 4-bit icon
+    r           icl8    1,024                   32      7.0     32×32 8-bit icon
+    r           il32    varies (3,072)          32      8.5     32x32 24-bit icon
+    r           l8mk    1,024                   32      8.5     32×32 8-bit mask
+    r           ich#    288                     48      8.5     48×48 1-bit mask
+    r           ich4    1,152                   48      8.5     48×48 4-bit icon
+    r           ich8    2,304                   48      8.5     48×48 8-bit icon
+    r           ih32    varies (6,912)          48      8.5     48×48 24-bit icon
+    r           h8mk    2,304                   48      8.5     48×48 8-bit mask
+    r           it32    varies (49,152)        128     10.0    128×128 24-bit icon
+    r           t8mk    16,384                 128     10.0    128×128 8-bit mask
+    r           icp4    varies                  16     10.7    16x16 icon in JPEG 2000 or PNG format
+    r           icp5    varies                  32     10.7    32x32 icon in JPEG 2000 or PNG format
+                icp6    varies                  64     10.7    64x64 icon in JPEG 2000 or PNG format
+    r           ic07    varies                 128     10.7    128x128 icon in JPEG 2000 or PNG format
+    r           ic08    varies                 256     10.5    256×256 icon in JPEG 2000 or PNG format
+    r           ic09    varies                 512     10.5    512×512 icon in JPEG 2000 or PNG format
+    r           ic10    varies                1024     10.7    1024×1024 in 10.7 (or 512x512@2x 'retina' in 10.8) icon in JPEG 2000 or PNG format
+                ic11    varies                  32     10.8    16x16@2x 'retina' icon in JPEG 2000 or PNG format
+                ic12    varies                  64     10.8    32x32@2x 'retina' icon in JPEG 2000 or PNG format
+                ic13    varies                 256     10.8    128x128@2x 'retina' icon in JPEG 2000 or PNG format
+                ic14    varies                 512     10.8    256x256@2x 'retina' icon in JPEG 2000 or PNG format
+
+     Other types (ignored):
+               'TOC '   varies          'Table of Contents' 
+                                        a list of all image types in the file, 
+                                        and their sizes (added in Mac OS X 10.7)
+
+                'icnV'  4               4-byte big endian float 
+                                        - equal to the bundle version number of Icon Composer.app that created to icon
+
     [See also:]
         Image Form Icon
         GIFReader JPEGReader PNGReader TIFFReader WindowsIconReader
@@ -125,7 +170,7 @@
 
     imageCount := 0.
     [ sizeRemaining > 0 ] whileTrue:[
-        chunkType := aStream nextBytes:4.
+        chunkType := aStream next:4.
         chunkType size ~~ 4 ifTrue:[
             ^ self fileFormatError:'not an icns file (short read on icon type)'.
         ].
@@ -134,7 +179,7 @@
         numChunkBytes := aStream nextUnsignedInt32MSB:true.
         numChunkBytes := numChunkBytes - 4 - 4. "/ type and size are included in count
 
-        chunkData := aStream next:numChunkBytes.
+        chunkData := aStream nextBytes:numChunkBytes.
         sizeRemaining := sizeRemaining - 4 - 4 - numChunkBytes.
 
         img := self readSingleIcon:chunkType from:chunkData.
@@ -164,16 +209,22 @@
     "
      Image fromFile:'/Applications/TextEdit.app/Contents/Resources/txt.icns'
     "
+
+    "Modified: / 22-02-2017 / 10:24:38 / cg"
 !
 
 readSingleIcon:iconType from:iconBytes
     "read a single image from the inputStream."
 
+    Logger info:'ICNSReader: read %1' with:iconType.
+
     ^ Error handle:[:ex |
-        self fileFormatError:'internal error / unhandled icon format: ',iconType.
+        self fileFormatError:'internal error while reading: ',iconType.
         nil
     ] do:[
-        self 
+        |img|
+
+        img := self 
             perform:('read_',(iconType copyReplaceAny:#( $# $ ) with:$_),'_from:') asSymbol 
             with:iconBytes
             ifNotUnderstood:[
@@ -182,6 +233,8 @@
                 self fileFormatError:'unsupported icon format: ',iconType.
                 nil
             ].
+        img inspect.    
+        img    
     ].
 
     "
@@ -190,6 +243,7 @@
     "
 
     "Modified: / 08-02-2017 / 19:08:05 / stefan"
+    "Modified: / 22-02-2017 / 10:26:42 / cg"
 ! !
 
 !MacOSXIconReader methodsFor:'image writing'!
@@ -253,7 +307,8 @@
      'test.icns' asFilename exists.
 
      Image fromFile:'test.icns'
-     
+
+     ImageSequence
      MacOSXIconReader
          saveAll:{
                     (Image fromScreen:(0@0 corner:16@16)) .
@@ -264,7 +319,7 @@
          onFile:'test.icns'   
     "
 
-    "Modified (comment): / 22-02-2017 / 00:57:58 / cg"
+    "Modified (comment): / 22-02-2017 / 01:06:48 / cg"
 ! !
 
 !MacOSXIconReader methodsFor:'private'!
@@ -589,7 +644,10 @@
 
     |img|
 
-    img := PNGReader fromStream:(bytes readStream).
+    "/ check for PNG header
+    (bytes startsWith:(PNGReader pngHeader)) ifTrue:[
+        img := PNGReader fromStream:(bytes readStream).
+    ].    
     img isNil ifTrue:[
         img := JPEGReader fromStream:(bytes readStream).
     ].
@@ -598,11 +656,15 @@
         self assert:(img height = expectedSizeOrNil).
     ].
     ^ img
+
+    "Modified: / 22-02-2017 / 11:01:58 / cg"
 !
 
 readPackBitsImageFrom:compressedData offset:offset width:w height:h depth:depth
-    |redData greenData blueData bytesPerRow bytesPerChannel n srcStart rowStart|
+    |uncompressed redData greenData blueData bytesPerRow bytesPerChannel n srcStart rowStart|
 
+    uncompressed := (compressedData size - offset) >= (w*h*(depth//8)).
+    
     depth == 24 ifTrue:[
         "/ rgb channels separate
         bytesPerRow := w.
@@ -611,17 +673,24 @@
         redData := ByteArray new:bytesPerChannel.
         greenData := ByteArray new:bytesPerChannel.
         blueData := ByteArray new:bytesPerChannel.
+
+        "/ uncompressed!!
+        uncompressed ifTrue:[
+            self halt:'check this'.
+            ^ nil
+        ].
+        
         srcStart := 1+offset.
         n := self class
-            decompressPackBitsFrom:compressedData at:srcStart to:redData at:1 count:bytesPerChannel.
+            decompressPackBitsV2From:compressedData at:srcStart to:redData at:1 count:bytesPerChannel.
         srcStart := srcStart + n.
         n := self class
-            decompressPackBitsFrom:compressedData at:srcStart to:greenData at:1 count:bytesPerChannel.
+            decompressPackBitsV2From:compressedData at:srcStart to:greenData at:1 count:bytesPerChannel.
         srcStart := srcStart + n.
         n := self class
-            decompressPackBitsFrom:compressedData at:srcStart to:blueData at:1 count:bytesPerChannel.
+            decompressPackBitsV2From:compressedData at:srcStart to:blueData at:1 count:bytesPerChannel.
         photometric := #rgb.
-        bitsPerSample := #(8 8 8).
+        bitsPerSample := #[8 8 8].
         samplesPerPixel := 3.
         width := w.
         height := h.
@@ -650,6 +719,7 @@
             bits:data
             mask:nil.
     ].
+    
     depth == 8 ifTrue:[
         "/ 8bit single channel
         bytesPerRow := w.
@@ -660,7 +730,7 @@
         ] ifFalse:[
             data := ByteArray new:bytesPerChannel.
             n := self class
-                decompressPackBitsFrom:compressedData at:1+offset to:data at:1 count:bytesPerChannel.
+                decompressPackBitsV2From:compressedData at:1+offset to:data at:1 count:bytesPerChannel.
         ].
         ^ Depth8Image new
             width:width height:height
@@ -669,8 +739,10 @@
             colorMap:nil
             bits:data mask:nil.
     ].
-self halt.
+    self halt:'check this'.
     ^ nil
+
+    "Modified: / 22-02-2017 / 12:06:14 / cg"
 !
 
 read_ICN__from:bytes
@@ -711,11 +783,20 @@
 read_h8mk_from:bytes
     "read an h8mk packbits format mask icon"
 
-    ^ self readPackBitsImageFrom:bytes asByteArray offset:0 width:48 height:48 depth:8.
+    |offset|
+
+    offset := 0.
+    (bytes from:1 to:4) = #[0 0 0 0] ifTrue:[
+        self halt.
+        offset := 4.
+    ].    
+    ^ self readPackBitsImageFrom:bytes asByteArray offset:offset width:48 height:48 depth:8.
+
+    "Modified: / 22-02-2017 / 10:32:07 / cg"
 !
 
 read_ic07_from:bytes
-    "read an ic07 (PNG or JPEG, 128) format icon"
+    "read an ic07 (PNG or JPEG, 128x128) format icon"
 
     ^ self readPNGOrJPEGFrom:bytes expectedSize:128.
 
@@ -723,10 +804,12 @@
      self fromFile:'/Applications/TextEdit.app/Contents/Resources/txt.icns'
      self fromFile:'test.icns'
     "
+
+    "Modified (comment): / 22-02-2017 / 11:02:50 / cg"
 !
 
 read_ic08_from:bytes
-    "read an ic08 (PNG or JPEG, 256) format icon"
+    "read an ic08 (PNG or JPEG, 256x256) format icon"
 
     ^ self readPNGOrJPEGFrom:bytes expectedSize:256.
 
@@ -734,10 +817,12 @@
      self fromFile:'/Applications/TextEdit.app/Contents/Resources/txt.icns'
      self fromFile:'test.icns'
     "
+
+    "Modified (comment): / 22-02-2017 / 11:02:55 / cg"
 !
 
 read_ic09_from:bytes
-    "read an ic09 (PNG or JPEG, 512) format icon"
+    "read an ic09 (PNG or JPEG, 512x512) format icon"
 
     ^ self readPNGOrJPEGFrom:bytes expectedSize:512.
 
@@ -745,10 +830,12 @@
      self fromFile:'/Applications/TextEdit.app/Contents/Resources/txt.icns'
      self fromFile:'test.icns'
     "
+
+    "Modified (comment): / 22-02-2017 / 11:03:00 / cg"
 !
 
 read_ic10_from:bytes
-    "read an ic10 (PNG or JPEG, 1024) format icon"
+    "read an ic10 (PNG or JPEG, 1024x1024) format icon"
 
     ^ self readPNGOrJPEGFrom:bytes expectedSize:1024.
 
@@ -756,6 +843,21 @@
      self fromFile:'/Applications/TextEdit.app/Contents/Resources/txt.icns'
      self fromFile:'test.icns'
     "
+
+    "Modified (comment): / 22-02-2017 / 11:03:05 / cg"
+!
+
+read_ic11_from:bytes
+    "read an ic11 (PNG or JPEG, 32x32) format icon"
+
+    ^ self readPNGOrJPEGFrom:bytes expectedSize:32.
+
+    "
+     self fromFile:'/Applications/TextEdit.app/Contents/Resources/txt.icns'
+     self fromFile:'test.icns'
+    "
+
+    "Created: / 22-02-2017 / 11:04:18 / cg"
 !
 
 read_ich4_from:bytes
@@ -855,15 +957,33 @@
 !
 
 read_ih32_from:bytes
-    "read an ih32 packbits format icon"
+    "read an ih32 packbits format 48x48x24 icon "
+
+    |offset|
 
-    ^ self readPackBitsImageFrom:bytes asByteArray offset:0  width:48 height:48 depth:24.
+    offset := 0.
+    (bytes from:1 to:4) = #[0 0 0 0] ifTrue:[
+        self halt.
+        offset := 4.
+    ].    
+    ^ self readPackBitsImageFrom:bytes asByteArray offset:offset width:48 height:48 depth:24.
+
+    "Modified (comment): / 22-02-2017 / 10:58:51 / cg"
 !
 
 read_il32_from:bytes
-    "read an il32 packbits format icon"
+    "read an il32 packbits format 32x32x24 icon"
+
+    |offset|
 
-    ^ self readPackBitsImageFrom:bytes asByteArray offset:0  width:32 height:32 depth:24.
+    offset := 0.
+    (bytes from:1 to:4) = #[0 0 0 0] ifTrue:[
+        self halt.
+        offset := 4.
+    ].    
+    ^ self readPackBitsImageFrom:bytes asByteArray offset:offset width:32 height:32 depth:24.
+
+    "Modified (comment): / 22-02-2017 / 10:59:19 / cg"
 !
 
 read_ipc4_from:bytes
@@ -878,7 +998,7 @@
 !
 
 read_ipc5_from:bytes
-    "read an ipc5 (PNG or JPEG, 32) format icon"
+    "read an ipc5 (PNG or JPEG, 32x32) format icon"
 
     ^ self readPNGOrJPEGFrom:bytes expectedSize:32.
 
@@ -886,40 +1006,84 @@
      self fromFile:'/Applications/TextEdit.app/Contents/Resources/txt.icns'
      self fromFile:'test.icns'
     "
+
+    "Modified (comment): / 22-02-2017 / 11:02:44 / cg"
 !
 
 read_is32_from:bytes
     "read an is32 packbits format 16x16x24 icon"
 
-    ^ self readPackBitsImageFrom:bytes asByteArray offset:0 width:16 height:16 depth:24.
+    |offset|
+
+    offset := 0.
+    (bytes from:1 to:4) = #[0 0 0 0] ifTrue:[
+        self halt.
+        offset := 4.
+    ].    
+    ^ self readPackBitsImageFrom:bytes asByteArray offset:offset width:16 height:16 depth:24.
+
+    "Modified: / 22-02-2017 / 10:32:25 / cg"
 !
 
 read_it32_from:bytes
     "read an it32 packbits format 128x128x24 icon"
 
-    ^ self readPackBitsImageFrom:bytes asByteArray offset:4 width:128 height:128 depth:24.
+    |offset|
+
+    offset := 0.
+    (bytes from:1 to:4) = #[0 0 0 0] ifTrue:[
+        self halt.
+        offset := 4.
+    ].    
+    ^ self readPackBitsImageFrom:bytes asByteArray offset:offset width:128 height:128 depth:24.
 
     "
      self fromFile:'/Applications/TextEdit.app/Contents/Resources/txt.icns'
     "
+
+    "Modified: / 22-02-2017 / 10:32:02 / cg"
 !
 
 read_l8mk_from:bytes
     "read an l8mk packbits format mask icon"
 
-    ^ self readPackBitsImageFrom:bytes asByteArray offset:0  width:32 height:32 depth:8.
+    |offset|
+
+    offset := 0.
+    (bytes from:1 to:4) = #[0 0 0 0] ifTrue:[
+        self halt.
+        offset := 4.
+    ].    
+    ^ self readPackBitsImageFrom:bytes asByteArray offset:offset width:32 height:32 depth:8.
+
+    "Modified: / 22-02-2017 / 10:32:34 / cg"
 !
 
 read_s8mk_from:bytes
     "read an s8mk packbits format mask icon"
 
-    ^ self readPackBitsImageFrom:bytes asByteArray offset:0  width:16 height:16 depth:8.
+    |offset|
+
+    offset := 0.
+    (bytes from:1 to:4) = #[0 0 0 0] ifTrue:[
+        offset := 4.
+    ].    
+    ^ self readPackBitsImageFrom:bytes asByteArray offset:offset width:16 height:16 depth:8.
+
+    "Modified: / 22-02-2017 / 10:34:46 / cg"
 !
 
 read_t8mk_from:bytes
-    "read an t8mk packbits format mask icon"
+    "read an t8mk 128x128x8 mask icon"
+
+    |img|
 
-    ^ self readPackBitsImageFrom:bytes asByteArray offset:0 width:64 height:64 depth:8.
+    self assert:(bytes size == (128*128)).
+    img := Depth8Image width:128 height:128 fromArray:bytes.
+    img photometric:#whiteIs0.
+    ^ img
+
+    "Modified (comment): / 22-02-2017 / 12:00:50 / cg"
 ! !
 
 !MacOSXIconReader class methodsFor:'documentation'!