Skip to content
This repository has been archived by the owner on May 16, 2022. It is now read-only.

Commit

Permalink
Separate image operations to dedicated module
Browse files Browse the repository at this point in the history
Signed-off-by: Igor Shishkin <me@teran.ru>
  • Loading branch information
teran committed Oct 16, 2017
1 parent 7178e9b commit dec79d0
Show file tree
Hide file tree
Showing 2 changed files with 144 additions and 99 deletions.
112 changes: 13 additions & 99 deletions src/imgsum/cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,53 +2,39 @@ package main

import (
"bufio"
"bytes"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"flag"
"fmt"
"image"
"image/jpeg"
"io"
"os"
"regexp"
"strings"

"github.com/Soreil/arw"
"github.com/brett-lempereur/ish"
"github.com/nf/cr2"
"imgsum/image"
)

type JsonOutput struct {
Duplicates [][]string `json:"duplicates"`
Count int `json:"count"`
}

var (
re_canon = regexp.MustCompile("(?i).cr(2)$")
re_sony = regexp.MustCompile("(?i).(arw|sr2)$")
)

func calculate(file string) error {
var img image.Image
img, err := getImage(file)
func calculate(file string) (error) {
i, err := image.NewImage(file)
if err != nil {
fmt.Fprintln(os.Stderr, file, err.Error())
return err
}

h, err := hash(img)
h, err := i.Hexdigest()
if err != nil {
fmt.Fprintln(os.Stderr, file, err.Error())
return err
}

fmt.Printf("%v %v\n", h, file)
fmt.Printf("%v %v\n", h, i.Filename())
return nil
}

func checkFiles(checksumFile string) error {
func check(checksumFile string) error {
fp, err := os.Open(checksumFile)
if err != nil {
fmt.Fprintln(os.Stderr, checksumFile, err.Error())
Expand All @@ -61,16 +47,16 @@ func checkFiles(checksumFile string) error {
for err != io.EOF {
fields := strings.Fields(line)
if len(fields) == 2 {
img, err := getImage(fields[1])
i, err := image.NewImage(fields[1])
if err != nil {
fmt.Fprintln(os.Stderr, fields[1], err.Error())
return err
continue
}

h, err := hash(img)
h, err := i.Hexdigest()
if err != nil {
fmt.Fprintln(os.Stderr, fields[1], err.Error())
return err
continue
}

if fields[0] == h {
Expand Down Expand Up @@ -138,69 +124,6 @@ func deduplicate(filename string, json_output bool) error {
return nil
}

func getImage(filename string) (image.Image, error) {
var img image.Image
var err error
var fp *os.File

fp, err = os.Open(filename)
if err != nil {
return nil, err
}
defer fp.Close()

if re_canon.Match([]byte(filename)) {
img, err = cr2.Decode(fp)
} else if re_sony.Match([]byte(filename)) {
header, err := arw.ParseHeader(fp)
meta, err := arw.ExtractMetaData(fp, int64(header.Offset), 0)
if err != nil {
return nil, err
}

var jpegOffset uint32
var jpegLength uint32
for i := range meta.FIA {
switch meta.FIA[i].Tag {
case arw.JPEGInterchangeFormat:
jpegOffset = meta.FIA[i].Offset
case arw.JPEGInterchangeFormatLength:
jpegLength = meta.FIA[i].Offset
}
}
jpg, err := arw.ExtractThumbnail(fp, jpegOffset, jpegLength)
if err != nil {
return nil, err
}
reader := bytes.NewReader(jpg)
img, err = jpeg.Decode(reader)
if err != nil {
return nil, err
}
} else {
img, _, err = image.Decode(fp)
}

if err != nil {
return nil, err
}

return img, nil
}

func hash(img image.Image) (string, error) {
hasher := ish.NewAverageHash(1024, 1024)
dh, err := hasher.Hash(img)
if err != nil {
return "", err
}

h := sha256.New()
h.Write(dh)

return hex.EncodeToString(h.Sum(nil)), nil
}

func main() {
flag.Usage = func() {
fmt.Printf("Usage: %s [OPTION]... [FILE]...\n", os.Args[0])
Expand Down Expand Up @@ -230,24 +153,15 @@ func main() {

if *check_mode == true {
for file := range flag.Args() {
err := checkFiles(flag.Arg(file))
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
check(flag.Arg(file))
}
} else if *deduplicate_mode {
for file := range flag.Args() {
err := deduplicate(flag.Arg(file), *json_output)
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
deduplicate(flag.Arg(file), *json_output)
}
} else {
for file := range flag.Args() {
err := calculate(flag.Arg(file))
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
calculate(flag.Arg(file))
}
}
}
131 changes: 131 additions & 0 deletions src/imgsum/image/image.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package image

import (
"bytes"
"crypto/sha256"
"encoding/hex"
stdimage "image"
"image/jpeg"
"os"
"regexp"

"github.com/brett-lempereur/ish"
"github.com/Soreil/arw"
"github.com/nf/cr2"
)

var (
re_canon = regexp.MustCompile("(?i).cr(2)$")
re_sony = regexp.MustCompile("(?i).(arw|sr2)$")
)

type Image struct {
filename string
fp *os.File
image stdimage.Image
}

func NewImage(filename string) (*Image, error) {
i := new(Image)
i.filename = filename

err := i.open()
if err != nil {
return nil, err
}
return i, nil
}

func (i *Image) open() (error) {
var err error
i.fp, err = os.Open(i.filename)
if err != nil {
return err
}
defer i.fp.Close()

if re_canon.Match([]byte(i.filename)) {
err = i.openCanonRaw()
} else if re_sony.Match([]byte(i.filename)) {
err = i.openSonyRaw()
} else {
err = i.openStdImage()
}

if err != nil {
return err
}
return nil
}

func (i *Image) openStdImage() (error) {
var err error
i.image, _, err = stdimage.Decode(i.fp)
if err != nil {
return err
}

return nil
}

func (i *Image) openCanonRaw() (error) {
var err error
i.image, err = cr2.Decode(i.fp)
if err != nil {
return err
}
return nil
}

func (i *Image) openSonyRaw() (error) {
var jpegOffset uint32
var jpegLength uint32

header, err := arw.ParseHeader(i.fp)
if err != nil {
return err
}

meta, err := arw.ExtractMetaData(i.fp, int64(header.Offset), 0)
if err != nil {
return err
}

for i := range meta.FIA {
switch meta.FIA[i].Tag {
case arw.JPEGInterchangeFormat:
jpegOffset = meta.FIA[i].Offset
case arw.JPEGInterchangeFormatLength:
jpegLength = meta.FIA[i].Offset
}
}

jpg, err := arw.ExtractThumbnail(i.fp, jpegOffset, jpegLength)
if err != nil {
return err
}

reader := bytes.NewReader(jpg)
i.image, err = jpeg.Decode(reader)
if err != nil {
return err
}
return nil
}

func (i *Image) Hexdigest() (string, error) {
hasher := ish.NewAverageHash(1024, 1024)
dh, err := hasher.Hash(i.image)
if err != nil {
return "", err
}

h := sha256.New()
h.Write(dh)

return hex.EncodeToString(h.Sum(nil)), nil
}

func (i *Image) Filename() (string) {
return i.filename
}

0 comments on commit dec79d0

Please sign in to comment.