Exit
  • Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
  • 한국 커뮤니티
0

Unable to transform Art duplicated from different document - C++ Plugin

Explorer ,
Aug 06, 2025 Aug 06, 2025

Hello everyone, 
My objective is to duplicate the existing artboard items and replace an art item with a different one from another .ai file using a C++ plugin. I am able to duplicate the artboard items and also duplicate another art item from a different .ai file, but I am not able to transform the newly duplicated art to the position of the original art.
Below is my code:

ASErr ReplaceFromExternalFile(const ai::FilePath& sourceFilePath, AIArtHandle oldArtHandle)
{
    ASErr error = kNoErr;
    //Store the current document handle
    AIDocumentHandle destDoc;
    sAIDocument->GetDocument(&destDoc);

    //Open source document containing new logo
    AIDocumentHandle sourceDoc;
    error = sAIDocumentList->Open(sourceFilePath, kAIUnknownColorModel, kDialogOff, false, &sourceDoc);
    if (error || !sourceDoc) return error;    

    //Get first art in source document
    sAIDocumentList->Activate(sourceDoc, false);

    //Find the art handle to be used in Destination document
    AILayerHandle sourceRoot;
    error = sAILayer->GetFirstLayer(&sourceRoot);
    if (error || !sourceRoot) return error;

    AIArtHandle newLogoArt = nullptr;
    error = sAIArt->GetFirstArtOfLayer(sourceRoot, &newLogoArt);
    if (error || !newLogoArt) return error;

    while (newLogoArt != nullptr) 
    {
        short artType;
        error = sAIArt->GetArtType(newLogoArt, &artType);
        if (error) return error;

        if (artType != kUnknownArt)
        {
            break; // found usable art
        }

        error = sAIArt->GetArtSibling(newLogoArt, &newLogoArt);
        if (error) return error;
    }

    if (!newLogoArt) 
    {
        sAIDocumentList->Close(sourceDoc);
        return kNotFoundErr;
    }   

    //Acitvate the destination document
    error = sAIDocumentList->Activate(destDoc, true);
    if (error) return error;

    //Get the layer handle and group
    AILayerHandle layerDest;
    AIArtHandle artDestGroup;

    error = sAILayer->GetFirstLayer(&layerDest);
    if (error || !layerDest) return error;

    sAIArt->GetFirstArtOfLayer(sourceRoot, &artDestGroup);

    // Duplicate the art in destination document
    AIArtHandle  pastedArt = nullptr;
    error = sAIArt->DuplicateArt(newLogoArt, kPlaceAboveAll, artDestGroup, &pastedArt);
    if (error) return error;

    //Transform to the old logo position
    AIReal dx = _newArtBoardRect.left;// -newBounds.left * scaleX;
    AIReal dy = _newArtBoardRect.top;// -newBounds.bottom * scaleY;
    transformArtToNewPosition(pastedArt, dx, dy);
    
    //Added below line to check transform is working or not
    AIReal dx = _newArtBoardRect.left;
    AIReal dy = _newArtBoardRect.top;
    transformArtToNewPosition(oldLogoArtHandle, dx, dy);

    //Delete old logo ---
    //error = sAIArt->DeleteArt(oldLogoArtHandle);
    //if (error) return error;

    //Clean up ---
    sAIDocumentList->Close(sourceDoc); // close the source logo file

    return kNoErr;
}

Also added code for the transformArtToNewPosition and please find below:

ASErr transformArtToNewPosition(AIArtHandle art, AIReal tx, AIReal ty)
{
	ASErr result = kNoErr;
	AIRealRect artBounds;
	AIRealPoint artCenter;
	AIRealMatrix artMatrix;
	AIReal lineScale;
	ai::int32 transformFlags = kTransformObjects | kScaleLines | kTransformChildren;
    
    short artType;
    ASErr error = sAIArt->GetArtType(art, &artType);
    if (error == kGroupArt)
    {
        return error;
    }

	lineScale = (sAIRealMath->AIRealSqrt(1)) * (sAIRealMath->AIRealSqrt(1));

	result = sAIArt->GetArtBounds(art, &artBounds);
	artCenter.h = artBounds.left + (artBounds.right - artBounds.left) / 2;
	artCenter.v = artBounds.bottom + (artBounds.top - artBounds.bottom) / 2;

	// move object so that the centerpoint is at the origin
    sAIRealMath->AIRealMatrixSetIdentity(&artMatrix);
	sAIRealMath->AIRealMatrixSetTranslate(&artMatrix, -artCenter.h, -artCenter.v);
	sAIRealMath->AIRealMatrixConcatTranslate(&artMatrix, tx, ty);
	sAIRealMath->AIRealMatrixConcatRotate(&artMatrix, 0);
	sAIRealMath->AIRealMatrixConcatScale(&artMatrix, 1, 1);
	sAIRealMath->AIRealMatrixConcatTranslate(&artMatrix, artCenter.h, artCenter.v);

	result = sAITransformArt->TransformArt(art, &artMatrix, lineScale, transformFlags);

	return result;
}

 With the above transformArtToNewPosition code, I can transform the oldLogoArtHandle, but I cannot change the position of the newly duplicated art. Please check the attached image for the current output of my plugin.Duplicate_Replace_Transform_Issue.png

 

Could anyone shed some light on this or provide any input to help achieve my requirement? Thanks in advance!

TOPICS
How-to , SDK
218
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

Engaged , Aug 12, 2025 Aug 12, 2025

The code for duplicating looks fine. As A Patterson says, the API works when used correctly and your code is overly complicated, so chances are there’s a logic bug buried in it.  If you’ve still not solved it, I will say this bit of code “smells off” to me:

 

    AIReal dx = _newArtBoardRect.left;// -newBounds.left * scaleX;
    AIReal dy = _newArtBoardRect.top;// -newBounds.bottom * scaleY;
    transformArtToNewPosition(pastedArt, dx, dy);
    

 

ExtendScript’s high-level API allows you to set an o

...
Translate
Adobe
Engaged ,
Aug 07, 2025 Aug 07, 2025

1. I don’t understand what the screenshot is showing.

 

2. Be aware that TransformArt is not recursive. To reposition a collection (group/compound path) of items, you must recursively traverse its contents and call TraverseArt on each of its Art items yourself.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Aug 07, 2025 Aug 07, 2025

Hi hhas01, thank you for the reply.

1. When I run my plugin I am able to duplicate the contents of first artboard and place the Yellow rect in the correct position. I want to replace yellow rect with blue rect. Blue rect is in a different file. As it's showing the screenshot Blue rect was duplicated but not able to transform to Yellow rect position.

2. Yes, I have added TransformGroupItems function to recursively traverse its contents and call TraverseArt. But still not working. 

Is my code for duplicating Art from another .ai file correct? Any help? Thanks

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guide ,
Aug 07, 2025 Aug 07, 2025

We also move art between documents and don't have any problems (that I know of!) like this. That said, your matrix code seems overly complicated for a straight translation. Our base class has a function like this:

 

void Translate(AIArtHandle handle, AIReal x, AIReal y, ETranslateOptions options)
{
	AIRealMatrix matrix;
	sAIRealMath->AIRealMatrixSetTranslate(&matrix, x, y);

	ai::int32 flags = kTransformObjects | kTransformFillGradients | kTransformFillPatterns | kTransformStrokePatterns;

	if (options == ETranslateOptions::TranslateChildren) {
		flags |= kTransformChildren;
	}

	auto err =	sAITransformArt->TransformArt(handle, &matrix, 1.0, flags);
	THROW_EXCEP_IF(err);
}

 I don't think that's the source of your problem necessarily, but the very least your transformation could be simplified.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Aug 07, 2025 Aug 07, 2025

Thank you, Patterson, for the simplified version of the Translate function.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Aug 12, 2025 Aug 12, 2025

The code for duplicating looks fine. As A Patterson says, the API works when used correctly and your code is overly complicated, so chances are there’s a logic bug buried in it.  If you’ve still not solved it, I will say this bit of code “smells off” to me:

 

    AIReal dx = _newArtBoardRect.left;// -newBounds.left * scaleX;
    AIReal dy = _newArtBoardRect.top;// -newBounds.bottom * scaleY;
    transformArtToNewPosition(pastedArt, dx, dy);
    

 

ExtendScript’s high-level API allows you to set an object’s absolute position really easily using `object.position = [x,y]`. 

 

Using the low-level C++ API, you must configure an AIMatrix to move (Translate) an Art object relative to its current position. So to center your new Art object over your old Art object:

 

1. calculate both Art objects’ centerpoints

2. calculate the x and y distances between those two points

3. pass these x and y distance values to the AIRealMatrixSetTranslate() function to populate your AIMatrix

4. pass this matrix and the new Art object to TransformArt(). (Or, if it’s a group or other collection, apply TransformArt recursively to all of its children.)

 

Me, I might define a convenience function named `ASErr RepositionObjectToCenterOfObject(AIArtHandle newObject, AIArtHandle oldObject)` and fill in its function body from there. 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Aug 13, 2025 Aug 13, 2025
LATEST

Thank you for the reply. I solved the issue, and it's due to the wrong calculation.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines