I took a quick look and fixed a few other problems along the way. Essentially my changes do this:
- Draw the bounding box on a temporary image, set its alpha transparency, and then blit this over top of the main image.
- Avoid extraneous drawing cycles (when the mouse isn’t moving, no sense in drawing the same image again).
- Ensure that width and height are always positive. If the rect is drawn by dragging the mouse left or up, your code would end up with a negative width and/or height, raising an exception when trying to write the final image.
Here is a screenshot of running the fixed code:
I split the code into two parts to avoid the scrollbars:
import pygame, sys
from PIL import Image
pygame.init()
def displayImage(screen, px, topleft, prior):
# ensure that the rect always has positive width, height
x, y = topleft
width = pygame.mouse.get_pos()[0] - topleft[0]
height = pygame.mouse.get_pos()[1] - topleft[1]
if width < 0:
x += width
width = abs(width)
if height < 0:
y += height
height = abs(height)
# eliminate redundant drawing cycles (when mouse isn't moving)
current = x, y, width, height
if not (width and height):
return current
if current == prior:
return current
# draw transparent box and blit it onto canvas
screen.blit(px, px.get_rect())
im = pygame.Surface((width, height))
im.fill((128, 128, 128))
pygame.draw.rect(im, (32, 32, 32), im.get_rect(), 1)
im.set_alpha(128)
screen.blit(im, (x, y))
pygame.display.flip()
# return current box extents
return (x, y, width, height)
And part 2 (concatenate to the above):
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 = bottomright = prior = None
n=0
while n!=1:
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONUP:
if not topleft:
topleft = event.pos
else:
bottomright = event.pos
n=1
if topleft:
prior = displayImage(screen, px, topleft, prior)
return ( topleft + bottomright )
if __name__ == "__main__":
input_loc="stack.png"
output_loc="out.png"
screen, px = setup(input_loc)
left, upper, right, lower = mainLoop(screen, px)
# ensure output rect always has positive width, height
if right < left:
left, right = right, left
if lower < upper:
lower, upper = upper, lower
im = Image.open(input_loc)
im = im.crop(( left, upper, right, lower))
pygame.display.quit()
im.save(output_loc)