blob: 7a200e48904adc5da4c28c9a4c9b6c76b563bd30 [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);
}