blob: 19f35658a108c339e957658044b750a7774ce433 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.pdfbox.jbig2.image;
import java.awt.image.MultiPixelPackedSampleModel;
import java.awt.image.Raster;
import java.awt.image.SampleModel;
import java.awt.image.SinglePixelPackedSampleModel;
import java.awt.image.WritableRaster;
abstract class Scanline {
public interface ScanlineFilter {
public void filter(int x, int y, int componentIndex, Object data, int length);
}
/**
* A Scanline for pixel interleaved byte data with three components. Although its name contains
* "BGR" it doesn't really matter how the components are organized, als long as there are three of
* them.
*/
protected static final class ByteBGRScanline extends Scanline {
private final Raster srcRaster;
private final WritableRaster dstRaster;
private final int data[];
protected ByteBGRScanline(Raster src, WritableRaster dst, final int length) {
super(length);
srcRaster = src;
dstRaster = dst;
data = new int[3 * length];
}
@Override
protected void accumulate(final int weight, final Scanline dst) {
final ByteBGRScanline bcs = (ByteBGRScanline) dst;
final int abuf[] = data;
final int bbuf[] = bcs.data;
for (int b = 0; b < bbuf.length; b++)
bbuf[b] += weight * abuf[b];
}
@Override
protected void clear() {
final int[] b = data;
for (int j = 0; j < b.length; j++)
b[j] = 0;
}
@Override
protected void fetch(final int x, final int y) {
srcRaster.getPixels(x, y, length, 1, data);
}
@Override
protected void filter(final int[] preShift, final int[] postShift, final Weighttab[] tabs, final Scanline dst) {
final ByteBGRScanline bcs = (ByteBGRScanline) dst;
final int nx = dst.length;
// start sum at 1<<shift-1 for rounding
final int start[] = new int[]{
1 << postShift[0] - 1, 1 << postShift[1] - 1, 1 << postShift[2] - 1
};
final int abuf[] = data;
final int bbuf[] = bcs.data;
// the next two blocks are duplicated except for the missing shift
// operation if preShift==0.
if (preShift[0] != 0 || preShift[1] != 0 || preShift[2] != 0)
for (int bp = 0, b = 0; b < nx; b++) {
final Weighttab wtab = tabs[b];
final int an = wtab.weights.length;
int sumr = start[0];
int sumg = start[1];
int sumb = start[2];
for (int wp = 0, ap = wtab.i0 * 3; wp < an && ap < abuf.length; wp++) {
final int w = wtab.weights[wp];
sumr += w * (abuf[ap++] >> preShift[0]);
sumg += w * (abuf[ap++] >> preShift[1]);
sumb += w * (abuf[ap++] >> preShift[2]);
}
int t = sumr >> postShift[0];
bbuf[bp++] = t < 0 ? 0 : t > 255 ? 255 : t;
t = sumg >> postShift[1];
bbuf[bp++] = t < 0 ? 0 : t > 255 ? 255 : t;
t = sumb >> postShift[2];
bbuf[bp++] = t < 0 ? 0 : t > 255 ? 255 : t;
}
else
for (int bp = 0, b = 0; b < nx; b++) {
final Weighttab wtab = tabs[b];
final int an = wtab.weights.length;
int sumr = start[0];
int sumg = start[1];
int sumb = start[2];
for (int wp = 0, ap = wtab.i0 * 3; wp < an && ap < abuf.length; wp++) {
final int w = wtab.weights[wp];
sumr += w * abuf[ap++];
sumg += w * abuf[ap++];
sumb += w * abuf[ap++];
}
bbuf[bp++] = sumr >> postShift[0];
bbuf[bp++] = sumg >> postShift[1];
bbuf[bp++] = sumb >> postShift[2];
}
}
@Override
protected void shift(final int[] shift) {
final int half[] = new int[]{
1 << shift[0] - 1, 1 << shift[1] - 1, 1 << shift[2] - 1
};
final int abuf[] = data;
for (int b = 0; b < abuf.length;) {
for (int c = 0; c < 3; c++, b++) {
final int t = abuf[b] + half[c] >> shift[c];
abuf[b] = t < 0 ? 0 : t > 255 ? 255 : t;
}
}
}
@Override
protected void store(final int x, final int y) {
dstRaster.setPixels(x, y, length, 1, data);
}
}
/**
* A Scanline for packed integer pixels.
*/
protected static final class IntegerSinglePixelPackedScanline extends Scanline {
private final Raster srcRaster;
private final WritableRaster dstRaster;
private final int data[];
private final int[] bitMasks;
private final int[] bitOffsets;
private final int componentCount;
private final SinglePixelPackedSampleModel srcSM;
private final int tmp[];
protected IntegerSinglePixelPackedScanline(Raster src, WritableRaster dst, final int length) {
super(length);
srcRaster = src;
dstRaster = dst;
srcSM = (SinglePixelPackedSampleModel) srcRaster.getSampleModel();
bitMasks = srcSM.getBitMasks();
bitOffsets = srcSM.getBitOffsets();
componentCount = bitMasks.length;
if (componentCount != bitOffsets.length || bitOffsets.length != srcSM.getNumBands())
throw new IllegalArgumentException("weird: getBitMasks().length != getBitOffsets().length");
tmp = new int[componentCount];
data = new int[componentCount * length];
}
@Override
protected void accumulate(final int weight, final Scanline dst) {
final IntegerSinglePixelPackedScanline ispps = (IntegerSinglePixelPackedScanline) dst;
final int abuf[] = data;
final int bbuf[] = ispps.data;
for (int b = 0; b < bbuf.length; b++)
bbuf[b] += weight * abuf[b];
}
@Override
protected void clear() {
final int[] b = data;
for (int j = 0; j < b.length; j++)
b[j] = 0;
}
@Override
protected void fetch(final int x, final int y) {
srcRaster.getPixels(x, y, length, 1, data);
}
@Override
protected void filter(final int[] preShift, final int[] postShift, final Weighttab[] tabs, final Scanline dst) {
final IntegerSinglePixelPackedScanline ispps = (IntegerSinglePixelPackedScanline) dst;
final int nx = dst.length;
// start sum at 1<<shift-1 for rounding
final int start[] = tmp;
for (int c = 0; c < componentCount; c++)
start[c] = 1 << postShift[c] - 1;
final int abuf[] = data;
final int bbuf[] = ispps.data;
// the next two blocks are duplicated except for the missing shift
// operation if preShift==0.
boolean hasPreShift = false;
for (int c = 0; c < componentCount && !hasPreShift; c++)
hasPreShift |= preShift[c] != 0;
if (hasPreShift)
for (int bp = 0, b = 0; b < nx; b++) {
final Weighttab wtab = tabs[b];
final int an = wtab.weights.length;
for (int c = 0; c < componentCount; c++) {
int sum = start[c];
for (int wp = 0, ap = wtab.i0 * componentCount + c; wp < an && ap < abuf.length; wp++, ap += componentCount)
sum += wtab.weights[wp] * (abuf[ap] >> preShift[c]);
final int t = sum >> postShift[c];
bbuf[bp++] = t < 0 ? 0 : t > 255 ? 255 : t;
}
}
else
for (int bp = 0, b = 0; b < nx; b++) {
final Weighttab wtab = tabs[b];
final int an = wtab.weights.length;
for (int c = 0; c < componentCount; c++) {
int sum = start[c];
for (int wp = 0, ap = wtab.i0 * componentCount + c; wp < an && ap < abuf.length; wp++, ap += componentCount)
sum += wtab.weights[wp] * abuf[ap];
bbuf[bp++] = sum >> postShift[c];
}
}
}
@Override
protected void shift(final int[] shift) {
final int half[] = tmp;
for (int c = 0; c < componentCount; c++)
half[c] = 1 << shift[c] - 1;
final int abuf[] = data;
for (int b = 0; b < abuf.length;) {
for (int c = 0; c < componentCount; c++, b++) {
final int t = abuf[b] + half[c] >> shift[c];
abuf[b] = t < 0 ? 0 : t > 255 ? 255 : t;
}
}
}
@Override
protected void store(final int x, final int y) {
dstRaster.setPixels(x, y, length, 1, data);
}
}
/**
* A Scanline for packed integer pixels.
*/
protected static final class GenericRasterScanline extends Scanline {
private final Raster srcRaster;
private final WritableRaster dstRaster;
private final int componentCount;
private final int data[][];
private final SampleModel srcSM;
private final SampleModel dstSM;
private final int channelMask[];
private final int[] tmp;
private final ScanlineFilter inputFilter;
protected GenericRasterScanline(Raster src, WritableRaster dst, final int length, int bitsPerChannel[],
ScanlineFilter inputFilter) {
super(length);
srcRaster = src;
dstRaster = dst;
this.inputFilter = inputFilter;
srcSM = srcRaster.getSampleModel();
dstSM = dstRaster.getSampleModel();
componentCount = srcSM.getNumBands();
if (componentCount != dstSM.getNumBands())
throw new IllegalArgumentException("weird: src raster num bands != dst raster num bands");
tmp = new int[componentCount];
data = new int[componentCount][];
for (int i = 0; i < data.length; i++)
data[i] = new int[length];
channelMask = new int[componentCount];
for (int c = 0; c < componentCount; c++)
channelMask[c] = (1 << bitsPerChannel[c]) - 1;
}
@Override
protected void accumulate(final int weight, final Scanline dst) {
final GenericRasterScanline grs = (GenericRasterScanline) dst;
final int l = grs.data[0].length;
for (int c = 0; c < componentCount; c++) {
final int ac[] = data[c];
final int bc[] = grs.data[c];
for (int b = 0; b < l; b++)
bc[b] += weight * ac[b];
}
}
@Override
protected void clear() {
for (int c = 0; c < componentCount; c++) {
final int[] b = data[c];
for (int x = 0; x < b.length; x++)
b[x] = 0;
}
}
@Override
protected void fetch(final int x, final int y) {
for (int c = 0; c < componentCount; c++) {
srcRaster.getSamples(x, y, length, 1, c, data[c]);
if (null != inputFilter)
inputFilter.filter(x, y, c, data[c], length);
}
}
@Override
protected void filter(final int[] preShift, final int[] postShift, final Weighttab[] tabs, final Scanline dst) {
final GenericRasterScanline grs = (GenericRasterScanline) dst;
final int nx = dst.length;
// start sum at 1<<shift-1 for rounding
final int start[] = tmp;
for (int c = 0; c < componentCount; c++)
start[c] = 1 << postShift[c] - 1;
final int l = data[0].length;
// the next two blocks are duplicated except for the missing shift
// operation if preShift==0.
boolean hasPreShift = false;
for (int c = 0; c < componentCount && !hasPreShift; c++)
hasPreShift |= preShift[c] != 0;
if (hasPreShift)
for (int c = 0; c < componentCount; c++) {
final int ac[] = data[c];
final int bc[] = grs.data[c];
final int m = channelMask[c];
for (int b = 0; b < nx; b++) {
final Weighttab wtab = tabs[b];
final int an = wtab.weights.length;
int sum = start[c];
for (int wp = 0, ap = wtab.i0; wp < an && ap < l; wp++, ap++)
sum += wtab.weights[wp] * (ac[ap] >> preShift[c]);
final int t = sum >> postShift[c];
bc[b] = t < 0 ? 0 : t > m ? m : t;
}
}
else
for (int c = 0; c < componentCount; c++) {
final int ac[] = data[c];
final int bc[] = grs.data[c];
for (int b = 0; b < nx; b++) {
final Weighttab wtab = tabs[b];
final int an = wtab.weights.length;
int sum = start[c];
for (int wp = 0, ap = wtab.i0; wp < an && ap < l; wp++, ap++)
sum += wtab.weights[wp] * ac[ap];
bc[b] = sum >> postShift[c];
}
}
}
@Override
protected void shift(final int[] shift) {
final int half[] = tmp;
for (int c = 0; c < componentCount; c++)
half[c] = 1 << shift[c] - 1;
final int abuf[][] = data;
final int l = abuf[0].length;
for (int c = 0; c < componentCount; c++) {
final int ac[] = data[c];
final int m = channelMask[c];
for (int a = 0; a < l; a++) {
final int t = ac[a] + half[c] >> shift[c];
ac[a] = t < 0 ? 0 : t > m ? m : t;
}
}
}
@Override
protected void store(final int x, final int y) {
final int nx = length;
for (int c = 0; c < componentCount; c++)
dstRaster.setSamples(x, y, nx, 1, c, data[c]);
}
}
/**
* A Scanline for BiLevel input data ({@link MultiPixelPackedSampleModel}) to indexed output data
* (<code>sun.awt.image.ByteInterleavedRaster</code>).
*/
protected static final class ByteBiLevelPackedScanline extends Scanline {
private final Raster srcRaster;
private final WritableRaster dstRaster;
private final int data[];
protected ByteBiLevelPackedScanline(Raster src, WritableRaster dst, final int length) {
super(length);
srcRaster = src;
dstRaster = dst;
data = new int[length];
}
@Override
protected void accumulate(final int weight, final Scanline dst) {
final ByteBiLevelPackedScanline bblps = (ByteBiLevelPackedScanline) dst;
final int abuf[] = data;
final int bbuf[] = bblps.data;
for (int b = 0; b < bbuf.length; b++)
bbuf[b] += weight * abuf[b];
}
@Override
protected void clear() {
final int[] b = data;
for (int j = 0; j < b.length; j++)
b[j] = 0;
}
@Override
protected void fetch(final int x, final int y) {
srcRaster.getPixels(x, y, length, 1, data);
for (int i = 0; i < length; i++)
if (data[i] != 0)
data[i] = 255;
}
@Override
protected void filter(final int[] preShift, final int[] postShift, final Weighttab[] tabs, final Scanline dst) {
final ByteBiLevelPackedScanline bblps = (ByteBiLevelPackedScanline) dst;
final int nx = dst.length;
// start sum at 1<<shift-1 for rounding
final int start = 1 << postShift[0] - 1;
final int abuf[] = data;
final int bbuf[] = bblps.data;
// the next two blocks are duplicated except for the missing shift
// operation if preShift==0.
final int preShift0 = preShift[0];
final int postShift0 = postShift[0];
if (preShift0 != 0)
for (int bp = 0, b = 0; b < nx; b++) {
final Weighttab wtab = tabs[b];
final int an = wtab.weights.length;
int sum = start;
for (int wp = 0, ap = wtab.i0; wp < an && ap < abuf.length; wp++) {
sum += wtab.weights[wp] * (abuf[ap++] >> preShift0);
}
final int t = sum >> postShift0;
bbuf[bp++] = t < 0 ? 0 : t > 255 ? 255 : t;
}
else
for (int bp = 0, b = 0; b < nx; b++) {
final Weighttab wtab = tabs[b];
final int an = wtab.weights.length;
int sum = start;
for (int wp = 0, ap = wtab.i0; wp < an && ap < abuf.length; wp++) {
sum += wtab.weights[wp] * abuf[ap++];
}
bbuf[bp++] = sum >> postShift0;
}
}
@Override
protected void shift(final int[] shift) {
final int shift0 = shift[0];
final int half = 1 << shift0 - 1;
final int abuf[] = data;
for (int b = 0; b < abuf.length; b++) {
final int t = abuf[b] + half >> shift0;
abuf[b] = t < 0 ? 0 : t > 255 ? 255 : t;
}
}
@Override
protected void store(final int x, final int y) {
dstRaster.setPixels(x, y, length, 1, data);
}
}
int y;
protected final int length;
protected Scanline(final int width) {
length = width;
}
protected final int getWidth() {
return length;
}
protected abstract void clear();
protected abstract void fetch(int x, int y);
protected abstract void filter(int[] preShift, int[] postShift, Weighttab[] xweights, Scanline dst);
protected abstract void accumulate(int weight, Scanline dst);
protected abstract void shift(int[] finalshift);
protected abstract void store(int x, int y);
}