Skip to content

BGR;[15,16,34,32] modes are documented but not part of ImageMode #5933

Description

@FirefoxMetzger

I found a few image modes that are listed as partially supported in the docs (here), but that are not listed in ImageMode:

from PIL import ImageMode

# note: I'm using the private variable here because it supports `in`
# and leads to nicer code
# afaik correct access is done via ImageMode.getmode(mode)

assert "BGR;15" in ImageMode._modes
assert "BGR;16" in ImageMode._modes
assert "BGR;24" in ImageMode._modes
assert "BGR;32" in ImageMode._modes

Is there any reason why these have not been added? If not, would a PR adding those be welcome?

Activity

  1. FirefoxMetzger commented on Jan 5, 2022

    @FirefoxMetzger
    ContributorAuthor

    On that note, is there any chance to add "1;8" as an official mode and not just a rawmode?

    I might be going about this the wrong way, but I can't seem to figure out how to save a boolean array while setting the mode explicitly:

    image = np.arange(256 * 256).reshape((256, 256)) % 2 == 0
    
    Image.fromarray(expected).save("fancy.png")  # works
    Image.fromarray(expected, mode="1").save("fancy.png")  # saves corrupted image
    Image.fromarray(expected, mode="1;8").save("fancy.png")  # invalid mode
  2. radarhere commented on Jan 5, 2022

    @radarhere
    Member

    I think when I documented BGR;* in #4047, I was just working from

    } else if (strcmp(mode, "BGR;15") == 0) {
    /* EXPERIMENTAL */
    /* 15-bit reversed true colour */
    im->bands = 1;
    im->pixelsize = 2;
    im->linesize = (xsize * 2 + 3) & -4;
    im->type = IMAGING_TYPE_SPECIAL;
    } else if (strcmp(mode, "BGR;16") == 0) {
    /* EXPERIMENTAL */
    /* 16-bit reversed true colour */
    im->bands = 1;
    im->pixelsize = 2;
    im->linesize = (xsize * 2 + 3) & -4;
    im->type = IMAGING_TYPE_SPECIAL;
    } else if (strcmp(mode, "BGR;24") == 0) {
    /* EXPERIMENTAL */
    /* 24-bit reversed true colour */
    im->bands = 1;
    im->pixelsize = 3;
    im->linesize = (xsize * 3 + 3) & -4;
    im->type = IMAGING_TYPE_SPECIAL;
    } else if (strcmp(mode, "BGR;32") == 0) {

    The support for those modes is not great - BGR;32 isn't even mentioned anywhere else in src.

    That said, I don't see any problem with a PR adding those modes to ImageMode.


    Image.fromarray(expected).save("fancy.png") goes through

    Pillow/src/PIL/Image.py

    Lines 2806 to 2816 in 3f77466

    if mode is None:
    try:
    typekey = (1, 1) + shape[2:], arr["typestr"]
    except KeyError as e:
    raise TypeError("Cannot handle this data type") from e
    try:
    mode, rawmode = _fromarray_typemap[typekey]
    except KeyError as e:
    raise TypeError("Cannot handle this data type: %s, %s" % typekey) from e
    else:
    rawmode = mode

    to come out with a mode of 1 and a rawmode of 1;8 - so yes, I'm not surprised that you can't get the same result when explicitly setting the mode, which would lead to identical values for mode and rawmode.

    But I'm also not clear on why you need to set the mode explicitly?

  3. FirefoxMetzger commented on Jan 6, 2022

    @FirefoxMetzger
    ContributorAuthor

    The support for those modes is not great - BGR;32 isn't even mentioned anywhere else in src.

    I agree, I never saw this mode in real code neither.

    My motivation for doing this is a refactor in our codebase that makes it lean on ImageMode instead of maintaining our own list of channels for each mode, which could go out of sync as pillow improves. I noticed that those modes are missing, so I think it makes sense to make that list complete.


    But I'm also not clear on why you need to set the mode [1;8] explicitly?

    Because I was writing a unit-test and it caught me off guard that the following round trip fails:

    # a boolean ndarray saved as b/w
    expected = np.arange(256 * 256).reshape((256, 256)) % 2 == 0
    Image.fromarray(expected, mode="1").save("fancy.png")
    actual = np.asarray(Image.open("fancy.png"))
    
    assert np.allclose(actual, expected)

    In my case, the solution was to drop mode=1 completely, but it is unexpected that the above does not work. From here, I did some searching on what the correct mode=XX value should be, but it seems that it is impossible to set the mode explicitly for this scenario. Instead, it has to be resolved implicitly by pillow using the shape and dtype of the array.

  4. FirefoxMetzger commented on Jan 6, 2022

    @FirefoxMetzger
    ContributorAuthor

    @radarhere I added a PR to add the BGR;XX ImageModes. Do I just wait for a review from here, or is there anything else I should do?

  5. radarhere commented on Jan 6, 2022

    @radarhere
    Member

    Yes, it's now just a matter of waiting for reviews/comments on your PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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