dicom 0.7 → 0.8
Sign up to get free protection for your applications and to get access to all the features.
- 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
|