also looking at this
fix(image): validate raw initialization and 16-bit white levels
#911
1 file
+27
-4
| @@ -40,7 +40,10 @@ pub const RawImage = struct { | ||
| 40 | 40 | allocator: std.mem.Allocator, |
| 41 | 41 | |
| 42 | 42 | 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); | |
| 44 | 47 | @memset(data, 0); |
| 45 | 48 | |
| 46 | 49 | return RawImage{ |
| @@ -50,7 +53,7 @@ pub const RawImage = struct { | ||
| 50 | 53 | .bits_per_sample = bits, |
| 51 | 54 | .bayer_pattern = .rggb, |
| 52 | 55 | .black_level = 0, |
| 53 | .white_level = @as(u16, 1) << @intCast(bits), | |
| 56 | .white_level = @intCast((@as(u32, 1) << @intCast(bits)) - 1), | |
| 54 | 57 | .color_matrix = .{ 1, 0, 0, 0, 1, 0, 0, 0, 1 }, |
| 55 | 58 | .white_balance = .{ 1, 1, 1 }, |
| 56 | 59 | .allocator = allocator, |
| @@ -63,12 +66,12 @@ pub const RawImage = struct { | ||
| 63 | 66 | |
| 64 | 67 | pub fn getValue(self: *const RawImage, x: u32, y: u32) u16 { |
| 65 | 68 | 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]; | |
| 67 | 70 | } |
| 68 | 71 | |
| 69 | 72 | pub fn setValue(self: *RawImage, x: u32, y: u32, value: u16) void { |
| 70 | 73 | 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; | |
| 72 | 75 | } |
| 73 | 76 | }; |
| 74 | 77 | |
| @@ -1024,3 +1027,23 @@ fn bilinearSample(img: *Image, x: f32, y: f32) Color { | ||
| 1024 | 1027 | .a = 255, |
| 1025 | 1028 | }; |
| 1026 | 1029 | } |
| 1030 | ||
| 1031 | test "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 | ||
| 1040 | test "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 | ||
| 1046 | test "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 | } | |