A fast image processing library with low memory needs.

libvips : an image processing library

CI Fuzzing Status Coverity Status Gitter

Introduction

libvips is a demand-driven, horizontally threaded image processing library. Compared to similar libraries, libvips runs quickly and uses little memory. libvips is licensed under the LGPL 2.1+.

It has around 300 operations covering arithmetic, histograms, convolution, morphological operations, frequency filtering, colour, resampling, statistics and others. It supports a large range of numeric types, from 8-bit int to 128-bit complex. Images can have any number of bands. It supports a good range of image formats, including JPEG, JPEG2000, TIFF, PNG, WebP, HEIC, AVIF, FITS, Matlab, OpenEXR, PDF, SVG, HDR, PPM / PGM / PFM, CSV, GIF, Analyze, NIfTI, DeepZoom, and OpenSlide. It can also load images via ImageMagick or GraphicsMagick, letting it work with formats like DICOM.

It comes with bindings for C, C++, and the command-line. Full bindings are available for Ruby, Python, PHP, C# / .NET, Go, and Lua. libvips is used as an image processing engine by sharp (on node.js), bimg, sharp for Go, Ruby on Rails, carrierwave-vips, mediawiki, PhotoFlow and others. The official libvips GUI is nip2, a strange combination of a spreadsheet and an photo editor.

Install

There are packages for most Unix-like operating systems, including macOS. Check your package manager.

There are binaries for Windows in releases.

The libvips website has detailed install notes.

Building libvips from a source tarball

We keep pre-baked tarballs in releases.

Untar, then in the libvips directory you should just be able to do:

./configure

Check the summary at the end of configure carefully. libvips must have build-essential, pkg-config, libglib2.0-dev, libexpat1-dev.

You'll need the dev packages for the file format support you want. For basic jpeg and tiff support, you'll need libtiff5-dev, libjpeg-turbo8-dev, and libgsf-1-dev. See the Dependencies section below for a full list of the things that libvips can be configured to use.

Once configure is looking OK, compile and install with the usual:

make
sudo make install

By default this will install files to /usr/local.

Testing

Run the test suite with:

make check

Run a specific test with:

pytest test/test-suite/test_foreign.py -k test_tiff

Building libvips from git

Clone the latest sources with:

git clone git://github.com/libvips/libvips.git

Building from git needs more packages -- you'll need at least gtk-doc and gobject-introspection, see the dependencies section below. For example:

brew install gtk-doc 

Then generate the build system with:

./autogen.sh --prefix=/home/john/vips

Debug build:

CFLAGS="-g -Wall" CXXFLAGS="-g -Wall" \
  ./configure --prefix=/home/john/vips --enable-debug
make
make install

Built-in loaders

libvips has a number of built-in loaders and savers. You can disable these if you wish, for example:

./configure --prefix=/Users/john/vips --without-nsgif --without-ppm

Dependencies

libvips has to have libglib2.0-dev and libexpat1-dev. Other dependencies are optional.

Optional dependencies

If suitable versions are found, libvips will add support for the following libraries automatically. See ./configure --help for a set of flags to control library detection. Packages are generally found with pkg-config, so make sure that is working.

Libraries like nifti do not use pkg-config so libvips will also look for them in the default path and in $prefix. If you have installed your own versions of these libraries in a different location, libvips will not see them. Use switches to libvips configure like:

./configure --prefix=/Users/john/vips \
  --with-nifti-includes=/opt/local/include \
  --with-nifti-libraries=/opt/local/lib 

or perhaps:

CFLAGS="-g -Wall -I/opt/local/include -L/opt/local/lib" \
  CXXFLAGS="-g -Wall -I/opt/local/include -L/opt/local/lib" \
  ./configure --prefix=/Users/john/vips 

libjpeg

The IJG JPEG library. Use the -turbo version if you can.

libexif

If available, libvips adds support for EXIF metadata in JPEG files.

librsvg

The usual SVG loader. If this is not present, vips will try to load SVGs via imagemagick instead.

PDFium

If present, libvips will attempt to load PDFs with PDFium. Download the prebuilt pdfium binary from:

https://github.com/bblanchon/pdfium-binaries

Untar to the libvips install prefix, for example:

cd ~/vips
tar xf ~/pdfium-linux.tgz

Create a pdfium.pc like this (update the version number):

VIPSHOME=/home/john/vips
cat > $VIPSHOME/lib/pkgconfig/pdfium.pc << EOF
     prefix=$VIPSHOME
     exec_prefix=\${prefix}
     libdir=\${exec_prefix}/lib
     includedir=\${prefix}/include
     Name: pdfium
     Description: pdfium
     Version: 4290
     Requires:
     Libs: -L\${libdir} -lpdfium
     Cflags: -I\${includedir}
EOF

If PDFium is not detected, libvips will look for poppler-glib instead.

poppler-glib

The Poppler PDF renderer, with a glib API. If this is not present, vips will try to load PDFs via imagemagick.

libgsf-1

If available, libvips adds support for creating image pyramids with dzsave.

libtiff

The TIFF library. It needs to be built with support for JPEG and ZIP compression. 3.4b037 and later are known to be OK.

