diff options
Diffstat (limited to 'source/rofi-icon-fetcher.c')
-rw-r--r-- | source/rofi-icon-fetcher.c | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/source/rofi-icon-fetcher.c b/source/rofi-icon-fetcher.c index e67e2f24..e0917248 100644 --- a/source/rofi-icon-fetcher.c +++ b/source/rofi-icon-fetcher.c @@ -39,6 +39,9 @@ #include "nkutils-xdg-theme.h" +#include <stdint.h> +#include <jpeglib.h> + typedef struct { // Context for icon-themes. @@ -129,6 +132,67 @@ void rofi_icon_fetcher_destroy ( void ) g_free ( rofi_icon_fetcher_data ); } + + + +static cairo_surface_t* cairo_image_surface_create_from_jpeg_private(struct jpeg_decompress_struct* cinfo) { + cairo_surface_t* surface = 0; + unsigned char* data = 0; + unsigned char* rgb = 0; + + jpeg_read_header(cinfo, TRUE); + jpeg_start_decompress(cinfo); + + surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, cinfo->image_width, cinfo->image_height); + data = cairo_image_surface_get_data(surface); + rgb = (unsigned char*)(malloc(cinfo->output_width * cinfo->output_components)); + + while(cinfo->output_scanline < cinfo->output_height) { + unsigned int i; + int scanline = cinfo->output_scanline * cairo_image_surface_get_stride(surface); + + jpeg_read_scanlines(cinfo, &rgb, 1); + + for(i = 0; i < cinfo->output_width; i++) { + int offset = scanline + (i * 4); + + data[offset + 3] = 255; + data[offset + 2] = rgb[(i * 3)]; + data[offset + 1] = rgb[(i * 3) + 1]; + data[offset ] = rgb[(i * 3) + 2]; + } + } + + free(rgb); + + jpeg_finish_decompress(cinfo); + jpeg_destroy_decompress(cinfo); + + cairo_surface_mark_dirty(surface); + + return surface; +} + +static cairo_surface_t* cairo_image_surface_create_from_jpeg(const char* file) { + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + cairo_surface_t* surface; + FILE* infile; + + if((infile = fopen(file, "rb")) == NULL) return NULL; + + cinfo.err = jpeg_std_error(&jerr); + + jpeg_create_decompress(&cinfo); + jpeg_stdio_src(&cinfo, infile); + + surface = cairo_image_surface_create_from_jpeg_private(&cinfo); + + fclose(infile); + + return surface; +} + static void rofi_icon_fetcher_worker ( thread_state *sdata, G_GNUC_UNUSED gpointer user_data ) { g_debug ( "starting up icon fetching thread." ); @@ -160,6 +224,9 @@ static void rofi_icon_fetcher_worker ( thread_state *sdata, G_GNUC_UNUSED gpoint if ( g_str_has_suffix ( icon_path, ".png" ) ) { icon_surf = cairo_image_surface_create_from_png ( icon_path ); } + else if ( g_str_has_suffix ( icon_path, ".jpeg" ) || g_str_has_suffix ( icon_path, ".jpg" ) ) { + icon_surf = cairo_image_surface_create_from_jpeg ( icon_path ); + } else if ( g_str_has_suffix ( icon_path, ".svg" ) ) { icon_surf = cairo_image_surface_create_from_svg ( icon_path, sentry->size ); } @@ -167,6 +234,30 @@ static void rofi_icon_fetcher_worker ( thread_state *sdata, G_GNUC_UNUSED gpoint g_debug ( "icon type not yet supported: %s", icon_path ); } if ( icon_surf ) { + if ( cairo_surface_status ( icon_surf ) == CAIRO_STATUS_SUCCESS ) { + float sw = sentry->size/(float)cairo_image_surface_get_width( icon_surf ); + float sh = sentry->size/(float)cairo_image_surface_get_height( icon_surf ); + + float scale = ( sw > sh)? sh:sw; + if ( scale < 0.5 ) + { + cairo_surface_t * surface = cairo_image_surface_create( + cairo_image_surface_get_format( icon_surf ), + cairo_image_surface_get_width( icon_surf )*scale, + cairo_image_surface_get_height( icon_surf )*scale); + + cairo_t *d = cairo_create ( surface ); + cairo_scale ( d, scale, scale ); + cairo_set_source_surface ( d, icon_surf, 0.0,0.0); + cairo_paint ( d ); + + cairo_destroy ( d ); + cairo_surface_destroy ( icon_surf ); + icon_surf = surface; + } + + + } // check if surface is valid. if ( cairo_surface_status ( icon_surf ) != CAIRO_STATUS_SUCCESS ) { g_debug ( "icon failed to open: %s(%d): %s", sentry->entry->name, sentry->size, icon_path ); |