reed_solomon.go 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. // go-qrcode
  2. // Copyright 2014 Tom Harwood
  3. // Package reedsolomon provides error correction encoding for QR Code 2005.
  4. //
  5. // QR Code 2005 uses a Reed-Solomon error correcting code to detect and correct
  6. // errors encountered during decoding.
  7. //
  8. // The generated RS codes are systematic, and consist of the input data with
  9. // error correction bytes appended.
  10. package reedsolomon
  11. import (
  12. "log"
  13. bitset "github.com/skip2/go-qrcode/bitset"
  14. )
  15. // Encode data for QR Code 2005 using the appropriate Reed-Solomon code.
  16. //
  17. // numECBytes is the number of error correction bytes to append, and is
  18. // determined by the target QR Code's version and error correction level.
  19. //
  20. // ISO/IEC 18004 table 9 specifies the numECBytes required. e.g. a 1-L code has
  21. // numECBytes=7.
  22. func Encode(data *bitset.Bitset, numECBytes int) *bitset.Bitset {
  23. // Create a polynomial representing |data|.
  24. //
  25. // The bytes are interpreted as the sequence of coefficients of a polynomial.
  26. // The last byte's value becomes the x^0 coefficient, the second to last
  27. // becomes the x^1 coefficient and so on.
  28. ecpoly := newGFPolyFromData(data)
  29. ecpoly = gfPolyMultiply(ecpoly, newGFPolyMonomial(gfOne, numECBytes))
  30. // Pick the generator polynomial.
  31. generator := rsGeneratorPoly(numECBytes)
  32. // Generate the error correction bytes.
  33. remainder := gfPolyRemainder(ecpoly, generator)
  34. // Combine the data & error correcting bytes.
  35. // The mathematically correct answer is:
  36. //
  37. // result := gfPolyAdd(ecpoly, remainder).
  38. //
  39. // The encoding used by QR Code 2005 is slightly different this result: To
  40. // preserve the original |data| bit sequence exactly, the data and remainder
  41. // are combined manually below. This ensures any most significant zero bits
  42. // are preserved (and not optimised away).
  43. result := bitset.Clone(data)
  44. result.AppendBytes(remainder.data(numECBytes))
  45. return result
  46. }
  47. // rsGeneratorPoly returns the Reed-Solomon generator polynomial with |degree|.
  48. //
  49. // The generator polynomial is calculated as:
  50. // (x + a^0)(x + a^1)...(x + a^degree-1)
  51. func rsGeneratorPoly(degree int) gfPoly {
  52. if degree < 2 {
  53. log.Panic("degree < 2")
  54. }
  55. generator := gfPoly{term: []gfElement{1}}
  56. for i := 0; i < degree; i++ {
  57. nextPoly := gfPoly{term: []gfElement{gfExpTable[i], 1}}
  58. generator = gfPolyMultiply(generator, nextPoly)
  59. }
  60. return generator
  61. }