2015-06-21 65 views
0

注意:我對Encoding/Decoding沒有太多瞭解,但是在遇到這個問題後,這些單詞對我來說已經是完整的術語。Python編碼:打開/讀取圖像文件,解碼圖像,重新編碼圖像

問題: 我在這裏有點困惑。我正在玩編碼/解碼圖像,在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) 
+0

我開始在維基百科上查找jpg,然後純文本文件。一個圖像文件不會有任何純文本數據可以被編碼成ascii。他們只是不同類型的數據,蘋果和桔子,純文本文件和二進制文件 –

+0

因此,我可以從ascii解碼圖像數據,但只是沒有回到它?那意味着這是一種單向轉換? – Crispy

+0

等待,當打開一個文件爲二進制文件時,它的編碼是什麼?我知道python默認爲ascii,但這是原始數據正確嗎?該死,我不能通過這個。 – Crispy

回答

1

的UnicodeEncodeError是雨後春筍般冒出來,因爲JPEG是一個二進制文件和ASCII編碼是在純文本文件純文本。

純文本文件可以使用通用文本編輯器創建,如用於Windows的記事本或用於Linux的nano。大多數將使用ASCII或Unicode編碼。當一個文本編輯器正在讀取一個ASCII文件時,它會抓取一個字節,比如說01100001(分解爲97),並找到相應的字形'a'。

所以當一個文本編輯器嘗試讀取一個JPG文件時,它將獲取相同的字節01100001並獲得'a',但由於該文件包含用於顯示照片的信息,因此文本將變得亂七八糟。嘗試在記事本或nano中打開jpeg。

至於這裏的編碼是一個解釋:What is the difference between encode/decode?

+0

感謝您發佈答案。 – Crispy

2

不同於正常/疼痛的文本文件的圖像文件不具有任何的編碼,所示的數據是圖像的二進制等效的可視化表示。就像@ 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