Page 1 of 1

Create timed subtitles/text on GIF

Posted: 2014-03-23T03:29:20-07:00
by Andy
Hi,

as the title says i want to add multiple subtitles to a gif.
For example frame 1-5 subtitle 1 and frame 6-10 subtitle 2.

I already found a solution but it's far from perfect.

I do it like this:
  • Extract frames from a movie with ffmpeg
  • Traverse all frames and add the text. "convert -annotate +2+4 'test' currentFrame.png currentFrame.png"
  • Create gif "convert *.png out.gif"
This method has two big disadvantages. First it is slow and second, effects that are applied to the gif are applied to the text as well and i want to avoid that.

Something like this would be great:

Code: Select all

"convert -annotate frame 1-5 'sub1' -annotate frame 6-10 'sub2' *.png out.gif"
Is that possible?

Thanks,
Andy

Re: Create timed subtitles/text on GIF

Posted: 2014-03-23T10:00:40-07:00
by snibgo
Windows syntax:

Code: Select all

convert ^
  wandTip0.gif -coalesce ^
  -gravity SouthWest ^
  ( -clone 0-5 -annotate 0 "Sub1" ) ^
  ( -clone 6-10 -annotate 0 "Sub2" ) ^
  ( -clone 11-15 ) ^
  -delete 0-15 ^
  out.gif
The input has 16 frames, numbered 0 to 15. The command makes copies of the first 6 and annotates them. Likewise the next 5 frames. So we now have 16+6+5 = 27 frames. I copy the remaining frames and delete the originals.

Re: Create timed subtitles/text on GIF

Posted: 2014-03-23T15:28:10-07:00
by Andy
Hi snibgo,
thanks for your suggestion but i don't have a gif as input.
As i said, i have extracted images.

Re: Create timed subtitles/text on GIF

Posted: 2014-03-23T15:56:32-07:00
by snibgo
Then use *.png instead of gif, eg:

Code: Select all

convert ^
  wt_*.png ^
  -gravity SouthWest ^
  ( -clone 0-5 -annotate 0 "Sub1" ) ^
  ( -clone 6-10 -annotate 0 "Sub2" ) ^
  ( -clone 11-15 ) ^
  -delete 0-15 ^
  out.gif
(Windows syntax.)

Re: Create timed subtitles/text on GIF

Posted: 2014-03-24T02:38:03-07:00
by Andy
well, right, i could have guessed that myself. :) Thanks

Works good but there is one problem left.

How do i paint two texts on the same frame because sometimes the subtitles or texts i want to paint overlap and some frames don't have text at all.

Something like this:

30 frames in total.
Frame 5 - 15 sub1
Frame 10 - 20 sub2
Frame 1 - 30 sub3

I could do something like this but that gets really messy really quick as you can see:

Code: Select all


  ( -clone 1-5 -annotate 0 "Sub3" ) ^
  ( -clone 5-10 -annotate 0 "Sub1" -annotate 0 "Sub3" ) ^
  ( -clone 10-15 -annotate 0 "Sub1" -annotate 0 "Sub2" -annotate 0 "Sub3" ) ^
  ( -clone15-20 -annotate 0 "Sub2" -annotate 0 "Sub3" ) ^
  ( -clone 20-30 -annotate 0 "Sub3" ) ^

I am generating the convert call with a script so that makes it even harder to generate something like above automatically.
Is there any other way to do it? I tried to play around with -insert - swap and -delete but that does not seem to work either because i cannot swap ranges .

Greetings

Re: Create timed subtitles/text on GIF

Posted: 2014-03-24T08:33:50-07:00
by snibgo
There are many way of doing this. You could process each frame separately, with one convert per operation per frame:

Code: Select all

convert indir\frame_01.png -annotate 0 "sub3" outdir\frame_01.png

Code: Select all

convert indir\frame_02.png -annotate 0 "sub3" outdir\frame_02.png
etc. This is probably the easiest method to implement if your script is generated from another script or program. To avoid calling convert multiple times, they can be combined:

Code: Select all

convert ^
  ( indir\frame_01.png -annotate 0 "sub3" -write outdir\frame_01.png -delete ) ^
  ( indir\frame_02.png -annotate 0 "sub3" -write outdir\frame_02.png -delete ) ^
  NULL:

Re: Create timed subtitles/text on GIF

Posted: 2014-03-29T03:54:27-07:00
by Andy
Hi snibgo,
i finally had the time to play around with your suggestions a bit.

Looks good for one text but as soon as i print two strings on the same image the text starts to flicker.

