Управление эффектами преобразования изображений в презентациях с Java
Обзор
Aspose.Slides представляет регулировку изображений как упорядоченную коллекцию операций преобразования изображений. Для рамки изображения начните с её ISlidesPicture и получите доступ к ISlidesPicture.getImageTransform. Возвращаемый IImageTransformOperationCollection позволяет добавлять, перечислять, просматривать, удалять и очищать эффекты без перезаписи оригинальных байтов изображения.
В этой статье демонстрируется полный рабочий процесс для яркости и контраста, цветовых преобразований, размытия, прозрачности, упорядоченных цепочек эффектов, эффективных значений, удаления и проверки round‑trip PPTX.
Понимание владения эффектом и повторного использования изображений
Ресурс изображения и объект, который его отображает, — разные сущности:
- IPPImage хранит или ссылается на исходные данные изображения, принадлежащие презентации.
- ISlidesPicture принадлежит заполнению изображения и ссылается на ресурс изображения, одновременно храня коллекцию преобразований изображения.
- IPictureFrame — объект формы слайда, который владеет соответствующим заполнением картинки, геометрией, настройками обрезки и другими параметрами уровня рамки.
Поэтому операции преобразования изображения не изменяют байты в IPPImage. Когда один и тот же IPPImage передаётся в IShapeCollection.addPictureFrame более одного раза, каждый новый кадр получает собственный ISlidesPicture и собственную коллекцию преобразований. Применение градации к одному кадру не делает градацию другими кадрами, даже если все они используют один и тот же встроенный ресурс изображения.
Та же модель ISlidesPicture.getImageTransform используется и другими заполнениями изображений, например фигурой или фоном слайда. Приведённые ниже примеры сосредоточены на кадрах изображений.
Использование допустимых диапазонов параметров и единиц измерения
Продемонстрированные методы используют следующие смысловые диапазоны и единицы. Сохраняйте значения в этих диапазонах, даже если конкретная версия библиотеки не отклоняет каждое выходящее за пределы значение сразу; целевой формат презентации может нормализовать, опустить или отклонить недопустимые данные при сохранении или при открытии файла PowerPoint.
| Операция | Параметры | Допустимый диапазон и единицы |
|---|---|---|
| addBrightnessContrastEffect | brightness, contrast |
от -100 до 100, процентов; 0 оставляет компонент без изменений. |
| addGrayScaleEffect | Нет | Нет числовых параметров. Альфа остаётся без изменений. |
| addDuotoneEffect | color1, color2 |
Два цвета для тёмных и светлых пикселей. Каналы RGB и альфа в java.awt.Color используют значения от 0 до 255. |
| addTintEffect | hue, amount |
Тон — от 0 включительно до 360 исключительно, в градусах; количество — от -100 до 100, процентов. |
| addHSLEffect | hue, saturation, luminance |
Тон — от 0 включительно до 360 исключительно, в градусах; насыщенность и светимость — от -100 до 100, процентов. |
| addColorReplaceEffect | color |
Цвет замены использует значения каналов от 0 до 255. Существующие значения альфа сохраняются. |
| addBlurEffect | radius, grow |
Радиус неотрицательный и измеряется в пунктах; grow — логическое значение, определяющее, может ли размытый контент выходить за оригинальные границы. |
| addAlphaModulateFixedEffect | amount |
Неотрицательный процент. Используйте диапазон 0‑100 для обычного масштабирования непрозрачности: 0 — полностью прозрачный, 100 — сохраняет существующую альфу. |
| addAlphaReplaceEffect | alpha |
От 0 до 100, процентов непрозрачности. |
| addAlphaBiLevelEffect | threshold |
От 0 до 100, процентов порога альфа. Значения ниже порога становятся прозрачными; значения, равные или превышающие порог, становятся непрозрачными. |
Для фиксированного модуля альфа прозрачность и непрозрачность являются взаимодополняющими. Например, 35 % прозрачности соответствует значению модуля альфа = 65 %.
Применение яркости и контраста
IImageTransformOperationCollection.addBrightnessContrastEffect возвращает операцию IBrightnessContrast. Ее скалярные настройки задаются при создании операции. IBrightnessContrast.getEffective возвращает вычисленные только для чтения значения, которые можно просмотреть или записать в журнал.
В следующем примере яркость увеличивается на 15 %, контраст — на 20 %, после чего отображается предварительный просмотр без изменения встроенного изображения:
import com.aspose.slides.*;
import java.nio.file.Files;
import java.nio.file.Paths;
Presentation presentation = new Presentation();
try {
ISlide slide = presentation.getSlides().get_Item(0);
byte[] imageData = Files.readAllBytes(Paths.get("photo.png"));
IPPImage image = presentation.getImages().addImage(imageData);
IPictureFrame pictureFrame = slide.getShapes().addPictureFrame(ShapeType.Rectangle, 50, 50, 400, 260, image);
IImageTransformOperationCollection imageTransform = pictureFrame.getPictureFormat().getPicture().getImageTransform();
IBrightnessContrast brightnessContrast = imageTransform.addBrightnessContrastEffect(15f, 20f);
IBrightnessContrastEffectiveData effectiveValues = brightnessContrast.getEffective();
System.out.println("Brightness: " + effectiveValues.getBrightness() + "%");
System.out.println("Contrast: " + effectiveValues.getContrast() + "%");
IImage preview = slide.getImage();
try {
preview.save("brightness-contrast-preview.png", ImageFormat.Png);
} finally {
preview.dispose();
}
} finally {
presentation.dispose();
}
BrightnessContrast — расширение эффекта изображения Office 2010 и менее переносимо, чем стандартный эффект luminance DrawingML. Когда требуется сохранять возможность редактирования яркости и контраста после round‑trip PPTX, используйте IImageTransformOperationCollection.addLuminanceEffect и проверьте результат после повторного открытия файла. Раздел о ограничениях формата объясняет это различие подробнее.
Применение цветовых преобразований
Цветовые эффекты можно применять независимо к разным кадрам, которые используют один ресурс изображения. В следующем примере создаются пять кадров и применяются градация, дутон, оттенок, регулировка HSL и замена цвета.
IDuotone содержит два независимо редактируемых цветовых параметра: color1 сопоставляется темным пикселям, color2 — светлым. Это делает его полезным примером эффекта, настройки которого сложнее одного скалярного значения.
import com.aspose.slides.*;
import java.awt.Color;
import java.nio.file.Files;
import java.nio.file.Paths;
Presentation presentation = new Presentation();
try {
ISlide slide = presentation.getSlides().get_Item(0);
byte[] imageData = Files.readAllBytes(Paths.get("photo.png"));
IPPImage image = presentation.getImages().addImage(imageData);
IPictureFrame grayFrame = slide.getShapes().addPictureFrame(ShapeType.Rectangle, 20, 20, 180, 120, image);
grayFrame.getPictureFormat().getPicture().getImageTransform().addGrayScaleEffect();
IPictureFrame duotoneFrame = slide.getShapes().addPictureFrame(ShapeType.Rectangle, 220, 20, 180, 120, image);
IDuotone duotone = duotoneFrame.getPictureFormat().getPicture().getImageTransform().addDuotoneEffect();
duotone.getColor1().setColor(new Color(0, 0, 128));
duotone.getColor2().setColor(new Color(255, 215, 0));
IPictureFrame tintFrame = slide.getShapes().addPictureFrame(ShapeType.Rectangle, 420, 20, 180, 120, image);
tintFrame.getPictureFormat().getPicture().getImageTransform().addTintEffect(210f, 35f);
IPictureFrame hslFrame = slide.getShapes().addPictureFrame(ShapeType.Rectangle, 120, 170, 180, 120, image);
hslFrame.getPictureFormat().getPicture().getImageTransform().addHSLEffect(30f, 20f, -10f);
IPictureFrame replacementFrame = slide.getShapes().addPictureFrame(ShapeType.Rectangle, 320, 170, 180, 120, image);
IColorReplace colorReplacement = replacementFrame.getPictureFormat().getPicture().getImageTransform().addColorReplaceEffect();
colorReplacement.getColor().setColor(new Color(100, 149, 237));
presentation.save("color-transformations.pptx", SaveFormat.Pptx);
} finally {
presentation.dispose();
}
addColorReplaceEffect заменяет каждый пиксель фиксированным цветом, сохраняя альфа‑канал. Это отличается от addColorChangeEffect, который сопоставляет один исходный цвет другому и раскрывает форматы как исходного, так и целевого цвета.
Добавление размытия, прозрачности и альфа‑эффектов
addBlurEffect влияет на все цветовые каналы, включая альфа. Установите grow в true, когда размытие может выйти за пределы оригинальных границ картинки.
Для равномерной прозрачности используйте addAlphaModulateFixedEffect. Он умножает каждое существующее значение альфа, поэтому частично прозрачные пиксели остаются пропорционально различными. addAlphaReplaceEffect вместо этого задаёт одно значение альфа для всех пикселей. addAlphaBiLevelEffect переводит альфу в два уровня на основе порога.
import com.aspose.slides.*;
import java.nio.file.Files;
import java.nio.file.Paths;
Presentation presentation = new Presentation();
try {
ISlide slide = presentation.getSlides().get_Item(0);
byte[] imageData = Files.readAllBytes(Paths.get("photo.png"));
IPPImage image = presentation.getImages().addImage(imageData);
IPictureFrame blurredFrame = slide.getShapes().addPictureFrame(ShapeType.Rectangle, 20, 20, 200, 140, image);
IBlur blur = blurredFrame.getPictureFormat().getPicture().getImageTransform().addBlurEffect(4.5, true);
blur.setRadius(5);
IPictureFrame transparentFrame = slide.getShapes().addPictureFrame(ShapeType.Rectangle, 240, 20, 200, 140, image);
IAlphaModulateFixed alphaModulate = transparentFrame.getPictureFormat().getPicture().getImageTransform().addAlphaModulateFixedEffect(65f);
alphaModulate.setAmount(60f);
IPictureFrame uniformAlphaFrame = slide.getShapes().addPictureFrame(ShapeType.Rectangle, 20, 180, 200, 140, image);
uniformAlphaFrame.getPictureFormat().getPicture().getImageTransform().addAlphaReplaceEffect(55f);
IPictureFrame binaryAlphaFrame = slide.getShapes().addPictureFrame(ShapeType.Rectangle, 240, 180, 200, 140, image);
IAlphaBiLevel alphaBiLevel = binaryAlphaFrame.getPictureFormat().getPicture().getImageTransform().addAlphaBiLevelEffect(50f);
alphaBiLevel.setThreshold(45f);
binaryAlphaFrame.getPictureFormat().getPicture().getImageTransform().addAlphaInverseEffect();
presentation.save("blur-and-alpha-effects.pptx", SaveFormat.Pptx);
} finally {
presentation.dispose();
}
К другим альфа‑операциям без параметров относятся addAlphaCeilingEffect, который делает любую ненулевую альфу полностью непрозрачной; addAlphaFloorEffect, который делает любую альфу ниже 100 % полностью прозрачной; и addAlphaInverseEffect, который преобразует альфу в 100% - alpha.
Создание упорядоченной цепочки эффектов
Каждый метод add...Effect добавляет новую операцию в конец коллекции. Рендерер использует коллекцию как упорядоченный конвейер: вывод операции 0 становится входом операции 1 и так далее. Следовательно, одинаковые операции в разном порядке могут дать разный результат.
Например, градация, а затем оттенок сначала удаляют хроматическую информацию, а затем перекрашивают полученную светимость. Оттенок, а затем градация убирает оттенок обратно. Аналогично, замена альфа может переопределить значения, вычисленные предыдущими операциями, тогда как модуляция альфа сохраняет их относительные различия.
В следующем примере создаётся цепочка из четырёх операций, сохраняется как PPTX, презентация открывается повторно, проверяются типы операций и их порядок, после чего рендерится результат повторного открытия:
import com.aspose.slides.*;
import java.nio.file.Files;
import java.nio.file.Paths;
Presentation presentation = new Presentation();
try {
ISlide slide = presentation.getSlides().get_Item(0);
byte[] imageData = Files.readAllBytes(Paths.get("photo.png"));
IPPImage image = presentation.getImages().addImage(imageData);
IPictureFrame pictureFrame = slide.getShapes().addPictureFrame(ShapeType.Rectangle, 50, 50, 400, 260, image);
IImageTransformOperationCollection imageTransform = pictureFrame.getPictureFormat().getPicture().getImageTransform();
imageTransform.addGrayScaleEffect();
imageTransform.addTintEffect(220f, 25f);
imageTransform.addBlurEffect(2.5, false);
imageTransform.addAlphaModulateFixedEffect(80f);
presentation.save("image-transform-chain.pptx", SaveFormat.Pptx);
} finally {
presentation.dispose();
}
Presentation reopenedPresentation = new Presentation("image-transform-chain.pptx");
try {
IShape reopenedShape = reopenedPresentation.getSlides().get_Item(0).getShapes().get_Item(0);
if (reopenedShape instanceof IPictureFrame) {
IPictureFrame reopenedFrame = (IPictureFrame) reopenedShape;
IImageTransformOperationCollection reopenedTransform = reopenedFrame.getPictureFormat().getPicture().getImageTransform();
boolean orderIsPreserved = reopenedTransform.size() == 4 &&
reopenedTransform.get_Item(0) instanceof IGrayScale &&
reopenedTransform.get_Item(1) instanceof ITint &&
reopenedTransform.get_Item(2) instanceof IBlur &&
reopenedTransform.get_Item(3) instanceof IAlphaModulateFixed;
System.out.println(orderIsPreserved ? "The effect chain was preserved." : "The effect chain changed during the round trip.");
IImage renderedSlide = reopenedPresentation.getSlides().get_Item(0).getImage();
try {
renderedSlide.save("reopened-effect-chain.png", ImageFormat.Png);
} finally {
renderedSlide.dispose();
}
} else {
System.out.println("The reopened shape is not a picture frame.");
}
} finally {
reopenedPresentation.dispose();
}
Коллекция не накладывает матрицу совместимости, ограничивающую цветовые, альфа‑ и размывающие операции отдельными цепочками. Их можно комбинировать, но не все комбинации полезны. Фиксированная замена цвета убирает вариации RGB, созданные предыдущими цветовыми эффектами; градация после дутон удаляет два выбранных цвета; а операции альфа‑ceiling, floor, replacement или bi‑level могут отбрасывать детали альфа, созданные ранее. Формируйте цепочку в соответствии с желаемой последовательностью обработки пикселей, а не рассматривайте её элементы как набор несортированных флагов форматирования.
Просмотр редактируемых и эффективных значений
Редактируемая операция — это объект, хранящийся в ISlidesPicture.getImageTransform. В зависимости от эффекта она может непосредственно раскрывать изменяемые члены. Например, IBlur раскрывает изменяемые radius и grow, IAlphaModulateFixed — изменяемый amount, а IAlphaBiLevel — изменяемый threshold. Цветовые эффекты, такие как IDuotone, раскрывают изменяемые объекты IColorFormat.
Некоторые интерфейсы операций, включая IBrightnessContrast, IHSL, ITint и IAlphaReplace, не раскрывают свои параметры создания как изменяемые свойства. Чтобы изменить эти настройки, удалите операцию и добавьте замену в нужной позиции.
Эффективные данные, возвращаемые getEffective(), вычисляются и только для чтения. Они полезны для разрешения цветовых зависимостей от темы и чтения нормализованных значений, используемых рендерером, но не являются отдельной поверхностью редактирования. В следующем примере перечисляется цепочка и просматриваются эффективные значения, где соответствующий API их предоставляет:
import com.aspose.slides.*;
Presentation presentation = new Presentation("image-transform-chain.pptx");
try {
IPictureFrame pictureFrame = null;
for (IShape shape : presentation.getSlides().get_Item(0).getShapes()) {
if (shape instanceof IPictureFrame) {
pictureFrame = (IPictureFrame) shape;
break;
}
}
if (pictureFrame != null) {
IImageTransformOperationCollection imageTransform = pictureFrame.getPictureFormat().getPicture().getImageTransform();
for (int index = 0; index < imageTransform.size(); index++) {
IImageTransformOperation operation = imageTransform.get_Item(index);
System.out.println(index + ": " + operation.getClass().getSimpleName());
if (operation instanceof IBrightnessContrast) {
IBrightnessContrastEffectiveData data = ((IBrightnessContrast) operation).getEffective();
System.out.println(" Brightness: " + data.getBrightness());
System.out.println(" Contrast: " + data.getContrast());
} else if (operation instanceof ILuminance) {
ILuminanceEffectiveData data = ((ILuminance) operation).getEffective();
System.out.println(" Brightness: " + data.getBrightness());
System.out.println(" Contrast: " + data.getContrast());
} else if (operation instanceof IDuotone) {
IDuotoneEffectiveData data = ((IDuotone) operation).getEffective();
System.out.println(" Dark color: " + data.getColor1());
System.out.println(" Light color: " + data.getColor2());
} else if (operation instanceof IColorReplace) {
IColorReplaceEffectiveData data = ((IColorReplace) operation).getEffective();
System.out.println(" Replacement color: " + data.getColor());
} else if (operation instanceof IHSL) {
IHSLEffectiveData data = ((IHSL) operation).getEffective();
System.out.println(" HSL: " + data.getHue() + ", " + data.getSaturation() + ", " + data.getLuminance());
} else if (operation instanceof ITint) {
ITintEffectiveData data = ((ITint) operation).getEffective();
System.out.println(" Tint: " + data.getHue() + ", " + data.getAmount());
} else if (operation instanceof IBlur) {
IBlurEffectiveData data = ((IBlur) operation).getEffective();
System.out.println(" Blur radius: " + data.getRadius() + " pt");
} else if (operation instanceof IAlphaModulateFixed) {
IAlphaModulateFixedEffectiveData data = ((IAlphaModulateFixed) operation).getEffective();
System.out.println(" Alpha amount: " + data.getAmount() + "%");
} else if (operation instanceof IAlphaReplace) {
IAlphaReplaceEffectiveData data = ((IAlphaReplace) operation).getEffective();
System.out.println(" Replacement alpha: " + data.getAlpha() + "%");
} else if (operation instanceof IAlphaBiLevel) {
IAlphaBiLevelEffectiveData data = ((IAlphaBiLevel) operation).getEffective();
System.out.println(" Alpha threshold: " + data.getThreshold() + "%");
}
}
}
} finally {
presentation.dispose();
}
Эффекты без параметров, такие как градация, альфа‑ceiling и альфа‑inverse, также имеют объект эффективных данных, но скалярных настроек для вывода нет. Их наличие и позиция в коллекции — важная информация.
Удаление или очистка преобразований изображения
Используйте IImageTransformOperationCollection.removeAt для удаления одной операции по индексу. Поскольку индексы смещаются после удаления, сначала найдите нужный элемент, а затем удалите его после перечисления. Для удаления всей цепочки используйте ImageTransformOperationCollection.clear.
import com.aspose.slides.*;
Presentation presentation = new Presentation("image-transform-chain.pptx");
try {
IPictureFrame pictureFrame = null;
for (IShape shape : presentation.getSlides().get_Item(0).getShapes()) {
if (shape instanceof IPictureFrame) {
pictureFrame = (IPictureFrame) shape;
break;
}
}
if (pictureFrame != null) {
IImageTransformOperationCollection imageTransform = pictureFrame.getPictureFormat().getPicture().getImageTransform();
int blurIndex = -1;
for (int index = 0; index < imageTransform.size(); index++) {
if (imageTransform.get_Item(index) instanceof IBlur) {
blurIndex = index;
break;
}
}
if (blurIndex >= 0) {
imageTransform.removeAt(blurIndex);
System.out.println("The blur operation was removed.");
}
imageTransform.clear();
System.out.println("Remaining operations: " + imageTransform.size());
presentation.save("image-transforms-cleared.pptx", SaveFormat.Pptx);
}
} finally {
presentation.dispose();
}
Удаление или очистка преобразований меняет только форматирование изображения. Это не удаляет, не перекомпрессирует и не изменяет повторно используемый ресурс IPPImage.
Учёт форматов презентаций и целевых экспортов
Преобразования изображений происходят в DrawingML, поэтому PPTX — предпочтительный редактируемый формат для цепочек эффектов. Даже в PPTX не все операции обладают одинаковой переносимостью:
- Стандартные операции DrawingML, такие как luminance, grayscale, duotone, tint, HSL, blur и общие альфа‑операции, имеют наибольшие шансы выжить при round‑trip PPTX. Всегда повторно открывайте созданный файл и проверяйте коллекцию, если требуется сохранение.
- BrightnessContrast — расширение Office 2010, а не стандартная операция luminance DrawingML. Его можно использовать для рендеринга в памяти, но нельзя гарантировать, что после сохранения и повторного открытия PPTX он останется редактируемым IBrightnessContrast. Предпочтительно использовать addLuminanceEffect для постоянных настроек яркости и контраста.
- Бинарный формат PPT предшествует полной модели эффектов DrawingML. Сохранение в PPT может опустить неподдерживаемые операции, сократить цепочку до поддерживаемого подмножества или приблизительно воспроизвести внешний вид. Не используйте PPT для проверки сложных редактируемых цепочек.
- Рендеринг в PNG, JPEG, TIFF, PDF, SVG, HTML или другие визуальные форматы применяет поддерживаемую цепочку к полученному изображению. Эти выводы не содержат редактируемой
IImageTransformOperationCollection; растровые форматы фиксируют результат в пикселях, а экспорты документов/векторов хранят собственное представление рендеринга. - Эффекты не делают связанное изображение самостоятельным. Рендеринг связанной картинки всё равно зависит от наличия связанного ресурса при загрузке презентации.
Разные потребители презентаций могут по‑разному обрабатывать граничные случаи, особенно когда комбинируются несколько альфа‑ или цветоквантизационных операций. Для критически важных выводов тестируйте как редактируемый round‑trip, так и итоговый экспортный формат с тем же Aspose.Slides, который используется в продакшене.
FAQ
Изменяют ли эффекты преобразования изображения встроенные данные изображения?
Нет. Операции принадлежат ISlidesPicture, используемому в заполнении изображения. Базовые байты IPPImage остаются неизменными.
Будут ли два кадра, использующие один и тот же образ, разделять свои эффекты?
Нет. Повторное использование IPPImage избавляет от дублирования данных изображения, но каждый кадр обычно имеет отдельный ISlidesPicture и отдельную коллекцию преобразований.
Можно ли комбинировать цветовые, размывающие и альфа‑эффекты?
Да. Коллекция принимает их в одной упорядоченной цепочке. Учитывайте, как каждая операция влияет на результат предыдущей, поскольку операции замены и пороговые операции могут удалять ранее созданные цветовые или альфа‑детали.
Почему эффективные значения только для чтения?
Эффективные данные отображают вычисленные значения, используемые при рендеринге, включая разрешённые цвета. Редактируйте операцию, хранящуюся в коллекции, где доступны изменяемые члены; иначе удалите её и добавьте замену с новыми параметрами создания.
Какой формат использовать для сохранения цепочки преобразований?
Используйте PPTX и проверяйте файл повторным открытием. Устаревший PPT не может полностью представить модель эффектов DrawingML, а форматы экспортов сохраняют лишь внешний вид, а не редактируемые операции преобразования.