Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract if source_file in edit images to views #232

Merged
merged 4 commits into from
May 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 3 additions & 7 deletions src/iiif/image_handling.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,17 +103,16 @@ def content_type_to_format(content_type):
return content_type.split("/")[1]


def scale_image(source_file, content_type, scaling, content):
def scale_image(content_type, scaling, content):
"""
Scale the image to the desired size. Never scale up.

:param content: The image data
:param source_file: Bool whether the raw source file should be returned without any scaling
:param scaling: The scaling string from the url
:param content_type: The content type of the image
:return: The scaled image data
"""
if source_file or scaling.lower() == "full":
if scaling.lower() == "full":
return content

desired_width, desired_height = parse_scaling_string(scaling)
Expand Down Expand Up @@ -194,7 +193,7 @@ def clamp(n, minn, maxn):
# TODO: Extract sub functions to own functions for:
# - asserting the region is valid
# - return original when no crop was applied
def crop_image(source_file, content_type, region, content):
def crop_image(content_type, region, content):
"""
Crop the image to the desired size. Never crop outside the image.

Expand All @@ -204,9 +203,6 @@ def crop_image(source_file, content_type, region, content):
:param content_type: The content type of the image
:return: The cropped image data
"""
if source_file:
return content

img = Image.open(BytesIO(content))

match region.lower():
Expand Down
2 changes: 0 additions & 2 deletions src/iiif/parsing.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ def get_info_from_iiif_url(iiif_url, source_file):
"formatting": formatting,
"region": region,
"scaling": scaling,
"source_file": source_file, # Bool whether the file should be served without image processing (pdf/xls)
"source_filename": source_filename, # The filename on the source system
"filename": relevant_url_part, # The filename if this file needs to be stored on disc
"info_json": info_json, # Whether the info.json is requested instead of the image itself
Expand All @@ -115,7 +114,6 @@ def get_info_from_iiif_url(iiif_url, source_file):
"formatting": formatting,
"region": region,
"scaling": scaling,
"source_file": source_file, # Bool whether the file should be served without image processing (pdf/xls)
"source_filename": source_filename, # The filename on the source system
"filename": relevant_url_part, # The filename if this file needs to be stored on disc
"info_json": info_json,
Expand Down
29 changes: 17 additions & 12 deletions src/iiif/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ def index(request, iiif_url):
authentication.check_auth_availability(request)
mail_jwt_token, is_mail_login = authentication.read_out_mail_jwt_token(request)
scope = authentication.get_max_scope(request, mail_jwt_token)
url_info = parsing.get_url_info(
iiif_url, utils.str_to_bool(request.GET.get("source_file"))
)

is_source_file_requested = utils.str_to_bool(request.GET.get("source_file"))
url_info = parsing.get_url_info(iiif_url, is_source_file_requested)

authentication.check_wabo_for_mail_login(is_mail_login, url_info)
metadata, _ = get_metadata(url_info, iiif_url, {})
Expand All @@ -42,16 +42,12 @@ def index(request, iiif_url):

file_content = file_response.content
file_type = file_response.headers.get("Content-Type")
if url_info["info_json"]:
response_content = generate_info_json(
request.build_absolute_uri().split("/info.json")[0],

if is_source_file_requested:
return HttpResponse(
file_content,
file_type,
)
return HttpResponse(
response_content,
content_type="application/json",
)

if not is_image_content_type(file_type):
raise utils.ImmediateHttpResponse(
Expand All @@ -60,15 +56,24 @@ def index(request, iiif_url):
)
)

if url_info["info_json"]:
response_content = generate_info_json(
request.build_absolute_uri().split("/info.json")[0],
file_content,
file_type,
)
return HttpResponse(
response_content,
content_type="application/json",
)

