fckeuspy-go/vendor/github.com/makiuchi-d/gozxing/qrcode/decoder/decoder.go
2025-09-28 21:03:39 +02:00

169 lines
4.5 KiB
Go

package decoder
import (
"github.com/makiuchi-d/gozxing"
"github.com/makiuchi-d/gozxing/common"
"github.com/makiuchi-d/gozxing/common/reedsolomon"
)
type Decoder struct {
rsDecoder *reedsolomon.ReedSolomonDecoder
}
func NewDecoder() *Decoder {
return &Decoder{
rsDecoder: reedsolomon.NewReedSolomonDecoder(reedsolomon.GenericGF_QR_CODE_FIELD_256),
}
}
func (this *Decoder) DecodeBoolMapWithoutHint(image [][]bool) (*common.DecoderResult, error) {
return this.DecodeBoolMap(image, nil)
}
func (this *Decoder) DecodeBoolMap(image [][]bool, hints map[gozxing.DecodeHintType]interface{}) (*common.DecoderResult, error) {
bits, e := gozxing.ParseBoolMapToBitMatrix(image)
if e != nil {
return nil, e
}
return this.Decode(bits, hints)
}
func (this *Decoder) DecodeWithoutHint(bits *gozxing.BitMatrix) (*common.DecoderResult, error) {
return this.Decode(bits, nil)
}
func (this *Decoder) Decode(bits *gozxing.BitMatrix, hints map[gozxing.DecodeHintType]interface{}) (*common.DecoderResult, error) {
// Construct a parser and read version, error-correction level
parser, e := NewBitMatrixParser(bits)
if e != nil {
return nil, gozxing.WrapFormatException(e)
}
var fece gozxing.ReaderException
result, e := this.decode(parser, hints)
if e == nil {
return result, nil
}
switch e.(type) {
case gozxing.FormatException, gozxing.ChecksumException:
fece = e.(gozxing.ReaderException)
}
e = nil
// Revert the bit matrix
parser.Remask()
// Will be attempting a mirrored reading of the version and format info.
parser.SetMirror(true)
if e == nil {
// Preemptively read the version.
_, e = parser.ReadVersion()
}
if e == nil {
// Preemptively read the format information.
_, e = parser.ReadFormatInformation()
}
if e == nil {
/*
* Since we're here, this means we have successfully detected some kind
* of version and format information when mirrored. This is a good sign,
* that the QR code may be mirrored, and we should try once more with a
* mirrored content.
*/
// Prepare for a mirrored reading.
parser.Mirror()
}
if e == nil {
result, e = this.decode(parser, hints)
}
if e == nil {
// Success! Notify the caller that the code was mirrored.
result.SetOther(NewQRCodeDecoderMetaData(true))
return result, nil
}
// `e` is not nil
switch e.(type) {
case gozxing.FormatException, gozxing.ChecksumException:
// Throw the exception from the original reading
return nil, fece
default:
return nil, e
}
}
func (this *Decoder) decode(parser *BitMatrixParser, hints map[gozxing.DecodeHintType]interface{}) (*common.DecoderResult, error) {
version, e := parser.ReadVersion()
if e != nil {
return nil, gozxing.WrapFormatException(e)
}
formatinfo, e := parser.ReadFormatInformation()
if e != nil {
return nil, gozxing.WrapFormatException(e)
}
ecLevel := formatinfo.GetErrorCorrectionLevel()
// Read codewords
codewords, e := parser.ReadCodewords()
if e != nil {
return nil, gozxing.WrapFormatException(e)
}
// Separate into data blocks
dataBlocks, e := DataBlock_GetDataBlocks(codewords, version, ecLevel)
if e != nil {
return nil, gozxing.WrapFormatException(e)
}
// Count total number of data bytes
totalBytes := 0
for _, dataBlock := range dataBlocks {
totalBytes += dataBlock.GetNumDataCodewords()
}
resultBytes := make([]byte, totalBytes)
resultOffset := 0
// Error-correct and copy data blocks together into a stream of bytes
for _, dataBlock := range dataBlocks {
codewordBytes := dataBlock.GetCodewords()
numDataCodewords := dataBlock.GetNumDataCodewords()
e := this.correctErrors(codewordBytes, numDataCodewords)
if e != nil {
return nil, e
}
for i := 0; i < numDataCodewords; i++ {
resultBytes[resultOffset] = codewordBytes[i]
resultOffset++
}
}
// Decode the contents of that stream of bytes
return DecodedBitStreamParser_Decode(resultBytes, version, ecLevel, hints)
}
func (this *Decoder) correctErrors(codewordBytes []byte, numDataCodewords int) error {
numCodewords := len(codewordBytes)
// First read into an array of ints
codewordsInts := make([]int, numCodewords)
for i := 0; i < numCodewords; i++ {
codewordsInts[i] = int(codewordBytes[i] & 0xFF)
}
e := this.rsDecoder.Decode(codewordsInts, numCodewords-numDataCodewords)
if e != nil {
return gozxing.WrapChecksumException(e)
}
// Copy back into array of bytes -- only need to worry about the bytes that were data
// We don't care about errors in the error-correction codewords
for i := 0; i < numDataCodewords; i++ {
codewordBytes[i] = byte(codewordsInts[i])
}
return nil
}