Рендеринг слайдов презентаций как SVG‑изображения в JavaScript

Обзор

SVG — масштабируемый основанный на XML формат изображений, который хорошо подходит для веб‑публикации, просмотров слайдов, рабочих процессов доступности и автоматической пост‑обработки. Aspose.Slides for Node.js via Java экспортирует каждый слайд в отдельный файл SVG и позволяет управлять тем, как записываются текст, шрифты, изображения и элементы SVG.

Используйте SVGOptions когда экспортированный SVG должен быть компактным, предсказуемым во всех браузерах или готовым к интерактивному использованию.

Экспорт слайда в SVG

Создайте Presentation, выберите слайд и запишите его в поток с помощью Slide.writeAsSvg. Приведённый ниже пример экспортирует каждый слайд презентации в отдельный файл SVG.

const slides = require("aspose.slides.via.java");
const java = require("java");

const presentation = new slides.Presentation("presentation.pptx");
try {
    const slideCount = presentation.getSlides().size();
    for (let slideIndex = 0; slideIndex < slideCount; slideIndex++) {
        const slide = presentation.getSlides().get_Item(slideIndex);
        const outputFileName = `slide-${slide.getSlideNumber()}.svg`;
        const svgStream = java.newInstanceSync("java.io.FileOutputStream", outputFileName);
        try {
            slide.writeAsSvg(svgStream);
        } finally {
            svgStream.close();
        }
    }
} finally {
    presentation.dispose();
}

Имя файла формируется с помощью Slide.getSlideNumber, а не индекса цикла. Вы также можете экспортировать отдельную форму с помощью Shape.writeAsSvg, если просмотрщик слайдов или веб‑страница требуется только эта форма.

Настройка вывода SVG

SVGOptions управляет рендерингом SVG. Для текстовых рамок SVGOptions.setUseFrameSize включает рамку текста в область рендеринга, а SVGOptions.setUseFrameRotation определяет, применяется ли вращение рамки. Установите SVGOptions.setDisableFontLigatures в true, когда текст должен рендериться без лигатур.

const slides = require("aspose.slides.via.java");
const java = require("java");

const presentation = new slides.Presentation("presentation.pptx");
try {
    const svgOptions = new slides.SVGOptions();
    svgOptions.setDisableFontLigatures(true);
    svgOptions.setUseFrameSize(true);
    svgOptions.setUseFrameRotation(false);

    const slide = presentation.getSlides().get_Item(0);
    const svgStream = java.newInstanceSync(
        "java.io.FileOutputStream",
        "slide-with-custom-options.svg"
    );
    try {
        slide.writeAsSvg(svgStream, svgOptions);
    } finally {
        svgStream.close();
    }
} finally {
    presentation.dispose();
}

Управление текстом и шрифтами

Векторизация всего текста

Установите SVGOptions.setVectorizeText в true, чтобы записать весь текст слайда в виде векторной графики. Это устраняет зависимости от шрифтов и делает визуальный результат более согласованным во всех браузерах, но текст больше нельзя будет выделять или искать как SVG‑текст.

const slides = require("aspose.slides.via.java");
const java = require("java");

const presentation = new slides.Presentation("presentation.pptx");
try {
    const svgOptions = new slides.SVGOptions();
    svgOptions.setVectorizeText(true);

    const slide = presentation.getSlides().get_Item(0);
    const svgStream = java.newInstanceSync(
        "java.io.FileOutputStream",
        "slide-with-vectorized-text.svg"
    );
    try {
        slide.writeAsSvg(svgStream, svgOptions);
    } finally {
        svgStream.close();
    }
} finally {
    presentation.dispose();
}

Выбор способа обработки внешних шрифтов

SVGOptions.setExternalFontsHandling использует значение SvgExternalFontsHandling для шрифтов, загружаемых извне. Выберите AddLinksToFontFiles, чтобы ссылаться на отдельные файлы шрифтов, Embed, чтобы включить данные шрифта в SVG, или Vectorize, чтобы отрисовывать только текст, использующий внешние шрифты, как графику. Проверьте лицензирование шрифтов перед их встраиванием.

