teynav / signalApngSticker

Convert Telegram Stickers (tgs) to Apng <300 kb for Signal Automatically using script
GNU General Public License v3.0
67 stars 5 forks source link

Support for webm and webp stickers, various bug fixes, code identation cleanup #7

Closed laggykiller closed 1 year ago

laggykiller commented 1 year ago

This pull request will make change to the script_v3 but not the rust program.

Support for webm and webp stickers

Not all telegram stickers are in tgs format. Take a look at this webm example and webp example. This pull request will add support to those formats.

Support for non-square stickers

Not all telegram stickers are downloaded as square. Examples could be found in the webm example given up there. The solution is to pad original video with transparent space using ffmpeg: ffmpeg -r $_FPS -i "$thedir/frame/%d.png" -vcodec apng -pix_fmt rgba -vf "scale=$RES:-1:flags=neighbor:sws_dither=none" -vf "scale=$RES:$RES:force_original_aspect_ratio=decrease,pad=$RES:$RES:(ow-iw)/2:(oh-ih)/2:color=black@0,setsar=1" -r $GFRAMES -plays 0 "$thedir/output.apng" &>/dev/null

Fix bug which cause pngquant to fail

Example using webm example 10th sticker (output_strip.1.png can be downloaded here)

pngquant --nofs --quality 85 --strip --ext '.2.png' -v "./output_strip.1.png"
./output_strip.1.png:
  read 622KB file
  made histogram...90 colors found
  selecting colors...9%
  selecting colors...18%
  selecting colors...61%
  selecting colors...91%
  moving colormap towards local minimum
  image degradation MSE=2.516 (Q=91) exceeded limit of 2.450 (91)
Skipped 1 file out of a total of 1 file.

Using --quality 0-85 solved the problem

Better zero-padding with the file name

 for (( i=0 ; i<10 ; i++ )) ;
 do
       mv $thedir/final/this-$i.png $thedir/final/this-0$i.png 
 **done**

It is not safe to assume there is only 10 frames in a sticker. Moreover this does not work if there is only 1 frame, and throws errors if there is no exactly 10 frames. To make it more robust, the code is changed to

if [[ ! -f $thedir/final/this.png ]]; then # Only this.png exists if only one frame exists
  for file in $thedir/final/*.png; do
        i=$(echo "$file" | sed -e 's/.*this-\(.*\)\.png/\1/')
        i_padded=$(printf "%03d" $i)
        file_new=$(echo "$file" | sed -r "s/(this-).*(\.png)/\1${i_padded}\2/g")
        mv $file $file_new
  done
fi

Better handling of static stickers

If the sticker is static, then only $thedir/final/this.png exists An explicit check (if [[ ! -f $thedir/final/this.png ]]) is added so that it will not fail to handle static stickers

Allow lower res and fps

For example, the 25th sticker of the webm example given above is too chaotic that the resolution needs to be further down Hence, res 200 is added and minimum fps could go down to 3 (if [[ $GFRAMES -gt "3" ]])

Bug fix in core-hybrid shouldwait

...
DEFAULTR=$isresdiff
convert  -crop $DEFAULTR $thedir/output_final.png  $thedir/final/this.png 
ff=0
for file in $thedir/final/*.png 
do 
      shouldwait=$(python -c "print($f%5)")
      if [[ $shouldwait == 0 ]] 
      then
        wait 
      fi
...

On line shouldwait=$(python -c "print($f%5)"), $f should be $ff

...
DEFAULTR=$isresdiff
convert  -crop $DEFAULTR $thedir/output_final.png  $thedir/final/this.png 
ff=1
for file in $thedir/final/*.png; do 
      shouldwait=$(python -c "print($ff%5)")
      if [[ $shouldwait == 0 ]]; then
        wait 
      fi
...

Python open file using with

Files should be closed using f.close(). Using with open() ensures f still get closed if exception occurs. For more info, read this: https://stackoverflow.com/questions/2738365/whats-the-advantage-of-using-with-as-statement-in-python

Code identation cleanup

The original code identation is quite messy, which this pull request will also fix

laggykiller commented 1 year ago

Added function for quickly handling static images, as well as allowing different size limit for static and animated file (Useful for WhatsApp sticker making) (Default size limit is unchanged)

teynav commented 1 year ago

Hey thanks a lot, give me some time to review it, I have been trying to solve this issue!!!

teynav commented 1 year ago

@laggykiller This looks promising, I just don't wanna make it into ./script_v3 , could you copy all your changes to ./script_v4 folder, I know this might sound stupid but i like to do versioning like this, this makes it easy for me to compare if something goes wrong in future. I hope you wouldn't mind

laggykiller commented 1 year ago

Bumped to v4 and changed README

teynav commented 1 year ago

Thanks a lot, I will review it in next 2 days. This looks like great work. Although am not quite sure but all video stickers of telegrams are vp9 codec, Right?

laggykiller commented 1 year ago

Although am not quite sure but all video stickers of telegrams are vp9 codec, Right?

webm also supports AV1 codec as shown here: https://en.wikipedia.org/wiki/WebM

However, according to here: https://core.telegram.org/stickers/webm-vp9-encoding

Video must be encoded with the VP9 codec.

teynav commented 1 year ago

Is there any way we can implement transparency instead of changing it to color black? https://t.me/addstickers/Minecraft

laggykiller commented 1 year ago

Seems like specifying decoder libvpx-vp9 for webm file input is needed to achieve this

ffmpeg -y -c:v libvpx-vp9 -i .\in.webm -r 30 -loop 0 .\out.apng

Reference: https://stackoverflow.com/questions/68553648/how-to-make-ffmpeg-re-encode-an-vp9-webm-with-alpha-into-a-vp9-webm-with-alpha