> There is one: choose the size so that the image is displayed without scaling.
You're apparently not paying attention. There is currently no way to do that (except in Chrome via JavaScript maybe)
What size would you choose?
By default a browser will display the image at its natural size * devicePixelRatio. devicePixelRatio can be non-integer values. Further, the devicePixelRatio is fluid in Chrome and Firefox. Press Ctrl/Cmd +/- and it changes.
In Chrome (the only browser that's implemented ResizeObserver with devicePixelContentBoxSize), you can ask exactly how many devicePixels a given element is ... other browsers have not implemented this. And no, elem.getBoundingClientRect will not do it.
But, even if you have the API it would still be a pita. You'd have to take the size of your original image, figure out some integer-multiple that matches the current devicePixelRatio, pray that it still fits your design, create an element that large, then use the ResizeObverser to see if you really got that size. If not, adjust up or down a pixel at time until you do.
"pray that it still fits your design" means assume you had a 200x100 image you want displayed at 2x so 400x200 and the users DPI is 1.33. If you ask for 400x200 you'll actually get 532x266. Your 200x100 image will not scale pixel perfect to 532x266. You could, via JavaScript, compute what size to ask for to get 4x scaling. That size with a DPI of 1.33 is 300.7518796992481. You can't ask for a fractional size (well you can, but it's going to get rounded) But now your design no longer works. You expected the image to take 400 CSS units but it's only taking 300, too small. And, further, there's no guarantee you'll get 300. You might get 301. To find out requires the devicePixelContentBoxSize mentioned above