|
1 | 1 | #include "image.h"
|
2 | 2 | #include "common/io/io.h"
|
3 | 3 | #include "common/printing.h"
|
| 4 | +#include "common/processing.h" |
4 | 5 | #include "util/stringUtils.h"
|
5 | 6 | #include "util/base64.h"
|
6 | 7 | #include "detection/terminalsize/terminalsize.h"
|
@@ -138,6 +139,126 @@ static bool printImageIterm(bool printError)
|
138 | 139 | return true;
|
139 | 140 | }
|
140 | 141 |
|
| 142 | +static bool printImageKittyIcat(bool printError) |
| 143 | +{ |
| 144 | + const FFOptionsLogo* options = &instance.config.logo; |
| 145 | + |
| 146 | + if (!ffPathExists(options->source.chars, FF_PATHTYPE_FILE)) |
| 147 | + { |
| 148 | + if (printError) |
| 149 | + fputs("Logo (kitty-icat): Failed to load image file\n", stderr); |
| 150 | + return false; |
| 151 | + } |
| 152 | + |
| 153 | + fflush(stdout); |
| 154 | + |
| 155 | + FF_STRBUF_AUTO_DESTROY buf = ffStrbufCreate(); |
| 156 | + |
| 157 | + if (options->position == FF_LOGO_POSITION_LEFT) |
| 158 | + { |
| 159 | + ffStrbufAppendF(&buf, "\e[2J\e[3J\e[%u;%uH", |
| 160 | + (unsigned) options->paddingTop + 1, |
| 161 | + (unsigned) options->paddingLeft + 1 |
| 162 | + ); |
| 163 | + } |
| 164 | + else if (options->position == FF_LOGO_POSITION_TOP) |
| 165 | + { |
| 166 | + if (!options->width) |
| 167 | + { |
| 168 | + ffStrbufAppendNC(&buf, options->paddingTop, '\n'); |
| 169 | + ffStrbufAppendNC(&buf, options->paddingLeft, ' '); |
| 170 | + } |
| 171 | + else |
| 172 | + { |
| 173 | + if (printError) |
| 174 | + fputs("Logo (kitty-icat): position top is not supported when logo width is set\n", stderr); |
| 175 | + return false; |
| 176 | + } |
| 177 | + } |
| 178 | + else if (options->position == FF_LOGO_POSITION_RIGHT) |
| 179 | + { |
| 180 | + if (printError) |
| 181 | + fputs("Logo (kitty-icat): position right is not supported\n", stderr); |
| 182 | + return false; |
| 183 | + } |
| 184 | + |
| 185 | + uint32_t prevLength = buf.length; |
| 186 | + |
| 187 | + const char* error = NULL; |
| 188 | + |
| 189 | + if (options->width) |
| 190 | + { |
| 191 | + char place[64]; |
| 192 | + snprintf(place, |
| 193 | + ARRAY_SIZE(place), |
| 194 | + "--place=%ux9999@%ux%u", |
| 195 | + options->width, |
| 196 | + options->paddingLeft + 1, |
| 197 | + options->paddingTop + 1); |
| 198 | + |
| 199 | + error = ffProcessAppendStdOut(&buf, (char* []) { |
| 200 | + "kitten", |
| 201 | + "icat", |
| 202 | + "-n", |
| 203 | + "--align=left", |
| 204 | + place, |
| 205 | + "--scale-up", |
| 206 | + options->source.chars, |
| 207 | + NULL, |
| 208 | + }); |
| 209 | + } |
| 210 | + else |
| 211 | + { |
| 212 | + error = ffProcessAppendStdOut(&buf, (char* []) { |
| 213 | + "kitten", |
| 214 | + "icat", |
| 215 | + "-n", |
| 216 | + "--align=left", |
| 217 | + options->source.chars, |
| 218 | + NULL, |
| 219 | + }); |
| 220 | + } |
| 221 | + if (error) |
| 222 | + { |
| 223 | + if (printError) |
| 224 | + fprintf(stderr, "Logo (kitty-icat): running `kitten icat` failed %s\n", error); |
| 225 | + return false; |
| 226 | + } |
| 227 | + |
| 228 | + if (buf.length == prevLength) |
| 229 | + { |
| 230 | + if (printError) |
| 231 | + fputs("Logo (kitty-icat): `kitten icat` returned empty output\n", stderr); |
| 232 | + return false; |
| 233 | + } |
| 234 | + |
| 235 | + ffWriteFDBuffer(FFUnixFD2NativeFD(STDOUT_FILENO), &buf); |
| 236 | + |
| 237 | + if (options->position == FF_LOGO_POSITION_LEFT || options->position == FF_LOGO_POSITION_RIGHT) |
| 238 | + { |
| 239 | + uint16_t X = 0, Y = 0; |
| 240 | + const char* error = ffGetTerminalResponse("\e[6n", 2, "%*[^0-9]%hu;%huR", &Y, &X); |
| 241 | + if (error) |
| 242 | + { |
| 243 | + fprintf(stderr, "\nLogo (kitty-icat): fail to query cursor position: %s\n", error); |
| 244 | + return true; // We already printed image logo, don't print ascii logo then |
| 245 | + } |
| 246 | + if (X < options->paddingLeft + options->width) |
| 247 | + X = (uint16_t) (options->paddingLeft + options->width); |
| 248 | + if (options->position == FF_LOGO_POSITION_LEFT) |
| 249 | + instance.state.logoWidth = X + options->paddingRight - 1; |
| 250 | + instance.state.logoHeight = Y; |
| 251 | + fputs("\e[H", stdout); |
| 252 | + } |
| 253 | + else if (options->position == FF_LOGO_POSITION_TOP) |
| 254 | + { |
| 255 | + instance.state.logoWidth = instance.state.logoHeight = 0; |
| 256 | + ffPrintCharTimes('\n', options->paddingRight); |
| 257 | + } |
| 258 | + |
| 259 | + return true; |
| 260 | +} |
| 261 | + |
141 | 262 | static bool printImageKittyDirect(bool printError)
|
142 | 263 | {
|
143 | 264 | const FFOptionsLogo* options = &instance.config.logo;
|
@@ -957,6 +1078,9 @@ bool ffLogoPrintImageIfExists(FFLogoType type, bool printError)
|
957 | 1078 | if(type == FF_LOGO_TYPE_IMAGE_KITTY_DIRECT)
|
958 | 1079 | return printImageKittyDirect(printError);
|
959 | 1080 |
|
| 1081 | + if(type == FF_LOGO_TYPE_IMAGE_KITTY_ICAT) |
| 1082 | + return printImageKittyIcat(printError); |
| 1083 | + |
960 | 1084 | #if !defined(FF_HAVE_CHAFA)
|
961 | 1085 | if(type == FF_LOGO_TYPE_IMAGE_CHAFA)
|
962 | 1086 | {
|
|
0 commit comments