Photoshop 脚本从文档的每一面裁剪 x 像素

Photoshop scripting crop away x pixels from every side of document

我有很多像这样的图片需要批量处理:

我想要完成的是剪掉每一边的边框,但这里有一个问题:修剪不起作用,因为图像每个角落的颜色都不是黑色而是白色,所以我改为'试图在每一侧裁掉大约 5 个像素。我已经写了一些代码来做到这一点,但似乎某处有错误导致有趣、镜像和错误裁剪的图像:

function cropLayerToBounds(){
var layer = activeDocument.activeLayer; //Grab the currently selected layer

// get height and width
var actualHeight = layer.bounds[2]-layer.bounds[0]; //Grab the height
var actualWidth = layer.bounds[3]-layer.bounds[1]; //Grab the width

// calculate desired height and width
var desiredHeight = actualHeight - 5;
var desiredWidth = actualWidth - 5;

// not sure if necessary
    var doc = app.activeDocument;
    var halfWidth = (desiredWidth/2);
    var halfHeight = (desiredHeight/2);
    var centerX = (doc.width/2);
    var centerY = (doc.height/2);

// error seems to be here

   // tried this
   var bounds = [0,0,desiredHeight,desiredWidth];

   // and this
   var bounds = [(centerX-halfWidth),(centerY-halfHeight),(centerX+halfWidth),(centerY+halfHeight)];

    doc.crop(bounds);


}

我用这种方式处理的图像看起来有点像这样:

以下脚本使用名为 cropCanvas 的自定义函数来满足您的要求。

没有必要访问 activeDocument.activeLayer,因为裁剪会影响整个文档(即 canvas)。

示例要点:

var document = app.activeDocument; // Assumes a document is active.

// Obtain original ruler units prefs.
var originalRulerUnits = app.preferences.rulerUnits;

// Set the ruler units prefs to pixels.
app.preferences.rulerUnits = Units.PIXELS;

/**
 * Crops the canvas by x number of pixels equally from all sides.
 * @param {Number} [amountOfPixels=0] - Number of pixels to crop.
 */
function cropCanvas(amountOfPixels) {
    amountOfPixels = amountOfPixels || 0; // Defaults to zero.

    // Obtain height and width of canvas.
    var canvasWidth = document.width.value;
    var canvasHeight = document.height.value;

    // Define the new bounds.
    var newBounds = [
        amountOfPixels,
        amountOfPixels,
        canvasWidth - amountOfPixels,
        canvasHeight - amountOfPixels
    ];

    // Crop the canvas. 
    document.crop(newBounds);
}

// Invoke the `cropCanvas` function passing
// in the `amountOfPixels` value.
cropCanvas(5);

// Reset ruler prefs.
app.preferences.rulerUnits = originalRulerUnits;

备注:

  1. 脚本最初通过 app.preferences.rulerUnits; 获取 Photoshop 的当前标尺单位,并将其分配给 originalRulerUnits 变量,然后再将标尺单位设置为像素。

  2. cropCanvas(...)函数有一个参数,即amountOfPixels。这使得可以使用一个参数调用该函数,该参数指定裁剪图像所依据的像素数量。例如:

    cropCanvas(5); // Crops 5 x pixels from all sides.
    
    cropCanvas(25); // Crops 25 x pixels from all sides.
    
  3. 最后,Photoshop 的标尺单位被重置为其原始单位。


其他注意事项

不设置 app.preferences.rulerUnits = Units.PIXELS; 会导致根据您的问题中显示的示例进行不正确的裁剪。但是,当 Photoshop 的 标尺原点 的坐标 而不是 设置为 (0,0).

时,也会产生意想不到的结果

为了说明这个潜在的问题,请执行以下操作:

  1. 打开图像 PhotoShop。
  2. 通过键入 Command+R(macOS)控制+R(Windows)
  3. 通过将 pointer/cursor 放置在 window 左上角的标尺交叉点上来更改标尺的零原点,然后沿对角线向下拖动到图像上。将出现一组十字线,标记标尺的新起点。进一步解释here
  4. 然后 运行 上面提供的示例要点。

如您所见,当标尺的零原点未设置为零时,可能会出现不希望的裁剪。

通过双击标尺的左上角,可以将标尺原点重置为默认值(即 0,0)。

