Способ создания подписи или хэша изображения в ASP.NET для обнаружения дубликатов?

У меня довольно большой сайт, на который мои участники добавляют тысячи изображений каждый день. Очевидно, что существует много дублирования, и мне просто интересно, могу ли я во время загрузки изображения каким-то образом сгенерировать подпись или хэш изображения, чтобы сохранить его. И каждый раз, когда кто-то загружает изображение, я просто запускаю проверку, существует ли эта подпись, и выдает ошибку о том, что это изображение уже существует. Не уверен, что такая технология уже существует для asp.net, но я знаю о tineye.com, который уже делает это.

Если вы думаете, что можете помочь, я был бы признателен за ваш вклад.

Крис


person Community    schedule 02.12.2009    source источник


Ответы (5)


Вы используете любой производный HashAlgorithm для генерации хэша из массива байтов файла. Обычно используется MD5, но вы можете заменить его любым из тех, что представлены в пространстве имен System.Security.Cryptography. Это работает для любого двоичного файла, а не только для изображений.

Многие сайты предоставляют хэши MD5 при загрузке файлов, чтобы проверить, правильно ли вы загрузили файл. Например, в образе ISO CD/DVD могут отсутствовать байты, когда вы получили его целиком. После того, как вы загрузили файл, вы генерируете для него хэш и убеждаетесь, что он такой же, как и должен быть на сайте. Если все сравнить, то у вас точная копия.

Я бы, вероятно, использовал что-то похожее на это:

public static class Helpers
{
    //If you're running .NET 2.0 or lower, remove the 'this' keyword from the
    //method signature as 2.0 doesn't support extension methods.
    static string GetHashString(this byte[] bytes, HashAlgorithm cryptoProvider)
    {
        byte[] hash = cryptoProvider.ComputeHash(bytes);
        return Convert.ToBase64String(hash);
    }
}

Требует:

using System.Security.Cryptography;

Позвоните, используя:

byte[] bytes = File.ReadAllBytes("FilePath");
string filehash = bytes.GetHashString(new MD5CryptoServiceProvider());

или если вы работаете в .NET 2.0 или ниже:

string filehash = Helpers.GetHashString(File.ReadAllBytes("FilePath"), new MD5CryptoServiceProvider());

Если бы вы решили использовать другой метод хеширования вместо MD5 для незначительной вероятности коллизий:

string filehash = bytes.GetHashString(new SHA1CryptoServiceProvider());

Таким образом, ваш метод has не зависит от поставщика криптографии, и если вы решите, что хотите изменить используемого провайдера криптографии, вы просто вводите другой в параметр cryptoProvider.

Вы можете использовать любой из других классов хеширования, просто изменив поставщика услуг, который вы передаете:

string md5Hash = bytes.GetHashString(new MD5CryptoServiceProvider());
string sha1Hash = bytes.GetHashString(new SHA1CryptoServiceProvider());
string sha256Hash = bytes.GetHashString(new SHA256CryptoServiceProvider());
string sha384Hash = bytes.GetHashString(new SHA384CryptoServiceProvider());
string sha512Hash = bytes.GetHashString(new SHA512CryptoServiceProvider());
person BenAlabaster    schedule 02.12.2009
comment
@ChristopheD Насколько я понимаю, существует аналогичная вероятность коллизий с генерацией GUID, но на практике вероятность того, что это произойдет, настолько мала, что о ней не стоит беспокоиться. - person BenAlabaster; 02.12.2009

Ключевое слово, которое может представлять интерес, — перцептивное хеширование.

person TC.    schedule 02.12.2009

Обычно вы просто используете MD5 или аналогичный для создания хеша. Однако это не гарантирует уникальность, поэтому я рекомендую вам использовать хэш в качестве отправной точки. Определите, соответствует ли изображение каким-либо известным хэшам, которые вы сохранили, затем отдельно загрузите те, которым оно соответствует, и выполните полное сравнение байтов для потенциальных коллизий, чтобы быть уверенным.

Другой, более простой метод, заключается в том, чтобы просто выбрать небольшое количество битов и прочитать первую часть изображения... сохранить это количество начальных битов, как если бы они были хешем. Это по-прежнему дает вам небольшое количество потенциальных столкновений, которые вам нужно проверить, но имеет гораздо меньше накладных расходов.

person Stephen M. Redd    schedule 02.12.2009
comment
+1 за то, что он единственный, кто указал, что, поскольку хеш теряет данные, его можно использовать только в качестве отправной точки и нельзя использовать для определения того, действительно ли две вещи равны. - person Greg Beech; 02.12.2009
comment
@Greg - я понимаю это теоретически, но, учитывая, что на практике вероятность того, что два файла создадут один и тот же хэш MD5 (за пределами чисто научной теоретической установки), означает, что этот аргумент спорен. Хэш может быть алгоритмом с потерями, но вы не должны иметь возможность генерировать файл из хэша. Он предназначен для проверки совпадения двух файлов. Если файлы одинаковые, то и хэш один и тот же, если они разные, то и хэш другой. Поскольку вероятность столкновения равна одному на миллиарды, шансы на то, что любые два разных фрагмента данных на вашем сервере будут иметь одинаковый хэш, равны крошечный. - person BenAlabaster; 02.12.2009
comment
Хэши в большинстве случаев достаточно уникальны, но для их создания требуется использовать весь двоичный файл. С большими изображениями или большими объемами данных возникает много накладных расходов, поэтому я выступал за использование только первой части файла вместо хэша. Но если вы это сделаете, необходимость перепроверки возрастет. - person Stephen M. Redd; 02.12.2009

Посмотрите в пространстве имен System.Security.Cryptography. У вас есть выбор из нескольких алгоритмов/реализаций хеширования. Вот пример с использованием md5, но, поскольку у вас их много, вам может понадобиться что-то большее, например SHA1:

public byte[] HashImage(Stream imageData)
{
    return new MD5CryptoServiceProvider().ComputeHash(imageData);
} 
person Joel Coehoorn    schedule 02.12.2009
comment
Количество изображений не имеет значения - вы не получите столкновения в MD5, если только кто-то не сделает это намеренно. - person Mark Byers; 02.12.2009

Я не знаю, существует ли он уже или нет, но я не могу придумать причину, по которой вы не можете сделать это самостоятельно. Что-то похожее на это даст вам хэш файла.

var fileStream = Request.Files[0].InputStream;//the uploaded file
var hasher = System.Security.Cryptography.HMACMD5();
var theHash = hasher.ComputeHash(fileStream);

System.Security.Cryptography

person Ken Henderson    schedule 02.12.2009