/*
* Geotoolkit.org - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2010-2014, Open Source Geospatial Foundation (OSGeo)
* (C) 2010-2014, Geomatys
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotoolkit.image.io.plugin.TiffWriter;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.image.RenderedImage;
import java.awt.image.WritableRenderedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageTypeSpecifier;
import org.geotoolkit.image.internal.PhotometricInterpretation;
import org.geotoolkit.image.internal.SampleType;
import org.geotoolkit.image.io.plugin.TiffImageWriter;
import org.geotoolkit.image.iterator.PixelIterator;
import org.geotoolkit.image.iterator.PixelIteratorFactory;
//import org.junit.Ignore;
import org.junit.Test;
/**
* {@link TestTiffImageWriter} implementation which write image without any compression.
*
* @author Remi Marechal (Geomatys).
*/
public strictfp class UncompressedTiffWriterTest extends TestTiffImageWriter {
public UncompressedTiffWriterTest() throws IOException {
super(null);
}
/**
* Verify writing conformity when writing only one strip which is equals to image width.<br>
* Concretely check writing conformity when strip offset and strip byte count values are contained into tag.
*
* @throws java.io.IOException
* @see TiffImageWriter#writeImageByStrips(java.awt.image.RenderedImage, javax.imageio.ImageWriteParam)
* @see TiffImageWriter#writeByteCountAndOffsets(long, short, java.lang.Object, long, short, java.lang.Object)
*/
@Test
public void singleStripTest() throws IOException {
//-- 1 band byte --//
testSingleStrip("TestWriteEmpty : 1 band Byte", SampleType.BYTE, 1, PhotometricInterpretation.GRAYSCALE);
//-- 1 band short --//
testSingleStrip("TestWriteEmpty : 1 band Short", SampleType.USHORT, 1, PhotometricInterpretation.GRAYSCALE);
//-- 1 band int --//
testSingleStrip("TestWriteEmpty : 1 band Integer", SampleType.INTEGER, 1, PhotometricInterpretation.GRAYSCALE);
//-- 1 band Float --//
testSingleStrip("TestWriteEmpty : 1 band Float", SampleType.FLOAT, 1, PhotometricInterpretation.GRAYSCALE);
//-- 1 band double --//
testSingleStrip("TestWriteEmpty : 1 Double Byte", SampleType.DOUBLE, 1, PhotometricInterpretation.GRAYSCALE);
//-- 3 bands RGB --//
testSingleStrip("TestWriteEmpty : 3 bands Byte", SampleType.BYTE, 3, PhotometricInterpretation.RGB);
//-- 4 band RGB --//
testSingleStrip("TestWriteEmpty : 4 bands Byte", SampleType.BYTE, 4, PhotometricInterpretation.RGB);
//--Color Map --//
//-- 1 band byte --//
testSingleStrip("TestWriteEmpty : 1 bands Byte Color Map", SampleType.BYTE, 1, PhotometricInterpretation.PALETTE);
//-- uncomment this code when a solution for multi band with color palette will be approuved.
// //-- 1 band byte --//
// testSingleStrip("TestWriteEmpty : 4 bands Byte Color Map", Byte.SIZE, 4, PHOTOMETRIC_PALETTE, SAMPLEFORMAT_UINT);
}
/**
* Write and read an image without any subsampling or other, and with only one strip.
*
* @param message
* @param sampleBitsSize
* @param numBand
* @param photometricInterpretation
* @param sampleFormat
* @throws IOException
*/
private void testSingleStrip(final String message, final SampleType sampleType,
final int numBand, final PhotometricInterpretation photometricInterpretation)
throws IOException {
final File fileTest = File.createTempFile(message, "tiff", tempDir);
writer.setOutput(fileTest); //-- to initialize writer
//-- only one strip
final int width = random.nextInt(256) + 16;
final int height = 1;
/*
* Image volontary created with planarconfiguration equal 1 to don't build banded sampleModel
* because with banded sample model one strip offset for each band and the aim of this test is
* to have only a single strip offset tiff tag.
* N = StripsPerImage for PlanarConfiguration equal to 1; N = SamplesPerPixel * StripsPerImage for PlanarConfiguration equal to 2
*/
final ImageTypeSpecifier typeSpecifier = buildImageTypeSpecifier(sampleType, numBand, photometricInterpretation);
final WritableRenderedImage sourceImage = typeSpecifier.createBufferedImage(width, height);//createImageTest(width, height, sampleBitsSize, numBand, photometricInterpretation, sampleFormat);
writer.write(sourceImage);
writer.dispose();
reader.setInput(fileTest);
final RenderedImage tested = reader.read(0);
reader.dispose();
checkImage(message, sourceImage, tested);
}
/**
* Test method.
*
* @throws IOException
*/
@Test
public void writeEmptyTest() throws IOException {
//-- 1 band byte --//
TestWriteEmpty("TestWriteEmpty : 1 band Byte", SampleType.BYTE, 1, PhotometricInterpretation.GRAYSCALE);
//-- 1 band short --//
TestWriteEmpty("TestWriteEmpty : 1 band Short", SampleType.USHORT, 1, PhotometricInterpretation.GRAYSCALE);
//-- 1 band int --//
TestWriteEmpty("TestWriteEmpty : 1 band Integer", SampleType.INTEGER, 1, PhotometricInterpretation.GRAYSCALE);
//-- 1 band Float --//
TestWriteEmpty("TestWriteEmpty : 1 band Float", SampleType.FLOAT, 1, PhotometricInterpretation.GRAYSCALE);
//-- 1 band double --//
TestWriteEmpty("TestWriteEmpty : 1 Double Byte", SampleType.DOUBLE, 1, PhotometricInterpretation.GRAYSCALE);
//-- 3 bands RGB --//
TestWriteEmpty("TestWriteEmpty : 3 bands Byte", SampleType.BYTE, 3, PhotometricInterpretation.RGB);
//-- 4 band RGB --//
TestWriteEmpty("TestWriteEmpty : 4 bands Byte", SampleType.BYTE, 4, PhotometricInterpretation.RGB);
//--Color Map --//
//-- 1 band byte --//
TestWriteEmpty("TestWriteEmpty : 1 bands Byte Color Map", SampleType.BYTE, 1, PhotometricInterpretation.PALETTE);
}
/**
* Effectuate test write empty in function of given parameter.
*
* @param message error message in case of assertion fail.
* @param sampleBitsSize
* @param numBand
* @param photometricInterpretation
* @param sampleFormat
* @throws IOException if problem during I/O action.
*/
private void TestWriteEmpty(final String message, final SampleType sampleType,
final int numBand, final PhotometricInterpretation photometricInterpretation)
throws IOException {
writer.reset();
final File fileTest = File.createTempFile(message, "tiff", tempDir);
writer.setOutput(fileTest); //-- to initialize writer
final ImageTypeSpecifier sourceImgSpec = buildImageTypeSpecifier(sampleType, numBand, photometricInterpretation);
final int width = random.nextInt(256) + 16;
final int height = random.nextInt(256) + 16;
writer.prepareWriteEmpty(null, sourceImgSpec, width, height, null, null, writerParam);
//-- create an empty source image to simulate write empty --//
final WritableRenderedImage sourceImage = sourceImgSpec.createBufferedImage(width, height);
replacePixels(sourceImage, sampleType, numBand, photometricInterpretation);
reader.setInput(fileTest);
final RenderedImage tested = reader.read(0);
reader.dispose();
checkImage(message, sourceImage, tested);
}
/**
* Improve method {@link TIFFImageWriter#replacePixels(java.awt.image.RenderedImage, javax.imageio.ImageWriteParam) }.
*
* @throws IOException if problem during I/O action.
*/
@Test
// @Ignore
public void replacePixelTest() throws IOException {
//-- 1 band byte --//
TestReplacePixel("replacePixel : 1 band Byte", SampleType.BYTE, 1, PhotometricInterpretation.GRAYSCALE);
//-- 1 band short --//
TestReplacePixel("replacePixel : 1 band Short", SampleType.USHORT, 1, PhotometricInterpretation.GRAYSCALE);
//-- 1 band int --//
TestReplacePixel("replacePixel : 1 band Integer", SampleType.INTEGER, 1, PhotometricInterpretation.GRAYSCALE);
//-- 1 band Float --//
TestReplacePixel("replacePixel : 1 band Float", SampleType.FLOAT, 1, PhotometricInterpretation.GRAYSCALE);
//-- 1 band double --//
TestReplacePixel("replacePixel : 1 Double Byte", SampleType.DOUBLE, 1, PhotometricInterpretation.GRAYSCALE);
//-- 3 bands RGB --//
TestReplacePixel("replacePixel : 3 bands Byte", SampleType.BYTE, 3, PhotometricInterpretation.RGB);
//-- 4 band RGB --//
TestReplacePixel("replacePixel : 4 bands Byte", SampleType.BYTE, 4, PhotometricInterpretation.RGB);
//--Color Map --//
//-- 1 band byte --//
TestReplacePixel("replacePixel : 1 bands Byte Color Map", SampleType.BYTE, 1, PhotometricInterpretation.PALETTE);
//-- uncomment this code when a solution for multi band with color palette will be approuved.
// //-- 1 band byte --//
// TestReplacePixel("replacePixel : 4 bands Byte Color Map", Byte.SIZE, 4, PHOTOMETRIC_PALETTE, SAMPLEFORMAT_UINT);
}
/**
* Replace pixel into source image.<br/>
* Moreover 5 smaller images than source image are generate to replace source
* image pixel at all corner and at center of the source image.
*
* @param sourceImage
* @param sampleBitsSize
* @param numBand
* @param photometricInterpretation
* @param sampleFormat
* @throws IOException if problem during I/O action.
*/
private void replacePixels(final WritableRenderedImage sourceImage, final SampleType sampleType,
final int numBand, final PhotometricInterpretation photometricInterpretation)
throws IOException {
final int width = sourceImage.getWidth();
final int height = sourceImage.getHeight();
final int w_2 = width >>> 1;
final int h_2 = height >>> 1;
final int w_4 = width >>> 2;
final int h_4 = height >>> 2;
final int w_8 = width >>> 3;
final int h_8 = height >>> 3;
//-- prepare replace pixel
final int regionMinX = random.nextInt(w_2);
final int regionMinY = random.nextInt(h_2);
final Rectangle repRegion = new Rectangle(regionMinX, regionMinY, w_2 , h_2);
writer.prepareReplacePixels(0, repRegion);
//-- replace region lower left corner --//
WritableRenderedImage imgLLC = createImageTest(w_4, h_4, sampleType, numBand, photometricInterpretation);
int dstOffX = regionMinX - w_8 + random.nextInt(w_8);
int dstOffY = regionMinY - h_8 + random.nextInt(h_8);
Point destOffset = new Point(dstOffX, dstOffY);
replacePixelsInResultImage(sourceImage, repRegion, imgLLC, destOffset);
writerParam.setDestinationOffset(destOffset);
writer.replacePixels(imgLLC, writerParam);
//-- replace region lower right corner --//
imgLLC = createImageTest(w_4, h_4, sampleType, numBand, photometricInterpretation);
dstOffX = regionMinX + w_4 + random.nextInt(w_8);
dstOffY = regionMinY - h_8 + random.nextInt(h_8);
destOffset = new Point(dstOffX, dstOffY);
replacePixelsInResultImage(sourceImage, repRegion, imgLLC, destOffset);
writerParam.setDestinationOffset(destOffset);
writer.replacePixels(imgLLC, writerParam);
//-- replace region upper left corner --//
imgLLC = createImageTest(w_4, h_4, sampleType, numBand, photometricInterpretation);
dstOffX = regionMinX - w_8 + random.nextInt(w_8);
dstOffY = regionMinY + h_4 + random.nextInt(h_8);
destOffset = new Point(dstOffX, dstOffY);
replacePixelsInResultImage(sourceImage, repRegion, imgLLC, destOffset);
writerParam.setDestinationOffset(destOffset);
writer.replacePixels(imgLLC, writerParam);
//-- replace region upper right corner --//
imgLLC = createImageTest(w_4, h_4, sampleType, numBand, photometricInterpretation);
dstOffX = regionMinX + w_4 + random.nextInt(w_8);
dstOffY = regionMinY + h_4 + random.nextInt(h_8);
destOffset = new Point(dstOffX, dstOffY);
replacePixelsInResultImage(sourceImage, repRegion, imgLLC, destOffset);
writerParam.setDestinationOffset(destOffset);
writer.replacePixels(imgLLC, writerParam);
//-- replace region center --//
imgLLC = createImageTest(w_4, h_4, sampleType, numBand, photometricInterpretation);
dstOffX = regionMinX + w_8 + random.nextInt(w_8);
dstOffY = regionMinY + h_8 + random.nextInt(h_8);
destOffset = new Point(dstOffX, dstOffY);
replacePixelsInResultImage(sourceImage, repRegion, imgLLC, destOffset);
writerParam.setDestinationOffset(destOffset);
writer.replacePixels(imgLLC, writerParam);
writer.dispose();
}
/**
* Test method {@link TiffImageWriter#replacePixels(java.awt.image.RenderedImage, javax.imageio.ImageWriteParam) }
* in function of followed criterions.
*
* @param message message in case of error.
* @param sampleType
* @param numBand band number
* @param photometricInterpretation
* @throws IOException if problem during I/O action.
*/
protected void TestReplacePixel (final String message, final SampleType sampleType,
final int numBand, final PhotometricInterpretation photometricInterpretation)
throws IOException {
final File fileTest = File.createTempFile(message, "tiff", tempDir);
final int width = random.nextInt(256) + 16;
final int height = random.nextInt(256) + 16;
final WritableRenderedImage sourceImage = createImageTest(width, height, sampleType, numBand, photometricInterpretation);
writer.setOutput(fileTest); //-- to initialize writer
writerParam.setDestinationOffset(new Point());
writer.write(sourceImage, writerParam);
replacePixels(sourceImage, sampleType, numBand, photometricInterpretation);
reader.setInput(fileTest);
final RenderedImage tested = reader.read(0);
reader.dispose();
checkImage(message, sourceImage, tested);
}
/**
* Fill source image with pixels values from replaceImage at sourceImage and replaceImage intersection.
*
* @param sourceImage source image which will be filled by piece of replaceImage.
* @param sourceRegion region of source image which may be modified.
* @param replaceImage image which will be copied (entirely or not) into sourceImage.
* @param destOffset offset in X and Y direction into sourceImage where to copy replacePixel image.
* @throws IOException if problem during I/O action.
*/
private void replacePixelsInResultImage(final WritableRenderedImage sourceImage, final Rectangle sourceRegion,
final RenderedImage replaceImage, final Point destOffset) throws IOException {
final Rectangle rectImage = new Rectangle(sourceImage.getMinX(), sourceImage.getMinY(), sourceImage.getWidth(), sourceImage.getHeight());
assert rectImage.intersects(sourceRegion) : "sourceRegion and source image should intersect.";
Rectangle sourceInter = rectImage.intersection(sourceRegion);
//-- interested sourceImage region which will be replaced
final Rectangle rectRIP = new Rectangle(replaceImage.getWidth(), replaceImage.getHeight());
rectRIP.translate(destOffset.x, destOffset.y);
sourceInter = sourceInter.intersection(rectRIP);
//-- interested replaceImage Region
final Rectangle repRect = new Rectangle(sourceInter);
repRect.translate(-destOffset.x, -destOffset.y);
assert repRect.x >= 0;
assert repRect.y >= 0;
final PixelIterator sourcePix = PixelIteratorFactory.createRowMajorWriteableIterator(sourceImage, sourceImage, sourceInter);
final PixelIterator replacePix = PixelIteratorFactory.createRowMajorIterator(replaceImage, repRect);
while (sourcePix.next()) {
replacePix.next();
sourcePix.setSampleDouble(replacePix.getSampleDouble());
}
}
}