Rev 34 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
/* $Id: avatar.c 36 2024-08-22 02:54:07Z nishi $ */
#include "rv_avatar.h"
#include "rv_md5.h"
#include <stdio.h>
#include <stdlib.h>
#include <png.h>
int hex_to_num_len(const char* hex, int len) {
int i;
int num = 0;
for(i = 0; i < len; i++) {
num = num << 4;
if(hex[i] >= '0' && hex[i] <= '9') {
num |= hex[i] - '0';
} else if(hex[i] >= 'a' && hex[i] <= 'f') {
num |= hex[i] - 'a' + 10;
} else if(hex[i] >= 'A' && hex[i] <= 'F') {
num |= hex[i] - 'A' + 10;
}
}
return num;
}
char* generate_ident(const char* username, int* r, int* g, int* b) {
char* ident = malloc(25);
char* hash = rv_md5(username);
double h = hex_to_num_len(hash + 32 - 2 - 2 - 3, 3);
double s = hex_to_num_len(hash + 32 - 2 - 2, 2);
double v = hex_to_num_len(hash + 32 - 2, 2);
h = h * 360 / 4095;
s = 65 - s * 20 / 255;
v = 75 - v * 20 / 255;
double max;
double min;
if(v < 50) {
max = 2.55 * (v + v * (s / 100));
min = 2.55 * (v - v * (s / 100));
} else if(v >= 50) {
max = 2.55 * (v + (100 - v) * (s / 100));
min = 2.55 * (v - (100 - v) * (s / 100));
}
if(0 <= h && h < 60) {
*r = max;
*g = (h / 60) * (max - min) + min;
*b = min;
} else if(60 <= h && h < 120) {
*r = ((120 - h) / 60) * (max - min) + min;
*g = max;
*b = min;
} else if(120 <= h && h < 128) {
*r = min;
*g = max;
*b = ((h - 120) / 60) * (max - min) + min;
} else if(180 <= h && h < 240) {
*r = min;
*g = ((240 - h) / 60) * (max - min) + min;
*b = max;
} else if(240 <= h && h < 300) {
*r = ((h - 240) / 60) * (max - min) + min;
*g = min;
*b = max;
} else if(300 <= h && h < 360) {
*r = max;
*g = min;
*b = ((360 - h) / 60) * (max - min) + min;
}
int y, x;
for(x = 0; x < 3; x++) {
for(y = 0; y < 5; y++) {
int i;
char c = hash[y + x * 5];
int px = 0;
if(c >= '0' && c <= '9') {
px = c - '0';
} else if(c >= 'a' && c <= 'f') {
px = c - 'a' + 10;
}
if((px % 2) == 0) {
px = 1;
} else {
px = 0;
}
for(i = 0; i < 2; i++) {
int incr = -1;
if(i == 1) incr = 1;
ident[y * 5 + x * incr + 2] = px;
}
}
}
free(hash);
return ident;
}
void rv_avatar_generate(const char* name, const char* username) {
FILE* f = fopen(name, "wb");
int pxr;
int pxg;
int pxb;
char* ident = generate_ident(username, &pxr, &pxg, &pxb);
if(f == NULL) return;
png_structp pngp = NULL;
png_infop infop = NULL;
png_bytep row = NULL;
pngp = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
infop = png_create_info_struct(pngp);
if(setjmp(png_jmpbuf(pngp))) {
goto closeall;
}
png_init_io(pngp, f);
png_set_IHDR(pngp, infop, 255, 255, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
png_text title;
title.compression = PNG_TEXT_COMPRESSION_NONE;
title.key = "Title";
title.text = "Generated by RepoView";
png_set_text(pngp, infop, &title, 1);
png_write_info(pngp, infop);
row = (png_bytep)malloc(3 * 255 * sizeof(png_byte));
int x, y;
for(y = 0; y < 255; y++) {
for(x = 0; x < 255; x++) {
int px = x / 51;
int py = y / 51;
int colr = 0;
int colg = 0;
int colb = 0;
if(ident[px + py * 5]) {
colr = pxr;
colg = pxg;
colb = pxb;
} else {
colr = colg = colb = 240;
}
row[x * 3 + 0] = colr;
row[x * 3 + 1] = colg;
row[x * 3 + 2] = colb;
}
png_write_row(pngp, row);
}
png_write_end(pngp, NULL);
closeall:
fclose(f);
if(infop != NULL) png_free_data(pngp, infop, PNG_FREE_ALL, -1);
if(pngp != NULL) png_destroy_write_struct(&pngp, (png_infopp)NULL);
if(row != NULL) free(row);
free(ident);
}