def create_image_grid(images: list[Image.Image], nrow: int) -> Image.Image:
    """Create a grid of images using PIL.

    This function arranges a list of PIL images into a grid layout with a specified
    number of images per row. All input images must have the same dimensions.

    Args:
        images (list[Image.Image]): List of PIL Images to arrange in a grid. All
            images must have identical dimensions.
        nrow (int): Number of images to display per row in the grid.

    Returns:
        Image.Image: A new PIL Image containing the arranged grid of input images
            with white background.

    Raises:
        ValueError: If ``images`` list is empty.

    Examples:
        Create a 2x2 grid from 4 images:

        >>> from PIL import Image
        >>> import numpy as np
        >>> # Create sample images
        >>> img1 = Image.fromarray(np.zeros((64, 64, 3), dtype=np.uint8))
        >>> img2 = Image.fromarray(np.ones((64, 64, 3), dtype=np.uint8) * 255)
        >>> images = [img1, img2, img1, img2]
        >>> # Create grid with 2 images per row
        >>> grid = create_image_grid(images, nrow=2)
        >>> isinstance(grid, Image.Image)
        True
        >>> grid.size
        (128, 128)

    Note:
        - All input images must have identical dimensions
        - The grid is filled row by row, left to right, top to bottom
        - If the number of images is not divisible by ``nrow``, the last row may
          be partially filled
        - The output image dimensions will be:
          width = ``nrow`` * image_width
          height = ceil(len(images)/nrow) * image_height
    """
    if not images:
        msg = "No images provided to create grid"
        raise ValueError(msg)

    # Assuming all images have the same size
    img_width, img_height = images[0].size

    # Calculate grid dimensions
    ncol = (len(images) + nrow - 1) // nrow  # Ceiling division
    grid_width = nrow * img_width
    grid_height = ncol * img_height

    # Create a new image with white background
    grid_image = Image.new("RGB", (grid_width, grid_height), color="white")

    # Paste images into grid
    for idx, img in enumerate(images):
        row = idx // nrow
        col = idx % nrow
        grid_image.paste(img, (col * img_width, row * img_height))

    return grid_image
Create a grid of images using PIL.

    This function arranges a list of PIL images into a grid layout with a specified
    number of images per row. All input images must have the same dimensions.

    Args:
        images (list[Image.Image]): List of PIL Images to arrange in a grid. All
            images must have identical dimensions.
        nrow (int): Number of images to display per row in the grid.

    Returns:
        Image.Image: A new PIL Image containing the arranged grid of input images
            with white background.

    Raises:
        ValueError: If ``images`` list is empty.

    Examples:
        Create a 2x2 grid from 4 images:

        >>> from PIL import Image
        >>> import numpy as np
        >>> # Create sample images
        >>> img1 = Image.fromarray(np.zeros((64, 64, 3), dtype=np.uint8))
        >>> img2 = Image.fromarray(np.ones((64, 64, 3), dtype=np.uint8) * 255)
        >>> images = [img1, img2, img1, img2]
        >>> # Create grid with 2 images per row
        >>> grid = create_image_grid(images, nrow=2)
        >>> isinstance(grid, Image.Image)
        True
        >>> grid.size
        (128, 128)

    Note:
        - All input images must have identical dimensions
        - The grid is filled row by row, left to right, top to bottom
        - If the number of images is not divisible by ``nrow``, the last row may
          be partially filled
        - The output image dimensions will be:
          width = ``nrow`` * image_width
          height = ceil(len(images)/nrow) * image_height
    
src/anomalib/visualization/image/functional.py