Pomelo

libvips source code

Pomelo uses libvips under LGPL-3.0-or-later through the NetVips.Native.win-x64 package. The build-win64-mxe project builds libvips as one DLL with every dependency linked in (its "web" build) and publishes it in a release zip, the libvips-packaging project repackages that zip into a tarball, the net-vips project packs the DLL from that tarball into the NetVips.Native.win-x64 package, and Pomelo ships the DLL unmodified as vips\libvips-42.dll.

For every version Pomelo has shipped, this page gives the exact source of libvips and of every LGPL or MPL library in that DLL, the patches the build applies to them, and how the DLL was built. The other libraries in it use permissive licences, listed in the third-party notices in the app. Copies of the archives are kept on this site next to this page for as long as Pomelo is offered. Requests for the source on a physical medium go to andrealoroni2.0@gmail.com

NetVips.Native.win-x64 8.18.7 (libvips 8.18.7)

First shipped in: Pomelo 1.0.0

Where the DLL comes from

The NuGet package NetVips.Native.win-x64 8.18.7 takes its lib/*.dll files from the libvips-packaging release tarball libvips-8.18.7-win-x64.tar.gz (the DownloadBinaries target of build/Build.cs at net-vips commit cd15060b98052d0b0b4c68e6330a6a3a7af65916). libvips-packaging builds that tarball from a release zip of the build-win64-mxe project. The revisions are:

The two archives that lead to the DLL:

Source of the LGPL and MPL libraries

Library Version Licence Source archive SHA-256 Copy on this site
cairo 1.18.6 MPL 1.1 cairo-1.18.6.tar.xz 1c767308174337a74694da0f3ec069c271452163a1ef4540964c50c301f157d4 part 1, part 2
fribidi 1.0.17 LGPLv3 fribidi-1.0.17.tar.xz 6949dcde27d41cebad1fd741fcafc36d55a1020d2d872d4a6eb3914caabbada2 fribidi-1.0.17.tar.xz
glib 2.90.0 LGPLv3 glib-2.90.0.tar.xz 17d15cac2af80a33271127408e0abc2748eb297c595c2a26409e81e14e7d1b8f glib-2.90.0.tar.xz
libexif 0.6.26 LGPLv3 libexif-0.6.26.tar.xz 4a055ed6575e61ca46c3172be3c753cc16c9becd0f99ec71d58dd0e471476c0c libexif-0.6.26.tar.xz
libheif 1.23.5 LGPLv3 libheif-1.23.5.tar.gz fd9036064c4432f0550d15072ddf34956a248279ee9aeaff0fba3fa0f77d8f1a libheif-1.23.5.tar.gz
librsvg 2.63.2 LGPLv3 librsvg-2.63.2.tar.xz 852b18e1a00b8605528825a27dc7748bff2a5dd254028f59dc22a34ea57e81b6 librsvg-2.63.2.tar.xz
libvips 8.18.7 LGPLv3 vips-8.18.7.tar.xz 5baaead3b0bb20ffdb9e9ff09aa9fda08620923df77b63b436654cb5e0b3bf94 vips-8.18.7.tar.xz
pango 1.58.2 LGPLv3 pango-1.58.2.tar.xz 342385b6ca3b7c73455d7c80a13b7dbe4489e00bc3bd4c5bd6ed4dce421e374a pango-1.58.2.tar.xz
proxy-libintl 0.5 LGPLv3 0.5.tar.gz f7a1cbd7579baaf575c66f9d99fb6295e9b0684a28b095967cfda17857595303 proxy-libintl-0.5.tar.gz

The copy of cairo-1.18.6.tar.xz is in two parts, because this site serves files of at most 25 MiB. Join them, then check the joined file against the SHA-256 in the table. In Windows PowerShell: cmd /c copy /b cairo-1.18.6.tar.xz.001 + cairo-1.18.6.tar.xz.002 cairo-1.18.6.tar.xz, then Get-FileHash cairo-1.18.6.tar.xz. On Linux or macOS: cat cairo-1.18.6.tar.xz.001 cairo-1.18.6.tar.xz.002 > cairo-1.18.6.tar.xz, then sha256sum cairo-1.18.6.tar.xz.

The versions are those in the package's versions.json. The package definitions below name the same versions. The package's THIRD-PARTY-NOTICES.md lists cairo under the Mozilla Public License 1.1 and the other eight under the LGPLv3, used through the "any later version" clause of the LGPLv2 or LGPLv2.1.

Version, archive and checksum of each library come from these package definitions:

The package definitions of fribidi, libexif, libheif, libvips and proxy-libintl give a GitHub project (_GH_CONF) and no URL. Their URLs follow from the rule in mxe's mxe.github.mk and each answered an HTTP HEAD request with status 200 (after redirects) on 2026-10-19. GitHub serves the proxy-libintl archive as 0.5.tar.gz, and the copy on this site has the name proxy-libintl-0.5.tar.gz, under which mxe stores it.

Patches applied to the sources

The build unpacks the source archive of each library and applies that library's patch files in file name order before it builds. build-win64-mxe sets the patch list (_PATCHES) of all nine libraries in its own package definitions, and mxe takes a library's patches only from that list (PKG_PATCHES in the Makefile of mxe at the commit above). So mxe's own patches for cairo, glib, libexif and librsvg (src/cairo-1-fixes.patch, src/glib-1-fixes.patch, src/libexif-1-fixes.patch and src/librsvg-1-fixes.patch in the mxe fork) are not applied, and mxe carries no patch for the other five libraries. The patches that are applied are all in build-win64-mxe at commit ef19ca09af2453d127453d677c849ccb37cf5694, at these paths:

Library Patch files
cairo build/patches/cairo-1-fixes.patch, build/patches/cairo-1-nanoserver-compat.patch
fribidi none
glib build/patches/glib-2-dllexport-static.patch, build/patches/glib-2-fixes.patch, build/patches/glib-2-without-gregex.patch, build/patches/glib-2-without-win32appinfo.patch
libexif none
libheif build/patches/libheif-1-fixes.patch
librsvg build/patches/librsvg-2-fixes.patch
libvips none
pango none
proxy-libintl build/plugins/proxy-libintl/patches/proxy-libintl-1-fixes.patch

Each list is the set of files that the pattern in the package definition matches in that repository: build/patches/<library>-[0-9]*.patch for the libraries in build/overrides.mk, build/libheif.mk and build/vips.mk, and patches/proxy-libintl-[0-9]*.patch next to build/plugins/proxy-libintl/proxy-libintl.mk. For the four libraries marked none the pattern matches no file. Two other patch files for these libraries do not apply to this DLL: build/plugins/ffi-compat/patches/glib-2-static.patch belongs to the --with-ffi-compat build, which has -ffi in the zip name, and build/plugins/all-deps/patches/vips-8-dlldir-as-libdir.patch belongs to the all build. The lists come from reading the build files at the commits, not from a build log.

The build recipe of each library is in the same files: build/overrides.mk (cairo, fribidi, glib, libexif, librsvg and pango), build/libheif.mk, build/vips.mk and build/plugins/proxy-libintl/proxy-libintl.mk. The checkout of build-win64-mxe at commit ef19ca09af2453d127453d677c849ccb37cf5694 contains all of them and all patch files, so the source archive of a library plus its patches is the source of that library in the shipped DLL. The statement about the mxe fork depends on the open mxe item above.

How it was built

libvips-packaging builds the tarball in its CI workflow (.github/workflows/ci.yml, platform win-x64) with this command at the repository root:

./build.sh win-x64

For win-x64, build.sh runs these two commands (its loop variable $flavour is win-x64):

docker build --pull -t vips-dev-win32 platforms/win32
docker run --rm -e "PLATFORM=win-x64" -v $PWD:/packaging vips-dev-win32 sh -c "/packaging/build/win.sh"

platforms/win32/Dockerfile defines the container:

FROM debian:trixie
RUN apt-get update && apt-get install -y curl zip

build/win.sh runs inside it with PLATFORM=win-x64. versions.properties sets VERSION_VIPS=8.18.7, so VERSION_VIPS_SHORT is 8.18. The script downloads the build-win64-mxe release zip and repackages it:

set -e

source /packaging/versions.properties

VERSION_VIPS_SHORT=${VERSION_VIPS%.[[:digit:]]*}

# Common options for curl
CURL="curl --silent --location --retry 3 --retry-max-time 30"

# Fetch and unzip
mkdir /vips
cd /vips

VARIANT=static

case "${PLATFORM#*-}" in
  x64) ARCH=x64 ;;
  x64.net462)
    ARCH=x64
    VARIANT=static-ffi
    ;;
  x86) ARCH=x86 ;;
  x86.net462)
    ARCH=x86
    VARIANT=static-ffi
    ;;
  arm64) ARCH=arm64 ;;
  arm64.net481)
    ARCH=arm64
    VARIANT=static-ffi
    ;;
esac

FILENAME="vips-dev-${ARCH}-web-${VERSION_VIPS}-${VARIANT}.zip"
URL="https://github.com/libvips/build-win64-mxe/releases/download/v${VERSION_VIPS}/${FILENAME}"
echo "Downloading $URL"
$CURL -O $URL
unzip $FILENAME

cd /vips/vips-dev-${VERSION_VIPS_SHORT}

# Move DLLs to the lib directory
cp bin/*.dll lib/

# Add third-party notices
$CURL -O https://raw.githubusercontent.com/kleisauke/libvips-packaging/main/THIRD-PARTY-NOTICES.md

# Create tarball
tar czf /packaging/libvips-${VERSION_VIPS}-${PLATFORM}.tar.gz \
  include \
  lib/glib-2.0 \
  lib/*.{dll,lib} \
  versions.json \
  THIRD-PARTY-NOTICES.md

# Allow tarballs to be read outside container
chmod 644 /packaging/libvips-${VERSION_VIPS}-${PLATFORM}.tar.gz

# Remove working directories
rm -rf lib include versions.json THIRD-PARTY-NOTICES.md

The release zip comes from build-win64-mxe, which publishes no build log, and its release notes contain no command. The asset name vips-dev-x64-web-8.18.7-static.zip and packaging/package-vips.sh show its options: dependency set web, target x86_64-w64-mingw32.static, mozjpeg, zlib-ng, no FFI compatibility, no HEVC, no debug build. The command that follows from them, run at the root of a build-win64-mxe checkout of commit ef19ca09af2453d127453d677c849ccb37cf5694, is:

./build.sh --target x86_64-w64-mingw32.static vips-web

This command is derived from the asset name and the build scripts. It is not copied from a log. vips-web is the default package. Adding --without-prebuilt builds mxe from the branch named above instead of pulling the prebuilt image. TO CONFIRM: the exact command line the maintainer ran for the published v8.18.7 release zip

With these options build.sh runs the following (values derived from its code: $oci_runtime is podman if installed and docker otherwise, $image is ghcr.io/libvips/build-win64-mxe:latest, $with_prebuilt is true, ${pkgs[*]} is vips-web, ${mxe_targets[*]} is x86_64-w64-mingw32.static, $with_debug, $with_ffi_compat and $with_hevc are false, $with_zlib_ng is true, $jpeg_impl is mozjpeg, $git_commit is empty and $plugin_dirs is plugins/llvm-mingw /data /data/plugins/mozjpeg /data/plugins/zlib-ng /data/plugins/web-deps /data/plugins/proxy-libintl):

$oci_runtime build \
  --pull=$with_prebuilt \
  -t libvips-build-win-mxe \
  -f container/Dockerfile \
  --build-arg BASE_IMAGE="$image" \
  --build-arg SOURCE_DATE_EPOCH="$(git log -1 --pretty=%ct)" \
  --build-arg PKGS="${pkgs[*]}" \
  --build-arg MXE_TARGETS="${mxe_targets[*]}" \
  --build-arg DEBUG="$with_debug" \
  --build-arg PLUGIN_DIRS="$plugin_dirs" \
  --build-arg GIT_COMMIT="$git_commit" \
  build
$oci_runtime run --rm -t \
  -v $PWD/packaging:/data/packaging \
  -e PKGS="${pkgs[*]}" \
  -e MXE_TARGETS="${mxe_targets[*]}" \
  -e FFI_COMPAT="$with_ffi_compat" \
  -e JPEG_IMPL="$jpeg_impl" \
  -e HEVC="$with_hevc" \
  -e DEBUG="$with_debug" \
  -e ZLIB_NG="$with_zlib_ng" \
  libvips-build-win-mxe

The first command copies build/ into the image as /data and runs this step of container/Dockerfile (PKGS, MXE_TARGETS, PLUGIN_DIRS and GIT_COMMIT are the build arguments above):

make gendef $PKGS \
  MXE_PLUGIN_DIRS="$PLUGIN_DIRS" \
  MXE_TARGETS="$MXE_TARGETS" \
  GIT_COMMIT=$GIT_COMMIT

The second command runs packaging/package.sh, which calls ./package-vips.sh web x86_64-w64-mingw32.static and writes the zip. build/vips.mk builds libvips itself as a shared library even for the static target, because the language bindings need libvips-42.dll. The options of the web build are in build/plugins/web-deps/overrides.mk.

Use a modified libvips

Settings > About in Pomelo shows this text.

Use a modified libvips

Pomelo loads libvips from vips\libvips-42.dll in its install folder. You can run Pomelo with your own build of that file, for example one made from the source and build commands on the libvips source page. Use a 64-bit libvips-42.dll of the same libvips version with the same libraries linked in, so that Pomelo's calls into it keep working.

1. Open Settings, search for "developer settings" and turn on Developer Mode.
2. Quit Pomelo from its tray icon.
3. In PowerShell, copy the installed app to a folder you own:
   $app = Get-AppxPackage -Name andrealo.Pomelo
   Copy-Item $app.InstallLocation "$env:USERPROFILE\Pomelo-modified" -Recurse
4. In the copy, delete AppxSignature.p7s, AppxBlockMap.xml and the AppxMetadata folder.
5. Replace vips\libvips-42.dll in the copy with your build.
6. Uninstall the installed Pomelo. This also deletes its settings and its free file counter:
   Get-AppxPackage -Name andrealo.Pomelo | Remove-AppxPackage
7. Register the copy:
   Add-AppxPackage -Register "$env:USERPROFILE\Pomelo-modified\AppxManifest.xml"
8. Start Pomelo from the Start menu.

To go back, run the command in step 6 again and install Pomelo from the Microsoft Store.