Mercurial > hg > orthanc-tests
changeset 807:bfbadbfae1e2 pixel-anon
merged default -> pixel-anon
author | Alain Mazy <am@orthanc.team> |
---|---|
date | Thu, 10 Apr 2025 16:33:10 +0200 |
parents | 8dfe8f2590b0 (current diff) b047f7e84741 (diff) |
children | |
files | |
diffstat | 8 files changed, 132 insertions(+), 13 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgtags Tue Mar 25 15:30:05 2025 +0100 +++ b/.hgtags Thu Apr 10 16:33:10 2025 +0200 @@ -47,3 +47,4 @@ 7bfc8992ab8fc44bd811bc60ebf3332303bc87ed Orthanc-1.12.4 847b3c6b360b9b0daeab327133703c60e14e51f0 Orthanc-1.12.5 287aae544b3133f6cecdf768f5a09dacbd75cf91 Orthanc-1.12.6 +2eca398d9676e2378343c48769a4b3938ba96005 Orthanc-1.12.7
--- a/CITATION.cff Tue Mar 25 15:30:05 2025 +0100 +++ b/CITATION.cff Thu Apr 10 16:33:10 2025 +0200 @@ -10,5 +10,5 @@ doi: "10.1007/s10278-018-0082-y" license: "GPL-3.0-or-later" repository-code: "https://orthanc.uclouvain.be/hg/orthanc/" -version: 1.12.6 -date-released: 2025-01-22 +version: 1.12.7 +date-released: 2025-04-07
--- a/NewTests/Authorization/test_authorization.py Tue Mar 25 15:30:05 2025 +0100 +++ b/NewTests/Authorization/test_authorization.py Thu Apr 10 16:33:10 2025 +0200 @@ -341,6 +341,16 @@ o.upload_files_dicom_web(paths = [here / "../../Database/Beaufix/IM-0001-0001.dcm"]) o_admin.instances.delete(orthanc_ids=instances_ids) + if o_admin.is_plugin_version_at_least("authorization", 0, 9, 1): + + # uploader-a shall not be able to upload a study through DICOMWeb using /dicom-web/studies/<StudyInstanceUID of label_b> + self.assert_is_forbidden(lambda: o.upload_files_dicom_web(paths = [here / "../../Database/Knix/Loc/IM-0001-0002.dcm"], endpoint=f"/dicom-web/studies/{self.label_b_study_dicom_id}")) + + # uploader-a shall be able to upload a study through DICOMWeb using /dicom-web/studies/<StudyInstanceUID of label_a> + o.upload_files_dicom_web(paths = [here / "../../Database/Knix/Loc/IM-0001-0002.dcm"], endpoint=f"/dicom-web/studies/{self.label_a_study_dicom_id}") + + # note that, uploader-a is allowed to upload to /dicom-web/studies without checking any labels :-() + o.upload_files_dicom_web(paths = [here / "../../Database/Knix/Loc/IM-0001-0002.dcm"], endpoint=f"/dicom-web/studies") def test_resource_token(self):
--- a/NewTests/PostgresUpgrades/test_pg_upgrades.py Tue Mar 25 15:30:05 2025 +0100 +++ b/NewTests/PostgresUpgrades/test_pg_upgrades.py Thu Apr 10 16:33:10 2025 +0200 @@ -71,6 +71,8 @@ subprocess.run(["docker", "compose", "stop", "orthanc-pg-15-under-tests"], check=True) time.sleep(2) + + # test a full upgrade from a very old version, and a downgrade to the previous version (where we run the integration tests) def test_upgrades_downgrades_with_pg_15(self): # remove everything including the DB from previous tests @@ -144,10 +146,11 @@ o.wait_started() # time.sleep(10000) - subprocess.run(["docker", "compose", "up", "orthanc-tests"], check=True) + subprocess.run(["docker", "compose", "up", "orthanc-tests", "--exit-code-from", "orthanc-tests"], check=True) + # make sure we can still start a new Orthanc with an Old PG server def test_latest_orthanc_with_pg_9(self): # remove everything including the DB from previous tests
--- a/NewTests/requirements.txt Tue Mar 25 15:30:05 2025 +0100 +++ b/NewTests/requirements.txt Thu Apr 10 16:33:10 2025 +0200 @@ -1,3 +1,3 @@ -orthanc-api-client>=0.18.4 +orthanc-api-client>=0.18.5 orthanc-tools>=0.13.0 uvicorn \ No newline at end of file
--- a/Plugins/Transfers/Run.py Tue Mar 25 15:30:05 2025 +0100 +++ b/Plugins/Transfers/Run.py Thu Apr 10 16:33:10 2025 +0200 @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # -*- coding: utf-8 -*-
--- a/Tests/Tests.py Tue Mar 25 15:30:05 2025 +0100 +++ b/Tests/Tests.py Thu Apr 10 16:33:10 2025 +0200 @@ -2562,30 +2562,30 @@ a = ExtractDicomTags(Anonymize(u, { 'PatientName' : 'toto' }), tags) for i in range(4): self.assertNotEqual(ids[i], a[i]) - self.assertFalse(a[4].startswith('Orthanc')) + self.assertNotIn('PS 3.15', a[4]) a = ExtractDicomTags(Anonymize(u, { 'SOPInstanceUID' : 'instance' }), tags) self.assertEqual('instance', a[3]) - self.assertFalse(a[4].startswith('Orthanc')) + self.assertNotIn('PS 3.15', a[4]) a = ExtractDicomTags(Anonymize(u, { 'SeriesInstanceUID' : 'series' }), tags) self.assertEqual('series', a[2]) - self.assertFalse(a[4].startswith('Orthanc')) + self.assertNotIn('PS 3.15', a[4]) a = ExtractDicomTags(Anonymize(u, { 'StudyInstanceUID' : 'study' }), tags) self.assertEqual('study', a[1]) - self.assertFalse(a[4].startswith('Orthanc')) + self.assertNotIn('PS 3.15', a[4]) a = ExtractDicomTags(Anonymize(u, { 'PatientID' : 'patient' }), tags) self.assertEqual('patient', a[0]) - self.assertFalse(a[4].startswith('Orthanc')) + self.assertNotIn('PS 3.15', a[4]) a = ExtractDicomTags(Anonymize(u, { 'PatientID' : 'patient', 'StudyInstanceUID' : 'study', 'SeriesInstanceUID' : 'series', 'SOPInstanceUID' : 'instance' }), tags) self.assertEqual('patient', a[0]) - self.assertFalse(a[4].startswith('Orthanc')) + self.assertNotIn('PS 3.15', a[4]) self.assertEqual(1, len(DoGet(_REMOTE, '/instances'))) @@ -6702,7 +6702,6 @@ SYNTAXES = [ '1.2.840.10008.1.2', '1.2.840.10008.1.2.1', - '1.2.840.10008.1.2.1.99', # Deflated Explicit VR Little Endian (cannot be decoded in debug mode if Orthanc is statically linked against DCMTK 3.6.5) '1.2.840.10008.1.2.2', '1.2.840.10008.1.2.4.50', '1.2.840.10008.1.2.4.51', @@ -6710,6 +6709,10 @@ '1.2.840.10008.1.2.4.70', ] + if IsOrthancVersionAbove(_REMOTE, 1, 12, 7): + SYNTAXES.append('1.2.840.10008.1.2.1.99') # Deflated Explicit VR Little Endian (cannot be decoded in debug mode if Orthanc is statically linked against DCMTK 3.6.5) + + if HasGdcmPlugin(_REMOTE): SYNTAXES = SYNTAXES + [ '1.2.840.10008.1.2.4.80', # This makes DCMTK 3.6.2 crash @@ -7377,7 +7380,6 @@ SYNTAXES = [ '1.2.840.10008.1.2', '1.2.840.10008.1.2.1', - '1.2.840.10008.1.2.1.99', # Deflated Explicit VR Little Endian (cannot be decoded in debug mode if Orthanc is statically linked against DCMTK 3.6.5) '1.2.840.10008.1.2.2', '1.2.840.10008.1.2.4.50', '1.2.840.10008.1.2.4.51', @@ -7385,6 +7387,11 @@ '1.2.840.10008.1.2.4.70', ] + if IsOrthancVersionAbove(_REMOTE, 1, 12, 7): + SYNTAXES.append('1.2.840.10008.1.2.1.99') # Deflated Explicit VR Little Endian (cannot be decoded in debug mode if Orthanc is statically linked against DCMTK 3.6.5) + + + if HasGdcmPlugin(_REMOTE): SYNTAXES = SYNTAXES + [ '1.2.840.10008.1.2.4.80', # This makes DCMTK 3.6.2 crash @@ -8356,6 +8363,7 @@ tags2021b = GetTags(study, { 'DicomVersion' : '2021b' }) tags2023b = GetTags(study, { 'DicomVersion' : '2023b' }) tagsDefault = GetTags(study, {}) + tagsReplace = GetTags(study, { 'Replace' : { 'StationName': 'tutu' }}) orthancVersion = DoGet(_REMOTE, '/system') ['Version'] if orthancVersion.startswith('mainline-'): # happens in unstable orthancteam/orthanc images @@ -8365,6 +8373,9 @@ self.assertEqual('Orthanc %s - PS 3.15-2017c Table E.1-1 Basic Profile' % orthancVersion, tags2017c['0012,0063']) self.assertEqual('Orthanc %s - PS 3.15-2021b Table E.1-1 Basic Profile' % orthancVersion, tags2021b['0012,0063']) self.assertEqual('Orthanc %s - PS 3.15-2023b Table E.1-1 Basic Profile' % orthancVersion, tags2023b['0012,0063']) + if IsOrthancVersionAbove(_REMOTE, 1, 12, 7): + self.assertEqual('Orthanc %s' % orthancVersion, tagsReplace['0012,0063']) + self.assertEqual(tagsDefault['0012,0063'], tags2023b['0012,0063']) self.assertEqual(len(tags2021b), len(tags2023b)) @@ -11953,3 +11964,97 @@ ] }) self.assertEqual(1, len(a)) + + def test_deflated_invalid_size(self): # https://discourse.orthanc-server.org/t/transcoding-to-deflated-transfer-syntax-fails/5489 + if IsOrthancVersionAbove(_REMOTE, 1, 12, 7): + instanceId = '6582b1c0-292ad5ab-ba0f088f-f7a1766f-9a29a54f' + + r = UploadInstance(_REMOTE, 'TransferSyntaxes/1.2.840.10008.1.2.1.99.dcm') + attachments = DoGet(_REMOTE, '/instances/' + instanceId + '/attachments/dicom/info/') + self.assertEqual(instanceId, r['ID']) + self.assertEqual(181071, int(attachments['UncompressedSize'])) + + DoDelete(_REMOTE, '/instances/' + instanceId) + + subprocess.check_call([ FindExecutable('storescu'), '-xd', # propose deflated + _REMOTE['Server'], str(_REMOTE['DicomPort']), + GetDatabasePath('TransferSyntaxes/1.2.840.10008.1.2.1.99.dcm') ]) + attachments = DoGet(_REMOTE, '/instances/' + instanceId + '/attachments/dicom/info/') + self.assertLessEqual(181071, int(attachments['UncompressedSize'])) + self.assertGreaterEqual(181073, int(attachments['UncompressedSize'])) # there might be some padding added + + def test_embed_jpeg(self): + if not IsOrthancVersionAbove(_REMOTE, 1, 12, 7): + return + + with open(GetDatabasePath('Lena.jpg'), 'rb') as f: + jpeg = f.read() + + i = DoPost(_REMOTE, '/tools/create-dicom', json.dumps({ + 'Content' : 'data:image/jpeg;base64,%s' % base64.b64encode(jpeg).decode(), + 'Encapsulate' : True, + 'Tags' : { + 'SOPClassUID' : '1.2.840.10008.5.1.4.1.1.7', + } + })) ['ID'] + + tags = DoGet(_REMOTE, '/instances/%s/tags?simplify' % i) + self.assertEqual(tags['BitsAllocated'], '8') + self.assertEqual(tags['BitsStored'], '8') + self.assertEqual(tags['Columns'], '512') + self.assertEqual(tags['HighBit'], '7') + self.assertEqual(tags['PhotometricInterpretation'], 'YBR_FULL_422') + self.assertEqual(tags['PixelData'], None) + self.assertEqual(tags['PixelRepresentation'], '0') + self.assertEqual(tags['PlanarConfiguration'], '0') + self.assertEqual(tags['Rows'], '512') + self.assertEqual(tags['SOPClassUID'], '1.2.840.10008.5.1.4.1.1.7') + self.assertEqual(tags['SamplesPerPixel'], '3') + self.assertEqual(tags['SpecificCharacterSet'], 'ISO_IR 100') + pixelData = DoGet(_REMOTE, '/instances/%s/content/7fe0,0010' % i) + self.assertEqual(len(pixelData), 2) + self.assertEqual(pixelData[0], '0') + self.assertEqual(pixelData[1], '1') + resp, embedded = DoGetRaw(_REMOTE, '/instances/%s/content/7fe0,0010/1' % i) + self.assertEqual('200', resp['status']) + self.assertEqual(len(embedded), len(jpeg)) + self.assertEqual(embedded, jpeg) + + b = io.BytesIO() + UncompressImage(jpeg).convert('L').save(b, format = 'jpeg') + + b.seek(0) + grayscale = b.read() + + if len(grayscale) % 2 != 0: + grayscale = grayscale + '\0' # Add padding to OW boundaries (2 bytes) + + i = DoPost(_REMOTE, '/tools/create-dicom', json.dumps({ + 'Content' : 'data:image/jpeg;base64,%s' % base64.b64encode(grayscale).decode(), + 'Encapsulate' : True, + 'Tags' : { + 'SOPClassUID' : '1.2.840.10008.5.1.4.1.1.7', + } + })) ['ID'] + + tags = DoGet(_REMOTE, '/instances/%s/tags?simplify' % i) + self.assertEqual(tags['BitsAllocated'], '8') + self.assertEqual(tags['BitsStored'], '8') + self.assertEqual(tags['Columns'], '512') + self.assertEqual(tags['HighBit'], '7') + self.assertEqual(tags['PhotometricInterpretation'], 'MONOCHROME2') + self.assertEqual(tags['PixelData'], None) + self.assertEqual(tags['PixelRepresentation'], '0') + self.assertFalse('PlanarConfiguration' in tags) + self.assertEqual(tags['Rows'], '512') + self.assertEqual(tags['SOPClassUID'], '1.2.840.10008.5.1.4.1.1.7') + self.assertEqual(tags['SamplesPerPixel'], '1') + self.assertEqual(tags['SpecificCharacterSet'], 'ISO_IR 100') + pixelData = DoGet(_REMOTE, '/instances/%s/content/7fe0,0010' % i) + self.assertEqual(len(pixelData), 2) + self.assertEqual(pixelData[0], '0') + self.assertEqual(pixelData[1], '1') + resp, embedded = DoGetRaw(_REMOTE, '/instances/%s/content/7fe0,0010/1' % i) + self.assertEqual('200', resp['status']) + self.assertEqual(len(embedded), len(grayscale)) + self.assertEqual(embedded, grayscale)