removed the old whatsnew docs
now part of the gh-pages blog
This commit is contained in:
parent
af2fd6f58b
commit
12e9c369e2
177
whatsnew-8.4.md
177
whatsnew-8.4.md
@ -1,177 +0,0 @@
|
|||||||
libvips 8.4 should be out by the end of September 2016. This page introduces the main features.
|
|
||||||
|
|
||||||
## New operators
|
|
||||||
|
|
||||||
There are some fun new operators. `vips_perlin()` and `vips_worley()`
|
|
||||||
make Perlin and Worley noise. They are useful for generating
|
|
||||||
synthetic random textures. The implementations in vips can generate images of
|
|
||||||
any size very quickly.
|
|
||||||
|
|
||||||
Here's an example of a marble texture simulated with a Perlin noise generator
|
|
||||||
using the Ruby libvips binding.
|
|
||||||
|
|
||||||
```
|
|
||||||
#!/usr/bin/ruby
|
|
||||||
|
|
||||||
require 'vips'
|
|
||||||
|
|
||||||
size = 1024
|
|
||||||
|
|
||||||
# perlin's "turbulence" image
|
|
||||||
def turbulence(size)
|
|
||||||
layers = []
|
|
||||||
iterations = Math.log(size, 2) - 2
|
|
||||||
(0 ... iterations).each do |i|
|
|
||||||
layer = Vips::Image.perlin(size, size, :cell_size => size / 2 ** i)
|
|
||||||
layer = layer.abs * (1.0 / (i + 1))
|
|
||||||
layers << layer
|
|
||||||
end
|
|
||||||
|
|
||||||
layers.reduce(:+)
|
|
||||||
end
|
|
||||||
|
|
||||||
# make a 256 element colour map: a linear fade from start to stop, with
|
|
||||||
# start and stop as CIELAB colours, the output map as sRGB
|
|
||||||
def gradient(start, stop)
|
|
||||||
lut = Vips::Image.identity / 255
|
|
||||||
lut = lut * start + (lut * -1 + 1) * stop
|
|
||||||
lut.colourspace(:srgb, :source_space => :lab)
|
|
||||||
end
|
|
||||||
|
|
||||||
# an image where the pixel value is 0 .. 4 * 360 across
|
|
||||||
angles = Vips::Image.xyz(size, size)[0] * 360 * 4 / size
|
|
||||||
|
|
||||||
# make a turbulent stripe pattern using 0 .. 255
|
|
||||||
stripe = ((angles + turbulence(size) * 700).sin + 1) * 128
|
|
||||||
|
|
||||||
# make a colour map (a smooth gradient from white to dark brown) then map
|
|
||||||
# our turbulent image through it
|
|
||||||
dark_brown = [7.45, 4.3, 8]
|
|
||||||
white = [100, 0, 0]
|
|
||||||
stripe = stripe.maplut(gradient(dark_brown, white))
|
|
||||||
|
|
||||||
stripe.write_to_file ARGV[0]
|
|
||||||
```
|
|
||||||
|
|
||||||
## Rewritten convolution
|
|
||||||
|
|
||||||
The convolution functions were the old vips7 ones with a small
|
|
||||||
wrapper. They've now been rewritten for vips8, and the vector path has
|
|
||||||
been completely replaced. It can be up to about 2x faster.
|
|
||||||
|
|
||||||
The old vips7 vector path was based on int arithmetic, so this mask
|
|
||||||
(a simple 3x3 average), for example:
|
|
||||||
|
|
||||||
```
|
|
||||||
3 3 9 0
|
|
||||||
1 1 1
|
|
||||||
1 1 1
|
|
||||||
1 1 1
|
|
||||||
```
|
|
||||||
|
|
||||||
Would be computed as nine adds, followed by a divide by the constant 9,
|
|
||||||
with round-to-nearest. This was obviously accurate, but dividing
|
|
||||||
by a constant is slow.
|
|
||||||
|
|
||||||
The new path first computes a fixed-point float approximation of the
|
|
||||||
int mask. In this case it'll settle on this:
|
|
||||||
|
|
||||||
```
|
|
||||||
3 3 1 0
|
|
||||||
3 3 3
|
|
||||||
3 4 4
|
|
||||||
4 4 4
|
|
||||||
```
|
|
||||||
|
|
||||||
Where 3 is approximately 1/9 in 3.5 bit fixed-point, and the whole
|
|
||||||
mask sums to 1.0 (the sum of the int mask), or 32 in 3.5 bit.
|
|
||||||
|
|
||||||
It's not possible to match each element and the sum at the same time,
|
|
||||||
so vips uses an iterative algorithm to find the approximation that
|
|
||||||
matches the sum exactly, matches each element as well as it can, and
|
|
||||||
which spreads any error through the mask. In this case, the mix of 3 and 4
|
|
||||||
is there to make the sum work. There's an error test and a fallback:
|
|
||||||
if the maximum possible error is over 10%, it'll switch to a non-vector
|
|
||||||
path based on exact int arithmetic. You can use `--vips-info` to see
|
|
||||||
what path ends up being taken.
|
|
||||||
|
|
||||||
Now there's a fixed-point version of the mask, vips can compute the
|
|
||||||
convolution as 9 fused multiply-adds, followed by an add and a 5-bit shift
|
|
||||||
to get back to the nearest int. Getting rid of the divide-by-a-constant
|
|
||||||
gives a nice speed improvement. On my laptop with vips 8.3 and a 10k x 10k
|
|
||||||
pixel RGB image I see:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ time vips conv wtc.v x7.v avg.mat --vips-info
|
|
||||||
real 0m1.311s
|
|
||||||
user 0m1.376s
|
|
||||||
sys 0m0.372s
|
|
||||||
```
|
|
||||||
|
|
||||||
With vips 8.4 it's now:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ time vips convi wtc.v x8.v avg.mat --vips-info
|
|
||||||
info: convi: using vector path
|
|
||||||
real 0m0.774s
|
|
||||||
user 0m0.888s
|
|
||||||
sys 0m0.352s
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
The peak error is small:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ vips subtract x7.v x8.v x.v
|
|
||||||
$ vips abs x.v x2.v
|
|
||||||
$ vips max x2.v
|
|
||||||
11.000000
|
|
||||||
```
|
|
||||||
|
|
||||||
## Image resize
|
|
||||||
|
|
||||||
`vips_resize()` has seen some good improvements.
|
|
||||||
|
|
||||||
* There's a new `centre` option which switches over to centre-convention for
|
|
||||||
subsampling. This makes it a much better match for ImageMagick.
|
|
||||||
`vipsthumbnail` uses this new option.
|
|
||||||
* It now does round-to-nearest when calculating image bounds. This makes it
|
|
||||||
much simpler to calculate a shrink factor which will produce an image of a
|
|
||||||
specific size.
|
|
||||||
* A series of changes improve accuracy for the linear and cubic kernels, and
|
|
||||||
improve spatial accuracy.
|
|
||||||
* It used to simply use nearest for upsampling, in line with things like PDF,
|
|
||||||
but this is not a good choice for many applications. It now upsizes with
|
|
||||||
bicubic by default.
|
|
||||||
|
|
||||||
## Unicode on Windows
|
|
||||||
|
|
||||||
This is only a small thing, but the Windows build now supports Unicode
|
|
||||||
filenames.
|
|
||||||
|
|
||||||
## File format support
|
|
||||||
|
|
||||||
As usual, there are a lot of improvements to file format read and write.
|
|
||||||
|
|
||||||
* Thanks to work by Felix Bünemann, `webp` read and write supports many more
|
|
||||||
options.
|
|
||||||
* andris has improved `pdfload` so you can load many pages in a single
|
|
||||||
operation.
|
|
||||||
* Many people have worked on `dzsave` Google mode. It's now better at
|
|
||||||
skipping blank tiles and supports tile overlaps. Felix Bünemann added
|
|
||||||
support for compressed zip output.
|
|
||||||
* Henri Chain has added `radsave_buffer` to improve Radiance support.
|
|
||||||
* TIFF files with an orientation tag should now autorotate, `tiffsave`
|
|
||||||
has better jpeg compression support, and it knows about the `strip`
|
|
||||||
metadata option.
|
|
||||||
* The load-via-libMagick operator now supports IM7.
|
|
||||||
* The GIF loader is much smarter about guessing the number of colour channels.
|
|
||||||
* PNG save supports `strip`.
|
|
||||||
* The SVG loader supports `svgz` compressed files thanks to Felix Bünemann.
|
|
||||||
|
|
||||||
## Other
|
|
||||||
|
|
||||||
Improvements to the build system, reductions in memory use, many small
|
|
||||||
bug fixes, improvements to the C++ binding, improvements to the Python binding,
|
|
||||||
many small performance fixes. As usual, the ChanegLog has more detail if
|
|
||||||
you're interested.
|
|
184
whatsnew-8.5.md
184
whatsnew-8.5.md
@ -1,184 +0,0 @@
|
|||||||
libvips 8.5 should be out by the end of March 2017. This page introduces the
|
|
||||||
main features.
|
|
||||||
|
|
||||||
## New operators
|
|
||||||
|
|
||||||
Almost all of the logic from the `vipsthumbnail` program is now in a pair of
|
|
||||||
new operators, `vips_thumbnail()` and `vips_thumbnail_buffer()`. These are very
|
|
||||||
handy for the various scripting languages with vips bindings: you can now make
|
|
||||||
a high-quality, high-speed thumbnail in PHP (for example) with just:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$filename = ...;
|
|
||||||
$image = Vips\Image::thumbnail($filename, 200, ["height" => 200]);
|
|
||||||
$image.writeToFile("my-thumbnail.jpg");
|
|
||||||
```
|
|
||||||
|
|
||||||
The new thumbnail operator has also picked up some useful features:
|
|
||||||
|
|
||||||
* **Smart crop** A new cropping mode called `attention` searches the image for
|
|
||||||
edges, skin tones and areas of saturated colour, and attempts to position the
|
|
||||||
crop box over the most significant feature. There's a `vips_smartcrop()`
|
|
||||||
operator as well.
|
|
||||||
|
|
||||||
* **Crop constraints** Thanks to tomasc, libvips has crop constraints. You
|
|
||||||
can set it to only thumbnail if the image is larger or smaller than the target
|
|
||||||
(the `<` and `>` modifiers in imagemagick), and to crop to a width or height.
|
|
||||||
|
|
||||||
* **Buffer sources** `vips_thumbnail_buffer()` will thumbnail an image held as
|
|
||||||
a formatted block of data in memory. This is useful for cloud services, where
|
|
||||||
the filesystem is often rather slow.
|
|
||||||
|
|
||||||
CLAHE, or Contrast-Limited Adaptive Histogram Equalisation, is a simple way to
|
|
||||||
make local histogram equalisation more useful.
|
|
||||||
|
|
||||||
Plain local equalization removes
|
|
||||||
all global brightness variation and can make images hard to understand.
|
|
||||||
The `hist_local` operator now has a `max-slope` parameter you can use to limit
|
|
||||||
how much equalisation can alter your image. A value of 3 generally works well.
|
|
||||||
|
|
||||||
## Toilet roll images
|
|
||||||
|
|
||||||
libvips used to let you pick single pages out of multi-page images, such
|
|
||||||
as PDFs, but had little support for processing entire documents.
|
|
||||||
|
|
||||||
libvips 8.5 now has good support for toilet roll images. You can load a
|
|
||||||
multipage image as a very tall, thin strip, process the whole thing, and write
|
|
||||||
back to another multi-page file. The extra feature is an `n` parameter which
|
|
||||||
gives the number of pages to load, or -1 to load all pages.
|
|
||||||
|
|
||||||
For example, (OME-
|
|
||||||
TIFF)[https://www.openmicroscopy.org/site/support/ome-model/ome-tiff]
|
|
||||||
is a standard for microscopy data that stores volumetric images as multi-page
|
|
||||||
TIFFs. They have some (sample
|
|
||||||
data)[https://www.openmicroscopy.org/site/support/ome-model/ome-tiff/data.html]
|
|
||||||
including a 4D image of an embryo.
|
|
||||||
|
|
||||||
Each TIFF contains 10 slices. Normally you just see page 0:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ vipsheader tubhiswt_C0_TP13.ome.tif
|
|
||||||
tubhiswt_C0_TP13.ome.tif: 512x512 uchar, 1 band, b-w, tiffload
|
|
||||||
```
|
|
||||||
|
|
||||||
Use `n=-1` and you see all the pages as a very tall strip:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ vipsheader tubhiswt_C0_TP13.ome.tif[n=-1]
|
|
||||||
tubhiswt_C0_TP13.ome.tif: 512x5120 uchar, 1 band, b-w, tiffload
|
|
||||||
```
|
|
||||||
|
|
||||||
You can work with PDF, TIFF, GIF and all imagemagick-supported formats in
|
|
||||||
this way.
|
|
||||||
|
|
||||||
You can write this tall strip to another file, and it will be broken up into
|
|
||||||
pages:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ vips copy tubhiswt_C0_TP13.ome.tif[n=-1] x.tif
|
|
||||||
$ vipsheader x.tif
|
|
||||||
x.tif: 512x512 uchar, 1 band, b-w, tiffload
|
|
||||||
$ vipsheader x.tif[n=-1]
|
|
||||||
x.tif: 512x5120 uchar, 1 band, b-w, tiffload
|
|
||||||
```
|
|
||||||
|
|
||||||
The extra magic is a `page-height` property that images carry around that says
|
|
||||||
how long each sheet of toilet paper is.
|
|
||||||
|
|
||||||
There are clearly some restrictions with this style of multi-page document
|
|
||||||
handling: all pages must have identical width, height and colour depth; and image
|
|
||||||
processing operators have no idea they are dealing with a multi-page document,
|
|
||||||
so if you do something like `resize`, you'll need to update `page-height`.
|
|
||||||
You'll also need to be careful about edge effects if you're using spatial
|
|
||||||
filters.
|
|
||||||
|
|
||||||
## Computation reordering
|
|
||||||
|
|
||||||
Thanks to the developer of
|
|
||||||
(PhotoFlow)[https://github.com/aferrero2707/PhotoFlow], a non-destructive image
|
|
||||||
editor with a libvips backend, libvips can now reorder computations to reduce
|
|
||||||
recalculation. This can (sometimes) produce a dramatic speedup.
|
|
||||||
|
|
||||||
This has been (discussed on the libvips
|
|
||||||
blog)[http://libvips.blogspot.co.uk/2017/01/automatic-computation-reordering.html],
|
|
||||||
but briefly, the order in which operator arguments are evaluated can have a
|
|
||||||
big effect on runtime due to the way libvips tries to cache and reuse results
|
|
||||||
behind the scenes.
|
|
||||||
|
|
||||||
The blog post has some examples and some graphs.
|
|
||||||
|
|
||||||
## New sequential mode
|
|
||||||
|
|
||||||
libvips sequential mode has been around for a while. This is the thing libvips
|
|
||||||
uses to stream pixels through your computer, from input file to output file,
|
|
||||||
without having to have the whole image in memory all at the same time. When it
|
|
||||||
works, it give a nice performance boost and a large drop in memory use.
|
|
||||||
|
|
||||||
There are some more complex cases where it didn't work. Consider this Python
|
|
||||||
program:
|
|
||||||
|
|
||||||
```python
|
|
||||||
#!/usr/bin/python
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import random
|
|
||||||
|
|
||||||
import gi
|
|
||||||
gi.require_version('Vips', '8.0')
|
|
||||||
from gi.repository import Vips
|
|
||||||
|
|
||||||
composite = Vips.Image.black(10000, 10000)
|
|
||||||
|
|
||||||
for filename in sys.argv[2:]:
|
|
||||||
tile = Vips.Image.new_from_file(filename, access = Vips.Access.SEQUENTIAL)
|
|
||||||
x = random.randint(0, composite.width - tile.width)
|
|
||||||
y = random.randint(0, composite.height - tile.height)
|
|
||||||
composite = composite.insert(tile, x, y)
|
|
||||||
|
|
||||||
composite.write_to_file(sys.argv[1])
|
|
||||||
```
|
|
||||||
|
|
||||||
It makes a large 10,000 x 10,000 pixel image, then inserts all of the images
|
|
||||||
you list at random positions, then writes the result.
|
|
||||||
|
|
||||||
You'd think this could work with sequential mode, but sadly with earlier
|
|
||||||
libvipses it will sometimes fail. The problem is that images can cover each
|
|
||||||
other, so while writing, libvips can discover that it only needs the bottom few
|
|
||||||
pixels of one of the input images. The image loaders used to track the current
|
|
||||||
read position, and if a request came in for some pixels way down the image,
|
|
||||||
they'd assume one of the evaluation threads had run ahead of the rest and
|
|
||||||
needed to be stalled. Once stalled, it was only restarted on a long timeout,
|
|
||||||
causing performance to drop through the floor.
|
|
||||||
|
|
||||||
libvips 8.5 has a new implementation of sequential mode that changes the way
|
|
||||||
threads are kept together as images are processed. Rather than trying to add
|
|
||||||
constraints to load operations, instead it puts the constraints into operations
|
|
||||||
that can cause threads to become spread out, such as vertical shrink.
|
|
||||||
|
|
||||||
As a result of this change, many more things can run in sequential mode, and
|
|
||||||
out of order reads should be impossible.
|
|
||||||
|
|
||||||
## `libxml2` swapped out for `expat`
|
|
||||||
|
|
||||||
libvips has used libxml2 as its XML parser since dinosaurs roamed the Earth.
|
|
||||||
Now libvips is based on gobject, the XML parser selected by glib, expat, makes
|
|
||||||
more sense, since it will already be linked.
|
|
||||||
|
|
||||||
It's nice to be able to remove a required dependency for a change.
|
|
||||||
|
|
||||||
## File format support
|
|
||||||
|
|
||||||
As usual, there are a range of improvements to file format read and write.
|
|
||||||
|
|
||||||
* Thanks to a push from Felix Bünemann, TIFF now supports load and save to and
|
|
||||||
from memory buffers.
|
|
||||||
* `dzsave` can write to memory (as a zip file) as well.
|
|
||||||
* Again, thanks to pushing from Felix, libvips now supports ICC, XMP and IPCT
|
|
||||||
metadata for WebP images.
|
|
||||||
* FITS images support `bzero` and `bscale`.
|
|
||||||
* `tiffload` memory use is now much lower for images with large strips.
|
|
||||||
|
|
||||||
## Other
|
|
||||||
|
|
||||||
Many small bug fixes, improvements to the C++ binding. As usual, the
|
|
||||||
ChangeLog has more detail, if you're interested.
|
|
Loading…
Reference in New Issue
Block a user