From 222fecc3384ba1327ac4754d762f853f7d34f89b Mon Sep 17 00:00:00 2001 From: simon987 Date: Fri, 27 Dec 2019 13:29:41 -0500 Subject: [PATCH] Initial commit --- .gitignore | 3 + README.md | 25 ++++++ examples/phash.go | 14 ++++ fastimagehash.go | 201 ++++++++++++++++++++++++++++++++++++++++++++++ go.mod | 3 + 5 files changed, 246 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 examples/phash.go create mode 100644 fastimagehash.go create mode 100644 go.mod diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3b7898c --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea/ +pkg/ +*.iml diff --git a/README.md b/README.md new file mode 100644 index 0000000..2073b5c --- /dev/null +++ b/README.md @@ -0,0 +1,25 @@ +## fastimagehash-go + +[fastimagehash](https://github.com/simon987/fastimagehash) *cgo* bindings. + +The latest `libfastimagehash` version must be installed as system library +for `fastimagehash-go` to compile. + + +### Example usage +```go +package main + +import ( + "github.com/simon987/fastimagehash" + "fmt" +) + +func main() { + hash, ret := fastimagehash.PHashFile("/path/to/image.jpg", 8, 4) + + if ret == fastimagehash.Ok { + fmt.Printf("%s (%d)\n", hash.ToHexStringReversed(), ret) + } +} +``` \ No newline at end of file diff --git a/examples/phash.go b/examples/phash.go new file mode 100644 index 0000000..6f8681f --- /dev/null +++ b/examples/phash.go @@ -0,0 +1,14 @@ +package main + +import ( + "fastimagehash" + "fmt" +) + +func main() { + hash, ret := fastimagehash.PHashFile("/path/to/image.jpg", 8, 4) + + if ret == fastimagehash.Ok { + fmt.Printf("%s (%d)\n", hash.ToHexStringReversed(), ret) + } +} diff --git a/fastimagehash.go b/fastimagehash.go new file mode 100644 index 0000000..71feb56 --- /dev/null +++ b/fastimagehash.go @@ -0,0 +1,201 @@ +package fastimagehash + +import "C" +import ( + "io/ioutil" + "os" + "unsafe" +) + +/* +#cgo LDFLAGS: -L. -lfastimagehash +#include +#include +#include + +char *hash_to_hex_string_reversed_wr(void *h, int size) { + char *out = malloc(size * 2 + 1); + hash_to_hex_string_reversed((uchar*)h, out, size); + return out; +} + +char *hash_to_hex_string_wr(void *h, int size) { + char *out = malloc(size * 2 + 1); + hash_to_hex_string((uchar*)h, out, size); + return out; +} + +uchar *phash_mem_wr(void *buf, size_t buf_len, int hash_size, int highfreq_factor, int* ret) { + uchar *out = malloc(hash_size); + *ret = phash_mem((uchar*)buf, out, buf_len, hash_size, highfreq_factor); + return out; +} + +uchar *ahash_mem_wr(void *buf, size_t buf_len, int hash_size, int* ret) { + uchar *out = malloc(hash_size); + *ret = ahash_mem((uchar*)buf, out, buf_len, hash_size); + return out; +} + +uchar *dhash_mem_wr(void *buf, size_t buf_len, int hash_size, int* ret) { + uchar *out = malloc(hash_size); + *ret = dhash_mem((uchar*)buf, out, buf_len, hash_size); + return out; +} + +uchar *whash_mem_wr(void *buf, size_t buf_len, int hash_size, int img_scale, int* ret) { + uchar *out = malloc(hash_size); + *ret = whash_mem((uchar*)buf, out, buf_len, hash_size, img_scale); + return out; +} + +multi_hash_t *multi_mem_wr(void* buf, size_t buf_len, int hash_size, int ph_highfreq_factor, int wh_img_scale, int* ret) { + multi_hash_t *m = multi_hash_create(hash_size); + *ret = multi_hash_mem(buf, m, buf_len, hash_size, ph_highfreq_factor, wh_img_scale); + return m; +} +*/ +import "C" + +type Code int + +const ( + Ok = 0 + ReadErr Code = -2 + DecodeErr Code = -3 +) + +type Hash struct { + Size int + Bytes []byte +} + +type MultiHash struct { + PHash Hash + AHash Hash + DHash Hash + WHash Hash +} + +func retHash(hash *C.uchar, hashSize int, ret C.int) (*Hash, Code) { + goHash := C.GoBytes(unsafe.Pointer(hash), C.int(hashSize)) + C.free(unsafe.Pointer(hash)) + + return &Hash{ + Size: hashSize, + Bytes: goHash, + }, Code(ret) +} + +func retMultiHash(m *C.multi_hash_t, hashSize int, ret C.int) (*MultiHash, Code) { + goPHash := C.GoBytes(unsafe.Pointer(m.phash), C.int(hashSize)) + goAHash := C.GoBytes(unsafe.Pointer(m.ahash), C.int(hashSize)) + goDHash := C.GoBytes(unsafe.Pointer(m.dhash), C.int(hashSize)) + goWHash := C.GoBytes(unsafe.Pointer(m.whash), C.int(hashSize)) + C.multi_hash_destroy(m) + + return &MultiHash{ + PHash: Hash{hashSize, goPHash}, + AHash: Hash{hashSize, goAHash}, + DHash: Hash{hashSize, goDHash}, + WHash: Hash{hashSize, goWHash}, + }, Code(ret) +} + +func readAll(filepath string) ([]byte, error) { + f, err := os.Open(filepath) + if err != nil { + return nil, err + } + + bytes, err := ioutil.ReadAll(f) + if err != nil { + return nil, err + } + return bytes, nil +} + +func (h *Hash) ToHexStringReversed() (ret string) { + out := C.hash_to_hex_string_reversed_wr(unsafe.Pointer(&h.Bytes[0]), C.int(h.Size)) + ret = C.GoString(out) + C.free(unsafe.Pointer(out)) + return +} + +func (h *Hash) ToHexString() (ret string) { + out := C.hash_to_hex_string_wr(unsafe.Pointer(&h.Bytes[0]), C.int(h.Size)) + ret = C.GoString(out) + C.free(unsafe.Pointer(out)) + return +} + +func PHashFile(filepath string, hashSize, highFreqFactor int) (*Hash, Code) { + bytes, err := readAll(filepath) + if err != nil { + return nil, ReadErr + } + return PHashMem(bytes, hashSize, highFreqFactor) +} + +func PHashMem(buf []byte, hashSize, highFreqFactor int) (*Hash, Code) { + var ret C.int + hash := C.phash_mem_wr(unsafe.Pointer(&buf[0]), C.size_t(len(buf)), C.int(hashSize), C.int(highFreqFactor), &ret) + return retHash(hash, hashSize, ret) +} + +func AHashFile(filepath string, hashSize int) (*Hash, Code) { + bytes, err := readAll(filepath) + if err != nil { + return nil, ReadErr + } + return AHashMem(bytes, hashSize) +} + +func AHashMem(buf []byte, hashSize int) (*Hash, Code) { + var ret C.int + hash := C.ahash_mem_wr(unsafe.Pointer(&buf[0]), C.size_t(len(buf)), C.int(hashSize), &ret) + return retHash(hash, hashSize, ret) +} + +func DHashFile(filepath string, hashSize int) (*Hash, Code) { + bytes, err := readAll(filepath) + if err != nil { + return nil, ReadErr + } + return DHashMem(bytes, hashSize) +} + +func DHashMem(buf []byte, hashSize int) (*Hash, Code) { + var ret C.int + hash := C.dhash_mem_wr(unsafe.Pointer(&buf[0]), C.size_t(len(buf)), C.int(hashSize), &ret) + return retHash(hash, hashSize, ret) +} + +func WHashFile(filepath string, hashSize, imgScale int) (*Hash, Code) { + bytes, err := readAll(filepath) + if err != nil { + return nil, ReadErr + } + return WHashMem(bytes, hashSize, imgScale) +} + +func WHashMem(buf []byte, hashSize, imgScale int) (*Hash, Code) { + var ret C.int + hash := C.whash_mem_wr(unsafe.Pointer(&buf[0]), C.size_t(len(buf)), C.int(hashSize), C.int(imgScale), &ret) + return retHash(hash, hashSize, ret) +} + +func MultiHashFile(filepath string, hashSize, phHighFreqFactor, whImgScale int) (*MultiHash, Code) { + bytes, err := readAll(filepath) + if err != nil { + return nil, ReadErr + } + return MultiHashMem(bytes, hashSize, phHighFreqFactor, whImgScale) +} + +func MultiHashMem(buf []byte, hashSize, phHighFreqFactor, whImgScale int) (*MultiHash, Code) { + var ret C.int + m := C.multi_mem_wr(unsafe.Pointer(&buf[0]), C.size_t(len(buf)), C.int(hashSize), + C.int(phHighFreqFactor), C.int(whImgScale), &ret) + return retMultiHash(m, hashSize, ret) +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..14cd5a9 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/simon987/fastimagehash-go + +go 1.13