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

Suboptimal segements chosen, causing bitmap generation to fail #37

Open
awbacker opened this issue Jun 17, 2020 · 4 comments
Open

Suboptimal segements chosen, causing bitmap generation to fail #37

awbacker opened this issue Jun 17, 2020 · 4 comments
Assignees

Comments

@awbacker
Copy link

awbacker commented Jun 17, 2020

I use the library heavily to generate qr bitmaps (manually creating the image), so thank you for creating it!

The following test case should generate correctly:

  • AlphaNumeric (single segment)
  • V4
  • Ecc H (Highest)
  • Changing 6998877 to 699E877 causes generation to succeed
func TestShouldCreateTheQrCode(t *testing.T) {
	msg := "HTTPS://ABC.DE/F/393AABB6998877XYZ0518AUQCRVJN25"
	//                                 E    <-- change to E and no crash
	qrc, err := qrcode.NewWithForcedVersion(msg, 4, qrcode.Highest)
	if err != nil {
		t.Error(err)
	}
	qrc.Bitmap()
}

=== RUN   TestShouldCreateTheQrCode
2020/06/17 12:26:01 BUG: got len 296, expected 288
--- FAIL: TestShouldCreateTheQrCode (0.00s)
panic: BUG: got len 296, expected 288 [recovered]
	panic: BUG: got len 296, expected 288

I noticed that after the call to encoder.encode the length is 290 (and somehow numPaddingBits() == -2?). In any case, I am not familiar enough with the code to debug fully yet, but will be giving it a try this afternoon.

The multi-segments by default kind of thing is clever, it just appears to be failing in this case. I feel that most users will calculate their version/recovery-level based on the published data lengths which assume single-segment, especially for high volumes.

@awbacker awbacker changed the title Suboptimal bits/segements chosen, causing bitmap generation to fail Suboptimal segements chosen, causing bitmap generation to fail Jun 17, 2020
@skip2 skip2 self-assigned this Jun 17, 2020
@skip2
Copy link
Owner

skip2 commented Jun 17, 2020

Hi Andrew.

Thanks for the kind words.

You're right, the optimiser is being too clever, and a single alphanumeric segment would be a more efficient (and more predictable) encoding.

We currently use a single byte segment when it's more efficient than multiple segments. I've now added use of a single alphanumeric segment (only if the content allows it), when it's more efficient than multiple segments.

da1b656

let me know if that helps,

thanks,

skip2

@awbacker
Copy link
Author

awbacker commented Jun 17, 2020

I took a look at that and it seems like it would work, but I haven't had a chance to try it yet. Looking through your code taught me a lot about QR codes, even though I already knew enough to do the basic stuff like determine a good ecc. Well done :)

In the end I made below change in my vendored version.

// rather than try only binary, try the "best" encoding based on the data as a 
// single segment in encode([]bytes). 
minEncoding := minDataEncoding(d.data)
singleSegment, err := d.encodedLength(minEncoding, len(d.data))
...

func minDataEncoding(data []byte) dataMode {
	m := dataModeNone
	for _, v := range data {
		if n := minByteEncoding(v); n > m {
			m = n
		}
		if m == dataModeByte {
			break
		}
	}
	return m
}

// smallest mode that applies to a single byte
func minByteEncoding(chr byte) dataMode {
	if chr >= '0' && chr <= '9' {
		return dataModeNumeric
	}
	if chr >= 'A' && chr <= 'Z' {
		return dataModeAlphanumeric
	}
	switch chr {
	case ':', '/', '.', '-', '+', '*', '$', '%':
		return dataModeAlphanumeric
	}
	return dataModeByte
}

I may fork this repo and create a PR, if thats helpful to you in some way. I'll and add this change, and possibly others to make writing "your own" NewWithFixedVersion analog easier, such as public functions for "utility" work, and public functions, and possibly decomposing encode a bit.

My particular case, generating an insane amount of qr codes:

  • All data is identical in length
  • All data is either alphanum or binary, 99% alphanum
  • Version is fixed
  • Ecc has a min value, but > that is fine
  • Speed is important
  • No image generation/etc (I do that manually from the bitmap)

Anyway, the code has been wonderful to work with. Its easy for me to put something together that does just the 1 thing I want, but you have so much more in there! Feel free to close this, as you see fit.

@fenglijunnb
Copy link

@awbacker
Hi Andrew.
I really appreciate your PR, but I have a question about how to generate the flower-style QR code. I really don't have a clue. I hope you can help me
1

@fenglijunnb
Copy link

@awbacker This is a similar image that I downloaded from some platforms

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants