api
我使用上面的代码从python中的立体声wav文件中提取字节。但是,我得到了一些乱码而不是字节。使用import wave,struct
f = wave.open('bird.wav', 'r')
for i in range(5,10):
frame = f.readframes(i)
print frame
struct.unpack('<H',frame)
函数我收到以下错误
&#34; unpack需要一个长度为2&#34;
的字符串参数
我在代码中进行哪些更改以在1&0和0&#39;中打印这些字节?我想稍后修改用于隐写术的音频帧的LSB。
答案 0 :(得分:1)
我不确定你为什么要用二进制文件打印这些字节,但这样做很容易。
您需要将字节转换为整数,然后使用str.format
方法对其进行格式化,旧的%
- 样式格式化不会做位。
执行转换的简单方法是使用ord
函数,但对于大量字节,最好通过创建bytearray
来在一次点击中转换它们。
#Some bytes, using hexadecimal escape codes
s = '\x01\x07\x0f\x35\xad\xff'
print ' '.join(['{0:08b}'.format(ord(c)) for c in s])
b = bytearray(s)
print ' '.join(['{0:08b}'.format(u) for u in b])
<强>输出强>
00000001 00000111 00001111 00110101 10101101 11111111
00000001 00000111 00001111 00110101 10101101 11111111
通常,十六进制表示法比二进制表示更方便。
from binascii import hexlify
print hexlify(s)
print ' '.join(['%02X' % u for u in b])
print ' '.join(['%02X' % ord(c) for c in s])
print ' '.join(['{0:02X}'.format(ord(c)) for c in s])
<强>输出强>
01070f35adff
01 07 0F 35 AD FF
01 07 0F 35 AD FF
01 07 0F 35 AD FF
我刚刚看到你的评论重新隐写。翻转字节位的最方便的方法是使用bytearray
。您可以使用bytearray
函数轻松地将str
转换回字符串。
print hexlify(str(b))
<强>输出强>
01070f35adff
字符串格式化选项在官方Python文档中描述。对于旧%
- 样式格式,请参阅5.6.2. String Formatting Operations。对于现代str.format
选项,请参阅7.1.3. Format String Syntax和7.1.3.1. Format Specification Mini-Language。
在{0:08b}
中冒号之前的0
是字段位置(在最近的Python版本中可以省略)。它表示我们希望将此格式代码应用于.format
的第一个参数,即索引为零的参数。例如,
'{0} {2} {1}'.format('one', 'two', 'three')
打印
one three two
b
表示我们要将数字打印为二进制数。 08
表示我们希望输出宽度为8个字符,对于小于8位的二进制数,填充为零。
在%02X
中,大写X
表示我们要将数字打印为十六进制,对于大于9的数字使用大写字母A-F,我们可以使用小写x
来获取小写字母。 02
表示我们希望输出宽度为2个字符,对于小于2个十六进制数字的十六进制数字,填充为零。
答案 1 :(得分:1)
如果要修改字节的lsb,则无法将值表示为二进制字符串。实际上,你会做一些事情(伪代码):
<%= link_to fa_icon("close"), wiki_collaborator_path(@wiki, c), method: :delete, remote: true %>
有更多直接有效的方法来修改位值,而bitwise operators则更新。例如,假设我们要将01001001(十进制73)更改为01001000.我们要创建一个位掩码11111110,其十进制值为254,byte = '\x6h'
binary = convert_to_bits(byte) # some way of getting 1s and 0s in a string
binary = binary[:7] + my_bit_string
byte = convert_to_byte(binary)
表示我们的值。
AND
当你将一个位嵌入一个字节时,lsb可能会改变,也可能不会改变。有很多方法可以解决这个问题,但最直接的方法是将lsb归零,然后使用>>> value = 73 & 254
>>> value
72
>>> '{0:08b}'.format(value)
'01001000'
覆盖它(如果你还希望嵌入多个位,则非常通用)。
OR
您也可以使用byte = (byte & 254) | my_bit
将lsb归零,然后使用right shift
,但这需要2次操作而不是1次。
left shift
或者您可以检查lsb和您的位是否不同并使用byte = ((byte >> 1) << 1) | my_bit
翻转它。但是,此方法使用分支并且效率最低。
XOR
因此,您需要做的就是将字节转换为整数数组。您可以使用if (byte & 1) != my_bit:
byte = byte ^ 1
# no need to do anything if they are the same
,但有更高效的内置方式。使用bytearray()
和bytes()
:
[ord(byte) for byte in frame]
使用array.array()
(对于数十万字节来说,这似乎有点慢):
>>> frame = '\x0f\x02\x0e\x02\xf7\x00\xf7\x00T\xffT\xff'
>>> frame_bytes = bytearray(frame)
>>> frame_bytes[0]
15
>>> frame_bytes[0] = 14 # modify
>>> bytes(frame_bytes) # convert back to bytes
'\x0e\x02\x0e\x02\xf7\x00\xf7\x00T\xffT\xff'
嵌入和提取的示例。
>>> import array
>>> frame = '\x0f\x02\x0e\x02\xf7\x00\xf7\x00T\xffT\xff'
>>> frame_bytes = array.array('B', frame)
>>> frame_bytes[0]
15
>>> frame_bytes[0] = 14 # modify
>>> frame_bytes.tostring() # convert back to bytes; in Python 3 use `tobytes()`
'\x0e\x02\x0e\x02\xf7\x00\xf7\x00T\xffT\xff'
如果您的秘密是一个字符串或一系列字节,则convert them to a list of 1s and 0s很容易。
最后,请确保不要修改任何标头数据,因为这可能会使文件无法读取。