Управление рамками изображений в презентациях с помощью JavaScript

Обзор

Рамка изображения — это форма слайда, отображающая изображение. В Aspose.Slides ресурс изображения и форма, отображающая его, являются отдельными объектами: объект Presentation владеет встроенными ресурсами изображений через свою ImageCollection, а объект PictureFrame управляет положением изображения, размером, форматированием линии, вращением, обрезкой, эффектами изображения и другими настройками уровня рамки.

Это разделение полезно, когда одно и то же изображение показывается более одного раза. Добавьте изображение в презентацию один раз, сохраните возвращённый объект PPImage, и используйте этот ресурс изображения при создании рамок изображений.

Рамки изображений могут содержать растровые изображения, такие как PNG или JPEG, и векторные SVG‑изображения. Они также могут ссылаться на связанные изображения вместо хранения байтов изображения в презентации. Выбор влияет на переносимость, размер файла, извлечение и поведение экспорта, поэтому полезно решить, как изображение должно храниться, до применения форматирования или оптимизации.

Добавление и форматирование встроенного изображения

Для встроенного изображения добавьте данные изображения в презентацию и создайте рамку изображения с помощью ShapeCollection.addPictureFrame. Изображение становится частью пакета презентации, поэтому презентация остаётся автономной при перемещении на другой компьютер.

Следующий пример добавляет PNG‑изображение, создаёт рамку с исходными размерами изображения и применяет форматирование линии и вращение:

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);

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

    const pictureFrame = slide.getShapes().addPictureFrame(aspose.slides.ShapeType.Rectangle, 50, 100, image.getWidth(), image.getHeight(), image);
    pictureFrame.getLineFormat().getFillFormat().setFillType(java.newByte(aspose.slides.FillType.Solid));
    pictureFrame.getLineFormat().getFillFormat().getSolidFillColor().setColor(java.getStaticFieldValue("java.awt.Color", "BLUE"));
    pictureFrame.getLineFormat().setWidth(3);
    pictureFrame.setRotation(15);

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

Рамка изображения управляет отображаемой геометрией; изменение размера рамки не меняет оригинальные пиксельные размеры, хранящиеся во встроенном ресурсе изображения. Это различие становится важным при последующей обрезке или сжатии изображения.

Использование относительного масштаба

PictureFrame предоставляет относительное масштабирование ширины и высоты рамки через методы setRelativeScaleWidth и setRelativeScaleHeight. Значение 1.0 соответствует 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);

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

    const pictureFrame = slide.getShapes().addPictureFrame(aspose.slides.ShapeType.Rectangle, 50, 50, 100, 100, image);
    pictureFrame.setRelativeScaleWidth(java.newFloat(1.35));
    pictureFrame.setRelativeScaleHeight(java.newFloat(0.8));

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

Относительный масштаб меняет настройки масштаба рамки; он не пересчитывает и не сжимает встроенное изображение.

Встроенные и связанные изображения

Встроенное изображение хранит данные изображения внутри презентации и поэтому является самым надёжным выбором для переносимости и предсказуемого рендеринга. Связанное изображение хранит внешний путь через метод Picture.setLinkPathLong вместо встраивания данных изображения тем же способом.

Связанные изображения могут уменьшить объём данных изображения, хранящихся в PPTX, но они вводят внешнюю зависимость. Связанный файл должен оставаться доступным приложению, которое открывает или рендерит презентацию. Если путь изменится, файл будет перемещён или ресурс станет недоступным, связанное изображение может не отобразиться как ожидалось. Для презентаций, которые нужно отправлять по электронной почте, архивировать или рендерить в изолированных средах, встроенные изображения обычно надёжнее.

Добавление связанного изображения

Следующий пример создаёт рамку изображения и указывает её на локальный файл изображения. Он работает только с привязкой изображений; привязка видео — отдельный медиапоток и намеренно не смешана в этом примере.

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

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

    const pictureFrame = slide.getShapes().addPictureFrame(aspose.slides.ShapeType.Rectangle, 50, 50, 320, 180, null);
    const linkPath = path.resolve("image.png");
    pictureFrame.getPictureFormat().getPicture().setLinkPathLong(linkPath);

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

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

