{"id":13778199,"url":"https://github.com/libvips/lua-vips","last_synced_at":"2025-06-23T07:10:23.902Z","repository":{"id":21297308,"uuid":"92176943","full_name":"libvips/lua-vips","owner":"libvips","description":"Lua binding for the libvips image processing library","archived":false,"fork":false,"pushed_at":"2025-02-09T11:52:28.000Z","size":15753,"stargazers_count":139,"open_issues_count":7,"forks_count":9,"subscribers_count":14,"default_branch":"master","last_synced_at":"2025-06-20T07:54:19.199Z","etag":null,"topics":["image-processing-library","libvips","lua","luajit","vips"],"latest_commit_sha":null,"homepage":null,"language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/libvips.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"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}},"created_at":"2017-05-23T13:35:37.000Z","updated_at":"2025-04-24T23:14:36.000Z","dependencies_parsed_at":"2024-03-13T22:38:41.685Z","dependency_job_id":"ff539f6d-f25e-4c71-b116-d92871427ac9","html_url":"https://github.com/libvips/lua-vips","commit_stats":{"total_commits":201,"total_committers":10,"mean_commits":20.1,"dds":"0.46766169154228854","last_synced_commit":"e33563e40445dc9f391b05dcd9d7ef547d3b45ea"},"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/libvips/lua-vips","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/libvips%2Flua-vips","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/libvips%2Flua-vips/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/libvips%2Flua-vips/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/libvips%2Flua-vips/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/libvips","download_url":"https://codeload.github.com/libvips/lua-vips/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/libvips%2Flua-vips/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260958957,"owners_count":23088809,"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","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":["image-processing-library","libvips","lua","luajit","vips"],"created_at":"2024-08-03T18:00:51.994Z","updated_at":"2025-06-23T07:10:18.887Z","avatar_url":"https://github.com/libvips.png","language":"Lua","readme":"# lua-vips\n\n[![CI](https://github.com/libvips/lua-vips/workflows/CI/badge.svg)](https://github.com/libvips/lua-vips/actions)\n\nThis is a Lua binding for the [libvips image processing\nlibrary](http://libvips.github.io/libvips).  `libvips`\nis a [fast image processing library with low memory needs](https://github.com/jcupitt/lua-vips-bench).\n`lua-vips` uses ffi and needs either\n- luajit \u003e= 2.0 or\n- standard Lua (5.1 up to 5.4) combined with the [`luaffi-tkl`](https://luarocks.org/modules/sudheerhebbale/luaffi-tkl) Lua package.\n\nOn the x64 architecture `lua-vips` is continuously tested\n- on Linux and MacOS with Lua 5.1, 5.2, 5.3, 5.4 and openresty-luajit\n- on Windows using [MSYS2 MinGW-w64](https://www.msys2.org/) with Lua 5.3, 5.4 and luajit\n\n`lua-vips`  should work on arm64 (recently tested on a Pinephone Pro using PostmarketOS) and possibly x86 (currently untested)\nas well.\n\nThe libvips documentation includes a handy searchable table of [every operation in\nlibvips](http://libvips.github.io/libvips/API/current/func-list.html). This\nis a good place to check if it supports some feature you need. Read on to\nsee how to call libvips operations.\n\n# Example\n\n[Install the libvips shared\nlibrary](https://libvips.github.io/libvips/install.html), then install this rock with:\n\t\n```shell\nluarocks install lua-vips\n```\n\nWhen used with LuaJIT please first exhibit luaffi-tkl as provided by the VM via:\n```shell\nluarocks config --lua-version=5.1 rocks_provided.luaffi-tkl 2.1-1\n```\n\nExample:\n\n```lua\nlocal vips = require \"vips\"\n\n-- fast thumbnail generator\nlocal image = vips.Image.thumbnail(\"somefile.jpg\", 128)\nimage:write_to_file(\"tiny.jpg\")\n\n-- make a new image with some text rendered on it\nimage = vips.Image.text(\"Hello \u003ci\u003eWorld!\u003c/i\u003e\", {dpi = 300})\n\n-- call a method\nimage = image:invert()\n\n-- use the `..` operator to join images bandwise\nimage = image .. image .. image\n\n-- add a constant\nimage = image + 12\n-- add a different value to each band\nimage = image + { 1, 2, 3 }\n-- add two images\nimage = image + image\n\n-- split bands up again\nb1, b2, b3 = image:bandsplit()\n\n-- read a pixel from coordinate (10, 20)\nr, g, b = image(10, 20)\n\n-- make all pixels less than 128 bright blue\n--    :less(128) makes an 8-bit image where each band is 255 (true) if that \n--        value is less than 128, and 0 (false) if it's \u003e= 128 ... you can use\n---       images or {1,2,3} constants as well as simple values\n--    :bandand() joins all image bands together with bitwise AND, so you get a\n--        one-band image which is true where all bands are true\n--    condition:ifthenelse(then, else) takes a condition image and uses true or\n--        false values to pick pixels from the then or else images ... then and\n--        else can be constants or images\nimage = image:less(128):bandand():ifthenelse({ 0, 0, 255 }, image)\n\n-- go to Yxy colourspace\nimage = image:colourspace(\"yxy\")\n\n-- pass options to a save operation\nimage:write_to_file(\"x.png\", { compression = 9 })\n```\n\n# How it works\n\nlibvips has quite a bit of introspection machinery built in. \n\nWhen you call something like `image:hough_circle{ scale = 4 }`, the `__index`\nmethod on the `lua-vips` image class opens libvips with ffi and searches\nfor an operation called `hough_circle`. It discovers what arguments the\noperation takes, checks you supplied the correct arguments, and transforms\nthem into the form that libvips needs. It executes the operator, then pulls\nout all the results and returns them as a Lua table.\n\nThis means that, although `lua-vips` supports almost 300 operators, the\nbinding itself is small, should be simple to maintain, and should always\nbe up to date.\n\n# Getting more help\n\nThe libvips website has a handy table of [all the libvips\noperators](http://libvips.github.io/libvips/API/current/func-list.html). Each\none links to the main API docs so you can see what you need to pass to it.\n\nA simple way to see the arguments for an operation is to try running it\nfrom the command-line. For example:\n\n```bash\n$ vips embed\nembed an image in a larger image\nusage:\n   embed in out x y width height\nwhere:\n   in           - Input image, input VipsImage\n   out          - Output image, output VipsImage\n   x            - Left edge of input in output, input gint\n\t\t\tdefault: 0\n\t\t\tmin: -1000000000, max: 1000000000\n   y            - Top edge of input in output, input gint\n\t\t\tdefault: 0\n\t\t\tmin: -1000000000, max: 1000000000\n   width        - Image width in pixels, input gint\n\t\t\tdefault: 1\n\t\t\tmin: 1, max: 1000000000\n   height       - Image height in pixels, input gint\n\t\t\tdefault: 1\n\t\t\tmin: 1, max: 1000000000\noptional arguments:\n   extend       - How to generate the extra pixels, input VipsExtend\n\t\t\tdefault: black\n\t\t\tallowed: black, copy, repeat, mirror, white, background\n   background   - Color for background pixels, input VipsArrayDouble\noperation flags: sequential \n```\n\nSo you can call `embed` like this:\n\n```lua\nlocal image = image:embed(100, 100, image:width() + 200, image:height() + 200,\n    { extend = \"mirror\" })\n```\n\nTo add a 100 pixel mirror edge around an image.\n\n# Features\n\nThis section runs through the main features of the binding. \n\nTo load the binding use:\n\n```lua\nlocal vips = require \"vips\"\n```\n\n## Make images\n\nYou can make images from files or from buffers (Lua strings), you can wrap\na vips image around an ffi array, or you can use one of the libvips create\noperators to make an image for you.\n\n### `image = vips.Image.new_from_file(filename [, options])`\n\nOpens the file and returns an image. You can pass a set of options in a final\ntable argument, for example:\n\n```lua\nlocal image = vips.Image.new_from_file(\"somefile.jpg\", \n   { access = \"sequential\" })\n```\n\nSome options are specific to some file types, for example, `shrink`, meaning\nshrink by an integer factor during load, only applies to images loaded via\nlibjpeg.\n\nYou can embed options in filenames using the standard libvips syntax. For\nexample, these are equivalent:\n\n```lua\nlocal image = vips.Image.new_from_file(\"somefile.jpg\", { shrink = 2 })\nlocal image = vips.Image.new_from_file(\"somefile.jpg[shrink=2]\")\n```\n\nYou can call specific file format loaders directly, for example:\n\n```lua\nlocal image = vips.Image.jpegload(\"somefile.jpg\", { shrink = 4 })\n```\n\nThe [loader section in the API\ndocs](http://libvips.github.io/libvips/API/current/VipsForeignSave.html) lists\nall loaders and their options. \n\n### `image = vips.Image.new_from_buffer(string [, string_options, options])`\n\nThe string argument should contain an image file in some container format, such\nas JPEG. You can supply options, just as with `new_from_file`. These are\nequivalent:\n\n```lua\nlocal image = vips.Image.new_from_buffer(string, \"\", { shrink = 2 })\nlocal image = vips.Image.new_from_buffer(string, \"shrink=2\")\n```\n\nUse (for example) `vips.Image.jpegload_buffer` to call a loader directly.\n\n### `image = vips.Image.new_from_memory(data, width, height, bands, format)`\n\nThis wraps a libvips image around a FFI memory array. The memory array should be\nformatted as a C-style array. Images are always band-interleaved, so an RGB\nimage three pixels across and two pixels down, for example, is laid out as:\n\n```\nRGBRGBRGB\nRGBRGBRGB\n```\n\nExample:\n\n```lua\nlocal width = 64\nlocal height = 32\nlocal data = ffi.new(\"unsigned char[?]\", width * height)\nlocal im = vips.Image.new_from_memory(data, width, height, 1, \"uchar\")\n```\n\nThe returned image is using a pointer to the `data` area, but the Lua/LuaJIT interpreter won't always know this. You should keep a reference to `data` alive for as long as you are using any downstream images, or you'll get a crash.\n\n### `image = vips.Image.new_from_memory_ptr(data, size, width, height, bands, format)`\n\nSame as `new_from_memory`, but for any kind of data pointer (non-FFI allocated) by specifying the length of the data in bytes. The pointed data must be valid for the lifespan of the image and any downstream images.\n\nA string can be used as the data pointer thanks to FFI semantics.\n\n### `image = vips.Image.new_from_image(image, pixel)`\n\nMakes a new image with the size, format, and resolution of `image`, but with\neach pixel having the value `pixel`. For example:\n\n```lua\nlocal new_image = vips.Image.new_from_image(image, 12)\n```\n\nWill make a new image with one band where every pixel has the value 12. You can\ncall it as a member function. `pixel` can be a table to make a many-band image,\nfor example:\n\n```lua\nlocal new_image = image:new_from_image{ 1, 2, 3 }\n```\n\nWill make a new three-band image, where all the red pixels have the value 1,\ngreens are 2 and blues are 3.\n\n### `image = vips.Image.new_from_array(array [, scale [, offset]])`\n\nMakes a new image from a Lua table. For example:\n\n```lua\nlocal image = vips.Image.new_from_array{ 1, 2, 3 }\n```\n\nMakes a one-band image, three pixels across and one high. Use nested tables for\n2D images. You can set a scale and offset with two extra number parameters --\nhandy for integer convolution masks.\n\n```lua\nlocal mask = vips.Image.new_from_array(\n    {{-1,  -1, -1}, \n     {-1,  16, -1}, \n     {-1,  -1, -1}}, 8)\nlocal image = image:conv(mask, { precision = \"integer\" })\n```\n\n### `image = vips.Image.copy_memory(self)`\n\nThe image is rendered to a large memory buffer, and a new image is returned\nwhich represents the memory area. \n\nThis is handy for breaking a pipeline.\n\n### `image = vips.Image.black(width, height)`\n\nMakes a new one band, 8 bit, black image. You can call any of the libvips image\ncreation operators in this way, for example:\n\n```lua\nlocal noise = vips.Image.perlin(256, 256, { cell_size = 128 })\n```\n\nSee:\n\n[http://libvips.github.io/libvips/API/current/libvips-create.html](http://libvips.github.io/libvips/API/current/libvips-create.html)\n\n## Get and set image metadata\n\nYou can read and write aribitrary image metadata. \n\n### `number = vips.Image.get_typeof(image, field_name)`\n\nThis returns the GType for a field, or 0 if the field does not exist.\n`vips.gvalue` has a set of GTypes you can check against. \n\n### `mixed = vips.Image.get(image, field_name)`\n\nThis reads any named piece of metadata from the image, for example:\n\n```lua\nlocal version = image:get(\"exif-ifd2-ExifVersion\")\n```\n\nThe item is converted to some Lua type in the obvious way. There are convenient\nshortcuts for many of the standard fields, so these are equivalent:\n\n```lua\nlocal width = image:get(\"width\")\nlocal width = image:width()\n```\n\nIf the field does not exist, `lua-vips` will throw an error. Use `get_typeof`\nto check for the existence of a field.\n\n### `vips.Image.set_type(image, gtype, field_name, value)`\n\nThis creates a new metadata item of the specified type, name and value. \n\n### `vips.Image.set(image, field_name, value)`\n\nThis changes the value of an existing field, but will not change its type.\n\nYou can't use `set()` to change core fields such as like `width` or\n`interpretation`.  Use `copy()` instead.\n\nImage references will be shared by the operation cache, so modifying an image\ncan change an image somewhere else in your program. Before changing an image,\nyou must make sure you own a private copy of an image with `copy`.\n\n```lua\nlocal new_image = image:copy()\nnew_image:set(\"orientation\", 7)\n```\n\n### `boolean = vips.Image.remove(image, field_name)`\n\nThis will remove a piece of metadata. It returns `true` if an item was\nsuccessfully removed, `false` otherwise. \n\nAs with `set`, you must use copy before removing a metadata item.\n\n## Call any libvips operation\n\nYou can call any libvips operation as a member function, for example\n`hough_circle`, the circular Hough transform:\n\n[http://libvips.github.io/libvips/API/current/libvips-arithmetic.html#vips-hough-circle](http://libvips.github.io/libvips/API/current/libvips-arithmetic.html#vips-hough-circle)\n\nCan be called from Lua like this:\n\n```lua\nlocal image2 = image:hough_circle{ scale = 2, max_radius = 50 }\n```\n\nThe rules are:\n\n1. `self` is used to set the first required input image argument.\n\n2. If you supply one more argument than the number of required arguments, \n   and the final argument you supply is a table, \n   that extra table is used to set any optional input arguments. \n\n3. If you supply a constant (a number, or a table of numbers) and libvips \n   wants an image, your constant is automatically turned into an image using\n   the first input image you supplied as a guide. \n\n4. For enums, you can supply a number or a string. The string is an enum member\n   nickname (the part after the final underscore).\n\n5. `MODIFY` arguments, for example the image you pass to `draw_circle`, are\n   copied to memory before being set, and the new image is returned as one of\n   the results. \n\n6. Operation results are returned as an unpacked array in the order: all\n   required output args, then all optional output args, then all deprecated\n   output args.\n\nYou can write (for example):\n\n```lua\nmax_value = image:max()\n```\n\nTo get the maximum value from an image. If you look at [the `max`\noperator](http://libvips.github.io/libvips/API/current/libvips-arithmetic.html#vips-max),\nit can actually return a lot more than this. You can write:\n\n```lua\nmax_value, x, y = image:max()\n```\n\nTo get the position of the maximum, or:\n\n```lua\nmax_value, x, y, maxes = image:max{ size = 10 }\n```\n\nand `maxes` will be an array of the top 10 maximum values in order. \n\n## Operator overloads\n\nThe Lua operators are overloaded in the obvious way, so you can write (for\nexample):\n\n```lua\nimage = (image * 2 + 13) % 4\n```\n\nand the appropriate vips operations will be called. You can mix images, number\nconstants, and array constants freely.\n\nThe relational operators are not overloaded, unfortunately; Lua does not\npermit this. You must write something like:\n\n```lua\nimage = image:less(128):ifthenelse(128, image)\n```\n\nto set all values less than 128 to 128.\n\n`__call` (ie. `()`) is overloaded to call the libvips `getpoint` operator. \nYou can write:\n\n```lua\nimage = vips.Image.new_from_file(\"k2.jpg\")\nr, g, b = image(10, 10)\n```\n\nand `r`, `g`, `b` will be the RGB values for the pixel at coordinate (10, 10).\n\n`..` is overloaded to mean `bandjoin`. \n\nUse `im:bands()` to get the number of bands and `im:extract_band(N)` to extract a\nband (note bands number from zero). lua-vips does not overload `#` and `[]` for\nthis, since mixing numbering from zero and one causes confusion. \n\n## Convenience functions\n\nA set of convenience functions are also defined.\n\n### `array\u003cimage\u003e = image:bandsplit()`\n\nThis splits a many-band image into an array of one band images.\n\n### `image:bandjoin()`\n\nThe `bandjoin` operator takes an array of images as input. This can be awkward\nto call --- you must write:\n\n\n```lua\nimage = vips.Image.bandjoin{ image, image }\n```\n\nto join an image to itself. Instead, `lua-vips` defines `bandjoin` as a member\nfunction, so you write:\n\n```lua\nimage = image:bandjoin(image)\n```\n\nto join an image to itself, or perhaps:\n\n```lua\nimage = R:bandjoin{ G, B }\n```\n\nto join three RGB bands. Constants work too, so you can write:\n\n```lua\nimage = image:bandjoin(255)\nimage = R:bandjoin{ 128, 23 }\n```\n\nThe `bandrank` and `composite` operators works in the same way. \n\n### `image = condition_image:ifthenelse(then_image, else_image [, options])`\n\nThis uses the condition image to pick pixels between then and else. Unlike all\nother operators, if you use a constant for `then_image` or `else_image`, they\nfirst match to each other, and only match to the condition image if both then\nand else are constants. \n\n### `image = image:sin()`\n\nMany vips arithmetic operators are implemented by larger operators which take\nan enum to set their action. For example, sine is implemented by the `math`\noperator, so you must write:\n\n```lua\nimage = image:math(\"sin\")\n```\n\nThis is annoying, so a set of convenience functions are defined to enable you\nto write:\n\n```lua\nimage = image:sin()\n```\n\nThere are about 40 of these. \n\n## Write\n\nYou can write images to files, to ffi arrays, or to formatted strings. \n\n### `image:write_to_file(filename [, options])`\n\nThe filename suffix is used to pick the save operator. Just as with \n`new_from_file`, not all options will be correct for all file\ntypes. You can call savers directly if you wish, for example:\n\n```lua\nimage:jpegsave(\"x.jpg\", { Q = 90 })\n```\n\n### `string = image:write_to_buffer(suffix [, options])`\n\nThe suffix is used to pick the saver that is used to generate the result, so\n`\".jpg\"` will make a JPEG-formatted string. Again, you can call the savers\ndirectly if you wish, perhaps:\n\n```lua\nlocal str = image:jpegsave_buffer{ Q = 90 }\n```\n\n### `memory = image:write_to_memory()`\n\nA large ffi char array is allocated and the image is rendered to it. \n\n```lua\nlocal mem = image:write_to_memory()\nprint(\"written \", ffi.sizeof(mem), \"bytes to\", mem)\n```\n\n### `ptr, size = image:write_to_memory_ptr()`\n\nAn allocated char array pointer (GCd with a `ffi.gc` callback) and the length in bytes of the image data is directly returned from libvips (no intermediate FFI allocation).\n\n## True Streaming\n\nWhen processing images an image library would usually read an image from a file into memory, decode and process it and finally write the encoded result into a file. The processing can only start when the image is fully read into memory and the writing can only start when the processing step is completed.\nLibvips can process images directly from a pipe and write directly to a pipe, without the need to read the whole image to memory before being able to start and without the need to finish processing before being able to start writing. This is achieved using a technique called true streaming. In this context there are sources and targets and the processing step happens from source to target. Sources can be created from files, memory or descriptors (like stdin) and targets can be created to files, memory or descriptors (like stdout). Here is an example:\n\n```lua test.lua\nlocal vips = require \"vips\"\nlocal stdin, stdout = 0, 1\nlocal source = vips.Source.new_from_descriptor(stdin)\nlocal target = vips.Target.new_to_descriptor(stdout)\nlocal image = vips.Image.new_from_source(source, '', { access = 'sequential' })\nimage = image:invert()\nimage:write_to_target(target, '.jpg')\n```\n\nRunning this script in a Unix terminal via \n```term\ncurl https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/600px-Cat03.jpg | lua test.lua \u003e out.jpg\n```\n\nwill feed a cat image from the internet into standard input, from which the Lua script reads and inverts it and writes it to standard output, where it is redirected to a file. This all happens simultaneously, so the processing and writing doesn't need to wait until the whole image is downloaded from the internet.\n\n## Error handling\n\nMost `lua-vips` methods will call `error()` if they detect an error. Use\n`pcall()` to call a method and catch an error. \n\nUse `get_typeof` to test for a field of a certain name without throwing an\nerror.\n\n## The libvips operation cache\n\nlibvips keeps a cache of recent operations, such as load, save, shrink, and\nso on. If you repeat an operation, you'll get the cached result back. \n\nIt keeps track of the number of open files, allocated memory and cached\noperations, and will trim the cache if more than 100 files are open at once,\nmore than 100mb of memory has been allocated, or more than 1,000 operations\nare being held.\n\nNormally this cache is useful and harmless, but for some applications you may \nwant to change these values.\n\n```lua\n-- set number of cached operations\nvips.cache_set_max(100)\n-- set maximum cache memory use\nvips.cache_set_max_mem(10 * 1024 * 1024)\n-- set maximum number of open files\nvips.cache_set_max_files(10)\n```\n\n# Development\n\n### Setup for Ubuntu\n\nConfigure `luarocks` for a local tree\n\n```shell\nluarocks help path\n```\n\nappend\n\n```shell\neval `luarocks path`\nexport PATH=\"$HOME/.luarocks/bin:$PATH\"\n```\n\nto `~/.bashrc`.\n\n### Install\n\n```shell\nluarocks --local make\n```\n\n### Unit testing\n\nYou need:\n\n```shell\nluarocks --local install busted \nluarocks --local install luacov\nluarocks --local install say\n```\n\nThen to run the test suite:\n\n```shell\nbusted . \n```\n\nfor verbose output:\n\n```shell\nbusted . -o gtest -v\n```\n\n### Linting and static analysis\n\nYou need:\n\n```shell\nluarocks --local install luacheck\n```\n\nThen to run the linter:\n\n```shell\nluacheck .\n```\n\n### Test\n\nRun the example script with:\n\n```shell\nlua example/hello-world.lua\n```\n\n### Update rock\n\n```shell\nrm *.src.rock\nluarocks upload lua-vips-1.1-12.rockspec --api-key=xxxxxxxxxxxxxx\n```\n\n### Links\n\nhttp://luajit.org/ext_ffi_api.html\n\nhttp://luajit.org/ext_ffi_semantics.html\n\nhttps://github.com/luarocks/luarocks/wiki/creating-a-rock\n\nhttps://olivinelabs.com/busted/\n\n### Running on Windows using Mingw-w64\n\nInstalling `lua-vips` on Windows is a bit harder than on Unix systems. We recommend using MinGW (Minimalist GNU for Windows) for the installation. Here are the steps:\n\n1. Install [MSYS2](https://www.msys2.org/) to the default path.\n2. Start Mingw-w64 64bit console from the start menu. Check that is says MINGW64. The following steps happen in that console.\n3. Update MSYS2 using\n   ```shell\n      pacman -Syuu\n   ```\n4. Install the build tools (including Lua 5.4 and Luarocks) via\n   ```shell\n      pacman -S git make mingw-w64-x86_64-toolchain mingw-w64-x86_64-lua-luarocks\n   ```\n5. Install `libvips` with (optional) dependencies via\n   ```shell\n      pacman -S\n         mingw-w64-x86_64-libvips\n         mingw-w64-x86_64-openslide\n         mingw-w64-x86_64-libheif\n         mingw-w64-x86_64-libjxl\n         mingw-w64-x86_64-imagemagick\n         mingw-w64-x86_64-poppler\n   ```\n6. Optionally: If you want to use `lua-vips` with LuaJIT instead of Lua 5.4 install LuaJIT via\n   ```shell\n      pacman -S mingw-w64-x86_64-luajit\n      luarocks config --scope system lua_version 5.1\n      luarocks config --scope system lua_interpreter luajit.exe\n      luarocks config --scope system variables.LUA_DIR /mingw64/bin\n      luarocks config --scope system variables.LUA_INCDIR /mingw64/include/luajit-2.1/\n      luarocks config --scope system rocks_provided.luaffi-tkl 2.1-1\n   ```\n7. Install `lua-vips` via\n   ```shell\n      luarocks install lua-vips\n   ```\n   or clone the repository and run `luarocks make` in the `lua-vips` folder.\n8.  Add `C:\\msys64\\mingw64\\bin` and `C:\\msys64\\usr\\bin` to the top of your `PATH`\n   environment variable in the Windows Advanced system settings and restart the console.\n\n9.  Run `lua` or `luajit` and try\n    ```lua\n    vips = require \"vips\"\n    print(vips.Image.xyz(3,2))\n    ```\n\n### Running under Wine (Windows emulation on Linux)\n\n@jcupitt used the luapower all-in-one to get a 64-bit Windows LuaJIT build:\n\nhttps://luapower.com/\n\nLuaJIT on Windows searches `PATH` to find DLLs. You can't set this directly\nfrom Linux, you have to change the registry. See:\n\nhttps://www.winehq.org/docs/wineusr-guide/environment-variables\n\nThen add the `bin` area of the libvips Windows build to `PATH`.\n\n```\nz:\\home\\john\\GIT\\build-win64\\8.5\\vips-dev-8.5\\bin\n```\n\nYou must have no trailing backslash.\n\nTry LuaJIT:\n\n```\n$ ~/packages/luajit/luapower-all-master/bin/mingw64/luajit.exe \nLuaJIT 2.1.0-beta2 -- Copyright (C) 2005-2016 Mike Pall.\nhttp://luajit.org/\nJIT: ON SSE2 SSE3 SSE4.1 fold cse dce fwd dse narrow loop abc sink fuse\n\u003e print(os.getenv(\"PATH\"))\nC:\\windows\\system32;C:\\windows;C:\\windows\\system32\\wbem;z:\\home\\john\\GIT\\build-win64\\8.5\\vips-dev-8.5\\bin\n\u003e ffi = require \"ffi\"\n\u003e ffi.load(\"libvips-42.dll\")\n\u003e ^D\n```\n\nThe Windows luajit will pick up your `.luarocks/share/lua/5.1/vips.lua` install,\nso to test just install and run:\n\n```\n$ ~/packages/luajit/luapower-all-master/bin/mingw64/luajit.exe\nLuaJIT 2.1.0-beta2 -- Copyright (C) 2005-2016 Mike Pall. http://luajit.org/\n  JIT: ON SSE2 SSE3 SSE4.1 fold cse dce fwd dse narrow loop abc sink fuse\n\u003e vips = require \"vips\"\n\u003e x = vips.Image.new_from_file(\"z:\\\\data\\\\john\\\\pics\\\\k2.jpg\")\n\u003e print(x:width())\n1450\n\u003e x = vips.Image.text(\"hello\", {dpi = 300})\n\u003e x:write_to_file(\"x.png\")\n\u003e \n```\n\n","funding_links":[],"categories":["Libraries"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flibvips%2Flua-vips","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flibvips%2Flua-vips","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flibvips%2Flua-vips/lists"}