crop = partial(
crop_image,
url_info["source_file"],
file_type,
url_info["region"],
)
scale = partial(
scale_image,
url_info["source_file"],
file_type,
url_info["scaling"],
)
Expand Down
44 changes: 44 additions & 0 deletions tests/test_iiif.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from tests.test_settings import (
IMAGE_BINARY_DATA,
PRE_WABO_IMG_URL_NO_SCALING,
PRE_WABO_IMG_URL_SOURCE_FILE,
PRE_WABO_IMG_URL_WITH_EMPTY_SCALING,
PRE_WABO_IMG_URL_WITH_EXTRA_REFERENCE,
PRE_WABO_IMG_URL_WITH_REGION,
Expand Down Expand Up @@ -147,6 +148,27 @@ def test_get_image_when_image_server_gives_ConnectTimeout(
== RESPONSE_CONTENT_ERROR_RESPONSE_FROM_IMAGE_SERVER + " ConnectTimeout"
)

@patch("iiif.image_server.get_image_from_server")
@patch("iiif.metadata.do_metadata_request")
def test_get_info_json_non_image_raises(
self, mock_do_metadata_request, mock_get_image_from_server, client
):
mock_do_metadata_request.return_value = MockResponse(
200,
json_content=PRE_WABO_METADATA_CONTENT,
)
mock_get_image_from_server.return_value = MockResponse(
200, content=b"b", headers={"Content-Type": "text/xml"}
)

header = {
"HTTP_AUTHORIZATION": "Bearer "
+ create_authz_token(settings.BOUWDOSSIER_READ_SCOPE)
}

response = client.get(self.url + PRE_WABO_INFO_JSON_URL, **header)
assert response.status_code == 400

@patch("iiif.image_server.get_image_from_server")
@patch("iiif.metadata.do_metadata_request")
def test_get_info_json(
Expand Down Expand Up @@ -453,6 +475,28 @@ def test_get_restricted_image_with_only_extended_scope_and_no_read_scope(
assert response.status_code == 200
assert response.content == IMAGE_BINARY_DATA

@patch("iiif.image_server.get_image_from_server")
@patch("iiif.metadata.do_metadata_request")
def test_get_source_image(
self, mock_do_metadata_request, mock_get_image_from_server, client
):
mock_do_metadata_request.return_value = MockResponse(
200,
json_content=PRE_WABO_METADATA_CONTENT,
)
mock_get_image_from_server.return_value = MockResponse(
200, content=IMAGE_BINARY_DATA, headers={"Content-Type": "image/jpeg"}
)

header = {
"HTTP_AUTHORIZATION": "Bearer "
+ create_authz_token(settings.BOUWDOSSIER_READ_SCOPE)
}

response = client.get(self.url + PRE_WABO_IMG_URL_SOURCE_FILE, **header)
assert response.status_code == 200
assert response.content == IMAGE_BINARY_DATA

@patch("iiif.image_server.get_image_from_server")
@patch("iiif.metadata.do_metadata_request")
def test_get_resized_image(
Expand Down
62 changes: 18 additions & 44 deletions tests/test_image_handling.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,30 +40,14 @@ def test_parse_scaling_string(self):
assert parse_scaling_string("100,100") == (100, 100)

def test_scale_image(self):
assert (
scale_image(False, "image/jpeg", "full", self.img_96x85) == self.img_96x85
)
assert (
scale_image(False, "image/jpeg", "100,100", self.img_96x85)
== self.img_96x85
)
assert (
scale_image(False, "image/jpeg", "100,", self.img_96x85) == self.img_96x85
)
assert (
scale_image(False, "image/jpeg", ",100", self.img_96x85) == self.img_96x85
)
assert (
scale_image(True, "image/jpeg", "20,20", self.img_96x85) == self.img_96x85
)
assert (
scale_image(False, "image/jpeg", "50,50", self.img_96x85) == self.img_50x44
)
assert scale_image(False, "image/jpeg", "50,", self.img_96x85) == self.img_50x44
assert (
scale_image(False, "image/jpeg", "60,44", self.img_96x85) == self.img_49x44
)
assert scale_image(False, "image/jpeg", ",44", self.img_96x85) == self.img_49x44
assert scale_image("image/jpeg", "full", self.img_96x85) == self.img_96x85
assert scale_image("image/jpeg", "100,100", self.img_96x85) == self.img_96x85
assert scale_image("image/jpeg", "100,", self.img_96x85) == self.img_96x85
assert scale_image("image/jpeg", ",100", self.img_96x85) == self.img_96x85
assert scale_image("image/jpeg", "50,50", self.img_96x85) == self.img_50x44
assert scale_image("image/jpeg", "50,", self.img_96x85) == self.img_50x44
assert scale_image("image/jpeg", "60,44", self.img_96x85) == self.img_49x44
assert scale_image("image/jpeg", ",44", self.img_96x85) == self.img_49x44

@pytest.mark.parametrize("param", [None, "", ",,,", "x,y,w,h", "50,50,,"])
def test_parse_invalid_region_string_raises(self, param):
Expand All @@ -75,43 +59,33 @@ def test_parse_region_string(self):
assert parse_region_string("0,0,50,44") == (0, 0, 50, 44)

def test_crop_image(self):
assert crop_image(False, "image/jpeg", "full", self.img_96x85) == self.img_96x85
assert (
crop_image(False, "image/jpeg", "square", self.img_96x85) == self.img_85x85
)
assert crop_image("image/jpeg", "full", self.img_96x85) == self.img_96x85
assert crop_image("image/jpeg", "square", self.img_96x85) == self.img_85x85
assert crop_image("image/jpeg", "0,0,100,100", self.img_96x85) == self.img_96x85
assert (
crop_image(False, "image/jpeg", "0,0,100,100", self.img_96x85)
== self.img_96x85
)
assert (
crop_image(True, "image/jpeg", "0,0,50,44", self.img_96x85)
== self.img_96x85
)
assert (
crop_image(False, "image/jpeg", "0,0,50,44", self.img_96x85)
== self.img_0x0x50x44
crop_image("image/jpeg", "0,0,50,44", self.img_96x85) == self.img_0x0x50x44
)
assert (
crop_image(False, "image/jpeg", "24,24,48,48", self.img_96x85)
crop_image("image/jpeg", "24,24,48,48", self.img_96x85)
== self.img_24x24x72x72
)
assert (
crop_image(False, "image/jpeg", "0,41,96,85", self.img_96x85)
crop_image("image/jpeg", "0,41,96,85", self.img_96x85)
== self.img_0x41x96x44
)
assert (
crop_image(False, "image/jpeg", "48,0,96,85", self.img_96x85)
crop_image("image/jpeg", "48,0,96,85", self.img_96x85)
== self.img_48x0x48x85
)
assert (
crop_image(False, "image/jpeg", "-50,-56,100,100", self.img_96x85)
crop_image("image/jpeg", "-50,-56,100,100", self.img_96x85)
== self.img_0x0x50x44
)

def test_crop_image_no_size(self):
with pytest.raises(ImmediateHttpResponse):
crop_image(False, "image/jpeg", "0,0,0,0", self.img_96x85)
crop_image("image/jpeg", "0,0,0,0", self.img_96x85)

def test_crop_outside_image(self):
with pytest.raises(ImmediateHttpResponse):
crop_image(False, "image/jpeg", "100,100,50,50", self.img_96x85)
crop_image("image/jpeg", "100,100,50,50", self.img_96x85)
4 changes: 4 additions & 0 deletions tests/test_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ def filename_from_url(url):
PRE_WABO_IMG_URL_BASE + "10000,10000,48,48/full/0/default.jpg"
)


PRE_WABO_IMG_URL_SOURCE_FILE = (
"2/edepot:ST-00015-ST00000126_00001.jpg/?source_file=true&"
)
PRE_WABO_IMG_URL_NO_SCALING = (
"2/edepot:ST-00015-ST00000126_00001.jpg/full/full/0/default.jpg"
)
Expand Down
Loading
Loading