in pathology/transformation_pipeline/ingestion_lib/dicom_gen/dicom_slide_coordinates_microscopic_image.py [0:0]
def _create_image_dicom_metadata(image_path: str) -> _ImageDicomMetadata:
"""Creates image metadata for VL Slide-Coordinates DICOM.
Args:
image_path: Path to an image.
Returns:
Image metadata for VL Slide-Coordinates DICOM.
Raises:
InvalidFlatImageError: If invalid flat image (e.g. invalid path, error
reading image, unsupported image format or dimensions, etc).
"""
try:
with PIL.Image.open(image_path) as img:
img.load()
except Exception as exp:
raise InvalidFlatImageError(
f'Failed to open image: {image_path}.',
ingest_const.ErrorMsgs.FLAT_IMAGE_FAILED_TO_OPEN,
) from exp
if img.format not in _SUPPORTED_IMAGE_FORMATS:
raise InvalidFlatImageError(
f'Unexpected image format {img.format} in {image_path}.',
ingest_const.ErrorMsgs.FLAT_IMAGE_UNEXPECTED_FORMAT,
)
if img.width > _MAX_IMAGE_SIZE or img.height > _MAX_IMAGE_SIZE:
raise InvalidFlatImageError(
(
f'Unexpected image dimensions {img.width} x {img.height} '
f'in {image_path}. Expected <= {_MAX_IMAGE_SIZE}.'
),
ingest_const.ErrorMsgs.FLAT_IMAGE_UNEXPECTED_DIMENSIONS,
)
tif_tags = _TifTagsDicomMetadata()
if img.format == 'PNG':
if img.mode == 'RGBA' and _is_opaque(img):
img = img.convert(mode='RGB')
with io.BytesIO() as jpg_bytes:
img.save(jpg_bytes, format='JPEG2000', irreversible=False)
image_bytes = jpg_bytes.getvalue()
with PIL.Image.open(jpg_bytes) as img:
img.load()
image_type = _DICOM_IMAGE_TYPE_DERIVED
transfer_syntax = ingest_const.DicomImageTransferSyntax.JPEG_2000
elif img.format == 'TIFF':
if img.mode == 'RGBA' and _is_opaque(img):
img = img.convert(mode='RGB')
img.save(image_path)
ancillary_image_path = os.path.splitext(image_path)[0] + '.jpg'
ancillary_image = ancillary_image_extractor.AncillaryImage(
path=ancillary_image_path
)
if not ancillary_image_extractor.extract_jpg_image(
image_path,
ancillary_image,
convert_to_jpeg_2000=True,
):
raise InvalidFlatImageError(
f'Failed to convert TIF to JPG: {image_path}',
ingest_const.ErrorMsgs.FLAT_IMAGE_FAILED_TO_CONVERT_TIF_TO_JPG,
)
with PIL.Image.open(ancillary_image.path) as img:
img.load()
with open(ancillary_image.path, 'rb') as img_file:
image_bytes = img_file.read()
if ancillary_image.extracted_without_decompression:
image_type = _DICOM_IMAGE_TYPE_ORIGINAL
transfer_syntax = ingest_const.DicomImageTransferSyntax.JPEG_LOSSY
else:
image_type = _DICOM_IMAGE_TYPE_DERIVED
transfer_syntax = ingest_const.DicomImageTransferSyntax.JPEG_2000
tif_tags = _extract_tif_tags_metadata(image_path)
else:
with open(image_path, 'rb') as img_file:
image_bytes = img_file.read()
image_type = _DICOM_IMAGE_TYPE_ORIGINAL
transfer_syntax = ingest_const.DicomImageTransferSyntax.JPEG_LOSSY
if img.mode not in ['RGB', 'RGBA', '1', 'L']:
raise InvalidFlatImageError(
f'Unexpected image mode {img.mode} in {image_path}.',
ingest_const.ErrorMsgs.FLAT_IMAGE_UNEXPECTED_PIXEL_MODE,
)
if img.mode in ['RGB', 'RGBA']:
if transfer_syntax == ingest_const.DicomImageTransferSyntax.JPEG_LOSSY:
photometric_interpretation = 'YBR_FULL_422'
else:
photometric_interpretation = 'RGB'
samples_per_pixel = 3
else:
photometric_interpretation = 'MONOCHROME2'
samples_per_pixel = 1
compression_ratio = str(
round(
(img.width * img.height * samples_per_pixel)
/ os.path.getsize(image_path),
2,
)
)
return _ImageDicomMetadata( # pytype: disable=wrong-arg-types # pillow-102-upgrade
image_bytes,
img.width,
img.height,
photometric_interpretation,
samples_per_pixel,
compression_ratio,
image_type,
icc_profile=img.info.get('icc_profile'),
transfer_syntax=transfer_syntax,
tif_tags=tif_tags,
)