Skip to content

Commit a5b0409

Browse files
committed
Merge branch 'add-markdown-docs' into 8.5
2 parents c2cb4c3 + 887eb24 commit a5b0409

28 files changed

+2270
-32
lines changed

ChangeLog

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
25/3/17 started 8.5.2
22
- better behaviour for truncated PNG files, thanks Yury
33
- missing proto for vips_tiffsave_buffer(), thanks greut
4+
- move some docs from the wiki and blog into core libvips docs
5+
- add support for markdown in docs
46

57
25/3/17 started 8.5.1
68
- init more classes earlier, thanks David

TODO

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
- add analytics tags to docs output
2+
13
- not sure about utf8 error messages on win
24

35
- strange:

autogen.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ find doc -depth \( \
2727
-o -path 'doc/images/*' \
2828
-o -name '*.xml' ! -name libvips-docs.xml ! -path 'doc/xml/*' \
2929
-o -name '*.py' \
30+
-o -name '*.md' \
31+
-o -name '*.docbook' \
3032
\) -prune -or \( \
3133
-type f \
3234
-o -type d -empty \

doc/Examples.md

Lines changed: 326 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,326 @@
1+
<refmeta>
2+
<refentrytitle>Examples</refentrytitle>
3+
<manvolnum>3</manvolnum>
4+
<refmiscinfo>libvips</refmiscinfo>
5+
</refmeta>
6+
7+
<refnamediv>
8+
<refname>libvips examples</refname>
9+
<refpurpose>A few example Python programs using libvips</refpurpose>
10+
</refnamediv>
11+
12+
This page shows a few libvips examples using Python. They will work with small syntax
13+
changes in any language with a libvips binding.
14+
15+
The libvips test suite is written in Python and exercises every operation in the API.
16+
It's also a useful source of examples.
17+
18+
# Average a region of interest box on an image
19+
20+
``` python
21+
#!/usr/bin/env python
22+
23+
import sys
24+
import gi
25+
gi.require_version('Vips', '8.0')
26+
from gi.repository import Vips
27+
28+
left = 10
29+
top = 10
30+
width = 64
31+
height = 64
32+
33+
image = Vips.Image.new_from_file(sys.argv[1])
34+
roi = image.crop(left, top, width, height)
35+
print 'average:', roi.avg()
36+
```
37+
38+
# libvips and numpy
39+
40+
You can use `Vips.Image.new_from_memory_copy()` to make a vips image from an area of
41+
memory. The memory array needs to be laid out band-interleaved, as a set of scanlines,
42+
with no padding between lines.
43+
44+
This example moves an image from numpy to vips, but it's simple to move the other way
45+
(use `Vips.Image.write_to_memory()`) to to move images into or out of PIL.
46+
47+
```python
48+
#!/usr/bin/python
49+
50+
import numpy
51+
import scipy.ndimage
52+
import gi
53+
gi.require_version('Vips', '8.0')
54+
from gi.repository import Vips
55+
56+
def np_dtype_to_vips_format(np_dtype):
57+
'''
58+
Map numpy data types to VIPS data formats.
59+
60+
Parameters
61+
----------
62+
np_dtype: numpy.dtype
63+
64+
Returns
65+
-------
66+
gi.overrides.Vips.BandFormat
67+
'''
68+
lookup = {
69+
numpy.dtype('int8'): Vips.BandFormat.CHAR,
70+
numpy.dtype('uint8'): Vips.BandFormat.UCHAR,
71+
numpy.dtype('int16'): Vips.BandFormat.SHORT,
72+
numpy.dtype('uint16'): Vips.BandFormat.USHORT,
73+
numpy.dtype('int32'): Vips.BandFormat.INT,
74+
numpy.dtype('float32'): Vips.BandFormat.FLOAT,
75+
numpy.dtype('float64'): Vips.BandFormat.DOUBLE
76+
}
77+
return lookup[np_dtype]
78+
79+
def np_array_to_vips_image(array):
80+
'''
81+
Convert a `numpy` array to a `Vips` image object.
82+
83+
Parameters
84+
----------
85+
nparray: numpy.ndarray
86+
87+
Returns
88+
-------
89+
gi.overrides.Vips.image
90+
'''
91+
# Look up what VIPS format corresponds to the type of this np array
92+
vips_format = np_dtype_to_vips_format(array.dtype)
93+
dims = array.shape
94+
height = dims[0]
95+
width = 1
96+
bands = 1
97+
if len(dims) > 1:
98+
width = dims[1]
99+
if len(dims) > 2:
100+
bands = dims[2]
101+
img = Vips.Image.new_from_memory_copy(array.data,
102+
width, height, bands, vips_format)
103+
104+
return img
105+
106+
array = numpy.random.random((10,10))
107+
vips_image = np_array_to_vips_image(array)
108+
print 'avg =', vips_image.avg()
109+
110+
array = scipy.ndimage.imread("test.jpg")
111+
vips_image = np_array_to_vips_image(array)
112+
print 'avg =', vips_image.avg()
113+
vips_image.write_to_file("test2.jpg")
114+
```
115+
116+
# Watermarking
117+
118+
This example renders a simple watermark on an image. Use it like this:
119+
120+
121+
```
122+
./watermark.py somefile.png output.jpg "hello <i>world</i>"
123+
```
124+
125+
The text is rendered in transparent red pixels all over the image. It knows about
126+
transparency, CMYK, and 16-bit images.
127+
128+
```python
129+
#!/usr/bin/python
130+
131+
import sys
132+
import gi
133+
gi.require_version('Vips', '8.0')
134+
from gi.repository import Vips
135+
136+
im = Vips.Image.new_from_file(sys.argv[1], access = Vips.Access.SEQUENTIAL)
137+
138+
text = Vips.Image.text(sys.argv[3], width = 500, dpi = 300)
139+
text = (text * 0.3).cast("uchar")
140+
text = text.embed(100, 100, text.width + 200, text.width + 200)
141+
text = text.replicate(1 + im.width / text.width, 1 + im.height / text.height)
142+
text = text.crop(0, 0, im.width, im.height)
143+
144+
# we want to blend into the visible part of the image and leave any alpha
145+
# channels untouched ... we need to split im into two parts
146+
147+
# 16-bit images have 65535 as white
148+
if im.format == Vips.BandFormat.USHORT:
149+
white = 65535
150+
else:
151+
white = 255
152+
153+
# guess how many bands from the start of im contain visible colour information
154+
if im.bands >= 4 and im.interpretation == Vips.Interpretation.CMYK:
155+
# cmyk image ... put the white into the magenta channel
156+
n_visible_bands = 4
157+
text_colour = [0, white, 0, 0]
158+
elif im.bands >= 3:
159+
# colour image ... put the white into the red channel
160+
n_visible_bands = 3
161+
text_colour = [white, 0, 0]
162+
else:
163+
# mono image
164+
n_visible_bands = 1
165+
text_colour = white
166+
167+
# split into image and alpha
168+
if im.bands - n_visible_bands > 0:
169+
alpha = im.extract_band(n_visible_bands, n = im.bands - n_visible_bands)
170+
im = im.extract_band(0, n = n_visible_bands)
171+
else:
172+
alpha = None
173+
174+
# blend means do a smooth fade using the 0 - 255 values in the condition channel
175+
# (test in this case) ... this will render the anit-aliasing
176+
im = text.ifthenelse(text_colour, im, blend = True)
177+
178+
# reattach alpha
179+
if alpha:
180+
im = im.bandjoin(alpha)
181+
182+
im.write_to_file(sys.argv[2])
183+
184+
```
185+
186+
# Build huge image mosaic
187+
188+
This makes a 100,000 x 100,000 black image, then inserts all the images you pass on the
189+
command-line into it at random positions. libvips is able to run this program in
190+
sequential mode: it'll open all the input images at the same time, and stream pixels from
191+
them as it needs them to generate the output.
192+
193+
To test it, first make a large 1-bit image. This command will take the green channel and
194+
write as a 1-bit fax image. `wtc.jpg` is a test 10,000 x 10,000 jpeg:
195+
196+
```
197+
$ vips extract_band wtc.jpg x.tif[squash,compression=ccittfax4,strip] 1
198+
```
199+
200+
Now make 1,000 copies of that image in a subdirectory:
201+
202+
```
203+
$ mkdir test
204+
$ for i in {1..1000}; do cp x.tif test/$i.tif; done
205+
```
206+
207+
And run this Python program on them:
208+
209+
```
210+
$ time ./try255.py x.tif[squash,compression=ccittfax4,strip,bigtif] test/*
211+
real 1m59.924s
212+
user 4m5.388s
213+
sys 0m8.936s
214+
```
215+
216+
It completes in just under two minutes on this laptop, and needs about
217+
7gb of RAM to run. It would need about the same amount of memory for a
218+
full-colour RGB image, I was just keen to keep disc usage down.
219+
220+
If you wanted to handle transparency, or if you wanted mixed CMYK and RGB images, you'd
221+
need to do some more work to convert them all into the same colourspace before
222+
inserting them.
223+
224+
``` python
225+
#!/usr/bin/env python
226+
227+
import sys
228+
import random
229+
230+
import gi
231+
gi.require_version('Vips', '8.0')
232+
from gi.repository import Vips
233+
234+
# turn on progress reporting
235+
Vips.progress_set(True)
236+
237+
# this makes a 8-bit, mono image of 100,000 x 100,000 pixels, each pixel zero
238+
im = Vips.Image.black(100000, 100000)
239+
240+
for filename in sys.argv[2:]:
241+
tile = Vips.Image.new_from_file(filename, access = Vips.Access.SEQUENTIAL)
242+
243+
im = im.insert(tile,
244+
random.randint(0, im.width - tile.width),
245+
random.randint(0, im.height - tile.height))
246+
247+
im.write_to_file(sys.argv[1])
248+
249+
```
250+
251+
# Rename DICOM images using header fields
252+
253+
DICOM images commonly come in an awful directory hierarchy named as something
254+
like `images/a/b/e/z04`. There can be thousands of files and it can be very
255+
hard to find the one you want.
256+
257+
This utility copies files to a single flat directory, naming them using
258+
fields from the DICOM header. You can actually find stuff! Useful.
259+
260+
```python
261+
#!/usr/bin/env python
262+
263+
import sys
264+
import re
265+
import os
266+
import shutil
267+
268+
import gi
269+
gi.require_version('Vips', '8.0')
270+
from gi.repository import Vips
271+
272+
if len(sys.argv) != 3:
273+
print 'rename DICOM files using tags from the header'
274+
sys.exit(1)
275+
276+
srcdir = sys.argv[1]
277+
destdir = sys.argv[2]
278+
279+
if not os.access(destdir, os.F_OK | os.R_OK | os.W_OK | os.X_OK):
280+
os.mkdir(destdir)
281+
282+
def get_field(vim, field):
283+
result = vim.get_value(field)
284+
285+
# remove any \n etc.
286+
result = re.sub("\n", "", result)
287+
288+
# remove any leading or trailing spaces
289+
result = re.sub(" $", "", result)
290+
result = re.sub("^ ", "", result)
291+
292+
return result
293+
294+
modality_name = "magick-dcm:Modality"
295+
series_name = "magick-dcm:SeriesNumber"
296+
instance_name = "magick-dcm:Instance(formerlyImage)Number"
297+
date_name = "magick-dcm:ImageDate"
298+
299+
for(dirpath, dirnames, filenames) in os.walk(srcdir):
300+
for file in filenames:
301+
path = os.path.join(dirpath, file)
302+
303+
try:
304+
vim = Vips.Image.new_from_file(path)
305+
except Vips.Error, e:
306+
print 'unable to open', path
307+
print e
308+
continue
309+
310+
try:
311+
modality = get_field(vim, modality_name)
312+
series = get_field(vim, series_name)
313+
instance = get_field(vim, instance_name)
314+
date = get_field(vim, date_name)
315+
except Vips.Error, e:
316+
print 'unable to get fields from header', path
317+
print e
318+
continue
319+
320+
match = re.match("(\d\d\d\d)(\d\d)(\d\d)", date)
321+
date = match.group(1) + "." + match.group(2) + "." + match.group(3)
322+
323+
newname = "lan." + modality + "." + instance + "." + date + ".IMA"
324+
325+
shutil.copyfile(path, os.path.join(destdir, newname))
326+
```

0 commit comments

Comments
 (0)