Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clarification on "filter_palette_zero" #187

Closed
MasterInQuestion opened this issue Mar 18, 2024 · 4 comments
Closed

Clarification on "filter_palette_zero" #187

MasterInQuestion opened this issue Mar 18, 2024 · 4 comments

Comments

@MasterInQuestion
Copy link

MasterInQuestion commented Mar 18, 2024

    For Palette images and those of < 8bpc (bit-depth per component):
    https://github.com/lvandeve/lodepng/blob/44cdab80e1c55d6b5decae3596a17c3c4c3c3c7c/lodepng.cpp#L6111-L6125
    https://github.com/lvandeve/lodepng/blob/44cdab80e1c55d6b5decae3596a17c3c4c3c3c7c/lodepng.h#L911-L915
[[
/*
    There is a heuristic called the minimum sum of absolute differences heuristic, suggested by the PNG standard:
    |*| If the image type is Palette, or the bit depth is smaller than 8: then do not filter the image (i.e. use fixed filtering, with the filter None).
    |*| (The other case) If the image type is Grayscale or RGB (with or without Alpha), and the bit depth is not smaller than 8, then use adaptive filtering heuristic as follows:
    Independently for each row, apply all 5 filters and select the filter that produces the smallest sum of absolute values per row.
    This heuristic is used if filter strategy is LFS_MINSUM and filter_palette_zero is true.

    If filter_palette_zero is true and filter_strategy is not LFS_MINSUM, the above heuristic is followed.
    But for "the other case", whatever strategy filter_strategy is set to instead of the minimum sum heuristic is used.
*/
    if (
    settings->filter_palette_zero &&
    ( color->colortype == LCT_PALETTE || color->bitdepth < 8 )
    ) {
    strategy = LFS_ZERO; };

/*
    If true, follows the official PNG heuristic:
    If the PNG uses a palette or lower than 8 bit depth, set all filters to zero.
    Otherwise use the filter_strategy.
    Note that to completely follow the official PNG heuristic:
    filter_palette_zero must be true, and filter_strategy must be LFS_MINSUM.
*/
    unsigned filter_palette_zero;
]]
    The PNG standard didn't suggest so:
    https://www.w3.org/TR/png/#12Filter-selection
    ; it's suggested by the "libpng" book...
    https://web.archive.org/web/20241217191412/http://libpng.org/pub/png/book/chapter09.html#INDEX-682

    Note there are some malapropos ideas in the PNG book.
    Notably:
    "So how does an encoder actually choose the proper filter for each row? Testing all possible combinations is clearly impossible: ..."
<^>    It's actually suggested by the PNG standard as the optimal optimization method...
    If speed is not of primary concern.
    .
    "The first rule is that filters are rarely useful on palette images, so don't even bother with them."
<^>    No filtering does not necessarily cause best compression in such cases. (mere mostly)
    It's mostly as a performance optimization.
    .
    "The theory, to some extent based on empirical evidence, is that switching filters too often can have a deleterious effect on the main compression engine."
<^>    Data, are no more than data. It is all upon: the interpretation.
    For any proper general purpose compressor, this shouldn't make a difference.
    .
    “In particular, you cannot treat color values and transparency values as if they are separate, unrelated entities.
    Attempting to partition the palette into a "color part" and a "transparent part":
    Makes no more sense, than attempting to partition a standard RGB palette into: red, green, and blue parts.”
<^>    https://www.awaresystems.be/imaging/tiff/tifftags/planarconfiguration.html
    https://gist.github.com/Jim-Bar/3cbba684a71d1a9d468a6711a6eddbeb#packed-planar-and-semi-planar
    Planar in certain cases may be noticeably more compressible than Packed.
    (the opposite may occur too, much dependent on the input)
    .
    Also much dependent on the compressor implementation:
    https://github.com/MasterInQuestion/talk/discussions/40
    https://github.com/libjxl/libjxl/issues/3921#issuecomment-2513471925

