# Buggy code
def get_pixeldata(dicom_dataset):
    """Use the GDCM package to decode *Pixel Data*.

    Returns
    -------
    numpy.ndarray
        A correctly sized (but not shaped) array of the entire data volume

    Raises
    ------
    ImportError
        If the required packages are not available.
    TypeError
        If the image could not be read by GDCM or if the *Pixel Data* type is
        unsupported.
    AttributeError
        If the decoded amount of data does not match the expected amount.
    """

    if not HAVE_GDCM:
        msg = (
            "GDCM requires both the gdcm package and numpy "
            "and one or more could not be imported"
        )
        raise ImportError(msg)

    if HAVE_GDCM_IN_MEMORY_SUPPORT:
        gdcm_data_element = create_data_element(dicom_dataset)
        gdcm_image = create_image(dicom_dataset, gdcm_data_element)
    else:
        gdcm_image_reader = create_image_reader(dicom_dataset.filename)
        if not gdcm_image_reader.Read():
            raise TypeError("GDCM could not read DICOM image")
        gdcm_image = gdcm_image_reader.GetImage()

    # GDCM returns char* as type str. Python 3 decodes this to
    # unicode strings by default.
    # The SWIG docs mention that they always decode byte streams
    # as utf-8 strings for Python 3, with the `surrogateescape`
    # error handler configured.
    # Therefore, we can encode them back to their original bytearray
    # representation on Python 3 by using the same parameters.

    pixel_bytearray = gdcm_image.GetBuffer().encode("utf-8", "surrogateescape")

    # Here we need to be careful because in some cases, GDCM reads a
    # buffer that is too large, so we need to make sure we only include
    # the first n_rows * n_columns * dtype_size bytes.
    expected_length_bytes = get_expected_length(dicom_dataset)
    if dicom_dataset.PhotometricInterpretation == "YBR_FULL_422":
        # GDCM has already resampled the pixel data, see PS3.3 C.7.6.3.1.2
        expected_length_bytes = expected_length_bytes // 2 * 3

    if len(pixel_bytearray) > expected_length_bytes:
        # We make sure that all the bytes after are in fact zeros
        padding = pixel_bytearray[expected_length_bytes:]
        if numpy.any(numpy.frombuffer(padding, numpy.byte)):
            pixel_bytearray = pixel_bytearray[:expected_length_bytes]
        else:
            # We revert to the old behavior which should then result
            #   in a Numpy error later on.
            pass

    numpy_dtype = pixel_dtype(dicom_dataset)
    pixel_array = numpy.frombuffer(pixel_bytearray, dtype=numpy_dtype)

    expected_length_pixels = get_expected_length(dicom_dataset, "pixels")
    if pixel_array.size != expected_length_pixels:
        raise AttributeError(
            "Amount of pixel data %d does "
            "not match the expected data %d"
            % (pixel_array.size, expected_length_pixels)
        )

    if should_change_PhotometricInterpretation_to_RGB(dicom_dataset):
        dicom_dataset.PhotometricInterpretation = "RGB"

    return pixel_array.copy()


# Traceback (TypeError)
import gdcm
gdcm.Version_GetVersion()
'2.8.4'
from pydicom import __version__
__version__
'2.1.0.dev0'
from pydicom import dcmread
from pydicom.data import get_testdata_file
from io import BytesIO
with open(get_testdata_file("JPEG2000.dcm", 'rb') as f:
...     bs = BytesIO(f.read())
...
ds = dcmread(bs)
arr = ds.pixel_array
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File ".../pydicom/dataset.py", line 1613, in pixel_array
self.convert_pixel_data()
File ".../pydicom/dataset.py", line 1322, in convert_pixel_data
self._convert_pixel_data_without_handler()
File ".../pydicom/dataset.py", line 1432, in _convert_pixel_data_without_handler
raise last_exception
File ".../pydicom/dataset.py", line 1412, in _convert_pixel_data_without_handler
self._do_pixel_data_conversion(handler)
File ".../pydicom/dataset.py", line 1439, in _do_pixel_data_conversion
arr = handler.get_pixeldata(self)
File ".../pydicom/pixel_data_handlers/gdcm_handler.py", line 209, in get_pixeldata
gdcm_image_reader = create_image_reader(dicom_dataset.filename)
File ".../pydicom/pixel_data_handlers/gdcm_handler.py", line 177, in create_image_reader
image_reader.SetFileName(filename)
File ".../python3.6/site-packages/gdcmswig.py", line 7959, in SetFileName
return _gdcmswig.Reader_SetFileName(self, filename_native)
TypeError: in method 'Reader_SetFileName', argument 2 of type 'char const *'

# Fixed code
def get_pixeldata(dicom_dataset):
    """Use the GDCM package to decode *Pixel Data*.

    Returns
    -------
    numpy.ndarray
        A correctly sized (but not shaped) array of the entire data volume

    Raises
    ------
    ImportError
        If the required packages are not available.
    TypeError
        If the image could not be read by GDCM or if the *Pixel Data* type is
        unsupported.
    AttributeError
        If the decoded amount of data does not match the expected amount.
    """

    if not HAVE_GDCM:
        msg = (
            "GDCM requires both the gdcm package and numpy "
            "and one or more could not be imported"
        )
        raise ImportError(msg)

    if HAVE_GDCM_IN_MEMORY_SUPPORT:
        gdcm_data_element = create_data_element(dicom_dataset)
        gdcm_image = create_image(dicom_dataset, gdcm_data_element)
    else:
        gdcm_image_reader = create_image_reader(dicom_dataset)
        if not gdcm_image_reader.Read():
            raise TypeError("GDCM could not read DICOM image")
        gdcm_image = gdcm_image_reader.GetImage()

    # GDCM returns char* as type str. Python 3 decodes this to
    # unicode strings by default.
    # The SWIG docs mention that they always decode byte streams
    # as utf-8 strings for Python 3, with the `surrogateescape`
    # error handler configured.
    # Therefore, we can encode them back to their original bytearray
    # representation on Python 3 by using the same parameters.

    pixel_bytearray = gdcm_image.GetBuffer().encode("utf-8", "surrogateescape")

    # Here we need to be careful because in some cases, GDCM reads a
    # buffer that is too large, so we need to make sure we only include
    # the first n_rows * n_columns * dtype_size bytes.
    expected_length_bytes = get_expected_length(dicom_dataset)
    if dicom_dataset.PhotometricInterpretation == "YBR_FULL_422":
        # GDCM has already resampled the pixel data, see PS3.3 C.7.6.3.1.2
        expected_length_bytes = expected_length_bytes // 2 * 3

    if len(pixel_bytearray) > expected_length_bytes:
        # We make sure that all the bytes after are in fact zeros
        padding = pixel_bytearray[expected_length_bytes:]
        if numpy.any(numpy.frombuffer(padding, numpy.byte)):
            pixel_bytearray = pixel_bytearray[:expected_length_bytes]
        else:
            # We revert to the old behavior which should then result
            #   in a Numpy error later on.
            pass

    numpy_dtype = pixel_dtype(dicom_dataset)
    pixel_array = numpy.frombuffer(pixel_bytearray, dtype=numpy_dtype)

    expected_length_pixels = get_expected_length(dicom_dataset, "pixels")
    if pixel_array.size != expected_length_pixels:
        raise AttributeError(
            "Amount of pixel data %d does "
            "not match the expected data %d"
            % (pixel_array.size, expected_length_pixels)
        )

    if should_change_PhotometricInterpretation_to_RGB(dicom_dataset):
        dicom_dataset.PhotometricInterpretation = "RGB"

    return pixel_array.copy()