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