Initial sixel support

This commit is contained in:
Linus Dierheimer
2022-04-06 14:02:05 +02:00
parent 12371cdc84
commit 5346104ffa
12 changed files with 224 additions and 44 deletions
+38 -5
View File
@@ -5,6 +5,11 @@ project(fastfetch
LANGUAGES C
)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
find_package(PkgConfig REQUIRED)
# This is set to off by github actions for release builds
OPTION(SET_TWEAK "Add tweak to project version" ON)
@@ -23,6 +28,7 @@ OPTION(ENABLE_DCONF "Enable dconf" ON)
OPTION(ENABLE_DBUS "Enable dbus-1" ON)
OPTION(ENABLE_XFCONF "Enable libxfconf-0" ON)
OPTION(ENABLE_RPM "Enable rpm" ON)
OPTION(ENABLE_IMAGEMAGICK "Enable imagemagick" ON)
# Track commits between version bumps for output in --version
if (SET_TWEAK AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
@@ -60,11 +66,6 @@ fastfetch_load_text(src/data/help_config.txt DATATEXT_HELP_CONFIG)
configure_file(src/fastfetch_config.h.in fastfetch_config.h)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
find_package(PkgConfig REQUIRED)
# Init CMake targets
add_library(libfastfetch STATIC
@@ -82,6 +83,7 @@ add_library(libfastfetch STATIC
src/common/networking.c
src/logo/logo.c
src/logo/builtin.c
src/logo/image.c
src/detection/os.c
src/detection/plasma.c
src/detection/gtk.c
@@ -239,6 +241,15 @@ if(ENABLE_RPM)
endif(RPM_FOUND)
endif(ENABLE_RPM)
if(ENABLE_IMAGEMAGICK)
pkg_check_modules (IMAGEMAGICK ImageMagick)
if(IMAGEMAGICK_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_IMAGEMAGICK=1)
else(IMAGEMAGICK_FOUND)
message(WARNING "Package imagemagick not found. Building without support.")
endif(IMAGEMAGICK_FOUND)
endif(ENABLE_IMAGEMAGICK)
target_include_directories(libfastfetch
PUBLIC ${PROJECT_BINARY_DIR}
PUBLIC ${PROJECT_SOURCE_DIR}/src
@@ -255,6 +266,23 @@ target_include_directories(libfastfetch
PRIVATE ${DBUS_INCLUDE_DIRS}
PRIVATE ${XFCONF_INCLUDE_DIRS}
PRIVATE ${RPM_INCLUDE_DIRS}
PRIVATE ${IMAGEMAGICK_INCLUDE_DIRS}
)
target_compile_options(libfastfetch
PRIVATE ${LIBPCI_CFLAGS_OTHER}
PRIVATE ${VULKAN_CFLAGS_OTHER}
PRIVATE ${WAYLAND_CFLAGS_OTHER}
PRIVATE ${XCB_RANDR_CFLAGS_OTHER}
PRIVATE ${XCB_CFLAGS_OTHER}
PRIVATE ${XRANDR_CFLAGS_OTHER}
PRIVATE ${X11_CFLAGS_OTHER}
PRIVATE ${GIO_CFLAGS_OTHER}
PRIVATE ${DCONF_CFLAGS_OTHER}
PRIVATE ${DBUS_CFLAGS_OTHER}
PRIVATE ${XFCONF_CFLAGS_OTHER}
PRIVATE ${RPM_CFLAGS_OTHER}
PRIVATE ${IMAGEMAGICK_CFLAGS_OTHER}
)
target_link_libraries(libfastfetch
@@ -308,6 +336,11 @@ install(
DESTINATION ${CMAKE_INSTALL_BINDIR}
)
install(
TARGETS flashfetch
DESTINATION ${CMAKE_INSTALL_BINDIR}
)
install(
FILES completions/bash
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/bash-completion/completions
+1
View File
@@ -28,6 +28,7 @@ The following libraries are used if present at runtime:
* [`libwayland-client`](https://wayland.freedesktop.org/): Better resolution performance and output in wayland sessions. Supports different refresh rates per monitor.
* [`libGIO`](https://developer.gnome.org/gio/unstable/): Needed for values that are only stored GSettings.
* [`libDConf`](https://developer.gnome.org/dconf/unstable/): Needed for values that are only stored in DConf + Fallback for GSettings.
* [`libmagickcore` (ImageMagick)](https://www.imagemagick.org/): Images in terminal using sixel
* [`libDBus`](https://www.freedesktop.org/wiki/Software/dbus): Needed for detecting current media player and song.
* [`libXFConf`](https://gitlab.xfce.org/xfce/xfconf): Needed for XFWM theme and XFCE Terminal font.
* [`librpm`](http://rpm.org/): Needed for rpm package count.
+3 -1
View File
@@ -91,7 +91,7 @@ static void initCacheDir(FFstate* state)
static void initState(FFstate* state)
{
ffStrbufInit(&state->logoWidthEscapeCode);
state->logoWidth = 0;
state->logoHeight = 0;
state->keysHeight = 0;
state->passwd = getpwuid(getuid());
@@ -108,6 +108,7 @@ static void defaultConfig(FFinstance* instance)
instance->config.logoType = FF_LOGO_TYPE_AUTO;
for(uint8_t i = 0; i < (uint8_t) FASTFETCH_LOGO_MAX_COLORS; ++i)
ffStrbufInit(&instance->config.logoColors[i]);
instance->config.logoWidth = 65;
instance->config.logoPaddingLeft = 0;
instance->config.logoPaddingRight = 4;
instance->config.logoPrintRemaining = true;
@@ -198,6 +199,7 @@ static void defaultConfig(FFinstance* instance)
ffStrbufInitA(&instance->config.libDBus, 0);
ffStrbufInitA(&instance->config.libXFConf, 0);
ffStrbufInitA(&instance->config.librpm, 0);
ffStrbufInitA(&instance->config.libImageMagick, 0);
ffStrbufInitA(&instance->config.diskFolders, 0);
+6
View File
@@ -307,6 +307,12 @@ bool ffParsePropFileValues(const char* filename, uint32_t numQueries, FFpropquer
return true;
}
void ffPrintChar(char c, uint32_t times)
{
for(uint32_t i = 0; i < times; i++)
putchar(c);
}
bool ffParsePropFile(const char* filename, const char* start, FFstrbuf* buffer)
{
return ffParsePropFileValues(filename, 1, (FFpropquery[]){{start, buffer}});
+7 -1
View File
@@ -61,10 +61,16 @@
# Logo type option:
# Sets the logo type to use.
# Must be auto, builtin, file or raw.
# Must be auto, builtin, file, raw or sixel.
# Default is auto.
#--logo-type auto
# Logo width option:
# Sets the width of the logos (in characters) if the logo is an image.
# Must be a positive integer.
# Default is 65.
#--logo-width 65
# Logo color options:
# Overwrite a color in the logo. Also works for user provided logos.
# In the user logo, they replace $[1-9]. Use $$ to print a single $ sign.
+2 -1
View File
@@ -21,7 +21,8 @@ General options:
Logo options:
-l,--logo <logo>: set the logo to use. The type is specified by --logo-type. If default: the name of a builtin logo or a path to a file
--logo-type <type>: set the type of the logo given. Must be auto, builtin, file or raw
--logo-type <type>: set the type of the logo given. Must be auto, builtin, file, raw or sixel
--logo-width <width>: set the width of the logo (in characters), if it is an image
--logo-color-[1-9] <color>: overwrite a color in the logo
--logo-padding <padding>: set the padding on the left and the right of the logo
--logo-padding-left <padding>: set the padding on the left of the logo
+6
View File
@@ -731,6 +731,8 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con
instance->config.logoType = FF_LOGO_TYPE_FILE;
else if(strcasecmp(value, "raw") == 0)
instance->config.logoType = FF_LOGO_TYPE_RAW;
else if(strcasecmp(value, "sixel") == 0)
instance->config.logoType = FF_LOGO_TYPE_SIXEL;
else
{
fprintf(stderr, "Error: unknown logo type: %s\n", value);
@@ -751,6 +753,8 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con
optionParseColor(key, value, &instance->config.logoColors[index]);
}
else if(strcasecmp(key, "--logo-width") == 0)
instance->config.logoWidth = optionParseUInt32(key, value);
else if(strcasecmp(key, "--logo-padding") == 0)
{
uint32_t padding = optionParseUInt32(key, value);
@@ -958,6 +962,8 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con
optionParseString(key, value, &instance->config.libXFConf);
else if(strcasecmp(key, "--lib-rpm") == 0)
optionParseString(key, value, &instance->config.librpm);
else if(strcasecmp(key, "--lib-imagemagick") == 0)
optionParseString(key, value, &instance->config.libImageMagick);
//////////////////
//Module options//
+6 -1
View File
@@ -37,6 +37,7 @@ typedef enum FFLogoType
FF_LOGO_TYPE_BUILTIN, //Builtin ascii art.
FF_LOGO_TYPE_FILE, //Raw text file, printed as is.
FF_LOGO_TYPE_RAW, //Raw text file, printed with color codes replacement.
FF_LOGO_TYPE_SIXEL, //Image file, printed as sixel codes.
} FFLogoType;
typedef struct FFconfig
@@ -44,6 +45,7 @@ typedef struct FFconfig
FFstrbuf logoName;
FFLogoType logoType;
FFstrbuf logoColors[FASTFETCH_LOGO_MAX_COLORS];
uint32_t logoWidth;
uint32_t logoPaddingLeft;
uint32_t logoPaddingRight;
bool logoPrintRemaining;
@@ -133,6 +135,7 @@ typedef struct FFconfig
FFstrbuf libDBus;
FFstrbuf libXFConf;
FFstrbuf librpm;
FFstrbuf libImageMagick;
FFstrbuf diskFolders;
@@ -153,7 +156,7 @@ typedef struct FFconfig
typedef struct FFstate
{
FFstrbuf logoWidthEscapeCode;
uint32_t logoWidth;
uint32_t logoHeight;
uint32_t keysHeight;
@@ -400,6 +403,8 @@ bool ffPrintFromCache(FFinstance* instance, const char* moduleName, const FFstrb
void ffPrintAndSaveToCache(FFinstance* instance, const char* moduleName, const FFstrbuf* customKeyFormat, const FFstrbuf* value, const FFstrbuf* formatString, uint32_t numArgs, const FFformatarg* arguments);
void ffPrintAndAppendToCache(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat, FFcache* cache, const FFstrbuf* value, const FFstrbuf* formatString, uint32_t numArgs, const FFformatarg* arguments);
void ffPrintChar(char c, uint32_t times);
void ffCacheValidate(FFinstance* instance);
void ffCacheOpenWrite(FFinstance* instance, const char* moduleName, FFcache* cache);
void ffCacheClose(FFcache* cache);
+5 -7
View File
@@ -1260,14 +1260,12 @@ static const FFlogo* detectBuiltinLogo(const FFinstance* instance)
void ffLogoSetMainColor(FFinstance* instance)
{
const FFlogo* logo;
const FFlogo* logo = NULL;
if(instance->config.logoName.length > 0)
{
logo = getBuiltinLogo(instance->config.logoName.chars);
if(logo == NULL)
logo = getLogoUnknown();
}
else
logo = getBuiltinLogo(instance->config.logoName.chars);
if(logo == NULL)
logo = detectBuiltinLogo(instance);
ffStrbufAppendS(&instance->config.mainColor, logo->builtinColors[0]);
+119
View File
@@ -0,0 +1,119 @@
#include "logo.h"
#ifdef FF_HAVE_IMAGEMAGICK
#include <MagickCore/MagickCore.h>
#include <sys/ioctl.h>
#include <unistd.h>
static bool printSixel(FFinstance* instance)
{
struct winsize winsize;
if(ioctl(STDOUT_FILENO, TIOCGWINSZ, &winsize) != 0)
return false;
FF_LIBRARY_LOAD(imageMagick, instance->config.libImageMagick, false, "libMagickCore-7.Q16HDRI.so", "libMagickCore-7.Q16HDRI.so.10")
FF_LIBRARY_LOAD_SYMBOL(imageMagick, AcquireExceptionInfo, false)
FF_LIBRARY_LOAD_SYMBOL(imageMagick, DestroyExceptionInfo, false)
FF_LIBRARY_LOAD_SYMBOL(imageMagick, AcquireImageInfo, false)
FF_LIBRARY_LOAD_SYMBOL(imageMagick, DestroyImageInfo, false)
FF_LIBRARY_LOAD_SYMBOL(imageMagick, CopyMagickString, false)
FF_LIBRARY_LOAD_SYMBOL(imageMagick, ReadImage, false)
FF_LIBRARY_LOAD_SYMBOL(imageMagick, ResizeImage, false)
FF_LIBRARY_LOAD_SYMBOL(imageMagick, WriteImage, false)
FF_LIBRARY_LOAD_SYMBOL(imageMagick, DestroyImage, false)
ExceptionInfo* exceptionInfo = ffAcquireExceptionInfo();
if(exceptionInfo == NULL)
{
dlclose(imageMagick);
return false;
}
ImageInfo* imageInfoIn = ffAcquireImageInfo();
if(imageInfoIn == NULL)
{
ffDestroyExceptionInfo(exceptionInfo);
dlclose(imageMagick);
return false;
}
//+1, because we need to copy the null byte too
ffCopyMagickString(imageInfoIn->filename, instance->config.logoName.chars, instance->config.logoName.length + 1);
Image* image = ffReadImage(imageInfoIn, exceptionInfo);
ffDestroyImageInfo(imageInfoIn);
if(image == NULL)
{
ffDestroyExceptionInfo(exceptionInfo);
dlclose(imageMagick);
return false;
}
double characterPixelWidth = winsize.ws_xpixel / (double) winsize.ws_col;
double characterPixelHeight = winsize.ws_ypixel / (double) winsize.ws_row;
//We keep the values as double, to have more precise calculations later
double imagePixelWidth = (double) instance->config.logoWidth * characterPixelWidth;
double imagePixelHeight = (imagePixelWidth / (double) image->columns) * (double) image->rows;
image = ffResizeImage(image, (size_t) imagePixelWidth, (size_t) imagePixelHeight, UndefinedFilter, exceptionInfo);
if(image == NULL)
{
ffDestroyExceptionInfo(exceptionInfo);
dlclose(imageMagick);
return false;
}
ImageInfo* imageInfoOut = ffAcquireImageInfo();
if(imageInfoOut == NULL)
{
ffDestroyImage(image);
ffDestroyExceptionInfo(exceptionInfo);
dlclose(imageMagick);
return false;
}
ffPrintChar(' ', instance->config.logoPaddingLeft);
imageInfoOut->file = stdout;
ffCopyMagickString(imageInfoOut->magick, "SIXEL", 6);
MagickBooleanType writeResult = ffWriteImage(imageInfoOut, image, exceptionInfo);
ffDestroyImageInfo(imageInfoOut);
ffDestroyImage(image);
ffDestroyExceptionInfo(exceptionInfo);
dlclose(imageMagick);
if(writeResult == MagickFalse)
return false;
instance->state.logoHeight = (uint32_t) (imagePixelHeight / characterPixelHeight);
instance->state.logoWidth = (uint32_t) (imagePixelWidth / characterPixelWidth);
instance->state.logoWidth += instance->config.logoPaddingLeft + instance->config.logoPaddingRight;
fputs("\033[9999999D", stdout);
if(instance->state.logoHeight > 0)
{
printf("\033[%uA", instance->state.logoHeight);
return true;
}
return false;
}
#endif
void ffLogoPrintSixel(FFinstance* instance)
{
bool sixelPrinted = false;
#ifdef FF_HAVE_IMAGEMAGICK
sixelPrinted = printSixel(instance);
#endif
if(!sixelPrinted)
ffLogoPrintBuiltinDetected(instance);
}
+28 -28
View File
@@ -2,19 +2,12 @@
#include <ctype.h>
static inline void printSpaces(uint32_t padding)
{
for(uint32_t i = 0; i < padding; i++)
putchar(' ');
}
void ffLogoPrint(FFinstance* instance, const char* data, bool doColorReplacement)
{
uint32_t maxLineLength = 0;
uint32_t currentlineLength = 0;
fputs(FASTFETCH_TEXT_MODIFIER_BOLT, stdout);
printSpaces(instance->config.logoPaddingLeft);
ffPrintChar(' ', instance->config.logoPaddingLeft);
//Use logoColor[0] as the default color
if(doColorReplacement)
@@ -25,7 +18,7 @@ void ffLogoPrint(FFinstance* instance, const char* data, bool doColorReplacement
//We are at the end of a line. Print paddings and update max line length
if(*data == '\n' || (*data == '\r' && *(data + 1) == '\n'))
{
printSpaces(instance->config.logoPaddingRight);
ffPrintChar(' ', instance->config.logoPaddingRight);
//We have \r\n, skip the \r
if(*data == '\r')
@@ -34,10 +27,10 @@ void ffLogoPrint(FFinstance* instance, const char* data, bool doColorReplacement
putchar('\n');
++data;
printSpaces(instance->config.logoPaddingLeft);
ffPrintChar(' ', instance->config.logoPaddingLeft);
if(currentlineLength > maxLineLength)
maxLineLength = currentlineLength;
if(currentlineLength > instance->state.logoWidth)
instance->state.logoWidth = currentlineLength;
currentlineLength = 0;
++instance->state.logoHeight;
@@ -47,7 +40,7 @@ void ffLogoPrint(FFinstance* instance, const char* data, bool doColorReplacement
//Always print tabs as 4 spaces, to have consistent spacing
if(*data == '\t')
{
printSpaces(4);
ffPrintChar(' ', 4);
++data;
continue;
}
@@ -135,25 +128,21 @@ void ffLogoPrint(FFinstance* instance, const char* data, bool doColorReplacement
}
}
printSpaces(instance->config.logoPaddingRight);
ffPrintChar(' ', instance->config.logoPaddingRight);
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
//Happens if the last line is the longest
if(currentlineLength > maxLineLength)
maxLineLength = currentlineLength;
if(currentlineLength > instance->state.logoWidth)
instance->state.logoWidth = currentlineLength;
maxLineLength += instance->config.logoPaddingLeft + instance->config.logoPaddingRight;
instance->state.logoWidth += instance->config.logoPaddingLeft + instance->config.logoPaddingRight;
//If the logo is none, and we have no padding, don't go to the left
if(maxLineLength > 0)
ffStrbufAppendF(&instance->state.logoWidthEscapeCode, "\033[%uC", maxLineLength);
//Go to the leftmost position
fputs("\033[9999999D", stdout);
//If the logo height is > 1, go up the height
if(instance->state.logoHeight > 0)
printf("\033[%uA", instance->state.logoHeight);
//Go to the leftmost position
fputs("\033[9999999D", stdout);
}
static void logoPrintFile(FFinstance* instance, bool doColorReplacement)
@@ -187,9 +176,9 @@ void ffPrintLogo(FFinstance* instance)
if(( //Logo type needs set logo name, but nothing was given. Print question mark
instance->config.logoType == FF_LOGO_TYPE_BUILTIN ||
instance->config.logoType == FF_LOGO_TYPE_FILE ||
instance->config.logoType == FF_LOGO_TYPE_RAW
) && instance->config.logoName.length == 0
)
instance->config.logoType == FF_LOGO_TYPE_RAW ||
instance->config.logoType == FF_LOGO_TYPE_SIXEL
) && instance->config.logoName.length == 0)
ffLogoPrintUnknown(instance);
else if(instance->config.logoType == FF_LOGO_TYPE_BUILTIN)
ffLogoPrintBuiltin(instance);
@@ -197,22 +186,33 @@ void ffPrintLogo(FFinstance* instance)
logoPrintFile(instance, true);
else if(instance->config.logoType == FF_LOGO_TYPE_RAW)
logoPrintFile(instance, false);
else if(instance->config.logoType == FF_LOGO_TYPE_SIXEL)
ffLogoPrintSixel(instance);
else
logoPrintDetected(instance);
}
static inline void printLogoWidth(const FFinstance* instance)
{
if(instance->state.logoWidth > 0)
printf("\033[%uC", instance->state.logoWidth);
}
void ffPrintRemainingLogo(FFinstance* instance)
{
if(!instance->config.logoPrintRemaining)
return;
for(uint32_t i = instance->state.keysHeight; i <= instance->state.logoHeight; i++)
ffStrbufPutTo(&instance->state.logoWidthEscapeCode, stdout);
{
printLogoWidth(instance);
putchar('\n');
}
}
void ffPrintLogoLine(FFinstance* instance)
{
ffStrbufWriteTo(&instance->state.logoWidthEscapeCode, stdout);
printLogoWidth(instance);
++instance->state.keysHeight;
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
}
+3
View File
@@ -16,4 +16,7 @@ void ffLogoPrintBuiltin(FFinstance* instance);
bool ffLogoPrintBuiltinIfExists(FFinstance* instance);
void ffLogoPrintBuiltinDetected(FFinstance* instance);
//image.c
void ffLogoPrintSixel(FFinstance* instance);
#endif