Skip to content

Commit e805b24

Browse files
authored
Expand PIL image support. (#523)
* fixes#511 Change-Id: I7303becbbd6a9441c406a28e84ecc86d2fdd35bd * add gif support Change-Id: Ibc8e091c63d30626f78510156e8c024014dddcca * link to references Change-Id: I49b9ab206ade37a8a5535b21fa7fdf62a0c569d2 * describe logic Change-Id: I813e8569b91e01a0884b1c2ff75dfa84fcf4a609 * add test gif Change-Id: I1e4a62bb1e1fade244771027380b8a13f444885d * format Change-Id: Ifb93c70f8ad48dce0fd0921de0e9e117819dc55c
1 parent 32b754f commit e805b24

File tree

3 files changed

+39
-1
lines changed

3 files changed

+39
-1
lines changed

google/generativeai/types/content_types.py

+24-1
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,34 @@
7373

7474

7575
def pil_to_blob(img):
76+
# When you load an image with PIL you get a subclass of PIL.Image
77+
# The subclass knows what file type it was loaded from it has a `.format` class attribute
78+
# and the `get_format_mimetype` method. Convert these back to the same file type.
79+
#
80+
# The base image class doesn't know its file type, it just knows its mode.
81+
# RGBA converts to PNG easily, P[allet] converts to GIF, RGB to GIF.
82+
# But for anything else I'm not going to bother mapping it out (for now) let's just convert to RGB and send it.
83+
#
84+
# References:
85+
# - file formats: https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html
86+
# - image modes: https://pillow.readthedocs.io/en/stable/handbook/concepts.html#modes
87+
7688
bytesio = io.BytesIO()
77-
if isinstance(img, PIL.PngImagePlugin.PngImageFile) or img.mode == "RGBA":
89+
90+
get_mime = getattr(img, "get_format_mimetype", None)
91+
if get_mime is not None:
92+
# If the image is created from a file, convert back to the same file type.
93+
img.save(bytesio, format=img.format)
94+
mime_type = img.get_format_mimetype()
95+
elif img.mode == "RGBA":
7896
img.save(bytesio, format="PNG")
7997
mime_type = "image/png"
98+
elif img.mode == "P":
99+
img.save(bytesio, format="GIF")
100+
mime_type = "image/gif"
80101
else:
102+
if img.mode != "RGB":
103+
img = img.convert("RGB")
81104
img.save(bytesio, format="JPEG")
82105
mime_type = "image/jpeg"
83106
bytesio.seek(0)

tests/test_content.py

+15
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@
3535
TEST_JPG_URL = "https://storage.googleapis.com/generativeai-downloads/data/test_img.jpg"
3636
TEST_JPG_DATA = TEST_JPG_PATH.read_bytes()
3737

38+
TEST_GIF_PATH = HERE / "test_img.gif"
39+
TEST_GIF_URL = "https://storage.googleapis.com/generativeai-downloads/data/test_img.gif"
40+
TEST_GIF_DATA = TEST_GIF_PATH.read_bytes()
41+
3842

3943
# simple test function
4044
def datetime():
@@ -88,6 +92,17 @@ def test_jpg_to_blob(self, image):
8892
self.assertEqual(blob.mime_type, "image/jpeg")
8993
self.assertStartsWith(blob.data, b"\xff\xd8\xff\xe0\x00\x10JFIF")
9094

95+
@parameterized.named_parameters(
96+
["PIL", PIL.Image.open(TEST_GIF_PATH)],
97+
["P", PIL.Image.fromarray(np.zeros([6, 6, 3], dtype=np.uint8)).convert("P")],
98+
["IPython", IPython.display.Image(filename=TEST_GIF_PATH)],
99+
)
100+
def test_gif_to_blob(self, image):
101+
blob = content_types.image_to_blob(image)
102+
self.assertIsInstance(blob, protos.Blob)
103+
self.assertEqual(blob.mime_type, "image/gif")
104+
self.assertStartsWith(blob.data, b"GIF87a")
105+
91106
@parameterized.named_parameters(
92107
["BlobDict", {"mime_type": "image/png", "data": TEST_PNG_DATA}],
93108
["protos.Blob", protos.Blob(mime_type="image/png", data=TEST_PNG_DATA)],

tests/test_img.gif

353 Bytes
Loading

0 commit comments

Comments
 (0)