Repository: AUTOMATIC1111/stable-diffusion-webui

Issue:
[Feature Request]: Add image format selection to API
### Is there an existing issue for this?

- [X] I have searched the existing issues and checked the recent builds/commits

### What would your feature do ?

Add format selection to endpoints that return images.
Png files can get very big and add considerable latency when using api over slow connections.
Jpg files are usually much smaller and don't lose too much quality.

### Proposed workflow

`requests.post('http://127.0.0.1:7860/sdapi/v1/txt2img' , json={'prompt': 'cat', 'format': 'jpg'})`
Should return a picture of cat in jpg format instead of png.

### Additional information

_No response_


Discussion:
you can already post to `sdapi/options` and set `samples_format` and `grid_format` to `jpg`

I tried that, it still returns png.
```
requests.get("http://127.0.0.1:7860/sdapi/v1/options").json()["samples_format"]
Out[29]: 'jpg'

requests.get("http://127.0.0.1:7860/sdapi/v1/options").json()["grid_format"]
Out[30]: 'jpg'

r = requests.post("http://127.0.0.1:7860/sdapi/v1/txt2img", json={"prompt": "cat"})

base64.decodebytes(r.json()["images"][0].encode())[:10]
Out[32]: b'\x89PNG\r\n\x1a\n\x00\x00'
```
you're right, i just took a look: `encode_pil_to_base64` in `modules/api.py` always forces png.  
passing additional arg in api request would be messy as it would require to modify all endpoints.  
but it would be easy to add to one more `options`, something like `api_format` (like we already have `samples_format`) so its only used within encode function.  

That would be great, or just make samples_format also apply to api.
Do I need to make a separate issue for this, or edit this one, or leave it as it is?
leave it as-is, i'll do it...

Resolving patch:
diff --git a/modules/api/api.py b/modules/api/api.py
--- a/modules/api/api.py
+++ b/modules/api/api.py
@@ -22,6 +22,8 @@
 from modules.realesrgan_model import get_realesrgan_models
 from modules import devices
 from typing import List
+import piexif
+import piexif.helper
 
 def upscaler_to_index(name: str):
     try:
@@ -56,18 +58,30 @@ def decode_base64_to_image(encoding):
 def encode_pil_to_base64(image):
     with io.BytesIO() as output_bytes:
 
-        # Copy any text-only metadata
-        use_metadata = False
-        metadata = PngImagePlugin.PngInfo()
-        for key, value in image.info.items():
-            if isinstance(key, str) and isinstance(value, str):
-                metadata.add_text(key, value)
-                use_metadata = True
+        if opts.samples_format.lower() == 'png':
+            use_metadata = False
+            metadata = PngImagePlugin.PngInfo()
+            for key, value in image.info.items():
+                if isinstance(key, str) and isinstance(value, str):
+                    metadata.add_text(key, value)
+                    use_metadata = True
+            image.save(output_bytes, format="PNG", pnginfo=(metadata if use_metadata else None), quality=opts.jpeg_quality)
+
+        elif opts.samples_format.lower() in ("jpg", "jpeg", "webp"):
+            parameters = image.info.get('parameters', None)
+            exif_bytes = piexif.dump({
+                "Exif": { piexif.ExifIFD.UserComment: piexif.helper.UserComment.dump(parameters or "", encoding="unicode") }
+            })
+            if opts.samples_format.lower() in ("jpg", "jpeg"):
+                image.save(output_bytes, format="JPEG", exif = exif_bytes, quality=opts.jpeg_quality)
+            else:
+                image.save(output_bytes, format="WEBP", exif = exif_bytes, quality=opts.jpeg_quality)
+
+        else:
+            raise HTTPException(status_code=500, detail="Invalid image format")
 
-        image.save(
-            output_bytes, "PNG", pnginfo=(metadata if use_metadata else None)
-        )
         bytes_data = output_bytes.getvalue()
+
     return base64.b64encode(bytes_data)
 
 def api_middleware(app: FastAPI):


Test patch: