Jacek Kucharczyk e85616cec2 JBIG2Decoder implementation (#67)
* 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
* Decoded full document
* 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
* 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.
* Integrate jbig2 tests with build system
* Added jbig2 integration test golden files.
* Minor jbig2 integration test fix
* Removed jbig2 integration image assertions
* Fixed jbig2 rowstride issue. Implemented jbig2 bit writer
* Changed golden files logic. Fixes r13 issues.
2019-07-14 21:18:40 +00:00

196 lines
4.1 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 mmr
import (
"io"
"github.com/unidoc/unipdf/v3/common"
"github.com/unidoc/unipdf/v3/internal/jbig2/reader"
)
const (
maxRunDataBuffer int = 1024 << 7
minRunDataBuffer int = 3
codeOffset uint = 24
)
type runData struct {
r *reader.SubstreamReader
offset int
lastOffset int
lastCode int
buffer []byte
bufferBase int
bufferTop int
}
func newRunData(r *reader.SubstreamReader) (*runData, error) {
d := &runData{
r: r,
offset: 0,
lastOffset: 1,
}
length := minInt(maxInt(minRunDataBuffer, int(r.Length())), maxRunDataBuffer)
d.buffer = make([]byte, length)
if err := d.fillBuffer(0); err != nil {
if err == io.EOF {
d.buffer = make([]byte, 10)
common.Log.Debug("FillBuffer failed: %v", err)
} else {
return nil, err
}
}
return d, nil
}
// align skips to the next byte
func (r *runData) align() {
r.offset = ((r.offset + 7) >> 3) << 3
}
func (r *runData) uncompressGetCode(table []*code) (*code, error) {
return r.uncompressGetCodeLittleEndian(table)
}
func (r *runData) uncompressGetCodeLittleEndian(table []*code) (*code, error) {
cd, err := r.uncompressGetNextCodeLittleEndian()
if err != nil {
common.Log.Debug("UncompressGetNextCodeLittleEndian failed: %v", err)
return nil, err
}
cd &= 0xffffff
index := cd >> (codeOffset - firstLevelTableSize)
result := table[index]
if result != nil && result.nonNilSubTable {
index = (cd >> (codeOffset - firstLevelTableSize - secondLevelTableSize)) & secondLevelTableMask
result = result.subTable[index]
}
return result, nil
}
func (r *runData) uncompressGetNextCodeLittleEndian() (int, error) {
bitsToFill := r.offset - r.lastOffset
// check whether we can refill, or need to fill in absolute mode
if bitsToFill < 0 || bitsToFill > 24 {
// refill at absolute offset
byteOffset := (r.offset >> 3) - r.bufferBase
if byteOffset >= r.bufferTop {
byteOffset += r.bufferBase
if err := r.fillBuffer(byteOffset); err != nil {
return 0, err
}
byteOffset -= r.bufferBase
}
lastCode := (uint32(r.buffer[byteOffset]&0xFF) << 16) |
(uint32(r.buffer[byteOffset+1]&0xFF) << 8) |
(uint32(r.buffer[byteOffset+2] & 0xFF))
bitOffset := uint32(r.offset & 7)
lastCode <<= bitOffset
r.lastCode = int(lastCode)
} else {
// the offset to the next byte boundary as seen from the last offset
bitOffset := r.lastOffset & 7 // lastoffset % 8
avail := 7 - bitOffset
if bitsToFill <= avail {
r.lastCode <<= uint(bitsToFill)
} else {
byteOffset := (r.lastOffset >> 3) + 3 - r.bufferBase
if byteOffset >= r.bufferTop {
byteOffset += r.bufferBase
if err := r.fillBuffer(byteOffset); err != nil {
return 0, err
}
byteOffset -= r.bufferBase
}
bitOffset = 8 - bitOffset
for {
r.lastCode <<= uint(bitOffset)
r.lastCode |= int(uint(r.buffer[byteOffset]) & 0xFF)
bitsToFill -= bitOffset
byteOffset++
bitOffset = 8
if !(bitsToFill >= 8) {
break
}
}
r.lastCode <<= uint(bitsToFill)
}
}
r.lastOffset = r.offset
return r.lastCode, nil
}
func (r *runData) fillBuffer(byteOffset int) error {
r.bufferBase = byteOffset
_, err := r.r.Seek(int64(byteOffset), io.SeekStart)
if err != nil {
if err == io.EOF {
common.Log.Debug("Seak EOF")
r.bufferTop = -1
} else {
return err
}
}
if err == nil {
r.bufferTop, err = r.r.Read(r.buffer)
if err != nil {
if err == io.EOF {
common.Log.Debug("Read EOF")
r.bufferTop = -1
} else {
return err
}
}
}
// check filling degree
if r.bufferTop > -1 && r.bufferTop < 3 {
for r.bufferTop < 3 {
b, err := r.r.ReadByte()
if err != nil {
if err == io.EOF {
r.buffer[r.bufferTop] = 0
} else {
return err
}
} else {
r.buffer[r.bufferTop] = b & 0xFF
}
r.bufferTop++
}
}
// leave some room in order to save a few tests in the calling code
r.bufferTop -= 3
if r.bufferTop < 0 {
// if we're at EOF just supply zero-bytes
r.buffer = make([]byte, len(r.buffer))
r.bufferTop = len(r.buffer) - 3
}
return nil
}