使用little-endian格式将4个字节转换为整数(最低有效位优先)

时间:2013-07-06 01:24:46

标签: ruby

根据Wikipedia页面,.bmp图像的宽度存储在文件的标头中,字节为0x12到0x15。例如,在256x256的图像中,字节0x12到0x15看起来像这样; Ruby将每个字节转换为整数:

file = File.open("red_bmp.bmp", "r")
bytes = file.bytes.to_a
bytes[0x12..0x15]
#=> [0, 1, 0, 0]

为了将其转换为little-endian格式,我最好的解决方案是将每个十进制值转换为十六进制字符串,反转数组,连接元素,并将生成的十六进制字符串转换回整数。

width = bytes[0x12..0x15].map {|x| x.to_s(16).rjust(2, "0")}.reverse.join.to_i(16)
#=> 256
  • 有更简单的方法吗?
  • 是否有一种简单的方法来读取文件并返回十六进制值而不是整数数组(不使用x.to_s(16).rjust(2, "0"))?

2 个答案:

答案 0 :(得分:6)

Ruby中的字节争吵通常涉及String#unpackArray#pack;在您的情况下,您希望将一些字节解压缩为本机Ruby值,因此您需要String#unpack并且希望使用V格式:

V         | Integer | 32-bit unsigned, VAX (little-endian) byte order

我会做这样的事情:

# The "b for binary" is important since you just want to deal with bytes
# and any encoding will get in the way.
fp = open(whatever, 'rb')

# Seek to the desired offset.
fp.seek(0x12)

# Read in four bytes.
s = fp.read(4)

# Unpack the bytes and the array:
two_fifty_six = s.unpack('V').first

答案 1 :(得分:2)

  

有没有更简单的方法可以解决这个问题?

f =  File.open('mybmp.bmp',"wb")
str = [256, 256].pack "l>2"
p str     #"\x00\x00\x01\x00\x00\x00\x01\x00"
f.write str
f.close

f = File.open('mybmp.bmp', "rb")
str = f.read 8
arr = str.unpack "l>2"
p arr     #[256, 256]

str = arr.pack("l<2")
p str    #"\x00\x01\x00\x00\x00\x01\x00\x00"
  

是否有一种简单的方法来读取文件并返回十六进制值而不是整数数组

用这一行替换上面的最后两行:

p arr.map {|num| sprintf "%04x", num }  #["0100", "0100"]

或者,或许:

arr = str.unpack "h*"
results = []

arr[0].scan(/.{8}/) do |chars8|
  curr = ""

  chars8.scan(/.{2}/) do |chars2|
    curr << "\\x#{chars2}"
  end

  results << curr
end

p results     #["\\x00\\x00\\x10\\x00", "\\x00\\x00\\x10\\x00"]