dicom 0.9.3 → 0.9.4

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.
@@ -1,12 +1,14 @@
1
1
  module DICOM
2
+
3
+ # This module is the general interface between the ImageItem class and the
4
+ # image methods found in the specific image processor modules.
5
+ #
2
6
  module ImageProcessor
3
7
 
4
8
  # Creates image objects from one or more compressed, binary string blobs.
5
- # Returns an array of images. If decompression fails, returns false.
6
- #
7
- # === Parameters
8
9
  #
9
- # * <tt>blobs</tt> -- Binary string blob(s) containing compressed pixel data.
10
+ # @param [Array<String>, String] blobs binary string blob(s) containing compressed pixel data
11
+ # @return [Array<MagickImage>, FalseClass] - an array of images, or false (if decompression failed)
10
12
  #
11
13
  def decompress(blobs)
12
14
  raise ArgumentError, "Expected Array or String, got #{blobs.class}." unless [String, Array].include?(blobs.class)
@@ -20,9 +22,9 @@ module DICOM
20
22
 
21
23
  # Extracts an array of pixels (integers) from an image object.
22
24
  #
23
- # === Parameters
24
- #
25
- # * <tt>image</tt> -- An Rmagick image object.
25
+ # @param [MagickImage] image a Magick image object
26
+ # @param [String] photometry a code describing the photometry of the pixel data (e.g. 'MONOCHROME1' or 'COLOR')
27
+ # @return [Array<Integer>] an array of pixel values
26
28
  #
27
29
  def export_pixels(image, photometry)
28
30
  raise ArgumentError, "Expected String, got #{photometry.class}." unless photometry.is_a?(String)
@@ -31,20 +33,21 @@ module DICOM
31
33
 
32
34
  # Creates an image object from a binary string blob.
33
35
  #
34
- # === Parameters
35
- #
36
- # * <tt>blob</tt> -- Binary string blob containing raw pixel data.
37
- # * <tt>columns</tt> -- Number of columns.
38
- # * <tt>rows</tt> -- Number of rows.
39
- # * <tt>depth</tt> -- Bit depth of the encoded pixel data.
40
- # * <tt>photometry</tt> -- String describing the DICOM photometry of the pixel data. Example: 'MONOCHROME1', 'RGB'.
36
+ # @param [String] blob binary string blob containing pixel data
37
+ # @param [Integer] columns the number of columns
38
+ # @param [Integer] rows the number of rows
39
+ # @param [Integer] depth the bit depth of the encoded pixel data
40
+ # @param [String] photometry a code describing the photometry of the pixel data (e.g. 'MONOCHROME1' or 'COLOR')
41
+ # @return [MagickImage] a Magick image object
41
42
  #
42
43
  def import_pixels(blob, columns, rows, depth, photometry)
43
44
  raise ArgumentError, "Expected String, got #{blob.class}." unless blob.is_a?(String)
44
45
  image_module.import_pixels(blob, columns, rows, depth, photometry)
45
46
  end
46
47
 
47
- # Returns an array containing the image objects that are supported by the image processor.
48
+ # Gives an array containing the image objects that are supported by the image processor.
49
+ #
50
+ # @return [Array] the valid image classes
48
51
  #
49
52
  def valid_image_objects
50
53
  return [Magick::Image, MiniMagick::Image]
@@ -54,6 +57,12 @@ module DICOM
54
57
  private
55
58
 
56
59
 
60
+ # Gives the specific image processor module corresponding to the specified
61
+ # image_processor module option.
62
+ #
63
+ # @raise [RuntimeError] if an unknown image processor is specified
64
+ # @return [DcmMiniMagick, DcmRMagick] the image processor module to be used
65
+ #
57
66
  def image_module
58
67
  case DICOM.image_processor
59
68
  when :mini_magick
@@ -1,15 +1,16 @@
1
1
  module DICOM
2
2
  module ImageProcessor
3
+
4
+ # This module contains methods for interacting with pixel data using the mini_magick gem.
5
+ #
3
6
  module DcmMiniMagick
4
7
 
5
8
  class << self
6
9
 
7
10
  # Creates image objects from an array of compressed, binary string blobs.
