JDK-8011764 : Drawing in the scaled VolatileImage is inaccurate.
Resolution:Not an Issue
The Version table provides details related to the release that this issue/RFE will be addressed.
Unresolved : Release in which this issue/RFE will be addressed. Resolved: Release in which this issue/RFE has been resolved. Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availabitlity Release.
Some rendering operations to the non-scaled BufferedImage and to the scaled VolatileImage is inconsistent. See example in the test.
Here are the relevant parts of an email conversation that I had with Sergey on the topic:
The problem is that the rendering is done with "stroke control" on. That setting allows us to perturb lines for quality purposes. In the case of 1:1 rendering, that setting is important as it allows us to move the line by 1/2 a pixel to make it appear crisp, so regular non-retina 1:1 rendering of lines is already biased to "fake" coordinates. With the advent of retina rendering at a 2:1 scale, integer lines are already crisp and require no bias to make them look nice and so the retina (full scale) rendering is actually correct whereas the non-retina rendering is a compromise that we've lived with for 20 years.
When you draw a line at point=1, then the line is a 1-pixel wide box centered on that coordinate and so it goes from 0.5 to 1.5. Under AA we bump that up by half a pixel to 1.0 to 2.0 so that it isn't a 2-pixel wide and half-intensity line. Under non-AA we bump it up by a different amount (I think the rounding factor is .25 pixels so that line widths grow evenly for lines on integer coordinates).
We specifically added the STROKE_CONTROL hints early on because of this issue that developers expected a line at x=1 to be "that pixel column that is separated from the edge of the drawable by a 1 pixel margin" even though the math would have it be a fractional coordinate straddling the edge of the pixels.
Under retina, the line would be at point=2 and it would extend twice as far (2 full pixels total width, so it extends 1.0 pixels on either side of the true coordinate) and so it actually a box from 1.0 to 3.0 and it is already on pixel boundaries so the line biasing code does not come into play for AA and I'd have to do the math, but it would probably also be off by a "retina pixel" on retina displays as well.
If you look at the full resolution image you see that the line drawn at x=1 is 1 pixel from the border and that is absolutely correct according to the geometry of drawing a 1-unit line on an integer coordinate in a scaled coordinate system.
Note that the down-scaled version of the retina image is performed with the default scaling algorithm which, I believe, is NEAREST_NEIGHBOR and so the pixels that end up in the final image are a subset of the pixels in the original image. If the rounding went the other way, then there would be a pixel gap to the edge of the image in the down-sampled image because it would have chosen the first (green) pixel to include, and then the third (red) pixel. But, given our default rounding that considers the edges of pixels to be included in the pixel that is below and to their right, sampling the full-res image at 1.0 chooses the second pixel instead, and we get no border.
So, the full res image shows what drawLines really truly should look like, and then when you combine that with the rounding choices made by the default algorithm, they conspire to produce a final image that has no gap at the left edge of the resulting down-scaled image.
The down-scaling algorithm can be specified by the KEY_INTERPOLATION hint, but the test case does not set any hints and relies on the defaults. Unfortunately, there is no hint for "choose the pixels out of the image that would represent what we would have drawn at half the scale".
Sergey, please comment
Why do you consider this bug is not an issue? You did not leave any explanation of your decision in comments.
Here, BitmapImage and a snapshot of a Volatile image, taken with retina emulator, differ in similar fashion: line and oval are drawn one pixel off.
Expectedly, if you run DrawLineRound.java with scaling factor==1 instead of 2 on retina, it has exactly the same inaccuracy as with factor 2.
Looks like the problem in the PixelToParallelogramConverter.drawGeneralLine.
Possibly PixelToParallelogramConverter.normalize should take into account current scale of the graphics?