docs: def _png(code, version, file, scale=1, module_color=(0, 0, 0, 255),
           background=(255, 255, 255, 255), quiet_zone=4, debug=False):
      """See: pyqrcode.QRCode.png()
  
      This function was abstracted away from QRCode to allow for the output of
      QR codes during the build process, i.e. for debugging. It works
      just the same except you must specify the code's version. This is needed
      to calculate the PNG's size.
  
      This method will write the given file out as a PNG file. Note, it
      depends on the PyPNG module to do this.
  
      :param module_color: Color of the QR code (default: ``(0, 0, 0, 255)`` (black))
      :param background: Optional background color. If set to ``None`` the PNG
              will have a transparent background.
              (default: ``(255, 255, 255, 255)`` (white))
      :param quiet_zone: Border around the QR code (also known as quiet zone)
              (default: ``4``). Set to zero (``0``) if the code shouldn't
              have a border.
      :param debug: Inidicates if errors in the QR code should be added (as red
              modules) to the output (default: ``False``).
      """
      import png
      
      # Coerce scale parameter into an integer
      try:
          scale = int(scale)
      except ValueError:
          raise ValueError('The scale parameter must be an integer')
  
      def scale_code(size):
          """To perform the scaling we need to inflate the number of bits.
          The PNG library expects all of the bits when it draws the PNG.
          Effectively, we double, tripple, etc. the number of columns and
          the number of rows.
          """
          # This is one row's worth of each possible module
          # PNG's use 0 for black and 1 for white, this is the
          # reverse of the QR standard
          black = [0] * scale
          white = [1] * scale
  
          # Tuple to lookup colors
          # The 3rd color is the module_color unless "debug" is enabled
          colors = (white, black, (([2] * scale) if debug else black))
  
          # Whitespace added on the left and right side
          border_module = white * quiet_zone
          # This is the row to show up at the top and bottom border
          border_row = [[1] * size] * scale * quiet_zone
  
          # This will hold the final PNG's bits
          bits = []
  
          # Add scale rows before the code as a border,
          # as per the standard
          bits.extend(border_row)
  
          # Add each row of the to the final PNG bits
          for row in code:
              tmp_row = []
  
              # Add one all white module to the beginning
              # to create the vertical border
              tmp_row.extend(border_module)
  
              # Go through each bit in the code
              for bit in row:
                  # Use the standard color or the "debug" color
                  tmp_row.extend(colors[(bit if bit in (0, 1) else 2)])
  
              # Add one all white module to the end
              # to create the vertical border
              tmp_row.extend(border_module)
  
              # Copy each row scale times
              for n in range(scale):
                  bits.append(tmp_row)
  
          # Add the bottom border
          bits.extend(border_row)
  
          return bits
  
      def png_pallete_color(color):
          """This creates a palette color from a list or tuple. The list or
          tuple must be of length 3 (for rgb) or 4 (for rgba). The values
          must be between 0 and 255. Note rgb colors will be given an added
          alpha component set to 255.
  
          The pallete color is represented as a list, this is what is returned.
          """
          if color is None:
              return ()
          if not isinstance(color, (tuple, list)):
              r, g, b = _hex_to_rgb(color)
              return r, g, b, 255
          rgba = []
          if not (3 <= len(color) <= 4):
              raise ValueError('Colors must be a list or tuple of length '
                               ' 3 or 4. You passed in "{0}".'.format(color))
          for c in color:
              c = int(c)
              if 0 <= c <= 255:
                  rgba.append(int(c))
              else:
                  raise ValueError('Color components must be between 0 and 255')
          # Make all colors have an alpha channel
          if len(rgba) == 3:
              rgba.append(255)
          return tuple(rgba)
  
      if module_color is None:
          raise ValueError('The module_color must not be None')
  
      bitdepth = 1
      # foreground aka module color
      fg_col = png_pallete_color(module_color)
      transparent = background is None
      # If background color is set to None, the inverse color of the
      # foreground color is calculated
      bg_col = png_pallete_color(background) if background is not None else tuple([255 - c for c in fg_col])
      # Assume greyscale if module color is black and background color is white
      greyscale = fg_col[:3] == (0, 0, 0) and (not debug and transparent or bg_col == (255, 255, 255, 255))
      transparent_color = 1 if transparent and greyscale else None
      palette = [fg_col, bg_col] if not greyscale else None
      if debug:
          # Add "red" as color for error modules
          palette.append((255, 0, 0, 255))
          bitdepth = 2
  
      # The size of the PNG
      size = _get_png_size(version, scale, quiet_zone)
  
      # We need to increase the size of the code to match up to the
      # scale parameter.
      code_rows = scale_code(size)
  
      # Write out the PNG
      f, autoclose = _get_writable(file, 'wb')
      w = png.Writer(width=size, height=size, greyscale=greyscale,
                     transparent=transparent_color, palette=palette,
                     bitdepth=bitdepth)
      try:
          w.write(f, code_rows)
      finally:
          if autoclose:
              f.close()