When using python and pygame: after loading the screen with the background image and blitting new objects (Text, circles, rectangles, etc.), is there a way to save the modified screen so as to be recalled later in the program? Specifically, I am setting the background and blitting new objects and would like to save the screen image with all of the blits in intact so it can be used later in the program as a new background upon which sprites can be manipulated. Any suggestions welcomed!
Blitting works both ways, meaning you can blit something onto the display screen, but you can also blit the screen onto another surface. So simply make a new surface the same size of your display surface and blit the screen onto that surface for later use.
found a solution and it works better than I expected:
after blitted my raw background onto my surface and then adding numerous circles, rectangles and text to make an image with multiple dial, gauges and labels I ran the following:
pygame.display.update()
window = pygame.display.set_mode((800,480),0,32)
pygame.image.save(TFT,"screen_update.jpg")
the new image is saved to disk(XDcard on my RPi2) as "screen_update.jpg"
then I simply change the name to "ANAL_update.jpg" and use that as the background on my next program run. I commented out all of the code used to create the rectangles, circles and labels and it works. I will add an selectable "update" routine to the program and move all of extra drawing and labelling to that routine to be used when I wish to change the layout of he background. I like the fact that the program creates a new updated file that just needs to be renamed for use and for copying the background to other machines.
note: This is working on my RaspberryPi 2B with HDMI output to a 42" HD tv for development, but it is intended to run on an RPi3B with he official RPi 7 inch TFT display. Thanks to all of you that responded and to the others who left pertinent code for previous questions similar to mine.
I was wondering if it is possible to save a canvas that had several textures painted on it as an image file.
I know I can save regular Image's (kivy.core.image) or Texture's (kivy.graphics.texture) as an image file with the save() function, so if I am able to convert the canvas to an Image or a Texture it should be easy, but so far I wasn't able to do this.
Widgets have an export_to_png method. Call this from the Widget whose canvas you have drawn on.
The problem is that your MyPainter widget has its default size of (100,100) and its default position (0,0). So it is actually behind your Save Button. So all your drawing is actually outside the MyPainter widget, and saving the widget to an image is blank.
The fix is to change the pos and size of MyPainter, and perhaps use collide_point() in your on_touch_down() and on_touch_move() methods to ensure that you are actually drawing on the MyPainter widget.
i want to load an image for 5 seconds and then delete it from the display surface without overwriting it.
I load my image with this function:
pygame.image.load('image.png')
is there a function that undo this in python?
No, once you change a Surface, it remains change.
An easy solution is to just create a copy of the target Surface before you change it (using .copy()) and, if the Surface in question is the root Surface, simply blit the copy back onto it.
Is it possible to make a rect transparent in pygame?
I need it because I'm using rects as particles for my game. :P
pygame.draw functions will not draw with alpha. The documentation says:
Most of the arguments accept a color argument that is an RGB triplet. These can also accept an RGBA quadruplet. The alpha value will be written directly into the Surface if it contains pixel alphas, but the draw function will not draw transparently.
What you can do is create a second surface and then blit it to the screen. Blitting will do alpha blending and color keys. Also, you can specify alpha at the surface level (faster and less memory) or at the pixel level (slower but more precise). You can do either:
s = pygame.Surface((1000,750)) # the size of your rect
s.set_alpha(128) # alpha level
s.fill((255,255,255)) # this fills the entire surface
windowSurface.blit(s, (0,0)) # (0,0) are the top-left coordinates
or,
s = pygame.Surface((1000,750), pygame.SRCALPHA) # per-pixel alpha
s.fill((255,255,255,128)) # notice the alpha value in the color
windowSurface.blit(s, (0,0))
Keep in mind in the first case, that anything else you draw to s will get blitted with the alpha value you specify. So if you're using this to draw overlay controls for example, you might be better off using the second alternative.
Also, consider using pygame.HWSURFACE to create the surface hardware-accelerated.
Check the Surface docs at the pygame site, especially the intro.
Draw a transparent rectangle in pygame
I have had this question as a pygame user before, and this is a method of solving your problem.
I've just started learning some pygame (quite new to programming overall), and I have some very basic questions about how it works.
I haven't found a place yet that explains when I need to blit or not to include a certain surface on the screen. For example, when drawing a circle:
circle = pygame.draw.circle(screen, (0, 0, 0), (100, 100), 15, 1)
I don't need to do screen.blit(circle), but when displaying text:
text = font.render("TEXT", 1, (10, 10, 10))
textpos = text.get_rect()
textpos.centerx = screen.get_rect().centerx
screen.blit(text, textpos)
If I don't blit, the text won't appear.
To be honest, I really don't know what blitting is supposed to do, apart from "pasting" the desired surface onto the screen. I hope I have been clear enough.
The short answer
I haven't found a place yet that explains when I need to blit or not to include a certain surface on the screen.
Each operation will behave differently, and you'll need to read the documentation for the function you're working with.
The long answer
What Is Blitting?
First, you need to realize what blitting is doing. Your screen is just a collection of pixels, and blitting is doing a complete copy of one set of pixels onto another. For example, you can have a surface with an image that you loaded from the hard drive, and can display it multiple times on the screen in different positions by blitting that surface on top of the screen surface multiple times.
So, you often have code like this...
my_image = load_my_image()
screen.blit(my_image, position)
screen.blit(my_image, another_position)
In two lines of code, we copied a ton of pixels from the source surface (my_image) onto the screen by "blitting".
How do the pygame.draw.* functions blit?
Technically, the pygame.draw.* methods could have been written to do something similar. So, instead of your example...
pygame.draw.circle(screen, COLOR, POS, RADIUS, WIDTH)
...they COULD have had you do this...
circle_surface = pygame.draw.circle(COLOR, RADIUS, WIDTH)
screen.blit(circle_surface, POS)
If this were the case, you would get the same result. Internally, though, the pygame.draw.circle() method directly manipulates the surface you pass to it rather than create a new surface. This might have been chosen as the way to do things because they could have it run faster or with less memory than creating a new surface.
So which do I do?
So, to your question of "when to blit" and "when not to", basically, you need to read the documentation to see what the function actually does.
Here is the pygame.draw.circle() docs:
pygame.draw.circle():
draw a circle around a point
circle(Surface, color, pos, radius, width=0) -> Rect
Draws a circular shape on the Surface. The pos argument is the center of the circle, and radius is the size. The width argument is the thickness to draw the outer edge. If width is zero then the circle will be filled.
Note that it says that "draws a shape on the surface", so it has already done the pixel changes for you. Also, it doesn't return a surface (it returns a Rect, but that just tells you where the pixel changes were done).
Now let's look at the pygame.font.Font.render() documentation:
draw text on a new Surface
render(text, antialias, color, background=None) -> Surface
This creates a new Surface with the specified text rendered on it. Pygame provides no way to directly draw text on an existing Surface: instead you must use Font.render() to create an image (Surface) of the text, then blit this image onto another Surface.
...
As you can see, it specifically says that the text is drawn on a NEW Surface, which is created and returned to you. This surface is NOT your screen's surface (it can't be, you didn't even tell the render() function what your screen's surface is). That's a pretty good indication that you will need to actually blit this surface to the screen.
Blit means 'BL'ock 'I'mage 'T'ranfser
When you are displaying things on the screen you will, in some way, use screen because that's where you are putting it.
When you do:
pygame.draw.circle(screen, (0, 0, 0), (100, 100), 15, 1)
you are still using screen but you are just not blitting because pygame is drawing it for you.
And when you use text, pygame renders it into an image then you have to blit it.
So basically you blit images, but you can also have pygame draw them for you. But remember when you blit an image, say over a background, you need to loop it back and fourth; so that it blits the background, then the image, then the background etc...
You dont need to know much more than that, but you can read all about it here Pygame Blit
I hope this helped. Good Luck!
Imagine that you are a painter:
You have a canvas, and a brush.
Let's say that your main screen surface will be your canvas, and all the other surfaces, are "in your head" - you know how to draw them already.
When you call blit, you paint on top of the surface, covering any pixels that were overlapped. That is why you need to repaint the whole screen black so that you won't have any smudges on the painting while moving an object.
As Mark already said, you can draw a circle with a function, or first blit it to a new surface, and blit that on the screen surface.
If you have a more complicated surface - curves, text etc. you wouldn't need to have a surface for that, so you don't have to do any expensive calculations, just drawing. The setback is that your program takes up more memory, so you have to choose between those 2.