diff --git a/README.md b/README.md index d8ba215..03570da 100644 --- a/README.md +++ b/README.md @@ -45,8 +45,8 @@ func main() { ## Release Note ### v0.4.0(TBA) -- **IMPORTANT** goimagehash does not have compatible with the before version -when it comes to the serialization based on string. bit set order is changed. +- **IMPORTANT** goimagehash v0.0.4 does not have compatible with the before +version when it comes to the serialization. ### v0.3.0 - Support DifferenceHashExtend. diff --git a/_examples/examples.go b/_examples/examples.go index 5abf37f..67c056f 100644 --- a/_examples/examples.go +++ b/_examples/examples.go @@ -25,8 +25,8 @@ func main() { distance, _ = hash1.Distance(hash2) fmt.Printf("Distance between images: %v\n", distance) - hash1, _ = goimagehash.PerceptionHash(img1) - hash2, _ = goimagehash.PerceptionHash(img2) - distance, _ = hash1.Distance(hash2) - fmt.Printf("Distance between images: %v\n", distance) + hash1, _ = goimagehash.PerceptionHash(img1) + hash2, _ = goimagehash.PerceptionHash(img2) + distance, _ = hash1.Distance(hash2) + fmt.Printf("Distance between images: %v\n", distance) } diff --git a/_examples/load_and_dump.go b/_examples/load_and_dump.go new file mode 100644 index 0000000..b639bef --- /dev/null +++ b/_examples/load_and_dump.go @@ -0,0 +1,43 @@ +package main + +import ( + "bufio" + "bytes" + "fmt" + "github.com/corona10/goimagehash" + "image/jpeg" + "os" +) + +func main() { + file1, _ := os.Open("sample1.jpg") + file2, _ := os.Open("sample2.jpg") + defer file1.Close() + defer file2.Close() + var b bytes.Buffer + foo := bufio.NewWriter(&b) + img1, _ := jpeg.Decode(file1) + img2, _ := jpeg.Decode(file2) + hash1, _ := goimagehash.AverageHashExtend(img1, 15) + hash2, _ := goimagehash.AverageHashExtend(img2, 15) + distance, _ := hash1.Distance(hash2) + fmt.Printf("Distance between images: %v\n", distance) + + err := hash1.Dump(foo) + if err != nil { + fmt.Println(err) + } + foo.Flush() + bar := bufio.NewReader(&b) + hash3, err := goimagehash.LoadImageHashExtend(bar) + if err != nil { + fmt.Println(err) + } + distance, _ = hash1.Distance(hash3) + fmt.Printf("Distance between hash1 and hash3: %v\n", distance) + distance, _ = hash2.Distance(hash3) + fmt.Printf("Distance between hash2 and hash3: %v\n", distance) + fmt.Println(hash1.ToString()) + fmt.Println(hash2.ToString()) + fmt.Println(hash3.ToString()) +} diff --git a/imagehash.go b/imagehash.go index e62746f..9072807 100644 --- a/imagehash.go +++ b/imagehash.go @@ -6,9 +6,11 @@ package goimagehash import ( "encoding/binary" + "encoding/gob" "encoding/hex" "errors" "fmt" + "io" ) // Kind describes the kinds of hash. @@ -73,7 +75,38 @@ func (h *ImageHash) leftShiftSet(idx int) { const strFmt = "%1s:%016x" +// Dump method writes a binary serialization into w io.Writer. +func (h *ImageHash) Dump(w io.Writer) error { + type D struct { + Hash uint64 + Kind Kind + } + enc := gob.NewEncoder(w) + err := enc.Encode(D{Hash: h.hash, Kind: h.kind}) + if err != nil { + return err + } + return nil +} + +// LoadImageHash method loads a ExtImageHash from io.Reader. +func LoadImageHash(b io.Reader) (*ImageHash, error) { + type E struct { + Hash uint64 + Kind Kind + } + var e E + dec := gob.NewDecoder(b) + err := dec.Decode(&e) + if err != nil { + return nil, err + } + return &ImageHash{hash: e.Hash, kind: e.Kind}, nil +} + // ImageHashFromString returns an image hash from a hex representation +// +// Deprecated: Use goimagehash.LoadImageHash instead. func ImageHashFromString(s string) (*ImageHash, error) { var kindStr string var hash uint64 @@ -148,9 +181,40 @@ func (h *ExtImageHash) GetKind() Kind { return h.kind } +// Dump method writes a binary serialization into w io.Writer. +func (h *ExtImageHash) Dump(w io.Writer) error { + type D struct { + Hash []uint64 + Kind Kind + } + enc := gob.NewEncoder(w) + err := enc.Encode(D{Hash: h.hash, Kind: h.kind}) + if err != nil { + return err + } + return nil +} + +// LoadImageHashExtend method loads a ExtImageHash from io.Reader. +func LoadImageHashExtend(b io.Reader) (*ExtImageHash, error) { + type E struct { + Hash []uint64 + Kind Kind + } + var e E + dec := gob.NewDecoder(b) + err := dec.Decode(&e) + if err != nil { + return nil, err + } + return &ExtImageHash{hash: e.Hash, kind: e.Kind}, nil +} + const extStrFmt = "%1s:%s" // ExtImageHashFromString returns a big hash from a hex representation +// +// Deprecated: Use goimagehash.LoadImageHashExtend instead. func ExtImageHashFromString(s string) (*ExtImageHash, error) { var kindStr string var hashStr string diff --git a/imagehash_test.go b/imagehash_test.go index 0bca9f0..ae90f2f 100644 --- a/imagehash_test.go +++ b/imagehash_test.go @@ -5,6 +5,8 @@ package goimagehash import ( + "bufio" + "bytes" "errors" "image" _ "image/jpeg" @@ -124,3 +126,76 @@ func TestSerialization(t *testing.T) { } } } + +func TestDumpAndLoad(t *testing.T) { + checkErr := func(err error) { + if err != nil { + t.Errorf("%v", err) + } + } + + methods := []func(img image.Image) (*ImageHash, error){ + AverageHash, PerceptionHash, DifferenceHash, + } + examples := []string{ + "_examples/sample1.jpg", "_examples/sample2.jpg", "_examples/sample3.jpg", "_examples/sample4.jpg", + } + + for _, ex := range examples { + file, err := os.Open(ex) + checkErr(err) + + defer file.Close() + + img, _, err := image.Decode(file) + checkErr(err) + + for _, method := range methods { + hash, err := method(img) + checkErr(err) + var b bytes.Buffer + foo := bufio.NewWriter(&b) + err = hash.Dump(foo) + checkErr(err) + foo.Flush() + bar := bufio.NewReader(&b) + reHash, err := LoadImageHash(bar) + checkErr(err) + + distance, err := hash.Distance(reHash) + checkErr(err) + + if distance != 0 { + t.Errorf("Original and unserialized objects should be identical, got distance=%v", distance) + } + } + + // test for ExtIExtImageHash + extMethods := []func(img image.Image, hashSize int) (*ExtImageHash, error){ + AverageHashExtend, PerceptionHashExtend, DifferenceHashExtend, + } + + hashSizeList := []int{8, 16} + for _, hashSize := range hashSizeList { + for _, method := range extMethods { + hash, err := method(img, hashSize) + checkErr(err) + var b bytes.Buffer + foo := bufio.NewWriter(&b) + err = hash.Dump(foo) + checkErr(err) + foo.Flush() + bar := bufio.NewReader(&b) + reHash, err := LoadImageHashExtend(bar) + checkErr(err) + + distance, err := hash.Distance(reHash) + checkErr(err) + + if distance != 0 { + t.Errorf("Original and unserialized objects should be identical, got distance=%v", distance) + } + } + } + } +}