Hello,
We need to replace a MasterSlide from a Presentation (aka “target”) with a MasterSlide from a “base” Presentation. We noticed that when the MasterSlide from the target Presentation has a gradient background, an InvalidOperationException
occurs.
This behavior can be seen in the latest Aspose Slides for Java version 20.3, the attached Presentations and the following Java code:
try {
final String basetPptxFile = [PATH] + "basePresentation.pptx";
final String targetPptxFile = [PATH] + "targetWithGradient.pptx";
final String masterName = "Main_Master"; //MasterSlide exists in both PPTX
IPresentation targetPpt = new Presentation(targetPptxFile);
// Save targetPpt to a byte[]. While redundant here, it mimics our flow.
try (ByteArrayOutputStream pptStream = new ByteArrayOutputStream()) {
targetPpt.save(pptStream, SaveFormat.Pptx);
}
// Find the MasterSlide in targetPpt that will be replaced
IMasterSlide masterToReplace = null;
for (IMasterSlide master : targetPpt.getMasters()) {
if (masterName.equals(master.getName())) {
masterToReplace = master;
break;
}
}
Objects.requireNonNull(masterToReplace, "MasterSlide in TARGET PPTX mssing");
// Manipulate the targetPpt by replacing the MasterSlide
// Find the MasterSlide from basePpt to clone onto targetPpt
IPresentation basetPpt = new Presentation(basetPptxFile);
IMasterSlide masterToClone = null;
for (IMasterSlide master : basetPpt.getMasters()) {
if (masterName.equals(master.getName())) {
masterToClone = master;
break;
}
}
Objects.requireNonNull(masterToClone, "MasterSlide in BASE PPTX mssing");
// Clone the masterToClone into the target PPTX
IMasterSlide clonedMaster = targetPpt.getMasters().addClone(masterToClone);
// Map the layouts in clonedMaster
Map<String, ILayoutSlide> layoutsFromClone = new HashMap<>();
for (ILayoutSlide layout : clonedMaster.getLayoutSlides()) {
layoutsFromClone.put(layout.getName(), layout);
}
// Migrate all depending slides
for (ILayoutSlide layout : masterToReplace.getLayoutSlides()) {
if (layout.hasDependingSlides()) {
ILayoutSlide layoutFromClone = layoutsFromClone.get(layout.getName());
if (layoutFromClone == null) {
// clone the layout onto clonedMaster
layoutFromClone = clonedMaster.getLayoutSlides().addClone(layout);
// add cloned layout to map
layoutsFromClone.put(layout.getName(), layoutFromClone);
}
for (ISlide slide : layout.getDependingSlides()) {
slide.setLayoutSlide(layoutFromClone);
}
// Confirm there are no longer any dependencies
if (layout.hasDependingSlides()) {
throw new IllegalStateException("Layout stil has dependencies");
}
}
}
// Confirm there are no longer any dependencies
if (masterToReplace.hasDependingSlides()) {
throw new IllegalStateException("MasterSlide stil has dependencies");
}
// Finally remove the masterToReplace - which is no longer unused.
targetPpt.getMasters().remove(masterToReplace);
// Try to save the targetPpt
String newFile = targetPptxFile.replace(".pptx", "_merged.pptx");
Files.deleteIfExists(Paths.get(newFile));
// This is where the InvalidOperationException occurs
targetPpt.save(newFile, SaveFormat.Pptx);
System.out.println("Saved Merged Presentation: " + newFile);
} catch (Exception ex) {
System.out.println("Unexpected exception: " + ex.getMessage());
ex.printStackTrace();
}
Running the sample code should throw InvalidOperationException
with the following stack:
class com.aspose.slides.exceptions.InvalidOperationException: Color is not resolved yet.
com.aspose.slides.fu.do(Unknown Source)
com.aspose.slides.GradientStopEffectiveData.do(Unknown Source)
com.aspose.slides.pu.int(Unknown Source)
com.aspose.slides.ms.do(Unknown Source)
com.aspose.slides.ms.do(Unknown Source)
com.aspose.slides.ms.do(Unknown Source)
com.aspose.slides.ms.do(Unknown Source)
com.aspose.slides.ms.<init>(Unknown Source)
com.aspose.slides.BaseSlide.do(Unknown Source)
com.aspose.slides.Slide.do(Unknown Source)
com.aspose.slides.Slide.do(Unknown Source)
com.aspose.slides.Slide.do(Unknown Source)
com.aspose.slides.af3.try(Unknown Source)
com.aspose.slides.af3.do(Unknown Source)
com.aspose.slides.Presentation.do(Unknown Source)
com.aspose.slides.Presentation.do(Unknown Source)
com.aspose.slides.Presentation.save(Unknown Source)
Additional Observations:
-
Gradient Background: As stated above, the culprit seems to be the MasterSlide with a gradient background. For example the exception does not occur if you replace the 3rd line of code with:
final String targetPptxFile = [PATH] + "targetWithoutGradient.pptx";
-
Multiple Saves: The code above saves the
targetPpt
two times. If you comment out the lines that savetargetPpt
as a byte array - the exception does not occur. It seems that savingtargetPpt
as a byte array causes the Presentation instance to be in a weird state. Note that for us, it is necessary to generate the byte array. -
Prior Slides Versions: Please also note that this seems to be a regressive issue that did not occur under prior Slides versions. For example, if you run the same code under Aspose Slides for Java version 19.7 - the exception does not occur.
-
Workaround: In lieu of removing the code that saves the Presentation to a byte array, we found a workaround that circumvents the exception. The exception does not occur if you reapply the background of the cloned MasterSlide before it’s saved for the second time. For example, adding the following code prior to calling
targetPpt.save
circumvents the exception:clonedMaster.getBackground().getFillFormat().setFillType( clonedMaster.getBackground().getEffective().getFillFormat().getFillType());
Environment Details:
- Aspose Slides for Java 20.3
- Java version 1.8.0_211
- Windows 10 OS (but also reproducible under Linux).
File descriptions in the Presentations.zip (180.4 KB) attachment:
- basePresentation.pptx: Presentation whose MasterSlide will be cloned.
- targetWithGradient.pptx: Presentation whose MasterSlide will be replaced. The MasterSlide has a gradient background.
- targetWithoutGradient.pptx: Presentation whose MasterSlide will be replaced. The MasterSlide does not have a gradient background.
- targetWithoutGradient_merged.pptx: Presentation generated from our environment after running the code above, when using ‘targetWithoutGradient.pptx’ as the
targetPpt
Thanks!