package org.icepdf.core.pobjects.graphics.RasterOps;
import java.awt.*;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.DataBufferByte;
import java.awt.image.Raster;
import java.awt.image.RasterOp;
import java.awt.image.WritableRaster;
/**
* Applies the decode value array tot he specified raster. The decode array
* is specific to PDF and describes how to map image samples into the range of
* values appropriate for the image’s colour space.
* <br>
* This Raster Operation should be applied to any image type before colour
* conversion takes place.
*
* @since 5.1
*/
public class DecodeRasterOp implements RasterOp {
private static final float NORMAL_DECODE_CEIL = 1.0f / 255;
private RenderingHints hints = null;
private float[] decode;
public DecodeRasterOp(float[] decode, RenderingHints hints) {
this.hints = hints;
this.decode = decode;
}
/**
* Simple test to see if the decode is none standard where standard is
* [0,1,0,1,0,1].
*
* @param decode decode array to check
* @return true if the decode is not normal, otherwise false.
*/
private static boolean isNormalDecode(float[] decode) {
// normal decode is always [0,1,0,1....]
for (int i = 0, max = decode.length; i < max; i += 2) {
if (decode[i] != 0.0f || decode[i + 1] != NORMAL_DECODE_CEIL) {
return false;
}
}
return true;
}
public WritableRaster filter(Raster src, WritableRaster dest) {
// check if we have none 0-1 decode, if so continue if not return
if (isNormalDecode(decode)) {
return (WritableRaster) src;
}
if (dest == null) dest = src.createCompatibleWritableRaster();
// may have to add some instance of checks
byte[] srcPixels = ((DataBufferByte) src.getDataBuffer()).getData();
byte[] destPixels = ((DataBufferByte) dest.getDataBuffer()).getData();
int bands = src.getNumBands();
for (int pixel = 0; pixel < srcPixels.length; pixel += bands) {
// apply decode param.
for (int i = 0; i < bands; i++) {
destPixels[pixel + i] = normalizeComponents(srcPixels[pixel + i], decode, i);
}
}
return dest;
}
public Rectangle2D getBounds2D(Raster src) {
return null;
}
public WritableRaster createCompatibleDestRaster(Raster src) {
return src.createCompatibleWritableRaster();
}
public Point2D getPoint2D(Point2D srcPt, Point2D dstPt) {
if (dstPt == null)
dstPt = (Point2D) srcPt.clone();
else
dstPt.setLocation(srcPt);
return dstPt;
}
public RenderingHints getRenderingHints() {
return hints;
}
/**
* Apply the Decode Array domain for each colour component. Assumes output
* range is 0-255 for each value in out.
*
* @param pixels colour to process by decode
* @param decode decode array for colour space
* @return decoded value..
*/
private static byte normalizeComponents(
byte pixels,
float[] decode,
int i) {
// interpolate each colour component for the given decode domain.
return (byte) ((decode[i * 2] * 255) + (pixels & 0xff) * (decode[(i * 2) + 1] * 255));
}
}