Zig bindings for JPEG XL

Hi! I am trying to add support for reading/writing images in my Zig programs via JPEG XL.

I’ve managed to read them fine, but I can’t compile the encoder. There’s a mismatch in the signature, but I think it should work.

So, the original signature for the function I am having problems with is:

JXL_EXPORT JxlEncoderStatus JxlEncoderProcessOutput(JxlEncoder *enc, uint8_t **next_out, size_t *avail_out)

The generated Zig bindings have this signature:

pub extern fn JxlEncoderProcessOutput(enc: ?*JxlEncoder, next_out: [*c][*c]u8, avail_out: [*c]usize) JxlEncoderStatus;

I am porting the decoding code from here:

  uint8_t* next_out = compressed->data();
  size_t avail_out = compressed->size() - (next_out - compressed->data());
  JxlEncoderStatus process_result = JXL_ENC_NEED_MORE_OUTPUT;
  while (process_result == JXL_ENC_NEED_MORE_OUTPUT) {
    process_result = JxlEncoderProcessOutput(enc.get(), &next_out, &avail_out);
    if (process_result == JXL_ENC_NEED_MORE_OUTPUT) {
      size_t offset = next_out - compressed->data();
      compressed->resize(compressed->size() * 2);
      next_out = compressed->data() + offset;
      avail_out = compressed->size() - offset;
    }
  }

Which looks like this in Zig:

var compressed = std.ArrayList(u8).init(allocator);
defer compressed.deinit();
try compressed.resize(64);
var next_out: [*c]u8 = compressed.items.ptr;
var avail_out = compressed.items.len - (@intFromPtr(next_out) - @intFromPtr(compressed.items.ptr));
var process_result = jxl.JXL_ENC_NEED_MORE_OUTPUT;
while (process_result == jxl.JXL_ENC_NEED_MORE_OUTPUT) {
    process_result = jxl.JxlEncoderProcessOutput(enc, &next_out, &avail_out);
    if (process_result == jxl.JXL_ENC_NEED_MORE_OUTPUT) {
        const offset: usize = @intFromPtr(next_out) - @intFromPtr(compressed.items.ptr);
        try compressed.resize(compressed.items.len * 2);
        next_out = @intFromPtr(compressed.items.ptr) + offset;
        avail_out = @intFromPtr(compressed.items.ptr) - offset;
    }
}

However, I am getting this error at the line where I call JxlEncoderProcessOutput

src/main.zig:69:53: error: expected type 'c_int', found 'c_uint'
src/main.zig:69:53: note: signed 32-bit int cannot represent all possible unsigned 32-bit values

Can someone point out what am I doing wrong?
I’ve uploaded a minimal version of this, so you can try it out.
build.zig.zon (2.8 KB)
main.zig (3.2 KB)
build.zig (750 Bytes)

1 Like

I think this line is deducing process_result to be c_int, but JxlEncoderProcessOutput returns c_uint. You can try @intCasting the return value.

3 Likes

You’re right, I forgot to check the return value :sweat_smile:
Thank you!