On Wed, 2 Apr 2025 12:24:54 GMT, Sergey Bylokhov <s...@openjdk.org> wrote:
>>>The idea of the current approach, as I understand it is that we find the >>>last band of the first pixel, be it 3 for pixel-interleaved RGBA, or 30000 >>>for band-interleaved image, and then add 1 to it, meaning the size >>>sufficient to fit that last band: >>>int size = maxBandOff + 1; >>>At this point we can already fit the first pixel, so what's left is to fit >>>the remaining first scanline (hence width - 1): >> >> This looks suspicious. Let's try calculating the size or pointer to the last >> pixel using the formula: >> "starting offset + pointer to the last pixel + pixelStride" but in reverse >> order. >> >> // This moves the pointer to the start of the last row. >> size = scanlineStride * (height - 1); >> // This moves the pointer to the start of the last pixel in the last row. >> size += pixelStride * (width - 1); >> >> **Note**: At this point, the size is not necessarily aligned to pixelStride >> because scanlineStride may include a gap larger than pixelStride at the end. >> >> Now, we need to account for the last pixel in the last row. In a theoretical >> case where the offset is 0, simply adding pixelStride one more time would be >> sufficient. >> >> However, in our case, we add maxBandOff + 1, which seems odd since >> maxBandOff represents the offset of the largest component, placing it >> somewhere within the pixelStride. >> >> To fix this, we should actually add the second part of the pixelStride only >> if maxBandOff is smaller than pixelStride. >> >> btw, I'm not sure why we can't use the first component instead of the last >> one: >> >> >> int minBandOff = bandOffsets[0]; >> for (int i = 1; i < bandOffsets.length; i++) { >> minBandOff = Math.min(minBandOff, bandOffsets[i]); >> } >> >> long size = 0; >> >> if (minBandOff >= 0) >> size += minBandOff; >> if (pixelStride > 0) >> size += pixelStride * width; >> if (scanlineStride > 0) >> size += scanlineStride * (height - 1); >> return (int) size; >> >> >> ...Still investigating this. > > Or maybe we should modify the code that relies on the current size? > > Why does our code work fine when skipping the end of the scanline in cases > where there is a gap, but it cannot skip the pixelStride when there is a gap > as well? > why we can't use the first component instead of the last one We definitely cannot do that because of the band-interleaved case: imagine if there are like 10000 bytes of red samples followed by another 10000 bytes of green samples - with `pixelStride=1` and `scanlineStride=100` if we take the first component offset (0), our calculated size would only fit the red channel. In your calculations using "starting offset + pointer to the last pixel + pixelStride", you assume only pixel-interleaved variant, but this calculation would break with other interleaving modes. Actually, for pixel-interleaved layout there is a simple commonly-used formula, like: `size = startingOffset + scanlineStride * height`. But the problem is that we don't really know the `startingOffset`, we only know offsets of the individual components, which leads to the other issue... > the size is not necessarily aligned to pixelStride because scanlineStride may > include a gap larger than pixelStride at the end. Good point, and because of the way `pixelStride` and `scanlineStride` are formulated (offsets between same-band samples of the adjacent pixels/scanlines), they don't tell us anything about the alignment. And moreover, in the case of unused components, where our `bandOffsets` don't fully fill the `pixelStride`, there is an ambiguity: Consider `bandOffsets = {1, 2, 3}` and `pixelStride=4`, is that a `xRGB` layout with `startingOffset=0`, or `RGBx` with `startingOffset=1`? The answer is - we don't have enough info as far as I'm concerned... ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/24111#discussion_r2024717944