You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@sedona.apache.org by "ShiroKSH (via GitHub)" <gi...@apache.org> on 2026/07/15 10:58:49 UTC
[PR] fix: preserve component sample model band offsets [sedona]
ShiroKSH opened a new pull request, #3108:
URL: https://github.com/apache/sedona/pull/3108
## Summary
- pair `ComponentSampleModel` band offsets with band positions in its contiguous fast path
- add coverage for a legal raster layout that reorders data banks and uses distinct offsets
The slow path already uses the band position. The fast path used the mapped bank number instead, returning samples from the wrong positions when the mapping is non-identity.
## Validation
- executed the regression fixture against the updated fast-path implementation
- ran Python bytecode compilation
- ran Black formatting verification
- checked the staged diff with `git diff --check`
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: issues-unsubscribe@sedona.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] [GH-3166] Resolve raster sample positions the way Java AWT does in the Python reader [sedona]
Posted by "jiayuasu (via GitHub)" <gi...@apache.org>.
jiayuasu commented on PR #3108:
URL: https://github.com/apache/sedona/pull/3108#issuecomment-5077300048
Added the warning in 3fce157. `UserWarning` via `warnings.warn`, matching how this package already reports its geometry speedup fallback, one message per quirk:
> This raster packs one pixel per 32 bit sample. java.awt.image derives the bit mask for it as `(1 << 32) - 1`, which is zero on an int, so Java reads every pixel of such a raster as zero and writes to it are no-ops. Returning zeroes to match.
> This raster's data bit offset (4) is not a multiple of its 8 bits per pixel, so some pixels straddle two samples. java.awt.image shifts those by a negative distance, which it takes modulo 32, reading the top bits of the sample instead; Java's own writes to those pixels are lossy in the same way. Returning what Java reads.
The trigger is the negative shift distance itself, not the alignment of the data bit offset, because whether a pixel straddles also depends on the width: 4 bit pixels at offset 2 in a 32 bit sample fit until x reaches 8. Checking the distance keeps it exact in both directions.
Behaviour, all three verified rather than assumed:
- reading the packed layout `RS_MakeRasterForTesting` builds today emits nothing, asserted in the test under `warnings.simplefilter("error")` so a future false positive fails CI
- 500 reads of one odd raster produce 1 warning, since Python's default filter dedups per message and location; distinct layouts warn separately
- values did not move: the 7580 case sweep against `java.awt.image` is still exact
Worth knowing where this does and does not help: inside a pandas UDF the warning lands on executor stderr, which is easy to miss. It is aimed at driver-side reads and notebooks, so it is a signpost for whoever is debugging an odd raster interactively rather than a guard rail on a cluster.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: issues-unsubscribe@sedona.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] [GH-3166] Resolve raster sample positions the way Java AWT does in the Python reader [sedona]
Posted by "jiayuasu (via GitHub)" <gi...@apache.org>.
jiayuasu merged PR #3108:
URL: https://github.com/apache/sedona/pull/3108
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: issues-unsubscribe@sedona.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] [GH-3166] Resolve raster sample positions the way Java AWT does in the Python reader [sedona]
Posted by "jiayuasu (via GitHub)" <gi...@apache.org>.
jiayuasu commented on PR #3108:
URL: https://github.com/apache/sedona/pull/3108#issuecomment-5077227463
Confirmed and fixed in 9553cc6. JDK 17 returns `[154, 188, 222, 248]`, the port returned `[154, 188, 222, 0]`.
Correction to my previous comment first: the claim that the 1004-case sweep covered unaligned data bit offsets was wrong. Its offsets were `{0, numBits, 3 * numBits, size, size + numBits}`, every one of them a multiple of `num_bits`, so it never built a pixel straddling two samples. The sweep could not have caught this, and I should not have described it as covering unaligned offsets.
Root cause is narrower than the shift distance alone. Java reads a sample through `DataBuffer.getElem()`, which returns a signed `int`, then applies `>>`: an arithmetic shift whose distance an `int` shift takes modulo 32. So the -4 distance becomes 28 and the sample's top bits move down, sign extended. The port shifted an unsigned array by a negative count, which numpy zeroes. Samples are now read as `int32` and shifted by `shifts & 31`, which is Java's width and Java's masking.
It is not only about the sign bit, so I added both variants as regression cases: the same layout over `{0x12345678, 0}` reads `[35, 69, 103, 1]` in Java, and the last pixel was `0` here too. Test is `test_multi_pixel_packed_pixel_straddling_two_samples`, parameterized over both banks.
Keeping the offsets in scope rather than narrowing the claim, since the reader has to handle whatever a serialized Java raster contains. The sweep now enumerates every `data_bit_offset` from 0 to two samples wide instead of a handful:
| | layouts | mismatched vs java.awt.image |
|---|---|---|
| master | 7580 | 5295 |
| previous head 642de29 | 7580 | 1291 |
| this head 9553cc6 | 7580 | 0 |
Verified on numpy 1.26.4 and 2.5.1 with numpy warnings raised as errors. The unit tests are at 22 cases, 21 of which fail without this branch.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: issues-unsubscribe@sedona.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] fix: preserve component sample model band offsets [sedona]
Posted by "jiayuasu (via GitHub)" <gi...@apache.org>.
jiayuasu commented on code in PR #3108:
URL: https://github.com/apache/sedona/pull/3108#discussion_r3599265932
##########
python/sedona/spark/raster/sample_model.py:
##########
@@ -80,9 +80,9 @@ def as_numpy(self, data_buffer: DataBuffer) -> np.ndarray:
if self.scanline_stride == self.width and self.pixel_stride == 1:
# Fast path: no gaps between pixels
band_arrs = []
- for bank_index in self.bank_indices:
+ for k, bank_index in enumerate(self.bank_indices):
bank_data = data_buffer.bank_data[bank_index]
- offset = self.band_offsets[bank_index]
+ offset = self.band_offsets[k]
Review Comment:
Could we calculate the effective start here (`data_buffer.offsets[bank_index] + self.band_offsets[k]`) and always slice a `width * height` window? I may be missing an invariant, but a component model can have a zero band offset with a padded backing bank; then the current branch seems to pass the whole bank to `reshape()`. The slow path may need the buffer offset too. A zero-offset case in the new test would help confirm it.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: issues-unsubscribe@sedona.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] [GH-3166] Resolve raster sample positions the way Java AWT does in the Python reader [sedona]
Posted by "jiayuasu (via GitHub)" <gi...@apache.org>.
jiayuasu commented on PR #3108:
URL: https://github.com/apache/sedona/pull/3108#issuecomment-5077130212
Confirmed against the JDK and fixed in https://github.com/apache/sedona/commit/642de290053000f1025626901fdb4644fa2bf7ec.
[P1] MultiPixelPackedSampleModel(TYPE_INT, 3, 2, 32, 4, 0) is accepted by Java and reads every pixel as zero, because bitMask = (1 << 32) - 1 is evaluated on an int whose shift count is taken modulo 32. The mask is now derived as (1 << (num_bits % 32)) - 1, which reproduces that and leaves every other width alone (8 on byte and 16 on ushort still mask normally).
[P2] Java leaves the bit offset of a zero mask at 0 and reads the band as zero; getBitOffsets() returns [16, 8, 0, 0] for {0xFF0000, 0xFF00, 0xFF, 0}. The offset is now 0 for a zero mask. Worth noting the crash was numpy-2 only: on numpy 1.26 the -1 shift happened to yield the right answer, so this would not have shown up in CI.
Rather than patch just these two, I swept both packed models over 1004 layouts recorded from java.awt.image: every num_bits that divides the sample size for byte, ushort and int samples, aligned and unaligned data bit offsets, zero and non-zero bank offsets, and mask sets covering zero masks, whole-sample masks and masks over the sign bit. All 1004 match on numpy 1.26 and 2.5, with numpy warnings raised as errors; 510 of them do not match on master. No third case of this kind is left.
One thing the sweep turned up: Java rejects non-contiguous bit masks in the SinglePixelPackedSampleModel constructor (Mask 195 must be contiguous), so those layouts cannot reach the reader and need no handling.
Two new regression tests cover P1 and P2 (test_multi_pixel_packed_whole_sample_pixels_read_zero, test_single_pixel_packed_zero_mask_reads_zero), taking their expected values from the same JDK run.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: issues-unsubscribe@sedona.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] [GH-3166] Resolve raster sample positions the way Java AWT does in the Python reader [sedona]
Posted by "Copilot (via GitHub)" <gi...@apache.org>.
Copilot commented on code in PR #3108:
URL: https://github.com/apache/sedona/pull/3108#discussion_r3649367979
##########
python/sedona/spark/raster/sample_model.py:
##########
@@ -188,27 +189,21 @@ def __init__(
self.data_bit_offset = data_bit_offset
def as_numpy(self, data_buffer: DataBuffer) -> np.ndarray:
- bank_data = data_buffer.bank_data[0]
- bits_per_value = bank_data.dtype.itemsize * 8
- pixel_per_value = bits_per_value / self.num_bits
- shift_right = bits_per_value - self.num_bits
- mask = ((1 << self.num_bits) - 1) << shift_right
-
- band_data = []
- for y in range(self.height):
- pos = y * self.scanline_stride + self.data_bit_offset // bits_per_value
- value = bank_data[pos]
- shift = self.data_bit_offset % bits_per_value
- value = value << shift
- pixels: List[int] = []
- while len(pixels) < self.width:
- while shift < bits_per_value and len(pixels) < self.width:
- pixels.append((value & mask) >> shift_right)
- value = value << self.num_bits
- shift += self.num_bits
- pos += 1
- value = bank_data[pos]
- shift = 0
- band_data.append(np.array(pixels, dtype=bank_data.dtype))
-
- return np.array(band_data).reshape(1, self.height, self.width)
+ samples = data_buffer.bank_samples()
+ bits_per_value = samples.dtype.itemsize * 8
+
+ # Resolve every pixel on its own, the way Java does: this sample model requires
+ # num_bits to divide the size of a data element, so no pixel spans two elements.
+ pixel_bits = self.data_bit_offset + np.arange(self.width) * self.num_bits
+ cols = pixel_bits // bits_per_value
+ shifts = bits_per_value - (pixel_bits % bits_per_value) - self.num_bits
Review Comment:
MultiPixelPackedSampleModel.as_numpy currently assumes pixels never span two data elements (see the comment) and extracts each pixel from a single element via a simple shift/mask. When data_bit_offset is not a multiple of num_bits (e.g., 4-bit pixels with data_bit_offset=2), Java AWT will read pixels that span two elements; the current vectorized formula will return incorrect values for those columns.
##########
python/tests/raster/test_sample_model.py:
##########
@@ -0,0 +1,277 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""Tests for reading rasters whose sample models use the less common layouts.
+
+The expected samples of every test were produced by handing the same sample model and data
+buffer to java.awt.image, so they record what Java AWT reads for these layouts. Each test
+names the Java layout it covers, which is enough to reproduce it.
+"""
+
+from typing import List
+
+import numpy as np
+import pytest
+
+from sedona.spark.raster.data_buffer import DataBuffer
+from sedona.spark.raster.sample_model import (
+ ComponentSampleModel,
+ MultiPixelPackedSampleModel,
+ PixelInterleavedSampleModel,
+ SinglePixelPackedSampleModel,
+)
+
+
+def ramp(start: int, length: int, dtype=np.int32) -> np.ndarray:
+ """A bank of consecutive values, so that a sample identifies its own position."""
+ return np.arange(start, start + length, dtype=dtype)
+
+
+def signed_int32(mask: int) -> int:
+ """Turn a bit mask written in its unsigned form into the value the deserializer
+ produces for it, which is negative for masks covering the top bit."""
+ return mask - (1 << 32) if mask >= (1 << 31) else mask
+
+
+def int_bank(values: List[int]) -> np.ndarray:
+ """An int32 bank holding values written in their unsigned form."""
+ return np.array(values, dtype=np.uint32).astype(np.int32)
+
+
+def test_component_fast_path_pairs_band_offsets_with_bands() -> None:
+ # ComponentSampleModel(TYPE_INT, 2, 2, 1, 2, {1, 0}, {3, 1})
+ sample_model = ComponentSampleModel(DataBuffer.TYPE_INT, 2, 2, 1, 2, [1, 0], [3, 1])
+ data_buffer = DataBuffer(DataBuffer.TYPE_INT, [ramp(10, 7), ramp(20, 7)], 7, [0, 0])
+
+ np.testing.assert_array_equal(
+ sample_model.as_numpy(data_buffer),
+ np.array([[[23, 24], [25, 26]], [[11, 12], [13, 14]]]),
+ )
+
+
+def test_component_fast_path_applies_bank_offsets() -> None:
+ # ComponentSampleModel(TYPE_INT, 2, 2, 1, 2, {1, 0}, {3, 1})
+ # over DataBufferInt(banks, 7, {2, 1})
+ sample_model = ComponentSampleModel(DataBuffer.TYPE_INT, 2, 2, 1, 2, [1, 0], [3, 1])
+ data_buffer = DataBuffer(DataBuffer.TYPE_INT, [ramp(10, 9), ramp(20, 9)], 7, [2, 1])
+
+ np.testing.assert_array_equal(
+ sample_model.as_numpy(data_buffer),
+ np.array([[[24, 25], [26, 27]], [[13, 14], [15, 16]]]),
+ )
+
+
+def test_component_fast_path_reads_a_bounded_window_of_padded_banks() -> None:
+ # ComponentSampleModel(TYPE_INT, 2, 2, 1, 2, {0, 1}, {0, 0}) over banks of 6 samples,
+ # so the band offsets alone give no reason to narrow a bank down to 4 samples
+ sample_model = ComponentSampleModel(DataBuffer.TYPE_INT, 2, 2, 1, 2, [0, 1], [0, 0])
+ data_buffer = DataBuffer(DataBuffer.TYPE_INT, [ramp(10, 6), ramp(20, 6)], 6, [0, 0])
+
+ np.testing.assert_array_equal(
+ sample_model.as_numpy(data_buffer),
+ np.array([[[10, 11], [12, 13]], [[20, 21], [22, 23]]]),
+ )
+
+
+def test_banded_sample_model_over_reordered_banks() -> None:
+ # BandedSampleModel(TYPE_INT, 2, 2, 2, {1, 0}, {1, 2}) over DataBufferInt(banks, 6, {1, 2}),
+ # which is deserialized as a component model with a unit pixel stride
+ sample_model = ComponentSampleModel(DataBuffer.TYPE_INT, 2, 2, 1, 2, [1, 0], [1, 2])
+ data_buffer = DataBuffer(DataBuffer.TYPE_INT, [ramp(10, 8), ramp(20, 8)], 6, [1, 2])
+
+ np.testing.assert_array_equal(
+ sample_model.as_numpy(data_buffer),
+ np.array([[[23, 24], [25, 26]], [[13, 14], [15, 16]]]),
+ )
+
+
+def test_component_slow_path_applies_bank_offsets() -> None:
+ # ComponentSampleModel(TYPE_INT, 3, 2, 2, 8, {1, 1, 0}, {0, 1, 4})
+ # over DataBufferInt(banks, 20, {3, 2}): two bands share a bank, and there are gaps
+ # both between the scanlines and between the pixels within them
+ sample_model = ComponentSampleModel(
+ DataBuffer.TYPE_INT, 3, 2, 2, 8, [1, 1, 0], [0, 1, 4]
+ )
+ data_buffer = DataBuffer(
+ DataBuffer.TYPE_INT, [ramp(100, 24), ramp(200, 24)], 20, [3, 2]
+ )
+
+ np.testing.assert_array_equal(
+ sample_model.as_numpy(data_buffer),
+ np.array(
+ [
+ [[202, 204, 206], [210, 212, 214]],
+ [[203, 205, 207], [211, 213, 215]],
+ [[107, 109, 111], [115, 117, 119]],
+ ]
+ ),
+ )
+
+
+def test_pixel_interleaved_fast_path_applies_bank_offset() -> None:
+ # PixelInterleavedSampleModel(TYPE_INT, 2, 2, 3, 6, {0, 1, 2})
+ # over DataBufferInt(bank of 20 samples, 17, {3})
+ sample_model = PixelInterleavedSampleModel(
+ DataBuffer.TYPE_INT, 2, 2, 3, 6, [0, 1, 2]
+ )
+ data_buffer = DataBuffer(DataBuffer.TYPE_INT, [ramp(10, 20)], 17, [3])
+
+ np.testing.assert_array_equal(
+ sample_model.as_numpy(data_buffer),
+ np.array([[[13, 16], [19, 22]], [[14, 17], [20, 23]], [[15, 18], [21, 24]]]),
+ )
+
+
+def test_pixel_interleaved_slow_path_band_offsets_may_exceed_pixel_stride() -> None:
+ # PixelInterleavedSampleModel(TYPE_INT, 2, 2, 4, 10, {3, 1, 0})
+ # over DataBufferInt(bank, 20, {2}): band 0 sits past the window the three bands of a
+ # single pixel would occupy
+ sample_model = PixelInterleavedSampleModel(
+ DataBuffer.TYPE_INT, 2, 2, 4, 10, [3, 1, 0]
+ )
+ data_buffer = DataBuffer(DataBuffer.TYPE_INT, [ramp(10, 24)], 20, [2])
+
+ np.testing.assert_array_equal(
+ sample_model.as_numpy(data_buffer),
+ np.array([[[15, 19], [25, 29]], [[13, 17], [23, 27]], [[12, 16], [22, 26]]]),
+ )
+
+
+def test_single_pixel_packed_argb_does_not_sign_extend() -> None:
+ # SinglePixelPackedSampleModel(TYPE_INT, 2, 2, 3, {0xFF000000, 0xFF0000, 0xFF00, 0xFF})
+ # over DataBufferInt(bank, 7, {1}): the alpha mask covers the sign bit of the samples
+ sample_model = SinglePixelPackedSampleModel(
+ DataBuffer.TYPE_INT,
+ 2,
+ 2,
+ 3,
+ [signed_int32(0xFF000000), 0x00FF0000, 0x0000FF00, 0x000000FF],
+ )
+ data_buffer = DataBuffer(
+ DataBuffer.TYPE_INT,
+ [int_bank([0, 0x8090A0B0, 0x102030F0, 0, 0xFFFFFFFF, 0x01020304, 0, 0])],
+ 7,
+ [1],
+ )
+
+ np.testing.assert_array_equal(
+ sample_model.as_numpy(data_buffer),
+ np.array(
+ [
+ [[128, 16], [255, 1]],
+ [[144, 32], [255, 2]],
+ [[160, 48], [255, 3]],
+ [[176, 240], [255, 4]],
+ ]
+ ),
+ )
+
+
+def test_single_pixel_packed_applies_bank_offset() -> None:
+ # SinglePixelPackedSampleModel(TYPE_USHORT, 2, 2, 4, {0xF800, 0x7E0, 0x1F}) over
+ # DataBufferUShort(bank, 8, {2}): RGB 565 pixels starting two samples into the bank
+ sample_model = SinglePixelPackedSampleModel(
+ DataBuffer.TYPE_USHORT, 2, 2, 4, [0xF800, 0x07E0, 0x001F]
+ )
+ data_buffer = DataBuffer(
+ DataBuffer.TYPE_USHORT,
+ [np.array([0, 0xF81F, 0x07E0, 0, 0, 0x1234, 0xFFFF, 0], dtype=np.uint16)],
+ 8,
+ [2],
+ )
+
+ np.testing.assert_array_equal(
+ sample_model.as_numpy(data_buffer),
+ np.array([[[0, 0], [31, 0]], [[63, 0], [63, 0]], [[0, 0], [31, 0]]]),
+ )
+
+
+def test_multi_pixel_packed_applies_bit_and_bank_offsets() -> None:
+ # MultiPixelPackedSampleModel(TYPE_BYTE, 5, 2, 4, 4, 4) over DataBufferByte(bank, 9, {1}):
+ # four bits per pixel, with both the bank and the first scanline starting half a byte in
+ sample_model = MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE, 5, 2, 4, 4, 4)
+ data_buffer = DataBuffer(
+ DataBuffer.TYPE_BYTE,
+ [
+ np.array(
+ [0xFF, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x00],
+ dtype=np.uint8,
+ )
+ ],
+ 9,
+ [1],
+ )
+
+ np.testing.assert_array_equal(
+ sample_model.as_numpy(data_buffer),
+ np.array([[[1, 2, 3, 4, 5], [9, 10, 11, 12, 13]]]),
+ )
+
+
+def test_multi_pixel_packed_stays_within_the_bank() -> None:
Review Comment:
The new MultiPixelPackedSampleModel coverage only exercises data_bit_offset values that are multiples of num_bits (so each pixel fits within one element). A regression in the spanning-two-elements case (e.g., num_bits=4, data_bit_offset=2) would not be caught; adding a small unaligned-offset test would lock in the intended Java AWT behavior.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: issues-unsubscribe@sedona.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] [GH-3166] Resolve raster sample positions the way Java AWT does in the Python reader [sedona]
Posted by "jiayuasu (via GitHub)" <gi...@apache.org>.
jiayuasu commented on PR #3108:
URL: https://github.com/apache/sedona/pull/3108#issuecomment-5077076492
Both confirmed against the JDK and fixed in 642de29.
[P1] `MultiPixelPackedSampleModel(TYPE_INT, 3, 2, 32, 4, 0)` is accepted by Java and reads every pixel as zero, because `bitMask = (1 << 32) - 1` is evaluated on an int whose shift count is taken modulo 32. The mask is now derived as `(1 << (num_bits % 32)) - 1`, which reproduces that and leaves every other width alone (8 on byte and 16 on ushort still mask normally).
[P2] Java leaves the bit offset of a zero mask at 0 and reads the band as zero; `getBitOffsets()` returns `[16, 8, 0, 0]` for `{0xFF0000, 0xFF00, 0xFF, 0}`. The offset is now 0 for a zero mask. Worth noting the crash was numpy-2 only: on numpy 1.26 the `-1` shift happened to yield the right answer, so this would not have shown up in CI.
Rather than patch just these two, I swept both packed models over 1004 layouts recorded from `java.awt.image`: every `num_bits` that divides the sample size for byte, ushort and int samples, aligned and unaligned data bit offsets, zero and non-zero bank offsets, and mask sets covering zero masks, whole-sample masks and masks over the sign bit. All 1004 match on numpy 1.26 and 2.5, with numpy warnings raised as errors; 510 of them do not match on master. No third case of this kind is left.
One thing the sweep turned up: Java rejects non-contiguous bit masks in the `SinglePixelPackedSampleModel` constructor (`Mask 195 must be contiguous`), so those layouts cannot reach the reader and need no handling.
Two new regression tests cover P1 and P2 (`test_multi_pixel_packed_whole_sample_pixels_read_zero`, `test_single_pixel_packed_zero_mask_reads_zero`), taking their expected values from the same JDK run.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: issues-unsubscribe@sedona.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org