Image reuse, XImage and ZIndex

Hello,
I’m modifying a multipage existing PDF.
I need to add images with different "ZIndex"es.
I also need to reuse images multiple times in the same document without growing the document size.

Using the XImage type,the container Resources property and page.Contents.Add( new Aspose.Pdf.Operators.XXXX… ) allows me to reuse images (so the document size is doesn’t grow if the same image is added added 1 or 10 times), but I didn’t find a way to specify the ZIndex.

Using the Aspose.Pdf.Image type to insert images in a FloatingBox allows me to play with the ZIndex property but the document size growes if the very same image file is used multiple times in the same document.

I’m turning round with the API for “some time”. Can anyone point me in the right direction?

Regards

Eric.

@jlalaux

Please try to Optimize PDF document after working with images to see if the file size gets back to where it was before. In case it does not help, please share your sample PDF along with sample code snippet to test the case. We will test the scenario in our environment and address it accordingly.

I tried to optimize the document but it makes no differences.

Please note that I have no control at all on the source PDF documents. I must reuse them as they are.

Here is a code example: I use XImages to reuse the same resources. The PDF document does not grow if the image is added 1 or 3 times.
The problem is the ZIndex. I didn’t find a way to use ZIndex with this method.

Add or remove the comments on “Take(1)” to add the image on the all pages or only on the first.

			const double resolutionFactor = 5;
		const string imagePath = "c:/temp/cbre.jpg";
		const double ratio = 0.17;
		Dictionary<string, XImage> knownImages = new Dictionary<string, XImage>();

		// With or without adding the image on all 3 pages the document size will be the same : 240ko
		foreach( var page in pdf.Pages/*.Take(1)*/ ) {
			XImage xImage;
			string imageKey = imagePath + ratio;
			knownImages.TryGetValue( imageKey, out xImage );
			if( xImage == null ) {
				using( var bmp = SD.Bitmap.FromFile( imagePath ) )
				using( var petitBmp = new SD.Bitmap( bmp, (int)(bmp.Width * ratio * resolutionFactor), (int)(bmp.Height * ratio * resolutionFactor) ) )
				using( var graphics = SD.Graphics.FromImage( petitBmp ) )
				using( var ms = new System.IO.MemoryStream() ) {
					bool compresserJpeg = !(imagePath.EndsWith( ".png" ) || imagePath.EndsWith( ".gif" ));
					if( compresserJpeg ) {
						var qualiteEncoder = System.Drawing.Imaging.Encoder.Quality;
						var paramQualite = new SD.Imaging.EncoderParameter( qualiteEncoder, 80L );
						var parametresEncodage = new SD.Imaging.EncoderParameters( 1 );
						parametresEncodage.Param[0] = paramQualite;
						var imageCodecInfo = SD.Imaging.ImageCodecInfo.GetImageEncoders().First( it => it.FormatID == SD.Imaging.ImageFormat.Jpeg.Guid );
						petitBmp.Save( ms, imageCodecInfo, parametresEncodage );
					}
					else {
						petitBmp.Save( ms, SD.Imaging.ImageFormat.Png );
					}
					var rectangleImage = new Aspose.Pdf.Rectangle( 200, 200, 200 + bmp.Width * ratio, 200 + bmp.Height * ratio );
					page.AddImage( ms, rectangleImage );
					int nbImages = page.Resources.Images.Count;
					xImage = page.Resources.Images[nbImages];
					knownImages.Add( imageKey, xImage );
				}
			}
			else {
				if( !page.Resources.Images.Contains( xImage ) ) {
					page.Resources.Images.Add( xImage );
				}
				page.Contents.Add( new Aspose.Pdf.Operators.GSave() );
				page.Contents.Add( new Aspose.Pdf.Operators.ConcatenateMatrix( new Aspose.Pdf.Matrix( xImage.Width / resolutionFactor, 0, 0, xImage.Height / resolutionFactor, 200, 200 ) ) );
				page.Contents.Add( new Aspose.Pdf.Operators.Do( xImage.Name ) );
				page.Contents.Add( new Aspose.Pdf.Operators.GRestore() );
			}

		}

		pdf.Optimize();
		var optimizeOptions = new Aspose.Pdf.Optimization.OptimizationOptions {
			LinkDuplcateStreams = true
		};
		pdf.OptimizeResources( optimizeOptions );

		pdf.Save( "c:/temp/test_with_logos.pdf" );

Here is a second example: I do not use XImages to be able to change ZIndex, but this way the document gets bigger ig the same image is used multiple times.
Please note that mi resized images are saved to an unique file if same image and resizing is used, so the Aspose.Pdf framework could see that it can use the same resource, but it does not.

const string imagePath = "c:/temp/cbre.jpg";

const double ratio = 0.17;

using( var pdf = new Aspose.Pdf.Document( “c:/temp/test.pdf” ) ) {
// No impact:
pdf.OptimizeSize = true;

// Without this, pdf.OptimizeResources( optimizeOptions ) throws "System.Collections.Generic.KeyNotFoundException"!
foreach( var p in pdf.Pages ) {
	p.PageInfo.Margin = new MarginInfo( 0, 0, 0, 0 );
}

// Document size will grow if the image is added, not only on the first page, but on all pages
foreach( var page in pdf.Pages/*.Take(1)*/ ) {

	SD.Size sizeInPdf;
	using( var bmp = SD.Bitmap.FromFile( imagePath ) ) {
		sizeInPdf = new SD.Size( (int)(bmp.Width * ratio), (int)(bmp.Height * ratio) );
	}
	var fb = new FloatingBox( sizeInPdf.Width, sizeInPdf.Height );
	fb.Left = 200;
	fb.Top = 400;
	//fb.VerticalAlignment = VerticalAlignment.Bottom;
	Aspose.Pdf.Image image = new Aspose.Pdf.Image() { File = imagePath };
	image.VerticalAlignment = VerticalAlignment.Bottom;
	fb.Paragraphs.Add( image );
	fb.ZIndex = 12;
	page.Paragraphs.Add( fb );
}

pdf.Optimize();

var optimizeOptions = new Aspose.Pdf.Optimization.OptimizationOptions {
	LinkDuplcateStreams = true
};

// This line does not reduce PDF size if the image is added multiple times but it breaks pages ration : the document pages are "landscape" but become "portrait" :
// this line also throws "System.Collections.Generic.KeyNotFoundException" if margins are not set to 0 on all pages :
//pdf.OptimizeResources( optimizeOptions );

pdf.Save( "c:/temp/test_with_logos2.pdf" );

}

Regards,

Eric.test.pdf (272.2 KB)

@jlalaux

An investigation ticket as PDFNET-52237 has been logged in our issue tracking system to further analyze the feasibility of ZIndex Property for XImage Class. We will further look into its details and keep you posted with the status of ticket resolution. Please be patient and spare us some time.

We are sorry for the inconvenience.