codebude / QRCoder

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

QR Code Fixed Size #151

Closed solutionsdev2009 closed 5 years ago

solutionsdev2009 commented 5 years ago

Type of issue

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

Expected Behavior

Current Behavior

Hi. I want to generate QR Image with fixed size e.g. 200 x 200 or 250 x 250. I am using the following sample code but it gives different image size e.g. 164 x 164 or 174 x 174.

int targetSize = 200;
            QRCodeGenerator qrGenerator = new QRCodeGenerator();
            QRCodeData qrCodeData = qrGenerator.CreateQrCode("this is test value", QRCodeGenerator.ECCLevel.M);
            var ppm = targetSize / qrCodeData.ModuleMatrix.Count();
            QRCode qrCode = new QRCode(qrCodeData);
            var bm32bpp = qrCode.GetGraphic(ppm);
            bm32bpp.Save("Files/" + "test_qr_01.png", ImageFormat.Png);

If I change ECCLevel or text value, then it gives different width and height. I can use SvgQRCode to make fixed size .svg file but I want to create .png, .jpg files. I tried to find open source (MIT License) library to convert svg to png/jpg but unable to find it. Please suggest Thanks

Possible Solution (optional)

Steps to Reproduce (for bugs)

Your Environment

Include as many relevant details about the environment you experienced the bug in.

codebude commented 5 years ago

In theory your code/logic is fine, but there is one problem. Module count depents on the amount of data. Less data (either by shorter payload string or by lower ECC level, which means less error correction data is stored) results in less modules. The amount of modules ranges from 21 (QR code version 1) to 177 (QR code version 40).

When doing your calculation e.g. for module count 21 and 200 target width, your logic gives a ppm of 9. It does so, because you're working with int. A more correct value of the calculation would be 9,52380952380952. Because 9x21 = 189.

Have a look at this snippet I wrote for you (and press F8/Run to see its results): https://rextester.com/ORXUS66866

Now one could think about working with doubles, to get nearly exact ppm-values, but this doesn't work either. Because the rendering method doesn't take doubles like 9,5238... But why? The parameter says "pixel per module". So ppm=9,5238 e.g. would mean draw each module (black/white block) in a width of 9,5238. This technically is impossible. A pixel is the smallest unit.

So how to solve this problem? As you can see when using with "full" pixels, the calculation for 21 modules would give a ppm of 9 which results in a QR code of 189 px. Now we had to fill further 11px. We could do so, by drawing 11 of the 21 modules 1px wider. Since this is an inaccurancy, I didn't implement such algortihm in the library.

What you could do, if you nevertheless want to go this way: Use your calculation to generate QR codes. Then use the Graphics class to stretch the QR code bitmap to your desired size like shown here: https://stackoverflow.com/a/2001692/251719 By doing so the Graphics class decides which pixels to paint twice to reach the target size. But keep in mind, this will affect the image quality due to the reasons explained above.

solutionsdev2009 commented 5 years ago

Hi codebude Thanks for providing detailed information. much appreciated. I will try out resizing QR Image as per https://stackoverflow.com/a/2001692/251719 I also tried the following steps and its working for me so far

  1. Generate SVG string using GetGraphic method of class SvgQRCode
  2. Pass SVG string to another library (https://github.com/vvvv/SVG) to convert svg into image (png or jpeg) It gives good results without losing image quality. Thanks for your support