PyGame:如何将透明度应用于带有alpha通道的图像?

9
我希望能够显示具有指定透明度的带有alpha通道的图像,但是无法弄清楚如何实现。
为了说明我在这方面的困难,以下内容是从此SO答案中略微修改的代码片段,但是如果您运行它,您会发现“image”失去了其本来的alpha通道,而“image2”的alpha通道永远不会改变!糟糕。
#!/usr/bin/env python

import pygame, sys

pygame.init()

window = pygame.display.set_mode((200, 200))
background = pygame.Surface((window.get_size()))
background.fill((255, 255, 255))
image = image2 = pygame.image.load('alpha.png')

image = image.convert()
rect = image.get_rect()

image2 = image2.convert_alpha()
rect2 = image2.get_rect()

rect2.left = rect.width + 1

i = 0
while True:
  for event in pygame.event.get():
    if event.type == 12:
      pygame.quit()
      sys.exit()

  image.set_alpha(i)
  image2.set_alpha(i)

  window.fill((255, 255, 255))
  window.blit(background, background.get_rect())
  window.blit(image, rect)
  window.blit(image2, rect2)

  if i == 255:
    i = 0
  else:
    i += 1

  pygame.display.update()
  pygame.time.Clock().tick(60)

所以...怎么做?

1
我不确定,但是 image = image2 = pygame.image.load('alpha.png') 可能会引用相同的实例,从而擦除图像 2 的透明度。 - ninMonkey
你是在寻找每个像素的透明度,还是每个表面只有一个透明度值? - ninMonkey
如果我单独声明image和image2,我会得到相同的结果。说实话,我并不在乎如何做到这一点,只要它是高效的,并且我能够达到期望的结果:在保留原始alpha值的情况下改变图像或表面的透明度。 - Synthead
4个回答

15

制作所需展示图片的副本(以免更改原图),并使用以下代码:

self.image = self.original_image.copy()
# this works on images with per pixel alpha too
alpha = 128
self.image.fill((255, 255, 255, alpha), None, pygame.BLEND_RGBA_MULT)

抱歉,无法提供完整的示例。


1
我发现只有在将8位调色板图像通过convert_alpha之后才能正常工作。这没关系,只需事先转换图像即可。 :D - Augusta

8

就我所知,根据图片本身不同,结果可能会有所不同。在我的情况下,我发现使用Gimp更改图像可以使代码保持简单:

image = pygame.image.load('path/to/my.png').convert()
image.set_alpha(128)
surface.blit(image, (0, 0))

使用该代码后,以下精灵图并未正常工作: http://www.spriters-resource.com/resources/sheets/47/50365.png 然而,在使用Gimp更改以下两个内容后,它确实可以正常工作:
  1. 图像 -> 模式 -> 转换为颜色配置文件... 并使用默认值
  2. 图像 -> 模式 -> 索引... 并使用默认值
保存更改后,我在Ubuntu中可以使用它。我无法发布结果的图片,因为我是新用户...

在 Gimp 2.1 中,我没有找到第一个选项(图像 -> 模式 -> 转换为颜色配置文件),但只做第二步对我有效。 - RonquilloAeon

6
如果您只是想在pygame中加载一张带有alpha通道的图片,以下是操作步骤:
self.image = pygame.image.load("image file path").convert_alpha()

当您将此图像绘制在屏幕上时,它应该包括透明度。

不是答案。他已经知道如何做到这一点,但想知道在使用具有像素alpha值的图像时如何更改图像宽度alpha。 - Junuxx
2
我知道这是一个旧的帖子,但如果使用这种方法时它不包括透明度怎么办? - DonutSteve

2
您的代码有些复杂 :-) 但是,“非逐像素”或“全局alpha”对于Pygame来说很难做到正确。

所有文档都在http://www.pygame.org/docs/ref/surface.htm中有记录 - 但确实,缺乏详细的文字或示例。

如果您正在传输(源)的表面具有像素本身的alpha像素值(即32位深度),那么由表面的set_alpha方法设置的“全局alpha”值将被忽略。

为了使用此“全局”alpha,您的源表面不能具有每像素alpha。如果您的原始图像(在您的情况下是“alpha.png”文件)本身不使用透明度,那么很容易实现:

import pygame
pygame.init()
window = pygame.display.set_mode((200, 200))
image = pygame.image.load('alpha.png').convert(24)
image.set_alpha(128)
window.fill((255,255,255))
window.blit(image, (0,0))
pygame.display.flip()

然而,如果你的 "alpha.png" 图像本身使用了透明度,并且你想要保留它,那么就会变得更加棘手!
你需要:创建另一个与图像大小相同、深度为 24 的表面; 填充该表面,使用一个在图像中未使用的颜色(比如“色度键”)——通常在视频效果中,它们使用纯绿色或纯白色,但你可以选择任何 RGB 值。如果你的图像是照片而不是像素艺术,则无法知道哪个值不会被使用。只需随便选一个,希望没有太多“失败的像素”。 因此,用此关键颜色填充您的表面,并将其设置为表面的关键颜色:当混合时,该颜色将完全透明。 接下来,只需将原始图像混合到这个中间表面上,设置其全局 alpha(set_alpha),并将其混合到目标表面上。
在代码中,大致翻译为:
import pygame
pygame.init()
window = pygame.display.set_mode((200, 200))
image = pygame.image.load('alpha.png')
surface = pygame.Surface(image.get_size(), depth=24)
key = (0,255,0)
surface.fill(surface.get_rect(), key)
surface.set_colorkey(key)
surface.blit(image, (0,0))
surface.set_alpha(128) 
window.fill((255,255,255))
window.blit(surface, (0,0))
pygame.display.flip()

实际上,粉红色/紫色是用作键的颜色。 - Bartlomiej Lewandowski
1
由于上述的 alpha 技术是跟随颜色的,那么这是否意味着我不能像原始 PNG 图片一样拥有不同的 alpha 值?这将导致反锯齿边缘和文本具有污染的边缘,你知道吗? - Synthead
是的,就是这个意思。好处在于,由于您无论如何都会淡化对象,因此别名伪影不太可能被察觉到。 - jsbueno
如果目标表面(屏幕)上的颜色与colorkey接近,则可以进一步减轻别名现象。 - jsbueno
2
好消息:在 Pygame 2.0 中,引用文档的话说,“每个表面的 alpha 可以与每个像素的 alpha 结合使用。” :-) - MestreLion
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接