ReviewOS

also looking at this

home-lang/home

fix(image): validate raw initialization and 16-bit white levels

#911
Merged chris wants to merge fix/raw-image-initialization into main
1 file +27 -4
packages/image/src/raw.zigmodified+27-4
Changes to packages/image/src/raw.zig
@@ -40,7 +40,10 @@ pub const RawImage = struct {
4040 allocator: std.mem.Allocator,
4141
4242 pub fn init(allocator: std.mem.Allocator, width: u32, height: u32, bits: u8) !RawImage {
43 const data = try allocator.alloc(u16, width * height);
43 if (bits == 0 or bits > 16) return error.InvalidBitDepth;
44 if (width == 0 or height == 0) return error.InvalidDimensions;
45 const count = std.math.mul(usize, width, height) catch return error.ImageTooLarge;
46 const data = try allocator.alloc(u16, count);
4447 @memset(data, 0);
4548
4649 return RawImage{
@@ -50,7 +53,7 @@ pub const RawImage = struct {
5053 .bits_per_sample = bits,
5154 .bayer_pattern = .rggb,
5255 .black_level = 0,
53 .white_level = @as(u16, 1) << @intCast(bits),
56 .white_level = @intCast((@as(u32, 1) << @intCast(bits)) - 1),
5457 .color_matrix = .{ 1, 0, 0, 0, 1, 0, 0, 0, 1 },
5558 .white_balance = .{ 1, 1, 1 },
5659 .allocator = allocator,
@@ -63,12 +66,12 @@ pub const RawImage = struct {
6366
6467 pub fn getValue(self: *const RawImage, x: u32, y: u32) u16 {
6568 if (x >= self.width or y >= self.height) return 0;
66 return self.data[y * self.width + x];
69 return self.data[@as(usize, y) * self.width + x];
6770 }
6871
6972 pub fn setValue(self: *RawImage, x: u32, y: u32, value: u16) void {
7073 if (x >= self.width or y >= self.height) return;
71 self.data[y * self.width + x] = value;
74 self.data[@as(usize, y) * self.width + x] = value;
7275 }
7376};
7477
@@ -1024,3 +1027,23 @@ fn bilinearSample(img: *Image, x: f32, y: f32) Color {
10241027 .a = 255,
10251028 };
10261029}
1030
1031test "raw image white level covers the full declared bit depth" {
1032 var raw = try RawImage.init(std.testing.allocator, 2, 2, 16);
1033 defer raw.deinit();
1034 try std.testing.expectEqual(@as(u16, 65535), raw.white_level);
1035 var twelve = try RawImage.init(std.testing.allocator, 2, 2, 12);
1036 defer twelve.deinit();
1037 try std.testing.expectEqual(@as(u16, 4095), twelve.white_level);
1038}
1039
1040test "raw image rejects empty geometry and invalid bit depths" {
1041 try std.testing.expectError(error.InvalidBitDepth, RawImage.init(std.testing.allocator, 2, 2, 0));
1042 try std.testing.expectError(error.InvalidBitDepth, RawImage.init(std.testing.allocator, 2, 2, 17));
1043 try std.testing.expectError(error.InvalidDimensions, RawImage.init(std.testing.allocator, 0, 2, 12));
1044}
1045
1046test "raw image propagates allocation failure" {
1047 var failing = std.testing.FailingAllocator.init(std.testing.allocator, .{ .fail_index = 0 });
1048 try std.testing.expectError(error.OutOfMemory, RawImage.init(failing.allocator(), 2, 2, 12));
1049}