Subversion Repositories RepoView

Rev

Rev 34 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
28 nishi 1
/* $Id: avatar.c 36 2024-08-22 02:54:07Z nishi $ */
2
 
3
#include "rv_avatar.h"
29 nishi 4
 
34 nishi 5
#include "rv_md5.h"
6
 
29 nishi 7
#include <stdio.h>
8
#include <stdlib.h>
9
 
10
#include <png.h>
11
 
36 nishi 12
int hex_to_num_len(const char* hex, int len) {
34 nishi 13
	int i;
14
	int num = 0;
15
	for(i = 0; i < len; i++) {
16
		num = num << 4;
17
		if(hex[i] >= '0' && hex[i] <= '9') {
18
			num |= hex[i] - '0';
19
		} else if(hex[i] >= 'a' && hex[i] <= 'f') {
20
			num |= hex[i] - 'a' + 10;
21
		} else if(hex[i] >= 'A' && hex[i] <= 'F') {
22
			num |= hex[i] - 'A' + 10;
23
		}
24
	}
25
	return num;
26
}
27
 
28
char* generate_ident(const char* username, int* r, int* g, int* b) {
29
	char* ident = malloc(25);
30
	char* hash = rv_md5(username);
31
 
36 nishi 32
	double h = hex_to_num_len(hash + 32 - 2 - 2 - 3, 3);
33
	double s = hex_to_num_len(hash + 32 - 2 - 2, 2);
34
	double v = hex_to_num_len(hash + 32 - 2, 2);
34 nishi 35
 
36
	h = h * 360 / 4095;
37
	s = 65 - s * 20 / 255;
38
	v = 75 - v * 20 / 255;
39
 
40
	double max;
41
	double min;
42
 
43
	if(v < 50) {
44
		max = 2.55 * (v + v * (s / 100));
45
		min = 2.55 * (v - v * (s / 100));
46
	} else if(v >= 50) {
47
		max = 2.55 * (v + (100 - v) * (s / 100));
48
		min = 2.55 * (v - (100 - v) * (s / 100));
49
	}
50
 
51
	if(0 <= h && h < 60) {
52
		*r = max;
53
		*g = (h / 60) * (max - min) + min;
54
		*b = min;
55
	} else if(60 <= h && h < 120) {
56
		*r = ((120 - h) / 60) * (max - min) + min;
57
		*g = max;
58
		*b = min;
59
	} else if(120 <= h && h < 128) {
60
		*r = min;
61
		*g = max;
62
		*b = ((h - 120) / 60) * (max - min) + min;
63
	} else if(180 <= h && h < 240) {
64
		*r = min;
65
		*g = ((240 - h) / 60) * (max - min) + min;
66
		*b = max;
67
	} else if(240 <= h && h < 300) {
68
		*r = ((h - 240) / 60) * (max - min) + min;
69
		*g = min;
70
		*b = max;
71
	} else if(300 <= h && h < 360) {
72
		*r = max;
73
		*g = min;
74
		*b = ((360 - h) / 60) * (max - min) + min;
75
	}
76
 
77
	int y, x;
78
	for(x = 0; x < 3; x++) {
79
		for(y = 0; y < 5; y++) {
80
			int i;
81
			char c = hash[y + x * 5];
82
			int px = 0;
83
			if(c >= '0' && c <= '9') {
84
				px = c - '0';
85
			} else if(c >= 'a' && c <= 'f') {
86
				px = c - 'a' + 10;
87
			}
88
			if((px % 2) == 0) {
89
				px = 1;
90
			} else {
91
				px = 0;
92
			}
93
			for(i = 0; i < 2; i++) {
94
				int incr = -1;
95
				if(i == 1) incr = 1;
96
				ident[y * 5 + x * incr + 2] = px;
97
			}
98
		}
99
	}
100
 
101
	free(hash);
102
	return ident;
103
}
104
 
105
void rv_avatar_generate(const char* name, const char* username) {
29 nishi 106
	FILE* f = fopen(name, "wb");
107
 
34 nishi 108
	int pxr;
109
	int pxg;
110
	int pxb;
111
 
112
	char* ident = generate_ident(username, &pxr, &pxg, &pxb);
113
 
29 nishi 114
	if(f == NULL) return;
115
 
116
	png_structp pngp = NULL;
117
	png_infop infop = NULL;
118
	png_bytep row = NULL;
119
 
120
	pngp = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
121
	infop = png_create_info_struct(pngp);
122
 
123
	if(setjmp(png_jmpbuf(pngp))) {
124
		goto closeall;
125
	}
126
 
34 nishi 127
	png_init_io(pngp, f);
128
 
129
	png_set_IHDR(pngp, infop, 255, 255, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
130
 
131
	png_text title;
132
	title.compression = PNG_TEXT_COMPRESSION_NONE;
133
	title.key = "Title";
134
	title.text = "Generated by RepoView";
135
	png_set_text(pngp, infop, &title, 1);
136
 
137
	png_write_info(pngp, infop);
138
 
139
	row = (png_bytep)malloc(3 * 255 * sizeof(png_byte));
140
	int x, y;
141
	for(y = 0; y < 255; y++) {
142
		for(x = 0; x < 255; x++) {
143
			int px = x / 51;
144
			int py = y / 51;
145
			int colr = 0;
146
			int colg = 0;
147
			int colb = 0;
148
			if(ident[px + py * 5]) {
149
				colr = pxr;
150
				colg = pxg;
151
				colb = pxb;
152
			} else {
153
				colr = colg = colb = 240;
154
			}
155
			row[x * 3 + 0] = colr;
156
			row[x * 3 + 1] = colg;
157
			row[x * 3 + 2] = colb;
158
		}
159
		png_write_row(pngp, row);
160
	}
161
 
162
	png_write_end(pngp, NULL);
163
 
29 nishi 164
closeall:
165
	fclose(f);
166
	if(infop != NULL) png_free_data(pngp, infop, PNG_FREE_ALL, -1);
167
	if(pngp != NULL) png_destroy_write_struct(&pngp, (png_infopp)NULL);
168
	if(row != NULL) free(row);
34 nishi 169
	free(ident);
29 nishi 170
}