def mat_image_to_img_node(image, img_node, fit=False):
    """Return mat which transforms from image to img_node coords."""
    # 1 scale
    # 2 if not fit: apply img_node offset
    # 3 apply img_node transform
    mat1 = mat.invert(mat.scale(*get_image_scale(image, img_node)))
    mat2 = mat.offset(img_node) if not fit else mat.ident_mat()
    mat3 = mat.copy_from(img_node)
    return mat.compose_triplemat(mat1, mat2, mat3)
def mat_path_to_img_node(path, img_node, fit=False):
    """Return mat which transforms from path to img_node coords."""
    # 1 apply path transform
    # 2 apply path parent transform
    # 3 reverse img_node parent transform
    mat1 = mat.copy_from(path) if not fit else mat.ident_mat()
    mat2 = mat.absolute(path.getparent())
    mat3 = mat.invert(mat.absolute(img_node.getparent()))
    return mat.compose_triplemat(mat1, mat2, mat3)
def mat_img_node_to_path(img_node, path, fit=False):
    """Return mat which transforms from img_node to path coords."""
    # 1 apply img_node parent transform
    # 2 reverse path parent transform
    # 3 ??? reverse path transform
    mat1 = mat.absolute(img_node.getparent())
    mat2 = mat.invert(mat.absolute(path.getparent()))
    # TODO: verify mat3 for fit option
    mat3 = mat.invert(mat.copy_from(path)) if not fit else mat.ident_mat()
    return mat.compose_triplemat(mat1, mat2, mat3)
 def get_clip_geom(self, node, parents=False):
     """Return clipped node and clip bbox as csp (quadrilateral)."""
     clip_base = node
     clip_path_csp = None
     clipped_node, clip_path_def = self.get_clip_def(node, parents)
     if clip_path_def is not None:
         clip_path_units = clip_path_def.get('clipPathUnits')
         if clipped_node == clip_base:
             if clip_path_units == 'objectBoundingBox':
                 # TODO: implement support for 'objectBoundingBox'
                 # 1. get geom box of clipped object (clip_base)
                 # 2. convert into a matrix transformation
                 # 3. pass matrix as cmat to get_clip_bbox_csp()
                 # until implemented, fall back to:
                 cmat = mat.ident_mat()
             else:
                 cmat = mat.ident_mat()
         else:
             if clip_path_units == 'objectBoundingBox':
                 # TODO: implement support for 'objectBoundingBox'
                 # 1. get geom box of clipped group (clipped_node)
                 # 2. convert into a matrix transformation
                 # 3. compose with cmat (see below)
                 # 4. pass cmat to get_clip_bbox_csp()
                 # until implemented, fall back to:
                 umat = mat.ident_mat()
             else:
                 umat = mat.ident_mat()
             # compensate preserved transforms on nested groups
             pmat = mat.compose_triplemat(
                 mat.copy_from(clipped_node),
                 mat.absolute_diff(clip_base, clipped_node),
                 mat.invert(mat.copy_from(clip_base)))
             # finally, compose with matrix for clipPathUnits
             # TODO: once we have real umat, check compose order!
             cmat = mat.compose_doublemat(umat, pmat)
         clip_path_csp = get_clip_bbox_csp(clip_path_def, cmat)
         mat.apply_to(mat.invert(cmat), clip_path_csp)
     return (clipped_node, clip_path_csp)