Skip to content

Commit d67f3f6

Browse files
committed
Merge pull request libvips#5 from stanislaw/master
Better markup for your example
2 parents db76c45 + 8c513ed commit d67f3f6

File tree

1 file changed

+184
-179
lines changed

1 file changed

+184
-179
lines changed

README.md

Lines changed: 184 additions & 179 deletions
Original file line numberDiff line numberDiff line change
@@ -55,197 +55,202 @@ ruby-vips has [rdoc documentation](http://rubyvips.holymonkey.com).
5555

5656
## Example.
5757

58-
require 'rubygems'
59-
require 'vips'
60-
include VIPS
58+
```ruby
59+
require 'rubygems'
60+
require 'vips'
61+
include VIPS
6162

62-
# Create an image object. It will not actually load the image until needed.
63-
im = Image.jpeg('mypic.jpg')
63+
# Create an image object. It will not actually load the image until needed.
64+
im = Image.jpeg('mypic.jpg')
6465

65-
# Shrink the jpeg by a factor of four when loading -- huge speed and CPU
66-
# improvements on large images.
67-
im = Image.jpeg('mypic.jpg', :shrink_factor => 4)
66+
# Shrink the jpeg by a factor of four when loading -- huge speed and CPU
67+
# improvements on large images.
68+
im = Image.jpeg('mypic.jpg', :shrink_factor => 4)
6869

69-
# Add a shrink by a factor of two to the pipeline. This will not actually be
70-
# executed yet.
71-
im_shrink_by_two = im.shrink(2)
70+
# Add a shrink by a factor of two to the pipeline. This will not actually be
71+
# executed yet.
72+
im_shrink_by_two = im.shrink(2)
7273

73-
# Write out the shrunk image to a PNG file. This is where the image is
74-
# actually loaded and resized. With images that allow for random access from
75-
# the hard drive (VIPS native format, tiled OpenEXR, ppm/pbm/pgm/pfm, tiled
76-
# tiff, and RAW images), the entire image is never read into memory.
77-
im_shrink_by_two.png('out.png', :interlace => true)
74+
# Write out the shrunk image to a PNG file. This is where the image is
75+
# actually loaded and resized. With images that allow for random access from
76+
# the hard drive (VIPS native format, tiled OpenEXR, ppm/pbm/pgm/pfm, tiled
77+
# tiff, and RAW images), the entire image is never read into memory.
78+
im_shrink_by_two.png('out.png', :interlace => true)
7879

79-
# All ruby-vips image commands can be chained, so the above sequence could
80-
# be written as:
81-
Image.jpeg('mypic.jpg', :shrink_factor => 4).shrink(2).png('out.png')
80+
# All ruby-vips image commands can be chained, so the above sequence could
81+
# be written as:
82+
Image.jpeg('mypic.jpg', :shrink_factor => 4).shrink(2).png('out.png')
8283

83-
# The statement above will load the jpeg (pre-shrunk by a factor of four),
84-
# shrink the image again by a factor of two, and then save as a png image.
84+
# The statement above will load the jpeg (pre-shrunk by a factor of four),
85+
# shrink the image again by a factor of two, and then save as a png image.
8586

86-
# If you want to let vips determine file formats, you can use the generic
87-
# reader and writer:
88-
Image.new('mypic.jpg').shrink(2).write('out.png')
87+
# If you want to let vips determine file formats, you can use the generic
88+
# reader and writer:
89+
Image.new('mypic.jpg').shrink(2).write('out.png')
90+
```
8991

9092
## Longer example
9193

92-
#!/usr/bin/env ruby
93-
94-
require 'rubygems'
95-
require 'vips'
96-
97-
include VIPS
98-
99-
# sample image shrinker for ruby-vips
100-
101-
# handy for leak checking, but not actually a complete shrinker. It takes
102-
# no account of things like colour profiles, for example
103-
#
104-
# see vipsthumbnail, part of the standard vips distrubution, for a complete
105-
# shrink program:
106-
#
107-
# https://github.com/jcupitt/libvips/blob/master/tools/vipsthumbnail.c
108-
#
109-
# this demo ought to be worked up to include all that stuff
110-
111-
# test with:
112-
#
113-
# $ for i in {1..100}; do cp ~/pics/wtc.jpg t_$i.jpg; done
114-
# $ soak.rb t_*.jpg
115-
#
116-
# where wtc.jpg is a 10,000 x 10,000 pixel RGB image
117-
#
118-
# with ruby-vips 0.1.1 and vips-7.28.7 I see a steady ~180mb of memuse as
119-
# this program runs (watching RES in top)
120-
#
121-
# 100mb of this is the vips operation cache, we could disable this to get
122-
# memuse down further if necessary
123-
#
124-
# on my laptop (2009 macbook running ubuntu 12.04):
125-
#
126-
# $ time ./soak.rb t_*.jpg
127-
# real 0m47.809s
128-
# user 0m33.626s
129-
# sys 0m1.516s
130-
#
131-
# ie. about 0.5s real time to do a high-quality shrink of a 10k x 10k
132-
# rgb jpg
133-
134-
# target size we shrink to ... the image will fit inside a size x size box
135-
size = 100
136-
137-
# we apply a slight sharpen to thumbnails to make then "pop" a bit
138-
mask = [
139-
[-1, -1, -1],
140-
[-1, 32, -1,],
141-
[-1, -1, -1]
142-
]
143-
m = Mask.new mask, 24, 0
144-
145-
# show what we do
146-
# verbose = true
147-
verbose = false
148-
149-
ARGV.each do |filename|
150-
puts "loop #{filename} ..."
151-
152-
# get the image size ... ,new() only decompresses pixels on access,
153-
# just opening and getting properties is fast
154-
#
155-
# this will decode small images to a memory buffer, large images to a
156-
# temporary disc file which is then mapped
157-
#
158-
# vips also supports sequential mode access, where the image is
159-
# directly streamed from the source, through the decode library, to
160-
# the destination, but ruby-vips does not yet expose this,
161-
# unfortunately
162-
#
163-
# see
164-
#
165-
# http://libvips.blogspot.co.uk/2012/02/sequential-mode-read.html
166-
#
167-
# enabling this mode would help speed up tiff and png thumbnailing and
168-
# reduce disc traffic, must get around to adding it to ruby-vips
169-
a = Image.new(filename)
170-
171-
# largest dimension
172-
d = [a.x_size, a.y_size].max
173-
174-
shrink = d / size.to_f
175-
puts "shrink of #{shrink}" if verbose
176-
177-
# jpeg images can be shrunk very quickly during load, by a factor of 2,
178-
# 4 or 8
179-
#
180-
# if this is a jpeg, turn on shrink-on-load
181-
#
182-
# a better file type test would be good here :-( vips has a nice one,
183-
# but it's not exposed in ruby-vips yet
184-
if filename.end_with? ".jpg"
185-
if shrink >= 8
186-
load_shrink = 8
187-
elsif shrink >= 4
188-
load_shrink = 4
189-
elsif shrink >= 2
190-
load_shrink = 4
191-
end
192-
193-
puts "jpeg shrink on load of #{load_shrink}" if verbose
194-
195-
a = Image.jpeg(filename, :shrink_factor => load_shrink)
196-
197-
# and recalculate the shrink we need, since the dimensions have changed
198-
d = [a.x_size, a.y_size].max
199-
shrink = d / size.to_f
200-
end
201-
202-
# we shrink in two stages: we use a box filter (each pixel in output
203-
# is the average of a m x n box of pixels in the input) to shrink by
204-
# the largest integer factor we can, then an affine transform to get
205-
# down to the exact size we need
206-
#
207-
# if you just shrink with the affine, you'll get bad aliasing for large
208-
# shrink factors (more than x2)
209-
210-
ishrink = shrink.to_i
211-
212-
# size after int shrink
213-
id = (d / ishrink).to_i
214-
215-
# therefore residual float scale (note! not shrink)
216-
rscale = size.to_f / id
217-
218-
puts "block shrink by #{ishrink}" if verbose
219-
puts "residual scale by #{rscale}" if verbose
220-
221-
# vips has other interpolators, eg. :nohalo ... see the output of
222-
# "vips list classes" at the command-line
223-
#
224-
# :bicubic is well-known and mostly good enough
225-
a = a.shrink(ishrink).affinei_resize(:bicubic, rscale)
226-
227-
# this will look a little "soft", apply a gentle sharpen
228-
a = a.conv(m)
229-
230-
# finally ... write to the output
231-
#
232-
# this call will run the pipeline we have built above across all your
233-
# CPUs, though for a simple pipeline like this you'll be spending
234-
# most of your time in the file import / export libraries, which
235-
# are generally single-threaded
236-
a = JPEGWriter.new(a, {:quality => 50})
237-
a.write('test.jpg')
238-
239-
# force the GC to run and free up any memory vips is hanging on to
240-
#
241-
# without this you'll see memuse slowly climb until ruby runs the GC
242-
# for you
243-
#
244-
# something to make ruby-vips drop refs to vips objects explicitly
245-
# would be nice
246-
GC.start
94+
```ruby
95+
96+
#!/usr/bin/env ruby
97+
98+
require 'rubygems'
99+
require 'vips'
100+
101+
include VIPS
102+
103+
# sample image shrinker for ruby-vips
104+
105+
# handy for leak checking, but not actually a complete shrinker. It takes
106+
# no account of things like colour profiles, for example
107+
#
108+
# see vipsthumbnail, part of the standard vips distrubution, for a complete
109+
# shrink program:
110+
#
111+
# https://github.com/jcupitt/libvips/blob/master/tools/vipsthumbnail.c
112+
#
113+
# this demo ought to be worked up to include all that stuff
114+
115+
# test with:
116+
#
117+
# $ for i in {1..100}; do cp ~/pics/wtc.jpg t_$i.jpg; done
118+
# $ soak.rb t_*.jpg
119+
#
120+
# where wtc.jpg is a 10,000 x 10,000 pixel RGB image
121+
#
122+
# with ruby-vips 0.1.1 and vips-7.28.7 I see a steady ~180mb of memuse as
123+
# this program runs (watching RES in top)
124+
#
125+
# 100mb of this is the vips operation cache, we could disable this to get
126+
# memuse down further if necessary
127+
#
128+
# on my laptop (2009 macbook running ubuntu 12.04):
129+
#
130+
# $ time ./soak.rb t_*.jpg
131+
# real 0m47.809s
132+
# user 0m33.626s
133+
# sys 0m1.516s
134+
#
135+
# ie. about 0.5s real time to do a high-quality shrink of a 10k x 10k
136+
# rgb jpg
137+
138+
# target size we shrink to ... the image will fit inside a size x size box
139+
size = 100
140+
141+
# we apply a slight sharpen to thumbnails to make then "pop" a bit
142+
mask = [
143+
[-1, -1, -1],
144+
[-1, 32, -1,],
145+
[-1, -1, -1]
146+
]
147+
m = Mask.new mask, 24, 0
148+
149+
# show what we do
150+
# verbose = true
151+
verbose = false
152+
153+
ARGV.each do |filename|
154+
puts "loop #{filename} ..."
155+
156+
# get the image size ... ,new() only decompresses pixels on access,
157+
# just opening and getting properties is fast
158+
#
159+
# this will decode small images to a memory buffer, large images to a
160+
# temporary disc file which is then mapped
161+
#
162+
# vips also supports sequential mode access, where the image is
163+
# directly streamed from the source, through the decode library, to
164+
# the destination, but ruby-vips does not yet expose this,
165+
# unfortunately
166+
#
167+
# see
168+
#
169+
# http://libvips.blogspot.co.uk/2012/02/sequential-mode-read.html
170+
#
171+
# enabling this mode would help speed up tiff and png thumbnailing and
172+
# reduce disc traffic, must get around to adding it to ruby-vips
173+
a = Image.new(filename)
174+
175+
# largest dimension
176+
d = [a.x_size, a.y_size].max
177+
178+
shrink = d / size.to_f
179+
puts "shrink of #{shrink}" if verbose
180+
181+
# jpeg images can be shrunk very quickly during load, by a factor of 2,
182+
# 4 or 8
183+
#
184+
# if this is a jpeg, turn on shrink-on-load
185+
#
186+
# a better file type test would be good here :-( vips has a nice one,
187+
# but it's not exposed in ruby-vips yet
188+
if filename.end_with? ".jpg"
189+
if shrink >= 8
190+
load_shrink = 8
191+
elsif shrink >= 4
192+
load_shrink = 4
193+
elsif shrink >= 2
194+
load_shrink = 4
247195
end
248196

197+
puts "jpeg shrink on load of #{load_shrink}" if verbose
198+
199+
a = Image.jpeg(filename, :shrink_factor => load_shrink)
200+
201+
# and recalculate the shrink we need, since the dimensions have changed
202+
d = [a.x_size, a.y_size].max
203+
shrink = d / size.to_f
204+
end
205+
206+
# we shrink in two stages: we use a box filter (each pixel in output
207+
# is the average of a m x n box of pixels in the input) to shrink by
208+
# the largest integer factor we can, then an affine transform to get
209+
# down to the exact size we need
210+
#
211+
# if you just shrink with the affine, you'll get bad aliasing for large
212+
# shrink factors (more than x2)
213+
214+
ishrink = shrink.to_i
215+
216+
# size after int shrink
217+
id = (d / ishrink).to_i
218+
219+
# therefore residual float scale (note! not shrink)
220+
rscale = size.to_f / id
221+
222+
puts "block shrink by #{ishrink}" if verbose
223+
puts "residual scale by #{rscale}" if verbose
224+
225+
# vips has other interpolators, eg. :nohalo ... see the output of
226+
# "vips list classes" at the command-line
227+
#
228+
# :bicubic is well-known and mostly good enough
229+
a = a.shrink(ishrink).affinei_resize(:bicubic, rscale)
230+
231+
# this will look a little "soft", apply a gentle sharpen
232+
a = a.conv(m)
233+
234+
# finally ... write to the output
235+
#
236+
# this call will run the pipeline we have built above across all your
237+
# CPUs, though for a simple pipeline like this you'll be spending
238+
# most of your time in the file import / export libraries, which
239+
# are generally single-threaded
240+
a = JPEGWriter.new(a, {:quality => 50})
241+
a.write('test.jpg')
242+
243+
# force the GC to run and free up any memory vips is hanging on to
244+
#
245+
# without this you'll see memuse slowly climb until ruby runs the GC
246+
# for you
247+
#
248+
# something to make ruby-vips drop refs to vips objects explicitly
249+
# would be nice
250+
GC.start
251+
end
252+
```
253+
249254
## Why use ruby-vips?
250255

251256
- It supports over 250 low-level image and color manipulation operations.

0 commit comments

Comments
 (0)