summaryrefslogtreecommitdiffstats
path: root/source/rofi-icon-fetcher.c
diff options
context:
space:
mode:
Diffstat (limited to 'source/rofi-icon-fetcher.c')
-rw-r--r--source/rofi-icon-fetcher.c91
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 );