def preprocess_image(
        self, input_images: List[List[Optional[Image.Image]]], vae_scale_factor: int
    ) -> Tuple[List[List[torch.Tensor]], List[List[List[int]]], List[int]]:
        """
        Preprocesses input images for the VisualCloze pipeline.

        This function handles the preprocessing of input images by:
        1. Resizing and cropping images to maintain consistent dimensions
        2. Converting images to the Tensor format for the VAE
        3. Normalizing pixel values
        4. Tracking image sizes and positions of target images

        Args:
            input_images (List[List[Optional[Image.Image]]]):
                A nested list of PIL Images where:
                - Outer list represents different samples, including in-context examples and the query
                - Inner list contains images for the task
                - In the last row, condition images are provided and the target images are placed as None
            vae_scale_factor (int):
                The scale factor used by the VAE for resizing images

        Returns:
            Tuple containing:
            - List[List[torch.Tensor]]: Preprocessed images in tensor format
            - List[List[List[int]]]: Dimensions of each processed image [height, width]
            - List[int]: Target positions indicating which images are to be generated
        """
        n_samples, n_task_images = len(input_images), len(input_images[0])
        divisible = 2 * vae_scale_factor

        processed_images: List[List[Image.Image]] = [[] for _ in range(n_samples)]
        resize_size: List[Optional[Tuple[int, int]]] = [None for _ in range(n_samples)]
        target_position: List[int] = []

        # Process each sample
        for i in range(n_samples):
            # Determine size from first non-None image
            for j in range(n_task_images):
                if input_images[i][j] is not None:
                    aspect_ratio = input_images[i][j].width / input_images[i][j].height
                    target_area = self.resolution * self.resolution
                    new_h = int((target_area / aspect_ratio) ** 0.5)
                    new_w = int(new_h * aspect_ratio)

                    new_w = max(new_w // divisible, 1) * divisible
                    new_h = max(new_h // divisible, 1) * divisible
                    resize_size[i] = (new_w, new_h)
                    break

            # Process all images in the sample
            for j in range(n_task_images):
                if input_images[i][j] is not None:
                    target = self._resize_and_crop(input_images[i][j], resize_size[i][0], resize_size[i][1])
                    processed_images[i].append(target)
                    if i == n_samples - 1:
                        target_position.append(0)
                else:
                    blank = Image.new("RGB", resize_size[i] or (self.resolution, self.resolution), (0, 0, 0))
                    processed_images[i].append(blank)
                    if i == n_samples - 1:
                        target_position.append(1)

        # Ensure consistent width for multiple target images when there are multiple target images
        if len(target_position) > 1 and sum(target_position) > 1:
            new_w = resize_size[n_samples - 1][0] or 384
            for i in range(len(processed_images)):
                for j in range(len(processed_images[i])):
                    if processed_images[i][j] is not None:
                        new_h = int(processed_images[i][j].height * (new_w / processed_images[i][j].width))
                        new_w = int(new_w / 16) * 16
                        new_h = int(new_h / 16) * 16
                        processed_images[i][j] = self.height(processed_images[i][j], new_h, new_w)

        # Convert to tensors and normalize
        image_sizes = []
        for i in range(len(processed_images)):
            image_sizes.append([[img.height, img.width] for img in processed_images[i]])
            for j, image in enumerate(processed_images[i]):
                image = self.pil_to_numpy(image)
                image = self.numpy_to_pt(image)
                image = self.normalize(image)
                processed_images[i][j] = image

        return processed_images, image_sizes, target_position

        Preprocesses input images for the VisualCloze pipeline.

        This function handles the preprocessing of input images by:
        1. Resizing and cropping images to maintain consistent dimensions
        2. Converting images to the Tensor format for the VAE
        3. Normalizing pixel values
        4. Tracking image sizes and positions of target images

        Args:
            input_images (List[List[Optional[Image.Image]]]):
                A nested list of PIL Images where:
                - Outer list represents different samples, including in-context examples and the query
                - Inner list contains images for the task
                - In the last row, condition images are provided and the target images are placed as None
            vae_scale_factor (int):
                The scale factor used by the VAE for resizing images

        Returns:
            Tuple containing:
            - List[List[torch.Tensor]]: Preprocessed images in tensor format
            - List[List[List[int]]]: Dimensions of each processed image [height, width]
            - List[int]: Target positions indicating which images are to be generated
        
src/diffusers/pipelines/visualcloze/visualcloze_utils.py