const slides = require("aspose.slides.via.java");
const java = require("java");

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

    const linkedFontsOptions = new slides.SVGOptions();
    linkedFontsOptions.setExternalFontsHandling(
        slides.SvgExternalFontsHandling.AddLinksToFontFiles
    );
    const linkedFontsStream = java.newInstanceSync(
        "java.io.FileOutputStream",
        "slide-with-font-links.svg"
    );
    try {
        slide.writeAsSvg(linkedFontsStream, linkedFontsOptions);
    } finally {
        linkedFontsStream.close();
    }

    const embeddedFontsOptions = new slides.SVGOptions();
    embeddedFontsOptions.setExternalFontsHandling(
        slides.SvgExternalFontsHandling.Embed
    );
    const embeddedFontsStream = java.newInstanceSync(
        "java.io.FileOutputStream",
        "slide-with-embedded-fonts.svg"
    );
    try {
        slide.writeAsSvg(embeddedFontsStream, embeddedFontsOptions);
    } finally {
        embeddedFontsStream.close();
    }

    const vectorizedExternalFontsOptions = new slides.SVGOptions();
    vectorizedExternalFontsOptions.setExternalFontsHandling(
        slides.SvgExternalFontsHandling.Vectorize
    );
    const vectorizedExternalFontsStream = java.newInstanceSync(
        "java.io.FileOutputStream",
        "slide-with-vectorized-external-fonts.svg"
    );
    try {
        slide.writeAsSvg(vectorizedExternalFontsStream, vectorizedExternalFontsOptions);
    } finally {
        vectorizedExternalFontsStream.close();
    }
} finally {
    presentation.dispose();
}

Сокращение размера внедрённых изображений

Используйте SVGOptions.setPicturesCompression, чтобы уменьшить разрешение внедрённых изображений, SVGOptions.setDeletePicturesCroppedAreas, чтобы исключить обрезанные области исходных изображений, и SVGOptions.setJpegQuality, чтобы управлять качеством кодирования JPEG. Эти параметры уменьшают размер файла за счёт точности изображения или сохранённых данных изображения.

const slides = require("aspose.slides.via.java");
const java = require("java");

const presentation = new slides.Presentation("presentation.pptx");
try {
    const svgOptions = new slides.SVGOptions();
    svgOptions.setPicturesCompression(slides.PicturesCompression.Dpi150);
    svgOptions.setDeletePicturesCroppedAreas(true);
    svgOptions.setJpegQuality(80);

    const slide = presentation.getSlides().get_Item(0);
    const svgStream = java.newInstanceSync("java.io.FileOutputStream", "compressed-slide.svg");
    try {
        slide.writeAsSvg(svgStream, svgOptions);
    } finally {
        svgStream.close();
    }
} finally {
    presentation.dispose();
}

Назначение стабильных идентификаторов формам и тексту

Передайте контроллер форматирования в SVGOptions.setShapeFormattingController, чтобы задать SvgShape.setId для каждой формы SVG. Контроллер, который также обрабатывает текстовые спаны, может задавать значения SvgTSpan.setId у элементов текста tspan.

Следующий контроллер использует Shape.getOfficeInteropShapeId, который стабилен в течение срока жизни формы, и повторяемый счётчик для её текстовых спанов. Это делает сгенерированные идентификаторы пригодными для пост‑обработки неизменённой презентации.

const slides = require("aspose.slides.via.java");
const java = require("java");

class StableSvgIdController {
    constructor() {
        this.currentShapeId = "";
        this.textSpanIndex = 0;
    }

    formatShape(svgShape, shape) {
        this.currentShapeId = `shape-${shape.getOfficeInteropShapeId()}`;
        this.textSpanIndex = 0;
        svgShape.setId(this.currentShapeId);
    }

    formatText(svgTSpan, portion, textFrame) {
        const textSpanId = `${this.currentShapeId}-text-${this.textSpanIndex++}`;
        svgTSpan.setId(textSpanId);
    }

