How to improve watermark image in Python? - python

I am using python for watermark image source code from this
import Image
import ImageEnhance
import random
def _percent(var):
"""
Just a simple interface to the _val function with a more meaningful name.
"""
return _val(var, True)
def _int(var):
"""
Just a simple interface to the _val function with a more meaningful name.
"""
return _val(var)
def _val(var, is_percent=False):
"""
Tries to determine the appropriate value of a particular variable that is
passed in. If the value is supposed to be a percentage, a whole integer
will be sought after and then turned into a floating point number between
0 and 1. If the value is supposed to be an integer, the variable is cast
into an integer.
"""
try:
if is_percent:
var = float(int(var.strip('%')) / 100.0)
else:
var = int(var)
except ValueError:
raise ValueError('invalid watermark parameter: ' + var)
return var
def reduce_opacity(img, opacity):
"""
Returns an image with reduced opacity.
"""
assert opacity >= 0 and opacity <= 1
if img.mode != 'RGBA':
img = img.convert('RGBA')
else:
img = img.copy()
alpha = img.split()[3]
alpha = ImageEnhance.Brightness(alpha).enhance(opacity)
img.putalpha(alpha)
return img
def determine_scale(scale, img, mark):
"""
Scales an image using a specified ratio or 'F'. If `scale` is 'F', the
image is scaled to be as big as possible to fit in `img` without falling off
the edges. Returns the scaled `mark`.
"""
if scale:
try:
scale = float(scale)
except (ValueError, TypeError):
pass
if type(scale) in (str, unicode) and scale.lower() == 'f':
# scale, but preserve the aspect ratio
scale = min(
float(img.size[0]) / mark.size[0],
float(img.size[1]) / mark.size[1]
)
elif type(scale) not in (float, int):
raise ValueError(
'Invalid scale value "%s"! Valid values are 1) "F" for ratio-preserving scaling and 2) floating-point numbers and integers greater than 0.' % (
scale,))
# determine the new width and height
w = int(mark.size[0] * float(scale)) / 2
h = int(mark.size[1] * float(scale)) / 2
print w, h
# apply the new width and height, and return the new `mark`
return (w, h)
else:
print 'Mark Size', mark.size
return mark.size
def determine_rotation(rotation, mark):
"""
Determines the number of degrees to rotate the watermark image.
"""
if (isinstance(rotation, str) or isinstance(rotation, unicode)) \
and rotation.lower() == 'r':
rotation = random.randint(0, 359)
else:
rotation = _int(rotation)
return rotation
def determine_position(position, img, mark):
"""
Options:
TL: top-left
TR: top-right
BR: bottom-right
BL: bottom-left
C: centered
R: random
X%xY%: relative positioning on both the X and Y axes
X%xY: relative positioning on the X axis and absolute positioning on the
Y axis
XxY%: absolute positioning on the X axis and relative positioning on the
Y axis
XxY: absolute positioning on both the X and Y axes
"""
max_left = max(img.size[0] - mark.size[0], 0)
max_top = max(img.size[1] - mark.size[1], 0)
if not position:
position = 'r'
if isinstance(position, tuple):
left, top = position
elif isinstance(position, str) or isinstance(position, unicode):
position = position.lower()
# corner positioning
if position in ['tl', 'tr', 'br', 'bl']:
if 't' in position:
top = 0
elif 'b' in position:
top = max_top
if 'l' in position:
left = 0
elif 'r' in position:
left = max_left
# center positioning
elif position == 'c':
left = int(max_left / 2)
top = int(max_top / 2)
# random positioning
elif position == 'r':
left = random.randint(0, max_left)
top = random.randint(0, max_top)
# relative or absolute positioning
elif 'x' in position:
left, top = position.split('x')
if '%' in left:
left = max_left * _percent(left)
else:
left = _int(left)
if '%' in top:
top = max_top * _percent(top)
else:
top = _int(top)
print 'top left', left, top
return (left, top)
def watermark(img, mark, position=(0, 0), opacity=1, scale=1.0, tile=False,
greyscale=False, rotation=0, return_name=False, **kwargs):
"""
Adds a watermark to an image.
"""
if opacity < 1:
mark = reduce_opacity(mark, opacity)
if type(scale) != tuple:
scale = determine_scale(scale, img, mark)
print 'mark mode', mark.mode
mark = mark.resize(scale)
if greyscale and mark.mode != 'LA':
mark = mark.convert('LA')
rotation = determine_rotation(rotation, mark)
if rotation != 0:
# give some leeway for rotation overlapping
new_w = mark.size[0]
new_h = mark.size[1]
new_mark = Image.new('RGBA', (new_w, new_h), (0, 0, 0, 0))
# new_mark.putalpha()
# center the watermark in the newly resized image
new_l = (new_w - mark.size[0]) / 2
new_t = (new_h - mark.size[1]) / 2
new_mark.paste(mark, (new_l, new_t))
mark = new_mark.rotate(rotation, Image.BICUBIC, expand=True)
position = determine_position(position, img, mark)
print 'image mode', img.mode
print 'mark mode', mark.mode
if img.mode != 'RGBA':
img = img.convert('RGBA')
print 'image ---', img.mode
alpha = img.split()[3]
alpha = ImageEnhance.Brightness(alpha).enhance(opacity)
img.putalpha(alpha)
# make sure we have a tuple for a position now
assert isinstance(position, tuple), 'Invalid position "%s"!' % position
# create a transparent layer the size of the image and draw the
# watermark in that layer.
layer = Image.new('RGBA', img.size, (0, 0, 0, 0))
if tile:
first_y = position[1] % mark.size[1] - mark.size[1]
first_x = position[0] % mark.size[0] - mark.size[0]
for y in range(first_y, img.size[1], mark.size[1]):
for x in range(first_x, img.size[0], mark.size[0]):
layer.paste(mark, (x, y))
else:
layer.paste(mark, position)
# composite the watermark with the layer
return Image.composite(layer, img, layer)
def test():
im = Image.open('/home/chanhle/0450034_a (4th copy).jpg')
mark = Image.open('/home/chanhle/UMA LOGO.png')
# im.save('/home/chanhle/0120047_a.png')
watermark(im, mark,
position='C',
opacity=0.8,
scale='f',
rotation=45).save('/home/chanhle/test3.jpg', 'JPEG')
if __name__ == '__main__':
test()
This is Image I want to watermark
here is logo
and result when run code above
Result when I use online tools it's beautiful.
As you see in result logo watermark is not sharp enough it's not beautiful as I expected.
How to improve this quality?
Thank for support.

Change:
mark = mark.resize(scale)
to:
mark = mark.resize(scale, Image.ANTIALIAS)
change the opacity to 0.5. And try saving as a PNG image or add quality=100 to the save arguments if using JPEG.

Related

How to crop images / edges in a picture in OpenCV

Here's a picture of a maze solver, when the BFS function goes over the image it goes around the image
I know it's possible to just crop the image manually, but I want a function where the computer can automatically detect non black edges and delete them. How would I do this?
#Program that will read an image and pass through to folder using OpenCV, select starting and ending points, and solve the maze using a BFS function
#will be imported on to flask backend
'''
Requirements: pip3 install opencv-python (or contrib version depending on console)
'''
#libraries
import imghdr
import cv2
import numpy as np
import threading
import colorsys
#first we will read the image, and countour it to a gray image so reading the image will be easier
#set threshhold value
img = cv2.imread("Mazes/maze3.jpg", cv2.IMREAD_GRAYSCALE)
_, img = cv2.threshold(img, 120, 255, cv2.THRESH_BINARY)
img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
h, w = img.shape[:2]
#seperate function to display image
def solution():
global img
#show image
cv2.imshow("Maze Solver", img)
#run mouse pointer function for user to click points
cv2.setMouseCallback('Maze Solver', maze_points)
while True:
#after thread is ran display image
cv2.imshow("Maze Solver", img)
cv2.waitKey(1)
#this is a function that will map the cursor as a point so user can press twice to determine the start and end points
class Point(object):
def __init__(self, x = 0, y = 0):
self.x = x
self.y = y
def __add__(self, other):
return Point(self.x + other.x, self.y + other.y)
def __eq__(self, other):
return self.x == other.x and self.y == other.y
#variable that will store the # of times mouse is clicked
num_of_clicks = 0
#determine how big pointer will appear on screen
mouse_click_size = 2
#initialize start and end pointer so user clicks
start_point = Point()
end_point = Point()
#subtree that will point nodes in directions that they go in
subtree = [Point(0, -1), Point(0, 1), Point(1, 0), Point(-1, 0)]
#this function is to call the mouse to click two points on the image (just for opencv, if needed can input through console)
def maze_points(running, pX, pY, flags, param):
#globals
global img, start_point, end_point, num_of_clicks
#if the running is true then run
if running == cv2.EVENT_LBUTTONUP:
#start point clikc
if num_of_clicks == 0:
cv2.rectangle(img, (pX - mouse_click_size, pY - mouse_click_size),
(pX + mouse_click_size, pY + mouse_click_size), (0, 0, 255), -1)
start_point = Point(pX, pY)
print("start = ", start_point.x, start_point.y)
num_of_clicks += 1
#end point click
elif num_of_clicks == 1:
cv2.rectangle(img, (pX - mouse_click_size, pY - mouse_click_size),
(pX + mouse_click_size, pY + mouse_click_size), (0, 200, 50), -1)
end_point = Point(pX, pY)
print("end = ", end_point.x, end_point.y)
num_of_clicks += 1
#this is the bfs function that will search through all nodes and cells using bfs
def solve_maze(start, end):
#globals
global img, h, w
const = 10000
#if a path is found display (debugging)
true_path = False
#set queue
queue = []
#if cell has been checked for valid path
cell_checked = [[0 for j in range(w)] for i in range(h)]
#parent subtree for checked cells
tree_begin = [[Point() for j in range(w)] for i in range(h)]
#store starting point for maze
queue.append(start)
cell_checked[start.y][start.x] = 1
#loop to search through nodes until maze is empty
while len(queue) > 0:
valid_paths = queue.pop(0)
#will search through subtree by surrounding cells
for nodes in subtree:
cell = valid_paths + nodes
point_x = cell.x
point_y = cell.y
solution_max = 0
#to solve this we will determine all borders as black and search through them
# if cell(a surrounding pixel) is in range of image, not visited, !(B==0 && G==0 && R==0) i.e. pixel is
# not black as black represents border
if (point_x >= 0 and point_x < w and point_y >= 0 and point_y < h and cell_checked[point_y][point_x] == solution_max and
(img[point_y][point_x][0] != 0 or img[point_y][point_x][1] != 0 or img[point_y][point_x][2] != 0)):
queue.append(cell)
cell_checked[cell.y][cell.x] = cell_checked[valid_paths.y][valid_paths.x] + 1 # Later
#bfs function characteristics (blue)
img[cell.y][cell.x] = list(reversed(
[i * 255 for i in colorsys.rgb_to_hsv(cell_checked[cell.y][cell.x] / const, 1, 1)])
)
#once tree path is found
tree_begin[cell.y][cell.x] = valid_paths
#end path once end pixel is found
if cell == end:
true_path = True
del queue[:]
break
#list of paths to trace it
path_nodes = []
#display the found path
if true_path:
valid_paths = end
#loop to get path from found correct path from bfs, end to start, and reverse it to display path from start
while valid_paths != start:
path_nodes.append(valid_paths)
valid_paths = tree_begin[valid_paths.y][valid_paths.x]
path_nodes.append(valid_paths)
path_nodes.reverse()
#display path
for valid_paths in path_nodes:
img[valid_paths.y][valid_paths.x] = [0, 0, 255]
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
#p = cv2.dilate(img[p.y], kernel, iterations=2)
#console display
print("Path Found")
else:
print("Path Not Found")
#console function for points
print("Select start and end points : ")
#use a thread function to simoultaneously run display function, mouse function, and run BFS through it
mazeSolver = threading.Thread(target=solution, args=())
#daemon will join any other exisitng thread
mazeSolver.daemon = True
mazeSolver.start()
#when clicks are less than 2 don't run any functions
while num_of_clicks < 2:
pass
#solve maze
solve_maze(start_point, end_point)
cv2.waitKey(0)
'''
50 images tested with 93% accuracy rate
'''
I'm using win10 and latest version of OpenCV.

Is there an easy way to detect four near identical images with OpenCV when thresholding is insufficient?

I'm trying to detect these chevrons from four instances of bluestacks running the same game:
To make it a little easier at a glance to see the differences. These are the same chevrons zoomed. For some reason, bluestacks render them marginally different every time.
I've tried to use thresholding and different methods with OpenCV but I need to drop it so low I get too many false positives and the different methods don't seem to make a difference.
I'm using win32gui for my template:
class WindowCapture:
# properties
w = 0
h = 0
hwnd = None
cropped_x = 0
cropped_y = 0
offset_x = 0
offset_y = 0
# constructor
def __init__(self, window_name=None):
# find the handle for the window we want to capture.
# if no window name is given, capture the entire screen
if window_name is None:
self.hwnd = win32gui.GetDesktopWindow()
else:
self.hwnd = win32gui.FindWindow(None, window_name)
if not self.hwnd:
raise Exception('Window not found: {}'.format(window_name))
# get the window size
window_rect = win32gui.GetWindowRect(self.hwnd)
self.w = window_rect[2] - window_rect[0]
self.h = window_rect[3] - window_rect[1]
# account for the window border and titlebar and cut them off
border_pixels = 8
titlebar_pixels = 40
self.w = self.w - (border_pixels * 2)
self.h = self.h - titlebar_pixels - border_pixels
self.cropped_x = border_pixels
self.cropped_y = titlebar_pixels
# set the cropped coordinates offset so we can translate screenshot
# images into actual screen positions
self.offset_x = window_rect[0] + self.cropped_x
self.offset_y = window_rect[1] + self.cropped_y
def get_screenshot(self):
# get the window image data
wDC = win32gui.GetWindowDC(self.hwnd)
dcObj = win32ui.CreateDCFromHandle(wDC)
cDC = dcObj.CreateCompatibleDC()
dataBitMap = win32ui.CreateBitmap()
dataBitMap.CreateCompatibleBitmap(dcObj, self.w, self.h)
cDC.SelectObject(dataBitMap)
cDC.BitBlt((0, 0), (self.w, self.h), dcObj, (self.cropped_x, self.cropped_y), win32con.SRCCOPY)
# convert the raw data into a format opencv can read
# dataBitMap.SaveBitmapFile(cDC, 'debug.bmp')
signedIntsArray = dataBitMap.GetBitmapBits(True)
img = np.fromstring(signedIntsArray, dtype='uint8')
img.shape = (self.h, self.w, 4)
# free resources
dcObj.DeleteDC()
cDC.DeleteDC()
win32gui.ReleaseDC(self.hwnd, wDC)
win32gui.DeleteObject(dataBitMap.GetHandle())
img = img[...,:3]
img = np.ascontiguousarray(img)
return img
#staticmethod
def list_window_names():
def winEnumHandler(hwnd, ctx):
if win32gui.IsWindowVisible(hwnd):
print(hex(hwnd), win32gui.GetWindowText(hwnd))
win32gui.EnumWindows(winEnumHandler, None)
# translate a pixel position on a screenshot image to a pixel position on the screen.
# pos = (x, y)
def get_screen_position(self, pos):
return (pos[0] + self.offset_x, pos[1] + self.offset_y)
And OpenCV and Numpy for my object detection:
class Vision:
# properties
needle_img = None
needle_w = 0
needle_h = 0
method = None
# constructor
def __init__(self, needle_img_path, method=cv.TM_CCOEFF_NORMED):
self.needle_img = cv.imread(needle_img_path, cv.IMREAD_UNCHANGED)
# Save the dimensions of the needle image
self.needle_w = self.needle_img.shape[1]
self.needle_h = self.needle_img.shape[0]
# There are 6 methods to choose from:
# TM_CCOEFF, TM_CCOEFF_NORMED, TM_CCORR, TM_CCORR_NORMED, TM_SQDIFF, TM_SQDIFF_NORMED
self.method = method
def find(self, haystack_img, threshold=0.5, debug_mode=None):
# run the OpenCV algorithm
result = cv.matchTemplate(haystack_img, self.needle_img, self.method)
# Get the all the positions from the match result that exceed our threshold
locations = np.where(result >= threshold)
locations = list(zip(*locations[::-1]))
rectangles = []
for loc in locations:
rect = [int(loc[0]), int(loc[1]), self.needle_w, self.needle_h]
# Add every box to the list twice in order to retain single (non-overlapping) boxes
rectangles.append(rect)
rectangles.append(rect)
# Apply group rectangles
rectangles, weights = cv.groupRectangles(rectangles, groupThreshold=1, eps=0.5)
points = []
if len(rectangles):
line_color = (0, 255, 0)
line_type = cv.LINE_4
marker_color = (255, 0, 255)
marker_type = cv.MARKER_CROSS
# Loop over all the rectangles
for (x, y, w, h) in rectangles:
# Determine the center position
center_x = x + int(w/2)
center_y = y + int(h/2)
# Save the points
points.append((center_x, center_y))
if debug_mode == 'rectangles':
# Determine the box position
top_left = (x, y)
bottom_right = (x + w, y + h)
# Draw the box
cv.rectangle(haystack_img, top_left, bottom_right, color=line_color,
lineType=line_type, thickness=2)
elif debug_mode == 'points':
# Draw the center point
cv.drawMarker(haystack_img, (center_x, center_y),
color=marker_color, markerType=marker_type,
markerSize=40, thickness=2)
return points
And then I'm calling the match like this:
chevronsicon = Vision('chevrons.jpg')
# checks for chevrons
chevron = chevronsicon.find(screenshotCropped, 0.86, 'points')
# mouse controls
if chevrons :
py.moveTo(chevrons[0])
Thresholding and different OpenCV methods have worked every single time I've come across this issue previously. I was considering using a gaussian function to blur the edges and then canny to see if I could get a consistent match but I'm not sure if that's overworking what might be a very simple answer I'm simply not aware of.
Is there an easier way to detect these?

