384 lines
8.4 KiB
Go
Raw Normal View History

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 23:18:40 +02:00
/*
* This file is subject to the terms and conditions defined in
* file 'LICENSE.md', which is part of this source code package.
*/
package jbig2
import (
"errors"
"fmt"
"math"
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 23:18:40 +02:00
"github.com/unidoc/unipdf/v3/common"
"github.com/unidoc/unipdf/v3/internal/jbig2/bitmap"
"github.com/unidoc/unipdf/v3/internal/jbig2/segments"
)
// Page represents JBIG2 Page structure.
// It contains all the included segments header definitions mapped to
// their number relation to the document and the resultant page bitmap.
type Page struct {
// Segments relation of the page number to their structures.
Segments map[int]*segments.Header
// PageNumber defines page number.
// NOTE: page numeration starts from 1.
PageNumber int
// Bitmap represents the page image.
Bitmap *bitmap.Bitmap
FinalHeight int
FinalWidth int
ResolutionX int
ResolutionY int
// Document is a relation to page's document
Document *Document
}
// GetBitmap implements segments.Pager interface.
func (p *Page) GetBitmap() (bm *bitmap.Bitmap, err error) {
common.Log.Trace(fmt.Sprintf("[PAGE][#%d] GetBitmap begins...", p.PageNumber))
defer func() {
if err != nil {
common.Log.Trace(fmt.Sprintf("[PAGE][#%d] GetBitmap failed. %v", p.PageNumber, err))
} else {
common.Log.Trace(fmt.Sprintf("[PAGE][#%d] GetBitmap finished", p.PageNumber))
}
}()
if p.Bitmap != nil {
return p.Bitmap, nil
}
err = p.composePageBitmap()
if err != nil {
return nil, err
}
return p.Bitmap, nil
}
// GetSegment implements segments.Pager interface.
func (p *Page) GetSegment(number int) *segments.Header {
s, ok := p.Segments[number]
if ok {
return s
}
if !ok || s == nil {
s, _ = p.Document.GlobalSegments.GetSegment(number)
return s
}
common.Log.Info("Segment not found, returning nil.")
return nil
}
// String implements Stringer interface.
func (p *Page) String() string {
return fmt.Sprintf("Page #%d", p.PageNumber)
}
// newPage is the creator for the Page structure.
func newPage(d *Document, pageNumber int) *Page {
return &Page{Document: d, PageNumber: pageNumber, Segments: map[int]*segments.Header{}}
}
// composePageBitmap composes the segment's bitmaps
// as a single page Bitmap.
func (p *Page) composePageBitmap() error {
if p.PageNumber == 0 {
return nil
}
h := p.getPageInformationSegment()
if h == nil {
return errors.New("Page Information segment not found")
}
// get the Segment data
seg, err := h.GetSegmentData()
if err != nil {
return err
}
pageInformation, ok := seg.(*segments.PageInformationSegment)
if !ok {
return errors.New("PageInformation Segment is of invalid type")
}
if err = p.createPage(pageInformation); err != nil {
return err
}
p.clearSegmentData()
return nil
}
func (p *Page) createPage(i *segments.PageInformationSegment) error {
var err error
if !i.IsStripe || i.PageBMHeight != -1 {
// Page 79, 4)
err = p.createNormalPage(i)
} else {
err = p.createStripedPage(i)
}
return err
}
func (p *Page) createNormalPage(i *segments.PageInformationSegment) error {
p.Bitmap = bitmap.New(i.PageBMWidth, i.PageBMHeight)
// Page 79, 3)
// if default pixel value is not 0, byte will be filled with 0xff
if i.DefaultPixelValue() != 0 {
p.Bitmap.SetDefaultPixel()
}
for _, h := range p.Segments {
switch h.Type {
case 6, 7, 22, 23, 38, 39, 42, 43:
common.Log.Trace("Getting Segment: %d", h.SegmentNumber)
s, err := h.GetSegmentData()
if err != nil {
return err
}
r, ok := s.(segments.Regioner)
if !ok {
common.Log.Debug("Segment: %T is not a Regioner", s)
return errors.New("invalid jbig2 segment type - not a Regioner")
}
regionBitmap, err := r.GetRegionBitmap()
if err != nil {
return err
}
if p.fitsPage(i, regionBitmap) {
p.Bitmap = regionBitmap
} else {
regionInfo := r.GetRegionInfo()
op := p.getCombinationOperator(i, regionInfo.CombinaionOperator)
err = bitmap.Blit(regionBitmap, p.Bitmap, int(regionInfo.XLocation), int(regionInfo.YLocation), op)
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 23:18:40 +02:00
if err != nil {
return err
}
}
break
}
}
return nil
}
func (p *Page) createStripedPage(i *segments.PageInformationSegment) error {
pageStripes, err := p.collectPageStripes()
if err != nil {
return err
}
var startLine int
for _, sd := range pageStripes {
if eos, ok := sd.(*segments.EndOfStripe); ok {
startLine = eos.LineNumber() + 1
} else {
r := sd.(segments.Regioner)
regionInfo := r.GetRegionInfo()
op := p.getCombinationOperator(i, regionInfo.CombinaionOperator)
regionBitmap, err := r.GetRegionBitmap()
if err != nil {
return err
}
err = bitmap.Blit(regionBitmap, p.Bitmap, int(regionInfo.XLocation), startLine, op)
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 23:18:40 +02:00
if err != nil {
return err
}
}
}
return nil
}
func (p *Page) collectPageStripes() ([]segments.Segmenter, error) {
var (
stripes []segments.Segmenter
err error
)
for _, h := range p.Segments {
switch h.Type {
case 6, 7, 22, 23, 38, 39, 42, 43:
var s segments.Segmenter
s, err = h.GetSegmentData()
if err != nil {
return nil, err
}
stripes = append(stripes, s)
case 50:
var s segments.Segmenter
s, err = h.GetSegmentData()
if err != nil {
return nil, err
}
eos, ok := s.(*segments.EndOfStripe)
if !ok {
err = errors.New("segment EndOfStripe is of invalid type")
return nil, err
}
stripes = append(stripes, eos)
p.FinalHeight = eos.LineNumber()
}
}
return stripes, nil
}
func (p *Page) clearSegmentData() {
for i := range p.Segments {
p.Segments[i].CleanSegmentData()
}
}
func (p *Page) clearPageData() {
p.Bitmap = nil
}
// countRegions counts the region segments in the Page.
func (p *Page) countRegions() int {
var regionCount int
for _, h := range p.Segments {
switch h.Type {
case 6, 7, 22, 23, 38, 39, 42, 43:
regionCount++
}
}
return regionCount
}
func (p *Page) fitsPage(i *segments.PageInformationSegment, regionBitmap *bitmap.Bitmap) bool {
return p.countRegions() == 1 &&
i.DefaultPixelValue() == 0 &&
i.PageBMWidth == regionBitmap.Width &&
i.PageBMHeight == regionBitmap.Height
}
func (p *Page) getCombinationOperator(i *segments.PageInformationSegment, newOperator bitmap.CombinationOperator) bitmap.CombinationOperator {
if i.CombinationOperatorOverrideAllowed() {
return newOperator
}
return i.CombinationOperator()
}
// getPageInformationSegment returns the associated page information segment.
func (p *Page) getPageInformationSegment() *segments.Header {
for _, s := range p.Segments {
if s.Type == segments.TPageInformation {
return s
}
}
common.Log.Debug("Page information segment not found for page: %s.", p)
return nil
}
func (p *Page) getHeight() (int, error) {
if p.FinalHeight == 0 {
h := p.getPageInformationSegment()
if h == nil {
return 0, errors.New("nil page information")
}
s, err := h.GetSegmentData()
if err != nil {
return 0, err
}
pi, ok := s.(*segments.PageInformationSegment)
if !ok {
return 0, errors.New("page information segment is of invalid type")
}
if pi.PageBMHeight == math.MaxInt32 {
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 23:18:40 +02:00
_, err = p.GetBitmap()
if err != nil {
return 0, err
}
} else {
p.FinalHeight = pi.PageBMHeight
}
}
return p.FinalHeight, nil
}
func (p *Page) getWidth() (int, error) {
if p.FinalWidth == 0 {
h := p.getPageInformationSegment()
if h == nil {
return 0, errors.New("nil page information")
}
s, err := h.GetSegmentData()
if err != nil {
return 0, err
}
pi, ok := s.(*segments.PageInformationSegment)
if !ok {
return 0, errors.New("page information segment is of invalid type")
}
p.FinalWidth = pi.PageBMWidth
}
return p.FinalWidth, nil
}
func (p *Page) getResolutionX() (int, error) {
if p.ResolutionX == 0 {
h := p.getPageInformationSegment()
if h == nil {
return 0, errors.New("nil page information")
}
s, err := h.GetSegmentData()
if err != nil {
return 0, err
}
pi, ok := s.(*segments.PageInformationSegment)
if !ok {
return 0, errors.New("page information segment is of invalid type")
}
p.ResolutionX = pi.ResolutionX
}
return p.ResolutionX, nil
}
func (p *Page) getResolutionY() (int, error) {
if p.ResolutionY == 0 {
h := p.getPageInformationSegment()
if h == nil {
return 0, errors.New("nil page information")
}
s, err := h.GetSegmentData()
if err != nil {
return 0, err
}
pi, ok := s.(*segments.PageInformationSegment)
if !ok {
return 0, errors.New("page information segment is of invalid type")
}
p.ResolutionY = pi.ResolutionY
}
return p.ResolutionY, nil
}