Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DrawImage draws allways the same (first) image #127

Closed
andreas20240621 opened this issue Jun 21, 2024 · 26 comments
Closed

DrawImage draws allways the same (first) image #127

andreas20240621 opened this issue Jun 21, 2024 · 26 comments
Labels
bug Something isn't working investigation Under investigation

Comments

@andreas20240621
Copy link

!!!!! If you think there is a bug in PDFsharp then please use the IssueSubmissionTemplate to make the issue replicable.
!!!!! https://docs.pdfsharp.net/General/IssueReporting.html
!!!!! => Sorry, but this link doesn't work

Reporting an Issue Here

When creating an PDF with three different Images, using XGraphics.DrawImage, the resulting PDF schould show up three different images.

Actual Behavior

The resulting pdf shows up the same (first) image for three times.
This happend, if PDFSharp 6.1.0 is used
This does not happen, if PDFSharp 6.0.0 is used.

Steps to Reproduce the Behavior

!!!!! We strongly recommend using the IssueSubmissionTemplate to make sure we can replicate the issue.
!!!!! https://docs.pdfsharp.net/General/IssueReporting.html
!!!!! => sorry, this link does not work.

Download Solution from embedded zip File.
Compile Solution using NuGet Package PDFSharp6.1.0
Run the compiled Program. This will produce the wrong result.
(file PdfSharpTest1.pdf in the Solution Folder)

Compile Solution using NuGet Package PDFSharp6.0.0
Run the compiled Program. This will produce the correct result.
(file PdfSharpTest1.pdf in the Solution Folder)

PdfSharpTest1.zip

This sample project contains 2 PDF Files. These are the results when Project is compiled with PDFSharp 6.0.0 oder PDFSharp 6.1.0
The PDF named PdfSharpTest1-Version6.0.0.pdf contains the expected result.
The PDF named PdfSharpTest1-Version6.1.0.pdf contains the wrong result.

@ThomasHoevel ThomasHoevel added bug Something isn't working investigation Under investigation labels Jun 21, 2024
@ThomasHoevel
Copy link
Member

ThomasHoevel commented Jun 21, 2024

Thanks for the feedback.
Issue does not show with Core build and WPF, but shows with GDI build.

Your code that does not work with the GDI build is this:

using FileStream stream = File.OpenRead(iamgeFile);
MemoryStream mems = new MemoryStream();
stream.CopyTo(mems);
mems.Position = 0; // Added by me to make WPF build work.

XImage resultImage = XImage.FromStream(mems);

Here is a shorter version that works:

FileStream stream = File.OpenRead(iamgeFile);
XImage resultImage = XImage.FromStream(stream);

And here is an even shorter version that also works:
XImage resultImage = XImage.FromFile(iamgeFile);

Will investigate further next week. It should also work with the indirection to the MemoryStream object.

There was a hyphen missing in the URL:
https://docs.pdfsharp.net/General/Issue-Reporting.html

@andreas20240621
Copy link
Author

Thanks for your fast response.
You are right, that both of your versions do work correctly.

But they both keep an file stream open, what i tried to avoid.

i've added the following "File.Delete" at the end of the Main Routine

pdfoutput.Save(Path.Combine(targetDirectory, "PdfSharpTest1.pdf"));

File.Delete(Path.Combine(targetDirectory, "pic1.jpg"));
File.Delete(Path.Combine(targetDirectory, "pic2.jpg"));
File.Delete(Path.Combine(targetDirectory, "pic3.jpg"));

And the program throw the error
System.IO.IOException: "The process cannot access the file 'D:\repos\PdfSharpTest1\pic1.jpg' because it is being used by another process."

In my productiv Application, i do not delete those files of course, but we have PDF outputs with a very large number of images included. So it would be very unhandy to keep them all open, during program execution.

So i will look forward to your investigation next week, to enable MemoryStreams here again.
We use Library 6.0.0 for now, so it doesn't hurry.

th-joerger added a commit to th-joerger/PDFsharp that referenced this issue Jun 27, 2024
…fore consumed streams are compared and wrongly treated as equal, which leads to all images in the document to be the same image.
@th-joerger
Copy link

th-joerger commented Jun 27, 2024

I encountered the same problem in my production environment. Several customers have been severly affected with hundreds of wrongly printed qr codes.

The culprit seems to be this dysfunctional code:

                    else if (image._stream != null!)
                    {
                        if (image._stream is MemoryStream ms)
                        {
                            var md5 = System.Security.Cryptography.MD5.Create();
                            var hash = md5.ComputeHash(ms);
                            image._path = "*md5:" + HashToString(hash);
                        }
                        else
                        {
                            // TODO Use hash code.
                            image._path = "*" + Guid.NewGuid().ToString("B");
                        }
                    }
