|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
/* |
|
********************************************************************** |
|
********************************************************************** |
|
********************************************************************** |
|
*** COPYRIGHT (c) Eastman Kodak Company, 1997 *** |
|
*** As an unpublished work pursuant to Title 17 of the United *** |
|
*** States Code. All rights reserved. *** |
|
********************************************************************** |
|
********************************************************************** |
|
**********************************************************************/ |
|
|
|
package java.awt.image; |
|
|
|
import java.awt.Point; |
|
import java.awt.Graphics2D; |
|
import java.awt.color.*; |
|
import sun.java2d.cmm.ColorTransform; |
|
import sun.java2d.cmm.CMSManager; |
|
import sun.java2d.cmm.ProfileDeferralMgr; |
|
import sun.java2d.cmm.PCMM; |
|
import java.awt.geom.Rectangle2D; |
|
import java.awt.geom.Point2D; |
|
import java.awt.RenderingHints; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public class ColorConvertOp implements BufferedImageOp, RasterOp { |
|
ICC_Profile[] profileList; |
|
ColorSpace[] CSList; |
|
ColorTransform thisTransform, thisRasterTransform; |
|
ICC_Profile thisSrcProfile, thisDestProfile; |
|
RenderingHints hints; |
|
boolean gotProfiles; |
|
float[] srcMinVals, srcMaxVals, dstMinVals, dstMaxVals; |
|
|
|
|
|
static { |
|
if (ProfileDeferralMgr.deferring) { |
|
ProfileDeferralMgr.activateProfiles(); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public ColorConvertOp (RenderingHints hints) |
|
{ |
|
profileList = new ICC_Profile [0]; |
|
this.hints = hints; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public ColorConvertOp (ColorSpace cspace, RenderingHints hints) |
|
{ |
|
if (cspace == null) { |
|
throw new NullPointerException("ColorSpace cannot be null"); |
|
} |
|
if (cspace instanceof ICC_ColorSpace) { |
|
profileList = new ICC_Profile [1]; /* 1 profile in the list */ |
|
|
|
profileList [0] = ((ICC_ColorSpace) cspace).getProfile(); |
|
} |
|
else { |
|
CSList = new ColorSpace[1]; |
|
CSList[0] = cspace; |
|
} |
|
this.hints = hints; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public ColorConvertOp(ColorSpace srcCspace, ColorSpace dstCspace, |
|
RenderingHints hints) |
|
{ |
|
if ((srcCspace == null) || (dstCspace == null)) { |
|
throw new NullPointerException("ColorSpaces cannot be null"); |
|
} |
|
if ((srcCspace instanceof ICC_ColorSpace) && |
|
(dstCspace instanceof ICC_ColorSpace)) { |
|
profileList = new ICC_Profile [2]; /* 2 profiles in the list */ |
|
|
|
profileList [0] = ((ICC_ColorSpace) srcCspace).getProfile(); |
|
profileList [1] = ((ICC_ColorSpace) dstCspace).getProfile(); |
|
|
|
getMinMaxValsFromColorSpaces(srcCspace, dstCspace); |
|
} else { |
|
|
|
CSList = new ColorSpace[2]; |
|
CSList[0] = srcCspace; |
|
CSList[1] = dstCspace; |
|
} |
|
this.hints = hints; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public ColorConvertOp (ICC_Profile[] profiles, RenderingHints hints) |
|
{ |
|
if (profiles == null) { |
|
throw new NullPointerException("Profiles cannot be null"); |
|
} |
|
gotProfiles = true; |
|
profileList = new ICC_Profile[profiles.length]; |
|
for (int i1 = 0; i1 < profiles.length; i1++) { |
|
profileList[i1] = profiles[i1]; |
|
} |
|
this.hints = hints; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public final ICC_Profile[] getICC_Profiles() { |
|
if (gotProfiles) { |
|
ICC_Profile[] profiles = new ICC_Profile[profileList.length]; |
|
for (int i1 = 0; i1 < profileList.length; i1++) { |
|
profiles[i1] = profileList[i1]; |
|
} |
|
return profiles; |
|
} |
|
return null; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public final BufferedImage filter(BufferedImage src, BufferedImage dest) { |
|
ColorSpace srcColorSpace, destColorSpace; |
|
BufferedImage savdest = null; |
|
|
|
if (src.getColorModel() instanceof IndexColorModel) { |
|
IndexColorModel icm = (IndexColorModel) src.getColorModel(); |
|
src = icm.convertToIntDiscrete(src.getRaster(), true); |
|
} |
|
srcColorSpace = src.getColorModel().getColorSpace(); |
|
if (dest != null) { |
|
if (dest.getColorModel() instanceof IndexColorModel) { |
|
savdest = dest; |
|
dest = null; |
|
destColorSpace = null; |
|
} else { |
|
destColorSpace = dest.getColorModel().getColorSpace(); |
|
} |
|
} else { |
|
destColorSpace = null; |
|
} |
|
|
|
if ((CSList != null) || |
|
(!(srcColorSpace instanceof ICC_ColorSpace)) || |
|
((dest != null) && |
|
(!(destColorSpace instanceof ICC_ColorSpace)))) { |
|
|
|
dest = nonICCBIFilter(src, srcColorSpace, dest, destColorSpace); |
|
} else { |
|
dest = ICCBIFilter(src, srcColorSpace, dest, destColorSpace); |
|
} |
|
|
|
if (savdest != null) { |
|
Graphics2D big = savdest.createGraphics(); |
|
try { |
|
big.drawImage(dest, 0, 0, null); |
|
} finally { |
|
big.dispose(); |
|
} |
|
return savdest; |
|
} else { |
|
return dest; |
|
} |
|
} |
|
|
|
private final BufferedImage ICCBIFilter(BufferedImage src, |
|
ColorSpace srcColorSpace, |
|
BufferedImage dest, |
|
ColorSpace destColorSpace) { |
|
int nProfiles = profileList.length; |
|
ICC_Profile srcProfile = null, destProfile = null; |
|
|
|
srcProfile = ((ICC_ColorSpace) srcColorSpace).getProfile(); |
|
|
|
if (dest == null) { |
|
the output color space */ |
|
if (nProfiles == 0) { |
|
throw new IllegalArgumentException( |
|
"Destination ColorSpace is undefined"); |
|
} |
|
destProfile = profileList [nProfiles - 1]; |
|
dest = createCompatibleDestImage(src, null); |
|
} |
|
else { |
|
if (src.getHeight() != dest.getHeight() || |
|
src.getWidth() != dest.getWidth()) { |
|
throw new IllegalArgumentException( |
|
"Width or height of BufferedImages do not match"); |
|
} |
|
destProfile = ((ICC_ColorSpace) destColorSpace).getProfile(); |
|
} |
|
|
|
|
|
|
|
*/ |
|
if (srcProfile == destProfile) { |
|
boolean noTrans = true; |
|
for (int i = 0; i < nProfiles; i++) { |
|
if (srcProfile != profileList[i]) { |
|
noTrans = false; |
|
break; |
|
} |
|
} |
|
if (noTrans) { |
|
Graphics2D g = dest.createGraphics(); |
|
try { |
|
g.drawImage(src, 0, 0, null); |
|
} finally { |
|
g.dispose(); |
|
} |
|
|
|
return dest; |
|
} |
|
} |
|
|
|
|
|
if ((thisTransform == null) || (thisSrcProfile != srcProfile) || |
|
(thisDestProfile != destProfile) ) { |
|
updateBITransform(srcProfile, destProfile); |
|
} |
|
|
|
|
|
thisTransform.colorConvert(src, dest); |
|
|
|
return dest; |
|
} |
|
|
|
private void updateBITransform(ICC_Profile srcProfile, |
|
ICC_Profile destProfile) { |
|
ICC_Profile[] theProfiles; |
|
int i1, nProfiles, nTransforms, whichTrans, renderState; |
|
ColorTransform[] theTransforms; |
|
boolean useSrc = false, useDest = false; |
|
|
|
nProfiles = profileList.length; |
|
nTransforms = nProfiles; |
|
if ((nProfiles == 0) || (srcProfile != profileList[0])) { |
|
nTransforms += 1; |
|
useSrc = true; |
|
} |
|
if ((nProfiles == 0) || (destProfile != profileList[nProfiles - 1]) || |
|
(nTransforms < 2)) { |
|
nTransforms += 1; |
|
useDest = true; |
|
} |
|
|
|
|
|
theProfiles = new ICC_Profile[nTransforms]; /* the list of profiles |
|
for this Op */ |
|
|
|
int idx = 0; |
|
if (useSrc) { |
|
|
|
theProfiles[idx++] = srcProfile; |
|
} |
|
|
|
for (i1 = 0; i1 < nProfiles; i1++) { |
|
|
|
theProfiles[idx++] = profileList [i1]; |
|
} |
|
|
|
if (useDest) { |
|
|
|
theProfiles[idx] = destProfile; |
|
} |
|
|
|
|
|
theTransforms = new ColorTransform [nTransforms]; |
|
|
|
|
|
if (theProfiles[0].getProfileClass() == ICC_Profile.CLASS_OUTPUT) { |
|
|
|
render as colorimetric */ |
|
renderState = ICC_Profile.icRelativeColorimetric; |
|
} |
|
else { |
|
renderState = ICC_Profile.icPerceptual; /* render any other |
|
class perceptually */ |
|
} |
|
|
|
whichTrans = ColorTransform.In; |
|
|
|
PCMM mdl = CMSManager.getModule(); |
|
|
|
|
|
for (i1 = 0; i1 < nTransforms; i1++) { |
|
if (i1 == nTransforms -1) { |
|
whichTrans = ColorTransform.Out; /* get output transform */ |
|
} |
|
else { |
|
if ((whichTrans == ColorTransform.Simulation) && |
|
(theProfiles[i1].getProfileClass () == |
|
ICC_Profile.CLASS_ABSTRACT)) { |
|
renderState = ICC_Profile.icPerceptual; |
|
whichTrans = ColorTransform.In; |
|
} |
|
} |
|
|
|
theTransforms[i1] = mdl.createTransform ( |
|
theProfiles[i1], renderState, whichTrans); |
|
|
|
|
|
from next profile */ |
|
renderState = getRenderingIntent(theProfiles[i1]); |
|
|
|
|
|
whichTrans = ColorTransform.Simulation; |
|
} |
|
|
|
|
|
thisTransform = mdl.createTransform(theTransforms); |
|
|
|
|
|
thisSrcProfile = srcProfile; |
|
thisDestProfile = destProfile; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public final WritableRaster filter (Raster src, WritableRaster dest) { |
|
|
|
if (CSList != null) { |
|
|
|
return nonICCRasterFilter(src, dest); |
|
} |
|
int nProfiles = profileList.length; |
|
if (nProfiles < 2) { |
|
throw new IllegalArgumentException( |
|
"Source or Destination ColorSpace is undefined"); |
|
} |
|
if (src.getNumBands() != profileList[0].getNumComponents()) { |
|
throw new IllegalArgumentException( |
|
"Numbers of source Raster bands and source color space " + |
|
"components do not match"); |
|
} |
|
if (dest == null) { |
|
dest = createCompatibleDestRaster(src); |
|
} |
|
else { |
|
if (src.getHeight() != dest.getHeight() || |
|
src.getWidth() != dest.getWidth()) { |
|
throw new IllegalArgumentException( |
|
"Width or height of Rasters do not match"); |
|
} |
|
if (dest.getNumBands() != |
|
profileList[nProfiles-1].getNumComponents()) { |
|
throw new IllegalArgumentException( |
|
"Numbers of destination Raster bands and destination " + |
|
"color space components do not match"); |
|
} |
|
} |
|
|
|
|
|
if (thisRasterTransform == null) { |
|
int i1, whichTrans, renderState; |
|
ColorTransform[] theTransforms; |
|
|
|
|
|
theTransforms = new ColorTransform [nProfiles]; |
|
|
|
|
|
if (profileList[0].getProfileClass() == ICC_Profile.CLASS_OUTPUT) { |
|
|
|
render as colorimetric */ |
|
renderState = ICC_Profile.icRelativeColorimetric; |
|
} |
|
else { |
|
renderState = ICC_Profile.icPerceptual; /* render any other |
|
class perceptually */ |
|
} |
|
|
|
whichTrans = ColorTransform.In; |
|
|
|
PCMM mdl = CMSManager.getModule(); |
|
|
|
|
|
for (i1 = 0; i1 < nProfiles; i1++) { |
|
if (i1 == nProfiles -1) { |
|
whichTrans = ColorTransform.Out; /* get output transform */ |
|
} |
|
else { |
|
if ((whichTrans == ColorTransform.Simulation) && |
|
(profileList[i1].getProfileClass () == |
|
ICC_Profile.CLASS_ABSTRACT)) { |
|
renderState = ICC_Profile.icPerceptual; |
|
whichTrans = ColorTransform.In; |
|
} |
|
} |
|
|
|
theTransforms[i1] = mdl.createTransform ( |
|
profileList[i1], renderState, whichTrans); |
|
|
|
|
|
from next profile */ |
|
renderState = getRenderingIntent(profileList[i1]); |
|
|
|
|
|
whichTrans = ColorTransform.Simulation; |
|
} |
|
|
|
|
|
thisRasterTransform = mdl.createTransform(theTransforms); |
|
} |
|
|
|
int srcTransferType = src.getTransferType(); |
|
int dstTransferType = dest.getTransferType(); |
|
if ((srcTransferType == DataBuffer.TYPE_FLOAT) || |
|
(srcTransferType == DataBuffer.TYPE_DOUBLE) || |
|
(dstTransferType == DataBuffer.TYPE_FLOAT) || |
|
(dstTransferType == DataBuffer.TYPE_DOUBLE)) { |
|
if (srcMinVals == null) { |
|
getMinMaxValsFromProfiles(profileList[0], |
|
profileList[nProfiles-1]); |
|
} |
|
|
|
thisRasterTransform.colorConvert(src, dest, |
|
srcMinVals, srcMaxVals, |
|
dstMinVals, dstMaxVals); |
|
} else { |
|
|
|
thisRasterTransform.colorConvert(src, dest); |
|
} |
|
|
|
|
|
return dest; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public final Rectangle2D getBounds2D (BufferedImage src) { |
|
return getBounds2D(src.getRaster()); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public final Rectangle2D getBounds2D (Raster src) { |
|
|
|
|
|
src.getWidth(), src.getHeight()); */ |
|
return src.getBounds(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public BufferedImage createCompatibleDestImage (BufferedImage src, |
|
ColorModel destCM) { |
|
ColorSpace cs = null;; |
|
if (destCM == null) { |
|
if (CSList == null) { |
|
|
|
int nProfiles = profileList.length; |
|
if (nProfiles == 0) { |
|
throw new IllegalArgumentException( |
|
"Destination ColorSpace is undefined"); |
|
} |
|
ICC_Profile destProfile = profileList[nProfiles - 1]; |
|
cs = new ICC_ColorSpace(destProfile); |
|
} else { |
|
|
|
int nSpaces = CSList.length; |
|
cs = CSList[nSpaces - 1]; |
|
} |
|
} |
|
return createCompatibleDestImage(src, destCM, cs); |
|
} |
|
|
|
private BufferedImage createCompatibleDestImage(BufferedImage src, |
|
ColorModel destCM, |
|
ColorSpace destCS) { |
|
BufferedImage image; |
|
if (destCM == null) { |
|
ColorModel srcCM = src.getColorModel(); |
|
int nbands = destCS.getNumComponents(); |
|
boolean hasAlpha = srcCM.hasAlpha(); |
|
if (hasAlpha) { |
|
nbands += 1; |
|
} |
|
int[] nbits = new int[nbands]; |
|
for (int i = 0; i < nbands; i++) { |
|
nbits[i] = 8; |
|
} |
|
destCM = new ComponentColorModel(destCS, nbits, hasAlpha, |
|
srcCM.isAlphaPremultiplied(), |
|
srcCM.getTransparency(), |
|
DataBuffer.TYPE_BYTE); |
|
} |
|
int w = src.getWidth(); |
|
int h = src.getHeight(); |
|
image = new BufferedImage(destCM, |
|
destCM.createCompatibleWritableRaster(w, h), |
|
destCM.isAlphaPremultiplied(), null); |
|
return image; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public WritableRaster createCompatibleDestRaster (Raster src) { |
|
int ncomponents; |
|
|
|
if (CSList != null) { |
|
|
|
if (CSList.length != 2) { |
|
throw new IllegalArgumentException( |
|
"Destination ColorSpace is undefined"); |
|
} |
|
ncomponents = CSList[1].getNumComponents(); |
|
} else { |
|
|
|
int nProfiles = profileList.length; |
|
if (nProfiles < 2) { |
|
throw new IllegalArgumentException( |
|
"Destination ColorSpace is undefined"); |
|
} |
|
ncomponents = profileList[nProfiles-1].getNumComponents(); |
|
} |
|
|
|
WritableRaster dest = |
|
Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, |
|
src.getWidth(), |
|
src.getHeight(), |
|
ncomponents, |
|
new Point(src.getMinX(), src.getMinY())); |
|
return dest; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public final Point2D getPoint2D (Point2D srcPt, Point2D dstPt) { |
|
if (dstPt == null) { |
|
dstPt = new Point2D.Float(); |
|
} |
|
dstPt.setLocation(srcPt.getX(), srcPt.getY()); |
|
|
|
return dstPt; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private int getRenderingIntent (ICC_Profile profile) { |
|
byte[] header = profile.getData(ICC_Profile.icSigHead); |
|
int index = ICC_Profile.icHdrRenderingIntent; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
return ((header[index+2] & 0xff) << 8) | |
|
(header[index+3] & 0xff); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public final RenderingHints getRenderingHints() { |
|
return hints; |
|
} |
|
|
|
private final BufferedImage nonICCBIFilter(BufferedImage src, |
|
ColorSpace srcColorSpace, |
|
BufferedImage dst, |
|
ColorSpace dstColorSpace) { |
|
|
|
int w = src.getWidth(); |
|
int h = src.getHeight(); |
|
ICC_ColorSpace ciespace = |
|
(ICC_ColorSpace) ColorSpace.getInstance(ColorSpace.CS_CIEXYZ); |
|
if (dst == null) { |
|
dst = createCompatibleDestImage(src, null); |
|
dstColorSpace = dst.getColorModel().getColorSpace(); |
|
} else { |
|
if ((h != dst.getHeight()) || (w != dst.getWidth())) { |
|
throw new IllegalArgumentException( |
|
"Width or height of BufferedImages do not match"); |
|
} |
|
} |
|
Raster srcRas = src.getRaster(); |
|
WritableRaster dstRas = dst.getRaster(); |
|
ColorModel srcCM = src.getColorModel(); |
|
ColorModel dstCM = dst.getColorModel(); |
|
int srcNumComp = srcCM.getNumColorComponents(); |
|
int dstNumComp = dstCM.getNumColorComponents(); |
|
boolean dstHasAlpha = dstCM.hasAlpha(); |
|
boolean needSrcAlpha = srcCM.hasAlpha() && dstHasAlpha; |
|
ColorSpace[] list; |
|
if ((CSList == null) && (profileList.length != 0)) { |
|
|
|
boolean nonICCSrc, nonICCDst; |
|
ICC_Profile srcProfile, dstProfile; |
|
if (!(srcColorSpace instanceof ICC_ColorSpace)) { |
|
nonICCSrc = true; |
|
srcProfile = ciespace.getProfile(); |
|
} else { |
|
nonICCSrc = false; |
|
srcProfile = ((ICC_ColorSpace) srcColorSpace).getProfile(); |
|
} |
|
if (!(dstColorSpace instanceof ICC_ColorSpace)) { |
|
nonICCDst = true; |
|
dstProfile = ciespace.getProfile(); |
|
} else { |
|
nonICCDst = false; |
|
dstProfile = ((ICC_ColorSpace) dstColorSpace).getProfile(); |
|
} |
|
|
|
if ((thisTransform == null) || (thisSrcProfile != srcProfile) || |
|
(thisDestProfile != dstProfile) ) { |
|
updateBITransform(srcProfile, dstProfile); |
|
} |
|
// process per scanline |
|
float maxNum = 65535.0f; |
|
ColorSpace cs; |
|
int iccSrcNumComp; |
|
if (nonICCSrc) { |
|
cs = ciespace; |
|
iccSrcNumComp = 3; |
|
} else { |
|
cs = srcColorSpace; |
|
iccSrcNumComp = srcNumComp; |
|
} |
|
float[] srcMinVal = new float[iccSrcNumComp]; |
|
float[] srcInvDiffMinMax = new float[iccSrcNumComp]; |
|
for (int i = 0; i < srcNumComp; i++) { |
|
srcMinVal[i] = cs.getMinValue(i); |
|
srcInvDiffMinMax[i] = maxNum / (cs.getMaxValue(i) - srcMinVal[i]); |
|
} |
|
int iccDstNumComp; |
|
if (nonICCDst) { |
|
cs = ciespace; |
|
iccDstNumComp = 3; |
|
} else { |
|
cs = dstColorSpace; |
|
iccDstNumComp = dstNumComp; |
|
} |
|
float[] dstMinVal = new float[iccDstNumComp]; |
|
float[] dstDiffMinMax = new float[iccDstNumComp]; |
|
for (int i = 0; i < dstNumComp; i++) { |
|
dstMinVal[i] = cs.getMinValue(i); |
|
dstDiffMinMax[i] = (cs.getMaxValue(i) - dstMinVal[i]) / maxNum; |
|
} |
|
float[] dstColor; |
|
if (dstHasAlpha) { |
|
int size = ((dstNumComp + 1) > 3) ? (dstNumComp + 1) : 3; |
|
dstColor = new float[size]; |
|
} else { |
|
int size = (dstNumComp > 3) ? dstNumComp : 3; |
|
dstColor = new float[size]; |
|
} |
|
short[] srcLine = new short[w * iccSrcNumComp]; |
|
short[] dstLine = new short[w * iccDstNumComp]; |
|
Object pixel; |
|
float[] color; |
|
float[] alpha = null; |
|
if (needSrcAlpha) { |
|
alpha = new float[w]; |
|
} |
|
int idx; |
|
|
|
for (int y = 0; y < h; y++) { |
|
|
|
pixel = null; |
|
color = null; |
|
idx = 0; |
|
for (int x = 0; x < w; x++) { |
|
pixel = srcRas.getDataElements(x, y, pixel); |
|
color = srcCM.getNormalizedComponents(pixel, color, 0); |
|
if (needSrcAlpha) { |
|
alpha[x] = color[srcNumComp]; |
|
} |
|
if (nonICCSrc) { |
|
color = srcColorSpace.toCIEXYZ(color); |
|
} |
|
for (int i = 0; i < iccSrcNumComp; i++) { |
|
srcLine[idx++] = (short) |
|
((color[i] - srcMinVal[i]) * srcInvDiffMinMax[i] + |
|
0.5f); |
|
} |
|
} |
|
|
|
thisTransform.colorConvert(srcLine, dstLine); |
|
|
|
pixel = null; |
|
idx = 0; |
|
for (int x = 0; x < w; x++) { |
|
for (int i = 0; i < iccDstNumComp; i++) { |
|
dstColor[i] = ((float) (dstLine[idx++] & 0xffff)) * |
|
dstDiffMinMax[i] + dstMinVal[i]; |
|
} |
|
if (nonICCDst) { |
|
color = srcColorSpace.fromCIEXYZ(dstColor); |
|
for (int i = 0; i < dstNumComp; i++) { |
|
dstColor[i] = color[i]; |
|
} |
|
} |
|
if (needSrcAlpha) { |
|
dstColor[dstNumComp] = alpha[x]; |
|
} else if (dstHasAlpha) { |
|
dstColor[dstNumComp] = 1.0f; |
|
} |
|
pixel = dstCM.getDataElements(dstColor, 0, pixel); |
|
dstRas.setDataElements(x, y, pixel); |
|
} |
|
} |
|
} else { |
|
/* possible non-ICC src, possible CSList, possible non-ICC dst */ |
|
|
|
int numCS; |
|
if (CSList == null) { |
|
numCS = 0; |
|
} else { |
|
numCS = CSList.length; |
|
} |
|
float[] dstColor; |
|
if (dstHasAlpha) { |
|
dstColor = new float[dstNumComp + 1]; |
|
} else { |
|
dstColor = new float[dstNumComp]; |
|
} |
|
Object spixel = null; |
|
Object dpixel = null; |
|
float[] color = null; |
|
float[] tmpColor; |
|
|
|
for (int y = 0; y < h; y++) { |
|
for (int x = 0; x < w; x++) { |
|
spixel = srcRas.getDataElements(x, y, spixel); |
|
color = srcCM.getNormalizedComponents(spixel, color, 0); |
|
tmpColor = srcColorSpace.toCIEXYZ(color); |
|
for (int i = 0; i < numCS; i++) { |
|
tmpColor = CSList[i].fromCIEXYZ(tmpColor); |
|
tmpColor = CSList[i].toCIEXYZ(tmpColor); |
|
} |
|
tmpColor = dstColorSpace.fromCIEXYZ(tmpColor); |
|
for (int i = 0; i < dstNumComp; i++) { |
|
dstColor[i] = tmpColor[i]; |
|
} |
|
if (needSrcAlpha) { |
|
dstColor[dstNumComp] = color[srcNumComp]; |
|
} else if (dstHasAlpha) { |
|
dstColor[dstNumComp] = 1.0f; |
|
} |
|
dpixel = dstCM.getDataElements(dstColor, 0, dpixel); |
|
dstRas.setDataElements(x, y, dpixel); |
|
|
|
} |
|
} |
|
} |
|
|
|
return dst; |
|
} |
|
|
|
|
|
or double transferTypes */ |
|
private final WritableRaster nonICCRasterFilter(Raster src, |
|
WritableRaster dst) { |
|
|
|
if (CSList.length != 2) { |
|
throw new IllegalArgumentException( |
|
"Destination ColorSpace is undefined"); |
|
} |
|
if (src.getNumBands() != CSList[0].getNumComponents()) { |
|
throw new IllegalArgumentException( |
|
"Numbers of source Raster bands and source color space " + |
|
"components do not match"); |
|
} |
|
if (dst == null) { |
|
dst = createCompatibleDestRaster(src); |
|
} else { |
|
if (src.getHeight() != dst.getHeight() || |
|
src.getWidth() != dst.getWidth()) { |
|
throw new IllegalArgumentException( |
|
"Width or height of Rasters do not match"); |
|
} |
|
if (dst.getNumBands() != CSList[1].getNumComponents()) { |
|
throw new IllegalArgumentException( |
|
"Numbers of destination Raster bands and destination " + |
|
"color space components do not match"); |
|
} |
|
} |
|
|
|
if (srcMinVals == null) { |
|
getMinMaxValsFromColorSpaces(CSList[0], CSList[1]); |
|
} |
|
|
|
SampleModel srcSM = src.getSampleModel(); |
|
SampleModel dstSM = dst.getSampleModel(); |
|
boolean srcIsFloat, dstIsFloat; |
|
int srcTransferType = src.getTransferType(); |
|
int dstTransferType = dst.getTransferType(); |
|
if ((srcTransferType == DataBuffer.TYPE_FLOAT) || |
|
(srcTransferType == DataBuffer.TYPE_DOUBLE)) { |
|
srcIsFloat = true; |
|
} else { |
|
srcIsFloat = false; |
|
} |
|
if ((dstTransferType == DataBuffer.TYPE_FLOAT) || |
|
(dstTransferType == DataBuffer.TYPE_DOUBLE)) { |
|
dstIsFloat = true; |
|
} else { |
|
dstIsFloat = false; |
|
} |
|
int w = src.getWidth(); |
|
int h = src.getHeight(); |
|
int srcNumBands = src.getNumBands(); |
|
int dstNumBands = dst.getNumBands(); |
|
float[] srcScaleFactor = null; |
|
float[] dstScaleFactor = null; |
|
if (!srcIsFloat) { |
|
srcScaleFactor = new float[srcNumBands]; |
|
for (int i = 0; i < srcNumBands; i++) { |
|
if (srcTransferType == DataBuffer.TYPE_SHORT) { |
|
srcScaleFactor[i] = (srcMaxVals[i] - srcMinVals[i]) / |
|
32767.0f; |
|
} else { |
|
srcScaleFactor[i] = (srcMaxVals[i] - srcMinVals[i]) / |
|
((float) ((1 << srcSM.getSampleSize(i)) - 1)); |
|
} |
|
} |
|
} |
|
if (!dstIsFloat) { |
|
dstScaleFactor = new float[dstNumBands]; |
|
for (int i = 0; i < dstNumBands; i++) { |
|
if (dstTransferType == DataBuffer.TYPE_SHORT) { |
|
dstScaleFactor[i] = 32767.0f / |
|
(dstMaxVals[i] - dstMinVals[i]); |
|
} else { |
|
dstScaleFactor[i] = |
|
((float) ((1 << dstSM.getSampleSize(i)) - 1)) / |
|
(dstMaxVals[i] - dstMinVals[i]); |
|
} |
|
} |
|
} |
|
int ys = src.getMinY(); |
|
int yd = dst.getMinY(); |
|
int xs, xd; |
|
float sample; |
|
float[] color = new float[srcNumBands]; |
|
float[] tmpColor; |
|
ColorSpace srcColorSpace = CSList[0]; |
|
ColorSpace dstColorSpace = CSList[1]; |
|
|
|
for (int y = 0; y < h; y++, ys++, yd++) { |
|
|
|
xs = src.getMinX(); |
|
xd = dst.getMinX(); |
|
for (int x = 0; x < w; x++, xs++, xd++) { |
|
for (int i = 0; i < srcNumBands; i++) { |
|
sample = src.getSampleFloat(xs, ys, i); |
|
if (!srcIsFloat) { |
|
sample = sample * srcScaleFactor[i] + srcMinVals[i]; |
|
} |
|
color[i] = sample; |
|
} |
|
tmpColor = srcColorSpace.toCIEXYZ(color); |
|
tmpColor = dstColorSpace.fromCIEXYZ(tmpColor); |
|
for (int i = 0; i < dstNumBands; i++) { |
|
sample = tmpColor[i]; |
|
if (!dstIsFloat) { |
|
sample = (sample - dstMinVals[i]) * dstScaleFactor[i]; |
|
} |
|
dst.setSample(xd, yd, i, sample); |
|
} |
|
} |
|
} |
|
return dst; |
|
} |
|
|
|
private void getMinMaxValsFromProfiles(ICC_Profile srcProfile, |
|
ICC_Profile dstProfile) { |
|
int type = srcProfile.getColorSpaceType(); |
|
int nc = srcProfile.getNumComponents(); |
|
srcMinVals = new float[nc]; |
|
srcMaxVals = new float[nc]; |
|
setMinMax(type, nc, srcMinVals, srcMaxVals); |
|
type = dstProfile.getColorSpaceType(); |
|
nc = dstProfile.getNumComponents(); |
|
dstMinVals = new float[nc]; |
|
dstMaxVals = new float[nc]; |
|
setMinMax(type, nc, dstMinVals, dstMaxVals); |
|
} |
|
|
|
private void setMinMax(int type, int nc, float[] minVals, float[] maxVals) { |
|
if (type == ColorSpace.TYPE_Lab) { |
|
minVals[0] = 0.0f; |
|
maxVals[0] = 100.0f; |
|
minVals[1] = -128.0f; |
|
maxVals[1] = 127.0f; |
|
minVals[2] = -128.0f; |
|
maxVals[2] = 127.0f; |
|
} else if (type == ColorSpace.TYPE_XYZ) { |
|
minVals[0] = minVals[1] = minVals[2] = 0.0f; |
|
maxVals[0] = maxVals[1] = maxVals[2] = 1.0f + (32767.0f/ 32768.0f); |
|
} else { |
|
for (int i = 0; i < nc; i++) { |
|
minVals[i] = 0.0f; |
|
maxVals[i] = 1.0f; |
|
} |
|
} |
|
} |
|
|
|
private void getMinMaxValsFromColorSpaces(ColorSpace srcCspace, |
|
ColorSpace dstCspace) { |
|
int nc = srcCspace.getNumComponents(); |
|
srcMinVals = new float[nc]; |
|
srcMaxVals = new float[nc]; |
|
for (int i = 0; i < nc; i++) { |
|
srcMinVals[i] = srcCspace.getMinValue(i); |
|
srcMaxVals[i] = srcCspace.getMaxValue(i); |
|
} |
|
nc = dstCspace.getNumComponents(); |
|
dstMinVals = new float[nc]; |
|
dstMaxVals = new float[nc]; |
|
for (int i = 0; i < nc; i++) { |
|
dstMinVals[i] = dstCspace.getMinValue(i); |
|
dstMaxVals[i] = dstCspace.getMaxValue(i); |
|
} |
|
} |
|
|
|
} |