Packages

A DICOM file format parser and utility library for Elixir

Current section

Files

Jump to
ex_dicom lib util misc.ex
Raw

lib/util/misc.ex

defmodule ExDicom.Util.Misc do
@moduledoc """
Utility functions for DICOM parsing and data handling.
"""
@string_vrs %{
"AE" => true,
"AS" => true,
"AT" => false,
"CS" => true,
"DA" => true,
"DS" => true,
"DT" => true,
"FL" => false,
"FD" => false,
"IS" => true,
"LO" => true,
"LT" => true,
"OB" => false,
"OD" => false,
"OF" => false,
"OW" => false,
"PN" => true,
"SH" => true,
"SL" => false,
"SQ" => false,
"SS" => false,
"ST" => true,
"TM" => true,
"UI" => true,
"UL" => false,
# undefined in original
"UN" => nil,
"UR" => true,
"US" => false,
"UT" => true
}
@typedoc """
Type representing a parsed person name with standard DICOM components.
"""
@type person_name :: %{
family_name: String.t() | nil,
given_name: String.t() | nil,
middle_name: String.t() | nil,
prefix: String.t() | nil,
suffix: String.t() | nil
}
@doc """
Tests if the given VR (Value Representation) is a string type.
## Parameters
* vr - The VR code to test
## Returns
* `true` if string type
* `false` if not string type
* `nil` if unknown VR or UN type
## Examples
iex> ExDicom.Util.string_vr?("PN")
true
iex> ExDicom.Util.string_vr?("UN")
nil
"""
@spec string_vr?(String.t()) :: boolean() | nil
def string_vr?(vr) when is_binary(vr) do
Map.get(@string_vrs, vr)
end
def string_vr?(_), do: nil
@doc """
Tests if a given tag in the format xggggeeee is a private tag.
Private tags are identified by having an odd group number.
## Parameters
* tag - The DICOM tag in format xggggeeee
## Returns
* `true` if the tag is private
* `false` if the tag is not private
## Raises
* RuntimeError if the fourth character of the tag cannot be parsed as hex
## Examples
iex> ExDicom.Util.private_tag?("x00090010")
true
iex> ExDicom.Util.private_tag?("x00080010")
false
"""
@spec private_tag?(String.t()) :: boolean()
def private_tag?(tag) when is_binary(tag) do
case Integer.parse(String.at(tag, 4), 16) do
{last_group_digit, _} ->
rem(last_group_digit, 2) == 1
_ ->
raise "ExDicom.Util.private_tag?: cannot parse last character of group"
end
end
@doc """
Parses a PN (Person Name) formatted string into a map with standardized name components.
## Parameters
* person_name - A string in the PN VR format (components separated by ^)
## Returns
* A map with :family_name, :given_name, :middle_name, :prefix, and :suffix keys
* `nil` if input is nil
## Examples
iex> ExDicom.Util.parse_pn("Smith^John^A^Dr^Jr")
%{
family_name: "Smith",
given_name: "John",
middle_name: "A",
prefix: "Dr",
suffix: "Jr"
}
iex> ExDicom.Util.parse_pn(nil)
nil
"""
@spec parse_pn(String.t() | nil) :: person_name() | nil
def parse_pn(nil), do: nil
def parse_pn(person_name) when is_binary(person_name) do
[family_name, given_name, middle_name, prefix, suffix | _rest] =
String.split(person_name, "^", parts: 5, trim: false) ++ List.duplicate(nil, 5)
%{
family_name: empty_to_nil(family_name),
given_name: empty_to_nil(given_name),
middle_name: empty_to_nil(middle_name),
prefix: empty_to_nil(prefix),
suffix: empty_to_nil(suffix)
}
end
# Helper function to convert empty strings to nil
defp empty_to_nil(""), do: nil
defp empty_to_nil(string), do: string
end