comparison gfxconv.c @ 479:b768bfb0b364

Improve color remapping, add option for removing unused colors from the final output palette.
author Matti Hamalainen <ccr@tnsp.org>
date Wed, 07 Nov 2012 04:09:00 +0200
parents 7c7a57590236
children d7fc7e011c90
comparison
equal deleted inserted replaced
478:7c7a57590236 479:b768bfb0b364
116 optPlanedWidth = 1, 116 optPlanedWidth = 1,
117 optForcedFormat = -1; 117 optForcedFormat = -1;
118 int optInSkip = 0; 118 int optInSkip = 0;
119 BOOL optInMulticolor = FALSE, 119 BOOL optInMulticolor = FALSE,
120 optSequential = FALSE, 120 optSequential = FALSE,
121 optRemapColors = FALSE; 121 optRemapColors = FALSE,
122 optRemapRemove = FALSE;
122 int optNRemapTable = 0; 123 int optNRemapTable = 0;
123 DMMapValue optRemapTable[DM_MAX_COLORS]; 124 DMMapValue optRemapTable[DM_MAX_COLORS];
124 int optColors[C64_MAX_COLORS]; 125 int optColors[C64_MAX_COLORS];
125 126
126 DMImageSpec optSpec = 127 DMImageSpec optSpec =
150 { 11, 'w', "width", "Item width (number of items per row, min 1)", OPT_ARGREQ }, 151 { 11, 'w', "width", "Item width (number of items per row, min 1)", OPT_ARGREQ },
151 { 12, 'P', "paletted", "Use indexed/paletted output (png, pcx output only)", OPT_NONE }, 152 { 12, 'P', "paletted", "Use indexed/paletted output (png, pcx output only)", OPT_NONE },
152 { 13, 'B', "bplanes", "Bits per pixel OR # of bitplanes (certain output formats)", OPT_ARGREQ }, 153 { 13, 'B', "bplanes", "Bits per pixel OR # of bitplanes (certain output formats)", OPT_ARGREQ },
153 { 14, 'I', "interleave", "Interleave scanlines (default: output whole planes)", OPT_NONE }, 154 { 14, 'I', "interleave", "Interleave scanlines (default: output whole planes)", OPT_NONE },
154 { 16, 'R', "remap", "Remap output image colors (-R <(#RRGGBB|index):index>[,<..>] | -R @map.txt)", OPT_ARGREQ }, 155 { 16, 'R', "remap", "Remap output image colors (-R <(#RRGGBB|index):index>[,<..>] | -R @map.txt)", OPT_ARGREQ },
156 { 18, 'r', "remap-remove", "Remove unused colors from remapped palette (requires -R)\n", OPT_NONE },
155 }; 157 };
156 158
157 static const int optListN = sizeof(optList) / sizeof(optList[0]); 159 static const int optListN = sizeof(optList) / sizeof(optList[0]);
158 160
159 161
578 } 580 }
579 581
580 optRemapColors = TRUE; 582 optRemapColors = TRUE;
581 break; 583 break;
582 584
585 case 18:
586 optRemapRemove = TRUE;
587 break;
588
583 default: 589 default:
584 dmError("Unknown option '%s'.\n", currArg); 590 dmError("Unknown option '%s'.\n", currArg);
585 return FALSE; 591 return FALSE;
586 } 592 }
587 593
743 749
744 int dmRemapImageColors(DMImage *image) 750 int dmRemapImageColors(DMImage *image)
745 { 751 {
746 dmMsg(1, "Remapping %d output image colors.\n", optNRemapTable); 752 dmMsg(1, "Remapping %d output image colors.\n", optNRemapTable);
747 DMColor *npal = dmCalloc(image->ncolors, sizeof(DMColor)); 753 DMColor *npal = dmCalloc(image->ncolors, sizeof(DMColor));
748 int *dpal = dmMalloc(image->ncolors * sizeof(int)); 754 int *mapping = dmMalloc(image->ncolors * sizeof(int));
749 BOOL *spal = dmCalloc(image->ncolors, sizeof(BOOL)); 755 BOOL *mapped = dmMalloc(image->ncolors * sizeof(BOOL));
750 int index, xc, yc, nncolors = image->ncolors; 756 BOOL *used = dmMalloc(image->ncolors * sizeof(BOOL));
751 757 int n, index, xc, yc, ncolors = image->ncolors;
752 if (npal == NULL || spal == NULL || dpal == NULL) 758
753 { 759 if (npal == NULL || mapping == NULL || mapped == NULL || used == NULL)
754 dmError("Could not allocate memory for remapped palette.\n"); 760 {
761 dmError("Could not allocate memory for reused palette.\n");
755 return DMERR_MALLOC; 762 return DMERR_MALLOC;
756 } 763 }
757 764
758 for (index = 0; index < image->ncolors; index++) 765 for (index = 0; index < image->ncolors; index++)
759 dpal[index] = -1; 766 {
760 767 mapping[index] = -1;
761 // Find and mark mapped colors 768 used[index] = mapped[index] = FALSE;
769 }
770
771 // Find used colors
772 dmMsg(2, "Scanning image for used colors...\n");
773 for (yc = 0; yc < image->height; yc++)
774 {
775 Uint8 *dp = image->data + image->pitch * yc;
776 for (xc = 0; xc < image->width; xc++)
777 {
778 Uint8 col = dp[xc];
779 if (col < image->ncolors)
780 used[col] = TRUE;
781 }
782 }
783
784 // Match and mark mapped colors
762 for (index = 0; index < optNRemapTable; index++) 785 for (index = 0; index < optNRemapTable; index++)
763 { 786 {
764 DMMapValue *map = &optRemapTable[index]; 787 DMMapValue *map = &optRemapTable[index];
765 if (map->triplet) 788 if (map->triplet)
766 { 789 {
767 BOOL found = FALSE; 790 BOOL found = FALSE;
768 int n;
769 for (n = 0; n < image->ncolors; n++) 791 for (n = 0; n < image->ncolors; n++)
770 { 792 {
771 if (dmCompareColor(&(image->pal[n]), &(map->color), map->alpha)) 793 if (dmCompareColor(&(image->pal[n]), &(map->color), map->alpha))
772 { 794 {
773 dmMsg(3, "RGBA match #%02x%02x%02x%02x: %d -> %d\n", 795 dmMsg(3, "RGBA match #%02x%02x%02x%02x: %d -> %d\n",
774 map->color.r, map->color.g, map->color.b, map->color.a, 796 map->color.r, map->color.g, map->color.b, map->color.a,
775 n, 797 n,
776 map->to); 798 map->to);
777 799
778 dpal[map->to] = n; 800 if (used[n])
779 spal[n] = TRUE; 801 {
780 found = TRUE; 802 mapping[n] = map->to;
781 // break; 803 mapped[map->to] = TRUE;
804 found = TRUE;
805 }
782 } 806 }
783 } 807 }
784 808
785 if (!found) 809 if (!found)
786 { 810 {
789 map->color.r, map->color.g, map->color.b, map->color.a); 813 map->color.r, map->color.g, map->color.b, map->color.a);
790 } 814 }
791 } 815 }
792 else 816 else
793 { 817 {
794 dmMsg(3, "Map index: %d -> %d\n", 818 if (used[map->from])
795 map->from, map->to); 819 {
796 820 dmMsg(3, "Map index: %d -> %d\n",
797 dpal[map->to] = map->from; 821 map->from, map->to);
798 spal[map->from] = TRUE; 822
823 mapping[map->from] = map->to;
824 mapped[map->to] = TRUE;
825 }
799 } 826 }
800 } 827 }
801 828
802 // Fill in the rest 829 // Fill in the rest
803 dmMsg(3, "Placing non-mapped palette entries.\n"); 830 if (optRemapRemove)
831 {
832 dmMsg(2, "Removing unused colors.\n");
833 for (index = 0; index < image->ncolors; index++)
834 if (mapping[index] < 0 && used[index])
835 {
836 for (n = 0; n < image->ncolors; n++)
837 if (!mapped[n])
838 {
839 mapping[index] = n;
840 mapped[n] = TRUE;
841 break;
842 }
843 }
844 }
845 else
846 {
847 for (index = 0; index < image->ncolors; index++)
848 if (mapping[index] < 0)
849 {
850 for (n = 0; n < image->ncolors; n++)
851 if (!mapped[n])
852 {
853 mapping[index] = n;
854 mapped[n] = TRUE;
855 break;
856 }
857 }
858 }
859
860 // Calculate final number of palette colors
861 ncolors = 0;
804 for (index = 0; index < image->ncolors; index++) 862 for (index = 0; index < image->ncolors; index++)
805 { 863 {
806 if (dpal[index] < 0) 864 if (mapping[index] > ncolors)
807 { 865 ncolors = mapping[index] + 1;
808 int src;
809 for (src = 0; src < image->ncolors; src++)
810 {
811 if (!spal[src])
812 {
813 dpal[index] = src;
814 spal[src] = TRUE;
815 break;
816 }
817 }
818 }
819 } 866 }
820 867
821 // Copy palette entries 868 // Copy palette entries
822 dmMsg(3, "Creating new palette.\n"); 869 for (index = 0; index < ncolors; index++)
823 for (index = 0; index < image->ncolors; index++) 870 {
824 { 871 if (mapping[index] >= 0)
825 if (dpal[index] >= 0 && dpal[index] < image->ncolors) 872 {
826 { 873 memcpy(&npal[index], &(image->pal[mapping[index]]), sizeof(DMColor));
827 memcpy(&npal[index], &(image->pal[dpal[index]]), sizeof(DMColor)); 874 }
828 nncolors = index; 875 }
829 }
830 }
831
832 876
833 // Remap image 877 // Remap image
834 dmMsg(1, "Remapping image ...\n"); 878 dmMsg(1, "Remapping image to %d colors...\n", ncolors);
835 for (yc = 0; yc < image->height; yc++) 879 for (yc = 0; yc < image->height; yc++)
836 { 880 {
837 Uint8 *dp = image->data + image->pitch * yc; 881 Uint8 *dp = image->data + image->pitch * yc;
838 for (xc = 0; xc < image->width; xc++) 882 for (xc = 0; xc < image->width; xc++)
839 { 883 {
840 Uint8 col = dp[xc]; 884 Uint8 col = dp[xc];
841 if (col < image->ncolors && dpal[col] >= 0 && dpal[col] < image->ncolors) 885 if (col < image->ncolors && mapping[col] >= 0 && mapping[col] < image->ncolors)
842 { 886 dp[xc] = mapping[col];
843 dp[xc] = dpal[col];
844 }
845 else 887 else
846 dp[xc] = 0; 888 dp[xc] = 0;
847 } 889 }
848 } 890 }
849 891
850 // Set new palette, free memory 892 // Set new palette, free memory
851 dmFree(image->pal); 893 dmFree(image->pal);
852 image->pal = npal; 894 image->pal = npal;
853 image->ncolors = nncolors; 895 image->ncolors = ncolors;
854 dmFree(spal); 896
855 dmFree(dpal); 897 dmFree(mapping);
898 dmFree(mapped);
899 dmFree(used);
856 return DMERR_OK; 900 return DMERR_OK;
857 } 901 }
858 902
859 903
860 int dmWriteImage(const char *filename, DMImage *image, DMImageSpec *spec, int iformat, BOOL info) 904 int dmWriteImage(const char *filename, DMImage *image, DMImageSpec *spec, int iformat, BOOL info)