unipdf/internal/jbig2/document/segments/page-information.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

434 lines
11 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 (
"encoding/binary"
"fmt"
"math"
"strings"
"github.com/unidoc/unipdf/v3/common"
"github.com/unidoc/unipdf/v3/internal/jbig2/bitmap"
"github.com/unidoc/unipdf/v3/internal/jbig2/errors"
"github.com/unidoc/unipdf/v3/internal/jbig2/reader"
"github.com/unidoc/unipdf/v3/internal/jbig2/writer"
)
// PageInformationSegment represents the segment type Page Information 7.4.8.
type PageInformationSegment struct {
r reader.StreamReader
// Page bitmap height, four byte, 7.4.8.1
PageBMHeight int
// Page bitmap width, four byte, 7.4.8.1
PageBMWidth int
// Page X resolution, four byte 7.4.8.3
ResolutionX int
// Page Y resolution, four byte 7.4.8.4
ResolutionY int
// Page segment flags, one byte 7.4.8.5
combinaitonOperatorOverrideAllowed bool
combinationOperator bitmap.CombinationOperator
requiresAuxiliaryBuffer bool
defaultPixelValue uint8
mightContainRefinements bool
IsLossless bool
// Page striping information, two byte 7.4.8.6
IsStripe bool
MaxStripeSize uint16
}
// Encode implements SegmentEncoder interface.
func (p *PageInformationSegment) Encode(w writer.BinaryWriter) (n int, err error) {
const processName = "PageInformationSegment.Encode"
tm := make([]byte, 4)
// encode page bitmap width 7.4.8.1
binary.BigEndian.PutUint32(tm, uint32(p.PageBMWidth))
n, err = w.Write(tm)
if err != nil {
return n, errors.Wrap(err, processName, "width")
}
// encode page bitmap height 7.4.8.2
binary.BigEndian.PutUint32(tm, uint32(p.PageBMHeight))
var temp int
temp, err = w.Write(tm)
if err != nil {
return temp + n, errors.Wrap(err, processName, "height")
}
n += temp
// encode page x resolution - 7.4.8.3
binary.BigEndian.PutUint32(tm, uint32(p.ResolutionX))
temp, err = w.Write(tm)
if err != nil {
return temp + n, errors.Wrap(err, processName, "x resolution")
}
n += temp
// encode page y resolution - 7.4.8.4
binary.BigEndian.PutUint32(tm, uint32(p.ResolutionY))
if temp, err = w.Write(tm); err != nil {
return temp + n, errors.Wrap(err, processName, "y resolution")
}
n += temp
// page flags - 7.4.8.5
if err = p.encodeFlags(w); err != nil {
return n, errors.Wrap(err, processName, "")
}
n++
// page striping information - 7.4.8.6
if temp, err = p.encodeStripingInformation(w); err != nil {
return n, errors.Wrap(err, processName, "")
}
n += temp
return n, nil
}
// Init implements Segmenter interface.
func (p *PageInformationSegment) Init(h *Header, r reader.StreamReader) (err error) {
p.r = r
if err = p.parseHeader(); err != nil {
return errors.Wrap(err, "PageInformationSegment.Init", "")
}
return nil
}
// CombinationOperator gets the combination operator used by the page information segment.
func (p *PageInformationSegment) CombinationOperator() bitmap.CombinationOperator {
return p.combinationOperator
}
// CombinationOperatorOverrideAllowed defines if the Page segment has allowed override.
func (p *PageInformationSegment) CombinationOperatorOverrideAllowed() bool {
return p.combinaitonOperatorOverrideAllowed
}
// DefaultPixelValue returns page segment default pixel.
func (p *PageInformationSegment) DefaultPixelValue() uint8 {
return p.defaultPixelValue
}
// Size returns the byte size of the page information segment data.
// The page information segment is composed of:
// - bitmap width - 4 bytes
// - bitmap height - 4 bytes
// - x resolution - 4 bytes
// - y resolution - 4 bytes
// - flags - 1 byte
// - stripping information - 2 bytes
// Total 19 bytes
func (p *PageInformationSegment) Size() int {
return 19
}
// String implements Stringer interface.
func (p *PageInformationSegment) String() string {
sb := &strings.Builder{}
sb.WriteString("\n[PAGE-INFORMATION-SEGMENT]\n")
sb.WriteString(fmt.Sprintf("\t- BMHeight: %d\n", p.PageBMHeight))
sb.WriteString(fmt.Sprintf("\t- BMWidth: %d\n", p.PageBMWidth))
sb.WriteString(fmt.Sprintf("\t- ResolutionX: %d\n", p.ResolutionX))
sb.WriteString(fmt.Sprintf("\t- ResolutionY: %d\n", p.ResolutionY))
sb.WriteString(fmt.Sprintf("\t- CombinationOperator: %s\n", p.combinationOperator))
sb.WriteString(fmt.Sprintf("\t- CombinationOperatorOverride: %v\n", p.combinaitonOperatorOverrideAllowed))
sb.WriteString(fmt.Sprintf("\t- IsLossless: %v\n", p.IsLossless))
sb.WriteString(fmt.Sprintf("\t- RequiresAuxiliaryBuffer: %v\n", p.requiresAuxiliaryBuffer))
sb.WriteString(fmt.Sprintf("\t- MightContainRefinements: %v\n", p.mightContainRefinements))
sb.WriteString(fmt.Sprintf("\t- IsStriped: %v\n", p.IsStripe))
sb.WriteString(fmt.Sprintf("\t- MaxStripeSize: %v\n", p.MaxStripeSize))
return sb.String()
}
func (p *PageInformationSegment) checkInput() error {
if p.PageBMHeight == math.MaxInt32 {
if !p.IsStripe {
common.Log.Debug("PageInformationSegment.IsStripe should be true.")
}
}
return nil
}
func (p *PageInformationSegment) encodeFlags(w writer.BinaryWriter) (err error) {
const processName = "encodeFlags"
// reserved bits
if err = w.SkipBits(1); err != nil {
return errors.Wrap(err, processName, "reserved bit")
}
// combination operator override
var bit int
if p.CombinationOperatorOverrideAllowed() {
bit = 1
}
if err = w.WriteBit(bit); err != nil {
return errors.Wrap(err, processName, "combination operator overridden")
}
// requires auxiliary buffer
bit = 0
if p.requiresAuxiliaryBuffer {
bit = 1
}
if err = w.WriteBit(bit); err != nil {
return errors.Wrap(err, processName, "requires auxiliary buffer")
}
// default page combination operator - 2 bits
if err = w.WriteBit((int(p.combinationOperator) >> 1) & 0x01); err != nil {
return errors.Wrap(err, processName, "combination operator first bit")
}
if err = w.WriteBit(int(p.combinationOperator) & 0x01); err != nil {
return errors.Wrap(err, processName, "combination operator second bit")
}
// default page pixel value
bit = int(p.defaultPixelValue)
if err = w.WriteBit(bit); err != nil {
return errors.Wrap(err, processName, "default page pixel value")
}
// contains refinement
bit = 0
if p.mightContainRefinements {
bit = 1
}
if err = w.WriteBit(bit); err != nil {
return errors.Wrap(err, processName, "contains refinement")
}
// page is eventually lossless
bit = 0
if p.IsLossless {
bit = 1
}
if err = w.WriteBit(bit); err != nil {
return errors.Wrap(err, processName, "page is eventually lossless")
}
return nil
}
func (p *PageInformationSegment) encodeStripingInformation(w writer.BinaryWriter) (n int, err error) {
const processName = "encodeStripingInformation"
if !p.IsStripe {
// if there is no page striping write two empty bytes
if n, err = w.Write([]byte{0x00, 0x00}); err != nil {
return 0, errors.Wrap(err, processName, "no striping")
}
return n, nil
}
temp := make([]byte, 2)
binary.BigEndian.PutUint16(temp, p.MaxStripeSize|1<<15)
if n, err = w.Write(temp); err != nil {
return 0, errors.Wrapf(err, processName, "striping: %d", p.MaxStripeSize)
}
return n, nil
}
func (p *PageInformationSegment) parseHeader() (err error) {
common.Log.Trace("[PageInformationSegment] ParsingHeader...")
defer func() {
var str = "[PageInformationSegment] ParsingHeader Finished"
if err != nil {
str += " with error " + err.Error()
} else {
str += " successfully"
}
common.Log.Trace(str)
}()
if err = p.readWidthAndHeight(); err != nil {
return err
}
if err = p.readResolution(); err != nil {
return err
}
// Bit 7 - dirty read
_, err = p.r.ReadBit()
if err != nil {
return err
}
// Bit 6
if err = p.readCombinationOperatorOverrideAllowed(); err != nil {
return err
}
// Bit 5
if err = p.readRequiresAuxiliaryBuffer(); err != nil {
return err
}
// Bit 3-4
if err = p.readCombinationOperator(); err != nil {
return err
}
// Bit 2
if err = p.readDefaultPixelValue(); err != nil {
return err
}
// Bit 1
if err = p.readContainsRefinement(); err != nil {
return err
}
// Bit 0
if err = p.readIsLossless(); err != nil {
return err
}
// Bit 15
if err = p.readIsStriped(); err != nil {
return err
}
// Bit 0 - 14
if err = p.readMaxStripeSize(); err != nil {
return err
}
if err = p.checkInput(); err != nil {
return err
}
common.Log.Trace("%s", p)
return nil
}
func (p *PageInformationSegment) readResolution() error {
tempResolution, err := p.r.ReadBits(32)
if err != nil {
return err
}
p.ResolutionX = int(tempResolution & math.MaxInt32)
tempResolution, err = p.r.ReadBits(32)
if err != nil {
return err
}
p.ResolutionY = int(tempResolution & math.MaxInt32)
return nil
}
// readCombinationOperatorOverrideAllowed - Bit 6
func (p *PageInformationSegment) readCombinationOperatorOverrideAllowed() error {
b, err := p.r.ReadBit()
if err != nil {
return err
}
if b == 1 {
p.combinaitonOperatorOverrideAllowed = true
}
return nil
}
// readRequiresAuxiliaryBuffer - Bit 5
func (p *PageInformationSegment) readRequiresAuxiliaryBuffer() error {
b, err := p.r.ReadBit()
if err != nil {
return err
}
if b == 1 {
p.requiresAuxiliaryBuffer = true
}
return nil
}
// readCombinationOperator - Bit 3 -4
func (p *PageInformationSegment) readCombinationOperator() error {
b, err := p.r.ReadBits(2)
if err != nil {
return err
}
p.combinationOperator = bitmap.CombinationOperator(int(b))
return nil
}
// readDefaultPixelValue - Bit 2
func (p *PageInformationSegment) readDefaultPixelValue() error {
b, err := p.r.ReadBit()
if err != nil {
return err
}
p.defaultPixelValue = uint8(b & 0xf)
return nil
}
// readContainsRefinement - Bit 1
func (p *PageInformationSegment) readContainsRefinement() error {
b, err := p.r.ReadBit()
if err != nil {
return err
}
if b == 1 {
p.mightContainRefinements = true
}
return nil
}
// readIsLossless - Bit 0
func (p *PageInformationSegment) readIsLossless() error {
b, err := p.r.ReadBit()
if err != nil {
return err
}
if b == 1 {
p.IsLossless = true
}
return nil
}
// readIsStriped - Bit 15
func (p *PageInformationSegment) readIsStriped() error {
b, err := p.r.ReadBit()
if err != nil {
return err
}
if b == 1 {
p.IsStripe = true
}
return nil
}
// readMaxStripeSize - Bit 0-14
func (p *PageInformationSegment) readMaxStripeSize() error {
b, err := p.r.ReadBits(15)
if err != nil {
return err
}
p.MaxStripeSize = uint16(b & math.MaxUint16)
return nil
}
func (p *PageInformationSegment) readWidthAndHeight() error {
tempInt, err := p.r.ReadBits(32)
if err != nil {
return err
}
p.PageBMWidth = int(tempInt & math.MaxInt32)
tempInt, err = p.r.ReadBits(32)
if err != nil {
return err
}
p.PageBMHeight = int(tempInt & math.MaxInt32)
return nil
}