2013-05-29 106 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中,所述文件命令由包文件提供。你的操作系統可能有所不同

相關問題