code: def fromtif(path, ext='tif', start=None, stop=None, recursive=False, nplanes=None, npartitions=None, labels=None, engine=None, credentials=None, discard_extra=False):
      from tifffile import TiffFile
      if nplanes is not None and nplanes <= 0:
          raise ValueError('nplanes must be positive if passed, got %d' % nplanes)
      def getarray(idx_buffer_filename):
          idx, buf, fname = idx_buffer_filename
          fbuf = BytesIO(buf)
          tfh = TiffFile(fbuf)
          ary = tfh.asarray()
          pageCount = ary.shape[0]
          if nplanes is not None:
              extra = pageCount % nplanes
              if extra:
                  if discard_extra:
                      pageCount = pageCount - extra
                      logging.getLogger('thunder').warn('Ignored %d pages in file %s' % (extra, fname))
                  else:
                      raise ValueError("nplanes '%d' does not evenly divide '%d in file %s'" % (nplanes, pageCount,
                                                                                                fname))
              values = [ary[i:(i+nplanes)] for i in range(0, pageCount, nplanes)]
          else:
              values = [ary]
          tfh.close()
          if ary.ndim == 3:
              values = [val.squeeze() for val in values]
          nvals = len(values)
          keys = [(idx*nvals + timepoint,) for timepoint in range(nvals)]
          return zip(keys, values)
      recount = False if nplanes is None else True
      data = frompath(path, accessor=getarray, ext=ext, start=start, stop=stop,
                      recursive=recursive, npartitions=npartitions, recount=recount,
                      labels=labels, engine=engine, credentials=credentials)
      if engine is not None and npartitions is not None and data.npartitions() < npartitions:
          data = data.repartition(npartitions)
      return data