77#include <string.h>
88
99#include "stable-diffusion.h"
10+ #include "./gif.h" // charlietangora/gif-h
1011
1112#ifndef MSF_GIF_IMPL
1213#define MSF_GIF_IMPL
@@ -401,7 +402,7 @@ int create_mjpg_avi_membuf_from_sd_images(sd_image_t* images, int num_images, in
401402// ---------------- Helper: create_gif_buf_from_sd_images ----------------
402403// Builds a GIF in memory from an array of sd_image_t. Returns 0 on success, -1 on failure.
403404// Caller must free(*out_data) when done.
404- int create_gif_buf_from_sd_images (sd_image_t * images , int num_images , int fps , uint8_t * * out_data , size_t * out_len )
405+ int create_gif_buf_from_sd_images_msf (sd_image_t * images , int num_images , int fps , uint8_t * * out_data , size_t * out_len )
405406{
406407 if (!images || num_images <= 0 || !out_data || !out_len ) return -1 ;
407408
@@ -471,4 +472,96 @@ int create_gif_buf_from_sd_images(sd_image_t* images, int num_images, int fps,
471472 return 0 ;
472473}
473474
475+ int create_gif_buf_from_sd_images_gifh (sd_image_t * images , int num_images , int fps , uint8_t * * out_data , size_t * out_len )
476+ {
477+ if (!images || num_images <= 0 || !out_data || !out_len ) return -1 ;
478+
479+ // basic parameter heuristics
480+ if (fps <= 0 ) fps = 16 ;
481+ uint32_t delay = (uint32_t )(100 / fps ); // hundredths of a second per frame
482+
483+ int bitDepth = 8 ;
484+ bool dither = false;
485+
486+ // assume all images same size; use first
487+ uint32_t width = images [0 ].width ;
488+ uint32_t height = images [0 ].height ;
489+
490+ GifWriter gw ;
491+ memset (& gw , 0 , sizeof (gw ));
492+
493+ if (!GifBegin (& gw , width , height , delay , bitDepth , dither ))
494+ {
495+ if (gw .oldImage ) GIF_FREE (gw .oldImage );
496+
497+ fprintf (stderr , "Error: GifBegin failed.\n" );
498+ return -1 ;
499+ }
500+
501+ // Feed frames
502+ for (int i = 0 ; i < num_images ; i ++ )
503+ {
504+ sd_image_t * img = & images [i ];
505+
506+ if (img -> width != width || img -> height != height ) {
507+ fprintf (stderr , "Frame %d has mismatched dimensions.\n" , i );
508+ GifEnd (& gw );
509+ memfile_free (& gw .mem );
510+ return -1 ;
511+ }
512+
513+ // gif-h expects 4 channels (RGBA) or 3 channels (RGB). It quantizes internally.
514+ // If your images have 3 channels, that’s fine. If 4 channels, it also works.
515+ int channels = img -> channel ;
516+ if (channels != 3 && channels != 4 ) {
517+ fprintf (stderr , "Unsupported channel count: %d\n" , channels );
518+ GifEnd (& gw );
519+ memfile_free (& gw .mem );
520+ return -1 ;
521+ }
522+
523+ // gif-h requires 4 channels (RGBA). If you only have RGB, add opaque alpha.
524+ uint8_t * frame_rgba = NULL ;
525+ if (channels == 3 ) {
526+ frame_rgba = (uint8_t * )malloc (width * height * 4 );
527+ for (int p = 0 ; p < width * height ; p ++ ) {
528+ frame_rgba [p * 4 + 0 ] = img -> data [p * 3 + 0 ];
529+ frame_rgba [p * 4 + 1 ] = img -> data [p * 3 + 1 ];
530+ frame_rgba [p * 4 + 2 ] = img -> data [p * 3 + 2 ];
531+ frame_rgba [p * 4 + 3 ] = 255 ;
532+ }
533+ } else {
534+ frame_rgba = img -> data ; // already RGBA
535+ }
536+
537+ if (!GifWriteFrame (& gw , frame_rgba , width , height , delay , bitDepth , dither ))
538+ {
539+ fprintf (stderr , "GIF Write Failed\n" );
540+ GifEnd (& gw );
541+ memfile_free (& gw .mem );
542+ return -1 ;
543+ }
544+
545+ if (channels == 3 ) {
546+ free (frame_rgba );
547+ }
548+ }
549+
550+ if (!GifEnd (& gw ))
551+ {
552+ memfile_free (& gw .mem );
553+ return -1 ;
554+ }
555+
556+ uint8_t * buf = memfile_detach (& gw .mem , out_len );
557+ if (!buf )
558+ {
559+ memfile_free (& gw .mem );
560+ return -1 ;
561+ }
562+
563+ * out_data = buf ;
564+ return 0 ;
565+ }
566+
474567#endif // __AVI_WRITER_H__
0 commit comments