We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Unhandled value out of range
## Sentry link
<!-- The public (aka "share") Sentry issue link. -->
https://sentry.io/share/issue/7dd836d27daa41dfa59dfbdf39a40d51/

## Description
<!-- Example: We are trying to access property foo of ImportantClass but the instance is null. -->
<!-- Include any additional information you may have, including potential remedies if any come to mind, and the general context of the code (what causes it to run in the app).  -->

We need to capture and handle this error to avoid returning a 500 error in the link below.

> 'l' format requires -2147483648 <= number <= 2147483647

Originates from this fragment of code:

https://github.com/WordPress/openverse-api/blob/81b7860e2662f4b135919da0728eea194f15c260/api/catalog/api/views/image_views.py#L125-L130

<!-- Mention whether this is a known regression, i.e., the feature used to work and now does not.  -->

## Reproduction
<!-- Share the steps to reproduce the issue, if you were able to, OR a note sharing that you tried to reproduce but weren’t able to. -->
1. Go to https://api-dev.openverse.engineering/v1/images/6c855680-b426-40f1-adc6-f61f434d0be9/watermark/

## Aditional context
Related to #483.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `api/catalog/api/views/image_views.py`
Content:
```
1 import io
2 
3 from django.conf import settings
4 from django.http.response import FileResponse, HttpResponse
5 from django.utils.decorators import method_decorator
6 from rest_framework.decorators import action
7 from rest_framework.exceptions import NotFound
8 from rest_framework.response import Response
9 
10 import piexif
11 import requests
12 from drf_yasg.utils import swagger_auto_schema
13 from PIL import Image as PILImage
14 
15 from catalog.api.constants.media_types import IMAGE_TYPE
16 from catalog.api.docs.image_docs import (
17     ImageComplain,
18     ImageDetail,
19     ImageOembed,
20     ImageRelated,
21     ImageSearch,
22     ImageStats,
23     ImageThumbnail,
24 )
25 from catalog.api.models import Image
26 from catalog.api.serializers.image_serializers import (
27     ImageReportRequestSerializer,
28     ImageSearchRequestSerializer,
29     ImageSerializer,
30     OembedRequestSerializer,
31     OembedSerializer,
32     WatermarkRequestSerializer,
33 )
34 from catalog.api.serializers.media_serializers import MediaThumbnailRequestSerializer
35 from catalog.api.utils.exceptions import get_api_exception
36 from catalog.api.utils.throttle import (
37     AnonThumbnailRateThrottle,
38     OAuth2IdThumbnailRateThrottle,
39 )
40 from catalog.api.utils.watermark import watermark
41 from catalog.api.views.media_views import MediaViewSet
42 
43 
44 @method_decorator(swagger_auto_schema(**ImageSearch.swagger_setup), "list")
45 @method_decorator(swagger_auto_schema(**ImageStats.swagger_setup), "stats")
46 @method_decorator(swagger_auto_schema(**ImageDetail.swagger_setup), "retrieve")
47 @method_decorator(swagger_auto_schema(**ImageRelated.swagger_setup), "related")
48 @method_decorator(swagger_auto_schema(**ImageComplain.swagger_setup), "report")
49 @method_decorator(swagger_auto_schema(**ImageOembed.swagger_setup), "oembed")
50 @method_decorator(swagger_auto_schema(**ImageThumbnail.swagger_setup), "thumbnail")
51 @method_decorator(swagger_auto_schema(auto_schema=None), "watermark")
52 class ImageViewSet(MediaViewSet):
53     """
54     Viewset for all endpoints pertaining to images.
55     """
56 
57     model_class = Image
58     query_serializer_class = ImageSearchRequestSerializer
59     default_index = settings.MEDIA_INDEX_MAPPING[IMAGE_TYPE]
60     qa_index = "search-qa-image"
61 
62     serializer_class = ImageSerializer
63 
64     OEMBED_HEADERS = {
65         "User-Agent": settings.OUTBOUND_USER_AGENT_TEMPLATE.format(purpose="OEmbed"),
66     }
67 
68     # Extra actions
69 
70     @action(
71         detail=False,
72         url_path="oembed",
73         url_name="oembed",
74         serializer_class=OembedSerializer,
75     )
76     def oembed(self, request, *_, **__):
77         params = OembedRequestSerializer(data=request.query_params)
78         params.is_valid(raise_exception=True)
79 
80         context = self.get_serializer_context()
81 
82         url = params.validated_data["url"]
83         identifier = url.rsplit("/", 1)[1]
84         try:
85             image = self.get_queryset().get(identifier=identifier)
86         except Image.DoesNotExist:
87             return get_api_exception("Could not find image.", 404)
88         if not (image.height and image.width):
89             image_file = requests.get(image.url, headers=self.OEMBED_HEADERS)
90             width, height = PILImage.open(io.BytesIO(image_file.content)).size
91             context |= {
92                 "width": width,
93                 "height": height,
94             }
95 
96         serializer = self.get_serializer(image, context=context)
97         return Response(data=serializer.data)
98 
99     @action(
100         detail=True,
101         url_path="thumb",
102         url_name="thumb",
103         serializer_class=MediaThumbnailRequestSerializer,
104         throttle_classes=[AnonThumbnailRateThrottle, OAuth2IdThumbnailRateThrottle],
105     )
106     def thumbnail(self, request, *_, **__):
107         image = self.get_object()
108 
109         image_url = image.url
110         if not image_url:
111             raise get_api_exception("Could not find image.", 404)
112 
113         return super().thumbnail(image_url, request)
114 
115     @action(detail=True, url_path="watermark", url_name="watermark")
116     def watermark(self, request, *_, **__):
117         if not settings.WATERMARK_ENABLED:
118             raise NotFound("The watermark feature is currently disabled.")
119 
120         params = WatermarkRequestSerializer(data=request.query_params)
121         params.is_valid(raise_exception=True)
122 
123         image = self.get_object()
124         image_url = image.url
125         image_info = {
126             attr: getattr(image, attr)
127             for attr in ["title", "creator", "license", "license_version"]
128         }
129 
130         # Create the actual watermarked image.
131         watermarked, exif = watermark(image_url, image_info, params.data["watermark"])
132         # Re-insert EXIF metadata.
133         if exif:
134             exif_bytes = piexif.dump(exif)
135         else:
136             exif_bytes = None
137         img_bytes = io.BytesIO()
138         self._save_wrapper(watermarked, exif_bytes, img_bytes)
139 
140         if params.data["embed_metadata"]:
141             # Embed ccREL metadata with XMP.
142             work_properties = {
143                 "creator": image.creator,
144                 "license_url": image.license_url,
145                 "attribution": image.attribution,
146                 "work_landing_page": image.foreign_landing_url,
147                 "identifier": str(image.identifier),
148             }
149 
150             # Import inside a function to allow server run without Exempi library
151             import libxmp
152 
153             from catalog.api.utils import ccrel
154 
155             try:
156                 with_xmp = ccrel.embed_xmp_bytes(img_bytes, work_properties)
157                 return FileResponse(with_xmp, content_type="image/jpeg")
158             except (libxmp.XMPError, AttributeError):
159                 # Just send the EXIF-ified file if libxmp fails to add metadata
160                 response = HttpResponse(content_type="image/jpeg")
161                 self._save_wrapper(watermarked, exif_bytes, response)
162                 return response
163         else:
164             response = HttpResponse(img_bytes, content_type="image/jpeg")
165             self._save_wrapper(watermarked, exif_bytes, response)
166             return response
167 
168     @action(
169         detail=True,
170         methods=["post"],
171         serializer_class=ImageReportRequestSerializer,
172     )
173     def report(self, *args, **kwargs):
174         return super().report(*args, **kwargs)
175 
176     # Helper functions
177 
178     @staticmethod
179     def _save_wrapper(pil_img, exif_bytes, destination):
180         """
181         PIL crashes if exif_bytes=None, so we have to wrap it to avoid littering
182         the code with branches.
183         """
184         if exif_bytes:
185             pil_img.save(destination, "jpeg", exif=exif_bytes)
186         else:
187             pil_img.save(destination, "jpeg")
188
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/api/catalog/api/views/image_views.py b/api/catalog/api/views/image_views.py
--- a/api/catalog/api/views/image_views.py
+++ b/api/catalog/api/views/image_views.py
@@ -1,4 +1,5 @@
 import io
+import struct
 
 from django.conf import settings
 from django.http.response import FileResponse, HttpResponse
@@ -131,7 +132,14 @@
         watermarked, exif = watermark(image_url, image_info, params.data["watermark"])
         # Re-insert EXIF metadata.
         if exif:
-            exif_bytes = piexif.dump(exif)
+            # piexif dump raises InvalidImageDataError which is a child class
+            # of ValueError, and a struct error when the value is not
+            # between -2147483648 and 2147483647
+            # https://github.com/WordPress/openverse-api/issues/849
+            try:
+                exif_bytes = piexif.dump(exif)
+            except (struct.error, ValueError):
+                exif_bytes = None
         else:
             exif_bytes = None
         img_bytes = io.BytesIO()

{"golden_diff": "diff --git a/api/catalog/api/views/image_views.py b/api/catalog/api/views/image_views.py\n--- a/api/catalog/api/views/image_views.py\n+++ b/api/catalog/api/views/image_views.py\n@@ -1,4 +1,5 @@\n import io\n+import struct\n \n from django.conf import settings\n from django.http.response import FileResponse, HttpResponse\n@@ -131,7 +132,14 @@\n         watermarked, exif = watermark(image_url, image_info, params.data[\"watermark\"])\n         # Re-insert EXIF metadata.\n         if exif:\n-            exif_bytes = piexif.dump(exif)\n+            # piexif dump raises InvalidImageDataError which is a child class\n+            # of ValueError, and a struct error when the value is not\n+            # between -2147483648 and 2147483647\n+            # https://github.com/WordPress/openverse-api/issues/849\n+            try:\n+                exif_bytes = piexif.dump(exif)\n+            except (struct.error, ValueError):\n+                exif_bytes = None\n         else:\n             exif_bytes = None\n         img_bytes = io.BytesIO()\n", "issue": "Unhandled value out of range\n## Sentry link\r\n<!-- The public (aka \"share\") Sentry issue link. -->\r\nhttps://sentry.io/share/issue/7dd836d27daa41dfa59dfbdf39a40d51/\r\n\r\n## Description\r\n<!-- Example: We are trying to access property foo of ImportantClass but the instance is null. -->\r\n<!-- Include any additional information you may have, including potential remedies if any come to mind, and the general context of the code (what causes it to run in the app).  -->\r\n\r\nWe need to capture and handle this error to avoid returning a 500 error in the link below.\r\n\r\n> 'l' format requires -2147483648 <= number <= 2147483647\r\n\r\nOriginates from this fragment of code:\r\n\r\nhttps://github.com/WordPress/openverse-api/blob/81b7860e2662f4b135919da0728eea194f15c260/api/catalog/api/views/image_views.py#L125-L130\r\n\r\n<!-- Mention whether this is a known regression, i.e., the feature used to work and now does not.  -->\r\n\r\n## Reproduction\r\n<!-- Share the steps to reproduce the issue, if you were able to, OR a note sharing that you tried to reproduce but weren\u2019t able to. -->\r\n1. Go to https://api-dev.openverse.engineering/v1/images/6c855680-b426-40f1-adc6-f61f434d0be9/watermark/\r\n\r\n## Aditional context\r\nRelated to #483.\r\n\n", "before_files": [{"content": "import io\n\nfrom django.conf import settings\nfrom django.http.response import FileResponse, HttpResponse\nfrom django.utils.decorators import method_decorator\nfrom rest_framework.decorators import action\nfrom rest_framework.exceptions import NotFound\nfrom rest_framework.response import Response\n\nimport piexif\nimport requests\nfrom drf_yasg.utils import swagger_auto_schema\nfrom PIL import Image as PILImage\n\nfrom catalog.api.constants.media_types import IMAGE_TYPE\nfrom catalog.api.docs.image_docs import (\n    ImageComplain,\n    ImageDetail,\n    ImageOembed,\n    ImageRelated,\n    ImageSearch,\n    ImageStats,\n    ImageThumbnail,\n)\nfrom catalog.api.models import Image\nfrom catalog.api.serializers.image_serializers import (\n    ImageReportRequestSerializer,\n    ImageSearchRequestSerializer,\n    ImageSerializer,\n    OembedRequestSerializer,\n    OembedSerializer,\n    WatermarkRequestSerializer,\n)\nfrom catalog.api.serializers.media_serializers import MediaThumbnailRequestSerializer\nfrom catalog.api.utils.exceptions import get_api_exception\nfrom catalog.api.utils.throttle import (\n    AnonThumbnailRateThrottle,\n    OAuth2IdThumbnailRateThrottle,\n)\nfrom catalog.api.utils.watermark import watermark\nfrom catalog.api.views.media_views import MediaViewSet\n\n\n@method_decorator(swagger_auto_schema(**ImageSearch.swagger_setup), \"list\")\n@method_decorator(swagger_auto_schema(**ImageStats.swagger_setup), \"stats\")\n@method_decorator(swagger_auto_schema(**ImageDetail.swagger_setup), \"retrieve\")\n@method_decorator(swagger_auto_schema(**ImageRelated.swagger_setup), \"related\")\n@method_decorator(swagger_auto_schema(**ImageComplain.swagger_setup), \"report\")\n@method_decorator(swagger_auto_schema(**ImageOembed.swagger_setup), \"oembed\")\n@method_decorator(swagger_auto_schema(**ImageThumbnail.swagger_setup), \"thumbnail\")\n@method_decorator(swagger_auto_schema(auto_schema=None), \"watermark\")\nclass ImageViewSet(MediaViewSet):\n    \"\"\"\n    Viewset for all endpoints pertaining to images.\n    \"\"\"\n\n    model_class = Image\n    query_serializer_class = ImageSearchRequestSerializer\n    default_index = settings.MEDIA_INDEX_MAPPING[IMAGE_TYPE]\n    qa_index = \"search-qa-image\"\n\n    serializer_class = ImageSerializer\n\n    OEMBED_HEADERS = {\n        \"User-Agent\": settings.OUTBOUND_USER_AGENT_TEMPLATE.format(purpose=\"OEmbed\"),\n    }\n\n    # Extra actions\n\n    @action(\n        detail=False,\n        url_path=\"oembed\",\n        url_name=\"oembed\",\n        serializer_class=OembedSerializer,\n    )\n    def oembed(self, request, *_, **__):\n        params = OembedRequestSerializer(data=request.query_params)\n        params.is_valid(raise_exception=True)\n\n        context = self.get_serializer_context()\n\n        url = params.validated_data[\"url\"]\n        identifier = url.rsplit(\"/\", 1)[1]\n        try:\n            image = self.get_queryset().get(identifier=identifier)\n        except Image.DoesNotExist:\n            return get_api_exception(\"Could not find image.\", 404)\n        if not (image.height and image.width):\n            image_file = requests.get(image.url, headers=self.OEMBED_HEADERS)\n            width, height = PILImage.open(io.BytesIO(image_file.content)).size\n            context |= {\n                \"width\": width,\n                \"height\": height,\n            }\n\n        serializer = self.get_serializer(image, context=context)\n        return Response(data=serializer.data)\n\n    @action(\n        detail=True,\n        url_path=\"thumb\",\n        url_name=\"thumb\",\n        serializer_class=MediaThumbnailRequestSerializer,\n        throttle_classes=[AnonThumbnailRateThrottle, OAuth2IdThumbnailRateThrottle],\n    )\n    def thumbnail(self, request, *_, **__):\n        image = self.get_object()\n\n        image_url = image.url\n        if not image_url:\n            raise get_api_exception(\"Could not find image.\", 404)\n\n        return super().thumbnail(image_url, request)\n\n    @action(detail=True, url_path=\"watermark\", url_name=\"watermark\")\n    def watermark(self, request, *_, **__):\n        if not settings.WATERMARK_ENABLED:\n            raise NotFound(\"The watermark feature is currently disabled.\")\n\n        params = WatermarkRequestSerializer(data=request.query_params)\n        params.is_valid(raise_exception=True)\n\n        image = self.get_object()\n        image_url = image.url\n        image_info = {\n            attr: getattr(image, attr)\n            for attr in [\"title\", \"creator\", \"license\", \"license_version\"]\n        }\n\n        # Create the actual watermarked image.\n        watermarked, exif = watermark(image_url, image_info, params.data[\"watermark\"])\n        # Re-insert EXIF metadata.\n        if exif:\n            exif_bytes = piexif.dump(exif)\n        else:\n            exif_bytes = None\n        img_bytes = io.BytesIO()\n        self._save_wrapper(watermarked, exif_bytes, img_bytes)\n\n        if params.data[\"embed_metadata\"]:\n            # Embed ccREL metadata with XMP.\n            work_properties = {\n                \"creator\": image.creator,\n                \"license_url\": image.license_url,\n                \"attribution\": image.attribution,\n                \"work_landing_page\": image.foreign_landing_url,\n                \"identifier\": str(image.identifier),\n            }\n\n            # Import inside a function to allow server run without Exempi library\n            import libxmp\n\n            from catalog.api.utils import ccrel\n\n            try:\n                with_xmp = ccrel.embed_xmp_bytes(img_bytes, work_properties)\n                return FileResponse(with_xmp, content_type=\"image/jpeg\")\n            except (libxmp.XMPError, AttributeError):\n                # Just send the EXIF-ified file if libxmp fails to add metadata\n                response = HttpResponse(content_type=\"image/jpeg\")\n                self._save_wrapper(watermarked, exif_bytes, response)\n                return response\n        else:\n            response = HttpResponse(img_bytes, content_type=\"image/jpeg\")\n            self._save_wrapper(watermarked, exif_bytes, response)\n            return response\n\n    @action(\n        detail=True,\n        methods=[\"post\"],\n        serializer_class=ImageReportRequestSerializer,\n    )\n    def report(self, *args, **kwargs):\n        return super().report(*args, **kwargs)\n\n    # Helper functions\n\n    @staticmethod\n    def _save_wrapper(pil_img, exif_bytes, destination):\n        \"\"\"\n        PIL crashes if exif_bytes=None, so we have to wrap it to avoid littering\n        the code with branches.\n        \"\"\"\n        if exif_bytes:\n            pil_img.save(destination, \"jpeg\", exif=exif_bytes)\n        else:\n            pil_img.save(destination, \"jpeg\")\n", "path": "api/catalog/api/views/image_views.py"}], "after_files": [{"content": "import io\nimport struct\n\nfrom django.conf import settings\nfrom django.http.response import FileResponse, HttpResponse\nfrom django.utils.decorators import method_decorator\nfrom rest_framework.decorators import action\nfrom rest_framework.exceptions import NotFound\nfrom rest_framework.response import Response\n\nimport piexif\nimport requests\nfrom drf_yasg.utils import swagger_auto_schema\nfrom PIL import Image as PILImage\n\nfrom catalog.api.constants.media_types import IMAGE_TYPE\nfrom catalog.api.docs.image_docs import (\n    ImageComplain,\n    ImageDetail,\n    ImageOembed,\n    ImageRelated,\n    ImageSearch,\n    ImageStats,\n    ImageThumbnail,\n)\nfrom catalog.api.models import Image\nfrom catalog.api.serializers.image_serializers import (\n    ImageReportRequestSerializer,\n    ImageSearchRequestSerializer,\n    ImageSerializer,\n    OembedRequestSerializer,\n    OembedSerializer,\n    WatermarkRequestSerializer,\n)\nfrom catalog.api.serializers.media_serializers import MediaThumbnailRequestSerializer\nfrom catalog.api.utils.exceptions import get_api_exception\nfrom catalog.api.utils.throttle import (\n    AnonThumbnailRateThrottle,\n    OAuth2IdThumbnailRateThrottle,\n)\nfrom catalog.api.utils.watermark import watermark\nfrom catalog.api.views.media_views import MediaViewSet\n\n\n@method_decorator(swagger_auto_schema(**ImageSearch.swagger_setup), \"list\")\n@method_decorator(swagger_auto_schema(**ImageStats.swagger_setup), \"stats\")\n@method_decorator(swagger_auto_schema(**ImageDetail.swagger_setup), \"retrieve\")\n@method_decorator(swagger_auto_schema(**ImageRelated.swagger_setup), \"related\")\n@method_decorator(swagger_auto_schema(**ImageComplain.swagger_setup), \"report\")\n@method_decorator(swagger_auto_schema(**ImageOembed.swagger_setup), \"oembed\")\n@method_decorator(swagger_auto_schema(**ImageThumbnail.swagger_setup), \"thumbnail\")\n@method_decorator(swagger_auto_schema(auto_schema=None), \"watermark\")\nclass ImageViewSet(MediaViewSet):\n    \"\"\"\n    Viewset for all endpoints pertaining to images.\n    \"\"\"\n\n    model_class = Image\n    query_serializer_class = ImageSearchRequestSerializer\n    default_index = settings.MEDIA_INDEX_MAPPING[IMAGE_TYPE]\n    qa_index = \"search-qa-image\"\n\n    serializer_class = ImageSerializer\n\n    OEMBED_HEADERS = {\n        \"User-Agent\": settings.OUTBOUND_USER_AGENT_TEMPLATE.format(purpose=\"OEmbed\"),\n    }\n\n    # Extra actions\n\n    @action(\n        detail=False,\n        url_path=\"oembed\",\n        url_name=\"oembed\",\n        serializer_class=OembedSerializer,\n    )\n    def oembed(self, request, *_, **__):\n        params = OembedRequestSerializer(data=request.query_params)\n        params.is_valid(raise_exception=True)\n\n        context = self.get_serializer_context()\n\n        url = params.validated_data[\"url\"]\n        identifier = url.rsplit(\"/\", 1)[1]\n        try:\n            image = self.get_queryset().get(identifier=identifier)\n        except Image.DoesNotExist:\n            return get_api_exception(\"Could not find image.\", 404)\n        if not (image.height and image.width):\n            image_file = requests.get(image.url, headers=self.OEMBED_HEADERS)\n            width, height = PILImage.open(io.BytesIO(image_file.content)).size\n            context |= {\n                \"width\": width,\n                \"height\": height,\n            }\n\n        serializer = self.get_serializer(image, context=context)\n        return Response(data=serializer.data)\n\n    @action(\n        detail=True,\n        url_path=\"thumb\",\n        url_name=\"thumb\",\n        serializer_class=MediaThumbnailRequestSerializer,\n        throttle_classes=[AnonThumbnailRateThrottle, OAuth2IdThumbnailRateThrottle],\n    )\n    def thumbnail(self, request, *_, **__):\n        image = self.get_object()\n\n        image_url = image.url\n        if not image_url:\n            raise get_api_exception(\"Could not find image.\", 404)\n\n        return super().thumbnail(image_url, request)\n\n    @action(detail=True, url_path=\"watermark\", url_name=\"watermark\")\n    def watermark(self, request, *_, **__):\n        if not settings.WATERMARK_ENABLED:\n            raise NotFound(\"The watermark feature is currently disabled.\")\n\n        params = WatermarkRequestSerializer(data=request.query_params)\n        params.is_valid(raise_exception=True)\n\n        image = self.get_object()\n        image_url = image.url\n        image_info = {\n            attr: getattr(image, attr)\n            for attr in [\"title\", \"creator\", \"license\", \"license_version\"]\n        }\n\n        # Create the actual watermarked image.\n        watermarked, exif = watermark(image_url, image_info, params.data[\"watermark\"])\n        # Re-insert EXIF metadata.\n        if exif:\n            # piexif dump raises InvalidImageDataError which is a child class\n            # of ValueError, and a struct error when the value is not\n            # between -2147483648 and 2147483647\n            # https://github.com/WordPress/openverse-api/issues/849\n            try:\n                exif_bytes = piexif.dump(exif)\n            except (struct.error, ValueError):\n                exif_bytes = None\n        else:\n            exif_bytes = None\n        img_bytes = io.BytesIO()\n        self._save_wrapper(watermarked, exif_bytes, img_bytes)\n\n        if params.data[\"embed_metadata\"]:\n            # Embed ccREL metadata with XMP.\n            work_properties = {\n                \"creator\": image.creator,\n                \"license_url\": image.license_url,\n                \"attribution\": image.attribution,\n                \"work_landing_page\": image.foreign_landing_url,\n                \"identifier\": str(image.identifier),\n            }\n\n            # Import inside a function to allow server run without Exempi library\n            import libxmp\n\n            from catalog.api.utils import ccrel\n\n            try:\n                with_xmp = ccrel.embed_xmp_bytes(img_bytes, work_properties)\n                return FileResponse(with_xmp, content_type=\"image/jpeg\")\n            except (libxmp.XMPError, AttributeError):\n                # Just send the EXIF-ified file if libxmp fails to add metadata\n                response = HttpResponse(content_type=\"image/jpeg\")\n                self._save_wrapper(watermarked, exif_bytes, response)\n                return response\n        else:\n            response = HttpResponse(img_bytes, content_type=\"image/jpeg\")\n            self._save_wrapper(watermarked, exif_bytes, response)\n            return response\n\n    @action(\n        detail=True,\n        methods=[\"post\"],\n        serializer_class=ImageReportRequestSerializer,\n    )\n    def report(self, *args, **kwargs):\n        return super().report(*args, **kwargs)\n\n    # Helper functions\n\n    @staticmethod\n    def _save_wrapper(pil_img, exif_bytes, destination):\n        \"\"\"\n        PIL crashes if exif_bytes=None, so we have to wrap it to avoid littering\n        the code with branches.\n        \"\"\"\n        if exif_bytes:\n            pil_img.save(destination, \"jpeg\", exif=exif_bytes)\n        else:\n            pil_img.save(destination, \"jpeg\")\n", "path": "api/catalog/api/views/image_views.py"}]}