Speeding up python image color thresholding/filtering

I am working on a problem where I need to find bounding boxes for white area in an image. Since I am dealing with real-world pictures, I have set a threshold on the RGB values, I create a mask from that and then label it and get bounding box coordinates from that. Here is the code.
import numpy as np
from skimage import io, measure
def bin_labelled_img_to_bboxes(bin_image_labelled):
bboxes = []
for j in np.unique(bin_image_labelled):
if j == 0:
continue
curr = (bin_image_labelled == j)
if np.sum(curr) < 50*50:
continue
indices = np.nonzero(curr)
miny = np.min(indices[0])
minx = np.min(indices[1])
maxy = np.max(indices[0])
maxx = np.max(indices[1])
bboxes.append(((miny, minx), (maxy, maxx)))
return bboxes
class WhiteSeperator(object):
def __init__ (self, img_path):
self.img_path = img_path
self.img = io.imread(self.img_path)
self.bin_image_labelled = np.zeros((self.img.shape[0], self.img.shape[1]))
self.bboxes = []
def get_bin_labelled_img(self):
img = self.img
chan1 = (img[:,:,0] > 200) * (img[:,:,0] <= 255)
chan2 = (img[:,:,0] > 180) * (img[:,:,0] <= 255)
chan3 = (img[:,:,0] > 140) * (img[:,:,0] <= 255)
bin_img = (chan1*chan2*chan3)
bin_image_labelled = measure.label(bin_img)
return bin_image_labelled
def get_white_bboxes(self):
final_white_bboxes = []
self.bin_image_labelled = self.get_bin_labelled_img()
white_bboxes = bin_labelled_img_to_bboxes(self.bin_image_labelled)
for bbox in white_bboxes:
width = bbox[1][1]-bbox[0][1]
height = bbox[1][0]-bbox[0][0]
if height > 80 and width > 200:
self.bboxes.append(bbox)
final_white_bboxes.append(bbox)
return final_white_bboxes
This takes about 3-11 seconds per image for high res images (3000 something x 2000 something). My assumption is that the variance in time per image depends on the number of white bounding boxes found (blaming the bin_labelled_img_to_bboxes function here)
Since I have to do this on video frames, even 3 seconds is super slow. Can the above be done in a more efficient way?

