Skip to content

Commit

Permalink
Add tiffdump endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
banesullivan committed Apr 27, 2022
1 parent 89c30dd commit 7de8da3
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 0 deletions.
47 changes: 47 additions & 0 deletions django_large_image/rest/metadata.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
import io
import json
import pathlib

from drf_yasg.utils import swagger_auto_schema
from rest_framework.decorators import action
from rest_framework.exceptions import APIException, ValidationError
from rest_framework.request import Request
from rest_framework.response import Response

from django_large_image import tilesource
from django_large_image.rest import params
from django_large_image.rest.base import LargeImageMixinBase

try:
import tifftools
from tifftools.exceptions import TifftoolsError
except ImportError: # pragma: no cover
tifftools = None
TifftoolsError = None

metadata_summary = 'Returns tile metadata.'
metadata_parameters = params.BASE
metadata_internal_summary = 'Returns additional known metadata about the tile source.'
Expand All @@ -15,6 +27,7 @@
bands_parameters = params.BASE
band_summary = 'Returns single band information.'
band_parameters = params.BASE + [params.band]
tiffdump_summary = 'Returns tifftools tiffdump JSON. This will raise a `ValidationError` if the image is not a Tiff.'


class MetaDataMixin(LargeImageMixinBase):
Expand Down Expand Up @@ -63,6 +76,32 @@ def band(self, request: Request, pk: int = None) -> Response:
metadata = source.getOneBandInformation(band)
return Response(metadata)

@swagger_auto_schema(
method='GET',
operation_summary=tiffdump_summary,
)
@action(detail=False)
def tiffdump(self, request: Request, pk: int = None) -> Response:
if tifftools is None: # pragma: no cover
raise APIException('`tifftools` is not installed on the server.')
source = self.get_tile_source(request, pk, style=False)
# This will only work for local files (path on disk)
path = source._getLargeImagePath()
try:
if not pathlib.Path(path).exists():
raise OSError # pragma: no cover
except OSError:
raise APIException(
'The image path is not local and tifftools will not be able to open this image.'
)
output = io.StringIO()
try:
tifftools.tiff_dump(path, dest=output, outformat='json')
except (TifftoolsError, OSError) as e:
raise ValidationError(str(e))
output.seek(0)
return Response(json.loads(output.read()))


class MetaDataDetailMixin(MetaDataMixin):
@swagger_auto_schema(
Expand Down Expand Up @@ -100,3 +139,11 @@ def bands(self, request: Request, pk: int = None) -> Response:
@action(detail=True)
def band(self, request: Request, pk: int = None) -> Response:
return super().band(request, pk)

@swagger_auto_schema(
method='GET',
operation_summary=tiffdump_summary,
)
@action(detail=True)
def tiffdump(self, request: Request, pk: int = None) -> Response:
return super().tiffdump(request, pk)
22 changes: 22 additions & 0 deletions project/example/core/tests/test_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,25 @@ def test_bad_image_data(authenticated_api_client, lonely_header_file):
# Catches server error safely and returns 500-level APIException
response = authenticated_api_client.get(f'/api/image-file/{lonely_header_file.pk}/metadata')
assert status.is_server_error(response.status_code)


@pytest.mark.django_db(transaction=True)
def test_tiffdump(authenticated_api_client, s3_image_file_geotiff, png_image):
response = authenticated_api_client.get(
f'/api/s3-image-file/{s3_image_file_geotiff.pk}/tiffdump'
)
assert status.is_success(response.status_code)
dump = response.data
assert 'firstifd' in dump
assert 'size' in dump
assert dump['ifds']

# Server error raised when image isn't accessible locally
response = authenticated_api_client.get(
f'/api/s3-vsi-image-file/{s3_image_file_geotiff.pk}/tiffdump'
)
assert status.is_server_error(response.status_code)

# Client error raised when image is not a tiff
response = authenticated_api_client.get(f'/api/image-file/{png_image.pk}/tiffdump')
assert status.is_client_error(response.status_code)

0 comments on commit 7de8da3

Please sign in to comment.