I tried it like this:

Code: Select all

convert 
   \( 001.png -font "Indie-Flower" -pointsize 11  -annotate +259+63.58 "kbhjh"  -write 001.png \) 
   \( 002.png -font "Indie-Flower" -pointsize 11  -annotate +259+63.58 "kbhjh"  -write 002.png \) 
   \( 003.png -font "Indie-Flower" -pointsize 11  -annotate +259+63.58 "kbhjh"  -write 003.png \) 
   \( 003.png -font "Verdana" -pointsize 20  -annotate +0+0 "TEST"  -write 003.png \) 
-dispose Previous -delay 30 -coalesce -layers OptimizePlus -loop 0  +dither
test.gif
I noticed that the generated images look fine. They all have the text in the right spots so my guess is there is a problem with generating the gif in the same run.

Greetings

Re: Create timed subtitles/text on GIF

Posted: 2014-03-29T05:09:33-07:00
by snibgo
It works okay for me, with a few adjustments:

1. "-delay 30" before, not after, the inputs.

2. Insert "-gravity NorthWest" before "-annotate +0+0". Otherwise the text is outside the image.

3. Your script has 4 frames in the output gif (because there are four images in the list). If you only want 3 frames, you can "+delete". But you might want 4 frames, of course.

So my version of your script (Windows syntax) is:

Code: Select all

convert -size 300x200 xc:pink 001.png
convert -size 300x200 xc:lime 002.png
convert -size 300x200 xc:khaki 003.png

convert ^
   -delay 30 ^
   ( 001.png -font "Indie-Flower" -pointsize 11  -annotate +259+63.58 "kbhjh"  -write 001.png ) ^
   ( 002.png -font "Indie-Flower" -pointsize 11  -annotate +259+63.58 "kbhjh"  -write 002.png ) ^
   ( 003.png -font "Indie-Flower" -pointsize 11  -annotate +259+63.58 "kbhjh"  -write 003.png +delete ) ^
   ( 003.png -font "Verdana" -pointsize 20  -gravity NorthWest -annotate +0+0 "TEST"  -write 003.png ) ^
   -dispose Previous -coalesce -layers OptimizePlus -loop 0  +dither ^
test.gif
Writing each frame is useful for debugging but not required for the output, so:

Code: Select all

convert ^
   -delay 30 ^
   ( 001.png -font "Indie-Flower" -pointsize 11  -annotate +259+63.58 "kbhjh"  ) ^
   ( 002.png -font "Indie-Flower" -pointsize 11  -annotate +259+63.58 "kbhjh"  ) ^
   ( 003.png -font "Indie-Flower" -pointsize 11  -annotate +259+63.58 "kbhjh" ^
             -font "Verdana" -pointsize 20  -gravity NorthWest -annotate +0+0 "TEST" ) ^
   -dispose Previous -coalesce -layers OptimizePlus -loop 0  +dither ^
   test3frames.gif

convert ^
   -delay 30 ^
   ( 001.png -font "Indie-Flower" -pointsize 11  -annotate +259+63.58 "kbhjh" ) ^
   ( 002.png -font "Indie-Flower" -pointsize 11  -annotate +259+63.58 "kbhjh" ) ^
   ( 003.png -font "Indie-Flower" -pointsize 11  -annotate +259+63.58 "kbhjh" ) ^
   ( -clone 2 -font "Verdana" -pointsize 20  -gravity NorthWest -annotate +0+0 "TEST" ) ^
   -dispose Previous -coalesce -layers OptimizePlus -loop 0  +dither ^
   test4frames.gif

Re: Create timed subtitles/text on GIF

Posted: 2014-03-29T05:36:24-07:00
by Andy
The second example works! Thanks.

As you mentioned it. What is the best place to add parameters like -colors or -sharpen in your example?
My tests suggest that i have to pass each parameter to the "sub converts", is that right?

Re: Create timed subtitles/text on GIF

Posted: 2014-03-29T06:29:38-07:00
by snibgo
If you want to apply the same action(s) to all the frames, put it after the final close parenthesis ")". Or after one close parenthesis ")" but before the next open "(" to apply to all the preceding frames.

