mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-11-04 12:14:19 +01:00
163 lines
5.8 KiB
C
163 lines
5.8 KiB
C
#ifdef FF_HAVE_IMAGEMAGICK6
|
|
|
|
#include "image.h"
|
|
#include "common/library.h"
|
|
#include "common/mallocHelper.h"
|
|
|
|
#include <magick/MagickCore.h>
|
|
#include <stdlib.h>
|
|
|
|
static FF_LIBRARY_SYMBOL(ResizeImage)
|
|
|
|
static void* logoResize(const void* image, size_t width, size_t height, void* exceptionInfo) {
|
|
return ffResizeImage(image, width, height, UndefinedFilter, 1.0, exceptionInfo);
|
|
}
|
|
|
|
// Decode the image source, resize it to the requested pixel size and export it as a blob
|
|
// in the given ImageMagick format ("RGBA" for kitty / chafa, "SIXEL" for sixel output).
|
|
// On success requestData->logoPixelWidth / logoPixelHeight hold the real image dimensions.
|
|
static FFLogoImageResult im6EncodeImage(FFLogoRequestData* requestData, const char* magick, uint32_t magickLength, void** outBlob, size_t* outLength) {
|
|
// clang-format off
|
|
FF_LIBRARY_LOAD(imageMagick, FF_LOGO_IMAGE_RESULT_INIT_ERROR,
|
|
"libMagickCore-6.Q16HDRI" FF_LIBRARY_EXTENSION, 8,
|
|
"libMagickCore-6.Q16" FF_LIBRARY_EXTENSION, 8,
|
|
"libMagickCore-6" FF_LIBRARY_EXTENSION, 8
|
|
)
|
|
// clang-format on
|
|
FF_LIBRARY_LOAD_SYMBOL_ADDRESS(imageMagick, ffResizeImage, ResizeImage, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
|
|
|
|
FF_LIBRARY_LOAD_SYMBOL(imageMagick, MagickCoreGenesis, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
|
|
FF_LIBRARY_LOAD_SYMBOL(imageMagick, MagickCoreTerminus, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
|
|
FF_LIBRARY_LOAD_SYMBOL(imageMagick, AcquireExceptionInfo, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
|
|
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, ReadImage, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
|
|
FF_LIBRARY_LOAD_SYMBOL(imageMagick, DestroyImage, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
|
|
FF_LIBRARY_LOAD_SYMBOL(imageMagick, CopyMagickString, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
|
|
FF_LIBRARY_LOAD_SYMBOL(imageMagick, ImageToBlob, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
|
|
|
|
FFLogoImageResult result = FF_LOGO_IMAGE_RESULT_RUN_ERROR;
|
|
ExceptionInfo* exceptionInfo = nullptr;
|
|
Image* image = nullptr;
|
|
ImageInfo* imageInfoOut = nullptr;
|
|
FF_AUTO_FREE void* blob = nullptr;
|
|
size_t length = 0;
|
|
|
|
ffMagickCoreGenesis(nullptr, MagickFalse);
|
|
|
|
exceptionInfo = ffAcquireExceptionInfo();
|
|
if (exceptionInfo == nullptr) {
|
|
goto cleanup;
|
|
}
|
|
|
|
{
|
|
ImageInfo* imageInfoIn = ffAcquireImageInfo();
|
|
if (imageInfoIn == nullptr) {
|
|
goto cleanup;
|
|
}
|
|
|
|
//+1, because we need to copy the null byte too
|
|
ffCopyMagickString(imageInfoIn->filename, instance.config.logo.source.chars, instance.config.logo.source.length + 1);
|
|
|
|
image = ffReadImage(imageInfoIn, exceptionInfo);
|
|
ffDestroyImageInfo(imageInfoIn);
|
|
if (image == nullptr) {
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
if (requestData->logoPixelWidth == 0 && requestData->logoPixelHeight == 0) {
|
|
requestData->logoPixelWidth = (uint32_t) image->columns;
|
|
requestData->logoPixelHeight = (uint32_t) image->rows;
|
|
} else if (requestData->logoPixelWidth == 0) {
|
|
requestData->logoPixelWidth = (uint32_t) ((double) image->columns / (double) image->rows * requestData->logoPixelHeight);
|
|
} else if (requestData->logoPixelHeight == 0) {
|
|
requestData->logoPixelHeight = (uint32_t) ((double) image->rows / (double) image->columns * requestData->logoPixelWidth);
|
|
}
|
|
|
|
if (requestData->logoPixelWidth == 0 || requestData->logoPixelHeight == 0) {
|
|
goto cleanup;
|
|
}
|
|
|
|
{
|
|
Image* resized = logoResize(image, requestData->logoPixelWidth, requestData->logoPixelHeight, exceptionInfo);
|
|
ffDestroyImage(image);
|
|
image = resized;
|
|
if (image == nullptr) {
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
imageInfoOut = ffAcquireImageInfo();
|
|
if (imageInfoOut == nullptr) {
|
|
goto cleanup;
|
|
}
|
|
|
|
ffCopyMagickString(imageInfoOut->magick, magick, magickLength);
|
|
|
|
blob = ffImageToBlob(imageInfoOut, image, &length, exceptionInfo);
|
|
if (blob == nullptr || length == 0) {
|
|
goto cleanup;
|
|
}
|
|
|
|
*outBlob = blob;
|
|
*outLength = length;
|
|
blob = nullptr; // Ownership is transferred to the caller
|
|
result = FF_LOGO_IMAGE_RESULT_SUCCESS;
|
|
|
|
cleanup:
|
|
if (imageInfoOut) {
|
|
ffDestroyImageInfo(imageInfoOut);
|
|
}
|
|
if (image) {
|
|
ffDestroyImage(image);
|
|
}
|
|
if (exceptionInfo) {
|
|
ffDestroyExceptionInfo(exceptionInfo);
|
|
}
|
|
ffMagickCoreTerminus();
|
|
|
|
// leak imageMagick to prevent fastfetch from crashing #552
|
|
imageMagick = nullptr;
|
|
return result;
|
|
}
|
|
|
|
static void setError(FFLogoImageResult result, const char** error) {
|
|
if (error) {
|
|
*error = result == FF_LOGO_IMAGE_RESULT_INIT_ERROR
|
|
? "Image Magick library not found"
|
|
: "Failed to load / convert the image source";
|
|
}
|
|
}
|
|
|
|
bool ffImageCreateIM6(FFLogoRequestData* requestData, FFImageBuffer* out, const char** error) {
|
|
void* blob = nullptr;
|
|
size_t length = 0;
|
|
FFLogoImageResult result = im6EncodeImage(requestData, "RGBA", 5, &blob, &length);
|
|
if (result != FF_LOGO_IMAGE_RESULT_SUCCESS) {
|
|
setError(result, error);
|
|
return false;
|
|
}
|
|
|
|
out->data = blob;
|
|
out->width = requestData->logoPixelWidth;
|
|
out->height = requestData->logoPixelHeight;
|
|
return true;
|
|
}
|
|
|
|
bool ffImageSixelEncodeIM6(FFLogoRequestData* requestData, FFstrbuf* out, const char** error) {
|
|
FF_AUTO_FREE void* blob = nullptr;
|
|
size_t length = 0;
|
|
FFLogoImageResult result = im6EncodeImage(requestData, "SIXEL", 6, &blob, &length);
|
|
if (result != FF_LOGO_IMAGE_RESULT_SUCCESS) {
|
|
setError(result, error);
|
|
return false;
|
|
}
|
|
|
|
ffStrbufSetNS(out, (uint32_t) length, (const char*) blob);
|
|
return true;
|
|
}
|
|
|
|
#endif
|