def mesh_from_dvid_tarfile(server,
                           uuid,
                           tsv_instance,
                           bodies,
                           simplify=1.0,
                           drop_normals=False,
                           rescale_factor=1.0,
                           output_path='{body}.obj'):
    from neuclease.dvid import fetch_tarfile

    for body in bodies:
        logger.info(f"Body {body}: Fetching tarfile")
        tar_bytes = fetch_tarfile(server, uuid, tsv_instance, body)

        logger.info(f"Body {body}: Loading mesh")
        mesh = Mesh.from_tarfile(tar_bytes)

        if simplify != 1.0:
            logger.info(f"Body {body}: Simplifying")
            mesh.simplify(simplify, in_memory=True)

        if drop_normals:
            mesh.drop_normals()

        if rescale_factor != 1.0:
            logger.info(f"Body {body}: Scaling by {rescale_factor}x")
            mesh.vertices_zyx[:] *= rescale_factor

        p = output_path.format(body=body)
        logger.info(f"Body {body}: Serializing to {p}")
        mesh.serialize(p)
def decimate_existing_mesh(server, uuid, instance, body_id, fraction, max_vertices=1e9, rescale=1.0, output_format=None, output_path=None, output_dvid=None, tar_bytes=None):
    """
    Fetch all supervoxel meshes for the given body, combine them into a
    single mesh, and then decimate that mesh at the specified fraction.
    The output will be written to a file, or to a dvid instance (or both).
    
    Args:
        tar_bytes:
            Optional. You can provide the tarfile contents (as bytes) directly,
            in which case the input server will not be used.
    """
    if output_path is not None:
        fmt = os.path.splitext(output_path)[1][1:]
        if output_format is not None and output_format != fmt:
            raise RuntimeError(f"Mismatch between output format '{output_format}'"
                               f" and output file extension in '{output_path}'")
        output_format = fmt
    
    if output_format is None:
        raise RuntimeError("You must specify an output format (or an output path with a file extension)")

    assert output_format in Mesh.MESH_FORMATS, \
        f"Unknown output format: {output_format}"

    assert output_path is not None or output_dvid is not None, \
        "No output location specified"

    if tar_bytes is None:
        with Timer(f"Body: {body_id} Fetching tarfile", logger):
            tar_bytes = fetch_tarfile(server, uuid, instance, body_id)
    
    with Timer(f"Body: {body_id}: Loading mesh for body {body_id}", logger):
        mesh = Mesh.from_tarfile(tar_bytes, keep_normals=False)

    mesh_mb = mesh.uncompressed_size() / 1e6
    orig_vertices = len(mesh.vertices_zyx)
    logger.info(f"Body: {body_id}: Original mesh has {orig_vertices} vertices and {len(mesh.faces)} faces ({mesh_mb:.1f} MB)")

    fraction = min(fraction, max_vertices / len(mesh.vertices_zyx))    
    with Timer(f"Body: {body_id}: Decimating at {fraction:.2f}", logger):
        mesh.simplify(fraction, in_memory=True)

    mesh_mb = mesh.uncompressed_size() / 1e6
    logger.info(f"Body: {body_id}: Final mesh has {len(mesh.vertices_zyx)} vertices and {len(mesh.faces)} faces ({mesh_mb:.1f} MB)")

    if not isinstance(rescale, Iterable):
        rescale = 3*[rescale]
    
    rescale = np.asarray(rescale)
    if not (rescale == 1.0).all():
        mesh.vertices_zyx[:] *= rescale

    with Timer(f"Body: {body_id}: Serializing", logger):
        mesh_bytes = None
        if output_dvid is not None:
            assert len(output_dvid) == 3
            mesh_bytes = mesh.serialize(fmt=output_format)
            post_key(*output_dvid, f"{body_id}.{output_format}", mesh_bytes)
            
        if output_path:
            if mesh_bytes is None:
                mesh.serialize(output_path)
            else:
                with open(output_path, 'wb') as f:
                    f.write(mesh_bytes)
    
    return len(mesh.vertices_zyx), fraction, orig_vertices