#if GDI
                    else if (image._gdiImage != null!)
                    {
                        // TODO Use hash code.
                        image._path = "*" + Guid.NewGuid().ToString("B");
                    }
#endif

The md5 is always *md5:d41d8cd98f00b204e9800998ecf8427e which is the md5 hash of an empty input. The stream image._stream is already consumed when computing the hash, because in GDI in XImage.cs, the stream is already used to create an Image.

The work around for GDI with the check for the existence of image._gdiImage comes to late after the md5 hash is already computed.

When the memory stream is reset, everything works as expected.

                        if (image._stream is MemoryStream ms)
                        {
                            ms.Seek(0, SeekOrigin.Begin); // make sure, ms is not already consumed
                            var md5 = System.Security.Cryptography.MD5.Create();
                            var hash = md5.ComputeHash(ms);
                            image._path = "*md5:" + HashToString(hash);
                        }

So, I think the fix is, to check for the existence of image._gdiImage before computing the md5 hash. I send you a PR #128 including a test. I would also appreciate you properly merging PRs instead of simply copying the code and squashing my contribution.

@ThomasHoevel
Copy link
Member

The issue has been resolved with version 6.1.1 released today.
We are sorry for any inconveniences the issue has caused.

@andreas20240621
Copy link
Author

Yes, the issue has been fixed with version 6.1.1

@X1WGM
Copy link

X1WGM commented Jul 12, 2024

Hi,
I am using 6.1.1 and this is still an issue for me.
I have a number of DrawImage's where the XImage is either FromFile or FromStream. All the FromFile images are correct. However, I have 3 "different" FromStream images and images 2 and 3 are a repeat of image 1. If I remove image 1, image 3 becomes a repeat of image 2.
So in simple terms, the first image that is drawn using FromStream is then always repeated on subsequent DrawImage commands. It's like the first image is cached and then just reused over and over.
I hope this can be fixed.
Thank you.

Update:-
It seems there is some sort of caching happening. I have saved my image 2 stream to disk and then used FromFile. This also draws as image 1, even though I can clearly see it is a different image. If I then rename image 2 on disk and use a new FromFile XImage, it still draws as image 1. So is there some sort of Meta data that is being checked and if the same as image 1 just use that instead?

I hope this helps a little.

@ThomasHoevel
Copy link
Member

Hi, I am using 6.1.1 and this is still an issue for me.

Please use the Issue Submission Template so we can replicate your issue.
Does this happen with all three builds? Or just with the GDI build as the issue discussed here?

@X1WGM
Copy link

X1WGM commented Jul 15, 2024

Hi, I am using 6.1.1 and this is still an issue for me.

Please use the Issue Submission Template so we can replicate your issue. Does this happen with all three builds? Or just with the GDI build as the issue discussed here?

Thank you for the fast reply. I would love to use the Submission Template. Only I have no idea what or where that is. Please forgive me. Sorry.

I am using C# .NET Framework 4.8 in an MVC website. So again, sorry for my ignorance, is that GDI? I can say I am not developing a WPF project. Just a corporate website. Everything was going perfectly until I noticed this issue.

I am in the process of creating a Customer Credit Agreement document using PDFSharp. It all looks fantastic but when I get the 3 unique signatures from the SQL database and DrawImage(FromStream) them on the document, whichever one I draw first is then repeated for the other 2. If I change the order of the DrawImage statements, I get a different signature, but again, repeated.

For my sanity, I tried saving the 3 streams to disk and there I can see that they are all different. Now here's another pointer (hopefully)... Even though I can see that the 3 images on disk are different, if I then use DrawImage(FromFile) for the 3 images, the same problem occurs. I.e. Whichever image is drawn first is repeated for the other 2. So in my mind, it's like any image that originated from a stream, even after saving to disk, is seen as the same image and therefore maybe taken from cache or something like that.

I do hope this helps you. And if there's anything I can provide to assist, please let me know.

Thank you.

@ThomasHoevel
Copy link
Member

For issue reporting, see here:
https://docs.pdfsharp.net/General/Issue-Reporting.html

It should be easy to replicate the issue without MVC in a console application.

@X1WGM
Copy link

X1WGM commented Jul 15, 2024

For issue reporting, see here: https://docs.pdfsharp.net/General/Issue-Reporting.html

It should be easy to replicate the issue without MVC in a console application.

Thank you. Here's a quick update that may help...
If I resize the image using C# code it works and I get the the images I expect.

@ThomasHoevel
Copy link
Member

