Repository: python-pillow/Pillow

Issue:
Transparent png converted to green
Hi, I'm using libimagequant library to optimize a png, and the result is perfect, the only problem is that pngs with transparent background are converted to a green background, i don't know why this is happening, the palette generated is correct is there a solution for this, apart from replacing colors?

Code:

```python
img = img.convert('RGBA')
attr = liq.Attr()
input_image = attr.create_rgba(img.tobytes(), img.width, img.height, 0)
result = input_image.quantize(attr)
out_pixels = result.remap_image(input_image)
out_palette = result.get_palette()
out_img = Image.frombytes('P', (img.width, img.height), out_pixels)
palette_data = []
for color in out_palette:
    palette_data.append(color.r)
    palette_data.append(color.g)
    palette_data.append(color.b)
out_img.putpalette(palette_data)
out_img.save('output.png')
```


Discussion:
Please can you share an example image that causes this?

Your code isn't self-contained. Please share runnable example code. For example, we don't know what's in `img`, or what `liq` is.
Sorry about that

```python
from PIL import Image
import libimagequant as liq

img = Image.open("test.png")
img = img.convert('RGBA')
attr = liq.Attr()
input_image = attr.create_rgba(img.tobytes(), img.width, img.height, 0)
result = input_image.quantize(attr)
out_pixels = result.remap_image(input_image)
out_palette = result.get_palette()
out_img = Image.frombytes('P', (img.width, img.height), out_pixels)
palette_data = []
for color in out_palette:
    palette_data.append(color.r)
    palette_data.append(color.g)
    palette_data.append(color.b)
out_img.putpalette(palette_data)
out_img.save('output.png')
```

![test](https://user-images.githubusercontent.com/40673097/94939726-e8b31780-04a8-11eb-8f69-7d94fefb8733.png)

![output](https://user-images.githubusercontent.com/40673097/94939747-eea8f880-04a8-11eb-9c79-ad57cf6dfc03.png)

Have you tried something like this:


```python
img = Image.open("test.png")
quantized = img.quantize(method=Image.LIBIMAGEQUANT)
quantized.save('out.png')
```

https://github.com/python-pillow/Pillow/blob/master/src/PIL/Image.py#L1039
I didnt build pillow to use libimagequant, thats why im doing it the other way.

But i think the error of the bg from transparent to green is coming in the putpalette method, i dont know why but its not using transparency
There are a few ways to do transparency, either using 'PA' mode (paletted w/ alpha) or setting the im.info['transparency'] value. 

But the basic palletted image doesn't have any transparency, as you can see by passing in the rgb values, but not alpha. 
Issue fixed by RoadrunnerWMC. Please see https://github.com/RoadrunnerWMC/libimagequant-python/issues/1. 
`putpalette` doesn't look like it supports alpha. But there's an apparently undocumented function that does. Add the following line before the `save()` at the end and I think it works:
```python
out_img.im.putpalettealphas(bytes(c.a for c in out_palette))
```

Resolving patch:
diff --git a/src/PIL/Image.py b/src/PIL/Image.py
--- a/src/PIL/Image.py
+++ b/src/PIL/Image.py
@@ -815,9 +815,15 @@ def load(self):
         """
         if self.im and self.palette and self.palette.dirty:
             # realize palette
-            self.im.putpalette(*self.palette.getdata())
+            mode, arr = self.palette.getdata()
+            if mode == "RGBA":
+                mode = "RGB"
+                self.info["transparency"] = arr[3::4]
+                arr = bytes(
+                    value for (index, value) in enumerate(arr) if index % 4 != 3
+                )
+            self.im.putpalette(mode, arr)
             self.palette.dirty = 0
-            self.palette.mode = "RGB"
             self.palette.rawmode = None
             if "transparency" in self.info:
                 if isinstance(self.info["transparency"], int):
@@ -825,6 +831,8 @@ def load(self):
                 else:
                     self.im.putpalettealphas(self.info["transparency"])
                 self.palette.mode = "RGBA"
+            else:
+                self.palette.mode = "RGB"
 
         if self.im:
             if cffi and USE_CFFI_ACCESS:
@@ -1672,12 +1680,14 @@ def putdata(self, data, scale=1.0, offset=0.0):
 
     def putpalette(self, data, rawmode="RGB"):
         """
-        Attaches a palette to this image.  The image must be a "P",
-        "PA", "L" or "LA" image, and the palette sequence must contain
-        768 integer values, where each group of three values represent
-        the red, green, and blue values for the corresponding pixel
-        index. Instead of an integer sequence, you can use an 8-bit
-        string.
+        Attaches a palette to this image.  The image must be a "P", "PA", "L"
+        or "LA" image.
+
+        The palette sequence must contain either 768 integer values, or 1024
+        integer values if alpha is included. Each group of values represents
+        the red, green, blue (and alpha if included) values for the
+        corresponding pixel index. Instead of an integer sequence, you can use
+        an 8-bit string.
 
         :param data: A palette sequence (either a list or a string).
         :param rawmode: The raw mode of the palette.


Test patch:
diff --git a/Tests/test_image_putpalette.py b/Tests/test_image_putpalette.py
--- a/Tests/test_image_putpalette.py
+++ b/Tests/test_image_putpalette.py
@@ -1,8 +1,8 @@
 import pytest
 
-from PIL import ImagePalette
+from PIL import Image, ImagePalette
 
-from .helper import hopper
+from .helper import assert_image_equal, hopper
 
 
 def test_putpalette():
@@ -39,3 +39,20 @@ def test_imagepalette():
     im.putpalette(ImagePalette.random())
     im.putpalette(ImagePalette.sepia())
     im.putpalette(ImagePalette.wedge())
+
+
+def test_putpalette_with_alpha_values():
+    with Image.open("Tests/images/transparent.gif") as im:
+        expected = im.convert("RGBA")
+
+        palette = im.getpalette()
+        transparency = im.info.pop("transparency")
+
+        palette_with_alpha_values = []
+        for i in range(256):
+            color = palette[i * 3 : i * 3 + 3]
+            alpha = 0 if i == transparency else 255
+            palette_with_alpha_values += color + [alpha]
+        im.putpalette(palette_with_alpha_values, "RGBA")
+
+        assert_image_equal(im.convert("RGBA"), expected)