URLhttps://learnscript.net/zh/pygame/surface/
    复制链接转到说明  示例

    如何使用 Surface 表面对象?以及表面(图像)的透明度,透明颜色键,颜色,大小等问题

    我被代码海扁署名-非商业-禁演绎
    阅读 28:21·字数 8506·更新 

    本节内容不涉及矩形的碰撞检测和子表面。

    Pygame 中的 Surface 对象

    在 Pygame 中,可以将Surface表面对象理解为画布,一些内容会被绘制在画布中,比如,图像,图形或另一个画布。某些模块的函数的返回值是一个Surface表面对象,比如,display模块的set_mode函数,如果你希望使用构造器创建Surface对象,则size参数是必需的,其他参数可以省略。一旦Surface对象被创建,其特性和颜色深度将是不可改变的,并将被黑色填充。

    Surface(size, flags, depth, masks)
    Surface(size, flags, surface)

    size 参数

    size参数表示表面的大小,他可以是依次包含表面宽度和高度的 Python 浮点数序列对象,或一个Vector2对象(对象的x变量对应表面宽度,对象的y变量对应表面高度)。

    flags 参数

    flags参数是一个整数,决定了表面对象的一些特性,可以是以下pygame模块变量,SRCALPHA(使用颜色中的透明度信息来计算透明度)。

    depth 参数

    depth参数是表示颜色深度的整数,一般不需要设置,除非你希望使用自己的像素格式,随意指定depth可能导致游戏运行缓慢。

    masks 参数

    masks参数是一个包含四个整数的 Python 元组,表示用于转换颜色和映射整数的掩码。

    surface 参数

    surface参数是作为参考的另一个表面对象,当你没有或无法提供参数flagsdepthmasks时,将采用该表面对象的特性,颜色深度或掩码。

    在下面的示例中,表面s1和表面s2的颜色深度相同。

    create.py
    # 导入 Surface 对象
    from pygame import Surface
    
    # 创建大小为 800x600,颜色深度为 16 的表面 s1 = Surface((800, 600), depth=16) print(f'颜色深度:{s1.get_bitsize()}') # 表面 s2 的颜色深度与 s1 相同 s2 = Surface([400, 300], 0, s1) print(f'颜色深度:{s2.get_bitsize()}')
    颜色深度:16
    颜色深度:16

    获取表面的大小

    Surface对象的get_widthget_heightget_size方法,可用于获取表面的宽度,高度和大小。

    get_width()

    返回值

    get_width方法的返回值是表示表面宽度的整数。

    get_height()

    返回值

    get_height方法的返回值是表示表面高度的整数。

    get_size()

    返回值

    get_size方法的返回值是形式为(width,height)的 Python 整数元组,其中width为表面宽度,height为表面高度。

    size.py
    from pygame import Surface
    
    # 创建大小为 800x600 的表面 s = Surface((800, 600)) # 显示表面的大小 print(f'宽度:{s.get_width()} 高度:{s.get_height()} 大小:{s.get_size()}')
    宽度:800 高度:600 大小:(800, 600)

    根据表面的大小创建矩形

    Surface对象的get_rect方法,可根据表面的大小创建一个新的矩形,默认情况下,新矩形的左上角为原点,大小与表面相同。

    get_rect(**kwargs)

    kwargs 参数

    可变参数kwargs所包含的位置参数将用于设置新的矩形对象,位置参数的名称需要与矩形对象的变量名称相同。

    返回值

    get_rect方法的返回值是Rect对象。

    矩形

    关于Rect矩形对象的变量,你可以查看获取和设置矩形信息一段。

    在下面的示例中,我们根据表面对象s创建了一个新的矩形,并设置了该矩形的左上角坐标。

    rect.py
    from pygame import Surface
    
    # 创建大小为 800x600 的表面 s = Surface((800, 600)) # 根据表面创建矩形,并设置左上角坐标为 10 10 print(s.get_rect(topleft=(10, 10)))
    <rect(10, 10, 800, 600)>

    获取表面的特性

    Surface对象的get_flags方法,可用于获取表面的特性,你可以通过与位运算符&来判断表面是否具有某一特性。以下是一些表示表面特性的pygame模块变量,HWACCEL(使用硬件加速),RLEACCEL(表面采用 RLE 编码),SWSURFACE(表面存储在系统内存,而非显卡内存),PREALLOC(表面采用预分配内存),SRCALPHA(表面支持像素颜色中的透明度),SRCCOLORKEY(使用表面的透明颜色键来计算透明度)。

    get_flags()

    返回值

    get_flags方法的返回值是表示表面特性的整数。

    flags.py
    from pygame import Surface, SRCALPHA
    
    # 创建支持透明度的表面 s = Surface([400, 300], SRCALPHA) # 通过 & 判断表面是否支持透明度 f = s.get_flags() print(f'表面支持颜色透明度?{f & SRCALPHA == SRCALPHA}')
    表面支持颜色透明度?True

    获取和设置表面的透明度

    如果Surface表面对象被设置了透明度,那么表面中绘制的内容将被透明度影响,当然这还要取决于绘制时所采用的参数。

    Surface对象的get_alpha方法,可用于获取表面的透明度。

    get_alpha()

    返回值

    get_alpha方法返回表示表面透明度的整数,范围从0255

    Surface对象的set_alpha方法,可用于设置表面的透明度。

    set_alpha(value)
    set_alpha(value, flags=0)

    value 参数

    value参数是表示表面透明度的整数,范围从0255,其中0为完全透明,255为不透明。

    这里需要特别说明,如果将value参数设置为空值None,那么不但表面不再拥有透明度,像素中的透明度也不再生效,即便你在创建表面对象时,将构造器的flags参数设置为了SRCALPHA

    flags 参数

    flags参数可以被设置为pygame模块的RLEACCEL变量,以在未启用硬件加速的情况下提供更好的性能,这会导致表面在其内容被修改时的效率下降,但被其他表面渲染时的效率上升。

    alpha.py
    from pygame import Surface, SRCALPHA
    
    # 创建支持透明度的表面,并设置表面的透明度 s = Surface((800, 600), SRCALPHA) s.set_alpha(50) print(f'表面的透明度:{s.get_alpha()}')
    # 在表面绘制两个透明度不同的矩形 from pygame import draw draw.rect(s, '#ff0000', [0, 0, 50, 50]) draw.rect(s, '#ff000099', [50, 0, 50, 50])
    # 创建游戏窗口并绘制 s from pygame import display w = display.set_mode((800, 600)) w.blit(s, (0, 0)) display.flip()
    import time time.sleep(3)
    表面的透明度:50

    获取和设置表面的透明颜色键

    如果Surface表面对象拥有透明颜色键,并且所绘制内容的颜色与透明颜色键相同(颜色中的红色,绿色,蓝色相同),那么该内容将不会被绘制,无论表面对象自身是否支持颜色的透明度。

    Surface对象的get_colorkey方法,可用于获取表面所使用的透明颜色键。

    get_colorkey()

    返回值

    get_colorkey方法的返回值是表示透明颜色键的形式类似于(r,g,b,a)的 Python 元组,其中r表示红色,g表示绿色,b表示蓝色,a表示透明度(始终为255)。如果表面对象没有设置透明颜色键,那么get_colorkey方法会返回空值None

    Surface对象的set_colorkey方法,可用于设置表面所使用的透明颜色键。

    set_colorkey(color)
    set_colorkey(color, flags=0)

    color 参数

    color参数是一个包含透明颜色键信息的对象,该对象的书写格式与Color对象的构造器的rgbvalue参数类似,颜色中的透明度始终被视为255(不透明)。如果将color参数设置为None,则表示取消表面的透明颜色键。

    flags 参数

    flags参数可以被设置为pygame模块的RLEACCEL变量,以在未启用硬件加速的情况下提供更好的性能,这会导致表面在其内容被修改时的效率下降,但被其他表面渲染时的效率上升。

    在下面的示例中,我们将透明颜色键设置为红色,之后被绘制的第一个红色矩形将是完全透明的,无论其自身是否拥有透明度,第二个黄色矩形将是半透明的,因为其自身拥有并且表面支持透明度。

    colorkey.py
    from pygame import Surface, SRCALPHA
    
    # 创建支持透明度的表面,并将其透明颜色键设置为红色 s = Surface((800, 600), SRCALPHA) s.set_colorkey(0xff0000) print(f'透明颜色键:{s.get_colorkey()}')
    # 在表面分别绘制红色和黄色的矩形 from pygame import draw draw.rect(s, '#ff000088', [0, 0, 50, 50]) draw.rect(s, '#ffff0099', [50, 0, 50, 50])
    # 创建游戏窗口并绘制 s from pygame import display w = display.set_mode((800, 600)) w.blit(s, (0, 0)) display.flip()
    import time time.sleep(3)
    透明颜色键:(255, 0, 0, 17)

    预先计算表面中的颜色的透明度

    Surface对象的premul_alpha方法,可预先将表面中像素的颜色的透明度与红色,绿色,蓝色进行计算,并将计算结果作为新的表面对象返回。预先计算透明度对于混合模式BLEND_PREMULTIPLIED非常有效,因为该模式认为颜色中的红色,绿色,蓝色已经与透明度进行了计算,这可以在一定程度上改进渲染的效率。

    premul_alpha()

    返回值

    premul_alpha方法的返回值是预先计算了透明度的新的Surface表面对象。

    premul_alpha 方法不会计算表面自身的透明度

    Surface对象的premul_alpha方法的返回值不会受表面自身透明度的影响,即使通过set_alpha方法为表面设置了有效的透明度,因为premul_alpha只考虑表面中像素的透明度。关于set_alpha方法,请参考获取和设置表面的透明度一段。

    在下面的示例中,我们预先计算表面对象s的透明度,得到了新的表面对象pa,将两个表面对象同时绘制在游戏窗口中,他们展现了不同的透明度,因为premul_alpha方法不考虑表面自身的透明度。

    premul_alpha.py
    from pygame import Surface, SRCALPHA, BLEND_PREMULTIPLIED
    
    # 创建一个表面并填充具有透明度的红色 s = Surface([100, 100], SRCALPHA) s.fill([255, 0, 0, 100]) # 将表面自身的透明度设置为 50 s.set_alpha(50)
    # 预先计算透明度 pa = s.premul_alpha()
    # 创建游戏窗口并绘制 s 和 pa(pa 使用 BLEND_PREMULTIPLIED) from pygame import display w = display.set_mode((800, 600)) w.blit(s, (0, 0)) w.blit(pa, (100, 100), special_flags=BLEND_PREMULTIPLIED) display.flip()
    import time time.sleep(3)

    获取和设置表面的调色板

    Surface对象的get_palette方法,可用于获取颜色深度为 8 的表面所使用的索引颜色(调色板)。

    get_palette()

    返回值

    get_palette方法的返回值是一个包含Color对象的 Python 元组,每一个Color对象对应一个索引颜色。

    Surface对象的get_palette_at方法,可根据给出的索引获取调色板中的某个颜色,仅适用于颜色深度为 8 的表面。

    get_palette_at(index)

    index 参数

    index参数是调色板中某个颜色的索引,取值范围是0255

    返回值

    get_palette_at方法的返回值是一个表示索引颜色的Color对象。

    Surface对象的set_palette方法,可用于设置颜色深度为 8 的表面所使用的索引颜色(调色板)。

    set_palette(palette)

    palette 参数

    palette参数是一个包含索引颜色信息的 Python 序列对象,颜色信息的书写格式与Color对象的构造器的rgbvalue参数类似,但其不支持字符串和整数(0xRRGGBBAA),并且颜色的透明度必须为255(不透明)。

    这里需要说明,palette参数不必给出调色板中的全部 256 个索引颜色,比如,当只给出一个索引颜色时,则只有调色板的第一个索引颜色被修改,其余索引颜色不变。

    Surface对象的set_palette_at方法,可根据给出的索引设置调色板中的某个颜色,仅适用于颜色深度为 8 的表面。

    set_palette_at(index, color)

    index 参数

    index参数是调色板中某个颜色的索引,取值范围是0255

    color 参数

    color参数是一个包含索引颜色信息的对象,该对象的书写格式与Color对象的构造器的rgbvalue参数类似,但其不支持字符串和整数(0xRRGGBBAA),并且颜色中的透明度始终被视为255(不透明)。

    无法通过 get_palette,get_palette_at 方法所返回的 Color 对象修改调色板中的颜色

    Surface对象的get_paletteget_palette_at方法所返回的Color对象是调色板颜色的副本,因此修改他们不会影响调色板中的原有颜色。

    颜色

    关于Color构造器的rgbvalue参数,你可以查看Pygame 中的 Color 对象一段。

    在下面的示例中,我们将调色板的第一个颜色(黑色)修改为了红色,这将导致黑色背景的表面对象s被显示为红色。

    palette.py
    from pygame import Surface, Color
    
    # 创建颜色深度为 8 的表面 s = Surface((800, 600), depth=8) # 获取调色板 print(s.get_palette())
    # 设置调色板中的第一个颜色(黑色) s.set_palette([(255, 0, 0)])
    # 获取调色板中的第一个颜色 c = s.get_palette_at(0) print(c)
    # 设置调色板中的第二个颜色 s.set_palette_at(1, Color('#00FF00'))
    # 创建游戏窗口并绘制 s from pygame import display w = display.set_mode((800, 600)) w.blit(s, (0, 0)) display.flip()
    import time time.sleep(3)
    ((0, 0, 0, 255), (0, 0, 85, 255),)
    (255, 0, 0, 255)

    获取和设置表面中的某个像素的颜色

    Surface对象的get_atget_at_mapped方法,可根据给出的坐标,获取表面中某个像素的颜色。

    get_at(x_y)
    get_at_mapped(x_y)

    x_y 参数

    x_y参数是依次包含 X 坐标和 Y 坐标的 Python 整数序列对象。如果坐标所指示的位置超出了表面的范围,那么将引发异常IndexError

    返回值

    get_at方法的返回值是表示像素颜色的Color对象,如果表面对象不支持透明度,那么所返回的Color对象的透明度始终为255

    get_at_mapped方法的返回值是表示像素颜色的映射整数。

    Surface对象的set_at方法,可用于设置表面中某个像素的颜色。

    set_at(x_y, color)

    x_y 参数

    x_y参数是依次包含 X 坐标和 Y 坐标的 Python 整数序列对象。如果坐标所指示的位置超出了表面的有效范围,那么set_at方法不会产生任何影响。

    color 参数

    color参数是一个包含颜色信息的对象,该对象的书写格式与Color对象的构造器的rgbvalue参数类似。如果表面对象使用了调色板,那么将在调色板中选择最接近于color参数的颜色。

    get_at,get_at_mapped,set_at 方法的性能问题

    在循环中使用Surface对象的get_atget_at_mappedset_at方法,可能导致游戏出现性能问题,以上方法可能会临时锁定表面对象。

    无法通过 get_at 方法所返回的 Color 对象修改像素的颜色

    Surface对象的get_at方法所返回的Color对象是像素的颜色的副本,因此对其进行修改不会影响原有像素的颜色。

    在下面的示例中,我们通过set_at方法在游戏窗口中绘制了一条白色的线段。

    pixel_color.py
    from pygame import Surface
    
    # 创建表面,并获取坐标为 0 0 的像素的颜色 s = Surface((800, 600)) print(f'坐标 0 0 处的颜色:{s.get_at((0, 0))}')
    # 绘制一条白色的线段 for i in range(100, 700): s.set_at([i, 300], 'white') print(f'坐标 100 300 处的颜色:{hex(s.get_at_mapped([100, 300]))}')
    # 创建游戏窗口并绘制 s from pygame import display w = display.set_mode((800, 600)) w.blit(s, (0, 0)) display.flip()
    import time time.sleep(3)
    坐标 0 0 处的颜色:(0, 0, 0, 255)
    坐标 100 300 处的颜色:0xffffff

    转换颜色与映射整数

    颜色的映射整数,即颜色在表面中对应的整数,同一个颜色在不同的表面中,其映射整数可能不同,不同颜色在同一个表面的映射整数可能相同(比如,使用了调色板的表面中的两个相近的颜色)。要获取表面中某个坐标的颜色的映射整数,请参考获取和设置表面中的某个像素的颜色一段。

    Surface对象的map_rgb方法,可获取指定颜色在表面中的映射整数。

    map_rgb(color)

    color 参数

    color参数是一个包含颜色信息的对象,该对象的书写格式与Color对象的构造器的rgbvalue参数类似,但其不支持字符串和整数(0xRRGGBBAA)。由于映射整数并不考虑透明度,因此颜色信息中的透明度将被忽略。

    返回值

    map_rgb方法的返回值是颜色的映射整数。

    Surface对象的unmap_rgb方法,可获取指定映射整数在表面中对应的颜色。

    unmap_rgb(mapped_int)

    mapped_int 参数

    mapped_int参数是颜色的映射整数。

    返回值

    unmap_rgb方法的返回值是一个Color对象,表示映射整数对应的颜色。

    此外,Surface对象的get_masksget_shiftsget_losses方法,可用于获取颜色与映射整数转换所需的掩码,移位,有效位的信息。在正常的游戏开发中,这三个函数很少被使用。

    get_masks()
    get_shifts()
    get_losses()

    返回值

    get_masksget_shiftsget_losses方法的返回值是一个形式类似于(r,g,b,a)的 Python 整数元组,其中rgbr分别表示红色,绿色,蓝色,透明度所对应的掩码,移位,有效位信息。

    mapped.py
    from pygame import Surface
    
    # 创建颜色深度为 8 的表面 s1 = Surface([400, 300], depth=8) # 两个不同颜色的映射整数相同 m1 = s1.map_rgb([255, 0, 0]) print(m1, s1.unmap_rgb(m1)) m2 = s1.map_rgb([250, 5, 5]) print(m2, s1.unmap_rgb(m2)) # 映射整数不考虑透明度 m3 = s1.map_rgb([255, 0, 0, 100]) print(m3, s1.unmap_rgb(m3))
    # 创建颜色深度为 32 的表面 s2 = Surface([400, 300], depth=32) # 相同的颜色在 s1 和 s2 中的映射整数不同 m3 = s2.map_rgb([255, 0, 0]) print(m3, s2.unmap_rgb(m3))
    96 (255, 0, 0, 255)
    96 (255, 0, 0, 255)
    96 (255, 0, 0, 255)
    16711680 (255, 0, 0, 255)

    获取表面的边界

    Surface对象的get_bounding_rect方法,可用于获取表面的边界,该边界是包含所有符合要求的像素的最小矩形,这些像素的颜色透明度大于或等于给出的最小透明度。

    get_bounding_rect(min_alpha=1)

    min_alpha 参数

    min_alpha参数是表示最小透明度的整数,其取值范围不限于0255

    返回值

    get_bounding_rect方法的返回值是表示表面边界的Rect对象。

    get_bounding_rect 方法可能不会返回预期的结果

    如果使用set_colorkey方法为表面设置了透明颜色键,那么Surface对象的get_bounding_rect方法所返回的结果可能不符合你的预期,游戏边界可能等同于整个表面。关于方法set_colorkey,请参考获取和设置表面的透明颜色键一段。

    至于表面自身的透明度,并不会影响get_bounding_rect方法的计算结果,因为表面自身的透明度并非像素颜色的透明度。关于表面透明度,请参考获取和设置表面的透明度一段。

    get_bounding_rect 方法的性能问题

    在循环中使用Surface对象的get_bounding_rect方法,可能导致游戏出现性能问题,该方法可能会临时锁定表面对象。

    在下面的示例中,虽然我们将表面自身的透明度设置为了0,但之后的表面边界依然被认定为不透明的矩形。

    bounding_rect.py
    from pygame import Surface, SRCALPHA
    
    # 创建支持透明度的表面 s = Surface((800, 600), SRCALPHA)
    # 在表面绘制不透明与透明度为 1 的矩形 from pygame import draw draw.rect(s, '#ff0000', [0, 0, 50, 50]) draw.rect(s, '#ff000001', [50, 0, 50, 50]) print(f'表面边界:{s.get_bounding_rect()}')
    # 将表面自身的透明度设置为 0 s.set_alpha(0) print(f'表面边界(透明度大于等于 2):{s.get_bounding_rect(2)}')
    表面边界:<rect(0, 0, 100, 50)>
    表面边界(透明度大于等于 2):<rect(0, 0, 50, 50)>

    获取 Surface 表面对象所需的存储空间

    Surface对象的get_bitsize方法,可用于获取表面的颜色深度,即需要多少个 bit 来存储一个像素(对应的颜色),该个数可能小于所需字节对应的 bit 个数。

    get_bitsize()

    返回值

    get_bitsize方法的返回值是一个整数,表示需要的 bit 个数。

    Surface对象的get_bytesize方法,可用于获取存储一个像素(中的颜色)所需的字节数。

    get_bytesize()

    返回值

    get_bytesize方法的返回值是一个整数,表示需要的字节数。

    Surface对象的get_pitch方法,可用于获取存储一行像素(中的颜色)所需的字节数。

    get_pitch()

    返回值

    get_pitch方法的返回值是一个整数,表示需要的字节数。

    在下面的示例中,表面s存储一个像素需要15个 bit(2个字节,其中一个 bit 没有被使用)。

    space.py
    from pygame import Surface
    
    # 创建颜色深度为 15 的表面 s = Surface((100, 100), depth=15) print(f'一个像素需要 {s.get_bitsize()} 个 bit,{s.get_bytesize()} 个字节') print(f'一行像素需要 {s.get_pitch()} 个字节')
    一个像素需要 15 个 bit,2 个字节

    获取表面的缓冲区

    Surface对象的get_buffer方法返回一个表示表面缓冲区的BufferProxy对象,通过该对象可以直接访问或操作表面中的数据。get_buffer方法将隐式的锁定表面对象,直至BufferProxy对象被垃圾回收。

    get_buffer()

    返回值

    get_buffer方法返回表示缓冲区的BufferProxy对象。

    Surface对象的_pixels_address变量是一个整数,表示表面缓冲区的地址。

    surface._pixels_address

    buffer.py
    from pygame import Surface
    
    s = Surface((100, 100)) # 获取表面的缓冲区对象 b = s.get_buffer() # 获取表面缓冲区的地址 print(f'缓冲区地址:{s._pixels_address}')
    缓冲区地址:

    获取表面的缓冲区视图

    Surface对象的get_view方法与get_buffer方法类似,返回一个表示表面缓冲区的BufferProxy对象,只不过该对象中的数据经过了筛选。

    get_view(kind='2')

    kind 参数

    kind参数是一个字符串,表示如何对缓冲区中的数据进行筛选,可以是以下有效取值,'0''1''2''3''r''g''b''a'

    返回值

    get_view方法返回一个BufferProxy对象,该对象包含经过筛选的缓冲区数据。

    复制表面

    Surface对象的copy方法返回一个新的表面对象,该对象对应的表面的大小,特性,像素格式,调色板,自身透明度(并非透明颜色键)等,与原有表面相同。

    copy()

    返回值

    copy方法返回复制的Surface表面对象。

    在下面的示例中,虽然表面对象s1设置了透明颜色键,但s2的颜色透明键依然为空值None

    copy.py
    from pygame import Surface, SRCALPHA
    
    # 创建一个表面,然后复制他 s1 = Surface([400, 300], SRCALPHA, 16) s1.set_colorkey('#ff0000') s1.set_alpha(100) s2 = s1.copy()
    # s2 的透明颜色键为 None,与 s1 不同 print(f'复制的表面:{s2.get_size()} {s2.get_flags()} {s2.get_bitsize()} {s2.get_colorkey()} {s2.get_alpha()}')
    复制的表面:(400, 300) 65536 16 None 100

    内容分类

    源码

    src/zh/surface·codebeatme/pygame·GitHub

    讲解视频

    如何在 Pygame 中获取表面大小及其矩形对象·YouTube如何在 Pygame 中获取表面大小及其矩形对象·Bilibili
    如何在 Pygame 中获取和设置表面的透明度·YouTube如何在 Pygame 中获取和设置表面的透明度·Bilibili
    如何在 Pygame 中使图像背景透明·YouTube如何在 Pygame 中使图像背景透明·Bilibili