ThomasHoevel commented Jul 15, 2024

Here's a quick update that may help...

It would be good to have code that allows to replicate the issue.
You have images that cause an issue, but as long as you do not share neither your images nor your code, we're having difficulties to investigate the matter.

@X1WGM
Copy link

X1WGM commented Jul 15, 2024

Here's a quick update that may help...
It would be good to have code that allows to replicate the issue.
You have images that cause an issue, but as long as you do not share neither your images nor your code, we're having difficulties to investigate the matter.

Again, thank you for your fast responses.
I will try and create a simple console project that will replicate the problem. Can you check the https://github.com/empira/PDFsharp.IssueSubmissionTemplate link as it just sends me in circles. And the other link to this on the page is a 404.

@ThomasHoevel
Copy link
Member

@X1WGM
Copy link

X1WGM commented Jul 15, 2024

This link works: https://docs.pdfsharp.net/General/Issue-Reporting.html

This link works: https://github.com/empira/PDFsharp.IssueSubmissionTemplate

Unfortunately not for me... (Maybe I'm doing something wrong)

https://docs.pdfsharp.net/General/Issue-Reporting.html takes me to a page with a link to https://github.com/empira/PDFsharp.IssueSubmissionTemplate. Further down this page is this...

  1. Download the solution from https://github.com/empira/PDFsharp.IssueSubmissionTemplate (I am presuming this is what I need?)

Which is the same page. However, when I click it I can see the URL trying to change to something else before just refreshing the current page.
There is also a link under the heading Template solution for issue reports. This is the 404 link. So sorry.

Anyway, back to the real issue. I will try now to create a console project that I can send over and some images.

Thank you.

@ThomasHoevel
Copy link
Member

Try this page:
https://github.com/empira/PDFsharp.IssueSubmissionTemplate

Near the top is a green button labelled "<> Code" with a drop-down menu.

The drop-down menu gives you several options to get the code, including "Download ZIP", or "Clone" with "GitHub CLI", or copy the "HTTPS" link to clone with Visual Studio - to name just a few options.

@th-joerger
Copy link

You can try my fix from #128

NuGet packages can be found here.

@X1WGM
Copy link

X1WGM commented Jul 15, 2024

Try this page: https://github.com/empira/PDFsharp.IssueSubmissionTemplate

Near the top is a green button labelled "<> Code" with a drop-down menu.

The drop-down menu gives you several options to get the code, including "Download ZIP", or "Clone" with "GitHub CLI", or copy the "HTTPS" link to clone with Visual Studio - to name just a few options.

I now understand. It's a whole project. For some reason I was expecting some kind of web form. Sorry.
I downloaded and opened the solution. Really not sure where to start to be honest. However, I have created and attached a simple console project that replicates my problem. I am sorry that this is probably not your preferred way but it was quick and easy for me to get this issue over to you.
Thanks again for your help here. 👍
PDFSharpIssue127.zip

@X1WGM
Copy link

X1WGM commented Jul 15, 2024

You can try my fix from #128

NuGet packages can be found here.

Thank you. I know I need to get myself familiar with how GitHub works and how I can get your fix into my project so that I can try it. However, I am hoping that the attached ZIP in my reply to @ThomasHoevel will help locate the problem and version 6.1.2 will be released soon. Fingers crossed.

@ThomasHoevel ThomasHoevel reopened this Jul 15, 2024
@ThomasHoevel
Copy link
Member

@X1WGM I can replicate the issue now.
How did you create those images? Scanner software?

Will talk to my boss about a 6.1.2 version. Maybe we'll skip 6.1.2 and go for 6.2.0 Preview 1 instead.
Anyway, issue will be resolved with the next version.

The change from PR 128 does not make a difference in this case, so not worth giving it a try.

@X1WGM
Copy link

X1WGM commented Jul 16, 2024

@X1WGM I can replicate the issue now. How did you create those images? Scanner software?

Will talk to my boss about a 6.1.2 version. Maybe we'll skip 6.1.2 and go for 6.2.0 Preview 1 instead. Anyway, issue will be resolved with the next version.

The change from PR 128 does not make a difference in this case, so not worth giving it a try.

Hello @ThomasHoevel,

The images were created from a byte array. Here is the process of the web app that I have created...

  1. On a Samsung tablet running Google Chrome a customer signs 2 different sections of their credit agreement and another signature is captured for the sales representative. So 3 unique signatures.
  2. These are then serialized into a byte array and persisted to an MS SQL database.
  3. They are then read from the database as a stream and then added to the PDFSharp document.

What I did for testing this was save the streams to disk, I.e. Image1.png, Image2.png & Image3.png. As you can see in my example project the 3 images are different when viewed on the file system. But when these are added to the document, the first image used is then duplicated for the other images.

I have cunningly found a work-around for now. That is... If I resize the 3 images to different dimensions but keeping the aspect ratio, they all work as expected. In my testing, even a resize back to the original size causes them to duplicate the first image. So it's like it is caching the first images dimensions and then any subsequent images of the same size get ignored and the first image is used. That's just what I have found. I hope this helps.

Anyway, fantastic software. Our credit agreements are looking neat and professional. Thank you. 👍👍👍

@ThomasHoevel
Copy link
Member

ThomasHoevel commented Jul 16, 2024

The issue submitted by X1WGM is different from the issue submitted by Andreas.
The "X1WGM" issue is as follows:

  • The three images are identical except for the Alpha mask - image bits are always 0 for the three sample images
  • The Core build of PDFsharp 6.1.1 does not account for the Alpha mask when calculating a hashcode - this is a bug and it will be fixed with the forthcoming preview version

See also:
https://github.com/empira/PDFsharp/wiki/PDFsharp-6.1.0-and-6.1.1-incorrectly-duplicate-first-image

@ascott18
Copy link

ascott18 commented Oct 21, 2024

Here's a workaround that doesn't require building the entire library from source, nor making any modifications to the content of images:

var image = XImage.FromStream(stream);

// HACK: Workaround https://github.com/empira/PDFsharp/issues/127
var selectorField = image.GetType().GetField("_selector", BindingFlags.Instance | BindingFlags.NonPublic);
var selector = Activator.CreateInstance(selectorField.FieldType, image, doc.Options);
selector.GetType().GetField("<Path>k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(selector, Guid.NewGuid().ToString());
selectorField.SetValue(image, selector);
// END HACK: Workaround https://github.com/empira/PDFsharp/issues/127

@Loyalar
Copy link

Loyalar commented Nov 7, 2024

Here's a workaround that doesn't require building the entire library from source, nor making any modifications to the content of images:

var image = XImage.FromStream(stream);

// HACK: Workaround https://github.com/empira/PDFsharp/issues/127
var selectorField = image.GetType().GetField("_selector", BindingFlags.Instance | BindingFlags.NonPublic);
var selector = Activator.CreateInstance(selectorField.FieldType, image, doc.Options);
selector.GetType().GetField("<Path>k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(selector, Guid.NewGuid().ToString());
selectorField.SetValue(image, selector);
// END HACK: Workaround https://github.com/empira/PDFsharp/issues/127

This workaround seems to work perfectly as a temporary solution.

When using this code, it was a bit unclear what the doc.Options was referring to, as the doc does not exist in the scope of this code block. I would just like to clear up that the doc is of course the reference to the PdfDocument instance.

@D-ACE
Copy link

D-ACE commented Nov 11, 2024

Here's a workaround that doesn't require building the entire library from source, nor making any modifications to the content of images:

var image = XImage.FromStream(stream);

// HACK: Workaround https://github.com/empira/PDFsharp/issues/127
var selectorField = image.GetType().GetField("_selector", BindingFlags.Instance | BindingFlags.NonPublic);
var selector = Activator.CreateInstance(selectorField.FieldType, image, doc.Options);
selector.GetType().GetField("<Path>k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(selector, Guid.NewGuid().ToString());
selectorField.SetValue(image, selector);
// END HACK: Workaround https://github.com/empira/PDFsharp/issues/127

Thanks for this fix.
It works, the bug still persist in this 6.1.1 version and 6.2-preview

@ThomasHoevel
Copy link
Member

I want to clarify one point:

The issue discussed here occurs if two images have identical pixels when the only differences are in the mask.

The sample images we have seen consist of black pixels only, stored in RGB format using 24 bits per pixel. It would save memory to store those all-black images in monochrome format with just 1 bit per pixel, but that's a different story.

The alpha mask finally leads to a grayscale image.

I did not expect that applications would use all-black images with identical dimensions where the only differences are in the masks.

The workaround above is a workaround, not a fix. It disables the detection of identical images and should only be used if you are affected by this issue.

Another workaround is changing the image dimensions. If you have e.g. four static images that are all 320 pixels wide, then consider changing one image to 321 pels, one to 322 pels, one to 323 pels width.

Images will then be added to the PDF only once, even if they are used multiple times on the same or different pages.

@ThomasHoevel
Copy link
Member

Issue should be resolved with PDFsharp 6.2.0 Preview 2.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working investigation Under investigation
Projects
None yet
Development

No branches or pull requests

7 participants