From 31bdd25a26892bea95bceccfcbf9705fbccfaf5f Mon Sep 17 00:00:00 2001 From: Linus Dierheimer Date: Thu, 14 Apr 2022 11:36:57 +0200 Subject: [PATCH] Kitty graphics protocol support --- src/logo/image/im6.c | 11 +++- src/logo/image/im7.c | 10 +++- src/logo/image/image.c | 122 +++++++++++++++++++++++++++++++---------- src/logo/image/image.h | 3 +- 4 files changed, 113 insertions(+), 33 deletions(-) diff --git a/src/logo/image/im6.c b/src/logo/image/im6.c index c14eba17c..1779909a5 100644 --- a/src/logo/image/im6.c +++ b/src/logo/image/im6.c @@ -4,17 +4,26 @@ #include static FF_LIBRARY_SYMBOL(ResizeImage); +static FF_LIBRARY_SYMBOL(WriteImage); static void* logoResize(const void* image, size_t width, size_t height, void* exceptionInfo) { return ffResizeImage(image, width, height, UndefinedFilter, 1.0, exceptionInfo); } +static bool logoWrite(void* imageInfo, void* image, void* exceptionInfo) +{ + FF_UNUSED(exceptionInfo); + return ffWriteImage(imageInfo, image) == MagickTrue; +} + FFLogoImageResult ffLogoPrintImageIM6(FFinstance* instance, FFLogoType type) { FF_LIBRARY_LOAD(imageMagick, instance->config.libImageMagick, FF_LOGO_IMAGE_RESULT_INIT_ERROR, "libMagickCore-6.Q16HDRI.so", 8, "libMagickCore-6.Q16.so", 8) FF_LIBRARY_LOAD_SYMBOL_ADRESS(imageMagick, ffResizeImage, ResizeImage, FF_LOGO_IMAGE_RESULT_INIT_ERROR); - return ffLogoPrintImageImpl(instance, imageMagick, logoResize, type); + FF_LIBRARY_LOAD_SYMBOL_ADRESS(imageMagick, ffWriteImage, WriteImage, FF_LOGO_IMAGE_RESULT_INIT_ERROR); + + return ffLogoPrintImageImpl(instance, imageMagick, logoResize, logoWrite, type); } #endif diff --git a/src/logo/image/im7.c b/src/logo/image/im7.c index 74f12d9a6..a514b9a5b 100644 --- a/src/logo/image/im7.c +++ b/src/logo/image/im7.c @@ -4,17 +4,25 @@ #include static FF_LIBRARY_SYMBOL(ResizeImage); +static FF_LIBRARY_SYMBOL(WriteImage); static void* logoResize(const void* image, size_t width, size_t height, void* exceptionInfo) { return ffResizeImage(image, width, height, UndefinedFilter, exceptionInfo); } +static bool logoWrite(void* imageInfo, void* image, void* exceptionInfo) +{ + return ffWriteImage(imageInfo, image, exceptionInfo) == MagickTrue; +} + FFLogoImageResult ffLogoPrintImageIM7(FFinstance* instance, FFLogoType type) { FF_LIBRARY_LOAD(imageMagick, instance->config.libImageMagick, FF_LOGO_IMAGE_RESULT_INIT_ERROR, "libMagickCore-7.Q16HDRI.so", 11, "libMagickCore-7.Q16.so", 11) FF_LIBRARY_LOAD_SYMBOL_ADRESS(imageMagick, ffResizeImage, ResizeImage, FF_LOGO_IMAGE_RESULT_INIT_ERROR); - return ffLogoPrintImageImpl(instance, imageMagick, logoResize, type); + FF_LIBRARY_LOAD_SYMBOL_ADRESS(imageMagick, ffWriteImage, WriteImage, FF_LOGO_IMAGE_RESULT_INIT_ERROR); + + return ffLogoPrintImageImpl(instance, imageMagick, logoResize, logoWrite, type); } #endif diff --git a/src/logo/image/image.c b/src/logo/image/image.c index 9a248ed5c..bdc22aa20 100644 --- a/src/logo/image/image.c +++ b/src/logo/image/image.c @@ -2,6 +2,8 @@ #if defined(FF_HAVE_IMAGEMAGICK7) || defined(FF_HAVE_IMAGEMAGICK6) +#define FF_KITTY_MAX_CHUNK_SIZE 4096 + //We use only the defines from here, that are exactly the same in both versions #ifdef FF_HAVE_IMAGEMAGICK7 #include @@ -9,7 +11,81 @@ #include #endif -FFLogoImageResult ffLogoPrintImageImpl(FFinstance* instance, void* imageMagick, FFLogoIMResizeFunc resizeFunc, FFLogoType type) +typedef struct ImageMagickFunctions +{ + FF_LIBRARY_SYMBOL(CopyMagickString) + FF_LIBRARY_SYMBOL(ImageToBlob) + FF_LIBRARY_SYMBOL(Base64Encode) + + FFLogoIMWriteFunc writeFunc; +} ImageMagickFunctions; + +static inline bool checkAllocationResult(void* data, size_t length) +{ + if(data == NULL) + return false; + + if(length == 0) + { + free(data); + return false; + } + + return true; +} + +static void printImageKittyChunc(char** blob, size_t* length, uint32_t chunkSize) +{ + size_t toWrite = chunkSize < *length ? chunkSize : *length; + fputs("\033_Gm=1;", stdout); + fwrite(*blob, sizeof(**blob), toWrite, stdout); + fputs("\033\\", stdout); + *blob = *blob + toWrite; + *length -= toWrite; +} + +static bool printImageKitty(ImageInfo* imageInfo, Image* image, ExceptionInfo* ExceptionInfo, uint32_t paddingLeft, ImageMagickFunctions* functions) +{ + functions->ffCopyMagickString(imageInfo->magick, "RGBA", 5); + + size_t length; + void* blob = functions->ffImageToBlob(imageInfo, image, &length, ExceptionInfo); + if(!checkAllocationResult(blob, length)) + return false; + + void* encoded = functions->ffBase64Encode(blob, length, &length); + free(blob); + if(!checkAllocationResult(encoded, length)) + return false; + + ffPrintCharTimes(' ', paddingLeft); + + char* currentPos = (char*) encoded; + + printf("\033_Ga=T,f=32,s=%u,v=%u,m=1;\033\\", (uint32_t) image->columns, (uint32_t) image->rows); + while (length > 0) + printImageKittyChunc(¤tPos, &length, FF_KITTY_MAX_CHUNK_SIZE); + fputs("\033_Gm=0;\033\\", stdout); + + free(encoded); + return true; +} + +static bool printImageSixel(ImageInfo* imageInfo, Image* image, ExceptionInfo* exceptionInfo, uint32_t paddingLeft, ImageMagickFunctions* functions) +{ + ffPrintCharTimes(' ', paddingLeft); + + functions->ffCopyMagickString(imageInfo->magick, "SIXEL", 6); + imageInfo->file = stdout; + bool writeResult = functions->writeFunc(imageInfo, image, exceptionInfo); + + if(!writeResult) + printf("\033[%uD", paddingLeft); + + return writeResult; +} + +FFLogoImageResult ffLogoPrintImageImpl(FFinstance* instance, void* imageMagick, FFLogoIMResizeFunc resizeFunc, FFLogoIMWriteFunc writeFunc, FFLogoType type) { struct winsize winsize; if(ioctl(STDOUT_FILENO, TIOCGWINSZ, &winsize) != 0) @@ -19,11 +95,15 @@ FFLogoImageResult ffLogoPrintImageImpl(FFinstance* instance, void* imageMagick, FF_LIBRARY_LOAD_SYMBOL(imageMagick, DestroyExceptionInfo, FF_LOGO_IMAGE_RESULT_INIT_ERROR) FF_LIBRARY_LOAD_SYMBOL(imageMagick, AcquireImageInfo, FF_LOGO_IMAGE_RESULT_INIT_ERROR) FF_LIBRARY_LOAD_SYMBOL(imageMagick, DestroyImageInfo, FF_LOGO_IMAGE_RESULT_INIT_ERROR) - FF_LIBRARY_LOAD_SYMBOL(imageMagick, CopyMagickString, FF_LOGO_IMAGE_RESULT_INIT_ERROR) FF_LIBRARY_LOAD_SYMBOL(imageMagick, ReadImage, FF_LOGO_IMAGE_RESULT_INIT_ERROR) FF_LIBRARY_LOAD_SYMBOL(imageMagick, DestroyImage, FF_LOGO_IMAGE_RESULT_INIT_ERROR) - FF_LIBRARY_LOAD_SYMBOL(imageMagick, ImageToBlob, FF_LOGO_IMAGE_RESULT_INIT_ERROR) - FF_LIBRARY_LOAD_SYMBOL(imageMagick, Base64Encode, FF_LOGO_IMAGE_RESULT_INIT_ERROR) + + ImageMagickFunctions functions; + functions.writeFunc = writeFunc; + + FF_LIBRARY_LOAD_SYMBOL_ADRESS(imageMagick, functions.ffCopyMagickString, CopyMagickString, FF_LOGO_IMAGE_RESULT_INIT_ERROR) + FF_LIBRARY_LOAD_SYMBOL_ADRESS(imageMagick, functions.ffImageToBlob, ImageToBlob, FF_LOGO_IMAGE_RESULT_INIT_ERROR) + FF_LIBRARY_LOAD_SYMBOL_ADRESS(imageMagick, functions.ffBase64Encode, Base64Encode, FF_LOGO_IMAGE_RESULT_INIT_ERROR) ExceptionInfo* exceptionInfo = ffAcquireExceptionInfo(); if(exceptionInfo == NULL) @@ -41,7 +121,7 @@ FFLogoImageResult ffLogoPrintImageImpl(FFinstance* instance, void* imageMagick, } //+1, because we need to copy the null byte too - ffCopyMagickString(imageInfoIn->filename, instance->config.logoName.chars, instance->config.logoName.length + 1); + functions.ffCopyMagickString(imageInfoIn->filename, instance->config.logoName.chars, instance->config.logoName.length + 1); Image* originalImage = ffReadImage(imageInfoIn, exceptionInfo); ffDestroyImageInfo(imageInfoIn); @@ -85,37 +165,19 @@ FFLogoImageResult ffLogoPrintImageImpl(FFinstance* instance, void* imageMagick, return FF_LOGO_IMAGE_RESULT_RUN_ERROR; } - if(type == FF_LOGO_TYPE_SIXEL) - ffCopyMagickString(imageInfoOut->magick, "SIXEL", 6); - else //Kitty - ffCopyMagickString(imageInfoOut->magick, "RGBA", 5); - - size_t length; - void* data = ffImageToBlob(imageInfoOut, resizedImage, &length, exceptionInfo); + bool printSuccessful; + if(type == FF_LOGO_TYPE_KITTY) + printSuccessful = printImageKitty(imageInfoOut, resizedImage, exceptionInfo, instance->config.logoPaddingLeft, &functions); + else + printSuccessful = printImageSixel(imageInfoOut, resizedImage, exceptionInfo, instance->config.logoPaddingLeft, &functions); ffDestroyImageInfo(imageInfoOut); ffDestroyImage(resizedImage); ffDestroyExceptionInfo(exceptionInfo); dlclose(imageMagick); - if(data == NULL || length == 0) - return false; - - ffPrintCharTimes(' ', instance->config.logoPaddingLeft); - - if(type == FF_LOGO_TYPE_KITTY) - { - void* encoded = ffBase64Encode(data, length, &length); - free(data); - data = encoded; - printf("\033_Ga=T,f=32,s=%u,v=%u;", (uint32_t) imagePixelWidth, (uint32_t) imagePixelHeight); - } - - fwrite(data, sizeof(char), length, stdout); - free(data); - - if(type == FF_LOGO_TYPE_KITTY) - fputs("\033\\", stdout); + if(!printSuccessful) + return FF_LOGO_IMAGE_RESULT_RUN_ERROR; instance->state.logoHeight = (uint32_t) (imagePixelHeight / characterPixelHeight); instance->state.logoWidth = instance->config.logoWidth + instance->config.logoPaddingLeft + instance->config.logoPaddingRight; diff --git a/src/logo/image/image.h b/src/logo/image/image.h index 2c38e544e..db22b24c0 100644 --- a/src/logo/image/image.h +++ b/src/logo/image/image.h @@ -21,8 +21,9 @@ typedef enum FFLogoImageResult } FFLogoImageResult; typedef void*(*FFLogoIMResizeFunc)(const void* image, size_t width, size_t height, void* exceptionInfo); +typedef bool(*FFLogoIMWriteFunc)(void* imageInfo, void* image, void* exceptionInfo); -FFLogoImageResult ffLogoPrintImageImpl(FFinstance* instance, void* library, FFLogoIMResizeFunc resizeFunc, FFLogoType type); +FFLogoImageResult ffLogoPrintImageImpl(FFinstance* instance, void* library, FFLogoIMResizeFunc resizeFunc, FFLogoIMWriteFunc writeFunc, FFLogoType type); #endif