Files
OmaPhoto/kernels/LevelsPixels.c
T

61 lines
2.7 KiB
C

#include "LevelsPixels.h"
#include <math.h>
void levels_apply(uint8_t *pixels, size_t count, const float *tables) {
for (size_t i=0; i<count; ++i) {
uint8_t *p = pixels + i*4;
float alpha = p[3];
if (!alpha) continue;
for (int channel=0; channel<3; ++channel) {
float x = fminf(255, p[channel]*255.0f/alpha);
int lo = (int)x, hi = lo < 255 ? lo+1 : 255;
const float *table = tables + channel*256;
float result = table[lo] + (table[hi]-table[lo])*(x-lo);
p[channel] = (uint8_t)fminf(alpha, fmaxf(0, roundf(result*alpha)));
}
}
}
void levels_histogram(const uint8_t *pixels, const uint8_t *coverage, size_t count, double *bins) {
for (size_t i=0; i<count; ++i) {
const uint8_t *p = pixels+i*4;
if (!p[3]) continue;
double weight = p[3]/255.0 * (coverage ? coverage[i]/255.0 : 1);
for (int channel=0; channel<3; ++channel) {
int value = (int)fmin(255, round(p[channel]*255.0/p[3]));
bins[(channel+1)*256+value] += weight;
bins[value] += weight/3.0;
}
}
}
/// A color lookup through `cube` (`dimension`³ RGBA entries, red varying fastest), blended between the eight nearest
/// entries, on unpremultiplied colors; alpha is kept.
void cube_apply(uint8_t *pixels, size_t count, const float *cube, int dimension) {
const float scale = (dimension - 1) / 255.0f;
const size_t dy = dimension, dz = (size_t)dimension * dimension;
for (size_t i=0; i<count; ++i) {
uint8_t *p = pixels + i*4;
float alpha = p[3];
if (!alpha) continue;
float position[3], fraction[3];
int lo[3];
for (int channel=0; channel<3; ++channel) {
position[channel] = fminf(255, p[channel]*255.0f/alpha) * scale;
lo[channel] = (int)position[channel];
if (lo[channel] > dimension - 2) lo[channel] = dimension - 2;
fraction[channel] = position[channel] - lo[channel];
}
const float *base = cube + ((size_t)lo[0] + lo[1]*dy + lo[2]*dz) * 4;
const size_t sx = 4, sy = dy*4, sz = dz*4;
for (int channel=0; channel<3; ++channel) {
const float *c = base + channel;
float x00 = c[0] + (c[sx] - c[0]) * fraction[0];
float x10 = c[sy] + (c[sy+sx] - c[sy]) * fraction[0];
float x01 = c[sz] + (c[sz+sx] - c[sz]) * fraction[0];
float x11 = c[sz+sy] + (c[sz+sy+sx] - c[sz+sy]) * fraction[0];
float y0 = x00 + (x10 - x00) * fraction[1];
float y1 = x01 + (x11 - x01) * fraction[1];
float result = y0 + (y1 - y0) * fraction[2];
p[channel] = (uint8_t)fminf(alpha, fmaxf(0, roundf(result*alpha)));
}
}
}