diff --git a/warehouse/__init__.py b/warehouse/__init__.py
index e02dcc40cb7c0902631461d458d9ebc951a4e991..11eb99580b6948552cb76c253f786c5d27b1ea74 100644
--- a/warehouse/__init__.py
+++ b/warehouse/__init__.py
@@ -6,7 +6,7 @@ from flask import Flask, render_template, request, redirect, url_for, Response,
 from requests_oauthlib import OAuth2Session
 
 from .models import db, Item, Location, Photo
-from .utils import render_pdf, print_pdf, qrcode_svg, render_markdown, send_thumbnail
+from .utils import render_pdf, print_pdf, qrcode_svg, render_markdown
 
 app = Flask(__name__, instance_relative_config=True)
 app.config.from_pyfile('config.cfg')
@@ -185,13 +185,11 @@ def photo_show(photo_id):
 
 @app.route('/photos/<int:photo_id>/small')
 def photo_small(photo_id):
-	photo = Photo.query.get_or_404(photo_id)
-	return send_thumbnail(photo.image, 130, 100)
+	return Photo.query.get_or_404(photo_id).send_thumbnail(130, 100)
 
 @app.route('/photos/<int:photo_id>/medium')
 def photo_medium(photo_id):
-	photo = Photo.query.get_or_404(photo_id)
-	return send_thumbnail(photo.image, 390, 300)
+	return Photo.query.get_or_404(photo_id).send_thumbnail(390, 300)
 
 @app.route('/C/<code>')
 @app.route('/c/<code>')
diff --git a/warehouse/models.py b/warehouse/models.py
index 5803213ca6a6a1afcf692a7602398fa8b7049b39..40af4a5323c328bfbcdb9a22fa1d8adb1154f48a 100644
--- a/warehouse/models.py
+++ b/warehouse/models.py
@@ -1,7 +1,8 @@
 import secrets
 import os
+import io
 
-from flask import current_app, send_file
+from flask import current_app, send_file, Markup
 from flask_sqlalchemy import SQLAlchemy
 from PIL import Image
 
@@ -42,10 +43,15 @@ class Photo(db.Model):
 		path = os.path.join(current_app.config['UPLOAD_FOLDER'], self.path)
 		return send_file(path, mimetype=self.mimetype)
 
-	@property
-	def image(self):
+	def send_thumbnail(self, max_width, max_height):
 		path = os.path.join(current_app.config['UPLOAD_FOLDER'], self.path)
-		return Image.open(path, formats=['JPEG'])
+		buf = io.BytesIO()
+		with Image.open(path, formats=['JPEG']) as img:
+			scale = min(max_width/img.width, max_height/img.height)
+			img.thumbnail((int(img.width*scale), int(img.height*scale)))
+			img.save(buf, format='JPEG', quality=70)
+			buf.seek(0)
+		return send_file(buf, mimetype='image/jpeg')
 
 def token_typable():
 	alphabet = '23456789ABCDEFGHJKLMNPQRSTUVWX' # not '01OIYZ'
diff --git a/warehouse/utils/__init__.py b/warehouse/utils/__init__.py
index 676a459079afb6fda3d98133f2cb72790438a6ac..1fbb582e821e73c0a3cd55d1da01b59e2d7cc151 100644
--- a/warehouse/utils/__init__.py
+++ b/warehouse/utils/__init__.py
@@ -2,8 +2,7 @@ from .pdf import render_pdf
 from .ipp import print_pdf
 from .codes import qrcode_svg
 
-import io
-from flask import Markup, send_file
+from flask import Markup
 import markdown
 import bleach
 
@@ -17,11 +16,3 @@ def render_markdown(text, short=False):
 		result = result.split('<p>', 1)[-1]
 		result = result.split('</p>', 1)[0]
 	return Markup(result)
-
-def send_thumbnail(img, max_width, max_height):
-	scale = min(max_width/img.width, max_height/img.height)
-	img.thumbnail((int(img.width*scale), int(img.height*scale)))
-	buf = io.BytesIO()
-	img.save(buf, format='JPEG', quality=70)
-	buf.seek(0)
-	return send_file(buf, mimetype='image/jpeg')