Извлечение изображений из рамок изображений

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

Извлечение растрового изображения

Современный API изображений использует IImage напрямую. Следующий пример находит первое встроенное растровое изображение на слайде и сохраняет его как PNG:

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

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

    for (let i = 0; i < slide.getShapes().size(); i++) {
        const shape = slide.getShapes().get_Item(i);
        if (!java.instanceOf(shape, "com.aspose.slides.IPictureFrame")) {
            continue;
        }

        const embeddedImage = shape.getPictureFormat().getPicture().getImage();
        if (embeddedImage == null || embeddedImage.getSvgImage() != null) {
            continue;
        }

        const rasterImage = embeddedImage.getImage();
        try {
            rasterImage.save("extracted-image.png", aspose.slides.ImageFormat.Png);
        } finally {
            rasterImage.dispose();
        }
        break;
    }
} finally {
    presentation.dispose();
}

Сохранение через IImage.save преобразует извлечённое изображение в запрошенный формат вывода. Если вам нужны закодированные байты, хранящиеся в презентации, а не преобразованный растровый файл, используйте бинарные данные ресурса изображения.

Извлечение SVG‑изображения

Для SVG‑картинки объект PPImage предоставляет объект SvgImage. Это позволяет получить SVG‑данные напрямую, не растеризуя изображение сначала.

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

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

    for (let i = 0; i < slide.getShapes().size(); i++) {
        const shape = slide.getShapes().get_Item(i);
        if (!java.instanceOf(shape, "com.aspose.slides.IPictureFrame")) {
            continue;
        }

        const embeddedImage = shape.getPictureFormat().getPicture().getImage();
        const svgImage = embeddedImage != null ? embeddedImage.getSvgImage() : null;
        if (svgImage == null) {
            continue;
        }

        fs.writeFileSync("extracted-image.svg", svgImage.getSvgData());
        break;
    }
} finally {
    presentation.dispose();
}

Сохранение содержания SVG в виде SVG сохраняет векторный источник внутри презентации. Растровый экспорт, такой как PNG или JPEG, обязательно рендерит векторное содержание в пиксели. Экспорт слайда в PDF или SVG также является операцией рендеринга, поэтому экспортированная графика не должна рассматриваться как побайтная копия оригинального встроенного SVG; используйте данные SvgImage.getSvgData при необходимости самого векторного ресурса.

Обрезка изображения

Обрезка изменяет, какая часть изображения видна внутри рамки. Значения обрезки в PictureFillFormat задаются в процентах от размеров исходного изображения. Обрезка изначально не удаляет скрытые пиксели из встроенного изображения; она лишь меняет видимую область.

Следующий пример безопасно находит рамку изображения и применяет значения обрезки:

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

const presentation = new aspose.slides.Presentation("input.pptx");
try {
    const slide = presentation.getSlides().get_Item(0);
    let pictureFrame = null;

    for (let i = 0; i < slide.getShapes().size(); i++) {
        const shape = slide.getShapes().get_Item(i);
        if (java.instanceOf(shape, "com.aspose.slides.IPictureFrame")) {
            pictureFrame = shape;
            break;
        }
    }

    if (pictureFrame != null) {
        pictureFrame.getPictureFormat().setCropLeft(java.newFloat(23.6));
        pictureFrame.getPictureFormat().setCropRight(java.newFloat(21.5));
        pictureFrame.getPictureFormat().setCropTop(java.newFloat(3));
        pictureFrame.getPictureFormat().setCropBottom(java.newFloat(31));
        presentation.save("cropped-image.pptx", aspose.slides.SaveFormat.Pptx);
    }
} finally {
    presentation.dispose();
}

Поскольку скрытые данные изображения всё ещё присутствуют, обрезку можно изменить позже без потери оригинальных пикселей. Если размер файла важнее возможности возврата, обрезанные области можно физически удалить, как описано в следующем разделе.

Удаление данных обрезанных изображений

PictureFillFormat.deletePictureCroppedAreas удаляет данные изображения за пределами текущего прямоугольника обрезки и возвращает полученный ресурс изображения. Это может уменьшить размер файла, но является деструктивной оптимизацией: после сохранения презентации удалённые пиксели более недоступны для последующей операции «отобрезки».

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

