Repository: python-pillow/Pillow

Issue:
RGBA Image.resize with Nearest Neighbor Interpolation introduces new RGB Values
### What did you do?

Resizing an RGBA image with Image.resize and nearest neighbor interpolation.

### What did you expect to happen?

Image resized to given size, no new RGB values introduced.

### What actually happened?

New RGB values introduced.

### What are your OS, Python and Pillow versions?

* OS: Linux
* Python: 3.8.6
* Pillow: 6.2.1

### Python Example

```python
import numpy as np
from PIL import Image

image = np.asarray([[[1, 1, 0, 128]], [[2, 2, 0, 64]]], dtype=np.uint8)

print("Input")
print(image)
print("")

image = Image.fromarray(image)
image = image.resize((1, 1), Image.NEAREST)
image = np.asarray(image)

print("Output")
print(image)
```

```
Input
[[[  1   1   0 128]]
 [[  2   2   0  64]]]

Output
[[[ 3  3  0 64]]]
```




Discussion:
This may not be related, but Pillow 6.2.1 is a bit old. Is there any reason you haven't upgraded to a newer Pillow version?
The version is fixed for the project I am working on but it's also happening with Pillow 8.1.0. Maybe issue #4516 is related?
You'll likely think this is a basic question, but could you link me to something explaining that nearest neighbor interpolation shouldn't introduce new values?
> You'll likely think this is a basic question, but could you link me to something explaining that nearest neighbor interpolation shouldn't introduce new values?

From https://pillow.readthedocs.io/en/stable/handbook/concepts.html#PIL.Image.NEAREST:

> Pick one nearest pixel from the input image. Ignore all other input pixels.

I would interpret that as meaning that each pixel in the output will be equal to one of the original pixels, i.e. not introducing new values.

Resolving patch:
diff --git a/src/PIL/Image.py b/src/PIL/Image.py
--- a/src/PIL/Image.py
+++ b/src/PIL/Image.py
@@ -1910,7 +1910,7 @@ def resize(self, size, resample=BICUBIC, box=None, reducing_gap=None):
         if self.mode in ("1", "P"):
             resample = NEAREST
 
-        if self.mode in ["LA", "RGBA"]:
+        if self.mode in ["LA", "RGBA"] and resample != NEAREST:
             im = self.convert(self.mode[:-1] + "a")
             im = im.resize(size, resample, box)
             return im.convert(self.mode)
@@ -2394,14 +2394,14 @@ def getdata(self):
         :returns: An :py:class:`~PIL.Image.Image` object.
         """
 
-        if self.mode == "LA":
+        if self.mode == "LA" and resample != NEAREST:
             return (
                 self.convert("La")
                 .transform(size, method, data, resample, fill, fillcolor)
                 .convert("LA")
             )
 
-        if self.mode == "RGBA":
+        if self.mode == "RGBA" and resample != NEAREST:
             return (
                 self.convert("RGBa")
                 .transform(size, method, data, resample, fill, fillcolor)


Test patch:
diff --git a/Tests/test_image_transform.py b/Tests/test_image_transform.py
--- a/Tests/test_image_transform.py
+++ b/Tests/test_image_transform.py
@@ -143,6 +143,41 @@ def op(im, sz):
 
         self._test_alpha_premult(op)
 
+    def _test_nearest(self, op, mode):
+        # create white image with half transparent,
+        # do op,
+        # the image should remain white with half transparent
+        transparent, opaque = {
+            "RGBA": ((255, 255, 255, 0), (255, 255, 255, 255)),
+            "LA": ((255, 0), (255, 255)),
+        }[mode]
+        im = Image.new(mode, (10, 10), transparent)
+        im2 = Image.new(mode, (5, 10), opaque)
+        im.paste(im2, (0, 0))
+
+        im = op(im, (40, 10))
+
+        colors = im.getcolors()
+        assert colors == [
+            (20 * 10, opaque),
+            (20 * 10, transparent),
+        ]
+
+    @pytest.mark.parametrize("mode", ("RGBA", "LA"))
+    def test_nearest_resize(self, mode):
+        def op(im, sz):
+            return im.resize(sz, Image.NEAREST)
+
+        self._test_nearest(op, mode)
+
+    @pytest.mark.parametrize("mode", ("RGBA", "LA"))
+    def test_nearest_transform(self, mode):
+        def op(im, sz):
+            (w, h) = im.size
+            return im.transform(sz, Image.EXTENT, (0, 0, w, h), Image.NEAREST)
+
+        self._test_nearest(op, mode)
+
     def test_blank_fill(self):
         # attempting to hit
         # https://github.com/python-pillow/Pillow/issues/254 reported