Python InDesign 脚本:从预检中获取溢出的文本框以自动调整大小

Python InDesign scripting: Get overflowing textbox from preflight for automatic resizing

感谢 ,我能够弄清楚如何 运行 使用 Python 和 InDesign 脚本 API 对我的文档进行印前检查。现在我想自动调整溢出文本框的文本大小,但无法弄清楚如何从 Preflight 对象中检索 TextBox 对象。

我提到了 API specification,但所有的属性似乎只产生不唯一定义文本框的字符串,如本例所示:

Errors Found (1):

  Text Frame (R=2)

有什么方法可以从预检中检索违规对象,以便稍后对其进行操作吗?非常感谢您对此事的额外投入,因为我被困住了!

如果您只需要查找并修复溢出错误,我建议您使用以下解决方案:

这是修复文本溢出错误的简单Extendscript。它减小了活动文档中所有溢出文本框中的字体大小:

var doc = app.activeDocument;

var frames = doc.textFrames.everyItem().getElements();
var f = frames.length

while(f--) {
    var frame = frames[f];
    if (frame.overflows) resize_font(frame)
}

function resize_font(frame) {
    app.scriptPreferences.enableRedraw = false;
    while (frame.overflows) {
        var texts = frame.parentStory.texts.everyItem().getElements();
        var t = texts.length;
        while(t--) {
            var characters = texts[t].characters.everyItem().getElements();
            var c = characters.length;
            while (c--) characters[c].pointSize = characters[c].pointSize * .99;
        }
    }
    app.scriptPreferences.enableRedraw = true;
}

您可以将它保存在任何文件夹中,然后 运行 通过 Python 脚本:

import win32com.client

app = win32com.client.Dispatch('InDesign.Application.CS6')
doc = app.Open(r'd:\temp\test.indd')

profile = app.PreflightProfiles.Item('Whosebug Profile')
print('Profile name:', profile.name)

process = app.PreflightProcesses.Add(doc, profile)
process.WaitForProcess()
errors = process.processResults
print('Errors:', errors)

if errors[:4] != 'None':
    script = r'd:\temp\fix_overset.jsx'  # <-- here is the script to fix overset
    print('Run script', script)
    app.DoScript(script, 1246973031)     # run the jsx script

    # 1246973031 --> ScriptLanguage.JAVASCRIPT
    # https://www.indesignjs.de/extendscriptAPI/indesign-latest/#ScriptLanguage.html

    process = app.PreflightProcesses.Add(doc, profile)
    process.WaitForProcess()
    errors = process.processResults
    print('Errors:', errors)             # it should print 'None'
    if errors[:4] == 'None':
        doc.Save()

doc.Close()

input('\nDone... Press <ENTER> to close the window')

多亏了Yuri的精彩解答,我才得以解决我的问题,虽然还有一些不足。

在 Python 中,我加载我的文档并检查预检期间是否检测到任何问题。如果是这样,我将继续调整文本框架。

myDoc = app.Open(input_file_path)

profile = app.PreflightProfiles.Item(1)
process = app.PreflightProcesses.Add(myDoc, profile)
process.WaitForProcess()
results = process.processResults

if "None" not in results:
    # Fix errors
    script = open("data/script.jsx")
    app.DoScript(script.read(), 1246973031, variables.resize_array)

    process.WaitForProcess()
    results = process.processResults

    # Check if problems were resolved
    if "None" not in results:
        info_fail(card.name, "Error while running preflight")
        myDoc.Close(1852776480)
        return FLAG_PREFLIGHT_FAIL

我加载存储在 script.jsx 中的 JavaScript 文件,该文件由多个组件组成。我首先提取参数并加载所有页面,因为我想单独处理它们。然后我将页面上的所有文本框收集到一个数组中。

var doc = app.activeDocument;
var pages = doc.pages;
var resizeGroup = arguments[0];
var condenseGroup = arguments[1];

