2013-05-29 38 views
4

我基本上是在读一图片文件的标题,做一个快速的比较,看看有什么样的文件,它实际上是。 BMP,GIF,PNG都很容易,因为它们的标题分别包含BM,GIF和PNG以标识它们自己。 JPG会让我感到一阵循环。红宝石 - 比较“==”十六进制值字符串

jpg的前3个字节往往是0xff \ 0xd8 \ 0xff,对于我的生活,无论如何设置它,我都无法在简单比较中获得真正的值。

我在第一个4个字节阅读:

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

我知道我很接近,但我不能得到它的工作。请让我知道我在这里错过了什么。

注:我知道有宝石为我做到这一点,但我不希望使用的宝石。就那么简单。

+0

你的数据是怎样的? –

+0

@Anand我使用data [0,3]来获取我在 – Kyle

回答

9

这是一个字符编码的问题会工作得很好。阅读从JPEG前4个字节返回一个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 

Integer#chr(由马里奥Visic建议)创建级联ASCII字符也可以工作:

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

您的代码工作正常,我当数据是一个字符串 - 但数据很可能字节值的数组。

试试这个:

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

为作为条件。

+0

中读到的4中的前3个字节。对于ruby等我还是有点新的。即时通讯使用IO从实际的JPG文件中读取4个字节,我认为它读取字符串形式(?)的十六进制值,但不完全确定。无论如何,这个数组是一个好主意,但没有奏效:/ – 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

虽然Stefan的回答很好解释,你应该在下面检查他的答案! –

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库,识别大量的文件类型。

该文档有点稀疏(自述文件甚至没有“hello world”示例),并且它在几年内没有更新,但不要让它阻止您尝试它。使用起来非常简单,而且非常稳固 - 今天我使用了产品代码,并且它仍然可以正常工作。

如果出于某种原因无法使用该gem,但处于* nix环境并且可以访问“文件”命令,则可以通过将其解压为“文件”来获得相同的功能:

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

在Debian中,所述文件命令由包文件提供。你的操作系统可能有所不同