Path: blob/master/test/jdk/javax/imageio/plugins/tiff/WriteToSequenceAfterAbort.java
41153 views
/*1* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223import java.awt.Color;24import java.awt.Graphics2D;25import java.awt.Rectangle;26import java.awt.image.BufferedImage;27import java.io.File;28import java.io.FileNotFoundException;29import java.io.FileOutputStream;30import java.io.IOException;3132import javax.imageio.ImageIO;33import javax.imageio.ImageWriter;34import javax.imageio.event.IIOWriteProgressListener;35import javax.imageio.stream.ImageOutputStream;3637import static java.awt.image.BufferedImage.TYPE_BYTE_BINARY;38import java.awt.image.ColorModel;39import java.awt.image.Raster;40import java.awt.image.RenderedImage;41import java.awt.image.SampleModel;42import java.awt.image.WritableRaster;43import java.util.Vector;44import javax.imageio.IIOImage;45import javax.imageio.ImageReader;46import javax.imageio.stream.ImageInputStream;4748/**49* @test50* @bug 814424551* @summary Ensure aborting write works properly for a TIFF sequence.52*/53public final class WriteToSequenceAfterAbort implements IIOWriteProgressListener {5455private volatile boolean abortFlag = true;56private volatile boolean isAbortCalled;57private volatile boolean isCompleteCalled;58private volatile boolean isProgressCalled;59private volatile boolean isStartedCalled;60private static final int WIDTH = 100;61private static final int HEIGHT = 100;62private static final int NUM_TILES_XY = 3;6364private class TiledImage implements RenderedImage {65private final BufferedImage tile;66private final BufferedImage image;67private final int numXTiles, numYTiles;68private boolean isImageInitialized = false;6970TiledImage(BufferedImage tile, int numXTiles, int numYTiles) {71this.tile = tile;72this.numXTiles = numXTiles;73this.numYTiles = numYTiles;74image = new BufferedImage(getWidth(), getHeight(), tile.getType());75}7677@Override78public Vector<RenderedImage> getSources() {79return null;80}8182@Override83public Object getProperty(String string) {84return java.awt.Image.UndefinedProperty;85}8687@Override88public String[] getPropertyNames() {89return new String[0];90}9192@Override93public ColorModel getColorModel() {94return tile.getColorModel();95}9697@Override98public SampleModel getSampleModel() {99return tile.getSampleModel();100}101102@Override103public int getWidth() {104return numXTiles*tile.getWidth();105}106107@Override108public int getHeight() {109return numYTiles*tile.getHeight();110}111112@Override113public int getMinX() {114return 0;115}116117@Override118public int getMinY() {119return 0;120}121122@Override123public int getNumXTiles() {124return numXTiles;125}126127@Override128public int getNumYTiles() {129return numYTiles;130}131132@Override133public int getMinTileX() {134return 0;135}136137@Override138public int getMinTileY() {139return 0;140}141142@Override143public int getTileWidth() {144return tile.getWidth();145}146147@Override148public int getTileHeight() {149return tile.getHeight();150}151152@Override153public int getTileGridXOffset() {154return 0;155}156157@Override158public int getTileGridYOffset() {159return 0;160}161162@Override163public Raster getTile(int x, int y) {164WritableRaster r = tile.getRaster();165return r.createWritableTranslatedChild(x*tile.getWidth(),166y*tile.getHeight());167}168169@Override170public Raster getData() {171return getAsBufferedImage().getData();172}173174@Override175public Raster getData(Rectangle r) {176return getAsBufferedImage().getData(r);177}178179@Override180public WritableRaster copyData(WritableRaster wr) {181return getAsBufferedImage().copyData(wr);182}183184public BufferedImage getAsBufferedImage() {185synchronized (image) {186if (!isImageInitialized) {187int tx0 = getMinTileX(), ty0 = getMinTileY();188int txN = tx0 + getNumXTiles(), tyN = ty0 + getNumYTiles();189for (int j = ty0; j < tyN; j++) {190for (int i = tx0; i < txN; i++) {191image.setData(getTile(i, j));192}193}194}195isImageInitialized = true;196}197return image;198}199}200201private void test(final ImageWriter writer) throws IOException {202String suffix = writer.getOriginatingProvider().getFileSuffixes()[0];203204// Image initialization205BufferedImage imageUpperLeft =206new BufferedImage(WIDTH, HEIGHT, TYPE_BYTE_BINARY);207Graphics2D g = imageUpperLeft.createGraphics();208g.setColor(Color.WHITE);209g.fillRect(0, 0, WIDTH/2, HEIGHT/2);210g.dispose();211BufferedImage imageLowerRight =212new BufferedImage(WIDTH, HEIGHT, TYPE_BYTE_BINARY);213g = imageLowerRight.createGraphics();214g.setColor(Color.WHITE);215g.fillRect(WIDTH/2, HEIGHT/2, WIDTH/2, HEIGHT/2);216g.dispose();217TiledImage[] images = new TiledImage[] {218new TiledImage(imageUpperLeft, NUM_TILES_XY, NUM_TILES_XY),219new TiledImage(imageUpperLeft, NUM_TILES_XY, NUM_TILES_XY),220new TiledImage(imageLowerRight, NUM_TILES_XY, NUM_TILES_XY),221new TiledImage(imageLowerRight, NUM_TILES_XY, NUM_TILES_XY)222};223224// File initialization225File file = File.createTempFile("temp", "." + suffix);226file.deleteOnExit();227FileOutputStream fos = new SkipWriteOnAbortOutputStream(file);228ImageOutputStream ios = ImageIO.createImageOutputStream(fos);229writer.setOutput(ios);230writer.addIIOWriteProgressListener(this);231232writer.prepareWriteSequence(null);233boolean[] abortions = new boolean[] {true, false, true, false};234for (int i = 0; i < 4; i++) {235abortFlag = abortions[i];236isAbortCalled = false;237isCompleteCalled = false;238isProgressCalled = false;239isStartedCalled = false;240241TiledImage image = images[i];242if (abortFlag) {243// This write will be aborted, and file will not be touched244writer.writeToSequence(new IIOImage(image, null, null), null);245if (!isStartedCalled) {246throw new RuntimeException("Started should be called");247}248if (!isProgressCalled) {249throw new RuntimeException("Progress should be called");250}251if (!isAbortCalled) {252throw new RuntimeException("Abort should be called");253}254if (isCompleteCalled) {255throw new RuntimeException("Complete should not be called");256}257} else {258// This write should be completed successfully and the file should259// contain correct image data.260writer.writeToSequence(new IIOImage(image, null, null), null);261if (!isStartedCalled) {262throw new RuntimeException("Started should be called");263}264if (!isProgressCalled) {265throw new RuntimeException("Progress should be called");266}267if (isAbortCalled) {268throw new RuntimeException("Abort should not be called");269}270if (!isCompleteCalled) {271throw new RuntimeException("Complete should be called");272}273}274}275276writer.endWriteSequence();277writer.dispose();278ios.close();279280// Validates content of the file.281ImageReader reader = ImageIO.getImageReader(writer);282ImageInputStream iis = ImageIO.createImageInputStream(file);283reader.setInput(iis);284for (int i = 0; i < 2; i++) {285System.out.println("Testing image " + i);286BufferedImage imageRead = reader.read(i);287BufferedImage imageWrite = images[2 * i].getAsBufferedImage();288for (int x = 0; x < WIDTH; ++x) {289for (int y = 0; y < HEIGHT; ++y) {290if (imageRead.getRGB(x, y) != imageWrite.getRGB(x, y)) {291throw new RuntimeException("Test failed for image " + i);292}293}294}295}296}297298public static void main(final String[] args) throws IOException {299WriteToSequenceAfterAbort writeAfterAbort = new WriteToSequenceAfterAbort();300ImageWriter writer = ImageIO.getImageWritersByFormatName("TIFF").next();301writeAfterAbort.test(writer);302System.out.println("Test passed.");303}304305// Callbacks306307@Override308public void imageComplete(ImageWriter source) {309isCompleteCalled = true;310}311312@Override313public void imageProgress(ImageWriter source, float percentageDone) {314isProgressCalled = true;315if (percentageDone > 50 && abortFlag) {316source.abort();317}318}319320@Override321public void imageStarted(ImageWriter source, int imageIndex) {322isStartedCalled = true;323}324325@Override326public void writeAborted(final ImageWriter source) {327isAbortCalled = true;328}329330@Override331public void thumbnailComplete(ImageWriter source) {332}333334@Override335public void thumbnailProgress(ImageWriter source, float percentageDone) {336}337338@Override339public void thumbnailStarted(ImageWriter source, int imageIndex,340int thumbnailIndex) {341}342343/**344* We need to skip writes on abort, because content of the file after abort345* is undefined.346*/347private class SkipWriteOnAbortOutputStream extends FileOutputStream {348349SkipWriteOnAbortOutputStream(File file) throws FileNotFoundException {350super(file);351}352353@Override354public void write(int b) throws IOException {355if (!abortFlag) {356super.write(b);357}358}359360@Override361public void write(byte[] b) throws IOException {362if (!abortFlag) {363super.write(b);364}365}366367@Override368public void write(byte[] b, int off, int len) throws IOException {369if (!abortFlag) {370super.write(b, off, len);371}372}373}374}375376377378