use of java.awt.color.ColorSpace in project jdk8u_jdk by JetBrains.
the class JPEGImageWriter method writeOnThread.
private void writeOnThread(IIOMetadata streamMetadata, IIOImage image, ImageWriteParam param) throws IOException {
if (ios == null) {
throw new IllegalStateException("Output has not been set!");
}
if (image == null) {
throw new IllegalArgumentException("image is null!");
}
// if streamMetadata is not null, issue a warning
if (streamMetadata != null) {
warningOccurred(WARNING_STREAM_METADATA_IGNORED);
}
// Obtain the raster and image, if there is one
boolean rasterOnly = image.hasRaster();
RenderedImage rimage = null;
if (rasterOnly) {
srcRas = image.getRaster();
} else {
rimage = image.getRenderedImage();
if (rimage instanceof BufferedImage) {
// Use the Raster directly.
srcRas = ((BufferedImage) rimage).getRaster();
} else if (rimage.getNumXTiles() == 1 && rimage.getNumYTiles() == 1) {
// Get the unique tile.
srcRas = rimage.getTile(rimage.getMinTileX(), rimage.getMinTileY());
// as the tile dimensions might differ.
if (srcRas.getWidth() != rimage.getWidth() || srcRas.getHeight() != rimage.getHeight()) {
srcRas = srcRas.createChild(srcRas.getMinX(), srcRas.getMinY(), rimage.getWidth(), rimage.getHeight(), srcRas.getMinX(), srcRas.getMinY(), null);
}
} else {
// Image is tiled so get a contiguous raster by copying.
srcRas = rimage.getData();
}
}
// Now determine if we are using a band subset
// By default, we are using all source bands
int numSrcBands = srcRas.getNumBands();
indexed = false;
indexCM = null;
ColorModel cm = null;
ColorSpace cs = null;
isAlphaPremultiplied = false;
srcCM = null;
if (!rasterOnly) {
cm = rimage.getColorModel();
if (cm != null) {
cs = cm.getColorSpace();
if (cm instanceof IndexColorModel) {
indexed = true;
indexCM = (IndexColorModel) cm;
numSrcBands = cm.getNumComponents();
}
if (cm.isAlphaPremultiplied()) {
isAlphaPremultiplied = true;
srcCM = cm;
}
}
}
srcBands = JPEG.bandOffsets[numSrcBands - 1];
int numBandsUsed = numSrcBands;
if (param != null) {
int[] sBands = param.getSourceBands();
if (sBands != null) {
if (indexed) {
warningOccurred(WARNING_NO_BANDS_ON_INDEXED);
} else {
srcBands = sBands;
numBandsUsed = srcBands.length;
if (numBandsUsed > numSrcBands) {
throw new IIOException("ImageWriteParam specifies too many source bands");
}
}
}
}
boolean usingBandSubset = (numBandsUsed != numSrcBands);
boolean fullImage = ((!rasterOnly) && (!usingBandSubset));
int[] bandSizes = null;
if (!indexed) {
bandSizes = srcRas.getSampleModel().getSampleSize();
// If this is a subset, we must adjust bandSizes
if (usingBandSubset) {
int[] temp = new int[numBandsUsed];
for (int i = 0; i < numBandsUsed; i++) {
temp[i] = bandSizes[srcBands[i]];
}
bandSizes = temp;
}
} else {
int[] tempSize = srcRas.getSampleModel().getSampleSize();
bandSizes = new int[numSrcBands];
for (int i = 0; i < numSrcBands; i++) {
// All the same
bandSizes[i] = tempSize[0];
}
}
for (int i = 0; i < bandSizes.length; i++) {
// per sample.
if (bandSizes[i] <= 0 || bandSizes[i] > 8) {
throw new IIOException("Illegal band size: should be 0 < size <= 8");
}
// to 8-bit.
if (indexed) {
bandSizes[i] = 8;
}
}
if (debug) {
System.out.println("numSrcBands is " + numSrcBands);
System.out.println("numBandsUsed is " + numBandsUsed);
System.out.println("usingBandSubset is " + usingBandSubset);
System.out.println("fullImage is " + fullImage);
System.out.print("Band sizes:");
for (int i = 0; i < bandSizes.length; i++) {
System.out.print(" " + bandSizes[i]);
}
System.out.println();
}
// Destination type, if there is one
ImageTypeSpecifier destType = null;
if (param != null) {
destType = param.getDestinationType();
// Ignore dest type if we are writing a complete image
if ((fullImage) && (destType != null)) {
warningOccurred(WARNING_DEST_IGNORED);
destType = null;
}
}
// Examine the param
sourceXOffset = srcRas.getMinX();
sourceYOffset = srcRas.getMinY();
int imageWidth = srcRas.getWidth();
int imageHeight = srcRas.getHeight();
sourceWidth = imageWidth;
sourceHeight = imageHeight;
int periodX = 1;
int periodY = 1;
int gridX = 0;
int gridY = 0;
JPEGQTable[] qTables = null;
JPEGHuffmanTable[] DCHuffmanTables = null;
JPEGHuffmanTable[] ACHuffmanTables = null;
boolean optimizeHuffman = false;
JPEGImageWriteParam jparam = null;
int progressiveMode = ImageWriteParam.MODE_DISABLED;
if (param != null) {
Rectangle sourceRegion = param.getSourceRegion();
if (sourceRegion != null) {
Rectangle imageBounds = new Rectangle(sourceXOffset, sourceYOffset, sourceWidth, sourceHeight);
sourceRegion = sourceRegion.intersection(imageBounds);
sourceXOffset = sourceRegion.x;
sourceYOffset = sourceRegion.y;
sourceWidth = sourceRegion.width;
sourceHeight = sourceRegion.height;
}
if (sourceWidth + sourceXOffset > imageWidth) {
sourceWidth = imageWidth - sourceXOffset;
}
if (sourceHeight + sourceYOffset > imageHeight) {
sourceHeight = imageHeight - sourceYOffset;
}
periodX = param.getSourceXSubsampling();
periodY = param.getSourceYSubsampling();
gridX = param.getSubsamplingXOffset();
gridY = param.getSubsamplingYOffset();
switch(param.getCompressionMode()) {
case ImageWriteParam.MODE_DISABLED:
throw new IIOException("JPEG compression cannot be disabled");
case ImageWriteParam.MODE_EXPLICIT:
float quality = param.getCompressionQuality();
quality = JPEG.convertToLinearQuality(quality);
qTables = new JPEGQTable[2];
qTables[0] = JPEGQTable.K1Luminance.getScaledInstance(quality, true);
qTables[1] = JPEGQTable.K2Chrominance.getScaledInstance(quality, true);
break;
case ImageWriteParam.MODE_DEFAULT:
qTables = new JPEGQTable[2];
qTables[0] = JPEGQTable.K1Div2Luminance;
qTables[1] = JPEGQTable.K2Div2Chrominance;
break;
}
progressiveMode = param.getProgressiveMode();
if (param instanceof JPEGImageWriteParam) {
jparam = (JPEGImageWriteParam) param;
optimizeHuffman = jparam.getOptimizeHuffmanTables();
}
}
// Now examine the metadata
IIOMetadata mdata = image.getMetadata();
if (mdata != null) {
if (mdata instanceof JPEGMetadata) {
metadata = (JPEGMetadata) mdata;
if (debug) {
System.out.println("We have metadata, and it's JPEG metadata");
}
} else {
if (!rasterOnly) {
ImageTypeSpecifier type = destType;
if (type == null) {
type = new ImageTypeSpecifier(rimage);
}
metadata = (JPEGMetadata) convertImageMetadata(mdata, type, param);
} else {
warningOccurred(WARNING_METADATA_NOT_JPEG_FOR_RASTER);
}
}
}
// First set a default state
// If it's there, use it
ignoreJFIF = false;
// If it's there, use it
ignoreAdobe = false;
// Change if needed
newAdobeTransform = JPEG.ADOBE_IMPOSSIBLE;
writeDefaultJFIF = false;
writeAdobe = false;
// By default we'll do no conversion:
int inCsType = JPEG.JCS_UNKNOWN;
int outCsType = JPEG.JCS_UNKNOWN;
JFIFMarkerSegment jfif = null;
AdobeMarkerSegment adobe = null;
SOFMarkerSegment sof = null;
if (metadata != null) {
jfif = (JFIFMarkerSegment) metadata.findMarkerSegment(JFIFMarkerSegment.class, true);
adobe = (AdobeMarkerSegment) metadata.findMarkerSegment(AdobeMarkerSegment.class, true);
sof = (SOFMarkerSegment) metadata.findMarkerSegment(SOFMarkerSegment.class, true);
}
// By default don't write one
iccProfile = null;
// PhotoYCC does this
convertTosRGB = false;
converted = null;
if (destType != null) {
if (numBandsUsed != destType.getNumBands()) {
throw new IIOException("Number of source bands != number of destination bands");
}
cs = destType.getColorModel().getColorSpace();
// Check the metadata against the destination type
if (metadata != null) {
checkSOFBands(sof, numBandsUsed);
checkJFIF(jfif, destType, false);
// Do we want to write an ICC profile?
if ((jfif != null) && (ignoreJFIF == false)) {
if (JPEG.isNonStandardICC(cs)) {
iccProfile = ((ICC_ColorSpace) cs).getProfile();
}
}
checkAdobe(adobe, destType, false);
} else {
// If we can add a JFIF or an Adobe marker segment, do so
if (JPEG.isJFIFcompliant(destType, false)) {
writeDefaultJFIF = true;
// Do we want to write an ICC profile?
if (JPEG.isNonStandardICC(cs)) {
iccProfile = ((ICC_ColorSpace) cs).getProfile();
}
} else {
int transform = JPEG.transformForType(destType, false);
if (transform != JPEG.ADOBE_IMPOSSIBLE) {
writeAdobe = true;
newAdobeTransform = transform;
}
}
// re-create the metadata
metadata = new JPEGMetadata(destType, null, this);
}
inCsType = getSrcCSType(destType);
outCsType = getDefaultDestCSType(destType);
} else {
// no destination type
if (metadata == null) {
if (fullImage) {
// no dest, no metadata, full image
// Use default metadata matching the image and param
metadata = new JPEGMetadata(new ImageTypeSpecifier(rimage), param, this);
if (metadata.findMarkerSegment(JFIFMarkerSegment.class, true) != null) {
cs = rimage.getColorModel().getColorSpace();
if (JPEG.isNonStandardICC(cs)) {
iccProfile = ((ICC_ColorSpace) cs).getProfile();
}
}
inCsType = getSrcCSType(rimage);
outCsType = getDefaultDestCSType(rimage);
}
// else no dest, no metadata, not an image,
// so no special headers, no color conversion
} else {
// no dest type, but there is metadata
checkSOFBands(sof, numBandsUsed);
if (fullImage) {
// no dest, metadata, image
// Check that the metadata and the image match
ImageTypeSpecifier inputType = new ImageTypeSpecifier(rimage);
inCsType = getSrcCSType(rimage);
if (cm != null) {
boolean alpha = cm.hasAlpha();
switch(cs.getType()) {
case ColorSpace.TYPE_GRAY:
if (!alpha) {
outCsType = JPEG.JCS_GRAYSCALE;
} else {
if (jfif != null) {
ignoreJFIF = true;
warningOccurred(WARNING_IMAGE_METADATA_JFIF_MISMATCH);
}
// out colorspace remains unknown
}
if ((adobe != null) && (adobe.transform != JPEG.ADOBE_UNKNOWN)) {
newAdobeTransform = JPEG.ADOBE_UNKNOWN;
warningOccurred(WARNING_IMAGE_METADATA_ADOBE_MISMATCH);
}
break;
case ColorSpace.TYPE_RGB:
if (!alpha) {
if (jfif != null) {
outCsType = JPEG.JCS_YCbCr;
if (JPEG.isNonStandardICC(cs) || ((cs instanceof ICC_ColorSpace) && (jfif.iccSegment != null))) {
iccProfile = ((ICC_ColorSpace) cs).getProfile();
}
} else if (adobe != null) {
switch(adobe.transform) {
case JPEG.ADOBE_UNKNOWN:
outCsType = JPEG.JCS_RGB;
break;
case JPEG.ADOBE_YCC:
outCsType = JPEG.JCS_YCbCr;
break;
default:
warningOccurred(WARNING_IMAGE_METADATA_ADOBE_MISMATCH);
newAdobeTransform = JPEG.ADOBE_UNKNOWN;
outCsType = JPEG.JCS_RGB;
break;
}
} else {
// consult the ids
int outCS = sof.getIDencodedCSType();
// consult the sampling factors
if (outCS != JPEG.JCS_UNKNOWN) {
outCsType = outCS;
} else {
boolean subsampled = isSubsampled(sof.componentSpecs);
if (subsampled) {
outCsType = JPEG.JCS_YCbCr;
} else {
outCsType = JPEG.JCS_RGB;
}
}
}
} else {
// RGBA
if (jfif != null) {
ignoreJFIF = true;
warningOccurred(WARNING_IMAGE_METADATA_JFIF_MISMATCH);
}
if (adobe != null) {
if (adobe.transform != JPEG.ADOBE_UNKNOWN) {
newAdobeTransform = JPEG.ADOBE_UNKNOWN;
warningOccurred(WARNING_IMAGE_METADATA_ADOBE_MISMATCH);
}
outCsType = JPEG.JCS_RGBA;
} else {
// consult the ids
int outCS = sof.getIDencodedCSType();
// consult the sampling factors
if (outCS != JPEG.JCS_UNKNOWN) {
outCsType = outCS;
} else {
boolean subsampled = isSubsampled(sof.componentSpecs);
outCsType = subsampled ? JPEG.JCS_YCbCrA : JPEG.JCS_RGBA;
}
}
}
break;
case ColorSpace.TYPE_3CLR:
if (cs == JPEG.JCS.getYCC()) {
if (!alpha) {
if (jfif != null) {
convertTosRGB = true;
convertOp = new ColorConvertOp(cs, JPEG.JCS.sRGB, null);
outCsType = JPEG.JCS_YCbCr;
} else if (adobe != null) {
if (adobe.transform != JPEG.ADOBE_YCC) {
newAdobeTransform = JPEG.ADOBE_YCC;
warningOccurred(WARNING_IMAGE_METADATA_ADOBE_MISMATCH);
}
outCsType = JPEG.JCS_YCC;
} else {
outCsType = JPEG.JCS_YCC;
}
} else {
// PhotoYCCA
if (jfif != null) {
ignoreJFIF = true;
warningOccurred(WARNING_IMAGE_METADATA_JFIF_MISMATCH);
} else if (adobe != null) {
if (adobe.transform != JPEG.ADOBE_UNKNOWN) {
newAdobeTransform = JPEG.ADOBE_UNKNOWN;
warningOccurred(WARNING_IMAGE_METADATA_ADOBE_MISMATCH);
}
}
outCsType = JPEG.JCS_YCCA;
}
}
}
}
}
// else no dest, metadata, not an image. Defaults ok
}
}
boolean metadataProgressive = false;
int[] scans = null;
if (metadata != null) {
if (sof == null) {
sof = (SOFMarkerSegment) metadata.findMarkerSegment(SOFMarkerSegment.class, true);
}
if ((sof != null) && (sof.tag == JPEG.SOF2)) {
metadataProgressive = true;
if (progressiveMode == ImageWriteParam.MODE_COPY_FROM_METADATA) {
// Might still be null
scans = collectScans(metadata, sof);
} else {
numScans = 0;
}
}
if (jfif == null) {
jfif = (JFIFMarkerSegment) metadata.findMarkerSegment(JFIFMarkerSegment.class, true);
}
}
thumbnails = image.getThumbnails();
int numThumbs = image.getNumThumbnails();
forceJFIF = false;
// then thumbnails can be written
if (!writeDefaultJFIF) {
// If there is no metadata, then we can't write thumbnails
if (metadata == null) {
thumbnails = null;
if (numThumbs != 0) {
warningOccurred(WARNING_IGNORING_THUMBS);
}
} else {
// then the user must specify JFIF on the metadata
if (fullImage == false) {
if (jfif == null) {
// Or we can't include thumbnails
thumbnails = null;
if (numThumbs != 0) {
warningOccurred(WARNING_IGNORING_THUMBS);
}
}
} else {
// It is a full image, and there is metadata
if (jfif == null) {
// Can it have JFIF?
if ((outCsType == JPEG.JCS_GRAYSCALE) || (outCsType == JPEG.JCS_YCbCr)) {
if (numThumbs != 0) {
forceJFIF = true;
warningOccurred(WARNING_FORCING_JFIF);
}
} else {
// Nope, not JFIF-compatible
thumbnails = null;
if (numThumbs != 0) {
warningOccurred(WARNING_IGNORING_THUMBS);
}
}
}
}
}
}
// Set up a boolean to indicate whether we need to call back to
// write metadata
boolean haveMetadata = ((metadata != null) || writeDefaultJFIF || writeAdobe);
// Now that we have dealt with metadata, finalize our tables set up
// Are we going to write tables? By default, yes.
boolean writeDQT = true;
boolean writeDHT = true;
// But if the metadata has no tables, no.
DQTMarkerSegment dqt = null;
DHTMarkerSegment dht = null;
int restartInterval = 0;
if (metadata != null) {
dqt = (DQTMarkerSegment) metadata.findMarkerSegment(DQTMarkerSegment.class, true);
dht = (DHTMarkerSegment) metadata.findMarkerSegment(DHTMarkerSegment.class, true);
DRIMarkerSegment dri = (DRIMarkerSegment) metadata.findMarkerSegment(DRIMarkerSegment.class, true);
if (dri != null) {
restartInterval = dri.restartInterval;
}
if (dqt == null) {
writeDQT = false;
}
if (dht == null) {
// Ignored if optimizeHuffman is true
writeDHT = false;
}
}
// to use
if (qTables == null) {
// Get them from metadata, or use defaults
if (dqt != null) {
qTables = collectQTablesFromMetadata(metadata);
} else if (streamQTables != null) {
qTables = streamQTables;
} else if ((jparam != null) && (jparam.areTablesSet())) {
qTables = jparam.getQTables();
} else {
qTables = JPEG.getDefaultQTables();
}
}
// If we are optimizing, we don't want any tables.
if (optimizeHuffman == false) {
// If they were for progressive scans, we can't use them.
if ((dht != null) && (metadataProgressive == false)) {
DCHuffmanTables = collectHTablesFromMetadata(metadata, true);
ACHuffmanTables = collectHTablesFromMetadata(metadata, false);
} else if (streamDCHuffmanTables != null) {
DCHuffmanTables = streamDCHuffmanTables;
ACHuffmanTables = streamACHuffmanTables;
} else if ((jparam != null) && (jparam.areTablesSet())) {
DCHuffmanTables = jparam.getDCHuffmanTables();
ACHuffmanTables = jparam.getACHuffmanTables();
} else {
DCHuffmanTables = JPEG.getDefaultHuffmanTables(true);
ACHuffmanTables = JPEG.getDefaultHuffmanTables(false);
}
}
// By default, ids are 1 - N, no subsampling
int[] componentIds = new int[numBandsUsed];
int[] HsamplingFactors = new int[numBandsUsed];
int[] VsamplingFactors = new int[numBandsUsed];
int[] QtableSelectors = new int[numBandsUsed];
for (int i = 0; i < numBandsUsed; i++) {
// JFIF compatible
componentIds[i] = i + 1;
HsamplingFactors[i] = 1;
VsamplingFactors[i] = 1;
QtableSelectors[i] = 0;
}
// Now override them with the contents of sof, if there is one,
if (sof != null) {
for (int i = 0; i < numBandsUsed; i++) {
if (forceJFIF == false) {
// else use JFIF-compatible default
componentIds[i] = sof.componentSpecs[i].componentId;
}
HsamplingFactors[i] = sof.componentSpecs[i].HsamplingFactor;
VsamplingFactors[i] = sof.componentSpecs[i].VsamplingFactor;
QtableSelectors[i] = sof.componentSpecs[i].QtableSelector;
}
}
sourceXOffset += gridX;
sourceWidth -= gridX;
sourceYOffset += gridY;
sourceHeight -= gridY;
int destWidth = (sourceWidth + periodX - 1) / periodX;
int destHeight = (sourceHeight + periodY - 1) / periodY;
// Create an appropriate 1-line databuffer for writing
int lineSize = sourceWidth * numBandsUsed;
DataBufferByte buffer = new DataBufferByte(lineSize);
// Create a raster from that
int[] bandOffs = JPEG.bandOffsets[numBandsUsed - 1];
raster = Raster.createInterleavedRaster(buffer, sourceWidth, 1, lineSize, numBandsUsed, bandOffs, null);
// Call the writer, who will call back for every scanline
clearAbortRequest();
cbLock.lock();
try {
processImageStarted(currentImage);
} finally {
cbLock.unlock();
}
boolean aborted = false;
if (debug) {
System.out.println("inCsType: " + inCsType);
System.out.println("outCsType: " + outCsType);
}
// Note that getData disables acceleration on buffer, but it is
// just a 1-line intermediate data transfer buffer that does not
// affect the acceleration of the source image.
aborted = writeImage(structPointer, buffer.getData(), inCsType, outCsType, numBandsUsed, bandSizes, sourceWidth, destWidth, destHeight, periodX, periodY, qTables, writeDQT, DCHuffmanTables, ACHuffmanTables, writeDHT, optimizeHuffman, (progressiveMode != ImageWriteParam.MODE_DISABLED), numScans, scans, componentIds, HsamplingFactors, VsamplingFactors, QtableSelectors, haveMetadata, restartInterval);
cbLock.lock();
try {
if (aborted) {
processWriteAborted();
} else {
processImageComplete();
}
ios.flush();
} finally {
cbLock.unlock();
}
// After a successful write
currentImage++;
}
use of java.awt.color.ColorSpace in project jdk8u_jdk by JetBrains.
the class JPEGImageWriter method getDefaultDestCSType.
private int getDefaultDestCSType(ColorModel cm) {
int retval = JPEG.JCS_UNKNOWN;
if (cm != null) {
boolean alpha = cm.hasAlpha();
ColorSpace cs = cm.getColorSpace();
switch(cs.getType()) {
case ColorSpace.TYPE_GRAY:
retval = JPEG.JCS_GRAYSCALE;
break;
case ColorSpace.TYPE_RGB:
if (alpha) {
retval = JPEG.JCS_YCbCrA;
} else {
retval = JPEG.JCS_YCbCr;
}
break;
case ColorSpace.TYPE_YCbCr:
if (alpha) {
retval = JPEG.JCS_YCbCrA;
} else {
retval = JPEG.JCS_YCbCr;
}
break;
case ColorSpace.TYPE_3CLR:
if (cs == JPEG.JCS.getYCC()) {
if (alpha) {
retval = JPEG.JCS_YCCA;
} else {
retval = JPEG.JCS_YCC;
}
}
case ColorSpace.TYPE_CMYK:
retval = JPEG.JCS_YCCK;
break;
}
}
return retval;
}
use of java.awt.color.ColorSpace in project jdk8u_jdk by JetBrains.
the class ImageTypeProducer method checkColorConversion.
/**
* Checks the implied color conversion between the stream and
* the target image, altering the IJG output color space if necessary.
* If a java color conversion is required, then this sets up
* <code>convert</code>.
* If bands are being rearranged at all (either source or destination
* bands are specified in the param), then the default color
* conversions are assumed to be correct.
* Throws an IIOException if there is no conversion available.
*/
private void checkColorConversion(BufferedImage image, ImageReadParam param) throws IIOException {
// a Raster.
if (param != null) {
if ((param.getSourceBands() != null) || (param.getDestinationBands() != null)) {
// Accept default conversions out of decoder, silently
return;
}
}
// XXX - We do not currently support any indexed color models,
// though we could, as IJG will quantize for us.
// This is a performance and memory-use issue, as
// users can read RGB and then convert to indexed in Java.
ColorModel cm = image.getColorModel();
if (cm instanceof IndexColorModel) {
throw new IIOException("IndexColorModel not supported");
}
// Now check the ColorSpace type against outColorSpaceCode
// We may want to tweak the default
ColorSpace cs = cm.getColorSpace();
int csType = cs.getType();
convert = null;
switch(outColorSpaceCode) {
case // Its gray in the file
JPEG.JCS_GRAYSCALE:
if (csType == ColorSpace.TYPE_RGB) {
// We want RGB
// IJG can do this for us more efficiently
setOutColorSpace(structPointer, JPEG.JCS_RGB);
// Update java state according to changes
// in the native part of decoder.
outColorSpaceCode = JPEG.JCS_RGB;
numComponents = 3;
} else if (csType != ColorSpace.TYPE_GRAY) {
throw new IIOException("Incompatible color conversion");
}
break;
case // IJG wants to go to RGB
JPEG.JCS_RGB:
if (csType == ColorSpace.TYPE_GRAY) {
// We want gray
if (colorSpaceCode == JPEG.JCS_YCbCr) {
// If the jpeg space is YCbCr, IJG can do it
setOutColorSpace(structPointer, JPEG.JCS_GRAYSCALE);
// Update java state according to changes
// in the native part of decoder.
outColorSpaceCode = JPEG.JCS_GRAYSCALE;
numComponents = 1;
}
} else if ((iccCS != null) && (cm.getNumComponents() == numComponents) && (cs != iccCS)) {
// We have an ICC profile but it isn't used in the dest
// image. So convert from the profile cs to the target cs
convert = new ColorConvertOp(iccCS, cs, null);
// Leave IJG conversion in place; we still need it
} else if ((iccCS == null) && (!cs.isCS_sRGB()) && (cm.getNumComponents() == numComponents)) {
// Target isn't sRGB, so convert from sRGB to the target
convert = new ColorConvertOp(JPEG.JCS.sRGB, cs, null);
} else if (csType != ColorSpace.TYPE_RGB) {
throw new IIOException("Incompatible color conversion");
}
break;
case JPEG.JCS_RGBA:
// No conversions available; image must be RGBA
if ((csType != ColorSpace.TYPE_RGB) || (cm.getNumComponents() != numComponents)) {
throw new IIOException("Incompatible color conversion");
}
break;
case JPEG.JCS_YCC:
{
ColorSpace YCC = JPEG.JCS.getYCC();
if (YCC == null) {
// We can't do YCC at all
throw new IIOException("Incompatible color conversion");
}
if ((cs != YCC) && (cm.getNumComponents() == numComponents)) {
convert = new ColorConvertOp(YCC, cs, null);
}
}
break;
case JPEG.JCS_YCCA:
{
ColorSpace YCC = JPEG.JCS.getYCC();
// No conversions available; image must be YCCA
if (// We can't do YCC at all
(YCC == null) || (cs != YCC) || (cm.getNumComponents() != numComponents)) {
throw new IIOException("Incompatible color conversion");
}
}
break;
default:
// Anything else we can't handle at all
throw new IIOException("Incompatible color conversion");
}
}
use of java.awt.color.ColorSpace in project jdk8u_jdk by JetBrains.
the class JFIFMarkerSegment method writeThumb.
private void writeThumb(ImageOutputStream ios, BufferedImage thumb, JFIFExtensionMarkerSegment jfxx, int index, boolean onlyOne, JPEGImageWriter writer) throws IOException {
ColorModel cm = thumb.getColorModel();
ColorSpace cs = cm.getColorSpace();
if (cm instanceof IndexColorModel) {
// So if it's the only one, we need to write the header first
if (onlyOne) {
write(ios, writer);
}
if ((jfxx == null) || (jfxx.code == THUMB_PALETTE)) {
// default
writeJFXXSegment(index, thumb, ios, writer);
} else {
// Expand to RGB
BufferedImage thumbRGB = ((IndexColorModel) cm).convertToIntDiscrete(thumb.getRaster(), false);
jfxx.setThumbnail(thumbRGB);
writer.thumbnailStarted(index);
// Handles clipping if needed
jfxx.write(ios, writer);
writer.thumbnailComplete();
}
} else if (cs.getType() == ColorSpace.TYPE_RGB) {
if (jfxx == null) {
if (onlyOne) {
// As part of the header
write(ios, thumb, writer);
} else {
// default
writeJFXXSegment(index, thumb, ios, writer);
}
} else {
// If this is the only one, write the header first
if (onlyOne) {
write(ios, writer);
}
if (jfxx.code == THUMB_PALETTE) {
// default
writeJFXXSegment(index, thumb, ios, writer);
writer.warningOccurred(JPEGImageWriter.WARNING_NO_RGB_THUMB_AS_INDEXED);
} else {
jfxx.setThumbnail(thumb);
writer.thumbnailStarted(index);
// Handles clipping if needed
jfxx.write(ios, writer);
writer.thumbnailComplete();
}
}
} else if (cs.getType() == ColorSpace.TYPE_GRAY) {
if (jfxx == null) {
if (onlyOne) {
BufferedImage thumbRGB = expandGrayThumb(thumb);
// As part of the header
write(ios, thumbRGB, writer);
} else {
// default
writeJFXXSegment(index, thumb, ios, writer);
}
} else {
// If this is the only one, write the header first
if (onlyOne) {
write(ios, writer);
}
if (jfxx.code == THUMB_RGB) {
BufferedImage thumbRGB = expandGrayThumb(thumb);
writeJFXXSegment(index, thumbRGB, ios, writer);
} else if (jfxx.code == THUMB_JPEG) {
jfxx.setThumbnail(thumb);
writer.thumbnailStarted(index);
// Handles clipping if needed
jfxx.write(ios, writer);
writer.thumbnailComplete();
} else if (jfxx.code == THUMB_PALETTE) {
// default
writeJFXXSegment(index, thumb, ios, writer);
writer.warningOccurred(JPEGImageWriter.WARNING_NO_GRAY_THUMB_AS_INDEXED);
}
}
} else {
writer.warningOccurred(JPEGImageWriter.WARNING_ILLEGAL_THUMBNAIL);
}
}
use of java.awt.color.ColorSpace in project imageio-ext by geosolutions-it.
the class PNMImageWriter method write.
public void write(IIOMetadata streamMetadata, IIOImage image, ImageWriteParam param) throws IOException {
clearAbortRequest();
processImageStarted(0);
if (param == null)
param = getDefaultWriteParam();
RenderedImage input = null;
Raster inputRaster = null;
boolean writeRaster = image.hasRaster();
Rectangle sourceRegion = param.getSourceRegion();
SampleModel sampleModel = null;
ColorModel colorModel = null;
if (writeRaster) {
inputRaster = image.getRaster();
sampleModel = inputRaster.getSampleModel();
if (sourceRegion == null)
sourceRegion = inputRaster.getBounds();
else
sourceRegion = sourceRegion.intersection(inputRaster.getBounds());
} else {
input = image.getRenderedImage();
sampleModel = input.getSampleModel();
colorModel = input.getColorModel();
Rectangle rect = new Rectangle(input.getMinX(), input.getMinY(), input.getWidth(), input.getHeight());
if (sourceRegion == null)
sourceRegion = rect;
else
sourceRegion = sourceRegion.intersection(rect);
}
if (sourceRegion.isEmpty())
throw new RuntimeException(I18N.getString("PNMImageWrite1"));
ImageUtil.canEncodeImage(this, colorModel, sampleModel);
int scaleX = param.getSourceXSubsampling();
int scaleY = param.getSourceYSubsampling();
int xOffset = param.getSubsamplingXOffset();
int yOffset = param.getSubsamplingYOffset();
sourceRegion.translate(xOffset, yOffset);
sourceRegion.width -= xOffset;
sourceRegion.height -= yOffset;
int w = (sourceRegion.width + scaleX - 1) / scaleX;
int h = (sourceRegion.height + scaleY - 1) / scaleY;
int tileWidth = sampleModel.getWidth();
// Raw data can only handle bytes, everything greater must be ASCII.
int[] sampleSize = sampleModel.getSampleSize();
int[] sourceBands = param.getSourceBands();
int numBands = sampleModel.getNumBands();
if (sourceBands != null) {
sampleModel = sampleModel.createSubsetSampleModel(sourceBands);
colorModel = null;
numBands = sampleModel.getNumBands();
} else {
sourceBands = new int[numBands];
for (int i = 0; i < numBands; i++) sourceBands[i] = i;
}
// Colormap populated for non-bilevel IndexColorModel only.
byte[] reds = null;
byte[] greens = null;
byte[] blues = null;
// Flag indicating that PB data should be inverted before writing.
boolean isPBMInverted = false;
if (numBands == 1) {
if (colorModel instanceof IndexColorModel) {
IndexColorModel icm = (IndexColorModel) colorModel;
int mapSize = icm.getMapSize();
if (mapSize < (1 << sampleSize[0]))
throw new RuntimeException(I18N.getString("PNMImageWrite2"));
if (sampleSize[0] == 1) {
variant = PBM_RAW;
// Set PBM inversion flag if 1 maps to a higher color
// value than 0: PBM expects white-is-zero so if this
// does not obtain then inversion needs to occur.
isPBMInverted = icm.getRed(1) > icm.getRed(0);
} else {
variant = PPM_RAW;
reds = new byte[mapSize];
greens = new byte[mapSize];
blues = new byte[mapSize];
icm.getReds(reds);
icm.getGreens(greens);
icm.getBlues(blues);
}
} else if (sampleSize[0] == 1) {
variant = PBM_RAW;
} else if (sampleSize[0] <= 8) {
variant = PGM_RAW;
} else {
variant = PGM_ASCII;
}
} else if (numBands == 3) {
if (sampleSize[0] <= 8 && sampleSize[1] <= 8 && sampleSize[2] <= 8) {
// all 3 bands must be <= 8
variant = PPM_RAW;
} else {
variant = PPM_ASCII;
}
} else {
throw new RuntimeException(I18N.getString("PNMImageWrite3"));
}
IIOMetadata inputMetadata = image.getMetadata();
ImageTypeSpecifier imageType;
if (colorModel != null) {
imageType = new ImageTypeSpecifier(colorModel, sampleModel);
} else {
int dataType = sampleModel.getDataType();
switch(numBands) {
case 1:
imageType = ImageTypeSpecifier.createGrayscale(sampleSize[0], dataType, false);
break;
case 3:
ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
imageType = ImageTypeSpecifier.createInterleaved(cs, new int[] { 0, 1, 2 }, dataType, false, false);
break;
default:
throw new IIOException("Cannot encode image with " + numBands + " bands!");
}
}
PNMMetadata metadata;
if (inputMetadata != null) {
// Convert metadata.
metadata = (PNMMetadata) convertImageMetadata(inputMetadata, imageType, param);
} else {
// Use default.
metadata = (PNMMetadata) getDefaultImageMetadata(imageType, param);
}
// Read parameters
boolean isRawPNM;
if (param instanceof PNMImageWriteParam) {
isRawPNM = ((PNMImageWriteParam) param).getRaw();
} else {
isRawPNM = metadata.isRaw();
}
maxValue = metadata.getMaxValue();
for (int i = 0; i < sampleSize.length; i++) {
int v = (1 << sampleSize[i]) - 1;
if (v > maxValue) {
maxValue = v;
}
}
if (isRawPNM) {
// Raw output is desired.
int maxBitDepth = metadata.getMaxBitDepth();
if (!isRaw(variant) && maxBitDepth <= 8) {
// Current variant is ASCII and the bit depth is acceptable
// so convert to RAW variant by adding '3' to variant.
variant += 0x3;
} else if (isRaw(variant) && maxBitDepth > 8) {
// Current variant is RAW and the bit depth it too large for
// RAW so convert to ASCII.
variant -= 0x3;
}
// Omitted cases are (variant == RAW && max <= 8) and
// (variant == ASCII && max > 8) neither of which requires action.
} else if (isRaw(variant)) {
// Raw output is NOT desired so convert to ASCII
variant -= 0x3;
}
// Write PNM file.
// magic value: 'P'
stream.writeByte('P');
stream.writeByte(variant);
stream.write(lineSeparator);
// comment line
stream.write(COMMENT.getBytes());
// Write the comments provided in the metadata
Iterator comments = metadata.getComments();
if (comments != null) {
while (comments.hasNext()) {
stream.write(lineSeparator);
String comment = "# " + (String) comments.next();
stream.write(comment.getBytes());
}
}
stream.write(lineSeparator);
// width
writeInteger(stream, w);
stream.write(SPACE);
// height
writeInteger(stream, h);
// Write sample max value for non-binary images
if ((variant != PBM_RAW) && (variant != PBM_ASCII)) {
stream.write(lineSeparator);
writeInteger(stream, maxValue);
}
// last header value and the start of the raw data.
if (variant == PBM_RAW || variant == PGM_RAW || variant == PPM_RAW) {
stream.write('\n');
}
// Set flag for optimal image writing case: row-packed data with
// correct band order if applicable.
boolean writeOptimal = false;
if (variant == PBM_RAW && sampleModel.getTransferType() == DataBuffer.TYPE_BYTE && sampleModel instanceof MultiPixelPackedSampleModel) {
MultiPixelPackedSampleModel mppsm = (MultiPixelPackedSampleModel) sampleModel;
int originX = 0;
if (writeRaster)
originX = inputRaster.getMinX();
else
originX = input.getMinX();
// Must have left-aligned bytes with unity bit stride.
if (mppsm.getBitOffset((sourceRegion.x - originX) % tileWidth) == 0 && mppsm.getPixelBitStride() == 1 && scaleX == 1)
writeOptimal = true;
} else if ((variant == PGM_RAW || variant == PPM_RAW) && sampleModel instanceof ComponentSampleModel && !(colorModel instanceof IndexColorModel)) {
ComponentSampleModel csm = (ComponentSampleModel) sampleModel;
// Pixel stride must equal band count.
if (csm.getPixelStride() == numBands && scaleX == 1) {
writeOptimal = true;
// Band offsets must equal band indices.
if (variant == PPM_RAW) {
int[] bandOffsets = csm.getBandOffsets();
for (int b = 0; b < numBands; b++) {
if (bandOffsets[b] != b) {
writeOptimal = false;
break;
}
}
}
}
}
// Write using an optimal approach if possible.
if (writeOptimal) {
int bytesPerRow = variant == PBM_RAW ? (w + 7) / 8 : w * sampleModel.getNumBands();
byte[] bdata = null;
byte[] invertedData = new byte[bytesPerRow];
// Loop over tiles to minimize cobbling.
for (int j = 0; j < sourceRegion.height; j++) {
if (abortRequested())
break;
Raster lineRaster = null;
if (writeRaster) {
lineRaster = inputRaster.createChild(sourceRegion.x, j, sourceRegion.width, 1, 0, 0, null);
} else {
lineRaster = input.getData(new Rectangle(sourceRegion.x, sourceRegion.y + j, w, 1));
lineRaster = lineRaster.createTranslatedChild(0, 0);
}
bdata = ((DataBufferByte) lineRaster.getDataBuffer()).getData();
sampleModel = lineRaster.getSampleModel();
int offset = 0;
if (sampleModel instanceof ComponentSampleModel) {
offset = ((ComponentSampleModel) sampleModel).getOffset(lineRaster.getMinX() - lineRaster.getSampleModelTranslateX(), lineRaster.getMinY() - lineRaster.getSampleModelTranslateY());
} else if (sampleModel instanceof MultiPixelPackedSampleModel) {
offset = ((MultiPixelPackedSampleModel) sampleModel).getOffset(lineRaster.getMinX() - lineRaster.getSampleModelTranslateX(), lineRaster.getMinX() - lineRaster.getSampleModelTranslateY());
}
if (isPBMInverted) {
for (int k = offset, m = 0; m < bytesPerRow; k++, m++) invertedData[m] = (byte) ~bdata[k];
bdata = invertedData;
offset = 0;
}
stream.write(bdata, offset, bytesPerRow);
processImageProgress(100.0F * j / sourceRegion.height);
}
// Write all buffered bytes and return.
stream.flush();
if (abortRequested())
processWriteAborted();
else
processImageComplete();
return;
}
// Buffer for 1 rows of original pixels
int size = sourceRegion.width * numBands;
int[] pixels = new int[size];
// Also allocate a buffer to hold the data to be written to the file,
// so we can use array writes.
byte[] bpixels = reds == null ? new byte[w * numBands] : new byte[w * 3];
// The index of the sample being written, used to
// place a line separator after every 16th sample in
// ASCII mode. Not used in raw mode.
int count = 0;
// Process line by line
int lastRow = sourceRegion.y + sourceRegion.height;
for (int row = sourceRegion.y; row < lastRow; row += scaleY) {
if (abortRequested())
break;
// Grab the pixels
Raster src = null;
if (writeRaster)
src = inputRaster.createChild(sourceRegion.x, row, sourceRegion.width, 1, sourceRegion.x, row, sourceBands);
else
src = input.getData(new Rectangle(sourceRegion.x, row, sourceRegion.width, 1));
src.getPixels(sourceRegion.x, row, sourceRegion.width, 1, pixels);
if (isPBMInverted)
for (int i = 0; i < size; i += scaleX) bpixels[i] ^= 1;
switch(variant) {
case PBM_ASCII:
for (int i = 0; i < size; i += scaleX) {
if ((count++ % 16) == 0)
stream.write(lineSeparator);
else
stream.write(SPACE);
writeInteger(stream, isPBMInverted ? (byte) ~pixels[i] : pixels[i]);
}
stream.write(lineSeparator);
break;
case PGM_ASCII:
for (int i = 0; i < size; i += scaleX) {
if ((count++ % 16) == 0)
stream.write(lineSeparator);
else
stream.write(SPACE);
writeInteger(stream, pixels[i]);
}
stream.write(lineSeparator);
break;
case PPM_ASCII:
if (reds == null) {
for (int i = 0; i < size; i += scaleX * numBands) {
for (int j = 0; j < numBands; j++) {
if ((count++ % 16) == 0)
stream.write(lineSeparator);
else
stream.write(SPACE);
writeInteger(stream, pixels[i + j]);
}
}
} else {
for (int i = 0; i < size; i += scaleX) {
if ((count++ % 5) == 0)
stream.write(lineSeparator);
else
stream.write(SPACE);
writeInteger(stream, (reds[pixels[i]] & 0xFF));
stream.write(SPACE);
writeInteger(stream, (greens[pixels[i]] & 0xFF));
stream.write(SPACE);
writeInteger(stream, (blues[pixels[i]] & 0xFF));
}
}
stream.write(lineSeparator);
break;
case PBM_RAW:
// 8 pixels packed into 1 byte, the leftovers are padded.
int kdst = 0;
int b = 0;
int pos = 7;
for (int i = 0; i < size; i += scaleX) {
b |= pixels[i] << pos;
pos--;
if (pos == -1) {
bpixels[kdst++] = (byte) b;
b = 0;
pos = 7;
}
}
if (pos != 7)
bpixels[kdst++] = (byte) b;
stream.write(bpixels, 0, kdst);
break;
case PGM_RAW:
for (int i = 0, j = 0; i < size; i += scaleX) {
bpixels[j++] = (byte) (pixels[i]);
}
stream.write(bpixels, 0, w);
break;
case PPM_RAW:
if (reds == null) {
// no need to expand
for (int i = 0, k = 0; i < size; i += scaleX * numBands) {
for (int j = 0; j < numBands; j++) bpixels[k++] = (byte) (pixels[i + j] & 0xFF);
}
} else {
for (int i = 0, j = 0; i < size; i += scaleX) {
bpixels[j++] = reds[pixels[i]];
bpixels[j++] = greens[pixels[i]];
bpixels[j++] = blues[pixels[i]];
}
}
stream.write(bpixels, 0, bpixels.length);
break;
}
processImageProgress(100.0F * (row - sourceRegion.y) / sourceRegion.height);
}
// Force all buffered bytes to be written out.
stream.flush();
if (abortRequested())
processWriteAborted();
else
processImageComplete();
}
Aggregations