We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add 16bit encode/decode to JPEG2K (WIP)
Add the ability to write 16bit JPEG2k Images (for DICOM medical images).

I'd trying to add a decoder too but I couldn't quite figure it out.  Here's my dumb test case:

``` python
import numpy as np
from PIL import Image

arr = np.zeros((64, 96), dtype=np.uint16)
arr[16:64, 0:32] = 300

img = Image.fromarray(arr, 'I;16')
img.save('grr.j2k')  # Works

img2 = Image.open('grr.j2k')
arr2 = np.array(img2)

np.testing.assert_almost_equal(arr, arr2)  # Fails
```

Thoughts?


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `PIL/Jpeg2KImagePlugin.py`
Content:
```
1 #
2 # The Python Imaging Library
3 # $Id$
4 #
5 # JPEG2000 file handling
6 #
7 # History:
8 # 2014-03-12 ajh  Created
9 #
10 # Copyright (c) 2014 Coriolis Systems Limited
11 # Copyright (c) 2014 Alastair Houghton
12 #
13 # See the README file for information on usage and redistribution.
14 #
15 
16 __version__ = "0.1"
17 
18 from PIL import Image, ImageFile
19 import struct
20 import os
21 import io
22 
23 
24 def _parse_codestream(fp):
25     """Parse the JPEG 2000 codestream to extract the size and component
26     count from the SIZ marker segment, returning a PIL (size, mode) tuple."""
27 
28     hdr = fp.read(2)
29     lsiz = struct.unpack('>H', hdr)[0]
30     siz = hdr + fp.read(lsiz - 2)
31     lsiz, rsiz, xsiz, ysiz, xosiz, yosiz, xtsiz, ytsiz, \
32         xtosiz, ytosiz, csiz \
33         = struct.unpack('>HHIIIIIIIIH', siz[:38])
34     ssiz = [None]*csiz
35     xrsiz = [None]*csiz
36     yrsiz = [None]*csiz
37     for i in range(csiz):
38         ssiz[i], xrsiz[i], yrsiz[i] \
39             = struct.unpack('>BBB', siz[36 + 3 * i:39 + 3 * i])
40 
41     size = (xsiz - xosiz, ysiz - yosiz)
42     if csiz == 1:
43         mode = 'L'
44     elif csiz == 2:
45         mode = 'LA'
46     elif csiz == 3:
47         mode = 'RGB'
48     elif csiz == 4:
49         mode = 'RGBA'
50     else:
51         mode = None
52 
53     return (size, mode)
54 
55 
56 def _parse_jp2_header(fp):
57     """Parse the JP2 header box to extract size, component count and
58     color space information, returning a PIL (size, mode) tuple."""
59 
60     # Find the JP2 header box
61     header = None
62     while True:
63         lbox, tbox = struct.unpack('>I4s', fp.read(8))
64         if lbox == 1:
65             lbox = struct.unpack('>Q', fp.read(8))[0]
66             hlen = 16
67         else:
68             hlen = 8
69 
70         if tbox == b'jp2h':
71             header = fp.read(lbox - hlen)
72             break
73         else:
74             fp.seek(lbox - hlen, os.SEEK_CUR)
75 
76     if header is None:
77         raise SyntaxError('could not find JP2 header')
78 
79     size = None
80     mode = None
81 
82     hio = io.BytesIO(header)
83     while True:
84         lbox, tbox = struct.unpack('>I4s', hio.read(8))
85         if lbox == 1:
86             lbox = struct.unpack('>Q', hio.read(8))[0]
87             hlen = 16
88         else:
89             hlen = 8
90 
91         content = hio.read(lbox - hlen)
92 
93         if tbox == b'ihdr':
94             height, width, nc, bpc, c, unkc, ipr \
95                 = struct.unpack('>IIHBBBB', content)
96             size = (width, height)
97             if unkc:
98                 if nc == 1:
99                     mode = 'L'
100                 elif nc == 2:
101                     mode = 'LA'
102                 elif nc == 3:
103                     mode = 'RGB'
104                 elif nc == 4:
105                     mode = 'RGBA'
106                 break
107         elif tbox == b'colr':
108             meth, prec, approx = struct.unpack('>BBB', content[:3])
109             if meth == 1:
110                 cs = struct.unpack('>I', content[3:7])[0]
111                 if cs == 16:   # sRGB
112                     if nc == 3:
113                         mode = 'RGB'
114                     elif nc == 4:
115                         mode = 'RGBA'
116                     break
117                 elif cs == 17:  # grayscale
118                     if nc == 1:
119                         mode = 'L'
120                     elif nc == 2:
121                         mode = 'LA'
122                     break
123                 elif cs == 18:  # sYCC
124                     if nc == 3:
125                         mode = 'RGB'
126                     elif nc == 4:
127                         mode = 'RGBA'
128                     break
129 
130     return (size, mode)
131 
132 
133 ##
134 # Image plugin for JPEG2000 images.
135 
136 class Jpeg2KImageFile(ImageFile.ImageFile):
137     format = "JPEG2000"
138     format_description = "JPEG 2000 (ISO 15444)"
139 
140     def _open(self):
141         sig = self.fp.read(4)
142         if sig == b'\xff\x4f\xff\x51':
143             self.codec = "j2k"
144             self.size, self.mode = _parse_codestream(self.fp)
145         else:
146             sig = sig + self.fp.read(8)
147 
148             if sig == b'\x00\x00\x00\x0cjP  \x0d\x0a\x87\x0a':
149                 self.codec = "jp2"
150                 self.size, self.mode = _parse_jp2_header(self.fp)
151             else:
152                 raise SyntaxError('not a JPEG 2000 file')
153 
154         if self.size is None or self.mode is None:
155             raise SyntaxError('unable to determine size/mode')
156 
157         self.reduce = 0
158         self.layers = 0
159 
160         fd = -1
161         length = -1
162 
163         if hasattr(self.fp, "fileno"):
164             try:
165                 fd = self.fp.fileno()
166                 length = os.fstat(fd).st_size
167             except:
168                 fd = -1
169         elif hasattr(self.fp, "seek"):
170             try:
171                 pos = f.tell()
172                 f.seek(0, 2)
173                 length = f.tell()
174                 f.seek(pos, 0)
175             except:
176                 length = -1
177         
178         self.tile = [('jpeg2k', (0, 0) + self.size, 0,
179                       (self.codec, self.reduce, self.layers, fd, length))]
180 
181     def load(self):
182         if self.reduce:
183             power = 1 << self.reduce
184             adjust = power >> 1
185             self.size = (int((self.size[0] + adjust) / power),
186                          int((self.size[1] + adjust) / power))
187 
188         if self.tile:
189             # Update the reduce and layers settings
190             t = self.tile[0]
191             t3 = (t[3][0], self.reduce, self.layers, t[3][3], t[3][4])
192             self.tile = [(t[0], (0, 0) + self.size, t[2], t3)]
193 
194         ImageFile.ImageFile.load(self)
195 
196 
197 def _accept(prefix):
198     return (prefix[:4] == b'\xff\x4f\xff\x51'
199             or prefix[:12] == b'\x00\x00\x00\x0cjP  \x0d\x0a\x87\x0a')
200 
201 
202 # ------------------------------------------------------------
203 # Save support
204 
205 def _save(im, fp, filename):
206     if filename.endswith('.j2k'):
207         kind = 'j2k'
208     else:
209         kind = 'jp2'
210 
211     # Get the keyword arguments
212     info = im.encoderinfo
213 
214     offset = info.get('offset', None)
215     tile_offset = info.get('tile_offset', None)
216     tile_size = info.get('tile_size', None)
217     quality_mode = info.get('quality_mode', 'rates')
218     quality_layers = info.get('quality_layers', None)
219     num_resolutions = info.get('num_resolutions', 0)
220     cblk_size = info.get('codeblock_size', None)
221     precinct_size = info.get('precinct_size', None)
222     irreversible = info.get('irreversible', False)
223     progression = info.get('progression', 'LRCP')
224     cinema_mode = info.get('cinema_mode', 'no')
225     fd = -1
226 
227     if hasattr(fp, "fileno"):
228         try:
229             fd = fp.fileno()
230         except:
231             fd = -1
232 
233     im.encoderconfig = (
234         offset,
235         tile_offset,
236         tile_size,
237         quality_mode,
238         quality_layers,
239         num_resolutions,
240         cblk_size,
241         precinct_size,
242         irreversible,
243         progression,
244         cinema_mode,
245         fd
246     )
247 
248     ImageFile._save(im, fp, [('jpeg2k', (0, 0)+im.size, 0, kind)])
249 
250 # ------------------------------------------------------------
251 # Registry stuff
252 
253 Image.register_open('JPEG2000', Jpeg2KImageFile, _accept)
254 Image.register_save('JPEG2000', _save)
255 
256 Image.register_extension('JPEG2000', '.jp2')
257 Image.register_extension('JPEG2000', '.j2k')
258 Image.register_extension('JPEG2000', '.jpc')
259 Image.register_extension('JPEG2000', '.jpf')
260 Image.register_extension('JPEG2000', '.jpx')
261 Image.register_extension('JPEG2000', '.j2c')
262 
263 Image.register_mime('JPEG2000', 'image/jp2')
264 Image.register_mime('JPEG2000', 'image/jpx')
265
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/PIL/Jpeg2KImagePlugin.py b/PIL/Jpeg2KImagePlugin.py
--- a/PIL/Jpeg2KImagePlugin.py
+++ b/PIL/Jpeg2KImagePlugin.py
@@ -40,7 +40,10 @@
 
     size = (xsiz - xosiz, ysiz - yosiz)
     if csiz == 1:
-        mode = 'L'
+        if (yrsiz[0] & 0x7f) > 8:
+            mode = 'I;16'
+        else:
+            mode = 'L'
     elif csiz == 2:
         mode = 'LA'
     elif csiz == 3:
@@ -78,6 +81,7 @@
 
     size = None
     mode = None
+    bpc = None
 
     hio = io.BytesIO(header)
     while True:
@@ -95,7 +99,9 @@
                 = struct.unpack('>IIHBBBB', content)
             size = (width, height)
             if unkc:
-                if nc == 1:
+                if nc == 1 and (bpc & 0x7f) > 8:
+                    mode = 'I;16'
+                elif nc == 1:
                     mode = 'L'
                 elif nc == 2:
                     mode = 'LA'
@@ -109,13 +115,19 @@
             if meth == 1:
                 cs = struct.unpack('>I', content[3:7])[0]
                 if cs == 16:   # sRGB
-                    if nc == 3:
+                    if nc == 1 and (bpc & 0x7f) > 8:
+                        mode = 'I;16'
+                    elif nc == 1:
+                        mode = 'L'
+                    elif nc == 3:
                         mode = 'RGB'
                     elif nc == 4:
                         mode = 'RGBA'
                     break
                 elif cs == 17:  # grayscale
-                    if nc == 1:
+                    if nc == 1 and (bpc & 0x7f) > 8:
+                        mode = 'I;16'
+                    elif nc == 1:
                         mode = 'L'
                     elif nc == 2:
                         mode = 'LA'
@@ -129,10 +141,10 @@
 
     return (size, mode)
 
-
 ##
 # Image plugin for JPEG2000 images.
 
+
 class Jpeg2KImageFile(ImageFile.ImageFile):
     format = "JPEG2000"
     format_description = "JPEG 2000 (ISO 15444)"
@@ -174,7 +186,7 @@
                 f.seek(pos, 0)
             except:
                 length = -1
-        
+
         self.tile = [('jpeg2k', (0, 0) + self.size, 0,
                       (self.codec, self.reduce, self.layers, fd, length))]

{"golden_diff": "diff --git a/PIL/Jpeg2KImagePlugin.py b/PIL/Jpeg2KImagePlugin.py\n--- a/PIL/Jpeg2KImagePlugin.py\n+++ b/PIL/Jpeg2KImagePlugin.py\n@@ -40,7 +40,10 @@\n \n     size = (xsiz - xosiz, ysiz - yosiz)\n     if csiz == 1:\n-        mode = 'L'\n+        if (yrsiz[0] & 0x7f) > 8:\n+            mode = 'I;16'\n+        else:\n+            mode = 'L'\n     elif csiz == 2:\n         mode = 'LA'\n     elif csiz == 3:\n@@ -78,6 +81,7 @@\n \n     size = None\n     mode = None\n+    bpc = None\n \n     hio = io.BytesIO(header)\n     while True:\n@@ -95,7 +99,9 @@\n                 = struct.unpack('>IIHBBBB', content)\n             size = (width, height)\n             if unkc:\n-                if nc == 1:\n+                if nc == 1 and (bpc & 0x7f) > 8:\n+                    mode = 'I;16'\n+                elif nc == 1:\n                     mode = 'L'\n                 elif nc == 2:\n                     mode = 'LA'\n@@ -109,13 +115,19 @@\n             if meth == 1:\n                 cs = struct.unpack('>I', content[3:7])[0]\n                 if cs == 16:   # sRGB\n-                    if nc == 3:\n+                    if nc == 1 and (bpc & 0x7f) > 8:\n+                        mode = 'I;16'\n+                    elif nc == 1:\n+                        mode = 'L'\n+                    elif nc == 3:\n                         mode = 'RGB'\n                     elif nc == 4:\n                         mode = 'RGBA'\n                     break\n                 elif cs == 17:  # grayscale\n-                    if nc == 1:\n+                    if nc == 1 and (bpc & 0x7f) > 8:\n+                        mode = 'I;16'\n+                    elif nc == 1:\n                         mode = 'L'\n                     elif nc == 2:\n                         mode = 'LA'\n@@ -129,10 +141,10 @@\n \n     return (size, mode)\n \n-\n ##\n # Image plugin for JPEG2000 images.\n \n+\n class Jpeg2KImageFile(ImageFile.ImageFile):\n     format = \"JPEG2000\"\n     format_description = \"JPEG 2000 (ISO 15444)\"\n@@ -174,7 +186,7 @@\n                 f.seek(pos, 0)\n             except:\n                 length = -1\n-        \n+\n         self.tile = [('jpeg2k', (0, 0) + self.size, 0,\n                       (self.codec, self.reduce, self.layers, fd, length))]\n", "issue": "Add 16bit encode/decode to JPEG2K (WIP)\nAdd the ability to write 16bit JPEG2k Images (for DICOM medical images).\n\nI'd trying to add a decoder too but I couldn't quite figure it out.  Here's my dumb test case:\n\n``` python\nimport numpy as np\nfrom PIL import Image\n\narr = np.zeros((64, 96), dtype=np.uint16)\narr[16:64, 0:32] = 300\n\nimg = Image.fromarray(arr, 'I;16')\nimg.save('grr.j2k')  # Works\n\nimg2 = Image.open('grr.j2k')\narr2 = np.array(img2)\n\nnp.testing.assert_almost_equal(arr, arr2)  # Fails\n```\n\nThoughts?\n\n", "before_files": [{"content": "#\n# The Python Imaging Library\n# $Id$\n#\n# JPEG2000 file handling\n#\n# History:\n# 2014-03-12 ajh  Created\n#\n# Copyright (c) 2014 Coriolis Systems Limited\n# Copyright (c) 2014 Alastair Houghton\n#\n# See the README file for information on usage and redistribution.\n#\n\n__version__ = \"0.1\"\n\nfrom PIL import Image, ImageFile\nimport struct\nimport os\nimport io\n\n\ndef _parse_codestream(fp):\n    \"\"\"Parse the JPEG 2000 codestream to extract the size and component\n    count from the SIZ marker segment, returning a PIL (size, mode) tuple.\"\"\"\n\n    hdr = fp.read(2)\n    lsiz = struct.unpack('>H', hdr)[0]\n    siz = hdr + fp.read(lsiz - 2)\n    lsiz, rsiz, xsiz, ysiz, xosiz, yosiz, xtsiz, ytsiz, \\\n        xtosiz, ytosiz, csiz \\\n        = struct.unpack('>HHIIIIIIIIH', siz[:38])\n    ssiz = [None]*csiz\n    xrsiz = [None]*csiz\n    yrsiz = [None]*csiz\n    for i in range(csiz):\n        ssiz[i], xrsiz[i], yrsiz[i] \\\n            = struct.unpack('>BBB', siz[36 + 3 * i:39 + 3 * i])\n\n    size = (xsiz - xosiz, ysiz - yosiz)\n    if csiz == 1:\n        mode = 'L'\n    elif csiz == 2:\n        mode = 'LA'\n    elif csiz == 3:\n        mode = 'RGB'\n    elif csiz == 4:\n        mode = 'RGBA'\n    else:\n        mode = None\n\n    return (size, mode)\n\n\ndef _parse_jp2_header(fp):\n    \"\"\"Parse the JP2 header box to extract size, component count and\n    color space information, returning a PIL (size, mode) tuple.\"\"\"\n\n    # Find the JP2 header box\n    header = None\n    while True:\n        lbox, tbox = struct.unpack('>I4s', fp.read(8))\n        if lbox == 1:\n            lbox = struct.unpack('>Q', fp.read(8))[0]\n            hlen = 16\n        else:\n            hlen = 8\n\n        if tbox == b'jp2h':\n            header = fp.read(lbox - hlen)\n            break\n        else:\n            fp.seek(lbox - hlen, os.SEEK_CUR)\n\n    if header is None:\n        raise SyntaxError('could not find JP2 header')\n\n    size = None\n    mode = None\n\n    hio = io.BytesIO(header)\n    while True:\n        lbox, tbox = struct.unpack('>I4s', hio.read(8))\n        if lbox == 1:\n            lbox = struct.unpack('>Q', hio.read(8))[0]\n            hlen = 16\n        else:\n            hlen = 8\n\n        content = hio.read(lbox - hlen)\n\n        if tbox == b'ihdr':\n            height, width, nc, bpc, c, unkc, ipr \\\n                = struct.unpack('>IIHBBBB', content)\n            size = (width, height)\n            if unkc:\n                if nc == 1:\n                    mode = 'L'\n                elif nc == 2:\n                    mode = 'LA'\n                elif nc == 3:\n                    mode = 'RGB'\n                elif nc == 4:\n                    mode = 'RGBA'\n                break\n        elif tbox == b'colr':\n            meth, prec, approx = struct.unpack('>BBB', content[:3])\n            if meth == 1:\n                cs = struct.unpack('>I', content[3:7])[0]\n                if cs == 16:   # sRGB\n                    if nc == 3:\n                        mode = 'RGB'\n                    elif nc == 4:\n                        mode = 'RGBA'\n                    break\n                elif cs == 17:  # grayscale\n                    if nc == 1:\n                        mode = 'L'\n                    elif nc == 2:\n                        mode = 'LA'\n                    break\n                elif cs == 18:  # sYCC\n                    if nc == 3:\n                        mode = 'RGB'\n                    elif nc == 4:\n                        mode = 'RGBA'\n                    break\n\n    return (size, mode)\n\n\n##\n# Image plugin for JPEG2000 images.\n\nclass Jpeg2KImageFile(ImageFile.ImageFile):\n    format = \"JPEG2000\"\n    format_description = \"JPEG 2000 (ISO 15444)\"\n\n    def _open(self):\n        sig = self.fp.read(4)\n        if sig == b'\\xff\\x4f\\xff\\x51':\n            self.codec = \"j2k\"\n            self.size, self.mode = _parse_codestream(self.fp)\n        else:\n            sig = sig + self.fp.read(8)\n\n            if sig == b'\\x00\\x00\\x00\\x0cjP  \\x0d\\x0a\\x87\\x0a':\n                self.codec = \"jp2\"\n                self.size, self.mode = _parse_jp2_header(self.fp)\n            else:\n                raise SyntaxError('not a JPEG 2000 file')\n\n        if self.size is None or self.mode is None:\n            raise SyntaxError('unable to determine size/mode')\n\n        self.reduce = 0\n        self.layers = 0\n\n        fd = -1\n        length = -1\n\n        if hasattr(self.fp, \"fileno\"):\n            try:\n                fd = self.fp.fileno()\n                length = os.fstat(fd).st_size\n            except:\n                fd = -1\n        elif hasattr(self.fp, \"seek\"):\n            try:\n                pos = f.tell()\n                f.seek(0, 2)\n                length = f.tell()\n                f.seek(pos, 0)\n            except:\n                length = -1\n        \n        self.tile = [('jpeg2k', (0, 0) + self.size, 0,\n                      (self.codec, self.reduce, self.layers, fd, length))]\n\n    def load(self):\n        if self.reduce:\n            power = 1 << self.reduce\n            adjust = power >> 1\n            self.size = (int((self.size[0] + adjust) / power),\n                         int((self.size[1] + adjust) / power))\n\n        if self.tile:\n            # Update the reduce and layers settings\n            t = self.tile[0]\n            t3 = (t[3][0], self.reduce, self.layers, t[3][3], t[3][4])\n            self.tile = [(t[0], (0, 0) + self.size, t[2], t3)]\n\n        ImageFile.ImageFile.load(self)\n\n\ndef _accept(prefix):\n    return (prefix[:4] == b'\\xff\\x4f\\xff\\x51'\n            or prefix[:12] == b'\\x00\\x00\\x00\\x0cjP  \\x0d\\x0a\\x87\\x0a')\n\n\n# ------------------------------------------------------------\n# Save support\n\ndef _save(im, fp, filename):\n    if filename.endswith('.j2k'):\n        kind = 'j2k'\n    else:\n        kind = 'jp2'\n\n    # Get the keyword arguments\n    info = im.encoderinfo\n\n    offset = info.get('offset', None)\n    tile_offset = info.get('tile_offset', None)\n    tile_size = info.get('tile_size', None)\n    quality_mode = info.get('quality_mode', 'rates')\n    quality_layers = info.get('quality_layers', None)\n    num_resolutions = info.get('num_resolutions', 0)\n    cblk_size = info.get('codeblock_size', None)\n    precinct_size = info.get('precinct_size', None)\n    irreversible = info.get('irreversible', False)\n    progression = info.get('progression', 'LRCP')\n    cinema_mode = info.get('cinema_mode', 'no')\n    fd = -1\n\n    if hasattr(fp, \"fileno\"):\n        try:\n            fd = fp.fileno()\n        except:\n            fd = -1\n\n    im.encoderconfig = (\n        offset,\n        tile_offset,\n        tile_size,\n        quality_mode,\n        quality_layers,\n        num_resolutions,\n        cblk_size,\n        precinct_size,\n        irreversible,\n        progression,\n        cinema_mode,\n        fd\n    )\n\n    ImageFile._save(im, fp, [('jpeg2k', (0, 0)+im.size, 0, kind)])\n\n# ------------------------------------------------------------\n# Registry stuff\n\nImage.register_open('JPEG2000', Jpeg2KImageFile, _accept)\nImage.register_save('JPEG2000', _save)\n\nImage.register_extension('JPEG2000', '.jp2')\nImage.register_extension('JPEG2000', '.j2k')\nImage.register_extension('JPEG2000', '.jpc')\nImage.register_extension('JPEG2000', '.jpf')\nImage.register_extension('JPEG2000', '.jpx')\nImage.register_extension('JPEG2000', '.j2c')\n\nImage.register_mime('JPEG2000', 'image/jp2')\nImage.register_mime('JPEG2000', 'image/jpx')\n", "path": "PIL/Jpeg2KImagePlugin.py"}], "after_files": [{"content": "#\n# The Python Imaging Library\n# $Id$\n#\n# JPEG2000 file handling\n#\n# History:\n# 2014-03-12 ajh  Created\n#\n# Copyright (c) 2014 Coriolis Systems Limited\n# Copyright (c) 2014 Alastair Houghton\n#\n# See the README file for information on usage and redistribution.\n#\n\n__version__ = \"0.1\"\n\nfrom PIL import Image, ImageFile\nimport struct\nimport os\nimport io\n\n\ndef _parse_codestream(fp):\n    \"\"\"Parse the JPEG 2000 codestream to extract the size and component\n    count from the SIZ marker segment, returning a PIL (size, mode) tuple.\"\"\"\n\n    hdr = fp.read(2)\n    lsiz = struct.unpack('>H', hdr)[0]\n    siz = hdr + fp.read(lsiz - 2)\n    lsiz, rsiz, xsiz, ysiz, xosiz, yosiz, xtsiz, ytsiz, \\\n        xtosiz, ytosiz, csiz \\\n        = struct.unpack('>HHIIIIIIIIH', siz[:38])\n    ssiz = [None]*csiz\n    xrsiz = [None]*csiz\n    yrsiz = [None]*csiz\n    for i in range(csiz):\n        ssiz[i], xrsiz[i], yrsiz[i] \\\n            = struct.unpack('>BBB', siz[36 + 3 * i:39 + 3 * i])\n\n    size = (xsiz - xosiz, ysiz - yosiz)\n    if csiz == 1:\n        if (yrsiz[0] & 0x7f) > 8:\n            mode = 'I;16'\n        else:\n            mode = 'L'\n    elif csiz == 2:\n        mode = 'LA'\n    elif csiz == 3:\n        mode = 'RGB'\n    elif csiz == 4:\n        mode = 'RGBA'\n    else:\n        mode = None\n\n    return (size, mode)\n\n\ndef _parse_jp2_header(fp):\n    \"\"\"Parse the JP2 header box to extract size, component count and\n    color space information, returning a PIL (size, mode) tuple.\"\"\"\n\n    # Find the JP2 header box\n    header = None\n    while True:\n        lbox, tbox = struct.unpack('>I4s', fp.read(8))\n        if lbox == 1:\n            lbox = struct.unpack('>Q', fp.read(8))[0]\n            hlen = 16\n        else:\n            hlen = 8\n\n        if tbox == b'jp2h':\n            header = fp.read(lbox - hlen)\n            break\n        else:\n            fp.seek(lbox - hlen, os.SEEK_CUR)\n\n    if header is None:\n        raise SyntaxError('could not find JP2 header')\n\n    size = None\n    mode = None\n    bpc = None\n\n    hio = io.BytesIO(header)\n    while True:\n        lbox, tbox = struct.unpack('>I4s', hio.read(8))\n        if lbox == 1:\n            lbox = struct.unpack('>Q', hio.read(8))[0]\n            hlen = 16\n        else:\n            hlen = 8\n\n        content = hio.read(lbox - hlen)\n\n        if tbox == b'ihdr':\n            height, width, nc, bpc, c, unkc, ipr \\\n                = struct.unpack('>IIHBBBB', content)\n            size = (width, height)\n            if unkc:\n                if nc == 1 and (bpc & 0x7f) > 8:\n                    mode = 'I;16'\n                elif nc == 1:\n                    mode = 'L'\n                elif nc == 2:\n                    mode = 'LA'\n                elif nc == 3:\n                    mode = 'RGB'\n                elif nc == 4:\n                    mode = 'RGBA'\n                break\n        elif tbox == b'colr':\n            meth, prec, approx = struct.unpack('>BBB', content[:3])\n            if meth == 1:\n                cs = struct.unpack('>I', content[3:7])[0]\n                if cs == 16:   # sRGB\n                    if nc == 1 and (bpc & 0x7f) > 8:\n                        mode = 'I;16'\n                    elif nc == 1:\n                        mode = 'L'\n                    elif nc == 3:\n                        mode = 'RGB'\n                    elif nc == 4:\n                        mode = 'RGBA'\n                    break\n                elif cs == 17:  # grayscale\n                    if nc == 1 and (bpc & 0x7f) > 8:\n                        mode = 'I;16'\n                    elif nc == 1:\n                        mode = 'L'\n                    elif nc == 2:\n                        mode = 'LA'\n                    break\n                elif cs == 18:  # sYCC\n                    if nc == 3:\n                        mode = 'RGB'\n                    elif nc == 4:\n                        mode = 'RGBA'\n                    break\n\n    return (size, mode)\n\n##\n# Image plugin for JPEG2000 images.\n\n\nclass Jpeg2KImageFile(ImageFile.ImageFile):\n    format = \"JPEG2000\"\n    format_description = \"JPEG 2000 (ISO 15444)\"\n\n    def _open(self):\n        sig = self.fp.read(4)\n        if sig == b'\\xff\\x4f\\xff\\x51':\n            self.codec = \"j2k\"\n            self.size, self.mode = _parse_codestream(self.fp)\n        else:\n            sig = sig + self.fp.read(8)\n\n            if sig == b'\\x00\\x00\\x00\\x0cjP  \\x0d\\x0a\\x87\\x0a':\n                self.codec = \"jp2\"\n                self.size, self.mode = _parse_jp2_header(self.fp)\n            else:\n                raise SyntaxError('not a JPEG 2000 file')\n\n        if self.size is None or self.mode is None:\n            raise SyntaxError('unable to determine size/mode')\n\n        self.reduce = 0\n        self.layers = 0\n\n        fd = -1\n        length = -1\n\n        if hasattr(self.fp, \"fileno\"):\n            try:\n                fd = self.fp.fileno()\n                length = os.fstat(fd).st_size\n            except:\n                fd = -1\n        elif hasattr(self.fp, \"seek\"):\n            try:\n                pos = f.tell()\n                f.seek(0, 2)\n                length = f.tell()\n                f.seek(pos, 0)\n            except:\n                length = -1\n\n        self.tile = [('jpeg2k', (0, 0) + self.size, 0,\n                      (self.codec, self.reduce, self.layers, fd, length))]\n\n    def load(self):\n        if self.reduce:\n            power = 1 << self.reduce\n            adjust = power >> 1\n            self.size = (int((self.size[0] + adjust) / power),\n                         int((self.size[1] + adjust) / power))\n\n        if self.tile:\n            # Update the reduce and layers settings\n            t = self.tile[0]\n            t3 = (t[3][0], self.reduce, self.layers, t[3][3], t[3][4])\n            self.tile = [(t[0], (0, 0) + self.size, t[2], t3)]\n\n        ImageFile.ImageFile.load(self)\n\n\ndef _accept(prefix):\n    return (prefix[:4] == b'\\xff\\x4f\\xff\\x51'\n            or prefix[:12] == b'\\x00\\x00\\x00\\x0cjP  \\x0d\\x0a\\x87\\x0a')\n\n\n# ------------------------------------------------------------\n# Save support\n\ndef _save(im, fp, filename):\n    if filename.endswith('.j2k'):\n        kind = 'j2k'\n    else:\n        kind = 'jp2'\n\n    # Get the keyword arguments\n    info = im.encoderinfo\n\n    offset = info.get('offset', None)\n    tile_offset = info.get('tile_offset', None)\n    tile_size = info.get('tile_size', None)\n    quality_mode = info.get('quality_mode', 'rates')\n    quality_layers = info.get('quality_layers', None)\n    num_resolutions = info.get('num_resolutions', 0)\n    cblk_size = info.get('codeblock_size', None)\n    precinct_size = info.get('precinct_size', None)\n    irreversible = info.get('irreversible', False)\n    progression = info.get('progression', 'LRCP')\n    cinema_mode = info.get('cinema_mode', 'no')\n    fd = -1\n\n    if hasattr(fp, \"fileno\"):\n        try:\n            fd = fp.fileno()\n        except:\n            fd = -1\n\n    im.encoderconfig = (\n        offset,\n        tile_offset,\n        tile_size,\n        quality_mode,\n        quality_layers,\n        num_resolutions,\n        cblk_size,\n        precinct_size,\n        irreversible,\n        progression,\n        cinema_mode,\n        fd\n    )\n\n    ImageFile._save(im, fp, [('jpeg2k', (0, 0)+im.size, 0, kind)])\n\n# ------------------------------------------------------------\n# Registry stuff\n\nImage.register_open('JPEG2000', Jpeg2KImageFile, _accept)\nImage.register_save('JPEG2000', _save)\n\nImage.register_extension('JPEG2000', '.jp2')\nImage.register_extension('JPEG2000', '.j2k')\nImage.register_extension('JPEG2000', '.jpc')\nImage.register_extension('JPEG2000', '.jpf')\nImage.register_extension('JPEG2000', '.jpx')\nImage.register_extension('JPEG2000', '.j2c')\n\nImage.register_mime('JPEG2000', 'image/jp2')\nImage.register_mime('JPEG2000', 'image/jpx')\n", "path": "PIL/Jpeg2KImagePlugin.py"}]}