i'm uploading files to azure like so:
with open(tempfile, "rb") as data:
blob_client.upload_blob(data, blob_type='BlockBlob', length=None, metadata=None)
how can i get a progress indication?
when i try uploading as stream, it only uploads one chunk.
i'm sure i'm doing something wrong, but can't find info.
thanks!
It looks like the Azure library doesn't include a callback function to monitor progress.
Fortunately, you can add a wrapper around Python's file object which can call a callback everytime there's a read.
Try this:
import os
from io import BufferedReader, FileIO
class ProgressFile(BufferedReader):
# For binary opening only
def __init__(self, filename, read_callback):
f = FileIO(file=filename, mode='r')
self._read_callback = read_callback
super().__init__(raw=f)
# I prefer Pathlib but this should still support 2.x
self.length = os.stat(filename).st_size
def read(self, size=None):
calc_sz = size
if not calc_sz:
calc_sz = self.length - self.tell()
self._read_callback(position=self.tell(), read_size=calc_sz, total=self.length)
return super(ProgressFile, self).read(size)
def my_callback(position, read_size, total):
# Write your own callback. You could convert the absolute values to percentages
# Using .format rather than f'' for compatibility
print("position: {position}, read_size: {read_size}, total: {total}".format(position=position,
read_size=read_size,
total=total))
myfile = ProgressFile(filename='mybigfile.txt', read_callback=my_callback)
Then you would do
blob_client.upload_blob(myfile, blob_type='BlockBlob', length=None, metadata=None)
myfile.close()
Edit:
It looks like TQDM (progress monitor) has a neat wrapper: https://github.com/tqdm/tqdm#hooks-and-callbacks.
The bonus there is that you get easy access to a pretty progress bar.
This is how I ended up using the tqdm wrapper that Alastair mentioned above
size = os.stat(fname).st_size
with tqdm.wrapattr(open(fname, 'rb'), "read", total=size) as data:
blob_client.upload_blob(data)
Works perfectly, shows time estimate, progress bar, human readable file sizes and transfer speeds.
I'm hoping this is a simple issue and I'm just missing something. I have a script saved in two different locations, on our shared server and locally on my desktop. When I run the script from the server I get what appears to be easygui error.
Traceback (most recent call last):
File "Z:\Python\module1.py", line 35, in <module>
reply = buttonbox(msg=msg,image=IMG)
TypeError: buttonbox() got an unexpected keyword argument 'msg'
This I can get around. For some reason, message is required for the version that is saved on the server and msg is required for the version saved on my desktop. That is ok since it at least works. What breaks this for me is the image feature. It works in the version on my desktop but I have no idea how to get it to work on the version on our server. Full code shown below:
import PIL
from PIL import Image
import os
from easygui import *
import sys
print sys.version, sys.version_info
WORKDIR = "c:\\temp"
DESKTOP = 'c:' + os.environ['HOMEPATH'] + "\Desktop"
os.chdir(DESKTOP)
IMAGES = os.listdir(DESKTOP+"\\New Items Images")
for IMAGE in IMAGES:
path = DESKTOP+"\\New Items Images\\"+IMAGE
#Creates a Tkinter-compatible photo image, which can be used everywhere Tkinter expects an image object.
img = Image.open(path)
width, height = img.size
if width >= height:
basewidth = 600
wpercent = (basewidth / float(img.size[0]))
hsize = int((float(img.size[1]) * float(wpercent)))
else:
baseheight = 600
hpercent = (baseheight / float(img.size[1]))
wsize = int((float(img.size[0]) * float(hpercent)))
img = img.resize((basewidth, hsize), PIL.Image.ANTIALIAS)
img.save(DESKTOP + "\\" + IMAGE)
IMG = DESKTOP+"\\"+IMAGE
SKU = "sku"
msg = "Is %s acceptable?\n%s\n%sx%s" % (IMAGE, SKU, width, height)
reply = buttonbox(msg=msg,image=IMG)
if ynbox == 1:
print "This would now get pushed to CA"
`
Generally speaking I know that this is probably ugly code. But that aside, what the end game goal here is to open an image, display it to the user, then delete all created imaged from desktop. Any advice or help would be greatly appreciated.
Perhaps its the way its imported and its picking up buttonbox from another library and not recognising the parameters.
does this work?
import easygui
easygui.buttonbox(msg=msg, image=IMG)
or even plain data like this work?
import easygui
easygui.buttonbox('Click on your favorite flavor.', 'Favorite Flavor', ('Chocolate', 'Vanilla', 'Strawberry'))
if neither of those work you might want to check the version of easygui and the documentation related.
or perhaps its a conflict with the class "ButtonBox" and instantiation function "buttonbox" they have that are named the same except one doesn't use kwargs and for some reason there is an issue there.
https://github.com/robertlugg/easygui/blob/master/easygui/boxes/button_box.py#L110
try instantiate a class version like this
bb = ButtonBox("message", "title", ('Chocolate', 'Vanilla'), None, None, None, None)
reply = bb.run()
How do I convert an svg to png, in Python? I am storing the svg in an instance of StringIO. Should I use the pyCairo library? How do I write that code?
Here is what I did using cairosvg:
from cairosvg import svg2png
svg_code = """
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10"/>
<line x1="12" y1="8" x2="12" y2="12"/>
<line x1="12" y1="16" x2="12" y2="16"/>
</svg>
"""
svg2png(bytestring=svg_code,write_to='output.png')
And it works like a charm!
See more: cairosvg document
The answer is "pyrsvg" - a Python binding for librsvg.
There is an Ubuntu python-rsvg package providing it. Searching Google for its name is poor because its source code seems to be contained inside the "gnome-python-desktop" Gnome project GIT repository.
I made a minimalist "hello world" that renders SVG to a cairo
surface and writes it to disk:
import cairo
import rsvg
img = cairo.ImageSurface(cairo.FORMAT_ARGB32, 640,480)
ctx = cairo.Context(img)
## handle = rsvg.Handle(<svg filename>)
# or, for in memory SVG data:
handle= rsvg.Handle(None, str(<svg data>))
handle.render_cairo(ctx)
img.write_to_png("svg.png")
Update: as of 2014 the needed package for Fedora Linux distribution is: gnome-python2-rsvg. The above snippet listing still works as-is.
Install Inkscape and call it as command line:
${INKSCAPE_PATH} -z -f ${source_svg} -w ${width} -j -e ${dest_png}
You can also snap specific rectangular area only using parameter -j, e.g. co-ordinate "0:125:451:217"
${INKSCAPE_PATH} -z -f ${source_svg} -w ${width} -j -a ${coordinates} -e ${dest_png}
If you want to show only one object in the SVG file, you can specify the parameter -i with the object id that you have setup in the SVG. It hides everything else.
${INKSCAPE_PATH} -z -f ${source_svg} -w ${width} -i ${object} -j -a ${coordinates} -e ${dest_png}
I'm using Wand-py (an implementation of the Wand wrapper around ImageMagick) to import some pretty advanced SVGs and so far have seen great results! This is all the code it takes:
with wand.image.Image( blob=svg_file.read(), format="svg" ) as image:
png_image = image.make_blob("png")
I just discovered this today, and felt like it was worth sharing for anyone else who might straggle across this answer as it's been a while since most of these questions were answered.
NOTE: Technically in testing I discovered you don't even actually have to pass in the format parameter for ImageMagick, so with wand.image.Image( blob=svg_file.read() ) as image: was all that was really needed.
EDIT: From an attempted edit by qris, here's some helpful code that lets you use ImageMagick with an SVG that has a transparent background:
from wand.api import library
import wand.color
import wand.image
with wand.image.Image() as image:
with wand.color.Color('transparent') as background_color:
library.MagickSetBackgroundColor(image.wand,
background_color.resource)
image.read(blob=svg_file.read(), format="svg")
png_image = image.make_blob("png32")
with open(output_filename, "wb") as out:
out.write(png_image)
I did not find any of the answers satisfactory. All the mentioned libraries have some problem or the other like Cairo dropping support for python 3.6 (they dropped Python 2 support some 3 years ago!). Also, installing the mentioned libraries on the Mac was a pain.
Finally, I found the best solution was svglib + reportlab. Both installed without a hitch using pip and first call to convert from svg to png worked beautifully! Very happy with the solution.
Just 2 commands do the trick:
from svglib.svglib import svg2rlg
from reportlab.graphics import renderPM
drawing = svg2rlg("my.svg")
renderPM.drawToFile(drawing, "my.png", fmt="PNG")
Are there any limitations with these I should be aware of?
Try this: http://cairosvg.org/
The site says:
CairoSVG is written in pure python and only depends on Pycairo. It is
known to work on Python 2.6 and 2.7.
Update November 25, 2016:
2.0.0 is a new major version, its changelog includes:
Drop Python 2 support
Another solution I've just found here How to render a scaled SVG to a QImage?
from PySide.QtSvg import *
from PySide.QtGui import *
def convertSvgToPng(svgFilepath,pngFilepath,width):
r=QSvgRenderer(svgFilepath)
height=r.defaultSize().height()*width/r.defaultSize().width()
i=QImage(width,height,QImage.Format_ARGB32)
p=QPainter(i)
r.render(p)
i.save(pngFilepath)
p.end()
PySide is easily installed from a binary package in Windows (and I use it for other things so is easy for me).
However, I noticed a few problems when converting country flags from Wikimedia, so perhaps not the most robust svg parser/renderer.
A little extension on the answer of jsbueno:
#!/usr/bin/env python
import cairo
import rsvg
from xml.dom import minidom
def convert_svg_to_png(svg_file, output_file):
# Get the svg files content
with open(svg_file) as f:
svg_data = f.read()
# Get the width / height inside of the SVG
doc = minidom.parse(svg_file)
width = int([path.getAttribute('width') for path
in doc.getElementsByTagName('svg')][0])
height = int([path.getAttribute('height') for path
in doc.getElementsByTagName('svg')][0])
doc.unlink()
# create the png
img = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
ctx = cairo.Context(img)
handler = rsvg.Handle(None, str(svg_data))
handler.render_cairo(ctx)
img.write_to_png(output_file)
if __name__ == '__main__':
from argparse import ArgumentParser
parser = ArgumentParser()
parser.add_argument("-f", "--file", dest="svg_file",
help="SVG input file", metavar="FILE")
parser.add_argument("-o", "--output", dest="output", default="svg.png",
help="PNG output file", metavar="FILE")
args = parser.parse_args()
convert_svg_to_png(args.svg_file, args.output)
Here is a another solution without using rsvg(which is currently not available for windows).Only install cairosvg using pip install CairoSVG
svg2png.py
from cairosvg import svg2png
svg_code = open("input.svg", 'rt').read()
svg2png(bytestring=svg_code,write_to='output.png')
SVG scaling and PNG rendering
Using pycairo and librsvg I was able to achieve SVG scaling and rendering to a bitmap. Assuming your SVG is not exactly 256x256 pixels, the desired output, you can read in the SVG to a Cairo context using rsvg and then scale it and write to a PNG.
main.py
import cairo
import rsvg
width = 256
height = 256
svg = rsvg.Handle('cool.svg')
unscaled_width = svg.props.width
unscaled_height = svg.props.height
svg_surface = cairo.SVGSurface(None, width, height)
svg_context = cairo.Context(svg_surface)
svg_context.save()
svg_context.scale(width/unscaled_width, height/unscaled_height)
svg.render_cairo(svg_context)
svg_context.restore()
svg_surface.write_to_png('cool.png')
RSVG C binding
From the Cario website with some minor modification. Also a good example of how to call a C-library from Python
from ctypes import CDLL, POINTER, Structure, byref, util
from ctypes import c_bool, c_byte, c_void_p, c_int, c_double, c_uint32, c_char_p
class _PycairoContext(Structure):
_fields_ = [("PyObject_HEAD", c_byte * object.__basicsize__),
("ctx", c_void_p),
("base", c_void_p)]
class _RsvgProps(Structure):
_fields_ = [("width", c_int), ("height", c_int),
("em", c_double), ("ex", c_double)]
class _GError(Structure):
_fields_ = [("domain", c_uint32), ("code", c_int), ("message", c_char_p)]
def _load_rsvg(rsvg_lib_path=None, gobject_lib_path=None):
if rsvg_lib_path is None:
rsvg_lib_path = util.find_library('rsvg-2')
if gobject_lib_path is None:
gobject_lib_path = util.find_library('gobject-2.0')
l = CDLL(rsvg_lib_path)
g = CDLL(gobject_lib_path)
g.g_type_init()
l.rsvg_handle_new_from_file.argtypes = [c_char_p, POINTER(POINTER(_GError))]
l.rsvg_handle_new_from_file.restype = c_void_p
l.rsvg_handle_render_cairo.argtypes = [c_void_p, c_void_p]
l.rsvg_handle_render_cairo.restype = c_bool
l.rsvg_handle_get_dimensions.argtypes = [c_void_p, POINTER(_RsvgProps)]
return l
_librsvg = _load_rsvg()
class Handle(object):
def __init__(self, path):
lib = _librsvg
err = POINTER(_GError)()
self.handle = lib.rsvg_handle_new_from_file(path.encode(), byref(err))
if self.handle is None:
gerr = err.contents
raise Exception(gerr.message)
self.props = _RsvgProps()
lib.rsvg_handle_get_dimensions(self.handle, byref(self.props))
def get_dimension_data(self):
svgDim = self.RsvgDimensionData()
_librsvg.rsvg_handle_get_dimensions(self.handle, byref(svgDim))
return (svgDim.width, svgDim.height)
def render_cairo(self, ctx):
"""Returns True is drawing succeeded."""
z = _PycairoContext.from_address(id(ctx))
return _librsvg.rsvg_handle_render_cairo(self.handle, z.ctx)
Here is an approach where Inkscape is called by Python.
Note that it suppresses certain crufty output that Inkscape writes to the console (specifically, stderr and stdout) during normal error-free operation. The output is captured in two string variables, out and err.
import subprocess # May want to use subprocess32 instead
cmd_list = [ '/full/path/to/inkscape', '-z',
'--export-png', '/path/to/output.png',
'--export-width', 100,
'--export-height', 100,
'/path/to/input.svg' ]
# Invoke the command. Divert output that normally goes to stdout or stderr.
p = subprocess.Popen( cmd_list, stdout=subprocess.PIPE, stderr=subprocess.PIPE )
# Below, < out > and < err > are strings or < None >, derived from stdout and stderr.
out, err = p.communicate() # Waits for process to terminate
# Maybe do something with stdout output that is in < out >
# Maybe do something with stderr output that is in < err >
if p.returncode:
raise Exception( 'Inkscape error: ' + (err or '?') )
For example, when running a particular job on my Mac OS system, out ended up being:
Background RRGGBBAA: ffffff00
Area 0:0:339:339 exported to 100 x 100 pixels (72.4584 dpi)
Bitmap saved as: /path/to/output.png
(The input svg file had a size of 339 by 339 pixels.)
Try this python script:
Don't forget to install cairosvg: pip3 install cairosvg
#!/usr/bin/env python3
import os
import cairosvg
for file in os.listdir('.'):
if os.path.isfile(file) and file.endswith(".svg"):
name = file.split('.svg')[0]
cairosvg.svg2png(url=name+'.svg',write_to=name+'.png')
Try using Gtk.Image and Gdk.Pixbuf
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('Gdk', '3.0')
from gi.repository import Gdk, Gtk
from PIL import Image
image = Gtk.Image()
image.set_from_file("path/to/image.svg")
pb = image.get_pixbuf()
pb.savev("path/to/convented/image.jpeg","jpeg",[],[])
im = Image.open("path/to/convented/image.jpeg")
pix = im.load()
print(pix[1,1])
Actually, I did not want to be dependent of anything else but Python (Cairo, Ink.., etc.)
My requirements were to be as simple as possible, at most, a simple pip install "savior" would suffice, that's why any of those above didn't suit for me.
I came through this (going further than Stackoverflow on the research).
https://www.tutorialexample.com/best-practice-to-python-convert-svg-to-png-with-svglib-python-tutorial/
Looks good, so far. So I share it in case anyone in the same situation.
All the answer's here are great, but I figure I'll mention that I have made a simple library that loads SVG's files as pillow Image instances which can then be exported. It uses inkscape like in blj's answer, but renders to stdout so that no temporary files are made. There's some basic usage stuff in the README.
https://github.com/jlwoolf/pillow-svg
EDIT:
As suggested, here's a brief explanation, since the link could become invalid:
The library uses inkscape's command line interface to convert the image to a png of a specific size or dpi using the python subprocess library. By setting --export-filename to -, inkscape redirects the output to the stdout. The first two lines are discarded, and the remaining output is passed to PIL.Image.open, converting it to pillow image instance.
import subprocess
from PIL import Image
options = ["inkscape", "--export-filename=-", "--export-type=png", "file.svg"]
pipe = subprocess.Popen(options, stdout=subprocess.PIPE)
pipe.stdout.readline()
pipe.stdout.readline()
img = Image.open(pipe.stdout)
From there you can do whatever pillow image operations you need (like export as a jpg, resize, crop, etc).
EDIT 2:
Just added support for skia-python (haven't fully tested it, but seems to work so far). This way you can convert an svg to png with only a single pip install (no need to use inkscape).
Here is an explanation of how the library uses skia-python:
First, the svg file is loaded into a skia.SVGDOM. From there you can grab the SVGDOM's dimensions, using containerSize. Then a skia.Surface of the desired image output size is made. The canvas is scaled to fit the svg to the surface, and then the svg is rendered. From there, an image snapshot can be made, which can then be fed to PIL.Image.open.
import skia
from PIL import Image
skia_stream = skia.Stream.MakeFromFile("file.svg")
skia_svg = skia.SVGDOM.MakeFromStream(skia_stream)
svg_width, svg_height = skia_svg.containerSize()
surface_width, surface_height = 512, 512
surface = skia.Surface(surface_width, surface_height)
with surface as canvas:
canvas.scale(surface_width / svg_width, surface_height / svg_height)
skia_svg.render(canvas)
with io.BytesIO(surface.makeImageSnapshot().encodeToData()) as f:
img = Image.open(f)
img.load()
Edit 3:
I have fleshed out the library much much more. There is a command line utility now for easy svg conversion, along with more documentation explaining usage. Hope it helps!
Posting my code from this StackOverflow answer. It's a workaround to svglib+reportlib not supporting a transparent background and no scaling (see #sarang's answer and #ualter-jr's answer as well as these Github issues on scaling not working and this one on transparency)
This uses pyMuPDF to render an intermediate pdf from reportlab to PNG.
The big advantage is that it doesn't need any external libraries as pymupdf comes with precompiled wheels for Windows, Linux and MacOS.
The whole thing is as easy as
pip install pymupdf svglib
and then executing the following lines
import fitz
from svglib import svglib
from reportlab.graphics import renderPDF
# Convert svg to pdf in memory with svglib+reportlab
# directly rendering to png does not support transparency nor scaling
drawing = svglib.svg2rlg(path="input.svg")
pdf = renderPDF.drawToString(drawing)
# Open pdf with fitz (pyMuPdf) to convert to PNG
doc = fitz.Document(stream=pdf)
pix = doc.load_page(0).get_pixmap(alpha=True, dpi=300)
pix.save("output.png")
I'm trying to read the EXIF info for microscope images like this one:
https://dl.dropboxusercontent.com/u/3816350/E3-9.tif
I am most interested in the "Image Description" tag because it contains information about the scale of the image. I have successfully loaded the EXIF info using the exifread package:
import exifread
f = open('E3-9.tif', 'rb')
exif_info = exifread.process_file(f)
for tag in exif_info.keys():
print "Key: %s, value %s" % (tag, exif_info[tag])
However, the Image Description is cutoff in the output and I cannot figure out how to display the entire "Image ImageDescription" field. Any idea how I can do this?
BTW, I tried using PIL to read the EXIF info (as described here) using this code:
from PIL import Image
from PIL.ExifTags import TAGS
img = Image.open('E3-9.tif')
exif_data = img._getexif()
But I get the following error:
Traceback (most recent call last):
File "/Users/..../2014-01-02 - Read scale from tif file.py", line 22, in <module>
exif_data = img._getexif()
File "/Users/danhickstein/Library/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/PIL/Image.py", line 512, in __getattr__
raise AttributeError(name)
AttributeError: _getexif
I have also tried exiftool on the command line, but it also slightly cuts off the Image Description field.
Any tips would be appreciated.
The metadata you're looking may be part of the image's IPTC metadata, not EXIF. If so, you'll need a different Python module to read it. Take a look at "Exif manipulation library for python [closed]" for recommendations that include IPTC data.
Here is the hilariously slow and inefficient method of calling exiftool on the command line using subprocess.check_output. Not my finest hour, but it works:
import matplotlib.pyplot as plt
import subprocess, glob, re
def get_magnification(filename):
p = subprocess.check_output('exiftool -tab %s'%filename,shell=True)
xpix = float(re.findall('XpixCal=\d*.\d*',p)[0][8:])
ypix = float(re.findall('YpixCal=\d*.\d*',p)[0][8:])
mag = int(re.findall('p.\d+',p)[0][2:])
return xpix,ypix,mag
xpix,ypix,mag = get_magnification('E3-9.tif')
print 'X pixels per nm: %.3f'%(xpix)
print 'Y pixels per nm: %.3f'%(ypix)
print 'Magnification: %ix'%(mag)
You have to use exif_info[tag].values to get the full ImageDescription
ImageGrab from PIL would have been ideal. I'm looking for similar functionality, specifically the ability to define the screenshot's bounding box. I've been looking for a library to do so on Mac OS X but haven't had any luck. I also wasn't able to find any sample code to do it (maybe pyobjc?).
While not exactly what you want, in a pinch you might just use:
os.system("screencapture screen.png")
Then open that image with the Image module. I'm sure a better solution exists though.
Here's how to capture and save a screenshot with PyObjC, based on my answer here
You can capture the entire screen, or specify a region to capture. If you don't need to do that, I'd recommend just calling the screencapture command (more features, more robust, and quicker - the initial PyObjC import alone can take around a second)
import Quartz
import LaunchServices
from Cocoa import NSURL
import Quartz.CoreGraphics as CG
def screenshot(path, region = None):
"""region should be a CGRect, something like:
>>> import Quartz.CoreGraphics as CG
>>> region = CG.CGRectMake(0, 0, 100, 100)
>>> sp = ScreenPixel()
>>> sp.capture(region=region)
The default region is CG.CGRectInfinite (captures the full screen)
"""
if region is None:
region = CG.CGRectInfinite
# Create screenshot as CGImage
image = CG.CGWindowListCreateImage(
region,
CG.kCGWindowListOptionOnScreenOnly,
CG.kCGNullWindowID,
CG.kCGWindowImageDefault)
dpi = 72 # FIXME: Should query this from somewhere, e.g for retina displays
url = NSURL.fileURLWithPath_(path)
dest = Quartz.CGImageDestinationCreateWithURL(
url,
LaunchServices.kUTTypePNG, # file type
1, # 1 image in file
None
)
properties = {
Quartz.kCGImagePropertyDPIWidth: dpi,
Quartz.kCGImagePropertyDPIHeight: dpi,
}
# Add the image to the destination, characterizing the image with
# the properties dictionary.
Quartz.CGImageDestinationAddImage(dest, image, properties)
# When all the images (only 1 in this example) are added to the destination,
# finalize the CGImageDestination object.
Quartz.CGImageDestinationFinalize(dest)
if __name__ == '__main__':
# Capture full screen
screenshot("/tmp/testscreenshot_full.png")
# Capture region (100x100 box from top-left)
region = CG.CGRectMake(0, 0, 100, 100)
screenshot("/tmp/testscreenshot_partial.png", region=region)
While I do understand that this thread is close to five years old now, I'm answering this in the hope that it helps people in future.
Here's what worked for me, based on an answer in this thread (credit goes to ponty ) : Take a screenshot via a python script. [Linux]
https://github.com/ponty/pyscreenshot
Install:
easy_install pyscreenshot
Example:
import pyscreenshot
# fullscreen
screenshot=pyscreenshot.grab()
screenshot.show()
# part of the screen
screenshot=pyscreenshot.grab(bbox=(10,10,500,500))
screenshot.show()
# save to file
pyscreenshot.grab_to_file('screenshot.png')
Pillow has since added ImageGrab support for macOS!
However it's not in v2.9 (as of right now the latest) so I just added this file to my local module.
The code is as below:
#
# The Python Imaging Library
# $Id$
#
# screen grabber (macOS and Windows only)
#
# History:
# 2001-04-26 fl created
# 2001-09-17 fl use builtin driver, if present
# 2002-11-19 fl added grabclipboard support
#
# Copyright (c) 2001-2002 by Secret Labs AB
# Copyright (c) 2001-2002 by Fredrik Lundh
#
# See the README file for information on usage and redistribution.
#
from . import Image
import sys
if sys.platform not in ["win32", "darwin"]:
raise ImportError("ImageGrab is macOS and Windows only")
if sys.platform == "win32":
grabber = Image.core.grabscreen
elif sys.platform == "darwin":
import os
import tempfile
import subprocess
def grab(bbox=None):
if sys.platform == "darwin":
fh, filepath = tempfile.mkstemp('.png')
os.close(fh)
subprocess.call(['screencapture', '-x', filepath])
im = Image.open(filepath)
im.load()
os.unlink(filepath)
else:
size, data = grabber()
im = Image.frombytes(
"RGB", size, data,
# RGB, 32-bit line padding, origin lower left corner
"raw", "BGR", (size[0]*3 + 3) & -4, -1
)
if bbox:
im = im.crop(bbox)
return im
def grabclipboard():
if sys.platform == "darwin":
fh, filepath = tempfile.mkstemp('.jpg')
os.close(fh)
commands = [
"set theFile to (open for access POSIX file \""+filepath+"\" with write permission)",
"try",
"write (the clipboard as JPEG picture) to theFile",
"end try",
"close access theFile"
]
script = ["osascript"]
for command in commands:
script += ["-e", command]
subprocess.call(script)
im = None
if os.stat(filepath).st_size != 0:
im = Image.open(filepath)
im.load()
os.unlink(filepath)
return im
else:
debug = 0 # temporary interface
data = Image.core.grabclipboard(debug)
if isinstance(data, bytes):
from . import BmpImagePlugin
import io
return BmpImagePlugin.DibImageFile(io.BytesIO(data))
return data
from subprocess import call
import time
from time import gmtime, strftime
# Take screenshot every 10 seconds and store in the folder where the
# code file is present on disk. To stop the script press Cmd+Z/C
def take_screen_shot():
# save screen shots where
call(["screencapture", "Screenshot" + strftime("%Y-%m-%d %H:%M:%S", gmtime()) + ".jpg"])
def build_screen_shot_base():
while True:
take_screen_shot()
time.sleep(10)
build_screen_shot_base()
I found that using webkit2png was the most convenient solution for me on OS X.
brew install webkit2png
webkit2png http://stackoverflow.com