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

[RFC] Downsample when decoding #146

Closed
Closed
Show file tree
Hide file tree
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
18 changes: 17 additions & 1 deletion src/formats/jpeg.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
11 changes: 6 additions & 5 deletions src/formats/loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down
13 changes: 10 additions & 3 deletions src/formats/loader.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
16 changes: 11 additions & 5 deletions src/image.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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");
Expand All @@ -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;
Expand All @@ -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) {
Expand Down Expand Up @@ -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:
Expand Down
9 changes: 8 additions & 1 deletion src/image.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
12 changes: 8 additions & 4 deletions src/imagelist.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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))) {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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]);
Expand Down
Loading