pythonctypesautocadcomtypes

Using Python to IMAGECLIP an image in Autocad


I want to automatize the creation of a Clipping Boundary of an Image (references externes) in Autocad using known coordinates.

I'm able to do it manually using the native function IMAGECLIP in Autocad by drawing a polygon.

It seems the key parameter is ClipBoundary But I'm not able to use it proprely. For your information, the ObjectName of the image is AcDbRasterImage and it has beed add via AddRaster(image_path, insertion_point, 1, 0) (pyautocad). https://help.autodesk.com/view/OARX/2022/ENU/?guid=GUID-D9612F57-7F1F-4CFD-B804-838B826C59FC

I've try this code but it doesn't work :

import comtypes.client

# Connexion à l'application AutoCAD active
acad = comtypes.client.GetActiveObject("AutoCAD.Application")
doc = acad.ActiveDocument
modelspace = doc.ModelSpace

# Appliquer la boundary de clip à l'image raster
def apply_clip_boundary(raster, points):
    raster.ClippingEnabled = True  # Activer le clipping

    # Debugging: Output the clip points to verify the correct format
    print("Points to be passed to ClipBoundary:", list(points))
    print(raster.ClipBoundary)
    # Appliquer la ClipBoundary
    raster.ClipBoundary = points  # Assurez-vous que les points sont bien formatés
    print("Clip boundary applied and enabled.")
    print(raster.ClipBoundary)

# Créer les points 2D initiaux (x, y)
points = [
        (325100.2407, 7682500.6218),
        (325100.6019, 7682500.6218),
        (325100.6019, 7682500.3992),
        (325100.2407, 7682500.3992),
        (325100.2407, 7682500.6218)
    ]


# Sélectionner un raster par son nom
def get_raster_by_name(name):
    for item in modelspace:
        if item.ObjectName == "AcDbRasterImage" and item.Name == name:
            return item
    return None

# Obtenir le raster et appliquer la boundary
raster = get_raster_by_name("photo")
if raster:
    apply_clip_boundary(raster, points)
else:
    print("Raster not found.")

The result of the script is : no error message, but nothing happens

This is the result when I use : print(raster.ClipBoundary) before passing points

<bound method ClipBoundary of <POINTER(IAcadRasterImage) ptr=0x214be61a5d8 at 214c65509c0>>

and this is the result of the print(raster.ClipBoundary) after passing points:

[(325100.2407, 7682500.6218), (325100.6019, 7682500.6218), (325100.6019, 7682500.3992), (325100.2407, 7682500.3992), (325100.2407, 7682500.6218)]

My conclusion is either I don't pass the good kind of datas (array of points?) or I do not know how to use ClipBoundary.... it seems ClipBoundary is not anymore a method after passing parameters points

While raster.ClipBoundary = points doesn't work, raster.ClippingEnabled = True does work ( I noticed the parameter in Autocad UI changed whenever I pass a parameter True or False for ClippingEnabled)

I'm in nativ WCS (I did not change it). Maybe it's a problem of coordinate system? Does ClipBoundary need points to be passed in local (relativ from the image, from the insert_point of the image? from the boundingbox of the image)? maybe I should use ClipBoundary like a fonction() ?

I also tried to pass directly a polygon, but it doesn't work: from pyautocad import Autocad, APoint, aDouble import comtypes.client from ctypes import c_double

# Connexion à AutoCAD via pyautocad
acad = Autocad(create_if_not_exists=True)

def apply_clip_boundary(raster, points):
    # Vérifiez si le raster est bien trouvé avant de continuer
    if not raster:
        print("Raster not found.")
        return

    # Créer une polyligne 2D avec les points fournis (pas de Z, donc uniquement X et Y)
    polyline_points = aDouble(*[coord for point in points for coord in point])  # Ajouter uniquement X et Y
    
    # Utilisation de AddLightWeightPolyline pour créer une polyline 2D
    pl = acad.model.AddLightWeightPolyline(polyline_points)
    
    # Clôturer la polyligne
    pl.Closed = True

    # Activer la boundary de clip et ajouter la géométrie au raster
    raster.ClipBoundary = pl
    raster.ClippingEnabled = True

    return pl

def get_raster_by_name(name):
    # Rechercher le raster par son nom dans le modèle
    for item in acad.iter_objects():
        if item.ObjectName == "AcDbRasterImage" and item.Name == name:
            return item
    return None

# Points définissant la boundary de découpe
points = [
    (325100.2407, 7682500.6218),
    (325100.6019, 7682500.6218),
    (325100.6019, 7682500.3992),
    (325100.2407, 7682500.3992)
]

# Obtenir le raster et appliquer la boundary
raster = get_raster_by_name("photo")
if raster:
    apply_clip_boundary(raster, points)
else:
    print("Raster not found.")

Even if I would like to avoid "SendCommand" method, as much as possible. I will accept this solution.


Solution

  • Note: I don't have AutoCAD installed, so I can't do any testing to support my statement(s).

    But as the very URL from the question ([AutoDesk.Help]: ClipBoundary Method (ActiveX)) states, ClipBoundary is a method, which means it has to be invoked.

    raster.ClipBoundary = points
    

    doesn't make any sense, instead you should:

    raster.ClipBoundary(points)