icns

Easily create .icns files (Mac Icons) with this Go library or the included CLI.
Log | Files | Refs | LICENSE

commit 05f19e01c8d9cd97f171eaf6a5d469129e9e97af
parent a422e6afe37279c7d99291ae910e3c39f95d715b
Author: Jack Mordaunt <jackmordaunt@gmail.com>
Date:   Thu,  6 May 2021 17:18:06 +0800

feat(DecodeAll): export func that returns all decoded images

Diffstat:
Mreader.go | 67+++++++++++++++++++++++++++++++++++++++++++------------------------
1 file changed, 43 insertions(+), 24 deletions(-)

diff --git a/reader.go b/reader.go @@ -7,8 +7,6 @@ import ( "image" "io" "io/ioutil" - - "github.com/pkg/errors" ) var jpeg2000header = []byte{0x00, 0x00, 0x00, 0x0c, 0x6a, 0x50, 0x20, 0x20} @@ -17,44 +15,75 @@ var jpeg2000header = []byte{0x00, 0x00, 0x00, 0x0c, 0x6a, 0x50, 0x20, 0x20} // ignoring all other sizes. The format returned will be whatever the icon data // is, typically jpeg or png. func Decode(r io.Reader) (image.Image, error) { + icons, err := decode(r) + if err != nil { + return nil, err + } + var biggest iconReader + for _, icon := range icons { + if icon.Size > biggest.Size { + biggest = icon + } + } + img, _, err := image.Decode(biggest.r) + if err != nil { + return nil, fmt.Errorf("decoding largest image: %w", err) + } + return img, nil +} + +// DecodeAll extracts all icon resolutions present in the icns data. +func DecodeAll(r io.Reader) (images []image.Image, err error) { + icons, err := decode(r) + if err != nil { + return nil, err + } + for _, icon := range icons { + img, _, err := image.Decode(icon.r) + if err != nil { + return nil, fmt.Errorf("decoding %q icon: %w", icon.OsType, err) + } + images = append(images, img) + } + return images, nil +} + +func decode(r io.Reader) (icons []iconReader, err error) { data, err := ioutil.ReadAll(r) if err != nil { return nil, err } - icnsHeader := data[0:4] - if string(icnsHeader) != "icns" { + var ( + header = data[0:4] + fileSize = binary.BigEndian.Uint32(data[4:8]) + read = uint32(8) + ) + if string(header) != "icns" { return nil, fmt.Errorf("invalid header for icns file") } - fileSize := binary.BigEndian.Uint32(data[4:8]) - icons := []iconReader{} - read := uint32(8) for read < fileSize { next := data[read : read+4] read += 4 switch string(next) { case "TOC ": tocSize := binary.BigEndian.Uint32(data[read : read+4]) - read += tocSize-4 // size includes header and size fields + read += tocSize - 4 // size includes header and size fields continue case "icnV": read += 4 continue } - dataSize := binary.BigEndian.Uint32(data[read : read+4]) read += 4 if dataSize == 0 { continue // no content, we're not interested } - iconData := data[read : read+dataSize-8] - read += dataSize-8 // size includes header and size fields - + read += dataSize - 8 // size includes header and size fields if isOsType(string(next)) { if bytes.Equal(iconData[:8], jpeg2000header) { continue // skipping JPEG2000 } - icons = append(icons, iconReader{ OsType: osTypeFromID(string(next)), r: bytes.NewBuffer(iconData), @@ -64,17 +93,7 @@ func Decode(r io.Reader) (image.Image, error) { if len(icons) == 0 { return nil, fmt.Errorf("no icons found") } - var biggest iconReader - for _, icon := range icons { - if icon.Size > biggest.Size { - biggest = icon - } - } - img, _, err := image.Decode(biggest.r) - if err != nil { - return nil, errors.Wrap(err, "decoding largest image") - } - return img, nil + return icons, nil } type iconReader struct {