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:
| M | reader.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 {