mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-08-05 12:35:29 -04:00
#573: Always return RAWImageType for JPEG.
+ Bonus: Fix luma to gray conversion
This commit is contained in:
parent
b67975eef7
commit
419ffc9373
@ -97,10 +97,6 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
|
|
||||||
protected abstract List<String> getMIMETypes();
|
protected abstract List<String> getMIMETypes();
|
||||||
|
|
||||||
protected boolean allowsNullRawImageType() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static void failBecause(String message, Throwable exception) {
|
protected static void failBecause(String message, Throwable exception) {
|
||||||
throw new AssertionError(message, exception);
|
throw new AssertionError(message, exception);
|
||||||
}
|
}
|
||||||
@ -221,6 +217,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
image = reader.read(i);
|
image = reader.read(i);
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
failBecause(String.format("Image %s index %s could not be read: %s", data.getInput(), i, e), e);
|
failBecause(String.format("Image %s index %s could not be read: %s", data.getInput(), i, e), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1359,9 +1356,6 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
reader.setInput(data.getInputStream());
|
reader.setInput(data.getInputStream());
|
||||||
|
|
||||||
ImageTypeSpecifier rawType = reader.getRawImageType(0);
|
ImageTypeSpecifier rawType = reader.getRawImageType(0);
|
||||||
if (rawType == null && allowsNullRawImageType()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
assertNotNull(rawType);
|
assertNotNull(rawType);
|
||||||
|
|
||||||
Iterator<ImageTypeSpecifier> types = reader.getImageTypes(0);
|
Iterator<ImageTypeSpecifier> types = reader.getImageTypes(0);
|
||||||
@ -1383,6 +1377,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
|
|
||||||
assertTrue("ImageTypeSpecifier from getRawImageType should be in the iterator from getImageTypes", rawFound);
|
assertTrue("ImageTypeSpecifier from getRawImageType should be in the iterator from getImageTypes", rawFound);
|
||||||
}
|
}
|
||||||
|
|
||||||
reader.dispose();
|
reader.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,6 +62,7 @@ class FastCMYKToRGB implements /*BufferedImageOp,*/ RasterOp {
|
|||||||
* @return {@code dest}, or a new {@link WritableRaster} if {@code dest} is {@code null}.
|
* @return {@code dest}, or a new {@link WritableRaster} if {@code dest} is {@code null}.
|
||||||
* @throws IllegalArgumentException if {@code src} and {@code dest} refer to the same object
|
* @throws IllegalArgumentException if {@code src} and {@code dest} refer to the same object
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public WritableRaster filter(Raster src, WritableRaster dest) {
|
public WritableRaster filter(Raster src, WritableRaster dest) {
|
||||||
Validate.notNull(src, "src may not be null");
|
Validate.notNull(src, "src may not be null");
|
||||||
// TODO: Why not allow same raster, if converting to 4 byte ABGR?
|
// TODO: Why not allow same raster, if converting to 4 byte ABGR?
|
||||||
@ -142,10 +143,12 @@ class FastCMYKToRGB implements /*BufferedImageOp,*/ RasterOp {
|
|||||||
rgb[2] = (byte) (255 - (((cmyk[2] & 0xFF) * (255 - k) / 255) + k));
|
rgb[2] = (byte) (255 - (((cmyk[2] & 0xFF) * (255 - k) / 255) + k));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Rectangle2D getBounds2D(Raster src) {
|
public Rectangle2D getBounds2D(Raster src) {
|
||||||
return src.getBounds();
|
return src.getBounds();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public WritableRaster createCompatibleDestRaster(final Raster src) {
|
public WritableRaster createCompatibleDestRaster(final Raster src) {
|
||||||
// WHAT?? This code no longer work for JRE 7u45+... JRE bug?!
|
// WHAT?? This code no longer work for JRE 7u45+... JRE bug?!
|
||||||
// Raster child = src.createChild(0, 0, src.getWidth(), src.getHeight(), 0, 0, new int[] {0, 1, 2});
|
// Raster child = src.createChild(0, 0, src.getWidth(), src.getHeight(), 0, 0, new int[] {0, 1, 2});
|
||||||
@ -157,6 +160,7 @@ class FastCMYKToRGB implements /*BufferedImageOp,*/ RasterOp {
|
|||||||
return raster.createWritableChild(0, 0, src.getWidth(), src.getHeight(), 0, 0, new int[] {0, 1, 2});
|
return raster.createWritableChild(0, 0, src.getWidth(), src.getHeight(), 0, 0, new int[] {0, 1, 2});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Point2D getPoint2D(Point2D srcPt, Point2D dstPt) {
|
public Point2D getPoint2D(Point2D srcPt, Point2D dstPt) {
|
||||||
if (dstPt == null) {
|
if (dstPt == null) {
|
||||||
dstPt = new Point2D.Double(srcPt.getX(), srcPt.getY());
|
dstPt = new Point2D.Double(srcPt.getX(), srcPt.getY());
|
||||||
@ -168,6 +172,7 @@ class FastCMYKToRGB implements /*BufferedImageOp,*/ RasterOp {
|
|||||||
return dstPt;
|
return dstPt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public RenderingHints getRenderingHints() {
|
public RenderingHints getRenderingHints() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -194,73 +194,38 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex) throws IOException {
|
public Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex) throws IOException {
|
||||||
checkBounds(imageIndex);
|
ImageTypeSpecifier rawImageType = getRawImageType(imageIndex);
|
||||||
initHeader(imageIndex);
|
ColorModel rawColorModel = rawImageType.getColorModel();
|
||||||
|
JPEGColorSpace sourceCSType = getSourceCSType(getJFIF(), getAdobeDCT(), getSOF());
|
||||||
|
|
||||||
Iterator<ImageTypeSpecifier> types;
|
Set<ImageTypeSpecifier> types = new LinkedHashSet<>();
|
||||||
try {
|
|
||||||
types = delegate.getImageTypes(0);
|
|
||||||
}
|
|
||||||
catch (IndexOutOfBoundsException | NegativeArraySizeException ignore) {
|
|
||||||
types = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
JPEGColorSpace csType = getSourceCSType(getJFIF(), getAdobeDCT(), getSOF());
|
if (rawColorModel.getColorSpace().getType() != ColorSpace.TYPE_GRAY) {
|
||||||
|
// Add the standard types, we can always convert to these, except for gray
|
||||||
if (types == null || !types.hasNext() || csType == JPEGColorSpace.CMYK || csType == JPEGColorSpace.YCCK) {
|
if (rawColorModel.hasAlpha()) {
|
||||||
ArrayList<ImageTypeSpecifier> typeList = new ArrayList<>();
|
types.add(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_INT_ARGB));
|
||||||
// Add the standard types, we can always convert to these
|
types.add(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_4BYTE_ABGR));
|
||||||
typeList.add(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_3BYTE_BGR));
|
types.add(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_INT_ARGB_PRE));
|
||||||
typeList.add(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB));
|
types.add(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_4BYTE_ABGR_PRE));
|
||||||
typeList.add(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_INT_BGR));
|
|
||||||
|
|
||||||
// We also read and return CMYK if the source image is CMYK/YCCK + original color profile if present
|
|
||||||
ICC_Profile profile = getEmbeddedICCProfile(false);
|
|
||||||
|
|
||||||
if (csType == JPEGColorSpace.CMYK || csType == JPEGColorSpace.YCCK) {
|
|
||||||
if (profile != null && profile.getNumComponents() == 4) {
|
|
||||||
typeList.add(ImageTypeSpecifiers.createInterleaved(ColorSpaces.createColorSpace(profile), new int[] {3, 2, 1, 0}, DataBuffer.TYPE_BYTE, false, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
typeList.add(ImageTypeSpecifiers.createInterleaved(ColorSpaces.getColorSpace(ColorSpaces.CS_GENERIC_CMYK), new int[] {3, 2, 1, 0}, DataBuffer.TYPE_BYTE, false, false));
|
|
||||||
}
|
|
||||||
else if (csType == JPEGColorSpace.YCbCr || csType == JPEGColorSpace.RGB) {
|
|
||||||
if (profile != null && profile.getNumComponents() == 3) {
|
|
||||||
typeList.add(ImageTypeSpecifiers.createInterleaved(ColorSpaces.createColorSpace(profile), new int[] {0, 1, 2}, DataBuffer.TYPE_BYTE, false, false));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (csType == JPEGColorSpace.YCbCrA || csType == JPEGColorSpace.RGBA) {
|
|
||||||
// Prepend ARGB types
|
|
||||||
typeList.addAll(0, Arrays.asList(
|
|
||||||
ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_INT_ARGB),
|
|
||||||
ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_4BYTE_ABGR),
|
|
||||||
ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_INT_ARGB_PRE),
|
|
||||||
ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_4BYTE_ABGR_PRE)
|
|
||||||
));
|
|
||||||
|
|
||||||
if (profile != null && profile.getNumComponents() == 3) {
|
|
||||||
typeList.add(ImageTypeSpecifiers.createInterleaved(ColorSpaces.createColorSpace(profile), new int[] {0, 1, 2, 3}, DataBuffer.TYPE_BYTE, true, false));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return typeList.iterator();
|
types.add(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_3BYTE_BGR));
|
||||||
|
types.add(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB));
|
||||||
|
types.add(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_INT_BGR));
|
||||||
}
|
}
|
||||||
else if (csType == JPEGColorSpace.RGB) {
|
|
||||||
// Bug in com.sun...JPEGImageReader: returns gray as acceptable type, but refuses to convert
|
|
||||||
ArrayList<ImageTypeSpecifier> typeList = new ArrayList<>();
|
|
||||||
|
|
||||||
// Filter out the gray type
|
types.add(rawImageType);
|
||||||
while (types.hasNext()) {
|
|
||||||
ImageTypeSpecifier type = types.next();
|
// If the source type has a luminance (Y) component, we can also convert to gray
|
||||||
if (type.getBufferedImageType() != BufferedImage.TYPE_BYTE_GRAY) {
|
if (sourceCSType != JPEGColorSpace.RGB && sourceCSType != JPEGColorSpace.RGBA && sourceCSType != JPEGColorSpace.CMYK) {
|
||||||
typeList.add(type);
|
if (rawColorModel.hasAlpha()) {
|
||||||
}
|
types.add(ImageTypeSpecifiers.createGrayscale(8, DataBuffer.TYPE_BYTE, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
return typeList.iterator();
|
types.add(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_BYTE_GRAY));
|
||||||
}
|
}
|
||||||
|
|
||||||
return types;
|
return types.iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -268,34 +233,55 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
checkBounds(imageIndex);
|
checkBounds(imageIndex);
|
||||||
initHeader(imageIndex);
|
initHeader(imageIndex);
|
||||||
|
|
||||||
// If delegate can determine the spec, we'll just go with that
|
// Consult the image metadata
|
||||||
try {
|
|
||||||
ImageTypeSpecifier rawType = delegate.getRawImageType(0);
|
|
||||||
|
|
||||||
if (rawType != null) {
|
|
||||||
return rawType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (IIOException | NullPointerException | ArrayIndexOutOfBoundsException | NegativeArraySizeException ignore) {
|
|
||||||
// Fall through
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, consult the image metadata
|
|
||||||
JPEGColorSpace csType = getSourceCSType(getJFIF(), getAdobeDCT(), getSOF());
|
JPEGColorSpace csType = getSourceCSType(getJFIF(), getAdobeDCT(), getSOF());
|
||||||
|
ICC_Profile profile = getEmbeddedICCProfile(false);
|
||||||
|
|
||||||
|
ColorSpace cs;
|
||||||
|
boolean hasAlpha = false;
|
||||||
|
|
||||||
switch (csType) {
|
switch (csType) {
|
||||||
case CMYK:
|
case GrayA:
|
||||||
// Create based on embedded profile if exists, or create from "Generic CMYK"
|
hasAlpha = true;
|
||||||
ICC_Profile profile = getEmbeddedICCProfile(false);
|
case Gray:
|
||||||
|
// Create based on embedded profile if exists, otherwise create from Gray
|
||||||
|
cs = profile != null && profile.getNumComponents() == 1
|
||||||
|
? ColorSpaces.createColorSpace(profile)
|
||||||
|
: ColorSpaces.getColorSpace(ColorSpace.CS_GRAY);
|
||||||
|
return ImageTypeSpecifiers.createInterleaved(cs, hasAlpha ? new int[] {1, 0} : new int[] {0}, DataBuffer.TYPE_BYTE, hasAlpha, false);
|
||||||
|
|
||||||
if (profile != null && profile.getNumComponents() == 4) {
|
case YCbCrA:
|
||||||
return ImageTypeSpecifiers.createInterleaved(ColorSpaces.createColorSpace(profile), new int[]{3, 2, 1, 0}, DataBuffer.TYPE_BYTE, false, false);
|
case RGBA:
|
||||||
|
case PhotoYCCA:
|
||||||
|
hasAlpha = true;
|
||||||
|
case YCbCr:
|
||||||
|
case RGB:
|
||||||
|
case PhotoYCC:
|
||||||
|
// Create based on PhotoYCC profile...
|
||||||
|
if (csType == JPEGColorSpace.PhotoYCC || csType == JPEGColorSpace.PhotoYCCA) {
|
||||||
|
cs = ColorSpaces.getColorSpace(ColorSpace.CS_PYCC);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// ...or create based on embedded profile if exists, otherwise create from sRGB
|
||||||
|
cs = profile != null && profile.getNumComponents() == 3
|
||||||
|
? ColorSpaces.createColorSpace(profile)
|
||||||
|
: ColorSpaces.getColorSpace(ColorSpace.CS_sRGB);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ImageTypeSpecifiers.createInterleaved(ColorSpaces.getColorSpace(ColorSpaces.CS_GENERIC_CMYK), new int[] {3, 2, 1, 0}, DataBuffer.TYPE_BYTE, false, false);
|
return ImageTypeSpecifiers.createInterleaved(cs, hasAlpha ? new int[] {3, 2, 1, 0} : new int[] {2, 1, 0}, DataBuffer.TYPE_BYTE, hasAlpha, false);
|
||||||
|
|
||||||
|
case YCCK:
|
||||||
|
case CMYK:
|
||||||
|
// Create based on embedded profile if exists, otherwise create from "Generic CMYK"
|
||||||
|
cs = profile != null && profile.getNumComponents() == 4
|
||||||
|
? ColorSpaces.createColorSpace(profile)
|
||||||
|
: ColorSpaces.getColorSpace(ColorSpaces.CS_GENERIC_CMYK);
|
||||||
|
|
||||||
|
return ImageTypeSpecifiers.createInterleaved(cs, new int[] {3, 2, 1, 0}, DataBuffer.TYPE_BYTE, false, false);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// For other types, we probably can't give a proper type, return null
|
// For other types, we probably can't give a proper type
|
||||||
return null;
|
throw new IIOException("Could not determine JPEG source color space");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -322,7 +308,8 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
adobeDCT = null;
|
adobeDCT = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
JPEGColorSpace sourceCSType = getSourceCSType(getJFIF(), adobeDCT, sof);
|
JFIF jfif = getJFIF();
|
||||||
|
JPEGColorSpace sourceCSType = getSourceCSType(jfif, adobeDCT, sof);
|
||||||
|
|
||||||
if (sof.marker == JPEG.SOF3) {
|
if (sof.marker == JPEG.SOF3) {
|
||||||
// Read image as lossless
|
// Read image as lossless
|
||||||
@ -347,20 +334,15 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
// We need to apply ICC profile unless the profile is sRGB/default gray (whatever that is)
|
// We need to apply ICC profile unless the profile is sRGB/default gray (whatever that is)
|
||||||
// - or only filter out the bad ICC profiles in the JPEGSegmentImageInputStream.
|
// - or only filter out the bad ICC profiles in the JPEGSegmentImageInputStream.
|
||||||
else if (delegate.canReadRaster() && (
|
else if (bogusAdobeDCT
|
||||||
bogusAdobeDCT ||
|
|| profile != null && !ColorSpaces.isCS_sRGB(profile)
|
||||||
sourceCSType == JPEGColorSpace.CMYK ||
|
|| (long) sof.lines * sof.samplesPerLine > Integer.MAX_VALUE
|
||||||
sourceCSType == JPEGColorSpace.YCCK ||
|
|| delegateCSTypeMismatch(jfif, adobeDCT, sof, sourceCSType)) {
|
||||||
profile != null && !ColorSpaces.isCS_sRGB(profile) ||
|
|
||||||
(long) sof.lines * sof.samplesPerLine > Integer.MAX_VALUE ||
|
|
||||||
!delegate.getImageTypes(0).hasNext() ||
|
|
||||||
sourceCSType == JPEGColorSpace.YCbCr && getRawImageType(imageIndex) != null)) { // TODO: Issue warning?
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
System.out.println("Reading using raster and extra conversion");
|
System.out.println("Reading using raster and extra conversion");
|
||||||
System.out.println("ICC color profile: " + profile);
|
System.out.println("ICC color profile: " + profile);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Possible to optimize slightly, to avoid readAsRaster for non-CMYK and other good types?
|
|
||||||
return readImageAsRasterAndReplaceColorProfile(imageIndex, param, sof, sourceCSType, profile);
|
return readImageAsRasterAndReplaceColorProfile(imageIndex, param, sof, sourceCSType, profile);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -371,6 +353,56 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
return delegate.read(0, param);
|
return delegate.read(0, param);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean delegateCSTypeMismatch(final JFIF jfif, final AdobeDCT adobeDCT, final Frame startOfFrame, final JPEGColorSpace sourceCSType) throws IOException {
|
||||||
|
switch (sourceCSType) {
|
||||||
|
case GrayA:
|
||||||
|
case RGBA:
|
||||||
|
case YCbCrA:
|
||||||
|
case PhotoYCC:
|
||||||
|
case PhotoYCCA:
|
||||||
|
case CMYK:
|
||||||
|
case YCCK:
|
||||||
|
// These are no longer supported by the delegate, we'll handle ourselves
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
ImageTypeSpecifier rawImageType = delegate.getRawImageType(0);
|
||||||
|
|
||||||
|
switch (sourceCSType) {
|
||||||
|
case Gray:
|
||||||
|
return rawImageType == null || rawImageType.getColorModel().getColorSpace().getType() != ColorSpace.TYPE_GRAY;
|
||||||
|
case YCbCr:
|
||||||
|
// NOTE: For backwards compatibility, null is allowed for YCbCr
|
||||||
|
if (rawImageType == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If We have a JFIF, but with non-standard component Ids, the standard reader mistakes it for RGB
|
||||||
|
if (jfif != null && (startOfFrame.components[0].id != 1 || startOfFrame.components[1].id != 2 || startOfFrame.components[2].id != 3)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Else, if we have no Adobe marker and no subsampling, the standard reader mistakes it for RGB
|
||||||
|
else if (adobeDCT == null
|
||||||
|
&& (startOfFrame.components[0].id != 1 || startOfFrame.components[1].id != 2 || startOfFrame.components[2].id != 3)
|
||||||
|
&& (startOfFrame.components[0].hSub == 1 || startOfFrame.components[0].vSub == 1
|
||||||
|
|| startOfFrame.components[1].hSub == 1 || startOfFrame.components[1].vSub == 1
|
||||||
|
|| startOfFrame.components[2].hSub == 1 || startOfFrame.components[2].vSub == 1)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case RGB:
|
||||||
|
return rawImageType == null || rawImageType.getColorModel().getColorSpace().getType() != ColorSpace.TYPE_RGB;
|
||||||
|
default:
|
||||||
|
// Probably needs special handling, but we don't know what to do...
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IIOException | NullPointerException | ArrayIndexOutOfBoundsException | NegativeArraySizeException ignore) {
|
||||||
|
// An exception here is a clear indicator we need to handle conversion
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private BufferedImage readImageAsRasterAndReplaceColorProfile(int imageIndex, ImageReadParam param, Frame startOfFrame, JPEGColorSpace csType, ICC_Profile profile) throws IOException {
|
private BufferedImage readImageAsRasterAndReplaceColorProfile(int imageIndex, ImageReadParam param, Frame startOfFrame, JPEGColorSpace csType, ICC_Profile profile) throws IOException {
|
||||||
int origWidth = getWidth(imageIndex);
|
int origWidth = getWidth(imageIndex);
|
||||||
int origHeight = getHeight(imageIndex);
|
int origHeight = getHeight(imageIndex);
|
||||||
@ -388,7 +420,10 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
RasterOp convert = null;
|
RasterOp convert = null;
|
||||||
ICC_ColorSpace intendedCS = profile != null ? ColorSpaces.createColorSpace(profile) : null;
|
ICC_ColorSpace intendedCS = profile != null ? ColorSpaces.createColorSpace(profile) : null;
|
||||||
|
|
||||||
if (profile != null && (csType == JPEGColorSpace.Gray || csType == JPEGColorSpace.GrayA)) {
|
if (destination.getNumBands() <= 2 && (csType != JPEGColorSpace.Gray && csType != JPEGColorSpace.GrayA)) {
|
||||||
|
convert = new LumaToGray();
|
||||||
|
}
|
||||||
|
else if (profile != null && (csType == JPEGColorSpace.Gray || csType == JPEGColorSpace.GrayA)) {
|
||||||
// com.sun. reader does not do ColorConvertOp for CS_GRAY, even if embedded ICC profile,
|
// com.sun. reader does not do ColorConvertOp for CS_GRAY, even if embedded ICC profile,
|
||||||
// probably because IJG native part does it already...? If applied, color looks wrong (too dark)...
|
// probably because IJG native part does it already...? If applied, color looks wrong (too dark)...
|
||||||
// convert = new ColorConvertOp(intendedCS, image.getColorModel().getColorSpace(), null);
|
// convert = new ColorConvertOp(intendedCS, image.getColorModel().getColorSpace(), null);
|
||||||
@ -397,8 +432,7 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
// Handle inconsistencies
|
// Handle inconsistencies
|
||||||
if (startOfFrame.componentsInFrame() != intendedCS.getNumComponents()) {
|
if (startOfFrame.componentsInFrame() != intendedCS.getNumComponents()) {
|
||||||
// If ICC profile number of components and startOfFrame does not match, ignore ICC profile
|
// If ICC profile number of components and startOfFrame does not match, ignore ICC profile
|
||||||
processWarningOccurred(String.format(
|
processWarningOccurred(String.format("Embedded ICC color profile is incompatible with image data. " +
|
||||||
"Embedded ICC color profile is incompatible with image data. " +
|
|
||||||
"Profile indicates %d components, but SOF%d has %d color components. " +
|
"Profile indicates %d components, but SOF%d has %d color components. " +
|
||||||
"Ignoring ICC profile, assuming source color space %s.",
|
"Ignoring ICC profile, assuming source color space %s.",
|
||||||
intendedCS.getNumComponents(), startOfFrame.marker & 0xf, startOfFrame.componentsInFrame(), csType
|
intendedCS.getNumComponents(), startOfFrame.marker & 0xf, startOfFrame.componentsInFrame(), csType
|
||||||
@ -422,10 +456,7 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
ColorSpace cmykCS = ColorSpaces.getColorSpace(ColorSpaces.CS_GENERIC_CMYK);
|
ColorSpace cmykCS = ColorSpaces.getColorSpace(ColorSpaces.CS_GENERIC_CMYK);
|
||||||
|
|
||||||
if (cmykCS instanceof ICC_ColorSpace) {
|
if (cmykCS instanceof ICC_ColorSpace) {
|
||||||
processWarningOccurred(
|
processWarningOccurred("No embedded ICC color profile, defaulting to \"generic\" CMYK ICC profile. Colors may look incorrect.");
|
||||||
"No embedded ICC color profile, defaulting to \"generic\" CMYK ICC profile. " +
|
|
||||||
"Colors may look incorrect."
|
|
||||||
);
|
|
||||||
|
|
||||||
// NOTE: Avoid using CCOp if same color space, as it's more compatible that way
|
// NOTE: Avoid using CCOp if same color space, as it's more compatible that way
|
||||||
if (cmykCS != image.getColorModel().getColorSpace()) {
|
if (cmykCS != image.getColorModel().getColorSpace()) {
|
||||||
@ -434,17 +465,11 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// ColorConvertOp using non-ICC CS is deadly slow, fall back to fast conversion instead
|
// ColorConvertOp using non-ICC CS is deadly slow, fall back to fast conversion instead
|
||||||
processWarningOccurred(
|
processWarningOccurred("No embedded ICC color profile, will convert using inaccurate CMYK to RGB conversion. Colors may look incorrect.");
|
||||||
"No embedded ICC color profile, will convert using inaccurate CMYK to RGB conversion. " +
|
|
||||||
"Colors may look incorrect."
|
|
||||||
);
|
|
||||||
|
|
||||||
convert = new FastCMYKToRGB();
|
convert = new FastCMYKToRGB();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (profile != null) {
|
|
||||||
processWarningOccurred("Embedded ICC color profile is incompatible with Java 2D, color profile will be ignored.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// We'll need a read param
|
// We'll need a read param
|
||||||
if (param == null) {
|
if (param == null) {
|
||||||
@ -523,10 +548,9 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
switch (adobeDCT.transform) {
|
switch (adobeDCT.transform) {
|
||||||
case AdobeDCT.Unknown:
|
case AdobeDCT.Unknown:
|
||||||
return JPEGColorSpace.RGB;
|
return JPEGColorSpace.RGB;
|
||||||
case AdobeDCT.YCC:
|
|
||||||
return JPEGColorSpace.YCbCr;
|
|
||||||
default:
|
default:
|
||||||
// TODO: Warning!
|
// TODO: Warning!
|
||||||
|
case AdobeDCT.YCC:
|
||||||
return JPEGColorSpace.YCbCr; // assume it's YCbCr
|
return JPEGColorSpace.YCbCr; // assume it's YCbCr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -556,10 +580,9 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
switch (adobeDCT.transform) {
|
switch (adobeDCT.transform) {
|
||||||
case AdobeDCT.Unknown:
|
case AdobeDCT.Unknown:
|
||||||
return JPEGColorSpace.CMYK;
|
return JPEGColorSpace.CMYK;
|
||||||
case AdobeDCT.YCCK:
|
|
||||||
return JPEGColorSpace.YCCK;
|
|
||||||
default:
|
default:
|
||||||
// TODO: Warning!
|
// TODO: Warning!
|
||||||
|
case AdobeDCT.YCCK:
|
||||||
return JPEGColorSpace.YCCK; // assume it's YCCK
|
return JPEGColorSpace.YCCK; // assume it's YCCK
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,65 @@
|
|||||||
|
package com.twelvemonkeys.imageio.plugins.jpeg;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.lang.Validate;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.geom.Point2D;
|
||||||
|
import java.awt.geom.Rectangle2D;
|
||||||
|
import java.awt.image.Raster;
|
||||||
|
import java.awt.image.RasterOp;
|
||||||
|
import java.awt.image.WritableRaster;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LumaToGray.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haraldk$
|
||||||
|
* @version $Id: LumaToGray.java,v 1.0 10/04/2021 haraldk Exp$
|
||||||
|
*/
|
||||||
|
final class LumaToGray implements RasterOp {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WritableRaster filter(final Raster src, WritableRaster dest) {
|
||||||
|
Validate.notNull(src, "src may not be null");
|
||||||
|
Validate.isTrue(src != dest, "src and dest raster may not be same");
|
||||||
|
Validate.isTrue(src.getNumDataElements() >= 3, src.getNumDataElements(), "Luma raster must have at least 3 data elements: %s");
|
||||||
|
|
||||||
|
if (dest == null) {
|
||||||
|
dest = createCompatibleDestRaster(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If src and dest have alpha component, keep it, otherwise extract luma only
|
||||||
|
int[] bandList = src.getNumBands() > 3 && dest.getNumBands() > 1 ? new int[] {0, 3} : new int[] {0};
|
||||||
|
dest.setRect(0, 0, src.createChild(0, 0, src.getWidth(), src.getHeight(), 0, 0, bandList));
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Rectangle2D getBounds2D(final Raster src) {
|
||||||
|
return src.getBounds();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WritableRaster createCompatibleDestRaster(final Raster src) {
|
||||||
|
WritableRaster raster = src.createCompatibleWritableRaster();
|
||||||
|
return raster.createWritableChild(0, 0, src.getWidth(), src.getHeight(), 0, 0, new int[] {0});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Point2D getPoint2D(final Point2D srcPt, Point2D dstPt) {
|
||||||
|
if (dstPt == null) {
|
||||||
|
dstPt = new Point2D.Double(srcPt.getX(), srcPt.getY());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dstPt.setLocation(srcPt);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dstPt;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RenderingHints getRenderingHints() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -63,7 +63,7 @@ public class FastCMYKToRGBTest {
|
|||||||
assertNotNull(pixel);
|
assertNotNull(pixel);
|
||||||
assertEquals(3, pixel.length);
|
assertEquals(3, pixel.length);
|
||||||
byte[] expected = {(byte) 255, (byte) 255, (byte) 255};
|
byte[] expected = {(byte) 255, (byte) 255, (byte) 255};
|
||||||
assertTrue(String.format("Was: %s, expected: %s", Arrays.toString(pixel), Arrays.toString(expected)), Arrays.equals(expected, pixel));
|
assertArrayEquals(String.format("Was: %s, expected: %s", Arrays.toString(pixel), Arrays.toString(expected)), expected, pixel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -95,7 +95,7 @@ public class FastCMYKToRGBTest {
|
|||||||
assertNotNull(pixel);
|
assertNotNull(pixel);
|
||||||
assertEquals(3, pixel.length);
|
assertEquals(3, pixel.length);
|
||||||
byte[] expected = {(byte) 0, (byte) 0, (byte) 0};
|
byte[] expected = {(byte) 0, (byte) 0, (byte) 0};
|
||||||
assertTrue(String.format("Was: %s, expected: %s", Arrays.toString(pixel), Arrays.toString(expected)), Arrays.equals(expected, pixel));
|
assertArrayEquals(String.format("Was: %s, expected: %s", Arrays.toString(pixel), Arrays.toString(expected)), expected, pixel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,7 +134,7 @@ public class FastCMYKToRGBTest {
|
|||||||
assertNotNull(pixel);
|
assertNotNull(pixel);
|
||||||
assertEquals(3, pixel.length);
|
assertEquals(3, pixel.length);
|
||||||
byte[] expected = {(byte) (255 - i), (byte) i, (byte) (127 - i)};
|
byte[] expected = {(byte) (255 - i), (byte) i, (byte) (127 - i)};
|
||||||
assertTrue(String.format("Was: %s, expected: %s", Arrays.toString(pixel), Arrays.toString(expected)), Arrays.equals(expected, pixel));
|
assertArrayEquals(String.format("Was: %s, expected: %s", Arrays.toString(pixel), Arrays.toString(expected)), expected, pixel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,7 +153,7 @@ public class FastCMYKToRGBTest {
|
|||||||
assertNotNull(pixel);
|
assertNotNull(pixel);
|
||||||
assertEquals(3, pixel.length);
|
assertEquals(3, pixel.length);
|
||||||
byte[] expected = {(byte) (255 - i), (byte) i, (byte) (127 - i)};
|
byte[] expected = {(byte) (255 - i), (byte) i, (byte) (127 - i)};
|
||||||
assertTrue(String.format("Was: %s, expected: %s", Arrays.toString(pixel), Arrays.toString(expected)), Arrays.equals(expected, pixel));
|
assertArrayEquals(String.format("Was: %s, expected: %s", Arrays.toString(pixel), Arrays.toString(expected)), expected, pixel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,7 +172,7 @@ public class FastCMYKToRGBTest {
|
|||||||
assertNotNull(pixel);
|
assertNotNull(pixel);
|
||||||
assertEquals(4, pixel.length);
|
assertEquals(4, pixel.length);
|
||||||
byte[] expected = {(byte) (255 - i), (byte) i, (byte) (127 - i), (byte) 0xff};
|
byte[] expected = {(byte) (255 - i), (byte) i, (byte) (127 - i), (byte) 0xff};
|
||||||
assertTrue(String.format("Was: %s, expected: %s", Arrays.toString(pixel), Arrays.toString(expected)), Arrays.equals(expected, pixel));
|
assertArrayEquals(String.format("Was: %s, expected: %s", Arrays.toString(pixel), Arrays.toString(expected)), expected, pixel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
package com.twelvemonkeys.imageio.plugins.jpeg;
|
package com.twelvemonkeys.imageio.plugins.jpeg;
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest;
|
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest;
|
||||||
|
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
|
||||||
import com.twelvemonkeys.lang.StringUtil;
|
import com.twelvemonkeys.lang.StringUtil;
|
||||||
|
|
||||||
import org.hamcrest.core.IsInstanceOf;
|
import org.hamcrest.core.IsInstanceOf;
|
||||||
@ -55,6 +56,7 @@ import java.awt.*;
|
|||||||
import java.awt.color.ColorSpace;
|
import java.awt.color.ColorSpace;
|
||||||
import java.awt.color.ICC_Profile;
|
import java.awt.color.ICC_Profile;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.awt.image.DataBuffer;
|
||||||
import java.awt.image.DataBufferByte;
|
import java.awt.image.DataBufferByte;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -140,11 +142,6 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader
|
|||||||
// More test data in specific tests below
|
// More test data in specific tests below
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean allowsNullRawImageType() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<String> getFormatNames() {
|
protected List<String> getFormatNames() {
|
||||||
return Arrays.asList("JPEG", "jpeg", "JPG", "jpg",
|
return Arrays.asList("JPEG", "jpeg", "JPG", "jpg",
|
||||||
@ -422,8 +419,8 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testYCbCrNotSubsampledNonstandardChannelIndexes() throws IOException {
|
public void testYCbCrNotSubsampledNonstandardComponentIds() throws IOException {
|
||||||
// Regression: Make sure 3 channel, non-subsampled JFIF, defaults to YCbCr, even if unstandard channel indexes
|
// Regression: Make sure 3 channel, non-subsampled JFIF, defaults to YCbCr, even if nonstandard component ids
|
||||||
JPEGImageReader reader = createReader();
|
JPEGImageReader reader = createReader();
|
||||||
try (ImageInputStream stream = ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/jfif-ycbcr-no-subsampling-intel.jpg"))) {
|
try (ImageInputStream stream = ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/jfif-ycbcr-no-subsampling-intel.jpg"))) {
|
||||||
reader.setInput(stream);
|
reader.setInput(stream);
|
||||||
@ -1235,6 +1232,56 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRGBANoGrayImageTypes() throws IOException {
|
||||||
|
JPEGImageReader reader = createReader();
|
||||||
|
reader.setInput(ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/adobe-unknown-rgb-ids.jpg")));
|
||||||
|
|
||||||
|
Iterator<ImageTypeSpecifier> imageTypes = reader.getImageTypes(0);
|
||||||
|
|
||||||
|
while (imageTypes.hasNext()) {
|
||||||
|
ImageTypeSpecifier specifier = imageTypes.next();
|
||||||
|
assertNotEquals("RGB JPEGs can't be decoded as Gray as it has no luminance (Y) component", ColorSpace.TYPE_GRAY, specifier.getColorModel().getColorSpace().getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
reader.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = Exception.class)
|
||||||
|
public void testRGBAsGray() throws IOException {
|
||||||
|
final JPEGImageReader reader = createReader();
|
||||||
|
try {
|
||||||
|
reader.setInput(ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/adobe-unknown-rgb-ids.jpg")));
|
||||||
|
|
||||||
|
assertEquals(225, reader.getWidth(0));
|
||||||
|
assertEquals(156, reader.getHeight(0));
|
||||||
|
|
||||||
|
final ImageReadParam param = reader.getDefaultReadParam();
|
||||||
|
param.setSourceRegion(new Rectangle(0, 0, 225, 8));
|
||||||
|
param.setDestinationType(ImageTypeSpecifiers.createGrayscale(8, DataBuffer.TYPE_BYTE));
|
||||||
|
|
||||||
|
// Should ideally throw IIOException due to destination type mismatch, but throws IllegalArgumentException...
|
||||||
|
reader.read(0, param);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
reader.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testYCbCrAsGray() throws IOException {
|
||||||
|
JPEGImageReader reader = createReader();
|
||||||
|
reader.setInput(ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/jfif-ycbcr-no-subsampling-intel.jpg")));
|
||||||
|
|
||||||
|
ImageReadParam param = reader.getDefaultReadParam();
|
||||||
|
param.setDestinationType(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_BYTE_GRAY));
|
||||||
|
|
||||||
|
BufferedImage image = reader.read(0, param);
|
||||||
|
|
||||||
|
assertNotNull(image);
|
||||||
|
assertEquals(BufferedImage.TYPE_BYTE_GRAY, image.getType());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Slightly fuzzy RGB equals method. Tolerance +/-5 steps.
|
* Slightly fuzzy RGB equals method. Tolerance +/-5 steps.
|
||||||
*/
|
*/
|
||||||
@ -1818,7 +1865,7 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader
|
|||||||
reader.setInput(ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/exif-jfif-app13-app14ycck-3channel.jpg")));
|
reader.setInput(ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/exif-jfif-app13-app14ycck-3channel.jpg")));
|
||||||
|
|
||||||
ImageTypeSpecifier rawType = reader.getRawImageType(0);
|
ImageTypeSpecifier rawType = reader.getRawImageType(0);
|
||||||
assertNull(rawType); // But no exception, please...
|
assertNotNull(rawType); // As of Java 9, use RGB for YCC and CMYK for YCCK
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
reader.dispose();
|
reader.dispose();
|
||||||
|
@ -0,0 +1,79 @@
|
|||||||
|
package com.twelvemonkeys.imageio.plugins.jpeg;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.awt.image.DataBuffer;
|
||||||
|
import java.awt.image.Raster;
|
||||||
|
import java.awt.image.WritableRaster;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LumaToGrayTest.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haraldk$
|
||||||
|
* @version $Id: LumaToGrayTest.java,v 1.0 10/04/2021 haraldk Exp$
|
||||||
|
*/
|
||||||
|
public class LumaToGrayTest {
|
||||||
|
@Test
|
||||||
|
public void testConvertByteYcc() {
|
||||||
|
LumaToGray convert = new LumaToGray();
|
||||||
|
|
||||||
|
WritableRaster input = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, 1, 1, 3, null);
|
||||||
|
WritableRaster result = null;
|
||||||
|
|
||||||
|
byte[] pixel = null;
|
||||||
|
for (int i = 0; i < 255; i++) {
|
||||||
|
input.setDataElements(0, 0, new byte[] {(byte) i, (byte) (255 - i), (byte) (127 + i)});
|
||||||
|
result = convert.filter(input, result);
|
||||||
|
pixel = (byte[]) result.getDataElements(0, 0, pixel);
|
||||||
|
|
||||||
|
assertNotNull(pixel);
|
||||||
|
assertEquals(1, pixel.length);
|
||||||
|
byte[] expected = {(byte) i};
|
||||||
|
assertArrayEquals(String.format("Was: %s, expected: %s", Arrays.toString(pixel), Arrays.toString(expected)), expected, pixel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConvertByteYccK() {
|
||||||
|
LumaToGray convert = new LumaToGray();
|
||||||
|
|
||||||
|
WritableRaster input = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, 1, 1, 4, null);
|
||||||
|
WritableRaster result = null;
|
||||||
|
|
||||||
|
byte[] pixel = null;
|
||||||
|
for (int i = 0; i < 255; i++) {
|
||||||
|
input.setDataElements(0, 0, new byte[] {(byte) i, (byte) (255 - i), (byte) (127 + i), (byte) 255});
|
||||||
|
result = convert.filter(input, result);
|
||||||
|
pixel = (byte[]) result.getDataElements(0, 0, pixel);
|
||||||
|
|
||||||
|
assertNotNull(pixel);
|
||||||
|
assertEquals(1, pixel.length);
|
||||||
|
byte[] expected = {(byte) i};
|
||||||
|
assertArrayEquals(String.format("Was: %s, expected: %s", Arrays.toString(pixel), Arrays.toString(expected)), expected, pixel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConvertByteYccA() {
|
||||||
|
LumaToGray convert = new LumaToGray();
|
||||||
|
|
||||||
|
WritableRaster input = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, 1, 1, 4, null);
|
||||||
|
WritableRaster result = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, 1, 1, 2, null);
|
||||||
|
|
||||||
|
byte[] pixel = null;
|
||||||
|
for (int i = 0; i < 255; i++) {
|
||||||
|
input.setDataElements(0, 0, new byte[] {(byte) i, (byte) 255, (byte) (127 + i), (byte) (255 - i)});
|
||||||
|
result = convert.filter(input, result);
|
||||||
|
pixel = (byte[]) result.getDataElements(0, 0, pixel);
|
||||||
|
|
||||||
|
assertNotNull(pixel);
|
||||||
|
assertEquals(2, pixel.length);
|
||||||
|
byte[] expected = {(byte) i, (byte) (255 - i)};
|
||||||
|
assertArrayEquals(String.format("Was: %s, expected: %s", Arrays.toString(pixel), Arrays.toString(expected)), expected, pixel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user