[Pygame] setting alpha makes solid black

[Pygame] setting alpha makes solid black

Postby metulburr » Tue Apr 23, 2013 1:28 pm

I am trying to make a highlight feature upon mouse over image. I am not sure exactly about alphas. All images by default are by themselves, and already alpha set. This being one image in directory.
fire.png
fire.png (1.87 KiB) Viewed 2113 times


But when highlight is True, the alpha turns poure black. I was expecting alpha(50))


set alpha code:
Code: Select all
      if self.images.highlight:
         self.images.image[1].set_alpha(None)
      else:
         self.images.image[1].set_alpha(50)



full code:
Code: Select all
import pygame
import os
import time

class ImageClass:
   def __init__(self):
      self.image_dir = '/home/metulburr/Pictures/alchemy_images'
      self.album = []
      self.image = None
      self.image_ind = 0
      self.rect = None
      self.highlight = False
      self.get_images()
      self.rect = self.album[0][1].get_rect() #set initial first rect
      
   def get_images(self):
      for f in os.listdir(self.image_dir):
         if f.endswith('.png'):
            self.album.append(
                  (
                     os.path.splitext(f)[0].replace('_',' ').title(),
                     pygame.image.load(os.path.join(self.image_dir, f))
                  )
               )
   def get_highlight_bg(self):
      if self.highlight:
         return (255,255,255)
      
      
class Control:
   def __init__(self):
      pygame.init()
      self.screensize = (600,600)
      self.screen = pygame.display.set_mode(self.screensize)
      self.clock = pygame.time.Clock()
      self.mouseX = 0
      self.mouseY = 0
      self.keys = None
      self.mouse_keys = (0,0,0)
      self.mouse_held = False
      self.is_dragging = False
      
      
      self.images = ImageClass()
      
   def text(self, displaytext, color=(0,0,0), size=15, ul=False, bold=False,
         ital=False, font='timesnewroman'):
      font = pygame.font.SysFont(font, size)
      font.set_underline(ul)
      font.set_bold(bold)
      font.set_italic(ital)
      label = font.render(displaytext, 1, color)
      return label

   def update(self):
      if self.images.image_ind > len(self.images.album)-1: #if at end of list
         self.images.image_ind = 0
      self.images.image = self.images.album[self.images.image_ind]
      
      if self.images.highlight:
         self.images.image[1].set_alpha(None)
      else:
         self.images.image[1].set_alpha(50)

      self.screen.fill((150,150,150))
      
      #check for mouse over image, with no click
      if self.images.rect.collidepoint((self.mouseX, self.mouseY)):
         self.images.highlight = True
      else:
         self.images.highlight = False
      
      #check for mouse over image and click
      if self.images.rect.collidepoint((self.mouseX, self.mouseY)) and self.mouse_held:
         self.is_dragging = True
         
      #mouse image with mouse upon dragging
      if self.is_dragging: #keep moving box if mouse is still holding but movees too fast
         self.images.rect[1] = self.mouseY - self.images.image[1].get_size()[1] // 2
         self.images.rect[0] = self.mouseX - self.images.image[1].get_size()[0] // 2
      
      self.screen.blit(self.images.image[1], (self.images.rect[0],self.images.rect[1]))
      self.screen.blit(
            self.text(self.images.image[0], color=(0,0,0)),
               (self.images.rect[0] + 20,self.images.rect[1] + 75)
         )
         
      self.test()
      
   def test(self):
      print(self.images.image[1].get_colorkey())
      
   def main(self):
      run = True
      while run:
         for event in pygame.event.get():
            if event.type == pygame.QUIT:
               run = False
            if event.type == pygame.KEYDOWN:
               if event.key == pygame.K_SPACE:
                  self.images.image_ind += 1
            if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
               self.mouse_held = True
            if event.type == pygame.MOUSEBUTTONUP and event.button == 1:
               self.mouse_held = False
               self.is_dragging = False
                  
         self.keys = pygame.key.get_pressed()
         self.mouseX, self.mouseY = pygame.mouse.get_pos()
         self.mouse_keys = pygame.mouse.get_pressed()

         self.update()
         pygame.display.flip()
         self.clock.tick(60)
         

controller = Control()
controller.main()
New Users, Read This
OS Ubuntu 14.04, Arch Linux, Gentoo, Windows 7/8
https://github.com/metulburr
steam
User avatar
metulburr
 
Posts: 1509
Joined: Thu Feb 07, 2013 4:47 pm
Location: Elmira, NY

Re: [Pygame] setting alpha makes solid black

Postby Mekire » Tue Apr 23, 2013 1:44 pm

