// Copyright 2019 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.//go:generate go run gen.go
// Package ccitt implements a CCITT (fax) image decoder.
package ccittimport ()var ( errIncompleteCode = errors.New("ccitt: incomplete code") errInvalidBounds = errors.New("ccitt: invalid bounds") errInvalidCode = errors.New("ccitt: invalid code") errInvalidMode = errors.New("ccitt: invalid mode") errInvalidOffset = errors.New("ccitt: invalid offset") errMissingEOL = errors.New("ccitt: missing End-of-Line") errRunLengthOverflowsWidth = errors.New("ccitt: run length overflows width") errRunLengthTooLong = errors.New("ccitt: run length too long") errUnsupportedMode = errors.New("ccitt: unsupported mode") errUnsupportedSubFormat = errors.New("ccitt: unsupported sub-format") errUnsupportedWidth = errors.New("ccitt: unsupported width"))// Order specifies the bit ordering in a CCITT data stream.typeOrderuint32const (// LSB means Least Significant Bits first.LSBOrder = iota// MSB means Most Significant Bits first.MSB)// SubFormat represents that the CCITT format consists of a number of// sub-formats. Decoding or encoding a CCITT data stream requires knowing the// sub-format context. It is not represented in the data stream per se.typeSubFormatuint32const (Group3SubFormat = iotaGroup4)// AutoDetectHeight is passed as the height argument to NewReader to indicate// that the image height (the number of rows) is not known in advance.constAutoDetectHeight = -1// Options are optional parameters.typeOptionsstruct {// Align means that some variable-bit-width codes are byte-aligned. Align bool// Invert means that black is the 1 bit or 0xFF byte, and white is 0. Invert bool}// maxWidth is the maximum (inclusive) supported width. This is a limitation of// this implementation, to guard against integer overflow, and not anything// inherent to the CCITT format.const maxWidth = 1 << 20func invertBytes( []byte) {for , := range { [] = ^ }}func reverseBitsWithinBytes( []byte) {for , := range { [] = bits.Reverse8() }}// highBits writes to dst (1 bit per pixel, most significant bit first) the// high (0x80) bits from src (1 byte per pixel). It returns the number of bytes// written and read such that dst[:d] is the packed form of src[:s].//// For example, if src starts with the 8 bytes [0x7D, 0x7E, 0x7F, 0x80, 0x81,// 0x82, 0x00, 0xFF] then 0x1D will be written to dst[0].//// If src has (8 * len(dst)) or more bytes then only len(dst) bytes are// written, (8 * len(dst)) bytes are read, and invert is ignored.//// Otherwise, if len(src) is not a multiple of 8 then the final byte written to// dst is padded with 1 bits (if invert is true) or 0 bits. If inverted, the 1s// are typically temporary, e.g. they will be flipped back to 0s by an// invertBytes call in the highBits caller, reader.Read.func highBits( []byte, []byte, bool) ( int, int) {// Pack as many complete groups of 8 src bytes as we can. := len() / 8if > len() { = len() } := [:]for := range { := [*8 : *8+8] [] = (([0] & 0x80) >> 0) | (([1] & 0x80) >> 1) | (([2] & 0x80) >> 2) | (([3] & 0x80) >> 3) | (([4] & 0x80) >> 4) | (([5] & 0x80) >> 5) | (([6] & 0x80) >> 6) | (([7] & 0x80) >> 7) } , = , 8* , = [:], [:]// Pack up to 7 remaining src bytes, if there's room in dst.if (len() > 0) && (len() > 0) { := byte(0)if { = 0xFF >> uint(len()) }for , := range { |= ( & 0x80) >> uint() } [0] = , = +1, +len() }return , }type bitReader struct { r io.Reader// readErr is the error returned from the most recent r.Read call. As the // io.Reader documentation says, when r.Read returns (n, err), "always // process the n > 0 bytes returned before considering the error err". readErr error// order is whether to process r's bytes LSB first or MSB first. order Order// The high nBits bits of the bits field hold upcoming bits in MSB order. bits uint64 nBits uint32// bytes[br:bw] holds bytes read from r but not yet loaded into bits. br uint32 bw uint32 bytes [1024]uint8}func ( *bitReader) () { := .nBits & 7 .bits <<= .nBits -= }// nextBitMaxNBits is the maximum possible value of bitReader.nBits after a// bitReader.nextBit call, provided that bitReader.nBits was not more than this// value before that call.//// Note that the decode function can unread bits, which can temporarily set the// bitReader.nBits value above nextBitMaxNBits.const nextBitMaxNBits = 31func ( *bitReader) () (uint64, error) {for {if .nBits > 0 { := .bits >> 63 .bits <<= 1 .nBits--return , nil }if := .bw - .br; >= 4 {// Read 32 bits, even though b.bits is a uint64, since the decode // function may need to unread up to maxCodeLength bits, putting // them back in the remaining (64 - 32) bits. TestMaxCodeLength // checks that the generated maxCodeLength constant fits. // // If changing the Uint32 call, also change nextBitMaxNBits. .bits = uint64(binary.BigEndian.Uint32(.bytes[.br:])) << 32 .br += 4 .nBits = 32continue } elseif > 0 { .bits = uint64(.bytes[.br]) << (7 * 8) .br++ .nBits = 8continue }if .readErr != nil {return0, .readErr } , := .r.Read(.bytes[:]) .br = 0 .bw = uint32() .readErr = if .order != MSB {reverseBitsWithinBytes(.bytes[:.bw]) } }}func decode( *bitReader, [][2]int16) (uint32, error) { , , := uint32(0), uint64(0), int32(1)for { , := .nextBit()if != nil {if == io.EOF { = errIncompleteCode }return0, } |= << (63 - ) ++// The "&1" is redundant, but can eliminate a bounds check. = int32([][&1])if < 0 {returnuint32(^), nil } elseif == 0 {// Unread the bits we've read, then return errInvalidCode. .bits = (.bits >> ) | .nBits += return0, errInvalidCode } }}// decodeEOL decodes the 12-bit EOL code 0000_0000_0001.func decodeEOL( *bitReader) error { , := uint32(0), uint64(0)for { , := .nextBit()if != nil {if == io.EOF { = errMissingEOL }return } |= << (63 - ) ++if < 12 {if &1 == 0 {continue } } elseif &1 != 0 {returnnil }// Unread the bits we've read, then return errMissingEOL. .bits = (.bits >> ) | .nBits += returnerrMissingEOL }}type reader struct { br bitReader subFormat SubFormat// width is the image width in pixels. width int// rowsRemaining starts at the image height in pixels, when the reader is // driven through the io.Reader interface, and decrements to zero as rows // are decoded. Alternatively, it may be negative if the image height is // not known in advance at the time of the NewReader call. // // When driven through DecodeIntoGray, this field is unused. rowsRemaining int// curr and prev hold the current and previous rows. Each element is either // 0x00 (black) or 0xFF (white). // // prev may be nil, when processing the first row. curr []byte prev []byte// ri is the read index. curr[:ri] are those bytes of curr that have been // passed along via the Read method. // // When the reader is driven through DecodeIntoGray, instead of through the // io.Reader interface, this field is unused. ri int// wi is the write index. curr[:wi] are those bytes of curr that have // already been decoded via the decodeRow method. // // What this implementation calls wi is roughly equivalent to what the spec // calls the a0 index. wi int// These fields are copied from the *Options (which may be nil). align bool invert bool// atStartOfRow is whether we have just started the row. Some parts of the // spec say to treat this situation as if "wi = -1". atStartOfRow bool// penColorIsWhite is whether the next run is black or white. penColorIsWhite bool// seenStartOfImage is whether we've called the startDecode method. seenStartOfImage bool// truncated is whether the input is missing the final 6 consecutive EOL's // (for Group3) or 2 consecutive EOL's (for Group4). Omitting that trailer // (but otherwise padding to a byte boundary, with either all 0 bits or all // 1 bits) is invalid according to the spec, but happens in practice when // exporting from Adobe Acrobat to TIFF + CCITT. This package silently // ignores the format error for CCITT input that has been truncated in that // fashion, returning the full decoded image. // // Detecting trailer truncation (just after the final row of pixels) // requires knowing which row is the final row, and therefore does not // trigger if the image height is not known in advance. truncated bool// readErr is a sticky error for the Read method. readErr error}func ( *reader) ( []byte) (int, error) {if .readErr != nil {return0, .readErr } := forlen() > 0 {// Allocate buffers (and decode any start-of-image codes), if // processing the first or second row.if .curr == nil {if !.seenStartOfImage {if .readErr = .startDecode(); .readErr != nil {break } .atStartOfRow = true } .curr = make([]byte, .width) }// Decode the next row, if necessary.if .atStartOfRow {if .rowsRemaining < 0 {// We do not know the image height in advance. See if the next // code is an EOL. If it is, it is consumed. If it isn't, the // bitReader shouldn't advance along the bit stream, and we // simply decode another row of pixel data. // // For the Group4 subFormat, we may need to align to a byte // boundary. For the Group3 subFormat, the previous z.decodeRow // call (or z.startDecode call) has already consumed one of the // 6 consecutive EOL's. The next EOL is actually the second of // 6, in the middle, and we shouldn't align at that point.if .align && (.subFormat == Group4) { .br.alignToByteBoundary() }if := .decodeEOL(); == errMissingEOL {// No-op. It's another row of pixel data. } elseif != nil { .readErr = break } else {if .readErr = .finishDecode(true); .readErr != nil {break } .readErr = io.EOFbreak } } elseif .rowsRemaining == 0 {// We do know the image height in advance, and we have already // decoded exactly that many rows.if .readErr = .finishDecode(false); .readErr != nil {break } .readErr = io.EOFbreak } else { .rowsRemaining-- }if .readErr = .decodeRow(.rowsRemaining == 0); .readErr != nil {break } }// Pack from z.curr (1 byte per pixel) to p (1 bit per pixel). , := highBits(, .curr[.ri:], .invert) = [:] .ri += // Prepare to decode the next row, if necessary.if .ri == len(.curr) { .ri, .curr, .prev = 0, .prev, .curr .atStartOfRow = true } } := len() - len()if .invert {invertBytes([:]) }return , .readErr}func ( *reader) () byte {if .penColorIsWhite {return0xFF }return0x00}func ( *reader) () error {switch .subFormat {caseGroup3:if := .decodeEOL(); != nil {return }caseGroup4:// No-op.default:returnerrUnsupportedSubFormat } .seenStartOfImage = truereturnnil}func ( *reader) ( bool) error { := 0switch .subFormat {caseGroup3:if .truncated {returnnil }// The stream ends with a RTC (Return To Control) of 6 consecutive // EOL's, but we should have already just seen an EOL, either in // z.startDecode (for a zero-height image) or in z.decodeRow. = 5caseGroup4: := .rowsRemaining < 0if {// Aligning to a byte boundary was already handled by reader.Read. } elseif .align { .br.alignToByteBoundary() }// The stream ends with two EOL's. If the first one is missing, and we // had an explicit image height, we just assume that the trailing two // EOL's were truncated and return a nil error.if := .decodeEOL(); != nil {if ( == errMissingEOL) && ! { .truncated = truereturnnil }return } = 1default:returnerrUnsupportedSubFormat }if { -- }for ; > 0; -- {if := .decodeEOL(); != nil {return } }returnnil}func ( *reader) () error {returndecodeEOL(&.br)}func ( *reader) ( bool) error { .wi = 0 .atStartOfRow = true .penColorIsWhite = trueif .align { .br.alignToByteBoundary() }switch .subFormat {caseGroup3:for ; .wi < len(.curr); .atStartOfRow = false {if := .decodeRun(); != nil {return } } := .decodeEOL()if && ( == errMissingEOL) { .truncated = truereturnnil }returncaseGroup4:for ; .wi < len(.curr); .atStartOfRow = false { , := decode(&.br, modeDecodeTable[:])if != nil {return } := readerMode{}if < uint32(len(readerModes)) { = readerModes[] }if .function == nil {returnerrInvalidMode }if := .function(, .arg); != nil {return } }returnnil }returnerrUnsupportedSubFormat}func ( *reader) () error { := blackDecodeTable[:]if .penColorIsWhite { = whiteDecodeTable[:] } := 0for { , := decode(&.br, )if != nil {return }if > maxWidth {panic("unreachable") } += int()if > maxWidth {returnerrRunLengthTooLong }// Anything 0x3F or below is a terminal code.if <= 0x3F {break } }if > (len(.curr) - .wi) {returnerrRunLengthOverflowsWidth } := .curr[.wi : .wi+] := .penColor()for := range { [] = } .wi += .penColorIsWhite = !.penColorIsWhitereturnnil}// The various modes' semantics are based on determining a row of pixels'// "changing elements": those pixels whose color differs from the one on its// immediate left.//// The row above the first row is implicitly all white. Similarly, the column// to the left of the first column is implicitly all white.//// For example, here's Figure 1 in "ITU-T Recommendation T.6", where the// current and previous rows contain black (B) and white (w) pixels. The a?// indexes point into curr, the b? indexes point into prev.//// b1 b2// v v// prev: BBBBBwwwwwBBBwwwww// curr: BBBwwwwwBBBBBBwwww// ^ ^ ^// a0 a1 a2//// a0 is the "reference element" or current decoder position, roughly// equivalent to what this implementation calls reader.wi.//// a1 is the next changing element to the right of a0, on the "coding line"// (the current row).//// a2 is the next changing element to the right of a1, again on curr.//// b1 is the first changing element on the "reference line" (the previous row)// to the right of a0 and of opposite color to a0.//// b2 is the next changing element to the right of b1, again on prev.//// The various modes calculate a1 (and a2, for modeH):// - modePass calculates that a1 is at or to the right of b2.// - modeH calculates a1 and a2 without considering b1 or b2.// - modeV* calculates a1 to be b1 plus an adjustment (between -3 and +3).const ( findB1 = false findB2 = true)// findB finds either the b1 or b2 value.func ( *reader) ( bool) int {// The initial row is a special case. The previous row is implicitly all // white, so that there are no changing pixel elements. We return b1 or b2 // to be at the end of the row.iflen(.prev) != len(.curr) {returnlen(.curr) } := .wiif .atStartOfRow {// a0 is implicitly at -1, on a white pixel. b1 is the first black // pixel in the previous row. b2 is the first white pixel after that.for ; ( < len(.prev)) && (.prev[] == 0xFF); ++ { }if == findB2 {for ; ( < len(.prev)) && (.prev[] == 0x00); ++ { } }return }// As per figure 1 above, assume that the current pen color is white. // First, walk past every contiguous black pixel in prev, starting at a0. := ^.penColor()for ; ( < len(.prev)) && (.prev[] == ); ++ { }// Then walk past every contiguous white pixel. := ^for ; ( < len(.prev)) && (.prev[] == ); ++ { }// We're now at a black pixel (or at the end of the row). That's b1.if == findB2 {// If we're looking for b2, walk past every contiguous black pixel // again. := ^for ; ( < len(.prev)) && (.prev[] == ); ++ { } }return}type readerMode struct { function func(z *reader, arg int) error arg int}var readerModes = [...]readerMode{modePass: {function: readerModePass},modeH: {function: readerModeH},modeV0: {function: readerModeV, arg: +0},modeVR1: {function: readerModeV, arg: +1},modeVR2: {function: readerModeV, arg: +2},modeVR3: {function: readerModeV, arg: +3},modeVL1: {function: readerModeV, arg: -1},modeVL2: {function: readerModeV, arg: -2},modeVL3: {function: readerModeV, arg: -3},modeExt: {function: readerModeExt},}func readerModePass( *reader, int) error { := .findB(findB2)if ( < .wi) || (len(.curr) < ) {returnerrInvalidOffset } := .curr[.wi:] := .penColor()for := range { [] = } .wi = returnnil}func readerModeH( *reader, int) error {// The first iteration finds a1. The second finds a2.for := 0; < 2; ++ {if := .decodeRun(); != nil {return } }returnnil}func readerModeV( *reader, int) error { := .findB(findB1) + if ( < .wi) || (len(.curr) < ) {returnerrInvalidOffset } := .curr[.wi:] := .penColor()for := range { [] = } .wi = .penColorIsWhite = !.penColorIsWhitereturnnil}func readerModeExt( *reader, int) error {returnerrUnsupportedMode}// DecodeIntoGray decodes the CCITT-formatted data in r into dst.//// It returns an error if dst's width and height don't match the implied width// and height of CCITT-formatted data.func ( *image.Gray, io.Reader, Order, SubFormat, *Options) error { := .Bounds()if (.Dx() < 0) || (.Dy() < 0) {returnerrInvalidBounds }if .Dx() > maxWidth {returnerrUnsupportedWidth } := reader{br: bitReader{r: , order: },subFormat: ,align: ( != nil) && .Align,invert: ( != nil) && .Invert,width: .Dx(), }if := .startDecode(); != nil {return } := .Dx()for := .Min.Y; < .Max.Y; ++ { := ( - .Min.Y) * .Stride .curr = .Pix[ : +]if := .decodeRow(+1 == .Max.Y); != nil {return } .curr, .prev = nil, .curr }if := .finishDecode(false); != nil {return }if .invert {for := .Min.Y; < .Max.Y; ++ { := ( - .Min.Y) * .StrideinvertBytes(.Pix[ : +]) } }returnnil}// NewReader returns an io.Reader that decodes the CCITT-formatted data in r.// The resultant byte stream is one bit per pixel (MSB first), with 1 meaning// white and 0 meaning black. Each row in the result is byte-aligned.//// A negative height, such as passing AutoDetectHeight, means that the image// height is not known in advance. A negative width is invalid.func ( io.Reader, Order, SubFormat, int, int, *Options) io.Reader { := error(nil)if < 0 { = errInvalidBounds } elseif > maxWidth { = errUnsupportedWidth }return &reader{br: bitReader{r: , order: },subFormat: ,align: ( != nil) && .Align,invert: ( != nil) && .Invert,width: ,rowsRemaining: ,readErr: , }}
The pages are generated with Goldsv0.8.7. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.