dicom 0.7 → 0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +55 -0
- data/README +51 -29
- data/init.rb +1 -0
- data/lib/dicom.rb +35 -21
- data/lib/dicom/{Anonymizer.rb → anonymizer.rb} +178 -80
- data/lib/dicom/constants.rb +121 -0
- data/lib/dicom/d_client.rb +888 -0
- data/lib/dicom/d_library.rb +208 -0
- data/lib/dicom/d_object.rb +424 -0
- data/lib/dicom/d_read.rb +433 -0
- data/lib/dicom/d_server.rb +397 -0
- data/lib/dicom/d_write.rb +420 -0
- data/lib/dicom/data_element.rb +175 -0
- data/lib/dicom/{Dictionary.rb → dictionary.rb} +390 -398
- data/lib/dicom/elements.rb +82 -0
- data/lib/dicom/file_handler.rb +116 -0
- data/lib/dicom/item.rb +87 -0
- data/lib/dicom/{Link.rb → link.rb} +749 -388
- data/lib/dicom/ruby_extensions.rb +44 -35
- data/lib/dicom/sequence.rb +62 -0
- data/lib/dicom/stream.rb +493 -0
- data/lib/dicom/super_item.rb +696 -0
- data/lib/dicom/super_parent.rb +615 -0
- metadata +25 -18
- data/DOCUMENTATION +0 -469
- data/lib/dicom/DClient.rb +0 -584
- data/lib/dicom/DLibrary.rb +0 -194
- data/lib/dicom/DObject.rb +0 -1579
- data/lib/dicom/DRead.rb +0 -532
- data/lib/dicom/DServer.rb +0 -304
- data/lib/dicom/DWrite.rb +0 -410
- data/lib/dicom/FileHandler.rb +0 -50
- data/lib/dicom/Stream.rb +0 -354
data/CHANGELOG
CHANGED
@@ -1,3 +1,58 @@
|
|
1
|
+
= 0.8
|
2
|
+
|
3
|
+
=== 1st August, 2010
|
4
|
+
|
5
|
+
* Overall changes:
|
6
|
+
* A complete rewrite of data element handling has resulted in a substantially different syntax and significantly cleaner and simpler code.
|
7
|
+
* Greatly increased speed in DICOM object interaction. Especially noticeable on larger DICOM files.
|
8
|
+
* A complete overhaul of the documentation has resulted in a consistent RDoc-style documentation across all classes/modules.
|
9
|
+
* Increased use of module constants for improved code readability.
|
10
|
+
* Major cleanup of codes and comments to make it consistent with Ruby 'best practice' guidelines.
|
11
|
+
* Ready for Rails 3 (compatible with Bundler).
|
12
|
+
* Resulting from the rewrite is a number of new classes and modules for handling the various data objects:
|
13
|
+
* DataElement: Ordinary data elements are instances of this class.
|
14
|
+
* Item: Item elements are instances of this class.
|
15
|
+
* Sequence: Sequence elements are instances of this class.
|
16
|
+
* SuperItem: Methods which are shared between DObject and Item (mostly image related methods).
|
17
|
+
* SuperParent: Methods which are shared between all parent objects (DObject, Item & Sequence).
|
18
|
+
* Elements: A mix-in module used by all element objects (DataElement, Item & Sequence).
|
19
|
+
* DObject:
|
20
|
+
* Completely rewritten data element handling.
|
21
|
+
* Rewritten print() method with improved tree structure visualization, item indices and the ability to run on any parent element.
|
22
|
+
* Renamed the print_properties() method to information(), and improved the amount of information outputted.
|
23
|
+
* Removed the following methods: get_frames(), get_image_pos(), get_pos(), get_value(), get_bin(), set_value()
|
24
|
+
* Renamed get_pixels() method to decode_pixels().
|
25
|
+
* Replaced get_value() with value(). The set_value() method is replaced by the new() methods of DataElement, Sequence and Item classes.
|
26
|
+
* Added the ability to add items at a specific index (shifting any existing items to appear after the inserted item).
|
27
|
+
* Added the transfer_syntax=() method for changing the transfer syntax of a DICOM object.
|
28
|
+
* Implemented a more robust padding of data element values with odd length, based on data element VR.
|
29
|
+
* Added methods for removing all sequences, removing selected groups and returning all data elements of a selected group.
|
30
|
+
* Optimized the get_image_narray() method to more efficiently return the pixel data.
|
31
|
+
* Refined the print_all convenience method to call both print() and information().
|
32
|
+
* DRead:
|
33
|
+
* More robust against crashing when parsing invalid files by proper use of exception handling.
|
34
|
+
* Fixed some cases where a failed read where incorrectly marked as successful.
|
35
|
+
* Increased compatibility (handles DICOM files saved with explicit syntax but no transfer syntax tag).
|
36
|
+
* Explicit DICOM files with data elements of type "OF" are now handled correctly (both read and write).
|
37
|
+
* DWrite:
|
38
|
+
* Simplified code and execution by removing group lengths (deprecated in the DICOM standard) and using undefined length for sequences/items.
|
39
|
+
* More flexible insertion of missing meta group elements.
|
40
|
+
* Dictionary:
|
41
|
+
* Some minor text corrections.
|
42
|
+
* Anonymizer:
|
43
|
+
* Anonymizations executes much faster thanks to the work done with DObject data element handling.
|
44
|
+
* Only top level data elements can be anonymized.
|
45
|
+
* DClient:
|
46
|
+
* Can transmit multiple DICOM files at once with the send() method, which now will accept both DObjects and file strings.
|
47
|
+
* Added the echo() method for performing a C-ECHO-RQ against a SCP.
|
48
|
+
* DServer:
|
49
|
+
* Support for role negotiation.
|
50
|
+
* Properly returns called AE title in association response.
|
51
|
+
* The lists of acceptable abstract and transfer syntax can now be easily modified by the user.
|
52
|
+
* Receiving multiple files (like an entire series, or study) in a single association is now supported.
|
53
|
+
* Properly receives and responds to a C-ECHO-RQ.
|
54
|
+
|
55
|
+
|
1
56
|
= 0.7
|
2
57
|
|
3
58
|
=== 28th February, 2010
|
data/README
CHANGED
@@ -1,48 +1,70 @@
|
|
1
|
-
RUBY
|
1
|
+
RUBY-DICOM
|
2
2
|
======================
|
3
3
|
|
4
4
|
SUMMARY
|
5
5
|
--------
|
6
6
|
|
7
|
-
|
7
|
+
Ruby-DICOM is a small and simple library for handling DICOM in Ruby. DICOM (Digital Imaging
|
8
8
|
and Communications in Medicine) is a standard for handling, storing, printing,
|
9
9
|
and transmitting information in medical imaging. It includes a file format definition
|
10
|
-
and a network communications protocol. Ruby
|
11
|
-
writing to this file format. It also features
|
12
|
-
communication modalities like
|
10
|
+
and a network communications protocol. Ruby-DICOM supports reading from, editing
|
11
|
+
and writing to this file format. It also features basic support for select network
|
12
|
+
communication modalities like querying, moving, sending and receiving files.
|
13
|
+
|
14
|
+
|
15
|
+
INSTALLATION
|
16
|
+
------------
|
17
|
+
|
18
|
+
gem install dicom
|
19
|
+
|
13
20
|
|
14
21
|
BASIC USAGE
|
15
22
|
-----------
|
16
23
|
|
17
24
|
require "dicom"
|
18
25
|
# Read file:
|
19
|
-
|
26
|
+
obj = DICOM::DObject.new("some_file.dcm")
|
20
27
|
# Display some key information about the file:
|
21
|
-
|
22
|
-
# Print all
|
23
|
-
|
28
|
+
obj.information
|
29
|
+
# Print all data elements to screen:
|
30
|
+
obj.print
|
24
31
|
# Retrieve a data element value:
|
25
|
-
name =
|
26
|
-
#
|
27
|
-
|
28
|
-
#
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
image
|
33
|
-
|
32
|
+
name = obj.value("0010.0010")
|
33
|
+
# Modify the data element's value:
|
34
|
+
obj["0010.0010"].value = "Anonymous"
|
35
|
+
# Remove a data element from the DICOM object:
|
36
|
+
obj.remove("7FE0,0010")
|
37
|
+
# Retrieve the pixel data in a Ruby Array:
|
38
|
+
pixels = obj.get_image
|
39
|
+
# Load the pixel data to a RMagick image object and display it on the screen:
|
40
|
+
image = obj.get_image_magick
|
41
|
+
image.display
|
42
|
+
# Load the pixel data to a NArray object and display it on screen (using NImage):
|
43
|
+
pixel_data = obj.get_image_narray
|
44
|
+
NImage.show pixel_data[0,true,true]
|
34
45
|
# Send a local file to a server (PACS) over the network:
|
35
46
|
node = DICOM::DClient.new("10.1.25.200", 104)
|
36
|
-
node.send("
|
37
|
-
|
38
|
-
|
39
|
-
When
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
A hack to avoid this effect is to append ";0" after a command.
|
47
|
+
node.send("some_file.dcm")
|
48
|
+
|
49
|
+
IRB:
|
50
|
+
When working with Ruby DICOM in irb, you may be annoyed with all the information
|
51
|
+
that is printed to screen, regardless if you have set verbose as false. This is because
|
52
|
+
in irb every variable loaded in the program is automatically printed to the screen.
|
53
|
+
A useful hack to avoid this effect is to append ";0" after a command.
|
44
54
|
Example:
|
45
|
-
|
55
|
+
obj = DICOM::DObject.new("some_file.dcm") ;0
|
56
|
+
|
57
|
+
|
58
|
+
RESOURCES
|
59
|
+
---------
|
60
|
+
|
61
|
+
Official home page:
|
62
|
+
http://dicom.rubyforge.org/
|
63
|
+
Discussion forum:
|
64
|
+
http://groups.google.no/group/ruby-dicom
|
65
|
+
Source code repository:
|
66
|
+
http://github.com/cuthbert/ruby-dicom
|
67
|
+
|
46
68
|
|
47
69
|
COPYRIGHT
|
48
70
|
---------
|
@@ -73,6 +95,6 @@ Location:
|
|
73
95
|
Oslo, Norway
|
74
96
|
|
75
97
|
Email:
|
76
|
-
chris.lervag [@nospam] @gmail.com
|
77
|
-
Please don't hesitate to email me if have any thoughts about this project!
|
98
|
+
chris.lervag [@nospam.com] @gmail.com
|
99
|
+
Please don't hesitate to email me if you have any thoughts about this project!
|
78
100
|
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'dicom'
|
data/lib/dicom.rb
CHANGED
@@ -1,25 +1,39 @@
|
|
1
|
+
# Loads the files that are used by Ruby DICOM.
|
2
|
+
#
|
3
|
+
# The following classes are meant to be used by users of Ruby DICOM:
|
4
|
+
# * DObject - for reading, manipulating and writing DICOM files.
|
5
|
+
# * DataElement, Sequence, Item, SuperParent, Elements - users who wish to interact with their DICOM objects will use these classes/modules.
|
6
|
+
# * SuperItem - Image related methods are found in this class.
|
7
|
+
# * DClient - for client side network communication, like querying, moving & sending DICOM files.
|
8
|
+
# * DServer - for server side network communication: Setting up your own DICOM storage node (SCP).
|
9
|
+
# * Anonymizer - a convenience class for anonymizing your DICOM files.
|
10
|
+
#
|
11
|
+
# The rest of the classes visible in the documentation generated by RDoc is in principle
|
12
|
+
# 'private' classes, which are mainly of interest to developers.
|
13
|
+
|
1
14
|
# Core library:
|
2
|
-
|
3
|
-
require 'dicom/
|
4
|
-
require 'dicom/
|
5
|
-
require 'dicom/
|
6
|
-
|
7
|
-
require 'dicom/
|
8
|
-
require 'dicom/
|
9
|
-
require 'dicom/
|
10
|
-
require 'dicom/
|
11
|
-
require 'dicom/
|
12
|
-
|
13
|
-
require 'dicom/
|
15
|
+
# Super classes/modules:
|
16
|
+
require 'dicom/super_parent'
|
17
|
+
require 'dicom/super_item'
|
18
|
+
require 'dicom/elements'
|
19
|
+
# Subclasses and independent classes:
|
20
|
+
require 'dicom/data_element'
|
21
|
+
require 'dicom/d_client'
|
22
|
+
require 'dicom/dictionary'
|
23
|
+
require 'dicom/d_library'
|
24
|
+
require 'dicom/d_object'
|
25
|
+
require 'dicom/d_read'
|
26
|
+
require 'dicom/d_server'
|
27
|
+
require 'dicom/d_write'
|
28
|
+
require 'dicom/file_handler'
|
29
|
+
require 'dicom/item'
|
30
|
+
require 'dicom/link'
|
31
|
+
require 'dicom/sequence'
|
32
|
+
require 'dicom/stream'
|
14
33
|
# Extensions to the Ruby library:
|
15
34
|
require 'dicom/ruby_extensions'
|
35
|
+
# Module constants:
|
36
|
+
require 'dicom/constants'
|
16
37
|
|
17
|
-
#
|
18
|
-
|
19
|
-
|
20
|
-
# Load the DICOM Library class (dictionary):
|
21
|
-
DICOM::LIBRARY = DICOM::DLibrary.new
|
22
|
-
|
23
|
-
# Ruby DICOM implementation name and uid:
|
24
|
-
DICOM::NAME = "RUBY_DICOM_" + DICOM::VERSION
|
25
|
-
DICOM::UID = "1.2.826.0.1.3680043.8.641"
|
38
|
+
# Extensions (non-core functionality):
|
39
|
+
require 'dicom/anonymizer'
|
@@ -2,26 +2,39 @@
|
|
2
2
|
|
3
3
|
module DICOM
|
4
4
|
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
5
|
+
# This is a convenience class for handling anonymization of DICOM files.
|
6
|
+
#
|
7
|
+
# === Notes
|
8
|
+
#
|
9
|
+
# For 'advanced' anonymization, a good resource might be:
|
10
|
+
# ftp://medical.nema.org/medical/dicom/supps/sup142_pc.pdf
|
11
|
+
# (Clinical Trials De-identification Profiles, DICOM Standards Committee, Working Group 18)
|
12
|
+
#
|
8
13
|
class Anonymizer
|
9
14
|
|
10
|
-
|
11
|
-
|
12
|
-
#
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
15
|
+
# A boolean that if set as true will cause all anonymized tags to be blank instead of get some generic value.
|
16
|
+
attr_accessor :blank
|
17
|
+
# A boolean that if set as true will cause all anonymized tags to be get enumerated values, to enable post-anonymization identification by the user.
|
18
|
+
attr_accessor :enumeration
|
19
|
+
# A boolean, which if enumeration has been selected, can be set as true to make the anonymization produce an identity file that will provide a relationship between original and anonymized values.
|
20
|
+
attr_accessor :identity_file
|
21
|
+
# A boolean that if set as true, will make the anonymization remove all private tags.
|
22
|
+
attr_accessor :remove_private
|
23
|
+
# The path where the anonymized files will be saved. If this value is not set, the original DICOM files will be overwritten.
|
24
|
+
attr_accessor :write_path
|
25
|
+
|
26
|
+
# Creates an Anonymizer instance.
|
27
|
+
#
|
28
|
+
# === Examples
|
29
|
+
#
|
30
|
+
# a = Anonymizer.new
|
31
|
+
#
|
32
|
+
def initialize
|
17
33
|
# Default value of accessors:
|
18
|
-
# Replace all values with a blank string?
|
19
34
|
@blank = false
|
20
|
-
# Enumerate selected replacement values?
|
21
35
|
@enumeration = false
|
22
|
-
|
36
|
+
@identity_file = nil
|
23
37
|
@remove_private = false
|
24
|
-
# A separate path may be selected for writing the anonymized files:
|
25
38
|
@write_path = nil
|
26
39
|
# Array of folders to be processed for anonymization:
|
27
40
|
@folders = Array.new
|
@@ -33,9 +46,9 @@ module DICOM
|
|
33
46
|
@values = Array.new
|
34
47
|
# Which data elements will have enumeration applied, if requested by the user:
|
35
48
|
@enum = Array.new
|
36
|
-
# We use a
|
37
|
-
@enum_old_hash =
|
38
|
-
@enum_new_hash =
|
49
|
+
# We use a Hash to store information from DICOM files if enumeration is desired:
|
50
|
+
@enum_old_hash = Hash.new
|
51
|
+
@enum_new_hash = Hash.new
|
39
52
|
# All the files to be anonymized will be put in this array:
|
40
53
|
@files = Array.new
|
41
54
|
# Write paths will be determined later and put in this array:
|
@@ -44,14 +57,16 @@ module DICOM
|
|
44
57
|
set_defaults
|
45
58
|
end
|
46
59
|
|
47
|
-
|
48
|
-
#
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
#
|
60
|
+
# Adds an exception folder which will be avoided when anonymizing.
|
61
|
+
#
|
62
|
+
# === Parameters
|
63
|
+
#
|
64
|
+
# * <tt>path</tt> -- String. A path that will be avoided.
|
65
|
+
#
|
66
|
+
# === Examples
|
67
|
+
#
|
68
|
+
# a.add_exception("/home/dicom/tutorials/")
|
69
|
+
#
|
55
70
|
def add_exception(path)
|
56
71
|
if path
|
57
72
|
# Remove last character if the path ends with a file separator:
|
@@ -60,12 +75,40 @@ module DICOM
|
|
60
75
|
end
|
61
76
|
end
|
62
77
|
|
78
|
+
# Adds a folder who's files will be anonymized.
|
79
|
+
#
|
80
|
+
# === Parameters
|
81
|
+
#
|
82
|
+
# * <tt>path</tt> -- String. A path that will be included in the anonymization.
|
83
|
+
#
|
84
|
+
# === Examples
|
85
|
+
#
|
86
|
+
# a.add_folder("/home/dicom")
|
87
|
+
#
|
88
|
+
def add_folder(path)
|
89
|
+
@folders << path if path
|
90
|
+
end
|
63
91
|
|
64
|
-
# Adds a tag to the list of tags that will be anonymized
|
65
|
-
|
92
|
+
# Adds a tag to the list of tags that will be anonymized.
|
93
|
+
#
|
94
|
+
# === Parameters
|
95
|
+
#
|
96
|
+
# * <tt>tag</tt> -- String. A data element tag.
|
97
|
+
# * <tt>options</tt> -- A hash of parameters.
|
98
|
+
#
|
99
|
+
# === Options
|
100
|
+
#
|
101
|
+
# * <tt>:value</tt> -- A replacement value to use for when anonymizing this data element.
|
102
|
+
# * <tt>:enum</tt> -- Boolean. Specifies if enumeration is to be used for this tag (true) or not (false).
|
103
|
+
#
|
104
|
+
# === Examples
|
105
|
+
#
|
106
|
+
# a.add_tag("0010,0010, :value => "MrAnonymous", :enum => true)
|
107
|
+
#
|
108
|
+
def add_tag(tag, options={})
|
66
109
|
# Options and defaults:
|
67
|
-
value =
|
68
|
-
enum =
|
110
|
+
value = options[:value] || ""
|
111
|
+
enum = options[:enum] || false
|
69
112
|
if tag
|
70
113
|
if tag.is_a?(String)
|
71
114
|
if tag.length == 9
|
@@ -84,8 +127,13 @@ module DICOM
|
|
84
127
|
end
|
85
128
|
end
|
86
129
|
|
87
|
-
|
88
|
-
#
|
130
|
+
# Sets the enumeration status for a specific tag.
|
131
|
+
#
|
132
|
+
# === Parameters
|
133
|
+
#
|
134
|
+
# * <tt>tag</tt> -- String. A data element tag.
|
135
|
+
# * <tt>enum</tt> -- Boolean. True to enable enumeration, false to disable it.
|
136
|
+
#
|
89
137
|
def change_enum(tag, enum)
|
90
138
|
pos = @tags.index(tag)
|
91
139
|
if pos
|
@@ -99,8 +147,17 @@ module DICOM
|
|
99
147
|
end
|
100
148
|
end
|
101
149
|
|
102
|
-
|
103
|
-
#
|
150
|
+
# Changes the value to be used in the anonymization of a specific tag.
|
151
|
+
#
|
152
|
+
# === Parameters
|
153
|
+
#
|
154
|
+
# * <tt>tag</tt> -- String. A data element tag.
|
155
|
+
# * <tt>value</tt> -- The new anonymization replacement value for this data element.
|
156
|
+
#
|
157
|
+
# === Examples
|
158
|
+
#
|
159
|
+
# a.change_value("0008,0090", "Dr.No")
|
160
|
+
#
|
104
161
|
def change_value(tag, value)
|
105
162
|
pos = @tags.index(tag)
|
106
163
|
if pos
|
@@ -114,8 +171,21 @@ module DICOM
|
|
114
171
|
end
|
115
172
|
end
|
116
173
|
|
117
|
-
|
118
|
-
#
|
174
|
+
# Executes the anonymization process.
|
175
|
+
#
|
176
|
+
# This method is run when all settings have been finalized for the Anonymization instance.
|
177
|
+
#
|
178
|
+
# === Restrictions
|
179
|
+
#
|
180
|
+
# * Only top level data elements are anonymized!
|
181
|
+
#
|
182
|
+
# === Parameters
|
183
|
+
#
|
184
|
+
# * <tt>verbose</tt> -- Boolean. If set as true, verbose behaviour will be set for the DObject instances that are anonymized. Defaults to false.
|
185
|
+
#
|
186
|
+
#--
|
187
|
+
# FIXME: This method has grown a bit lengthy. Perhaps it should be looked at one day.
|
188
|
+
#
|
119
189
|
def execute(verbose=false)
|
120
190
|
# Search through the folders to gather all the files to be anonymized:
|
121
191
|
puts "*******************************************************"
|
@@ -153,24 +223,28 @@ module DICOM
|
|
153
223
|
if obj.read_success
|
154
224
|
# Anonymize the desired tags:
|
155
225
|
@tags.each_index do |j|
|
156
|
-
|
157
|
-
|
158
|
-
if
|
159
|
-
|
160
|
-
elsif @enumeration
|
161
|
-
old_value = obj.get_value(pos, :silent => true)
|
162
|
-
# Only launch enumeration logic if tag exists:
|
163
|
-
if old_value
|
164
|
-
value = get_enumeration_value(old_value, j)
|
165
|
-
else
|
226
|
+
if obj.exists?(@tags[j])
|
227
|
+
element = obj[@tags[j]]
|
228
|
+
if element.is_a?(DataElement)
|
229
|
+
if @blank
|
166
230
|
value = ""
|
231
|
+
elsif @enumeration
|
232
|
+
old_value = element.value
|
233
|
+
# Only launch enumeration logic if tag exists:
|
234
|
+
if old_value
|
235
|
+
value = get_enumeration_value(old_value, j)
|
236
|
+
else
|
237
|
+
value = ""
|
238
|
+
end
|
239
|
+
else
|
240
|
+
# Value is simply value in array:
|
241
|
+
value = @values[j]
|
167
242
|
end
|
168
|
-
|
169
|
-
|
170
|
-
|
243
|
+
element.value = value
|
244
|
+
elsif element.is_a?(Item)
|
245
|
+
# Possibly a binary data item:
|
246
|
+
element.bin = ""
|
171
247
|
end
|
172
|
-
# Update DICOM object with new value:
|
173
|
-
obj.set_value(value, pos, :create => false, :silent => true)
|
174
248
|
end
|
175
249
|
end
|
176
250
|
# Remove private tags?
|
@@ -215,11 +289,11 @@ module DICOM
|
|
215
289
|
puts "No files were found in specified folders. Aborting."
|
216
290
|
end
|
217
291
|
puts "*******************************************************"
|
218
|
-
end
|
219
|
-
|
292
|
+
end
|
220
293
|
|
221
|
-
# Prints a list of which tags are currently selected for anonymization along with
|
222
|
-
# replacement values that will be used and enumeration status.
|
294
|
+
# Prints to screen a list of which tags are currently selected for anonymization along with
|
295
|
+
# the replacement values that will be used and enumeration status.
|
296
|
+
#
|
223
297
|
def print
|
224
298
|
# Extract the string lengths which are needed to make the formatting nice:
|
225
299
|
names = Array.new
|
@@ -229,9 +303,9 @@ module DICOM
|
|
229
303
|
type_lengths = Array.new
|
230
304
|
value_lengths = Array.new
|
231
305
|
@tags.each_index do |i|
|
232
|
-
|
233
|
-
names <<
|
234
|
-
types <<
|
306
|
+
name, vr = LIBRARY.get_name_vr(@tags[i])
|
307
|
+
names << name
|
308
|
+
types << vr
|
235
309
|
tag_lengths[i] = @tags[i].length
|
236
310
|
name_lengths[i] = names[i].length
|
237
311
|
type_lengths[i] = types[i].length
|
@@ -272,8 +346,16 @@ module DICOM
|
|
272
346
|
end
|
273
347
|
end
|
274
348
|
|
275
|
-
|
276
|
-
#
|
349
|
+
# Removes a tag from the list of tags that will be anonymized.
|
350
|
+
#
|
351
|
+
# === Parameters
|
352
|
+
#
|
353
|
+
# * <tt>tag</tt> -- String. A data element tag.
|
354
|
+
#
|
355
|
+
# === Examples
|
356
|
+
#
|
357
|
+
# a.remove_tag("0010,0010")
|
358
|
+
#
|
277
359
|
def remove_tag(tag)
|
278
360
|
pos = @tags.index(tag)
|
279
361
|
if pos
|
@@ -290,9 +372,16 @@ module DICOM
|
|
290
372
|
private
|
291
373
|
|
292
374
|
|
293
|
-
# Finds the common path in
|
294
|
-
#
|
295
|
-
|
375
|
+
# Finds the common path (if any) in the instance file path array, by performing a recursive search
|
376
|
+
# on the folders that make up the path of one such file.
|
377
|
+
# Returns the index of the last folder in the path of the selected file that is common for all file paths.
|
378
|
+
#
|
379
|
+
# === Parameters
|
380
|
+
#
|
381
|
+
# * <tt>str_arr</tt> -- An array of folder strings from the path of a select file.
|
382
|
+
# * <tt>index</tt> -- Fixnum. The index of the folder in str_arr to check against all file paths.
|
383
|
+
#
|
384
|
+
def common_path(str_arr, index=0)
|
296
385
|
common_folders = Array.new
|
297
386
|
# Find out how much of the path is similar for all files in @files array:
|
298
387
|
folder = str_arr[index]
|
@@ -310,8 +399,8 @@ module DICOM
|
|
310
399
|
return result
|
311
400
|
end
|
312
401
|
|
313
|
-
|
314
|
-
#
|
402
|
+
# Creates a hash that is used for storing information that is used when enumeration is selected.
|
403
|
+
#
|
315
404
|
def create_enum_hash
|
316
405
|
@enum.each_index do |i|
|
317
406
|
@enum_old_hash[@tags[i]] = Array.new
|
@@ -319,8 +408,16 @@ module DICOM
|
|
319
408
|
end
|
320
409
|
end
|
321
410
|
|
322
|
-
|
323
|
-
#
|
411
|
+
# Handles the enumeration for the current data element tag.
|
412
|
+
# If its value has been encountered before, its corresponding enumerated value is retrieved,
|
413
|
+
# and if a new value is encountered, a new enumerated value is found by increasing an index by 1.
|
414
|
+
# Returns the value which will be used for the anonymization of this tag.
|
415
|
+
#
|
416
|
+
# === Parameters
|
417
|
+
#
|
418
|
+
# * <tt>current</tt> -- The original value of the tag that are about to be anonymized.
|
419
|
+
# * <tt>j</tt> -- Fixnum. The index of this tag in the tag-related instance arrays.
|
420
|
+
#
|
324
421
|
def get_enumeration_value(current, j)
|
325
422
|
# Is enumeration requested for this tag?
|
326
423
|
if @enum[j]
|
@@ -346,8 +443,9 @@ module DICOM
|
|
346
443
|
return value
|
347
444
|
end
|
348
445
|
|
349
|
-
|
350
|
-
#
|
446
|
+
# Discovers all the files contained in the specified directory (all its sub-directories),
|
447
|
+
# and adds these files to the instance file array.
|
448
|
+
#
|
351
449
|
def load_files
|
352
450
|
# Load find library:
|
353
451
|
require 'find'
|
@@ -371,16 +469,16 @@ module DICOM
|
|
371
469
|
end
|
372
470
|
end
|
373
471
|
|
374
|
-
|
375
|
-
#
|
376
|
-
#
|
472
|
+
# Analyzes the write_path and the 'read' file path to determine if they have some common root.
|
473
|
+
# If there are parts of the file path that exists also in the write path, the common parts will not be added to the write_path.
|
474
|
+
# The processed paths are put in a write_path instance array.
|
475
|
+
#
|
377
476
|
def process_write_paths
|
378
477
|
# First make sure @write_path ends with a file separator character:
|
379
478
|
last_character = @write_path[-1..-1]
|
380
479
|
@write_path = @write_path + File::SEPARATOR unless last_character == File::SEPARATOR
|
381
480
|
# Differing behaviour if we have one, or several files in our array:
|
382
481
|
if @files.length == 1
|
383
|
-
# One file.
|
384
482
|
# Write path is requested write path + old file name:
|
385
483
|
str_arr = @files[0].split(File::SEPARATOR)
|
386
484
|
@write_paths << @write_path + str_arr.last
|
@@ -389,7 +487,7 @@ module DICOM
|
|
389
487
|
# Find out how much of the path they have in common, remove that and
|
390
488
|
# add the remaining to the @write_path:
|
391
489
|
str_arr = @files[0].split(File::SEPARATOR)
|
392
|
-
last_match_index = common_path(str_arr
|
490
|
+
last_match_index = common_path(str_arr)
|
393
491
|
if last_match_index >= 0
|
394
492
|
# Remove the matching folders from the path that will be added to @write_path:
|
395
493
|
@files.each do |file|
|
@@ -406,8 +504,9 @@ module DICOM
|
|
406
504
|
end
|
407
505
|
end
|
408
506
|
|
409
|
-
|
410
|
-
#
|
507
|
+
# Sets up the default tags that will be anonymized, along with default replacement values and enumeration settings.
|
508
|
+
# The data is stored in 3 separate instance arrays for tags, values and enumeration.
|
509
|
+
#
|
411
510
|
def set_defaults
|
412
511
|
data = [
|
413
512
|
["0008,0012", "20000101", false], # Instance Creation Date
|
@@ -431,9 +530,9 @@ module DICOM
|
|
431
530
|
@enum = data[2]
|
432
531
|
end
|
433
532
|
|
434
|
-
|
435
533
|
# Writes an identity file, which allows reidentification of DICOM files that have been anonymized
|
436
|
-
# using the enumeration feature. Values
|
534
|
+
# using the enumeration feature. Values are saved in a text file, using semi colon delineation.
|
535
|
+
#
|
437
536
|
def write_identity_file
|
438
537
|
# Open file and prepare to write text:
|
439
538
|
File.open( @identity_file, 'w' ) do |output|
|
@@ -455,6 +554,5 @@ module DICOM
|
|
455
554
|
end
|
456
555
|
end
|
457
556
|
|
458
|
-
|
459
|
-
|
460
|
-
end # of module
|
557
|
+
end
|
558
|
+
end
|