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

Issue:
Don't include source in wheel builds 
Try and figure out how to not include the C++ source files with the wheel builds ([see also](https://twitter.com/eborisch/status/1324014037206708226)).


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/release-wheels.yml b/.github/workflows/release-wheels.yml
index e4511f9..bb7313c 100644
--- a/.github/workflows/release-wheels.yml
+++ b/.github/workflows/release-wheels.yml
@@ -31,7 +31,7 @@ jobs:
     - name: Store artifacts
       uses: actions/upload-artifact@v4
       with:
-        name: wheels
+        name: sdist
         path: ./dist
 
   build-wheels:
@@ -184,7 +184,7 @@ jobs:
     - name: Store artifacts
       uses: actions/upload-artifact@v4
       with:
-        name: wheels
+        name: wheel-${{ matrix.python }}-${{ matrix.platform_id }}
         path: ./dist
 
   test-package:
@@ -206,8 +206,8 @@ jobs:
     - name: Download the wheels
       uses: actions/download-artifact@v4
       with:
-        name: wheels
         path: dist/
+        merge-multiple: true
 
     - name: Install from package wheels and test
       # If testing wheel builds might need --pre to install dev version
diff --git a/.gitignore b/.gitignore
index 98f89ab..f24d096 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,7 +14,6 @@ dist/
 downloads/
 eggs/
 .eggs/
-lib/
 lib64/
 parts/
 sdist/
@@ -56,7 +55,7 @@ coverage.xml
 *.pot
 
 # Django stuff:
-*.log
+#*.log
 local_settings.py
 db.sqlite3
 db.sqlite3-journal
diff --git a/.gitmodules b/.gitmodules
index 1fc0398..2e98c2d 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,3 @@
 [submodule "libjpeg/src/libjpeg"]
-	path = libjpeg/src/libjpeg
+	path = lib/libjpeg
 	url = https://github.com/thorfdbg/libjpeg.git
diff --git a/build.py b/build.py
index af17ec2..655624e 100644
--- a/build.py
+++ b/build.py
@@ -9,8 +9,9 @@
 
 
 PACKAGE_DIR = Path(__file__).parent / "libjpeg"
-LIBJPEG_SRC = PACKAGE_DIR / 'src' / 'libjpeg'
-INTERFACE_SRC = PACKAGE_DIR / 'src' / 'interface'
+LIB_DIR = Path(__file__).parent / "lib"
+LIBJPEG_SRC = LIB_DIR / 'libjpeg'
+INTERFACE_SRC = LIB_DIR / 'interface'
 
 
 def build(setup_kwargs: Any) -> Any:
diff --git a/libjpeg/src/interface/decode.cpp b/lib/interface/decode.cpp
similarity index 98%
rename from libjpeg/src/interface/decode.cpp
rename to lib/interface/decode.cpp
index 6b90d14..f197207 100644
--- a/libjpeg/src/interface/decode.cpp
+++ b/lib/interface/decode.cpp
@@ -18,8 +18,13 @@
 #include "../libjpeg/interface/jpeg.hpp"
 
 
-std::string Decode(char *inArray, char *outArray, int inLength, int outLength, int colourTransform)
-{
+std::string Decode(
+    char *inArray,
+    char *outArray,
+    int inLength,
+    int outLength,
+    int colourTransform
+) {
     /*
 
     Parameters
@@ -254,8 +259,11 @@ std::string Decode(char *inArray, char *outArray, int inLength, int outLength, i
 }
 
 
-std::string GetJPEGParameters(char *inArray, int inLength, struct JPEGParameters *param)
-{
+std::string GetJPEGParameters(
+    char *inArray,
+    int inLength,
+    struct JPEGParameters *param
+) {
     /*
 
     Parameters
diff --git a/libjpeg/src/interface/decode.hpp b/lib/interface/decode.hpp
similarity index 93%
rename from libjpeg/src/interface/decode.hpp
rename to lib/interface/decode.hpp
index 936a0aa..749ea57 100644
--- a/libjpeg/src/interface/decode.hpp
+++ b/lib/interface/decode.hpp
@@ -18,7 +18,9 @@
 
     // Return the parameters of the encoded JPEG file in `inArray`
     extern std::string GetJPEGParameters(
-        char *inArray, int inLength, struct JPEGParameters *param
+        char *inArray,
+        int inLength,
+        struct JPEGParameters *param
     );
 
     struct StreamData {
diff --git a/libjpeg/src/interface/streamhook.cpp b/lib/interface/streamhook.cpp
similarity index 98%
rename from libjpeg/src/interface/streamhook.cpp
rename to lib/interface/streamhook.cpp
index f8fb0aa..9f993e8 100644
--- a/libjpeg/src/interface/streamhook.cpp
+++ b/lib/interface/streamhook.cpp
@@ -51,8 +51,8 @@ JPG_LONG IStreamHook(struct JPG_Hook *hook, struct JPG_TagItem *tags)
         }
         case JPGFLAG_ACTION_WRITE:
         {
-            UBYTE *buffer = (UBYTE *)tags->GetTagPtr(JPGTAG_FIO_BUFFER);
-            ULONG  size   = (ULONG  )tags->GetTagData(JPGTAG_FIO_SIZE);
+            // UBYTE *buffer = (UBYTE *)tags->GetTagPtr(JPGTAG_FIO_BUFFER);
+            // ULONG  size   = (ULONG  )tags->GetTagData(JPGTAG_FIO_SIZE);
 
             // We want to raise an error so writing can be implemented
             return -1;
@@ -60,7 +60,7 @@ JPG_LONG IStreamHook(struct JPG_Hook *hook, struct JPG_TagItem *tags)
         case JPGFLAG_ACTION_SEEK:
         {
             LONG mode   = tags->GetTagData(JPGTAG_FIO_SEEKMODE);
-            LONG offset = tags->GetTagData(JPGTAG_FIO_OFFSET);
+            // LONG offset = tags->GetTagData(JPGTAG_FIO_OFFSET);
 
             // We want to raise an error here seek can be implemented
             switch(mode) {
diff --git a/libjpeg/src/interface/streamhook.hpp b/lib/interface/streamhook.hpp
similarity index 100%
rename from libjpeg/src/interface/streamhook.hpp
rename to lib/interface/streamhook.hpp
diff --git a/libjpeg/src/interface/utils.hpp b/lib/interface/utils.hpp
similarity index 100%
rename from libjpeg/src/interface/utils.hpp
rename to lib/interface/utils.hpp
diff --git a/lib/libjpeg b/lib/libjpeg
new file mode 160000
index 0000000..db33a6e
--- /dev/null
+++ b/lib/libjpeg
@@ -0,0 +1,1 @@
+Subproject commit db33a6ee2d034eea2c62fd3c5dcb6fa86746579f
diff --git a/libjpeg/_libjpeg.cpp b/libjpeg/_libjpeg.cpp
index 1ed39a6..f3f4600 100644
--- a/libjpeg/_libjpeg.cpp
+++ b/libjpeg/_libjpeg.cpp
@@ -4,13 +4,13 @@
 {
     "distutils": {
         "depends": [
-            "/home/dean/Coding/src/pylibjpeg-libjpeg/libjpeg/src/interface/decode.hpp",
-            "/home/dean/Coding/src/pylibjpeg-libjpeg/libjpeg/src/libjpeg/cmd/reconstruct.hpp",
-            "/tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/core/include/numpy/arrayobject.h",
-            "/tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/core/include/numpy/arrayscalars.h",
-            "/tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/core/include/numpy/ndarrayobject.h",
-            "/tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/core/include/numpy/ndarraytypes.h",
-            "/tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/core/include/numpy/ufuncobject.h"
+            "/home/dean/Coding/src/pylibjpeg-libjpeg/lib/interface/decode.hpp",
+            "/home/dean/Coding/src/pylibjpeg-libjpeg/lib/libjpeg/cmd/reconstruct.hpp",
+            "/tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/core/include/numpy/arrayobject.h",
+            "/tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/core/include/numpy/arrayscalars.h",
+            "/tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/core/include/numpy/ndarrayobject.h",
+            "/tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/core/include/numpy/ndarraytypes.h",
+            "/tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/core/include/numpy/ufuncobject.h"
         ],
         "extra_compile_args": [
             "-DUSE_AUTOCONF",
@@ -20,157 +20,157 @@
             "-lgcc_s"
         ],
         "include_dirs": [
-            "/home/dean/Coding/src/pylibjpeg-libjpeg/libjpeg/src/libjpeg",
-            "/home/dean/Coding/src/pylibjpeg-libjpeg/libjpeg/src/interface",
-            "/tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/core/include"
+            "/home/dean/Coding/src/pylibjpeg-libjpeg/lib/libjpeg",
+            "/home/dean/Coding/src/pylibjpeg-libjpeg/lib/interface",
+            "/tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/core/include"
         ],
         "language": "c++",
         "name": "_libjpeg",
         "sources": [
             "libjpeg/_libjpeg.pyx",
-            "libjpeg/src/interface/decode.cpp",
-            "libjpeg/src/interface/streamhook.cpp",
-            "libjpeg/src/libjpeg/colortrafo/lslosslesstrafo.cpp",
-            "libjpeg/src/libjpeg/colortrafo/integertrafo.cpp",
-            "libjpeg/src/libjpeg/colortrafo/floattrafo.cpp",
-            "libjpeg/src/libjpeg/colortrafo/colortrafo.cpp",
-            "libjpeg/src/libjpeg/colortrafo/trivialtrafo.cpp",
-            "libjpeg/src/libjpeg/colortrafo/multiplicationtrafo.cpp",
-            "libjpeg/src/libjpeg/colortrafo/colortransformerfactory.cpp",
-            "libjpeg/src/libjpeg/colortrafo/ycbcrtrafo.cpp",
-            "libjpeg/src/libjpeg/boxes/tonemapperbox.cpp",
-            "libjpeg/src/libjpeg/boxes/box.cpp",
-            "libjpeg/src/libjpeg/boxes/nonlineartrafobox.cpp",
-            "libjpeg/src/libjpeg/boxes/parametrictonemappingbox.cpp",
-            "libjpeg/src/libjpeg/boxes/databox.cpp",
-            "libjpeg/src/libjpeg/boxes/floattonemappingbox.cpp",
-            "libjpeg/src/libjpeg/boxes/filetypebox.cpp",
-            "libjpeg/src/libjpeg/boxes/outputconversionbox.cpp",
-            "libjpeg/src/libjpeg/boxes/refinementspecbox.cpp",
-            "libjpeg/src/libjpeg/boxes/alphabox.cpp",
-            "libjpeg/src/libjpeg/boxes/dctbox.cpp",
-            "libjpeg/src/libjpeg/boxes/colortrafobox.cpp",
-            "libjpeg/src/libjpeg/boxes/matrixbox.cpp",
-            "libjpeg/src/libjpeg/boxes/floattransformationbox.cpp",
-            "libjpeg/src/libjpeg/boxes/lineartransformationbox.cpp",
-            "libjpeg/src/libjpeg/boxes/superbox.cpp",
-            "libjpeg/src/libjpeg/boxes/inversetonemappingbox.cpp",
-            "libjpeg/src/libjpeg/boxes/mergingspecbox.cpp",
-            "libjpeg/src/libjpeg/boxes/namespace.cpp",
-            "libjpeg/src/libjpeg/boxes/checksumbox.cpp",
-            "libjpeg/src/libjpeg/tools/line.cpp",
-            "libjpeg/src/libjpeg/tools/debug.cpp",
-            "libjpeg/src/libjpeg/tools/numerics.cpp",
-            "libjpeg/src/libjpeg/tools/checksum.cpp",
-            "libjpeg/src/libjpeg/tools/environment.cpp",
-            "libjpeg/src/libjpeg/tools/traits.cpp",
-            "libjpeg/src/libjpeg/tools/priorityqueue.cpp",
-            "libjpeg/src/libjpeg/tools/rectangle.cpp",
-            "libjpeg/src/libjpeg/std/stddef.cpp",
-            "libjpeg/src/libjpeg/std/stdio.cpp",
-            "libjpeg/src/libjpeg/std/errno.cpp",
-            "libjpeg/src/libjpeg/std/math.cpp",
-            "libjpeg/src/libjpeg/std/stdlib.cpp",
-            "libjpeg/src/libjpeg/std/assert.cpp",
-            "libjpeg/src/libjpeg/std/stdarg.cpp",
-            "libjpeg/src/libjpeg/std/ctype.cpp",
-            "libjpeg/src/libjpeg/std/setjmp.cpp",
-            "libjpeg/src/libjpeg/std/string.cpp",
-            "libjpeg/src/libjpeg/std/unistd.cpp",
-            "libjpeg/src/libjpeg/codestream/rectanglerequest.cpp",
-            "libjpeg/src/libjpeg/codestream/encoder.cpp",
-            "libjpeg/src/libjpeg/codestream/decoder.cpp",
-            "libjpeg/src/libjpeg/codestream/predictor.cpp",
-            "libjpeg/src/libjpeg/codestream/sampleinterleavedlsscan.cpp",
-            "libjpeg/src/libjpeg/codestream/predictorbase.cpp",
-            "libjpeg/src/libjpeg/codestream/image.cpp",
-            "libjpeg/src/libjpeg/codestream/jpeglsscan.cpp",
-            "libjpeg/src/libjpeg/codestream/sequentialscan.cpp",
-            "libjpeg/src/libjpeg/codestream/refinementscan.cpp",
-            "libjpeg/src/libjpeg/codestream/singlecomponentlsscan.cpp",
-            "libjpeg/src/libjpeg/codestream/acsequentialscan.cpp",
-            "libjpeg/src/libjpeg/codestream/losslessscan.cpp",
-            "libjpeg/src/libjpeg/codestream/tables.cpp",
-            "libjpeg/src/libjpeg/codestream/entropyparser.cpp",
-            "libjpeg/src/libjpeg/codestream/predictivescan.cpp",
-            "libjpeg/src/libjpeg/codestream/aclosslessscan.cpp",
-            "libjpeg/src/libjpeg/codestream/acrefinementscan.cpp",
-            "libjpeg/src/libjpeg/codestream/lineinterleavedlsscan.cpp",
-            "libjpeg/src/libjpeg/upsampling/interdownsampler.cpp",
-            "libjpeg/src/libjpeg/upsampling/downsamplerbase.cpp",
-            "libjpeg/src/libjpeg/upsampling/upsamplerbase.cpp",
-            "libjpeg/src/libjpeg/upsampling/upsampler.cpp",
-            "libjpeg/src/libjpeg/upsampling/cositedupsampler.cpp",
-            "libjpeg/src/libjpeg/upsampling/downsampler.cpp",
-            "libjpeg/src/libjpeg/control/blockctrl.cpp",
-            "libjpeg/src/libjpeg/control/bufferctrl.cpp",
-            "libjpeg/src/libjpeg/control/blockbuffer.cpp",
-            "libjpeg/src/libjpeg/control/blockbitmaprequester.cpp",
-            "libjpeg/src/libjpeg/control/bitmapctrl.cpp",
-            "libjpeg/src/libjpeg/control/residualblockhelper.cpp",
-            "libjpeg/src/libjpeg/control/linemerger.cpp",
-            "libjpeg/src/libjpeg/control/linelineadapter.cpp",
-            "libjpeg/src/libjpeg/control/residualbuffer.cpp",
-            "libjpeg/src/libjpeg/control/linebuffer.cpp",
-            "libjpeg/src/libjpeg/control/lineadapter.cpp",
-            "libjpeg/src/libjpeg/control/linebitmaprequester.cpp",
-            "libjpeg/src/libjpeg/control/blocklineadapter.cpp",
-            "libjpeg/src/libjpeg/control/hierarchicalbitmaprequester.cpp",
-            "libjpeg/src/libjpeg/dct/liftingdct.cpp",
-            "libjpeg/src/libjpeg/dct/idct.cpp",
-            "libjpeg/src/libjpeg/dct/dct.cpp",
-            "libjpeg/src/libjpeg/dct/deringing.cpp",
-            "libjpeg/src/libjpeg/cmd/defaulttmoc.cpp",
-            "libjpeg/src/libjpeg/cmd/filehook.cpp",
-            "libjpeg/src/libjpeg/cmd/iohelpers.cpp",
-            "libjpeg/src/libjpeg/cmd/reconstruct.cpp",
-            "libjpeg/src/libjpeg/cmd/main.cpp",
-            "libjpeg/src/libjpeg/cmd/encodec.cpp",
-            "libjpeg/src/libjpeg/cmd/encodeb.cpp",
-            "libjpeg/src/libjpeg/cmd/tmo.cpp",
-            "libjpeg/src/libjpeg/cmd/encodea.cpp",
-            "libjpeg/src/libjpeg/cmd/bitmaphook.cpp",
-            "libjpeg/src/libjpeg/marker/thresholds.cpp",
-            "libjpeg/src/libjpeg/marker/quantization.cpp",
-            "libjpeg/src/libjpeg/marker/adobemarker.cpp",
-            "libjpeg/src/libjpeg/marker/jfifmarker.cpp",
-            "libjpeg/src/libjpeg/marker/frame.cpp",
-            "libjpeg/src/libjpeg/marker/scantypes.cpp",
-            "libjpeg/src/libjpeg/marker/scan.cpp",
-            "libjpeg/src/libjpeg/marker/huffmantable.cpp",
-            "libjpeg/src/libjpeg/marker/lscolortrafo.cpp",
-            "libjpeg/src/libjpeg/marker/exifmarker.cpp",
-            "libjpeg/src/libjpeg/marker/restartintervalmarker.cpp",
-            "libjpeg/src/libjpeg/marker/component.cpp",
-            "libjpeg/src/libjpeg/marker/actable.cpp",
-            "libjpeg/src/libjpeg/marker/quantizationtable.cpp",
-            "libjpeg/src/libjpeg/io/bytestream.cpp",
-            "libjpeg/src/libjpeg/io/randomaccessstream.cpp",
-            "libjpeg/src/libjpeg/io/staticstream.cpp",
-            "libjpeg/src/libjpeg/io/decoderstream.cpp",
-            "libjpeg/src/libjpeg/io/iostream.cpp",
-            "libjpeg/src/libjpeg/io/bitstream.cpp",
-            "libjpeg/src/libjpeg/io/memorystream.cpp",
-            "libjpeg/src/libjpeg/io/checksumadapter.cpp",
-            "libjpeg/src/libjpeg/interface/tagitem.cpp",
-            "libjpeg/src/libjpeg/interface/types.cpp",
-            "libjpeg/src/libjpeg/interface/jpgtypes.cpp",
-            "libjpeg/src/libjpeg/interface/jpeg.cpp",
-            "libjpeg/src/libjpeg/interface/parameters.cpp",
-            "libjpeg/src/libjpeg/interface/imagebitmap.cpp",
-            "libjpeg/src/libjpeg/interface/hooks.cpp",
-            "libjpeg/src/libjpeg/interface/bitmaphook.cpp",
-            "libjpeg/src/libjpeg/coding/blockrow.cpp",
-            "libjpeg/src/libjpeg/coding/huffmantemplate.cpp",
-            "libjpeg/src/libjpeg/coding/qmcoder.cpp",
-            "libjpeg/src/libjpeg/coding/arithmetictemplate.cpp",
-            "libjpeg/src/libjpeg/coding/arthdeco.cpp",
-            "libjpeg/src/libjpeg/coding/huffmanstatistics.cpp",
-            "libjpeg/src/libjpeg/coding/huffmandecoder.cpp",
-            "libjpeg/src/libjpeg/coding/huffmancoder.cpp",
-            "libjpeg/src/libjpeg/coding/actemplate.cpp",
-            "libjpeg/src/libjpeg/coding/decodertemplate.cpp",
-            "libjpeg/src/libjpeg/coding/quantizedrow.cpp"
+            "lib/interface/decode.cpp",
+            "lib/interface/streamhook.cpp",
+            "lib/libjpeg/colortrafo/lslosslesstrafo.cpp",
+            "lib/libjpeg/colortrafo/integertrafo.cpp",
+            "lib/libjpeg/colortrafo/floattrafo.cpp",
+            "lib/libjpeg/colortrafo/colortrafo.cpp",
+            "lib/libjpeg/colortrafo/trivialtrafo.cpp",
+            "lib/libjpeg/colortrafo/multiplicationtrafo.cpp",
+            "lib/libjpeg/colortrafo/colortransformerfactory.cpp",
+            "lib/libjpeg/colortrafo/ycbcrtrafo.cpp",
+            "lib/libjpeg/boxes/tonemapperbox.cpp",
+            "lib/libjpeg/boxes/box.cpp",
+            "lib/libjpeg/boxes/nonlineartrafobox.cpp",
+            "lib/libjpeg/boxes/parametrictonemappingbox.cpp",
+            "lib/libjpeg/boxes/databox.cpp",
+            "lib/libjpeg/boxes/floattonemappingbox.cpp",
+            "lib/libjpeg/boxes/filetypebox.cpp",
+            "lib/libjpeg/boxes/outputconversionbox.cpp",
+            "lib/libjpeg/boxes/refinementspecbox.cpp",
+            "lib/libjpeg/boxes/alphabox.cpp",
+            "lib/libjpeg/boxes/dctbox.cpp",
+            "lib/libjpeg/boxes/colortrafobox.cpp",
+            "lib/libjpeg/boxes/matrixbox.cpp",
+            "lib/libjpeg/boxes/floattransformationbox.cpp",
+            "lib/libjpeg/boxes/lineartransformationbox.cpp",
+            "lib/libjpeg/boxes/superbox.cpp",
+            "lib/libjpeg/boxes/inversetonemappingbox.cpp",
+            "lib/libjpeg/boxes/mergingspecbox.cpp",
+            "lib/libjpeg/boxes/namespace.cpp",
+            "lib/libjpeg/boxes/checksumbox.cpp",
+            "lib/libjpeg/tools/line.cpp",
+            "lib/libjpeg/tools/debug.cpp",
+            "lib/libjpeg/tools/numerics.cpp",
+            "lib/libjpeg/tools/checksum.cpp",
+            "lib/libjpeg/tools/environment.cpp",
+            "lib/libjpeg/tools/traits.cpp",
+            "lib/libjpeg/tools/priorityqueue.cpp",
+            "lib/libjpeg/tools/rectangle.cpp",
+            "lib/libjpeg/std/stddef.cpp",
+            "lib/libjpeg/std/stdio.cpp",
+            "lib/libjpeg/std/errno.cpp",
+            "lib/libjpeg/std/math.cpp",
+            "lib/libjpeg/std/stdlib.cpp",
+            "lib/libjpeg/std/assert.cpp",
+            "lib/libjpeg/std/stdarg.cpp",
+            "lib/libjpeg/std/ctype.cpp",
+            "lib/libjpeg/std/setjmp.cpp",
+            "lib/libjpeg/std/string.cpp",
+            "lib/libjpeg/std/unistd.cpp",
+            "lib/libjpeg/codestream/rectanglerequest.cpp",
+            "lib/libjpeg/codestream/encoder.cpp",
+            "lib/libjpeg/codestream/decoder.cpp",
+            "lib/libjpeg/codestream/predictor.cpp",
+            "lib/libjpeg/codestream/sampleinterleavedlsscan.cpp",
+            "lib/libjpeg/codestream/predictorbase.cpp",
+            "lib/libjpeg/codestream/image.cpp",
+            "lib/libjpeg/codestream/jpeglsscan.cpp",
+            "lib/libjpeg/codestream/sequentialscan.cpp",
+            "lib/libjpeg/codestream/refinementscan.cpp",
+            "lib/libjpeg/codestream/singlecomponentlsscan.cpp",
+            "lib/libjpeg/codestream/acsequentialscan.cpp",
+            "lib/libjpeg/codestream/losslessscan.cpp",
+            "lib/libjpeg/codestream/tables.cpp",
+            "lib/libjpeg/codestream/entropyparser.cpp",
+            "lib/libjpeg/codestream/predictivescan.cpp",
+            "lib/libjpeg/codestream/aclosslessscan.cpp",
+            "lib/libjpeg/codestream/acrefinementscan.cpp",
+            "lib/libjpeg/codestream/lineinterleavedlsscan.cpp",
+            "lib/libjpeg/upsampling/interdownsampler.cpp",
+            "lib/libjpeg/upsampling/downsamplerbase.cpp",
+            "lib/libjpeg/upsampling/upsamplerbase.cpp",
+            "lib/libjpeg/upsampling/upsampler.cpp",
+            "lib/libjpeg/upsampling/cositedupsampler.cpp",
+            "lib/libjpeg/upsampling/downsampler.cpp",
+            "lib/libjpeg/control/blockctrl.cpp",
+            "lib/libjpeg/control/bufferctrl.cpp",
+            "lib/libjpeg/control/blockbuffer.cpp",
+            "lib/libjpeg/control/blockbitmaprequester.cpp",
+            "lib/libjpeg/control/bitmapctrl.cpp",
+            "lib/libjpeg/control/residualblockhelper.cpp",
+            "lib/libjpeg/control/linemerger.cpp",
+            "lib/libjpeg/control/linelineadapter.cpp",
+            "lib/libjpeg/control/residualbuffer.cpp",
+            "lib/libjpeg/control/linebuffer.cpp",
+            "lib/libjpeg/control/lineadapter.cpp",
+            "lib/libjpeg/control/linebitmaprequester.cpp",
+            "lib/libjpeg/control/blocklineadapter.cpp",
+            "lib/libjpeg/control/hierarchicalbitmaprequester.cpp",
+            "lib/libjpeg/dct/liftingdct.cpp",
+            "lib/libjpeg/dct/idct.cpp",
+            "lib/libjpeg/dct/dct.cpp",
+            "lib/libjpeg/dct/deringing.cpp",
+            "lib/libjpeg/cmd/defaulttmoc.cpp",
+            "lib/libjpeg/cmd/filehook.cpp",
+            "lib/libjpeg/cmd/iohelpers.cpp",
+            "lib/libjpeg/cmd/reconstruct.cpp",
+            "lib/libjpeg/cmd/main.cpp",
+            "lib/libjpeg/cmd/encodec.cpp",
+            "lib/libjpeg/cmd/encodeb.cpp",
+            "lib/libjpeg/cmd/tmo.cpp",
+            "lib/libjpeg/cmd/encodea.cpp",
+            "lib/libjpeg/cmd/bitmaphook.cpp",
+            "lib/libjpeg/marker/thresholds.cpp",
+            "lib/libjpeg/marker/quantization.cpp",
+            "lib/libjpeg/marker/adobemarker.cpp",
+            "lib/libjpeg/marker/jfifmarker.cpp",
+            "lib/libjpeg/marker/frame.cpp",
+            "lib/libjpeg/marker/scantypes.cpp",
+            "lib/libjpeg/marker/scan.cpp",
+            "lib/libjpeg/marker/huffmantable.cpp",
+            "lib/libjpeg/marker/lscolortrafo.cpp",
+            "lib/libjpeg/marker/exifmarker.cpp",
+            "lib/libjpeg/marker/restartintervalmarker.cpp",
+            "lib/libjpeg/marker/component.cpp",
+            "lib/libjpeg/marker/actable.cpp",
+            "lib/libjpeg/marker/quantizationtable.cpp",
+            "lib/libjpeg/io/bytestream.cpp",
+            "lib/libjpeg/io/randomaccessstream.cpp",
+            "lib/libjpeg/io/staticstream.cpp",
+            "lib/libjpeg/io/decoderstream.cpp",
+            "lib/libjpeg/io/iostream.cpp",
+            "lib/libjpeg/io/bitstream.cpp",
+            "lib/libjpeg/io/memorystream.cpp",
+            "lib/libjpeg/io/checksumadapter.cpp",
+            "lib/libjpeg/interface/tagitem.cpp",
+            "lib/libjpeg/interface/types.cpp",
+            "lib/libjpeg/interface/jpgtypes.cpp",
+            "lib/libjpeg/interface/jpeg.cpp",
+            "lib/libjpeg/interface/parameters.cpp",
+            "lib/libjpeg/interface/imagebitmap.cpp",
+            "lib/libjpeg/interface/hooks.cpp",
+            "lib/libjpeg/interface/bitmaphook.cpp",
+            "lib/libjpeg/coding/blockrow.cpp",
+            "lib/libjpeg/coding/huffmantemplate.cpp",
+            "lib/libjpeg/coding/qmcoder.cpp",
+            "lib/libjpeg/coding/arithmetictemplate.cpp",
+            "lib/libjpeg/coding/arthdeco.cpp",
+            "lib/libjpeg/coding/huffmanstatistics.cpp",
+            "lib/libjpeg/coding/huffmandecoder.cpp",
+            "lib/libjpeg/coding/huffmancoder.cpp",
+            "lib/libjpeg/coding/actemplate.cpp",
+            "lib/libjpeg/coding/decodertemplate.cpp",
+            "lib/libjpeg/coding/quantizedrow.cpp"
         ]
     },
     "module_name": "_libjpeg"
@@ -1688,44 +1688,9 @@ static const char *__pyx_f[] = {
   #define __PYX_FORCE_INIT_THREADS 0
 #endif
 
-/* BufferFormatStructs.proto */
-struct __Pyx_StructField_;
-#define __PYX_BUF_FLAGS_PACKED_STRUCT (1 << 0)
-typedef struct {
-  const char* name;
-  struct __Pyx_StructField_* fields;
-  size_t size;
-  size_t arraysize[8];
-  int ndim;
-  char typegroup;
-  char is_unsigned;
-  int flags;
-} __Pyx_TypeInfo;
-typedef struct __Pyx_StructField_ {
-  __Pyx_TypeInfo* type;
-  const char* name;
-  size_t offset;
-} __Pyx_StructField;
-typedef struct {
-  __Pyx_StructField* field;
-  size_t parent_offset;
-} __Pyx_BufFmt_StackElem;
-typedef struct {
-  __Pyx_StructField root;
-  __Pyx_BufFmt_StackElem* head;
-  size_t fmt_offset;
-  size_t new_count, enc_count;
-  size_t struct_alignment;
-  int is_complex;
-  char enc_type;
-  char new_packmode;
-  char enc_packmode;
-  char is_valid_array;
-} __Pyx_BufFmt_Context;
-
 /* #### Code section: numeric_typedefs ### */
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":730
+/* "../../../../../tmp/pip-build-env-zlp83btd/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             # <<<<<<<<<<<<<<
@@ -1734,7 +1699,7 @@ typedef struct {
  */
 typedef npy_int8 __pyx_t_5numpy_int8_t;
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":731
+/* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":732
  * 
  * ctypedef npy_int8       int8_t
  * ctypedef npy_int16      int16_t             # <<<<<<<<<<<<<<
@@ -1743,7 +1708,7 @@ typedef npy_int8 __pyx_t_5numpy_int8_t;
  */
 typedef npy_int16 __pyx_t_5numpy_int16_t;
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":732
+/* "../../../../../tmp/pip-build-env-zlp83btd/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             # <<<<<<<<<<<<<<
@@ -1752,7 +1717,7 @@ typedef npy_int16 __pyx_t_5numpy_int16_t;
  */
 typedef npy_int32 __pyx_t_5numpy_int32_t;
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":733
+/* "../../../../../tmp/pip-build-env-zlp83btd/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             # <<<<<<<<<<<<<<
@@ -1761,7 +1726,7 @@ typedef npy_int32 __pyx_t_5numpy_int32_t;
  */
 typedef npy_int64 __pyx_t_5numpy_int64_t;
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":737
+/* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":738
  * #ctypedef npy_int128     int128_t
  * 
  * ctypedef npy_uint8      uint8_t             # <<<<<<<<<<<<<<
@@ -1770,7 +1735,7 @@ typedef npy_int64 __pyx_t_5numpy_int64_t;
  */
 typedef npy_uint8 __pyx_t_5numpy_uint8_t;
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":738
+/* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":739
  * 
  * ctypedef npy_uint8      uint8_t
  * ctypedef npy_uint16     uint16_t             # <<<<<<<<<<<<<<
@@ -1779,7 +1744,7 @@ typedef npy_uint8 __pyx_t_5numpy_uint8_t;
  */
 typedef npy_uint16 __pyx_t_5numpy_uint16_t;
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":739
+/* "../../../../../tmp/pip-build-env-zlp83btd/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             # <<<<<<<<<<<<<<
@@ -1788,7 +1753,7 @@ typedef npy_uint16 __pyx_t_5numpy_uint16_t;
  */
 typedef npy_uint32 __pyx_t_5numpy_uint32_t;
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":740
+/* "../../../../../tmp/pip-build-env-zlp83btd/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             # <<<<<<<<<<<<<<
@@ -1797,7 +1762,7 @@ typedef npy_uint32 __pyx_t_5numpy_uint32_t;
  */
 typedef npy_uint64 __pyx_t_5numpy_uint64_t;
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":744
+/* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":745
  * #ctypedef npy_uint128    uint128_t
  * 
  * ctypedef npy_float32    float32_t             # <<<<<<<<<<<<<<
@@ -1806,7 +1771,7 @@ typedef npy_uint64 __pyx_t_5numpy_uint64_t;
  */
 typedef npy_float32 __pyx_t_5numpy_float32_t;
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":745
+/* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":746
  * 
  * ctypedef npy_float32    float32_t
  * ctypedef npy_float64    float64_t             # <<<<<<<<<<<<<<
@@ -1815,43 +1780,61 @@ typedef npy_float32 __pyx_t_5numpy_float32_t;
  */
 typedef npy_float64 __pyx_t_5numpy_float64_t;
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":754
+/* "../../../../../tmp/pip-build-env-zlp83btd/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             # <<<<<<<<<<<<<<
+ * ctypedef npy_longlong   long_t
  * ctypedef npy_longlong   longlong_t
- * 
  */
 typedef npy_long __pyx_t_5numpy_int_t;
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":755
+/* "../../../../../tmp/pip-build-env-zlp83btd/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             # <<<<<<<<<<<<<<
+ * ctypedef npy_longlong   longlong_t
+ * 
+ */
+typedef npy_longlong __pyx_t_5numpy_long_t;
+
+/* "../../../../../tmp/pip-build-env-zlp83btd/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             # <<<<<<<<<<<<<<
  * 
  * ctypedef npy_ulong      uint_t
  */
 typedef npy_longlong __pyx_t_5numpy_longlong_t;
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":757
+/* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":759
  * ctypedef npy_longlong   longlong_t
  * 
  * ctypedef npy_ulong      uint_t             # <<<<<<<<<<<<<<
+ * ctypedef npy_ulonglong  ulong_t
  * ctypedef npy_ulonglong  ulonglong_t
- * 
  */
 typedef npy_ulong __pyx_t_5numpy_uint_t;
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":758
+/* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":760
+ * 
+ * ctypedef npy_ulong      uint_t
+ * ctypedef npy_ulonglong  ulong_t             # <<<<<<<<<<<<<<
+ * ctypedef npy_ulonglong  ulonglong_t
  * 
+ */
+typedef npy_ulonglong __pyx_t_5numpy_ulong_t;
+
+/* "../../../../../tmp/pip-build-env-zlp83btd/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             # <<<<<<<<<<<<<<
  * 
  * ctypedef npy_intp       intp_t
  */
 typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t;
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":760
+/* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":763
  * ctypedef npy_ulonglong  ulonglong_t
  * 
  * ctypedef npy_intp       intp_t             # <<<<<<<<<<<<<<
@@ -1860,7 +1843,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t;
  */
 typedef npy_intp __pyx_t_5numpy_intp_t;
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":761
+/* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":764
  * 
  * ctypedef npy_intp       intp_t
  * ctypedef npy_uintp      uintp_t             # <<<<<<<<<<<<<<
@@ -1869,7 +1852,7 @@ typedef npy_intp __pyx_t_5numpy_intp_t;
  */
 typedef npy_uintp __pyx_t_5numpy_uintp_t;
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":763
+/* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":766
  * ctypedef npy_uintp      uintp_t
  * 
  * ctypedef npy_double     float_t             # <<<<<<<<<<<<<<
@@ -1878,7 +1861,7 @@ typedef npy_uintp __pyx_t_5numpy_uintp_t;
  */
 typedef npy_double __pyx_t_5numpy_float_t;
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":764
+/* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":767
  * 
  * ctypedef npy_double     float_t
  * ctypedef npy_double     double_t             # <<<<<<<<<<<<<<
@@ -1887,7 +1870,7 @@ typedef npy_double __pyx_t_5numpy_float_t;
  */
 typedef npy_double __pyx_t_5numpy_double_t;
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":765
+/* "../../../../../tmp/pip-build-env-zlp83btd/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             # <<<<<<<<<<<<<<
@@ -1924,7 +1907,7 @@ static CYTHON_INLINE __pyx_t_double_complex __pyx_t_double_complex_from_parts(do
 
 /*--- Type declarations ---*/
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":767
+/* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":770
  * ctypedef npy_longdouble longdouble_t
  * 
  * ctypedef npy_cfloat      cfloat_t             # <<<<<<<<<<<<<<
@@ -1933,7 +1916,7 @@ static CYTHON_INLINE __pyx_t_double_complex __pyx_t_double_complex_from_parts(do
  */
 typedef npy_cfloat __pyx_t_5numpy_cfloat_t;
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":768
+/* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":771
  * 
  * ctypedef npy_cfloat      cfloat_t
  * ctypedef npy_cdouble     cdouble_t             # <<<<<<<<<<<<<<
@@ -1942,7 +1925,7 @@ typedef npy_cfloat __pyx_t_5numpy_cfloat_t;
  */
 typedef npy_cdouble __pyx_t_5numpy_cdouble_t;
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":769
+/* "../../../../../tmp/pip-build-env-zlp83btd/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             # <<<<<<<<<<<<<<
@@ -1951,7 +1934,7 @@ typedef npy_cdouble __pyx_t_5numpy_cdouble_t;
  */
 typedef npy_clongdouble __pyx_t_5numpy_clongdouble_t;
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":771
+/* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":774
  * ctypedef npy_clongdouble clongdouble_t
  * 
  * ctypedef npy_cdouble     complex_t             # <<<<<<<<<<<<<<
@@ -2221,27 +2204,6 @@ static int __Pyx_ParseOptionalKeywords(PyObject *kwds, PyObject *const *kwvalues
         __Pyx__ArgTypeTest(obj, type, name, exact))
 static int __Pyx__ArgTypeTest(PyObject *obj, PyTypeObject *type, const char *name, int exact);
 
-/* IsLittleEndian.proto */
-static CYTHON_INLINE int __Pyx_Is_Little_Endian(void);
-
-/* BufferFormatCheck.proto */
-static const char* __Pyx_BufFmt_CheckString(__Pyx_BufFmt_Context* ctx, const char* ts);
-static void __Pyx_BufFmt_Init(__Pyx_BufFmt_Context* ctx,
-                              __Pyx_BufFmt_StackElem* stack,
-                              __Pyx_TypeInfo* type);
-
-/* BufferGetAndValidate.proto */
-#define __Pyx_GetBufferAndValidate(buf, obj, dtype, flags, nd, cast, stack)\
-    ((obj == Py_None || obj == NULL) ?\
-    (__Pyx_ZeroBuffer(buf), 0) :\
-    __Pyx__GetBufferAndValidate(buf, obj, dtype, flags, nd, cast, stack))
-static int  __Pyx__GetBufferAndValidate(Py_buffer* buf, PyObject* obj,
-    __Pyx_TypeInfo* dtype, int flags, int nd, int cast, __Pyx_BufFmt_StackElem* stack);
-static void __Pyx_ZeroBuffer(Py_buffer* buf);
-static CYTHON_INLINE void __Pyx_SafeReleaseBuffer(Py_buffer* info);
-static Py_ssize_t __Pyx_minusones[] = { -1, -1, -1, -1, -1, -1, -1, -1 };
-static Py_ssize_t __Pyx_zeros[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
-
 /* PyDictVersioning.proto */
 #if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_TYPE_SLOTS
 #define __PYX_DICT_VERSION_INIT  ((PY_UINT64_T) -1)
@@ -2345,6 +2307,9 @@ static CYTHON_INLINE int __Pyx_IterFinish(void);
 /* UnpackItemEndCheck.proto */
 static int __Pyx_IternextUnpackEndCheck(PyObject *retval, Py_ssize_t expected);
 
+/* PyIntCompare.proto */
+static CYTHON_INLINE int __Pyx_PyInt_BoolNeObjC(PyObject *op1, PyObject *op2, long intval, long inplace);
+
 /* PyIntBinop.proto */
 #if !CYTHON_COMPILING_IN_PYPY
 static PyObject* __Pyx_PyInt_TrueDivideObjC(PyObject *op1, PyObject *op2, long intval, int inplace, int zerodivision_check);
@@ -2367,27 +2332,8 @@ static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key);
 /* ExtTypeTest.proto */
 static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type);
 
-/* GetItemInt.proto */
-#define __Pyx_GetItemInt(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\
-    (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\
-    __Pyx_GetItemInt_Fast(o, (Py_ssize_t)i, is_list, wraparound, boundscheck) :\
-    (is_list ? (PyErr_SetString(PyExc_IndexError, "list index out of range"), (PyObject*)NULL) :\
-               __Pyx_GetItemInt_Generic(o, to_py_func(i))))
-#define __Pyx_GetItemInt_List(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\
-    (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\
-    __Pyx_GetItemInt_List_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) :\
-    (PyErr_SetString(PyExc_IndexError, "list index out of range"), (PyObject*)NULL))
-static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i,
-                                                              int wraparound, int boundscheck);
-#define __Pyx_GetItemInt_Tuple(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\
-    (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\
-    __Pyx_GetItemInt_Tuple_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) :\
-    (PyErr_SetString(PyExc_IndexError, "tuple index out of range"), (PyObject*)NULL))
-static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i,
-                                                              int wraparound, int boundscheck);
-static PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j);
-static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i,
-                                                     int is_list, int wraparound, int boundscheck);
+/* PyObjectCallOneArg.proto */
+static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg);
 
 /* TypeImport.proto */
 #ifndef __PYX_HAVE_RT_ImportType_proto_3_0_7
@@ -2596,29 +2542,6 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object);
 static void __Pyx_AddTraceback(const char *funcname, int c_line,
                                int py_line, const char *filename);
 
-/* BufferStructDeclare.proto */
-typedef struct {
-  Py_ssize_t shape, strides, suboffsets;
-} __Pyx_Buf_DimInfo;
-typedef struct {
-  size_t refcount;
-  Py_buffer pybuffer;
-} __Pyx_Buffer;
-typedef struct {
-  __Pyx_Buffer *rcbuffer;
-  char *data;
-  __Pyx_Buf_DimInfo diminfo[8];
-} __Pyx_LocalBuf_ND;
-
-#if PY_MAJOR_VERSION < 3
-    static int __Pyx_GetBuffer(PyObject *obj, Py_buffer *view, int flags);
-    static void __Pyx_ReleaseBuffer(Py_buffer *view);
-#else
-    #define __Pyx_GetBuffer PyObject_GetBuffer
-    #define __Pyx_ReleaseBuffer PyBuffer_Release
-#endif
-
-
 /* GCCDiagnostics.proto */
 #if !defined(__INTEL_COMPILER) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
 #define __Pyx_HAS_GCC_DIAGNOSTIC
@@ -2722,12 +2645,12 @@ typedef struct {
     #endif
 #endif
 
-/* CIntToPy.proto */
-static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value);
-
 /* CIntFromPy.proto */
 static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *);
 
+/* CIntToPy.proto */
+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value);
+
 /* CIntToPy.proto */
 static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value);
 
@@ -2812,7 +2735,6 @@ static CYTHON_INLINE PyObject *__pyx_convert_PyStr_string_to_py_std__in_string(s
 static CYTHON_INLINE PyObject *__pyx_convert_PyBytes_string_to_py_std__in_string(std::string const &); /*proto*/
 static CYTHON_INLINE PyObject *__pyx_convert_PyByteArray_string_to_py_std__in_string(std::string const &); /*proto*/
 /* #### Code section: typeinfo ### */
-static __Pyx_TypeInfo __Pyx_TypeInfo_nn___pyx_t_5numpy_uint8_t = { "uint8_t", NULL, sizeof(__pyx_t_5numpy_uint8_t), { 0 }, 0, __PYX_IS_UNSIGNED(__pyx_t_5numpy_uint8_t) ? 'U' : 'I', __PYX_IS_UNSIGNED(__pyx_t_5numpy_uint8_t), 0 };
 /* #### Code section: before_global_var ### */
 #define __Pyx_MODULE_NAME "_libjpeg"
 extern int __pyx_module_is_main__libjpeg;
@@ -2822,35 +2744,51 @@ int __pyx_module_is_main__libjpeg = 0;
 /* #### Code section: global_var ### */
 static PyObject *__pyx_builtin_ImportError;
 /* #### Code section: string_decls ### */
-static const char __pyx_k__3[] = ".";
-static const char __pyx_k__4[] = "*";
+static const char __pyx_k__3[] = "::::";
+static const char __pyx_k__4[] = ".";
+static const char __pyx_k__5[] = "*";
 static const char __pyx_k_np[] = "np";
-static const char __pyx_k__11[] = "?";
+static const char __pyx_k__12[] = "?";
 static const char __pyx_k_bpp[] = "bpp";
 static const char __pyx_k_fin[] = "fin";
+static const char __pyx_k_int[] = "int";
+static const char __pyx_k_msg[] = "msg";
+static const char __pyx_k_out[] = "out";
+static const char __pyx_k_src[] = "src";
+static const char __pyx_k_Dict[] = "Dict";
+static const char __pyx_k_None[] = "None";
+static const char __pyx_k_bool[] = "bool";
 static const char __pyx_k_ceil[] = "ceil";
+static const char __pyx_k_code[] = "code";
 static const char __pyx_k_fout[] = "fout";
 static const char __pyx_k_main[] = "__main__";
 static const char __pyx_k_math[] = "math";
 static const char __pyx_k_name[] = "__name__";
+static const char __pyx_k_p_in[] = "p_in";
 static const char __pyx_k_rows[] = "rows";
 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_dtype[] = "dtype";
 static const char __pyx_k_numpy[] = "numpy";
+static const char __pyx_k_p_out[] = "p_out";
 static const char __pyx_k_param[] = "param";
-static const char __pyx_k_shape[] = "shape";
+static const char __pyx_k_split[] = "split";
 static const char __pyx_k_uint8[] = "uint8";
+static const char __pyx_k_utf_8[] = "utf-8";
 static const char __pyx_k_zeros[] = "zeros";
 static const char __pyx_k_decode[] = "decode";
 static const char __pyx_k_falpha[] = "falpha";
 static const char __pyx_k_import[] = "__import__";
-static const char __pyx_k_pInput[] = "pInput";
 static const char __pyx_k_pParam[] = "pParam";
+static const char __pyx_k_return[] = "return";
 static const char __pyx_k_status[] = "status";
+static const char __pyx_k_typing[] = "typing";
 static const char __pyx_k_columns[] = "columns";
 static const char __pyx_k_libjpeg[] = "_libjpeg";
-static const char __pyx_k_pOutput[] = "pOutput";
+static const char __pyx_k_as_array[] = "as_array";
 static const char __pyx_k_nr_bytes[] = "nr_bytes";
 static const char __pyx_k_upsample[] = "upsample";
 static const char __pyx_k_precision[] = "precision";
@@ -2859,20 +2797,21 @@ static const char __pyx_k_ImportError[] = "ImportError";
 static const char __pyx_k_colourspace[] = "colourspace";
 static const char __pyx_k_reconstruct[] = "reconstruct";
 static const char __pyx_k_initializing[] = "_initializing";
-static const char __pyx_k_input_buffer[] = "input_buffer";
 static const char __pyx_k_is_coroutine[] = "_is_coroutine";
 static const char __pyx_k_nr_components[] = "nr_components";
-static const char __pyx_k_output_buffer[] = "output_buffer";
 static const char __pyx_k_get_parameters[] = "get_parameters";
+static const char __pyx_k_Union_bytes_None[] = "Union[bytes, None]";
 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_libjpeg__libjpeg_pyx[] = "libjpeg/_libjpeg.pyx";
+static const char __pyx_k_Tuple_int_Dict_str_int[] = "Tuple[int, Dict[str, int]]";
 static const char __pyx_k_numpy_core_multiarray_failed_to[] = "numpy.core.multiarray failed to import";
+static const char __pyx_k_Tuple_bytes_Union_bytes_np_ndarr[] = "Tuple[bytes, Union[bytes, np.ndarray, None], Dict[str, int]]";
 static const char __pyx_k_numpy_core_umath_failed_to_impor[] = "numpy.core.umath failed to import";
 /* #### Code section: decls ### */
-static PyObject *__pyx_pf_8_libjpeg_decode(CYTHON_UNUSED PyObject *__pyx_self, PyArrayObject *__pyx_v_input_buffer, PyObject *__pyx_v_colourspace); /* proto */
-static PyObject *__pyx_pf_8_libjpeg_2get_parameters(CYTHON_UNUSED PyObject *__pyx_self, PyArrayObject *__pyx_v_input_buffer); /* proto */
-static PyObject *__pyx_pf_8_libjpeg_4reconstruct(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_fin, PyObject *__pyx_v_fout, PyObject *__pyx_v_colourspace, PyObject *__pyx_v_falpha, PyObject *__pyx_v_upsample); /* proto */
+static PyObject *__pyx_pf_8_libjpeg_decode(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_src, PyObject *__pyx_v_colourspace, bool __pyx_v_as_array); /* proto */
+static PyObject *__pyx_pf_8_libjpeg_2get_parameters(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_src); /* proto */
+static PyObject *__pyx_pf_8_libjpeg_4reconstruct(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_fin, PyObject *__pyx_v_fout, PyObject *__pyx_v_colourspace, PyObject *__pyx_v_falpha, bool __pyx_v_upsample); /* proto */
 /* #### Code section: late_includes ### */
 /* #### Code section: module_state ### */
 typedef struct {
@@ -2940,14 +2879,26 @@ typedef struct {
   PyTypeObject *__pyx_ptype_5numpy_ufunc;
   #if CYTHON_USE_MODULE_STATE
   #endif
+  PyObject *__pyx_n_s_Dict;
   PyObject *__pyx_n_s_ImportError;
-  PyObject *__pyx_n_s__11;
+  PyObject *__pyx_n_s_None;
+  PyObject *__pyx_n_s_Tuple;
+  PyObject *__pyx_kp_s_Tuple_bytes_Union_bytes_np_ndarr;
+  PyObject *__pyx_kp_s_Tuple_int_Dict_str_int;
+  PyObject *__pyx_n_s_Union;
+  PyObject *__pyx_kp_s_Union_bytes_None;
+  PyObject *__pyx_n_s__12;
   PyObject *__pyx_kp_u__3;
-  PyObject *__pyx_n_s__4;
+  PyObject *__pyx_kp_u__4;
+  PyObject *__pyx_n_s__5;
+  PyObject *__pyx_n_s_as_array;
   PyObject *__pyx_n_s_asyncio_coroutines;
+  PyObject *__pyx_n_s_bool;
   PyObject *__pyx_n_s_bpp;
+  PyObject *__pyx_n_s_bytes;
   PyObject *__pyx_n_s_ceil;
   PyObject *__pyx_n_s_cline_in_traceback;
+  PyObject *__pyx_n_s_code;
   PyObject *__pyx_n_s_colourspace;
   PyObject *__pyx_n_u_columns;
   PyObject *__pyx_n_s_decode;
@@ -2958,12 +2909,13 @@ typedef struct {
   PyObject *__pyx_n_s_get_parameters;
   PyObject *__pyx_n_s_import;
   PyObject *__pyx_n_s_initializing;
-  PyObject *__pyx_n_s_input_buffer;
+  PyObject *__pyx_n_s_int;
   PyObject *__pyx_n_s_is_coroutine;
   PyObject *__pyx_n_s_libjpeg;
   PyObject *__pyx_kp_s_libjpeg__libjpeg_pyx;
   PyObject *__pyx_n_s_main;
   PyObject *__pyx_n_s_math;
+  PyObject *__pyx_n_s_msg;
   PyObject *__pyx_n_s_name;
   PyObject *__pyx_n_s_np;
   PyObject *__pyx_n_s_nr_bytes;
@@ -2971,31 +2923,36 @@ typedef struct {
   PyObject *__pyx_n_s_numpy;
   PyObject *__pyx_kp_u_numpy_core_multiarray_failed_to;
   PyObject *__pyx_kp_u_numpy_core_umath_failed_to_impor;
-  PyObject *__pyx_n_s_output_buffer;
-  PyObject *__pyx_n_s_pInput;
-  PyObject *__pyx_n_s_pOutput;
+  PyObject *__pyx_n_s_out;
   PyObject *__pyx_n_s_pParam;
+  PyObject *__pyx_n_s_p_in;
+  PyObject *__pyx_n_s_p_out;
   PyObject *__pyx_n_s_param;
   PyObject *__pyx_n_s_parameters;
   PyObject *__pyx_n_u_precision;
   PyObject *__pyx_n_s_reconstruct;
+  PyObject *__pyx_n_s_return;
   PyObject *__pyx_n_u_rows;
-  PyObject *__pyx_n_s_shape;
   PyObject *__pyx_n_s_spec;
+  PyObject *__pyx_n_s_split;
+  PyObject *__pyx_n_s_src;
   PyObject *__pyx_n_s_status;
   PyObject *__pyx_n_s_test;
+  PyObject *__pyx_n_s_typing;
   PyObject *__pyx_n_s_uint8;
   PyObject *__pyx_n_s_upsample;
+  PyObject *__pyx_kp_u_utf_8;
   PyObject *__pyx_n_s_zeros;
+  PyObject *__pyx_int_0;
   PyObject *__pyx_int_8;
   PyObject *__pyx_tuple_;
   PyObject *__pyx_tuple__2;
-  PyObject *__pyx_tuple__5;
-  PyObject *__pyx_tuple__7;
-  PyObject *__pyx_tuple__9;
-  PyObject *__pyx_codeobj__6;
-  PyObject *__pyx_codeobj__8;
-  PyObject *__pyx_codeobj__10;
+  PyObject *__pyx_tuple__6;
+  PyObject *__pyx_tuple__8;
+  PyObject *__pyx_tuple__10;
+  PyObject *__pyx_codeobj__7;
+  PyObject *__pyx_codeobj__9;
+  PyObject *__pyx_codeobj__11;
 } __pyx_mstate;
 
 #if CYTHON_USE_MODULE_STATE
@@ -3054,14 +3011,26 @@ static int __pyx_m_clear(PyObject *m) {
   Py_CLEAR(clear_module_state->__pyx_ptype_5numpy_flexible);
   Py_CLEAR(clear_module_state->__pyx_ptype_5numpy_character);
   Py_CLEAR(clear_module_state->__pyx_ptype_5numpy_ufunc);
+  Py_CLEAR(clear_module_state->__pyx_n_s_Dict);
   Py_CLEAR(clear_module_state->__pyx_n_s_ImportError);
-  Py_CLEAR(clear_module_state->__pyx_n_s__11);
+  Py_CLEAR(clear_module_state->__pyx_n_s_None);
+  Py_CLEAR(clear_module_state->__pyx_n_s_Tuple);
+  Py_CLEAR(clear_module_state->__pyx_kp_s_Tuple_bytes_Union_bytes_np_ndarr);
+  Py_CLEAR(clear_module_state->__pyx_kp_s_Tuple_int_Dict_str_int);
+  Py_CLEAR(clear_module_state->__pyx_n_s_Union);
+  Py_CLEAR(clear_module_state->__pyx_kp_s_Union_bytes_None);
+  Py_CLEAR(clear_module_state->__pyx_n_s__12);
   Py_CLEAR(clear_module_state->__pyx_kp_u__3);
-  Py_CLEAR(clear_module_state->__pyx_n_s__4);
+  Py_CLEAR(clear_module_state->__pyx_kp_u__4);
+  Py_CLEAR(clear_module_state->__pyx_n_s__5);
+  Py_CLEAR(clear_module_state->__pyx_n_s_as_array);
   Py_CLEAR(clear_module_state->__pyx_n_s_asyncio_coroutines);
+  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_n_s_ceil);
   Py_CLEAR(clear_module_state->__pyx_n_s_cline_in_traceback);
+  Py_CLEAR(clear_module_state->__pyx_n_s_code);
   Py_CLEAR(clear_module_state->__pyx_n_s_colourspace);
   Py_CLEAR(clear_module_state->__pyx_n_u_columns);
   Py_CLEAR(clear_module_state->__pyx_n_s_decode);
@@ -3072,12 +3041,13 @@ static int __pyx_m_clear(PyObject *m) {
   Py_CLEAR(clear_module_state->__pyx_n_s_get_parameters);
   Py_CLEAR(clear_module_state->__pyx_n_s_import);
   Py_CLEAR(clear_module_state->__pyx_n_s_initializing);
-  Py_CLEAR(clear_module_state->__pyx_n_s_input_buffer);
+  Py_CLEAR(clear_module_state->__pyx_n_s_int);
   Py_CLEAR(clear_module_state->__pyx_n_s_is_coroutine);
   Py_CLEAR(clear_module_state->__pyx_n_s_libjpeg);
   Py_CLEAR(clear_module_state->__pyx_kp_s_libjpeg__libjpeg_pyx);
   Py_CLEAR(clear_module_state->__pyx_n_s_main);
   Py_CLEAR(clear_module_state->__pyx_n_s_math);
+  Py_CLEAR(clear_module_state->__pyx_n_s_msg);
   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);
@@ -3085,31 +3055,36 @@ static int __pyx_m_clear(PyObject *m) {
   Py_CLEAR(clear_module_state->__pyx_n_s_numpy);
   Py_CLEAR(clear_module_state->__pyx_kp_u_numpy_core_multiarray_failed_to);
   Py_CLEAR(clear_module_state->__pyx_kp_u_numpy_core_umath_failed_to_impor);
-  Py_CLEAR(clear_module_state->__pyx_n_s_output_buffer);
-  Py_CLEAR(clear_module_state->__pyx_n_s_pInput);
-  Py_CLEAR(clear_module_state->__pyx_n_s_pOutput);
+  Py_CLEAR(clear_module_state->__pyx_n_s_out);
   Py_CLEAR(clear_module_state->__pyx_n_s_pParam);
+  Py_CLEAR(clear_module_state->__pyx_n_s_p_in);
+  Py_CLEAR(clear_module_state->__pyx_n_s_p_out);
   Py_CLEAR(clear_module_state->__pyx_n_s_param);
   Py_CLEAR(clear_module_state->__pyx_n_s_parameters);
   Py_CLEAR(clear_module_state->__pyx_n_u_precision);
   Py_CLEAR(clear_module_state->__pyx_n_s_reconstruct);
+  Py_CLEAR(clear_module_state->__pyx_n_s_return);
   Py_CLEAR(clear_module_state->__pyx_n_u_rows);
-  Py_CLEAR(clear_module_state->__pyx_n_s_shape);
   Py_CLEAR(clear_module_state->__pyx_n_s_spec);
+  Py_CLEAR(clear_module_state->__pyx_n_s_split);
+  Py_CLEAR(clear_module_state->__pyx_n_s_src);
   Py_CLEAR(clear_module_state->__pyx_n_s_status);
   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_uint8);
   Py_CLEAR(clear_module_state->__pyx_n_s_upsample);
+  Py_CLEAR(clear_module_state->__pyx_kp_u_utf_8);
   Py_CLEAR(clear_module_state->__pyx_n_s_zeros);
+  Py_CLEAR(clear_module_state->__pyx_int_0);
   Py_CLEAR(clear_module_state->__pyx_int_8);
   Py_CLEAR(clear_module_state->__pyx_tuple_);
   Py_CLEAR(clear_module_state->__pyx_tuple__2);
-  Py_CLEAR(clear_module_state->__pyx_tuple__5);
-  Py_CLEAR(clear_module_state->__pyx_tuple__7);
-  Py_CLEAR(clear_module_state->__pyx_tuple__9);
-  Py_CLEAR(clear_module_state->__pyx_codeobj__6);
-  Py_CLEAR(clear_module_state->__pyx_codeobj__8);
-  Py_CLEAR(clear_module_state->__pyx_codeobj__10);
+  Py_CLEAR(clear_module_state->__pyx_tuple__6);
+  Py_CLEAR(clear_module_state->__pyx_tuple__8);
+  Py_CLEAR(clear_module_state->__pyx_tuple__10);
+  Py_CLEAR(clear_module_state->__pyx_codeobj__7);
+  Py_CLEAR(clear_module_state->__pyx_codeobj__9);
+  Py_CLEAR(clear_module_state->__pyx_codeobj__11);
   return 0;
 }
 #endif
@@ -3146,14 +3121,26 @@ static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) {
   Py_VISIT(traverse_module_state->__pyx_ptype_5numpy_flexible);
   Py_VISIT(traverse_module_state->__pyx_ptype_5numpy_character);
   Py_VISIT(traverse_module_state->__pyx_ptype_5numpy_ufunc);
+  Py_VISIT(traverse_module_state->__pyx_n_s_Dict);
   Py_VISIT(traverse_module_state->__pyx_n_s_ImportError);
-  Py_VISIT(traverse_module_state->__pyx_n_s__11);
+  Py_VISIT(traverse_module_state->__pyx_n_s_None);
+  Py_VISIT(traverse_module_state->__pyx_n_s_Tuple);
+  Py_VISIT(traverse_module_state->__pyx_kp_s_Tuple_bytes_Union_bytes_np_ndarr);
+  Py_VISIT(traverse_module_state->__pyx_kp_s_Tuple_int_Dict_str_int);
+  Py_VISIT(traverse_module_state->__pyx_n_s_Union);
+  Py_VISIT(traverse_module_state->__pyx_kp_s_Union_bytes_None);
+  Py_VISIT(traverse_module_state->__pyx_n_s__12);
   Py_VISIT(traverse_module_state->__pyx_kp_u__3);
-  Py_VISIT(traverse_module_state->__pyx_n_s__4);
+  Py_VISIT(traverse_module_state->__pyx_kp_u__4);
+  Py_VISIT(traverse_module_state->__pyx_n_s__5);
+  Py_VISIT(traverse_module_state->__pyx_n_s_as_array);
   Py_VISIT(traverse_module_state->__pyx_n_s_asyncio_coroutines);
+  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_n_s_ceil);
   Py_VISIT(traverse_module_state->__pyx_n_s_cline_in_traceback);
+  Py_VISIT(traverse_module_state->__pyx_n_s_code);
   Py_VISIT(traverse_module_state->__pyx_n_s_colourspace);
   Py_VISIT(traverse_module_state->__pyx_n_u_columns);
   Py_VISIT(traverse_module_state->__pyx_n_s_decode);
@@ -3164,12 +3151,13 @@ static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) {
   Py_VISIT(traverse_module_state->__pyx_n_s_get_parameters);
   Py_VISIT(traverse_module_state->__pyx_n_s_import);
   Py_VISIT(traverse_module_state->__pyx_n_s_initializing);
-  Py_VISIT(traverse_module_state->__pyx_n_s_input_buffer);
+  Py_VISIT(traverse_module_state->__pyx_n_s_int);
   Py_VISIT(traverse_module_state->__pyx_n_s_is_coroutine);
   Py_VISIT(traverse_module_state->__pyx_n_s_libjpeg);
   Py_VISIT(traverse_module_state->__pyx_kp_s_libjpeg__libjpeg_pyx);
   Py_VISIT(traverse_module_state->__pyx_n_s_main);
   Py_VISIT(traverse_module_state->__pyx_n_s_math);
+  Py_VISIT(traverse_module_state->__pyx_n_s_msg);
   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);
@@ -3177,31 +3165,36 @@ static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) {
   Py_VISIT(traverse_module_state->__pyx_n_s_numpy);
   Py_VISIT(traverse_module_state->__pyx_kp_u_numpy_core_multiarray_failed_to);
   Py_VISIT(traverse_module_state->__pyx_kp_u_numpy_core_umath_failed_to_impor);
-  Py_VISIT(traverse_module_state->__pyx_n_s_output_buffer);
-  Py_VISIT(traverse_module_state->__pyx_n_s_pInput);
-  Py_VISIT(traverse_module_state->__pyx_n_s_pOutput);
+  Py_VISIT(traverse_module_state->__pyx_n_s_out);
   Py_VISIT(traverse_module_state->__pyx_n_s_pParam);
+  Py_VISIT(traverse_module_state->__pyx_n_s_p_in);
+  Py_VISIT(traverse_module_state->__pyx_n_s_p_out);
   Py_VISIT(traverse_module_state->__pyx_n_s_param);
   Py_VISIT(traverse_module_state->__pyx_n_s_parameters);
   Py_VISIT(traverse_module_state->__pyx_n_u_precision);
   Py_VISIT(traverse_module_state->__pyx_n_s_reconstruct);
+  Py_VISIT(traverse_module_state->__pyx_n_s_return);
   Py_VISIT(traverse_module_state->__pyx_n_u_rows);
-  Py_VISIT(traverse_module_state->__pyx_n_s_shape);
   Py_VISIT(traverse_module_state->__pyx_n_s_spec);
+  Py_VISIT(traverse_module_state->__pyx_n_s_split);
+  Py_VISIT(traverse_module_state->__pyx_n_s_src);
   Py_VISIT(traverse_module_state->__pyx_n_s_status);
   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_uint8);
   Py_VISIT(traverse_module_state->__pyx_n_s_upsample);
+  Py_VISIT(traverse_module_state->__pyx_kp_u_utf_8);
   Py_VISIT(traverse_module_state->__pyx_n_s_zeros);
+  Py_VISIT(traverse_module_state->__pyx_int_0);
   Py_VISIT(traverse_module_state->__pyx_int_8);
   Py_VISIT(traverse_module_state->__pyx_tuple_);
   Py_VISIT(traverse_module_state->__pyx_tuple__2);
-  Py_VISIT(traverse_module_state->__pyx_tuple__5);
-  Py_VISIT(traverse_module_state->__pyx_tuple__7);
-  Py_VISIT(traverse_module_state->__pyx_tuple__9);
-  Py_VISIT(traverse_module_state->__pyx_codeobj__6);
-  Py_VISIT(traverse_module_state->__pyx_codeobj__8);
-  Py_VISIT(traverse_module_state->__pyx_codeobj__10);
+  Py_VISIT(traverse_module_state->__pyx_tuple__6);
+  Py_VISIT(traverse_module_state->__pyx_tuple__8);
+  Py_VISIT(traverse_module_state->__pyx_tuple__10);
+  Py_VISIT(traverse_module_state->__pyx_codeobj__7);
+  Py_VISIT(traverse_module_state->__pyx_codeobj__9);
+  Py_VISIT(traverse_module_state->__pyx_codeobj__11);
   return 0;
 }
 #endif
@@ -3270,14 +3263,26 @@ static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) {
 #define __pyx_ptype_5numpy_ufunc __pyx_mstate_global->__pyx_ptype_5numpy_ufunc
 #if CYTHON_USE_MODULE_STATE
 #endif
+#define __pyx_n_s_Dict __pyx_mstate_global->__pyx_n_s_Dict
 #define __pyx_n_s_ImportError __pyx_mstate_global->__pyx_n_s_ImportError
-#define __pyx_n_s__11 __pyx_mstate_global->__pyx_n_s__11
+#define __pyx_n_s_None __pyx_mstate_global->__pyx_n_s_None
+#define __pyx_n_s_Tuple __pyx_mstate_global->__pyx_n_s_Tuple
+#define __pyx_kp_s_Tuple_bytes_Union_bytes_np_ndarr __pyx_mstate_global->__pyx_kp_s_Tuple_bytes_Union_bytes_np_ndarr
+#define __pyx_kp_s_Tuple_int_Dict_str_int __pyx_mstate_global->__pyx_kp_s_Tuple_int_Dict_str_int
+#define __pyx_n_s_Union __pyx_mstate_global->__pyx_n_s_Union
+#define __pyx_kp_s_Union_bytes_None __pyx_mstate_global->__pyx_kp_s_Union_bytes_None
+#define __pyx_n_s__12 __pyx_mstate_global->__pyx_n_s__12
 #define __pyx_kp_u__3 __pyx_mstate_global->__pyx_kp_u__3
-#define __pyx_n_s__4 __pyx_mstate_global->__pyx_n_s__4
+#define __pyx_kp_u__4 __pyx_mstate_global->__pyx_kp_u__4
+#define __pyx_n_s__5 __pyx_mstate_global->__pyx_n_s__5
+#define __pyx_n_s_as_array __pyx_mstate_global->__pyx_n_s_as_array
 #define __pyx_n_s_asyncio_coroutines __pyx_mstate_global->__pyx_n_s_asyncio_coroutines
+#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_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_code __pyx_mstate_global->__pyx_n_s_code
 #define __pyx_n_s_colourspace __pyx_mstate_global->__pyx_n_s_colourspace
 #define __pyx_n_u_columns __pyx_mstate_global->__pyx_n_u_columns
 #define __pyx_n_s_decode __pyx_mstate_global->__pyx_n_s_decode
@@ -3288,12 +3293,13 @@ static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) {
 #define __pyx_n_s_get_parameters __pyx_mstate_global->__pyx_n_s_get_parameters
 #define __pyx_n_s_import __pyx_mstate_global->__pyx_n_s_import
 #define __pyx_n_s_initializing __pyx_mstate_global->__pyx_n_s_initializing
-#define __pyx_n_s_input_buffer __pyx_mstate_global->__pyx_n_s_input_buffer
+#define __pyx_n_s_int __pyx_mstate_global->__pyx_n_s_int
 #define __pyx_n_s_is_coroutine __pyx_mstate_global->__pyx_n_s_is_coroutine
 #define __pyx_n_s_libjpeg __pyx_mstate_global->__pyx_n_s_libjpeg
 #define __pyx_kp_s_libjpeg__libjpeg_pyx __pyx_mstate_global->__pyx_kp_s_libjpeg__libjpeg_pyx
 #define __pyx_n_s_main __pyx_mstate_global->__pyx_n_s_main
 #define __pyx_n_s_math __pyx_mstate_global->__pyx_n_s_math
+#define __pyx_n_s_msg __pyx_mstate_global->__pyx_n_s_msg
 #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
@@ -3301,31 +3307,36 @@ static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) {
 #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
 #define __pyx_kp_u_numpy_core_umath_failed_to_impor __pyx_mstate_global->__pyx_kp_u_numpy_core_umath_failed_to_impor
-#define __pyx_n_s_output_buffer __pyx_mstate_global->__pyx_n_s_output_buffer
-#define __pyx_n_s_pInput __pyx_mstate_global->__pyx_n_s_pInput
-#define __pyx_n_s_pOutput __pyx_mstate_global->__pyx_n_s_pOutput
+#define __pyx_n_s_out __pyx_mstate_global->__pyx_n_s_out
 #define __pyx_n_s_pParam __pyx_mstate_global->__pyx_n_s_pParam
+#define __pyx_n_s_p_in __pyx_mstate_global->__pyx_n_s_p_in
+#define __pyx_n_s_p_out __pyx_mstate_global->__pyx_n_s_p_out
 #define __pyx_n_s_param __pyx_mstate_global->__pyx_n_s_param
 #define __pyx_n_s_parameters __pyx_mstate_global->__pyx_n_s_parameters
 #define __pyx_n_u_precision __pyx_mstate_global->__pyx_n_u_precision
 #define __pyx_n_s_reconstruct __pyx_mstate_global->__pyx_n_s_reconstruct
+#define __pyx_n_s_return __pyx_mstate_global->__pyx_n_s_return
 #define __pyx_n_u_rows __pyx_mstate_global->__pyx_n_u_rows
-#define __pyx_n_s_shape __pyx_mstate_global->__pyx_n_s_shape
 #define __pyx_n_s_spec __pyx_mstate_global->__pyx_n_s_spec
+#define __pyx_n_s_split __pyx_mstate_global->__pyx_n_s_split
+#define __pyx_n_s_src __pyx_mstate_global->__pyx_n_s_src
 #define __pyx_n_s_status __pyx_mstate_global->__pyx_n_s_status
 #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_uint8 __pyx_mstate_global->__pyx_n_s_uint8
 #define __pyx_n_s_upsample __pyx_mstate_global->__pyx_n_s_upsample
+#define __pyx_kp_u_utf_8 __pyx_mstate_global->__pyx_kp_u_utf_8
 #define __pyx_n_s_zeros __pyx_mstate_global->__pyx_n_s_zeros
+#define __pyx_int_0 __pyx_mstate_global->__pyx_int_0
 #define __pyx_int_8 __pyx_mstate_global->__pyx_int_8
 #define __pyx_tuple_ __pyx_mstate_global->__pyx_tuple_
 #define __pyx_tuple__2 __pyx_mstate_global->__pyx_tuple__2
-#define __pyx_tuple__5 __pyx_mstate_global->__pyx_tuple__5
-#define __pyx_tuple__7 __pyx_mstate_global->__pyx_tuple__7
-#define __pyx_tuple__9 __pyx_mstate_global->__pyx_tuple__9
-#define __pyx_codeobj__6 __pyx_mstate_global->__pyx_codeobj__6
-#define __pyx_codeobj__8 __pyx_mstate_global->__pyx_codeobj__8
-#define __pyx_codeobj__10 __pyx_mstate_global->__pyx_codeobj__10
+#define __pyx_tuple__6 __pyx_mstate_global->__pyx_tuple__6
+#define __pyx_tuple__8 __pyx_mstate_global->__pyx_tuple__8
+#define __pyx_tuple__10 __pyx_mstate_global->__pyx_tuple__10
+#define __pyx_codeobj__7 __pyx_mstate_global->__pyx_codeobj__7
+#define __pyx_codeobj__9 __pyx_mstate_global->__pyx_codeobj__9
+#define __pyx_codeobj__11 __pyx_mstate_global->__pyx_codeobj__11
 /* #### Code section: module_code ### */
 
 /* "string.to_py":31
@@ -3577,7 +3588,7 @@ static CYTHON_INLINE PyObject *__pyx_convert_PyByteArray_string_to_py_std__in_st
   return __pyx_r;
 }
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":245
+/* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":245
  * 
  *         @property
  *         cdef inline PyObject* base(self) nogil:             # <<<<<<<<<<<<<<
@@ -3588,7 +3599,7 @@ static CYTHON_INLINE PyObject *__pyx_convert_PyByteArray_string_to_py_std__in_st
 static CYTHON_INLINE PyObject *__pyx_f_5numpy_7ndarray_4base_base(PyArrayObject *__pyx_v_self) {
   PyObject *__pyx_r;
 
-  /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":248
+  /* "../../../../../tmp/pip-build-env-zlp83btd/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)             # <<<<<<<<<<<<<<
@@ -3598,7 +3609,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_7ndarray_4base_base(PyArrayObject
   __pyx_r = PyArray_BASE(__pyx_v_self);
   goto __pyx_L0;
 
-  /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":245
+  /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":245
  * 
  *         @property
  *         cdef inline PyObject* base(self) nogil:             # <<<<<<<<<<<<<<
@@ -3611,7 +3622,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_7ndarray_4base_base(PyArrayObject
   return __pyx_r;
 }
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":251
+/* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":251
  * 
  *         @property
  *         cdef inline dtype descr(self):             # <<<<<<<<<<<<<<
@@ -3625,7 +3636,7 @@ static CYTHON_INLINE PyArray_Descr *__pyx_f_5numpy_7ndarray_5descr_descr(PyArray
   PyArray_Descr *__pyx_t_1;
   __Pyx_RefNannySetupContext("descr", 1);
 
-  /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":254
+  /* "../../../../../tmp/pip-build-env-zlp83btd/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)             # <<<<<<<<<<<<<<
@@ -3638,7 +3649,7 @@ static CYTHON_INLINE PyArray_Descr *__pyx_f_5numpy_7ndarray_5descr_descr(PyArray
   __pyx_r = ((PyArray_Descr *)__pyx_t_1);
   goto __pyx_L0;
 
-  /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":251
+  /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":251
  * 
  *         @property
  *         cdef inline dtype descr(self):             # <<<<<<<<<<<<<<
@@ -3653,7 +3664,7 @@ static CYTHON_INLINE PyArray_Descr *__pyx_f_5numpy_7ndarray_5descr_descr(PyArray
   return __pyx_r;
 }
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":257
+/* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":257
  * 
  *         @property
  *         cdef inline int ndim(self) nogil:             # <<<<<<<<<<<<<<
@@ -3664,7 +3675,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/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":260
+  /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":260
  *             """Returns the number of dimensions in the array.
  *             """
  *             return PyArray_NDIM(self)             # <<<<<<<<<<<<<<
@@ -3674,7 +3685,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_7ndarray_4ndim_ndim(PyArrayObject *__pyx
   __pyx_r = PyArray_NDIM(__pyx_v_self);
   goto __pyx_L0;
 
-  /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":257
+  /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":257
  * 
  *         @property
  *         cdef inline int ndim(self) nogil:             # <<<<<<<<<<<<<<
@@ -3687,7 +3698,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_7ndarray_4ndim_ndim(PyArrayObject *__pyx
   return __pyx_r;
 }
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":263
+/* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":263
  * 
  *         @property
  *         cdef inline npy_intp *shape(self) nogil:             # <<<<<<<<<<<<<<
@@ -3698,7 +3709,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/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":268
+  /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":268
  *             Can return NULL for 0-dimensional arrays.
  *             """
  *             return PyArray_DIMS(self)             # <<<<<<<<<<<<<<
@@ -3708,7 +3719,7 @@ static CYTHON_INLINE npy_intp *__pyx_f_5numpy_7ndarray_5shape_shape(PyArrayObjec
   __pyx_r = PyArray_DIMS(__pyx_v_self);
   goto __pyx_L0;
 
-  /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":263
+  /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":263
  * 
  *         @property
  *         cdef inline npy_intp *shape(self) nogil:             # <<<<<<<<<<<<<<
@@ -3721,7 +3732,7 @@ static CYTHON_INLINE npy_intp *__pyx_f_5numpy_7ndarray_5shape_shape(PyArrayObjec
   return __pyx_r;
 }
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":271
+/* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":271
  * 
  *         @property
  *         cdef inline npy_intp *strides(self) nogil:             # <<<<<<<<<<<<<<
@@ -3732,7 +3743,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/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":275
+  /* "../../../../../tmp/pip-build-env-zlp83btd/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)             # <<<<<<<<<<<<<<
@@ -3742,7 +3753,7 @@ static CYTHON_INLINE npy_intp *__pyx_f_5numpy_7ndarray_7strides_strides(PyArrayO
   __pyx_r = PyArray_STRIDES(__pyx_v_self);
   goto __pyx_L0;
 
-  /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":271
+  /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":271
  * 
  *         @property
  *         cdef inline npy_intp *strides(self) nogil:             # <<<<<<<<<<<<<<
@@ -3755,7 +3766,7 @@ static CYTHON_INLINE npy_intp *__pyx_f_5numpy_7ndarray_7strides_strides(PyArrayO
   return __pyx_r;
 }
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":278
+/* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":278
  * 
  *         @property
  *         cdef inline npy_intp size(self) nogil:             # <<<<<<<<<<<<<<
@@ -3766,7 +3777,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/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":281
+  /* "../../../../../tmp/pip-build-env-zlp83btd/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)             # <<<<<<<<<<<<<<
@@ -3776,7 +3787,7 @@ static CYTHON_INLINE npy_intp __pyx_f_5numpy_7ndarray_4size_size(PyArrayObject *
   __pyx_r = PyArray_SIZE(__pyx_v_self);
   goto __pyx_L0;
 
-  /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":278
+  /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":278
  * 
  *         @property
  *         cdef inline npy_intp size(self) nogil:             # <<<<<<<<<<<<<<
@@ -3789,7 +3800,7 @@ static CYTHON_INLINE npy_intp __pyx_f_5numpy_7ndarray_4size_size(PyArrayObject *
   return __pyx_r;
 }
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":284
+/* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":284
  * 
  *         @property
  *         cdef inline char* data(self) nogil:             # <<<<<<<<<<<<<<
@@ -3800,7 +3811,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/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":290
+  /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":290
  *             of `PyArray_DATA()` instead, which returns a 'void*'.
  *             """
  *             return PyArray_BYTES(self)             # <<<<<<<<<<<<<<
@@ -3810,7 +3821,7 @@ static CYTHON_INLINE char *__pyx_f_5numpy_7ndarray_4data_data(PyArrayObject *__p
   __pyx_r = PyArray_BYTES(__pyx_v_self);
   goto __pyx_L0;
 
-  /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":284
+  /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":284
  * 
  *         @property
  *         cdef inline char* data(self) nogil:             # <<<<<<<<<<<<<<
@@ -3823,7 +3834,7 @@ static CYTHON_INLINE char *__pyx_f_5numpy_7ndarray_4data_data(PyArrayObject *__p
   return __pyx_r;
 }
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":773
+/* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":776
  * ctypedef npy_cdouble     complex_t
  * 
  * cdef inline object PyArray_MultiIterNew1(a):             # <<<<<<<<<<<<<<
@@ -3840,7 +3851,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("PyArray_MultiIterNew1", 1);
 
-  /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":774
+  /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":777
  * 
  * cdef inline object PyArray_MultiIterNew1(a):
  *     return PyArray_MultiIterNew(1, <void*>a)             # <<<<<<<<<<<<<<
@@ -3848,13 +3859,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__
  * cdef inline object PyArray_MultiIterNew2(a, b):
  */
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 774, __pyx_L1_error)
+  __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 777, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
   __pyx_r = __pyx_t_1;
   __pyx_t_1 = 0;
   goto __pyx_L0;
 
-  /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":773
+  /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":776
  * ctypedef npy_cdouble     complex_t
  * 
  * cdef inline object PyArray_MultiIterNew1(a):             # <<<<<<<<<<<<<<
@@ -3873,7 +3884,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__
   return __pyx_r;
 }
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":776
+/* "../../../../../tmp/pip-build-env-zlp83btd/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):             # <<<<<<<<<<<<<<
@@ -3890,7 +3901,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("PyArray_MultiIterNew2", 1);
 
-  /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":777
+  /* "../../../../../tmp/pip-build-env-zlp83btd/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)             # <<<<<<<<<<<<<<
@@ -3898,13 +3909,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__
  * cdef inline object PyArray_MultiIterNew3(a, b, c):
  */
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 777, __pyx_L1_error)
+  __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 780, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
   __pyx_r = __pyx_t_1;
   __pyx_t_1 = 0;
   goto __pyx_L0;
 
-  /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":776
+  /* "../../../../../tmp/pip-build-env-zlp83btd/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):             # <<<<<<<<<<<<<<
@@ -3923,7 +3934,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__
   return __pyx_r;
 }
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":779
+/* "../../../../../tmp/pip-build-env-zlp83btd/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):             # <<<<<<<<<<<<<<
@@ -3940,7 +3951,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("PyArray_MultiIterNew3", 1);
 
-  /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":780
+  /* "../../../../../tmp/pip-build-env-zlp83btd/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)             # <<<<<<<<<<<<<<
@@ -3948,13 +3959,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__
  * cdef inline object PyArray_MultiIterNew4(a, b, c, d):
  */
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 780, __pyx_L1_error)
+  __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 783, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
   __pyx_r = __pyx_t_1;
   __pyx_t_1 = 0;
   goto __pyx_L0;
 
-  /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":779
+  /* "../../../../../tmp/pip-build-env-zlp83btd/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):             # <<<<<<<<<<<<<<
@@ -3973,7 +3984,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__
   return __pyx_r;
 }
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":782
+/* "../../../../../tmp/pip-build-env-zlp83btd/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):             # <<<<<<<<<<<<<<
@@ -3990,7 +4001,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("PyArray_MultiIterNew4", 1);
 
-  /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":783
+  /* "../../../../../tmp/pip-build-env-zlp83btd/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)             # <<<<<<<<<<<<<<
@@ -3998,13 +4009,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__
  * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e):
  */
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 783, __pyx_L1_error)
+  __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 786, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
   __pyx_r = __pyx_t_1;
   __pyx_t_1 = 0;
   goto __pyx_L0;
 
-  /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":782
+  /* "../../../../../tmp/pip-build-env-zlp83btd/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):             # <<<<<<<<<<<<<<
@@ -4023,7 +4034,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__
   return __pyx_r;
 }
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":785
+/* "../../../../../tmp/pip-build-env-zlp83btd/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):             # <<<<<<<<<<<<<<
@@ -4040,7 +4051,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("PyArray_MultiIterNew5", 1);
 
-  /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":786
+  /* "../../../../../tmp/pip-build-env-zlp83btd/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)             # <<<<<<<<<<<<<<
@@ -4048,13 +4059,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__
  * cdef inline tuple PyDataType_SHAPE(dtype d):
  */
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 786, __pyx_L1_error)
+  __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 789, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
   __pyx_r = __pyx_t_1;
   __pyx_t_1 = 0;
   goto __pyx_L0;
 
-  /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":785
+  /* "../../../../../tmp/pip-build-env-zlp83btd/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):             # <<<<<<<<<<<<<<
@@ -4073,7 +4084,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__
   return __pyx_r;
 }
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":788
+/* "../../../../../tmp/pip-build-env-zlp83btd/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):             # <<<<<<<<<<<<<<
@@ -4087,7 +4098,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__
   int __pyx_t_1;
   __Pyx_RefNannySetupContext("PyDataType_SHAPE", 1);
 
-  /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":789
+  /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":792
  * 
  * cdef inline tuple PyDataType_SHAPE(dtype d):
  *     if PyDataType_HASSUBARRAY(d):             # <<<<<<<<<<<<<<
@@ -4097,7 +4108,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/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":790
+    /* "../../../../../tmp/pip-build-env-zlp83btd/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             # <<<<<<<<<<<<<<
@@ -4109,7 +4120,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__
     __pyx_r = ((PyObject*)__pyx_v_d->subarray->shape);
     goto __pyx_L0;
 
-    /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":789
+    /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":792
  * 
  * cdef inline tuple PyDataType_SHAPE(dtype d):
  *     if PyDataType_HASSUBARRAY(d):             # <<<<<<<<<<<<<<
@@ -4118,7 +4129,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__
  */
   }
 
-  /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":792
+  /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":795
  *         return <tuple>d.subarray.shape
  *     else:
  *         return ()             # <<<<<<<<<<<<<<
@@ -4132,7 +4143,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__
     goto __pyx_L0;
   }
 
-  /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":788
+  /* "../../../../../tmp/pip-build-env-zlp83btd/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):             # <<<<<<<<<<<<<<
@@ -4147,7 +4158,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__
   return __pyx_r;
 }
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":968
+/* "../../../../../tmp/pip-build-env-zlp83btd/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):             # <<<<<<<<<<<<<<
@@ -4156,12 +4167,8 @@ 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) {
-  int __pyx_t_1;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
 
-  /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":969
+  /* "../../../../../tmp/pip-build-env-zlp83btd/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!             # <<<<<<<<<<<<<<
@@ -4170,16 +4177,16 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a
  */
   Py_INCREF(__pyx_v_base);
 
-  /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":970
+  /* "../../../../../tmp/pip-build-env-zlp83btd/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)             # <<<<<<<<<<<<<<
  * 
  * cdef inline object get_array_base(ndarray arr):
  */
-  __pyx_t_1 = PyArray_SetBaseObject(__pyx_v_arr, __pyx_v_base); if (unlikely(__pyx_t_1 == ((int)-1))) __PYX_ERR(1, 970, __pyx_L1_error)
+  (void)(PyArray_SetBaseObject(__pyx_v_arr, __pyx_v_base));
 
-  /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":968
+  /* "../../../../../tmp/pip-build-env-zlp83btd/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):             # <<<<<<<<<<<<<<
@@ -4188,13 +4195,9 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a
  */
 
   /* function exit code */
-  goto __pyx_L0;
-  __pyx_L1_error:;
-  __Pyx_AddTraceback("numpy.set_array_base", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_L0:;
 }
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":972
+/* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":974
  *     PyArray_SetBaseObject(arr, base)
  * 
  * cdef inline object get_array_base(ndarray arr):             # <<<<<<<<<<<<<<
@@ -4209,7 +4212,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py
   int __pyx_t_1;
   __Pyx_RefNannySetupContext("get_array_base", 1);
 
-  /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":973
+  /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":975
  * 
  * cdef inline object get_array_base(ndarray arr):
  *     base = PyArray_BASE(arr)             # <<<<<<<<<<<<<<
@@ -4218,7 +4221,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py
  */
   __pyx_v_base = PyArray_BASE(__pyx_v_arr);
 
-  /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":974
+  /* "../../../../../tmp/pip-build-env-zlp83btd/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:             # <<<<<<<<<<<<<<
@@ -4228,7 +4231,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/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":975
+    /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":977
  *     base = PyArray_BASE(arr)
  *     if base is NULL:
  *         return None             # <<<<<<<<<<<<<<
@@ -4239,7 +4242,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/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":974
+    /* "../../../../../tmp/pip-build-env-zlp83btd/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:             # <<<<<<<<<<<<<<
@@ -4248,7 +4251,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py
  */
   }
 
-  /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":976
+  /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":978
  *     if base is NULL:
  *         return None
  *     return <object>base             # <<<<<<<<<<<<<<
@@ -4260,7 +4263,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py
   __pyx_r = ((PyObject *)__pyx_v_base);
   goto __pyx_L0;
 
-  /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":972
+  /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":974
  *     PyArray_SetBaseObject(arr, base)
  * 
  * cdef inline object get_array_base(ndarray arr):             # <<<<<<<<<<<<<<
@@ -4275,7 +4278,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py
   return __pyx_r;
 }
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":980
+/* "../../../../../tmp/pip-build-env-zlp83btd/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:             # <<<<<<<<<<<<<<
@@ -4299,7 +4302,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) {
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("import_array", 1);
 
-  /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":981
+  /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":983
  * # Cython code.
  * cdef inline int import_array() except -1:
  *     try:             # <<<<<<<<<<<<<<
@@ -4315,16 +4318,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) {
     __Pyx_XGOTREF(__pyx_t_3);
     /*try:*/ {
 
-      /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":982
+      /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":984
  * cdef inline int import_array() except -1:
  *     try:
  *         __pyx_import_array()             # <<<<<<<<<<<<<<
  *     except Exception:
  *         raise ImportError("numpy.core.multiarray failed to import")
  */
-      __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(1, 982, __pyx_L3_error)
+      __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(1, 984, __pyx_L3_error)
 
-      /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":981
+      /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":983
  * # Cython code.
  * cdef inline int import_array() except -1:
  *     try:             # <<<<<<<<<<<<<<
@@ -4338,7 +4341,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) {
     goto __pyx_L8_try_end;
     __pyx_L3_error:;
 
-    /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":983
+    /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":985
  *     try:
  *         __pyx_import_array()
  *     except Exception:             # <<<<<<<<<<<<<<
@@ -4348,27 +4351,27 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) {
     __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0])));
     if (__pyx_t_4) {
       __Pyx_AddTraceback("numpy.import_array", __pyx_clineno, __pyx_lineno, __pyx_filename);
-      if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(1, 983, __pyx_L5_except_error)
+      if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(1, 985, __pyx_L5_except_error)
       __Pyx_XGOTREF(__pyx_t_5);
       __Pyx_XGOTREF(__pyx_t_6);
       __Pyx_XGOTREF(__pyx_t_7);
 
-      /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":984
+      /* "../../../../../tmp/pip-build-env-zlp83btd/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_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple_, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 984, __pyx_L5_except_error)
+      __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple_, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 986, __pyx_L5_except_error)
       __Pyx_GOTREF(__pyx_t_8);
       __Pyx_Raise(__pyx_t_8, 0, 0, 0);
       __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
-      __PYX_ERR(1, 984, __pyx_L5_except_error)
+      __PYX_ERR(1, 986, __pyx_L5_except_error)
     }
     goto __pyx_L5_except_error;
 
-    /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":981
+    /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":983
  * # Cython code.
  * cdef inline int import_array() except -1:
  *     try:             # <<<<<<<<<<<<<<
@@ -4384,7 +4387,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) {
     __pyx_L8_try_end:;
   }
 
-  /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":980
+  /* "../../../../../tmp/pip-build-env-zlp83btd/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:             # <<<<<<<<<<<<<<
@@ -4407,7 +4410,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) {
   return __pyx_r;
 }
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":986
+/* "../../../../../tmp/pip-build-env-zlp83btd/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:             # <<<<<<<<<<<<<<
@@ -4431,7 +4434,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) {
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("import_umath", 1);
 
-  /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":987
+  /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":989
  * 
  * cdef inline int import_umath() except -1:
  *     try:             # <<<<<<<<<<<<<<
@@ -4447,16 +4450,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) {
     __Pyx_XGOTREF(__pyx_t_3);
     /*try:*/ {
 
-      /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":988
+      /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":990
  * cdef inline int import_umath() except -1:
  *     try:
  *         _import_umath()             # <<<<<<<<<<<<<<
  *     except Exception:
  *         raise ImportError("numpy.core.umath failed to import")
  */
-      __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(1, 988, __pyx_L3_error)
+      __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(1, 990, __pyx_L3_error)
 
-      /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":987
+      /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":989
  * 
  * cdef inline int import_umath() except -1:
  *     try:             # <<<<<<<<<<<<<<
@@ -4470,7 +4473,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) {
     goto __pyx_L8_try_end;
     __pyx_L3_error:;
 
-    /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":989
+    /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":991
  *     try:
  *         _import_umath()
  *     except Exception:             # <<<<<<<<<<<<<<
@@ -4480,27 +4483,27 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) {
     __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0])));
     if (__pyx_t_4) {
       __Pyx_AddTraceback("numpy.import_umath", __pyx_clineno, __pyx_lineno, __pyx_filename);
-      if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(1, 989, __pyx_L5_except_error)
+      if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(1, 991, __pyx_L5_except_error)
       __Pyx_XGOTREF(__pyx_t_5);
       __Pyx_XGOTREF(__pyx_t_6);
       __Pyx_XGOTREF(__pyx_t_7);
 
-      /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":990
+      /* "../../../../../tmp/pip-build-env-zlp83btd/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_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__2, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 990, __pyx_L5_except_error)
+      __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__2, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 992, __pyx_L5_except_error)
       __Pyx_GOTREF(__pyx_t_8);
       __Pyx_Raise(__pyx_t_8, 0, 0, 0);
       __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
-      __PYX_ERR(1, 990, __pyx_L5_except_error)
+      __PYX_ERR(1, 992, __pyx_L5_except_error)
     }
     goto __pyx_L5_except_error;
 
-    /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":987
+    /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":989
  * 
  * cdef inline int import_umath() except -1:
  *     try:             # <<<<<<<<<<<<<<
@@ -4516,7 +4519,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) {
     __pyx_L8_try_end:;
   }
 
-  /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":986
+  /* "../../../../../tmp/pip-build-env-zlp83btd/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:             # <<<<<<<<<<<<<<
@@ -4539,7 +4542,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) {
   return __pyx_r;
 }
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":992
+/* "../../../../../tmp/pip-build-env-zlp83btd/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:             # <<<<<<<<<<<<<<
@@ -4563,7 +4566,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) {
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("import_ufunc", 1);
 
-  /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":993
+  /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":995
  * 
  * cdef inline int import_ufunc() except -1:
  *     try:             # <<<<<<<<<<<<<<
@@ -4579,16 +4582,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) {
     __Pyx_XGOTREF(__pyx_t_3);
     /*try:*/ {
 
-      /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":994
+      /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":996
  * cdef inline int import_ufunc() except -1:
  *     try:
  *         _import_umath()             # <<<<<<<<<<<<<<
  *     except Exception:
  *         raise ImportError("numpy.core.umath failed to import")
  */
-      __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(1, 994, __pyx_L3_error)
+      __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(1, 996, __pyx_L3_error)
 
-      /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":993
+      /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":995
  * 
  * cdef inline int import_ufunc() except -1:
  *     try:             # <<<<<<<<<<<<<<
@@ -4602,7 +4605,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) {
     goto __pyx_L8_try_end;
     __pyx_L3_error:;
 
-    /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":995
+    /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":997
  *     try:
  *         _import_umath()
  *     except Exception:             # <<<<<<<<<<<<<<
@@ -4612,27 +4615,27 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) {
     __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0])));
     if (__pyx_t_4) {
       __Pyx_AddTraceback("numpy.import_ufunc", __pyx_clineno, __pyx_lineno, __pyx_filename);
-      if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(1, 995, __pyx_L5_except_error)
+      if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(1, 997, __pyx_L5_except_error)
       __Pyx_XGOTREF(__pyx_t_5);
       __Pyx_XGOTREF(__pyx_t_6);
       __Pyx_XGOTREF(__pyx_t_7);
 
-      /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":996
+      /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":998
  *         _import_umath()
  *     except Exception:
  *         raise ImportError("numpy.core.umath failed to import")             # <<<<<<<<<<<<<<
  * 
  * 
  */
-      __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__2, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 996, __pyx_L5_except_error)
+      __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__2, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 998, __pyx_L5_except_error)
       __Pyx_GOTREF(__pyx_t_8);
       __Pyx_Raise(__pyx_t_8, 0, 0, 0);
       __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
-      __PYX_ERR(1, 996, __pyx_L5_except_error)
+      __PYX_ERR(1, 998, __pyx_L5_except_error)
     }
     goto __pyx_L5_except_error;
 
-    /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":993
+    /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":995
  * 
  * cdef inline int import_ufunc() except -1:
  *     try:             # <<<<<<<<<<<<<<
@@ -4648,7 +4651,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) {
     __pyx_L8_try_end:;
   }
 
-  /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":992
+  /* "../../../../../tmp/pip-build-env-zlp83btd/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:             # <<<<<<<<<<<<<<
@@ -4671,7 +4674,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) {
   return __pyx_r;
 }
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":999
+/* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1001
  * 
  * 
  * cdef inline bint is_timedelta64_object(object obj):             # <<<<<<<<<<<<<<
@@ -4682,7 +4685,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/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":1011
+  /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1013
  *     bool
  *     """
  *     return PyObject_TypeCheck(obj, &PyTimedeltaArrType_Type)             # <<<<<<<<<<<<<<
@@ -4692,7 +4695,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/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":999
+  /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1001
  * 
  * 
  * cdef inline bint is_timedelta64_object(object obj):             # <<<<<<<<<<<<<<
@@ -4705,7 +4708,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_is_timedelta64_object(PyObject *__pyx_v_
   return __pyx_r;
 }
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":1014
+/* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1016
  * 
  * 
  * cdef inline bint is_datetime64_object(object obj):             # <<<<<<<<<<<<<<
@@ -4716,7 +4719,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/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":1026
+  /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1028
  *     bool
  *     """
  *     return PyObject_TypeCheck(obj, &PyDatetimeArrType_Type)             # <<<<<<<<<<<<<<
@@ -4726,7 +4729,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/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":1014
+  /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1016
  * 
  * 
  * cdef inline bint is_datetime64_object(object obj):             # <<<<<<<<<<<<<<
@@ -4739,7 +4742,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_is_datetime64_object(PyObject *__pyx_v_o
   return __pyx_r;
 }
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":1029
+/* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1031
  * 
  * 
  * cdef inline npy_datetime get_datetime64_value(object obj) nogil:             # <<<<<<<<<<<<<<
@@ -4750,7 +4753,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/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":1036
+  /* "../../../../../tmp/pip-build-env-zlp83btd/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             # <<<<<<<<<<<<<<
@@ -4760,7 +4763,7 @@ static CYTHON_INLINE npy_datetime __pyx_f_5numpy_get_datetime64_value(PyObject *
   __pyx_r = ((PyDatetimeScalarObject *)__pyx_v_obj)->obval;
   goto __pyx_L0;
 
-  /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":1029
+  /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1031
  * 
  * 
  * cdef inline npy_datetime get_datetime64_value(object obj) nogil:             # <<<<<<<<<<<<<<
@@ -4773,7 +4776,7 @@ static CYTHON_INLINE npy_datetime __pyx_f_5numpy_get_datetime64_value(PyObject *
   return __pyx_r;
 }
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":1039
+/* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1041
  * 
  * 
  * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil:             # <<<<<<<<<<<<<<
@@ -4784,7 +4787,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/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":1043
+  /* "../../../../../tmp/pip-build-env-zlp83btd/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             # <<<<<<<<<<<<<<
@@ -4794,7 +4797,7 @@ static CYTHON_INLINE npy_timedelta __pyx_f_5numpy_get_timedelta64_value(PyObject
   __pyx_r = ((PyTimedeltaScalarObject *)__pyx_v_obj)->obval;
   goto __pyx_L0;
 
-  /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":1039
+  /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1041
  * 
  * 
  * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil:             # <<<<<<<<<<<<<<
@@ -4807,7 +4810,7 @@ static CYTHON_INLINE npy_timedelta __pyx_f_5numpy_get_timedelta64_value(PyObject
   return __pyx_r;
 }
 
-/* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":1046
+/* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1048
  * 
  * 
  * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil:             # <<<<<<<<<<<<<<
@@ -4818,7 +4821,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/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":1050
+  /* "../../../../../tmp/pip-build-env-zlp83btd/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             # <<<<<<<<<<<<<<
@@ -4826,7 +4829,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/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":1046
+  /* "../../../../../tmp/pip-build-env-zlp83btd/overlay/lib/python3.8/site-packages/numpy/__init__.cython-30.pxd":1048
  * 
  * 
  * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil:             # <<<<<<<<<<<<<<
@@ -4839,12 +4842,12 @@ static CYTHON_INLINE NPY_DATETIMEUNIT __pyx_f_5numpy_get_datetime64_unit(PyObjec
   return __pyx_r;
 }
 
-/* "_libjpeg.pyx":36
- * 
+/* "_libjpeg.pyx":37
  * 
- * def decode(np.ndarray[np.uint8_t, ndim=1] input_buffer, colourspace):             # <<<<<<<<<<<<<<
- *     """Return the decoded JPEG data from `input_buffer`.
  * 
+ * def decode(             # <<<<<<<<<<<<<<
+ *     src: bytes,
+ *     colourspace: int,
  */
 
 /* Python wrapper */
@@ -4855,7 +4858,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_8_libjpeg_decode, "Return the decoded JPEG data from `input_buffer`.\n\n    Parameters\n    ----------\n    input_buffer : numpy.ndarray\n        A 1D array of ``np.uint8`` containing the raw encoded JPEG image.\n    colourspace : int\n        | ``0`` : ``JPGFLAG_MATRIX_COLORTRANSFORMATION_NONE``\n        | ``1`` : ``JPGFLAG_MATRIX_COLORTRANSFORMATION_YCBCR``\n        | ``2`` : ``JPGFLAG_MATRIX_COLORTRANSFORMATION_LSRCT``\n        | ``2`` : ``JPGFLAG_MATRIX_COLORTRANSFORMATION_RCT``\n        | ``3`` : ``JPGFLAG_MATRIX_COLORTRANSFORMATION_FREEFORM``\n\n    Returns\n    -------\n    bytes\n        The status and any error message of the decoding operation.\n    numpy.ndarray or None\n        A 1D array of ``np.uint8`` containing the decoded image data. Returns\n        ``None`` if the decode fails.\n    dict\n        A :class:`dict` containing the image parameters.\n    ");
+PyDoc_STRVAR(__pyx_doc_8_libjpeg_decode, "Return the decoded JPEG data from `input_buffer`.\n\n    Parameters\n    ----------\n    input_buffer : numpy.ndarray\n        A 1D array of ``np.uint8`` containing the raw encoded JPEG image.\n    colourspace : int\n        | ``0`` : ``JPGFLAG_MATRIX_COLORTRANSFORMATION_NONE``\n        | ``1`` : ``JPGFLAG_MATRIX_COLORTRANSFORMATION_YCBCR``\n        | ``2`` : ``JPGFLAG_MATRIX_COLORTRANSFORMATION_LSRCT``\n        | ``2`` : ``JPGFLAG_MATRIX_COLORTRANSFORMATION_RCT``\n        | ``3`` : ``JPGFLAG_MATRIX_COLORTRANSFORMATION_FREEFORM``\n    as_array : bool, optional\n        If ``True`` then return the decoded image data as an ndarray, otherwise\n        (default) return the decoded image data as :class:`bytearray`.\n\n    Returns\n    -------\n    tuple[bytes, bytes | numpy.ndarray | None, dict]\n\n        * The status and any error message of the decoding operation.\n        * The decoded image data (if any) as either bytearray or ndarray\n        * A :class:`dict` containing the image parameters\n    ");
 static PyMethodDef __pyx_mdef_8_libjpeg_1decode = {"decode", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_8_libjpeg_1decode, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_8_libjpeg_decode};
 static PyObject *__pyx_pw_8_libjpeg_1decode(PyObject *__pyx_self, 
 #if CYTHON_METH_FASTCALL
@@ -4864,13 +4867,14 @@ PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds
 PyObject *__pyx_args, PyObject *__pyx_kwds
 #endif
 ) {
-  PyArrayObject *__pyx_v_input_buffer = 0;
+  PyObject *__pyx_v_src = 0;
   PyObject *__pyx_v_colourspace = 0;
+  bool __pyx_v_as_array;
   #if !CYTHON_METH_FASTCALL
   CYTHON_UNUSED Py_ssize_t __pyx_nargs;
   #endif
   CYTHON_UNUSED PyObject *const *__pyx_kwvalues;
-  PyObject* values[2] = {0,0};
+  PyObject* values[3] = {0,0,0};
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
@@ -4886,10 +4890,12 @@ PyObject *__pyx_args, PyObject *__pyx_kwds
   #endif
   __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs);
   {
-    PyObject **__pyx_pyargnames[] = {&__pyx_n_s_input_buffer,&__pyx_n_s_colourspace,0};
+    PyObject **__pyx_pyargnames[] = {&__pyx_n_s_src,&__pyx_n_s_colourspace,&__pyx_n_s_as_array,0};
     if (__pyx_kwds) {
       Py_ssize_t kw_args;
       switch (__pyx_nargs) {
+        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);
@@ -4900,11 +4906,11 @@ PyObject *__pyx_args, PyObject *__pyx_kwds
       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_input_buffer)) != 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(2, 36, __pyx_L3_error)
+        else if (unlikely(PyErr_Occurred())) __PYX_ERR(2, 37, __pyx_L3_error)
         else goto __pyx_L5_argtuple_error;
         CYTHON_FALLTHROUGH;
         case  1:
@@ -4912,27 +4918,51 @@ PyObject *__pyx_args, PyObject *__pyx_kwds
           (void)__Pyx_Arg_NewRef_FASTCALL(values[1]);
           kw_args--;
         }
-        else if (unlikely(PyErr_Occurred())) __PYX_ERR(2, 36, __pyx_L3_error)
+        else if (unlikely(PyErr_Occurred())) __PYX_ERR(2, 37, __pyx_L3_error)
         else {
-          __Pyx_RaiseArgtupleInvalid("decode", 1, 2, 2, 1); __PYX_ERR(2, 36, __pyx_L3_error)
+          __Pyx_RaiseArgtupleInvalid("decode", 0, 2, 3, 1); __PYX_ERR(2, 37, __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(2, 37, __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(2, 36, __pyx_L3_error)
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "decode") < 0)) __PYX_ERR(2, 37, __pyx_L3_error)
       }
-    } else if (unlikely(__pyx_nargs != 2)) {
-      goto __pyx_L5_argtuple_error;
     } else {
-      values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0);
-      values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1);
+      switch (__pyx_nargs) {
+        case  3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2);
+        CYTHON_FALLTHROUGH;
+        case  2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1);
+        values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0);
+        break;
+        default: goto __pyx_L5_argtuple_error;
+      }
+    }
+    __pyx_v_src = ((PyObject*)values[0]);
+    __pyx_v_colourspace = ((PyObject*)values[1]);
+    if (values[2]) {
+      __pyx_v_as_array = __Pyx_PyObject_IsTrue(values[2]); if (unlikely((__pyx_v_as_array == ((bool)-1)) && PyErr_Occurred())) __PYX_ERR(2, 40, __pyx_L3_error)
+    } else {
+
+      /* "_libjpeg.pyx":40
+ *     src: bytes,
+ *     colourspace: int,
+ *     as_array: bool = False,             # <<<<<<<<<<<<<<
+ * ) -> Tuple[bytes, Union[bytes, np.ndarray, None], Dict[str, int]]:
+ *     """Return the decoded JPEG data from `input_buffer`.
+ */
+      __pyx_v_as_array = ((bool)((int)0));
     }
-    __pyx_v_input_buffer = ((PyArrayObject *)values[0]);
-    __pyx_v_colourspace = values[1];
   }
   goto __pyx_L6_skip;
   __pyx_L5_argtuple_error:;
-  __Pyx_RaiseArgtupleInvalid("decode", 1, 2, 2, __pyx_nargs); __PYX_ERR(2, 36, __pyx_L3_error)
+  __Pyx_RaiseArgtupleInvalid("decode", 0, 2, 3, __pyx_nargs); __PYX_ERR(2, 37, __pyx_L3_error)
   __pyx_L6_skip:;
   goto __pyx_L4_argument_unpacking_done;
   __pyx_L3_error:;
@@ -4946,8 +4976,17 @@ PyObject *__pyx_args, PyObject *__pyx_kwds
   __Pyx_RefNannyFinishContext();
   return NULL;
   __pyx_L4_argument_unpacking_done:;
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_input_buffer), __pyx_ptype_5numpy_ndarray, 1, "input_buffer", 0))) __PYX_ERR(2, 36, __pyx_L1_error)
-  __pyx_r = __pyx_pf_8_libjpeg_decode(__pyx_self, __pyx_v_input_buffer, __pyx_v_colourspace);
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_src), (&PyBytes_Type), 0, "src", 1))) __PYX_ERR(2, 38, __pyx_L1_error)
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_colourspace), (&PyInt_Type), 0, "colourspace", 1))) __PYX_ERR(2, 39, __pyx_L1_error)
+  __pyx_r = __pyx_pf_8_libjpeg_decode(__pyx_self, __pyx_v_src, __pyx_v_colourspace, __pyx_v_as_array);
+
+  /* "_libjpeg.pyx":37
+ * 
+ * 
+ * def decode(             # <<<<<<<<<<<<<<
+ *     src: bytes,
+ *     colourspace: int,
+ */
 
   /* function exit code */
   goto __pyx_L0;
@@ -4964,16 +5003,16 @@ PyObject *__pyx_args, PyObject *__pyx_kwds
   return __pyx_r;
 }
 
-static PyObject *__pyx_pf_8_libjpeg_decode(CYTHON_UNUSED PyObject *__pyx_self, PyArrayObject *__pyx_v_input_buffer, PyObject *__pyx_v_colourspace) {
+static PyObject *__pyx_pf_8_libjpeg_decode(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_src, PyObject *__pyx_v_colourspace, bool __pyx_v_as_array) {
   PyObject *__pyx_v_status = NULL;
   PyObject *__pyx_v_param = NULL;
-  char *__pyx_v_pInput;
+  PyObject *__pyx_v_code = NULL;
+  CYTHON_UNUSED PyObject *__pyx_v_msg = NULL;
+  char *__pyx_v_p_in;
   PyObject *__pyx_v_bpp = NULL;
   PyObject *__pyx_v_nr_bytes = NULL;
-  PyObject *__pyx_v_output_buffer = NULL;
-  char *__pyx_v_pOutput;
-  __Pyx_LocalBuf_ND __pyx_pybuffernd_input_buffer;
-  __Pyx_Buffer __pyx_pybuffer_input_buffer;
+  char *__pyx_v_p_out;
+  PyObject *__pyx_v_out = NULL;
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   PyObject *__pyx_t_1 = NULL;
@@ -4982,31 +5021,24 @@ static PyObject *__pyx_pf_8_libjpeg_decode(CYTHON_UNUSED PyObject *__pyx_self, P
   int __pyx_t_4;
   PyObject *__pyx_t_5 = NULL;
   PyObject *(*__pyx_t_6)(PyObject *);
-  PyObject *__pyx_t_7 = NULL;
-  npy_intp *__pyx_t_8;
-  int __pyx_t_9;
+  int __pyx_t_7;
+  char *__pyx_t_8;
+  PyObject *__pyx_t_9 = NULL;
+  Py_ssize_t __pyx_t_10;
+  int __pyx_t_11;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("decode", 1);
-  __pyx_pybuffer_input_buffer.pybuffer.buf = NULL;
-  __pyx_pybuffer_input_buffer.refcount = 0;
-  __pyx_pybuffernd_input_buffer.data = NULL;
-  __pyx_pybuffernd_input_buffer.rcbuffer = &__pyx_pybuffer_input_buffer;
-  {
-    __Pyx_BufFmt_StackElem __pyx_stack[1];
-    if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_input_buffer.rcbuffer->pybuffer, (PyObject*)__pyx_v_input_buffer, &__Pyx_TypeInfo_nn___pyx_t_5numpy_uint8_t, PyBUF_FORMAT| PyBUF_STRIDES, 1, 0, __pyx_stack) == -1)) __PYX_ERR(2, 36, __pyx_L1_error)
-  }
-  __pyx_pybuffernd_input_buffer.diminfo[0].strides = __pyx_pybuffernd_input_buffer.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_input_buffer.diminfo[0].shape = __pyx_pybuffernd_input_buffer.rcbuffer->pybuffer.shape[0];
 
-  /* "_libjpeg.pyx":61
+  /* "_libjpeg.pyx":67
  *     """
  *     # Get the image parameters
- *     status, param = get_parameters(input_buffer)             # <<<<<<<<<<<<<<
- * 
- *     # Pointer to first element in input array
+ *     status, param = get_parameters(src)             # <<<<<<<<<<<<<<
+ *     code, msg = status.decode("utf-8").split("::::")
+ *     if int(code) != 0:
  */
-  __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_get_parameters); if (unlikely(!__pyx_t_2)) __PYX_ERR(2, 61, __pyx_L1_error)
+  __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_get_parameters); if (unlikely(!__pyx_t_2)) __PYX_ERR(2, 67, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
   __pyx_t_3 = NULL;
   __pyx_t_4 = 0;
@@ -5023,10 +5055,10 @@ static PyObject *__pyx_pf_8_libjpeg_decode(CYTHON_UNUSED PyObject *__pyx_self, P
   }
   #endif
   {
-    PyObject *__pyx_callargs[2] = {__pyx_t_3, ((PyObject *)__pyx_v_input_buffer)};
+    PyObject *__pyx_callargs[2] = {__pyx_t_3, __pyx_v_src};
     __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;
-    if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 61, __pyx_L1_error)
+    if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 67, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_1);
     __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
   }
@@ -5036,7 +5068,7 @@ static PyObject *__pyx_pf_8_libjpeg_decode(CYTHON_UNUSED PyObject *__pyx_self, P
     if (unlikely(size != 2)) {
       if (size > 2) __Pyx_RaiseTooManyValuesError(2);
       else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size);
-      __PYX_ERR(2, 61, __pyx_L1_error)
+      __PYX_ERR(2, 67, __pyx_L1_error)
     }
     #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
     if (likely(PyTuple_CheckExact(sequence))) {
@@ -5049,15 +5081,15 @@ static PyObject *__pyx_pf_8_libjpeg_decode(CYTHON_UNUSED PyObject *__pyx_self, P
     __Pyx_INCREF(__pyx_t_2);
     __Pyx_INCREF(__pyx_t_3);
     #else
-    __pyx_t_2 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_2)) __PYX_ERR(2, 61, __pyx_L1_error)
+    __pyx_t_2 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_2)) __PYX_ERR(2, 67, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_2);
-    __pyx_t_3 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 61, __pyx_L1_error)
+    __pyx_t_3 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 67, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_3);
     #endif
     __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
   } else {
     Py_ssize_t index = -1;
-    __pyx_t_5 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_5)) __PYX_ERR(2, 61, __pyx_L1_error)
+    __pyx_t_5 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_5)) __PYX_ERR(2, 67, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_5);
     __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
     __pyx_t_6 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_5);
@@ -5065,7 +5097,7 @@ static PyObject *__pyx_pf_8_libjpeg_decode(CYTHON_UNUSED PyObject *__pyx_self, P
     __Pyx_GOTREF(__pyx_t_2);
     index = 1; __pyx_t_3 = __pyx_t_6(__pyx_t_5); if (unlikely(!__pyx_t_3)) goto __pyx_L3_unpacking_failed;
     __Pyx_GOTREF(__pyx_t_3);
-    if (__Pyx_IternextUnpackEndCheck(__pyx_t_6(__pyx_t_5), 2) < 0) __PYX_ERR(2, 61, __pyx_L1_error)
+    if (__Pyx_IternextUnpackEndCheck(__pyx_t_6(__pyx_t_5), 2) < 0) __PYX_ERR(2, 67, __pyx_L1_error)
     __pyx_t_6 = NULL;
     __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
     goto __pyx_L4_unpacking_done;
@@ -5073,7 +5105,7 @@ static PyObject *__pyx_pf_8_libjpeg_decode(CYTHON_UNUSED PyObject *__pyx_self, P
     __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
     __pyx_t_6 = NULL;
     if (__Pyx_IterFinish() == 0) __Pyx_RaiseNeedMoreValuesError(index);
-    __PYX_ERR(2, 61, __pyx_L1_error)
+    __PYX_ERR(2, 67, __pyx_L1_error)
     __pyx_L4_unpacking_done:;
   }
   __pyx_v_status = __pyx_t_2;
@@ -5081,27 +5113,180 @@ static PyObject *__pyx_pf_8_libjpeg_decode(CYTHON_UNUSED PyObject *__pyx_self, P
   __pyx_v_param = __pyx_t_3;
   __pyx_t_3 = 0;
 
-  /* "_libjpeg.pyx":64
+  /* "_libjpeg.pyx":68
+ *     # Get the image parameters
+ *     status, param = get_parameters(src)
+ *     code, msg = status.decode("utf-8").split("::::")             # <<<<<<<<<<<<<<
+ *     if int(code) != 0:
+ *         return status, None, param
+ */
+  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_status, __pyx_n_s_decode); if (unlikely(!__pyx_t_2)) __PYX_ERR(2, 68, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_5 = NULL;
+  __pyx_t_4 = 0;
+  #if CYTHON_UNPACK_METHODS
+  if (likely(PyMethod_Check(__pyx_t_2))) {
+    __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_2);
+    if (likely(__pyx_t_5)) {
+      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2);
+      __Pyx_INCREF(__pyx_t_5);
+      __Pyx_INCREF(function);
+      __Pyx_DECREF_SET(__pyx_t_2, function);
+      __pyx_t_4 = 1;
+    }
+  }
+  #endif
+  {
+    PyObject *__pyx_callargs[2] = {__pyx_t_5, __pyx_kp_u_utf_8};
+    __pyx_t_3 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+1-__pyx_t_4, 1+__pyx_t_4);
+    __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0;
+    if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 68, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_3);
+    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  }
+  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_split); if (unlikely(!__pyx_t_2)) __PYX_ERR(2, 68, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  __pyx_t_3 = NULL;
+  __pyx_t_4 = 0;
+  #if CYTHON_UNPACK_METHODS
+  if (likely(PyMethod_Check(__pyx_t_2))) {
+    __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2);
+    if (likely(__pyx_t_3)) {
+      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2);
+      __Pyx_INCREF(__pyx_t_3);
+      __Pyx_INCREF(function);
+      __Pyx_DECREF_SET(__pyx_t_2, function);
+      __pyx_t_4 = 1;
+    }
+  }
+  #endif
+  {
+    PyObject *__pyx_callargs[2] = {__pyx_t_3, __pyx_kp_u__3};
+    __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;
+    if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 68, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_1);
+    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  }
+  if ((likely(PyTuple_CheckExact(__pyx_t_1))) || (PyList_CheckExact(__pyx_t_1))) {
+    PyObject* sequence = __pyx_t_1;
+    Py_ssize_t size = __Pyx_PySequence_SIZE(sequence);
+    if (unlikely(size != 2)) {
+      if (size > 2) __Pyx_RaiseTooManyValuesError(2);
+      else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size);
+      __PYX_ERR(2, 68, __pyx_L1_error)
+    }
+    #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
+    if (likely(PyTuple_CheckExact(sequence))) {
+      __pyx_t_2 = PyTuple_GET_ITEM(sequence, 0); 
+      __pyx_t_3 = PyTuple_GET_ITEM(sequence, 1); 
+    } else {
+      __pyx_t_2 = PyList_GET_ITEM(sequence, 0); 
+      __pyx_t_3 = PyList_GET_ITEM(sequence, 1); 
+    }
+    __Pyx_INCREF(__pyx_t_2);
+    __Pyx_INCREF(__pyx_t_3);
+    #else
+    __pyx_t_2 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_2)) __PYX_ERR(2, 68, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_2);
+    __pyx_t_3 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 68, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_3);
+    #endif
+    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  } else {
+    Py_ssize_t index = -1;
+    __pyx_t_5 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_5)) __PYX_ERR(2, 68, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_5);
+    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+    __pyx_t_6 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_5);
+    index = 0; __pyx_t_2 = __pyx_t_6(__pyx_t_5); if (unlikely(!__pyx_t_2)) goto __pyx_L5_unpacking_failed;
+    __Pyx_GOTREF(__pyx_t_2);
+    index = 1; __pyx_t_3 = __pyx_t_6(__pyx_t_5); if (unlikely(!__pyx_t_3)) goto __pyx_L5_unpacking_failed;
+    __Pyx_GOTREF(__pyx_t_3);
+    if (__Pyx_IternextUnpackEndCheck(__pyx_t_6(__pyx_t_5), 2) < 0) __PYX_ERR(2, 68, __pyx_L1_error)
+    __pyx_t_6 = NULL;
+    __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+    goto __pyx_L6_unpacking_done;
+    __pyx_L5_unpacking_failed:;
+    __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+    __pyx_t_6 = NULL;
+    if (__Pyx_IterFinish() == 0) __Pyx_RaiseNeedMoreValuesError(index);
+    __PYX_ERR(2, 68, __pyx_L1_error)
+    __pyx_L6_unpacking_done:;
+  }
+  __pyx_v_code = __pyx_t_2;
+  __pyx_t_2 = 0;
+  __pyx_v_msg = __pyx_t_3;
+  __pyx_t_3 = 0;
+
+  /* "_libjpeg.pyx":69
+ *     status, param = get_parameters(src)
+ *     code, msg = status.decode("utf-8").split("::::")
+ *     if int(code) != 0:             # <<<<<<<<<<<<<<
+ *         return status, None, param
+ * 
+ */
+  __pyx_t_1 = __Pyx_PyNumber_Int(__pyx_v_code); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 69, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_7 = (__Pyx_PyInt_BoolNeObjC(__pyx_t_1, __pyx_int_0, 0, 0)); if (unlikely((__pyx_t_7 < 0))) __PYX_ERR(2, 69, __pyx_L1_error)
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  if (__pyx_t_7) {
+
+    /* "_libjpeg.pyx":70
+ *     code, msg = status.decode("utf-8").split("::::")
+ *     if int(code) != 0:
+ *         return status, None, param             # <<<<<<<<<<<<<<
  * 
  *     # Pointer to first element in input array
- *     cdef char *pInput = <char *>np.PyArray_DATA(input_buffer)             # <<<<<<<<<<<<<<
+ */
+    __Pyx_XDECREF(__pyx_r);
+    __pyx_t_1 = PyTuple_New(3); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 70, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_1);
+    __Pyx_INCREF(__pyx_v_status);
+    __Pyx_GIVEREF(__pyx_v_status);
+    if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_v_status)) __PYX_ERR(2, 70, __pyx_L1_error);
+    __Pyx_INCREF(Py_None);
+    __Pyx_GIVEREF(Py_None);
+    if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 1, Py_None)) __PYX_ERR(2, 70, __pyx_L1_error);
+    __Pyx_INCREF(__pyx_v_param);
+    __Pyx_GIVEREF(__pyx_v_param);
+    if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 2, __pyx_v_param)) __PYX_ERR(2, 70, __pyx_L1_error);
+    __pyx_r = ((PyObject*)__pyx_t_1);
+    __pyx_t_1 = 0;
+    goto __pyx_L0;
+
+    /* "_libjpeg.pyx":69
+ *     status, param = get_parameters(src)
+ *     code, msg = status.decode("utf-8").split("::::")
+ *     if int(code) != 0:             # <<<<<<<<<<<<<<
+ *         return status, None, param
+ * 
+ */
+  }
+
+  /* "_libjpeg.pyx":73
+ * 
+ *     # Pointer to first element in input array
+ *     cdef char* p_in = <char*>src             # <<<<<<<<<<<<<<
  * 
  *     # Create array for output and get pointer to first element
  */
-  __pyx_v_pInput = ((char *)PyArray_DATA(((PyArrayObject *)__pyx_v_input_buffer)));
+  __pyx_t_8 = __Pyx_PyBytes_AsWritableString(__pyx_v_src); if (unlikely((!__pyx_t_8) && PyErr_Occurred())) __PYX_ERR(2, 73, __pyx_L1_error)
+  __pyx_v_p_in = ((char *)__pyx_t_8);
 
-  /* "_libjpeg.pyx":67
+  /* "_libjpeg.pyx":76
  * 
  *     # Create array for output and get pointer to first element
  *     bpp = ceil(param['precision'] / 8)             # <<<<<<<<<<<<<<
  *     nr_bytes = (
  *         param['rows'] * param['columns'] * param['nr_components'] * bpp
  */
-  __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_ceil); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 67, __pyx_L1_error)
+  __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_ceil); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 76, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_3);
-  __pyx_t_2 = __Pyx_PyObject_Dict_GetItem(__pyx_v_param, __pyx_n_u_precision); if (unlikely(!__pyx_t_2)) __PYX_ERR(2, 67, __pyx_L1_error)
+  __pyx_t_2 = __Pyx_PyObject_Dict_GetItem(__pyx_v_param, __pyx_n_u_precision); if (unlikely(!__pyx_t_2)) __PYX_ERR(2, 76, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  __pyx_t_5 = __Pyx_PyInt_TrueDivideObjC(__pyx_t_2, __pyx_int_8, 8, 0, 0); if (unlikely(!__pyx_t_5)) __PYX_ERR(2, 67, __pyx_L1_error)
+  __pyx_t_5 = __Pyx_PyInt_TrueDivideObjC(__pyx_t_2, __pyx_int_8, 8, 0, 0); if (unlikely(!__pyx_t_5)) __PYX_ERR(2, 76, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_5);
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
   __pyx_t_2 = NULL;
@@ -5123,158 +5308,197 @@ static PyObject *__pyx_pf_8_libjpeg_decode(CYTHON_UNUSED PyObject *__pyx_self, P
     __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_3, __pyx_callargs+1-__pyx_t_4, 1+__pyx_t_4);
     __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
     __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
-    if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 67, __pyx_L1_error)
+    if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 76, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_1);
     __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
   }
   __pyx_v_bpp = __pyx_t_1;
   __pyx_t_1 = 0;
 
-  /* "_libjpeg.pyx":69
+  /* "_libjpeg.pyx":78
  *     bpp = ceil(param['precision'] / 8)
  *     nr_bytes = (
  *         param['rows'] * param['columns'] * param['nr_components'] * bpp             # <<<<<<<<<<<<<<
  *     )
- *     output_buffer = np.zeros(nr_bytes, dtype=np.uint8)
+ * 
  */
-  __pyx_t_1 = __Pyx_PyObject_Dict_GetItem(__pyx_v_param, __pyx_n_u_rows); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 69, __pyx_L1_error)
+  __pyx_t_1 = __Pyx_PyObject_Dict_GetItem(__pyx_v_param, __pyx_n_u_rows); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 78, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
-  __pyx_t_3 = __Pyx_PyObject_Dict_GetItem(__pyx_v_param, __pyx_n_u_columns); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 69, __pyx_L1_error)
+  __pyx_t_3 = __Pyx_PyObject_Dict_GetItem(__pyx_v_param, __pyx_n_u_columns); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 78, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_3);
-  __pyx_t_5 = PyNumber_Multiply(__pyx_t_1, __pyx_t_3); if (unlikely(!__pyx_t_5)) __PYX_ERR(2, 69, __pyx_L1_error)
+  __pyx_t_5 = PyNumber_Multiply(__pyx_t_1, __pyx_t_3); if (unlikely(!__pyx_t_5)) __PYX_ERR(2, 78, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_5);
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
   __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-  __pyx_t_3 = __Pyx_PyObject_Dict_GetItem(__pyx_v_param, __pyx_n_u_nr_components); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 69, __pyx_L1_error)
+  __pyx_t_3 = __Pyx_PyObject_Dict_GetItem(__pyx_v_param, __pyx_n_u_nr_components); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 78, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_3);
-  __pyx_t_1 = PyNumber_Multiply(__pyx_t_5, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 69, __pyx_L1_error)
+  __pyx_t_1 = PyNumber_Multiply(__pyx_t_5, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 78, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
   __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
   __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-  __pyx_t_3 = PyNumber_Multiply(__pyx_t_1, __pyx_v_bpp); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 69, __pyx_L1_error)
+  __pyx_t_3 = PyNumber_Multiply(__pyx_t_1, __pyx_v_bpp); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 78, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_3);
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
   __pyx_v_nr_bytes = __pyx_t_3;
   __pyx_t_3 = 0;
 
-  /* "_libjpeg.pyx":71
- *         param['rows'] * param['columns'] * param['nr_components'] * bpp
- *     )
- *     output_buffer = np.zeros(nr_bytes, dtype=np.uint8)             # <<<<<<<<<<<<<<
- *     cdef char *pOutput = <char *>np.PyArray_DATA(output_buffer)
+  /* "_libjpeg.pyx":82
  * 
+ *     cdef char *p_out
+ *     if as_array:             # <<<<<<<<<<<<<<
+ *         out = np.zeros(nr_bytes, dtype=np.uint8)
+ *         p_out = <char *>np.PyArray_DATA(out)
  */
-  __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 71, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_t_3);
-  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_zeros); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 71, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_t_1);
-  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-  __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 71, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_t_3);
-  __Pyx_INCREF(__pyx_v_nr_bytes);
-  __Pyx_GIVEREF(__pyx_v_nr_bytes);
-  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_v_nr_bytes)) __PYX_ERR(2, 71, __pyx_L1_error);
-  __pyx_t_5 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_5)) __PYX_ERR(2, 71, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_t_5);
-  __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(2, 71, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_t_2);
-  __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_uint8); if (unlikely(!__pyx_t_7)) __PYX_ERR(2, 71, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_t_7);
-  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-  if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_dtype, __pyx_t_7) < 0) __PYX_ERR(2, 71, __pyx_L1_error)
-  __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
-  __pyx_t_7 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_3, __pyx_t_5); if (unlikely(!__pyx_t_7)) __PYX_ERR(2, 71, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_t_7);
-  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-  __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
-  __pyx_v_output_buffer = __pyx_t_7;
-  __pyx_t_7 = 0;
+  __pyx_t_7 = (__pyx_v_as_array != 0);
+  if (__pyx_t_7) {
 
-  /* "_libjpeg.pyx":72
- *     )
- *     output_buffer = np.zeros(nr_bytes, dtype=np.uint8)
- *     cdef char *pOutput = <char *>np.PyArray_DATA(output_buffer)             # <<<<<<<<<<<<<<
+    /* "_libjpeg.pyx":83
+ *     cdef char *p_out
+ *     if as_array:
+ *         out = np.zeros(nr_bytes, dtype=np.uint8)             # <<<<<<<<<<<<<<
+ *         p_out = <char *>np.PyArray_DATA(out)
+ *     else:
+ */
+    __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 83, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_3);
+    __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_zeros); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 83, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_1);
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 83, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_3);
+    __Pyx_INCREF(__pyx_v_nr_bytes);
+    __Pyx_GIVEREF(__pyx_v_nr_bytes);
+    if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_v_nr_bytes)) __PYX_ERR(2, 83, __pyx_L1_error);
+    __pyx_t_5 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_5)) __PYX_ERR(2, 83, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_5);
+    __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(2, 83, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_2);
+    __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_uint8); if (unlikely(!__pyx_t_9)) __PYX_ERR(2, 83, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_9);
+    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+    if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_dtype, __pyx_t_9) < 0) __PYX_ERR(2, 83, __pyx_L1_error)
+    __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
+    __pyx_t_9 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_3, __pyx_t_5); if (unlikely(!__pyx_t_9)) __PYX_ERR(2, 83, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_9);
+    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+    __pyx_v_out = __pyx_t_9;
+    __pyx_t_9 = 0;
+
+    /* "_libjpeg.pyx":84
+ *     if as_array:
+ *         out = np.zeros(nr_bytes, dtype=np.uint8)
+ *         p_out = <char *>np.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(2, 84, __pyx_L1_error)
+    __pyx_v_p_out = ((char *)PyArray_DATA(((PyArrayObject *)__pyx_v_out)));
+
+    /* "_libjpeg.pyx":82
+ * 
+ *     cdef char *p_out
+ *     if as_array:             # <<<<<<<<<<<<<<
+ *         out = np.zeros(nr_bytes, dtype=np.uint8)
+ *         p_out = <char *>np.PyArray_DATA(out)
+ */
+    goto __pyx_L8;
+  }
+
+  /* "_libjpeg.pyx":86
+ *         p_out = <char *>np.PyArray_DATA(out)
+ *     else:
+ *         out = bytearray(nr_bytes)             # <<<<<<<<<<<<<<
+ *         p_out = <char *>out
  * 
- *     # Decode the data - output is written to output_buffer
  */
-  if (!(likely(((__pyx_v_output_buffer) == Py_None) || likely(__Pyx_TypeTest(__pyx_v_output_buffer, __pyx_ptype_5numpy_ndarray))))) __PYX_ERR(2, 72, __pyx_L1_error)
-  __pyx_v_pOutput = ((char *)PyArray_DATA(((PyArrayObject *)__pyx_v_output_buffer)));
+  /*else*/ {
+    __pyx_t_9 = __Pyx_PyObject_CallOneArg(((PyObject *)(&PyByteArray_Type)), __pyx_v_nr_bytes); if (unlikely(!__pyx_t_9)) __PYX_ERR(2, 86, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_9);
+    __pyx_v_out = __pyx_t_9;
+    __pyx_t_9 = 0;
 
-  /* "_libjpeg.pyx":78
- *         pInput,
- *         pOutput,
- *         input_buffer.shape[0],             # <<<<<<<<<<<<<<
- *         output_buffer.shape[0],
- *         colourspace
- */
-  __pyx_t_8 = __pyx_f_5numpy_7ndarray_5shape_shape(((PyArrayObject *)__pyx_v_input_buffer)); if (unlikely(__pyx_t_8 == ((npy_intp *)NULL) && PyErr_Occurred())) __PYX_ERR(2, 78, __pyx_L1_error)
-
-  /* "_libjpeg.pyx":79
- *         pOutput,
- *         input_buffer.shape[0],
- *         output_buffer.shape[0],             # <<<<<<<<<<<<<<
- *         colourspace
+    /* "_libjpeg.pyx":87
+ *     else:
+ *         out = bytearray(nr_bytes)
+ *         p_out = <char *>out             # <<<<<<<<<<<<<<
+ * 
+ *     # Decode the data - output is written to output_buffer
+ */
+    __pyx_t_8 = __Pyx_PyObject_AsWritableString(__pyx_v_out); if (unlikely((!__pyx_t_8) && PyErr_Occurred())) __PYX_ERR(2, 87, __pyx_L1_error)
+    __pyx_v_p_out = ((char *)__pyx_t_8);
+  }
+  __pyx_L8:;
+
+  /* "_libjpeg.pyx":93
+ *         p_in,
+ *         p_out,
+ *         len(src),             # <<<<<<<<<<<<<<
+ *         nr_bytes,
+ *         colourspace,
+ */
+  __pyx_t_10 = __Pyx_PyBytes_GET_SIZE(__pyx_v_src); if (unlikely(__pyx_t_10 == ((Py_ssize_t)-1))) __PYX_ERR(2, 93, __pyx_L1_error)
+
+  /* "_libjpeg.pyx":94
+ *         p_out,
+ *         len(src),
+ *         nr_bytes,             # <<<<<<<<<<<<<<
+ *         colourspace,
  *     )
  */
-  __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_v_output_buffer, __pyx_n_s_shape); if (unlikely(!__pyx_t_7)) __PYX_ERR(2, 79, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_t_7);
-  __pyx_t_5 = __Pyx_GetItemInt(__pyx_t_7, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_5)) __PYX_ERR(2, 79, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_t_5);
-  __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
-  __pyx_t_4 = __Pyx_PyInt_As_int(__pyx_t_5); if (unlikely((__pyx_t_4 == (int)-1) && PyErr_Occurred())) __PYX_ERR(2, 79, __pyx_L1_error)
-  __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+  __pyx_t_4 = __Pyx_PyInt_As_int(__pyx_v_nr_bytes); if (unlikely((__pyx_t_4 == (int)-1) && PyErr_Occurred())) __PYX_ERR(2, 94, __pyx_L1_error)
 
-  /* "_libjpeg.pyx":80
- *         input_buffer.shape[0],
- *         output_buffer.shape[0],
- *         colourspace             # <<<<<<<<<<<<<<
+  /* "_libjpeg.pyx":95
+ *         len(src),
+ *         nr_bytes,
+ *         colourspace,             # <<<<<<<<<<<<<<
  *     )
  * 
  */
-  __pyx_t_9 = __Pyx_PyInt_As_int(__pyx_v_colourspace); if (unlikely((__pyx_t_9 == (int)-1) && PyErr_Occurred())) __PYX_ERR(2, 80, __pyx_L1_error)
+  __pyx_t_11 = __Pyx_PyInt_As_int(__pyx_v_colourspace); if (unlikely((__pyx_t_11 == (int)-1) && PyErr_Occurred())) __PYX_ERR(2, 95, __pyx_L1_error)
 
-  /* "_libjpeg.pyx":75
+  /* "_libjpeg.pyx":90
  * 
  *     # Decode the data - output is written to output_buffer
  *     status = Decode(             # <<<<<<<<<<<<<<
- *         pInput,
- *         pOutput,
+ *         p_in,
+ *         p_out,
  */
-  __pyx_t_5 = __pyx_convert_PyBytes_string_to_py_std__in_string(Decode(__pyx_v_pInput, __pyx_v_pOutput, (__pyx_t_8[0]), __pyx_t_4, __pyx_t_9)); if (unlikely(!__pyx_t_5)) __PYX_ERR(2, 75, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_t_5);
-  __Pyx_DECREF_SET(__pyx_v_status, __pyx_t_5);
-  __pyx_t_5 = 0;
+  __pyx_t_9 = __pyx_convert_PyBytes_string_to_py_std__in_string(Decode(__pyx_v_p_in, __pyx_v_p_out, __pyx_t_10, __pyx_t_4, __pyx_t_11)); if (unlikely(!__pyx_t_9)) __PYX_ERR(2, 90, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_9);
+  __Pyx_DECREF_SET(__pyx_v_status, __pyx_t_9);
+  __pyx_t_9 = 0;
 
-  /* "_libjpeg.pyx":83
+  /* "_libjpeg.pyx":98
  *     )
  * 
- *     return status, output_buffer, param             # <<<<<<<<<<<<<<
+ *     return status, out, param             # <<<<<<<<<<<<<<
  * 
  * 
  */
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_5 = PyTuple_New(3); if (unlikely(!__pyx_t_5)) __PYX_ERR(2, 83, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_t_5);
+  __pyx_t_9 = PyTuple_New(3); if (unlikely(!__pyx_t_9)) __PYX_ERR(2, 98, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_9);
   __Pyx_INCREF(__pyx_v_status);
   __Pyx_GIVEREF(__pyx_v_status);
-  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_v_status)) __PYX_ERR(2, 83, __pyx_L1_error);
-  __Pyx_INCREF(__pyx_v_output_buffer);
-  __Pyx_GIVEREF(__pyx_v_output_buffer);
-  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_v_output_buffer)) __PYX_ERR(2, 83, __pyx_L1_error);
+  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_v_status)) __PYX_ERR(2, 98, __pyx_L1_error);
+  __Pyx_INCREF(__pyx_v_out);
+  __Pyx_GIVEREF(__pyx_v_out);
+  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_9, 1, __pyx_v_out)) __PYX_ERR(2, 98, __pyx_L1_error);
   __Pyx_INCREF(__pyx_v_param);
   __Pyx_GIVEREF(__pyx_v_param);
-  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_5, 2, __pyx_v_param)) __PYX_ERR(2, 83, __pyx_L1_error);
-  __pyx_r = __pyx_t_5;
-  __pyx_t_5 = 0;
+  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_9, 2, __pyx_v_param)) __PYX_ERR(2, 98, __pyx_L1_error);
+  __pyx_r = ((PyObject*)__pyx_t_9);
+  __pyx_t_9 = 0;
   goto __pyx_L0;
 
-  /* "_libjpeg.pyx":36
- * 
+  /* "_libjpeg.pyx":37
  * 
- * def decode(np.ndarray[np.uint8_t, ndim=1] input_buffer, colourspace):             # <<<<<<<<<<<<<<
- *     """Return the decoded JPEG data from `input_buffer`.
  * 
+ * def decode(             # <<<<<<<<<<<<<<
+ *     src: bytes,
+ *     colourspace: int,
  */
 
   /* function exit code */
@@ -5283,33 +5507,26 @@ static PyObject *__pyx_pf_8_libjpeg_decode(CYTHON_UNUSED PyObject *__pyx_self, P
   __Pyx_XDECREF(__pyx_t_2);
   __Pyx_XDECREF(__pyx_t_3);
   __Pyx_XDECREF(__pyx_t_5);
-  __Pyx_XDECREF(__pyx_t_7);
-  { PyObject *__pyx_type, *__pyx_value, *__pyx_tb;
-    __Pyx_PyThreadState_declare
-    __Pyx_PyThreadState_assign
-    __Pyx_ErrFetch(&__pyx_type, &__pyx_value, &__pyx_tb);
-    __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_input_buffer.rcbuffer->pybuffer);
-  __Pyx_ErrRestore(__pyx_type, __pyx_value, __pyx_tb);}
+  __Pyx_XDECREF(__pyx_t_9);
   __Pyx_AddTraceback("_libjpeg.decode", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
-  goto __pyx_L2;
   __pyx_L0:;
-  __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_input_buffer.rcbuffer->pybuffer);
-  __pyx_L2:;
   __Pyx_XDECREF(__pyx_v_status);
   __Pyx_XDECREF(__pyx_v_param);
+  __Pyx_XDECREF(__pyx_v_code);
+  __Pyx_XDECREF(__pyx_v_msg);
   __Pyx_XDECREF(__pyx_v_bpp);
   __Pyx_XDECREF(__pyx_v_nr_bytes);
-  __Pyx_XDECREF(__pyx_v_output_buffer);
+  __Pyx_XDECREF(__pyx_v_out);
   __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "_libjpeg.pyx":86
+/* "_libjpeg.pyx":101
  * 
  * 
- * def get_parameters(np.ndarray[np.uint8_t, ndim=1] input_buffer):             # <<<<<<<<<<<<<<
+ * def get_parameters(src: bytes) -> Tuple[int, Dict[str, int]]:             # <<<<<<<<<<<<<<
  *     """Return a :class:`dict` containing the JPEG image parameters.
  * 
  */
@@ -5322,7 +5539,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_8_libjpeg_2get_parameters, "Return a :class:`dict` containing the JPEG image parameters.\n\n    Parameters\n    ----------\n    input_buffer : numpy.ndarray\n        A 1D array of ``np.uint8`` containing the encoded JPEG image.\n\n    Returns\n    -------\n    dict\n        A :class:`dict` containing the JPEG image parameters.\n    ");
+PyDoc_STRVAR(__pyx_doc_8_libjpeg_2get_parameters, "Return a :class:`dict` containing the JPEG image parameters.\n\n    Parameters\n    ----------\n    src : bytes\n        The encoded JPEG image.\n\n    Returns\n    -------\n    dict\n        A :class:`dict` containing the JPEG image parameters.\n    ");
 static PyMethodDef __pyx_mdef_8_libjpeg_3get_parameters = {"get_parameters", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_8_libjpeg_3get_parameters, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_8_libjpeg_2get_parameters};
 static PyObject *__pyx_pw_8_libjpeg_3get_parameters(PyObject *__pyx_self, 
 #if CYTHON_METH_FASTCALL
@@ -5331,7 +5548,7 @@ PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds
 PyObject *__pyx_args, PyObject *__pyx_kwds
 #endif
 ) {
-  PyArrayObject *__pyx_v_input_buffer = 0;
+  PyObject *__pyx_v_src = 0;
   #if !CYTHON_METH_FASTCALL
   CYTHON_UNUSED Py_ssize_t __pyx_nargs;
   #endif
@@ -5352,7 +5569,7 @@ PyObject *__pyx_args, PyObject *__pyx_kwds
   #endif
   __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs);
   {
-    PyObject **__pyx_pyargnames[] = {&__pyx_n_s_input_buffer,0};
+    PyObject **__pyx_pyargnames[] = {&__pyx_n_s_src,0};
     if (__pyx_kwds) {
       Py_ssize_t kw_args;
       switch (__pyx_nargs) {
@@ -5364,27 +5581,27 @@ PyObject *__pyx_args, PyObject *__pyx_kwds
       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_input_buffer)) != 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(2, 86, __pyx_L3_error)
+        else if (unlikely(PyErr_Occurred())) __PYX_ERR(2, 101, __pyx_L3_error)
         else goto __pyx_L5_argtuple_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(2, 86, __pyx_L3_error)
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "get_parameters") < 0)) __PYX_ERR(2, 101, __pyx_L3_error)
       }
     } else if (unlikely(__pyx_nargs != 1)) {
       goto __pyx_L5_argtuple_error;
     } else {
       values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0);
     }
-    __pyx_v_input_buffer = ((PyArrayObject *)values[0]);
+    __pyx_v_src = ((PyObject*)values[0]);
   }
   goto __pyx_L6_skip;
   __pyx_L5_argtuple_error:;
-  __Pyx_RaiseArgtupleInvalid("get_parameters", 1, 1, 1, __pyx_nargs); __PYX_ERR(2, 86, __pyx_L3_error)
+  __Pyx_RaiseArgtupleInvalid("get_parameters", 1, 1, 1, __pyx_nargs); __PYX_ERR(2, 101, __pyx_L3_error)
   __pyx_L6_skip:;
   goto __pyx_L4_argument_unpacking_done;
   __pyx_L3_error:;
@@ -5398,8 +5615,8 @@ PyObject *__pyx_args, PyObject *__pyx_kwds
   __Pyx_RefNannyFinishContext();
   return NULL;
   __pyx_L4_argument_unpacking_done:;
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_input_buffer), __pyx_ptype_5numpy_ndarray, 1, "input_buffer", 0))) __PYX_ERR(2, 86, __pyx_L1_error)
-  __pyx_r = __pyx_pf_8_libjpeg_2get_parameters(__pyx_self, __pyx_v_input_buffer);
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_src), (&PyBytes_Type), 0, "src", 1))) __PYX_ERR(2, 101, __pyx_L1_error)
+  __pyx_r = __pyx_pf_8_libjpeg_2get_parameters(__pyx_self, __pyx_v_src);
 
   /* function exit code */
   goto __pyx_L0;
@@ -5416,34 +5633,24 @@ PyObject *__pyx_args, PyObject *__pyx_kwds
   return __pyx_r;
 }
 
-static PyObject *__pyx_pf_8_libjpeg_2get_parameters(CYTHON_UNUSED PyObject *__pyx_self, PyArrayObject *__pyx_v_input_buffer) {
+static PyObject *__pyx_pf_8_libjpeg_2get_parameters(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_src) {
   struct JPEGParameters __pyx_v_param;
   struct JPEGParameters *__pyx_v_pParam;
-  char *__pyx_v_pInput;
+  char *__pyx_v_p_in;
   std::string __pyx_v_status;
   PyObject *__pyx_v_parameters = NULL;
-  __Pyx_LocalBuf_ND __pyx_pybuffernd_input_buffer;
-  __Pyx_Buffer __pyx_pybuffer_input_buffer;
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
-  npy_intp *__pyx_t_1;
-  PyObject *__pyx_t_2 = NULL;
+  char *__pyx_t_1;
+  Py_ssize_t __pyx_t_2;
   PyObject *__pyx_t_3 = NULL;
+  PyObject *__pyx_t_4 = NULL;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("get_parameters", 1);
-  __pyx_pybuffer_input_buffer.pybuffer.buf = NULL;
-  __pyx_pybuffer_input_buffer.refcount = 0;
-  __pyx_pybuffernd_input_buffer.data = NULL;
-  __pyx_pybuffernd_input_buffer.rcbuffer = &__pyx_pybuffer_input_buffer;
-  {
-    __Pyx_BufFmt_StackElem __pyx_stack[1];
-    if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_input_buffer.rcbuffer->pybuffer, (PyObject*)__pyx_v_input_buffer, &__Pyx_TypeInfo_nn___pyx_t_5numpy_uint8_t, PyBUF_FORMAT| PyBUF_STRIDES, 1, 0, __pyx_stack) == -1)) __PYX_ERR(2, 86, __pyx_L1_error)
-  }
-  __pyx_pybuffernd_input_buffer.diminfo[0].strides = __pyx_pybuffernd_input_buffer.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_input_buffer.diminfo[0].shape = __pyx_pybuffernd_input_buffer.rcbuffer->pybuffer.shape[0];
 
-  /* "_libjpeg.pyx":100
+  /* "_libjpeg.pyx":115
  *     """
  *     cdef JPEGParameters param
  *     param.columns = 0             # <<<<<<<<<<<<<<
@@ -5452,7 +5659,7 @@ static PyObject *__pyx_pf_8_libjpeg_2get_parameters(CYTHON_UNUSED PyObject *__py
  */
   __pyx_v_param.columns = 0;
 
-  /* "_libjpeg.pyx":101
+  /* "_libjpeg.pyx":116
  *     cdef JPEGParameters param
  *     param.columns = 0
  *     param.rows = 0             # <<<<<<<<<<<<<<
@@ -5461,7 +5668,7 @@ static PyObject *__pyx_pf_8_libjpeg_2get_parameters(CYTHON_UNUSED PyObject *__py
  */
   __pyx_v_param.rows = 0;
 
-  /* "_libjpeg.pyx":102
+  /* "_libjpeg.pyx":117
  *     param.columns = 0
  *     param.rows = 0
  *     param.samples_per_pixel = 0             # <<<<<<<<<<<<<<
@@ -5470,7 +5677,7 @@ static PyObject *__pyx_pf_8_libjpeg_2get_parameters(CYTHON_UNUSED PyObject *__py
  */
   __pyx_v_param.samples_per_pixel = 0;
 
-  /* "_libjpeg.pyx":103
+  /* "_libjpeg.pyx":118
  *     param.rows = 0
  *     param.samples_per_pixel = 0
  *     param.bits_per_sample = 0             # <<<<<<<<<<<<<<
@@ -5479,7 +5686,7 @@ static PyObject *__pyx_pf_8_libjpeg_2get_parameters(CYTHON_UNUSED PyObject *__py
  */
   __pyx_v_param.bits_per_sample = 0;
 
-  /* "_libjpeg.pyx":106
+  /* "_libjpeg.pyx":121
  * 
  *     # Pointer to the JPEGParameters object
  *     cdef JPEGParameters *pParam = &param             # <<<<<<<<<<<<<<
@@ -5488,86 +5695,79 @@ static PyObject *__pyx_pf_8_libjpeg_2get_parameters(CYTHON_UNUSED PyObject *__py
  */
   __pyx_v_pParam = (&__pyx_v_param);
 
-  /* "_libjpeg.pyx":109
+  /* "_libjpeg.pyx":124
  * 
  *     # Pointer to first element in input array
- *     cdef char *pInput = <char *>np.PyArray_DATA(input_buffer)             # <<<<<<<<<<<<<<
+ *     cdef char* p_in = <char*>src             # <<<<<<<<<<<<<<
  * 
  *     # Decode the data - output is written to output_buffer
  */
-  __pyx_v_pInput = ((char *)PyArray_DATA(((PyArrayObject *)__pyx_v_input_buffer)));
-
-  /* "_libjpeg.pyx":114
- *     status = GetJPEGParameters(
- *         pInput,
- *         input_buffer.shape[0],             # <<<<<<<<<<<<<<
- *         pParam
- *     )
- */
-  __pyx_t_1 = __pyx_f_5numpy_7ndarray_5shape_shape(((PyArrayObject *)__pyx_v_input_buffer)); if (unlikely(__pyx_t_1 == ((npy_intp *)NULL) && PyErr_Occurred())) __PYX_ERR(2, 114, __pyx_L1_error)
+  __pyx_t_1 = __Pyx_PyBytes_AsWritableString(__pyx_v_src); if (unlikely((!__pyx_t_1) && PyErr_Occurred())) __PYX_ERR(2, 124, __pyx_L1_error)
+  __pyx_v_p_in = ((char *)__pyx_t_1);
 
-  /* "_libjpeg.pyx":112
+  /* "_libjpeg.pyx":127
  * 
  *     # Decode the data - output is written to output_buffer
- *     status = GetJPEGParameters(             # <<<<<<<<<<<<<<
- *         pInput,
- *         input_buffer.shape[0],
+ *     status = GetJPEGParameters(p_in, len(src), pParam)             # <<<<<<<<<<<<<<
+ *     parameters = {
+ *         'rows' : param.rows,
  */
-  __pyx_v_status = GetJPEGParameters(__pyx_v_pInput, (__pyx_t_1[0]), __pyx_v_pParam);
+  __pyx_t_2 = __Pyx_PyBytes_GET_SIZE(__pyx_v_src); if (unlikely(__pyx_t_2 == ((Py_ssize_t)-1))) __PYX_ERR(2, 127, __pyx_L1_error)
+  __pyx_v_status = GetJPEGParameters(__pyx_v_p_in, __pyx_t_2, __pyx_v_pParam);
 
-  /* "_libjpeg.pyx":119
- * 
+  /* "_libjpeg.pyx":129
+ *     status = GetJPEGParameters(p_in, len(src), pParam)
  *     parameters = {
  *         'rows' : param.rows,             # <<<<<<<<<<<<<<
  *         'columns' : param.columns,
  *         'nr_components' : param.samples_per_pixel,
  */
-  __pyx_t_2 = __Pyx_PyDict_NewPresized(4); if (unlikely(!__pyx_t_2)) __PYX_ERR(2, 119, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_t_2);
-  __pyx_t_3 = __Pyx_PyInt_From_long(__pyx_v_param.rows); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 119, __pyx_L1_error)
+  __pyx_t_3 = __Pyx_PyDict_NewPresized(4); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 129, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_3);
-  if (PyDict_SetItem(__pyx_t_2, __pyx_n_u_rows, __pyx_t_3) < 0) __PYX_ERR(2, 119, __pyx_L1_error)
-  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  __pyx_t_4 = __Pyx_PyInt_From_long(__pyx_v_param.rows); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 129, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_4);
+  if (PyDict_SetItem(__pyx_t_3, __pyx_n_u_rows, __pyx_t_4) < 0) __PYX_ERR(2, 129, __pyx_L1_error)
+  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
 
-  /* "_libjpeg.pyx":120
+  /* "_libjpeg.pyx":130
  *     parameters = {
  *         'rows' : param.rows,
  *         'columns' : param.columns,             # <<<<<<<<<<<<<<
  *         'nr_components' : param.samples_per_pixel,
  *         'precision' : param.bits_per_sample,
  */
-  __pyx_t_3 = __Pyx_PyInt_From_long(__pyx_v_param.columns); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 120, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_t_3);
-  if (PyDict_SetItem(__pyx_t_2, __pyx_n_u_columns, __pyx_t_3) < 0) __PYX_ERR(2, 119, __pyx_L1_error)
-  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  __pyx_t_4 = __Pyx_PyInt_From_long(__pyx_v_param.columns); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 130, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_4);
+  if (PyDict_SetItem(__pyx_t_3, __pyx_n_u_columns, __pyx_t_4) < 0) __PYX_ERR(2, 129, __pyx_L1_error)
+  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
 
-  /* "_libjpeg.pyx":121
+  /* "_libjpeg.pyx":131
  *         'rows' : param.rows,
  *         'columns' : param.columns,
  *         'nr_components' : param.samples_per_pixel,             # <<<<<<<<<<<<<<
  *         'precision' : param.bits_per_sample,
  *     }
  */
-  __pyx_t_3 = __Pyx_PyInt_From_int(__pyx_v_param.samples_per_pixel); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 121, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_t_3);
-  if (PyDict_SetItem(__pyx_t_2, __pyx_n_u_nr_components, __pyx_t_3) < 0) __PYX_ERR(2, 119, __pyx_L1_error)
-  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  __pyx_t_4 = __Pyx_PyInt_From_int(__pyx_v_param.samples_per_pixel); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 131, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_4);
+  if (PyDict_SetItem(__pyx_t_3, __pyx_n_u_nr_components, __pyx_t_4) < 0) __PYX_ERR(2, 129, __pyx_L1_error)
+  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
 
-  /* "_libjpeg.pyx":122
+  /* "_libjpeg.pyx":132
  *         'columns' : param.columns,
  *         'nr_components' : param.samples_per_pixel,
  *         'precision' : param.bits_per_sample,             # <<<<<<<<<<<<<<
  *     }
  * 
  */
-  __pyx_t_3 = __Pyx_PyInt_From_char(__pyx_v_param.bits_per_sample); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 122, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_t_3);
-  if (PyDict_SetItem(__pyx_t_2, __pyx_n_u_precision, __pyx_t_3) < 0) __PYX_ERR(2, 119, __pyx_L1_error)
-  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-  __pyx_v_parameters = ((PyObject*)__pyx_t_2);
-  __pyx_t_2 = 0;
+  __pyx_t_4 = __Pyx_PyInt_From_char(__pyx_v_param.bits_per_sample); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 132, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_4);
+  if (PyDict_SetItem(__pyx_t_3, __pyx_n_u_precision, __pyx_t_4) < 0) __PYX_ERR(2, 129, __pyx_L1_error)
+  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+  __pyx_v_parameters = ((PyObject*)__pyx_t_3);
+  __pyx_t_3 = 0;
 
-  /* "_libjpeg.pyx":125
+  /* "_libjpeg.pyx":135
  *     }
  * 
  *     return status, parameters             # <<<<<<<<<<<<<<
@@ -5575,56 +5775,47 @@ static PyObject *__pyx_pf_8_libjpeg_2get_parameters(CYTHON_UNUSED PyObject *__py
  * 
  */
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_2 = __pyx_convert_PyBytes_string_to_py_std__in_string(__pyx_v_status); if (unlikely(!__pyx_t_2)) __PYX_ERR(2, 125, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_t_2);
-  __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 125, __pyx_L1_error)
+  __pyx_t_3 = __pyx_convert_PyBytes_string_to_py_std__in_string(__pyx_v_status); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 135, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_3);
-  __Pyx_GIVEREF(__pyx_t_2);
-  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_2)) __PYX_ERR(2, 125, __pyx_L1_error);
+  __pyx_t_4 = PyTuple_New(2); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 135, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_4);
+  __Pyx_GIVEREF(__pyx_t_3);
+  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_3)) __PYX_ERR(2, 135, __pyx_L1_error);
   __Pyx_INCREF(__pyx_v_parameters);
   __Pyx_GIVEREF(__pyx_v_parameters);
-  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_v_parameters)) __PYX_ERR(2, 125, __pyx_L1_error);
-  __pyx_t_2 = 0;
-  __pyx_r = __pyx_t_3;
+  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_4, 1, __pyx_v_parameters)) __PYX_ERR(2, 135, __pyx_L1_error);
   __pyx_t_3 = 0;
+  __pyx_r = ((PyObject*)__pyx_t_4);
+  __pyx_t_4 = 0;
   goto __pyx_L0;
 
-  /* "_libjpeg.pyx":86
+  /* "_libjpeg.pyx":101
  * 
  * 
- * def get_parameters(np.ndarray[np.uint8_t, ndim=1] input_buffer):             # <<<<<<<<<<<<<<
+ * def get_parameters(src: bytes) -> Tuple[int, Dict[str, int]]:             # <<<<<<<<<<<<<<
  *     """Return a :class:`dict` containing the JPEG image parameters.
  * 
  */
 
   /* function exit code */
   __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_2);
   __Pyx_XDECREF(__pyx_t_3);
-  { PyObject *__pyx_type, *__pyx_value, *__pyx_tb;
-    __Pyx_PyThreadState_declare
-    __Pyx_PyThreadState_assign
-    __Pyx_ErrFetch(&__pyx_type, &__pyx_value, &__pyx_tb);
-    __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_input_buffer.rcbuffer->pybuffer);
-  __Pyx_ErrRestore(__pyx_type, __pyx_value, __pyx_tb);}
+  __Pyx_XDECREF(__pyx_t_4);
   __Pyx_AddTraceback("_libjpeg.get_parameters", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
-  goto __pyx_L2;
   __pyx_L0:;
-  __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_input_buffer.rcbuffer->pybuffer);
-  __pyx_L2:;
   __Pyx_XDECREF(__pyx_v_parameters);
   __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "_libjpeg.pyx":138
+/* "_libjpeg.pyx":148
  * 
  * 
- * def reconstruct(fin, fout, colourspace, falpha, upsample):             # <<<<<<<<<<<<<<
- *     """Decode the JPEG file in `fin` and write it to `fout` as PNM.
- * 
+ * def reconstruct(             # <<<<<<<<<<<<<<
+ *     fin: bytes,
+ *     fout: bytes,
  */
 
 /* Python wrapper */
@@ -5648,7 +5839,7 @@ PyObject *__pyx_args, PyObject *__pyx_kwds
   PyObject *__pyx_v_fout = 0;
   PyObject *__pyx_v_colourspace = 0;
   PyObject *__pyx_v_falpha = 0;
-  PyObject *__pyx_v_upsample = 0;
+  bool __pyx_v_upsample;
   #if !CYTHON_METH_FASTCALL
   CYTHON_UNUSED Py_ssize_t __pyx_nargs;
   #endif
@@ -5693,7 +5884,7 @@ PyObject *__pyx_args, PyObject *__pyx_kwds
           (void)__Pyx_Arg_NewRef_FASTCALL(values[0]);
           kw_args--;
         }
-        else if (unlikely(PyErr_Occurred())) __PYX_ERR(2, 138, __pyx_L3_error)
+        else if (unlikely(PyErr_Occurred())) __PYX_ERR(2, 148, __pyx_L3_error)
         else goto __pyx_L5_argtuple_error;
         CYTHON_FALLTHROUGH;
         case  1:
@@ -5701,9 +5892,9 @@ PyObject *__pyx_args, PyObject *__pyx_kwds
           (void)__Pyx_Arg_NewRef_FASTCALL(values[1]);
           kw_args--;
         }
-        else if (unlikely(PyErr_Occurred())) __PYX_ERR(2, 138, __pyx_L3_error)
+        else if (unlikely(PyErr_Occurred())) __PYX_ERR(2, 148, __pyx_L3_error)
         else {
-          __Pyx_RaiseArgtupleInvalid("reconstruct", 1, 5, 5, 1); __PYX_ERR(2, 138, __pyx_L3_error)
+          __Pyx_RaiseArgtupleInvalid("reconstruct", 1, 5, 5, 1); __PYX_ERR(2, 148, __pyx_L3_error)
         }
         CYTHON_FALLTHROUGH;
         case  2:
@@ -5711,9 +5902,9 @@ PyObject *__pyx_args, PyObject *__pyx_kwds
           (void)__Pyx_Arg_NewRef_FASTCALL(values[2]);
           kw_args--;
         }
-        else if (unlikely(PyErr_Occurred())) __PYX_ERR(2, 138, __pyx_L3_error)
+        else if (unlikely(PyErr_Occurred())) __PYX_ERR(2, 148, __pyx_L3_error)
         else {
-          __Pyx_RaiseArgtupleInvalid("reconstruct", 1, 5, 5, 2); __PYX_ERR(2, 138, __pyx_L3_error)
+          __Pyx_RaiseArgtupleInvalid("reconstruct", 1, 5, 5, 2); __PYX_ERR(2, 148, __pyx_L3_error)
         }
         CYTHON_FALLTHROUGH;
         case  3:
@@ -5721,9 +5912,9 @@ PyObject *__pyx_args, PyObject *__pyx_kwds
           (void)__Pyx_Arg_NewRef_FASTCALL(values[3]);
           kw_args--;
         }
-        else if (unlikely(PyErr_Occurred())) __PYX_ERR(2, 138, __pyx_L3_error)
+        else if (unlikely(PyErr_Occurred())) __PYX_ERR(2, 148, __pyx_L3_error)
         else {
-          __Pyx_RaiseArgtupleInvalid("reconstruct", 1, 5, 5, 3); __PYX_ERR(2, 138, __pyx_L3_error)
+          __Pyx_RaiseArgtupleInvalid("reconstruct", 1, 5, 5, 3); __PYX_ERR(2, 148, __pyx_L3_error)
         }
         CYTHON_FALLTHROUGH;
         case  4:
@@ -5731,14 +5922,14 @@ PyObject *__pyx_args, PyObject *__pyx_kwds
           (void)__Pyx_Arg_NewRef_FASTCALL(values[4]);
           kw_args--;
         }
-        else if (unlikely(PyErr_Occurred())) __PYX_ERR(2, 138, __pyx_L3_error)
+        else if (unlikely(PyErr_Occurred())) __PYX_ERR(2, 148, __pyx_L3_error)
         else {
-          __Pyx_RaiseArgtupleInvalid("reconstruct", 1, 5, 5, 4); __PYX_ERR(2, 138, __pyx_L3_error)
+          __Pyx_RaiseArgtupleInvalid("reconstruct", 1, 5, 5, 4); __PYX_ERR(2, 148, __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, "reconstruct") < 0)) __PYX_ERR(2, 138, __pyx_L3_error)
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "reconstruct") < 0)) __PYX_ERR(2, 148, __pyx_L3_error)
       }
     } else if (unlikely(__pyx_nargs != 5)) {
       goto __pyx_L5_argtuple_error;
@@ -5749,15 +5940,15 @@ PyObject *__pyx_args, PyObject *__pyx_kwds
       values[3] = __Pyx_Arg_FASTCALL(__pyx_args, 3);
       values[4] = __Pyx_Arg_FASTCALL(__pyx_args, 4);
     }
-    __pyx_v_fin = values[0];
-    __pyx_v_fout = values[1];
-    __pyx_v_colourspace = values[2];
+    __pyx_v_fin = ((PyObject*)values[0]);
+    __pyx_v_fout = ((PyObject*)values[1]);
+    __pyx_v_colourspace = ((PyObject*)values[2]);
     __pyx_v_falpha = values[3];
-    __pyx_v_upsample = values[4];
+    __pyx_v_upsample = __Pyx_PyObject_IsTrue(values[4]); if (unlikely((__pyx_v_upsample == ((bool)-1)) && PyErr_Occurred())) __PYX_ERR(2, 153, __pyx_L3_error)
   }
   goto __pyx_L6_skip;
   __pyx_L5_argtuple_error:;
-  __Pyx_RaiseArgtupleInvalid("reconstruct", 1, 5, 5, __pyx_nargs); __PYX_ERR(2, 138, __pyx_L3_error)
+  __Pyx_RaiseArgtupleInvalid("reconstruct", 1, 5, 5, __pyx_nargs); __PYX_ERR(2, 148, __pyx_L3_error)
   __pyx_L6_skip:;
   goto __pyx_L4_argument_unpacking_done;
   __pyx_L3_error:;
@@ -5771,9 +5962,16 @@ PyObject *__pyx_args, PyObject *__pyx_kwds
   __Pyx_RefNannyFinishContext();
   return NULL;
   __pyx_L4_argument_unpacking_done:;
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_fin), (&PyBytes_Type), 0, "fin", 1))) __PYX_ERR(2, 149, __pyx_L1_error)
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_fout), (&PyBytes_Type), 0, "fout", 1))) __PYX_ERR(2, 150, __pyx_L1_error)
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_colourspace), (&PyInt_Type), 0, "colourspace", 1))) __PYX_ERR(2, 151, __pyx_L1_error)
   __pyx_r = __pyx_pf_8_libjpeg_4reconstruct(__pyx_self, __pyx_v_fin, __pyx_v_fout, __pyx_v_colourspace, __pyx_v_falpha, __pyx_v_upsample);
 
   /* 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) {
@@ -5784,21 +5982,20 @@ PyObject *__pyx_args, PyObject *__pyx_kwds
   return __pyx_r;
 }
 
-static PyObject *__pyx_pf_8_libjpeg_4reconstruct(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_fin, PyObject *__pyx_v_fout, PyObject *__pyx_v_colourspace, PyObject *__pyx_v_falpha, PyObject *__pyx_v_upsample) {
+static PyObject *__pyx_pf_8_libjpeg_4reconstruct(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_fin, PyObject *__pyx_v_fout, PyObject *__pyx_v_colourspace, PyObject *__pyx_v_falpha, bool __pyx_v_upsample) {
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   int __pyx_t_1;
   char const *__pyx_t_2;
   char const *__pyx_t_3;
   int __pyx_t_4;
-  bool __pyx_t_5;
-  char const *__pyx_t_6;
+  char const *__pyx_t_5;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("reconstruct", 1);
 
-  /* "_libjpeg.pyx":157
+  /* "_libjpeg.pyx":173
  *         flag.
  *     """
  *     if falpha is None:             # <<<<<<<<<<<<<<
@@ -5808,20 +6005,19 @@ static PyObject *__pyx_pf_8_libjpeg_4reconstruct(CYTHON_UNUSED PyObject *__pyx_s
   __pyx_t_1 = (__pyx_v_falpha == Py_None);
   if (__pyx_t_1) {
 
-    /* "_libjpeg.pyx":158
+    /* "_libjpeg.pyx":174
  *     """
  *     if falpha is None:
  *         Reconstruct(fin, fout, colourspace, NULL, upsample)             # <<<<<<<<<<<<<<
  *     else:
  *         Reconstruct(fin, fout, colourspace, falpha, upsample)
  */
-    __pyx_t_2 = __Pyx_PyObject_AsString(__pyx_v_fin); if (unlikely((!__pyx_t_2) && PyErr_Occurred())) __PYX_ERR(2, 158, __pyx_L1_error)
-    __pyx_t_3 = __Pyx_PyObject_AsString(__pyx_v_fout); if (unlikely((!__pyx_t_3) && PyErr_Occurred())) __PYX_ERR(2, 158, __pyx_L1_error)
-    __pyx_t_4 = __Pyx_PyInt_As_int(__pyx_v_colourspace); if (unlikely((__pyx_t_4 == (int)-1) && PyErr_Occurred())) __PYX_ERR(2, 158, __pyx_L1_error)
-    __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_v_upsample); if (unlikely((__pyx_t_5 == ((bool)-1)) && PyErr_Occurred())) __PYX_ERR(2, 158, __pyx_L1_error)
-    Reconstruct(__pyx_t_2, __pyx_t_3, __pyx_t_4, NULL, __pyx_t_5);
+    __pyx_t_2 = __Pyx_PyBytes_AsString(__pyx_v_fin); if (unlikely((!__pyx_t_2) && PyErr_Occurred())) __PYX_ERR(2, 174, __pyx_L1_error)
+    __pyx_t_3 = __Pyx_PyBytes_AsString(__pyx_v_fout); if (unlikely((!__pyx_t_3) && PyErr_Occurred())) __PYX_ERR(2, 174, __pyx_L1_error)
+    __pyx_t_4 = __Pyx_PyInt_As_int(__pyx_v_colourspace); if (unlikely((__pyx_t_4 == (int)-1) && PyErr_Occurred())) __PYX_ERR(2, 174, __pyx_L1_error)
+    Reconstruct(__pyx_t_2, __pyx_t_3, __pyx_t_4, NULL, __pyx_v_upsample);
 
-    /* "_libjpeg.pyx":157
+    /* "_libjpeg.pyx":173
  *         flag.
  *     """
  *     if falpha is None:             # <<<<<<<<<<<<<<
@@ -5831,27 +6027,26 @@ static PyObject *__pyx_pf_8_libjpeg_4reconstruct(CYTHON_UNUSED PyObject *__pyx_s
     goto __pyx_L3;
   }
 
-  /* "_libjpeg.pyx":160
+  /* "_libjpeg.pyx":176
  *         Reconstruct(fin, fout, colourspace, NULL, upsample)
  *     else:
  *         Reconstruct(fin, fout, colourspace, falpha, upsample)             # <<<<<<<<<<<<<<
  */
   /*else*/ {
-    __pyx_t_2 = __Pyx_PyObject_AsString(__pyx_v_fin); if (unlikely((!__pyx_t_2) && PyErr_Occurred())) __PYX_ERR(2, 160, __pyx_L1_error)
-    __pyx_t_3 = __Pyx_PyObject_AsString(__pyx_v_fout); if (unlikely((!__pyx_t_3) && PyErr_Occurred())) __PYX_ERR(2, 160, __pyx_L1_error)
-    __pyx_t_4 = __Pyx_PyInt_As_int(__pyx_v_colourspace); if (unlikely((__pyx_t_4 == (int)-1) && PyErr_Occurred())) __PYX_ERR(2, 160, __pyx_L1_error)
-    __pyx_t_6 = __Pyx_PyObject_AsString(__pyx_v_falpha); if (unlikely((!__pyx_t_6) && PyErr_Occurred())) __PYX_ERR(2, 160, __pyx_L1_error)
-    __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_v_upsample); if (unlikely((__pyx_t_5 == ((bool)-1)) && PyErr_Occurred())) __PYX_ERR(2, 160, __pyx_L1_error)
-    Reconstruct(__pyx_t_2, __pyx_t_3, __pyx_t_4, __pyx_t_6, __pyx_t_5);
+    __pyx_t_2 = __Pyx_PyBytes_AsString(__pyx_v_fin); if (unlikely((!__pyx_t_2) && PyErr_Occurred())) __PYX_ERR(2, 176, __pyx_L1_error)
+    __pyx_t_3 = __Pyx_PyBytes_AsString(__pyx_v_fout); if (unlikely((!__pyx_t_3) && PyErr_Occurred())) __PYX_ERR(2, 176, __pyx_L1_error)
+    __pyx_t_4 = __Pyx_PyInt_As_int(__pyx_v_colourspace); if (unlikely((__pyx_t_4 == (int)-1) && PyErr_Occurred())) __PYX_ERR(2, 176, __pyx_L1_error)
+    __pyx_t_5 = __Pyx_PyObject_AsString(__pyx_v_falpha); if (unlikely((!__pyx_t_5) && PyErr_Occurred())) __PYX_ERR(2, 176, __pyx_L1_error)
+    Reconstruct(__pyx_t_2, __pyx_t_3, __pyx_t_4, __pyx_t_5, __pyx_v_upsample);
   }
   __pyx_L3:;
 
-  /* "_libjpeg.pyx":138
+  /* "_libjpeg.pyx":148
  * 
  * 
- * def reconstruct(fin, fout, colourspace, falpha, upsample):             # <<<<<<<<<<<<<<
- *     """Decode the JPEG file in `fin` and write it to `fout` as PNM.
- * 
+ * def reconstruct(             # <<<<<<<<<<<<<<
+ *     fin: bytes,
+ *     fout: bytes,
  */
 
   /* function exit code */
@@ -5882,14 +6077,26 @@ static PyMethodDef __pyx_methods[] = {
 
 static int __Pyx_CreateStringTabAndInitStrings(void) {
   __Pyx_StringTabEntry __pyx_string_tab[] = {
+    {&__pyx_n_s_Dict, __pyx_k_Dict, sizeof(__pyx_k_Dict), 0, 0, 1, 1},
     {&__pyx_n_s_ImportError, __pyx_k_ImportError, sizeof(__pyx_k_ImportError), 0, 0, 1, 1},
-    {&__pyx_n_s__11, __pyx_k__11, sizeof(__pyx_k__11), 0, 0, 1, 1},
+    {&__pyx_n_s_None, __pyx_k_None, sizeof(__pyx_k_None), 0, 0, 1, 1},
+    {&__pyx_n_s_Tuple, __pyx_k_Tuple, sizeof(__pyx_k_Tuple), 0, 0, 1, 1},
+    {&__pyx_kp_s_Tuple_bytes_Union_bytes_np_ndarr, __pyx_k_Tuple_bytes_Union_bytes_np_ndarr, sizeof(__pyx_k_Tuple_bytes_Union_bytes_np_ndarr), 0, 0, 1, 0},
+    {&__pyx_kp_s_Tuple_int_Dict_str_int, __pyx_k_Tuple_int_Dict_str_int, sizeof(__pyx_k_Tuple_int_Dict_str_int), 0, 0, 1, 0},
+    {&__pyx_n_s_Union, __pyx_k_Union, sizeof(__pyx_k_Union), 0, 0, 1, 1},
+    {&__pyx_kp_s_Union_bytes_None, __pyx_k_Union_bytes_None, sizeof(__pyx_k_Union_bytes_None), 0, 0, 1, 0},
+    {&__pyx_n_s__12, __pyx_k__12, sizeof(__pyx_k__12), 0, 0, 1, 1},
     {&__pyx_kp_u__3, __pyx_k__3, sizeof(__pyx_k__3), 0, 1, 0, 0},
-    {&__pyx_n_s__4, __pyx_k__4, sizeof(__pyx_k__4), 0, 0, 1, 1},
+    {&__pyx_kp_u__4, __pyx_k__4, sizeof(__pyx_k__4), 0, 1, 0, 0},
+    {&__pyx_n_s__5, __pyx_k__5, sizeof(__pyx_k__5), 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_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_code, __pyx_k_code, sizeof(__pyx_k_code), 0, 0, 1, 1},
     {&__pyx_n_s_colourspace, __pyx_k_colourspace, sizeof(__pyx_k_colourspace), 0, 0, 1, 1},
     {&__pyx_n_u_columns, __pyx_k_columns, sizeof(__pyx_k_columns), 0, 1, 0, 1},
     {&__pyx_n_s_decode, __pyx_k_decode, sizeof(__pyx_k_decode), 0, 0, 1, 1},
@@ -5900,12 +6107,13 @@ static int __Pyx_CreateStringTabAndInitStrings(void) {
     {&__pyx_n_s_get_parameters, __pyx_k_get_parameters, sizeof(__pyx_k_get_parameters), 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_input_buffer, __pyx_k_input_buffer, sizeof(__pyx_k_input_buffer), 0, 0, 1, 1},
+    {&__pyx_n_s_int, __pyx_k_int, sizeof(__pyx_k_int), 0, 0, 1, 1},
     {&__pyx_n_s_is_coroutine, __pyx_k_is_coroutine, sizeof(__pyx_k_is_coroutine), 0, 0, 1, 1},
     {&__pyx_n_s_libjpeg, __pyx_k_libjpeg, sizeof(__pyx_k_libjpeg), 0, 0, 1, 1},
     {&__pyx_kp_s_libjpeg__libjpeg_pyx, __pyx_k_libjpeg__libjpeg_pyx, sizeof(__pyx_k_libjpeg__libjpeg_pyx), 0, 0, 1, 0},
     {&__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_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},
@@ -5913,21 +6121,25 @@ static int __Pyx_CreateStringTabAndInitStrings(void) {
     {&__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_n_s_output_buffer, __pyx_k_output_buffer, sizeof(__pyx_k_output_buffer), 0, 0, 1, 1},
-    {&__pyx_n_s_pInput, __pyx_k_pInput, sizeof(__pyx_k_pInput), 0, 0, 1, 1},
-    {&__pyx_n_s_pOutput, __pyx_k_pOutput, sizeof(__pyx_k_pOutput), 0, 0, 1, 1},
+    {&__pyx_n_s_out, __pyx_k_out, sizeof(__pyx_k_out), 0, 0, 1, 1},
     {&__pyx_n_s_pParam, __pyx_k_pParam, sizeof(__pyx_k_pParam), 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_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_u_precision, __pyx_k_precision, sizeof(__pyx_k_precision), 0, 1, 0, 1},
     {&__pyx_n_s_reconstruct, __pyx_k_reconstruct, sizeof(__pyx_k_reconstruct), 0, 0, 1, 1},
+    {&__pyx_n_s_return, __pyx_k_return, sizeof(__pyx_k_return), 0, 0, 1, 1},
     {&__pyx_n_u_rows, __pyx_k_rows, sizeof(__pyx_k_rows), 0, 1, 0, 1},
-    {&__pyx_n_s_shape, __pyx_k_shape, sizeof(__pyx_k_shape), 0, 0, 1, 1},
     {&__pyx_n_s_spec, __pyx_k_spec, sizeof(__pyx_k_spec), 0, 0, 1, 1},
+    {&__pyx_n_s_split, __pyx_k_split, sizeof(__pyx_k_split), 0, 0, 1, 1},
+    {&__pyx_n_s_src, __pyx_k_src, sizeof(__pyx_k_src), 0, 0, 1, 1},
     {&__pyx_n_s_status, __pyx_k_status, sizeof(__pyx_k_status), 0, 0, 1, 1},
     {&__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_uint8, __pyx_k_uint8, sizeof(__pyx_k_uint8), 0, 0, 1, 1},
     {&__pyx_n_s_upsample, __pyx_k_upsample, sizeof(__pyx_k_upsample), 0, 0, 1, 1},
+    {&__pyx_kp_u_utf_8, __pyx_k_utf_8, sizeof(__pyx_k_utf_8), 0, 1, 0, 0},
     {&__pyx_n_s_zeros, __pyx_k_zeros, sizeof(__pyx_k_zeros), 0, 0, 1, 1},
     {0, 0, 0, 0, 0, 0, 0}
   };
@@ -5935,7 +6147,7 @@ static int __Pyx_CreateStringTabAndInitStrings(void) {
 }
 /* #### Code section: cached_builtins ### */
 static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) {
-  __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(1, 984, __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;
@@ -5946,63 +6158,63 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) {
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__Pyx_InitCachedConstants", 0);
 
-  /* "../../../../../tmp/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":984
+  /* "../../../../../tmp/pip-build-env-zlp83btd/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, 984, __pyx_L1_error)
+  __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/tmp85u0zy6f/.venv/lib/python3.10/site-packages/numpy/__init__.cython-30.pxd":990
+  /* "../../../../../tmp/pip-build-env-zlp83btd/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, 990, __pyx_L1_error)
+  __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);
 
-  /* "_libjpeg.pyx":36
+  /* "_libjpeg.pyx":37
  * 
  * 
- * def decode(np.ndarray[np.uint8_t, ndim=1] input_buffer, colourspace):             # <<<<<<<<<<<<<<
- *     """Return the decoded JPEG data from `input_buffer`.
- * 
+ * def decode(             # <<<<<<<<<<<<<<
+ *     src: bytes,
+ *     colourspace: int,
  */
-  __pyx_tuple__5 = PyTuple_Pack(9, __pyx_n_s_input_buffer, __pyx_n_s_colourspace, __pyx_n_s_status, __pyx_n_s_param, __pyx_n_s_pInput, __pyx_n_s_bpp, __pyx_n_s_nr_bytes, __pyx_n_s_output_buffer, __pyx_n_s_pOutput); if (unlikely(!__pyx_tuple__5)) __PYX_ERR(2, 36, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_tuple__5);
-  __Pyx_GIVEREF(__pyx_tuple__5);
-  __pyx_codeobj__6 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 9, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__5, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_libjpeg__libjpeg_pyx, __pyx_n_s_decode, 36, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__6)) __PYX_ERR(2, 36, __pyx_L1_error)
+  __pyx_tuple__6 = PyTuple_Pack(12, __pyx_n_s_src, __pyx_n_s_colourspace, __pyx_n_s_as_array, __pyx_n_s_status, __pyx_n_s_param, __pyx_n_s_code, __pyx_n_s_msg, __pyx_n_s_p_in, __pyx_n_s_bpp, __pyx_n_s_nr_bytes, __pyx_n_s_p_out, __pyx_n_s_out); if (unlikely(!__pyx_tuple__6)) __PYX_ERR(2, 37, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_tuple__6);
+  __Pyx_GIVEREF(__pyx_tuple__6);
+  __pyx_codeobj__7 = (PyObject*)__Pyx_PyCode_New(3, 0, 0, 12, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__6, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_libjpeg__libjpeg_pyx, __pyx_n_s_decode, 37, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__7)) __PYX_ERR(2, 37, __pyx_L1_error)
 
-  /* "_libjpeg.pyx":86
+  /* "_libjpeg.pyx":101
  * 
  * 
- * def get_parameters(np.ndarray[np.uint8_t, ndim=1] input_buffer):             # <<<<<<<<<<<<<<
+ * def get_parameters(src: bytes) -> Tuple[int, Dict[str, int]]:             # <<<<<<<<<<<<<<
  *     """Return a :class:`dict` containing the JPEG image parameters.
  * 
  */
-  __pyx_tuple__7 = PyTuple_Pack(6, __pyx_n_s_input_buffer, __pyx_n_s_param, __pyx_n_s_pParam, __pyx_n_s_pInput, __pyx_n_s_status, __pyx_n_s_parameters); if (unlikely(!__pyx_tuple__7)) __PYX_ERR(2, 86, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_tuple__7);
-  __Pyx_GIVEREF(__pyx_tuple__7);
-  __pyx_codeobj__8 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 6, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__7, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_libjpeg__libjpeg_pyx, __pyx_n_s_get_parameters, 86, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__8)) __PYX_ERR(2, 86, __pyx_L1_error)
+  __pyx_tuple__8 = PyTuple_Pack(6, __pyx_n_s_src, __pyx_n_s_param, __pyx_n_s_pParam, __pyx_n_s_p_in, __pyx_n_s_status, __pyx_n_s_parameters); if (unlikely(!__pyx_tuple__8)) __PYX_ERR(2, 101, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_tuple__8);
+  __Pyx_GIVEREF(__pyx_tuple__8);
+  __pyx_codeobj__9 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 6, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__8, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_libjpeg__libjpeg_pyx, __pyx_n_s_get_parameters, 101, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__9)) __PYX_ERR(2, 101, __pyx_L1_error)
 
-  /* "_libjpeg.pyx":138
+  /* "_libjpeg.pyx":148
  * 
  * 
- * def reconstruct(fin, fout, colourspace, falpha, upsample):             # <<<<<<<<<<<<<<
- *     """Decode the JPEG file in `fin` and write it to `fout` as PNM.
- * 
+ * def reconstruct(             # <<<<<<<<<<<<<<
+ *     fin: bytes,
+ *     fout: bytes,
  */
-  __pyx_tuple__9 = PyTuple_Pack(5, __pyx_n_s_fin, __pyx_n_s_fout, __pyx_n_s_colourspace, __pyx_n_s_falpha, __pyx_n_s_upsample); if (unlikely(!__pyx_tuple__9)) __PYX_ERR(2, 138, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_tuple__9);
-  __Pyx_GIVEREF(__pyx_tuple__9);
-  __pyx_codeobj__10 = (PyObject*)__Pyx_PyCode_New(5, 0, 0, 5, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__9, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_libjpeg__libjpeg_pyx, __pyx_n_s_reconstruct, 138, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__10)) __PYX_ERR(2, 138, __pyx_L1_error)
+  __pyx_tuple__10 = PyTuple_Pack(5, __pyx_n_s_fin, __pyx_n_s_fout, __pyx_n_s_colourspace, __pyx_n_s_falpha, __pyx_n_s_upsample); if (unlikely(!__pyx_tuple__10)) __PYX_ERR(2, 148, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_tuple__10);
+  __Pyx_GIVEREF(__pyx_tuple__10);
+  __pyx_codeobj__11 = (PyObject*)__Pyx_PyCode_New(5, 0, 0, 5, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__10, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_libjpeg__libjpeg_pyx, __pyx_n_s_reconstruct, 148, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__11)) __PYX_ERR(2, 148, __pyx_L1_error)
   __Pyx_RefNannyFinishContext();
   return 0;
   __pyx_L1_error:;
@@ -6013,6 +6225,7 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) {
 
 static CYTHON_SMALL_CODE int __Pyx_InitConstants(void) {
   if (__Pyx_CreateStringTabAndInitStrings() < 0) __PYX_ERR(2, 1, __pyx_L1_error);
+  __pyx_int_0 = PyInt_FromLong(0); if (unlikely(!__pyx_int_0)) __PYX_ERR(2, 1, __pyx_L1_error)
   __pyx_int_8 = PyInt_FromLong(8); if (unlikely(!__pyx_int_8)) __PYX_ERR(2, 1, __pyx_L1_error)
   return 0;
   __pyx_L1_error:;
@@ -6112,17 +6325,17 @@ static int __Pyx_modinit_type_import_code(void) {
   __pyx_ptype_5numpy_flatiter = __Pyx_ImportType_3_0_7(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_7(PyArrayIterObject),__Pyx_ImportType_CheckSize_Ignore_3_0_7); if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(1, 225, __pyx_L1_error)
   __pyx_ptype_5numpy_broadcast = __Pyx_ImportType_3_0_7(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_7(PyArrayMultiIterObject),__Pyx_ImportType_CheckSize_Ignore_3_0_7); if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(1, 229, __pyx_L1_error)
   __pyx_ptype_5numpy_ndarray = __Pyx_ImportType_3_0_7(__pyx_t_1, "numpy", "ndarray", sizeof(PyArrayObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_7(PyArrayObject),__Pyx_ImportType_CheckSize_Ignore_3_0_7); if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(1, 238, __pyx_L1_error)
-  __pyx_ptype_5numpy_generic = __Pyx_ImportType_3_0_7(__pyx_t_1, "numpy", "generic", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_7(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_7); if (!__pyx_ptype_5numpy_generic) __PYX_ERR(1, 809, __pyx_L1_error)
-  __pyx_ptype_5numpy_number = __Pyx_ImportType_3_0_7(__pyx_t_1, "numpy", "number", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_7(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_7); if (!__pyx_ptype_5numpy_number) __PYX_ERR(1, 811, __pyx_L1_error)
-  __pyx_ptype_5numpy_integer = __Pyx_ImportType_3_0_7(__pyx_t_1, "numpy", "integer", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_7(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_7); if (!__pyx_ptype_5numpy_integer) __PYX_ERR(1, 813, __pyx_L1_error)
-  __pyx_ptype_5numpy_signedinteger = __Pyx_ImportType_3_0_7(__pyx_t_1, "numpy", "signedinteger", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_7(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_7); if (!__pyx_ptype_5numpy_signedinteger) __PYX_ERR(1, 815, __pyx_L1_error)
-  __pyx_ptype_5numpy_unsignedinteger = __Pyx_ImportType_3_0_7(__pyx_t_1, "numpy", "unsignedinteger", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_7(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_7); if (!__pyx_ptype_5numpy_unsignedinteger) __PYX_ERR(1, 817, __pyx_L1_error)
-  __pyx_ptype_5numpy_inexact = __Pyx_ImportType_3_0_7(__pyx_t_1, "numpy", "inexact", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_7(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_7); if (!__pyx_ptype_5numpy_inexact) __PYX_ERR(1, 819, __pyx_L1_error)
-  __pyx_ptype_5numpy_floating = __Pyx_ImportType_3_0_7(__pyx_t_1, "numpy", "floating", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_7(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_7); if (!__pyx_ptype_5numpy_floating) __PYX_ERR(1, 821, __pyx_L1_error)
-  __pyx_ptype_5numpy_complexfloating = __Pyx_ImportType_3_0_7(__pyx_t_1, "numpy", "complexfloating", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_7(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_7); if (!__pyx_ptype_5numpy_complexfloating) __PYX_ERR(1, 823, __pyx_L1_error)
-  __pyx_ptype_5numpy_flexible = __Pyx_ImportType_3_0_7(__pyx_t_1, "numpy", "flexible", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_7(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_7); if (!__pyx_ptype_5numpy_flexible) __PYX_ERR(1, 825, __pyx_L1_error)
-  __pyx_ptype_5numpy_character = __Pyx_ImportType_3_0_7(__pyx_t_1, "numpy", "character", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_7(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_7); if (!__pyx_ptype_5numpy_character) __PYX_ERR(1, 827, __pyx_L1_error)
-  __pyx_ptype_5numpy_ufunc = __Pyx_ImportType_3_0_7(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_7(PyUFuncObject),__Pyx_ImportType_CheckSize_Ignore_3_0_7); if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(1, 866, __pyx_L1_error)
+  __pyx_ptype_5numpy_generic = __Pyx_ImportType_3_0_7(__pyx_t_1, "numpy", "generic", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_7(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_7); if (!__pyx_ptype_5numpy_generic) __PYX_ERR(1, 812, __pyx_L1_error)
+  __pyx_ptype_5numpy_number = __Pyx_ImportType_3_0_7(__pyx_t_1, "numpy", "number", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_7(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_7); if (!__pyx_ptype_5numpy_number) __PYX_ERR(1, 814, __pyx_L1_error)
+  __pyx_ptype_5numpy_integer = __Pyx_ImportType_3_0_7(__pyx_t_1, "numpy", "integer", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_7(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_7); if (!__pyx_ptype_5numpy_integer) __PYX_ERR(1, 816, __pyx_L1_error)
+  __pyx_ptype_5numpy_signedinteger = __Pyx_ImportType_3_0_7(__pyx_t_1, "numpy", "signedinteger", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_7(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_7); if (!__pyx_ptype_5numpy_signedinteger) __PYX_ERR(1, 818, __pyx_L1_error)
+  __pyx_ptype_5numpy_unsignedinteger = __Pyx_ImportType_3_0_7(__pyx_t_1, "numpy", "unsignedinteger", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_7(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_7); if (!__pyx_ptype_5numpy_unsignedinteger) __PYX_ERR(1, 820, __pyx_L1_error)
+  __pyx_ptype_5numpy_inexact = __Pyx_ImportType_3_0_7(__pyx_t_1, "numpy", "inexact", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_7(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_7); if (!__pyx_ptype_5numpy_inexact) __PYX_ERR(1, 822, __pyx_L1_error)
+  __pyx_ptype_5numpy_floating = __Pyx_ImportType_3_0_7(__pyx_t_1, "numpy", "floating", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_7(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_7); if (!__pyx_ptype_5numpy_floating) __PYX_ERR(1, 824, __pyx_L1_error)
+  __pyx_ptype_5numpy_complexfloating = __Pyx_ImportType_3_0_7(__pyx_t_1, "numpy", "complexfloating", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_7(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_7); if (!__pyx_ptype_5numpy_complexfloating) __PYX_ERR(1, 826, __pyx_L1_error)
+  __pyx_ptype_5numpy_flexible = __Pyx_ImportType_3_0_7(__pyx_t_1, "numpy", "flexible", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_7(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_7); if (!__pyx_ptype_5numpy_flexible) __PYX_ERR(1, 828, __pyx_L1_error)
+  __pyx_ptype_5numpy_character = __Pyx_ImportType_3_0_7(__pyx_t_1, "numpy", "character", sizeof(PyObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_7(PyObject),__Pyx_ImportType_CheckSize_Warn_3_0_7); if (!__pyx_ptype_5numpy_character) __PYX_ERR(1, 830, __pyx_L1_error)
+  __pyx_ptype_5numpy_ufunc = __Pyx_ImportType_3_0_7(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __PYX_GET_STRUCT_ALIGNMENT_3_0_7(PyUFuncObject),__Pyx_ImportType_CheckSize_Ignore_3_0_7); 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;
@@ -6312,6 +6525,7 @@ static CYTHON_SMALL_CODE int __pyx_pymod_exec__libjpeg(PyObject *__pyx_pyinit_mo
   PyObject *__pyx_t_1 = NULL;
   PyObject *__pyx_t_2 = NULL;
   PyObject *__pyx_t_3 = NULL;
+  PyObject *__pyx_t_4 = NULL;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
@@ -6431,8 +6645,8 @@ if (!__Pyx_RefNanny) {
  * # distutils: language=c++
  * 
  * from math import ceil             # <<<<<<<<<<<<<<
+ * from typing import Union, Dict, Tuple
  * 
- * from libcpp cimport bool
  */
   __pyx_t_2 = PyList_New(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(2, 4, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
@@ -6448,63 +6662,139 @@ if (!__Pyx_RefNanny) {
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
   __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
 
-  /* "_libjpeg.pyx":9
- * from libcpp.string cimport string
+  /* "_libjpeg.pyx":5
  * 
- * import numpy as np             # <<<<<<<<<<<<<<
- * cimport numpy as np
+ * from math import ceil
+ * from typing import Union, Dict, Tuple             # <<<<<<<<<<<<<<
  * 
+ * from libcpp cimport bool
  */
-  __pyx_t_3 = __Pyx_ImportDottedModule(__pyx_n_s_numpy, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 9, __pyx_L1_error)
+  __pyx_t_3 = PyList_New(3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 5, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_3);
+  __Pyx_INCREF(__pyx_n_s_Union);
+  __Pyx_GIVEREF(__pyx_n_s_Union);
+  if (__Pyx_PyList_SET_ITEM(__pyx_t_3, 0, __pyx_n_s_Union)) __PYX_ERR(2, 5, __pyx_L1_error);
+  __Pyx_INCREF(__pyx_n_s_Dict);
+  __Pyx_GIVEREF(__pyx_n_s_Dict);
+  if (__Pyx_PyList_SET_ITEM(__pyx_t_3, 1, __pyx_n_s_Dict)) __PYX_ERR(2, 5, __pyx_L1_error);
+  __Pyx_INCREF(__pyx_n_s_Tuple);
+  __Pyx_GIVEREF(__pyx_n_s_Tuple);
+  if (__Pyx_PyList_SET_ITEM(__pyx_t_3, 2, __pyx_n_s_Tuple)) __PYX_ERR(2, 5, __pyx_L1_error);
+  __pyx_t_2 = __Pyx_Import(__pyx_n_s_typing, __pyx_t_3, 0); if (unlikely(!__pyx_t_2)) __PYX_ERR(2, 5, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  __pyx_t_3 = __Pyx_ImportFrom(__pyx_t_2, __pyx_n_s_Union); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 5, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_3);
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_Union, __pyx_t_3) < 0) __PYX_ERR(2, 5, __pyx_L1_error)
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  __pyx_t_3 = __Pyx_ImportFrom(__pyx_t_2, __pyx_n_s_Dict); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 5, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_3);
-  if (PyDict_SetItem(__pyx_d, __pyx_n_s_np, __pyx_t_3) < 0) __PYX_ERR(2, 9, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_Dict, __pyx_t_3) < 0) __PYX_ERR(2, 5, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  __pyx_t_3 = __Pyx_ImportFrom(__pyx_t_2, __pyx_n_s_Tuple); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 5, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_3);
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_Tuple, __pyx_t_3) < 0) __PYX_ERR(2, 5, __pyx_L1_error)
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 
-  /* "_libjpeg.pyx":36
+  /* "_libjpeg.pyx":10
+ * from libcpp.string cimport string
  * 
+ * import numpy as np             # <<<<<<<<<<<<<<
+ * cimport numpy as np
  * 
- * def decode(np.ndarray[np.uint8_t, ndim=1] input_buffer, colourspace):             # <<<<<<<<<<<<<<
+ */
+  __pyx_t_2 = __Pyx_ImportDottedModule(__pyx_n_s_numpy, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(2, 10, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_2);
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_np, __pyx_t_2) < 0) __PYX_ERR(2, 10, __pyx_L1_error)
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+
+  /* "_libjpeg.pyx":40
+ *     src: bytes,
+ *     colourspace: int,
+ *     as_array: bool = False,             # <<<<<<<<<<<<<<
+ * ) -> Tuple[bytes, Union[bytes, np.ndarray, None], Dict[str, int]]:
  *     """Return the decoded JPEG data from `input_buffer`.
+ */
+  __pyx_t_2 = __Pyx_PyBool_FromLong(((int)0)); if (unlikely(!__pyx_t_2)) __PYX_ERR(2, 40, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_2);
+
+  /* "_libjpeg.pyx":37
+ * 
  * 
+ * def decode(             # <<<<<<<<<<<<<<
+ *     src: bytes,
+ *     colourspace: int,
  */
-  __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_8_libjpeg_1decode, 0, __pyx_n_s_decode, NULL, __pyx_n_s_libjpeg, __pyx_d, ((PyObject *)__pyx_codeobj__6)); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 36, __pyx_L1_error)
+  __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 37, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_3);
-  if (PyDict_SetItem(__pyx_d, __pyx_n_s_decode, __pyx_t_3) < 0) __PYX_ERR(2, 36, __pyx_L1_error)
+  __Pyx_GIVEREF(__pyx_t_2);
+  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_2)) __PYX_ERR(2, 37, __pyx_L1_error);
+  __pyx_t_2 = 0;
+  __pyx_t_2 = __Pyx_PyDict_NewPresized(4); if (unlikely(!__pyx_t_2)) __PYX_ERR(2, 37, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_2);
+  if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_src, __pyx_n_s_bytes) < 0) __PYX_ERR(2, 37, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_colourspace, __pyx_n_s_int) < 0) __PYX_ERR(2, 37, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_as_array, __pyx_n_s_bool) < 0) __PYX_ERR(2, 37, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_return, __pyx_kp_s_Tuple_bytes_Union_bytes_np_ndarr) < 0) __PYX_ERR(2, 37, __pyx_L1_error)
+  __pyx_t_4 = __Pyx_CyFunction_New(&__pyx_mdef_8_libjpeg_1decode, 0, __pyx_n_s_decode, NULL, __pyx_n_s_libjpeg, __pyx_d, ((PyObject *)__pyx_codeobj__7)); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 37, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_4);
+  __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_4, __pyx_t_3);
+  __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_4, __pyx_t_2);
   __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_decode, __pyx_t_4) < 0) __PYX_ERR(2, 37, __pyx_L1_error)
+  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
 
-  /* "_libjpeg.pyx":86
+  /* "_libjpeg.pyx":101
  * 
  * 
- * def get_parameters(np.ndarray[np.uint8_t, ndim=1] input_buffer):             # <<<<<<<<<<<<<<
+ * def get_parameters(src: bytes) -> Tuple[int, Dict[str, int]]:             # <<<<<<<<<<<<<<
  *     """Return a :class:`dict` containing the JPEG image parameters.
  * 
  */
-  __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_8_libjpeg_3get_parameters, 0, __pyx_n_s_get_parameters, NULL, __pyx_n_s_libjpeg, __pyx_d, ((PyObject *)__pyx_codeobj__8)); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 86, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_t_3);
-  if (PyDict_SetItem(__pyx_d, __pyx_n_s_get_parameters, __pyx_t_3) < 0) __PYX_ERR(2, 86, __pyx_L1_error)
-  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  __pyx_t_4 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 101, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_4);
+  if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_src, __pyx_n_s_bytes) < 0) __PYX_ERR(2, 101, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_return, __pyx_kp_s_Tuple_int_Dict_str_int) < 0) __PYX_ERR(2, 101, __pyx_L1_error)
+  __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_8_libjpeg_3get_parameters, 0, __pyx_n_s_get_parameters, NULL, __pyx_n_s_libjpeg, __pyx_d, ((PyObject *)__pyx_codeobj__9)); if (unlikely(!__pyx_t_2)) __PYX_ERR(2, 101, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_2, __pyx_t_4);
+  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_get_parameters, __pyx_t_2) < 0) __PYX_ERR(2, 101, __pyx_L1_error)
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 
-  /* "_libjpeg.pyx":138
+  /* "_libjpeg.pyx":148
  * 
  * 
- * def reconstruct(fin, fout, colourspace, falpha, upsample):             # <<<<<<<<<<<<<<
- *     """Decode the JPEG file in `fin` and write it to `fout` as PNM.
- * 
+ * def reconstruct(             # <<<<<<<<<<<<<<
+ *     fin: bytes,
+ *     fout: bytes,
  */
-  __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_8_libjpeg_5reconstruct, 0, __pyx_n_s_reconstruct, NULL, __pyx_n_s_libjpeg, __pyx_d, ((PyObject *)__pyx_codeobj__10)); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 138, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_t_3);
-  if (PyDict_SetItem(__pyx_d, __pyx_n_s_reconstruct, __pyx_t_3) < 0) __PYX_ERR(2, 138, __pyx_L1_error)
-  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  __pyx_t_2 = __Pyx_PyDict_NewPresized(6); if (unlikely(!__pyx_t_2)) __PYX_ERR(2, 148, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_2);
+  if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_fin, __pyx_n_s_bytes) < 0) __PYX_ERR(2, 148, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_fout, __pyx_n_s_bytes) < 0) __PYX_ERR(2, 148, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_colourspace, __pyx_n_s_int) < 0) __PYX_ERR(2, 148, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_falpha, __pyx_kp_s_Union_bytes_None) < 0) __PYX_ERR(2, 148, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_upsample, __pyx_n_s_bool) < 0) __PYX_ERR(2, 148, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_return, __pyx_n_s_None) < 0) __PYX_ERR(2, 148, __pyx_L1_error)
+  __pyx_t_4 = __Pyx_CyFunction_New(&__pyx_mdef_8_libjpeg_5reconstruct, 0, __pyx_n_s_reconstruct, NULL, __pyx_n_s_libjpeg, __pyx_d, ((PyObject *)__pyx_codeobj__11)); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 148, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_4);
+  __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_4, __pyx_t_2);
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_reconstruct, __pyx_t_4) < 0) __PYX_ERR(2, 148, __pyx_L1_error)
+  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
 
   /* "_libjpeg.pyx":1
  * # cython: language_level=3             # <<<<<<<<<<<<<<
  * # distutils: language=c++
  * 
  */
-  __pyx_t_3 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 1, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_t_3);
-  if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_3) < 0) __PYX_ERR(2, 1, __pyx_L1_error)
-  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  __pyx_t_4 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 1, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_4);
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_4) < 0) __PYX_ERR(2, 1, __pyx_L1_error)
+  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
 
   /*--- Wrapped vars code ---*/
 
@@ -6512,6 +6802,7 @@ if (!__Pyx_RefNanny) {
   __pyx_L1_error:;
   __Pyx_XDECREF(__pyx_t_2);
   __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_XDECREF(__pyx_t_4);
   if (__pyx_m) {
     if (__pyx_d && stringtab_initialized) {
       __Pyx_AddTraceback("init _libjpeg", __pyx_clineno, __pyx_lineno, __pyx_filename);
@@ -7511,610 +7802,42 @@ static int __Pyx_ParseOptionalKeywords(
     PyErr_Format(PyExc_TypeError,
         "%s() got an unexpected keyword argument '%U'",
         function_name, key);
-    #endif
-bad:
-    Py_XDECREF(key);
-    Py_XDECREF(value);
-    return -1;
-}
-
-/* ArgTypeTest */
-static int __Pyx__ArgTypeTest(PyObject *obj, PyTypeObject *type, const char *name, int exact)
-{
-    __Pyx_TypeName type_name;
-    __Pyx_TypeName obj_type_name;
-    if (unlikely(!type)) {
-        PyErr_SetString(PyExc_SystemError, "Missing type object");
-        return 0;
-    }
-    else if (exact) {
-        #if PY_MAJOR_VERSION == 2
-        if ((type == &PyBaseString_Type) && likely(__Pyx_PyBaseString_CheckExact(obj))) return 1;
-        #endif
-    }
-    else {
-        if (likely(__Pyx_TypeCheck(obj, type))) return 1;
-    }
-    type_name = __Pyx_PyType_GetName(type);
-    obj_type_name = __Pyx_PyType_GetName(Py_TYPE(obj));
-    PyErr_Format(PyExc_TypeError,
-        "Argument '%.200s' has incorrect type (expected " __Pyx_FMT_TYPENAME
-        ", got " __Pyx_FMT_TYPENAME ")", name, type_name, obj_type_name);
-    __Pyx_DECREF_TypeName(type_name);
-    __Pyx_DECREF_TypeName(obj_type_name);
-    return 0;
-}
-
-/* IsLittleEndian */
-static CYTHON_INLINE int __Pyx_Is_Little_Endian(void)
-{
-  union {
-    uint32_t u32;
-    uint8_t u8[4];
-  } S;
-  S.u32 = 0x01020304;
-  return S.u8[0] == 4;
-}
-
-/* BufferFormatCheck */
-static void __Pyx_BufFmt_Init(__Pyx_BufFmt_Context* ctx,
-                              __Pyx_BufFmt_StackElem* stack,
-                              __Pyx_TypeInfo* type) {
-  stack[0].field = &ctx->root;
-  stack[0].parent_offset = 0;
-  ctx->root.type = type;
-  ctx->root.name = "buffer dtype";
-  ctx->root.offset = 0;
-  ctx->head = stack;
-  ctx->head->field = &ctx->root;
-  ctx->fmt_offset = 0;
-  ctx->head->parent_offset = 0;
-  ctx->new_packmode = '@';
-  ctx->enc_packmode = '@';
-  ctx->new_count = 1;
-  ctx->enc_count = 0;
-  ctx->enc_type = 0;
-  ctx->is_complex = 0;
-  ctx->is_valid_array = 0;
-  ctx->struct_alignment = 0;
-  while (type->typegroup == 'S') {
-    ++ctx->head;
-    ctx->head->field = type->fields;
-    ctx->head->parent_offset = 0;
-    type = type->fields->type;
-  }
-}
-static int __Pyx_BufFmt_ParseNumber(const char** ts) {
-    int count;
-    const char* t = *ts;
-    if (*t < '0' || *t > '9') {
-      return -1;
-    } else {
-        count = *t++ - '0';
-        while (*t >= '0' && *t <= '9') {
-            count *= 10;
-            count += *t++ - '0';
-        }
-    }
-    *ts = t;
-    return count;
-}
-static int __Pyx_BufFmt_ExpectNumber(const char **ts) {
-    int number = __Pyx_BufFmt_ParseNumber(ts);
-    if (number == -1)
-        PyErr_Format(PyExc_ValueError,\
-                     "Does not understand character buffer dtype format string ('%c')", **ts);
-    return number;
-}
-static void __Pyx_BufFmt_RaiseUnexpectedChar(char ch) {
-  PyErr_Format(PyExc_ValueError,
-               "Unexpected format string character: '%c'", ch);
-}
-static const char* __Pyx_BufFmt_DescribeTypeChar(char ch, int is_complex) {
-  switch (ch) {
-    case '?': return "'bool'";
-    case 'c': return "'char'";
-    case 'b': return "'signed char'";
-    case 'B': return "'unsigned char'";
-    case 'h': return "'short'";
-    case 'H': return "'unsigned short'";
-    case 'i': return "'int'";
-    case 'I': return "'unsigned int'";
-    case 'l': return "'long'";
-    case 'L': return "'unsigned long'";
-    case 'q': return "'long long'";
-    case 'Q': return "'unsigned long long'";
-    case 'f': return (is_complex ? "'complex float'" : "'float'");
-    case 'd': return (is_complex ? "'complex double'" : "'double'");
-    case 'g': return (is_complex ? "'complex long double'" : "'long double'");
-    case 'T': return "a struct";
-    case 'O': return "Python object";
-    case 'P': return "a pointer";
-    case 's': case 'p': return "a string";
-    case 0: return "end";
-    default: return "unparsable format string";
-  }
-}
-static size_t __Pyx_BufFmt_TypeCharToStandardSize(char ch, int is_complex) {
-  switch (ch) {
-    case '?': case 'c': case 'b': case 'B': case 's': case 'p': return 1;
-    case 'h': case 'H': return 2;
-    case 'i': case 'I': case 'l': case 'L': return 4;
-    case 'q': case 'Q': return 8;
-    case 'f': return (is_complex ? 8 : 4);
-    case 'd': return (is_complex ? 16 : 8);
-    case 'g': {
-      PyErr_SetString(PyExc_ValueError, "Python does not define a standard format string size for long double ('g')..");
-      return 0;
-    }
-    case 'O': case 'P': return sizeof(void*);
-    default:
-      __Pyx_BufFmt_RaiseUnexpectedChar(ch);
-      return 0;
-    }
-}
-static size_t __Pyx_BufFmt_TypeCharToNativeSize(char ch, int is_complex) {
-  switch (ch) {
-    case '?': case 'c': case 'b': case 'B': case 's': case 'p': return 1;
-    case 'h': case 'H': return sizeof(short);
-    case 'i': case 'I': return sizeof(int);
-    case 'l': case 'L': return sizeof(long);
-    #ifdef HAVE_LONG_LONG
-    case 'q': case 'Q': return sizeof(PY_LONG_LONG);
-    #endif
-    case 'f': return sizeof(float) * (is_complex ? 2 : 1);
-    case 'd': return sizeof(double) * (is_complex ? 2 : 1);
-    case 'g': return sizeof(long double) * (is_complex ? 2 : 1);
-    case 'O': case 'P': return sizeof(void*);
-    default: {
-      __Pyx_BufFmt_RaiseUnexpectedChar(ch);
-      return 0;
-    }
-  }
-}
-typedef struct { char c; short x; } __Pyx_st_short;
-typedef struct { char c; int x; } __Pyx_st_int;
-typedef struct { char c; long x; } __Pyx_st_long;
-typedef struct { char c; float x; } __Pyx_st_float;
-typedef struct { char c; double x; } __Pyx_st_double;
-typedef struct { char c; long double x; } __Pyx_st_longdouble;
-typedef struct { char c; void *x; } __Pyx_st_void_p;
-#ifdef HAVE_LONG_LONG
-typedef struct { char c; PY_LONG_LONG x; } __Pyx_st_longlong;
-#endif
-static size_t __Pyx_BufFmt_TypeCharToAlignment(char ch, int is_complex) {
-  CYTHON_UNUSED_VAR(is_complex);
-  switch (ch) {
-    case '?': case 'c': case 'b': case 'B': case 's': case 'p': return 1;
-    case 'h': case 'H': return sizeof(__Pyx_st_short) - sizeof(short);
-    case 'i': case 'I': return sizeof(__Pyx_st_int) - sizeof(int);
-    case 'l': case 'L': return sizeof(__Pyx_st_long) - sizeof(long);
-#ifdef HAVE_LONG_LONG
-    case 'q': case 'Q': return sizeof(__Pyx_st_longlong) - sizeof(PY_LONG_LONG);
-#endif
-    case 'f': return sizeof(__Pyx_st_float) - sizeof(float);
-    case 'd': return sizeof(__Pyx_st_double) - sizeof(double);
-    case 'g': return sizeof(__Pyx_st_longdouble) - sizeof(long double);
-    case 'P': case 'O': return sizeof(__Pyx_st_void_p) - sizeof(void*);
-    default:
-      __Pyx_BufFmt_RaiseUnexpectedChar(ch);
-      return 0;
-    }
-}
-/* These are for computing the padding at the end of the struct to align
-   on the first member of the struct. This will probably the same as above,
-   but we don't have any guarantees.
- */
-typedef struct { short x; char c; } __Pyx_pad_short;
-typedef struct { int x; char c; } __Pyx_pad_int;
-typedef struct { long x; char c; } __Pyx_pad_long;
-typedef struct { float x; char c; } __Pyx_pad_float;
-typedef struct { double x; char c; } __Pyx_pad_double;
-typedef struct { long double x; char c; } __Pyx_pad_longdouble;
-typedef struct { void *x; char c; } __Pyx_pad_void_p;
-#ifdef HAVE_LONG_LONG
-typedef struct { PY_LONG_LONG x; char c; } __Pyx_pad_longlong;
-#endif
-static size_t __Pyx_BufFmt_TypeCharToPadding(char ch, int is_complex) {
-  CYTHON_UNUSED_VAR(is_complex);
-  switch (ch) {
-    case '?': case 'c': case 'b': case 'B': case 's': case 'p': return 1;
-    case 'h': case 'H': return sizeof(__Pyx_pad_short) - sizeof(short);
-    case 'i': case 'I': return sizeof(__Pyx_pad_int) - sizeof(int);
-    case 'l': case 'L': return sizeof(__Pyx_pad_long) - sizeof(long);
-#ifdef HAVE_LONG_LONG
-    case 'q': case 'Q': return sizeof(__Pyx_pad_longlong) - sizeof(PY_LONG_LONG);
-#endif
-    case 'f': return sizeof(__Pyx_pad_float) - sizeof(float);
-    case 'd': return sizeof(__Pyx_pad_double) - sizeof(double);
-    case 'g': return sizeof(__Pyx_pad_longdouble) - sizeof(long double);
-    case 'P': case 'O': return sizeof(__Pyx_pad_void_p) - sizeof(void*);
-    default:
-      __Pyx_BufFmt_RaiseUnexpectedChar(ch);
-      return 0;
-    }
-}
-static char __Pyx_BufFmt_TypeCharToGroup(char ch, int is_complex) {
-  switch (ch) {
-    case 'c':
-        return 'H';
-    case 'b': case 'h': case 'i':
-    case 'l': case 'q': case 's': case 'p':
-        return 'I';
-    case '?': case 'B': case 'H': case 'I': case 'L': case 'Q':
-        return 'U';
-    case 'f': case 'd': case 'g':
-        return (is_complex ? 'C' : 'R');
-    case 'O':
-        return 'O';
-    case 'P':
-        return 'P';
-    default: {
-      __Pyx_BufFmt_RaiseUnexpectedChar(ch);
-      return 0;
-    }
-  }
-}
-static void __Pyx_BufFmt_RaiseExpected(__Pyx_BufFmt_Context* ctx) {
-  if (ctx->head == NULL || ctx->head->field == &ctx->root) {
-    const char* expected;
-    const char* quote;
-    if (ctx->head == NULL) {
-      expected = "end";
-      quote = "";
-    } else {
-      expected = ctx->head->field->type->name;
-      quote = "'";
-    }
-    PyErr_Format(PyExc_ValueError,
-                 "Buffer dtype mismatch, expected %s%s%s but got %s",
-                 quote, expected, quote,
-                 __Pyx_BufFmt_DescribeTypeChar(ctx->enc_type, ctx->is_complex));
-  } else {
-    __Pyx_StructField* field = ctx->head->field;
-    __Pyx_StructField* parent = (ctx->head - 1)->field;
-    PyErr_Format(PyExc_ValueError,
-                 "Buffer dtype mismatch, expected '%s' but got %s in '%s.%s'",
-                 field->type->name, __Pyx_BufFmt_DescribeTypeChar(ctx->enc_type, ctx->is_complex),
-                 parent->type->name, field->name);
-  }
-}
-static int __Pyx_BufFmt_ProcessTypeChunk(__Pyx_BufFmt_Context* ctx) {
-  char group;
-  size_t size, offset, arraysize = 1;
-  if (ctx->enc_type == 0) return 0;
-  if (ctx->head->field->type->arraysize[0]) {
-    int i, ndim = 0;
-    if (ctx->enc_type == 's' || ctx->enc_type == 'p') {
-        ctx->is_valid_array = ctx->head->field->type->ndim == 1;
-        ndim = 1;
-        if (ctx->enc_count != ctx->head->field->type->arraysize[0]) {
-            PyErr_Format(PyExc_ValueError,
-                         "Expected a dimension of size %zu, got %zu",
-                         ctx->head->field->type->arraysize[0], ctx->enc_count);
-            return -1;
-        }
-    }
-    if (!ctx->is_valid_array) {
-      PyErr_Format(PyExc_ValueError, "Expected %d dimensions, got %d",
-                   ctx->head->field->type->ndim, ndim);
-      return -1;
-    }
-    for (i = 0; i < ctx->head->field->type->ndim; i++) {
-      arraysize *= ctx->head->field->type->arraysize[i];
-    }
-    ctx->is_valid_array = 0;
-    ctx->enc_count = 1;
-  }
-  group = __Pyx_BufFmt_TypeCharToGroup(ctx->enc_type, ctx->is_complex);
-  do {
-    __Pyx_StructField* field = ctx->head->field;
-    __Pyx_TypeInfo* type = field->type;
-    if (ctx->enc_packmode == '@' || ctx->enc_packmode == '^') {
-      size = __Pyx_BufFmt_TypeCharToNativeSize(ctx->enc_type, ctx->is_complex);
-    } else {
-      size = __Pyx_BufFmt_TypeCharToStandardSize(ctx->enc_type, ctx->is_complex);
-    }
-    if (ctx->enc_packmode == '@') {
-      size_t align_at = __Pyx_BufFmt_TypeCharToAlignment(ctx->enc_type, ctx->is_complex);
-      size_t align_mod_offset;
-      if (align_at == 0) return -1;
-      align_mod_offset = ctx->fmt_offset % align_at;
-      if (align_mod_offset > 0) ctx->fmt_offset += align_at - align_mod_offset;
-      if (ctx->struct_alignment == 0)
-          ctx->struct_alignment = __Pyx_BufFmt_TypeCharToPadding(ctx->enc_type,
-                                                                 ctx->is_complex);
-    }
-    if (type->size != size || type->typegroup != group) {
-      if (type->typegroup == 'C' && type->fields != NULL) {
-        size_t parent_offset = ctx->head->parent_offset + field->offset;
-        ++ctx->head;
-        ctx->head->field = type->fields;
-        ctx->head->parent_offset = parent_offset;
-        continue;
-      }
-      if ((type->typegroup == 'H' || group == 'H') && type->size == size) {
-      } else {
-          __Pyx_BufFmt_RaiseExpected(ctx);
-          return -1;
-      }
-    }
-    offset = ctx->head->parent_offset + field->offset;
-    if (ctx->fmt_offset != offset) {
-      PyErr_Format(PyExc_ValueError,
-                   "Buffer dtype mismatch; next field is at offset %" CYTHON_FORMAT_SSIZE_T "d but %" CYTHON_FORMAT_SSIZE_T "d expected",
-                   (Py_ssize_t)ctx->fmt_offset, (Py_ssize_t)offset);
-      return -1;
-    }
-    ctx->fmt_offset += size;
-    if (arraysize)
-      ctx->fmt_offset += (arraysize - 1) * size;
-    --ctx->enc_count;
-    while (1) {
-      if (field == &ctx->root) {
-        ctx->head = NULL;
-        if (ctx->enc_count != 0) {
-          __Pyx_BufFmt_RaiseExpected(ctx);
-          return -1;
-        }
-        break;
-      }
-      ctx->head->field = ++field;
-      if (field->type == NULL) {
-        --ctx->head;
-        field = ctx->head->field;
-        continue;
-      } else if (field->type->typegroup == 'S') {
-        size_t parent_offset = ctx->head->parent_offset + field->offset;
-        if (field->type->fields->type == NULL) continue;
-        field = field->type->fields;
-        ++ctx->head;
-        ctx->head->field = field;
-        ctx->head->parent_offset = parent_offset;
-        break;
-      } else {
-        break;
-      }
-    }
-  } while (ctx->enc_count);
-  ctx->enc_type = 0;
-  ctx->is_complex = 0;
-  return 0;
-}
-static int
-__pyx_buffmt_parse_array(__Pyx_BufFmt_Context* ctx, const char** tsp)
-{
-    const char *ts = *tsp;
-    int i = 0, number, ndim;
-    ++ts;
-    if (ctx->new_count != 1) {
-        PyErr_SetString(PyExc_ValueError,
-                        "Cannot handle repeated arrays in format string");
-        return -1;
-    }
-    if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return -1;
-    ndim = ctx->head->field->type->ndim;
-    while (*ts && *ts != ')') {
-        switch (*ts) {
-            case ' ': case '\f': case '\r': case '\n': case '\t': case '\v':  continue;
-            default:  break;
-        }
-        number = __Pyx_BufFmt_ExpectNumber(&ts);
-        if (number == -1) return -1;
-        if (i < ndim && (size_t) number != ctx->head->field->type->arraysize[i]) {
-            PyErr_Format(PyExc_ValueError,
-                        "Expected a dimension of size %zu, got %d",
-                        ctx->head->field->type->arraysize[i], number);
-            return -1;
-        }
-        if (*ts != ',' && *ts != ')') {
-            PyErr_Format(PyExc_ValueError,
-                                "Expected a comma in format string, got '%c'", *ts);
-            return -1;
-        }
-        if (*ts == ',') ts++;
-        i++;
-    }
-    if (i != ndim) {
-        PyErr_Format(PyExc_ValueError, "Expected %d dimension(s), got %d",
-                            ctx->head->field->type->ndim, i);
-        return -1;
-    }
-    if (!*ts) {
-        PyErr_SetString(PyExc_ValueError,
-                        "Unexpected end of format string, expected ')'");
-        return -1;
-    }
-    ctx->is_valid_array = 1;
-    ctx->new_count = 1;
-    *tsp = ++ts;
-    return 0;
-}
-static const char* __Pyx_BufFmt_CheckString(__Pyx_BufFmt_Context* ctx, const char* ts) {
-  int got_Z = 0;
-  while (1) {
-    switch(*ts) {
-      case 0:
-        if (ctx->enc_type != 0 && ctx->head == NULL) {
-          __Pyx_BufFmt_RaiseExpected(ctx);
-          return NULL;
-        }
-        if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return NULL;
-        if (ctx->head != NULL) {
-          __Pyx_BufFmt_RaiseExpected(ctx);
-          return NULL;
-        }
-        return ts;
-      case ' ':
-      case '\r':
-      case '\n':
-        ++ts;
-        break;
-      case '<':
-        if (!__Pyx_Is_Little_Endian()) {
-          PyErr_SetString(PyExc_ValueError, "Little-endian buffer not supported on big-endian compiler");
-          return NULL;
-        }
-        ctx->new_packmode = '=';
-        ++ts;
-        break;
-      case '>':
-      case '!':
-        if (__Pyx_Is_Little_Endian()) {
-          PyErr_SetString(PyExc_ValueError, "Big-endian buffer not supported on little-endian compiler");
-          return NULL;
-        }
-        ctx->new_packmode = '=';
-        ++ts;
-        break;
-      case '=':
-      case '@':
-      case '^':
-        ctx->new_packmode = *ts++;
-        break;
-      case 'T':
-        {
-          const char* ts_after_sub;
-          size_t i, struct_count = ctx->new_count;
-          size_t struct_alignment = ctx->struct_alignment;
-          ctx->new_count = 1;
-          ++ts;
-          if (*ts != '{') {
-            PyErr_SetString(PyExc_ValueError, "Buffer acquisition: Expected '{' after 'T'");
-            return NULL;
-          }
-          if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return NULL;
-          ctx->enc_type = 0;
-          ctx->enc_count = 0;
-          ctx->struct_alignment = 0;
-          ++ts;
-          ts_after_sub = ts;
-          for (i = 0; i != struct_count; ++i) {
-            ts_after_sub = __Pyx_BufFmt_CheckString(ctx, ts);
-            if (!ts_after_sub) return NULL;
-          }
-          ts = ts_after_sub;
-          if (struct_alignment) ctx->struct_alignment = struct_alignment;
-        }
-        break;
-      case '}':
-        {
-          size_t alignment = ctx->struct_alignment;
-          ++ts;
-          if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return NULL;
-          ctx->enc_type = 0;
-          if (alignment && ctx->fmt_offset % alignment) {
-            ctx->fmt_offset += alignment - (ctx->fmt_offset % alignment);
-          }
-        }
-        return ts;
-      case 'x':
-        if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return NULL;
-        ctx->fmt_offset += ctx->new_count;
-        ctx->new_count = 1;
-        ctx->enc_count = 0;
-        ctx->enc_type = 0;
-        ctx->enc_packmode = ctx->new_packmode;
-        ++ts;
-        break;
-      case 'Z':
-        got_Z = 1;
-        ++ts;
-        if (*ts != 'f' && *ts != 'd' && *ts != 'g') {
-          __Pyx_BufFmt_RaiseUnexpectedChar('Z');
-          return NULL;
-        }
-        CYTHON_FALLTHROUGH;
-      case '?': case 'c': case 'b': case 'B': case 'h': case 'H': case 'i': case 'I':
-      case 'l': case 'L': case 'q': case 'Q':
-      case 'f': case 'd': case 'g':
-      case 'O': case 'p':
-        if ((ctx->enc_type == *ts) && (got_Z == ctx->is_complex) &&
-            (ctx->enc_packmode == ctx->new_packmode) && (!ctx->is_valid_array)) {
-          ctx->enc_count += ctx->new_count;
-          ctx->new_count = 1;
-          got_Z = 0;
-          ++ts;
-          break;
-        }
-        CYTHON_FALLTHROUGH;
-      case 's':
-        if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return NULL;
-        ctx->enc_count = ctx->new_count;
-        ctx->enc_packmode = ctx->new_packmode;
-        ctx->enc_type = *ts;
-        ctx->is_complex = got_Z;
-        ++ts;
-        ctx->new_count = 1;
-        got_Z = 0;
-        break;
-      case ':':
-        ++ts;
-        while(*ts != ':') ++ts;
-        ++ts;
-        break;
-      case '(':
-        if (__pyx_buffmt_parse_array(ctx, &ts) < 0) return NULL;
-        break;
-      default:
-        {
-          int number = __Pyx_BufFmt_ExpectNumber(&ts);
-          if (number == -1) return NULL;
-          ctx->new_count = (size_t)number;
-        }
-    }
-  }
+    #endif
+bad:
+    Py_XDECREF(key);
+    Py_XDECREF(value);
+    return -1;
 }
 
-/* BufferGetAndValidate */
-  static CYTHON_INLINE void __Pyx_SafeReleaseBuffer(Py_buffer* info) {
-  if (unlikely(info->buf == NULL)) return;
-  if (info->suboffsets == __Pyx_minusones) info->suboffsets = NULL;
-  __Pyx_ReleaseBuffer(info);
-}
-static void __Pyx_ZeroBuffer(Py_buffer* buf) {
-  buf->buf = NULL;
-  buf->obj = NULL;
-  buf->strides = __Pyx_zeros;
-  buf->shape = __Pyx_zeros;
-  buf->suboffsets = __Pyx_minusones;
-}
-static int __Pyx__GetBufferAndValidate(
-        Py_buffer* buf, PyObject* obj,  __Pyx_TypeInfo* dtype, int flags,
-        int nd, int cast, __Pyx_BufFmt_StackElem* stack)
+/* ArgTypeTest */
+static int __Pyx__ArgTypeTest(PyObject *obj, PyTypeObject *type, const char *name, int exact)
 {
-  buf->buf = NULL;
-  if (unlikely(__Pyx_GetBuffer(obj, buf, flags) == -1)) {
-    __Pyx_ZeroBuffer(buf);
-    return -1;
-  }
-  if (unlikely(buf->ndim != nd)) {
-    PyErr_Format(PyExc_ValueError,
-                 "Buffer has wrong number of dimensions (expected %d, got %d)",
-                 nd, buf->ndim);
-    goto fail;
-  }
-  if (!cast) {
-    __Pyx_BufFmt_Context ctx;
-    __Pyx_BufFmt_Init(&ctx, stack, dtype);
-    if (!__Pyx_BufFmt_CheckString(&ctx, buf->format)) goto fail;
-  }
-  if (unlikely((size_t)buf->itemsize != dtype->size)) {
-    PyErr_Format(PyExc_ValueError,
-      "Item size of buffer (%" CYTHON_FORMAT_SSIZE_T "d byte%s) does not match size of '%s' (%" CYTHON_FORMAT_SSIZE_T "d byte%s)",
-      buf->itemsize, (buf->itemsize > 1) ? "s" : "",
-      dtype->name, (Py_ssize_t)dtype->size, (dtype->size > 1) ? "s" : "");
-    goto fail;
-  }
-  if (buf->suboffsets == NULL) buf->suboffsets = __Pyx_minusones;
-  return 0;
-fail:;
-  __Pyx_SafeReleaseBuffer(buf);
-  return -1;
+    __Pyx_TypeName type_name;
+    __Pyx_TypeName obj_type_name;
+    if (unlikely(!type)) {
+        PyErr_SetString(PyExc_SystemError, "Missing type object");
+        return 0;
+    }
+    else if (exact) {
+        #if PY_MAJOR_VERSION == 2
+        if ((type == &PyBaseString_Type) && likely(__Pyx_PyBaseString_CheckExact(obj))) return 1;
+        #endif
+    }
+    else {
+        if (likely(__Pyx_TypeCheck(obj, type))) return 1;
+    }
+    type_name = __Pyx_PyType_GetName(type);
+    obj_type_name = __Pyx_PyType_GetName(Py_TYPE(obj));
+    PyErr_Format(PyExc_TypeError,
+        "Argument '%.200s' has incorrect type (expected " __Pyx_FMT_TYPENAME
+        ", got " __Pyx_FMT_TYPENAME ")", name, type_name, obj_type_name);
+    __Pyx_DECREF_TypeName(type_name);
+    __Pyx_DECREF_TypeName(obj_type_name);
+    return 0;
 }
 
 /* PyDictVersioning */
-  #if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_TYPE_SLOTS
+#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_TYPE_SLOTS
 static CYTHON_INLINE PY_UINT64_T __Pyx_get_tp_dict_version(PyObject *obj) {
     PyObject *dict = Py_TYPE(obj)->tp_dict;
     return likely(dict) ? __PYX_GET_DICT_VERSION(dict) : 0;
@@ -8140,7 +7863,7 @@ static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UIN
 #endif
 
 /* GetModuleGlobalName */
-  #if CYTHON_USE_DICT_VERSIONS
+#if CYTHON_USE_DICT_VERSIONS
 static PyObject *__Pyx__GetModuleGlobalName(PyObject *name, PY_UINT64_T *dict_version, PyObject **dict_cached_value)
 #else
 static CYTHON_INLINE PyObject *__Pyx__GetModuleGlobalName(PyObject *name)
@@ -8183,7 +7906,7 @@ static CYTHON_INLINE PyObject *__Pyx__GetModuleGlobalName(PyObject *name)
 }
 
 /* PyFunctionFastCall */
-  #if CYTHON_FAST_PYCALL && !CYTHON_VECTORCALL
+#if CYTHON_FAST_PYCALL && !CYTHON_VECTORCALL
 static PyObject* __Pyx_PyFunction_FastCallNoKw(PyCodeObject *co, PyObject **args, Py_ssize_t na,
                                                PyObject *globals) {
     PyFrameObject *f;
@@ -8306,7 +8029,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args,
 #endif
 
 /* PyObjectCallMethO */
-  #if CYTHON_COMPILING_IN_CPYTHON
+#if CYTHON_COMPILING_IN_CPYTHON
 static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg) {
     PyObject *self, *result;
     PyCFunction cfunc;
@@ -8331,7 +8054,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject
 #endif
 
 /* PyObjectFastCall */
-  #if PY_VERSION_HEX < 0x03090000 || CYTHON_COMPILING_IN_LIMITED_API
+#if PY_VERSION_HEX < 0x03090000 || CYTHON_COMPILING_IN_LIMITED_API
 static PyObject* __Pyx_PyObject_FastCall_fallback(PyObject *func, PyObject **args, size_t nargs, PyObject *kwargs) {
     PyObject *argstuple;
     PyObject *result = 0;
@@ -8409,20 +8132,20 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_FastCallDict(PyObject *func, PyObj
 }
 
 /* RaiseTooManyValuesToUnpack */
-  static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected) {
+static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected) {
     PyErr_Format(PyExc_ValueError,
                  "too many values to unpack (expected %" CYTHON_FORMAT_SSIZE_T "d)", expected);
 }
 
 /* RaiseNeedMoreValuesToUnpack */
-  static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index) {
+static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index) {
     PyErr_Format(PyExc_ValueError,
                  "need more than %" CYTHON_FORMAT_SSIZE_T "d value%.1s to unpack",
                  index, (index == 1) ? "" : "s");
 }
 
 /* IterFinish */
-  static CYTHON_INLINE int __Pyx_IterFinish(void) {
+static CYTHON_INLINE int __Pyx_IterFinish(void) {
     __Pyx_PyThreadState_declare
     __Pyx_PyThreadState_assign
     PyObject* exc_type = __Pyx_PyErr_CurrentExceptionType();
@@ -8436,7 +8159,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_FastCallDict(PyObject *func, PyObj
 }
 
 /* UnpackItemEndCheck */
-  static int __Pyx_IternextUnpackEndCheck(PyObject *retval, Py_ssize_t expected) {
+static int __Pyx_IternextUnpackEndCheck(PyObject *retval, Py_ssize_t expected) {
     if (unlikely(retval)) {
         Py_DECREF(retval);
         __Pyx_RaiseTooManyValuesError(expected);
@@ -8445,8 +8168,80 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_FastCallDict(PyObject *func, PyObj
     return __Pyx_IterFinish();
 }
 
+/* PyIntCompare */
+static CYTHON_INLINE int __Pyx_PyInt_BoolNeObjC(PyObject *op1, PyObject *op2, long intval, long inplace) {
+    CYTHON_MAYBE_UNUSED_VAR(intval);
+    CYTHON_UNUSED_VAR(inplace);
+    if (op1 == op2) {
+        return 0;
+    }
+    #if PY_MAJOR_VERSION < 3
+    if (likely(PyInt_CheckExact(op1))) {
+        const long b = intval;
+        long a = PyInt_AS_LONG(op1);
+        return (a != b);
+    }
+    #endif
+    #if CYTHON_USE_PYLONG_INTERNALS
+    if (likely(PyLong_CheckExact(op1))) {
+        int unequal;
+        unsigned long uintval;
+        Py_ssize_t size = __Pyx_PyLong_DigitCount(op1);
+        const digit* digits = __Pyx_PyLong_Digits(op1);
+        if (intval == 0) {
+            return (__Pyx_PyLong_IsZero(op1) != 1);
+        } else if (intval < 0) {
+            if (__Pyx_PyLong_IsNonNeg(op1))
+                return 1;
+            intval = -intval;
+        } else {
+            if (__Pyx_PyLong_IsNeg(op1))
+                return 1;
+        }
+        uintval = (unsigned long) intval;
+#if PyLong_SHIFT * 4 < SIZEOF_LONG*8
+        if (uintval >> (PyLong_SHIFT * 4)) {
+            unequal = (size != 5) || (digits[0] != (uintval & (unsigned long) PyLong_MASK))
+                 | (digits[1] != ((uintval >> (1 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)) | (digits[2] != ((uintval >> (2 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)) | (digits[3] != ((uintval >> (3 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)) | (digits[4] != ((uintval >> (4 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK));
+        } else
+#endif
+#if PyLong_SHIFT * 3 < SIZEOF_LONG*8
+        if (uintval >> (PyLong_SHIFT * 3)) {
+            unequal = (size != 4) || (digits[0] != (uintval & (unsigned long) PyLong_MASK))
+                 | (digits[1] != ((uintval >> (1 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)) | (digits[2] != ((uintval >> (2 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)) | (digits[3] != ((uintval >> (3 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK));
+        } else
+#endif
+#if PyLong_SHIFT * 2 < SIZEOF_LONG*8
+        if (uintval >> (PyLong_SHIFT * 2)) {
+            unequal = (size != 3) || (digits[0] != (uintval & (unsigned long) PyLong_MASK))
+                 | (digits[1] != ((uintval >> (1 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)) | (digits[2] != ((uintval >> (2 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK));
+        } else
+#endif
+#if PyLong_SHIFT * 1 < SIZEOF_LONG*8
+        if (uintval >> (PyLong_SHIFT * 1)) {
+            unequal = (size != 2) || (digits[0] != (uintval & (unsigned long) PyLong_MASK))
+                 | (digits[1] != ((uintval >> (1 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK));
+        } else
+#endif
+            unequal = (size != 1) || (((unsigned long) digits[0]) != (uintval & (unsigned long) PyLong_MASK));
+        return (unequal != 0);
+    }
+    #endif
+    if (PyFloat_CheckExact(op1)) {
+        const long b = intval;
+#if CYTHON_COMPILING_IN_LIMITED_API
+        double a = __pyx_PyFloat_AsDouble(op1);
+#else
+        double a = PyFloat_AS_DOUBLE(op1);
+#endif
+        return ((double)a != (double)b);
+    }
+    return __Pyx_PyObject_IsTrueAndDecref(
+        PyObject_RichCompare(op1, op2, Py_NE));
+}
+
 /* PyIntBinop */
-  #if !CYTHON_COMPILING_IN_PYPY
+#if !CYTHON_COMPILING_IN_PYPY
 static PyObject* __Pyx_PyInt_TrueDivideObjC(PyObject *op1, PyObject *op2, long intval, int inplace, int zerodivision_check) {
     CYTHON_MAYBE_UNUSED_VAR(intval);
     CYTHON_MAYBE_UNUSED_VAR(inplace);
@@ -8541,7 +8336,7 @@ static PyObject* __Pyx_PyInt_TrueDivideObjC(PyObject *op1, PyObject *op2, long i
 #endif
 
 /* DictGetItem */
-  #if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY
+#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY
 static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) {
     PyObject *value;
     value = PyDict_GetItemWithError(d, key);
@@ -8565,7 +8360,7 @@ static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) {
 #endif
 
 /* ExtTypeTest */
-  static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) {
+static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) {
     __Pyx_TypeName obj_type_name;
     __Pyx_TypeName type_name;
     if (unlikely(!type)) {
@@ -8584,103 +8379,14 @@ static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) {
     return 0;
 }
 
-/* GetItemInt */
-  static PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j) {
-    PyObject *r;
-    if (unlikely(!j)) return NULL;
-    r = PyObject_GetItem(o, j);
-    Py_DECREF(j);
-    return r;
-}
-static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i,
-                                                              CYTHON_NCP_UNUSED int wraparound,
-                                                              CYTHON_NCP_UNUSED int boundscheck) {
-#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
-    Py_ssize_t wrapped_i = i;
-    if (wraparound & unlikely(i < 0)) {
-        wrapped_i += PyList_GET_SIZE(o);
-    }
-    if ((!boundscheck) || likely(__Pyx_is_valid_index(wrapped_i, PyList_GET_SIZE(o)))) {
-        PyObject *r = PyList_GET_ITEM(o, wrapped_i);
-        Py_INCREF(r);
-        return r;
-    }
-    return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i));
-#else
-    return PySequence_GetItem(o, i);
-#endif
-}
-static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i,
-                                                              CYTHON_NCP_UNUSED int wraparound,
-                                                              CYTHON_NCP_UNUSED int boundscheck) {
-#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
-    Py_ssize_t wrapped_i = i;
-    if (wraparound & unlikely(i < 0)) {
-        wrapped_i += PyTuple_GET_SIZE(o);
-    }
-    if ((!boundscheck) || likely(__Pyx_is_valid_index(wrapped_i, PyTuple_GET_SIZE(o)))) {
-        PyObject *r = PyTuple_GET_ITEM(o, wrapped_i);
-        Py_INCREF(r);
-        return r;
-    }
-    return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i));
-#else
-    return PySequence_GetItem(o, i);
-#endif
-}
-static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, int is_list,
-                                                     CYTHON_NCP_UNUSED int wraparound,
-                                                     CYTHON_NCP_UNUSED int boundscheck) {
-#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS && CYTHON_USE_TYPE_SLOTS
-    if (is_list || PyList_CheckExact(o)) {
-        Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyList_GET_SIZE(o);
-        if ((!boundscheck) || (likely(__Pyx_is_valid_index(n, PyList_GET_SIZE(o))))) {
-            PyObject *r = PyList_GET_ITEM(o, n);
-            Py_INCREF(r);
-            return r;
-        }
-    }
-    else if (PyTuple_CheckExact(o)) {
-        Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyTuple_GET_SIZE(o);
-        if ((!boundscheck) || likely(__Pyx_is_valid_index(n, PyTuple_GET_SIZE(o)))) {
-            PyObject *r = PyTuple_GET_ITEM(o, n);
-            Py_INCREF(r);
-            return r;
-        }
-    } else {
-        PyMappingMethods *mm = Py_TYPE(o)->tp_as_mapping;
-        PySequenceMethods *sm = Py_TYPE(o)->tp_as_sequence;
-        if (mm && mm->mp_subscript) {
-            PyObject *r, *key = PyInt_FromSsize_t(i);
-            if (unlikely(!key)) return NULL;
-            r = mm->mp_subscript(o, key);
-            Py_DECREF(key);
-            return r;
-        }
-        if (likely(sm && sm->sq_item)) {
-            if (wraparound && unlikely(i < 0) && likely(sm->sq_length)) {
-                Py_ssize_t l = sm->sq_length(o);
-                if (likely(l >= 0)) {
-                    i += l;
-                } else {
-                    if (!PyErr_ExceptionMatches(PyExc_OverflowError))
-                        return NULL;
-                    PyErr_Clear();
-                }
-            }
-            return sm->sq_item(o, i);
-        }
-    }
-#else
-    if (is_list || !PyMapping_Check(o)) {
-        return PySequence_GetItem(o, i);
-    }
-#endif
-    return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i));
+/* PyObjectCallOneArg */
+static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) {
+    PyObject *args[2] = {NULL, arg};
+    return __Pyx_PyObject_FastCall(func, args+1, 1 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET);
 }
 
 /* TypeImport */
-  #ifndef __PYX_HAVE_RT_ImportType_3_0_7
+#ifndef __PYX_HAVE_RT_ImportType_3_0_7
 #define __PYX_HAVE_RT_ImportType_3_0_7
 static PyTypeObject *__Pyx_ImportType_3_0_7(PyObject *module, const char *module_name, const char *class_name,
     size_t size, size_t alignment, enum __Pyx_ImportType_CheckSize_3_0_7 check_size)
@@ -8760,7 +8466,7 @@ static PyTypeObject *__Pyx_ImportType_3_0_7(PyObject *module, const char *module
 #endif
 
 /* Import */
-  static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level) {
+static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level) {
     PyObject *module = 0;
     PyObject *empty_dict = 0;
     PyObject *empty_list = 0;
@@ -8818,7 +8524,7 @@ static PyTypeObject *__Pyx_ImportType_3_0_7(PyObject *module, const char *module
 }
 
 /* ImportFrom */
-  static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name) {
+static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name) {
     PyObject* value = __Pyx_PyObject_GetAttrStr(module, name);
     if (unlikely(!value) && PyErr_ExceptionMatches(PyExc_AttributeError)) {
         const char* module_name_str = 0;
@@ -8830,7 +8536,7 @@ static PyTypeObject *__Pyx_ImportType_3_0_7(PyObject *module, const char *module
         if (unlikely(!module_name_str)) { goto modbad; }
         module_name = PyUnicode_FromString(module_name_str);
         if (unlikely(!module_name)) { goto modbad; }
-        module_dot = PyUnicode_Concat(module_name, __pyx_kp_u__3);
+        module_dot = PyUnicode_Concat(module_name, __pyx_kp_u__4);
         if (unlikely(!module_dot)) { goto modbad; }
         full_name = PyUnicode_Concat(module_dot, name);
         if (unlikely(!full_name)) { goto modbad; }
@@ -8861,7 +8567,7 @@ static PyTypeObject *__Pyx_ImportType_3_0_7(PyObject *module, const char *module
 }
 
 /* ImportDottedModule */
-  #if PY_MAJOR_VERSION >= 3
+#if PY_MAJOR_VERSION >= 3
 static PyObject *__Pyx__ImportDottedModule_Error(PyObject *name, PyObject *parts_tuple, Py_ssize_t count) {
     PyObject *partial_name = NULL, *slice = NULL, *sep = NULL;
     if (unlikely(PyErr_Occurred())) {
@@ -8938,7 +8644,7 @@ static PyObject *__Pyx_ImportDottedModule_WalkParts(PyObject *module, PyObject *
 #endif
 static PyObject *__Pyx__ImportDottedModule(PyObject *name, PyObject *parts_tuple) {
 #if PY_MAJOR_VERSION < 3
-    PyObject *module, *from_list, *star = __pyx_n_s__4;
+    PyObject *module, *from_list, *star = __pyx_n_s__5;
     CYTHON_UNUSED_VAR(parts_tuple);
     from_list = PyList_New(1);
     if (unlikely(!from_list))
@@ -8989,7 +8695,7 @@ static PyObject *__Pyx_ImportDottedModule(PyObject *name, PyObject *parts_tuple)
 }
 
 /* FixUpExtensionType */
-  #if CYTHON_USE_TYPE_SPECS
+#if CYTHON_USE_TYPE_SPECS
 static int __Pyx_fix_up_extension_type_from_spec(PyType_Spec *spec, PyTypeObject *type) {
 #if PY_VERSION_HEX > 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API
     CYTHON_UNUSED_VAR(spec);
@@ -9062,12 +8768,12 @@ static int __Pyx_fix_up_extension_type_from_spec(PyType_Spec *spec, PyTypeObject
 #endif
 
 /* FetchSharedCythonModule */
-  static PyObject *__Pyx_FetchSharedCythonABIModule(void) {
+static PyObject *__Pyx_FetchSharedCythonABIModule(void) {
     return __Pyx_PyImport_AddModuleRef((char*) __PYX_ABI_MODULE_NAME);
 }
 
 /* FetchCommonType */
-  static int __Pyx_VerifyCachedType(PyObject *cached_type,
+static int __Pyx_VerifyCachedType(PyObject *cached_type,
                                const char *name,
                                Py_ssize_t basicsize,
                                Py_ssize_t expected_basicsize) {
@@ -9168,7 +8874,7 @@ static PyTypeObject *__Pyx_FetchCommonTypeFromSpec(PyObject *module, PyType_Spec
 #endif
 
 /* PyVectorcallFastCallDict */
-  #if CYTHON_METH_FASTCALL
+#if CYTHON_METH_FASTCALL
 static PyObject *__Pyx_PyVectorcall_FastCallDict_kw(PyObject *func, __pyx_vectorcallfunc vc, PyObject *const *args, size_t nargs, PyObject *kw)
 {
     PyObject *res = NULL;
@@ -9224,7 +8930,7 @@ static CYTHON_INLINE PyObject *__Pyx_PyVectorcall_FastCallDict(PyObject *func, _
 #endif
 
 /* CythonFunctionShared */
-  #if CYTHON_COMPILING_IN_LIMITED_API
+#if CYTHON_COMPILING_IN_LIMITED_API
 static CYTHON_INLINE int __Pyx__IsSameCyOrCFunction(PyObject *func, void *cfunc) {
     if (__Pyx_CyFunction_Check(func)) {
         return PyCFunction_GetFunction(((__pyx_CyFunctionObject*)func)->func) == (PyCFunction) cfunc;
@@ -10226,7 +9932,7 @@ static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *func, Py
 }
 
 /* CythonFunction */
-  static PyObject *__Pyx_CyFunction_New(PyMethodDef *ml, int flags, PyObject* qualname,
+static PyObject *__Pyx_CyFunction_New(PyMethodDef *ml, int flags, PyObject* qualname,
                                       PyObject *closure, PyObject *module, PyObject* globals, PyObject* code) {
     PyObject *op = __Pyx_CyFunction_Init(
         PyObject_GC_New(__pyx_CyFunctionObject, __pyx_CyFunctionType),
@@ -10239,7 +9945,7 @@ static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *func, Py
 }
 
 /* CLineInTraceback */
-  #ifndef CYTHON_CLINE_IN_TRACEBACK
+#ifndef CYTHON_CLINE_IN_TRACEBACK
 static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) {
     PyObject *use_cline;
     PyObject *ptype, *pvalue, *ptraceback;
@@ -10282,7 +9988,7 @@ static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) {
 #endif
 
 /* CodeObjectCache */
-  #if !CYTHON_COMPILING_IN_LIMITED_API
+#if !CYTHON_COMPILING_IN_LIMITED_API
 static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line) {
     int start = 0, mid = 0, end = count - 1;
     if (end >= 0 && code_line > entries[end].code_line) {
@@ -10364,7 +10070,7 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) {
 #endif
 
 /* AddTraceback */
-  #include "compile.h"
+#include "compile.h"
 #include "frameobject.h"
 #include "traceback.h"
 #if PY_VERSION_HEX >= 0x030b00a6 && !CYTHON_COMPILING_IN_LIMITED_API
@@ -10555,33 +10261,8 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line,
 }
 #endif
 
-#if PY_MAJOR_VERSION < 3
-static int __Pyx_GetBuffer(PyObject *obj, Py_buffer *view, int flags) {
-    __Pyx_TypeName obj_type_name;
-    if (PyObject_CheckBuffer(obj)) return PyObject_GetBuffer(obj, view, flags);
-    obj_type_name = __Pyx_PyType_GetName(Py_TYPE(obj));
-    PyErr_Format(PyExc_TypeError,
-                 "'" __Pyx_FMT_TYPENAME "' does not have the buffer interface",
-                 obj_type_name);
-    __Pyx_DECREF_TypeName(obj_type_name);
-    return -1;
-}
-static void __Pyx_ReleaseBuffer(Py_buffer *view) {
-    PyObject *obj = view->obj;
-    if (!obj) return;
-    if (PyObject_CheckBuffer(obj)) {
-        PyBuffer_Release(view);
-        return;
-    }
-    if ((0)) {}
-    view->obj = NULL;
-    Py_DECREF(obj);
-}
-#endif
-
-
-  /* CIntFromPyVerify */
-  #define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\
+/* CIntFromPyVerify */
+#define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\
     __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 0)
 #define __PYX_VERIFY_RETURN_INT_EXC(target_type, func_type, func_value)\
     __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 1)
@@ -10603,7 +10284,7 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) {
     }
 
 /* Declarations */
-  #if CYTHON_CCOMPLEX && (1) && (!0 || __cplusplus)
+#if CYTHON_CCOMPLEX && (1) && (!0 || __cplusplus)
   #ifdef __cplusplus
     static CYTHON_INLINE __pyx_t_float_complex __pyx_t_float_complex_from_parts(float x, float y) {
       return ::std::complex< float >(x, y);
@@ -10623,7 +10304,7 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) {
 #endif
 
 /* Arithmetic */
-  #if CYTHON_CCOMPLEX && (1) && (!0 || __cplusplus)
+#if CYTHON_CCOMPLEX && (1) && (!0 || __cplusplus)
 #else
     static CYTHON_INLINE int __Pyx_c_eq_float(__pyx_t_float_complex a, __pyx_t_float_complex b) {
        return (a.real == b.real) && (a.imag == b.imag);
@@ -10757,7 +10438,7 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) {
 #endif
 
 /* Declarations */
-  #if CYTHON_CCOMPLEX && (1) && (!0 || __cplusplus)
+#if CYTHON_CCOMPLEX && (1) && (!0 || __cplusplus)
   #ifdef __cplusplus
     static CYTHON_INLINE __pyx_t_double_complex __pyx_t_double_complex_from_parts(double x, double y) {
       return ::std::complex< double >(x, y);
@@ -10777,7 +10458,7 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) {
 #endif
 
 /* Arithmetic */
-  #if CYTHON_CCOMPLEX && (1) && (!0 || __cplusplus)
+#if CYTHON_CCOMPLEX && (1) && (!0 || __cplusplus)
 #else
     static CYTHON_INLINE int __Pyx_c_eq_double(__pyx_t_double_complex a, __pyx_t_double_complex b) {
        return (a.real == b.real) && (a.imag == b.imag);
@@ -10910,72 +10591,8 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) {
     #endif
 #endif
 
-/* CIntToPy */
-  static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) {
-#ifdef __Pyx_HAS_GCC_DIAGNOSTIC
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wconversion"
-#endif
-    const long neg_one = (long) -1, const_zero = (long) 0;
-#ifdef __Pyx_HAS_GCC_DIAGNOSTIC
-#pragma GCC diagnostic pop
-#endif
-    const int is_unsigned = neg_one > const_zero;
-    if (is_unsigned) {
-        if (sizeof(long) < sizeof(long)) {
-            return PyInt_FromLong((long) value);
-        } else if (sizeof(long) <= sizeof(unsigned long)) {
-            return PyLong_FromUnsignedLong((unsigned long) value);
-#ifdef HAVE_LONG_LONG
-        } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) {
-            return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value);
-#endif
-        }
-    } else {
-        if (sizeof(long) <= sizeof(long)) {
-            return PyInt_FromLong((long) value);
-#ifdef HAVE_LONG_LONG
-        } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) {
-            return PyLong_FromLongLong((PY_LONG_LONG) value);
-#endif
-        }
-    }
-    {
-        int one = 1; int little = (int)*(unsigned char *)&one;
-        unsigned char *bytes = (unsigned char *)&value;
-#if !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX < 0x030d0000
-        return _PyLong_FromByteArray(bytes, sizeof(long),
-                                     little, !is_unsigned);
-#else
-        PyObject *from_bytes, *result = NULL;
-        PyObject *py_bytes = NULL, *arg_tuple = NULL, *kwds = NULL, *order_str = NULL;
-        from_bytes = PyObject_GetAttrString((PyObject*)&PyLong_Type, "from_bytes");
-        if (!from_bytes) return NULL;
-        py_bytes = PyBytes_FromStringAndSize((char*)bytes, sizeof(long));
-        if (!py_bytes) goto limited_bad;
-        order_str = PyUnicode_FromString(little ? "little" : "big");
-        if (!order_str) goto limited_bad;
-        arg_tuple = PyTuple_Pack(2, py_bytes, order_str);
-        if (!arg_tuple) goto limited_bad;
-        if (!is_unsigned) {
-            kwds = PyDict_New();
-            if (!kwds) goto limited_bad;
-            if (PyDict_SetItemString(kwds, "signed", __Pyx_NewRef(Py_True))) goto limited_bad;
-        }
-        result = PyObject_Call(from_bytes, arg_tuple, kwds);
-        limited_bad:
-        Py_XDECREF(kwds);
-        Py_XDECREF(arg_tuple);
-        Py_XDECREF(order_str);
-        Py_XDECREF(py_bytes);
-        Py_XDECREF(from_bytes);
-        return result;
-#endif
-    }
-}
-
 /* CIntFromPy */
-  static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) {
+static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) {
 #ifdef __Pyx_HAS_GCC_DIAGNOSTIC
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wconversion"
@@ -11248,7 +10865,71 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) {
 }
 
 /* CIntToPy */
-  static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) {
+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) {
+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wconversion"
+#endif
+    const long neg_one = (long) -1, const_zero = (long) 0;
+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC
+#pragma GCC diagnostic pop
+#endif
+    const int is_unsigned = neg_one > const_zero;
+    if (is_unsigned) {
+        if (sizeof(long) < sizeof(long)) {
+            return PyInt_FromLong((long) value);
+        } else if (sizeof(long) <= sizeof(unsigned long)) {
+            return PyLong_FromUnsignedLong((unsigned long) value);
+#ifdef HAVE_LONG_LONG
+        } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) {
+            return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value);
+#endif
+        }
+    } else {
+        if (sizeof(long) <= sizeof(long)) {
+            return PyInt_FromLong((long) value);
+#ifdef HAVE_LONG_LONG
+        } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) {
+            return PyLong_FromLongLong((PY_LONG_LONG) value);
+#endif
+        }
+    }
+    {
+        int one = 1; int little = (int)*(unsigned char *)&one;
+        unsigned char *bytes = (unsigned char *)&value;
+#if !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX < 0x030d0000
+        return _PyLong_FromByteArray(bytes, sizeof(long),
+                                     little, !is_unsigned);
+#else
+        PyObject *from_bytes, *result = NULL;
+        PyObject *py_bytes = NULL, *arg_tuple = NULL, *kwds = NULL, *order_str = NULL;
+        from_bytes = PyObject_GetAttrString((PyObject*)&PyLong_Type, "from_bytes");
+        if (!from_bytes) return NULL;
+        py_bytes = PyBytes_FromStringAndSize((char*)bytes, sizeof(long));
+        if (!py_bytes) goto limited_bad;
+        order_str = PyUnicode_FromString(little ? "little" : "big");
+        if (!order_str) goto limited_bad;
+        arg_tuple = PyTuple_Pack(2, py_bytes, order_str);
+        if (!arg_tuple) goto limited_bad;
+        if (!is_unsigned) {
+            kwds = PyDict_New();
+            if (!kwds) goto limited_bad;
+            if (PyDict_SetItemString(kwds, "signed", __Pyx_NewRef(Py_True))) goto limited_bad;
+        }
+        result = PyObject_Call(from_bytes, arg_tuple, kwds);
+        limited_bad:
+        Py_XDECREF(kwds);
+        Py_XDECREF(arg_tuple);
+        Py_XDECREF(order_str);
+        Py_XDECREF(py_bytes);
+        Py_XDECREF(from_bytes);
+        return result;
+#endif
+    }
+}
+
+/* CIntToPy */
+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) {
 #ifdef __Pyx_HAS_GCC_DIAGNOSTIC
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wconversion"
@@ -11312,7 +10993,7 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) {
 }
 
 /* CIntToPy */
-  static CYTHON_INLINE PyObject* __Pyx_PyInt_From_char(char value) {
+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_char(char value) {
 #ifdef __Pyx_HAS_GCC_DIAGNOSTIC
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wconversion"
@@ -11376,7 +11057,7 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) {
 }
 
 /* FormatTypeName */
-  #if CYTHON_COMPILING_IN_LIMITED_API
+#if CYTHON_COMPILING_IN_LIMITED_API
 static __Pyx_TypeName
 __Pyx_PyType_GetName(PyTypeObject* tp)
 {
@@ -11385,14 +11066,14 @@ __Pyx_PyType_GetName(PyTypeObject* tp)
     if (unlikely(name == NULL) || unlikely(!PyUnicode_Check(name))) {
         PyErr_Clear();
         Py_XDECREF(name);
-        name = __Pyx_NewRef(__pyx_n_s__11);
+        name = __Pyx_NewRef(__pyx_n_s__12);
     }
     return name;
 }
 #endif
 
 /* CIntFromPy */
-  static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) {
+static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) {
 #ifdef __Pyx_HAS_GCC_DIAGNOSTIC
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wconversion"
@@ -11665,7 +11346,7 @@ __Pyx_PyType_GetName(PyTypeObject* tp)
 }
 
 /* FastTypeChecks */
-  #if CYTHON_COMPILING_IN_CPYTHON
+#if CYTHON_COMPILING_IN_CPYTHON
 static int __Pyx_InBases(PyTypeObject *a, PyTypeObject *b) {
     while (a) {
         a = __Pyx_PyType_GetSlot(a, tp_base, PyTypeObject*);
@@ -11781,7 +11462,7 @@ static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches2(PyObject *err, PyObj
 #endif
 
 /* CheckBinaryVersion */
-  static unsigned long __Pyx_get_runtime_version(void) {
+static unsigned long __Pyx_get_runtime_version(void) {
 #if __PYX_LIMITED_VERSION_HEX >= 0x030B00A4
     return Py_Version & ~0xFFUL;
 #else
@@ -11828,7 +11509,7 @@ static int __Pyx_check_binary_version(unsigned long ct_version, unsigned long rt
 }
 
 /* InitStrings */
-  #if PY_MAJOR_VERSION >= 3
+#if PY_MAJOR_VERSION >= 3
 static int __Pyx_InitString(__Pyx_StringTabEntry t, PyObject **str) {
     if (t.is_unicode | t.is_str) {
         if (t.intern) {
diff --git a/libjpeg/_libjpeg.pyx b/libjpeg/_libjpeg.pyx
index 28d50b6..7770540 100644
--- a/libjpeg/_libjpeg.pyx
+++ b/libjpeg/_libjpeg.pyx
@@ -2,6 +2,7 @@
 # distutils: language=c++
 
 from math import ceil
+from typing import Union, Dict, Tuple
 
 from libcpp cimport bool
 from libcpp.string cimport string
@@ -33,7 +34,11 @@ cdef extern from "decode.hpp":
     )
 
 
-def decode(np.ndarray[np.uint8_t, ndim=1] input_buffer, colourspace):
+def decode(
+    src: bytes,
+    colourspace: int,
+    as_array: bool = False,
+) -> Tuple[bytes, Union[bytes, np.ndarray, None], Dict[str, int]]:
     """Return the decoded JPEG data from `input_buffer`.
 
     Parameters
@@ -46,50 +51,60 @@ def decode(np.ndarray[np.uint8_t, ndim=1] input_buffer, colourspace):
         | ``2`` : ``JPGFLAG_MATRIX_COLORTRANSFORMATION_LSRCT``
         | ``2`` : ``JPGFLAG_MATRIX_COLORTRANSFORMATION_RCT``
         | ``3`` : ``JPGFLAG_MATRIX_COLORTRANSFORMATION_FREEFORM``
+    as_array : bool, optional
+        If ``True`` then return the decoded image data as an ndarray, otherwise
+        (default) return the decoded image data as :class:`bytearray`.
 
     Returns
     -------
-    bytes
-        The status and any error message of the decoding operation.
-    numpy.ndarray or None
-        A 1D array of ``np.uint8`` containing the decoded image data. Returns
-        ``None`` if the decode fails.
-    dict
-        A :class:`dict` containing the image parameters.
+    tuple[bytes, bytes | numpy.ndarray | None, dict]
+
+        * The status and any error message of the decoding operation.
+        * The decoded image data (if any) as either bytearray or ndarray
+        * A :class:`dict` containing the image parameters
     """
     # Get the image parameters
-    status, param = get_parameters(input_buffer)
+    status, param = get_parameters(src)
+    code, msg = status.decode("utf-8").split("::::")
+    if int(code) != 0:
+        return status, None, param
 
     # Pointer to first element in input array
-    cdef char *pInput = <char *>np.PyArray_DATA(input_buffer)
+    cdef char* p_in = <char*>src
 
     # Create array for output and get pointer to first element
     bpp = ceil(param['precision'] / 8)
     nr_bytes = (
         param['rows'] * param['columns'] * param['nr_components'] * bpp
     )
-    output_buffer = np.zeros(nr_bytes, dtype=np.uint8)
-    cdef char *pOutput = <char *>np.PyArray_DATA(output_buffer)
+
+    cdef char *p_out
+    if as_array:
+        out = np.zeros(nr_bytes, dtype=np.uint8)
+        p_out = <char *>np.PyArray_DATA(out)
+    else:
+        out = bytearray(nr_bytes)
+        p_out = <char *>out
 
     # Decode the data - output is written to output_buffer
     status = Decode(
-        pInput,
-        pOutput,
-        input_buffer.shape[0],
-        output_buffer.shape[0],
-        colourspace
+        p_in,
+        p_out,
+        len(src),
+        nr_bytes,
+        colourspace,
     )
 
-    return status, output_buffer, param
+    return status, out, param
 
 
-def get_parameters(np.ndarray[np.uint8_t, ndim=1] input_buffer):
+def get_parameters(src: bytes) -> Tuple[int, Dict[str, int]]:
     """Return a :class:`dict` containing the JPEG image parameters.
 
     Parameters
     ----------
-    input_buffer : numpy.ndarray
-        A 1D array of ``np.uint8`` containing the encoded JPEG image.
+    src : bytes
+        The encoded JPEG image.
 
     Returns
     -------
@@ -106,15 +121,10 @@ def get_parameters(np.ndarray[np.uint8_t, ndim=1] input_buffer):
     cdef JPEGParameters *pParam = &param
 
     # Pointer to first element in input array
-    cdef char *pInput = <char *>np.PyArray_DATA(input_buffer)
+    cdef char* p_in = <char*>src
 
     # Decode the data - output is written to output_buffer
-    status = GetJPEGParameters(
-        pInput,
-        input_buffer.shape[0],
-        pParam
-    )
-
+    status = GetJPEGParameters(p_in, len(src), pParam)
     parameters = {
         'rows' : param.rows,
         'columns' : param.columns,
@@ -135,7 +145,13 @@ cdef extern from "cmd/reconstruct.hpp":
     )
 
 
-def reconstruct(fin, fout, colourspace, falpha, upsample):
+def reconstruct(
+    fin: bytes,
+    fout: bytes,
+    colourspace: int,
+    falpha: Union[bytes, None],
+    upsample: bool,
+) -> None:
     """Decode the JPEG file in `fin` and write it to `fout` as PNM.
 
     Parameters
diff --git a/libjpeg/py.typed b/libjpeg/py.typed
new file mode 100644
index 0000000..e69de29
diff --git a/libjpeg/src/libjpeg b/libjpeg/src/libjpeg
deleted file mode 160000
index 87636f3..0000000
--- a/libjpeg/src/libjpeg
+++ /dev/null
@@ -1,1 +0,0 @@
-Subproject commit 87636f3b26b41b85b2fb7355c589a8c456ef808c
diff --git a/libjpeg/utils.py b/libjpeg/utils.py
index e390f39..d2d9172 100644
--- a/libjpeg/utils.py
+++ b/libjpeg/utils.py
@@ -1,7 +1,9 @@
-
 import enum
+from io import BytesIO
 from math import ceil
+import os
 from pathlib import Path
+from typing import Union, BinaryIO, Any, Dict, cast, TYPE_CHECKING
 import warnings
 
 import numpy as np
@@ -9,51 +11,71 @@
 import _libjpeg
 
 
+if TYPE_CHECKING:  # pragma: no cover
+    from pydicom.dataset import Dataset
+
+
+class Version(enum.IntEnum):
+    v1 = 1
+    v2 = 2
+
+
+COLOURSPACE = {
+    "MONOCHROME1": 0,
+    "MONOCHROME2": 0,
+    "RGB": 1,
+    "YBR_FULL": 0,
+    "YBR_FULL_422": 0,
+}
+
+
 LIBJPEG_ERROR_CODES = {
-    -1024 : "A parameter for a function was out of range",
-    -1025 : "Stream run out of data",
-    -1026 : "A code block run out of data",
-    -1027 : "Tried to perform an unputc or or an unget on an empty stream",
-    -1028 : "Some parameter run out of range",
-    -1029 : "The requested operation does not apply",
-    -1030 : "Tried to create an already existing object",
-    -1031 : "Tried to access a non-existing object",
-    -1032 : "A non-optional parameter was left out",
-    -1033 : "Forgot to delay a 0xFF",
-    -1034 : (
-        "Internal error: the requested operation is not available"
-    ),
-    -1035 : (
+    -1024: "A parameter for a function was out of range",
+    -1025: "Stream run out of data",
+    -1026: "A code block run out of data",
+    -1027: "Tried to perform an unputc or or an unget on an empty stream",
+    -1028: "Some parameter run out of range",
+    -1029: "The requested operation does not apply",
+    -1030: "Tried to create an already existing object",
+    -1031: "Tried to access a non-existing object",
+    -1032: "A non-optional parameter was left out",
+    -1033: "Forgot to delay a 0xFF",
+    -1034: ("Internal error: the requested operation is not available"),
+    -1035: (
         "Internal error: an item computed on a former pass does not "
         "coincide with the same item on a later pass"
     ),
-    -1036 : "The stream passed in is no valid jpeg stream",
-    -1037 : (
+    -1036: "The stream passed in is no valid jpeg stream",
+    -1037: (
         "A unique marker turned up more than once. The input stream is "
         "most likely corrupt"
     ),
-    -1038 : "A misplaced marker segment was found",
-    -1040 : (
+    -1038: "A misplaced marker segment was found",
+    -1040: (
         "The specified parameters are valid, but are not supported by "
         "the selected profile. Either use a higher profile, or use "
         "simpler parameters (encoder only). "
     ),
-    -1041 : (
+    -1041: (
         "Internal error: the worker thread that was currently active had "
         "to terminate unexpectedly"
     ),
-    -1042 : (
+    -1042: (
         "The encoder tried to emit a symbol for which no Huffman code "
         "was defined. This happens if the standard Huffman table is used "
         "for an alphabet for which it was not defined. The reaction "
         "to this exception should be to create a custom huffman table "
         "instead"
     ),
-    -2046 : "Failed to construct the JPEG object",
+    -2046: "Failed to construct the JPEG object",
 }
 
 
-def decode(stream, colour_transform=0, reshape=True):
+def decode(
+    stream: Union[str, os.PathLike, bytes, bytearray, BinaryIO],
+    colour_transform: int = 0,
+    reshape: bool = True,
+) -> np.ndarray:
     """Return the decoded JPEG data from `arr` as a :class:`numpy.ndarray`.
 
     .. versionchanged:: 1.2
@@ -62,9 +84,10 @@ def decode(stream, colour_transform=0, reshape=True):
 
     Parameters
     ----------
-    stream : str, Path, numpy.ndarray or bytes
-        The path to the JPEG file, a 1D array of ``np.uint8``, or a Python
-        :class:`bytes` object containing the raw encoded JPEG image.
+    stream : str, pathlib.Path, bytes or file-like
+        The path to the JPEG file or a Python object containing the
+        encoded JPEG data. If using a file-like then the object must have
+        ``tell()``, ``seek()`` and ``read()`` methods.
     colour_transform : int, optional
         The colour transform used, one of:
         | ``0`` : No transform applied (default)
@@ -87,100 +110,129 @@ def decode(stream, colour_transform=0, reshape=True):
     """
     if isinstance(stream, (str, Path)):
         with open(stream, "rb") as f:
-            stream = f.read()
-
-    if isinstance(stream, bytes):
-        arr = np.frombuffer(stream, 'uint8')
+            buffer = f.read()
+    elif isinstance(stream, (bytes, bytearray)):
+        buffer = stream
     else:
-        arr = stream
-
-    status, out, params = _libjpeg.decode(arr, colour_transform)
+        # BinaryIO
+        stream = cast(BinaryIO, stream)
+        required_methods = ["read", "tell", "seek"]
+        if not all([hasattr(stream, meth) for meth in required_methods]):
+            raise TypeError(
+                "The Python object containing the encoded JPEG 2000 data must "
+                "either be bytes or have read(), tell() and seek() methods."
+            )
+        buffer = stream.read()
+
+    status, out, params = _libjpeg.decode(buffer, colour_transform, as_array=True)
     status = status.decode("utf-8")
     code, msg = status.split("::::")
     code = int(code)
 
-    if code == 0 and reshape is True:
+    if code == 0 and reshape:
         bpp = ceil(params["precision"] / 8)
         if bpp == 2:
-            out = out.view('uint16')
+            out = out.view("uint16")
 
-        shape = [params['rows'], params['columns']]
+        shape = [params["rows"], params["columns"]]
         if params["nr_components"] > 1:
             shape.append(params["nr_components"])
 
-        return out.reshape(*shape)
-    elif code == 0 and reshape is False:
-        return out
+        return cast(np.ndarray, out.reshape(*shape))
+
+    if code == 0 and not reshape:
+        return cast(np.ndarray, out)
 
     if code in LIBJPEG_ERROR_CODES:
         raise RuntimeError(
-            "libjpeg error code '{}' returned from Decode(): {} - {}"
-            .format(code, LIBJPEG_ERROR_CODES[code], msg)
+            f"libjpeg error code '{code}' returned from Decode(): "
+            f"{LIBJPEG_ERROR_CODES[code]} - {msg}"
         )
 
-    raise RuntimeError(
-        "Unknown error code '{}' returned from Decode(): {}"
-        .format(code, msg)
-    )
+    raise RuntimeError(f"Unknown error code '{code}' returned from Decode(): {msg}")
 
 
-def decode_pixel_data(arr, ds = None, **kwargs):
+def decode_pixel_data(
+    src: bytes,
+    ds: Union["Dataset", Dict[str, Any], None] = None,
+    version: int = Version.v1,
+    **kwargs: Any,
+) -> Union[np.ndarray, bytearray]:
     """Return the decoded JPEG data from `arr` as a :class:`numpy.ndarray`.
 
     Intended for use with *pydicom* ``Dataset`` objects.
 
     Parameters
     ----------
-    arr : numpy.ndarray or bytes
-        A 1D array of ``np.uint8``, or a Python :class:`bytes` object
-        containing the encoded JPEG image.
+    src : bytes
+        A Python :class:`bytes` instance containing the encoded JPEG data.
     ds : pydicom.dataset.Dataset, optional
         A :class:`~pydicom.dataset.Dataset` containing the group ``0x0028``
         elements corresponding to the *Pixel Data*. Must contain a
         (0028,0004) *Photometric Interpretation* element with the colour
         space of the pixel data, one of ``'MONOCHROME1'``, ``'MONOCHROME2'``,
         ``'RGB'``, ``'YBR_FULL'``, ``'YBR_FULL_422'``.
-    **kwargs
+    version : int, optional
+
+        * If ``1`` (default) then return the image data as an :class:`numpy.ndarray`
+        * If ``2`` then return the image data as :class:`bytearray`
 
     Returns
     -------
-    numpy.ndarray
-        A 1D array of ``numpy.uint8`` containing the decoded image data.
+    bytearray | numpy.ndarray
+        The image data as either a bytearray or ndarray.
 
     Raises
     ------
     RuntimeError
         If the decoding failed.
     """
-    colours = {
-        'MONOCHROME1': 0,
-        'MONOCHROME2' : 0,
-        'RGB' : 1,
-        'YBR_FULL' : 0,
-        'YBR_FULL_422' : 0,
-    }
-
-    photometric_interpretation = kwargs.get("photometric_interpretation")
-    pi = ds.get("PhotometricInterpretation", photometric_interpretation)
-    if not pi:
-        raise ValueError(
-            "The (0028,0004) Photometric Interpretation element is missing "
-            "from the dataset"
-        )
+    ds = {} if not ds else ds
+
+    if version == Version.v1:
+        photometric_interpretation = kwargs.get("photometric_interpretation")
+        pi = ds.get("PhotometricInterpretation", photometric_interpretation)
+        if not pi:
+            raise ValueError(
+                "The (0028,0004) Photometric Interpretation element is missing "
+                "from the dataset"
+            )
+
+        try:
+            transform = COLOURSPACE[pi]
+        except KeyError:
+            warnings.warn(
+                f"Unsupported (0028,0004) Photometric Interpretation '{pi}', no "
+                "colour transformation will be applied"
+            )
+            transform = 0
+
+        return decode(src, transform, reshape=False)
+
+    # Version 2
+    photometric_interpretation = kwargs.get("photometric_interpretation", pi)
+    colour_transform = COLOURSPACE.get(photometric_interpretation, 0)
+
+    status, out, params = _libjpeg.decode(src, colour_transform, as_array=False)
+    status = status.decode("utf-8")
+    code, msg = status.split("::::")
+    code = int(code)
+
+    if code == 0:
+        return cast(bytearray, out)
 
-    try:
-        transform = colours[pi]
-    except KeyError:
-        warnings.warn(
-            f"Unsupported (0028,0004) Photometric Interpretation '{pi}', no "
-            "colour transformation will be applied"
+    if code in LIBJPEG_ERROR_CODES:
+        raise RuntimeError(
+            f"libjpeg error code '{code}' returned from decode(): "
+            f"{LIBJPEG_ERROR_CODES[code]} - {msg}"
         )
-        transform = 0
 
-    return decode(arr, transform, reshape=False)
+    raise RuntimeError(f"Unknown error code '{code}' returned from decode(): {msg}")
 
 
-def get_parameters(stream):
+def get_parameters(
+    stream: Union[str, os.PathLike, bytes, bytearray, BinaryIO],
+) -> Dict[str, int]:
     """Return a :class:`dict` containing JPEG image parameters.
 
     .. versionchanged:: 1.2
@@ -189,7 +241,7 @@ def get_parameters(stream):
 
     Parameters
     ----------
-    stream : str, Path, numpy.ndarray or bytes
+    stream : str, Path, bytes
         The path to the JPEG file, a 1D array of ``np.uint8``, or a Python
         :class:`bytes` object containing the raw encoded JPEG image.
 
@@ -207,34 +259,39 @@ def get_parameters(stream):
     """
     if isinstance(stream, (str, Path)):
         with open(stream, "rb") as f:
-            stream = f.read()
-
-    if isinstance(stream, bytes):
-        arr = np.frombuffer(stream, 'uint8')
+            buffer = f.read()
+    elif isinstance(stream, (bytes, bytearray)):
+        buffer = stream
     else:
-        arr = stream
+        stream = cast(BinaryIO, stream)
+        buffer = stream.read()
 
-    status, params = _libjpeg.get_parameters(arr)
+    status, params = _libjpeg.get_parameters(buffer)
     status = status.decode("utf-8")
     code, msg = status.split("::::")
     code = int(code)
 
     if code == 0:
-        return params
+        return cast(Dict[str, int], params)
 
     if code in LIBJPEG_ERROR_CODES:
         raise RuntimeError(
-            "libjpeg error code '{}' returned from GetJPEGParameters(): "
-            "{} - {}".format(code, LIBJPEG_ERROR_CODES[code], msg)
+            f"libjpeg error code '{code}' returned from GetJPEGParameters(): "
+            f"{LIBJPEG_ERROR_CODES[code]} - {msg}"
         )
 
     raise RuntimeError(
-        "Unknown error code '{}' returned from GetJPEGParameters(): {}"
-        .format(status, msg)
+        f"Unknown error code '{status}' returned from GetJPEGParameters(): {msg}"
     )
 
 
-def reconstruct(fin, fout, colourspace=1, falpha=None, upsample=True):
+def reconstruct(
+    fin: Union[str, os.PathLike, bytes],
+    fout: Union[str, os.PathLike, bytes],
+    colourspace: int = 1,
+    falpha: Union[bytes, None] = None,
+    upsample: bool = True,
+) -> None:
     """Simple wrapper for the libjpeg ``cmd/reconstruct::Reconstruct()``
     function.
 
@@ -263,14 +320,14 @@ def reconstruct(fin, fout, colourspace=1, falpha=None, upsample=True):
     """
     if isinstance(fin, (str, Path)):
         fin = str(fin)
-        fin = bytes(fin, 'utf-8')
+        fin = bytes(fin, "utf-8")
 
     if isinstance(fout, (str, Path)):
         fout = str(fout)
-        fout = bytes(fout, 'utf-8')
+        fout = bytes(fout, "utf-8")
 
     if falpha and isinstance(falpha, (str, Path)):
         falpha = str(falpha)
-        falpha = bytes(falpha, 'utf-8')
+        falpha = bytes(falpha, "utf-8")
 
     _libjpeg.reconstruct(fin, fout, colourspace, falpha, upsample)
diff --git a/poetry.lock b/poetry.lock
index 858c616..6325378 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -310,12 +310,51 @@ files = [
 dev = ["pre-commit", "tox"]
 testing = ["pytest", "pytest-benchmark"]
 
+[[package]]
+name = "pydicom"
+version = "2.4.4"
+description = "A pure Python package for reading and writing DICOM data"
+optional = true
+python-versions = ">=3.7"
+files = [
+    {file = "pydicom-2.4.4-py3-none-any.whl", hash = "sha256:f9f8e19b78525be57aa6384484298833e4d06ac1d6226c79459131ddb0bd7c42"},
+    {file = "pydicom-2.4.4.tar.gz", hash = "sha256:90b4801d851ce65be3df520e16bbfa3d6c767cf2a3a3b1c18f6780e6b670b87a"},
+]
+
+[package.extras]
+docs = ["matplotlib", "numpy", "numpydoc", "pillow", "sphinx", "sphinx-copybutton", "sphinx-gallery", "sphinx_rtd_theme", "sphinxcontrib-napoleon"]
+
+[[package]]
+name = "pylibjpeg"
+version = "2.0.0.dev0"
+description = "A Python framework for decoding JPEG and decoding/encoding DICOMRLE data, with a focus on supporting pydicom"
+optional = true
+python-versions = ">=3.8"
+files = []
+develop = false
+
+[package.dependencies]
+numpy = "*"
+
+[package.extras]
+all = ["pylibjpeg-libjpeg", "pylibjpeg-openjpeg", "pylibjpeg-rle"]
+dev = ["black (==23.12.1)", "mypy (==1.8.0)", "pytest", "pytest-cov"]
+libjpeg = ["pylibjpeg-libjpeg"]
+openjpeg = ["pylibjpeg-openjpeg"]
+rle = ["pylibjpeg-rle"]
+
+[package.source]
+type = "git"
+url = "https://github.com/pydicom/pylibjpeg.git"
+reference = "HEAD"
+resolved_reference = "1b4fab891295aed33c6a504ab983e48cf763cc0e"
+
 [[package]]
 name = "pylibjpeg-data"
 version = "1.0.0.dev0"
 description = "Optional JPEG and DICOM data used for testing pylibjpeg"
 optional = true
-python-versions = ">=3.6"
+python-versions = ">=3.8"
 files = []
 develop = false
 
@@ -323,7 +362,7 @@ develop = false
 type = "git"
 url = "https://github.com/pydicom/pylibjpeg-data.git"
 reference = "HEAD"
-resolved_reference = "2ab4b8a65b070656eca2582bd23197a3d01cdccd"
+resolved_reference = "916aa154a06ac6e85678d8bcffe4273814752c96"
 
 [[package]]
 name = "pytest"
@@ -389,9 +428,9 @@ files = [
 
 [extras]
 dev = ["black", "coverage", "mypy", "pytest", "pytest-cov"]
-tests = ["coverage", "pylibjpeg-data", "pytest", "pytest-cov"]
+tests = ["coverage", "pydicom", "pylibjpeg", "pylibjpeg-data", "pytest", "pytest-cov"]
 
 [metadata]
 lock-version = "2.0"
 python-versions = "^3.8"
-content-hash = "64522c182d9c24165d3bf5ab2f630c9bf8cb64fc47ba6b15c3c64e06b46f1485"
+content-hash = "e4f29c6332ebc09ac33a172012e49c702d00f76e4bc2d29661ca0c33304e4b60"
diff --git a/pyproject.toml b/pyproject.toml
index e637f06..24916fa 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -38,19 +38,22 @@ description = """\
     "for pylibjpeg"\
 """
 homepage = "https://github.com/pydicom/pylibjpeg-libjpeg"
-include = [
-    "libjpeg/src/*",
-]
-exclude = [
-    "libjpeg/src/config.log",
-    "libjpeg/src/config.status",
-]
 keywords = ["dicom pydicom python jpg jpeg jpg-ls jpeg-ls libjpeg pylibjpeg"]
 license = "GPL V3.0"
 maintainers = ["scaramallion <scaramallion@users.noreply.github.com>"]
 name = "pylibjpeg-libjpeg"
+# We want to be able to build from sdist, so include required libjpeg src
+#   But don't include any libjpeg src in the built wheels
+include = [
+    { path = "lib", format = "sdist" },
+    { path = "build_tools", format = "sdist" },
+]
+exclude = [
+    "lib/libjpeg/config.log",
+    "lib/libjpeg/config.status",
+]
 packages = [
-    {include = "libjpeg"}
+    { include = "libjpeg" },
 ]
 readme = "README.md"
 version = "2.0.0.dev0"
@@ -65,11 +68,13 @@ coverage = { version = "^7.3", optional = true }
 mypy = { version = "^1.7", optional = true }
 pytest = { version = "^7.4", optional = true }
 pytest-cov = { version = "^4.1", optional = true }
+pydicom = { version = "^2.4", optional = true }
+pylibjpeg = { git = "https://github.com/pydicom/pylibjpeg.git", optional = true}
 pylibjpeg-data = { git = "https://github.com/pydicom/pylibjpeg-data.git", optional = true}
 
 [tool.poetry.extras]
 dev = ["black", "coverage", "mypy", "pytest", "pytest-cov"]
-tests = ["coverage", "pytest", "pytest-cov", "pylibjpeg-data"]
+tests = ["coverage", "pytest", "pytest-cov", "pylibjpeg-data", "pylibjpeg", "pydicom"]
 
 [tool.poetry.plugins."pylibjpeg.jpeg_decoders"]
 libjpeg = "libjpeg:decode"


Test patch:
diff --git a/libjpeg/tests/__init__.py b/libjpeg/tests/__init__.py
index 023d945..4bc6bdc 100644
--- a/libjpeg/tests/__init__.py
+++ b/libjpeg/tests/__init__.py
@@ -1,11 +1,11 @@
-
 import sys
 
 # Add the pylibjpeg testing data to libjpeg (if available)
 try:
     import ljdata as _data
-    globals()['data'] = _data
+
+    globals()["data"] = _data
     # Add to cache - needed for pytest
-    sys.modules['libjpeg.data'] = _data
+    sys.modules["libjpeg.data"] = _data
 except ImportError:
     pass
diff --git a/libjpeg/tests/test_decode.py b/libjpeg/tests/test_decode.py
index aaffb03..66ed03b 100644
--- a/libjpeg/tests/test_decode.py
+++ b/libjpeg/tests/test_decode.py
@@ -12,6 +12,7 @@
     import pydicom
     from pydicom.encaps import generate_pixel_data_frame
     from pydicom.pixel_data_handlers.util import reshape_pixel_array
+
     HAS_PYDICOM = True
 except ImportError:
     HAS_PYDICOM = False
@@ -20,48 +21,48 @@
 from libjpeg.data import get_indexed_datasets, JPEG_DIRECTORY
 
 
-DIR_10918 = JPEG_DIRECTORY / '10918'
-DIR_14495 = JPEG_DIRECTORY / '14495'
+DIR_10918 = JPEG_DIRECTORY / "10918"
+DIR_14495 = JPEG_DIRECTORY / "14495"
 
 
 REF_DCM = {
-    '1.2.840.10008.1.2.4.50' : [
+    "1.2.840.10008.1.2.4.50": [
         # filename, (rows, columns, samples/px, bits/sample)
-        ('JPEGBaseline_1s_1f_u_08_08.dcm', (100, 100, 1, 8)),
-        ('SC_rgb_dcmtk_+eb+cy+np.dcm', (100, 100, 3, 8)),
-        ('color3d_jpeg_baseline.dcm', (480, 640, 3, 8)),
-        ('SC_rgb_dcmtk_+eb+cr.dcm', (100, 100, 3, 8)),
-        ('SC_rgb_dcmtk_+eb+cy+n1.dcm', (100, 100, 3, 8)),
-        ('SC_rgb_dcmtk_+eb+cy+s4.dcm', (100, 100, 3, 8)),
+        ("JPEGBaseline_1s_1f_u_08_08.dcm", (100, 100, 1, 8)),
+        ("SC_rgb_dcmtk_+eb+cy+np.dcm", (100, 100, 3, 8)),
+        ("color3d_jpeg_baseline.dcm", (480, 640, 3, 8)),
+        ("SC_rgb_dcmtk_+eb+cr.dcm", (100, 100, 3, 8)),
+        ("SC_rgb_dcmtk_+eb+cy+n1.dcm", (100, 100, 3, 8)),
+        ("SC_rgb_dcmtk_+eb+cy+s4.dcm", (100, 100, 3, 8)),
     ],
-    '1.2.840.10008.1.2.4.51' : [
-        ('RG2_JPLY_fixed.dcm', (2140, 1760, 1, 12)),
-        ('JPEGExtended_1s_1f_u_16_12.dcm', (1024, 256, 1, 12)),
-        ('JPEGExtended_3s_1f_u_08_08.dcm', (576, 768, 3, 8)),
+    "1.2.840.10008.1.2.4.51": [
+        ("RG2_JPLY_fixed.dcm", (2140, 1760, 1, 12)),
+        ("JPEGExtended_1s_1f_u_16_12.dcm", (1024, 256, 1, 12)),
+        ("JPEGExtended_3s_1f_u_08_08.dcm", (576, 768, 3, 8)),
     ],
-    '1.2.840.10008.1.2.4.57' : [
-        ('JPEGLossless_1s_1f_u_16_12.dcm', (1024, 1024, 1, 12)),
+    "1.2.840.10008.1.2.4.57": [
+        ("JPEGLossless_1s_1f_u_16_12.dcm", (1024, 1024, 1, 12)),
     ],
-    '1.2.840.10008.1.2.4.70' : [
-        ('JPEG-LL.dcm', (1024, 256, 1, 16)),
-        ('JPEGLosslessP14SV1_1s_1f_u_08_08.dcm', (768, 1024, 1, 8)),
-        ('JPEGLosslessP14SV1_1s_1f_u_16_16.dcm', (535, 800, 1, 16)),
-        ('MG1_JPLL.dcm', (4664, 3064, 1, 12)),
-        ('RG1_JPLL.dcm', (1955, 1841, 1, 15)),
-        ('RG2_JPLL.dcm', (2140, 1760, 1, 10)),
-        ('SC_rgb_jpeg_gdcm.dcm', (100, 100, 3, 8)),
+    "1.2.840.10008.1.2.4.70": [
+        ("JPEG-LL.dcm", (1024, 256, 1, 16)),
+        ("JPEGLosslessP14SV1_1s_1f_u_08_08.dcm", (768, 1024, 1, 8)),
+        ("JPEGLosslessP14SV1_1s_1f_u_16_16.dcm", (535, 800, 1, 16)),
+        ("MG1_JPLL.dcm", (4664, 3064, 1, 12)),
+        ("RG1_JPLL.dcm", (1955, 1841, 1, 15)),
+        ("RG2_JPLL.dcm", (2140, 1760, 1, 10)),
+        ("SC_rgb_jpeg_gdcm.dcm", (100, 100, 3, 8)),
     ],
-    '1.2.840.10008.1.2.4.80' : [
-        ('emri_small_jpeg_ls_lossless.dcm', (64, 64, 1, 12)),
-        ('MR_small_jpeg_ls_lossless.dcm', (64, 64, 1, 16)),
-        ('RG1_JLSL.dcm', (1955, 1841, 1, 16)),
-        ('RG2_JLSL.dcm', (2140, 1760, 1, 10)),
+    "1.2.840.10008.1.2.4.80": [
+        ("emri_small_jpeg_ls_lossless.dcm", (64, 64, 1, 12)),
+        ("MR_small_jpeg_ls_lossless.dcm", (64, 64, 1, 16)),
+        ("RG1_JLSL.dcm", (1955, 1841, 1, 16)),
+        ("RG2_JLSL.dcm", (2140, 1760, 1, 10)),
     ],
-    '1.2.840.10008.1.2.4.81' : [
-        ('CT1_JLSN.dcm', (512, 512, 1, 16)),
-        ('MG1_JLSN.dcm', (4664, 3064, 1, 12)),
-        ('RG1_JLSN.dcm', (1955, 1841, 1, 15)),
-        ('RG2_JLSN.dcm', (2140, 1760, 1, 10)),
+    "1.2.840.10008.1.2.4.81": [
+        ("CT1_JLSN.dcm", (512, 512, 1, 16)),
+        ("MG1_JLSN.dcm", (4664, 3064, 1, 12)),
+        ("RG1_JLSN.dcm", (1955, 1841, 1, 15)),
+        ("RG2_JLSN.dcm", (2140, 1760, 1, 10)),
     ],
 }
 
@@ -70,24 +71,24 @@
 @pytest.mark.skipif(not HAS_PYDICOM, reason="No pydicom")
 def test_decode_bytes():
     """Test decode using bytes."""
-    index = get_indexed_datasets('1.2.840.10008.1.2.4.50')
-    ds = index['JPEGBaseline_1s_1f_u_08_08.dcm']['ds']
-    nr_frames = ds.get('NumberOfFrames', 1)
+    index = get_indexed_datasets("1.2.840.10008.1.2.4.50")
+    ds = index["JPEGBaseline_1s_1f_u_08_08.dcm"]["ds"]
+    nr_frames = ds.get("NumberOfFrames", 1)
     frame = next(generate_pixel_data_frame(ds.PixelData, nr_frames))
     arr = decode(frame)
     assert arr.flags.writeable
-    assert 'uint8' == arr.dtype
+    assert "uint8" == arr.dtype
     assert (ds.Rows, ds.Columns) == arr.shape
 
     # Reference values from GDCM handler
-    assert  76 == arr[ 5, 50]
+    assert 76 == arr[5, 50]
     assert 167 == arr[15, 50]
     assert 149 == arr[25, 50]
     assert 203 == arr[35, 50]
-    assert  29 == arr[45, 50]
+    assert 29 == arr[45, 50]
     assert 142 == arr[55, 50]
-    assert   1 == arr[65, 50]
-    assert  64 == arr[75, 50]
+    assert 1 == arr[65, 50]
+    assert 64 == arr[75, 50]
     assert 192 == arr[85, 50]
     assert 255 == arr[95, 50]
 
@@ -96,30 +97,30 @@ def test_decode_bytes():
 @pytest.mark.skipif(not HAS_PYDICOM, reason="No pydicom")
 def test_invalid_colourspace_warns():
     """Test that using an unknown colourspace gives a warning."""
-    index = get_indexed_datasets('1.2.840.10008.1.2.4.50')
-    ds = index['JPEGBaseline_1s_1f_u_08_08.dcm']['ds']
-    nr_frames = ds.get('NumberOfFrames', 1)
+    index = get_indexed_datasets("1.2.840.10008.1.2.4.50")
+    ds = index["JPEGBaseline_1s_1f_u_08_08.dcm"]["ds"]
+    nr_frames = ds.get("NumberOfFrames", 1)
     frame = next(generate_pixel_data_frame(ds.PixelData, nr_frames))
     msg = r"no colour transformation will be applied"
-    ds.PhotometricInterpretation = 'ANY'
+    ds.PhotometricInterpretation = "ANY"
     with pytest.warns(UserWarning, match=msg):
-        arr = decode_pixel_data(np.frombuffer(frame, 'uint8'), ds)
+        arr = decode_pixel_data(frame, ds)
 
     arr = reshape_pixel_array(ds, arr)
 
     assert arr.flags.writeable
-    assert 'uint8' == arr.dtype
+    assert "uint8" == arr.dtype
     assert (ds.Rows, ds.Columns) == arr.shape
 
     # Reference values from GDCM handler
-    assert  76 == arr[ 5, 50]
+    assert 76 == arr[5, 50]
     assert 167 == arr[15, 50]
     assert 149 == arr[25, 50]
     assert 203 == arr[35, 50]
-    assert  29 == arr[45, 50]
+    assert 29 == arr[45, 50]
     assert 142 == arr[55, 50]
-    assert   1 == arr[65, 50]
-    assert  64 == arr[75, 50]
+    assert 1 == arr[65, 50]
+    assert 64 == arr[75, 50]
     assert 192 == arr[85, 50]
     assert 255 == arr[95, 50]
 
@@ -127,20 +128,21 @@ def test_invalid_colourspace_warns():
 @pytest.mark.skipif(not HAS_PYDICOM, reason="No pydicom")
 class TestDecodeDCM:
     """Tests for get_parameters() using DICOM datasets."""
+
     def generate_frames(self, ds):
         """Return a generator object with the dataset's pixel data frames."""
-        nr_frames = ds.get('NumberOfFrames', 1)
+        nr_frames = ds.get("NumberOfFrames", 1)
         return generate_pixel_data_frame(ds.PixelData, nr_frames)
 
-    @pytest.mark.parametrize("fname, info", REF_DCM['1.2.840.10008.1.2.4.50'])
+    @pytest.mark.parametrize("fname, info", REF_DCM["1.2.840.10008.1.2.4.50"])
     def test_baseline(self, fname, info):
         """Test get_parameters() for the baseline datasets."""
-        #info: (rows, columns, spp, bps)
-        index = get_indexed_datasets('1.2.840.10008.1.2.4.50')
-        ds = index[fname]['ds']
+        # info: (rows, columns, spp, bps)
+        index = get_indexed_datasets("1.2.840.10008.1.2.4.50")
+        ds = index[fname]["ds"]
 
         frame = next(self.generate_frames(ds))
-        arr = decode(np.frombuffer(frame, 'uint8'), reshape=True)
+        arr = decode(frame, reshape=True)
 
         if info[2] == 1:
             assert (info[0], info[1]) == arr.shape
@@ -148,19 +150,19 @@ def test_baseline(self, fname, info):
             assert (info[0], info[1], info[2]) == arr.shape
 
         if 1 <= info[3] <= 8:
-            assert arr.dtype == 'uint8'
+            assert arr.dtype == "uint8"
         if 9 <= info[3] <= 16:
-            assert arr.dtype == 'uint16'
+            assert arr.dtype == "uint16"
 
-    @pytest.mark.parametrize("fname, info", REF_DCM['1.2.840.10008.1.2.4.51'])
+    @pytest.mark.parametrize("fname, info", REF_DCM["1.2.840.10008.1.2.4.51"])
     def test_extended(self, fname, info):
         """Test get_parameters() for the baseline datasets."""
-        #info: (rows, columns, spp, bps)
-        index = get_indexed_datasets('1.2.840.10008.1.2.4.51')
-        ds = index[fname]['ds']
+        # info: (rows, columns, spp, bps)
+        index = get_indexed_datasets("1.2.840.10008.1.2.4.51")
+        ds = index[fname]["ds"]
 
         frame = next(self.generate_frames(ds))
-        arr = decode(np.frombuffer(frame, 'uint8'), reshape=True)
+        arr = decode(frame, reshape=True)
 
         if info[2] == 1:
             assert (info[0], info[1]) == arr.shape
@@ -168,19 +170,19 @@ def test_extended(self, fname, info):
             assert (info[0], info[1], info[2]) == arr.shape
 
         if 1 <= info[3] <= 8:
-            assert arr.dtype == 'uint8'
+            assert arr.dtype == "uint8"
         if 9 <= info[3] <= 16:
-            assert arr.dtype == 'uint16'
+            assert arr.dtype == "uint16"
 
-    @pytest.mark.parametrize("fname, info", REF_DCM['1.2.840.10008.1.2.4.57'])
+    @pytest.mark.parametrize("fname, info", REF_DCM["1.2.840.10008.1.2.4.57"])
     def test_lossless(self, fname, info):
         """Test get_parameters() for the lossless datasets."""
-        #info: (rows, columns, spp, bps)
-        index = get_indexed_datasets('1.2.840.10008.1.2.4.57')
-        ds = index[fname]['ds']
+        # info: (rows, columns, spp, bps)
+        index = get_indexed_datasets("1.2.840.10008.1.2.4.57")
+        ds = index[fname]["ds"]
 
         frame = next(self.generate_frames(ds))
-        arr = decode(np.frombuffer(frame, 'uint8'), reshape=True)
+        arr = decode(frame, reshape=True)
 
         if info[2] == 1:
             assert (info[0], info[1]) == arr.shape
@@ -188,19 +190,19 @@ def test_lossless(self, fname, info):
             assert (info[0], info[1], info[2]) == arr.shape
 
         if 1 <= info[3] <= 8:
-            assert arr.dtype == 'uint8'
+            assert arr.dtype == "uint8"
         if 9 <= info[3] <= 16:
-            assert arr.dtype == 'uint16'
+            assert arr.dtype == "uint16"
 
-    @pytest.mark.parametrize("fname, info", REF_DCM['1.2.840.10008.1.2.4.70'])
+    @pytest.mark.parametrize("fname, info", REF_DCM["1.2.840.10008.1.2.4.70"])
     def test_lossless_sv1(self, fname, info):
         """Test get_parameters() for the lossless SV1 datasets."""
-        #info: (rows, columns, spp, bps)
-        index = get_indexed_datasets('1.2.840.10008.1.2.4.70')
-        ds = index[fname]['ds']
+        # info: (rows, columns, spp, bps)
+        index = get_indexed_datasets("1.2.840.10008.1.2.4.70")
+        ds = index[fname]["ds"]
 
         frame = next(self.generate_frames(ds))
-        arr = decode(np.frombuffer(frame, 'uint8'), reshape=True)
+        arr = decode(frame, reshape=True)
 
         if info[2] == 1:
             assert (info[0], info[1]) == arr.shape
@@ -208,19 +210,19 @@ def test_lossless_sv1(self, fname, info):
             assert (info[0], info[1], info[2]) == arr.shape
 
         if 1 <= info[3] <= 8:
-            assert arr.dtype == 'uint8'
+            assert arr.dtype == "uint8"
         if 9 <= info[3] <= 16:
-            assert arr.dtype == 'uint16'
+            assert arr.dtype == "uint16"
 
-    @pytest.mark.parametrize("fname, info", REF_DCM['1.2.840.10008.1.2.4.80'])
+    @pytest.mark.parametrize("fname, info", REF_DCM["1.2.840.10008.1.2.4.80"])
     def test_extended(self, fname, info):
         """Test get_parameters() for the LS lossless datasets."""
-        #info: (rows, columns, spp, bps)
-        index = get_indexed_datasets('1.2.840.10008.1.2.4.80')
-        ds = index[fname]['ds']
+        # info: (rows, columns, spp, bps)
+        index = get_indexed_datasets("1.2.840.10008.1.2.4.80")
+        ds = index[fname]["ds"]
 
         frame = next(self.generate_frames(ds))
-        arr = decode(np.frombuffer(frame, 'uint8'), reshape=True)
+        arr = decode(frame, reshape=True)
 
         if info[2] == 1:
             assert (info[0], info[1]) == arr.shape
@@ -228,19 +230,19 @@ def test_extended(self, fname, info):
             assert (info[0], info[1], info[2]) == arr.shape
 
         if 1 <= info[3] <= 8:
-            assert arr.dtype == 'uint8'
+            assert arr.dtype == "uint8"
         if 9 <= info[3] <= 16:
-            assert arr.dtype == 'uint16'
+            assert arr.dtype == "uint16"
 
-    @pytest.mark.parametrize("fname, info", REF_DCM['1.2.840.10008.1.2.4.81'])
+    @pytest.mark.parametrize("fname, info", REF_DCM["1.2.840.10008.1.2.4.81"])
     def test_extended(self, fname, info):
         """Test get_parameters() for the LS lossy datasets."""
-        #info: (rows, columns, spp, bps)
-        index = get_indexed_datasets('1.2.840.10008.1.2.4.81')
-        ds = index[fname]['ds']
+        # info: (rows, columns, spp, bps)
+        index = get_indexed_datasets("1.2.840.10008.1.2.4.81")
+        ds = index[fname]["ds"]
 
         frame = next(self.generate_frames(ds))
-        arr = decode(np.frombuffer(frame, 'uint8'), reshape=True)
+        arr = decode(frame, reshape=True)
 
         if info[2] == 1:
             assert (info[0], info[1]) == arr.shape
@@ -248,162 +250,154 @@ def test_extended(self, fname, info):
             assert (info[0], info[1], info[2]) == arr.shape
 
         if 1 <= info[3] <= 8:
-            assert arr.dtype == 'uint8'
+            assert arr.dtype == "uint8"
         if 9 <= info[3] <= 16:
-            assert arr.dtype == 'uint16'
+            assert arr.dtype == "uint16"
 
 
 REF_JPG = {
-    '10918' : {
+    "10918": {
         # Reference values using libjpeg's `jpeg` app + imageJ
         # Very circular but having issues with other programs interpreting
         #   it as CYMK and doing weird stuff
-        'p1' : [
+        "p1": [
             # ([top left pixel], [bottom right pixel])
-            (
-                'A1.JPG', (257, 255, 4, 8),
-                ([138, 76, 239, 216], [155, 217, 191, 115])
-            ),
-            #('B1.JPG', (1, 1, 1, 1)),
-            #('B2.JPG', (1, 1, 1, 1)), missing DHT marker (its in B1.JPG)
+            ("A1.JPG", (257, 255, 4, 8), ([138, 76, 239, 216], [155, 217, 191, 115])),
+            # ('B1.JPG', (1, 1, 1, 1)),
+            # ('B2.JPG', (1, 1, 1, 1)), missing DHT marker (its in B1.JPG)
         ],
-        'p2' : [
-            (
-                'A1.JPG', (257, 255, 4, 8),
-                ([138, 76, 239, 216], [155, 217, 191, 115])
-            ),
-            #('B1.JPG', ()),
-            #('B2.JPG', ()), missing DHT (in B1)
-            (
-                'C1.JPG', (257, 255, 4, 8),
-                ([138, 76, 239, 216], [155, 217, 191, 115])
-            ),
-            (
-                'C2.JPG', (257, 255, 4, 8),
-                ([138, 76, 239, 216], [155, 217, 191, 115])
-            ),
+        "p2": [
+            ("A1.JPG", (257, 255, 4, 8), ([138, 76, 239, 216], [155, 217, 191, 115])),
+            # ('B1.JPG', ()),
+            # ('B2.JPG', ()), missing DHT (in B1)
+            ("C1.JPG", (257, 255, 4, 8), ([138, 76, 239, 216], [155, 217, 191, 115])),
+            ("C2.JPG", (257, 255, 4, 8), ([138, 76, 239, 216], [155, 217, 191, 115])),
         ],
-        'p4' : [
+        "p4": [
+            ("A1.JPG", (257, 255, 4, 8), ([138, 76, 239, 216], [155, 217, 191, 115])),
+            # ('B1.JPG', ()),
+            # ('B2.JPG', ()),
+            ("C1.JPG", (257, 255, 4, 8), ([138, 76, 239, 216], [155, 217, 191, 115])),
+            ("C2.JPG", (257, 255, 4, 8), ([138, 76, 239, 216], [155, 217, 191, 115])),
             (
-                'A1.JPG', (257, 255, 4, 8),
-                ([138, 76, 239, 216], [155, 217, 191, 115])
+                "E1.JPG",
+                (257, 255, 4, 12),
+                ([2119, 1183, 3907, 3487], [2502, 3402, 3041, 1872]),
             ),
-            #('B1.JPG', ()),
-            #('B2.JPG', ()),
             (
-                'C1.JPG', (257, 255, 4, 8),
-                ([138, 76, 239, 216], [155, 217, 191, 115])
-            ),
-            (
-                'C2.JPG', (257, 255, 4, 8),
-                ([138, 76, 239, 216], [155, 217, 191, 115])
-            ),
-            (
-                'E1.JPG', (257, 255, 4, 12),
-                ([2119, 1183, 3907, 3487], [2502, 3402, 3041, 1872])
-            ),
-            (
-                'E2.JPG', (257, 255, 4, 12),
-                ([2119, 1183, 3907, 3487], [2502, 3402, 3041, 1872])
+                "E2.JPG",
+                (257, 255, 4, 12),
+                ([2119, 1183, 3907, 3487], [2502, 3402, 3041, 1872]),
             ),
         ],
-        'p14' : [
-            (
-                'O1.JPG', (257, 255, 4, 8),
-                ([132, 76, 245, 218], [156, 211, 191, 116])
-            ),
+        "p14": [
+            ("O1.JPG", (257, 255, 4, 8), ([132, 76, 245, 218], [156, 211, 191, 116])),
             (
-                'O2.JPG', (257, 255, 4, 16),
-                ([33792, 19456, 62720, 55808], [39936, 53888, 48768, 29696])
+                "O2.JPG",
+                (257, 255, 4, 16),
+                ([33792, 19456, 62720, 55808], [39936, 53888, 48768, 29696]),
             ),
         ],
     },
-    '14495' : {
-        'JLS' : [  # Lossless
+    "14495": {
+        "JLS": [  # Lossless
             (
                 # Reference values using GDCM
-                'T8C0E0.JLS', (256, 256, 3, 8),
-                ([161, 122, 108], [101, 99, 95])
+                "T8C0E0.JLS",
+                (256, 256, 3, 8),
+                ([161, 122, 108], [101, 99, 95]),
             ),
             (
                 # GDCM and CharPyLS fail on this one - both use CharLS
-                 # Circular reference
-                'T8C1E0.JLS', (256, 256, 3, 8),
-                ([161, 122, 108], [101, 99, 95])
+                # Circular reference
+                "T8C1E0.JLS",
+                (256, 256, 3, 8),
+                ([161, 122, 108], [101, 99, 95]),
             ),
             (
                 # CharLS fails
                 # Circular reference
-                'T8C2E0.JLS', (256, 256, 3, 8),
-                ([161, 122, 108], [101, 99, 95])
+                "T8C2E0.JLS",
+                (256, 256, 3, 8),
+                ([161, 122, 108], [101, 99, 95]),
             ),
             (
                 # Reference values using GDCM
-                'T8NDE0.JLS', (128, 128, 1, 8),
-                (108, 231)
+                "T8NDE0.JLS",
+                (128, 128, 1, 8),
+                (108, 231),
             ),
             (
                 # CharLS fails
                 # Circular reference
-                'T8SSE0.JLS', (256, 256, 3, 8),
-                ([161, 122, 108], [101, 171, 231])
+                "T8SSE0.JLS",
+                (256, 256, 3, 8),
+                ([161, 122, 108], [101, 171, 231]),
             ),
             (
                 # Reference values using GDCM
-                'T16E0.JLS', (256, 256, 1, 12),
-                (1963, 1596)
+                "T16E0.JLS",
+                (256, 256, 1, 12),
+                (1963, 1596),
             ),
         ],
-        'JNL' : [  # Near lossless
+        "JNL": [  # Near lossless
             (
                 # Reference values using GDCM
-                'T8C0E3.JLS', (256, 256, 3, 8),
-                ([161, 119, 105], [98, 96, 93])
+                "T8C0E3.JLS",
+                (256, 256, 3, 8),
+                ([161, 119, 105], [98, 96, 93]),
             ),
             (
                 # CharLS fails
                 # Circular reference
-                'T8C1E3.JLS', (256, 256, 3, 8),
-                ([161, 119, 105], [101, 100, 97])
+                "T8C1E3.JLS",
+                (256, 256, 3, 8),
+                ([161, 119, 105], [101, 100, 97]),
             ),
             (
                 # CharLS fails
                 # Circular reference
-                'T8C2E3.JLS', (256, 256, 3, 8),
-                ([161, 119, 105], [98, 96, 94])
+                "T8C2E3.JLS",
+                (256, 256, 3, 8),
+                ([161, 119, 105], [98, 96, 94]),
             ),
             (
                 # Reference values using GDCM
-                'T8NDE3.JLS', (128, 128, 1, 8),
-                (105, 229)
+                "T8NDE3.JLS",
+                (128, 128, 1, 8),
+                (105, 229),
             ),
             (
                 # CharLS fails
                 # Circular reference
-                'T8SSE3.JLS', (256, 256, 3, 8),
-                ([161, 119, 105], [102, 169, 234])
+                "T8SSE3.JLS",
+                (256, 256, 3, 8),
+                ([161, 119, 105], [102, 169, 234]),
             ),
             (
                 # Reference values using GDCM
-                'T16E3.JLS', (256, 256, 1, 12),
-                (1960, 1593)
+                "T16E3.JLS",
+                (256, 256, 1, 12),
+                (1960, 1593),
             ),
         ],
     },
-    '15444' : {},
+    "15444": {},
 }
 
 
 class TestDecodeJPG:
     """Tests for get_parameters() using JPEG compliance data."""
-    @pytest.mark.parametrize("fname, info, ref", REF_JPG['10918']['p1'])
+
+    @pytest.mark.parametrize("fname, info, ref", REF_JPG["10918"]["p1"])
     def test_baseline(self, fname, info, ref):
         """Test decoding the baseline compliance images."""
-        #info: (rows, columns, spp, bps)
-        with open(os.path.join(DIR_10918, 'p1', fname), 'rb') as fp:
+        # info: (rows, columns, spp, bps)
+        with open(os.path.join(DIR_10918, "p1", fname), "rb") as fp:
             data = fp.read()
 
-        arr = decode(np.frombuffer(data, 'uint8'), reshape=True)
+        arr = decode(data, reshape=True)
         assert arr.flags.writeable
 
         if info[2] == 1:
@@ -412,19 +406,19 @@ def test_baseline(self, fname, info, ref):
             assert (info[0], info[1], info[2]) == arr.shape
 
         # Process 1 is always 8-bit
-        assert arr.dtype == 'uint8'
+        assert arr.dtype == "uint8"
 
         assert ref[0] == arr[0, 0, :].tolist()
         assert ref[1] == arr[-1, -1, :].tolist()
 
-    @pytest.mark.parametrize("fname, info, ref", REF_JPG['10918']['p2'])
+    @pytest.mark.parametrize("fname, info, ref", REF_JPG["10918"]["p2"])
     def test_extended_p2(self, fname, info, ref):
         """Test decoding the extended p2 compliance images."""
-        #info: (rows, columns, spp, bps)
-        with open(os.path.join(DIR_10918, 'p2', fname), 'rb') as fp:
+        # info: (rows, columns, spp, bps)
+        with open(os.path.join(DIR_10918, "p2", fname), "rb") as fp:
             data = fp.read()
 
-        arr = decode(np.frombuffer(data, 'uint8'), reshape=True)
+        arr = decode(data, reshape=True)
         assert arr.flags.writeable
 
         if info[2] == 1:
@@ -433,19 +427,19 @@ def test_extended_p2(self, fname, info, ref):
             assert (info[0], info[1], info[2]) == arr.shape
 
         # Process 2 is always 8-bit
-        assert arr.dtype == 'uint8'
+        assert arr.dtype == "uint8"
 
         assert ref[0] == arr[0, 0, :].tolist()
         assert ref[1] == arr[-1, -1, :].tolist()
 
-    @pytest.mark.parametrize("fname, info, ref", REF_JPG['10918']['p4'])
+    @pytest.mark.parametrize("fname, info, ref", REF_JPG["10918"]["p4"])
     def test_extended_p4(self, fname, info, ref):
         """Test decoding the extended p4 compliance images."""
-        #info: (rows, columns, spp, bps)
-        with open(os.path.join(DIR_10918, 'p4', fname), 'rb') as fp:
+        # info: (rows, columns, spp, bps)
+        with open(os.path.join(DIR_10918, "p4", fname), "rb") as fp:
             data = fp.read()
 
-        arr = decode(np.frombuffer(data, 'uint8'), reshape=True)
+        arr = decode(data, reshape=True)
         assert arr.flags.writeable
 
         if info[2] == 1:
@@ -454,21 +448,21 @@ def test_extended_p4(self, fname, info, ref):
             assert (info[0], info[1], info[2]) == arr.shape
 
         if 1 <= info[3] <= 8:
-            assert arr.dtype == 'uint8'
+            assert arr.dtype == "uint8"
         if 9 <= info[3] <= 16:
-            assert arr.dtype == 'uint16'
+            assert arr.dtype == "uint16"
 
         assert ref[0] == arr[0, 0, :].tolist()
         assert ref[1] == arr[-1, -1, :].tolist()
 
-    @pytest.mark.parametrize("fname, info, ref", REF_JPG['10918']['p14'])
+    @pytest.mark.parametrize("fname, info, ref", REF_JPG["10918"]["p14"])
     def test_lossless_p14(self, fname, info, ref):
         """Test decoding the extended p14 compliance images."""
-        #info: (rows, columns, spp, bps)
-        with open(os.path.join(DIR_10918, 'p14', fname), 'rb') as fp:
+        # info: (rows, columns, spp, bps)
+        with open(os.path.join(DIR_10918, "p14", fname), "rb") as fp:
             data = fp.read()
 
-        arr = decode(np.frombuffer(data, 'uint8'), reshape=True)
+        arr = decode(data, reshape=True)
         assert arr.flags.writeable
 
         if info[2] == 1:
@@ -477,24 +471,21 @@ def test_lossless_p14(self, fname, info, ref):
             assert (info[0], info[1], info[2]) == arr.shape
 
         if 1 <= info[3] <= 8:
-            assert arr.dtype == 'uint8'
+            assert arr.dtype == "uint8"
         if 9 <= info[3] <= 16:
-            assert arr.dtype == 'uint16'
+            assert arr.dtype == "uint16"
 
         assert ref[0] == arr[0, 0, :].tolist()
         assert ref[1] == arr[-1, -1, :].tolist()
 
-    @pytest.mark.parametrize("fname, info, ref", REF_JPG['14495']['JLS'])
+    @pytest.mark.parametrize("fname, info, ref", REF_JPG["14495"]["JLS"])
     def test_jls(self, fname, info, ref):
         """Test decoding the JPEG-LS lossless compliance images."""
-        #info: (rows, columns, spp, bps)
-        with open(os.path.join(DIR_14495, 'JLS', fname), 'rb') as fp:
+        # info: (rows, columns, spp, bps)
+        with open(os.path.join(DIR_14495, "JLS", fname), "rb") as fp:
             data = fp.read()
 
-        arr = decode(
-            np.frombuffer(data, 'uint8'),
-            reshape=True,
-        )
+        arr = decode(data, reshape=True)
         assert arr.flags.writeable
 
         if info[2] == 1:
@@ -503,9 +494,9 @@ def test_jls(self, fname, info, ref):
             assert (info[0], info[1], info[2]) == arr.shape
 
         if 1 <= info[3] <= 8:
-            assert arr.dtype == 'uint8'
+            assert arr.dtype == "uint8"
         if 9 <= info[3] <= 16:
-            assert arr.dtype == 'uint16'
+            assert arr.dtype == "uint16"
 
         if info[2] == 1:
             assert ref[0] == arr[0, 0].tolist()
@@ -514,14 +505,14 @@ def test_jls(self, fname, info, ref):
             assert ref[0] == arr[0, 0, :].tolist()
             assert ref[1] == arr[-1, -1, :].tolist()
 
-    @pytest.mark.parametrize("fname, info, ref", REF_JPG['14495']['JNL'])
+    @pytest.mark.parametrize("fname, info, ref", REF_JPG["14495"]["JNL"])
     def test_jnl(self, fname, info, ref):
         """Test decoding the JPEG-LS near lossless compliance images."""
-        #info: (rows, columns, spp, bps)
-        with open(os.path.join(DIR_14495, 'JNL', fname), 'rb') as fp:
+        # info: (rows, columns, spp, bps)
+        with open(os.path.join(DIR_14495, "JNL", fname), "rb") as fp:
             data = fp.read()
 
-        arr = decode(np.frombuffer(data, 'uint8'), reshape=True)
+        arr = decode(data, reshape=True)
         assert arr.flags.writeable
 
         if info[2] == 1:
@@ -530,9 +521,9 @@ def test_jnl(self, fname, info, ref):
             assert (info[0], info[1], info[2]) == arr.shape
 
         if 1 <= info[3] <= 8:
-            assert arr.dtype == 'uint8'
+            assert arr.dtype == "uint8"
         if 9 <= info[3] <= 16:
-            assert arr.dtype == 'uint16'
+            assert arr.dtype == "uint16"
 
         if info[2] == 1:
             assert ref[0] == arr[0, 0].tolist()
@@ -543,7 +534,7 @@ def test_jnl(self, fname, info, ref):
 
     def test_str(self):
         """Test decoding using a str path."""
-        p = DIR_10918 / 'p1' / 'A1.JPG'
+        p = DIR_10918 / "p1" / "A1.JPG"
         p = os.fspath(p)
         assert isinstance(p, str)
         arr = decode(p)
@@ -551,7 +542,7 @@ def test_str(self):
 
     def test_path(self):
         """Test decoding using a Path path."""
-        p = DIR_10918 / 'p1' / 'A1.JPG'
+        p = DIR_10918 / "p1" / "A1.JPG"
         assert isinstance(p, Path)
         arr = decode(p)
         assert arr.shape == (257, 255, 4)
diff --git a/libjpeg/tests/test_handler.py b/libjpeg/tests/test_handler.py
index d51ec4c..92a640f 100644
--- a/libjpeg/tests/test_handler.py
+++ b/libjpeg/tests/test_handler.py
@@ -10,6 +10,7 @@
     import pydicom.config
     from pydicom.pixel_data_handlers.util import convert_color_space
     from pydicom.encaps import defragment_data
+
     HAS_PYDICOM = True
 except ImportError:
     HAS_PYDICOM = False
@@ -20,6 +21,7 @@
 
 class HandlerTestBase:
     """Baseclass for handler tests."""
+
     uid = None
 
     def setup_method(self):
@@ -45,40 +47,33 @@ def plot(self, arr, index=None, cmap=None):
 @pytest.mark.skipif(not HAS_PYDICOM, reason="No dependencies")
 class TestLibrary:
     """Tests for libjpeg itself."""
+
     def test_non_conformant_raises(self):
         """Test that a non-conformant JPEG image raises an exception."""
-        ds_list = get_indexed_datasets('1.2.840.10008.1.2.4.51')
+        ds_list = get_indexed_datasets("1.2.840.10008.1.2.4.51")
         # Image has invalid Se value in the SOS marker segment
-        item = ds_list['JPEG-lossy.dcm']
-        assert 0xC000 == item['Status'][1]
+        item = ds_list["JPEG-lossy.dcm"]
+        assert 0xC000 == item["Status"][1]
         msg = (
             r"libjpeg error code '-1038' returned from Decode\(\): A "
             r"misplaced marker segment was found - scan start must be zero "
             r"and scan stop must be 63 for the sequential operating modes"
         )
         with pytest.raises(RuntimeError, match=msg):
-            item['ds'].pixel_array
+            item["ds"].pixel_array
 
     def test_invalid_colour_transform(self):
         """Test that an invalid colour transform raises an exception."""
-        ds_list = get_indexed_datasets('1.2.840.10008.1.2.4.50')
+        ds_list = get_indexed_datasets("1.2.840.10008.1.2.4.50")
         # Image has invalid Se value in the SOS marker segment
-        ds = ds_list['color3d_jpeg_baseline.dcm']['ds']
+        ds = ds_list["color3d_jpeg_baseline.dcm"]["ds"]
         data = defragment_data(ds.PixelData)
         msg = (
             r"Unknown error code '-8194' returned from Decode\(\): "
             r"Invalid colourTransform value"
         )
         with pytest.raises(RuntimeError, match=msg):
-            decode(np.frombuffer(data, 'uint8'), -1)
-
-    def test_invalid_buffer(self):
-        """Test that an invalid colour transform raises an exception."""
-        msg = (
-            r"Buffer dtype mismatch, expected 'uint8_t' but got 'double'"
-        )
-        with pytest.raises(ValueError, match=msg):
-            decode(np.zeros(1), 'YBR_FULL')
+            decode(data, -1)
 
 
 # ISO/IEC 10918 JPEG
@@ -113,119 +108,120 @@ class TestJPEGBaseline(HandlerTestBase):
     ----------------
     1 sample/px, 8/8 bits allocated/stored, unsigned, > 1 frame
     """
-    uid = '1.2.840.10008.1.2.4.50'
+
+    uid = "1.2.840.10008.1.2.4.50"
 
     def test_1s_1f(self):
         """Test greyscale."""
-        ds = self.ds['JPEGBaseline_1s_1f_u_08_08.dcm']['ds']
+        ds = self.ds["JPEGBaseline_1s_1f_u_08_08.dcm"]["ds"]
         assert self.uid == ds.file_meta.TransferSyntaxUID
         assert 1 == ds.SamplesPerPixel
-        assert 1 == getattr(ds, 'NumberOfFrames', 1)
-        assert 'MONOCHROME' in ds.PhotometricInterpretation
+        assert 1 == getattr(ds, "NumberOfFrames", 1)
+        assert "MONOCHROME" in ds.PhotometricInterpretation
         assert 8 == ds.BitsAllocated == ds.BitsStored
         assert 0 == ds.PixelRepresentation
 
         arr = ds.pixel_array
         assert arr.flags.writeable
-        assert 'uint8' == arr.dtype
+        assert "uint8" == arr.dtype
         assert (ds.Rows, ds.Columns) == arr.shape
 
-        #self.plot(arr, cmap='gray')
+        # self.plot(arr, cmap='gray')
 
         # Reference values from GDCM handler
-        assert  76 == arr[ 5, 50]
+        assert 76 == arr[5, 50]
         assert 167 == arr[15, 50]
         assert 149 == arr[25, 50]
         assert 203 == arr[35, 50]
-        assert  29 == arr[45, 50]
+        assert 29 == arr[45, 50]
         assert 142 == arr[55, 50]
-        assert   1 == arr[65, 50]
-        assert  64 == arr[75, 50]
+        assert 1 == arr[65, 50]
+        assert 64 == arr[75, 50]
         assert 192 == arr[85, 50]
         assert 255 == arr[95, 50]
 
-    @pytest.mark.skip('No suitable dataset')
+    @pytest.mark.skip("No suitable dataset")
     def test_1s_Nf(self):
         """Test greyscale with N frames."""
-        ds = self.ds['JPEGBaseline_1s_2f_08_08.dcm']['ds']
+        ds = self.ds["JPEGBaseline_1s_2f_08_08.dcm"]["ds"]
         assert self.uid == ds.file_meta.TransferSyntaxUID
         assert 1 == ds.SamplesPerPixel
-        assert 2 == getattr(ds, 'NumberOfFrames', 1)
-        assert 'MONOCHROME' in ds.PhotometricInterpretation
+        assert 2 == getattr(ds, "NumberOfFrames", 1)
+        assert "MONOCHROME" in ds.PhotometricInterpretation
         assert 8 == ds.BitsAllocated == ds.BitsStored
         assert 0 == ds.PixelRepresentation
 
         arr = ds.pixel_array
         assert arr.flags.writeable
-        assert 'uint8' == arr.dtype
+        assert "uint8" == arr.dtype
         assert (2, ds.Rows, ds.Columns) == arr.shape
 
-        #self.plot(arr, index=0, cmap='gray')
+        # self.plot(arr, index=0, cmap='gray')
 
     def test_3s_1f_ybr_422(self):
         """Test YBR with 422 subsampling."""
         # +cy is YCbCr
         # +s2 is 422 subsampling w/ YBR_FULL_422
-        ds = self.ds['SC_rgb_dcmtk_+eb+cy+np.dcm']['ds']
+        ds = self.ds["SC_rgb_dcmtk_+eb+cy+np.dcm"]["ds"]
         assert self.uid == ds.file_meta.TransferSyntaxUID
         assert 3 == ds.SamplesPerPixel
-        assert 1 == getattr(ds, 'NumberOfFrames', 1)
-        assert 'YBR_FULL_422' == ds.PhotometricInterpretation
+        assert 1 == getattr(ds, "NumberOfFrames", 1)
+        assert "YBR_FULL_422" == ds.PhotometricInterpretation
         assert 8 == ds.BitsAllocated == ds.BitsStored
         assert 0 == ds.PixelRepresentation
 
         arr = ds.pixel_array
         assert arr.flags.writeable
-        assert 'uint8' == arr.dtype
+        assert "uint8" == arr.dtype
         assert (ds.Rows, ds.Columns, 3) == arr.shape
 
-        #self.plot(arr)
+        # self.plot(arr)
 
         # Reference values may be slightly different depending on handler
         # Pillow: assert ( 76,  86, 251) == tuple(arr[ 5, 50, :])
-        assert ( 76,  85, 254) == tuple(arr[ 5, 50, :])
+        assert (76, 85, 254) == tuple(arr[5, 50, :])
         # GDCM:   assert (166, 109, 190) == tuple(arr[15, 50, :])
         # Pillow: assert (166, 112, 185) == tuple(arr[15, 50, :])
         assert (166, 108, 190) == tuple(arr[15, 50, :])
         # Pillow: assert (150,  46,  17) == tuple(arr[25, 50, :])
-        assert (150,  46,  21) == tuple(arr[25, 50, :])
+        assert (150, 46, 21) == tuple(arr[25, 50, :])
         # GDCM:   assert (203,  85,  74) == tuple(arr[35, 50, :])
         # Pillow: assert (203,  95,  75) == tuple(arr[35, 50, :])
-        assert (203,  86,  74) == tuple(arr[35, 50, :])
+        assert (203, 86, 74) == tuple(arr[35, 50, :])
         # GDCM:   assert ( 29, 255, 108) == tuple(arr[45, 50, :])
         # Pillow: assert ( 29, 255, 109) == tuple(arr[45, 50, :])
-        assert ( 29, 255, 107) == tuple(arr[45, 50, :])
+        assert (29, 255, 107) == tuple(arr[45, 50, :])
         # Pillow: assert (142, 189, 118) == tuple(arr[55, 50, :])
         assert (142, 192, 117) == tuple(arr[55, 50, :])
-        assert (  0, 128, 128) == tuple(arr[65, 50, :])
-        assert ( 64, 128, 128) == tuple(arr[75, 50, :])
+        assert (0, 128, 128) == tuple(arr[65, 50, :])
+        assert (64, 128, 128) == tuple(arr[75, 50, :])
         assert (192, 128, 128) == tuple(arr[85, 50, :])
         assert (255, 128, 128) == tuple(arr[95, 50, :])
 
     def test_3s_Nf_ybr_422(self):
         """Test 3 sample/px with N frames."""
-        ds = self.ds['color3d_jpeg_baseline.dcm']['ds']
+        ds = self.ds["color3d_jpeg_baseline.dcm"]["ds"]
         assert self.uid == ds.file_meta.TransferSyntaxUID
         assert 3 == ds.SamplesPerPixel
-        assert 1 != getattr(ds, 'NumberOfFrames', 1)
+        assert 1 != getattr(ds, "NumberOfFrames", 1)
         assert 8 == ds.BitsAllocated == ds.BitsStored
-        assert 'YBR_FULL_422' == ds.PhotometricInterpretation
+        assert "YBR_FULL_422" == ds.PhotometricInterpretation
         assert 0 == ds.PixelRepresentation
 
         arr = ds.pixel_array
         assert arr.flags.writeable
-        assert 'uint8' == arr.dtype
+        assert "uint8" == arr.dtype
         assert (ds.NumberOfFrames, ds.Rows, ds.Columns, 3) == arr.shape
 
         # Gives a MemoryError in GitHub CI build otherwise
         arr = arr[0:10, ...]
-        arr = convert_color_space(arr, 'YBR_FULL', 'RGB')
+        arr = convert_color_space(arr, "YBR_FULL", "RGB")
 
-        #self.plot(arr, index=3)
+        # self.plot(arr, index=3)
 
         # GDCM: all match
-        assert (41,  41,  41) == tuple(arr[3, 159, 290, :])
-        assert (57,  57,  57) == tuple(arr[3, 169, 290, :])
+        assert (41, 41, 41) == tuple(arr[3, 159, 290, :])
+        assert (57, 57, 57) == tuple(arr[3, 169, 290, :])
         # Pillow: assert (71, 168, 125) == tuple(arr[3, 41, 380, :])
         assert (72, 167, 125) == tuple(arr[3, 41, 380, :])
 
@@ -233,29 +229,29 @@ def test_3s_Nf_ybr_422(self):
     def test_3s_1f_rgb_non(self):
         """Test RGB."""
         # +cr is RGB - DICOM non-conformant
-        ds = self.ds['SC_rgb_dcmtk_+eb+cr.dcm']['ds']
+        ds = self.ds["SC_rgb_dcmtk_+eb+cr.dcm"]["ds"]
         assert self.uid == ds.file_meta.TransferSyntaxUID
         assert 3 == ds.SamplesPerPixel
-        assert 1 == getattr(ds, 'NumberOfFrames', 1)
-        assert 'RGB' == ds.PhotometricInterpretation
+        assert 1 == getattr(ds, "NumberOfFrames", 1)
+        assert "RGB" == ds.PhotometricInterpretation
         assert 8 == ds.BitsAllocated == ds.BitsStored
         assert 0 == ds.PixelRepresentation
 
         arr = ds.pixel_array
         assert arr.flags.writeable
-        assert 'uint8' == arr.dtype
+        assert "uint8" == arr.dtype
         assert (ds.Rows, ds.Columns, 3) == arr.shape
 
-        #self.plot(arr)
+        # self.plot(arr)
 
-        assert (255,   0,   0) == tuple(arr[ 5, 50, :])
+        assert (255, 0, 0) == tuple(arr[5, 50, :])
         assert (255, 128, 128) == tuple(arr[15, 50, :])
-        assert (  0, 255,   0) == tuple(arr[25, 50, :])
+        assert (0, 255, 0) == tuple(arr[25, 50, :])
         assert (128, 255, 128) == tuple(arr[35, 50, :])
-        assert (  0,   0, 255) == tuple(arr[45, 50, :])
+        assert (0, 0, 255) == tuple(arr[45, 50, :])
         assert (128, 128, 255) == tuple(arr[55, 50, :])
-        assert (  0,   0,   0) == tuple(arr[65, 50, :])
-        assert ( 64,  64,  64) == tuple(arr[75, 50, :])
+        assert (0, 0, 0) == tuple(arr[65, 50, :])
+        assert (64, 64, 64) == tuple(arr[75, 50, :])
         assert (192, 192, 192) == tuple(arr[85, 50, :])
         assert (255, 255, 255) == tuple(arr[95, 50, :])
 
@@ -263,36 +259,36 @@ def test_3s_1f_ybr_411_non(self):
         """Test YBR with 411 subsampling."""
         # +cy is YCbCr
         # +n1 is 411 subsampling w/ YBR_FULL - DICOM non-conformant
-        ds = self.ds['SC_rgb_dcmtk_+eb+cy+n1.dcm']['ds']
+        ds = self.ds["SC_rgb_dcmtk_+eb+cy+n1.dcm"]["ds"]
         assert self.uid == ds.file_meta.TransferSyntaxUID
         assert 3 == ds.SamplesPerPixel
-        assert 1 == getattr(ds, 'NumberOfFrames', 1)
-        assert 'YBR_FULL' == ds.PhotometricInterpretation
+        assert 1 == getattr(ds, "NumberOfFrames", 1)
+        assert "YBR_FULL" == ds.PhotometricInterpretation
         assert 8 == ds.BitsAllocated == ds.BitsStored
         assert 0 == ds.PixelRepresentation
 
         arr = ds.pixel_array
         assert arr.flags.writeable
-        assert 'uint8' == arr.dtype
+        assert "uint8" == arr.dtype
         assert (ds.Rows, ds.Columns, 3) == arr.shape
 
-        arr = convert_color_space(arr, 'YBR_FULL', 'RGB')
+        arr = convert_color_space(arr, "YBR_FULL", "RGB")
 
-        #self.plot(arr)
+        # self.plot(arr)
 
         # GDCM: all match
         # Pillow: assert (248,   3,   2) == tuple(arr[ 5, 50, :])
-        assert (253,   1,   0) == tuple(arr[ 5, 50, :])
+        assert (253, 1, 0) == tuple(arr[5, 50, :])
         # Pillow: assert (246, 131, 138) == tuple(arr[15, 50, :])
         assert (253, 129, 131) == tuple(arr[15, 50, :])
         # Pillow: assert (129, 252, 145) == tuple(arr[35, 50, :])
         assert (127, 255, 129) == tuple(arr[35, 50, :])
         # Pillow: assert (  2,   0, 254) == tuple(arr[45, 50, :])
-        assert (  0,   0, 254) == tuple(arr[45, 50, :])
+        assert (0, 0, 254) == tuple(arr[45, 50, :])
         # Pillow: assert (128, 128, 250) == tuple(arr[55, 50, :])
         assert (127, 128, 255) == tuple(arr[55, 50, :])
-        assert (  0,   0,   0) == tuple(arr[65, 50, :])
-        assert ( 64,  64,  64) == tuple(arr[75, 50, :])
+        assert (0, 0, 0) == tuple(arr[65, 50, :])
+        assert (64, 64, 64) == tuple(arr[75, 50, :])
         assert (192, 192, 192) == tuple(arr[85, 50, :])
         assert (255, 255, 255) == tuple(arr[95, 50, :])
 
@@ -300,31 +296,31 @@ def test_3s_1f_ybr_444_non(self):
         """Test YBR with 444 subsampling."""
         # +cy is YCbCr
         # +s4 is 444 subsampling w/ YBR_FULL - DICOM non-conformant
-        ds = self.ds['SC_rgb_dcmtk_+eb+cy+s4.dcm']['ds']
+        ds = self.ds["SC_rgb_dcmtk_+eb+cy+s4.dcm"]["ds"]
         assert self.uid == ds.file_meta.TransferSyntaxUID
         assert 3 == ds.SamplesPerPixel
-        assert 1 == getattr(ds, 'NumberOfFrames', 1)
-        assert 'YBR_FULL' == ds.PhotometricInterpretation
+        assert 1 == getattr(ds, "NumberOfFrames", 1)
+        assert "YBR_FULL" == ds.PhotometricInterpretation
         assert 8 == ds.BitsAllocated == ds.BitsStored
         assert 0 == ds.PixelRepresentation
 
         arr = ds.pixel_array
         assert arr.flags.writeable
-        assert 'uint8' == arr.dtype
+        assert "uint8" == arr.dtype
         assert (ds.Rows, ds.Columns, 3) == arr.shape
 
-        arr = convert_color_space(arr, 'YBR_FULL', 'RGB')
+        arr = convert_color_space(arr, "YBR_FULL", "RGB")
 
-        #self.plot(arr)
+        # self.plot(arr)
 
-        assert (254,   0,   0) == tuple(arr[ 5, 50, :])
+        assert (254, 0, 0) == tuple(arr[5, 50, :])
         assert (255, 127, 127) == tuple(arr[15, 50, :])
-        assert (  0, 255,   5) == tuple(arr[25, 50, :])
+        assert (0, 255, 5) == tuple(arr[25, 50, :])
         assert (129, 255, 129) == tuple(arr[35, 50, :])
-        assert (  0,   0, 254) == tuple(arr[45, 50, :])
+        assert (0, 0, 254) == tuple(arr[45, 50, :])
         assert (128, 127, 255) == tuple(arr[55, 50, :])
-        assert (  0,   0,   0) == tuple(arr[65, 50, :])
-        assert ( 64,  64,  64) == tuple(arr[75, 50, :])
+        assert (0, 0, 0) == tuple(arr[65, 50, :])
+        assert (64, 64, 64) == tuple(arr[75, 50, :])
         assert (192, 192, 192) == tuple(arr[85, 50, :])
         assert (255, 255, 255) == tuple(arr[95, 50, :])
 
@@ -360,7 +356,8 @@ class TestJPEGExtended(HandlerTestBase):
     1 sample/px, 8/8 bits allocated/stored, unsigned, > 1 frame
     1 sample/px, 16/12 bits allocated/stored, unsigned, > 1 frame
     """
-    uid = '1.2.840.10008.1.2.4.51'
+
+    uid = "1.2.840.10008.1.2.4.51"
 
     # Process 2
     @pytest.mark.skip("No suitable dataset")
@@ -374,11 +371,11 @@ def test_1s_Nf_u_08_08(self):
     # Process 4
     def test_1s_1f_u_16_10(self):
         """Test process 4 greyscale."""
-        ds = self.ds['RG2_JPLY_fixed.dcm']['ds']
+        ds = self.ds["RG2_JPLY_fixed.dcm"]["ds"]
         assert self.uid == ds.file_meta.TransferSyntaxUID
         assert 1 == ds.SamplesPerPixel
-        assert 1 == getattr(ds, 'NumberOfFrames', 1)
-        assert 'MONOCHROME' in ds.PhotometricInterpretation
+        assert 1 == getattr(ds, "NumberOfFrames", 1)
+        assert "MONOCHROME" in ds.PhotometricInterpretation
         assert 16 == ds.BitsAllocated
         # Input precision is 12, not 10
         assert 10 == ds.BitsStored
@@ -386,10 +383,10 @@ def test_1s_1f_u_16_10(self):
 
         arr = ds.pixel_array
         assert arr.flags.writeable
-        assert 'uint16' == arr.dtype
+        assert "uint16" == arr.dtype
         assert (ds.Rows, ds.Columns) == arr.shape
 
-        #self.plot(arr)
+        # self.plot(arr)
 
         # Reference values from output of IJG's djpeg recompiled for 12-bit
         # Note differences       |              |
@@ -400,21 +397,21 @@ def test_1s_1f_u_16_10(self):
 
     def test_1s_1f_u_16_12(self):
         """Test process 4 greyscale."""
-        ds = self.ds['JPEGExtended_1s_1f_u_16_12.dcm']['ds']
+        ds = self.ds["JPEGExtended_1s_1f_u_16_12.dcm"]["ds"]
         assert self.uid == ds.file_meta.TransferSyntaxUID
         assert 1 == ds.SamplesPerPixel
-        assert 1 == getattr(ds, 'NumberOfFrames', 1)
-        assert 'MONOCHROME' in ds.PhotometricInterpretation
+        assert 1 == getattr(ds, "NumberOfFrames", 1)
+        assert "MONOCHROME" in ds.PhotometricInterpretation
         assert 16 == ds.BitsAllocated
         assert 12 == ds.BitsStored
         assert 0 == ds.PixelRepresentation
 
         arr = ds.pixel_array
         assert arr.flags.writeable
-        assert 'uint16' == arr.dtype
+        assert "uint16" == arr.dtype
         assert (ds.Rows, ds.Columns) == arr.shape
 
-        #self.plot(arr)
+        # self.plot(arr)
 
         # Reference values from output of IJG's djpeg recompiled for 12-bit
         # Note differences  |
@@ -431,34 +428,34 @@ def test_1s_Nf_u_16_12(self):
     def test_3s_1f_u_08_08_non(self):
         """Test process 2 greyscale."""
         # Non-conformant to DICOM
-        ds = self.ds['JPEGExtended_3s_1f_u_08_08.dcm']['ds']
+        ds = self.ds["JPEGExtended_3s_1f_u_08_08.dcm"]["ds"]
         assert self.uid == ds.file_meta.TransferSyntaxUID
         assert 3 == ds.SamplesPerPixel
-        assert 1 == getattr(ds, 'NumberOfFrames', 1)
-        assert 'YBR_FULL' in ds.PhotometricInterpretation
+        assert 1 == getattr(ds, "NumberOfFrames", 1)
+        assert "YBR_FULL" in ds.PhotometricInterpretation
         assert 8 == ds.BitsAllocated
         assert 8 == ds.BitsStored
         assert 0 == ds.PixelRepresentation
 
         arr = ds.pixel_array
         assert arr.flags.writeable
-        assert 'uint8' == arr.dtype
+        assert "uint8" == arr.dtype
         assert (ds.Rows, ds.Columns, 3) == arr.shape
 
-        #self.plot(arr)
+        # self.plot(arr)
 
         # Reference values from GDCM handler - in YBR colour space
         assert [
-            [ 71,  86, 147],
-            [124,  62, 167],
-            [138,  66, 175],
-            [145,  65, 172],
-            [150,  59, 168],
-            [178,  59, 167],
-            [183,  56, 171],
-            [201,  83, 165],
-            [213,  92, 153],
-            [255, 132, 134]
+            [71, 86, 147],
+            [124, 62, 167],
+            [138, 66, 175],
+            [145, 65, 172],
+            [150, 59, 168],
+            [178, 59, 167],
+            [183, 56, 171],
+            [201, 83, 165],
+            [213, 92, 153],
+            [255, 132, 134],
         ] == arr[41, 105:115].tolist()
 
 
@@ -517,25 +514,26 @@ class TestJPEGLossless(HandlerTestBase):
     3 sample/px, 16/16 bits allocated/stored, unsigned, RGB, 1 frame
     3 sample/px, 16/16 bits allocated/stored, unsigned, RGB, > 1 frame
     """
-    uid = '1.2.840.10008.1.2.4.57'
+
+    uid = "1.2.840.10008.1.2.4.57"
 
     def test_1s_1f_u_08_08(self):
         """Test process 2 greyscale."""
-        ds = self.ds['JPEGLossless_1s_1f_u_16_12.dcm']['ds']
+        ds = self.ds["JPEGLossless_1s_1f_u_16_12.dcm"]["ds"]
         assert self.uid == ds.file_meta.TransferSyntaxUID
         assert 1 == ds.SamplesPerPixel
-        assert 1 == getattr(ds, 'NumberOfFrames', 1)
-        assert 'MONOCHROME' in ds.PhotometricInterpretation
+        assert 1 == getattr(ds, "NumberOfFrames", 1)
+        assert "MONOCHROME" in ds.PhotometricInterpretation
         assert 16 == ds.BitsAllocated
         assert 12 == ds.BitsStored
         assert 0 == ds.PixelRepresentation
 
         arr = ds.pixel_array
         assert arr.flags.writeable
-        assert 'uint16' == arr.dtype
+        assert "uint16" == arr.dtype
         assert (ds.Rows, ds.Columns) == arr.shape
 
-        #self.plot(arr)
+        # self.plot(arr)
 
         # Reference values from GDCM handler - lossless must be identical!
         assert [392, 304, 238, 250, 224, 257, 221, 182, 166, 68] == (
@@ -599,26 +597,27 @@ class TestJPEGLosslessSV1(HandlerTestBase):
     3 sample/px, 16/16 bits allocated/stored, unsigned, RGB, 1 frame
     3 sample/px, 16/16 bits allocated/stored, unsigned, RGB, > 1 frame
     """
-    uid = '1.2.840.10008.1.2.4.70'
+
+    uid = "1.2.840.10008.1.2.4.70"
 
     # 1 sample/px, 8/8
     def test_1s_1f_u_08_08(self):
         """Test process 2 greyscale."""
-        ds = self.ds['JPEGLosslessP14SV1_1s_1f_u_08_08.dcm']['ds']
+        ds = self.ds["JPEGLosslessP14SV1_1s_1f_u_08_08.dcm"]["ds"]
         assert self.uid == ds.file_meta.TransferSyntaxUID
         assert 1 == ds.SamplesPerPixel
-        assert 1 == getattr(ds, 'NumberOfFrames', 1)
-        assert 'MONOCHROME' in ds.PhotometricInterpretation
+        assert 1 == getattr(ds, "NumberOfFrames", 1)
+        assert "MONOCHROME" in ds.PhotometricInterpretation
         assert 8 == ds.BitsAllocated
         assert 8 == ds.BitsStored
         assert 0 == ds.PixelRepresentation
 
         arr = ds.pixel_array
         assert arr.flags.writeable
-        assert 'uint8' == arr.dtype
+        assert "uint8" == arr.dtype
         assert (ds.Rows, ds.Columns) == arr.shape
 
-        #self.plot(arr)
+        # self.plot(arr)
 
         # Reference values from GDCM handler
         assert [0, 255, 254, 253, 253, 252, 251] == arr[121:128, 974].tolist()
@@ -626,21 +625,21 @@ def test_1s_1f_u_08_08(self):
     # 1 sample/px, 16/NN
     def test_1s_1f_u_16_10(self):
         """Test process 2 greyscale."""
-        ds = self.ds['RG2_JPLL.dcm']['ds']
+        ds = self.ds["RG2_JPLL.dcm"]["ds"]
         assert self.uid == ds.file_meta.TransferSyntaxUID
         assert 1 == ds.SamplesPerPixel
-        assert 1 == getattr(ds, 'NumberOfFrames', 1)
-        assert 'MONOCHROME' in ds.PhotometricInterpretation
+        assert 1 == getattr(ds, "NumberOfFrames", 1)
+        assert "MONOCHROME" in ds.PhotometricInterpretation
         assert 16 == ds.BitsAllocated
         assert 10 == ds.BitsStored
         assert 0 == ds.PixelRepresentation
 
         arr = ds.pixel_array
         assert arr.flags.writeable
-        assert 'uint16' == arr.dtype
+        assert "uint16" == arr.dtype
         assert (ds.Rows, ds.Columns) == arr.shape
 
-        #self.plot(arr)
+        # self.plot(arr)
 
         # Reference values from GDCM handler
         assert [574, 669, 763, 782, 789, 736, 637, 583, 592, 589] == (
@@ -649,42 +648,42 @@ def test_1s_1f_u_16_10(self):
 
     def test_1s_1f_u_16_12(self):
         """Test process 2 greyscale."""
-        ds = self.ds['MG1_JPLL.dcm']['ds']
+        ds = self.ds["MG1_JPLL.dcm"]["ds"]
         assert self.uid == ds.file_meta.TransferSyntaxUID
         assert 1 == ds.SamplesPerPixel
-        assert 1 == getattr(ds, 'NumberOfFrames', 1)
-        assert 'MONOCHROME' in ds.PhotometricInterpretation
+        assert 1 == getattr(ds, "NumberOfFrames", 1)
+        assert "MONOCHROME" in ds.PhotometricInterpretation
         assert 16 == ds.BitsAllocated
         assert 12 == ds.BitsStored
         assert 0 == ds.PixelRepresentation
 
         arr = ds.pixel_array
         assert arr.flags.writeable
-        assert 'uint16' == arr.dtype
+        assert "uint16" == arr.dtype
         assert (ds.Rows, ds.Columns) == arr.shape
 
-        #self.plot(arr)
+        # self.plot(arr)
 
         # Reference values from GDCM handler
         assert [3023, 2862, 2841, 2825, 2841] == arr[1830:1835, 1285].tolist()
 
     def test_1s_1f_u_16_15(self):
         """Test process 2 greyscale."""
-        ds = self.ds['RG1_JPLL.dcm']['ds']
+        ds = self.ds["RG1_JPLL.dcm"]["ds"]
         assert self.uid == ds.file_meta.TransferSyntaxUID
         assert 1 == ds.SamplesPerPixel
-        assert 1 == getattr(ds, 'NumberOfFrames', 1)
-        assert 'MONOCHROME' in ds.PhotometricInterpretation
+        assert 1 == getattr(ds, "NumberOfFrames", 1)
+        assert "MONOCHROME" in ds.PhotometricInterpretation
         assert 16 == ds.BitsAllocated
         assert 15 == ds.BitsStored
         assert 0 == ds.PixelRepresentation
 
         arr = ds.pixel_array
         assert arr.flags.writeable
-        assert 'uint16' == arr.dtype
+        assert "uint16" == arr.dtype
         assert (ds.Rows, ds.Columns) == arr.shape
 
-        #self.plot(arr)
+        # self.plot(arr)
 
         # Reference values from GDCM handler
         assert [24043, 23906, 23669, 23526, 22962, 22874, 22501, 22066] == (
@@ -693,21 +692,21 @@ def test_1s_1f_u_16_15(self):
 
     def test_1s_1f_i_16_16(self):
         """Test process 2 greyscale."""
-        ds = self.ds['JPEG-LL.dcm']['ds']
+        ds = self.ds["JPEG-LL.dcm"]["ds"]
         assert self.uid == ds.file_meta.TransferSyntaxUID
         assert 1 == ds.SamplesPerPixel
-        assert 1 == getattr(ds, 'NumberOfFrames', 1)
-        assert 'MONOCHROME' in ds.PhotometricInterpretation
+        assert 1 == getattr(ds, "NumberOfFrames", 1)
+        assert "MONOCHROME" in ds.PhotometricInterpretation
         assert 16 == ds.BitsAllocated
         assert 16 == ds.BitsStored
         assert 1 == ds.PixelRepresentation
 
         arr = ds.pixel_array
         assert arr.flags.writeable
-        assert 'int16' == arr.dtype
+        assert "int16" == arr.dtype
         assert (ds.Rows, ds.Columns) == arr.shape
 
-        #self.plot(arr)
+        # self.plot(arr)
 
         assert 227 == arr[420, 140]
         assert 105 == arr[230, 120]
@@ -715,30 +714,30 @@ def test_1s_1f_i_16_16(self):
     # 3 samples/px, 8/8
     def test_3s_1f_u_08_08_rgb(self):
         """Test process 2 greyscale."""
-        ds = self.ds['SC_rgb_jpeg_gdcm.dcm']['ds']
+        ds = self.ds["SC_rgb_jpeg_gdcm.dcm"]["ds"]
         assert self.uid == ds.file_meta.TransferSyntaxUID
         assert 3 == ds.SamplesPerPixel
-        assert 1 == getattr(ds, 'NumberOfFrames', 1)
-        assert 'RGB' in ds.PhotometricInterpretation
+        assert 1 == getattr(ds, "NumberOfFrames", 1)
+        assert "RGB" in ds.PhotometricInterpretation
         assert 8 == ds.BitsAllocated
         assert 8 == ds.BitsStored
         assert 0 == ds.PixelRepresentation
 
         arr = ds.pixel_array
         assert arr.flags.writeable
-        assert 'uint8' == arr.dtype
+        assert "uint8" == arr.dtype
         assert (ds.Rows, ds.Columns, 3) == arr.shape
 
-        #self.plot(arr)
+        # self.plot(arr)
 
-        assert (255,   0,   0) == tuple(arr[ 5, 50, :])
+        assert (255, 0, 0) == tuple(arr[5, 50, :])
         assert (255, 128, 128) == tuple(arr[15, 50, :])
-        assert (  0, 255,   0) == tuple(arr[25, 50, :])
+        assert (0, 255, 0) == tuple(arr[25, 50, :])
         assert (128, 255, 128) == tuple(arr[35, 50, :])
-        assert (  0,   0, 255) == tuple(arr[45, 50, :])
+        assert (0, 0, 255) == tuple(arr[45, 50, :])
         assert (128, 128, 255) == tuple(arr[55, 50, :])
-        assert (  0,   0,   0) == tuple(arr[65, 50, :])
-        assert ( 64,  64,  64) == tuple(arr[75, 50, :])
+        assert (0, 0, 0) == tuple(arr[65, 50, :])
+        assert (64, 64, 64) == tuple(arr[75, 50, :])
         assert (192, 192, 192) == tuple(arr[85, 50, :])
         assert (255, 255, 255) == tuple(arr[95, 50, :])
 
@@ -791,54 +790,55 @@ class TestJPEGLSLossless(HandlerTestBase):
     3 sample/px, 16/16 bits allocated/stored, unsigned, RGB, 1 frame
     3 sample/px, 16/16 bits allocated/stored, unsigned, RGB, > 1 frame
     """
-    uid = '1.2.840.10008.1.2.4.80'
+
+    uid = "1.2.840.10008.1.2.4.80"
 
     def test_1s_1f_i_16_16(self):
         """Test process 2 greyscale."""
-        ds = self.ds['MR_small_jpeg_ls_lossless.dcm']['ds']
+        ds = self.ds["MR_small_jpeg_ls_lossless.dcm"]["ds"]
         assert self.uid == ds.file_meta.TransferSyntaxUID
         assert 1 == ds.SamplesPerPixel
-        assert 1 == getattr(ds, 'NumberOfFrames', 1)
-        assert 'MONOCHROME' in ds.PhotometricInterpretation
+        assert 1 == getattr(ds, "NumberOfFrames", 1)
+        assert "MONOCHROME" in ds.PhotometricInterpretation
         assert 16 == ds.BitsAllocated
         assert 16 == ds.BitsStored
         assert 1 == ds.PixelRepresentation
 
         arr = ds.pixel_array
         assert arr.flags.writeable
-        assert 'int16' == arr.dtype
+        assert "int16" == arr.dtype
         assert (ds.Rows, ds.Columns) == arr.shape
 
-        #self.plot(arr, cmap='gray')
+        # self.plot(arr, cmap='gray')
 
         # Reference values from GDCM handler
-        assert [1194,  879,  127,  661, 1943, 1885, 1857, 1746, 1699] == (
+        assert [1194, 879, 127, 661, 1943, 1885, 1857, 1746, 1699] == (
             arr[55:65, 38].tolist()
         )
 
     def test_1s_Nf_u_16_12(self):
         """Test process 2 greyscale."""
-        ds = self.ds['emri_small_jpeg_ls_lossless.dcm']['ds']
+        ds = self.ds["emri_small_jpeg_ls_lossless.dcm"]["ds"]
         assert self.uid == ds.file_meta.TransferSyntaxUID
         assert 1 == ds.SamplesPerPixel
-        assert 10 == getattr(ds, 'NumberOfFrames', 1)
-        assert 'MONOCHROME' in ds.PhotometricInterpretation
+        assert 10 == getattr(ds, "NumberOfFrames", 1)
+        assert "MONOCHROME" in ds.PhotometricInterpretation
         assert 16 == ds.BitsAllocated
         assert 12 == ds.BitsStored
         assert 0 == ds.PixelRepresentation
 
         arr = ds.pixel_array
         assert arr.flags.writeable
-        assert 'uint16' == arr.dtype
+        assert "uint16" == arr.dtype
         assert (10, ds.Rows, ds.Columns) == arr.shape
 
-        #self.plot(arr, index=0, cmap='gray')
+        # self.plot(arr, index=0, cmap='gray')
 
         # Reference values from GDCM handler
-        assert [361, 295, 215,  98,  79,  70,  41,  29,  61,  64] == (
+        assert [361, 295, 215, 98, 79, 70, 41, 29, 61, 64] == (
             arr[0, 18:28, 48].tolist()
         )
-        assert [298, 332, 355, 361, 324, 263, 169, 105,  53,  45] == (
+        assert [298, 332, 355, 361, 324, 263, 169, 105, 53, 45] == (
             arr[9, 18:28, 48].tolist()
         )
 
@@ -888,25 +888,26 @@ class TestJPEGLS(HandlerTestBase):
     3 sample/px, 16/16 bits allocated/stored, unsigned, RGB, 1 frame
     3 sample/px, 16/16 bits allocated/stored, unsigned, RGB, > 1 frame
     """
-    uid = '1.2.840.10008.1.2.4.81'
+
+    uid = "1.2.840.10008.1.2.4.81"
 
     def test_1s_1f_i_16_16(self):
         """Test process 2 greyscale."""
-        ds = self.ds['CT1_JLSN.dcm']['ds']
+        ds = self.ds["CT1_JLSN.dcm"]["ds"]
         assert self.uid == ds.file_meta.TransferSyntaxUID
         assert 1 == ds.SamplesPerPixel
-        assert 1 == getattr(ds, 'NumberOfFrames', 1)
-        assert 'MONOCHROME' in ds.PhotometricInterpretation
+        assert 1 == getattr(ds, "NumberOfFrames", 1)
+        assert "MONOCHROME" in ds.PhotometricInterpretation
         assert 16 == ds.BitsAllocated
         assert 16 == ds.BitsStored
         assert 1 == ds.PixelRepresentation
 
         arr = ds.pixel_array
         assert arr.flags.writeable
-        assert 'int16' == arr.dtype
+        assert "int16" == arr.dtype
         assert (ds.Rows, ds.Columns) == arr.shape
 
-        #self.plot(arr)
+        # self.plot(arr)
 
         # Reference values from GDCM handler
         assert [-2000, -2000, 936, 946, 927, 925, 918, 929, 931, 921] == (
@@ -915,21 +916,21 @@ def test_1s_1f_i_16_16(self):
 
     def test_1s_1f_u_16_10(self):
         """Test process 2 greyscale."""
-        ds = self.ds['RG2_JLSN.dcm']['ds']
+        ds = self.ds["RG2_JLSN.dcm"]["ds"]
         assert self.uid == ds.file_meta.TransferSyntaxUID
         assert 1 == ds.SamplesPerPixel
-        assert 1 == getattr(ds, 'NumberOfFrames', 1)
-        assert 'MONOCHROME' in ds.PhotometricInterpretation
+        assert 1 == getattr(ds, "NumberOfFrames", 1)
+        assert "MONOCHROME" in ds.PhotometricInterpretation
         assert 16 == ds.BitsAllocated
         assert 10 == ds.BitsStored
         assert 0 == ds.PixelRepresentation
 
         arr = ds.pixel_array
         assert arr.flags.writeable
-        assert 'uint16' == arr.dtype
+        assert "uint16" == arr.dtype
         assert (ds.Rows, ds.Columns) == arr.shape
 
-        #self.plot(arr)
+        # self.plot(arr)
 
         # Reference values from GDCM handler
         assert [574, 666, 760, 781, 789, 733, 634, 585, 594, 589] == (
@@ -938,21 +939,21 @@ def test_1s_1f_u_16_10(self):
 
     def test_1s_1f_u_16_12(self):
         """Test process 2 greyscale."""
-        ds = self.ds['MG1_JLSN.dcm']['ds']
+        ds = self.ds["MG1_JLSN.dcm"]["ds"]
         assert self.uid == ds.file_meta.TransferSyntaxUID
         assert 1 == ds.SamplesPerPixel
-        assert 1 == getattr(ds, 'NumberOfFrames', 1)
-        assert 'MONOCHROME' in ds.PhotometricInterpretation
+        assert 1 == getattr(ds, "NumberOfFrames", 1)
+        assert "MONOCHROME" in ds.PhotometricInterpretation
         assert 16 == ds.BitsAllocated
         assert 12 == ds.BitsStored
         assert 0 == ds.PixelRepresentation
 
         arr = ds.pixel_array
         assert arr.flags.writeable
-        assert 'uint16' == arr.dtype
+        assert "uint16" == arr.dtype
         assert (ds.Rows, ds.Columns) == arr.shape
 
-        #self.plot(arr)
+        # self.plot(arr)
 
         # Reference values from GDCM handler
         assert [3027, 2859, 2839, 2821, 2837, 2834, 2817, 2844, 2837] == (
@@ -961,21 +962,21 @@ def test_1s_1f_u_16_12(self):
 
     def test_1s_1f_u_16_15(self):
         """Test process 2 greyscale."""
-        ds = self.ds['RG1_JLSN.dcm']['ds']
+        ds = self.ds["RG1_JLSN.dcm"]["ds"]
         assert self.uid == ds.file_meta.TransferSyntaxUID
         assert 1 == ds.SamplesPerPixel
-        assert 1 == getattr(ds, 'NumberOfFrames', 1)
-        assert 'MONOCHROME' in ds.PhotometricInterpretation
+        assert 1 == getattr(ds, "NumberOfFrames", 1)
+        assert "MONOCHROME" in ds.PhotometricInterpretation
         assert 16 == ds.BitsAllocated
         assert 15 == ds.BitsStored
         assert 0 == ds.PixelRepresentation
 
         arr = ds.pixel_array
         assert arr.flags.writeable
-        assert 'uint16' == arr.dtype
+        assert "uint16" == arr.dtype
         assert (ds.Rows, ds.Columns) == arr.shape
 
-        #self.plot(arr)
+        # self.plot(arr)
 
         # Reference values from GDCM handler
         assert [24047, 23910, 23668, 23529, 22960, 22871, 22505, 22066] == (
@@ -990,15 +991,16 @@ class TestJPEG2000Lossless(HandlerTestBase):
 
     1.2.840.10008.1.2.4.90 : JPEG 2000 Image Compression (Lossless Only)
     """
-    uid = '1.2.840.10008.1.2.4.90'
+
+    uid = "1.2.840.10008.1.2.4.90"
 
     def test_1s_1f_i_16_16(self):
         """Test process 2 greyscale."""
-        ds = self.ds['693_J2KR.dcm']['ds']
+        ds = self.ds["693_J2KR.dcm"]["ds"]
         assert self.uid == ds.file_meta.TransferSyntaxUID
         assert 1 == ds.SamplesPerPixel
-        assert 1 == getattr(ds, 'NumberOfFrames', 1)
-        assert 'MONOCHROME' in ds.PhotometricInterpretation
+        assert 1 == getattr(ds, "NumberOfFrames", 1)
+        assert "MONOCHROME" in ds.PhotometricInterpretation
         assert 16 == ds.BitsAllocated
         assert 16 == ds.BitsStored
         assert 1 == ds.PixelRepresentation
@@ -1017,15 +1019,16 @@ class TestJPEG2000(HandlerTestBase):
 
     1.2.840.10008.1.2.4.91 : JPEG 2000 Image Compression
     """
-    uid = '1.2.840.10008.1.2.4.91'
+
+    uid = "1.2.840.10008.1.2.4.91"
 
     def test_1s_1f_i_16_16(self):
         """Test process 2 greyscale."""
-        ds = self.ds['693_J2KI.dcm']['ds']
+        ds = self.ds["693_J2KI.dcm"]["ds"]
         assert self.uid == ds.file_meta.TransferSyntaxUID
         assert 1 == ds.SamplesPerPixel
-        assert 1 == getattr(ds, 'NumberOfFrames', 1)
-        assert 'MONOCHROME' in ds.PhotometricInterpretation
+        assert 1 == getattr(ds, "NumberOfFrames", 1)
+        assert "MONOCHROME" in ds.PhotometricInterpretation
         assert 16 == ds.BitsAllocated
         assert 14 == ds.BitsStored
         assert 1 == ds.PixelRepresentation
diff --git a/libjpeg/tests/test_parameters.py b/libjpeg/tests/test_parameters.py
index 2b7e24f..31fbd52 100644
--- a/libjpeg/tests/test_parameters.py
+++ b/libjpeg/tests/test_parameters.py
@@ -12,6 +12,7 @@
     import pydicom.config
     from pydicom.pixel_data_handlers.util import convert_color_space
     from pydicom.encaps import defragment_data, generate_pixel_data_frame
+
     HAS_PYDICOM = True
 except ImportError:
     HAS_PYDICOM = False
@@ -20,62 +21,62 @@
 from libjpeg.data import get_indexed_datasets, JPEG_DIRECTORY
 
 
-DIR_10918 = os.path.join(JPEG_DIRECTORY, '10918')
-DIR_14495 = os.path.join(JPEG_DIRECTORY, '14495')
+DIR_10918 = os.path.join(JPEG_DIRECTORY, "10918")
+DIR_14495 = os.path.join(JPEG_DIRECTORY, "14495")
 
 
 REF_DCM = {
-    '1.2.840.10008.1.2.4.50' : [
+    "1.2.840.10008.1.2.4.50": [
         # filename, (rows, columns, samples/px, bits/sample)
-        ('JPEGBaseline_1s_1f_u_08_08.dcm', (100, 100, 1, 8)),
-        ('SC_rgb_dcmtk_+eb+cy+np.dcm', (100, 100, 3, 8)),
-        ('color3d_jpeg_baseline.dcm', (480, 640, 3, 8)),
-        ('SC_rgb_dcmtk_+eb+cr.dcm', (100, 100, 3, 8)),
-        ('SC_rgb_dcmtk_+eb+cy+n1.dcm', (100, 100, 3, 8)),
-        ('SC_rgb_dcmtk_+eb+cy+s4.dcm', (100, 100, 3, 8)),
+        ("JPEGBaseline_1s_1f_u_08_08.dcm", (100, 100, 1, 8)),
+        ("SC_rgb_dcmtk_+eb+cy+np.dcm", (100, 100, 3, 8)),
+        ("color3d_jpeg_baseline.dcm", (480, 640, 3, 8)),
+        ("SC_rgb_dcmtk_+eb+cr.dcm", (100, 100, 3, 8)),
+        ("SC_rgb_dcmtk_+eb+cy+n1.dcm", (100, 100, 3, 8)),
+        ("SC_rgb_dcmtk_+eb+cy+s4.dcm", (100, 100, 3, 8)),
     ],
-    '1.2.840.10008.1.2.4.51' : [
-        ('RG2_JPLY_fixed.dcm', (2140, 1760, 1, 12)),
-        ('JPEGExtended_1s_1f_u_16_12.dcm', (1024, 256, 1, 12)),
-        ('JPEGExtended_3s_1f_u_08_08.dcm', (576, 768, 3, 8)),
+    "1.2.840.10008.1.2.4.51": [
+        ("RG2_JPLY_fixed.dcm", (2140, 1760, 1, 12)),
+        ("JPEGExtended_1s_1f_u_16_12.dcm", (1024, 256, 1, 12)),
+        ("JPEGExtended_3s_1f_u_08_08.dcm", (576, 768, 3, 8)),
     ],
-    '1.2.840.10008.1.2.4.57' : [
-        ('JPEGLossless_1s_1f_u_16_12.dcm', (1024, 1024, 1, 12)),
+    "1.2.840.10008.1.2.4.57": [
+        ("JPEGLossless_1s_1f_u_16_12.dcm", (1024, 1024, 1, 12)),
     ],
-    '1.2.840.10008.1.2.4.70' : [
-        ('JPEG-LL.dcm', (1024, 256, 1, 16)),
-        ('JPEGLosslessP14SV1_1s_1f_u_08_08.dcm', (768, 1024, 1, 8)),
-        ('JPEGLosslessP14SV1_1s_1f_u_16_16.dcm', (535, 800, 1, 16)),
-        ('MG1_JPLL.dcm', (4664, 3064, 1, 12)),
-        ('RG1_JPLL.dcm', (1955, 1841, 1, 15)),
-        ('RG2_JPLL.dcm', (2140, 1760, 1, 10)),
-        ('SC_rgb_jpeg_gdcm.dcm', (100, 100, 3, 8)),
+    "1.2.840.10008.1.2.4.70": [
+        ("JPEG-LL.dcm", (1024, 256, 1, 16)),
+        ("JPEGLosslessP14SV1_1s_1f_u_08_08.dcm", (768, 1024, 1, 8)),
+        ("JPEGLosslessP14SV1_1s_1f_u_16_16.dcm", (535, 800, 1, 16)),
+        ("MG1_JPLL.dcm", (4664, 3064, 1, 12)),
+        ("RG1_JPLL.dcm", (1955, 1841, 1, 15)),
+        ("RG2_JPLL.dcm", (2140, 1760, 1, 10)),
+        ("SC_rgb_jpeg_gdcm.dcm", (100, 100, 3, 8)),
     ],
-    '1.2.840.10008.1.2.4.80' : [
-        ('emri_small_jpeg_ls_lossless.dcm', (64, 64, 1, 12)),
-        ('MR_small_jpeg_ls_lossless.dcm', (64, 64, 1, 16)),
-        ('RG1_JLSL.dcm', (1955, 1841, 1, 16)),
-        ('RG2_JLSL.dcm', (2140, 1760, 1, 10)),
+    "1.2.840.10008.1.2.4.80": [
+        ("emri_small_jpeg_ls_lossless.dcm", (64, 64, 1, 12)),
+        ("MR_small_jpeg_ls_lossless.dcm", (64, 64, 1, 16)),
+        ("RG1_JLSL.dcm", (1955, 1841, 1, 16)),
+        ("RG2_JLSL.dcm", (2140, 1760, 1, 10)),
     ],
-    '1.2.840.10008.1.2.4.81' : [
-        ('CT1_JLSN.dcm', (512, 512, 1, 16)),
-        ('MG1_JLSN.dcm', (4664, 3064, 1, 12)),
-        ('RG1_JLSN.dcm', (1955, 1841, 1, 15)),
-        ('RG2_JLSN.dcm', (2140, 1760, 1, 10)),
+    "1.2.840.10008.1.2.4.81": [
+        ("CT1_JLSN.dcm", (512, 512, 1, 16)),
+        ("MG1_JLSN.dcm", (4664, 3064, 1, 12)),
+        ("RG1_JLSN.dcm", (1955, 1841, 1, 15)),
+        ("RG2_JLSN.dcm", (2140, 1760, 1, 10)),
     ],
 }
 
 
 def test_get_parameters_bytes():
     """Test get_parameters() using bytes."""
-    with open(os.path.join(DIR_10918, 'p1', 'A1.JPG'), 'rb') as fp:
+    with open(os.path.join(DIR_10918, "p1", "A1.JPG"), "rb") as fp:
         data = fp.read()
 
     params = get_parameters(data)
 
     info = (257, 255, 4, 8)
 
-    assert (info[0], info[1]) == (params['rows'], params['columns'])
+    assert (info[0], info[1]) == (params["rows"], params["columns"])
     assert info[2] == params["nr_components"]
     assert info[3] == params["precision"]
 
@@ -83,13 +84,13 @@ def test_get_parameters_bytes():
 @pytest.mark.skipif(not HAS_PYDICOM, reason="No pydicom")
 def test_non_conformant_raises():
     """Test that a non-conformant JPEG image raises an exception."""
-    ds_list = get_indexed_datasets('1.2.840.10008.1.2.4.51')
+    ds_list = get_indexed_datasets("1.2.840.10008.1.2.4.51")
     # Image has invalid Se value in the SOS marker segment
-    item = ds_list['JPEG-lossy.dcm']
-    assert 0xC000 == item['Status'][1]
-    ds = item['ds']
+    item = ds_list["JPEG-lossy.dcm"]
+    assert 0xC000 == item["Status"][1]
+    ds = item["ds"]
 
-    nr_frames = ds.get('NumberOfFrames', 1)
+    nr_frames = ds.get("NumberOfFrames", 1)
     frame = next(generate_pixel_data_frame(ds.PixelData, nr_frames))
 
     msg = (
@@ -101,219 +102,214 @@ def test_non_conformant_raises():
         get_parameters(frame)
 
 
-@pytest.mark.skip("Not sure how to trigger exception")
-def test_unknown_error_raised():
-    """Test that an unknown error is handled properly."""
-    #get_parameters(b'')
-    pass
-
-
 @pytest.mark.skipif(not HAS_PYDICOM, reason="No pydicom")
 class TestGetParametersDCM:
     """Tests for get_parameters() using DICOM datasets."""
+
     def generate_frames(self, ds):
         """Return a generator object with the dataset's pixel data frames."""
-        nr_frames = ds.get('NumberOfFrames', 1)
+        nr_frames = ds.get("NumberOfFrames", 1)
         return generate_pixel_data_frame(ds.PixelData, nr_frames)
 
-    @pytest.mark.parametrize("fname, info", REF_DCM['1.2.840.10008.1.2.4.50'])
+    @pytest.mark.parametrize("fname, info", REF_DCM["1.2.840.10008.1.2.4.50"])
     def test_baseline(self, fname, info):
         """Test get_parameters() for the baseline datasets."""
-        #info: (rows, columns, spp, bps)
-        index = get_indexed_datasets('1.2.840.10008.1.2.4.50')
-        ds = index[fname]['ds']
+        # info: (rows, columns, spp, bps)
+        index = get_indexed_datasets("1.2.840.10008.1.2.4.50")
+        ds = index[fname]["ds"]
 
         frame = next(self.generate_frames(ds))
-        params = get_parameters(np.frombuffer(frame, 'uint8'))
+        params = get_parameters(frame)
 
-        assert (info[0], info[1]) == (params['rows'], params['columns'])
+        assert (info[0], info[1]) == (params["rows"], params["columns"])
         assert info[2] == params["nr_components"]
         assert info[3] == params["precision"]
 
-    @pytest.mark.parametrize("fname, info", REF_DCM['1.2.840.10008.1.2.4.51'])
+    @pytest.mark.parametrize("fname, info", REF_DCM["1.2.840.10008.1.2.4.51"])
     def test_extended(self, fname, info):
         """Test get_parameters() for the baseline datasets."""
-        #info: (rows, columns, spp, bps)
-        index = get_indexed_datasets('1.2.840.10008.1.2.4.51')
-        ds = index[fname]['ds']
+        # info: (rows, columns, spp, bps)
+        index = get_indexed_datasets("1.2.840.10008.1.2.4.51")
+        ds = index[fname]["ds"]
 
         frame = next(self.generate_frames(ds))
-        params = get_parameters(np.frombuffer(frame, 'uint8'))
+        params = get_parameters(frame)
 
-        assert (info[0], info[1]) == (params['rows'], params['columns'])
+        assert (info[0], info[1]) == (params["rows"], params["columns"])
         assert info[2] == params["nr_components"]
         assert info[3] == params["precision"]
 
-    @pytest.mark.parametrize("fname, info", REF_DCM['1.2.840.10008.1.2.4.57'])
+    @pytest.mark.parametrize("fname, info", REF_DCM["1.2.840.10008.1.2.4.57"])
     def test_lossless(self, fname, info):
         """Test get_parameters() for the lossless datasets."""
-        #info: (rows, columns, spp, bps)
-        index = get_indexed_datasets('1.2.840.10008.1.2.4.57')
-        ds = index[fname]['ds']
+        # info: (rows, columns, spp, bps)
+        index = get_indexed_datasets("1.2.840.10008.1.2.4.57")
+        ds = index[fname]["ds"]
 
         frame = next(self.generate_frames(ds))
-        params = get_parameters(np.frombuffer(frame, 'uint8'))
+        params = get_parameters(frame)
 
-        assert (info[0], info[1]) == (params['rows'], params['columns'])
+        assert (info[0], info[1]) == (params["rows"], params["columns"])
         assert info[2] == params["nr_components"]
         assert info[3] == params["precision"]
 
-    @pytest.mark.parametrize("fname, info", REF_DCM['1.2.840.10008.1.2.4.70'])
+    @pytest.mark.parametrize("fname, info", REF_DCM["1.2.840.10008.1.2.4.70"])
     def test_lossless_sv1(self, fname, info):
         """Test get_parameters() for the lossless SV1 datasets."""
-        #info: (rows, columns, spp, bps)
-        index = get_indexed_datasets('1.2.840.10008.1.2.4.70')
-        ds = index[fname]['ds']
+        # info: (rows, columns, spp, bps)
+        index = get_indexed_datasets("1.2.840.10008.1.2.4.70")
+        ds = index[fname]["ds"]
 
         frame = next(self.generate_frames(ds))
-        params = get_parameters(np.frombuffer(frame, 'uint8'))
+        params = get_parameters(frame)
 
-        assert (info[0], info[1]) == (params['rows'], params['columns'])
+        assert (info[0], info[1]) == (params["rows"], params["columns"])
         assert info[2] == params["nr_components"]
         assert info[3] == params["precision"]
 
-    @pytest.mark.parametrize("fname, info", REF_DCM['1.2.840.10008.1.2.4.80'])
+    @pytest.mark.parametrize("fname, info", REF_DCM["1.2.840.10008.1.2.4.80"])
     def test_extended(self, fname, info):
         """Test get_parameters() for the LS lossless datasets."""
-        #info: (rows, columns, spp, bps)
-        index = get_indexed_datasets('1.2.840.10008.1.2.4.80')
-        ds = index[fname]['ds']
+        # info: (rows, columns, spp, bps)
+        index = get_indexed_datasets("1.2.840.10008.1.2.4.80")
+        ds = index[fname]["ds"]
 
         frame = next(self.generate_frames(ds))
-        params = get_parameters(np.frombuffer(frame, 'uint8'))
+        params = get_parameters(frame)
 
-        assert (info[0], info[1]) == (params['rows'], params['columns'])
+        assert (info[0], info[1]) == (params["rows"], params["columns"])
         assert info[2] == params["nr_components"]
         assert info[3] == params["precision"]
 
-    @pytest.mark.parametrize("fname, info", REF_DCM['1.2.840.10008.1.2.4.81'])
+    @pytest.mark.parametrize("fname, info", REF_DCM["1.2.840.10008.1.2.4.81"])
     def test_extended(self, fname, info):
         """Test get_parameters() for the LS lossy datasets."""
-        #info: (rows, columns, spp, bps)
-        index = get_indexed_datasets('1.2.840.10008.1.2.4.81')
-        ds = index[fname]['ds']
+        # info: (rows, columns, spp, bps)
+        index = get_indexed_datasets("1.2.840.10008.1.2.4.81")
+        ds = index[fname]["ds"]
 
         frame = next(self.generate_frames(ds))
-        params = get_parameters(np.frombuffer(frame, 'uint8'))
+        params = get_parameters(frame)
 
-        assert (info[0], info[1]) == (params['rows'], params['columns'])
+        assert (info[0], info[1]) == (params["rows"], params["columns"])
         assert info[2] == params["nr_components"]
         assert info[3] == params["precision"]
 
 
 REF_JPG = {
-    '10918' : {
-        'p1' : [
-            ('A1.JPG', (257, 255, 4, 8)),
-            #('B1.JPG', (1, 1, 1, 1)),
-            #('B2.JPG', (1, 1, 1, 1)), missing DHT marker (its in B1.JPG)
+    "10918": {
+        "p1": [
+            ("A1.JPG", (257, 255, 4, 8)),
+            # ('B1.JPG', (1, 1, 1, 1)),
+            # ('B2.JPG', (1, 1, 1, 1)), missing DHT marker (its in B1.JPG)
         ],
-        'p2' : [
-            ('A1.JPG', (257, 255, 4, 8)),
-            #('B1.JPG', ()),
-            #('B2.JPG', ()), missing DHT (in B1)
-            ('C1.JPG', (257, 255, 4, 8)),
-            ('C2.JPG', (257, 255, 4, 8)),
+        "p2": [
+            ("A1.JPG", (257, 255, 4, 8)),
+            # ('B1.JPG', ()),
+            # ('B2.JPG', ()), missing DHT (in B1)
+            ("C1.JPG", (257, 255, 4, 8)),
+            ("C2.JPG", (257, 255, 4, 8)),
         ],
-        'p4' : [
-            ('A1.JPG', (257, 255, 4, 8)),
-            #('B1.JPG', ()),
-            #('B2.JPG', ()),
-            ('C1.JPG', (257, 255, 4, 8)),
-            ('C2.JPG', (257, 255, 4, 8)),
-            ('E1.JPG', (257, 255, 4, 12)),
-            ('E2.JPG', (257, 255, 4, 12)),
+        "p4": [
+            ("A1.JPG", (257, 255, 4, 8)),
+            # ('B1.JPG', ()),
+            # ('B2.JPG', ()),
+            ("C1.JPG", (257, 255, 4, 8)),
+            ("C2.JPG", (257, 255, 4, 8)),
+            ("E1.JPG", (257, 255, 4, 12)),
+            ("E2.JPG", (257, 255, 4, 12)),
         ],
-        'p14' : [
-            ('O1.JPG', (257, 255, 4, 8)),
-            ('O2.JPG', (257, 255, 4, 16)),
+        "p14": [
+            ("O1.JPG", (257, 255, 4, 8)),
+            ("O2.JPG", (257, 255, 4, 16)),
         ],
     },
-    '14495' : {
-        'JLS' : [
-            ('T8C0E0.JLS', (256, 256, 3, 8)),
-            ('T8C1E0.JLS', (256, 256, 3, 8)),
-            ('T8C2E0.JLS', (256, 256, 3, 8)),
-            ('T8NDE0.JLS', (128, 128, 1, 8)),
-            ('T8SSE0.JLS', (256, 256, 3, 8)),
-            ('T16E0.JLS', (256, 256, 1, 12)),
+    "14495": {
+        "JLS": [
+            ("T8C0E0.JLS", (256, 256, 3, 8)),
+            ("T8C1E0.JLS", (256, 256, 3, 8)),
+            ("T8C2E0.JLS", (256, 256, 3, 8)),
+            ("T8NDE0.JLS", (128, 128, 1, 8)),
+            ("T8SSE0.JLS", (256, 256, 3, 8)),
+            ("T16E0.JLS", (256, 256, 1, 12)),
         ],
-        'JNL' : [
-            ('T8C0E3.JLS', (256, 256, 3, 8)),
-            ('T8C1E3.JLS', (256, 256, 3, 8)),
-            ('T8C2E3.JLS', (256, 256, 3, 8)),
-            ('T8NDE3.JLS', (128, 128, 1, 8)),
-            ('T8SSE3.JLS', (256, 256, 3, 8)),
-            ('T16E3.JLS', (256, 256, 1, 12)),
+        "JNL": [
+            ("T8C0E3.JLS", (256, 256, 3, 8)),
+            ("T8C1E3.JLS", (256, 256, 3, 8)),
+            ("T8C2E3.JLS", (256, 256, 3, 8)),
+            ("T8NDE3.JLS", (128, 128, 1, 8)),
+            ("T8SSE3.JLS", (256, 256, 3, 8)),
+            ("T16E3.JLS", (256, 256, 1, 12)),
         ],
     },
-    '15444' : {},
+    "15444": {},
 }
 
 
 class TestGetParametersJPG:
     """Tests for get_parameters() using JPEG compliance data."""
-    @pytest.mark.parametrize("fname, info", REF_JPG['10918']['p1'])
+
+    @pytest.mark.parametrize("fname, info", REF_JPG["10918"]["p1"])
     def test_baseline(self, fname, info):
         """Test get_parameters() for the baseline compliance images."""
-        #info: (rows, columns, spp, bps)
-        with open(os.path.join(DIR_10918, 'p1', fname), 'rb') as fp:
+        # info: (rows, columns, spp, bps)
+        with open(os.path.join(DIR_10918, "p1", fname), "rb") as fp:
             data = fp.read()
 
-        params = get_parameters(np.frombuffer(data, 'uint8'))
+        params = get_parameters(data)
 
-        assert (info[0], info[1]) == (params['rows'], params['columns'])
+        assert (info[0], info[1]) == (params["rows"], params["columns"])
         assert info[2] == params["nr_components"]
         assert info[3] == params["precision"]
 
-    @pytest.mark.parametrize("fname, info", REF_JPG['10918']['p2'])
+    @pytest.mark.parametrize("fname, info", REF_JPG["10918"]["p2"])
     def test_extended_p2(self, fname, info):
         """Test get_parameters() for the extended p2 compliance images."""
-        #info: (rows, columns, spp, bps)
-        with open(os.path.join(DIR_10918, 'p2', fname), 'rb') as fp:
+        # info: (rows, columns, spp, bps)
+        with open(os.path.join(DIR_10918, "p2", fname), "rb") as fp:
             data = fp.read()
 
-        params = get_parameters(np.frombuffer(data, 'uint8'))
+        params = get_parameters(data)
 
-        assert (info[0], info[1]) == (params['rows'], params['columns'])
+        assert (info[0], info[1]) == (params["rows"], params["columns"])
         assert info[2] == params["nr_components"]
         assert info[3] == params["precision"]
 
-    @pytest.mark.parametrize("fname, info", REF_JPG['10918']['p4'])
+    @pytest.mark.parametrize("fname, info", REF_JPG["10918"]["p4"])
     def test_extended_p4(self, fname, info):
         """Test get_parameters() for the extended p4 compliance images."""
-        #info: (rows, columns, spp, bps)
-        with open(os.path.join(DIR_10918, 'p4', fname), 'rb') as fp:
+        # info: (rows, columns, spp, bps)
+        with open(os.path.join(DIR_10918, "p4", fname), "rb") as fp:
             data = fp.read()
 
-        params = get_parameters(np.frombuffer(data, 'uint8'))
+        params = get_parameters(data)
 
-        assert (info[0], info[1]) == (params['rows'], params['columns'])
+        assert (info[0], info[1]) == (params["rows"], params["columns"])
         assert info[2] == params["nr_components"]
         assert info[3] == params["precision"]
 
-    @pytest.mark.parametrize("fname, info", REF_JPG['10918']['p14'])
+    @pytest.mark.parametrize("fname, info", REF_JPG["10918"]["p14"])
     def test_lossless_p14(self, fname, info):
         """Test get_parameters() for the extended p14 compliance images."""
-        #info: (rows, columns, spp, bps)
-        with open(os.path.join(DIR_10918, 'p14', fname), 'rb') as fp:
+        # info: (rows, columns, spp, bps)
+        with open(os.path.join(DIR_10918, "p14", fname), "rb") as fp:
             data = fp.read()
 
-        params = get_parameters(np.frombuffer(data, 'uint8'))
+        params = get_parameters(data)
 
-        assert (info[0], info[1]) == (params['rows'], params['columns'])
+        assert (info[0], info[1]) == (params["rows"], params["columns"])
         assert info[2] == params["nr_components"]
         assert info[3] == params["precision"]
 
-    @pytest.mark.parametrize("fname, info", REF_JPG['14495']['JLS'])
+    @pytest.mark.parametrize("fname, info", REF_JPG["14495"]["JLS"])
     def test_jls(self, fname, info):
         """Test get_parameters() for the JPEG-LS compliance images."""
-        #info: (rows, columns, spp, bps)
-        with open(os.path.join(DIR_14495, 'JLS', fname), 'rb') as fp:
+        # info: (rows, columns, spp, bps)
+        with open(os.path.join(DIR_14495, "JLS", fname), "rb") as fp:
             data = fp.read()
 
-        params = get_parameters(np.frombuffer(data, 'uint8'))
+        params = get_parameters(data)
 
-        assert (info[0], info[1]) == (params['rows'], params['columns'])
+        assert (info[0], info[1]) == (params["rows"], params["columns"])
         assert info[2] == params["nr_components"]
         assert info[3] == params["precision"]
diff --git a/libjpeg/tests/test_reconstruct.py b/libjpeg/tests/test_reconstruct.py
index e34cafb..d931e43 100644
--- a/libjpeg/tests/test_reconstruct.py
+++ b/libjpeg/tests/test_reconstruct.py
@@ -10,8 +10,8 @@
 from libjpeg.data import JPEG_DIRECTORY
 
 
-DIR_10918 = os.path.join(JPEG_DIRECTORY, '10918')
-DIR_14495 = os.path.join(JPEG_DIRECTORY, '14495')
+DIR_10918 = os.path.join(JPEG_DIRECTORY, "10918")
+DIR_14495 = os.path.join(JPEG_DIRECTORY, "14495")
 
 
 def test_reconstruct_no_alpha():
@@ -21,41 +21,38 @@ def test_reconstruct_no_alpha():
     inname = os.path.join(tempdir.name, os.urandom(24).hex())
     outname = os.path.join(tempdir.name, os.urandom(24).hex())
 
-    infile = open(inname, 'wb')
-    with open(os.path.join(DIR_14495, 'JLS', 'T8C0E0.JLS'), 'rb') as fp:
+    infile = open(inname, "wb")
+    with open(os.path.join(DIR_14495, "JLS", "T8C0E0.JLS"), "rb") as fp:
         infile.write(fp.read())
 
     infile.close()
 
     # Output file
-    reconstruct(
-        inname, outname, colourspace=0, falpha=None, upsample=True
-    )
-    with open(outname, 'rb') as f:
+    reconstruct(inname, outname, colourspace=0, falpha=None, upsample=True)
+    with open(outname, "rb") as f:
         data = f.read()
 
     tempdir.cleanup()
 
-    assert b'P6\n256 256' == data[:10]
+    assert b"P6\n256 256" == data[:10]
 
 
 @pytest.mark.skip("Needs more understanding")
 def test_reconstruct_alpha():
     """Basic test of reconstruct() with pretend alpha data."""
     # Input file
-    infile = NamedTemporaryFile('rb+')
-    with open(os.path.join(DIR_10918, 'p1', 'A1.JPG'), 'rb') as fp:
+    infile = NamedTemporaryFile("rb+")
+    with open(os.path.join(DIR_10918, "p1", "A1.JPG"), "rb") as fp:
         infile.write(fp.read())
 
     # Output file - CMY
-    outfile = NamedTemporaryFile('rb+')
+    outfile = NamedTemporaryFile("rb+")
     # Output file - "alpha"
-    alphafile = NamedTemporaryFile('rb+')
+    alphafile = NamedTemporaryFile("rb+")
 
     reconstruct(
-        infile.name, outfile.name, colourspace=0,
-        falpha=alphafile.name, upsample=True
+        infile.name, outfile.name, colourspace=0, falpha=alphafile.name, upsample=True
     )
 
-    assert b'' == alphafile.read(10)
-    assert b'P6\n256 256' == outfile.read(10)
+    assert b"" == alphafile.read(10)
+    assert b"P6\n256 256" == outfile.read(10)