From 38b65478e5506ba5b7114e78270e58516faab171 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Fri, 7 Apr 2017 15:59:37 +0100 Subject: [PATCH] bump version, doc tweaks more sotons removed --- ChangeLog | 3 + README.md | 20 +-- configure.ac | 4 +- doc/Examples.xml | 321 ++++++++++++++++++++++++++++++++++++++++ doc/libvips-docs.xml.in | 2 +- 5 files changed, 337 insertions(+), 13 deletions(-) create mode 100644 doc/Examples.xml diff --git a/ChangeLog b/ChangeLog index 9170cbc4..8f06ed74 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +7/4/17 started 8.5.3 +- more link fixing in docs + 25/3/17 started 8.5.2 - better behaviour for truncated PNG files, thanks Yury - missing proto for vips_tiffsave_buffer(), thanks greut diff --git a/README.md b/README.md index 6a11fa67..6b91c299 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ libvips is a 2D image processing library. Compared to similar libraries, [libvips runs quickly and uses little -memory](http://www.vips.ecs.soton.ac.uk/index.php?title=Speed_and_Memory_Use). +memory](https://github.com/jcupitt/libvips/wiki/Speed-and-memory-use). libvips is licensed under the LGPL 2.1+. It has around 300 operations covering arithmetic, histograms, @@ -17,20 +17,20 @@ PDF, SVG, HDR, PPM, CSV, GIF, Analyze, DeepZoom, and OpenSlide. It can also load images via ImageMagick or GraphicsMagick. It has APIs for -[C](http://www.vips.ecs.soton.ac.uk/supported/current/doc/html/libvips/using-from-c.html) +[C](http://jcupitt.github.io/libvips/API/current/using-from-c.html) and -[C++](http://www.vips.ecs.soton.ac.uk/supported/current/doc/html/libvips/using-from-cpp.html) +[C++](http://jcupitt.github.io/libvips/API/current/using-from-cpp.html) and comes with a [Python -binding](http://www.vips.ecs.soton.ac.uk/supported/current/doc/html/libvips/using-from-python.html) +binding](http://jcupitt.github.io/libvips/API/current/using-from-python.html) and a [command-line -interface](http://www.vips.ecs.soton.ac.uk/supported/current/doc/html/libvips/using-cli.html). +interface](http://jcupitt.github.io/libvips/API/current/using-cli.html). Bindings are available for [Ruby](https://rubygems.org/gems/ruby-vips), [PHP](https://github.com/jcupitt/php-vips), [Go](https://github.com/davidbyttow/govips), JavaScript and others. There is full -[documentation](http://www.vips.ecs.soton.ac.uk/supported/current/doc/html/libvips/index.html). +[documentation](http://jcupitt.github.io/libvips/API/current). There are several GUIs as well, see the [VIPS -website](http://www.vips.ecs.soton.ac.uk). +website](http://jcupitt.github.io/libvips). There are packages for most unix-like operating systems and binaries for Windows and OS X. @@ -39,7 +39,7 @@ Windows and OS X. We keep pre-baked tarballs of releases on the vips website: -http://www.vips.ecs.soton.ac.uk/supported/current/ +https://github.com/jcupitt/libvips/releases Untar, then in the libvips directory you should just be able to do: @@ -65,9 +65,9 @@ Once `configure` is looking OK, compile and install with the usual: By default this will install files to `/usr/local`. We have detailed guides on the wiki for [building on -Windows](http://www.vips.ecs.soton.ac.uk/index.php?title=Build_on_windows) +Windows](https://github.com/jcupitt/libvips/wiki/Build_for_Windows) and [building on OS -X](http://www.vips.ecs.soton.ac.uk/index.php?title=Build_on_OS_X). +X](https://github.com/jcupitt/libvips/wiki/Build_on_OS_X). # Building libvips from git diff --git a/configure.ac b/configure.ac index 68f79789..089615d4 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # also update the version number in the m4 macros below -AC_INIT([vips], [8.5.2], [vipsip@jiscmail.ac.uk]) +AC_INIT([vips], [8.5.3], [vipsip@jiscmail.ac.uk]) # required for gobject-introspection AC_PREREQ(2.62) @@ -18,7 +18,7 @@ AC_CONFIG_MACRO_DIR([m4]) # user-visible library versioning m4_define([vips_major_version], [8]) m4_define([vips_minor_version], [5]) -m4_define([vips_micro_version], [2]) +m4_define([vips_micro_version], [3]) m4_define([vips_version], [vips_major_version.vips_minor_version.vips_micro_version]) diff --git a/doc/Examples.xml b/doc/Examples.xml new file mode 100644 index 00000000..aba6cdee --- /dev/null +++ b/doc/Examples.xml @@ -0,0 +1,321 @@ + + + + + + + Examples 3 libvips + + + libvips examples A few example Python programs using libvips + + + This page shows a few libvips examples using Python. They will work with small syntax changes in any language with a libvips binding. + + + The libvips test suite is written in Python and exercises every operation in the API. It’s also a useful source of examples. + + + Average a region of interest box on an image + +#!/usr/bin/env python + +import sys +import gi +gi.require_version('Vips', '8.0') +from gi.repository import Vips + +left = 10 +top = 10 +width = 64 +height = 64 + +image = Vips.Image.new_from_file(sys.argv[1]) +roi = image.crop(left, top, width, height) +print 'average:', roi.avg() + + + + libvips and numpy + + You can use Vips.Image.new_from_memory_copy() to make a vips image from an area of memory. The memory array needs to be laid out band-interleaved, as a set of scanlines, with no padding between lines. + + + This example moves an image from numpy to vips, but it’s simple to move the other way (use Vips.Image.write_to_memory()) to to move images into or out of PIL. + + +#!/usr/bin/python + +import numpy +import scipy.ndimage +import gi +gi.require_version('Vips', '8.0') +from gi.repository import Vips + +def np_dtype_to_vips_format(np_dtype): + ''' + Map numpy data types to VIPS data formats. + + Parameters + ---------- + np_dtype: numpy.dtype + + Returns + ------- + gi.overrides.Vips.BandFormat + ''' + lookup = { + numpy.dtype('int8'): Vips.BandFormat.CHAR, + numpy.dtype('uint8'): Vips.BandFormat.UCHAR, + numpy.dtype('int16'): Vips.BandFormat.SHORT, + numpy.dtype('uint16'): Vips.BandFormat.USHORT, + numpy.dtype('int32'): Vips.BandFormat.INT, + numpy.dtype('float32'): Vips.BandFormat.FLOAT, + numpy.dtype('float64'): Vips.BandFormat.DOUBLE + } + return lookup[np_dtype] + +def np_array_to_vips_image(array): + ''' + Convert a `numpy` array to a `Vips` image object. + + Parameters + ---------- + nparray: numpy.ndarray + + Returns + ------- + gi.overrides.Vips.image + ''' + # Look up what VIPS format corresponds to the type of this np array + vips_format = np_dtype_to_vips_format(array.dtype) + dims = array.shape + height = dims[0] + width = 1 + bands = 1 + if len(dims) > 1: + width = dims[1] + if len(dims) > 2: + bands = dims[2] + img = Vips.Image.new_from_memory_copy(array.data, + width, height, bands, vips_format) + + return img + +array = numpy.random.random((10,10)) +vips_image = np_array_to_vips_image(array) +print 'avg =', vips_image.avg() + +array = scipy.ndimage.imread("test.jpg") +vips_image = np_array_to_vips_image(array) +print 'avg =', vips_image.avg() +vips_image.write_to_file("test2.jpg") + + + + Watermarking + + This example renders a simple watermark on an image. Use it like this: + + +./watermark.py somefile.png output.jpg "hello <i>world</i>" + + + The text is rendered in transparent red pixels all over the image. It knows about transparency, CMYK, and 16-bit images. + + +#!/usr/bin/python + +import sys +import gi +gi.require_version('Vips', '8.0') +from gi.repository import Vips + +im = Vips.Image.new_from_file(sys.argv[1], access = Vips.Access.SEQUENTIAL) + +text = Vips.Image.text(sys.argv[3], width = 500, dpi = 300) +text = (text * 0.3).cast("uchar") +text = text.embed(100, 100, text.width + 200, text.width + 200) +text = text.replicate(1 + im.width / text.width, 1 + im.height / text.height) +text = text.crop(0, 0, im.width, im.height) + +# we want to blend into the visible part of the image and leave any alpha +# channels untouched ... we need to split im into two parts + +# 16-bit images have 65535 as white +if im.format == Vips.BandFormat.USHORT: + white = 65535 +else: + white = 255 + +# guess how many bands from the start of im contain visible colour information +if im.bands >= 4 and im.interpretation == Vips.Interpretation.CMYK: + # cmyk image ... put the white into the magenta channel + n_visible_bands = 4 + text_colour = [0, white, 0, 0] +elif im.bands >= 3: + # colour image ... put the white into the red channel + n_visible_bands = 3 + text_colour = [white, 0, 0] +else: + # mono image + n_visible_bands = 1 + text_colour = white + +# split into image and alpha +if im.bands - n_visible_bands > 0: + alpha = im.extract_band(n_visible_bands, n = im.bands - n_visible_bands) + im = im.extract_band(0, n = n_visible_bands) +else: + alpha = None + +# blend means do a smooth fade using the 0 - 255 values in the condition channel +# (test in this case) ... this will render the anit-aliasing +im = text.ifthenelse(text_colour, im, blend = True) + +# reattach alpha +if alpha: + im = im.bandjoin(alpha) + +im.write_to_file(sys.argv[2]) + + + + Build huge image mosaic + + This makes a 100,000 x 100,000 black image, then inserts all the images you pass on the command-line into it at random positions. libvips is able to run this program in sequential mode: it’ll open all the input images at the same time, and stream pixels from them as it needs them to generate the output. + + + To test it, first make a large 1-bit image. This command will take the green channel and write as a 1-bit fax image. wtc.jpg is a test 10,000 x 10,000 jpeg: + + +$ vips extract_band wtc.jpg x.tif[squash,compression=ccittfax4,strip] 1 + + + Now make 1,000 copies of that image in a subdirectory: + + +$ mkdir test +$ for i in {1..1000}; do cp x.tif test/$i.tif; done + + + And run this Python program on them: + + +$ time ./try255.py x.tif[squash,compression=ccittfax4,strip,bigtif] test/* +real 1m59.924s +user 4m5.388s +sys 0m8.936s + + + It completes in just under two minutes on this laptop, and needs about 7gb of RAM to run. It would need about the same amount of memory for a full-colour RGB image, I was just keen to keep disc usage down. + + + If you wanted to handle transparency, or if you wanted mixed CMYK and RGB images, you’d need to do some more work to convert them all into the same colourspace before inserting them. + + +#!/usr/bin/env python + +import sys +import random + +import gi +gi.require_version('Vips', '8.0') +from gi.repository import Vips + +# turn on progress reporting +Vips.progress_set(True) + +# this makes a 8-bit, mono image of 100,000 x 100,000 pixels, each pixel zero +im = Vips.Image.black(100000, 100000) + +for filename in sys.argv[2:]: + tile = Vips.Image.new_from_file(filename, access = Vips.Access.SEQUENTIAL) + + im = im.insert(tile, + random.randint(0, im.width - tile.width), + random.randint(0, im.height - tile.height)) + +im.write_to_file(sys.argv[1]) + + + + Rename DICOM images using header fields + + DICOM images commonly come in an awful directory hierarchy named as something like images/a/b/e/z04. There can be thousands of files and it can be very hard to find the one you want. + + + This utility copies files to a single flat directory, naming them using fields from the DICOM header. You can actually find stuff! Useful. + + +#!/usr/bin/env python + +import sys +import re +import os +import shutil + +import gi +gi.require_version('Vips', '8.0') +from gi.repository import Vips + +if len(sys.argv) != 3: + print 'rename DICOM files using tags from the header' + sys.exit(1) + +srcdir = sys.argv[1] +destdir = sys.argv[2] + +if not os.access(destdir, os.F_OK | os.R_OK | os.W_OK | os.X_OK): + os.mkdir(destdir) + +def get_field(vim, field): + result = vim.get_value(field) + + # remove any \n etc. + result = re.sub("\n", "", result) + + # remove any leading or trailing spaces + result = re.sub(" $", "", result) + result = re.sub("^ ", "", result) + + return result + +modality_name = "magick-dcm:Modality" +series_name = "magick-dcm:SeriesNumber" +instance_name = "magick-dcm:Instance(formerlyImage)Number" +date_name = "magick-dcm:ImageDate" + +for(dirpath, dirnames, filenames) in os.walk(srcdir): + for file in filenames: + path = os.path.join(dirpath, file) + + try: + vim = Vips.Image.new_from_file(path) + except Vips.Error, e: + print 'unable to open', path + print e + continue + + try: + modality = get_field(vim, modality_name) + series = get_field(vim, series_name) + instance = get_field(vim, instance_name) + date = get_field(vim, date_name) + except Vips.Error, e: + print 'unable to get fields from header', path + print e + continue + + match = re.match("(\d\d\d\d)(\d\d)(\d\d)", date) + date = match.group(1) + "." + match.group(2) + "." + match.group(3) + + newname = "lan." + modality + "." + instance + "." + date + ".IMA" + + shutil.copyfile(path, os.path.join(destdir, newname)) + + + + + diff --git a/doc/libvips-docs.xml.in b/doc/libvips-docs.xml.in index ef1dcf99..2eed5775 100644 --- a/doc/libvips-docs.xml.in +++ b/doc/libvips-docs.xml.in @@ -12,7 +12,7 @@ For VIPS @VIPS_VERSION@. The latest version of this documentation can be found on the VIPS website. + url="http://jcupitt.github.io/libvips/API/current/">VIPS website.