unipdf/internal/jbig2/segments/generic-refinement-region.go
Jacek Kucharczyk 24648f4481 Issue #144 Fix - JBIG2 - Changed integer variables types (#148)
* Fixing platform indepenedent integer size
* Cleared test logs.
* Cleared unnecessary int32
* Defined precise integer size for jbig2 segments.
2019-08-29 19:12:18 +00:00

1012 lines
24 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 segments
import (
"errors"
"fmt"
"strings"
"time"
"github.com/unidoc/unipdf/v3/common"
"github.com/unidoc/unipdf/v3/internal/jbig2/bitmap"
"github.com/unidoc/unipdf/v3/internal/jbig2/decoder/arithmetic"
"github.com/unidoc/unipdf/v3/internal/jbig2/reader"
)
// GenericRefinementRegion represtents jbig2 generic refinement region segment - 7.4.7.
type GenericRefinementRegion struct {
t0 templater
t1 templater
r reader.StreamReader
h *Header
// Region segment information flags 7.4.1.
RegionInfo *RegionSegment
// Generic refinement region segment flags 7.4.7.2.
IsTPGROn bool
TemplateID int8
Template templater
// Generic refinement region segment AT flags 7.4.7.3.
GrAtX []int8
GrAtY []int8
// Decoded data as pixel values (use row stride/width to wrap line).
RegionBitmap *bitmap.Bitmap
// Variables for decoding.
ReferenceBitmap *bitmap.Bitmap
ReferenceDX int32
ReferenceDY int32
arithDecode *arithmetic.Decoder
cx *arithmetic.DecoderStats
override bool
grAtOverride []bool
}
// Init implements Segmenter interface.
func (g *GenericRefinementRegion) Init(header *Header, r reader.StreamReader) error {
g.h = header
g.r = r
g.RegionInfo = NewRegionSegment(r)
return g.parseHeader()
}
// GetRegionBitmap implements Regioner interface.
func (g *GenericRefinementRegion) GetRegionBitmap() (*bitmap.Bitmap, error) {
var err error
common.Log.Trace("[GENERIC-REF-REGION] GetRegionBitmap begins...")
defer func() {
if err != nil {
common.Log.Trace("[GENERIC-REF-REGION] GetRegionBitmap failed. %v", err)
} else {
common.Log.Trace("[GENERIC-REF-REGION] GetRegionBitmap finished.")
}
}()
if g.RegionBitmap != nil {
return g.RegionBitmap, nil
}
// 6.3.5.6 - 1)
isLineTypicalPredicted := 0
if g.ReferenceBitmap == nil {
// Get the reference bitmap, which is the base of refinement process
g.ReferenceBitmap, err = g.getGrReference()
if err != nil {
return nil, err
}
}
if g.arithDecode == nil {
g.arithDecode, err = arithmetic.New(g.r)
if err != nil {
return nil, err
}
}
if g.cx == nil {
g.cx = arithmetic.NewStats(8192, 1)
}
g.RegionBitmap = bitmap.New(int(g.RegionInfo.BitmapWidth), int(g.RegionInfo.BitmapHeight))
if g.TemplateID == 0 {
if err = g.updateOverride(); err != nil {
return nil, err
}
}
paddedWidth := (g.RegionBitmap.Width + 7) & -8
var deltaRefStride int
if g.IsTPGROn {
deltaRefStride = int(-g.ReferenceDY) * g.ReferenceBitmap.RowStride
}
yOffset := deltaRefStride + 1
// 6.3.5.6 - 3
for y := 0; y < g.RegionBitmap.Height; y++ {
// 6.3.5.6 - 3 b)
if g.IsTPGROn {
temp, err := g.decodeSLTP()
if err != nil {
return nil, err
}
isLineTypicalPredicted ^= temp
}
if isLineTypicalPredicted == 0 {
// 6.3.5.6 - 3 c)
err = g.decodeOptimized(y, g.RegionBitmap.Width, g.RegionBitmap.RowStride, g.ReferenceBitmap.RowStride, paddedWidth, deltaRefStride, yOffset)
if err != nil {
return nil, err
}
} else {
// 6.3.5.6 - 3 d)
err = g.decodeTypicalPredictedLine(y, g.RegionBitmap.Width, g.RegionBitmap.RowStride, g.ReferenceBitmap.RowStride, paddedWidth, deltaRefStride)
if err != nil {
return nil, err
}
}
}
// 6.3.5.6 - 4)
return g.RegionBitmap, nil
}
// GetRegionInfo implements Regioner interface.
func (g *GenericRefinementRegion) GetRegionInfo() *RegionSegment {
return g.RegionInfo
}
func (g *GenericRefinementRegion) decodeSLTP() (int, error) {
g.Template.setIndex(g.cx)
return g.arithDecode.DecodeBit(g.cx)
}
func (g *GenericRefinementRegion) getGrReference() (*bitmap.Bitmap, error) {
segments := g.h.RTSegments
if len(segments) == 0 {
return nil, errors.New("Referenced Segment not exists")
}
s, err := segments[0].GetSegmentData()
if err != nil {
return nil, err
}
r, ok := s.(Regioner)
if !ok {
return nil, fmt.Errorf("Refered to Segment is not a Regioner: %T", s)
}
return r.GetRegionBitmap()
}
func (g *GenericRefinementRegion) decodeOptimized(
lineNumber, width, rowStride, refRowStride, paddedWidth, deltaRefStride, lineOffset int,
) error {
var (
err error
rx int
tempIndex int
)
currentLine := lineNumber - int(g.ReferenceDY)
if t := int(-g.ReferenceDX); t > 0 {
rx = t
}
refByteIndex := g.ReferenceBitmap.GetByteIndex(rx, currentLine)
if g.ReferenceDX > 0 {
tempIndex = int(g.ReferenceDX)
}
byteIndex := g.RegionBitmap.GetByteIndex(tempIndex, lineNumber)
switch g.TemplateID {
case 0:
err = g.decodeTemplate(lineNumber, width, rowStride, refRowStride, paddedWidth, deltaRefStride, lineOffset, byteIndex, currentLine, refByteIndex, g.t0)
case 1:
err = g.decodeTemplate(lineNumber, width, rowStride, refRowStride, paddedWidth, deltaRefStride, lineOffset, byteIndex, currentLine, refByteIndex, g.t1)
}
return err
}
func (g *GenericRefinementRegion) decodeTypicalPredictedLine(
lineNumber, width, rowStride, refRowStride, paddedWidth, deltaRefStride int,
) error {
// Offset of the reference bitmap with respect to the bitmap being decoded
currentLine := lineNumber - int(g.ReferenceDY)
refByteIndex := g.ReferenceBitmap.GetByteIndex(0, currentLine)
byteIndex := g.RegionBitmap.GetByteIndex(0, lineNumber)
var err error
switch g.TemplateID {
case 0:
err = g.decodeTypicalPredictedLineTemplate0(lineNumber, width, rowStride, refRowStride, paddedWidth, deltaRefStride, byteIndex, currentLine, refByteIndex)
case 1:
err = g.decodeTypicalPredictedLineTemplate1(lineNumber, width, rowStride, refRowStride, paddedWidth, deltaRefStride, byteIndex, currentLine, refByteIndex)
}
return err
}
func (g *GenericRefinementRegion) decodeTypicalPredictedLineTemplate0(
lineNumber, width, rowStride, refRowStride, paddedWidth,
deltaRefStride, byteIndex, currentLine, refByteIndex int,
) error {
var (
context, overridenContext, previousLine, previousReferenceLine,
currentReferenceLine, nextReferenceLine int
temp byte
err error
)
if lineNumber > 0 {
temp, err = g.RegionBitmap.GetByte(byteIndex - rowStride)
if err != nil {
return err
}
previousLine = int(temp)
}
if currentLine > 0 && currentLine <= g.ReferenceBitmap.Height {
temp, err = g.ReferenceBitmap.GetByte(refByteIndex - refRowStride + deltaRefStride)
if err != nil {
return err
}
previousReferenceLine = int(temp) << 4
}
if currentLine >= 0 && currentLine < g.ReferenceBitmap.Height {
temp, err = g.ReferenceBitmap.GetByte(refByteIndex + deltaRefStride)
if err != nil {
return err
}
currentReferenceLine = int(temp) << 1
}
if currentLine > -2 && currentLine < g.ReferenceBitmap.Height-1 {
temp, err = g.ReferenceBitmap.GetByte(refByteIndex + refRowStride + deltaRefStride)
if err != nil {
return err
}
nextReferenceLine = int(temp)
}
context = ((previousLine >> 5) & 0x6) | ((nextReferenceLine >> 2) & 0x30) | (currentReferenceLine & 0x180) | (previousReferenceLine & 0xc00)
var nextByte int
for x := 0; x < paddedWidth; x = nextByte {
var result int
nextByte = x + 8
var minorWidth int
if minorWidth = width - x; minorWidth > 8 {
minorWidth = 8
}
readNextByte := nextByte < width
refReadNextByte := nextByte < g.ReferenceBitmap.Width
yOffset := deltaRefStride + 1
if lineNumber > 0 {
temp = 0
if readNextByte {
temp, err = g.RegionBitmap.GetByte(byteIndex - rowStride + 1)
if err != nil {
return err
}
}
previousLine = (previousLine << 8) | int(temp)
}
if currentLine > 0 && currentLine <= g.ReferenceBitmap.Height {
var tempVal int
temp = 0
if refReadNextByte {
temp, err = g.ReferenceBitmap.GetByte(refByteIndex - refRowStride + yOffset)
if err != nil {
return err
}
tempVal = int(temp) << 4
}
previousReferenceLine = (previousReferenceLine << 8) | tempVal
}
if currentLine >= 0 && currentLine < g.ReferenceBitmap.Height {
var tempVal int
if refReadNextByte {
temp, err = g.ReferenceBitmap.GetByte(refByteIndex + yOffset)
if err != nil {
return err
}
tempVal = int(temp) << 1
}
currentReferenceLine = (currentReferenceLine << 8) | tempVal
}
if currentLine > -2 && currentLine < (g.ReferenceBitmap.Height-1) {
temp = 0
if refReadNextByte {
temp, err = g.ReferenceBitmap.GetByte(refByteIndex + refRowStride + yOffset)
if err != nil {
return err
}
}
nextReferenceLine = (nextReferenceLine << 8) | int(temp)
}
for minorX := 0; minorX < minorWidth; minorX++ {
var bit int
isPixelTypicalPredicted := false
bitmapValue := (context >> 4) & 0x1ff
if bitmapValue == 0x1ff {
isPixelTypicalPredicted = true
bit = 1
} else if bitmapValue == 0x00 {
isPixelTypicalPredicted = true
}
if !isPixelTypicalPredicted {
if g.override {
overridenContext = g.overrideAtTemplate0(context, x+minorX, lineNumber, result, minorX)
g.cx.SetIndex(int32(overridenContext))
} else {
g.cx.SetIndex(int32(context))
}
bit, err = g.arithDecode.DecodeBit(g.cx)
if err != nil {
return err
}
}
toShift := uint(7 - minorX)
result |= int(bit << toShift)
context = ((context & 0xdb6) << 1) | bit | (previousLine>>toShift+5)&0x002 |
((nextReferenceLine>>toShift + 2) & 0x010) |
((currentReferenceLine >> toShift) & 0x080) |
((previousReferenceLine >> toShift) & 0x400)
}
err = g.RegionBitmap.SetByte(byteIndex, byte(result))
if err != nil {
return err
}
byteIndex++
refByteIndex++
}
return nil
}
func (g *GenericRefinementRegion) decodeTypicalPredictedLineTemplate1(
lineNumber, width, rowStride, refRowStride, paddedWidth,
deltaRefStride, byteIndex, currentLine, refByteIndex int,
) (err error) {
var (
context, grReferenceValue int
previousLine, previousReferenceLine int
currentReferenceLine, nextReferenceLine int
temp byte
)
if lineNumber > 0 {
temp, err = g.RegionBitmap.GetByte(byteIndex - rowStride)
if err != nil {
return
}
previousLine = int(temp)
}
if currentLine > 0 && currentLine <= g.ReferenceBitmap.Height {
temp, err = g.ReferenceBitmap.GetByte(refByteIndex - refRowStride + deltaRefStride)
if err != nil {
return
}
previousReferenceLine = int(temp) << 2
}
if currentLine >= 0 && currentLine < g.ReferenceBitmap.Height {
temp, err = g.ReferenceBitmap.GetByte(refByteIndex + deltaRefStride)
if err != nil {
return
}
currentReferenceLine = int(temp)
}
if currentLine > -2 && currentLine < g.ReferenceBitmap.Height-1 {
temp, err = g.ReferenceBitmap.GetByte(refByteIndex + refRowStride + deltaRefStride)
if err != nil {
return
}
nextReferenceLine = int(temp)
}
context = ((previousLine >> 5) & 0x6) | ((nextReferenceLine >> 2) & 0x30) |
(currentReferenceLine & 0xc0) | (previousReferenceLine & 0x200)
grReferenceValue = ((nextReferenceLine >> 2) & 0x70) | (currentReferenceLine & 0xc0) |
(previousReferenceLine & 0x700)
var nextByte int
for x := 0; x < paddedWidth; x = nextByte {
var (
minorWidth int
result int
)
nextByte = x + 8
if minorWidth = width - x; minorWidth > 8 {
minorWidth = 8
}
readNextByte := nextByte < width
refReadNextByte := nextByte < g.ReferenceBitmap.Width
yOffset := deltaRefStride + 1
if lineNumber > 0 {
temp = 0
if readNextByte {
temp, err = g.RegionBitmap.GetByte(byteIndex - rowStride + 1)
if err != nil {
return
}
}
previousLine = (previousLine << 8) | int(temp)
}
if currentLine > 0 && currentLine <= g.ReferenceBitmap.Height {
temp = 0
var tempVal int
if refReadNextByte {
temp, err = g.ReferenceBitmap.GetByte(refByteIndex - refRowStride + yOffset)
if err != nil {
return
}
tempVal = int(temp) << 2
}
previousReferenceLine = (previousReferenceLine << 8) | tempVal
}
if currentLine >= 0 && currentLine < g.ReferenceBitmap.Height {
temp = 0
if refReadNextByte {
temp, err = g.ReferenceBitmap.GetByte(refByteIndex + yOffset)
if err != nil {
return
}
}
currentReferenceLine = (currentReferenceLine << 8) | int(temp)
}
if currentLine > -2 && currentLine < (g.ReferenceBitmap.Height-1) {
temp = 0
if refReadNextByte {
temp, err = g.ReferenceBitmap.GetByte(refByteIndex + refRowStride + yOffset)
if err != nil {
return
}
}
nextReferenceLine = (nextReferenceLine << 8) | int(temp)
}
for minorX := 0; minorX < minorWidth; minorX++ {
var bit int
bitmapValue := (grReferenceValue >> 4) & 0x1ff
if bitmapValue == 0x1ff {
bit = 1
} else if bitmapValue == 0x00 {
bit = 0
} else {
g.cx.SetIndex(int32(context))
bit, err = g.arithDecode.DecodeBit(g.cx)
if err != nil {
return
}
}
toShift := uint(7 - minorX)
result |= int(bit << toShift)
context = ((context & 0x0d6) << 1) | bit | (previousLine>>toShift+5)&0x002 |
((nextReferenceLine>>toShift + 2) & 0x010) |
((currentReferenceLine >> toShift) & 0x040) |
((previousReferenceLine >> toShift) & 0x200)
grReferenceValue = ((grReferenceValue & 0xdb) << 1) |
((nextReferenceLine>>toShift + 2) & 0x010) |
((currentReferenceLine >> toShift) & 0x080) |
((previousReferenceLine >> toShift) & 0x400)
}
err = g.RegionBitmap.SetByte(byteIndex, byte(result))
if err != nil {
return
}
byteIndex++
refByteIndex++
}
return nil
}
func (g *GenericRefinementRegion) decodeTemplate(
lineNumber, width, rowStride, refRowStride, paddedWidth,
deltaRefStride, lineOffset, byteIndex, currentLine, refByteIndex int,
templateFormation templater,
) (err error) {
var (
c1, c2, c3, c4, c5 int16
w1, w2, w3, w4 int
temp byte
)
if currentLine >= 1 && (currentLine-1) < g.ReferenceBitmap.Height {
temp, err = g.ReferenceBitmap.GetByte(refByteIndex - refRowStride)
if err != nil {
return
}
w1 = int(temp)
}
if currentLine >= 0 && (currentLine) < g.ReferenceBitmap.Height {
temp, err = g.ReferenceBitmap.GetByte(refByteIndex)
if err != nil {
return
}
w2 = int(temp)
}
if currentLine >= -1 && (currentLine+1) < g.ReferenceBitmap.Height {
temp, err = g.ReferenceBitmap.GetByte(refByteIndex + refRowStride)
if err != nil {
return
}
w3 = int(temp)
}
refByteIndex++
if lineNumber >= 1 {
temp, err = g.RegionBitmap.GetByte(byteIndex - rowStride)
if err != nil {
return
}
w4 = int(temp)
}
byteIndex++
modReferenceDX := g.ReferenceDX % 8
shiftOffset := 6 + modReferenceDX
modRefByteIdx := refByteIndex % refRowStride
if shiftOffset >= 0 {
if shiftOffset < 8 {
c1 = int16(w1>>uint(shiftOffset)) & 0x07
}
if shiftOffset < 8 {
c2 = int16(w2>>uint(shiftOffset)) & 0x07
}
if shiftOffset < 8 {
c3 = int16(w3>>uint(shiftOffset)) & 0x07
}
if shiftOffset == 6 && modRefByteIdx > 1 {
if currentLine >= 1 && (currentLine-1) < g.ReferenceBitmap.Height {
temp, err = g.ReferenceBitmap.GetByte(refByteIndex - refRowStride - 2)
if err != nil {
return err
}
c1 |= int16(temp<<2) & 0x04
}
if currentLine >= 0 && currentLine < g.ReferenceBitmap.Height {
temp, err = g.ReferenceBitmap.GetByte(refByteIndex - 2)
if err != nil {
return err
}
c2 |= int16(temp<<2) & 0x04
}
if currentLine >= -1 && currentLine+1 < g.ReferenceBitmap.Height {
temp, err = g.ReferenceBitmap.GetByte(refByteIndex + refRowStride - 2)
if err != nil {
return err
}
c3 |= int16(temp<<2) & 0x04
}
}
if shiftOffset == 0 {
w1 = 0
w2 = 0
w3 = 0
if modRefByteIdx < refRowStride-1 {
if currentLine >= 1 && currentLine-1 < g.ReferenceBitmap.Height {
temp, err = g.ReferenceBitmap.GetByte(refByteIndex - refRowStride)
if err != nil {
return err
}
w1 = int(temp)
}
if currentLine >= 0 && currentLine < g.ReferenceBitmap.Height {
temp, err = g.ReferenceBitmap.GetByte(refByteIndex)
if err != nil {
return err
}
w2 = int(temp)
}
if currentLine >= -1 && currentLine+1 < g.ReferenceBitmap.Height {
temp, err = g.ReferenceBitmap.GetByte(refByteIndex + refRowStride)
if err != nil {
return err
}
w3 = int(temp)
}
}
refByteIndex++
}
} else {
c1 = int16(w1<<1) & 0x07
c2 = int16(w2<<1) & 0x07
c3 = int16(w3<<1) & 0x07
w1 = 0
w2 = 0
w3 = 0
if modRefByteIdx < refRowStride-1 {
if currentLine >= 1 && currentLine-1 < g.ReferenceBitmap.Height {
temp, err = g.ReferenceBitmap.GetByte(refByteIndex - refRowStride)
if err != nil {
return err
}
w1 = int(temp)
}
if currentLine >= 0 && currentLine < g.ReferenceBitmap.Height {
temp, err = g.ReferenceBitmap.GetByte(refByteIndex)
if err != nil {
return err
}
w2 = int(temp)
}
if currentLine >= -1 && currentLine+1 < g.ReferenceBitmap.Height {
temp, err = g.ReferenceBitmap.GetByte(refByteIndex + refRowStride)
if err != nil {
return err
}
w3 = int(temp)
}
refByteIndex++
}
c1 |= int16((w1 >> 7) & 0x07)
c2 |= int16((w2 >> 7) & 0x07)
c3 |= int16((w3 >> 7) & 0x07)
}
c4 = int16(w4 >> 6)
c5 = 0
modBitsToTrim := (2 - modReferenceDX) % 8
w1 <<= uint(modBitsToTrim)
w2 <<= uint(modBitsToTrim)
w3 <<= uint(modBitsToTrim)
w4 <<= 2
var bit int
for x := 0; x < width; x++ {
minorX := x & 0x07
tval := templateFormation.form(c1, c2, c3, c4, c5)
if g.override {
temp, err = g.RegionBitmap.GetByte(g.RegionBitmap.GetByteIndex(x, lineNumber))
if err != nil {
return err
}
g.cx.SetIndex(int32(g.overrideAtTemplate0(int(tval), x, lineNumber, int(temp), minorX)))
} else {
g.cx.SetIndex(int32(tval))
}
bit, err = g.arithDecode.DecodeBit(g.cx)
if err != nil {
return err
}
if err = g.RegionBitmap.SetPixel(x, lineNumber, byte(bit)); err != nil {
return err
}
c1 = (((c1 << 1) | 0x01&int16(w1>>7)) & 0x07)
c2 = (((c2 << 1) | 0x01&int16(w2>>7)) & 0x07)
c3 = (((c3 << 1) | 0x01&int16(w3>>7)) & 0x07)
c4 = (((c4 << 1) | 0x01&int16(w4>>7)) & 0x07)
c5 = int16(bit)
if (x-int(g.ReferenceDX))%8 == 5 {
w1 = 0
w2 = 0
w3 = 0
if ((x-int(g.ReferenceDX))/8)+1 < g.ReferenceBitmap.RowStride {
if currentLine >= 1 && (currentLine-1) < g.ReferenceBitmap.Height {
temp, err = g.ReferenceBitmap.GetByte(refByteIndex - refRowStride)
if err != nil {
return err
}
w1 = int(temp)
}
if currentLine >= 0 && currentLine < g.ReferenceBitmap.Height {
temp, err = g.ReferenceBitmap.GetByte(refByteIndex)
if err != nil {
return err
}
w2 = int(temp)
}
if currentLine >= -1 && (currentLine+1) < g.ReferenceBitmap.Height {
temp, err = g.ReferenceBitmap.GetByte(refByteIndex + refRowStride)
if err != nil {
return err
}
w3 = int(temp)
}
}
refByteIndex++
} else {
w1 <<= 1
w2 <<= 1
w3 <<= 1
}
if minorX == 5 && lineNumber >= 1 {
if ((x >> 3) + 1) >= g.RegionBitmap.RowStride {
w4 = 0
} else {
temp, err = g.RegionBitmap.GetByte(byteIndex - rowStride)
if err != nil {
return err
}
w4 = int(temp)
}
byteIndex++
} else {
w4 <<= 1
}
}
return nil
}
func (g *GenericRefinementRegion) getPixel(b *bitmap.Bitmap, x, y int) int {
if x < 0 || x >= b.Width {
return 0
}
if y < 0 || y >= b.Height {
return 0
}
if b.GetPixel(x, y) {
return 1
}
return 0
}
func (g *GenericRefinementRegion) overrideAtTemplate0(context, x, y, result, minorX int) int {
if g.grAtOverride[0] {
context &= 0xfff7
if g.GrAtY[0] == 0 && int(g.GrAtX[0]) >= -minorX {
context |= (result >> uint(7-(minorX+int(g.GrAtX[0]))) & 0x1) << 3
} else {
context |= g.getPixel(g.RegionBitmap, x+int(g.GrAtX[0]), y+int(g.GrAtY[0])) << 3
}
}
if g.grAtOverride[1] {
context &= 0xefff
if g.GrAtY[1] == 0 && int(g.GrAtX[1]) >= -minorX {
context |= (result >> uint(7-(minorX+int(g.GrAtX[1]))) & 0x1) << 12
} else {
context |= g.getPixel(g.ReferenceBitmap, x+int(g.GrAtX[1]), y+int(g.GrAtY[1]))
}
}
return context
}
func (g *GenericRefinementRegion) parseHeader() (err error) {
common.Log.Trace("[GENERIC-REF-REGION] parsing Header...")
ts := time.Now()
defer func() {
if err == nil {
common.Log.Trace("[GENERIC-REF-REGION] parsing header finishid in: %d ns", time.Since(ts).Nanoseconds())
} else {
common.Log.Trace("[GENERIC-REF-REGION] parsing header failed: %s", err)
}
}()
if err = g.RegionInfo.parseHeader(); err != nil {
return err
}
// Bit 2-7
_, err = g.r.ReadBits(6) // Dirty Read
if err != nil {
return err
}
// Bit 1
g.IsTPGROn, err = g.r.ReadBool()
if err != nil {
return err
}
// Bit 0
var templateID int
templateID, err = g.r.ReadBit()
if err != nil {
return err
}
g.TemplateID = int8(templateID)
switch g.TemplateID {
case 0:
g.Template = g.t0
if err = g.readAtPixels(); err != nil {
return
}
case 1:
g.Template = g.t1
}
return nil
}
func (g *GenericRefinementRegion) readAtPixels() error {
g.GrAtX = make([]int8, 2)
g.GrAtY = make([]int8, 2)
// Byte 0
temp, err := g.r.ReadByte()
if err != nil {
return err
}
g.GrAtX[0] = int8(temp)
// Byte 1
temp, err = g.r.ReadByte()
if err != nil {
return err
}
g.GrAtY[0] = int8(temp)
// Byte 2
temp, err = g.r.ReadByte()
if err != nil {
return err
}
g.GrAtX[1] = int8(temp)
// Byte 3
temp, err = g.r.ReadByte()
if err != nil {
return err
}
g.GrAtY[1] = int8(temp)
return nil
}
// setParameters sets the parameters for the Generic Refinemenet Region.
func (g *GenericRefinementRegion) setParameters(
cx *arithmetic.DecoderStats, arithmDecoder *arithmetic.Decoder,
grTemplate int8, regionWidth, regionHeight uint32,
grReference *bitmap.Bitmap, grReferenceDX, grReferenceDY int32,
isTPGRon bool, grAtX []int8, grAtY []int8,
) {
common.Log.Trace("[GENERIC-REF-REGION] setParameters")
if cx != nil {
g.cx = cx
}
if arithmDecoder != nil {
g.arithDecode = arithmDecoder
}
if regionHeight < 0 {
common.Log.Debug("[GENERIC-REF-REGION] setParameters with region height < 0")
}
g.TemplateID = grTemplate
g.RegionInfo.BitmapWidth = regionWidth
g.RegionInfo.BitmapHeight = regionHeight
g.ReferenceBitmap = grReference
g.ReferenceDX = grReferenceDX
g.ReferenceDY = grReferenceDY
g.IsTPGROn = isTPGRon
g.GrAtX = grAtX
g.GrAtY = grAtY
g.RegionBitmap = nil
common.Log.Trace("[GENERIC-REF-REGION] setParameters finished. %s", g)
}
func (g *GenericRefinementRegion) updateOverride() error {
if g.GrAtX == nil || g.GrAtY == nil {
return errors.New("AT pixels not set")
}
if len(g.GrAtX) != len(g.GrAtY) {
return errors.New("AT pixel inconsistent")
}
g.grAtOverride = make([]bool, len(g.GrAtX))
switch g.TemplateID {
case 0:
if g.GrAtX[0] != -1 && g.GrAtY[0] != -1 {
g.grAtOverride[0] = true
g.override = true
}
if g.GrAtX[1] != -1 && g.GrAtY[1] != -1 {
g.grAtOverride[1] = true
g.override = true
}
case 1:
g.override = false
}
return nil
}
type templater interface {
form(c1, c2, c3, c4, c5 int16) int16
setIndex(cx *arithmetic.DecoderStats)
}
type template0 struct{}
func (t *template0) form(c1, c2, c3, c4, c5 int16) int16 {
return (c1 << 10) | (c2 << 7) | (c3 << 4) | (c4 << 1) | c5
}
func (t *template0) setIndex(cx *arithmetic.DecoderStats) {
// Figure 14, page 22
cx.SetIndex(0x100)
}
var _ templater = &template0{}
type template1 struct{}
func (t *template1) form(c1, c2, c3, c4, c5 int16) int16 {
return ((c1 & 0x02) << 8) | (c2 << 6) | ((c3 & 0x03) << 4) | (c4 << 1) | c5
}
func (t *template1) setIndex(cx *arithmetic.DecoderStats) {
// Figure 15, page 22
cx.SetIndex(0x080)
}
var _ templater = &template1{}
// String implements the Stringer interface.
func (g *GenericRefinementRegion) String() string {
sb := &strings.Builder{}
sb.WriteString("\n[GENERIC REGION]\n")
sb.WriteString(g.RegionInfo.String() + "\n")
sb.WriteString(fmt.Sprintf("\t- IsTPGRon: %v\n", g.IsTPGROn))
sb.WriteString(fmt.Sprintf("\t- TemplateID: %v\n", g.TemplateID))
sb.WriteString(fmt.Sprintf("\t- GrAtX: %v\n", g.GrAtX))
sb.WriteString(fmt.Sprintf("\t- GrAtY: %v\n", g.GrAtY))
sb.WriteString(fmt.Sprintf("\t- ReferenceDX %v\n", g.ReferenceDX))
sb.WriteString(fmt.Sprintf("\t- ReferencDeY: %v\n", g.ReferenceDY))
return sb.String()
}
// newGenericRefinementRegion is a creator for the Generic Refinement Region.
func newGenericRefinementRegion(r reader.StreamReader, h *Header) *GenericRefinementRegion {
return &GenericRefinementRegion{
r: r,
RegionInfo: NewRegionSegment(r),
h: h,
t0: &template0{},
t1: &template1{},
}
}