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

1723 lines
46 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 bitmap
import (
"github.com/unidoc/unipdf/v3/common"
"github.com/unidoc/unipdf/v3/internal/jbig2/errors"
)
// RasterOperator is the raster operation flag operator.
// There are following raster operations:
// PixClr 0000 0x0
// PixSet 1111 0xf
// PixSrc s 1100 0xc
// PixDst d 1010 0xa
// PixNotSrc ~s 0011 0x3
// PixNotDst ~d 0101 0x5
// PixSrcOrDst s | d 1110 0xe
// PixSrcAndDst s & d 1000 0x8
// PixSrcXorDst s ^ d 0110 0x6
// PixNotSrcOrDst ~s | d 1011 0xb
// PixNotSrcAndDst ~s & d 0010 0x2
// PixSrcOrNotDst s | ~d 1101 0xd
// PixSrcAndNotDst s & ~d 0100 0x4
// PixNotPixSrcOrDst ~(s | d) 0001 0x1
// PixNotPixSrcAndDst ~(s & d) 0111 0x7
// PixNotPixSrcXorDst ~(s ^ d) 1001 0X9
type RasterOperator int
// Raster operator constant definitions.
const (
PixSrc RasterOperator = 0xc
PixDst RasterOperator = 0xa
PixNotSrc RasterOperator = 0x3
PixNotDst RasterOperator = 0x5
PixClr RasterOperator = 0x0
PixSet RasterOperator = 0xf
PixSrcOrDst RasterOperator = 0xe
PixSrcAndDst RasterOperator = 0x8
PixSrcXorDst RasterOperator = 0x6
PixNotSrcOrDst RasterOperator = 0xb
PixNotSrcAndDst RasterOperator = 0x2
PixSrcOrNotDst RasterOperator = 0xd
PixSrcAndNotDst RasterOperator = 0x4
PixNotPixSrcOrDst RasterOperator = 0x1
PixNotPixSrcAndDst RasterOperator = 0x7
PixNotPixSrcXorDst RasterOperator = 0x9
PixPaint = PixSrcOrDst
PixSubtract = PixNotSrcAndDst
PixMask = PixSrcAndDst
)
// RasterOperation does the rastering operation on the provided 'dest' bitmap.
// There are 18 operations, described by the 'op' RasterOperator.
// The PixDst is a no-op.
//
// PixClr, PixSet, PixNotPixDst operate only on the 'dest'.
//
// The other 14 involve both 'src' and 'dest' bitmaps and depends on the bit values of either just the src or the
// both 'src' and 'dest'.
// Out of these 14 operators there are only 12 unique logical combinations. ~(s) ^ d) == ~(s ^ d) == s ^ ~(d).
// Parameters:
// 'dest' 'dest' bitmap
// 'dx' x val of UL corner of 'dest' bitmap
// 'dy' y val of UL corner of 'dest' bitmap
// 'dw' is the width of the operational rectangle on the bitmap 'dest'
// 'dh' is the height of the operational rectangle on the bitmap 'dest'
// 'op' raster operator code
// 'src' 'src' bitmap
// 'sx' x val of UL corner of 'src' bitmap
// 'sy' y val of UL corner of 'src' bitmap
func RasterOperation(dest *Bitmap, dx, dy, dw, dh int, op RasterOperator, src *Bitmap, sx, sy int) error {
return rasterOperation(dest, dx, dy, dw, dh, op, src, sx, sy)
}
// RasterOperation has the same function as the RasterOperation package function, where the
// 'b' bitmap is the 'dest'.
func (b *Bitmap) RasterOperation(dx, dy, dw, dh int, op RasterOperator, src *Bitmap, sx, sy int) error {
return rasterOperation(b, dx, dy, dw, dh, op, src, sx, sy)
}
func rasterOperation(dest *Bitmap, dx, dy, dw, dh int, op RasterOperator, src *Bitmap, sx, sy int) error {
const processName = "rasterOperation"
if dest == nil {
return errors.Error(processName, "nil 'dest' Bitmap")
}
if op == PixDst {
return nil
}
switch op {
case PixClr, PixSet, PixNotDst:
rasterOpUniLow(dest, dx, dy, dw, dh, op)
return nil
}
if src == nil {
common.Log.Debug("RasterOperation source bitmap is not defined")
return errors.Error(processName, "nil 'src' bitmap")
}
if err := rasterOpLow(dest, dx, dy, dw, dh, op, src, sx, sy); err != nil {
return errors.Wrap(err, processName, "")
}
return nil
}
// rasterOpLow scales width, performs clipping, checks alignment and dispatches for the 'op' RasterOperator.
func rasterOpLow(dest *Bitmap, dx, dy int, dw, dh int, op RasterOperator, src *Bitmap, sx, sy int) error {
var dHangW, sHangW, dHangH, sHangH int
// first, clip horizontally (sx, dx, dw)
if dx < 0 {
sx -= dx
dw += dx
dx = 0
}
if sx < 0 {
dx -= sx
dw += sx
sx = 0
}
// rect ovhang dest to right
dHangW = dx + dw - dest.Width
if dHangW > 0 {
dw -= dHangW
}
// rect ovhang src to right
sHangW = sx + dw - src.Width
if sHangW > 0 {
dw -= sHangW
}
// clip vertically (sy, dy, dh)
if dy < 0 {
sy -= dy
dh += dy
dy = 0
}
if sy < 0 {
dy -= sy
dh += sy
sy = 0
}
// rect ovhang dest below
dHangH = dy + dh - dest.Height
if dHangH > 0 {
dh -= dHangH
}
// rect ovhang src below
sHangH = sy + dh - src.Height
if sHangH > 0 {
dh -= sHangH
}
// quit if clipped entirely
if dw <= 0 || dh <= 0 {
return nil
}
// dispatch to aligned or non-aligned blitters.
var err error
switch {
case dx&7 == 0 && sx&7 == 0:
err = rasterOpByteAlignedLow(dest, dx, dy, dw, dh, op, src, sx, sy)
case dx&7 == sx&7:
err = rasterOpVAlignedLow(dest, dx, dy, dw, dh, op, src, sx, sy)
default:
err = rasterOpGeneralLow(dest, dx, dy, dw, dh, op, src, sx, sy)
}
if err != nil {
return errors.Wrap(err, "rasterOpLow", "")
}
return nil
}
// rasterOpByteAlignedLow called when both the src and dest bitmaps are left aligned on 8-bit boundaries - dx & 7 == 0 AND sx & 7 == 0.
func rasterOpByteAlignedLow(dest *Bitmap, dx, dy, dw, dh int, op RasterOperator, src *Bitmap, sx, sy int) error {
var (
// mask for lat partial byte
lwMask byte
// index of the first src byte
psfWord int
// index of the first dest byte
pdfWord int
// line index for source and dest bitmap
lines, lined int
i, j int
)
// get the number of full bytes
fullBytesNumber := dw >> 3
// get the number of ovrhang bits in last partial word
lwBits := dw & 7
if lwBits > 0 {
lwMask = lmaskByte[lwBits]
}
psfWord = src.RowStride*sy + (sx >> 3)
pdfWord = dest.RowStride*dy + (dx >> 3)
switch op {
case PixSrc:
for i = 0; i < dh; i++ {
lines = psfWord + i*src.RowStride
lined = pdfWord + i*dest.RowStride
for j = 0; j < fullBytesNumber; j++ {
dest.Data[lined] = src.Data[lines]
lined++
lines++
}
if lwBits > 0 {
dest.Data[lined] = combinePartial(dest.Data[lined], src.Data[lines], lwMask)
}
}
case PixNotSrc:
for i = 0; i < dh; i++ {
lines = psfWord + i*src.RowStride
lined = pdfWord + i*dest.RowStride
for j = 0; j < fullBytesNumber; j++ {
dest.Data[lined] = ^(src.Data[lines])
lined++
lines++
}
if lwBits > 0 {
dest.Data[lined] = combinePartial(dest.Data[lined], ^src.Data[lines], lwMask)
}
}
case PixSrcOrDst:
for i = 0; i < dh; i++ {
lines = psfWord + i*src.RowStride
lined = pdfWord + i*dest.RowStride
for j = 0; j < fullBytesNumber; j++ {
dest.Data[lined] |= src.Data[lines]
lined++
lines++
}
if lwBits > 0 {
dest.Data[lined] = combinePartial(dest.Data[lined], src.Data[lines]|dest.Data[lined], lwMask)
}
}
case PixSrcAndDst:
for i = 0; i < dh; i++ {
lines = psfWord + i*src.RowStride
lined = pdfWord + i*dest.RowStride
for j = 0; j < fullBytesNumber; j++ {
dest.Data[lined] &= src.Data[lines]
lined++
lines++
}
if lwBits > 0 {
dest.Data[lined] = combinePartial(dest.Data[lined], src.Data[lines]&dest.Data[lined], lwMask)
}
}
case PixSrcXorDst:
for i = 0; i < dh; i++ {
lines = psfWord + i*src.RowStride
lined = pdfWord + i*dest.RowStride
for j = 0; j < fullBytesNumber; j++ {
dest.Data[lined] ^= src.Data[lines]
lined++
lines++
}
if lwBits > 0 {
dest.Data[lined] = combinePartial(dest.Data[lined], src.Data[lines]^dest.Data[lined], lwMask)
}
}
case PixNotSrcOrDst:
for i = 0; i < dh; i++ {
lines = psfWord + i*src.RowStride
lined = pdfWord + i*dest.RowStride
for j = 0; j < fullBytesNumber; j++ {
dest.Data[lined] |= ^(src.Data[lines])
lined++
lines++
}
if lwBits > 0 {
dest.Data[lined] = combinePartial(dest.Data[lined], ^(src.Data[lines])|dest.Data[lined], lwMask)
}
}
case PixNotSrcAndDst:
for i = 0; i < dh; i++ {
lines = psfWord + i*src.RowStride
lined = pdfWord + i*dest.RowStride
for j = 0; j < fullBytesNumber; j++ {
dest.Data[lined] &= ^(src.Data[lines])
lined++
lines++
}
if lwBits > 0 {
dest.Data[lined] = combinePartial(dest.Data[lined], ^(src.Data[lines])&dest.Data[lined], lwMask)
}
}
case PixSrcOrNotDst:
for i = 0; i < dh; i++ {
lines = psfWord + i*src.RowStride
lined = pdfWord + i*dest.RowStride
for j = 0; j < fullBytesNumber; j++ {
dest.Data[lined] = src.Data[lines] | ^(dest.Data[lined])
lined++
lines++
}
if lwBits > 0 {
dest.Data[lined] = combinePartial(dest.Data[lined], src.Data[lines]|^(dest.Data[lined]), lwMask)
}
}
case PixSrcAndNotDst:
for i = 0; i < dh; i++ {
lines = psfWord + i*src.RowStride
lined = pdfWord + i*dest.RowStride
for j = 0; j < fullBytesNumber; j++ {
dest.Data[lined] = src.Data[lines] & ^(dest.Data[lined])
lined++
lines++
}
if lwBits > 0 {
dest.Data[lined] = combinePartial(dest.Data[lined], src.Data[lines]&^(dest.Data[lined]), lwMask)
}
}
case PixNotPixSrcOrDst:
for i = 0; i < dh; i++ {
lines = psfWord + i*src.RowStride
lined = pdfWord + i*dest.RowStride
for j = 0; j < fullBytesNumber; j++ {
dest.Data[lined] = ^(src.Data[lines] | dest.Data[lined])
lined++
lines++
}
if lwBits > 0 {
dest.Data[lined] = combinePartial(dest.Data[lined], ^(src.Data[lines] | dest.Data[lined]), lwMask)
}
}
case PixNotPixSrcAndDst:
for i = 0; i < dh; i++ {
lines = psfWord + i*src.RowStride
lined = pdfWord + i*dest.RowStride
for j = 0; j < fullBytesNumber; j++ {
dest.Data[lined] = ^(src.Data[lines] & dest.Data[lined])
lined++
lines++
}
if lwBits > 0 {
dest.Data[lined] = combinePartial(dest.Data[lined], ^(src.Data[lines] & dest.Data[lined]), lwMask)
}
}
case PixNotPixSrcXorDst:
for i = 0; i < dh; i++ {
lines = psfWord + i*src.RowStride
lined = pdfWord + i*dest.RowStride
for j = 0; j < fullBytesNumber; j++ {
dest.Data[lined] = ^(src.Data[lines] ^ dest.Data[lined])
lined++
lines++
}
if lwBits > 0 {
dest.Data[lined] = combinePartial(dest.Data[lined], ^(src.Data[lines] ^ dest.Data[lined]), lwMask)
}
}
default:
common.Log.Debug("Provided invalid raster operator: %v", op)
return errors.Error("rasterOpByteAlignedLow", "invalid raster operator")
}
return nil
}
// rasterOpVAlignedLow called when the left side of the src and dest bitmaps have the same alignment
// relative to 8-bit boundaries. That is: dx & 7 == sx & 7.
func rasterOpVAlignedLow(dest *Bitmap, dx, dy, dw, dh int, op RasterOperator, src *Bitmap, sx, sy int) error {
var (
// boolean if first dest byte is doubly partial
dfwPart2B bool
// boolean if there exist a full dest byte
dfwFullB bool
// number of full bytes in dest
dnFullBytes int
// index of first full dest byte
pdfwFull int
// index of first full src byte
psfwFull int
// boolean if last dest byte is partial
dlwPartB bool
// mask for last partial dest byte
dlwMask byte
// last byte dest bits in ovrhang
dlwBits int
// index of last partial dest byte
pdlwPart int
// index of last partial src byte
pslwPart int
i, j int
)
// first byte dest bits in ovrhang
dfwBits := 8 - (dx & 7)
// mask for first partial dest byte
dfwMask := rmaskByte[dfwBits]
// index of first partial dest byte
pdfwPart := dest.RowStride*dy + (dx >> 3)
// index of first partial src byte
psfwPart := src.RowStride*sy + (sx >> 3)
// is the first word doubly partial?
if dw < dfwBits {
dfwPart2B = true
dfwMask &= lmaskByte[8-dfwBits+dw]
}
// is there a full dest byte?
if !dfwPart2B {
dnFullBytes = (dw - dfwBits) >> 3
if dnFullBytes > 0 {
// there is a full dest byte
dfwFullB = true
pdfwFull = pdfwPart + 1
psfwFull = psfwPart + 1
}
}
dlwBits = (dx + dw) & 7
// is the last word partial?
if !(dfwPart2B || dlwBits == 0) {
dlwPartB = true
dlwMask = lmaskByte[dlwBits]
pdlwPart = pdfwPart + 1 + dnFullBytes
pslwPart = psfwPart + 1 + dnFullBytes
}
switch op {
case PixSrc:
// do the first partial byte
for i = 0; i < dh; i++ {
dest.Data[pdfwPart] = combinePartial(dest.Data[pdfwPart], src.Data[psfwPart], dfwMask)
pdfwPart += dest.RowStride
psfwPart += src.RowStride
}
// do the full bytes
if dfwFullB {
for i = 0; i < dh; i++ {
for j = 0; j < dnFullBytes; j++ {
dest.Data[pdfwFull+j] = src.Data[psfwFull+j]
}
pdfwFull += dest.RowStride
psfwFull += src.RowStride
}
}
// do the last partial byte
if dlwPartB {
for i = 0; i < dh; i++ {
dest.Data[pdlwPart] = combinePartial(dest.Data[pdlwPart], src.Data[pslwPart], dlwMask)
pdlwPart += dest.RowStride
pslwPart += src.RowStride
}
}
case PixNotSrc:
// do the first partial byte
for i = 0; i < dh; i++ {
dest.Data[pdfwPart] = combinePartial(dest.Data[pdfwPart], ^src.Data[psfwPart], dfwMask)
pdfwPart += dest.RowStride
psfwPart += src.RowStride
}
// do the full bytes
if dfwFullB {
for i = 0; i < dh; i++ {
for j = 0; j < dnFullBytes; j++ {
dest.Data[pdfwFull+j] = ^src.Data[psfwFull+j]
}
pdfwFull += dest.RowStride
psfwFull += src.RowStride
}
}
// do the last partial byte
if dlwPartB {
for i = 0; i < dh; i++ {
dest.Data[pdlwPart] = combinePartial(dest.Data[pdlwPart], ^src.Data[pslwPart], dlwMask)
pdlwPart += dest.RowStride
pslwPart += src.RowStride
}
}
case PixSrcOrDst:
// do the first partial byte
for i = 0; i < dh; i++ {
dest.Data[pdfwPart] = combinePartial(dest.Data[pdfwPart], src.Data[psfwPart]|dest.Data[pdfwPart], dfwMask)
pdfwPart += dest.RowStride
psfwPart += src.RowStride
}
// do the full bytes
if dfwFullB {
for i = 0; i < dh; i++ {
for j = 0; j < dnFullBytes; j++ {
dest.Data[pdfwFull+j] |= src.Data[psfwFull+j]
}
pdfwFull += dest.RowStride
psfwFull += src.RowStride
}
}
// do the last partial byte
if dlwPartB {
for i = 0; i < dh; i++ {
dest.Data[pdlwPart] = combinePartial(dest.Data[pdlwPart], src.Data[pslwPart]|dest.Data[pdlwPart], dlwMask)
pdlwPart += dest.RowStride
pslwPart += src.RowStride
}
}
case PixSrcAndDst:
// do the first partial byte
for i = 0; i < dh; i++ {
dest.Data[pdfwPart] = combinePartial(dest.Data[pdfwPart], src.Data[psfwPart]&dest.Data[pdfwPart], dfwMask)
pdfwPart += dest.RowStride
psfwPart += src.RowStride
}
// do the full bytes
if dfwFullB {
for i = 0; i < dh; i++ {
for j = 0; j < dnFullBytes; j++ {
dest.Data[pdfwFull+j] &= src.Data[psfwFull+j]
}
pdfwFull += dest.RowStride
psfwFull += src.RowStride
}
}
// do the last partial byte
if dlwPartB {
for i = 0; i < dh; i++ {
dest.Data[pdlwPart] = combinePartial(dest.Data[pdlwPart], src.Data[pslwPart]&dest.Data[pdlwPart], dlwMask)
pdlwPart += dest.RowStride
pslwPart += src.RowStride
}
}
case PixSrcXorDst:
// do the first partial byte
for i = 0; i < dh; i++ {
dest.Data[pdfwPart] = combinePartial(dest.Data[pdfwPart], src.Data[psfwPart]^dest.Data[pdfwPart], dfwMask)
pdfwPart += dest.RowStride
psfwPart += src.RowStride
}
// do the full bytes
if dfwFullB {
for i = 0; i < dh; i++ {
for j = 0; j < dnFullBytes; j++ {
dest.Data[pdfwFull+j] ^= src.Data[psfwFull+j]
}
pdfwFull += dest.RowStride
psfwFull += src.RowStride
}
}
// do the last partial byte
if dlwPartB {
for i = 0; i < dh; i++ {
dest.Data[pdlwPart] = combinePartial(dest.Data[pdlwPart], src.Data[pslwPart]^dest.Data[pdlwPart], dlwMask)
pdlwPart += dest.RowStride
pslwPart += src.RowStride
}
}
case PixNotSrcOrDst:
// do the first partial byte
for i = 0; i < dh; i++ {
dest.Data[pdfwPart] = combinePartial(dest.Data[pdfwPart], ^(src.Data[psfwPart])|dest.Data[pdfwPart], dfwMask)
pdfwPart += dest.RowStride
psfwPart += src.RowStride
}
// do the full bytes
if dfwFullB {
for i = 0; i < dh; i++ {
for j = 0; j < dnFullBytes; j++ {
dest.Data[pdfwFull+j] |= ^(src.Data[psfwFull+j])
}
pdfwFull += dest.RowStride
psfwFull += src.RowStride
}
}
// do the last partial byte
if dlwPartB {
for i = 0; i < dh; i++ {
dest.Data[pdlwPart] = combinePartial(dest.Data[pdlwPart], ^(src.Data[pslwPart])|dest.Data[pdlwPart], dlwMask)
pdlwPart += dest.RowStride
pslwPart += src.RowStride
}
}
case PixNotSrcAndDst:
// do the first partial byte
for i = 0; i < dh; i++ {
dest.Data[pdfwPart] = combinePartial(dest.Data[pdfwPart], ^(src.Data[psfwPart])&dest.Data[pdfwPart], dfwMask)
pdfwPart += dest.RowStride
psfwPart += src.RowStride
}
// do the full bytes
if dfwFullB {
for i = 0; i < dh; i++ {
for j = 0; j < dnFullBytes; j++ {
dest.Data[pdfwFull+j] &= ^src.Data[psfwFull+j]
}
pdfwFull += dest.RowStride
psfwFull += src.RowStride
}
}
// do the last partial byte
if dlwPartB {
for i = 0; i < dh; i++ {
dest.Data[pdlwPart] = combinePartial(dest.Data[pdlwPart], ^(src.Data[pslwPart])&dest.Data[pdlwPart], dlwMask)
pdlwPart += dest.RowStride
pslwPart += src.RowStride
}
}
case PixSrcOrNotDst:
// do the first partial byte
for i = 0; i < dh; i++ {
dest.Data[pdfwPart] = combinePartial(dest.Data[pdfwPart], src.Data[psfwPart]|^(dest.Data[pdfwPart]), dfwMask)
pdfwPart += dest.RowStride
psfwPart += src.RowStride
}
// do the full bytes
if dfwFullB {
for i = 0; i < dh; i++ {
for j = 0; j < dnFullBytes; j++ {
dest.Data[pdfwFull+j] = src.Data[psfwFull+j] | ^(dest.Data[pdfwFull+j])
}
pdfwFull += dest.RowStride
psfwFull += src.RowStride
}
}
// do the last partial byte
if dlwPartB {
for i = 0; i < dh; i++ {
dest.Data[pdlwPart] = combinePartial(dest.Data[pdlwPart], src.Data[pslwPart]|^(dest.Data[pdlwPart]), dlwMask)
pdlwPart += dest.RowStride
pslwPart += src.RowStride
}
}
case PixSrcAndNotDst:
// do the first partial byte
for i = 0; i < dh; i++ {
dest.Data[pdfwPart] = combinePartial(dest.Data[pdfwPart], src.Data[psfwPart]&^(dest.Data[pdfwPart]), dfwMask)
pdfwPart += dest.RowStride
psfwPart += src.RowStride
}
// do the full bytes
if dfwFullB {
for i = 0; i < dh; i++ {
for j = 0; j < dnFullBytes; j++ {
dest.Data[pdfwFull+j] = src.Data[psfwFull+j] & ^(dest.Data[pdfwFull+j])
}
pdfwFull += dest.RowStride
psfwFull += src.RowStride
}
}
// do the last partial byte
if dlwPartB {
for i = 0; i < dh; i++ {
dest.Data[pdlwPart] = combinePartial(dest.Data[pdlwPart], src.Data[pslwPart]&^(dest.Data[pdlwPart]), dlwMask)
pdlwPart += dest.RowStride
pslwPart += src.RowStride
}
}
case PixNotPixSrcOrDst:
// do the first partial byte
for i = 0; i < dh; i++ {
dest.Data[pdfwPart] = combinePartial(dest.Data[pdfwPart], ^(src.Data[psfwPart] | dest.Data[pdfwPart]), dfwMask)
pdfwPart += dest.RowStride
psfwPart += src.RowStride
}
// do the full bytes
if dfwFullB {
for i = 0; i < dh; i++ {
for j = 0; j < dnFullBytes; j++ {
dest.Data[pdfwFull+j] = ^(src.Data[psfwFull+j] | dest.Data[pdfwFull+j])
}
pdfwFull += dest.RowStride
psfwFull += src.RowStride
}
}
// do the last partial byte
if dlwPartB {
for i = 0; i < dh; i++ {
dest.Data[pdlwPart] = combinePartial(dest.Data[pdlwPart], ^(src.Data[pslwPart] | dest.Data[pdlwPart]), dlwMask)
pdlwPart += dest.RowStride
pslwPart += src.RowStride
}
}
case PixNotPixSrcAndDst:
// do the first partial byte
for i = 0; i < dh; i++ {
dest.Data[pdfwPart] = combinePartial(dest.Data[pdfwPart], ^(src.Data[psfwPart] & dest.Data[pdfwPart]), dfwMask)
pdfwPart += dest.RowStride
psfwPart += src.RowStride
}
// do the full bytes
if dfwFullB {
for i = 0; i < dh; i++ {
for j = 0; j < dnFullBytes; j++ {
dest.Data[pdfwFull+j] = ^(src.Data[psfwFull+j] & dest.Data[pdfwFull+j])
}
pdfwFull += dest.RowStride
psfwFull += src.RowStride
}
}
// do the last partial byte
if dlwPartB {
for i = 0; i < dh; i++ {
dest.Data[pdlwPart] = combinePartial(dest.Data[pdlwPart], ^(src.Data[pslwPart] & dest.Data[pdlwPart]), dlwMask)
pdlwPart += dest.RowStride
pslwPart += src.RowStride
}
}
case PixNotPixSrcXorDst:
// do the first partial byte
for i = 0; i < dh; i++ {
dest.Data[pdfwPart] = combinePartial(dest.Data[pdfwPart], ^(src.Data[psfwPart] ^ dest.Data[pdfwPart]), dfwMask)
pdfwPart += dest.RowStride
psfwPart += src.RowStride
}
// do the full bytes
if dfwFullB {
for i = 0; i < dh; i++ {
for j = 0; j < dnFullBytes; j++ {
dest.Data[pdfwFull+j] = ^(src.Data[psfwFull+j] ^ dest.Data[pdfwFull+j])
}
pdfwFull += dest.RowStride
psfwFull += src.RowStride
}
}
// do the last partial byte
if dlwPartB {
for i = 0; i < dh; i++ {
dest.Data[pdlwPart] = combinePartial(dest.Data[pdlwPart], ^(src.Data[pslwPart] ^ dest.Data[pdlwPart]), dlwMask)
pdlwPart += dest.RowStride
pslwPart += src.RowStride
}
}
default:
common.Log.Debug("Invalid raster operator: %d", op)
return errors.Error("rasterOpVAlignedLow", "invalid raster operator")
}
return nil
}
// rasterOpGeneralLow called when the 'src' and 'dst' rects don't have the same byte alignment.
func rasterOpGeneralLow(dest *Bitmap, dx, dy, dw, dh int, op RasterOperator, src *Bitmap, sx, sy int) error {
var (
// dfwPartB boolean if first dest byte is partial.
dfwPartB bool
// dfwPart2B boolean if first dest byte is doubly partial.
dfwPart2B bool
// dfwMask mask for first partial 'dest'byte.
dfwMask byte
// dfwBits are first byte 'dest' bits in overhang.
dfwBits int
// dHang is the 'dest' overhang in first partial byte or if the
// 'dest' is byte aligned.
dHang int
// pdfwPart is an index of the first partial 'dest' byte.
pdfwPart int
// psfwPart is an index of the first partial 'src' byte.
psfwPart int
// dfwFullB a boolean if there exists a full 'dest' byte.
dfwFullB bool
// dnFullBytes number of full bytes in 'dest'.
dnFullBytes int
// pdfwFull is the index of the first full 'dest' byte.
pdfwFull int
// psfwFull is the index of the first full 'src' byte.
psfwFull int
// dlwPartB boolean if last 'dest' word is partial.
dlwPartB bool
// dlwMask is a mask for the last partial 'dest' byte.
dlwMask byte
// dlwBits are the last word 'dest' bits in ovrhang.
dlwBits int
// pdlwPart is the index of the last partial 'dest' byte.
pdlwPart int
// pslwPart is the index of the last partial 'src' byte.
pslwPart int
// sBytes compose 'src' byte aligned with the 'dest' bytes.
sBytes byte
// sfwBits is a first word 'src' bits in overhang, or 8 if src is byte aligned.
sfwBits int
// sHang is a 'src' overhang in the first partial byte or 0 if 'src' is word aligned.
sHang int
// sleftShift are the bits to shift left for source bytes to align
// with the 'dest'. Also the number of bits that get shifted to the right to align with the 'dest'.
sleftShift uint
// srightShift are the bits to shift right for source byte to align with the 'dest'. Also the number of bits
// that get shifted to the left to align with the 'dest'.
srightShift uint
// srightMask is the mask for selecting sleftshift bits that have been shifted right by srightshift bits.
srightMask byte
// shift direction
sfwShiftDir shift
// sfwAddB is additional sfw right shift needed
sfwAddB bool
// slwAddB is additional slw right shift needed
slwAddB bool
i, j int
)
if sx&7 != 0 {
sHang = 8 - (sx & 7)
}
if dx&7 != 0 {
dHang = 8 - (dx & 7)
}
if sHang == 0 && dHang == 0 {
srightMask = rmaskByte[0]
} else {
if dHang > sHang {
sleftShift = uint(dHang - sHang)
} else {
sleftShift = uint(8 - (sHang - dHang))
}
srightShift = 8 - sleftShift
srightMask = rmaskByte[sleftShift]
}
// is the first dest word partial?
if (dx & 7) != 0 {
dfwPartB = true
dfwBits = 8 - (dx & 7)
dfwMask = rmaskByte[dfwBits]
pdfwPart = dest.RowStride*dy + (dx >> 3)
psfwPart = src.RowStride*sy + (sx >> 3)
sfwBits = 8 - (sx & 7)
if dfwBits > sfwBits {
sfwShiftDir = shiftLeft
if dw >= sHang {
sfwAddB = true
}
} else {
sfwShiftDir = shiftRight
}
}
if dw < dfwBits {
dfwPart2B = true
dfwMask &= lmaskByte[8-dfwBits+dw]
}
if !dfwPart2B {
dnFullBytes = (dw - dfwBits) >> 3
if dnFullBytes != 0 {
dfwFullB = true
pdfwFull = dest.RowStride*dy + ((dx + dHang) >> 3)
psfwFull = src.RowStride*sy + ((sx + dHang) >> 3)
}
}
dlwBits = (dx + dw) & 7
if !(dfwPart2B || dlwBits == 0) {
dlwPartB = true
dlwMask = lmaskByte[dlwBits]
pdlwPart = dest.RowStride*dy + ((dx + dHang) >> 3) + dnFullBytes
pslwPart = src.RowStride*sy + ((sx + dHang) >> 3) + dnFullBytes
if dlwBits > int(srightShift) {
slwAddB = true
}
}
switch op {
case PixSrc:
// do the first partial word
if dfwPartB {
for i = 0; i < dh; i++ {
if sfwShiftDir == shiftLeft {
sBytes = src.Data[psfwPart] << sleftShift
if sfwAddB {
sBytes = combinePartial(sBytes, src.Data[psfwPart+1]>>srightShift, srightMask)
}
} else {
sBytes = src.Data[psfwPart] >> srightShift
}
dest.Data[pdfwPart] = combinePartial(dest.Data[pdfwPart], sBytes, dfwMask)
pdfwPart += dest.RowStride
psfwPart += src.RowStride
}
}
// do the full words
if dfwFullB {
for i = 0; i < dh; i++ {
for j = 0; j < dnFullBytes; j++ {
sBytes = combinePartial(src.Data[psfwFull+j]<<sleftShift, src.Data[psfwFull+j+1]>>srightShift, srightMask)
dest.Data[pdfwFull+j] = sBytes
}
pdfwFull += dest.RowStride
psfwFull += src.RowStride
}
}
// do the last partial word
if dlwPartB {
for i = 0; i < dh; i++ {
sBytes = src.Data[pslwPart] << sleftShift
if slwAddB {
sBytes = combinePartial(sBytes, src.Data[pslwPart+1]>>srightShift, srightMask)
}
dest.Data[pdlwPart] = combinePartial(dest.Data[pdlwPart], sBytes, dlwMask)
pdlwPart += dest.RowStride
pslwPart += src.RowStride
}
}
case PixNotSrc:
// do the first partial word
if dfwPartB {
for i = 0; i < dh; i++ {
if sfwShiftDir == shiftLeft {
sBytes = src.Data[psfwPart] << sleftShift
if sfwAddB {
sBytes = combinePartial(sBytes, src.Data[psfwPart+1]>>srightShift, srightMask)
}
} else {
sBytes = src.Data[psfwPart] >> srightShift
}
dest.Data[pdfwPart] = combinePartial(dest.Data[pdfwPart], ^sBytes, dfwMask)
pdfwPart += dest.RowStride
psfwPart += src.RowStride
}
}
// do the full words
if dfwFullB {
for i = 0; i < dh; i++ {
for j = 0; j < dnFullBytes; j++ {
sBytes = combinePartial(src.Data[psfwFull+j]<<sleftShift, src.Data[psfwFull+j+1]>>srightShift, srightMask)
dest.Data[pdfwFull+j] = ^sBytes
}
pdfwFull += dest.RowStride
psfwFull += src.RowStride
}
}
// do the last partial word
if dlwPartB {
for i = 0; i < dh; i++ {
sBytes = src.Data[pslwPart] << sleftShift
if slwAddB {
sBytes = combinePartial(sBytes, src.Data[pslwPart+1]>>srightShift, srightMask)
}
dest.Data[pdlwPart] = combinePartial(dest.Data[pdlwPart], ^sBytes, dlwMask)
pdlwPart += dest.RowStride
pslwPart += src.RowStride
}
}
case PixSrcOrDst:
// do the first partial word
if dfwPartB {
for i = 0; i < dh; i++ {
if sfwShiftDir == shiftLeft {
sBytes = src.Data[psfwPart] << sleftShift
if sfwAddB {
sBytes = combinePartial(sBytes, src.Data[psfwPart+1]>>srightShift, srightMask)
}
} else {
sBytes = src.Data[psfwPart] >> srightShift
}
dest.Data[pdfwPart] = combinePartial(dest.Data[pdfwPart], sBytes|dest.Data[pdfwPart], dfwMask)
pdfwPart += dest.RowStride
psfwPart += src.RowStride
}
}
// do the full words
if dfwFullB {
for i = 0; i < dh; i++ {
for j = 0; j < dnFullBytes; j++ {
sBytes = combinePartial(src.Data[psfwFull+j]<<sleftShift, src.Data[psfwFull+j+1]>>srightShift, srightMask)
dest.Data[pdfwFull+j] |= sBytes
}
pdfwFull += dest.RowStride
psfwFull += src.RowStride
}
}
// do the last partial word
if dlwPartB {
for i = 0; i < dh; i++ {
sBytes = src.Data[pslwPart] << sleftShift
if slwAddB {
sBytes = combinePartial(sBytes, src.Data[pslwPart+1]>>srightShift, srightMask)
}
dest.Data[pdlwPart] = combinePartial(dest.Data[pdlwPart], sBytes|dest.Data[pdlwPart], dlwMask)
pdlwPart += dest.RowStride
pslwPart += src.RowStride
}
}
case PixSrcAndDst:
// do the first partial word
if dfwPartB {
for i = 0; i < dh; i++ {
if sfwShiftDir == shiftLeft {
sBytes = src.Data[psfwPart] << sleftShift
if sfwAddB {
sBytes = combinePartial(sBytes, src.Data[psfwPart+1]>>srightShift, srightMask)
}
} else {
sBytes = src.Data[psfwPart] >> srightShift
}
dest.Data[pdfwPart] = combinePartial(dest.Data[pdfwPart], sBytes&dest.Data[pdfwPart], dfwMask)
pdfwPart += dest.RowStride
psfwPart += src.RowStride
}
}
// do the full words
if dfwFullB {
for i = 0; i < dh; i++ {
for j = 0; j < dnFullBytes; j++ {
sBytes = combinePartial(src.Data[psfwFull+j]<<sleftShift, src.Data[psfwFull+j+1]>>srightShift, srightMask)
dest.Data[pdfwFull+j] &= sBytes
}
pdfwFull += dest.RowStride
psfwFull += src.RowStride
}
}
// do the last partial word
if dlwPartB {
for i = 0; i < dh; i++ {
sBytes = src.Data[pslwPart] << sleftShift
if slwAddB {
sBytes = combinePartial(sBytes, src.Data[pslwPart+1]>>srightShift, srightMask)
}
dest.Data[pdlwPart] = combinePartial(dest.Data[pdlwPart], sBytes&dest.Data[pdlwPart], dlwMask)
pdlwPart += dest.RowStride
pslwPart += src.RowStride
}
}
case PixSrcXorDst:
// do the first partial word
if dfwPartB {
for i = 0; i < dh; i++ {
if sfwShiftDir == shiftLeft {
sBytes = src.Data[psfwPart] << sleftShift
if sfwAddB {
sBytes = combinePartial(sBytes, src.Data[psfwPart+1]>>srightShift, srightMask)
}
} else {
sBytes = src.Data[psfwPart] >> srightShift
}
dest.Data[pdfwPart] = combinePartial(dest.Data[pdfwPart], sBytes^dest.Data[pdfwPart], dfwMask)
pdfwPart += dest.RowStride
psfwPart += src.RowStride
}
}
// do the full words
if dfwFullB {
for i = 0; i < dh; i++ {
for j = 0; j < dnFullBytes; j++ {
sBytes = combinePartial(src.Data[psfwFull+j]<<sleftShift, src.Data[psfwFull+j+1]>>srightShift, srightMask)
dest.Data[pdfwFull+j] ^= sBytes
}
pdfwFull += dest.RowStride
psfwFull += src.RowStride
}
}
// do the last partial word
if dlwPartB {
for i = 0; i < dh; i++ {
sBytes = src.Data[pslwPart] << sleftShift
if slwAddB {
sBytes = combinePartial(sBytes, src.Data[pslwPart+1]>>srightShift, srightMask)
}
dest.Data[pdlwPart] = combinePartial(dest.Data[pdlwPart], sBytes^dest.Data[pdlwPart], dlwMask)
pdlwPart += dest.RowStride
pslwPart += src.RowStride
}
}
case PixNotSrcOrDst:
// do the first partial word
if dfwPartB {
for i = 0; i < dh; i++ {
if sfwShiftDir == shiftLeft {
sBytes = src.Data[psfwPart] << sleftShift
if sfwAddB {
sBytes = combinePartial(sBytes, src.Data[psfwPart+1]>>srightShift, srightMask)
}
} else {
sBytes = src.Data[psfwPart] >> srightShift
}
dest.Data[pdfwPart] = combinePartial(dest.Data[pdfwPart], ^sBytes|dest.Data[pdfwPart], dfwMask)
pdfwPart += dest.RowStride
psfwPart += src.RowStride
}
}
// do the full words
if dfwFullB {
for i = 0; i < dh; i++ {
for j = 0; j < dnFullBytes; j++ {
sBytes = combinePartial(src.Data[psfwFull+j]<<sleftShift, src.Data[psfwFull+j+1]>>srightShift, srightMask)
dest.Data[pdfwFull+j] |= ^sBytes
}
pdfwFull += dest.RowStride
psfwFull += src.RowStride
}
}
// do the last partial word
if dlwPartB {
for i = 0; i < dh; i++ {
sBytes = src.Data[pslwPart] << sleftShift
if slwAddB {
sBytes = combinePartial(sBytes, src.Data[pslwPart+1]>>srightShift, srightMask)
}
dest.Data[pdlwPart] = combinePartial(dest.Data[pdlwPart], ^sBytes|dest.Data[pdlwPart], dlwMask)
pdlwPart += dest.RowStride
pslwPart += src.RowStride
}
}
case PixNotSrcAndDst:
// do the first partial word
if dfwPartB {
for i = 0; i < dh; i++ {
if sfwShiftDir == shiftLeft {
sBytes = src.Data[psfwPart] << sleftShift
if sfwAddB {
sBytes = combinePartial(sBytes, src.Data[psfwPart+1]>>srightShift, srightMask)
}
} else {
sBytes = src.Data[psfwPart] >> srightShift
}
dest.Data[pdfwPart] = combinePartial(dest.Data[pdfwPart], ^sBytes&dest.Data[pdfwPart], dfwMask)
pdfwPart += dest.RowStride
psfwPart += src.RowStride
}
}
// do the full words
if dfwFullB {
for i = 0; i < dh; i++ {
for j = 0; j < dnFullBytes; j++ {
sBytes = combinePartial(src.Data[psfwFull+j]<<sleftShift, src.Data[psfwFull+j+1]>>srightShift, srightMask)
dest.Data[pdfwFull+j] &= ^sBytes
}
pdfwFull += dest.RowStride
psfwFull += src.RowStride
}
}
// do the last partial word
if dlwPartB {
for i = 0; i < dh; i++ {
sBytes = src.Data[pslwPart] << sleftShift
if slwAddB {
sBytes = combinePartial(sBytes, src.Data[pslwPart+1]>>srightShift, srightMask)
}
dest.Data[pdlwPart] = combinePartial(dest.Data[pdlwPart], ^sBytes&dest.Data[pdlwPart], dlwMask)
pdlwPart += dest.RowStride
pslwPart += src.RowStride
}
}
case PixSrcOrNotDst:
// do the first partial word
if dfwPartB {
for i = 0; i < dh; i++ {
if sfwShiftDir == shiftLeft {
sBytes = src.Data[psfwPart] << sleftShift
if sfwAddB {
sBytes = combinePartial(sBytes, src.Data[psfwPart+1]>>srightShift, srightMask)
}
} else {
sBytes = src.Data[psfwPart] >> srightShift
}
dest.Data[pdfwPart] = combinePartial(dest.Data[pdfwPart], sBytes|^dest.Data[pdfwPart], dfwMask)
pdfwPart += dest.RowStride
psfwPart += src.RowStride
}
}
// do the full words
if dfwFullB {
for i = 0; i < dh; i++ {
for j = 0; j < dnFullBytes; j++ {
sBytes = combinePartial(src.Data[psfwFull+j]<<sleftShift, src.Data[psfwFull+j+1]>>srightShift, srightMask)
dest.Data[pdfwFull+j] = sBytes | ^dest.Data[pdfwFull+j]
}
pdfwFull += dest.RowStride
psfwFull += src.RowStride
}
}
// do the last partial word
if dlwPartB {
for i = 0; i < dh; i++ {
sBytes = src.Data[pslwPart] << sleftShift
if slwAddB {
sBytes = combinePartial(sBytes, src.Data[pslwPart+1]>>srightShift, srightMask)
}
dest.Data[pdlwPart] = combinePartial(dest.Data[pdlwPart], sBytes|^dest.Data[pdlwPart], dlwMask)
pdlwPart += dest.RowStride
pslwPart += src.RowStride
}
}
case PixSrcAndNotDst:
// do the first partial word
if dfwPartB {
for i = 0; i < dh; i++ {
if sfwShiftDir == shiftLeft {
sBytes = src.Data[psfwPart] << sleftShift
if sfwAddB {
sBytes = combinePartial(sBytes, src.Data[psfwPart+1]>>srightShift, srightMask)
}
} else {
sBytes = src.Data[psfwPart] >> srightShift
}
dest.Data[pdfwPart] = combinePartial(dest.Data[pdfwPart], sBytes & ^dest.Data[pdfwPart], dfwMask)
pdfwPart += dest.RowStride
psfwPart += src.RowStride
}
}
// do the full words
if dfwFullB {
for i = 0; i < dh; i++ {
for j = 0; j < dnFullBytes; j++ {
sBytes = combinePartial(src.Data[psfwFull+j]<<sleftShift, src.Data[psfwFull+j+1]>>srightShift, srightMask)
dest.Data[pdfwFull+j] = sBytes & ^dest.Data[pdfwFull+j]
}
pdfwFull += dest.RowStride
psfwFull += src.RowStride
}
}
// do the last partial word
if dlwPartB {
for i = 0; i < dh; i++ {
sBytes = src.Data[pslwPart] << sleftShift
if slwAddB {
sBytes = combinePartial(sBytes, src.Data[pslwPart+1]>>srightShift, srightMask)
}
dest.Data[pdlwPart] = combinePartial(dest.Data[pdlwPart], sBytes & ^dest.Data[pdlwPart], dlwMask)
pdlwPart += dest.RowStride
pslwPart += src.RowStride
}
}
case PixNotPixSrcOrDst:
// do the first partial word
if dfwPartB {
for i = 0; i < dh; i++ {
if sfwShiftDir == shiftLeft {
sBytes = src.Data[psfwPart] << sleftShift
if sfwAddB {
sBytes = combinePartial(sBytes, src.Data[psfwPart+1]>>srightShift, srightMask)
}
} else {
sBytes = src.Data[psfwPart] >> srightShift
}
dest.Data[pdfwPart] = combinePartial(dest.Data[pdfwPart], ^(sBytes | dest.Data[pdfwPart]), dfwMask)
pdfwPart += dest.RowStride
psfwPart += src.RowStride
}
}
// do the full words
if dfwFullB {
for i = 0; i < dh; i++ {
for j = 0; j < dnFullBytes; j++ {
sBytes = combinePartial(src.Data[psfwFull+j]<<sleftShift, src.Data[psfwFull+j+1]>>srightShift, srightMask)
dest.Data[pdfwFull+j] = ^(sBytes | dest.Data[pdfwFull+j])
}
pdfwFull += dest.RowStride
psfwFull += src.RowStride
}
}
// do the last partial word
if dlwPartB {
for i = 0; i < dh; i++ {
sBytes = src.Data[pslwPart] << sleftShift
if slwAddB {
sBytes = combinePartial(sBytes, src.Data[pslwPart+1]>>srightShift, srightMask)
}
dest.Data[pdlwPart] = combinePartial(dest.Data[pdlwPart], ^(sBytes | dest.Data[pdlwPart]), dlwMask)
pdlwPart += dest.RowStride
pslwPart += src.RowStride
}
}
case PixNotPixSrcAndDst:
// do the first partial word
if dfwPartB {
for i = 0; i < dh; i++ {
if sfwShiftDir == shiftLeft {
sBytes = src.Data[psfwPart] << sleftShift
if sfwAddB {
sBytes = combinePartial(sBytes, src.Data[psfwPart+1]>>srightShift, srightMask)
}
} else {
sBytes = src.Data[psfwPart] >> srightShift
}
dest.Data[pdfwPart] = combinePartial(dest.Data[pdfwPart], ^(sBytes & dest.Data[pdfwPart]), dfwMask)
pdfwPart += dest.RowStride
psfwPart += src.RowStride
}
}
// do the full words
if dfwFullB {
for i = 0; i < dh; i++ {
for j = 0; j < dnFullBytes; j++ {
sBytes = combinePartial(src.Data[psfwFull+j]<<sleftShift, src.Data[psfwFull+j+1]>>srightShift, srightMask)
dest.Data[pdfwFull+j] = ^(sBytes & dest.Data[pdfwFull+j])
}
pdfwFull += dest.RowStride
psfwFull += src.RowStride
}
}
// do the last partial word
if dlwPartB {
for i = 0; i < dh; i++ {
sBytes = src.Data[pslwPart] << sleftShift
if slwAddB {
sBytes = combinePartial(sBytes, src.Data[pslwPart+1]>>srightShift, srightMask)
}
dest.Data[pdlwPart] = combinePartial(dest.Data[pdlwPart], ^(sBytes & dest.Data[pdlwPart]), dlwMask)
pdlwPart += dest.RowStride
pslwPart += src.RowStride
}
}
case PixNotPixSrcXorDst:
// do the first partial word
if dfwPartB {
for i = 0; i < dh; i++ {
if sfwShiftDir == shiftLeft {
sBytes = src.Data[psfwPart] << sleftShift
if sfwAddB {
sBytes = combinePartial(sBytes, src.Data[psfwPart+1]>>srightShift, srightMask)
}
} else {
sBytes = src.Data[psfwPart] >> srightShift
}
dest.Data[pdfwPart] = combinePartial(dest.Data[pdfwPart], ^(sBytes ^ dest.Data[pdfwPart]), dfwMask)
pdfwPart += dest.RowStride
psfwPart += src.RowStride
}
}
// do the full words
if dfwFullB {
for i = 0; i < dh; i++ {
for j = 0; j < dnFullBytes; j++ {
sBytes = combinePartial(src.Data[psfwFull+j]<<sleftShift, src.Data[psfwFull+j+1]>>srightShift, srightMask)
dest.Data[pdfwFull+j] = ^(sBytes ^ dest.Data[pdfwFull+j])
}
pdfwFull += dest.RowStride
psfwFull += src.RowStride
}
}
// do the last partial word
if dlwPartB {
for i = 0; i < dh; i++ {
sBytes = src.Data[pslwPart] << sleftShift
if slwAddB {
sBytes = combinePartial(sBytes, src.Data[pslwPart+1]>>srightShift, srightMask)
}
dest.Data[pdlwPart] = combinePartial(dest.Data[pdlwPart], ^(sBytes ^ dest.Data[pdlwPart]), dlwMask)
pdlwPart += dest.RowStride
pslwPart += src.RowStride
}
}
default:
common.Log.Debug("Operation: '%d' not permitted", op)
return errors.Error("rasterOpGeneralLow", "raster operation not permitted")
}
return nil
}
// rasterOpUniLow performs clipping, checks aligment and dispatches for the rasterop.
func rasterOpUniLow(dest *Bitmap, dx, dy, dw, dh int, op RasterOperator) {
// clip horizontally (dx, dw)
if dx < 0 {
dw += dx
dx = 0
}
dHangw := dx + dw - dest.Width
if dHangw > 0 {
// reduce dw
dw -= dHangw
}
// clip vertically(dy, dh)
if dy < 0 {
dh += dy
dy = 0
}
dHangh := dy + dh - dest.Height
if dHangh > 0 {
// reduce dh
dh -= dHangh
}
// if clipped entirely quit
if dw <= 0 || dh <= 0 {
return
}
if (dx & 7) == 0 {
rasterOpUniWordAlignedLow(dest, dx, dy, dw, dh, op)
} else {
rasterOpUniGeneralLow(dest, dx, dy, dw, dh, op)
}
}
// rasterOpUniWordAligneLow is called when the 'dest' bitmap is left aligned. This means dx & 7 == 0.
func rasterOpUniWordAlignedLow(dest *Bitmap, dx, dy int, dw, dh int, op RasterOperator) {
var (
// firstWordIndex is the byte index of the first byte
firstWordIndex int
// lwMask is the mask for the last partial byte
lwmask byte
i, j int
lined int
)
// fullBytesNumber is the number of Full bytes.
fullBytesNumber := dw >> 3
// lwBits is the number of ovrhang bits in last partial byte.
lwbits := dw & 7
if lwbits > 0 {
lwmask = lmaskByte[lwbits]
}
firstWordIndex = dest.RowStride*dy + (dx >> 3)
switch op {
case PixClr:
for i = 0; i < dh; i++ {
lined = firstWordIndex + i*dest.RowStride
for j = 0; j < fullBytesNumber; j++ {
dest.Data[lined] = 0x0
lined++
}
if lwbits > 0 {
dest.Data[lined] = combinePartial(dest.Data[lined], 0x0, lwmask)
}
}
case PixSet:
for i = 0; i < dh; i++ {
lined = firstWordIndex + i*dest.RowStride
for j = 0; j < fullBytesNumber; j++ {
dest.Data[lined] = 0xff
lined++
}
if lwbits > 0 {
dest.Data[lined] = combinePartial(dest.Data[lined], 0xff, lwmask)
}
}
case PixNotDst:
for i = 0; i < dh; i++ {
lined = firstWordIndex + i*dest.RowStride
for j = 0; j < fullBytesNumber; j++ {
dest.Data[lined] = ^dest.Data[lined]
lined++
}
if lwbits > 0 {
dest.Data[lined] = combinePartial(dest.Data[lined], ^dest.Data[lined], lwmask)
}
}
}
}
// rasterOpUniGeneralLow static low-level uni rasterop without byte aligment.
func rasterOpUniGeneralLow(dest *Bitmap, dx, dy int, dw, dh int, op RasterOperator) {
var (
// fbDoublyPartial boolean if first 'dest' byte is doubly partial.
fbDoublyPartial bool
// fbFull boolean if there exists a full 'dest' byte word.
fbFull bool
// fullBytesNumber is the number of full 'dest' bytes.
fullBytesNumber int
// firstFullByteIndex is an index in 'dest'.Data' of the first full byte.
firstFullByteIndex int
// lbBits last byte 'dest' bits in ovrhang.
lbBits int
// lastBytePartialIndex is an index in 'dest'.Data of the last partial byte.
lastBytePartialIndex int
// lbPartial boolean if last 'dest' byte is partial
lbPartial bool
// lbMask mask for the last partial 'dest' byte.
lbMask byte
)
// fbBits first byte 'dest' bits int ovrhang.
fbBits := 8 - (dx & 7)
// fbMask is a mask for first partial 'dest' byte.
fbMask := rmaskByte[fbBits]
// firstBytePartialIndex is an index in 'dest'.Data of the first partial byte.
firstBytePartialIndex := dest.RowStride*dy + (dx >> 3)
// is the first byte is doubly partial?
if dw < fbBits {
fbDoublyPartial = true
fbMask &= lmaskByte[8-fbBits+dw]
}
// is there a full 'dest' byte?
if !fbDoublyPartial {
fullBytesNumber = (dw - fbBits) >> 3
if fullBytesNumber != 0 {
fbFull = true
firstFullByteIndex = firstBytePartialIndex + 1
}
}
// is the last byte partial?
lbBits = (dx + dw) & 7
if !(fbDoublyPartial || lbBits == 0) {
lbPartial = true
lbMask = lmaskByte[lbBits]
lastBytePartialIndex = firstBytePartialIndex + 1 + fullBytesNumber
}
var i, j int
switch op {
case PixClr:
// do the first partial word
for i = 0; i < dh; i++ {
dest.Data[firstBytePartialIndex] = combinePartial(dest.Data[firstBytePartialIndex], 0x0, fbMask)
firstBytePartialIndex += dest.RowStride
}
// do the full words
if fbFull {
for i = 0; i < dh; i++ {
for j = 0; j < fullBytesNumber; j++ {
dest.Data[firstFullByteIndex+j] = 0x0
}
firstFullByteIndex += dest.RowStride
}
}
// last partial word
if lbPartial {
for i = 0; i < dh; i++ {
dest.Data[lastBytePartialIndex] = combinePartial(dest.Data[lastBytePartialIndex], 0x0, lbMask)
lastBytePartialIndex += dest.RowStride
}
}
case PixSet:
// do the first partial word
for i = 0; i < dh; i++ {
dest.Data[firstBytePartialIndex] = combinePartial(dest.Data[firstBytePartialIndex], 0xff, fbMask)
firstBytePartialIndex += dest.RowStride
}
// do the full words
if fbFull {
for i = 0; i < dh; i++ {
for j = 0; j < fullBytesNumber; j++ {
dest.Data[firstFullByteIndex+j] = 0xff
}
firstFullByteIndex += dest.RowStride
}
}
// last partial word
if lbPartial {
for i = 0; i < dh; i++ {
dest.Data[lastBytePartialIndex] = combinePartial(dest.Data[lastBytePartialIndex], 0xff, lbMask)
lastBytePartialIndex += dest.RowStride
}
}
case PixNotDst:
// do the first partial word
for i = 0; i < dh; i++ {
dest.Data[firstBytePartialIndex] = combinePartial(dest.Data[firstBytePartialIndex], ^dest.Data[firstBytePartialIndex], fbMask)
firstBytePartialIndex += dest.RowStride
}
// do the full words
if fbFull {
for i = 0; i < dh; i++ {
for j = 0; j < fullBytesNumber; j++ {
dest.Data[firstFullByteIndex+j] = ^(dest.Data[firstFullByteIndex+j])
}
firstFullByteIndex += dest.RowStride
}
}
// last partial word
if lbPartial {
for i = 0; i < dh; i++ {
dest.Data[lastBytePartialIndex] = combinePartial(dest.Data[lastBytePartialIndex], ^dest.Data[lastBytePartialIndex], lbMask)
lastBytePartialIndex += dest.RowStride
}
}
}
}
var (
lmaskByte = []byte{
// 00000000
0x00,
// 10000000
0x80,
// 11000000
0xC0,
// 11100000
0xE0,
// 11110000
0xF0,
// 11111000
0xF8,
// 11111100
0xFC,
// 11111110
0xFE,
// 11111111
0xFF,
}
rmaskByte = []byte{
// 00000000
0x00,
// 00000001
0x01,
// 00000011
0x03,
// 00000111
0x07,
// 00001111
0x0F,
// 00011111
0x1F,
// 00111111
0x3F,
// 01111111
0x7F,
// 11111111
0xFF,
}
)
func combinePartial(d, s, m byte) byte {
return (d & ^(m)) | (s & m)
}
type shift int
const (
shiftLeft shift = iota
shiftRight
)