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

393 lines
8.7 KiB
Go

package gozxing
import (
"math/bits"
"strings"
errors "golang.org/x/xerrors"
)
type BitMatrix struct {
width int
height int
rowSize int
bits []uint32
}
func NewSquareBitMatrix(dimension int) (*BitMatrix, error) {
return NewBitMatrix(dimension, dimension)
}
func NewBitMatrix(width, height int) (*BitMatrix, error) {
if width < 1 || height < 1 {
return nil, errors.New("IllegalArgumentException: Both dimensions must be greater than 0")
}
rowSize := (width + 31) / 32
bits := make([]uint32, rowSize*height)
return &BitMatrix{width, height, rowSize, bits}, nil
}
func ParseBoolMapToBitMatrix(image [][]bool) (*BitMatrix, error) {
var width, height int
height = len(image)
if height > 0 {
width = len(image[0])
}
bits, e := NewBitMatrix(width, height)
if e != nil {
return nil, e
}
for i := 0; i < height; i++ {
imageI := image[i]
for j := 0; j < width; j++ {
if imageI[j] {
bits.Set(j, i)
}
}
}
return bits, nil
}
func ParseStringToBitMatrix(stringRepresentation, setString, unsetString string) (*BitMatrix, error) {
if stringRepresentation == "" {
return nil, errors.New("IllegalArgumentException")
}
bits := make([]bool, len(stringRepresentation))
bitsPos := 0
rowStartPos := 0
rowLength := -1
nRows := 0
pos := 0
for pos < len(stringRepresentation) {
if c := stringRepresentation[pos]; c == '\n' || c == '\r' {
if bitsPos > rowStartPos {
if rowLength == -1 {
rowLength = bitsPos - rowStartPos
} else if bitsPos-rowStartPos != rowLength {
return nil, errors.New("IllegalArgumentException: row length do not match")
}
rowStartPos = bitsPos
nRows++
}
pos++
} else if strings.HasPrefix(stringRepresentation[pos:], setString) {
pos += len(setString)
bits[bitsPos] = true
bitsPos++
} else if strings.HasPrefix(stringRepresentation[pos:], unsetString) {
pos += len(unsetString)
bits[bitsPos] = false
bitsPos++
} else {
return nil, errors.New(
"IllegalArgumentException: illegal character encountered: " + stringRepresentation[pos:])
}
}
if bitsPos > rowStartPos {
if rowLength == -1 {
rowLength = bitsPos - rowStartPos
} else if bitsPos-rowStartPos != rowLength {
return nil, errors.New("IllegalArgumentException: row length do not match")
}
nRows++
}
matrix, e := NewBitMatrix(rowLength, nRows)
if e != nil {
return nil, e
}
for i := 0; i < bitsPos; i++ {
if bits[i] {
matrix.Set(i%rowLength, i/rowLength)
}
}
return matrix, nil
}
func (b *BitMatrix) Get(x, y int) bool {
if x < 0 || x >= b.width || y < 0 || y >= b.height {
return false
}
offset := (y * b.rowSize) + (x / 32)
return ((b.bits[offset] >> uint(x%32)) & 1) != 0
}
func (b *BitMatrix) Set(x, y int) {
offset := (y * b.rowSize) + (x / 32)
b.bits[offset] |= 1 << uint(x%32)
}
func (b *BitMatrix) Unset(x, y int) {
offset := (y * b.rowSize) + (x / 32)
b.bits[offset] &= ^(1 << uint(x%32))
}
func (b *BitMatrix) Flip(x, y int) {
offset := (y * b.rowSize) + (x / 32)
b.bits[offset] ^= 1 << uint(x%32)
}
func (b *BitMatrix) FlipAll() {
max := len(b.bits)
for i := 0; i < max; i++ {
b.bits[i] = ^b.bits[i]
}
}
func (b *BitMatrix) Xor(mask *BitMatrix) error {
if b.width != mask.width || b.height != mask.height || b.rowSize != mask.rowSize {
return errors.New("IllegalArgumentException: input matrix dimensions do not match")
}
for y := 0; y < b.height; y++ {
bOffset := y * b.rowSize
mOffset := y * mask.rowSize
for x := 0; x < b.rowSize; x++ {
b.bits[bOffset+x] ^= mask.bits[mOffset+x]
}
}
return nil
}
func (b *BitMatrix) Clear() {
max := len(b.bits)
for i := 0; i < max; i++ {
b.bits[i] = 0
}
}
func (b *BitMatrix) SetRegion(left, top, width, height int) error {
if top < 0 || left < 0 {
return errors.New("IllegalArgumentException: Left and top must be nonnegative")
}
if height < 1 || width < 1 {
return errors.New("IllegalArgumentException: Height and width must be at least 1")
}
right := left + width
bottom := top + height
if bottom > b.height || right > b.width {
return errors.New("IllegalArgumentException: The region must fit inside the matrix")
}
for y := top; y < bottom; y++ {
offset := y * b.rowSize
for x := left; x < right; x++ {
b.bits[offset+(x/32)] |= 1 << uint(x%32)
}
}
return nil
}
func (b *BitMatrix) GetRow(y int, row *BitArray) *BitArray {
if row == nil || row.GetSize() < b.width {
row = NewBitArray(b.width)
} else {
row.Clear()
}
offset := y * b.rowSize
for x := 0; x < b.rowSize; x++ {
row.SetBulk(x*32, b.bits[offset+x])
}
return row
}
func (b *BitMatrix) SetRow(y int, row *BitArray) {
offset := y * b.rowSize
copy(b.bits[offset:offset+b.rowSize], row.bits)
}
func (b *BitMatrix) Rotate180() {
height := b.height
rowSize := b.rowSize
for i := 0; i < height/2; i++ {
topOffset := i * rowSize
bottomOffset := (height-i)*rowSize - 1
for j := 0; j < rowSize; j++ {
top := topOffset + j
bottom := bottomOffset - j
b.bits[top], b.bits[bottom] = b.bits[bottom], b.bits[top]
}
}
if height%2 != 0 {
offset := rowSize * (height - 1) / 2
for j := 0; j < rowSize/2; j++ {
left := offset + j
right := offset + rowSize - 1 - j
b.bits[left], b.bits[right] = b.bits[right], b.bits[left]
}
}
if shift := uint(b.width % 32); shift != 0 {
for i := 0; i < height; i++ {
offset := rowSize * i
b.bits[offset] = bits.Reverse32(b.bits[offset]) >> uint(32-shift)
for j := 1; j < rowSize; j++ {
curbits := bits.Reverse32(b.bits[offset+j])
b.bits[offset+j-1] |= curbits << shift
b.bits[offset+j] = curbits >> uint(32-shift)
}
}
}
}
func (b *BitMatrix) Rotate90() {
newWidth := b.height
newHeight := b.width
newRowSize := (newWidth + 31) / 32
newBits := make([]uint32, newRowSize*newHeight)
for y := 0; y < b.height; y++ {
for x := 0; x < b.width; x++ {
offset := y*b.rowSize + (x / 32)
if ((b.bits[offset] >> (x & 0x1f)) & 1) != 0 {
newOffset := (newHeight-1-x)*newRowSize + (y / 32)
newBits[newOffset] |= 1 << (y & 0x1f)
}
}
}
b.width = newWidth
b.height = newHeight
b.rowSize = newRowSize
b.bits = newBits
}
func (b *BitMatrix) GetEnclosingRectangle() []int {
left := b.width
top := b.height
right := -1
bottom := -1
for y := 0; y < b.height; y++ {
for x32 := 0; x32 < b.rowSize; x32++ {
theBits := b.bits[y*b.rowSize+x32]
if theBits != 0 {
if y < top {
top = y
}
if y > bottom {
bottom = y
}
if x32*32 < left {
bit := 0
for (theBits << uint(31-bit)) == 0 {
bit++
}
if (x32*32 + bit) < left {
left = x32*32 + bit
}
}
if x32*32+31 > right {
bit := 31
for (theBits >> uint(bit)) == 0 {
bit--
}
if (x32*32 + bit) > right {
right = x32*32 + bit
}
}
}
}
}
if right < left || bottom < top {
return nil
}
return []int{left, top, right - left + 1, bottom - top + 1}
}
func (b *BitMatrix) GetTopLeftOnBit() []int {
bitsOffset := 0
for bitsOffset < len(b.bits) && b.bits[bitsOffset] == 0 {
bitsOffset++
}
if bitsOffset == len(b.bits) {
return nil
}
y := bitsOffset / b.rowSize
x := (bitsOffset % b.rowSize) * 32
theBits := b.bits[bitsOffset]
bit := uint(0)
for (theBits << (31 - bit)) == 0 {
bit++
}
x += int(bit)
return []int{x, y}
}
func (b *BitMatrix) GetBottomRightOnBit() []int {
bitsOffset := len(b.bits) - 1
for bitsOffset >= 0 && b.bits[bitsOffset] == 0 {
bitsOffset--
}
if bitsOffset < 0 {
return nil
}
y := bitsOffset / b.rowSize
x := (bitsOffset % b.rowSize) * 32
theBits := b.bits[bitsOffset]
bit := uint(31)
for (theBits >> bit) == 0 {
bit--
}
x += int(bit)
return []int{x, y}
}
func (b *BitMatrix) GetWidth() int {
return b.width
}
func (b *BitMatrix) GetHeight() int {
return b.height
}
func (b *BitMatrix) GetRowSize() int {
return b.rowSize
}
// public boolean equals(Object o)
// public int hashCode()
func (b *BitMatrix) String() string {
return b.ToString("X ", " ")
}
func (b *BitMatrix) ToString(setString, unsetString string) string {
return b.ToStringWithLineSeparator(setString, unsetString, "\n")
}
func (b *BitMatrix) ToStringWithLineSeparator(setString, unsetString, lineSeparator string) string {
setBytes := []byte(setString)
unsetBytes := []byte(unsetString)
lineSepBytes := []byte(lineSeparator)
lineSize := len(lineSeparator)
if len(setString) > len(unsetString) {
lineSize += b.width * len(setString)
} else {
lineSize += b.width * len(unsetString)
}
result := make([]byte, 0, b.height*lineSize)
for y := 0; y < b.height; y++ {
for x := 0; x < b.width; x++ {
var s []byte
if b.Get(x, y) {
s = setBytes
} else {
s = unsetBytes
}
result = append(result, s...)
}
result = append(result, lineSepBytes...)
}
return string(result)
}
// public BitMatrix clone()