8
- # Returns an array of images. If decompression fails, returns false.
9
- #
10
- # === Parameters
11
11
  #
12
- # * <tt>blobs</tt> -- An array of binary string blobs containing compressed pixel data.
12
+ # @param [Array<String>] blobs an array of binary string blobs containing compressed pixel data
13
+ # @return [Array<MiniMagick::Image>, FalseClass] - an array of images, or false (if decompression failed)
13
14
  #
14
15
  def decompress(blobs)
15
16
  images = Array.new
@@ -22,39 +23,36 @@ module DICOM
22
23
 
23
24
  # Extracts an array of pixels (integers) from an image object.
24
25
  #
25
- # === Notes
26
- #
27
- # * This feature is not available as of yet in the mini_magick image processor. If this feature is needed, please try another image processor (RMagick).
26
+ # @note This feature is not available as of yet in the mini_magick image processor.
27
+ # If this feature is needed, please try another image processor (RMagick).
28
28
  #
29
- # === Parameters
30
- #
31
- # * <tt>image</tt> -- An MiniMagick image object.
29
+ # @param [MiniMagick::Image] image a mini_magick image object
30
+ # @param [String] photometry a code describing the photometry of the pixel data (e.g. 'MONOCHROME1' or 'COLOR')
31
+ # @return [Array<Integer>] an array of pixel values
32
32
  #
33
33
  def export_pixels(image, photometry)
34
34
  raise ArgumentError, "Expected MiniMagick::Image, got #{image.class}." unless image.is_a?(MiniMagick::Image)
35
35
  raise "Exporting pixels is not yet available with the mini_magick processor. Please try another image processor (RMagick)."
36
36
  end
37
37
 
38
- # Creates an image object from a binary string blob which contains raw pixel data.
39
- #
40
- # === Parameters
38
+ # Creates an image object from a binary string blob.
41
39
  #
42
- # * <tt>blob</tt> -- Binary string blob containing raw pixel data.
43
- # * <tt>columns</tt> -- Number of columns.
44
- # * <tt>rows</tt> -- Number of rows.
45
- # * <tt>depth</tt> -- Bit depth of the encoded pixel data.
46
- # * <tt>photometry</tt> -- String describing the DICOM photometry of the pixel data.
47
- # * <tt>format</tt> -- String describing the image format to be used when creating the image object. Defaults to 'png'.
40
+ # @param [String] blob binary string blob containing pixel data
41
+ # @param [Integer] columns the number of columns
42
+ # @param [Integer] rows the number of rows
43
+ # @param [Integer] depth the bit depth of the encoded pixel data
44
+ # @param [String] photometry a code describing the photometry of the pixel data (e.g. 'MONOCHROME1' or 'COLOR')
45
+ # @param [String] format the image format to use
46
+ # @return [Magick::Image] a mini_magick image object
48
47
  #
49
48
  def import_pixels(blob, columns, rows, depth, photometry, format="png")
50
49
  image = MiniMagick::Image.import_pixels(blob, columns, rows, depth, im_map(photometry), format)
51
50
  end
52
51
 
53
- # Returns an ImageMagick pixel map string based on the input DICOM photometry string.
54
- #
55
- # === Parameters
52
+ # Converts a given DICOM photometry string to a mini_magick pixel map string.
56
53
  #
57
- # * <tt>photometry</tt> -- String describing the photometry of the pixel data. Example: 'MONOCHROME1' or 'COLOR'.
54
+ # @param [String] photometry a code describing the photometry of the pixel data (e.g. 'MONOCHROME1' or 'COLOR')
55
+ # @return [String] a mini_magick pixel map string
58
56
  #
59
57
  def im_map(photometry)
60
58
  raise ArgumentError, "Expected String, got #{photometry.class}." unless photometry.is_a?(String)
@@ -1,35 +1,38 @@
1
1
  module DICOM
2
2
  module ImageProcessor
3
+
4
+ # This module contains methods for interacting with pixel data using the RMagick gem.
5
+ #
3
6
  module DcmRMagick
4
7
 
5
8
  class << self
6
9
 
7
10
  # Creates image objects from an array of compressed, binary string blobs.
8
- # Returns an array of images. If decompression fails, returns false.
9
11
  #
10
- # === Notes
12
+ # === Note
11
13
  #
12
- # The method tries to use RMagick of unpacking, but it seems that ImageMagick is not able to handle most of the
13
- # compressed image variants used in the DICOM standard. To get a more robust implementation which is able to handle
14
- # most types of compressed DICOM files, something else is needed.
14
+ # The method tries to use RMagick for unpacking, but unortunately, it seems that
15
+ # ImageMagick is not able to handle most of the compressed image variants used in the DICOM
16
+ # standard. To get a more robust implementation which is able to handle most types of
17
+ # compressed DICOM files, something else is needed.
15
18
  #
16
- # Probably a good candidate to use is the PVRG-JPEG library, which seems to be able to handle everything that is jpeg.
17
- # It exists in the Ubuntu repositories, where it can be installed and run through terminal. For source code, and some
18
- # additional information, check this link: http://www.panix.com/~eli/jpeg/
19
+ # Probably a good candidate to use is the PVRG-JPEG library, which seems to be able to handle
20
+ # everything that is jpeg. It exists in the Ubuntu repositories, where it can be installed and
21
+ # run through terminal. For source code, and some additional information, check out this link:
22
+ # http://www.panix.com/~eli/jpeg/
19
23
  #
20
24
  # Another idea would be to study how other open source libraries, like GDCM handle these files.
21
25
  #
22
- # === Parameters
23
- #
24
- # * <tt>blobs</tt> -- An array of binary string blobs containing compressed pixel data.
25
- #
26
- #--
27
- # The following transfer syntaxes have been verified as failing with ImageMagick:
28
- # TXS_JPEG_LOSSLESS_NH is not supported by (my) ImageMagick version: "Unsupported JPEG process: SOF type 0xc3"
29
- # TXS_JPEG_LOSSLESS_NH_FOP is not supported by (my) ImageMagick version: "Unsupported JPEG process: SOF type 0xc3"
30
- # TXS_JPEG_2000_PART1_LOSSLESS is not supported by (my) ImageMagick version: "jpc_dec_decodepkts failed"
26
+ # @param [Array<String>] blobs an array of binary string blobs containing compressed pixel data
27
+ # @return [Array<Magick::Image>, FalseClass] - an array of images, or false (if decompression failed)
31
28
  #
32
29
  def decompress(blobs)
30
+ # FIXME:
31
+ # The following transfer syntaxes have been verified as failing with ImageMagick:
32
+ # TXS_JPEG_LOSSLESS_NH is not supported by (my) ImageMagick version: "Unsupported JPEG process: SOF type 0xc3"
33
+ # TXS_JPEG_LOSSLESS_NH_FOP is not supported by (my) ImageMagick version: "Unsupported JPEG process: SOF type 0xc3"
34
+ # TXS_JPEG_2000_PART1_LOSSLESS is not supported by (my) ImageMagick version: "jpc_dec_decodepkts failed"
35
+ #
33
36
  images = Array.new
34
37
  # We attempt to decompress the pixels using ImageMagick:
35
38
  blobs.each do |string|
@@ -40,9 +43,9 @@ module DICOM
40
43
 
41
44
  # Extracts an array of pixels (integers) from an image object.
42
45
  #
43
- # === Parameters
44
- #
45
- # * <tt>image</tt> -- An Rmagick image object.
46
+ # @param [Magick::Image] image an RMagick image object
47
+ # @param [String] photometry a code describing the photometry of the pixel data (e.g. 'MONOCHROME1' or 'COLOR')
48
+ # @return [Array<Integer>] an array of pixel values
46
49
  #
47
50
  def export_pixels(image, photometry)
48
51
  raise ArgumentError, "Expected Magick::Image, got #{image.class}." unless image.is_a?(Magick::Image)
@@ -50,22 +53,25 @@ module DICOM
50
53
  return pixels
51
54
  end
52
55
 
53
- # Creates an image object from a binary string blob which contains raw pixel data.
56
+ # Creates an image object from a binary string blob.
54
57
  #