So, apparently you can only use that set_alpha if your image does not use per-pixel alpha.

From the docs:
This value is different than the per pixel Surface alpha. If the Surface format contains per pixel alphas, then this alpha value will be ignored. If the Surface contains per pixel alphas, setting the alpha value to None will disable the per pixel transparency.


You will need to use a color-keyed surface if you want to do it this way.

You will have to fill the background of your images with some solid color; then use that color as a color-key. When loading use convert() (not convert_alpha()). Then the set_alpha method will be able to allow transparency while dragging.

-Mek

Edit: You should never not convert a surface. Use either convert_alpha or convert when initially loading the images depending on what is required (and explicitly set a color_key if needed). This makes blitting images faster for one, but also, if you don't do either, some pygame functionality will automatically use the top left pixel color as your transparent color. This can be unpredictable sometimes.
User avatar
Mekire
 
Posts: 1020
Joined: Thu Feb 07, 2013 11:33 pm
Location: Amakusa, Japan

Re: [Pygame] setting alpha makes solid black

Postby metulburr » Tue Apr 23, 2013 1:57 pm

you mean manuelly filling the color? Thats 365 images. Damn.

EDIT:
well i didnt use anything because the pics were already set to alpha background full.
New Users, Read This
OS Ubuntu 14.04, Arch Linux, Gentoo, Windows 7/8
https://github.com/metulburr
steam
User avatar
metulburr
 
Posts: 1509
Joined: Thu Feb 07, 2013 4:47 pm
Location: Elmira, NY

Re: [Pygame] setting alpha makes solid black

Postby Mekire » Tue Apr 23, 2013 2:00 pm

Yeah don't do that. Just test the theory.

What you should actually do is create a new surface in pygame using convert.
Fill that surface and set its color key. Then blit your image onto that surface.
then set the alpha of the new surface. Should work.

-Mek

Edit: It is particularly important that you use convert_alpha on pictures that already have alpha. If you don't you may dramatically slow your program when blitting a large number of these non-converted surfaces.
User avatar
Mekire
 
Posts: 1020
Joined: Thu Feb 07, 2013 11:33 pm
Location: Amakusa, Japan

Re: [Pygame] setting alpha makes solid black

Postby metulburr » Tue Apr 23, 2013 2:05 pm

Then blit your image onto that surface

so each image is going to have its own mini surface? And that is the surface that is changing the alpha when highlighted? That actually never came to mind when thinking of how to do this
New Users, Read This
OS Ubuntu 14.04, Arch Linux, Gentoo, Windows 7/8
https://github.com/metulburr
steam
User avatar
metulburr
 
Posts: 1509
Joined: Thu Feb 07, 2013 4:47 pm
Location: Elmira, NY

Re: [Pygame] setting alpha makes solid black

Postby metulburr » Tue Apr 23, 2013 2:13 pm

so you mean like:
Code: Select all
   def get_images(self):
      for f in os.listdir(self.image_dir):
         if f.endswith('.png'):

            image_obj = pygame.image.load(os.path.join(self.image_dir, f))
            image_surface = pygame.Surface(image_obj.get_size()).convert()
            image_surface.fill((0,0,0,50))
            image_surface.set_colorkey((255,255,255))
            #image_obj.fill((0,0,0, 155))
            image_obj.set_alpha(50)
            
            self.album.append(
                  (
                     os.path.splitext(f)[0].replace('_',' ').title(),
                     image_obj,
                     image_surface
                  )
               )


and setting:
Code: Select all
      if self.images.highlight:
         self.images.image[3].set_alpha(50)
      else:
         self.images.image[3].set_alpha(255)


now just my problem is all of the images are already alpha set themselves, and not the colorkey i set in the code.

Is this correct? I think for me to test this i would have to remove the image's alpha and color them white, on aqll 365 images. Which to me looks like a lot of work in GIMP
New Users, Read This
OS Ubuntu 14.04, Arch Linux, Gentoo, Windows 7/8
https://github.com/metulburr
steam
User avatar
metulburr
 
Posts: 1509
Joined: Thu Feb 07, 2013 4:47 pm
Location: Elmira, NY

Re: [Pygame] setting alpha makes solid black

Postby Mekire » Tue Apr 23, 2013 2:14 pm

Completely untested:
Code: Select all
def __init__(self,location):
    self.original_image = pygame.image.load("fire.png").convert_alpha()
    self.image = self.original_image
    self.highlight_image = self.make_highlight()
    self.rect = self.image.get_rect(topleft=location)
    self.highlight = False

def make_highlight(self):
    temp = pygame.Surface(self.rect.size).convert()
    temp.set_colorkey((255,0,255))
    temp.fill((255,0,255))
    temp.blit(self.original_image,(0,0))
    temp.set_alpha(100)
    return temp

