-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Migrate to go-flac v2 (go-flac/go-flac#5)
Signed-off-by: eternal-flame-AD <[email protected]>
- Loading branch information
1 parent
c2bd6c3
commit 90a5473
Showing
8 changed files
with
378 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package flacpicture | ||
|
||
import "errors" | ||
|
||
var ( | ||
// ErrorNotPictureMetadataBlock is returned if the metadata provided is not a picture block. | ||
ErrorNotPictureMetadataBlock = errors.New("Not a picture metadata block") | ||
// ErrorUnsupportedMIME is returned if the provided image MIME type is unsupported. | ||
ErrorUnsupportedMIME = errors.New("Unsupported MIME") | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
module github.com/go-flac/flacpicture/v2 | ||
|
||
go 1.20 | ||
|
||
require github.com/go-flac/go-flac v1.0.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
github.com/go-flac/go-flac v1.0.0 h1:6qI9XOVLcO50xpzm3nXvO31BgDgHhnr/p/rER/K/doY= | ||
github.com/go-flac/go-flac v1.0.0/go.mod h1:WnZhcpmq4u1UdZMNn9LYSoASpWOCMOoxXxcWEHSzkW8= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package flacpicture | ||
|
||
import ( | ||
"bytes" | ||
"image/jpeg" | ||
"image/png" | ||
) | ||
|
||
// ParsePicture decodes the image and inflates the Width, Height, ColorDepth, IndexedColorCount fields. This is called automatically by NewFromImageData | ||
func (c *MetadataBlockPicture) ParsePicture() error { | ||
switch c.MIME { | ||
case "image/jpeg": | ||
img, err := jpeg.Decode(bytes.NewReader(c.ImageData)) | ||
if err != nil { | ||
return err | ||
} | ||
c.IndexedColorCount = uint32(0) | ||
size := img.Bounds() | ||
c.Width = uint32(size.Max.X) | ||
c.Height = uint32(size.Max.Y) | ||
c.ColorDepth = uint32(24) | ||
case "image/png": | ||
img, err := png.Decode(bytes.NewReader(c.ImageData)) | ||
if err != nil { | ||
return err | ||
} | ||
c.IndexedColorCount = uint32(0) | ||
size := img.Bounds() | ||
c.Width = uint32(size.Max.X) | ||
c.Height = uint32(size.Max.Y) | ||
c.ColorDepth = uint32(32) | ||
default: | ||
return ErrorUnsupportedMIME | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
package flacpicture | ||
|
||
import ( | ||
"bytes" | ||
|
||
flac "github.com/go-flac/go-flac" | ||
) | ||
|
||
// PictureType defines the type of this image | ||
type PictureType uint32 | ||
|
||
const ( | ||
PictureTypeOther PictureType = iota | ||
PictureTypeFileIcon | ||
PictureTypeOtherIcon | ||
PictureTypeFrontCover | ||
PictureTypeBackCover | ||
PictureTypeLeaflet | ||
PictureTypeMedia | ||
PictureTypeLeadArtist | ||
PictureTypeArtist | ||
PictureTypeConductor | ||
PictureTypeBand | ||
PictureTypeComposer | ||
PictureTypeLyricist | ||
PictureTypeRecordingLocation | ||
PictureTypeDuringRecording | ||
PictureTypeDuringPerformance | ||
PictureTypeScreenCapture | ||
PictureTypeBrightColouredFish | ||
PictureTypeIllustration | ||
PictureTypeBandArtistLogotype | ||
PictureTypePublisherStudioLogotype | ||
) | ||
|
||
// MetadataBlockPicture represents a picture metadata block | ||
type MetadataBlockPicture struct { | ||
PictureType PictureType | ||
MIME string | ||
Description string | ||
Width uint32 | ||
Height uint32 | ||
ColorDepth uint32 | ||
IndexedColorCount uint32 | ||
ImageData []byte | ||
} | ||
|
||
// Marshal encodes the PictureBlock to a standard FLAC MetaDataBlock to be accepted by go-flac | ||
func (c *MetadataBlockPicture) Marshal() flac.MetaDataBlock { | ||
res := bytes.NewBuffer([]byte{}) | ||
res.Write(encodeUint32(uint32(c.PictureType))) | ||
res.Write(encodeUint32(uint32(len(c.MIME)))) | ||
res.Write([]byte(c.MIME)) | ||
res.Write(encodeUint32(uint32(len(c.Description)))) | ||
res.Write([]byte(c.Description)) | ||
res.Write(encodeUint32(c.Width)) | ||
res.Write(encodeUint32(c.Height)) | ||
res.Write(encodeUint32(c.ColorDepth)) | ||
res.Write(encodeUint32(c.IndexedColorCount)) | ||
res.Write(encodeUint32(uint32(len(c.ImageData)))) | ||
res.Write(c.ImageData) | ||
return flac.MetaDataBlock{ | ||
Type: flac.Picture, | ||
Data: res.Bytes(), | ||
} | ||
} | ||
|
||
// NewFromImageData generates a MetadataBlockPicture from image data, returns an error if the picture data connot be parsed | ||
func NewFromImageData(pictype PictureType, description string, imgdata []byte, mime string) (*MetadataBlockPicture, error) { | ||
res := new(MetadataBlockPicture) | ||
res.PictureType = pictype | ||
res.Description = description | ||
res.MIME = mime | ||
res.ImageData = imgdata | ||
err := res.ParsePicture() | ||
return res, err | ||
} | ||
|
||
// ParseFromMetaDataBlock parses an existing picture MetaDataBlock | ||
func ParseFromMetaDataBlock(meta flac.MetaDataBlock) (*MetadataBlockPicture, error) { | ||
if meta.Type != flac.Picture { | ||
return nil, ErrorNotPictureMetadataBlock | ||
} | ||
res := new(MetadataBlockPicture) | ||
data := bytes.NewBuffer(meta.Data) | ||
|
||
if pictype, err := readUint32(data); err != nil { | ||
return nil, err | ||
} else { | ||
res.PictureType = PictureType(pictype) | ||
} | ||
|
||
if mimebytes, err := readBytesWith32bitSize(data); err != nil { | ||
return nil, err | ||
} else { | ||
res.MIME = string(mimebytes) | ||
} | ||
|
||
if descbytes, err := readBytesWith32bitSize(data); err != nil { | ||
return nil, err | ||
} else { | ||
res.Description = string(descbytes) | ||
} | ||
|
||
if width, err := readUint32(data); err != nil { | ||
return nil, err | ||
} else { | ||
res.Width = width | ||
} | ||
|
||
if height, err := readUint32(data); err != nil { | ||
return nil, err | ||
} else { | ||
res.Height = height | ||
} | ||
|
||
if depth, err := readUint32(data); err != nil { | ||
return nil, err | ||
} else { | ||
res.ColorDepth = depth | ||
} | ||
|
||
if count, err := readUint32(data); err != nil { | ||
return nil, err | ||
} else { | ||
res.IndexedColorCount = count | ||
} | ||
|
||
if pic, err := readBytesWith32bitSize(data); err != nil { | ||
return nil, err | ||
} else { | ||
res.ImageData = pic | ||
} | ||
|
||
return res, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
package flacpicture | ||
|
||
import ( | ||
"archive/zip" | ||
"bytes" | ||
"fmt" | ||
"io/ioutil" | ||
"net/http" | ||
"testing" | ||
|
||
flac "github.com/go-flac/go-flac" | ||
) | ||
|
||
func httpGetBytes(url string) ([]byte, error) { | ||
res, err := http.Get(url) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if res.StatusCode != 200 { | ||
return nil, fmt.Errorf("HTTP status %d", res.StatusCode) | ||
} | ||
return ioutil.ReadAll(res.Body) | ||
} | ||
|
||
func TestPNGPictureDecode(t *testing.T) { | ||
imgdata, err := httpGetBytes("https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png") | ||
if err != nil { | ||
t.Errorf("Error while downloading test file: %s", err.Error()) | ||
t.FailNow() | ||
} | ||
pic, err := NewFromImageData(PictureTypeArtist, "test description", imgdata, "image/png") | ||
if err != nil { | ||
t.Errorf("Error while constructing image data: %s", err.Error()) | ||
t.Fail() | ||
} | ||
|
||
if pic.MIME != "image/png" { | ||
t.Errorf("MIME decode error: got %s", pic.MIME) | ||
t.Fail() | ||
} | ||
|
||
if pic.Height != 600 || pic.Width != 800 { | ||
t.Errorf("JPEG size error: got %dx%d", pic.Width, pic.Height) | ||
t.Fail() | ||
} | ||
} | ||
func TestJPEGPictureDecode(t *testing.T) { | ||
imgdata, err := httpGetBytes("https://jpeg.org/images/jpeg-home.jpg") | ||
if err != nil { | ||
t.Errorf("Error while downloading test file: %s", err.Error()) | ||
t.FailNow() | ||
} | ||
pic, err := NewFromImageData(PictureTypeArtist, "test description", imgdata, "image/jpeg") | ||
if err != nil { | ||
t.Errorf("Error while constructing image data: %s", err.Error()) | ||
t.Fail() | ||
} | ||
|
||
if pic.MIME != "image/jpeg" { | ||
t.Errorf("MIME decode error: got %s", pic.MIME) | ||
t.Fail() | ||
} | ||
|
||
if pic.Height != 400 || pic.Width != 800 { | ||
t.Errorf("JPEG size error: got %dx%d", pic.Width, pic.Height) | ||
t.Fail() | ||
} | ||
} | ||
|
||
func TestPictureModify(t *testing.T) { | ||
imgdata, err := httpGetBytes("https://jpeg.org/images/jpeg-home.jpg") | ||
if err != nil { | ||
t.Errorf("Error while downloading test file: %s", err.Error()) | ||
t.FailNow() | ||
} | ||
pic, err := NewFromImageData(PictureTypeArtist, "test description", imgdata, "image/jpeg") | ||
if err != nil { | ||
t.Errorf("Error while constructing image data: %s", err.Error()) | ||
t.Fail() | ||
} | ||
|
||
pic.Description = "another description" | ||
|
||
pic, err = ParseFromMetaDataBlock(pic.Marshal()) | ||
if err != nil { | ||
t.Errorf("Error while parsing modified image data: %s", err.Error()) | ||
t.Fail() | ||
} | ||
|
||
if pic.Description != "another description" { | ||
t.Errorf("description unepected: %s", pic.Description) | ||
t.Fail() | ||
} | ||
} | ||
|
||
func TestJPEGFromExistingFLAC(t *testing.T) { | ||
zipdata, err := httpGetBytes("http://helpguide.sony.net/high-res/sample1/v1/data/Sample_BeeMoved_96kHz24bit.flac.zip") | ||
if err != nil { | ||
t.Errorf("Error while downloading test file: %s", err.Error()) | ||
t.FailNow() | ||
} | ||
zipfile, err := zip.NewReader(bytes.NewReader(zipdata), int64(len(zipdata))) | ||
if err != nil { | ||
t.Errorf("Error while decompressing test file: %s", err.Error()) | ||
t.FailNow() | ||
} | ||
if zipfile.File[0].Name != "Sample_BeeMoved_96kHz24bit.flac" { | ||
t.Errorf("Unexpected test file content: %s", zipfile.File[0].Name) | ||
t.FailNow() | ||
} | ||
|
||
flachandle, err := zipfile.File[0].Open() | ||
if err != nil { | ||
t.Errorf("Failed to decompress test file: %s", err) | ||
t.FailNow() | ||
} | ||
|
||
f, err := flac.ParseBytes(flachandle) | ||
if err != nil { | ||
t.Errorf("Failed to parse flac file: %s", err) | ||
t.FailNow() | ||
} | ||
|
||
var pic *MetadataBlockPicture | ||
for _, meta := range f.Meta { | ||
if meta.Type == flac.Picture { | ||
pic, err = ParseFromMetaDataBlock(*meta) | ||
if err != nil { | ||
t.Errorf("Error while parsing metadata image: %s", err.Error()) | ||
t.Fail() | ||
} | ||
} | ||
} | ||
if pic.PictureType != PictureTypeFrontCover { | ||
t.Error("Picture type does not match") | ||
t.Fail() | ||
} | ||
if pic.MIME != "image/jpeg" { | ||
t.Errorf("Picture MIME does not match: %s", pic.MIME) | ||
t.Fail() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package flacpicture | ||
|
||
import ( | ||
"bytes" | ||
"encoding/binary" | ||
"io" | ||
) | ||
|
||
func encodeUint32(n uint32) []byte { | ||
buf := bytes.NewBuffer([]byte{}) | ||
if err := binary.Write(buf, binary.BigEndian, n); err != nil { | ||
panic(err) | ||
} | ||
return buf.Bytes() | ||
} | ||
|
||
func readUint32(r io.Reader) (res uint32, err error) { | ||
err = binary.Read(r, binary.BigEndian, &res) | ||
return | ||
} | ||
|
||
func readBytesWith32bitSize(r io.Reader) (res []byte, err error) { | ||
var size uint32 | ||
size, err = readUint32(r) | ||
if err != nil { | ||
return | ||
} | ||
bufall := bytes.NewBuffer([]byte{}) | ||
for size > 0 { | ||
var nn int | ||
buf := make([]byte, size) | ||
nn, err = r.Read(buf) | ||
if err != nil { | ||
return | ||
} | ||
bufall.Write(buf) | ||
size -= uint32(nn) | ||
} | ||
res = bufall.Bytes() | ||
return | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package flacpicture | ||
|
||
const ( | ||
// MIMEURL is the MIME string indicating that imgData is a URL pointing to the image | ||
MIMEURL = "-->" | ||
) |