Skip to content

BUG: BaseImageToImageConverter and ImageCompressionConverter crash on CMYK images when output format is PNG #3257

Closed

Description

BaseImageToImageConverter and ImageCompressionConverter support converting and compressing images across JPEG, PNG, and WEBP formats. However, when processing an image in CMYK color mode (common in print media, scans, and press JPEGs) with output_format="PNG", both converters crash with an unhandled OSError:

KeyError: 'CMYK'
OSError: cannot write mode CMYK as PNG

Root Cause

Pillow's PNG encoder (PIL.PngImagePlugin) only supports modes 1, L, LA, I, I;16, P, RGB, and RGBA. When saving a CMYK image to a PNG buffer, Pillow raises KeyError: 'CMYK'.

  1. In BaseImageToImageConverter._transform_image:
    Mode conversion is only handled for output_format == "JPEG" via _prepare_image_for_jpeg. Although BaseImageToImageConverter already defines _convert_to_rgb_or_rgba(image), it is never called when output_format == "PNG". Subclasses such as ImageResizingConverter pass CMYK images directly to transformed.save(buffer, "PNG"), crashing at runtime.
  2. In ImageCompressionConverter._compress_image:
    Format preparation is likewise only performed for output_format == "JPEG". PNG targets with CMYK mode bypass mode normalization and crash upon image.save(compressed_bytes, output_format, **save_kwargs).

Reproduction

from PIL import Image
from pyrit.converter import ImageResizingConverter, ImageCompressionConverter

cmyk_image = Image.new("CMYK", (40, 40), (100, 50, 0, 0))

# 1. BaseImageToImageConverter / ImageResizingConverter
resizer = ImageResizingConverter(output_format="PNG")
resizer._transform_image(cmyk_image, "JPEG")
# Raises: OSError: cannot write mode CMYK as PNG

# 2. ImageCompressionConverter
compressor = ImageCompressionConverter(output_format="PNG")
compressor._compress_image(cmyk_image, "JPEG", 500)
# Raises: OSError: cannot write mode CMYK as PNG

Proposed Fix

A fix would convert CMYK images to RGB when output_format == "PNG":

  • In BaseImageToImageConverter._transform_image:
    elif output_format == "PNG" and image.mode == "CMYK":
        image = self._convert_to_rgb_or_rgba(image)
    
  • In ImageCompressionConverter._compress_image:
    elif output_format == "PNG" and image.mode == "CMYK":
        image = image.convert("RGB")
    

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions