def composite_image(im1, im2): if isinstance(im1, GdkPixbuf.Pixbuf): im1 = image_tools.pixbuf_to_pil(im1) if isinstance(im2, GdkPixbuf.Pixbuf): im2 = image_tools.pixbuf_to_pil(im2) im = Image.new('RGBA', (im1.size[0] + im2.size[0], max(im1.size[1], im2.size[1]))) im.paste(im1, (0, 0, im1.size[0], im1.size[1])) im.paste(im2, (im1.size[0], 0, im1.size[0] + im2.size[0], im2.size[1])) return im
def composite_image(im1, im2): if isinstance(im1, gtk.gdk.Pixbuf): im1 = image_tools.pixbuf_to_pil(im1) if isinstance(im2, gtk.gdk.Pixbuf): im2 = image_tools.pixbuf_to_pil(im2) im = Image.new('RGBA', (im1.size[0] + im2.size[0], max(im1.size[1], im2.size[1]))) im.paste(im1, (0, 0, im1.size[0], im1.size[1])) im.paste(im2, (im1.size[0], 0, im1.size[0]+im2.size[0], im2.size[1])) return im
def draw_histogram(pixbuf, height=170, fill=170, text=True): """Draw a histogram from <pixbuf> and return it as another pixbuf. The returned prixbuf will be 262x<height> px. The value of <fill> determines the colour intensity of the filled graphs, valid values are between 0 and 255. If <text> is True a label with the maximum pixel value will be added to one corner. """ im = Image.new('RGB', (258, height - 4), (30, 30, 30)) hist_data = image_tools.pixbuf_to_pil(pixbuf).histogram() maximum = max(hist_data[:768] + [1]) y_scale = float(height - 6) / maximum r = [int(hist_data[n] * y_scale) for n in range(256)] g = [int(hist_data[n] * y_scale) for n in range(256, 512)] b = [int(hist_data[n] * y_scale) for n in range(512, 768)] im_data = im.getdata() # Draw the filling colours for x in range(256): for y in range(1, max(r[x], g[x], b[x]) + 1): r_px = y <= r[x] and fill or 0 g_px = y <= g[x] and fill or 0 b_px = y <= b[x] and fill or 0 im_data.putpixel((x + 1, height - 5 - y), (r_px, g_px, b_px)) # Draw the outlines for x in range(1, 256): for y in range(r[x - 1] + 1, r[x] + 1) + [r[x]] * (r[x] != 0): r_px, g_px, b_px = im_data.getpixel((x + 1, height - 5 - y)) im_data.putpixel((x + 1, height - 5 - y), (255, g_px, b_px)) for y in range(r[x] + 1, r[x - 1] + 1): r_px, g_px, b_px = im_data.getpixel((x, height - 5 - y)) im_data.putpixel((x, height - 5 - y), (255, g_px, b_px)) for y in range(g[x - 1] + 1, g[x] + 1) + [g[x]] * (g[x] != 0): r_px, g_px, b_px = im_data.getpixel((x + 1, height - 5 - y)) im_data.putpixel((x + 1, height - 5 - y), (r_px, 255, b_px)) for y in range(g[x] + 1, g[x - 1] + 1): r_px, g_px, b_px = im_data.getpixel((x, height - 5 - y)) im_data.putpixel((x, height - 5 - y), (r_px, 255, b_px)) for y in range(b[x - 1] + 1, b[x] + 1) + [b[x]] * (b[x] != 0): r_px, g_px, b_px = im_data.getpixel((x + 1, height - 5 - y)) im_data.putpixel((x + 1, height - 5 - y), (r_px, g_px, 255)) for y in range(b[x] + 1, b[x - 1] + 1): r_px, g_px, b_px = im_data.getpixel((x, height - 5 - y)) im_data.putpixel((x, height - 5 - y), (r_px, g_px, 255)) if text: maxstr = 'max: ' + str(maximum) draw = ImageDraw.Draw(im) draw.rectangle((0, 0, len(maxstr) * 6 + 2, 10), fill=(30, 30, 30)) draw.text((2, 0), maxstr, fill=(255, 255, 255)) im = ImageOps.expand(im, 1, (80, 80, 80)) im = ImageOps.expand(im, 1, (0, 0, 0)) return image_tools.pil_to_pixbuf(im)
def draw_histogram(pixbuf, height=170, fill=170, text=True): """Draw a histogram from <pixbuf> and return it as another pixbuf. The returned prixbuf will be 262x<height> px. The value of <fill> determines the colour intensity of the filled graphs, valid values are between 0 and 255. If <text> is True a label with the maximum pixel value will be added to one corner. """ im = Image.new('RGB', (258, height - 4), (30, 30, 30)) hist_data = image_tools.pixbuf_to_pil(pixbuf).histogram() maximum = max(hist_data[:768] + [1]) y_scale = float(height - 6) / maximum r = [int(hist_data[n] * y_scale) for n in xrange(256)] g = [int(hist_data[n] * y_scale) for n in xrange(256, 512)] b = [int(hist_data[n] * y_scale) for n in xrange(512, 768)] im_data = im.getdata() # Draw the filling colours for x in xrange(256): for y in xrange(1, max(r[x], g[x], b[x]) + 1): r_px = y <= r[x] and fill or 0 g_px = y <= g[x] and fill or 0 b_px = y <= b[x] and fill or 0 im_data.putpixel((x + 1, height - 5 - y), (r_px, g_px, b_px)) # Draw the outlines for x in xrange(1, 256): for y in range(r[x-1] + 1, r[x] + 1) + [r[x]] * (r[x] != 0): r_px, g_px, b_px = im_data.getpixel((x + 1, height - 5 - y)) im_data.putpixel((x + 1, height - 5 - y), (255, g_px, b_px)) for y in range(r[x] + 1, r[x-1] + 1): r_px, g_px, b_px = im_data.getpixel((x, height - 5 - y)) im_data.putpixel((x, height - 5 - y), (255, g_px, b_px)) for y in range(g[x-1] + 1, g[x] + 1) + [g[x]] * (g[x] != 0): r_px, g_px, b_px = im_data.getpixel((x + 1, height - 5 - y)) im_data.putpixel((x + 1, height - 5 - y), (r_px, 255, b_px)) for y in range(g[x] + 1, g[x-1] + 1): r_px, g_px, b_px = im_data.getpixel((x, height - 5 - y)) im_data.putpixel((x, height - 5 - y), (r_px, 255, b_px)) for y in range(b[x-1] + 1, b[x] + 1) + [b[x]] * (b[x] != 0): r_px, g_px, b_px = im_data.getpixel((x + 1, height - 5 - y)) im_data.putpixel((x + 1, height - 5 - y), (r_px, g_px, 255)) for y in range(b[x] + 1, b[x-1] + 1): r_px, g_px, b_px = im_data.getpixel((x, height - 5 - y)) im_data.putpixel((x, height - 5 - y), (r_px, g_px, 255)) if text: maxstr = 'max: ' + str(maximum) draw = ImageDraw.Draw(im) draw.rectangle((0, 0, len(maxstr) * 6 + 2, 10), fill=(30, 30, 30)) draw.text((2, 0), maxstr, fill=(255, 255, 255)) im = ImageOps.expand(im, 1, (80, 80, 80)) im = ImageOps.expand(im, 1, (0, 0, 0)) return image_tools.pil_to_pixbuf(im)
def _copy_windows(self, pixbuf, path): """ Copies pixbuf and path to the clipboard. Uses native Win32 API, as GTK+ doesn't seem to work. """ windll = ctypes.windll OpenClipboard = windll.user32.OpenClipboard EmptyClipboard = windll.user32.EmptyClipboard SetClipboardData = windll.user32.SetClipboardData CloseClipboard = windll.user32.CloseClipboard GlobalAlloc = windll.kernel32.GlobalAlloc GlobalLock = windll.kernel32.GlobalLock GlobalLock.restype = ctypes.c_void_p GlobalUnlock = windll.kernel32.GlobalUnlock def buffer_to_handle(buffer, buffer_size): """ Creates a memory handle for the passed data. This handle doesn't need to be freed by the application. """ global_mem = GlobalAlloc( 0x0042, # GMEM_MOVEABLE | GMEM_ZEROINIT buffer_size) lock = GlobalLock(global_mem) ctypes.memmove(lock, ctypes.addressof(buffer), buffer_size) GlobalUnlock(global_mem) return global_mem # Paste the text as Unicode string text_buffer = ctypes.create_unicode_buffer(path) text_handle = buffer_to_handle(text_buffer, ctypes.sizeof(text_buffer)) # Paste the image as Win32 DIB structure pil = image_tools.pixbuf_to_pil(pixbuf) output = cStringIO.StringIO() pil.convert("RGB").save(output, "BMP") dibdata = output.getvalue()[14:] output.close() image_buffer = ctypes.create_string_buffer(dibdata) image_handle = buffer_to_handle(image_buffer, ctypes.sizeof(image_buffer)) # Actually copy data to clipboard if OpenClipboard(self._window.window.handle): EmptyClipboard() SetClipboardData( 13, # CF_UNICODETEXT text_handle) SetClipboardData( 8, # CF_DIB image_handle) CloseClipboard() else: log.warning('Could not open clipboard.')
def test_pixbuf_to_pil(self): for image in ( 'transparent.png', 'transparent-indexed.png', 'pattern-opaque-rgb.png', 'pattern-opaque-rgba.png', 'pattern-transparent-rgba.png', ): pixbuf = image_tools.load_pixbuf(get_image_path(image)) im = image_tools.pixbuf_to_pil(pixbuf) msg = ('pixbuf_to_pil("%s") failed; ' 'result %%(diff_type)s differs: %%(diff)s' % (image, )) self.assertImagesEqual(im, pixbuf, msg=msg)
def _copy_windows(self, pixbuf, path): """ Copies pixbuf and path to the clipboard. Uses native Win32 API, as GTK+ doesn't seem to work. """ windll = ctypes.windll OpenClipboard = windll.user32.OpenClipboard EmptyClipboard = windll.user32.EmptyClipboard SetClipboardData = windll.user32.SetClipboardData CloseClipboard = windll.user32.CloseClipboard GlobalAlloc = windll.kernel32.GlobalAlloc GlobalLock = windll.kernel32.GlobalLock GlobalLock.restype = ctypes.c_void_p GlobalUnlock = windll.kernel32.GlobalUnlock def buffer_to_handle(buffer, buffer_size): """ Creates a memory handle for the passed data. This handle doesn't need to be freed by the application. """ global_mem = GlobalAlloc( 0x0042, # GMEM_MOVEABLE | GMEM_ZEROINIT buffer_size) lock = GlobalLock(global_mem) ctypes.memmove(lock, ctypes.addressof(buffer), buffer_size) GlobalUnlock(global_mem) return global_mem # Paste the text as Unicode string text_buffer = ctypes.create_unicode_buffer(path) text_handle = buffer_to_handle(text_buffer, ctypes.sizeof(text_buffer)) # Paste the image as Win32 DIB structure pil = image_tools.pixbuf_to_pil(pixbuf) output = cStringIO.StringIO() pil.convert("RGB").save(output, "BMP") dibdata = output.getvalue()[14:] output.close() image_buffer = ctypes.create_string_buffer(dibdata) image_handle = buffer_to_handle(image_buffer, ctypes.sizeof(image_buffer)) # Actually copy data to clipboard if OpenClipboard(self._window.window.handle): EmptyClipboard() SetClipboardData(13, # CF_UNICODETEXT text_handle) SetClipboardData(8, # CF_DIB image_handle) CloseClipboard() else: log.warning('Could not open clipboard.')
def test_pixbuf_to_pil(self): for image in ( 'transparent.png', 'transparent-indexed.png', 'pattern-opaque-rgb.png', 'pattern-opaque-rgba.png', 'pattern-transparent-rgba.png', ): pixbuf = image_tools.load_pixbuf(get_image_path(image)) im = image_tools.pixbuf_to_pil(pixbuf) msg = ( 'pixbuf_to_pil("%s") failed; ' 'result %%(diff_type)s differs: %%(diff)s' % (image,) ) self.assertImagesEqual(im, pixbuf, msg=msg)