summaryrefslogtreecommitdiff
path: root/src/loader/loader.c
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-07-14 08:49:12 +0300
committerPaul Buetow <paul@buetow.org>2026-07-14 08:49:12 +0300
commit12be1b9ae52829292d13cc2fcc6ff7571d050d62 (patch)
tree674aafaeb3485bb38dd1e2ecc3d62f77e3584366 /src/loader/loader.c
parent484fbca06312dbe0f381109763f701671f22e602 (diff)
progressive: libjpeg-turbo two-phase JPEG backend (st0)
M6: progressive low-res preview via libjpeg-turbo. - jpeg.c: two-phase decode (1/8 low-res via progress_cb, full via GdkPixbuf with EXIF orientation). Feature-gated. - loader.h/c: LoaderProgressCb + load_progressive on backend struct; loader_load_async accepts progress params; JPEG special-cased in task thread. - window.c: _load_progress_cb marshals partial to main thread. - tests: test_loader_jpeg (progress + dims), test_progressive_jpeg (sample). 16/16 green, ASan clean.
Diffstat (limited to 'src/loader/loader.c')
-rw-r--r--src/loader/loader.c58
1 files changed, 53 insertions, 5 deletions
diff --git a/src/loader/loader.c b/src/loader/loader.c
index 9721c2a..65cc4cb 100644
--- a/src/loader/loader.c
+++ b/src/loader/loader.c
@@ -28,7 +28,6 @@ extern const GgazeLoaderBackend avif_backend;
#ifdef HAVE_HEIF
extern const GgazeLoaderBackend heif_backend;
#endif
-
static const GgazeLoaderBackend *BACKENDS[] = {
#ifdef HAVE_JXL
&jxl_backend,
@@ -70,7 +69,7 @@ loader_load(GFile *p_file, GCancellable *p_cancel, GError **p_err) {
guint8 head[GGAZE_SNIFF_LEN];
gsize u_read = _read_header(p_file, p_cancel, head, GGAZE_SNIFF_LEN, p_err);
- if (u_read == 0 && p_err != NULL && *p_err != NULL) {
+ if (u_read == 0 && p_err != NULL) {
return (NULL);
}
@@ -87,12 +86,54 @@ loader_load(GFile *p_file, GCancellable *p_cancel, GError **p_err) {
/* --- async wrapper (M3) -------------------------------------------------- */
+typedef struct {
+ LoaderProgressCb p_cb;
+ gpointer p_data;
+} ProgressPair;
+
static void
_load_task_thread(GTask *p_task, gpointer p_src, gpointer p_task_data,
GCancellable *p_cancel) {
- (void)p_task_data;
- GError *p_err = NULL;
- GdkTexture *p_tex = loader_load((GFile *)p_src, p_cancel, &p_err);
+ ProgressPair *p_pair = (ProgressPair *)p_task_data;
+ GError *p_err = NULL;
+ GdkTexture *p_tex = NULL;
+
+ /* Sniff and dispatch to the first matching backend. */
+ guint8 head[GGAZE_SNIFF_LEN];
+ gsize u_read =
+ _read_header((GFile *)p_src, p_cancel, head, GGAZE_SNIFF_LEN, &p_err);
+ if (u_read == 0 && p_err != NULL) {
+ g_task_return_error(p_task, p_err);
+ return;
+ }
+ gboolean b_found = FALSE;
+#ifdef HAVE_JPEG
+ extern const GgazeLoaderBackend jpeg_backend;
+ if (detect_format(head, u_read) == GGAZE_FMT_JPEG && p_pair != NULL) {
+ p_tex = jpeg_backend.load_progressive(
+ (GFile *)p_src, p_cancel, p_pair->p_cb, p_pair->p_data, &p_err);
+ b_found = TRUE;
+ }
+#endif
+ if (!b_found) {
+ for (gsize u_i = 0; u_i < G_N_ELEMENTS(BACKENDS); u_i++) {
+ if (BACKENDS[u_i]->can_load(head, u_read)) {
+ if (BACKENDS[u_i]->load_progressive != NULL && p_pair != NULL) {
+ p_tex = BACKENDS[u_i]->load_progressive((GFile *)p_src, p_cancel,
+ p_pair->p_cb,
+ p_pair->p_data, &p_err);
+ } else {
+ p_tex = BACKENDS[u_i]->load((GFile *)p_src, p_cancel, &p_err);
+ }
+ b_found = TRUE;
+ break;
+ }
+ }
+ } /* end if (!b_found) */
+ if (!b_found) {
+ g_set_error(&p_err, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ "unsupported or unrecognized image format");
+ }
if (p_tex == NULL) {
g_task_return_error(p_task, p_err);
} else {
@@ -102,9 +143,16 @@ _load_task_thread(GTask *p_task, gpointer p_src, gpointer p_task_data,
void
loader_load_async(GFile *p_file, GCancellable *p_cancel,
+ LoaderProgressCb p_progress, gpointer p_progress_data,
GAsyncReadyCallback p_cb, gpointer p_data) {
g_return_if_fail(G_IS_FILE(p_file));
GTask *p_task = g_task_new(p_file, p_cancel, p_cb, p_data);
+ if (p_progress != NULL) {
+ ProgressPair *p_pair = g_new(ProgressPair, 1);
+ p_pair->p_cb = p_progress;
+ p_pair->p_data = p_progress_data;
+ g_task_set_task_data(p_task, p_pair, (GDestroyNotify)g_free);
+ }
g_task_run_in_thread(p_task, _load_task_thread);
g_object_unref(p_task);
}