Files
OmaPhoto/kernels/AdjustPixels.c
T
雷电芽衣andClaude c864304695
Release / deb (push) Canceled after 0s
Release / rpm (push) Canceled after 0s
Release / arch (push) Canceled after 0s
Release / publish (push) Canceled after 0s
OmaPhoto 1.0.0: the Linux port of Compositor
A layered image editor for Linux and Omarchy, ported from Compositor
(github.com/robbietilton/Compositor), whose Swift source is its
specification. It reads and writes Compositor's .comp projects.

Packages for Ubuntu, Fedora and Arch come from the release workflow;
scripts/install/ holds one install script per distribution family,
and flake.nix serves NixOS.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-09-26 00:44:52 -04:00

97 lines
4.4 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "AdjustPixels.h"
#include <math.h>
void adjust_gradient_map(uint8_t *rgba, size_t width, size_t height, size_t stride, const uint8_t *table) {
for (size_t y = 0; y < height; y++) {
uint8_t *p = rgba + y * stride;
for (size_t x = 0; x < width; x++, p += 4) {
unsigned a = p[3];
if (a == 0) continue;
unsigned r = p[0], g = p[1], b = p[2];
if (a < 255) {
r = (r * 255u + a / 2) / a;
g = (g * 255u + a / 2) / a;
b = (b * 255u + a / 2) / a;
if (r > 255) r = 255;
if (g > 255) g = 255;
if (b > 255) b = 255;
}
unsigned level = (2126u * r + 7152u * g + 722u * b + 5000u) / 10000u;
const uint8_t *color = table + (level > 255 ? 255 : level) * 3;
p[0] = (uint8_t)((color[0] * a + 127u) / 255u);
p[1] = (uint8_t)((color[1] * a + 127u) / 255u);
p[2] = (uint8_t)((color[2] * a + 127u) / 255u);
}
}
}
static inline uint32_t mix32(uint32_t x) {
x ^= x >> 16;
x *= 0x7feb352dU;
x ^= x >> 15;
x *= 0x846ca68bU;
x ^= x >> 16;
return x;
}
// A value in −1…1 for an integer lattice point, fixed by the point and the seed. Two uniform halves
// summed give a triangular spread, closer to film grain than flat noise.
static inline float lattice(int64_t ix, int64_t iy, uint32_t seed) {
uint32_t h = mix32((uint32_t)ix * 0x9E3779B1U ^ mix32((uint32_t)iy * 0x85EBCA77U ^ seed));
return (float)(h & 0xFFFFU) / 65535.0f + (float)(h >> 16) / 65535.0f - 1.0f;
}
static inline float clamp255(float value) { return value < 0 ? 0 : value > 255 ? 255 : value; }
void adjust_grain(uint8_t *rgba, size_t width, size_t height, size_t stride, double amount, double size,
double roughness, uint32_t seed, double originX, double originY, double unitsPerPixel) {
if (!(amount > 0) || !(unitsPerPixel > 0)) return;
if (!(size > 0)) size = 1;
float strength = (float)(amount > 100 ? 1.0 : amount / 100.0) * 0.35f * 255.0f;
float rough = (float)(roughness < 0 ? 0.0 : roughness > 100 ? 1.0 : roughness / 100.0);
uint32_t fineSeed = mix32(seed ^ 0xA511E9B3U);
for (size_t y = 0; y < height; y++) {
double v = originY + ((double)y + 0.5) * unitsPerPixel;
double cellY = floor(v / size);
float ty = (float)(v / size - cellY);
ty = ty * ty * (3.0f - 2.0f * ty);
int64_t iy = (int64_t)cellY, fineY = (int64_t)floor(v);
uint8_t *p = rgba + y * stride;
for (size_t x = 0; x < width; x++, p += 4) {
unsigned a = p[3];
if (a == 0) continue;
double u = originX + ((double)x + 0.5) * unitsPerPixel;
double cellX = floor(u / size);
float tx = (float)(u / size - cellX);
tx = tx * tx * (3.0f - 2.0f * tx);
int64_t ix = (int64_t)cellX;
float n00 = lattice(ix, iy, seed), n10 = lattice(ix + 1, iy, seed);
float n01 = lattice(ix, iy + 1, seed), n11 = lattice(ix + 1, iy + 1, seed);
float top = n00 + (n10 - n00) * tx, bottom = n01 + (n11 - n01) * tx;
// Blending neighbors narrows the spread; scaling restores about the lattice's own.
float smooth = (top + (bottom - top) * ty) * 1.6f;
float fine = lattice((int64_t)floor(u), fineY, fineSeed);
float noise = smooth + (fine - smooth) * rough;
float unpremultiply = a == 255 ? 1.0f : 255.0f / (float)a;
float r = p[0] * unpremultiply, g = p[1] * unpremultiply, b = p[2] * unpremultiply;
float level = (0.2126f * r + 0.7152f * g + 0.0722f * b) / 255.0f;
if (level > 1) level = 1;
// Film grain shows most in the midtones.
float delta = noise * strength * (0.4f + 2.4f * level * (1.0f - level));
float coverage = (float)a / 255.0f;
p[0] = (uint8_t)(clamp255(r + delta) * coverage + 0.5f);
p[1] = (uint8_t)(clamp255(g + delta) * coverage + 0.5f);
p[2] = (uint8_t)(clamp255(b + delta) * coverage + 0.5f);
}
}
}
void rgba_clamp_premultiplied(uint8_t *rgba, size_t count) {
for (size_t i = 0; i < count; i++, rgba += 4) {
uint8_t a = rgba[3];
if (rgba[0] > a) rgba[0] = a;
if (rgba[1] > a) rgba[1] = a;
if (rgba[2] > a) rgba[2] = a;
}
}