const presentation = new aspose.slides.Presentation("input.pptx");
try {
    const slide = presentation.getSlides().get_Item(0);
    let pictureFrame = null;

    for (let i = 0; i < slide.getShapes().size(); i++) {
        const shape = slide.getShapes().get_Item(i);
        if (java.instanceOf(shape, "com.aspose.slides.IPictureFrame")) {
            pictureFrame = shape;
            break;
        }
    }

    if (pictureFrame != null) {
        const croppedImage = pictureFrame.getPictureFormat().deletePictureCroppedAreas();
        if (croppedImage != null) {
            presentation.save("cropped-data-removed.pptx", aspose.slides.SaveFormat.Pptx);
        }
    }
} finally {
    presentation.dispose();
}

Метод может добавить новый ресурс изображения в презентацию. Если оригинальное изображение также используется другими рамками, эти рамки всё равно нуждаются в своём существующем ресурсе, поэтому удаление обрезанных областей не обязательно уменьшает общее количество изображений. Обрезка WMF или EMF содержимого этим методом растеризует результат в PNG.

Сжатие растровых изображений

PictureFillFormat.compressImage уменьшает разрешение растрового изображения относительно размера, в котором картинка отображается. Он также может удалять обрезанные области в той же операции. Метод возвращает true, когда изображение было изменено в размере или обрезано, и false, когда изменения не требовались.

Используйте предопределённое значение PicturesCompression в случае, когда достаточен стандартный целевой разрешение:

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

const presentation = new aspose.slides.Presentation("input.pptx");
try {
    const slide = presentation.getSlides().get_Item(0);
    let pictureFrame = null;

    for (let i = 0; i < slide.getShapes().size(); i++) {
        const shape = slide.getShapes().get_Item(i);
        if (java.instanceOf(shape, "com.aspose.slides.IPictureFrame")) {
            pictureFrame = shape;
            break;
        }
    }

    if (pictureFrame != null) {
        const compressed = pictureFrame.getPictureFormat().compressImage(true, aspose.slides.PicturesCompression.Dpi150);
        console.log(compressed ? "The image was compressed." : "No compression was necessary.");
        presentation.save("compressed-image.pptx", aspose.slides.SaveFormat.Pptx);
    }
} finally {
    presentation.dispose();
}

При необходимости конкретного целевого разрешения вместо предопределённого значения можно передать собственное положительное DPI.

Сжатие предназначено для растровых изображений. SVG‑и метафайлы не уменьшаются в этом растровом рабочем процессе. Также помните, что более низкое разрешение и удалённые обрезанные области невозможно восстановить из оптимизированной презентации. Выбирайте целевое разрешение, исходя из наибольшего размера, при котором изображение будет действительно просматриваться или экспортироваться, а не применяя минимальное DPI глобально.

Управление эффектами трансформации изображений

Для полного рабочего процесса, охватывающего яркость, контраст, цветовые трансформации, размытие, альфа‑эффекты, упорядоченные цепочки, проверку, удаление и проверку обратного пути, см. Image Transform Effects.

Блокировка геометрии рамки изображения

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

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

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

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

    const pictureFrame = slide.getShapes().addPictureFrame(aspose.slides.ShapeType.Rectangle, 50, 100, image.getWidth(), image.getHeight(), image);
    pictureFrame.getPictureFrameLock().setAspectRatioLocked(true);

    presentation.save("locked-picture-frame.pptx", aspose.slides.SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

Блокировка применяется к форме рамки изображения. Она не заставляет исходное изображение быть пересчитанным или постоянно изменённым до того же соотношения сторон.

Настройка значений StretchOffset

Когда режим заполнения изображения установлен в «растянуть», значения stretch‑offset в PictureFillFormat определяют прямоугольник заполнения относительно ограничивающего бокса рамки изображения. Положительные проценты создают отступ от края, отрицательные — выступ.

Это отличается от обрезки. Обрезка выбирает, какая часть исходного изображения видна; stretch‑offset изменяет прямоугольник, в который растягивается видимая заливка изображения.

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);

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

    const pictureFrame = slide.getShapes().addPictureFrame(aspose.slides.ShapeType.Rectangle, 10, 10, 400, 300, image);
    pictureFrame.getPictureFormat().setPictureFillMode(java.newByte(aspose.slides.PictureFillMode.Stretch));
    pictureFrame.getPictureFormat().setStretchOffsetLeft(java.newFloat(12));
    pictureFrame.getPictureFormat().setStretchOffsetRight(java.newFloat(12));
    pictureFrame.getPictureFormat().setStretchOffsetTop(java.newFloat(8));
    pictureFrame.getPictureFormat().setStretchOffsetBottom(java.newFloat(8));

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

