Python 编码:Open/Read 图像文件、解码图像、重新编码图像
Python Encoding: Open/Read Image File, Decode Image, RE-Encode Image
注意:我不太了解编码/解码,但是在我 运行 解决这个问题之后,这些词现在对我来说完全是行话。
问题:
我在这里有点困惑。我正在玩 encoding/decoding 图像,将图像存储为 django 模型中的 TextField
,环顾 Stack-Overflow 我发现我可以从 ascii
解码图像(我认为或二进制?任何 open('file', 'wb')
用作编码。我假设默认 ascii
) 到 latin1
并将其存储在数据库中没有问题。
问题来自从 latin1
解码数据创建图像。当尝试写入文件句柄时,我得到一个 UnicodeEncodeError
说 ascii
编码失败。
我认为问题是当以二进制数据 (rb
) 打开文件时,它不是正确的 ascii
编码,因为它包含二进制数据。然后我将二进制数据解码为 latin1
但是当转换回 ascii
时(尝试写入文件时自动编码),它失败了,原因不明。
我的猜测是,当解码为 latin1
时,原始二进制数据被转换为其他内容,然后当尝试编码回 ascii
时,它无法识别曾经的原始二进制数据数据。 (尽管原始数据和解码数据的长度相同)。
或者问题不在于对 latin1
的解码,而是我正在尝试对二进制数据进行 ascii 编码。在这种情况下,我将如何编码 latin1
数据返回图像。
我知道这很令人困惑,但我对这一切都很困惑,所以我无法很好地解释它。如果有人能回答这个问题,可能是谜语大师。
一些可视化代码:
>>> image_handle = open('test_image.jpg', 'rb')
>>>
>>> raw_image_data = image_handle.read()
>>> latin_image_data = raw_image_data.decode('latin1')
>>>
>>>
>>> # The raw data can't be processed by django
... # but in `latin1` it works
>>>
>>> # Analysis of the data
>>>
>>> type(raw_image_data), len(raw_image_data)
(<type 'str'>, 2383864)
>>>
>>> type(latin_image_data), len(latin_image_data)
(<type 'unicode'>, 2383864)
>>>
>>> len(raw_image_data) == len(latin_image_data)
True
>>>
>>>
>>> # How to write back to as a file?
>>>
>>> copy_image_handle = open('new_test_image.jpg', 'wb')
>>>
>>> copy_image_handle.write(raw_image_data)
>>> copy_image_handle.close()
>>>
>>>
>>> copy_image_handle = open('new_test_image.jpg', 'wb')
>>>
>>> copy_image_handle.write(latin_image_data)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-3: ordinal not in range(128)
>>>
>>>
>>> latin_image_data.encode('ascii')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-3: ordinal not in range(128)
>>>
>>>
>>> latin_image_data.decode('ascii')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-3: ordinal not in range(128)
弹出 UnicodeEncodeError,因为 jpeg 是二进制文件,而 ASCII 编码用于纯文本文件中的纯文本。
可以使用通用文本编辑器创建纯文本文件,例如用于 Windows 的记事本或用于 Linux 的 nano。大多数将使用 ASCII 或 Unicode 编码。当文本编辑器读取 ASCII 文件时,它会抓取一个字节,比如 01100001(十进制为 97),并找到相应的字形,'a'.
因此,当文本编辑器尝试读取 jpg 文件时,它会抓取相同的字节 01100001 并得到 'a',但由于该文件包含显示照片的信息,因此文本将只是乱码。尝试在记事本或 nano 中打开 jpeg。
关于编码这里有一个解释:What is the difference between encode/decode?
与 normal/pain 文本文件不同,图像文件没有任何编码,显示的数据是图像二进制等价物的可视化表示。就像@cameron-f 在上面的问题评论中所说,这基本上是胡言乱语,完成的任何编码都会破坏图像文件,所以不要尝试。
但这并不意味着所有的希望都破灭了。这是我通常将图像转换为字符串并返回图像的方法。
from base64 import b64decode, b64encode
image_handle = open('test_image.jpg', 'rb')
raw_image_data = image_handle.read()
encoded_data = b64encode(raw_image_data)
compressed_data = zlib.compress(encoded_image, 9)
uncompressed_data = zlib.decompress(compressed_data)
decoded_data = b64decode(uncompressed_data)
new_image_handle = open('new_test_image.jpg', 'wb')
new_image_handle.write(decoded_data)
new_image_handle.close()
image_handle.close()
# Data Types && Data Size Analysis
type(raw_image_data), len(raw_image_data)
>>> (<type 'str'>, 2383864)
type(encoded_image), len(encoded_image)
>>> (<type 'str'>, 3178488)
type(compressed_data), len(compressed_data)
>>> (<type 'str'>, 2189311)
type(uncompressed_data), len(uncompressed_data)
>>> (<type 'str'>, 3178488)
type(decode_data), len(decode_data)
>>> (<type 'str'>, 2383864)
# Showing that the conversions were successful
decode_data == raw_image_data
>>> True
encoded_data == uncompressed_data
>>> True
注意:我不太了解编码/解码,但是在我 运行 解决这个问题之后,这些词现在对我来说完全是行话。
问题:
我在这里有点困惑。我正在玩 encoding/decoding 图像,将图像存储为 django 模型中的 TextField
,环顾 Stack-Overflow 我发现我可以从 ascii
解码图像(我认为或二进制?任何 open('file', 'wb')
用作编码。我假设默认 ascii
) 到 latin1
并将其存储在数据库中没有问题。
问题来自从 latin1
解码数据创建图像。当尝试写入文件句柄时,我得到一个 UnicodeEncodeError
说 ascii
编码失败。
我认为问题是当以二进制数据 (rb
) 打开文件时,它不是正确的 ascii
编码,因为它包含二进制数据。然后我将二进制数据解码为 latin1
但是当转换回 ascii
时(尝试写入文件时自动编码),它失败了,原因不明。
我的猜测是,当解码为 latin1
时,原始二进制数据被转换为其他内容,然后当尝试编码回 ascii
时,它无法识别曾经的原始二进制数据数据。 (尽管原始数据和解码数据的长度相同)。
或者问题不在于对 latin1
的解码,而是我正在尝试对二进制数据进行 ascii 编码。在这种情况下,我将如何编码 latin1
数据返回图像。
我知道这很令人困惑,但我对这一切都很困惑,所以我无法很好地解释它。如果有人能回答这个问题,可能是谜语大师。
一些可视化代码:
>>> image_handle = open('test_image.jpg', 'rb')
>>>
>>> raw_image_data = image_handle.read()
>>> latin_image_data = raw_image_data.decode('latin1')
>>>
>>>
>>> # The raw data can't be processed by django
... # but in `latin1` it works
>>>
>>> # Analysis of the data
>>>
>>> type(raw_image_data), len(raw_image_data)
(<type 'str'>, 2383864)
>>>
>>> type(latin_image_data), len(latin_image_data)
(<type 'unicode'>, 2383864)
>>>
>>> len(raw_image_data) == len(latin_image_data)
True
>>>
>>>
>>> # How to write back to as a file?
>>>
>>> copy_image_handle = open('new_test_image.jpg', 'wb')
>>>
>>> copy_image_handle.write(raw_image_data)
>>> copy_image_handle.close()
>>>
>>>
>>> copy_image_handle = open('new_test_image.jpg', 'wb')
>>>
>>> copy_image_handle.write(latin_image_data)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-3: ordinal not in range(128)
>>>
>>>
>>> latin_image_data.encode('ascii')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-3: ordinal not in range(128)
>>>
>>>
>>> latin_image_data.decode('ascii')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-3: ordinal not in range(128)
弹出 UnicodeEncodeError,因为 jpeg 是二进制文件,而 ASCII 编码用于纯文本文件中的纯文本。
可以使用通用文本编辑器创建纯文本文件,例如用于 Windows 的记事本或用于 Linux 的 nano。大多数将使用 ASCII 或 Unicode 编码。当文本编辑器读取 ASCII 文件时,它会抓取一个字节,比如 01100001(十进制为 97),并找到相应的字形,'a'.
因此,当文本编辑器尝试读取 jpg 文件时,它会抓取相同的字节 01100001 并得到 'a',但由于该文件包含显示照片的信息,因此文本将只是乱码。尝试在记事本或 nano 中打开 jpeg。
关于编码这里有一个解释:What is the difference between encode/decode?
与 normal/pain 文本文件不同,图像文件没有任何编码,显示的数据是图像二进制等价物的可视化表示。就像@cameron-f 在上面的问题评论中所说,这基本上是胡言乱语,完成的任何编码都会破坏图像文件,所以不要尝试。
但这并不意味着所有的希望都破灭了。这是我通常将图像转换为字符串并返回图像的方法。
from base64 import b64decode, b64encode
image_handle = open('test_image.jpg', 'rb')
raw_image_data = image_handle.read()
encoded_data = b64encode(raw_image_data)
compressed_data = zlib.compress(encoded_image, 9)
uncompressed_data = zlib.decompress(compressed_data)
decoded_data = b64decode(uncompressed_data)
new_image_handle = open('new_test_image.jpg', 'wb')
new_image_handle.write(decoded_data)
new_image_handle.close()
image_handle.close()
# Data Types && Data Size Analysis
type(raw_image_data), len(raw_image_data)
>>> (<type 'str'>, 2383864)
type(encoded_image), len(encoded_image)
>>> (<type 'str'>, 3178488)
type(compressed_data), len(compressed_data)
>>> (<type 'str'>, 2189311)
type(uncompressed_data), len(uncompressed_data)
>>> (<type 'str'>, 3178488)
type(decode_data), len(decode_data)
>>> (<type 'str'>, 2383864)
# Showing that the conversions were successful
decode_data == raw_image_data
>>> True
encoded_data == uncompressed_data
>>> True