Repository: pydicom/pydicom

Issue:
Exception decompressing RLE encoded data with non-conformant padding
Getting Following error 
"Could not convert:  The amount of decoded RLE segment data doesn't match the expected amount (786433 vs. 786432 bytes)"
For following code
plt.imsave(os.path.join(output_folder,file)+'.png', convert_color_space(ds.pixel_array, ds[0x28,0x04].value, 'RGB'))
Also attaching DICOM file 
[US.1.2.156.112536.1.2127.130145051254127131.13912524190.144.txt](https://github.com/pydicom/pydicom/files/6799721/US.1.2.156.112536.1.2127.130145051254127131.13912524190.144.txt)

Please remove .txt extension to use DICOM file





Discussion:
It looks like the RLE segment has been padded out to 786433 bytes even though:

> Each RLE segment must be an even number of bytes or padded at its end with zero to make it even.

The solution would be to only raise an exception if the segment is shorter than expected and trim excess padding.

There's no simple workaround, but you should be able to do:
```python
from pydicom import dcmread
from pydicom.pixel_data_handlers import rle_handler
from pydicom.pixel_data_handlers.rle_handler import _parse_rle_header, _rle_decode_segment

def frame_decoder(data, rows, columns, nr_samples, nr_bits, segment_order = '>'):
    if nr_bits % 8:
        raise NotImplementedError(
            "Unable to decode RLE encoded pixel data with a (0028,0100) "
            f"'Bits Allocated' value of {nr_bits}"
        )

    offsets = _parse_rle_header(data[:64])
    nr_segments = len(offsets)

    bytes_per_sample = nr_bits // 8
    if nr_segments != nr_samples * bytes_per_sample:
        raise ValueError(
            "The number of RLE segments in the pixel data doesn't match the "
            f"expected amount ({nr_segments} vs. "
            f"{nr_samples * bytes_per_sample} segments)"
        )

    offsets.append(len(data))

    decoded = bytearray(rows * columns * nr_samples * bytes_per_sample)

    stride = bytes_per_sample * rows * columns
    for sample_number in range(nr_samples):
        le_gen = range(bytes_per_sample)
        byte_offsets = le_gen if segment_order == '<' else reversed(le_gen)
        for byte_offset in byte_offsets:
            ii = sample_number * bytes_per_sample + byte_offset
            segment = _rle_decode_segment(data[offsets[ii]:offsets[ii + 1]])
            if len(segment) < rows * columns:
                raise ValueError(
                    "The amount of decoded RLE segment data doesn't match the "
                    f"expected amount ({len(segment)} vs. "
                    f"{rows * columns} bytes)"
                )

            if segment_order == '>':
                byte_offset = bytes_per_sample - byte_offset - 1

            start = byte_offset + (sample_number * stride)
            decoded[start:start + stride:bytes_per_sample] = segment[:rows * columns]

    return decoded

rle_handler._rle_decode_frame = frame_decoder

ds = dcmread('path/to/file.dcm')
ds.decompress('rle')
arr = ds.pixel_array
```


Patch:
diff --git a/pydicom/pixel_data_handlers/rle_handler.py b/pydicom/pixel_data_handlers/rle_handler.py
--- a/pydicom/pixel_data_handlers/rle_handler.py
+++ b/pydicom/pixel_data_handlers/rle_handler.py
@@ -38,6 +38,7 @@
 from struct import unpack
 import sys
 from typing import List, TYPE_CHECKING, cast
+import warnings
 
 try:
     import numpy as np
@@ -332,13 +333,20 @@ def _rle_decode_frame(
             # ii is 1, 0, 3, 2, 5, 4 for the example above
             # This is where the segment order correction occurs
             segment = _rle_decode_segment(data[offsets[ii]:offsets[ii + 1]])
-            # Check that the number of decoded pixels is correct
-            if len(segment) != rows * columns:
+
+            # Check that the number of decoded bytes is correct
+            actual_length = len(segment)
+            if actual_length < rows * columns:
                 raise ValueError(
                     "The amount of decoded RLE segment data doesn't match the "
-                    f"expected amount ({len(segment)} vs. "
+                    f"expected amount ({actual_length} vs. "
                     f"{rows * columns} bytes)"
                 )
+            elif actual_length != rows * columns:
+                warnings.warn(
+                    "The decoded RLE segment contains non-conformant padding "
+                    f"- {actual_length} vs. {rows * columns} bytes expected"
+                )
 
             if segment_order == '>':
                 byte_offset = bytes_per_sample - byte_offset - 1
@@ -346,7 +354,9 @@ def _rle_decode_frame(
             # For 100 pixel/plane, 32-bit, 3 sample data, `start` will be
             #   0, 1, 2, 3, 400, 401, 402, 403, 800, 801, 802, 803
             start = byte_offset + (sample_number * stride)
-            decoded[start:start + stride:bytes_per_sample] = segment
+            decoded[start:start + stride:bytes_per_sample] = (
+                segment[:rows * columns]
+            )
 
     return decoded
 


Test patch:
diff --git a/pydicom/tests/test_rle_pixel_data.py b/pydicom/tests/test_rle_pixel_data.py
--- a/pydicom/tests/test_rle_pixel_data.py
+++ b/pydicom/tests/test_rle_pixel_data.py
@@ -881,11 +881,10 @@ def test_invalid_nr_segments_raises(self, header, samples, bits):
                 header, rows=1, columns=1, nr_samples=samples, nr_bits=bits
             )
 
-    def test_invalid_frame_data_raises(self):
-        """Test that invalid segment data raises exception."""
+    def test_invalid_segment_data_raises(self):
+        """Test invalid segment data raises exception"""
         ds = dcmread(RLE_16_1_1F)
         pixel_data = defragment_data(ds.PixelData)
-        # Missing byte
         msg = r"amount \(4095 vs. 4096 bytes\)"
         with pytest.raises(ValueError, match=msg):
             _rle_decode_frame(
@@ -896,13 +895,19 @@ def test_invalid_frame_data_raises(self):
                 ds.BitsAllocated
             )
 
-        # Extra byte
-        msg = r'amount \(4097 vs. 4096 bytes\)'
-        with pytest.raises(ValueError, match=msg):
-            _rle_decode_frame(
+    def test_nonconf_segment_padding_warns(self):
+        """Test non-conformant segment padding warns"""
+        ds = dcmread(RLE_16_1_1F)
+        pixel_data = defragment_data(ds.PixelData)
+        msg = (
+            r"The decoded RLE segment contains non-conformant padding - 4097 "
+            r"vs. 4096 bytes expected"
+        )
+        with pytest.warns(UserWarning, match=msg):
+            frame = _rle_decode_frame(
                 pixel_data + b'\x00\x01',
-                ds.Rows,
-                ds.Columns,
+                4096,
+                1,
                 ds.SamplesPerPixel,
                 ds.BitsAllocated
             )