def update(self):
    self.image = self.highlight_image if self.highlight else self.original_image
    #other stuff

-Mek
User avatar
Mekire
 
Posts: 1020
Joined: Thu Feb 07, 2013 11:33 pm
Location: Amakusa, Japan

Re: [Pygame] setting alpha makes solid black

Postby metulburr » Tue Apr 23, 2013 2:23 pm

well ok thanks Mekire.

Im taking a break, sucks thought since your online now. I am at a point where i am so stressed from this that i am starting to think about cigarettes, so i am taking a break.

but i will nit pick thorughout your code posted at some point today. Thanks for taking the time to help me in understanding this
New Users, Read This
OS Ubuntu 14.04, Arch Linux, Gentoo, Windows 7/8
https://github.com/metulburr
steam
User avatar
metulburr
 
Posts: 1509
Joined: Thu Feb 07, 2013 4:47 pm
Location: Elmira, NY

Re: [Pygame] setting alpha makes solid black

Postby Mekire » Tue Apr 23, 2013 2:37 pm

Cool. Just relax. I'm just trying to get my mind off of all the mindless paper work I have had to do today.

Here is a proof of concept. It is an edit of the sample I wrote for IvyMike. It uses his images and file names which can be found in his thread. This enables the transparency while dragging just fine. There are some pink artifacts around the images but this is a result of previous semi-transparent pixels in the originals. At some point you may have to resort to image editing for a clean result:
Code: Select all
import pygame as pg
import os  #os is used for centering the screen with os.environ
import sys #sys is used for sys.exit
import itertools

ELE_LIST = ["fire","water","sulphur"]

TRANS_DICT = {("fire" ,"water")   : "sulphur",
              ("fire" ,"sulphur") : "water",
              ("water","sulphur") : "fire"}

class Dragable(object):
    """Our dragable object class."""
    def __init__(self,kind,location):
        self.kind = kind
        self.get_img()
        self.image = self.original_image
        self.rect = self.image.get_rect(center=location)
        self.highlight_image = self.make_highlight()
        self.mask = pg.mask.from_surface(self.image,50)
        self.selected = False
    def get_img(self):
        """Our draggable objects now have an attribute self.kind to keep track
        of what type of element they are. As a result element image file names
        must conform to the form self.kind+"-icon.png"."""
        self.original_image  = pg.image.load(self.kind+"-icon.png").convert_alpha()
        self.mask = pg.mask.from_surface(self.original_image)
    def make_highlight(self):
        temp = pg.Surface(self.rect.size).convert()
        temp.set_colorkey((255,0,255))
        temp.fill((255,0,255))
        temp.blit(self.original_image,(0,0))
        temp.set_alpha(155)
        return temp

    def events(self,ev):
        if ev.type == pg.MOUSEBUTTONDOWN:
            if self.rect.collidepoint(ev.pos):
                offset = ev.pos[0]-self.rect.x,ev.pos[1]-self.rect.y
                if self.mask.get_at(offset):
                    if ev.button == 1:
                        self.selected = True
        elif ev.type == pg.MOUSEBUTTONUP:
            if ev.button == 1:
                self.selected = False
    def update(self,Surf):
        self.image = self.highlight_image if self.selected else self.original_image
        if self.selected:
            self.rect.center = pg.mouse.get_pos()
        Surf.blit(self.image,self.rect)

class Control(object):
    def __init__(self):
        pg.init()
        os.environ['SDL_VIDEO_CENTERED'] = '1'  #Center screen.
        self.Screen = pg.display.set_mode((850,640))
        self.Clock = pg.time.Clock()
        self.bg = pg.image.load("interface.jpg").convert() #load background image
        #The following line creates our list with a list comprehension.
        self.elements = [Dragable(name,(800,50+100*i)) for i,name in enumerate(ELE_LIST*2)]
        self.done = False #Flag for breaking out of main loop and exiting.

    def event_loop(self):
        for ev in pg.event.get():
            if ev.type==pg.QUIT or (ev.type==pg.KEYDOWN and ev.key==pg.K_ESCAPE):
                self.done = True
            for Ele in self.elements:
                Ele.events(ev)

    def update(self):
        self.Screen.fill(0)
        self.Screen.blit(self.bg,(0,0))
        #Updating using list comprehensions.
        [Ele.update(self.Screen) for Ele in self.elements if not Ele.selected]
        #Makes sure that the current one we are dragging around appears on top.
        [Ele.update(self.Screen) for Ele in self.elements if Ele.selected]

    def alchemize(self):
        for Eles in itertools.permutations(self.elements,2):
            if not Eles[0].selected and not Eles[1].selected:
                offset = Eles[1].rect.x-Eles[0].rect.x,Eles[1].rect.y-Eles[0].rect.y
                if Eles[0].mask.overlap_area(Eles[1].mask,offset):
                    self.elements.remove(Eles[0])
                    key = Eles[0].kind,Eles[1].kind
                    Eles[1].kind = TRANS_DICT.get(key,TRANS_DICT.get(key[::-1],key[0]))
                    Eles[1].get_img()
                    Eles[1].highlight_image = Eles[1].make_highlight()
                    Eles[1].rect.center = pg.mouse.get_pos()
                    break

    def main(self):
        while not self.done:
            self.event_loop()
            self.update()
            self.alchemize()
            pg.display.update()
            self.Clock.tick(60)

