Files
fastfetch/src/logo/image/image.c
T

573 lines
20 KiB
C
Raw Normal View History

2022-04-13 23:04:42 +02:00
#include "image.h"
2022-04-06 14:02:05 +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-21 15:50:45 +02:00
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
2022-05-23 15:32:10 +02:00
#include <sys/ioctl.h>
2022-04-14 15:11:14 +02:00
#ifdef FF_HAVE_ZLIB
2022-06-18 14:25:31 +02:00
#include <stdlib.h>
#include <dlfcn.h>
2022-04-14 15:11:14 +02:00
#include <zlib.h>
static bool compressBlob(const FFinstance* instance, void** blob, size_t* length)
{
FF_LIBRARY_LOAD(zlib, instance->config.libZ, false, "libz.so", 2)
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)
{
dlclose(zlib);
return false;
}
int compressResult = ffcompress2(compressed, &compressedLength, *blob, *length, Z_BEST_COMPRESSION);
dlclose(zlib);
if(compressResult != Z_OK)
{
free(compressed);
return false;
}
free(*blob);
*length = (size_t) compressedLength;
*blob = compressed;
return true;
}
#endif // FF_HAVE_ZLIB
//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 inline uint32_t simpleCeil(double value)
2022-04-21 15:50:45 +02:00
{
2022-05-23 15:32:10 +02:00
uint32_t result = (uint32_t) value;
return value == (double) result ? result : result + 1;
}
2022-04-30 11:22:51 +02:00
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
2022-05-23 15:32:10 +02:00
static void printImagePixels(FFinstance* instance, FFLogoRequestData* requestData, const FFstrbuf* result, const char* cacheFileName)
{
//Calculate character dimensions
2022-07-10 18:28:17 +02:00
instance->state.logoWidth = requestData->logoCharacterWidth + instance->config.logo.paddingLeft + instance->config.logo.paddingRight;
2022-04-21 15:50:45 +02:00
2022-05-23 15:32:10 +02:00
instance->state.logoHeight = requestData->logoCharacterHeight;
if(requestData->type == FF_LOGO_TYPE_KITTY)
2022-04-28 19:15:46 +02:00
instance->state.logoHeight -= 1;
2022-05-23 15:32:10 +02:00
//Write cache files
writeCacheStrbuf(requestData, result, cacheFileName);
2022-07-10 18:28:17 +02:00
if(instance->config.logo.width == 0)
2022-05-23 15:32:10 +02:00
writeCacheUint32(requestData, instance->state.logoWidth, FF_CACHE_FILE_WIDTH);
2022-07-10 18:28:17 +02:00
if(instance->config.logo.height == 0)
2022-05-23 15:32:10 +02:00
writeCacheUint32(requestData, instance->state.logoHeight, FF_CACHE_FILE_HEIGHT);
2022-04-14 11:36:57 +02:00
2022-04-22 13:20:40 +02:00
//Write result to stdout
2022-07-10 18:28:17 +02:00
ffPrintCharTimes(' ', instance->config.logo.paddingLeft);
2022-04-22 13:20:40 +02:00
fflush(stdout);
2022-06-19 18:22:00 +02:00
ffWriteFDBuffer(STDOUT_FILENO, result);
2022-04-14 11:36:57 +02:00
2022-05-23 15:32:10 +02:00
//Go to upper left corner
fputs("\033[9999999D", stdout);
printf("\033[%uA", instance->state.logoHeight);
2022-04-14 11:36:57 +02:00
}
2022-04-22 13:20:40 +02:00
static bool printImageSixel(FFinstance* instance, 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
2022-05-23 15:32:10 +02:00
printImagePixels(instance, 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
}
2022-04-22 13:20:40 +02:00
static bool printImageKitty(FFinstance* instance, 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
bool isCompressed = compressBlob(instance, &blob, &length);
#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;
2022-04-22 13:20:40 +02:00
FFstrbuf result;
ffStrbufInitA(&result, (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, &currentPos, &remainingLength, false);
2022-04-21 15:50:45 +02:00
while(remainingLength > 0)
2022-04-22 13:20:40 +02:00
appendKittyChunk(&result, &currentPos, &remainingLength, true);
2022-04-14 11:36:57 +02:00
2022-05-23 15:32:10 +02:00
printImagePixels(instance, requestData, &result, isCompressed ? FF_CACHE_FILE_KITTY_COMPRESSED : FF_CACHE_FILE_KITTY_UNCOMPRESSED);
2022-04-21 15:50:45 +02:00
2022-04-22 13:20:40 +02:00
ffStrbufDestroy(&result);
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
#include <chafa/chafa.h>
static bool printImageChafa(FFinstance* instance, FFLogoRequestData* requestData, const ImageData* imageData)
{
FF_LIBRARY_LOAD(chafa, instance->config.libChafa, false, "libchafa.so", 1)
FF_LIBRARY_LOAD_SYMBOL(chafa, chafa_symbol_map_new, false)
FF_LIBRARY_LOAD_SYMBOL(chafa, chafa_symbol_map_add_by_tags, false)
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)
FF_LIBRARY_LOAD_SYMBOL(chafa, g_string_free, false)
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();
ffchafa_symbol_map_add_by_tags(symbolMap, CHAFA_SYMBOL_TAG_ALL);
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);
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-06-08 10:59:33 +02:00
ffLogoPrintChars(instance, 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
ffg_string_free(str, TRUE);
ffchafa_canvas_unref(canvas);
ffchafa_canvas_config_unref(canvasConfig);
ffchafa_symbol_map_unref(symbolMap);
return true;
}
#endif
2022-04-21 15:50:45 +02:00
FFLogoImageResult ffLogoPrintImageImpl(FFinstance* instance, FFLogoRequestData* requestData, const FFIMData* imData)
2022-04-06 14:02:05 +02:00
{
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-04-21 15:50:45 +02:00
FF_LIBRARY_LOAD_SYMBOL_ADRESS(imData->library, imageData.ffCopyMagickString, CopyMagickString, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(imData->library, imageData.ffImageToBlob, ImageToBlob, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(imData->library, imageData.ffBase64Encode, Base64Encode, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
2022-04-06 14:02:05 +02:00
2022-04-21 15:50:45 +02:00
imageData.exceptionInfo = ffAcquireExceptionInfo();
if(imageData.exceptionInfo == NULL)
2022-04-13 23:13:25 +02:00
return FF_LOGO_IMAGE_RESULT_RUN_ERROR;
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-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
2022-07-10 18:28:17 +02: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-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);
requestData->logoCharacterWidth = simpleCeil((double) requestData->logoPixelWidth / requestData->characterPixelWidth);
requestData->logoCharacterHeight = simpleCeil((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);
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);
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-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;
if(requestData->type == FF_LOGO_TYPE_CHAFA)
2022-05-23 15:36:19 +02:00
{
#ifdef FF_HAVE_CHAFA
printSuccessful = printImageChafa(instance, requestData, &imageData);
#endif
}
2022-04-28 19:15:46 +02:00
else if(requestData->type == FF_LOGO_TYPE_KITTY)
printSuccessful = printImageKitty(instance, requestData, &imageData);
2022-05-23 15:32:10 +02:00
else if(requestData->type == FF_LOGO_TYPE_SIXEL)
printSuccessful = printImageSixel(instance, 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-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);
2022-04-21 15:50:45 +02:00
int fd = open(requestData->cacheDir.chars, O_RDONLY);
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)
{
FFstrbuf content;
ffStrbufInit(&content);
readCachedStrbuf(requestData, &content, cacheFileName);
uint32_t result = 0;
if(content.length != sizeof(result))
2022-04-30 11:22:51 +02:00
{
2022-05-23 15:32:10 +02:00
ffStrbufDestroy(&content);
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
ffStrbufDestroy(&content);
return result;
}
2022-04-21 15:50:45 +02:00
2022-05-23 15:32:10 +02:00
static bool printCachedChars(FFinstance* instance, FFLogoRequestData* requestData)
{
FFstrbuf content;
ffStrbufInitA(&content, 32768);
if(requestData->type == FF_LOGO_TYPE_CHAFA)
readCachedStrbuf(requestData, &content, FF_CACHE_FILE_CHAFA);
if(content.length == 0)
{
2022-04-30 11:22:51 +02:00
ffStrbufDestroy(&content);
2022-05-23 15:32:10 +02:00
return false;
}
2022-06-08 10:59:33 +02:00
ffLogoPrintChars(instance, content.chars, false);
2022-05-23 15:32:10 +02:00
ffStrbufDestroy(&content);
return true;
}
static bool printCachedPixel(FFinstance* instance, FFLogoRequestData* requestData)
{
2022-07-10 18:28:17 +02: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
2022-07-10 18:28:17 +02: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-04-22 13:20:40 +02:00
if(requestData->type == FF_LOGO_TYPE_KITTY)
{
fd = getCacheFD(requestData, FF_CACHE_FILE_KITTY_COMPRESSED);
if(fd == -1)
fd = getCacheFD(requestData, FF_CACHE_FILE_KITTY_UNCOMPRESSED);
}
2022-04-28 19:15:46 +02:00
else if(requestData->type == FF_LOGO_TYPE_SIXEL)
2022-04-22 13:20:40 +02:00
fd = getCacheFD(requestData, FF_CACHE_FILE_SIXEL);
if(fd == -1)
return false;
2022-07-10 18:28:17 +02:00
ffPrintCharTimes(' ', instance->config.logo.paddingLeft);
2022-04-22 13:20:40 +02:00
fflush(stdout);
char buffer[32768];
ssize_t readBytes;
while((readBytes = read(fd, buffer, sizeof(buffer))) > 0)
2022-05-23 15:32:10 +02:00
FF_UNUSED(write(STDOUT_FILENO, buffer, (size_t) readBytes));
2022-04-22 13:20:40 +02:00
close(fd);
2022-07-10 18:28:17 +02:00
instance->state.logoWidth = requestData->logoCharacterWidth + instance->config.logo.paddingLeft + instance->config.logo.paddingRight;
2022-05-23 15:32:10 +02:00
instance->state.logoHeight = requestData->logoCharacterHeight;
//Go to upper left corner
fputs("\033[9999999D", stdout);
printf("\033[%uA", instance->state.logoHeight);
2022-04-22 13:20:40 +02:00
return true;
2022-04-21 15:50:45 +02:00
}
2022-05-23 15:32:10 +02:00
static bool printCached(FFinstance* instance, FFLogoRequestData* requestData)
2022-04-21 15:50:45 +02:00
{
2022-05-23 15:32:10 +02:00
if(requestData->type == FF_LOGO_TYPE_CHAFA)
return printCachedChars(instance, requestData);
else
return printCachedPixel(instance, requestData);
}
static bool getCharacterPixelDimensions(FFLogoRequestData* requestData)
{
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-05-23 15:32:10 +02:00
return requestData->characterPixelWidth > 1.0 && requestData->characterPixelHeight > 1.0;
2022-04-21 15:50:45 +02:00
}
2022-06-08 10:59:33 +02:00
bool ffLogoPrintImageIfExists(FFinstance* instance, FFLogoType type)
2022-04-06 14:02:05 +02:00
{
2022-05-23 15:32:10 +02:00
//Performance optimisation
2022-04-28 19:15:46 +02:00
#ifndef FF_HAVE_CHAFA
if(type == FF_LOGO_TYPE_CHAFA)
2022-06-08 10:59:33 +02:00
return false;
2022-04-28 19:15:46 +02:00
#endif
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;
if(
2022-07-10 18:28:17 +02:00
(type != FF_LOGO_TYPE_CHAFA || instance->config.logo.width == 0 || instance->config.logo.height == 0) &&
2022-05-23 15:32:10 +02:00
!getCharacterPixelDimensions(&requestData)
)
2022-06-08 10:59:33 +02:00
return false;
2022-04-21 15:50:45 +02:00
2022-07-10 18:28:17 +02:00
requestData.logoPixelWidth = simpleCeil((double) instance->config.logo.width * requestData.characterPixelWidth);
requestData.logoPixelHeight = simpleCeil((double) instance->config.logo.height * requestData.characterPixelHeight);
2022-04-30 11:22:51 +02:00
2022-04-21 15:50:45 +02:00
ffStrbufInitA(&requestData.cacheDir, PATH_MAX * 2);
ffStrbufAppend(&requestData.cacheDir, &instance->state.cacheDir);
ffStrbufAppendS(&requestData.cacheDir, "images");
ffStrbufEnsureFree(&requestData.cacheDir, PATH_MAX);
2022-07-10 18:28:17 +02: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);
2022-06-08 10:59:33 +02:00
return false;
2022-04-21 15:50:45 +02:00
}
ffStrbufRecalculateLength(&requestData.cacheDir);
ffStrbufEnsureEndsWithC(&requestData.cacheDir, '/');
2022-04-21 15:50:45 +02:00
2022-05-23 15:32:10 +02:00
ffStrbufAppendF(&requestData.cacheDir, "%u", requestData.logoPixelWidth);
ffStrbufAppendC(&requestData.cacheDir, '*');
ffStrbufAppendF(&requestData.cacheDir, "%u", requestData.logoPixelHeight);
2022-04-21 15:50:45 +02:00
ffStrbufAppendC(&requestData.cacheDir, '/');
if(!instance->config.recache && printCached(instance, &requestData))
{
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 22:51:51 +02:00
#ifdef FF_HAVE_IMAGEMAGICK7
2022-04-21 15:50:45 +02:00
result = ffLogoPrintImageIM7(instance, &requestData);
#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)
result = ffLogoPrintImageIM6(instance, &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-06-08 10:59:33 +02:00
return result == FF_LOGO_IMAGE_RESULT_SUCCESS;
2022-04-06 14:54:39 +02:00
}
2022-04-22 21:29:14 +02:00
#else //FF_HAVE_IMAGEMAGICK{6, 7}
2022-06-08 15:22:34 +05:30
bool ffLogoPrintImageIfExists(FFinstance* instance, FFLogoType type)
2022-04-22 21:29:14 +02:00
{
2022-04-23 11:24:24 +02:00
FF_UNUSED(instance, type);
2022-06-08 10:59:33 +02:00
return false;
2022-04-22 21:29:14 +02:00
}
#endif //FF_HAVE_IMAGEMAGICK{6, 7}