9

I want to be able to change the size of a dynamic webp. Sample picture. I found this website to do just that.

So how can I implement something similar in my own program? I tried using ImageMagick7 or ffmpeg5, but failed.

Environment:

cat /etc/redhat-release: CentOS Linux release 7.8.2003 (Core)

1. Tried ffmpeg:

[developer@Dev_Payment_229 ~]$ /opt/ffmpeg-5/ffmpeg -i b.webp -vf "scale=320:-1" b_320.webp
ffmpeg version 5.1.1-static https://johnvansickle.com/ffmpeg/  Copyright (c) 2000-2022 the FFmpeg developers
  built with gcc 8 (Debian 8.3.0-6)
  configuration: --enable-gpl --enable-version3 --enable-static --disable-debug --disable-ffplay --disable-indev=sndio --disable-outdev=sndio --cc=gcc --enable-fontconfig --enable-frei0r --enable-gnutls --enable-gmp --enable-libgme --enable-gray --enable-libaom --enable-libfribidi --enable-libass --enable-libvmaf --enable-libfreetype --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-librubberband --enable-libsoxr --enable-libspeex --enable-libsrt --enable-libvorbis --enable-libopus --enable-libtheora --enable-libvidstab --enable-libvo-amrwbenc --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libdav1d --enable-libxvid --enable-libzvbi --enable-libzimg
  libavutil      57. 28.100 / 57. 28.100
  libavcodec     59. 37.100 / 59. 37.100
  libavformat    59. 27.100 / 59. 27.100
  libavdevice    59.  7.100 / 59.  7.100
  libavfilter     8. 44.100 /  8. 44.100
  libswscale      6.  7.100 /  6.  7.100
  libswresample   4.  7.100 /  4.  7.100
  libpostproc    56.  6.100 / 56.  6.100
[webp @ 0x7686f40] skipping unsupported chunk: ANIM
[webp @ 0x7686f40] skipping unsupported chunk: ANMF
    Last message repeated 10 times
[webp @ 0x7686f40] image data not found
[webp_pipe @ 0x7685700] Could not find codec parameters for stream 0 (Video: webp, none): unspecified size
Consider increasing the value for the 'analyzeduration' (0) and 'probesize' (5000000) options
Input #0, webp_pipe, from 'b.webp':
  Duration: N/A, bitrate: N/A
  Stream #0:0: Video: webp, none, 25 fps, 25 tbr, 25 tbn
Stream mapping:
  Stream #0:0 -> #0:0 (webp (native) -> webp (libwebp_anim))
Press [q] to stop, [?] for help
[webp @ 0x7697600] skipping unsupported chunk: ANIM
[webp @ 0x7697600] skipping unsupported chunk: ANMF
    Last message repeated 10 times
[webp @ 0x7697600] image data not found
Error while decoding stream #0:0: Invalid data found when processing input
Cannot determine format of input stream 0:0 after EOF
Error marking filters as finished
Conversion failed!

It seems that ffmpeg cannot recognize this dynamic WebP image.

2. Tried ImageMagick7

Install:

 yum -y install libwebp-devel libwebp-tools
[root@Dev_FTP_241 developer]# yum list installed | grep webp
libwebp.x86_64                         0.3.0-11.el7               @updates
libwebp-devel.x86_64                   0.3.0-11.el7               @updates
libwebp-tools.x86_64                   0.3.0-11.el7               @updates

Source code:

https://github.com/ImageMagick/ImageMagick/archive/refs/tags/7.1.1-0.tar.gz
tar -xvf ImageMagick-7.1.1-0.tar.gz
./configure --with-webp --prefix=/usr/local/imagemagick
make
make install

Single WebP can be resized:

[root@Dev_FTP_241 developer]#  /usr/local/imagemagick/bin/convert -resize 480  simple.webp simple_480.webp
Decoded /tmp/magick-LNPdXgk2zDpiuU6Qv9CpDups3560EATh. Dimensions: 2160 x 608. Now saving...
Saved file /tmp/magick-Q8JHRZZOXdp1r1x187eftzsFlw8AqAuo

But animated WebP failed:

[root@Dev_FTP_241 developer]#  /usr/local/imagemagick/bin/convert -resize 480  b.webp b_480.webp
Error! Decoding of an animated WebP file is not supported.
       Use webpmux to extract the individual frames or
       vwebp to view this image.
