├── sample2.v ├── memtrace.ods ├── combined.xlsx ├── composer.json ├── .gitignore ├── bench.ijm ├── ffmpeg.sh ├── gm.sh ├── netpbm.sh ├── ei.sh ├── vips.nip4 ├── vips.nip2 ├── gmic.sh ├── sips.sh ├── is.rb ├── ruby-vips.rb ├── imwand.py ├── vips.sh ├── image.pike ├── oiio.sh ├── rmagick.rb ├── lua-vips.lua ├── vips.js ├── vips.py ├── octave.m ├── ymagine.sh ├── opencvcopy.cc ├── vips.php ├── im.sh ├── im7.sh ├── imagick.php ├── scikit.py ├── pillow.py ├── vips-gegl.py ├── gegl.xml ├── vips.cc ├── opencv.cc ├── freeimage.c ├── combine.rb ├── imlib2.c ├── parse-top.rb ├── opencv-umat.cc ├── parse-ps.rb ├── vips.c ├── gd.c ├── README.md ├── peakmem.pl ├── gegl.c ├── ymagine.c ├── try.sh ├── tracemem.rb ├── gegl5x5.c ├── composer.lock ├── benchmark.sh ├── nip4.ws └── nip2-gegl.ws /sample2.v: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libvips/vips-bench/HEAD/sample2.v -------------------------------------------------------------------------------- /memtrace.ods: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libvips/vips-bench/HEAD/memtrace.ods -------------------------------------------------------------------------------- /combined.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libvips/vips-bench/HEAD/combined.xlsx -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": { 3 | "jcupitt/vips" : "@dev" 4 | } 5 | 6 | } 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | *.swp 3 | *.csv 4 | *.pyc 5 | tmp 6 | freeimage 7 | mask* 8 | opencv 9 | vips-cc 10 | imlib2 11 | ymagine-c 12 | vips8-cc 13 | vips-c 14 | gd 15 | tmp 16 | gegl 17 | a.out 18 | -------------------------------------------------------------------------------- /bench.ijm: -------------------------------------------------------------------------------- 1 | makeRectangle(100, 100, 4800, 4800); 2 | run("Crop"); 3 | run("Size...", "width=4320 height=4271 constrain average interpolation=Bilinear"); 4 | run("Convolve...", "text1=[-1 -1 -1\n-1 16 -1\n-1 -1 -1\n] normalize"); 5 | saveAs("tiff", "tmp/x2.tif"); 6 | -------------------------------------------------------------------------------- /ffmpeg.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | crop="iw-200:ih-200:100:100" 4 | scale="iw*.9:ih*.9" 5 | kernel="-1 -1 -1 -1 16 -1 -1 -1 -1" 6 | conv="$kernel:$kernel:$kernel:$kernel:1/8:1/8:1/8:1/8" 7 | 8 | ffmpeg -y -i $1 -vf "crop=$crop, scale=$scale, convolution=$conv" $2 9 | -------------------------------------------------------------------------------- /gm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # set -x 4 | 5 | # use mmap for image input 6 | #export MAGICK_MMAP_READ=TRUE 7 | 8 | gm convert $1 \ 9 | -shave 100x100 \ 10 | -filter triangle -resize 90x90% \ 11 | -convolve "-1, -1, -1, -1, 16, -1, -1, -1, -1" \ 12 | $2 13 | -------------------------------------------------------------------------------- /netpbm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cat > mask < /dev/null | \ 13 | pnmcut -left 100 -right -100 -top 100 -bottom -100 | \ 14 | pnmscale 0.9 | \ 15 | pnmconvol mask | \ 16 | pnmtotiff -truecolor -color 2> /dev/null > $2 17 | -------------------------------------------------------------------------------- /ei.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | width=$(vipsheader -f Xsize $1) 4 | height=$(vipsheader -f Ysize $1) 5 | 6 | width=$((width - 200)) 7 | height=$((height - 200)) 8 | 9 | # set -x 10 | 11 | econvert -i $1 \ 12 | --crop "100,100,$width,$height" \ 13 | --bilinear-scale 0.9 \ 14 | --convolve "-1, -1, -1, -1, 16, -1, -1, -1, -1" \ 15 | -o $2 16 | -------------------------------------------------------------------------------- /vips.nip4: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env nip4-batch 2 | 3 | main 4 | = error "usage: infile -o outfile", argc != 2 5 | = (sharpen @ shrink @ crop) (Image_file argv?1) 6 | { 7 | crop x = extract_area 100 100 (x.width - 200) (x.height - 200) x; 8 | shrink = resize Kernel_linear 0.9 0.9; 9 | sharpen = conv (Matrix_con 8 0 [[-1, -1, -1], [-1, 16, -1], [-1, -1, -1]]); 10 | } 11 | -------------------------------------------------------------------------------- /vips.nip2: -------------------------------------------------------------------------------- 1 | #!/home/john/vips/bin/nip2 -s 2 | 3 | main 4 | = error "usage: infile -o outfile", argc != 2 5 | = (sharpen @ shrink @ crop ) (Image_file argv?1) 6 | { 7 | crop x = extract_area 100 100 (x.width - 200) (x.height - 200) x; 8 | shrink = resize Kernel_linear 0.9 0.9; 9 | sharpen = conv (Matrix_con 8 0 [[-1, -1, -1], [-1, 16, -1], [-1, -1, -1]]); 10 | } 11 | -------------------------------------------------------------------------------- /gmic.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | width=$(vipsheader -f Xsize $1) 4 | height=$(vipsheader -f Ysize $1) 5 | crop_width=$((width - 200)) 6 | crop_height=$((height - 200)) 7 | 8 | gmic \ 9 | -verbose - \ 10 | -input $1 \ 11 | -crop 100,100,$crop_width,$crop_height \ 12 | -resize 90%,90%,1,3,3,1 \ 13 | "(-1,-1,-1;-1,9,-1;-1,-1,-1)" -convolve[-2] [-1] -keep[-2] \ 14 | -output $2,uchar 15 | -------------------------------------------------------------------------------- /sips.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | width=$(vipsheader -f Xsize $1) 4 | height=$(vipsheader -f Ysize $1) 5 | 6 | crop_width=$((width - 200)) 7 | crop_height=$((height - 200)) 8 | 9 | resize_width=$((crop_width * 9 / 10)) 10 | 11 | # set -x 12 | 13 | sips \ 14 | --cropToHeightWidth $crop_height $crop_width \ 15 | --resampleWidth $resize_width \ 16 | $1 --out $2 &> /dev/null 17 | 18 | -------------------------------------------------------------------------------- /is.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # gem install image_science 4 | 5 | require 'rubygems' 6 | require 'image_science' 7 | 8 | ImageScience.with_image(ARGV[0]) do |img| 9 | img.with_crop(100, 100, img.width() - 100, img.height() - 100) do |crop| 10 | crop.resize(crop.width() * 0.9, crop.height() * 0.9) do |small| 11 | small.save(ARGV[1]) 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /ruby-vips.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'vips' 4 | 5 | im = Vips::Image.new_from_file ARGV[0] 6 | 7 | im = im.crop 100, 100, im.width - 200, im.height - 200 8 | im = im.reduce 1.0 / 0.9, 1.0 / 0.9, kernel: :linear 9 | mask = Vips::Image.new_from_array [ 10 | [-1, -1, -1], 11 | [-1, 16, -1], 12 | [-1, -1, -1]], 8 13 | im = im.conv mask, precision: "integer" 14 | 15 | im.write_to_file ARGV[1] 16 | 17 | -------------------------------------------------------------------------------- /imwand.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from sys import argv 4 | from wand.image import Image 5 | 6 | input = argv[1] 7 | output = argv[2] 8 | 9 | with Image(filename=input) as img: 10 | img.shave(100, 100) 11 | img.resize(round(0.9 * img.width), round(0.9 * img.height), 'triangle') 12 | img.morphology(method='convolve', kernel='3x3: -0.125, -0.125, -0.125, -0.125, 2, -0.125, -0.125, -0.125, -0.125') 13 | img.save(filename=output) 14 | -------------------------------------------------------------------------------- /vips.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | width=$(vipsheader -f Xsize $1) 4 | height=$(vipsheader -f Ysize $1) 5 | 6 | width=$((width - 200)) 7 | height=$((height - 200)) 8 | 9 | # set -x 10 | 11 | vips crop $1 t1.v 100 100 $width $height 12 | vips reduce t1.v t2.v 1.111 1.111 --kernel linear 13 | 14 | cat > mask.con <copy(100, 100, 8 | image->xsize() - 101, image->ysize() - 101); 9 | 10 | image = image->scale(0.9); 11 | 12 | image = image->apply_matrix( 13 | ({({-1,-1,-1}), 14 | ({-1,16,-1}), 15 | ({-1,-1,-1})})); 16 | 17 | Stdio.write_file(argv[2], Image.TIFF.encode(image)); 18 | 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /oiio.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | width=$(vipsheader -f Xsize $1) 4 | height=$(vipsheader -f Ysize $1) 5 | 6 | width=$((width - 200)) 7 | height=$((height - 200)) 8 | 9 | # resize with triangle is bilinear 10 | 11 | # this will blur rather than sharpen, but the speed should be the same 12 | 13 | oiiotool $1 \ 14 | --crop $widthx$height+100+100 --origin +0+0 --fullpixels \ 15 | --resize:filter=triangle 90% \ 16 | --kernel gaussian 3x3 --convolve \ 17 | -o $2 18 | -------------------------------------------------------------------------------- /rmagick.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # gem install rmagick 4 | 5 | require 'rubygems' 6 | require 'rmagick' 7 | 8 | include Magick 9 | 10 | im = ImageList.new(ARGV[0]) 11 | 12 | im = im.shave(100, 100) 13 | # Triangle is bilinear for small size changes 14 | im = im.resize(im.columns * 0.9, im.rows * 0.9, filter = TriangleFilter) 15 | kernel = [-1, -1, -1, -1, 16, -1, -1, -1, -1] 16 | im = im.convolve(3, kernel) 17 | 18 | im.write(ARGV[1]) 19 | -------------------------------------------------------------------------------- /lua-vips.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/luajit 2 | 3 | vips = require("vips") 4 | 5 | image = vips.Image.new_from_file(arg[1]) 6 | 7 | image = image:crop(100, 100, image:width() - 200, image:height() - 200) 8 | 9 | image = image:reduce(1.0 / 0.9, 1.0 / 0.9, {kernel = "linear"}) 10 | 11 | mask = vips.Image.new_from_array( 12 | {{-1, -1, -1}, 13 | {-1, 16, -1}, 14 | {-1, -1, -1}}, 8) 15 | image = image:conv(mask, {precision = "integer"}) 16 | 17 | image:write_to_file(arg[2]); 18 | -------------------------------------------------------------------------------- /vips.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var vips = require('../node-vips'); 4 | 5 | image = vips.Image.newFromFile(process.argv[2]); 6 | 7 | image = image.crop(100, 100, image.width - 200, image.height - 200); 8 | 9 | image = image.reduce(1.0 / 0.9, 1.0 / 0.9, {kernel: 'linear'}); 10 | 11 | mask = vips.Image.newFromArray( 12 | [[-1, -1, -1], 13 | [-1, 16, -1], 14 | [-1, -1, -1]], 8); 15 | image = image.conv(mask, {precision: 'integer'}); 16 | 17 | image.writeToFile(process.argv[3]); 18 | -------------------------------------------------------------------------------- /vips.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import sys 4 | import pyvips 5 | 6 | im = pyvips.Image.new_from_file(sys.argv[1]) 7 | 8 | im = im.crop(100, 100, im.width - 200, im.height - 200) 9 | im = im.reduce(1.0 / 0.9, 1.0 / 0.9, kernel='linear') 10 | mask = pyvips.Image.new_from_array([[-1, -1, -1], 11 | [-1, 16, -1], 12 | [-1, -1, -1]], scale=8) 13 | im = im.conv(mask, precision='integer') 14 | 15 | im.write_to_file(sys.argv[2]) 16 | -------------------------------------------------------------------------------- /octave.m: -------------------------------------------------------------------------------- 1 | #!/usr/bin/octave -qf 2 | 3 | % we see some annoying warnings from GM without this 4 | warning("off") 5 | 6 | pkg load image 7 | 8 | im = imread(argv(){1}); 9 | im = im(101:end-100, 101:end-100); % Crop 10 | im = imresize(im, 0.9, 'linear'); % Shrink 11 | myFilter = [-1 -1 -1 12 | -1 16 -1 13 | -1 -1 -1]; 14 | im = conv2(double(im), myFilter); % Sharpen 15 | im = max(0, im ./ (max(max(im)) / 255)); % Renormalize 16 | imwrite(uint8(im), argv(){2}); % write back 17 | 18 | -------------------------------------------------------------------------------- /ymagine.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | #set -x 4 | 5 | YMAGINE=/home/john/ymagine/out/target/linux-x86_64/bin/ymagine 6 | 7 | width=$(vipsheader -f width $1) 8 | height=$(vipsheader -f height $1) 9 | 10 | width=$((width - 200)) 11 | height=$((height - 200)) 12 | 13 | shrunk_width=`bc < 16 | #include 17 | 18 | using namespace cv; 19 | 20 | int 21 | main (int argc, char **argv) 22 | { 23 | Ptr < IplImage > t1; 24 | 25 | if (!(t1 = cvLoadImage (argv[1]))) 26 | return 1; 27 | cvSaveImage (argv[2], t1); 28 | 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /vips.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | Vips\Access::SEQUENTIAL, 10 | ]); 11 | 12 | $im = $im->crop(100, 100, $im->width - 200, $im->height - 200); 13 | 14 | $im = $im->reduce(1.0 / 0.9, 1.0 / 0.9, ["kernel" => "linear"]); 15 | 16 | $mask = Vips\Image::newFromArray( 17 | [[-1, -1, -1], 18 | [-1, 16, -1], 19 | [-1, -1, -1]], 8); 20 | $im = $im->conv($mask, ["precision" => "integer"]); 21 | 22 | $im->writeToFile($argv[2]); 23 | -------------------------------------------------------------------------------- /im.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # we crop on load, it's a bit quicker and saves some memory 4 | # we can't crop 100 pixels with the crop-on-load syntax, so we have to 5 | # find the width and height ourselves 6 | width=$(vipsheader -f Xsize $1) 7 | height=$(vipsheader -f Ysize $1) 8 | 9 | width=$((width - 200)) 10 | height=$((height - 200)) 11 | 12 | # set -x 13 | 14 | # -filter triangle acts as bilinear with -resize and small size changes 15 | 16 | convert "$1[${width}x${height}+100+100]" \ 17 | -filter triangle -resize 90x90% \ 18 | -convolve "-1, -1, -1, -1, 16, -1, -1, -1, -1" \ 19 | $2 20 | -------------------------------------------------------------------------------- /im7.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # we crop on load, it's a bit quicker and saves some memory 4 | # we can't crop 100 pixels with the crop-on-load syntax, so we have to 5 | # find the width and height ourselves 6 | width=$(vipsheader -f Xsize $1) 7 | height=$(vipsheader -f Ysize $1) 8 | 9 | width=$((width - 200)) 10 | height=$((height - 200)) 11 | 12 | # set -x 13 | 14 | # -filter triangle acts as bilinear with -resize and small size changes 15 | 16 | magick "$1[${width}x${height}+100+100]" \ 17 | -filter triangle -resize 90x90% \ 18 | -convolve "-1, -1, -1, -1, 16, -1, -1, -1, -1" \ 19 | $2 20 | -------------------------------------------------------------------------------- /imagick.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | getImageGeometry(); 11 | $im->cropImage($geo['width'] - 200, $geo['height'] - 200, 100, 100); 12 | 13 | $geo = $im->getImageGeometry(); 14 | $im->resizeImage($geo['width'] * 0.9, $geo['height'] * 0.9, imagick::FILTER_TRIANGLE, 1); 15 | 16 | $kernel = ImagickKernel::fromMatrix([ 17 | [-1, -1, -1], 18 | [-1, 8, -1], 19 | [-1, -1, -1] 20 | ]); 21 | $im->convolveImage($kernel); 22 | 23 | $im->writeImage($argv[2]); 24 | 25 | $im->destroy(); 26 | -------------------------------------------------------------------------------- /scikit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import sys 4 | import numpy as np 5 | from scipy import ndimage, misc 6 | from PIL import Image 7 | import imageio 8 | 9 | im = imageio.imread(sys.argv[1]) 10 | 11 | width, height, bands = im.shape 12 | im = im[100:(width - 100), 100:(height - 100)] 13 | 14 | im = misc.imresize(im, 0.9, interp='bilinear') 15 | 16 | ker = (1.0 / 8.0) * np.array([[-1, -1, -1], 17 | [-1, 16, -1], 18 | [-1, -1, -1]]) 19 | im = ndimage.convolve(im, bands * [ker]) 20 | 21 | # save via PIL is slightly quicker 22 | out = Image.fromarray(im) 23 | out.save(sys.argv[2]) 24 | -------------------------------------------------------------------------------- /pillow.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import sys 4 | from PIL import Image, ImageFilter, __version__ 5 | 6 | Image.MAX_IMAGE_PIXELS = None 7 | 8 | # just to confirm we are getting the right version 9 | print(f'pillow.py: __version__ = {__version__}') 10 | 11 | im = Image.open(sys.argv[1]) 12 | width, height = im.size 13 | 14 | # Crop 100 pixels off all edges. 15 | im = im.crop((100, 100, width - 100, height - 100)) 16 | 17 | # Shrink by 10% 18 | width, height = im.size 19 | im = im.resize((int(width * 0.9), int(height * 0.9)), Image.BILINEAR) 20 | 21 | # sharpen 22 | filter = ImageFilter.Kernel((3, 3), 23 | (-1, -1, -1, 24 | -1, 16, -1, 25 | -1, -1, -1)) 26 | im = im.filter(filter) 27 | 28 | # write back again 29 | im.save(sys.argv[2]) 30 | 31 | -------------------------------------------------------------------------------- /vips-gegl.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # use pyvips, but try to match the exact processing that the gegl code is 4 | # doing, so everything is float, RGBA, and in linear light 5 | 6 | import sys 7 | import pyvips 8 | 9 | im = pyvips.Image.new_from_file(sys.argv[1]) 10 | 11 | im = im.bandjoin(255) 12 | im = im.colourspace('scrgb') 13 | 14 | im = im.crop(100, 100, im.width - 200, im.height - 200) 15 | im = im.reduce(1.0 / 0.9, 1.0 / 0.9, kernel='linear') 16 | mask = pyvips.Image.new_from_array([[-1, -1, -1], 17 | [-1, 16, -1], 18 | [-1, -1, -1]], scale=8) 19 | im = im.conv(mask, precision='integer') 20 | 21 | im = im.colourspace('srgb') 22 | im = im.extract_band(0, n=3) 23 | 24 | im.write_to_file(sys.argv[2]) 25 | -------------------------------------------------------------------------------- /gegl.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 0.1 8 | 9 | 10 | 11 | 12 | 13 | linear 14 | false 15 | 0.9 16 | 0.9 17 | 18 | 19 | 20 | 21 | 22 | 100 23 | 100 24 | 4800 25 | 4800 26 | 27 | 28 | 29 | 30 | 31 | wtc_small.png 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /vips.cc: -------------------------------------------------------------------------------- 1 | // compile with 2 | // g++ vips.cc `pkg-config vips-cpp --cflags --libs` 3 | 4 | #include 5 | 6 | using namespace vips; 7 | 8 | int 9 | main( int argc, char **argv ) 10 | { 11 | VipsImage *global; 12 | 13 | GError *error = NULL; 14 | 15 | if( VIPS_INIT( argv[0] ) ) 16 | return( -1 ); 17 | 18 | VImage in = VImage::new_from_file( argv[1] ); 19 | 20 | VImage mask = VImage::new_matrixv( 3, 3, 21 | -1.0, -1.0, -1.0, -1.0, 16.0, -1.0, -1.0, -1.0, -1.0 ); 22 | mask.set( "scale", 8 ); 23 | 24 | in 25 | .extract_area( 100, 100, in.width() - 200, in.height() - 200 ) 26 | .reduce( 1.0 / 0.9, 1.0 / 0.9, VImage::option()-> 27 | set( "kernel", VIPS_KERNEL_LINEAR ) ) 28 | .conv( mask, VImage::option()-> 29 | set( "precision", VIPS_PRECISION_INTEGER )) 30 | .write_to_file( argv[2] ); 31 | 32 | return( 0 ); 33 | } 34 | -------------------------------------------------------------------------------- /opencv.cc: -------------------------------------------------------------------------------- 1 | /* compile with: 2 | 3 | g++ -g -Wall opencv.cc `pkg-config opencv --cflags --libs` 4 | 5 | code from Amadan@shacknews, thank you very much! 6 | 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace cv; 14 | 15 | int 16 | main (int argc, char **argv) 17 | { 18 | Mat img = imread (argv[1]); 19 | 20 | if (img.empty ()) 21 | return 1; 22 | 23 | Mat crop = Mat (img, Rect (100, 100, img.cols - 200, img.rows - 200)); 24 | 25 | Mat shrunk; 26 | resize (crop, shrunk, Size (0, 0), 0.9, 0.9); 27 | 28 | float m[3][3] = { {-1, -1, -1}, {-1, 16, -1}, {-1, -1, -1} }; 29 | Mat kernel = Mat (3, 3, CV_32F, m) / 8.0; 30 | 31 | Mat sharp; 32 | filter2D (shrunk, sharp, -1, kernel, Point (-1, -1), 0, BORDER_REPLICATE); 33 | 34 | imwrite (argv[2], sharp); 35 | 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /freeimage.c: -------------------------------------------------------------------------------- 1 | /* Compile with: 2 | * 3 | * gcc freeimage.c -lfreeimage 4 | * 5 | * */ 6 | 7 | #include 8 | 9 | int 10 | main (int argc, char **argv) 11 | { 12 | FIBITMAP *t1; 13 | FIBITMAP *t2; 14 | int width; 15 | int height; 16 | 17 | FreeImage_Initialise (FALSE); 18 | 19 | t1 = FreeImage_Load (FIF_TIFF, argv[1], TIFF_DEFAULT); 20 | 21 | width = FreeImage_GetWidth (t1); 22 | height = FreeImage_GetHeight (t1); 23 | 24 | t2 = FreeImage_Copy (t1, 100, 100, width - 100, height - 100); 25 | FreeImage_Unload (t1); 26 | 27 | t1 = FreeImage_Rescale (t2, (width - 200) * 0.9, (height - 200) * 0.9, 28 | FILTER_BILINEAR); 29 | FreeImage_Unload (t2); 30 | 31 | /* FreeImage does not have a sharpen operation, so we skip that. 32 | * */ 33 | 34 | FreeImage_Save (FIF_TIFF, t1, argv[2], TIFF_DEFAULT); 35 | FreeImage_Unload (t1); 36 | 37 | FreeImage_DeInitialise (); 38 | 39 | return 0; 40 | } 41 | 42 | -------------------------------------------------------------------------------- /combine.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'csv' 4 | 5 | data = {} 6 | times = {} 7 | 8 | max_lines = 0 9 | ARGV.each do |filename| 10 | data[filename] = [] 11 | n_lines = 0 12 | CSV.foreach(filename) do |row| 13 | if row[0] =~ /time/ 14 | times[filename] = row[1].to_f 15 | else 16 | data[filename] << row 17 | end 18 | 19 | n_lines += 1 20 | end 21 | max_lines = [max_lines, n_lines].max 22 | end 23 | 24 | (0 .. max_lines).each do |line_no| 25 | output_line = [] 26 | data.each do |filename, lines| 27 | if line_no == 0 28 | output_line << lines[line_no][0] 29 | output_line << lines[line_no][1] 30 | elsif line_no < lines.length 31 | line = lines[line_no] 32 | output_line << times[filename] * line[0].to_f / lines[-1][0].to_f 33 | output_line << line[1] 34 | else 35 | output_line << [[], []] 36 | end 37 | end 38 | 39 | puts output_line.join(", ") 40 | end 41 | -------------------------------------------------------------------------------- /imlib2.c: -------------------------------------------------------------------------------- 1 | /* compile with 2 | * 3 | * gcc -g -Wall imlib2.c `pkg-config imlib2 --cflags --libs` 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | int 12 | main( int argc, char **argv ) 13 | { 14 | Imlib_Image image; 15 | int width; 16 | int height; 17 | char *tmp; 18 | 19 | if( argc != 3 ) 20 | exit( 1 ); 21 | 22 | if( !(image = imlib_load_image( argv[1] )) ) 23 | exit( 1 ); 24 | 25 | /* set the image we loaded as the current context image to work on 26 | */ 27 | imlib_context_set_image( image ); 28 | width = imlib_image_get_width(); 29 | height = imlib_image_get_height(); 30 | if( !(image = imlib_create_cropped_scaled_image( 100, 100, 31 | width - 200, height - 200, 32 | (width - 200) * 0.9, 33 | (height - 200) * 0.9 )) ) 34 | exit( 1 ); 35 | imlib_free_image(); 36 | imlib_context_set_image( image ); 37 | 38 | imlib_image_sharpen( 1 ); 39 | 40 | if( (tmp = strrchr( argv[2], '.' )) ) 41 | imlib_image_set_format( tmp + 1 ); 42 | 43 | /* save the image 44 | */ 45 | imlib_save_image( argv[2] ); 46 | imlib_free_image(); 47 | 48 | return( 0 ); 49 | } 50 | -------------------------------------------------------------------------------- /parse-top.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # watch the output of top -b, sum RES of processes matching a pattern and output 4 | # time and size in MB 5 | # 6 | # this will fail if top has been customized at all, we should probably use ps 7 | # and a loop instead 8 | 9 | require 'csv' 10 | require 'set' 11 | 12 | program = ARGV[0] 13 | units = { 'k' => 1, 'm' => 2, 'g' => 3 } 14 | 15 | puts "#{program},," 16 | 17 | page_total = 0 18 | peak_memory = 0 19 | start_time = 0 20 | 21 | CSV($stdin, :col_sep => " ") do |csv_in| 22 | csv_in.each do |row| 23 | if row[0] =~ /top/ and page_total > 1 24 | start_time = Time.now if start_time == 0 25 | peak_memory = [peak_memory, page_total].max 26 | puts "#{Time.now - start_time}, #{page_total}, #{peak_memory}" 27 | page_total = 0 28 | end 29 | 30 | next if not row[11] =~ /#{program}/ 31 | 32 | memstr = row[5] 33 | 34 | if memstr !~ /([0-9]+)([kmg]?)/ 35 | puts "bad memory size #{memstr}" 36 | next 37 | end 38 | mem = $~[1].to_i 39 | unit = $~[2] 40 | mem *= (2 ** 10) ** units[unit] if units[unit] 41 | mem /= (2 ** 10.to_f) ** 2 42 | 43 | page_total += mem 44 | 45 | # p row 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /opencv-umat.cc: -------------------------------------------------------------------------------- 1 | /* compile with: 2 | 3 | g++ -g -Wall opencv-umat.cc `pkg-config opencv --cflags --libs` 4 | 5 | code from Amadan@shacknews, thank you very much! 6 | 7 | this uses the opencv3 thing that lets it chose to use opencl, or threading, 8 | or whatever 9 | 10 | unfortunately, ubuntu is still on opencv 2.4.9 so we can't try this yet 11 | 12 | Amadan says that on his machine this code is only about 10% faster than 13 | regular opencv2, I guess it's spending a lot of time in tiff load and save 14 | 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | using namespace cv; 22 | 23 | int 24 | main (int argc, char **argv) 25 | { 26 | UMat img; 27 | imread (argv[1]).copyTo (img); 28 | 29 | if (img.empty ()) 30 | return 1; 31 | 32 | UMat crop = UMat (img, Rect (100, 100, img.cols - 200, img.rows - 200)); 33 | 34 | UMat shrunk; 35 | resize (crop, shrunk, Size (0, 0), 0.9, 0.9); 36 | 37 | float m[3][3] = { {-1, -1, -1}, {-1, 16, -1}, {-1, -1, -1} }; 38 | Mat kernel = Mat (3, 3, CV_32F, m) / 8.0; 39 | UMat k; 40 | kernel.copyTo (k); 41 | 42 | UMat sharp; 43 | filter2D (shrunk, sharp, -1, k, Point (-1, -1), 0, BORDER_REPLICATE); 44 | 45 | imwrite (argv[2], sharp); 46 | 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /parse-ps.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # watch the output of ps, sum RSS of processes matching a pattern and output 4 | # time and size in MB 5 | 6 | require 'set' 7 | 8 | program = ARGV[0] 9 | units = { 'm': 2, 'g': 3 } 10 | 11 | start_time = Time.now 12 | page_memory = 0 13 | peak_memory = 0 14 | trace = [] 15 | 16 | $stdin.each do |line| 17 | row = line.split 18 | prg = row[10 .. -1].join 19 | memstr = row[5] 20 | 21 | if row[0] =~ /USER/ 22 | peak_memory = [peak_memory, page_memory].max 23 | trace << [Time.now - start_time, page_memory, peak_memory] 24 | page_memory = 0 25 | next 26 | end 27 | 28 | next if not prg =~ /#{program}/ 29 | 30 | # we need to not count ourselves 31 | next if prg =~ /parse-ps/ 32 | 33 | if memstr !~ /([0-9]+)([kmg]?)/ 34 | puts "bad memory size #{memstr}" 35 | next 36 | end 37 | mem = $~[1].to_i * 1024 38 | unit = $~[2] 39 | mem *= (2 ** 10) ** units[unit] if units[unit] 40 | mem /= (2 ** 10.to_f) ** 2 41 | 42 | page_memory += mem 43 | end 44 | 45 | peak_memory = [peak_memory, page_memory].max 46 | trace << [Time.now - start_time, page_memory, peak_memory] 47 | trace << [Time.now - start_time, 0, peak_memory] 48 | 49 | puts ",#{program}," 50 | trace.each do |time, mem, peak| 51 | puts "#{time.round(2)}, #{mem}, #{peak}" 52 | end 53 | -------------------------------------------------------------------------------- /vips.c: -------------------------------------------------------------------------------- 1 | // compile with 2 | // gcc -Wall vips.c `pkg-config vips --cflags --libs` -o vips-c 3 | 4 | #include 5 | 6 | int 7 | main( int argc, char **argv ) 8 | { 9 | VipsImage *global; 10 | VipsImage **t; 11 | 12 | if( VIPS_INIT( argv[0] ) ) 13 | return( -1 ); 14 | 15 | global = vips_image_new(); 16 | t = (VipsImage **) vips_object_local_array( VIPS_OBJECT( global ), 5 ); 17 | 18 | if( !(t[0] = vips_image_new_from_file( argv[1], NULL )) ) 19 | vips_error_exit( NULL ); 20 | 21 | t[1] = vips_image_new_matrixv( 3, 3, 22 | -1.0, -1.0, -1.0, 23 | -1.0, 16.0, -1.0, 24 | -1.0, -1.0, -1.0 ); 25 | vips_image_set_double( t[1], "scale", 8 ); 26 | 27 | if( vips_crop( t[0], &t[2], 28 | 100, 100, t[0]->Xsize - 200, t[0]->Ysize - 200, NULL ) || 29 | /* lanczos2 version, handy for testing against pillow 30 | vips_reduce( t[2], &t[3], 1.0 / 0.9, 1.0 / 0.9, 31 | "kernel", VIPS_KERNEL_LANCZOS2, 32 | NULL ) || 33 | */ 34 | vips_reduce( t[2], &t[3], 1.0 / 0.9, 1.0 / 0.9, 35 | "kernel", VIPS_KERNEL_LINEAR, 36 | NULL ) || 37 | vips_conv( t[3], &t[4], t[1], 38 | "precision", VIPS_PRECISION_INTEGER, 39 | NULL ) || 40 | vips_image_write_to_file( t[4], argv[2], NULL ) ) 41 | vips_error_exit( NULL ); 42 | 43 | g_object_unref( global ); 44 | 45 | return( 0 ); 46 | } 47 | -------------------------------------------------------------------------------- /gd.c: -------------------------------------------------------------------------------- 1 | // compile with 2 | // gcc -Wall gd.c `pkg-config gdlib --cflags --libs` -o gd 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | int 10 | main( int argc, char **argv ) 11 | { 12 | FILE *fp; 13 | gdImagePtr original, cropped,resized; 14 | gdRect crop; 15 | 16 | if( argc != 3 ) { 17 | printf( "usage: %s in-jpeg out-jpeg\n", argv[0] ); 18 | exit( 1 ); 19 | } 20 | 21 | if( !(fp = fopen( argv[1], "r" )) ) { 22 | printf( "unable to open \"%s\"\n", argv[1] ); 23 | exit( 1 ); 24 | } 25 | if( !(original = gdImageCreateFromJpeg( fp )) ) { 26 | printf( "unable to load \"%s\"\n", argv[1] ); 27 | exit( 1 ); 28 | } 29 | fclose( fp ); 30 | 31 | crop.x = 100; 32 | crop.y = 100; 33 | crop.width = original->sx - 200; 34 | crop.height = original->sy - 200; 35 | cropped = gdImageCrop( original, &crop ); 36 | gdImageDestroy( original ); 37 | original = 0; 38 | if( !cropped ) { 39 | printf( "unable to crop image\n" ); 40 | exit( 1 ); 41 | } 42 | 43 | resized = gdImageScale( cropped, crop.width * 0.9, crop.height * 0.9 ); 44 | gdImageDestroy( cropped ); 45 | cropped = 0; 46 | if( !resized ) { 47 | printf( "unable to resize image\n" ); 48 | exit( 1 ); 49 | } 50 | 51 | //gdImageSharpen is extremely slow 52 | gdImageSharpen( resized, 75 ); 53 | 54 | if( !(fp = fopen( argv[2], "w" )) ) { 55 | printf( "unable to open \"%s\"\n", argv[2] ); 56 | exit( 1 ); 57 | } 58 | gdImageJpeg( resized, fp, -1 ); 59 | fclose( fp ); 60 | 61 | gdImageDestroy( resized ); 62 | 63 | return( 0 ); 64 | } 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vips-bench 2 | 3 | We've written programs using number of different image processing systems to 4 | load a TIFF image, crop 100 pixels off every edge, shrink by 10% with bilinear 5 | interpolation, sharpen with a 3x3 convolution and save again. It's a trivial 6 | test but it does give some idea of the speed and memory behaviour of these 7 | libraries (and it's also quite fun to compare the code). 8 | 9 | Bilinear interpolation is poor quality and no one would use it, but it is 10 | available everywhere. 11 | 12 | # Running the test 13 | 14 | 1. Put your system into performance mode with eg.: 15 | 16 | ``` 17 | echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor 18 | ``` 19 | 20 | 3. Install any packages you are missing with eg.: 21 | 22 | ``` 23 | sudo apt-get install imagemagick graphicsmagick libopencv-dev \ 24 | python-imaging netpbm libfreeimage-dev \ 25 | exactimage gegl composer libvips nip2 26 | ``` 27 | 28 | 4. Make a venv for python and install the python and ruby packages 29 | 30 | ``` 31 | python3 -m venv ~/vips 32 | . ~/vips/bin/activate 33 | pip install pyvips Pillow-SIMD gdlib 34 | gem install rmagick ruby-vips image_science 35 | ``` 36 | 37 | Then run the driver script: 38 | 39 | ./benchmark.sh 40 | 41 | to generate the test image and run all the benchmarks. 42 | 43 | The program is very simple and doesn't do much error checking. You'll need 44 | to look through the output and make sure everything is working correctly. In 45 | particular, make sure you have all the packages installed. 46 | 47 | # Results 48 | 49 | The [speed and memory use 50 | page](https://github.com/libvips/libvips/wiki/Speed-and-memory-use) on the 51 | libvips website has a table of results. 52 | 53 | # TODO 54 | 55 | The peakmem.pl program doesn't seem to be working correctly, investigate. 56 | 57 | -------------------------------------------------------------------------------- /peakmem.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | # from http://tstarling.com/blog/2010/06/measuring-memory-usage-with-strace 4 | 5 | # changes: 6 | # - show only max mem, and use \r to animate display 7 | # - better x64 detection ... Tim's version uses 8 | # if ( `uname -m` eq 'x86_64' ) { 9 | # to spot x64, but this will always fail since the uname output will 10 | # include a \n 11 | # - watch sub-processes too 12 | 13 | my $cmd; 14 | 15 | $machine = `uname -m`; 16 | chomp($machine); 17 | 18 | if ( $machine eq 'x86_64' ) { 19 | $cmd = 'strace -f -e trace=mmap,munmap,brk '; 20 | } else { 21 | $cmd = 'strace -f -e trace=mmap,mmap2,munmap,brk '; 22 | } 23 | 24 | for my $arg (@ARGV) { 25 | $arg =~ s/'/'\\''/g; 26 | $cmd .= " '$arg'"; 27 | } 28 | $cmd .= ' 2>&1 >/dev/null'; 29 | 30 | open( PIPE, "$cmd|" ) or die "Cannot execute command \"$cmd\"\n"; 31 | 32 | my $currentSize = 0; 33 | my $maxSize = 0; 34 | my %maps; 35 | my %topOfData; 36 | my ($addr, $length, $prot, $flags, $fd, $pgoffset); 37 | my $newTop; 38 | my $v; 39 | my $error = ''; 40 | 41 | # turn on output flushing after every write 42 | $|++; 43 | 44 | while ( ) { 45 | $pid = 0; 46 | if ( /^\[pid (\d+)\] / ) { 47 | $pid = $1; 48 | } 49 | 50 | if ( /mmap2?\((.*)\) = (\w+)/ ) { 51 | $v = $pid . $2; 52 | @params = split( /, ?/, $1 ); 53 | ($addr, $length, $prot, $flags, $fd, $pgoffset) = @params; 54 | if ( $addr eq 'NULL' && $fd == -1 ) { 55 | $maps{$v} = $length; 56 | $currentSize += $length; 57 | } 58 | 59 | } elsif ( /munmap\((\w+),/ ) { 60 | $v = $pid . $1; 61 | if ( defined( $maps{$v} ) ) { 62 | $currentSize -= $maps{$v}; 63 | undef $maps{$v}; 64 | } 65 | } elsif ( /brk\((\w+)\)\s*= (\w+)/ ) { 66 | $newTop = hex( $2 ); 67 | if ( hex( $1 ) == 0 or !defined( $topOfData{$pid} ) ) { 68 | $topOfData{$pid} = $newTop; 69 | } else { 70 | $currentSize += $newTop - $topOfData{$pid}; 71 | $topOfData{$pid} = $newTop; 72 | } 73 | } else { 74 | $error .= $_; 75 | } 76 | 77 | if ( int( ( $currentSize - $maxSize ) / 1048576 ) > 0 ) { 78 | $maxSize = $currentSize; 79 | printf( "\r%d MB", $maxSize / 1048576 ); 80 | } 81 | } 82 | printf( "\r%d MB \n", $maxSize / 1048576 ); 83 | close( PIPE ); 84 | if ( $? ) { 85 | print $error; 86 | } 87 | 88 | -------------------------------------------------------------------------------- /gegl.c: -------------------------------------------------------------------------------- 1 | /* compile with 2 | 3 | gcc -g -Wall gegl.c `pkg-config gegl-0.4 --cflags --libs` 4 | 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | static void 13 | null_log_handler (const gchar *log_domain, 14 | GLogLevelFlags log_level, 15 | const gchar *message, 16 | gpointer user_data) 17 | { 18 | } 19 | 20 | int 21 | main (int argc, char **argv) 22 | { 23 | GeglNode *gegl, *load, *crop, *scale, *sharp, *save; 24 | 25 | gegl_init (&argc, &argv); 26 | 27 | if (argc != 3) 28 | { 29 | fprintf (stderr, "usage: %s file-in file-out\n", argv[0]); 30 | exit (1); 31 | } 32 | 33 | g_log_set_handler ("GEGL-load.c", 34 | G_LOG_LEVEL_WARNING | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION, 35 | null_log_handler, NULL); 36 | g_log_set_handler ("GEGL-gegl-tile-handler-cache.c", 37 | G_LOG_LEVEL_WARNING | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION, 38 | null_log_handler, NULL); 39 | 40 | gegl = gegl_node_new (); 41 | 42 | load = gegl_node_new_child (gegl, 43 | "operation", "gegl:load", 44 | "path", argv[1], 45 | NULL); 46 | 47 | crop = gegl_node_new_child (gegl, 48 | "operation", "gegl:crop", 49 | "x", 100.0, 50 | "y", 100.0, 51 | "width", 4800.0, 52 | "height", 4800.0, 53 | NULL); 54 | 55 | scale = gegl_node_new_child (gegl, 56 | "operation", "gegl:scale-ratio", 57 | "x", 0.9, 58 | "y", 0.9, 59 | "sampler", GEGL_SAMPLER_LINEAR, 60 | NULL); 61 | 62 | sharp = gegl_node_new_child (gegl, 63 | "operation", "gegl:unsharp-mask", 64 | "std-dev", 1.0, // diameter 7 mask in gegl 65 | NULL); 66 | 67 | save = gegl_node_new_child (gegl, 68 | "operation", "gegl:save", 69 | //"operation", "gegl:png-save", 70 | //"bitdepth", 8, 71 | "path", argv[2], 72 | NULL); 73 | 74 | gegl_node_link_many (load, crop, scale, sharp, save, NULL); 75 | 76 | //gegl_node_dump( gegl, 0 ); 77 | 78 | gegl_node_process (save); 79 | 80 | //gegl_node_dump( gegl, 0 ); 81 | 82 | g_object_unref (gegl); 83 | 84 | gegl_exit (); 85 | 86 | return (0); 87 | } 88 | -------------------------------------------------------------------------------- /ymagine.c: -------------------------------------------------------------------------------- 1 | /* compile with 2 | 3 | YMAGINE=/home/john/ymagine 4 | gcc \ 5 | -I $YMAGINE/framework/ymagine/jni/include \ 6 | -I $YMAGINE/framework/yosal/include \ 7 | -L $YMAGINE/out/target/linux-x86_64 \ 8 | ymagine.c \ 9 | -l yahoo_ymagine \ 10 | -o ymagine-c 11 | 12 | */ 13 | 14 | #include "ymagine/ymagine.h" 15 | 16 | #include 17 | #include 18 | 19 | #ifndef O_BINARY 20 | #define O_BINARY 0 21 | #endif 22 | 23 | /* Using a callback to set output options dynamically based on input image */ 24 | 25 | static int 26 | progressCallback(YmagineFormatOptions *options, 27 | int format, int width, int height) 28 | { 29 | /* scaleMode can be YMAGINE_SCALE_CROP or YMAGINE_SCALE_LETTERBOX */ 30 | int scaleMode = YMAGINE_SCALE_LETTERBOX; 31 | int pad = 100; 32 | int cropwidth; 33 | int cropheight; 34 | int outwidth; 35 | int outheight; 36 | 37 | if (width <= 2 * pad || height <= 2 * pad) { 38 | return YMAGINE_OK; 39 | } 40 | 41 | cropwidth = width - 2 * pad; 42 | cropheight = height - 2 * pad; 43 | YmagineFormatOptions_setCrop(options, pad, pad, cropwidth, cropheight); 44 | 45 | outwidth = (cropwidth * 90) / 100; 46 | outheight = (cropheight * 90) / 100; 47 | if (outwidth < 1) { 48 | outwidth = 1; 49 | } 50 | if (outheight < 1) { 51 | outheight = 1; 52 | } 53 | YmagineFormatOptions_setResize(options, outwidth, outheight, scaleMode); 54 | 55 | return YMAGINE_OK; 56 | } 57 | 58 | int main(int argc, const char* argv[]) 59 | { 60 | int fdin; 61 | int fdout; 62 | const char* infile; 63 | const char* outfile; 64 | int rc = YMAGINE_ERROR; 65 | 66 | if (argc < 3) { 67 | fprintf(stdout, "usage: bench \n"); 68 | return 0; 69 | } 70 | 71 | infile = argv[1]; 72 | outfile = argv[2]; 73 | 74 | fdin = open(infile, O_RDONLY | O_BINARY); 75 | if (fdin < 0) { 76 | fprintf(stdout, "failed to open input file \"%s\"\n", infile); 77 | } else { 78 | int fmode = O_WRONLY | O_CREAT | O_BINARY; 79 | 80 | /* Truncate file if it already exisst */ 81 | fmode |= O_TRUNC; 82 | 83 | fdout = open(outfile, fmode, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 84 | if (fdout < 0) { 85 | fprintf(stdout, "failed to open output file \"%s\"\n", outfile); 86 | } else { 87 | Ychannel *channelin = YchannelInitFd(fdin, 0); 88 | Ychannel *channelout = YchannelInitFd(fdout, 1); 89 | YmagineFormatOptions *options; 90 | 91 | options = YmagineFormatOptions_Create(); 92 | YmagineFormatOptions_setFormat(options, YMAGINE_IMAGEFORMAT_JPEG); 93 | YmagineFormatOptions_setSharpen(options, 0.1); 94 | YmagineFormatOptions_setCallback(options, progressCallback); 95 | rc = YmagineTranscode(channelin, channelout, options); 96 | YmagineFormatOptions_Release(options); 97 | 98 | YchannelRelease(channelout); 99 | YchannelRelease(channelin); 100 | 101 | close(fdout); 102 | } 103 | 104 | close(fdin); 105 | } 106 | 107 | return 0; 108 | } 109 | -------------------------------------------------------------------------------- /try.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo rmagick.rb 4 | 5 | time ./rmagick.rb wtc_tiled_small.tif x.tif 6 | sleep 2 7 | time ./rmagick.rb wtc_tiled_small.tif x.tif 8 | sleep 2 9 | time ./rmagick.rb wtc_tiled_small.tif x.tif 10 | sleep 2 11 | time ./rmagick.rb wtc_tiled_small.tif x.tif 12 | sleep 2 13 | 14 | echo vips.py 15 | 16 | time ./vips.py wtc_tiled_small.tif x.tif 17 | sleep 2 18 | time ./vips.py wtc_tiled_small.tif x.tif 19 | sleep 2 20 | time ./vips.py wtc_tiled_small.tif x.tif 21 | sleep 2 22 | time ./vips.py wtc_tiled_small.tif x.tif 23 | sleep 2 24 | 25 | echo ruby-vips.rb 26 | 27 | time ./ruby-vips.rb wtc_tiled_small.tif x.tif 28 | sleep 2 29 | time ./ruby-vips.rb wtc_tiled_small.tif x.tif 30 | sleep 2 31 | time ./ruby-vips.rb wtc_tiled_small.tif x.tif 32 | sleep 2 33 | time ./ruby-vips.rb wtc_tiled_small.tif x.tif 34 | sleep 2 35 | 36 | echo nip2bench.sh 37 | 38 | time ./nip2bench.sh wtc_tiled_small.tif -o x.tif 39 | sleep 2 40 | time ./nip2bench.sh wtc_tiled_small.tif -o x.tif 41 | sleep 2 42 | time ./nip2bench.sh wtc_tiled_small.tif -o x.tif 43 | sleep 2 44 | time ./nip2bench.sh wtc_tiled_small.tif -o x.tif 45 | sleep 2 46 | 47 | echo vips.sh 48 | 49 | time ./vips.sh wtc_tiled_small.tif x.tif 50 | sleep 2 51 | time ./vips.sh wtc_tiled_small.tif x.tif 52 | sleep 2 53 | time ./vips.sh wtc_tiled_small.tif x.tif 54 | sleep 2 55 | time ./vips.sh wtc_tiled_small.tif x.tif 56 | sleep 2 57 | 58 | echo vips.cc 59 | 60 | g++ vips.cc `pkg-config vipsCC --cflags --libs` 61 | time ./a.out wtc_tiled_small.tif x.tif 62 | sleep 2 63 | time ./a.out wtc_tiled_small.tif x.tif 64 | sleep 2 65 | time ./a.out wtc_tiled_small.tif x.tif 66 | sleep 2 67 | time ./a.out wtc_tiled_small.tif x.tif 68 | sleep 2 69 | 70 | echo pil.py 71 | 72 | time ./pil.py wtc_tiled_small.tif x.tif 73 | sleep 2 74 | time ./pil.py wtc_tiled_small.tif x.tif 75 | sleep 2 76 | time ./pil.py wtc_tiled_small.tif x.tif 77 | sleep 2 78 | time ./pil.py wtc_tiled_small.tif x.tif 79 | sleep 2 80 | 81 | echo im.sh 82 | 83 | time ./im.sh wtc_tiled_small.tif x.tif 84 | sleep 2 85 | time ./im.sh wtc_tiled_small.tif x.tif 86 | sleep 2 87 | time ./im.sh wtc_tiled_small.tif x.tif 88 | sleep 2 89 | time ./im.sh wtc_tiled_small.tif x.tif 90 | sleep 2 91 | 92 | echo gm.sh 93 | 94 | time ./im.sh wtc_tiled_small.tif x.tif 95 | sleep 2 96 | time ./im.sh wtc_tiled_small.tif x.tif 97 | sleep 2 98 | time ./im.sh wtc_tiled_small.tif x.tif 99 | sleep 2 100 | time ./im.sh wtc_tiled_small.tif x.tif 101 | sleep 2 102 | 103 | echo freeimage.c 104 | 105 | gcc freeimage.c -lfreeimage 106 | time ./a.out wtc_tiled_small.tif x.tif 107 | sleep 2 108 | time ./a.out wtc_tiled_small.tif x.tif 109 | sleep 2 110 | time ./a.out wtc_tiled_small.tif x.tif 111 | sleep 2 112 | time ./a.out wtc_tiled_small.tif x.tif 113 | sleep 2 114 | 115 | echo netpbm.sh 116 | 117 | time ./netpbm.sh wtc_tiled_small.tif x.tif 118 | sleep 2 119 | time ./netpbm.sh wtc_tiled_small.tif x.tif 120 | sleep 2 121 | time ./netpbm.sh wtc_tiled_small.tif x.tif 122 | sleep 2 123 | time ./netpbm.sh wtc_tiled_small.tif x.tif 124 | sleep 2 125 | 126 | echo is.rb 127 | 128 | time ./is.rb wtc_tiled_small.tif x.tif 129 | sleep 2 130 | time ./is.rb wtc_tiled_small.tif x.tif 131 | sleep 2 132 | time ./is.rb wtc_tiled_small.tif x.tif 133 | sleep 2 134 | time ./is.rb wtc_tiled_small.tif x.tif 135 | sleep 2 136 | 137 | echo opencv.cc 138 | 139 | g++ -g -Wall opencv.cc `pkg-config opencv --cflags --libs` 140 | time ./a.out wtc_tiled_small.tif x.tif 141 | sleep 2 142 | time ./a.out wtc_tiled_small.tif x.tif 143 | sleep 2 144 | time ./a.out wtc_tiled_small.tif x.tif 145 | sleep 2 146 | time ./a.out wtc_tiled_small.tif x.tif 147 | sleep 2 148 | 149 | 150 | 151 | -------------------------------------------------------------------------------- /tracemem.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # from http://tstarling.com/blog/2010/06/measuring-memory-usage-with-strace 4 | 5 | # changes: 6 | # - show only max mem, and use \r to animate display 7 | # - better x64 detection ... Tim's version uses 8 | # if ( `uname -m` eq 'x86_64' ) { 9 | # to spot x64, but this will always fail since the uname output will 10 | # include a \n 11 | # - watch sub-processes too 12 | # - redo in ruby 13 | 14 | cmd = 'strace -f -e trace=mmap,munmap,brk' 15 | 16 | machine = `uname -m` 17 | if machine =~ /x86_64/ 18 | cmd += ',mmap2' 19 | end 20 | 21 | ARGV.each do |arg| 22 | cmd += " '#{arg.gsub /'/, "\\\\'"}'" 23 | end 24 | 25 | cmd += " 2>&1" 26 | 27 | puts "running #{cmd}" 28 | 29 | mapped_memory = {} 30 | current_size = 0 31 | peak_mem = 0 32 | top_of_data = {} 33 | unfinished = {} 34 | 35 | IO.popen(cmd) do |f| 36 | f.each_line do |line| 37 | puts line 38 | 39 | pid = 0 40 | if line =~ /^\[pid\s+(\d+)\] / 41 | pid = $~[1].to_i 42 | end 43 | 44 | if line =~ /(\w+)\((.*)\s+\/ 45 | syscall = $~[1] 46 | args = $~[2].split /, ?/ 47 | unfinished[pid] = {} if not unfinished.has_key?(pid) 48 | if unfinished[pid].has_key?(syscall) 49 | puts "nested unfinished #{syscall} on pid #{pid}" 50 | puts "line = #{line}" 51 | exit 52 | end 53 | unfinished[pid][syscall] = args 54 | puts "suspended pid = #{pid}, #{syscall}, args = #{args}" 55 | next 56 | end 57 | 58 | if line =~ /\<\.\.\.\s+(\w+)\s+resumed\>\s+\)\s+=\s+(.*)/ 59 | syscall = $~[1] 60 | result = $~[2].hex 61 | if not unfinished.has_key?(pid) 62 | puts "no suspended call for resume of #{syscall} #{pid}" 63 | exit 64 | end 65 | if not unfinished[pid].has_key?(syscall) 66 | puts "no suspended #{syscall} on #{pid}" 67 | p unfinished 68 | exit 69 | end 70 | 71 | args = unfinished[pid][syscall] 72 | unfinished[pid].delete(syscall) 73 | line = "(pseudo) #{syscall}(#{args.join(", ")}) = #{result}" 74 | 75 | puts "resumed #{line}" 76 | end 77 | 78 | if line =~ /mmap2?\((.*)\)\s+=\s+(\w+)/ 79 | key = pid * 2 ** 24 + $~[2].hex 80 | addr, length, prot, flags, fd, pgoffset = $~[1].split /, ?/ 81 | if addr == "NULL" and fd == "-1" 82 | mapped_memory[key] = length.to_i 83 | current_size += length.to_i 84 | end 85 | elsif line =~ /munmap\((.*)\)/ 86 | addr, length = $~[1].split /, ?/ 87 | key = pid * 2 ** 24 + addr.hex 88 | if mapped_memory.has_key?(key) 89 | if mapped_memory[key] != length.to_i 90 | puts "munmap length does not match" 91 | puts "mapped length was #{mapped_memory[key]}" 92 | puts "munmap length is #{length.to_i}" 93 | end 94 | current_size -= mapped_memory[key] 95 | mapped_memory.delete(key) 96 | end 97 | elsif line =~ /brk\((\w+)\)\s+=\s+(\w+)/ 98 | new_top = $~[2].hex 99 | if top_of_data.has_key?(pid) 100 | current_size += new_top - top_of_data[pid] 101 | end 102 | top_of_data[pid] = new_top 103 | elsif line !~ /SIGCHLD/ and line !~ /attached/ and line !~ /exited/ 104 | puts "trace: #{line}" 105 | end 106 | 107 | peak_mem = [peak_mem, current_size].max 108 | end 109 | end 110 | 111 | if not $? 112 | puts "command failed - #{cmd}" 113 | exit 114 | end 115 | 116 | puts "peak memory = #{peak_mem.to_f / (2 ** 10) ** 2} MB" 117 | -------------------------------------------------------------------------------- /gegl5x5.c: -------------------------------------------------------------------------------- 1 | /* compile with 2 | 3 | gcc -g -Wall gegl.c `pkg-config gegl-0.3 --cflags --libs` 4 | 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | static void 13 | null_log_handler (const gchar *log_domain, 14 | GLogLevelFlags log_level, 15 | const gchar *message, 16 | gpointer user_data) 17 | { 18 | } 19 | 20 | int 21 | main (int argc, char **argv) 22 | { 23 | GeglNode *gegl, *load, *crop, *scale, *sharp, *save; 24 | 25 | gegl_init (&argc, &argv); 26 | 27 | if (argc != 3) 28 | { 29 | fprintf (stderr, "usage: %s file-in file-out\n", argv[0]); 30 | exit (1); 31 | } 32 | 33 | g_log_set_handler ("GEGL-load.c", 34 | G_LOG_LEVEL_WARNING | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION, 35 | null_log_handler, NULL); 36 | g_log_set_handler ("GEGL-gegl-tile-handler-cache.c", 37 | G_LOG_LEVEL_WARNING | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION, 38 | null_log_handler, NULL); 39 | 40 | gegl = gegl_node_new (); 41 | 42 | load = gegl_node_new_child (gegl, 43 | "operation", "gegl:load", 44 | "path", argv[1], 45 | NULL); 46 | 47 | crop = gegl_node_new_child (gegl, 48 | "operation", "gegl:crop", 49 | "x", 100.0, 50 | "y", 100.0, 51 | "width", 4800.0, 52 | "height", 4800.0, 53 | NULL); 54 | 55 | scale = gegl_node_new_child (gegl, 56 | "operation", "gegl:scale-ratio", 57 | "x", 0.9, 58 | "y", 0.9, 59 | "sampler", GEGL_SAMPLER_LINEAR, 60 | NULL); 61 | 62 | sharp = gegl_node_new_child (gegl, 63 | "operation", "gegl:unsharp-mask", 64 | "std-dev", 1.0, // diameter 7 mask in gegl 65 | NULL); 66 | 67 | /* 68 | sharp = gegl_node_new_child (gegl, 69 | "operation", "gegl:convolution-matrix", 70 | "a1", -1.0, 71 | "b1", -1.0, 72 | "c1", -1.0, 73 | "d1", 0.0, 74 | "e1", 0.0, 75 | "a2", -1.0, 76 | "b2", 16.0, 77 | "c2", -1.0, 78 | "d2", 0.0, 79 | "e2", 0.0, 80 | "a3", -1.0, 81 | "b3", -1.0, 82 | "c3", -1.0, 83 | "d3", 0.0, 84 | "e3", 0.0, 85 | "a4", 0.0, 86 | "b4", 0.0, 87 | "c4", 0.0, 88 | "d4", 0.0, 89 | "e4", 0.0, 90 | "a5", 0.0, 91 | "b5", 0.0, 92 | "c5", 0.0, 93 | "d5", 0.0, 94 | "e5", 0.0, 95 | "divisor", 8.0, 96 | NULL); 97 | */ 98 | 99 | save = gegl_node_new_child (gegl, 100 | "operation", "gegl:save", 101 | //"operation", "gegl:png-save", 102 | //"bitdepth", 8, 103 | "path", argv[2], 104 | NULL); 105 | 106 | gegl_node_link_many (load, crop, scale, sharp, save, NULL); 107 | 108 | //gegl_node_dump( gegl, 0 ); 109 | 110 | gegl_node_process (save); 111 | 112 | //gegl_node_dump( gegl, 0 ); 113 | 114 | g_object_unref (gegl); 115 | 116 | gegl_exit (); 117 | 118 | return (0); 119 | } 120 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "07adee25d32f1573330c730fad0b4ce6", 8 | "packages": [ 9 | { 10 | "name": "jcupitt/vips", 11 | "version": "dev-master", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/libvips/php-vips.git", 15 | "reference": "adc8a4e379a1a9a9563a374e724e6598a20468f1" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/libvips/php-vips/zipball/adc8a4e379a1a9a9563a374e724e6598a20468f1", 20 | "reference": "adc8a4e379a1a9a9563a374e724e6598a20468f1", 21 | "shasum": "" 22 | }, 23 | "require": { 24 | "ext-ffi": "*", 25 | "php": ">=7.4", 26 | "psr/log": "^1.1.3|^2.0|^3.0" 27 | }, 28 | "require-dev": { 29 | "php-parallel-lint/php-parallel-lint": "^1.3", 30 | "phpdocumentor/shim": "^3.3", 31 | "phpunit/phpunit": "^9.5", 32 | "squizlabs/php_codesniffer": "^3.7" 33 | }, 34 | "default-branch": true, 35 | "type": "library", 36 | "extra": { 37 | "branch-alias": { 38 | "dev-master": "2.0.x-dev" 39 | } 40 | }, 41 | "autoload": { 42 | "psr-4": { 43 | "Jcupitt\\Vips\\": "src" 44 | } 45 | }, 46 | "notification-url": "https://packagist.org/downloads/", 47 | "license": [ 48 | "MIT" 49 | ], 50 | "authors": [ 51 | { 52 | "name": "John Cupitt", 53 | "email": "jcupitt@gmail.com", 54 | "homepage": "https://github.com/jcupitt", 55 | "role": "Developer" 56 | } 57 | ], 58 | "description": "A high-level interface to the libvips image processing library.", 59 | "homepage": "https://github.com/libvips/php-vips", 60 | "keywords": [ 61 | "image", 62 | "libvips", 63 | "processing" 64 | ], 65 | "support": { 66 | "issues": "https://github.com/libvips/php-vips/issues", 67 | "source": "https://github.com/libvips/php-vips/tree/master" 68 | }, 69 | "time": "2022-08-11T08:36:58+00:00" 70 | }, 71 | { 72 | "name": "psr/log", 73 | "version": "3.0.0", 74 | "source": { 75 | "type": "git", 76 | "url": "https://github.com/php-fig/log.git", 77 | "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" 78 | }, 79 | "dist": { 80 | "type": "zip", 81 | "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", 82 | "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", 83 | "shasum": "" 84 | }, 85 | "require": { 86 | "php": ">=8.0.0" 87 | }, 88 | "type": "library", 89 | "extra": { 90 | "branch-alias": { 91 | "dev-master": "3.x-dev" 92 | } 93 | }, 94 | "autoload": { 95 | "psr-4": { 96 | "Psr\\Log\\": "src" 97 | } 98 | }, 99 | "notification-url": "https://packagist.org/downloads/", 100 | "license": [ 101 | "MIT" 102 | ], 103 | "authors": [ 104 | { 105 | "name": "PHP-FIG", 106 | "homepage": "https://www.php-fig.org/" 107 | } 108 | ], 109 | "description": "Common interface for logging libraries", 110 | "homepage": "https://github.com/php-fig/log", 111 | "keywords": [ 112 | "log", 113 | "psr", 114 | "psr-3" 115 | ], 116 | "support": { 117 | "source": "https://github.com/php-fig/log/tree/3.0.0" 118 | }, 119 | "time": "2021-07-14T16:46:02+00:00" 120 | } 121 | ], 122 | "packages-dev": [], 123 | "aliases": [], 124 | "minimum-stability": "stable", 125 | "stability-flags": { 126 | "jcupitt/vips": 20 127 | }, 128 | "prefer-stable": false, 129 | "prefer-lowest": false, 130 | "platform": [], 131 | "platform-dev": [], 132 | "plugin-api-version": "2.2.0" 133 | } 134 | -------------------------------------------------------------------------------- /benchmark.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # subdir we keep image temps in for the benchmark 4 | tmp=tmp 5 | 6 | echo clearing test area ... 7 | rm -rf $tmp 8 | mkdir $tmp 9 | 10 | echo building test image ... 11 | vips colourspace sample2.v $tmp/t1.v srgb 12 | #vips replicate $tmp/t1.v $tmp/t2.v 20 15 13 | vips replicate $tmp/t1.v $tmp/t2.v 40 30 14 | vips extract_area $tmp/t2.v $tmp/x.tif[tile] 0 0 10000 10000 15 | vips copy $tmp/x.tif $tmp/x.jpg 16 | vips copy $tmp/x.tif $tmp/x.ppm 17 | vips copy $tmp/x.tif $tmp/x-strip.tif 18 | vipsheader $tmp/x.tif 19 | 20 | # needed for vips.php below 21 | composer install 22 | 23 | # try to find the real time a command took to run 24 | real_time() { 25 | # capture command output to y, time output to x 26 | (time -p $* &> tmp/y) &> tmp/x 27 | 28 | # get just the "real 0.2" line 29 | real=($(cat tmp/x | grep real)) 30 | 31 | # and just the number 32 | return_real_time=${real[1]} 33 | } 34 | 35 | # run a command several times, return the fastest real time 36 | 37 | # sleep for two secs between runs to let the system settle -- after a run 38 | # there's a short period of disc chatter we want to avoid 39 | 40 | # you should check that services like tracker are not running 41 | 42 | get_time() { 43 | cmd=$* 44 | 45 | times=() 46 | for i in {1..5}; do 47 | sleep 2 48 | real_time $cmd 49 | times+=($return_real_time) 50 | done 51 | 52 | IFS=$'\n' times=($(sort -g <<<"${times[*]}")) 53 | unset IFS 54 | 55 | cmd_time=$times 56 | } 57 | 58 | # run a command and get a trace of memuse in a csv file 59 | get_mem() { 60 | name=$1 61 | cmd=$2 62 | user=$(whoami) 63 | 64 | rm -f $tmp/vipsbench.lock 65 | (while [ ! -f $tmp/vipsbench.lock ]; do 66 | ps u -u $user 67 | sleep 0.01 68 | done | ./parse-ps.rb "$name" > "$name.csv") & 69 | $cmd 70 | touch $tmp/vipsbench.lock 71 | sleep 1 72 | cmd_mem=$(tail -1 "$name.csv" | awk '{ print $3 }') 73 | } 74 | 75 | # benchmark 76 | benchmark() { 77 | name=$1 78 | cmd=$2 79 | 80 | get_time $cmd 81 | get_mem "$name" "$cmd" 82 | echo $name, $cmd_time, $cmd_mem 83 | 84 | echo "time, $cmd_time, " >> "$name.csv" 85 | } 86 | 87 | rm -f *.csv 88 | 89 | echo "program, time (s), peak memory (MB)" 90 | 91 | # gm, im etc. control concurreny with this ... but leave at the default 92 | export OMP_NUM_THREADS=16 93 | 94 | # don't use hyperthreading with libvips: this is an int workload and sees no 95 | # benefit, and in fact a slight slowdown due to thread management 96 | export VIPS_CONCURRENCY=16 97 | 98 | gcc -Wall vips.c `pkg-config vips --cflags --libs` -o vips-c 99 | echo -n ppm- 100 | benchmark vips-c "./vips-c $tmp/x.ppm $tmp/x2.ppm" 101 | 102 | benchmark tiffcp "tiffcp -m 400000000 -s $tmp/x.tif $tmp/x2.tif" 103 | 104 | gcc -Wall vips.c `pkg-config vips --cflags --libs` -o vips-c 105 | benchmark vips-c "./vips-c $tmp/x.tif $tmp/x2.tif" 106 | 107 | benchmark vips.php "./vips.php $tmp/x.tif $tmp/x2.tif" 108 | 109 | g++ vips.cc `pkg-config vips-cpp --cflags --libs` -o vips-cc 110 | benchmark vips-cc "./vips-cc $tmp/x.tif $tmp/x2.tif" 111 | 112 | benchmark vips.py "./vips.py $tmp/x.tif $tmp/x2.tif" 113 | 114 | benchmark nip4 "./vips.nip4 $tmp/x.tif -o $tmp/x2.tif" 115 | 116 | benchmark lua-vips.lua "./lua-vips.lua $tmp/x.tif $tmp/x2.tif" 117 | 118 | benchmark ruby-vips "./ruby-vips.rb $tmp/x.tif $tmp/x2.tif" 119 | 120 | benchmark vips-gegl.py "./vips-gegl.py $tmp/x.jpg $tmp/x2.jpg" 121 | 122 | gcc -Wall vips.c `pkg-config vips --cflags --libs` -o vips-c 123 | export VIPS_CONCURRENCY=1 124 | echo -n 1thread- 125 | benchmark vips-c "./vips-c $tmp/x.tif $tmp/x2.tif" 126 | unset VIPS_CONCURRENCY 127 | 128 | gcc -Wall vips.c `pkg-config vips --cflags --libs` -o vips-c 129 | echo -n jpg- 130 | benchmark vips-c "./vips-c $tmp/x.jpg $tmp/x2.jpg" 131 | 132 | benchmark pillow-simd "./pillow.py $tmp/x-strip.tif $tmp/x2.tif" 133 | 134 | benchmark vips-cli "./vips.sh $tmp/x.tif $tmp/x2.tif" 135 | 136 | # sadly bitrotted in the shifting sands of node 137 | # benchmark vips.js "./vips.js $tmp/x.tif $tmp/x2.tif" 138 | 139 | echo -n ppm- 140 | benchmark gm "./gm.sh $tmp/x.ppm $tmp/x2.ppm" 141 | 142 | benchmark gm "./gm.sh $tmp/x.tif $tmp/x2.tif" 143 | 144 | echo -n jpg- 145 | benchmark gm "./gm.sh $tmp/x.jpg $tmp/x2.jpg" 146 | 147 | benchmark nip2 "./vips.nip2 $tmp/x.tif -o $tmp/x2.tif" 148 | 149 | # does not support tiled tif 150 | benchmark ffmpeg "./ffmpeg.sh $tmp/x-strip.tif -o $tmp/x2.tif" 151 | 152 | # OS X only 153 | # benchmark sips "./sips.sh $tmp/x.tif $tmp/x2.tif" 154 | 155 | # pnm hates tiled tiff 156 | benchmark pnm "./netpbm.sh $tmp/x-strip.tif $tmp/x2.tif" 157 | 158 | benchmark rmagick "./rmagick.rb $tmp/x.tif $tmp/x2.tif" 159 | 160 | # this needs careful config, see 161 | # https://github.com/jcupitt/vips-bench/issues/4 162 | YMAGINE=/home/john/ymagine 163 | if [ -d $YMAGINE ]; then 164 | export LD_LIBRARY_PATH=$YMAGINE/out/target/linux-x86_64:$LD_LIBRARY_PATH 165 | gcc \ 166 | -I $YMAGINE/framework/ymagine/jni/include \ 167 | -I $YMAGINE/framework/yosal/include \ 168 | -L $YMAGINE/out/target/linux-x86_64 \ 169 | ymagine.c \ 170 | -l yahoo_ymagine \ 171 | -o ymagine-c 172 | echo -n jpg- 173 | benchmark ymagine-c "./ymagine-c $tmp/x.jpg $tmp/x2.jpg" 174 | fi 175 | 176 | benchmark convert "./im.sh $tmp/x.tif $tmp/x2.tif" 177 | 178 | benchmark imwand.py "./imwand.py $tmp/x.tif $tmp/x2.tif" 179 | 180 | echo -n jpg- 181 | benchmark convert "./im.sh $tmp/x.jpg $tmp/x2.jpg" 182 | 183 | g++ -g -Wall opencv.cc `pkg-config opencv4 --cflags --libs` -o opencv 184 | benchmark opencv "./opencv $tmp/x.tif $tmp/x2.tif" 185 | 186 | benchmark oiio "./oiio.sh $tmp/x.tif $tmp/x2.tif" 187 | 188 | benchmark imagej "imagej -x 1000 -i $tmp/x-strip.tif -b bench.ijm" 189 | 190 | benchmark econvert "./ei.sh $tmp/x-strip.tif $tmp/x2.tif" 191 | 192 | gcc -Wall imlib2.c `pkg-config imlib2 --cflags --libs` -o imlib2 193 | benchmark imlib2 "./imlib2 $tmp/x.tif $tmp/x2.tif" 194 | 195 | benchmark magick "./im7.sh $tmp/x.tif $tmp/x2.tif" 196 | 197 | gcc freeimage.c -lfreeimage -o freeimage 198 | benchmark freeimage "./freeimage $tmp/x-strip.tif $tmp/x2.tif" 199 | 200 | # broken, again, in ruby 2.7 201 | # benchmark is "./is.rb $tmp/x-strip.tif $tmp/x2.tif" 202 | 203 | gcc -Wall gd.c `pkg-config gdlib --cflags --libs` -o gd 204 | echo -n jpg- 205 | benchmark gd "./gd $tmp/x.jpg $tmp/x2.jpg" 206 | 207 | benchmark imagick "./imagick.php $tmp/x.tif $tmp/x2.tif" 208 | 209 | gcc -Wall gegl.c `pkg-config gegl-0.4 --cflags --libs` -o gegl 210 | # gegl-0.4 doesn't have tiff support built in 211 | # echo -n tiff- 212 | # benchmark gegl "./gegl $tmp/x.tif $tmp/x2.tif" 213 | # this fails with an assert() error on ubuntu 19.04 214 | # don't use opencl and threads ... we want to avoid opencl's thread system 215 | export GEGL_THREADS=16 216 | export GEGL_USE_OPENCL=no 217 | echo -n jpg- 218 | benchmark gegl "./gegl $tmp/x.jpg $tmp/x2.jpg" 219 | 220 | # no longer in ubuntu 22.04 221 | # benchmark pike "./image.pike $tmp/x.tif $tmp/x2.tif" 222 | 223 | benchmark gmic "./gmic.sh $tmp/x.tif $tmp/x2.tif" 224 | 225 | # this has stopped working and needs fixing 226 | # benchmark scikit "./scikit.py $tmp/x-strip.tif $tmp/x2.tif" 227 | 228 | benchmark octave "./octave.m $tmp/x.tif $tmp/x2.tif" 229 | 230 | ./combine.rb *.csv > memtrace.csv 231 | 232 | echo "combined memory traces in memtrace.csv" 233 | 234 | echo clearing test area ... 235 | rm -rf $tmp 236 | 237 | -------------------------------------------------------------------------------- /nip4.ws: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 299 | 300 | 301 | 302 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | -------------------------------------------------------------------------------- /nip2-gegl.ws: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 299 | 300 | 301 | 302 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | --------------------------------------------------------------------------------