diff --git a/CHANGES b/CHANGES
index e7af312c53aad3740eaeab7d675daccb8e9abae7..c752f07ae64fe84ac76281c440ccc77b430ef7e9 100644
--- a/CHANGES
+++ b/CHANGES
@@ -37,6 +37,8 @@ Incompatible changes
 New modules and functions
 -------------------------
 
+o Support for decoding the AVIF image format through the new Image.AVIF module.
+
 
 New features
 ------------
diff --git a/src/post_modules/_Image_AVIF/Makefile.in b/src/post_modules/_Image_AVIF/Makefile.in
new file mode 100644
index 0000000000000000000000000000000000000000..7f9c90cce970ca1a115bbcc4cbc6aebc6dd8aed8
--- /dev/null
+++ b/src/post_modules/_Image_AVIF/Makefile.in
@@ -0,0 +1,10 @@
+@make_variables@
+VPATH=@srcdir@
+OBJS=image_avif.o
+MODULE_LDFLAGS=@LDFLAGS@ @LIBS@
+
+@dynamic_module_makefile@
+
+image_avif.o : $(SRCDIR)/image_avif.c
+
+@dependencies@
diff --git a/src/post_modules/_Image_AVIF/acconfig.h b/src/post_modules/_Image_AVIF/acconfig.h
new file mode 100644
index 0000000000000000000000000000000000000000..3c9afa6e9d8d43f8b787f619e9daf2928c158373
--- /dev/null
+++ b/src/post_modules/_Image_AVIF/acconfig.h
@@ -0,0 +1,7 @@
+/*
+|| This file is part of Pike. For copyright information see COPYRIGHT.
+|| Pike is distributed under GPL, LGPL and MPL. See the file COPYING
+|| for more information.
+*/
+@TOP@
+@BOTTOM@
diff --git a/src/post_modules/_Image_AVIF/config.h.in b/src/post_modules/_Image_AVIF/config.h.in
new file mode 100644
index 0000000000000000000000000000000000000000..6bc5b6818f6fc5760308ee551345f7b8a95059b7
--- /dev/null
+++ b/src/post_modules/_Image_AVIF/config.h.in
@@ -0,0 +1,215 @@
+/* config.h.in.  Generated from configure.in by autoheader.  */
+/*
+|| This file is part of Pike. For copyright information see COPYRIGHT.
+|| Pike is distributed under GPL, LGPL and MPL. See the file COPYING
+|| for more information.
+*/
+
+/* Define to 1 if you have the <avif/avif.h> header file. */
+#undef HAVE_AVIF_AVIF_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define when the -lavif library is available */
+#undef HAVE_LIBAVIF
+
+/* Define to 1 if you have the <minix/config.h> header file. */
+#undef HAVE_MINIX_CONFIG_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#undef HAVE_STDIO_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the <wchar.h> header file. */
+#undef HAVE_WCHAR_H
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if all of the C90 standard headers exist (not just the ones
+   required in a freestanding environment). This macro is provided for
+   backward compatibility; new code need not use it. */
+#undef STDC_HEADERS
+
+
+#ifndef _DARWIN_C_SOURCE
+/* Overrides disabling of non-posix symbols by _POSIX_C_SOURCE on Darwin. */
+#undef _DARWIN_C_SOURCE
+#endif
+
+#ifndef POSIX_SOURCE
+ /* We must define this *always* */
+# define POSIX_SOURCE	1
+#endif
+#ifndef _POSIX_C_SOURCE
+#if defined(__APPLE__) && defined(HAVE_SYS_SOCKET_H)
+/* The <sys/socket.h> headerfile is broken on MacOS X as is disregards
+ * _DARWIN_C_SOURCE with respect to the declaration of sendfile(2).
+ * We thus need to include <sys/socket.h> before we set the POSIX
+ * compatibility level.
+ */
+#include <sys/socket.h>
+#endif
+  /* Version of POSIX that we want to support.
+   * Note that POSIX.1-2001 and later require C99, and the earlier
+   * require C89.
+   *	undef		Not POSIX.
+   *	1		POSIX.1-1990
+   *	2		POSIX.2-1992
+   *	199309L		POSIX.1b-1993 (Real Time)
+   *	199506L		POSIX.1c-1995 (POSIX Threads)
+   *	200112L		POSIX.1-2001 (Austin Group Revision)
+   *	200809L		POSIX.1-2008
+   */
+# undef _POSIX_C_SOURCE
+#endif
+#ifndef _XOPEN_SOURCE
+  /* Version of XPG that we want to support.
+   * Note that this interacts with _POSIX_C_SOURCE above.
+   *	undef		Not XPG (X Open Group).
+   *	1		XPG 3 or 4 or 4v2 (see below).
+   *	500		XPG 5 (POSIX.1c-1995).
+   *	600		XPG 6 (POSIX.1-2001).
+   *	700		XPG 7 (POSIX.1-2008).
+   */
+# undef _XOPEN_SOURCE
+
+# if defined(_XOPEN_SOURCE) && ((_XOPEN_SOURCE + 0) < 500)
+   /* Define to 4 for XPG 4. NB: Overrides _XOPEN_SOURCE_EXTENDED below. */
+#  undef _XOPEN_VERSION
+
+   /* Define to 1 (and do NOT define _XOPEN_VERSION) for XPG 4v2. */
+#  undef _XOPEN_SOURCE_EXTENDED
+# endif
+#endif
+#ifndef _NETBSD_SOURCE
+#undef _NETBSD_SOURCE
+#endif
+#ifndef __BSD_VISIBLE
+#undef __BSD_VISIBLE
+#endif
+
+
+/* Enable extensions on AIX 3, Interix.  */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+/* Enable general extensions on macOS.  */
+#ifndef _DARWIN_C_SOURCE
+# undef _DARWIN_C_SOURCE
+#endif
+/* Enable general extensions on Solaris.  */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+/* Enable GNU extensions on systems that have them.  */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+/* Enable X/Open compliant socket functions that do not require linking
+   with -lxnet on HP-UX 11.11.  */
+#ifndef _HPUX_ALT_XOPEN_SOCKET_API
+# undef _HPUX_ALT_XOPEN_SOCKET_API
+#endif
+/* Identify the host operating system as Minix.
+   This macro does not affect the system headers' behavior.
+   A future release of Autoconf may stop defining this macro.  */
+#ifndef _MINIX
+# undef _MINIX
+#endif
+/* Enable general extensions on NetBSD.
+   Enable NetBSD compatibility extensions on Minix.  */
+#ifndef _NETBSD_SOURCE
+# undef _NETBSD_SOURCE
+#endif
+/* Enable OpenBSD compatibility extensions on NetBSD.
+   Oddly enough, this does nothing on OpenBSD.  */
+#ifndef _OPENBSD_SOURCE
+# undef _OPENBSD_SOURCE
+#endif
+/* Define to 1 if needed for POSIX-compatible behavior.  */
+#ifndef _POSIX_SOURCE
+# undef _POSIX_SOURCE
+#endif
+/* Define to 2 if needed for POSIX-compatible behavior.  */
+#ifndef _POSIX_1_SOURCE
+# undef _POSIX_1_SOURCE
+#endif
+/* Enable POSIX-compatible threading on Solaris.  */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+/* Enable extensions specified by ISO/IEC TS 18661-5:2014.  */
+#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__
+# undef __STDC_WANT_IEC_60559_ATTRIBS_EXT__
+#endif
+/* Enable extensions specified by ISO/IEC TS 18661-1:2014.  */
+#ifndef __STDC_WANT_IEC_60559_BFP_EXT__
+# undef __STDC_WANT_IEC_60559_BFP_EXT__
+#endif
+/* Enable extensions specified by ISO/IEC TS 18661-2:2015.  */
+#ifndef __STDC_WANT_IEC_60559_DFP_EXT__
+# undef __STDC_WANT_IEC_60559_DFP_EXT__
+#endif
+/* Enable extensions specified by ISO/IEC TS 18661-4:2015.  */
+#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__
+# undef __STDC_WANT_IEC_60559_FUNCS_EXT__
+#endif
+/* Enable extensions specified by ISO/IEC TS 18661-3:2015.  */
+#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__
+# undef __STDC_WANT_IEC_60559_TYPES_EXT__
+#endif
+/* Enable extensions specified by ISO/IEC TR 24731-2:2010.  */
+#ifndef __STDC_WANT_LIB_EXT2__
+# undef __STDC_WANT_LIB_EXT2__
+#endif
+/* Enable extensions specified by ISO/IEC 24747:2009.  */
+#ifndef __STDC_WANT_MATH_SPEC_FUNCS__
+# undef __STDC_WANT_MATH_SPEC_FUNCS__
+#endif
+/* Enable extensions on HP NonStop.  */
+#ifndef _TANDEM_SOURCE
+# undef _TANDEM_SOURCE
+#endif
+/* Enable X/Open extensions.  Define to 500 only if necessary
+   to make mbstate_t available.  */
+#ifndef _XOPEN_SOURCE
+# undef _XOPEN_SOURCE
+#endif
+
diff --git a/src/post_modules/_Image_AVIF/configure.in b/src/post_modules/_Image_AVIF/configure.in
new file mode 100644
index 0000000000000000000000000000000000000000..06b25e567953970e97cf5f309e30c77d8436f910
--- /dev/null
+++ b/src/post_modules/_Image_AVIF/configure.in
@@ -0,0 +1,21 @@
+#
+AC_INIT(image_avif.cmod)
+AC_MODULE_INIT()
+AC_CONFIG_HEADER(config.h)
+
+PIKE_FEATURE_NODEP(Image.AVIF)
+
+AC_CHECK_HEADERS(avif/avif.h)
+if test $ac_cv_header_avif_avif_h = yes ; then
+  have_libavif=false
+  AC_CHECK_LIB([avif], [avifVersion], [
+    LIBS="${LIBS-} -lavif"
+    have_libavif=true
+  ])
+  if $have_libavif; then
+    AC_DEFINE(HAVE_LIBAVIF,[],[Define when the -lavif library is available])
+    PIKE_FEATURE_OK(Image.AVIF)
+  fi
+fi
+
+AC_OUTPUT(Makefile,echo FOO >stamp-h )
diff --git a/src/post_modules/_Image_AVIF/image_avif.cmod b/src/post_modules/_Image_AVIF/image_avif.cmod
new file mode 100644
index 0000000000000000000000000000000000000000..146ce7b830fef65bd1785f802355a96834e68e66
--- /dev/null
+++ b/src/post_modules/_Image_AVIF/image_avif.cmod
@@ -0,0 +1,195 @@
+/* -*- c -*-
+|| This file is part of Pike. For copyright information see COPYRIGHT.
+|| Pike is distributed under GPL, LGPL and MPL. See the file COPYING
+|| for more information.
+*/
+
+/* https://github.com/AOMediaCodec/libavif/tree/main/examples
+ */
+
+#include "pike_macros.h"
+#include "object.h"
+#include "constants.h"
+#include "interpret.h"
+#include "svalue.h"
+#include "threads.h"
+#include "array.h"
+#include "builtin_functions.h"
+#include "mapping.h"
+#include "pike_error.h"
+#include "operators.h"
+#include "module_support.h"
+#include "modules/Image/image.h"
+#include "config.h"
+
+#ifdef HAVE_LIBAVIF
+DECLARATIONS
+
+#include <avif/avif.h>
+
+static struct program *img_program;
+
+static struct program *image_program()
+{
+  if( !img_program )
+  {
+    push_static_text("Image.Image");
+    SAFE_APPLY_MASTER("resolv",1);
+    img_program = Pike_sp[-1].u.program;
+    Pike_sp--;
+  }
+  return img_program;
+}
+
+static struct object *allocate_image(int w, int h )
+{
+  push_int(w);
+  push_int(h);
+  return clone_object(image_program(),2);
+}
+
+static inline unsigned char *image_ptr( struct object *img )
+{
+  char *x;
+  if( !img ) return 0;
+  x = get_storage( img, image_program() );
+  if( !x ) return 0;
+  return (unsigned char *)(((struct image  *)x)->img);
+}
+
+PIKEFUN mapping(string:object(Image.Image)|string) _decode( string data )
+{
+  int width, height, npix;
+  uint8_t *ip, *ap;
+  uint8_t av;
+  struct object *i = NULL, *a = NULL;
+
+  avifRGBImage rgb;
+  memset(&rgb, 0, sizeof(rgb));
+
+  avifDecoder *decoder = avifDecoderCreate();
+  decoder->imageCountLimit = 1;
+
+  avifResult result = avifDecoderSetIOMemory(decoder, (const uint8_t *)data->str, data->len);
+  if( result != AVIF_RESULT_OK ) {
+    goto cleanup;
+  }
+
+  result = avifDecoderParse(decoder);
+  if( result != AVIF_RESULT_OK ) {
+    goto cleanup;
+  }
+
+  if( avifDecoderNextImage(decoder) != AVIF_RESULT_OK ) {
+    goto cleanup;
+  }
+
+  avifRGBImageSetDefaults(&rgb, decoder->image);
+  /*result =*/ avifRGBImageAllocatePixels(&rgb);
+  /*if( result != AVIF_RESULT_OK ) {
+    goto cleanup;
+  }*/
+
+  result = avifImageYUVToRGB(decoder->image, &rgb);
+  if( result != AVIF_RESULT_OK ) {
+    goto cleanup;
+  }
+
+  pop_n_elems(args);
+
+  width = decoder->image->width;
+  height = decoder->image->height;
+
+  npix = width * height;
+  ip = ap = NULL;
+
+  if( decoder->alphaPresent ) {
+    a = allocate_image( width, height );
+    ap = image_ptr( a );
+  }
+  i = allocate_image( width, height );
+  ip = image_ptr( i );
+
+  if( rgb.depth > 8 ) {
+    uint16_t *rp = (uint16_t *)rgb.pixels;
+    int shift = rgb.depth - 8;
+    while( npix-- ) {
+      *(ip++) = (uint8_t)( *(rp++) >> shift ); // R
+      *(ip++) = (uint8_t)( *(rp++) >> shift ); // G
+      *(ip++) = (uint8_t)( *(rp++) >> shift ); // B
+      av = (uint8_t)( *(rp++) >> shift );
+
+      if( ap ) {
+        *(ap++) = av; // A
+        *(ap++) = av;
+        *(ap++) = av;
+      }
+    }
+  } else {
+    uint8_t *rp = rgb.pixels;
+    while( npix-- ) {
+      *(ip++) = *(rp++); // R
+      *(ip++) = *(rp++); // G
+      *(ip++) = *(rp++); // B
+      av = *(rp++);
+
+      if( ap ) {
+        *(ap++) = av; // A
+        *(ap++) = av;
+        *(ap++) = av;
+      }
+    }
+  }
+
+  push_static_text( "format" ); push_text( "image/avif" );
+  push_static_text( "xsize" ); push_int( width );
+  push_static_text( "ysize" ); push_int( height );
+  push_static_text( "image" );  push_object( i );
+  push_static_text( "alpha" );
+  if( a )
+    push_object( a );
+  else
+    push_undefined( );
+
+  f_aggregate_mapping( 10 );
+
+ cleanup:
+  avifRGBImageFreePixels(&rgb);
+  avifDecoderDestroy(decoder);
+  if( result != AVIF_RESULT_OK ) {
+    Pike_error("Failed to decode image\n");
+  }
+}
+
+PIKEFUN object(Image.Image) decode( string data )
+{
+  struct mapping *m;
+  struct svalue *p;
+
+  apply(Pike_fp->current_object, "_decode", args);
+
+  m = Pike_sp[-1].u.mapping;
+
+  if( TYPEOF(Pike_sp[-1]) != PIKE_T_MAPPING )
+      Pike_error("Decoding failed\n");
+
+  p = simple_mapping_string_lookup(m,"image");
+
+  if( !p || TYPEOF(*p) != PIKE_T_OBJECT )
+      Pike_error("Decoding failed\n");
+
+  ref_push_object( p->u.object );
+  stack_unlink(1);
+}
+
+PIKE_MODULE_INIT
+{
+  INIT
+  add_integer_constant("version", AVIF_VERSION, 0);
+}
+
+PIKE_MODULE_EXIT
+{
+  EXIT
+}
+#endif