hexsort.c (4790B)
1 /* See LICENSE file for copyright and license details. */ 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <stdint.h> 5 #include <unistd.h> 6 #include <string.h> 7 8 /* magic to return the ratio between two numbers */ 9 #define RATIO(a,b) (((a)>(b) ? 1.0*(b)/(a) : ((a) > 0 ? 1.0*(a)/(b) : 0))) 10 11 struct color_t { 12 char hex[8]; 13 int rgb[3]; 14 double val; 15 struct color_t *next; 16 }; 17 18 struct color_t *head = NULL; 19 struct color_t **sorted = NULL; 20 struct color_t **messed = NULL; 21 22 void 23 usage(char *argv0) { 24 fprintf(stderr, "usage: %s [mask]\n", argv0); 25 } 26 27 /* 28 * converts an hexadecimal representation of a color into a 3 dimensionnal 29 * array (RGB decomposition) 30 */ 31 void 32 hex2rgb(char *hex, int *rgb) 33 { 34 int i; 35 char tmp[2]; 36 for (i = 0; i < 3; i++) { 37 strncpy(tmp, hex + 1 + 2 * i, 2); 38 rgb[i] = strtol(tmp, NULL, 16); 39 } 40 } 41 42 /* 43 * Returns the "ratio" of the negative color for an RGB representation. 44 * 45 * For mask 4 (100)b which is red. It will return the purity ratio of its 46 * negative color: cyan (#00ffff). For example: 47 * 48 * #ff2d2d 255,45,45 45/45 = 1.0 (this is a "full" cyan) 49 * #ff3c1e 255,6°,30 60/30 = 0.5 (this is a "half" cyan) 50 */ 51 double 52 color_ratio(int *rgb, uint8_t mask) 53 { 54 switch(mask) { 55 case 4: return RATIO(rgb[1],rgb[2]); 56 case 2: return RATIO(rgb[0],rgb[2]); 57 case 1: return RATIO(rgb[0],rgb[1]); 58 case 3: return RATIO(rgb[1],rgb[2]); 59 case 5: return RATIO(rgb[0],rgb[2]); 60 case 6: return RATIO(rgb[0],rgb[1]); 61 } 62 return 0; 63 } 64 65 /* 66 * Calculate a score for the dominance of the color given by `mask` (3 bit 67 * representation of the RGB color, eg: 101 is magenta). 68 * This will calculate the score of the color regarding the mask, and return 69 * this value for comparison with other colors. "pure" refers to the color 70 * represented by the mask, "negative" refers to the opposite of this color. 71 * 72 * We differentiate 3 types of masks: 73 * + 100, 010, 001 74 * + 110, 101, 011 75 * + 111, 000 76 * 77 * First group will be the pure color, divided by the negative ratio. 78 * Second group will be the pure color multiplied by the pure ratio. 79 * Last group is just a plain sum of all colors. 80 * 81 * (Check function color_ratio() for an explanation on the ratio) 82 */ 83 double 84 color_dominant(int *rgb, uint8_t mask) 85 { 86 double pure = 0, negative = 0, ratio = 0; 87 88 int prgb[3]; 89 int nrgb[3]; 90 91 /* get the score of the current value */ 92 prgb[0] = rgb[0] * ((mask & 4)>>2); 93 prgb[1] = rgb[1] * ((mask & 2)>>1); 94 prgb[2] = rgb[2] * ((mask & 1)>>0); 95 96 /* score of the negative value */ 97 nrgb[0] = rgb[0] * (((mask ^ 4)>>2)&1); 98 nrgb[1] = rgb[1] * (((mask ^ 2)>>1)&1); 99 nrgb[2] = rgb[2] * (((mask ^ 1)>>0)&1); 100 101 /* 102 * calculate the average of either pure or negative color depending on 103 * the mask's value 104 */ 105 switch (mask) { 106 case 1: 107 case 2: 108 case 4: 109 pure = prgb[0] + prgb[1] + prgb[2]; 110 negative = (nrgb[0] + nrgb[1] + nrgb[2])/2; 111 ratio = 1 + negative * color_ratio(nrgb, mask); 112 return ((pure - negative) / ratio); 113 case 3: 114 case 5: 115 case 6: 116 pure = (prgb[0] + prgb[1] + prgb[2])/2; 117 negative = nrgb[0] + nrgb[1] + nrgb[2]; 118 ratio = 1 + pure * color_ratio(prgb, mask); 119 return ((pure - negative) * ratio); 120 } 121 122 pure = prgb[0] + prgb[1] + prgb[2]; 123 negative = nrgb[0] + nrgb[1] + nrgb[2]; 124 return pure - negative; 125 } 126 127 /* create a color node, and add it to the list */ 128 struct color_t * 129 color_new(char *hex, uint8_t mask) 130 { 131 struct color_t *new = NULL; 132 133 new = malloc(sizeof(struct color_t)); 134 if (new == NULL) 135 return NULL; 136 137 strncpy(new->hex, hex, 8); 138 hex2rgb(hex, new->rgb); 139 new->val = color_dominant(new->rgb, mask); 140 return new; 141 } 142 143 /* 144 * Takes an unsorted list of colors as an argument, and sort it depending on 145 * the mask value. 146 * The mask is a 3 bit representation of the RGB composition you want to use to 147 * sort colors, eg mask 011 will return the brightess cyan first, and darkest 148 * red last. 149 */ 150 struct color_t * 151 color_sort(struct color_t *cur, struct color_t *new, uint8_t mask) 152 { 153 if (cur == NULL) { 154 new->next = NULL; 155 } else { 156 if (new->val <= cur->val) { 157 cur->next = color_sort(cur->next, new, mask); 158 return cur; 159 } else { 160 new->next = cur; 161 } 162 } 163 return new; 164 } 165 166 /* 167 * print the content of our list in the format: 168 * <HEX> <RGB> <SCORE> 169 */ 170 void 171 color_print(struct color_t *node) 172 { 173 struct color_t *tmp = NULL; 174 for (tmp=node; tmp; tmp=tmp->next) { 175 printf("%s\t%d,%d,%d\t%f\n", 176 tmp->hex, 177 tmp->rgb[0], 178 tmp->rgb[1], 179 tmp->rgb[2], 180 tmp->val ); 181 } 182 } 183 184 int 185 main(int argc, char *argv[]) 186 { 187 char hex[8]; 188 uint8_t mask = 7; 189 190 /* print whitest by default */ 191 if (argc > 1) { 192 if (strncmp(argv[1], "-h", 2) == 0) 193 usage(argv[0]); 194 else 195 mask = atoi(argv[1]); 196 } 197 198 while (fgets(hex, 8, stdin)) { 199 if (hex[0] == '#') { 200 head = color_sort(head, color_new(hex, mask), mask); 201 } 202 } 203 color_print(head); 204 return 0; 205 }