# HG changeset patch # User Matti Hamalainen # Date 1588086547 -10800 # Node ID 14a4f8d78fe65024caabb317798b243424267e7f # Parent 6d12670e0248d7b989fd7f04d563279f1da6b875 More work on image palette remapping functionality. diff -r 6d12670e0248 -r 14a4f8d78fe6 tools/gfxconv.c --- a/tools/gfxconv.c Tue Apr 28 14:45:44 2020 +0300 +++ b/tools/gfxconv.c Tue Apr 28 18:09:07 2020 +0300 @@ -147,8 +147,8 @@ int optRemapMode = REMAP_NONE; int optNRemapTable = 0, optScaleMode = SCALE_AUTO; -float optRemapMaxDist = 0; -int optRemapFail = 0; +float optRemapMaxDist = -1; +int optRemapNoMatchColor = -1; DMMapValue optRemapTable[DM_MAX_COLORS]; int optColorMap[D64_NCOLORS]; char *optCharROMFilename = NULL; @@ -1139,6 +1139,7 @@ } +// XXX TODO: we need to evaluate the color vector itself, not just the distance float dmGetColorDist(const DMColor *c1, const DMColor *c2, const BOOL alpha) { const float @@ -1242,14 +1243,15 @@ int dmRemapImageColors(DMImage **pdst, const DMImage *src, const DMPalette *dpal, const BOOL alpha, - const float maxDist, const int noMatch, + const float maxDist, const int noMatchColor, const BOOL removeUnused) { DMPalette *tpal = NULL; const DMPalette *ppal; - BOOL *mapped = NULL, *used = NULL; - int *mapping = NULL; + BOOL *used = NULL; + int *mapping = NULL, *mapped = NULL; int res = DMERR_OK; + BOOL fail = FALSE; if (pdst == NULL || src == NULL || dpal == NULL) return DMERR_NULLPTR; @@ -1261,12 +1263,22 @@ goto out; } - dmMsg(1, "Remapping image from %d to %d colors @ tolerance=%1.2f, %s%s.\n", + dmMsg(1, "Remapping image from %d to %d colors @ maxDist=", src->pal->ncolors, - dpal->ncolors, - maxDist < 0 ? 0 : maxDist, - alpha ? "match alpha" : "disregard alpha", - noMatch < 0 ? ", fail on 'no match'" : ""); + dpal->ncolors); + + if (maxDist < 0) + dmPrint(1, "auto"); + else + dmPrint(1, "%1.3f", maxDist); + + dmPrint(1, ", %s, ", + alpha ? "match alpha" : "ignore alpha"); + + if (noMatchColor < 0) + dmPrint(1, "fail on 'no match'\n"); + else + dmPrint(1, "use color #%d if no match\n", noMatchColor); // Allocate remapping tables if ((mapped = dmMalloc0(src->pal->ncolors * sizeof(*mapped))) == NULL || @@ -1286,66 +1298,87 @@ { // Check if we can find a match in destination palette dpal float closestDist = 1000000, dist = 0; + int closestDC = -1; for (int dc = 0; dc < dpal->ncolors; dc++) { - if (maxDist < 0) + dist = dmGetColorDist(&src->pal->colors[sc], &dpal->colors[dc], alpha); + if (dist < closestDist) { - if (dmExactCompareColor(&src->pal->colors[sc], &dpal->colors[dc], alpha)) - { - mapping[sc] = dc; - break; - } + closestDist = dist; + closestDC = dc; + } + } + + // Did we find a close-enough match? + if (maxDist >= 0 && closestDist > maxDist) + { + // No, either error out or use noMatchColor color index + if (noMatchColor < 0) + { + DMColor *dcol = &dpal->colors[closestDC]; + + dmPrint(0, + "No match for source color #%d. Closest: #%d (%02x %02x %02x) [dist=%1.3f > %1.3f]\n", + sc, closestDC, dcol->r, dcol->g, dcol->b, + closestDist, maxDist); + fail = TRUE; } else { - dist = dmGetColorDist(&src->pal->colors[sc], &dpal->colors[dc], alpha); - if (dist < maxDist && dist < closestDist) - { - closestDist = dist; - mapping[sc] = dc; - } - } - } - - // Did we find a match? - if (mapping[sc] < 0) - { - // No, either error out or use noMatch color index - if (noMatch < 0) - { - res = dmError(DMERR_INVALID_DATA, - "Could not remap source color #%d, no matches found.\n", - sc); - goto out; - } - else - { - mapping[sc] = noMatch; + closestDC = noMatchColor; } } else { - DMColor *cs = &src->pal->colors[sc], - *cd = &dpal->colors[mapping[sc]]; - - dmPrint(3, "Palette match #%d (%02x %02x %02x) -> #%d (%02x %02x %02x) [dist=%1.2f]\n", - sc, cs->r, cs->g, cs->b, - mapping[sc], cd->r, cd->g, cd->b, + DMColor *scol = &src->pal->colors[sc], + *dcol = &dpal->colors[closestDC]; + + dmPrint(3, "Palette match #%d (%02x %02x %02x) -> #%d (%02x %02x %02x) [dist=%1.3f]\n", + sc, scol->r, scol->g, scol->b, + closestDC, dcol->r, dcol->g, dcol->b, closestDist); } + + mapping[sc] = closestDC; + } + + if (fail) + { + res = DMERR_INVALID_DATA; + goto out; } // Remove unused colors if requested if (removeUnused) { // Get the actually used colors - int nused, nc; + int nused; if ((res = dmScanUsedColors(src, TRUE, used, &nused)) != DMERR_OK) goto out; - dmMsg(2, "Found %d used colors.\n", nused); + dmMsg(2, "Found %d used color indices.\n", nused); + + // Remove duplicates from the mapped colour indices + for (int index = 0; index < src->pal->ncolors; index++) + { + for (int n = 0; n < src->pal->ncolors; n++) + if (n != index && + mapping[index] == mapping[n] && + used[n] && used[index]) + { + used[n] = FALSE; + } + } + + // Re-count number of actually used indices + nused = 0; + for (int index = 0; index < src->pal->ncolors; index++) + if (used[index]) + nused++; + + dmMsg(2, "After mapped dupe removal, %d color indices used.\n", nused); if ((res = dmPaletteAlloc(&tpal, nused, -1)) != DMERR_OK) { @@ -1353,15 +1386,30 @@ goto out; } - // Now, copy colors from dpal to tpal, re-mapping palette data - // and reorder the mapping indices to match it. - nc = 0; + // Copy colors from dpal to tpal, also mapping the reordered indices + nused = 0; for (int index = 0; index < src->pal->ncolors; index++) if (used[index]) { - memcpy(&tpal->colors[nc], &dpal->colors[mapping[index]], sizeof(DMColor)); - mapping[index] = nc; - nc++; + // Copy the color to tpal + memcpy(&tpal->colors[nused], &dpal->colors[mapping[index]], sizeof(DMColor)); + + // Save current mapping to mapped[] + mapped[nused] = mapping[index]; + + // Reorder the mapping + mapping[index] = nused; + nused++; + } + else + { + // "Unused" color, find matching mapping from mapped[] + for (int n = 0; n < nused; n++) + if (mapping[index] == mapped[n]) + { + mapping[index] = n; + break; + } } ppal = tpal; @@ -1811,8 +1859,7 @@ if ((res = dmRemapImageColors(&image, pimage, optPaletteData, optRemapMatchAlpha, - //optRemapMaxDist, optRemapFail, - 0.5, -1, + optRemapMaxDist, optRemapNoMatchColor, optRemapRemove)) != DMERR_OK) goto out;