Skip to content

Commit 6e15f27

Browse files
committed
Handle 7-bit RMIM
1 parent 2d2b43b commit 6e15f27

File tree

3 files changed

+27
-13
lines changed

3 files changed

+27
-13
lines changed

src/rmim.zig

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const bmp = @import("bmp.zig");
66
const io = @import("io.zig");
77
const report = @import("report.zig");
88

9+
pub const BMCOMP_NMAJMIN_H7 = 0x89;
910
pub const BMCOMP_NMAJMIN_H8 = 0x8a;
1011
pub const BMCOMP_NMAJMIN_HT8 = 0x94;
1112

@@ -102,9 +103,11 @@ fn decompressBmap(compression: u8, reader: anytype, end: u32, out: anytype) !voi
102103

103104
var in = std.io.bitReader(.little, reader.reader());
104105

105-
// only these are implemented
106-
if (compression != BMCOMP_NMAJMIN_H8 and compression != BMCOMP_NMAJMIN_HT8)
107-
return error.DecompressBmap;
106+
const color_bits: u8 = switch (compression) {
107+
BMCOMP_NMAJMIN_H7 => 7,
108+
BMCOMP_NMAJMIN_H8, BMCOMP_NMAJMIN_HT8 => 8,
109+
else => return error.DecompressBmap,
110+
};
108111

109112
var color = try in.readBitsNoEof(u8, 8);
110113
while (reader.pos < end or in.bit_count != 0) {
@@ -114,7 +117,7 @@ fn decompressBmap(compression: u8, reader: anytype, end: u32, out: anytype) !voi
114117
const d = try in.readBitsNoEof(u3, 3);
115118
color +%= @as(u8, @bitCast(delta[d])); // TODO: how to properly do this
116119
} else {
117-
color = try in.readBitsNoEof(u8, 8);
120+
color = try in.readBitsNoEof(u8, color_bits);
118121
}
119122
}
120123
}

src/rmim_encode.zig

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ const beginBlock = @import("block_writer.zig").beginBlock;
55
const endBlock = @import("block_writer.zig").endBlock;
66
const bmp = @import("bmp.zig");
77
const io = @import("io.zig");
8+
const report = @import("report.zig");
9+
const BMCOMP_NMAJMIN_H7 = @import("rmim.zig").BMCOMP_NMAJMIN_H7;
810
const BMCOMP_NMAJMIN_H8 = @import("rmim.zig").BMCOMP_NMAJMIN_H8;
911
const BMCOMP_NMAJMIN_HT8 = @import("rmim.zig").BMCOMP_NMAJMIN_HT8;
1012

@@ -24,18 +26,22 @@ pub fn encode(
2426

2527
const bmap_fixup = try beginBlock(out, "BMAP");
2628

27-
// only these are implemented
28-
if (compression != BMCOMP_NMAJMIN_H8 and compression != BMCOMP_NMAJMIN_HT8)
29-
return error.BadData;
3029
try out.writer().writeByte(compression);
31-
try compressBmap(header, out.writer());
30+
try compressBmap(header, compression, out.writer());
3231

3332
try endBlock(out, fixups, bmap_fixup);
3433

3534
try endBlock(out, fixups, im00_fixup);
3635
}
3736

38-
fn compressBmap(header: bmp.Bmp, writer: anytype) !void {
37+
fn compressBmap(header: bmp.Bmp, compression: u8, writer: anytype) !void {
38+
const color_bits: u8 = switch (compression) {
39+
BMCOMP_NMAJMIN_H7 => 7,
40+
BMCOMP_NMAJMIN_H8, BMCOMP_NMAJMIN_HT8 => 8,
41+
else => return error.BadData,
42+
};
43+
const max_pixel: u8 = @intCast((@as(u9, 1) << @intCast(color_bits)) - 1);
44+
3945
var out = std.io.bitWriter(.little, writer);
4046

4147
var pixit = try header.iterPixels();
@@ -44,6 +50,11 @@ fn compressBmap(header: bmp.Bmp, writer: anytype) !void {
4450
try out.writeBits(current, 8);
4551

4652
while (pixit.next()) |pixel| {
53+
if (pixel > max_pixel) {
54+
report.fatal("color index {} too large for encoding", .{pixel});
55+
return error.Reported;
56+
}
57+
4758
const diff = @as(i16, pixel) - current;
4859
if (diff == 0) {
4960
try out.writeBits(@as(u1, 0), 1);
@@ -55,7 +66,7 @@ fn compressBmap(header: bmp.Bmp, writer: anytype) !void {
5566
try out.writeBits(@as(u3, @intCast(diff + 3)), 3);
5667
} else {
5768
try out.writeBits(@as(u2, 1), 2);
58-
try out.writeBits(pixel, 8);
69+
try out.writeBits(pixel, color_bits);
5970
}
6071

6172
current = pixel;

src/tests.zig

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ test "Backyard Baseball 1997 round trip decode/encode" {
8888
defer result.deinit(allocator);
8989

9090
try expectBlockStats(&result.block_stats, &.{
91-
.{ "RMIM", 16, 30 },
91+
.{ "RMIM", 17, 30 },
9292
.{ "RMHD", 0, 30 },
9393
.{ "CYCL", 0, 30 },
9494
.{ "TRNS", 0, 30 },
@@ -238,7 +238,7 @@ test "Backyard Soccer round trip decode/encode" {
238238
defer result.deinit(allocator);
239239

240240
try expectBlockStats(&result.block_stats, &.{
241-
.{ "RMIM", 22, 29 },
241+
.{ "RMIM", 23, 29 },
242242
.{ "RMHD", 0, 29 },
243243
.{ "CYCL", 0, 29 },
244244
.{ "TRNS", 0, 29 },
@@ -313,7 +313,7 @@ test "Backyard Football round trip decode/encode" {
313313
defer result.deinit(allocator);
314314

315315
try expectBlockStats(&result.block_stats, &.{
316-
.{ "RMIM", 14, 56 },
316+
.{ "RMIM", 15, 56 },
317317
.{ "RMHD", 0, 56 },
318318
.{ "CYCL", 0, 56 },
319319
.{ "TRNS", 0, 56 },

0 commit comments

Comments
 (0)