code: def pil_get_frame(
      im, is_gray=None, as_gray=None, mode=None, dtype=None
  ):
      """
      is_gray: Whether the image *is* gray (by inspecting its palette).
      as_gray: Whether the resulting image must be converted to gaey.
      mode: The mode to convert to.
      """
  
      if is_gray is None:
          is_gray = _palette_is_grayscale(im)
  
      frame = im
  
      # Convert ...
      if mode is not None:
          # Mode is explicitly given ...
          if mode != im.mode:
              frame = im.convert(mode)
      elif as_gray:
          pass  # don't do any auto-conversions (but do the explicit one above)
      elif im.mode == "P" and is_gray:
          # Paletted images that are already gray by their palette
          # are converted so that the resulting numpy array is 2D.
          frame = im.convert("L")
      elif im.mode == "P":
          # Paletted images are converted to RGB/RGBA. We jump some loops to make
          # this work well.
          if im.info.get("transparency", None) is not None:
              # Let Pillow apply the transparency, see issue #210 and #246
              frame = im.convert("RGBA")
          elif im.palette.mode in ("RGB", "RGBA"):
              # We can do this ourselves. Pillow seems to sometimes screw
              # this up if a  multi-gif has a palette for each frame ...
              # Create palette array
              p = np.frombuffer(im.palette.getdata()[1], np.uint8)
              # Restore the raw mode that was saved to be used to parse the palette
              if hasattr(im.palette, "rawmode_saved"):
                  im.palette.rawmode = im.palette.rawmode_saved
              mode = (
                  im.palette.rawmode
                  if im.palette.rawmode
                  else im.palette.mode
              )
              nchannels = len(mode)
              # Shape it.
              p.shape = -1, nchannels
              if p.shape[1] == 3 or (
                  p.shape[1] == 4 and mode[-1] == "X"
              ):
                  p = np.column_stack(
                      (p[:, :3], 255 * np.ones(p.shape[0], p.dtype))
                  )
              # Swap the axes if the mode is in BGR and not RGB
              if mode.startswith("BGR"):
                  p = (
                      p[:, [2, 1, 0]]
                      if p.shape[1] == 3
                      else p[:, [2, 1, 0, 3]]
                  )
              # Apply palette
              frame_paletted = np.array(im, np.uint8)
              try:
                  frame = p[frame_paletted]
              except Exception:
                  # Ok, let PIL do it. The introduction of the branch that
                  # tests `im.info['transparency']` should make this happen
                  # much less often, but let's keep it, to be safe.
                  frame = im.convert("RGBA")
          else:
              # Let Pillow do it. Unlinke skimage, we always convert
              # to RGBA; palettes can be RGBA.
              if (
                  True
              ):  # im.format == 'PNG' and 'transparency' in im.info:
                  frame = im.convert("RGBA")
              else:
                  frame = im.convert("RGB")
      elif "A" in im.mode:
          frame = im.convert("RGBA")
      elif im.mode == "CMYK":
          frame = im.convert("RGB")
      elif im.format == "GIF" and im.mode == "RGB":
          # pillow9 returns RGBA images for subsequent frames so that it can deal
          # with multi-frame GIF that use frame-level palettes and don't dispose
          # all areas.
  
          # For backwards compatibility, we promote everything to RGBA.
          frame = im.convert("RGBA")
  
      # Apply a post-convert if necessary
      if as_gray:
          frame = frame.convert("F")  # Scipy compat
      elif not isinstance(frame, np.ndarray) and frame.mode == "1":
          # Workaround for crash in PIL. When im is 1-bit, the call array(im)
          # can cause a segfault, or generate garbage. See
          # https://github.com/scipy/scipy/issues/2138 and
          # https://github.com/python-pillow/Pillow/issues/350.
          #
          # This converts im from a 1-bit image to an 8-bit image.
          frame = frame.convert("L")
  
      # Convert to numpy array
      if im.mode.startswith("I;16"):
          # e.g. in16 PNG's
          shape = im.size
          dtype = ">u2" if im.mode.endswith("B") else "<u2"
          if "S" in im.mode:
              dtype = dtype.replace("u", "i")
          frame = np.frombuffer(frame.tobytes(), dtype).copy()
          frame.shape = shape[::-1]
      else:
          # Use uint16 for PNG's in mode I
          if im.format == "PNG" and im.mode == "I" and dtype is None:
              dtype = "uint16"
          frame = np.array(frame, dtype=dtype)
  
      return frame
  
imports: import logging
  import threading
  import numpy
  from ..core import Format, image_as_uint
  from ..core.request import URI_FILE, URI_BYTES
  from .pillowmulti import GIFFormat, TIFFFormat
label_desc: Use image node_id 4 for calling a global function with example usage: pil_get_frame(im, is_gray, as_gray, mode, dtype) and returns: frame