How to dynamically draw a recangle on the screen without glitching - python - python

https://media.giphy.com/media/3og0IDneIpXgdMDOzm/source.gif
I am working on a code that draws a transparent rectangle on screen and saves the section as an image, yet excessive rectangles are being left behind.
import wx
import win32gui
app = wx.App(False)
s = wx.ScreenDC()
s.Pen = wx.Pen("#FF0000")
int_x = win32gui.GetCursorPos()[0]
int_y = win32gui.GetCursorPos()[1]
while 1:
s.DrawRectangle(int_x,int_y,win32gui.GetCursorPos()[0]-int_x,win32gui.GetCursorPos()[1]-int_y)

I think you would need to do some kind of clear or refresh after the draw
s.Clear()
s.Refresh()
I haven't used this so I'm not sure if it will just work in your while loop but I'd imagine it won't and you would need something to handle the start (mousedown) and end (mouseup) of the drawing and then on mouseup do the clear and refresh that i mention.

Related

Preventing Image from being cleared [PYGAME- Python]

It's extremely painful to redraw each image everytime the screen is cleared.
import pygame
from pygame.locals import *
T = pygame.display.set_mode((500,500))
M = pygame.image.load("test.jpg")
X = 0
Y = 0
while True:
X += 1
Y += 1
# Other sprites are here which are also redrawn every time loop runs.
# Other code is here too, this is just a little part of it to help explain my problem
T.fill((0,0,0))
T.blit(M,(X,Y))
pygame.display.flip()
In the above code, I am loading the background image in M Variable, everytime I clear the screen to update the position of my sprites, I also have to redraw the background image which is causing severe FPS drops.
Anyway I can prevent the Background image from being cleared whenever I am using T.fill((0,0,0)) ?
First, try to convert the background image. Images should usually be converted with convert or convert_alpha to improve the performance.
M = pygame.image.load("test.jpg").convert()
Second, if the background image has the size of the screen you can omit the line T.fill((0,0,0)), since the background fills the screen anyway.
Third, if the background isn't scrolling and you only need to update some portions of the screen every frame, you can try to use pygame.display.update() instead of pygame.display.flip(). Pass a single rect or a list of rects to pygame.display.update to tell it which parts of the screen should be updated.
I'm not sure if these measures will improve the performance drastically. Pygame is rather slow because it still relies on software rendering.
Sidenote, use descriptive variable names instead of T, M, etc..

Turtle graphics window's canvas color *not* showing up in Postscript (.ps) file [duplicate]