change a label transparency to 0 in python (pygtk)

i want to add a transparent label over an image using pygtk, it does not seem to work with me, the label over comes the background pictures (slider) and i can only see my label. i had the idea to make a label transparent in order to see the background picture,, any suggestions please?
#!/usr/bin/python
# -*- coding: utf-8 -*-
import RPi.GPIO as GPIO
from time import sleep
import urllib2
import os
import xml.dom
import xml.dom.minidom
import pygtk
pygtk.require('2.0')
import gtk
import glib
#Configure the inputs/outputs
GPIO.setmode(GPIO.BCM)
GPIO.setup(4, GPIO.IN, pull_up_down = GPIO.PUD_UP) # The emplyee button
xmldoc = xml.dom.minidom.parse('/var/www/delay.xml')
delay = xmldoc.getElementsByTagName('delay')
def _begin():
if (GPIO.input(4)==0):
response=urllib2.urlopen("http://localhost/num.php?id_service=1",timeout=5) **#retrieve the next ticket number from MYSQL DB through an url**
number = response.read()
label = gtk.Label("9999 ") # for testing else it would be label= gtk.Label(number)**
response.close()
sleep(1);
return _begin()
def is_image(filename):
""" File is image if it has a common suffix and it is a regular file """
if not os.path.isfile(filename):
return False
for suffix in ['.jpg', '.png', '.bmp']:
if filename.lower().endswith(suffix):
return True
return False
def resizeToFit(image, frame, aspect=True, enlarge=False):
"""Resizes a rectangle to fit within another.
Parameters:
image -- A tuple of the original dimensions (width, height).
frame -- A tuple of the target dimensions (width, height).
aspect -- Maintain aspect ratio?
enlarge -- Allow image to be scaled up?
"""
if aspect:
return scaleToFit(image, frame, enlarge)
else:
return stretchToFit(image, frame, enlarge)
def scaleToFit(image, frame, enlarge=False):
image_width, image_height = image
frame_width, frame_height = frame
image_aspect = float(image_width) / image_height
frame_aspect = float(frame_width) / frame_height
# Determine maximum width/height (prevent up-scaling).
if not enlarge:
max_width = min(frame_width, image_width)
max_height = min(frame_height, image_height)
else:
max_width = frame_width
max_height = frame_height
# Frame is wider than image.
if frame_aspect > image_aspect:
height = max_height
width = int(height * image_aspect)
# Frame is taller than image.
else:
width = max_width
height = int(width / image_aspect)
return (width, height)
def stretchToFit(image, frame, enlarge=False):
image_width, image_height = image
frame_width, frame_height = frame
# Stop image from being blown up.
if not enlarge:
width = min(frame_width, image_width)
height = min(frame_height, image_height)
else:
width = frame_width
height = frame_height
return (width, height)
class ResizableImage(gtk.DrawingArea):
def __init__(self, aspect=True, enlarge=False,
interp=gtk.gdk.INTERP_NEAREST, backcolor=None, max=(1600,1200)):
"""Construct a ResizableImage control.
Parameters:
aspect -- Maintain aspect ratio?
enlarge -- Allow image to be scaled up?
interp -- Method of interpolation to be used.
backcolor -- Tuple (R, G, B) with values ranging from 0 to 1,
or None for transparent.
max -- Max dimensions for internal image (width, height).
"""
super(ResizableImage, self).__init__()
self.pixbuf = None
self.aspect = aspect
self.enlarge = enlarge
self.interp = interp
self.backcolor = backcolor
self.max = max
self.connect('expose_event', self.expose)
self.connect('realize', self.on_realize)
def on_realize(self, widget):
if self.backcolor is None:
color = gtk.gdk.Color()
else:
color = gtk.gdk.Color(*self.backcolor)
self.window.set_background(color)
def expose(self, widget, event):
# Load Cairo drawing context.
self.context = self.window.cairo_create()
# Set a clip region.
self.context.rectangle(
event.area.x, event.area.y,
event.area.width, event.area.height)
self.context.clip()
# Render image.
self.draw(self.context)
return False
def draw(self, context):
# Get dimensions.
rect = self.get_allocation()
x, y = rect.x, rect.y
# Remove parent offset, if any.
parent = self.get_parent()
if parent:
offset = parent.get_allocation()
x -= offset.x
y -= offset.y
# Fill background color.
if self.backcolor:
context.rectangle(x, y, rect.width, rect.height)
context.set_source_rgb(*self.backcolor)
context.fill_preserve()
# Check if there is an image.
if not self.pixbuf:
return
width, height = resizeToFit(
(self.pixbuf.get_width(), self.pixbuf.get_height()),
(rect.width, rect.height),
self.aspect,
self.enlarge)
x = x + (rect.width - width) / 2
y = y + (rect.height - height) / 2
context.set_source_pixbuf(
self.pixbuf.scale_simple(width, height, self.interp), x, y)
context.paint()
def set_from_pixbuf(self, pixbuf):
width, height = pixbuf.get_width(), pixbuf.get_height()
# Limit size of internal pixbuf to increase speed.
if not self.max or (width < self.max[0] and height < self.max[1]):
self.pixbuf = pixbuf
else:
width, height = resizeToFit((width, height), self.max)
self.pixbuf = pixbuf.scale_simple(
width, height,
gtk.gdk.INTERP_BILINEAR)
self.invalidate()
def set_from_file(self, filename):
self.set_from_pixbuf(gtk.gdk.pixbuf_new_from_file(filename))
def invalidate(self):
self.queue_draw()
class DemoGtk:
SECONDS_BETWEEN_PICTURES = int(delay[0].firstChild.nodeValue)
FULLSCREEN = True
WALK_INSTEAD_LISTDIR = True
def __init__(self):
self.window = gtk.Window()
self.window.connect('destroy', gtk.main_quit)
self.window.set_title('Slideshow')
self.image = ResizableImage( True, True, gtk.gdk.INTERP_BILINEAR)
self.image.show()
self.window.add(self.image)
self.window.add(label) # GO to def _begin there i declared the label with its value**
self.load_file_list()
self.window.show_all()
if self.FULLSCREEN:
self.window.fullscreen()
glib.timeout_add_seconds(self.SECONDS_BETWEEN_PICTURES, self.on_tick)
self.display()
def load_file_list(self):
""" Find all images """
self.files = []
self.index = 0
if self.WALK_INSTEAD_LISTDIR:
for directory, sub_directories, files in os.walk('.'):
for filename in files:
if is_image(filename):
filepath = os.path.join(directory, filename)
self.files.append(filepath)
else:
for filename in os.listdir('.'):
if is_image(filename):
self.files.append(filename)
print "Images:", self.files
def display(self):
""" Sent a request to change picture if it is possible """
if 0 <= self.index < len(self.files):
self.image.set_from_file(self.files[self.index])
return True
else:
return False
def on_tick(self):
""" Skip to another picture.
If this picture is last, go to the first one. """
self.index += 1
if self.index >= len(self.files):
self.index = 0
return self.display()
if __name__ == "__main__":
while 1:
gui = DemoGtk()
gtk.main()
_begin()
# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4

