Added second attribute to avoid unstable nature of qsort

This commit is contained in:
Andrew Murray 2021-03-31 09:05:19 +11:00
parent 7387ec23ac
commit 6541bd7cb5
3 changed files with 55 additions and 11 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

@ -7,7 +7,12 @@ import pytest
from PIL import Image
from .helper import assert_image_equal, assert_image_similar, hopper
from .helper import (
assert_image_equal,
assert_image_equal_tofile,
assert_image_similar,
hopper,
)
class TestImagingCoreResize:
@ -135,6 +140,17 @@ class TestImagingCoreResize:
with pytest.raises(ValueError):
self.resize(hopper(), (10, 10), 9)
def test_cross_platform(self, tmp_path):
# This test is intended for only check for consistent behaviour across
# platforms. So if a future Pillow change requires that the test file
# be updated, that is okay.
im = hopper().resize((64, 64))
temp_file = str(tmp_path / "temp.gif")
im.save(temp_file)
with Image.open(temp_file) as reloaded:
assert_image_equal_tofile(reloaded, "Tests/images/hopper_resized.gif")
@pytest.fixture
def gradients_image():

View File

@ -753,11 +753,19 @@ annotate_hash_table(BoxNode *n, HashTable *h, uint32_t *box) {
return 1;
}
typedef struct {
uint32_t *distance;
uint32_t index;
} DistanceWithIndex;
static int
_sort_ulong_ptr_keys(const void *a, const void *b) {
uint32_t A = **(uint32_t **)a;
uint32_t B = **(uint32_t **)b;
return (A == B) ? 0 : ((A < B) ? -1 : +1);
DistanceWithIndex *A = (DistanceWithIndex *)a;
DistanceWithIndex *B = (DistanceWithIndex *)b;
if (*A->distance == *B->distance) {
return A->index < B->index ? -1 : +1;
}
return *A->distance < *B->distance ? -1 : +1;
}
static int
@ -793,24 +801,42 @@ static int
build_distance_tables(
uint32_t *avgDist, uint32_t **avgDistSortKey, Pixel *p, uint32_t nEntries) {
uint32_t i, j;
DistanceWithIndex *dwi;
dwi = calloc(nEntries * nEntries, sizeof(DistanceWithIndex));
if (!dwi) {
return 0;
}
for (i = 0; i < nEntries; i++) {
avgDist[i * nEntries + i] = 0;
avgDistSortKey[i * nEntries + i] = &(avgDist[i * nEntries + i]);
dwi[i * nEntries + i] = (DistanceWithIndex){
&(avgDist[i * nEntries + i]),
i * nEntries + i
};
for (j = 0; j < i; j++) {
avgDist[j * nEntries + i] = avgDist[i * nEntries + j] =
_DISTSQR(p + i, p + j);
avgDistSortKey[j * nEntries + i] = &(avgDist[j * nEntries + i]);
avgDistSortKey[i * nEntries + j] = &(avgDist[i * nEntries + j]);
dwi[j * nEntries + i] = (DistanceWithIndex){
&(avgDist[j * nEntries + i]),
j * nEntries + i
};
dwi[i * nEntries + j] = (DistanceWithIndex){
&(avgDist[i * nEntries + j]),
i * nEntries + j
};
}
}
for (i = 0; i < nEntries; i++) {
qsort(
avgDistSortKey + i * nEntries,
dwi + i * nEntries,
nEntries,
sizeof(uint32_t *),
sizeof(DistanceWithIndex),
_sort_ulong_ptr_keys);
for (j = 0; j < nEntries; j++) {
avgDistSortKey[i * nEntries + j] = dwi[i * nEntries + j].distance;
}
}
free(dwi);
return 1;
}
@ -1176,8 +1202,10 @@ k_means(
if (!built) {
compute_palette_from_quantized_pixels(
pixelData, nPixels, paletteData, nPaletteEntries, avg, count, qp);
build_distance_tables(
avgDist, avgDistSortKey, paletteData, nPaletteEntries);
if (!build_distance_tables(
avgDist, avgDistSortKey, paletteData, nPaletteEntries)) {
goto error_3;
}
built = 1;
} else {
recompute_palette_from_averages(paletteData, nPaletteEntries, avg, count);