3789983e89
Reviewed-by: darcy, ihse
417 lines
17 KiB
Java
417 lines
17 KiB
Java
/*
|
|
* Copyright (c) 2017, 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 8164971 8187113
|
|
* @summary The test decodes a png file and checks if the metadata contains
|
|
* image creation time. In addition, the test also merges the custom
|
|
* metadata tree (both standard and native) and succeeds when the
|
|
* metadata contains expected image creation time.
|
|
* @run main PngCreationTimeTest
|
|
*/
|
|
import java.io.IOException;
|
|
import java.io.File;
|
|
import java.nio.file.Files;
|
|
import java.util.Iterator;
|
|
import java.awt.Graphics2D;
|
|
import java.awt.Color;
|
|
import java.awt.image.BufferedImage;
|
|
import javax.imageio.ImageIO;
|
|
import javax.imageio.IIOImage;
|
|
import javax.imageio.ImageTypeSpecifier;
|
|
import javax.imageio.stream.ImageInputStream;
|
|
import javax.imageio.stream.ImageOutputStream;
|
|
import javax.imageio.ImageReadParam;
|
|
import javax.imageio.ImageReader;
|
|
import javax.imageio.ImageWriter;
|
|
import javax.imageio.metadata.IIOMetadata;
|
|
import javax.imageio.metadata.IIOMetadataNode;
|
|
import org.w3c.dom.Node;
|
|
import org.w3c.dom.NamedNodeMap;
|
|
|
|
public class PngCreationTimeTest {
|
|
// Members
|
|
private static IIOMetadata pngMetadata = null;
|
|
|
|
public static void initializeTest() throws IOException {
|
|
Iterator<ImageReader> iterR = null;
|
|
ImageReader pngImageReader = null;
|
|
BufferedImage decImage = null;
|
|
ImageInputStream imageStream = null;
|
|
String fileName = "duke.png";
|
|
String separator = System.getProperty("file.separator");
|
|
String dirPath = System.getProperty("test.src", ".");
|
|
String filePath = dirPath + separator + fileName;
|
|
File file = null;
|
|
|
|
try {
|
|
// Open the required file and check if file exists.
|
|
file = new File(filePath);
|
|
if (file != null && !file.exists()) {
|
|
reportExceptionAndFail("Test Failed. Required image file was"
|
|
+ " not found.");
|
|
}
|
|
|
|
// Get PNG image reader
|
|
iterR = ImageIO.getImageReadersBySuffix("PNG");
|
|
if (iterR.hasNext()) {
|
|
pngImageReader = iterR.next();
|
|
ImageReadParam param = pngImageReader.getDefaultReadParam();
|
|
imageStream = ImageIO.createImageInputStream(file);
|
|
if (imageStream != null) {
|
|
// Last argument informs reader not to ignore metadata
|
|
pngImageReader.setInput(imageStream,
|
|
false,
|
|
false);
|
|
decImage = pngImageReader.read(0, param);
|
|
pngMetadata = pngImageReader.getImageMetadata(0);
|
|
if (pngMetadata != null) {
|
|
// Check if the metadata contains creation time
|
|
testImageMetadata(pngMetadata);
|
|
} else {
|
|
reportExceptionAndFail("Test Failed. Reader could not"
|
|
+ " generate image metadata.");
|
|
}
|
|
} else {
|
|
reportExceptionAndFail("Test Failed. Could not initialize"
|
|
+ " image input stream.");
|
|
}
|
|
} else {
|
|
reportExceptionAndFail("Test Failed. Required image reader"
|
|
+ " was not found.");
|
|
}
|
|
} finally {
|
|
// Release ther resources
|
|
if (imageStream != null) {
|
|
imageStream.close();
|
|
}
|
|
if (pngImageReader != null) {
|
|
pngImageReader.dispose();
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void testImageMetadata(IIOMetadata metadata) {
|
|
/*
|
|
* The source file contains Creation Time in its text chunk. Upon
|
|
* successful decoding, the Standard/Document/ImageCreationTime
|
|
* should exist in the metadata.
|
|
*/
|
|
if (metadata != null) {
|
|
Node keyNode = findNode(metadata.getAsTree("javax_imageio_1.0"),
|
|
"ImageCreationTime");
|
|
if (keyNode == null) {
|
|
reportExceptionAndFail("Test Failed: Could not find image"
|
|
+ " creation time in the metadata.");
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void testSaveCreationTime() throws IOException {
|
|
File file = null;
|
|
Iterator<ImageWriter> iterW = null;
|
|
Iterator<ImageReader> iterR = null;
|
|
ImageWriter pngImageWriter = null;
|
|
ImageReader pngImageReader = null;
|
|
ImageInputStream inputStream = null;
|
|
ImageOutputStream outputStream = null;
|
|
try {
|
|
// Create a simple image and fill with a color
|
|
int imageSize = 200;
|
|
BufferedImage buffImage = new BufferedImage(imageSize, imageSize,
|
|
BufferedImage.TYPE_INT_ARGB);
|
|
Graphics2D g2d = buffImage.createGraphics();
|
|
g2d.setColor(Color.red);
|
|
g2d.fillRect(0, 0, imageSize, imageSize);
|
|
|
|
// Create a temporary file for the output png image
|
|
String fileName = "RoundTripTest";
|
|
file = File.createTempFile(fileName, ".png");
|
|
if (file == null) {
|
|
reportExceptionAndFail("Test Failed. Could not create a"
|
|
+ " temporary file for round trip test.");
|
|
}
|
|
|
|
// Create a PNG writer and write test image with metadata
|
|
iterW = ImageIO.getImageWritersBySuffix("PNG");
|
|
if (iterW.hasNext()) {
|
|
pngImageWriter = iterW.next();
|
|
outputStream = ImageIO.createImageOutputStream(file);
|
|
if (outputStream != null) {
|
|
pngImageWriter.setOutput(outputStream);
|
|
|
|
// Get the default metadata & add image creation time to it.
|
|
ImageTypeSpecifier imgType =
|
|
ImageTypeSpecifier.createFromRenderedImage(buffImage);
|
|
IIOMetadata metadata =
|
|
pngImageWriter.getDefaultImageMetadata(imgType, null);
|
|
IIOMetadataNode root = createStandardMetadataNodeTree();
|
|
metadata.mergeTree("javax_imageio_1.0", root);
|
|
|
|
// Write a png image using buffImage & metadata
|
|
IIOImage iioImage = new IIOImage(buffImage, null, metadata);
|
|
pngImageWriter.write(iioImage);
|
|
} else {
|
|
reportExceptionAndFail("Test Failed. Could not initialize"
|
|
+ " image output stream for round trip test.");
|
|
}
|
|
} else {
|
|
reportExceptionAndFail("Test Failed. Could not find required"
|
|
+ " image writer for the round trip test.");
|
|
}
|
|
|
|
// Create a PNG reader and check if metadata was written
|
|
iterR = ImageIO.getImageReadersBySuffix("PNG");
|
|
if (iterR.hasNext()) {
|
|
pngImageReader = iterR.next();
|
|
inputStream = ImageIO.createImageInputStream(file);
|
|
if (inputStream != null) {
|
|
// Read the image and get the metadata
|
|
pngImageReader.setInput(inputStream, false, false);
|
|
pngImageReader.read(0);
|
|
IIOMetadata imgMetadata =
|
|
pngImageReader.getImageMetadata(0);
|
|
|
|
// Test if the metadata contains creation time.
|
|
testImageMetadata(imgMetadata);
|
|
} else {
|
|
reportExceptionAndFail("Test Failed. Could not initialize"
|
|
+ " image input stream for round trip test.");
|
|
}
|
|
} else {
|
|
reportExceptionAndFail("Test Failed. Cound not find the"
|
|
+ " required image reader.");
|
|
}
|
|
} finally {
|
|
// Release the resources held
|
|
if (inputStream != null) {
|
|
inputStream.close();
|
|
}
|
|
if (outputStream != null) {
|
|
outputStream.close();
|
|
}
|
|
if (pngImageWriter != null) {
|
|
pngImageWriter.dispose();
|
|
}
|
|
if (pngImageReader != null) {
|
|
pngImageReader.dispose();
|
|
}
|
|
// Delete the temp file as well
|
|
if (file != null) {
|
|
Files.delete(file.toPath());
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void reportExceptionAndFail(String message) {
|
|
// A common method to report exception.
|
|
throw new RuntimeException(message);
|
|
}
|
|
|
|
public static void testMergeNativeTree() {
|
|
// Merge a custom native metadata tree and inspect creation time
|
|
if (pngMetadata != null) {
|
|
try {
|
|
IIOMetadataNode root = createNativeMetadataNodeTree();
|
|
|
|
/*
|
|
* Merge the native metadata tree created. The data should
|
|
* reflect in Standard/Document/ImageCreationTime Node
|
|
*/
|
|
pngMetadata.mergeTree("javax_imageio_png_1.0", root);
|
|
Node keyNode = findNode(pngMetadata.getAsTree("javax_imageio_1.0"),
|
|
"ImageCreationTime");
|
|
if (keyNode != null) {
|
|
// Query the attributes of the node and check for the value
|
|
NamedNodeMap attrMap = keyNode.getAttributes();
|
|
String attrValue = attrMap.getNamedItem("year")
|
|
.getNodeValue();
|
|
int decYear = Integer.parseInt(attrValue);
|
|
if (decYear != 2014) {
|
|
// Throw exception. Incorrect year value observed
|
|
reportExceptionAndFail("Test Failed: Incorrect"
|
|
+ " creation time value observed.");
|
|
}
|
|
} else {
|
|
// Throw exception.
|
|
reportExceptionAndFail("Test Failed: Image creation"
|
|
+ " time doesn't exist in metadata.");
|
|
}
|
|
} catch (IOException ex) {
|
|
// Throw exception.
|
|
reportExceptionAndFail("Test Failed: While executing"
|
|
+ " mergeTree on metadata.");
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void testMergeStandardTree() {
|
|
// Merge a standard metadata tree and inspect creation time
|
|
if (pngMetadata != null) {
|
|
try {
|
|
IIOMetadataNode root = createStandardMetadataNodeTree();
|
|
|
|
/*
|
|
* Merge the standard metadata tree created. The data should
|
|
* correctly reflect in the native tree
|
|
*/
|
|
pngMetadata.mergeTree("javax_imageio_1.0", root);
|
|
Node keyNode = findNode(pngMetadata.getAsTree("javax_imageio_png_1.0"),
|
|
"tEXtEntry");
|
|
// Last text entry would contain the merged information
|
|
while (keyNode != null && keyNode.getNextSibling() != null) {
|
|
keyNode = keyNode.getNextSibling();
|
|
}
|
|
|
|
if (keyNode != null) {
|
|
// Query the attributes of the node and check for the value
|
|
NamedNodeMap attrMap = keyNode.getAttributes();
|
|
String attrValue = attrMap.getNamedItem("value")
|
|
.getNodeValue();
|
|
if (!attrValue.contains("2016")) {
|
|
// Throw exception. Incorrect year value observed
|
|
throw new RuntimeException("Test Failed: Incorrect"
|
|
+ " creation time value observed.");
|
|
}
|
|
} else {
|
|
// Throw exception.
|
|
reportExceptionAndFail("Test Failed: Image creation"
|
|
+ " time doesn't exist in metadata.");
|
|
}
|
|
} catch (IOException ex) {
|
|
// Throw exception.
|
|
reportExceptionAndFail("Test Failed: While executing"
|
|
+ " mergeTree on metadata.");
|
|
}
|
|
}
|
|
}
|
|
|
|
public static IIOMetadataNode createNativeMetadataNodeTree() {
|
|
// Create a text node to hold tEXtEntries
|
|
IIOMetadataNode tEXtNode = new IIOMetadataNode("tEXt");
|
|
|
|
// Create tEXt entry to hold random date time
|
|
IIOMetadataNode randomTimeEntry = new IIOMetadataNode("tEXtEntry");
|
|
randomTimeEntry.setAttribute("keyword", "Creation Time");
|
|
randomTimeEntry.setAttribute("value", "21 Dec 2015,Monday");
|
|
tEXtNode.appendChild(randomTimeEntry);
|
|
|
|
// Create a tEXt entry to hold time in RFC1123 format
|
|
IIOMetadataNode rfcTextEntry = new IIOMetadataNode("tEXtEntry");
|
|
rfcTextEntry.setAttribute("keyword", "Creation Time");
|
|
rfcTextEntry.setAttribute("value", "Mon, 21 Dec 2015 09:04:30 +0530");
|
|
tEXtNode.appendChild(rfcTextEntry);
|
|
|
|
// Create a tEXt entry to hold time in ISO format
|
|
IIOMetadataNode isoTextEntry = new IIOMetadataNode("tEXtEntry");
|
|
isoTextEntry.setAttribute("keyword", "Creation Time");
|
|
isoTextEntry.setAttribute("value", "2014-12-21T09:04:30+05:30");
|
|
tEXtNode.appendChild(isoTextEntry);
|
|
|
|
// Create a root node append the text node
|
|
IIOMetadataNode root = new IIOMetadataNode("javax_imageio_png_1.0");
|
|
root.appendChild(tEXtNode);
|
|
|
|
return root;
|
|
}
|
|
|
|
public static IIOMetadataNode createStandardMetadataNodeTree() {
|
|
/*
|
|
* Create standard metadata tree with creation time in
|
|
* Standard(Root)/Document/ImageCreationTime node
|
|
*/
|
|
IIOMetadataNode createTimeNode = new IIOMetadataNode("ImageCreationTime");
|
|
createTimeNode.setAttribute("year", "2016");
|
|
createTimeNode.setAttribute("month", "12");
|
|
createTimeNode.setAttribute("day", "21");
|
|
createTimeNode.setAttribute("hour", "18");
|
|
createTimeNode.setAttribute("minute", "30");
|
|
createTimeNode.setAttribute("second", "00");
|
|
|
|
// Create the Document node
|
|
IIOMetadataNode documentNode = new IIOMetadataNode("Document");
|
|
documentNode.appendChild(createTimeNode);
|
|
|
|
// Create a root node append the Document node
|
|
IIOMetadataNode root = new IIOMetadataNode("javax_imageio_1.0");
|
|
root.appendChild(documentNode);
|
|
|
|
return root;
|
|
}
|
|
|
|
public static Node findNode(Node root, String nodeName) {
|
|
// Return value
|
|
Node retVal = null;
|
|
|
|
if (root != null ) {
|
|
// Check if the name of root node matches the key
|
|
String name = root.getNodeName();
|
|
if (name.equalsIgnoreCase(nodeName)) {
|
|
return root;
|
|
}
|
|
|
|
// Process all children
|
|
Node node = root.getFirstChild();
|
|
while (node != null) {
|
|
retVal = findNode(node, nodeName);
|
|
if (retVal != null ) {
|
|
// We found the node. Stop the search
|
|
break;
|
|
}
|
|
node = node.getNextSibling();
|
|
}
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
public static void main(String[] args) throws IOException {
|
|
/*
|
|
* Initialize the test by decoding a PNG image that has creation
|
|
* time in one of its text chunks and check if the metadata returned
|
|
* contains image creation time.
|
|
*/
|
|
initializeTest();
|
|
|
|
/*
|
|
* Test the round trip usecase. Write a PNG file with "Creation Time"
|
|
* in text chunk and decode the same to check if the creation time
|
|
* was indeed written to the PNG file.
|
|
*/
|
|
testSaveCreationTime();
|
|
|
|
/*
|
|
* Modify the metadata by merging a standard metadata tree and inspect
|
|
* the value in the native tree
|
|
*/
|
|
testMergeNativeTree();
|
|
|
|
/*
|
|
* Modify the metadata by merging a native metadata tree and inspect
|
|
* the value in the standard tree.
|
|
*/
|
|
testMergeStandardTree();
|
|
}
|
|
}
|