From 2d72c96a45698ba95821a50b60c9eeb2f42b2ede Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Tue, 26 Jul 2016 17:22:07 +0200 Subject: [PATCH] Sort HDRi files by their image file size. --- .../modules/blender_cloud/texture_libs.py | 33 ++++++ pillar/manage.py | 8 +- tests/test_bcloud_home_project.py | 108 ++++++++++++++++++ 3 files changed, 145 insertions(+), 4 deletions(-) diff --git a/pillar/application/modules/blender_cloud/texture_libs.py b/pillar/application/modules/blender_cloud/texture_libs.py index 6bd302e4..3e24e8b5 100644 --- a/pillar/application/modules/blender_cloud/texture_libs.py +++ b/pillar/application/modules/blender_cloud/texture_libs.py @@ -110,5 +110,38 @@ def has_texture_node(proj, return_hdri=True): return count > 0 +def sort_by_image_width(node, original=None): + """Sort the files in an HDRi node by image file size.""" + + if node.get('node_type') != 'hdri': + return + + if not node.get('properties', {}).get('files'): + return + + # TODO: re-enable this once all current HDRis have been saved in correct order. + # # Don't bother sorting when the files haven't changed. + # if original is not None and \ + # original.get('properties', {}).get('files') == node['properties']['files']: + # return + + log.info('Sorting HDRi node %s', node.get('_id', 'NO-ID')) + files_coll = current_app.data.driver.db['files'] + + def sort_key(file_ref): + file_doc = files_coll.find_one(file_ref['file'], projection={'length': 1}) + return file_doc['length'] + + node['properties']['files'].sort(key=sort_key) + + +def sort_nodes_by_image_width(nodes): + for node in nodes: + sort_by_image_width(node) + + def setup_app(app, url_prefix): + app.on_replace_nodes += sort_by_image_width + app.on_insert_nodes += sort_nodes_by_image_width + app.register_blueprint(blueprint, url_prefix=url_prefix) diff --git a/pillar/manage.py b/pillar/manage.py index b85e3c14..35e0db0a 100755 --- a/pillar/manage.py +++ b/pillar/manage.py @@ -1113,11 +1113,11 @@ def hdri_sort(project_url): for node in nodes: log.info('Processing node %s', node['name']) - def width(file_ref): - file_doc = files_coll.find_one(file_ref['file'], projection={'width': 1}) - return file_doc['width'] + def sort_key(file_ref): + file_doc = files_coll.find_one(file_ref['file'], projection={'length': 1}) + return file_doc['length'] - files = sorted(node['properties']['files'], key=width) + files = sorted(node['properties']['files'], key=sort_key) log.info('Files pre-sort: %s', [file['resolution'] for file in node['properties']['files']]) diff --git a/tests/test_bcloud_home_project.py b/tests/test_bcloud_home_project.py index 97aa2f75..df307ad5 100644 --- a/tests/test_bcloud_home_project.py +++ b/tests/test_bcloud_home_project.py @@ -508,3 +508,111 @@ class TextureLibraryTest(AbstractHomeProjectTest): library_project_ids = {proj['_id'] for proj in libs} self.assertIn(unicode(self.hdri_proj_id), library_project_ids) self.assertIn(unicode(self.tex_proj_id), library_project_ids) + + +class HdriSortingTest(AbstractHomeProjectTest): + def setUp(self, **kwargs): + from manage_extra.node_types.hdri import node_type_hdri + + AbstractHomeProjectTest.setUp(self, **kwargs) + + self.user_id = self._create_user_with_token({u'subscriber'}, 'token') + self.hdri_proj_id, proj = self.ensure_project_exists(project_overrides={ + 'user': self.user_id, + 'permissions': {'world': ['DELETE', 'GET', 'POST', 'PUT']}, + 'node_types': [node_type_hdri], + }) + self.hdri_proj_id = ObjectId(self.hdri_proj_id) + self.assertIsNotNone(self.hdri_proj_id) + + # Add some test files. + with self.app.test_request_context(): + files_coll = self.app.data.driver.db['files'] + self.file_256p = files_coll.insert_one({ + 'name': '96f1adf5330a4cadbf73c13d718ac163.hdr', + 'format': 'radiance-hdr', + 'filename': 'symmetrical_garden_256p.hdr', + 'project': self.hdri_proj_id, + 'length': 106435, + 'user': self.user_id, + 'content_type': 'application/octet-stream', + 'file_path': '96f1adf5330a4cadbf73c13d718ac163.hdr'}).inserted_id + self.file_1k = files_coll.insert_one({ + 'name': '96f1adf5330a4cadbf73qweqwecqwev142v.hdr', + 'format': 'radiance-hdr', + 'filename': 'symmetrical_garden_1k.hdr', + 'project': self.hdri_proj_id, + 'length': 1431435, + 'user': self.user_id, + 'content_type': 'application/octet-stream', + 'file_path': 'd13rfc13r1evadbf73c13d718ac163.hdr'}).inserted_id + self.file_2k = files_coll.insert_one({ + 'name': '34134df5330a4cadbf73qweqwecqwev142v.hdr', + 'format': 'radiance-hdr', + 'filename': 'symmetrical_garden_2k.hdr', + 'project': self.hdri_proj_id, + 'length': 2431435, + 'user': self.user_id, + 'content_type': 'application/octet-stream', + 'file_path': 'd13rfc13r1evadbf73c13d718ac163.hdr'}).inserted_id + + def test_hdri_sorting_on_create(self): + # Create node with files in wrong order + node = {'project': self.hdri_proj_id, + 'node_type': 'hdri', + 'user': self.user_id, + 'properties': { + 'files': [ + {'resolution': '2k', 'file': self.file_2k}, + {'resolution': '256p', 'file': self.file_256p}, + {'resolution': '1k', 'file': self.file_1k}, + ], + 'status': 'published', + }, + 'name': 'Symmetrical Garden' + } + resp = self.post('/nodes', json=node, expected_status=201, auth_token='token') + node_info = resp.json() + + # Check that the node's files are in the right order + resp = self.get('/nodes/%s' % node_info['_id'], auth_token='token') + get_node = resp.json() + + self.assertEqual(['256p', '1k', '2k'], + [file_info['resolution'] + for file_info in get_node['properties']['files']]) + + def test_hdri_sorting_on_update(self): + # Create node with files in correct order + node = {'project': self.hdri_proj_id, + 'node_type': 'hdri', + 'user': self.user_id, + 'properties': { + 'files': [ + {'resolution': '256p', 'file': self.file_256p}, + {'resolution': '1k', 'file': self.file_1k}, + {'resolution': '2k', 'file': self.file_2k}, + ], + 'status': 'published', + }, + 'name': 'Symmetrical Garden' + } + resp = self.post('/nodes', json=node, expected_status=201, auth_token='token') + node_info = resp.json() + + # Mess up the node's order + node['properties']['files'] = [ + {'resolution': '2k', 'file': self.file_2k}, + {'resolution': '1k', 'file': self.file_1k}, + {'resolution': '256p', 'file': self.file_256p}, + ] + self.put('/nodes/%s' % node_info['_id'], json=node, auth_token='token', + headers={'If-Match': node_info['_etag']}) + + # Check that the node's files are in the right order + resp = self.get('/nodes/%s' % node_info['_id'], auth_token='token') + get_node = resp.json() + + self.assertEqual(['256p', '1k', '2k'], + [file_info['resolution'] + for file_info in get_node['properties']['files']])