Subversion Repositories RepoView

Rev

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);
}