dhash-vips 0.2.1.0 → 0.2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a51cdf1232968a0f4717b6a76ef15a7e4378004fabdc240e472fbaac429c22c7
4
- data.tar.gz: e20fc002226f349de7ce4cfd2c5709cbd8198640e6b2445a572abebce3a7b85d
3
+ metadata.gz: 6b9bb7ce3d33457aa4a9562c223fc86404304e6a15d92db631462e7f3d3ba1cb
4
+ data.tar.gz: '09c3df795276527873062983d954ebbdeb07125eccca88551a2fd56f95e13be2'
5
5
  SHA512:
6
- metadata.gz: cd4d7ecb82a95361cd7a1075691a9303c80f18c4b186f37cb348c041f9787d6bdf61e34d39df3d416980aba2b680e98568743c2f1822e8df75838cea8fde3e60
7
- data.tar.gz: 297c8b7e8662e97bd051777d2b662504ae15fcfed448bf9248fd8ef941fa320430eba48bb5ff64ad10f890d985c0d7aca337578f033dcfef031b3d52026de276
6
+ metadata.gz: 48e976f177d8fe6dcd010bc0501ec862d2c2bfdad45bfd17e1f6c2f03abd7481e4930683018c7ea879b9c7b339e8676460bea135f943314d25d5dc1b70f76e04
7
+ data.tar.gz: 23a9ea2f316a226872940e7f0e1dfb3547a01db4ab0c24d981ba4edc68934a02a54be4007aeb7015977c72f7fbf90ead4d092113b45a77c4076feb07ebb421c0
data/LICENSE.txt CHANGED
File without changes
data/bin/idhash ADDED
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env ruby
2
+ Signal.trap(:INT){ abort "\n(interrupted by SIGINT)" }
3
+
4
+ unless 2 == ARGV.size
5
+ puts "this command is to compare two images"
6
+ puts "usage: #{__FILE__} <path to image1> <path to image2>"
7
+ exit
8
+ end
9
+
10
+ require_relative "../lib/dhash-vips"
11
+ ha, hb = ARGV.map{ |filename| DHashVips::IDHash.fingerprint filename }
12
+ puts "distance: #{d1 = DHashVips::IDHash.distance ha, hb}"
13
+ size = 2 ** 3
14
+ shift = 2 * size * size
15
+ ai = ha >> shift
16
+ ad = ha - (ai << shift)
17
+ bi = hb >> shift
18
+ bd = hb - (bi << shift)
19
+
20
+ _127 = shift - 1
21
+ _63 = size * size - 1
22
+ # width = 800
23
+ # height = 800
24
+
25
+ d2 = 0
26
+ a, b = [[ad, ai, ARGV[0]], [bd, bi, ARGV[1]]].map do |xd, xi, path|
27
+ puts File.basename path
28
+ hor = Array.new(size){Array.new(size){" "}}
29
+ ver = Array.new(size){Array.new(size){" "}}
30
+ _127.downto(0).each_with_index do |i, ii|
31
+ if i > _63
32
+ y, x = (_127 - i).divmod size
33
+ else
34
+ x, y = (_63 - i).divmod size
35
+ end
36
+ if xi[i] > 0
37
+ target, c = if i > _63
38
+ [ver, %w{ v ^ }[xd[i]]]
39
+ else
40
+ [hor, %w{ > < }[xd[i]]]
41
+ end
42
+ target[y][x] = c
43
+ end
44
+ if ai[i] + bi[i] > 0 && ad[i] != bd[i]
45
+ d2 += 1
46
+ target = if i > _63
47
+ ver
48
+ else
49
+ hor
50
+ end
51
+ target[y][x] = "\e[7m#{target[y][x]}\e[27m"
52
+ end
53
+ end
54
+ hor.zip(ver).each{ |_| puts _.join " " }
55
+ end
56
+ abort "something went wrong" unless d1 * 2 == d2
57
+ puts "OK"
data/dhash-vips.gemspec CHANGED
@@ -1,17 +1,19 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = "dhash-vips"
3
- spec.version = "0.2.1.0"
3
+ spec.version = "0.2.4.0"
4
4
  spec.summary = "dHash and IDHash perceptual image hashing/fingerprinting"
5
- # spec.homepage = "https://github.com/nakilon/dhash-vips"
6
5
 
7
- spec.author = "Victor Maslov"
6
+ spec.author = "Victor Maslov aka Nakilon"
8
7
  spec.email = "nakilon@gmail.com"
9
8
  spec.license = "MIT"
9
+ spec.metadata = {"source_code_uri" => "https://github.com/nakilon/dhash-vips"}
10
10
 
11
11
  spec.add_dependency "ruby-vips", "~> 2.0", "!= 2.1.0", "!= 2.1.1"
12
12
 
13
13
  spec.require_path = "lib"
14
- spec.test_files = %w{ test.rb }
15
14
  spec.extensions = %w{ extconf.rb }
