Reputation: 8156
I have a logic that needs to compare base64 encoded images (JPEG and PNG) and check if they are the same.
The most basic approach to this is to compare the whole strings.
Since the images tend to be quite large, I was wondering if there was a faster and/or more memory efficient way to compare them. For example only comparing the first x characters, but base64 is done byte-by-byte that would only compare the first x bytes of the picture.
I'm not familiar with the inner workings of jpeg and png formats and the chance of the first bytes colliding (producing a false positive match), but if it's fairly low (like 1:10000) that would be acceptable.
Not that the basic comparsion is painfully slow, and since I need to read the whole strings into memory anyway for other operations, I will probably end up using a simple equality comparsion on them, I'm just interested in other possiblities.
EDIT:
Sorry for not clarifying this properly but this question was not meant to be about comparing image data. Lossy image formats make it painful anyway, and if the image is saved in a different format or with different options, it is different.
Upvotes: 3
Views: 10431
Reputation: 4451
As stated in comments an image will be compared only a few times (3 or 4 possible matches).
The low number of comparisons, probably doesn't make up for the cost of calculating a hash/digest.
I suggest to make a direct string comparison, if you have a match it will be only the length of the strings and if they don't match it will process only a few bytes until the first difference. If you want to avoid retrieving from the database all the records, you can choose to retrieve only the records that have the same length as the string to be compared.
Upvotes: 2
Reputation: 75976
Caveat: The base64-encoded image wraps inside it (after base64 decoding) the encoded image, in PNG or JPEG format. So, if you compare that content (with or without base64 decoding) you will get a match only if the full PNG/JPEG streams are equal, as when comparing files. This will not work if you want to test for raw image equality (i.e., same pixels). Not only because of metadata (eg, timestamps) but also because both formats have extra degrees of freedom in their encoding (compression algorithms and parameters) so that the same image content can produce different PNG/JPEG images.
If you are ok with that, if you really want to test for image equality at the (say) file level, then you could first test for string length (if the images are large is not very probable that the length will be equal) and only if they match do a byte-by-byte comparison. (see pmoleri answer regarding hash/digests). If you want to optimize, compare just a portion (say 100 bytes at the middle). PNG images, in particular have all the same 16 bytes, and the last 12 bytes.
Upvotes: 2
Reputation: 107
Try converting those specific formats into Image
and use this function.
I don't know if this works in your scenario, but try and let me know :)
public bool CompareImages(Image img1, Image img2)
{
bool rtn = true;
ImageConverter converter = new ImageConverter();
Bitmap bmp1 = img1;
Bitmap bmp2 = img2;
int dWid = Math.Min(bmp1.Width, bmp2.Width);
int dHei = Math.Min(bmp1.Height, bmp2.Height);
for (int x = 0; x <= dWid - 1; x++) {
for (int y = 0; y <= dHei - 1; y++) {
if (!bmp1.GetPixel(x, y).Equals(bmp2.GetPixel(x, y))) {
rtn = false;
break;
}
}
}
return rtn;
}
Upvotes: 1