Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

jxl: Add animation support #160

Merged
merged 1 commit into from
Jul 21, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 42 additions & 17 deletions src/formats/jxl.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include "../loader.h"

#include <jxl/decode.h>
#include <string.h>
#include <stdlib.h>

// JPEG XL loader implementation
enum loader_status decode_jxl(struct image* ctx, const uint8_t* data,
Expand All @@ -15,7 +15,7 @@ enum loader_status decode_jxl(struct image* ctx, const uint8_t* data,
JxlBasicInfo info;
JxlDecoderStatus status;
size_t buffer_sz;
struct pixmap* pm = NULL;
size_t frame_num = 0;

const JxlPixelFormat jxl_format = { .num_channels = 4, // ARBG
.data_type = JXL_TYPE_UINT8,
Expand All @@ -42,8 +42,8 @@ enum loader_status decode_jxl(struct image* ctx, const uint8_t* data,
}

// process decoding
status =
JxlDecoderSubscribeEvents(jxl, JXL_DEC_BASIC_INFO | JXL_DEC_FULL_IMAGE);
status = JxlDecoderSubscribeEvents(
jxl, JXL_DEC_BASIC_INFO | JXL_DEC_FRAME | JXL_DEC_FULL_IMAGE);
if (status != JXL_DEC_SUCCESS) {
goto fail;
}
Expand All @@ -62,23 +62,53 @@ enum loader_status decode_jxl(struct image* ctx, const uint8_t* data,
}
break;
case JXL_DEC_FULL_IMAGE:
break; // frame decoded, nothing to do
// convert ABGR -> ARGB
for (size_t i = 0; i < ctx->frames[frame_num].pm.width *
ctx->frames[frame_num].pm.height;
++i) {
ctx->frames[frame_num].pm.data[i] =
ABGR_TO_ARGB(ctx->frames[frame_num].pm.data[i]);
}
frame_num = ctx->num_frames;
break;
case JXL_DEC_FRAME:
ctx->frames = realloc(
ctx->frames, sizeof(*ctx->frames) * (ctx->num_frames + 1));
if (!ctx->frames) {
goto fail;
}
if (!pixmap_create(&ctx->frames[frame_num].pm, info.xsize,
info.ysize)) {
goto fail;
}
ctx->num_frames += 1;

if (info.have_animation) {
JxlFrameHeader header;
rc = JxlDecoderGetFrameHeader(jxl, &header);
if (rc != JXL_DEC_SUCCESS) {
goto fail;
}
ctx->frames[frame_num].duration = header.duration *
1000.0f * info.animation.tps_denominator /
info.animation.tps_numerator;
}
break;
case JXL_DEC_NEED_IMAGE_OUT_BUFFER:
// get image buffer size
rc = JxlDecoderImageOutBufferSize(jxl, &jxl_format, &buffer_sz);
if (rc != JXL_DEC_SUCCESS) {
goto fail;
}
pm = image_allocate_frame(ctx, info.xsize, info.ysize);
if (!pm) {
goto fail;
}
// check buffer format
if (buffer_sz != pm->width * pm->height * sizeof(argb_t)) {
if (buffer_sz !=
ctx->frames[frame_num].pm.width *
ctx->frames[frame_num].pm.height * sizeof(argb_t)) {
goto fail;
}
// set output buffer
rc = JxlDecoderSetImageOutBuffer(jxl, &jxl_format, pm->data,
rc = JxlDecoderSetImageOutBuffer(jxl, &jxl_format,
ctx->frames[frame_num].pm.data,
buffer_sz);
if (rc != JXL_DEC_SUCCESS) {
goto fail;
Expand All @@ -89,15 +119,10 @@ enum loader_status decode_jxl(struct image* ctx, const uint8_t* data,
}
} while (status != JXL_DEC_SUCCESS);

if (!pm) {
if (!ctx->frames) {
goto fail;
}

// convert ABGR -> ARGB
for (size_t i = 0; i < pm->width * pm->height; ++i) {
pm->data[i] = ABGR_TO_ARGB(pm->data[i]);
}

image_set_format(ctx, "JPEG XL %ubpp",
info.bits_per_sample * info.num_color_channels +
info.alpha_bits);
Expand Down
Loading