I am new to Python and have been working with the turtle module as a way of learning the language.
Thanks to stackoverflow, I researched and learned how to copy the image into an encapsulated postscript file and it works great. There is one problem, however. The turtle module allows background color which shows on the screen but does not show in the .eps file. All other colors, i.e. pen color and turtle color, make it through but not the background color.
As a matter of interest, I do not believe the import of Tkinter is necessary since I do not believe I am using any of the Tkinter module here. I included it as a part of trying to diagnose the problem. I had also used bgcolor=Orange rather than the s.bgcolor="orange".
No Joy.
I am including a simple code example:
# Python 2.7.3 on a Mac
import turtle
from Tkinter import *
s=turtle.Screen()
s.bgcolor("orange")
bob = turtle.Turtle()
bob.circle(250)
ts=bob.getscreen()
ts.getcanvas().postscript(file = "turtle.eps")
I tried to post the images of the screen and the .eps file but stackoverflow will not allow me to do so as a new user. Some sort of spam prevention. Simple enough to visualize though, screen has background color of orange and the eps file is white.
I would appreciate any ideas.
Postscript was designed for making marks on some medium like paper or film, not raster graphics. As such it doesn't have a background color per se that can be set to given color because that would normally be the color of the paper or unexposed film being used.
In order to simulate this you need to draw a rectangle the size of the canvas and fill it with the color you want as the background. I didn't see anything in the turtle module to query the canvas object returned by getcanvas() and the only alternative I can think of is to read the turtle.cfg file if there is one, or just hardcode the default 300x400 size. You might be able to look at the source and figure out where the dimensions of the current canvas are stored and access them directly.
Update:
I was just playing around in the Python console with the turtle module and discovered that what the canvas getcanvas() returns has a private attribute called _canvas which is a <Tkinter.Canvas instance>. This object has winfo_width() and winfo_height() methods which seem to contain the dimensions of the current turtle graphics window. So I would try drawing a filled rectangle of that size and see if that gives you what you want.
Update 2:
Here's code showing how to do what I suggested. Note: The background must be drawn before any other graphics are because otherwise the solid filled background rectangle created will cover up everything else on the screen.
Also, the added draw_background() function makes an effort to save and later restore the graphics state to what it was. This may not be necessary depending on your exact usage case.
import turtle
def draw_background(a_turtle):
""" Draw a background rectangle. """
ts = a_turtle.getscreen()
canvas = ts.getcanvas()
height = ts.getcanvas()._canvas.winfo_height()
width = ts.getcanvas()._canvas.winfo_width()
turtleheading = a_turtle.heading()
turtlespeed = a_turtle.speed()
penposn = a_turtle.position()
penstate = a_turtle.pen()
a_turtle.penup()
a_turtle.speed(0) # fastest
a_turtle.goto(-width/2-2, -height/2+3)
a_turtle.fillcolor(turtle.Screen().bgcolor())
a_turtle.begin_fill()
a_turtle.setheading(0)
a_turtle.forward(width)
a_turtle.setheading(90)
a_turtle.forward(height)
a_turtle.setheading(180)
a_turtle.forward(width)
a_turtle.setheading(270)
a_turtle.forward(height)
a_turtle.end_fill()
a_turtle.penup()
a_turtle.setposition(*penposn)
a_turtle.pen(penstate)
a_turtle.setheading(turtleheading)
a_turtle.speed(turtlespeed)
s = turtle.Screen()
s.bgcolor("orange")
bob = turtle.Turtle()
draw_background(bob)
ts = bob.getscreen()
canvas = ts.getcanvas()
bob.circle(250)
canvas.postscript(file="turtle.eps")
s.exitonclick() # optional
And here's the actual output produced (rendered onscreen via Photoshop):
I haven't found a way to get the canvas background colour on the generated (Encapsulated) PostScript file (I suspect it isn't possible). You can however fill your circle with a colour, and then use Canvas.postscript(colormode='color') as suggested by #mgilson:
import turtle
bob = turtle.Turtle()
bob.fillcolor('orange')
bob.begin_fill()
bob.circle(250)
bob.begin_fill()
ts = bob.getscreen()
ts.getcanvas().postscript(file='turtle.eps', colormode='color')
Improving #martineau's code after a decade
import turtle as t
Screen=t.Screen()
Canvas=Screen.getcanvas()
Width, Height = Canvas.winfo_width(), Canvas.winfo_height()
HalfWidth, HalfHeight = Width//2, Height//2
Background = t.Turtle()
Background.ht()
Background.speed(0)
def BackgroundColour(Colour:str="white"):
Background.clear() # Prevents accumulation of layers
Background.penup()
Background.goto(-HalfWidth,-HalfHeight)
Background.color(Colour)
Background.begin_fill()
Background.goto(HalfWidth,-HalfHeight)
Background.goto(HalfWidth,HalfHeight)
Background.goto(-HalfWidth,HalfHeight)
Background.goto(-HalfWidth,-HalfHeight)
Background.end_fill()
Background.penup()
Background.home()
BackgroundColour("orange")
Bob=t.Turtle()
Bob.circle(250)
Canvas.postscript(file="turtle.eps")
This depends on what a person is trying to accomplish but generally, having the option to select which turtle to use to draw your background to me is unnecessary and can overcomplicate things so what one can do instead is have one specific turtle (which I named Background) to just update the background when desired.
Plus, rather than directing the turtle object via magnitude and direction with setheading() and forward(), its cleaner (and maybe faster) to simply give the direct coordinates of where the turtle should go.
Also for any newcomers: Keeping all of the constants like Canvas, Width, and Height outside the BackgroundColour() function speeds up your code since your computer doesn't have to recalculate or refetch any values every time the function is called.

What is the correct sequence for bliting surfaces to the screen in pygame?

