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

• Small Javascript to reset to "zero" the rotate value of a placed item.

Enthusiast ,
Oct 08, 2024 Oct 08, 2024

Hi -

 

I try to make a very "simple" Adobe Illustrator Javascript based on the below script (I found it somewhere years ago on internet, tbh can't remeber where).

 

The script should simply reset to zero (0°) the "rotate" value of the current selected placed item.

I tried already a lot of stuff, but can't make it works  :-P:

I found information like "app.getRotationMatrix(…)".  But yeah… How to make it work?   🤷🏻

 

 

Here is the source code (base), not the final script:

 

 

selection = app.activeDocument.selection;

for (i=0; i<selection.length; i++) {

    if(selection[i].typename == "TextFrame" || selection[i].typename == "PlacedItem" || selection[i].typename == "RasterItem") {
        get_matrix = selection[i].matrix;		

        if(selection[i].typename == "PlacedItem")
            get_matrix = concatenateScaleMatrix(get_matrix, 100, -100);

        invMatrix = invertMatrix(get_matrix);
        invMatrix.mValueTX = 0;
        invMatrix.mValueTY = 0;
        
        selection[i].transform(invMatrix);
    }
}

 

 

 

I tried something (w/ the help of ChatGPT), visually we are close to a result, but the placed item rotate value is just not reset to "zero" (0°):

 

 

 

function resetPlacedItemRotation() {
    var myDoc_DC = app.activeDocument;
    var IMG_selected = myDoc_DC.selection;

    if (IMG_selected.length === 0) {
        alert("Please select a placed item.");
        return;
    }

    for (var i = 0; i < IMG_selected.length; i++) {
        var item = IMG_selected[i];

        if (item.typename === "PlacedItem") {
            var confirmReset = confirm("Do you want to reset the rotation for the selected placed item?");
            
            if (confirmReset) {
                // Get the current transformation matrix
                var currentMatrix = item.matrix;

                // Calculate the current rotation angle in degrees
                var currentRotation = Math.atan2(currentMatrix.mValueB, currentMatrix.mValueA) * (180 / Math.PI);

                // Apply the exact opposite of the current rotation
                var rotationToApply = -currentRotation;  // Opposite direction

                // Rotate around the center of the placed item
                item.rotate(rotationToApply, true, true, true, true, Transformation.CENTER);

                alert("Rotation has been reset to 0° by applying " + rotationToApply.toFixed(3) + "°.");
            } else {
                alert("Operation canceled.");
            }
        } else {
            alert("Selected item is not a placed item.");
        }
    }
}

resetPlacedItemRotation();

 

 

 

 

Thank you,

Enjoy your day,

 

 

 - Dimitri

 

TOPICS
Scripting
2.3K
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

Advocate , Oct 11, 2024 Oct 11, 2024

Seulement rotation 0°

// JavaScript Document
// This script resets the rotation angle to 0 degrees for bitmap clips and Imported artwork.
  var info = false;
      testObjects(selection);
// -------
function testObjects(a) {
  var deg,
      tag,
      selLen = a.length;
    for (var c = 0; c < selLen; c++) {
        if(a[c].typename == 'GroupItem'){
          testObjects(a[c].pageItems);
        } else
            if(a[c].typename=='RasterItem' || a[c].typename == 'PlacedItem') {
              d
...
Translate
Adobe
Community Expert ,
Oct 08, 2024 Oct 08, 2024

Hi @dimitri_cas, here is one approach—get the rotation from the placed item's matrix, then rotate it by that negative amount:

(function () {

    var doc = app.activeDocument,
        placedItem = doc.selection[0];

    if (!placedItem)
        return alert('Please select a placed item and try again.');

    var sr = getLinkScaleAndRotation(placedItem),
        scale = [sr[0], sr[1]],
        rotation = sr[2];

    placedItem.rotate(-rotation);

})();

/**
 * Return the scale, rotation and size
 * of a PlacedItem or RasterItem.
 * @author m1b
 * @version 2023-03-09
 * @param {PlacedItem|RasterItem} item - an Illustrator item.
 * @param {Boolean} round - whether to round numbers to nearest integer.
 * @returns {Array} [scaleX%, scaleY%, rotation°, width, height]
 */
function getLinkScaleAndRotation(item, round) {

    if (item == undefined)
        return;

    var m = item.matrix,
        rotatedAmount,
        unrotatedMatrix,
        scaledAmount;

    var flipPlacedItem = (item.typename == 'PlacedItem') ? 1 : -1;

    try {
        rotatedAmount = item.tags.getByName('BBAccumRotation').value * 180 / Math.PI;
    } catch (error) {
        rotatedAmount = 0;
    }
    unrotatedMatrix = app.concatenateRotationMatrix(m, rotatedAmount * flipPlacedItem);

    if (
        unrotatedMatrix.mValueA == 0
        && unrotatedMatrix.mValueB !== 0
        && unrotatedMatrix.mValueC !== 0
        && unrotatedMatrix.mValueD == 0
    )
        scaledAmount = [unrotatedMatrix.mValueB * 100, unrotatedMatrix.mValueC * -100 * flipPlacedItem];
    else
        scaledAmount = [unrotatedMatrix.mValueA * 100, unrotatedMatrix.mValueD * -100 * flipPlacedItem];

    if (scaledAmount[0] == 0 || scaledAmount[1] == 0)
        return;

    if (round)
        return [round(scaledAmount[0]), round(scaledAmount[1]), round(rotatedAmount)];
    else
        return [scaledAmount[0], scaledAmount[1], rotatedAmount];

};

 

There are other ways, eg. read the rotation value from a tag:

 

rotatedAmount = item.tags.getByName('BBAccumRotation').value * 180 / Math.PI;

 

 

I also wrote a function that derives the rotation value by minimizing the area of the rectangular bounds of the item:

/**
 * Returns the rotation amount in degrees
 * that the item needs to be rotated such
 * that it has a minimal bounding box area.
 * Assuming that `item` is a rectangular
 * object, such as a PlacedItem, RasterItem
 * or a rectangular path item, the resulting
 * rotation will rotate it so that the sides
 * of the rectangle align to a factor of 90°.
 * In other words, it will return the value
 * required to "unrotate" the item.
 * @author m1b
 * @version 2023-08-25
 * @param {PageItem} item - an Illustrator page item.
 * @returns {Number}
 */
function findRotationByMinimalBounds(item) {

    // we will rotate a copy and leave the original
    var workingItem = item.duplicate(),

        convergenceThreshold = 0.001,
        inc = 45, // the starting rotation increment
        rotationAmount = 0,
        prevArea = area(workingItem);

    while (Math.abs(inc) >= convergenceThreshold) {

        workingItem.rotate(inc);

        var newArea = area(workingItem);

        if (newArea < prevArea) {
            prevArea = newArea;
            rotationAmount -= inc;
            inc *= 0.5;
        }

        else {
            workingItem.rotate(-inc); // Undo the last rotation
            inc *= -0.5;
        }

    }

    // clean up
    workingItem.remove();

    return round(rotationAmount, 2);

    /**
     * Returns area of bounding box of `item`.
     * @param {PageItem} item
     * @returns {Number}
     */
    function area(item) {
        return item.width * item.height;
    };

};

/**
 * Rounds `n` to `places` decimal places.
 * @param {Number} n - the number to round
 * @param {Number} places - number of decimal places, can be negative
 * @returns {Number}
 */
function round(n, places) {
    var m = Math.pow(10, places != undefined ? places : 3);
    return Math.round(n * m) / m;
};

 

Each method has pros and cons. I suggest you try the first approach first and see how you go. It only works with an unskewed matrix. The second approach only works if the tag exists, and no rotations have been performed without updating it. The third option is probably the most robust but is a bit slower.

- Mark

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
Enthusiast ,
Oct 08, 2024 Oct 08, 2024

Hi m1b -

 

Thanks for your reply.

First way/option seems to work perfectly  😉

It worked well the first time, I tried already in another document on another placed image and it didn't work.

The seoncd time, result is quite similar than mine… 😞

 

Thx again.

Enjoy your day.

 

  

 

- Dimitri

 

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
Community Expert ,
Oct 08, 2024 Oct 08, 2024

I think to get Mark's first script to run properly requires to reset the bounding box after each rotation to zero degree. You may want to modify that.

 

You may also have a look at this approach by Sky Chaser High which is pretty good.

 

/* ===============================================================================================================================================
   resetToFullScale

   Description
   This script resets the scale to 100% and the rotation angle to 0 degrees for the linked files.
   Embedded images is also supported.

   Usage
   Select the linked files or the embedded images, run this script from File > Scripts > Other Script...

   Notes
   In rare cases, if you continue to use the script, it may not work.
   In that case, restart Illustrator and try again.

   Requirements
   Illustrator CS6 or higher

   Version
   1.0.1

   Homepage
   github.com/sky-chaser-high/adobe-illustrator-scripts

   License
   Released under the MIT license.
   https://opensource.org/licenses/mit-license.php
   =============================================================================================================================================== */

(function() {
    if (app.documents.length > 0 && app.activeDocument.selection.length > 0) main();
})();


function main() {
    // work around a bug
    try {
        app.executeMenuCommand('Adobe Update Link Shortcut'); // Link Panel > Update Link
        app.redraw();
    }
    catch (err) { }

    var items = app.activeDocument.selection;
    var images = getImageItems(items);

    for (var i = 0; i < images.length; i++) {
        resetToFullScale(images[i]);
    }
}


function resetToFullScale(item) {
    var basis = {
        'left': item.left,
        'top': item.top,
        'width': item.width,
        'height': item.height
    };

    var filename = '';
    try {
        if (item.typename == 'PlacedItem') filename = item.file.name;
    }
    catch (err) { }

    // work around a bug
    var deg = getRotationAngle(item);
    item.rotate(deg * -1);
    var scale = getScale(item);
    item.resize(1 / scale.x * 100, 1 / scale.y * 100);

    item.matrix.mValueA = 1;
    item.matrix.mValueB = 0;
    item.matrix.mValueC = 0;
    item.matrix.mValueD = (/\.eps$/i.test(filename) || item.typename == 'RasterItem') ? 1 : -1; // invert the sign except for eps file and embedded image

    // workaround for the reflect object
    item.left = 0;
    item.top = 0;

    // reposition the object to the center
    item.left = basis.left - (item.width - basis.width) / 2;
    item.top = basis.top + (item.height - basis.height) / 2;
}


function getRotationAngle(item) {
    var matrix = item.matrix;
    var rad = Math.atan2(matrix.mValueB, matrix.mValueA);
    var deg = rad * 180 / Math.PI;
    return (item.typename == 'PlacedItem') ? deg * -1 : deg;
}


function getScale(item) {
    var matrix = item.matrix;
    var x = Math.sqrt(Math.pow(matrix.mValueA, 2) + Math.pow(matrix.mValueB, 2));
    var y = Math.sqrt(Math.pow(matrix.mValueC, 2) + Math.pow(matrix.mValueD, 2));
    return {
        x: x,
        y: y
    };
}


function getImageItems(items) {
    var images = [];
    for (var i = 0; i < items.length; i++) {
        var item = items[i];
        if (item.typename == 'PlacedItem' || item.typename == 'RasterItem') {
            images.push(item);
        }
        if (item.typename == 'GroupItem') {
            images = images.concat(getImageItems(item.pageItems));
        }
    }
    return images;
}
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
Advocate ,
Oct 08, 2024 Oct 08, 2024

Bonjour à tous,

Je pense que vous devriez ajouter cela à vos scripts...

 

    var tag = getTag(item);
    if (tag != undefined) tag.value = 0;
}
//-----------
function getTag(obj)
{ // retourne le V.tag de nom "BBAccumRotation" si il existe
     try {
     var tag = obj.tags.getByName("BBAccumRotation");
     }   catch (e) {
        if (info) alert( "The specified tag doesn’t exist" );
        return undefined;
        }
     return tag;
}

 

René

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
Enthusiast ,
Oct 10, 2024 Oct 10, 2024

Hello René -

 

OK, mais cela fait quoi en résumé?

Car la version de Kurt semble fonctionner correctement.

 

Merci pour votre intervention  🙂

 

 

- Dimitri

 

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
Advocate ,
Oct 11, 2024 Oct 11, 2024

Bonjour Dimitri,

Si on prend le script de Kurt, pour la version d'Illustrator que j'utilise.

 

renl80416020_0-1728644487429.png

Si je sélectinne l'image après exécution.

renl80416020_1-1728644696622.png

C'est pourquoi je propose de réinitialiser le Tag  à la valeur 0.

René

 

 

 

 

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
Enthusiast ,
Oct 10, 2024 Oct 10, 2024

Hi Kurt  🙂

 

It works perfectly fine (for now).

A sh*t, It reset everything. I only need the "roate value" to be reset (nothing else).

 

Thanks a lot enjoy your day.

 

 

- Dimitri

 

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
Enthusiast ,
Oct 11, 2024 Oct 11, 2024

This one doesn't work, it resets all the transformation.

Not only the "rotate value"

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
Enthusiast ,
Oct 11, 2024 Oct 11, 2024

Hi…

 

The one from "Sky Chaser High"

OK… Pretty good, but here too, it resets all the transformations, not only the "rotate value"  😕

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
Community Expert ,
Oct 10, 2024 Oct 10, 2024

It would be interesting if you post a test file where the rotation fails, then we could possibly explain why.

 

Did you try each of the approaches I mentioned?

 

For example, I made the following technique for a job last year due to issues of other methods not being robust enough. However the downside is it will only rotate to the nearest factor of 90°. So very good for straightening, but if something rotated 91° it will rotate back by 1° only. You can compensate if you know the aspect ratio.

 

Anyway, here is test code. First select a placed item and run script:

(function () {

    var doc = app.activeDocument,
        item = doc.selection[0];

    // undo the rotation
    item.rotate(-findRotationByMinimalBounds(item));

})();

/**
 * Returns the rotation amount in degrees
 * that the item needs to be rotated such
 * that it has a minimal bounding box area.
 * Assuming that `item` is a rectangular
 * object, such as a PlacedItem, RasterItem
 * or a rectangular path item, the resulting
 * rotation will rotate it so that the sides
 * of the rectangle align to a factor of 90°.
 * In other words, it will return the value
 * required to "unrotate" the item.
 * @author m1b
 * @version 2023-08-25
 * @Param {PageItem} item - an Illustrator page item.
 * @Returns {Number}
 */
function findRotationByMinimalBounds(item) {

    // we will rotate a copy and leave the original
    var workingItem = item.duplicate(),

        convergenceThreshold = 0.001,
        inc = 45, // the starting rotation increment
        rotationAmount = 0,
        prevArea = area(workingItem);

    while (Math.abs(inc) >= convergenceThreshold) {

        workingItem.rotate(inc);

        var newArea = area(workingItem);

        if (newArea < prevArea) {
            prevArea = newArea;
            rotationAmount -= inc;
            inc *= 0.5;
        }

        else {
            workingItem.rotate(-inc); // Undo the last rotation
            inc *= -0.5;
        }

    }

    // clean up
    workingItem.remove();

    return round(rotationAmount, 2);

    /**
     * Returns area of bounding box of `item`.
     * @Param {PageItem} item
     * @Returns {Number}
     */
    function area(item) {
        return item.width * item.height;
    };

};

/**
 * Rounds `n` to `places` decimal places.
 * @Param {Number} n - the number to round
 * @Param {Number} places - number of decimal places, can be negative
 * @Returns {Number}
 */
function round(n, places) {
    var m = Math.pow(10, places != undefined ? places : 3);
    return Math.round(n * m) / m;
};

 

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
Enthusiast ,
Oct 11, 2024 Oct 11, 2024

Hi Mar k--The last one, the most "robust" as you said

Doesn't work too

Sorry… You written

findRotationByMinimalBounds(item)

"

But what/where the "item" in your code?

thx

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
Advocate ,
Oct 11, 2024 Oct 11, 2024

Seulement rotation 0°

// JavaScript Document
// This script resets the rotation angle to 0 degrees for bitmap clips and Imported artwork.
  var info = false;
      testObjects(selection);
// -------
function testObjects(a) {
  var deg,
      tag,
      selLen = a.length;
    for (var c = 0; c < selLen; c++) {
        if(a[c].typename == 'GroupItem'){
          testObjects(a[c].pageItems);
        } else
            if(a[c].typename=='RasterItem' || a[c].typename == 'PlacedItem') {
              deg = getRotationAngle(a[c]);
              a[c].rotate(deg * -1);
              tag = getTag(a[c]);
              if (tag != undefined) tag.value = 0;
            }
    }
}
// -------
function getRotationAngle(item) {
    var mtx = item.matrix;
    var deg = Math.atan2(mtx.mValueB, mtx.mValueA) * 180 / Math.PI;
    return (item.typename == 'PlacedItem') ? deg * -1 : deg;
}
// -------
function getTag(obj)
{ // retourne le V.tag de nom "BBAccumRotation" si il existe
     try {
     var tag = obj.tags.getByName("BBAccumRotation");
     }   catch (e) {
          if (info) alert( "The specified tag doesn’t exist" );
        return undefined;
        }
     return tag;
}
// -------

René

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
Enthusiast ,
Oct 14, 2024 Oct 14, 2024

Salut René  🙂

Hi Mark m1b  🙂

 

Last script from René is exactly what I'm looking for. For now, it works like a charm (in most of the cases, see next message).

Two both of you a BIG thx (merci), for your time, explanations and your expertise.

 

Enjoy your day…

 

 

 

- Dimitri

 

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
Enthusiast ,
Oct 16, 2024 Oct 16, 2024

Hi again 🙂

 

It works in most of the cases…

Now I just had a case were the value was "Rotate: 176.52°"

And the script didn't reacted correctly, placed item was like flipped vertically and not really at 0°…

  

- Dimitri

 

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
Advocate ,
Oct 16, 2024 Oct 16, 2024

Bonjour Dimitri,

Après de multiples essais,

176.52° rotation copier et ensuite CTRL+D

et bien d'autres...

renl80416020_0-1729107808454.png

Après alignement etajout de bordures.

renl80416020_1-1729107901075.png

René

 

 

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
Community Expert ,
Oct 16, 2024 Oct 16, 2024

Hi @dimitri_cas if you discover an item that won't rotate correctly, please post a demo document (save as an Illustrator-editable pdf). That is the best way to get to the bottom of it.

- Mark

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
Enthusiast ,
Oct 17, 2024 Oct 17, 2024

Hi Mark 🙂

Salut René renél80416020

 

Here we go, a PDF (Illustrator editable) with the wrong/incorrect behaviour of the script

screensh_ 2024-10-17 at 10.32.51.png

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
Advocate ,
Oct 17, 2024 Oct 17, 2024

Salut Dimitri,

Merci pour l'exemple, ma version d'Illustrator est un peu ancienne CS6, je peux cependant ouvrir le pdf peut-être a t'il subit des modifications?

Exemple l'image de gauche (sélection ?):

renl80416020_0-1729198248988.png

Si maintenant j'utilise une image sans anomalie:

renl80416020_1-1729198342698.png

Le résultat est correct.

René

 

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
Enthusiast ,
Oct 22, 2024 Oct 22, 2024
LATEST

Bonjour René  🙂

 

Je ne m'explique pas trop le souci.

Probablement avez vous raison…

 

 

 

Merci.

 

 

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
Community Expert ,
Oct 11, 2024 Oct 11, 2024

@dimitri_cas `item` is a parameter in my function, which expects a PlacedItem or a RasterItem (it will work with other things too, but if they aren't rectangular it might not give expected results). You can see my code above I call the function with item being the selected item. So: 1) select a placed item, and 2) run script.

 

I think you are struggling to understand something. So far, literally everyone who has commented here has given a correct answer. I suggest you post an example of a document that causes a particular script to fail.

- Mark

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
Community Expert ,
Oct 16, 2024 Oct 16, 2024

Hi @dimitri_cas, you are already well on your way to a solution, but I just remembered that I did a similar thing in a previous script I wrote. Maybe you could look at it and see if it sheds any light on the problem.

- Mark

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
Enthusiast ,
Oct 17, 2024 Oct 17, 2024

Hi Mark -

Salut René renél80416020

 

Thanks to both of you for your help.

Strangely enough, currently I can't reproduce the "wrong behaviour" of the script (ie. That it flipped not to 0° the placed item, instead of just resetting the rotate value to 0°). And I don't know why…  😛

 

If I still encounter the "wrong behaviour" I'll post the file (PDF) as requested  😉

 

 

Thanks again, and

both of you, enjoy your day.

 

 

 - Dimitri

 

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