URLhttps://learnscript.net/zh-hant/pygame/surface/
    複製連結移至說明  範例

    如何使用 Surface 表面物件?以及表面(影像)的透明度,透明色彩鍵,色彩,大小等問題

    閱讀 27:56·字數 8384·更新 
    Youtube 頻道
    訂閱 375

    本節內容不涉及矩形的碰撞偵測和子表面。

    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-hant/surface·codebeatme/pygame·GitHub

    講解影片

    Pygame 取得 Surface 表面的大小及其 Rect 矩形物件·YouTube
    Pygame 表面(影像)透明度控製,Surface 物件簡介·YouTube
    Pygame 影像背景的透明處理·YouTube