comparison tools/gfxconv.c @ 2481:f3d9cdb0a295

Some work towards more flexible palette remapping.
author Matti Hamalainen <ccr@tnsp.org>
date Tue, 28 Apr 2020 00:47:06 +0300
parents 16c57206cef7
children 2d60e112255e
comparison
equal deleted inserted replaced
2480:c7a0913e1032 2481:f3d9cdb0a295
75 SCALE_RELATIVE, 75 SCALE_RELATIVE,
76 SCALE_AUTO, 76 SCALE_AUTO,
77 }; 77 };
78 78
79 79
80 enum
81 {
82 REMAP_NONE = 0,
83 REMAP_AUTO,
84 REMAP_MAPPED,
85 };
86
80 typedef struct 87 typedef struct
81 { 88 {
82 char *name; // Descriptive name of the format 89 char *name; // Descriptive name of the format
83 char *fext; // File extension 90 char *fext; // File extension
84 int flags; // DM_FMT_* flags, see libgfx.h 91 int flags; // DM_FMT_* flags, see libgfx.h
132 optCropX0, optCropY0, 139 optCropX0, optCropY0,
133 optCropW, optCropH; 140 optCropW, optCropH;
134 141
135 BOOL optInMulticolor = FALSE, 142 BOOL optInMulticolor = FALSE,
136 optSequential = FALSE, 143 optSequential = FALSE,
137 optRemapColors = FALSE,
138 optRemapRemove = FALSE, 144 optRemapRemove = FALSE,
145 optRemapMatchAlpha = FALSE,
139 optUsePalette = FALSE; 146 optUsePalette = FALSE;
147 int optRemapMode = REMAP_NONE;
140 int optNRemapTable = 0, 148 int optNRemapTable = 0,
141 optScaleMode = SCALE_AUTO; 149 optScaleMode = SCALE_AUTO;
150 float optRemapMaxDist = 0;
151 int optRemapFail = 0;
142 DMMapValue optRemapTable[DM_MAX_COLORS]; 152 DMMapValue optRemapTable[DM_MAX_COLORS];
143 int optColorMap[D64_NCOLORS]; 153 int optColorMap[D64_NCOLORS];
144 char *optCharROMFilename = NULL; 154 char *optCharROMFilename = NULL;
145 DMC64Palette *optC64Palette = NULL; 155 DMC64Palette *optC64Palette = NULL;
146 char *optPaletteFile = NULL; 156 char *optPaletteFile = NULL;
182 { 34, 'B', "bpp" , "Bits per plane (some output formats)", OPT_ARGREQ }, 192 { 34, 'B', "bpp" , "Bits per plane (some output formats)", OPT_ARGREQ },
183 { 36, 'I', "interleave" , "Interleaved/planar output (some output formats)", OPT_NONE }, 193 { 36, 'I', "interleave" , "Interleaved/planar output (some output formats)", OPT_NONE },
184 { 38, 'C', "compress" , "Use compression -C <0-9>, 0 = disable, default is 9", OPT_ARGREQ }, 194 { 38, 'C', "compress" , "Use compression -C <0-9>, 0 = disable, default is 9", OPT_ARGREQ },
185 { 42, 'R', "remap" , "Remap output image colors (-R <(#RRGGBB|index):index>[,<..>][+remove] | -R auto[+remove] | -R @map.txt[+remove])", OPT_ARGREQ }, 195 { 42, 'R', "remap" , "Remap output image colors (-R <(#RRGGBB|index):index>[,<..>][+remove] | -R auto[+remove] | -R @map.txt[+remove])", OPT_ARGREQ },
186 { 44, 0, "char-rom" , "Set character ROM file to be used.", OPT_ARGREQ }, 196 { 44, 0, "char-rom" , "Set character ROM file to be used.", OPT_ARGREQ },
187 { 46, 'p', "palette" , "Set C64 palette to be used (see list with -p help).", OPT_ARGREQ }, 197 { 46, 'p', "palette" , "Set palette to be used (see list with -p help). "
198 "For paletted image file input, this will replace the "
199 "image's original palette. Color remapping will not be "
200 "done unless -R option is also specified.", OPT_ARGREQ },
188 }; 201 };
189 202
190 static const int optListN = sizeof(optList) / sizeof(optList[0]); 203 static const int optListN = sizeof(optList) / sizeof(optList[0]);
191 204
192 205
930 } 943 }
931 } 944 }
932 break; 945 break;
933 946
934 case 42: 947 case 42:
935 if ((tmpStr = dm_strrcasecmp(optArg, "+remove")) != NULL) 948 while ((tmpStr = strchr(optArg, '+')) != NULL)
936 { 949 {
937 optRemapRemove = TRUE; 950 char *topt = tmpStr + 1,
951 *tend = strchr(topt, '+');
952
938 *tmpStr = 0; 953 *tmpStr = 0;
939 } 954 if (tend != NULL)
940 955 {
941 if (optArg[0] == '@') 956 *tend = 0;
942 { 957 tmpStr = tend + 1;
943 if (optArg[1] != 0) 958 }
944 { 959 else
945 int res; 960 tmpStr = tend;
946 if ((res = dmParseColorRemapFile(optArg + 1, 961
947 optRemapTable, &optNRemapTable, DM_MAX_COLORS)) != DMERR_OK) 962 if (strcasecmp(topt, "remove") == 0)
963 optRemapRemove = TRUE;
964 else
965 if (strcasecmp(topt, "alpha") == 0)
966 optRemapMatchAlpha = TRUE;
967 else
968 {
969 dmErrorMsg("Unknown -R option flag '%s'.\n", topt);
970 return FALSE;
971 }
972 }
973
974 if (strcasecmp(optArg, "auto") == 0)
975 {
976 if (optRemapMode != REMAP_NONE && optRemapMode != REMAP_AUTO)
977 {
978 dmErrorMsg("Remap mode already set to something else than 'auto'. You can only have one remapping mode.\n");
979 return FALSE;
980 }
981
982 // Check if we have more?
983 if (optArg[4] == ':')
984 {
985 }
986
987 optRemapMode = REMAP_AUTO;
988 }
989 else
990 {
991 if (optRemapMode != REMAP_NONE && optRemapMode != REMAP_MAPPED)
992 {
993 dmErrorMsg("Remap mode already set to something else than 'mapped'. You can only have one remapping mode.\n");
994 return FALSE;
995 }
996
997 if (optArg[0] == '@')
998 {
999 if (optArg[1] != 0)
1000 {
1001 int res;
1002 if ((res = dmParseColorRemapFile(optArg + 1,
1003 optRemapTable, &optNRemapTable, DM_MAX_COLORS)) != DMERR_OK)
1004 return FALSE;
1005 }
1006 else
1007 {
1008 dmErrorMsg("No remap filename given.\n");
948 return FALSE; 1009 return FALSE;
1010 }
949 } 1011 }
950 else 1012 else
951 { 1013 {
952 dmErrorMsg("No remap filename given.\n"); 1014 if (!dmParseMapOptionString(optArg, optRemapTable,
953 return FALSE; 1015 &optNRemapTable, DM_MAX_COLORS, TRUE, "color remap option"))
954 } 1016 return FALSE;
955 } 1017 }
956 else 1018
957 if (dm_strcasecmp(optArg, "auto") != 0) 1019 optRemapMode = REMAP_MAPPED;
958 { 1020 }
959 if (!dmParseMapOptionString(optArg, optRemapTable, 1021
960 &optNRemapTable, DM_MAX_COLORS, TRUE, "color remap option")) 1022 if (optRemapMatchAlpha)
961 return FALSE; 1023 {
962 } 1024 dmErrorMsg("WARNING: Palette alpha matching may have unexpected results.\n");
963 1025 }
964 optRemapColors = TRUE;
965 break; 1026 break;
966 1027
967 case 44: 1028 case 44:
968 optCharROMFilename = optArg; 1029 optCharROMFilename = optArg;
969 break; 1030 break;
1076 else 1137 else
1077 return FALSE; 1138 return FALSE;
1078 } 1139 }
1079 1140
1080 1141
1081 int dmRemoveUnusedImageColors(DMImage **pdst, const DMImage *src) 1142 float dmGetColorDist(const DMColor *c1, const DMColor *c2, const BOOL alpha)
1082 { 1143 {
1083 DMPalette *tmpPal = NULL; 1144 const float
1084 int *mapping = dmMalloc(src->pal->ncolors * sizeof(int)); 1145 dr = (c1->r - c2->r) / 255.0,
1085 BOOL *mapped = dmMalloc(src->pal->ncolors * sizeof(BOOL)); 1146 dg = (c1->g - c2->g) / 255.0,
1086 BOOL *used = dmMalloc(src->pal->ncolors * sizeof(BOOL)); 1147 db = (c1->b - c2->b) / 255.0;
1087 int n, index, xc, yc, ncolors, res = DMERR_OK; 1148
1088 DMImage *dst; 1149 if (alpha)
1089 1150 {
1090 if (mapping == NULL || mapped == NULL || used == NULL) 1151 const float da = (c1->a - c2->a) / 255.0;
1152 return (dr * dr + dg * dg + db * db + da * da) / 4.0;
1153 }
1154 else
1155 return (dr * dr + dg * dg + db * db) / 3.0;
1156 }
1157
1158
1159 int dmScanUsedColors(const DMImage *src, const BOOL warn, BOOL *used, int *nused)
1160 {
1161 BOOL warned = FALSE;
1162 *nused = 0;
1163
1164 if (src == NULL || used == NULL || nused == NULL)
1165 return DMERR_NULLPTR;
1166
1167 if (src->pal == NULL || src->pixfmt != DM_PIXFMT_PALETTE)
1168 {
1169 return dmError(DMERR_INVALID_DATA,
1170 "Source image is not paletted.\n");
1171 }
1172
1173 for (int index = 0; index < src->pal->ncolors; index++)
1174 used[index] = FALSE;
1175
1176 for (int yc = 0; yc < src->height; yc++)
1177 {
1178 const Uint8 *dp = src->data + src->pitch * yc;
1179 for (int xc = 0; xc < src->width; xc++)
1180 {
1181 Uint8 col = dp[xc];
1182 if (col < src->pal->ncolors)
1183 {
1184 if (!used[col])
1185 {
1186 used[col] = TRUE;
1187 (*nused)++;
1188 }
1189 }
1190 else
1191 if (warn && !warned)
1192 {
1193 dmErrorMsg("Image contains color indices that are out of bounds of the palette.\n");
1194 warned = TRUE;
1195 }
1196 }
1197 }
1198
1199 return DMERR_OK;
1200 }
1201
1202
1203 int dmDoRemapImageColors(DMImage **pdst, const DMImage *src,
1204 const int *mapping, const DMPalette *dpal)
1205 {
1206 DMImage *dst = NULL;
1207 int res = DMERR_OK;
1208
1209 if (pdst == NULL || src == NULL || mapping == NULL)
1210 return DMERR_NULLPTR;
1211
1212 // Allocate target image
1213 if ((dst = *pdst = dmImageAlloc(src->width, src->height,
1214 src->pixfmt, -1)) == NULL)
1091 { 1215 {
1092 res = dmError(DMERR_MALLOC, 1216 res = dmError(DMERR_MALLOC,
1093 "Could not allocate memory for reused palette.\n"); 1217 "Could not allocate image for re-mapped data.\n");
1094 goto out; 1218 goto out;
1095 } 1219 }
1096 1220
1097 if ((res = dmPaletteAlloc(&tmpPal, src->pal->ncolors, -1)) != DMERR_OK) 1221 for (int yc = 0; yc < src->height; yc++)
1222 {
1223 Uint8 *sp = src->data + src->pitch * yc;
1224 Uint8 *dp = dst->data + dst->pitch * yc;
1225 for (int xc = 0; xc < src->width; xc++)
1226 {
1227 dp[xc] = mapping[sp[xc]];
1228 }
1229 }
1230
1231 if ((res = dmPaletteCopy(&dst->pal, dpal)) != DMERR_OK)
1232 {
1233 dmErrorMsg("Error installing remapped palette to destination image: %s\n",
1234 dmErrorStr(res));
1235 goto out;
1236 }
1237
1238 out:
1239 return res;
1240 }
1241
1242
1243 int dmRemapImageColors(DMImage **pdst, const DMImage *src,
1244 const DMPalette *dpal, const BOOL alpha,
1245 const float maxDist, const int noMatch,
1246 const BOOL removeUnused)
1247 {
1248 DMPalette *tpal = NULL;
1249 const DMPalette *ppal;
1250 BOOL *mapped = NULL, *used = NULL;
1251 int *mapping = NULL;
1252 int res = DMERR_OK;
1253
1254 if (pdst == NULL || src == NULL || dpal == NULL)
1255 return DMERR_NULLPTR;
1256
1257 if (src->pal == NULL || src->pixfmt != DM_PIXFMT_PALETTE)
1258 {
1259 res = dmError(DMERR_INVALID_DATA,
1260 "Source image is not paletted.\n");
1261 goto out;
1262 }
1263
1264 dmMsg(1, "Remapping image from %d to %d colors @ tolerance=%1.2f, %s%s.\n",
1265 src->pal->ncolors,
1266 dpal->ncolors,
1267 maxDist < 0 ? 0 : maxDist,
1268 alpha ? "match alpha" : "disregard alpha",
1269 noMatch < 0 ? ", fail on 'no match'" : "");
1270
1271 // Allocate remapping tables
1272 if ((mapped = dmMalloc0(src->pal->ncolors * sizeof(*mapped))) == NULL ||
1273 (used = dmMalloc0(src->pal->ncolors * sizeof(*used))) == NULL ||
1274 (mapping = dmMalloc(src->pal->ncolors * sizeof(*mapping))) == NULL)
1275 {
1276 res = dmError(DMERR_MALLOC,
1277 "Could not allocate memory for color remap tables.\n");
1278 goto out;
1279 }
1280
1281 for (int index = 0; index < src->pal->ncolors; index++)
1282 mapping[index] = -1;
1283
1284 // Populate remap table
1285 for (int sc = 0; sc < src->pal->ncolors; sc++)
1286 {
1287 // Check if we can find a match in destination palette dpal
1288 float closestDist = 1000000, dist = 0;
1289
1290 for (int dc = 0; dc < dpal->ncolors; dc++)
1291 {
1292 if (maxDist < 0)
1293 {
1294 if (dmExactCompareColor(&src->pal->colors[sc], &dpal->colors[dc], alpha))
1295 {
1296 mapping[sc] = dc;
1297 break;
1298 }
1299 }
1300 else
1301 {
1302 dist = dmGetColorDist(&src->pal->colors[sc], &dpal->colors[dc], alpha);
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 }
1326 }
1327 else
1328 {
1329 DMColor *cs = &src->pal->colors[sc],
1330 *cd = &dpal->colors[mapping[sc]];
1331
1332 dmPrint(3, "Palette match #%d (%02x %02x %02x) -> #%d (%02x %02x %02x) [dist=%1.2f]\n",
1333 sc, cs->r, cs->g, cs->b,
1334 mapping[sc], cd->r, cd->g, cd->b,
1335 closestDist);
1336 }
1337 }
1338
1339 // Remove unused colors if requested
1340 if (removeUnused)
1341 {
1342 // Get the actually used colors
1343 int nused, nc;
1344
1345 if ((res = dmScanUsedColors(src, TRUE, used, &nused)) != DMERR_OK)
1346 goto out;
1347
1348 dmMsg(2, "Found %d used colors.\n", nused);
1349
1350 if ((res = dmPaletteAlloc(&tpal, nused, -1)) != DMERR_OK)
1351 {
1352 dmErrorMsg("Could not allocate memory for remap palette.\n");
1353 goto out;
1354 }
1355
1356 // Now, copy colors from dpal to tpal, re-mapping palette data
1357 // and reorder the mapping indices to match it.
1358 nc = 0;
1359 for (int index = 0; index < src->pal->ncolors; index++)
1360 if (used[index])
1361 {
1362 memcpy(&tpal->colors[nc], &dpal->colors[mapping[index]], sizeof(DMColor));
1363 mapping[index] = nc;
1364 nc++;
1365 }
1366
1367 ppal = tpal;
1368 }
1369 else
1370 ppal = dpal;
1371
1372 // Perform image data remapping
1373 res = dmDoRemapImageColors(pdst, src, mapping, ppal);
1374
1375 out:
1376 dmFree(tpal);
1377 dmFree(mapping);
1378 dmFree(mapped);
1379 dmFree(used);
1380 return res;
1381 }
1382
1383
1384 int dmMapImageColors(DMImage **pdst, const DMImage *src,
1385 const DMMapValue *mapTable, const int nmapTable,
1386 const BOOL removeUnused)
1387 {
1388 DMPalette *tpal = NULL;
1389 BOOL *mapped = NULL, *used = NULL;
1390 int *mapping = NULL;
1391 int nused, res = DMERR_OK;
1392
1393 if (pdst == NULL || src == NULL || mapTable == NULL)
1394 return DMERR_NULLPTR;
1395
1396 if (src->pal == NULL || src->pixfmt != DM_PIXFMT_PALETTE)
1397 {
1398 res = dmError(DMERR_INVALID_DATA,
1399 "Source image is not paletted.\n");
1400 goto out;
1401 }
1402
1403 // Allocate remapping tables
1404 if ((mapped = dmMalloc(src->pal->ncolors * sizeof(*mapped))) == NULL ||
1405 (used = dmMalloc(src->pal->ncolors * sizeof(*used))) == NULL ||
1406 (mapping = dmMalloc(src->pal->ncolors * sizeof(*mapping))) == NULL)
1407 {
1408 res = dmError(DMERR_MALLOC,
1409 "Could not allocate memory for color remap tables.\n");
1410 goto out;
1411 }
1412
1413 for (int index = 0; index < src->pal->ncolors; index++)
1414 {
1415 mapping[index] = -1;
1416 mapped[index] = FALSE;
1417 }
1418
1419 if ((res = dmPaletteAlloc(&tpal, src->pal->ncolors, -1)) != DMERR_OK)
1098 { 1420 {
1099 dmErrorMsg("Could not allocate memory for remap palette.\n"); 1421 dmErrorMsg("Could not allocate memory for remap palette.\n");
1100 goto out; 1422 goto out;
1101 } 1423 }
1102 1424
1103 if ((dst = *pdst = dmImageAlloc(src->width, src->height, src->pixfmt, src->bpp)) == NULL) 1425 dmMsg(1, "Remapping %d input image of %d colors.\n",
1104 {
1105 res = dmError(DMERR_MALLOC,
1106 "Could not allocate memory for remapped image.\n");
1107 goto out;
1108 }
1109
1110 dmMsg(1, "Remapping %d output image colors of %d colors.\n",
1111 optNRemapTable, src->pal->ncolors); 1426 optNRemapTable, src->pal->ncolors);
1112 1427
1113
1114 // Find used colors
1115 dmMsg(2, "Scanning image for used colors...\n");
1116 for (index = 0; index < src->pal->ncolors; index++)
1117 {
1118 mapping[index] = -1;
1119 mapped[index] = used[index] = FALSE;
1120 }
1121
1122 for (ncolors = yc = 0; yc < src->height; yc++)
1123 {
1124 const Uint8 *dp = src->data + src->pitch * yc;
1125 for (xc = 0; xc < src->width; xc++)
1126 {
1127 Uint8 col = dp[xc];
1128 if (col < src->pal->ncolors && !used[col])
1129 {
1130 used[col] = TRUE;
1131 ncolors++;
1132 }
1133 }
1134 }
1135 dmMsg(2, "Found %d used colors, creating remap-table.\n", ncolors);
1136
1137 // Match and mark mapped colors 1428 // Match and mark mapped colors
1138 for (index = 0; index < optNRemapTable; index++) 1429 for (int index = 0; index < nmapTable; index++)
1139 { 1430 {
1140 DMMapValue *map = &optRemapTable[index]; 1431 const DMMapValue *map = &mapTable[index];
1141 if (map->triplet) 1432 if (map->triplet)
1142 { 1433 {
1143 BOOL found = FALSE; 1434 BOOL found = FALSE;
1144 for (n = 0; n < src->pal->ncolors; n++) 1435 for (int n = 0; n < src->pal->ncolors; n++)
1145 { 1436 {
1146 if (dmExactCompareColor(&(src->pal->colors[n]), &(map->color), map->alpha)) 1437 if (dmExactCompareColor(&src->pal->colors[n], &map->color, map->alpha))
1147 { 1438 {
1148 dmMsg(3, "RGBA match #%02x%02x%02x%02x: %d -> %d\n", 1439 dmMsg(3, "RGBA match #%02x%02x%02x%02x: %d -> %d\n",
1149 map->color.r, map->color.g, map->color.b, map->color.a, 1440 map->color.r, map->color.g, map->color.b, map->color.a,
1150 n, 1441 n,
1151 map->to); 1442 map->to);
1171 mapping[map->from] = map->to; 1462 mapping[map->from] = map->to;
1172 mapped[map->to] = TRUE; 1463 mapped[map->to] = TRUE;
1173 } 1464 }
1174 } 1465 }
1175 1466
1176 // Fill in the rest 1467 // Fill the unmapped colors
1177 if (optRemapRemove) 1468 if (removeUnused)
1178 dmMsg(2, "Removing unused colors.\n"); 1469 {
1179 1470 dmMsg(2, "Scanning for used colors.\n");
1180 for (index = 0; index < src->pal->ncolors; index++) 1471
1472 if ((res = dmScanUsedColors(src, TRUE, used, &nused)) != DMERR_OK)
1473 goto out;
1474
1475 dmMsg(2, "Removing unused colors: %d -> %d.\n",
1476 src->pal->ncolors, nused);
1477 }
1478
1479 for (int index = 0; index < src->pal->ncolors; index++)
1181 if (mapping[index] < 0 && 1480 if (mapping[index] < 0 &&
1182 (!optRemapRemove || (optRemapRemove && used[index]))) 1481 (!removeUnused || used[index]))
1183 { 1482 {
1184 for (n = 0; n < src->pal->ncolors; n++) 1483 for (int n = 0; n < src->pal->ncolors; n++)
1185 if (!mapped[n]) 1484 if (!mapped[n])
1186 { 1485 {
1187 mapping[index] = n; 1486 mapping[index] = n;
1188 mapped[n] = TRUE; 1487 mapped[n] = TRUE;
1189 break; 1488 break;
1190 } 1489 }
1191 } 1490 }
1192 1491
1193 // Calculate final number of palette colors 1492 // Copy mapped palette entries
1194 ncolors = 0; 1493 for (int index = 0; index < src->pal->ncolors; index++)
1195 for (index = 0; index < src->pal->ncolors; index++) 1494 if (mapping[index] >= 0)
1196 { 1495 {
1197 if (mapping[index] + 1 > ncolors) 1496 memcpy(&tpal->colors[mapping[index]], &src->pal->colors[index], sizeof(DMColor));
1198 ncolors = mapping[index] + 1; 1497 }
1199 } 1498
1200 1499 // Perform image data remapping
1201 // Copy palette entries 1500 res = dmDoRemapImageColors(pdst, src, mapping, tpal);
1202 for (index = 0; index < src->pal->ncolors; index++)
1203 {
1204 if (mapping[index] >= 0)
1205 {
1206 memcpy(&tmpPal->colors[mapping[index]], &(src->pal->colors[index]), sizeof(DMColor));
1207 }
1208 }
1209
1210 // Remap image
1211 dmMsg(1, "Remapping image to %d colors...\n", ncolors);
1212 for (yc = 0; yc < src->height; yc++)
1213 {
1214 Uint8 *sp = src->data + src->pitch * yc;
1215 Uint8 *dp = dst->data + dst->pitch * yc;
1216 for (xc = 0; xc < src->width; xc++)
1217 {
1218 Uint8 col = sp[xc];
1219 if (col < src->pal->ncolors &&
1220 mapping[col] >= 0 &&
1221 mapping[col] < src->pal->ncolors)
1222 dp[xc] = mapping[col];
1223 else
1224 dp[xc] = 0;
1225 }
1226 }
1227
1228 // Set new palette, free memory
1229 if ((res = dmPaletteCopy(&dst->pal, tmpPal)) != DMERR_OK)
1230 {
1231 res = dmError(DMERR_MALLOC,
1232 "Could not allocate memory for final remapped palette.\n");
1233 goto out;
1234 }
1235 1501
1236 out: 1502 out:
1503 dmPaletteFree(tpal);
1237 dmFree(mapping); 1504 dmFree(mapping);
1238 dmFree(mapped); 1505 dmFree(mapped);
1239 dmFree(used); 1506 dmFree(used);
1240 return res; 1507 return res;
1241 } 1508 }
1464 int res; 1731 int res;
1465 1732
1466 if ((res = dmf_open_stdio(hdrFilename, "wb", &fp)) != DMERR_OK) 1733 if ((res = dmf_open_stdio(hdrFilename, "wb", &fp)) != DMERR_OK)
1467 { 1734 {
1468 return dmError(res, 1735 return dmError(res,
1469 "RAW: Could not open file '%s' for writing: %s\n", 1736 "Could not open file '%s' for writing: %s\n",
1470 hdrFilename, dmErrorStr(res)); 1737 hdrFilename, dmErrorStr(res));
1471 } 1738 }
1472 1739
1473 res = dmWriteIFFMasterRAWHeader(fp, dataFilename, prefix, img, spec); 1740 res = dmWriteIFFMasterRAWHeader(fp, dataFilename, prefix, img, spec);
1474 1741
1479 1746
1480 int dmWriteImage(const char *filename, DMImage *pimage, 1747 int dmWriteImage(const char *filename, DMImage *pimage,
1481 DMImageWriteSpec *spec, const DMImageFormat *fmt) 1748 DMImageWriteSpec *spec, const DMImageFormat *fmt)
1482 { 1749 {
1483 int res = DMERR_OK; 1750 int res = DMERR_OK;
1751 DMImage *image = pimage;
1752 BOOL allocated = FALSE;
1484 1753
1485 // Check if writing is even supported 1754 // Check if writing is even supported
1486 if (fmt->write == NULL || (fmt->flags & DM_FMT_WR) == 0) 1755 if (fmt->write == NULL || (fmt->flags & DM_FMT_WR) == 0)
1487 { 1756 {
1488 return dmError(DMERR_NOT_SUPPORTED, 1757 return dmError(DMERR_NOT_SUPPORTED,
1494 fmt->name, 1763 fmt->name,
1495 pimage->width, pimage->height, 1764 pimage->width, pimage->height,
1496 pimage->width * spec->scaleX, pimage->height * spec->scaleY, 1765 pimage->width * spec->scaleX, pimage->height * spec->scaleY,
1497 spec->scaleX, spec->scaleY); 1766 spec->scaleX, spec->scaleY);
1498 1767
1499 // Perform color remapping 1768 if (image->pixfmt == DM_PIXFMT_PALETTE)
1500 DMImage *image = pimage; 1769 {
1501 BOOL allocated = FALSE; 1770 switch (optRemapMode)
1502 if (optRemapColors && image->pixfmt == DM_PIXFMT_PALETTE) 1771 {
1503 { 1772 case REMAP_NONE:
1504 if ((res = dmRemoveUnusedImageColors(&image, pimage)) != DMERR_OK) 1773 if (optPaletteData != NULL)
1505 return res; 1774 {
1506 1775 DMPalette *tpal;
1507 allocated = TRUE; 1776
1777 dmMsg(1, "Replacing image palette %d colors with %d colors.\n",
1778 image->pal->ncolors, optPaletteData->ncolors);
1779
1780 if ((res = dmPaletteCopy(&tpal, optPaletteData)) != DMERR_OK)
1781 return res;
1782
1783 if (image->pal->ncolors != optPaletteData->ncolors)
1784 {
1785 dmMsg(1, "Trying to resize to %d colors.\n",
1786 image->pal->ncolors);
1787
1788 if ((res = dmPaletteResize(&tpal, image->pal->ncolors)) != DMERR_OK)
1789 return res;
1790 }
1791
1792 dmPaletteFree(image->pal);
1793 image->pal = tpal;
1794 }
1795 break;
1796
1797 case REMAP_MAPPED:
1798 if ((res = dmMapImageColors(&image, pimage,
1799 optRemapTable, optNRemapTable, optRemapRemove)) != DMERR_OK)
1800 goto out;
1801 allocated = TRUE;
1802 break;
1803
1804 case REMAP_AUTO:
1805 if (optPaletteData == NULL)
1806 {
1807 dmErrorMsg(
1808 "Color auto-remapping requested, but target palette not set? (-p option)\n");
1809 goto out;
1810 }
1811
1812 if ((res = dmRemapImageColors(&image, pimage,
1813 optPaletteData, optRemapMatchAlpha,
1814 //optRemapMaxDist, optRemapFail,
1815 0.5, -1,
1816 optRemapRemove)) != DMERR_OK)
1817 goto out;
1818
1819 allocated = TRUE;
1820 break;
1821 }
1822 }
1823 else
1824 if (optRemapMode != REMAP_NONE)
1825 {
1826 dmErrorMsg("Color remapping requested, but image is not paletted?\n");
1827 goto out;
1508 } 1828 }
1509 1829
1510 // Determine number of planes, if paletted 1830 // Determine number of planes, if paletted
1511 if (spec->nplanes == 0) 1831 if (spec->nplanes == 0)
1512 { 1832 {