在 JavaScript 中管理 PowerPoint 文本段落

概述

Aspose.Slides for Node.js via Java 将文本表示为文本框、段落和区块的层次结构:

  • TextFrame 表示形状中的文本容器,并提供对其段落集合的访问。
  • Paragraph 表示文本框中的一个段落,并提供对其区块和段落级别格式的访问。
  • Portion 表示段落内的一个文本运行。每个区块可以拥有自己的文本和字符级别格式。

因此,一个段落可以通过使用多个区块来包含不同字体、颜色、大小和其他格式的文本。

创建和格式化段落

在形状的文本框中创建段落,并使用区块来格式化各个文本运行。本节演示如何在每个段落中组合多个区块并应用不同的颜色、字体大小和样式。

创建包含多个区块的段落

以下 JavaScript 示例创建了三个段落,每个段落包含三个由 Paragraph.getPortions 返回的文本运行。它复用默认段落及其空区块,然后添加其余的段落和区块。格式通过 Portion.getPortionFormat 应用:每个段落的第一个区块为红色、加粗、15 磅;第二个为蓝色、斜体、18 磅。第三个区块保留默认格式:

var aspose = aspose || {};
aspose.slides = require("aspose.slides.via.java");
const java = require("java");

const presentation = new aspose.slides.Presentation();
try {
    const slide = presentation.getSlides().get_Item(0);

    const shape = slide.getShapes().addAutoShape(aspose.slides.ShapeType.Rectangle, 50, 150, 300, 150);
    const textFrame = shape.getTextFrame();

    const firstParagraph = textFrame.getParagraphs().get_Item(0);
    firstParagraph.getPortions().add(new aspose.slides.Portion());
    firstParagraph.getPortions().add(new aspose.slides.Portion());

    const secondParagraph = new aspose.slides.Paragraph();
    secondParagraph.getPortions().add(new aspose.slides.Portion());
    secondParagraph.getPortions().add(new aspose.slides.Portion());
    secondParagraph.getPortions().add(new aspose.slides.Portion());
    textFrame.getParagraphs().add(secondParagraph);

    const thirdParagraph = new aspose.slides.Paragraph();
    thirdParagraph.getPortions().add(new aspose.slides.Portion());
    thirdParagraph.getPortions().add(new aspose.slides.Portion());
    thirdParagraph.getPortions().add(new aspose.slides.Portion());
    textFrame.getParagraphs().add(thirdParagraph);

    const paragraphCount = textFrame.getParagraphs().getCount();
    for (let paragraphIndex = 0; paragraphIndex < paragraphCount; paragraphIndex++) {
        const paragraph = textFrame.getParagraphs().get_Item(paragraphIndex);
        const portionCount = paragraph.getPortions().getCount();
        for (let portionIndex = 0; portionIndex < portionCount; portionIndex++) {
            const portion = paragraph.getPortions().get_Item(portionIndex);
            portion.setText("Portion " + (paragraphIndex + 1) + "." + (portionIndex + 1));

            if (portionIndex === 0) {
                portion.getPortionFormat().getFillFormat().setFillType(java.newByte(aspose.slides.FillType.Solid));
                portion.getPortionFormat().getFillFormat().getSolidFillColor().setColor(java.getStaticFieldValue("java.awt.Color", "RED"));
                portion.getPortionFormat().setFontBold(java.newByte(aspose.slides.NullableBool.True));
                portion.getPortionFormat().setFontHeight(15);
            } else if (portionIndex === 1) {
                portion.getPortionFormat().getFillFormat().setFillType(java.newByte(aspose.slides.FillType.Solid));
                portion.getPortionFormat().getFillFormat().getSolidFillColor().setColor(java.getStaticFieldValue("java.awt.Color", "BLUE"));
                portion.getPortionFormat().setFontItalic(java.newByte(aspose.slides.NullableBool.True));
                portion.getPortionFormat().setFontHeight(18);
            }
        }
    }

    presentation.save("paragraphs_with_portions.pptx", aspose.slides.SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

创建项目符号和编号列表

将段落文本组织为符号、数字或自定义图像列表。本节示例涵盖项目符号格式、多层列表以及自定义起始编号。

创建项目符号或编号列表

项目符号和编号使相关项目更易浏览。在 Aspose.Slides 中,列表设置通过 BulletFormat 定义。

此 JavaScript 示例在同一个文本框中添加了符号项目符号和编号项。BulletFormat.setType 选择项目符号类型,而 BulletFormat.setChar 提供符号并且 BulletFormat.setNumberedBulletStyle 选择编号样式。两个项目均使用黑色项目符号,高度为 100%,段落缩进为 25 磅:

var aspose = aspose || {};
aspose.slides = require("aspose.slides.via.java");
const java = require("java");

const presentation = new aspose.slides.Presentation();
try {
    const slide = presentation.getSlides().get_Item(0);

    const shape = slide.getShapes().addAutoShape(aspose.slides.ShapeType.Rectangle, 200, 200, 400, 200);
    const textFrame = shape.getTextFrame();
    textFrame.getParagraphs().clear();

    const symbolParagraph = new aspose.slides.Paragraph();
    symbolParagraph.setText("Welcome to Aspose.Slides");
    symbolParagraph.getParagraphFormat().getBullet().setType(java.newByte(aspose.slides.BulletType.Symbol));
    symbolParagraph.getParagraphFormat().getBullet().setChar(java.newChar(0x2022));
    symbolParagraph.getParagraphFormat().setIndent(25);
    symbolParagraph.getParagraphFormat().getBullet().getColor().setColorType(aspose.slides.ColorType.RGB);
    symbolParagraph.getParagraphFormat().getBullet().getColor().setColor(java.getStaticFieldValue("java.awt.Color", "BLACK"));
    symbolParagraph.getParagraphFormat().getBullet().setBulletHardColor(java.newByte(aspose.slides.NullableBool.True));
    symbolParagraph.getParagraphFormat().getBullet().setHeight(100);
    textFrame.getParagraphs().add(symbolParagraph);

    const numberedParagraph = new aspose.slides.Paragraph();
    numberedParagraph.setText("This is a numbered item");
    numberedParagraph.getParagraphFormat().getBullet().setType(java.newByte(aspose.slides.BulletType.Numbered));
    numberedParagraph.getParagraphFormat().getBullet().setNumberedBulletStyle(java.newByte(aspose.slides.NumberedBulletStyle.BulletCircleNumWDBlackPlain));
    numberedParagraph.getParagraphFormat().setIndent(25);
    numberedParagraph.getParagraphFormat().getBullet().getColor().setColorType(aspose.slides.ColorType.RGB);
    numberedParagraph.getParagraphFormat().getBullet().getColor().setColor(java.getStaticFieldValue("java.awt.Color", "BLACK"));
    numberedParagraph.getParagraphFormat().getBullet().setBulletHardColor(java.newByte(aspose.slides.NullableBool.True));
    numberedParagraph.getParagraphFormat().getBullet().setHeight(100);
    textFrame.getParagraphs().add(numberedParagraph);

    presentation.save("bulleted_and_numbered_list.pptx", aspose.slides.SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

使用图片项目符号

图片项目符号允许使用自定义图像代替符号或数字。

此 JavaScript 示例从应用程序工作目录加载 image.png,将图像添加到演示文稿的图像集合中作为 PPImage,并将其用作段落项目符号。它调用 BulletFormat.setType 使用图片项目符号,并通过 BulletFormat.getPicture 赋予图像。BulletFormat.setHeight 设置为 100% 以相对于段落文本确定项目符号大小:

var aspose = aspose || {};
aspose.slides = require("aspose.slides.via.java");
const java = require("java");

const presentation = new aspose.slides.Presentation();
try {
    const slide = presentation.getSlides().get_Item(0);

    const bulletImage = aspose.slides.Images.fromFile("image.png");
    let presentationImage;
    try {
        presentationImage = presentation.getImages().addImage(bulletImage);
    } finally {
        bulletImage.dispose();
    }

    const shape = slide.getShapes().addAutoShape(aspose.slides.ShapeType.Rectangle, 200, 200, 400, 200);
    const textFrame = shape.getTextFrame();
    textFrame.getParagraphs().clear();

    const paragraph = new aspose.slides.Paragraph();
    paragraph.setText("Welcome to Aspose.Slides");
    paragraph.getParagraphFormat().getBullet().setType(java.newByte(aspose.slides.BulletType.Picture));
    paragraph.getParagraphFormat().getBullet().getPicture().setImage(presentationImage);
    paragraph.getParagraphFormat().getBullet().setHeight(100);
    textFrame.getParagraphs().add(paragraph);

    presentation.save("picture_bullet.pptx", aspose.slides.SaveFormat.Pptx);
    presentation.save("picture_bullet.ppt", aspose.slides.SaveFormat.Ppt);
} finally {
    presentation.dispose();
}

创建多层列表

通过设置 ParagraphFormat.setDepth 将段落放置在列表的不同层级。顶层的深度为 0。

此 JavaScript 示例为四个段落分别分配 0 到 3 的 ParagraphFormat.setDepth 值,以在同一个文本框内创建层次结构。每个段落使用符号项目符号,利用 BulletFormat.setChar 在圆形项目符号和连字符之间交替,以区分相邻层级:

var aspose = aspose || {};
aspose.slides = require("aspose.slides.via.java");
const java = require("java");

const presentation = new aspose.slides.Presentation();
try {
    const slide = presentation.getSlides().get_Item(0);

    const shape = slide.getShapes().addAutoShape(aspose.slides.ShapeType.Rectangle, 200, 200, 400, 200);
    const textFrame = shape.getTextFrame();
    textFrame.getParagraphs().clear();

    const firstParagraph = new aspose.slides.Paragraph();
    firstParagraph.setText("Content");
    firstParagraph.getParagraphFormat().getBullet().setType(java.newByte(aspose.slides.BulletType.Symbol));
    firstParagraph.getParagraphFormat().getBullet().setChar(java.newChar(0x2022));
    firstParagraph.getParagraphFormat().getDefaultPortionFormat().getFillFormat().setFillType(java.newByte(aspose.slides.FillType.Solid));
    firstParagraph.getParagraphFormat().getDefaultPortionFormat().getFillFormat().getSolidFillColor().setColor(java.getStaticFieldValue("java.awt.Color", "BLACK"));
    firstParagraph.getParagraphFormat().setDepth(java.newShort(0));

    const secondParagraph = new aspose.slides.Paragraph();
    secondParagraph.setText("Second level");
    secondParagraph.getParagraphFormat().getBullet().setType(java.newByte(aspose.slides.BulletType.Symbol));
    secondParagraph.getParagraphFormat().getBullet().setChar(java.newChar(45));
    secondParagraph.getParagraphFormat().getDefaultPortionFormat().getFillFormat().setFillType(java.newByte(aspose.slides.FillType.Solid));
    secondParagraph.getParagraphFormat().getDefaultPortionFormat().getFillFormat().getSolidFillColor().setColor(java.getStaticFieldValue("java.awt.Color", "BLACK"));
    secondParagraph.getParagraphFormat().setDepth(java.newShort(1));

    const thirdParagraph = new aspose.slides.Paragraph();
    thirdParagraph.setText("Third level");
    thirdParagraph.getParagraphFormat().getBullet().setType(java.newByte(aspose.slides.BulletType.Symbol));
    thirdParagraph.getParagraphFormat().getBullet().setChar(java.newChar(0x2022));
    thirdParagraph.getParagraphFormat().getDefaultPortionFormat().getFillFormat().setFillType(java.newByte(aspose.slides.FillType.Solid));
    thirdParagraph.getParagraphFormat().getDefaultPortionFormat().getFillFormat().getSolidFillColor().setColor(java.getStaticFieldValue("java.awt.Color", "BLACK"));
    thirdParagraph.getParagraphFormat().setDepth(java.newShort(2));

    const fourthParagraph = new aspose.slides.Paragraph();
    fourthParagraph.setText("Fourth level");
    fourthParagraph.getParagraphFormat().getBullet().setType(java.newByte(aspose.slides.BulletType.Symbol));
    fourthParagraph.getParagraphFormat().getBullet().setChar(java.newChar(45));
    fourthParagraph.getParagraphFormat().getDefaultPortionFormat().getFillFormat().setFillType(java.newByte(aspose.slides.FillType.Solid));
    fourthParagraph.getParagraphFormat().getDefaultPortionFormat().getFillFormat().getSolidFillColor().setColor(java.getStaticFieldValue("java.awt.Color", "BLACK"));
    fourthParagraph.getParagraphFormat().setDepth(java.newShort(3));

    textFrame.getParagraphs().add(firstParagraph);
    textFrame.getParagraphs().add(secondParagraph);
    textFrame.getParagraphs().add(thirdParagraph);
    textFrame.getParagraphs().add(fourthParagraph);

    presentation.save("multilevel_list.pptx", aspose.slides.SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

自定义起始编号

使用 BulletFormat.setNumberedBulletStartWith 为编号段落设置显示的初始数字。

此 JavaScript 示例将 BulletFormat.setType 设置为使用编号,并为三个段落分别分配 2、3、7 的 BulletFormat.setNumberedBulletStartWith 值。起始值对每个段落单独配置,使显示的数字可以跳过:

var aspose = aspose || {};
aspose.slides = require("aspose.slides.via.java");
const java = require("java");

const presentation = new aspose.slides.Presentation();
try {
    const slide = presentation.getSlides().get_Item(0);

    const shape = slide.getShapes().addAutoShape(aspose.slides.ShapeType.Rectangle, 200, 200, 400, 200);
    const textFrame = shape.getTextFrame();
    textFrame.getParagraphs().clear();

    const firstParagraph = new aspose.slides.Paragraph();
    firstParagraph.setText("Start at 2");
    firstParagraph.getParagraphFormat().getBullet().setType(java.newByte(aspose.slides.BulletType.Numbered));
    firstParagraph.getParagraphFormat().getBullet().setNumberedBulletStartWith(java.newShort(2));
    textFrame.getParagraphs().add(firstParagraph);

    const secondParagraph = new aspose.slides.Paragraph();
    secondParagraph.setText("Start at 3");
    secondParagraph.getParagraphFormat().getBullet().setType(java.newByte(aspose.slides.BulletType.Numbered));
    secondParagraph.getParagraphFormat().getBullet().setNumberedBulletStartWith(java.newShort(3));
    textFrame.getParagraphs().add(secondParagraph);

    const thirdParagraph = new aspose.slides.Paragraph();
    thirdParagraph.setText("Start at 7");
    thirdParagraph.getParagraphFormat().getBullet().setType(java.newByte(aspose.slides.BulletType.Numbered));
    thirdParagraph.getParagraphFormat().getBullet().setNumberedBulletStartWith(java.newShort(7));
    textFrame.getParagraphs().add(thirdParagraph);

    presentation.save("custom_numbered_list.pptx", aspose.slides.SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

控制段落布局和结束属性

调整段落边距和缩进,以控制首行和换行行的位置。您还可以单独格式化段落结束标记,而不影响可见的文本区块。

设置首行缩进

使用 ParagraphFormat.setIndent 方法控制段落的首行缩进。此设置仅移动首行相对于段落左边距的距离。正值将首行向右移动,而其余行保持与段落正文对齐。

当需要整体移动段落时使用 ParagraphFormat.setMarginLeft;仅需移动首行时使用 ParagraphFormat.setIndent。

以下示例为三个段落设置相同的 ParagraphFormat.setMarginLeft 为 20 磅,且 ParagraphFormat.setIndent 分别为 0、20、40 磅。首行起始偏移逐步增大,而换行行保持相同的左边距:

var aspose = aspose || {};
aspose.slides = require("aspose.slides.via.java");
const java = require("java");

const presentation = new aspose.slides.Presentation();
try {
    const slide = presentation.getSlides().get_Item(0);

    const shape = slide.getShapes().addAutoShape(aspose.slides.ShapeType.Rectangle, 50, 50, 420, 220);
    shape.getFillFormat().setFillType(java.newByte(aspose.slides.FillType.NoFill));
    shape.getLineFormat().getFillFormat().setFillType(java.newByte(aspose.slides.FillType.Solid));
    shape.getLineFormat().getFillFormat().getSolidFillColor().setColor(java.getStaticFieldValue("java.awt.Color", "GRAY"));

    const textFrame = shape.getTextFrame();
    textFrame.getTextFrameFormat().setAutofitType(java.newByte(aspose.slides.TextAutofitType.Shape));
    textFrame.getParagraphs().clear();

    const firstParagraph = new aspose.slides.Paragraph();
    firstParagraph.setText("No first-line indent. Wrapped lines start at the same position as the first line.");
    firstParagraph.getParagraphFormat().getDefaultPortionFormat().getFillFormat().setFillType(java.newByte(aspose.slides.FillType.Solid));
    firstParagraph.getParagraphFormat().getDefaultPortionFormat().getFillFormat().getSolidFillColor().setColor(java.getStaticFieldValue("java.awt.Color", "BLACK"));
    firstParagraph.getParagraphFormat().setMarginLeft(20);
    firstParagraph.getParagraphFormat().setIndent(0);

    const secondParagraph = new aspose.slides.Paragraph();
    secondParagraph.setText("First-line indent of 20 points. The first line moves to the right, while wrapped lines remain aligned to the paragraph body.");
    secondParagraph.getParagraphFormat().getDefaultPortionFormat().getFillFormat().setFillType(java.newByte(aspose.slides.FillType.Solid));
    secondParagraph.getParagraphFormat().getDefaultPortionFormat().getFillFormat().getSolidFillColor().setColor(java.getStaticFieldValue("java.awt.Color", "BLACK"));
    secondParagraph.getParagraphFormat().setMarginLeft(20);
    secondParagraph.getParagraphFormat().setIndent(20);

    const thirdParagraph = new aspose.slides.Paragraph();
    thirdParagraph.setText("First-line indent of 40 points. This paragraph shows a larger first-line offset to make the effect easier to see.");
    thirdParagraph.getParagraphFormat().getDefaultPortionFormat().getFillFormat().setFillType(java.newByte(aspose.slides.FillType.Solid));
    thirdParagraph.getParagraphFormat().getDefaultPortionFormat().getFillFormat().getSolidFillColor().setColor(java.getStaticFieldValue("java.awt.Color", "BLACK"));
    thirdParagraph.getParagraphFormat().setMarginLeft(20);
    thirdParagraph.getParagraphFormat().setIndent(40);

    textFrame.getParagraphs().add(firstParagraph);
    textFrame.getParagraphs().add(secondParagraph);
    textFrame.getParagraphs().add(thirdParagraph);

    presentation.save("paragraph_indent.pptx", aspose.slides.SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

效果如下:

段落的首行缩进

设置悬挂缩进

悬挂缩进是一种段落布局,其中首行位于其余行的左侧。在 Aspose.Slides 中,可通过 ParagraphFormat.setIndent 方法实现此效果。将缩进设置为负值即可使首行相对于段落正文向左移动。

实际上,ParagraphFormat.setMarginLeft 定义段落正文的左侧位置,而 ParagraphFormat.setIndent 定义首行相对于该边距的位置。要创建悬挂缩进,请设置正的左边距并使用负的缩进值。

此格式在参考文献、书目、词汇表条目以及其他需要换行行对齐到段落正文而非首字符的段落中非常有用。

以下 JavaScript 示例将 ParagraphFormat.setMarginLeft 设置为 40 和 60 磅,分别配合 ParagraphFormat.setIndent 为 -20 和 -30 磅。在每个段落中,首行位于换行行左侧;第二个段落的悬挂缩进更深:

var aspose = aspose || {};
aspose.slides = require("aspose.slides.via.java");
const java = require("java");

const presentation = new aspose.slides.Presentation();
try {
    const slide = presentation.getSlides().get_Item(0);

    const shape = slide.getShapes().addAutoShape(aspose.slides.ShapeType.Rectangle, 50, 50, 420, 220);
    shape.getFillFormat().setFillType(java.newByte(aspose.slides.FillType.NoFill));
    shape.getLineFormat().getFillFormat().setFillType(java.newByte(aspose.slides.FillType.Solid));
    shape.getLineFormat().getFillFormat().getSolidFillColor().setColor(java.getStaticFieldValue("java.awt.Color", "GRAY"));

    const textFrame = shape.getTextFrame();
    textFrame.getTextFrameFormat().setAutofitType(java.newByte(aspose.slides.TextAutofitType.Shape));
    textFrame.getParagraphs().clear();

    const firstParagraph = new aspose.slides.Paragraph();
    firstParagraph.setText("A hanging indent is created by combining a positive left margin with a negative indent. The first line starts to the left, while wrapped lines align with the paragraph body.");
    firstParagraph.getParagraphFormat().getDefaultPortionFormat().getFillFormat().setFillType(java.newByte(aspose.slides.FillType.Solid));
    firstParagraph.getParagraphFormat().getDefaultPortionFormat().getFillFormat().getSolidFillColor().setColor(java.getStaticFieldValue("java.awt.Color", "BLACK"));
    firstParagraph.getParagraphFormat().setMarginLeft(40);
    firstParagraph.getParagraphFormat().setIndent(-20);

    const secondParagraph = new aspose.slides.Paragraph();
    secondParagraph.setText("This second example uses a deeper hanging indent so the difference between the first line and the wrapped lines is easier to compare.");
    secondParagraph.getParagraphFormat().getDefaultPortionFormat().getFillFormat().setFillType(java.newByte(aspose.slides.FillType.Solid));
    secondParagraph.getParagraphFormat().getDefaultPortionFormat().getFillFormat().getSolidFillColor().setColor(java.getStaticFieldValue("java.awt.Color", "BLACK"));
    secondParagraph.getParagraphFormat().setMarginLeft(60);
    secondParagraph.getParagraphFormat().setIndent(-30);

    textFrame.getParagraphs().add(firstParagraph);
    textFrame.getParagraphs().add(secondParagraph);

    presentation.save("hanging_indent.pptx", aspose.slides.SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

效果如下:

段落的悬挂缩进

设置段落结束运行属性

Paragraph.setEndParagraphPortionFormat 方法控制段落结束标记的格式。以下示例创建一个 PortionFormat ,其 BasePortionFormat.setFontHeight 为 48 磅,且 BasePortionFormat.setLatinFont 为 Times New Roman。将此格式分配给第二段落的结束标记,而保持可见文本区块不变:

var aspose = aspose || {};
aspose.slides = require("aspose.slides.via.java");

const presentation = new aspose.slides.Presentation();
try {
    const slide = presentation.getSlides().get_Item(0);

    const shape = slide.getShapes().addAutoShape(aspose.slides.ShapeType.Rectangle, 10, 10, 200, 250);
    const textFrame = shape.getTextFrame();
    textFrame.getParagraphs().clear();

    const firstParagraph = new aspose.slides.Paragraph();
    firstParagraph.getPortions().add(new aspose.slides.Portion("Sample text"));

    const secondParagraph = new aspose.slides.Paragraph();
    secondParagraph.getPortions().add(new aspose.slides.Portion("Sample text 2"));

    const endParagraphFormat = new aspose.slides.PortionFormat();
    endParagraphFormat.setFontHeight(48);
    endParagraphFormat.setLatinFont(new aspose.slides.FontData("Times New Roman"));
    secondParagraph.setEndParagraphPortionFormat(endParagraphFormat);

    textFrame.getParagraphs().add(firstParagraph);
    textFrame.getParagraphs().add(secondParagraph);

    presentation.save("end_paragraph_format.pptx", aspose.slides.SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

统计渲染行数

有关影响自动换行和行尾标点的段落规则,请参阅 控制换行 和 控制悬挂标点。

使用 Paragraph.getLinesCount 可统计段落在文本布局后占用的行数,包括自动换行。这在检查演示文稿模板中的文本长度和布局时非常有用。

段落是 TextFrame.getParagraphs 中的一个项目,可能会占用多行渲染的行数。段落内部的显式换行会强制另起一行,而不会创建新段落。自动换行根据可用宽度生成行,而不在文本中插入显式换行符。因此,仅统计段落或换行字符并不能得到渲染行数。

以下示例创建一个文本形状,统计其行数,随后缩窄形状并用更短的字符串替换文本。示例通过 TextFrameFormat.setWrapText 启用换行,并通过 TextFrameFormat.setAutofitType 禁用自动适配,以便形状宽度控制换行而不会自动缩小文本或调整形状大小。每次测量均使用 Paragraph.getLinesCount。形状尺寸单位为磅。最后,示例再添加一个段落并汇总文本框中的行数。

var aspose = aspose || {};
aspose.slides = require("aspose.slides.via.java");
const java = require("java");

const presentation = new aspose.slides.Presentation();
try {
    const slide = presentation.getSlides().get_Item(0);

    const shape = slide.getShapes().addAutoShape(aspose.slides.ShapeType.Rectangle, 50, 50, 400, 200);
    const textFrame = shape.getTextFrame();
    textFrame.getTextFrameFormat().setWrapText(java.newByte(aspose.slides.NullableBool.True));
    textFrame.getTextFrameFormat().setAutofitType(java.newByte(aspose.slides.TextAutofitType.None));

    const paragraph = textFrame.getParagraphs().get_Item(0);
    paragraph.getParagraphFormat().getDefaultPortionFormat().setFontHeight(20);
    paragraph.setText("This text demonstrates how automatic wrapping changes the number of rendered lines.");
    console.log("Original width: " + paragraph.getLinesCount());

    shape.setWidth(150);
    console.log("Narrower shape: " + paragraph.getLinesCount());

    paragraph.setText("Short text.");
    console.log("Shorter text: " + paragraph.getLinesCount());

    const secondParagraph = new aspose.slides.Paragraph();
    secondParagraph.setText("Another paragraph.");
    secondParagraph.getParagraphFormat().getDefaultPortionFormat().setFontHeight(20);
    textFrame.getParagraphs().add(secondParagraph);

    let totalLineCount = 0;
    for (let i = 0; i < textFrame.getParagraphs().getCount(); i++) {
        const currentParagraph = textFrame.getParagraphs().get_Item(i);
        totalLineCount += currentParagraph.getLinesCount();
    }
    console.log("Total lines in the text frame: " + totalLineCount);
} finally {
    presentation.dispose();
}

使用这些文本和尺寸,缩窄形状会增加行数,而用短字符串替换文本会减少行数。确切计数会因字体可用性、替代、字体大小、边距、缩进、换行和自动适配设置而异;请使用目标环境的字体和布局设置来检查模板。

仅凭行数无法判断文本是否溢出容器。可用高度、行高、段落和行间距以及自动适配行为也会影响;即使是一行文本,在禁用换行时也可能超出可用宽度。

导入和导出段落内容

使用 HTML 将文本导入演示文稿,或将现有段落导出以供外部使用。本节还展示如何将单个段落渲染为图像,包括表格单元格中的段落。

将 HTML 文本导入段落

使用 ParagraphCollection.addFromHtml 将 HTML 标记转换为文本框中的段落和区块。

此 JavaScript 示例从应用程序工作目录读取 file.html,并将标记传递给 ParagraphCollection.addFromHtml。它清除文本框的默认段落,使框只包含导入的内容。矩形形状在幻灯片的每一侧留有 10 磅的边距:

var aspose = aspose || {};
aspose.slides = require("aspose.slides.via.java");
const java = require("java");
const fs = require("fs");

const presentation = new aspose.slides.Presentation();
try {
    const slide = presentation.getSlides().get_Item(0);

    const shapeWidth = presentation.getSlideSize().getSize().getWidth() - 20;
    const shapeHeight = presentation.getSlideSize().getSize().getHeight() - 20;
    const shape = slide.getShapes().addAutoShape(aspose.slides.ShapeType.Rectangle, 10, 10, shapeWidth, shapeHeight);
    shape.getFillFormat().setFillType(java.newByte(aspose.slides.FillType.NoFill));
    shape.getTextFrame().getParagraphs().clear();

    const html = fs.readFileSync("file.html", "utf8");
    shape.getTextFrame().getParagraphs().addFromHtml(html);
    presentation.save("html_text.pptx", aspose.slides.SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

将段落文本导出为 HTML

使用 ParagraphCollection.exportToHtml 将选定范围的段落导出为 HTML。当在网站上复用演示文稿文本时,您可能希望保留局部强调,而不携带演示文稿的字体、大小或文本框样式。通过设置 TextToHtmlConversionOptions.setTextInheritanceLimit 来控制导出器在格式继承上的深度。

下载 示例演示文稿 并放置在应用程序工作目录中。它的第一张幻灯片包含一个文本形状,文本为 “Inherited text; explicit red 18pt”。输入故意使用了多个格式层级:

  • 演示文稿的默认文本样式提供 Calibri 字体和 28 pt 大小。
  • 文本框的一级文本样式提供蓝色文本和斜体。
  • 段落显式设置为粗体。
  • 第二个区块 “explicit red 18pt” 显式设置为红色文本和 18 pt 大小。

以下完整示例将相同段落导出三次。它将 TextToHtmlConversionOptions 传递给导出方法,并将每个结果写入单独的 UTF-8 HTML 文件:

var aspose = aspose || {};
aspose.slides = require("aspose.slides.via.java");
const java = require("java");
const fs = require("fs");

const presentation = new aspose.slides.Presentation("text-inheritance.pptx");
try {
    const shape = presentation.getSlides().get_Item(0).getShapes().get_Item(0);

    if (java.instanceOf(shape, "com.aspose.slides.IAutoShape")) {
        const textFrame = shape.getTextFrame();
        if (textFrame !== null) {
            const paragraphs = textFrame.getParagraphs();

            const modes = [aspose.slides.TextInheritanceLimit.All, aspose.slides.TextInheritanceLimit.TextBox, aspose.slides.TextInheritanceLimit.ParagraphOnly];
            const fileNames = ["All.html", "TextBox.html", "ParagraphOnly.html"];

            for (let i = 0; i < modes.length; i++) {
                const options = new aspose.slides.TextToHtmlConversionOptions();
                options.setTextInheritanceLimit(modes[i]);

                const html = paragraphs.exportToHtml(0, paragraphs.getCount(), options);
                fs.writeFileSync(fileNames[i], html, "utf8");
            }
        } else {
            console.log("The first shape does not contain a text frame.");
        }
    } else {
        console.log("The first shape is not a text shape.");
    }
} finally {
    presentation.dispose();
}

生成的 HTML 包含以下针对首个区块 “Inherited text; ” 的 CSS。表格列出了相关声明,其他生成的属性为简洁起见已省略。

输出 首个区块的相关 CSS 外观
All.html font-family:'Calibri'; font-size:28pt; color:#0000ff; font-style:italic; font-weight:bold 蓝色、粗体、斜体文字,字号 28pt,使用 Calibri(若该字体可用)。
TextBox.html color:#0000ff; font-style:italic; font-weight:bold 蓝色、粗体、斜体文字;页面或浏览器提供字体族和大小。
ParagraphOnly.html font-weight:bold 粗体文字;页面或浏览器提供字体族、大小、颜色和斜体样式。

第二个区块在所有三种输出中均保留 color:#ff0000、font-size:18pt 和 font-weight:bold。在 All 和 TextBox 中仍保留斜体,而 ParagraphOnly 中不保留。限制继承因此不会移除显式分配给段落或区块的格式。

在同一浏览器中打开这些文件进行比较。在两种受限模式下,省略的 CSS 属性由目标页面的样式或浏览器默认解析,因此最终外观取决于 HTML 的使用位置。

将段落渲染为图像

Paragraph.getImage 直接渲染单个段落并返回一个 IImage。使用 IImage.save 将结果保存为文件或流。无需渲染包含的形状或手动裁剪位图。

如果段落在其父集合中未找到、没有有效的渲染边界,或无法渲染,Paragraph.getImage 可能返回 null。在保存之前检查结果,并在使用后释放返回的图像。

以默认比例渲染段落

示例创建一个包含三段落的文本框幻灯片。

包含三个段落的文本框

以下示例在索引为 1 的位置选择第二段落,并在不传递比例参数的情况下调用 Paragraph.getImage。它检查形状是否包含所需段落以及渲染是否返回图像,然后调用 IImage.save 将其以 PNG 格式保存。finally 块在使用后释放图像。

var aspose = aspose || {};
aspose.slides = require("aspose.slides.via.java");
const java = require("java");

const presentation = new aspose.slides.Presentation();
try {
    const slide = presentation.getSlides().get_Item(0);

    const sourceShape = slide.getShapes().addAutoShape(aspose.slides.ShapeType.Rectangle, 20, 20, 400, 100);
    const sourceTextFrame = sourceShape.getTextFrame();
    sourceTextFrame.getParagraphs().clear();
    for (const text of ["First paragraph", "Second paragraph", "Third paragraph"]) {
        const sourceParagraph = new aspose.slides.Paragraph();
        sourceParagraph.setText(text);
        sourceTextFrame.getParagraphs().add(sourceParagraph);
    }
    const shape = slide.getShapes().get_Item(0);

    if (java.instanceOf(shape, "com.aspose.slides.IAutoShape")) {
        const textFrame = shape.getTextFrame();
        if (textFrame !== null && textFrame.getParagraphs().getCount() > 1) {
            const paragraph = textFrame.getParagraphs().get_Item(1);
            const paragraphImage = paragraph.getImage();

            if (paragraphImage !== null) {
                try {
                    paragraphImage.save("paragraph.png", aspose.slides.ImageFormat.Png);
                } finally {
                    paragraphImage.dispose();
                }
            } else {
                console.log("The paragraph could not be rendered.");
            }
        } else {
            console.log("The expected paragraph was not found.");
        }
    } else {
        console.log("The first shape is not a text shape.");
    }
} finally {
    presentation.dispose();
}

结果如下:

段落图像

在表格单元格中按比例渲染段落

使用接受 scaleX 和 scaleY 参数的 Paragraph.getImage 重载来设置水平和垂直比例因子。以下示例创建一个表格,在其第一个单元格中以默认宽高的两倍渲染段落,并将结果保存为 PNG 图像。

var aspose = aspose || {};
aspose.slides = require("aspose.slides.via.java");
const java = require("java");

const scaleX = 2;
const scaleY = 2;

const presentation = new aspose.slides.Presentation();
try {
    const slide = presentation.getSlides().get_Item(0);
    
    const columnWidths = java.newArray("double", [300]);
    const rowHeights = java.newArray("double", [80]);
    const table = slide.getShapes().addTable(50, 50, columnWidths, rowHeights);
    const paragraph = table.get_Item(0, 0).getTextFrame().getParagraphs().get_Item(0);
    paragraph.setText("Text in a table cell");

    const paragraphImage = paragraph.getImage(scaleX, scaleY);
    if (paragraphImage !== null) {
        try {
            paragraphImage.save("table_paragraph.png", aspose.slides.ImageFormat.Png);
        } finally {
            paragraphImage.dispose();
        }
    } else {
        console.log("The paragraph could not be rendered.");
    }
} finally {
    presentation.dispose();
}

比例因子为 1 时保持该轴的默认像素尺寸。例如,两个因子均为 2 时,生成的图像宽高约为默认尺寸的两倍,像素数为四倍。更大的因子通常可为放大或高分辨率输出提供更清晰的文本,但也会增加内存使用和文件大小。小于 1 的因子会生成更小且细节更少的图像。使用相等的因子可保持段落的宽高比;不同的水平和垂直因子会独立拉伸输出。

在需要包含形状填充、边框或其他视觉上下文的情况下,使用 Shape.getImage 渲染整个形状仍然有用。若仅需段落图像,请使用 Paragraph.getImage。

常见问题

我可以完全禁用文本框内的换行吗?

是的。将 TextFrameFormat.setWrapText 设置为禁用换行,使行不会在文本框的边缘断开。

如何获得特定段落在幻灯片上的精确边界?

使用 Paragraph.getRect 获取段落的边界矩形。Portion.getRect 提供单个区块的边界。

段落对齐方式(左、右、居中或两端对齐)在哪里控制?

ParagraphFormat.setAlignment 是段落级别的设置,适用于整个段落,而不受单个区块格式的影响。

要在每行中垂直对齐不同字体大小的区块,请参见 对齐行内字体。

我可以为段落的一部分设置校对语言吗?

可以。为单个区块设置 BasePortionFormat.setLanguageId,即可让同一段落包含多种语言的文本。