代码拉取完成,页面将自动刷新
package bitmap
import (
"image"
"sort"
"strings"
"gitee.com/coodder/unipdf/common"
"gitee.com/coodder/unipdf/internal/jbig2/basic"
"gitee.com/coodder/unipdf/internal/jbig2/errors"
)
// Bitmaps is the structure that contains slice of the bitmaps and the bounding boxes.
// It allows to safely get the Bitmap and the bounding boxes.
type Bitmaps struct {
Values []*Bitmap
Boxes []*image.Rectangle
}
// AddBitmap adds the bitmap 'bm' to the 'b' Bitmaps Values.
func (b *Bitmaps) AddBitmap(bm *Bitmap) {
b.Values = append(b.Values, bm)
}
// AddBox adds the 'box' to the 'b' Bitmaps.
func (b *Bitmaps) AddBox(box *image.Rectangle) {
b.Boxes = append(b.Boxes, box)
}
// ClipToBitmap returns a Bitmaps where each Bitmap is 'AND'ed with
// with the associated region stored in box with the 's' Bitmap.
func (b *Bitmaps) ClipToBitmap(s *Bitmap) (*Bitmaps, error) {
const processName = "Bitmaps.ClipToBitmap"
if b == nil {
return nil, errors.Error(processName, "Bitmaps not defined")
}
if s == nil {
return nil, errors.Error(processName, "source bitmap not defined")
}
n := len(b.Values)
d := &Bitmaps{Values: make([]*Bitmap, n), Boxes: make([]*image.Rectangle, n)}
var (
bm, bmC *Bitmap
box *image.Rectangle
err error
)
for i := 0; i < n; i++ {
if bm, err = b.GetBitmap(i); err != nil {
return nil, errors.Wrap(err, processName, "")
}
if box, err = b.GetBox(i); err != nil {
return nil, errors.Wrap(err, processName, "")
}
if bmC, err = s.clipRectangle(box, nil); err != nil {
return nil, errors.Wrap(err, processName, "")
}
if bmC, err = bmC.And(bm); err != nil {
return nil, errors.Wrap(err, processName, "")
}
d.Values[i] = bmC
d.Boxes[i] = box
}
return d, nil
}
// CountPixels counts the pixels for all the bitmaps and stores into *basic.NumSlice.
func (b *Bitmaps) CountPixels() *basic.NumSlice {
ns := &basic.NumSlice{}
for _, bm := range b.Values {
ns.AddInt(bm.CountPixels())
}
return ns
}
// GetBitmap gets the bitmap at the 'i' index.
// If the index is out of possible range the function returns error.
func (b *Bitmaps) GetBitmap(i int) (*Bitmap, error) {
const processName = "GetBitmap"
if b == nil {
return nil, errors.Error(processName, "provided nil Bitmaps")
}
if i > len(b.Values)-1 {
return nil, errors.Errorf(processName, "index: '%d' out of range", i)
}
return b.Values[i], nil
}
// GetBox gets the Box at the 'i' index.
// If the index is out of range the function returns error.
func (b *Bitmaps) GetBox(i int) (*image.Rectangle, error) {
const processName = "GetBox"
if b == nil {
return nil, errors.Error(processName, "provided nil 'Bitmaps'")
}
if i > len(b.Boxes)-1 {
return nil, errors.Errorf(processName, "index: '%d' out of range", i)
}
return b.Boxes[i], nil
}
// GroupByHeight groups bitmaps by height sorted from the lowest to the highest.
func (b *Bitmaps) GroupByHeight() (*BitmapsArray, error) {
const processName = "GroupByHeight"
if len(b.Values) == 0 {
return nil, errors.Error(processName, "no values provided")
}
a := &BitmapsArray{}
b.SortByHeight()
// initialize height class
hc := -1
currentIndex := -1
for i := 0; i < len(b.Values); i++ {
h := b.Values[i].Height
if h > hc {
hc = h
currentIndex++
a.Values = append(a.Values, &Bitmaps{})
}
a.Values[currentIndex].AddBitmap(b.Values[i])
}
return a, nil
}
// GroupByWidth groups bitmaps by height sorted from the lowest to the highest.
func (b *Bitmaps) GroupByWidth() (*BitmapsArray, error) {
const processName = "GroupByWidth"
if len(b.Values) == 0 {
return nil, errors.Error(processName, "no values provided")
}
a := &BitmapsArray{}
b.SortByWidth()
// initialize height class
wc := -1
currentIndex := -1
for i := 0; i < len(b.Values); i++ {
w := b.Values[i].Width
if w > wc {
wc = w
currentIndex++
a.Values = append(a.Values, &Bitmaps{})
}
a.Values[currentIndex].AddBitmap(b.Values[i])
}
return a, nil
}
// HeightSorter returns sorting function based on the bitmaps height.
func (b *Bitmaps) HeightSorter() func(i, j int) bool {
return func(i, j int) bool {
v := b.Values[i].Height < b.Values[j].Height
common.Log.Debug("Height: %v < %v = %v", b.Values[i].Height, b.Values[j].Height, v)
return v
}
}
// WidthSorter returns the sorting function based on the bitmaps width.
func (b *Bitmaps) WidthSorter() func(i, j int) bool {
return func(i, j int) bool {
return b.Values[i].Width < b.Values[j].Width
}
}
// SelectBySize selects provided bitmaps by provided 'width', 'height' location filter 'tp' and size comparison 'relation.
// Returns 'b' bitmap if it's empty or all the bitmaps matches the pattern.
func (b *Bitmaps) SelectBySize(width, height int, tp LocationFilter, relation SizeComparison) (d *Bitmaps, err error) {
const processName = "Bitmaps.SelectBySize"
if b == nil {
return nil, errors.Error(processName, "'b' Bitmaps not defined")
}
// check the location filter type
switch tp {
case LocSelectWidth, LocSelectHeight, LocSelectIfEither, LocSelectIfBoth:
default:
return nil, errors.Errorf(processName, "provided invalid location filter type: %d", tp)
}
// check the relation value
switch relation {
case SizeSelectIfLT, SizeSelectIfGT, SizeSelectIfLTE, SizeSelectIfGTE, SizeSelectIfEQ:
default:
return nil, errors.Errorf(processName, "invalid relation: '%d'", relation)
}
na, err := b.makeSizeIndicator(width, height, tp, relation)
if err != nil {
return nil, errors.Wrap(err, processName, "")
}
d, err = b.selectByIndicator(na)
if err != nil {
return nil, errors.Wrap(err, processName, "")
}
return d, nil
}
// Size returns bitmaps size.
func (b *Bitmaps) Size() int {
return len(b.Values)
}
// SelectByIndexes selects bitmaps by provided indexes 'idx'.
func (b *Bitmaps) SelectByIndexes(idx []int) (*Bitmaps, error) {
const processName = "Bitmaps.SortIndexesByHeight"
temp, err := b.selectByIndexes(idx)
if err != nil {
return nil, errors.Wrap(err, processName, "")
}
return temp, nil
}
// byHeight is the wrapper for the Height sorting of bitmaps
type byHeight Bitmaps
// Len implements sort.Interface Len function.
func (b *byHeight) Len() int {
return len(b.Values)
}
// Less implements sort.Interface Less function.
func (b *byHeight) Less(i, j int) bool {
return b.Values[i].Height < b.Values[j].Height
}
// Swap implements sort.Interface Swap function.
func (b *byHeight) Swap(i, j int) {
b.Values[i], b.Values[j] = b.Values[j], b.Values[i]
if b.Boxes != nil {
b.Boxes[i], b.Boxes[j] = b.Boxes[j], b.Boxes[i]
}
}
// SortByHeight sorts the bitmaps by height.
func (b *Bitmaps) SortByHeight() {
byH := (*byHeight)(b)
sort.Sort(byH)
}
// SortByWidth sorts bitmaps by width.
func (b *Bitmaps) SortByWidth() {
byW := (*byWidth)(b)
sort.Sort(byW)
}
// byWidth is the wrapper for the Height sorting of bitmaps
type byWidth Bitmaps
// Len implements sort.Interface Len function.
func (b *byWidth) Len() int {
return len(b.Values)
}
// Less implements sort.Interface Less function.
func (b *byWidth) Less(i, j int) bool {
return b.Values[i].Width < b.Values[j].Width
}
// Swap implements sort.Interface Swap function.
func (b *byWidth) Swap(i, j int) {
b.Values[i], b.Values[j] = b.Values[j], b.Values[i]
if b.Boxes != nil {
b.Boxes[i], b.Boxes[j] = b.Boxes[j], b.Boxes[i]
}
}
func (b *Bitmaps) selectByIndexes(idx []int) (*Bitmaps, error) {
d := &Bitmaps{}
for _, id := range idx {
temp, err := b.GetBitmap(id)
if err != nil {
return nil, errors.Wrap(err, "selectByIndexes", "")
}
d.AddBitmap(temp)
}
return d, nil
}
func (b *Bitmaps) String() string {
sb := strings.Builder{}
for _, bm := range b.Values {
sb.WriteString(bm.String())
sb.WriteRune('\n')
}
return sb.String()
}
func (b *Bitmaps) makeSizeIndicator(width, height int, tp LocationFilter, relation SizeComparison) (na *basic.NumSlice, err error) {
const processName = "Bitmaps.makeSizeIndicator"
if b == nil {
return nil, errors.Error(processName, "bitmaps 'b' not defined")
}
switch tp {
case LocSelectWidth, LocSelectHeight, LocSelectIfEither, LocSelectIfBoth:
default:
return nil, errors.Errorf(processName, "provided invalid location filter type: %d", tp)
}
switch relation {
case SizeSelectIfLT, SizeSelectIfGT, SizeSelectIfLTE, SizeSelectIfGTE, SizeSelectIfEQ:
default:
return nil, errors.Errorf(processName, "invalid relation: '%d'", relation)
}
na = &basic.NumSlice{}
var (
intValue, w, h int
bm *Bitmap
)
for _, bm = range b.Values {
intValue = 0
w, h = bm.Width, bm.Height
switch tp {
case LocSelectWidth:
if (relation == SizeSelectIfLT && w < width) ||
(relation == SizeSelectIfGT && w > width) ||
(relation == SizeSelectIfLTE && w <= width) ||
(relation == SizeSelectIfGTE && w >= width) ||
(relation == SizeSelectIfEQ && w == width) {
intValue = 1
}
case LocSelectHeight:
if (relation == SizeSelectIfLT && h < height) ||
(relation == SizeSelectIfGT && h > height) ||
(relation == SizeSelectIfLTE && h <= height) ||
(relation == SizeSelectIfGTE && h >= height) ||
(relation == SizeSelectIfEQ && h == height) {
intValue = 1
}
case LocSelectIfEither:
if (relation == SizeSelectIfLT && (w < width || h < height)) ||
(relation == SizeSelectIfGT && (w > width || h > height)) ||
(relation == SizeSelectIfLTE && (w <= width || h <= height)) ||
(relation == SizeSelectIfGTE && (w >= width || h >= height)) ||
(relation == SizeSelectIfEQ && (w == width || h == height)) {
intValue = 1
}
case LocSelectIfBoth:
if (relation == SizeSelectIfLT && (w < width && h < height)) ||
(relation == SizeSelectIfGT && (w > width && h > height)) ||
(relation == SizeSelectIfLTE && (w <= width && h <= height)) ||
(relation == SizeSelectIfGTE && (w >= width && h >= height)) ||
(relation == SizeSelectIfEQ && (w == width && h == height)) {
intValue = 1
}
}
na.AddInt(intValue)
}
return na, nil
}
func (b *Bitmaps) selectByIndicator(na *basic.NumSlice) (d *Bitmaps, err error) {
const processName = "Bitmaps.selectByIndicator"
if b == nil {
return nil, errors.Error(processName, "'b' bitmaps not defined")
}
if na == nil {
return nil, errors.Error(processName, "'na' indicators not defined")
}
if len(b.Values) == 0 {
return b, nil
}
if len(*na) != len(b.Values) {
return nil, errors.Errorf(processName, "na length: %d, is different than bitmaps: %d", len(*na), len(b.Values))
}
var intValue, i, changeCount int
for i = 0; i < len(*na); i++ {
if intValue, err = na.GetInt(i); err != nil {
return nil, errors.Wrap(err, processName, "first check")
}
if intValue == 1 {
changeCount++
}
}
if changeCount == len(b.Values) {
return b, nil
}
d = &Bitmaps{}
hasBoxes := len(b.Values) == len(b.Boxes)
for i = 0; i < len(*na); i++ {
if intValue = int((*na)[i]); intValue == 0 {
continue
}
d.Values = append(d.Values, b.Values[i])
if hasBoxes {
d.Boxes = append(d.Boxes, b.Boxes[i])
}
}
return d, nil
}
// BitmapsArray is the struct that contains slice of the 'Bitmaps',
// with the bounding boxes around each 'Bitmaps'.
type BitmapsArray struct {
Values []*Bitmaps
Boxes []*image.Rectangle
}
// AddBitmaps adds the 'bm' Bitmaps to the 'b'.Values.
func (b *BitmapsArray) AddBitmaps(bm *Bitmaps) {
b.Values = append(b.Values, bm)
}
// AddBox adds the 'box' to the 'b' Boxes.
func (b *BitmapsArray) AddBox(box *image.Rectangle) {
b.Boxes = append(b.Boxes, box)
}
// GetBitmaps gets the 'Bitmaps' at the 'i' position.
// Returns error if the index is out of range.
func (b *BitmapsArray) GetBitmaps(i int) (*Bitmaps, error) {
const processName = "BitmapsArray.GetBitmaps"
if b == nil {
return nil, errors.Error(processName, "provided nil 'BitmapsArray'")
}
if i > len(b.Values)-1 {
return nil, errors.Errorf(processName, "index: '%d' out of range", i)
}
return b.Values[i], nil
}
// GetBox gets the boundary box at 'i' position.
// Returns error if the index is out of range.
func (b *BitmapsArray) GetBox(i int) (*image.Rectangle, error) {
const processName = "BitmapsArray.GetBox"
if b == nil {
return nil, errors.Error(processName, "provided nil 'BitmapsArray'")
}
if i > len(b.Boxes)-1 {
return nil, errors.Errorf(processName, "index: '%d' out of range", i)
}
return b.Boxes[i], nil
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。