ImageComparator compares a byte[] for equality by creating 2 hashes for the bytearray and comparing thoose hashes.
/** * * JFreeReport : a free Java reporting library * * * Project Info: http://reporting.pentaho.org/ * * (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors. * * 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; * either version 2.1 of the License, or (at your option) any later version. * * 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. * * You should have received a copy of the GNU Lesser General Public License along with this * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307, USA. * * [Java is a trademark or registered trademark of Sun Microsystems, Inc. * in the United States and other countries.] * * ------------ * ImageComparator.java * ------------ * (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors. */ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; /** * The ImageComparator tries to compare a byte[] for equality by creating 2 hashes for the * bytearray and comparing thoose hashes. If no digest algorithms are available, then the * complete byte[] is used for comparison. * <p> * Using the digest method trades computing time for space. * * @author Thomas Morgner */ public class ImageComparator { /** * A ImageCompareData that uses the complete image data for comparison. */ private static final class CompleteImageCompareData { /** * The image content. */ private final byte[] image; /** * Create a new CompleteImageCompareData instance. * * @param image the image data used for comparison. */ private CompleteImageCompareData (final byte[] image) { this.image = image; } /** * Checks whether the given Object equals this object. * * @param o the to be compared object * @return true, if both objects are equal */ public boolean equals (final Object o) { if (this == o) { return true; } if (!(o instanceof CompleteImageCompareData)) { return false; } final CompleteImageCompareData data = (CompleteImageCompareData) o; if (!Arrays.equals(image, data.image)) { return false; } return true; } /** * returns a hashcode for this class. * * @return always 0. */ public int hashCode () { return image.length; } } /** * An ImageComparator which uses precomputed Message-Digests to compare the image. */ private static final class DigestImageCompareData { /** * An MD5 digest. */ private byte[] digestMD5Data; /** * An SHA digest. */ private byte[] digestSHAData; /** * Creates a new DigestImageCompareData instance. * * @param digestMD5Data the MD5 digest data * @param digestSHAData the SHA1 digest data */ private DigestImageCompareData (final byte[] digestMD5Data, final byte[] digestSHAData) { if (digestMD5Data == null || digestSHAData == null) { throw new NullPointerException(); } this.digestMD5Data = digestMD5Data; this.digestSHAData = digestSHAData; } /** * Checks whether the given Object equals this object. * * @param o the to be compared object * @return true, if both objects are equal */ public boolean equals (final Object o) { if (this == o) { return true; } if (!(o instanceof DigestImageCompareData)) { return false; } final DigestImageCompareData data = (DigestImageCompareData) o; if (!Arrays.equals(digestMD5Data, data.digestMD5Data)) { return false; } if (!Arrays.equals(digestSHAData, data.digestSHAData)) { return false; } return true; } /** * returns a hashcode for this class. * * @return always 0. */ public int hashCode () { return 0; } } /** * An MD5 message digest. */ private MessageDigest digestMD5; /** * An SHA message digest. */ private MessageDigest digestSHA; /** * Creates a new ImageComparator. The comparator checks whether the MD5 and the SHA * message digest implementations are available. If they are not available, an * alternative comparison method is used, which is more memory consuming. */ public ImageComparator () { try { digestMD5 = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException nse) { System.out.println("No MD5 algorithm available"); } try { digestSHA = MessageDigest.getInstance("SHA"); } catch (NoSuchAlgorithmException nse) { System.out.println("No SHA algorithm available"); } } /** * Creates 2 comparable objects. These objects can be compared for equality. * * @param image the image data which should be prepared for comparison * @param fast whether to prefer the memory intensive faster compare method to the * digest based comparation. This may result in outofmemory errors on huge * reports or images. * @return the prepared image data. */ public Object createCompareData (final byte[] image, final boolean fast) { if (fast == false && (digestMD5 != null && digestSHA != null)) { final byte[] dataMD5 = digestMD5.digest(image); final byte[] dataSHA = digestSHA.digest(image); if (dataSHA != null && dataMD5 != null) { return new DigestImageCompareData(dataMD5, dataSHA); } } return new CompleteImageCompareData(image); } }