diff --git a/src/formats/jpeg.c b/src/formats/jpeg.c index 561dff7..d4ff080 100644 --- a/src/formats/jpeg.c +++ b/src/formats/jpeg.c @@ -35,7 +35,7 @@ static void jpg_error_exit(j_common_ptr jpg) // JPEG loader implementation enum loader_status decode_jpeg(struct image* ctx, const uint8_t* data, - size_t size) + size_t size, size_t max_w, size_t max_h) { struct pixmap* pm; struct jpeg_decompress_struct jpg; @@ -59,6 +59,22 @@ enum loader_status decode_jpeg(struct image* ctx, const uint8_t* data, jpeg_create_decompress(&jpg); jpeg_mem_src(&jpg, data, size); jpeg_read_header(&jpg, TRUE); + + if (max_w > 0 && max_h > 0) { + // Find out the biggest scaler for our target resolution + while (max_w < jpg.image_width / jpg.scale_denom || + max_h < jpg.image_height / jpg.scale_denom) { + jpg.scale_denom++; + } + if (jpg.scale_denom > 1) { + jpg.scale_denom--; + } + + printf("XXXX SCALE %du = %du X %du\n", jpg.scale_denom, + jpg.image_width / jpg.scale_denom, + jpg.image_height / jpg.scale_denom); + } + jpeg_start_decompress(&jpg); #ifdef LIBJPEG_TURBO_VERSION jpg.out_color_space = JCS_EXT_BGRA; diff --git a/src/formats/loader.c b/src/formats/loader.c index 8940a84..c7dbf07 100644 --- a/src/formats/loader.c +++ b/src/formats/loader.c @@ -12,9 +12,10 @@ // Construct function name of loader #define LOADER_FUNCTION(name) decode_##name // Declaration of loader function -#define LOADER_DECLARE(name) \ - enum loader_status LOADER_FUNCTION(name)(struct image * ctx, \ - const uint8_t* data, size_t size) +#define LOADER_DECLARE(name) \ + enum loader_status LOADER_FUNCTION(name)(struct image * ctx, \ + const uint8_t* data, size_t size, \ + size_t max_w, size_t max_h) const char* supported_formats = "bmp, pnm, tga" #ifdef HAVE_LIBJPEG @@ -124,12 +125,12 @@ static const image_decoder decoders[] = { }; enum loader_status load_image(struct image* ctx, const uint8_t* data, - size_t size) + size_t size, size_t max_w, size_t max_h) { enum loader_status status = ldr_unsupported; for (size_t i = 0; i < sizeof(decoders) / sizeof(decoders[0]); ++i) { - switch (decoders[i](ctx, data, size)) { + switch (decoders[i](ctx, data, size, max_w, max_h)) { case ldr_success: return ldr_success; case ldr_unsupported: diff --git a/src/formats/loader.h b/src/formats/loader.h index 0ef0acd..b69bfce 100644 --- a/src/formats/loader.h +++ b/src/formats/loader.h @@ -24,17 +24,24 @@ extern const char* supported_formats; * @return loader status */ typedef enum loader_status (*image_decoder)(struct image* ctx, - const uint8_t* data, size_t size); + const uint8_t* data, size_t size, + size_t max_w, size_t max_h); /** - * Load image from memory buffer. + * Load image from memory buffer. If max_w and max_h are specified (both non + * zero), the loader will attempt to decode the image to the closest resolution + * that's at least as big as the specified target, respecting the aspect ratio + * of the source image. This is only done if the decoder supports downsampling + * on decode (eg jpg does) * @param ctx image context * @param data raw image data * @param size size of image data in bytes + * @param max_w Maximum render width for this image + * @param max_h Maximum render height for this image * @return loader status */ enum loader_status load_image(struct image* ctx, const uint8_t* data, - size_t size); + size_t size, size_t max_w, size_t max_h); /** * Print decoding problem description. diff --git a/src/image.c b/src/image.c index 19b4cc1..d250911 100644 --- a/src/image.c +++ b/src/image.c @@ -26,7 +26,8 @@ * @return image instance or NULL on errors */ static struct image* image_create(const char* path, const uint8_t* data, - size_t size) + size_t size, + struct target_resolution* tgt_res) { struct image* ctx; enum loader_status status; @@ -48,7 +49,11 @@ static struct image* image_create(const char* path, const uint8_t* data, ctx->file_size = size; // decode image - status = load_image(ctx, data, size); + if (tgt_res) { + status = load_image(ctx, data, size, tgt_res->w, tgt_res->h); + } else { + status = load_image(ctx, data, size, 0, 0); + } if (status != ldr_success) { if (status == ldr_unsupported) { image_print_error(ctx, "unsupported format"); @@ -64,7 +69,8 @@ static struct image* image_create(const char* path, const uint8_t* data, return ctx; } -struct image* image_from_file(const char* file) +struct image* image_from_file(const char* file, + struct target_resolution* tgt_res) { struct image* ctx = NULL; void* data = MAP_FAILED; @@ -89,7 +95,7 @@ struct image* image_from_file(const char* file) goto done; } - ctx = image_create(file, data, st.st_size); + ctx = image_create(file, data, st.st_size, tgt_res); done: if (data != MAP_FAILED) { @@ -132,7 +138,7 @@ struct image* image_from_stdin(void) } if (data) { - ctx = image_create(STDIN_FILE_NAME, data, size); + ctx = image_create(STDIN_FILE_NAME, data, size, NULL); } done: diff --git a/src/image.h b/src/image.h index 4d36880..9fd7da9 100644 --- a/src/image.h +++ b/src/image.h @@ -34,15 +34,22 @@ struct image_info { char* value; ///< Meta value }; +struct target_resolution { + size_t w; ///< Maximum width this image will render to (eg screen width) + size_t h; ///< Maximum height this image will render to (eg screen height) +}; + /** Name used for image, that is read from stdin through pipe. */ #define STDIN_FILE_NAME "{STDIN}" /** * Load image from file. * @param file path to the file to load + * @param target (maximum) resolution for this image. NULL for no maximum. * @return image context or NULL on errors */ -struct image* image_from_file(const char* file); +struct image* image_from_file(const char* file, + struct target_resolution* tgt_res); /** * Load image from stdin data. diff --git a/src/imagelist.c b/src/imagelist.c index a6d302e..f3966eb 100644 --- a/src/imagelist.c +++ b/src/imagelist.c @@ -329,7 +329,8 @@ static void* preloader_thread(__attribute__((unused)) void* data) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); - img = image_from_file(ctx.entries[index]->path); + struct target_resolution tgt_res = { .w = 1920, .h = 1080 }; + img = image_from_file(ctx.entries[index]->path, &tgt_res); if (img) { image_free(ctx.next); ctx.next = img; @@ -537,7 +538,8 @@ bool image_list_scan(const char** files, size_t num) if (strcmp(ctx.entries[ctx.index]->path, STDIN_FILE_NAME) == 0) { ctx.current = image_from_stdin(); } else { - ctx.current = image_from_file(ctx.entries[ctx.index]->path); + struct target_resolution tgt_res = { .w = 1920, .h = 1080 }; + ctx.current = image_from_file(ctx.entries[ctx.index]->path, &tgt_res); } if (!ctx.current && ((force_start && num == 1) || !image_list_jump(jump_next_file))) { @@ -610,7 +612,8 @@ bool image_list_reset(void) // reload current image image_free(ctx.current); - ctx.current = image_from_file(ctx.entries[ctx.index]->path); + struct target_resolution tgt_res = { .w = 1920, .h = 1080 }; + ctx.current = image_from_file(ctx.entries[ctx.index]->path, &tgt_res); if (ctx.current) { preloader_ctl(true); return true; @@ -661,7 +664,8 @@ bool image_list_jump(enum list_jump jump) image = ctx.prev; ctx.prev = NULL; } else { - image = image_from_file(ctx.entries[index]->path); + struct target_resolution tgt_res = { .w = 1920, .h = 1080 }; + image = image_from_file(ctx.entries[index]->path, &tgt_res); if (!image) { // not an image, remove entry from list free(ctx.entries[index]);