Decoding of /tmp/magick-jMiy7ytmAnBzpS8UpafCQ5B44BjDTUSD failed.
Status: 4 (UNSUPPORTED_FEATURE)
convert: delegate failed `'dwebp' -pam '%i' -o '%o'' @ error/delegate.c/InvokeDelegate/1924.
convert: unable to open file '/tmp/magick-D-NMEGWU_a0IypZWwTpYiWIE61nteoig': No such file or directory @ error/constitute.c/ReadImage/786.
convert: no images defined `b_480.webp' @ error/convert.c/ConvertImageCommand/3342.
2

4 Answers 4

3

Google’s cwebp can resize WebP images but curiously not animated ones.

I had success trying with sharp, which is a npm package based on libvips.

Maybe the re-scaling works via the libvips CLI. If not, a sample sharp script (to be run with node.js) could look like this:

#!/usr/bin/env node

import * as fs from 'node:fs';
import sharp from 'sharp';

const dir = await fs.promises.opendir('./source');
const buffers = [];
for await (const dirent of dir) {
  if (dirent.isFile()) {
    buffers.push([
      dirent.name, fs.createReadStream('./source/'+dirent.name),
    ]);
  }
}

const width = 128; // change to your target width

await fs.promises.mkdir('./resized/');

for (const _buf of buffers) {
  const pipeline = sharp({ pages: -1, })
    .resize({ width, height: width, fit: 'inside' })
    .toFile('./resized/'+_buf[0]);

  try {
    await _buf[1].pipe(pipeline);
  } catch (e) {
    console.log('problem: '+e);
  }
}
2
  • 1
    I finally solved by using python. A python script with pillow .
    – shsf
    May 24 at 7:18
  • Doesn't work for me: "TypeError: dest.on is not a function" on await _buf[1].pipe(pipeline);
    – Vedmant
    Jun 26 at 3:20
7

ffmpeg doesn't seem to support decoding .webp in general as of today.

ImageMagick has that capability. You need to make sure that libwebpdemux is available in your system and that your ImageMagick build has WebP support enabled. Then using this command worked for me:

magick input.webp -resize 50% -layers coalesce output.webp

-layers coalesce is required to standarize frames, else you get errors for frame dimensions.

4

For me image magick works, but you have to input the resize size option in percentage for some reason else the webp loses its animation.

So if the original is 512x512 and you want 480x480 you have to do some simple calculations first:

480 / 512 * 100 = 93,75%

magick b_512.webp -resize 93.75% b_480.webp

You have to use dot not comma as decimal separater...

1

using python script

install python:

yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel libjpeg-turbo-devel readline-devel tk-devel gcc make

wget https://www.python.org/ftp/python/3.9.9/Python-3.9.9.tgz

tar -zxvf Python-3.9.9.tgz

cd Python-3.9.9

./configure --prefix=/usr/local/python3.9
make
make install

/usr/local/python3.9/bin/python3 -V
/usr/local/python3.9/bin/pip3 -V

install pillow:

/usr/local/python3.9/bin/pip3 install pillow==9.5.0

create .py: vi resize.py

# coding:utf-8
# resize.py
import sys
from PIL import Image, ImageSequence

try:
    height = int(sys.argv[1])
    input_file = sys.argv[2]
    output_file = sys.argv[3]
except IndexError:
    print('Usage: python resize.py <height> <input_file> <output_file>')
    print('Example: python resize.py 400 input.webp output.webp')
    sys.exit(1)

# 加载动态 WebP 图像
image = Image.open(input_file)

# 计算新的高度(保持原始宽高比)
orig_width, orig_height = image.size
width = int(orig_width * (height / orig_height))
if height <= 0:
    width = orig_width
    height = orig_height

# 获取所有帧数据
frames = []
for frame in ImageSequence.Iterator(image):
    frames.append(frame.copy())

if len(frames) > 1:
    # print('多张')
    # 缩放每个帧
    new_frames = []

    first_frame = frames[0]

    for i in range(len(frames)):
        new_frame = frames[i].resize((width, height))
        new_frames.append(new_frame)

    # 将动画 图像另存为文件
    new_frames[0].save(
        output_file,
        save_all=True,
        append_images=new_frames[1:],
    )

else:
    # print('单张')
    # 缩放图像
    new_img = image.resize((width, height))
    # 保存新图像
    new_img.save(output_file)

Test:

/usr/local/python3.9/bin/python3 resize.py 260  animated.webp ani_resize260.webp

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .