Привет,
Я хочу использовать веб-API для pyvips.
Но действительно плохая производительность. Где я ошибаюсь?
Мой код следующий;
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)
Баш
FLASK_APP = запуск фляги hello.py
```bash
ab -c 10 -n 10 http://54.229.246.74/image\?image\=foto.jpeg
Привет @volkan ,
Я бы реорганизовал ваш конвейер примерно так:
thumbnail
чтобы открыть изображение и уменьшить его размер за одну операцию.gravity
чтобы добавить фонЯ сделаю тебе пример.
Вот тестовая программа, которая запускает ваш код и возможный новый конвейер. Я изменил касательную в вашей версии на:
tangent = float(im.width) / im.height
Но в остальном без изменений.
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
На этом ноутбуке с изображением 6k x 4k я вижу:
$ python volkan.py ~/pics/theo.jpg x.jpg
ImageTransform() took 0.490525960922
after revision, took 0.0774891376495
Вы можете сделать код водяного знака немного проще, я попробую.
Думаю, я бы добавил водяной знак вот так:
# 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)
Итак, мы использовали новую функцию «размер текста по размеру поля» в 8.6, используя x * 0.3
вместо linear
(они делают то же самое, просто перегрузку оператора легче читать), сохраняя текст как 8-битный, чтобы избежать смещения позже, и использование gravity
чтобы сделать embed
немного проще.
@jcupitt ваши примеры очень полезны. Спасибо.
ОК, закрою!
Самый полезный комментарий
Думаю, я бы добавил водяной знак вот так:
Итак, мы использовали новую функцию «размер текста по размеру поля» в 8.6, используя
x * 0.3
вместоlinear
(они делают то же самое, просто перегрузку оператора легче читать), сохраняя текст как 8-битный, чтобы избежать смещения позже, и использованиеgravity
чтобы сделатьembed
немного проще.