const std = @import("std"); const jpg = @import("root.zig"); pub const Segment = union(enum) { temporary: void, reset: void, start_of_image: void, end_of_image: void, start_of_frame: void, define_quantization_table: void, define_huffman_table: void, define_restart_interval: void, define_number_of_lines: void, define_hierarchy_progression: void, extend_huffman_table: void, jfif: jpg.Jfif, application_segment: void, comment: void, start_of_scan: void, const Self = @This(); pub fn read(gpa: std.mem.Allocator, reader: *std.Io.Reader) !Self { _ = gpa; if (try reader.peekByte() != 0xff) { return error.InvalidMarkerHeader; } reader.toss(1); const marker = jpg.Marker.from_u8(try reader.peekByte()) catch return error.InvalidMarkerByte; reader.toss(1); return switch (marker) { .temporary => .{ .temporary = void{} }, .reset => .{ .reset = void{} }, .start_of_image => .{ .start_of_image = void{} }, .end_of_image => .{ .end_of_image = void{} }, .application_segment => |n| switch (n) { 0 => jfif: { // NOTE: we can toss the length of this segment // since the JFIF segment has a predefined size reader.toss(2); break :jfif .{ .jfif = try jpg.Jfif.read(reader) }; }, else => unreachable, }, else => { std.debug.panic("unimplemented tag '{s}'\n", .{@tagName(marker)}); }, }; } }; test "file" { const buffer = @embedFile("../testing/rgb.jpg"); var reader: std.Io.Reader = .fixed(buffer); var segment: Segment = try .read(std.testing.allocator, &reader); try std.testing.expectEqual(.start_of_image, std.meta.activeTag(segment)); segment = try .read(std.testing.allocator, &reader); try std.testing.expectEqual(.jfif, std.meta.activeTag(segment)); segment = try .read(std.testing.allocator, &reader); try std.testing.expectEqual(.jfif, std.meta.activeTag(segment)); }