2013-05-29 4 views
4

Я в основном читаю в заголовке файла изображения и делаю быстрое сравнение, чтобы увидеть, какой файл он на самом деле. BMP, GIF, PNG все легко, так как их заголовки содержат BM, GIF и PNG, чтобы идентифицировать себя. JPG бросает меня на бит цикла.Ruby - Сравнение «==» шестнадцатеричного значения с строкой

Первые 3 байта jpg имеют тенденцию быть 0xff \ 0xd8 \ 0xff, и для жизни меня я не могу получить истинное значение в простом сравнении, независимо от того, как я его настроил.

Я прочитал в первые 4 байта:

if data[0, 3] == "\xff\xd8\xff" 
    puts "This is a JPG" 
end 

Я знаю, что я близко, но я просто не могу заставить его работать. Пожалуйста, дайте мне знать, чего я здесь пропустил.

Примечание: Я знаю, что для этого есть драгоценные камни, но я не хочу использовать драгоценный камень. Просто как тот.

+0

Как ваши данные выглядят? –

+0

@ И я использую данные [0, 3], чтобы получить первые 3 байта из 4, которые я прочитал в – Kyle

ответ

9

Это проблема кодировки символов. Чтение первых 4 байтов из JPEG возвращает ASCII закодированную строку:

head = File.read("some.jpg", 4) 
# => "\xFF\xD8\xFF\xE1" 

head.encodig 
# => #<Encoding:ASCII-8BIT> 

Строки с другой стороны, являются UTF-8 кодируются:

jpg_prefix = "\xff\xd8\xff" 
# => "\xFF\xD8\xFF" 

jpg_prefix.encoding 
# => #<Encoding:UTF-8> 

Сравнение UTF-8 и ASCII строки не работает Ожидаемый результат:

head[0,3] == jpg_prefix 
# => false 

Вы должны явно установить кодировку с String#force_encoding:

jpg_prefix = "\xff\xd8\xff".force_encoding(Encoding::ASCII_8BIT) 
# => "\xFF\xD8\xFF" 

jpg_prefix.encoding 
# => #<Encoding:ASCII-8BIT> 

head[0,3] == jpg_prefix 
# => true 

конкатенации ASCII символы, созданные с Integer#chr (как это было предложено Марио Visic) также работает:

jpg_prefix = 0xff.chr + 0xd8.chr + 0xff.chr 
# => "\xFF\xD8\xFF" 

jpg_prefix.encoding 
# => #<Encoding:ASCII-8BIT> 

Или с помощью Array#pack:

jpg_prefix = ["FFD8FF"].pack("H*") 
# => "\xFF\xD8\xFF" 

jpg_prefix.encoding 
# => #<Encoding:ASCII-8BIT> 
+0

Очень хорошее объяснение. Очень признателен – Kyle

0

Ваш код отлично работает для меня, когда Data является строкой, но данные, вероятно, представляют собой массив байтовых значений.

Попробуйте это:

if data[0,3] == [0xff, 0xd8, 0xff] 

в качестве условия.

+0

Я все еще немного новичок в рубине и тому подобное. Я использую IO для чтения в 4 байтах из фактического файла JPG, и я думаю, что он читает шестнадцатеричные значения в строковой форме (?), Но не полностью уверен. В любом случае массив был хорошей идеей, но не работал:/ – Kyle

+0

Является ли ваша строка, возможно, другой кодировкой кодировки тем, что вы ожидаете? Вы распечатали первые три байта строки и проверили значения байтов? – mcfinnigan

+0

Я также обнаружил, что это боль. Если я использую 'puts' для отображения данных, он всегда появляется как ????. Я подтвердил, что он читает правильные данные. – Kyle

0

Вы должны иметь возможность сравнить информацию о файле с кодами символов, что-то вроде:

if data[0, 3] == 0xff.chr + 0xd8.chr + 0xff.chr 
    puts "This is a JPG" 
end 

Если вы застряли, вы всегда можете заглянуть код в fastimage драгоценного камня, код обнаружения типа здесь: https://github.com/sdsykes/fastimage/blob/master/lib/fastimage.rb#L337-L354

Как и другие (@Stefan), строки не совпадали в вашем первоначальном примере, потому что кодировки отличались.

# Check the encodings for our strings: 
"\xff\xd8\xff".encoding     #=> <Encoding:UTF-8> 
(0xff.chr + 0xd8.chr + 0xff.chr).encoding #=> <Encoding:ASCII-8BIT> 

# Compare our two strings with different encodings: 
utf8 = "\xff\xd8\xff" 
ascii = 0xff.chr + 0xd8.chr + 0xff.chr 

utf8 == ascii        #=> false 
utf8.force_encoding("ASCII-8BIT") == ascii #=> true 

Ваш оригинальный код на самом деле работал бы хорошо, если вы вынуждены кодировку быть ASCII-8BIT

+0

Ваше решение сработало! Не могли бы вы немного объяснить мне, как это работает, чтобы я мог понять это? – Kyle

+0

Конечно, я обновлю ответ. –

+0

Ответ Стефана очень хорошо объясняет это; вы должны проверить его ответ ниже! –

0

Идентификация файлов это хорошая вещь, чтобы позволить кому-то еще делать , если сможешь.Камни ruby-filemagic сделают это.

gem 'ruby-filemagic' 

При использовании, он возвращает строку:

require 'filemagic' 

magic = FileMagic.new 
p magic.file("/tmp/pic1.jpg") 
# => "JPEG image data, JFIF standard 1.02" 

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

case magic.file(path) 
when /JPEG/ 
    # do JPEG stuff 
when /GIF/ 
    # do GIF stuff 
else 
    # we don't recognize it 
end 

рубинового filemagic использует libmagic библиотеку, которая распознает большое количество типов файлов.

Документация немного редка (README даже не имеет примера «привет мир»), и она не обновляется через несколько лет, но не позволяйте этому мешать вам попробовать. Он достаточно прост в использовании и довольно прочный - сегодня у меня есть производственный код, и он все еще работает нормально.

Если по какой-либо причине вы не можете использовать драгоценный камень, но находитесь в среде * nix и имеете доступ к команде «файл», вы можете получить такую ​​же функциональность, выгрузив ее в «файл»:

p `file /tmp/pic1.jpg` 
# => "/tmp/pic1.jpg: JPEG image data, JFIF standard 1.02\n 

В Debian, то файл команда обеспечивается пакетом файла. Ваша ОС может отличаться.

Смежные вопросы