-
Notifications
You must be signed in to change notification settings - Fork 0
/
database.go
109 lines (92 loc) · 2.11 KB
/
database.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package disgo
import (
"encoding"
"errors"
"image"
"io"
"io/ioutil"
"github.com/disintegration/imaging"
)
var (
ErrNotFound = errors.New("Image not found")
ErrNotSupported = errors.New("Underlying index does not support loading or saving")
)
type Index interface {
Insert(PHash) error
Search(PHash, int) ([]PHash, error)
}
type DB struct {
index Index
hasher func(image.Image) (PHash, error)
}
func New() *DB {
return NewDB(NewRadixIndex())
}
func NewDB(index Index) *DB {
r := &DB{
index: index,
hasher: Hash,
}
return r
}
func (db *DB) Add(img image.Image) (PHash, error) {
hash, err := db.hasher(img)
if err == nil {
err = db.AddHash(hash)
}
return hash, err
}
func (db *DB) AddFile(reader io.Reader) (hash PHash, err error) {
img, err := imaging.Decode(reader)
if err == nil {
hash, err = db.Add(img)
}
return hash, err
}
func (db *DB) AddHash(hash PHash) error {
db.index.Insert(hash)
return nil
}
func (db *DB) Save(writer io.Writer) error {
buf, err := db.MarshalBinary()
if err == nil {
_, err = writer.Write(buf)
}
return err
}
func (db *DB) MarshalBinary() ([]byte, error) {
if marshaler, ok := db.index.(encoding.BinaryMarshaler); ok {
return marshaler.MarshalBinary()
}
return nil, ErrNotSupported
}
func (db *DB) Load(reader io.Reader) error {
buf, err := ioutil.ReadAll(reader)
if err == nil {
err = db.UnmarshalBinary(buf)
}
return err
}
func (db *DB) UnmarshalBinary(buf []byte) error {
if unmarshaler, ok := db.index.(encoding.BinaryUnmarshaler); ok {
return unmarshaler.UnmarshalBinary(buf)
}
return ErrNotSupported
}
func (db *DB) Search(img image.Image, maxDistance int) (matches []PHash, err error) {
hash, err := db.hasher(img)
if err == nil {
matches, err = db.SearchByHash(hash, maxDistance)
}
return matches, err
}
func (db *DB) SearchByFile(reader io.Reader, maxDistance int) (matches []PHash, err error) {
img, err := imaging.Decode(reader)
if err == nil {
matches, err = db.Search(img, maxDistance)
}
return matches, err
}
func (db *DB) SearchByHash(hash PHash, maxDistance int) ([]PHash, error) {
return db.index.Search(hash, maxDistance)
}