Is there any way to compare the ImageFill object of two graphicNodes?
I just want to make sure the fileOrDataURI are the same.
ImageFill object has no fileOrDataURI
property. Try to compare .toString()
function results of two ImageFill objects or convert objects to json strings with JSON.stringify
and compare them
The problem here is that it might be possible to check the “outer parameters”, to my knowledge, Adobe XD stores images as part of a .xd
file (the last time I’ve checked, at least, that was the case), and not as a reference to some file in your file system (you can easily check this by opening a .xd
file on another machine).
Therefore, a fileURI
doesn’t exist any longer as soon as XD has imported the image, or at least, it can’t be the same for two objects.
All in all, the only way to really check whether two fills are the same would be to somehow check their actual content, i.e., e.g., a data URI.
To my knowledge, there’s no way to do so directly inside XD (at least, no way is clearly documented). Therefore, the only solution I could image would be to
- Create some sort of “neutral rectangle”, which, when exported with a specific image fill, always exports it the same way.
- Apply the fill (a clone, thereof, with
ImageFill.clone()
) to that rectangle and export it programmatically - Read the file and compare its raw data to another set of data fetched this way
While I can’t check right now, I firmly believe this would only compare the “metadata” in the ImageFill
, i.e., mimeType
, naturalWidth
etc., which could be the same in many cases (e.g., multiple portrait photos with 512px*512px). Therefore, this might get you the results you’re looking for, but probably would result in false positives. Also, this would evaluate to false if, say, scaleBehaviour
is different, although the image might be the same (which is what should get compared here).
Basically, that’s probably a question someone from Adobe has to answer, but I’m rather sure there’s no trivial way to check fills’ image datas for equality.
PS: @wata.hia Welcome to the forums !
.toString()
of ImageFill object returns something like ImageFill(/Users/user/Downloads/image.png)
(for file), so first will be equal to second (in case of original question - fileOrDataURI are the same
). Anyway, need to clarify the original question: need to compare fileUrl/base64 strings only, or compare whole objects, or compare raw content of images.
Wow, that’s interesting. I’ll have to check what happens when one opens an XD document on another machine. It wouldn’t be exactly ideal when an XD document provides info on the file structure of the creator’s system… (not really a vulnerability, but still, not ideal)
Thanks for the reply everyone! I will try the different options out.
@afuchs / @schenglooi is this actually expected behavior – for ImageFill.toString()
to leak file paths like this?
I’ve converted this into a feature request post type so folks can upvote it to indicate interest.
It’s not possibly to reliably do this today – toString()
isn’t a safe bet since its output isn’t a frozen API contract… and it already will not work the way you want for images that came from a data URI or the clipboard.
Does XD internally track duplications of objects in any way? I’m guessing that even duplicate data URI or clipboard insertions count as separate images as far as the internal model goes…
So I’m not sure there’s a great way to do this that doesn’t involve somehow computing that the bytes of the image is the same (and that seems somewhat expensive), especially for documents with large (or a large number) of images.
If you paste from the clipboard twice and it happens to contain the exact same bitmap data both times, I’m not sure if XD will auto-detect that they are identical… But certainly if you paste once and then clone that object in your design a bunch of times (or use it in a Component, a Repeat Grid, etc.) XD knows they are all the same image asset – but plugins won’t be able to tell that right now.
Ok, I did some research regarding this. Here are the (literal) results of
console.log(selection.items[0].fill.toString());
where a rectangle with an image fill is selected for different cases:
Image dragged from Chrome into existing rectangle
(apperently some temporary folder. I’m on a German system, - Kopie
is the default “duplicate” appendix of Windows for files)
ImageFill(C:\Users\pablo\AppData\Local\Packages\Adobe.CC.XD_adky2gkssdxte\TempState\NoPath - Kopie.png)
Image dragged frome Chrome into existing rectangle duplicated
Same results
ImageFill(C:\Users\pablo\AppData\Local\Packages\Adobe.CC.XD_adky2gkssdxte\TempState\NoPath - Kopie.png)
Image copied and pasted from Chrome:
ImageFill(<data URI>)
Rectangle node with image copied and pasted from Chrome duplicated
ImageFill(<data URI>)
Image directly dragged into XD from Chrome (not into a rectangle)
ImageFill(C:\Users\pablo\AppData\Local\Packages\Adobe.CC.XD_adky2gkssdxte\TempState\NoPath.jpg)
[…] duplicated
ImageFill(C:\Users\pablo\AppData\Local\Packages\Adobe.CC.XD_adky2gkssdxte\TempState\NoPath.jpg)
Image dragged from file system into XD
ImageFill(C:\Users\pablo\OneDrive\Pictures\DSC00258.JPG)
exposing the path
The previous node after saving and re-opening the document as cloud document
ImageFill(C:\Users\pablo\OneDrive\Pictures\DSC00258.JPG)
Still exposing the original file path. This, potentially, is not good .
All of this was tested on Windows 10, XD 25.1.12.7, Creative Cloud Sync 4.3.24.11.
XD 29 has cleaned up this area a bunch:
-
To tell if two ImageFills use the same underlying raster asset, compare their
assetId
properties.- Two ImageFills with the same
assetId
may still look different in the XD document though, due to cropping, rotation, flipping, masks, opacity/blendmode, border/blur/shadow styles, etc.
- Two ImageFills with the same
-
toString()
no longer includes a path, which as @pklaschka pointed out could be surprising data disclosure in some cases, and also is tempting to erroneously use for comparisons (even though it won’t work in those “data URI” cases). -
toString()
now displays just the image filename (if available) and adds the image’s natural size – two bits of info that seem useful when debugging and printing ImageFill objects to the console. But for programmatic purposes in production code, don’t rely on this string –toString()
output is always subject to change. Use layer name if you need a label, and use thenaturalWidth
/naturalHeight
getters for size.