@lvandeve
Copy link
Owner

Both the png standard and the comments in lodepng.cpp/.h mention the heuristic of using filter 0 for palette and <8bpp images, and mention the minimum sum heuristic, so it seems to match up and should be fine to refer to the png standard for this.

However, I simplified the comments in 5225268, including removing some duplication and referring to the png standard in a softer way

@MasterInQuestion
Copy link
Author

    I mean only the Filter 0 assertion for Palette and < 8bpc:
    The PNG standard ("w3.org" one) mere suggests as recommendation.
    Unlike the "libpng" book saying outright "don't even bother"...

    However, I no more use PNG for almost all cases [1]:
    For the apparent superiority of WebP Lossless in possibly every case.
[ [1]
    Except when the size difference would be subliminal: e.g. < 4 KiB QR codes etc.
    [ ^ Where the file system would regardless take, for anything below that threshold typically. ]
    Or the target lacks WebP support.
    [ E.g. https://github.com/orgs/community/discussions/145830#discussion-7575424 ] ]

    Nevertheless, documentation in code might be troublesome.
    Probably the writing itself is troublesome... Literacy is a hard topic.

    Anyway, the previous inaccuracies are gone with your change.
    Note: Exact URL provides better reference.

@lvandeve
Copy link
Owner

Thanks, the wording is indeed improved then

@MasterInQuestion
Copy link
Author

MasterInQuestion commented Dec 25, 2024

    Thank you too.

    Probably not perfectly on-topic here:
    But `zopflipng` seems to had "filter_palette_zero" true.
    (which is undesirable for whose purpose, aforementioned)

    Also I noted `zopflipng` may output bigger file with higher iteration count:
    Compared to that of the previous (lower) iterations.
    (e.g. "--iterations=10000" may output bigger than "--iterations=7500")

    And the Usage examples in the help output:
    https://github.com/google/zopfli/blob/7113f4e96bd26df27c46d590df95e517b966f10d/src/zopflipng/zopflipng_bin.cc#L142
    ("--filters=01234mepb")
    Really doesn't make sense.
    To deliver the optimal output, shall only require: "--filters=0b" (others are always bigger) [1]
    [ ^ https://github.com/MasterInQuestion/attach#readme ]
    .
    And which filter type to continue the iterations on:
    At many times, can be determined without running all iterations for both.
    (so a potential huge performance improvement)
[ ^
    If the 1st round has "b" output bigger than "0" (or vice-versa) for 3%:
    Extremely likely (possibly absolutely) that the image, would be smaller with this filter type. ]

[ [1]
    Not necessarily.
    E.g. https://github.com/MasterInQuestion/attach/raw/main/google/zopfli/204/FF-icon.png
    (74,567 B; PNG: RGBA, 512x512)
    .
    Where "p", "e", "1" could be smaller:
    [ zopflipng -y --always_zopflify --iterations=10 --filters=${x} "FF-icon.png" ${Out} ]
    "b": 76,350 B
    "p": 74,546 B
    "e": 74,674 B
    "1": 70,966 B
    "2": 79,062 B
    "3": 78,623 B
    "4": 84,471 B
    "m": 80,381 B
    "0": 100,764 B

    Some explanation on "b" (brute force) desirable. ]

MasterInQuestion referenced this issue in MasterInQuestion/attach Jan 7, 2025
	`ffmpeg` ("libwebp"): -lossless 1 -q 100 -compression_level 6
	(equivalent `cwebp` "-z 9" [ https://github.com͏/webmproject/libwebp/commit/65b99f1c924cf7bf225f420b3cc115b66cdfbf42#diff-c5ca9350a65e20a9ab5947ba07a54ca4234cf6b7acdb2d77b589fee60a06aa13 ])

	~ 28.35% size of the best PNG practically attainable.
	(`zopflipng`: --iterations=10 --filters=0b)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants