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

Positioning a clipping mask with contents

Contributor ,
Oct 21, 2024 Oct 21, 2024

Copy link to clipboard

Copied

 

 

var item = doc.pageItems[i];
var itemWidth = item.width;
var newX = (docWidth - itemWidth) / 2;
var newY = 0;
item.position = [newX, newY];

 

 

When the items are simple shapes the above script works as expected i.e. the top border aligned at top artboard side. In case the items are cplipping mask with contents which is higher than the mask then the script fails i.e. the top artbord side aligned with top mask contents. What is possible to do to fix it? I expect that the clipping mask top border will be aligned at the artboard's top side. 

TOPICS
Scripting

Views

569

Translate

Translate

Report

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

Community Expert , Oct 21, 2024 Oct 21, 2024

Hey, here's a handy function for getting the bounds of objects that accounts for clipping masks and compound paths. Let me know if you have any questions?

 

GetVisibleBounds: https://github.com/joshbduncan/illustrator-scripts/blob/ada54de802cb950f711f2b78ae93e231a426998c/jsx/utils/GetVisibleBounds.jsxinc

 

Votes

Translate

Translate
Adobe
Community Expert ,
Oct 21, 2024 Oct 21, 2024

Copy link to clipboard

Copied

Hey, here's a handy function for getting the bounds of objects that accounts for clipping masks and compound paths. Let me know if you have any questions?

 

GetVisibleBounds: https://github.com/joshbduncan/illustrator-scripts/blob/ada54de802cb950f711f2b78ae93e231a426998c/jsx...

 

Votes

Translate

Translate

Report

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
Contributor ,
Oct 21, 2024 Oct 21, 2024

Copy link to clipboard

Copied

As I understand it, the item.position property always places the object on the boundaries of the real content (e.g. what is hidden in the mask)?

Votes

Translate

Translate

Report

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 21, 2024 Oct 21, 2024

Copy link to clipboard

Copied

Correct the position property (and same for the multiple bounds properties). The function linked above returns an array of the provided object bounds [left, top, right, bottom] accounting for the mask. Running the script below in the provided file (with linked function included) presents a dialog with the info from the screenshot. As you can see the hidden ovals are included in the info from the API, whereas the custom function returns what I think you are looking for...

 

var o = app.activeDocument.selection[0];
alert(
  "Placement Info\nPosition: " +
    o.position +
    "\nGeometric Bounds: " +
    o.geometricBounds +
    "\nVisible Bounds: " +
    o.visibleBounds +
    "\ngetVisibleBounds: " +
    getVisibleBounds(o)
);

 CleanShot 2024-10-21 at 13.09.14@2x.png

CleanShot 2024-10-21 at 13.10.06@2x.png

Votes

Translate

Translate

Report

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 21, 2024 Oct 21, 2024

Copy link to clipboard

Copied

Bonjour,

L'objet qui sert de masque est le premier objet du groupe masque, c'est lui qui doit servir pour le positionnement.

Un exemple de script pour comprendre...

 

// JavaScript Document
// De elleere
// Place les objets sélectionnés en haut et au  centre du plan de travail actif
// Places the selected objects at the top and center of the active artboard
// Contours or not to be taken into account (var visibleBds)
// -------
var visibleBds = false;
// -------
var doc = activeDocument,
    Origin = doc.rulerOrigin,
    largDoc = doc.width,
    hautDoc = doc.height,
    origX = -Origin[0],
    origY = -Origin[1]+hautDoc,
    objRef,
    item,
    dxy,
    sel = selection;

     for (var i = 0; i < sel.length; i++) {
        item = sel[i];
        objRef = item.typename == "GroupItem" && item.pageItems[0].clipping ? item.pageItems[0] : item;
        dxy = visibleBds ? TopCenterV(objRef,origX,origY) : TopCenterP(objRef,origX,origY);
        //dxy = TopCenterVG(objRef,origX,origY,visibleBds)
        // -------
        // for info
        var mes = "the two functions TopCenterG() and TopCenterP() are equivalent"+"\r";
        if (i == 0) alert(mes+TopCenterG(objRef,origX,origY)+"\r"+TopCenterP(objRef,origX,origY));
        // -------
        item.translate(dxy[0],dxy[1]);
        item.selected = false;
    }
// -------
function TopCenterG(obj,X,Y) {
  var v = obj.geometricBounds;
    var dx = X - v[0] + (activeDocument.width-(v[2]-v[0]))/2,
        dy = Y - v[1];
  return [dx,dy];
}
// -------
function TopCenterP(obj,X,Y) {
    var dx = X - obj.position[0] + (activeDocument.width-obj.width)/2,
        dy = Y - obj.position[1];
  return [dx,dy];
}
// -------
function TopCenterV(obj,X,Y) {
    var v = obj.visibleBounds;
    var dx = X - v[0] + (activeDocument.width-(v[2]-v[0]))/2, 
        dy = Y - v[1];
  return [dx,dy];
}
// -------
// To use this function, replace line 23 with
// dxy = TopCenterVG(objRef,origX,origY,visibleBds)
// and remove the other three functions
function TopCenterVG(obj,X,Y,at) {   // at for visibleBds
    var v = at ? obj.visibleBounds : obj.geometricBounds;
    var dx = X - v[0] + (activeDocument.width-(v[2]-v[0]))/2, 
        dy = Y - v[1];
  return [dx,dy];
}
// -------

 

René

Votes

Translate

Translate

Report

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 21, 2024 Oct 21, 2024

Copy link to clipboard

Copied

@renél80416020, yes this works perfectly for simple objects where the mask is the first item that encompasses all. The main purpose of the function I linked above is to cover more edge cases. For example, if the selected object is a group that includes a mask along with other objects (like the attached file), the helper function still gives the correct info so that you can calculate a proper translation matrix. Your script probably covers most people's needs, I just needed more coverage for a few more involved scripts I was working on. Cheers!

Votes

Translate

Translate

Report

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 23, 2024 Oct 23, 2024

Copy link to clipboard

Copied

Bonjour @jduncan,

Merci pour votre remarque qui est très pertinente, mon script est forcément limité, c'était surtout dans un but pédagogique afin de permettre à @andyf65867865 de progresser dans sa compréhension des propriétés position, geometriqueBounds et visibleBounds (en bref tout simplement tenter de répondre à la question posée).

j'avoue ne pas avoir pensé à chercher plus loin.

Déformation professionnelle, j'ai enseigné pendant 38 années...

Cependant j'ai une question, si un objet masque est mini d'un contour, ce qui est possible, ne doit on pas en tenir compte dans visiblebounds?

Exemple: Un des masques du groupe sélectionné possède un contour noir de 11pts,

la bonne réponse serait plutôt celle du bas...

visibleBounds mask.JPG

Le non de la fonction getVisibleBounds peut prêter à confusion?

René

 

Votes

Translate

Translate

Report

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 23, 2024 Oct 23, 2024

Copy link to clipboard

Copied

@renél80416020, you have a keen eye and are definitely right. This has come up before to be honest but I wasn't sure how to handle it... I should have picked a different name for the function initially but by the time I realized that it might be confusing (my definition of visible bounds doesn't match the official API) others had found the function on Github and were referencing it by the name `getVisibleBounds` so I didn't want to create confusion by changing it. It is really silly actually, since the function deals exclusively with geometric bounds. It probably should have been called something like `getGeometricBoundsOfClippedItems()`.

 

I was kind of new to scripting when I wrote this function but a long-time Ai user, so to me, the size of an item is the size of the path (excluding any strokes) like displayed in the transform palette. So the reason I choose `visible` was to say the potential visible parts of a clipped collection of items.

 

A fix would be simple so maybe I'll make another utility function that does just that... Thanks for the feedback, I really appreciate it!

Votes

Translate

Translate

Report

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 24, 2024 Oct 24, 2024

Copy link to clipboard

Copied

@jduncan,

Vous êtes vraiment modeste quand vous écrivez:

"J’étais un peu novice en matière de script quand j’ai écrit cette fonction"

René

Votes

Translate

Translate

Report

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 24, 2024 Oct 24, 2024

Copy link to clipboard

Copied

LATEST

Voici ma version faite pour l'occasion.

// JavaScript Document
// pos masque 4 test plus.js
// Author Landry René elleere@aliceadsl.fr
// Wed, 23 October 2024 11:02:00 GMT
// Place les objets sélectionnés en haut et au  centre du plan de travail actif
// Places the selected objects at the top and center of the active artboard
// Contours or not to be taken into account (variable visibleBds)
/*Note: If the variable AdjustMask = true the framing is done on the masked object
  false The clipping group.  */
// INIT -------
var visibleBds = true; // alignment mode visibleBounds or geometricBounds
var AdjustMask = true; // Adjust masks
var entourRect = false; // draws an ungrouped frame around the object
// ------------
var result = false;
var res = "dialog { orientation: 'column', alignChildren: 'right', \
  info: Group { orientation: 'column', alignChildren: 'left', \
    text: 'Choice of mode:', \
    modeType: Group { orientation: 'column', alignChildren: 'left', margins: 8, \
    rbtn1:  RadioButton { text: 'GeometricBounds'}, \
    rbtn2:  RadioButton { text: 'VisibleBounds'}, \
    ajkbox: Checkbox { text: 'Adjust masks?'}, \
  }, \
  } \
  buttons: Group { orientation: 'row', \
    ok: Button { text: 'OK', properties:{name:'ok'} }, \
  } \
}";

var win = new Window(res);
    win.frameLocation = [100,150];
    win.text = "TopCenter de LR";
    win.info.modeType.rbtn1.value = !visibleBds;
    win.info.modeType.rbtn2.value = visibleBds;
    win.info.modeType.ajkbox.value = AdjustMask;

    win.buttons.ok.onClick = function() {
      visibleBds = win.info.modeType.rbtn2.value;
      AdjustMask = win.info.modeType.ajkbox.value;
      result = true;
      win.close();
    }
    win.show();
// -------
if (result){
  var doc = activeDocument,
      Origin = doc.rulerOrigin,
      hautDoc = doc.height,
      origX = -Origin[0],
      origY = -Origin[1]+hautDoc,
      objRef,
      dxy,
      tabs,
      mask,
      VG,
      selg,
      sel = selection;

      for (var j = 0; j < sel.length; j++){

        mask = false;
        objRef = sel[j];
        if (objRef.guides) continue;
        tabs  = [];
          if (objRef.typename == "GroupItem" && AdjustMask) {
            selg = objRef.pageItems;
            detectclippingInGrp(selg,tabs);
          }
        VG = visibleBds ? objRef.visibleBounds : objRef.geometricBounds;

            if (tabs.length > 0 && mask) {
              getCadre(VG,tabs);
            }
             dxy = TopCenter(VG,origX,origY);
             // -------
        objRef.translate(dxy[0],dxy[1]);
        objRef.selected = false;
            if (entourRect) {
              var cadre= enCadre(doc,VG,4);
                  cadre.translate(dxy[0],dxy[1]);
            }
      }
}
// -------
function TopCenter(v,X,Y) {
    var dx = X - v[0] + (activeDocument.width-(v[2]-v[0]))/2,
        dy = Y - v[1];
  return [dx,dy];
}
// -------
function getCadre(VG,tabs) {
  var xmin, ymin, xmax, ymax, vi;
      xmin = ymin =  Infinity;
      xmax = ymax = -Infinity;
            for (var i = 0; i < tabs.length; i++){
              vi = visibleBds ? tabs[i].visibleBounds : tabs[i].geometricBounds;
              xmin = Math.min(vi[0],xmin);
              ymax = Math.max(vi[1],ymax);
              xmax = Math.max(vi[2],xmax);
              ymin = Math.min(vi[3],ymin);
            }
                if (VG[0] < xmin) VG[0] = xmin;
                if (VG[1] > ymax) VG[1] = ymax;
                if (VG[2] > xmax) VG[2] = xmax;
                if (VG[3] < ymin) VG[3] = ymin;
}
// -------
function detectclippingInGrp (grp,tabs){
  // Global variable mask
  var item;
    for(var i = 0; i < grp.length; i++){
      item = grp[i];
      if (item.clipping) {tabs.push(item); mask = true; return;}
        if (item.typename == "GroupItem") {
            if (item.clipped) {
              tabs.push(item.pageItems[0]); mask = true; // alert('clipping');
            }
            else {detectclippingInGrp(item,tabs);}
        }
        else tabs.push(item);
      }
}
// -------
function enCadre(doc,VG,color){
        var cadre = doc.pathItems.rectangle(VG[1],VG[0],VG[2]-VG[0],VG[1]-VG[3]);
            cadre.filled = false;
            //cadre.selected = true;
            cadre.stroked = true;
            cadre.strokeWidth = 2;
            cadre.strokeColor = doc.swatches[color].color;
            return cadre;
}
// -------

Moins complète que la votre @jduncan ...

René

Votes

Translate

Translate

Report

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