Skip to content

Commit 80f7a98

Browse files
Even faster image caching
1 parent cff3aed commit 80f7a98

File tree

1 file changed

+101
-141
lines changed

1 file changed

+101
-141
lines changed

src/logo/image/image.c

Lines changed: 101 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,20 @@ typedef struct ImageData
6565
ExceptionInfo* exceptionInfo;
6666
} ImageData;
6767

68+
static inline bool checkAllocationResult(void* data, size_t length)
69+
{
70+
if(data == NULL)
71+
return false;
72+
73+
if(length == 0)
74+
{
75+
free(data);
76+
return false;
77+
}
78+
79+
return true;
80+
}
81+
6882
static void finishPrinting(FFinstance* instance, const FFLogoRequestData* requestData)
6983
{
7084
instance->state.logoWidth = (uint32_t) (requestData->imagePixelWidth / requestData->characterPixelWidth) + instance->config.logoPaddingLeft + instance->config.logoPaddingRight;
@@ -78,45 +92,68 @@ static void finishPrinting(FFinstance* instance, const FFLogoRequestData* reques
7892
printf("\033[%uA", instance->state.logoHeight);
7993
}
8094

81-
static inline bool checkAllocationResult(void* data, size_t length)
95+
static void writeResult(FFinstance* instance, FFLogoRequestData* requestData, const FFstrbuf* result, const char* cacheFileName)
8296
{
83-
if(data == NULL)
84-
return false;
97+
//Write result to stdout
98+
ffPrintCharTimes(' ', instance->config.logoPaddingLeft);
99+
fflush(stdout);
100+
ffWriteFDContent(STDOUT_FILENO, result);
85101

86-
if(length == 0)
87-
{
88-
free(data);
89-
return false;
90-
}
102+
//Write result to cache file
103+
uint32_t cacheDirLength = requestData->cacheDir.length;
104+
ffStrbufAppendS(&requestData->cacheDir, cacheFileName);
105+
ffWriteFileContent(requestData->cacheDir.chars, result);
106+
ffStrbufSubstrBefore(&requestData->cacheDir, cacheDirLength);
91107

92-
return true;
108+
//Write height cache file
109+
ffStrbufAppendS(&requestData->cacheDir, FF_CACHE_FILE_HEIGHT);
110+
FFstrbuf content;
111+
content.chars = (char*) &requestData->imagePixelHeight;
112+
content.length = sizeof(requestData->imagePixelHeight);
113+
ffWriteFileContent(requestData->cacheDir.chars, &content);
114+
ffStrbufSubstrBefore(&requestData->cacheDir, cacheDirLength);
115+
116+
//Write escape codes to stdout
117+
finishPrinting(instance, requestData);
93118
}
94119

95-
static void writeCacheFile(FFLogoRequestData* requestData, const char* filename, char* blob, size_t length)
120+
static bool printImageSixel(FFinstance* instance, FFLogoRequestData* requestData, const ImageData* imageData)
96121
{
97-
uint32_t cacheDirLength = requestData->cacheDir.length;
98-
ffStrbufAppendS(&requestData->cacheDir, filename);
122+
imageData->ffCopyMagickString(imageData->imageInfo->magick, "SIXEL", 6);
99123

100-
FFstrbuf cachedContent;
101-
cachedContent.chars = blob;
102-
cachedContent.length = (uint32_t) length;
103-
ffWriteFileContent(requestData->cacheDir.chars, &cachedContent);
124+
size_t length;
125+
void* blob = imageData->ffImageToBlob(imageData->imageInfo, imageData->image, &length, imageData->exceptionInfo);
126+
if(!checkAllocationResult(blob, length))
127+
return false;
104128

105-
ffStrbufSubstrBefore(&requestData->cacheDir, cacheDirLength);
106-
}
129+
FFstrbuf result;
130+
result.chars = (char*) blob;
131+
result.length = (uint32_t) length;
107132

133+
writeResult(instance, requestData, &result, FF_CACHE_FILE_SIXEL);
134+
135+
free(blob);
136+
return true;
137+
}
108138

