code: def _save(im, fp, filename, chunk=putchunk):
      # save an image to disk (called by the save method)
  
      mode = im.mode
  
      if mode == "P":
          #
          # attempt to minimize storage requirements for palette images
          if "bits" in im.encoderinfo:
              # number of bits specified by user
              colors = 1 << im.encoderinfo["bits"]
          else:
              # check palette contents
              if im.palette:
                  colors = max(
                      min(len(im.palette.getdata()[1]) // 3, 256), 2
                  )
              else:
                  colors = 256
  
          if colors <= 2:
              bits = 1
          elif colors <= 4:
              bits = 2
          elif colors <= 16:
              bits = 4
          else:
              bits = 8
          if bits != 8:
              mode = "%s;%d" % (mode, bits)
  
      # encoder options
      im.encoderconfig = (
          im.encoderinfo.get("optimize", False),
          im.encoderinfo.get("compress_level", -1),
          im.encoderinfo.get("compress_type", -1),
          im.encoderinfo.get("dictionary", b""),
      )
  
      # get the corresponding PNG mode
      try:
          rawmode, mode = _OUTMODES[mode]
      except KeyError:
          raise IOError("cannot write mode %s as PNG" % mode)
  
      #
      # write minimal PNG file
  
      fp.write(_MAGIC)
  
      chunk(
          fp,
          b"IHDR",
          o32(im.size[0]),  # 0: size
          o32(im.size[1]),
          mode,  # 8: depth/type
          b"\0",  # 10: compression
          b"\0",  # 11: filter category
          b"\0",  # 12: interlace flag
      )
  
      chunks = [b"cHRM", b"gAMA", b"sBIT", b"sRGB", b"tIME"]
  
      icc = im.encoderinfo.get(
          "icc_profile", im.info.get("icc_profile")
      )
      if icc:
          # ICC profile
          # according to PNG spec, the iCCP chunk contains:
          # Profile name  1-79 bytes (character string)
          # Null separator        1 byte (null character)
          # Compression method    1 byte (0)
          # Compressed profile    n bytes (zlib with deflate compression)
          name = b"ICC Profile"
          data = name + b"\0\0" + zlib.compress(icc)
          chunk(fp, b"iCCP", data)
  
          # You must either have sRGB or iCCP.
          # Disallow sRGB chunks when an iCCP-chunk has been emitted.
          chunks.remove(b"sRGB")
  
      info = im.encoderinfo.get("pnginfo")
      if info:
          chunks_multiple_allowed = [b"sPLT", b"iTXt", b"tEXt", b"zTXt"]
          for cid, data in info.chunks:
              if cid in chunks:
                  chunks.remove(cid)
                  chunk(fp, cid, data)
              elif cid in chunks_multiple_allowed:
                  chunk(fp, cid, data)
  
      if im.mode == "P":
          palette_byte_number = (2**bits) * 3
          palette_bytes = im.im.getpalette("RGB")[:palette_byte_number]
          while len(palette_bytes) < palette_byte_number:
              palette_bytes += b"\0"
          chunk(fp, b"PLTE", palette_bytes)
  
      transparency = im.encoderinfo.get(
          "transparency", im.info.get("transparency", None)
      )
  
      if transparency or transparency == 0:
          if im.mode == "P":
              # limit to actual palette size
              alpha_bytes = 2**bits
              if isinstance(transparency, bytes):
                  chunk(fp, b"tRNS", transparency[:alpha_bytes])
              else:
                  transparency = max(0, min(255, transparency))
                  alpha = b"\xFF" * transparency + b"\0"
                  chunk(fp, b"tRNS", alpha[:alpha_bytes])
          elif im.mode in ("1", "L", "I"):
              transparency = max(0, min(65535, transparency))
              chunk(fp, b"tRNS", o16(transparency))
          elif im.mode == "RGB":
              red, green, blue = transparency
              chunk(fp, b"tRNS", o16(red) + o16(green) + o16(blue))
          else:
              if "transparency" in im.encoderinfo:
                  # don't bother with transparency if it's an RGBA
                  # and it's in the info dict. It's probably just stale.
                  raise IOError("cannot use transparency for this mode")
      else:
          if im.mode == "P" and im.im.getpalettemode() == "RGBA":
              alpha = im.im.getpalette("RGBA", "A")
              alpha_bytes = 2**bits
              chunk(fp, b"tRNS", alpha[:alpha_bytes])
  
      dpi = im.encoderinfo.get("dpi")
      if dpi:
          chunk(
              fp,
              b"pHYs",
              o32(int(dpi[0] / 0.0254 + 0.5)),
              o32(int(dpi[1] / 0.0254 + 0.5)),
              b"\x01",
          )
  
      info = im.encoderinfo.get("pnginfo")
      if info:
          chunks = [b"bKGD", b"hIST"]
          for cid, data in info.chunks:
              if cid in chunks:
                  chunks.remove(cid)
                  chunk(fp, cid, data)
  
      exif = im.encoderinfo.get("exif", im.info.get("exif"))
      if exif:
          if isinstance(exif, Image.Exif):
              exif = exif.tobytes(8)
          if exif.startswith(b"Exif\x00\x00"):
              exif = exif[6:]
          chunk(fp, b"eXIf", exif)
  
      ImageFile._save(
          im, _idat(fp, chunk), [("zip", (0, 0) + im.size, 0, rawmode)]
      )
  
      chunk(fp, b"IEND", b"")
  
      if hasattr(fp, "flush"):
          fp.flush()
  
imports: import logging
  import re
  import struct
  import zlib
  from .None import Image, ImageFile, ImagePalette
  from ._binary import i8, i16be, i32be, o16be, o32be
  from ._util import py3
label_desc: Use image node_id 5 for calling a global function with example usage: _save(im, fp, filename, chunk) without return types