如何載入和儲存遊戲影像?以及影像與位元組序列的轉換等問題
訂閱 375
雖然本節的範例中包含繪製影像的程式碼,但本節不會講解與影像繪製相關的問題,要了解繪製,請檢視如何繪製表面(影像,字型)?以及色彩混合模式,裁剪區域,鎖定等問題一節。
Pygame 影像載入,image 模組簡介影片示範 YouTube
Pygame 中的 image 模組
Pygame 套件的image
模組,包含了與影像相關的功能,主要涉及影像的載入,影像的儲存,以及影像的轉換,當你匯入pygame
模組時,image
模組會被pygame
模組匯入。事實上,Pygame 套件並不包含一個名稱為Image
的類別,image
模組只會傳回或操作繪製了影像的Surface
物件。
表面
關於表面物件Surface
,你可以檢視如何使用 Surface 表面物件?以及表面(影像)的透明度,透明色彩鍵,色彩,大小等問題一節。
判斷遊戲是否支援擴充的影像格式
image
模組的get_extended
函式,可用於判斷遊戲是否支援擴充的影像格式,這通常取決於你所安裝的 Pygame 版本,但無論如何,Pygame 總是支援未壓縮的bmp
影像格式。
get_extended()
- 傳回值
如果
get_extended
函式傳回True
,那麽表示遊戲支援擴充的影像格式。
from pygame import image
print(f'支援擴充的影像格式?{image.get_extended()}')
支援擴充的影像格式?True
為遊戲載入影像
image
模組的load
,load_basic
,load_extended
函式,可用於載入影像並傳回一個繪製了影像的Surface
表面物件,其中,load
和load_extended
函式可以自行判斷影像的格式,但有時需要通過檔案的副檔名來完成此目標,load_basic
函式則只能載入bmp
格式的影像。
當 Pygame 不支援擴充的影像格式時,image
模組的load_extended
函式會引發例外狀況NotImplementedError: loading images of extended format is not available
。至於如何判斷 Pygame 是否支援擴充的影像格式,你可以檢視判斷遊戲是否支援擴充的影像格式一段。
load(filename, namehint='')
load_basic(filename)
load_extended(filename, namehint='')
- filename 參數
filename
參數是表示影像檔案路徑的字串,或包含影像檔案路徑的類路徑(path-like
)物件,或包含影像資料的IO
物件。- namehint 參數
namehint
參數是一個用於提示檔案副檔名的字串,如果filename
參數是一個IO
物件,並且你希望傳遞檔案副檔名的話。- 傳回值
load
,load_basic
,load_extended
函式的傳回值是繪製了影像的Surface
表面物件。
load,load_extended 函式能夠載入的影像格式有哪些?
如果 Pygame 支援完整的擴充影像格式,那麽load
和load_extended
函式能夠載入以下的影像格式,bmp
,gif
(不支援動畫),jpeg
(jpg
),lbm
(pbm
,pgm
,ppm
),pcx
,png
,pnm
,svg
(有限的支援),tga
(非壓縮),tiff
(tif
),webp
,xpm
。
load,load_basic,load_extended 函式所傳回的 Surface 物件需要進行轉換
在大部分情況下,你需要對load
,load_basic
,load_extended
函式所傳回的Surface
物件進行轉換,呼叫他們的convert
或convert_alpha
方法,以便在視窗中快速進行繪製。
在下面的範例中,我們使用 Python 的open
函式開啟了影像檔案sky.webp
,並將傳回的IO
物件傳遞給了load
函式。
# 在執行腳本前,請將命令列跳躍至 load.py 所在的目錄
from pygame import image, display
# 通過 IO 物件載入影像檔案 sky.webp
data = open('sky.webp', 'rb')
sky = image.load(data)
# 直接載入影像檔案 candy.png
candy = image.load_extended('candy.png')
# 建立遊戲視窗,繪製天空和糖果,並等候 2 秒鐘
s = display.set_mode((800, 600))
s.blit(sky, (0, 0))
s.blit(candy, (100, 100))
display.flip()
import time
time.sleep(2)
將遊戲畫面儲存為影像
image
模組的save
,save_extended
函式,可用於將繪製了影像的Surface
表面物件儲存為檔案或IO
物件。一個遊戲中可能包含多個Surface
物件,他們也許繪製了遊戲中的某個角色或視窗的整個顯示區域。save
和save_extended
函式可根據檔案的副檔名來決定影像格式,如果無法得知檔案副檔名,那麽影像格式將被認定為tga
(非壓縮)。
當 Pygame 不支援擴充的影像格式時,save_extended
函式會引發例外狀況NotImplementedError: saving images of extended format is not available
。至於如何判斷 Pygame 是否支援擴充的影像格式,你可以檢視判斷遊戲是否支援擴充的影像格式一段。
save(surface, filename, namehint='')
save_extended(surface, filename, namehint='')
- surface 參數
surface
參數是需要被轉換的Surface
表面物件。- filename 參數
filename
參數是表示影像檔案路徑的字串,或包含影像檔案路徑的類路徑(path-like
)物件,或可儲存影像資料的IO
物件。- namehint 參數
namehint
參數是一個用於提示檔案副檔名的字串,如果filename
參數是一個IO
物件,並且你希望傳遞檔案副檔名的話。
save,save_extended 函式能夠儲存的影像格式有哪些?
如果 Pygame 支援完整的擴充影像格式,那麽save
和save_extended
函式能夠將Surface
表面物件儲存為以下的影像格式,bmp
,jpeg
(jpg
),png
,tga
(非壓縮)。
# 在執行腳本前,請將命令列跳躍至 save.py 所在的目錄
from pygame import image, Surface
# 載入影像檔案,並將他們繪製在表面物件 surface 中
sky = image.load('sky.webp')
candy = image.load_extended('candy.png')
surface = Surface((800, 600))
surface.blit(sky, (0, 0))
surface.blit(candy, (100, 100))
# 將 surface 儲存至檔案,影像格式為 jpg
image.save(surface, 'combine.jpg')
save,save_extended 函式所使用的 IO 物件需要改變指標位置才能被重新載入
如果使用save
,save_extended
函式,將Surface
表面物件儲存至某個IO
物件,那麽可能需要將IO
物件的指標移動至開頭,才能使用image
模組重新載入該IO
物件。
在下面的範例中,我們將Surface
物件儲存到了IO
物件中,之後需要呼叫IO
物件的seek
方法將指標移動至開頭,否則重新載入IO
物件可能會導致例外狀況pygame.error: Unsupported image format
。
# 在執行腳本前,請將命令列跳躍至 reload.py 所在的目錄
from pygame import image
# 將 surface 儲存至 IO 物件
import io
bs = io.BytesIO()
sky = image.load('sky.webp')
# 指定影像格式為 png
image.save(sky, bs, '.png')
# 重新載入 IO 物件之前,需要將指標移動至開頭
bs.seek(0)
new_sky = image.load(bs, '.png')
將影像轉換為位元組序列物件
image
模組的tobytes
函式,可用於將繪製了影像的Surface
表面物件轉換為一個bytes
位元組序列物件。當你使用該函式時,通常是希望將遊戲影像傳遞給其他 Python 套件進行處理。
image
模組的tostring
函式與tobytes
函式相同,你可以將其中一個視為另一個的別名,但建議采用tobytes
。
tobytes(surface, format, flipped=False)
- surface 參數
surface
參數是被轉換為bytes
位元組序列的Surface
表面物件。- format 參數
format
參數是一個字串,表示轉換所采用的色彩格式,擁有以下有效取值,'P'
(采用 8 位調色板表示色彩),'RGB'
(使用 24 個 bit 表示色彩,按照紅綠藍的順序),'RGBX'
(使用 32 個 bit 表示色彩,按照紅綠藍的順序,末尾的 8 個比特不被使用),'RGBA'
(使用 32 個 bit 表示色彩,按照紅綠藍透明度的順序),'ARGB'
(使用 32 個 bit 表示色彩,按照透明度紅綠藍的順序),'BGRA'
(使用 32 個 bit 表示色彩,按照藍綠紅透明度的順序),'RGBA_PREMULT'
(使用 32 個 bit 表示色彩,按照紅綠藍透明度的順序,其中紅綠藍已經預先與透明度進行了計算),'ARGB_PREMULT'
(使用 32 個 bit 表示色彩,按照透明度紅綠藍的順序,其中紅綠藍已經預先與透明度進行了計算)。- flipped 參數
flipped
參數是一個布林值(預設為False
),如果為True
,則相當於先將Surface
物件表示的影像進行垂直翻轉,然後再轉換為bytes
位元組序列(這對於 Python PyOpenGL 套件可能是有效的)。
在下面的範例中,我們使用tobytes
函式將Surface
物件轉換為bytes
物件,然後使用PIL
模組(需要安裝)將bytes
物件儲存為影像檔案pil.sky.webp
。
# 在執行腳本前,請將命令列跳躍至 to_bytes.py 所在的目錄
from pygame import image
# 將 Surface 物件轉換為 bytes,色彩格式為 RGBA
sky = image.load('sky.webp')
bs = image.tobytes(sky, 'RGBA')
# 使用 PIL 讀取 bytes,並將影像儲存為檔案 pil.sky.webp
import PIL.Image
i = PIL.Image.frombytes('RGBA', (729, 1296), bs)
i.save('pil.sky.webp')
將位元組序列物件轉換為影像
image
模組的frombytes
函式,可用於將bytes
位元組序列物件轉換為一個表示影像的Surface
表面物件。當你使用該函式時,bytes
位元組序列物件通常來自於其他 Python 套件,這意味著要將其他套件處理的影像轉換為Surface
物件。
image
模組的fromstring
函式與frombytes
函式相同,你可以將其中一個視為另一個的別名,但建議采用frombytes
。
frombytes(bytes, size, format, flipped=False)
- bytes 參數
bytes
參數是被轉換為Surface
表面物件的bytes
位元組序列。- size 參數
size
參數是一個形式類似於(width,height)
的元組,或形式類似於[width,height]
的串列,其中width
為影像的寬度,height
為影像的高度。你不能隨意設定
size
參數,其表示的大小必須與bytes
參數對應的影像的大小相同。- format 參數
format
參數是一個字串,表示轉換所采用的色彩格式,擁有以下有效取值,'P'
(采用 8 位調色板表示色彩),'RGB'
(使用 24 個 bit 表示色彩,按照紅綠藍的順序),'RGBX'
(使用 32 個 bit 表示色彩,按照紅綠藍的順序,末尾的 8 個比特不被使用),'RGBA'
(使用 32 個 bit 表示色彩,按照紅綠藍透明度的順序),'ARGB'
(使用 32 個 bit 表示色彩,按照透明度紅綠藍的順序),'BGRA'
(使用 32 個 bit 表示色彩,按照藍綠紅透明度的順序)。- flipped 參數
flipped
參數是一個布林值(預設為False
),如果為True
,則轉換後的Surface
物件所表示的影像會被垂直翻轉。
在下面的範例中,我們使用frombytes
函式,將包含天空影像的bytes
物件轉換為了Surface
物件,並對影像進行了垂直翻轉。
# 在執行腳本前,請將命令列跳躍至 from_bytes.py 所在的目錄
from pygame import image, display
# 使用 PIL 讀取影像檔案,並轉換為 bytes 物件
import PIL.Image
bs = PIL.Image.open('sky.webp').tobytes()
# 將 bytes 物件轉換為 Surface 物件
sky = image.frombytes(bs, (729, 1296), 'RGB', True)
# 建立遊戲視窗,繪製天空,並等候 2 秒鐘
s = display.set_mode((800, 600))
s.blit(sky, (0, 0))
display.flip()
import time
time.sleep(2)
將位元組緩沖轉換為影像
image
模組的frombuffer
函式,可用於將位元組緩沖區中的內容轉換為一個表示影像的Surface
表面物件,該函式的參數的作用與frombytes
函式類似,但存在以下不同。
image
模組的frombuffer
函式的bytes
參數可以是一個BufferProxy
,bytes
,bytearray
,memoryview
,或遵守緩沖協定的物件。相對於frombytes
函式,frombuffer
函式的bytes
參數額外支援'BGR'
(使用 24 個 bit 表示色彩,按照藍綠紅的順序)。
frombuffer(bytes, size, format)
frombuffer 函式擁有更高的執行效率
相對於frombytes
函式,frombuffer
函式擁有更高的執行效率,因為沒有分配和複製影像像素資料的過程。
# 在執行腳本前,請將命令列跳躍至 from_buffer.py 所在的目錄
from pygame import image, display
# 使用 PIL 讀取影像檔案,並轉換為 bytes 物件
import PIL.Image
bs = PIL.Image.open('sky.webp').tobytes()
# 將 bytes 物件轉換為 Surface 物件
sky = image.frombuffer(bs, (729, 1296), 'RGB', True)
# 建立遊戲視窗,繪製天空,並等候 2 秒鐘
s = display.set_mode((800, 600))
s.blit(sky, (0, 0))
display.flip()
import time
time.sleep(2)
取得 SDL_Image 的版本資訊
image
模組的get_sdl_image_version
函式,其傳回值是一個元組,該元組包含了 SDL_Image 的版本資訊。
get_sdl_image_version(linked=True)
- linked 參數
如果
linked
參數為True
,則函式get_sdl_image_version
傳回目前所使用的 SDL_Image 的版本資訊,否則傳回 Pygame 套件在編譯階段所針對的 SDL_Image 版本。- 傳回值
get_sdl_image_version
函式的傳回值是一個形式類似於(major,minor,patch)
的 Python 元組,其中major
表示主要版本號碼,minor
表示次要版本號碼,patch
表示修補號碼。當你所安裝的 Pygame 版本不支援擴充影像格式時,
get_sdl_image_version
函式將傳回空值None
,這反映了擴充影像格式的實作需要 SDL_Image。
from pygame import image
# 取得 SDL_Image 版本
print(f'目前使用的 SDL_Image 版本:{image.get_sdl_image_version()}')
print(f'編譯階段針對的 SDL_Image 版本:{image.get_sdl_image_version(False)}')
目前使用的 SDL_Image 版本:(2, 0, 5)
編譯階段針對的 SDL_Image 版本:(2, 0, 5)