summaryrefslogtreecommitdiffstats
path: root/lib/Python/Lib/PIL/EpsImagePlugin.py
diff options
context:
space:
mode:
authorGravatar Walter Purcaro <vuolter@users.noreply.github.com> 2015-05-12 14:07:48 +0200
committerGravatar Walter Purcaro <vuolter@users.noreply.github.com> 2015-05-12 14:07:48 +0200
commit5d86cfd98437eaa2b84b07ba19d51d50d64bc53f (patch)
tree735c4b2445a274be1440b75c7733d2805ff24307 /lib/Python/Lib/PIL/EpsImagePlugin.py
parentOther import fixes (2) (diff)
downloadpyload-5d86cfd98437eaa2b84b07ba19d51d50d64bc53f.tar.xz
Missing optional lib
Diffstat (limited to 'lib/Python/Lib/PIL/EpsImagePlugin.py')
-rw-r--r--lib/Python/Lib/PIL/EpsImagePlugin.py424
1 files changed, 424 insertions, 0 deletions
diff --git a/lib/Python/Lib/PIL/EpsImagePlugin.py b/lib/Python/Lib/PIL/EpsImagePlugin.py
new file mode 100644
index 000000000..83024b63f
--- /dev/null
+++ b/lib/Python/Lib/PIL/EpsImagePlugin.py
@@ -0,0 +1,424 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# EPS file handling
+#
+# History:
+# 1995-09-01 fl Created (0.1)
+# 1996-05-18 fl Don't choke on "atend" fields, Ghostscript interface (0.2)
+# 1996-08-22 fl Don't choke on floating point BoundingBox values
+# 1996-08-23 fl Handle files from Macintosh (0.3)
+# 2001-02-17 fl Use 're' instead of 'regex' (Python 2.1) (0.4)
+# 2003-09-07 fl Check gs.close status (from Federico Di Gregorio) (0.5)
+# 2014-05-07 e Handling of EPS with binary preview and fixed resolution
+# resizing
+#
+# Copyright (c) 1997-2003 by Secret Labs AB.
+# Copyright (c) 1995-2003 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+__version__ = "0.5"
+
+import re
+import io
+from PIL import Image, ImageFile, _binary
+
+#
+# --------------------------------------------------------------------
+
+i32 = _binary.i32le
+o32 = _binary.o32le
+
+split = re.compile(r"^%%([^:]*):[ \t]*(.*)[ \t]*$")
+field = re.compile(r"^%[%!\w]([^:]*)[ \t]*$")
+
+gs_windows_binary = None
+import sys
+if sys.platform.startswith('win'):
+ import shutil
+ if hasattr(shutil, 'which'):
+ which = shutil.which
+ else:
+ # Python < 3.3
+ import distutils.spawn
+ which = distutils.spawn.find_executable
+ for binary in ('gswin32c', 'gswin64c', 'gs'):
+ if which(binary) is not None:
+ gs_windows_binary = binary
+ break
+ else:
+ gs_windows_binary = False
+
+
+def has_ghostscript():
+ if gs_windows_binary:
+ return True
+ if not sys.platform.startswith('win'):
+ import subprocess
+ try:
+ gs = subprocess.Popen(['gs', '--version'], stdout=subprocess.PIPE)
+ gs.stdout.read()
+ return True
+ except OSError:
+ # no ghostscript
+ pass
+ return False
+
+
+def Ghostscript(tile, size, fp, scale=1):
+ """Render an image using Ghostscript"""
+
+ # Unpack decoder tile
+ decoder, tile, offset, data = tile[0]
+ length, bbox = data
+
+ # Hack to support hi-res rendering
+ scale = int(scale) or 1
+ # orig_size = size
+ # orig_bbox = bbox
+ size = (size[0] * scale, size[1] * scale)
+ # resolution is dependent on bbox and size
+ res = (float((72.0 * size[0]) / (bbox[2]-bbox[0])),
+ float((72.0 * size[1]) / (bbox[3]-bbox[1])))
+ # print("Ghostscript", scale, size, orig_size, bbox, orig_bbox, res)
+
+ import os
+ import subprocess
+ import tempfile
+
+ out_fd, outfile = tempfile.mkstemp()
+ os.close(out_fd)
+
+ infile_temp = None
+ if hasattr(fp, 'name') and os.path.exists(fp.name):
+ infile = fp.name
+ else:
+ in_fd, infile_temp = tempfile.mkstemp()
+ os.close(in_fd)
+ infile = infile_temp
+
+ # ignore length and offset!
+ # ghostscript can read it
+ # copy whole file to read in ghostscript
+ with open(infile_temp, 'wb') as f:
+ # fetch length of fp
+ fp.seek(0, 2)
+ fsize = fp.tell()
+ # ensure start position
+ # go back
+ fp.seek(0)
+ lengthfile = fsize
+ while lengthfile > 0:
+ s = fp.read(min(lengthfile, 100*1024))
+ if not s:
+ break
+ lengthfile -= len(s)
+ f.write(s)
+
+ # Build ghostscript command
+ command = ["gs",
+ "-q", # quiet mode
+ "-g%dx%d" % size, # set output geometry (pixels)
+ "-r%fx%f" % res, # set input DPI (dots per inch)
+ "-dNOPAUSE -dSAFER", # don't pause between pages,
+ # safe mode
+ "-sDEVICE=ppmraw", # ppm driver
+ "-sOutputFile=%s" % outfile, # output file
+ "-c", "%d %d translate" % (-bbox[0], -bbox[1]),
+ # adjust for image origin
+ "-f", infile, # input file
+ ]
+
+ if gs_windows_binary is not None:
+ if not gs_windows_binary:
+ raise WindowsError('Unable to locate Ghostscript on paths')
+ command[0] = gs_windows_binary
+
+ # push data through ghostscript
+ try:
+ gs = subprocess.Popen(command, stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE)
+ gs.stdin.close()
+ status = gs.wait()
+ if status:
+ raise IOError("gs failed (status %d)" % status)
+ im = Image.core.open_ppm(outfile)
+ finally:
+ try:
+ os.unlink(outfile)
+ if infile_temp:
+ os.unlink(infile_temp)
+ except:
+ pass
+
+ return im
+
+
+class PSFile:
+ """
+ Wrapper for bytesio object that treats either CR or LF as end of line.
+ """
+ def __init__(self, fp):
+ self.fp = fp
+ self.char = None
+
+ def seek(self, offset, whence=0):
+ self.char = None
+ self.fp.seek(offset, whence)
+
+ def readline(self):
+ s = self.char or b""
+ self.char = None
+
+ c = self.fp.read(1)
+ while c not in b"\r\n":
+ s = s + c
+ c = self.fp.read(1)
+
+ self.char = self.fp.read(1)
+ # line endings can be 1 or 2 of \r \n, in either order
+ if self.char in b"\r\n":
+ self.char = None
+
+ return s.decode('latin-1')
+
+
+def _accept(prefix):
+ return prefix[:4] == b"%!PS" or i32(prefix) == 0xC6D3D0C5
+
+##
+# Image plugin for Encapsulated Postscript. This plugin supports only
+# a few variants of this format.
+
+
+class EpsImageFile(ImageFile.ImageFile):
+ """EPS File Parser for the Python Imaging Library"""
+
+ format = "EPS"
+ format_description = "Encapsulated Postscript"
+
+ mode_map = {1: "L", 2: "LAB", 3: "RGB"}
+
+ def _open(self):
+ (length, offset) = self._find_offset(self.fp)
+
+ # Rewrap the open file pointer in something that will
+ # convert line endings and decode to latin-1.
+ try:
+ if bytes is str:
+ # Python2, no encoding conversion necessary
+ fp = open(self.fp.name, "Ur")
+ else:
+ # Python3, can use bare open command.
+ fp = open(self.fp.name, "Ur", encoding='latin-1')
+ except:
+ # Expect this for bytesio/stringio
+ fp = PSFile(self.fp)
+
+ # go to offset - start of "%!PS"
+ fp.seek(offset)
+
+ box = None
+
+ self.mode = "RGB"
+ self.size = 1, 1 # FIXME: huh?
+
+ #
+ # Load EPS header
+
+ s = fp.readline().strip('\r\n')
+
+ while s:
+ if len(s) > 255:
+ raise SyntaxError("not an EPS file")
+
+ try:
+ m = split.match(s)
+ except re.error as v:
+ raise SyntaxError("not an EPS file")
+
+ if m:
+ k, v = m.group(1, 2)
+ self.info[k] = v
+ if k == "BoundingBox":
+ try:
+ # Note: The DSC spec says that BoundingBox
+ # fields should be integers, but some drivers
+ # put floating point values there anyway.
+ box = [int(float(s)) for s in v.split()]
+ self.size = box[2] - box[0], box[3] - box[1]
+ self.tile = [("eps", (0, 0) + self.size, offset,
+ (length, box))]
+ except:
+ pass
+
+ else:
+ m = field.match(s)
+ if m:
+ k = m.group(1)
+
+ if k == "EndComments":
+ break
+ if k[:8] == "PS-Adobe":
+ self.info[k[:8]] = k[9:]
+ else:
+ self.info[k] = ""
+ elif s[0] == '%':
+ # handle non-DSC Postscript comments that some
+ # tools mistakenly put in the Comments section
+ pass
+ else:
+ raise IOError("bad EPS header")
+
+ s = fp.readline().strip('\r\n')
+
+ if s[:1] != "%":
+ break
+
+ #
+ # Scan for an "ImageData" descriptor
+
+ while s[:1] == "%":
+
+ if len(s) > 255:
+ raise SyntaxError("not an EPS file")
+
+ if s[:11] == "%ImageData:":
+ # Encoded bitmapped image.
+ [x, y, bi, mo, z3, z4, en, id] = s[11:].split(None, 7)
+
+ if int(bi) != 8:
+ break
+ try:
+ self.mode = self.mode_map[int(mo)]
+ except:
+ break
+
+ self.size = int(x), int(y)
+ return
+
+ s = fp.readline().strip('\r\n')
+ if not s:
+ break
+
+ if not box:
+ raise IOError("cannot determine EPS bounding box")
+
+ def _find_offset(self, fp):
+
+ s = fp.read(160)
+
+ if s[:4] == b"%!PS":
+ # for HEAD without binary preview
+ fp.seek(0, 2)
+ length = fp.tell()
+ offset = 0
+ elif i32(s[0:4]) == 0xC6D3D0C5:
+ # FIX for: Some EPS file not handled correctly / issue #302
+ # EPS can contain binary data
+ # or start directly with latin coding
+ # more info see:
+ # http://partners.adobe.com/public/developer/en/ps/5002.EPSF_Spec.pdf
+ offset = i32(s[4:8])
+ length = i32(s[8:12])
+ else:
+ raise SyntaxError("not an EPS file")
+
+ return (length, offset)
+
+ def load(self, scale=1):
+ # Load EPS via Ghostscript
+ if not self.tile:
+ return
+ self.im = Ghostscript(self.tile, self.size, self.fp, scale)
+ self.mode = self.im.mode
+ self.size = self.im.size
+ self.tile = []
+
+ def load_seek(self, *args, **kwargs):
+ # we can't incrementally load, so force ImageFile.parser to
+ # use our custom load method by defining this method.
+ pass
+
+
+#
+# --------------------------------------------------------------------
+
+def _save(im, fp, filename, eps=1):
+ """EPS Writer for the Python Imaging Library."""
+
+ #
+ # make sure image data is available
+ im.load()
+
+ #
+ # determine postscript image mode
+ if im.mode == "L":
+ operator = (8, 1, "image")
+ elif im.mode == "RGB":
+ operator = (8, 3, "false 3 colorimage")
+ elif im.mode == "CMYK":
+ operator = (8, 4, "false 4 colorimage")
+ else:
+ raise ValueError("image mode is not supported")
+
+ class NoCloseStream:
+ def __init__(self, fp):
+ self.fp = fp
+
+ def __getattr__(self, name):
+ return getattr(self.fp, name)
+
+ def close(self):
+ pass
+
+ base_fp = fp
+ fp = NoCloseStream(fp)
+ if sys.version_info[0] > 2:
+ fp = io.TextIOWrapper(fp, encoding='latin-1')
+
+ if eps:
+ #
+ # write EPS header
+ fp.write("%!PS-Adobe-3.0 EPSF-3.0\n")
+ fp.write("%%Creator: PIL 0.1 EpsEncode\n")
+ # fp.write("%%CreationDate: %s"...)
+ fp.write("%%%%BoundingBox: 0 0 %d %d\n" % im.size)
+ fp.write("%%Pages: 1\n")
+ fp.write("%%EndComments\n")
+ fp.write("%%Page: 1 1\n")
+ fp.write("%%ImageData: %d %d " % im.size)
+ fp.write("%d %d 0 1 1 \"%s\"\n" % operator)
+
+ #
+ # image header
+ fp.write("gsave\n")
+ fp.write("10 dict begin\n")
+ fp.write("/buf %d string def\n" % (im.size[0] * operator[1]))
+ fp.write("%d %d scale\n" % im.size)
+ fp.write("%d %d 8\n" % im.size) # <= bits
+ fp.write("[%d 0 0 -%d 0 %d]\n" % (im.size[0], im.size[1], im.size[1]))
+ fp.write("{ currentfile buf readhexstring pop } bind\n")
+ fp.write(operator[2] + "\n")
+ fp.flush()
+
+ ImageFile._save(im, base_fp, [("eps", (0, 0)+im.size, 0, None)])
+
+ fp.write("\n%%%%EndBinary\n")
+ fp.write("grestore end\n")
+ fp.flush()
+
+#
+# --------------------------------------------------------------------
+
+Image.register_open(EpsImageFile.format, EpsImageFile, _accept)
+
+Image.register_save(EpsImageFile.format, _save)
+
+Image.register_extension(EpsImageFile.format, ".ps")
+Image.register_extension(EpsImageFile.format, ".eps")
+
+Image.register_mime(EpsImageFile.format, "application/postscript")