Using pygtk how can I make a simple fullscreen slide show

Using pygtk how can I make a full screen slide show that rotates through all the images in a directory switching them every x seconds
In the past I wrote exactly the same thing. Then I deleted it. This version uses a prepared code for exposing an image while scaling it. It was taken from Jack Valmadre’s Blog
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Taken and customed from Jack Valmadre's Blog:
# http://jackvalmadre.wordpress.com/2008/09/21/resizable-image-control/
#
# Put together and created the time switching by Izidor Matusov <izidor.matusov#gmail.com>
import os
import pygtk
pygtk.require('2.0')
import gtk
import glib
def is_image(filename):
""" File is image if it has a common suffix and it is a regular file """
if not os.path.isfile(filename):
return False
for suffix in ['.jpg', '.png', '.bmp']:
if filename.lower().endswith(suffix):
return True
return False
def resizeToFit(image, frame, aspect=True, enlarge=False):
"""Resizes a rectangle to fit within another.
Parameters:
image -- A tuple of the original dimensions (width, height).
frame -- A tuple of the target dimensions (width, height).
aspect -- Maintain aspect ratio?
enlarge -- Allow image to be scaled up?
"""
if aspect:
return scaleToFit(image, frame, enlarge)
else:
return stretchToFit(image, frame, enlarge)
def scaleToFit(image, frame, enlarge=False):
image_width, image_height = image
frame_width, frame_height = frame
image_aspect = float(image_width) / image_height
frame_aspect = float(frame_width) / frame_height
# Determine maximum width/height (prevent up-scaling).
if not enlarge:
max_width = min(frame_width, image_width)
max_height = min(frame_height, image_height)
else:
max_width = frame_width
max_height = frame_height
# Frame is wider than image.
if frame_aspect > image_aspect:
height = max_height
width = int(height * image_aspect)
# Frame is taller than image.
else:
width = max_width
height = int(width / image_aspect)
return (width, height)
def stretchToFit(image, frame, enlarge=False):
image_width, image_height = image
frame_width, frame_height = frame
# Stop image from being blown up.
if not enlarge:
width = min(frame_width, image_width)
height = min(frame_height, image_height)
else:
width = frame_width
height = frame_height
return (width, height)
class ResizableImage(gtk.DrawingArea):
def __init__(self, aspect=True, enlarge=False,
interp=gtk.gdk.INTERP_NEAREST, backcolor=None, max=(1600,1200)):
"""Construct a ResizableImage control.
Parameters:
aspect -- Maintain aspect ratio?
enlarge -- Allow image to be scaled up?
interp -- Method of interpolation to be used.
backcolor -- Tuple (R, G, B) with values ranging from 0 to 1,
or None for transparent.
max -- Max dimensions for internal image (width, height).
"""
super(ResizableImage, self).__init__()
self.pixbuf = None
self.aspect = aspect
self.enlarge = enlarge
self.interp = interp
self.backcolor = backcolor
self.max = max
self.connect('expose_event', self.expose)
self.connect('realize', self.on_realize)
def on_realize(self, widget):
if self.backcolor is None:
color = gtk.gdk.Color()
else:
color = gtk.gdk.Color(*self.backcolor)
self.window.set_background(color)
def expose(self, widget, event):
# Load Cairo drawing context.
self.context = self.window.cairo_create()
# Set a clip region.
self.context.rectangle(
event.area.x, event.area.y,
event.area.width, event.area.height)
self.context.clip()
# Render image.
self.draw(self.context)
return False
def draw(self, context):
# Get dimensions.
rect = self.get_allocation()
x, y = rect.x, rect.y
# Remove parent offset, if any.
parent = self.get_parent()
if parent:
offset = parent.get_allocation()
x -= offset.x
y -= offset.y
# Fill background color.
if self.backcolor:
context.rectangle(x, y, rect.width, rect.height)
context.set_source_rgb(*self.backcolor)
context.fill_preserve()
# Check if there is an image.
if not self.pixbuf:
return
width, height = resizeToFit(
(self.pixbuf.get_width(), self.pixbuf.get_height()),
(rect.width, rect.height),
self.aspect,
self.enlarge)
x = x + (rect.width - width) / 2
y = y + (rect.height - height) / 2
context.set_source_pixbuf(
self.pixbuf.scale_simple(width, height, self.interp), x, y)
context.paint()
def set_from_pixbuf(self, pixbuf):
width, height = pixbuf.get_width(), pixbuf.get_height()
# Limit size of internal pixbuf to increase speed.
if not self.max or (width < self.max[0] and height < self.max[1]):
self.pixbuf = pixbuf
else:
width, height = resizeToFit((width, height), self.max)
self.pixbuf = pixbuf.scale_simple(
width, height,
gtk.gdk.INTERP_BILINEAR)
self.invalidate()
def set_from_file(self, filename):
self.set_from_pixbuf(gtk.gdk.pixbuf_new_from_file(filename))
def invalidate(self):
self.queue_draw()
class DemoGtk:
SECONDS_BETWEEN_PICTURES = 3
FULLSCREEN = True
WALK_INSTEAD_LISTDIR = True
def __init__(self):
self.window = gtk.Window()
self.window.connect('destroy', gtk.main_quit)
self.window.set_title('Slideshow')
self.image = ResizableImage( True, True, gtk.gdk.INTERP_BILINEAR)
self.image.show()
self.window.add(self.image)
self.load_file_list()
self.window.show_all()
if self.FULLSCREEN:
self.window.fullscreen()
glib.timeout_add_seconds(self.SECONDS_BETWEEN_PICTURES, self.on_tick)
self.display()
def load_file_list(self):
""" Find all images """
self.files = []
self.index = 0
if self.WALK_INSTEAD_LISTDIR:
for directory, sub_directories, files in os.walk('.'):
for filename in files:
if is_image(filename):
filepath = os.path.join(directory, filename)
self.files.append(filepath)
else:
for filename in os.listdir('.'):
if is_image(filename):
self.files.append(filename)
print "Images:", self.files
def display(self):
""" Sent a request to change picture if it is possible """
if 0 <= self.index < len(self.files):
self.image.set_from_file(self.files[self.index])
return True
else:
return False
def on_tick(self):
""" Skip to another picture.
If this picture is last, go to the first one. """
self.index += 1
if self.index >= len(self.files):
self.index = 0
return self.display()
if __name__ == "__main__":
gui = DemoGtk()
gtk.main()
# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
Use gtk.Image and gtk.Window.fullscreen().

Categories

Resources