152 lines
4.3 KiB
Zig
152 lines
4.3 KiB
Zig
const std = @import("std");
|
|
|
|
const Format = @import("Format.zig");
|
|
|
|
const format: Format = .{
|
|
.magic_length = magic.len,
|
|
// NOTE The information (like width and height) is not in a fixed position
|
|
.info_length = magic.len,
|
|
.extension = "jpeg",
|
|
.media_type = "image/jpeg",
|
|
.isFormat = isJpeg,
|
|
};
|
|
|
|
const magic = "\xFF\xD8\xFF";
|
|
|
|
const Info = union(enum) {
|
|
partial: void,
|
|
full: Header,
|
|
|
|
pub fn makeFull(full: Header) Info {
|
|
return .{ .full = full };
|
|
}
|
|
|
|
test "refAllDecls" {
|
|
std.testing.refAllDecls(@This());
|
|
}
|
|
};
|
|
|
|
const Header = struct {
|
|
width: u32,
|
|
height: u32,
|
|
};
|
|
|
|
const Marker = enum(u8) {
|
|
/// Start of frame, Huffman coding, Baseline DCT
|
|
SOF_0 = 0xC0,
|
|
/// Start of frame, Huffman coding, Extended sequential DCT
|
|
SOF_1 = 0xC1,
|
|
/// Start of frame, Huffman coding, Progressive DCT
|
|
SOF_2 = 0xC2,
|
|
/// Start of frame, Huffman coding, Lossless (sequential)
|
|
SOF_3 = 0xC3,
|
|
/// Start of frame, Huffman coding, Differential sequential DCT
|
|
SOF_5 = 0xC5,
|
|
/// Start of frame, Huffman coding, Differential progressive DCT
|
|
SOF_6 = 0xC6,
|
|
/// Start of frame, Huffman coding, Differential lossless (sequential)
|
|
SOF_7 = 0xC7,
|
|
/// Start of frame, arithmetic coding, Extended sequential DCT
|
|
SOF_9 = 0xC9,
|
|
/// Start of frame, arithmetic coding, Progressive DCT
|
|
SOF_10 = 0xCA,
|
|
/// Start of frame, arithmetic coding, Lossless (sequential)
|
|
SOF_11 = 0xCB,
|
|
/// Start of frame, arithmetic coding, Differential sequential DCT
|
|
SOF_13 = 0xCD,
|
|
/// Start of frame, arithmetic coding, Differential progressive DCT
|
|
SOF_14 = 0xCE,
|
|
/// Start of frame, arithmetic coding, Differential lossless (sequential)
|
|
SOF_15 = 0xCF,
|
|
/// Define Huffman table(s)
|
|
DHT = 0xC4,
|
|
/// Define arithmetic coding conditioning(s)
|
|
DAC = 0xCC,
|
|
/// Start of image
|
|
SOI = 0xD8,
|
|
/// End of image
|
|
EOI = 0xD9,
|
|
/// Start of scan
|
|
SOS = 0xDA,
|
|
/// Define quantization table(s)
|
|
DQT = 0xDB,
|
|
/// Define number of lines
|
|
DNL = 0xDC,
|
|
/// Define restart interval
|
|
DRI = 0xDD,
|
|
/// Define hierarchical progression
|
|
DHP = 0xDE,
|
|
/// Expand reference component(s)
|
|
EXP = 0xDF,
|
|
/// Comment
|
|
COM = 0xFE,
|
|
/// For temporary private use in arithmetic coding
|
|
TEM = 0x01,
|
|
|
|
_,
|
|
|
|
/// Restart with modulo 8 count `m`
|
|
pub fn RST(m: u3) Marker {
|
|
return @enumFromInt(0xD0 | m);
|
|
}
|
|
|
|
pub fn isRST(self: Marker) ?u3 {
|
|
return if (@intFromEnum(self) & 0b1111_1000 == 0xD0) @intCast(@intFromEnum(self) & 0b0000_0111) else null;
|
|
}
|
|
|
|
/// Reserved for application segments
|
|
pub fn APP(n: u4) Marker {
|
|
return @enumFromInt(0xE0 | n);
|
|
}
|
|
|
|
pub fn isAPP(self: Marker) ?u3 {
|
|
return if (@intFromEnum(self) & 0b1111_0000 == 0xE0) @intCast(@intFromEnum(self) & 0b0000_1111) else null;
|
|
}
|
|
|
|
/// A standalone marker has no content and is not followed by segment length
|
|
/// parameter.
|
|
pub fn isStandalone(self: Marker) bool {
|
|
return self.isRST() != null or
|
|
self == .SOI or
|
|
self == .EOI or
|
|
self == .TEM;
|
|
}
|
|
|
|
test "refAllDecls" {
|
|
std.testing.refAllDecls(@This());
|
|
}
|
|
};
|
|
|
|
/// The caller asserts that the buffer is at least `format.magic_length` bytes
|
|
/// long.
|
|
pub fn isJpeg(buffer: []const u8) bool {
|
|
return std.mem.eql(u8, buffer[0..format.magic_length], magic);
|
|
}
|
|
|
|
/// The caller asserts that the buffer is at least `format.info_length` bytes
|
|
/// long. The information is not in a fixed position, so you need to provide a
|
|
/// substantial amount of data, in the order of kilobytes. Depending on the
|
|
/// amount of metadata, the information might be in the first kilobyte or dozens
|
|
/// of kilobytes in.
|
|
///
|
|
/// This function returns:
|
|
///
|
|
/// - `null` when the buffer is not a JPEG or it's a malformed JPEG
|
|
/// - `.partial` when the buffer appears to be a part of a JPEG, but the
|
|
/// information could not be found within the buffer provided
|
|
/// - `.full` when the buffer appears to be a part of a JPEG and the information
|
|
/// was fully contained within the buffer provided
|
|
pub fn info(buffer: []const u8) ?Info {
|
|
std.debug.assert(buffer.len >= format.info_length);
|
|
|
|
if (!isJpeg(buffer)) {
|
|
return null;
|
|
}
|
|
|
|
@panic("TODO");
|
|
}
|
|
|
|
test "refAllDecls" {
|
|
std.testing.refAllDecls(@This());
|
|
}
|