docs: def _read_openjpeg(self, rlevel=0, verbose=False, area=None):
          """Read a JPEG 2000 image using libopenjpeg.
  
          Parameters
          ----------
          rlevel : int, optional
              Factor by which to rlevel output resolution.  Use -1 to get the
              lowest resolution thumbnail.
          verbose : bool, optional
              Print informational messages produced by the OpenJPEG library.
          area : tuple, optional
              Specifies decoding image area,
              (first_row, first_col, last_row, last_col)
  
          Returns
          -------
          ndarray
              The image data.
  
          Raises
          ------
          RuntimeError
              If the image has differing subsample factors.
          """
          self._subsampling_sanity_check()
  
          self._populate_dparams(rlevel)
  
          with ExitStack() as stack:
              try:
                  self._dparams.decod_format = self._codec_format
  
                  dinfo = opj.create_decompress(self._dparams.decod_format)
  
                  event_mgr = opj.EventMgrType()
                  handler = ctypes.cast(_INFO_CALLBACK, ctypes.c_void_p)
                  event_mgr.info_handler = handler if self.verbose else None
                  event_mgr.warning_handler = ctypes.cast(_WARNING_CALLBACK,
                                                          ctypes.c_void_p)
                  event_mgr.error_handler = ctypes.cast(_ERROR_CALLBACK,
                                                        ctypes.c_void_p)
                  opj.set_event_mgr(dinfo, ctypes.byref(event_mgr))
  
                  opj.setup_decoder(dinfo, self._dparams)
  
                  with open(self.filename, 'rb') as fptr:
                      src = fptr.read()
                  cio = opj.cio_open(dinfo, src)
  
                  raw_image = opj.decode(dinfo, cio)
  
                  stack.callback(opj.image_destroy, raw_image)
                  stack.callback(opj.destroy_decompress, dinfo)
                  stack.callback(opj.cio_close, cio)
  
                  image = self._extract_image(raw_image)
  
              except ValueError:
                  opj2.check_error(0)
  
          if area is not None:
              x0, y0, x1, y1 = area
              extent = 2 ** rlevel
  
              area = [int(round(float(x) / extent + 2 ** -20)) for x in area]
              rows = slice(area[0], area[2], None)
              cols = slice(area[1], area[3], None)
              image = image[rows, cols]
  
          return image