如何加载和保存游戏图像?以及图像与字节序列的转换等问题
关注 1260
虽然本节的示例中包含绘制图像的代码,但本节不会讲解与图像绘制相关的问题,要了解绘制,请查看如何绘制表面(图像,字体)?以及颜色混合模式,剪辑区域,锁定等问题一节。
如何在 Pygame 中加载图像视频演示 YouTube如何在 Pygame 中加载图像视频演示 Bilibili
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)