Используйте stretch‑offset для размещения заливки. Используйте свойства обрезки, когда цель — скрыть края исходного изображения.

Хранение, размер файла и соображения экспорта

Основные компромиссы легче управлять, когда хранение изображений и форматирование рамок изображений рассматриваются отдельно:

  • Встроенные изображения делают презентацию автономной и являются самым надёжным вариантом для совместного использования и серверного рендеринга, но большие растровые изображения увеличивают размер PPTX и потребление памяти.
  • Связанные изображения могут уменьшить размер пакета, но презентация зависит от доступности внешних файлов по сохранённым путям или локациям.
  • Обрезка изначально не разрушительна. Скрытые пиксели остаются встроенными, пока обрезанные области явно не удалены или не удалены во время сжатия.
  • Сжатие может существенно уменьшить размер файла для переразмеренных растровых изображений, но оно теряет исходное разрешение. Его следует применять после того, как известен предполагаемый размер изображения на слайде.
  • SVG‑изображения следует оставлять в виде SVG, когда важна сохранность вектора. Извлекайте встроенный SVG напрямую, когда нужен сам векторный ресурс. Экспорт слайдов в растровый формат всегда преобразует отрендеренный слайд в пиксели.
  • Повторяющиеся изображения следует переиспользовать существующий ресурс PPImage, когда это возможно, вместо многократной загрузки одного и того же файла в рабочий процесс презентации.

Для крупных презентаций оптимизация изображений обычно наиболее эффективна при избирательном применении: храните логотипы и диаграммы как векторный контент, сжимайте фотографии в соответствии с их реальным отображаемым размером, удаляйте обрезанные пиксели только тогда, когда последующее редактирование не требуется, и избегайте внешних ссылок, если только управление зависимостями не является частью дизайна развертывания.

FAQ

В чём разница между рамкой изображения и ресурсом изображения?

PPImage представляет ресурс изображения, связанный с презентацией. PictureFrame — это форма на слайде, отображающая изображение и хранящая геометрию и форматирование уровня рамки, такие как размер, вращение, значения обрезки, эффекты и блокировки.

Надо ли встраивать или связывать изображения?

Встраивайте изображения, когда презентация должна быть переносимой, архивируемой или рендериться без доступа к внешним ресурсам. Связывайте изображения только тогда, когда намеренно хранить файлы изображений вне PPTX и внешние расположения могут быть надёжно поддержаны.

Уменьшает ли обрезка размер файла PPTX?

Не сама по себе. Обычные настройки обрезки скрывают части исходного изображения, но сохраняют подлежащие пиксели. Используйте PictureFillFormat.deletePictureCroppedAreas или сжатие изображения с удалением обрезанных областей, когда эти пиксели могут быть удалены навсегда.

Можно ли восстановить качество изображения после сжатия?

Нет. Сжатие может уменьшить сохранённое растровое разрешение, а удаление обрезанных областей отбрасывает данные изображения. Сохраняйте оригинальное исходное изображение вне презентации, если позже может потребоваться редактирование в высоком разрешении.

Как следует обращаться с SVG‑изображениями?

Сохраняйте SVG‑контент как SVG, когда важна векторная точность. Встроенный SvgImage можно извлечь напрямую. Рендеринг слайда в растровый формат, такой как PNG или JPEG, растеризует SVG как часть изображения слайда.

Как избежать небезопасных привидений при чтении существующих слайдов?

Проверьте тип формы перед использованием членов, специфичных для рамки изображения. Проверка java.instanceOf против PictureFrame предотвращает недопустимые приведения типов и позволяет коду обрабатывать слайды, не содержащие рамок изображений.