To apply to just one frame, put it within the appropriate parenthesis. Put it before or after the annotate, according to whether you want the text to be affected. (As a matter of style, I would keep "-font", "-pointsize" and "-annotate" together, ie don't split them up.)

These are the general rules for processing multiple images.

Re: Create timed subtitles/text on GIF

Posted: 2014-04-05T07:46:35-07:00
by Andy
I hope you don't mind this huge breaks in my replies but i only have time on the weekends to work on this.

My convert call looks like this:

Code: Select all

convert -delay 7.05882352941176  

\( 001.png -font "Indie-Flower" -pointsize 10 -fill "rgba(255,255,255,0.560)" -stroke none -annotate +22.5+40.221875 "test"  -modulate 100,90,100 -sharpen 0x1  -brightness-contrast 0x0  \)  

\( 002.png -font "Indie-Flower" -pointsize 10 -fill "rgba(255,255,255,0.560)" -stroke none -annotate +22.5+40.221875 "test"  -modulate 100,90,100 -sharpen 0x1  -brightness-contrast 0x0  \)  

\( 003.png -font "Indie-Flower" -pointsize 10 -fill "rgba(255,255,255,0.560)" -stroke none -annotate +22.5+40.221875 "test"  -modulate 100,90,100 -sharpen 0x1  -brightness-contrast 0x0  \)  

-enhance -dispose Previous -coalesce -layers OptimizePlus -loop 0 +dither -colors 512 test.gif
but i noticed, no matter where input: "-modulate 100,90,100 -sharpen 0x1 -brightness-contrast 0x0" they are always applied to the text as well. I tried before the image name, after the image name and like above.

But this also happens when i call it like this:

Code: Select all

convert -modulate 100,90,100 -sharpen 0x1  -brightness-contrast -40x0 -fuzz 0 -delay 11.7647058823529 -enhance -dispose Previous -coalesce -layers OptimizePlus -loop 0 +dither    \( -font 'Indie-Flower' -pointsize 10 -fill 'rgba(255,255,255,0.560)' -stroke none -annotate +22.5+40.221875 'test' \) *.png test.gif
So it's probably not related to the sub converts.

Also, the "-color" option does not seem to work like expected. For some reasons when adding "-colors 512" the gif gets slightly bigger.
But when i try it without the sub converts the option makes the gif smaller, so i guess something is wrong.

Last thing i noticed. The gif is a little bigger when i use the sub convert.

Greetings,
Andy

Re: Create timed subtitles/text on GIF

Posted: 2014-04-05T08:12:27-07:00
by snibgo
What version of IM are you using? "convert -version".

In the bad old days, IM didn't execute operations in the order given. These days it does.
Andy wrote:I tried before the image name
That shouldn't work.
Andy wrote:convert -modulate 100,90,100 -sharpen 0x1 -brightness-contrast -40x0 -fuzz 0 -delay 11.7647058823529 -enhance -dispose Previous -coalesce -layers OptimizePlus -loop 0 +dither \( -font 'Indie-Flower' -pointsize 10 -fill 'rgba(255,255,255,0.560)' -stroke none -annotate +22.5+40.221875 'test' \) *.png test.gif
This shouldn't work, because you are doing operations before reading the images. This is old syntax for old versions of IM.

Try these commands:

Code: Select all

convert rose: -gravity center -pointsize 20 -fill blue -annotate +0+0 "test" r.png

convert rose: -modulate 100,0,100 -gravity center -pointsize 20 -fill blue -annotate +0+0 "test" r1.png

convert rose: -gravity center -pointsize 20 -fill blue -annotate +0+0 "test" -modulate 100,0,100 r2.png
r.png should be blue text on red rose. r1.png should be blue text on grey rose. r2.png should be grey text on grey rose.

If your version is older than 6.8.something, I suggest you upgrade.

Re: Create timed subtitles/text on GIF

Posted: 2014-04-05T11:12:23-07:00
by Andy

Code: Select all

$ convert -version
Version: ImageMagick 6.8.8-9 Q16 x86_64 2014-03-20 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2014 ImageMagick Studio LLC
Features: DPC HDRI Modules OpenCL OpenMP
Delegates: bzlib cairo fontconfig freetype gslib jng jpeg lcms lqr ltdl lzma openexr pangocairo png ps rsvg tiff webp wmf x xml zlib
Yes, worked all as you described it.
snibgo wrote:
Andy wrote:convert -modulate 100,90,100 -sharpen 0x1 -brightness-contrast -40x0 -fuzz 0 -delay 11.7647058823529 -enhance -dispose Previous -coalesce -layers OptimizePlus -loop 0 +dither \( -font 'Indie-Flower' -pointsize 10 -fill 'rgba(255,255,255,0.560)' -stroke none -annotate +22.5+40.221875 'test' \) *.png test.gif
This shouldn't work, because you are doing operations before reading the images. This is old syntax for old versions of IM.
Strange, it works for me.