Reputation: 37
I'm trying to compare two different views to compare the image to see if it's the same or not. This is my code...
public boolean equals(View view1, View view2){
view1.setDrawingCacheEnabled(true);
view1.buildDrawingCache();
Bitmap b1 = view1.getDrawingCache();
view2.setDrawingCacheEnabled(true);
view2.buildDrawingCache();
Bitmap b2 = view2.getDrawingCache();
ByteBuffer buffer1 = ByteBuffer.allocate(b1.getHeight() * b1.getRowBytes());
b1.copyPixelsToBuffer(buffer1);
ByteBuffer buffer2 = ByteBuffer.allocate(b2.getHeight() * b2.getRowBytes());
b2.copyPixelsToBuffer(buffer2);
return Arrays.equals(buffer1.array(), buffer2.array());
}
However, this is returning true no matter what. Can anyone tell me why im doing wrong?
Upvotes: 0
Views: 2032
Reputation: 8588
@Idistic's answer helped me to get another solution which is good also for images with higher resolutions which can cause OutOfMemory
error. The main idea was to split the images into several parts and compare their bytes. In my case 10 parts was enough, I think it is enough for the most of the cases.
private boolean compareBitmaps(Bitmap bitmap1, Bitmap bitmap2)
{
if (Build.VERSION.SDK_INT > 11)
{
return bitmap1.sameAs(bitmap2);
}
int chunkNumbers = 10;
int rows, cols;
int chunkHeight, chunkWidth;
rows = cols = (int) Math.sqrt(chunkNumbers);
chunkHeight = bitmap1.getHeight() / rows;
chunkWidth = bitmap1.getWidth() / cols;
int yCoord = 0;
for (int x = 0; x < rows; x++)
{
int xCoord = 0;
for (int y = 0; y < cols; y++)
{
try
{
Bitmap bitmapChunk1 = Bitmap.createBitmap(bitmap1, xCoord, yCoord, chunkWidth, chunkHeight);
Bitmap bitmapChunk2 = Bitmap.createBitmap(bitmap2, xCoord, yCoord, chunkWidth, chunkHeight);
if (!sameAs(bitmapChunk1, bitmapChunk2))
{
recycleBitmaps(bitmapChunk1, bitmapChunk2);
return false;
}
recycleBitmaps(bitmapChunk1, bitmapChunk2);
xCoord += chunkWidth;
}
catch (Exception e)
{
return false;
}
}
yCoord += chunkHeight;
}
return true;
}
private boolean sameAs(Bitmap bitmap1, Bitmap bitmap2)
{
// Different types of image
if (bitmap1.getConfig() != bitmap2.getConfig())
return false;
// Different sizes
if (bitmap1.getWidth() != bitmap2.getWidth())
return false;
if (bitmap1.getHeight() != bitmap2.getHeight())
return false;
int w = bitmap1.getWidth();
int h = bitmap1.getHeight();
int[] argbA = new int[w * h];
int[] argbB = new int[w * h];
bitmap1.getPixels(argbA, 0, w, 0, 0, w, h);
bitmap2.getPixels(argbB, 0, w, 0, 0, w, h);
// Alpha channel special check
if (bitmap1.getConfig() == Bitmap.Config.ALPHA_8)
{
final int length = w * h;
for (int i = 0; i < length; i++)
{
if ((argbA[i] & 0xFF000000) != (argbB[i] & 0xFF000000))
{
return false;
}
}
return true;
}
return Arrays.equals(argbA, argbB);
}
private void recycleBitmaps(Bitmap bitmap1, Bitmap bitmap2)
{
bitmap1.recycle();
bitmap2.recycle();
bitmap1 = null;
bitmap2 = null;
}
Upvotes: 0
Reputation: 6311
UPDATE: The code below works fine, but your code above seems to always return null from the .getDrawingCache() not sure if this is your problem or not. I don't have the time to look too deeply into this, but you might check getDrawingCache() returns null to see how a similar problem was solved, else please provide you logcat.
Here is a port (not really checked too stringently) of the sameAs function from API 15, introduced in API 12
One special check they do is to see if the image is alpha channel, and a few optimization's to avoid the array check if possible (probably not an issue with your use case) might as well take advantage of the open source when you can ;-)
boolean SameAs(Bitmap A, Bitmap B) {
// Different types of image
if(A.getConfig() != B.getConfig())
return false;
// Different sizes
if (A.getWidth() != B.getWidth())
return false;
if (A.getHeight() != B.getHeight())
return false;
// Allocate arrays - OK because at worst we have 3 bytes + Alpha (?)
int w = A.getWidth();
int h = A.getHeight();
int[] argbA = new int[w*h];
int[] argbB = new int[w*h];
A.getPixels(argbA, 0, w, 0, 0, w, h);
B.getPixels(argbB, 0, w, 0, 0, w, h);
// Alpha channel special check
if (A.getConfig() == Config.ALPHA_8) {
// in this case we have to manually compare the alpha channel as the rest is garbage.
final int length = w * h;
for (int i = 0 ; i < length ; i++) {
if ((argbA[i] & 0xFF000000) != (argbB[i] & 0xFF000000)) {
return false;
}
}
return true;
}
return Arrays.equals(argbA, argbB);
}
Upvotes: 0
Reputation: 16235
Not sure what's wrong with that code, if anything, but did you try Bitmap.sameAs(Bitmap)?
Upvotes: 1