--- 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'!