4924727: reader.abort() method does not work when called inside imageStarted for PNG
Reviewed-by: prr, serb, bpb
--- a/jdk/make/mapfiles/libjpeg/mapfile-vers Sat Sep 10 14:50:35 2016 +0530
+++ b/jdk/make/mapfiles/libjpeg/mapfile-vers Mon Sep 12 12:07:56 2016 +0530
@@ -42,6 +42,7 @@
Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_resetReader;
Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_disposeReader;
Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_resetLibraryState;
+ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_clearNativeReadAbortFlag;
Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_initWriterIDs;
Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_initJPEGImageWriter;
Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_setDest;
--- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageReader.java Sat Sep 10 14:50:35 2016 +0530
+++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageReader.java Mon Sep 12 12:07:56 2016 +0530
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -749,6 +749,10 @@
checkIndex(imageIndex);
clearAbortRequest();
processImageStarted(imageIndex);
+ if (abortRequested()) {
+ processReadAborted();
+ return bi;
+ }
if (param == null)
param = getDefaultReadParam();
@@ -1005,9 +1009,6 @@
int j = isBottomUp ? (height -1)*bytesPerScanline : 0;
for (int i=0; i<height; i++) {
- if (abortRequested()) {
- break;
- }
iis.readFully(bdata, j, bytesPerScanline);
iis.skipBytes(padding);
j += isBottomUp ? -bytesPerScanline : bytesPerScanline;
@@ -1015,6 +1016,9 @@
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F * i/destinationRegion.height);
+ if (abortRequested()) {
+ break;
+ }
}
} else {
byte[] buf = new byte[lineLength];
@@ -1051,9 +1055,6 @@
for (int j = 0, y = sourceRegion.y;
j < destinationRegion.height; j++, y+=scaleY) {
-
- if (abortRequested())
- break;
iis.read(buf, 0, lineLength);
for (int i = 0; i < destinationRegion.width; i++) {
//get the bit and assign to the data buffer of the raster
@@ -1067,6 +1068,9 @@
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F*j/destinationRegion.height);
+ if (abortRequested()) {
+ break;
+ }
}
}
}
@@ -1087,9 +1091,6 @@
int j = isBottomUp ? (height -1) * bytesPerScanline : 0;
for (int i=0; i<height; i++) {
- if (abortRequested()) {
- break;
- }
iis.readFully(bdata, j, bytesPerScanline);
iis.skipBytes(padding);
j += isBottomUp ? -bytesPerScanline : bytesPerScanline;
@@ -1097,6 +1098,9 @@
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F * i/destinationRegion.height);
+ if (abortRequested()) {
+ break;
+ }
}
} else {
byte[] buf = new byte[lineLength];
@@ -1133,9 +1137,6 @@
for (int j = 0, y = sourceRegion.y;
j < destinationRegion.height; j++, y+=scaleY) {
-
- if (abortRequested())
- break;
iis.read(buf, 0, lineLength);
for (int i = 0; i < destinationRegion.width; i++) {
//get the bit and assign to the data buffer of the raster
@@ -1149,6 +1150,9 @@
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F*j/destinationRegion.height);
+ if (abortRequested()) {
+ break;
+ }
}
}
}
@@ -1168,9 +1172,6 @@
int j = isBottomUp ? (height -1) * width : 0;
for (int i=0; i<height; i++) {
- if (abortRequested()) {
- break;
- }
iis.readFully(bdata, j, width);
iis.skipBytes(padding);
j += isBottomUp ? -width : width;
@@ -1178,6 +1179,9 @@
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F * i/destinationRegion.height);
+ if (abortRequested()) {
+ break;
+ }
}
} else {
byte[] buf = new byte[lineLength];
@@ -1200,9 +1204,6 @@
for (int j = 0, y = sourceRegion.y;
j < destinationRegion.height; j++, y+=scaleY) {
-
- if (abortRequested())
- break;
iis.read(buf, 0, lineLength);
for (int i = 0, m = sourceRegion.x;
i < destinationRegion.width; i++, m += scaleX) {
@@ -1216,6 +1217,9 @@
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F*j/destinationRegion.height);
+ if (abortRequested()) {
+ break;
+ }
}
}
}
@@ -1235,9 +1239,6 @@
int j = isBottomUp ? (height -1) * width * 3 : 0;
for (int i=0; i<height; i++) {
- if (abortRequested()) {
- break;
- }
iis.readFully(bdata, j, lineStride);
iis.skipBytes(padding);
j += isBottomUp ? -lineStride : lineStride;
@@ -1245,6 +1246,9 @@
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F * i/destinationRegion.height);
+ if (abortRequested()) {
+ break;
+ }
}
} else {
byte[] buf = new byte[lineLength];
@@ -1267,9 +1271,6 @@
for (int j = 0, y = sourceRegion.y;
j < destinationRegion.height; j++, y+=scaleY) {
-
- if (abortRequested())
- break;
iis.read(buf, 0, lineLength);
for (int i = 0, m = 3 * sourceRegion.x;
i < destinationRegion.width; i++, m += 3 * scaleX) {
@@ -1285,6 +1286,9 @@
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F*j/destinationRegion.height);
+ if (abortRequested()) {
+ break;
+ }
}
}
}
@@ -1302,10 +1306,6 @@
if (noTransform) {
int j = isBottomUp ? (height -1) * width : 0;
for (int i=0; i<height; i++) {
- if (abortRequested()) {
- break;
- }
-
iis.readFully(sdata, j, width);
iis.skipBytes(padding);
@@ -1314,6 +1314,9 @@
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F * i/destinationRegion.height);
+ if (abortRequested()) {
+ break;
+ }
}
} else {
short[] buf = new short[lineLength];
@@ -1336,9 +1339,6 @@
for (int j = 0, y = sourceRegion.y;
j < destinationRegion.height; j++, y+=scaleY) {
-
- if (abortRequested())
- break;
iis.readFully(buf, 0, lineLength);
for (int i = 0, m = sourceRegion.x;
i < destinationRegion.width; i++, m += scaleX) {
@@ -1352,6 +1352,9 @@
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F*j/destinationRegion.height);
+ if (abortRequested()) {
+ break;
+ }
}
}
}
@@ -1361,15 +1364,15 @@
int j = isBottomUp ? (height -1) * width : 0;
for (int i=0; i<height; i++) {
- if (abortRequested()) {
- break;
- }
iis.readFully(idata, j, width);
j += isBottomUp ? -width : width;
processImageUpdate(bi, 0, i,
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F * i/destinationRegion.height);
+ if (abortRequested()) {
+ break;
+ }
}
} else {
int[] buf = new int[width];
@@ -1392,9 +1395,6 @@
for (int j = 0, y = sourceRegion.y;
j < destinationRegion.height; j++, y+=scaleY) {
-
- if (abortRequested())
- break;
iis.readFully(buf, 0, width);
for (int i = 0, m = sourceRegion.x;
i < destinationRegion.width; i++, m += scaleX) {
@@ -1408,6 +1408,9 @@
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F*j/destinationRegion.height);
+ if (abortRequested()) {
+ break;
+ }
}
}
}
--- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageReader.java Sat Sep 10 14:50:35 2016 +0530
+++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageReader.java Mon Sep 12 12:07:56 2016 +0530
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -456,6 +456,9 @@
// Update IIOReadProgressListeners
++rowsDone;
processImageProgress(100.0F*rowsDone/height);
+ if (abortRequested()) {
+ return;
+ }
if (decodeThisRow) {
outputRow();
@@ -860,7 +863,6 @@
throw new IndexOutOfBoundsException("imageIndex out of bounds!");
}
- clearAbortRequest();
readMetadata();
// A null ImageReadParam means we use the default
@@ -903,8 +905,13 @@
(streamY - sourceRegion.y)/sourceYSubsampling;
computeDecodeThisRow();
+ clearAbortRequest();
// Inform IIOReadProgressListeners of start of image
processImageStarted(imageIndex);
+ if (abortRequested()) {
+ processReadAborted();
+ return theImage;
+ }
startPass(0);
this.rowBuf = new byte[width];
@@ -947,7 +954,7 @@
int codeSize = initCodeSize + 1;
int codeMask = (1 << codeSize) - 1;
- while (!abortRequested()) {
+ do {
code = getCode(codeSize, codeMask);
if (code == clearCode) {
@@ -1005,7 +1012,7 @@
outputPixels(string, len);
oldCode = code;
- }
+ } while (!abortRequested());
processReadAborted();
return theImage;
--- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java Sat Sep 10 14:50:35 2016 +0530
+++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java Mon Sep 12 12:07:56 2016 +0530
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -1327,28 +1327,32 @@
System.out.println("callbackUpdates is " + callbackUpdates);
}
- // Finally, we are ready to read
-
+ /*
+ * All the Jpeg processing happens in native, we should clear
+ * abortFlag of imageIODataStruct in imageioJPEG.c. And we need to
+ * clear abortFlag because if in previous read() if we had called
+ * reader.abort() that will continue to be valid for present call also.
+ */
+ clearNativeReadAbortFlag(structPointer);
processImageStarted(currentImage);
-
- boolean aborted = false;
-
- // Note that getData disables acceleration on buffer, but it is
- // just a 1-line intermediate data transfer buffer that will not
- // affect the acceleration of the resulting image.
- aborted = readImage(structPointer,
- buffer.getData(),
- numRasterBands,
- srcBands,
- bandSizes,
- srcROI.x, srcROI.y,
- srcROI.width, srcROI.height,
- periodX, periodY,
- abbrevQTables,
- abbrevDCHuffmanTables,
- abbrevACHuffmanTables,
- minProgressivePass, maxProgressivePass,
- callbackUpdates);
+ /*
+ * Note that getData disables acceleration on buffer, but it is
+ * just a 1-line intermediate data transfer buffer that will not
+ * affect the acceleration of the resulting image.
+ */
+ boolean aborted = readImage(structPointer,
+ buffer.getData(),
+ numRasterBands,
+ srcBands,
+ bandSizes,
+ srcROI.x, srcROI.y,
+ srcROI.width, srcROI.height,
+ periodX, periodY,
+ abbrevQTables,
+ abbrevDCHuffmanTables,
+ abbrevACHuffmanTables,
+ minProgressivePass, maxProgressivePass,
+ callbackUpdates);
if (aborted) {
processReadAborted();
@@ -1513,6 +1517,12 @@
int maxProgressivePass,
boolean wantUpdates);
+ /*
+ * We should call clearNativeReadAbortFlag() before we start reading
+ * jpeg image as image processing happens at native side.
+ */
+ private native void clearNativeReadAbortFlag(long structPointer);
+
public void abort() {
setThreadLock();
try {
--- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageReader.java Sat Sep 10 14:50:35 2016 +0530
+++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageReader.java Mon Sep 12 12:07:56 2016 +0530
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -937,12 +937,6 @@
for (int srcY = 0; srcY < passHeight; srcY++) {
// Skip filter byte and the remaining row bytes
pixelStream.skipBytes(1 + bytesPerRow);
-
- // If read has been aborted, just return
- // processReadAborted will be called later
- if (abortRequested()) {
- return;
- }
}
}
@@ -996,6 +990,13 @@
for (int srcY = 0; srcY < passHeight; srcY++) {
// Update count of pixels read
updateImageProgress(passWidth);
+ /*
+ * If read has been aborted, just return
+ * processReadAborted will be called later
+ */
+ if (abortRequested()) {
+ return;
+ }
// Skip filter byte and the remaining row bytes
pixelStream.skipBytes(1 + bytesPerRow);
}
@@ -1105,7 +1106,13 @@
for (int srcY = 0; srcY < passHeight; srcY++) {
// Update count of pixels read
updateImageProgress(passWidth);
-
+ /*
+ * If read has been aborted, just return
+ * processReadAborted will be called later
+ */
+ if (abortRequested()) {
+ return;
+ }
// Read the filter type byte and a row of data
int filter = pixelStream.read();
try {
@@ -1195,12 +1202,6 @@
updateWidth, 1,
updateXStep, updateYStep,
destinationBands);
-
- // If read has been aborted, just return
- // processReadAborted will be called later
- if (abortRequested()) {
- return;
- }
}
}
@@ -1215,8 +1216,6 @@
this.pixelsDone = 0;
this.totalPixels = width*height;
- clearAbortRequest();
-
if (metadata.IHDR_interlaceMethod == 0) {
decodePass(0, 0, 0, 1, 1, width, height);
} else {
@@ -1241,8 +1240,10 @@
(height + ybump)/YSubsampling);
}
- // If read has been aborted, just return
- // processReadAborted will be called later
+ /*
+ * If read has been aborted, just return
+ * processReadAborted will be called later
+ */
if (abortRequested()) {
return;
}
@@ -1332,13 +1333,19 @@
inputBandsForColorType[colorType],
theImage.getSampleModel().getNumBands());
+ clearAbortRequest();
processImageStarted(0);
- decodeImage();
if (abortRequested()) {
processReadAborted();
} else {
- processImageComplete();
+ decodeImage();
+ if (abortRequested()) {
+ processReadAborted();
+ } else {
+ processImageComplete();
+ }
}
+
} catch (IOException e) {
throw new IIOException("Error reading PNG image data", e);
} finally {
--- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReader.java Sat Sep 10 14:50:35 2016 +0530
+++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReader.java Mon Sep 12 12:07:56 2016 +0530
@@ -1131,8 +1131,12 @@
pixelsToRead = destRegion.width * destRegion.height;
pixelsRead = 0;
+ clearAbortRequest();
processImageStarted(imageIndex);
- processImageProgress(0.0f);
+ if (abortRequested()) {
+ processReadAborted();
+ return theImage;
+ }
tilesAcross = (width + tileOrStripWidth - 1) / tileOrStripWidth;
tilesDown = (height + tileOrStripHeight - 1) / tileOrStripHeight;
@@ -1286,6 +1290,10 @@
}
reportProgress();
+ if (abortRequested()) {
+ processReadAborted();
+ return theImage;
+ }
}
}
} else {
@@ -1294,16 +1302,14 @@
decodeTile(ti, tj, -1);
reportProgress();
+ if (abortRequested()) {
+ processReadAborted();
+ return theImage;
+ }
}
}
}
-
- if (abortRequested()) {
- processReadAborted();
- } else {
- processImageComplete();
- }
-
+ processImageComplete();
return theImage;
}
--- a/jdk/src/java.desktop/share/native/libjavajpeg/imageioJPEG.c Sat Sep 10 14:50:35 2016 +0530
+++ b/jdk/src/java.desktop/share/native/libjavajpeg/imageioJPEG.c Mon Sep 12 12:07:56 2016 +0530
@@ -2162,6 +2162,25 @@
}
JNIEXPORT void JNICALL
+Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_clearNativeReadAbortFlag
+ (JNIEnv *env,
+ jobject this,
+ jlong ptr) {
+
+ imageIODataPtr data = (imageIODataPtr)jlong_to_ptr(ptr);
+
+ if (data == NULL) {
+ JNU_ThrowByName(env,
+ "java/lang/IllegalStateException",
+ "Attempting to use reader after dispose()");
+ return;
+ }
+
+ data->abortFlag = JNI_FALSE;
+
+}
+
+JNIEXPORT void JNICALL
Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_abortRead
(JNIEnv *env,
jobject this,
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/imageio/ReadAbortTest.java Mon Sep 12 12:07:56 2016 +0530
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+ /*
+ * @test
+ * @bug 4924727
+ * @summary Test verifies that if we call ImageReader.abort() in
+ * IIOReadProgressListener.imageStarted() or
+ * IIOReadProgressListener.imageProgress() are we
+ * calling IIOReadProgressListener.readAborted() for all readers.
+ * @run main ReadAbortTest
+ */
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.util.Iterator;
+import javax.imageio.ImageIO;
+import javax.imageio.ImageReader;
+import javax.imageio.event.IIOReadProgressListener;
+import javax.imageio.stream.ImageInputStream;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.nio.file.Files;
+
+public class ReadAbortTest implements IIOReadProgressListener {
+
+ ImageReader reader = null;
+ ImageInputStream iis = null;
+ BufferedImage bimg = null;
+ File file;
+ boolean startAbort = false;
+ boolean startAborted = false;
+ boolean progressAbort = false;
+ boolean progressAborted = false;
+ Color srccolor = Color.red;
+ int width = 100;
+ int heght = 100;
+
+ public ReadAbortTest(String format) throws Exception {
+ try {
+ System.out.println("Test for format " + format);
+ bimg = new BufferedImage(width, heght,
+ BufferedImage.TYPE_INT_RGB);
+
+ Graphics2D g = bimg.createGraphics();
+ g.setColor(srccolor);
+ g.fillRect(0, 0, width, heght);
+ g.dispose();
+
+ file = File.createTempFile("src_", "." + format, new File("."));
+ ImageIO.write(bimg, format, file);
+ ImageInputStream iis = ImageIO.createImageInputStream(file);
+
+ Iterator iter = ImageIO.getImageReaders(iis);
+ while (iter.hasNext()) {
+ reader = (ImageReader) iter.next();
+ break;
+ }
+ reader.setInput(iis);
+ reader.addIIOReadProgressListener(this);
+
+ // Abort reading in IIOReadProgressListener.imageStarted().
+ startAbort = true;
+ bimg = reader.read(0);
+ startAbort = false;
+
+ // Abort reading in IIOReadProgressListener.imageProgress().
+ progressAbort = true;
+ bimg = reader.read(0);
+ progressAbort = false;
+
+ iis.close();
+ /*
+ * All abort requests from imageStarted,imageProgress and
+ * imageComplete from IIOReadProgressListener should be reached
+ * otherwise throw RuntimeException.
+ */
+ if (!(startAborted
+ && progressAborted)) {
+ throw new RuntimeException("All IIOReadProgressListener abort"
+ + " requests are not processed for format "
+ + format);
+ }
+ } catch (Exception e) {
+ throw e;
+ } finally {
+ Files.delete(file.toPath());
+ }
+ }
+
+ /*
+ * Abstract methods that we need to implement from
+ * IIOReadProgressListener, and relevant for this test case.
+ */
+ @Override
+ public void imageStarted(ImageReader source, int imageIndex) {
+ System.out.println("imageStarted called");
+ if (startAbort) {
+ source.abort();
+ }
+ }
+
+ @Override
+ public void imageProgress(ImageReader source, float percentageDone) {
+ System.out.println("imageProgress called");
+ if (progressAbort) {
+ source.abort();
+ }
+ }
+
+ @Override
+ public void readAborted(ImageReader source) {
+ System.out.println("readAborted called");
+ // Verify IIOReadProgressListener.imageStarted() abort request.
+ if (startAbort) {
+ System.out.println("imageStarted aborted ");
+ startAborted = true;
+ }
+
+ // Verify IIOReadProgressListener.imageProgress() abort request.
+ if (progressAbort) {
+ System.out.println("imageProgress aborted ");
+ progressAborted = true;
+ }
+ }
+
+ public static void main(String args[]) throws Exception {
+ final String[] formats = {"bmp", "png", "gif", "jpg", "tif"};
+ for (String format : formats) {
+ new ReadAbortTest(format);
+ }
+ }
+
+ /*
+ * Remaining abstract methods that we need to implement from
+ * IIOReadProgressListener, but not relevant for this test case.
+ */
+ @Override
+ public void imageComplete(ImageReader source) {
+ }
+
+ @Override
+ public void sequenceStarted(ImageReader reader, int i) {
+ }
+
+ @Override
+ public void sequenceComplete(ImageReader reader) {
+ }
+
+ @Override
+ public void thumbnailStarted(ImageReader reader, int i, int i1) {
+ }
+
+ @Override
+ public void thumbnailProgress(ImageReader reader, float f) {
+ }
+
+ @Override
+ public void thumbnailComplete(ImageReader reader) {
+ }
+}
+