Created
January 19, 2021 10:04
-
-
Save jcupitt/1420f8046f98c1866857711e55cf6d48 to your computer and use it in GitHub Desktop.
pil - pyvips image resize benchmark
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python3 | |
import time | |
import sys | |
from io import BytesIO | |
import pyvips | |
from PIL import Image # Pillow-SIMD | |
def figure_size(ih, iw, oh, ow): | |
if oh / ih >= ow / oh: | |
return int(iw * (oh / ih)), oh | |
if oh / ih < ow / oh: | |
return ow, int(ih * (ow / iw)) # width height | |
def scale(ih, iw, oh, ow): | |
if oh / ih >= ow / oh: | |
return (oh / ih) | |
if oh / ih < ow / oh: | |
return (ow / iw) # scale | |
def bench(last=None, do_print=False, iterations=None, level=0, info=""): | |
if not last: | |
return time.clock_gettime(time.CLOCK_THREAD_CPUTIME_ID), time.process_time(), time.perf_counter() | |
result = ( | |
time.clock_gettime(time.CLOCK_THREAD_CPUTIME_ID) - last[0], | |
time.process_time() - last[1], | |
time.perf_counter() - last[2]) | |
if do_print: | |
print() | |
print((level * " ") + f"took {time.clock_gettime(time.CLOCK_THREAD_CPUTIME_ID) - last[0]} thread time") | |
print((level * " ") + f"took {time.process_time() - last[1]:.4f} cpu time") | |
print((level * " ") + f"took {time.perf_counter() - last[2]:.4f} real time") | |
if iterations: | |
print((level * " ") + f"took {(time.perf_counter() - last[2]) / iterations:.4f} per iteration") | |
if info: | |
print((level * " ") + info) | |
return result | |
def generate_image_pil(image, height, width, quality=75, optimize=False): | |
if not isinstance(image, Image.Image): | |
image = Image.open(BytesIO(image)) | |
resize_image = image.resize(figure_size(image.height, image.width, height, width)) | |
jpg_file = BytesIO() | |
resize_image.save(jpg_file, format="JPEG", quality=quality, optimize=optimize) | |
return jpg_file, resize_image | |
def generate_image_vips(image, height, width, quality=75, optimize=False): | |
if not isinstance(image, pyvips.Image): | |
image = pyvips.Image.new_from_buffer(image, "") | |
resize_image = image.resize(scale(image.height, image.width, height, width)) | |
copy_timer = time.perf_counter() | |
copy = resize_image.copy_memory() | |
print(f"memory copy took: {time.perf_counter() - copy_timer:.4f}") | |
jpg_file = resize_image.write_to_buffer('.jpg', Q=quality, optimize_coding=optimize) | |
return jpg_file, copy | |
def generate_image_vips_thumbnail(image_bytes, height, width, quality=75, optimize=False): | |
resize_image = pyvips.Image.thumbnail_buffer(image_bytes, width, height=height) | |
jpg_bytes = resize_image.write_to_buffer('.jpg', Q=quality, optimize_coding=optimize) | |
return jpg_bytes | |
image_file = open(sys.argv[1], 'rb') | |
image = BytesIO(image_file.read()) | |
outside_run_time = bench() | |
run_time = bench() | |
original_jpg, original = generate_image_pil(image.getbuffer(), 3508, 2480, quality=90, | |
optimize=False) # insert image decision tree | |
bench(run_time, do_print=True, level=1, info="original conversion with pil") | |
run_time = bench() | |
preview_jpg, preview = generate_image_pil(original, 800, 600, quality=80, optimize=False) | |
bench(run_time, do_print=True, level=1, info="preview conversion with pil") | |
run_time = bench() | |
thumbnail_jpg, thumbnail = generate_image_pil(preview, 250, 250, quality=80, optimize=False) | |
bench(run_time, do_print=True, level=1, info="thumbnail conversion with pil") | |
bench(outside_run_time, do_print=True, info="total time for pil") | |
open("original_pil.jpg", "wb").write(original_jpg.getbuffer()) | |
open("preview_pil.jpg", "wb").write(preview_jpg.getbuffer()) | |
open("thumbnail_pil.jpg", "wb").write(thumbnail_jpg.getbuffer()) | |
outside_run_time = bench() | |
run_time = bench() | |
original_jpg, original = generate_image_vips(image.getvalue(), 3508, 2480, quality=90, optimize=False) | |
bench(run_time, do_print=True, level=1, info="original conversion with vips") | |
run_time = bench() | |
preview_jpg, preview = generate_image_vips(original, 800, 600, quality=80, optimize=False) | |
bench(run_time, do_print=True, level=1, info="preview conversion with vips") | |
run_time = bench() | |
thumbnail_jpg, thumbnail = generate_image_vips(preview, 250, 250, quality=80, optimize=False) | |
bench(run_time, do_print=True, level=1, info="thumbnail conversion with vips") | |
bench(outside_run_time, do_print=True, info="total time for vips") | |
open("original_vips.jpg", "wb").write(original_jpg) | |
open("preview_vips.jpg", "wb").write(preview_jpg) | |
open("thumbnail_vips.jpg", "wb").write(thumbnail_jpg) | |
image_bytes = image.getvalue() | |
outside_run_time = bench() | |
run_time = bench() | |
original_jpg = generate_image_vips_thumbnail(image_bytes, 3508, 2480, quality=90, optimize=False) | |
bench(run_time, do_print=True, level=1, info="original conversion with vips thumbnail") | |
run_time = bench() | |
preview_jpg = generate_image_vips_thumbnail(image_bytes, 800, 600, quality=80, optimize=False) | |
bench(run_time, do_print=True, level=1, info="preview conversion with vips thumbnail") | |
run_time = bench() | |
thumbnail_jpg = generate_image_vips_thumbnail(image_bytes, 250, 250, quality=80, optimize=False) | |
bench(run_time, do_print=True, level=1, info="thumbnail conversion with vips thumbnail") | |
bench(outside_run_time, do_print=True, info="total time for vips thumbnail") | |
open("original_vips_thumbnail.jpg", "wb").write(original_jpg) | |
open("preview_vips_thumbnail.jpg", "wb").write(preview_jpg) | |
open("thumbnail_vips_thumbnail.jpg", "wb").write(thumbnail_jpg) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment