Посмотрите на класс MessageDigest. По сути, вы создаете его экземпляр, а затем передаете ему серию байтов. Байты могут быть байтами, непосредственно загруженными из URL, если вы знаете, что два «одинаковых» изображения будут тем же файлом / потоком байтов. Или, если необходимо, вы можете создать BufferedImage из потока, а затем извлечь значения пикселей, например:
MessageDigest md = MessageDigest.getInstance("MD5");
ByteBuffer bb = ByteBuffer.allocate(4 * bimg.getWidth());
for (int y = bimg.getHeight()-1; y >= 0; y--) {
bb.clear();
for (int x = bimg.getWidth()-1; x >= 0; x--) {
bb.putInt(bimg.getRGB(x, y));
}
md.update(bb.array());
}
byte[] digBytes = md.digest();
В любом случае MessageDigest.digest () в конечном итоге дает вам байтовый массив, который является «подписью» изображения. Вы можете преобразовать это в шестнадцатеричную строку, если это полезно, например, для помещения в HashMap или таблицу базы данных, например ::100100
StringBuilder sb = new StringBuilder();
for (byte b : digBytes) {
sb.append(String.format("%02X", b & 0xff));
}
String signature = sb.toString();
Если содержимое / изображение из двух URL-адресов дает вам одинаковую подпись, значит, это одно и то же изображение.
Редактировать: Я забыл упомянуть, что, если вы хэшируете значения пикселей, вы, вероятно, захотите включить размеры изображения в хеш. (Точно так же: записать два целых числа в 8-байтовый ByteBuffer, затем обновить MessageDigest с помощью соответствующего 8-байтового массива.)
Другое дело, что кто-то упоминал, что MD5 не является устойчивым к столкновениям . Другими словами, существует методика построения нескольких байтовых последовательностей с одним и тем же хешем MD5 без необходимости использовать метод "грубой силы" методом проб и ошибок (где в среднем вы ожидаете попробовать около 2 ^ 64 или 16 миллиардов миллиардов файлов до попадания в коллизию). Это делает MD5 неподходящим , где вы пытаетесь защитить от этой модели угрозы . Если вы не обеспокоены случаем, когда кто-то может сознательно попытаться обмануть вашу дубликатную идентификацию, и вы просто беспокоитесь о вероятности дублирования хеша "случайно", тогда MD5 абсолютно в порядке. На самом деле, это не только хорошо, это на самом деле немного чрезмерно - как я уже сказал, в среднем вы ожидаете один «ложный дубликат» после примерно 16 миллиардов миллиардов файлов. Или, другими словами, у вас может быть, скажем, миллиард файлов, и вероятность столкновения будет очень близка к нулю.
Если вы обеспокоены изложенной моделью угрозы (т. Е. Вы думаете, что кто-то может сознательно посвятить процессорное время созданию файлов, чтобы обмануть вашу систему), тогда решение состоит в том, чтобы использовать более сильный хеш. Java поддерживает SHA1 из коробки (просто замените «MD5» на «SHA1»). Теперь это даст вам более длинные хэши (160 бит вместо 128 бит), но с учетом современных знаний делает невозможным обнаружение коллизий.
Лично для этой цели я бы даже подумал об использовании приличной 64-битной хеш-функции. Это по-прежнему позволяет сравнивать десятки миллионов изображений с вероятностью ложного срабатывания, близкой к нулю.