16
- spec.files = %w{ extconf.rb Gemfile LICENSE.txt common.rb dhash-vips.gemspec idhash.c lib/dhash-vips-post-install-test.rb lib/dhash-vips.rb }
15
+ spec.files = %w{ LICENSE.txt dhash-vips.gemspec lib/dhash-vips.rb idhash.c lib/dhash-vips-post-install-test.rb } + spec.extensions +
16
+ %w{ bin/idhash }
17
+ spec.executables = %w{ idhash }
18
+ spec.bindir = "bin"
17
19
  end
data/extconf.rb CHANGED
@@ -3,32 +3,27 @@ require "mkmf"
3
3
  File.write "Makefile", dummy_makefile(?.).join
4
4
 
5
5
  unless Gem::Version.new(RUBY_VERSION) < Gem::Version.new("2.3.8")
6
- if ruby_source_dir = if File.directory? "/ruby"
7
- "-I/ruby" # for Github Actions: docker (currently disabled) and benchmark
8
- elsif ENV["RBENV_ROOT"] && ENV["RBENV_VERSION"] && File.exist?(t = "#{ENV["RBENV_ROOT"]}/sources/#{ENV["RBENV_VERSION"]}/ruby-#{ENV["RBENV_VERSION"]}/bignum.c") # https://github.com/rbenv/rbenv/issues/1199
9
- "-I#{File.dirname t}"
10
- end
11
- append_cppflags ruby_source_dir
12
- append_cppflags "-DRUBY_EXPORT" unless Gem::Version.new(RUBY_VERSION) < Gem::Version.new("2.4")
13
- create_makefile "idhash"
14
- # Why this hack?
15
- # 1. Because I want to use Ruby and ./idhash.bundle for tests, not C.
16
- # 2. Because I don't want to bother users with two gems instead of one.
17
- File.write "Makefile", <<~HEREDOC + File.read("Makefile")
18
- .PHONY: test
19
- test: all
20
- \t$(RUBY) -r./lib/dhash-vips.rb ./lib/dhash-vips-post-install-test.rb
21
- HEREDOC
22
- end
6
+ append_cppflags "-DRUBY_EXPORT" unless Gem::Version.new(RUBY_VERSION) < Gem::Version.new("2.4")
7
+ create_makefile "idhash"
8
+ # Why this hack?
9
+ # 1. Because I want to use Ruby and ./idhash.bundle for tests, not C.
10
+ # 2. Because I don't want to bother users with two gems instead of one.
11
+ File.write "Makefile", <<~HEREDOC + File.read("Makefile")
12
+ .PHONY: test
13
+ test: all
14
+ \t$(RUBY) -r./lib/dhash-vips.rb ./lib/dhash-vips-post-install-test.rb
15
+ HEREDOC
23
16
  end
24
17
 
25
18
  __END__
26
19
 
27
- to test: $ rake clean && rake install
28
-
29
20
  # this unlike using rake is building to current directory
30
- # that is vital to be able to require the native extention for benchmarking, etc.
21
+ # that is vital to be able to require the native extension for benchmarking, etc.
31
22
  $ ruby extconf.rb && make clean && make
23
+
24
+ # to test the installation:
25
+ $ rake clean && rake install
26
+
32
27
  $ ruby -e "require 'dhash-vips'; p DHashVips::IDHash.method(:distance3).source_location" # using -r makes bundler mad
33
28
  # [".../dhash-vips.rb", 32] # if LoadError
34
29
  # [".../dhash-vips.rb", 52] # if native (or 42 with Ruby<2.4)
data/idhash.c CHANGED
@@ -1,29 +1,35 @@
1
- #include <bignum.c>
1
+ #include <ruby.h>
2
2
 
3
- static VALUE idhash_distance(VALUE self, VALUE a, VALUE b){
4
- BDIGIT* tempd;
5
- long i, an = BIGNUM_LEN(a), bn = BIGNUM_LEN(b), templ, acc = 0;
6
- BDIGIT* as = BDIGITS(a);
7
- BDIGIT* bs = BDIGITS(b);
8
- while (0 < an && as[an-1] == 0) an--; // for (i = an; --i;) printf("%u\n", as[i]);
9
- while (0 < bn && bs[bn-1] == 0) bn--; // for (i = bn; --i;) printf("%u\n", bs[i]);
10
- // printf("%lu %lu\n", an, bn);
11
- if (an < bn) {
12
- tempd = as; as = bs; bs = tempd;
13
- templ = an; an = bn; bn = templ;
14
- }
15
- for (i = an; i-- > 4;) {
16
- // printf("%ld : (%u | %u) & (%u ^ %u)\n", i, as[i], (i >= bn ? 0 : bs[i]), as[i-4], bs[i-4]);
17
- acc += __builtin_popcountl((as[i] | (i >= bn ? 0 : bs[i])) & (as[i-4] ^ bs[i-4]));
18
- // printf("%ld : %ld\n", i, acc);
19
- }
20
- RB_GC_GUARD(a);
21
- RB_GC_GUARD(b);
22
- return INT2FIX(acc);
3
+ static VALUE idhash_distance(VALUE self, VALUE a, VALUE b) {
4
+ const size_t max_words = 256 / sizeof(uint64_t);
5
+
6
+ const size_t word_numbits = sizeof(uint64_t) * CHAR_BIT;
7
+ size_t n;
8
+ n = rb_absint_numwords(a, word_numbits, NULL);
9
+ if (n > max_words || n == (size_t)-1)
10
+ rb_raise(rb_eRangeError, "fingerprint #1 exceeds 256 bits");
11
+ n = rb_absint_numwords(b, word_numbits, NULL);
12
+ if (n > max_words || n == (size_t)-1)
13
+ rb_raise(rb_eRangeError, "fingerprint #2 exceeds 256 bits");
14
+
15
+ uint64_t as[max_words], bs[max_words];
16
+ rb_integer_pack(
17
+ a, as, max_words, sizeof(uint64_t), 0,
18
+ INTEGER_PACK_LSWORD_FIRST | INTEGER_PACK_NATIVE_BYTE_ORDER | INTEGER_PACK_2COMP
19
+ );
20
+ rb_integer_pack(
21
+ b, bs, max_words, sizeof(uint64_t), 0,
22
+ INTEGER_PACK_LSWORD_FIRST | INTEGER_PACK_NATIVE_BYTE_ORDER | INTEGER_PACK_2COMP
23
+ );
24
+
25
+ return INT2FIX(
26
+ __builtin_popcountll((as[3] | bs[3]) & (as[1] ^ bs[1])) +
27
+ __builtin_popcountll((as[2] | bs[2]) & (as[0] ^ bs[0]))
28
+ );
23
29
  }
24
30
 
25
31
  void Init_idhash() {
26
- VALUE m = rb_define_module("DHashVips");
27
- VALUE mm = rb_define_module_under(m, "IDHash");
28
- rb_define_module_function(mm, "distance3_c", idhash_distance, 2);
32
+ VALUE m = rb_define_module("DHashVips");
33
+ VALUE mm = rb_define_module_under(m, "IDHash");
34
+ rb_define_module_function(mm, "distance3_c", idhash_distance, 2);
29
35
  }
data/lib/dhash-vips.rb CHANGED
@@ -3,6 +3,10 @@ Vips.vector_set false
3
3
 
4
4
  module DHashVips
5
5
 
6
+ def self.bw image
7
+ (image.has_alpha? ? image.flatten(background: 255) : image).colourspace("b-w")[0]
8
+ end
9
+
6
10
  module DHash
7
11
  extend self
8
12
 
@@ -11,12 +15,11 @@ module DHashVips
11
15
  end
12
16
 
13
17
  def pixelate input, hash_size
14
- image = if input.is_a? Vips::Image
18
+ DHashVips.bw( if input.is_a? Vips::Image
15
19
  input.thumbnail_image(hash_size + 1, height: hash_size, size: :force)
16
20
  else
17
21
  Vips::Image.thumbnail(input, hash_size + 1, height: hash_size, size: :force)
18
- end
19
- (image.has_alpha? ? image.flatten : image).colourspace("b-w")[0]
22
+ end )
20
23
  end
21
24
 
22
25
  def calculate file, hash_size = 8
@@ -35,10 +38,7 @@ module DHashVips
35
38
  require_relative "../idhash.#{Gem::Platform.local.os == "darwin" ? "bundle" : "o"}"
36
39
  rescue LoadError
37
40
  class << self
38
- # https://github.com/minitest/minitest/issues/939
39
- def distance3 a, b
40
- distance3_ruby a, b
41
- end
41
+ alias distance3 distance3_ruby
42
42
  end
43
43
  else
44
44
  # we can't just do `defined? Bignum` because it's defined but deprecated (some internal CONST_DEPRECATED flag)
@@ -103,7 +103,7 @@ module DHashVips
103
103
  else
104
104
  Vips::Image.thumbnail(input, size, height: size, size: :force)
105
105
  end
106
- array = (image.has_alpha? ? image.flatten : image).flatten.colourspace("b-w")[0].to_enum.map &:flatten
106
+ array = DHashVips.bw(image).to_enum.map &:flatten
107
107
  d1, i1, d2, i2 = [array, array.transpose].flat_map do |a|
108
108
  d = a.zip(a.rotate(1)).flat_map{ |r1, r2| r1.zip(r2).map{ |i, j| i - j } }
109
109
  m = median d.map(&:abs).sort
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dhash-vips
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1.0
4
+ version: 0.2.4.0
5
5
  platform: ruby
6
6
  authors:
7
- - Victor Maslov
8
- autorequire:
7
+ - Victor Maslov aka Nakilon
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-12-06 00:00:00.000000000 Z
11
+ date: 2025-04-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ruby-vips
@@ -36,27 +36,27 @@ dependencies:
36
36
  - - "!="
37
37
  - !ruby/object:Gem::Version
38
38
  version: 2.1.1
39
- description:
39
+ description:
40
40
  email: nakilon@gmail.com
41
- executables: []
41
+ executables:
42
+ - idhash
42
43
  extensions:
43
44
  - extconf.rb
44
45
  extra_rdoc_files: []
45
46
  files:
46
- - Gemfile
47
47
  - LICENSE.txt
48
- - common.rb
48
+ - bin/idhash
49
49
  - dhash-vips.gemspec
50
50
  - extconf.rb
51
51
  - idhash.c
52
52
  - lib/dhash-vips-post-install-test.rb
53
53
  - lib/dhash-vips.rb
54
- - test.rb
55
- homepage:
54
+ homepage:
56
55
  licenses:
57
56
  - MIT
58
- metadata: {}
59
- post_install_message:
57
+ metadata:
58
+ source_code_uri: https://github.com/nakilon/dhash-vips
59
+ post_install_message:
60
60
  rdoc_options: []
61
61
  require_paths:
62
62
  - lib
@@ -71,9 +71,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
71
71
  - !ruby/object:Gem::Version
72
72
  version: '0'
73
73
  requirements: []
74
- rubygems_version: 3.3.25
75
- signing_key:
74
+ rubygems_version: 3.1.6
75
+ signing_key:
76
76
  specification_version: 4
77
77
  summary: dHash and IDHash perceptual image hashing/fingerprinting
78
- test_files:
79
- - test.rb
78
+ test_files: []
data/Gemfile DELETED
@@ -1,12 +0,0 @@
1
- source "https://rubygems.org"
2
-
3
- gem "rake"
4
- gem "rmagick"
5
- gem "dhash", github: "nakilon/dhash"
6
- gem "phamilie"
7
- gem "get_process_mem"
8
- gem "mll"
9
- gem "minitest"
10
- gem "byebug", "<11.1.0" # for Ruby 2.3
11
-
12
- gemspec
data/common.rb DELETED
@@ -1,11 +0,0 @@
1
- def download_if_needed path
2
- require "open-uri"
3
- require "digest"
4
- FileUtils.mkdir_p File.dirname path
5
- open("http://gems.nakilon.pro.storage.yandexcloud.net/dhash-vips/#{File.basename path}".tap do |url|
6
- puts "downloading #{path} from #{url}"
7
- end) do |link|
8
- File.open(path, "wb"){ |file| IO.copy_stream link, file }
9
- end unless File.exist?(path) && Digest::MD5.file(path) == File.basename(path, File.extname(path))
10
- path
11
- end
data/test.rb DELETED
@@ -1,225 +0,0 @@
1
- require "minitest/autorun"
2
-
3
- require_relative "lib/dhash-vips"
4
-
5
- # TODO tests about `fingerprint(4)`
6
-
7
- [
8
- [DHashVips::DHash, :hamming, :calculate, 2, 23, 9, 53, 7],
9
-
10
- # vips-8.9.1-Tue Jan 28 13:05:46 UTC 2020
11
- # [[0, 14, 26, 27, 31, 27, 32, 28, 43, 43, 34, 37, 37, 34, 35, 42],
12
- # [14, 0, 28, 25, 39, 35, 32, 32, 43, 43, 38, 41, 41, 38, 37, 50],
13
- # [26, 28, 0, 13, 35, 41, 28, 30, 41, 41, 36, 33, 35, 32, 27, 36],
14
- # [27, 25, 13, 0, 36, 36, 31, 35, 40, 40, 33, 32, 42, 35, 26, 33],
15
- # [31, 39, 35, 36, 0, 16, 33, 33, 40, 40, 31, 24, 28, 33, 40, 31],
16
- # [27, 35, 41, 36, 16, 0, 41, 41, 38, 38, 23, 26, 24, 29, 34, 27],
17
- # [32, 32, 28, 31, 33, 41, 0, 10, 27, 25, 38, 35, 37, 32, 23, 34],
18
- # [28, 32, 30, 35, 33, 41, 10, 0, 27, 27, 34, 31, 37, 36, 27, 34],
19
- # [43, 43, 41, 40, 40, 38, 27, 27, 0, 2, 35, 34, 30, 31, 28, 27],
20
- # [43, 43, 41, 40, 40, 38, 25, 27, 2, 0, 35, 34, 30, 31, 28, 27],
21
- # [34, 38, 36, 33, 31, 23, 38, 34, 35, 35, 0, 9, 23, 26, 29, 18],
22
- # [37, 41, 33, 32, 24, 26, 35, 31, 34, 34, 9, 0, 22, 25, 30, 19],
23
- # [37, 41, 35, 42, 28, 24, 37, 37, 30, 30, 23, 22, 0, 19, 26, 23],
24
- # [34, 38, 32, 35, 33, 29, 32, 36, 31, 31, 26, 25, 19, 0, 21, 26],
25
- # [35, 37, 27, 26, 40, 34, 23, 27, 28, 28, 29, 30, 26, 21, 0, 23],
26
- # [42, 50, 36, 33, 31, 27, 34, 34, 27, 27, 18, 19, 23, 26, 23, 0]]
27
-
28
- # vips-8.11.3-Wed Aug 11 09:29:27 UTC 2021
29
- # [[0, 17, 25, 30, 30, 26, 35, 30, 42, 42, 35, 32, 36, 32, 34, 42],
30
- # [17, 0, 28, 27, 39, 35, 32, 29, 43, 43, 38, 39, 43, 37, 37, 49],
31
- # [25, 28, 0, 13, 35, 41, 28, 29, 41, 41, 38, 35, 33, 31, 27, 37],
32
- # [30, 27, 13, 0, 36, 36, 31, 34, 38, 38, 35, 32, 40, 34, 26, 32],
33
- # [30, 39, 35, 36, 0, 16, 35, 34, 40, 40, 31, 26, 28, 34, 40, 30],
34
- # [26, 35, 41, 36, 16, 0, 41, 44, 38, 38, 23, 28, 26, 30, 34, 24],
35
- # [35, 32, 28, 31, 35, 41, 0, 11, 27, 27, 38, 35, 33, 33, 21, 35],
36
- # [30, 29, 29, 34, 34, 44, 11, 0, 28, 28, 37, 32, 36, 40, 30, 38],
37
- # [42, 43, 41, 38, 40, 38, 27, 28, 0, 0, 33, 34, 30, 32, 28, 30],
38
- # [42, 43, 41, 38, 40, 38, 27, 28, 0, 0, 33, 34, 30, 32, 28, 30],
39
- # [35, 38, 38, 35, 31, 23, 38, 37, 33, 33, 0, 11, 23, 27, 31, 17],
40
- # [32, 39, 35, 32, 26, 28, 35, 32, 34, 34, 11, 0, 24, 26, 30, 20],
41
- # [36, 43, 33, 40, 28, 26, 33, 36, 30, 30, 23, 24, 0, 20, 26, 22],
42
- # [32, 37, 31, 34, 34, 30, 33, 40, 32, 32, 27, 26, 20, 0, 20, 26],
43
- # [34, 37, 27, 26, 40, 34, 21, 30, 28, 28, 31, 30, 26, 20, 0, 24],
44
- # [42, 49, 37, 32, 30, 24, 35, 38, 30, 30, 17, 20, 22, 26, 24, 0]]
45
-
46
- # v0.1.2.0
47
- # [[0, 18, 25, 27, 28, 25, 33, 31, 39, 40, 33, 35, 32, 28, 36, 47],
48
- # [18, 0, 31, 25, 34, 33, 33, 33, 39, 38, 37, 43, 40, 36, 40, 53],
49
- # [25, 31, 0, 16, 31, 38, 26, 32, 42, 41, 36, 38, 31, 31, 31, 32],
50
- # [27, 25, 16, 0, 35, 36, 26, 32, 38, 37, 34, 34, 41, 37, 27, 34],
51
- # [28, 34, 31, 35, 0, 17, 39, 37, 41, 44, 31, 27, 26, 32, 32, 33],
52
- # [25, 33, 38, 36, 17, 0, 46, 40, 38, 39, 24, 28, 25, 31, 25, 30],
53
- # [33, 33, 26, 26, 39, 46, 0, 10, 26, 25, 34, 32, 31, 35, 33, 30],
54
- # [31, 33, 32, 32, 37, 40, 10, 0, 26, 27, 34, 32, 33, 33, 33, 34],
55
- # [39, 39, 42, 38, 41, 38, 26, 26, 0, 3, 36, 34, 35, 33, 37, 28],
56
- # [40, 38, 41, 37, 44, 39, 25, 27, 3, 0, 35, 35, 36, 36, 36, 27],
57
- # [33, 37, 36, 34, 31, 24, 34, 34, 36, 35, 0, 10, 23, 31, 23, 22],
58
- # [35, 43, 38, 34, 27, 28, 32, 32, 34, 35, 10, 0, 23, 29, 23, 20],
59
- # [32, 40, 31, 41, 26, 25, 31, 33, 35, 36, 23, 23, 0, 20, 24, 21],
60
- # [28, 36, 31, 37, 32, 31, 35, 33, 33, 36, 31, 29, 20, 0, 20, 25],
61
- # [36, 40, 31, 27, 32, 25, 33, 33, 37, 36, 23, 23, 24, 20, 0, 17],
62
- # [47, 53, 32, 34, 33, 30, 30, 34, 28, 27, 22, 20, 21, 25, 17, 0]]
63
-
64
- # v0.2.0.0
65
- # [[0, 18, 26, 28, 28, 24, 35, 31, 42, 42, 32, 34, 33, 29, 35, 40],
66
- # [18, 0, 30, 24, 38, 34, 33, 33, 44, 42, 38, 42, 41, 37, 37, 50],
67
- # [26, 30, 0, 16, 34, 38, 29, 35, 42, 40, 36, 38, 31, 31, 31, 36],
68
- # [28, 24, 16, 0, 36, 36, 31, 35, 40, 38, 34, 34, 41, 37, 27, 34],
69
- # [28, 38, 34, 36, 0, 14, 35, 33, 40, 42, 32, 26, 27, 33, 35, 28],
70
- # [24, 34, 38, 36, 14, 0, 43, 39, 38, 40, 24, 28, 25, 31, 29, 28],
71
- # [35, 33, 29, 31, 35, 43, 0, 8, 27, 25, 35, 33, 32, 32, 28, 31],
72
- # [31, 33, 35, 35, 33, 39, 8, 0, 27, 27, 35, 33, 34, 34, 28, 33],
73
- # [42, 44, 42, 40, 40, 38, 27, 27, 0, 2, 34, 32, 31, 33, 31, 28],
74
- # [42, 42, 40, 38, 42, 40, 25, 27, 2, 0, 34, 34, 33, 35, 31, 28],
75
- # [32, 38, 36, 34, 32, 24, 35, 35, 34, 34, 0, 10, 23, 31, 25, 18],
76
- # [34, 42, 38, 34, 26, 28, 33, 33, 32, 34, 10, 0, 23, 29, 25, 16],
77
- # [33, 41, 31, 41, 27, 25, 32, 34, 31, 33, 23, 23, 0, 20, 24, 19],
78
- # [29, 37, 31, 37, 33, 31, 32, 34, 33, 35, 31, 29, 20, 0, 22, 27],
79
- # [35, 37, 31, 27, 35, 29, 28, 28, 31, 31, 25, 25, 24, 22, 0, 23],
80
- # [40, 50, 36, 34, 28, 28, 31, 33, 28, 28, 18, 16, 19, 27, 23, 0]]
81
-
82
- [DHashVips::IDHash, :distance, :fingerprint, 8, 21, 23, 72, 0],
83
-
84
- # vips-8.9.1-Tue Jan 28 13:05:46 UTC 2020
85
- # [[0, 16, 32, 35, 57, 45, 51, 50, 48, 47, 54, 48, 60, 50, 47, 56],
86
- # [16, 0, 30, 34, 58, 47, 55, 56, 47, 50, 57, 49, 62, 52, 52, 61],
87
- # [32, 30, 0, 9, 47, 54, 45, 41, 65, 62, 42, 37, 51, 44, 49, 49],
88
- # [35, 34, 9, 0, 54, 64, 42, 40, 57, 56, 48, 39, 50, 40, 41, 51],
89
- # [57, 58, 47, 54, 0, 22, 43, 45, 64, 61, 48, 47, 35, 43, 47, 48],
90
- # [45, 47, 54, 64, 22, 0, 53, 54, 55, 54, 40, 46, 39, 42, 43, 42],
91
- # [51, 55, 45, 42, 43, 53, 0, 6, 33, 35, 52, 43, 46, 45, 44, 47],
92
- # [50, 56, 41, 40, 45, 54, 6, 0, 38, 41, 53, 50, 48, 45, 41, 42],
93
- # [48, 47, 65, 57, 64, 55, 33, 38, 0, 9, 51, 53, 47, 47, 41, 46],
94
- # [47, 50, 62, 56, 61, 54, 35, 41, 9, 0, 51, 57, 50, 49, 44, 43],
95
- # [54, 57, 42, 48, 48, 40, 52, 53, 51, 51, 0, 10, 33, 36, 38, 25],
96
- # [48, 49, 37, 39, 47, 46, 43, 50, 53, 57, 10, 0, 27, 30, 37, 27],
97
- # [60, 62, 51, 50, 35, 39, 46, 48, 47, 50, 33, 27, 0, 20, 23, 28],
98
- # [50, 52, 44, 40, 43, 42, 45, 45, 47, 49, 36, 30, 20, 0, 35, 39],
99
- # [47, 52, 49, 41, 47, 43, 44, 41, 41, 44, 38, 37, 23, 35, 0, 19],
100
- # [56, 61, 49, 51, 48, 42, 47, 42, 46, 43, 25, 27, 28, 39, 19, 0]]
101
-
102
- # vips-8.11.3-Wed Aug 11 09:29:27 UTC 2021
103
- # [[0, 17, 30, 35, 55, 46, 51, 54, 48, 46, 57, 48, 59, 52, 49, 54],
104
- # [17, 0, 30, 37, 57, 46, 54, 55, 46, 49, 60, 50, 61, 54, 51, 58],
105
- # [30, 30, 0, 12, 46, 57, 47, 42, 66, 59, 44, 37, 49, 44, 48, 49],
106
- # [35, 37, 12, 0, 54, 67, 44, 41, 58, 53, 48, 41, 56, 42, 46, 48],
107
- # [55, 57, 46, 54, 0, 23, 45, 43, 65, 63, 48, 48, 34, 42, 48, 47],
108
- # [46, 46, 57, 67, 23, 0, 57, 56, 51, 50, 42, 48, 37, 38, 46, 40],
109
- # [51, 54, 47, 44, 45, 57, 0, 6, 33, 34, 49, 43, 49, 41, 45, 47],
110
- # [54, 55, 42, 41, 43, 56, 6, 0, 40, 39, 51, 50, 49, 40, 44, 44],
111
- # [48, 46, 66, 58, 65, 51, 33, 40, 0, 10, 47, 53, 48, 46, 40, 46],
112
- # [46, 49, 59, 53, 63, 50, 34, 39, 10, 0, 50, 57, 50, 49, 40, 43],
113
- # [57, 60, 44, 48, 48, 42, 49, 51, 47, 50, 0, 9, 33, 32, 40, 23],
114
- # [48, 50, 37, 41, 48, 48, 43, 50, 53, 57, 9, 0, 28, 27, 38, 28],
115
- # [59, 61, 49, 56, 34, 37, 49, 49, 48, 50, 33, 28, 0, 21, 24, 27],
116
- # [52, 54, 44, 42, 42, 38, 41, 40, 46, 49, 32, 27, 21, 0, 36, 35],
117
- # [49, 51, 48, 46, 48, 46, 45, 44, 40, 40, 40, 38, 24, 36, 0, 21],
118
- # [54, 58, 49, 48, 47, 40, 47, 44, 46, 43, 23, 28, 27, 35, 21, 0]]
119
-
120
- # v0.1.2.0
121
- # [[0, 17, 34, 40, 53, 43, 53, 52, 47, 47, 56, 44, 54, 51, 47, 57],
122
- # [17, 0, 35, 33, 56, 45, 56, 52, 48, 49, 58, 49, 64, 57, 53, 58],
123
- # [34, 35, 0, 8, 51, 57, 45, 40, 57, 54, 47, 40, 49, 47, 47, 48],
124
- # [40, 33, 8, 0, 56, 62, 44, 40, 53, 47, 50, 41, 53, 41, 42, 47],
125
- # [53, 56, 51, 56, 0, 21, 41, 48, 72, 65, 46, 47, 36, 43, 43, 43],
126
- # [43, 45, 57, 62, 21, 0, 54, 56, 61, 60, 41, 47, 38, 39, 43, 39],
127
- # [53, 56, 45, 44, 41, 54, 0, 12, 39, 40, 47, 44, 44, 38, 48, 41],
128
- # [52, 52, 40, 40, 48, 56, 12, 0, 35, 36, 51, 50, 47, 39, 41, 43],
129
- # [47, 48, 57, 53, 72, 61, 39, 35, 0, 11, 53, 53, 57, 48, 42, 51],
130
- # [47, 49, 54, 47, 65, 60, 40, 36, 11, 0, 50, 54, 51, 49, 45, 47],
131
- # [56, 58, 47, 50, 46, 41, 47, 51, 53, 50, 0, 13, 32, 36, 38, 23],
132
- # [44, 49, 40, 41, 47, 47, 44, 50, 53, 54, 13, 0, 28, 30, 35, 27],
133
- # [54, 64, 49, 53, 36, 38, 44, 47, 57, 51, 32, 28, 0, 21, 24, 28],
134
- # [51, 57, 47, 41, 43, 39, 38, 39, 48, 49, 36, 30, 21, 0, 31, 35],
135
- # [47, 53, 47, 42, 43, 43, 48, 41, 42, 45, 38, 35, 24, 31, 0, 19],
136
- # [57, 58, 48, 47, 43, 39, 41, 43, 51, 47, 23, 27, 28, 35, 19, 0]]
137
-
138
- # v0.2.0.0
139
- # [[0, 17, 34, 40, 53, 43, 53, 52, 47, 47, 56, 44, 54, 51, 47, 57],
140
- # [17, 0, 35, 33, 56, 45, 56, 52, 48, 49, 58, 49, 64, 57, 53, 58],
141
- # [34, 35, 0, 8, 51, 57, 45, 40, 57, 54, 47, 40, 49, 47, 47, 48],
142
- # [40, 33, 8, 0, 56, 62, 44, 40, 53, 47, 50, 41, 53, 41, 42, 47],
143
- # [53, 56, 51, 56, 0, 21, 41, 48, 72, 65, 46, 47, 36, 43, 43, 43],
144
- # [43, 45, 57, 62, 21, 0, 54, 56, 61, 60, 41, 47, 38, 39, 43, 39],
145
- # [53, 56, 45, 44, 41, 54, 0, 12, 39, 40, 47, 44, 44, 38, 48, 41],
146
- # [52, 52, 40, 40, 48, 56, 12, 0, 35, 36, 51, 50, 47, 39, 41, 43],
147
- # [47, 48, 57, 53, 72, 61, 39, 35, 0, 11, 53, 53, 57, 48, 42, 51],
148
- # [47, 49, 54, 47, 65, 60, 40, 36, 11, 0, 50, 54, 51, 49, 45, 47],
149
- # [56, 58, 47, 50, 46, 41, 47, 51, 53, 50, 0, 13, 32, 36, 38, 23],
150
- # [44, 49, 40, 41, 47, 47, 44, 50, 53, 54, 13, 0, 28, 30, 35, 27],
151
- # [54, 64, 49, 53, 36, 38, 44, 47, 57, 51, 32, 28, 0, 21, 24, 28],
152
- # [51, 57, 47, 41, 43, 39, 38, 39, 48, 49, 36, 30, 21, 0, 31, 35],
153
- # [47, 53, 47, 42, 43, 43, 48, 41, 42, 45, 38, 35, 24, 31, 0, 19],
154
- # [57, 58, 48, 47, 43, 39, 41, 43, 51, 47, 23, 27, 28, 35, 19, 0]]
155
-
156
- ].each do |lib, dm, calc, min_similar, max_similar, min_not_similar, max_not_similar, bw_exceptional|
157
-
158
- describe lib do
159
- require "fileutils"
160
- require "digest"
161
- require "mll"
162
-
163
- # these are false positive by idhash
164
- # 6d97739b4a08f965dc9239dd24382e96.jpg
165
- # 1b1d4bde376084011d027bba1c047a4b.jpg
166
- [
167
- [ %w{
168
- 1d468d064d2e26b5b5de9a0241ef2d4b.jpg 92d90b8977f813af803c78107e7f698e.jpg
169
- 309666c7b45ecbf8f13e85a0bd6b0a4c.jpg 3f9f3db06db20d1d9f8188cd753f6ef4.jpg
170
- 679634ff89a31279a39f03e278bc9a01.jpg df0a3b93e9412536ee8a11255f974141.jpg
171
- 54192a3f65bd03163b04849e1577a40b.jpg 6d32f57459e5b79b5deca2a361eb8c6e.jpg
172
- 4b62e0eef58bfbc8d0d2fbf2b9d05483.jpg b8eb0ca91855b657f12fb3d627d45c53.jpg
173
- 21cd9a6986d98976b6b4655e1de7baf4.jpg 9b158c0d4953d47171a22ed84917f812.jpg
174
- 9c2c240ec02356472fb532f404d28dde.jpg fc762fa286489d8afc80adc8cdcb125e.jpg
175
- 7a833d873f8d49f12882e86af1cc6b79.jpg ac033cf01a3941dd1baa876082938bc9.jpg
176
- }, min_similar, max_similar], # slightly silimar images
177
- [ %w{
178
- 71662d4d4029a3b41d47d5baf681ab9a.jpg ad8a37f872956666c3077a3e9e737984.jpg
179
- }, bw_exceptional, bw_exceptional], # these are the same photo but of different size and colorspace
180
- ].each do |_images, min, max|
181
-
182
- require_relative "common"
183
- images = _images.map{ |_| download_if_needed "test_images/#{_}" }
184
-
185
- hashes = images.map &lib.method(calc)
186
- table = MLL::table[lib.method(dm), [hashes], [hashes]]
187
-
188
- # STDERR.puts ""
189
- # require "pp"
190
- # PP.pp table, STDERR
191
- # STDERR.puts ""
192
-
193
- hashes.size.times.to_a.repeated_combination(2) do |i, j|
194
- it "#{_images[i]} #{_images[j]}" do
195
- case
196
- when i == j
197
- assert_predicate table[i][j], :zero?
198
- when (j - i).abs == 1 && (i + j - 1) % 4 == 0
199
- # STDERR.puts [table[i][j], min, max].inspect
200
- assert_includes min..max, table[i][j]
201
- else
202
- # STDERR.puts [table[i][j], min_not_similar, max_not_similar].inspect
203
- assert_includes min_not_similar..max_not_similar, table[i][j]
204
- end
205
- end
206
- end
207
-
208
- end
209
-
210
- it "accepts Vips::Image" do
211
- # https://github.com/libvips/ruby-vips/issues/349
212
- lib.public_send calc, Vips::Image.new_from_buffer("GIF89a\x01\x00\x01\x00\x80\x01\x00\xFF\xFF\xFF\x00\x00\x00,\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02D\x01\x00;", "")
213
- end
214
-
215
- end
216
-
217
- end
218
-
219
- describe DHashVips::IDHash do
220
- it "does not call distance3_ruby" do
221
- DHashVips::IDHash.stub :distance3_ruby, ->*{fail} do
222
- assert_equal 0, DHashVips::IDHash.distance3((2<<256)-1, (2<<256)-1)
223
- end
224
- end
225
- end