Hi,
I want to use web api for pyvips.
But realy bad performance. Where do I make mistakes?
My code is following;
hello.py
from flask import Flask
from Image import ImageTransform
from flask import request
from flask import send_file
import io
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello World!"
@app.route("/image")
def image():
image_value = request.args.get('image')
i = ImageTransform(image_value)
i.set_transform()
a = i.image.write_to_buffer('.jpeg')
return send_file(io.BytesIO(a), mimetype='image/jpg')
Image.py
import pyvips
import math
class ImageTransform(object):
image = None
def __init__(self, file_name):
self.image = pyvips.Image.new_from_file(file_name, access='sequential')
def set_resize_transform(self, width, height):
im = self.image
mem = im.write_to_buffer('.jpeg[Q=80]')
im = pyvips.Image.thumbnail_buffer(mem, width, height=height)
im = im.bandjoin(255)
im = im.gravity("centre", width, height,
extend="background",
background=[244, 244, 244, 255])
self.image = im
pass
def set_ratio_and_watermark_transform(self):
im = self.image
# ##### ######
# Trigonometry: Tangent = Opposite / Adjacent
tangent = im.height/im.width
# convert arctangent to degrees
angle = math.atan(tangent)*(180/math.pi);
water_mark_x = 140
water_mark_y = 140
water_mark_len = 16
# a^2 = b^2 + c^2 ; a = sqrt(b^2 + c^2)
half_hypotenuse = math.sqrt(im.height*im.height + im.width*im.width)/2;
font_size = int(math.hypot(im.height, im.width)/math.hypot(water_mark_x, water_mark_y)*(4 + int(water_mark_len/2)))
text = pyvips.Image.text("text text text", font = "Futura Medium", align='centre', width = 500, dpi = (font_size*4))
text = text.linear(0.3, 0)
text = text.similarity(angle=angle)
x = (im.width-text.width)/2
y = (im.height-text.height)/2
text = text.embed(x, y, text.width + x, text.height + y, extend="copy")
w = im.width if text.width > im.width else text.width
h = im.height if text.height > im.height else text.height
im = text.ifthenelse(255, im, blend=True)
self.image = im
def set_transform(self, type=int):
self.set_ratio_and_watermark_transform()
self.set_resize_transform(600, 450)
def write_image(self,dest_name):
self.image.write_to_file(dest_name)
```bash
FLASK_APP=hello.py flask run
```bash
ab -c 10 -n 10 http://54.229.246.74/image\?image\=foto.jpeg
Hello @volkan,
I would reorganise your pipeline to something like:
thumbnail to open the image and downsize in one operationgravity to add the backgroundI'll make an example for you.
Here's a test program that runs your code and a possible new pipeline. I changed the tangent line in your version to:
tangent = float(im.width) / im.height
But otherwise unaltered.
import time
import sys
import math
import pyvips
from Image import ImageTransform
start = time.time()
i = ImageTransform(sys.argv[1])
i.set_transform()
i.write_image(sys.argv[2])
end = time.time()
print "ImageTransform() took ", end - start
start = time.time()
target_width = 600
target_height = 450
# efficiently load and downsize in one operation
im = pyvips.Image.thumbnail(sys.argv[1], target_width, height=target_height)
# watermark
tangent = float(im.width) / im.height
angle = math.atan(tangent) * (180 / math.pi)
water_mark_x = 140
water_mark_y = 140
water_mark_len = 16
half_hypotenuse = math.sqrt(im.height*im.height + im.width*im.width)/2;
font_size = int(math.hypot(im.height, im.width)/math.hypot(water_mark_x, water_mark_y)*(4 + int(water_mark_len/2)))
text = pyvips.Image.text("text text text", font = "Futura Medium", align='centre', width = 500, dpi = (font_size*4))
text = text.linear(0.3, 0)
text = text.similarity(angle=angle)
x = (im.width - text.width) / 2
y = (im.height - text.height) / 2
text = text.embed(x, y, text.width + x, text.height + y, extend="copy")
w = im.width if text.width > im.width else text.width
h = im.height if text.height > im.height else text.height
im = text.ifthenelse(255, im, blend=True)
# add alpha and margins
im = im.bandjoin(255)
im = im.gravity("centre", target_width, target_height,
extend="background",
background=[244, 244, 244, 255])
im.write_to_file(sys.argv[2])
end = time.time()
print "after revision, took ", end - start
On this laptop with a 6k x 4k image, I see:
$ python volkan.py ~/pics/theo.jpg x.jpg
ImageTransform() took 0.490525960922
after revision, took 0.0774891376495
You could make your watermark code a little simpler, I'll have a go.
I think I'd add the watermark like this:
# in libvips 8.6, you can get text to automatically size to fill a rectangle
text = pyvips.Image.text("text text text",
font="Futura Medium", align="centre",
width=300, height=300)
# scale down brightness, then back to 8 bit ... this will avoid float arithmetic
# for the rotate/expand/ifthenelse
text = (text * 0.3).cast("uchar")
tangent = float(im.width) / im.height
angle = math.atan(tangent) * (180 / math.pi)
text = text.similarity(angle=angle)
text = text.gravity("centre", target_width, target_height)
im = text.ifthenelse(255, im, blend=True)
So that's using the new "size text to fit box" feature in 8.6, using x * 0.3 instead of linear (they do the same thing, the operator overload is just easier to read), keeping the text as 8-bit to avoid float later, and using gravity to make the embed a bit simpler.
@jcupitt your examples very helpful. Thanks.
OK, I'll close!
Most helpful comment
I think I'd add the watermark like this:
So that's using the new "size text to fit box" feature in 8.6, using
x * 0.3instead oflinear(they do the same thing, the operator overload is just easier to read), keeping the text as 8-bit to avoid float later, and usinggravityto make theembeda bit simpler.