comparison tools/gfxconv.c @ 2487:14a4f8d78fe6

More work on image palette remapping functionality.
author Matti Hamalainen <ccr@tnsp.org>
date Tue, 28 Apr 2020 18:09:07 +0300
parents fce2ed3f681f
children 87c8be2bc8ba
comparison
equal deleted inserted replaced
2486:6d12670e0248 2487:14a4f8d78fe6
145 optRemapMatchAlpha = FALSE, 145 optRemapMatchAlpha = FALSE,
146 optUsePalette = FALSE; 146 optUsePalette = FALSE;
147 int optRemapMode = REMAP_NONE; 147 int optRemapMode = REMAP_NONE;
148 int optNRemapTable = 0, 148 int optNRemapTable = 0,
149 optScaleMode = SCALE_AUTO; 149 optScaleMode = SCALE_AUTO;
150 float optRemapMaxDist = 0; 150 float optRemapMaxDist = -1;
151 int optRemapFail = 0; 151 int optRemapNoMatchColor = -1;
152 DMMapValue optRemapTable[DM_MAX_COLORS]; 152 DMMapValue optRemapTable[DM_MAX_COLORS];
153 int optColorMap[D64_NCOLORS]; 153 int optColorMap[D64_NCOLORS];
154 char *optCharROMFilename = NULL; 154 char *optCharROMFilename = NULL;
155 DMC64Palette *optC64Palette = NULL; 155 DMC64Palette *optC64Palette = NULL;
156 char *optPaletteFile = NULL; 156 char *optPaletteFile = NULL;
1137 else 1137 else
1138 return FALSE; 1138 return FALSE;
1139 } 1139 }
1140 1140
1141 1141
1142 // XXX TODO: we need to evaluate the color vector itself, not just the distance
1142 float dmGetColorDist(const DMColor *c1, const DMColor *c2, const BOOL alpha) 1143 float dmGetColorDist(const DMColor *c1, const DMColor *c2, const BOOL alpha)
1143 { 1144 {
1144 const float 1145 const float
1145 dr = (c1->r - c2->r) / 255.0, 1146 dr = (c1->r - c2->r) / 255.0,
1146 dg = (c1->g - c2->g) / 255.0, 1147 dg = (c1->g - c2->g) / 255.0,
1240 } 1241 }
1241 1242
1242 1243
1243 int dmRemapImageColors(DMImage **pdst, const DMImage *src, 1244 int dmRemapImageColors(DMImage **pdst, const DMImage *src,
1244 const DMPalette *dpal, const BOOL alpha, 1245 const DMPalette *dpal, const BOOL alpha,
1245 const float maxDist, const int noMatch, 1246 const float maxDist, const int noMatchColor,
1246 const BOOL removeUnused) 1247 const BOOL removeUnused)
1247 { 1248 {
1248 DMPalette *tpal = NULL; 1249 DMPalette *tpal = NULL;
1249 const DMPalette *ppal; 1250 const DMPalette *ppal;
1250 BOOL *mapped = NULL, *used = NULL; 1251 BOOL *used = NULL;
1251 int *mapping = NULL; 1252 int *mapping = NULL, *mapped = NULL;
1252 int res = DMERR_OK; 1253 int res = DMERR_OK;
1254 BOOL fail = FALSE;
1253 1255
1254 if (pdst == NULL || src == NULL || dpal == NULL) 1256 if (pdst == NULL || src == NULL || dpal == NULL)
1255 return DMERR_NULLPTR; 1257 return DMERR_NULLPTR;
1256 1258
1257 if (src->pal == NULL || src->pixfmt != DM_PIXFMT_PALETTE) 1259 if (src->pal == NULL || src->pixfmt != DM_PIXFMT_PALETTE)
1259 res = dmError(DMERR_INVALID_DATA, 1261 res = dmError(DMERR_INVALID_DATA,
1260 "Source image is not paletted.\n"); 1262 "Source image is not paletted.\n");
1261 goto out; 1263 goto out;
1262 } 1264 }
1263 1265
1264 dmMsg(1, "Remapping image from %d to %d colors @ tolerance=%1.2f, %s%s.\n", 1266 dmMsg(1, "Remapping image from %d to %d colors @ maxDist=",
1265 src->pal->ncolors, 1267 src->pal->ncolors,
1266 dpal->ncolors, 1268 dpal->ncolors);
1267 maxDist < 0 ? 0 : maxDist, 1269
1268 alpha ? "match alpha" : "disregard alpha", 1270 if (maxDist < 0)
1269 noMatch < 0 ? ", fail on 'no match'" : ""); 1271 dmPrint(1, "auto");
1272 else
1273 dmPrint(1, "%1.3f", maxDist);
1274
1275 dmPrint(1, ", %s, ",
1276 alpha ? "match alpha" : "ignore alpha");
1277
1278 if (noMatchColor < 0)
1279 dmPrint(1, "fail on 'no match'\n");
1280 else
1281 dmPrint(1, "use color #%d if no match\n", noMatchColor);
1270 1282
1271 // Allocate remapping tables 1283 // Allocate remapping tables
1272 if ((mapped = dmMalloc0(src->pal->ncolors * sizeof(*mapped))) == NULL || 1284 if ((mapped = dmMalloc0(src->pal->ncolors * sizeof(*mapped))) == NULL ||
1273 (used = dmMalloc0(src->pal->ncolors * sizeof(*used))) == NULL || 1285 (used = dmMalloc0(src->pal->ncolors * sizeof(*used))) == NULL ||
1274 (mapping = dmMalloc(src->pal->ncolors * sizeof(*mapping))) == NULL) 1286 (mapping = dmMalloc(src->pal->ncolors * sizeof(*mapping))) == NULL)
1284 // Populate remap table 1296 // Populate remap table
1285 for (int sc = 0; sc < src->pal->ncolors; sc++) 1297 for (int sc = 0; sc < src->pal->ncolors; sc++)
1286 { 1298 {
1287 // Check if we can find a match in destination palette dpal 1299 // Check if we can find a match in destination palette dpal
1288 float closestDist = 1000000, dist = 0; 1300 float closestDist = 1000000, dist = 0;
1301 int closestDC = -1;
1289 1302
1290 for (int dc = 0; dc < dpal->ncolors; dc++) 1303 for (int dc = 0; dc < dpal->ncolors; dc++)
1291 { 1304 {
1292 if (maxDist < 0) 1305 dist = dmGetColorDist(&src->pal->colors[sc], &dpal->colors[dc], alpha);
1293 { 1306 if (dist < closestDist)
1294 if (dmExactCompareColor(&src->pal->colors[sc], &dpal->colors[dc], alpha)) 1307 {
1295 { 1308 closestDist = dist;
1296 mapping[sc] = dc; 1309 closestDC = dc;
1297 break; 1310 }
1298 } 1311 }
1312
1313 // Did we find a close-enough match?
1314 if (maxDist >= 0 && closestDist > maxDist)
1315 {
1316 // No, either error out or use noMatchColor color index
1317 if (noMatchColor < 0)
1318 {
1319 DMColor *dcol = &dpal->colors[closestDC];
1320
1321 dmPrint(0,
1322 "No match for source color #%d. Closest: #%d (%02x %02x %02x) [dist=%1.3f > %1.3f]\n",
1323 sc, closestDC, dcol->r, dcol->g, dcol->b,
1324 closestDist, maxDist);
1325 fail = TRUE;
1299 } 1326 }
1300 else 1327 else
1301 { 1328 {
1302 dist = dmGetColorDist(&src->pal->colors[sc], &dpal->colors[dc], alpha); 1329 closestDC = noMatchColor;
1303 if (dist < maxDist && dist < closestDist)
1304 {
1305 closestDist = dist;
1306 mapping[sc] = dc;
1307 }
1308 }
1309 }
1310
1311 // Did we find a match?
1312 if (mapping[sc] < 0)
1313 {
1314 // No, either error out or use noMatch color index
1315 if (noMatch < 0)
1316 {
1317 res = dmError(DMERR_INVALID_DATA,
1318 "Could not remap source color #%d, no matches found.\n",
1319 sc);
1320 goto out;
1321 }
1322 else
1323 {
1324 mapping[sc] = noMatch;
1325 } 1330 }
1326 } 1331 }
1327 else 1332 else
1328 { 1333 {
1329 DMColor *cs = &src->pal->colors[sc], 1334 DMColor *scol = &src->pal->colors[sc],
1330 *cd = &dpal->colors[mapping[sc]]; 1335 *dcol = &dpal->colors[closestDC];
1331 1336
1332 dmPrint(3, "Palette match #%d (%02x %02x %02x) -> #%d (%02x %02x %02x) [dist=%1.2f]\n", 1337 dmPrint(3, "Palette match #%d (%02x %02x %02x) -> #%d (%02x %02x %02x) [dist=%1.3f]\n",
1333 sc, cs->r, cs->g, cs->b, 1338 sc, scol->r, scol->g, scol->b,
1334 mapping[sc], cd->r, cd->g, cd->b, 1339 closestDC, dcol->r, dcol->g, dcol->b,
1335 closestDist); 1340 closestDist);
1336 } 1341 }
1342
1343 mapping[sc] = closestDC;
1344 }
1345
1346 if (fail)
1347 {
1348 res = DMERR_INVALID_DATA;
1349 goto out;
1337 } 1350 }
1338 1351
1339 // Remove unused colors if requested 1352 // Remove unused colors if requested
1340 if (removeUnused) 1353 if (removeUnused)
1341 { 1354 {
1342 // Get the actually used colors 1355 // Get the actually used colors
1343 int nused, nc; 1356 int nused;
1344 1357
1345 if ((res = dmScanUsedColors(src, TRUE, used, &nused)) != DMERR_OK) 1358 if ((res = dmScanUsedColors(src, TRUE, used, &nused)) != DMERR_OK)
1346 goto out; 1359 goto out;
1347 1360
1348 dmMsg(2, "Found %d used colors.\n", nused); 1361 dmMsg(2, "Found %d used color indices.\n", nused);
1362
1363 // Remove duplicates from the mapped colour indices
1364 for (int index = 0; index < src->pal->ncolors; index++)
1365 {
1366 for (int n = 0; n < src->pal->ncolors; n++)
1367 if (n != index &&
1368 mapping[index] == mapping[n] &&
1369 used[n] && used[index])
1370 {
1371 used[n] = FALSE;
1372 }
1373 }
1374
1375 // Re-count number of actually used indices
1376 nused = 0;
1377 for (int index = 0; index < src->pal->ncolors; index++)
1378 if (used[index])
1379 nused++;
1380
1381 dmMsg(2, "After mapped dupe removal, %d color indices used.\n", nused);
1349 1382
1350 if ((res = dmPaletteAlloc(&tpal, nused, -1)) != DMERR_OK) 1383 if ((res = dmPaletteAlloc(&tpal, nused, -1)) != DMERR_OK)
1351 { 1384 {
1352 dmErrorMsg("Could not allocate memory for remap palette.\n"); 1385 dmErrorMsg("Could not allocate memory for remap palette.\n");
1353 goto out; 1386 goto out;
1354 } 1387 }
1355 1388
1356 // Now, copy colors from dpal to tpal, re-mapping palette data 1389 // Copy colors from dpal to tpal, also mapping the reordered indices
1357 // and reorder the mapping indices to match it. 1390 nused = 0;
1358 nc = 0;
1359 for (int index = 0; index < src->pal->ncolors; index++) 1391 for (int index = 0; index < src->pal->ncolors; index++)
1360 if (used[index]) 1392 if (used[index])
1361 { 1393 {
1362 memcpy(&tpal->colors[nc], &dpal->colors[mapping[index]], sizeof(DMColor)); 1394 // Copy the color to tpal
1363 mapping[index] = nc; 1395 memcpy(&tpal->colors[nused], &dpal->colors[mapping[index]], sizeof(DMColor));
1364 nc++; 1396
1397 // Save current mapping to mapped[]
1398 mapped[nused] = mapping[index];
1399
1400 // Reorder the mapping
1401 mapping[index] = nused;
1402 nused++;
1403 }
1404 else
1405 {
1406 // "Unused" color, find matching mapping from mapped[]
1407 for (int n = 0; n < nused; n++)
1408 if (mapping[index] == mapped[n])
1409 {
1410 mapping[index] = n;
1411 break;
1412 }
1365 } 1413 }
1366 1414
1367 ppal = tpal; 1415 ppal = tpal;
1368 } 1416 }
1369 else 1417 else
1809 goto out; 1857 goto out;
1810 } 1858 }
1811 1859
1812 if ((res = dmRemapImageColors(&image, pimage, 1860 if ((res = dmRemapImageColors(&image, pimage,
1813 optPaletteData, optRemapMatchAlpha, 1861 optPaletteData, optRemapMatchAlpha,
1814 //optRemapMaxDist, optRemapFail, 1862 optRemapMaxDist, optRemapNoMatchColor,
1815 0.5, -1,
1816 optRemapRemove)) != DMERR_OK) 1863 optRemapRemove)) != DMERR_OK)
1817 goto out; 1864 goto out;
1818 1865
1819 allocated = TRUE; 1866 allocated = TRUE;
1820 break; 1867 break;