{"id":15567023,"url":"https://github.com/lopcode/vips-ffm","last_synced_at":"2025-07-29T08:08:20.560Z","repository":{"id":251744762,"uuid":"838313812","full_name":"lopcode/vips-ffm","owner":"lopcode","description":"Fast, safe, complete libvips bindings for image processing in Java / JVM projects","archived":false,"fork":false,"pushed_at":"2025-07-19T18:24:53.000Z","size":13210,"stargazers_count":69,"open_issues_count":3,"forks_count":6,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-07-19T21:45:18.597Z","etag":null,"topics":["class-file","ffm","image-processing","java","jep-454","jep-457","kotlin","libvips","photo-fox","vips"],"latest_commit_sha":null,"homepage":"http://vipsffm.photofox.app/","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lopcode.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":["lopcode"]}},"created_at":"2024-08-05T11:44:32.000Z","updated_at":"2025-07-19T18:40:03.000Z","dependencies_parsed_at":"2024-12-20T13:34:48.107Z","dependency_job_id":"ca906c49-7667-4bff-9dff-1070ed205705","html_url":"https://github.com/lopcode/vips-ffm","commit_stats":{"total_commits":83,"total_committers":2,"mean_commits":41.5,"dds":0.02409638554216864,"last_synced_commit":"d3b13a215f12de3c4201142b82aa7cc94ce4fb66"},"previous_names":["lopcode/im-ffm","lopcode/vips-ffm"],"tags_count":43,"template":false,"template_full_name":null,"purl":"pkg:github/lopcode/vips-ffm","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lopcode%2Fvips-ffm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lopcode%2Fvips-ffm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lopcode%2Fvips-ffm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lopcode%2Fvips-ffm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lopcode","download_url":"https://codeload.github.com/lopcode/vips-ffm/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lopcode%2Fvips-ffm/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267652763,"owners_count":24122097,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-29T02:00:12.549Z","response_time":2574,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["class-file","ffm","image-processing","java","jep-454","jep-457","kotlin","libvips","photo-fox","vips"],"created_at":"2024-10-02T17:09:42.754Z","updated_at":"2025-07-29T08:08:20.551Z","avatar_url":"https://github.com/lopcode.png","language":"Java","readme":"# vips-ffm\n\nFast, safe, complete [libvips](https://github.com/libvips/libvips) bindings for image processing in Java / JVM projects.\n\nSupports a vast range of image formats, including HEIC, JXL, WebP, PNG, JPEG, and more. Pronounced \"vips (like zips)\neff-eff-emm\". The project is relatively new, but aims to be production ready. Tested on macOS 14, Windows 11, and Linux\n(Ubuntu 24.04, Debian 12.1, with and without jemalloc). Should work on any architecture you can use libvips and\nJava on (arm64/amd64/etc).\n\nUses the \"Foreign Function \u0026 Memory API\" ([JEP 454](https://openjdk.org/jeps/454)), and the \"Class-File API\" ([JEP 457](https://openjdk.org/jeps/457)) released in JDK 22.\nBuilt in such a way that it's usually the fastest image processing library available for Java.\n\nUsed the library? I'd love to hear from more users - let me know in [Discussions](https://github.com/lopcode/vips-ffm/discussions). Please also give [the repo](https://github.com/lopcode/vips-ffm)\na star 🌟️!\n\n## Usage\n\n`vips-ffm` is available on Maven Central. To get set up with Gradle:\n\n```kotlin\nrepositories {\n    mavenCentral()\n}\n\ndependencies {\n    implementation(\"app.photofox.vips-ffm:vips-ffm-core:1.8.0\")\n}\n```\n\nFigure out what you're trying to do by looking at the [libvips documentation](https://www.libvips.org/API/current/)\nfirst, then use it through one of the helper classes (for example, [VImage](https://vipsffm.photofox.app/app.photofox.vipsffm/app/photofox/vipsffm/VImage.html)).\nThere are also lots of examples in the [samples](#samples).\n\nYou must add `--enable-native-access=ALL-UNNAMED` to your JVM runtime arguments. If you don't, you'll get a warning\nabout \"Restricted methods\". In the future, the JVM will throw an error if you don't explicitly include this flag.\n\nAs the project uses the Java FFM API, and Markdown comments, your target must also be JDK 23+. Bindings are currently\ngenerated from libvips `8.17.0` (but should be safe to use with different minor or patch versions).\n\n\u003e [!NOTE]\n\u003e This library **does not** include `libvips` in the download, you must add it to the system/container you're building\n\u003e for. See details in [native library loading](#native-library-loading).\n\n### Thumbnail sample\n\nTo get a feeling for the bindings, here's an indicative sample written in Kotlin (using the Java bindings) that:\n* Loads an original JPEG image from disk\n* Writes a copy of it to disk\n* Creates a 400px thumbnail from the original, and writes that to disk\n\n```kotlin\nimport app.photofox.vipsffm.Vips\nimport app.photofox.vipsffm.VImage\nimport app.photofox.vipsffm.VipsOption\nimport app.photofox.vipsffm.enums.VipsAccess\n\n// ...\n\n// Call once to initialise libvips when your program starts, from any thread\n//   Note that by default this blocks untrusted operations (like loading PDFs)\n//   See the \"Allowing untrusted operations\" section below to read about permitting untrusted operations\nVips.init()\n\n// Use `Vips.run` to wrap your usage of the API, and get an arena with an appropriate lifetime to use\n// Usage of the API, arena, and resulting V-Objects must be done from the thread that called `Vips.run`\nVips.run { arena -\u003e\n    val sourceImage = VImage.newFromFile(\n      arena,\n      \"sample/src/main/resources/sample_images/rabbit.jpg\"\n    )\n    val sourceWidth = sourceImage.width\n    val sourceHeight = sourceImage.height\n    logger.info(\"source image size: $sourceWidth x $sourceHeight\")\n\n    val outputPath = workingDirectory.resolve(\"rabbit_copy.jpg\")\n    sourceImage.writeToFile(outputPath.absolutePathString())\n\n    val thumbnail = sourceImage.thumbnailImage(\n      400,\n      VipsOption.Boolean(\"auto-rotate\", true) // example of an option\n    )\n    val thumbnailWidth = thumbnail.width\n    val thumbnailHeight = thumbnail.height\n    logger.info(\"thumbnail image size: $thumbnailWidth x $thumbnailHeight\")\n}\n\n// Optionally call at the end of your program, for memory leak detection, from any thread\nVips.shutdown()\n```\n\n## Samples\n\nSamples are included that show various usages of these bindings. They include validations, and run on GitHub Actions as\n\"end-to-end tests\" during development. You can find them all listed [here](https://github.com/lopcode/vips-ffm/tree/main/sample/src/main/kotlin/vipsffm/sample).\n\nTo get set up to run samples (on macOS):\n* `brew install vips`\n* `sdk use java 23-open`\n* Then either:\n  * Run `./run_samples.sh` in your terminal\n  * Use the included `Run samples` profile in IntelliJ\n\n```\n[main] INFO vipsffm.SampleRunner - clearing sample run directory at path \"sample_run\"\n[main] INFO vipsffm.SampleRunner - running sample \"RawGetVersionSample\"...\n[main] INFO vipsffm.sample.RawGetVersionSample - libvips version: \"8.15.5\"\n[main] INFO vipsffm.SampleRunner - validation succeeded ✅\n[main] INFO vipsffm.SampleRunner - running sample \"HelperGetVersionSample\"...\n[main] INFO vipsffm.sample.HelperGetVersionSample - libvips version: \"8.15.5\"\n[main] INFO vipsffm.SampleRunner - validation succeeded ✅\n[main] INFO vipsffm.SampleRunner - running sample \"VImageCreateThumbnailSample\"...\n[main] INFO vipsffm.sample.VImageCreateThumbnailSample - source image size: 2490 x 3084\n[main] INFO vipsffm.sample.VImageCreateThumbnailSample - thumbnail image size: 323 x 400\n[main] INFO vipsffm.SampleRunner - validation succeeded ✅\n[main] INFO vipsffm.SampleRunner - running sample \"VImageChainSample\"...\n[main] INFO vipsffm.SampleRunner - validation succeeded ✅\n[main] INFO vipsffm.SampleRunner - running sample \"VSourceTargetSample\"...\n[main] INFO vipsffm.SampleRunner - validation succeeded ✅\n[main] INFO vipsffm.SampleRunner - running sample \"VImageCopyWriteSample\"...\n[main] INFO vipsffm.SampleRunner - validation succeeded ✅\n[main] INFO vipsffm.SampleRunner - running sample \"VOptionHyphenSample\"...\n[main] INFO vipsffm.SampleRunner - validation succeeded ✅\n[main] INFO vipsffm.SampleRunner - running sample \"VImageCachingSample\"...\n[main] INFO vipsffm.SampleRunner - validation succeeded ✅\n[main] INFO vipsffm.SampleRunner - running sample \"VImageBlobSample\"...\n[main] INFO vipsffm.SampleRunner - validation succeeded ✅\n[main] INFO vipsffm.SampleRunner - running sample \"VImageArrayJoinSample\"...\n[main] INFO vipsffm.SampleRunner - validation succeeded ✅\n[main] INFO vipsffm.SampleRunner - running sample \"VBlobByteBufferSample\"...\n[main] INFO vipsffm.SampleRunner - validation succeeded ✅\n[main] INFO vipsffm.SampleRunner - running sample \"VTargetToFileSample\"...\n[main] INFO vipsffm.SampleRunner - validation succeeded ✅\n[main] INFO vipsffm.SampleRunner - running sample \"VImageJoinSample\"...\n[main] INFO vipsffm.SampleRunner - validation succeeded ✅\n[main] INFO vipsffm.SampleRunner - running sample \"VImageFromBytesSample\"...\n[main] INFO vipsffm.SampleRunner - validation succeeded ✅\n[main] INFO vipsffm.SampleRunner - running sample \"VImageStreamSample\"...\n[main] INFO vipsffm.SampleRunner - validation succeeded ✅\n[main] INFO vipsffm.SampleRunner - shutting down vips to check for memory leaks...\nmemory: high-water mark 151.24 MB\n[main] INFO vipsffm.SampleRunner - all samples ran successfully 🎉\n```\n\n### Detailed usage\n\nMost operations **do not** use the C API directly (as described in the [bindings docs](https://www.libvips.org/API/current/binding.html)) - they\nshould be safe to use with different libvips versions, assuming there haven't been major changes.\n\nAll libvips operations are exposed via helper classes, like `VImage`. You must provide an [Arena][1] to operations like\n`VImage.newFromFile`, which constrains the lifetime of objects generated during usage. You can get an appropriate arena\nby using `Vips.run` as shown in the [sample](#thumbnail-sample) below. `VImage` and associated enums have extensive\nJavadocs included, which are automatically generated from the same source that the libvips website uses, for ease of use.\nThese helper objects expose their raw pointers as a last resort via functions like `VTarget.getUnsafeStructAddress` - if\nyou need to use these raw pointers and can't find an alternative, please file a GitHub Issue.\n\nHelper enums are generated for the version of libvips shown above. If you need to use an enum from another version,\nwhich isn't present in `vips-ffm`, you can use `VipsOption.Enum(rawValue)` or `VEnum.Raw(rawValue)`.\n\n\u003e [!CAUTION]\n\u003e Bindings generated by `jextract` are available in `VipsRaw`, and wrapped with validation in `VipsHelper`. These\n\u003e functions are difficult to use without accidentally causing memory leaks, or even segfaults! If what you want to do is\n\u003e available in `VImage` and other `V`-prefixed classes, use those instead. If you notice something missing, please open\n\u003e a GitHub Issue.\n\n### Docker checks\n\nThese samples are also run in Docker containers, to verify behaviour on specific Linux distributions. They're useful to\nlook at if you're deploying `libvips` and `vips-ffm` workloads using containers.\n\nYou can find them in the [`docker_tests`](docker_tests) folder.\n\n## Native library loading\n\nThis library requires the `libvips`, `glib`, and `gobject` native libraries to be present in your library path:\n* On macOS: `DYLD_LIBRARY_PATH` (installed with `brew install vips`)\n* On Linux: `LD_LIBRARY_PATH` (installed with `apt install libvips-dev` on Debian / Ubuntu)\n* On Windows: `PATH`\n\nThe naming conventions of these libraries are not consistent across operating systems, so vips-ffm attempts to load each\nin the following order:\n* `vips`, `vips.{abiNumber}`, `libvips-{abiNumber}` \n* `glib-2.0`, `glib-2.0.{abiNumber}`, `libglib-2.0-{abiNumber}`\n* `gobject-2.0`, `gobject-2.0.{abiNumber}`, `libgobject-2.0-{abiNumber}`\n\nOverride properties are provided to set your own \"ABI number\", but note that vips-ffm might not support that version\nyet (which could manifest as crashes/segfaults):\n* `vipsffm.abinumber.vips.override`, default: `42`\n* `vipsffm.abinumber.glib.override`, default: `0`\n* `vipsffm.abinumber.gobject.override`, default: `0`\n\nIf you want to manually override the library lookup path for any of the above (for example, if you're using a platform\nlike Android where it's hard to set the system library path), you can do so using these system properties:\n* libvips: `vipsffm.libpath.vips.override` (eg `/opt/homebrew/lib/libvips.dylib`)\n* glib: `vipsffm.libpath.glib.override`\n* gobject: `vipsffm.libpath.gobject.override`\n\n## Operationalisation\n\nlibvips maintain [a checklist](https://www.libvips.org/API/8.17/developer-checklist.html) of things to be aware of when\nusing the library. Of particular note for vips-ffm is memory usage - especially if the library is used for long-running\napplication (like a server).\n\n### Operation cache\n\nAt the time of writing, libvips maintains a cache of the 100 most recent operations ([see docs](https://www.libvips.org/API/8.17/how-it-works.html#operation-cache)).\nIf running an image proxy, or something that processes lots of different images, you won't see any benefit, and can\ndisable it:\n\n```java\nVips.init();\nVips.disableOperationCache();\n```\n\n### Memory allocation\n\nOn glibc-based Linux systems (e.g. Debian, Red Hat), the default memory allocator performs poorly for long-running,\nmultithreaded processes with frequent small allocations. Using an alternative allocator like jemalloc can reduce the\noff-heap footprint of the JVM when using libvips.\n\nNote that the jemalloc project is going through [some turbulence](https://jasone.github.io/2025/06/12/jemalloc-postmortem/)\nat the moment. Facebook have [forked it](https://github.com/facebook/jemalloc), though its maintenance status is\ncurrently unknown.\n\nAn example of using jemalloc on Ubuntu:\n1. Install jemalloc\n   ```sh\n   apt install libjemalloc2\n   ```\n2. Set the `LD_PRELOAD` environment variable before running your application.\n   ```sh\n   ln -sT \"$(readlink -e /usr/lib/*/libjemalloc.so.2)\" /usr/local/lib/libjemalloc.so # symlink jemalloc to a standard location\n   export LD_PRELOAD=/usr/local/lib/libjemalloc.so\n   java -jar ...\n   ```\n\n### Allowing untrusted operations\n\nBy default, vips-ffm sets the \"block untrusted operations\" flag in libvips, in an attempt to be \"secure by default\".\nThis includes blocking things like the imagemagick and PDF loaders. If you get an error relating to \"operation is\nblocked\", then the operation you're trying to use is marked as untrusted in libvips.\n\nIf you need to work with operations and formats that are marked as \"untrusted\" in libvips, you can permit them\nexplicitly:\n```java\nVips.allowUntrustedOperations();\n```\n\nSee the [libvips docs](https://www.libvips.org/API/8.17/func.block_untrusted_set.html) for guidance on figuring out what\nloaders and operations are marked as trusted or untrusted.\n\n## Project goals\n\nIdeas and suggestions are welcome, but please make sure they fit in to these goals, or you have a good argument about\nwhy a goal should change!\n\n* Avoid manual work by automating as much as possible. This means upstream changes can be rapidly integrated.\n* Use the libvips operations API, as described in the [libvips documentation](https://www.libvips.org/API/current/binding.html)\n* Provide access to the raw bindings (`VipsHelper`), so users aren't blocked by helper bugs or API annoyances.\n* Incubate in [Photo Fox](https://github.com/lopcode/photo-fox) with some \"real world\" usage.\n\n## Contributing\n\nPlease see the contributing guidelines: [CONTRIBUTING.md](CONTRIBUTING.md).\n\nSome great non-code ways to help the project:\n\n* Use the library and give your feedback in [Discussions](https://github.com/lopcode/vips-ffm/discussions)\n  * Or [file an issue](https://github.com/lopcode/vips-ffm/issues) if you have a problem!\n* Share the [announcement post](https://www.lopcode.com/posts/2024/10/vips-ffm-1/) in your circles\n* Star the repo 🌟\n\nThank you for being enthusiastic about the project!\n\n## Releasing\n\n* GitHub Releases automatically result in a deployment to GitHub Packages\n* Maven Central releases happen manually \n  * This can only be done by @lopcode\n  * And only after a GitHub Release is made\n  * Run `./publish_release_to_maven_central.sh \u003cversion matching github release version, including v prefix\u003e` \n\n[1]: https://docs.oracle.com/en/java/javase/23/core/memory-segments-and-arenas.html\n","funding_links":["https://github.com/sponsors/lopcode"],"categories":["Projects","Recently Updated"],"sub_categories":["Imagery","[Mar 08, 2025](/content/2025/03/08/README.md)"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flopcode%2Fvips-ffm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flopcode%2Fvips-ffm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flopcode%2Fvips-ffm/lists"}