55
- # === Parameters
56
- #
57
- # * <tt>blob</tt> -- Binary string blob containing raw pixel data.
58
- # * <tt>columns</tt> -- Number of columns.
59
- # * <tt>rows</tt> -- Number of rows.
60
- # * <tt>depth</tt> -- Bit depth of the encoded pixel data.
61
- # * <tt>photometry</tt> -- String describing the DICOM photometry of the pixel data.
62
- # * <tt>format</tt> -- String describing the image format to be used when creating the image object. Defaults to 'png'.
58
+ # @param [String] blob binary string blob containing pixel data
59
+ # @param [Integer] columns the number of columns
60
+ # @param [Integer] rows the number of rows
61
+ # @param [Integer] depth the bit depth of the encoded pixel data
62
+ # @param [String] photometry a code describing the photometry of the pixel data (e.g. 'MONOCHROME1' or 'COLOR')
63
+ # @param [String] format the image format to use
64
+ # @return [Magick::Image] an RMagick image object
63
65
  #
64
66
  def import_pixels(blob, columns, rows, depth, photometry, format="png")
65
67
  image = Magick::Image.new(columns,rows).import_pixels(0, 0, columns, rows, rm_map(photometry), blob, rm_data_type(depth))
66
68
  end
67
69
 
68
- # Returns the RMagick StorageType pixel value corresponding to the given bit length.
70
+ # Converts a given bit depth to an RMagick StorageType.
71
+ #
72
+ # @raise [ArgumentError] if given an unsupported bit depth
73
+ # @param [Integer] bit_depth the bit depth of the pixel data
74
+ # @return [Magick::CharPixel, Magick::ShortPixel] the proper storage type
69
75
  #
70
76
  def rm_data_type(bit_depth)
71
77
  return case bit_depth
@@ -78,11 +84,10 @@ module DICOM
78
84
  end
79
85
  end
80
86
 
81
- # Returns an RMagick pixel map string based on the input DICOM photometry string.
82
- #
83
- # === Parameters
87
+ # Converts a given DICOM photometry string to an RMagick pixel map string.
84
88
  #
85
- # * <tt>photometry</tt> -- String describing the photometry of the pixel data. Example: 'MONOCHROME1' or 'COLOR'.
89
+ # @param [String] photometry a code describing the photometry of the pixel data (e.g. 'MONOCHROME1' or 'COLOR')
90
+ # @return [String] an RMagick pixel map string
86
91
  #
87
92
  def rm_map(photometry)
88
93
  raise ArgumentError, "Expected String, got #{photometry.class}." unless photometry.is_a?(String)