109-
static void printImageKittyBlobChunk(const char** blob, size_t* length)
139+
static void appendKittyChunk(FFstrbuf* result, const char** blob, size_t* length, bool printEscapeCode)
110140
{
111-
size_t toWrite = FF_KITTY_MAX_CHUNK_SIZE < *length ? FF_KITTY_MAX_CHUNK_SIZE : *length;
112-
fputs("\033_Gm=1;", stdout);
113-
fwrite(*blob, sizeof(**blob), toWrite, stdout);
114-
fputs("\033\\", stdout);
115-
*blob += toWrite;
116-
*length -= toWrite;
141+
uint32_t chunkSize = *length > FF_KITTY_MAX_CHUNK_SIZE ? FF_KITTY_MAX_CHUNK_SIZE : (uint32_t) *length;
142+
143+
if(printEscapeCode)
144+
ffStrbufAppendS(result, "\033_G");
145+
else
146+
ffStrbufAppendC(result, ',');
147+
148+
ffStrbufAppendS(result, chunkSize != *length ? "m=1" : "m=0");
149+
ffStrbufAppendC(result, ';');
150+
ffStrbufAppendNS(result, chunkSize, *blob);
151+
ffStrbufAppendS(result, "\033\\");
152+
*length -= chunkSize;
153+
*blob += chunkSize;
117154
}
118155

119-
static bool printImageKitty(const FFinstance* instance, FFLogoRequestData* requestData, const ImageData* imageData)
156+
static bool printImageKitty(FFinstance* instance, FFLogoRequestData* requestData, const ImageData* imageData)
120157
{
121158
imageData->ffCopyMagickString(imageData->imageInfo->magick, "RGBA", 5);
122159

@@ -136,43 +173,26 @@ static bool printImageKitty(const FFinstance* instance, FFLogoRequestData* reque
136173
if(!checkAllocationResult(chars, length))
137174
return false;
138175

139-
ffPrintCharTimes(' ', instance->config.logoPaddingLeft);
176+
FFstrbuf result;
177+
ffStrbufInitA(&result, (uint32_t) (length + 1024));
140178

141179
const char* currentPos = chars;
142180
size_t remainingLength = length;
143181

144-
printf("\033_Ga=T,f=32,s=%u,v=%u%s,m=1;\033\\", requestData->imagePixelWidth, requestData->imagePixelHeight, isCompressed ? ",o=z" : "");
182+
ffStrbufAppendF(&result, "\033_Ga=T,f=32,s=%u,v=%u", requestData->imagePixelWidth, requestData->imagePixelHeight);
183+
if(isCompressed)
184+
ffStrbufAppendS(&result, ",o=z");
185+
appendKittyChunk(&result, &currentPos, &remainingLength, false);
145186
while(remainingLength > 0)
146-
printImageKittyBlobChunk(&currentPos, &remainingLength);
147-
fputs("\033_Gm=0;\033\\", stdout);
187+
appendKittyChunk(&result, &currentPos, &remainingLength, true);
148188

149-
if(isCompressed)
150-
writeCacheFile(requestData, FF_CACHE_FILE_KITTY_COMPRESSED, chars, length);
151-
else
152-
writeCacheFile(requestData, FF_CACHE_FILE_KITTY_UNCOMPRESSED, chars, length);
189+
writeResult(instance, requestData, &result, isCompressed ? FF_CACHE_FILE_KITTY_COMPRESSED : FF_CACHE_FILE_KITTY_UNCOMPRESSED);
153190

191+
ffStrbufDestroy(&result);
154192
free(chars);
155193
return true;
156194
}
157195

158-
static bool printImageSixel(const FFinstance* instance, FFLogoRequestData* requestData, const ImageData* imageData)
159-
{
160-
imageData->ffCopyMagickString(imageData->imageInfo->magick, "SIXEL", 6);
161-
162-
size_t length;
163-
void* blob = imageData->ffImageToBlob(imageData->imageInfo, imageData->image, &length, imageData->exceptionInfo);
164-
if(!checkAllocationResult(blob, length))
165-
return false;
166-
167-
ffPrintCharTimes(' ', instance->config.logoPaddingLeft);
168-
fwrite(blob, sizeof(*blob), length, stdout);
169-
170-
writeCacheFile(requestData, FF_CACHE_FILE_SIXEL, blob, length);
171-
172-
free(blob);
173-
return true;
174-
}
175-
176196
FFLogoImageResult ffLogoPrintImageImpl(FFinstance* instance, FFLogoRequestData* requestData, const FFIMData* imData)
177197
{
178198
FF_LIBRARY_LOAD_SYMBOL(imData->library, AcquireExceptionInfo, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
@@ -245,101 +265,21 @@ FFLogoImageResult ffLogoPrintImageImpl(FFinstance* instance, FFLogoRequestData*
245265
ffDestroyImage(imageData.image);
246266
ffDestroyExceptionInfo(imageData.exceptionInfo);
247267

248-
if(!printSuccessful)
249-
return FF_LOGO_IMAGE_RESULT_RUN_ERROR;
250-
251-
//Write height file
252-
uint32_t folderPathLength = requestData->cacheDir.length;
253-
ffStrbufAppendS(&requestData->cacheDir, FF_CACHE_FILE_HEIGHT);
254-
255-
FFstrbuf content;
256-
content.chars = (char*) &requestData->imagePixelHeight;
257-
content.length = sizeof(requestData->imagePixelHeight);
258-
ffWriteFileContent(requestData->cacheDir.chars, &content);
259-
260-
ffStrbufSubstrBefore(&requestData->cacheDir, folderPathLength);
261-
262-
finishPrinting(instance, requestData);
263-
return FF_LOGO_IMAGE_RESULT_SUCCESS;
268+
return printSuccessful ? FF_LOGO_IMAGE_RESULT_SUCCESS : FF_LOGO_IMAGE_RESULT_RUN_ERROR;
264269
}
265270

266271
#endif //FF_HAVE_IMAGEMAGICK{6, 7}
267272

268-
static bool printCachedSixelFile(const FFinstance* instance, const FFLogoRequestData* requestData)
269-
{
270-
int fd = open(requestData->cacheDir.chars, O_RDONLY);
271-
if(fd == -1)
272-
return false;
273-
274-
ffPrintCharTimes(' ', instance->config.logoPaddingLeft);
275-
fflush(stdout);
276-
277-
char buffer[4096];
278-
ssize_t readBytes;
279-
280-
while((readBytes = read(fd, buffer, sizeof(buffer))) > 0)
281-
write(STDOUT_FILENO, buffer, (size_t) readBytes);
282-
283-
close(fd);
284-
return true;
285-
}
286-
287-
static bool printCachedSixel(const FFinstance* instance, FFLogoRequestData* requestData)
273+
static int getCacheFD(FFLogoRequestData* requestData, const char* fileName)
288274
{
289275
uint32_t cacheDirLength = requestData->cacheDir.length;
290-
bool result;
291-
292-
ffStrbufAppendS(&requestData->cacheDir, FF_CACHE_FILE_SIXEL);
293-
result = printCachedSixelFile(instance, requestData);
294-
ffStrbufSubstrBefore(&requestData->cacheDir, cacheDirLength);
295-
296-
return result;
297-
}
298-
299-
static bool printCachedKittyFile(const FFinstance* instance, const FFLogoRequestData* requestData, bool isCompressed)
300-
{
276+
ffStrbufAppendS(&requestData->cacheDir, fileName);
301277
int fd = open(requestData->cacheDir.chars, O_RDONLY);
302-
if(fd == -1)
303-
return false;
304-
305-
char buffer[FF_KITTY_MAX_CHUNK_SIZE];
306-
307-
ffPrintCharTimes(' ', instance->config.logoPaddingLeft);
308-
printf("\033_Ga=T,f=32,s=%u,v=%u%s,m=1;\033\\", requestData->imagePixelWidth, requestData->imagePixelHeight, isCompressed ? ",o=z" : "");
309-
310-
ssize_t readBytes;
311-
while((readBytes = read(fd, buffer, sizeof(buffer))) > 0)
312-
{
313-
fputs("\033_Gm=1;",stdout);
314-
fwrite(buffer, 1, (size_t) readBytes, stdout);
315-
fputs("\033\\", stdout);
316-
}
317-
318-
fputs("\033_Gm=0;\033\\", stdout);
319-
320-
close(fd);
321-
return true;
322-
}
323-
324-
static bool printCachedKitty(const FFinstance* instance, FFLogoRequestData* requestData)
325-
{
326-
uint32_t cacheDirLength = requestData->cacheDir.length;
327-
bool result;
328-
329-
ffStrbufAppendS(&requestData->cacheDir, FF_CACHE_FILE_KITTY_COMPRESSED);
330-
result = printCachedKittyFile(instance, requestData, true);
331278
ffStrbufSubstrBefore(&requestData->cacheDir, cacheDirLength);
332-
if(result)
333-
return true;
334-
335-
ffStrbufAppendS(&requestData->cacheDir, FF_CACHE_FILE_KITTY_UNCOMPRESSED);
336-
result = printCachedKittyFile(instance, requestData, false);
337-
ffStrbufSubstrBefore(&requestData->cacheDir, cacheDirLength);
338-
339-
return result;
279+
return fd;
340280
}
341281

342-
static bool printCached(const FFinstance* instance, FFLogoRequestData* requestData)
282+
static bool printCached(FFinstance* instance, FFLogoRequestData* requestData)
343283
{
344284
uint32_t cacheDirLength = requestData->cacheDir.length;
345285
ffStrbufAppendS(&requestData->cacheDir, FF_CACHE_FILE_HEIGHT);
@@ -357,10 +297,31 @@ static bool printCached(const FFinstance* instance, FFLogoRequestData* requestDa
357297
if(requestData->imagePixelHeight < 1)
358298
return false;
359299

360-
if(requestData->type == FF_LOGO_TYPE_SIXEL)
361-
return printCachedSixel(instance, requestData);
300+
int fd;
301+
if(requestData->type == FF_LOGO_TYPE_KITTY)
302+
{
303+
fd = getCacheFD(requestData, FF_CACHE_FILE_KITTY_COMPRESSED);
304+
if(fd == -1)
305+
fd = getCacheFD(requestData, FF_CACHE_FILE_KITTY_UNCOMPRESSED);
306+
}
362307
else
363-
return printCachedKitty(instance, requestData);
308+
fd = getCacheFD(requestData, FF_CACHE_FILE_SIXEL);
309+
310+
if(fd == -1)
311+
return false;
312+
313+
ffPrintCharTimes(' ', instance->config.logoPaddingLeft);
314+
fflush(stdout);
315+
316+
char buffer[32768];
317+
ssize_t readBytes;
318+
while((readBytes = read(fd, buffer, sizeof(buffer))) > 0)
319+
(void) write(STDOUT_FILENO, buffer, (size_t) readBytes);
320+
321+
close(fd);
322+
323+
finishPrinting(instance, requestData);
324+
return true;
364325
}
365326

366327
static bool getTermInfo(struct winsize* winsize)
@@ -417,7 +378,6 @@ bool ffLogoPrintImageIfExists(FFinstance* instance, FFLogoType type)
417378

418379
if(!instance->config.recache && printCached(instance, &requestData))
419380
{
420-
finishPrinting(instance, &requestData);
421381
ffStrbufDestroy(&requestData.cacheDir);
422382
return true;
423383
}

0 commit comments

Comments
 (0)