Towsif7's picture
firrst commit
59e40e1
raw
history blame contribute delete
No virus
10.1 kB
import io
import time
import zipfile
import requests
from PIL import Image, ImageColor
from carvekit.utils.image_utils import transparency_paste, add_margin
from carvekit.utils.mask_utils import extract_alpha_channel
from carvekit.web.responses.api import error_dict
from carvekit.api.interface import Interface
def process_remove_bg(
interface: Interface, params, image, bg, is_json_or_www_encoded=False
):
"""
Handles a request to the removebg api method
Args:
interface: CarveKit interface
bg: background pil image
is_json_or_www_encoded: is "json" or "x-www-form-urlencoded" content-type
image: foreground pil image
params: parameters
"""
h, w = image.size
if h < 2 or w < 2:
return error_dict("Image is too small. Minimum size 2x2"), 400
if "size" in params.keys():
value = params["size"]
if value == "preview" or value == "small" or value == "regular":
image.thumbnail((625, 400), resample=3) # 0.25 mp
elif value == "medium":
image.thumbnail((1504, 1000), resample=3) # 1.5 mp
elif value == "hd":
image.thumbnail((2000, 2000), resample=3) # 2.5 mp
else:
image.thumbnail((6250, 4000), resample=3) # 25 mp
roi_box = [0, 0, image.size[0], image.size[1]]
if "type" in params.keys():
value = params["type"]
pass
if "roi" in params.keys():
value = params["roi"].split(" ")
if len(value) == 4:
for i, coord in enumerate(value):
if "px" in coord:
coord = coord.replace("px", "")
try:
coord = int(coord)
except BaseException:
return (
error_dict(
"Error converting roi coordinate string to number!"
),
400,
)
if coord < 0:
error_dict("Bad roi coordinate."), 400
if (i == 0 or i == 2) and coord > image.size[0]:
return (
error_dict(
"The roi coordinate cannot be larger than the image size."
),
400,
)
elif (i == 1 or i == 3) and coord > image.size[1]:
return (
error_dict(
"The roi coordinate cannot be larger than the image size."
),
400,
)
roi_box[i] = int(coord)
elif "%" in coord:
coord = coord.replace("%", "")
try:
coord = int(coord)
except BaseException:
return (
error_dict(
"Error converting roi coordinate string to number!"
),
400,
)
if coord > 100:
return (
error_dict("The coordinate cannot be more than 100%"),
400,
)
elif coord < 0:
return error_dict("Coordinate cannot be less than 0%"), 400
if i == 0 or i == 2:
coord = int(image.size[0] * coord / 100)
elif i == 1 or i == 3:
coord = int(image.size[1] * coord / 100)
roi_box[i] = coord
else:
return error_dict("Something wrong with roi coordinates!"), 400
new_image = image.copy()
new_image = new_image.crop(roi_box)
h, w = new_image.size
if h < 2 or w < 2:
return error_dict("Image is too small. Minimum size 2x2"), 400
new_image = interface([new_image])[0]
scaled = False
if "scale" in params.keys() and params["scale"] != 100:
value = params["scale"]
new_image.thumbnail(
(int(image.size[0] * value / 100), int(image.size[1] * value / 100)),
resample=3,
)
scaled = True
if "crop" in params.keys():
value = params["crop"]
if value:
new_image = new_image.crop(new_image.getbbox())
if "crop_margin" in params.keys():
crop_margin = params["crop_margin"]
if "px" in crop_margin:
crop_margin = crop_margin.replace("px", "")
crop_margin = abs(int(crop_margin))
if crop_margin > 500:
return (
error_dict(
"The crop_margin cannot be larger than the original image size."
),
400,
)
new_image = add_margin(
new_image,
crop_margin,
crop_margin,
crop_margin,
crop_margin,
(0, 0, 0, 0),
)
elif "%" in crop_margin:
crop_margin = crop_margin.replace("%", "")
crop_margin = int(crop_margin)
new_image = add_margin(
new_image,
int(new_image.size[1] * crop_margin / 100),
int(new_image.size[0] * crop_margin / 100),
int(new_image.size[1] * crop_margin / 100),
int(new_image.size[0] * crop_margin / 100),
(0, 0, 0, 0),
)
else:
if "position" in params.keys() and scaled is False:
value = params["position"]
if len(value) == 2:
new_image = transparency_paste(
Image.new("RGBA", image.size),
new_image,
(
int(image.size[0] * value[0] / 100),
int(image.size[1] * value[1] / 100),
),
)
else:
new_image = transparency_paste(
Image.new("RGBA", image.size), new_image, roi_box
)
elif scaled is False:
new_image = transparency_paste(
Image.new("RGBA", image.size), new_image, roi_box
)
if "channels" in params.keys():
value = params["channels"]
if value == "alpha":
new_image = extract_alpha_channel(new_image)
else:
bg_changed = False
if "bg_color" in params.keys():
value = params["bg_color"]
if len(value) > 0:
color = ImageColor.getcolor(value, "RGB")
bg = Image.new("RGBA", new_image.size, color)
bg = transparency_paste(bg, new_image, (0, 0))
new_image = bg.copy()
bg_changed = True
if "bg_image_url" in params.keys() and bg_changed is False:
value = params["bg_image_url"]
if len(value) > 0:
try:
bg = Image.open(io.BytesIO(requests.get(value).content))
except BaseException:
return error_dict("Error download background image!"), 400
bg = bg.resize(new_image.size)
bg = bg.convert("RGBA")
bg = transparency_paste(bg, new_image, (0, 0))
new_image = bg.copy()
bg_changed = True
if not is_json_or_www_encoded:
if bg and bg_changed is False:
bg = bg.resize(new_image.size)
bg = bg.convert("RGBA")
bg = transparency_paste(bg, new_image, (0, 0))
new_image = bg.copy()
if "format" in params.keys():
value = params["format"]
if value == "jpg":
new_image = new_image.convert("RGB")
img_io = io.BytesIO()
new_image.save(img_io, "JPEG", quality=100)
img_io.seek(0)
return {"type": "jpg", "data": [img_io, new_image.size]}
elif value == "zip":
mask = extract_alpha_channel(new_image)
mask_buff = io.BytesIO()
mask.save(mask_buff, "PNG")
mask_buff.seek(0)
image_buff = io.BytesIO()
image.save(image_buff, "JPEG")
image_buff.seek(0)
fileobj = io.BytesIO()
with zipfile.ZipFile(fileobj, "w") as zip_file:
zip_info = zipfile.ZipInfo(filename="color.jpg")
zip_info.date_time = time.localtime(time.time())[:6]
zip_info.compress_type = zipfile.ZIP_DEFLATED
zip_file.writestr(zip_info, image_buff.getvalue())
zip_info = zipfile.ZipInfo(filename="alpha.png")
zip_info.date_time = time.localtime(time.time())[:6]
zip_info.compress_type = zipfile.ZIP_DEFLATED
zip_file.writestr(zip_info, mask_buff.getvalue())
fileobj.seek(0)
return {"type": "zip", "data": [fileobj.read(), new_image.size]}
else:
buff = io.BytesIO()
new_image.save(buff, "PNG")
buff.seek(0)
return {"type": "png", "data": [buff, new_image.size]}
return (
error_dict(
"Something wrong with request or http api. Please, open new issue on Github! This is error in "
"code."
),
400,
)