@@ -1,121 +1,134 @@
1
- module DICOM
2
-
3
- # The Item class handles information related to items - the elements contained in sequences.
4
- #
5
- # === Inheritance
6
- #
7
- # As the Item class inherits from the ImageItem class, which itself inherits from the Parent class,
8
- # all ImageItem and Parent methods are also available to instances of Item.
9
- #
10
- class Item < ImageItem
11
-
12
- # Include the Elemental mix-in module:
13
- include Elemental
14
-
15
- # The index of this Item in the group of items belonging to its parent. If the Item is without parent, index is nil.
16
- attr_accessor :index
17
-
18
- # Creates an Item instance.
19
- #
20
- # === Notes
21
- #
22
- # Normally, an Item contains data elements and/or sequences. However, in some cases, an Item will instead/also
23
- # carry binary string data, like the pixel data of an encapsulated image fragment.
24
- #
25
- # === Parameters
26
- #
27
- # * <tt>options</tt> -- A hash of parameters.
28
- #
29
- # === Options
30
- #
31
- # * <tt>:bin</tt> -- A binary string to be carried by the Item.
32
- # * <tt>:index</tt> -- Fixnum. If the Item is to be inserted at a specific index (Item number), this option parameter needs to set.
33
- # * <tt>:length</tt> -- Fixnum. The Item length (which either refers to the length of the encoded string of children of this Item, or the length of its binary data).
34
- # * <tt>:name</tt> - String. The name of the Item may be specified upon creation. If it is not, a default name is chosen.
35
- # * <tt>:parent</tt> - Sequence or DObject instance which the Item instance shall belong to.
36
- # * <tt>:vr</tt> -- String. The value representation of the Item may be specified upon creation. If it is not, a default vr is chosen.
37
- #
38
- # === Examples
39
- #
40
- # # Create an empty Item and connect it to the "Structure Set ROI Sequence":
41
- # item = Item.new(:parent => dcm["3006,0020"])
42
- # # Create a "Pixel Data Item" which carries an encapsulated image frame (a pre-encoded binary):
43
- # pixel_item = Item.new(:bin => processed_pixel_data, :parent => dcm["7FE0,0010"][1])
44
- #
45
- def initialize(options={})
46
- # Set common parent variables:
47
- initialize_parent
48
- # Set instance variables:
49
- @tag = ITEM_TAG
50
- @value = nil
51
- @name = options[:name] || "Item"
52
- @vr = options[:vr] || ITEM_VR
53
- if options[:bin]
54
- self.bin = options[:bin]
55
- else
56
- @length = options[:length] || -1
57
- end
58
- if options[:parent]
59
- @parent = options[:parent]
60
- @index = options[:index] if options[:index]
61
- @parent.add_item(self, :index => options[:index], :no_follow => true)
62
- end
63
- end
64
-
65
- # Returns true if the argument is an instance with attributes equal to self.
66
- #
67
- def ==(other)
68
- if other.respond_to?(:to_item)
69
- other.send(:state) == state
70
- end
71
- end
72
-
73
- alias_method :eql?, :==
74
-
75
- # Sets the binary string that the Item will contain.
76
- #
77
- # === Parameters
78
- #
79
- # * <tt>new_bin</tt> -- A binary string of encoded data.
80
- #
81
- # === Examples
82
- #
83
- # # Insert a custom jpeg in the (encapsulated) pixel data element, in it's first pixel data item:
84
- # dcm["7FE0,0010"][1].children.first.bin = jpeg_binary_string
85
- #
86
- def bin=(new_bin)
87
- raise ArgumentError, "Invalid parameter type. String was expected, got #{new_bin.class}." unless new_bin.is_a?(String)
88
- # Add an empty byte at the end if the length of the binary is odd:
89
- if new_bin.length.odd?
90
- @bin = new_bin + "\x00"
91
- else
92
- @bin = new_bin
93
- end
94
- @value = nil
95
- @length = @bin.length
96
- end
97
-
98
- # Generates a Fixnum hash value for this instance.
99
- #
100
- def hash
101
- state.hash
102
- end
103
-
104
- # Returns self.
105
- #
106
- def to_item
107
- self
108
- end
109
-
110
-
111
- private
112
-
113
-
114
- # Returns the attributes of this instance in an array (for comparison purposes).
115
- #
116
- def state
117
- [@vr, @name, @tags]
118
- end
119
-
120
- end
1
+ module DICOM
2
+
3
+ # The Item class handles information related to items - the elements contained in sequences.
4
+ #
5
+ # === Inheritance
6
+ #
7
+ # As the Item class inherits from the ImageItem class, which itself inherits from the Parent class,
8
+ # all ImageItem and Parent methods are also available to instances of Item.
9
+ #
10
+ class Item < ImageItem
11
+
12
+ # Include the Elemental mix-in module:
13
+ include Elemental
14
+
15
+ # The index of this Item in the group of items belonging to its parent. If the Item is without parent, index is nil.
16
+ attr_accessor :index
17
+
18
+ # Creates an Item instance.
19
+ #
20
+ # Normally, an Item contains data elements and/or sequences. However,
21
+ # in some cases, an Item will instead/also carry binary string data,
22
+ # like the pixel data of an encapsulated image fragment.
23
+ #
24
+ # @param [Hash] options the options to use for creating the item
25
+ # @option options [String] :bin a binary string to be carried by the item
26
+ # @option options [String] :indexif the item is to be inserted at a specific index (Item number), this option parameter needs to set
27
+ # @option options [String] :length theiItem length (which either refers to the length of the encoded string of children of this item, or the length of its binary data)
28
+ # @option options [String] :name the name of the item may be specified upon creation (if not, a default name is used)
29
+ # @option options [String] :parent a Sequence or DObject instance which the item instance shall belong to
30
+ # @option options [String] :vr the value representation of the item may be specified upon creation (if not, a default vr is used)
31
+ #
32
+ # @example Create an empty Item and connect it to the "Structure Set ROI Sequence"
33
+ # item = Item.new(:parent => dcm["3006,0020"])
34
+ # @example Create a "Pixel Data Item" which carries an encapsulated image frame (a pre-encoded binary)
35
+ # pixel_item = Item.new(:bin => processed_pixel_data, :parent => dcm["7FE0,0010"][1])
36
+ #
37
+ def initialize(options={})
38
+ # Set common parent variables:
39
+ initialize_parent
40
+ # Set instance variables:
41
+ @tag = ITEM_TAG
42
+ @value = nil
43
+ @name = options[:name] || "Item"
44
+ @vr = options[:vr] || ITEM_VR
45
+ if options[:bin]
46
+ self.bin = options[:bin]
47
+ else
48
+ @length = options[:length] || -1
49
+ end
50
+ if options[:parent]
51
+ @parent = options[:parent]
52
+ @index = options[:index] if options[:index]
53
+ @parent.add_item(self, :index => options[:index], :no_follow => true)
54
+ end
55
+ end
56
+
57
+ # Checks for equality.
58
+ #
59
+ # Other and self are considered equivalent if they are
60
+ # of compatible types and their attributes are equivalent.
61
+ #
62
+ # @param other an object to be compared with self.
63
+ # @return [Boolean] true if self and other are considered equivalent
64
+ #
65
+ def ==(other)
66
+ if other.respond_to?(:to_item)
67
+ other.send(:state) == state
68
+ end
69
+ end
70
+
71
+ alias_method :eql?, :==
72
+
73
+ # Sets the binary string that the Item will contain.
74
+ #
75
+ # @param [String] new_bin a binary string of encoded data
76
+ # @example Insert a custom jpeg in the (encapsulated) pixel data element (in it's first pixel data item)
77
+ # dcm['7FE0,0010'][1].children.first.bin = jpeg_binary_string
78
+ #
79
+ def bin=(new_bin)
80
+ raise ArgumentError, "Invalid parameter type. String was expected, got #{new_bin.class}." unless new_bin.is_a?(String)
81
+ # Add an empty byte at the end if the length of the binary is odd:
82
+ if new_bin.length.odd?
83
+ @bin = new_bin + "\x00"
84
+ else
85
+ @bin = new_bin
86
+ end
87
+ @value = nil
88
+ @length = @bin.length
89
+ end
90
+
91
+ # Computes a hash code for this object.
92
+ #
93
+ # @note Two objects with the same attributes will have the same hash code.
94
+ #
95
+ # @return [Fixnum] the object's hash code
96
+ #
97
+ def hash
98
+ state.hash
99
+ end
100
+
101
+ # Loads data from an encoded DICOM string and creates
102
+ # sequences and elements which are linked to this instance.
103
+ #
104
+ # @param [String] bin an encoded binary string containing DICOM information
105
+ # @param [String] syntax the transfer syntax to use when decoding the DICOM string
106
+ #
107
+ def parse(bin, syntax)
108
+ raise ArgumentError, "Invalid argument 'bin'. Expected String, got #{bin.class}." unless bin.is_a?(String)
109
+ raise ArgumentError, "Invalid argument 'syntax'. Expected String, got #{syntax.class}." unless syntax.is_a?(String)
110
+ read(bin, signature=false, :syntax => syntax)
111
+ end
112
+
113
+ # Returns self.
114
+ #
115
+ # @return [Item] self
116
+ #
117
+ def to_item
118
+ self
119
+ end
120
+
121
+
122
+ private
123
+
124
+
125
+ # Collects the attributes of this instance.
126
+ #
127
+ # @return [Array<String, Sequence, Element>] an array of attributes
128
+ #
129
+ def state
130
+ [@vr, @name, @tags]
131
+ end
132
+
133
+ end
121
134
  end