// Loop over all available pages separately
for (var pageIndex = 0; pageIndex < pages.length; pageIndex++) {
    var page = pages[pageIndex];
    var pageItems = page.allPageItems;
    var textFrames = [];

    // Collect all TextFrames in an array
    for (var pageItemIndex = 0; pageItemIndex < pageItems.length; pageItemIndex++) {
        var candidate = pageItems[pageItemIndex];
        if (candidate instanceof TextFrame) {
            textFrames.push(candidate);
        }
    }

我想要实现的是这样一种设置,如果一组文本框中的一个文本框溢出,则该组中所有文本框的文本大小也会进行调整。例如。文本框1设置为8号时溢出,设置为6时不再溢出。由于文本框1与文本框2在同一组中,因此它们都将调整为6号(假设第二个框架不溢出)这个尺寸)。

为了处理这个问题,我传递了一个包含组的数组。我现在检查文本框架是否包含在这些组之一中(这很乏味,我不得不编写自己的方法,因为据我所知,InDesign 不支持像 filter() 这样的现代函数......) .

// Check if TextFrame overflows, if so add all TextFrames that should be the same size
    for (var textFrameIndex = 0; textFrameIndex < textFrames.length; textFrameIndex++) {
        var textFrame = textFrames[textFrameIndex];

        // If text frame overflows, adjust it and all the frames that are supposed to be of the same size
        if (textFrame.overflows) {
            var foundResizeGroup = filterArrayWithString(resizeGroup, textFrame.name);
            var foundCondenseGroup = filterArrayWithString(condenseGroup, textFrame.name);
            var process = false;
            var chosenGroup, type;

            if (foundResizeGroup.length > 0) {
                chosenGroup = foundResizeGroup;
                type = "resize";
                process = true;
            } else if (foundCondenseGroup.length > 0) {
                chosenGroup = foundCondenseGroup;
                type = "condense";
                process = true;
            }

            if (process) {
                var foundFrames = findTextFramesFromNames(textFrames, chosenGroup);
                adjustTextFrameGroup(foundFrames, type);
            }
        }
    }

如果是这种情况,我会调整文本大小或文本的第二轴(这会压缩我的可变字体的文本)。这是使用以下函数完成的:

function adjustTextFrameGroup(resizeGroup, type) {
    // Check if some overflowing textboxes
    if (!someOverflowing(resizeGroup)) {
        return;
    }

    app.scriptPreferences.enableRedraw = false;

    while (someOverflowing(resizeGroup)) {
        for (var textFrameIndex = 0; textFrameIndex < resizeGroup.length; textFrameIndex++) {
            var textFrame = resizeGroup[textFrameIndex];
            if (type === "resize") decreaseFontSize(textFrame);
            else if (type === "condense") condenseFont(textFrame);
            else alert("Unknown operation");
        }
    }

    app.scriptPreferences.enableRedraw = true;
}

function someOverflowing(textFrames) {
    for (var textFrameIndex = 0; textFrameIndex < textFrames.length; textFrameIndex++) {
        var textFrame = textFrames[textFrameIndex];
        if (textFrame.overflows) {
            return true;
        }
    }

    return false;
}

function decreaseFontSize(frame) {
    var texts = frame.parentStory.texts.everyItem().getElements();
    for (var textIndex = 0; textIndex < texts.length; textIndex++) {
        var characters = texts[textIndex].characters.everyItem().getElements();
        for (var characterIndex = 0; characterIndex < characters.length; characterIndex++) {
            characters[characterIndex].pointSize = characters[characterIndex].pointSize - 0.25;
        }
    }
}

function condenseFont(frame) {
    var texts = frame.parentStory.texts.everyItem().getElements();
    for (var textIndex = 0; textIndex < texts.length; textIndex++) {
        var characters = texts[textIndex].characters.everyItem().getElements();
        for (var characterIndex = 0; characterIndex < characters.length; characterIndex++) {
            characters[characterIndex].setNthDesignAxis(1, characters[characterIndex].designAxes[1] - 5)
        }
    }
}

我知道可以改进此代码(并且愿意接受反馈),例如,如果一个组由多个文本框组成,该过程将为所有这些框 运行,即使它需要只能 运行 一次。我对旧的 JavaScript 感到非常沮丧,而且影响可以忽略不计。其余函数也只是辅助函数,我想用更现代的版本替换它们。遗憾的是,如前所述,我认为它们根本不可用。

再次感谢尤里,她给了我很大的帮助!