imagehash: Add new serialization API dump/load. (#24)

Create a new APIs for serializing purpose which can use
standard io.Reader/io.Writer APIs.

ToString() API will be remain for debugging purpose and
ExtImageHashFromString, ImageHashFromString will be removed after next
version.

- New APIs are added: LoadExtImageHash, LoadImageHash, xxxHash.Dump
- These APIs are deprecated: ExtImageHashFromString, ImageHashFromString
This commit is contained in:
Dong-hee Na 2019-03-17 11:34:56 +09:00 committed by GitHub
parent 7558e00b90
commit 84eb1859d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 188 additions and 6 deletions

View File

@ -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.

View File

@ -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)
}

View File

@ -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())
}

View File

@ -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

View File

@ -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)
}
}
}
}
}