authorgravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2024-12-30 01:47:06 -08:00
committergravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2024-12-30 01:47:06 -08:00
log64cfdaabc303a26095c5b5f9146f87ba6997a031
tree8909bf3f5f9e57dcdea3dca18cf6aac4bc53e7c6
parent5aaaebb7f77a6737c10dd7be77926019e0f32ab4

add YUV


4 files changed, 69 insertions(+), 2 deletions(-)

YUV.zig created+45
......@@ -0,0 +1,45 @@
1const std = @import("std");
2const Self = @This();
3const color = @import("./mod.zig");
4const _x = @import("./_x.zig");
5const vec4 = @Vector(4, f32);
6
7y: f32, // [ 0 .. 1 ]
8u: f32, // [ -0.436 .. +0.436 ]
9v: f32, // [ -0.615 .. +0.615 ]
10a: f32, // [ 0 .. 1 ]
11
12pub fn initYUVA(y: f32, u: f32, v: f32, a: f32) Self {
13 return Self{
14 .y = y,
15 .u = u,
16 .v = v,
17 .a = a,
18 };
19}
20
21pub fn initYUV(y: f32, u: f32, v: f32) Self {
22 return initYUVA(y, u, v, 255);
23}
24
25pub fn eql(x: Self, y: Self) bool {
26 return x.y == y.y and x.u == y.u and x.v == y.v and x.a == y.a;
27}
28
29pub usingnamespace _x.mixin(@This(), f32, .y, .u, .v);
30
31// https://web.archive.org/web/20180423091842/http://www.equasys.de/colorconversion.html
32pub fn to_srgb(x: Self) color.sRGB {
33 // zig fmt: off
34 const y, const u, const v, const a = x.to_array();
35 const r = y * 1.000 + u * 0.000 + v * 1.140;
36 const g = y * 1.000 + u * -0.395 + v * -0.581;
37 const b = y * 1.000 + u * 2.032 + v * 0.000;
38 return color.sRGB.from_float(.{ r, g, b, a });
39 // zig fmt: on
40}
41
42pub fn normal(x: Self) vec4 {
43 const v: vec4 = x.to_array();
44 return v * @as(vec4, .{ 255, 255, 255, 1 });
45}
mod.zig+1
......@@ -7,3 +7,4 @@ pub const CMYK = @import("./CMYK.zig");
77pub const HSL = @import("./HSL.zig");
88pub const HSV = @import("./HSV.zig");
99pub const YCbCr = @import("./YCbCr.zig");
10pub const YUV = @import("./YUV.zig");
sRGB.zig+14-2
......@@ -4,6 +4,7 @@ const std = @import("std");
44const Self = @This();
55const color = @import("./mod.zig");
66const _x = @import("./_x.zig");
7const vec4 = @Vector(4, f32);
78
89r: u8, // red value
910g: u8, // green value
......@@ -104,8 +105,8 @@ pub fn to_float(x: Self) Float {
104105 };
105106}
106107
107pub fn from_float(y: @Vector(4, f32)) Self {
108 const r, const g, const b, const a = y * @as(@Vector(4, f32), @splat(255.0));
108pub fn from_float(y: vec4) Self {
109 const r, const g, const b, const a = y * @as(vec4, @splat(255.0));
109110 return .{
110111 .r = @intFromFloat(r),
111112 .g = @intFromFloat(g),
......@@ -174,3 +175,14 @@ pub fn to_ycbcr(x: Self) color.YCbCr {
174175 });
175176 // zig fmt: on
176177}
178
179// https://web.archive.org/web/20180423091842/http://www.equasys.de/colorconversion.html
180pub fn to_yuv(x: Self) color.YUV {
181 // zig fmt: off
182 const r, const g, const b, const a = x.to_vec() / @as(vec4, @splat(255));
183 const y = r * 0.299 + g * 0.587 + b * 0.114;
184 const u = r * -0.147 + g * -0.289 + b * 0.436;
185 const v = r * 0.615 + g * -0.515 + b * -0.100;
186 return color.YUV.initYUVA(y, u, v, a);
187 // zig fmt: on
188}
test.zig+9
......@@ -72,4 +72,13 @@ test {
7272 try expect(o.to_ycbcr().to_array()).toEqual(.{ 166, 173, 65, 255 });
7373 try expect(o.to_ycbcr().to_srgb().to_array()).toEqual(.{ 77, 195, 245, 255 });
7474 }
75 {
76 // Y: 166.244, U: 39.741, V: -76.541
77 const y, const u, const v, const a = o.to_yuv().normal();
78 try std.testing.expectApproxEqAbs(166.244, y, 0.001);
79 try std.testing.expectApproxEqAbs(39.723, u, 0.001);
80 try std.testing.expectApproxEqAbs(-76.539, v, 0.001);
81 try std.testing.expect(a == 1.0);
82 try expect(o.to_yuv().to_srgb().to_array()).toEqual(.{ 78, 195, 246, 255 });
83 }
7584}