Python编码:打开/读取图像文件,解码图像,重新编码图像

时间:2015-06-21 00:31:38

标签: python image encoding character-encoding

注意:我对编码/解码知之甚少,但在遇到这个问题之后,这些话现在已经完全符合我的行话。

问题: 我在这里有点困惑。我正在玩编码/解码图像,将图像存储为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)

2 个答案:

答案 0 :(得分:3)

与普通/痛苦的文本文件不同,图像文件没有任何编码,所显示的数据是图像的二进制等价物的直观表示。就像@ 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

答案 1 :(得分:1)

UnicodeEncodeError正在弹出,因为jpeg是二进制文件,ASCII编码用于纯文本文件中的纯文本。

可以使用通用文本编辑器创建纯文本文件,例如Windows的记事本或Linux的nano。大多数将使用ASCII或Unicode编码。当文本编辑器正在读取ASCII文件时,它将获取一个字节,比如01100001(dec为97),并找到相应的字形,&#39; a&#39;。

因此,当文本编辑器尝试读取jpg时,它将获取相同的字节01100001并获得“#”;但由于该文件包含用于显示照片的信息,因此文本将是乱码。尝试在记事本或nano中打开jpeg。

至于编码,这里有一个解释:What is the difference between encode/decode?