Implementation:Bentoml BentoML IO Descriptor Image
| Knowledge Sources | |
|---|---|
| Domains | IO Descriptors, Image Processing, API Specification |
| Last Updated | 2026-02-13 15:00 GMT |
Overview
The Image IO descriptor defines API specification for BentoML services that accept or return image data, supporting both PIL Image and NumPy ndarray representations.
Description
The Image class is an IO descriptor that handles image-based inputs and outputs for BentoML services. It extends IODescriptor[ImageType] where ImageType is a union of PIL.Image.Image and numpy.ndarray. The descriptor manages:
- MIME type handling: Validates and maps MIME types to PIL image formats using a lazily-initialized mapping from Pillow's
Image.MIMEdictionary. - PIL mode configuration: Supports all PIL color modes (RGB, RGBA, CMYK, L, etc.) with a default of RGB.
- Allowed MIME type filtering: Optionally restricts accepted input image types to a user-specified set.
- HTTP request parsing: Handles both multipart/form-data uploads and raw image body content, searching multipart form fields for image data matching allowed MIME types.
- HTTP response generation: Serializes PIL images or NumPy arrays to the configured output format with proper Content-Disposition headers following RFC 2183.
- gRPC protobuf serialization: Converts between
pb.File/pb_v1alpha1.Fileprotobuf messages and PIL images for both v1 and v1alpha1 protocol versions. - OpenAPI schema generation: Produces binary string schemas for API documentation with appropriate MIME type content mappings.
The module lazily initializes Pillow through initialize_pillow(), which builds the MIME-to-extension mapping and filters out write-only formats (PALM, PDF). The lazy initialization is cached via functools.lru_cache.
Usage
Use this descriptor when building BentoML services that process image data, such as image classification, object detection, or image transformation services. It is specified as the input or output parameter in the @svc.api decorator of a legacy BentoML service.
Code Reference
Source Location
- Repository: Bentoml_BentoML
- File: src/bentoml/_internal/io_descriptors/image.py
- Lines: 1-483
Signature
class Image(
IODescriptor[ImageType],
descriptor_id="bentoml.io.Image",
proto_fields=("file",),
):
def __init__(
self,
pilmode: _Mode | None = DEFAULT_PIL_MODE,
mime_type: str = "image/jpeg",
*,
allowed_mime_types: t.Iterable[str] | None = None,
): ...
def _from_sample(self, sample: ImageType | str) -> ImageType: ...
def to_spec(self) -> dict[str, t.Any]: ...
@classmethod
def from_spec(cls, spec: dict[str, t.Any]) -> t.Self: ...
def input_type(self) -> UnionType: ...
def openapi_schema(self) -> Schema: ...
def openapi_request_body(self) -> dict[str, t.Any]: ...
def openapi_responses(self) -> OpenAPIResponse: ...
async def from_http_request(self, request: Request) -> ImageType: ...
async def to_http_response(self, obj: ImageType, ctx: Context | None = None) -> Response: ...
async def from_proto(self, field: pb.File | pb_v1alpha1.File | bytes) -> ImageType: ...
async def to_proto(self, obj: ImageType) -> pb.File: ...
Import
from bentoml.io import Image
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| pilmode | str or None | No | PIL color mode (e.g., "RGB", "RGBA", "L", "CMYK"). Defaults to "RGB". |
| mime_type | str | No | MIME type for the output image format. Defaults to "image/jpeg". |
| allowed_mime_types | Iterable[str] or None | No | Restricts accepted input MIME types. If None, all readable image MIME types are accepted. |
Outputs
| Name | Type | Description |
|---|---|---|
| ImageType | PIL.Image.Image or numpy.ndarray | The deserialized image from an incoming request, or the image to serialize for a response. |
Usage Examples
from __future__ import annotations
from typing import TYPE_CHECKING, Any
import bentoml
from bentoml.io import Image, NumpyNdarray
import numpy as np
if TYPE_CHECKING:
from PIL.Image import Image as PILImage
from numpy.typing import NDArray
runner = bentoml.tensorflow.get("image-classification:latest").to_runner()
svc = bentoml.legacy.Service("vit-object-detection", runners=[runner])
@svc.api(input=Image(), output=NumpyNdarray(dtype="float32"))
async def predict_image(f: PILImage) -> NDArray[Any]:
arr = np.array(f) / 255.0
arr = np.expand_dims(arr, (0, 3)).astype("float32")
return await runner.async_run(arr)
# Using from_sample to create a descriptor from a sample image
input_spec = Image.from_sample("/path/to/image.jpg")
@svc.api(input=input_spec, output=Image())
async def transform(input_img: PILImage) -> PILImage:
return input_img.rotate(90)