|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.java2d.pipe; |
|
|
|
import java.awt.color.ColorSpace; |
|
import java.awt.image.AffineTransformOp; |
|
import java.awt.image.BufferedImage; |
|
import java.awt.image.BufferedImageOp; |
|
import java.awt.image.BufferedImageOp; |
|
import java.awt.image.ByteLookupTable; |
|
import java.awt.image.ColorModel; |
|
import java.awt.image.ConvolveOp; |
|
import java.awt.image.IndexColorModel; |
|
import java.awt.image.Kernel; |
|
import java.awt.image.LookupOp; |
|
import java.awt.image.LookupTable; |
|
import java.awt.image.RescaleOp; |
|
import java.awt.image.ShortLookupTable; |
|
import sun.java2d.SurfaceData; |
|
import sun.java2d.loops.CompositeType; |
|
import static sun.java2d.pipe.BufferedOpCodes.*; |
|
|
|
public class BufferedBufImgOps { |
|
|
|
public static void enableBufImgOp(RenderQueue rq, SurfaceData srcData, |
|
BufferedImage srcImg, |
|
BufferedImageOp biop) |
|
{ |
|
if (biop instanceof ConvolveOp) { |
|
enableConvolveOp(rq, srcData, (ConvolveOp)biop); |
|
} else if (biop instanceof RescaleOp) { |
|
enableRescaleOp(rq, srcData, srcImg, (RescaleOp)biop); |
|
} else if (biop instanceof LookupOp) { |
|
enableLookupOp(rq, srcData, srcImg, (LookupOp)biop); |
|
} else { |
|
throw new InternalError("Unknown BufferedImageOp"); |
|
} |
|
} |
|
|
|
public static void disableBufImgOp(RenderQueue rq, BufferedImageOp biop) { |
|
if (biop instanceof ConvolveOp) { |
|
disableConvolveOp(rq); |
|
} else if (biop instanceof RescaleOp) { |
|
disableRescaleOp(rq); |
|
} else if (biop instanceof LookupOp) { |
|
disableLookupOp(rq); |
|
} else { |
|
throw new InternalError("Unknown BufferedImageOp"); |
|
} |
|
} |
|
|
|
/**************************** ConvolveOp support ****************************/ |
|
|
|
public static boolean isConvolveOpValid(ConvolveOp cop) { |
|
Kernel kernel = cop.getKernel(); |
|
int kw = kernel.getWidth(); |
|
int kh = kernel.getHeight(); |
|
// REMIND: we currently can only handle 3x3 and 5x5 kernels, |
|
// but hopefully this is just a temporary restriction; |
|
|
|
if (!(kw == 3 && kh == 3) && !(kw == 5 && kh == 5)) { |
|
return false; |
|
} |
|
return true; |
|
} |
|
|
|
private static void enableConvolveOp(RenderQueue rq, |
|
SurfaceData srcData, |
|
ConvolveOp cop) |
|
{ |
|
|
|
boolean edgeZero = |
|
cop.getEdgeCondition() == ConvolveOp.EDGE_ZERO_FILL; |
|
Kernel kernel = cop.getKernel(); |
|
int kernelWidth = kernel.getWidth(); |
|
int kernelHeight = kernel.getHeight(); |
|
int kernelSize = kernelWidth * kernelHeight; |
|
int sizeofFloat = 4; |
|
int totalBytesRequired = 4 + 8 + 12 + (kernelSize * sizeofFloat); |
|
|
|
RenderBuffer buf = rq.getBuffer(); |
|
rq.ensureCapacityAndAlignment(totalBytesRequired, 4); |
|
buf.putInt(ENABLE_CONVOLVE_OP); |
|
buf.putLong(srcData.getNativeOps()); |
|
buf.putInt(edgeZero ? 1 : 0); |
|
buf.putInt(kernelWidth); |
|
buf.putInt(kernelHeight); |
|
buf.put(kernel.getKernelData(null)); |
|
} |
|
|
|
private static void disableConvolveOp(RenderQueue rq) { |
|
|
|
RenderBuffer buf = rq.getBuffer(); |
|
rq.ensureCapacity(4); |
|
buf.putInt(DISABLE_CONVOLVE_OP); |
|
} |
|
|
|
/**************************** RescaleOp support *****************************/ |
|
|
|
public static boolean isRescaleOpValid(RescaleOp rop, |
|
BufferedImage srcImg) |
|
{ |
|
int numFactors = rop.getNumFactors(); |
|
ColorModel srcCM = srcImg.getColorModel(); |
|
|
|
if (srcCM instanceof IndexColorModel) { |
|
throw new |
|
IllegalArgumentException("Rescaling cannot be "+ |
|
"performed on an indexed image"); |
|
} |
|
if (numFactors != 1 && |
|
numFactors != srcCM.getNumColorComponents() && |
|
numFactors != srcCM.getNumComponents()) |
|
{ |
|
throw new IllegalArgumentException("Number of scaling constants "+ |
|
"does not equal the number of"+ |
|
" of color or color/alpha "+ |
|
" components"); |
|
} |
|
|
|
int csType = srcCM.getColorSpace().getType(); |
|
if (csType != ColorSpace.TYPE_RGB && |
|
csType != ColorSpace.TYPE_GRAY) |
|
{ |
|
|
|
return false; |
|
} |
|
|
|
if (numFactors == 2 || numFactors > 4) { |
|
|
|
return false; |
|
} |
|
|
|
return true; |
|
} |
|
|
|
private static void enableRescaleOp(RenderQueue rq, |
|
SurfaceData srcData, |
|
BufferedImage srcImg, |
|
RescaleOp rop) |
|
{ |
|
|
|
ColorModel srcCM = srcImg.getColorModel(); |
|
boolean nonPremult = |
|
srcCM.hasAlpha() && |
|
srcCM.isAlphaPremultiplied(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
int numFactors = rop.getNumFactors(); |
|
float[] origScaleFactors = rop.getScaleFactors(null); |
|
float[] origOffsets = rop.getOffsets(null); |
|
|
|
// To make things easier, we will always pass all four bands |
|
|
|
float[] normScaleFactors; |
|
float[] normOffsets; |
|
|
|
if (numFactors == 1) { |
|
normScaleFactors = new float[4]; |
|
normOffsets = new float[4]; |
|
for (int i = 0; i < 3; i++) { |
|
normScaleFactors[i] = origScaleFactors[0]; |
|
normOffsets[i] = origOffsets[0]; |
|
} |
|
|
|
normScaleFactors[3] = 1.0f; |
|
normOffsets[3] = 0.0f; |
|
} else if (numFactors == 3) { |
|
normScaleFactors = new float[4]; |
|
normOffsets = new float[4]; |
|
for (int i = 0; i < 3; i++) { |
|
normScaleFactors[i] = origScaleFactors[i]; |
|
normOffsets[i] = origOffsets[i]; |
|
} |
|
|
|
normScaleFactors[3] = 1.0f; |
|
normOffsets[3] = 0.0f; |
|
} else { |
|
normScaleFactors = origScaleFactors; |
|
normOffsets = origOffsets; |
|
} |
|
|
|
// The user-provided offsets are specified in the range |
|
// of each source color band, but the OpenGL shader only wants |
|
// to deal with data in the range [0,1], so we need to normalize |
|
|
|
if (srcCM.getNumComponents() == 1) { |
|
|
|
int nBits = srcCM.getComponentSize(0); |
|
int maxValue = (1 << nBits) - 1; |
|
for (int i = 0; i < 3; i++) { |
|
normOffsets[i] /= maxValue; |
|
} |
|
} else { |
|
|
|
for (int i = 0; i < srcCM.getNumComponents(); i++) { |
|
int nBits = srcCM.getComponentSize(i); |
|
int maxValue = (1 << nBits) - 1; |
|
normOffsets[i] /= maxValue; |
|
} |
|
} |
|
|
|
int sizeofFloat = 4; |
|
int totalBytesRequired = 4 + 8 + 4 + (4 * sizeofFloat * 2); |
|
|
|
RenderBuffer buf = rq.getBuffer(); |
|
rq.ensureCapacityAndAlignment(totalBytesRequired, 4); |
|
buf.putInt(ENABLE_RESCALE_OP); |
|
buf.putLong(srcData.getNativeOps()); |
|
buf.putInt(nonPremult ? 1 : 0); |
|
buf.put(normScaleFactors); |
|
buf.put(normOffsets); |
|
} |
|
|
|
private static void disableRescaleOp(RenderQueue rq) { |
|
|
|
RenderBuffer buf = rq.getBuffer(); |
|
rq.ensureCapacity(4); |
|
buf.putInt(DISABLE_RESCALE_OP); |
|
} |
|
|
|
/**************************** LookupOp support ******************************/ |
|
|
|
public static boolean isLookupOpValid(LookupOp lop, |
|
BufferedImage srcImg) |
|
{ |
|
LookupTable table = lop.getTable(); |
|
int numComps = table.getNumComponents(); |
|
ColorModel srcCM = srcImg.getColorModel(); |
|
|
|
if (srcCM instanceof IndexColorModel) { |
|
throw new |
|
IllegalArgumentException("LookupOp cannot be "+ |
|
"performed on an indexed image"); |
|
} |
|
if (numComps != 1 && |
|
numComps != srcCM.getNumComponents() && |
|
numComps != srcCM.getNumColorComponents()) |
|
{ |
|
throw new IllegalArgumentException("Number of arrays in the "+ |
|
" lookup table ("+ |
|
numComps+ |
|
") is not compatible with"+ |
|
" the src image: "+srcImg); |
|
} |
|
|
|
int csType = srcCM.getColorSpace().getType(); |
|
if (csType != ColorSpace.TYPE_RGB && |
|
csType != ColorSpace.TYPE_GRAY) |
|
{ |
|
|
|
return false; |
|
} |
|
|
|
if (numComps == 2 || numComps > 4) { |
|
|
|
return false; |
|
} |
|
|
|
// The LookupTable spec says that "all arrays must be the |
|
// same size" but unfortunately the constructors do not |
|
// enforce that. Also, our native code only works with |
|
// arrays no larger than 256 elements, so check both of |
|
|
|
if (table instanceof ByteLookupTable) { |
|
byte[][] data = ((ByteLookupTable)table).getTable(); |
|
for (int i = 1; i < data.length; i++) { |
|
if (data[i].length > 256 || |
|
data[i].length != data[i-1].length) |
|
{ |
|
return false; |
|
} |
|
} |
|
} else if (table instanceof ShortLookupTable) { |
|
short[][] data = ((ShortLookupTable)table).getTable(); |
|
for (int i = 1; i < data.length; i++) { |
|
if (data[i].length > 256 || |
|
data[i].length != data[i-1].length) |
|
{ |
|
return false; |
|
} |
|
} |
|
} else { |
|
return false; |
|
} |
|
|
|
return true; |
|
} |
|
|
|
private static void enableLookupOp(RenderQueue rq, |
|
SurfaceData srcData, |
|
BufferedImage srcImg, |
|
LookupOp lop) |
|
{ |
|
|
|
boolean nonPremult = |
|
srcImg.getColorModel().hasAlpha() && |
|
srcImg.isAlphaPremultiplied(); |
|
|
|
LookupTable table = lop.getTable(); |
|
int numBands = table.getNumComponents(); |
|
int offset = table.getOffset(); |
|
int bandLength; |
|
int bytesPerElem; |
|
boolean shortData; |
|
|
|
if (table instanceof ShortLookupTable) { |
|
short[][] data = ((ShortLookupTable)table).getTable(); |
|
bandLength = data[0].length; |
|
bytesPerElem = 2; |
|
shortData = true; |
|
} else { |
|
byte[][] data = ((ByteLookupTable)table).getTable(); |
|
bandLength = data[0].length; |
|
bytesPerElem = 1; |
|
shortData = false; |
|
} |
|
|
|
|
|
int totalLutBytes = numBands * bandLength * bytesPerElem; |
|
int paddedLutBytes = (totalLutBytes + 3) & (~3); |
|
int padding = paddedLutBytes - totalLutBytes; |
|
int totalBytesRequired = 4 + 8 + 20 + paddedLutBytes; |
|
|
|
RenderBuffer buf = rq.getBuffer(); |
|
rq.ensureCapacityAndAlignment(totalBytesRequired, 4); |
|
buf.putInt(ENABLE_LOOKUP_OP); |
|
buf.putLong(srcData.getNativeOps()); |
|
buf.putInt(nonPremult ? 1 : 0); |
|
buf.putInt(shortData ? 1 : 0); |
|
buf.putInt(numBands); |
|
buf.putInt(bandLength); |
|
buf.putInt(offset); |
|
if (shortData) { |
|
short[][] data = ((ShortLookupTable)table).getTable(); |
|
for (int i = 0; i < numBands; i++) { |
|
buf.put(data[i]); |
|
} |
|
} else { |
|
byte[][] data = ((ByteLookupTable)table).getTable(); |
|
for (int i = 0; i < numBands; i++) { |
|
buf.put(data[i]); |
|
} |
|
} |
|
if (padding != 0) { |
|
buf.position(buf.position() + padding); |
|
} |
|
} |
|
|
|
private static void disableLookupOp(RenderQueue rq) { |
|
|
|
RenderBuffer buf = rq.getBuffer(); |
|
rq.ensureCapacity(4); |
|
buf.putInt(DISABLE_LOOKUP_OP); |
|
} |
|
} |