重要提示: 现在,正如您在问题中提到的那样,这对您来说应该不是什么大问题 "...需要作为批处理。",这表明您的最终脚本将以编程方式逐个打开图像(即自动化)。打开图像时,标尺原点默认为 0,0,因此不会发生不需要的裁剪。

但是,在脚本的一个功能是允许它 运行 在用户打开的图像上并且可能已经定义了新的标尺原点的情况下。然后您的脚本还需要将标尺原点重置为零(即 0,0)。

处理非零标尺原点的示例要点:

var document = app.activeDocument; // Assumes a document is active.

// Obtain original ruler units prefs.
var originalRulerUnits = app.preferences.rulerUnits;

// Set the ruler units prefs to pixels.
app.preferences.rulerUnits = Units.PIXELS;

/**
 * Photoshop API doesn't provide a method to reset the ruler origin to [0, 0].
 * This get the cuurent ruler origin so we can offset the value.
 * @returns {Object} with properties `x` and `y` offset for rulers.
 */
function getRulerOffset() {
    var ref = new ActionReference();

    ref.putEnumerated(
        charIDToTypeID("Dcmn"),
        charIDToTypeID("Ordn"),
        charIDToTypeID("Trgt")
    );
    var desc = executeActionGet(ref);

    var rulerPositionX = desc.getInteger(stringIDToTypeID('rulerOriginH')) / 65536;
    var rulerPositionY = desc.getInteger(stringIDToTypeID('rulerOriginV')) / 65536;

    return {
        x : rulerPositionX,
        y : rulerPositionY
    }
}

/**
 * Crops the canvas by x number of pixels equally from all sides.
 * @param {Number} [amountOfPixels=0] - Number of pixels to crop.
 */
function cropCanvas(amountOfPixels) {
    amountOfPixels = amountOfPixels || 0; // Defaults to zero.

    // Obtain height and width of canvas.
    var canvasWidth = document.width.value;
    var canvasHeight = document.height.value;

    // Obtain current ruler x and y offset.
    var rulerOffsetX = getRulerOffset().x;
    var rulerOffsetY = getRulerOffset().y;

    // Define the new bounds.
    var newBounds = [
        amountOfPixels - rulerOffsetX,
        amountOfPixels - rulerOffsetY,
        canvasWidth - amountOfPixels - rulerOffsetX,
        canvasHeight - amountOfPixels - rulerOffsetY
    ];

    // Crop the canvas. 
    document.crop(newBounds);
}

// Invoke the `cropCanvas` function passing
// in the `amountOfPixels` value.
cropCanvas(5);

// Reset ruler prefs.
app.preferences.rulerUnits = originalRulerUnits;

修改后的脚本(以上)现在除了以前的要点外还包括:

  1. 一个新函数,即getRulerOffset,即returns当前xy标尺原点的坐标。不幸的是,Photoshop 不提供可以调用以重置标尺原点的 API,因此我们必须获取当前值。

  2. cropCanvas函数中,我们现在额外创建了两个新变量(rulerOffsetXrulerOffsetY),并且在定义[=31时减去它们的值=]变量.


另一个利用resizeCanvas()方法的解决方案

满足您要求的另一种方法是使用 resizeCanvas() 方法而不是 crop() 方法。我实际上更喜欢这种方法,因为 标尺原点 的位置(如 "Additional considerations" 部分所述)没有影响。

这里有一个要点:

var document = app.activeDocument;

// Obtain original ruler units prefs.
var originalRulerUnits = app.preferences.rulerUnits;

// Set the ruler units prefs to pixels.
app.preferences.rulerUnits = Units.PIXELS;

/**
 * Resizes canvas removing x number of pixels equally from all sides.
 * @param {Number} [amountOfPixels=0] - Number of pixels to remove.
 */
function removePixelsFromAllSides(amountOfPixels) {
    amountOfPixels = amountOfPixels || 0;

    document.resizeCanvas(
       document.width.value - (amountOfPixels * 2),
       document.height.value - (amountOfPixels * 2),
       AnchorPosition.MIDDLECENTER
    );
}

// Invoke the function passing in the `amountOfPixels` value.
removePixelsFromAllSides(5);

// Reset ruler prefs.
app.preferences.rulerUnits = originalRulerUnits;