if __name__ == "__main__":
    RunIt = Control()
    RunIt.main()
    pg.quit();sys.exit()

-Mek
Last edited by Mekire on Tue Apr 23, 2013 3:49 pm, edited 1 time in total.
User avatar
Mekire
 
Posts: 1020
Joined: Thu Feb 07, 2013 11:33 pm
Location: Amakusa, Japan

Re: [Pygame] setting alpha makes solid black

Postby Mekire » Tue Apr 23, 2013 3:16 pm

OK, so I have found another method you might be interested in. It is much simpler, but again requires clean surfaces.

You can blit convert_alpha() surfaces (and possibly others) using various blend modes. I have not used these in the past but it seems pretty straight forward.

All you have to do is blit with no blend mode when not selected and using a desired blend mode when selected.

Code: Select all
if not self.selected:
    Surf.blit(self.image,self.rect)
else:
    Surf.blit(self.image,self.rect,None,pygame.BLEND_ADD)

A list of blending modes can be found here: http://www.pygame.org/docs/ref/surface.html#pygame.Surface.blit

-Mek
User avatar
Mekire
 
Posts: 1020
Joined: Thu Feb 07, 2013 11:33 pm
Location: Amakusa, Japan

Re: [Pygame] setting alpha makes solid black

Postby metulburr » Tue Apr 23, 2013 8:01 pm

i understand you previous example before BLENDs, but what i get confused about is the alpha channel. Like some images i get with the background already alpha, and some i get, white, some are purple. I thought the ideal way was to already ahve the image have the background alpha transparent? So its ideal to have it (255,0,255)? why that color?

And then the other part i get confused on is loaded images with convert() or conver_alpha() sometimes do not display with some images and do with some others. Should i manuelly edit the background of every image i plan to use in pygame to a specified color with no/or with alpha transparency in GIMP, before writing code?

Also another part i got confused on was i had in my mind initially the background as a highlight and the image stays the same, upon highlighting the image, kind of like the actual littlealchemy, but now that i see the image highlight, i kind of like that better than just the background.

I would like to learn and get this understood, so i dont really want to use BLEND_ADD as an alternative. Sorry, sometimes i overthink on things, and need to step back and take a break to refresh my head.

Code: Select all
import pygame
import os
import time

class ImageClass:
   def __init__(self):
      self.image_dir = '/home/metulburr/Pictures/alchemy_images'

      self.album = []
      self.image = None
      self.image_ind = 0
      self.rect = None
      self.highlight = False
      self.get_images()
      self.rect = self.album[0][1].get_rect() #set initial first rect
      

      
   def get_images(self):
      for f in os.listdir(self.image_dir):
         if f.endswith('.png'):

            orig_image = pygame.image.load(os.path.join(self.image_dir, f)).convert_alpha()
            rect = orig_image.get_rect()
            highlight_image = self.make_highlight(rect, orig_image)
            
            
            self.album.append(
                  (
                     os.path.splitext(f)[0].replace('_',' ').title(),
                     orig_image,
                     highlight_image,
                     rect
                     
                  )
               )
   def make_highlight(self, rect, img):
      temp = pygame.Surface(rect.size).convert()
      temp.set_colorkey((255,255,255))
      temp.fill((255,255,255))
      temp.blit(img,(0,0))
      temp.set_alpha(100)
      return temp
      
class Control:
   def __init__(self):
      pygame.init()
      self.screensize = (600,600)
      self.screen = pygame.display.set_mode(self.screensize)
      self.clock = pygame.time.Clock()
      self.mouseX = 0
      self.mouseY = 0
      self.keys = None
      self.mouse_keys = (0,0,0)
      self.mouse_held = False
      self.is_dragging = False
      
      
      self.images = ImageClass()
      
   def text(self, displaytext, color=(0,0,0), size=15, ul=False, bold=False,
         ital=False, font='timesnewroman'):
      font = pygame.font.SysFont(font, size)
      font.set_underline(ul)
      font.set_bold(bold)
      font.set_italic(ital)
      label = font.render(displaytext, 1, color)
      return label

   def update(self):
      if self.images.image_ind > len(self.images.album)-1: #if at end of list
         self.images.image_ind = 0
      self.images.image = self.images.album[self.images.image_ind]
      
      #check for mouse over image, with no click
      if self.images.rect.collidepoint((self.mouseX, self.mouseY)):# and not self.mouse_held:
         self.images.highlight = True
      else:
         self.images.highlight = False
      
      #check for mouse over image and click
      if self.images.rect.collidepoint((self.mouseX, self.mouseY)) and self.mouse_held:
         self.is_dragging = True
         
      #mouse image with mouse upon dragging
      if self.is_dragging: #keep moving box if mouse is still holding but movees too fast
         self.images.rect[1] = self.mouseY - self.images.image[1].get_size()[1] // 2
         self.images.rect[0] = self.mouseX - self.images.image[1].get_size()[0] // 2
      
      if not self.images.highlight:
         self.screen.blit(self.images.image[1], (self.images.rect[0],self.images.rect[1]))
      else:
         self.screen.blit(self.images.image[2], (self.images.rect[0],self.images.rect[1]))
      self.screen.blit(
            self.text(self.images.image[0], color=(0,0,0)),
               (self.images.rect[0] + 20,self.images.rect[1] + 75)
         )
         
      self.test()
      
   def test(self):
      print(self.images.image[1].get_colorkey())
      #self.screen.blit(self.images.highlighter, (0,0))
      
   def main(self):
      run = True
      while run:
         for event in pygame.event.get():
            if event.type == pygame.QUIT:
               run = False
            if event.type == pygame.KEYDOWN:
               if event.key == pygame.K_SPACE:
                  self.images.image_ind += 1
            if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
               self.mouse_held = True
            if event.type == pygame.MOUSEBUTTONUP and event.button == 1:
               self.mouse_held = False
               self.is_dragging = False
                  
         self.keys = pygame.key.get_pressed()
         self.mouseX, self.mouseY = pygame.mouse.get_pos()
         self.mouse_keys = pygame.mouse.get_pressed()

         self.screen.fill((150,150,150))
         self.update()
         pygame.display.flip()
         self.clock.tick(60)
         

controller = Control()
controller.main()


This works, but i changed the color to white, as the purple was showing through the images and white seemed more multi color friendly looking.
New Users, Read This
OS Ubuntu 14.04, Arch Linux, Gentoo, Windows 7/8
https://github.com/metulburr
steam
User avatar
metulburr
 
Posts: 1509
Joined: Thu Feb 07, 2013 4:47 pm
Location: Elmira, NY

Re: [Pygame] setting alpha makes solid black

Postby Mekire » Wed Apr 24, 2013 2:49 pm

The color you use for your color key is not mandated. You just need it to be some rare color that you won't miss. If you use white then you can't have any pure white in the images you use (it will show as transparent). Not being able to use white is a little more inhibiting than not being able to use magenta. Other than that logic, the choice is completely arbitrary.

Also the BLEND_ADD mode doesn't actually seem to be too good a solution in this case (your image disappears if you drag it over white). It is just good to be aware of all your options. The method that will obviously achieve the best results is individually editing each image and saving a "highlight version," but yes, it is a bit tedious.

-Mek
User avatar
Mekire
 
Posts: 1020
Joined: Thu Feb 07, 2013 11:33 pm
Location: Amakusa, Japan

Re: [Pygame] setting alpha makes solid black

Postby metulburr » Wed Apr 24, 2013 3:47 pm

The color you use for your color key is not mandated. You just need it to be some rare color that you won't miss. If you use white then you can't have any pure white in the images you use (it will show as transparent). Not being able to use white is a little more inhibiting than not being able to use magenta. Other than that logic, the choice is completely arbitrary.


So there is a chance of having multiple different background colors to use for different images in a game, if the images' bg were to contain your colorkey color. OK that is more simple than what i was thinking. I was thinking pygame had a method of selecting what part of the image you wanted to select the colorley to be affected at.
New Users, Read This
OS Ubuntu 14.04, Arch Linux, Gentoo, Windows 7/8
https://github.com/metulburr
steam
User avatar
metulburr
 
Posts: 1509
Joined: Thu Feb 07, 2013 4:47 pm
Location: Elmira, NY


Return to Game Development

Who is online

Users browsing this forum: No registered users and 1 guest