Repository: python-pillow/Pillow

Issue:
EPS files are loaded without transparency
<!--
Thank you for reporting an issue.

Follow these guidelines to ensure your issue is handled properly.

If you have a ...

1.  General question: consider asking the question on Stack Overflow
    with the python-imaging-library tag:

    * https://stackoverflow.com/questions/tagged/python-imaging-library

    Do not ask a question in both places.

    If you think you have found a bug or have an unexplained exception
    then file a bug report here.

2.  Bug report: include a self-contained, copy-pastable example that
    generates the issue if possible. Be concise with code posted.
    Guidelines on how to provide a good bug report:

    * https://stackoverflow.com/help/mcve

    Bug reports which follow these guidelines are easier to diagnose,
    and are often handled much more quickly.

3.  Feature request: do a quick search of existing issues
    to make sure this has not been asked before.

We know asking good questions takes effort, and we appreciate your time.
Thank you.
-->

EPS files can have transparency, and GhostScript have the option to keep it. However, if we use Pillow to open an EPS-file, then the alpha-channel is discarded. To my understanding, this is because Pillow is currently using the `ppm` (portable pixel map)-driver, which creates RGB-images, not RGBA-images. 

I therefore propose to add an option to specify which driver to use with GhostScript (or add a flag that can be enabled to use the `pngalpha` driver instead of the `ppmraw` driver)

To my understanding, this can be fixed by modifying line 120 in `src/PIL/EpsImagePlugin.py`: https://github.com/python-pillow/Pillow/blob/20b8a8377372b1f318ae275acd5e11bad4722e2e/src/PIL/EpsImagePlugin.py#L120
into
```python
        "-sDEVICE=pngalpha",  # png driver
```

I made the change locally on my machine, and it seemed to work well. 
### What are your OS, Python and Pillow versions?

* OS: Windows 10
* Python: 3.8
* Pillow: 8.2.0


### Endnote: Script to generate a postscript file and convert it with Pillow
```python
import turtle
from PIL import Image

pen = turtle.Turtle()
for side in range(4):
    pen.forward(50)
    pen.right(90)

turtle.getscreen().getcanvas().postscript(file="square.eps")
img = Image.open('square.eps')
img.save("image.png")
```
<!--
Please include **code** that reproduces the issue and whenever possible, an **image** that demonstrates the issue. Please upload images to GitHub, not to third-party file hosting sites. If necessary, add the image to a zip or tar archive.

The best reproductions are self-contained scripts with minimal dependencies. If you are using a framework such as Plone, Django, or Buildout, try to replicate the issue just using Pillow.
-->



Discussion:

Resolving patch:
diff --git a/src/PIL/EpsImagePlugin.py b/src/PIL/EpsImagePlugin.py
--- a/src/PIL/EpsImagePlugin.py
+++ b/src/PIL/EpsImagePlugin.py
@@ -61,7 +61,7 @@ def has_ghostscript():
     return False
 
 
-def Ghostscript(tile, size, fp, scale=1):
+def Ghostscript(tile, size, fp, scale=1, transparency=False):
     """Render an image using Ghostscript"""
 
     # Unpack decoder tile
@@ -108,6 +108,8 @@ def Ghostscript(tile, size, fp, scale=1):
                 lengthfile -= len(s)
                 f.write(s)
 
+    device = "pngalpha" if transparency else "ppmraw"
+
     # Build Ghostscript command
     command = [
         "gs",
@@ -117,7 +119,7 @@ def Ghostscript(tile, size, fp, scale=1):
         "-dBATCH",  # exit after processing
         "-dNOPAUSE",  # don't pause between pages
         "-dSAFER",  # safe mode
-        "-sDEVICE=ppmraw",  # ppm driver
+        f"-sDEVICE={device}",
         f"-sOutputFile={outfile}",  # output file
         # adjust for image origin
         "-c",
@@ -325,11 +327,11 @@ def _find_offset(self, fp):
 
         return (length, offset)
 
-    def load(self, scale=1):
+    def load(self, scale=1, transparency=False):
         # Load EPS via Ghostscript
         if not self.tile:
             return
-        self.im = Ghostscript(self.tile, self.size, self.fp, scale)
+        self.im = Ghostscript(self.tile, self.size, self.fp, scale, transparency)
         self.mode = self.im.mode
         self._size = self.im.size
         self.tile = []


Test patch:
diff --git a/Tests/images/reqd_showpage_transparency.png b/Tests/images/reqd_showpage_transparency.png
new file mode 100644
Binary files /dev/null and b/Tests/images/reqd_showpage_transparency.png differ
diff --git a/Tests/test_file_eps.py b/Tests/test_file_eps.py
--- a/Tests/test_file_eps.py
+++ b/Tests/test_file_eps.py
@@ -96,6 +96,17 @@ def test_showpage():
             assert_image_similar(plot_image, target, 6)
 
 
+@pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available")
+def test_transparency():
+    with Image.open("Tests/images/reqd_showpage.eps") as plot_image:
+        plot_image.load(transparency=True)
+        assert plot_image.mode == "RGBA"
+
+        with Image.open("Tests/images/reqd_showpage_transparency.png") as target:
+            #  fonts could be slightly different
+            assert_image_similar(plot_image, target, 6)
+
+
 @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available")
 def test_file_object(tmp_path):
     # issue 479