codebude / QRCoder

A pure C# Open Source QR Code implementation
MIT License
4.61k stars 1.1k forks source link

QR Code Generation slightly different on Macs #135

Closed ghost closed 6 years ago

ghost commented 6 years ago

Type of issue

[x] Bug
[ ] Question (e.g. about handling/usage)
[ ] Request for new feature/improvement

Expected Behavior

Using the same payload on windows & Mac environments, should generate the same QR encoding.

Current Behavior

The same payload shows differently on Mac than on windows, rendering tests useless. The QR code image shows correctly, but the actual text is different.

Even just taking an empty string, this is produced:

Windows:

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAkQAAAJEAQAAAADfmwb3AAAB90lEQVR4nO3cUXLCMAxF0ewg+98lO6BTZoIdRQlQSixmjr8aat6H5ulKVtxO139al4mSOHGBbMECzFQRVE59gf5Jd6iLdkZwlnJSdKI2LzBXMTUyXTM7NGP9xgnyFNd8/2w+2EJJnLhAtmBBGWa2z5fH2/bfbYvwdgslceIC2YIFlZjZF4OV0u4WSuLEBbIFC6ozs3+kJE5cIFuw4PuYGTp7SuLEBbIFCwozc/fx0RZK4sQFsgULxjMzrNDPz/kWSuLEBbIFC4owM1uhsz9YlMSJC2QLFoxn5mXvZWk2oTmsCJTEiQtkCxYMYmZP//B4KxCrO+mHFYGSOHGBbMGCk5mZMT/8dvcnSuLEBbIFCyows31/uXp+39bdRG+b11soiRMXyBYsqMLMMH5p38reolISJy6QLVhQhJnZCtptapMUDUrixAWyBQvGMjOrCOH77fHl2kJJnLhAtmDB55mZ/blQ9gJ1elgRKIkTF8gWLBjEzL4YrJgf2vs//K8ASuLEBbIFC85nZigVr91gpCROXCBbsGA4M/Pa8ORdSErixAWyBQvOZ+ZGOJvabDdTEicukC1YUIGZ2zemmfAbdyEpiRMXyBYs+CAz31uUxIkLZAsWYKaKoHLqC/RPukNdtDOCs5STohO1eYG5iqmR6ZrZoRnrNV0lJ8g/drDgyPgzOEUAAAAASUVORK5CYII=

Mac:

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAkQAAAJEAQAAAADfmwb3AAABdElEQVR4nO3YQW7EIAwFUN8g97/l3GCqRklgDMl01FYQ6XkFjnlLfkQ8/6geQSKRSCQSiUQikUgkEolEIpFIJNIdpci1HL3lYoREIpFI00ilv2/X8e+xHW5HSCQSiTSTVIfBi3Q6QiKRSKTZpXpLIpFIpPtJ6c+eRCKRSBNLp9t3IyQSiUQaL6UqEZDC4GWERCKRSJNIvVrHy5/9RZFIJBJpvNQ+xKy9/gvNZSKQSCQSaZBU3/5p+9ykbRWRzpJIJBJprNS789PX0xWJRCKRZpDK+Ue+7qNB4ioRSCQSiTRS2qo9VYfGUsMkEolEGi/1Ktnl1aYTGiQSiUQaK0Wu5QiD8uYex+rDbCGRSCTS/0ulX7b7qR5Xj5NIJBJpCmkbbN9g4qgfJgKJRCKRJpDKh2YVnyUCiUQikUZI/WxoVyQSiUSaRGrgttcbJpFIJNIMUqoTuJcSJBKJRBov/a5IJBKJRCKRSCQSiUQikUgkEolEupH0BXaw4Mh6b+9WAAAAAElFTkSuQmCC

Putting those strings into https://codebeautify.org/base64-to-image-converter produces the same image.

Steps to Reproduce (for bugs)

Using the following code:

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            var payload = (string)value;
            QRCodeGenerator qrCodeGenerator = new QRCodeGenerator();
            QRCodeData qrCodeData = qrCodeGenerator.CreateQrCode(
                payload,
                QRCodeGenerator.ECCLevel.Q,     // TODO: Consider making this configurable.
                forceUtf8: false,               // TODO: Decide whether to force us to use UTF-8 for all payloads.
                utf8BOM: false                  // Never use a UTF-8 BOM.
            );
            PngByteQRCode qrCode = new PngByteQRCode(qrCodeData);
            var array = qrCode.GetGraphic(
                pixelsPerModule: 20             // TODO: Consider making this configurable.
            );

            writer.WriteValue("data:image/png;base64," + Convert.ToBase64String(array));
        }

Your Environment

codebude commented 6 years ago

Hello @AnthonyRonning ,

thanks for your report. Indeed I see the differences and your point. Unfortunately this isn't the fault of QRCoder - so I can't barely do anything.

I compared both PNG files in a hex editor and via debugging at runtime. The input to the PNG class is the same on both system (WIN and MAC). So the differences appear when creating the PNG files. A PNG file contains the image information in a compressed way (deflate compression). For this I use the following code in the PngByteQRCode.cs-class:

//[...]
private static void Deflate(Stream output, byte[] bytes)
{
    using (var deflateStream = new DeflateStream(output, CompressionMode.Compress, leaveOpen: true))
    {
        deflateStream.Write(bytes, 0, bytes.Length);
    }
}
//[...]

The deflate stream behaves differently on Win and Mac. Thus the payload of the PNG image changes (and also some header information like payload size).

To fix this problem, the DeflateStream from System.IO.Compression has to be fixed, which isn't anything I can do.

To workaround your issue you could either do your tests on a QRCode data level (like running the tests on the QRCodeData instead of the output of the PngByteQRCode) or do it on a pixel level, by opening the PngByteQrCode as Image/Bitmap object and then compare the outcome pixel by pixel.

If I missunderstood you in any point or if you think I'm wrong with my analysis, please let me know and feel free to re-open this issue.