From f6420eb709cabf7a828c4b7c6dcc8a123fea2126 Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Wed, 28 Jun 2023 10:36:20 +0300 Subject: [PATCH] Added test to check exif rotated images width/height (#6384) ### Motivation and context ### How has this been tested? ### Checklist - [x] I submit my changes into the `develop` branch - [ ] I have added a description of my changes into the [CHANGELOG](https://github.com/opencv/cvat/blob/develop/CHANGELOG.md) file - [ ] I have updated the documentation accordingly - [x] I have added tests to cover my changes - [ ] I have linked related issues (see [GitHub docs]( https://help.github.com/en/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword)) - [ ] I have increased versions of npm packages if it is necessary ([cvat-canvas](https://github.com/opencv/cvat/tree/develop/cvat-canvas#versioning), [cvat-core](https://github.com/opencv/cvat/tree/develop/cvat-core#versioning), [cvat-data](https://github.com/opencv/cvat/tree/develop/cvat-data#versioning) and [cvat-ui](https://github.com/opencv/cvat/tree/develop/cvat-ui#versioning)) ### License - [x] I submit _my code changes_ under the same [MIT License]( https://github.com/opencv/cvat/blob/develop/LICENSE) that covers the project. Feel free to contact the maintainers if that's a concern. --- cvat-ui/webpack.config.js | 3 -- cvat/apps/engine/media_extractors.py | 2 +- .../case_107_connected_file_share.js | 3 +- .../actions_tasks3/case_118_multi_tasks.js | 3 +- .../images/exif_rotated/left.jpg | Bin 0 -> 3874 bytes .../images/exif_rotated/right.jpg | Bin 0 -> 5990 bytes tests/python/rest_api/test_tasks.py | 34 ++++++++++++++++++ 7 files changed, 39 insertions(+), 6 deletions(-) create mode 100644 tests/mounted_file_share/images/exif_rotated/left.jpg create mode 100644 tests/mounted_file_share/images/exif_rotated/right.jpg diff --git a/cvat-ui/webpack.config.js b/cvat-ui/webpack.config.js index 46f37c843e41..95279a160ff5 100644 --- a/cvat-ui/webpack.config.js +++ b/cvat-ui/webpack.config.js @@ -46,9 +46,6 @@ module.exports = (env) => { publicPath: '/', }, devServer: { - devMiddleware: { - writeToDisk: true, - }, compress: false, host: process.env.CVAT_UI_HOST || 'localhost', client: { diff --git a/cvat/apps/engine/media_extractors.py b/cvat/apps/engine/media_extractors.py index 3fcffed9edef..c79bd84a8ea0 100644 --- a/cvat/apps/engine/media_extractors.py +++ b/cvat/apps/engine/media_extractors.py @@ -667,7 +667,7 @@ def save_as_chunk(self, images, chunk_path): output = io.BytesIO() if self._dimension == DimensionType.DIM_2D: pil_image = rotate_within_exif(Image.open(image)) - pil_image.save(output, format=pil_image.format if pil_image.format else ext or self.IMAGE_EXT, quality=100, subsampling=0) + pil_image.save(output, format=pil_image.format if pil_image.format else self.IMAGE_EXT, quality=100, subsampling=0) else: output, ext = self._write_pcd_file(image)[0:2] arcname = '{:06d}.{}'.format(idx, ext) diff --git a/tests/cypress/e2e/actions_tasks3/case_107_connected_file_share.js b/tests/cypress/e2e/actions_tasks3/case_107_connected_file_share.js index f84c9593f909..36d5367a79a7 100644 --- a/tests/cypress/e2e/actions_tasks3/case_107_connected_file_share.js +++ b/tests/cypress/e2e/actions_tasks3/case_107_connected_file_share.js @@ -38,7 +38,8 @@ context('Connected file share.', () => { cy.get('button').contains('images').click(); cy.wait('@shareRequest').then((interception) => { expect(interception.response.body - .sort((a, b) => a.name.localeCompare(b.name))) + .sort((a, b) => a.name.localeCompare(b.name)) + .filter((el) => el.mime_type === 'image')) .to.deep.equal(expectedImagesList); }); expectedImagesList.forEach((el) => { diff --git a/tests/cypress/e2e/actions_tasks3/case_118_multi_tasks.js b/tests/cypress/e2e/actions_tasks3/case_118_multi_tasks.js index ee1f053cd85d..b4358b05c856 100644 --- a/tests/cypress/e2e/actions_tasks3/case_118_multi_tasks.js +++ b/tests/cypress/e2e/actions_tasks3/case_118_multi_tasks.js @@ -100,7 +100,8 @@ context('Create mutli tasks.', () => { cy.get('button').contains('images').click(); cy.wait('@shareRequest').then((interception) => { expect(interception.response.body - .sort((a, b) => a.name.localeCompare(b.name))) + .sort((a, b) => a.name.localeCompare(b.name)) + .filter((el) => el.mime_type === 'image')) .to.deep.equal(expectedImagesList); }); expectedImagesList.forEach((el) => { diff --git a/tests/mounted_file_share/images/exif_rotated/left.jpg b/tests/mounted_file_share/images/exif_rotated/left.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ad1f89850f5a98e5b8047b2604fece8cba81d421 GIT binary patch literal 3874 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 literal 0 HcmV?d00001 diff --git a/tests/mounted_file_share/images/exif_rotated/right.jpg b/tests/mounted_file_share/images/exif_rotated/right.jpg new file mode 100644 index 0000000000000000000000000000000000000000..183ffebb8eaf0657add2e7794b27854fcf7fc923 GIT binary patch literal 5990 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 literal 0 HcmV?d00001 diff --git a/tests/python/rest_api/test_tasks.py b/tests/python/rest_api/test_tasks.py index e59962608e48..d03b857ca601 100644 --- a/tests/python/rest_api/test_tasks.py +++ b/tests/python/rest_api/test_tasks.py @@ -7,6 +7,7 @@ import json import os import os.path as osp +import zipfile from copy import deepcopy from functools import partial from http import HTTPStatus @@ -689,6 +690,39 @@ def test_can_create_task_with_defined_start_and_stop_frames(self): (task, _) = api_client.tasks_api.retrieve(task_id) assert task.size == 4 + def test_can_create_task_with_exif_rotated_images(self): + task_spec = { + "name": f"test {self._USERNAME} to create a task with exif rotated images", + "labels": [ + { + "name": "car", + } + ], + } + + image_files = ["images/exif_rotated/left.jpg", "images/exif_rotated/right.jpg"] + task_data = { + "server_files": image_files, + "image_quality": 70, + "segment_size": 500, + "use_cache": True, + "sorting_method": "natural", + } + + task_id, _ = create_task(self._USERNAME, task_spec, task_data) + + # check that the frames have correct width and height + with make_api_client(self._USERNAME) as api_client: + _, response = api_client.tasks_api.retrieve_data( + task_id, number=0, type="chunk", quality="original" + ) + with zipfile.ZipFile(io.BytesIO(response.data)) as zip_file: + for name in zip_file.namelist(): + with zip_file.open(name) as zipped_img: + im = Image.open(zipped_img) + # original is 480x640 with 90/-90 degrees rotation + assert im.height == 640 and im.width == 480 + def test_can_create_task_with_sorting_method_natural(self): task_spec = { "name": f"test {self._USERNAME} to create a task with a custom sorting method",