I am creating a simple mp3 player and my first task was to create a simple button that a user could press. I created a class called Button which handled this behavior and detects if a user has clicked it and then changes color. I am now trying to have a default text that the button displays and another string (pres_string) which will be displayed if the button is being pressed.
The only problem is my background surface seems to be in the wrong place and is drawing over any changes I have made.
Here is my code:
http://pastebin.com/Nh3yy01X
As you can see I've commented out the lines I described and tried it with basic variables in the main function just to test what was going wrong.
Thanks for any help.
(Feel free to change the title of the question, I wasn't sure what most accuratelydescribed my problem)
Clear the surface every loop
def draw(self):
# clear screen."
self.screen.fill( self.color_bg )
# first draw background
# Then buttons
# then any extra top level text
# update
pygame.display.flip()
tip: For colors, you can call pygame.Color() with human-names like red ( gray20 and gray80 have a nice contrast, to use for bg and text. )
from pygame import Color
text = Color('gray20')
Your button, psuedocode. Fix: moved color as an instance member.
class Button(object):
def __init__(self, text, rect=None):
self.color_bg = Color("gray20")
self.color_text = color("gray80")
if rect is None: rect = Rect(0,0,1,1)
self.rect = rect
self._render()
def _render(self):
# draw button and .render() font, cache to surface for later.
self.surface_cached = self.surface.copy()
# render text
#if size changes, save rect.size of cached surface , mantaining location
self.rect.size = cache.get_rect.size
def draw(self):
# draw cached surface
screen.blit( self.surface_cached, self.rect)
For testClick use Rect.collidepoint http://www.pygame.org/docs/ref/rect.html#Rect.collidepoint
2D bitmap-based computer graphics are like drawing or painting - you put the new ink on top of whatever was there already. So your background must be the first thing you draw each time.

PyS60 application not going full screen

I am very new to PyS60. I was testing how to set an application to full screen mode but unfortunately, it doesn't work as expected. I tested the script on Nokia 6120 Classic. Here is what I did:
appuifw.app.screen = 'full'
What I get is a half screen of my application with a plain white colour below. What am I doing wrong? Thanks in advance.
Make sure you define own functions for screen redraw and screen rotate callbacks. When you rotate the device, you have to manually rescale everything to fit the new screen size. Otherwise you might get that "half of screen" effect.
canvas = img = None
def cb_redraw(aRect=(0,0,0,0)):
''' Overwrite default screen redraw event handler '''
if img:
canvas.blit(img)
def cb_resize(aSize=(0,0,0,0)):
''' Overwrite default screen resize event handler '''
global img
img = graphics.Image.new(canvas.size)
appuifw.app.screen = 'full'
canvas = appuifw.Canvas(
resize_callback = cb_resize,
redraw_callback = cb_redraw)
appuifw.app.body = canvas
If you haven't already, I would advise using the latest version of PyS60 from https://garage.maemo.org/frs/?group_id=854 and trying again.
Do the other two screen modes work as they are supposed to?

Digital Image cropping in Python

Got this question from a professor, a physicist.
I am a beginner in Python programming. I am not a computer professional I am a physicist. I was trying to write a code in python for my own research which involves a little image processing.
All I need to do is to display an image and then select a region of interest using my mouse and finally crop out the selected region. I can do this in Matlab using the ginput() function.
I tried using PIL. But I find that after I issue the command Image.show(), the image is displayed but then the program halts there unless I exit from the image window. Is there any way to implement what I was planning. Do I need to download any other module? Please advise.
While I agree with David that you should probably just use GIMP or some other image manipulation program, here is a script (as I took it to be an exercise to the reader) using pygame that does what you want. You will need to install pygame as well as the PIL, usage would be:
scriptname.py <input_path> <output_path>
Actual script:
import pygame, sys
from PIL import Image
pygame.init()
def displayImage( screen, px, topleft):
screen.blit(px, px.get_rect())
if topleft:
pygame.draw.rect( screen, (128,128,128), pygame.Rect(topleft[0], topleft[1], pygame.mouse.get_pos()[0] - topleft[0], pygame.mouse.get_pos()[1] - topleft[1]))
pygame.display.flip()
def setup(path):
px = pygame.image.load(path)
screen = pygame.display.set_mode( px.get_rect()[2:] )
screen.blit(px, px.get_rect())
pygame.display.flip()
return screen, px
def mainLoop(screen, px):
topleft = None
bottomright = None
runProgram = True
while runProgram:
for event in pygame.event.get():
if event.type == pygame.QUIT:
runProgram = False
elif event.type == pygame.MOUSEBUTTONUP:
if not topleft:
topleft = event.pos
else:
bottomright = event.pos
runProgram = False
displayImage(screen, px, topleft)
return ( topleft + bottomright )
if __name__ == "__main__":
screen, px = setup(sys.argv[1])
left, upper, right, lower = mainLoop(screen, px)
im = Image.open(sys.argv[1])
im = im.crop(( left, upper, right, lower))
im.save(sys.argv[2])
Hope this helps :)
For what it's worth (coming from another physicist), I would just do this in an image processing program like the GIMP. The main benefit of doing this task in Python (or any language) would be to save time by automating the process, but unless you - well, the professor - can somehow develop an algorithm to automatically figure out what part of the image to crop, there doesn't seem to be much time to be saved by automation.
If I remember correctly, GIMP is actually scriptable, possibly with Python, so it might be possible to write a time-saving GIMP script to do what your professor friend wants.
Image.show() just calls whatever simple picture viewer it can find on the current platform, one that may or may not have a crop-and-save facility.
If you are on a Windows box and you just need to make it work on your machine, set the ‘Open with...’ association to make it so running an image loads it into an editor of your choice. On OS X and *nix you'd want to hack the _showxv() method at the bottom of Image.py to change the command used to open the image.
If you do actually need to provide a portable solution, you'll need to use a UI framework to power your cropping application. The choices boil down to Tkinter (ImageTk.py gives you a wrapper for displaying PIL images in Tk), PyQT4 (ImageQt in PIL 1.1.6 gives you a wrapper for displaying images in QT4) or wxPython (a higher-level application authoring toolkit using wxWidgets). It'll be quite a bit of work to get the hang of a full UI kit, but you'll be able to completely customise how your application's interface will work.
Is there a script in python like a library to auto crop images :
Automatically crop image
What you are looking for is the module: matplotlib, it emulates Matlab. See the ginput() function. That allow you to find the bounding box, then you can use crop from PIL.
http://matplotlib.sourceforge.net/api/figure_api.html

Categories

Resources