2022-04-13 23:04:42 +02:00
|
|
|
#include "image.h"
|
2023-01-28 12:40:12 +01:00
|
|
|
#include "common/io/io.h"
|
2022-07-25 13:15:01 +02:00
|
|
|
#include "common/printing.h"
|
2024-05-03 01:08:14 +08:00
|
|
|
#include "util/stringUtils.h"
|
2022-04-06 14:02:05 +02:00
|
|
|
|
2023-06-12 15:10:41 +02:00
|
|
|
#include <limits.h>
|
2023-08-22 15:31:10 +08:00
|
|
|
#include <math.h>
|
2023-06-12 15:10:41 +02:00
|
|
|
|
2023-01-09 13:42:58 +08:00
|
|
|
#ifdef __APPLE__
|
|
|
|
|
#include <sys/syslimits.h>
|
2023-04-02 20:40:37 +08:00
|
|
|
#elif _WIN32
|
|
|
|
|
#include <windows.h>
|
2023-01-09 13:42:58 +08:00
|
|
|
#endif
|
|
|
|
|
|
2023-11-07 15:19:53 +08:00
|
|
|
// https://github.com/kostya/benchmarks/blob/master/base64/test-nolib.c#L145
|
|
|
|
|
static void base64EncodeRaw(uint32_t size, const char *str, uint32_t *out_size, char *output)
|
2022-12-22 21:37:16 +08:00
|
|
|
{
|
2023-11-07 15:19:53 +08:00
|
|
|
static const char chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
|
|
|
char *out = output;
|
|
|
|
|
const char *ends = str + (size - size % 3);
|
|
|
|
|
while (str != ends) {
|
|
|
|
|
uint32_t n = __builtin_bswap32(*(uint32_t*) str);
|
|
|
|
|
*out++ = chars[(n >> 26) & 63];
|
|
|
|
|
*out++ = chars[(n >> 20) & 63];
|
|
|
|
|
*out++ = chars[(n >> 14) & 63];
|
|
|
|
|
*out++ = chars[(n >> 8) & 63];
|
|
|
|
|
str += 3;
|
|
|
|
|
}
|
2022-12-22 21:37:16 +08:00
|
|
|
|
2023-11-07 15:19:53 +08:00
|
|
|
if (size % 3 == 1) {
|
|
|
|
|
uint64_t n = (uint64_t)*str << 16;
|
|
|
|
|
*out++ = chars[(n >> 18) & 63];
|
|
|
|
|
*out++ = chars[(n >> 12) & 63];
|
|
|
|
|
*out++ = '=';
|
|
|
|
|
*out++ = '=';
|
|
|
|
|
} else if (size % 3 == 2) {
|
|
|
|
|
uint64_t n = (uint64_t)*str++ << 16;
|
|
|
|
|
n |= (uint64_t)*str << 8;
|
|
|
|
|
*out++ = chars[(n >> 18) & 63];
|
|
|
|
|
*out++ = chars[(n >> 12) & 63];
|
|
|
|
|
*out++ = chars[(n >> 6) & 63];
|
|
|
|
|
*out++ = '=';
|
2022-12-22 21:37:16 +08:00
|
|
|
}
|
2023-11-07 15:19:53 +08:00
|
|
|
*out = '\0';
|
|
|
|
|
*out_size = (uint32_t) (out - output);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static FFstrbuf base64Encode(const FFstrbuf* in)
|
|
|
|
|
{
|
|
|
|
|
FFstrbuf out = ffStrbufCreateA(10 + in->length * 4 / 3);
|
|
|
|
|
base64EncodeRaw(in->length, in->chars, &out.length, out.chars);
|
|
|
|
|
assert(out.length < out.allocated);
|
|
|
|
|
|
2022-12-22 21:37:16 +08:00
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-03 07:56:43 +08:00
|
|
|
static bool printImageIterm(bool printError)
|
2022-12-22 21:37:16 +08:00
|
|
|
{
|
2023-10-25 14:43:46 +08:00
|
|
|
const FFOptionsLogo* options = &instance.config.logo;
|
2023-04-15 15:29:54 +08:00
|
|
|
FF_STRBUF_AUTO_DESTROY buf = ffStrbufCreate();
|
2023-09-15 10:53:09 +08:00
|
|
|
if(!ffAppendFileBuffer(options->source.chars, &buf))
|
2023-01-01 12:29:08 +08:00
|
|
|
{
|
2024-05-03 07:56:43 +08:00
|
|
|
if (printError)
|
|
|
|
|
fputs("Logo (iterm): Failed to load image file\n", stderr);
|
2022-12-22 21:37:16 +08:00
|
|
|
return false;
|
2023-01-01 12:29:08 +08:00
|
|
|
}
|
2022-12-22 21:37:16 +08:00
|
|
|
|
2023-09-02 00:35:18 -04:00
|
|
|
fflush(stdout);
|
2023-04-15 15:29:54 +08:00
|
|
|
|
|
|
|
|
FF_STRBUF_AUTO_DESTROY base64 = base64Encode(&buf);
|
2023-09-02 00:35:18 -04:00
|
|
|
ffStrbufClear(&buf);
|
|
|
|
|
|
2023-09-15 10:53:09 +08:00
|
|
|
if (!options->width || !options->height)
|
2023-09-02 00:35:18 -04:00
|
|
|
{
|
2024-06-27 10:27:17 +08:00
|
|
|
if (options->position == FF_LOGO_POSITION_LEFT)
|
2023-09-03 22:20:11 +08:00
|
|
|
{
|
|
|
|
|
ffStrbufAppendF(&buf, "\e[2J\e[3J\e[%u;%uH",
|
2023-09-15 10:53:09 +08:00
|
|
|
(unsigned) options->paddingTop,
|
|
|
|
|
(unsigned) options->paddingLeft
|
2023-09-03 22:20:11 +08:00
|
|
|
);
|
|
|
|
|
}
|
2024-06-27 10:27:17 +08:00
|
|
|
else if (options->position == FF_LOGO_POSITION_TOP)
|
2023-09-03 22:39:09 +08:00
|
|
|
{
|
2023-09-15 10:53:09 +08:00
|
|
|
ffStrbufAppendNC(&buf, options->paddingTop, '\n');
|
|
|
|
|
ffStrbufAppendNC(&buf, options->paddingLeft, ' ');
|
2023-09-03 22:39:09 +08:00
|
|
|
}
|
2024-06-27 20:39:22 +08:00
|
|
|
else if (options->position == FF_LOGO_POSITION_RIGHT)
|
|
|
|
|
{
|
|
|
|
|
if (printError)
|
|
|
|
|
fputs("Logo (iterm): Must set logo width and height\n", stderr);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2024-05-10 14:30:00 +08:00
|
|
|
if (options->width)
|
|
|
|
|
ffStrbufAppendF(&buf, "\e]1337;File=inline=1;width=%u:%s\a", (unsigned) options->width, base64.chars);
|
|
|
|
|
else
|
|
|
|
|
ffStrbufAppendF(&buf, "\e]1337;File=inline=1:%s\a", base64.chars);
|
2023-09-02 00:35:18 -04:00
|
|
|
ffWriteFDBuffer(FFUnixFD2NativeFD(STDOUT_FILENO), &buf);
|
|
|
|
|
|
2024-06-27 10:27:17 +08:00
|
|
|
if (options->position == FF_LOGO_POSITION_LEFT)
|
2023-09-03 22:20:11 +08:00
|
|
|
{
|
|
|
|
|
uint16_t X = 0, Y = 0;
|
|
|
|
|
const char* error = ffGetTerminalResponse("\e[6n", "\e[%hu;%huR", &Y, &X);
|
|
|
|
|
if (error)
|
|
|
|
|
{
|
|
|
|
|
fprintf(stderr, "\nLogo (iterm): fail to query cursor position: %s\n", error);
|
|
|
|
|
return true; // We already printed image logo, don't print ascii logo then
|
|
|
|
|
}
|
2023-09-15 10:53:09 +08:00
|
|
|
instance.state.logoWidth = X + options->paddingRight;
|
2023-09-03 22:20:11 +08:00
|
|
|
instance.state.logoHeight = Y;
|
|
|
|
|
fputs("\e[H", stdout);
|
|
|
|
|
}
|
2024-06-27 10:27:17 +08:00
|
|
|
else if (options->position == FF_LOGO_POSITION_TOP)
|
2023-09-02 00:35:18 -04:00
|
|
|
{
|
2023-09-03 22:20:11 +08:00
|
|
|
instance.state.logoWidth = instance.state.logoHeight = 0;
|
2023-09-15 10:53:09 +08:00
|
|
|
ffPrintCharTimes('\n', options->paddingRight);
|
2023-09-02 00:35:18 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2023-09-15 10:53:09 +08:00
|
|
|
ffStrbufAppendNC(&buf, options->paddingTop, '\n');
|
2024-06-27 20:39:22 +08:00
|
|
|
if (options->position == FF_LOGO_POSITION_RIGHT)
|
|
|
|
|
ffStrbufAppendF(&buf, "\e[9999999C\e[%uD", (unsigned) options->paddingRight + options->width);
|
|
|
|
|
else
|
|
|
|
|
ffStrbufAppendF(&buf, "\e[%uC", (unsigned) options->paddingLeft);
|
2023-09-03 22:20:11 +08:00
|
|
|
ffStrbufAppendF(&buf, "\e]1337;File=inline=1;width=%u;height=%u;preserveAspectRatio=%u:%s\a\n",
|
2023-09-15 10:53:09 +08:00
|
|
|
(unsigned) options->width,
|
|
|
|
|
(unsigned) options->height,
|
2023-11-07 08:49:22 +08:00
|
|
|
(unsigned) options->preserveAspectRatio,
|
2023-09-03 22:20:11 +08:00
|
|
|
base64.chars
|
2023-09-02 00:35:18 -04:00
|
|
|
);
|
2023-09-03 22:20:11 +08:00
|
|
|
|
2024-06-27 10:27:17 +08:00
|
|
|
if (options->position == FF_LOGO_POSITION_LEFT)
|
2023-09-03 22:20:11 +08:00
|
|
|
{
|
2023-09-15 10:53:09 +08:00
|
|
|
instance.state.logoWidth = options->width + options->paddingLeft + options->paddingRight;
|
|
|
|
|
instance.state.logoHeight = options->paddingTop + options->height;
|
2023-09-03 22:20:11 +08:00
|
|
|
ffStrbufAppendF(&buf, "\e[%uA", (unsigned) instance.state.logoHeight);
|
|
|
|
|
}
|
2024-06-27 10:27:17 +08:00
|
|
|
else if (options->position == FF_LOGO_POSITION_TOP)
|
2023-09-03 22:20:11 +08:00
|
|
|
{
|
|
|
|
|
instance.state.logoWidth = instance.state.logoHeight = 0;
|
2023-09-15 10:53:09 +08:00
|
|
|
ffStrbufAppendNC(&buf, options->paddingRight, '\n');
|
2023-09-03 22:20:11 +08:00
|
|
|
}
|
2024-06-27 20:39:22 +08:00
|
|
|
else if (options->position == FF_LOGO_POSITION_RIGHT)
|
|
|
|
|
{
|
|
|
|
|
instance.state.logoWidth = instance.state.logoHeight = 0;
|
|
|
|
|
ffStrbufAppendF(&buf, "\e[1G\e[%uA", (unsigned) options->height);
|
|
|
|
|
}
|
2023-09-02 00:35:18 -04:00
|
|
|
ffWriteFDBuffer(FFUnixFD2NativeFD(STDOUT_FILENO), &buf);
|
|
|
|
|
}
|
2022-12-22 21:37:16 +08:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-03 07:56:43 +08:00
|
|
|
static bool printImageKittyDirect(bool printError)
|
2022-12-23 12:34:30 +08:00
|
|
|
{
|
2023-10-25 14:43:46 +08:00
|
|
|
const FFOptionsLogo* options = &instance.config.logo;
|
2024-05-03 07:56:43 +08:00
|
|
|
|
|
|
|
|
if (!ffPathExists(options->source.chars, FF_PATHTYPE_FILE))
|
|
|
|
|
{
|
|
|
|
|
if (printError)
|
|
|
|
|
fputs("Logo (kitty-direct): Failed to load image file\n", stderr);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-15 10:53:09 +08:00
|
|
|
FF_STRBUF_AUTO_DESTROY base64 = base64Encode(&options->source);
|
2023-09-02 00:35:18 -04:00
|
|
|
|
2023-09-15 10:53:09 +08:00
|
|
|
if (!options->width || !options->height)
|
2023-07-18 21:09:37 +08:00
|
|
|
{
|
2024-06-27 10:27:17 +08:00
|
|
|
if (options->position == FF_LOGO_POSITION_LEFT)
|
2023-09-03 22:20:11 +08:00
|
|
|
{
|
|
|
|
|
// We must clear the entre screen to make sure that terminal buffer won't scroll up
|
|
|
|
|
printf("\e[2J\e[3J\e[%u;%uH",
|
2023-09-15 10:53:09 +08:00
|
|
|
(unsigned) options->paddingTop,
|
|
|
|
|
(unsigned) options->paddingLeft
|
2023-09-03 22:20:11 +08:00
|
|
|
);
|
|
|
|
|
}
|
2024-06-27 10:27:17 +08:00
|
|
|
else if (options->position == FF_LOGO_POSITION_TOP)
|
2023-09-03 22:39:09 +08:00
|
|
|
{
|
2023-09-15 10:53:09 +08:00
|
|
|
ffPrintCharTimes('\n', options->paddingTop);
|
|
|
|
|
ffPrintCharTimes(' ', options->paddingLeft);
|
2023-09-03 22:39:09 +08:00
|
|
|
}
|
2024-06-27 20:39:22 +08:00
|
|
|
else if (options->position == FF_LOGO_POSITION_RIGHT)
|
|
|
|
|
{
|
|
|
|
|
if (printError)
|
|
|
|
|
fputs("Logo (iterm): Must set logo width and height\n", stderr);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2024-05-10 14:30:00 +08:00
|
|
|
|
|
|
|
|
if (options->width)
|
|
|
|
|
printf("\e_Ga=T,f=100,t=f,c=%u;%s\e\\", (unsigned) options->width, base64.chars);
|
|
|
|
|
else
|
|
|
|
|
printf("\e_Ga=T,f=100,t=f;%s\e\\", base64.chars);
|
2023-09-02 00:35:18 -04:00
|
|
|
fflush(stdout);
|
2024-06-27 10:27:17 +08:00
|
|
|
if (options->position == FF_LOGO_POSITION_LEFT)
|
2023-09-03 22:20:11 +08:00
|
|
|
{
|
|
|
|
|
uint16_t X = 0, Y = 0;
|
|
|
|
|
const char* error = ffGetTerminalResponse("\e[6n", "\e[%hu;%huR", &Y, &X);
|
|
|
|
|
if (error)
|
|
|
|
|
{
|
|
|
|
|
fprintf(stderr, "\nLogo (kitty-direct): fail to query cursor position: %s\n", error);
|
|
|
|
|
return true; // We already printed image logo, don't print ascii logo then
|
|
|
|
|
}
|
2023-09-15 10:53:09 +08:00
|
|
|
instance.state.logoWidth = X + options->paddingRight;
|
2023-09-03 22:20:11 +08:00
|
|
|
instance.state.logoHeight = Y;
|
|
|
|
|
fputs("\e[H", stdout);
|
|
|
|
|
}
|
2024-06-27 10:27:17 +08:00
|
|
|
else if (options->position == FF_LOGO_POSITION_TOP)
|
2023-09-02 00:35:18 -04:00
|
|
|
{
|
2023-09-03 22:20:11 +08:00
|
|
|
instance.state.logoWidth = instance.state.logoHeight = 0;
|
2023-09-15 10:53:09 +08:00
|
|
|
ffPrintCharTimes('\n', options->paddingRight);
|
2023-09-02 00:35:18 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2023-09-15 10:53:09 +08:00
|
|
|
ffPrintCharTimes('\n', options->paddingTop);
|
2024-06-27 20:39:22 +08:00
|
|
|
if (options->position == FF_LOGO_POSITION_RIGHT)
|
|
|
|
|
printf("\e[9999999C\e[%uD", (unsigned) options->paddingRight + options->width);
|
|
|
|
|
else
|
|
|
|
|
printf("\e[%uC", (unsigned) options->paddingLeft);
|
2023-09-02 00:35:18 -04:00
|
|
|
|
2023-09-03 22:20:11 +08:00
|
|
|
printf("\e_Ga=T,f=100,t=f,c=%u,r=%u;%s\e\\\n",
|
2023-09-15 10:53:09 +08:00
|
|
|
(unsigned) options->width,
|
|
|
|
|
(unsigned) options->height,
|
2023-09-03 22:20:11 +08:00
|
|
|
base64.chars
|
2023-09-02 00:35:18 -04:00
|
|
|
);
|
2024-06-27 10:27:17 +08:00
|
|
|
if (options->position == FF_LOGO_POSITION_LEFT)
|
2023-09-03 22:20:11 +08:00
|
|
|
{
|
2023-09-15 10:53:09 +08:00
|
|
|
instance.state.logoWidth = options->width + options->paddingLeft + options->paddingRight;
|
|
|
|
|
instance.state.logoHeight = options->paddingTop + options->height;
|
2023-09-03 22:20:11 +08:00
|
|
|
printf("\e[%uA", (unsigned) instance.state.logoHeight);
|
|
|
|
|
}
|
2024-06-27 10:27:17 +08:00
|
|
|
else if (options->position == FF_LOGO_POSITION_TOP)
|
2023-09-03 22:20:11 +08:00
|
|
|
{
|
|
|
|
|
instance.state.logoWidth = instance.state.logoHeight = 0;
|
2023-09-15 10:53:09 +08:00
|
|
|
ffPrintCharTimes('\n', options->paddingRight);
|
2023-09-03 22:20:11 +08:00
|
|
|
}
|
2024-06-27 20:39:22 +08:00
|
|
|
else if (options->position == FF_LOGO_POSITION_RIGHT)
|
|
|
|
|
{
|
|
|
|
|
instance.state.logoWidth = instance.state.logoHeight = 0;
|
|
|
|
|
printf("\e[1G\e[%uA", (unsigned) options->height);
|
|
|
|
|
}
|
2023-07-18 21:09:37 +08:00
|
|
|
}
|
2022-12-23 12:34:30 +08:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-11 16:19:02 +02:00
|
|
|
#if defined(FF_HAVE_IMAGEMAGICK7) || defined(FF_HAVE_IMAGEMAGICK6)
|
2022-04-06 14:02:05 +02:00
|
|
|
|
2022-04-14 11:36:57 +02:00
|
|
|
#define FF_KITTY_MAX_CHUNK_SIZE 4096
|
|
|
|
|
|
2022-04-21 15:50:45 +02:00
|
|
|
#define FF_CACHE_FILE_HEIGHT "height"
|
2022-05-23 15:32:10 +02:00
|
|
|
#define FF_CACHE_FILE_WIDTH "width"
|
2022-04-21 15:50:45 +02:00
|
|
|
#define FF_CACHE_FILE_SIXEL "sixel"
|
|
|
|
|
#define FF_CACHE_FILE_KITTY_COMPRESSED "kittyc"
|
|
|
|
|
#define FF_CACHE_FILE_KITTY_UNCOMPRESSED "kittyu"
|
2022-04-28 19:15:46 +02:00
|
|
|
#define FF_CACHE_FILE_CHAFA "chafa"
|
2022-04-19 11:48:08 +02:00
|
|
|
|
2022-04-21 15:50:45 +02:00
|
|
|
#include <string.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <fcntl.h>
|
2022-12-20 11:37:54 +08:00
|
|
|
|
|
|
|
|
#ifndef _WIN32
|
2022-05-23 15:32:10 +02:00
|
|
|
#include <sys/ioctl.h>
|
2022-12-20 11:37:54 +08:00
|
|
|
#else
|
|
|
|
|
#include <wincon.h>
|
|
|
|
|
|
2022-12-20 22:37:15 +08:00
|
|
|
static inline char* realpath(const char* restrict file_name, char* restrict resolved_name)
|
2022-12-20 11:37:54 +08:00
|
|
|
{
|
2022-12-22 02:40:56 +08:00
|
|
|
char* result = _fullpath(resolved_name, file_name, _MAX_PATH);
|
|
|
|
|
if(result)
|
|
|
|
|
{
|
|
|
|
|
resolved_name[1] = resolved_name[0]; // Drive Name
|
|
|
|
|
resolved_name[0] = '/';
|
|
|
|
|
}
|
2023-01-07 21:57:35 +08:00
|
|
|
return result;
|
2022-12-20 11:37:54 +08:00
|
|
|
}
|
|
|
|
|
#endif
|
2022-04-19 11:48:08 +02:00
|
|
|
|
2022-04-14 15:11:14 +02:00
|
|
|
#ifdef FF_HAVE_ZLIB
|
2022-07-25 11:20:38 +02:00
|
|
|
#include "common/library.h"
|
2022-06-18 14:25:31 +02:00
|
|
|
#include <stdlib.h>
|
2022-04-14 15:11:14 +02:00
|
|
|
#include <zlib.h>
|
|
|
|
|
|
2023-06-24 10:59:53 +08:00
|
|
|
static bool compressBlob(void** blob, size_t* length)
|
2022-04-14 15:11:14 +02:00
|
|
|
{
|
2023-10-25 16:24:24 +08:00
|
|
|
FF_LIBRARY_LOAD(zlib, &instance.config.library.libZ, false, "libz" FF_LIBRARY_EXTENSION, 2)
|
2022-04-14 15:11:14 +02:00
|
|
|
FF_LIBRARY_LOAD_SYMBOL(zlib, compressBound, false)
|
|
|
|
|
FF_LIBRARY_LOAD_SYMBOL(zlib, compress2, false)
|
|
|
|
|
|
|
|
|
|
uLong compressedLength = ffcompressBound(*length);
|
|
|
|
|
void* compressed = malloc(compressedLength);
|
|
|
|
|
if(compressed == NULL)
|
|
|
|
|
return false;
|
|
|
|
|
|
2023-02-15 14:51:04 +08:00
|
|
|
if(ffcompress2(compressed, &compressedLength, *blob, *length, Z_BEST_COMPRESSION) != Z_OK)
|
2022-04-14 15:11:14 +02:00
|
|
|
{
|
|
|
|
|
free(compressed);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free(*blob);
|
|
|
|
|
|
|
|
|
|
*length = (size_t) compressedLength;
|
|
|
|
|
*blob = compressed;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif // FF_HAVE_ZLIB
|
|
|
|
|
|
2022-04-11 16:19:02 +02:00
|
|
|
//We use only the defines from here, that are exactly the same in both versions
|
|
|
|
|
#ifdef FF_HAVE_IMAGEMAGICK7
|
|
|
|
|
#include <MagickCore/MagickCore.h>
|
|
|
|
|
#else
|
|
|
|
|
#include <magick/MagickCore.h>
|
|
|
|
|
#endif
|
2022-04-06 14:02:05 +02:00
|
|
|
|
2022-04-21 15:50:45 +02:00
|
|
|
typedef struct ImageData
|
2022-04-14 11:36:57 +02:00
|
|
|
{
|
|
|
|
|
FF_LIBRARY_SYMBOL(CopyMagickString)
|
|
|
|
|
FF_LIBRARY_SYMBOL(ImageToBlob)
|
|
|
|
|
FF_LIBRARY_SYMBOL(Base64Encode)
|
|
|
|
|
|
2022-04-21 15:50:45 +02:00
|
|
|
ImageInfo* imageInfo;
|
|
|
|
|
Image* image;
|
|
|
|
|
ExceptionInfo* exceptionInfo;
|
|
|
|
|
} ImageData;
|
|
|
|
|
|
2022-04-22 13:20:40 +02:00
|
|
|
static inline bool checkAllocationResult(void* data, size_t length)
|
|
|
|
|
{
|
|
|
|
|
if(data == NULL)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if(length == 0)
|
|
|
|
|
{
|
|
|
|
|
free(data);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-23 15:32:10 +02:00
|
|
|
static void writeCacheStrbuf(FFLogoRequestData* requestData, const FFstrbuf* value, const char* cacheFileName)
|
|
|
|
|
{
|
|
|
|
|
uint32_t cacheDirLength = requestData->cacheDir.length;
|
|
|
|
|
ffStrbufAppendS(&requestData->cacheDir, cacheFileName);
|
2022-06-19 18:22:00 +02:00
|
|
|
ffWriteFileBuffer(requestData->cacheDir.chars, value);
|
2022-05-23 15:32:10 +02:00
|
|
|
ffStrbufSubstrBefore(&requestData->cacheDir, cacheDirLength);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void writeCacheUint32(FFLogoRequestData* requestData, uint32_t value, const char* cacheFileName)
|
|
|
|
|
{
|
|
|
|
|
FFstrbuf content;
|
|
|
|
|
content.chars = (char*) &value;
|
|
|
|
|
content.length = sizeof(value);
|
|
|
|
|
writeCacheStrbuf(requestData, &content, cacheFileName);
|
|
|
|
|
}
|
2022-04-21 15:50:45 +02:00
|
|
|
|
2023-06-24 10:59:53 +08:00
|
|
|
static void printImagePixels(FFLogoRequestData* requestData, const FFstrbuf* result, const char* cacheFileName)
|
2022-05-23 15:32:10 +02:00
|
|
|
{
|
2023-10-25 14:43:46 +08:00
|
|
|
const FFOptionsLogo* options = &instance.config.logo;
|
2022-05-23 15:32:10 +02:00
|
|
|
//Calculate character dimensions
|
2023-09-15 10:53:09 +08:00
|
|
|
instance.state.logoWidth = requestData->logoCharacterWidth + options->paddingLeft + options->paddingRight;
|
|
|
|
|
instance.state.logoHeight = requestData->logoCharacterHeight + options->paddingTop - 1;
|
2022-04-28 19:15:46 +02:00
|
|
|
|
2022-05-23 15:32:10 +02:00
|
|
|
//Write cache files
|
|
|
|
|
writeCacheStrbuf(requestData, result, cacheFileName);
|
|
|
|
|
|
2023-09-15 10:53:09 +08:00
|
|
|
if(options->width == 0)
|
2023-09-02 22:32:34 +08:00
|
|
|
writeCacheUint32(requestData, requestData->logoCharacterWidth, FF_CACHE_FILE_WIDTH);
|
2022-05-23 15:32:10 +02:00
|
|
|
|
2023-09-15 10:53:09 +08:00
|
|
|
if(options->height == 0)
|
2023-09-02 22:32:34 +08:00
|
|
|
writeCacheUint32(requestData, requestData->logoCharacterHeight, FF_CACHE_FILE_HEIGHT);
|
2022-04-14 11:36:57 +02:00
|
|
|
|
2022-04-22 13:20:40 +02:00
|
|
|
//Write result to stdout
|
2023-09-15 10:53:09 +08:00
|
|
|
ffPrintCharTimes('\n', options->paddingTop);
|
|
|
|
|
ffPrintCharTimes(' ', options->paddingLeft);
|
2022-04-22 13:20:40 +02:00
|
|
|
fflush(stdout);
|
2023-01-28 22:05:23 +08:00
|
|
|
ffWriteFDBuffer(FFUnixFD2NativeFD(STDOUT_FILENO), result);
|
2022-04-14 11:36:57 +02:00
|
|
|
|
2022-05-23 15:32:10 +02:00
|
|
|
//Go to upper left corner
|
2023-09-03 19:55:57 +08:00
|
|
|
printf("\e[1G\e[%uA", instance.state.logoHeight);
|
2022-04-14 11:36:57 +02:00
|
|
|
}
|
|
|
|
|
|
2023-06-24 10:59:53 +08:00
|
|
|
static bool printImageSixel(FFLogoRequestData* requestData, const ImageData* imageData)
|
2022-04-21 15:50:45 +02:00
|
|
|
{
|
2022-04-22 13:20:40 +02:00
|
|
|
imageData->ffCopyMagickString(imageData->imageInfo->magick, "SIXEL", 6);
|
2022-04-21 15:50:45 +02:00
|
|
|
|
2022-04-22 13:20:40 +02:00
|
|
|
size_t length;
|
|
|
|
|
void* blob = imageData->ffImageToBlob(imageData->imageInfo, imageData->image, &length, imageData->exceptionInfo);
|
|
|
|
|
if(!checkAllocationResult(blob, length))
|
|
|
|
|
return false;
|
2022-04-21 15:50:45 +02:00
|
|
|
|
2022-04-22 13:20:40 +02:00
|
|
|
FFstrbuf result;
|
|
|
|
|
result.chars = (char*) blob;
|
|
|
|
|
result.length = (uint32_t) length;
|
2022-04-21 15:50:45 +02:00
|
|
|
|
2023-06-24 10:59:53 +08:00
|
|
|
printImagePixels(requestData, &result, FF_CACHE_FILE_SIXEL);
|
2022-04-22 13:20:40 +02:00
|
|
|
|
|
|
|
|
free(blob);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2022-04-21 15:50:45 +02:00
|
|
|
|
2022-04-22 13:20:40 +02:00
|
|
|
static void appendKittyChunk(FFstrbuf* result, const char** blob, size_t* length, bool printEscapeCode)
|
2022-04-14 11:36:57 +02:00
|
|
|
{
|
2022-04-22 13:20:40 +02:00
|
|
|
uint32_t chunkSize = *length > FF_KITTY_MAX_CHUNK_SIZE ? FF_KITTY_MAX_CHUNK_SIZE : (uint32_t) *length;
|
|
|
|
|
|
|
|
|
|
if(printEscapeCode)
|
|
|
|
|
ffStrbufAppendS(result, "\033_G");
|
|
|
|
|
else
|
|
|
|
|
ffStrbufAppendC(result, ',');
|
|
|
|
|
|
|
|
|
|
ffStrbufAppendS(result, chunkSize != *length ? "m=1" : "m=0");
|
|
|
|
|
ffStrbufAppendC(result, ';');
|
|
|
|
|
ffStrbufAppendNS(result, chunkSize, *blob);
|
|
|
|
|
ffStrbufAppendS(result, "\033\\");
|
|
|
|
|
*length -= chunkSize;
|
|
|
|
|
*blob += chunkSize;
|
2022-04-14 11:36:57 +02:00
|
|
|
}
|
|
|
|
|
|
2023-06-24 10:59:53 +08:00
|
|
|
static bool printImageKitty(FFLogoRequestData* requestData, const ImageData* imageData)
|
2022-04-14 11:36:57 +02:00
|
|
|
{
|
2022-04-21 15:50:45 +02:00
|
|
|
imageData->ffCopyMagickString(imageData->imageInfo->magick, "RGBA", 5);
|
2022-04-14 11:36:57 +02:00
|
|
|
|
|
|
|
|
size_t length;
|
2022-04-21 15:50:45 +02:00
|
|
|
void* blob = imageData->ffImageToBlob(imageData->imageInfo, imageData->image, &length, imageData->exceptionInfo);
|
2022-04-14 11:36:57 +02:00
|
|
|
if(!checkAllocationResult(blob, length))
|
|
|
|
|
return false;
|
|
|
|
|
|
2022-04-14 15:11:14 +02:00
|
|
|
#ifdef FF_HAVE_ZLIB
|
2023-06-24 10:59:53 +08:00
|
|
|
bool isCompressed = compressBlob(&blob, &length);
|
2022-04-14 15:11:14 +02:00
|
|
|
#else
|
|
|
|
|
bool isCompressed = false;
|
|
|
|
|
#endif
|
|
|
|
|
|
2022-04-21 15:50:45 +02:00
|
|
|
char* chars = imageData->ffBase64Encode(blob, length, &length);
|
2022-04-14 11:36:57 +02:00
|
|
|
free(blob);
|
2022-04-21 15:50:45 +02:00
|
|
|
if(!checkAllocationResult(chars, length))
|
2022-04-14 11:36:57 +02:00
|
|
|
return false;
|
|
|
|
|
|
2023-04-15 15:29:54 +08:00
|
|
|
FF_STRBUF_AUTO_DESTROY result = ffStrbufCreateA((uint32_t) (length + 1024));
|
2022-04-14 11:36:57 +02:00
|
|
|
|
2022-04-21 15:50:45 +02:00
|
|
|
const char* currentPos = chars;
|
|
|
|
|
size_t remainingLength = length;
|
2022-04-14 11:36:57 +02:00
|
|
|
|
2022-05-23 15:32:10 +02:00
|
|
|
ffStrbufAppendF(&result, "\033_Ga=T,f=32,s=%u,v=%u", requestData->logoPixelWidth, requestData->logoPixelHeight);
|
2022-04-22 13:20:40 +02:00
|
|
|
if(isCompressed)
|
|
|
|
|
ffStrbufAppendS(&result, ",o=z");
|
|
|
|
|
appendKittyChunk(&result, ¤tPos, &remainingLength, false);
|
2022-04-21 15:50:45 +02:00
|
|
|
while(remainingLength > 0)
|
2022-04-22 13:20:40 +02:00
|
|
|
appendKittyChunk(&result, ¤tPos, &remainingLength, true);
|
2022-04-14 11:36:57 +02:00
|
|
|
|
2023-06-24 10:59:53 +08:00
|
|
|
printImagePixels(requestData, &result, isCompressed ? FF_CACHE_FILE_KITTY_COMPRESSED : FF_CACHE_FILE_KITTY_UNCOMPRESSED);
|
2022-04-21 15:50:45 +02:00
|
|
|
|
|
|
|
|
free(chars);
|
2022-04-14 11:36:57 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-28 19:15:46 +02:00
|
|
|
#ifdef FF_HAVE_CHAFA
|
2022-12-19 20:41:33 +08:00
|
|
|
#include <chafa.h>
|
2023-06-24 10:59:53 +08:00
|
|
|
static bool printImageChafa(FFLogoRequestData* requestData, const ImageData* imageData)
|
2022-04-28 19:15:46 +02:00
|
|
|
{
|
2023-10-25 16:24:24 +08:00
|
|
|
FF_LIBRARY_LOAD(chafa, &instance.config.library.libChafa, false,
|
2022-12-22 02:07:35 +08:00
|
|
|
"libchafa" FF_LIBRARY_EXTENSION, 1,
|
|
|
|
|
"libchafa-0" FF_LIBRARY_EXTENSION, -1 // Required for Windows
|
|
|
|
|
)
|
2022-04-28 19:15:46 +02:00
|
|
|
FF_LIBRARY_LOAD_SYMBOL(chafa, chafa_symbol_map_new, false)
|
2022-12-22 02:07:35 +08:00
|
|
|
FF_LIBRARY_LOAD_SYMBOL(chafa, chafa_symbol_map_apply_selectors, false)
|
2022-04-28 19:15:46 +02:00
|
|
|
FF_LIBRARY_LOAD_SYMBOL(chafa, chafa_canvas_config_new, false)
|
|
|
|
|
FF_LIBRARY_LOAD_SYMBOL(chafa, chafa_canvas_config_set_geometry, false)
|
|
|
|
|
FF_LIBRARY_LOAD_SYMBOL(chafa, chafa_canvas_config_set_symbol_map, false)
|
|
|
|
|
FF_LIBRARY_LOAD_SYMBOL(chafa, chafa_canvas_new, false)
|
|
|
|
|
FF_LIBRARY_LOAD_SYMBOL(chafa, chafa_canvas_draw_all_pixels, false)
|
|
|
|
|
FF_LIBRARY_LOAD_SYMBOL(chafa, chafa_canvas_print, false)
|
|
|
|
|
FF_LIBRARY_LOAD_SYMBOL(chafa, chafa_canvas_unref, false)
|
|
|
|
|
FF_LIBRARY_LOAD_SYMBOL(chafa, chafa_canvas_config_unref, false)
|
|
|
|
|
FF_LIBRARY_LOAD_SYMBOL(chafa, chafa_symbol_map_unref, false)
|
2022-12-22 02:07:35 +08:00
|
|
|
|
2022-04-28 19:15:46 +02:00
|
|
|
imageData->ffCopyMagickString(imageData->imageInfo->magick, "RGBA", 5);
|
|
|
|
|
size_t length;
|
|
|
|
|
void* blob = imageData->ffImageToBlob(imageData->imageInfo, imageData->image, &length, imageData->exceptionInfo);
|
|
|
|
|
if(!checkAllocationResult(blob, length))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
ChafaSymbolMap* symbolMap = ffchafa_symbol_map_new();
|
2022-12-22 02:07:35 +08:00
|
|
|
GError* error = NULL;
|
2023-06-24 10:59:53 +08:00
|
|
|
if(!ffchafa_symbol_map_apply_selectors(symbolMap, instance.config.logo.chafaSymbols.chars, &error))
|
2022-12-22 02:07:35 +08:00
|
|
|
fputs(error->message, stderr);
|
2022-04-28 19:15:46 +02:00
|
|
|
|
|
|
|
|
ChafaCanvasConfig* canvasConfig = ffchafa_canvas_config_new();
|
2022-05-23 15:32:10 +02:00
|
|
|
ffchafa_canvas_config_set_geometry(canvasConfig, (gint) requestData->logoCharacterWidth, (gint) requestData->logoCharacterHeight);
|
2022-04-28 19:15:46 +02:00
|
|
|
ffchafa_canvas_config_set_symbol_map(canvasConfig, symbolMap);
|
2022-12-22 11:36:13 +08:00
|
|
|
|
2023-06-24 10:59:53 +08:00
|
|
|
if(instance.config.logo.chafaFgOnly)
|
2022-12-22 11:36:13 +08:00
|
|
|
{
|
|
|
|
|
FF_LIBRARY_LOAD_SYMBOL_LAZY(chafa, chafa_canvas_config_set_fg_only_enabled);
|
|
|
|
|
if(ffchafa_canvas_config_set_fg_only_enabled)
|
|
|
|
|
ffchafa_canvas_config_set_fg_only_enabled(canvasConfig, true);
|
|
|
|
|
}
|
2023-06-24 10:59:53 +08:00
|
|
|
if(instance.config.logo.chafaCanvasMode < CHAFA_CANVAS_MODE_MAX)
|
2022-12-22 11:36:13 +08:00
|
|
|
{
|
|
|
|
|
FF_LIBRARY_LOAD_SYMBOL_LAZY(chafa, chafa_canvas_config_set_canvas_mode);
|
|
|
|
|
if(ffchafa_canvas_config_set_canvas_mode)
|
2023-06-24 10:59:53 +08:00
|
|
|
ffchafa_canvas_config_set_canvas_mode(canvasConfig, (ChafaCanvasMode) instance.config.logo.chafaCanvasMode);
|
2022-12-22 11:36:13 +08:00
|
|
|
}
|
2023-06-24 10:59:53 +08:00
|
|
|
if(instance.config.logo.chafaColorSpace < CHAFA_COLOR_SPACE_MAX)
|
2022-12-22 11:36:13 +08:00
|
|
|
{
|
|
|
|
|
FF_LIBRARY_LOAD_SYMBOL_LAZY(chafa, chafa_canvas_config_set_color_space)
|
|
|
|
|
if(ffchafa_canvas_config_set_color_space)
|
2023-06-24 10:59:53 +08:00
|
|
|
ffchafa_canvas_config_set_color_space(canvasConfig, (ChafaColorSpace) instance.config.logo.chafaColorSpace);
|
2022-12-22 11:36:13 +08:00
|
|
|
}
|
2023-06-24 10:59:53 +08:00
|
|
|
if(instance.config.logo.chafaDitherMode < CHAFA_DITHER_MODE_MAX)
|
2022-12-22 11:36:13 +08:00
|
|
|
{
|
|
|
|
|
FF_LIBRARY_LOAD_SYMBOL_LAZY(chafa, chafa_canvas_config_set_dither_mode)
|
|
|
|
|
if(ffchafa_canvas_config_set_dither_mode)
|
2023-06-24 10:59:53 +08:00
|
|
|
ffchafa_canvas_config_set_dither_mode(canvasConfig, (ChafaDitherMode) instance.config.logo.chafaDitherMode);
|
2022-12-22 11:36:13 +08:00
|
|
|
}
|
2022-04-28 19:15:46 +02:00
|
|
|
|
|
|
|
|
ChafaCanvas* canvas = ffchafa_canvas_new(canvasConfig);
|
|
|
|
|
ffchafa_canvas_draw_all_pixels(
|
|
|
|
|
canvas,
|
|
|
|
|
CHAFA_PIXEL_RGBA8_UNASSOCIATED,
|
|
|
|
|
blob,
|
|
|
|
|
(gint) imageData->image->columns,
|
|
|
|
|
(gint) imageData->image->rows,
|
|
|
|
|
(gint) imageData->image->columns * 4
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
GString* str = ffchafa_canvas_print(canvas, NULL);
|
|
|
|
|
FFstrbuf result;
|
2022-05-23 15:32:10 +02:00
|
|
|
result.allocated = (uint32_t) str->allocated_len;
|
2022-04-28 19:15:46 +02:00
|
|
|
result.length = (uint32_t) str->len;
|
2022-05-23 15:32:10 +02:00
|
|
|
result.chars = str->str;
|
2022-12-20 22:44:45 +08:00
|
|
|
|
2023-06-24 10:59:53 +08:00
|
|
|
ffLogoPrintChars(result.chars, false);
|
2022-05-23 15:32:10 +02:00
|
|
|
writeCacheStrbuf(requestData, &result, FF_CACHE_FILE_CHAFA);
|
2022-04-28 19:15:46 +02:00
|
|
|
|
2022-12-22 11:36:13 +08:00
|
|
|
// FIXME: These functions must be imported from `libglib` dlls on Windows
|
|
|
|
|
FF_LIBRARY_LOAD_SYMBOL_LAZY(chafa, g_string_free);
|
|
|
|
|
if(ffg_string_free)
|
|
|
|
|
ffg_string_free(str, TRUE);
|
|
|
|
|
if(error)
|
|
|
|
|
{
|
|
|
|
|
FF_LIBRARY_LOAD_SYMBOL_LAZY(chafa, g_error_free)
|
|
|
|
|
if(ffg_error_free)
|
|
|
|
|
ffg_error_free(error);
|
|
|
|
|
}
|
2022-12-22 02:07:35 +08:00
|
|
|
|
2022-04-28 19:15:46 +02:00
|
|
|
ffchafa_canvas_unref(canvas);
|
|
|
|
|
ffchafa_canvas_config_unref(canvasConfig);
|
|
|
|
|
ffchafa_symbol_map_unref(symbolMap);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2023-06-24 10:59:53 +08:00
|
|
|
FFLogoImageResult ffLogoPrintImageImpl(FFLogoRequestData* requestData, const FFIMData* imData)
|
2022-04-06 14:02:05 +02:00
|
|
|
{
|
2022-12-20 11:01:13 +08:00
|
|
|
FF_LIBRARY_LOAD_SYMBOL(imData->library, MagickCoreGenesis, FF_LOGO_IMAGE_RESULT_INIT_ERROR);
|
|
|
|
|
FF_LIBRARY_LOAD_SYMBOL(imData->library, MagickCoreTerminus, FF_LOGO_IMAGE_RESULT_INIT_ERROR);
|
2022-04-21 15:50:45 +02:00
|
|
|
FF_LIBRARY_LOAD_SYMBOL(imData->library, AcquireExceptionInfo, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
|
|
|
|
|
FF_LIBRARY_LOAD_SYMBOL(imData->library, DestroyExceptionInfo, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
|
|
|
|
|
FF_LIBRARY_LOAD_SYMBOL(imData->library, AcquireImageInfo, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
|
|
|
|
|
FF_LIBRARY_LOAD_SYMBOL(imData->library, DestroyImageInfo, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
|
|
|
|
|
FF_LIBRARY_LOAD_SYMBOL(imData->library, ReadImage, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
|
|
|
|
|
FF_LIBRARY_LOAD_SYMBOL(imData->library, DestroyImage, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
|
2022-04-14 11:36:57 +02:00
|
|
|
|
2022-04-21 15:50:45 +02:00
|
|
|
ImageData imageData;
|
2022-04-14 11:36:57 +02:00
|
|
|
|
2022-09-10 13:36:15 +08:00
|
|
|
FF_LIBRARY_LOAD_SYMBOL_VAR(imData->library, imageData, CopyMagickString, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
|
|
|
|
|
FF_LIBRARY_LOAD_SYMBOL_VAR(imData->library, imageData, ImageToBlob, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
|
|
|
|
|
FF_LIBRARY_LOAD_SYMBOL_VAR(imData->library, imageData, Base64Encode, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
|
2022-04-06 14:02:05 +02:00
|
|
|
|
2022-12-20 11:01:13 +08:00
|
|
|
ffMagickCoreGenesis(NULL, MagickFalse);
|
|
|
|
|
|
2022-04-21 15:50:45 +02:00
|
|
|
imageData.exceptionInfo = ffAcquireExceptionInfo();
|
|
|
|
|
if(imageData.exceptionInfo == NULL)
|
2022-12-20 11:01:13 +08:00
|
|
|
{
|
|
|
|
|
ffMagickCoreTerminus();
|
2022-04-13 23:13:25 +02:00
|
|
|
return FF_LOGO_IMAGE_RESULT_RUN_ERROR;
|
2022-12-20 11:01:13 +08:00
|
|
|
}
|
2022-04-06 14:02:05 +02:00
|
|
|
|
|
|
|
|
ImageInfo* imageInfoIn = ffAcquireImageInfo();
|
|
|
|
|
if(imageInfoIn == NULL)
|
|
|
|
|
{
|
2022-04-21 15:50:45 +02:00
|
|
|
ffDestroyExceptionInfo(imageData.exceptionInfo);
|
2022-12-20 11:01:13 +08:00
|
|
|
ffMagickCoreTerminus();
|
2022-04-13 23:13:25 +02:00
|
|
|
return FF_LOGO_IMAGE_RESULT_RUN_ERROR;
|
2022-04-06 14:02:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+1, because we need to copy the null byte too
|
2023-06-24 10:59:53 +08:00
|
|
|
imageData.ffCopyMagickString(imageInfoIn->filename, instance.config.logo.source.chars, instance.config.logo.source.length + 1);
|
2022-04-06 14:02:05 +02:00
|
|
|
|
2022-05-23 15:32:10 +02:00
|
|
|
imageData.image = ffReadImage(imageInfoIn, imageData.exceptionInfo);
|
2022-04-06 14:02:05 +02:00
|
|
|
ffDestroyImageInfo(imageInfoIn);
|
2022-05-23 15:32:10 +02:00
|
|
|
if(imageData.image == NULL)
|
2022-04-06 14:02:05 +02:00
|
|
|
{
|
2022-04-21 15:50:45 +02:00
|
|
|
ffDestroyExceptionInfo(imageData.exceptionInfo);
|
2022-12-20 11:01:13 +08:00
|
|
|
ffMagickCoreTerminus();
|
2022-04-13 23:13:25 +02:00
|
|
|
return FF_LOGO_IMAGE_RESULT_RUN_ERROR;
|
2022-04-06 14:02:05 +02:00
|
|
|
}
|
|
|
|
|
|
2022-05-23 15:32:10 +02:00
|
|
|
if(requestData->logoPixelWidth == 0 && requestData->logoPixelHeight == 0)
|
2022-04-10 22:08:41 +02:00
|
|
|
{
|
2022-05-23 15:32:10 +02:00
|
|
|
requestData->logoPixelWidth = (uint32_t) imageData.image->columns;
|
|
|
|
|
requestData->logoPixelHeight = (uint32_t) imageData.image->rows;
|
2022-04-10 22:08:41 +02:00
|
|
|
}
|
2022-05-23 15:32:10 +02:00
|
|
|
else if(requestData->logoPixelWidth == 0)
|
|
|
|
|
requestData->logoPixelWidth = (uint32_t) ((double) imageData.image->columns / (double) imageData.image->rows * requestData->logoPixelHeight);
|
|
|
|
|
else if(requestData->logoPixelHeight == 0)
|
|
|
|
|
requestData->logoPixelHeight = (uint32_t) ((double) imageData.image->rows / (double) imageData.image->columns * requestData->logoPixelWidth);
|
|
|
|
|
|
2023-08-22 15:31:10 +08:00
|
|
|
requestData->logoCharacterWidth = (uint32_t) ceil((double) requestData->logoPixelWidth / requestData->characterPixelWidth);
|
|
|
|
|
requestData->logoCharacterHeight = (uint32_t) ceil((double) requestData->logoPixelHeight / requestData->characterPixelHeight);
|
2022-04-10 22:08:41 +02:00
|
|
|
|
2022-05-23 15:32:10 +02:00
|
|
|
if(requestData->logoPixelWidth == 0 || requestData->logoPixelHeight == 0 || requestData->logoCharacterWidth == 0 || requestData->logoCharacterHeight == 0)
|
2022-04-06 14:02:05 +02:00
|
|
|
{
|
2022-05-23 15:32:10 +02:00
|
|
|
ffDestroyImage(imageData.image);
|
|
|
|
|
ffDestroyExceptionInfo(imageData.exceptionInfo);
|
2022-12-20 11:01:13 +08:00
|
|
|
ffMagickCoreTerminus();
|
2022-05-23 15:32:10 +02:00
|
|
|
return FF_LOGO_IMAGE_RESULT_RUN_ERROR;
|
2022-04-28 19:15:46 +02:00
|
|
|
}
|
2022-05-23 15:32:10 +02:00
|
|
|
|
|
|
|
|
Image* resized = imData->resizeFunc(imageData.image, requestData->logoPixelWidth, requestData->logoPixelHeight, imageData.exceptionInfo);
|
|
|
|
|
ffDestroyImage(imageData.image);
|
|
|
|
|
if(resized == NULL)
|
2022-04-28 19:15:46 +02:00
|
|
|
{
|
2022-05-23 15:32:10 +02:00
|
|
|
ffDestroyExceptionInfo(imageData.exceptionInfo);
|
2022-12-20 11:01:13 +08:00
|
|
|
ffMagickCoreTerminus();
|
2022-05-23 15:32:10 +02:00
|
|
|
return FF_LOGO_IMAGE_RESULT_RUN_ERROR;
|
2022-04-06 14:02:05 +02:00
|
|
|
}
|
2022-05-23 15:32:10 +02:00
|
|
|
imageData.image = resized;
|
2022-04-06 14:02:05 +02:00
|
|
|
|
2022-04-21 15:50:45 +02:00
|
|
|
imageData.imageInfo = ffAcquireImageInfo();
|
|
|
|
|
if(imageData.imageInfo == NULL)
|
2022-04-06 14:02:05 +02:00
|
|
|
{
|
2022-04-21 15:50:45 +02:00
|
|
|
ffDestroyImage(imageData.image);
|
|
|
|
|
ffDestroyExceptionInfo(imageData.exceptionInfo);
|
2022-12-20 11:01:13 +08:00
|
|
|
ffMagickCoreTerminus();
|
2022-04-13 23:13:25 +02:00
|
|
|
return FF_LOGO_IMAGE_RESULT_RUN_ERROR;
|
2022-04-06 14:02:05 +02:00
|
|
|
}
|
|
|
|
|
|
2022-05-23 15:32:10 +02:00
|
|
|
bool printSuccessful = false;
|
2022-12-12 13:43:10 +01:00
|
|
|
if(requestData->type == FF_LOGO_TYPE_IMAGE_CHAFA)
|
2022-05-23 15:36:19 +02:00
|
|
|
{
|
|
|
|
|
#ifdef FF_HAVE_CHAFA
|
2023-06-24 10:59:53 +08:00
|
|
|
printSuccessful = printImageChafa(requestData, &imageData);
|
2022-05-23 15:36:19 +02:00
|
|
|
#endif
|
|
|
|
|
}
|
2022-12-12 13:43:10 +01:00
|
|
|
else if(requestData->type == FF_LOGO_TYPE_IMAGE_KITTY)
|
2023-06-24 10:59:53 +08:00
|
|
|
printSuccessful = printImageKitty(requestData, &imageData);
|
2022-12-12 13:43:10 +01:00
|
|
|
else if(requestData->type == FF_LOGO_TYPE_IMAGE_SIXEL)
|
2023-06-24 10:59:53 +08:00
|
|
|
printSuccessful = printImageSixel(requestData, &imageData);
|
2022-04-06 14:02:05 +02:00
|
|
|
|
2022-04-21 15:50:45 +02:00
|
|
|
ffDestroyImageInfo(imageData.imageInfo);
|
|
|
|
|
ffDestroyImage(imageData.image);
|
|
|
|
|
ffDestroyExceptionInfo(imageData.exceptionInfo);
|
2022-12-20 11:01:13 +08:00
|
|
|
ffMagickCoreTerminus();
|
2022-04-06 14:02:05 +02:00
|
|
|
|
2022-04-22 13:20:40 +02:00
|
|
|
return printSuccessful ? FF_LOGO_IMAGE_RESULT_SUCCESS : FF_LOGO_IMAGE_RESULT_RUN_ERROR;
|
2022-04-06 14:02:05 +02:00
|
|
|
}
|
2022-04-13 23:04:42 +02:00
|
|
|
|
2022-04-22 13:20:40 +02:00
|
|
|
static int getCacheFD(FFLogoRequestData* requestData, const char* fileName)
|
2022-04-21 15:50:45 +02:00
|
|
|
{
|
|
|
|
|
uint32_t cacheDirLength = requestData->cacheDir.length;
|
2022-04-22 13:20:40 +02:00
|
|
|
ffStrbufAppendS(&requestData->cacheDir, fileName);
|
2023-12-04 20:32:46 +08:00
|
|
|
int fd = open(requestData->cacheDir.chars, O_RDONLY
|
|
|
|
|
#ifdef O_CLOEXEC
|
|
|
|
|
| O_CLOEXEC
|
|
|
|
|
#endif
|
|
|
|
|
);
|
2022-04-21 15:50:45 +02:00
|
|
|
ffStrbufSubstrBefore(&requestData->cacheDir, cacheDirLength);
|
2022-04-22 13:20:40 +02:00
|
|
|
return fd;
|
2022-04-21 15:50:45 +02:00
|
|
|
}
|
|
|
|
|
|
2022-05-23 15:32:10 +02:00
|
|
|
static void readCachedStrbuf(FFLogoRequestData* requestData, FFstrbuf* result, const char* cacheFileName)
|
2022-04-21 15:50:45 +02:00
|
|
|
{
|
2022-05-23 15:32:10 +02:00
|
|
|
uint32_t cacheDirLength = requestData->cacheDir.length;
|
|
|
|
|
ffStrbufAppendS(&requestData->cacheDir, cacheFileName);
|
2022-06-20 16:27:33 +02:00
|
|
|
ffAppendFileBuffer(requestData->cacheDir.chars, result);
|
2022-05-23 15:32:10 +02:00
|
|
|
ffStrbufSubstrBefore(&requestData->cacheDir, cacheDirLength);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static uint32_t readCachedUint32(FFLogoRequestData* requestData, const char* cacheFileName)
|
|
|
|
|
{
|
2023-04-15 15:29:54 +08:00
|
|
|
FF_STRBUF_AUTO_DESTROY content = ffStrbufCreate();
|
2022-05-23 15:32:10 +02:00
|
|
|
readCachedStrbuf(requestData, &content, cacheFileName);
|
|
|
|
|
|
|
|
|
|
uint32_t result = 0;
|
|
|
|
|
|
|
|
|
|
if(content.length != sizeof(result))
|
|
|
|
|
return 0;
|
2022-04-21 15:50:45 +02:00
|
|
|
|
2022-05-23 15:32:10 +02:00
|
|
|
memcpy(&result, content.chars, sizeof(result));
|
2022-04-21 15:50:45 +02:00
|
|
|
|
2022-05-23 15:32:10 +02:00
|
|
|
return result;
|
|
|
|
|
}
|
2022-04-21 15:50:45 +02:00
|
|
|
|
2023-06-24 10:59:53 +08:00
|
|
|
static bool printCachedChars(FFLogoRequestData* requestData)
|
2022-05-23 15:32:10 +02:00
|
|
|
{
|
2023-04-15 15:29:54 +08:00
|
|
|
FF_STRBUF_AUTO_DESTROY content = ffStrbufCreateA(32768);
|
2022-05-23 15:32:10 +02:00
|
|
|
|
2022-12-12 13:43:10 +01:00
|
|
|
if(requestData->type == FF_LOGO_TYPE_IMAGE_CHAFA)
|
2022-05-23 15:32:10 +02:00
|
|
|
readCachedStrbuf(requestData, &content, FF_CACHE_FILE_CHAFA);
|
|
|
|
|
|
|
|
|
|
if(content.length == 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
2023-06-24 10:59:53 +08:00
|
|
|
ffLogoPrintChars(content.chars, false);
|
2022-05-23 15:32:10 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-24 10:59:53 +08:00
|
|
|
static bool printCachedPixel(FFLogoRequestData* requestData)
|
2022-05-23 15:32:10 +02:00
|
|
|
{
|
2023-06-24 10:59:53 +08:00
|
|
|
requestData->logoCharacterWidth = instance.config.logo.width;
|
2022-05-23 15:32:10 +02:00
|
|
|
if(requestData->logoCharacterWidth == 0)
|
|
|
|
|
{
|
|
|
|
|
requestData->logoCharacterWidth = readCachedUint32(requestData, FF_CACHE_FILE_WIDTH);
|
|
|
|
|
if(requestData->logoCharacterWidth == 0)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2022-04-21 15:50:45 +02:00
|
|
|
|
2023-06-24 10:59:53 +08:00
|
|
|
requestData->logoCharacterHeight = instance.config.logo.height;
|
2022-05-23 15:32:10 +02:00
|
|
|
if(requestData->logoCharacterHeight == 0)
|
|
|
|
|
{
|
|
|
|
|
requestData->logoCharacterHeight = readCachedUint32(requestData, FF_CACHE_FILE_HEIGHT);
|
|
|
|
|
if(requestData->logoCharacterHeight == 0)
|
2022-04-30 11:22:51 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
2022-04-21 15:50:45 +02:00
|
|
|
|
2022-05-23 15:32:10 +02:00
|
|
|
int fd = -1;
|
2022-12-12 13:43:10 +01:00
|
|
|
if(requestData->type == FF_LOGO_TYPE_IMAGE_KITTY)
|
2022-04-22 13:20:40 +02:00
|
|
|
{
|
|
|
|
|
fd = getCacheFD(requestData, FF_CACHE_FILE_KITTY_COMPRESSED);
|
|
|
|
|
if(fd == -1)
|
|
|
|
|
fd = getCacheFD(requestData, FF_CACHE_FILE_KITTY_UNCOMPRESSED);
|
|
|
|
|
}
|
2022-12-12 13:43:10 +01:00
|
|
|
else if(requestData->type == FF_LOGO_TYPE_IMAGE_SIXEL)
|
2022-04-22 13:20:40 +02:00
|
|
|
fd = getCacheFD(requestData, FF_CACHE_FILE_SIXEL);
|
|
|
|
|
|
|
|
|
|
if(fd == -1)
|
|
|
|
|
return false;
|
|
|
|
|
|
2023-06-24 10:59:53 +08:00
|
|
|
ffPrintCharTimes('\n', instance.config.logo.paddingTop);
|
|
|
|
|
ffPrintCharTimes(' ', instance.config.logo.paddingLeft);
|
2022-04-22 13:20:40 +02:00
|
|
|
fflush(stdout);
|
|
|
|
|
|
|
|
|
|
char buffer[32768];
|
|
|
|
|
ssize_t readBytes;
|
2023-01-28 22:05:23 +08:00
|
|
|
while((readBytes = ffReadFDData(FFUnixFD2NativeFD(fd), sizeof(buffer), buffer)) > 0)
|
|
|
|
|
ffWriteFDData(FFUnixFD2NativeFD(STDOUT_FILENO), (size_t) readBytes, buffer);
|
2022-04-22 13:20:40 +02:00
|
|
|
|
|
|
|
|
close(fd);
|
|
|
|
|
|
2023-06-24 10:59:53 +08:00
|
|
|
instance.state.logoWidth = requestData->logoCharacterWidth + instance.config.logo.paddingLeft + instance.config.logo.paddingRight;
|
|
|
|
|
instance.state.logoHeight = requestData->logoCharacterHeight + instance.config.logo.paddingTop;
|
2022-05-23 15:32:10 +02:00
|
|
|
|
|
|
|
|
//Go to upper left corner
|
2023-09-03 19:55:57 +08:00
|
|
|
printf("\e[1G\e[%uA", instance.state.logoHeight);
|
2022-04-22 13:20:40 +02:00
|
|
|
return true;
|
2022-04-21 15:50:45 +02:00
|
|
|
}
|
|
|
|
|
|
2023-06-24 10:59:53 +08:00
|
|
|
static bool printCached(FFLogoRequestData* requestData)
|
2022-04-21 15:50:45 +02:00
|
|
|
{
|
2022-12-12 13:43:10 +01:00
|
|
|
if(requestData->type == FF_LOGO_TYPE_IMAGE_CHAFA)
|
2023-06-24 10:59:53 +08:00
|
|
|
return printCachedChars(requestData);
|
2022-05-23 15:32:10 +02:00
|
|
|
else
|
2023-06-24 10:59:53 +08:00
|
|
|
return printCachedPixel(requestData);
|
2022-05-23 15:32:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool getCharacterPixelDimensions(FFLogoRequestData* requestData)
|
|
|
|
|
{
|
2022-12-20 11:37:54 +08:00
|
|
|
#ifndef _WIN32
|
|
|
|
|
|
2022-05-23 15:32:10 +02:00
|
|
|
struct winsize winsize;
|
|
|
|
|
|
2022-04-21 15:50:45 +02:00
|
|
|
//Initialize every member to 0, because it isn't guaranteed that every terminal sets them all
|
2022-05-23 15:32:10 +02:00
|
|
|
memset(&winsize, 0, sizeof(struct winsize));
|
|
|
|
|
|
|
|
|
|
ioctl(STDOUT_FILENO, TIOCGWINSZ, &winsize);
|
2022-04-21 15:50:45 +02:00
|
|
|
|
2022-05-23 15:32:10 +02:00
|
|
|
if(winsize.ws_row == 0 || winsize.ws_col == 0)
|
|
|
|
|
ffGetTerminalResponse("\033[18t", "\033[8;%hu;%hut", &winsize.ws_row, &winsize.ws_col);
|
2022-04-21 15:50:45 +02:00
|
|
|
|
2022-05-23 15:32:10 +02:00
|
|
|
if(winsize.ws_row == 0 || winsize.ws_col == 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if(winsize.ws_ypixel == 0 || winsize.ws_xpixel == 0)
|
|
|
|
|
ffGetTerminalResponse("\033[14t", "\033[4;%hu;%hut", &winsize.ws_ypixel, &winsize.ws_xpixel);
|
2022-04-21 15:50:45 +02:00
|
|
|
|
2022-05-23 15:32:10 +02:00
|
|
|
requestData->characterPixelWidth = winsize.ws_xpixel / (double) winsize.ws_col;
|
|
|
|
|
requestData->characterPixelHeight = winsize.ws_ypixel / (double) winsize.ws_row;
|
2022-04-21 15:50:45 +02:00
|
|
|
|
2022-12-20 11:37:54 +08:00
|
|
|
#else
|
|
|
|
|
|
|
|
|
|
CONSOLE_FONT_INFO cfi;
|
2022-12-20 22:44:45 +08:00
|
|
|
if(GetCurrentConsoleFont(GetStdHandle(STD_OUTPUT_HANDLE), FALSE, &cfi) == FALSE) // Only works for ConHost
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
requestData->characterPixelWidth = cfi.dwFontSize.X;
|
|
|
|
|
requestData->characterPixelHeight = cfi.dwFontSize.Y;
|
2022-12-20 11:37:54 +08:00
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
2022-05-23 15:32:10 +02:00
|
|
|
return requestData->characterPixelWidth > 1.0 && requestData->characterPixelHeight > 1.0;
|
2022-04-21 15:50:45 +02:00
|
|
|
}
|
|
|
|
|
|
2023-06-24 10:59:53 +08:00
|
|
|
static bool printImageIfExistsSlowPath(FFLogoType type, bool printError)
|
2022-04-06 14:02:05 +02:00
|
|
|
{
|
2022-04-21 15:50:45 +02:00
|
|
|
FFLogoRequestData requestData;
|
|
|
|
|
requestData.type = type;
|
2022-05-23 15:32:10 +02:00
|
|
|
requestData.characterPixelWidth = 1;
|
|
|
|
|
requestData.characterPixelHeight = 1;
|
|
|
|
|
|
2024-03-14 10:03:54 +08:00
|
|
|
if(!getCharacterPixelDimensions(&requestData))
|
|
|
|
|
{
|
2023-01-28 11:14:16 +01:00
|
|
|
if(printError)
|
2024-05-04 19:14:45 +08:00
|
|
|
fputs("Logo: getCharacterPixelDimensions() failed\n", stderr);
|
2022-06-08 10:59:33 +02:00
|
|
|
return false;
|
2022-12-23 12:44:19 +08:00
|
|
|
}
|
2022-04-21 15:50:45 +02:00
|
|
|
|
2023-08-22 15:31:10 +08:00
|
|
|
requestData.logoPixelWidth = (uint32_t) ceil((double) instance.config.logo.width * requestData.characterPixelWidth);
|
|
|
|
|
requestData.logoPixelHeight = (uint32_t) ceil((double) instance.config.logo.height * requestData.characterPixelHeight);
|
2022-04-30 11:22:51 +02:00
|
|
|
|
2023-01-15 15:57:26 +01:00
|
|
|
ffStrbufInit(&requestData.cacheDir);
|
2023-06-24 10:59:53 +08:00
|
|
|
ffStrbufAppend(&requestData.cacheDir, &instance.state.platform.cacheDir);
|
2023-01-28 11:28:05 +01:00
|
|
|
ffStrbufAppendS(&requestData.cacheDir, "fastfetch/images");
|
2022-04-21 15:50:45 +02:00
|
|
|
|
|
|
|
|
ffStrbufEnsureFree(&requestData.cacheDir, PATH_MAX);
|
2023-06-24 10:59:53 +08:00
|
|
|
if(realpath(instance.config.logo.source.chars, requestData.cacheDir.chars + requestData.cacheDir.length) == NULL)
|
2022-04-21 15:50:45 +02:00
|
|
|
{
|
|
|
|
|
//We can safely return here, because if realpath failed, we surely won't be able to read the file
|
|
|
|
|
ffStrbufDestroy(&requestData.cacheDir);
|
2023-01-28 11:14:16 +01:00
|
|
|
if(printError)
|
2024-05-04 19:14:45 +08:00
|
|
|
fputs("Logo: Querying realpath of the image source failed\n", stderr);
|
2022-06-08 10:59:33 +02:00
|
|
|
return false;
|
2022-04-21 15:50:45 +02:00
|
|
|
}
|
|
|
|
|
ffStrbufRecalculateLength(&requestData.cacheDir);
|
2022-06-22 20:14:10 +02:00
|
|
|
ffStrbufEnsureEndsWithC(&requestData.cacheDir, '/');
|
2023-08-22 15:31:10 +08:00
|
|
|
ffStrbufAppendF(&requestData.cacheDir, "%u*%u/", requestData.logoPixelWidth, requestData.logoPixelHeight);
|
2022-04-21 15:50:45 +02:00
|
|
|
|
2023-08-17 16:00:24 +08:00
|
|
|
if(!instance.config.logo.recache && printCached(&requestData))
|
2022-04-21 15:50:45 +02:00
|
|
|
{
|
|
|
|
|
ffStrbufDestroy(&requestData.cacheDir);
|
2022-06-08 10:59:33 +02:00
|
|
|
return true;
|
2022-04-21 15:50:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FFLogoImageResult result = FF_LOGO_IMAGE_RESULT_INIT_ERROR;
|
2022-04-11 16:19:02 +02:00
|
|
|
|
2022-04-11 22:51:51 +02:00
|
|
|
#ifdef FF_HAVE_IMAGEMAGICK7
|
2023-06-24 10:59:53 +08:00
|
|
|
result = ffLogoPrintImageIM7(&requestData);
|
2022-04-11 16:19:02 +02:00
|
|
|
#endif
|
|
|
|
|
|
2022-04-11 22:51:51 +02:00
|
|
|
#ifdef FF_HAVE_IMAGEMAGICK6
|
2022-04-21 15:50:45 +02:00
|
|
|
if(result == FF_LOGO_IMAGE_RESULT_INIT_ERROR)
|
2023-06-24 10:59:53 +08:00
|
|
|
result = ffLogoPrintImageIM6(&requestData);
|
2022-04-06 14:02:05 +02:00
|
|
|
#endif
|
2022-04-10 15:26:18 +02:00
|
|
|
|
2022-04-21 15:50:45 +02:00
|
|
|
ffStrbufDestroy(&requestData.cacheDir);
|
2022-12-23 12:44:19 +08:00
|
|
|
|
2023-01-28 11:14:16 +01:00
|
|
|
if(result == FF_LOGO_IMAGE_RESULT_SUCCESS)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
if(printError)
|
2022-12-23 12:44:19 +08:00
|
|
|
{
|
2023-01-28 11:14:16 +01:00
|
|
|
if(result == FF_LOGO_IMAGE_RESULT_INIT_ERROR)
|
|
|
|
|
fputs("Logo: Image Magick library not found\n", stderr);
|
|
|
|
|
else
|
2022-12-23 12:44:19 +08:00
|
|
|
fputs("Logo: Failed to load / convert the image source\n", stderr);
|
|
|
|
|
}
|
2023-01-28 11:14:16 +01:00
|
|
|
|
|
|
|
|
return false;
|
2022-04-06 14:54:39 +02:00
|
|
|
}
|
2022-04-22 21:29:14 +02:00
|
|
|
|
2022-12-23 12:44:19 +08:00
|
|
|
#endif //FF_HAVE_IMAGEMAGICK{6, 7}
|
|
|
|
|
|
2023-06-24 10:59:53 +08:00
|
|
|
bool ffLogoPrintImageIfExists(FFLogoType type, bool printError)
|
2022-04-22 21:29:14 +02:00
|
|
|
{
|
2024-05-05 20:01:12 +08:00
|
|
|
if(instance.config.display.pipe)
|
|
|
|
|
{
|
|
|
|
|
if(printError)
|
|
|
|
|
fputs("Logo: Image logo is not supported in pipe mode\n", stderr);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-24 10:59:53 +08:00
|
|
|
if(!ffPathExists(instance.config.logo.source.chars, FF_PATHTYPE_FILE))
|
2022-12-23 12:44:19 +08:00
|
|
|
{
|
2023-01-28 11:14:16 +01:00
|
|
|
if(printError)
|
2023-06-24 10:59:53 +08:00
|
|
|
fprintf(stderr, "Logo: Image source \"%s\" does not exist\n", instance.config.logo.source.chars);
|
2022-12-23 12:44:19 +08:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-03 01:08:14 +08:00
|
|
|
const char* term = getenv("TERM");
|
2024-05-04 19:43:41 +08:00
|
|
|
if((term && ffStrEquals(term, "screen")) || getenv("ZELLIJ"))
|
2024-05-03 01:08:14 +08:00
|
|
|
{
|
|
|
|
|
if(printError)
|
|
|
|
|
fputs("Logo: Image logo is not supported in terminal multiplexers\n", stderr);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-22 21:37:16 +08:00
|
|
|
if(type == FF_LOGO_TYPE_IMAGE_ITERM)
|
2024-05-03 07:56:43 +08:00
|
|
|
return printImageIterm(printError);
|
2022-12-23 12:44:19 +08:00
|
|
|
|
2023-07-18 21:09:37 +08:00
|
|
|
if(type == FF_LOGO_TYPE_IMAGE_KITTY_DIRECT)
|
2024-05-03 07:56:43 +08:00
|
|
|
return printImageKittyDirect(printError);
|
2022-12-23 12:44:19 +08:00
|
|
|
|
2023-01-28 11:14:16 +01:00
|
|
|
#if !defined(FF_HAVE_CHAFA)
|
2022-12-23 12:44:19 +08:00
|
|
|
if(type == FF_LOGO_TYPE_IMAGE_CHAFA)
|
|
|
|
|
{
|
2023-01-28 11:14:16 +01:00
|
|
|
if(printError)
|
|
|
|
|
fputs("Logo: Chafa support is not compiled in\n", stderr);
|
2022-12-23 12:44:19 +08:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2023-01-28 11:14:16 +01:00
|
|
|
#if !defined(FF_HAVE_IMAGEMAGICK7) && !defined(FF_HAVE_IMAGEMAGICK6)
|
|
|
|
|
if(printError)
|
|
|
|
|
fputs("Logo: Image Magick support is not compiled in\n", stderr);
|
2022-12-23 12:44:19 +08:00
|
|
|
return false;
|
2023-01-28 11:14:16 +01:00
|
|
|
#else
|
2023-06-24 10:59:53 +08:00
|
|
|
return printImageIfExistsSlowPath(type, printError);
|
2022-12-23 12:44:19 +08:00
|
|
|
#endif
|
2022-04-22 21:29:14 +02:00
|
|
|
}
|