fftw3

If libvips finds this library, it uses it for fourier transforms.

lcms2

If present, vips_icc_import(), vips_icc_export() and vips_icc_transform() can be used to manipulate images with ICC profiles.

libspng

If present, libvips will load PNG files using libspng. At the moment, libpng is still necessary for save.

libpng

If libspng is not present and libpng is, libvips will load PNG files with libpng. It will always save PNG files with libpng.

libimagequant

If present, libvips can write 8-bit palette-ised PNGs.

ImageMagick, or optionally GraphicsMagick

If available, libvips adds support for loading all libMagick-supported image file types. Use --with-magickpackage=GraphicsMagick to build against graphicsmagick instead.

Imagemagick 6.9+ needs to have been built with --with-modules. Most packaged IMs are, I think.

If you are going to be using libvips with untrusted images, perhaps in a web server, for example, you should consider the security implications of enabling a package with such a large attack surface.

pangoft2

If available, libvips adds support for text rendering. You need the package pangoft2 in pkg-config --list-all.

orc-0.4

If available, vips will accelerate some operations with this run-time compiler.

matio

If available, vips can load images from Matlab save files.

cfitsio

If available, vips can load FITS images.

libwebp

If available, vips can load and save WebP images.

libniftiio

If available, vips can load and save NIfTI images.

OpenEXR

If available, libvips will directly read (but not write, sadly) OpenEXR images.

OpenJPEG

If available, libvips will read and write JPEG2000 images.

OpenSlide

If available, libvips can load OpenSlide-supported virtual slide files: Aperio, Hamamatsu, Leica, MIRAX, Sakura, Trestle, and Ventana.

libheif

If available, libvips can load and save HEIC and AVIF images. Your libheif (in turn) needs to be built with the correct decoders and encoders. You can check with eg.:

$ pkg-config libheif --print-variables
builtin_avif_decoder
builtin_avif_encoder
builtin_h265_decoder
builtin_h265_encoder
exec_prefix
includedir
libdir
pcfiledir
prefix

Contributors

Code Contributors

This project exists thanks to all the people who contribute.

Organizations

Support this project with your organization. Your logo will show up here with a link to your website.

