unipdf/internal/jbig2/bitmap/components_test.go
Jacek Kucharczyk c582323a8f
JBIG2 Generic Encoder (#264)
* Prepared skeleton and basic component implementations for the jbig2 encoding.

* Added Bitset. Implemented Bitmap.

* Decoder with old Arithmetic Decoder

* Partly working arithmetic

* Working arithmetic decoder.

* MMR patched.

* rebuild to apache.

* Working generic

* Working generic

* Decoded full document

* Update Jenkinsfile go version [master] (#398)

* Update Jenkinsfile go version

* Decoded AnnexH document

* Minor issues fixed.

* Update README.md

* Fixed generic region errors. Added benchmark. Added bitmap unpadder. Added Bitmap toImage method.

* Fixed endofpage error

* Added integration test.

* Decoded all test files without errors. Implemented JBIG2Global.

* Merged with v3 version

* Fixed the EOF in the globals issue

* Fixed the JBIG2 ChocolateData Decode

* JBIG2 Added license information

* Minor fix in jbig2 encoding.

* Applied the logging convention

* Cleaned unnecessary imports

* Go modules clear unused imports

* checked out the README.md

* Moved trace to Debug. Fixed the build integrate tag in the document_decode_test.go

* Initial encoder skeleton

* Applied UniPDF Developer Guide. Fixed lint issues.

* Cleared documentation, fixed style issues.

* Added jbig2 doc.go files. Applied unipdf guide style.

* Minor code style changes.

* Minor naming and style issues fixes.

* Minor naming changes. Style issues fixed.

* Review r11 fixes.

* Added JBIG2 Encoder skeleton.

* Moved Document and Page to jbig2/document package. Created decoder package responsible for decoding jbig2 stream.

* Implemented raster functions.

* Added raster uni low test funcitons.

* Added raster low test functions

* untracked files on jbig2-encoder: c869089 Added raster low test functions

* index on jbig2-encoder: c869089 Added raster low test functions

* Added morph files.

* implemented jbig2 encoder basics

* JBIG2 Encoder - Generic method

* Added jbig2 image encode ttests, black/white image tests

* cleaned and tested jbig2 package

* unfinished jbig2 classified encoder

* jbig2 minor style changes

* minor jbig2 encoder changes

* prepared JBIG2 Encoder

* Style and lint fixes

* Minor changes and lints

* Fixed shift unsinged value build errors

* Minor naming change

* Added jbig2 encode, image gondels. Fixed jbig2 decode bug.

* Provided jbig2 core.DecodeGlobals function.

* Fixed JBIG2Encoder `r6` revision issues.

* Removed public JBIG2Encoder document.

* Minor style changes

* added NewJBIG2Encoder function.

* fixed JBIG2Encoder 'r9' revision issues.

* Cleared 'r9' commented code.

* Updated ACKNOWLEDGEMENETS. Fixed JBIG2Encoder 'r10' revision issues.

Co-authored-by: Gunnsteinn Hall <gunnsteinn.hall@gmail.com>
2020-03-27 11:47:41 +00:00

1396 lines
46 KiB
Go

/*
* This file is subject to the terms and conditions defined in
* file 'LICENSE.md', which is part of this source code package.
*/
package bitmap
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/unidoc/unipdf/v3/common"
)
// BenchmarkGetComponents benchmarks the get components methods.
func BenchmarkGetComponents(b *testing.B) {
// Having a bitmap 50x22 with few different components like letters.
//
// 1 2 3 4 5 6 7
//
// 111111 11112222 22222233 33333333 44444444 44
// 01234567 89012345 67890123 45678901 23456789 01234567 89
//
// 0 00000000 00000000 00000000 00000000 00000000 00000000 00000000
// 1 00000000 00000000 00000000 00000000 00000000 00000000 00000000
// 2 00111110 01111000 00100111 11000010 00100111 10010001 00000000
// 3 00100010 01001000 00100001 00000011 00100100 10010001 00000000
// 4 00100010 01001000 00100001 00000010 10100100 10010101 00000000
// 5 00100010 01001000 00100001 00000010 01100100 10011011 00000000
// 6 00111100 01111000 00100001 00000010 00100111 10010001 00000000
// 7 00000000 00000000 00000000 00000000 00000000 00000000 00000000
// 8 00000000 00000000 00000000 00000000 00000000 00000000 00000000
// 9 00000000 00000000 00000000 00000000 00000000 00000000 00000000
// 10 00000000 00000000 00000000 00000000 00000000 00000000 00000000
// 11 00000000 00000000 00000000 00000000 00000000 00000000 00000000
// 12 00000000 00000000 00000000 00000000 00000000 00000000 00000000
// 13 00000000 00000000 01111111 11111000 00000000 00000000 00000000
// 14 00000000 00000000 01111111 11111000 00000000 00000000 00000000
// 15 00000000 00000000 01100011 00011000 00000000 00000000 00000000
// 16 00000000 00000000 01100011 00011000 00000000 00000000 00000000
// 17 00000000 00000000 01100011 00011000 00000000 00000000 00000000
// 18 00000000 00000000 01111111 11111000 00000000 00000000 00000000
// 19 00000000 00000000 00010101 01010000 00000000 00000000 00000000
// 20 00000000 00000000 00000000 00000000 00000000 00000000 00000000
// 21 00000000 00000000 00000000 00000000 00000000 00000000 00000000
//
//
data := []byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3E, 0x78, 0x27, 0xC2, 0x27, 0x91, 0x00,
0x22, 0x48, 0x21, 0x03, 0x24, 0x91, 0x00,
0x22, 0x48, 0x21, 0x02, 0xA4, 0x95, 0x00,
0x22, 0x48, 0x21, 0x02, 0x64, 0x9B, 0x00,
0x3C, 0x78, 0x21, 0x02, 0x27, 0x91, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7F, 0xF8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7F, 0xF8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x63, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x63, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x63, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7F, 0xF8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x15, 0x50, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}
bm, err := NewWithData(50, 22, data)
require.NoError(b, err)
type bmSizes struct {
name string
bm *Bitmap
size int
}
bm2, err := expandBinaryPower2(bm, 2)
require.NoError(b, err)
bm4, err := expandBinaryPower2(bm, 4)
require.NoError(b, err)
bm8, err := expandBinaryPower2(bm, 8)
require.NoError(b, err)
sizes := []*bmSizes{
{"One", bm, 1},
{"Two", bm2, 2},
{"Four", bm4, 4},
{"Eight", bm8, 8},
}
b.Run("ComponentConn", func(b *testing.B) {
w, h := 12, 8
for _, size := range sizes {
b.Run(size.name, func(b *testing.B) {
var bmB *Bitmap
maxW, maxH := w*size.size, h*size.size
for i := 0; i < b.N; i++ {
b.StopTimer()
bmB, err = copyBitmap(nil, size.bm)
require.NoError(b, err)
b.StartTimer()
_, _, err = bmB.GetComponents(ComponentConn, maxW, maxH)
assert.NoError(b, err)
}
})
}
})
b.Run("ComponentCharacters", func(b *testing.B) {
w, h := 12, 8
for _, size := range sizes {
b.Run(size.name, func(b *testing.B) {
var bmB *Bitmap
maxW, maxH := w*size.size, h*size.size
for i := 0; i < b.N; i++ {
b.StopTimer()
bmB, err = copyBitmap(nil, size.bm)
require.NoError(b, err)
b.StartTimer()
_, _, err = bmB.GetComponents(ComponentCharacters, maxW, maxH)
assert.NoError(b, err)
}
})
}
})
b.Run("ComponentWords", func(b *testing.B) {
w, h := 20, 8
for _, size := range sizes {
b.Run(size.name, func(b *testing.B) {
var bmB *Bitmap
maxW, maxH := w*size.size, h*size.size
for i := 0; i < b.N; i++ {
b.StopTimer()
bmB, err = copyBitmap(nil, size.bm)
require.NoError(b, err)
b.StartTimer()
_, _, err = bmB.GetComponents(ComponentWords, maxW, maxH)
assert.NoError(b, err)
}
})
}
})
}
// TestConnComponents is the function that tests the connectivity components methods.
func TestConnComponents(t *testing.T) {
// Having a bitmap 50x18 with few different components like letters
//
// 1 2 3 4 5 6 7
//
// 111111 11112222 22222233 33333333 44444444 44
// 01234567 89012345 67890123 45678901 23456789 01234567 89
//
// 0 00000000 00000000 00000000 00000000 00000000 00000000 00000000
// 1 00000000 00000000 00000000 00000000 00000000 00000000 00000000
// 2 00111110 01111000 00100111 11000010 00100111 10010001 00000000
// 3 00100010 01001000 00100001 00000011 00100100 10010001 00000000
// 4 00100010 01001000 00100001 00000010 10100100 10010101 00000000
// 5 00100010 01001000 00100001 00000010 01100100 10011011 00000000
// 6 00111100 01111000 00100001 00000010 00100111 10010001 00000000
// 7 00000000 00000000 00000000 00000000 00000000 00000000 00000000
// 8 00000000 00000000 00000000 00000000 00000000 00000000 00000000
// 9 00000000 00000000 01111111 11111000 00000000 00000000 00000000
// 10 00000000 00000000 01111111 11111000 00000000 00000000 00000000
// 11 00000000 00000000 01100011 00011000 00000000 00000000 00000000
// 12 00000000 00000000 01100011 00011000 00000000 00000000 00000000
// 13 00000000 00000000 01100011 00011000 00000000 00000000 00000000
// 14 00000000 00000000 01111111 11111000 00000000 00000000 00000000
// 15 00000000 00000000 00010101 01010000 00000000 00000000 00000000
// 16 00000000 00000000 00000000 00000000 00000000 00000000 00000000
// 17 00000000 00000000 00000000 00000000 00000000 00000000 00000000
//
//
data := []byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3E, 0x78, 0x27, 0xC2, 0x27, 0x91, 0x00,
0x22, 0x48, 0x21, 0x03, 0x24, 0x91, 0x00,
0x22, 0x48, 0x21, 0x02, 0xA4, 0x95, 0x00,
0x22, 0x48, 0x21, 0x02, 0x64, 0x9B, 0x00,
0x3C, 0x78, 0x21, 0x02, 0x27, 0x91, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7F, 0xF8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7F, 0xF8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x63, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x63, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x63, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7F, 0xF8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x15, 0x50, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}
bm, err := NewWithData(50, 18, data)
require.NoError(t, err)
common.SetLogger(common.NewConsoleLogger(common.LogLevelDebug))
t.Run("Connectivity8", func(t *testing.T) {
// for connectivity 8 there should be 8 components:
// letters: d, o, i, t, n, o, w
// and a skull image.
t.Run("WithBitmaps", func(t *testing.T) {
bitmaps := &Bitmaps{}
bm, err := copyBitmap(nil, bm)
require.NoError(t, err)
boxes, err := bm.ConnComponents(bitmaps, 8)
require.NoError(t, err)
if assert.Len(t, bitmaps.Values, 8) && assert.Len(t, *boxes, 8) {
for i, bm := range bitmaps.Values {
box := bitmaps.Boxes[i]
switch i {
case 0:
assert.Equal(t, 5, bm.Width)
assert.Equal(t, 5, bm.Height)
// Letter 'D' - expected data:
//
// 11111000 0xF8
// 10001000 0x88
// 10001000 0x88
// 10001000 0x88
// 11110000 0xF0
assert.Equal(t, []byte{0xF8, 0x88, 0x88, 0x88, 0xF0}, bm.Data)
assert.Equal(t, box.Min.X, 2)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 6+1)
assert.Equal(t, box.Max.Y, 6+1)
case 1:
assert.Equal(t, 4, bm.Width)
assert.Equal(t, 5, bm.Height)
// Letter 'O' - expected data:
//
// 11110000 - 0xF0
// 10010000 - 0x90
// 10010000 - 0x90
// 10010000 - 0x90
// 11110000 - 0xF0
assert.Equal(t, []byte{0xF0, 0x90, 0x90, 0x90, 0xF0}, bm.Data)
assert.Equal(t, box.Min.X, 9)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 12+1)
assert.Equal(t, box.Max.Y, 6+1)
case 2:
assert.Equal(t, 1, bm.Width)
assert.Equal(t, 5, bm.Height)
// Letter 'I' - expected data:
//
// 10000000 - 0x80
// 10000000 - 0x80
// 10000000 - 0x80
// 10000000 - 0x80
// 10000000 - 0x80
assert.Equal(t, []byte{0x80, 0x80, 0x80, 0x80, 0x80}, bm.Data)
assert.Equal(t, box.Min.X, 18)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 18+1)
assert.Equal(t, box.Max.Y, 6+1)
case 3:
assert.Equal(t, 5, bm.Width)
assert.Equal(t, 5, bm.Width)
// Letter 'T' - expected data:
//
// 11111000 - 0xF8
// 00100000 - 0x20
// 00100000 - 0x20
// 00100000 - 0x20
// 00100000 - 0x20
assert.Equal(t, []byte{0xF8, 0x20, 0x20, 0x20, 0x20}, bm.Data)
assert.Equal(t, box.Min.X, 21)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 25+1)
assert.Equal(t, box.Max.Y, 6+1)
case 4:
assert.Equal(t, 5, bm.Width)
assert.Equal(t, 5, bm.Height)
// Letter 'N' - expected data:
//
// 10001000 - 0x88
// 11001000 - 0xC8
// 10101000 - 0xA8
// 10011000 - 0x98
// 10001000 - 0x88
assert.Equal(t, []byte{0x88, 0xC8, 0xA8, 0x98, 0x88}, bm.Data)
assert.Equal(t, box.Min.X, 30)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 34+1)
assert.Equal(t, box.Max.Y, 6+1)
case 5:
assert.Equal(t, 4, bm.Width)
assert.Equal(t, 5, bm.Height)
// Letter 'O' - expected data:
//
// 11110000 - 0xF0
// 10010000 - 0x90
// 10010000 - 0x90
// 10010000 - 0x90
// 11110000 - 0xF0
assert.Equal(t, []byte{0xF0, 0x90, 0x90, 0x90, 0xF0}, bm.Data)
assert.Equal(t, box.Min.X, 37)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 40+1)
assert.Equal(t, box.Max.Y, 6+1)
case 6:
assert.Equal(t, 5, bm.Width)
assert.Equal(t, 5, bm.Height)
// Letter 'W' - expected data:
//
// 10001000 - 0x88
// 10001000 - 0x88
// 10101000 - 0xA8
// 11011000 - 0xD8
// 10001000 - 0x88
assert.Equal(t, []byte{0x88, 0x88, 0xA8, 0xD8, 0x88}, bm.Data)
assert.Equal(t, box.Min.X, 43)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 47+1)
assert.Equal(t, box.Max.Y, 6+1)
case 7:
// the last one is the the image
//
// 11111111 11110000 - 0xFF, 0xF0
// 11111111 11110000 - 0xFF, 0xF0
// 11000110 00110000 - 0xC6, 0x30
// 11000110 00110000 - 0xC6, 0x30
// 11000110 00110000 - 0xC6, 0x30
// 11111111 11110000 - 0xFF, 0xF0
// 00101010 10100000 - 0x2A, 0xA0
assert.Equal(t, 12, bm.Width)
assert.Equal(t, 7, bm.Height)
assert.Equal(t, []byte{0xFF, 0xF0, 0xFF, 0xF0, 0xC6, 0x30, 0xC6, 0x30, 0xC6, 0x30, 0xFF, 0xF0, 0x2A, 0xA0}, bm.Data)
assert.Equal(t, box.Min.X, 17)
assert.Equal(t, box.Min.Y, 9)
assert.Equal(t, box.Max.X, 28+1)
assert.Equal(t, box.Max.Y, 15+1)
}
}
}
})
t.Run("OnlyBoxes", func(t *testing.T) {
bm, err := copyBitmap(nil, bm)
require.NoError(t, err)
boxes, err := bm.ConnComponents(nil, 8)
require.NoError(t, err)
require.Len(t, *boxes, 8)
for i, box := range *boxes {
switch i {
case 0:
assert.Equal(t, box.Min.X, 2)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 6+1)
assert.Equal(t, box.Max.Y, 6+1)
case 1:
assert.Equal(t, box.Min.X, 9)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 12+1)
assert.Equal(t, box.Max.Y, 6+1)
case 2:
assert.Equal(t, box.Min.X, 18)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 18+1)
assert.Equal(t, box.Max.Y, 6+1)
case 3:
assert.Equal(t, box.Min.X, 21)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 25+1)
assert.Equal(t, box.Max.Y, 6+1)
case 4:
assert.Equal(t, box.Min.X, 30)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 34+1)
assert.Equal(t, box.Max.Y, 6+1)
case 5:
assert.Equal(t, box.Min.X, 37)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 40+1)
assert.Equal(t, box.Max.Y, 6+1)
case 6:
assert.Equal(t, box.Min.X, 43)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 47+1)
assert.Equal(t, box.Max.Y, 6+1)
case 7:
assert.Equal(t, box.Min.X, 17)
assert.Equal(t, box.Min.Y, 9)
assert.Equal(t, box.Max.X, 28+1)
assert.Equal(t, box.Max.Y, 15+1)
}
}
})
})
t.Run("Connectivity4", func(t *testing.T) {
// Having the connectivity of '4' the letters that
// are connected using their corners are not treated
// as single letter.
// Thus when there were '8' symbols in '8' connectivity
// the letter 'N' and 'W' both disassembles into 3 copmonents.
// This gives us 8-2+3+3 = 12 classes.
t.Run("WithBitmaps", func(t *testing.T) {
bitmaps := &Bitmaps{}
bm, err := copyBitmap(nil, bm)
require.NoError(t, err)
boxes, err := bm.ConnComponents(bitmaps, 4)
require.NoError(t, err)
require.NotNil(t, boxes)
cond := assert.Len(t, bitmaps.Values, 12) && assert.Len(t, *boxes, 12) && assert.Len(t, bitmaps.Boxes, 12)
require.True(t, cond)
for i, bm := range bitmaps.Values {
// The box in bitmaps must be equal to box as an output.
box := bitmaps.Boxes[i]
assert.Equal(t, box, (*boxes)[i])
switch i {
case 0:
assert.Equal(t, 5, bm.Width)
assert.Equal(t, 5, bm.Height)
// Letter 'D' - expected data:
//
// 11111000 0xF8
// 10001000 0x88
// 10001000 0x88
// 10001000 0x88
// 11110000 0xF0
assert.Equal(t, []byte{0xF8, 0x88, 0x88, 0x88, 0xF0}, bm.Data)
assert.Equal(t, box.Min.X, 2)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 6+1)
assert.Equal(t, box.Max.Y, 6+1)
case 1:
assert.Equal(t, 4, bm.Width)
assert.Equal(t, 5, bm.Height)
// Letter 'O' - expected data:
//
// 11110000 - 0xF0
// 10010000 - 0x90
// 10010000 - 0x90
// 10010000 - 0x90
// 11110000 - 0xF0
assert.Equal(t, []byte{0xF0, 0x90, 0x90, 0x90, 0xF0}, bm.Data)
assert.Equal(t, box.Min.X, 9)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 12+1)
assert.Equal(t, box.Max.Y, 6+1)
case 2:
assert.Equal(t, 1, bm.Width)
assert.Equal(t, 5, bm.Height)
// Letter 'I' - expected data:
//
// 10000000 - 0x80
// 10000000 - 0x80
// 10000000 - 0x80
// 10000000 - 0x80
// 10000000 - 0x80
assert.Equal(t, []byte{0x80, 0x80, 0x80, 0x80, 0x80}, bm.Data)
assert.Equal(t, box.Min.X, 18)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 18+1)
assert.Equal(t, box.Max.Y, 6+1)
case 3:
assert.Equal(t, 5, bm.Width)
assert.Equal(t, 5, bm.Width)
// Letter 'T' - expected data:
//
// 11111000 - 0xF8
// 00100000 - 0x20
// 00100000 - 0x20
// 00100000 - 0x20
// 00100000 - 0x20
assert.Equal(t, []byte{0xF8, 0x20, 0x20, 0x20, 0x20}, bm.Data)
assert.Equal(t, box.Min.X, 21)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 25+1)
assert.Equal(t, box.Max.Y, 6+1)
case 4:
assert.Equal(t, 2, bm.Width)
assert.Equal(t, 5, bm.Height)
// Left part of letter 'N' - expected data:
//
// 10000000 - 0x80
// 11000000 - 0xC0
// 10000000 - 0x80
// 10000000 - 0x80
// 10000000 - 0x80
assert.Equal(t, []byte{0x80, 0xC0, 0x80, 0x80, 0x80}, bm.Data)
assert.Equal(t, box.Min.X, 30)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 31+1)
assert.Equal(t, box.Max.Y, 6+1)
case 5:
// A right side of the letter 'N' - expected data:
//
// 01000000 - 0x40
// 01000000 - 0x40
// 01000000 - 0x40
// 11000000 - 0xC0
// 01000000 - 0x40
assert.Equal(t, 2, bm.Width)
assert.Equal(t, 5, bm.Height)
assert.Equal(t, []byte{0x40, 0x40, 0x40, 0xC0, 0x40}, bm.Data)
assert.Equal(t, box.Min.X, 33)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 34+1)
assert.Equal(t, box.Max.Y, 6+1)
case 6:
assert.Equal(t, 4, bm.Width)
assert.Equal(t, 5, bm.Height)
// Letter 'O' - expected data:
//
// 11110000 - 0xF0
// 10010000 - 0x90
// 10010000 - 0x90
// 10010000 - 0x90
// 11110000 - 0xF0
assert.Equal(t, []byte{0xF0, 0x90, 0x90, 0x90, 0xF0}, bm.Data)
assert.Equal(t, box.Min.X, 37)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 40+1)
assert.Equal(t, box.Max.Y, 6+1)
case 7:
// Left part of the letter 'W' - expected data:
// 10000000 - 0x80
// 10000000 - 0x80
// 10000000 - 0x80
// 11000000 - 0xC0
// 10000000 - 0x80
assert.Equal(t, 2, bm.Width)
assert.Equal(t, 5, bm.Height)
assert.Equal(t, []byte{0x80, 0x80, 0x80, 0xC0, 0x80}, bm.Data)
assert.Equal(t, box.Min.X, 43)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 44+1)
assert.Equal(t, box.Max.Y, 6+1)
case 8:
// The right part of the letter 'W' - expected data:
//
// 01000000 - 0x40
// 01000000 - 0x40
// 01000000 - 0x40
// 11000000 - 0xC0
// 01000000 - 0x40
assert.Equal(t, 2, bm.Width)
assert.Equal(t, 5, bm.Height)
assert.Equal(t, []byte{0x40, 0x40, 0x40, 0xC0, 0x40}, bm.Data)
assert.Equal(t, box.Min.X, 46)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 47+1)
assert.Equal(t, box.Max.Y, 6+1)
case 9:
// A single dot in the middle of 'N' letter - expected data:
// 10000000 - 0x80
assert.Equal(t, 1, bm.Width, bm)
assert.Equal(t, 1, bm.Height)
assert.Equal(t, []byte{0x80}, bm.Data)
assert.Equal(t, box.Min.X, 32)
assert.Equal(t, box.Min.Y, 4)
assert.Equal(t, box.Max.X, 32+1)
assert.Equal(t, box.Max.Y, 4+1)
case 10:
// The dot in the middle of the 'W' letter
// 100000000 - 0x80
assert.Equal(t, 1, bm.Width)
assert.Equal(t, 1, bm.Height)
assert.Equal(t, []byte{0x80}, bm.Data)
assert.Equal(t, box.Min.X, 45)
assert.Equal(t, box.Min.Y, 4)
assert.Equal(t, box.Max.X, 45+1)
assert.Equal(t, box.Max.Y, 4+1)
case 11:
// the last one is the the image
//
// 11111111 11110000 - 0xFF, 0xF0
// 11111111 11110000 - 0xFF, 0xF0
// 11000110 00110000 - 0xC6, 0x30
// 11000110 00110000 - 0xC6, 0x30
// 11000110 00110000 - 0xC6, 0x30
// 11111111 11110000 - 0xFF, 0xF0
// 00101010 10100000 - 0x2A, 0xA0
assert.Equal(t, 12, bm.Width)
assert.Equal(t, 7, bm.Height)
assert.Equal(t, []byte{0xFF, 0xF0, 0xFF, 0xF0, 0xC6, 0x30, 0xC6, 0x30, 0xC6, 0x30, 0xFF, 0xF0, 0x2A, 0xA0}, bm.Data)
assert.Equal(t, box.Min.X, 17)
assert.Equal(t, box.Min.Y, 9)
assert.Equal(t, box.Max.X, 28+1)
assert.Equal(t, box.Max.Y, 15+1)
}
}
})
t.Run("OnlyBoxes", func(t *testing.T) {
bm, err := copyBitmap(nil, bm)
require.NoError(t, err)
boxes, err := bm.ConnComponents(nil, 4)
require.NoError(t, err)
require.Len(t, *boxes, 12)
for i, box := range *boxes {
switch i {
case 0:
assert.Equal(t, box.Min.X, 2)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 6+1)
assert.Equal(t, box.Max.Y, 6+1)
case 1:
assert.Equal(t, box.Min.X, 9)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 12+1)
assert.Equal(t, box.Max.Y, 6+1)
case 2:
assert.Equal(t, box.Min.X, 18)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 18+1)
assert.Equal(t, box.Max.Y, 6+1)
case 3:
assert.Equal(t, box.Min.X, 21)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 25+1)
assert.Equal(t, box.Max.Y, 6+1)
case 4:
assert.Equal(t, box.Min.X, 30)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 31+1)
assert.Equal(t, box.Max.Y, 6+1)
case 5:
assert.Equal(t, box.Min.X, 33)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 34+1)
assert.Equal(t, box.Max.Y, 6+1)
case 6:
assert.Equal(t, box.Min.X, 37)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 40+1)
assert.Equal(t, box.Max.Y, 6+1)
case 7:
assert.Equal(t, box.Min.X, 43)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 44+1)
assert.Equal(t, box.Max.Y, 6+1)
case 8:
assert.Equal(t, box.Min.X, 46)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 47+1)
assert.Equal(t, box.Max.Y, 6+1)
case 9:
assert.Equal(t, box.Min.X, 32)
assert.Equal(t, box.Min.Y, 4)
assert.Equal(t, box.Max.X, 32+1)
assert.Equal(t, box.Max.Y, 4+1)
case 10:
assert.Equal(t, box.Min.X, 45)
assert.Equal(t, box.Min.Y, 4)
assert.Equal(t, box.Max.X, 45+1)
assert.Equal(t, box.Max.Y, 4+1)
case 11:
assert.Equal(t, box.Min.X, 17)
assert.Equal(t, box.Min.Y, 9)
assert.Equal(t, box.Max.X, 28+1)
assert.Equal(t, box.Max.Y, 15+1)
}
}
})
})
t.Run("Invalid", func(t *testing.T) {
t.Run("NoBitmap", func(t *testing.T) {
var bm *Bitmap
_, err := bm.ConnComponents(nil, 8)
require.Error(t, err)
})
t.Run("Connectivity", func(t *testing.T) {
// having any bitmap with some connectivity different
// then '4' and '8' - i.e. '2' should return error.
bm := New(10, 10)
_, err := bm.ConnComponents(nil, 2)
require.Error(t, err)
})
})
}
// TestGetComponents tests the GetComponents function.
func TestGetComponents(t *testing.T) {
// Having a bitmap 50x22 with few different components like letters.
//
// 1 2 3 4 5 6 7
//
// 111111 11112222 22222233 33333333 44444444 44
// 01234567 89012345 67890123 45678901 23456789 01234567 89
//
// 0 00000000 00000000 00000000 00000000 00000000 00000000 00000000
// 1 00000000 00000000 00000000 00000000 00000000 00000000 00000000
// 2 00111110 01111000 00100111 11000010 00100111 10010001 00000000
// 3 00100010 01001000 00100001 00000011 00100100 10010001 00000000
// 4 00100010 01001000 00100001 00000010 10100100 10010101 00000000
// 5 00100010 01001000 00100001 00000010 01100100 10011011 00000000
// 6 00111100 01111000 00100001 00000010 00100111 10010001 00000000
// 7 00000000 00000000 00000000 00000000 00000000 00000000 00000000
// 8 00000000 00000000 00000000 00000000 00000000 00000000 00000000
// 9 00000000 00000000 00000000 00000000 00000000 00000000 00000000
// 10 00000000 00000000 00000000 00000000 00000000 00000000 00000000
// 11 00000000 00000000 00000000 00000000 00000000 00000000 00000000
// 12 00000000 00000000 00000000 00000000 00000000 00000000 00000000
// 13 00000000 00000000 01111111 11111000 00000000 00000000 00000000
// 14 00000000 00000000 01111111 11111000 00000000 00000000 00000000
// 15 00000000 00000000 01100011 00011000 00000000 00000000 00000000
// 16 00000000 00000000 01100011 00011000 00000000 00000000 00000000
// 17 00000000 00000000 01100011 00011000 00000000 00000000 00000000
// 18 00000000 00000000 01111111 11111000 00000000 00000000 00000000
// 19 00000000 00000000 00010101 01010000 00000000 00000000 00000000
// 20 00000000 00000000 00000000 00000000 00000000 00000000 00000000
// 21 00000000 00000000 00000000 00000000 00000000 00000000 00000000
//
//
data := []byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3E, 0x78, 0x27, 0xC2, 0x27, 0x91, 0x00,
0x22, 0x48, 0x21, 0x03, 0x24, 0x91, 0x00,
0x22, 0x48, 0x21, 0x02, 0xA4, 0x95, 0x00,
0x22, 0x48, 0x21, 0x02, 0x64, 0x9B, 0x00,
0x3C, 0x78, 0x21, 0x02, 0x27, 0x91, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7F, 0xF8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7F, 0xF8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x63, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x63, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x63, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7F, 0xF8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x15, 0x50, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}
bm, err := NewWithData(50, 22, data)
require.NoError(t, err)
t.Run("ComponentConn", func(t *testing.T) {
t.Run("Max12-8", func(t *testing.T) {
// the highest component is 12 bits wide and 8bits tall.
// this should get all possible components out of the given input bitmap.
bm, err = copyBitmap(nil, bm)
require.NoError(t, err)
bitmaps, boxes, err := bm.GetComponents(ComponentConn, 12, 8)
require.NoError(t, err)
require.NotNil(t, bitmaps)
require.NotNil(t, boxes)
if assert.Len(t, bitmaps.Values, 8) && assert.Len(t, *boxes, 8) {
for i, bm := range bitmaps.Values {
box := bitmaps.Boxes[i]
switch i {
case 0:
assert.Equal(t, 5, bm.Width)
assert.Equal(t, 5, bm.Height)
// Letter 'D' - expected data:
//
// 11111000 0xF8
// 10001000 0x88
// 10001000 0x88
// 10001000 0x88
// 11110000 0xF0
assert.Equal(t, []byte{0xF8, 0x88, 0x88, 0x88, 0xF0}, bm.Data)
assert.Equal(t, box.Min.X, 2)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 6+1)
assert.Equal(t, box.Max.Y, 6+1)
case 1:
assert.Equal(t, 4, bm.Width)
assert.Equal(t, 5, bm.Height)
// Letter 'O' - expected data:
//
// 11110000 - 0xF0
// 10010000 - 0x90
// 10010000 - 0x90
// 10010000 - 0x90
// 11110000 - 0xF0
assert.Equal(t, []byte{0xF0, 0x90, 0x90, 0x90, 0xF0}, bm.Data)
assert.Equal(t, box.Min.X, 9)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 12+1)
assert.Equal(t, box.Max.Y, 6+1)
case 2:
assert.Equal(t, 1, bm.Width)
assert.Equal(t, 5, bm.Height)
// Letter 'I' - expected data:
//
// 10000000 - 0x80
// 10000000 - 0x80
// 10000000 - 0x80
// 10000000 - 0x80
// 10000000 - 0x80
assert.Equal(t, []byte{0x80, 0x80, 0x80, 0x80, 0x80}, bm.Data)
assert.Equal(t, box.Min.X, 18)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 18+1)
assert.Equal(t, box.Max.Y, 6+1)
case 3:
assert.Equal(t, 5, bm.Width)
assert.Equal(t, 5, bm.Width)
// Letter 'T' - expected data:
//
// 11111000 - 0xF8
// 00100000 - 0x20
// 00100000 - 0x20
// 00100000 - 0x20
// 00100000 - 0x20
assert.Equal(t, []byte{0xF8, 0x20, 0x20, 0x20, 0x20}, bm.Data)
assert.Equal(t, box.Min.X, 21)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 25+1)
assert.Equal(t, box.Max.Y, 6+1)
case 4:
assert.Equal(t, 5, bm.Width)
assert.Equal(t, 5, bm.Height)
// Letter 'N' - expected data:
//
// 10001000 - 0x88
// 11001000 - 0xC8
// 10101000 - 0xA8
// 10011000 - 0x98
// 10001000 - 0x88
assert.Equal(t, []byte{0x88, 0xC8, 0xA8, 0x98, 0x88}, bm.Data)
assert.Equal(t, box.Min.X, 30)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 34+1)
assert.Equal(t, box.Max.Y, 6+1)
case 5:
assert.Equal(t, 4, bm.Width)
assert.Equal(t, 5, bm.Height)
// Letter 'O' - expected data:
//
// 11110000 - 0xF0
// 10010000 - 0x90
// 10010000 - 0x90
// 10010000 - 0x90
// 11110000 - 0xF0
assert.Equal(t, []byte{0xF0, 0x90, 0x90, 0x90, 0xF0}, bm.Data)
assert.Equal(t, box.Min.X, 37)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 40+1)
assert.Equal(t, box.Max.Y, 6+1)
case 6:
assert.Equal(t, 5, bm.Width)
assert.Equal(t, 5, bm.Height)
// Letter 'W' - expected data:
//
// 10001000 - 0x88
// 10001000 - 0x88
// 10101000 - 0xA8
// 11011000 - 0xD8
// 10001000 - 0x88
assert.Equal(t, []byte{0x88, 0x88, 0xA8, 0xD8, 0x88}, bm.Data)
assert.Equal(t, box.Min.X, 43)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 47+1)
assert.Equal(t, box.Max.Y, 6+1)
case 7:
// the last one is the the image
//
// 11111111 11110000 - 0xFF, 0xF0
// 11111111 11110000 - 0xFF, 0xF0
// 11000110 00110000 - 0xC6, 0x30
// 11000110 00110000 - 0xC6, 0x30
// 11000110 00110000 - 0xC6, 0x30
// 11111111 11110000 - 0xFF, 0xF0
// 00101010 10100000 - 0x2A, 0xA0
assert.Equal(t, 12, bm.Width)
assert.Equal(t, 7, bm.Height)
assert.Equal(t, []byte{0xFF, 0xF0, 0xFF, 0xF0, 0xC6, 0x30, 0xC6, 0x30, 0xC6, 0x30, 0xFF, 0xF0, 0x2A, 0xA0}, bm.Data)
assert.Equal(t, box.Min.X, 17)
assert.Equal(t, box.Min.Y, 13)
assert.Equal(t, box.Max.X, 28+1)
assert.Equal(t, box.Max.Y, 19+1)
}
}
}
})
t.Run("Max10-6", func(t *testing.T) {
bm, err := copyBitmap(nil, bm)
require.NoError(t, err)
bitmaps, boxes, err := bm.GetComponents(ComponentConn, 10, 6)
require.NoError(t, err)
if assert.Len(t, bitmaps.Values, 7) && assert.Len(t, *boxes, 7) {
for i, bm := range bitmaps.Values {
box := bitmaps.Boxes[i]
switch i {
case 0:
assert.Equal(t, 5, bm.Width)
assert.Equal(t, 5, bm.Height)
// Letter 'D' - expected data:
//
// 11111000 0xF8
// 10001000 0x88
// 10001000 0x88
// 10001000 0x88
// 11110000 0xF0
assert.Equal(t, []byte{0xF8, 0x88, 0x88, 0x88, 0xF0}, bm.Data)
assert.Equal(t, box.Min.X, 2)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 6+1)
assert.Equal(t, box.Max.Y, 6+1)
case 1:
assert.Equal(t, 4, bm.Width)
assert.Equal(t, 5, bm.Height)
// Letter 'O' - expected data:
//
// 11110000 - 0xF0
// 10010000 - 0x90
// 10010000 - 0x90
// 10010000 - 0x90
// 11110000 - 0xF0
assert.Equal(t, []byte{0xF0, 0x90, 0x90, 0x90, 0xF0}, bm.Data)
assert.Equal(t, box.Min.X, 9)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 12+1)
assert.Equal(t, box.Max.Y, 6+1)
case 2:
assert.Equal(t, 1, bm.Width)
assert.Equal(t, 5, bm.Height)
// Letter 'I' - expected data:
//
// 10000000 - 0x80
// 10000000 - 0x80
// 10000000 - 0x80
// 10000000 - 0x80
// 10000000 - 0x80
assert.Equal(t, []byte{0x80, 0x80, 0x80, 0x80, 0x80}, bm.Data)
assert.Equal(t, box.Min.X, 18)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 18+1)
assert.Equal(t, box.Max.Y, 6+1)
case 3:
assert.Equal(t, 5, bm.Width)
assert.Equal(t, 5, bm.Width)
// Letter 'T' - expected data:
//
// 11111000 - 0xF8
// 00100000 - 0x20
// 00100000 - 0x20
// 00100000 - 0x20
// 00100000 - 0x20
assert.Equal(t, []byte{0xF8, 0x20, 0x20, 0x20, 0x20}, bm.Data)
assert.Equal(t, box.Min.X, 21)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 25+1)
assert.Equal(t, box.Max.Y, 6+1)
case 4:
assert.Equal(t, 5, bm.Width)
assert.Equal(t, 5, bm.Height)
// Letter 'N' - expected data:
//
// 10001000 - 0x88
// 11001000 - 0xC8
// 10101000 - 0xA8
// 10011000 - 0x98
// 10001000 - 0x88
assert.Equal(t, []byte{0x88, 0xC8, 0xA8, 0x98, 0x88}, bm.Data)
assert.Equal(t, box.Min.X, 30)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 34+1)
assert.Equal(t, box.Max.Y, 6+1)
case 5:
assert.Equal(t, 4, bm.Width)
assert.Equal(t, 5, bm.Height)
// Letter 'O' - expected data:
//
// 11110000 - 0xF0
// 10010000 - 0x90
// 10010000 - 0x90
// 10010000 - 0x90
// 11110000 - 0xF0
assert.Equal(t, []byte{0xF0, 0x90, 0x90, 0x90, 0xF0}, bm.Data)
assert.Equal(t, box.Min.X, 37)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 40+1)
assert.Equal(t, box.Max.Y, 6+1)
case 6:
assert.Equal(t, 5, bm.Width)
assert.Equal(t, 5, bm.Height)
// Letter 'W' - expected data:
//
// 10001000 - 0x88
// 10001000 - 0x88
// 10101000 - 0xA8
// 11011000 - 0xD8
// 10001000 - 0x88
assert.Equal(t, []byte{0x88, 0x88, 0xA8, 0xD8, 0x88}, bm.Data)
assert.Equal(t, box.Min.X, 43)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 47+1)
assert.Equal(t, box.Max.Y, 6+1)
}
}
}
})
})
t.Run("Char", func(t *testing.T) {
// the highest component is 12 bits wide and 8bits tall.
// this should get all possible components out of the given input bitmap.
bm, err = copyBitmap(nil, bm)
require.NoError(t, err)
bitmaps, boxes, err := bm.GetComponents(ComponentCharacters, 12, 8)
require.NoError(t, err)
require.NotNil(t, bitmaps)
require.NotNil(t, boxes)
if assert.Len(t, bitmaps.Values, 8) && assert.Len(t, *boxes, 8) {
for i, bm := range bitmaps.Values {
box := bitmaps.Boxes[i]
switch i {
case 0:
assert.Equal(t, 5, bm.Width)
assert.Equal(t, 5, bm.Height)
// Letter 'D' - expected data:
//
// 11111000 0xF8
// 10001000 0x88
// 10001000 0x88
// 10001000 0x88
// 11110000 0xF0
assert.Equal(t, []byte{0xF8, 0x88, 0x88, 0x88, 0xF0}, bm.Data)
assert.Equal(t, box.Min.X, 2)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 6+1)
assert.Equal(t, box.Max.Y, 6+1)
case 1:
assert.Equal(t, 4, bm.Width)
assert.Equal(t, 5, bm.Height)
// Letter 'O' - expected data:
//
// 11110000 - 0xF0
// 10010000 - 0x90
// 10010000 - 0x90
// 10010000 - 0x90
// 11110000 - 0xF0
assert.Equal(t, []byte{0xF0, 0x90, 0x90, 0x90, 0xF0}, bm.Data)
assert.Equal(t, box.Min.X, 9)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 12+1)
assert.Equal(t, box.Max.Y, 6+1)
case 2:
assert.Equal(t, 1, bm.Width)
assert.Equal(t, 5, bm.Height)
// Letter 'I' - expected data:
//
// 10000000 - 0x80
// 10000000 - 0x80
// 10000000 - 0x80
// 10000000 - 0x80
// 10000000 - 0x80
assert.Equal(t, []byte{0x80, 0x80, 0x80, 0x80, 0x80}, bm.Data)
assert.Equal(t, box.Min.X, 18)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 18+1)
assert.Equal(t, box.Max.Y, 6+1)
case 3:
assert.Equal(t, 5, bm.Width)
assert.Equal(t, 5, bm.Width)
// Letter 'T' - expected data:
//
// 11111000 - 0xF8
// 00100000 - 0x20
// 00100000 - 0x20
// 00100000 - 0x20
// 00100000 - 0x20
assert.Equal(t, []byte{0xF8, 0x20, 0x20, 0x20, 0x20}, bm.Data)
assert.Equal(t, box.Min.X, 21)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 25+1)
assert.Equal(t, box.Max.Y, 6+1)
case 4:
assert.Equal(t, 5, bm.Width)
assert.Equal(t, 5, bm.Height)
// Letter 'N' - expected data:
//
// 10001000 - 0x88
// 11001000 - 0xC8
// 10101000 - 0xA8
// 10011000 - 0x98
// 10001000 - 0x88
assert.Equal(t, []byte{0x88, 0xC8, 0xA8, 0x98, 0x88}, bm.Data)
assert.Equal(t, box.Min.X, 30)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 34+1)
assert.Equal(t, box.Max.Y, 6+1)
case 5:
assert.Equal(t, 4, bm.Width)
assert.Equal(t, 5, bm.Height)
// Letter 'O' - expected data:
//
// 11110000 - 0xF0
// 10010000 - 0x90
// 10010000 - 0x90
// 10010000 - 0x90
// 11110000 - 0xF0
assert.Equal(t, []byte{0xF0, 0x90, 0x90, 0x90, 0xF0}, bm.Data)
assert.Equal(t, box.Min.X, 37)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 40+1)
assert.Equal(t, box.Max.Y, 6+1)
case 6:
assert.Equal(t, 5, bm.Width)
assert.Equal(t, 5, bm.Height)
// Letter 'W' - expected data:
//
// 10001000 - 0x88
// 10001000 - 0x88
// 10101000 - 0xA8
// 11011000 - 0xD8
// 10001000 - 0x88
assert.Equal(t, []byte{0x88, 0x88, 0xA8, 0xD8, 0x88}, bm.Data)
assert.Equal(t, box.Min.X, 43)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 47+1)
assert.Equal(t, box.Max.Y, 6+1)
case 7:
// the last one is the the image
//
// 11111111 11110000 - 0xFF, 0xF0
// 11111111 11110000 - 0xFF, 0xF0
// 11000110 00110000 - 0xC6, 0x30
// 11000110 00110000 - 0xC6, 0x30
// 11000110 00110000 - 0xC6, 0x30
// 11111111 11110000 - 0xFF, 0xF0
// 00101010 10100000 - 0x2A, 0xA0
assert.Equal(t, 12, bm.Width)
assert.Equal(t, 7, bm.Height)
assert.Equal(t, []byte{0xFF, 0xF0, 0xFF, 0xF0, 0xC6, 0x30, 0xC6, 0x30, 0xC6, 0x30, 0xFF, 0xF0, 0x2A, 0xA0}, bm.Data)
assert.Equal(t, box.Min.X, 17)
assert.Equal(t, box.Min.Y, 13)
assert.Equal(t, box.Max.X, 28+1)
assert.Equal(t, box.Max.Y, 19+1)
}
}
}
})
t.Run("Word", func(t *testing.T) {
// the highest component is 20 bits wide and 8bits tall.
bm, err = copyBitmap(nil, bm)
require.NoError(t, err)
bitmaps, boxes, err := bm.GetComponents(ComponentWords, 20, 8)
require.NoError(t, err)
require.NotNil(t, bitmaps)
require.NotNil(t, boxes)
// this should result in a three words and a image components:
if assert.Len(t, bitmaps.Values, 4) && assert.Len(t, *boxes, 4) {
for i, word := range bitmaps.Values {
box := (*boxes)[i]
switch i {
case 0:
// the first word should look like 'DO'.
//
// 11111001 11100000 - 0xF9, 0xE0
// 10001001 00100000 - 0x89, 0x20
// 10001001 00100000 - 0x89, 0x20
// 10001001 00100000 - 0x89, 0x20
// 11110001 11100000 - 0xF1, 0xE0
data := []byte{0xF9, 0xE0, 0x89, 0x20, 0x89, 0x20, 0x89, 0x20, 0xF1, 0xE0}
assert.Equal(t, data, word.Data)
assert.Equal(t, box.Min.X, 2)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 12+1)
assert.Equal(t, box.Max.Y, 6+1)
case 1:
// the second word should be like 'IT'
//
// 10011111 - 0x9F
// 10000100 - 0x84
// 10000100 - 0x84
// 10000100 - 0x84
// 10000100 - 0x84
data := []byte{0x9F, 0x84, 0x84, 0x84, 0x84}
assert.Equal(t, data, word.Data)
assert.Equal(t, box.Min.X, 18)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 25+1)
assert.Equal(t, box.Max.Y, 6+1)
case 2:
// the third word should look like 'NOW'
//
// 10001001 11100100 01000000 - 0x89, 0xE4, 0x40
// 11001001 00100100 01000000 - 0xC9, 0x24, 0x40
// 10101001 00100101 01000000 - 0xA9, 0x25, 0x40
// 10011001 00100110 11000000 - 0x99, 0x26, 0xC0
// 10001001 11100100 01000000 - 0x89, 0xE4, 0x40
data := []byte{
0x89, 0xE4, 0x40,
0xC9, 0x24, 0x40,
0xA9, 0x25, 0x40,
0x99, 0x26, 0xC0,
0x89, 0xE4, 0x40,
}
assert.Equal(t, data, word.Data)
assert.Equal(t, box.Min.X, 30)
assert.Equal(t, box.Min.Y, 2)
assert.Equal(t, box.Max.X, 47+1)
assert.Equal(t, box.Max.Y, 6+1)
case 3:
// the last component is the image of the 'skull'i
//
// 11111111 11110000 - 0xFF, 0xF0
// 11111111 11110000 - 0xFF, 0xF0
// 11000110 00110000 - 0xC6, 0x30
// 11000110 00110000 - 0xC6, 0x30
// 11000110 00110000 - 0xC6, 0x30
// 11111111 11110000 - 0xFF, 0xF0
// 00101010 10100000 - 0x2A, 0xA0
data := []byte{
0xFF, 0xF0,
0xFF, 0xF0,
0xC6, 0x30,
0xC6, 0x30,
0xC6, 0x30,
0xFF, 0xF0,
0x2A, 0xA0,
}
assert.Equal(t, 12, word.Width)
assert.Equal(t, 7, word.Height)
assert.Equal(t, data, word.Data, word.String())
assert.Equal(t, box.Min.X, 17)
assert.Equal(t, box.Min.Y, 13)
assert.Equal(t, box.Max.X, 28+1)
assert.Equal(t, box.Max.Y, 19+1)
}
}
}
})
t.Run("Zero", func(t *testing.T) {
// Create a zero like bitmap - it should not create any component.
bm := New(bm.Width, bm.Height)
bitmaps, boxes, err := bm.GetComponents(ComponentConn, 12, 8)
require.NoError(t, err)
if assert.NotNil(t, bitmaps) {
assert.Empty(t, bitmaps.Values)
}
if assert.NotNil(t, boxes) {
assert.Empty(t, *boxes)
}
})
t.Run("EmptyBitmap", func(t *testing.T) {
var b *Bitmap
_, _, err := b.GetComponents(ComponentConn, 12, 8)
assert.Error(t, err)
})
}
// TestWordMaskByDilation tests the WordMaskByDilation function.
func TestWordMaskByDilation(t *testing.T) {
// Having a bitmap 50x18 with few different components like letters
//
// 1 2 3 4 5 6 7
//
// 111111 11112222 22222233 33333333 44444444 44
// 01234567 89012345 67890123 45678901 23456789 01234567 89
//
// 0 00000000 00000000 00000000 00000000 00000000 00000000 00000000
// 1 00000000 00000000 00000000 00000000 00000000 00000000 00000000
// 2 00111110 01111000 00100111 11000010 00100111 10010001 00000000
// 3 00100010 01001000 00100001 00000011 00100100 10010001 00000000
// 4 00100010 01001000 00100001 00000010 10100100 10010101 00000000
// 5 00100010 01001000 00100001 00000010 01100100 10011011 00000000
// 6 00111100 01111000 00100001 00000010 00100111 10010001 00000000
// 7 00000000 00000000 00000000 00000000 00000000 00000000 00000000
// 8 00000000 00000000 00000000 00000000 00000000 00000000 00000000
// 9 00000000 00000000 01111111 11111000 00000000 00000000 00000000
// 10 00000000 00000000 01111111 11111000 00000000 00000000 00000000
// 11 00000000 00000000 01100011 00011000 00000000 00000000 00000000
// 12 00000000 00000000 01100011 00011000 00000000 00000000 00000000
// 13 00000000 00000000 01100011 00011000 00000000 00000000 00000000
// 14 00000000 00000000 01111111 11111000 00000000 00000000 00000000
// 15 00000000 00000000 00010101 01010000 00000000 00000000 00000000
// 16 00000000 00000000 00000000 00000000 00000000 00000000 00000000
// 17 00000000 00000000 00000000 00000000 00000000 00000000 00000000
//
//
data := []byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3E, 0x78, 0x27, 0xC2, 0x27, 0x91, 0x00,
0x22, 0x48, 0x21, 0x03, 0x24, 0x91, 0x00,
0x22, 0x48, 0x21, 0x02, 0xA4, 0x95, 0x00,
0x22, 0x48, 0x21, 0x02, 0x64, 0x9B, 0x00,
0x3C, 0x78, 0x21, 0x02, 0x27, 0x91, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7F, 0xF8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7F, 0xF8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x63, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x63, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x63, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7F, 0xF8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x15, 0x50, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}
bm, err := NewWithData(50, 18, data)
require.NoError(t, err)
masks, _, err := wordMaskByDilation(bm)
require.NoError(t, err)
// the function wordMaskByDilation should create a mask bitmap that
// would set all the box areas for each copmonent of the input
// with all 'ONE' by using dilation.
//
// 1 2 3 4 5 6 7
//
// 111111 11112222 22222233 33333333 44444444 44
// 01234567 89012345 67890123 45678901 23456789 01234567 89
//
// 0 00000000 00000000 00000000 00000000 00000000 00000000 00000000
// 1 00000000 00000000 00000000 00000000 00000000 00000000 00000000
// 2 00111111 11111000 00111111 11000011 11111111 11111111 00000000
// 3 00111111 11111000 00100001 00000011 11111111 11111111 00000000
// 4 00111111 11111000 00100001 00000011 11111111 11111111 00000000
// 5 00111111 11111000 00100001 00000011 11111111 11111111 00000000
// 6 00111111 11111000 00100001 00000011 11111111 11111111 00000000
// 7 00000000 00000000 00000000 00000000 00000000 00000000 00000000
// 8 00000000 00000000 00000000 00000000 00000000 00000000 00000000
// 9 00000000 00000000 01111111 11111000 00000000 00000000 00000000
// 10 00000000 00000000 01111111 11111000 00000000 00000000 00000000
// 11 00000000 00000000 01111111 11111000 00000000 00000000 00000000
// 12 00000000 00000000 01111111 11111000 00000000 00000000 00000000
// 13 00000000 00000000 01111111 11111000 00000000 00000000 00000000
// 14 00000000 00000000 01111111 11111000 00000000 00000000 00000000
// 15 00000000 00000000 00011111 11110000 00000000 00000000 00000000
// 16 00000000 00000000 00000000 00000000 00000000 00000000 00000000
// 17 00000000 00000000 00000000 00000000 00000000 00000000 00000000
//
result := []byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3F, 0xF8, 0x3F, 0xC3, 0xFF, 0xFF, 0x00,
0x3F, 0xF8, 0x21, 0x03, 0xFF, 0xFF, 0x00,
0x3F, 0xF8, 0x21, 0x03, 0xFF, 0xFF, 0x00,
0x3F, 0xF8, 0x21, 0x03, 0xFF, 0xFF, 0x00,
0x3F, 0xF8, 0x21, 0x03, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7F, 0xF8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7F, 0xF8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7F, 0xF8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7F, 0xF8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7F, 0xF8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7F, 0xF8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1F, 0xF0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}
assert.Equal(t, result, masks.Data)
}