org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of pdfbox Show documentation
Show all versions of pdfbox Show documentation
The Apache PDFBox library is an open source Java tool for working with PDF documents.
/*
* 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.pdmodel.graphics.color;
import org.apache.pdfbox.cos.COSBase;
import org.apache.pdfbox.cos.COSArray;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.cos.COSObject;
import org.apache.pdfbox.pdmodel.MissingResourceException;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.common.COSObjectable;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.awt.image.ComponentColorModel;
import java.awt.image.WritableRaster;
import java.io.IOException;
import java.awt.color.ColorSpace;
import java.awt.image.ColorModel;
/**
* A color space specifies how the colours of graphics objects will be painted on the page.
*
* @author John Hewson
* @author Ben Litchfield
*/
public abstract class PDColorSpace implements COSObjectable
{
/**
* Creates a color space space given a name or array.
* @param colorSpace the color space COS object
* @return a new color space
* @throws IOException if the color space is unknown or cannot be created
*/
public static PDColorSpace create(COSBase colorSpace) throws IOException
{
return create(colorSpace, null);
}
/**
* Creates a color space given a name or array. Abbreviated device color names are not supported
* here, please replace them first.
*
* @param colorSpace the color space COS object
* @param resources the current resources.
* @return a new color space
* @throws MissingResourceException if the color space is missing in the resources dictionary
* @throws IOException if the color space is unknown or cannot be created
*/
public static PDColorSpace create(COSBase colorSpace,
PDResources resources)
throws IOException
{
return create(colorSpace, resources, false);
}
/**
* Creates a color space given a name or array. Abbreviated device color names are not supported
* here, please replace them first. This method is for PDFBox internal use only, others should
* use {@link #create(COSBase, PDResources)}.
*
* @param colorSpace the color space COS object
* @param resources the current resources.
* @param wasDefault if current color space was used by a default color space.
* @return a new color space.
* @throws MissingResourceException if the color space is missing in the resources dictionary
* @throws IOException if the color space is unknown or cannot be created.
*/
public static PDColorSpace create(COSBase colorSpace,
PDResources resources,
boolean wasDefault)
throws IOException
{
if (colorSpace instanceof COSObject)
{
return create(((COSObject) colorSpace).getObject(), resources);
}
else if (colorSpace instanceof COSName)
{
COSName name = (COSName)colorSpace;
// default color spaces
if (resources != null)
{
COSName defaultName = null;
if (name.equals(COSName.DEVICECMYK) &&
resources.hasColorSpace(COSName.DEFAULT_CMYK))
{
defaultName = COSName.DEFAULT_CMYK;
}
else if (name.equals(COSName.DEVICERGB) &&
resources.hasColorSpace(COSName.DEFAULT_RGB))
{
defaultName = COSName.DEFAULT_RGB;
}
else if (name.equals(COSName.DEVICEGRAY) &&
resources.hasColorSpace(COSName.DEFAULT_GRAY))
{
defaultName = COSName.DEFAULT_GRAY;
}
if (resources.hasColorSpace(defaultName) && !wasDefault)
{
return resources.getColorSpace(defaultName, true);
}
}
// built-in color spaces
if (name == COSName.DEVICECMYK)
{
return PDDeviceCMYK.INSTANCE;
}
else if (name == COSName.DEVICERGB)
{
return PDDeviceRGB.INSTANCE;
}
else if (name == COSName.DEVICEGRAY)
{
return PDDeviceGray.INSTANCE;
}
else if (name == COSName.PATTERN)
{
return new PDPattern(resources);
}
else if (resources != null)
{
if (!resources.hasColorSpace(name))
{
throw new MissingResourceException("Missing color space: " + name.getName());
}
return resources.getColorSpace(name);
}
else
{
throw new MissingResourceException("Unknown color space: " + name.getName());
}
}
else if (colorSpace instanceof COSArray)
{
COSArray array = (COSArray)colorSpace;
COSName name = (COSName)array.getObject(0);
// TODO cache these returned color spaces?
if (name == COSName.CALGRAY)
{
return new PDCalGray(array);
}
else if (name == COSName.CALRGB)
{
return new PDCalRGB(array);
}
else if (name == COSName.DEVICEN)
{
return new PDDeviceN(array);
}
else if (name == COSName.INDEXED)
{
return new PDIndexed(array);
}
else if (name == COSName.SEPARATION)
{
return new PDSeparation(array);
}
else if (name == COSName.ICCBASED)
{
return new PDICCBased(array);
}
else if (name == COSName.LAB)
{
return new PDLab(array);
}
else if (name == COSName.PATTERN)
{
if (array.size() == 1)
{
return new PDPattern(resources);
}
else
{
return new PDPattern(resources, PDColorSpace.create(array.get(1)));
}
}
else if (name == COSName.DEVICECMYK ||
name == COSName.DEVICERGB ||
name == COSName.DEVICEGRAY)
{
// not allowed in an array, but we sometimes encounter these regardless
return create(name, resources, wasDefault);
}
else
{
throw new IOException("Invalid color space kind: " + name);
}
}
else
{
throw new IOException("Expected a name or array but got: " + colorSpace);
}
}
// array for the given parameters
protected COSArray array;
/**
* Returns the name of the color space.
* @return the name of the color space
*/
public abstract String getName();
/**
* Returns the number of components in this color space
* @return the number of components in this color space
*/
public abstract int getNumberOfComponents();
/**
* Returns the default decode array for this color space.
* @param bitsPerComponent the number of bits per component.
* @return the default decode array
*/
public abstract float[] getDefaultDecode(int bitsPerComponent);
/**
* Returns the initial color value for this color space.
* @return the initial color value for this color space
*/
public abstract PDColor getInitialColor();
/**
* Returns the RGB equivalent of the given color value.
* @param value a color value with component values between 0 and 1
* @return an array of R,G,B value between 0 and 255
* @throws IOException if the color conversion fails
*/
public abstract float[] toRGB(float[] value) throws IOException;
/**
* Returns the (A)RGB equivalent of the given raster.
* @param raster the source raster
* @return an (A)RGB buffered image
* @throws IOException if the color conversion fails
*/
public abstract BufferedImage toRGBImage(WritableRaster raster) throws IOException;
/**
* Returns the (A)RGB equivalent of the given raster, using the given AWT color space
* to perform the conversion.
* @param raster the source raster
* @param colorSpace the AWT
* @return an (A)RGB buffered image
*/
protected BufferedImage toRGBImageAWT(WritableRaster raster, ColorSpace colorSpace)
{
//
// WARNING: this method is performance sensitive, modify with care!
//
// ICC Profile color transforms are only fast when performed using ColorConvertOp
ColorModel colorModel = new ComponentColorModel(colorSpace,
false, false, Transparency.OPAQUE, raster.getDataBuffer().getDataType());
BufferedImage src = new BufferedImage(colorModel, raster, false, null);
BufferedImage dest = new BufferedImage(raster.getWidth(), raster.getHeight(),
BufferedImage.TYPE_INT_RGB);
ColorConvertOp op = new ColorConvertOp(null);
op.filter(src, dest);
return dest;
}
@Override
public COSBase getCOSObject()
{
return array;
}
}