airsdk / Adobe-Runtime-Support

Report, track and discuss issues in Adobe AIR. Monitored by Adobe - and HARMAN - and maintained by the AIR community.
199 stars 11 forks source link

Big image (BitmapData) in small Bitmap incorrect render #162

Closed itlancer closed 3 weeks ago

itlancer commented 4 years ago

Problem Description

Loaded big image (2300x1500 pixels, for example) into small bitmap object (90x60 pixels, for example) cause incorrect render (it starts to work like mask/scrollRect) when it x coordinate more than about 1255 pixels (different from image to image). This is very old bug.

Tested with many different AIR and Flash Player versions even with latests AIR 32.0.0.144 beta and AIR 33.0.2.330 with different Windows, macOS, Android and iOS devices, its architectures, build target and OSes versions.

Tracker link: https://tracker.adobe.com/#/view/AIR-4153130 Related issue: http://forum.starling-framework.org/topic/all-platforms-big-image-in-small-bitmap-object-render-problem

Same problem with all cases with any "big image". Changing renderMode in application manifest doesn't help. Changing Stage::quality doesn't help. Changing Bitmap::smoothing doesn't help. Changing requestedDisplayResolution in application manifest doesn't help. Parent (DisplayObjectContainer) that contains Bitmap object doesn't matter.

Steps to Reproduce

Launch code below and move mouse (or touch) somewhere to the right side of stage (application screen). "Problem coordinates" seems depends on screen resolution, application window size, image resolution and some other factors. Application example with sources and example of image attached. big_image_bug.zip

package {
    import flash.display.Bitmap;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;
    import flash.display.Sprite;
    import flash.events.Event;

    public class BigImageBug extends Sprite {

        [Embed(source = "big_image.jpg")]
        private const EmbeddedImage:Class;//Embed image just for simplicity

        private var bitmap:Bitmap;

        public function BigImageBug() {
            //Just to use whole avaiable stage space
            stage.align = StageAlign.TOP_LEFT;
            stage.scaleMode = StageScaleMode.NO_SCALE;

            bitmap = new EmbeddedImage();//Type of loading or embedding image doesn't matter
            bitmap.width = 90;//Set image width/height relatively small
            bitmap.height = 60;
            //bitmap.cacheAsBitmap = true;//Uncomment this line for workaround
            addChild(bitmap);

            addEventListener(Event.ENTER_FRAME, enterFrameMove);
        }

        //Move image (bitmap) at mouse coordinates
        private function enterFrameMove(e:Event):void {
            bitmap.x = stage.mouseX;
            bitmap.y = stage.mouseY;
        }
    }
}

Actual Result: Image incorrect render. It start to work something like scrollRect and show only strange part of image. actual

Expected Result: Correct image render. expected

Known Workarounds

ajwfrost commented 4 years ago

This is an interesting one - I'm a little surprised that changing the quality doesn't help actually. But essentially, this is a problem caused by overflow of the matrix that's used to render the image onto the display. The combination of the downscaling plus the translation means that the matrix ends up overflowing/invalid, and the failsafe drops back to a standard matrix which means you just get the normal image scaling/location, viewed through the clip bounds.

There's an aspect of the scale that's resulting from the anti-aliasing setting (related to stage quality) which is why I might think it would work if stage quality is lower. We can look at workarounds but the obvious option is to redraw the scaled image to a smaller bitmap..

thanks

itlancer commented 3 months ago

Issue still exists with latest AIR 51.0.1.1.

ajwfrost commented 3 months ago

We can look again at this, I think we should be able to detect the overflow of the matrix.... which means our options would either be:

ajwfrost commented 3 months ago

So we have a way of working around this, specifically for bitmaps, which will help to a certain extent. The issue isn't that the scaling matrix itself isn't invertible, it's the translation part which overflows. This is to work out which pixel from the picture should be drawn into which target pixel on the output: as the target pixel gets larger, when there is a big downscale value then the translation gets massive. When the code detects it's gone wrong (got too large to fit into the 32-bit value) then it resets the scaling matrix to just an identity matrix so you just get a window onto the large image.

We've updated this so that in these cases, when we detect the 32-bit overflow, we switch it into a 64-bit variable. If the value would have overflowed a 64-bit value, then it would still end up with the same problem (so a huge image, massively scaled down, positioned at a very large x value, could still hit this... but it would be rare!)

thanks

itlancer commented 1 month ago

@ajwfrost Still doesn't work with AIR 51.0.1.4. The same sample as in original post. Now actual result not as scrollRect but display only top left corner of image.

itlancer commented 3 weeks ago

Fixed with latest AIR 51.1.1.2. Thanks!