Repository: pydicom/pylibjpeg-openjpeg (language: python)

Issue:
`encode` lossless documentation correction
From `encode` documentation it seems that these calls should give the same result:

```
import numpy as np
from pydicom import dcmread
from openjpeg import encode, decode

dcm = dcmread("chest.dcm") 

with open('test_jpeg_1.j2k', 'wb') as f:
    f.write(encode(dcm.pixel_array))

with open('test_jpeg_2.j2k', 'wb') as f:
    f.write(encode(dcm.pixel_array, compression_ratios=[1]))

with open('test_jpeg_1.j2k', 'rb') as f:
    im_1 = decode(f.read())

with open('test_jpeg_2.j2k', 'rb') as f:
    im_2 = decode(f.read())

np.allclose(im_1, im_2)
# False
```

But they are not (the diff is small, but still). From function documentation:

"""
compression_ratios : list[float], optional. Required if using lossy encoding, this is the compression ratio to use for each layer. Should be in decreasing order (such as ``[80, 30, 10]``) and the final value may be **``1`` to indicate lossless encoding** should be used for that layer. Cannot be used with `signal_noise_ratios`.
"""

True lossless is achieved with `encode(dcm.pixel_array)` and `encode(dcm.pixel_array, compression_ratios=[1])` results in a small residual.

*attached example CT dicom (single channel, grayscale, int16) from public data (just changed the extension to `.txt`, since github does not allow for `.dcm`), but you probably can reproduce with any other dicom.

[chest.txt](https://github.com/pydicom/pylibjpeg-openjpeg/files/14138326/chest.txt)



Discussion / hints:
Using `compression_ratios` (or `signal_noise_ratios`) signals that you want lossy compression with DWT 9-7. Would you prefer to have `compression_ratios=[1]` signal lossless mode? Or just a docstring update to make it a bit clearer?

I feel like this only requires a documentation edit, since right now it is confusing. I.e. instead of "the final value may be 1 to indicate lossless encoding" use something like "`compression_ratios=[1]` does not correspond to lossless encoding" since it does not, and documentation says it does.

Fix patch:
diff --git a/README.md b/README.md
index 5680ba0..83af561 100644
--- a/README.md
+++ b/README.md
@@ -49,7 +49,6 @@ Encoding of NumPy ndarrays is supported for the following:
 * Number of rows/columns: up to 65535
 * Number of planes: 1, 3 or 4
 
-
 ### Transfer Syntaxes
 | UID | Description |
 | --- | --- |
@@ -95,10 +94,10 @@ Lossless encoding of RGB with multiple-component transformation:
 ```python
 
 import numpy as np
-from openjpeg import encode
+from openjpeg import encode_array
 
-arr = np.random.randint(low=0, high=65535, size=(100, 100, 3), dtype="uint8")
-encode(arr, photometric_interpretation=1)  # 1: sRGB
+arr = np.random.randint(low=0, high=65536, size=(100, 100, 3), dtype="uint8")
+encode_array(arr, photometric_interpretation=1)  # 1: sRGB
 ```
 
 Lossy encoding of a monochrome image using compression ratios:
@@ -106,12 +105,12 @@ Lossy encoding of a monochrome image using compression ratios:
 ```python
 
 import numpy as np
-from openjpeg import encode
+from openjpeg import encode_array
 
-arr = np.random.randint(low=-2**15, high=2**15 - 1, size=(100, 100), dtype="int8")
+arr = np.random.randint(low=-2**15, high=2**15, size=(100, 100), dtype="int8")
 # You must determine your own values for `compression_ratios`
 #   as these are for illustration purposes only
-encode(arr, compression_ratios=[2, 4, 6])
+encode_array(arr, compression_ratios=[5, 2])
 ```
 
 Lossy encoding of a monochrome image using peak signal-to-noise ratios:
@@ -119,14 +118,14 @@ Lossy encoding of a monochrome image using peak signal-to-noise ratios:
 ```python
 
 import numpy as np
-from openjpeg import encode
+from openjpeg import encode_array
 
-arr = np.random.randint(low=-2**15, high=2**15 - 1, size=(100, 100), dtype="int8")
+arr = np.random.randint(low=-2**15, high=2**15, size=(100, 100), dtype="int8")
 # You must determine your own values for `signal_noise_ratios`
 #   as these are for illustration purposes only
-encode(arr, signal_noise_ratios=[50, 80, 100])
+encode_array(arr, signal_noise_ratios=[50, 80, 100])
 ```
 
-See the docstring for the [encode() function][2] for full details.
+See the docstring for the [encode_array() function][2] for full details.
 
-[2]: https://github.com/pydicom/pylibjpeg-openjpeg/blob/main/openjpeg/utils.py#L428
+[2]: https://github.com/pydicom/pylibjpeg-openjpeg/blob/main/openjpeg/utils.py#L429
diff --git a/build.py b/build.py
index 7832954..b64a311 100644
--- a/build.py
+++ b/build.py
@@ -1,6 +1,5 @@
 
 import os
-import sys
 from pathlib import Path
 import shutil
 import subprocess
diff --git a/lib/interface/decode.c b/lib/interface/decode.c
index 47cf301..3957129 100644
--- a/lib/interface/decode.c
+++ b/lib/interface/decode.c
@@ -562,6 +562,7 @@ extern int Decode(PyObject* fd, unsigned char *out, int codec_format)
     }
 
     // Convert colour space (if required)
+    // Colour space information is only available with JP2
     if (
         image->color_space != OPJ_CLRSPC_SYCC
         && image->numcomps == 3
@@ -668,7 +669,7 @@ extern int Decode(PyObject* fd, unsigned char *out, int codec_format)
             }
         }
     } else {
-        // Support for more than 16-bits per component is not implemented
+        // Support for more than 32-bits per component is not implemented
         return_code = 7;
         goto failure;
     }
diff --git a/lib/interface/encode.c b/lib/interface/encode.c
index b611fb2..bc742c0 100644
--- a/lib/interface/encode.c
+++ b/lib/interface/encode.c
@@ -29,7 +29,7 @@ static void error_callback(const char *msg, void *callback) {
 }
 
 
-extern int Encode(
+extern int EncodeArray(
     PyArrayObject *arr,
     PyObject *dst,
     int bits_stored,
@@ -49,23 +49,21 @@ extern int Encode(
     dst : PyObject *
         The destination for the encoded codestream, should be a BinaryIO.
     bits_stored : int
-        Supported values: 1-16
+        Supported values: 1-24
     photometric_interpretation : int
         Supported values: 0-5
     use_mct : int
         Supported values 0-1, can't be used with subsampling
     compression_ratios : list[float]
-        Encode lossy with the specified compression ratio for each layer. The
-        ratio should be decreasing with increasing layer, and may be 1 to signal
-        the use of lossless encoding for that layer.
+        Encode lossy with the specified compression ratio for each quality
+        layer. The ratio should be decreasing with increasing layer.
     signal_noise_ratios : list[float]
-        Encode lossy with the specified peak signal-to-noise ratio. The ratio
-        should be increasing with increasing layer, but may be 0 in the final
-        layer to signal the use of lossless encoding for that layer.
+        Encode lossy with the specified peak signal-to-noise ratio for each
+        quality layer. The ratio should be increasing with increasing layer.
     codec_format : int
         The format of the encoded JPEG 2000 data, one of:
         * ``0`` - OPJ_CODEC_J2K : JPEG-2000 codestream
-        * ``2`` - OPJ_CODEC_JP2 : JP2 file format
+        * ``1`` - OPJ_CODEC_JP2 : JP2 file format
 
     Returns
     -------
@@ -110,12 +108,12 @@ extern int Encode(
         }
     }
 
-    // Check number of rows and columns is in (1, 65535)
-    if (rows < 1 || rows > 65535) {
+    // Check number of rows and columns is in (1, 2^16 - 1)
+    if (rows < 1 || rows > 0xFFFF) {
         py_error("The input array has an unsupported number of rows");
         return 3;
     }
-    if (columns < 1 || columns > 65535) {
+    if (columns < 1 || columns > 0xFFFF) {
         py_error("The input array has an unsupported number of columns");
         return 4;
     }
@@ -203,7 +201,7 @@ extern int Encode(
     }
 
     // Check the encoding format
-    if (codec_format != 0 && codec_format != 2) {
+    if (codec_format != 0 && codec_format != 1) {
         py_error("The value of the 'codec_format' parameter is invalid");
         return 10;
     }
@@ -241,6 +239,7 @@ extern int Encode(
     Py_ssize_t nr_snr_layers = PyObject_Length(signal_noise_ratios);
     if (nr_cr_layers > 0 || nr_snr_layers > 0) {
         // Lossy compression using compression ratios
+        // For 1 quality layer we use reversible if CR is 1 or PSNR is 0
         parameters.irreversible = 1;  // use DWT 9-7
         if (nr_cr_layers > 0) {
             if (nr_cr_layers > 100) {
@@ -257,12 +256,16 @@ extern int Encode(
                     goto failure;
                 }
                 double value = PyFloat_AsDouble(item);
-                if (value < 1 || value > 1000) {
+                if (value < 1) {
                     return_code = 13;
                     goto failure;
                 }
                 // Maximum 100 rates
                 parameters.tcp_rates[idx] = value;
+
+                if (nr_cr_layers == 1 && value == 1) {
+                    parameters.irreversible = 0;  // use DWT 5-3
+                }
             }
             py_debug("Encoding using lossy compression based on compression ratios");
 
@@ -282,12 +285,16 @@ extern int Encode(
                     goto failure;
                 }
                 double value = PyFloat_AsDouble(item);
-                if (value < 0 || value > 1000) {
+                if (value < 0) {
                     return_code = 16;
                     goto failure;
                 }
                 // Maximum 100 ratios
                 parameters.tcp_distoratio[idx] = value;
+
+                if (nr_snr_layers == 1 && value == 0) {
+                    parameters.irreversible = 0;  // use DWT 5-3
+                }
             }
             py_debug(
                 "Encoding using lossy compression based on peak signal-to-noise ratios"
@@ -389,7 +396,7 @@ extern int Encode(
             codec = opj_create_compress(OPJ_CODEC_J2K);
             break;
         }
-        case 2: { // JP2 codestream
+        case 1: { // JP2 codestream
             codec = opj_create_compress(OPJ_CODEC_JP2);
             break;
         }
@@ -464,3 +471,439 @@ extern int Encode(
         opj_image_destroy(image);
         return return_code;
 }
+
+
+extern int EncodeBuffer(
+    PyObject *src,
+    unsigned int columns,
+    unsigned int rows,
+    unsigned int samples_per_pixel,
+    unsigned int bits_stored,
+    unsigned int is_signed,
+    unsigned int photometric_interpretation,
+    PyObject *dst,
+    unsigned int use_mct,
+    PyObject *compression_ratios,
+    PyObject *signal_noise_ratios,
+    int codec_format
+)
+{
+    /* Encode image data using JPEG 2000.
+
+    Parameters
+    ----------
+    src : PyObject *
+        The image data to be encoded, as a little endian and colour-by-pixel
+        ordered bytes or bytearray.
+    columns : int
+        Supported values: 1-2^16 - 1
+    rows : int
+        Supported values: 1-2^16 - 1
+    samples_per_pixel : int
+        Supported values: 1, 3, 4
+    bits_stored : int
+        Supported values: 1-24
+    is_signed : int
+        0 for unsigned, 1 for signed
+    photometric_interpretation : int
+        Supported values: 0-5
+    dst : PyObject *
+        The destination for the encoded codestream, should be a BinaryIO or
+        an object with write(), tell() and seek().
+    use_mct : int
+        Supported values 0-1, can't be used with subsampling
+    compression_ratios : list[float]
+        Encode lossy with the specified compression ratio for each quality
+        layer. The ratio should be decreasing with increasing layer.
+    signal_noise_ratios : list[float]
+        Encode lossy with the specified peak signal-to-noise ratio for each
+        quality layer. The ratio should be increasing with increasing layer.
+    codec_format : int
+        The format of the encoded JPEG 2000 data, one of:
+        * ``0`` - OPJ_CODEC_J2K : JPEG-2000 codestream
+        * ``1`` - OPJ_CODEC_JP2 : JP2 file format
+
+    Returns
+    -------
+    int
+        The exit status, 0 for success, failure otherwise.
+    */
+
+    // Check input
+    // Check bits_stored is in (1, 24)
+    unsigned int bytes_per_pixel;
+    if (bits_stored > 0 && bits_stored <= 8) {
+        bytes_per_pixel = 1;
+    } else if (bits_stored > 8 && bits_stored <= 16) {
+        bytes_per_pixel = 2;
+    } else if (bits_stored > 16 && bits_stored <= 24) {
+        bytes_per_pixel = 4;
+    } else {
+        py_error("The value of the 'bits_stored' parameter is invalid");
+        return 50;
+    }
+
+    // Check samples_per_pixel is 1, 3 or 4
+    switch (samples_per_pixel) {
+        case 1: break;
+        case 3: break;
+        case 4: break;
+        default: {
+            py_error("The number of samples per pixel is not supported");
+            return 51;
+        }
+    }
+
+    // Check number of rows and columns is in (1, 2^16 - 1)
+    // The J2K standard supports up to 32-bit rows and columns
+    if (rows < 1 || rows > 0xFFFF) {
+        py_error("The number of rows is invalid");
+        return 52;
+    }
+    if (columns < 1 || columns > 0xFFFF) {
+        py_error("The number of columns is invalid");
+        return 53;
+    }
+
+    // Check is_signed is 0 or 1
+    if (is_signed != 0 && is_signed != 1) {
+        py_error("The value of the 'is_signed' parameter is invalid");
+        return 54;
+    }
+
+    // Check length of `src` matches expected dimensions
+    Py_ssize_t actual_length = PyObject_Length(src);
+    // (2**24 - 1) x (2**24 - 1) * 4 * 4 -> requires 52-bits
+    // OPJ_INT64 covers from (-2**63, 2**63 - 1) which is sufficient
+    OPJ_INT64 expected_length = rows * columns * samples_per_pixel * bytes_per_pixel;
+    if (actual_length != expected_length) {
+        py_error("The length of `src` does not match the expected length");
+        return 55;
+    }
+
+    // Check `photometric_interpretation` is valid
+    if (
+        samples_per_pixel == 1
+        && (
+            photometric_interpretation != 0  // OPJ_CLRSPC_UNSPECIFIED
+            && photometric_interpretation != 2  // OPJ_CLRSPC_GRAY
+        )
+    ) {
+        py_error(
+            "The value of the 'photometric_interpretation' parameter is not "
+            "valid for the number of samples per pixel"
+        );
+        return 9;
+    }
+
+    if (
+        samples_per_pixel == 3
+        && (
+            photometric_interpretation != 0  // OPJ_CLRSPC_UNSPECIFIED
+            && photometric_interpretation != 1  // OPJ_CLRSPC_SRGB
+            && photometric_interpretation != 3  // OPJ_CLRSPC_SYCC
+            && photometric_interpretation != 4  // OPJ_CLRSPC_EYCC
+        )
+    ) {
+        py_error(
+            "The value of the 'photometric_interpretation' parameter is not "
+            "valid for the number of samples per pixel"
+        );
+        return 9;
+    }
+
+    if (
+        samples_per_pixel == 4
+        && (
+            photometric_interpretation != 0  // OPJ_CLRSPC_UNSPECIFIED
+            && photometric_interpretation != 5  // OPJ_CLRSPC_CMYK
+        )
+    ) {
+        py_error(
+            "The value of the 'photometric_interpretation' parameter is not "
+            "valid for the number of samples per pixel"
+        );
+        return 9;
+    }
+
+    // Check the encoding format
+    if (codec_format != 0 && codec_format != 1) {
+        py_error("The value of the 'codec_format' parameter is invalid");
+        return 10;
+    }
+
+    // Disable MCT if the input is not RGB
+    if (samples_per_pixel != 3 || photometric_interpretation != 1) {
+        use_mct = 0;
+    }
+
+    // Encoding parameters
+    unsigned int return_code;
+    opj_cparameters_t parameters;
+    opj_stream_t *stream = 00;
+    opj_codec_t *codec = 00;
+    opj_image_t *image = NULL;
+
+    // subsampling_dx 1
+    // subsampling_dy 1
+    // tcp_numlayers = 0
+    // tcp_rates[0] = 0
+    // prog_order = OPJ_LRCP
+    // cblockw_init = 64
+    // cblockh_init = 64
+    // numresolution = 6
+    opj_set_default_encoder_parameters(&parameters);
+
+    // Set MCT and codec
+    parameters.tcp_mct = use_mct;
+    parameters.cod_format = codec_format;
+
+    // Set up for lossy (if applicable)
+    Py_ssize_t nr_cr_layers = PyObject_Length(compression_ratios);
+    Py_ssize_t nr_snr_layers = PyObject_Length(signal_noise_ratios);
+    if (nr_cr_layers > 0 || nr_snr_layers > 0) {
+        // Lossy compression using compression ratios
+        parameters.irreversible = 1;  // use DWT 9-7
+        if (nr_cr_layers > 0) {
+            if (nr_cr_layers > 100) {
+                return_code = 11;
+                goto failure;
+            }
+
+            parameters.cp_disto_alloc = 1;  // Allocation by rate/distortion
+            parameters.tcp_numlayers = nr_cr_layers;
+            for (int idx = 0; idx < nr_cr_layers; idx++) {
+                PyObject *item = PyList_GetItem(compression_ratios, idx);
+                if (item == NULL || !PyFloat_Check(item)) {
+                    return_code = 12;
+                    goto failure;
+                }
+                double value = PyFloat_AsDouble(item);
+                if (value < 1) {
+                    return_code = 13;
+                    goto failure;
+                }
+                // Maximum 100 rates
+                parameters.tcp_rates[idx] = value;
+
+                if (nr_cr_layers == 1 && value == 1) {
+                    parameters.irreversible = 0;  // use DWT 5-3
+                }
+            }
+            py_debug("Encoding using lossy compression based on compression ratios");
+
+        } else {
+            // Lossy compression using peak signal-to-noise ratios
+            if (nr_snr_layers > 100) {
+                return_code = 14;
+                goto failure;
+            }
+
+            parameters.cp_fixed_quality = 1;
+            parameters.tcp_numlayers = nr_snr_layers;
+            for (int idx = 0; idx < nr_snr_layers; idx++) {
+                PyObject *item = PyList_GetItem(signal_noise_ratios, idx);
+                if (item == NULL || !PyFloat_Check(item)) {
+                    return_code = 15;
+                    goto failure;
+                }
+                double value = PyFloat_AsDouble(item);
+                if (value < 0) {
+                    return_code = 16;
+                    goto failure;
+                }
+                // Maximum 100 ratios
+                parameters.tcp_distoratio[idx] = value;
+
+                if (nr_snr_layers == 1 && value == 0) {
+                    parameters.irreversible = 0;  // use DWT 5-3
+                }
+            }
+            py_debug(
+                "Encoding using lossy compression based on peak signal-to-noise ratios"
+            );
+        }
+    }
+
+    py_debug("Input validation complete, setting up for encoding");
+
+    // Create the input image and configure it
+    // Setup the parameters for each image component
+    opj_image_cmptparm_t *cmptparm;
+    cmptparm = (opj_image_cmptparm_t*) calloc(
+        (OPJ_UINT32) samples_per_pixel,
+        sizeof(opj_image_cmptparm_t)
+    );
+    if (!cmptparm) {
+        py_error("Failed to assign the image component parameters");
+        return_code = 20;
+        goto failure;
+    }
+    unsigned int i;
+    for (i = 0; i < samples_per_pixel; i++) {
+        cmptparm[i].prec = (OPJ_UINT32) bits_stored;
+        cmptparm[i].sgnd = (OPJ_UINT32) is_signed;
+        // Sub-sampling: none
+        cmptparm[i].dx = (OPJ_UINT32) 1;
+        cmptparm[i].dy = (OPJ_UINT32) 1;
+        cmptparm[i].w = (OPJ_UINT32) columns;
+        cmptparm[i].h = (OPJ_UINT32) rows;
+    }
+
+    // Create the input image object
+    image = opj_image_create(
+        (OPJ_UINT32) samples_per_pixel,
+        &cmptparm[0],
+        photometric_interpretation
+    );
+
+    free(cmptparm);
+    if (!image) {
+        py_error("Failed to create an empty image object");
+        return_code = 21;
+        goto failure;
+    }
+
+    /* set image offset and reference grid */
+    image->x0 = (OPJ_UINT32)parameters.image_offset_x0;
+    image->y0 = (OPJ_UINT32)parameters.image_offset_y0;
+    image->x1 = (OPJ_UINT32)parameters.image_offset_x0 + (OPJ_UINT32) columns;
+    image->y1 = (OPJ_UINT32)parameters.image_offset_y0 + (OPJ_UINT32) rows;
+
+    // Add the image data
+    // src is ordered as colour-by-pixel
+    unsigned int p;
+    OPJ_UINT64 nr_pixels = rows * columns;
+    char *data = PyBytes_AsString(src);
+    if (bytes_per_pixel == 1) {
+        for (OPJ_UINT64 ii = 0; ii < nr_pixels; ii++)
+        {
+            for (p = 0; p < samples_per_pixel; p++)
+            {
+                image->comps[p].data[ii] = is_signed ? *data : (unsigned char) *data;
+                data++;
+            }
+        }
+    } else if (bytes_per_pixel == 2) {
+        union {
+            short val;
+            unsigned char vals[2];
+        } u16;
+
+        for (OPJ_UINT64 ii = 0; ii < nr_pixels; ii++)
+        {
+            for (p = 0; p < samples_per_pixel; p++)
+            {
+                u16.vals[0] = (unsigned char) *data;
+                data++;
+                u16.vals[1] = (unsigned char) *data;
+                data++;
+                image->comps[p].data[ii] = is_signed ? u16.val : (unsigned short) u16.val;
+            }
+        }
+    } else if (bytes_per_pixel == 4) {
+        union {
+            long val;
+            unsigned char vals[4];
+        } u32;
+
+        for (OPJ_UINT64 ii = 0; ii < nr_pixels; ii++)
+        {
+            for (p = 0; p < samples_per_pixel; p++)
+            {
+                u32.vals[0] = (unsigned char) *data;
+                data++;
+                u32.vals[1] = (unsigned char) *data;
+                data++;
+                u32.vals[2] = (unsigned char) *data;
+                data++;
+                u32.vals[3] = (unsigned char) *data;
+                data++;
+                image->comps[p].data[ii] = is_signed ? u32.val : (unsigned long) u32.val;
+            }
+        }
+    }
+    py_debug("Input image configured and populated with data");
+
+    /* Get an encoder handle */
+    switch (parameters.cod_format) {
+        case 0: {  // J2K codestream only
+            codec = opj_create_compress(OPJ_CODEC_J2K);
+            break;
+        }
+        case 1: { // JP2 codestream
+            codec = opj_create_compress(OPJ_CODEC_JP2);
+            break;
+        }
+        default:
+            py_error("Failed to set the encoding handler");
+            return_code = 22;
+            goto failure;
+    }
+
+    /* Send info, warning, error message to Python logging */
+    opj_set_info_handler(codec, info_callback, NULL);
+    opj_set_warning_handler(codec, warning_callback, NULL);
+    opj_set_error_handler(codec, error_callback, NULL);
+
+    if (! opj_setup_encoder(codec, &parameters, image)) {
+        py_error("Failed to set up the encoder");
+        return_code = 23;
+        goto failure;
+    }
+
+    // Creates an abstract output stream; allocates memory
+    // cio::opj_stream_create(buffer size, is_input)
+    stream = opj_stream_create(BUFFER_SIZE, OPJ_FALSE);
+
+    if (!stream) {
+        py_error("Failed to create the output stream");
+        return_code = 24;
+        goto failure;
+    }
+
+    // Functions for the stream
+    opj_stream_set_user_data(stream, dst, NULL);
+    opj_stream_set_write_function(stream, py_write);
+    opj_stream_set_skip_function(stream, py_skip);
+    opj_stream_set_seek_function(stream, py_seek_set);
+
+    OPJ_BOOL result;
+
+    // Encode `image` using `codec` and put the output in `stream`
+    py_debug("Encoding started");
+    result = opj_start_compress(codec, image, stream);
+    if (!result)  {
+        py_error("Failure result from 'opj_start_compress()'");
+        return_code = 25;
+        goto failure;
+    }
+
+    result = result && opj_encode(codec, stream);
+    if (!result)  {
+        py_error("Failure result from 'opj_encode()'");
+        return_code = 26;
+        goto failure;
+    }
+
+    result = result && opj_end_compress(codec, stream);
+    if (!result)  {
+        py_error("Failure result from 'opj_end_compress()'");
+        return_code = 27;
+        goto failure;
+    }
+
+    py_debug("Encoding completed");
+
+    opj_stream_destroy(stream);
+    opj_destroy_codec(codec);
+    opj_image_destroy(image);
+
+    return 0;
+
+    failure:
+        opj_stream_destroy(stream);
+        opj_destroy_codec(codec);
+        opj_image_destroy(image);
+        return return_code;
+}
diff --git a/lib/interface/utils.c b/lib/interface/utils.c
index 29517bc..a2811f1 100644
--- a/lib/interface/utils.c
+++ b/lib/interface/utils.c
@@ -67,7 +67,7 @@ Py_ssize_t py_tell(PyObject *stream)
     Returns
     -------
     Py_ssize_t
-        The new position in the `stream`.
+        The current position in the `stream`.
     */
     PyObject *result;
     Py_ssize_t location;
@@ -162,7 +162,7 @@ OPJ_BOOL py_seek(Py_ssize_t offset, void *stream, int whence)
     OPJ_TRUE : OBJ_BOOL
     */
     // Python and C; SEEK_SET is 0, SEEK_CUR is 1 and SEEK_END is 2
-    // fd.seek(nr_bytes),
+    // stream.seek(nr_bytes, whence),
     // k: convert C unsigned long int to Python int
     // i: convert C int to a Python integer
     PyObject *result;
@@ -197,7 +197,7 @@ OPJ_BOOL py_seek_set(OPJ_OFF_T offset, void *stream)
 OPJ_OFF_T py_skip(OPJ_OFF_T offset, void *stream)
 {
     /* Change the `stream` position by `offset` from SEEK_CUR and return the
-    new position.
+    number of skipped bytes.
 
     Parameters
     ----------
@@ -208,15 +208,18 @@ OPJ_OFF_T py_skip(OPJ_OFF_T offset, void *stream)
 
     Returns
     -------
-    off_t
-        The new position in the `stream`.
+    int
+        The number of bytes skipped
     */
+    off_t initial;
+    initial = py_tell(stream);
+
     py_seek(offset, stream, SEEK_CUR);
 
-    off_t pos;
-    pos = py_tell(stream);
+    off_t current;
+    current = py_tell(stream);
 
-    return pos ? pos : (OPJ_OFF_T) -1;
+    return current - initial;
 }
 
 
diff --git a/openjpeg/_openjpeg.c b/openjpeg/_openjpeg.c
index 166ca9b..2a2c7a2 100644
--- a/openjpeg/_openjpeg.c
+++ b/openjpeg/_openjpeg.c
@@ -1,19 +1,19 @@
-/* Generated by Cython 3.0.8 */
+/* Generated by Cython 3.0.9 */
 
 /* BEGIN: Cython Metadata
 {
     "distutils": {
         "depends": [
-            "/tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/core/include/numpy/arrayobject.h",
-            "/tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/core/include/numpy/arrayscalars.h",
-            "/tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/core/include/numpy/ndarrayobject.h",
-            "/tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/core/include/numpy/ndarraytypes.h",
-            "/tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/core/include/numpy/ufuncobject.h"
+            "/tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/core/include/numpy/arrayobject.h",
+            "/tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/core/include/numpy/arrayscalars.h",
+            "/tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/core/include/numpy/ndarrayobject.h",
+            "/tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/core/include/numpy/ndarraytypes.h",
+            "/tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/core/include/numpy/ufuncobject.h"
         ],
         "include_dirs": [
             "/home/dean/Coding/src/pylibjpeg-openjpeg/lib/openjpeg/src/lib/openjp2",
             "/home/dean/Coding/src/pylibjpeg-openjpeg/lib/interface",
-            "/tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/core/include"
+            "/tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/core/include"
         ],
         "language": "c",
         "name": "_openjpeg",
@@ -82,10 +82,10 @@ END: Cython Metadata */
 #else
 #define __PYX_EXTRA_ABI_MODULE_NAME ""
 #endif
-#define CYTHON_ABI "3_0_8" __PYX_EXTRA_ABI_MODULE_NAME
+#define CYTHON_ABI "3_0_9" __PYX_EXTRA_ABI_MODULE_NAME
 #define __PYX_ABI_MODULE_NAME "_cython_" CYTHON_ABI
 #define __PYX_TYPE_MODULE_PREFIX __PYX_ABI_MODULE_NAME "."
-#define CYTHON_HEX_VERSION 0x030008F0
+#define CYTHON_HEX_VERSION 0x030009F0
 #define CYTHON_FUTURE_DIVISION 1
 #include <stddef.h>
 #ifndef offsetof
@@ -778,8 +778,13 @@ END: Cython Metadata */
   typedef PyObject *(*__Pyx_PyCFunctionFastWithKeywords) (PyObject *self, PyObject *const *args,
                                                           Py_ssize_t nargs, PyObject *kwnames);
 #else
-  #define __Pyx_PyCFunctionFast _PyCFunctionFast
-  #define __Pyx_PyCFunctionFastWithKeywords _PyCFunctionFastWithKeywords
+  #if PY_VERSION_HEX >= 0x030d00A4
+  #  define __Pyx_PyCFunctionFast PyCFunctionFast
+  #  define __Pyx_PyCFunctionFastWithKeywords PyCFunctionFastWithKeywords
+  #else
+  #  define __Pyx_PyCFunctionFast _PyCFunctionFast
+  #  define __Pyx_PyCFunctionFastWithKeywords _PyCFunctionFastWithKeywords
+  #endif
 #endif
 #if CYTHON_METH_FASTCALL
   #define __Pyx_METH_FASTCALL METH_FASTCALL
@@ -1131,7 +1136,7 @@ static CYTHON_INLINE PyObject * __Pyx_PyDict_GetItemStrWithError(PyObject *dict,
   #define __Pyx_PyBytes_GET_SIZE(o) PyBytes_Size(o)
   #define __Pyx_PyByteArray_GET_SIZE(o) PyByteArray_Size(o)
 #endif
-#if PY_VERSION_HEX >= 0x030d00A1
+#if __PYX_LIMITED_VERSION_HEX >= 0x030d00A1
   #define __Pyx_PyImport_AddModuleRef(name) PyImport_AddModuleRef(name)
 #else
   static CYTHON_INLINE PyObject *__Pyx_PyImport_AddModuleRef(const char *name) {
@@ -1218,7 +1223,7 @@ static CYTHON_INLINE float __PYX_NAN() {
 #endif
 
 #define __PYX_MARK_ERR_POS(f_index, lineno) \
-    { __pyx_filename = __pyx_f[f_index]; (void)__pyx_filename; __pyx_lineno = lineno; (void)__pyx_lineno; __pyx_clineno = __LINE__; (void)__pyx_clineno; }
+    { __pyx_filename = __pyx_f[f_index]; (void)__pyx_filename; __pyx_lineno = lineno; (void)__pyx_lineno; __pyx_clineno = __LINE__;  (void)__pyx_clineno; }
 #define __PYX_ERR(f_index, lineno, Ln_error) \
     { __PYX_MARK_ERR_POS(f_index, lineno) goto Ln_error; }
 
@@ -1332,24 +1337,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char*);
 #define __Pyx_PyByteArray_FromCString(s)   __Pyx_PyByteArray_FromString((const char*)s)
 #define __Pyx_PyStr_FromCString(s)     __Pyx_PyStr_FromString((const char*)s)
 #define __Pyx_PyUnicode_FromCString(s) __Pyx_PyUnicode_FromString((const char*)s)
-#if CYTHON_COMPILING_IN_LIMITED_API
-static CYTHON_INLINE size_t __Pyx_Py_UNICODE_strlen(const wchar_t *u)
-{
-    const wchar_t *u_end = u;
-    while (*u_end++) ;
-    return (size_t)(u_end - u - 1);
-}
-#else
-static CYTHON_INLINE size_t __Pyx_Py_UNICODE_strlen(const Py_UNICODE *u)
-{
-    const Py_UNICODE *u_end = u;
-    while (*u_end++) ;
-    return (size_t)(u_end - u - 1);
-}
-#endif
 #define __Pyx_PyUnicode_FromOrdinal(o)       PyUnicode_FromOrdinal((int)o)
-#define __Pyx_PyUnicode_FromUnicode(u)       PyUnicode_FromUnicode(u, __Pyx_Py_UNICODE_strlen(u))
-#define __Pyx_PyUnicode_FromUnicodeAndLength PyUnicode_FromUnicode
 #define __Pyx_PyUnicode_AsUnicode            PyUnicode_AsUnicode
 #define __Pyx_NewRef(obj) (Py_INCREF(obj), obj)
 #define __Pyx_Owned_Py_None(b) __Pyx_NewRef(Py_None)
@@ -1552,7 +1540,7 @@ static const char *__pyx_f[] = {
 
 /* #### Code section: numeric_typedefs ### */
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":731
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":731
  * # in Cython to enable them only on the right systems.
  * 
  * ctypedef npy_int8       int8_t             # <<<<<<<<<<<<<<
@@ -1561,7 +1549,7 @@ static const char *__pyx_f[] = {
  */
 typedef npy_int8 __pyx_t_5numpy_int8_t;
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":732
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":732
  * 
  * ctypedef npy_int8       int8_t
  * ctypedef npy_int16      int16_t             # <<<<<<<<<<<<<<
@@ -1570,7 +1558,7 @@ typedef npy_int8 __pyx_t_5numpy_int8_t;
  */
 typedef npy_int16 __pyx_t_5numpy_int16_t;
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":733
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":733
  * ctypedef npy_int8       int8_t
  * ctypedef npy_int16      int16_t
  * ctypedef npy_int32      int32_t             # <<<<<<<<<<<<<<
@@ -1579,7 +1567,7 @@ typedef npy_int16 __pyx_t_5numpy_int16_t;
  */
 typedef npy_int32 __pyx_t_5numpy_int32_t;
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":734
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":734
  * ctypedef npy_int16      int16_t
  * ctypedef npy_int32      int32_t
  * ctypedef npy_int64      int64_t             # <<<<<<<<<<<<<<
@@ -1588,7 +1576,7 @@ typedef npy_int32 __pyx_t_5numpy_int32_t;
  */
 typedef npy_int64 __pyx_t_5numpy_int64_t;
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":738
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":738
  * #ctypedef npy_int128     int128_t
  * 
  * ctypedef npy_uint8      uint8_t             # <<<<<<<<<<<<<<
@@ -1597,7 +1585,7 @@ typedef npy_int64 __pyx_t_5numpy_int64_t;
  */
 typedef npy_uint8 __pyx_t_5numpy_uint8_t;
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":739
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":739
  * 
  * ctypedef npy_uint8      uint8_t
  * ctypedef npy_uint16     uint16_t             # <<<<<<<<<<<<<<
@@ -1606,7 +1594,7 @@ typedef npy_uint8 __pyx_t_5numpy_uint8_t;
  */
 typedef npy_uint16 __pyx_t_5numpy_uint16_t;
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":740
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":740
  * ctypedef npy_uint8      uint8_t
  * ctypedef npy_uint16     uint16_t
  * ctypedef npy_uint32     uint32_t             # <<<<<<<<<<<<<<
@@ -1615,7 +1603,7 @@ typedef npy_uint16 __pyx_t_5numpy_uint16_t;
  */
 typedef npy_uint32 __pyx_t_5numpy_uint32_t;
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":741
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":741
  * ctypedef npy_uint16     uint16_t
  * ctypedef npy_uint32     uint32_t
  * ctypedef npy_uint64     uint64_t             # <<<<<<<<<<<<<<
@@ -1624,7 +1612,7 @@ typedef npy_uint32 __pyx_t_5numpy_uint32_t;
  */
 typedef npy_uint64 __pyx_t_5numpy_uint64_t;
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":745
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":745
  * #ctypedef npy_uint128    uint128_t
  * 
  * ctypedef npy_float32    float32_t             # <<<<<<<<<<<<<<
@@ -1633,7 +1621,7 @@ typedef npy_uint64 __pyx_t_5numpy_uint64_t;
  */
 typedef npy_float32 __pyx_t_5numpy_float32_t;
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":746
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":746
  * 
  * ctypedef npy_float32    float32_t
  * ctypedef npy_float64    float64_t             # <<<<<<<<<<<<<<
@@ -1642,7 +1630,7 @@ typedef npy_float32 __pyx_t_5numpy_float32_t;
  */
 typedef npy_float64 __pyx_t_5numpy_float64_t;
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":755
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":755
  * # The int types are mapped a bit surprising --
  * # numpy.int corresponds to 'l' and numpy.long to 'q'
  * ctypedef npy_long       int_t             # <<<<<<<<<<<<<<
@@ -1651,7 +1639,7 @@ typedef npy_float64 __pyx_t_5numpy_float64_t;
  */
 typedef npy_long __pyx_t_5numpy_int_t;
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":756
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":756
  * # numpy.int corresponds to 'l' and numpy.long to 'q'
  * ctypedef npy_long       int_t
  * ctypedef npy_longlong   long_t             # <<<<<<<<<<<<<<
@@ -1660,7 +1648,7 @@ typedef npy_long __pyx_t_5numpy_int_t;
  */
 typedef npy_longlong __pyx_t_5numpy_long_t;
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":757
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":757
  * ctypedef npy_long       int_t
  * ctypedef npy_longlong   long_t
  * ctypedef npy_longlong   longlong_t             # <<<<<<<<<<<<<<
@@ -1669,7 +1657,7 @@ typedef npy_longlong __pyx_t_5numpy_long_t;
  */
 typedef npy_longlong __pyx_t_5numpy_longlong_t;
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":759
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":759
  * ctypedef npy_longlong   longlong_t
  * 
  * ctypedef npy_ulong      uint_t             # <<<<<<<<<<<<<<
@@ -1678,7 +1666,7 @@ typedef npy_longlong __pyx_t_5numpy_longlong_t;
  */
 typedef npy_ulong __pyx_t_5numpy_uint_t;
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":760
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":760
  * 
  * ctypedef npy_ulong      uint_t
  * ctypedef npy_ulonglong  ulong_t             # <<<<<<<<<<<<<<
@@ -1687,7 +1675,7 @@ typedef npy_ulong __pyx_t_5numpy_uint_t;
  */
 typedef npy_ulonglong __pyx_t_5numpy_ulong_t;
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":761
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":761
  * ctypedef npy_ulong      uint_t
  * ctypedef npy_ulonglong  ulong_t
  * ctypedef npy_ulonglong  ulonglong_t             # <<<<<<<<<<<<<<
@@ -1696,7 +1684,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulong_t;
  */
 typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t;
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":763
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":763
  * ctypedef npy_ulonglong  ulonglong_t
  * 
  * ctypedef npy_intp       intp_t             # <<<<<<<<<<<<<<
@@ -1705,7 +1693,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t;
  */
 typedef npy_intp __pyx_t_5numpy_intp_t;
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":764
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":764
  * 
  * ctypedef npy_intp       intp_t
  * ctypedef npy_uintp      uintp_t             # <<<<<<<<<<<<<<
@@ -1714,7 +1702,7 @@ typedef npy_intp __pyx_t_5numpy_intp_t;
  */
 typedef npy_uintp __pyx_t_5numpy_uintp_t;
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":766
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":766
  * ctypedef npy_uintp      uintp_t
  * 
  * ctypedef npy_double     float_t             # <<<<<<<<<<<<<<
@@ -1723,7 +1711,7 @@ typedef npy_uintp __pyx_t_5numpy_uintp_t;
  */
 typedef npy_double __pyx_t_5numpy_float_t;
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":767
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":767
  * 
  * ctypedef npy_double     float_t
  * ctypedef npy_double     double_t             # <<<<<<<<<<<<<<
@@ -1732,7 +1720,7 @@ typedef npy_double __pyx_t_5numpy_float_t;
  */
 typedef npy_double __pyx_t_5numpy_double_t;
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":768
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":768
  * ctypedef npy_double     float_t
  * ctypedef npy_double     double_t
  * ctypedef npy_longdouble longdouble_t             # <<<<<<<<<<<<<<
@@ -1769,7 +1757,7 @@ static CYTHON_INLINE __pyx_t_double_complex __pyx_t_double_complex_from_parts(do
 
 /*--- Type declarations ---*/
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":770
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":770
  * ctypedef npy_longdouble longdouble_t
  * 
  * ctypedef npy_cfloat      cfloat_t             # <<<<<<<<<<<<<<
@@ -1778,7 +1766,7 @@ static CYTHON_INLINE __pyx_t_double_complex __pyx_t_double_complex_from_parts(do
  */
 typedef npy_cfloat __pyx_t_5numpy_cfloat_t;
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":771
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":771
  * 
  * ctypedef npy_cfloat      cfloat_t
  * ctypedef npy_cdouble     cdouble_t             # <<<<<<<<<<<<<<
@@ -1787,7 +1775,7 @@ typedef npy_cfloat __pyx_t_5numpy_cfloat_t;
  */
 typedef npy_cdouble __pyx_t_5numpy_cdouble_t;
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":772
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":772
  * ctypedef npy_cfloat      cfloat_t
  * ctypedef npy_cdouble     cdouble_t
  * ctypedef npy_clongdouble clongdouble_t             # <<<<<<<<<<<<<<
@@ -1796,7 +1784,7 @@ typedef npy_cdouble __pyx_t_5numpy_cdouble_t;
  */
 typedef npy_clongdouble __pyx_t_5numpy_clongdouble_t;
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":774
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":774
  * ctypedef npy_clongdouble clongdouble_t
  * 
  * ctypedef npy_cdouble     complex_t             # <<<<<<<<<<<<<<
@@ -1821,7 +1809,7 @@ struct __pyx_t_9_openjpeg_JPEG2000Parameters {
   uint32_t columns;
   uint32_t rows;
   int colourspace;
-  uint32_t nr_components;
+  uint32_t samples_per_pixel;
   uint32_t precision;
   unsigned int is_signed;
   uint32_t nr_tiles;
@@ -2475,23 +2463,26 @@ static CYTHON_INLINE double __Pyx_PyUnicode_AsDouble(PyObject *obj) {
 static CYTHON_INLINE PyObject* __Pyx__PyNumber_Float(PyObject* obj);
 #define __Pyx_PyNumber_Float(x) (PyFloat_CheckExact(x) ? __Pyx_NewRef(x) : __Pyx__PyNumber_Float(x))
 
+/* CIntToPyUnicode.proto */
+static CYTHON_INLINE PyObject* __Pyx_PyUnicode_From_Py_ssize_t(Py_ssize_t value, Py_ssize_t width, char padding_char, char format_char);
+
 /* TypeImport.proto */
-#ifndef __PYX_HAVE_RT_ImportType_proto_3_0_8
-#define __PYX_HAVE_RT_ImportType_proto_3_0_8
+#ifndef __PYX_HAVE_RT_ImportType_proto_3_0_9
+#define __PYX_HAVE_RT_ImportType_proto_3_0_9
 #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
 #include <stdalign.h>
 #endif
 #if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) || __cplusplus >= 201103L
-#define __PYX_GET_STRUCT_ALIGNMENT_3_0_8(s) alignof(s)
+#define __PYX_GET_STRUCT_ALIGNMENT_3_0_9(s) alignof(s)
 #else
-#define __PYX_GET_STRUCT_ALIGNMENT_3_0_8(s) sizeof(void*)
+#define __PYX_GET_STRUCT_ALIGNMENT_3_0_9(s) sizeof(void*)
 #endif
-enum __Pyx_ImportType_CheckSize_3_0_8 {
-   __Pyx_ImportType_CheckSize_Error_3_0_8 = 0,
-   __Pyx_ImportType_CheckSize_Warn_3_0_8 = 1,
-   __Pyx_ImportType_CheckSize_Ignore_3_0_8 = 2
+enum __Pyx_ImportType_CheckSize_3_0_9 {
+   __Pyx_ImportType_CheckSize_Error_3_0_9 = 0,
+   __Pyx_ImportType_CheckSize_Warn_3_0_9 = 1,
+   __Pyx_ImportType_CheckSize_Ignore_3_0_9 = 2
 };
-static PyTypeObject *__Pyx_ImportType_3_0_8(PyObject* module, const char *module_name, const char *class_name, size_t size, size_t alignment, enum __Pyx_ImportType_CheckSize_3_0_8 check_size);
+static PyTypeObject *__Pyx_ImportType_3_0_9(PyObject* module, const char *module_name, const char *class_name, size_t size, size_t alignment, enum __Pyx_ImportType_CheckSize_3_0_9 check_size);
 #endif
 
 /* Import.proto */
@@ -2871,7 +2862,8 @@ static CYTHON_INLINE char *__pyx_f_5numpy_7ndarray_4data_data(PyArrayObject *__p
 __PYX_EXTERN_C DL_IMPORT(char) *OpenJpegVersion(void); /*proto*/
 __PYX_EXTERN_C DL_IMPORT(int) Decode(void *, unsigned char *, int); /*proto*/
 __PYX_EXTERN_C DL_IMPORT(int) GetParameters(void *, int, struct __pyx_t_9_openjpeg_JPEG2000Parameters *); /*proto*/
-__PYX_EXTERN_C DL_IMPORT(int) Encode(PyArrayObject *, PyObject *, int, int, int, PyObject *, PyObject *, int); /*proto*/
+__PYX_EXTERN_C DL_IMPORT(int) EncodeArray(PyArrayObject *, PyObject *, int, int, int, PyObject *, PyObject *, int); /*proto*/
+__PYX_EXTERN_C DL_IMPORT(int) EncodeBuffer(PyObject *, int, int, int, int, int, int, PyObject *, int, PyObject *, PyObject *, int); /*proto*/
 /* #### Code section: typeinfo ### */
 /* #### Code section: before_global_var ### */
 #define __Pyx_MODULE_NAME "_openjpeg"
@@ -2883,19 +2875,21 @@ int __pyx_module_is_main__openjpeg = 0;
 static PyObject *__pyx_builtin_KeyError;
 static PyObject *__pyx_builtin_RuntimeError;
 static PyObject *__pyx_builtin_ValueError;
+static PyObject *__pyx_builtin_TypeError;
 static PyObject *__pyx_builtin_ImportError;
 /* #### Code section: string_decls ### */
 static const char __pyx_k_x[] = "x";
 static const char __pyx_k__3[] = ": ";
 static const char __pyx_k__4[] = ")";
 static const char __pyx_k__6[] = ", ";
+static const char __pyx_k__9[] = "'";
 static const char __pyx_k_fp[] = "fp";
 static const char __pyx_k_io[] = "io";
 static const char __pyx_k_np[] = "np";
 static const char __pyx_k_YUV[] = "YUV";
 static const char __pyx_k__10[] = ".";
 static const char __pyx_k__11[] = "*";
-static const char __pyx_k__20[] = "?";
+static const char __pyx_k__22[] = "?";
 static const char __pyx_k_arr[] = "arr";
 static const char __pyx_k_bpp[] = "bpp";
 static const char __pyx_k_dst[] = "dst";
@@ -2905,6 +2899,7 @@ static const char __pyx_k_min[] = "min";
 static const char __pyx_k_msg[] = "msg";
 static const char __pyx_k_out[] = "out";
 static const char __pyx_k_ptr[] = "ptr";
+static const char __pyx_k_src[] = "src";
 static const char __pyx_k_CYMK[] = "CYMK";
 static const char __pyx_k_Dict[] = "Dict";
 static const char __pyx_k_List[] = "List";
@@ -2921,7 +2916,7 @@ static const char __pyx_k_spec[] = "__spec__";
 static const char __pyx_k_test[] = "__test__";
 static const char __pyx_k_Tuple[] = "Tuple";
 static const char __pyx_k_Union[] = "Union";
-static const char __pyx_k_bytes[] = "bytes";
+static const char __pyx_k_bytes[] = " bytes";
 static const char __pyx_k_codec[] = "codec";
 static const char __pyx_k_dtype[] = "dtype";
 static const char __pyx_k_e_YCC[] = "e-YCC";
@@ -2935,7 +2930,6 @@ static const char __pyx_k_zeros[] = "zeros";
 static const char __pyx_k_ERRORS[] = "ERRORS";
 static const char __pyx_k_LOGGER[] = "LOGGER";
 static const char __pyx_k_decode[] = "decode";
-static const char __pyx_k_encode[] = "encode";
 static const char __pyx_k_import[] = "__import__";
 static const char __pyx_k_result[] = "result";
 static const char __pyx_k_return[] = "return";
@@ -2946,6 +2940,7 @@ static const char __pyx_k_BytesIO[] = "BytesIO";
 static const char __pyx_k_allowed[] = "allowed";
 static const char __pyx_k_arr_max[] = "arr_max";
 static const char __pyx_k_arr_min[] = "arr_min";
+static const char __pyx_k_bytes_2[] = "bytes";
 static const char __pyx_k_colours[] = "colours";
 static const char __pyx_k_columns[] = "columns";
 static const char __pyx_k_logging[] = "logging";
@@ -2961,6 +2956,7 @@ static const char __pyx_k_itemsize[] = "itemsize";
 static const char __pyx_k_nr_bytes[] = "nr_bytes";
 static const char __pyx_k_nr_tiles[] = "nr_tiles";
 static const char __pyx_k_openjpeg[] = "_openjpeg";
+static const char __pyx_k_TypeError[] = "TypeError";
 static const char __pyx_k_getLogger[] = "getLogger";
 static const char __pyx_k_is_signed[] = "is_signed";
 static const char __pyx_k_precision[] = "precision";
@@ -2975,46 +2971,67 @@ static const char __pyx_k_return_code[] = "return_code";
 static const char __pyx_k_unspecified[] = "unspecified";
 static const char __pyx_k_RuntimeError[] = "RuntimeError";
 static const char __pyx_k_codec_format[] = "codec_format";
+static const char __pyx_k_encode_array[] = "encode_array";
 static const char __pyx_k_initializing[] = "_initializing";
 static const char __pyx_k_is_coroutine[] = "_is_coroutine";
-static const char __pyx_k_nr_components[] = "nr_components";
+static const char __pyx_k_actual_length[] = "actual_length";
+static const char __pyx_k_encode_buffer[] = "encode_buffer";
 static const char __pyx_k_get_parameters[] = "get_parameters";
+static const char __pyx_k_must_be_0_or_1[] = "', must be 0 or 1";
 static const char __pyx_k_Tuple_int_bytes[] = "Tuple[int, bytes]";
+static const char __pyx_k_bytes_allocated[] = "bytes_allocated";
+static const char __pyx_k_expected_length[] = "expected_length";
+static const char __pyx_k_must_be_1_3_or_4[] = "', must be 1, 3 or 4";
+static const char __pyx_k_samples_per_pixel[] = "samples_per_pixel";
+static const char __pyx_k_Invalid_rows_value[] = "Invalid 'rows' value '";
 static const char __pyx_k_asyncio_coroutines[] = "asyncio.coroutines";
 static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback";
 static const char __pyx_k_compression_ratios[] = "compression_ratios";
 static const char __pyx_k_signal_noise_ratios[] = "signal_noise_ratios";
+static const char __pyx_k_The_length_of_src_is[] = "The length of 'src' is ";
+static const char __pyx_k_Invalid_columns_value[] = "Invalid 'columns' value '";
+static const char __pyx_k_Invalid_use_mct_value[] = "Invalid 'use_mct' value '";
 static const char __pyx_k_A_bits_stored_value_of[] = "A 'bits_stored' value of ";
 static const char __pyx_k_failed_to_decode_image[] = "failed to decode image";
 static const char __pyx_k_openjpeg__openjpeg_pyx[] = "openjpeg/_openjpeg.pyx";
+static const char __pyx_k_Invalid_is_signed_value[] = "Invalid 'is_signed' value '";
+static const char __pyx_k_must_be_in_the_range_0_5[] = "', must be in the range [0, 5]";
+static const char __pyx_k_Invalid_bits_stored_value[] = "Invalid 'bits_stored' value '";
 static const char __pyx_k_failed_to_read_the_header[] = "failed to read the header";
+static const char __pyx_k_must_be_in_the_range_1_24[] = "', must be in the range [1, 24]";
+static const char __pyx_k_Invalid_codec_format_value[] = "Invalid 'codec_format' value '";
 static const char __pyx_k_Union_np_ndarray_bytearray[] = "Union[np.ndarray, bytearray]";
 static const char __pyx_k_photometric_interpretation[] = "photometric_interpretation";
 static const char __pyx_k_Dict_str_Union_str_int_bool[] = "Dict[str, Union[str, int, bool]]";
 static const char __pyx_k_Error_decoding_the_J2K_data[] = "Error decoding the J2K data";
 static const char __pyx_k_failed_to_setup_the_decoder[] = "failed to setup the decoder";
+static const char __pyx_k_must_be_in_the_range_1_65535[] = "', must be in the range [1, 65535]";
 static const char __pyx_k_failed_to_set_the_decoded_area[] = "failed to set the decoded area";
 static const char __pyx_k_is_incompatible_with_the_range[] = " is incompatible with the range of pixel data in the input array: (";
+static const char __pyx_k_src_must_be_bytes_or_bytearray[] = "'src' must be bytes or bytearray, not ";
+static const char __pyx_k_Invalid_samples_per_pixel_value[] = "Invalid 'samples_per_pixel' value '";
 static const char __pyx_k_More_than_10_compression_layers[] = "More than 10 compression layers is not supported";
 static const char __pyx_k_The_input_array_contains_values[] = "The input array contains values outside the range of the maximum supported bit-depth of 24";
+static const char __pyx_k_bytes_which_doesn_t_match_the_e[] = " bytes which doesn't match the expected length of ";
 static const char __pyx_k_numpy_core_multiarray_failed_to[] = "numpy.core.multiarray failed to import";
 static const char __pyx_k_only_bool_u1_u2_u4_i1_i2_and_i4[] = "', only bool, u1, u2, u4, i1, i2 and i4 are supported";
+static const char __pyx_k_Invalid_photometric_interpretati[] = "Invalid 'photometric_interpretation' value '";
 static const char __pyx_k_Invalid_value_for_the_bits_store[] = "Invalid value for the 'bits_stored' parameter, the value must be in the range (1, ";
 static const char __pyx_k_Only_one_of_compression_ratios_o[] = "Only one of 'compression_ratios' or 'signal_noise_ratios' is allowed when performing lossy compression";
 static const char __pyx_k_The_input_array_has_an_unsupport[] = "The input array has an unsupported dtype '";
-static const char __pyx_k_The_value_of_the_codec_format_pa[] = "The value of the 'codec_format' parameter is invalid, must be 0 or 2";
 static const char __pyx_k_failed_to_create_the_input_strea[] = "failed to create the input stream";
 static const char __pyx_k_failed_to_set_the_component_indi[] = "failed to set the component indices";
 static const char __pyx_k_failed_to_upscale_subsampled_com[] = "failed to upscale subsampled components";
 static const char __pyx_k_numpy_core_umath_failed_to_impor[] = "numpy.core.umath failed to import";
-static const char __pyx_k_support_for_more_than_16_bits_pe[] = "support for more than 16-bits per component is not implemented";
+static const char __pyx_k_support_for_more_than_32_bits_pe[] = "support for more than 32-bits per component is not implemented";
 /* #### Code section: decls ### */
 static PyObject *__pyx_pf_9_openjpeg_get_version(CYTHON_UNUSED PyObject *__pyx_self); /* proto */
-static PyObject *__pyx_pf_9_openjpeg_8__defaults__(CYTHON_UNUSED PyObject *__pyx_self); /* proto */
-static PyObject *__pyx_pf_9_openjpeg_2decode(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_fp, PyObject *__pyx_v_codec, PyObject *__pyx_v_as_array); /* proto */
 static PyObject *__pyx_pf_9_openjpeg_10__defaults__(CYTHON_UNUSED PyObject *__pyx_self); /* proto */
+static PyObject *__pyx_pf_9_openjpeg_2decode(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_fp, PyObject *__pyx_v_codec, PyObject *__pyx_v_as_array); /* proto */
+static PyObject *__pyx_pf_9_openjpeg_12__defaults__(CYTHON_UNUSED PyObject *__pyx_self); /* proto */
 static PyObject *__pyx_pf_9_openjpeg_4get_parameters(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_fp, PyObject *__pyx_v_codec); /* proto */
-static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self, PyArrayObject *__pyx_v_arr, int __pyx_v_bits_stored, int __pyx_v_photometric_interpretation, int __pyx_v_use_mct, PyObject *__pyx_v_compression_ratios, PyObject *__pyx_v_signal_noise_ratios, int __pyx_v_codec_format); /* proto */
+static PyObject *__pyx_pf_9_openjpeg_6encode_array(CYTHON_UNUSED PyObject *__pyx_self, PyArrayObject *__pyx_v_arr, int __pyx_v_bits_stored, int __pyx_v_photometric_interpretation, int __pyx_v_use_mct, PyObject *__pyx_v_compression_ratios, PyObject *__pyx_v_signal_noise_ratios, int __pyx_v_codec_format); /* proto */
+static PyObject *__pyx_pf_9_openjpeg_8encode_buffer(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_src, int __pyx_v_columns, int __pyx_v_rows, int __pyx_v_samples_per_pixel, int __pyx_v_bits_stored, int __pyx_v_is_signed, int __pyx_v_photometric_interpretation, int __pyx_v_use_mct, PyObject *__pyx_v_compression_ratios, PyObject *__pyx_v_signal_noise_ratios, int __pyx_v_codec_format); /* proto */
 /* #### Code section: late_includes ### */
 /* #### Code section: module_state ### */
 typedef struct {
@@ -3089,6 +3106,14 @@ typedef struct {
   PyObject *__pyx_n_s_ERRORS;
   PyObject *__pyx_kp_u_Error_decoding_the_J2K_data;
   PyObject *__pyx_n_s_ImportError;
+  PyObject *__pyx_kp_u_Invalid_bits_stored_value;
+  PyObject *__pyx_kp_u_Invalid_codec_format_value;
+  PyObject *__pyx_kp_u_Invalid_columns_value;
+  PyObject *__pyx_kp_u_Invalid_is_signed_value;
+  PyObject *__pyx_kp_u_Invalid_photometric_interpretati;
+  PyObject *__pyx_kp_u_Invalid_rows_value;
+  PyObject *__pyx_kp_u_Invalid_samples_per_pixel_value;
+  PyObject *__pyx_kp_u_Invalid_use_mct_value;
   PyObject *__pyx_kp_u_Invalid_value_for_the_bits_store;
   PyObject *__pyx_n_s_KeyError;
   PyObject *__pyx_n_s_LOGGER;
@@ -3098,19 +3123,22 @@ typedef struct {
   PyObject *__pyx_n_s_RuntimeError;
   PyObject *__pyx_kp_u_The_input_array_contains_values;
   PyObject *__pyx_kp_u_The_input_array_has_an_unsupport;
-  PyObject *__pyx_kp_u_The_value_of_the_codec_format_pa;
+  PyObject *__pyx_kp_u_The_length_of_src_is;
   PyObject *__pyx_n_s_Tuple;
   PyObject *__pyx_kp_s_Tuple_int_bytes;
+  PyObject *__pyx_n_s_TypeError;
   PyObject *__pyx_n_s_Union;
   PyObject *__pyx_kp_s_Union_np_ndarray_bytearray;
   PyObject *__pyx_n_s_ValueError;
   PyObject *__pyx_n_u_YUV;
   PyObject *__pyx_kp_u__10;
   PyObject *__pyx_n_s__11;
-  PyObject *__pyx_n_s__20;
+  PyObject *__pyx_n_s__22;
   PyObject *__pyx_kp_u__3;
   PyObject *__pyx_kp_u__4;
   PyObject *__pyx_kp_u__6;
+  PyObject *__pyx_kp_u__9;
+  PyObject *__pyx_n_s_actual_length;
   PyObject *__pyx_n_s_allowed;
   PyObject *__pyx_n_s_arr;
   PyObject *__pyx_n_s_arr_max;
@@ -3120,7 +3148,10 @@ typedef struct {
   PyObject *__pyx_n_s_bits_stored;
   PyObject *__pyx_n_s_bool;
   PyObject *__pyx_n_s_bpp;
-  PyObject *__pyx_n_s_bytes;
+  PyObject *__pyx_kp_u_bytes;
+  PyObject *__pyx_n_s_bytes_2;
+  PyObject *__pyx_n_s_bytes_allocated;
+  PyObject *__pyx_kp_u_bytes_which_doesn_t_match_the_e;
   PyObject *__pyx_n_s_ceil;
   PyObject *__pyx_n_s_cline_in_traceback;
   PyObject *__pyx_n_s_codec;
@@ -3128,13 +3159,16 @@ typedef struct {
   PyObject *__pyx_n_s_colours;
   PyObject *__pyx_n_s_colourspace;
   PyObject *__pyx_n_u_colourspace;
+  PyObject *__pyx_n_s_columns;
   PyObject *__pyx_n_u_columns;
   PyObject *__pyx_n_s_compression_ratios;
   PyObject *__pyx_n_s_decode;
   PyObject *__pyx_n_s_dst;
   PyObject *__pyx_n_s_dtype;
   PyObject *__pyx_kp_u_e_YCC;
-  PyObject *__pyx_n_s_encode;
+  PyObject *__pyx_n_s_encode_array;
+  PyObject *__pyx_n_s_encode_buffer;
+  PyObject *__pyx_n_s_expected_length;
   PyObject *__pyx_kp_u_failed_to_create_the_input_strea;
   PyObject *__pyx_kp_u_failed_to_decode_image;
   PyObject *__pyx_kp_u_failed_to_read_the_header;
@@ -3156,6 +3190,7 @@ typedef struct {
   PyObject *__pyx_n_s_io;
   PyObject *__pyx_n_s_is_coroutine;
   PyObject *__pyx_kp_u_is_incompatible_with_the_range;
+  PyObject *__pyx_n_s_is_signed;
   PyObject *__pyx_n_u_is_signed;
   PyObject *__pyx_n_s_itemsize;
   PyObject *__pyx_n_s_logging;
@@ -3165,10 +3200,14 @@ typedef struct {
   PyObject *__pyx_n_s_min;
   PyObject *__pyx_n_u_monochrome;
   PyObject *__pyx_n_s_msg;
+  PyObject *__pyx_kp_u_must_be_0_or_1;
+  PyObject *__pyx_kp_u_must_be_1_3_or_4;
+  PyObject *__pyx_kp_u_must_be_in_the_range_0_5;
+  PyObject *__pyx_kp_u_must_be_in_the_range_1_24;
+  PyObject *__pyx_kp_u_must_be_in_the_range_1_65535;
   PyObject *__pyx_n_s_name;
   PyObject *__pyx_n_s_np;
   PyObject *__pyx_n_s_nr_bytes;
-  PyObject *__pyx_n_u_nr_components;
   PyObject *__pyx_n_u_nr_tiles;
   PyObject *__pyx_n_s_numpy;
   PyObject *__pyx_kp_u_numpy_core_multiarray_failed_to;
@@ -3188,11 +3227,16 @@ typedef struct {
   PyObject *__pyx_n_s_result;
   PyObject *__pyx_n_s_return;
   PyObject *__pyx_n_s_return_code;
+  PyObject *__pyx_n_s_rows;
   PyObject *__pyx_n_u_rows;
   PyObject *__pyx_n_u_sRGB;
+  PyObject *__pyx_n_s_samples_per_pixel;
+  PyObject *__pyx_n_u_samples_per_pixel;
   PyObject *__pyx_n_s_signal_noise_ratios;
   PyObject *__pyx_n_s_spec;
-  PyObject *__pyx_kp_u_support_for_more_than_16_bits_pe;
+  PyObject *__pyx_n_s_src;
+  PyObject *__pyx_kp_u_src_must_be_bytes_or_bytearray;
+  PyObject *__pyx_kp_u_support_for_more_than_32_bits_pe;
   PyObject *__pyx_n_s_test;
   PyObject *__pyx_n_s_typing;
   PyObject *__pyx_n_s_uint16;
@@ -3222,15 +3266,16 @@ typedef struct {
   PyObject *__pyx_tuple__5;
   PyObject *__pyx_tuple__7;
   PyObject *__pyx_tuple__8;
-  PyObject *__pyx_tuple__9;
   PyObject *__pyx_tuple__12;
   PyObject *__pyx_tuple__14;
   PyObject *__pyx_tuple__16;
   PyObject *__pyx_tuple__18;
+  PyObject *__pyx_tuple__20;
   PyObject *__pyx_codeobj__13;
   PyObject *__pyx_codeobj__15;
   PyObject *__pyx_codeobj__17;
   PyObject *__pyx_codeobj__19;
+  PyObject *__pyx_codeobj__21;
 } __pyx_mstate;
 
 #if CYTHON_USE_MODULE_STATE
@@ -3298,6 +3343,14 @@ static int __pyx_m_clear(PyObject *m) {
   Py_CLEAR(clear_module_state->__pyx_n_s_ERRORS);
   Py_CLEAR(clear_module_state->__pyx_kp_u_Error_decoding_the_J2K_data);
   Py_CLEAR(clear_module_state->__pyx_n_s_ImportError);
+  Py_CLEAR(clear_module_state->__pyx_kp_u_Invalid_bits_stored_value);
+  Py_CLEAR(clear_module_state->__pyx_kp_u_Invalid_codec_format_value);
+  Py_CLEAR(clear_module_state->__pyx_kp_u_Invalid_columns_value);
+  Py_CLEAR(clear_module_state->__pyx_kp_u_Invalid_is_signed_value);
+  Py_CLEAR(clear_module_state->__pyx_kp_u_Invalid_photometric_interpretati);
+  Py_CLEAR(clear_module_state->__pyx_kp_u_Invalid_rows_value);
+  Py_CLEAR(clear_module_state->__pyx_kp_u_Invalid_samples_per_pixel_value);
+  Py_CLEAR(clear_module_state->__pyx_kp_u_Invalid_use_mct_value);
   Py_CLEAR(clear_module_state->__pyx_kp_u_Invalid_value_for_the_bits_store);
   Py_CLEAR(clear_module_state->__pyx_n_s_KeyError);
   Py_CLEAR(clear_module_state->__pyx_n_s_LOGGER);
@@ -3307,19 +3360,22 @@ static int __pyx_m_clear(PyObject *m) {
   Py_CLEAR(clear_module_state->__pyx_n_s_RuntimeError);
   Py_CLEAR(clear_module_state->__pyx_kp_u_The_input_array_contains_values);
   Py_CLEAR(clear_module_state->__pyx_kp_u_The_input_array_has_an_unsupport);
-  Py_CLEAR(clear_module_state->__pyx_kp_u_The_value_of_the_codec_format_pa);
+  Py_CLEAR(clear_module_state->__pyx_kp_u_The_length_of_src_is);
   Py_CLEAR(clear_module_state->__pyx_n_s_Tuple);
   Py_CLEAR(clear_module_state->__pyx_kp_s_Tuple_int_bytes);
+  Py_CLEAR(clear_module_state->__pyx_n_s_TypeError);
   Py_CLEAR(clear_module_state->__pyx_n_s_Union);
   Py_CLEAR(clear_module_state->__pyx_kp_s_Union_np_ndarray_bytearray);
   Py_CLEAR(clear_module_state->__pyx_n_s_ValueError);
   Py_CLEAR(clear_module_state->__pyx_n_u_YUV);
   Py_CLEAR(clear_module_state->__pyx_kp_u__10);
   Py_CLEAR(clear_module_state->__pyx_n_s__11);
-  Py_CLEAR(clear_module_state->__pyx_n_s__20);
+  Py_CLEAR(clear_module_state->__pyx_n_s__22);
   Py_CLEAR(clear_module_state->__pyx_kp_u__3);
   Py_CLEAR(clear_module_state->__pyx_kp_u__4);
   Py_CLEAR(clear_module_state->__pyx_kp_u__6);
+  Py_CLEAR(clear_module_state->__pyx_kp_u__9);
+  Py_CLEAR(clear_module_state->__pyx_n_s_actual_length);
   Py_CLEAR(clear_module_state->__pyx_n_s_allowed);
   Py_CLEAR(clear_module_state->__pyx_n_s_arr);
   Py_CLEAR(clear_module_state->__pyx_n_s_arr_max);
@@ -3329,7 +3385,10 @@ static int __pyx_m_clear(PyObject *m) {
   Py_CLEAR(clear_module_state->__pyx_n_s_bits_stored);
   Py_CLEAR(clear_module_state->__pyx_n_s_bool);
   Py_CLEAR(clear_module_state->__pyx_n_s_bpp);
-  Py_CLEAR(clear_module_state->__pyx_n_s_bytes);
+  Py_CLEAR(clear_module_state->__pyx_kp_u_bytes);
+  Py_CLEAR(clear_module_state->__pyx_n_s_bytes_2);
+  Py_CLEAR(clear_module_state->__pyx_n_s_bytes_allocated);
+  Py_CLEAR(clear_module_state->__pyx_kp_u_bytes_which_doesn_t_match_the_e);
   Py_CLEAR(clear_module_state->__pyx_n_s_ceil);
   Py_CLEAR(clear_module_state->__pyx_n_s_cline_in_traceback);
   Py_CLEAR(clear_module_state->__pyx_n_s_codec);
@@ -3337,13 +3396,16 @@ static int __pyx_m_clear(PyObject *m) {
   Py_CLEAR(clear_module_state->__pyx_n_s_colours);
   Py_CLEAR(clear_module_state->__pyx_n_s_colourspace);
   Py_CLEAR(clear_module_state->__pyx_n_u_colourspace);
+  Py_CLEAR(clear_module_state->__pyx_n_s_columns);
   Py_CLEAR(clear_module_state->__pyx_n_u_columns);
   Py_CLEAR(clear_module_state->__pyx_n_s_compression_ratios);
   Py_CLEAR(clear_module_state->__pyx_n_s_decode);
   Py_CLEAR(clear_module_state->__pyx_n_s_dst);
   Py_CLEAR(clear_module_state->__pyx_n_s_dtype);
   Py_CLEAR(clear_module_state->__pyx_kp_u_e_YCC);
-  Py_CLEAR(clear_module_state->__pyx_n_s_encode);
+  Py_CLEAR(clear_module_state->__pyx_n_s_encode_array);
+  Py_CLEAR(clear_module_state->__pyx_n_s_encode_buffer);
+  Py_CLEAR(clear_module_state->__pyx_n_s_expected_length);
   Py_CLEAR(clear_module_state->__pyx_kp_u_failed_to_create_the_input_strea);
   Py_CLEAR(clear_module_state->__pyx_kp_u_failed_to_decode_image);
   Py_CLEAR(clear_module_state->__pyx_kp_u_failed_to_read_the_header);
@@ -3365,6 +3427,7 @@ static int __pyx_m_clear(PyObject *m) {
   Py_CLEAR(clear_module_state->__pyx_n_s_io);
   Py_CLEAR(clear_module_state->__pyx_n_s_is_coroutine);
   Py_CLEAR(clear_module_state->__pyx_kp_u_is_incompatible_with_the_range);
+  Py_CLEAR(clear_module_state->__pyx_n_s_is_signed);
   Py_CLEAR(clear_module_state->__pyx_n_u_is_signed);
   Py_CLEAR(clear_module_state->__pyx_n_s_itemsize);
   Py_CLEAR(clear_module_state->__pyx_n_s_logging);
@@ -3374,10 +3437,14 @@ static int __pyx_m_clear(PyObject *m) {
   Py_CLEAR(clear_module_state->__pyx_n_s_min);
   Py_CLEAR(clear_module_state->__pyx_n_u_monochrome);
   Py_CLEAR(clear_module_state->__pyx_n_s_msg);
+  Py_CLEAR(clear_module_state->__pyx_kp_u_must_be_0_or_1);
+  Py_CLEAR(clear_module_state->__pyx_kp_u_must_be_1_3_or_4);
+  Py_CLEAR(clear_module_state->__pyx_kp_u_must_be_in_the_range_0_5);
+  Py_CLEAR(clear_module_state->__pyx_kp_u_must_be_in_the_range_1_24);
+  Py_CLEAR(clear_module_state->__pyx_kp_u_must_be_in_the_range_1_65535);
   Py_CLEAR(clear_module_state->__pyx_n_s_name);
   Py_CLEAR(clear_module_state->__pyx_n_s_np);
   Py_CLEAR(clear_module_state->__pyx_n_s_nr_bytes);
-  Py_CLEAR(clear_module_state->__pyx_n_u_nr_components);
   Py_CLEAR(clear_module_state->__pyx_n_u_nr_tiles);
   Py_CLEAR(clear_module_state->__pyx_n_s_numpy);
   Py_CLEAR(clear_module_state->__pyx_kp_u_numpy_core_multiarray_failed_to);
@@ -3397,11 +3464,16 @@ static int __pyx_m_clear(PyObject *m) {
   Py_CLEAR(clear_module_state->__pyx_n_s_result);
   Py_CLEAR(clear_module_state->__pyx_n_s_return);
   Py_CLEAR(clear_module_state->__pyx_n_s_return_code);
+  Py_CLEAR(clear_module_state->__pyx_n_s_rows);
   Py_CLEAR(clear_module_state->__pyx_n_u_rows);
   Py_CLEAR(clear_module_state->__pyx_n_u_sRGB);
+  Py_CLEAR(clear_module_state->__pyx_n_s_samples_per_pixel);
+  Py_CLEAR(clear_module_state->__pyx_n_u_samples_per_pixel);
   Py_CLEAR(clear_module_state->__pyx_n_s_signal_noise_ratios);
   Py_CLEAR(clear_module_state->__pyx_n_s_spec);
-  Py_CLEAR(clear_module_state->__pyx_kp_u_support_for_more_than_16_bits_pe);
+  Py_CLEAR(clear_module_state->__pyx_n_s_src);
+  Py_CLEAR(clear_module_state->__pyx_kp_u_src_must_be_bytes_or_bytearray);
+  Py_CLEAR(clear_module_state->__pyx_kp_u_support_for_more_than_32_bits_pe);
   Py_CLEAR(clear_module_state->__pyx_n_s_test);
   Py_CLEAR(clear_module_state->__pyx_n_s_typing);
   Py_CLEAR(clear_module_state->__pyx_n_s_uint16);
@@ -3431,15 +3503,16 @@ static int __pyx_m_clear(PyObject *m) {
   Py_CLEAR(clear_module_state->__pyx_tuple__5);
   Py_CLEAR(clear_module_state->__pyx_tuple__7);
   Py_CLEAR(clear_module_state->__pyx_tuple__8);
-  Py_CLEAR(clear_module_state->__pyx_tuple__9);
   Py_CLEAR(clear_module_state->__pyx_tuple__12);
   Py_CLEAR(clear_module_state->__pyx_tuple__14);
   Py_CLEAR(clear_module_state->__pyx_tuple__16);
   Py_CLEAR(clear_module_state->__pyx_tuple__18);
+  Py_CLEAR(clear_module_state->__pyx_tuple__20);
   Py_CLEAR(clear_module_state->__pyx_codeobj__13);
   Py_CLEAR(clear_module_state->__pyx_codeobj__15);
   Py_CLEAR(clear_module_state->__pyx_codeobj__17);
   Py_CLEAR(clear_module_state->__pyx_codeobj__19);
+  Py_CLEAR(clear_module_state->__pyx_codeobj__21);
   return 0;
 }
 #endif
@@ -3485,6 +3558,14 @@ static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) {
   Py_VISIT(traverse_module_state->__pyx_n_s_ERRORS);
   Py_VISIT(traverse_module_state->__pyx_kp_u_Error_decoding_the_J2K_data);
   Py_VISIT(traverse_module_state->__pyx_n_s_ImportError);
+  Py_VISIT(traverse_module_state->__pyx_kp_u_Invalid_bits_stored_value);
+  Py_VISIT(traverse_module_state->__pyx_kp_u_Invalid_codec_format_value);
+  Py_VISIT(traverse_module_state->__pyx_kp_u_Invalid_columns_value);
+  Py_VISIT(traverse_module_state->__pyx_kp_u_Invalid_is_signed_value);
+  Py_VISIT(traverse_module_state->__pyx_kp_u_Invalid_photometric_interpretati);
+  Py_VISIT(traverse_module_state->__pyx_kp_u_Invalid_rows_value);
+  Py_VISIT(traverse_module_state->__pyx_kp_u_Invalid_samples_per_pixel_value);
+  Py_VISIT(traverse_module_state->__pyx_kp_u_Invalid_use_mct_value);
   Py_VISIT(traverse_module_state->__pyx_kp_u_Invalid_value_for_the_bits_store);
   Py_VISIT(traverse_module_state->__pyx_n_s_KeyError);
   Py_VISIT(traverse_module_state->__pyx_n_s_LOGGER);
@@ -3494,19 +3575,22 @@ static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) {
   Py_VISIT(traverse_module_state->__pyx_n_s_RuntimeError);
   Py_VISIT(traverse_module_state->__pyx_kp_u_The_input_array_contains_values);
   Py_VISIT(traverse_module_state->__pyx_kp_u_The_input_array_has_an_unsupport);
-  Py_VISIT(traverse_module_state->__pyx_kp_u_The_value_of_the_codec_format_pa);
+  Py_VISIT(traverse_module_state->__pyx_kp_u_The_length_of_src_is);
   Py_VISIT(traverse_module_state->__pyx_n_s_Tuple);
   Py_VISIT(traverse_module_state->__pyx_kp_s_Tuple_int_bytes);
+  Py_VISIT(traverse_module_state->__pyx_n_s_TypeError);
   Py_VISIT(traverse_module_state->__pyx_n_s_Union);
   Py_VISIT(traverse_module_state->__pyx_kp_s_Union_np_ndarray_bytearray);
   Py_VISIT(traverse_module_state->__pyx_n_s_ValueError);
   Py_VISIT(traverse_module_state->__pyx_n_u_YUV);
   Py_VISIT(traverse_module_state->__pyx_kp_u__10);
   Py_VISIT(traverse_module_state->__pyx_n_s__11);
-  Py_VISIT(traverse_module_state->__pyx_n_s__20);
+  Py_VISIT(traverse_module_state->__pyx_n_s__22);
   Py_VISIT(traverse_module_state->__pyx_kp_u__3);
   Py_VISIT(traverse_module_state->__pyx_kp_u__4);
   Py_VISIT(traverse_module_state->__pyx_kp_u__6);
+  Py_VISIT(traverse_module_state->__pyx_kp_u__9);
+  Py_VISIT(traverse_module_state->__pyx_n_s_actual_length);
   Py_VISIT(traverse_module_state->__pyx_n_s_allowed);
   Py_VISIT(traverse_module_state->__pyx_n_s_arr);
   Py_VISIT(traverse_module_state->__pyx_n_s_arr_max);
@@ -3516,7 +3600,10 @@ static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) {
   Py_VISIT(traverse_module_state->__pyx_n_s_bits_stored);
   Py_VISIT(traverse_module_state->__pyx_n_s_bool);
   Py_VISIT(traverse_module_state->__pyx_n_s_bpp);
-  Py_VISIT(traverse_module_state->__pyx_n_s_bytes);
+  Py_VISIT(traverse_module_state->__pyx_kp_u_bytes);
+  Py_VISIT(traverse_module_state->__pyx_n_s_bytes_2);
+  Py_VISIT(traverse_module_state->__pyx_n_s_bytes_allocated);
+  Py_VISIT(traverse_module_state->__pyx_kp_u_bytes_which_doesn_t_match_the_e);
   Py_VISIT(traverse_module_state->__pyx_n_s_ceil);
   Py_VISIT(traverse_module_state->__pyx_n_s_cline_in_traceback);
   Py_VISIT(traverse_module_state->__pyx_n_s_codec);
@@ -3524,13 +3611,16 @@ static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) {
   Py_VISIT(traverse_module_state->__pyx_n_s_colours);
   Py_VISIT(traverse_module_state->__pyx_n_s_colourspace);
   Py_VISIT(traverse_module_state->__pyx_n_u_colourspace);
+  Py_VISIT(traverse_module_state->__pyx_n_s_columns);
   Py_VISIT(traverse_module_state->__pyx_n_u_columns);
   Py_VISIT(traverse_module_state->__pyx_n_s_compression_ratios);
   Py_VISIT(traverse_module_state->__pyx_n_s_decode);
   Py_VISIT(traverse_module_state->__pyx_n_s_dst);
   Py_VISIT(traverse_module_state->__pyx_n_s_dtype);
   Py_VISIT(traverse_module_state->__pyx_kp_u_e_YCC);
-  Py_VISIT(traverse_module_state->__pyx_n_s_encode);
+  Py_VISIT(traverse_module_state->__pyx_n_s_encode_array);
+  Py_VISIT(traverse_module_state->__pyx_n_s_encode_buffer);
+  Py_VISIT(traverse_module_state->__pyx_n_s_expected_length);
   Py_VISIT(traverse_module_state->__pyx_kp_u_failed_to_create_the_input_strea);
   Py_VISIT(traverse_module_state->__pyx_kp_u_failed_to_decode_image);
   Py_VISIT(traverse_module_state->__pyx_kp_u_failed_to_read_the_header);
@@ -3552,6 +3642,7 @@ static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) {
   Py_VISIT(traverse_module_state->__pyx_n_s_io);
   Py_VISIT(traverse_module_state->__pyx_n_s_is_coroutine);
   Py_VISIT(traverse_module_state->__pyx_kp_u_is_incompatible_with_the_range);
+  Py_VISIT(traverse_module_state->__pyx_n_s_is_signed);
   Py_VISIT(traverse_module_state->__pyx_n_u_is_signed);
   Py_VISIT(traverse_module_state->__pyx_n_s_itemsize);
   Py_VISIT(traverse_module_state->__pyx_n_s_logging);
@@ -3561,10 +3652,14 @@ static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) {
   Py_VISIT(traverse_module_state->__pyx_n_s_min);
   Py_VISIT(traverse_module_state->__pyx_n_u_monochrome);
   Py_VISIT(traverse_module_state->__pyx_n_s_msg);
+  Py_VISIT(traverse_module_state->__pyx_kp_u_must_be_0_or_1);
+  Py_VISIT(traverse_module_state->__pyx_kp_u_must_be_1_3_or_4);
+  Py_VISIT(traverse_module_state->__pyx_kp_u_must_be_in_the_range_0_5);
+  Py_VISIT(traverse_module_state->__pyx_kp_u_must_be_in_the_range_1_24);
+  Py_VISIT(traverse_module_state->__pyx_kp_u_must_be_in_the_range_1_65535);
   Py_VISIT(traverse_module_state->__pyx_n_s_name);
   Py_VISIT(traverse_module_state->__pyx_n_s_np);
   Py_VISIT(traverse_module_state->__pyx_n_s_nr_bytes);
-  Py_VISIT(traverse_module_state->__pyx_n_u_nr_components);
   Py_VISIT(traverse_module_state->__pyx_n_u_nr_tiles);
   Py_VISIT(traverse_module_state->__pyx_n_s_numpy);
   Py_VISIT(traverse_module_state->__pyx_kp_u_numpy_core_multiarray_failed_to);
@@ -3584,11 +3679,16 @@ static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) {
   Py_VISIT(traverse_module_state->__pyx_n_s_result);
   Py_VISIT(traverse_module_state->__pyx_n_s_return);
   Py_VISIT(traverse_module_state->__pyx_n_s_return_code);
+  Py_VISIT(traverse_module_state->__pyx_n_s_rows);
   Py_VISIT(traverse_module_state->__pyx_n_u_rows);
   Py_VISIT(traverse_module_state->__pyx_n_u_sRGB);
+  Py_VISIT(traverse_module_state->__pyx_n_s_samples_per_pixel);
+  Py_VISIT(traverse_module_state->__pyx_n_u_samples_per_pixel);
   Py_VISIT(traverse_module_state->__pyx_n_s_signal_noise_ratios);
   Py_VISIT(traverse_module_state->__pyx_n_s_spec);
-  Py_VISIT(traverse_module_state->__pyx_kp_u_support_for_more_than_16_bits_pe);
+  Py_VISIT(traverse_module_state->__pyx_n_s_src);
+  Py_VISIT(traverse_module_state->__pyx_kp_u_src_must_be_bytes_or_bytearray);
+  Py_VISIT(traverse_module_state->__pyx_kp_u_support_for_more_than_32_bits_pe);
   Py_VISIT(traverse_module_state->__pyx_n_s_test);
   Py_VISIT(traverse_module_state->__pyx_n_s_typing);
   Py_VISIT(traverse_module_state->__pyx_n_s_uint16);
@@ -3618,15 +3718,16 @@ static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) {
   Py_VISIT(traverse_module_state->__pyx_tuple__5);
   Py_VISIT(traverse_module_state->__pyx_tuple__7);
   Py_VISIT(traverse_module_state->__pyx_tuple__8);
-  Py_VISIT(traverse_module_state->__pyx_tuple__9);
   Py_VISIT(traverse_module_state->__pyx_tuple__12);
   Py_VISIT(traverse_module_state->__pyx_tuple__14);
   Py_VISIT(traverse_module_state->__pyx_tuple__16);
   Py_VISIT(traverse_module_state->__pyx_tuple__18);
+  Py_VISIT(traverse_module_state->__pyx_tuple__20);
   Py_VISIT(traverse_module_state->__pyx_codeobj__13);
   Py_VISIT(traverse_module_state->__pyx_codeobj__15);
   Py_VISIT(traverse_module_state->__pyx_codeobj__17);
   Py_VISIT(traverse_module_state->__pyx_codeobj__19);
+  Py_VISIT(traverse_module_state->__pyx_codeobj__21);
   return 0;
 }
 #endif
@@ -3702,6 +3803,14 @@ static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) {
 #define __pyx_n_s_ERRORS __pyx_mstate_global->__pyx_n_s_ERRORS
 #define __pyx_kp_u_Error_decoding_the_J2K_data __pyx_mstate_global->__pyx_kp_u_Error_decoding_the_J2K_data
 #define __pyx_n_s_ImportError __pyx_mstate_global->__pyx_n_s_ImportError
+#define __pyx_kp_u_Invalid_bits_stored_value __pyx_mstate_global->__pyx_kp_u_Invalid_bits_stored_value
+#define __pyx_kp_u_Invalid_codec_format_value __pyx_mstate_global->__pyx_kp_u_Invalid_codec_format_value
+#define __pyx_kp_u_Invalid_columns_value __pyx_mstate_global->__pyx_kp_u_Invalid_columns_value
+#define __pyx_kp_u_Invalid_is_signed_value __pyx_mstate_global->__pyx_kp_u_Invalid_is_signed_value
+#define __pyx_kp_u_Invalid_photometric_interpretati __pyx_mstate_global->__pyx_kp_u_Invalid_photometric_interpretati
+#define __pyx_kp_u_Invalid_rows_value __pyx_mstate_global->__pyx_kp_u_Invalid_rows_value
+#define __pyx_kp_u_Invalid_samples_per_pixel_value __pyx_mstate_global->__pyx_kp_u_Invalid_samples_per_pixel_value
+#define __pyx_kp_u_Invalid_use_mct_value __pyx_mstate_global->__pyx_kp_u_Invalid_use_mct_value
 #define __pyx_kp_u_Invalid_value_for_the_bits_store __pyx_mstate_global->__pyx_kp_u_Invalid_value_for_the_bits_store
 #define __pyx_n_s_KeyError __pyx_mstate_global->__pyx_n_s_KeyError
 #define __pyx_n_s_LOGGER __pyx_mstate_global->__pyx_n_s_LOGGER
@@ -3711,19 +3820,22 @@ static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) {
 #define __pyx_n_s_RuntimeError __pyx_mstate_global->__pyx_n_s_RuntimeError
 #define __pyx_kp_u_The_input_array_contains_values __pyx_mstate_global->__pyx_kp_u_The_input_array_contains_values
 #define __pyx_kp_u_The_input_array_has_an_unsupport __pyx_mstate_global->__pyx_kp_u_The_input_array_has_an_unsupport
-#define __pyx_kp_u_The_value_of_the_codec_format_pa __pyx_mstate_global->__pyx_kp_u_The_value_of_the_codec_format_pa
+#define __pyx_kp_u_The_length_of_src_is __pyx_mstate_global->__pyx_kp_u_The_length_of_src_is
 #define __pyx_n_s_Tuple __pyx_mstate_global->__pyx_n_s_Tuple
 #define __pyx_kp_s_Tuple_int_bytes __pyx_mstate_global->__pyx_kp_s_Tuple_int_bytes
+#define __pyx_n_s_TypeError __pyx_mstate_global->__pyx_n_s_TypeError
 #define __pyx_n_s_Union __pyx_mstate_global->__pyx_n_s_Union
 #define __pyx_kp_s_Union_np_ndarray_bytearray __pyx_mstate_global->__pyx_kp_s_Union_np_ndarray_bytearray
 #define __pyx_n_s_ValueError __pyx_mstate_global->__pyx_n_s_ValueError
 #define __pyx_n_u_YUV __pyx_mstate_global->__pyx_n_u_YUV
 #define __pyx_kp_u__10 __pyx_mstate_global->__pyx_kp_u__10
 #define __pyx_n_s__11 __pyx_mstate_global->__pyx_n_s__11
-#define __pyx_n_s__20 __pyx_mstate_global->__pyx_n_s__20
+#define __pyx_n_s__22 __pyx_mstate_global->__pyx_n_s__22
 #define __pyx_kp_u__3 __pyx_mstate_global->__pyx_kp_u__3
 #define __pyx_kp_u__4 __pyx_mstate_global->__pyx_kp_u__4
 #define __pyx_kp_u__6 __pyx_mstate_global->__pyx_kp_u__6
+#define __pyx_kp_u__9 __pyx_mstate_global->__pyx_kp_u__9
+#define __pyx_n_s_actual_length __pyx_mstate_global->__pyx_n_s_actual_length
 #define __pyx_n_s_allowed __pyx_mstate_global->__pyx_n_s_allowed
 #define __pyx_n_s_arr __pyx_mstate_global->__pyx_n_s_arr
 #define __pyx_n_s_arr_max __pyx_mstate_global->__pyx_n_s_arr_max
@@ -3733,7 +3845,10 @@ static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) {
 #define __pyx_n_s_bits_stored __pyx_mstate_global->__pyx_n_s_bits_stored
 #define __pyx_n_s_bool __pyx_mstate_global->__pyx_n_s_bool
 #define __pyx_n_s_bpp __pyx_mstate_global->__pyx_n_s_bpp
-#define __pyx_n_s_bytes __pyx_mstate_global->__pyx_n_s_bytes
+#define __pyx_kp_u_bytes __pyx_mstate_global->__pyx_kp_u_bytes
+#define __pyx_n_s_bytes_2 __pyx_mstate_global->__pyx_n_s_bytes_2
+#define __pyx_n_s_bytes_allocated __pyx_mstate_global->__pyx_n_s_bytes_allocated
+#define __pyx_kp_u_bytes_which_doesn_t_match_the_e __pyx_mstate_global->__pyx_kp_u_bytes_which_doesn_t_match_the_e
 #define __pyx_n_s_ceil __pyx_mstate_global->__pyx_n_s_ceil
 #define __pyx_n_s_cline_in_traceback __pyx_mstate_global->__pyx_n_s_cline_in_traceback
 #define __pyx_n_s_codec __pyx_mstate_global->__pyx_n_s_codec
@@ -3741,13 +3856,16 @@ static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) {
 #define __pyx_n_s_colours __pyx_mstate_global->__pyx_n_s_colours
 #define __pyx_n_s_colourspace __pyx_mstate_global->__pyx_n_s_colourspace
 #define __pyx_n_u_colourspace __pyx_mstate_global->__pyx_n_u_colourspace
+#define __pyx_n_s_columns __pyx_mstate_global->__pyx_n_s_columns
 #define __pyx_n_u_columns __pyx_mstate_global->__pyx_n_u_columns
 #define __pyx_n_s_compression_ratios __pyx_mstate_global->__pyx_n_s_compression_ratios
 #define __pyx_n_s_decode __pyx_mstate_global->__pyx_n_s_decode
 #define __pyx_n_s_dst __pyx_mstate_global->__pyx_n_s_dst
 #define __pyx_n_s_dtype __pyx_mstate_global->__pyx_n_s_dtype
 #define __pyx_kp_u_e_YCC __pyx_mstate_global->__pyx_kp_u_e_YCC
-#define __pyx_n_s_encode __pyx_mstate_global->__pyx_n_s_encode
+#define __pyx_n_s_encode_array __pyx_mstate_global->__pyx_n_s_encode_array
+#define __pyx_n_s_encode_buffer __pyx_mstate_global->__pyx_n_s_encode_buffer
+#define __pyx_n_s_expected_length __pyx_mstate_global->__pyx_n_s_expected_length
 #define __pyx_kp_u_failed_to_create_the_input_strea __pyx_mstate_global->__pyx_kp_u_failed_to_create_the_input_strea
 #define __pyx_kp_u_failed_to_decode_image __pyx_mstate_global->__pyx_kp_u_failed_to_decode_image
 #define __pyx_kp_u_failed_to_read_the_header __pyx_mstate_global->__pyx_kp_u_failed_to_read_the_header
@@ -3769,6 +3887,7 @@ static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) {
 #define __pyx_n_s_io __pyx_mstate_global->__pyx_n_s_io
 #define __pyx_n_s_is_coroutine __pyx_mstate_global->__pyx_n_s_is_coroutine
 #define __pyx_kp_u_is_incompatible_with_the_range __pyx_mstate_global->__pyx_kp_u_is_incompatible_with_the_range
+#define __pyx_n_s_is_signed __pyx_mstate_global->__pyx_n_s_is_signed
 #define __pyx_n_u_is_signed __pyx_mstate_global->__pyx_n_u_is_signed
 #define __pyx_n_s_itemsize __pyx_mstate_global->__pyx_n_s_itemsize
 #define __pyx_n_s_logging __pyx_mstate_global->__pyx_n_s_logging
@@ -3778,10 +3897,14 @@ static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) {
 #define __pyx_n_s_min __pyx_mstate_global->__pyx_n_s_min
 #define __pyx_n_u_monochrome __pyx_mstate_global->__pyx_n_u_monochrome
 #define __pyx_n_s_msg __pyx_mstate_global->__pyx_n_s_msg
+#define __pyx_kp_u_must_be_0_or_1 __pyx_mstate_global->__pyx_kp_u_must_be_0_or_1
+#define __pyx_kp_u_must_be_1_3_or_4 __pyx_mstate_global->__pyx_kp_u_must_be_1_3_or_4
+#define __pyx_kp_u_must_be_in_the_range_0_5 __pyx_mstate_global->__pyx_kp_u_must_be_in_the_range_0_5
+#define __pyx_kp_u_must_be_in_the_range_1_24 __pyx_mstate_global->__pyx_kp_u_must_be_in_the_range_1_24
+#define __pyx_kp_u_must_be_in_the_range_1_65535 __pyx_mstate_global->__pyx_kp_u_must_be_in_the_range_1_65535
 #define __pyx_n_s_name __pyx_mstate_global->__pyx_n_s_name
 #define __pyx_n_s_np __pyx_mstate_global->__pyx_n_s_np
 #define __pyx_n_s_nr_bytes __pyx_mstate_global->__pyx_n_s_nr_bytes
-#define __pyx_n_u_nr_components __pyx_mstate_global->__pyx_n_u_nr_components
 #define __pyx_n_u_nr_tiles __pyx_mstate_global->__pyx_n_u_nr_tiles
 #define __pyx_n_s_numpy __pyx_mstate_global->__pyx_n_s_numpy
 #define __pyx_kp_u_numpy_core_multiarray_failed_to __pyx_mstate_global->__pyx_kp_u_numpy_core_multiarray_failed_to
@@ -3801,11 +3924,16 @@ static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) {
 #define __pyx_n_s_result __pyx_mstate_global->__pyx_n_s_result
 #define __pyx_n_s_return __pyx_mstate_global->__pyx_n_s_return
 #define __pyx_n_s_return_code __pyx_mstate_global->__pyx_n_s_return_code
+#define __pyx_n_s_rows __pyx_mstate_global->__pyx_n_s_rows
 #define __pyx_n_u_rows __pyx_mstate_global->__pyx_n_u_rows
 #define __pyx_n_u_sRGB __pyx_mstate_global->__pyx_n_u_sRGB
+#define __pyx_n_s_samples_per_pixel __pyx_mstate_global->__pyx_n_s_samples_per_pixel
+#define __pyx_n_u_samples_per_pixel __pyx_mstate_global->__pyx_n_u_samples_per_pixel
 #define __pyx_n_s_signal_noise_ratios __pyx_mstate_global->__pyx_n_s_signal_noise_ratios
 #define __pyx_n_s_spec __pyx_mstate_global->__pyx_n_s_spec
-#define __pyx_kp_u_support_for_more_than_16_bits_pe __pyx_mstate_global->__pyx_kp_u_support_for_more_than_16_bits_pe
+#define __pyx_n_s_src __pyx_mstate_global->__pyx_n_s_src
+#define __pyx_kp_u_src_must_be_bytes_or_bytearray __pyx_mstate_global->__pyx_kp_u_src_must_be_bytes_or_bytearray
+#define __pyx_kp_u_support_for_more_than_32_bits_pe __pyx_mstate_global->__pyx_kp_u_support_for_more_than_32_bits_pe
 #define __pyx_n_s_test __pyx_mstate_global->__pyx_n_s_test
 #define __pyx_n_s_typing __pyx_mstate_global->__pyx_n_s_typing
 #define __pyx_n_s_uint16 __pyx_mstate_global->__pyx_n_s_uint16
@@ -3835,18 +3963,19 @@ static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) {
 #define __pyx_tuple__5 __pyx_mstate_global->__pyx_tuple__5
 #define __pyx_tuple__7 __pyx_mstate_global->__pyx_tuple__7
 #define __pyx_tuple__8 __pyx_mstate_global->__pyx_tuple__8
-#define __pyx_tuple__9 __pyx_mstate_global->__pyx_tuple__9
 #define __pyx_tuple__12 __pyx_mstate_global->__pyx_tuple__12
 #define __pyx_tuple__14 __pyx_mstate_global->__pyx_tuple__14
 #define __pyx_tuple__16 __pyx_mstate_global->__pyx_tuple__16
 #define __pyx_tuple__18 __pyx_mstate_global->__pyx_tuple__18
+#define __pyx_tuple__20 __pyx_mstate_global->__pyx_tuple__20
 #define __pyx_codeobj__13 __pyx_mstate_global->__pyx_codeobj__13
 #define __pyx_codeobj__15 __pyx_mstate_global->__pyx_codeobj__15
 #define __pyx_codeobj__17 __pyx_mstate_global->__pyx_codeobj__17
 #define __pyx_codeobj__19 __pyx_mstate_global->__pyx_codeobj__19
+#define __pyx_codeobj__21 __pyx_mstate_global->__pyx_codeobj__21
 /* #### Code section: module_code ### */
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":245
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":245
  * 
  *         @property
  *         cdef inline PyObject* base(self) nogil:             # <<<<<<<<<<<<<<
@@ -3857,7 +3986,7 @@ static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) {
 static CYTHON_INLINE PyObject *__pyx_f_5numpy_7ndarray_4base_base(PyArrayObject *__pyx_v_self) {
   PyObject *__pyx_r;
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":248
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":248
  *             """Returns a borrowed reference to the object owning the data/memory.
  *             """
  *             return PyArray_BASE(self)             # <<<<<<<<<<<<<<
@@ -3867,7 +3996,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_7ndarray_4base_base(PyArrayObject
   __pyx_r = PyArray_BASE(__pyx_v_self);
   goto __pyx_L0;
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":245
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":245
  * 
  *         @property
  *         cdef inline PyObject* base(self) nogil:             # <<<<<<<<<<<<<<
@@ -3880,7 +4009,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_7ndarray_4base_base(PyArrayObject
   return __pyx_r;
 }
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":251
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":251
  * 
  *         @property
  *         cdef inline dtype descr(self):             # <<<<<<<<<<<<<<
@@ -3894,7 +4023,7 @@ static CYTHON_INLINE PyArray_Descr *__pyx_f_5numpy_7ndarray_5descr_descr(PyArray
   PyArray_Descr *__pyx_t_1;
   __Pyx_RefNannySetupContext("descr", 1);
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":254
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":254
  *             """Returns an owned reference to the dtype of the array.
  *             """
  *             return <dtype>PyArray_DESCR(self)             # <<<<<<<<<<<<<<
@@ -3907,7 +4036,7 @@ static CYTHON_INLINE PyArray_Descr *__pyx_f_5numpy_7ndarray_5descr_descr(PyArray
   __pyx_r = ((PyArray_Descr *)__pyx_t_1);
   goto __pyx_L0;
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":251
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":251
  * 
  *         @property
  *         cdef inline dtype descr(self):             # <<<<<<<<<<<<<<
@@ -3922,7 +4051,7 @@ static CYTHON_INLINE PyArray_Descr *__pyx_f_5numpy_7ndarray_5descr_descr(PyArray
   return __pyx_r;
 }
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":257
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":257
  * 
  *         @property
  *         cdef inline int ndim(self) nogil:             # <<<<<<<<<<<<<<
@@ -3933,7 +4062,7 @@ static CYTHON_INLINE PyArray_Descr *__pyx_f_5numpy_7ndarray_5descr_descr(PyArray
 static CYTHON_INLINE int __pyx_f_5numpy_7ndarray_4ndim_ndim(PyArrayObject *__pyx_v_self) {
   int __pyx_r;
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":260
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":260
  *             """Returns the number of dimensions in the array.
  *             """
  *             return PyArray_NDIM(self)             # <<<<<<<<<<<<<<
@@ -3943,7 +4072,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_7ndarray_4ndim_ndim(PyArrayObject *__pyx
   __pyx_r = PyArray_NDIM(__pyx_v_self);
   goto __pyx_L0;
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":257
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":257
  * 
  *         @property
  *         cdef inline int ndim(self) nogil:             # <<<<<<<<<<<<<<
@@ -3956,7 +4085,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_7ndarray_4ndim_ndim(PyArrayObject *__pyx
   return __pyx_r;
 }
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":263
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":263
  * 
  *         @property
  *         cdef inline npy_intp *shape(self) nogil:             # <<<<<<<<<<<<<<
@@ -3967,7 +4096,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_7ndarray_4ndim_ndim(PyArrayObject *__pyx
 static CYTHON_INLINE npy_intp *__pyx_f_5numpy_7ndarray_5shape_shape(PyArrayObject *__pyx_v_self) {
   npy_intp *__pyx_r;
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":268
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":268
  *             Can return NULL for 0-dimensional arrays.
  *             """
  *             return PyArray_DIMS(self)             # <<<<<<<<<<<<<<
@@ -3977,7 +4106,7 @@ static CYTHON_INLINE npy_intp *__pyx_f_5numpy_7ndarray_5shape_shape(PyArrayObjec
   __pyx_r = PyArray_DIMS(__pyx_v_self);
   goto __pyx_L0;
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":263
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":263
  * 
  *         @property
  *         cdef inline npy_intp *shape(self) nogil:             # <<<<<<<<<<<<<<
@@ -3990,7 +4119,7 @@ static CYTHON_INLINE npy_intp *__pyx_f_5numpy_7ndarray_5shape_shape(PyArrayObjec
   return __pyx_r;
 }
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":271
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":271
  * 
  *         @property
  *         cdef inline npy_intp *strides(self) nogil:             # <<<<<<<<<<<<<<
@@ -4001,7 +4130,7 @@ static CYTHON_INLINE npy_intp *__pyx_f_5numpy_7ndarray_5shape_shape(PyArrayObjec
 static CYTHON_INLINE npy_intp *__pyx_f_5numpy_7ndarray_7strides_strides(PyArrayObject *__pyx_v_self) {
   npy_intp *__pyx_r;
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":275
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":275
  *             The number of elements matches the number of dimensions of the array (ndim).
  *             """
  *             return PyArray_STRIDES(self)             # <<<<<<<<<<<<<<
@@ -4011,7 +4140,7 @@ static CYTHON_INLINE npy_intp *__pyx_f_5numpy_7ndarray_7strides_strides(PyArrayO
   __pyx_r = PyArray_STRIDES(__pyx_v_self);
   goto __pyx_L0;
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":271
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":271
  * 
  *         @property
  *         cdef inline npy_intp *strides(self) nogil:             # <<<<<<<<<<<<<<
@@ -4024,7 +4153,7 @@ static CYTHON_INLINE npy_intp *__pyx_f_5numpy_7ndarray_7strides_strides(PyArrayO
   return __pyx_r;
 }
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":278
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":278
  * 
  *         @property
  *         cdef inline npy_intp size(self) nogil:             # <<<<<<<<<<<<<<
@@ -4035,7 +4164,7 @@ static CYTHON_INLINE npy_intp *__pyx_f_5numpy_7ndarray_7strides_strides(PyArrayO
 static CYTHON_INLINE npy_intp __pyx_f_5numpy_7ndarray_4size_size(PyArrayObject *__pyx_v_self) {
   npy_intp __pyx_r;
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":281
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":281
  *             """Returns the total size (in number of elements) of the array.
  *             """
  *             return PyArray_SIZE(self)             # <<<<<<<<<<<<<<
@@ -4045,7 +4174,7 @@ static CYTHON_INLINE npy_intp __pyx_f_5numpy_7ndarray_4size_size(PyArrayObject *
   __pyx_r = PyArray_SIZE(__pyx_v_self);
   goto __pyx_L0;
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":278
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":278
  * 
  *         @property
  *         cdef inline npy_intp size(self) nogil:             # <<<<<<<<<<<<<<
@@ -4058,7 +4187,7 @@ static CYTHON_INLINE npy_intp __pyx_f_5numpy_7ndarray_4size_size(PyArrayObject *
   return __pyx_r;
 }
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":284
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":284
  * 
  *         @property
  *         cdef inline char* data(self) nogil:             # <<<<<<<<<<<<<<
@@ -4069,7 +4198,7 @@ static CYTHON_INLINE npy_intp __pyx_f_5numpy_7ndarray_4size_size(PyArrayObject *
 static CYTHON_INLINE char *__pyx_f_5numpy_7ndarray_4data_data(PyArrayObject *__pyx_v_self) {
   char *__pyx_r;
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":290
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":290
  *             of `PyArray_DATA()` instead, which returns a 'void*'.
  *             """
  *             return PyArray_BYTES(self)             # <<<<<<<<<<<<<<
@@ -4079,7 +4208,7 @@ static CYTHON_INLINE char *__pyx_f_5numpy_7ndarray_4data_data(PyArrayObject *__p
   __pyx_r = PyArray_BYTES(__pyx_v_self);
   goto __pyx_L0;
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":284
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":284
  * 
  *         @property
  *         cdef inline char* data(self) nogil:             # <<<<<<<<<<<<<<
@@ -4092,7 +4221,7 @@ static CYTHON_INLINE char *__pyx_f_5numpy_7ndarray_4data_data(PyArrayObject *__p
   return __pyx_r;
 }
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":776
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":776
  * ctypedef npy_cdouble     complex_t
  * 
  * cdef inline object PyArray_MultiIterNew1(a):             # <<<<<<<<<<<<<<
@@ -4109,7 +4238,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("PyArray_MultiIterNew1", 1);
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":777
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":777
  * 
  * cdef inline object PyArray_MultiIterNew1(a):
  *     return PyArray_MultiIterNew(1, <void*>a)             # <<<<<<<<<<<<<<
@@ -4123,7 +4252,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__
   __pyx_t_1 = 0;
   goto __pyx_L0;
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":776
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":776
  * ctypedef npy_cdouble     complex_t
  * 
  * cdef inline object PyArray_MultiIterNew1(a):             # <<<<<<<<<<<<<<
@@ -4142,7 +4271,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__
   return __pyx_r;
 }
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":779
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":779
  *     return PyArray_MultiIterNew(1, <void*>a)
  * 
  * cdef inline object PyArray_MultiIterNew2(a, b):             # <<<<<<<<<<<<<<
@@ -4159,7 +4288,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("PyArray_MultiIterNew2", 1);
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":780
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":780
  * 
  * cdef inline object PyArray_MultiIterNew2(a, b):
  *     return PyArray_MultiIterNew(2, <void*>a, <void*>b)             # <<<<<<<<<<<<<<
@@ -4173,7 +4302,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__
   __pyx_t_1 = 0;
   goto __pyx_L0;
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":779
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":779
  *     return PyArray_MultiIterNew(1, <void*>a)
  * 
  * cdef inline object PyArray_MultiIterNew2(a, b):             # <<<<<<<<<<<<<<
@@ -4192,7 +4321,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__
   return __pyx_r;
 }
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":782
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":782
  *     return PyArray_MultiIterNew(2, <void*>a, <void*>b)
  * 
  * cdef inline object PyArray_MultiIterNew3(a, b, c):             # <<<<<<<<<<<<<<
@@ -4209,7 +4338,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("PyArray_MultiIterNew3", 1);
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":783
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":783
  * 
  * cdef inline object PyArray_MultiIterNew3(a, b, c):
  *     return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c)             # <<<<<<<<<<<<<<
@@ -4223,7 +4352,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__
   __pyx_t_1 = 0;
   goto __pyx_L0;
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":782
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":782
  *     return PyArray_MultiIterNew(2, <void*>a, <void*>b)
  * 
  * cdef inline object PyArray_MultiIterNew3(a, b, c):             # <<<<<<<<<<<<<<
@@ -4242,7 +4371,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__
   return __pyx_r;
 }
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":785
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":785
  *     return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c)
  * 
  * cdef inline object PyArray_MultiIterNew4(a, b, c, d):             # <<<<<<<<<<<<<<
@@ -4259,7 +4388,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("PyArray_MultiIterNew4", 1);
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":786
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":786
  * 
  * cdef inline object PyArray_MultiIterNew4(a, b, c, d):
  *     return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d)             # <<<<<<<<<<<<<<
@@ -4273,7 +4402,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__
   __pyx_t_1 = 0;
   goto __pyx_L0;
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":785
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":785
  *     return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c)
  * 
  * cdef inline object PyArray_MultiIterNew4(a, b, c, d):             # <<<<<<<<<<<<<<
@@ -4292,7 +4421,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__
   return __pyx_r;
 }
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":788
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":788
  *     return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d)
  * 
  * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e):             # <<<<<<<<<<<<<<
@@ -4309,7 +4438,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("PyArray_MultiIterNew5", 1);
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":789
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":789
  * 
  * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e):
  *     return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e)             # <<<<<<<<<<<<<<
@@ -4323,7 +4452,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__
   __pyx_t_1 = 0;
   goto __pyx_L0;
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":788
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":788
  *     return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d)
  * 
  * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e):             # <<<<<<<<<<<<<<
@@ -4342,7 +4471,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__
   return __pyx_r;
 }
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":791
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":791
  *     return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e)
  * 
  * cdef inline tuple PyDataType_SHAPE(dtype d):             # <<<<<<<<<<<<<<
@@ -4356,7 +4485,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__
   int __pyx_t_1;
   __Pyx_RefNannySetupContext("PyDataType_SHAPE", 1);
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":792
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":792
  * 
  * cdef inline tuple PyDataType_SHAPE(dtype d):
  *     if PyDataType_HASSUBARRAY(d):             # <<<<<<<<<<<<<<
@@ -4366,7 +4495,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__
   __pyx_t_1 = PyDataType_HASSUBARRAY(__pyx_v_d);
   if (__pyx_t_1) {
 
-    /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":793
+    /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":793
  * cdef inline tuple PyDataType_SHAPE(dtype d):
  *     if PyDataType_HASSUBARRAY(d):
  *         return <tuple>d.subarray.shape             # <<<<<<<<<<<<<<
@@ -4378,7 +4507,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__
     __pyx_r = ((PyObject*)__pyx_v_d->subarray->shape);
     goto __pyx_L0;
 
-    /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":792
+    /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":792
  * 
  * cdef inline tuple PyDataType_SHAPE(dtype d):
  *     if PyDataType_HASSUBARRAY(d):             # <<<<<<<<<<<<<<
@@ -4387,7 +4516,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__
  */
   }
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":795
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":795
  *         return <tuple>d.subarray.shape
  *     else:
  *         return ()             # <<<<<<<<<<<<<<
@@ -4401,7 +4530,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__
     goto __pyx_L0;
   }
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":791
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":791
  *     return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e)
  * 
  * cdef inline tuple PyDataType_SHAPE(dtype d):             # <<<<<<<<<<<<<<
@@ -4416,7 +4545,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__
   return __pyx_r;
 }
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":970
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":970
  *     int _import_umath() except -1
  * 
  * cdef inline void set_array_base(ndarray arr, object base):             # <<<<<<<<<<<<<<
@@ -4426,7 +4555,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__
 
 static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_arr, PyObject *__pyx_v_base) {
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":971
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":971
  * 
  * cdef inline void set_array_base(ndarray arr, object base):
  *     Py_INCREF(base) # important to do this before stealing the reference below!             # <<<<<<<<<<<<<<
@@ -4435,7 +4564,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a
  */
   Py_INCREF(__pyx_v_base);
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":972
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":972
  * cdef inline void set_array_base(ndarray arr, object base):
  *     Py_INCREF(base) # important to do this before stealing the reference below!
  *     PyArray_SetBaseObject(arr, base)             # <<<<<<<<<<<<<<
@@ -4444,7 +4573,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a
  */
   (void)(PyArray_SetBaseObject(__pyx_v_arr, __pyx_v_base));
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":970
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":970
  *     int _import_umath() except -1
  * 
  * cdef inline void set_array_base(ndarray arr, object base):             # <<<<<<<<<<<<<<
@@ -4455,7 +4584,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a
   /* function exit code */
 }
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":974
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":974
  *     PyArray_SetBaseObject(arr, base)
  * 
  * cdef inline object get_array_base(ndarray arr):             # <<<<<<<<<<<<<<
@@ -4470,7 +4599,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py
   int __pyx_t_1;
   __Pyx_RefNannySetupContext("get_array_base", 1);
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":975
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":975
  * 
  * cdef inline object get_array_base(ndarray arr):
  *     base = PyArray_BASE(arr)             # <<<<<<<<<<<<<<
@@ -4479,7 +4608,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py
  */
   __pyx_v_base = PyArray_BASE(__pyx_v_arr);
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":976
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":976
  * cdef inline object get_array_base(ndarray arr):
  *     base = PyArray_BASE(arr)
  *     if base is NULL:             # <<<<<<<<<<<<<<
@@ -4489,7 +4618,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py
   __pyx_t_1 = (__pyx_v_base == NULL);
   if (__pyx_t_1) {
 
-    /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":977
+    /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":977
  *     base = PyArray_BASE(arr)
  *     if base is NULL:
  *         return None             # <<<<<<<<<<<<<<
@@ -4500,7 +4629,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py
     __pyx_r = Py_None; __Pyx_INCREF(Py_None);
     goto __pyx_L0;
 
-    /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":976
+    /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":976
  * cdef inline object get_array_base(ndarray arr):
  *     base = PyArray_BASE(arr)
  *     if base is NULL:             # <<<<<<<<<<<<<<
@@ -4509,7 +4638,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py
  */
   }
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":978
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":978
  *     if base is NULL:
  *         return None
  *     return <object>base             # <<<<<<<<<<<<<<
@@ -4521,7 +4650,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py
   __pyx_r = ((PyObject *)__pyx_v_base);
   goto __pyx_L0;
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":974
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":974
  *     PyArray_SetBaseObject(arr, base)
  * 
  * cdef inline object get_array_base(ndarray arr):             # <<<<<<<<<<<<<<
@@ -4536,7 +4665,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py
   return __pyx_r;
 }
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":982
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":982
  * # Versions of the import_* functions which are more suitable for
  * # Cython code.
  * cdef inline int import_array() except -1:             # <<<<<<<<<<<<<<
@@ -4560,7 +4689,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) {
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("import_array", 1);
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":983
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":983
  * # Cython code.
  * cdef inline int import_array() except -1:
  *     try:             # <<<<<<<<<<<<<<
@@ -4576,7 +4705,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) {
     __Pyx_XGOTREF(__pyx_t_3);
     /*try:*/ {
 
-      /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":984
+      /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":984
  * cdef inline int import_array() except -1:
  *     try:
  *         __pyx_import_array()             # <<<<<<<<<<<<<<
@@ -4585,7 +4714,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) {
  */
       __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(1, 984, __pyx_L3_error)
 
-      /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":983
+      /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":983
  * # Cython code.
  * cdef inline int import_array() except -1:
  *     try:             # <<<<<<<<<<<<<<
@@ -4599,7 +4728,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) {
     goto __pyx_L8_try_end;
     __pyx_L3_error:;
 
-    /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":985
+    /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":985
  *     try:
  *         __pyx_import_array()
  *     except Exception:             # <<<<<<<<<<<<<<
@@ -4614,7 +4743,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) {
       __Pyx_XGOTREF(__pyx_t_6);
       __Pyx_XGOTREF(__pyx_t_7);
 
-      /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":986
+      /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":986
  *         __pyx_import_array()
  *     except Exception:
  *         raise ImportError("numpy.core.multiarray failed to import")             # <<<<<<<<<<<<<<
@@ -4629,7 +4758,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) {
     }
     goto __pyx_L5_except_error;
 
-    /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":983
+    /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":983
  * # Cython code.
  * cdef inline int import_array() except -1:
  *     try:             # <<<<<<<<<<<<<<
@@ -4645,7 +4774,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) {
     __pyx_L8_try_end:;
   }
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":982
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":982
  * # Versions of the import_* functions which are more suitable for
  * # Cython code.
  * cdef inline int import_array() except -1:             # <<<<<<<<<<<<<<
@@ -4668,7 +4797,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) {
   return __pyx_r;
 }
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":988
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":988
  *         raise ImportError("numpy.core.multiarray failed to import")
  * 
  * cdef inline int import_umath() except -1:             # <<<<<<<<<<<<<<
@@ -4692,7 +4821,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) {
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("import_umath", 1);
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":989
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":989
  * 
  * cdef inline int import_umath() except -1:
  *     try:             # <<<<<<<<<<<<<<
@@ -4708,7 +4837,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) {
     __Pyx_XGOTREF(__pyx_t_3);
     /*try:*/ {
 
-      /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":990
+      /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":990
  * cdef inline int import_umath() except -1:
  *     try:
  *         _import_umath()             # <<<<<<<<<<<<<<
@@ -4717,7 +4846,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) {
  */
       __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(1, 990, __pyx_L3_error)
 
-      /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":989
+      /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":989
  * 
  * cdef inline int import_umath() except -1:
  *     try:             # <<<<<<<<<<<<<<
@@ -4731,7 +4860,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) {
     goto __pyx_L8_try_end;
     __pyx_L3_error:;
 
-    /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":991
+    /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":991
  *     try:
  *         _import_umath()
  *     except Exception:             # <<<<<<<<<<<<<<
@@ -4746,7 +4875,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) {
       __Pyx_XGOTREF(__pyx_t_6);
       __Pyx_XGOTREF(__pyx_t_7);
 
-      /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":992
+      /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":992
  *         _import_umath()
  *     except Exception:
  *         raise ImportError("numpy.core.umath failed to import")             # <<<<<<<<<<<<<<
@@ -4761,7 +4890,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) {
     }
     goto __pyx_L5_except_error;
 
-    /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":989
+    /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":989
  * 
  * cdef inline int import_umath() except -1:
  *     try:             # <<<<<<<<<<<<<<
@@ -4777,7 +4906,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) {
     __pyx_L8_try_end:;
   }
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":988
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":988
  *         raise ImportError("numpy.core.multiarray failed to import")
  * 
  * cdef inline int import_umath() except -1:             # <<<<<<<<<<<<<<
@@ -4800,7 +4929,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) {
   return __pyx_r;
 }
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":994
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":994
  *         raise ImportError("numpy.core.umath failed to import")
  * 
  * cdef inline int import_ufunc() except -1:             # <<<<<<<<<<<<<<
@@ -4824,7 +4953,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) {
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("import_ufunc", 1);
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":995
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":995
  * 
  * cdef inline int import_ufunc() except -1:
  *     try:             # <<<<<<<<<<<<<<
@@ -4840,7 +4969,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) {
     __Pyx_XGOTREF(__pyx_t_3);
     /*try:*/ {
 
-      /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":996
+      /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":996
  * cdef inline int import_ufunc() except -1:
  *     try:
  *         _import_umath()             # <<<<<<<<<<<<<<
@@ -4849,7 +4978,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) {
  */
       __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(1, 996, __pyx_L3_error)
 
-      /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":995
+      /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":995
  * 
  * cdef inline int import_ufunc() except -1:
  *     try:             # <<<<<<<<<<<<<<
@@ -4863,7 +4992,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) {
     goto __pyx_L8_try_end;
     __pyx_L3_error:;
 
-    /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":997
+    /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":997
  *     try:
  *         _import_umath()
  *     except Exception:             # <<<<<<<<<<<<<<
@@ -4878,7 +5007,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) {
       __Pyx_XGOTREF(__pyx_t_6);
       __Pyx_XGOTREF(__pyx_t_7);
 
-      /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":998
+      /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":998
  *         _import_umath()
  *     except Exception:
  *         raise ImportError("numpy.core.umath failed to import")             # <<<<<<<<<<<<<<
@@ -4893,7 +5022,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) {
     }
     goto __pyx_L5_except_error;
 
-    /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":995
+    /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":995
  * 
  * cdef inline int import_ufunc() except -1:
  *     try:             # <<<<<<<<<<<<<<
@@ -4909,7 +5038,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) {
     __pyx_L8_try_end:;
   }
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":994
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":994
  *         raise ImportError("numpy.core.umath failed to import")
  * 
  * cdef inline int import_ufunc() except -1:             # <<<<<<<<<<<<<<
@@ -4932,7 +5061,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) {
   return __pyx_r;
 }
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1001
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1001
  * 
  * 
  * cdef inline bint is_timedelta64_object(object obj):             # <<<<<<<<<<<<<<
@@ -4943,7 +5072,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) {
 static CYTHON_INLINE int __pyx_f_5numpy_is_timedelta64_object(PyObject *__pyx_v_obj) {
   int __pyx_r;
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1013
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1013
  *     bool
  *     """
  *     return PyObject_TypeCheck(obj, &PyTimedeltaArrType_Type)             # <<<<<<<<<<<<<<
@@ -4953,7 +5082,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_is_timedelta64_object(PyObject *__pyx_v_
   __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyTimedeltaArrType_Type));
   goto __pyx_L0;
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1001
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1001
  * 
  * 
  * cdef inline bint is_timedelta64_object(object obj):             # <<<<<<<<<<<<<<
@@ -4966,7 +5095,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_is_timedelta64_object(PyObject *__pyx_v_
   return __pyx_r;
 }
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1016
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1016
  * 
  * 
  * cdef inline bint is_datetime64_object(object obj):             # <<<<<<<<<<<<<<
@@ -4977,7 +5106,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_is_timedelta64_object(PyObject *__pyx_v_
 static CYTHON_INLINE int __pyx_f_5numpy_is_datetime64_object(PyObject *__pyx_v_obj) {
   int __pyx_r;
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1028
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1028
  *     bool
  *     """
  *     return PyObject_TypeCheck(obj, &PyDatetimeArrType_Type)             # <<<<<<<<<<<<<<
@@ -4987,7 +5116,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_is_datetime64_object(PyObject *__pyx_v_o
   __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyDatetimeArrType_Type));
   goto __pyx_L0;
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1016
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1016
  * 
  * 
  * cdef inline bint is_datetime64_object(object obj):             # <<<<<<<<<<<<<<
@@ -5000,7 +5129,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_is_datetime64_object(PyObject *__pyx_v_o
   return __pyx_r;
 }
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1031
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1031
  * 
  * 
  * cdef inline npy_datetime get_datetime64_value(object obj) nogil:             # <<<<<<<<<<<<<<
@@ -5011,7 +5140,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_is_datetime64_object(PyObject *__pyx_v_o
 static CYTHON_INLINE npy_datetime __pyx_f_5numpy_get_datetime64_value(PyObject *__pyx_v_obj) {
   npy_datetime __pyx_r;
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1038
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1038
  *     also needed.  That can be found using `get_datetime64_unit`.
  *     """
  *     return (<PyDatetimeScalarObject*>obj).obval             # <<<<<<<<<<<<<<
@@ -5021,7 +5150,7 @@ static CYTHON_INLINE npy_datetime __pyx_f_5numpy_get_datetime64_value(PyObject *
   __pyx_r = ((PyDatetimeScalarObject *)__pyx_v_obj)->obval;
   goto __pyx_L0;
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1031
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1031
  * 
  * 
  * cdef inline npy_datetime get_datetime64_value(object obj) nogil:             # <<<<<<<<<<<<<<
@@ -5034,7 +5163,7 @@ static CYTHON_INLINE npy_datetime __pyx_f_5numpy_get_datetime64_value(PyObject *
   return __pyx_r;
 }
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1041
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1041
  * 
  * 
  * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil:             # <<<<<<<<<<<<<<
@@ -5045,7 +5174,7 @@ static CYTHON_INLINE npy_datetime __pyx_f_5numpy_get_datetime64_value(PyObject *
 static CYTHON_INLINE npy_timedelta __pyx_f_5numpy_get_timedelta64_value(PyObject *__pyx_v_obj) {
   npy_timedelta __pyx_r;
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1045
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1045
  *     returns the int64 value underlying scalar numpy timedelta64 object
  *     """
  *     return (<PyTimedeltaScalarObject*>obj).obval             # <<<<<<<<<<<<<<
@@ -5055,7 +5184,7 @@ static CYTHON_INLINE npy_timedelta __pyx_f_5numpy_get_timedelta64_value(PyObject
   __pyx_r = ((PyTimedeltaScalarObject *)__pyx_v_obj)->obval;
   goto __pyx_L0;
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1041
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1041
  * 
  * 
  * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil:             # <<<<<<<<<<<<<<
@@ -5068,7 +5197,7 @@ static CYTHON_INLINE npy_timedelta __pyx_f_5numpy_get_timedelta64_value(PyObject
   return __pyx_r;
 }
 
-/* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1048
+/* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1048
  * 
  * 
  * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil:             # <<<<<<<<<<<<<<
@@ -5079,7 +5208,7 @@ static CYTHON_INLINE npy_timedelta __pyx_f_5numpy_get_timedelta64_value(PyObject
 static CYTHON_INLINE NPY_DATETIMEUNIT __pyx_f_5numpy_get_datetime64_unit(PyObject *__pyx_v_obj) {
   NPY_DATETIMEUNIT __pyx_r;
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1052
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1052
  *     returns the unit part of the dtype for a numpy datetime64 object.
  *     """
  *     return <NPY_DATETIMEUNIT>(<PyDatetimeScalarObject*>obj).obmeta.base             # <<<<<<<<<<<<<<
@@ -5087,7 +5216,7 @@ static CYTHON_INLINE NPY_DATETIMEUNIT __pyx_f_5numpy_get_datetime64_unit(PyObjec
   __pyx_r = ((NPY_DATETIMEUNIT)((PyDatetimeScalarObject *)__pyx_v_obj)->obmeta.base);
   goto __pyx_L0;
 
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1048
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1048
  * 
  * 
  * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil:             # <<<<<<<<<<<<<<
@@ -5100,7 +5229,7 @@ static CYTHON_INLINE NPY_DATETIMEUNIT __pyx_f_5numpy_get_datetime64_unit(PyObjec
   return __pyx_r;
 }
 
-/* "_openjpeg.pyx":52
+/* "_openjpeg.pyx":65
  * 
  * 
  * def get_version() -> bytes:             # <<<<<<<<<<<<<<
@@ -5135,7 +5264,7 @@ static PyObject *__pyx_pf_9_openjpeg_get_version(CYTHON_UNUSED PyObject *__pyx_s
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("get_version", 1);
 
-  /* "_openjpeg.pyx":54
+  /* "_openjpeg.pyx":67
  * def get_version() -> bytes:
  *     """Return the openjpeg version as bytes."""
  *     cdef char *version = OpenJpegVersion()             # <<<<<<<<<<<<<<
@@ -5144,7 +5273,7 @@ static PyObject *__pyx_pf_9_openjpeg_get_version(CYTHON_UNUSED PyObject *__pyx_s
  */
   __pyx_v_version = OpenJpegVersion();
 
-  /* "_openjpeg.pyx":56
+  /* "_openjpeg.pyx":69
  *     cdef char *version = OpenJpegVersion()
  * 
  *     return version             # <<<<<<<<<<<<<<
@@ -5152,13 +5281,13 @@ static PyObject *__pyx_pf_9_openjpeg_get_version(CYTHON_UNUSED PyObject *__pyx_s
  * 
  */
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = __Pyx_PyBytes_FromString(__pyx_v_version); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 56, __pyx_L1_error)
+  __pyx_t_1 = __Pyx_PyBytes_FromString(__pyx_v_version); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 69, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
   __pyx_r = ((PyObject*)__pyx_t_1);
   __pyx_t_1 = 0;
   goto __pyx_L0;
 
-  /* "_openjpeg.pyx":52
+  /* "_openjpeg.pyx":65
  * 
  * 
  * def get_version() -> bytes:             # <<<<<<<<<<<<<<
@@ -5177,7 +5306,7 @@ static PyObject *__pyx_pf_9_openjpeg_get_version(CYTHON_UNUSED PyObject *__pyx_s
   return __pyx_r;
 }
 
-/* "_openjpeg.pyx":59
+/* "_openjpeg.pyx":72
  * 
  * 
  * def decode(             # <<<<<<<<<<<<<<
@@ -5185,7 +5314,7 @@ static PyObject *__pyx_pf_9_openjpeg_get_version(CYTHON_UNUSED PyObject *__pyx_s
  *     codec: int = 0,
  */
 
-static PyObject *__pyx_pf_9_openjpeg_8__defaults__(CYTHON_UNUSED PyObject *__pyx_self) {
+static PyObject *__pyx_pf_9_openjpeg_10__defaults__(CYTHON_UNUSED PyObject *__pyx_self) {
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   PyObject *__pyx_t_1 = NULL;
@@ -5196,36 +5325,36 @@ static PyObject *__pyx_pf_9_openjpeg_8__defaults__(CYTHON_UNUSED PyObject *__pyx
   __Pyx_RefNannySetupContext("__defaults__", 1);
   __Pyx_XDECREF(__pyx_r);
 
-  /* "_openjpeg.pyx":62
+  /* "_openjpeg.pyx":75
  *     fp: BinaryIO,
  *     codec: int = 0,
  *     as_array: bool = False             # <<<<<<<<<<<<<<
  * ) -> Union[np.ndarray, bytearray]:
  *     """Return the decoded JPEG 2000 data from Python file-like `fp`.
  */
-  __pyx_t_1 = PyTuple_New(2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 59, __pyx_L1_error)
+  __pyx_t_1 = PyTuple_New(2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 72, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
   __Pyx_INCREF(__Pyx_CyFunction_Defaults(__pyx_defaults, __pyx_self)->__pyx_arg_codec);
   __Pyx_GIVEREF(__Pyx_CyFunction_Defaults(__pyx_defaults, __pyx_self)->__pyx_arg_codec);
-  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 0, __Pyx_CyFunction_Defaults(__pyx_defaults, __pyx_self)->__pyx_arg_codec)) __PYX_ERR(0, 59, __pyx_L1_error);
+  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 0, __Pyx_CyFunction_Defaults(__pyx_defaults, __pyx_self)->__pyx_arg_codec)) __PYX_ERR(0, 72, __pyx_L1_error);
   __Pyx_INCREF(((PyObject *)Py_False));
   __Pyx_GIVEREF(((PyObject *)Py_False));
-  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 1, ((PyObject *)Py_False))) __PYX_ERR(0, 59, __pyx_L1_error);
+  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 1, ((PyObject *)Py_False))) __PYX_ERR(0, 72, __pyx_L1_error);
 
-  /* "_openjpeg.pyx":59
+  /* "_openjpeg.pyx":72
  * 
  * 
  * def decode(             # <<<<<<<<<<<<<<
  *     fp: BinaryIO,
  *     codec: int = 0,
  */
-  __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 59, __pyx_L1_error)
+  __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 72, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
   __Pyx_GIVEREF(__pyx_t_1);
-  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_1)) __PYX_ERR(0, 59, __pyx_L1_error);
+  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_1)) __PYX_ERR(0, 72, __pyx_L1_error);
   __Pyx_INCREF(Py_None);
   __Pyx_GIVEREF(Py_None);
-  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 1, Py_None)) __PYX_ERR(0, 59, __pyx_L1_error);
+  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 1, Py_None)) __PYX_ERR(0, 72, __pyx_L1_error);
   __pyx_t_1 = 0;
   __pyx_r = __pyx_t_2;
   __pyx_t_2 = 0;
@@ -5306,26 +5435,26 @@ PyObject *__pyx_args, PyObject *__pyx_kwds
           (void)__Pyx_Arg_NewRef_FASTCALL(values[0]);
           kw_args--;
         }
-        else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 59, __pyx_L3_error)
+        else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 72, __pyx_L3_error)
         else goto __pyx_L5_argtuple_error;
         CYTHON_FALLTHROUGH;
         case  1:
         if (kw_args > 0) {
           PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_codec);
           if (value) { values[1] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; }
-          else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 59, __pyx_L3_error)
+          else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 72, __pyx_L3_error)
         }
         CYTHON_FALLTHROUGH;
         case  2:
         if (kw_args > 0) {
           PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_as_array);
           if (value) { values[2] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; }
-          else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 59, __pyx_L3_error)
+          else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 72, __pyx_L3_error)
         }
       }
       if (unlikely(kw_args > 0)) {
         const Py_ssize_t kwd_pos_args = __pyx_nargs;
-        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "decode") < 0)) __PYX_ERR(0, 59, __pyx_L3_error)
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "decode") < 0)) __PYX_ERR(0, 72, __pyx_L3_error)
       }
     } else {
       switch (__pyx_nargs) {
@@ -5344,7 +5473,7 @@ PyObject *__pyx_args, PyObject *__pyx_kwds
   }
   goto __pyx_L6_skip;
   __pyx_L5_argtuple_error:;
-  __Pyx_RaiseArgtupleInvalid("decode", 0, 1, 3, __pyx_nargs); __PYX_ERR(0, 59, __pyx_L3_error)
+  __Pyx_RaiseArgtupleInvalid("decode", 0, 1, 3, __pyx_nargs); __PYX_ERR(0, 72, __pyx_L3_error)
   __pyx_L6_skip:;
   goto __pyx_L4_argument_unpacking_done;
   __pyx_L3_error:;
@@ -5358,7 +5487,7 @@ PyObject *__pyx_args, PyObject *__pyx_kwds
   __Pyx_RefNannyFinishContext();
   return NULL;
   __pyx_L4_argument_unpacking_done:;
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_codec), (&PyInt_Type), 0, "codec", 1))) __PYX_ERR(0, 61, __pyx_L1_error)
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_codec), (&PyInt_Type), 0, "codec", 1))) __PYX_ERR(0, 74, __pyx_L1_error)
   __pyx_r = __pyx_pf_9_openjpeg_2decode(__pyx_self, __pyx_v_fp, __pyx_v_codec, __pyx_v_as_array);
 
   /* function exit code */
@@ -5399,14 +5528,14 @@ static PyObject *__pyx_pf_9_openjpeg_2decode(CYTHON_UNUSED PyObject *__pyx_self,
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("decode", 1);
 
-  /* "_openjpeg.pyx":93
+  /* "_openjpeg.pyx":106
  *         If unable to decode the JPEG 2000 data.
  *     """
  *     param = get_parameters(fp, codec)             # <<<<<<<<<<<<<<
  *     bpp = ceil(param['precision'] / 8)
  *     if bpp == 3:
  */
-  __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_get_parameters); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 93, __pyx_L1_error)
+  __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_get_parameters); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 106, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
   __pyx_t_3 = NULL;
   __pyx_t_4 = 0;
@@ -5426,25 +5555,25 @@ static PyObject *__pyx_pf_9_openjpeg_2decode(CYTHON_UNUSED PyObject *__pyx_self,
     PyObject *__pyx_callargs[3] = {__pyx_t_3, __pyx_v_fp, __pyx_v_codec};
     __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+1-__pyx_t_4, 2+__pyx_t_4);
     __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0;
-    if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 93, __pyx_L1_error)
+    if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 106, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_1);
     __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
   }
   __pyx_v_param = __pyx_t_1;
   __pyx_t_1 = 0;
 
-  /* "_openjpeg.pyx":94
+  /* "_openjpeg.pyx":107
  *     """
  *     param = get_parameters(fp, codec)
  *     bpp = ceil(param['precision'] / 8)             # <<<<<<<<<<<<<<
  *     if bpp == 3:
  *         bpp = 4
  */
-  __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_ceil); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 94, __pyx_L1_error)
+  __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_ceil); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 107, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  __pyx_t_3 = __Pyx_PyObject_Dict_GetItem(__pyx_v_param, __pyx_n_u_precision); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 94, __pyx_L1_error)
+  __pyx_t_3 = __Pyx_PyObject_Dict_GetItem(__pyx_v_param, __pyx_n_u_precision); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 107, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_3);
-  __pyx_t_5 = __Pyx_PyInt_TrueDivideObjC(__pyx_t_3, __pyx_int_8, 8, 0, 0); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 94, __pyx_L1_error)
+  __pyx_t_5 = __Pyx_PyInt_TrueDivideObjC(__pyx_t_3, __pyx_int_8, 8, 0, 0); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 107, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_5);
   __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
   __pyx_t_3 = NULL;
@@ -5466,71 +5595,71 @@ static PyObject *__pyx_pf_9_openjpeg_2decode(CYTHON_UNUSED PyObject *__pyx_self,
     __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+1-__pyx_t_4, 1+__pyx_t_4);
     __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0;
     __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
-    if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 94, __pyx_L1_error)
+    if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 107, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_1);
     __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
   }
   __pyx_v_bpp = __pyx_t_1;
   __pyx_t_1 = 0;
 
-  /* "_openjpeg.pyx":95
+  /* "_openjpeg.pyx":108
  *     param = get_parameters(fp, codec)
  *     bpp = ceil(param['precision'] / 8)
  *     if bpp == 3:             # <<<<<<<<<<<<<<
  *         bpp = 4
- *     nr_bytes = param['rows'] * param['columns'] * param['nr_components'] * bpp
+ *     nr_bytes = param['rows'] * param['columns'] * param['samples_per_pixel'] * bpp
  */
-  __pyx_t_6 = (__Pyx_PyInt_BoolEqObjC(__pyx_v_bpp, __pyx_int_3, 3, 0)); if (unlikely((__pyx_t_6 < 0))) __PYX_ERR(0, 95, __pyx_L1_error)
+  __pyx_t_6 = (__Pyx_PyInt_BoolEqObjC(__pyx_v_bpp, __pyx_int_3, 3, 0)); if (unlikely((__pyx_t_6 < 0))) __PYX_ERR(0, 108, __pyx_L1_error)
   if (__pyx_t_6) {
 
-    /* "_openjpeg.pyx":96
+    /* "_openjpeg.pyx":109
  *     bpp = ceil(param['precision'] / 8)
  *     if bpp == 3:
  *         bpp = 4             # <<<<<<<<<<<<<<
- *     nr_bytes = param['rows'] * param['columns'] * param['nr_components'] * bpp
+ *     nr_bytes = param['rows'] * param['columns'] * param['samples_per_pixel'] * bpp
  * 
  */
     __Pyx_INCREF(__pyx_int_4);
     __Pyx_DECREF_SET(__pyx_v_bpp, __pyx_int_4);
 
-    /* "_openjpeg.pyx":95
+    /* "_openjpeg.pyx":108
  *     param = get_parameters(fp, codec)
  *     bpp = ceil(param['precision'] / 8)
  *     if bpp == 3:             # <<<<<<<<<<<<<<
  *         bpp = 4
- *     nr_bytes = param['rows'] * param['columns'] * param['nr_components'] * bpp
+ *     nr_bytes = param['rows'] * param['columns'] * param['samples_per_pixel'] * bpp
  */
   }
 
-  /* "_openjpeg.pyx":97
+  /* "_openjpeg.pyx":110
  *     if bpp == 3:
  *         bpp = 4
- *     nr_bytes = param['rows'] * param['columns'] * param['nr_components'] * bpp             # <<<<<<<<<<<<<<
+ *     nr_bytes = param['rows'] * param['columns'] * param['samples_per_pixel'] * bpp             # <<<<<<<<<<<<<<
  * 
  *     cdef PyObject* p_in = <PyObject*>fp
  */
-  __pyx_t_1 = __Pyx_PyObject_Dict_GetItem(__pyx_v_param, __pyx_n_u_rows); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 97, __pyx_L1_error)
+  __pyx_t_1 = __Pyx_PyObject_Dict_GetItem(__pyx_v_param, __pyx_n_u_rows); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 110, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
-  __pyx_t_2 = __Pyx_PyObject_Dict_GetItem(__pyx_v_param, __pyx_n_u_columns); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 97, __pyx_L1_error)
+  __pyx_t_2 = __Pyx_PyObject_Dict_GetItem(__pyx_v_param, __pyx_n_u_columns); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 110, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  __pyx_t_5 = PyNumber_Multiply(__pyx_t_1, __pyx_t_2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 97, __pyx_L1_error)
+  __pyx_t_5 = PyNumber_Multiply(__pyx_t_1, __pyx_t_2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 110, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_5);
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-  __pyx_t_2 = __Pyx_PyObject_Dict_GetItem(__pyx_v_param, __pyx_n_u_nr_components); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 97, __pyx_L1_error)
+  __pyx_t_2 = __Pyx_PyObject_Dict_GetItem(__pyx_v_param, __pyx_n_u_samples_per_pixel); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 110, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  __pyx_t_1 = PyNumber_Multiply(__pyx_t_5, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 97, __pyx_L1_error)
+  __pyx_t_1 = PyNumber_Multiply(__pyx_t_5, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 110, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
   __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-  __pyx_t_2 = PyNumber_Multiply(__pyx_t_1, __pyx_v_bpp); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 97, __pyx_L1_error)
+  __pyx_t_2 = PyNumber_Multiply(__pyx_t_1, __pyx_v_bpp); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 110, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
   __pyx_v_nr_bytes = __pyx_t_2;
   __pyx_t_2 = 0;
 
-  /* "_openjpeg.pyx":99
- *     nr_bytes = param['rows'] * param['columns'] * param['nr_components'] * bpp
+  /* "_openjpeg.pyx":112
+ *     nr_bytes = param['rows'] * param['columns'] * param['samples_per_pixel'] * bpp
  * 
  *     cdef PyObject* p_in = <PyObject*>fp             # <<<<<<<<<<<<<<
  *     cdef unsigned char *p_out
@@ -5538,43 +5667,43 @@ static PyObject *__pyx_pf_9_openjpeg_2decode(CYTHON_UNUSED PyObject *__pyx_self,
  */
   __pyx_v_p_in = ((PyObject *)__pyx_v_fp);
 
-  /* "_openjpeg.pyx":101
+  /* "_openjpeg.pyx":114
  *     cdef PyObject* p_in = <PyObject*>fp
  *     cdef unsigned char *p_out
  *     if as_array:             # <<<<<<<<<<<<<<
  *         out = np.zeros(nr_bytes, dtype=np.uint8)
  *         p_out = <unsigned char *>cnp.PyArray_DATA(out)
  */
-  __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_v_as_array); if (unlikely((__pyx_t_6 < 0))) __PYX_ERR(0, 101, __pyx_L1_error)
+  __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_v_as_array); if (unlikely((__pyx_t_6 < 0))) __PYX_ERR(0, 114, __pyx_L1_error)
   if (__pyx_t_6) {
 
-    /* "_openjpeg.pyx":102
+    /* "_openjpeg.pyx":115
  *     cdef unsigned char *p_out
  *     if as_array:
  *         out = np.zeros(nr_bytes, dtype=np.uint8)             # <<<<<<<<<<<<<<
  *         p_out = <unsigned char *>cnp.PyArray_DATA(out)
  *     else:
  */
-    __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 102, __pyx_L1_error)
+    __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 115, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_2);
-    __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_zeros); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 102, __pyx_L1_error)
+    __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_zeros); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 115, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_1);
     __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-    __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 102, __pyx_L1_error)
+    __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 115, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_2);
     __Pyx_INCREF(__pyx_v_nr_bytes);
     __Pyx_GIVEREF(__pyx_v_nr_bytes);
-    if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_v_nr_bytes)) __PYX_ERR(0, 102, __pyx_L1_error);
-    __pyx_t_5 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 102, __pyx_L1_error)
+    if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_v_nr_bytes)) __PYX_ERR(0, 115, __pyx_L1_error);
+    __pyx_t_5 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 115, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_5);
-    __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 102, __pyx_L1_error)
+    __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 115, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_3);
-    __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_uint8); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 102, __pyx_L1_error)
+    __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_uint8); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 115, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_7);
     __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-    if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_dtype, __pyx_t_7) < 0) __PYX_ERR(0, 102, __pyx_L1_error)
+    if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_dtype, __pyx_t_7) < 0) __PYX_ERR(0, 115, __pyx_L1_error)
     __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
-    __pyx_t_7 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_2, __pyx_t_5); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 102, __pyx_L1_error)
+    __pyx_t_7 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_2, __pyx_t_5); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 115, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_7);
     __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
     __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
@@ -5582,17 +5711,17 @@ static PyObject *__pyx_pf_9_openjpeg_2decode(CYTHON_UNUSED PyObject *__pyx_self,
     __pyx_v_out = __pyx_t_7;
     __pyx_t_7 = 0;
 
-    /* "_openjpeg.pyx":103
+    /* "_openjpeg.pyx":116
  *     if as_array:
  *         out = np.zeros(nr_bytes, dtype=np.uint8)
  *         p_out = <unsigned char *>cnp.PyArray_DATA(out)             # <<<<<<<<<<<<<<
  *     else:
  *         out = bytearray(nr_bytes)
  */
-    if (!(likely(((__pyx_v_out) == Py_None) || likely(__Pyx_TypeTest(__pyx_v_out, __pyx_ptype_5numpy_ndarray))))) __PYX_ERR(0, 103, __pyx_L1_error)
+    if (!(likely(((__pyx_v_out) == Py_None) || likely(__Pyx_TypeTest(__pyx_v_out, __pyx_ptype_5numpy_ndarray))))) __PYX_ERR(0, 116, __pyx_L1_error)
     __pyx_v_p_out = ((unsigned char *)PyArray_DATA(((PyArrayObject *)__pyx_v_out)));
 
-    /* "_openjpeg.pyx":101
+    /* "_openjpeg.pyx":114
  *     cdef PyObject* p_in = <PyObject*>fp
  *     cdef unsigned char *p_out
  *     if as_array:             # <<<<<<<<<<<<<<
@@ -5602,7 +5731,7 @@ static PyObject *__pyx_pf_9_openjpeg_2decode(CYTHON_UNUSED PyObject *__pyx_self,
     goto __pyx_L4;
   }
 
-  /* "_openjpeg.pyx":105
+  /* "_openjpeg.pyx":118
  *         p_out = <unsigned char *>cnp.PyArray_DATA(out)
  *     else:
  *         out = bytearray(nr_bytes)             # <<<<<<<<<<<<<<
@@ -5610,34 +5739,34 @@ static PyObject *__pyx_pf_9_openjpeg_2decode(CYTHON_UNUSED PyObject *__pyx_self,
  * 
  */
   /*else*/ {
-    __pyx_t_7 = __Pyx_PyObject_CallOneArg(((PyObject *)(&PyByteArray_Type)), __pyx_v_nr_bytes); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 105, __pyx_L1_error)
+    __pyx_t_7 = __Pyx_PyObject_CallOneArg(((PyObject *)(&PyByteArray_Type)), __pyx_v_nr_bytes); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 118, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_7);
     __pyx_v_out = __pyx_t_7;
     __pyx_t_7 = 0;
 
-    /* "_openjpeg.pyx":106
+    /* "_openjpeg.pyx":119
  *     else:
  *         out = bytearray(nr_bytes)
  *         p_out = <unsigned char *>out             # <<<<<<<<<<<<<<
  * 
  *     return_code = Decode(p_in, p_out, codec)
  */
-    __pyx_t_8 = __Pyx_PyObject_AsWritableUString(__pyx_v_out); if (unlikely((!__pyx_t_8) && PyErr_Occurred())) __PYX_ERR(0, 106, __pyx_L1_error)
+    __pyx_t_8 = __Pyx_PyObject_AsWritableUString(__pyx_v_out); if (unlikely((!__pyx_t_8) && PyErr_Occurred())) __PYX_ERR(0, 119, __pyx_L1_error)
     __pyx_v_p_out = ((unsigned char *)__pyx_t_8);
   }
   __pyx_L4:;
 
-  /* "_openjpeg.pyx":108
+  /* "_openjpeg.pyx":121
  *         p_out = <unsigned char *>out
  * 
  *     return_code = Decode(p_in, p_out, codec)             # <<<<<<<<<<<<<<
  * 
  *     return return_code, out
  */
-  __pyx_t_4 = __Pyx_PyInt_As_int(__pyx_v_codec); if (unlikely((__pyx_t_4 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 108, __pyx_L1_error)
+  __pyx_t_4 = __Pyx_PyInt_As_int(__pyx_v_codec); if (unlikely((__pyx_t_4 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 121, __pyx_L1_error)
   __pyx_v_return_code = Decode(__pyx_v_p_in, __pyx_v_p_out, __pyx_t_4);
 
-  /* "_openjpeg.pyx":110
+  /* "_openjpeg.pyx":123
  *     return_code = Decode(p_in, p_out, codec)
  * 
  *     return return_code, out             # <<<<<<<<<<<<<<
@@ -5645,21 +5774,21 @@ static PyObject *__pyx_pf_9_openjpeg_2decode(CYTHON_UNUSED PyObject *__pyx_self,
  * 
  */
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_7 = __Pyx_PyInt_From_int(__pyx_v_return_code); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 110, __pyx_L1_error)
+  __pyx_t_7 = __Pyx_PyInt_From_int(__pyx_v_return_code); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 123, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_7);
-  __pyx_t_5 = PyTuple_New(2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 110, __pyx_L1_error)
+  __pyx_t_5 = PyTuple_New(2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 123, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_5);
   __Pyx_GIVEREF(__pyx_t_7);
-  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_7)) __PYX_ERR(0, 110, __pyx_L1_error);
+  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_7)) __PYX_ERR(0, 123, __pyx_L1_error);
   __Pyx_INCREF(__pyx_v_out);
   __Pyx_GIVEREF(__pyx_v_out);
-  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_v_out)) __PYX_ERR(0, 110, __pyx_L1_error);
+  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_v_out)) __PYX_ERR(0, 123, __pyx_L1_error);
   __pyx_t_7 = 0;
   __pyx_r = __pyx_t_5;
   __pyx_t_5 = 0;
   goto __pyx_L0;
 
-  /* "_openjpeg.pyx":59
+  /* "_openjpeg.pyx":72
  * 
  * 
  * def decode(             # <<<<<<<<<<<<<<
@@ -5686,7 +5815,7 @@ static PyObject *__pyx_pf_9_openjpeg_2decode(CYTHON_UNUSED PyObject *__pyx_self,
   return __pyx_r;
 }
 
-/* "_openjpeg.pyx":113
+/* "_openjpeg.pyx":126
  * 
  * 
  * def get_parameters(fp: BinaryIO, codec: int = 0) -> Dict[str, Union[str, int, bool]]:             # <<<<<<<<<<<<<<
@@ -5694,7 +5823,7 @@ static PyObject *__pyx_pf_9_openjpeg_2decode(CYTHON_UNUSED PyObject *__pyx_self,
  * 
  */
 
-static PyObject *__pyx_pf_9_openjpeg_10__defaults__(CYTHON_UNUSED PyObject *__pyx_self) {
+static PyObject *__pyx_pf_9_openjpeg_12__defaults__(CYTHON_UNUSED PyObject *__pyx_self) {
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   PyObject *__pyx_t_1 = NULL;
@@ -5704,18 +5833,18 @@ static PyObject *__pyx_pf_9_openjpeg_10__defaults__(CYTHON_UNUSED PyObject *__py
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__defaults__", 1);
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 113, __pyx_L1_error)
+  __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 126, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
   __Pyx_INCREF(__Pyx_CyFunction_Defaults(__pyx_defaults1, __pyx_self)->__pyx_arg_codec);
   __Pyx_GIVEREF(__Pyx_CyFunction_Defaults(__pyx_defaults1, __pyx_self)->__pyx_arg_codec);
-  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 0, __Pyx_CyFunction_Defaults(__pyx_defaults1, __pyx_self)->__pyx_arg_codec)) __PYX_ERR(0, 113, __pyx_L1_error);
-  __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 113, __pyx_L1_error)
+  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 0, __Pyx_CyFunction_Defaults(__pyx_defaults1, __pyx_self)->__pyx_arg_codec)) __PYX_ERR(0, 126, __pyx_L1_error);
+  __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 126, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
   __Pyx_GIVEREF(__pyx_t_1);
-  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_1)) __PYX_ERR(0, 113, __pyx_L1_error);
+  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_1)) __PYX_ERR(0, 126, __pyx_L1_error);
   __Pyx_INCREF(Py_None);
   __Pyx_GIVEREF(Py_None);
-  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 1, Py_None)) __PYX_ERR(0, 113, __pyx_L1_error);
+  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 1, Py_None)) __PYX_ERR(0, 126, __pyx_L1_error);
   __pyx_t_1 = 0;
   __pyx_r = __pyx_t_2;
   __pyx_t_2 = 0;
@@ -5741,7 +5870,7 @@ PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds
 PyObject *__pyx_args, PyObject *__pyx_kwds
 #endif
 ); /*proto*/
-PyDoc_STRVAR(__pyx_doc_9_openjpeg_4get_parameters, "Return a :class:`dict` containing the JPEG 2000 image parameters.\n\n    Parameters\n    ----------\n    fp : file-like\n        A Python file-like containing the encoded JPEG 2000 data.\n    codec : int, optional\n        The codec to use for decoding, one of:\n\n        * ``0``: JPEG-2000 codestream\n        * ``1``: JPT-stream (JPEG 2000, JPIP)\n        * ``2``: JP2 file format\n\n    Returns\n    -------\n    dict\n        A :class:`dict` containing the J2K image parameters:\n        ``{'columns': int, 'rows': int, 'colourspace': str,\n        'nr_components: int, 'precision': int, `is_signed`: bool,\n        'nr_tiles: int'}``. Possible colour spaces are \"unknown\",\n        \"unspecified\", \"sRGB\", \"monochrome\", \"YUV\", \"e-YCC\" and \"CYMK\".\n\n    Raises\n    ------\n    RuntimeError\n        If unable to decode the JPEG 2000 data.\n    ");
+PyDoc_STRVAR(__pyx_doc_9_openjpeg_4get_parameters, "Return a :class:`dict` containing the JPEG 2000 image parameters.\n\n    Parameters\n    ----------\n    fp : file-like\n        A Python file-like containing the encoded JPEG 2000 data.\n    codec : int, optional\n        The codec to use for decoding, one of:\n\n        * ``0``: JPEG-2000 codestream\n        * ``1``: JPT-stream (JPEG 2000, JPIP)\n        * ``2``: JP2 file format\n\n    Returns\n    -------\n    dict\n        A :class:`dict` containing the J2K image parameters:\n        ``{'columns': int, 'rows': int, 'colourspace': str,\n        'samples_per_pixel: int, 'precision': int, `is_signed`: bool,\n        'nr_tiles: int'}``. Possible colour spaces are \"unknown\",\n        \"unspecified\", \"sRGB\", \"monochrome\", \"YUV\", \"e-YCC\" and \"CYMK\".\n\n    Raises\n    ------\n    RuntimeError\n        If unable to decode the JPEG 2000 data.\n    ");
 static PyMethodDef __pyx_mdef_9_openjpeg_5get_parameters = {"get_parameters", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_9_openjpeg_5get_parameters, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_9_openjpeg_4get_parameters};
 static PyObject *__pyx_pw_9_openjpeg_5get_parameters(PyObject *__pyx_self, 
 #if CYTHON_METH_FASTCALL
@@ -5792,19 +5921,19 @@ PyObject *__pyx_args, PyObject *__pyx_kwds
           (void)__Pyx_Arg_NewRef_FASTCALL(values[0]);
           kw_args--;
         }
-        else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 113, __pyx_L3_error)
+        else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 126, __pyx_L3_error)
         else goto __pyx_L5_argtuple_error;
         CYTHON_FALLTHROUGH;
         case  1:
         if (kw_args > 0) {
           PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_codec);
           if (value) { values[1] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; }
-          else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 113, __pyx_L3_error)
+          else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 126, __pyx_L3_error)
         }
       }
       if (unlikely(kw_args > 0)) {
         const Py_ssize_t kwd_pos_args = __pyx_nargs;
-        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "get_parameters") < 0)) __PYX_ERR(0, 113, __pyx_L3_error)
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "get_parameters") < 0)) __PYX_ERR(0, 126, __pyx_L3_error)
       }
     } else {
       switch (__pyx_nargs) {
@@ -5820,7 +5949,7 @@ PyObject *__pyx_args, PyObject *__pyx_kwds
   }
   goto __pyx_L6_skip;
   __pyx_L5_argtuple_error:;
-  __Pyx_RaiseArgtupleInvalid("get_parameters", 0, 1, 2, __pyx_nargs); __PYX_ERR(0, 113, __pyx_L3_error)
+  __Pyx_RaiseArgtupleInvalid("get_parameters", 0, 1, 2, __pyx_nargs); __PYX_ERR(0, 126, __pyx_L3_error)
   __pyx_L6_skip:;
   goto __pyx_L4_argument_unpacking_done;
   __pyx_L3_error:;
@@ -5834,7 +5963,7 @@ PyObject *__pyx_args, PyObject *__pyx_kwds
   __Pyx_RefNannyFinishContext();
   return NULL;
   __pyx_L4_argument_unpacking_done:;
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_codec), (&PyInt_Type), 0, "codec", 1))) __PYX_ERR(0, 113, __pyx_L1_error)
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_codec), (&PyInt_Type), 0, "codec", 1))) __PYX_ERR(0, 126, __pyx_L1_error)
   __pyx_r = __pyx_pf_9_openjpeg_4get_parameters(__pyx_self, __pyx_v_fp, __pyx_v_codec);
 
   /* function exit code */
@@ -5876,7 +6005,7 @@ static PyObject *__pyx_pf_9_openjpeg_4get_parameters(CYTHON_UNUSED PyObject *__p
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("get_parameters", 1);
 
-  /* "_openjpeg.pyx":142
+  /* "_openjpeg.pyx":155
  *     """
  *     cdef JPEG2000Parameters param
  *     param.columns = 0             # <<<<<<<<<<<<<<
@@ -5885,44 +6014,44 @@ static PyObject *__pyx_pf_9_openjpeg_4get_parameters(CYTHON_UNUSED PyObject *__p
  */
   __pyx_v_param.columns = 0;
 
-  /* "_openjpeg.pyx":143
+  /* "_openjpeg.pyx":156
  *     cdef JPEG2000Parameters param
  *     param.columns = 0
  *     param.rows = 0             # <<<<<<<<<<<<<<
  *     param.colourspace = 0
- *     param.nr_components = 0
+ *     param.samples_per_pixel = 0
  */
   __pyx_v_param.rows = 0;
 
-  /* "_openjpeg.pyx":144
+  /* "_openjpeg.pyx":157
  *     param.columns = 0
  *     param.rows = 0
  *     param.colourspace = 0             # <<<<<<<<<<<<<<
- *     param.nr_components = 0
+ *     param.samples_per_pixel = 0
  *     param.precision = 0
  */
   __pyx_v_param.colourspace = 0;
 
-  /* "_openjpeg.pyx":145
+  /* "_openjpeg.pyx":158
  *     param.rows = 0
  *     param.colourspace = 0
- *     param.nr_components = 0             # <<<<<<<<<<<<<<
+ *     param.samples_per_pixel = 0             # <<<<<<<<<<<<<<
  *     param.precision = 0
  *     param.is_signed = 0
  */
-  __pyx_v_param.nr_components = 0;
+  __pyx_v_param.samples_per_pixel = 0;
 
-  /* "_openjpeg.pyx":146
+  /* "_openjpeg.pyx":159
  *     param.colourspace = 0
- *     param.nr_components = 0
+ *     param.samples_per_pixel = 0
  *     param.precision = 0             # <<<<<<<<<<<<<<
  *     param.is_signed = 0
  *     param.nr_tiles = 0
  */
   __pyx_v_param.precision = 0;
 
-  /* "_openjpeg.pyx":147
- *     param.nr_components = 0
+  /* "_openjpeg.pyx":160
+ *     param.samples_per_pixel = 0
  *     param.precision = 0
  *     param.is_signed = 0             # <<<<<<<<<<<<<<
  *     param.nr_tiles = 0
@@ -5930,7 +6059,7 @@ static PyObject *__pyx_pf_9_openjpeg_4get_parameters(CYTHON_UNUSED PyObject *__p
  */
   __pyx_v_param.is_signed = 0;
 
-  /* "_openjpeg.pyx":148
+  /* "_openjpeg.pyx":161
  *     param.precision = 0
  *     param.is_signed = 0
  *     param.nr_tiles = 0             # <<<<<<<<<<<<<<
@@ -5939,7 +6068,7 @@ static PyObject *__pyx_pf_9_openjpeg_4get_parameters(CYTHON_UNUSED PyObject *__p
  */
   __pyx_v_param.nr_tiles = 0;
 
-  /* "_openjpeg.pyx":151
+  /* "_openjpeg.pyx":164
  * 
  *     # Pointer to the JPEGParameters object
  *     cdef JPEG2000Parameters *p_param = &param             # <<<<<<<<<<<<<<
@@ -5948,7 +6077,7 @@ static PyObject *__pyx_pf_9_openjpeg_4get_parameters(CYTHON_UNUSED PyObject *__p
  */
   __pyx_v_p_param = (&__pyx_v_param);
 
-  /* "_openjpeg.pyx":154
+  /* "_openjpeg.pyx":167
  * 
  *     # Pointer to J2K data
  *     cdef PyObject* ptr = <PyObject*>fp             # <<<<<<<<<<<<<<
@@ -5957,17 +6086,17 @@ static PyObject *__pyx_pf_9_openjpeg_4get_parameters(CYTHON_UNUSED PyObject *__p
  */
   __pyx_v_ptr = ((PyObject *)__pyx_v_fp);
 
-  /* "_openjpeg.pyx":157
+  /* "_openjpeg.pyx":170
  * 
  *     # Decode the data - output is written to output_buffer
  *     result = GetParameters(ptr, codec, p_param)             # <<<<<<<<<<<<<<
  *     if result != 0:
  *         try:
  */
-  __pyx_t_1 = __Pyx_PyInt_As_int(__pyx_v_codec); if (unlikely((__pyx_t_1 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 157, __pyx_L1_error)
+  __pyx_t_1 = __Pyx_PyInt_As_int(__pyx_v_codec); if (unlikely((__pyx_t_1 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 170, __pyx_L1_error)
   __pyx_v_result = GetParameters(__pyx_v_ptr, __pyx_t_1, __pyx_v_p_param);
 
-  /* "_openjpeg.pyx":158
+  /* "_openjpeg.pyx":171
  *     # Decode the data - output is written to output_buffer
  *     result = GetParameters(ptr, codec, p_param)
  *     if result != 0:             # <<<<<<<<<<<<<<
@@ -5977,7 +6106,7 @@ static PyObject *__pyx_pf_9_openjpeg_4get_parameters(CYTHON_UNUSED PyObject *__p
   __pyx_t_2 = (__pyx_v_result != 0);
   if (__pyx_t_2) {
 
-    /* "_openjpeg.pyx":159
+    /* "_openjpeg.pyx":172
  *     result = GetParameters(ptr, codec, p_param)
  *     if result != 0:
  *         try:             # <<<<<<<<<<<<<<
@@ -5993,28 +6122,28 @@ static PyObject *__pyx_pf_9_openjpeg_4get_parameters(CYTHON_UNUSED PyObject *__p
       __Pyx_XGOTREF(__pyx_t_5);
       /*try:*/ {
 
-        /* "_openjpeg.pyx":160
+        /* "_openjpeg.pyx":173
  *     if result != 0:
  *         try:
  *             msg = f": {ERRORS[result]}"             # <<<<<<<<<<<<<<
  *         except KeyError:
  *             pass
  */
-        __Pyx_GetModuleGlobalName(__pyx_t_6, __pyx_n_s_ERRORS); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 160, __pyx_L4_error)
+        __Pyx_GetModuleGlobalName(__pyx_t_6, __pyx_n_s_ERRORS); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 173, __pyx_L4_error)
         __Pyx_GOTREF(__pyx_t_6);
-        __pyx_t_7 = __Pyx_GetItemInt(__pyx_t_6, __pyx_v_result, int, 1, __Pyx_PyInt_From_int, 0, 1, 1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 160, __pyx_L4_error)
+        __pyx_t_7 = __Pyx_GetItemInt(__pyx_t_6, __pyx_v_result, int, 1, __Pyx_PyInt_From_int, 0, 1, 1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 173, __pyx_L4_error)
         __Pyx_GOTREF(__pyx_t_7);
         __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
-        __pyx_t_6 = __Pyx_PyObject_FormatSimple(__pyx_t_7, __pyx_empty_unicode); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 160, __pyx_L4_error)
+        __pyx_t_6 = __Pyx_PyObject_FormatSimple(__pyx_t_7, __pyx_empty_unicode); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 173, __pyx_L4_error)
         __Pyx_GOTREF(__pyx_t_6);
         __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
-        __pyx_t_7 = __Pyx_PyUnicode_Concat(__pyx_kp_u__3, __pyx_t_6); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 160, __pyx_L4_error)
+        __pyx_t_7 = __Pyx_PyUnicode_Concat(__pyx_kp_u__3, __pyx_t_6); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 173, __pyx_L4_error)
         __Pyx_GOTREF(__pyx_t_7);
         __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
         __pyx_v_msg = ((PyObject*)__pyx_t_7);
         __pyx_t_7 = 0;
 
-        /* "_openjpeg.pyx":159
+        /* "_openjpeg.pyx":172
  *     result = GetParameters(ptr, codec, p_param)
  *     if result != 0:
  *         try:             # <<<<<<<<<<<<<<
@@ -6030,7 +6159,7 @@ static PyObject *__pyx_pf_9_openjpeg_4get_parameters(CYTHON_UNUSED PyObject *__p
       __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
       __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0;
 
-      /* "_openjpeg.pyx":161
+      /* "_openjpeg.pyx":174
  *         try:
  *             msg = f": {ERRORS[result]}"
  *         except KeyError:             # <<<<<<<<<<<<<<
@@ -6044,7 +6173,7 @@ static PyObject *__pyx_pf_9_openjpeg_4get_parameters(CYTHON_UNUSED PyObject *__p
       }
       goto __pyx_L6_except_error;
 
-      /* "_openjpeg.pyx":159
+      /* "_openjpeg.pyx":172
  *     result = GetParameters(ptr, codec, p_param)
  *     if result != 0:
  *         try:             # <<<<<<<<<<<<<<
@@ -6065,24 +6194,24 @@ static PyObject *__pyx_pf_9_openjpeg_4get_parameters(CYTHON_UNUSED PyObject *__p
       __pyx_L9_try_end:;
     }
 
-    /* "_openjpeg.pyx":164
+    /* "_openjpeg.pyx":177
  *             pass
  * 
  *         raise RuntimeError("Error decoding the J2K data" + msg)             # <<<<<<<<<<<<<<
  * 
  *     # From openjpeg.h#L309
  */
-    if (unlikely(!__pyx_v_msg)) { __Pyx_RaiseUnboundLocalError("msg"); __PYX_ERR(0, 164, __pyx_L1_error) }
-    __pyx_t_7 = __Pyx_PyUnicode_Concat(__pyx_kp_u_Error_decoding_the_J2K_data, __pyx_v_msg); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 164, __pyx_L1_error)
+    if (unlikely(!__pyx_v_msg)) { __Pyx_RaiseUnboundLocalError("msg"); __PYX_ERR(0, 177, __pyx_L1_error) }
+    __pyx_t_7 = __Pyx_PyUnicode_Concat(__pyx_kp_u_Error_decoding_the_J2K_data, __pyx_v_msg); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 177, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_7);
-    __pyx_t_6 = __Pyx_PyObject_CallOneArg(__pyx_builtin_RuntimeError, __pyx_t_7); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 164, __pyx_L1_error)
+    __pyx_t_6 = __Pyx_PyObject_CallOneArg(__pyx_builtin_RuntimeError, __pyx_t_7); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 177, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_6);
     __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
     __Pyx_Raise(__pyx_t_6, 0, 0, 0);
     __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
-    __PYX_ERR(0, 164, __pyx_L1_error)
+    __PYX_ERR(0, 177, __pyx_L1_error)
 
-    /* "_openjpeg.pyx":158
+    /* "_openjpeg.pyx":171
  *     # Decode the data - output is written to output_buffer
  *     result = GetParameters(ptr, codec, p_param)
  *     if result != 0:             # <<<<<<<<<<<<<<
@@ -6091,26 +6220,26 @@ static PyObject *__pyx_pf_9_openjpeg_4get_parameters(CYTHON_UNUSED PyObject *__p
  */
   }
 
-  /* "_openjpeg.pyx":168
+  /* "_openjpeg.pyx":181
  *     # From openjpeg.h#L309
  *     colours = {
  *         -1: "unknown",             # <<<<<<<<<<<<<<
  *          0: "unspecified",
  *          1: "sRGB",
  */
-  __pyx_t_6 = __Pyx_PyDict_NewPresized(7); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 168, __pyx_L1_error)
+  __pyx_t_6 = __Pyx_PyDict_NewPresized(7); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 181, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_6);
-  if (PyDict_SetItem(__pyx_t_6, __pyx_int_neg_1, __pyx_n_u_unknown) < 0) __PYX_ERR(0, 168, __pyx_L1_error)
-  if (PyDict_SetItem(__pyx_t_6, __pyx_int_0, __pyx_n_u_unspecified) < 0) __PYX_ERR(0, 168, __pyx_L1_error)
-  if (PyDict_SetItem(__pyx_t_6, __pyx_int_1, __pyx_n_u_sRGB) < 0) __PYX_ERR(0, 168, __pyx_L1_error)
-  if (PyDict_SetItem(__pyx_t_6, __pyx_int_2, __pyx_n_u_monochrome) < 0) __PYX_ERR(0, 168, __pyx_L1_error)
-  if (PyDict_SetItem(__pyx_t_6, __pyx_int_3, __pyx_n_u_YUV) < 0) __PYX_ERR(0, 168, __pyx_L1_error)
-  if (PyDict_SetItem(__pyx_t_6, __pyx_int_4, __pyx_kp_u_e_YCC) < 0) __PYX_ERR(0, 168, __pyx_L1_error)
-  if (PyDict_SetItem(__pyx_t_6, __pyx_int_5, __pyx_n_u_CYMK) < 0) __PYX_ERR(0, 168, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_6, __pyx_int_neg_1, __pyx_n_u_unknown) < 0) __PYX_ERR(0, 181, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_6, __pyx_int_0, __pyx_n_u_unspecified) < 0) __PYX_ERR(0, 181, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_6, __pyx_int_1, __pyx_n_u_sRGB) < 0) __PYX_ERR(0, 181, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_6, __pyx_int_2, __pyx_n_u_monochrome) < 0) __PYX_ERR(0, 181, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_6, __pyx_int_3, __pyx_n_u_YUV) < 0) __PYX_ERR(0, 181, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_6, __pyx_int_4, __pyx_kp_u_e_YCC) < 0) __PYX_ERR(0, 181, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_6, __pyx_int_5, __pyx_n_u_CYMK) < 0) __PYX_ERR(0, 181, __pyx_L1_error)
   __pyx_v_colours = ((PyObject*)__pyx_t_6);
   __pyx_t_6 = 0;
 
-  /* "_openjpeg.pyx":177
+  /* "_openjpeg.pyx":190
  *     }
  * 
  *     try:             # <<<<<<<<<<<<<<
@@ -6126,22 +6255,22 @@ static PyObject *__pyx_pf_9_openjpeg_4get_parameters(CYTHON_UNUSED PyObject *__p
     __Pyx_XGOTREF(__pyx_t_3);
     /*try:*/ {
 
-      /* "_openjpeg.pyx":178
+      /* "_openjpeg.pyx":191
  * 
  *     try:
  *         colourspace = colours[param.colourspace]             # <<<<<<<<<<<<<<
  *     except KeyError:
  *         colourspace = "unknown"
  */
-      __pyx_t_6 = __Pyx_PyInt_From_int(__pyx_v_param.colourspace); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 178, __pyx_L10_error)
+      __pyx_t_6 = __Pyx_PyInt_From_int(__pyx_v_param.colourspace); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 191, __pyx_L10_error)
       __Pyx_GOTREF(__pyx_t_6);
-      __pyx_t_7 = __Pyx_PyDict_GetItem(__pyx_v_colours, __pyx_t_6); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 178, __pyx_L10_error)
+      __pyx_t_7 = __Pyx_PyDict_GetItem(__pyx_v_colours, __pyx_t_6); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 191, __pyx_L10_error)
       __Pyx_GOTREF(__pyx_t_7);
       __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
       __pyx_v_colourspace = __pyx_t_7;
       __pyx_t_7 = 0;
 
-      /* "_openjpeg.pyx":177
+      /* "_openjpeg.pyx":190
  *     }
  * 
  *     try:             # <<<<<<<<<<<<<<
@@ -6157,7 +6286,7 @@ static PyObject *__pyx_pf_9_openjpeg_4get_parameters(CYTHON_UNUSED PyObject *__p
     __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
     __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0;
 
-    /* "_openjpeg.pyx":179
+    /* "_openjpeg.pyx":192
  *     try:
  *         colourspace = colours[param.colourspace]
  *     except KeyError:             # <<<<<<<<<<<<<<
@@ -6167,12 +6296,12 @@ static PyObject *__pyx_pf_9_openjpeg_4get_parameters(CYTHON_UNUSED PyObject *__p
     __pyx_t_1 = __Pyx_PyErr_ExceptionMatches(__pyx_builtin_KeyError);
     if (__pyx_t_1) {
       __Pyx_AddTraceback("_openjpeg.get_parameters", __pyx_clineno, __pyx_lineno, __pyx_filename);
-      if (__Pyx_GetException(&__pyx_t_7, &__pyx_t_6, &__pyx_t_8) < 0) __PYX_ERR(0, 179, __pyx_L12_except_error)
+      if (__Pyx_GetException(&__pyx_t_7, &__pyx_t_6, &__pyx_t_8) < 0) __PYX_ERR(0, 192, __pyx_L12_except_error)
       __Pyx_XGOTREF(__pyx_t_7);
       __Pyx_XGOTREF(__pyx_t_6);
       __Pyx_XGOTREF(__pyx_t_8);
 
-      /* "_openjpeg.pyx":180
+      /* "_openjpeg.pyx":193
  *         colourspace = colours[param.colourspace]
  *     except KeyError:
  *         colourspace = "unknown"             # <<<<<<<<<<<<<<
@@ -6188,7 +6317,7 @@ static PyObject *__pyx_pf_9_openjpeg_4get_parameters(CYTHON_UNUSED PyObject *__p
     }
     goto __pyx_L12_except_error;
 
-    /* "_openjpeg.pyx":177
+    /* "_openjpeg.pyx":190
  *     }
  * 
  *     try:             # <<<<<<<<<<<<<<
@@ -6209,96 +6338,96 @@ static PyObject *__pyx_pf_9_openjpeg_4get_parameters(CYTHON_UNUSED PyObject *__p
     __pyx_L15_try_end:;
   }
 
-  /* "_openjpeg.pyx":183
+  /* "_openjpeg.pyx":196
  * 
  *     parameters = {
  *         'rows' : param.rows,             # <<<<<<<<<<<<<<
  *         'columns' : param.columns,
  *         'colourspace' : colourspace,
  */
-  __pyx_t_8 = __Pyx_PyDict_NewPresized(7); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 183, __pyx_L1_error)
+  __pyx_t_8 = __Pyx_PyDict_NewPresized(7); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 196, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_8);
-  __pyx_t_6 = __Pyx_PyInt_From_uint32_t(__pyx_v_param.rows); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 183, __pyx_L1_error)
+  __pyx_t_6 = __Pyx_PyInt_From_uint32_t(__pyx_v_param.rows); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 196, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_6);
-  if (PyDict_SetItem(__pyx_t_8, __pyx_n_u_rows, __pyx_t_6) < 0) __PYX_ERR(0, 183, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_8, __pyx_n_u_rows, __pyx_t_6) < 0) __PYX_ERR(0, 196, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
 
-  /* "_openjpeg.pyx":184
+  /* "_openjpeg.pyx":197
  *     parameters = {
  *         'rows' : param.rows,
  *         'columns' : param.columns,             # <<<<<<<<<<<<<<
  *         'colourspace' : colourspace,
- *         'nr_components' : param.nr_components,
+ *         'samples_per_pixel' : param.samples_per_pixel,
  */
-  __pyx_t_6 = __Pyx_PyInt_From_uint32_t(__pyx_v_param.columns); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 184, __pyx_L1_error)
+  __pyx_t_6 = __Pyx_PyInt_From_uint32_t(__pyx_v_param.columns); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 197, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_6);
-  if (PyDict_SetItem(__pyx_t_8, __pyx_n_u_columns, __pyx_t_6) < 0) __PYX_ERR(0, 183, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_8, __pyx_n_u_columns, __pyx_t_6) < 0) __PYX_ERR(0, 196, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
 
-  /* "_openjpeg.pyx":185
+  /* "_openjpeg.pyx":198
  *         'rows' : param.rows,
  *         'columns' : param.columns,
  *         'colourspace' : colourspace,             # <<<<<<<<<<<<<<
- *         'nr_components' : param.nr_components,
+ *         'samples_per_pixel' : param.samples_per_pixel,
  *         'precision' : param.precision,
  */
-  if (PyDict_SetItem(__pyx_t_8, __pyx_n_u_colourspace, __pyx_v_colourspace) < 0) __PYX_ERR(0, 183, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_8, __pyx_n_u_colourspace, __pyx_v_colourspace) < 0) __PYX_ERR(0, 196, __pyx_L1_error)
 
-  /* "_openjpeg.pyx":186
+  /* "_openjpeg.pyx":199
  *         'columns' : param.columns,
  *         'colourspace' : colourspace,
- *         'nr_components' : param.nr_components,             # <<<<<<<<<<<<<<
+ *         'samples_per_pixel' : param.samples_per_pixel,             # <<<<<<<<<<<<<<
  *         'precision' : param.precision,
  *         'is_signed' : bool(param.is_signed),
  */
-  __pyx_t_6 = __Pyx_PyInt_From_uint32_t(__pyx_v_param.nr_components); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 186, __pyx_L1_error)
+  __pyx_t_6 = __Pyx_PyInt_From_uint32_t(__pyx_v_param.samples_per_pixel); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 199, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_6);
-  if (PyDict_SetItem(__pyx_t_8, __pyx_n_u_nr_components, __pyx_t_6) < 0) __PYX_ERR(0, 183, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_8, __pyx_n_u_samples_per_pixel, __pyx_t_6) < 0) __PYX_ERR(0, 196, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
 
-  /* "_openjpeg.pyx":187
+  /* "_openjpeg.pyx":200
  *         'colourspace' : colourspace,
- *         'nr_components' : param.nr_components,
+ *         'samples_per_pixel' : param.samples_per_pixel,
  *         'precision' : param.precision,             # <<<<<<<<<<<<<<
  *         'is_signed' : bool(param.is_signed),
  *         'nr_tiles' : param.nr_tiles,
  */
-  __pyx_t_6 = __Pyx_PyInt_From_uint32_t(__pyx_v_param.precision); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 187, __pyx_L1_error)
+  __pyx_t_6 = __Pyx_PyInt_From_uint32_t(__pyx_v_param.precision); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 200, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_6);
-  if (PyDict_SetItem(__pyx_t_8, __pyx_n_u_precision, __pyx_t_6) < 0) __PYX_ERR(0, 183, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_8, __pyx_n_u_precision, __pyx_t_6) < 0) __PYX_ERR(0, 196, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
 
-  /* "_openjpeg.pyx":188
- *         'nr_components' : param.nr_components,
+  /* "_openjpeg.pyx":201
+ *         'samples_per_pixel' : param.samples_per_pixel,
  *         'precision' : param.precision,
  *         'is_signed' : bool(param.is_signed),             # <<<<<<<<<<<<<<
  *         'nr_tiles' : param.nr_tiles,
  *     }
  */
-  __pyx_t_6 = __Pyx_PyInt_From_unsigned_int(__pyx_v_param.is_signed); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 188, __pyx_L1_error)
+  __pyx_t_6 = __Pyx_PyInt_From_unsigned_int(__pyx_v_param.is_signed); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 201, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_6);
-  __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_6); if (unlikely((__pyx_t_2 < 0))) __PYX_ERR(0, 188, __pyx_L1_error)
+  __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_6); if (unlikely((__pyx_t_2 < 0))) __PYX_ERR(0, 201, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
-  __pyx_t_6 = __Pyx_PyBool_FromLong((!(!__pyx_t_2))); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 188, __pyx_L1_error)
+  __pyx_t_6 = __Pyx_PyBool_FromLong((!(!__pyx_t_2))); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 201, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_6);
-  if (PyDict_SetItem(__pyx_t_8, __pyx_n_u_is_signed, __pyx_t_6) < 0) __PYX_ERR(0, 183, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_8, __pyx_n_u_is_signed, __pyx_t_6) < 0) __PYX_ERR(0, 196, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
 
-  /* "_openjpeg.pyx":189
+  /* "_openjpeg.pyx":202
  *         'precision' : param.precision,
  *         'is_signed' : bool(param.is_signed),
  *         'nr_tiles' : param.nr_tiles,             # <<<<<<<<<<<<<<
  *     }
  * 
  */
-  __pyx_t_6 = __Pyx_PyInt_From_uint32_t(__pyx_v_param.nr_tiles); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 189, __pyx_L1_error)
+  __pyx_t_6 = __Pyx_PyInt_From_uint32_t(__pyx_v_param.nr_tiles); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 202, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_6);
-  if (PyDict_SetItem(__pyx_t_8, __pyx_n_u_nr_tiles, __pyx_t_6) < 0) __PYX_ERR(0, 183, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_8, __pyx_n_u_nr_tiles, __pyx_t_6) < 0) __PYX_ERR(0, 196, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
   __pyx_v_parameters = ((PyObject*)__pyx_t_8);
   __pyx_t_8 = 0;
 
-  /* "_openjpeg.pyx":192
+  /* "_openjpeg.pyx":205
  *     }
  * 
  *     return parameters             # <<<<<<<<<<<<<<
@@ -6310,7 +6439,7 @@ static PyObject *__pyx_pf_9_openjpeg_4get_parameters(CYTHON_UNUSED PyObject *__p
   __pyx_r = __pyx_v_parameters;
   goto __pyx_L0;
 
-  /* "_openjpeg.pyx":113
+  /* "_openjpeg.pyx":126
  * 
  * 
  * def get_parameters(fp: BinaryIO, codec: int = 0) -> Dict[str, Union[str, int, bool]]:             # <<<<<<<<<<<<<<
@@ -6335,25 +6464,25 @@ static PyObject *__pyx_pf_9_openjpeg_4get_parameters(CYTHON_UNUSED PyObject *__p
   return __pyx_r;
 }
 
-/* "_openjpeg.pyx":195
+/* "_openjpeg.pyx":208
  * 
  * 
- * def encode(             # <<<<<<<<<<<<<<
+ * def encode_array(             # <<<<<<<<<<<<<<
  *     cnp.ndarray arr,
  *     int bits_stored,
  */
 
 /* Python wrapper */
-static PyObject *__pyx_pw_9_openjpeg_7encode(PyObject *__pyx_self, 
+static PyObject *__pyx_pw_9_openjpeg_7encode_array(PyObject *__pyx_self, 
 #if CYTHON_METH_FASTCALL
 PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds
 #else
 PyObject *__pyx_args, PyObject *__pyx_kwds
 #endif
 ); /*proto*/
-PyDoc_STRVAR(__pyx_doc_9_openjpeg_6encode, "Return the JPEG 2000 compressed `arr`.\n\n    Parameters\n    ----------\n    arr : numpy.ndarray\n        The array containing the image data to be encoded.\n    bits_stored : int, optional\n        The number of bits used per pixel.\n    photometric_interpretation : int, optional\n        The colour space of the unencoded image data that will be set in the\n        JPEG 2000 metadata.\n    use_mct : bool, optional\n        If ``True`` then apply multi-component transformation (MCT) to RGB\n        images.\n    lossless : bool, optional\n        If ``True`` then use lossless encoding, otherwise use lossy encoding.\n    compression_ratios : list[float], optional\n        Required if using lossy encoding, this is the compression ratio to use\n        for each layer. Should be in decreasing order (such as ``[80, 30, 10]``)\n        and the final value may be ``1`` to indicate lossless encoding should\n        be used for that layer.\n    codec_format : int, optional\n        The codec to used when encoding:\n\n        * ``0``: JPEG 2000 codestream only (default) (J2K/J2C format)\n        * ``2``: A boxed JPEG 2000 codestream (JP2 format)\n\n    Returns\n    -------\n    int\n        The return code of the encoding, will be ``0`` for success, otherwise\n        encoding failed.\n    ");
-static PyMethodDef __pyx_mdef_9_openjpeg_7encode = {"encode", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_9_openjpeg_7encode, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_9_openjpeg_6encode};
-static PyObject *__pyx_pw_9_openjpeg_7encode(PyObject *__pyx_self, 
+PyDoc_STRVAR(__pyx_doc_9_openjpeg_6encode_array, "Return the JPEG 2000 compressed `arr`.\n\n    Parameters\n    ----------\n    arr : numpy.ndarray\n        The array containing the image data to be encoded.\n    bits_stored : int, optional\n        The number of bits used per pixel.\n    photometric_interpretation : int\n        The colour space of the unencoded image data that will be set in the\n        JPEG 2000 metadata.\n    use_mct : bool\n        If ``True`` then apply multi-component transformation (MCT) to RGB\n        images.\n    compression_ratios : list[float]\n        Required for lossy encoding, this is the compression ratio to use\n        for each quality layer. Cannot be used with `signal_noise_ratios`.\n    signal_noise_ratios : list[float]\n        Required for lossy encoding, this is the PSNR to use for each quality\n        layer. Cannot be used with `compression_ratios`.\n    codec_format : int\n        The codec to used when encoding:\n\n        * ``0``: JPEG 2000 codestream only (default) (J2K/J2C format)\n        * ``1``: A boxed JPEG 2000 codestream (JP2 format)\n\n    Returns\n    -------\n    tuple[int, bytes]\n        The return code of the encoding and the encoded image data. The return\n        code will be ``0`` for success, otherwise the encoding failed.\n    ");
+static PyMethodDef __pyx_mdef_9_openjpeg_7encode_array = {"encode_array", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_9_openjpeg_7encode_array, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_9_openjpeg_6encode_array};
+static PyObject *__pyx_pw_9_openjpeg_7encode_array(PyObject *__pyx_self, 
 #if CYTHON_METH_FASTCALL
 PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds
 #else
@@ -6377,7 +6506,7 @@ PyObject *__pyx_args, PyObject *__pyx_kwds
   int __pyx_clineno = 0;
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("encode (wrapper)", 0);
+  __Pyx_RefNannySetupContext("encode_array (wrapper)", 0);
   #if !CYTHON_METH_FASTCALL
   #if CYTHON_ASSUME_SAFE_MACROS
   __pyx_nargs = PyTuple_GET_SIZE(__pyx_args);
@@ -6415,7 +6544,7 @@ PyObject *__pyx_args, PyObject *__pyx_kwds
           (void)__Pyx_Arg_NewRef_FASTCALL(values[0]);
           kw_args--;
         }
-        else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 195, __pyx_L3_error)
+        else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 208, __pyx_L3_error)
         else goto __pyx_L5_argtuple_error;
         CYTHON_FALLTHROUGH;
         case  1:
@@ -6423,9 +6552,9 @@ PyObject *__pyx_args, PyObject *__pyx_kwds
           (void)__Pyx_Arg_NewRef_FASTCALL(values[1]);
           kw_args--;
         }
-        else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 195, __pyx_L3_error)
+        else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 208, __pyx_L3_error)
         else {
-          __Pyx_RaiseArgtupleInvalid("encode", 1, 7, 7, 1); __PYX_ERR(0, 195, __pyx_L3_error)
+          __Pyx_RaiseArgtupleInvalid("encode_array", 1, 7, 7, 1); __PYX_ERR(0, 208, __pyx_L3_error)
         }
         CYTHON_FALLTHROUGH;
         case  2:
@@ -6433,9 +6562,9 @@ PyObject *__pyx_args, PyObject *__pyx_kwds
           (void)__Pyx_Arg_NewRef_FASTCALL(values[2]);
           kw_args--;
         }
-        else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 195, __pyx_L3_error)
+        else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 208, __pyx_L3_error)
         else {
-          __Pyx_RaiseArgtupleInvalid("encode", 1, 7, 7, 2); __PYX_ERR(0, 195, __pyx_L3_error)
+          __Pyx_RaiseArgtupleInvalid("encode_array", 1, 7, 7, 2); __PYX_ERR(0, 208, __pyx_L3_error)
         }
         CYTHON_FALLTHROUGH;
         case  3:
@@ -6443,9 +6572,9 @@ PyObject *__pyx_args, PyObject *__pyx_kwds
           (void)__Pyx_Arg_NewRef_FASTCALL(values[3]);
           kw_args--;
         }
-        else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 195, __pyx_L3_error)
+        else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 208, __pyx_L3_error)
         else {
-          __Pyx_RaiseArgtupleInvalid("encode", 1, 7, 7, 3); __PYX_ERR(0, 195, __pyx_L3_error)
+          __Pyx_RaiseArgtupleInvalid("encode_array", 1, 7, 7, 3); __PYX_ERR(0, 208, __pyx_L3_error)
         }
         CYTHON_FALLTHROUGH;
         case  4:
@@ -6453,9 +6582,9 @@ PyObject *__pyx_args, PyObject *__pyx_kwds
           (void)__Pyx_Arg_NewRef_FASTCALL(values[4]);
           kw_args--;
         }
-        else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 195, __pyx_L3_error)
+        else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 208, __pyx_L3_error)
         else {
-          __Pyx_RaiseArgtupleInvalid("encode", 1, 7, 7, 4); __PYX_ERR(0, 195, __pyx_L3_error)
+          __Pyx_RaiseArgtupleInvalid("encode_array", 1, 7, 7, 4); __PYX_ERR(0, 208, __pyx_L3_error)
         }
         CYTHON_FALLTHROUGH;
         case  5:
@@ -6463,9 +6592,9 @@ PyObject *__pyx_args, PyObject *__pyx_kwds
           (void)__Pyx_Arg_NewRef_FASTCALL(values[5]);
           kw_args--;
         }
-        else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 195, __pyx_L3_error)
+        else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 208, __pyx_L3_error)
         else {
-          __Pyx_RaiseArgtupleInvalid("encode", 1, 7, 7, 5); __PYX_ERR(0, 195, __pyx_L3_error)
+          __Pyx_RaiseArgtupleInvalid("encode_array", 1, 7, 7, 5); __PYX_ERR(0, 208, __pyx_L3_error)
         }
         CYTHON_FALLTHROUGH;
         case  6:
@@ -6473,14 +6602,14 @@ PyObject *__pyx_args, PyObject *__pyx_kwds
           (void)__Pyx_Arg_NewRef_FASTCALL(values[6]);
           kw_args--;
         }
-        else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 195, __pyx_L3_error)
+        else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 208, __pyx_L3_error)
         else {
-          __Pyx_RaiseArgtupleInvalid("encode", 1, 7, 7, 6); __PYX_ERR(0, 195, __pyx_L3_error)
+          __Pyx_RaiseArgtupleInvalid("encode_array", 1, 7, 7, 6); __PYX_ERR(0, 208, __pyx_L3_error)
         }
       }
       if (unlikely(kw_args > 0)) {
         const Py_ssize_t kwd_pos_args = __pyx_nargs;
-        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "encode") < 0)) __PYX_ERR(0, 195, __pyx_L3_error)
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "encode_array") < 0)) __PYX_ERR(0, 208, __pyx_L3_error)
       }
     } else if (unlikely(__pyx_nargs != 7)) {
       goto __pyx_L5_argtuple_error;
@@ -6494,16 +6623,16 @@ PyObject *__pyx_args, PyObject *__pyx_kwds
       values[6] = __Pyx_Arg_FASTCALL(__pyx_args, 6);
     }
     __pyx_v_arr = ((PyArrayObject *)values[0]);
-    __pyx_v_bits_stored = __Pyx_PyInt_As_int(values[1]); if (unlikely((__pyx_v_bits_stored == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 197, __pyx_L3_error)
-    __pyx_v_photometric_interpretation = __Pyx_PyInt_As_int(values[2]); if (unlikely((__pyx_v_photometric_interpretation == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 198, __pyx_L3_error)
-    __pyx_v_use_mct = __Pyx_PyObject_IsTrue(values[3]); if (unlikely((__pyx_v_use_mct == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 199, __pyx_L3_error)
+    __pyx_v_bits_stored = __Pyx_PyInt_As_int(values[1]); if (unlikely((__pyx_v_bits_stored == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 210, __pyx_L3_error)
+    __pyx_v_photometric_interpretation = __Pyx_PyInt_As_int(values[2]); if (unlikely((__pyx_v_photometric_interpretation == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 211, __pyx_L3_error)
+    __pyx_v_use_mct = __Pyx_PyObject_IsTrue(values[3]); if (unlikely((__pyx_v_use_mct == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 212, __pyx_L3_error)
     __pyx_v_compression_ratios = ((PyObject*)values[4]);
     __pyx_v_signal_noise_ratios = ((PyObject*)values[5]);
-    __pyx_v_codec_format = __Pyx_PyInt_As_int(values[6]); if (unlikely((__pyx_v_codec_format == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 202, __pyx_L3_error)
+    __pyx_v_codec_format = __Pyx_PyInt_As_int(values[6]); if (unlikely((__pyx_v_codec_format == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 215, __pyx_L3_error)
   }
   goto __pyx_L6_skip;
   __pyx_L5_argtuple_error:;
-  __Pyx_RaiseArgtupleInvalid("encode", 1, 7, 7, __pyx_nargs); __PYX_ERR(0, 195, __pyx_L3_error)
+  __Pyx_RaiseArgtupleInvalid("encode_array", 1, 7, 7, __pyx_nargs); __PYX_ERR(0, 208, __pyx_L3_error)
   __pyx_L6_skip:;
   goto __pyx_L4_argument_unpacking_done;
   __pyx_L3_error:;
@@ -6513,14 +6642,14 @@ PyObject *__pyx_args, PyObject *__pyx_kwds
       __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]);
     }
   }
-  __Pyx_AddTraceback("_openjpeg.encode", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_AddTraceback("_openjpeg.encode_array", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __Pyx_RefNannyFinishContext();
   return NULL;
   __pyx_L4_argument_unpacking_done:;
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_arr), __pyx_ptype_5numpy_ndarray, 1, "arr", 0))) __PYX_ERR(0, 196, __pyx_L1_error)
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_compression_ratios), (&PyList_Type), 1, "compression_ratios", 1))) __PYX_ERR(0, 200, __pyx_L1_error)
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_signal_noise_ratios), (&PyList_Type), 1, "signal_noise_ratios", 1))) __PYX_ERR(0, 201, __pyx_L1_error)
-  __pyx_r = __pyx_pf_9_openjpeg_6encode(__pyx_self, __pyx_v_arr, __pyx_v_bits_stored, __pyx_v_photometric_interpretation, __pyx_v_use_mct, __pyx_v_compression_ratios, __pyx_v_signal_noise_ratios, __pyx_v_codec_format);
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_arr), __pyx_ptype_5numpy_ndarray, 1, "arr", 0))) __PYX_ERR(0, 209, __pyx_L1_error)
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_compression_ratios), (&PyList_Type), 1, "compression_ratios", 1))) __PYX_ERR(0, 213, __pyx_L1_error)
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_signal_noise_ratios), (&PyList_Type), 1, "signal_noise_ratios", 1))) __PYX_ERR(0, 214, __pyx_L1_error)
+  __pyx_r = __pyx_pf_9_openjpeg_6encode_array(__pyx_self, __pyx_v_arr, __pyx_v_bits_stored, __pyx_v_photometric_interpretation, __pyx_v_use_mct, __pyx_v_compression_ratios, __pyx_v_signal_noise_ratios, __pyx_v_codec_format);
 
   /* function exit code */
   goto __pyx_L0;
@@ -6537,7 +6666,7 @@ PyObject *__pyx_args, PyObject *__pyx_kwds
   return __pyx_r;
 }
 
-static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self, PyArrayObject *__pyx_v_arr, int __pyx_v_bits_stored, int __pyx_v_photometric_interpretation, int __pyx_v_use_mct, PyObject *__pyx_v_compression_ratios, PyObject *__pyx_v_signal_noise_ratios, int __pyx_v_codec_format) {
+static PyObject *__pyx_pf_9_openjpeg_6encode_array(CYTHON_UNUSED PyObject *__pyx_self, PyArrayObject *__pyx_v_arr, int __pyx_v_bits_stored, int __pyx_v_photometric_interpretation, int __pyx_v_use_mct, PyObject *__pyx_v_compression_ratios, PyObject *__pyx_v_signal_noise_ratios, int __pyx_v_codec_format) {
   PyObject *__pyx_v_allowed = NULL;
   PyObject *__pyx_v_arr_max = NULL;
   PyObject *__pyx_v_arr_min = NULL;
@@ -6563,47 +6692,47 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("encode", 0);
+  __Pyx_RefNannySetupContext("encode_array", 0);
   __Pyx_INCREF(__pyx_v_compression_ratios);
   __Pyx_INCREF(__pyx_v_signal_noise_ratios);
 
-  /* "_openjpeg.pyx":237
- *         encoding failed.
+  /* "_openjpeg.pyx":249
+ *         code will be ``0`` for success, otherwise the encoding failed.
  *     """
  *     if not (1 <= bits_stored <= arr.dtype.itemsize * 8):             # <<<<<<<<<<<<<<
  *         raise ValueError(
  *             "Invalid value for the 'bits_stored' parameter, the value must be "
  */
-  __pyx_t_1 = __Pyx_PyInt_From_int(__pyx_v_bits_stored); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 237, __pyx_L1_error)
+  __pyx_t_1 = __Pyx_PyInt_From_int(__pyx_v_bits_stored); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 249, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
-  __pyx_t_2 = PyObject_RichCompare(__pyx_int_1, __pyx_t_1, Py_LE); __Pyx_XGOTREF(__pyx_t_2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 237, __pyx_L1_error)
+  __pyx_t_2 = PyObject_RichCompare(__pyx_int_1, __pyx_t_1, Py_LE); __Pyx_XGOTREF(__pyx_t_2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 249, __pyx_L1_error)
   if (__Pyx_PyObject_IsTrue(__pyx_t_2)) {
     __Pyx_DECREF(__pyx_t_2);
-    __pyx_t_3 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_arr), __pyx_n_s_dtype); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 237, __pyx_L1_error)
+    __pyx_t_3 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_arr), __pyx_n_s_dtype); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 249, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_3);
-    __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_itemsize); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 237, __pyx_L1_error)
+    __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_itemsize); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 249, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_4);
     __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-    __pyx_t_3 = __Pyx_PyInt_MultiplyObjC(__pyx_t_4, __pyx_int_8, 8, 0, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 237, __pyx_L1_error)
+    __pyx_t_3 = __Pyx_PyInt_MultiplyObjC(__pyx_t_4, __pyx_int_8, 8, 0, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 249, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_3);
     __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
-    __pyx_t_2 = PyObject_RichCompare(__pyx_t_1, __pyx_t_3, Py_LE); __Pyx_XGOTREF(__pyx_t_2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 237, __pyx_L1_error)
+    __pyx_t_2 = PyObject_RichCompare(__pyx_t_1, __pyx_t_3, Py_LE); __Pyx_XGOTREF(__pyx_t_2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 249, __pyx_L1_error)
     __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
   }
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-  __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely((__pyx_t_5 < 0))) __PYX_ERR(0, 237, __pyx_L1_error)
+  __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely((__pyx_t_5 < 0))) __PYX_ERR(0, 249, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
   __pyx_t_6 = (!__pyx_t_5);
   if (unlikely(__pyx_t_6)) {
 
-    /* "_openjpeg.pyx":239
+    /* "_openjpeg.pyx":251
  *     if not (1 <= bits_stored <= arr.dtype.itemsize * 8):
  *         raise ValueError(
  *             "Invalid value for the 'bits_stored' parameter, the value must be "             # <<<<<<<<<<<<<<
  *             f"in the range (1, {arr.dtype.itemsize * 8})"
  *         )
  */
-    __pyx_t_2 = PyTuple_New(3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 239, __pyx_L1_error)
+    __pyx_t_2 = PyTuple_New(3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 251, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_2);
     __pyx_t_7 = 0;
     __pyx_t_8 = 127;
@@ -6612,22 +6741,22 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
     __Pyx_GIVEREF(__pyx_kp_u_Invalid_value_for_the_bits_store);
     PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_kp_u_Invalid_value_for_the_bits_store);
 
-    /* "_openjpeg.pyx":240
+    /* "_openjpeg.pyx":252
  *         raise ValueError(
  *             "Invalid value for the 'bits_stored' parameter, the value must be "
  *             f"in the range (1, {arr.dtype.itemsize * 8})"             # <<<<<<<<<<<<<<
  *         )
  * 
  */
-    __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_arr), __pyx_n_s_dtype); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 240, __pyx_L1_error)
+    __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_arr), __pyx_n_s_dtype); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 252, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_1);
-    __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_itemsize); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 240, __pyx_L1_error)
+    __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_itemsize); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 252, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_3);
     __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-    __pyx_t_1 = __Pyx_PyInt_MultiplyObjC(__pyx_t_3, __pyx_int_8, 8, 0, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 240, __pyx_L1_error)
+    __pyx_t_1 = __Pyx_PyInt_MultiplyObjC(__pyx_t_3, __pyx_int_8, 8, 0, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 252, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_1);
     __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-    __pyx_t_3 = __Pyx_PyObject_FormatSimple(__pyx_t_1, __pyx_empty_unicode); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 240, __pyx_L1_error)
+    __pyx_t_3 = __Pyx_PyObject_FormatSimple(__pyx_t_1, __pyx_empty_unicode); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 252, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_3);
     __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
     __pyx_t_8 = (__Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_3) > __pyx_t_8) ? __Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_3) : __pyx_t_8;
@@ -6640,33 +6769,33 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
     __Pyx_GIVEREF(__pyx_kp_u__4);
     PyTuple_SET_ITEM(__pyx_t_2, 2, __pyx_kp_u__4);
 
-    /* "_openjpeg.pyx":239
+    /* "_openjpeg.pyx":251
  *     if not (1 <= bits_stored <= arr.dtype.itemsize * 8):
  *         raise ValueError(
  *             "Invalid value for the 'bits_stored' parameter, the value must be "             # <<<<<<<<<<<<<<
  *             f"in the range (1, {arr.dtype.itemsize * 8})"
  *         )
  */
-    __pyx_t_3 = __Pyx_PyUnicode_Join(__pyx_t_2, 3, __pyx_t_7, __pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 239, __pyx_L1_error)
+    __pyx_t_3 = __Pyx_PyUnicode_Join(__pyx_t_2, 3, __pyx_t_7, __pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 251, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_3);
     __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 
-    /* "_openjpeg.pyx":238
+    /* "_openjpeg.pyx":250
  *     """
  *     if not (1 <= bits_stored <= arr.dtype.itemsize * 8):
  *         raise ValueError(             # <<<<<<<<<<<<<<
  *             "Invalid value for the 'bits_stored' parameter, the value must be "
  *             f"in the range (1, {arr.dtype.itemsize * 8})"
  */
-    __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 238, __pyx_L1_error)
+    __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 250, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_2);
     __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
     __Pyx_Raise(__pyx_t_2, 0, 0, 0);
     __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-    __PYX_ERR(0, 238, __pyx_L1_error)
+    __PYX_ERR(0, 250, __pyx_L1_error)
 
-    /* "_openjpeg.pyx":237
- *         encoding failed.
+    /* "_openjpeg.pyx":249
+ *         code will be ``0`` for success, otherwise the encoding failed.
  *     """
  *     if not (1 <= bits_stored <= arr.dtype.itemsize * 8):             # <<<<<<<<<<<<<<
  *         raise ValueError(
@@ -6674,60 +6803,60 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
  */
   }
 
-  /* "_openjpeg.pyx":243
+  /* "_openjpeg.pyx":255
  *         )
  * 
  *     allowed = (bool, np.uint8, np.int8, np.uint16, np.int16, np.uint32, np.int32)             # <<<<<<<<<<<<<<
  *     if arr.dtype not in allowed:
  *         raise ValueError(
  */
-  __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 243, __pyx_L1_error)
+  __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 255, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_uint8); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 243, __pyx_L1_error)
+  __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_uint8); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 255, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_3);
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-  __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 243, __pyx_L1_error)
+  __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 255, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_int8); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 243, __pyx_L1_error)
+  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_int8); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 255, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-  __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 243, __pyx_L1_error)
+  __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 255, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_uint16); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 243, __pyx_L1_error)
+  __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_uint16); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 255, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_4);
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-  __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 243, __pyx_L1_error)
+  __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 255, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_int16); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 243, __pyx_L1_error)
+  __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_int16); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 255, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_9);
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-  __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 243, __pyx_L1_error)
+  __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 255, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_uint32); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 243, __pyx_L1_error)
+  __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_uint32); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 255, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_10);
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-  __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 243, __pyx_L1_error)
+  __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 255, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  __pyx_t_11 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_int32); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 243, __pyx_L1_error)
+  __pyx_t_11 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_int32); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 255, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_11);
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-  __pyx_t_2 = PyTuple_New(7); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 243, __pyx_L1_error)
+  __pyx_t_2 = PyTuple_New(7); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 255, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
   __Pyx_INCREF(((PyObject*)&PyBool_Type));
   __Pyx_GIVEREF(((PyObject*)&PyBool_Type));
-  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 0, ((PyObject*)&PyBool_Type))) __PYX_ERR(0, 243, __pyx_L1_error);
+  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 0, ((PyObject*)&PyBool_Type))) __PYX_ERR(0, 255, __pyx_L1_error);
   __Pyx_GIVEREF(__pyx_t_3);
-  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_t_3)) __PYX_ERR(0, 243, __pyx_L1_error);
+  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_t_3)) __PYX_ERR(0, 255, __pyx_L1_error);
   __Pyx_GIVEREF(__pyx_t_1);
-  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 2, __pyx_t_1)) __PYX_ERR(0, 243, __pyx_L1_error);
+  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 2, __pyx_t_1)) __PYX_ERR(0, 255, __pyx_L1_error);
   __Pyx_GIVEREF(__pyx_t_4);
-  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 3, __pyx_t_4)) __PYX_ERR(0, 243, __pyx_L1_error);
+  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 3, __pyx_t_4)) __PYX_ERR(0, 255, __pyx_L1_error);
   __Pyx_GIVEREF(__pyx_t_9);
-  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 4, __pyx_t_9)) __PYX_ERR(0, 243, __pyx_L1_error);
+  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 4, __pyx_t_9)) __PYX_ERR(0, 255, __pyx_L1_error);
   __Pyx_GIVEREF(__pyx_t_10);
-  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 5, __pyx_t_10)) __PYX_ERR(0, 243, __pyx_L1_error);
+  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 5, __pyx_t_10)) __PYX_ERR(0, 255, __pyx_L1_error);
   __Pyx_GIVEREF(__pyx_t_11);
-  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 6, __pyx_t_11)) __PYX_ERR(0, 243, __pyx_L1_error);
+  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 6, __pyx_t_11)) __PYX_ERR(0, 255, __pyx_L1_error);
   __pyx_t_3 = 0;
   __pyx_t_1 = 0;
   __pyx_t_4 = 0;
@@ -6737,27 +6866,27 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
   __pyx_v_allowed = ((PyObject*)__pyx_t_2);
   __pyx_t_2 = 0;
 
-  /* "_openjpeg.pyx":244
+  /* "_openjpeg.pyx":256
  * 
  *     allowed = (bool, np.uint8, np.int8, np.uint16, np.int16, np.uint32, np.int32)
  *     if arr.dtype not in allowed:             # <<<<<<<<<<<<<<
  *         raise ValueError(
  *             f"The input array has an unsupported dtype '{arr.dtype}', only bool, "
  */
-  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_arr), __pyx_n_s_dtype); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 244, __pyx_L1_error)
+  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_arr), __pyx_n_s_dtype); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 256, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  __pyx_t_6 = (__Pyx_PySequence_ContainsTF(__pyx_t_2, __pyx_v_allowed, Py_NE)); if (unlikely((__pyx_t_6 < 0))) __PYX_ERR(0, 244, __pyx_L1_error)
+  __pyx_t_6 = (__Pyx_PySequence_ContainsTF(__pyx_t_2, __pyx_v_allowed, Py_NE)); if (unlikely((__pyx_t_6 < 0))) __PYX_ERR(0, 256, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
   if (unlikely(__pyx_t_6)) {
 
-    /* "_openjpeg.pyx":246
+    /* "_openjpeg.pyx":258
  *     if arr.dtype not in allowed:
  *         raise ValueError(
  *             f"The input array has an unsupported dtype '{arr.dtype}', only bool, "             # <<<<<<<<<<<<<<
  *             "u1, u2, u4, i1, i2 and i4 are supported"
  *         )
  */
-    __pyx_t_2 = PyTuple_New(3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 246, __pyx_L1_error)
+    __pyx_t_2 = PyTuple_New(3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 258, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_2);
     __pyx_t_7 = 0;
     __pyx_t_8 = 127;
@@ -6765,9 +6894,9 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
     __pyx_t_7 += 42;
     __Pyx_GIVEREF(__pyx_kp_u_The_input_array_has_an_unsupport);
     PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_kp_u_The_input_array_has_an_unsupport);
-    __pyx_t_11 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_arr), __pyx_n_s_dtype); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 246, __pyx_L1_error)
+    __pyx_t_11 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_arr), __pyx_n_s_dtype); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 258, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_11);
-    __pyx_t_10 = __Pyx_PyObject_FormatSimple(__pyx_t_11, __pyx_empty_unicode); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 246, __pyx_L1_error)
+    __pyx_t_10 = __Pyx_PyObject_FormatSimple(__pyx_t_11, __pyx_empty_unicode); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 258, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_10);
     __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
     __pyx_t_8 = (__Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_10) > __pyx_t_8) ? __Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_10) : __pyx_t_8;
@@ -6779,25 +6908,25 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
     __pyx_t_7 += 53;
     __Pyx_GIVEREF(__pyx_kp_u_only_bool_u1_u2_u4_i1_i2_and_i4);
     PyTuple_SET_ITEM(__pyx_t_2, 2, __pyx_kp_u_only_bool_u1_u2_u4_i1_i2_and_i4);
-    __pyx_t_10 = __Pyx_PyUnicode_Join(__pyx_t_2, 3, __pyx_t_7, __pyx_t_8); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 246, __pyx_L1_error)
+    __pyx_t_10 = __Pyx_PyUnicode_Join(__pyx_t_2, 3, __pyx_t_7, __pyx_t_8); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 258, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_10);
     __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 
-    /* "_openjpeg.pyx":245
+    /* "_openjpeg.pyx":257
  *     allowed = (bool, np.uint8, np.int8, np.uint16, np.int16, np.uint32, np.int32)
  *     if arr.dtype not in allowed:
  *         raise ValueError(             # <<<<<<<<<<<<<<
  *             f"The input array has an unsupported dtype '{arr.dtype}', only bool, "
  *             "u1, u2, u4, i1, i2 and i4 are supported"
  */
-    __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_10); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 245, __pyx_L1_error)
+    __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_10); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 257, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_2);
     __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
     __Pyx_Raise(__pyx_t_2, 0, 0, 0);
     __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-    __PYX_ERR(0, 245, __pyx_L1_error)
+    __PYX_ERR(0, 257, __pyx_L1_error)
 
-    /* "_openjpeg.pyx":244
+    /* "_openjpeg.pyx":256
  * 
  *     allowed = (bool, np.uint8, np.int8, np.uint16, np.int16, np.uint32, np.int32)
  *     if arr.dtype not in allowed:             # <<<<<<<<<<<<<<
@@ -6806,14 +6935,14 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
  */
   }
 
-  /* "_openjpeg.pyx":253
+  /* "_openjpeg.pyx":265
  *     #   based on their use of OPJ_INT32 for pixel values, it should be 32-bit for
  *     #   signed and 31 bit for unsigned. Maybe I've made a mistake somewhere?
  *     arr_max = arr.max()             # <<<<<<<<<<<<<<
  *     arr_min = arr.min()
  *     if (
  */
-  __pyx_t_10 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_arr), __pyx_n_s_max); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 253, __pyx_L1_error)
+  __pyx_t_10 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_arr), __pyx_n_s_max); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 265, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_10);
   __pyx_t_11 = NULL;
   __pyx_t_12 = 0;
@@ -6833,21 +6962,21 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
     PyObject *__pyx_callargs[2] = {__pyx_t_11, NULL};
     __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_10, __pyx_callargs+1-__pyx_t_12, 0+__pyx_t_12);
     __Pyx_XDECREF(__pyx_t_11); __pyx_t_11 = 0;
-    if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 253, __pyx_L1_error)
+    if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 265, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_2);
     __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
   }
   __pyx_v_arr_max = __pyx_t_2;
   __pyx_t_2 = 0;
 
-  /* "_openjpeg.pyx":254
+  /* "_openjpeg.pyx":266
  *     #   signed and 31 bit for unsigned. Maybe I've made a mistake somewhere?
  *     arr_max = arr.max()
  *     arr_min = arr.min()             # <<<<<<<<<<<<<<
  *     if (
  *         (arr.dtype == np.uint32 and arr_max > 2**24 - 1)
  */
-  __pyx_t_10 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_arr), __pyx_n_s_min); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 254, __pyx_L1_error)
+  __pyx_t_10 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_arr), __pyx_n_s_min); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 266, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_10);
   __pyx_t_11 = NULL;
   __pyx_t_12 = 0;
@@ -6867,38 +6996,38 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
     PyObject *__pyx_callargs[2] = {__pyx_t_11, NULL};
     __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_10, __pyx_callargs+1-__pyx_t_12, 0+__pyx_t_12);
     __Pyx_XDECREF(__pyx_t_11); __pyx_t_11 = 0;
-    if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 254, __pyx_L1_error)
+    if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 266, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_2);
     __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
   }
   __pyx_v_arr_min = __pyx_t_2;
   __pyx_t_2 = 0;
 
-  /* "_openjpeg.pyx":256
+  /* "_openjpeg.pyx":268
  *     arr_min = arr.min()
  *     if (
  *         (arr.dtype == np.uint32 and arr_max > 2**24 - 1)             # <<<<<<<<<<<<<<
  *         or (arr.dtype == np.int32 and (arr_max > 2**23 - 1 or arr_min < -2**23))
  *     ):
  */
-  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_arr), __pyx_n_s_dtype); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 256, __pyx_L1_error)
+  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_arr), __pyx_n_s_dtype); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 268, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  __Pyx_GetModuleGlobalName(__pyx_t_10, __pyx_n_s_np); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 256, __pyx_L1_error)
+  __Pyx_GetModuleGlobalName(__pyx_t_10, __pyx_n_s_np); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 268, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_10);
-  __pyx_t_11 = __Pyx_PyObject_GetAttrStr(__pyx_t_10, __pyx_n_s_uint32); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 256, __pyx_L1_error)
+  __pyx_t_11 = __Pyx_PyObject_GetAttrStr(__pyx_t_10, __pyx_n_s_uint32); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 268, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_11);
   __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
-  __pyx_t_10 = PyObject_RichCompare(__pyx_t_2, __pyx_t_11, Py_EQ); __Pyx_XGOTREF(__pyx_t_10); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 256, __pyx_L1_error)
+  __pyx_t_10 = PyObject_RichCompare(__pyx_t_2, __pyx_t_11, Py_EQ); __Pyx_XGOTREF(__pyx_t_10); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 268, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
   __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
-  __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_10); if (unlikely((__pyx_t_5 < 0))) __PYX_ERR(0, 256, __pyx_L1_error)
+  __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_10); if (unlikely((__pyx_t_5 < 0))) __PYX_ERR(0, 268, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
   if (!__pyx_t_5) {
     goto __pyx_L7_next_or;
   } else {
   }
-  __pyx_t_10 = PyObject_RichCompare(__pyx_v_arr_max, __pyx_int_16777215, Py_GT); __Pyx_XGOTREF(__pyx_t_10); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 256, __pyx_L1_error)
-  __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_10); if (unlikely((__pyx_t_5 < 0))) __PYX_ERR(0, 256, __pyx_L1_error)
+  __pyx_t_10 = PyObject_RichCompare(__pyx_v_arr_max, __pyx_int_16777215, Py_GT); __Pyx_XGOTREF(__pyx_t_10); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 268, __pyx_L1_error)
+  __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_10); if (unlikely((__pyx_t_5 < 0))) __PYX_ERR(0, 268, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
   if (!__pyx_t_5) {
   } else {
@@ -6907,45 +7036,45 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
   }
   __pyx_L7_next_or:;
 
-  /* "_openjpeg.pyx":257
+  /* "_openjpeg.pyx":269
  *     if (
  *         (arr.dtype == np.uint32 and arr_max > 2**24 - 1)
  *         or (arr.dtype == np.int32 and (arr_max > 2**23 - 1 or arr_min < -2**23))             # <<<<<<<<<<<<<<
  *     ):
  *         raise ValueError(
  */
-  __pyx_t_10 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_arr), __pyx_n_s_dtype); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 257, __pyx_L1_error)
+  __pyx_t_10 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_arr), __pyx_n_s_dtype); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 269, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_10);
-  __Pyx_GetModuleGlobalName(__pyx_t_11, __pyx_n_s_np); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 257, __pyx_L1_error)
+  __Pyx_GetModuleGlobalName(__pyx_t_11, __pyx_n_s_np); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 269, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_11);
-  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_11, __pyx_n_s_int32); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 257, __pyx_L1_error)
+  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_11, __pyx_n_s_int32); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 269, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
   __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
-  __pyx_t_11 = PyObject_RichCompare(__pyx_t_10, __pyx_t_2, Py_EQ); __Pyx_XGOTREF(__pyx_t_11); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 257, __pyx_L1_error)
+  __pyx_t_11 = PyObject_RichCompare(__pyx_t_10, __pyx_t_2, Py_EQ); __Pyx_XGOTREF(__pyx_t_11); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 269, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-  __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_11); if (unlikely((__pyx_t_5 < 0))) __PYX_ERR(0, 257, __pyx_L1_error)
+  __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_11); if (unlikely((__pyx_t_5 < 0))) __PYX_ERR(0, 269, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
   if (__pyx_t_5) {
   } else {
     __pyx_t_6 = __pyx_t_5;
     goto __pyx_L6_bool_binop_done;
   }
-  __pyx_t_11 = PyObject_RichCompare(__pyx_v_arr_max, __pyx_int_8388607, Py_GT); __Pyx_XGOTREF(__pyx_t_11); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 257, __pyx_L1_error)
-  __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_11); if (unlikely((__pyx_t_5 < 0))) __PYX_ERR(0, 257, __pyx_L1_error)
+  __pyx_t_11 = PyObject_RichCompare(__pyx_v_arr_max, __pyx_int_8388607, Py_GT); __Pyx_XGOTREF(__pyx_t_11); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 269, __pyx_L1_error)
+  __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_11); if (unlikely((__pyx_t_5 < 0))) __PYX_ERR(0, 269, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
   if (!__pyx_t_5) {
   } else {
     __pyx_t_6 = __pyx_t_5;
     goto __pyx_L6_bool_binop_done;
   }
-  __pyx_t_11 = PyObject_RichCompare(__pyx_v_arr_min, __pyx_int_neg_8388608, Py_LT); __Pyx_XGOTREF(__pyx_t_11); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 257, __pyx_L1_error)
-  __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_11); if (unlikely((__pyx_t_5 < 0))) __PYX_ERR(0, 257, __pyx_L1_error)
+  __pyx_t_11 = PyObject_RichCompare(__pyx_v_arr_min, __pyx_int_neg_8388608, Py_LT); __Pyx_XGOTREF(__pyx_t_11); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 269, __pyx_L1_error)
+  __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_11); if (unlikely((__pyx_t_5 < 0))) __PYX_ERR(0, 269, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
   __pyx_t_6 = __pyx_t_5;
   __pyx_L6_bool_binop_done:;
 
-  /* "_openjpeg.pyx":255
+  /* "_openjpeg.pyx":267
  *     arr_max = arr.max()
  *     arr_min = arr.min()
  *     if (             # <<<<<<<<<<<<<<
@@ -6954,20 +7083,20 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
  */
   if (unlikely(__pyx_t_6)) {
 
-    /* "_openjpeg.pyx":259
+    /* "_openjpeg.pyx":271
  *         or (arr.dtype == np.int32 and (arr_max > 2**23 - 1 or arr_min < -2**23))
  *     ):
  *         raise ValueError(             # <<<<<<<<<<<<<<
  *             "The input array contains values outside the range of the maximum "
  *             "supported bit-depth of 24"
  */
-    __pyx_t_11 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__5, NULL); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 259, __pyx_L1_error)
+    __pyx_t_11 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__5, NULL); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 271, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_11);
     __Pyx_Raise(__pyx_t_11, 0, 0, 0);
     __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
-    __PYX_ERR(0, 259, __pyx_L1_error)
+    __PYX_ERR(0, 271, __pyx_L1_error)
 
-    /* "_openjpeg.pyx":255
+    /* "_openjpeg.pyx":267
  *     arr_max = arr.max()
  *     arr_min = arr.min()
  *     if (             # <<<<<<<<<<<<<<
@@ -6976,51 +7105,51 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
  */
   }
 
-  /* "_openjpeg.pyx":265
+  /* "_openjpeg.pyx":277
  * 
  *     # Check the array matches bits_stored
  *     if arr.dtype in (np.uint8, np.uint16, np.uint32) and arr_max > 2**bits_stored - 1:             # <<<<<<<<<<<<<<
  *         raise ValueError(
  *             f"A 'bits_stored' value of {bits_stored} is incompatible with "
  */
-  __pyx_t_11 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_arr), __pyx_n_s_dtype); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 265, __pyx_L1_error)
+  __pyx_t_11 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_arr), __pyx_n_s_dtype); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 277, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_11);
-  __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 265, __pyx_L1_error)
+  __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 277, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_uint8); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 265, __pyx_L1_error)
+  __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_uint8); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 277, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_10);
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-  __pyx_t_2 = PyObject_RichCompare(__pyx_t_11, __pyx_t_10, Py_EQ); __Pyx_XGOTREF(__pyx_t_2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 265, __pyx_L1_error)
+  __pyx_t_2 = PyObject_RichCompare(__pyx_t_11, __pyx_t_10, Py_EQ); __Pyx_XGOTREF(__pyx_t_2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 277, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
-  __pyx_t_13 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely((__pyx_t_13 < 0))) __PYX_ERR(0, 265, __pyx_L1_error)
+  __pyx_t_13 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely((__pyx_t_13 < 0))) __PYX_ERR(0, 277, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
   if (!__pyx_t_13) {
   } else {
     __pyx_t_5 = __pyx_t_13;
     goto __pyx_L14_bool_binop_done;
   }
-  __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 265, __pyx_L1_error)
+  __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 277, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_uint16); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 265, __pyx_L1_error)
+  __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_uint16); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 277, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_10);
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-  __pyx_t_2 = PyObject_RichCompare(__pyx_t_11, __pyx_t_10, Py_EQ); __Pyx_XGOTREF(__pyx_t_2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 265, __pyx_L1_error)
+  __pyx_t_2 = PyObject_RichCompare(__pyx_t_11, __pyx_t_10, Py_EQ); __Pyx_XGOTREF(__pyx_t_2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 277, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
-  __pyx_t_13 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely((__pyx_t_13 < 0))) __PYX_ERR(0, 265, __pyx_L1_error)
+  __pyx_t_13 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely((__pyx_t_13 < 0))) __PYX_ERR(0, 277, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
   if (!__pyx_t_13) {
   } else {
     __pyx_t_5 = __pyx_t_13;
     goto __pyx_L14_bool_binop_done;
   }
-  __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 265, __pyx_L1_error)
+  __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 277, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_uint32); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 265, __pyx_L1_error)
+  __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_uint32); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 277, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_10);
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-  __pyx_t_2 = PyObject_RichCompare(__pyx_t_11, __pyx_t_10, Py_EQ); __Pyx_XGOTREF(__pyx_t_2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 265, __pyx_L1_error)
+  __pyx_t_2 = PyObject_RichCompare(__pyx_t_11, __pyx_t_10, Py_EQ); __Pyx_XGOTREF(__pyx_t_2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 277, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
-  __pyx_t_13 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely((__pyx_t_13 < 0))) __PYX_ERR(0, 265, __pyx_L1_error)
+  __pyx_t_13 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely((__pyx_t_13 < 0))) __PYX_ERR(0, 277, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
   __pyx_t_5 = __pyx_t_13;
   __pyx_L14_bool_binop_done:;
@@ -7031,24 +7160,24 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
     __pyx_t_6 = __pyx_t_13;
     goto __pyx_L12_bool_binop_done;
   }
-  __pyx_t_11 = PyFloat_FromDouble((pow(2.0, ((double)__pyx_v_bits_stored)) - 1.0)); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 265, __pyx_L1_error)
+  __pyx_t_11 = PyFloat_FromDouble((pow(2.0, ((double)__pyx_v_bits_stored)) - 1.0)); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 277, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_11);
-  __pyx_t_2 = PyObject_RichCompare(__pyx_v_arr_max, __pyx_t_11, Py_GT); __Pyx_XGOTREF(__pyx_t_2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 265, __pyx_L1_error)
+  __pyx_t_2 = PyObject_RichCompare(__pyx_v_arr_max, __pyx_t_11, Py_GT); __Pyx_XGOTREF(__pyx_t_2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 277, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
-  __pyx_t_13 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely((__pyx_t_13 < 0))) __PYX_ERR(0, 265, __pyx_L1_error)
+  __pyx_t_13 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely((__pyx_t_13 < 0))) __PYX_ERR(0, 277, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
   __pyx_t_6 = __pyx_t_13;
   __pyx_L12_bool_binop_done:;
   if (unlikely(__pyx_t_6)) {
 
-    /* "_openjpeg.pyx":267
+    /* "_openjpeg.pyx":279
  *     if arr.dtype in (np.uint8, np.uint16, np.uint32) and arr_max > 2**bits_stored - 1:
  *         raise ValueError(
  *             f"A 'bits_stored' value of {bits_stored} is incompatible with "             # <<<<<<<<<<<<<<
  *             f"the range of pixel data in the input array: ({arr_min}, {arr_max})"
  *         )
  */
-    __pyx_t_2 = PyTuple_New(7); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 267, __pyx_L1_error)
+    __pyx_t_2 = PyTuple_New(7); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 279, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_2);
     __pyx_t_7 = 0;
     __pyx_t_8 = 127;
@@ -7056,7 +7185,7 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
     __pyx_t_7 += 25;
     __Pyx_GIVEREF(__pyx_kp_u_A_bits_stored_value_of);
     PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_kp_u_A_bits_stored_value_of);
-    __pyx_t_11 = __Pyx_PyUnicode_From_int(__pyx_v_bits_stored, 0, ' ', 'd'); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 267, __pyx_L1_error)
+    __pyx_t_11 = __Pyx_PyUnicode_From_int(__pyx_v_bits_stored, 0, ' ', 'd'); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 279, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_11);
     __pyx_t_7 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_11);
     __Pyx_GIVEREF(__pyx_t_11);
@@ -7067,14 +7196,14 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
     __Pyx_GIVEREF(__pyx_kp_u_is_incompatible_with_the_range);
     PyTuple_SET_ITEM(__pyx_t_2, 2, __pyx_kp_u_is_incompatible_with_the_range);
 
-    /* "_openjpeg.pyx":268
+    /* "_openjpeg.pyx":280
  *         raise ValueError(
  *             f"A 'bits_stored' value of {bits_stored} is incompatible with "
  *             f"the range of pixel data in the input array: ({arr_min}, {arr_max})"             # <<<<<<<<<<<<<<
  *         )
  * 
  */
-    __pyx_t_11 = __Pyx_PyObject_FormatSimple(__pyx_v_arr_min, __pyx_empty_unicode); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 268, __pyx_L1_error)
+    __pyx_t_11 = __Pyx_PyObject_FormatSimple(__pyx_v_arr_min, __pyx_empty_unicode); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 280, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_11);
     __pyx_t_8 = (__Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_11) > __pyx_t_8) ? __Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_11) : __pyx_t_8;
     __pyx_t_7 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_11);
@@ -7085,7 +7214,7 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
     __pyx_t_7 += 2;
     __Pyx_GIVEREF(__pyx_kp_u__6);
     PyTuple_SET_ITEM(__pyx_t_2, 4, __pyx_kp_u__6);
-    __pyx_t_11 = __Pyx_PyObject_FormatSimple(__pyx_v_arr_max, __pyx_empty_unicode); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 268, __pyx_L1_error)
+    __pyx_t_11 = __Pyx_PyObject_FormatSimple(__pyx_v_arr_max, __pyx_empty_unicode); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 280, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_11);
     __pyx_t_8 = (__Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_11) > __pyx_t_8) ? __Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_11) : __pyx_t_8;
     __pyx_t_7 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_11);
@@ -7097,32 +7226,32 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
     __Pyx_GIVEREF(__pyx_kp_u__4);
     PyTuple_SET_ITEM(__pyx_t_2, 6, __pyx_kp_u__4);
 
-    /* "_openjpeg.pyx":267
+    /* "_openjpeg.pyx":279
  *     if arr.dtype in (np.uint8, np.uint16, np.uint32) and arr_max > 2**bits_stored - 1:
  *         raise ValueError(
  *             f"A 'bits_stored' value of {bits_stored} is incompatible with "             # <<<<<<<<<<<<<<
  *             f"the range of pixel data in the input array: ({arr_min}, {arr_max})"
  *         )
  */
-    __pyx_t_11 = __Pyx_PyUnicode_Join(__pyx_t_2, 7, __pyx_t_7, __pyx_t_8); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 267, __pyx_L1_error)
+    __pyx_t_11 = __Pyx_PyUnicode_Join(__pyx_t_2, 7, __pyx_t_7, __pyx_t_8); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 279, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_11);
     __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 
-    /* "_openjpeg.pyx":266
+    /* "_openjpeg.pyx":278
  *     # Check the array matches bits_stored
  *     if arr.dtype in (np.uint8, np.uint16, np.uint32) and arr_max > 2**bits_stored - 1:
  *         raise ValueError(             # <<<<<<<<<<<<<<
  *             f"A 'bits_stored' value of {bits_stored} is incompatible with "
  *             f"the range of pixel data in the input array: ({arr_min}, {arr_max})"
  */
-    __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_11); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 266, __pyx_L1_error)
+    __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_11); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 278, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_2);
     __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
     __Pyx_Raise(__pyx_t_2, 0, 0, 0);
     __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-    __PYX_ERR(0, 266, __pyx_L1_error)
+    __PYX_ERR(0, 278, __pyx_L1_error)
 
-    /* "_openjpeg.pyx":265
+    /* "_openjpeg.pyx":277
  * 
  *     # Check the array matches bits_stored
  *     if arr.dtype in (np.uint8, np.uint16, np.uint32) and arr_max > 2**bits_stored - 1:             # <<<<<<<<<<<<<<
@@ -7131,51 +7260,51 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
  */
   }
 
-  /* "_openjpeg.pyx":272
+  /* "_openjpeg.pyx":284
  * 
  *     if (
  *         arr.dtype in (np.int8, np.int16, np.int32)             # <<<<<<<<<<<<<<
  *         and (arr_max > 2**(bits_stored - 1) - 1 or arr_min < -2**(bits_stored - 1))
  *     ):
  */
-  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_arr), __pyx_n_s_dtype); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 272, __pyx_L1_error)
+  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_arr), __pyx_n_s_dtype); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 284, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  __Pyx_GetModuleGlobalName(__pyx_t_11, __pyx_n_s_np); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 272, __pyx_L1_error)
+  __Pyx_GetModuleGlobalName(__pyx_t_11, __pyx_n_s_np); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 284, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_11);
-  __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_11, __pyx_n_s_int8); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 272, __pyx_L1_error)
+  __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_11, __pyx_n_s_int8); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 284, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_10);
   __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
-  __pyx_t_11 = PyObject_RichCompare(__pyx_t_2, __pyx_t_10, Py_EQ); __Pyx_XGOTREF(__pyx_t_11); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 272, __pyx_L1_error)
+  __pyx_t_11 = PyObject_RichCompare(__pyx_t_2, __pyx_t_10, Py_EQ); __Pyx_XGOTREF(__pyx_t_11); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 284, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
-  __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_11); if (unlikely((__pyx_t_5 < 0))) __PYX_ERR(0, 272, __pyx_L1_error)
+  __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_11); if (unlikely((__pyx_t_5 < 0))) __PYX_ERR(0, 284, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
   if (!__pyx_t_5) {
   } else {
     __pyx_t_13 = __pyx_t_5;
     goto __pyx_L20_bool_binop_done;
   }
-  __Pyx_GetModuleGlobalName(__pyx_t_11, __pyx_n_s_np); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 272, __pyx_L1_error)
+  __Pyx_GetModuleGlobalName(__pyx_t_11, __pyx_n_s_np); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 284, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_11);
-  __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_11, __pyx_n_s_int16); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 272, __pyx_L1_error)
+  __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_11, __pyx_n_s_int16); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 284, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_10);
   __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
-  __pyx_t_11 = PyObject_RichCompare(__pyx_t_2, __pyx_t_10, Py_EQ); __Pyx_XGOTREF(__pyx_t_11); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 272, __pyx_L1_error)
+  __pyx_t_11 = PyObject_RichCompare(__pyx_t_2, __pyx_t_10, Py_EQ); __Pyx_XGOTREF(__pyx_t_11); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 284, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
-  __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_11); if (unlikely((__pyx_t_5 < 0))) __PYX_ERR(0, 272, __pyx_L1_error)
+  __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_11); if (unlikely((__pyx_t_5 < 0))) __PYX_ERR(0, 284, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
   if (!__pyx_t_5) {
   } else {
     __pyx_t_13 = __pyx_t_5;
     goto __pyx_L20_bool_binop_done;
   }
-  __Pyx_GetModuleGlobalName(__pyx_t_11, __pyx_n_s_np); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 272, __pyx_L1_error)
+  __Pyx_GetModuleGlobalName(__pyx_t_11, __pyx_n_s_np); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 284, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_11);
-  __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_11, __pyx_n_s_int32); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 272, __pyx_L1_error)
+  __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_11, __pyx_n_s_int32); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 284, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_10);
   __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
-  __pyx_t_11 = PyObject_RichCompare(__pyx_t_2, __pyx_t_10, Py_EQ); __Pyx_XGOTREF(__pyx_t_11); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 272, __pyx_L1_error)
+  __pyx_t_11 = PyObject_RichCompare(__pyx_t_2, __pyx_t_10, Py_EQ); __Pyx_XGOTREF(__pyx_t_11); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 284, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
-  __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_11); if (unlikely((__pyx_t_5 < 0))) __PYX_ERR(0, 272, __pyx_L1_error)
+  __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_11); if (unlikely((__pyx_t_5 < 0))) __PYX_ERR(0, 284, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
   __pyx_t_13 = __pyx_t_5;
   __pyx_L20_bool_binop_done:;
@@ -7187,34 +7316,34 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
     goto __pyx_L18_bool_binop_done;
   }
 
-  /* "_openjpeg.pyx":273
+  /* "_openjpeg.pyx":285
  *     if (
  *         arr.dtype in (np.int8, np.int16, np.int32)
  *         and (arr_max > 2**(bits_stored - 1) - 1 or arr_min < -2**(bits_stored - 1))             # <<<<<<<<<<<<<<
  *     ):
  *         raise ValueError(
  */
-  __pyx_t_2 = PyFloat_FromDouble((pow(2.0, ((double)(__pyx_v_bits_stored - 1))) - 1.0)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 273, __pyx_L1_error)
+  __pyx_t_2 = PyFloat_FromDouble((pow(2.0, ((double)(__pyx_v_bits_stored - 1))) - 1.0)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 285, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  __pyx_t_11 = PyObject_RichCompare(__pyx_v_arr_max, __pyx_t_2, Py_GT); __Pyx_XGOTREF(__pyx_t_11); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 273, __pyx_L1_error)
+  __pyx_t_11 = PyObject_RichCompare(__pyx_v_arr_max, __pyx_t_2, Py_GT); __Pyx_XGOTREF(__pyx_t_11); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 285, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-  __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_11); if (unlikely((__pyx_t_5 < 0))) __PYX_ERR(0, 273, __pyx_L1_error)
+  __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_11); if (unlikely((__pyx_t_5 < 0))) __PYX_ERR(0, 285, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
   if (!__pyx_t_5) {
   } else {
     __pyx_t_6 = __pyx_t_5;
     goto __pyx_L18_bool_binop_done;
   }
-  __pyx_t_11 = PyFloat_FromDouble((-pow(2.0, ((double)(__pyx_v_bits_stored - 1))))); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 273, __pyx_L1_error)
+  __pyx_t_11 = PyFloat_FromDouble((-pow(2.0, ((double)(__pyx_v_bits_stored - 1))))); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 285, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_11);
-  __pyx_t_2 = PyObject_RichCompare(__pyx_v_arr_min, __pyx_t_11, Py_LT); __Pyx_XGOTREF(__pyx_t_2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 273, __pyx_L1_error)
+  __pyx_t_2 = PyObject_RichCompare(__pyx_v_arr_min, __pyx_t_11, Py_LT); __Pyx_XGOTREF(__pyx_t_2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 285, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
-  __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely((__pyx_t_5 < 0))) __PYX_ERR(0, 273, __pyx_L1_error)
+  __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely((__pyx_t_5 < 0))) __PYX_ERR(0, 285, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
   __pyx_t_6 = __pyx_t_5;
   __pyx_L18_bool_binop_done:;
 
-  /* "_openjpeg.pyx":271
+  /* "_openjpeg.pyx":283
  *         )
  * 
  *     if (             # <<<<<<<<<<<<<<
@@ -7223,14 +7352,14 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
  */
   if (unlikely(__pyx_t_6)) {
 
-    /* "_openjpeg.pyx":276
+    /* "_openjpeg.pyx":288
  *     ):
  *         raise ValueError(
  *             f"A 'bits_stored' value of {bits_stored} is incompatible with "             # <<<<<<<<<<<<<<
  *             f"the range of pixel data in the input array: ({arr_min}, {arr_max})"
  *         )
  */
-    __pyx_t_2 = PyTuple_New(7); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 276, __pyx_L1_error)
+    __pyx_t_2 = PyTuple_New(7); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 288, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_2);
     __pyx_t_7 = 0;
     __pyx_t_8 = 127;
@@ -7238,7 +7367,7 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
     __pyx_t_7 += 25;
     __Pyx_GIVEREF(__pyx_kp_u_A_bits_stored_value_of);
     PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_kp_u_A_bits_stored_value_of);
-    __pyx_t_11 = __Pyx_PyUnicode_From_int(__pyx_v_bits_stored, 0, ' ', 'd'); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 276, __pyx_L1_error)
+    __pyx_t_11 = __Pyx_PyUnicode_From_int(__pyx_v_bits_stored, 0, ' ', 'd'); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 288, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_11);
     __pyx_t_7 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_11);
     __Pyx_GIVEREF(__pyx_t_11);
@@ -7249,14 +7378,14 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
     __Pyx_GIVEREF(__pyx_kp_u_is_incompatible_with_the_range);
     PyTuple_SET_ITEM(__pyx_t_2, 2, __pyx_kp_u_is_incompatible_with_the_range);
 
-    /* "_openjpeg.pyx":277
+    /* "_openjpeg.pyx":289
  *         raise ValueError(
  *             f"A 'bits_stored' value of {bits_stored} is incompatible with "
  *             f"the range of pixel data in the input array: ({arr_min}, {arr_max})"             # <<<<<<<<<<<<<<
  *         )
  * 
  */
-    __pyx_t_11 = __Pyx_PyObject_FormatSimple(__pyx_v_arr_min, __pyx_empty_unicode); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 277, __pyx_L1_error)
+    __pyx_t_11 = __Pyx_PyObject_FormatSimple(__pyx_v_arr_min, __pyx_empty_unicode); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 289, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_11);
     __pyx_t_8 = (__Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_11) > __pyx_t_8) ? __Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_11) : __pyx_t_8;
     __pyx_t_7 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_11);
@@ -7267,7 +7396,7 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
     __pyx_t_7 += 2;
     __Pyx_GIVEREF(__pyx_kp_u__6);
     PyTuple_SET_ITEM(__pyx_t_2, 4, __pyx_kp_u__6);
-    __pyx_t_11 = __Pyx_PyObject_FormatSimple(__pyx_v_arr_max, __pyx_empty_unicode); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 277, __pyx_L1_error)
+    __pyx_t_11 = __Pyx_PyObject_FormatSimple(__pyx_v_arr_max, __pyx_empty_unicode); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 289, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_11);
     __pyx_t_8 = (__Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_11) > __pyx_t_8) ? __Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_11) : __pyx_t_8;
     __pyx_t_7 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_11);
@@ -7279,32 +7408,32 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
     __Pyx_GIVEREF(__pyx_kp_u__4);
     PyTuple_SET_ITEM(__pyx_t_2, 6, __pyx_kp_u__4);
 
-    /* "_openjpeg.pyx":276
+    /* "_openjpeg.pyx":288
  *     ):
  *         raise ValueError(
  *             f"A 'bits_stored' value of {bits_stored} is incompatible with "             # <<<<<<<<<<<<<<
  *             f"the range of pixel data in the input array: ({arr_min}, {arr_max})"
  *         )
  */
-    __pyx_t_11 = __Pyx_PyUnicode_Join(__pyx_t_2, 7, __pyx_t_7, __pyx_t_8); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 276, __pyx_L1_error)
+    __pyx_t_11 = __Pyx_PyUnicode_Join(__pyx_t_2, 7, __pyx_t_7, __pyx_t_8); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 288, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_11);
     __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 
-    /* "_openjpeg.pyx":275
+    /* "_openjpeg.pyx":287
  *         and (arr_max > 2**(bits_stored - 1) - 1 or arr_min < -2**(bits_stored - 1))
  *     ):
  *         raise ValueError(             # <<<<<<<<<<<<<<
  *             f"A 'bits_stored' value of {bits_stored} is incompatible with "
  *             f"the range of pixel data in the input array: ({arr_min}, {arr_max})"
  */
-    __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_11); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 275, __pyx_L1_error)
+    __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_11); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 287, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_2);
     __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
     __Pyx_Raise(__pyx_t_2, 0, 0, 0);
     __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-    __PYX_ERR(0, 275, __pyx_L1_error)
+    __PYX_ERR(0, 287, __pyx_L1_error)
 
-    /* "_openjpeg.pyx":271
+    /* "_openjpeg.pyx":283
  *         )
  * 
  *     if (             # <<<<<<<<<<<<<<
@@ -7313,12 +7442,12 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
  */
   }
 
-  /* "_openjpeg.pyx":281
+  /* "_openjpeg.pyx":293
  * 
  *     # MCT may be used with RGB in both lossy and lossless modes
  *     use_mct = 1 if use_mct else 0             # <<<<<<<<<<<<<<
  * 
- *     if codec_format not in (0, 2):
+ *     if codec_format not in (0, 1):
  */
   if (__pyx_v_use_mct) {
     __pyx_t_6 = 1;
@@ -7327,16 +7456,16 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
   }
   __pyx_v_use_mct = __pyx_t_6;
 
-  /* "_openjpeg.pyx":283
+  /* "_openjpeg.pyx":295
  *     use_mct = 1 if use_mct else 0
  * 
- *     if codec_format not in (0, 2):             # <<<<<<<<<<<<<<
+ *     if codec_format not in (0, 1):             # <<<<<<<<<<<<<<
  *         raise ValueError(
- *             "The value of the 'codec_format' parameter is invalid, must be 0 or 2"
+ *             f"Invalid 'codec_format' value '{codec_format}', must be 0 or 1"
  */
   switch (__pyx_v_codec_format) {
     case 0:
-    case 2:
+    case 1:
     __pyx_t_6 = 0;
     break;
     default:
@@ -7346,29 +7475,59 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
   __pyx_t_5 = __pyx_t_6;
   if (unlikely(__pyx_t_5)) {
 
-    /* "_openjpeg.pyx":284
+    /* "_openjpeg.pyx":297
+ *     if codec_format not in (0, 1):
+ *         raise ValueError(
+ *             f"Invalid 'codec_format' value '{codec_format}', must be 0 or 1"             # <<<<<<<<<<<<<<
+ *         )
+ * 
+ */
+    __pyx_t_2 = PyTuple_New(3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 297, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_2);
+    __pyx_t_7 = 0;
+    __pyx_t_8 = 127;
+    __Pyx_INCREF(__pyx_kp_u_Invalid_codec_format_value);
+    __pyx_t_7 += 30;
+    __Pyx_GIVEREF(__pyx_kp_u_Invalid_codec_format_value);
+    PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_kp_u_Invalid_codec_format_value);
+    __pyx_t_11 = __Pyx_PyUnicode_From_int(__pyx_v_codec_format, 0, ' ', 'd'); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 297, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_11);
+    __pyx_t_7 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_11);
+    __Pyx_GIVEREF(__pyx_t_11);
+    PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_t_11);
+    __pyx_t_11 = 0;
+    __Pyx_INCREF(__pyx_kp_u_must_be_0_or_1);
+    __pyx_t_7 += 17;
+    __Pyx_GIVEREF(__pyx_kp_u_must_be_0_or_1);
+    PyTuple_SET_ITEM(__pyx_t_2, 2, __pyx_kp_u_must_be_0_or_1);
+    __pyx_t_11 = __Pyx_PyUnicode_Join(__pyx_t_2, 3, __pyx_t_7, __pyx_t_8); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 297, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_11);
+    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+
+    /* "_openjpeg.pyx":296
  * 
- *     if codec_format not in (0, 2):
+ *     if codec_format not in (0, 1):
  *         raise ValueError(             # <<<<<<<<<<<<<<
- *             "The value of the 'codec_format' parameter is invalid, must be 0 or 2"
+ *             f"Invalid 'codec_format' value '{codec_format}', must be 0 or 1"
  *         )
  */
-    __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__7, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 284, __pyx_L1_error)
+    __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_11); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 296, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_2);
+    __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
     __Pyx_Raise(__pyx_t_2, 0, 0, 0);
     __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-    __PYX_ERR(0, 284, __pyx_L1_error)
+    __PYX_ERR(0, 296, __pyx_L1_error)
 
-    /* "_openjpeg.pyx":283
+    /* "_openjpeg.pyx":295
  *     use_mct = 1 if use_mct else 0
  * 
- *     if codec_format not in (0, 2):             # <<<<<<<<<<<<<<
+ *     if codec_format not in (0, 1):             # <<<<<<<<<<<<<<
  *         raise ValueError(
- *             "The value of the 'codec_format' parameter is invalid, must be 0 or 2"
+ *             f"Invalid 'codec_format' value '{codec_format}', must be 0 or 1"
  */
   }
 
-  /* "_openjpeg.pyx":288
+  /* "_openjpeg.pyx":300
  *         )
  * 
  *     compression_ratios = [float(x) for x in compression_ratios]             # <<<<<<<<<<<<<<
@@ -7376,11 +7535,11 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
  *     if compression_ratios and signal_noise_ratios:
  */
   { /* enter inner scope */
-    __pyx_t_2 = PyList_New(0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 288, __pyx_L27_error)
+    __pyx_t_2 = PyList_New(0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 300, __pyx_L27_error)
     __Pyx_GOTREF(__pyx_t_2);
     if (unlikely(__pyx_v_compression_ratios == Py_None)) {
       PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable");
-      __PYX_ERR(0, 288, __pyx_L27_error)
+      __PYX_ERR(0, 300, __pyx_L27_error)
     }
     __pyx_t_11 = __pyx_v_compression_ratios; __Pyx_INCREF(__pyx_t_11);
     __pyx_t_7 = 0;
@@ -7388,21 +7547,21 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
       {
         Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_11);
         #if !CYTHON_ASSUME_SAFE_MACROS
-        if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 288, __pyx_L27_error)
+        if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 300, __pyx_L27_error)
         #endif
         if (__pyx_t_7 >= __pyx_temp) break;
       }
       #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
-      __pyx_t_10 = PyList_GET_ITEM(__pyx_t_11, __pyx_t_7); __Pyx_INCREF(__pyx_t_10); __pyx_t_7++; if (unlikely((0 < 0))) __PYX_ERR(0, 288, __pyx_L27_error)
+      __pyx_t_10 = PyList_GET_ITEM(__pyx_t_11, __pyx_t_7); __Pyx_INCREF(__pyx_t_10); __pyx_t_7++; if (unlikely((0 < 0))) __PYX_ERR(0, 300, __pyx_L27_error)
       #else
-      __pyx_t_10 = __Pyx_PySequence_ITEM(__pyx_t_11, __pyx_t_7); __pyx_t_7++; if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 288, __pyx_L27_error)
+      __pyx_t_10 = __Pyx_PySequence_ITEM(__pyx_t_11, __pyx_t_7); __pyx_t_7++; if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 300, __pyx_L27_error)
       __Pyx_GOTREF(__pyx_t_10);
       #endif
       __Pyx_XDECREF_SET(__pyx_7genexpr__pyx_v_x, __pyx_t_10);
       __pyx_t_10 = 0;
-      __pyx_t_10 = __Pyx_PyNumber_Float(__pyx_7genexpr__pyx_v_x); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 288, __pyx_L27_error)
+      __pyx_t_10 = __Pyx_PyNumber_Float(__pyx_7genexpr__pyx_v_x); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 300, __pyx_L27_error)
       __Pyx_GOTREF(__pyx_t_10);
-      if (unlikely(__Pyx_ListComp_Append(__pyx_t_2, (PyObject*)__pyx_t_10))) __PYX_ERR(0, 288, __pyx_L27_error)
+      if (unlikely(__Pyx_ListComp_Append(__pyx_t_2, (PyObject*)__pyx_t_10))) __PYX_ERR(0, 300, __pyx_L27_error)
       __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
     }
     __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
@@ -7416,7 +7575,7 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
   __Pyx_DECREF_SET(__pyx_v_compression_ratios, ((PyObject*)__pyx_t_2));
   __pyx_t_2 = 0;
 
-  /* "_openjpeg.pyx":289
+  /* "_openjpeg.pyx":301
  * 
  *     compression_ratios = [float(x) for x in compression_ratios]
  *     signal_noise_ratios = [float(x) for x in signal_noise_ratios]             # <<<<<<<<<<<<<<
@@ -7424,11 +7583,11 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
  *         raise ValueError(
  */
   { /* enter inner scope */
-    __pyx_t_2 = PyList_New(0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 289, __pyx_L34_error)
+    __pyx_t_2 = PyList_New(0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 301, __pyx_L34_error)
     __Pyx_GOTREF(__pyx_t_2);
     if (unlikely(__pyx_v_signal_noise_ratios == Py_None)) {
       PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable");
-      __PYX_ERR(0, 289, __pyx_L34_error)
+      __PYX_ERR(0, 301, __pyx_L34_error)
     }
     __pyx_t_11 = __pyx_v_signal_noise_ratios; __Pyx_INCREF(__pyx_t_11);
     __pyx_t_7 = 0;
@@ -7436,21 +7595,21 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
       {
         Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_11);
         #if !CYTHON_ASSUME_SAFE_MACROS
-        if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 289, __pyx_L34_error)
+        if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 301, __pyx_L34_error)
         #endif
         if (__pyx_t_7 >= __pyx_temp) break;
       }
       #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
-      __pyx_t_10 = PyList_GET_ITEM(__pyx_t_11, __pyx_t_7); __Pyx_INCREF(__pyx_t_10); __pyx_t_7++; if (unlikely((0 < 0))) __PYX_ERR(0, 289, __pyx_L34_error)
+      __pyx_t_10 = PyList_GET_ITEM(__pyx_t_11, __pyx_t_7); __Pyx_INCREF(__pyx_t_10); __pyx_t_7++; if (unlikely((0 < 0))) __PYX_ERR(0, 301, __pyx_L34_error)
       #else
-      __pyx_t_10 = __Pyx_PySequence_ITEM(__pyx_t_11, __pyx_t_7); __pyx_t_7++; if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 289, __pyx_L34_error)
+      __pyx_t_10 = __Pyx_PySequence_ITEM(__pyx_t_11, __pyx_t_7); __pyx_t_7++; if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 301, __pyx_L34_error)
       __Pyx_GOTREF(__pyx_t_10);
       #endif
       __Pyx_XDECREF_SET(__pyx_8genexpr1__pyx_v_x, __pyx_t_10);
       __pyx_t_10 = 0;
-      __pyx_t_10 = __Pyx_PyNumber_Float(__pyx_8genexpr1__pyx_v_x); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 289, __pyx_L34_error)
+      __pyx_t_10 = __Pyx_PyNumber_Float(__pyx_8genexpr1__pyx_v_x); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 301, __pyx_L34_error)
       __Pyx_GOTREF(__pyx_t_10);
-      if (unlikely(__Pyx_ListComp_Append(__pyx_t_2, (PyObject*)__pyx_t_10))) __PYX_ERR(0, 289, __pyx_L34_error)
+      if (unlikely(__Pyx_ListComp_Append(__pyx_t_2, (PyObject*)__pyx_t_10))) __PYX_ERR(0, 301, __pyx_L34_error)
       __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
     }
     __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
@@ -7464,7 +7623,7 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
   __Pyx_DECREF_SET(__pyx_v_signal_noise_ratios, ((PyObject*)__pyx_t_2));
   __pyx_t_2 = 0;
 
-  /* "_openjpeg.pyx":290
+  /* "_openjpeg.pyx":302
  *     compression_ratios = [float(x) for x in compression_ratios]
  *     signal_noise_ratios = [float(x) for x in signal_noise_ratios]
  *     if compression_ratios and signal_noise_ratios:             # <<<<<<<<<<<<<<
@@ -7482,20 +7641,20 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
   __pyx_L40_bool_binop_done:;
   if (unlikely(__pyx_t_5)) {
 
-    /* "_openjpeg.pyx":291
+    /* "_openjpeg.pyx":303
  *     signal_noise_ratios = [float(x) for x in signal_noise_ratios]
  *     if compression_ratios and signal_noise_ratios:
  *         raise ValueError(             # <<<<<<<<<<<<<<
  *             "Only one of 'compression_ratios' or 'signal_noise_ratios' is "
  *             "allowed when performing lossy compression"
  */
-    __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__8, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 291, __pyx_L1_error)
+    __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__7, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 303, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_2);
     __Pyx_Raise(__pyx_t_2, 0, 0, 0);
     __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-    __PYX_ERR(0, 291, __pyx_L1_error)
+    __PYX_ERR(0, 303, __pyx_L1_error)
 
-    /* "_openjpeg.pyx":290
+    /* "_openjpeg.pyx":302
  *     compression_ratios = [float(x) for x in compression_ratios]
  *     signal_noise_ratios = [float(x) for x in signal_noise_ratios]
  *     if compression_ratios and signal_noise_ratios:             # <<<<<<<<<<<<<<
@@ -7504,40 +7663,40 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
  */
   }
 
-  /* "_openjpeg.pyx":295
+  /* "_openjpeg.pyx":307
  *             "allowed when performing lossy compression"
  *         )
  *     if len(compression_ratios) > 10 or len(signal_noise_ratios) > 10:             # <<<<<<<<<<<<<<
  *         raise ValueError("More than 10 compression layers is not supported")
  * 
  */
-  __pyx_t_7 = __Pyx_PyList_GET_SIZE(__pyx_v_compression_ratios); if (unlikely(__pyx_t_7 == ((Py_ssize_t)-1))) __PYX_ERR(0, 295, __pyx_L1_error)
+  __pyx_t_7 = __Pyx_PyList_GET_SIZE(__pyx_v_compression_ratios); if (unlikely(__pyx_t_7 == ((Py_ssize_t)-1))) __PYX_ERR(0, 307, __pyx_L1_error)
   __pyx_t_6 = (__pyx_t_7 > 10);
   if (!__pyx_t_6) {
   } else {
     __pyx_t_5 = __pyx_t_6;
     goto __pyx_L43_bool_binop_done;
   }
-  __pyx_t_7 = __Pyx_PyList_GET_SIZE(__pyx_v_signal_noise_ratios); if (unlikely(__pyx_t_7 == ((Py_ssize_t)-1))) __PYX_ERR(0, 295, __pyx_L1_error)
+  __pyx_t_7 = __Pyx_PyList_GET_SIZE(__pyx_v_signal_noise_ratios); if (unlikely(__pyx_t_7 == ((Py_ssize_t)-1))) __PYX_ERR(0, 307, __pyx_L1_error)
   __pyx_t_6 = (__pyx_t_7 > 10);
   __pyx_t_5 = __pyx_t_6;
   __pyx_L43_bool_binop_done:;
   if (unlikely(__pyx_t_5)) {
 
-    /* "_openjpeg.pyx":296
+    /* "_openjpeg.pyx":308
  *         )
  *     if len(compression_ratios) > 10 or len(signal_noise_ratios) > 10:
  *         raise ValueError("More than 10 compression layers is not supported")             # <<<<<<<<<<<<<<
  * 
  *     # The destination for the encoded J2K codestream, needs to support BinaryIO
  */
-    __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__9, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 296, __pyx_L1_error)
+    __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__8, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 308, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_2);
     __Pyx_Raise(__pyx_t_2, 0, 0, 0);
     __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-    __PYX_ERR(0, 296, __pyx_L1_error)
+    __PYX_ERR(0, 308, __pyx_L1_error)
 
-    /* "_openjpeg.pyx":295
+    /* "_openjpeg.pyx":307
  *             "allowed when performing lossy compression"
  *         )
  *     if len(compression_ratios) > 10 or len(signal_noise_ratios) > 10:             # <<<<<<<<<<<<<<
@@ -7546,14 +7705,14 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
  */
   }
 
-  /* "_openjpeg.pyx":299
+  /* "_openjpeg.pyx":311
  * 
  *     # The destination for the encoded J2K codestream, needs to support BinaryIO
  *     dst = BytesIO()             # <<<<<<<<<<<<<<
- *     return_code = Encode(
+ *     return_code = EncodeArray(
  *         <cnp.PyArrayObject *> arr,
  */
-  __Pyx_GetModuleGlobalName(__pyx_t_11, __pyx_n_s_BytesIO); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 299, __pyx_L1_error)
+  __Pyx_GetModuleGlobalName(__pyx_t_11, __pyx_n_s_BytesIO); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 311, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_11);
   __pyx_t_10 = NULL;
   __pyx_t_12 = 0;
@@ -7573,31 +7732,33 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
     PyObject *__pyx_callargs[2] = {__pyx_t_10, NULL};
     __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_11, __pyx_callargs+1-__pyx_t_12, 0+__pyx_t_12);
     __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0;
-    if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 299, __pyx_L1_error)
+    if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 311, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_2);
     __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
   }
   __pyx_v_dst = __pyx_t_2;
   __pyx_t_2 = 0;
 
-  /* "_openjpeg.pyx":300
+  /* "_openjpeg.pyx":312
  *     # The destination for the encoded J2K codestream, needs to support BinaryIO
  *     dst = BytesIO()
- *     return_code = Encode(             # <<<<<<<<<<<<<<
+ *     return_code = EncodeArray(             # <<<<<<<<<<<<<<
  *         <cnp.PyArrayObject *> arr,
  *         <PyObject *> dst,
  */
-  __pyx_v_return_code = Encode(((PyArrayObject *)__pyx_v_arr), ((PyObject *)__pyx_v_dst), __pyx_v_bits_stored, __pyx_v_photometric_interpretation, __pyx_v_use_mct, ((PyObject *)__pyx_v_compression_ratios), ((PyObject *)__pyx_v_signal_noise_ratios), __pyx_v_codec_format);
+  __pyx_v_return_code = EncodeArray(((PyArrayObject *)__pyx_v_arr), ((PyObject *)__pyx_v_dst), __pyx_v_bits_stored, __pyx_v_photometric_interpretation, __pyx_v_use_mct, ((PyObject *)__pyx_v_compression_ratios), ((PyObject *)__pyx_v_signal_noise_ratios), __pyx_v_codec_format);
 
-  /* "_openjpeg.pyx":310
+  /* "_openjpeg.pyx":322
  *         codec_format,
  *     )
  *     return return_code, dst.getvalue()             # <<<<<<<<<<<<<<
+ * 
+ * 
  */
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_2 = __Pyx_PyInt_From_int(__pyx_v_return_code); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 310, __pyx_L1_error)
+  __pyx_t_2 = __Pyx_PyInt_From_int(__pyx_v_return_code); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 322, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_v_dst, __pyx_n_s_getvalue); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 310, __pyx_L1_error)
+  __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_v_dst, __pyx_n_s_getvalue); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 322, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_10);
   __pyx_t_9 = NULL;
   __pyx_t_12 = 0;
@@ -7617,26 +7778,26 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
     PyObject *__pyx_callargs[2] = {__pyx_t_9, NULL};
     __pyx_t_11 = __Pyx_PyObject_FastCall(__pyx_t_10, __pyx_callargs+1-__pyx_t_12, 0+__pyx_t_12);
     __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0;
-    if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 310, __pyx_L1_error)
+    if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 322, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_11);
     __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
   }
-  __pyx_t_10 = PyTuple_New(2); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 310, __pyx_L1_error)
+  __pyx_t_10 = PyTuple_New(2); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 322, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_10);
   __Pyx_GIVEREF(__pyx_t_2);
-  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_10, 0, __pyx_t_2)) __PYX_ERR(0, 310, __pyx_L1_error);
+  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_10, 0, __pyx_t_2)) __PYX_ERR(0, 322, __pyx_L1_error);
   __Pyx_GIVEREF(__pyx_t_11);
-  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_10, 1, __pyx_t_11)) __PYX_ERR(0, 310, __pyx_L1_error);
+  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_10, 1, __pyx_t_11)) __PYX_ERR(0, 322, __pyx_L1_error);
   __pyx_t_2 = 0;
   __pyx_t_11 = 0;
   __pyx_r = ((PyObject*)__pyx_t_10);
   __pyx_t_10 = 0;
   goto __pyx_L0;
 
-  /* "_openjpeg.pyx":195
+  /* "_openjpeg.pyx":208
  * 
  * 
- * def encode(             # <<<<<<<<<<<<<<
+ * def encode_array(             # <<<<<<<<<<<<<<
  *     cnp.ndarray arr,
  *     int bits_stored,
  */
@@ -7650,7 +7811,7 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
   __Pyx_XDECREF(__pyx_t_9);
   __Pyx_XDECREF(__pyx_t_10);
   __Pyx_XDECREF(__pyx_t_11);
-  __Pyx_AddTraceback("_openjpeg.encode", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_AddTraceback("_openjpeg.encode_array", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
   __Pyx_XDECREF(__pyx_v_allowed);
@@ -7666,279 +7827,1711 @@ static PyObject *__pyx_pf_9_openjpeg_6encode(CYTHON_UNUSED PyObject *__pyx_self,
   return __pyx_r;
 }
 
-static PyMethodDef __pyx_methods[] = {
-  {0, 0, 0, 0}
-};
-#ifndef CYTHON_SMALL_CODE
-#if defined(__clang__)
-    #define CYTHON_SMALL_CODE
-#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
-    #define CYTHON_SMALL_CODE __attribute__((cold))
-#else
-    #define CYTHON_SMALL_CODE
-#endif
-#endif
-/* #### Code section: pystring_table ### */
-
-static int __Pyx_CreateStringTabAndInitStrings(void) {
-  __Pyx_StringTabEntry __pyx_string_tab[] = {
-    {&__pyx_kp_u_A_bits_stored_value_of, __pyx_k_A_bits_stored_value_of, sizeof(__pyx_k_A_bits_stored_value_of), 0, 1, 0, 0},
-    {&__pyx_n_s_BinaryIO, __pyx_k_BinaryIO, sizeof(__pyx_k_BinaryIO), 0, 0, 1, 1},
-    {&__pyx_n_s_BytesIO, __pyx_k_BytesIO, sizeof(__pyx_k_BytesIO), 0, 0, 1, 1},
-    {&__pyx_n_u_CYMK, __pyx_k_CYMK, sizeof(__pyx_k_CYMK), 0, 1, 0, 1},
-    {&__pyx_n_s_Dict, __pyx_k_Dict, sizeof(__pyx_k_Dict), 0, 0, 1, 1},
-    {&__pyx_kp_s_Dict_str_Union_str_int_bool, __pyx_k_Dict_str_Union_str_int_bool, sizeof(__pyx_k_Dict_str_Union_str_int_bool), 0, 0, 1, 0},
-    {&__pyx_n_s_ERRORS, __pyx_k_ERRORS, sizeof(__pyx_k_ERRORS), 0, 0, 1, 1},
-    {&__pyx_kp_u_Error_decoding_the_J2K_data, __pyx_k_Error_decoding_the_J2K_data, sizeof(__pyx_k_Error_decoding_the_J2K_data), 0, 1, 0, 0},
-    {&__pyx_n_s_ImportError, __pyx_k_ImportError, sizeof(__pyx_k_ImportError), 0, 0, 1, 1},
-    {&__pyx_kp_u_Invalid_value_for_the_bits_store, __pyx_k_Invalid_value_for_the_bits_store, sizeof(__pyx_k_Invalid_value_for_the_bits_store), 0, 1, 0, 0},
-    {&__pyx_n_s_KeyError, __pyx_k_KeyError, sizeof(__pyx_k_KeyError), 0, 0, 1, 1},
-    {&__pyx_n_s_LOGGER, __pyx_k_LOGGER, sizeof(__pyx_k_LOGGER), 0, 0, 1, 1},
-    {&__pyx_n_s_List, __pyx_k_List, sizeof(__pyx_k_List), 0, 0, 1, 1},
-    {&__pyx_kp_u_More_than_10_compression_layers, __pyx_k_More_than_10_compression_layers, sizeof(__pyx_k_More_than_10_compression_layers), 0, 1, 0, 0},
-    {&__pyx_kp_u_Only_one_of_compression_ratios_o, __pyx_k_Only_one_of_compression_ratios_o, sizeof(__pyx_k_Only_one_of_compression_ratios_o), 0, 1, 0, 0},
-    {&__pyx_n_s_RuntimeError, __pyx_k_RuntimeError, sizeof(__pyx_k_RuntimeError), 0, 0, 1, 1},
-    {&__pyx_kp_u_The_input_array_contains_values, __pyx_k_The_input_array_contains_values, sizeof(__pyx_k_The_input_array_contains_values), 0, 1, 0, 0},
-    {&__pyx_kp_u_The_input_array_has_an_unsupport, __pyx_k_The_input_array_has_an_unsupport, sizeof(__pyx_k_The_input_array_has_an_unsupport), 0, 1, 0, 0},
-    {&__pyx_kp_u_The_value_of_the_codec_format_pa, __pyx_k_The_value_of_the_codec_format_pa, sizeof(__pyx_k_The_value_of_the_codec_format_pa), 0, 1, 0, 0},
-    {&__pyx_n_s_Tuple, __pyx_k_Tuple, sizeof(__pyx_k_Tuple), 0, 0, 1, 1},
-    {&__pyx_kp_s_Tuple_int_bytes, __pyx_k_Tuple_int_bytes, sizeof(__pyx_k_Tuple_int_bytes), 0, 0, 1, 0},
-    {&__pyx_n_s_Union, __pyx_k_Union, sizeof(__pyx_k_Union), 0, 0, 1, 1},
-    {&__pyx_kp_s_Union_np_ndarray_bytearray, __pyx_k_Union_np_ndarray_bytearray, sizeof(__pyx_k_Union_np_ndarray_bytearray), 0, 0, 1, 0},
-    {&__pyx_n_s_ValueError, __pyx_k_ValueError, sizeof(__pyx_k_ValueError), 0, 0, 1, 1},
-    {&__pyx_n_u_YUV, __pyx_k_YUV, sizeof(__pyx_k_YUV), 0, 1, 0, 1},
-    {&__pyx_kp_u__10, __pyx_k__10, sizeof(__pyx_k__10), 0, 1, 0, 0},
-    {&__pyx_n_s__11, __pyx_k__11, sizeof(__pyx_k__11), 0, 0, 1, 1},
-    {&__pyx_n_s__20, __pyx_k__20, sizeof(__pyx_k__20), 0, 0, 1, 1},
-    {&__pyx_kp_u__3, __pyx_k__3, sizeof(__pyx_k__3), 0, 1, 0, 0},
-    {&__pyx_kp_u__4, __pyx_k__4, sizeof(__pyx_k__4), 0, 1, 0, 0},
-    {&__pyx_kp_u__6, __pyx_k__6, sizeof(__pyx_k__6), 0, 1, 0, 0},
-    {&__pyx_n_s_allowed, __pyx_k_allowed, sizeof(__pyx_k_allowed), 0, 0, 1, 1},
-    {&__pyx_n_s_arr, __pyx_k_arr, sizeof(__pyx_k_arr), 0, 0, 1, 1},
-    {&__pyx_n_s_arr_max, __pyx_k_arr_max, sizeof(__pyx_k_arr_max), 0, 0, 1, 1},
-    {&__pyx_n_s_arr_min, __pyx_k_arr_min, sizeof(__pyx_k_arr_min), 0, 0, 1, 1},
-    {&__pyx_n_s_as_array, __pyx_k_as_array, sizeof(__pyx_k_as_array), 0, 0, 1, 1},
-    {&__pyx_n_s_asyncio_coroutines, __pyx_k_asyncio_coroutines, sizeof(__pyx_k_asyncio_coroutines), 0, 0, 1, 1},
-    {&__pyx_n_s_bits_stored, __pyx_k_bits_stored, sizeof(__pyx_k_bits_stored), 0, 0, 1, 1},
-    {&__pyx_n_s_bool, __pyx_k_bool, sizeof(__pyx_k_bool), 0, 0, 1, 1},
-    {&__pyx_n_s_bpp, __pyx_k_bpp, sizeof(__pyx_k_bpp), 0, 0, 1, 1},
-    {&__pyx_n_s_bytes, __pyx_k_bytes, sizeof(__pyx_k_bytes), 0, 0, 1, 1},
-    {&__pyx_n_s_ceil, __pyx_k_ceil, sizeof(__pyx_k_ceil), 0, 0, 1, 1},
-    {&__pyx_n_s_cline_in_traceback, __pyx_k_cline_in_traceback, sizeof(__pyx_k_cline_in_traceback), 0, 0, 1, 1},
-    {&__pyx_n_s_codec, __pyx_k_codec, sizeof(__pyx_k_codec), 0, 0, 1, 1},
-    {&__pyx_n_s_codec_format, __pyx_k_codec_format, sizeof(__pyx_k_codec_format), 0, 0, 1, 1},
-    {&__pyx_n_s_colours, __pyx_k_colours, sizeof(__pyx_k_colours), 0, 0, 1, 1},
-    {&__pyx_n_s_colourspace, __pyx_k_colourspace, sizeof(__pyx_k_colourspace), 0, 0, 1, 1},
-    {&__pyx_n_u_colourspace, __pyx_k_colourspace, sizeof(__pyx_k_colourspace), 0, 1, 0, 1},
-    {&__pyx_n_u_columns, __pyx_k_columns, sizeof(__pyx_k_columns), 0, 1, 0, 1},
-    {&__pyx_n_s_compression_ratios, __pyx_k_compression_ratios, sizeof(__pyx_k_compression_ratios), 0, 0, 1, 1},
-    {&__pyx_n_s_decode, __pyx_k_decode, sizeof(__pyx_k_decode), 0, 0, 1, 1},
-    {&__pyx_n_s_dst, __pyx_k_dst, sizeof(__pyx_k_dst), 0, 0, 1, 1},
-    {&__pyx_n_s_dtype, __pyx_k_dtype, sizeof(__pyx_k_dtype), 0, 0, 1, 1},
-    {&__pyx_kp_u_e_YCC, __pyx_k_e_YCC, sizeof(__pyx_k_e_YCC), 0, 1, 0, 0},
-    {&__pyx_n_s_encode, __pyx_k_encode, sizeof(__pyx_k_encode), 0, 0, 1, 1},
-    {&__pyx_kp_u_failed_to_create_the_input_strea, __pyx_k_failed_to_create_the_input_strea, sizeof(__pyx_k_failed_to_create_the_input_strea), 0, 1, 0, 0},
-    {&__pyx_kp_u_failed_to_decode_image, __pyx_k_failed_to_decode_image, sizeof(__pyx_k_failed_to_decode_image), 0, 1, 0, 0},
-    {&__pyx_kp_u_failed_to_read_the_header, __pyx_k_failed_to_read_the_header, sizeof(__pyx_k_failed_to_read_the_header), 0, 1, 0, 0},
-    {&__pyx_kp_u_failed_to_set_the_component_indi, __pyx_k_failed_to_set_the_component_indi, sizeof(__pyx_k_failed_to_set_the_component_indi), 0, 1, 0, 0},
-    {&__pyx_kp_u_failed_to_set_the_decoded_area, __pyx_k_failed_to_set_the_decoded_area, sizeof(__pyx_k_failed_to_set_the_decoded_area), 0, 1, 0, 0},
-    {&__pyx_kp_u_failed_to_setup_the_decoder, __pyx_k_failed_to_setup_the_decoder, sizeof(__pyx_k_failed_to_setup_the_decoder), 0, 1, 0, 0},
-    {&__pyx_kp_u_failed_to_upscale_subsampled_com, __pyx_k_failed_to_upscale_subsampled_com, sizeof(__pyx_k_failed_to_upscale_subsampled_com), 0, 1, 0, 0},
-    {&__pyx_n_s_fp, __pyx_k_fp, sizeof(__pyx_k_fp), 0, 0, 1, 1},
-    {&__pyx_n_s_getLogger, __pyx_k_getLogger, sizeof(__pyx_k_getLogger), 0, 0, 1, 1},
-    {&__pyx_n_s_get_parameters, __pyx_k_get_parameters, sizeof(__pyx_k_get_parameters), 0, 0, 1, 1},
-    {&__pyx_n_s_get_version, __pyx_k_get_version, sizeof(__pyx_k_get_version), 0, 0, 1, 1},
-    {&__pyx_n_s_getvalue, __pyx_k_getvalue, sizeof(__pyx_k_getvalue), 0, 0, 1, 1},
-    {&__pyx_n_s_import, __pyx_k_import, sizeof(__pyx_k_import), 0, 0, 1, 1},
-    {&__pyx_n_s_initializing, __pyx_k_initializing, sizeof(__pyx_k_initializing), 0, 0, 1, 1},
-    {&__pyx_n_s_int, __pyx_k_int, sizeof(__pyx_k_int), 0, 0, 1, 1},
-    {&__pyx_n_s_int16, __pyx_k_int16, sizeof(__pyx_k_int16), 0, 0, 1, 1},
-    {&__pyx_n_s_int32, __pyx_k_int32, sizeof(__pyx_k_int32), 0, 0, 1, 1},
-    {&__pyx_n_s_int8, __pyx_k_int8, sizeof(__pyx_k_int8), 0, 0, 1, 1},
-    {&__pyx_n_s_io, __pyx_k_io, sizeof(__pyx_k_io), 0, 0, 1, 1},
-    {&__pyx_n_s_is_coroutine, __pyx_k_is_coroutine, sizeof(__pyx_k_is_coroutine), 0, 0, 1, 1},
-    {&__pyx_kp_u_is_incompatible_with_the_range, __pyx_k_is_incompatible_with_the_range, sizeof(__pyx_k_is_incompatible_with_the_range), 0, 1, 0, 0},
-    {&__pyx_n_u_is_signed, __pyx_k_is_signed, sizeof(__pyx_k_is_signed), 0, 1, 0, 1},
-    {&__pyx_n_s_itemsize, __pyx_k_itemsize, sizeof(__pyx_k_itemsize), 0, 0, 1, 1},
-    {&__pyx_n_s_logging, __pyx_k_logging, sizeof(__pyx_k_logging), 0, 0, 1, 1},
-    {&__pyx_n_s_main, __pyx_k_main, sizeof(__pyx_k_main), 0, 0, 1, 1},
-    {&__pyx_n_s_math, __pyx_k_math, sizeof(__pyx_k_math), 0, 0, 1, 1},
-    {&__pyx_n_s_max, __pyx_k_max, sizeof(__pyx_k_max), 0, 0, 1, 1},
-    {&__pyx_n_s_min, __pyx_k_min, sizeof(__pyx_k_min), 0, 0, 1, 1},
-    {&__pyx_n_u_monochrome, __pyx_k_monochrome, sizeof(__pyx_k_monochrome), 0, 1, 0, 1},
-    {&__pyx_n_s_msg, __pyx_k_msg, sizeof(__pyx_k_msg), 0, 0, 1, 1},
-    {&__pyx_n_s_name, __pyx_k_name, sizeof(__pyx_k_name), 0, 0, 1, 1},
-    {&__pyx_n_s_np, __pyx_k_np, sizeof(__pyx_k_np), 0, 0, 1, 1},
-    {&__pyx_n_s_nr_bytes, __pyx_k_nr_bytes, sizeof(__pyx_k_nr_bytes), 0, 0, 1, 1},
-    {&__pyx_n_u_nr_components, __pyx_k_nr_components, sizeof(__pyx_k_nr_components), 0, 1, 0, 1},
-    {&__pyx_n_u_nr_tiles, __pyx_k_nr_tiles, sizeof(__pyx_k_nr_tiles), 0, 1, 0, 1},
-    {&__pyx_n_s_numpy, __pyx_k_numpy, sizeof(__pyx_k_numpy), 0, 0, 1, 1},
-    {&__pyx_kp_u_numpy_core_multiarray_failed_to, __pyx_k_numpy_core_multiarray_failed_to, sizeof(__pyx_k_numpy_core_multiarray_failed_to), 0, 1, 0, 0},
-    {&__pyx_kp_u_numpy_core_umath_failed_to_impor, __pyx_k_numpy_core_umath_failed_to_impor, sizeof(__pyx_k_numpy_core_umath_failed_to_impor), 0, 1, 0, 0},
-    {&__pyx_kp_u_only_bool_u1_u2_u4_i1_i2_and_i4, __pyx_k_only_bool_u1_u2_u4_i1_i2_and_i4, sizeof(__pyx_k_only_bool_u1_u2_u4_i1_i2_and_i4), 0, 1, 0, 0},
-    {&__pyx_n_s_openjpeg, __pyx_k_openjpeg, sizeof(__pyx_k_openjpeg), 0, 0, 1, 1},
-    {&__pyx_kp_s_openjpeg__openjpeg_pyx, __pyx_k_openjpeg__openjpeg_pyx, sizeof(__pyx_k_openjpeg__openjpeg_pyx), 0, 0, 1, 0},
-    {&__pyx_n_s_out, __pyx_k_out, sizeof(__pyx_k_out), 0, 0, 1, 1},
-    {&__pyx_n_s_p_in, __pyx_k_p_in, sizeof(__pyx_k_p_in), 0, 0, 1, 1},
-    {&__pyx_n_s_p_out, __pyx_k_p_out, sizeof(__pyx_k_p_out), 0, 0, 1, 1},
-    {&__pyx_n_s_p_param, __pyx_k_p_param, sizeof(__pyx_k_p_param), 0, 0, 1, 1},
-    {&__pyx_n_s_param, __pyx_k_param, sizeof(__pyx_k_param), 0, 0, 1, 1},
-    {&__pyx_n_s_parameters, __pyx_k_parameters, sizeof(__pyx_k_parameters), 0, 0, 1, 1},
-    {&__pyx_n_s_photometric_interpretation, __pyx_k_photometric_interpretation, sizeof(__pyx_k_photometric_interpretation), 0, 0, 1, 1},
-    {&__pyx_n_u_precision, __pyx_k_precision, sizeof(__pyx_k_precision), 0, 1, 0, 1},
-    {&__pyx_n_s_ptr, __pyx_k_ptr, sizeof(__pyx_k_ptr), 0, 0, 1, 1},
-    {&__pyx_n_s_result, __pyx_k_result, sizeof(__pyx_k_result), 0, 0, 1, 1},
-    {&__pyx_n_s_return, __pyx_k_return, sizeof(__pyx_k_return), 0, 0, 1, 1},
-    {&__pyx_n_s_return_code, __pyx_k_return_code, sizeof(__pyx_k_return_code), 0, 0, 1, 1},
-    {&__pyx_n_u_rows, __pyx_k_rows, sizeof(__pyx_k_rows), 0, 1, 0, 1},
-    {&__pyx_n_u_sRGB, __pyx_k_sRGB, sizeof(__pyx_k_sRGB), 0, 1, 0, 1},
-    {&__pyx_n_s_signal_noise_ratios, __pyx_k_signal_noise_ratios, sizeof(__pyx_k_signal_noise_ratios), 0, 0, 1, 1},
-    {&__pyx_n_s_spec, __pyx_k_spec, sizeof(__pyx_k_spec), 0, 0, 1, 1},
-    {&__pyx_kp_u_support_for_more_than_16_bits_pe, __pyx_k_support_for_more_than_16_bits_pe, sizeof(__pyx_k_support_for_more_than_16_bits_pe), 0, 1, 0, 0},
-    {&__pyx_n_s_test, __pyx_k_test, sizeof(__pyx_k_test), 0, 0, 1, 1},
-    {&__pyx_n_s_typing, __pyx_k_typing, sizeof(__pyx_k_typing), 0, 0, 1, 1},
-    {&__pyx_n_s_uint16, __pyx_k_uint16, sizeof(__pyx_k_uint16), 0, 0, 1, 1},
-    {&__pyx_n_s_uint32, __pyx_k_uint32, sizeof(__pyx_k_uint32), 0, 0, 1, 1},
-    {&__pyx_n_s_uint8, __pyx_k_uint8, sizeof(__pyx_k_uint8), 0, 0, 1, 1},
-    {&__pyx_n_u_unknown, __pyx_k_unknown, sizeof(__pyx_k_unknown), 0, 1, 0, 1},
-    {&__pyx_n_u_unspecified, __pyx_k_unspecified, sizeof(__pyx_k_unspecified), 0, 1, 0, 1},
-    {&__pyx_n_s_use_mct, __pyx_k_use_mct, sizeof(__pyx_k_use_mct), 0, 0, 1, 1},
-    {&__pyx_n_s_version, __pyx_k_version, sizeof(__pyx_k_version), 0, 0, 1, 1},
-    {&__pyx_n_s_x, __pyx_k_x, sizeof(__pyx_k_x), 0, 0, 1, 1},
-    {&__pyx_n_s_zeros, __pyx_k_zeros, sizeof(__pyx_k_zeros), 0, 0, 1, 1},
-    {0, 0, 0, 0, 0, 0, 0}
-  };
-  return __Pyx_InitStrings(__pyx_string_tab);
-}
-/* #### Code section: cached_builtins ### */
-static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) {
-  __pyx_builtin_KeyError = __Pyx_GetBuiltinName(__pyx_n_s_KeyError); if (!__pyx_builtin_KeyError) __PYX_ERR(0, 161, __pyx_L1_error)
-  __pyx_builtin_RuntimeError = __Pyx_GetBuiltinName(__pyx_n_s_RuntimeError); if (!__pyx_builtin_RuntimeError) __PYX_ERR(0, 164, __pyx_L1_error)
-  __pyx_builtin_ValueError = __Pyx_GetBuiltinName(__pyx_n_s_ValueError); if (!__pyx_builtin_ValueError) __PYX_ERR(0, 238, __pyx_L1_error)
-  __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(1, 986, __pyx_L1_error)
-  return 0;
-  __pyx_L1_error:;
-  return -1;
-}
-/* #### Code section: cached_constants ### */
-
-static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) {
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__Pyx_InitCachedConstants", 0);
-
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":986
- *         __pyx_import_array()
- *     except Exception:
- *         raise ImportError("numpy.core.multiarray failed to import")             # <<<<<<<<<<<<<<
+/* "_openjpeg.pyx":325
  * 
- * cdef inline int import_umath() except -1:
- */
-  __pyx_tuple_ = PyTuple_Pack(1, __pyx_kp_u_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple_)) __PYX_ERR(1, 986, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_tuple_);
-  __Pyx_GIVEREF(__pyx_tuple_);
-
-  /* "../../../../../tmp/pip-build-env-k1t5uzrx/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":992
- *         _import_umath()
- *     except Exception:
- *         raise ImportError("numpy.core.umath failed to import")             # <<<<<<<<<<<<<<
  * 
- * cdef inline int import_ufunc() except -1:
- */
-  __pyx_tuple__2 = PyTuple_Pack(1, __pyx_kp_u_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__2)) __PYX_ERR(1, 992, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_tuple__2);
-  __Pyx_GIVEREF(__pyx_tuple__2);
-
-  /* "_openjpeg.pyx":259
- *         or (arr.dtype == np.int32 and (arr_max > 2**23 - 1 or arr_min < -2**23))
- *     ):
- *         raise ValueError(             # <<<<<<<<<<<<<<
- *             "The input array contains values outside the range of the maximum "
- *             "supported bit-depth of 24"
+ * def encode_buffer(             # <<<<<<<<<<<<<<
+ *     src,
+ *     int columns,
  */
-  __pyx_tuple__5 = PyTuple_Pack(1, __pyx_kp_u_The_input_array_contains_values); if (unlikely(!__pyx_tuple__5)) __PYX_ERR(0, 259, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_tuple__5);
-  __Pyx_GIVEREF(__pyx_tuple__5);
 
-  /* "_openjpeg.pyx":284
+/* Python wrapper */
+static PyObject *__pyx_pw_9_openjpeg_9encode_buffer(PyObject *__pyx_self, 
+#if CYTHON_METH_FASTCALL
+PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds
+#else
+PyObject *__pyx_args, PyObject *__pyx_kwds
+#endif
+); /*proto*/
+PyDoc_STRVAR(__pyx_doc_9_openjpeg_8encode_buffer, "Return the JPEG 2000 compressed `src`.\n\n    If performing lossy encoding then either `compression_ratios` or\n    `signal_noise_ratios` must be set to a non-empty list, otherwise lossless\n    encoding will be used.\n\n    Parameters\n    ----------\n    src : bytes | bytearray\n        A bytes or bytearray containing the image data to be encoded, ordered as\n        little endian and colour-by-pixel.\n    columns : int\n        The number of columns in the image, should be in the range (1, 16777215).\n    rows : int\n        The number of rows in the image, should be in the range (1, 16777215).\n    samples_per_pixel : int\n        The number of samples per pixel, should be 1, 3 or 4.\n    bits_stored : int\n        The number of bits used per pixel (i.e. the sample precision), should be\n        in the range (1, 24).\n    is_signed: int\n        ``0`` if the image uses unsigned pixels, ``1`` for signed.\n    photometric_interpretation : int\n        The colour space of the unencoded image data that will be set in the\n        JPEG 2000 metadata, should be in the range (0, 5):\n            ``0``: OPJ_CLRSPC_UNSPECIFIED\n            ``1``: OPJ_CLRSPC_SRGB\n            ``2``: OPJ_CLRSPC_GRAY\n            ``3``: OPJ_CLRSPC_SYCC\n            ``4``: OPJ_CLRSPC_EYCC\n            ``5``: OPJ_CLRSPC_CMYK\n    use_mct : bool\n        If ``1`` then apply multi-component transformation (MCT) to RGB\n        images. Requires a `photometric_interpretation` of ``1`` and a\n        `samples_per_pixel` value of ``3``.\n    compression_ratios : list[float]\n        Required for lossy encoding, this is the compression ratio to use\n        for each quality layer. Cannot be used with `signal_noise_ratios`.\n    signal_noise_ratios : list[float]\n        Required for lossy encoding, this is the PSNR to use for each quality\n        layer. Cannot be used with `compression_ratios`.\n    codec_format : int, optional\n        The codec to used when encoding:\n\n        * ``0``: JPEG 2000"" codestream only (default) (J2K/J2C format)\n        * ``2``: A boxed JPEG 2000 codestream (JP2 format)\n\n    Returns\n    -------\n    tuple[int, bytes]\n        The return code of the encoding and the JPEG 2000 encoded image data.\n        The return code will be ``0`` for success, otherwise the encoding\n        failed.\n    ");
+static PyMethodDef __pyx_mdef_9_openjpeg_9encode_buffer = {"encode_buffer", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_9_openjpeg_9encode_buffer, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_9_openjpeg_8encode_buffer};
+static PyObject *__pyx_pw_9_openjpeg_9encode_buffer(PyObject *__pyx_self, 
+#if CYTHON_METH_FASTCALL
+PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds
+#else
+PyObject *__pyx_args, PyObject *__pyx_kwds
+#endif
+) {
+  PyObject *__pyx_v_src = 0;
+  int __pyx_v_columns;
+  int __pyx_v_rows;
+  int __pyx_v_samples_per_pixel;
+  int __pyx_v_bits_stored;
+  int __pyx_v_is_signed;
+  int __pyx_v_photometric_interpretation;
+  int __pyx_v_use_mct;
+  PyObject *__pyx_v_compression_ratios = 0;
+  PyObject *__pyx_v_signal_noise_ratios = 0;
+  int __pyx_v_codec_format;
+  #if !CYTHON_METH_FASTCALL
+  CYTHON_UNUSED Py_ssize_t __pyx_nargs;
+  #endif
+  CYTHON_UNUSED PyObject *const *__pyx_kwvalues;
+  PyObject* values[11] = {0,0,0,0,0,0,0,0,0,0,0};
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("encode_buffer (wrapper)", 0);
+  #if !CYTHON_METH_FASTCALL
+  #if CYTHON_ASSUME_SAFE_MACROS
+  __pyx_nargs = PyTuple_GET_SIZE(__pyx_args);
+  #else
+  __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL;
+  #endif
+  #endif
+  __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs);
+  {
+    PyObject **__pyx_pyargnames[] = {&__pyx_n_s_src,&__pyx_n_s_columns,&__pyx_n_s_rows,&__pyx_n_s_samples_per_pixel,&__pyx_n_s_bits_stored,&__pyx_n_s_is_signed,&__pyx_n_s_photometric_interpretation,&__pyx_n_s_use_mct,&__pyx_n_s_compression_ratios,&__pyx_n_s_signal_noise_ratios,&__pyx_n_s_codec_format,0};
+    if (__pyx_kwds) {
+      Py_ssize_t kw_args;
+      switch (__pyx_nargs) {
+        case 11: values[10] = __Pyx_Arg_FASTCALL(__pyx_args, 10);
+        CYTHON_FALLTHROUGH;
+        case 10: values[9] = __Pyx_Arg_FASTCALL(__pyx_args, 9);
+        CYTHON_FALLTHROUGH;
+        case  9: values[8] = __Pyx_Arg_FASTCALL(__pyx_args, 8);
+        CYTHON_FALLTHROUGH;
+        case  8: values[7] = __Pyx_Arg_FASTCALL(__pyx_args, 7);
+        CYTHON_FALLTHROUGH;
+        case  7: values[6] = __Pyx_Arg_FASTCALL(__pyx_args, 6);
+        CYTHON_FALLTHROUGH;
+        case  6: values[5] = __Pyx_Arg_FASTCALL(__pyx_args, 5);
+        CYTHON_FALLTHROUGH;
+        case  5: values[4] = __Pyx_Arg_FASTCALL(__pyx_args, 4);
+        CYTHON_FALLTHROUGH;
+        case  4: values[3] = __Pyx_Arg_FASTCALL(__pyx_args, 3);
+        CYTHON_FALLTHROUGH;
+        case  3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2);
+        CYTHON_FALLTHROUGH;
+        case  2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1);
+        CYTHON_FALLTHROUGH;
+        case  1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0);
+        CYTHON_FALLTHROUGH;
+        case  0: break;
+        default: goto __pyx_L5_argtuple_error;
+      }
+      kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds);
+      switch (__pyx_nargs) {
+        case  0:
+        if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_src)) != 0)) {
+          (void)__Pyx_Arg_NewRef_FASTCALL(values[0]);
+          kw_args--;
+        }
+        else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 325, __pyx_L3_error)
+        else goto __pyx_L5_argtuple_error;
+        CYTHON_FALLTHROUGH;
+        case  1:
+        if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_columns)) != 0)) {
+          (void)__Pyx_Arg_NewRef_FASTCALL(values[1]);
+          kw_args--;
+        }
+        else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 325, __pyx_L3_error)
+        else {
+          __Pyx_RaiseArgtupleInvalid("encode_buffer", 1, 11, 11, 1); __PYX_ERR(0, 325, __pyx_L3_error)
+        }
+        CYTHON_FALLTHROUGH;
+        case  2:
+        if (likely((values[2] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_rows)) != 0)) {
+          (void)__Pyx_Arg_NewRef_FASTCALL(values[2]);
+          kw_args--;
+        }
+        else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 325, __pyx_L3_error)
+        else {
+          __Pyx_RaiseArgtupleInvalid("encode_buffer", 1, 11, 11, 2); __PYX_ERR(0, 325, __pyx_L3_error)
+        }
+        CYTHON_FALLTHROUGH;
+        case  3:
+        if (likely((values[3] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_samples_per_pixel)) != 0)) {
+          (void)__Pyx_Arg_NewRef_FASTCALL(values[3]);
+          kw_args--;
+        }
+        else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 325, __pyx_L3_error)
+        else {
+          __Pyx_RaiseArgtupleInvalid("encode_buffer", 1, 11, 11, 3); __PYX_ERR(0, 325, __pyx_L3_error)
+        }
+        CYTHON_FALLTHROUGH;
+        case  4:
+        if (likely((values[4] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_bits_stored)) != 0)) {
+          (void)__Pyx_Arg_NewRef_FASTCALL(values[4]);
+          kw_args--;
+        }
+        else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 325, __pyx_L3_error)
+        else {
+          __Pyx_RaiseArgtupleInvalid("encode_buffer", 1, 11, 11, 4); __PYX_ERR(0, 325, __pyx_L3_error)
+        }
+        CYTHON_FALLTHROUGH;
+        case  5:
+        if (likely((values[5] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_is_signed)) != 0)) {
+          (void)__Pyx_Arg_NewRef_FASTCALL(values[5]);
+          kw_args--;
+        }
+        else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 325, __pyx_L3_error)
+        else {
+          __Pyx_RaiseArgtupleInvalid("encode_buffer", 1, 11, 11, 5); __PYX_ERR(0, 325, __pyx_L3_error)
+        }
+        CYTHON_FALLTHROUGH;
+        case  6:
+        if (likely((values[6] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_photometric_interpretation)) != 0)) {
+          (void)__Pyx_Arg_NewRef_FASTCALL(values[6]);
+          kw_args--;
+        }
+        else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 325, __pyx_L3_error)
+        else {
+          __Pyx_RaiseArgtupleInvalid("encode_buffer", 1, 11, 11, 6); __PYX_ERR(0, 325, __pyx_L3_error)
+        }
+        CYTHON_FALLTHROUGH;
+        case  7:
+        if (likely((values[7] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_use_mct)) != 0)) {
+          (void)__Pyx_Arg_NewRef_FASTCALL(values[7]);
+          kw_args--;
+        }
+        else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 325, __pyx_L3_error)
+        else {
+          __Pyx_RaiseArgtupleInvalid("encode_buffer", 1, 11, 11, 7); __PYX_ERR(0, 325, __pyx_L3_error)
+        }
+        CYTHON_FALLTHROUGH;
+        case  8:
+        if (likely((values[8] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_compression_ratios)) != 0)) {
+          (void)__Pyx_Arg_NewRef_FASTCALL(values[8]);
+          kw_args--;
+        }
+        else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 325, __pyx_L3_error)
+        else {
+          __Pyx_RaiseArgtupleInvalid("encode_buffer", 1, 11, 11, 8); __PYX_ERR(0, 325, __pyx_L3_error)
+        }
+        CYTHON_FALLTHROUGH;
+        case  9:
+        if (likely((values[9] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_signal_noise_ratios)) != 0)) {
+          (void)__Pyx_Arg_NewRef_FASTCALL(values[9]);
+          kw_args--;
+        }
+        else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 325, __pyx_L3_error)
+        else {
+          __Pyx_RaiseArgtupleInvalid("encode_buffer", 1, 11, 11, 9); __PYX_ERR(0, 325, __pyx_L3_error)
+        }
+        CYTHON_FALLTHROUGH;
+        case 10:
+        if (likely((values[10] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_codec_format)) != 0)) {
+          (void)__Pyx_Arg_NewRef_FASTCALL(values[10]);
+          kw_args--;
+        }
+        else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 325, __pyx_L3_error)
+        else {
+          __Pyx_RaiseArgtupleInvalid("encode_buffer", 1, 11, 11, 10); __PYX_ERR(0, 325, __pyx_L3_error)
+        }
+      }
+      if (unlikely(kw_args > 0)) {
+        const Py_ssize_t kwd_pos_args = __pyx_nargs;
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "encode_buffer") < 0)) __PYX_ERR(0, 325, __pyx_L3_error)
+      }
+    } else if (unlikely(__pyx_nargs != 11)) {
+      goto __pyx_L5_argtuple_error;
+    } else {
+      values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0);
+      values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1);
+      values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2);
+      values[3] = __Pyx_Arg_FASTCALL(__pyx_args, 3);
+      values[4] = __Pyx_Arg_FASTCALL(__pyx_args, 4);
+      values[5] = __Pyx_Arg_FASTCALL(__pyx_args, 5);
+      values[6] = __Pyx_Arg_FASTCALL(__pyx_args, 6);
+      values[7] = __Pyx_Arg_FASTCALL(__pyx_args, 7);
+      values[8] = __Pyx_Arg_FASTCALL(__pyx_args, 8);
+      values[9] = __Pyx_Arg_FASTCALL(__pyx_args, 9);
+      values[10] = __Pyx_Arg_FASTCALL(__pyx_args, 10);
+    }
+    __pyx_v_src = values[0];
+    __pyx_v_columns = __Pyx_PyInt_As_int(values[1]); if (unlikely((__pyx_v_columns == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 327, __pyx_L3_error)
+    __pyx_v_rows = __Pyx_PyInt_As_int(values[2]); if (unlikely((__pyx_v_rows == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 328, __pyx_L3_error)
+    __pyx_v_samples_per_pixel = __Pyx_PyInt_As_int(values[3]); if (unlikely((__pyx_v_samples_per_pixel == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 329, __pyx_L3_error)
+    __pyx_v_bits_stored = __Pyx_PyInt_As_int(values[4]); if (unlikely((__pyx_v_bits_stored == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 330, __pyx_L3_error)
+    __pyx_v_is_signed = __Pyx_PyInt_As_int(values[5]); if (unlikely((__pyx_v_is_signed == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 331, __pyx_L3_error)
+    __pyx_v_photometric_interpretation = __Pyx_PyInt_As_int(values[6]); if (unlikely((__pyx_v_photometric_interpretation == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 332, __pyx_L3_error)
+    __pyx_v_use_mct = __Pyx_PyInt_As_int(values[7]); if (unlikely((__pyx_v_use_mct == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 333, __pyx_L3_error)
+    __pyx_v_compression_ratios = ((PyObject*)values[8]);
+    __pyx_v_signal_noise_ratios = ((PyObject*)values[9]);
+    __pyx_v_codec_format = __Pyx_PyInt_As_int(values[10]); if (unlikely((__pyx_v_codec_format == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 336, __pyx_L3_error)
+  }
+  goto __pyx_L6_skip;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("encode_buffer", 1, 11, 11, __pyx_nargs); __PYX_ERR(0, 325, __pyx_L3_error)
+  __pyx_L6_skip:;
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L3_error:;
+  {
+    Py_ssize_t __pyx_temp;
+    for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) {
+      __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]);
+    }
+  }
+  __Pyx_AddTraceback("_openjpeg.encode_buffer", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+  __pyx_L4_argument_unpacking_done:;
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_compression_ratios), (&PyList_Type), 1, "compression_ratios", 1))) __PYX_ERR(0, 334, __pyx_L1_error)
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_signal_noise_ratios), (&PyList_Type), 1, "signal_noise_ratios", 1))) __PYX_ERR(0, 335, __pyx_L1_error)
+  __pyx_r = __pyx_pf_9_openjpeg_8encode_buffer(__pyx_self, __pyx_v_src, __pyx_v_columns, __pyx_v_rows, __pyx_v_samples_per_pixel, __pyx_v_bits_stored, __pyx_v_is_signed, __pyx_v_photometric_interpretation, __pyx_v_use_mct, __pyx_v_compression_ratios, __pyx_v_signal_noise_ratios, __pyx_v_codec_format);
+
+  /* function exit code */
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __pyx_r = NULL;
+  __pyx_L0:;
+  {
+    Py_ssize_t __pyx_temp;
+    for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) {
+      __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]);
+    }
+  }
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+static PyObject *__pyx_pf_9_openjpeg_8encode_buffer(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_src, int __pyx_v_columns, int __pyx_v_rows, int __pyx_v_samples_per_pixel, int __pyx_v_bits_stored, int __pyx_v_is_signed, int __pyx_v_photometric_interpretation, int __pyx_v_use_mct, PyObject *__pyx_v_compression_ratios, PyObject *__pyx_v_signal_noise_ratios, int __pyx_v_codec_format) {
+  PyObject *__pyx_v_bytes_allocated = NULL;
+  Py_ssize_t __pyx_v_actual_length;
+  PyObject *__pyx_v_expected_length = NULL;
+  PyObject *__pyx_v_dst = NULL;
+  int __pyx_v_return_code;
+  PyObject *__pyx_8genexpr2__pyx_v_x = NULL;
+  PyObject *__pyx_8genexpr3__pyx_v_x = NULL;
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  int __pyx_t_1;
+  int __pyx_t_2;
+  PyObject *__pyx_t_3 = NULL;
+  PyObject *__pyx_t_4 = NULL;
+  Py_ssize_t __pyx_t_5;
+  Py_UCS4 __pyx_t_6;
+  PyObject *__pyx_t_7 = NULL;
+  int __pyx_t_8;
+  PyObject *__pyx_t_9 = NULL;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("encode_buffer", 0);
+  __Pyx_INCREF(__pyx_v_compression_ratios);
+  __Pyx_INCREF(__pyx_v_signal_noise_ratios);
+
+  /* "_openjpeg.pyx":393
+ *     """
+ *     # Checks
+ *     if not isinstance(src, (bytes, bytearray)):             # <<<<<<<<<<<<<<
+ *         raise TypeError(
+ *             f"'src' must be bytes or bytearray, not {type(src).__name__}"
+ */
+  __pyx_t_2 = PyBytes_Check(__pyx_v_src); 
+  if (!__pyx_t_2) {
+  } else {
+    __pyx_t_1 = __pyx_t_2;
+    goto __pyx_L4_bool_binop_done;
+  }
+  __pyx_t_2 = PyByteArray_Check(__pyx_v_src); 
+  __pyx_t_1 = __pyx_t_2;
+  __pyx_L4_bool_binop_done:;
+  __pyx_t_2 = (!__pyx_t_1);
+  if (unlikely(__pyx_t_2)) {
+
+    /* "_openjpeg.pyx":395
+ *     if not isinstance(src, (bytes, bytearray)):
+ *         raise TypeError(
+ *             f"'src' must be bytes or bytearray, not {type(src).__name__}"             # <<<<<<<<<<<<<<
+ *         )
+ * 
+ */
+    __pyx_t_3 = __Pyx_PyObject_GetAttrStr(((PyObject *)Py_TYPE(__pyx_v_src)), __pyx_n_s_name); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 395, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_3);
+    __pyx_t_4 = __Pyx_PyObject_FormatSimple(__pyx_t_3, __pyx_empty_unicode); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 395, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_4);
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    __pyx_t_3 = __Pyx_PyUnicode_Concat(__pyx_kp_u_src_must_be_bytes_or_bytearray, __pyx_t_4); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 395, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_3);
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+
+    /* "_openjpeg.pyx":394
+ *     # Checks
+ *     if not isinstance(src, (bytes, bytearray)):
+ *         raise TypeError(             # <<<<<<<<<<<<<<
+ *             f"'src' must be bytes or bytearray, not {type(src).__name__}"
+ *         )
+ */
+    __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_builtin_TypeError, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 394, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_4);
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    __Pyx_Raise(__pyx_t_4, 0, 0, 0);
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    __PYX_ERR(0, 394, __pyx_L1_error)
+
+    /* "_openjpeg.pyx":393
+ *     """
+ *     # Checks
+ *     if not isinstance(src, (bytes, bytearray)):             # <<<<<<<<<<<<<<
+ *         raise TypeError(
+ *             f"'src' must be bytes or bytearray, not {type(src).__name__}"
+ */
+  }
+
+  /* "_openjpeg.pyx":398
+ *         )
+ * 
+ *     if not 1 <= columns <= 65535:             # <<<<<<<<<<<<<<
+ *         raise ValueError(
+ *             f"Invalid 'columns' value '{columns}', must be in the range [1, 65535]"
+ */
+  __pyx_t_2 = (1 <= __pyx_v_columns);
+  if (__pyx_t_2) {
+    __pyx_t_2 = (__pyx_v_columns <= 0xFFFF);
+  }
+  __pyx_t_1 = (!__pyx_t_2);
+  if (unlikely(__pyx_t_1)) {
+
+    /* "_openjpeg.pyx":400
+ *     if not 1 <= columns <= 65535:
+ *         raise ValueError(
+ *             f"Invalid 'columns' value '{columns}', must be in the range [1, 65535]"             # <<<<<<<<<<<<<<
+ *         )
+ * 
+ */
+    __pyx_t_4 = PyTuple_New(3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 400, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_4);
+    __pyx_t_5 = 0;
+    __pyx_t_6 = 127;
+    __Pyx_INCREF(__pyx_kp_u_Invalid_columns_value);
+    __pyx_t_5 += 25;
+    __Pyx_GIVEREF(__pyx_kp_u_Invalid_columns_value);
+    PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_kp_u_Invalid_columns_value);
+    __pyx_t_3 = __Pyx_PyUnicode_From_int(__pyx_v_columns, 0, ' ', 'd'); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 400, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_3);
+    __pyx_t_5 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_3);
+    __Pyx_GIVEREF(__pyx_t_3);
+    PyTuple_SET_ITEM(__pyx_t_4, 1, __pyx_t_3);
+    __pyx_t_3 = 0;
+    __Pyx_INCREF(__pyx_kp_u_must_be_in_the_range_1_65535);
+    __pyx_t_5 += 34;
+    __Pyx_GIVEREF(__pyx_kp_u_must_be_in_the_range_1_65535);
+    PyTuple_SET_ITEM(__pyx_t_4, 2, __pyx_kp_u_must_be_in_the_range_1_65535);
+    __pyx_t_3 = __Pyx_PyUnicode_Join(__pyx_t_4, 3, __pyx_t_5, __pyx_t_6); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 400, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_3);
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+
+    /* "_openjpeg.pyx":399
+ * 
+ *     if not 1 <= columns <= 65535:
+ *         raise ValueError(             # <<<<<<<<<<<<<<
+ *             f"Invalid 'columns' value '{columns}', must be in the range [1, 65535]"
+ *         )
+ */
+    __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 399, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_4);
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    __Pyx_Raise(__pyx_t_4, 0, 0, 0);
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    __PYX_ERR(0, 399, __pyx_L1_error)
+
+    /* "_openjpeg.pyx":398
+ *         )
+ * 
+ *     if not 1 <= columns <= 65535:             # <<<<<<<<<<<<<<
+ *         raise ValueError(
+ *             f"Invalid 'columns' value '{columns}', must be in the range [1, 65535]"
+ */
+  }
+
+  /* "_openjpeg.pyx":403
+ *         )
+ * 
+ *     if not 1 <= rows <= 65535:             # <<<<<<<<<<<<<<
+ *         raise ValueError(
+ *             f"Invalid 'rows' value '{rows}', must be in the range [1, 65535]"
+ */
+  __pyx_t_1 = (1 <= __pyx_v_rows);
+  if (__pyx_t_1) {
+    __pyx_t_1 = (__pyx_v_rows <= 0xFFFF);
+  }
+  __pyx_t_2 = (!__pyx_t_1);
+  if (unlikely(__pyx_t_2)) {
+
+    /* "_openjpeg.pyx":405
+ *     if not 1 <= rows <= 65535:
+ *         raise ValueError(
+ *             f"Invalid 'rows' value '{rows}', must be in the range [1, 65535]"             # <<<<<<<<<<<<<<
+ *         )
+ * 
+ */
+    __pyx_t_4 = PyTuple_New(3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 405, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_4);
+    __pyx_t_5 = 0;
+    __pyx_t_6 = 127;
+    __Pyx_INCREF(__pyx_kp_u_Invalid_rows_value);
+    __pyx_t_5 += 22;
+    __Pyx_GIVEREF(__pyx_kp_u_Invalid_rows_value);
+    PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_kp_u_Invalid_rows_value);
+    __pyx_t_3 = __Pyx_PyUnicode_From_int(__pyx_v_rows, 0, ' ', 'd'); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 405, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_3);
+    __pyx_t_5 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_3);
+    __Pyx_GIVEREF(__pyx_t_3);
+    PyTuple_SET_ITEM(__pyx_t_4, 1, __pyx_t_3);
+    __pyx_t_3 = 0;
+    __Pyx_INCREF(__pyx_kp_u_must_be_in_the_range_1_65535);
+    __pyx_t_5 += 34;
+    __Pyx_GIVEREF(__pyx_kp_u_must_be_in_the_range_1_65535);
+    PyTuple_SET_ITEM(__pyx_t_4, 2, __pyx_kp_u_must_be_in_the_range_1_65535);
+    __pyx_t_3 = __Pyx_PyUnicode_Join(__pyx_t_4, 3, __pyx_t_5, __pyx_t_6); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 405, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_3);
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+
+    /* "_openjpeg.pyx":404
+ * 
+ *     if not 1 <= rows <= 65535:
+ *         raise ValueError(             # <<<<<<<<<<<<<<
+ *             f"Invalid 'rows' value '{rows}', must be in the range [1, 65535]"
+ *         )
+ */
+    __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 404, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_4);
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    __Pyx_Raise(__pyx_t_4, 0, 0, 0);
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    __PYX_ERR(0, 404, __pyx_L1_error)
+
+    /* "_openjpeg.pyx":403
+ *         )
+ * 
+ *     if not 1 <= rows <= 65535:             # <<<<<<<<<<<<<<
+ *         raise ValueError(
+ *             f"Invalid 'rows' value '{rows}', must be in the range [1, 65535]"
+ */
+  }
+
+  /* "_openjpeg.pyx":408
+ *         )
+ * 
+ *     if samples_per_pixel not in (1, 3, 4):             # <<<<<<<<<<<<<<
+ *         raise ValueError(
+ *             f"Invalid 'samples_per_pixel' value '{samples_per_pixel}', must be 1, 3 "
+ */
+  switch (__pyx_v_samples_per_pixel) {
+    case 1:
+    case 3:
+    case 4:
+    __pyx_t_2 = 0;
+    break;
+    default:
+    __pyx_t_2 = 1;
+    break;
+  }
+  __pyx_t_1 = __pyx_t_2;
+  if (unlikely(__pyx_t_1)) {
+
+    /* "_openjpeg.pyx":410
+ *     if samples_per_pixel not in (1, 3, 4):
+ *         raise ValueError(
+ *             f"Invalid 'samples_per_pixel' value '{samples_per_pixel}', must be 1, 3 "             # <<<<<<<<<<<<<<
+ *             "or 4"
+ *         )
+ */
+    __pyx_t_4 = PyTuple_New(3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 410, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_4);
+    __pyx_t_5 = 0;
+    __pyx_t_6 = 127;
+    __Pyx_INCREF(__pyx_kp_u_Invalid_samples_per_pixel_value);
+    __pyx_t_5 += 35;
+    __Pyx_GIVEREF(__pyx_kp_u_Invalid_samples_per_pixel_value);
+    PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_kp_u_Invalid_samples_per_pixel_value);
+    __pyx_t_3 = __Pyx_PyUnicode_From_int(__pyx_v_samples_per_pixel, 0, ' ', 'd'); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 410, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_3);
+    __pyx_t_5 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_3);
+    __Pyx_GIVEREF(__pyx_t_3);
+    PyTuple_SET_ITEM(__pyx_t_4, 1, __pyx_t_3);
+    __pyx_t_3 = 0;
+    __Pyx_INCREF(__pyx_kp_u_must_be_1_3_or_4);
+    __pyx_t_5 += 20;
+    __Pyx_GIVEREF(__pyx_kp_u_must_be_1_3_or_4);
+    PyTuple_SET_ITEM(__pyx_t_4, 2, __pyx_kp_u_must_be_1_3_or_4);
+    __pyx_t_3 = __Pyx_PyUnicode_Join(__pyx_t_4, 3, __pyx_t_5, __pyx_t_6); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 410, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_3);
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+
+    /* "_openjpeg.pyx":409
+ * 
+ *     if samples_per_pixel not in (1, 3, 4):
+ *         raise ValueError(             # <<<<<<<<<<<<<<
+ *             f"Invalid 'samples_per_pixel' value '{samples_per_pixel}', must be 1, 3 "
+ *             "or 4"
+ */
+    __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 409, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_4);
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    __Pyx_Raise(__pyx_t_4, 0, 0, 0);
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    __PYX_ERR(0, 409, __pyx_L1_error)
+
+    /* "_openjpeg.pyx":408
+ *         )
+ * 
+ *     if samples_per_pixel not in (1, 3, 4):             # <<<<<<<<<<<<<<
+ *         raise ValueError(
+ *             f"Invalid 'samples_per_pixel' value '{samples_per_pixel}', must be 1, 3 "
+ */
+  }
+
+  /* "_openjpeg.pyx":414
+ *         )
+ * 
+ *     if 0 < bits_stored <= 8:             # <<<<<<<<<<<<<<
+ *         bytes_allocated = 1
+ *     elif 8 < bits_stored <= 16:
+ */
+  __pyx_t_1 = (0 < __pyx_v_bits_stored);
+  if (__pyx_t_1) {
+    __pyx_t_1 = (__pyx_v_bits_stored <= 8);
+  }
+  if (__pyx_t_1) {
+
+    /* "_openjpeg.pyx":415
+ * 
+ *     if 0 < bits_stored <= 8:
+ *         bytes_allocated = 1             # <<<<<<<<<<<<<<
+ *     elif 8 < bits_stored <= 16:
+ *         bytes_allocated = 2
+ */
+    __Pyx_INCREF(__pyx_int_1);
+    __pyx_v_bytes_allocated = __pyx_int_1;
+
+    /* "_openjpeg.pyx":414
+ *         )
+ * 
+ *     if 0 < bits_stored <= 8:             # <<<<<<<<<<<<<<
+ *         bytes_allocated = 1
+ *     elif 8 < bits_stored <= 16:
+ */
+    goto __pyx_L9;
+  }
+
+  /* "_openjpeg.pyx":416
+ *     if 0 < bits_stored <= 8:
+ *         bytes_allocated = 1
+ *     elif 8 < bits_stored <= 16:             # <<<<<<<<<<<<<<
+ *         bytes_allocated = 2
+ *     elif 16 < bits_stored <= 24:
+ */
+  __pyx_t_1 = (8 < __pyx_v_bits_stored);
+  if (__pyx_t_1) {
+    __pyx_t_1 = (__pyx_v_bits_stored <= 16);
+  }
+  if (__pyx_t_1) {
+
+    /* "_openjpeg.pyx":417
+ *         bytes_allocated = 1
+ *     elif 8 < bits_stored <= 16:
+ *         bytes_allocated = 2             # <<<<<<<<<<<<<<
+ *     elif 16 < bits_stored <= 24:
+ *         bytes_allocated = 4
+ */
+    __Pyx_INCREF(__pyx_int_2);
+    __pyx_v_bytes_allocated = __pyx_int_2;
+
+    /* "_openjpeg.pyx":416
+ *     if 0 < bits_stored <= 8:
+ *         bytes_allocated = 1
+ *     elif 8 < bits_stored <= 16:             # <<<<<<<<<<<<<<
+ *         bytes_allocated = 2
+ *     elif 16 < bits_stored <= 24:
+ */
+    goto __pyx_L9;
+  }
+
+  /* "_openjpeg.pyx":418
+ *     elif 8 < bits_stored <= 16:
+ *         bytes_allocated = 2
+ *     elif 16 < bits_stored <= 24:             # <<<<<<<<<<<<<<
+ *         bytes_allocated = 4
+ *     else:
+ */
+  __pyx_t_1 = (16 < __pyx_v_bits_stored);
+  if (__pyx_t_1) {
+    __pyx_t_1 = (__pyx_v_bits_stored <= 24);
+  }
+  if (likely(__pyx_t_1)) {
+
+    /* "_openjpeg.pyx":419
+ *         bytes_allocated = 2
+ *     elif 16 < bits_stored <= 24:
+ *         bytes_allocated = 4             # <<<<<<<<<<<<<<
+ *     else:
+ *         raise ValueError(
+ */
+    __Pyx_INCREF(__pyx_int_4);
+    __pyx_v_bytes_allocated = __pyx_int_4;
+
+    /* "_openjpeg.pyx":418
+ *     elif 8 < bits_stored <= 16:
+ *         bytes_allocated = 2
+ *     elif 16 < bits_stored <= 24:             # <<<<<<<<<<<<<<
+ *         bytes_allocated = 4
+ *     else:
+ */
+    goto __pyx_L9;
+  }
+
+  /* "_openjpeg.pyx":421
+ *         bytes_allocated = 4
+ *     else:
+ *         raise ValueError(             # <<<<<<<<<<<<<<
+ *             f"Invalid 'bits_stored' value '{bits_stored}', must be in the "
+ *             "range [1, 24]"
+ */
+  /*else*/ {
+
+    /* "_openjpeg.pyx":422
+ *     else:
+ *         raise ValueError(
+ *             f"Invalid 'bits_stored' value '{bits_stored}', must be in the "             # <<<<<<<<<<<<<<
+ *             "range [1, 24]"
+ *         )
+ */
+    __pyx_t_4 = PyTuple_New(3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 422, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_4);
+    __pyx_t_5 = 0;
+    __pyx_t_6 = 127;
+    __Pyx_INCREF(__pyx_kp_u_Invalid_bits_stored_value);
+    __pyx_t_5 += 29;
+    __Pyx_GIVEREF(__pyx_kp_u_Invalid_bits_stored_value);
+    PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_kp_u_Invalid_bits_stored_value);
+    __pyx_t_3 = __Pyx_PyUnicode_From_int(__pyx_v_bits_stored, 0, ' ', 'd'); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 422, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_3);
+    __pyx_t_5 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_3);
+    __Pyx_GIVEREF(__pyx_t_3);
+    PyTuple_SET_ITEM(__pyx_t_4, 1, __pyx_t_3);
+    __pyx_t_3 = 0;
+    __Pyx_INCREF(__pyx_kp_u_must_be_in_the_range_1_24);
+    __pyx_t_5 += 31;
+    __Pyx_GIVEREF(__pyx_kp_u_must_be_in_the_range_1_24);
+    PyTuple_SET_ITEM(__pyx_t_4, 2, __pyx_kp_u_must_be_in_the_range_1_24);
+    __pyx_t_3 = __Pyx_PyUnicode_Join(__pyx_t_4, 3, __pyx_t_5, __pyx_t_6); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 422, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_3);
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+
+    /* "_openjpeg.pyx":421
+ *         bytes_allocated = 4
+ *     else:
+ *         raise ValueError(             # <<<<<<<<<<<<<<
+ *             f"Invalid 'bits_stored' value '{bits_stored}', must be in the "
+ *             "range [1, 24]"
+ */
+    __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 421, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_4);
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    __Pyx_Raise(__pyx_t_4, 0, 0, 0);
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    __PYX_ERR(0, 421, __pyx_L1_error)
+  }
+  __pyx_L9:;
+
+  /* "_openjpeg.pyx":426
+ *         )
+ * 
+ *     actual_length = len(src)             # <<<<<<<<<<<<<<
+ *     expected_length = rows * columns * samples_per_pixel * bytes_allocated
+ *     if actual_length != expected_length:
+ */
+  __pyx_t_5 = PyObject_Length(__pyx_v_src); if (unlikely(__pyx_t_5 == ((Py_ssize_t)-1))) __PYX_ERR(0, 426, __pyx_L1_error)
+  __pyx_v_actual_length = __pyx_t_5;
+
+  /* "_openjpeg.pyx":427
+ * 
+ *     actual_length = len(src)
+ *     expected_length = rows * columns * samples_per_pixel * bytes_allocated             # <<<<<<<<<<<<<<
+ *     if actual_length != expected_length:
+ *         raise ValueError(
+ */
+  __pyx_t_4 = __Pyx_PyInt_From_int(((__pyx_v_rows * __pyx_v_columns) * __pyx_v_samples_per_pixel)); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 427, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_4);
+  __pyx_t_3 = PyNumber_Multiply(__pyx_t_4, __pyx_v_bytes_allocated); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 427, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_3);
+  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+  __pyx_v_expected_length = __pyx_t_3;
+  __pyx_t_3 = 0;
+
+  /* "_openjpeg.pyx":428
+ *     actual_length = len(src)
+ *     expected_length = rows * columns * samples_per_pixel * bytes_allocated
+ *     if actual_length != expected_length:             # <<<<<<<<<<<<<<
+ *         raise ValueError(
+ *             f"The length of 'src' is {actual_length} bytes which doesn't "
+ */
+  __pyx_t_3 = PyInt_FromSsize_t(__pyx_v_actual_length); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 428, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_3);
+  __pyx_t_4 = PyObject_RichCompare(__pyx_t_3, __pyx_v_expected_length, Py_NE); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 428, __pyx_L1_error)
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  __pyx_t_1 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely((__pyx_t_1 < 0))) __PYX_ERR(0, 428, __pyx_L1_error)
+  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+  if (unlikely(__pyx_t_1)) {
+
+    /* "_openjpeg.pyx":430
+ *     if actual_length != expected_length:
+ *         raise ValueError(
+ *             f"The length of 'src' is {actual_length} bytes which doesn't "             # <<<<<<<<<<<<<<
+ *             f"match the expected length of {expected_length} bytes"
+ *         )
+ */
+    __pyx_t_4 = PyTuple_New(5); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 430, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_4);
+    __pyx_t_5 = 0;
+    __pyx_t_6 = 127;
+    __Pyx_INCREF(__pyx_kp_u_The_length_of_src_is);
+    __pyx_t_5 += 23;
+    __Pyx_GIVEREF(__pyx_kp_u_The_length_of_src_is);
+    PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_kp_u_The_length_of_src_is);
+    __pyx_t_3 = __Pyx_PyUnicode_From_Py_ssize_t(__pyx_v_actual_length, 0, ' ', 'd'); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 430, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_3);
+    __pyx_t_5 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_3);
+    __Pyx_GIVEREF(__pyx_t_3);
+    PyTuple_SET_ITEM(__pyx_t_4, 1, __pyx_t_3);
+    __pyx_t_3 = 0;
+    __Pyx_INCREF(__pyx_kp_u_bytes_which_doesn_t_match_the_e);
+    __pyx_t_5 += 50;
+    __Pyx_GIVEREF(__pyx_kp_u_bytes_which_doesn_t_match_the_e);
+    PyTuple_SET_ITEM(__pyx_t_4, 2, __pyx_kp_u_bytes_which_doesn_t_match_the_e);
+
+    /* "_openjpeg.pyx":431
+ *         raise ValueError(
+ *             f"The length of 'src' is {actual_length} bytes which doesn't "
+ *             f"match the expected length of {expected_length} bytes"             # <<<<<<<<<<<<<<
+ *         )
+ * 
+ */
+    __pyx_t_3 = __Pyx_PyObject_FormatSimple(__pyx_v_expected_length, __pyx_empty_unicode); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 431, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_3);
+    __pyx_t_6 = (__Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_3) > __pyx_t_6) ? __Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_3) : __pyx_t_6;
+    __pyx_t_5 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_3);
+    __Pyx_GIVEREF(__pyx_t_3);
+    PyTuple_SET_ITEM(__pyx_t_4, 3, __pyx_t_3);
+    __pyx_t_3 = 0;
+    __Pyx_INCREF(__pyx_kp_u_bytes);
+    __pyx_t_5 += 6;
+    __Pyx_GIVEREF(__pyx_kp_u_bytes);
+    PyTuple_SET_ITEM(__pyx_t_4, 4, __pyx_kp_u_bytes);
+
+    /* "_openjpeg.pyx":430
+ *     if actual_length != expected_length:
+ *         raise ValueError(
+ *             f"The length of 'src' is {actual_length} bytes which doesn't "             # <<<<<<<<<<<<<<
+ *             f"match the expected length of {expected_length} bytes"
+ *         )
+ */
+    __pyx_t_3 = __Pyx_PyUnicode_Join(__pyx_t_4, 5, __pyx_t_5, __pyx_t_6); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 430, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_3);
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+
+    /* "_openjpeg.pyx":429
+ *     expected_length = rows * columns * samples_per_pixel * bytes_allocated
+ *     if actual_length != expected_length:
+ *         raise ValueError(             # <<<<<<<<<<<<<<
+ *             f"The length of 'src' is {actual_length} bytes which doesn't "
+ *             f"match the expected length of {expected_length} bytes"
+ */
+    __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 429, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_4);
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    __Pyx_Raise(__pyx_t_4, 0, 0, 0);
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    __PYX_ERR(0, 429, __pyx_L1_error)
+
+    /* "_openjpeg.pyx":428
+ *     actual_length = len(src)
+ *     expected_length = rows * columns * samples_per_pixel * bytes_allocated
+ *     if actual_length != expected_length:             # <<<<<<<<<<<<<<
+ *         raise ValueError(
+ *             f"The length of 'src' is {actual_length} bytes which doesn't "
+ */
+  }
+
+  /* "_openjpeg.pyx":434
+ *         )
+ * 
+ *     if is_signed not in (0, 1):             # <<<<<<<<<<<<<<
+ *         raise ValueError(f"Invalid 'is_signed' value '{is_signed}'")
+ * 
+ */
+  switch (__pyx_v_is_signed) {
+    case 0:
+    case 1:
+    __pyx_t_1 = 0;
+    break;
+    default:
+    __pyx_t_1 = 1;
+    break;
+  }
+  __pyx_t_2 = __pyx_t_1;
+  if (unlikely(__pyx_t_2)) {
+
+    /* "_openjpeg.pyx":435
+ * 
+ *     if is_signed not in (0, 1):
+ *         raise ValueError(f"Invalid 'is_signed' value '{is_signed}'")             # <<<<<<<<<<<<<<
+ * 
+ *     if photometric_interpretation not in (0, 1, 2, 3, 4, 5):
+ */
+    __pyx_t_4 = PyTuple_New(3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 435, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_4);
+    __pyx_t_5 = 0;
+    __pyx_t_6 = 127;
+    __Pyx_INCREF(__pyx_kp_u_Invalid_is_signed_value);
+    __pyx_t_5 += 27;
+    __Pyx_GIVEREF(__pyx_kp_u_Invalid_is_signed_value);
+    PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_kp_u_Invalid_is_signed_value);
+    __pyx_t_3 = __Pyx_PyUnicode_From_int(__pyx_v_is_signed, 0, ' ', 'd'); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 435, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_3);
+    __pyx_t_5 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_3);
+    __Pyx_GIVEREF(__pyx_t_3);
+    PyTuple_SET_ITEM(__pyx_t_4, 1, __pyx_t_3);
+    __pyx_t_3 = 0;
+    __Pyx_INCREF(__pyx_kp_u__9);
+    __pyx_t_5 += 1;
+    __Pyx_GIVEREF(__pyx_kp_u__9);
+    PyTuple_SET_ITEM(__pyx_t_4, 2, __pyx_kp_u__9);
+    __pyx_t_3 = __Pyx_PyUnicode_Join(__pyx_t_4, 3, __pyx_t_5, __pyx_t_6); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 435, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_3);
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 435, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_4);
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    __Pyx_Raise(__pyx_t_4, 0, 0, 0);
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    __PYX_ERR(0, 435, __pyx_L1_error)
+
+    /* "_openjpeg.pyx":434
+ *         )
+ * 
+ *     if is_signed not in (0, 1):             # <<<<<<<<<<<<<<
+ *         raise ValueError(f"Invalid 'is_signed' value '{is_signed}'")
+ * 
+ */
+  }
+
+  /* "_openjpeg.pyx":437
+ *         raise ValueError(f"Invalid 'is_signed' value '{is_signed}'")
+ * 
+ *     if photometric_interpretation not in (0, 1, 2, 3, 4, 5):             # <<<<<<<<<<<<<<
+ *         raise ValueError(
+ *             "Invalid 'photometric_interpretation' value "
+ */
+  switch (__pyx_v_photometric_interpretation) {
+    case 0:
+    case 1:
+    case 2:
+    case 3:
+    case 4:
+    case 5:
+    __pyx_t_2 = 0;
+    break;
+    default:
+    __pyx_t_2 = 1;
+    break;
+  }
+  __pyx_t_1 = __pyx_t_2;
+  if (unlikely(__pyx_t_1)) {
+
+    /* "_openjpeg.pyx":439
+ *     if photometric_interpretation not in (0, 1, 2, 3, 4, 5):
+ *         raise ValueError(
+ *             "Invalid 'photometric_interpretation' value "             # <<<<<<<<<<<<<<
+ *             f"'{photometric_interpretation}', must be in the range [0, 5]"
+ *         )
+ */
+    __pyx_t_4 = PyTuple_New(3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 439, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_4);
+    __pyx_t_5 = 0;
+    __pyx_t_6 = 127;
+    __Pyx_INCREF(__pyx_kp_u_Invalid_photometric_interpretati);
+    __pyx_t_5 += 44;
+    __Pyx_GIVEREF(__pyx_kp_u_Invalid_photometric_interpretati);
+    PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_kp_u_Invalid_photometric_interpretati);
+
+    /* "_openjpeg.pyx":440
+ *         raise ValueError(
+ *             "Invalid 'photometric_interpretation' value "
+ *             f"'{photometric_interpretation}', must be in the range [0, 5]"             # <<<<<<<<<<<<<<
+ *         )
+ * 
+ */
+    __pyx_t_3 = __Pyx_PyUnicode_From_int(__pyx_v_photometric_interpretation, 0, ' ', 'd'); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 440, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_3);
+    __pyx_t_5 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_3);
+    __Pyx_GIVEREF(__pyx_t_3);
+    PyTuple_SET_ITEM(__pyx_t_4, 1, __pyx_t_3);
+    __pyx_t_3 = 0;
+    __Pyx_INCREF(__pyx_kp_u_must_be_in_the_range_0_5);
+    __pyx_t_5 += 30;
+    __Pyx_GIVEREF(__pyx_kp_u_must_be_in_the_range_0_5);
+    PyTuple_SET_ITEM(__pyx_t_4, 2, __pyx_kp_u_must_be_in_the_range_0_5);
+
+    /* "_openjpeg.pyx":439
+ *     if photometric_interpretation not in (0, 1, 2, 3, 4, 5):
+ *         raise ValueError(
+ *             "Invalid 'photometric_interpretation' value "             # <<<<<<<<<<<<<<
+ *             f"'{photometric_interpretation}', must be in the range [0, 5]"
+ *         )
+ */
+    __pyx_t_3 = __Pyx_PyUnicode_Join(__pyx_t_4, 3, __pyx_t_5, __pyx_t_6); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 439, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_3);
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+
+    /* "_openjpeg.pyx":438
+ * 
+ *     if photometric_interpretation not in (0, 1, 2, 3, 4, 5):
+ *         raise ValueError(             # <<<<<<<<<<<<<<
+ *             "Invalid 'photometric_interpretation' value "
+ *             f"'{photometric_interpretation}', must be in the range [0, 5]"
+ */
+    __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 438, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_4);
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    __Pyx_Raise(__pyx_t_4, 0, 0, 0);
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    __PYX_ERR(0, 438, __pyx_L1_error)
+
+    /* "_openjpeg.pyx":437
+ *         raise ValueError(f"Invalid 'is_signed' value '{is_signed}'")
+ * 
+ *     if photometric_interpretation not in (0, 1, 2, 3, 4, 5):             # <<<<<<<<<<<<<<
+ *         raise ValueError(
+ *             "Invalid 'photometric_interpretation' value "
+ */
+  }
+
+  /* "_openjpeg.pyx":443
+ *         )
+ * 
+ *     if use_mct not in (0, 1):             # <<<<<<<<<<<<<<
+ *         raise ValueError(f"Invalid 'use_mct' value '{use_mct}'")
+ * 
+ */
+  switch (__pyx_v_use_mct) {
+    case 0:
+    case 1:
+    __pyx_t_1 = 0;
+    break;
+    default:
+    __pyx_t_1 = 1;
+    break;
+  }
+  __pyx_t_2 = __pyx_t_1;
+  if (unlikely(__pyx_t_2)) {
+
+    /* "_openjpeg.pyx":444
+ * 
+ *     if use_mct not in (0, 1):
+ *         raise ValueError(f"Invalid 'use_mct' value '{use_mct}'")             # <<<<<<<<<<<<<<
+ * 
+ *     if codec_format not in (0, 1):
+ */
+    __pyx_t_4 = PyTuple_New(3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 444, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_4);
+    __pyx_t_5 = 0;
+    __pyx_t_6 = 127;
+    __Pyx_INCREF(__pyx_kp_u_Invalid_use_mct_value);
+    __pyx_t_5 += 25;
+    __Pyx_GIVEREF(__pyx_kp_u_Invalid_use_mct_value);
+    PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_kp_u_Invalid_use_mct_value);
+    __pyx_t_3 = __Pyx_PyUnicode_From_int(__pyx_v_use_mct, 0, ' ', 'd'); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 444, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_3);
+    __pyx_t_5 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_3);
+    __Pyx_GIVEREF(__pyx_t_3);
+    PyTuple_SET_ITEM(__pyx_t_4, 1, __pyx_t_3);
+    __pyx_t_3 = 0;
+    __Pyx_INCREF(__pyx_kp_u__9);
+    __pyx_t_5 += 1;
+    __Pyx_GIVEREF(__pyx_kp_u__9);
+    PyTuple_SET_ITEM(__pyx_t_4, 2, __pyx_kp_u__9);
+    __pyx_t_3 = __Pyx_PyUnicode_Join(__pyx_t_4, 3, __pyx_t_5, __pyx_t_6); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 444, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_3);
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 444, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_4);
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    __Pyx_Raise(__pyx_t_4, 0, 0, 0);
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    __PYX_ERR(0, 444, __pyx_L1_error)
+
+    /* "_openjpeg.pyx":443
+ *         )
+ * 
+ *     if use_mct not in (0, 1):             # <<<<<<<<<<<<<<
+ *         raise ValueError(f"Invalid 'use_mct' value '{use_mct}'")
+ * 
+ */
+  }
+
+  /* "_openjpeg.pyx":446
+ *         raise ValueError(f"Invalid 'use_mct' value '{use_mct}'")
+ * 
+ *     if codec_format not in (0, 1):             # <<<<<<<<<<<<<<
+ *         raise ValueError(
+ *             f"Invalid 'codec_format' value '{codec_format}', must be 0 or 1"
+ */
+  switch (__pyx_v_codec_format) {
+    case 0:
+    case 1:
+    __pyx_t_2 = 0;
+    break;
+    default:
+    __pyx_t_2 = 1;
+    break;
+  }
+  __pyx_t_1 = __pyx_t_2;
+  if (unlikely(__pyx_t_1)) {
+
+    /* "_openjpeg.pyx":448
+ *     if codec_format not in (0, 1):
+ *         raise ValueError(
+ *             f"Invalid 'codec_format' value '{codec_format}', must be 0 or 1"             # <<<<<<<<<<<<<<
+ *         )
+ * 
+ */
+    __pyx_t_4 = PyTuple_New(3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 448, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_4);
+    __pyx_t_5 = 0;
+    __pyx_t_6 = 127;
+    __Pyx_INCREF(__pyx_kp_u_Invalid_codec_format_value);
+    __pyx_t_5 += 30;
+    __Pyx_GIVEREF(__pyx_kp_u_Invalid_codec_format_value);
+    PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_kp_u_Invalid_codec_format_value);
+    __pyx_t_3 = __Pyx_PyUnicode_From_int(__pyx_v_codec_format, 0, ' ', 'd'); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 448, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_3);
+    __pyx_t_5 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_3);
+    __Pyx_GIVEREF(__pyx_t_3);
+    PyTuple_SET_ITEM(__pyx_t_4, 1, __pyx_t_3);
+    __pyx_t_3 = 0;
+    __Pyx_INCREF(__pyx_kp_u_must_be_0_or_1);
+    __pyx_t_5 += 17;
+    __Pyx_GIVEREF(__pyx_kp_u_must_be_0_or_1);
+    PyTuple_SET_ITEM(__pyx_t_4, 2, __pyx_kp_u_must_be_0_or_1);
+    __pyx_t_3 = __Pyx_PyUnicode_Join(__pyx_t_4, 3, __pyx_t_5, __pyx_t_6); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 448, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_3);
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+
+    /* "_openjpeg.pyx":447
+ * 
+ *     if codec_format not in (0, 1):
+ *         raise ValueError(             # <<<<<<<<<<<<<<
+ *             f"Invalid 'codec_format' value '{codec_format}', must be 0 or 1"
+ *         )
+ */
+    __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 447, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_4);
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    __Pyx_Raise(__pyx_t_4, 0, 0, 0);
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    __PYX_ERR(0, 447, __pyx_L1_error)
+
+    /* "_openjpeg.pyx":446
+ *         raise ValueError(f"Invalid 'use_mct' value '{use_mct}'")
+ * 
+ *     if codec_format not in (0, 1):             # <<<<<<<<<<<<<<
+ *         raise ValueError(
+ *             f"Invalid 'codec_format' value '{codec_format}', must be 0 or 1"
+ */
+  }
+
+  /* "_openjpeg.pyx":451
+ *         )
+ * 
+ *     compression_ratios = [float(x) for x in compression_ratios]             # <<<<<<<<<<<<<<
+ *     signal_noise_ratios = [float(x) for x in signal_noise_ratios]
+ *     if compression_ratios and signal_noise_ratios:
+ */
+  { /* enter inner scope */
+    __pyx_t_4 = PyList_New(0); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 451, __pyx_L17_error)
+    __Pyx_GOTREF(__pyx_t_4);
+    if (unlikely(__pyx_v_compression_ratios == Py_None)) {
+      PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable");
+      __PYX_ERR(0, 451, __pyx_L17_error)
+    }
+    __pyx_t_3 = __pyx_v_compression_ratios; __Pyx_INCREF(__pyx_t_3);
+    __pyx_t_5 = 0;
+    for (;;) {
+      {
+        Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_3);
+        #if !CYTHON_ASSUME_SAFE_MACROS
+        if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 451, __pyx_L17_error)
+        #endif
+        if (__pyx_t_5 >= __pyx_temp) break;
+      }
+      #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
+      __pyx_t_7 = PyList_GET_ITEM(__pyx_t_3, __pyx_t_5); __Pyx_INCREF(__pyx_t_7); __pyx_t_5++; if (unlikely((0 < 0))) __PYX_ERR(0, 451, __pyx_L17_error)
+      #else
+      __pyx_t_7 = __Pyx_PySequence_ITEM(__pyx_t_3, __pyx_t_5); __pyx_t_5++; if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 451, __pyx_L17_error)
+      __Pyx_GOTREF(__pyx_t_7);
+      #endif
+      __Pyx_XDECREF_SET(__pyx_8genexpr2__pyx_v_x, __pyx_t_7);
+      __pyx_t_7 = 0;
+      __pyx_t_7 = __Pyx_PyNumber_Float(__pyx_8genexpr2__pyx_v_x); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 451, __pyx_L17_error)
+      __Pyx_GOTREF(__pyx_t_7);
+      if (unlikely(__Pyx_ListComp_Append(__pyx_t_4, (PyObject*)__pyx_t_7))) __PYX_ERR(0, 451, __pyx_L17_error)
+      __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+    }
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    __Pyx_XDECREF(__pyx_8genexpr2__pyx_v_x); __pyx_8genexpr2__pyx_v_x = 0;
+    goto __pyx_L21_exit_scope;
+    __pyx_L17_error:;
+    __Pyx_XDECREF(__pyx_8genexpr2__pyx_v_x); __pyx_8genexpr2__pyx_v_x = 0;
+    goto __pyx_L1_error;
+    __pyx_L21_exit_scope:;
+  } /* exit inner scope */
+  __Pyx_DECREF_SET(__pyx_v_compression_ratios, ((PyObject*)__pyx_t_4));
+  __pyx_t_4 = 0;
+
+  /* "_openjpeg.pyx":452
+ * 
+ *     compression_ratios = [float(x) for x in compression_ratios]
+ *     signal_noise_ratios = [float(x) for x in signal_noise_ratios]             # <<<<<<<<<<<<<<
+ *     if compression_ratios and signal_noise_ratios:
+ *         raise ValueError(
+ */
+  { /* enter inner scope */
+    __pyx_t_4 = PyList_New(0); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 452, __pyx_L24_error)
+    __Pyx_GOTREF(__pyx_t_4);
+    if (unlikely(__pyx_v_signal_noise_ratios == Py_None)) {
+      PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable");
+      __PYX_ERR(0, 452, __pyx_L24_error)
+    }
+    __pyx_t_3 = __pyx_v_signal_noise_ratios; __Pyx_INCREF(__pyx_t_3);
+    __pyx_t_5 = 0;
+    for (;;) {
+      {
+        Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_3);
+        #if !CYTHON_ASSUME_SAFE_MACROS
+        if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 452, __pyx_L24_error)
+        #endif
+        if (__pyx_t_5 >= __pyx_temp) break;
+      }
+      #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
+      __pyx_t_7 = PyList_GET_ITEM(__pyx_t_3, __pyx_t_5); __Pyx_INCREF(__pyx_t_7); __pyx_t_5++; if (unlikely((0 < 0))) __PYX_ERR(0, 452, __pyx_L24_error)
+      #else
+      __pyx_t_7 = __Pyx_PySequence_ITEM(__pyx_t_3, __pyx_t_5); __pyx_t_5++; if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 452, __pyx_L24_error)
+      __Pyx_GOTREF(__pyx_t_7);
+      #endif
+      __Pyx_XDECREF_SET(__pyx_8genexpr3__pyx_v_x, __pyx_t_7);
+      __pyx_t_7 = 0;
+      __pyx_t_7 = __Pyx_PyNumber_Float(__pyx_8genexpr3__pyx_v_x); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 452, __pyx_L24_error)
+      __Pyx_GOTREF(__pyx_t_7);
+      if (unlikely(__Pyx_ListComp_Append(__pyx_t_4, (PyObject*)__pyx_t_7))) __PYX_ERR(0, 452, __pyx_L24_error)
+      __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+    }
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    __Pyx_XDECREF(__pyx_8genexpr3__pyx_v_x); __pyx_8genexpr3__pyx_v_x = 0;
+    goto __pyx_L28_exit_scope;
+    __pyx_L24_error:;
+    __Pyx_XDECREF(__pyx_8genexpr3__pyx_v_x); __pyx_8genexpr3__pyx_v_x = 0;
+    goto __pyx_L1_error;
+    __pyx_L28_exit_scope:;
+  } /* exit inner scope */
+  __Pyx_DECREF_SET(__pyx_v_signal_noise_ratios, ((PyObject*)__pyx_t_4));
+  __pyx_t_4 = 0;
+
+  /* "_openjpeg.pyx":453
+ *     compression_ratios = [float(x) for x in compression_ratios]
+ *     signal_noise_ratios = [float(x) for x in signal_noise_ratios]
+ *     if compression_ratios and signal_noise_ratios:             # <<<<<<<<<<<<<<
+ *         raise ValueError(
+ *             "Only one of 'compression_ratios' or 'signal_noise_ratios' is "
+ */
+  __pyx_t_2 = (PyList_GET_SIZE(__pyx_v_compression_ratios) != 0);
+  if (__pyx_t_2) {
+  } else {
+    __pyx_t_1 = __pyx_t_2;
+    goto __pyx_L30_bool_binop_done;
+  }
+  __pyx_t_2 = (PyList_GET_SIZE(__pyx_v_signal_noise_ratios) != 0);
+  __pyx_t_1 = __pyx_t_2;
+  __pyx_L30_bool_binop_done:;
+  if (unlikely(__pyx_t_1)) {
+
+    /* "_openjpeg.pyx":454
+ *     signal_noise_ratios = [float(x) for x in signal_noise_ratios]
+ *     if compression_ratios and signal_noise_ratios:
+ *         raise ValueError(             # <<<<<<<<<<<<<<
+ *             "Only one of 'compression_ratios' or 'signal_noise_ratios' is "
+ *             "allowed when performing lossy compression"
+ */
+    __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__7, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 454, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_4);
+    __Pyx_Raise(__pyx_t_4, 0, 0, 0);
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    __PYX_ERR(0, 454, __pyx_L1_error)
+
+    /* "_openjpeg.pyx":453
+ *     compression_ratios = [float(x) for x in compression_ratios]
+ *     signal_noise_ratios = [float(x) for x in signal_noise_ratios]
+ *     if compression_ratios and signal_noise_ratios:             # <<<<<<<<<<<<<<
+ *         raise ValueError(
+ *             "Only one of 'compression_ratios' or 'signal_noise_ratios' is "
+ */
+  }
+
+  /* "_openjpeg.pyx":458
+ *             "allowed when performing lossy compression"
+ *         )
+ *     if len(compression_ratios) > 10 or len(signal_noise_ratios) > 10:             # <<<<<<<<<<<<<<
+ *         raise ValueError("More than 10 compression layers is not supported")
+ * 
+ */
+  __pyx_t_5 = __Pyx_PyList_GET_SIZE(__pyx_v_compression_ratios); if (unlikely(__pyx_t_5 == ((Py_ssize_t)-1))) __PYX_ERR(0, 458, __pyx_L1_error)
+  __pyx_t_2 = (__pyx_t_5 > 10);
+  if (!__pyx_t_2) {
+  } else {
+    __pyx_t_1 = __pyx_t_2;
+    goto __pyx_L33_bool_binop_done;
+  }
+  __pyx_t_5 = __Pyx_PyList_GET_SIZE(__pyx_v_signal_noise_ratios); if (unlikely(__pyx_t_5 == ((Py_ssize_t)-1))) __PYX_ERR(0, 458, __pyx_L1_error)
+  __pyx_t_2 = (__pyx_t_5 > 10);
+  __pyx_t_1 = __pyx_t_2;
+  __pyx_L33_bool_binop_done:;
+  if (unlikely(__pyx_t_1)) {
+
+    /* "_openjpeg.pyx":459
+ *         )
+ *     if len(compression_ratios) > 10 or len(signal_noise_ratios) > 10:
+ *         raise ValueError("More than 10 compression layers is not supported")             # <<<<<<<<<<<<<<
+ * 
+ *     dst = BytesIO()
+ */
+    __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__8, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 459, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_4);
+    __Pyx_Raise(__pyx_t_4, 0, 0, 0);
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    __PYX_ERR(0, 459, __pyx_L1_error)
+
+    /* "_openjpeg.pyx":458
+ *             "allowed when performing lossy compression"
+ *         )
+ *     if len(compression_ratios) > 10 or len(signal_noise_ratios) > 10:             # <<<<<<<<<<<<<<
+ *         raise ValueError("More than 10 compression layers is not supported")
+ * 
+ */
+  }
+
+  /* "_openjpeg.pyx":461
+ *         raise ValueError("More than 10 compression layers is not supported")
+ * 
+ *     dst = BytesIO()             # <<<<<<<<<<<<<<
+ *     return_code = EncodeBuffer(
+ *         <PyObject *> src,
+ */
+  __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_BytesIO); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 461, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_3);
+  __pyx_t_7 = NULL;
+  __pyx_t_8 = 0;
+  #if CYTHON_UNPACK_METHODS
+  if (unlikely(PyMethod_Check(__pyx_t_3))) {
+    __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_3);
+    if (likely(__pyx_t_7)) {
+      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
+      __Pyx_INCREF(__pyx_t_7);
+      __Pyx_INCREF(function);
+      __Pyx_DECREF_SET(__pyx_t_3, function);
+      __pyx_t_8 = 1;
+    }
+  }
+  #endif
+  {
+    PyObject *__pyx_callargs[2] = {__pyx_t_7, NULL};
+    __pyx_t_4 = __Pyx_PyObject_FastCall(__pyx_t_3, __pyx_callargs+1-__pyx_t_8, 0+__pyx_t_8);
+    __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0;
+    if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 461, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_4);
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  }
+  __pyx_v_dst = __pyx_t_4;
+  __pyx_t_4 = 0;
+
+  /* "_openjpeg.pyx":462
+ * 
+ *     dst = BytesIO()
+ *     return_code = EncodeBuffer(             # <<<<<<<<<<<<<<
+ *         <PyObject *> src,
+ *         columns,
+ */
+  __pyx_v_return_code = EncodeBuffer(((PyObject *)__pyx_v_src), __pyx_v_columns, __pyx_v_rows, __pyx_v_samples_per_pixel, __pyx_v_bits_stored, __pyx_v_is_signed, __pyx_v_photometric_interpretation, ((PyObject *)__pyx_v_dst), __pyx_v_use_mct, ((PyObject *)__pyx_v_compression_ratios), ((PyObject *)__pyx_v_signal_noise_ratios), __pyx_v_codec_format);
+
+  /* "_openjpeg.pyx":476
+ *         codec_format,
+ *     )
+ *     return return_code, dst.getvalue()             # <<<<<<<<<<<<<<
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_4 = __Pyx_PyInt_From_int(__pyx_v_return_code); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 476, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_4);
+  __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_v_dst, __pyx_n_s_getvalue); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 476, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_7);
+  __pyx_t_9 = NULL;
+  __pyx_t_8 = 0;
+  #if CYTHON_UNPACK_METHODS
+  if (likely(PyMethod_Check(__pyx_t_7))) {
+    __pyx_t_9 = PyMethod_GET_SELF(__pyx_t_7);
+    if (likely(__pyx_t_9)) {
+      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7);
+      __Pyx_INCREF(__pyx_t_9);
+      __Pyx_INCREF(function);
+      __Pyx_DECREF_SET(__pyx_t_7, function);
+      __pyx_t_8 = 1;
+    }
+  }
+  #endif
+  {
+    PyObject *__pyx_callargs[2] = {__pyx_t_9, NULL};
+    __pyx_t_3 = __Pyx_PyObject_FastCall(__pyx_t_7, __pyx_callargs+1-__pyx_t_8, 0+__pyx_t_8);
+    __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0;
+    if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 476, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_3);
+    __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+  }
+  __pyx_t_7 = PyTuple_New(2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 476, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_7);
+  __Pyx_GIVEREF(__pyx_t_4);
+  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_4)) __PYX_ERR(0, 476, __pyx_L1_error);
+  __Pyx_GIVEREF(__pyx_t_3);
+  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_7, 1, __pyx_t_3)) __PYX_ERR(0, 476, __pyx_L1_error);
+  __pyx_t_4 = 0;
+  __pyx_t_3 = 0;
+  __pyx_r = ((PyObject*)__pyx_t_7);
+  __pyx_t_7 = 0;
+  goto __pyx_L0;
+
+  /* "_openjpeg.pyx":325
+ * 
+ * 
+ * def encode_buffer(             # <<<<<<<<<<<<<<
+ *     src,
+ *     int columns,
+ */
+
+  /* function exit code */
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_XDECREF(__pyx_t_4);
+  __Pyx_XDECREF(__pyx_t_7);
+  __Pyx_XDECREF(__pyx_t_9);
+  __Pyx_AddTraceback("_openjpeg.encode_buffer", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XDECREF(__pyx_v_bytes_allocated);
+  __Pyx_XDECREF(__pyx_v_expected_length);
+  __Pyx_XDECREF(__pyx_v_dst);
+  __Pyx_XDECREF(__pyx_8genexpr2__pyx_v_x);
+  __Pyx_XDECREF(__pyx_8genexpr3__pyx_v_x);
+  __Pyx_XDECREF(__pyx_v_compression_ratios);
+  __Pyx_XDECREF(__pyx_v_signal_noise_ratios);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+static PyMethodDef __pyx_methods[] = {
+  {0, 0, 0, 0}
+};
+#ifndef CYTHON_SMALL_CODE
+#if defined(__clang__)
+    #define CYTHON_SMALL_CODE
+#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
+    #define CYTHON_SMALL_CODE __attribute__((cold))
+#else
+    #define CYTHON_SMALL_CODE
+#endif
+#endif
+/* #### Code section: pystring_table ### */
+
+static int __Pyx_CreateStringTabAndInitStrings(void) {
+  __Pyx_StringTabEntry __pyx_string_tab[] = {
+    {&__pyx_kp_u_A_bits_stored_value_of, __pyx_k_A_bits_stored_value_of, sizeof(__pyx_k_A_bits_stored_value_of), 0, 1, 0, 0},
+    {&__pyx_n_s_BinaryIO, __pyx_k_BinaryIO, sizeof(__pyx_k_BinaryIO), 0, 0, 1, 1},
+    {&__pyx_n_s_BytesIO, __pyx_k_BytesIO, sizeof(__pyx_k_BytesIO), 0, 0, 1, 1},
+    {&__pyx_n_u_CYMK, __pyx_k_CYMK, sizeof(__pyx_k_CYMK), 0, 1, 0, 1},
+    {&__pyx_n_s_Dict, __pyx_k_Dict, sizeof(__pyx_k_Dict), 0, 0, 1, 1},
+    {&__pyx_kp_s_Dict_str_Union_str_int_bool, __pyx_k_Dict_str_Union_str_int_bool, sizeof(__pyx_k_Dict_str_Union_str_int_bool), 0, 0, 1, 0},
+    {&__pyx_n_s_ERRORS, __pyx_k_ERRORS, sizeof(__pyx_k_ERRORS), 0, 0, 1, 1},
+    {&__pyx_kp_u_Error_decoding_the_J2K_data, __pyx_k_Error_decoding_the_J2K_data, sizeof(__pyx_k_Error_decoding_the_J2K_data), 0, 1, 0, 0},
+    {&__pyx_n_s_ImportError, __pyx_k_ImportError, sizeof(__pyx_k_ImportError), 0, 0, 1, 1},
+    {&__pyx_kp_u_Invalid_bits_stored_value, __pyx_k_Invalid_bits_stored_value, sizeof(__pyx_k_Invalid_bits_stored_value), 0, 1, 0, 0},
+    {&__pyx_kp_u_Invalid_codec_format_value, __pyx_k_Invalid_codec_format_value, sizeof(__pyx_k_Invalid_codec_format_value), 0, 1, 0, 0},
+    {&__pyx_kp_u_Invalid_columns_value, __pyx_k_Invalid_columns_value, sizeof(__pyx_k_Invalid_columns_value), 0, 1, 0, 0},
+    {&__pyx_kp_u_Invalid_is_signed_value, __pyx_k_Invalid_is_signed_value, sizeof(__pyx_k_Invalid_is_signed_value), 0, 1, 0, 0},
+    {&__pyx_kp_u_Invalid_photometric_interpretati, __pyx_k_Invalid_photometric_interpretati, sizeof(__pyx_k_Invalid_photometric_interpretati), 0, 1, 0, 0},
+    {&__pyx_kp_u_Invalid_rows_value, __pyx_k_Invalid_rows_value, sizeof(__pyx_k_Invalid_rows_value), 0, 1, 0, 0},
+    {&__pyx_kp_u_Invalid_samples_per_pixel_value, __pyx_k_Invalid_samples_per_pixel_value, sizeof(__pyx_k_Invalid_samples_per_pixel_value), 0, 1, 0, 0},
+    {&__pyx_kp_u_Invalid_use_mct_value, __pyx_k_Invalid_use_mct_value, sizeof(__pyx_k_Invalid_use_mct_value), 0, 1, 0, 0},
+    {&__pyx_kp_u_Invalid_value_for_the_bits_store, __pyx_k_Invalid_value_for_the_bits_store, sizeof(__pyx_k_Invalid_value_for_the_bits_store), 0, 1, 0, 0},
+    {&__pyx_n_s_KeyError, __pyx_k_KeyError, sizeof(__pyx_k_KeyError), 0, 0, 1, 1},
+    {&__pyx_n_s_LOGGER, __pyx_k_LOGGER, sizeof(__pyx_k_LOGGER), 0, 0, 1, 1},
+    {&__pyx_n_s_List, __pyx_k_List, sizeof(__pyx_k_List), 0, 0, 1, 1},
+    {&__pyx_kp_u_More_than_10_compression_layers, __pyx_k_More_than_10_compression_layers, sizeof(__pyx_k_More_than_10_compression_layers), 0, 1, 0, 0},
+    {&__pyx_kp_u_Only_one_of_compression_ratios_o, __pyx_k_Only_one_of_compression_ratios_o, sizeof(__pyx_k_Only_one_of_compression_ratios_o), 0, 1, 0, 0},
+    {&__pyx_n_s_RuntimeError, __pyx_k_RuntimeError, sizeof(__pyx_k_RuntimeError), 0, 0, 1, 1},
+    {&__pyx_kp_u_The_input_array_contains_values, __pyx_k_The_input_array_contains_values, sizeof(__pyx_k_The_input_array_contains_values), 0, 1, 0, 0},
+    {&__pyx_kp_u_The_input_array_has_an_unsupport, __pyx_k_The_input_array_has_an_unsupport, sizeof(__pyx_k_The_input_array_has_an_unsupport), 0, 1, 0, 0},
+    {&__pyx_kp_u_The_length_of_src_is, __pyx_k_The_length_of_src_is, sizeof(__pyx_k_The_length_of_src_is), 0, 1, 0, 0},
+    {&__pyx_n_s_Tuple, __pyx_k_Tuple, sizeof(__pyx_k_Tuple), 0, 0, 1, 1},
+    {&__pyx_kp_s_Tuple_int_bytes, __pyx_k_Tuple_int_bytes, sizeof(__pyx_k_Tuple_int_bytes), 0, 0, 1, 0},
+    {&__pyx_n_s_TypeError, __pyx_k_TypeError, sizeof(__pyx_k_TypeError), 0, 0, 1, 1},
+    {&__pyx_n_s_Union, __pyx_k_Union, sizeof(__pyx_k_Union), 0, 0, 1, 1},
+    {&__pyx_kp_s_Union_np_ndarray_bytearray, __pyx_k_Union_np_ndarray_bytearray, sizeof(__pyx_k_Union_np_ndarray_bytearray), 0, 0, 1, 0},
+    {&__pyx_n_s_ValueError, __pyx_k_ValueError, sizeof(__pyx_k_ValueError), 0, 0, 1, 1},
+    {&__pyx_n_u_YUV, __pyx_k_YUV, sizeof(__pyx_k_YUV), 0, 1, 0, 1},
+    {&__pyx_kp_u__10, __pyx_k__10, sizeof(__pyx_k__10), 0, 1, 0, 0},
+    {&__pyx_n_s__11, __pyx_k__11, sizeof(__pyx_k__11), 0, 0, 1, 1},
+    {&__pyx_n_s__22, __pyx_k__22, sizeof(__pyx_k__22), 0, 0, 1, 1},
+    {&__pyx_kp_u__3, __pyx_k__3, sizeof(__pyx_k__3), 0, 1, 0, 0},
+    {&__pyx_kp_u__4, __pyx_k__4, sizeof(__pyx_k__4), 0, 1, 0, 0},
+    {&__pyx_kp_u__6, __pyx_k__6, sizeof(__pyx_k__6), 0, 1, 0, 0},
+    {&__pyx_kp_u__9, __pyx_k__9, sizeof(__pyx_k__9), 0, 1, 0, 0},
+    {&__pyx_n_s_actual_length, __pyx_k_actual_length, sizeof(__pyx_k_actual_length), 0, 0, 1, 1},
+    {&__pyx_n_s_allowed, __pyx_k_allowed, sizeof(__pyx_k_allowed), 0, 0, 1, 1},
+    {&__pyx_n_s_arr, __pyx_k_arr, sizeof(__pyx_k_arr), 0, 0, 1, 1},
+    {&__pyx_n_s_arr_max, __pyx_k_arr_max, sizeof(__pyx_k_arr_max), 0, 0, 1, 1},
+    {&__pyx_n_s_arr_min, __pyx_k_arr_min, sizeof(__pyx_k_arr_min), 0, 0, 1, 1},
+    {&__pyx_n_s_as_array, __pyx_k_as_array, sizeof(__pyx_k_as_array), 0, 0, 1, 1},
+    {&__pyx_n_s_asyncio_coroutines, __pyx_k_asyncio_coroutines, sizeof(__pyx_k_asyncio_coroutines), 0, 0, 1, 1},
+    {&__pyx_n_s_bits_stored, __pyx_k_bits_stored, sizeof(__pyx_k_bits_stored), 0, 0, 1, 1},
+    {&__pyx_n_s_bool, __pyx_k_bool, sizeof(__pyx_k_bool), 0, 0, 1, 1},
+    {&__pyx_n_s_bpp, __pyx_k_bpp, sizeof(__pyx_k_bpp), 0, 0, 1, 1},
+    {&__pyx_kp_u_bytes, __pyx_k_bytes, sizeof(__pyx_k_bytes), 0, 1, 0, 0},
+    {&__pyx_n_s_bytes_2, __pyx_k_bytes_2, sizeof(__pyx_k_bytes_2), 0, 0, 1, 1},
+    {&__pyx_n_s_bytes_allocated, __pyx_k_bytes_allocated, sizeof(__pyx_k_bytes_allocated), 0, 0, 1, 1},
+    {&__pyx_kp_u_bytes_which_doesn_t_match_the_e, __pyx_k_bytes_which_doesn_t_match_the_e, sizeof(__pyx_k_bytes_which_doesn_t_match_the_e), 0, 1, 0, 0},
+    {&__pyx_n_s_ceil, __pyx_k_ceil, sizeof(__pyx_k_ceil), 0, 0, 1, 1},
+    {&__pyx_n_s_cline_in_traceback, __pyx_k_cline_in_traceback, sizeof(__pyx_k_cline_in_traceback), 0, 0, 1, 1},
+    {&__pyx_n_s_codec, __pyx_k_codec, sizeof(__pyx_k_codec), 0, 0, 1, 1},
+    {&__pyx_n_s_codec_format, __pyx_k_codec_format, sizeof(__pyx_k_codec_format), 0, 0, 1, 1},
+    {&__pyx_n_s_colours, __pyx_k_colours, sizeof(__pyx_k_colours), 0, 0, 1, 1},
+    {&__pyx_n_s_colourspace, __pyx_k_colourspace, sizeof(__pyx_k_colourspace), 0, 0, 1, 1},
+    {&__pyx_n_u_colourspace, __pyx_k_colourspace, sizeof(__pyx_k_colourspace), 0, 1, 0, 1},
+    {&__pyx_n_s_columns, __pyx_k_columns, sizeof(__pyx_k_columns), 0, 0, 1, 1},
+    {&__pyx_n_u_columns, __pyx_k_columns, sizeof(__pyx_k_columns), 0, 1, 0, 1},
+    {&__pyx_n_s_compression_ratios, __pyx_k_compression_ratios, sizeof(__pyx_k_compression_ratios), 0, 0, 1, 1},
+    {&__pyx_n_s_decode, __pyx_k_decode, sizeof(__pyx_k_decode), 0, 0, 1, 1},
+    {&__pyx_n_s_dst, __pyx_k_dst, sizeof(__pyx_k_dst), 0, 0, 1, 1},
+    {&__pyx_n_s_dtype, __pyx_k_dtype, sizeof(__pyx_k_dtype), 0, 0, 1, 1},
+    {&__pyx_kp_u_e_YCC, __pyx_k_e_YCC, sizeof(__pyx_k_e_YCC), 0, 1, 0, 0},
+    {&__pyx_n_s_encode_array, __pyx_k_encode_array, sizeof(__pyx_k_encode_array), 0, 0, 1, 1},
+    {&__pyx_n_s_encode_buffer, __pyx_k_encode_buffer, sizeof(__pyx_k_encode_buffer), 0, 0, 1, 1},
+    {&__pyx_n_s_expected_length, __pyx_k_expected_length, sizeof(__pyx_k_expected_length), 0, 0, 1, 1},
+    {&__pyx_kp_u_failed_to_create_the_input_strea, __pyx_k_failed_to_create_the_input_strea, sizeof(__pyx_k_failed_to_create_the_input_strea), 0, 1, 0, 0},
+    {&__pyx_kp_u_failed_to_decode_image, __pyx_k_failed_to_decode_image, sizeof(__pyx_k_failed_to_decode_image), 0, 1, 0, 0},
+    {&__pyx_kp_u_failed_to_read_the_header, __pyx_k_failed_to_read_the_header, sizeof(__pyx_k_failed_to_read_the_header), 0, 1, 0, 0},
+    {&__pyx_kp_u_failed_to_set_the_component_indi, __pyx_k_failed_to_set_the_component_indi, sizeof(__pyx_k_failed_to_set_the_component_indi), 0, 1, 0, 0},
+    {&__pyx_kp_u_failed_to_set_the_decoded_area, __pyx_k_failed_to_set_the_decoded_area, sizeof(__pyx_k_failed_to_set_the_decoded_area), 0, 1, 0, 0},
+    {&__pyx_kp_u_failed_to_setup_the_decoder, __pyx_k_failed_to_setup_the_decoder, sizeof(__pyx_k_failed_to_setup_the_decoder), 0, 1, 0, 0},
+    {&__pyx_kp_u_failed_to_upscale_subsampled_com, __pyx_k_failed_to_upscale_subsampled_com, sizeof(__pyx_k_failed_to_upscale_subsampled_com), 0, 1, 0, 0},
+    {&__pyx_n_s_fp, __pyx_k_fp, sizeof(__pyx_k_fp), 0, 0, 1, 1},
+    {&__pyx_n_s_getLogger, __pyx_k_getLogger, sizeof(__pyx_k_getLogger), 0, 0, 1, 1},
+    {&__pyx_n_s_get_parameters, __pyx_k_get_parameters, sizeof(__pyx_k_get_parameters), 0, 0, 1, 1},
+    {&__pyx_n_s_get_version, __pyx_k_get_version, sizeof(__pyx_k_get_version), 0, 0, 1, 1},
+    {&__pyx_n_s_getvalue, __pyx_k_getvalue, sizeof(__pyx_k_getvalue), 0, 0, 1, 1},
+    {&__pyx_n_s_import, __pyx_k_import, sizeof(__pyx_k_import), 0, 0, 1, 1},
+    {&__pyx_n_s_initializing, __pyx_k_initializing, sizeof(__pyx_k_initializing), 0, 0, 1, 1},
+    {&__pyx_n_s_int, __pyx_k_int, sizeof(__pyx_k_int), 0, 0, 1, 1},
+    {&__pyx_n_s_int16, __pyx_k_int16, sizeof(__pyx_k_int16), 0, 0, 1, 1},
+    {&__pyx_n_s_int32, __pyx_k_int32, sizeof(__pyx_k_int32), 0, 0, 1, 1},
+    {&__pyx_n_s_int8, __pyx_k_int8, sizeof(__pyx_k_int8), 0, 0, 1, 1},
+    {&__pyx_n_s_io, __pyx_k_io, sizeof(__pyx_k_io), 0, 0, 1, 1},
+    {&__pyx_n_s_is_coroutine, __pyx_k_is_coroutine, sizeof(__pyx_k_is_coroutine), 0, 0, 1, 1},
+    {&__pyx_kp_u_is_incompatible_with_the_range, __pyx_k_is_incompatible_with_the_range, sizeof(__pyx_k_is_incompatible_with_the_range), 0, 1, 0, 0},
+    {&__pyx_n_s_is_signed, __pyx_k_is_signed, sizeof(__pyx_k_is_signed), 0, 0, 1, 1},
+    {&__pyx_n_u_is_signed, __pyx_k_is_signed, sizeof(__pyx_k_is_signed), 0, 1, 0, 1},
+    {&__pyx_n_s_itemsize, __pyx_k_itemsize, sizeof(__pyx_k_itemsize), 0, 0, 1, 1},
+    {&__pyx_n_s_logging, __pyx_k_logging, sizeof(__pyx_k_logging), 0, 0, 1, 1},
+    {&__pyx_n_s_main, __pyx_k_main, sizeof(__pyx_k_main), 0, 0, 1, 1},
+    {&__pyx_n_s_math, __pyx_k_math, sizeof(__pyx_k_math), 0, 0, 1, 1},
+    {&__pyx_n_s_max, __pyx_k_max, sizeof(__pyx_k_max), 0, 0, 1, 1},
+    {&__pyx_n_s_min, __pyx_k_min, sizeof(__pyx_k_min), 0, 0, 1, 1},
+    {&__pyx_n_u_monochrome, __pyx_k_monochrome, sizeof(__pyx_k_monochrome), 0, 1, 0, 1},
+    {&__pyx_n_s_msg, __pyx_k_msg, sizeof(__pyx_k_msg), 0, 0, 1, 1},
+    {&__pyx_kp_u_must_be_0_or_1, __pyx_k_must_be_0_or_1, sizeof(__pyx_k_must_be_0_or_1), 0, 1, 0, 0},
+    {&__pyx_kp_u_must_be_1_3_or_4, __pyx_k_must_be_1_3_or_4, sizeof(__pyx_k_must_be_1_3_or_4), 0, 1, 0, 0},
+    {&__pyx_kp_u_must_be_in_the_range_0_5, __pyx_k_must_be_in_the_range_0_5, sizeof(__pyx_k_must_be_in_the_range_0_5), 0, 1, 0, 0},
+    {&__pyx_kp_u_must_be_in_the_range_1_24, __pyx_k_must_be_in_the_range_1_24, sizeof(__pyx_k_must_be_in_the_range_1_24), 0, 1, 0, 0},
+    {&__pyx_kp_u_must_be_in_the_range_1_65535, __pyx_k_must_be_in_the_range_1_65535, sizeof(__pyx_k_must_be_in_the_range_1_65535), 0, 1, 0, 0},
+    {&__pyx_n_s_name, __pyx_k_name, sizeof(__pyx_k_name), 0, 0, 1, 1},
+    {&__pyx_n_s_np, __pyx_k_np, sizeof(__pyx_k_np), 0, 0, 1, 1},
+    {&__pyx_n_s_nr_bytes, __pyx_k_nr_bytes, sizeof(__pyx_k_nr_bytes), 0, 0, 1, 1},
+    {&__pyx_n_u_nr_tiles, __pyx_k_nr_tiles, sizeof(__pyx_k_nr_tiles), 0, 1, 0, 1},
+    {&__pyx_n_s_numpy, __pyx_k_numpy, sizeof(__pyx_k_numpy), 0, 0, 1, 1},
+    {&__pyx_kp_u_numpy_core_multiarray_failed_to, __pyx_k_numpy_core_multiarray_failed_to, sizeof(__pyx_k_numpy_core_multiarray_failed_to), 0, 1, 0, 0},
+    {&__pyx_kp_u_numpy_core_umath_failed_to_impor, __pyx_k_numpy_core_umath_failed_to_impor, sizeof(__pyx_k_numpy_core_umath_failed_to_impor), 0, 1, 0, 0},
+    {&__pyx_kp_u_only_bool_u1_u2_u4_i1_i2_and_i4, __pyx_k_only_bool_u1_u2_u4_i1_i2_and_i4, sizeof(__pyx_k_only_bool_u1_u2_u4_i1_i2_and_i4), 0, 1, 0, 0},
+    {&__pyx_n_s_openjpeg, __pyx_k_openjpeg, sizeof(__pyx_k_openjpeg), 0, 0, 1, 1},
+    {&__pyx_kp_s_openjpeg__openjpeg_pyx, __pyx_k_openjpeg__openjpeg_pyx, sizeof(__pyx_k_openjpeg__openjpeg_pyx), 0, 0, 1, 0},
+    {&__pyx_n_s_out, __pyx_k_out, sizeof(__pyx_k_out), 0, 0, 1, 1},
+    {&__pyx_n_s_p_in, __pyx_k_p_in, sizeof(__pyx_k_p_in), 0, 0, 1, 1},
+    {&__pyx_n_s_p_out, __pyx_k_p_out, sizeof(__pyx_k_p_out), 0, 0, 1, 1},
+    {&__pyx_n_s_p_param, __pyx_k_p_param, sizeof(__pyx_k_p_param), 0, 0, 1, 1},
+    {&__pyx_n_s_param, __pyx_k_param, sizeof(__pyx_k_param), 0, 0, 1, 1},
+    {&__pyx_n_s_parameters, __pyx_k_parameters, sizeof(__pyx_k_parameters), 0, 0, 1, 1},
+    {&__pyx_n_s_photometric_interpretation, __pyx_k_photometric_interpretation, sizeof(__pyx_k_photometric_interpretation), 0, 0, 1, 1},
+    {&__pyx_n_u_precision, __pyx_k_precision, sizeof(__pyx_k_precision), 0, 1, 0, 1},
+    {&__pyx_n_s_ptr, __pyx_k_ptr, sizeof(__pyx_k_ptr), 0, 0, 1, 1},
+    {&__pyx_n_s_result, __pyx_k_result, sizeof(__pyx_k_result), 0, 0, 1, 1},
+    {&__pyx_n_s_return, __pyx_k_return, sizeof(__pyx_k_return), 0, 0, 1, 1},
+    {&__pyx_n_s_return_code, __pyx_k_return_code, sizeof(__pyx_k_return_code), 0, 0, 1, 1},
+    {&__pyx_n_s_rows, __pyx_k_rows, sizeof(__pyx_k_rows), 0, 0, 1, 1},
+    {&__pyx_n_u_rows, __pyx_k_rows, sizeof(__pyx_k_rows), 0, 1, 0, 1},
+    {&__pyx_n_u_sRGB, __pyx_k_sRGB, sizeof(__pyx_k_sRGB), 0, 1, 0, 1},
+    {&__pyx_n_s_samples_per_pixel, __pyx_k_samples_per_pixel, sizeof(__pyx_k_samples_per_pixel), 0, 0, 1, 1},
+    {&__pyx_n_u_samples_per_pixel, __pyx_k_samples_per_pixel, sizeof(__pyx_k_samples_per_pixel), 0, 1, 0, 1},
+    {&__pyx_n_s_signal_noise_ratios, __pyx_k_signal_noise_ratios, sizeof(__pyx_k_signal_noise_ratios), 0, 0, 1, 1},
+    {&__pyx_n_s_spec, __pyx_k_spec, sizeof(__pyx_k_spec), 0, 0, 1, 1},
+    {&__pyx_n_s_src, __pyx_k_src, sizeof(__pyx_k_src), 0, 0, 1, 1},
+    {&__pyx_kp_u_src_must_be_bytes_or_bytearray, __pyx_k_src_must_be_bytes_or_bytearray, sizeof(__pyx_k_src_must_be_bytes_or_bytearray), 0, 1, 0, 0},
+    {&__pyx_kp_u_support_for_more_than_32_bits_pe, __pyx_k_support_for_more_than_32_bits_pe, sizeof(__pyx_k_support_for_more_than_32_bits_pe), 0, 1, 0, 0},
+    {&__pyx_n_s_test, __pyx_k_test, sizeof(__pyx_k_test), 0, 0, 1, 1},
+    {&__pyx_n_s_typing, __pyx_k_typing, sizeof(__pyx_k_typing), 0, 0, 1, 1},
+    {&__pyx_n_s_uint16, __pyx_k_uint16, sizeof(__pyx_k_uint16), 0, 0, 1, 1},
+    {&__pyx_n_s_uint32, __pyx_k_uint32, sizeof(__pyx_k_uint32), 0, 0, 1, 1},
+    {&__pyx_n_s_uint8, __pyx_k_uint8, sizeof(__pyx_k_uint8), 0, 0, 1, 1},
+    {&__pyx_n_u_unknown, __pyx_k_unknown, sizeof(__pyx_k_unknown), 0, 1, 0, 1},
+    {&__pyx_n_u_unspecified, __pyx_k_unspecified, sizeof(__pyx_k_unspecified), 0, 1, 0, 1},
+    {&__pyx_n_s_use_mct, __pyx_k_use_mct, sizeof(__pyx_k_use_mct), 0, 0, 1, 1},
+    {&__pyx_n_s_version, __pyx_k_version, sizeof(__pyx_k_version), 0, 0, 1, 1},
+    {&__pyx_n_s_x, __pyx_k_x, sizeof(__pyx_k_x), 0, 0, 1, 1},
+    {&__pyx_n_s_zeros, __pyx_k_zeros, sizeof(__pyx_k_zeros), 0, 0, 1, 1},
+    {0, 0, 0, 0, 0, 0, 0}
+  };
+  return __Pyx_InitStrings(__pyx_string_tab);
+}
+/* #### Code section: cached_builtins ### */
+static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) {
+  __pyx_builtin_KeyError = __Pyx_GetBuiltinName(__pyx_n_s_KeyError); if (!__pyx_builtin_KeyError) __PYX_ERR(0, 174, __pyx_L1_error)
+  __pyx_builtin_RuntimeError = __Pyx_GetBuiltinName(__pyx_n_s_RuntimeError); if (!__pyx_builtin_RuntimeError) __PYX_ERR(0, 177, __pyx_L1_error)
+  __pyx_builtin_ValueError = __Pyx_GetBuiltinName(__pyx_n_s_ValueError); if (!__pyx_builtin_ValueError) __PYX_ERR(0, 250, __pyx_L1_error)
+  __pyx_builtin_TypeError = __Pyx_GetBuiltinName(__pyx_n_s_TypeError); if (!__pyx_builtin_TypeError) __PYX_ERR(0, 394, __pyx_L1_error)
+  __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(1, 986, __pyx_L1_error)
+  return 0;
+  __pyx_L1_error:;
+  return -1;
+}
+/* #### Code section: cached_constants ### */
+
+static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) {
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__Pyx_InitCachedConstants", 0);
+
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":986
+ *         __pyx_import_array()
+ *     except Exception:
+ *         raise ImportError("numpy.core.multiarray failed to import")             # <<<<<<<<<<<<<<
+ * 
+ * cdef inline int import_umath() except -1:
+ */
+  __pyx_tuple_ = PyTuple_Pack(1, __pyx_kp_u_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple_)) __PYX_ERR(1, 986, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_tuple_);
+  __Pyx_GIVEREF(__pyx_tuple_);
+
+  /* "../../../../../tmp/pip-build-env-t296z_u1/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":992
+ *         _import_umath()
+ *     except Exception:
+ *         raise ImportError("numpy.core.umath failed to import")             # <<<<<<<<<<<<<<
  * 
- *     if codec_format not in (0, 2):
+ * cdef inline int import_ufunc() except -1:
+ */
+  __pyx_tuple__2 = PyTuple_Pack(1, __pyx_kp_u_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__2)) __PYX_ERR(1, 992, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_tuple__2);
+  __Pyx_GIVEREF(__pyx_tuple__2);
+
+  /* "_openjpeg.pyx":271
+ *         or (arr.dtype == np.int32 and (arr_max > 2**23 - 1 or arr_min < -2**23))
+ *     ):
  *         raise ValueError(             # <<<<<<<<<<<<<<
- *             "The value of the 'codec_format' parameter is invalid, must be 0 or 2"
- *         )
+ *             "The input array contains values outside the range of the maximum "
+ *             "supported bit-depth of 24"
  */
-  __pyx_tuple__7 = PyTuple_Pack(1, __pyx_kp_u_The_value_of_the_codec_format_pa); if (unlikely(!__pyx_tuple__7)) __PYX_ERR(0, 284, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_tuple__7);
-  __Pyx_GIVEREF(__pyx_tuple__7);
+  __pyx_tuple__5 = PyTuple_Pack(1, __pyx_kp_u_The_input_array_contains_values); if (unlikely(!__pyx_tuple__5)) __PYX_ERR(0, 271, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_tuple__5);
+  __Pyx_GIVEREF(__pyx_tuple__5);
 
-  /* "_openjpeg.pyx":291
+  /* "_openjpeg.pyx":303
  *     signal_noise_ratios = [float(x) for x in signal_noise_ratios]
  *     if compression_ratios and signal_noise_ratios:
  *         raise ValueError(             # <<<<<<<<<<<<<<
  *             "Only one of 'compression_ratios' or 'signal_noise_ratios' is "
  *             "allowed when performing lossy compression"
  */
-  __pyx_tuple__8 = PyTuple_Pack(1, __pyx_kp_u_Only_one_of_compression_ratios_o); if (unlikely(!__pyx_tuple__8)) __PYX_ERR(0, 291, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_tuple__8);
-  __Pyx_GIVEREF(__pyx_tuple__8);
+  __pyx_tuple__7 = PyTuple_Pack(1, __pyx_kp_u_Only_one_of_compression_ratios_o); if (unlikely(!__pyx_tuple__7)) __PYX_ERR(0, 303, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_tuple__7);
+  __Pyx_GIVEREF(__pyx_tuple__7);
 
-  /* "_openjpeg.pyx":296
+  /* "_openjpeg.pyx":308
  *         )
  *     if len(compression_ratios) > 10 or len(signal_noise_ratios) > 10:
  *         raise ValueError("More than 10 compression layers is not supported")             # <<<<<<<<<<<<<<
  * 
  *     # The destination for the encoded J2K codestream, needs to support BinaryIO
  */
-  __pyx_tuple__9 = PyTuple_Pack(1, __pyx_kp_u_More_than_10_compression_layers); if (unlikely(!__pyx_tuple__9)) __PYX_ERR(0, 296, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_tuple__9);
-  __Pyx_GIVEREF(__pyx_tuple__9);
+  __pyx_tuple__8 = PyTuple_Pack(1, __pyx_kp_u_More_than_10_compression_layers); if (unlikely(!__pyx_tuple__8)) __PYX_ERR(0, 308, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_tuple__8);
+  __Pyx_GIVEREF(__pyx_tuple__8);
 
-  /* "_openjpeg.pyx":52
+  /* "_openjpeg.pyx":65
  * 
  * 
  * def get_version() -> bytes:             # <<<<<<<<<<<<<<
  *     """Return the openjpeg version as bytes."""
  *     cdef char *version = OpenJpegVersion()
  */
-  __pyx_tuple__12 = PyTuple_Pack(1, __pyx_n_s_version); if (unlikely(!__pyx_tuple__12)) __PYX_ERR(0, 52, __pyx_L1_error)
+  __pyx_tuple__12 = PyTuple_Pack(1, __pyx_n_s_version); if (unlikely(!__pyx_tuple__12)) __PYX_ERR(0, 65, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_tuple__12);
   __Pyx_GIVEREF(__pyx_tuple__12);
-  __pyx_codeobj__13 = (PyObject*)__Pyx_PyCode_New(0, 0, 0, 1, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__12, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_openjpeg__openjpeg_pyx, __pyx_n_s_get_version, 52, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__13)) __PYX_ERR(0, 52, __pyx_L1_error)
+  __pyx_codeobj__13 = (PyObject*)__Pyx_PyCode_New(0, 0, 0, 1, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__12, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_openjpeg__openjpeg_pyx, __pyx_n_s_get_version, 65, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__13)) __PYX_ERR(0, 65, __pyx_L1_error)
 
-  /* "_openjpeg.pyx":59
+  /* "_openjpeg.pyx":72
  * 
  * 
  * def decode(             # <<<<<<<<<<<<<<
  *     fp: BinaryIO,
  *     codec: int = 0,
  */
-  __pyx_tuple__14 = PyTuple_Pack(10, __pyx_n_s_fp, __pyx_n_s_codec, __pyx_n_s_as_array, __pyx_n_s_param, __pyx_n_s_bpp, __pyx_n_s_nr_bytes, __pyx_n_s_p_in, __pyx_n_s_p_out, __pyx_n_s_out, __pyx_n_s_return_code); if (unlikely(!__pyx_tuple__14)) __PYX_ERR(0, 59, __pyx_L1_error)
+  __pyx_tuple__14 = PyTuple_Pack(10, __pyx_n_s_fp, __pyx_n_s_codec, __pyx_n_s_as_array, __pyx_n_s_param, __pyx_n_s_bpp, __pyx_n_s_nr_bytes, __pyx_n_s_p_in, __pyx_n_s_p_out, __pyx_n_s_out, __pyx_n_s_return_code); if (unlikely(!__pyx_tuple__14)) __PYX_ERR(0, 72, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_tuple__14);
   __Pyx_GIVEREF(__pyx_tuple__14);
-  __pyx_codeobj__15 = (PyObject*)__Pyx_PyCode_New(3, 0, 0, 10, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__14, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_openjpeg__openjpeg_pyx, __pyx_n_s_decode, 59, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__15)) __PYX_ERR(0, 59, __pyx_L1_error)
+  __pyx_codeobj__15 = (PyObject*)__Pyx_PyCode_New(3, 0, 0, 10, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__14, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_openjpeg__openjpeg_pyx, __pyx_n_s_decode, 72, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__15)) __PYX_ERR(0, 72, __pyx_L1_error)
 
-  /* "_openjpeg.pyx":113
+  /* "_openjpeg.pyx":126
  * 
  * 
  * def get_parameters(fp: BinaryIO, codec: int = 0) -> Dict[str, Union[str, int, bool]]:             # <<<<<<<<<<<<<<
  *     """Return a :class:`dict` containing the JPEG 2000 image parameters.
  * 
  */
-  __pyx_tuple__16 = PyTuple_Pack(10, __pyx_n_s_fp, __pyx_n_s_codec, __pyx_n_s_param, __pyx_n_s_p_param, __pyx_n_s_ptr, __pyx_n_s_result, __pyx_n_s_msg, __pyx_n_s_colours, __pyx_n_s_colourspace, __pyx_n_s_parameters); if (unlikely(!__pyx_tuple__16)) __PYX_ERR(0, 113, __pyx_L1_error)
+  __pyx_tuple__16 = PyTuple_Pack(10, __pyx_n_s_fp, __pyx_n_s_codec, __pyx_n_s_param, __pyx_n_s_p_param, __pyx_n_s_ptr, __pyx_n_s_result, __pyx_n_s_msg, __pyx_n_s_colours, __pyx_n_s_colourspace, __pyx_n_s_parameters); if (unlikely(!__pyx_tuple__16)) __PYX_ERR(0, 126, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_tuple__16);
   __Pyx_GIVEREF(__pyx_tuple__16);
-  __pyx_codeobj__17 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 10, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__16, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_openjpeg__openjpeg_pyx, __pyx_n_s_get_parameters, 113, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__17)) __PYX_ERR(0, 113, __pyx_L1_error)
+  __pyx_codeobj__17 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 10, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__16, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_openjpeg__openjpeg_pyx, __pyx_n_s_get_parameters, 126, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__17)) __PYX_ERR(0, 126, __pyx_L1_error)
 
-  /* "_openjpeg.pyx":195
+  /* "_openjpeg.pyx":208
  * 
  * 
- * def encode(             # <<<<<<<<<<<<<<
+ * def encode_array(             # <<<<<<<<<<<<<<
  *     cnp.ndarray arr,
  *     int bits_stored,
  */
-  __pyx_tuple__18 = PyTuple_Pack(14, __pyx_n_s_arr, __pyx_n_s_bits_stored, __pyx_n_s_photometric_interpretation, __pyx_n_s_use_mct, __pyx_n_s_compression_ratios, __pyx_n_s_signal_noise_ratios, __pyx_n_s_codec_format, __pyx_n_s_allowed, __pyx_n_s_arr_max, __pyx_n_s_arr_min, __pyx_n_s_dst, __pyx_n_s_return_code, __pyx_n_s_x, __pyx_n_s_x); if (unlikely(!__pyx_tuple__18)) __PYX_ERR(0, 195, __pyx_L1_error)
+  __pyx_tuple__18 = PyTuple_Pack(14, __pyx_n_s_arr, __pyx_n_s_bits_stored, __pyx_n_s_photometric_interpretation, __pyx_n_s_use_mct, __pyx_n_s_compression_ratios, __pyx_n_s_signal_noise_ratios, __pyx_n_s_codec_format, __pyx_n_s_allowed, __pyx_n_s_arr_max, __pyx_n_s_arr_min, __pyx_n_s_dst, __pyx_n_s_return_code, __pyx_n_s_x, __pyx_n_s_x); if (unlikely(!__pyx_tuple__18)) __PYX_ERR(0, 208, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_tuple__18);
   __Pyx_GIVEREF(__pyx_tuple__18);
-  __pyx_codeobj__19 = (PyObject*)__Pyx_PyCode_New(7, 0, 0, 14, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__18, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_openjpeg__openjpeg_pyx, __pyx_n_s_encode, 195, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__19)) __PYX_ERR(0, 195, __pyx_L1_error)
+  __pyx_codeobj__19 = (PyObject*)__Pyx_PyCode_New(7, 0, 0, 14, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__18, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_openjpeg__openjpeg_pyx, __pyx_n_s_encode_array, 208, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__19)) __PYX_ERR(0, 208, __pyx_L1_error)
+
+  /* "_openjpeg.pyx":325
+ * 
+ * 
+ * def encode_buffer(             # <<<<<<<<<<<<<<
+ *     src,
+ *     int columns,
+ */
+  __pyx_tuple__20 = PyTuple_Pack(18, __pyx_n_s_src, __pyx_n_s_columns, __pyx_n_s_rows, __pyx_n_s_samples_per_pixel, __pyx_n_s_bits_stored, __pyx_n_s_is_signed, __pyx_n_s_photometric_interpretation, __pyx_n_s_use_mct, __pyx_n_s_compression_ratios, __pyx_n_s_signal_noise_ratios, __pyx_n_s_codec_format, __pyx_n_s_bytes_allocated, __pyx_n_s_actual_length, __pyx_n_s_expected_length, __pyx_n_s_dst, __pyx_n_s_return_code, __pyx_n_s_x, __pyx_n_s_x); if (unlikely(!__pyx_tuple__20)) __PYX_ERR(0, 325, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_tuple__20);
+  __Pyx_GIVEREF(__pyx_tuple__20);
+  __pyx_codeobj__21 = (PyObject*)__Pyx_PyCode_New(11, 0, 0, 18, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__20, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_openjpeg__openjpeg_pyx, __pyx_n_s_encode_buffer, 325, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__21)) __PYX_ERR(0, 325, __pyx_L1_error)
   __Pyx_RefNannyFinishContext();
   return 0;
   __pyx_L1_error:;
@@ -8044,33 +9637,33 @@ static int __Pyx_modinit_type_import_code(void) {
   /*--- Type import code ---*/
   __pyx_t_1 = PyImport_ImportModule(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 9, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
-  __pyx_ptype_7cpython_4type_type = __Pyx_ImportType_3_0_8(__pyx_t_1, __Pyx_BUILTIN_MODULE_NAME, "type", 
+  __pyx_ptype_7cpython_4type_type = __Pyx_ImportType_3_0_9(__pyx_t_1, __Pyx_BUILTIN_MODULE_NAME, "type", 
   #if defined(PYPY_VERSION_NUM) && PYPY_VERSION_NUM < 0x050B0000
-  sizeof(PyTypeObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_8(PyTypeObject),
+  sizeof(PyTypeObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_9(PyTypeObject),
   #elif CYTHON_COMPILING_IN_LIMITED_API
-  sizeof(PyTypeObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_8(PyTypeObject),
+  sizeof(PyTypeObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_9(PyTypeObject),
   #else
-  sizeof(PyHeapTypeObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_8(PyHeapTypeObject),
+  sizeof(PyHeapTypeObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_9(PyHeapTypeObject),
   #endif
-  __Pyx_ImportType_CheckSize_Warn_3_0_8); if (!__pyx_ptype_7cpython_4type_type) __PYX_ERR(2, 9, __pyx_L1_error)
+  __Pyx_ImportType_CheckSize_Warn_3_0_9); if (!__pyx_ptype_7cpython_4type_type) __PYX_ERR(2, 9, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
   __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 202, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
-  __pyx_ptype_5numpy_dtype = __Pyx_ImportType_3_0_8(__pyx_t_1, "numpy", "dtype", sizeof(PyArray_Descr), __PYX_GET_STRUCT_ALIGNMENT_3_0_8(PyArray_Descr),__Pyx_ImportType_CheckSize_Ignore_3_0_8); if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(1, 202, __pyx_L1_error)
-  __pyx_ptype_5numpy_flatiter = __Pyx_ImportType_3_0_8(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_8(PyArrayIterObject),__Pyx_ImportType_CheckSize_Ignore_3_0_8); if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(1, 225, __pyx_L1_error)
-  __pyx_ptype_5numpy_broadcast = __Pyx_ImportType_3_0_8(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_8(PyArrayMultiIterObject),__Pyx_ImportType_CheckSize_Ignore_3_0_8); if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(1, 229, __pyx_L1_error)
-  __pyx_ptype_5numpy_ndarray = __Pyx_ImportType_3_0_8(__pyx_t_1, "numpy", "ndarray", sizeof(PyArrayObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_8(PyArrayObject),__Pyx_ImportType_CheckSize_Ignore_3_0_8); if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(1, 238, __pyx_L1_error)
-  __pyx_ptype_5numpy_generic = __Pyx_ImportType_3_0_8(__pyx_t_1, "numpy", "generic", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_8(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_8); if (!__pyx_ptype_5numpy_generic) __PYX_ERR(1, 812, __pyx_L1_error)
-  __pyx_ptype_5numpy_number = __Pyx_ImportType_3_0_8(__pyx_t_1, "numpy", "number", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_8(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_8); if (!__pyx_ptype_5numpy_number) __PYX_ERR(1, 814, __pyx_L1_error)
-  __pyx_ptype_5numpy_integer = __Pyx_ImportType_3_0_8(__pyx_t_1, "numpy", "integer", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_8(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_8); if (!__pyx_ptype_5numpy_integer) __PYX_ERR(1, 816, __pyx_L1_error)
-  __pyx_ptype_5numpy_signedinteger = __Pyx_ImportType_3_0_8(__pyx_t_1, "numpy", "signedinteger", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_8(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_8); if (!__pyx_ptype_5numpy_signedinteger) __PYX_ERR(1, 818, __pyx_L1_error)
-  __pyx_ptype_5numpy_unsignedinteger = __Pyx_ImportType_3_0_8(__pyx_t_1, "numpy", "unsignedinteger", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_8(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_8); if (!__pyx_ptype_5numpy_unsignedinteger) __PYX_ERR(1, 820, __pyx_L1_error)
-  __pyx_ptype_5numpy_inexact = __Pyx_ImportType_3_0_8(__pyx_t_1, "numpy", "inexact", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_8(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_8); if (!__pyx_ptype_5numpy_inexact) __PYX_ERR(1, 822, __pyx_L1_error)
-  __pyx_ptype_5numpy_floating = __Pyx_ImportType_3_0_8(__pyx_t_1, "numpy", "floating", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_8(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_8); if (!__pyx_ptype_5numpy_floating) __PYX_ERR(1, 824, __pyx_L1_error)
-  __pyx_ptype_5numpy_complexfloating = __Pyx_ImportType_3_0_8(__pyx_t_1, "numpy", "complexfloating", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_8(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_8); if (!__pyx_ptype_5numpy_complexfloating) __PYX_ERR(1, 826, __pyx_L1_error)
-  __pyx_ptype_5numpy_flexible = __Pyx_ImportType_3_0_8(__pyx_t_1, "numpy", "flexible", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_8(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_8); if (!__pyx_ptype_5numpy_flexible) __PYX_ERR(1, 828, __pyx_L1_error)
-  __pyx_ptype_5numpy_character = __Pyx_ImportType_3_0_8(__pyx_t_1, "numpy", "character", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_8(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_8); if (!__pyx_ptype_5numpy_character) __PYX_ERR(1, 830, __pyx_L1_error)
-  __pyx_ptype_5numpy_ufunc = __Pyx_ImportType_3_0_8(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_8(PyUFuncObject),__Pyx_ImportType_CheckSize_Ignore_3_0_8); if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(1, 868, __pyx_L1_error)
+  __pyx_ptype_5numpy_dtype = __Pyx_ImportType_3_0_9(__pyx_t_1, "numpy", "dtype", sizeof(PyArray_Descr), __PYX_GET_STRUCT_ALIGNMENT_3_0_9(PyArray_Descr),__Pyx_ImportType_CheckSize_Ignore_3_0_9); if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(1, 202, __pyx_L1_error)
+  __pyx_ptype_5numpy_flatiter = __Pyx_ImportType_3_0_9(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_9(PyArrayIterObject),__Pyx_ImportType_CheckSize_Ignore_3_0_9); if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(1, 225, __pyx_L1_error)
+  __pyx_ptype_5numpy_broadcast = __Pyx_ImportType_3_0_9(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_9(PyArrayMultiIterObject),__Pyx_ImportType_CheckSize_Ignore_3_0_9); if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(1, 229, __pyx_L1_error)
+  __pyx_ptype_5numpy_ndarray = __Pyx_ImportType_3_0_9(__pyx_t_1, "numpy", "ndarray", sizeof(PyArrayObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_9(PyArrayObject),__Pyx_ImportType_CheckSize_Ignore_3_0_9); if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(1, 238, __pyx_L1_error)
+  __pyx_ptype_5numpy_generic = __Pyx_ImportType_3_0_9(__pyx_t_1, "numpy", "generic", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_9(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_9); if (!__pyx_ptype_5numpy_generic) __PYX_ERR(1, 812, __pyx_L1_error)
+  __pyx_ptype_5numpy_number = __Pyx_ImportType_3_0_9(__pyx_t_1, "numpy", "number", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_9(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_9); if (!__pyx_ptype_5numpy_number) __PYX_ERR(1, 814, __pyx_L1_error)
+  __pyx_ptype_5numpy_integer = __Pyx_ImportType_3_0_9(__pyx_t_1, "numpy", "integer", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_9(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_9); if (!__pyx_ptype_5numpy_integer) __PYX_ERR(1, 816, __pyx_L1_error)
+  __pyx_ptype_5numpy_signedinteger = __Pyx_ImportType_3_0_9(__pyx_t_1, "numpy", "signedinteger", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_9(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_9); if (!__pyx_ptype_5numpy_signedinteger) __PYX_ERR(1, 818, __pyx_L1_error)
+  __pyx_ptype_5numpy_unsignedinteger = __Pyx_ImportType_3_0_9(__pyx_t_1, "numpy", "unsignedinteger", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_9(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_9); if (!__pyx_ptype_5numpy_unsignedinteger) __PYX_ERR(1, 820, __pyx_L1_error)
+  __pyx_ptype_5numpy_inexact = __Pyx_ImportType_3_0_9(__pyx_t_1, "numpy", "inexact", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_9(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_9); if (!__pyx_ptype_5numpy_inexact) __PYX_ERR(1, 822, __pyx_L1_error)
+  __pyx_ptype_5numpy_floating = __Pyx_ImportType_3_0_9(__pyx_t_1, "numpy", "floating", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_9(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_9); if (!__pyx_ptype_5numpy_floating) __PYX_ERR(1, 824, __pyx_L1_error)
+  __pyx_ptype_5numpy_complexfloating = __Pyx_ImportType_3_0_9(__pyx_t_1, "numpy", "complexfloating", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_9(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_9); if (!__pyx_ptype_5numpy_complexfloating) __PYX_ERR(1, 826, __pyx_L1_error)
+  __pyx_ptype_5numpy_flexible = __Pyx_ImportType_3_0_9(__pyx_t_1, "numpy", "flexible", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_9(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_9); if (!__pyx_ptype_5numpy_flexible) __PYX_ERR(1, 828, __pyx_L1_error)
+  __pyx_ptype_5numpy_character = __Pyx_ImportType_3_0_9(__pyx_t_1, "numpy", "character", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_9(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_9); if (!__pyx_ptype_5numpy_character) __PYX_ERR(1, 830, __pyx_L1_error)
+  __pyx_ptype_5numpy_ufunc = __Pyx_ImportType_3_0_9(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_9(PyUFuncObject),__Pyx_ImportType_CheckSize_Ignore_3_0_9); if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(1, 868, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
   __Pyx_RefNannyFinishContext();
   return 0;
@@ -8491,149 +10084,166 @@ if (!__Pyx_RefNanny) {
   if (PyDict_SetItem(__pyx_d, __pyx_n_s_np, __pyx_t_3) < 0) __PYX_ERR(0, 11, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
 
-  /* "_openjpeg.pyx":39
+  /* "_openjpeg.pyx":52
  * 
  * 
  * LOGGER = logging.getLogger(__name__)             # <<<<<<<<<<<<<<
  * ERRORS = {
  *     1: "failed to create the input stream",
  */
-  __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_logging); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 39, __pyx_L1_error)
+  __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_logging); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 52, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_3);
-  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_getLogger); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 39, __pyx_L1_error)
+  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_getLogger); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 52, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
   __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-  __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_name); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 39, __pyx_L1_error)
+  __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_name); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 52, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_3);
-  __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 39, __pyx_L1_error)
+  __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 52, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_4);
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
   __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-  if (PyDict_SetItem(__pyx_d, __pyx_n_s_LOGGER, __pyx_t_4) < 0) __PYX_ERR(0, 39, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_LOGGER, __pyx_t_4) < 0) __PYX_ERR(0, 52, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
 
-  /* "_openjpeg.pyx":41
+  /* "_openjpeg.pyx":54
  * LOGGER = logging.getLogger(__name__)
  * ERRORS = {
  *     1: "failed to create the input stream",             # <<<<<<<<<<<<<<
  *     2: "failed to setup the decoder",
  *     3: "failed to read the header",
  */
-  __pyx_t_4 = __Pyx_PyDict_NewPresized(8); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 41, __pyx_L1_error)
+  __pyx_t_4 = __Pyx_PyDict_NewPresized(8); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 54, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_4);
-  if (PyDict_SetItem(__pyx_t_4, __pyx_int_1, __pyx_kp_u_failed_to_create_the_input_strea) < 0) __PYX_ERR(0, 41, __pyx_L1_error)
-  if (PyDict_SetItem(__pyx_t_4, __pyx_int_2, __pyx_kp_u_failed_to_setup_the_decoder) < 0) __PYX_ERR(0, 41, __pyx_L1_error)
-  if (PyDict_SetItem(__pyx_t_4, __pyx_int_3, __pyx_kp_u_failed_to_read_the_header) < 0) __PYX_ERR(0, 41, __pyx_L1_error)
-  if (PyDict_SetItem(__pyx_t_4, __pyx_int_4, __pyx_kp_u_failed_to_set_the_component_indi) < 0) __PYX_ERR(0, 41, __pyx_L1_error)
-  if (PyDict_SetItem(__pyx_t_4, __pyx_int_5, __pyx_kp_u_failed_to_set_the_decoded_area) < 0) __PYX_ERR(0, 41, __pyx_L1_error)
-  if (PyDict_SetItem(__pyx_t_4, __pyx_int_6, __pyx_kp_u_failed_to_decode_image) < 0) __PYX_ERR(0, 41, __pyx_L1_error)
-  if (PyDict_SetItem(__pyx_t_4, __pyx_int_7, __pyx_kp_u_support_for_more_than_16_bits_pe) < 0) __PYX_ERR(0, 41, __pyx_L1_error)
-  if (PyDict_SetItem(__pyx_t_4, __pyx_int_8, __pyx_kp_u_failed_to_upscale_subsampled_com) < 0) __PYX_ERR(0, 41, __pyx_L1_error)
-  if (PyDict_SetItem(__pyx_d, __pyx_n_s_ERRORS, __pyx_t_4) < 0) __PYX_ERR(0, 40, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_4, __pyx_int_1, __pyx_kp_u_failed_to_create_the_input_strea) < 0) __PYX_ERR(0, 54, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_4, __pyx_int_2, __pyx_kp_u_failed_to_setup_the_decoder) < 0) __PYX_ERR(0, 54, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_4, __pyx_int_3, __pyx_kp_u_failed_to_read_the_header) < 0) __PYX_ERR(0, 54, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_4, __pyx_int_4, __pyx_kp_u_failed_to_set_the_component_indi) < 0) __PYX_ERR(0, 54, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_4, __pyx_int_5, __pyx_kp_u_failed_to_set_the_decoded_area) < 0) __PYX_ERR(0, 54, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_4, __pyx_int_6, __pyx_kp_u_failed_to_decode_image) < 0) __PYX_ERR(0, 54, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_4, __pyx_int_7, __pyx_kp_u_support_for_more_than_32_bits_pe) < 0) __PYX_ERR(0, 54, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_4, __pyx_int_8, __pyx_kp_u_failed_to_upscale_subsampled_com) < 0) __PYX_ERR(0, 54, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_ERRORS, __pyx_t_4) < 0) __PYX_ERR(0, 53, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
 
-  /* "_openjpeg.pyx":52
+  /* "_openjpeg.pyx":65
  * 
  * 
  * def get_version() -> bytes:             # <<<<<<<<<<<<<<
  *     """Return the openjpeg version as bytes."""
  *     cdef char *version = OpenJpegVersion()
  */
-  __pyx_t_4 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 52, __pyx_L1_error)
+  __pyx_t_4 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 65, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_4);
-  if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_return, __pyx_n_s_bytes) < 0) __PYX_ERR(0, 52, __pyx_L1_error)
-  __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_9_openjpeg_1get_version, 0, __pyx_n_s_get_version, NULL, __pyx_n_s_openjpeg, __pyx_d, ((PyObject *)__pyx_codeobj__13)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 52, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_return, __pyx_n_s_bytes_2) < 0) __PYX_ERR(0, 65, __pyx_L1_error)
+  __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_9_openjpeg_1get_version, 0, __pyx_n_s_get_version, NULL, __pyx_n_s_openjpeg, __pyx_d, ((PyObject *)__pyx_codeobj__13)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 65, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_3);
   __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_4);
   __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
-  if (PyDict_SetItem(__pyx_d, __pyx_n_s_get_version, __pyx_t_3) < 0) __PYX_ERR(0, 52, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_get_version, __pyx_t_3) < 0) __PYX_ERR(0, 65, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
 
-  /* "_openjpeg.pyx":59
+  /* "_openjpeg.pyx":72
  * 
  * 
  * def decode(             # <<<<<<<<<<<<<<
  *     fp: BinaryIO,
  *     codec: int = 0,
  */
-  __pyx_t_3 = __Pyx_PyDict_NewPresized(4); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 59, __pyx_L1_error)
+  __pyx_t_3 = __Pyx_PyDict_NewPresized(4); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 72, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_3);
-  if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_fp, __pyx_n_s_BinaryIO) < 0) __PYX_ERR(0, 59, __pyx_L1_error)
-  if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_codec, __pyx_n_s_int) < 0) __PYX_ERR(0, 59, __pyx_L1_error)
-  if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_as_array, __pyx_n_s_bool) < 0) __PYX_ERR(0, 59, __pyx_L1_error)
-  if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_kp_s_Union_np_ndarray_bytearray) < 0) __PYX_ERR(0, 59, __pyx_L1_error)
-  __pyx_t_4 = __Pyx_CyFunction_New(&__pyx_mdef_9_openjpeg_3decode, 0, __pyx_n_s_decode, NULL, __pyx_n_s_openjpeg, __pyx_d, ((PyObject *)__pyx_codeobj__15)); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 59, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_fp, __pyx_n_s_BinaryIO) < 0) __PYX_ERR(0, 72, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_codec, __pyx_n_s_int) < 0) __PYX_ERR(0, 72, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_as_array, __pyx_n_s_bool) < 0) __PYX_ERR(0, 72, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_kp_s_Union_np_ndarray_bytearray) < 0) __PYX_ERR(0, 72, __pyx_L1_error)
+  __pyx_t_4 = __Pyx_CyFunction_New(&__pyx_mdef_9_openjpeg_3decode, 0, __pyx_n_s_decode, NULL, __pyx_n_s_openjpeg, __pyx_d, ((PyObject *)__pyx_codeobj__15)); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 72, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_4);
-  if (!__Pyx_CyFunction_InitDefaults(__pyx_t_4, sizeof(__pyx_defaults), 1)) __PYX_ERR(0, 59, __pyx_L1_error)
+  if (!__Pyx_CyFunction_InitDefaults(__pyx_t_4, sizeof(__pyx_defaults), 1)) __PYX_ERR(0, 72, __pyx_L1_error)
 
-  /* "_openjpeg.pyx":61
+  /* "_openjpeg.pyx":74
  * def decode(
  *     fp: BinaryIO,
  *     codec: int = 0,             # <<<<<<<<<<<<<<
  *     as_array: bool = False
  * ) -> Union[np.ndarray, bytearray]:
  */
-  if (!(likely(__Pyx_Py3Int_CheckExact(__pyx_int_0)) || __Pyx_RaiseUnexpectedTypeError("int", __pyx_int_0))) __PYX_ERR(0, 61, __pyx_L1_error)
+  if (!(likely(__Pyx_Py3Int_CheckExact(__pyx_int_0)) || __Pyx_RaiseUnexpectedTypeError("int", __pyx_int_0))) __PYX_ERR(0, 74, __pyx_L1_error)
   __Pyx_INCREF(__pyx_int_0);
   __Pyx_CyFunction_Defaults(__pyx_defaults, __pyx_t_4)->__pyx_arg_codec = ((PyObject*)__pyx_int_0);
   __Pyx_GIVEREF(__pyx_int_0);
-  __Pyx_CyFunction_SetDefaultsGetter(__pyx_t_4, __pyx_pf_9_openjpeg_8__defaults__);
+  __Pyx_CyFunction_SetDefaultsGetter(__pyx_t_4, __pyx_pf_9_openjpeg_10__defaults__);
   __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_4, __pyx_t_3);
   __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-  if (PyDict_SetItem(__pyx_d, __pyx_n_s_decode, __pyx_t_4) < 0) __PYX_ERR(0, 59, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_decode, __pyx_t_4) < 0) __PYX_ERR(0, 72, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
 
-  /* "_openjpeg.pyx":113
+  /* "_openjpeg.pyx":126
  * 
  * 
  * def get_parameters(fp: BinaryIO, codec: int = 0) -> Dict[str, Union[str, int, bool]]:             # <<<<<<<<<<<<<<
  *     """Return a :class:`dict` containing the JPEG 2000 image parameters.
  * 
  */
-  __pyx_t_4 = __Pyx_PyDict_NewPresized(3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 113, __pyx_L1_error)
+  __pyx_t_4 = __Pyx_PyDict_NewPresized(3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 126, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_4);
-  if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_fp, __pyx_n_s_BinaryIO) < 0) __PYX_ERR(0, 113, __pyx_L1_error)
-  if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_codec, __pyx_n_s_int) < 0) __PYX_ERR(0, 113, __pyx_L1_error)
-  if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_return, __pyx_kp_s_Dict_str_Union_str_int_bool) < 0) __PYX_ERR(0, 113, __pyx_L1_error)
-  __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_9_openjpeg_5get_parameters, 0, __pyx_n_s_get_parameters, NULL, __pyx_n_s_openjpeg, __pyx_d, ((PyObject *)__pyx_codeobj__17)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 113, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_fp, __pyx_n_s_BinaryIO) < 0) __PYX_ERR(0, 126, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_codec, __pyx_n_s_int) < 0) __PYX_ERR(0, 126, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_return, __pyx_kp_s_Dict_str_Union_str_int_bool) < 0) __PYX_ERR(0, 126, __pyx_L1_error)
+  __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_9_openjpeg_5get_parameters, 0, __pyx_n_s_get_parameters, NULL, __pyx_n_s_openjpeg, __pyx_d, ((PyObject *)__pyx_codeobj__17)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 126, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_3);
-  if (!__Pyx_CyFunction_InitDefaults(__pyx_t_3, sizeof(__pyx_defaults1), 1)) __PYX_ERR(0, 113, __pyx_L1_error)
-  if (!(likely(__Pyx_Py3Int_CheckExact(__pyx_int_0)) || __Pyx_RaiseUnexpectedTypeError("int", __pyx_int_0))) __PYX_ERR(0, 113, __pyx_L1_error)
+  if (!__Pyx_CyFunction_InitDefaults(__pyx_t_3, sizeof(__pyx_defaults1), 1)) __PYX_ERR(0, 126, __pyx_L1_error)
+  if (!(likely(__Pyx_Py3Int_CheckExact(__pyx_int_0)) || __Pyx_RaiseUnexpectedTypeError("int", __pyx_int_0))) __PYX_ERR(0, 126, __pyx_L1_error)
   __Pyx_INCREF(__pyx_int_0);
   __Pyx_CyFunction_Defaults(__pyx_defaults1, __pyx_t_3)->__pyx_arg_codec = ((PyObject*)__pyx_int_0);
   __Pyx_GIVEREF(__pyx_int_0);
-  __Pyx_CyFunction_SetDefaultsGetter(__pyx_t_3, __pyx_pf_9_openjpeg_10__defaults__);
+  __Pyx_CyFunction_SetDefaultsGetter(__pyx_t_3, __pyx_pf_9_openjpeg_12__defaults__);
   __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_4);
   __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
-  if (PyDict_SetItem(__pyx_d, __pyx_n_s_get_parameters, __pyx_t_3) < 0) __PYX_ERR(0, 113, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_get_parameters, __pyx_t_3) < 0) __PYX_ERR(0, 126, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
 
-  /* "_openjpeg.pyx":195
+  /* "_openjpeg.pyx":208
  * 
  * 
- * def encode(             # <<<<<<<<<<<<<<
+ * def encode_array(             # <<<<<<<<<<<<<<
  *     cnp.ndarray arr,
  *     int bits_stored,
  */
-  __pyx_t_3 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 195, __pyx_L1_error)
+  __pyx_t_3 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 208, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_3);
-  if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_kp_s_Tuple_int_bytes) < 0) __PYX_ERR(0, 195, __pyx_L1_error)
-  __pyx_t_4 = __Pyx_CyFunction_New(&__pyx_mdef_9_openjpeg_7encode, 0, __pyx_n_s_encode, NULL, __pyx_n_s_openjpeg, __pyx_d, ((PyObject *)__pyx_codeobj__19)); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 195, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_kp_s_Tuple_int_bytes) < 0) __PYX_ERR(0, 208, __pyx_L1_error)
+  __pyx_t_4 = __Pyx_CyFunction_New(&__pyx_mdef_9_openjpeg_7encode_array, 0, __pyx_n_s_encode_array, NULL, __pyx_n_s_openjpeg, __pyx_d, ((PyObject *)__pyx_codeobj__19)); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 208, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_4);
   __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_4, __pyx_t_3);
   __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-  if (PyDict_SetItem(__pyx_d, __pyx_n_s_encode, __pyx_t_4) < 0) __PYX_ERR(0, 195, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_encode_array, __pyx_t_4) < 0) __PYX_ERR(0, 208, __pyx_L1_error)
+  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+
+  /* "_openjpeg.pyx":325
+ * 
+ * 
+ * def encode_buffer(             # <<<<<<<<<<<<<<
+ *     src,
+ *     int columns,
+ */
+  __pyx_t_4 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 325, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_4);
+  if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_return, __pyx_kp_s_Tuple_int_bytes) < 0) __PYX_ERR(0, 325, __pyx_L1_error)
+  __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_9_openjpeg_9encode_buffer, 0, __pyx_n_s_encode_buffer, NULL, __pyx_n_s_openjpeg, __pyx_d, ((PyObject *)__pyx_codeobj__21)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 325, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_3);
+  __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_4);
   __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_encode_buffer, __pyx_t_3) < 0) __PYX_ERR(0, 325, __pyx_L1_error)
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
 
   /* "_openjpeg.pyx":1
  * # cython: language_level=3             # <<<<<<<<<<<<<<
  * # distutils: language=c
  * from math import ceil
  */
-  __pyx_t_4 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_t_4);
-  if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_4) < 0) __PYX_ERR(0, 1, __pyx_L1_error)
-  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+  __pyx_t_3 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_3);
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_3) < 0) __PYX_ERR(0, 1, __pyx_L1_error)
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
 
   /*--- Wrapped vars code ---*/
 
@@ -10827,11 +12437,84 @@ static CYTHON_INLINE PyObject* __Pyx__PyNumber_Float(PyObject* obj) {
     return PyFloat_FromDouble(val);
 }
 
+/* CIntToPyUnicode */
+static CYTHON_INLINE PyObject* __Pyx_PyUnicode_From_Py_ssize_t(Py_ssize_t value, Py_ssize_t width, char padding_char, char format_char) {
+    char digits[sizeof(Py_ssize_t)*3+2];
+    char *dpos, *end = digits + sizeof(Py_ssize_t)*3+2;
+    const char *hex_digits = DIGITS_HEX;
+    Py_ssize_t length, ulength;
+    int prepend_sign, last_one_off;
+    Py_ssize_t remaining;
+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wconversion"
+#endif
+    const Py_ssize_t neg_one = (Py_ssize_t) -1, const_zero = (Py_ssize_t) 0;
+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC
+#pragma GCC diagnostic pop
+#endif
+    const int is_unsigned = neg_one > const_zero;
+    if (format_char == 'X') {
+        hex_digits += 16;
+        format_char = 'x';
+    }
+    remaining = value;
+    last_one_off = 0;
+    dpos = end;
+    do {
+        int digit_pos;
+        switch (format_char) {
+        case 'o':
+            digit_pos = abs((int)(remaining % (8*8)));
+            remaining = (Py_ssize_t) (remaining / (8*8));
+            dpos -= 2;
+            memcpy(dpos, DIGIT_PAIRS_8 + digit_pos * 2, 2);
+            last_one_off = (digit_pos < 8);
+            break;
+        case 'd':
+            digit_pos = abs((int)(remaining % (10*10)));
+            remaining = (Py_ssize_t) (remaining / (10*10));
+            dpos -= 2;
+            memcpy(dpos, DIGIT_PAIRS_10 + digit_pos * 2, 2);
+            last_one_off = (digit_pos < 10);
+            break;
+        case 'x':
+            *(--dpos) = hex_digits[abs((int)(remaining % 16))];
+            remaining = (Py_ssize_t) (remaining / 16);
+            break;
+        default:
+            assert(0);
+            break;
+        }
+    } while (unlikely(remaining != 0));
+    assert(!last_one_off || *dpos == '0');
+    dpos += last_one_off;
+    length = end - dpos;
+    ulength = length;
+    prepend_sign = 0;
+    if (!is_unsigned && value <= neg_one) {
+        if (padding_char == ' ' || width <= length + 1) {
+            *(--dpos) = '-';
+            ++length;
+        } else {
+            prepend_sign = 1;
+        }
+        ++ulength;
+    }
+    if (width > ulength) {
+        ulength = width;
+    }
+    if (ulength == 1) {
+        return PyUnicode_FromOrdinal(*dpos);
+    }
+    return __Pyx_PyUnicode_BuildFromAscii(ulength, dpos, (int) length, prepend_sign, padding_char);
+}
+
 /* TypeImport */
-#ifndef __PYX_HAVE_RT_ImportType_3_0_8
-#define __PYX_HAVE_RT_ImportType_3_0_8
-static PyTypeObject *__Pyx_ImportType_3_0_8(PyObject *module, const char *module_name, const char *class_name,
-    size_t size, size_t alignment, enum __Pyx_ImportType_CheckSize_3_0_8 check_size)
+#ifndef __PYX_HAVE_RT_ImportType_3_0_9
+#define __PYX_HAVE_RT_ImportType_3_0_9
+static PyTypeObject *__Pyx_ImportType_3_0_9(PyObject *module, const char *module_name, const char *class_name,
+    size_t size, size_t alignment, enum __Pyx_ImportType_CheckSize_3_0_9 check_size)
 {
     PyObject *result = 0;
     char warning[200];
@@ -10885,7 +12568,7 @@ static PyTypeObject *__Pyx_ImportType_3_0_8(PyObject *module, const char *module
             module_name, class_name, size, basicsize+itemsize);
         goto bad;
     }
-    if (check_size == __Pyx_ImportType_CheckSize_Error_3_0_8 &&
+    if (check_size == __Pyx_ImportType_CheckSize_Error_3_0_9 &&
             ((size_t)basicsize > size || (size_t)(basicsize + itemsize) < size)) {
         PyErr_Format(PyExc_ValueError,
             "%.200s.%.200s size changed, may indicate binary incompatibility. "
@@ -10893,7 +12576,7 @@ static PyTypeObject *__Pyx_ImportType_3_0_8(PyObject *module, const char *module
             module_name, class_name, size, basicsize, basicsize+itemsize);
         goto bad;
     }
-    else if (check_size == __Pyx_ImportType_CheckSize_Warn_3_0_8 && (size_t)basicsize > size) {
+    else if (check_size == __Pyx_ImportType_CheckSize_Warn_3_0_9 && (size_t)basicsize > size) {
         PyOS_snprintf(warning, sizeof(warning),
             "%s.%s size changed, may indicate binary incompatibility. "
             "Expected %zd from C header, got %zd from PyObject",
@@ -12195,7 +13878,7 @@ static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS(PyObject *func,
     default:
         return NULL;
     }
-    return ((_PyCFunctionFastWithKeywords)(void(*)(void))def->ml_meth)(self, args, nargs, kwnames);
+    return ((__Pyx_PyCFunctionFastWithKeywords)(void(*)(void))def->ml_meth)(self, args, nargs, kwnames);
 }
 static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
 {
@@ -13519,7 +15202,7 @@ __Pyx_PyType_GetName(PyTypeObject* tp)
     if (unlikely(name == NULL) || unlikely(!PyUnicode_Check(name))) {
         PyErr_Clear();
         Py_XDECREF(name);
-        name = __Pyx_NewRef(__pyx_n_s__20);
+        name = __Pyx_NewRef(__pyx_n_s__22);
     }
     return name;
 }
diff --git a/openjpeg/_openjpeg.pyx b/openjpeg/_openjpeg.pyx
index 64974b4..9c7159f 100644
--- a/openjpeg/_openjpeg.pyx
+++ b/openjpeg/_openjpeg.pyx
@@ -15,7 +15,7 @@ cdef extern struct JPEG2000Parameters:
     uint32_t columns
     uint32_t rows
     int colourspace
-    uint32_t nr_components
+    uint32_t samples_per_pixel
     uint32_t precision
     unsigned int is_signed
     uint32_t nr_tiles
@@ -23,13 +23,26 @@ cdef extern struct JPEG2000Parameters:
 cdef extern char* OpenJpegVersion()
 cdef extern int Decode(void* fp, unsigned char* out, int codec)
 cdef extern int GetParameters(void* fp, int codec, JPEG2000Parameters *param)
-cdef extern int Encode(
+cdef extern int EncodeArray(
     cnp.PyArrayObject* arr,
     PyObject* dst,
     int bits_stored,
     int photometric_interpretation,
     bint use_mct,
-    # bint lossless,
+    PyObject* compression_ratios,
+    PyObject* signal_noise_ratios,
+    int codec_format,
+)
+cdef extern int EncodeBuffer(
+    PyObject* src,
+    int columns,
+    int rows,
+    int samples_per_pixel,
+    int bits_stored,
+    int is_signed,
+    int photometric_interpretation,
+    PyObject* dst,
+    bint use_mct,
     PyObject* compression_ratios,
     PyObject* signal_noise_ratios,
     int codec_format,
@@ -44,7 +57,7 @@ ERRORS = {
     4: "failed to set the component indices",
     5: "failed to set the decoded area",
     6: "failed to decode image",
-    7: "support for more than 16-bits per component is not implemented",
+    7: "support for more than 32-bits per component is not implemented",
     8: "failed to upscale subsampled components",
 }
 
@@ -94,7 +107,7 @@ def decode(
     bpp = ceil(param['precision'] / 8)
     if bpp == 3:
         bpp = 4
-    nr_bytes = param['rows'] * param['columns'] * param['nr_components'] * bpp
+    nr_bytes = param['rows'] * param['columns'] * param['samples_per_pixel'] * bpp
 
     cdef PyObject* p_in = <PyObject*>fp
     cdef unsigned char *p_out
@@ -129,7 +142,7 @@ def get_parameters(fp: BinaryIO, codec: int = 0) -> Dict[str, Union[str, int, bo
     dict
         A :class:`dict` containing the J2K image parameters:
         ``{'columns': int, 'rows': int, 'colourspace': str,
-        'nr_components: int, 'precision': int, `is_signed`: bool,
+        'samples_per_pixel: int, 'precision': int, `is_signed`: bool,
         'nr_tiles: int'}``. Possible colour spaces are "unknown",
         "unspecified", "sRGB", "monochrome", "YUV", "e-YCC" and "CYMK".
 
@@ -142,7 +155,7 @@ def get_parameters(fp: BinaryIO, codec: int = 0) -> Dict[str, Union[str, int, bo
     param.columns = 0
     param.rows = 0
     param.colourspace = 0
-    param.nr_components = 0
+    param.samples_per_pixel = 0
     param.precision = 0
     param.is_signed = 0
     param.nr_tiles = 0
@@ -183,7 +196,7 @@ def get_parameters(fp: BinaryIO, codec: int = 0) -> Dict[str, Union[str, int, bo
         'rows' : param.rows,
         'columns' : param.columns,
         'colourspace' : colourspace,
-        'nr_components' : param.nr_components,
+        'samples_per_pixel' : param.samples_per_pixel,
         'precision' : param.precision,
         'is_signed' : bool(param.is_signed),
         'nr_tiles' : param.nr_tiles,
@@ -192,7 +205,7 @@ def get_parameters(fp: BinaryIO, codec: int = 0) -> Dict[str, Union[str, int, bo
     return parameters
 
 
-def encode(
+def encode_array(
     cnp.ndarray arr,
     int bits_stored,
     int photometric_interpretation,
@@ -209,30 +222,29 @@ def encode(
         The array containing the image data to be encoded.
     bits_stored : int, optional
         The number of bits used per pixel.
-    photometric_interpretation : int, optional
+    photometric_interpretation : int
         The colour space of the unencoded image data that will be set in the
-        JPEG 2000 metadata.
-    use_mct : bool, optional
+        JP2 metadata (if `codec_format` is ``1``).
+    use_mct : bool
         If ``True`` then apply multi-component transformation (MCT) to RGB
         images.
-    lossless : bool, optional
-        If ``True`` then use lossless encoding, otherwise use lossy encoding.
-    compression_ratios : list[float], optional
-        Required if using lossy encoding, this is the compression ratio to use
-        for each layer. Should be in decreasing order (such as ``[80, 30, 10]``)
-        and the final value may be ``1`` to indicate lossless encoding should
-        be used for that layer.
-    codec_format : int, optional
+    compression_ratios : list[float]
+        Required for lossy encoding, this is the compression ratio to use
+        for each quality layer. Cannot be used with `signal_noise_ratios`.
+    signal_noise_ratios : list[float]
+        Required for lossy encoding, this is the PSNR to use for each quality
+        layer. Cannot be used with `compression_ratios`.
+    codec_format : int
         The codec to used when encoding:
 
         * ``0``: JPEG 2000 codestream only (default) (J2K/J2C format)
-        * ``2``: A boxed JPEG 2000 codestream (JP2 format)
+        * ``1``: A boxed JPEG 2000 codestream (JP2 format)
 
     Returns
     -------
-    int
-        The return code of the encoding, will be ``0`` for success, otherwise
-        encoding failed.
+    tuple[int, bytes]
+        The return code of the encoding and the encoded image data. The return
+        code will be ``0`` for success, otherwise the encoding failed.
     """
     if not (1 <= bits_stored <= arr.dtype.itemsize * 8):
         raise ValueError(
@@ -280,9 +292,9 @@ def encode(
     # MCT may be used with RGB in both lossy and lossless modes
     use_mct = 1 if use_mct else 0
 
-    if codec_format not in (0, 2):
+    if codec_format not in (0, 1):
         raise ValueError(
-            "The value of the 'codec_format' parameter is invalid, must be 0 or 2"
+            f"Invalid 'codec_format' value '{codec_format}', must be 0 or 1"
         )
 
     compression_ratios = [float(x) for x in compression_ratios]
@@ -297,7 +309,7 @@ def encode(
 
     # The destination for the encoded J2K codestream, needs to support BinaryIO
     dst = BytesIO()
-    return_code = Encode(
+    return_code = EncodeArray(
         <cnp.PyArrayObject *> arr,
         <PyObject *> dst,
         bits_stored,
@@ -308,3 +320,151 @@ def encode(
         codec_format,
     )
     return return_code, dst.getvalue()
+
+
+def encode_buffer(
+    src,
+    int columns,
+    int rows,
+    int samples_per_pixel,
+    int bits_stored,
+    int is_signed,
+    int photometric_interpretation,
+    int use_mct,
+    List[float] compression_ratios,
+    List[float] signal_noise_ratios,
+    int codec_format,
+) -> Tuple[int, bytes]:
+    """Return the JPEG 2000 compressed `src`.
+
+    If performing lossy encoding then either `compression_ratios` or
+    `signal_noise_ratios` must be set to a non-empty list, otherwise lossless
+    encoding will be used.
+
+    Parameters
+    ----------
+    src : bytes | bytearray
+        A bytes or bytearray containing the image data to be encoded, ordered as
+        little endian and colour-by-pixel.
+    columns : int
+        The number of columns in the image, should be in the range [1, 65535].
+    rows : int
+        The number of rows in the image, should be in the range [1, 65535].
+    samples_per_pixel : int
+        The number of samples per pixel, should be 1, 3 or 4.
+    bits_stored : int
+        The number of bits used per pixel (i.e. the sample precision), should be
+        in the range [1, 24].
+    is_signed: int
+        ``0`` if the image uses unsigned pixels, ``1`` for signed.
+    photometric_interpretation : int
+        The colour space of the unencoded image data that will be set in the
+        JP2 metadata (if `codec_format` is ``1``).
+    use_mct : bool
+        If ``1`` then apply multi-component transformation (MCT) to RGB
+        images. Requires a `photometric_interpretation` of ``1`` and a
+        `samples_per_pixel` value of ``3``, otherwise no MCT will be used.
+    compression_ratios : list[float]
+        Required for lossy encoding, this is the compression ratio to use
+        for each quality layer. Cannot be used with `signal_noise_ratios`.
+    signal_noise_ratios : list[float]
+        Required for lossy encoding, this is the PSNR to use for each quality
+        layer. Cannot be used with `compression_ratios`.
+    codec_format : int, optional
+        The codec to used when encoding:
+
+        * ``0``: JPEG 2000 codestream only (default) (J2K/J2C format)
+        * ``1``: A boxed JPEG 2000 codestream (JP2 format)
+
+    Returns
+    -------
+    tuple[int, bytes]
+        The return code of the encoding and the JPEG 2000 encoded image data.
+        The return code will be ``0`` for success, otherwise the encoding
+        failed.
+    """
+    # Checks
+    if not isinstance(src, (bytes, bytearray)):
+        raise TypeError(
+            f"'src' must be bytes or bytearray, not {type(src).__name__}"
+        )
+
+    if not 1 <= columns <= 65535:
+        raise ValueError(
+            f"Invalid 'columns' value '{columns}', must be in the range [1, 65535]"
+        )
+
+    if not 1 <= rows <= 65535:
+        raise ValueError(
+            f"Invalid 'rows' value '{rows}', must be in the range [1, 65535]"
+        )
+
+    if samples_per_pixel not in (1, 3, 4):
+        raise ValueError(
+            f"Invalid 'samples_per_pixel' value '{samples_per_pixel}', must be 1, 3 "
+            "or 4"
+        )
+
+    if 0 < bits_stored <= 8:
+        bytes_allocated = 1
+    elif 8 < bits_stored <= 16:
+        bytes_allocated = 2
+    elif 16 < bits_stored <= 24:
+        bytes_allocated = 4
+    else:
+        raise ValueError(
+            f"Invalid 'bits_stored' value '{bits_stored}', must be in the "
+            "range [1, 24]"
+        )
+
+    actual_length = len(src)
+    expected_length = rows * columns * samples_per_pixel * bytes_allocated
+    if actual_length != expected_length:
+        raise ValueError(
+            f"The length of 'src' is {actual_length} bytes which doesn't "
+            f"match the expected length of {expected_length} bytes"
+        )
+
+    if is_signed not in (0, 1):
+        raise ValueError(f"Invalid 'is_signed' value '{is_signed}'")
+
+    if photometric_interpretation not in (0, 1, 2, 3, 4, 5):
+        raise ValueError(
+            "Invalid 'photometric_interpretation' value "
+            f"'{photometric_interpretation}', must be in the range [0, 5]"
+        )
+
+    if use_mct not in (0, 1):
+        raise ValueError(f"Invalid 'use_mct' value '{use_mct}'")
+
+    if codec_format not in (0, 1):
+        raise ValueError(
+            f"Invalid 'codec_format' value '{codec_format}', must be 0 or 1"
+        )
+
+    compression_ratios = [float(x) for x in compression_ratios]
+    signal_noise_ratios = [float(x) for x in signal_noise_ratios]
+    if compression_ratios and signal_noise_ratios:
+        raise ValueError(
+            "Only one of 'compression_ratios' or 'signal_noise_ratios' is "
+            "allowed when performing lossy compression"
+        )
+    if len(compression_ratios) > 10 or len(signal_noise_ratios) > 10:
+        raise ValueError("More than 10 compression layers is not supported")
+
+    dst = BytesIO()
+    return_code = EncodeBuffer(
+        <PyObject *> src,
+        columns,
+        rows,
+        samples_per_pixel,
+        bits_stored,
+        is_signed,
+        photometric_interpretation,
+        <PyObject *> dst,
+        use_mct,
+        <PyObject *> compression_ratios,
+        <PyObject *> signal_noise_ratios,
+        codec_format,
+    )
+    return return_code, dst.getvalue()
diff --git a/openjpeg/utils.py b/openjpeg/utils.py
index fb8c147..61e123c 100644
--- a/openjpeg/utils.py
+++ b/openjpeg/utils.py
@@ -48,7 +48,7 @@ class PhotometricInterpretation(IntEnum):
     4: "failed to set the component indices",
     5: "failed to set the decoded area",
     6: "failed to decode image",
-    7: "support for more than 16-bits per component is not implemented",
+    7: "support for more than 32-bits per component is not implemented",
     8: "failed to upscale subsampled components",
 }
 ENCODING_ERRORS = {
@@ -61,10 +61,8 @@ class PhotometricInterpretation(IntEnum):
         "the input array has an invalid shape, must be (rows, columns) or "
         "(rows, columns, planes)"
     ),
-    3: ("the input array has an unsupported number of rows, must be " "in (1, 65535)"),
-    4: (
-        "the input array has an unsupported number of columns, must be " "in (1, 65535)"
-    ),
+    3: ("the input array has an unsupported number of rows, must be in [1, 65535]"),
+    4: ("the input array has an unsupported number of columns, must be in [1, 65535]"),
     5: (
         "the input array has an unsupported dtype, only bool, u1, u2, u4, i1, i2"
         " and i4 are supported"
@@ -72,20 +70,20 @@ class PhotometricInterpretation(IntEnum):
     6: "the input array must use little endian byte ordering",
     7: "the input array must be C-style, contiguous and aligned",
     8: (
-        "the image precision given by bits stored must be in (1, itemsize of "
-        "the input array's dtype)"
+        "the image precision given by bits stored must be in [1, itemsize of "
+        "the input array's dtype]"
     ),
     9: (
         "the value of the 'photometric_interpretation' parameter is not valid "
-        "for the number of samples per pixel in the input array"
+        "for the number of samples per pixel"
     ),
     10: "the valid of the 'codec_format' paramter is invalid",
     11: "more than 100 'compression_ratios' is not supported",
     12: "invalid item in the 'compression_ratios' value",
-    13: "invalid compression ratio, must be in the range (1, 1000)",
+    13: "invalid compression ratio, lowest value must be at least 1",
     14: "more than 100 'signal_noise_ratios' is not supported",
     15: "invalid item in the 'signal_noise_ratios' value",
-    16: "invalid signal-to-noise ratio, must be in the range (0, 1000)",
+    16: "invalid signal-to-noise ratio, lowest value must be at least 0",
     # Encoding errors
     20: "failed to assign the image component parameters",
     21: "failed to create an empty image object",
@@ -95,6 +93,12 @@ class PhotometricInterpretation(IntEnum):
     25: "failure result from 'opj_start_compress()'",
     26: "failure result from 'opj_encode()'",
     27: "failure result from 'opj_endt_compress()'",
+    50: "the value of the 'bits_stored' parameter is invalid",
+    51: "the value of the 'samples_per_pixel' parameter is invalid",
+    52: "the value of the 'rows' is invalid, must be in [1, 65535]",
+    53: "the value of the 'columns' is invalid, must be in [1, 65535]",
+    54: "the value of the 'is_signed' is invalid, must be 0 or 1",
+    55: "the length of 'src' doesn't match the expected length",
 }
 
 
@@ -114,7 +118,7 @@ def _get_format(stream: BinaryIO) -> int:
         The format of the encoded data, one of:
 
         * ``0``: JPEG-2000 codestream
-        * ``2``: JP2 file format
+        * ``1``: JP2 file format
 
     Raises
     ------
@@ -148,8 +152,7 @@ def decode(
     j2k_format: Union[int, None] = None,
     reshape: bool = True,
 ) -> np.ndarray:
-    """Return the decoded JPEG2000 data from `stream` as a
-    :class:`numpy.ndarray`.
+    """Return the decoded JPEG2000 data from `stream` as a :class:`numpy.ndarray`.
 
     .. versionchanged:: 1.1
 
@@ -157,7 +160,7 @@ def decode(
 
     Parameters
     ----------
-    stream : str, pathlib.Path, bytes or file-like
+    stream : str, pathlib.Path, bytes, bytearray or file-like
         The path to the JPEG 2000 file or a Python object containing the
         encoded JPEG 2000 data. If using a file-like then the object must have
         ``tell()``, ``seek()`` and ``read()`` methods.
@@ -216,7 +219,7 @@ def decode(
     precision = cast(int, meta["precision"])
     rows = cast(int, meta["rows"])
     columns = cast(int, meta["columns"])
-    pixels_per_sample = cast(int, meta["nr_components"])
+    pixels_per_sample = cast(int, meta["samples_per_pixel"])
     pixel_representation = cast(bool, meta["is_signed"])
     bpp = ceil(precision / 8)
 
@@ -232,7 +235,7 @@ def decode(
 
 
 def decode_pixel_data(
-    src: bytes,
+    src: Union[bytes, bytearray],
     ds: Union["Dataset", Dict[str, Any], None] = None,
     version: int = Version.v1,
     **kwargs: Any,
@@ -243,16 +246,14 @@ def decode_pixel_data(
 
     Parameters
     ----------
-    src : bytes
-        A Python object containing the encoded JPEG 2000 data. If not
-        :class:`bytes` then the object must have ``tell()``, ``seek()`` and
-        ``read()`` methods.
+    src : bytes | bytearray
+        The encoded JPEG 2000 data as :class:`bytes`, :class:`bytearray`.
     ds : pydicom.dataset.Dataset, optional
         A :class:`~pydicom.dataset.Dataset` containing the group ``0x0028``
         elements corresponding to the *Pixel data*. If used then the
         *Samples per Pixel*, *Bits Stored* and *Pixel Representation* values
         will be checked against the JPEG 2000 data and warnings issued if
-        different.
+        different. Not used if `version` is ``2``.
     version : int, optional
 
         * If ``1`` (default) then return the image data as an :class:`numpy.ndarray`
@@ -300,11 +301,11 @@ def decode_pixel_data(
         pixel_representation = ds.get("PixelRepresentation", pixel_representation)
 
         meta = get_parameters(buffer, j2k_format)
-        if samples_per_pixel != meta["nr_components"]:
+        if samples_per_pixel != meta["samples_per_pixel"]:
             warnings.warn(
                 f"The (0028,0002) Samples per Pixel value '{samples_per_pixel}' "
                 f"in the dataset does not match the number of components "
-                f"'{meta['nr_components']}' found in the JPEG 2000 data. "
+                f"'{meta['samples_per_pixel']}' found in the JPEG 2000 data. "
                 f"It's recommended that you change the  Samples per Pixel value "
                 f"to produce the correct output"
             )
@@ -368,7 +369,7 @@ def get_parameters(
     dict
         A :class:`dict` containing the J2K image parameters:
         ``{'columns': int, 'rows': int, 'colourspace': str,
-        'nr_components: int, 'precision': int, `is_signed`: bool}``. Possible
+        'samples_per_pixel: int, 'precision': int, `is_signed`: bool}``. Possible
         colour spaces are "unknown", "unspecified", "sRGB", "monochrome",
         "YUV", "e-YCC" and "CYMK".
 
@@ -425,7 +426,7 @@ def _get_bits_stored(arr: np.ndarray) -> int:
     return cast(int, arr.dtype.itemsize * 8)
 
 
-def encode(
+def encode_array(
     arr: np.ndarray,
     bits_stored: Union[int, None] = None,
     photometric_interpretation: int = 0,
@@ -441,22 +442,44 @@ def encode(
     use lossy compression either `compression_ratios` or `signal_noise_ratios`
     must be supplied.
 
+    The following encoding parameters are always used:
+
+    * No sub-sampling
+    * LRCP progression order
+    * 64 x 64 code blocks
+    * 6 DWT resolutions
+    * 2^15 x 2^15 precincts
+    * 1 tile
+    * No SOP or EPH markers
+    * MCT will be used by default for 3 samples per pixel if
+      `photometric_interpretation` is ``1`` (RGB)
+
+    Lossless compression will use the following:
+
+    * DWT 5-3 with reversible component transformation
+    * 1 quality layer
+
+    Lossy compression will use the following:
+
+    * DWT 9-7 with irreversible component transformation
+    * 1 or more quality layers
+
     Parameters
     ----------
     arr : numpy.ndarray
-        The array containing the image data to be encoded. 1-bit data should be
-        unpacked (if packed) and stored as a bool or u1 dtype.
+        The array containing the image data to be encoded. For 1-bit DICOM
+        *Pixel Data*, the data should be unpacked (if packed) and stored as a
+        bool or u1 dtype.
     bits_stored : int, optional
-        The bit-depth of the image, defaults to the minimum bit-depth required
-        to fully cover the range of pixel data in `arr`.
+        The bit-depth (precision) of the pixels in the image, defaults to the
+        minimum bit-depth required to fully cover the range of pixel data in
+        `arr`.
     photometric_interpretation : int, optional
-        The colour space of the unencoded image data that will be set in the
-        JPEG 2000 metadata. If you are encoded RGB or YCbCr data then it's
-        strongly recommended that you select the correct colour space so
-        that anyone decoding your image data will know which colour space
-        transforms to apply. One of:
+        The colour space of the unencoded image data, used to help determine
+        if MCT may be applied. If `codec_format` is ``1`` then this will also
+        be the colour space set in the JP2 metadata. One of:
 
-        * ``0``: Unspecified
+        * ``0``: Unspecified (default)
         * ``1``: sRGB
         * ``2``: Greyscale
         * ``3``: sYCC (YCbCr)
@@ -478,26 +501,33 @@ def encode(
         If MCT is not applied then *Photometric Intrepretation* should be the
         value corresponding to the unencoded dataset.
     compression_ratios : list[float], optional
-        Required if using lossy encoding, this is the compression ratio to use
-        for each layer. Should be in decreasing order (such as ``[80, 30, 10]``)
-        and the final value may be ``1`` to indicate lossless encoding should
-        be used for that layer. Cannot be used with `signal_noise_ratios`.
+        Required for lossy encoding, this is the compression ratio to use
+        for each quality layer. Each item in the list is the factor of
+        compression for a quality layer, so a value of ``[5]`` means 1 quality
+        layer with 5x compression and a value of ``[5, 2]`` means 2 quality
+        layers, one with 5x compression and one with 2x compression. If using
+        multiple quality layers then the list should be in ordered with
+        decreasing compression value and the lowest value must be at least 1.
+        **Cannot be used with** `signal_noise_ratios`.
     signal_noise_ratios : list[float], optional
-        Required if using lossy encoding, this is the desired peak
-        signal-to-noise ratio to use for each layer. Should be in increasing
-        order (such as ``[30, 40, 50]``), except for the last layer which may
-        be ``0`` to indicate lossless encoding should be used for that layer.
-        Cannot be used with `compression_ratios`.
+        Required for lossy encoding, this is a list of the desired peak
+        signal-to-noise ratio (PSNR) to use for each layer. Each item in the
+        list is the PSNR for a quality layer, so a value of ``[30]`` means 1
+        quality layer with a PSNR of 30, and a value of ``[30, 50]`` means 2
+        quality layers, one with a PSNR of 30 and one with a PSNR of 50. If
+        using multiple quality layers then the list should be in ordered with
+        increasing PSNR value and the lowest value must be greater than 0.
+        **Cannot be used with** `compression_ratios`.
     codec_format : int, optional
         The codec to used when encoding:
 
         * ``0``: JPEG 2000 codestream only (default) (J2K/J2C format)
-        * ``2``: A boxed JPEG 2000 codestream (JP2 format)
+        * ``1``: A boxed JPEG 2000 codestream (JP2 format)
 
     Returns
     -------
     bytes
-        The encoded JPEG 2000 image data.
+        A JPEG 2000 or JP2 (with `codec_format=1`) codestream.
     """
     if compression_ratios is None:
         compression_ratios = []
@@ -515,7 +545,7 @@ def encode(
         bits_stored = _get_bits_stored(arr)
 
     # The destination for the encoded data, must support BinaryIO
-    return_code, buffer = _openjpeg.encode(
+    return_code, buffer = _openjpeg.encode_array(
         arr,
         bits_stored,
         photometric_interpretation,
@@ -533,48 +563,208 @@ def encode(
     return cast(bytes, buffer)
 
 
-def encode_pixel_data(arr: np.ndarray, **kwargs: Any) -> bytes:
-    """Return the JPEG 2000 compressed `arr`.
+encode = encode_array
+
+
+def encode_buffer(
+    src: Union[bytes, bytearray],
+    columns: int,
+    rows: int,
+    samples_per_pixel: int,
+    bits_stored: int,
+    is_signed: bool,
+    *,
+    photometric_interpretation: int = 0,
+    use_mct: bool = True,
+    compression_ratios: Union[List[float], None] = None,
+    signal_noise_ratios: Union[List[float], None] = None,
+    codec_format: int = 0,
+    **kwargs: Any,
+) -> bytes:
+    """Return the JPEG 2000 compressed `src`.
+
+    .. versionadded:: 2.2
+
+    The following encoding parameters are always used:
 
-    .. versionadded:: 2.1
+    * No sub-sampling
+    * LRCP progression order
+    * 64 x 64 code blocks
+    * 6 DWT resolutions
+    * 2^15 x 2^15 precincts
+    * 1 tile
+    * No SOP or EPH markers
+    * MCT will be used by default for 3 samples per pixel if
+      `photometric_interpretation` is ``1`` (RGB)
+
+    Lossless compression will use the following:
+
+    * DWT 5-3 with reversible component transformation
+    * 1 quality layer
+
+    Lossy compression will use the following:
+
+    * DWT 9-7 with irreversible component transformation
+    * 1 or more quality layers
 
     Parameters
     ----------
-    src : numpy.ndarray
-        An array containing a single frame of image data to be encoded.
+    src : bytes | bytearray
+        A single frame of little endian, colour-by-pixel ordered image data to
+        be JPEG 2000 encoded. Each pixel should be encoded using the following
+        (each pixel has 1 or more samples):
+
+        * For  0 < bits per sample <=  8: 1 byte per sample
+        * For  8 < bits per sample <= 16: 2 bytes per sample
+        * For 16 < bits per sample <= 24: 4 bytes per sample
+    columns : int
+        The number of columns in the image, must be in the range [1, 2**16 - 1].
+    rows : int
+        The number of rows in the image, must be in the range [1, 2**16 - 1].
+    samples_per_pixel : int
+        The number of samples per pixel, must be 1, 3 or 4.
+    bits_stored : int
+        The number of bits per sample for each pixel, must be in the range
+        (1, 24).
+    is_signed : bool
+        If ``True`` then the image uses signed integers, ``False`` otherwise.
+    photometric_interpretation : int, optional
+        The colour space of the unencoded image data, used to help determine
+        if MCT may be applied. If `codec_format` is ``1`` then this will also
+        be the colour space set in the JP2 metadata. One of:
+
+        * ``0``: Unspecified (default)
+        * ``1``: sRGB
+        * ``2``: Greyscale
+        * ``3``: sYCC (YCbCr)
+        * ``4``: eYCC
+        * ``5``: CMYK
+    use_mct : bool, optional
+        Apply multi-component transformation (MCT) prior to encoding the image
+        data. Defaults to ``True`` when the `photometric_interpretation` is
+        ``1`` as it is intended for use with RGB data and should result in
+        smaller file sizes. For all other values of `photometric_interpretation`
+        the value of `use_mct` will be ignored and MCT not applied.
+
+        If MCT is applied then the corresponding value of (0028,0004)
+        *Photometric Interpretation* is:
+
+        * ``"YBR_RCT"`` for lossless encoding
+        * ``"YBR_ICT"`` for lossy encoding
+
+        If MCT is not applied then *Photometric Intrepretation* should be the
+        value corresponding to the unencoded dataset.
+    compression_ratios : list[float], optional
+        Required for lossy encoding, this is the compression ratio to use
+        for each quality layer. Each item in the list is the factor of
+        compression for a quality layer, so a value of ``[5]`` means 1 quality
+        layer with 5x compression and a value of ``[5, 2]`` means 2 quality
+        layers, one with 5x compression and one with 2x compression. If using
+        multiple quality layers then the list should be in ordered with
+        decreasing compression value and the lowest value must be at least 1.
+        **Cannot be used with** `signal_noise_ratios`.
+    signal_noise_ratios : list[float], optional
+        Required for lossy encoding, this is a list of the desired peak
+        signal-to-noise ratio (PSNR) to use for each layer. Each item in the
+        list is the PSNR for a quality layer, so a value of ``[30]`` means 1
+        quality layer with a PSNR of 30, and a value of ``[30, 50]`` means 2
+        quality layers, one with a PSNR of 30 and one with a PSNR of 50. If
+        using multiple quality layers then the list should be in ordered with
+        increasing PSNR value and the lowest value must be greater than 0.
+        **Cannot be used with** `compression_ratios`.
+    codec_format : int, optional
+        The codec to used when encoding:
+
+        * ``0``: JPEG 2000 codestream only (default) (J2K/J2C format)
+        * ``1``: A boxed JPEG 2000 codestream (JP2 format)
+
+    Returns
+    -------
+    bytes
+        A JPEG 2000 or JP2 (with `codec_format=1`) codestream.
+    """
+
+    if compression_ratios is None:
+        compression_ratios = []
+
+    if signal_noise_ratios is None:
+        signal_noise_ratios = []
+
+    return_code, buffer = _openjpeg.encode_buffer(
+        src,
+        columns,
+        rows,
+        samples_per_pixel,
+        bits_stored,
+        1 if is_signed else 0,
+        photometric_interpretation,
+        1 if use_mct else 0,
+        compression_ratios,
+        signal_noise_ratios,
+        codec_format,
+    )
+
+    if return_code != 0:
+        raise RuntimeError(
+            f"Error encoding the data: {ENCODING_ERRORS.get(return_code, return_code)}"
+        )
+
+    return cast(bytes, buffer)
+
+
+def encode_pixel_data(
+    src: Union[bytes, bytearray], **kwargs: Any
+) -> bytes:
+    """Return the JPEG 2000 compressed `src`.
+
+    .. versionadded:: 2.2
+
+    Parameters
+    ----------
+    src : bytes | bytearray
+        A single frame of little endian, colour-by-pixel ordered image data to
+        be JPEG2000 encoded. Each pixel should be encoded using the following:
+
+        * For  0 < bits per sample <=  8: 1 byte per sample
+        * For  8 < bits per sample <= 16: 2 bytes per sample
+        * For 16 < bits per sample <= 24: 4 bytes per sample
     **kwargs
+        The following keyword arguments are required:
+
+        * ``'rows'``: int - the number of rows in the image (1, 65535)
+        * ``'columns'``: int - the number of columns in the image (1, 65535)
+        * ``'samples_per_pixel': int - the number of samples per pixel, 1 or 3.
+        * ``'bits_stored'``: int - the number of bits per sample for pixels in
+          the image (1, 24)
+        * ``'photometric_interpretation'``: str - the colour space of the
+          image in `src`.
+
         The following keyword arguments are optional:
 
-        * ``'photometric_interpretation'``: int - the colour space of the
-          unencoded image in `arr`, one of the following:
-
-          * ``0``: Unspecified
-          * ``1``: sRGB
-          * ``2``: Greyscale
-          * ``3``: sYCC (YCbCr)
-          * ``4``: eYCC
-          * ``5``: CMYK
-
-          It is strongly recommended you supply an appropriate
-          `photometric_interpretation`.
-        * ``'bits_stored'``: int - the bit-depth of the pixels in the image,
-          if not supplied then the smallest bit-depth that covers the full range
-          of pixel data in `arr` will be used.
-        * ``'lossless'``: bool: ``True`` to use lossless encoding (default),
-          ``False`` for lossy encoding. If using lossy encoding then
-          `compression_ratios` is required.
-        * ```use_mct': bool: ``True`` to use MCT with RGB images (default),
-          ``False`` otherwise.
-        * ``'codec_format'``: int - 0 for a JPEG2000 codestream (default),
-          1 for a JP2 codestream
-        * ''`compression_ratios'``: list[float] - required if `lossless` is
-          ``False``. Should be a list of the desired compression ratio per layer
-          in decreasing values. The final layer may be 1 for lossless
-          compression of that layer. Minimum value is 1 (for lossless).
+        * ``'use_mct'``: bool: ``True`` to use MCT with RGB images (default)
+          ``False`` otherwise. Will be ignored if `photometric_interpretation`
+          is not RGB, YBR_RCT or YBR_ICT.
+        * ''`compression_ratios'``: list[float] - required for lossy encoding if
+          `signal_noise_ratios` is not used. The desired compression ratio to
+          use for each quality layer.
+        * ``'signal_noise_ratios'``: list[float] - required for lossy encoding
+          if `compression_ratios` is not used. The desired peak
+          signal-to-noise ratio (PSNR) to use for each quality layer.
 
     Returns
     -------
-    bytes
-        The JPEG 2000 encoded image data.
+    bytes | bytearray
+        A JPEG 2000 codestream.
     """
-    return encode(arr, **kwargs)
+    # A J2K codestream doesn't track the colour space, so the photometric
+    #   interpretation is only used to help with setting MCT
+    pi = kwargs["photometric_interpretation"]
+    if pi in ("RGB", "YBR_ICT", "YBR_RCT"):
+        kwargs["photometric_interpretation"] = 1
+    else:
+        kwargs["photometric_interpretation"] = 0
+
+    kwargs["is_signed"] = kwargs["pixel_representation"]
+    kwargs["codec_format"] = 0
+
+    return encode_buffer(src, **kwargs)
diff --git a/pyproject.toml b/pyproject.toml
index 0cba5c3..5d6c79f 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -48,7 +48,8 @@ packages = [
     {include = "openjpeg" },
 ]
 readme = "README.md"
-version = "2.1.1"
+version = "2.2.0"
+
 
 [tool.poetry.dependencies]
 python = "^3.8"


Test patch:
diff --git a/openjpeg/tests/test_encode.py b/openjpeg/tests/test_encode.py
index ee7c2af..4d49040 100644
--- a/openjpeg/tests/test_encode.py
+++ b/openjpeg/tests/test_encode.py
@@ -6,7 +6,8 @@
 
 from openjpeg.data import JPEG_DIRECTORY
 from openjpeg.utils import (
-    encode,
+    encode_array,
+    encode_buffer,
     encode_pixel_data,
     decode,
     PhotometricInterpretation as PI,
@@ -69,7 +70,7 @@ def parse_j2k(buffer):
 
 
 class TestEncode:
-    """Tests for encode()"""
+    """Tests for encode_array()"""
 
     def test_invalid_shape_raises(self):
         """Test invalid array shapes raise exceptions."""
@@ -78,10 +79,10 @@ def test_invalid_shape_raises(self):
             r"must be \(rows, columns\) or \(rows, columns, planes\)"
         )
         with pytest.raises(RuntimeError, match=msg):
-            encode(np.ones((1,), dtype="u1"))
+            encode_array(np.ones((1,), dtype="u1"))
 
         with pytest.raises(RuntimeError, match=msg):
-            encode(np.ones((1, 2, 3, 4), dtype="u1"))
+            encode_array(np.ones((1, 2, 3, 4), dtype="u1"))
 
     def test_invalid_samples_per_pixel_raises(self):
         """Test invalid samples per pixel raise exceptions."""
@@ -90,17 +91,17 @@ def test_invalid_samples_per_pixel_raises(self):
             "of samples per pixel, must be 1, 3 or 4"
         )
         with pytest.raises(RuntimeError, match=msg):
-            encode(np.ones((1, 2, 2), dtype="u1"))
+            encode_array(np.ones((1, 2, 2), dtype="u1"))
 
         with pytest.raises(RuntimeError, match=msg):
-            encode(np.ones((1, 2, 5), dtype="u1"))
+            encode_array(np.ones((1, 2, 5), dtype="u1"))
 
     def test_invalid_dtype_raises(self):
         """Test invalid array dtype raise exceptions."""
         msg = "input array has an unsupported dtype"
         for dtype in ("u8", "i8", "f", "d", "c", "U", "m", "M"):
             with pytest.raises((ValueError, RuntimeError), match=msg):
-                encode(np.ones((1, 2), dtype=dtype))
+                encode_array(np.ones((1, 2), dtype=dtype))
 
     def test_invalid_contiguity_raises(self):
         """Test invalid array contiguity raise exceptions."""
@@ -109,23 +110,23 @@ def test_invalid_contiguity_raises(self):
             "contiguous and aligned"
         )
         with pytest.raises(RuntimeError, match=msg):
-            encode(np.ones((3, 3), dtype="u1").T)
+            encode_array(np.ones((3, 3), dtype="u1").T)
 
     def test_invalid_dimensions_raises(self):
         """Test invalid array dimensions raise exceptions."""
         msg = (
             "Error encoding the data: the input array has an unsupported number "
-            r"of rows, must be in \(1, 65535\)"
+            r"of rows, must be in \[1, 65535\]"
         )
         with pytest.raises(RuntimeError, match=msg):
-            encode(np.ones((65536, 1), dtype="u1"))
+            encode_array(np.ones((65536, 1), dtype="u1"))
 
         msg = (
             "Error encoding the data: the input array has an unsupported number "
-            r"of columns, must be in \(1, 65535\)"
+            r"of columns, must be in \[1, 65535\]"
         )
         with pytest.raises(RuntimeError, match=msg):
-            encode(np.ones((1, 65536), dtype="u1"))
+            encode_array(np.ones((1, 65536), dtype="u1"))
 
     def test_invalid_bits_stored_raises(self):
         """Test invalid bits_stored"""
@@ -134,31 +135,31 @@ def test_invalid_bits_stored_raises(self):
             r"be in the range \(1, 8\)"
         )
         with pytest.raises(ValueError, match=msg):
-            encode(np.ones((1, 2), dtype="u1"), bits_stored=0)
+            encode_array(np.ones((1, 2), dtype="u1"), bits_stored=0)
 
         with pytest.raises(ValueError, match=msg):
-            encode(np.ones((1, 2), dtype="u1"), bits_stored=9)
+            encode_array(np.ones((1, 2), dtype="u1"), bits_stored=9)
 
         msg = (
             "A 'bits_stored' value of 15 is incompatible with the range of "
             r"pixel data in the input array: \(-16385, 2\)"
         )
         with pytest.raises(ValueError, match=msg):
-            encode(np.asarray([-(2**14) - 1, 2], dtype="i2"), bits_stored=15)
+            encode_array(np.asarray([-(2**14) - 1, 2], dtype="i2"), bits_stored=15)
 
         msg = (
             "A 'bits_stored' value of 15 is incompatible with the range of "
             r"pixel data in the input array: \(-16384, 16384\)"
         )
         with pytest.raises(ValueError, match=msg):
-            encode(np.asarray([-(2**14), 2**14], dtype="i2"), bits_stored=15)
+            encode_array(np.asarray([-(2**14), 2**14], dtype="i2"), bits_stored=15)
 
         msg = (
             "A 'bits_stored' value of 4 is incompatible with the range of "
             r"pixel data in the input array: \(0, 16\)"
         )
         with pytest.raises(ValueError, match=msg):
-            encode(np.asarray([0, 2**4], dtype="u2"), bits_stored=4)
+            encode_array(np.asarray([0, 2**4], dtype="u2"), bits_stored=4)
 
     def test_invalid_pixel_value_raises(self):
         """Test invalid pixel values raise exceptions."""
@@ -167,13 +168,13 @@ def test_invalid_pixel_value_raises(self):
             "supported bit-depth of 24"
         )
         with pytest.raises(ValueError, match=msg):
-            encode(np.asarray([2**24, 2], dtype="u4"))
+            encode_array(np.asarray([2**24, 2], dtype="u4"))
 
         with pytest.raises(ValueError, match=msg):
-            encode(np.asarray([2**23, 2], dtype="i4"))
+            encode_array(np.asarray([2**23, 2], dtype="i4"))
 
         with pytest.raises(ValueError, match=msg):
-            encode(np.asarray([-(2**23) - 1, 2], dtype="i4"))
+            encode_array(np.asarray([-(2**23) - 1, 2], dtype="i4"))
 
     def test_compression_snr_raises(self):
         """Test using compression_ratios and signal_noise_ratios raises."""
@@ -182,7 +183,7 @@ def test_compression_snr_raises(self):
             "allowed when performing lossy compression"
         )
         with pytest.raises(ValueError, match=msg):
-            encode(
+            encode_array(
                 np.asarray([0, 2], dtype="u2"),
                 compression_ratios=[2, 1],
                 signal_noise_ratios=[1, 2],
@@ -192,64 +193,53 @@ def test_invalid_photometric_raises(self):
         """Test invalid photometric_interpretation raises."""
         msg = (
             "Error encoding the data: the value of the 'photometric_interpretation' "
-            "parameter is not valid for the number of samples per pixel in the "
-            "input array"
+            "parameter is not valid for the number of samples per pixel"
         )
         with pytest.raises(RuntimeError, match=msg):
-            encode(np.ones((1, 2), dtype="u1"), photometric_interpretation=PI.RGB)
+            encode_array(np.ones((1, 2), dtype="u1"), photometric_interpretation=PI.RGB)
 
         with pytest.raises(RuntimeError, match=msg):
-            encode(
+            encode_array(
                 np.ones((1, 2, 3), dtype="u1"),
                 photometric_interpretation=PI.MONOCHROME2,
             )
 
         with pytest.raises(RuntimeError, match=msg):
-            encode(
+            encode_array(
                 np.ones((1, 2, 4), dtype="u1"),
                 photometric_interpretation=PI.MONOCHROME2,
             )
 
         with pytest.raises(RuntimeError, match=msg):
-            encode(np.ones((1, 2, 4), dtype="u1"), photometric_interpretation=PI.RGB)
-
-    def test_invalid_codec_format_raises(self):
-        """Test an invalid 'codec_format' raises and exception."""
-        msg = "The value of the 'codec_format' parameter is invalid, must be 0 or 2"
-        with pytest.raises(ValueError, match=msg):
-            encode(np.ones((1, 2), dtype="u1"), codec_format=1)
+            encode_array(
+                np.ones((1, 2, 4), dtype="u1"), photometric_interpretation=PI.RGB
+            )
 
     def test_invalid_compression_ratios_raises(self):
         """Test an invalid 'compression_ratios' raises exceptions."""
         msg = "More than 10 compression layers is not supported"
         with pytest.raises(ValueError, match=msg):
-            encode(np.ones((1, 2), dtype="u1"), compression_ratios=[1] * 11)
+            encode_array(np.ones((1, 2), dtype="u1"), compression_ratios=[1] * 11)
 
         msg = (
-            "Error encoding the data: invalid compression ratio, must be in the "
-            r"range \(1, 1000\)"
+            "Error encoding the data: invalid compression ratio, lowest value "
+            "must be at least 1"
         )
         with pytest.raises(RuntimeError, match=msg):
-            encode(np.ones((1, 2), dtype="u1"), compression_ratios=[0])
-
-        with pytest.raises(RuntimeError, match=msg):
-            encode(np.ones((1, 2), dtype="u1"), compression_ratios=[1001])
+            encode_array(np.ones((1, 2), dtype="u1"), compression_ratios=[0])
 
     def test_invalid_signal_noise_ratios_raises(self):
         """Test an invalid 'signal_noise_ratios' raises exceptions."""
         msg = "More than 10 compression layers is not supported"
         with pytest.raises(ValueError, match=msg):
-            encode(np.ones((1, 2), dtype="u1"), signal_noise_ratios=[1] * 11)
+            encode_array(np.ones((1, 2), dtype="u1"), signal_noise_ratios=[1] * 11)
 
         msg = (
-            "Error encoding the data: invalid signal-to-noise ratio, must be "
-            r"in the range \(0, 1000\)"
+            "Error encoding the data: invalid signal-to-noise ratio, lowest "
+            "value must be at least 0"
         )
         with pytest.raises(RuntimeError, match=msg):
-            encode(np.ones((1, 2), dtype="u1"), signal_noise_ratios=[-1])
-
-        with pytest.raises(RuntimeError, match=msg):
-            encode(np.ones((1, 2), dtype="u1"), signal_noise_ratios=[1001])
+            encode_array(np.ones((1, 2), dtype="u1"), signal_noise_ratios=[-1])
 
     def test_encoding_failures_raise(self):
         """Miscellaneous test to check that failures are handled properly."""
@@ -258,23 +248,23 @@ def test_encoding_failures_raise(self):
         #   creating the empty image
         #   setting the encoder
         #   creating the output stream
-        #   opj_encode()
+        #   opj_encode_array()
         #   opj_end_compress()
 
         # Input too small
         msg = r"Error encoding the data: failure result from 'opj_start_compress\(\)'"
         with pytest.raises(RuntimeError, match=msg):
-            encode(np.ones((1, 2), dtype="u1"))
+            encode_array(np.ones((1, 2), dtype="u1"))
 
     def test_mct(self):
         """Test that MCT is applied as required."""
         # Should only be applied with RGB
         arr = np.random.randint(0, 2**8 - 1, size=(100, 100, 3), dtype="u1")
-        buffer = encode(arr, photometric_interpretation=PI.RGB, use_mct=True)
+        buffer = encode_array(arr, photometric_interpretation=PI.RGB, use_mct=True)
         param = parse_j2k(buffer)
         assert param["mct"] is True
 
-        buffer = encode(
+        buffer = encode_array(
             arr,
             photometric_interpretation=PI.RGB,
             use_mct=True,
@@ -283,11 +273,11 @@ def test_mct(self):
         param = parse_j2k(buffer)
         assert param["mct"] is True
 
-        buffer = encode(arr, photometric_interpretation=PI.RGB, use_mct=False)
+        buffer = encode_array(arr, photometric_interpretation=PI.RGB, use_mct=False)
         param = parse_j2k(buffer)
         assert param["mct"] is False
 
-        buffer = encode(
+        buffer = encode_array(
             arr,
             photometric_interpretation=PI.RGB,
             use_mct=False,
@@ -297,11 +287,11 @@ def test_mct(self):
         assert param["mct"] is False
 
         for pi in (0, 3, 4):
-            buffer = encode(arr, photometric_interpretation=pi, use_mct=True)
+            buffer = encode_array(arr, photometric_interpretation=pi, use_mct=True)
             param = parse_j2k(buffer)
             assert param["mct"] is False
 
-            buffer = encode(
+            buffer = encode_array(
                 arr,
                 photometric_interpretation=pi,
                 use_mct=True,
@@ -311,11 +301,13 @@ def test_mct(self):
             assert param["mct"] is False
 
         arr = np.random.randint(0, 2**8 - 1, size=(100, 100), dtype="u1")
-        buffer = encode(arr, photometric_interpretation=PI.MONOCHROME1, use_mct=True)
+        buffer = encode_array(
+            arr, photometric_interpretation=PI.MONOCHROME1, use_mct=True
+        )
         param = parse_j2k(buffer)
         assert param["mct"] is False
 
-        buffer = encode(
+        buffer = encode_array(
             arr,
             photometric_interpretation=PI.MONOCHROME1,
             use_mct=True,
@@ -325,11 +317,11 @@ def test_mct(self):
         assert param["mct"] is False
 
         arr = np.random.randint(0, 2**8 - 1, size=(100, 100, 4), dtype="u1")
-        buffer = encode(arr, photometric_interpretation=5, use_mct=True)
+        buffer = encode_array(arr, photometric_interpretation=5, use_mct=True)
         param = parse_j2k(buffer)
         assert param["mct"] is False
 
-        buffer = encode(
+        buffer = encode_array(
             arr,
             photometric_interpretation=5,
             use_mct=True,
@@ -340,11 +332,26 @@ def test_mct(self):
 
     def test_lossless_bool(self):
         """Test encoding bool data for bit-depth 1"""
-        rows = 123
-        cols = 234
-        planes = 3
-        arr = np.random.randint(0, high=1, size=(rows, cols), dtype="bool")
-        buffer = encode(arr, photometric_interpretation=PI.MONOCHROME2)
+        """Test encoding bool data for bit-depth 1"""
+        # Convert one of the test images to 1-bit
+        # Note that as of OpenJpeg v2.5.0 that random 1-bit images are prone
+        #   to encoding failures
+        jpg = DIR_15444 / "HTJ2K" / "Bretagne1_ht.j2k"
+        with open(jpg, "rb") as f:
+            data = f.read()
+
+        arr = decode(data)
+        assert "uint8" == arr.dtype
+        assert (480, 640, 3) == arr.shape
+
+        mono = arr[..., 0]
+        mono[mono <= 127] = 0
+        mono[mono > 127] = 1
+        mono = mono.astype("bool")
+        assert mono.min() == 0
+        assert mono.max() == 1
+
+        buffer = encode_array(mono, photometric_interpretation=PI.MONOCHROME2)
         out = decode(buffer)
         param = parse_j2k(buffer)
         assert param["precision"] == 1
@@ -353,10 +360,13 @@ def test_lossless_bool(self):
         assert param["components"] == 1
 
         assert out.dtype.kind == "u"
-        assert np.array_equal(arr, out)
+        assert np.array_equal(mono, out)
 
-        arr = np.random.randint(0, high=1, size=(rows, cols, planes), dtype="bool")
-        buffer = encode(arr, photometric_interpretation=PI.RGB, use_mct=False)
+        arr[arr <= 127] = 0
+        arr[arr > 127] = 1
+        arr = arr.astype("bool")
+
+        buffer = encode_array(arr, photometric_interpretation=PI.RGB)
         out = decode(buffer)
         param = parse_j2k(buffer)
         assert param["precision"] == 1
@@ -371,11 +381,11 @@ def test_lossless_unsigned(self):
         """Test encoding unsigned data for bit-depth 1-16"""
         rows = 123
         cols = 234
-        for bit_depth in range(1, 17):
+        for bit_depth in range(2, 17):
             maximum = 2**bit_depth - 1
             dtype = f"u{math.ceil(bit_depth / 8)}"
-            arr = np.random.randint(0, high=maximum, size=(rows, cols), dtype=dtype)
-            buffer = encode(arr, photometric_interpretation=PI.MONOCHROME2)
+            arr = np.random.randint(0, high=maximum + 1, size=(rows, cols), dtype=dtype)
+            buffer = encode_array(arr, photometric_interpretation=PI.MONOCHROME2)
             out = decode(buffer)
             param = parse_j2k(buffer)
             assert param["precision"] == bit_depth
@@ -386,8 +396,10 @@ def test_lossless_unsigned(self):
             assert out.dtype.kind == "u"
             assert np.array_equal(arr, out)
 
-            arr = np.random.randint(0, high=maximum, size=(rows, cols, 3), dtype=dtype)
-            buffer = encode(arr, photometric_interpretation=PI.RGB, use_mct=False)
+            arr = np.random.randint(
+                0, high=maximum + 1, size=(rows, cols, 3), dtype=dtype
+            )
+            buffer = encode_array(arr, photometric_interpretation=PI.RGB, use_mct=False)
             out = decode(buffer)
             param = parse_j2k(buffer)
             assert param["precision"] == bit_depth
@@ -398,8 +410,10 @@ def test_lossless_unsigned(self):
             assert out.dtype.kind == "u"
             assert np.array_equal(arr, out)
 
-            arr = np.random.randint(0, high=maximum, size=(rows, cols, 4), dtype=dtype)
-            buffer = encode(arr, photometric_interpretation=5, use_mct=False)
+            arr = np.random.randint(
+                0, high=maximum + 1, size=(rows, cols, 4), dtype=dtype
+            )
+            buffer = encode_array(arr, photometric_interpretation=5, use_mct=False)
             out = decode(buffer)
             param = parse_j2k(buffer)
             assert param["precision"] == bit_depth
@@ -417,8 +431,8 @@ def test_lossless_unsigned_u4(self):
         planes = 3
         for bit_depth in range(17, 25):
             maximum = 2**bit_depth - 1
-            arr = np.random.randint(0, high=maximum, size=(rows, cols), dtype="u4")
-            buffer = encode(arr, photometric_interpretation=PI.MONOCHROME2)
+            arr = np.random.randint(0, high=maximum + 1, size=(rows, cols), dtype="u4")
+            buffer = encode_array(arr, photometric_interpretation=PI.MONOCHROME2)
             out = decode(buffer)
 
             param = parse_j2k(buffer)
@@ -431,9 +445,9 @@ def test_lossless_unsigned_u4(self):
             assert np.array_equal(arr, out)
 
             arr = np.random.randint(
-                0, high=maximum, size=(rows, cols, planes), dtype="u4"
+                0, high=maximum + 1, size=(rows, cols, planes), dtype="u4"
             )
-            buffer = encode(arr, photometric_interpretation=PI.RGB, use_mct=False)
+            buffer = encode_array(arr, photometric_interpretation=PI.RGB, use_mct=False)
             out = decode(buffer)
 
             param = parse_j2k(buffer)
@@ -449,14 +463,14 @@ def test_lossless_signed(self):
         """Test encoding signed data for bit-depth 1-16"""
         rows = 123
         cols = 543
-        for bit_depth in range(1, 17):
+        for bit_depth in range(2, 17):
             maximum = 2 ** (bit_depth - 1) - 1
             minimum = -(2 ** (bit_depth - 1))
             dtype = f"i{math.ceil(bit_depth / 8)}"
             arr = np.random.randint(
-                low=minimum, high=maximum, size=(rows, cols), dtype=dtype
+                low=minimum, high=maximum + 1, size=(rows, cols), dtype=dtype
             )
-            buffer = encode(arr, photometric_interpretation=PI.MONOCHROME2)
+            buffer = encode_array(arr, photometric_interpretation=PI.MONOCHROME2)
             out = decode(buffer)
 
             param = parse_j2k(buffer)
@@ -474,7 +488,7 @@ def test_lossless_signed(self):
             arr = np.random.randint(
                 low=minimum, high=maximum, size=(rows, cols, 3), dtype=dtype
             )
-            buffer = encode(arr, photometric_interpretation=PI.RGB, use_mct=False)
+            buffer = encode_array(arr, photometric_interpretation=PI.RGB, use_mct=False)
             out = decode(buffer)
 
             param = parse_j2k(buffer)
@@ -489,7 +503,7 @@ def test_lossless_signed(self):
             arr = np.random.randint(
                 low=minimum, high=maximum, size=(rows, cols, 4), dtype=dtype
             )
-            buffer = encode(arr, photometric_interpretation=5, use_mct=False)
+            buffer = encode_array(arr, photometric_interpretation=5, use_mct=False)
             out = decode(buffer)
 
             param = parse_j2k(buffer)
@@ -510,9 +524,9 @@ def test_lossless_signed_u4(self):
             maximum = 2 ** (bit_depth - 1) - 1
             minimum = -(2 ** (bit_depth - 1))
             arr = np.random.randint(
-                low=minimum, high=maximum, size=(rows, cols), dtype="i4"
+                low=minimum, high=maximum + 1, size=(rows, cols), dtype="i4"
             )
-            buffer = encode(arr, photometric_interpretation=PI.MONOCHROME2)
+            buffer = encode_array(arr, photometric_interpretation=PI.MONOCHROME2)
             out = decode(buffer)
 
             param = parse_j2k(buffer)
@@ -525,9 +539,9 @@ def test_lossless_signed_u4(self):
             assert np.array_equal(arr, out)
 
             arr = np.random.randint(
-                low=minimum, high=maximum, size=(rows, cols, planes), dtype="i4"
+                low=minimum, high=maximum + 1, size=(rows, cols, planes), dtype="i4"
             )
-            buffer = encode(arr, photometric_interpretation=PI.RGB, use_mct=False)
+            buffer = encode_array(arr, photometric_interpretation=PI.RGB, use_mct=False)
             out = decode(buffer)
 
             param = parse_j2k(buffer)
@@ -546,8 +560,8 @@ def test_lossy_unsigned(self):
         for bit_depth in range(1, 17):
             maximum = 2**bit_depth - 1
             dtype = f"u{math.ceil(bit_depth / 8)}"
-            arr = np.random.randint(0, high=maximum, size=(rows, cols), dtype=dtype)
-            buffer = encode(arr, compression_ratios=[4, 2, 1])
+            arr = np.random.randint(0, high=maximum + 1, size=(rows, cols), dtype=dtype)
+            buffer = encode_array(arr, compression_ratios=[4, 2, 1])
             out = decode(buffer)
             param = parse_j2k(buffer)
             assert param["precision"] == bit_depth
@@ -558,7 +572,7 @@ def test_lossy_unsigned(self):
             assert out.dtype.kind == "u"
             assert np.allclose(arr, out, atol=5)
 
-            buffer = encode(arr, signal_noise_ratios=[50, 100, 200])
+            buffer = encode_array(arr, signal_noise_ratios=[50, 100, 200])
             out = decode(buffer)
             param = parse_j2k(buffer)
             assert param["precision"] == bit_depth
@@ -578,9 +592,9 @@ def test_lossy_signed(self):
             minimum = -(2 ** (bit_depth - 1))
             dtype = f"i{math.ceil(bit_depth / 8)}"
             arr = np.random.randint(
-                low=minimum, high=maximum, size=(rows, cols), dtype=dtype
+                low=minimum, high=maximum + 1, size=(rows, cols), dtype=dtype
             )
-            buffer = encode(arr, compression_ratios=[4, 2, 1])
+            buffer = encode_array(arr, compression_ratios=[4, 2, 1])
             out = decode(buffer)
             param = parse_j2k(buffer)
             assert param["precision"] == bit_depth
@@ -591,7 +605,7 @@ def test_lossy_signed(self):
             assert out.dtype.kind == "i"
             assert np.allclose(arr, out, atol=5)
 
-            buffer = encode(arr, signal_noise_ratios=[50, 100, 200])
+            buffer = encode_array(arr, signal_noise_ratios=[50, 100, 200])
             out = decode(buffer)
             param = parse_j2k(buffer)
             assert param["precision"] == bit_depth
@@ -613,25 +627,23 @@ def test_roundtrip_u1_ybr(self):
         assert (256, 256, 3) == arr.shape
 
         # Test lossless
-        result = encode(arr, photometric_interpretation=PI.YBR_FULL)
+        result = encode_array(arr, photometric_interpretation=PI.YBR_FULL)
         out = decode(result)
         assert np.array_equal(arr, out)
 
         # Test lossy
-        result = encode(
+        result = encode_array(
             arr,
             photometric_interpretation=PI.YBR_FULL,
-            lossless=0,
             compression_ratios=[6, 4, 2, 1],
         )
         out = decode(result)
         assert np.allclose(out, arr, atol=2)
 
         # Test lossy
-        result = encode(
+        result = encode_array(
             arr,
             photometric_interpretation=PI.YBR_FULL,
-            lossless=0,
             compression_ratios=[80, 100, 150],
         )
         out = decode(result)
@@ -649,7 +661,7 @@ def test_roundtrip_i2_mono(self):
         assert (512, 512) == arr.shape
 
         # Test lossless
-        result = encode(
+        result = encode_array(
             arr,
             photometric_interpretation=PI.MONOCHROME2,
         )
@@ -657,7 +669,7 @@ def test_roundtrip_i2_mono(self):
         assert np.array_equal(arr, out)
 
         # Test lossy w/ compression ratios
-        result = encode(
+        result = encode_array(
             arr,
             photometric_interpretation=PI.MONOCHROME2,
             compression_ratios=[6, 4, 2, 1],
@@ -666,7 +678,7 @@ def test_roundtrip_i2_mono(self):
         assert np.allclose(out, arr, atol=2)
 
         # Test lossy w/ signal-to-noise ratios
-        result = encode(
+        result = encode_array(
             arr,
             photometric_interpretation=PI.MONOCHROME2,
             signal_noise_ratios=[80, 100],
@@ -674,15 +686,1091 @@ def test_roundtrip_i2_mono(self):
         out = decode(result)
         assert np.allclose(out, arr, atol=2)
 
+    def test_jp2(self):
+        """Test using JP2 format"""
+        jpg = DIR_15444 / "HTJ2K" / "Bretagne1_ht.j2k"
+        with open(jpg, "rb") as f:
+            arr = decode(f.read())
 
-class TestEncodePixelData:
-    """Tests for encode_pixel_data()"""
+        buffer = encode_array(arr, codec_format=1)
+        assert buffer.startswith(b"\x00\x00\x00\x0c\x6a\x50\x20\x20\x0d\x0a\x87\x0a")
 
-    def test_nominal(self):
-        """Test the function works OK"""
-        arr = np.random.randint(0, high=65535, size=(100, 100), dtype="u2")
-        buffer = encode_pixel_data(arr)
-        assert np.array_equal(arr, decode(buffer))
+
+class TestEncodeBuffer:
+    """Tests for _openjpeg.encode_buffer"""
+
+    def test_invalid_type_raises(self):
+        """Test invalid buffer type raises."""
+        msg = "'src' must be bytes or bytearray, not list"
+        with pytest.raises(TypeError, match=msg):
+            encode_buffer([1, 2, 3], 1, 1, 1, 1, False)
+
+    def test_invalid_shape_raises(self):
+        """Test invalid image shape raises."""
+        msg = r"Invalid 'columns' value '0', must be in the range \[1, 65535\]"
+        with pytest.raises(ValueError, match=msg):
+            encode_buffer(b"", 0, 1, 1, 1, False)
+
+        msg = r"Invalid 'columns' value '65536', must be in the range \[1, 65535\]"
+        with pytest.raises(ValueError, match=msg):
+            encode_buffer(b"", 65536, 1, 1, 1, False)
+
+        msg = r"Invalid 'rows' value '0', must be in the range \[1, 65535\]"
+        with pytest.raises(ValueError, match=msg):
+            encode_buffer(b"", 1, 0, 1, 1, False)
+
+        msg = r"Invalid 'rows' value '65536', must be in the range \[1, 65535\]"
+        with pytest.raises(ValueError, match=msg):
+            encode_buffer(b"", 1, 65536, 1, 1, False)
+
+        msg = "Invalid 'samples_per_pixel' value '0', must be 1, 3 or 4"
+        with pytest.raises(ValueError, match=msg):
+            encode_buffer(b"", 1, 1, 0, 1, False)
+
+        msg = "Invalid 'samples_per_pixel' value '2', must be 1, 3 or 4"
+        with pytest.raises(ValueError, match=msg):
+            encode_buffer(b"", 1, 1, 2, 1, False)
+
+    def test_invalid_bits_stored_raises(self):
+        """Test invalid image pixel precision."""
+        msg = r"Invalid 'bits_stored' value '0', must be in the range \[1, 24\]"
+        with pytest.raises(ValueError, match=msg):
+            encode_buffer(b"", 1, 1, 1, 0, False)
+
+        msg = r"Invalid 'bits_stored' value '25', must be in the range \[1, 24\]"
+        with pytest.raises(ValueError, match=msg):
+            encode_buffer(b"", 1, 1, 1, 25, False)
+
+    def test_invalid_length_raises(self):
+        """Test mismatch between actual and expected src length"""
+        msg = (
+            "The length of 'src' is 2 bytes which doesn't match the expected "
+            "length of 1 bytes"
+        )
+        for bits_stored in range(1, 9):
+            with pytest.raises(ValueError, match=msg):
+                encode_buffer(b"\x00\x01", 1, 1, 1, bits_stored, False)
+
+        msg = (
+            "The length of 'src' is 3 bytes which doesn't match the expected "
+            "length of 2 bytes"
+        )
+        for bits_stored in range(9, 17):
+            with pytest.raises(ValueError, match=msg):
+                encode_buffer(b"\x00\x01\x02", 1, 1, 1, bits_stored, False)
+
+        msg = (
+            "The length of 'src' is 3 bytes which doesn't match the expected "
+            "length of 4 bytes"
+        )
+        for bits_stored in range(17, 25):
+            with pytest.raises(ValueError, match=msg):
+                encode_buffer(b"\x00\x01\x02", 1, 1, 1, bits_stored, False)
+
+    def test_invalid_photometric_interpretation_raises(self):
+        """Test invalid photometric interpretation"""
+        msg = (
+            "Invalid 'photometric_interpretation' value '6', must be in the "
+            r"range \[0, 5\]"
+        )
+        with pytest.raises(ValueError, match=msg):
+            encode_buffer(b"\x00", 1, 1, 1, 8, False, photometric_interpretation=6)
+
+    def test_compression_snr_raises(self):
+        """Test using compression_ratios and signal_noise_ratios raises."""
+        msg = (
+            "Only one of 'compression_ratios' or 'signal_noise_ratios' is "
+            "allowed when performing lossy compression"
+        )
+        with pytest.raises(ValueError, match=msg):
+            encode_buffer(
+                b"\x00",
+                1,
+                1,
+                1,
+                8,
+                False,
+                compression_ratios=[2, 1],
+                signal_noise_ratios=[1, 2],
+            )
+
+    def test_invalid_compression_ratios_raises(self):
+        """Test an invalid 'compression_ratios' raises exceptions."""
+        msg = "More than 10 compression layers is not supported"
+        with pytest.raises(ValueError, match=msg):
+            encode_buffer(b"\x00", 1, 1, 1, 8, False, compression_ratios=[1] * 11)
+
+        msg = (
+            "Error encoding the data: invalid compression ratio, lowest value "
+            "must be at least 1"
+        )
+        with pytest.raises(RuntimeError, match=msg):
+            encode_buffer(b"\x00", 1, 1, 1, 8, False, compression_ratios=[0])
+
+    def test_invalid_signal_noise_ratios_raises(self):
+        """Test an invalid 'signal_noise_ratios' raises exceptions."""
+        msg = "More than 10 compression layers is not supported"
+        with pytest.raises(ValueError, match=msg):
+            encode_buffer(b"\x00", 1, 1, 1, 8, False, signal_noise_ratios=[1] * 11)
+
+        msg = (
+            "Error encoding the data: invalid signal-to-noise ratio, lowest "
+            "value must be at least 0"
+        )
+        with pytest.raises(RuntimeError, match=msg):
+            encode_buffer(b"\x00", 1, 1, 1, 8, False, signal_noise_ratios=[-1])
+
+    def test_invalid_pi_for_samples_raises(self):
+        """Test invalid photometric interpretation values for nr of samples."""
+        msg = (
+            "Error encoding the data: the value of the 'photometric_interpretation' "
+            "parameter is not valid for the number of samples per pixel"
+        )
+        with pytest.raises(RuntimeError, match=msg):
+            encode_buffer(b"\x00\x01", 1, 2, 1, 8, False, photometric_interpretation=1)
+
+        with pytest.raises(RuntimeError, match=msg):
+            encode_buffer(
+                b"\x00\x01\x02", 1, 1, 3, 8, False, photometric_interpretation=2
+            )
+
+        with pytest.raises(RuntimeError, match=msg):
+            encode_buffer(
+                b"\x00\x01\x02\x03", 1, 1, 4, 8, False, photometric_interpretation=2
+            )
+
+    def test_encoding_failures_raise(self):
+        """Miscellaneous test to check that failures are handled properly."""
+        # Not exhaustive!
+        # Input too small
+        msg = r"Error encoding the data: failure result from 'opj_start_compress\(\)'"
+        with pytest.raises(RuntimeError, match=msg):
+            encode_buffer(b"\x00\x01", 1, 2, 1, 8, False)
+
+    def test_mct(self):
+        """Test that MCT is applied as required."""
+        # Should only be applied with RGB
+        arr = np.random.randint(0, 2**8 - 1, size=(100, 100, 3), dtype="u1")
+        buffer = encode_buffer(
+            arr.tobytes(),
+            100,
+            100,
+            3,
+            8,
+            False,
+            photometric_interpretation=PI.RGB,
+            use_mct=True,
+        )
+        param = parse_j2k(buffer)
+        assert param["mct"] is True
+
+        buffer = encode_buffer(
+            arr.tobytes(),
+            100,
+            100,
+            3,
+            8,
+            False,
+            photometric_interpretation=PI.RGB,
+            use_mct=True,
+            compression_ratios=[2.5, 3, 5],
+        )
+        param = parse_j2k(buffer)
+        assert param["mct"] is True
+
+        buffer = encode_buffer(
+            arr.tobytes(),
+            100,
+            100,
+            3,
+            8,
+            False,
+            photometric_interpretation=PI.RGB,
+            use_mct=False,
+        )
+        param = parse_j2k(buffer)
+        assert param["mct"] is False
+
+        buffer = encode_buffer(
+            arr.tobytes(),
+            100,
+            100,
+            3,
+            8,
+            False,
+            photometric_interpretation=PI.RGB,
+            use_mct=False,
+            compression_ratios=[2.5, 3, 5],
+        )
+        param = parse_j2k(buffer)
+        assert param["mct"] is False
+
+        for pi in (0, 3, 4):
+            buffer = encode_buffer(
+                arr.tobytes(),
+                100,
+                100,
+                3,
+                8,
+                False,
+                photometric_interpretation=pi,
+                use_mct=True,
+            )
+            param = parse_j2k(buffer)
+            assert param["mct"] is False
+
+            buffer = encode_buffer(
+                arr.tobytes(),
+                100,
+                100,
+                3,
+                8,
+                False,
+                photometric_interpretation=pi,
+                use_mct=True,
+                compression_ratios=[2.5, 3, 5],
+            )
+            param = parse_j2k(buffer)
+            assert param["mct"] is False
+
+        arr = np.random.randint(0, 2**8 - 1, size=(100, 100), dtype="u1")
+        buffer = encode_buffer(
+            arr.tobytes(),
+            100,
+            100,
+            1,
+            8,
+            False,
+            photometric_interpretation=PI.MONOCHROME1,
+            use_mct=True,
+        )
+        param = parse_j2k(buffer)
+        assert param["mct"] is False
+
+        buffer = encode_buffer(
+            arr.tobytes(),
+            100,
+            100,
+            1,
+            8,
+            False,
+            photometric_interpretation=PI.MONOCHROME1,
+            use_mct=True,
+            compression_ratios=[2.5, 3, 5],
+        )
+        param = parse_j2k(buffer)
+        assert param["mct"] is False
+
+        arr = np.random.randint(0, 2**8 - 1, size=(100, 100, 4), dtype="u1")
+        buffer = encode_buffer(
+            arr.tobytes(),
+            100,
+            100,
+            4,
+            8,
+            False,
+            photometric_interpretation=5,
+            use_mct=True,
+        )
+        param = parse_j2k(buffer)
+        assert param["mct"] is False
+
+        buffer = encode_buffer(
+            arr.tobytes(),
+            100,
+            100,
+            4,
+            8,
+            False,
+            photometric_interpretation=5,
+            use_mct=True,
+            compression_ratios=[2.5, 3, 5],
+        )
+        param = parse_j2k(buffer)
+        assert param["mct"] is False
+
+    def test_lossless_bool(self):
+        """Test encoding bool data for bit-depth 1"""
+        # Convert one of the test images to 1-bit
+        # Note that as of OpenJpeg v2.5.0 that random 1-bit images are prone
+        #   to encoding failures
+        jpg = DIR_15444 / "HTJ2K" / "Bretagne1_ht.j2k"
+        with open(jpg, "rb") as f:
+            data = f.read()
+
+        arr = decode(data)
+        assert "uint8" == arr.dtype
+        assert (480, 640, 3) == arr.shape
+
+        mono = arr[..., 0]
+        mono[mono <= 127] = 0
+        mono[mono > 127] = 1
+        mono = mono.astype("bool")
+        assert mono.min() == 0
+        assert mono.max() == 1
+
+        buffer = encode_buffer(
+            mono.tobytes(),
+            640,
+            480,
+            1,
+            1,
+            False,
+            photometric_interpretation=PI.MONOCHROME2,
+        )
+        out = decode(buffer)
+        param = parse_j2k(buffer)
+        assert param["precision"] == 1
+        assert param["is_signed"] is False
+        assert param["layers"] == 1
+        assert param["components"] == 1
+
+        assert out.dtype.kind == "u"
+        assert np.array_equal(mono, out)
+
+        arr[arr <= 127] = 0
+        arr[arr > 127] = 1
+        arr = arr.astype("bool")
+
+        buffer = encode_buffer(
+            arr.tobytes(),
+            640,
+            480,
+            3,
+            1,
+            False,
+            photometric_interpretation=PI.RGB,
+        )
+        out = decode(buffer)
+        param = parse_j2k(buffer)
+        assert param["precision"] == 1
+        assert param["is_signed"] is False
+        assert param["layers"] == 1
+        assert param["components"] == 3
+
+        assert out.dtype.kind == "u"
+        assert np.array_equal(arr, out)
+
+    def test_lossless_unsigned_u1(self):
+        """Test encoding unsigned data for bit-depth 1-8"""
+        rows = 123
+        cols = 234
+        for bit_depth in range(2, 9):
+            maximum = 2**bit_depth - 1
+            arr = np.random.randint(0, high=maximum + 1, size=(rows, cols), dtype="u1")
+            buffer = encode_buffer(
+                arr.tobytes(),
+                cols,
+                rows,
+                1,
+                bit_depth,
+                False,
+                photometric_interpretation=PI.MONOCHROME2,
+            )
+            out = decode(buffer)
+            param = parse_j2k(buffer)
+            assert param["precision"] == bit_depth
+            assert param["is_signed"] is False
+            assert param["layers"] == 1
+            assert param["components"] == 1
+
+            assert out.dtype.kind == "u"
+            assert np.array_equal(arr, out)
+
+            arr = np.random.randint(
+                0, high=maximum + 1, size=(rows, cols, 3), dtype="u1"
+            )
+            buffer = encode_buffer(
+                arr.tobytes(),
+                cols,
+                rows,
+                3,
+                bit_depth,
+                False,
+                photometric_interpretation=PI.RGB,
+                use_mct=False,
+            )
+            out = decode(buffer)
+            param = parse_j2k(buffer)
+            assert param["precision"] == bit_depth
+            assert param["is_signed"] is False
+            assert param["layers"] == 1
+            assert param["components"] == 3
+
+            assert out.dtype.kind == "u"
+            assert np.array_equal(arr, out)
+
+            arr = np.random.randint(
+                0, high=maximum + 1, size=(rows, cols, 4), dtype="u1"
+            )
+            buffer = encode_buffer(
+                arr.tobytes(),
+                cols,
+                rows,
+                4,
+                bit_depth,
+                False,
+                photometric_interpretation=5,
+                use_mct=False,
+            )
+            out = decode(buffer)
+            param = parse_j2k(buffer)
+            assert param["precision"] == bit_depth
+            assert param["is_signed"] is False
+            assert param["layers"] == 1
+            assert param["components"] == 4
+
+            assert out.dtype.kind == "u"
+            assert np.array_equal(arr, out)
+
+    def test_lossless_unsigned_u2(self):
+        """Test encoding unsigned data for bit-depth 9-16"""
+        rows = 123
+        cols = 234
+        for bit_depth in range(9, 17):
+            maximum = 2**bit_depth - 1
+            arr = np.random.randint(0, high=maximum + 1, size=(rows, cols), dtype="u2")
+            buffer = encode_buffer(
+                arr.tobytes(),
+                cols,
+                rows,
+                1,
+                bit_depth,
+                False,
+                photometric_interpretation=PI.MONOCHROME2,
+            )
+            out = decode(buffer)
+            param = parse_j2k(buffer)
+            assert param["precision"] == bit_depth
+            assert param["is_signed"] is False
+            assert param["layers"] == 1
+            assert param["components"] == 1
+
+            assert out.dtype.kind == "u"
+            assert np.array_equal(arr, out)
+
+            arr = np.random.randint(
+                0, high=maximum + 1, size=(rows, cols, 3), dtype="u2"
+            )
+            buffer = encode_buffer(
+                arr.tobytes(),
+                cols,
+                rows,
+                3,
+                bit_depth,
+                False,
+                photometric_interpretation=PI.RGB,
+                use_mct=False,
+            )
+            out = decode(buffer)
+            param = parse_j2k(buffer)
+            assert param["precision"] == bit_depth
+            assert param["is_signed"] is False
+            assert param["layers"] == 1
+            assert param["components"] == 3
+
+            assert out.dtype.kind == "u"
+            assert np.array_equal(arr, out)
+
+            arr = np.random.randint(
+                0, high=maximum + 1, size=(rows, cols, 4), dtype="u2"
+            )
+            buffer = encode_buffer(
+                arr.tobytes(),
+                cols,
+                rows,
+                4,
+                bit_depth,
+                False,
+                photometric_interpretation=5,
+                use_mct=False,
+            )
+            out = decode(buffer)
+            param = parse_j2k(buffer)
+            assert param["precision"] == bit_depth
+            assert param["is_signed"] is False
+            assert param["layers"] == 1
+            assert param["components"] == 4
+
+            assert out.dtype.kind == "u"
+            assert np.array_equal(arr, out)
+
+    def test_lossless_unsigned_u4(self):
+        """Test encoding unsigned data for bit-depth 17-24"""
+        rows = 123
+        cols = 234
+        planes = 3
+        for bit_depth in range(17, 25):
+            maximum = 2**bit_depth - 1
+            arr = np.random.randint(0, high=maximum + 1, size=(rows, cols), dtype="u4")
+            buffer = encode_buffer(
+                arr.tobytes(),
+                cols,
+                rows,
+                1,
+                bit_depth,
+                False,
+                photometric_interpretation=PI.MONOCHROME2,
+            )
+            out = decode(buffer)
+
+            param = parse_j2k(buffer)
+            assert param["precision"] == bit_depth
+            assert param["is_signed"] is False
+            assert param["layers"] == 1
+            assert param["components"] == 1
+
+            assert out.dtype.kind == "u"
+            assert np.array_equal(arr, out)
+
+            arr = np.random.randint(
+                0, high=maximum + 1, size=(rows, cols, planes), dtype="u4"
+            )
+            buffer = encode_buffer(
+                arr.tobytes(),
+                cols,
+                rows,
+                3,
+                bit_depth,
+                False,
+                photometric_interpretation=PI.RGB,
+                use_mct=False,
+            )
+            out = decode(buffer)
+
+            param = parse_j2k(buffer)
+            assert param["precision"] == bit_depth
+            assert param["is_signed"] is False
+            assert param["layers"] == 1
+            assert param["components"] == 3
+
+            assert out.dtype.kind == "u"
+            assert np.array_equal(arr, out)
+
+    def test_lossless_signed_i1(self):
+        """Test encoding signed data for bit-depth 1-8"""
+        rows = 123
+        cols = 543
+        for bit_depth in range(2, 9):
+            maximum = 2 ** (bit_depth - 1) - 1
+            minimum = -(2 ** (bit_depth - 1))
+            arr = np.random.randint(
+                low=minimum, high=maximum + 1, size=(rows, cols), dtype="i1"
+            )
+            buffer = encode_buffer(
+                arr.tobytes(),
+                cols,
+                rows,
+                1,
+                bit_depth,
+                True,
+                photometric_interpretation=PI.MONOCHROME2,
+            )
+            out = decode(buffer)
+
+            param = parse_j2k(buffer)
+            assert param["precision"] == bit_depth
+            assert param["is_signed"] is True
+            assert param["layers"] == 1
+            assert param["components"] == 1
+
+            assert out.dtype.kind == "i"
+            assert np.array_equal(arr, out)
+
+            maximum = 2 ** (bit_depth - 1) - 1
+            minimum = -(2 ** (bit_depth - 1))
+            arr = np.random.randint(
+                low=minimum, high=maximum + 1, size=(rows, cols, 3), dtype="i1"
+            )
+            buffer = encode_buffer(
+                arr.tobytes(),
+                cols,
+                rows,
+                3,
+                bit_depth,
+                True,
+                photometric_interpretation=PI.RGB,
+                use_mct=False,
+            )
+            out = decode(buffer)
+
+            param = parse_j2k(buffer)
+            assert param["precision"] == bit_depth
+            assert param["is_signed"] is True
+            assert param["layers"] == 1
+            assert param["components"] == 3
+
+            assert out.dtype.kind == "i"
+            assert np.array_equal(arr, out)
+
+            arr = np.random.randint(
+                low=minimum, high=maximum + 1, size=(rows, cols, 4), dtype="i1"
+            )
+            buffer = encode_buffer(
+                arr.tobytes(),
+                cols,
+                rows,
+                4,
+                bit_depth,
+                True,
+                photometric_interpretation=5,
+                use_mct=False,
+            )
+            out = decode(buffer)
+
+            param = parse_j2k(buffer)
+            assert param["precision"] == bit_depth
+            assert param["is_signed"] is True
+            assert param["layers"] == 1
+            assert param["components"] == 4
+
+            assert out.dtype.kind == "i"
+            assert np.array_equal(arr, out)
+
+    def test_lossless_signed_i2(self):
+        """Test encoding signed data for bit-depth 9-16"""
+        rows = 123
+        cols = 543
+        for bit_depth in range(9, 17):
+            maximum = 2 ** (bit_depth - 1) - 1
+            minimum = -(2 ** (bit_depth - 1))
+            arr = np.random.randint(
+                low=minimum, high=maximum + 1, size=(rows, cols), dtype="i2"
+            )
+            buffer = encode_buffer(
+                arr.tobytes(),
+                cols,
+                rows,
+                1,
+                bit_depth,
+                True,
+                photometric_interpretation=PI.MONOCHROME2,
+            )
+            out = decode(buffer)
+
+            param = parse_j2k(buffer)
+            assert param["precision"] == bit_depth
+            assert param["is_signed"] is True
+            assert param["layers"] == 1
+            assert param["components"] == 1
+
+            assert out.dtype.kind == "i"
+            assert np.array_equal(arr, out)
+
+            maximum = 2 ** (bit_depth - 1) - 1
+            minimum = -(2 ** (bit_depth - 1))
+            arr = np.random.randint(
+                low=minimum, high=maximum + 1, size=(rows, cols, 3), dtype="i2"
+            )
+            buffer = encode_buffer(
+                arr.tobytes(),
+                cols,
+                rows,
+                3,
+                bit_depth,
+                True,
+                photometric_interpretation=PI.RGB,
+                use_mct=False,
+            )
+            out = decode(buffer)
+
+            param = parse_j2k(buffer)
+            assert param["precision"] == bit_depth
+            assert param["is_signed"] is True
+            assert param["layers"] == 1
+            assert param["components"] == 3
+
+            assert out.dtype.kind == "i"
+            assert np.array_equal(arr, out)
+
+            arr = np.random.randint(
+                low=minimum, high=maximum + 1, size=(rows, cols, 4), dtype="i2"
+            )
+            buffer = encode_buffer(
+                arr.tobytes(),
+                cols,
+                rows,
+                4,
+                bit_depth,
+                True,
+                photometric_interpretation=5,
+                use_mct=False,
+            )
+            out = decode(buffer)
+
+            param = parse_j2k(buffer)
+            assert param["precision"] == bit_depth
+            assert param["is_signed"] is True
+            assert param["layers"] == 1
+            assert param["components"] == 4
+
+            assert out.dtype.kind == "i"
+            assert np.array_equal(arr, out)
+
+    def test_lossless_signed_i4(self):
+        """Test encoding signed data for bit-depth 17-24"""
+        rows = 123
+        cols = 234
+        planes = 3
+        for bit_depth in range(17, 25):
+            maximum = 2 ** (bit_depth - 1) - 1
+            minimum = -(2 ** (bit_depth - 1))
+            arr = np.random.randint(
+                low=minimum, high=maximum + 1, size=(rows, cols), dtype="i4"
+            )
+            buffer = encode_buffer(
+                arr.tobytes(),
+                cols,
+                rows,
+                1,
+                bit_depth,
+                True,
+                photometric_interpretation=PI.MONOCHROME2,
+            )
+            out = decode(buffer)
+
+            param = parse_j2k(buffer)
+            assert param["precision"] == bit_depth
+            assert param["is_signed"] is True
+            assert param["layers"] == 1
+            assert param["components"] == 1
+
+            assert out.dtype.kind == "i"
+            assert np.array_equal(arr, out)
+
+            arr = np.random.randint(
+                low=minimum, high=maximum + 1, size=(rows, cols, planes), dtype="i4"
+            )
+            buffer = encode_buffer(
+                arr.tobytes(),
+                cols,
+                rows,
+                3,
+                bit_depth,
+                True,
+                photometric_interpretation=PI.RGB,
+                use_mct=False,
+            )
+            out = decode(buffer)
+
+            param = parse_j2k(buffer)
+            assert param["precision"] == bit_depth
+            assert param["is_signed"] is True
+            assert param["layers"] == 1
+            assert param["components"] == 3
+
+            assert out.dtype.kind == "i"
+            assert np.array_equal(arr, out)
+
+    def test_lossy_unsigned(self):
+        """Test lossy encoding with unsigned data"""
+        rows = 123
+        cols = 234
+        for bit_depth in range(2, 17):
+            maximum = 2**bit_depth - 1
+            dtype = f"u{math.ceil(bit_depth / 8)}"
+            arr = np.random.randint(0, high=maximum + 1, size=(rows, cols), dtype=dtype)
+            buffer = encode_buffer(
+                arr.tobytes(),
+                cols,
+                rows,
+                1,
+                bit_depth,
+                False,
+                compression_ratios=[4, 2, 1],
+            )
+            out = decode(buffer)
+            param = parse_j2k(buffer)
+            assert param["precision"] == bit_depth
+            assert param["is_signed"] is False
+            assert param["layers"] == 3
+            assert param["components"] == 1
+
+            assert out.dtype.kind == "u"
+            assert np.allclose(arr, out, atol=5)
+
+            buffer = encode_buffer(
+                arr.tobytes(),
+                cols,
+                rows,
+                1,
+                bit_depth,
+                False,
+                signal_noise_ratios=[50, 100, 200],
+            )
+            out = decode(buffer)
+            param = parse_j2k(buffer)
+            assert param["precision"] == bit_depth
+            assert param["is_signed"] is False
+            assert param["layers"] == 3
+            assert param["components"] == 1
+
+            assert out.dtype.kind == "u"
+            assert np.allclose(arr, out, atol=5)
+
+    def test_lossy_signed(self):
+        """Test lossy encoding with unsigned data"""
+        rows = 123
+        cols = 234
+        for bit_depth in range(2, 17):
+            maximum = 2 ** (bit_depth - 1) - 1
+            minimum = -(2 ** (bit_depth - 1))
+            dtype = f"i{math.ceil(bit_depth / 8)}"
+            arr = np.random.randint(
+                low=minimum, high=maximum + 1, size=(rows, cols), dtype=dtype
+            )
+            buffer = encode_buffer(
+                arr.tobytes(),
+                cols,
+                rows,
+                1,
+                bit_depth,
+                True,
+                compression_ratios=[4, 2, 1],
+            )
+            out = decode(buffer)
+            param = parse_j2k(buffer)
+            assert param["precision"] == bit_depth
+            assert param["is_signed"] is True
+            assert param["layers"] == 3
+            assert param["components"] == 1
+
+            assert out.dtype.kind == "i"
+            assert np.allclose(arr, out, atol=5)
+
+            buffer = encode_buffer(
+                arr.tobytes(),
+                cols,
+                rows,
+                1,
+                bit_depth,
+                True,
+                signal_noise_ratios=[50, 100, 200],
+            )
+            out = decode(buffer)
+            param = parse_j2k(buffer)
+            assert param["precision"] == bit_depth
+            assert param["is_signed"] is True
+            assert param["layers"] == 3
+            assert param["components"] == 1
+
+            assert out.dtype.kind == "i"
+            assert np.allclose(arr, out, atol=5)
+
+    def test_roundtrip_u1_ybr(self):
+        """Test a round trip for u1 YBR."""
+        jpg = DIR_15444 / "2KLS" / "oj36.j2k"
+        with open(jpg, "rb") as f:
+            data = f.read()
+
+        arr = decode(data)
+        assert "uint8" == arr.dtype
+        assert (256, 256, 3) == arr.shape
+
+        # Test lossless
+        result = encode_buffer(
+            arr.tobytes(),
+            256,
+            256,
+            3,
+            8,
+            False,
+            photometric_interpretation=PI.YBR_FULL,
+        )
+        out = decode(result)
+        assert np.array_equal(arr, out)
+
+        # Test lossy
+        result = encode_buffer(
+            arr.tobytes(),
+            256,
+            256,
+            3,
+            8,
+            False,
+            photometric_interpretation=PI.YBR_FULL,
+            compression_ratios=[6, 4, 2, 1],
+        )
+        out = decode(result)
+        assert np.allclose(out, arr, atol=2)
+
+        # Test lossy
+        result = encode_buffer(
+            arr.tobytes(),
+            256,
+            256,
+            3,
+            8,
+            False,
+            photometric_interpretation=PI.YBR_FULL,
+            compression_ratios=[80, 100, 150],
+        )
+        out = decode(result)
+        assert np.allclose(out, arr, atol=2)
+
+    def test_roundtrip_i2_mono(self):
+        """Test a round trip for i2 YBR."""
+
+        jpg = DIR_15444 / "2KLS" / "693.j2k"
+        with open(jpg, "rb") as f:
+            data = f.read()
+
+        arr = decode(data)
+        assert "i2" == arr.dtype
+        assert (512, 512) == arr.shape
+
+        # Test lossless
+        result = encode_buffer(
+            arr.tobytes(),
+            512,
+            512,
+            1,
+            14,
+            True,
+            photometric_interpretation=PI.MONOCHROME2,
+        )
+        out = decode(result)
+        assert np.array_equal(arr, out)
+
+        # Test lossy w/ compression ratios
+        result = encode_buffer(
+            arr.tobytes(),
+            512,
+            512,
+            1,
+            14,
+            True,
+            photometric_interpretation=PI.MONOCHROME2,
+            compression_ratios=[6, 4, 2, 1],
+        )
+        out = decode(result)
+        assert np.allclose(out, arr, atol=2)
+
+        # Test lossy w/ signal-to-noise ratios
+        result = encode_buffer(
+            arr.tobytes(),
+            512,
+            512,
+            1,
+            14,
+            True,
+            photometric_interpretation=PI.MONOCHROME2,
+            signal_noise_ratios=[80, 100],
+        )
+        out = decode(result)
+        assert np.allclose(out, arr, atol=2)
+
+    def test_jp2(self):
+        """Test using JP2 format"""
+        jpg = DIR_15444 / "HTJ2K" / "Bretagne1_ht.j2k"
+        with open(jpg, "rb") as f:
+            arr = decode(f.read())
+
+        kwargs = {
+            "rows": 480,
+            "columns": 640,
+            "samples_per_pixel": 3,
+            "pixel_representation": 0,
+            "is_signed": False,
+            "bits_stored": 8,
+            "codec_format": 1,
+        }
+
+        buffer = encode_buffer(arr.tobytes(), **kwargs)
+        assert buffer.startswith(b"\x00\x00\x00\x0c\x6a\x50\x20\x20\x0d\x0a\x87\x0a")
+
+
+class TestEncodePixelData:
+    """Tests for encode_pixel_data()"""
+
+    def test_nominal(self):
+        """Test the function works OK"""
+        jpg = DIR_15444 / "HTJ2K" / "Bretagne1_ht.j2k"
+        with open(jpg, "rb") as f:
+            arr = decode(f.read())
+
+        kwargs = {
+            "rows": 480,
+            "columns": 640,
+            "samples_per_pixel": 3,
+            "pixel_representation": 0,
+            "bits_stored": 8,
+            "photometric_interpretation": "RGB",
+        }
+        buffer = encode_pixel_data(arr.tobytes(), **kwargs)
+        assert np.array_equal(arr, decode(buffer))
+
+    def test_photometric_interpretation(self):
+        """Check photometric interpretation sets MCT correctly."""
+        jpg = DIR_15444 / "HTJ2K" / "Bretagne1_ht.j2k"
+        with open(jpg, "rb") as f:
+            arr = decode(f.read())
+
+        kwargs = {
+            "rows": 480,
+            "columns": 640,
+            "samples_per_pixel": 3,
+            "pixel_representation": 0,
+            "bits_stored": 8,
+        }
+        for pi in ("RGB", "YBR_ICT", "YBR_RCT"):
+            buffer = encode_pixel_data(
+                arr.tobytes(),
+                photometric_interpretation=pi,
+                **kwargs,
+            )
+            param = parse_j2k(buffer)
+            assert param["mct"] is True
+
+        buffer = encode_pixel_data(
+            arr.tobytes(),
+            photometric_interpretation="YBR_FULL",
+            use_mct=True,
+            **kwargs,
+        )
+        param = parse_j2k(buffer)
+        assert param["mct"] is False
+
+    def test_codec_format_ignored(self):
+        """Test that codec_format gets ignored."""
+        jpg = DIR_15444 / "HTJ2K" / "Bretagne1_ht.j2k"
+        with open(jpg, "rb") as f:
+            arr = decode(f.read())
+
+        kwargs = {
+            "rows": 480,
+            "columns": 640,
+            "samples_per_pixel": 3,
+            "pixel_representation": 0,
+            "photometric_interpretation": "RGB",
+            "bits_stored": 8,
+            "codec_format": 1,
+        }
+        buffer = encode_pixel_data(arr.tobytes(), **kwargs)
+        assert buffer.startswith(b"\xff\x4f\xff\x51")
+
+    def test_pixel_representation(self):
+        """Test pixel representation is applied correctly."""
+        jpg = DIR_15444 / "HTJ2K" / "Bretagne1_ht.j2k"
+        with open(jpg, "rb") as f:
+            arr = decode(f.read())
+
+        kwargs = {
+            "rows": 480,
+            "columns": 640,
+            "samples_per_pixel": 3,
+            "pixel_representation": 0,
+            "photometric_interpretation": "RGB",
+            "bits_stored": 8,
+        }
+        buffer = encode_pixel_data(arr.tobytes(), **kwargs)
+        info = parse_j2k(buffer)
+        assert info["is_signed"] is False
+
+        kwargs["pixel_representation"] = 1
+        buffer = encode_pixel_data(arr.tobytes(), **kwargs)
+        info = parse_j2k(buffer)
+        assert info["is_signed"] is True
 
 
 class TestGetBitsStored:
diff --git a/openjpeg/tests/test_parameters.py b/openjpeg/tests/test_parameters.py
index 1549b29..b7a2dc4 100644
--- a/openjpeg/tests/test_parameters.py
+++ b/openjpeg/tests/test_parameters.py
@@ -71,7 +71,7 @@ def test_subsampling():
     assert params["rows"] == 256
     assert params["columns"] == 256
     assert params["colourspace"] == "unspecified"
-    assert params["nr_components"] == 3
+    assert params["samples_per_pixel"] == 3
     assert params["precision"] == 8
     assert params["is_signed"] is False
     assert params["nr_tiles"] == 0
@@ -91,7 +91,7 @@ def test_jpeg2000r(self, fname, info):
         params = get_parameters(frame)
 
         assert (info[0], info[1]) == (params["rows"], params["columns"])
-        assert info[2] == params["nr_components"]
+        assert info[2] == params["samples_per_pixel"]
         assert info[3] == params["precision"]
         assert info[4] == params["is_signed"]
 
@@ -105,7 +105,7 @@ def test_jpeg2000i(self, fname, info):
         params = get_parameters(frame)
 
         assert (info[0], info[1]) == (params["rows"], params["columns"])
-        assert info[2] == params["nr_components"]
+        assert info[2] == params["samples_per_pixel"]
         assert info[3] == params["precision"]
         assert info[4] == params["is_signed"]