Repository: python-pillow/Pillow

Issue:
importing PIL.PngImagePlugin breaks Image.registered_extensions()
### What are your OS, Python and Pillow versions?

* OS: Windows 10
* Python: 3.9.13
* Pillow: 9.3.0

```python
from PIL import Image
print(Image.registered_extensions())
```
The code above outputs, all what I expected.
`{'.blp': 'BLP', '.bmp': 'BMP', '.dib': 'DIB', '.bufr': 'BUFR', '.cur': 'CUR', '.pcx': 'PCX', '.dcx': 'DCX', '.dds': 'DDS', '.ps': 'EPS', '.eps': 'EPS', '.fit': 'FITS', '.fits': 'FITS', '.fli': 'FLI', '.flc': 'FLI', '.ftc': 'FTEX', '.ftu': 'FTEX', '.gbr': 'GBR', '.gif': 'GIF', '.grib': 'GRIB', '.h5': 'HDF5', '.hdf': 'HDF5', '.png': 'PNG', '.apng': 'PNG', '.jp2': 'JPEG2000', '.j2k': 'JPEG2000', '.jpc': 'JPEG2000', '.jpf': 'JPEG2000', '.jpx': 'JPEG2000', '.j2c': 'JPEG2000', '.icns': 'ICNS', '.ico': 'ICO', '.im': 'IM', '.iim': 'IPTC', '.tif': 'TIFF', '.tiff': 'TIFF', '.jfif': 'JPEG', '.jpe': 'JPEG', '.jpg': 'JPEG', '.jpeg': 'JPEG', '.mpg': 'MPEG', '.mpeg': 'MPEG', '.mpo': 'MPO', '.msp': 'MSP', '.palm': 'PALM', '.pcd': 'PCD', '.pdf': 'PDF', '.pxr': 'PIXAR', '.pbm': 'PPM', '.pgm': 'PPM', '.ppm': 'PPM', '.pnm': 'PPM', '.psd': 'PSD', '.bw': 'SGI', '.rgb': 'SGI', '.rgba': 'SGI', '.sgi': 'SGI', '.ras': 'SUN', '.tga': 'TGA', '.icb': 'TGA', '.vda': 'TGA', '.vst': 'TGA', '.webp': 'WEBP', '.wmf': 'WMF', '.emf': 'WMF', '.xbm': 'XBM', '.xpm': 'XPM'}`

However, if I try to import `PIL.PngImagePlugin`, it will override the entire list and leave with ONLY PNG. I do not think this should be the behaviour because no where in the doc says just importing it will remove existing registered extensions.
```python
from PIL import Image
import PIL.PngImagePlugin
print(Image.registered_extensions())
```
The code above outputs:
`{'.png': 'PNG', '.apng': 'PNG'}`

What's even more interesting is, if I call `Image.registered_extensions()` before I import `PIL.PngImagePlugin`, it works as expected, the existing list is untouched. This should be the behaviour even if I do not call `Image.registered_extensions()` before importing.
```python
from PIL import Image
print(Image.registered_extensions())
import PIL.PngImagePlugin
print(Image.registered_extensions())
```
The code above outputs:
`{'.blp': 'BLP', '.bmp': 'BMP', '.dib': 'DIB', '.bufr': 'BUFR', '.cur': 'CUR', '.pcx': 'PCX', '.dcx': 'DCX', '.dds': 'DDS', '.ps': 'EPS', '.eps': 'EPS', '.fit': 'FITS', '.fits': 'FITS', '.fli': 'FLI', '.flc': 'FLI', '.ftc': 'FTEX', '.ftu': 'FTEX', '.gbr': 'GBR', '.gif': 'GIF', '.grib': 'GRIB', '.h5': 'HDF5', '.hdf': 'HDF5', '.png': 'PNG', '.apng': 'PNG', '.jp2': 'JPEG2000', '.j2k': 'JPEG2000', '.jpc': 'JPEG2000', '.jpf': 'JPEG2000', '.jpx': 'JPEG2000', '.j2c': 'JPEG2000', '.icns': 'ICNS', '.ico': 'ICO', '.im': 'IM', '.iim': 'IPTC', '.tif': 'TIFF', '.tiff': 'TIFF', '.jfif': 'JPEG', '.jpe': 'JPEG', '.jpg': 'JPEG', '.jpeg': 'JPEG', '.mpg': 'MPEG', '.mpeg': 'MPEG', '.mpo': 'MPO', '.msp': 'MSP', '.palm': 'PALM', '.pcd': 'PCD', '.pdf': 'PDF', '.pxr': 'PIXAR', '.pbm': 'PPM', '.pgm': 'PPM', '.ppm': 'PPM', '.pnm': 'PPM', '.psd': 'PSD', '.bw': 'SGI', '.rgb': 'SGI', '.rgba': 'SGI', '.sgi': 'SGI', '.ras': 'SUN', '.tga': 'TGA', '.icb': 'TGA', '.vda': 'TGA', '.vst': 'TGA', '.webp': 'WEBP', '.wmf': 'WMF', '.emf': 'WMF', '.xbm': 'XBM', '.xpm': 'XPM'}
{'.blp': 'BLP', '.bmp': 'BMP', '.dib': 'DIB', '.bufr': 'BUFR', '.cur': 'CUR', '.pcx': 'PCX', '.dcx': 'DCX', '.dds': 'DDS', '.ps': 'EPS', '.eps': 'EPS', '.fit': 'FITS', '.fits': 'FITS', '.fli': 'FLI', '.flc': 'FLI', '.ftc': 'FTEX', '.ftu': 'FTEX', '.gbr': 'GBR', '.gif': 'GIF', '.grib': 'GRIB', '.h5': 'HDF5', '.hdf': 'HDF5', '.png': 'PNG', '.apng': 'PNG', '.jp2': 'JPEG2000', '.j2k': 'JPEG2000', '.jpc': 'JPEG2000', '.jpf': 'JPEG2000', '.jpx': 'JPEG2000', '.j2c': 'JPEG2000', '.icns': 'ICNS', '.ico': 'ICO', '.im': 'IM', '.iim': 'IPTC', '.tif': 'TIFF', '.tiff': 'TIFF', '.jfif': 'JPEG', '.jpe': 'JPEG', '.jpg': 'JPEG', '.jpeg': 'JPEG', '.mpg': 'MPEG', '.mpeg': 'MPEG', '.mpo': 'MPO', '.msp': 'MSP', '.palm': 'PALM', '.pcd': 'PCD', '.pdf': 'PDF', '.pxr': 'PIXAR', '.pbm': 'PPM', '.pgm': 'PPM', '.ppm': 'PPM', '.pnm': 'PPM', '.psd': 'PSD', '.bw': 'SGI', '.rgb': 'SGI', '.rgba': 'SGI', '.sgi': 'SGI', '.ras': 'SUN', '.tga': 'TGA', '.icb': 'TGA', '.vda': 'TGA', '.vst': 'TGA', '.webp': 'WEBP', '.wmf': 'WMF', '.emf': 'WMF', '.xbm': 'XBM', '.xpm': 'XPM'}`

I've done some simple troubleshooting and found that https://github.com/python-pillow/Pillow/blob/d594f4cb8dc47fb0c69ae58d9fff86faae4515bd/src/PIL/PngImagePlugin.py#L1453 causes it. If I `print(Image.registered_extensions())` before that line, everything is good, but after that line, it overrides.

This directly causes https://github.com/gradio-app/gradio/issues/2843 https://github.com/AUTOMATIC1111/stable-diffusion-webui/issues/5603 https://github.com/AUTOMATIC1111/stable-diffusion-webui/issues/5664 and I believe many other downstream uses.


Discussion:
Can verify that this happens also on my Win10 machine on Python 3.10 as well as Ubuntu on Python 3.8 (running in WSL2).
So when you get the registered extensions, if nothing has been registered, it first initializes everything. But if something has been registered (like when you import the `PngImagePlugin`), then it just returns that instead of initializing everything.

https://github.com/python-pillow/Pillow/blob/7f6fe3c28728f0e68dba58b6ea9843de0b00ca3b/src/PIL/Image.py#L3416-L3423
So
```python
from PIL import Image
Image.init()
```
will load everything.

Resolving patch:
diff --git a/src/PIL/Image.py b/src/PIL/Image.py
--- a/src/PIL/Image.py
+++ b/src/PIL/Image.py
@@ -3417,8 +3417,7 @@ def registered_extensions():
     Returns a dictionary containing all file extensions belonging
     to registered plugins
     """
-    if not EXTENSION:
-        init()
+    init()
     return EXTENSION
 
 


Test patch:
diff --git a/Tests/test_image.py b/Tests/test_image.py
--- a/Tests/test_image.py
+++ b/Tests/test_image.py
@@ -401,8 +401,6 @@ def test_alpha_inplace(self):
     def test_registered_extensions_uninitialized(self):
         # Arrange
         Image._initialized = 0
-        extension = Image.EXTENSION
-        Image.EXTENSION = {}
 
         # Act
         Image.registered_extensions()
@@ -410,10 +408,6 @@ def test_registered_extensions_uninitialized(self):
         # Assert
         assert Image._initialized == 2
 
-        # Restore the original state and assert
-        Image.EXTENSION = extension
-        assert Image.EXTENSION
-
     def test_registered_extensions(self):
         # Arrange
         # Open an image to trigger plugin registration