code: def write(self, outfile, rows):
          
  
          # Values per row
          vpr = self.width * self.planes
  
          def check_rows(rows):
              """
              Yield each row in rows,
              but check each row first (for correct width).
              """
              for i, row in enumerate(rows):
                  try:
                      wrong_length = len(row) != vpr
                  except TypeError:
                      # When using an itertools.ichain object or
                      # other generator not supporting __len__,
                      # we set this to False to skip the check.
                      wrong_length = False
                  if wrong_length:
                      # Note: row numbers start at 0.
                      raise ProtocolError(
                          "Expected %d values but got %d value, in row %d" %
                          (vpr, len(row), i))
                  yield row
  
          if self.interlace:
              fmt = 'BH'[self.bitdepth > 8]
              a = array(fmt, itertools.chain(*check_rows(rows)))
              return self.write_array(outfile, a)
  
          nrows = self.write_passes(outfile, check_rows(rows))
          if nrows != self.height:
              raise ProtocolError(
                  "rows supplied (%d) does not match height (%d)" %
                  (nrows, self.height))
docs: Write a PNG image to the output file.
          `rows` should be an iterable that yields each row
          (each row is a sequence of values).
          The rows should be the rows of the original image,
          so there should be ``self.height`` rows of
          ``self.width * self.planes`` values.
          If `interlace` is specified (when creating the instance),
          then an interlaced PNG file will be written.
          Supply the rows in the normal image order;
          the interlacing is carried out internally.
  
          .. note ::
  
            Interlacing requires the entire image to be in working memory.