Salut,
Je souhaite utiliser l'API Web pour pyvips.
Mais très mauvaise performance. Où est-ce que je fais des erreurs ?
Mon code suit ;
bonjour.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=exécution de la fiole hello.py
```bash
ab -c 10 -n 10 http://54.229.246.74/image\?image\=foto.jpeg
Bonjour @volkan ,
Je réorganiserais votre pipeline en quelque chose comme :
thumbnail
pour ouvrir l'image et réduire la taille en une seule opérationgravity
pour ajouter l'arrière-planJe vais te faire un exemple.
Voici un programme de test qui exécute votre code et un éventuel nouveau pipeline. J'ai changé la ligne tangente dans votre version en :
tangent = float(im.width) / im.height
Mais sinon inchangé.
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
Sur cet ordinateur portable avec une image 6k x 4k, je vois :
$ python volkan.py ~/pics/theo.jpg x.jpg
ImageTransform() took 0.490525960922
after revision, took 0.0774891376495
Vous pourriez rendre votre code de filigrane un peu plus simple, je vais essayer.
Je pense que j'ajouterais le filigrane comme ceci :
# 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)
C'est donc en utilisant la nouvelle fonctionnalité "taille du texte pour ajuster la boîte" dans 8.6, en utilisant x * 0.3
au lieu de linear
(ils font la même chose, la surcharge de l'opérateur est juste plus facile à lire), en gardant le text en 8 bits pour éviter de flotter plus tard, et en utilisant gravity
pour rendre le embed
un peu plus simple.
@jcupitt vos exemples sont très utiles. Merci.
D'accord, je vais fermer !
Commentaire le plus utile
Je pense que j'ajouterais le filigrane comme ceci :
C'est donc en utilisant la nouvelle fonctionnalité "taille du texte pour ajuster la boîte" dans 8.6, en utilisant
x * 0.3
au lieu delinear
(ils font la même chose, la surcharge de l'opérateur est juste plus facile à lire), en gardant le text en 8 bits pour éviter de flotter plus tard, et en utilisantgravity
pour rendre leembed
un peu plus simple.