Implemented image conversion and resizing with pillow.

This commit is contained in:
s3lph 2018-09-09 23:59:06 +02:00
parent a7a2b5a76f
commit 31b1cc9c21
7 changed files with 56 additions and 34 deletions

View file

@ -2,6 +2,8 @@ from typing import Any, Dict, Union
import os import os
import magic import magic
from io import BytesIO
from PIL import Image
from matemat.webserver import pagelet, RequestArguments, PageletResponse, RedirectResponse, TemplateResponse from matemat.webserver import pagelet, RequestArguments, PageletResponse, RedirectResponse, TemplateResponse
from matemat.db import MatematDatabase from matemat.db import MatematDatabase
@ -124,16 +126,20 @@ def handle_change(args: RequestArguments, user: User, db: MatematDatabase, confi
return return
# Detect the MIME type # Detect the MIME type
filemagic: magic.FileMagic = magic.detect_from_content(avatar) filemagic: magic.FileMagic = magic.detect_from_content(avatar)
# Currently, only image/png is supported, don't process any other formats if not filemagic.mime_type.startswith('image/'):
if filemagic.mime_type != 'image/png':
# TODO: Optionally convert to png
return return
# Create the absolute path of the upload directory # Create the absolute path of the upload directory
abspath: str = os.path.join(os.path.abspath(config['UploadDir']), 'thumbnails/users/') abspath: str = os.path.join(os.path.abspath(config['UploadDir']), 'thumbnails/users/')
os.makedirs(abspath, exist_ok=True) os.makedirs(abspath, exist_ok=True)
try:
# Parse the image data
image: Image = Image.open(BytesIO(avatar))
# Resize the image to 150x150
image.thumbnail((150, 150), Image.LANCZOS)
# Write the image to the file # Write the image to the file
with open(os.path.join(abspath, f'{user.id}.png'), 'wb') as f: image.save(os.path.join(abspath, f'{user.id}.png'), 'PNG')
f.write(avatar) except OSError:
return
except UnicodeDecodeError: except UnicodeDecodeError:
raise ValueError('an argument not a string') raise ValueError('an argument not a string')
@ -182,22 +188,26 @@ def handle_admin_change(args: RequestArguments, db: MatematDatabase, config: Dic
# If a new product image was uploaded, process it # If a new product image was uploaded, process it
if 'image' in args: if 'image' in args:
# Read the raw image data from the request # Read the raw image data from the request
image = bytes(args.image) avatar = bytes(args.image)
# Only process the image, if its size is more than zero. Zero size means no new image was uploaded # Only process the image, if its size is more than zero. Zero size means no new image was uploaded
if len(image) == 0: if len(avatar) == 0:
return return
# Detect the MIME type # Detect the MIME type
filemagic: magic.FileMagic = magic.detect_from_content(image) filemagic: magic.FileMagic = magic.detect_from_content(avatar)
# Currently, only image/png is supported, don't process any other formats if not filemagic.mime_type.startswith('image/'):
if filemagic.mime_type != 'image/png':
# TODO: Optionally convert to png
return return
# Create the absolute path of the upload directory # Create the absolute path of the upload directory
abspath: str = os.path.join(os.path.abspath(config['UploadDir']), 'thumbnails/products/') abspath: str = os.path.join(os.path.abspath(config['UploadDir']), 'thumbnails/products/')
os.makedirs(abspath, exist_ok=True) os.makedirs(abspath, exist_ok=True)
try:
# Parse the image data
image: Image = Image.open(BytesIO(avatar))
# Resize the image to 150x150
image.thumbnail((150, 150), Image.LANCZOS)
# Write the image to the file # Write the image to the file
with open(os.path.join(abspath, f'{newproduct.id}.png'), 'wb') as f: image.save(os.path.join(abspath, f'{newproduct.id}.png'), 'PNG')
f.write(image) except OSError:
return
# The user requested to restock a product # The user requested to restock a product
elif change == 'restock': elif change == 'restock':

View file

@ -2,6 +2,8 @@ from typing import Any, Dict, Union
import os import os
import magic import magic
from PIL import Image
from io import BytesIO
from matemat.webserver import pagelet, RequestArguments, PageletResponse, RedirectResponse, TemplateResponse from matemat.webserver import pagelet, RequestArguments, PageletResponse, RedirectResponse, TemplateResponse
from matemat.db import MatematDatabase from matemat.db import MatematDatabase
@ -101,19 +103,23 @@ def handle_change(args: RequestArguments, product: Product, db: MatematDatabase,
# If a new product image was uploaded, process it # If a new product image was uploaded, process it
if 'image' in args: if 'image' in args:
# Read the raw image data from the request # Read the raw image data from the request
image = bytes(args.image) avatar = bytes(args.image)
# Only process the image, if its size is more than zero. Zero size means no new image was uploaded # Only process the image, if its size is more than zero. Zero size means no new image was uploaded
if len(image) == 0: if len(avatar) == 0:
return return
# Detect the MIME type # Detect the MIME type
filemagic: magic.FileMagic = magic.detect_from_content(image) filemagic: magic.FileMagic = magic.detect_from_content(avatar)
# Currently, only image/png is supported, don't process any other formats if not filemagic.mime_type.startswith('image/'):
if filemagic.mime_type != 'image/png':
# TODO: Optionally convert to png
return return
# Create the absolute path of the upload directory # Create the absolute path of the upload directory
abspath: str = os.path.join(os.path.abspath(config['UploadDir']), 'thumbnails/products/') abspath: str = os.path.join(os.path.abspath(config['UploadDir']), 'thumbnails/products/')
os.makedirs(abspath, exist_ok=True) os.makedirs(abspath, exist_ok=True)
try:
# Parse the image data
image: Image = Image.open(BytesIO(avatar))
# Resize the image to 150x150
image.thumbnail((150, 150), Image.LANCZOS)
# Write the image to the file # Write the image to the file
with open(os.path.join(abspath, f'{product.id}.png'), 'wb') as f: image.save(os.path.join(abspath, f'{product.id}.png'), 'PNG')
f.write(image) except OSError:
return

View file

@ -2,6 +2,8 @@ from typing import Any, Dict, Optional, Union
import os import os
import magic import magic
from PIL import Image
from io import BytesIO
from matemat.webserver import pagelet, RequestArguments, PageletResponse, RedirectResponse, TemplateResponse from matemat.webserver import pagelet, RequestArguments, PageletResponse, RedirectResponse, TemplateResponse
from matemat.db import MatematDatabase from matemat.db import MatematDatabase
@ -130,13 +132,17 @@ def handle_change(args: RequestArguments, user: User, authuser: User, db: Matema
return return
# Detect the MIME type # Detect the MIME type
filemagic: magic.FileMagic = magic.detect_from_content(avatar) filemagic: magic.FileMagic = magic.detect_from_content(avatar)
# Currently, only image/png is supported, don't process any other formats if not filemagic.mime_type.startswith('image/'):
if filemagic.mime_type != 'image/png':
# TODO: Optionally convert to png
return return
# Create the absolute path of the upload directory # Create the absolute path of the upload directory
abspath: str = os.path.join(os.path.abspath(config['UploadDir']), 'thumbnails/users/') abspath: str = os.path.join(os.path.abspath(config['UploadDir']), 'thumbnails/users/')
os.makedirs(abspath, exist_ok=True) os.makedirs(abspath, exist_ok=True)
try:
# Parse the image data
image: Image = Image.open(BytesIO(avatar))
# Resize the image to 150x150
image.thumbnail((150, 150), Image.LANCZOS)
# Write the image to the file # Write the image to the file
with open(os.path.join(abspath, f'{user.id}.png'), 'wb') as f: image.save(os.path.join(abspath, f'{user.id}.png'), 'PNG')
f.write(avatar) except OSError:
return

View file

@ -34,7 +34,7 @@
<img src="/upload/thumbnails/users/{{ authuser.id }}.png" alt="Avatar of {{ authuser.name }}" /><br/> <img src="/upload/thumbnails/users/{{ authuser.id }}.png" alt="Avatar of {{ authuser.name }}" /><br/>
<label for="admin-avatar-avatar">Upload new file: </label> <label for="admin-avatar-avatar">Upload new file: </label>
<input id="admin-avatar-avatar" type="file" name="avatar" accept="image/png" /><br/> <input id="admin-avatar-avatar" type="file" name="avatar" accept="image/*" /><br/>
<input type="submit" value="Save changes" /> <input type="submit" value="Save changes" />
</form> </form>

View file

@ -50,7 +50,7 @@
<input id="admin-newproduct-price-non-member" type="number" min="0" name="pricenonmember" /><br/> <input id="admin-newproduct-price-non-member" type="number" min="0" name="pricenonmember" /><br/>
<label for="admin-newproduct-image">Image: </label> <label for="admin-newproduct-image">Image: </label>
<input id="admin-newproduct-image" type="file" accept="image/png" /><br/> <input id="admin-newproduct-image" type="file" accept="image/*" /><br/>
<input type="submit" value="Create Product" /> <input type="submit" value="Create Product" />
</form> </form>

View file

@ -26,7 +26,7 @@
<label for="modproduct-image"> <label for="modproduct-image">
<img height="150" src="/upload/thumbnails/products/{{ product.id }}.png" alt="Image of {{ product.name }}" /> <img height="150" src="/upload/thumbnails/products/{{ product.id }}.png" alt="Image of {{ product.name }}" />
</label><br/> </label><br/>
<input id="modproduct-image" type="file" name="image" accept="image/png" /><br/> <input id="modproduct-image" type="file" name="image" accept="image/*" /><br/>
<input id="modproduct-productid" type="hidden" name="productid" value="{{ product.id }}" /><br/> <input id="modproduct-productid" type="hidden" name="productid" value="{{ product.id }}" /><br/>

View file

@ -44,7 +44,7 @@
<label for="moduser-account-avatar"> <label for="moduser-account-avatar">
<img height="150" src="/upload/thumbnails/users/{{ user.id }}.png" alt="Avatar of {{ user.name }}" /> <img height="150" src="/upload/thumbnails/users/{{ user.id }}.png" alt="Avatar of {{ user.name }}" />
</label><br/> </label><br/>
<input id="moduser-account-avatar" type="file" name="avatar" accept="image/png" /><br/> <input id="moduser-account-avatar" type="file" name="avatar" accept="image/*" /><br/>
<input id="moduser-account-userid" type="hidden" name="userid" value="{{ user.id }}" /><br/> <input id="moduser-account-userid" type="hidden" name="userid" value="{{ user.id }}" /><br/>