Presentation-to-Image Conversion in C# Is Not Processing Correctly

I am using a pptx file and converting it to images. The images are not correct. Note that this works fine on windows but fails on Ubuntu linux servers. The images are created but are missing parts of the slide. I am using the cross platform version of aspose.slides.

@rajat.jindal

It seems that you are experiencing issues with converting PPTX files to images on Ubuntu Linux servers, while the same process works correctly on Windows. This discrepancy can often be attributed to differences in the environment or dependencies required for the conversion process.

Here are a few steps you can take to troubleshoot and potentially resolve the issue:

  1. Check Dependencies: Ensure that you have all the necessary dependencies installed on your Linux server. Specifically, you should install the libgdiplus package, which is required for image processing in .NET applications on Linux. You can install it using the following command:

    sudo apt-get install libgdiplus
    
  2. Update Aspose.Slides: Make sure you are using the latest version of Aspose.Slides. There have been numerous updates and bug fixes in recent versions that may resolve your issue. If you are using an older version, consider upgrading to the latest one.

  3. Test with Different Fonts: Sometimes, issues can arise from specific fonts used in the presentation. If your PPTX file uses fonts that are not available on the Linux server, it may lead to rendering issues. Ensure that the necessary fonts are installed on your server.

  4. Run in Different Environments: If possible, try running your conversion code in a different environment or container to see if the issue persists. This can help isolate whether the problem is specific to your current server setup.

  5. Check for Known Issues: Review the Aspose forums for any similar issues reported by other users. There may be specific bugs or workarounds that have been documented.

If you continue to face issues after trying these steps, consider sharing a minimal reproducible example of your code along with the specific PPTX file that is causing problems. This will help in diagnosing the issue more effectively.

For further assistance, you might want to check out discussions on similar topics in the Aspose forums, as they can provide additional insights and solutions from other users who have faced comparable challenges.

If you have any more questions or need further assistance, feel free to ask!

image.png (15.7 KB)

I have libgdiplus installed on the system and running latest version of aspose.slides. The first image shows my ppt vs actual image after processing. The second one shows after installing libgdiplus. It is still not correct.

Untitled.png (27.3 KB)

@rajat.jindal,
We are sorry that you encountered this problem. We need more details to investigate the case. Please share the following files and information:

  • sample presentation file
  • code example to reproduce the problem
  • .NET target platform in your application project
  • Aspose.Slides version you are using

Hi,

I am using latest version of aspose.slides.
“Aspose.Slides.NET6.CrossPlatform” - Version=“25.3.0”

My project is targeting .NET 8.

I am unable to upload the presentation file here. It is not allowing. Here is the link to a test ppt file.
https://rajat-vb-test.s3.us-east-1.amazonaws.com/slides+with+itles.pptx

My code looks like this-

using Aspose.Slides;
using SkiaSharp;

private static readonly PresentationImageSize BaseThumbnailSize = new PresentationImageSize(192, 108);
private static readonly PresentationImageSize BaseSlideSize = new PresentationImageSize(1920, 1080);
private const double Aspect16By9 = 16.0 / 9.0;

private const string ImageContentType = "image/png";
private static readonly ImageFormat ImageFormat = ImageFormat.Png;
private static readonly LinkText ImageFileExtension = FileName.PngExtension;

public async Task<PresentationAnalyzerResult> ConvertSlidesToImagesAsync(string file, string accountId, string mediaId, int maxTitleLength = 100, string fileNamePrefix = "")
{
	Log.WriteInfo($"Starting ConvertSlidesToImagesAsync for {mediaId}");
	SetAsposeSlidesLicense();
	var pptFileContent = await _presentationRepository.GetPresentationFile(file).OnThreadpool();

	using (var presentation = new global::Aspose.Slides.Presentation(pptFileContent.Stream))
	{
		var aspectRatio = presentation.SlideSize.Size.Width / presentation.SlideSize.Size.Height;

		var slideSize = GetImageSize(aspectRatio, BaseSlideSize);
		float scaleX = 1f, scaleY = 1f;
		if (slideSize.Height > presentation.SlideSize.Size.Height)
		{
			scaleY = (float) Math.Ceiling(slideSize.Height / presentation.SlideSize.Size.Height);
			scaleX = scaleY;
		}

		var thumbnailSize = GetImageSize(aspectRatio, BaseThumbnailSize);
		var slides = presentation.Slides.ToArray();
		var titles = GetSlideTitles(slides, maxTitleLength).ToList();
		Log.WriteInfo($"Got {slides.Length} slides and {titles.Count} titles in presentation for {mediaId}. Saving images now.");

		await Task.WhenAll(
			slides.Select((slide, i) => SaveImage(slide, i, thumbnailSize, accountId, mediaId, fileNamePrefix, isThumbnail:true)).Concat(
				slides.Select((slide, i) => SaveImage(slide, i, slideSize, accountId, mediaId, fileNamePrefix, scaleX, scaleY)))).OnThreadpool();

		Log.WriteInfo($"Completed ConvertSlidesToImagesAsync for {mediaId}");

		return new PresentationAnalyzerResult()
		{
			SlideWidth = slideSize.Width,
			SlideHeight = slideSize.Height,
			ThumbnailWidth = thumbnailSize.Width,
			ThumbnailHeight = thumbnailSize.Height,
			SlideCount = presentation.Slides.Count,
			SlideTitles = titles,
			SlideExtension = ImageFileExtension
		};
	}
}

private async Task SaveImage(ISlide slide, int index, PresentationImageSize size, string accountId, string mediaId, string fileNamePrefix, float scaleX = 1f, float scaleY = 1f, bool isThumbnail = false)
{
	using (var image = slide.GetImage(scaleX, scaleY))
	{
		// Save the initial image to a memory stream
		using (var memoryStream = new MemoryStream())
		{
			image.Save(memoryStream, ImageFormat);
			memoryStream.Position = 0;

			// Load the image with SkiaSharp
			using (var originalBitmap = SKBitmap.Decode(memoryStream))
			{
				// Create a new bitmap with the target dimensions
				var resizedInfo = new SKImageInfo(size.Width, size.Height);
				using (var resizedBitmap = originalBitmap.Resize(resizedInfo, new SKSamplingOptions()))
				{
					if (resizedBitmap != null)
					{
						// Convert bitmap to image for encoding
						using (var resizedImage = SKImage.FromBitmap(resizedBitmap))
						{
							// Encode the image
							using (var encodedData = resizedImage.Encode(SKEncodedImageFormat.Png, 100))
							{
								// Save to output stream
								using (var outputStream = new MemoryStream())
								{
									encodedData.SaveTo(outputStream);
									outputStream.Position = 0;

									if (isThumbnail)
									{
										await _presentationRepository.UploadSlideThumbnail(
											new FileContent(ImageContentType, outputStream),
											accountId,
											mediaId,
											index + 1,
											fileNamePrefix
											).OnThreadpool();
									}
									else
									{
										await _presentationRepository.UploadSlideImage(
											new FileContent(ImageContentType, outputStream),
											accountId,
											mediaId,
											index + 1,
											fileNamePrefix
										).OnThreadpool();
									}
								}
							}
						}
					}
				}
			}
		}
	}
}

private static void SetAsposeSlidesLicense()
{
	var license = new global::Aspose.Slides.License();

	license.SetLicense("Aspose.Slides.lic");
}

private static PresentationImageSize GetImageSize(float aspectRatio, PresentationImageSize baseSize)
{
	return aspectRatio < Aspect16By9 ?
		new PresentationImageSize((int)(baseSize.Height * aspectRatio), baseSize.Height) 
		: new PresentationImageSize(baseSize.Width, (int)(baseSize.Width / aspectRatio));
}

public static IEnumerable<string> GetSlideTitles(ISlide[] slides, int maxTitleLength)
{
	return slides.Select(slide => GetTitle(slide, maxTitleLength));
}

private static String GetTitle(ISlide slide, int maxTitleLength)
{
	return slide.Shapes
		.Select(shape => GetTitle(shape, maxTitleLength))
		.NotNull()
		.FirstOrDefault()
		?? slide.SlideNumber.ToString();
}

private static string GetTitle(IShape shape, int maxTitleLength)
{
	if (IsTitleShape(shape))
	{
		var autoShape = shape as AutoShape;
		return autoShape?.TextFrame?.Text
			?.TruncateLongString(maxTitleLength)
			?.TrimToNull();
	}
	return null;
}

private static bool IsTitleShape(IShape shape)
{
	var placeholderType = shape.Placeholder?.Type;
	return (placeholderType == PlaceholderType.Title
		 || placeholderType == PlaceholderType.CenteredTitle
		 || placeholderType == PlaceholderType.Header
		 || placeholderType == PlaceholderType.Picture);
}

@rajat.jindal,
Thank you for the details. I need some time to check the issue. I will get back to you as soon as possible.

@rajat.jindal,
Thank you for your patience. The problem with incorrectly displaying text characters is caused by missing fonts (Wingdings 2 and Wingdings 3) on the operating system where the slides-to-images conversion was performed. These fonts are substituted with other fonts.

You should install the fonts on the operating system or use the FontsLoader class to load them as external fonts as shown below.

FontsLoader.LoadExternalFonts(new string[] { "path_to_folder_with_fonts" });

Custom PowerPoint Font in C#|Aspose.Slides Documentation

You can also check all font substitutions using the following code example.

using var presentation = new Presentation("slides+with+itles.pptx");

var fontSubstitutions = presentation.FontsManager.GetSubstitutions();
foreach (var fontSubstitution in fontSubstitutions)
{
    Console.WriteLine($"{fontSubstitution.OriginalFontName} -> {fontSubstitution.SubstitutedFontName}");
}

See also:
PowerPoint Fonts|Aspose.Slides Documentation

Hi Andrey,

Thanks for your response. But I am seeing missing images or incorrectly displayed images.
image.png (15.7 KB)

See uploaded image with left being from presentation and the right one being the one processed.

Is this also related to font?

@rajat.jindal,
If you mean the blue triangle, it is a text character from the Wingdings 3 font used as a bullet symbol. When the Wingdings 3 font is not available, the character is substituted with one from a different font, which results in a different appearance.
Screenshot.png (106.9 KB)
Screenshot2.png (122.7 KB)