| author | |
| committer | |
| log | 8c09516944357d85f4ffa3d7a1421f96f63ac420 |
| tree | c7c8525ea3bf15b99f208cb2aba986b8d86d67f6 |
| parent | b9313635237c1f05ed4e40b8b1dba5a51f76ef0f |
8 files changed, 87 insertions(+), 11 deletions(-)
CMYK.zig+10| ... | ... | @@ -27,3 +27,13 @@ pub fn initCMYKA(c: f32, m: f32, y: f32, k: f32, a: f32) Self { |
| 27 | 27 | pub fn eql(x: Self, y: Self) bool { |
| 28 | 28 | return x.c == y.c and x.m == y.m and x.y == y.y and x.k == y.k and x.a == y.a; |
| 29 | 29 | } |
| 30 | ||
| 31 | pub fn to_array(x: Self) [5]f32 { | |
| 32 | return .{ | |
| 33 | x.c, | |
| 34 | x.m, | |
| 35 | x.y, | |
| 36 | x.k, | |
| 37 | x.a, | |
| 38 | }; | |
| 39 | } |
HSL.zig+3| ... | ... | @@ -2,6 +2,7 @@ |
| 2 | 2 | |
| 3 | 3 | const std = @import("std"); |
| 4 | 4 | const Self = @This(); |
| 5 | const _x = @import("./_x.zig"); | |
| 5 | 6 | |
| 6 | 7 | h: f32, // hue |
| 7 | 8 | s: f32, // saturation |
| ... | ... | @@ -24,3 +25,5 @@ pub fn initHSLA(h: f32, s: f32, l: f32, a: f32) Self { |
| 24 | 25 | pub fn eql(x: Self, y: Self) bool { |
| 25 | 26 | return x.h == y.h and x.s == y.s and x.l == y.l and x.a == y.a; |
| 26 | 27 | } |
| 28 | ||
| 29 | pub usingnamespace _x.mixin(@This(), f32, .h, .s, .l); |
HSV.zig+3| ... | ... | @@ -2,6 +2,7 @@ |
| 2 | 2 | |
| 3 | 3 | const std = @import("std"); |
| 4 | 4 | const Self = @This(); |
| 5 | const _x = @import("./_x.zig"); | |
| 5 | 6 | |
| 6 | 7 | h: f32, // hue |
| 7 | 8 | s: f32, // saturation |
| ... | ... | @@ -24,3 +25,5 @@ pub fn initHSVA(h: f32, s: f32, v: f32, a: f32) Self { |
| 24 | 25 | pub fn eql(x: Self, y: Self) bool { |
| 25 | 26 | return x.h == y.h and x.s == y.s and x.v == y.v and x.a == y.a; |
| 26 | 27 | } |
| 28 | ||
| 29 | pub usingnamespace _x.mixin(@This(), f32, .h, .s, .v); |
LinearRgb.zig+3| ... | ... | @@ -2,6 +2,7 @@ |
| 2 | 2 | |
| 3 | 3 | const std = @import("std"); |
| 4 | 4 | const Self = @This(); |
| 5 | const _x = @import("./_x.zig"); | |
| 5 | 6 | |
| 6 | 7 | r: f32, // red |
| 7 | 8 | g: f32, // green |
| ... | ... | @@ -28,3 +29,5 @@ pub fn eql(x: Self, y: Self) bool { |
| 28 | 29 | pub fn relative_luminance(x: Self) f32 { |
| 29 | 30 | return (0.2126 * x.r) + (0.7152 * x.g) + (0.0722 * x.b); |
| 30 | 31 | } |
| 32 | ||
| 33 | pub usingnamespace _x.mixin(@This(), f32, .r, .g, .b); |
_x.zig+2-1| ... | ... | @@ -2,6 +2,7 @@ const std = @import("std"); |
| 2 | 2 | |
| 3 | 3 | pub fn mixin( |
| 4 | 4 | comptime T: type, |
| 5 | comptime I: type, | |
| 5 | 6 | comptime f1: std.meta.FieldEnum(T), |
| 6 | 7 | comptime f2: std.meta.FieldEnum(T), |
| 7 | 8 | comptime f3: std.meta.FieldEnum(T), |
| ... | ... | @@ -25,7 +26,7 @@ pub fn mixin( |
| 25 | 26 | return x; |
| 26 | 27 | } |
| 27 | 28 | |
| 28 | pub fn to_array(x: T, comptime I: type) [4]I { | |
| 29 | pub fn to_array(x: T) [4]I { | |
| 29 | 30 | return .{ |
| 30 | 31 | @field(x, @tagName(f1)), |
| 31 | 32 | @field(x, @tagName(f2)), |
build.zig+11-2| ... | ... | @@ -25,6 +25,15 @@ pub fn build(b: *std.Build) void { |
| 25 | 25 | const run_step = b.step("run", "Run the app"); |
| 26 | 26 | run_step.dependOn(&run_cmd.step); |
| 27 | 27 | |
| 28 | const test_step = b.step("test", "dummy test step to pass CI checks"); | |
| 29 | _ = test_step; | |
| 28 | const tests = b.addTest(.{ | |
| 29 | .root_source_file = b.path("test.zig"), | |
| 30 | .target = target, | |
| 31 | .optimize = mode, | |
| 32 | }); | |
| 33 | deps.addAllTo(tests); | |
| 34 | ||
| 35 | const test_step = b.step("test", "Run all library tests"); | |
| 36 | const tests_run = b.addRunArtifact(tests); | |
| 37 | tests_run.has_side_effects = true; | |
| 38 | test_step.dependOn(&tests_run.step); | |
| 30 | 39 | } |
sRGB.zig+8-8| ... | ... | @@ -73,7 +73,7 @@ pub fn format(x: Self, comptime fmt: []const u8, options: std.fmt.FormatOptions, |
| 73 | 73 | }); |
| 74 | 74 | } |
| 75 | 75 | |
| 76 | pub usingnamespace _x.mixin(@This(), .r, .g, .b); | |
| 76 | pub usingnamespace _x.mixin(@This(), u8, .r, .g, .b); | |
| 77 | 77 | |
| 78 | 78 | pub fn to_linear_rgb(x: Self) color.LinearRgb { |
| 79 | 79 | const lut = comptime blk: { |
| ... | ... | @@ -94,7 +94,7 @@ pub fn to_linear_rgb(x: Self) color.LinearRgb { |
| 94 | 94 | } |
| 95 | 95 | |
| 96 | 96 | pub fn to_float(x: Self) Float { |
| 97 | return Self{ | |
| 97 | return .{ | |
| 98 | 98 | .r = @as(f32, @floatFromInt(x.r)) / 255.0, |
| 99 | 99 | .g = @as(f32, @floatFromInt(x.g)) / 255.0, |
| 100 | 100 | .b = @as(f32, @floatFromInt(x.b)) / 255.0, |
| ... | ... | @@ -119,9 +119,9 @@ pub fn to_hsl(x: Self) color.HSL { |
| 119 | 119 | const delta = cmax - cmin; |
| 120 | 120 | const h = blk: { |
| 121 | 121 | if (delta == 0) break :blk 0; |
| 122 | if (cmax == f.r) break :blk ((((f.g - f.b) / delta) % 6) * 60) % 360; | |
| 123 | if (cmax == f.g) break :blk ((((f.b - f.r) / delta) + 2) * 60) % 360; | |
| 124 | if (cmax == f.b) break :blk ((((f.r - f.g) / delta) + 4) * 60) % 360; | |
| 122 | if (cmax == f.r) break :blk @rem(((f.g - f.b) / delta), 6.0) / 6.0; | |
| 123 | if (cmax == f.g) break :blk (((f.b - f.r) / delta) + 2) / 6.0; | |
| 124 | if (cmax == f.b) break :blk (((f.r - f.g) / delta) + 4) / 6.0; | |
| 125 | 125 | unreachable; |
| 126 | 126 | }; |
| 127 | 127 | const l = (cmax + cmin) / 2; |
| ... | ... | @@ -137,9 +137,9 @@ pub fn to_hsv(x: Self) color.HSV { |
| 137 | 137 | const delta = cmax - cmin; |
| 138 | 138 | const h = blk: { |
| 139 | 139 | if (delta == 0) break :blk 0; |
| 140 | if (cmax == f.r) break :blk ((((f.g - f.b) / delta) % 6) * 60) % 360; | |
| 141 | if (cmax == f.g) break :blk ((((f.b - f.r) / delta) + 2) * 60) % 360; | |
| 142 | if (cmax == f.b) break :blk ((((f.r - f.g) / delta) + 4) * 60) % 360; | |
| 140 | if (cmax == f.r) break :blk (@rem(((f.g - f.b) / delta), 6.0) / 6.0); | |
| 141 | if (cmax == f.g) break :blk ((((f.b - f.r) / delta) + 2) / 6.0); | |
| 142 | if (cmax == f.b) break :blk ((((f.r - f.g) / delta) + 4) / 6.0); | |
| 143 | 143 | unreachable; |
| 144 | 144 | }; |
| 145 | 145 | const s = if (cmax == 0) 0 else delta / cmax; |
test.zig created+47| ... | ... | @@ -0,0 +1,47 @@ |
| 1 | const std = @import("std"); | |
| 2 | const color = @import("color"); | |
| 3 | ||
| 4 | test { | |
| 5 | // https://www.colorhexa.com/4fc3f7 | |
| 6 | const o = color.sRGB.parseHexConst("#4FC3F7"); | |
| 7 | { | |
| 8 | const r, const g, const b, const a = o.to_array(); | |
| 9 | try std.testing.expect(r == 79); | |
| 10 | try std.testing.expect(g == 195); | |
| 11 | try std.testing.expect(b == 247); | |
| 12 | try std.testing.expect(a == 255); | |
| 13 | } | |
| 14 | { | |
| 15 | // 68% cyan, 21.1% magenta, 0% yellow and 3.1% black | |
| 16 | const c, const m, const y, const k, const a = o.to_cmyk().to_array(); | |
| 17 | try std.testing.expectApproxEqAbs(0.68, c, 0.01); | |
| 18 | try std.testing.expectApproxEqAbs(0.21, m, 0.01); | |
| 19 | try std.testing.expectApproxEqAbs(0.00, y, 0.01); | |
| 20 | try std.testing.expectApproxEqAbs(0.03, k, 0.01); | |
| 21 | try std.testing.expect(a == 1.0); | |
| 22 | } | |
| 23 | { | |
| 24 | // 198.6°, 91.3, 63.9 | |
| 25 | const h, const s, const l, const a = o.to_hsl().to_array(); | |
| 26 | try std.testing.expectApproxEqAbs(0.552, h, 0.001); | |
| 27 | try std.testing.expectApproxEqAbs(0.913, s, 0.001); | |
| 28 | try std.testing.expectApproxEqAbs(0.639, l, 0.001); | |
| 29 | try std.testing.expect(a == 1.0); | |
| 30 | } | |
| 31 | { | |
| 32 | // 198.6°, 68, 96.9 | |
| 33 | const h, const s, const v, const a = o.to_hsv().to_array(); | |
| 34 | try std.testing.expectApproxEqAbs(0.552, h, 0.001); | |
| 35 | try std.testing.expectApproxEqAbs(0.680, s, 0.001); | |
| 36 | try std.testing.expectApproxEqAbs(0.969, v, 0.001); | |
| 37 | try std.testing.expect(a == 1.0); | |
| 38 | } | |
| 39 | { | |
| 40 | // 0.0781874218051863, 0.545724461370187, 0.930110858375424 | |
| 41 | const r, const g, const b, const a = o.to_linear_rgb().to_array(); | |
| 42 | try std.testing.expectApproxEqAbs(0.078, r, 0.001); | |
| 43 | try std.testing.expectApproxEqAbs(0.545, g, 0.001); | |
| 44 | try std.testing.expectApproxEqAbs(0.930, b, 0.001); | |
| 45 | try std.testing.expect(a == 1.0); | |
| 46 | } | |
| 47 | } |