    createProxy() {
        const controller = this;
        const interfaceName = "com.aspose.slides.ISvgShapeAndTextFormattingController";
        const proxyMethods = {
            formatShape(svgShape, shape) {
                controller.formatShape(svgShape, shape);
            },
            formatText(svgTSpan, portion, textFrame) {
                controller.formatText(svgTSpan, portion, textFrame);
            }
        };
        return java.newProxy(interfaceName, proxyMethods);
    }
}

const presentation = new slides.Presentation("presentation.pptx");
try {
    const svgOptions = new slides.SVGOptions();
    const stableSvgIdController = new StableSvgIdController();
    const controllerProxy = stableSvgIdController.createProxy();
    svgOptions.setShapeFormattingController(controllerProxy);

    const slide = presentation.getSlides().get_Item(0);
    const svgStream = java.newInstanceSync(
        "java.io.FileOutputStream",
        "slide-with-stable-ids.svg"
    );
    try {
        slide.writeAsSvg(svgStream, svgOptions);
    } finally {
        svgStream.close();
    }
} finally {
    presentation.dispose();
}

Добавление обработчиков событий SVG

В контроллере форматирования вызовите SvgShape.setEventHandler с параметром SvgEvent, чтобы добавить обработчик JavaScript к экспортируемой форме. Назначьте контроллер с помощью SVGOptions.setShapeFormattingController и определите JavaScript‑функцию на странице или в документе SVG, где будет размещён результат.

const slides = require("aspose.slides.via.java");
const java = require("java");

class SvgEventController {
    formatShape(svgShape, shape) {
        if (shape.getName() === "ActionButton") {
            svgShape.setId("action-button");
            svgShape.setEventHandler(
                slides.SvgEvent.OnClick,
                "handleShapeClick(event)"
            );
        }
    }

    createProxy() {
        const controller = this;
        const interfaceName = "com.aspose.slides.ISvgShapeFormattingController";
        const proxyMethods = {
            formatShape(svgShape, shape) {
                controller.formatShape(svgShape, shape);
            }
        };
        return java.newProxy(interfaceName, proxyMethods);
    }
}

const presentation = new slides.Presentation("presentation.pptx");
try {
    const svgOptions = new slides.SVGOptions();
    const svgEventController = new SvgEventController();
    const controllerProxy = svgEventController.createProxy();
    svgOptions.setShapeFormattingController(controllerProxy);

    const slide = presentation.getSlides().get_Item(0);
    const svgStream = java.newInstanceSync("java.io.FileOutputStream", "interactive-slide.svg");
    try {
        slide.writeAsSvg(svgStream, svgOptions);
    } finally {
        svgStream.close();
    }
} finally {
    presentation.dispose();
}

Хост‑страница может определить JavaScript‑функцию, на которую ссылается обработчик. Присвоение идентификаторов и обработчиков событий позволяет реализовать просмотрщики слайдов, улучшения доступности и другие интерактивные рабочие процессы SVG.

Часто задаваемые вопросы

Когда следует использовать SVGOptions.setVectorizeText вместо SvgExternalFontsHandling.Vectorize?

Используйте [SVGOptions.setVectorizeText], когда весь текст должен быть независим от шрифтов. Используйте [SvgExternalFontsHandling.Vectorize], когда только текст, использующий внешние шрифты, следует преобразовать в графику.

Как лучше всего уменьшить размер SVG?

Начните с сжатия встроенных изображений, удаления обрезанных областей изображений и выбора ссылок на файлы шрифтов, если целевая среда может их обслуживать. Проверьте результат, так как уменьшение разрешения изображения, снижение качества JPEG и векторизация текста имеют разные компромиссы между качеством и размером.

Можно ли изменить экспортированные элементы SVG после экспорта?

Да. Присвойте идентификаторы через контроллер форматирования, а затем выберите соответствующие SVG‑элементы в вашем инструменте пост‑обработки или скрипте браузера.