Owner
libvips
A fast image processing library with low memory needs.
libvips
Comments
  • off by one problem when generating pyramidal tiff

    off by one problem when generating pyramidal tiff

    Original issue noted here: https://github.com/ruven/iipsrv/issues/98 but copied below since this is really a vips issue, not an IIP issue.

    I have confirmed that there is an ongoing resize bug in vips that is reproducible on the latest up-to-date RHEL6 and RHEL7 systems using either vips 7.x or the latest 8.4 version of vips. See the differences between the images below which were taken from the pyramidal tiff. The first was created using imagemagick and the second with vips 8.4.5 on RHEL7. Aside from being slower, we had found a few years back that IM creates intermittent corrupted ptifs that IIP can't open. I think the only option is to find the bug in vips or the library it's using and fix it - or switch to IM if the PTIF generation has been fixed since we last looked at it about 4 or 5 years ago. Any advice appreciated.

    One of the resolutions from an ImageMagick generated pyramidal tiff image image

    and same resolution from vips generated pyramidal tiff (note flatness on right side and bottom) image image

    command used to generate the ptif: vips im_vips2tiff ./source_tiff_file.tif vips_regen_8.4.5_rhel7.ptif:jpeg:90,tile:256x256,pyramid

    info about the original TIFF source: TIFF 11038x11038 11038x11038+0+0 8-bit DirectClass 365.5MB

    command used to generate the output above

    convert vips_regen_8.4.5_rhel7.ptif -quality 100 vips_regen_8.4.5_rhel7.jpg

    This produces one jpg for each of the 6 or 7 resolutions that vips generates in the ptif. All of the exported jpegs from a ptif generated by vips exhibit this problem whereas none of the exported jpgs generated with imagemagick do.

  • Tutorial for common image adjustments?

    Tutorial for common image adjustments?

    I'm new to libvips and want to perform common image corrections like the adjustment of white balance, hue, brightness or tonal range. Are there tutorials/documentations covering these adjustments? I'm also interested in applying filters like gaussian blur etc. with libvips

  • Join multiple images?

    Join multiple images?

    Hi i have a folder with these images: image_1.png, image_2.png, image_3.png. Its possible to join all this images togheter horizontaly? I found vips join, but that can only merge 2 images.

    In ImageMagick i would do: convert +append image_*.png output.png

    Thanks.

  • Final steps to 8.9.0

    Final steps to 8.9.0

    Let's get 8.9.0 out of the door now that streams are merged.

    This issue is for tracking the final checks before release.

    • [x] test win builds
    • [x] test macos
    • [x] write a "what's new" post
    • [x] test ruby-vips
    • [x] test pyvips
    • [x] test php-vips
    • [x] test lua-vips
    • [x] clear out PRs
    • [x] clear out bug issues
    • [x] add a thing to make old-style file and buffer loaders usable from the stream API
    • [x] benchmark
    • [x] out of order read in tiffload?
    • [x] decide: should we revert sharpen behaviour?
    • [x] update API docs

    @lovell and @kleisauke, do you have any things you'd like to add for 8.9?

  • conda installation

    conda installation

    Hello,

    I have seen this conda package for libvips: https://anaconda.org/zegami/libvips

    However, it has some limitations (e.g. openslide is not included).

    Is there anyone trying to build a conda package for libvips, and make it available either through conda-forge or bioconda?

    Best regards, Sebastian

  • Some newbie questions on how to do things with libvips

    Some newbie questions on how to do things with libvips

    Background: I have a Rust web server that do some image processing using OpenCV and I want to switch to libvips mostly because of performance.

    Lately I've been trying to write bindings for the libvips C library for rust and I'd like to start with the things I have to support in my application, which are decoding images from any known format, resizing, rotating, watermarking and encoding to jpeg or webp.

    I've been reading the docs and I've got a good idea on how the library works, but still got a couple doubts. Please bear in mind that I'm not a very experienced C programmer. I have some experience with C++, but still it's been almost 10 years since last time I used it.

    Here it goes:

    1. For the functions that take varargs options (the option named parameters), how do I specify them? Are them strings and should be specified like the options in the read from file options where you can just pass in the file name the options like this file.jpeg[shrink=2]? So should I specify a list with of option=value as strings (const *char)? Still about this options, how should I specify the ones that are enums?

    2. What are the types for the PNG options in the save function? https://libvips.github.io/libvips/API/current/VipsForeignSave.html#vips-pngsave Is there a place where I can find the defaults for the various options when encoding and decoding images?

    3. One of the features I have to support envolves removing the alpha channel of images when encoding to JPEG. I know it works out of the box, but I want a different behavior. The default way, it transform the transparent pixels to black, which makes sense, since 0 = transparent = black. How can I invert the alpha channel in a image with libvips to get the opposite result (the fully transparent pixels getting white instead of black)?

    4. About the error handling... How should I proceed? Should I have a background thread consuming and clearing the error buffer from time to time? If so how would it be a reasonable time to do it without degrading the performance of my application (because of the locks)...

    5. Still about error handling, if I call vips_error_freeze, the buffer will never be filled, meaning I never have to care clearing it, right?

    6. For watermarking I found out I should use the vips_composite2 function with the VIPS_BLEND_MODE_OVERLAY mode, but how can I set an opacity for the overlay image?

    Thank you in advance.

  • Process

    Process "Killed" using Python Vips8

    I run a program that stitches images together to an overview using merge() and join(), performs some operations on the overview image, and writes the resulting image to disk in form of a zoomify pyramid using dzsave().

    Individual images exists on disk as PNG files with a size of 3.5 to 6MB per file. The program works fine with small overviews, i.e. small number of images, but fails with a large number of images (about 10000 files).

    The program get's killed with exitcode 137 (128+9) after the stitching as soon as a function is applied to the resulting Vips.Image object.

    The error message is not very informative, it just says Killed.

    This is the tail of the DEBUG log output:

    2015-12-08 16:05:27 | gi.overrides.Vips              | DEBUG    | _call_base self=<Image object at 0x7f1f0ea0dc80 (VipsImage at 0xe9e687e0)>
    2015-12-08 16:05:27 | gi.overrides.Vips              | DEBUG    | assigning <Image object at 0x7f1f0ea0dc80 (VipsImage at 0xe9e687e0)> to in1
    2015-12-08 16:05:27 | gi.overrides.Vips              | DEBUG    | in1 needs a <GType VipsImage (33612672)>
    2015-12-08 16:05:27 | gi.overrides.Vips              | DEBUG    | assigning <Image object at 0x7f1f0ea0dc80 (VipsImage at 0xe9e687e0)>
    2015-12-08 16:05:27 | gi.overrides.Vips              | DEBUG    | assigning <Image object at 0x7f1f0fcc2eb0 (VipsImage at 0x2ee0ca0)> to in2
    2015-12-08 16:05:27 | gi.overrides.Vips              | DEBUG    | in2 needs a <GType VipsImage (33612672)>
    2015-12-08 16:05:27 | gi.overrides.Vips              | DEBUG    | assigning <Image object at 0x7f1f0fcc2eb0 (VipsImage at 0x2ee0ca0)>
    2015-12-08 16:05:27 | gi.overrides.Vips              | DEBUG    | assigning vertical to direction
    2015-12-08 16:05:27 | gi.overrides.Vips              | DEBUG    | direction needs a <GType VipsDirection (37071744)>
    2015-12-08 16:05:27 | gi.overrides.Vips              | DEBUG    | assigning vertical
    2015-12-08 16:05:27 | gi.overrides.Vips              | DEBUG    | _call_base checking cache for op <__main__.VipsJoin object at 0x7f1f0ccaf3c0 (VipsJoin at 0xe9cc4e50)>
    2015-12-08 16:05:27 | gi.overrides.Vips              | DEBUG    | _call_base got op2 <__main__.VipsJoin object at 0x7f1f0ccaf3c0 (VipsJoin at 0xe9cc4e50)>
    2015-12-08 16:05:27 | gi.overrides.Vips              | DEBUG    | _call_base fetching required output args
    2015-12-08 16:05:27 | gi.overrides.Vips              | DEBUG    | read out <Image object at 0x7f1f0f1b88c0 (VipsImage at 0xe9fdaaf0)> from out
    2015-12-08 16:05:27 | gi.overrides.Vips              | DEBUG    | _call_base fetching optional output args
    2015-12-08 16:05:27 | gi.overrides.Vips              | DEBUG    | success
    2015-12-08 16:05:27 | gi.overrides.Vips              | DEBUG    | Image.__getattr__ percent
    2015-12-08 16:05:27 | gi.overrides.Vips              | DEBUG    | _call_base name=percent, required=(99.9,) optional={}
    2015-12-08 16:05:27 | gi.overrides.Vips              | DEBUG    | _call_base self=<Image object at 0x7f1f0f1b88c0 (VipsImage at 0xe9fdaaf0)>
    2015-12-08 16:05:27 | gi.overrides.Vips              | DEBUG    | assigning <Image object at 0x7f1f0f1b88c0 (VipsImage at 0xe9fdaaf0)> to in
    2015-12-08 16:05:27 | gi.overrides.Vips              | DEBUG    | in needs a <GType VipsImage (33612672)>
    2015-12-08 16:05:27 | gi.overrides.Vips              | DEBUG    | assigning <Image object at 0x7f1f0f1b88c0 (VipsImage at 0xe9fdaaf0)>
    2015-12-08 16:05:27 | gi.overrides.Vips              | DEBUG    | assigning 99.9 to percent
    2015-12-08 16:05:27 | gi.overrides.Vips              | DEBUG    | percent needs a <GType gdouble (60)>
    2015-12-08 16:05:27 | gi.overrides.Vips              | DEBUG    | assigning 99.9
    2015-12-08 16:05:27 | gi.overrides.Vips              | DEBUG    | _call_base checking cache for op <__main__.VipsPercent object at 0x7f1f0f1b8910 (VipsPercent at 0xe9e6e980)>
    Killed
    

    The program was run on a machine with 32GB memory and 8 cores.

    The same error occurs when another function is called, e.g. scale() instead of percent().

    Here is a small test program that illustrates the actual program and might be helpful to reproduce the error:

    #! /usr/bin/env python
    import os
    import numpy as np
    import shutil
    import tempfile
    import itertools
    import logging
    import argparse
    from gi.repository import Vips
    
    
    def configure_logging():
        logger = logging.getLogger()
    
        fmt = '%(asctime)s | %(name)-30s | %(levelname)-8s | %(message)s'
        datefmt = '%Y-%m-%d %H:%M:%S'
        formatter = logging.Formatter(fmt=fmt, datefmt=datefmt)
    
        handler = logging.StreamHandler()
        handler.name = 'stream'
        handler.setFormatter(formatter)
        logger.addHandler(handler)
    
    
    if __name__ == '__main__':
    
        configure_logging()
    
        parser = argparse.ArgumentParser('Test program for Vips pyramid creation.')
        parser.add_argument('-v', '--verbosity', action='count', default=0,
                            help='increase logging verbosity')
        parser.add_argument('-m', '--mosaic_axis_length', default=2, type=int,
                            help='number of images along each dimension of a mosaic')
        parser.add_argument('-o', '--overview_axis_length', default=5, type=int,
                            help='number of mosaics along each dimension of the overview')
    
        tmp_dir = tempfile.gettempdir()
    
        args = parser.parse_args()
    
        logging_level_mapper = {
            0: logging.CRITICAL,
            1: logging.INFO,
            2: logging.DEBUG,
        }
    
        logger = logging.getLogger('test_vips_pyramid')
        logger.setLevel(logging_level_mapper[args.verbosity])
    
        vips_logger = logging.getLogger('gi.overrides.Vips')
        vips_logger.setLevel(logging_level_mapper[args.verbosity])
    
        # Create a squared "overview" image that is composed of many smaller squared
        # "mosaics", each of which is composed of several individual images.
        # NOTE: The size of the actual overview image is at least 0.5 * 10^6 pixels
        # along each dimension.
        mosaic_axis_length = args.mosaic_axis_length
        files = ['file_%d.png' % i for i in range(mosaic_axis_length**2)]
    
        overview_axis_length = args.overview_axis_length
        folder_names = ['directory_%d' % i for i in range(overview_axis_length**2)]
    
        input_dir = os.path.join(tmp_dir, 'vips_test', 'inputs')
        if not os.path.exists(input_dir):
            os.makedirs(input_dir)
    
        output_dir = os.path.join(tmp_dir, 'vips_test', 'outputs')
        if os.path.exists(output_dir):
            shutil.rmtree(output_dir)
    
        directories = [os.path.join(input_dir, f) for f in folder_names]
    
        # Create images on disk
        # NOTE: The actual images would already exist on disk
        logger.info('create images')
        for d in directories:
            if not os.path.exists(d):
                os.mkdir(d)
            for f in files:
                filename = os.path.join(input_dir, d, f)
                logger.debug('write image to file: %s', filename)
                img = Vips.Image.gaussnoise(100, 100)
               # NOTE: The actual dimensions are 2500 x 2600
                img.write_to_file(filename)
    
        logger.info('create mosaics')
        moasic_coordinates = list(itertools.product(
                                 range(mosaic_axis_length),
                                 range(mosaic_axis_length)))
        mosaics = list()
        for i, d in enumerate(directories):
            logger.debug('stitch mosaic # %d', i)
            # Build grid for the current mosaic
            mosaic_grid_dims = (mosaic_axis_length, mosaic_axis_length)
            mosaic_grid = np.empty(mosaic_grid_dims, dtype='O')
            for i, coords in enumerate(moasic_coordinates):
                filename = os.path.join(d, files[i])
                mosaic_grid[coords[0], coords[1]] = filename
    
            # Load individual images and stitch them together according to the grid layout
            for r in xrange(mosaic_grid.shape[0]):
                for c in xrange(mosaic_grid.shape[1]):
    
                    img = Vips.Image.new_from_file(mosaic_grid[r, c])
    
                    if c == 0:
                        row = img
                    else:
                        row = row.merge(img, 'horizontal', -img.width, 0)
    
                if r == 0:
                    mosaic = row
                else:
                    mosaic = mosaic.merge(row, 'vertical', 0, -img.height)
    
            mosaics.append(mosaic)
    
    
        logger.info('create overview')
        overview_coordinates = list(itertools.product(
                                  range(overview_axis_length),
                                  range(overview_axis_length)))
        # Build grid for the final overview image
        overview_grid_dims = (overview_axis_length, overview_axis_length)
        overiew_grid = np.empty(overview_grid_dims, dtype='O')
        for i, coords in enumerate(overview_coordinates):
            overiew_grid[coords[0], coords[1]] = mosaics[i]
    
        # Create spacer images, which will be inserted between individual mosaics
        img_dtype = img.get_format()
        col_spacer = Vips.Image.black(10, mosaic.height, bands=1).cast(img_dtype)
        row_width = (
            mosaic.width * overview_grid_dims[1] +
            10 * (overview_grid_dims[1] + 1)
        )
        row_spacer = Vips.Image.black(row_width, 10, bands=1).cast(img_dtype)
    
        # Stitch mosaics together according to the grid layout
        overview = row_spacer
        for r in xrange(overiew_grid.shape[0]):
            for c in xrange(overiew_grid.shape[1]):
    
                if c == 0:
                    row = col_spacer
    
                mosaic = overiew_grid[r, c]
                row = row.join(mosaic, 'horizontal')
                row = row.join(col_spacer, 'horizontal')
    
            overview = overview.join(row, 'vertical')
            overview = overview.join(row_spacer, 'vertical')
    
        # Clip intensity values
        logger.info('clip intensities')
        threshold = overview.percent(99.9)
        identity_image = Vips.Image.identity(ushort=True)
        condition_image = (identity_image >= threshold)
        lut = condition_image.ifthenelse(threshold, identity_image)
        overview = overview.maplut(lut)
    
        # Rescale to 8-bit
        logger.info('rescale intensities')
        overview = overview.scale()
    
        # Save as pyramid
        logger.info('create pyramid: %s', output_dir)
        overview.dzsave(output_dir, layout='zoomify')
    

    Run the program in DEBUG mode:

    test_vips_pyramid.py -vv
    

    Vips was installed from git (branch 8.1).

    I would like to include @riccardomurri and @smaffiol.

  • vips2png: Unable to write to target

    vips2png: Unable to write to target

    Hi, we get the error vips2png: unable to write to target when converting certain tiff files to png. This error is sporadic. Does this mean that it is unable to write to the file?

    Vips: 8.9.0 - Running inside alpine docker image Using bimg to talk to vips

  • Ruby vips8 read then write image files loop crashes after n images

    Ruby vips8 read then write image files loop crashes after n images

    Hi John,

    I have run into what seems to be a bug in vips8 or the Ruby interface to it.

    I am processing large numbers of 2K tif video images: 2048 x 1556 pixels. For each image: Image file gets read. Modified in some way. Modified image file gets written to a new file.

    This was working OK with ruby-vips (vips7). I changed over to vips8 and the gir_ffi-vips interface. All was working OK when processing just a handful of files (testing). When I tried to ramp it up to hundreds of files, there was a crash after about 30 files.

    I have isolated this to a very simple example ruby script which just reads a series of numbered 2048 x 1556 pixel all-black tif images and writes each image out — all to the same output file — the error appears when reading a series of different files — writing to different output files or to the same output file makes no difference. This bombs on my system after 16 images. The error message trace back to Vips::Image.write_to_file is:

    GLib-GObject-CRITICAL **: g_value_type_compatible: assertion 'G_TYPE_IS_VALUE (src_type)' failed value.rb:158: in check_type_compatibility': Vips::Image is incompatible with VipsImage (ArgumentError) from /Library/Ruby/Gems/2.0.0/gems/gir_ffi-0.7.9/lib/ffi-gobject/value.rb:139:inset_instance_enhanced' from /Library/Ruby/Gems/2.0.0/gems/gir_ffi-0.7.9/lib/ffi-gobject/value.rb:53:in set_value' from /Library/Ruby/Gems/2.0.0/gems/gir_ffi-0.7.9/lib/ffi-gobject/object.rb:77:inset_property_with_override' from /Library/Ruby/Gems/2.0.0/gems/gir_ffi-vips-0.1.0/lib/vips8/argument.rb:130:in set_value' from /Library/Ruby/Gems/2.0.0/gems/gir_ffi-vips-0.1.0/lib/vips8/call.rb:73:incall_base' from /Library/Ruby/Gems/2.0.0/gems/gir_ffi-vips-0.1.0/lib/vips8/image.rb:384:in `write_to_file'

    Mostly this is the error I get. One time the error was an address error (a zero address).

    Here is the simple test script:

    require 'vips8'
    require 'pathname'
    
    image_folder = Pathname(__FILE__).dirname + "IMAGE_FOLDER"
    
    (1..50).each do |image_number|
    
      puts "Image #{image_number}"
    
      source_file_path = image_folder + "test-2K-image-#{sprintf('%02d', image_number)}.tif"
    
      test_image = Vips::Image.new_from_file (source_file_path).to_s
    
      test_image.write_to_file((image_folder + "output_image.tif").to_s)
    end
    

    The test files are named "test-2K-image-01", etc. I can't attach a sample file because GitHub doesn't support uploading tif files. Just create a test file in Photoshop then duplicate and number the duplicates.

    As I say, the ruby-vips equivalent code worked without a problem.

    Any ideas?

    Paul Howson

  • Better PDF support

    Better PDF support

    It would be great if libvips had a direct binding to a pdf library to allow efficient generation of eg. thumbnails from PDFs.

    vips currently can read pdfs via imagemagick or graphicksmagic, but both of these are very slow and memory inefficient at that.

    I think a good candidate could be libpoppler which has a cairo output device (Usage in pdftocairo utility).

  • dzsave - -centre creates a huge differential in processing time

    dzsave - -centre creates a huge differential in processing time

    We're converting aperio .svs images directly to a google maps pyramid.

    In some basic tests, we're seeing a huge variance between running with and without centre.

    One of our smaller examples - a ~84 MB .svs:

    without

    [email protected]:/opt/Processing$ time vips dzsave 2 a --layout google --background black
    
    real     0m43.411s
    user 2m44.544s
    sys  0m42.400s
    

    with

    [email protected]:/opt/Processing$ time vips dzsave 2 b --layout google --background black --centre
    
    real     17m6.623s
    user 73m9.596s
    sys  17m53.780s
    

    Is this fairly par for the course? Is there anyway we can pre-process the image to optimize conversion?

    We have live samples that are 2 GB+ that are taking an hour without the flag, I'm not sure I want to see the difference at that rate. :)

  • cgifsave: add support for interlaced GIF write

    cgifsave: add support for interlaced GIF write

    cgif >= v0.3.0 supports writing interlaced (progressive) GIFs. Add support for interlaced GIF write in libvips. Note: As of now, cgif requires more memory for writing interlaced GIFs (tracked by https://github.com/dloebl/cgif/issues/52).

  • 10x slowdown when converting png to avif without resizing

    10x slowdown when converting png to avif without resizing

    Bug report

    Describe the bug I'm not sure if the bug is in libvips, libheif or libaom, but you got to start somewhere...

    When converting a PNG (specifically PNG, WEBP does not exhibit this for example) image to an AVIF image of the same dimensions, libvips takes 10x longer than when resizing the image as well.

    To Reproduce Steps to reproduce the behavior:

    1. Use Image source
    2. vipsthumbnail.exe .\source.png --size 3840x -o destination.heif[compression=av1,lossless=false,effort=2]
    3. libvips takes roughly 11 seconds on my machine (effort=2 to keep it lower).

    Expected behavior Running the above command slightly different results in it only taking ~1 second to be done. vipsthumbnail.exe .\source.png --size 4000x -o destination.heif[compression=av1,lossless=false,effort=2]

    You can also downsize and observe the same behaviour.

    vipsthumbnail.exe .\source.png --size 3400x -o destination.heif[compression=av1,lossless=false,effort=2]

    Or simply only change one dimension.

    vipsthumbnail.exe .\source.png --size 3840x1080 -o destination.heif[compression=av1,lossless=false,effort=2]

    Actual behavior Converting to AVIF without resizing the image takes ~10x as long.

    Screenshots

    vipsthumbnail.exe --vips-info .\source.png --size 4000x -o destination.heif[compression=av1,effort=2,lossless=false,Q=80,strip=true]
    VIPS-INFO: 10:10:54.474: thumbnailing .\artwork_landscape.png
    VIPS-INFO: 10:10:54.491: selected loader is VipsForeignLoadPngFile
    VIPS-INFO: 10:10:54.497: input size is 3840 x 2160
    VIPS-INFO: 10:10:54.504: loading with factor 1 pre-shrink
    VIPS-INFO: 10:10:54.519: pre-shrunk size is 3840 x 2160
    VIPS-INFO: 10:10:54.524: converting to processing space srgb
    VIPS-INFO: 10:10:54.529: residual scale 1,04167 x 1,04167
    VIPS-INFO: 10:10:54.535: converting to output space srgb
    VIPS-INFO: 10:10:54.540: thumbnailing .\source.png as .\destination.heif[compression=av1,effort=2,lossless=false,Q=80,strip=true]
    
    vipsthumbnail.exe --vips-info .\source.png --size 3840x -o destination.heif[compression=av1,effort=2,lossless=false,Q=80,strip=true]
    VIPS-INFO: 10:11:09.687: thumbnailing .\artwork_landscape.png
    VIPS-INFO: 10:11:09.704: selected loader is VipsForeignLoadPngFile
    VIPS-INFO: 10:11:09.712: input size is 3840 x 2160
    VIPS-INFO: 10:11:09.734: loading with factor 1 pre-shrink
    VIPS-INFO: 10:11:09.742: pre-shrunk size is 3840 x 2160
    VIPS-INFO: 10:11:09.750: converting to processing space srgb
    VIPS-INFO: 10:11:09.759: converting to output space srgb
    VIPS-INFO: 10:11:09.763: thumbnailing .\source.png as .\destination.heif[compression=av1,effort=2,lossless=false,Q=80,strip=true]
    

    Environment (please complete the following information)

    • OS: Debian Bullseye, Windows 10
    • Vips: 8.13.0, 8.12.2

    Additional context We managed to reproduce this locally with the prebuilt Windows binaries, but also with Linux binaries built from source with both libaom 3.4.0 and libaom 3.3.0, and both vips 8.13.0 and 8.12.2.

    Upscaling and downscaling an image takes roughly ~2 seconds, compared to not-scaling the image at all taking ~11 seconds.

    Interestingly the "slow" version has a maximum memory consumption of 17MB, whereas upscaling it takes 38MB.

    vips-profile-slow.txt vips-profile-fast.txt

  • WIP: move tiff decompress outside lock

    WIP: move tiff decompress outside lock

    Most time in TIFF read is spent in decompression. If we move this outside the lock, we can get a useful speedup.

    This commit adds the machinery to move the lock to before decompress, so jp2k decompression is now threaded.

    Before:

    $ vips copy wtc.jpg x.tif[tile,compression=jp2k]
    $ time vips avg x.tif
    117.249845
    real	0m15.085s
    user	0m16.155s
    sys	0m0.109s
    

    After:

    $ time vips avg x.tif
    117.249845
    real	0m1.207s
    user	0m18.384s
    sys	0m0.369s
    
  • move jpeg encode / decode outside libtiff

    move jpeg encode / decode outside libtiff

    At the moment, libvips does JPEG encode and decode using the standard libtiff mechanisms. This is easy, but it means that JPEG encoding runs inside libtiff, and that means it can't be threaded.

    We could handle the encode / decode ourselves and process many tiles in parallel. This could give a nice speedup in many cases, especially for OME tiff.

    openslide has sample code for this we could check.

    See: https://forum.image.sc/t/how-to-speed-up-the-process-of-ome-tiff-generation-using-multi-processing/69104/3

  • Inconsistencies using nearest neighbour for rotation

    Inconsistencies using nearest neighbour for rotation

    Bug report

    Describe the bug

    When rotating images using Vips with nearest neighbour interpolation the result has inconsistencies.

    This is especially obvious when rotating symmetrical pixel art.

    To Reproduce Steps to reproduce the behavior:

    1. Use Image of ladder at bottom
    2. Use Configuration interpolate: nearest and rotate 45 degrees
    3. See error

    Or with the Ruby binding:

    ladder = Vips::Image.new_from_file "./ladder.png"
    rotated = ladder.rotate 45, interpolate: Vips::Interpolate.new(:nearest)
    rotated.write_to_file "./rotated.png"
    

    Expected behavior

    Of course nearest neighbour produces artefacts, but I expect them to be symmetrical when the image being rotated is symmetrical.

    Actual behavior

    There are various discrepancies throughout.

    Screenshots

    magick_vs_vips_45

    Environment

    • OS: macOS 12.4 (21F79)
    • vips-8.12.2-Tue Jan 25 09:34:32 UTC 2022

    Additional context

    ImageMagick produces symmetrical results when using nearest neighbour. However when using "integer" it produces results more like Vips:

    magick_integer

    Original ladder image:

    ladder

    Or if theres a different way to rotate 1 bit pixel art I'd love to know :)

  • vipsheader returns wrong number of pages for PDF document

    vipsheader returns wrong number of pages for PDF document

    Describe the bug vipsheader -f n-pages test1.pdf returns 2 when in reality there is only 1 page in this pdf file

    To Reproduce

    1. Download attached test1.pdf
    2. Run vipsheader -f n-pages test1.pdf

    Expected behavior Return 1

    Actual behavior Returns 2

    Environment

    • OS: Centos 7.9
    • Vips: 8.12.2

    test1.pdf

Writing our own printf function, this is a project done under ALX Low Level Programming.

0x11. C - printf Writing our own printf function, this is a project done under ALX Low Level Programming. Resource secrets of printf Implementing prin

Apr 18, 2022
Make a directory to an ESP disk image

espack Make a directory to an ESP disk image. 把目录整体打包成一个 ESP 分区的磁盘镜像。 usage Download the released zip file from (here), for example espack-1.0.zip and

Jul 8, 2022
A docker image where you can run a judge program and a converter for multiple sequence alignment

genocon2021-docker 本リポジトリでは、ジャッジプログラム(eval.c)と Multiple Sequence Alignment (MSA) 変換プログラム(decode_cigar.py)を同梱した Docker イメージを提供しています。 また、サンプル解答プログラム(sam

Sep 20, 2021
Sqrt OS is a simulation of an OS scheduler and memory manager using different scheduling algorithms including Highest Priority First (non-preemptive), Shortest Remaining Time Next, and Round Robin.
Sqrt OS is a simulation of an OS scheduler and memory manager using different scheduling algorithms including Highest Priority First (non-preemptive), Shortest Remaining Time Next, and Round Robin.

A CPU scheduler determines an order for the execution of its scheduled processes; it decides which process will run according to a certain data structure that keeps track of the processes in the system and their status. A process, upon creation, has one of the three states: Running, Ready, Blocked (doing I/O, using other resources than CPU or waiting on unavailable resource).

Apr 15, 2022
Remote Download and Memory Execute for shellcode framework
Remote Download and Memory Execute for shellcode framework

RmExecute Remote Download and Memory Execute for shellcode framework 远程下载并内存加载的ShellCode框架,暂不支持X64 参(抄)考(袭)项目 windows下shellcode提取模板的实现 主要抄袭来源,直接使用这位大佬

Aug 15, 2022
PoC memory injection detection agent based on ETW, for offensive and defensive research purposes
PoC memory injection detection agent based on ETW, for offensive and defensive research purposes

TiEtwAgent - ETW-based process injection detection This project was created to research, build and test different memory injection detection use cases

Jul 29, 2022
Scans all running processes. Recognizes and dumps a variety of potentially malicious implants (replaced/implanted PEs, shellcodes, hooks, in-memory patches).
Scans all running processes. Recognizes and dumps a variety of potentially malicious implants (replaced/implanted PEs, shellcodes, hooks, in-memory patches).

Scans all running processes. Recognizes and dumps a variety of potentially malicious implants (replaced/implanted PEs, shellcodes, hooks, in-memory patches).

Aug 8, 2022
Bytehound - a memory profiler for Linux
Bytehound - a memory profiler for Linux

Bytehound - a memory profiler for Linux Features Can be used to analyze memory leaks, see where exactly the memory is being consumed, identify tempora

Aug 12, 2022
A fast character conversion and transliteration library based on the scheme defined for Japan National Tax Agency (国税庁) 's corporate number (法人番号) system.
A fast character conversion and transliteration library based on the scheme defined for Japan National Tax Agency (国税庁) 's corporate number (法人番号) system.

jntajis-python Documentation: https://jntajis-python.readthedocs.io/ What's JNTAJIS-python? JNTAJIS-python is a transliteration library, specifically

Aug 3, 2022
fast javascript bundler :package:
fast javascript bundler :package:

Fast JavaScript Bundler https://fjbundler.com What? It is what it says it is. However, this bundler aims to be a monolithic does-it-all type of bundle

Aug 5, 2022
Fast comparison-based sort algorithm

nanosort Algorithm nanosort aims to be a fast comparison-based sorting algorithm, tuned for POD types of reasonably small sizes. nanosort implements a

Aug 2, 2022
A fast phone number lib for Ruby (binds to Google's C++ libphonenumber)

MiniPhone A Ruby gem which plugs directly into Google's native C++ libphonenumber for extremely fast and robust phone number parsing, validation, and

Aug 8, 2022
Tau is a fast syntax highlighter capable of emitting HTML.

tau - a reasonably fast (wip) syntax highlighter. Tau is a fast syntax highlighter capable of emitting HTML. It highlights the following languages: py

Apr 21, 2022
Very fast Markdown parser and HTML generator implemented in WebAssembly, based on md4c

Very fast Markdown parser and HTML generator implemented in WebAssembly, based on md4c

Aug 8, 2022
The goal of insidesp is to do fast point in polygon classification, the sp way.

insidesp The goal of insidesp is to do fast point in polygon classification, the sp way. We are comparing a few ways of implementing this, essentially

Nov 12, 2021
Fast regular expression grep for source code with incremental index updates

Fast regular expression grep for source code with incremental index updates

Aug 10, 2022
Isocline is a pure C library that can be used as an alternative to the GNU readline library
Isocline is a pure C library that can be used as an alternative to the GNU readline library

Isocline: a portable readline alternative. Isocline is a pure C library that can be used as an alternative to the GNU readline library (latest release

Aug 5, 2022
A linux library to get the file path of the currently running shared library. Emulates use of Win32 GetModuleHandleEx/GetModuleFilename.

whereami A linux library to get the file path of the currently running shared library. Emulates use of Win32 GetModuleHandleEx/GetModuleFilename. usag

Nov 5, 2021
Command-line arguments parsing library.

argparse argparse - A command line arguments parsing library in C (compatible with C++). Description This module is inspired by parse-options.c (git)

Aug 8, 2022